rubygems-openpgp 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2011, Grant T. Olson
1
+ Copyright (c) 2011, 2013 Grant T. Olson
2
2
  All rights reserved.
3
3
 
4
4
  Redistribution and use in source and binary forms, with or without
@@ -4,6 +4,7 @@ require 'rubygems/user_interaction'
4
4
  require 'shellwords'
5
5
  require 'open3'
6
6
  require 'tempfile'
7
+ require 'gpg_status_parser'
7
8
 
8
9
  # Exception for this class
9
10
  class Gem::OpenPGPException < RuntimeError; end
@@ -29,9 +30,51 @@ module Gem::OpenPGP
29
30
  homedir_flag = ""
30
31
  homedir_flag = "--homedir #{shellescape(homedir)}" if homedir
31
32
 
32
- cmd = "gpg #{key_flag} #{homedir_flag} --detach-sign --armor"
33
- sig, err = run_gpg_command cmd, data
34
- sig
33
+ gpg_args = "#{key_flag} #{homedir_flag} --detach-sign --armor"
34
+ gpg_results = run_gpg(gpg_args, data)
35
+ did_gpg_error? gpg_results
36
+
37
+ gpg_results[:stdout]
38
+ end
39
+
40
+ # Extract the info we care about, throw away the rest
41
+ def self.verify_extract_status_info message, status_info
42
+ case message.status
43
+ when :GOODSIG, :BADSIG, :ERRSIG
44
+ status_info[:good_or_bad] = message.status
45
+ status_info[:uid] = (message.args[:username] || "").strip
46
+
47
+ when :SIG_ID
48
+ when :VALIDSIG, :EXPSIG, :BADSIG
49
+ status_info[:sig_status] = message.status
50
+ status_info[:primary_key] = "0x#{message.args[:primary_key_fpr][-9..-1]}"
51
+ when :TRUST_UNDEFINED, :TRUST_NEVER, :TRUST_MARGINAL, :TRUST_FULLY, :TRUST_ULTIMATE
52
+ status_info[:trust_status] = message.status
53
+ when :NO_PUBKEY
54
+ status_info[:failure] = "You don't have the public key. Use --get-key to automagically retrieve from keyservers"
55
+ when :IMPORTED, :IMPORT_OK, :IMPORT_RES
56
+ #silently_ignore
57
+ when :KEYEXPIRED, :SIGEXPIRED
58
+ # recalculating trust db, ignore.
59
+ else
60
+ puts "unexpected message: #{message.status} #{message.args.inspect}"
61
+ end
62
+ end
63
+
64
+ # Print info about the sig, check that we like it, and possibly abort
65
+ def self.verify_check_sig status_info
66
+ sig_msg = "Signature for #{status_info[:file_name]} from user #{status_info[:uid]} key #{status_info[:primary_key]} is #{status_info[:good_or_bad]}, #{status_info[:sig_status]} and #{status_info[:trust_status]}"
67
+ if status_info[:trust_status] == :TRUST_NEVER
68
+ say add_color(sig_msg, :red)
69
+ raise Gem::OpenPGPException, "Never Trusted. Won't install."
70
+ elsif status_info[:trust_status] == :TRUST_UNDEFINED
71
+ say add_color(sig_msg, :yellow)
72
+ if options[:trust] && !options[:no_trust]
73
+ raise Gem::OpenPGPException, "Trust Undefined and you've specified --trust. Won't install."
74
+ end
75
+ else
76
+ say add_color(sig_msg , :green)
77
+ end
35
78
  end
36
79
 
37
80
  # Given a string containing data, and a string containing
@@ -39,7 +82,7 @@ module Gem::OpenPGP
39
82
  # then raise an exception.
40
83
  #
41
84
  # Optionally tell gpg to retrive the key if it's not provided
42
- def self.verify data, sig, get_key=false, homedir=nil
85
+ def self.verify file_name, data, sig, get_key=false, homedir=nil
43
86
  is_gpg_available
44
87
  is_homedir_valid homedir if homedir
45
88
 
@@ -51,10 +94,22 @@ module Gem::OpenPGP
51
94
 
52
95
  homedir_flags = ""
53
96
  homedir_flags = "--homedir #{homedir}" if homedir
54
-
55
- cmd = "gpg #{get_key_params} #{homedir_flags} --verify #{sig_file.path} #{data_file.path}"
56
- res, err = run_gpg_command cmd
57
- [err, res]
97
+
98
+ gpg_args = "#{get_key_params} #{homedir_flags} --verify #{sig_file.path} #{data_file.path}"
99
+
100
+ status_info = {:file_name => file_name}
101
+ gpg_results = run_gpg(gpg_args) { |message| verify_extract_status_info(message, status_info) }
102
+
103
+ if status_info[:failure]
104
+ say add_color(status_info[:failure], :red)
105
+ raise Gem::OpenPGPException, "Fail!"
106
+ else
107
+ verify_check_sig status_info
108
+ end
109
+
110
+ did_gpg_error? gpg_results
111
+
112
+ [gpg_results[:stderr], gpg_results[:status]]
58
113
  end
