git-cipher 0.2 → 0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/bin/git-cipher +38 -75
  3. metadata +3 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3d52bb65c34660958a91e70fef43d596610bede9
4
- data.tar.gz: 7d83c6b13437a4fa8c1d166b76fda86abdf9a990
3
+ metadata.gz: fafc4d52d9e64f31c6224872f4357038dbde9902
4
+ data.tar.gz: 95f89526e90879fd8cb111a5489f6d458a3d9609
5
5
  SHA512:
6
- metadata.gz: 53dec9da0d8e7bed2874793c25bde8e9fad254059bdccee796dec7b131a7191a6a863ced6873e797007167236de4a5f25dfc562b33e01a7506d98da32d7872cb
7
- data.tar.gz: e1c65440edaeb32687e7b124f6c497bd8e9413f4ef7c7f92a23d55d13ab29691a820eed6918ca819f6273e4308fb8c1a4d9cabd5939b4661da25ee785766e2f2
6
+ metadata.gz: 433b3749ae3175d9c4927a83bdd321fbe72b5cc0cc8d462d77ba0bb37a2b9cfdc8ce0652f37e64309c0b6f78a000e4a92217e39b93332eba68d153d7c8dec9f4
7
+ data.tar.gz: 2c8157fab0532f359d2acaf2ebed1eae6e9719467ec6c5e37e5f2b8344c7ff479c263d28146db0daae67df6093eb3f83bf7f50b5764647f9dd633b4939323254
data/bin/git-cipher CHANGED
@@ -9,9 +9,9 @@ require 'tempfile'
9
9
  class Cipher
10
10
  EXTENSION = 'encrypted'
11
11
  DEFAULT_GPG_USER = 'greg@hurrell.net'
12
- DEFAULT_GPG_PRESET_COMMAND = '/usr/local/opt/gpg-agent/libexec/gpg-preset-passphrase'
12
+ EXECUTABLE_EXTENSIONS = %w[.js .sh]
13
13
  VALID_OPTIONS = %w[force help]
14
- VALID_SUBCOMMANDS = %w[decrypt encrypt help log preset forget]
14
+ VALID_SUBCOMMANDS = %w[decrypt encrypt help log ls]
15
15
 
16
16
  def run
17
17
  send @subcommand
@@ -63,15 +63,13 @@ private
63
63
  def decrypt
64
64
  if @files.empty?
65
65
  puts 'No explicit paths supplied: decrypting all matching files'
66
- Dir["**/.*.#{EXTENSION}"].each { |file| decrypt!(file) }
66
+ matching.each { |file| decrypt!(file) }
67
67
  else
68
68
  @files.each { |file| decrypt!(file) }
69
69
  end
70
70
  end
71
71
 
72
72
  def decrypt!(file)
73
- require_agent
74
-
75
73
  pathname = Pathname.new(file)
76
74
  basename = pathname.basename.to_s
77
75
  unless basename.start_with?('.')
@@ -102,11 +100,11 @@ private
102
100
  if $?.success?
103
101
  puts green(' done]')
104
102
 
105
- File.chmod(0600, outfile)
103
+ File.chmod(mode(outfile), outfile)
106
104
 
107
- # mark plain-text as older than ciphertext, this will prevent a
105
+ # Mark plain-text as older than ciphertext, this will prevent a
108
106
  # bin/encrypt run from needlessly changing the contents of the ciphertext
109
- # (as the encryption is non-deterministic)
107
+ # (as the encryption is non-deterministic).
110
108
  time = File.mtime(file) - 1
111
109
  File.utime(time, time, outfile)
112
110
  else
@@ -127,7 +125,7 @@ private
127
125
  def encrypt
128
126
  if @files.empty?
129
127
  puts 'No explicit paths supplied: encrypting all matching files'
130
- Dir["**/.*.#{EXTENSION}"].each do |file|
128
+ matching.each do |file|
131
129
  file = Pathname.new(file)
