rubygems-openpgp 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- checksums.yaml.gz.asc +11 -0
- data.tar.gz.asc +8 -8
- data/README.md +20 -19
- data/lib/rubygems/gem_openpgp.rb +2 -284
- data/lib/rubygems/openpgp/gpg_helpers.rb +24 -0
- data/lib/rubygems/openpgp/keymaster.rb +74 -0
- data/lib/rubygems/openpgp/openpgpexception.rb +1 -0
- data/lib/rubygems/openpgp/options.rb +10 -0
- data/lib/rubygems/openpgp/sign_plugins.rb +31 -0
- data/lib/rubygems/openpgp/signing.rb +109 -0
- data/lib/rubygems/openpgp/verification.rb +180 -0
- data/lib/rubygems/openpgp/verify_plugins.rb +45 -0
- data/lib/rubygems_plugin.rb +2 -70
- data/test/test_keymaster.rb +31 -0
- data/test/test_rubygems-openpgp.rb +6 -2
- metadata +61 -41
- metadata.gz.asc +8 -8
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0657ab763223c89affb7cfdbdfe7227ba093a0c0
|
4
|
+
data.tar.gz: 7b16826241b21a82815b8baa681697ad7e0f3983
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b3c5a89a986acbcd84aaee04aae27aa5a68966529c830232be62cb64a3f7c62c59d1a18e749007477516227bcdf5969a3c0b1507a62aaa55c6bd84c82f6a9244
|
7
|
+
data.tar.gz: adeb6e5b33bb455ff52f90405744417d566af3b721cc829576b8eba9eeed7c0cc7fa5072393bf0e4ce4c1c6020f0e8e85883c97d89ad5482894a26431f628bd6
|
checksums.yaml.gz.asc
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
-----BEGIN PGP SIGNATURE-----
|
2
|
+
Version: GnuPG v1.4.11 (GNU/Linux)
|
3
|
+
|
4
|
+
iQEcBAABAgAGBQJRPJV6AAoJEP5F5V2hilTW55oH/RVctpv/kKf8erckN0vvNZUa
|
5
|
+
KdtcULIoD0P8u26uiL8zTM4noWi2f3kkfv1fAd9026IsJarOpucfDmpZpTDb88Xw
|
6
|
+
gElUTXKhG7bnoPhuEfrz6/h5cwMpQREktIbVwtCF0ED7aRLbxcUChx+BfFLLeUW1
|
7
|
+
yLnwi8aN2EJlcL1w8fvDmPux6IppuZ/NPxo65dXVHIsjpyLvhrNhqaEOEHv2AP9b
|
8
|
+
xNWSV+sn8i9YfVUZhmZLLakWkmfoRGrZYXQYisTQbKfN5Kfeyg3uJRcQ9kk8Kmua
|
9
|
+
5UBTLEk/T2meyaN7FQ8l23P5ZNxcRhqDWnGKJMxRZxaShVJk4P8hmhgICL/YX6w=
|
10
|
+
=CtND
|
11
|
+
-----END PGP SIGNATURE-----
|
data.tar.gz.asc
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
-----BEGIN PGP SIGNATURE-----
|
2
|
-
Version: GnuPG
|
2
|
+
Version: GnuPG v1.4.11 (GNU/Linux)
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
=
|
4
|
+
iQEcBAABAgAGBQJRPJV3AAoJEP5F5V2hilTWJnAH/jyebr8gp9guDxLVuN3lodD9
|
5
|
+
OLjYgkI97P7e597lL7LDyMpadyo01yQjB1+xfKNQqgAaUtVUglfaeGjU+vnvpfAz
|
6
|
+
5Hx/SdztlhDnzK+W71wzdBJ6/8Nco6wDhDe8dQcM3BgSK2ijvHgCfYMqy9SoKGgC
|
7
|
+
ZHNWq+a2cPd8nglgaR2iTlN+0kzQq/f4WdGFOuCliq5E5ItFlCzMiSnVUfAvyT2G
|
8
|
+
lOvnxYvzMOItxQMHU9lVvGvYhUxsUd4bvRMBvy3rdbErnp3zFFSu2tHTEvoJt2+v
|
9
|
+
LvzBaiQ+u00qirlusp1amEHurUK7bPSuTSWN98fnrh5DaFwzh/hd1Cjrr0FY1xY=
|
10
|
+
=rKlC
|
11
11
|
-----END PGP SIGNATURE-----
|
data/README.md
CHANGED
@@ -1,6 +1,12 @@
|
|
1
1
|
rubygems-openpgp
|
2
2
|
================
|
3
3
|
|
4
|
+
Information for gem users and gem developers is slowly and surely migrating
|
5
|
+
to the [rubygems-openpgp Certificate
|
6
|
+
Authority](http://rubygems-openpgp-ca.org). You probably want to go
|
7
|
+
there unless you're interested in working on the plugin itself.
|
8
|
+
|
9
|
+
|
4
10
|
Software Assurance
|
5
11
|
------------------
|
6
12
|
|
@@ -44,33 +50,28 @@ Signing example
|
|
44
50
|
Verification Example
|
45
51
|
--------------------
|
46
52
|
|
53
|
+
A detailed walkthrough of verifiction is available at
|
54
|
+
[The Complete Guide to Verifying Gems with
|
55
|
+
rubygems-openpgp](http://www.rubygems-openpgp-ca.org/blog/the-complete-guide-to-verifying-gems-with-rubygems-openpgp.html)
|
56
|
+
|
57
|
+
### TLDR?
|
58
|
+
|
47
59
|
A test gem **openpgp_signed_hola** is on rubygems.org. To try out
|
48
60
|
this extension:
|
49
61
|
|
50
|
-
gem install openpgp_signed_hola-0.0.0.gem --verify
|
62
|
+
gem install openpgp_signed_hola-0.0.0.gem --verify --trust --get-key
|
51
63
|
|
52
|
-
But That Just Failed!
|
53
|
-
---------------------
|
54
64
|
|
55
|
-
|
56
|
-
verify the digital signature. You also want to perform some
|
57
|
-
authentication of that public key.
|
65
|
+
### But That Just Failed!
|
58
66
|
|
59
|
-
|
67
|
+
You probably don't *trust* my public key. More information is
|
68
|
+
available at [The Complete Guide to Verifying Gems with
|
69
|
+
rubygems-openpgp](http://www.rubygems-openpgp-ca.org/blog/the-complete-guide-to-verifying-gems-with-rubygems-openpgp.html)
|
60
70
|
|
61
71
|
Verifying your initial install
|
62
72
|
------------------------------
|
63
73
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
But if that copy isn't verified, if could already be compromised.
|
68
|
-
|
69
|
-
But don't worry. You can use a stand-alone signature to verify your
|
70
|
-
initial install. Since the stand-alone signature is on github, and
|
71
|
-
the software package is on rubygems.org, a malicious user would need
|
72
|
-
to compromise both sites to publish a compromised gem and
|
73
|
-
compromised/forged digital signature.
|
74
|
-
|
75
|
-
[Notes on verifying the initial install.](./doc/verifying-initial-install.md)
|
74
|
+
You can verify your initial install with a detached signature.
|
75
|
+
[Here's
|
76
|
+
how.](http://www.rubygems-openpgp-ca.org/blog/the-complete-guide-to-verifying-your-initial-install.html)
|
76
77
|
|
data/lib/rubygems/gem_openpgp.rb
CHANGED
@@ -1,284 +1,2 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'rubygems/
|
3
|
-
require 'rubygems/user_interaction'
|
4
|
-
require 'shellwords'
|
5
|
-
require 'open3'
|
6
|
-
require 'tempfile'
|
7
|
-
require 'gpg_status_parser'
|
8
|
-
|
9
|
-
# Exception for this class
|
10
|
-
class Gem::OpenPGPException < RuntimeError; end
|
11
|
-
|
12
|
-
# A wrapper that shells out the real OpenPGP crypto work
|
13
|
-
# to gpg.
|
14
|
-
module Gem::OpenPGP
|
15
|
-
extend Shellwords
|
16
|
-
extend Gem::UserInteraction
|
17
|
-
|
18
|
-
# Given a string of data, generate and return a detached
|
19
|
-
# signature. By defualt, this will use your primary secret key.
|
20
|
-
# This can be overridden by specifying a key_id for another
|
21
|
-
# private key.
|
22
|
-
def self.detach_sign data, key_id=nil, homedir=nil
|
23
|
-
is_gpg_available
|
24
|
-
is_key_valid key_id if key_id
|
25
|
-
is_homedir_valid homedir if homedir
|
26
|
-
|
27
|
-
key_flag = ""
|
28
|
-
key_flag = "-u #{shellescape(key_id)}" if key_id
|
29
|
-
|
30
|
-
homedir_flag = ""
|
31
|
-
homedir_flag = "--homedir #{shellescape(homedir)}" if homedir
|
32
|
-
|
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
|
78
|
-
end
|
79
|
-
|
80
|
-
# Given a string containing data, and a string containing
|
81
|
-
# a detached signature, verify the data. If we can't verify
|
82
|
-
# then raise an exception.
|
83
|
-
#
|
84
|
-
# Optionally tell gpg to retrive the key if it's not provided
|
85
|
-
def self.verify file_name, data, sig, get_key=false, homedir=nil
|
86
|
-
is_gpg_available
|
87
|
-
is_homedir_valid homedir if homedir
|
88
|
-
|
89
|
-
data_file = create_tempfile data
|
90
|
-
sig_file = create_tempfile sig
|
91
|
-
|
92
|
-
get_key_params = "--keyserver pool.sks-keyservers.net --keyserver-options auto-key-retrieve"
|
93
|
-
get_key_params = "" if get_key != true
|
94
|
-
|
95
|
-
homedir_flags = ""
|
96
|
-
homedir_flags = "--homedir #{homedir}" if homedir
|
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]]
|
113
|
-
end
|
114
|
-
|
115
|
-
# Signs an existing gemfile by iterating the tar'ed up contents,
|
116
|
-
# and signing any contents. creating a new file with original contents
|
117
|
-
# and OpenPGP sigs. The OpenPGP sigs are saved as .asc files so they
|
118
|
-
# won't conflict with X509 sigs.
|
119
|
-
#
|
120
|
-
# Optional param "key" allows you to use a different private
|
121
|
-
# key than the GPG default.
|
122
|
-
def self.sign_gem gem, key=nil, homedir=nil
|
123
|
-
unsigned_gem = gem + ".unsigned"
|
124
|
-
|
125
|
-
begin
|
126
|
-
FileUtils.mv gem, unsigned_gem
|
127
|
-
rescue Errno::ENOENT => ex
|
128
|
-
raise Gem::CommandLineError, "The gem #{gem} does not seem to exist. (#{ex.message})"
|
129
|
-
end
|
130
|
-
|
131
|
-
unsigned_gem_file = File.open(unsigned_gem, "r")
|
132
|
-
signed_gem_file = File.open(gem, "w")
|
133
|
-
|
134
|
-
signed_gem = Gem::Package::TarWriter.new(signed_gem_file)
|
135
|
-
|
136
|
-
Gem::Package::TarReader.new(unsigned_gem_file).each do |f|
|
137
|
-
say(f.full_name.inspect)
|
138
|
-
|
139
|
-
if f.full_name[-4..-1] == ".asc"
|
140
|
-
say("Skipping old signature file #{f.full_name}")
|
141
|
-
next
|
142
|
-
end
|
143
|
-
|
144
|
-
say("Signing #{f.full_name.inspect}...")
|
145
|
-
|
146
|
-
file_contents = f.read()
|
147
|
-
|
148
|
-
signed_gem.add_file(f.full_name, 0644) do |outfile|
|
149
|
-
outfile.write(file_contents)
|
150
|
-
end
|
151
|
-
|
152
|
-
signed_gem.add_file(f.full_name + ".asc", 0644) do |outfile|
|
153
|
-
outfile.write(Gem::OpenPGP.detach_sign(file_contents,key,homedir))
|
154
|
-
end
|
155
|
-
|
156
|
-
end
|
157
|
-
|
158
|
-
signed_gem_file.close
|
159
|
-
unsigned_gem_file.close
|
160
|
-
File.delete unsigned_gem_file
|
161
|
-
|
162
|
-
rescue Exception => ex
|
163
|
-
if unsigned_gem_file
|
164
|
-
FileUtils.mv unsigned_gem_file, gem
|
165
|
-
end
|
166
|
-
|
167
|
-
raise
|
168
|
-
end
|
169
|
-
|
170
|
-
def self.verify_gem gem, get_key=false, homedir=nil
|
171
|
-
|
172
|
-
begin
|
173
|
-
file = File.open(gem,"r")
|
174
|
-
rescue Errno::ENOENT => ex
|
175
|
-
raise Gem::CommandLineError, "Gem #{gem} not found. Note you can only verify local gems at this time, so you may need to run 'gem fetch #{gem}' before verifying."
|
176
|
-
end
|
177
|
-
|
178
|
-
tar_files = {}
|
179
|
-
|
180
|
-
Gem::Package::TarReader.new(file).each do |f|
|
181
|
-
tar_files[f.full_name] = f.read()
|
182
|
-
end
|
183
|
-
|
184
|
-
tar_files.keys.each do |file_name|
|
185
|
-
next if file_name[-4..-1] == ".asc"
|
186
|
-
|
187
|
-
sig_file_name = file_name + ".asc"
|
188
|
-
if !tar_files.has_key? sig_file_name
|
189
|
-
say add_color("WARNING!!! No sig found for #{file_name}", :red)
|
190
|
-
raise Gem::OpenPGPException, "Can't verify without sig, aborting!!!"
|
191
|
-
end
|
192
|
-
|
193
|
-
begin
|
194
|
-
err, res = Gem::OpenPGP.verify(file_name, tar_files[file_name], tar_files[sig_file_name], get_key, homedir)
|
195
|
-
|
196
|
-
rescue Gem::OpenPGPException => ex
|
197
|
-
color_code = "31"
|
198
|
-
say add_color(ex.message, :red)
|
199
|
-
raise
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
|
-
ensure
|
204
|
-
file.close unless file.nil?
|
205
|
-
end
|
206
|
-
|
207
|
-
private
|
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
|
-
|
217
|
-
# Tests to see if gpg is installed and available.
|
218
|
-
def self.is_gpg_available
|
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."
|
220
|
-
`gpg --version`
|
221
|
-
raise Gem::OpenPGPException, err_msg if $? != 0
|
222
|
-
rescue Errno::ENOENT => ex
|
223
|
-
raise Gem::OpenPGPException, err_msg if $? != 0
|
224
|
-
end
|
225
|
-
|
226
|
-
def self.is_key_valid key_id
|
227
|
-
valid = /^0x[A-Za-z0-9]{8,8}/.match(key_id)
|
228
|
-
if valid.nil?
|
229
|
-
err_msg = "Invalid key id. Keys should be in form of 0xDEADBEEF"
|
230
|
-
raise Gem::OpenPGPException, err_msg
|
231
|
-
end
|
232
|
-
end
|
233
|
-
|
234
|
-
def self.is_homedir_valid homedir
|
235
|
-
if !File.exists? homedir
|
236
|
-
raise OpenPGPException, "Bad homedir #{homedir.inspect}"
|
237
|
-
end
|
238
|
-
end
|
239
|
-
|
240
|
-
def self.run_gpg args, data=nil, &block
|
241
|
-
exit_status = nil
|
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|
|
246
|
-
stdin.write data if data
|
247
|
-
stdin.close
|
248
|
-
exit_status = wait_thr.value
|
249
|
-
GPGStatusParser.parse(status_file, &block)
|
250
|
-
out = stdout.read()
|
251
|
-
err = stderr.read()
|
252
|
-
{:status => exit_status, :stdout => out, :err => err}
|
253
|
-
end
|
254
|
-
gpg_results
|
255
|
-
ensure
|
256
|
-
status_file.close
|
257
|
-
status_file.unlink
|
258
|
-
end
|
259
|
-
|
260
|
-
def self.create_tempfile data
|
261
|
-
temp_file = Tempfile.new("rubygems_gpg")
|
262
|
-
temp_file.binmode
|
263
|
-
temp_file.write(data)
|
264
|
-
temp_file.close
|
265
|
-
temp_file
|
266
|
-
end
|
267
|
-
|
268
|
-
def self.add_color s, color=:green
|
269
|
-
color_code = case color
|
270
|
-
when :green then "32"
|
271
|
-
when :red then "31"
|
272
|
-
when :yellow then "33"
|
273
|
-
else raise RuntimeError, "Invalid color #{color.inspect}"
|
274
|
-
end
|
275
|
-
|
276
|
-
#TODO - NO-OP on windows
|
277
|
-
"\033[#{color_code}m#{s}\033[0m"
|
278
|
-
end
|
279
|
-
|
280
|
-
def self.options
|
281
|
-
@options ||= {}
|
282
|
-
@options
|
283
|
-
end
|
284
|
-
end
|
1
|
+
require 'rubygems/openpgp/signing'
|
2
|
+
require 'rubygems/openpgp/verification'
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Gem::OpenPGP
|
2
|
+
extend Gem::UserInteraction
|
3
|
+
|
4
|
+
private
|
5
|
+
|
6
|
+
def self.did_gpg_error? gpg_results
|
7
|
+
if gpg_results[:status] != 0
|
8
|
+
say add_color("gpg returned unexpected status code", :red)
|
9
|
+
say add_color(gpg_results[:stdout], :yellow)
|
10
|
+
say add_color(gpg_results[:stderr], :red)
|
11
|
+
raise Gem::OpenPGPException, "gpg returned unexpected error code #{gpg_results[:status]}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Tests to see if gpg is installed and available.
|
16
|
+
def self.is_gpg_available
|
17
|
+
err_msg = "Unable to find a working gnupg installation. Make sure gnupg is installed and you can call 'gpg --version' from a command prompt."
|
18
|
+
`gpg --version`
|
19
|
+
raise Gem::OpenPGPException, err_msg if $? != 0
|
20
|
+
rescue Errno::ENOENT => ex
|
21
|
+
raise Gem::OpenPGPException, err_msg if $? != 0
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Gem::OpenPGP
|
2
|
+
# Capture used signing keys so we can see if they changed.
|
3
|
+
module KeyMaster
|
4
|
+
SETTING_DIR = ".rubygems-openpgp"
|
5
|
+
KEYMASTER_FILE = "known_gems"
|
6
|
+
|
7
|
+
def self.full_setting_filename
|
8
|
+
home_dir = ENV["HOME"] || ENV["HOMEPATH"]
|
9
|
+
File.join(home_dir, SETTING_DIR, KEYMASTER_FILE)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.touch_keymaster_file
|
13
|
+
home_dir = ENV["HOME"] || ENV["HOMEPATH"]
|
14
|
+
|
15
|
+
setting_dir = File.join(home_dir, SETTING_DIR)
|
16
|
+
Dir.mkdir(setting_dir, 0700) if !File.directory? setting_dir
|
17
|
+
|
18
|
+
if !File.exists?(full_setting_filename)
|
19
|
+
File.open(full_setting_filename,"w").close
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.load_fingerprints
|
24
|
+
touch_keymaster_file
|
25
|
+
|
26
|
+
home_dir = ENV["HOME"] || ENV["HOMEPATH"]
|
27
|
+
|
28
|
+
fingerprints = {}
|
29
|
+
File.open(full_setting_filename) do |f|
|
30
|
+
f.readlines.each do |line|
|
31
|
+
gem, fingerprint = line.strip.split("\t")
|
32
|
+
fingerprints[gem] = fingerprint
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
fingerprints
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.save_fingerprints fingerprints
|
40
|
+
touch_keymaster_file
|
41
|
+
|
42
|
+
File.open(full_setting_filename,"w") do |f|
|
43
|
+
fingerprints.each_pair do |gem, fingerprint|
|
44
|
+
f.puts("#{gem}\t#{fingerprint}")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.get_fingerprint gem_name
|
50
|
+
load_fingerprints[gem_name]
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.add_fingerprint gem_name, fingerprint
|
54
|
+
fingerprints = load_fingerprints
|
55
|
+
fingerprints[gem_name] = fingerprint
|
56
|
+
save_fingerprints fingerprints
|
57
|
+
end
|
58
|
+
|
59
|
+
# Check that an existing gem fingerprint matches a given fingerprint.
|
60
|
+
# In the case we haven't seen the gem before, we'll add the fingerprint
|
61
|
+
# and won't complain.
|
62
|
+
def self.check_fingerprint gem_name, fingerprint
|
63
|
+
fingerprints = load_fingerprints
|
64
|
+
|
65
|
+
if !fingerprints.has_key?(gem_name)
|
66
|
+
add_fingerprint gem_name, fingerprint
|
67
|
+
return true
|
68
|
+
end
|
69
|
+
|
70
|
+
fingerprints[gem_name] == fingerprint
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
class Gem::OpenPGPException < RuntimeError; end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'rubygems/command_manager'
|
2
|
+
require 'rubygems/gem_openpgp'
|
3
|
+
|
4
|
+
Gem::CommandManager.instance.register_command :sign
|
5
|
+
|
6
|
+
# gem build hooks
|
7
|
+
b = Gem::CommandManager.instance[:build]
|
8
|
+
b.add_option("--sign", "Sign gem with OpenPGP.") do |value, options|
|
9
|
+
Gem::OpenPGP.options[:sign] = true
|
10
|
+
end
|
11
|
+
|
12
|
+
b.add_option('--key KEY', "Specify key id if you don't want to use your default gpg key") do |key, options|
|
13
|
+
Gem::OpenPGP.options[:key] = key
|
14
|
+
end
|
15
|
+
|
16
|
+
class Gem::Commands::BuildCommand
|
17
|
+
alias_method :original_execute, :execute
|
18
|
+
def execute
|
19
|
+
original_execute
|
20
|
+
|
21
|
+
if Gem::OpenPGP.options[:sign]
|
22
|
+
gemspec = get_one_gem_name
|
23
|
+
if File.exist? gemspec then
|
24
|
+
spec = Gem::Specification.load gemspec
|
25
|
+
file_name = File.join(".", File.basename(spec.cache_file))
|
26
|
+
Gem::OpenPGP.sign_gem file_name, key=Gem::OpenPGP.options[:key]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rubygems/package'
|
3
|
+
require 'rubygems/user_interaction'
|
4
|
+
require 'gpg_status_parser'
|
5
|
+
require 'rubygems/openpgp/gpg_helpers'
|
6
|
+
require 'rubygems/openpgp/openpgpexception'
|
7
|
+
require 'shellwords'
|
8
|
+
|
9
|
+
module Gem::OpenPGP
|
10
|
+
extend Shellwords
|
11
|
+
|
12
|
+
# Given a string of data, generate and return a detached
|
13
|
+
# signature. By defualt, this will use your primary secret key.
|
14
|
+
# This can be overridden by specifying a key_id for another
|
15
|
+
# private key.
|
16
|
+
def self.detach_sign data, key_id=nil, homedir=nil
|
17
|
+
is_gpg_available
|
18
|
+
is_key_valid key_id if key_id
|
19
|
+
is_homedir_valid homedir if homedir
|
20
|
+
|
21
|
+
key_flag = ""
|
22
|
+
key_flag = "-u #{shellescape(key_id)}" if key_id
|
23
|
+
|
24
|
+
homedir_flag = ""
|
25
|
+
homedir_flag = "--homedir #{shellescape(homedir)}" if homedir
|
26
|
+
|
27
|
+
gpg_args = "#{key_flag} #{homedir_flag} --detach-sign --armor"
|
28
|
+
gpg_results = GPGStatusParser.run_gpg(gpg_args, data)
|
29
|
+
did_gpg_error? gpg_results
|
30
|
+
|
31
|
+
gpg_results[:stdout]
|
32
|
+
end
|
33
|
+
|
34
|
+
# Signs an existing gemfile by iterating the tar'ed up contents,
|
35
|
+
# and signing any contents. creating a new file with original contents
|
36
|
+
# and OpenPGP sigs. The OpenPGP sigs are saved as .asc files so they
|
37
|
+
# won't conflict with X509 sigs.
|
38
|
+
#
|
39
|
+
# Optional param "key" allows you to use a different private
|
40
|
+
# key than the GPG default.
|
41
|
+
def self.sign_gem gem, key=nil, homedir=nil
|
42
|
+
unsigned_gem = gem + ".unsigned"
|
43
|
+
|
44
|
+
begin
|
45
|
+
FileUtils.mv gem, unsigned_gem
|
46
|
+
rescue Errno::ENOENT => ex
|
47
|
+
raise Gem::CommandLineError, "The gem #{gem} does not seem to exist. (#{ex.message})"
|
48
|
+
end
|
49
|
+
|
50
|
+
unsigned_gem_file = File.open(unsigned_gem, "r")
|
51
|
+
signed_gem_file = File.open(gem, "w")
|
52
|
+
|
53
|
+
signed_gem = Gem::Package::TarWriter.new(signed_gem_file)
|
54
|
+
|
55
|
+
Gem::Package::TarReader.new(unsigned_gem_file).each do |f|
|
56
|
+
|
57
|
+
if f.full_name[-4..-1] == ".asc"
|
58
|
+
say("Skipping old OpenPGP signature file #{f.full_name}")
|
59
|
+
next
|
60
|
+
end
|
61
|
+
|
62
|
+
file_contents = f.read()
|
63
|
+
|
64
|
+
# Copy file no matter what
|
65
|
+
signed_gem.add_file(f.full_name, 0644) do |outfile|
|
66
|
+
outfile.write(file_contents)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Only sign if it's really part of the gem and not
|
70
|
+
# a X.509 sig
|
71
|
+
if f.full_name[-3..-1] == ".gz"
|
72
|
+
say add_color("Signing #{f.full_name.inspect}...",:green)
|
73
|
+
signed_gem.add_file(f.full_name + ".asc", 0644) do |outfile|
|
74
|
+
outfile.write(Gem::OpenPGP.detach_sign(file_contents,key,homedir))
|
75
|
+
end
|
76
|
+
elsif f.full_name[-4..-1] != ".sig"
|
77
|
+
say add_color("Not signing #{f.full_name.inspect}. Didn't expect to see that...",:yellow)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
signed_gem_file.close
|
82
|
+
unsigned_gem_file.close
|
83
|
+
File.delete unsigned_gem_file
|
84
|
+
|
85
|
+
rescue Exception => ex
|
86
|
+
if unsigned_gem_file
|
87
|
+
FileUtils.mv unsigned_gem_file, gem
|
88
|
+
end
|
89
|
+
|
90
|
+
raise
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
def self.is_key_valid key_id
|
96
|
+
valid = /^0x[A-Za-z0-9]{8,8}/.match(key_id)
|
97
|
+
if valid.nil?
|
98
|
+
err_msg = "Invalid key id. Keys should be in form of 0xDEADBEEF"
|
99
|
+
raise Gem::OpenPGPException, err_msg
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def self.is_homedir_valid homedir
|
104
|
+
if !File.exists? homedir
|
105
|
+
raise OpenPGPException, "Bad homedir #{homedir.inspect}"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
@@ -0,0 +1,180 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rubygems/package'
|
3
|
+
require 'rubygems/user_interaction'
|
4
|
+
|
5
|
+
require 'tempfile'
|
6
|
+
require 'rbconfig'
|
7
|
+
|
8
|
+
require 'gpg_status_parser'
|
9
|
+
|
10
|
+
require 'rubygems/openpgp/keymaster'
|
11
|
+
require 'rubygems/openpgp/options'
|
12
|
+
require 'rubygems/openpgp/gpg_helpers'
|
13
|
+
require 'rubygems/openpgp/openpgpexception'
|
14
|
+
|
15
|
+
module Gem::OpenPGP
|
16
|
+
extend Gem::UserInteraction
|
17
|
+
|
18
|
+
# Given a string containing data, and a string containing
|
19
|
+
# a detached signature, verify the data. If we can't verify
|
20
|
+
# then raise an exception.
|
21
|
+
#
|
22
|
+
# Optionally tell gpg to retrive the key if it's not provided
|
23
|
+
#
|
24
|
+
# returns the fingerprint used to sign the file
|
25
|
+
def self.verify file_name, data, sig, get_key=false, homedir=nil
|
26
|
+
is_gpg_available
|
27
|
+
is_homedir_valid homedir if homedir
|
28
|
+
|
29
|
+
data_file = create_tempfile data
|
30
|
+
sig_file = create_tempfile sig
|
31
|
+
|
32
|
+
get_key_params = "--keyserver pool.sks-keyservers.net --keyserver-options auto-key-retrieve"
|
33
|
+
get_key_params = "" if get_key != true
|
34
|
+
|
35
|
+
homedir_flags = ""
|
36
|
+
homedir_flags = "--homedir #{homedir}" if homedir
|
37
|
+
|
38
|
+
gpg_args = "#{get_key_params} #{homedir_flags} --verify #{sig_file.path} #{data_file.path}"
|
39
|
+
|
40
|
+
status_info = {:file_name => file_name}
|
41
|
+
gpg_results = GPGStatusParser.run_gpg(gpg_args) { |message| verify_extract_status_info(message, status_info) }
|
42
|
+
|
43
|
+
if status_info[:failure]
|
44
|
+
say add_color(status_info[:failure], :red)
|
45
|
+
raise Gem::OpenPGPException, "Fail!"
|
46
|
+
else
|
47
|
+
verify_check_sig status_info
|
48
|
+
end
|
49
|
+
|
50
|
+
did_gpg_error? gpg_results
|
51
|
+
|
52
|
+
status_info[:primary_key_fingerprint]
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.verify_gem gem, get_key=false, homedir=nil
|
56
|
+
raise Gem::CommandLineError, "Gem #{gem} not found." if !File.exists?(gem)
|
57
|
+
|
58
|
+
gem_name = if Gem::VERSION[0..1] == "2." #gotta be a better way
|
59
|
+
Gem::Package.new(gem).spec.name
|
60
|
+
else
|
61
|
+
Gem::Format.from_file_by_path(gem).spec.name
|
62
|
+
end
|
63
|
+
|
64
|
+
say("Verifying #{gem_name}...")
|
65
|
+
|
66
|
+
file = File.open(gem,"r")
|
67
|
+
|
68
|
+
fingerprints = []
|
69
|
+
tar_files = {}
|
70
|
+
|
71
|
+
Gem::Package::TarReader.new(file).each do |f|
|
72
|
+
tar_files[f.full_name] = f.read()
|
73
|
+
end
|
74
|
+
|
75
|
+
tar_files.keys.each do |file_name|
|
76
|
+
next if [".asc",".sig"].include? file_name[-4..-1]
|
77
|
+
|
78
|
+
if file_name[-3..-1] != ".gz"
|
79
|
+
say add_color("Skipping #{file_name}. Only expected .gz files...", :yellow)
|
80
|
+
next
|
81
|
+
end
|
82
|
+
|
83
|
+
sig_file_name = file_name + ".asc"
|
84
|
+
if !tar_files.has_key? sig_file_name
|
85
|
+
say add_color("WARNING!!! No sig found for #{file_name}", :red)
|
86
|
+
raise Gem::OpenPGPException, "Can't verify without sig, aborting!!!"
|
87
|
+
end
|
88
|
+
|
89
|
+
begin
|
90
|
+
fingerprints << Gem::OpenPGP.verify(file_name, tar_files[file_name], tar_files[sig_file_name], get_key, homedir)
|
91
|
+
rescue Gem::OpenPGPException => ex
|
92
|
+
color_code = "31"
|
93
|
+
say add_color(ex.message, :red)
|
94
|
+
raise
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Verify fingerprint
|
99
|
+
fingerprints.uniq.each do |fp|
|
100
|
+
verify_gem_check_fingerprint gem_name, fp
|
101
|
+
end
|
102
|
+
|
103
|
+
ensure
|
104
|
+
file.close unless file.nil?
|
105
|
+
end
|
106
|
+
|
107
|
+
private
|
108
|
+
|
109
|
+
# Extract the info we care about, throw away the rest
|
110
|
+
def self.verify_extract_status_info message, status_info
|
111
|
+
case message.status
|
112
|
+
when :GOODSIG, :BADSIG, :ERRSIG
|
113
|
+
status_info[:good_or_bad] = message.status
|
114
|
+
status_info[:uid] = (message.args[:username] || "").strip
|
115
|
+
|
116
|
+
when :SIG_ID
|
117
|
+
when :VALIDSIG, :EXPSIG, :BADSIG
|
118
|
+
status_info[:sig_status] = message.status
|
119
|
+
status_info[:primary_key] = "0x#{message.args[:primary_key_fpr][-9..-1]}"
|
120
|
+
status_info[:primary_key_fingerprint] = message.args[:primary_key_fpr]
|
121
|
+
when :TRUST_UNDEFINED, :TRUST_NEVER, :TRUST_MARGINAL, :TRUST_FULLY, :TRUST_ULTIMATE
|
122
|
+
status_info[:trust_status] = message.status
|
123
|
+
when :NO_PUBKEY
|
124
|
+
status_info[:failure] = "You don't have the public key. Use --get-key to automagically retrieve from keyservers"
|
125
|
+
when :IMPORTED, :IMPORT_OK, :IMPORT_RES
|
126
|
+
#silently_ignore
|
127
|
+
when :KEYEXPIRED, :SIGEXPIRED
|
128
|
+
# recalculating trust db, ignore.
|
129
|
+
else
|
130
|
+
puts "unexpected message: #{message.status} #{message.args.inspect}"
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# Print info about the sig, check that we like it, and possibly abort
|
135
|
+
def self.verify_check_sig status_info
|
136
|
+
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]}"
|
137
|
+
if status_info[:trust_status] == :TRUST_NEVER
|
138
|
+
say add_color(sig_msg, :red)
|
139
|
+
raise Gem::OpenPGPException, "Never Trusted. Won't install."
|
140
|
+
elsif status_info[:trust_status] == :TRUST_UNDEFINED
|
141
|
+
say add_color(sig_msg, :yellow)
|
142
|
+
if options[:trust] && !options[:no_trust]
|
143
|
+
raise Gem::OpenPGPException, "Trust Undefined and you've specified --trust. Won't install."
|
144
|
+
end
|
145
|
+
else
|
146
|
+
say add_color(sig_msg , :green)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def self.verify_gem_check_fingerprint gem_name, fingerprint
|
151
|
+
if !Gem::OpenPGP::KeyMaster.check_fingerprint(gem_name, fingerprint)
|
152
|
+
raise Gem::OpenPGPException, "Gem #{gem_name} fingerprint #{fingerprint} didn't match fingerprint in #{Gem::OpenPGP::KeyMaster.full_setting_filename}. Won't install!"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def self.create_tempfile data
|
157
|
+
temp_file = Tempfile.new("rubygems_gpg")
|
158
|
+
temp_file.binmode
|
159
|
+
temp_file.write(data)
|
160
|
+
temp_file.close
|
161
|
+
temp_file
|
162
|
+
end
|
163
|
+
|
164
|
+
def self.add_color s, color=:green
|
165
|
+
color_code = case color
|
166
|
+
when :green then "32"
|
167
|
+
when :red then "31"
|
168
|
+
when :yellow then "33"
|
169
|
+
else raise RuntimeError, "Invalid color #{color.inspect}"
|
170
|
+
end
|
171
|
+
|
172
|
+
if (RbConfig::CONFIG['host_os'] =~ /mswin|mingw/)
|
173
|
+
s # no colors on windows
|
174
|
+
else
|
175
|
+
"\033[#{color_code}m#{s}\033[0m"
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
179
|
+
|
180
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'rubygems/command_manager'
|
2
|
+
require 'rubygems/gem_openpgp'
|
3
|
+
|
4
|
+
Gem::CommandManager.instance.register_command :verify
|
5
|
+
|
6
|
+
# gem install hooks
|
7
|
+
i = Gem::CommandManager.instance[:install]
|
8
|
+
i.add_option("--verify",
|
9
|
+
'Verifies a local gem that has been signed via OpenPGP.' +
|
10
|
+
'This helps to ensure the gem has not been tampered with in transit.') do |value, options|
|
11
|
+
Gem::OpenPGP.options[:verify] = true
|
12
|
+
end
|
13
|
+
|
14
|
+
i.add_option("--no-verify",
|
15
|
+
"Don't verify a gem, even if --verify has previously been specified") do |value, options|
|
16
|
+
Gem::OpenPGP.options[:no_verify] = true
|
17
|
+
end
|
18
|
+
|
19
|
+
i = Gem::CommandManager.instance[:install]
|
20
|
+
i.add_option("--trust",
|
21
|
+
'Enforce gnupg trust settings. Only install if trusted.') do |value, options|
|
22
|
+
Gem::OpenPGP.options[:trust] = true
|
23
|
+
end
|
24
|
+
|
25
|
+
i.add_option("--no-trust",
|
26
|
+
"Ignoure gnupg trust settings, even if --trust has previously been specified") do |value, options|
|
27
|
+
Gem::OpenPGP.options[:no_trust] = true
|
28
|
+
end
|
29
|
+
|
30
|
+
i.add_option('--get-key', "If the key is not available, download it from a keyserver") do |key, options|
|
31
|
+
Gem::OpenPGP.options[:get_key] = true
|
32
|
+
end
|
33
|
+
|
34
|
+
Gem.pre_install do |installer|
|
35
|
+
begin
|
36
|
+
# --no-verify overrides --verify
|
37
|
+
if Gem::OpenPGP.options[:verify] && !Gem::OpenPGP.options[:no_verify]
|
38
|
+
Gem::OpenPGP.verify_gem(installer.gem,
|
39
|
+
Gem::OpenPGP.options[:get_key])
|
40
|
+
end
|
41
|
+
rescue Gem::OpenPGPException => ex
|
42
|
+
installer.alert_error(ex.message)
|
43
|
+
installer.terminate_interaction(1)
|
44
|
+
end
|
45
|
+
end
|
data/lib/rubygems_plugin.rb
CHANGED
@@ -1,72 +1,4 @@
|
|
1
|
-
require 'rubygems/command_manager'
|
2
1
|
require 'rubygems/gem_openpgp'
|
2
|
+
require 'rubygems/openpgp/sign_plugins'
|
3
|
+
require 'rubygems/openpgp/verify_plugins'
|
3
4
|
|
4
|
-
Gem::CommandManager.instance.register_command :sign
|
5
|
-
Gem::CommandManager.instance.register_command :verify
|
6
|
-
|
7
|
-
# gem build hooks
|
8
|
-
b = Gem::CommandManager.instance[:build]
|
9
|
-
b.add_option("--sign", "Sign gem with OpenPGP.") do |value, options|
|
10
|
-
Gem::OpenPGP.options[:sign] = true
|
11
|
-
end
|
12
|
-
|
13
|
-
b.add_option('--key KEY', "Specify key id if you don't want to use your default gpg key") do |key, options|
|
14
|
-
Gem::OpenPGP.options[:key] = key
|
15
|
-
end
|
16
|
-
|
17
|
-
class Gem::Commands::BuildCommand
|
18
|
-
alias_method :original_execute, :execute
|
19
|
-
def execute
|
20
|
-
original_execute
|
21
|
-
|
22
|
-
if Gem::OpenPGP.options[:sign]
|
23
|
-
gemspec = get_one_gem_name
|
24
|
-
if File.exist? gemspec then
|
25
|
-
spec = Gem::Specification.load gemspec
|
26
|
-
file_name = File.join(".", File.basename(spec.cache_file))
|
27
|
-
Gem::OpenPGP.sign_gem file_name, key=Gem::OpenPGP.options[:key]
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
# gem install hooks
|
34
|
-
i = Gem::CommandManager.instance[:install]
|
35
|
-
i.add_option("--verify",
|
36
|
-
'Verifies a local gem that has been signed via OpenPGP.' +
|
37
|
-
'This helps to ensure the gem has not been tampered with in transit.') do |value, options|
|
38
|
-
Gem::OpenPGP.options[:verify] = true
|
39
|
-
end
|
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
|
56
|
-
|
57
|
-
i.add_option('--get-key', "If the key is not available, download it from a keyserver") do |key, options|
|
58
|
-
Gem::OpenPGP.options[:get_key] = true
|
59
|
-
end
|
60
|
-
|
61
|
-
Gem.pre_install do |installer|
|
62
|
-
begin
|
63
|
-
# --no-verify overrides --verify
|
64
|
-
if Gem::OpenPGP.options[:verify] && !Gem::OpenPGP.options[:no_verify]
|
65
|
-
Gem::OpenPGP.verify_gem(installer.gem,
|
66
|
-
Gem::OpenPGP.options[:get_key])
|
67
|
-
end
|
68
|
-
rescue Gem::OpenPGPException => ex
|
69
|
-
installer.alert_error(ex.message)
|
70
|
-
installer.terminate_interaction(1)
|
71
|
-
end
|
72
|
-
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'mocha/setup'
|
3
|
+
|
4
|
+
require 'rubygems/openpgp/keymaster'
|
5
|
+
|
6
|
+
class KeymasterTest < Test::Unit::TestCase
|
7
|
+
def setup
|
8
|
+
Gem::OpenPGP::KeyMaster.stubs(:load_fingerprints => {"foo" => "DEADBEEF"},
|
9
|
+
:save_fingerprints => nil)
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
def test_good_fingerprint
|
14
|
+
assert_block("Good fingerprint test") do
|
15
|
+
Gem::OpenPGP::KeyMaster.check_fingerprint("foo", "DEADBEEF") == true
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_bad_fingerprint
|
20
|
+
assert_block("Bad fingerprint test") do
|
21
|
+
Gem::OpenPGP::KeyMaster.check_fingerprint("foo", "C00FFEE") != true
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_new_gem
|
26
|
+
assert_block("New gem test") do
|
27
|
+
Gem::OpenPGP::KeyMaster.check_fingerprint("bar", "C00FFEE") == true
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -1,4 +1,6 @@
|
|
1
1
|
require 'test/unit'
|
2
|
+
require 'mocha/setup'
|
3
|
+
|
2
4
|
require 'rubygems_plugin'
|
3
5
|
require 'rubygems/gem_openpgp'
|
4
6
|
require 'tmpdir'
|
@@ -19,6 +21,8 @@ class RubygemsPluginTest < Test::Unit::TestCase
|
|
19
21
|
end
|
20
22
|
|
21
23
|
def test_gem_sign_and_verify
|
24
|
+
Gem::OpenPGP.stubs(:verify_gem_check_fingerprint => true)
|
25
|
+
|
22
26
|
in_tmp_gpg_homedir do |gpg_home|
|
23
27
|
assert_raise Gem::OpenPGPException do
|
24
28
|
Gem::OpenPGP.verify_gem UNSIGNED_GEM, false, gpg_home
|
@@ -41,12 +45,12 @@ class RubygemsPluginTest < Test::Unit::TestCase
|
|
41
45
|
|
42
46
|
sig = Gem::OpenPGP.detach_sign data, key_id=nil, homedir=gpg_home
|
43
47
|
assert_nothing_raised do
|
44
|
-
Gem::OpenPGP.verify data, sig, false, homedir=gpg_home
|
48
|
+
Gem::OpenPGP.verify "<file>", data, sig, false, homedir=gpg_home
|
45
49
|
end
|
46
50
|
|
47
51
|
# BAD SIG
|
48
52
|
assert_raise(Gem::OpenPGPException) do
|
49
|
-
Gem::OpenPGP.verify data + "\n", sig, false, homedir=gpg_home
|
53
|
+
Gem::OpenPGP.verify "<file>", data + "\n", sig, false, homedir=gpg_home
|
50
54
|
end
|
51
55
|
end
|
52
56
|
end
|
metadata
CHANGED
@@ -1,76 +1,96 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubygems-openpgp
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
version: 0.4.0
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.5.0
|
6
5
|
platform: ruby
|
7
|
-
authors:
|
6
|
+
authors:
|
8
7
|
- Grant Olson
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
- !ruby/object:Gem::Dependency
|
11
|
+
date: 2013-03-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
16
14
|
name: gpg_status_parser
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version: 0.3.0
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.4.0
|
24
20
|
type: :runtime
|
25
|
-
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.4.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: mocha
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.13.2
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.13.2
|
26
41
|
description: Digitally sign gems via OpenPGP.
|
27
42
|
email: kgo@grant-olson.net
|
28
43
|
executables: []
|
29
|
-
|
30
44
|
extensions: []
|
31
|
-
|
32
|
-
extra_rdoc_files:
|
45
|
+
extra_rdoc_files:
|
33
46
|
- README.md
|
34
|
-
files:
|
47
|
+
files:
|
35
48
|
- LICENSE
|
36
49
|
- Rakefile
|
37
50
|
- lib/rubygems_plugin.rb
|
38
51
|
- lib/rubygems/commands/verify_command.rb
|
39
52
|
- lib/rubygems/commands/sign_command.rb
|
40
53
|
- lib/rubygems/gem_openpgp.rb
|
54
|
+
- lib/rubygems/openpgp/gpg_helpers.rb
|
55
|
+
- lib/rubygems/openpgp/options.rb
|
56
|
+
- lib/rubygems/openpgp/signing.rb
|
57
|
+
- lib/rubygems/openpgp/verification.rb
|
58
|
+
- lib/rubygems/openpgp/keymaster.rb
|
59
|
+
- lib/rubygems/openpgp/verify_plugins.rb
|
60
|
+
- lib/rubygems/openpgp/sign_plugins.rb
|
61
|
+
- lib/rubygems/openpgp/openpgpexception.rb
|
41
62
|
- README.md
|
63
|
+
- test/test_keymaster.rb
|
42
64
|
- test/test_rubygems-openpgp.rb
|
43
65
|
- test/pablo_escobar_seckey.asc
|
44
66
|
- test/pablo_escobar_pubkey.asc
|
45
67
|
- test/unsigned_hola-0.0.0.gem
|
46
|
-
homepage: https://
|
47
|
-
licenses:
|
68
|
+
homepage: https://rubygems-openpgp-ca.org
|
69
|
+
licenses:
|
48
70
|
- BSD 3 Clause
|
71
|
+
metadata: {}
|
49
72
|
post_install_message:
|
50
73
|
rdoc_options: []
|
51
|
-
|
52
|
-
require_paths:
|
74
|
+
require_paths:
|
53
75
|
- lib
|
54
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
- !ruby/object:Gem::Version
|
65
|
-
version: "0"
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - '>='
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
66
86
|
requirements: []
|
67
|
-
|
68
87
|
rubyforge_project:
|
69
|
-
rubygems_version:
|
88
|
+
rubygems_version: 2.0.0.rc.2
|
70
89
|
signing_key:
|
71
|
-
specification_version:
|
90
|
+
specification_version: 4
|
72
91
|
summary: Sign gems via OpenPGP
|
73
|
-
test_files:
|
92
|
+
test_files:
|
93
|
+
- test/test_keymaster.rb
|
74
94
|
- test/test_rubygems-openpgp.rb
|
75
95
|
- test/pablo_escobar_seckey.asc
|
76
96
|
- test/pablo_escobar_pubkey.asc
|
metadata.gz.asc
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
-----BEGIN PGP SIGNATURE-----
|
2
|
-
Version: GnuPG
|
2
|
+
Version: GnuPG v1.4.11 (GNU/Linux)
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
=
|
4
|
+
iQEcBAABAgAGBQJRPJV0AAoJEP5F5V2hilTWUlgH/34nV018I/aZnDLYCQyFqJSJ
|
5
|
+
Ek96fj//cmCbbN55YG8ptgB4NyZBBsc0Nvhe7CEsKFbcZJoutqoPXKeE0A3Qe9lp
|
6
|
+
gnogg7mwcm5ndn2dxBH1fd2it0fS3vG09i5r7MMqsE5LzaLJ6OcmYWmNnV2HiPTr
|
7
|
+
LQeqyC4hFyweIYpgO8sgdCDjrAaWDTBfoHmvHZ8xHZRZypJP45EdQ/+brp+DZmKu
|
8
|
+
K5E7LpV9VOFFobb91a4RYuzqulSK5tQELSXkh2IcDPDyEu0FZl7iP3S6N6xuDUQc
|
9
|
+
Zvtg1UpyMWs31DlCeivJhmQbFBbaVgjcqyHrEXnMWAIRq4XQxA7sZcxgg+K9j7k=
|
10
|
+
=1hJH
|
11
11
|
-----END PGP SIGNATURE-----
|