59
114
 
60
115
  # Signs an existing gemfile by iterating the tar'ed up contents,
@@ -128,7 +183,6 @@ module Gem::OpenPGP
128
183
 
129
184
  tar_files.keys.each do |file_name|
130
185
  next if file_name[-4..-1] == ".asc"
131
- say "Verifying #{file_name}..."
132
186
 
133
187
  sig_file_name = file_name + ".asc"
134
188
  if !tar_files.has_key? sig_file_name
@@ -137,10 +191,8 @@ module Gem::OpenPGP
137
191
  end
138
192
 
139
193
  begin
140
- err, res = Gem::OpenPGP.verify(tar_files[file_name], tar_files[sig_file_name], get_key, homedir)
194
+ err, res = Gem::OpenPGP.verify(file_name, tar_files[file_name], tar_files[sig_file_name], get_key, homedir)
141
195
 
142
- say add_color(err, :green)
143
- say add_color(res, :green)
144
196
  rescue Gem::OpenPGPException => ex
145
197
  color_code = "31"
146
198
  say add_color(ex.message, :red)
@@ -154,6 +206,14 @@ module Gem::OpenPGP
154
206
 
155
207
  private
156
208
 
209
+ def self.did_gpg_error? gpg_results
210
+ if gpg_results[:status] != 0
211
+ say add_color("gpg returned unexpected status code", :red)
212
+ say add_color(gpg_results[:stderr], :red)
213
+ raise Gem::OpenPGPException, "gpg returned unexpected error code #{gpg_results[:status]}"
214
+ end
215
+ end
216
+
157
217
  # Tests to see if gpg is installed and available.
158
218
  def self.is_gpg_available
159
219
  err_msg = "Unable to find a working gnupg installation. Make sure gnupg is installed and you can call 'gpg --version' from a command prompt."
@@ -177,18 +237,24 @@ private
177
237
  end
178
238
  end
179
239
 
180
- def self.run_gpg_command cmd, data=nil
240
+ def self.run_gpg args, data=nil, &block
181
241
  exit_status = nil
182
- stdout, stderr = Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
242
+ status_file = Tempfile.new("status")
243
+
244
+ full_gpg_command = "gpg --status-file #{status_file.path} #{args}"
245
+ gpg_results = Open3.popen3(full_gpg_command) do |stdin, stdout, stderr, wait_thr|
183
246
  stdin.write data if data
184
247
  stdin.close
185
248
  exit_status = wait_thr.value
249
+ GPGStatusParser.parse(status_file, &block)
186
250
  out = stdout.read()
187
251
  err = stderr.read()
188
- raise Gem::OpenPGPException, "#{err}" if exit_status != 0
189
- [out,err]
252
+ {:status => exit_status, :stdout => out, :err => err}
190
253
  end
191
- [stdout, stderr]
254
+ gpg_results
255
+ ensure
256
+ status_file.close
257
+ status_file.unlink
192
258
  end
193
259
 
194
260
  def self.create_tempfile data
@@ -203,6 +269,7 @@ private
203
269
  color_code = case color
204
270
  when :green then "32"
205
271
  when :red then "31"
272
+ when :yellow then "33"
206
273
  else raise RuntimeError, "Invalid color #{color.inspect}"
207
274
  end
208
275
 