132
130
  encrypt!(
133
131
  file.dirname +
@@ -171,7 +169,7 @@ private
171
169
  end
172
170
  end
173
171
 
174
- File.chmod(0600, file)
172
+ File.chmod(mode(file), file)
175
173
  check_ignored(file)
176
174
  end
177
175
 
@@ -183,11 +181,6 @@ private
183
181
  %x{#{string.gsub("\n", ' ')}}
184
182
  end
185
183
 
186
- def forget
187
- `#{escape command_path(gpg_preset_command)} --forget #{keygrip}`
188
- die 'gpg-preset-passphrase failed' unless $?.success?
189
- end
190
-
191
184
  def get_config(key)
192
185
  value = `#{escape command_path('git')} config cipher.#{key}`.chomp
193
186
  return if value.empty?
@@ -217,10 +210,6 @@ private
217
210
  })
218
211
  end
219
212
 
220
- def gpg_preset_command
221
- ENV['GPG_PRESET_COMMAND'] || get_config('presetcommand') || DEFAULT_GPG_PRESET_COMMAND
222
- end
223
-
224
213
  def gpg_user
225
214
  ENV['GPG_USER'] || get_config('gpguser') || DEFAULT_GPG_USER
226
215
  end
@@ -229,17 +218,6 @@ private
229
218
  colorize(string, 32)
230
219
  end
231
220
 
232
- def keygrip
233
- # get the subkey fingerprint and convert it into a 40-char hex code
234
- @keygrip ||= execute(%{
235
- #{escape command_path('gpg')} --fingerprint #{escape gpg_user} |
236
- grep fingerprint |
237
- tail -1 |
238
- cut -d= -f2 |
239
- sed -e 's/ //g'
240
- })
241
- end
242
-
243
221
  def kill_line
244
222
  # 2K deletes the line, 0G moves to column 0
245
223
  # see: http://en.wikipedia.org/wiki/ANSI_escape_code
@@ -250,19 +228,18 @@ private
250
228
  if @files.empty?
251
229
  # TODO: would be nice to interleave these instead of doing them serially.
252
230
  puts 'No explicit paths supplied: logging all matching files'
253
- Dir["**/.*.#{EXTENSION}"].each { |file| log!(file) }
231
+ matching.each { |file| log!(file) }
254
232
  else
255
233
  @files.each { |file| log!(file) }
256
234
  end
257
235
  end
258
236
 
259
237
  def log!(file)
260
- require_agent
261
-
262
238
  commits = execute(%{
263
239
  #{escape command_path('git')} log
264
240
  --pretty=format:%H -- #{escape file}
265
241
  }).split
242
+ suffix = "-#{File.basename(file)}"
266
243
 
267
244
  commits.each do |commit|
268
245
  files = []
@@ -270,13 +247,14 @@ private
270
247
  # Get plaintext "post" image.
271
248
  files.push(post = temp_write(show(file, commit)))
272
249
  files.push(
273
- post_plaintext = temp_write(gpg_decrypt(post.path, '-'))
250
+ post_plaintext = temp_write(gpg_decrypt(post.path, '-'), suffix)
274
251
  )
275
252
 
276
253
  # Get plaintext "pre" image.
277
254
  files.push(pre = temp_write(show(file, "#{commit}~")))
278
255
  files.push(pre_plaintext = temp_write(
279
- pre.size.zero? ? '' : gpg_decrypt(pre.path, '-')
256
+ pre.size.zero? ? '' : gpg_decrypt(pre.path, '-'),
257
+ suffix
280
258
  ))
281
259
 
282
260
  # Print commit message.
@@ -304,6 +282,24 @@ private
304
282
  end
305
283
  end
306
284
 
285
+ def ls
286
+ matching.each { |file| puts file }
287
+ end
288
+
289
+ def matching
290
+ Dir.glob("**/*.#{EXTENSION}", File::FNM_DOTMATCH)
291
+ end
292
+
293
+ # Determine the appropriate mode for the given decrypted plaintext
294
+ # `file` based on its file extension.
295
+ def mode(file)
296
+ if EXECUTABLE_EXTENSIONS.include?(Pathname.new(file).extname)
297
+ 0700
298
+ else
299
+ 0600
300
+ end
301
+ end
302
+
307
303
  def normalize_option(option)
