dotgpg 0.5.1 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +26 -0
- data/dotgpg.gemspec +1 -1
- data/lib/dotgpg/cli.rb +103 -1
- data/lib/dotgpg.rb +13 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9809f26fb51e8fce8cce8bcbfb6656b1de07208f
|
4
|
+
data.tar.gz: 98e7d6a9928c1a64de793e7e57729756949cdbf1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2133b5d5e87cc941c0aebed9e2e12680d56abaf62fa42fca66cd1822d828e0eca3478c7c81e5cb3069bec3c0057be59de42c7ee72be4894f638410d875f23cbe
|
7
|
+
data.tar.gz: b8030f114a7fb96bdd9100f216529b566077a015f000f6d458f2b741d785d48b20e87cfcae7b22e55e04f8dcc1af1aba44eb2a63012a9bea7829423db0dd76fb
|
data/README.md
CHANGED
@@ -80,6 +80,10 @@ leJCaaNJQBbIOj4QOjFWiZ8ATqLH9nkgawSwOV3xp0MWayCJ3MVnibt4CaI=
|
|
80
80
|
-----END PGP PUBLIC KEY BLOCK-----
|
81
81
|
```
|
82
82
|
|
83
|
+
#### dotgpg merge
|
84
|
+
|
85
|
+
See the 'Integration With Git' section below.
|
86
|
+
|
83
87
|
## Why
|
84
88
|
|
85
89
|
Production secrets are the keys that your app needs to run. For example the session cookie encryption key, or the database password. These are critical to the running of your app, so it's essential to have a backup that is version controlled. Then if anything goes wrong, you can find the previous values and go back to running happily.
|
@@ -165,3 +169,25 @@ Occasionally people leave, or stop needing access to dotgpg. To remove them use
|
|
165
169
|
dotgpg rm conrad.irwin@gmail.com
|
166
170
|
```
|
167
171
|
|
172
|
+
### Integration with git
|
173
|
+
|
174
|
+
Encrypted files don't work well with many git workflows because they are (basically) binary files that appear to be text files. Because of this diff and merge may appear to work from git's point of view but will actually generate garbage according to GPG. It's possible to work around this:
|
175
|
+
|
176
|
+
Add the following lines to your [git config](http://git-scm.com/docs/git-config):
|
177
|
+
```
|
178
|
+
[diff "gpg"]
|
179
|
+
textconv = gpg -d -q --batch --no-tty 2>/dev/null
|
180
|
+
[merge "gpg"]
|
181
|
+
name = dotgpg merge driver
|
182
|
+
driver = "dotgpg merge %O %A %B"
|
183
|
+
```
|
184
|
+
(you may need to use `bundle exec dotgpg merge %O %A %B` depending on how you've installed dotgpg and ruby)
|
185
|
+
|
186
|
+
Add the following lines to your [git attributes](http://git-scm.com/book/en/v2/Customizing-Git-Git-Attributes)
|
187
|
+
```
|
188
|
+
*.gpg diff=gpg merge=gpg
|
189
|
+
```
|
190
|
+
|
191
|
+
Now `git diff` will show you the diff of the decrypted content. `git merge` will decrypted your files, try to merge the decrypted text, and then encrypt the subsequent output. If there's a conflict the file will be marked as such but will still be a valid GPG file - the decrypted file will contain the text with the merge conflict markers in it.
|
192
|
+
|
193
|
+
It's probably possible to adapt this to other VCS's.
|
data/dotgpg.gemspec
CHANGED
data/lib/dotgpg/cli.rb
CHANGED
@@ -23,7 +23,7 @@ class Dotgpg
|
|
23
23
|
info " #{directory}/.gpg/#{key.email}"
|
24
24
|
|
25
25
|
FileUtils.mkdir_p(dir.dotgpg)
|
26
|
-
unless File.exist? 'README.md'
|
26
|
+
unless File.exist? 'README.md'
|
27
27
|
FileUtils.cp Pathname.new(__FILE__).dirname.join("template/README.md"), dir.path.join("README.md")
|
28
28
|
dir.add_key(key)
|
29
29
|
end
|
@@ -100,6 +100,14 @@ class Dotgpg
|
|
100
100
|
fail e.message
|
101
101
|
end
|
102
102
|
|
103
|
+
desc "unsafe_cat FILES...", "unsafely decrypt and print files"
|
104
|
+
def unsafe_cat(*files)
|
105
|
+
return if helped?
|
106
|
+
files.each do |f|
|
107
|
+
$stdout.puts Dotgpg.decrypt_without_validating_signatures File.open f
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
103
111
|
desc "edit FILES...", "edit and re-encrypt files"
|
104
112
|
def edit(*files)
|
105
113
|
return if helped?
|
@@ -122,6 +130,100 @@ class Dotgpg
|
|
122
130
|
fail e.message
|
123
131
|
end
|
124
132
|
|
133
|
+
desc "merge MYFILE OLDFILE YOURFILE", "dotgpg-aware wrapper for merging via diff3(1)"
|
134
|
+
def merge(*files)
|
135
|
+
require 'find'
|
136
|
+
require 'digest'
|
137
|
+
require 'fileutils'
|
138
|
+
|
139
|
+
return if helped?
|
140
|
+
fail "usage: MYFILE OLDFILE YOURFILE" unless files.length == 3
|
141
|
+
|
142
|
+
# ok, we won't know which gpg directory was used for our files because
|
143
|
+
# the .merge_files are dumped in the root git dir. so we resort to ulginess
|
144
|
+
# - we hash OLDFILE, search for directories which contain a .gpg subdir
|
145
|
+
# and check the md5sums of all the files in said directory. if there's a
|
146
|
+
# match we have our dir
|
147
|
+
old_hash = Digest::SHA256.file(files[1]).hexdigest
|
148
|
+
|
149
|
+
# if file is nil DotGpg:Dir.closest throws an error. if it's just a blank
|
150
|
+
# string we get the "not in a dotgpg directory" message
|
151
|
+
file = ''
|
152
|
+
|
153
|
+
Find.find(::Dir.pwd) do |path|
|
154
|
+
if FileTest.directory?(path) && File.basename(path) == ".gpg"
|
155
|
+
# found a .gpg dir, check in the parent for our target file
|
156
|
+
dotgpg_dir = File.dirname path
|
157
|
+
gpg_files = ::Dir.glob(File.join dotgpg_dir, "*")
|
158
|
+
|
159
|
+
if matched = gpg_files.find { |f| File.file?(f) && old_hash == Digest::SHA256.file(f).hexdigest }
|
160
|
+
file = matched
|
161
|
+
break
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
dir = Dotgpg::Dir.closest(file)
|
167
|
+
fail "not in a dotgpg directory" unless dir
|
168
|
+
|
169
|
+
mine = Tempfile.open('mine')
|
170
|
+
old = Tempfile.open('old')
|
171
|
+
yours = Tempfile.open('yours')
|
172
|
+
|
173
|
+
begin
|
174
|
+
# decrypt all three of our files
|
175
|
+
dir.decrypt files[0], mine
|
176
|
+
dir.decrypt files[1], old
|
177
|
+
dir.decrypt files[2], yours
|
178
|
+
|
179
|
+
# flush our io
|
180
|
+
mine.flush
|
181
|
+
old.flush
|
182
|
+
yours.flush
|
183
|
+
|
184
|
+
# TODO - could also use diff3(1) here:
|
185
|
+
#
|
186
|
+
# "diff3 -L mine -L old -L yours -m #{mine.path} #{old.path} #{yours.path}"
|
187
|
+
#
|
188
|
+
# but git merge-file's output is more diff3-ish than diff3's, weird.
|
189
|
+
cmd = "git merge-file -L mine -L old -L yours -p %s %s %s 2>/dev/null" %
|
190
|
+
[ Shellwords.escape(mine.path), Shellwords.escape(old.path),
|
191
|
+
Shellwords.escape(yours.path) ]
|
192
|
+
|
193
|
+
# run our merge
|
194
|
+
diff = `#{cmd}`
|
195
|
+
conflict = !$?.success?
|
196
|
+
ensure
|
197
|
+
# close and unlink our tempfiles
|
198
|
+
mine.close!
|
199
|
+
old.close!
|
200
|
+
yours.close!
|
201
|
+
end
|
202
|
+
|
203
|
+
# make a new stringio object out of our diff output
|
204
|
+
io = StringIO.new diff
|
205
|
+
|
206
|
+
# create a new tempfile to write our merged file to
|
207
|
+
t = Tempfile.open('merged')
|
208
|
+
begin
|
209
|
+
# encrypt our diff3 output
|
210
|
+
dir.encrypt t, io
|
211
|
+
t.flush
|
212
|
+
|
213
|
+
# and copy that file back to OLDFILE (aka files[1]) since that's where
|
214
|
+
# git expects to find it
|
215
|
+
FileUtils.copy t.path, files[1]
|
216
|
+
ensure
|
217
|
+
t.close!
|
218
|
+
end
|
219
|
+
|
220
|
+
# this is important - this exit value is what git uses to decide if there
|
221
|
+
# is a conflict or not
|
222
|
+
exit (conflict ? 1 : 0)
|
223
|
+
rescue GPGME::Error::BadPassphrase => e
|
224
|
+
fail e.message
|
225
|
+
end
|
226
|
+
|
125
227
|
private
|
126
228
|
|
127
229
|
# If the global --help or -h flag is passed, show help.
|
data/lib/dotgpg.rb
CHANGED
@@ -94,4 +94,17 @@ class Dotgpg
|
|
94
94
|
io.puts(@passphrase)
|
95
95
|
io.flush
|
96
96
|
end
|
97
|
+
|
98
|
+
# this is a quick workaroundfor situations where finding a dotgpg directory is
|
99
|
+
# difficult.
|
100
|
+
#
|
101
|
+
# THIS WILL NOT VERIFY THE INPUT WAS SIGNED
|
102
|
+
# THIS WILL NOT VERIFY THE INPUT SIGNATURE IS VALID
|
103
|
+
# THIS WILL NOT VERIFY THE INPUT SIGNATURE IS TRUSTED
|
104
|
+
#
|
105
|
+
# see Dir#decrypt for the right way to read files.
|
106
|
+
|
107
|
+
def self.decrypt_without_validating_signatures(data)
|
108
|
+
GPGME::Crypto.new.decrypt data, passphrase_callback: Dotgpg.method(:passfunc)
|
109
|
+
end
|
97
110
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dotgpg
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Conrad Irwin
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain:
|
11
11
|
- certs/gem-public_cert.pem
|
12
|
-
date:
|
12
|
+
date: 2015-04-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: thor
|