@@ -38,6 +38,21 @@ i.add_option("--verify",
38
38
  Gem::OpenPGP.options[:verify] = true
39
39
  end
40
40
 
41
+ i.add_option("--no-verify",
42
+ "Don't verify a gem, even if --verify has previously been specified") do |value, options|
43
+ Gem::OpenPGP.options[:no_verify] = true
44
+ end
45
+
46
+ i = Gem::CommandManager.instance[:install]
47
+ i.add_option("--trust",
48
+ 'Enforce gnupg trust settings. Only install if trusted.') do |value, options|
49
+ Gem::OpenPGP.options[:trust] = true
50
+ end
51
+
52
+ i.add_option("--no-trust",
53
+ "Ignoure gnupg trust settings, even if --trust has previously been specified") do |value, options|
54
+ Gem::OpenPGP.options[:no_trust] = true
55
+ end
41
56
 
42
57
  i.add_option('--get-key', "If the key is not available, download it from a keyserver") do |key, options|
43
58
  Gem::OpenPGP.options[:get_key] = true
@@ -45,7 +60,8 @@ end
45
60
 
46
61
  Gem.pre_install do |installer|
47
62
  begin
48
- if Gem::OpenPGP.options[:verify]
63
+ # --no-verify overrides --verify
64
+ if Gem::OpenPGP.options[:verify] && !Gem::OpenPGP.options[:no_verify]
49
65
  Gem::OpenPGP.verify_gem(installer.gem,
50
66
  Gem::OpenPGP.options[:get_key])
51
67
  end
data.tar.gz.asc CHANGED
@@ -1,11 +1,11 @@
1
1
  -----BEGIN PGP SIGNATURE-----
2
2
  Version: GnuPG/MacGPG2 v2.0.17 (Darwin)
3
3
 
4
- iQEcBAABCgAGBQJRF6UkAAoJEP5F5V2hilTWp4EH/Ah94Ny5XMyjejkTuTAZPZw8
5
- 6jG5gQ0dl5l8c6VyXgLNwSDmCt0Rj5J1ZVvkz8LXj7xJpDyXu77Gk2FCDS30R7vH
6
- 4C3LbUdIGv5FhMGQ2CiVgPNbi8CRsNmnFg15otY782Uvu8sMbspkrVi31wFvWCz7
7
- Ik9tHle42aNwg5sYhYWi4gIHiLfQ3l+g6C2YJ38R/hKdU9J3Vu9RWxk3aAsSsuTp
8
- aEDxGvTkX+N9vUEdDIvpkZ7iuhATxiP4TpZo3vFORe0iwo44XQaZJQPb4jMKmnJt
9
- b9Q7a1o/WpmcPrnGDaHvsjPj4P5dFzaktDaafBCo7GUsws7JhN1sKZX1F4GSVjc=
10
- =FURw
4
+ iQEcBAABCgAGBQJRKNObAAoJEP5F5V2hilTWjFYH/RPGxYJA41R43Yrgqu56vtAU
5
+ iPY/pg041S42UnObIIFgA76fMeixzfFCdBkvFFnlDuqmbSLxtiJt0Q/ql5c/hFzA
6
+ S/rKibb1I9nlzOJ3p/GO78HzaD/M2Ja/jdrJtt+w7LVqSVtfDOyS+lPe3wxzf6SS
7
+ 7hgpycQv6GX3C5AEGY/nP0btkDxNtYMGGgcYz3WfrOEQFDIKS6IU4iZCj5c6Zw4n
8
+ yD2pAvHWoqdkYy0y+eUsi83E1zCL9fHEK3R/I+c9Kc4TQF2OXFmGZdc7wbYwtdPb
9
+ yDqlTNo8mbm+kxek1P4PobHJ7QADHRC7kOSBMOXVw80JALUThAt11Y+bHOHv3/Y=
10
+ =58pK
11
11
  -----END PGP SIGNATURE-----
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: rubygems-openpgp
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.3.0
5
+ version: 0.4.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Grant Olson
@@ -10,10 +10,20 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2013-02-10 00:00:00 Z
14
- dependencies: []
15
-
16
- description: Digitally sign gems via OpenPGP instead of OpenSSL
13
+ date: 2013-02-23 00:00:00 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: gpg_status_parser
17
+ prerelease: false
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.3.0
24
+ type: :runtime
25
+ version_requirements: *id001
26
+ description: Digitally sign gems via OpenPGP.
17
27
  email: kgo@grant-olson.net
18
28
  executables: []
19
29
 
metadata.gz.asc CHANGED
@@ -1,11 +1,11 @@
1
1
  -----BEGIN PGP SIGNATURE-----
2
2
  Version: GnuPG/MacGPG2 v2.0.17 (Darwin)
3
3
 
4
- iQEcBAABCgAGBQJRF6UqAAoJEP5F5V2hilTW4WgIAL4AJ1PPxZv+AuAwxBOFgIqR
5
- m8tM5N9bNM+KVwBplbIpl1cP/VJFN6onDeNlEY0YlCSR/EHuCOvtjCB8AFquAy72
6
- +zNxniM0d9zcEL0JRx2SLl44EBQOaFAYZ6VgLbkox9OuwUjSeEfdo66gfMtgdkHN
7
- +Tl5XKjnu5cnszfBXqfHKLdSjhAYbk0TeGRicffFDLMn7jzwwmOd9uLMmG3CrPg0
8
- mZiZpYWoazFPDnQ+KKj12ojcUCjFc/D8Xy77e2G2PP8kVOKb79Gn6Fd+npJuXL1X
9
- /8Uzkrpwc3EGCpMzT0/q4EyHc35CkaFtdbAhd4n33Rob4j+yIhi0j72tttfv1Jk=
10
- =VFwb
4
+ iQEcBAABCgAGBQJRKNOhAAoJEP5F5V2hilTWcBgIAIob5FD4SK6UxfnXQk0U+5nP
5
+ huK6hsanhLbH3m3fqz2BkB/WBVonF0sqO2zNIw+qxnIl/r426iXmxTfNYF3F+0Ri
6
+ mP7YF+HBNfuElraRBBKUXSCQoB0yxqLpx3mcDwjB//0Q9CWXdeCLzefbs7+4ca4q
7
+ rBezyxSxRXun2qBMBs7FSZYkC6rsP58EgTi555WfxymiqEZ9fEi1r4rEM37F+z2w
8
+ FBMlYjTJhATOIhHTi8nFQoGgjFcQG9a7cgABHGZwB9IR6k5O6IeTHVXCQvOlg4au
9
+ cj6HKS8YKpJGZPlPIJVpLmW9UhUQukg4AwTpPAHIeIiwZYahitQtm0Ra5MnSJtc=
10
+ =bh2W
11
11
  -----END PGP SIGNATURE-----