rubygems-openpgp 0.1.1 → 0.2.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.
- 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-----
|