rubygems-openpgp 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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-----
|