308
304
  normal = option.dup
309
305
 
@@ -318,17 +314,6 @@ private
318
314
  found
319
315
  end
320
316
 
321
- def preset
322
- passphrase = get_passphrase
323
- command = "#{escape command_path(gpg_preset_command)} --preset #{keygrip}"
324
- IO.popen(command, 'w+') do |io|
325
- io.puts passphrase
326
- io.close_write
327
- puts io.read # usually silent
328
- end
329
- die 'gpg-preset-passphrase failed' unless $?.success?
330
- end
331
-
332
317
  def process_args
333
318
  options, files = ARGV.partition { |arg| arg.start_with?('-') }
334
319
  subcommand = files.shift
@@ -351,17 +336,6 @@ private
351
336
  colorize(string, 31)
352
337
  end
353
338
 
354
- def require_agent
355
- unless ENV['GPG_AGENT_INFO']
356
- die <<-MSG
357
- GPG_AGENT_INFO not present in the environment.
358
- Try running this before retrying `#{command_name} #{@subcommand}`:
359
- eval $(gpg-agent --daemon)
360
- #{command_name} preset
361
- MSG
362
- end
363
- end
364
-
365
339
  def show(file, commit)
366
340
  # Redirect stderr to /dev/null because the file might not have existed prior
367
341
  # to this commit.
@@ -377,9 +351,8 @@ private
377
351
  doc.gsub(/^[ \t]{#{indent}}/, '')
378
352
  end
379
353
 
380
- def temp_write(contents)
381
- file = Tempfile.new('git-cipher-')
382
- file.chmod(0600)
354
+ def temp_write(contents, suffix = '')
355
+ file = Tempfile.new(['git-cipher-', suffix])
383
356
  file.write(contents)
384
357
  file.flush
385
358
  file
@@ -430,14 +403,6 @@ private
430
403
  #{command_name} encrypt -f
431
404
  #{command_name} encrypt --force # (alternative syntax)
432
405
  USAGE
433
- when 'forget'
434
- puts strip_heredoc(<<-USAGE)
435
- #{command_name} forget
436
-
437
- Forget passphrase previously stored using `#{command_name} preset`:
438
-
439
- #{command_name} forget
440
- USAGE
441
406
  when 'log'
442
407
  puts strip_heredoc(<<-USAGE)
443
408
  #{command_name} log FILE
@@ -447,13 +412,12 @@ private
447
412
 
448
413
  #{command_name} log foo
449
414
  USAGE
450
- when 'preset'
415
+ when 'ls'
451
416
  puts strip_heredoc(<<-USAGE)
452
- #{command_name} preset
453
-
454
- Store a passphrase in a running `gpg-agent` agent:
417
+ #{command_name} ls
455
418
 
456
- #{command_name} preset
419
+ Lists the encrypted files in the current directory and
420
+ its subdirectories.
457
421
  USAGE
458
422
  else
459
423
  puts strip_heredoc(<<-USAGE)
@@ -461,9 +425,8 @@ private
461
425
 
462
426
  #{command_name} decrypt
463
427
  #{command_name} encrypt
464
- #{command_name} forget
465
428
  #{command_name} log
466
- #{command_name} preset
429
+ #{command_name} ls
467
430
  USAGE
468
431
  end
469
432
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: git-cipher
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.2'
4
+ version: '0.3'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Greg Hurrell
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-08 00:00:00.000000000 Z
11
+ date: 2017-04-24 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: "\n Provides a convenient workflow for working with encrypted files
14
14
  in a public\n Git repo. Delegates the underlying work of encryption/decryption
@@ -43,7 +43,7 @@ requirements:
43
43
  - Git
44
44
  - GnuPG
45
45
  rubyforge_project:
46
- rubygems_version: 2.0.14
46
+ rubygems_version: 2.0.14.1
47
47
  signing_key:
48
48
  specification_version: 4
49
49
  summary: Manages encrypted content in a Git repo