rubygems-openpgp 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.asc +7 -7
- data/Rakefile +8 -0
- data/lib/rubygems/commands/sbuild_command.rb +8 -6
- data/lib/rubygems/commands/sign_command.rb +15 -41
- data/lib/rubygems/commands/verify_command.rb +20 -33
- data/lib/rubygems/commands/vinstall_command.rb +10 -6
- data/lib/rubygems/gem_openpgp.rb +187 -36
- data/lib/rubygems_plugin.rb +2 -2
- data/test/pablo_escobar_pubkey.asc +31 -0
- data/test/pablo_escobar_seckey.asc +58 -0
- data/test/test_rubygems-openpgp.rb +52 -0
- data/test/unsigned_hola-0.0.0.gem +0 -0
- metadata +11 -2
- metadata.gz.asc +7 -7
data.tar.gz.asc
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
-----BEGIN PGP SIGNATURE-----
|
2
2
|
Version: GnuPG v1.4.10 (GNU/Linux)
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
/
|
9
|
-
|
10
|
-
=
|
4
|
+
iQEcBAABAwAGBQJN5CnTAAoJEP5F5V2hilTW8WYIALAGfV7qJwhYHLi4SyU3tTUD
|
5
|
+
siDF6Ja3TisluSv41YKB0nisuXwjcGuzAbHLglAm7OdjIBEcauFvQPDUVdKPPvzx
|
6
|
+
06cPaSBKj2wCgrcolr7d/Xb9o9gLKpIJXJzd2PZpPxvZOH9Oz55DRYekENhk22Bi
|
7
|
+
Cl/mSwhpRzIqFPvyhDuEXnPs5oaErtvWczu/6HRAz+Au5Vy2dXG20F1x2/PwQcAp
|
8
|
+
O1Xnp0LD60Tq1hbWfesJ20WSW0r3x5iBuADxvUo9/WnTwt4P2xEy3A7JItAONfuV
|
9
|
+
0KlDcCgGdxvD0Fcq1LfyilMqojg/GFZomSM8KJYvjcFczav1hisXyYDTLgd82+s=
|
10
|
+
=sV5A
|
11
11
|
-----END PGP SIGNATURE-----
|
data/Rakefile
ADDED
@@ -1,30 +1,32 @@
|
|
1
1
|
require "rubygems/command"
|
2
2
|
require 'rubygems/version_option'
|
3
3
|
|
4
|
-
|
4
|
+
# currently unimplemented.
|
5
|
+
# This will build and sign with a single command.
|
6
|
+
class Gem::Commands::SbuildCommand < Gem::Command # :nodoc:
|
5
7
|
|
6
8
|
include Gem::VersionOption
|
7
9
|
|
8
|
-
def initialize
|
10
|
+
def initialize # :nodoc:
|
9
11
|
super 'sbuild', 'Build your gem, then sign it with OpenPGP'
|
10
12
|
|
11
13
|
add_version_option
|
12
14
|
|
13
15
|
end
|
14
16
|
|
15
|
-
def arguments
|
17
|
+
def arguments # :nodoc:
|
16
18
|
"GEMNAME name of gem to build"
|
17
19
|
end
|
18
20
|
|
19
|
-
def defaults_str
|
21
|
+
def defaults_str # :nodoc:
|
20
22
|
""
|
21
23
|
end
|
22
24
|
|
23
|
-
def usage
|
25
|
+
def usage # :nodoc:
|
24
26
|
"blah blah"
|
25
27
|
end
|
26
28
|
|
27
|
-
def execute
|
29
|
+
def execute # :nodoc:
|
28
30
|
version = options[:version] || Gem::Requirement.default
|
29
31
|
|
30
32
|
raise "Not implemented yet"
|
@@ -4,12 +4,17 @@ require 'rubygems/version_option'
|
|
4
4
|
require "rubygems/gem_openpgp"
|
5
5
|
require 'fileutils'
|
6
6
|
|
7
|
+
# CLI interface to the internal signing code:
|
8
|
+
#
|
9
|
+
# gem sign gemname-0.0.0.gem
|
10
|
+
#
|
11
|
+
# gem sign -key 0xDEADBEEF gemname-0.0.0.gem
|
7
12
|
class Gem::Commands::SignCommand < Gem::Command
|
8
13
|
|
9
14
|
include Gem::VersionOption
|
10
15
|
|
11
|
-
def initialize
|
12
|
-
super 'sign', '
|
16
|
+
def initialize # :nodoc:
|
17
|
+
super 'sign', 'Signs an existing gem with your OpenPGP key. This allows third parties to verify the key later via the \'gem verify\' command.', :key => nil
|
13
18
|
|
14
19
|
add_version_option
|
15
20
|
|
@@ -18,54 +23,23 @@ class Gem::Commands::SignCommand < Gem::Command
|
|
18
23
|
end
|
19
24
|
end
|
20
25
|
|
21
|
-
def arguments
|
26
|
+
def arguments # :nodoc:
|
22
27
|
"GEMNAME name of gem to sign"
|
23
28
|
end
|
24
29
|
|
25
|
-
def defaults_str
|
30
|
+
def defaults_str # :nodoc:
|
26
31
|
""
|
27
32
|
end
|
28
33
|
|
29
|
-
def usage
|
30
|
-
"
|
34
|
+
def usage # :nodoc:
|
35
|
+
"gem sign GEMNAME"
|
31
36
|
end
|
32
37
|
|
33
|
-
def execute
|
38
|
+
def execute # :nodoc:
|
34
39
|
version = options[:version] || Gem::Requirement.default
|
35
40
|
gem, specs = get_one_gem_name, []
|
36
|
-
|
37
|
-
|
38
|
-
FileUtils.mv gem, unsigned_gem
|
39
|
-
|
40
|
-
unsigned_gem_file = File.open(unsigned_gem, "r")
|
41
|
-
signed_gem_file = File.open(gem, "w")
|
42
|
-
|
43
|
-
signed_gem = Gem::Package::TarWriter.new(signed_gem_file)
|
44
|
-
|
45
|
-
Gem::Package::TarReader.new(unsigned_gem_file).each do |f|
|
46
|
-
say f.full_name.inspect
|
47
|
-
|
48
|
-
if f.full_name[-4..-1] == ".asc"
|
49
|
-
say "Skipping old signature file #{f.full_name}"
|
50
|
-
next
|
51
|
-
end
|
52
|
-
|
53
|
-
say "Signing #{f.full_name.inspect}..."
|
54
|
-
|
55
|
-
file_contents = f.read()
|
56
|
-
|
57
|
-
signed_gem.add_file(f.full_name, 0644) do |outfile|
|
58
|
-
outfile.write(file_contents)
|
59
|
-
end
|
60
|
-
|
61
|
-
signed_gem.add_file(f.full_name + ".asc", 0644) do |outfile|
|
62
|
-
outfile.write(Gem::OpenPGP.detach_sign(file_contents,options[:key]))
|
63
|
-
end
|
64
|
-
|
65
|
-
end
|
66
|
-
rescue Exception => ex
|
67
|
-
FileUtils.mv unsigned_gem_file, gem
|
68
|
-
raise
|
41
|
+
output = Gem::OpenPGP.sign_gem gem, key=options[:key]
|
42
|
+
say output.join("\n")
|
69
43
|
end
|
70
|
-
|
44
|
+
|
71
45
|
end
|
@@ -1,14 +1,20 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require 'rubygems/command'
|
2
|
+
require 'rubygems/package'
|
3
3
|
require 'rubygems/version_option'
|
4
|
-
require
|
5
|
-
|
4
|
+
require 'rubygems/gem_openpgp'
|
5
|
+
|
6
|
+
# Verifies a gem signed by the 'sign' command. Iterates through the
|
7
|
+
# gem contents and verifies all embedded files, if possible. Errors
|
8
|
+
# out if the signature is bad or the key is unknown.
|
9
|
+
#
|
10
|
+
# Optionally takes "--get-key" which automatically retreives the key
|
11
|
+
# from keyservers to make things easier for people unfamiliar with gpg.
|
6
12
|
class Gem::Commands::VerifyCommand < Gem::Command
|
7
13
|
|
8
14
|
include Gem::VersionOption
|
9
15
|
|
10
|
-
def initialize
|
11
|
-
super 'verify', '
|
16
|
+
def initialize # :nodoc:
|
17
|
+
super 'verify', 'Verifies a local gem that has been signed via OpenPGP. This helps to ensure the gem has not been tampered with in transit.'
|
12
18
|
|
13
19
|
add_version_option
|
14
20
|
|
@@ -18,42 +24,23 @@ class Gem::Commands::VerifyCommand < Gem::Command
|
|
18
24
|
|
19
25
|
end
|
20
26
|
|
21
|
-
def arguments
|
27
|
+
def arguments # :nodoc:
|
22
28
|
"GEMNAME name of gem to verify"
|
23
29
|
end
|
24
30
|
|
25
|
-
def defaults_str
|
31
|
+
def defaults_str # :nodoc:
|
26
32
|
""
|
27
33
|
end
|
28
34
|
|
29
|
-
def usage
|
30
|
-
"
|
35
|
+
def usage # :nodoc:
|
36
|
+
"gem verify GEMNAME"
|
31
37
|
end
|
32
38
|
|
33
|
-
def execute
|
39
|
+
def execute # :nodoc:
|
34
40
|
version = options[:version] || Gem::Requirement.default
|
35
41
|
gem, specs = get_one_gem_name, []
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
tar_files = {}
|
40
|
-
|
41
|
-
Gem::Package::TarReader.new(file).each do |f|
|
42
|
-
tar_files[f.full_name] = f.read()
|
43
|
-
end
|
44
|
-
|
45
|
-
tar_files.keys.each do |file_name|
|
46
|
-
next if file_name[-4..-1] == ".asc"
|
47
|
-
say "Verifying #{file_name}..."
|
48
|
-
|
49
|
-
sig_file_name = file_name + ".asc"
|
50
|
-
if !tar_files.has_key? sig_file_name
|
51
|
-
say "WARNING!!! No sig found for #{file_name}"
|
52
|
-
next
|
53
|
-
end
|
54
|
-
|
55
|
-
Gem::OpenPGP.verify(tar_files[file_name], tar_files[sig_file_name], options[:get_key])
|
56
|
-
end
|
42
|
+
output = Gem::OpenPGP.verify_gem gem, get_key=options[:get_key]
|
43
|
+
say output.join("\n")
|
57
44
|
end
|
58
|
-
|
45
|
+
|
59
46
|
end
|
@@ -1,30 +1,34 @@
|
|
1
1
|
require "rubygems/command"
|
2
2
|
require 'rubygems/version_option'
|
3
3
|
|
4
|
-
|
4
|
+
# Currently unimplemented.
|
5
|
+
# This will fetch, verify and install a gem. Ideally it will do the
|
6
|
+
# same with any dependencies that are downloaded, but this might be
|
7
|
+
# difficult in a gem.
|
8
|
+
class Gem::Commands::VinstallCommand < Gem::Command # :nodoc:
|
5
9
|
|
6
10
|
include Gem::VersionOption
|
7
11
|
|
8
|
-
def initialize
|
12
|
+
def initialize # :nodoc:
|
9
13
|
super 'vinstall', 'verify gem with GPG, and only install if sig check passes'
|
10
14
|
|
11
15
|
add_version_option
|
12
16
|
|
13
17
|
end
|
14
18
|
|
15
|
-
def arguments
|
19
|
+
def arguments # :nodoc:
|
16
20
|
"GEMNAME name of gem to build"
|
17
21
|
end
|
18
22
|
|
19
|
-
def defaults_str
|
23
|
+
def defaults_str # :nodoc:
|
20
24
|
""
|
21
25
|
end
|
22
26
|
|
23
|
-
def usage
|
27
|
+
def usage # :nodoc:
|
24
28
|
"blah blah"
|
25
29
|
end
|
26
30
|
|
27
|
-
def execute
|
31
|
+
def execute # :nodoc:
|
28
32
|
version = options[:version] || Gem::Requirement.default
|
29
33
|
|
30
34
|
puts "Not implemented yet."
|
data/lib/rubygems/gem_openpgp.rb
CHANGED
@@ -1,62 +1,213 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rubygems/package'
|
1
3
|
require 'open3'
|
2
4
|
require 'tempfile'
|
3
5
|
|
6
|
+
# Exception for this class
|
7
|
+
class Gem::OpenPGPException < RuntimeError; end
|
8
|
+
|
9
|
+
# A wrapper that shells out the real OpenPGP crypto work
|
10
|
+
# to gpg.
|
4
11
|
module Gem::OpenPGP
|
5
|
-
def self.openpgp_available?
|
6
|
-
`gpg --version`
|
7
|
-
$? == 0
|
8
|
-
rescue
|
9
|
-
false
|
10
|
-
end
|
11
12
|
|
12
|
-
|
13
|
+
# Given a string of data, generate and return a detached
|
14
|
+
# signature. By defualt, this will use your primary secret key.
|
15
|
+
# This can be overridden by specifying a key_id for another
|
16
|
+
# private key.
|
17
|
+
def self.detach_sign data, key_id=nil, homedir=nil
|
18
|
+
is_gpg_available
|
19
|
+
is_key_valid key_id if key_id
|
20
|
+
is_homedir_valid homedir if homedir
|
21
|
+
|
13
22
|
key_flag = ""
|
14
23
|
key_flag = "-u #{key_id}" if key_id
|
15
|
-
cmd = "gpg #{key_flag} --detach-sign --armor"
|
16
|
-
exit_status = nil
|
17
|
-
sig,err = Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
|
18
|
-
stdin.write data
|
19
|
-
stdin.close
|
20
|
-
exit_status = wait_thr.value
|
21
|
-
[stdout.read(), stderr.read()]
|
22
|
-
end
|
23
24
|
|
24
|
-
|
25
|
+
homedir_flag = ""
|
26
|
+
homedir_flag = "--homedir #{homedir}" if homedir
|
25
27
|
|
28
|
+
cmd = "gpg #{key_flag} #{homedir_flag} --detach-sign --armor"
|
29
|
+
sig, err = run_gpg_command cmd, data
|
26
30
|
sig
|
27
31
|
end
|
28
32
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
33
|
+
# Given a string containing data, and a string containing
|
34
|
+
# a detached signature, verify the data. If we can't verify
|
35
|
+
# then raise an exception.
|
36
|
+
#
|
37
|
+
# Optionally tell gpg to retrive the key if it's not provided
|
38
|
+
def self.verify data, sig, get_key=false, homedir=nil
|
39
|
+
is_gpg_available
|
40
|
+
is_homedir_valid homedir if homedir
|
34
41
|
|
35
|
-
|
36
|
-
sig_file
|
37
|
-
sig_file.write(sig)
|
38
|
-
sig_file.close
|
42
|
+
data_file = create_tempfile data
|
43
|
+
sig_file = create_tempfile sig
|
39
44
|
|
40
45
|
get_key_params = "--keyserver pool.sks-keyservers.net --keyserver-options auto-key-retrieve"
|
41
46
|
get_key_params = "" if get_key != true
|
42
47
|
|
43
|
-
|
48
|
+
homedir_flags = ""
|
49
|
+
homedir_flags = "--homedir #{homedir}" if homedir
|
50
|
+
|
51
|
+
cmd = "gpg #{get_key_params} #{homedir_flags} --verify #{sig_file.path} #{data_file.path}"
|
52
|
+
res, err = run_gpg_command cmd
|
53
|
+
[err, res]
|
54
|
+
end
|
55
|
+
|
56
|
+
# Signs an existing gemfile by iterating the tar'ed up contents,
|
57
|
+
# and signing any contents. creating a new file with original contents
|
58
|
+
# and OpenPGP sigs. The OpenPGP sigs are saved as .asc files so they
|
59
|
+
# won't conflict with X509 sigs.
|
60
|
+
#
|
61
|
+
# Optional param "key" allows you to use a different private
|
62
|
+
# key than the GPG default.
|
63
|
+
def self.sign_gem gem, key=nil, homedir=nil
|
64
|
+
output = []
|
65
|
+
|
66
|
+
unsigned_gem = gem + ".unsigned"
|
67
|
+
|
68
|
+
begin
|
69
|
+
FileUtils.mv gem, unsigned_gem
|
70
|
+
rescue Errno::ENOENT => ex
|
71
|
+
raise Gem::CommandLineError, "The gem #{gem} does not seem to exist. (#{ex.message})"
|
72
|
+
end
|
73
|
+
|
74
|
+
unsigned_gem_file = File.open(unsigned_gem, "r")
|
75
|
+
signed_gem_file = File.open(gem, "w")
|
76
|
+
|
77
|
+
signed_gem = Gem::Package::TarWriter.new(signed_gem_file)
|
78
|
+
|
79
|
+
Gem::Package::TarReader.new(unsigned_gem_file).each do |f|
|
80
|
+
output << f.full_name.inspect
|
81
|
+
|
82
|
+
if f.full_name[-4..-1] == ".asc"
|
83
|
+
output << "Skipping old signature file #{f.full_name}"
|
84
|
+
next
|
85
|
+
end
|
86
|
+
|
87
|
+
output << "Signing #{f.full_name.inspect}..."
|
88
|
+
|
89
|
+
file_contents = f.read()
|
90
|
+
|
91
|
+
signed_gem.add_file(f.full_name, 0644) do |outfile|
|
92
|
+
outfile.write(file_contents)
|
93
|
+
end
|
94
|
+
|
95
|
+
signed_gem.add_file(f.full_name + ".asc", 0644) do |outfile|
|
96
|
+
outfile.write(Gem::OpenPGP.detach_sign(file_contents,key,homedir))
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
signed_gem_file.close
|
102
|
+
unsigned_gem_file.close
|
103
|
+
File.delete unsigned_gem_file
|
104
|
+
|
105
|
+
output
|
106
|
+
rescue Exception => ex
|
107
|
+
if unsigned_gem_file
|
108
|
+
FileUtils.mv unsigned_gem_file, gem
|
109
|
+
end
|
110
|
+
|
111
|
+
raise
|
112
|
+
end
|
113
|
+
|
114
|
+
def self.verify_gem gem, get_key=false, homedir=nil
|
115
|
+
output =[]
|
116
|
+
|
117
|
+
begin
|
118
|
+
file = File.open(gem,"r")
|
119
|
+
rescue Errno::ENOENT => ex
|
120
|
+
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."
|
121
|
+
end
|
122
|
+
|
123
|
+
tar_files = {}
|
124
|
+
|
125
|
+
Gem::Package::TarReader.new(file).each do |f|
|
126
|
+
tar_files[f.full_name] = f.read()
|
127
|
+
end
|
128
|
+
|
129
|
+
tar_files.keys.each do |file_name|
|
130
|
+
next if file_name[-4..-1] == ".asc"
|
131
|
+
output << "Verifying #{file_name}..."
|
132
|
+
|
133
|
+
sig_file_name = file_name + ".asc"
|
134
|
+
if !tar_files.has_key? sig_file_name
|
135
|
+
output << "WARNING!!! No sig found for #{file_name}"
|
136
|
+
next
|
137
|
+
end
|
138
|
+
|
139
|
+
begin
|
140
|
+
err, res = Gem::OpenPGP.verify(tar_files[file_name], tar_files[sig_file_name], get_key, homedir)
|
141
|
+
|
142
|
+
output << add_color(err, :green)
|
143
|
+
output << add_color(res, :green)
|
144
|
+
rescue Gem::OpenPGPException => ex
|
145
|
+
color_code = "31"
|
146
|
+
output << add_color(ex.message, :red)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
file.close
|
151
|
+
|
152
|
+
output
|
153
|
+
end
|
154
|
+
|
155
|
+
private
|
156
|
+
|
157
|
+
# Tests to see if gpg is installed and available.
|
158
|
+
def self.is_gpg_available
|
159
|
+
err_msg = "Unable to find a working gnupg installation. Make sure gnupg is installed and you can call 'gpg --version' from a command prompt."
|
160
|
+
`gpg --version`
|
161
|
+
raise Gem::OpenPGPException, err_msg if $? != 0
|
162
|
+
rescue Errno::ENOENT => ex
|
163
|
+
raise Gem::OpenPGPException, err_msg if $? != 0
|
164
|
+
end
|
165
|
+
|
166
|
+
def self.is_key_valid key_id
|
167
|
+
valid = /^0x[A-Za-z0-9]{8,8}/.match(key_id)
|
168
|
+
if valid.nil?
|
169
|
+
err_msg = "Invalid key id. Keys should be in form of 0xDEADBEEF"
|
170
|
+
raise Gem::OpenPGPException, err_msg
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def self.is_homedir_valid homedir
|
175
|
+
if !File.exists? homedir
|
176
|
+
raise OpenPGPException, "Bad homedir #{homedir.inspect}"
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def self.run_gpg_command cmd, data=nil
|
44
181
|
exit_status = nil
|
45
|
-
|
182
|
+
stdout, stderr = Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
|
183
|
+
stdin.write data if data
|
46
184
|
stdin.close
|
47
185
|
exit_status = wait_thr.value
|
48
|
-
|
186
|
+
out = stdout.read()
|
187
|
+
err = stderr.read()
|
188
|
+
raise Gem::OpenPGPException, "#{err}" if exit_status != 0
|
189
|
+
[out,err]
|
49
190
|
end
|
191
|
+
[stdout, stderr]
|
192
|
+
end
|
50
193
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
194
|
+
def self.create_tempfile data
|
195
|
+
temp_file = Tempfile.new("rubygems_gpg")
|
196
|
+
temp_file.binmode
|
197
|
+
temp_file.write(data)
|
198
|
+
temp_file.close
|
199
|
+
temp_file
|
200
|
+
end
|
201
|
+
|
202
|
+
def self.add_color s, color=:green
|
203
|
+
color_code = case color
|
204
|
+
when :green then "32"
|
205
|
+
when :red then "31"
|
206
|
+
else raise RuntimeError, "Invalid color #{color.inspect}"
|
55
207
|
end
|
56
208
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
raise "gpg encountered errors! #{err}" if exit_status != 0
|
209
|
+
#TODO - NO-OP on windows
|
210
|
+
"\033[#{color_code}m#{s}\033[0m"
|
61
211
|
end
|
212
|
+
|
62
213
|
end
|
data/lib/rubygems_plugin.rb
CHANGED
@@ -2,5 +2,5 @@ require 'rubygems/command_manager'
|
|
2
2
|
|
3
3
|
Gem::CommandManager.instance.register_command :sign
|
4
4
|
Gem::CommandManager.instance.register_command :verify
|
5
|
-
Gem::CommandManager.instance.register_command :vinstall
|
6
|
-
Gem::CommandManager.instance.register_command :sbuild
|
5
|
+
#Gem::CommandManager.instance.register_command :vinstall
|
6
|
+
#Gem::CommandManager.instance.register_command :sbuild
|
@@ -0,0 +1,31 @@
|
|
1
|
+
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
2
|
+
Version: GnuPG v1.4.10 (GNU/Linux)
|
3
|
+
|
4
|
+
mQENBE3iyn0BCADgFkThsahECiM8Po0vIr8A7U6sI7qIQ2tG4Uq0HIx4sMtgffG7
|
5
|
+
F9TGTlLBgSZuog6BnxAg7A7q4IYg1Xnvuf8kl4Ade7AE5vhjXdoWUkuvZanJduXh
|
6
|
+
yxdQ7EqnLgqGHXfZXxB+OlWCPofpb5L4OLURYLTUQHuCrfQ2fEzXCu/wsTd8JbwY
|
7
|
+
k/EgpwCRWMhtH9vbMbmca8AvrsLK/fv0H4fNQiVJf0ZaKPM0fHy4II4fXQy9pmaf
|
8
|
+
qFF4og5IMIy2CYoPQxGGN1e37sSbJUlaxkJBUQAK5mQ1jqwKe/2+p9qJPcMDWH6h
|
9
|
+
M1FcOgD7wlb9f7lDNyW+Wp/pdxz0afZ3po3hABEBAAG0RlBhYmxvIEVzY29iYXIg
|
10
|
+
KElOU0VDVVJFIHJ1YnlnZW1zLW9wZW5wZ3AgdGVzdCBrZXkpIDxwYWJsb0BleGFt
|
11
|
+
cGxlLm9yZz6JATcEEwEIACEFAk3iyn0CGwMFCwkIBwMFFQoJCAsFFgIDAQACHgEC
|
12
|
+
F4AACgkQVd0SUQAeGtZdgwf+IxeO4kW7LrxtvL9s4YvrydRXVYbfyHoVYNp+g4cZ
|
13
|
+
apFtKtC9Zt7ZfEPXiaWAT1uJ8vXc4tqfnVuGy99yVn/Xif5cMmhQs5uMtvUYKxPW
|
14
|
+
EpiGOa+L5F3NevErTgzbFWRtAn/oQ7C5kk52WyyS1lndcYnHRmZpBFDVCa9cW0zK
|
15
|
+
KZJNCydiLoBNtN1HzaKbRNd8XPBV2guYdZCU9Q+y9jyUoblslHAuuaRvq76XtgdR
|
16
|
+
rI4L1H4Ply2I1cdNbv/8NAb9+l5s2X6CCflZheKD1pHPcWiJQ7FfYekefd2wPBWo
|
17
|
+
ZSdXMotgr1pV4Mj5iysfhhChJ4lzx1198+Q8aftkcWNdZbkBDQRN4sp9AQgAtMJH
|
18
|
+
aSLF62nvFjSFmiIbv/GyoVD4XZKfI8/9G9DO+ODPNf9X6PuyXfPsHkxMW7lKgvMQ
|
19
|
+
3DOn/RZWgSIB3YqX8mJA/LOVqA7e8cy6TFI10zD6tln5CMbnpVwfTUTn9m/CEnPF
|
20
|
+
l6OuaWzmvOGf3P9oPSjUCukPvzkJb46tCOluLtqGxKrom+hGczjZfYvbbmjeTu7Q
|
21
|
+
NNcmtcNYP1LFiR3I1iaFDjRUgdC37WFTeF5agVVdpEIyUmggB86NHiT3r7a189iB
|
22
|
+
KcaGU3JN+ZqzaeQ5TrN/Os7IaCDLczTOe2mdBYho8l6bEhc5Tdy1JJPAjaagl8ES
|
23
|
+
H0Bx0S7MPnu9sThmiwARAQABiQEfBBgBCAAJBQJN4sp9AhsMAAoJEFXdElEAHhrW
|
24
|
+
km0H/RZQ/iRuE5K8u1t8J6VBzyQYRk20i4Yjsu4kWm1fbNEQoLqy75cH8wWDmVR3
|
25
|
+
tSaUuQOQslGOVUZAZkB9feGZAzdoU+3Ui0H5dXuwRdr5/CW0k81i8K3lKZ3hP2Lf
|
26
|
+
bGhOLNX7akLMcB1yCf7oqmZaGeSpgMApcrwVlQFXgAAw64Cxp2vabxmKCcgoXUmX
|
27
|
+
dyVfOg3lUIsXvCjKUMIBmlYoIFwPhIgJW7SYzFThKv73gnXyJPy4U20VvpWv6wcr
|
28
|
+
duJNyknchgtvThLgD84AOR0BA5/w86xypFhaqjJhxkFjAo31qvsecFRbwz4KW5pJ
|
29
|
+
f4mUC5J7S/QpAFMTy3GTplonqYU=
|
30
|
+
=0O9l
|
31
|
+
-----END PGP PUBLIC KEY BLOCK-----
|
@@ -0,0 +1,58 @@
|
|
1
|
+
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
2
|
+
Version: GnuPG v1.4.10 (GNU/Linux)
|
3
|
+
|
4
|
+
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
|
56
|
+
wz4KW5pJf4mUC5J7S/QpAFMTy3GTplonqYU=
|
57
|
+
=1g/V
|
58
|
+
-----END PGP PRIVATE KEY BLOCK-----
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'rubygems_plugin'
|
3
|
+
require 'rubygems/gem_openpgp'
|
4
|
+
require 'tmpdir'
|
5
|
+
require 'fileutils'
|
6
|
+
|
7
|
+
class RubygemsPluginTest < Test::Unit::TestCase
|
8
|
+
UNSIGNED_GEM = "test/unsigned_hola-0.0.0.gem"
|
9
|
+
SIGNED_GEM = "test/openpgp_signed_hola-0.0.0.gem"
|
10
|
+
PABLOS_SECKEY = "test/pablo_escobar_seckey.asc"
|
11
|
+
PABLOS_PUBKEY = "test/pablo_escobar_pubkey.asc"
|
12
|
+
|
13
|
+
def in_tmp_gpg_homedir
|
14
|
+
gpg_home = Dir.mktmpdir()
|
15
|
+
`gpg --homedir=#{gpg_home} --import #{PABLOS_SECKEY}`
|
16
|
+
`gpg --homedir=#{gpg_home} --import #{PABLOS_PUBKEY}`
|
17
|
+
yield gpg_home
|
18
|
+
FileUtils.rm_rf(gpg_home)
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_gem_sign_and_verify
|
22
|
+
in_tmp_gpg_homedir do |gpg_home|
|
23
|
+
res = Gem::OpenPGP.verify_gem UNSIGNED_GEM, false, gpg_home
|
24
|
+
assert_match(/WARNING!!!/, res.join("\n"))
|
25
|
+
|
26
|
+
FileUtils.cp UNSIGNED_GEM, SIGNED_GEM
|
27
|
+
|
28
|
+
assert_nothing_raised do
|
29
|
+
Gem::OpenPGP.sign_gem SIGNED_GEM, nil, gpg_home
|
30
|
+
Gem::OpenPGP.verify_gem SIGNED_GEM , nil, gpg_home
|
31
|
+
end
|
32
|
+
end
|
33
|
+
ensure
|
34
|
+
File.delete SIGNED_GEM
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_basic_sign_and_verify
|
38
|
+
in_tmp_gpg_homedir do |gpg_home|
|
39
|
+
data = "The mysterious case of Pablo Escobar's hippos - http://baraza.wildlifedirect.org/2009/07/15/the-curious-case-of-pablo-escobars-hippos/"
|
40
|
+
|
41
|
+
sig = Gem::OpenPGP.detach_sign data, key_id=nil, homedir=gpg_home
|
42
|
+
assert_nothing_raised do
|
43
|
+
Gem::OpenPGP.verify data, sig, false, homedir=gpg_home
|
44
|
+
end
|
45
|
+
|
46
|
+
# BAD SIG
|
47
|
+
assert_raise(Gem::OpenPGPException) do
|
48
|
+
Gem::OpenPGP.verify data + "\n", sig, false, homedir=gpg_home
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubygems-openpgp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -20,6 +20,7 @@ extra_rdoc_files:
|
|
20
20
|
- README.md
|
21
21
|
files:
|
22
22
|
- LICENSE
|
23
|
+
- Rakefile
|
23
24
|
- lib/rubygems_plugin.rb
|
24
25
|
- lib/rubygems/commands/verify_command.rb
|
25
26
|
- lib/rubygems/commands/vinstall_command.rb
|
@@ -27,6 +28,10 @@ files:
|
|
27
28
|
- lib/rubygems/commands/sign_command.rb
|
28
29
|
- lib/rubygems/gem_openpgp.rb
|
29
30
|
- README.md
|
31
|
+
- test/test_rubygems-openpgp.rb
|
32
|
+
- test/pablo_escobar_seckey.asc
|
33
|
+
- test/pablo_escobar_pubkey.asc
|
34
|
+
- test/unsigned_hola-0.0.0.gem
|
30
35
|
has_rdoc: true
|
31
36
|
homepage: https://github.com/grant-olson/rubygems-openpgp
|
32
37
|
licenses:
|
@@ -53,4 +58,8 @@ rubygems_version: 1.6.2
|
|
53
58
|
signing_key:
|
54
59
|
specification_version: 3
|
55
60
|
summary: Sign gems via OpenPGP
|
56
|
-
test_files:
|
61
|
+
test_files:
|
62
|
+
- test/test_rubygems-openpgp.rb
|
63
|
+
- test/pablo_escobar_seckey.asc
|
64
|
+
- test/pablo_escobar_pubkey.asc
|
65
|
+
- test/unsigned_hola-0.0.0.gem
|
metadata.gz.asc
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
-----BEGIN PGP SIGNATURE-----
|
2
2
|
Version: GnuPG v1.4.10 (GNU/Linux)
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
=
|
4
|
+
iQEcBAABAwAGBQJN5CnWAAoJEP5F5V2hilTWFVcH/0qOUdBqaOts+c2uCVpeeWHu
|
5
|
+
mqyvaIpiBWyeW4Jg+rADeqfGU77v6skr9RDrb91d/DfOam4ikgZIAzVuIGo/szsI
|
6
|
+
qdphaRsvpLBgJcX/3JvtismRzzRwWPsh89nEO62ffvZRbCYG2EQ8cQYvG9+ZcN9e
|
7
|
+
DPE4i3uPDqymiRL1PXka/owS7Tn70dOe5wJAgbba6jxaNwS/BAC4o8qsDzEDQzPi
|
8
|
+
O/ik6C9mJROMpDqOPQh9MhfZYjC8KT2vAzhrBeogfbHFpPLigkeLoICGG9CCTdll
|
9
|
+
GyWNwAUHvG4ubWuvdWkyRYQKcFBUow1uuAPFMhyqB3/vo0A2Kn1X5D8Ud+T/cs0=
|
10
|
+
=kfmO
|
11
11
|
-----END PGP SIGNATURE-----
|