gpgme 1.0.8
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.sig +3 -0
- data/COPYING +340 -0
- data/COPYING.LESSER +510 -0
- data/Makefile +172 -0
- data/Manifest.txt +18 -0
- data/README +86 -0
- data/Rakefile +17 -0
- data/THANKS +15 -0
- data/examples/edit.rb +77 -0
- data/examples/genkey.rb +55 -0
- data/examples/keylist.rb +6 -0
- data/examples/roundtrip.rb +39 -0
- data/examples/sign.rb +29 -0
- data/examples/verify.rb +6 -0
- data/extconf.rb +26 -0
- data/gpgme_n.c +2622 -0
- data/lib/gpgme.rb +1561 -0
- data/lib/gpgme/compat.rb +46 -0
- data/lib/gpgme/constants.rb +164 -0
- metadata +109 -0
- metadata.gz.sig +0 -0
data/lib/gpgme.rb
ADDED
@@ -0,0 +1,1561 @@
|
|
1
|
+
=begin rdoc
|
2
|
+
= What's this?
|
3
|
+
|
4
|
+
Ruby-GPGME is a Ruby language binding of GPGME (GnuPG Made Easy).
|
5
|
+
|
6
|
+
= Requirements
|
7
|
+
|
8
|
+
- Ruby 1.8 or later
|
9
|
+
- GPGME 1.1.2 or later http://www.gnupg.org/(en)/related_software/gpgme/index.html
|
10
|
+
- gpg-agent (optional, but recommended)
|
11
|
+
|
12
|
+
= Installation
|
13
|
+
|
14
|
+
$ gem install ruby-gpgme
|
15
|
+
|
16
|
+
or
|
17
|
+
|
18
|
+
$ ruby extconf.rb
|
19
|
+
$ make
|
20
|
+
$ make install
|
21
|
+
|
22
|
+
= Examples
|
23
|
+
|
24
|
+
<tt>examples/genkey.rb</tt>:: Generate a key pair in your keyring.
|
25
|
+
<tt>examples/keylist.rb</tt>:: List your keyring like gpg --list-keys.
|
26
|
+
<tt>examples/roundtrip.rb</tt>:: Encrypt and decrypt a plain text.
|
27
|
+
<tt>examples/sign.rb</tt>:: Create a clear text signature.
|
28
|
+
<tt>examples/verify.rb</tt>:: Verify a clear text signature given from stdin.
|
29
|
+
|
30
|
+
= API
|
31
|
+
|
32
|
+
Ruby-GPGME provides three levels of API. The highest level API is
|
33
|
+
close to the command line interface of GnuPG. The mid level API looks
|
34
|
+
object-oriented (or rubyish). The lowest level API is close to the C
|
35
|
+
interface of GPGME.
|
36
|
+
|
37
|
+
== The highest level API
|
38
|
+
|
39
|
+
It can be written in the highest level API to create a cleartext
|
40
|
+
signature of the plaintext from stdin as follows.
|
41
|
+
|
42
|
+
$ ruby -rgpgme -e 'GPGME.clearsign($stdin, $stdout)'
|
43
|
+
|
44
|
+
== The mid level API
|
45
|
+
|
46
|
+
The same example can be rewritten in the mid level API as follows.
|
47
|
+
|
48
|
+
$ ruby -rgpgme -e <<End
|
49
|
+
ctx = GPGME::Ctx.new
|
50
|
+
plain = GPGME::Data.from_io($stdin)
|
51
|
+
sig = GPGME::Data.from_io($stdout)
|
52
|
+
ctx.sign(plain, sig, GPGME::SIG_MODE_CLEAR)
|
53
|
+
End
|
54
|
+
|
55
|
+
== The lowest level API
|
56
|
+
|
57
|
+
The same example can be rewritten in the lowest level API as follows.
|
58
|
+
|
59
|
+
$ ruby -rgpgme -e <<End
|
60
|
+
ret = Array.new
|
61
|
+
GPGME::gpgme_new(ret)
|
62
|
+
ctx = ret.shift
|
63
|
+
GPGME::gpgme_data_new_from_fd(ret, 0)
|
64
|
+
plain = ret.shift
|
65
|
+
GPGME::gpgme_data_new_from_fd(ret, 1)
|
66
|
+
sig = ret.shift
|
67
|
+
GPGME::gpgme_op_sign(ctx, plain, sig, GPGME::SIG_MODE_CLEAR)
|
68
|
+
End
|
69
|
+
|
70
|
+
As you see, it's much harder to write a program in this API than the
|
71
|
+
higher level API. However, if you are already familier with the C
|
72
|
+
interface of GPGME and/or want to control detailed behavior of GPGME,
|
73
|
+
it might be useful.
|
74
|
+
|
75
|
+
= License
|
76
|
+
|
77
|
+
Copyright (C) 2003,2006,2007,2008,2009 Daiki Ueno
|
78
|
+
|
79
|
+
This file is a part of Ruby-GPGME.
|
80
|
+
|
81
|
+
Ruby-GPGME is free software; you can redistribute it and/or
|
82
|
+
modify it under the terms of the GNU Lesser General Public
|
83
|
+
License as published by the Free Software Foundation; either
|
84
|
+
version 2.1 of the License, or (at your option) any later version.
|
85
|
+
|
86
|
+
Ruby-GPGME is distributed in the hope that it will be useful,
|
87
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
88
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
89
|
+
Lesser General Public License for more details.
|
90
|
+
|
91
|
+
You should have received a copy of the GNU Lesser General Public
|
92
|
+
License along with this library; if not, write to the Free Software
|
93
|
+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
94
|
+
=end
|
95
|
+
module GPGME
|
96
|
+
VERSION = "1.0.8"
|
97
|
+
end
|
98
|
+
|
99
|
+
require 'gpgme_n'
|
100
|
+
require 'gpgme/constants'
|
101
|
+
|
102
|
+
# call-seq:
|
103
|
+
# GPGME.decrypt(cipher, plain=nil, options=Hash.new){|signature| ...}
|
104
|
+
#
|
105
|
+
# <code>GPGME.decrypt</code> performs decryption.
|
106
|
+
#
|
107
|
+
# The arguments should be specified as follows.
|
108
|
+
#
|
109
|
+
# - GPGME.decrypt(<i>cipher</i>, <i>plain</i>, <i>options</i>)
|
110
|
+
# - GPGME.decrypt(<i>cipher</i>, <i>options</i>) -> <i>plain</i>
|
111
|
+
#
|
112
|
+
# All arguments except <i>cipher</i> are optional. <i>cipher</i> is
|
113
|
+
# input, and <i>plain</i> is output. If the last argument is a
|
114
|
+
# Hash, options will be read from it.
|
115
|
+
#
|
116
|
+
# An input argument is specified by an IO like object (which responds
|
117
|
+
# to <code>read</code>), a string, or a GPGME::Data object.
|
118
|
+
#
|
119
|
+
# An output argument is specified by an IO like object (which responds
|
120
|
+
# to <code>write</code>) or a GPGME::Data object.
|
121
|
+
#
|
122
|
+
# <i>options</i> are same as <code>GPGME::Ctx.new()</code>.
|
123
|
+
#
|
124
|
+
def GPGME.decrypt(cipher, *args_options)
|
125
|
+
raise ArgumentError, 'wrong number of arguments' if args_options.length > 2
|
126
|
+
args, options = split_args(args_options)
|
127
|
+
plain = args[0]
|
128
|
+
|
129
|
+
check_version(options)
|
130
|
+
GPGME::Ctx.new(options) do |ctx|
|
131
|
+
cipher_data = input_data(cipher)
|
132
|
+
plain_data = output_data(plain)
|
133
|
+
begin
|
134
|
+
ctx.decrypt_verify(cipher_data, plain_data)
|
135
|
+
rescue GPGME::Error::UnsupportedAlgorithm => exc
|
136
|
+
exc.algorithm = ctx.decrypt_result.unsupported_algorithm
|
137
|
+
raise exc
|
138
|
+
rescue GPGME::Error::WrongKeyUsage => exc
|
139
|
+
exc.key_usage = ctx.decrypt_result.wrong_key_usage
|
140
|
+
raise exc
|
141
|
+
end
|
142
|
+
|
143
|
+
verify_result = ctx.verify_result
|
144
|
+
if verify_result && block_given?
|
145
|
+
verify_result.signatures.each do |signature|
|
146
|
+
yield signature
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
unless plain
|
151
|
+
plain_data.seek(0, IO::SEEK_SET)
|
152
|
+
plain_data.read
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# call-seq:
|
158
|
+
# GPGME.verify(sig, signed_text=nil, plain=nil, options=Hash.new){|signature| ...}
|
159
|
+
#
|
160
|
+
# <code>GPGME.verify</code> verifies a signature.
|
161
|
+
#
|
162
|
+
# The arguments should be specified as follows.
|
163
|
+
#
|
164
|
+
# - GPGME.verify(<i>sig</i>, <i>signed_text</i>, <i>plain</i>, <i>options</i>)
|
165
|
+
# - GPGME.verify(<i>sig</i>, <i>signed_text</i>, <i>options</i>) -> <i>plain</i>
|
166
|
+
#
|
167
|
+
# All arguments except <i>sig</i> are optional. <i>sig</i> and
|
168
|
+
# <i>signed_text</i> are input. <i>plain</i> is output. If the last
|
169
|
+
# argument is a Hash, options will be read from it.
|
170
|
+
#
|
171
|
+
# An input argument is specified by an IO like object (which responds
|
172
|
+
# to <code>read</code>), a string, or a GPGME::Data object.
|
173
|
+
#
|
174
|
+
# An output argument is specified by an IO like object (which responds
|
175
|
+
# to <code>write</code>) or a GPGME::Data object.
|
176
|
+
#
|
177
|
+
# If <i>sig</i> is a detached signature, then the signed text should
|
178
|
+
# be provided in <i>signed_text</i> and <i>plain</i> should be
|
179
|
+
# <tt>nil</tt>. Otherwise, if <i>sig</i> is a normal (or cleartext)
|
180
|
+
# signature, <i>signed_text</i> should be <tt>nil</tt>.
|
181
|
+
#
|
182
|
+
# <i>options</i> are same as <code>GPGME::Ctx.new()</code>.
|
183
|
+
#
|
184
|
+
def GPGME.verify(sig, *args_options) # :yields: signature
|
185
|
+
raise ArgumentError, 'wrong number of arguments' if args_options.length > 3
|
186
|
+
args, options = split_args(args_options)
|
187
|
+
signed_text, plain = args
|
188
|
+
|
189
|
+
check_version(options)
|
190
|
+
GPGME::Ctx.new(options) do |ctx|
|
191
|
+
sig_data = input_data(sig)
|
192
|
+
if signed_text
|
193
|
+
signed_text_data = input_data(signed_text)
|
194
|
+
plain_data = nil
|
195
|
+
else
|
196
|
+
signed_text_data = nil
|
197
|
+
plain_data = output_data(plain)
|
198
|
+
end
|
199
|
+
ctx.verify(sig_data, signed_text_data, plain_data)
|
200
|
+
ctx.verify_result.signatures.each do |signature|
|
201
|
+
yield signature
|
202
|
+
end
|
203
|
+
if !signed_text && !plain
|
204
|
+
plain_data.seek(0, IO::SEEK_SET)
|
205
|
+
plain_data.read
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
# call-seq:
|
211
|
+
# GPGME.sign(plain, sig=nil, options=Hash.new)
|
212
|
+
#
|
213
|
+
# <code>GPGME.sign</code> creates a signature of the plaintext.
|
214
|
+
#
|
215
|
+
# The arguments should be specified as follows.
|
216
|
+
#
|
217
|
+
# - GPGME.sign(<i>plain</i>, <i>sig</i>, <i>options</i>)
|
218
|
+
# - GPGME.sign(<i>plain</i>, <i>options</i>) -> <i>sig</i>
|
219
|
+
#
|
220
|
+
# All arguments except <i>plain</i> are optional. <i>plain</i> is
|
221
|
+
# input and <i>sig</i> is output. If the last argument is a Hash,
|
222
|
+
# options will be read from it.
|
223
|
+
#
|
224
|
+
# An input argument is specified by an IO like object (which responds
|
225
|
+
# to <code>read</code>), a string, or a GPGME::Data object.
|
226
|
+
#
|
227
|
+
# An output argument is specified by an IO like object (which responds
|
228
|
+
# to <code>write</code>) or a GPGME::Data object.
|
229
|
+
#
|
230
|
+
# <i>options</i> are same as <code>GPGME::Ctx.new()</code> except for
|
231
|
+
#
|
232
|
+
# - <tt>:signers</tt> Signing keys. If specified, it is an array
|
233
|
+
# whose elements are a GPGME::Key object or a string.
|
234
|
+
# - <tt>:mode</tt> Desired type of a signature. Either
|
235
|
+
# <tt>GPGME::SIG_MODE_NORMAL</tt> for a normal signature,
|
236
|
+
# <tt>GPGME::SIG_MODE_DETACH</tt> for a detached signature, or
|
237
|
+
# <tt>GPGME::SIG_MODE_CLEAR</tt> for a cleartext signature.
|
238
|
+
#
|
239
|
+
def GPGME.sign(plain, *args_options)
|
240
|
+
raise ArgumentError, 'wrong number of arguments' if args_options.length > 2
|
241
|
+
args, options = split_args(args_options)
|
242
|
+
sig = args[0]
|
243
|
+
|
244
|
+
check_version(options)
|
245
|
+
GPGME::Ctx.new(options) do |ctx|
|
246
|
+
ctx.add_signer(*resolve_keys(options[:signers], true, [:sign])) if options[:signers]
|
247
|
+
mode = options[:mode] || GPGME::SIG_MODE_NORMAL
|
248
|
+
plain_data = input_data(plain)
|
249
|
+
sig_data = output_data(sig)
|
250
|
+
begin
|
251
|
+
ctx.sign(plain_data, sig_data, mode)
|
252
|
+
rescue GPGME::Error::UnusableSecretKey => exc
|
253
|
+
exc.keys = ctx.sign_result.invalid_signers
|
254
|
+
raise exc
|
255
|
+
end
|
256
|
+
|
257
|
+
unless sig
|
258
|
+
sig_data.seek(0, IO::SEEK_SET)
|
259
|
+
sig_data.read
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
# call-seq:
|
265
|
+
# GPGME.clearsign(plain, sig=nil, options=Hash.new)
|
266
|
+
#
|
267
|
+
# <code>GPGME.clearsign</code> creates a cleartext signature of the plaintext.
|
268
|
+
#
|
269
|
+
# The arguments should be specified as follows.
|
270
|
+
#
|
271
|
+
# - GPGME.clearsign(<i>plain</i>, <i>sig</i>, <i>options</i>)
|
272
|
+
# - GPGME.clearsign(<i>plain</i>, <i>options</i>) -> <i>sig</i>
|
273
|
+
#
|
274
|
+
# All arguments except <i>plain</i> are optional. <i>plain</i> is
|
275
|
+
# input and <i>sig</i> is output. If the last argument is a Hash,
|
276
|
+
# options will be read from it.
|
277
|
+
#
|
278
|
+
# An input argument is specified by an IO like object (which responds
|
279
|
+
# to <code>read</code>), a string, or a GPGME::Data object.
|
280
|
+
#
|
281
|
+
# An output argument is specified by an IO like object (which responds
|
282
|
+
# to <code>write</code>) or a GPGME::Data object.
|
283
|
+
#
|
284
|
+
# <i>options</i> are same as <code>GPGME::Ctx.new()</code> except for
|
285
|
+
#
|
286
|
+
# - <tt>:signers</tt> Signing keys. If specified, it is an array
|
287
|
+
# whose elements are a GPGME::Key object or a string.
|
288
|
+
#
|
289
|
+
def GPGME.clearsign(plain, *args_options)
|
290
|
+
raise ArgumentError, 'wrong number of arguments' if args_options.length > 2
|
291
|
+
args, options = split_args(args_options)
|
292
|
+
args.push(options.merge({:mode => GPGME::SIG_MODE_CLEAR}))
|
293
|
+
GPGME.sign(plain, *args)
|
294
|
+
end
|
295
|
+
|
296
|
+
# call-seq:
|
297
|
+
# GPGME.detach_sign(plain, sig=nil, options=Hash.new)
|
298
|
+
#
|
299
|
+
# <code>GPGME.detach_sign</code> creates a detached signature of the plaintext.
|
300
|
+
#
|
301
|
+
# The arguments should be specified as follows.
|
302
|
+
#
|
303
|
+
# - GPGME.detach_sign(<i>plain</i>, <i>sig</i>, <i>options</i>)
|
304
|
+
# - GPGME.detach_sign(<i>plain</i>, <i>options</i>) -> <i>sig</i>
|
305
|
+
#
|
306
|
+
# All arguments except <i>plain</i> are optional. <i>plain</i> is
|
307
|
+
# input and <i>sig</i> is output. If the last argument is a Hash,
|
308
|
+
# options will be read from it.
|
309
|
+
#
|
310
|
+
# An input argument is specified by an IO like object (which responds
|
311
|
+
# to <code>read</code>), a string, or a GPGME::Data object.
|
312
|
+
#
|
313
|
+
# An output argument is specified by an IO like object (which responds
|
314
|
+
# to <code>write</code>) or a GPGME::Data object.
|
315
|
+
#
|
316
|
+
# <i>options</i> are same as <code>GPGME::Ctx.new()</code> except for
|
317
|
+
#
|
318
|
+
# - <tt>:signers</tt> Signing keys. If specified, it is an array
|
319
|
+
# whose elements are a GPGME::Key object or a string.
|
320
|
+
#
|
321
|
+
def GPGME.detach_sign(plain, *args_options)
|
322
|
+
raise ArgumentError, 'wrong number of arguments' if args_options.length > 2
|
323
|
+
args, options = split_args(args_options)
|
324
|
+
args.push(options.merge({:mode => GPGME::SIG_MODE_DETACH}))
|
325
|
+
GPGME.sign(plain, *args)
|
326
|
+
end
|
327
|
+
|
328
|
+
# call-seq:
|
329
|
+
# GPGME.encrypt(recipients, plain, cipher=nil, options=Hash.new)
|
330
|
+
#
|
331
|
+
# <code>GPGME.encrypt</code> performs encryption.
|
332
|
+
#
|
333
|
+
# The arguments should be specified as follows.
|
334
|
+
#
|
335
|
+
# - GPGME.encrypt(<i>recipients</i>, <i>plain</i>, <i>cipher</i>, <i>options</i>)
|
336
|
+
# - GPGME.encrypt(<i>recipients</i>, <i>plain</i>, <i>options</i>) -> <i>cipher</i>
|
337
|
+
#
|
338
|
+
# All arguments except <i>recipients</i> and <i>plain</i> are
|
339
|
+
# optional. <i>plain</i> is input and <i>cipher</i> is output. If
|
340
|
+
# the last argument is a Hash, options will be read from it.
|
341
|
+
#
|
342
|
+
# The recipients are specified by an array whose elements are a string
|
343
|
+
# or a GPGME::Key object. If <i>recipients</i> is <tt>nil</tt>, it
|
344
|
+
# performs symmetric encryption.
|
345
|
+
#
|
346
|
+
# An input argument is specified by an IO like object (which responds
|
347
|
+
# to <code>read</code>), a string, or a GPGME::Data object.
|
348
|
+
#
|
349
|
+
# An output argument is specified by an IO like object (which responds
|
350
|
+
# to <code>write</code>) or a GPGME::Data object.
|
351
|
+
#
|
352
|
+
# <i>options</i> are same as <code>GPGME::Ctx.new()</code> except for
|
353
|
+
#
|
354
|
+
# - <tt>:sign</tt> If <tt>true</tt>, it performs a combined sign and
|
355
|
+
# encrypt operation.
|
356
|
+
# - <tt>:signers</tt> Signing keys. If specified, it is an array
|
357
|
+
# whose elements are a GPGME::Key object or a string.
|
358
|
+
# - <tt>:always_trust</tt> Setting this to <tt>true</tt> specifies all
|
359
|
+
# the recipients should be trusted.
|
360
|
+
#
|
361
|
+
def GPGME.encrypt(recipients, plain, *args_options)
|
362
|
+
raise ArgumentError, 'wrong number of arguments' if args_options.length > 3
|
363
|
+
args, options = split_args(args_options)
|
364
|
+
cipher = args[0]
|
365
|
+
recipient_keys = recipients ? resolve_keys(recipients, false, [:encrypt]) : nil
|
366
|
+
|
367
|
+
check_version(options)
|
368
|
+
GPGME::Ctx.new(options) do |ctx|
|
369
|
+
plain_data = input_data(plain)
|
370
|
+
cipher_data = output_data(cipher)
|
371
|
+
begin
|
372
|
+
flags = 0
|
373
|
+
if options[:always_trust]
|
374
|
+
flags |= GPGME::ENCRYPT_ALWAYS_TRUST
|
375
|
+
end
|
376
|
+
if options[:sign]
|
377
|
+
if options[:signers]
|
378
|
+
ctx.add_signer(*resolve_keys(options[:signers], true, [:sign]))
|
379
|
+
end
|
380
|
+
ctx.encrypt_sign(recipient_keys, plain_data, cipher_data, flags)
|
381
|
+
else
|
382
|
+
ctx.encrypt(recipient_keys, plain_data, cipher_data, flags)
|
383
|
+
end
|
384
|
+
rescue GPGME::Error::UnusablePublicKey => exc
|
385
|
+
exc.keys = ctx.encrypt_result.invalid_recipients
|
386
|
+
raise exc
|
387
|
+
rescue GPGME::Error::UnusableSecretKey => exc
|
388
|
+
exc.keys = ctx.sign_result.invalid_signers
|
389
|
+
raise exc
|
390
|
+
end
|
391
|
+
|
392
|
+
unless cipher
|
393
|
+
cipher_data.seek(0, IO::SEEK_SET)
|
394
|
+
cipher_data.read
|
395
|
+
end
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
# call-seq:
|
400
|
+
# GPGME.list_keys(pattern=nil, secret_only=false, options=Hash.new){|key| ...}
|
401
|
+
#
|
402
|
+
# <code>GPGME.list_keys</code> iterates over the key ring.
|
403
|
+
#
|
404
|
+
# The arguments should be specified as follows.
|
405
|
+
#
|
406
|
+
# - GPGME.list_keys(<i>pattern</i>, <i>secret_only</i>, <i>options</i>)
|
407
|
+
#
|
408
|
+
# All arguments are optional. If the last argument is a Hash, options
|
409
|
+
# will be read from it.
|
410
|
+
#
|
411
|
+
# <i>pattern</i> is a string or <tt>nil</tt>. If <i>pattern</i> is
|
412
|
+
# <tt>nil</tt>, all available keys are returned. If
|
413
|
+
# <i>secret_only</i> is <tt>true</tt>, the only secret keys are
|
414
|
+
# returned.
|
415
|
+
#
|
416
|
+
# <i>options</i> are same as <code>GPGME::Ctx.new()</code>.
|
417
|
+
#
|
418
|
+
def GPGME.list_keys(*args_options) # :yields: key
|
419
|
+
raise ArgumentError, 'wrong number of arguments' if args_options.length > 3
|
420
|
+
args, options = split_args(args_options)
|
421
|
+
pattern, secret_only = args
|
422
|
+
check_version(options)
|
423
|
+
GPGME::Ctx.new do |ctx|
|
424
|
+
if block_given?
|
425
|
+
ctx.each_key(pattern, secret_only || false) do |key|
|
426
|
+
yield key
|
427
|
+
end
|
428
|
+
else
|
429
|
+
ctx.keys(pattern, secret_only || false)
|
430
|
+
end
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
# call-seq:
|
435
|
+
# GPGME.export(pattern)
|
436
|
+
#
|
437
|
+
# <code>GPGME.export</code> extracts public keys from the key ring.
|
438
|
+
#
|
439
|
+
# The arguments should be specified as follows.
|
440
|
+
#
|
441
|
+
# - GPGME.export(<i>pattern</i>, <i>options</i>) -> <i>keydata</i>
|
442
|
+
# - GPGME.export(<i>pattern</i>, <i>keydata</i>, <i>options</i>)
|
443
|
+
#
|
444
|
+
# All arguments are optional. If the last argument is a Hash, options
|
445
|
+
# will be read from it.
|
446
|
+
#
|
447
|
+
# <i>pattern</i> is a string or <tt>nil</tt>. If <i>pattern</i> is
|
448
|
+
# <tt>nil</tt>, all available public keys are returned.
|
449
|
+
# <i>keydata</i> is output.
|
450
|
+
#
|
451
|
+
# An output argument is specified by an IO like object (which responds
|
452
|
+
# to <code>write</code>) or a GPGME::Data object.
|
453
|
+
#
|
454
|
+
# <i>options</i> are same as <code>GPGME::Ctx.new()</code>.
|
455
|
+
#
|
456
|
+
def GPGME.export(*args_options)
|
457
|
+
raise ArgumentError, 'wrong number of arguments' if args_options.length > 2
|
458
|
+
args, options = split_args(args_options)
|
459
|
+
pattern, key = args[0]
|
460
|
+
key_data = output_data(key)
|
461
|
+
check_version(options)
|
462
|
+
GPGME::Ctx.new(options) do |ctx|
|
463
|
+
ctx.export_keys(pattern, key_data)
|
464
|
+
|
465
|
+
unless key
|
466
|
+
key_data.seek(0, IO::SEEK_SET)
|
467
|
+
key_data.read
|
468
|
+
end
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
# call-seq:
|
473
|
+
# GPGME.import(keydata)
|
474
|
+
#
|
475
|
+
# <code>GPGME.import</code> adds the keys to the key ring.
|
476
|
+
#
|
477
|
+
# The arguments should be specified as follows.
|
478
|
+
#
|
479
|
+
# - GPGME.import(<i>keydata</i>, <i>options</i>)
|
480
|
+
#
|
481
|
+
# All arguments are optional. If the last argument is a Hash, options
|
482
|
+
# will be read from it.
|
483
|
+
#
|
484
|
+
# <i>keydata</i> is input.
|
485
|
+
#
|
486
|
+
# An input argument is specified by an IO like object (which responds
|
487
|
+
# to <code>read</code>), a string, or a GPGME::Data object.
|
488
|
+
#
|
489
|
+
# <i>options</i> are same as <code>GPGME::Ctx.new()</code>.
|
490
|
+
#
|
491
|
+
def GPGME.import(*args_options)
|
492
|
+
raise ArgumentError, 'wrong number of arguments' if args_options.length > 2
|
493
|
+
args, options = split_args(args_options)
|
494
|
+
key = args[0]
|
495
|
+
key_data = input_data(key)
|
496
|
+
check_version(options)
|
497
|
+
GPGME::Ctx.new(options) do |ctx|
|
498
|
+
ctx.import_keys(key_data)
|
499
|
+
ctx.import_result
|
500
|
+
end
|
501
|
+
end
|
502
|
+
|
503
|
+
module GPGME
|
504
|
+
# :stopdoc:
|
505
|
+
private
|
506
|
+
|
507
|
+
def split_args(args_options)
|
508
|
+
if args_options.length > 0 and args_options[-1].respond_to? :to_hash
|
509
|
+
args = args_options[0 ... -1]
|
510
|
+
options = args_options[-1].to_hash
|
511
|
+
else
|
512
|
+
args = args_options
|
513
|
+
options = Hash.new
|
514
|
+
end
|
515
|
+
[args, options]
|
516
|
+
end
|
517
|
+
module_function :split_args
|
518
|
+
|
519
|
+
def check_version(options = nil)
|
520
|
+
version = nil
|
521
|
+
if options.kind_of?(String)
|
522
|
+
version = options
|
523
|
+
elsif options.include?(:version)
|
524
|
+
version = options[:version]
|
525
|
+
end
|
526
|
+
unless GPGME::gpgme_check_version(version)
|
527
|
+
raise Error::InvalidVersion.new
|
528
|
+
end
|
529
|
+
end
|
530
|
+
module_function :check_version
|
531
|
+
|
532
|
+
def resolve_keys(keys_or_names, secret_only, purposes = Array.new)
|
533
|
+
keys = Array.new
|
534
|
+
keys_or_names.each do |key_or_name|
|
535
|
+
if key_or_name.kind_of? Key
|
536
|
+
keys << key_or_name
|
537
|
+
elsif key_or_name.kind_of? String
|
538
|
+
GPGME::Ctx.new do |ctx|
|
539
|
+
key = ctx.keys(key_or_name, secret_only).find {|k|
|
540
|
+
k.usable_for?(purposes)
|
541
|
+
}
|
542
|
+
keys << key if key
|
543
|
+
end
|
544
|
+
end
|
545
|
+
end
|
546
|
+
keys
|
547
|
+
end
|
548
|
+
module_function :resolve_keys
|
549
|
+
|
550
|
+
def input_data(input)
|
551
|
+
if input.kind_of? GPGME::Data
|
552
|
+
input
|
553
|
+
elsif input.respond_to? :to_str
|
554
|
+
GPGME::Data.from_str(input.to_str)
|
555
|
+
elsif input.respond_to? :read
|
556
|
+
GPGME::Data.from_callbacks(IOCallbacks.new(input))
|
557
|
+
else
|
558
|
+
raise ArgumentError, input.inspect
|
559
|
+
end
|
560
|
+
end
|
561
|
+
module_function :input_data
|
562
|
+
|
563
|
+
def output_data(output)
|
564
|
+
if output.kind_of? GPGME::Data
|
565
|
+
output
|
566
|
+
elsif output.respond_to? :write
|
567
|
+
GPGME::Data.from_callbacks(IOCallbacks.new(output))
|
568
|
+
elsif !output
|
569
|
+
GPGME::Data.empty
|
570
|
+
else
|
571
|
+
raise ArgumentError, output.inspect
|
572
|
+
end
|
573
|
+
end
|
574
|
+
module_function :output_data
|
575
|
+
|
576
|
+
class IOCallbacks
|
577
|
+
def initialize(io)
|
578
|
+
@io = io
|
579
|
+
end
|
580
|
+
|
581
|
+
def read(hook, length)
|
582
|
+
@io.read(length)
|
583
|
+
end
|
584
|
+
|
585
|
+
def write(hook, buffer, length)
|
586
|
+
@io.write(buffer[0 .. length])
|
587
|
+
end
|
588
|
+
|
589
|
+
def seek(hook, offset, whence)
|
590
|
+
return @io.pos if offset == 0 && whence == IO::SEEK_CUR
|
591
|
+
@io.seek(offset, whence)
|
592
|
+
@io.pos
|
593
|
+
end
|
594
|
+
end
|
595
|
+
|
596
|
+
PROTOCOL_NAMES = {
|
597
|
+
PROTOCOL_OpenPGP => :OpenPGP,
|
598
|
+
PROTOCOL_CMS => :CMS
|
599
|
+
}
|
600
|
+
|
601
|
+
KEYLIST_MODE_NAMES = {
|
602
|
+
KEYLIST_MODE_LOCAL => :local,
|
603
|
+
KEYLIST_MODE_EXTERN => :extern,
|
604
|
+
KEYLIST_MODE_SIGS => :sigs,
|
605
|
+
KEYLIST_MODE_VALIDATE => :validate
|
606
|
+
}
|
607
|
+
|
608
|
+
VALIDITY_NAMES = {
|
609
|
+
VALIDITY_UNKNOWN => :unknown,
|
610
|
+
VALIDITY_UNDEFINED => :undefined,
|
611
|
+
VALIDITY_NEVER => :never,
|
612
|
+
VALIDITY_MARGINAL => :marginal,
|
613
|
+
VALIDITY_FULL => :full,
|
614
|
+
VALIDITY_ULTIMATE => :ultimate
|
615
|
+
}
|
616
|
+
# :startdoc:
|
617
|
+
end
|
618
|
+
|
619
|
+
module GPGME
|
620
|
+
class Error < StandardError
|
621
|
+
def initialize(error)
|
622
|
+
@error = error
|
623
|
+
end
|
624
|
+
attr_reader :error
|
625
|
+
|
626
|
+
# Return the error code.
|
627
|
+
#
|
628
|
+
# The error code indicates the type of an error, or the reason why
|
629
|
+
# an operation failed.
|
630
|
+
def code
|
631
|
+
GPGME::gpgme_err_code(@error)
|
632
|
+
end
|
633
|
+
|
634
|
+
# Return the error source.
|
635
|
+
#
|
636
|
+
# The error source has not a precisely defined meaning. Sometimes
|
637
|
+
# it is the place where the error happened, sometimes it is the
|
638
|
+
# place where an error was encoded into an error value. Usually
|
639
|
+
# the error source will give an indication to where to look for
|
640
|
+
# the problem. This is not always true, but it is attempted to
|
641
|
+
# achieve this goal.
|
642
|
+
def source
|
643
|
+
GPGME::gpgme_err_source(@error)
|
644
|
+
end
|
645
|
+
|
646
|
+
# Return a description of the error code.
|
647
|
+
def message
|
648
|
+
GPGME::gpgme_strerror(@error)
|
649
|
+
end
|
650
|
+
|
651
|
+
class General < self; end
|
652
|
+
class InvalidValue < self; end
|
653
|
+
class UnusablePublicKey < self
|
654
|
+
attr_accessor :keys
|
655
|
+
end
|
656
|
+
class UnusableSecretKey < self
|
657
|
+
attr_accessor :keys
|
658
|
+
end
|
659
|
+
class NoData < self; end
|
660
|
+
class Conflict < self; end
|
661
|
+
class NotImplemented < self; end
|
662
|
+
class DecryptFailed < self; end
|
663
|
+
class BadPassphrase < self; end
|
664
|
+
class Canceled < self; end
|
665
|
+
class InvalidEngine < self; end
|
666
|
+
class AmbiguousName < self; end
|
667
|
+
class WrongKeyUsage < self
|
668
|
+
attr_accessor :key_usage
|
669
|
+
end
|
670
|
+
class CertificateRevoked < self; end
|
671
|
+
class CertificateExpired < self; end
|
672
|
+
class NoCRLKnown < self; end
|
673
|
+
class NoPolicyMatch < self; end
|
674
|
+
class NoSecretKey < self; end
|
675
|
+
class MissingCertificate < self; end
|
676
|
+
class BadCertificateChain < self; end
|
677
|
+
class UnsupportedAlgorithm < self
|
678
|
+
attr_accessor :algorithm
|
679
|
+
end
|
680
|
+
class BadSignature < self; end
|
681
|
+
class NoPublicKey < self; end
|
682
|
+
class InvalidVersion < self; end
|
683
|
+
end
|
684
|
+
|
685
|
+
def error_to_exception(err) # :nodoc:
|
686
|
+
case GPGME::gpgme_err_code(err)
|
687
|
+
when GPG_ERR_EOF
|
688
|
+
EOFError.new
|
689
|
+
when GPG_ERR_NO_ERROR
|
690
|
+
nil
|
691
|
+
when GPG_ERR_GENERAL
|
692
|
+
Error::General.new(err)
|
693
|
+
when GPG_ERR_ENOMEM
|
694
|
+
Errno::ENOMEM.new
|
695
|
+
when GPG_ERR_INV_VALUE
|
696
|
+
Error::InvalidValue.new(err)
|
697
|
+
when GPG_ERR_UNUSABLE_PUBKEY
|
698
|
+
Error::UnusablePublicKey.new(err)
|
699
|
+
when GPG_ERR_UNUSABLE_SECKEY
|
700
|
+
Error::UnusableSecretKey.new(err)
|
701
|
+
when GPG_ERR_NO_DATA
|
702
|
+
Error::NoData.new(err)
|
703
|
+
when GPG_ERR_CONFLICT
|
704
|
+
Error::Conflict.new(err)
|
705
|
+
when GPG_ERR_NOT_IMPLEMENTED
|
706
|
+
Error::NotImplemented.new(err)
|
707
|
+
when GPG_ERR_DECRYPT_FAILED
|
708
|
+
Error::DecryptFailed.new(err)
|
709
|
+
when GPG_ERR_BAD_PASSPHRASE
|
710
|
+
Error::BadPassphrase.new(err)
|
711
|
+
when GPG_ERR_CANCELED
|
712
|
+
Error::Canceled.new(err)
|
713
|
+
when GPG_ERR_INV_ENGINE
|
714
|
+
Error::InvalidEngine.new(err)
|
715
|
+
when GPG_ERR_AMBIGUOUS_NAME
|
716
|
+
Error::AmbiguousName.new(err)
|
717
|
+
when GPG_ERR_WRONG_KEY_USAGE
|
718
|
+
Error::WrongKeyUsage.new(err)
|
719
|
+
when GPG_ERR_CERT_REVOKED
|
720
|
+
Error::CertificateRevoked.new(err)
|
721
|
+
when GPG_ERR_CERT_EXPIRED
|
722
|
+
Error::CertificateExpired.new(err)
|
723
|
+
when GPG_ERR_NO_CRL_KNOWN
|
724
|
+
Error::NoCRLKnown.new(err)
|
725
|
+
when GPG_ERR_NO_POLICY_MATCH
|
726
|
+
Error::NoPolicyMatch.new(err)
|
727
|
+
when GPG_ERR_NO_SECKEY
|
728
|
+
Error::NoSecretKey.new(err)
|
729
|
+
when GPG_ERR_MISSING_CERT
|
730
|
+
Error::MissingCertificate.new(err)
|
731
|
+
when GPG_ERR_BAD_CERT_CHAIN
|
732
|
+
Error::BadCertificateChain.new(err)
|
733
|
+
when GPG_ERR_UNSUPPORTED_ALGORITHM
|
734
|
+
Error::UnsupportedAlgorithm.new(err)
|
735
|
+
when GPG_ERR_BAD_SIGNATURE
|
736
|
+
Error::BadSignature.new(err)
|
737
|
+
when GPG_ERR_NO_PUBKEY
|
738
|
+
Error::NoPublicKey.new(err)
|
739
|
+
else
|
740
|
+
Error.new(err)
|
741
|
+
end
|
742
|
+
end
|
743
|
+
module_function :error_to_exception
|
744
|
+
private :error_to_exception
|
745
|
+
|
746
|
+
class << self
|
747
|
+
alias pubkey_algo_name gpgme_pubkey_algo_name
|
748
|
+
alias hash_algo_name gpgme_hash_algo_name
|
749
|
+
end
|
750
|
+
|
751
|
+
# Verify that the engine implementing the protocol <i>proto</i> is
|
752
|
+
# installed in the system.
|
753
|
+
def engine_check_version(proto)
|
754
|
+
err = GPGME::gpgme_engine_check_version(proto)
|
755
|
+
exc = GPGME::error_to_exception(err)
|
756
|
+
raise exc if exc
|
757
|
+
end
|
758
|
+
module_function :engine_check_version
|
759
|
+
|
760
|
+
# Return a list of info structures of enabled engines.
|
761
|
+
def engine_info
|
762
|
+
rinfo = Array.new
|
763
|
+
GPGME::gpgme_get_engine_info(rinfo)
|
764
|
+
rinfo
|
765
|
+
end
|
766
|
+
module_function :engine_info
|
767
|
+
|
768
|
+
# Change the default configuration of the crypto engine implementing
|
769
|
+
# protocol <i>proto</i>.
|
770
|
+
#
|
771
|
+
# <i>file_name</i> is the file name of the executable program
|
772
|
+
# implementing the protocol.
|
773
|
+
# <i>home_dir</i> is the directory name of the configuration directory.
|
774
|
+
def set_engine_info(proto, file_name, home_dir)
|
775
|
+
err = GPGME::gpgme_set_engine_info(proto, file_name, home_dir)
|
776
|
+
exc = GPGME::error_to_exception(err)
|
777
|
+
raise exc if exc
|
778
|
+
end
|
779
|
+
module_function :set_engine_info
|
780
|
+
|
781
|
+
# A class for managing data buffers.
|
782
|
+
class Data
|
783
|
+
BLOCK_SIZE = 4096
|
784
|
+
|
785
|
+
# Create a new instance.
|
786
|
+
#
|
787
|
+
# The created data types depend on <i>arg</i>. If <i>arg</i> is
|
788
|
+
# <tt>nil</tt>, it creates an instance with an empty buffer.
|
789
|
+
# Otherwise, <i>arg</i> is either a string, an IO, or a Pathname.
|
790
|
+
def self.new(arg = nil, copy = false)
|
791
|
+
if arg.nil?
|
792
|
+
return empty
|
793
|
+
elsif arg.respond_to? :to_str
|
794
|
+
return from_str(arg.to_str, copy)
|
795
|
+
elsif arg.respond_to? :to_io
|
796
|
+
return from_io(arg.to_io)
|
797
|
+
elsif arg.respond_to? :open
|
798
|
+
return from_io(arg.open)
|
799
|
+
end
|
800
|
+
end
|
801
|
+
|
802
|
+
# Create a new instance with an empty buffer.
|
803
|
+
def self.empty
|
804
|
+
rdh = Array.new
|
805
|
+
err = GPGME::gpgme_data_new(rdh)
|
806
|
+
exc = GPGME::error_to_exception(err)
|
807
|
+
raise exc if exc
|
808
|
+
rdh[0]
|
809
|
+
end
|
810
|
+
|
811
|
+
# Create a new instance with internal buffer.
|
812
|
+
def self.from_str(buf, copy = true)
|
813
|
+
rdh = Array.new
|
814
|
+
err = GPGME::gpgme_data_new_from_mem(rdh, buf, buf.length)
|
815
|
+
exc = GPGME::error_to_exception(err)
|
816
|
+
raise exc if exc
|
817
|
+
rdh[0]
|
818
|
+
end
|
819
|
+
|
820
|
+
# Create a new instance associated with a given IO.
|
821
|
+
def self.from_io(io)
|
822
|
+
from_callbacks(IOCallbacks.new(arg))
|
823
|
+
end
|
824
|
+
|
825
|
+
# Create a new instance from the specified file descriptor.
|
826
|
+
def self.from_fd(fd)
|
827
|
+
rdh = Array.new
|
828
|
+
err = GPGME::gpgme_data_new_from_fd(rdh, fd)
|
829
|
+
exc = GPGME::error_to_exception(err)
|
830
|
+
raise exc if exc
|
831
|
+
rdh[0]
|
832
|
+
end
|
833
|
+
|
834
|
+
# Create a new instance from the specified callbacks.
|
835
|
+
def self.from_callbacks(callbacks, hook_value = nil)
|
836
|
+
rdh = Array.new
|
837
|
+
err = GPGME::gpgme_data_new_from_cbs(rdh, callbacks, hook_value)
|
838
|
+
exc = GPGME::error_to_exception(err)
|
839
|
+
raise exc if exc
|
840
|
+
rdh[0]
|
841
|
+
end
|
842
|
+
|
843
|
+
# Read at most <i>length</i> bytes from the data object, or to the end
|
844
|
+
# of file if <i>length</i> is omitted or is <tt>nil</tt>.
|
845
|
+
def read(length = nil)
|
846
|
+
if length
|
847
|
+
GPGME::gpgme_data_read(self, length)
|
848
|
+
else
|
849
|
+
buf = String.new
|
850
|
+
loop do
|
851
|
+
s = GPGME::gpgme_data_read(self, BLOCK_SIZE)
|
852
|
+
break unless s
|
853
|
+
buf << s
|
854
|
+
end
|
855
|
+
buf
|
856
|
+
end
|
857
|
+
end
|
858
|
+
|
859
|
+
# Seek to a given <i>offset</i> in the data object according to the
|
860
|
+
# value of <i>whence</i>.
|
861
|
+
def seek(offset, whence = IO::SEEK_SET)
|
862
|
+
GPGME::gpgme_data_seek(self, offset, IO::SEEK_SET)
|
863
|
+
end
|
864
|
+
|
865
|
+
# Write <i>length</i> bytes from <i>buffer</i> into the data object.
|
866
|
+
def write(buffer, length = buffer.length)
|
867
|
+
GPGME::gpgme_data_write(self, buffer, length)
|
868
|
+
end
|
869
|
+
|
870
|
+
# Return the encoding of the underlying data.
|
871
|
+
def encoding
|
872
|
+
GPGME::gpgme_data_get_encoding(self)
|
873
|
+
end
|
874
|
+
|
875
|
+
# Set the encoding to a given <i>encoding</i> of the underlying
|
876
|
+
# data object.
|
877
|
+
def encoding=(encoding)
|
878
|
+
err = GPGME::gpgme_data_set_encoding(self, encoding)
|
879
|
+
exc = GPGME::error_to_exception(err)
|
880
|
+
raise exc if exc
|
881
|
+
encoding
|
882
|
+
end
|
883
|
+
end
|
884
|
+
|
885
|
+
class EngineInfo
|
886
|
+
private_class_method :new
|
887
|
+
|
888
|
+
attr_reader :protocol, :file_name, :version, :req_version, :home_dir
|
889
|
+
alias required_version req_version
|
890
|
+
end
|
891
|
+
|
892
|
+
# A context within which all cryptographic operations are performed.
|
893
|
+
class Ctx
|
894
|
+
# Create a new instance from the given <i>options</i>.
|
895
|
+
# <i>options</i> is a Hash whose keys are
|
896
|
+
#
|
897
|
+
# * <tt>:protocol</tt> Either <tt>PROTOCOL_OpenPGP</tt> or
|
898
|
+
# <tt>PROTOCOL_CMS</tt>.
|
899
|
+
#
|
900
|
+
# * <tt>:armor</tt> If <tt>true</tt>, the output should be ASCII armored.
|
901
|
+
#
|
902
|
+
# * <tt>:textmode</tt> If <tt>true</tt>, inform the recipient that the
|
903
|
+
# input is text.
|
904
|
+
#
|
905
|
+
# * <tt>:keylist_mode</tt> Either
|
906
|
+
# <tt>KEYLIST_MODE_LOCAL</tt>,
|
907
|
+
# <tt>KEYLIST_MODE_EXTERN</tt>,
|
908
|
+
# <tt>KEYLIST_MODE_SIGS</tt>, or
|
909
|
+
# <tt>KEYLIST_MODE_VALIDATE</tt>.
|
910
|
+
# * <tt>:passphrase_callback</tt> A callback function.
|
911
|
+
# * <tt>:passphrase_callback_value</tt> An object passed to
|
912
|
+
# passphrase_callback.
|
913
|
+
# * <tt>:progress_callback</tt> A callback function.
|
914
|
+
# * <tt>:progress_callback_value</tt> An object passed to
|
915
|
+
# progress_callback.
|
916
|
+
#
|
917
|
+
def self.new(options = Hash.new)
|
918
|
+
rctx = Array.new
|
919
|
+
err = GPGME::gpgme_new(rctx)
|
920
|
+
exc = GPGME::error_to_exception(err)
|
921
|
+
raise exc if exc
|
922
|
+
ctx = rctx[0]
|
923
|
+
options.each_pair do |key, value|
|
924
|
+
case key
|
925
|
+
when :protocol
|
926
|
+
ctx.protocol = value
|
927
|
+
when :armor
|
928
|
+
ctx.armor = value
|
929
|
+
when :textmode
|
930
|
+
ctx.textmode = value
|
931
|
+
when :keylist_mode
|
932
|
+
ctx.keylist_mode = value
|
933
|
+
when :passphrase_callback
|
934
|
+
ctx.set_passphrase_callback(value,
|
935
|
+
options[:passphrase_callback_value])
|
936
|
+
when :progress_callback
|
937
|
+
ctx.set_progress_callback(value,
|
938
|
+
options[:progress_callback_value])
|
939
|
+
end
|
940
|
+
end
|
941
|
+
if block_given?
|
942
|
+
begin
|
943
|
+
yield ctx
|
944
|
+
ensure
|
945
|
+
GPGME::gpgme_release(ctx)
|
946
|
+
end
|
947
|
+
else
|
948
|
+
ctx
|
949
|
+
end
|
950
|
+
end
|
951
|
+
|
952
|
+
# Set the <i>protocol</i> used within this context.
|
953
|
+
def protocol=(proto)
|
954
|
+
err = GPGME::gpgme_set_protocol(self, proto)
|
955
|
+
exc = GPGME::error_to_exception(err)
|
956
|
+
raise exc if exc
|
957
|
+
proto
|
958
|
+
end
|
959
|
+
|
960
|
+
# Return the protocol used within this context.
|
961
|
+
def protocol
|
962
|
+
GPGME::gpgme_get_protocol(self)
|
963
|
+
end
|
964
|
+
|
965
|
+
# Tell whether the output should be ASCII armored.
|
966
|
+
def armor=(yes)
|
967
|
+
GPGME::gpgme_set_armor(self, yes ? 1 : 0)
|
968
|
+
yes
|
969
|
+
end
|
970
|
+
|
971
|
+
# Return true if the output is ASCII armored.
|
972
|
+
def armor
|
973
|
+
GPGME::gpgme_get_armor(self) == 1 ? true : false
|
974
|
+
end
|
975
|
+
|
976
|
+
# Tell whether canonical text mode should be used.
|
977
|
+
def textmode=(yes)
|
978
|
+
GPGME::gpgme_set_textmode(self, yes ? 1 : 0)
|
979
|
+
yes
|
980
|
+
end
|
981
|
+
|
982
|
+
# Return true if canonical text mode is enabled.
|
983
|
+
def textmode
|
984
|
+
GPGME::gpgme_get_textmode(self) == 1 ? true : false
|
985
|
+
end
|
986
|
+
|
987
|
+
# Change the default behaviour of the key listing functions.
|
988
|
+
def keylist_mode=(mode)
|
989
|
+
GPGME::gpgme_set_keylist_mode(self, mode)
|
990
|
+
mode
|
991
|
+
end
|
992
|
+
|
993
|
+
# Return the current key listing mode.
|
994
|
+
def keylist_mode
|
995
|
+
GPGME::gpgme_get_keylist_mode(self)
|
996
|
+
end
|
997
|
+
|
998
|
+
def inspect
|
999
|
+
"#<#{self.class} protocol=#{PROTOCOL_NAMES[protocol] || protocol}, \
|
1000
|
+
armor=#{armor}, textmode=#{textmode}, \
|
1001
|
+
keylist_mode=#{KEYLIST_MODE_NAMES[keylist_mode]}>"
|
1002
|
+
end
|
1003
|
+
|
1004
|
+
# Set the passphrase callback with given hook value.
|
1005
|
+
# <i>passfunc</i> should respond to <code>call</code> with 5 arguments.
|
1006
|
+
#
|
1007
|
+
# def passfunc(hook, uid_hint, passphrase_info, prev_was_bad, fd)
|
1008
|
+
# $stderr.write("Passphrase for #{uid_hint}: ")
|
1009
|
+
# $stderr.flush
|
1010
|
+
# begin
|
1011
|
+
# system('stty -echo')
|
1012
|
+
# io = IO.for_fd(fd, 'w')
|
1013
|
+
# io.puts(gets)
|
1014
|
+
# io.flush
|
1015
|
+
# ensure
|
1016
|
+
# (0 ... $_.length).each do |i| $_[i] = ?0 end if $_
|
1017
|
+
# system('stty echo')
|
1018
|
+
# end
|
1019
|
+
# $stderr.puts
|
1020
|
+
# end
|
1021
|
+
#
|
1022
|
+
# ctx.set_passphrase_callback(method(:passfunc))
|
1023
|
+
#
|
1024
|
+
def set_passphrase_callback(passfunc, hook_value = nil)
|
1025
|
+
GPGME::gpgme_set_passphrase_cb(self, passfunc, hook_value)
|
1026
|
+
end
|
1027
|
+
alias set_passphrase_cb set_passphrase_callback
|
1028
|
+
|
1029
|
+
# Set the progress callback with given hook value.
|
1030
|
+
# <i>progfunc</i> should respond to <code>call</code> with 5 arguments.
|
1031
|
+
#
|
1032
|
+
# def progfunc(hook, what, type, current, total)
|
1033
|
+
# $stderr.write("#{what}: #{current}/#{total}\r")
|
1034
|
+
# $stderr.flush
|
1035
|
+
# end
|
1036
|
+
#
|
1037
|
+
# ctx.set_progress_callback(method(:progfunc))
|
1038
|
+
#
|
1039
|
+
def set_progress_callback(progfunc, hook_value = nil)
|
1040
|
+
GPGME::gpgme_set_progress_cb(self, progfunc, hook_value)
|
1041
|
+
end
|
1042
|
+
alias set_progress_cb set_progress_callback
|
1043
|
+
|
1044
|
+
# Initiate a key listing operation for given pattern.
|
1045
|
+
# If <i>pattern</i> is <tt>nil</tt>, all available keys are
|
1046
|
+
# returned. If <i>secret_only</i> is <tt>true</tt>, the only
|
1047
|
+
# secret keys are returned.
|
1048
|
+
def keylist_start(pattern = nil, secret_only = false)
|
1049
|
+
err = GPGME::gpgme_op_keylist_start(self, pattern, secret_only ? 1 : 0)
|
1050
|
+
exc = GPGME::error_to_exception(err)
|
1051
|
+
raise exc if exc
|
1052
|
+
end
|
1053
|
+
|
1054
|
+
# Advance to the next key in the key listing operation.
|
1055
|
+
def keylist_next
|
1056
|
+
rkey = Array.new
|
1057
|
+
err = GPGME::gpgme_op_keylist_next(self, rkey)
|
1058
|
+
exc = GPGME::error_to_exception(err)
|
1059
|
+
raise exc if exc
|
1060
|
+
rkey[0]
|
1061
|
+
end
|
1062
|
+
|
1063
|
+
# End a pending key list operation.
|
1064
|
+
def keylist_end
|
1065
|
+
err = GPGME::gpgme_op_keylist_end(self)
|
1066
|
+
exc = GPGME::error_to_exception(err)
|
1067
|
+
raise exc if exc
|
1068
|
+
end
|
1069
|
+
|
1070
|
+
# Convenient method to iterate over keys.
|
1071
|
+
# If <i>pattern</i> is <tt>nil</tt>, all available keys are
|
1072
|
+
# returned. If <i>secret_only</i> is <tt>true</tt>, the only
|
1073
|
+
# secret keys are returned.
|
1074
|
+
def each_key(pattern = nil, secret_only = false, &block) # :yields: key
|
1075
|
+
keylist_start(pattern, secret_only)
|
1076
|
+
begin
|
1077
|
+
loop do
|
1078
|
+
yield keylist_next
|
1079
|
+
end
|
1080
|
+
keys
|
1081
|
+
rescue EOFError
|
1082
|
+
# The last key in the list has already been returned.
|
1083
|
+
ensure
|
1084
|
+
keylist_end
|
1085
|
+
end
|
1086
|
+
end
|
1087
|
+
alias each_keys each_key
|
1088
|
+
|
1089
|
+
def keys(pattern = nil, secret_only = nil)
|
1090
|
+
keys = Array.new
|
1091
|
+
each_key(pattern, secret_only) do |key|
|
1092
|
+
keys << key
|
1093
|
+
end
|
1094
|
+
keys
|
1095
|
+
end
|
1096
|
+
|
1097
|
+
# Get the key with the <i>fingerprint</i>.
|
1098
|
+
# If <i>secret</i> is <tt>true</tt>, secret key is returned.
|
1099
|
+
def get_key(fingerprint, secret = false)
|
1100
|
+
rkey = Array.new
|
1101
|
+
err = GPGME::gpgme_get_key(self, fingerprint, rkey, secret ? 1 : 0)
|
1102
|
+
exc = GPGME::error_to_exception(err)
|
1103
|
+
raise exc if exc
|
1104
|
+
rkey[0]
|
1105
|
+
end
|
1106
|
+
|
1107
|
+
# Generate a new key pair.
|
1108
|
+
# <i>parms</i> is a string which looks like
|
1109
|
+
#
|
1110
|
+
# <GnupgKeyParms format="internal">
|
1111
|
+
# Key-Type: DSA
|
1112
|
+
# Key-Length: 1024
|
1113
|
+
# Subkey-Type: ELG-E
|
1114
|
+
# Subkey-Length: 1024
|
1115
|
+
# Name-Real: Joe Tester
|
1116
|
+
# Name-Comment: with stupid passphrase
|
1117
|
+
# Name-Email: joe@foo.bar
|
1118
|
+
# Expire-Date: 0
|
1119
|
+
# Passphrase: abc
|
1120
|
+
# </GnupgKeyParms>
|
1121
|
+
#
|
1122
|
+
# If <i>pubkey</i> and <i>seckey</i> are both set to <tt>nil</tt>,
|
1123
|
+
# it stores the generated key pair into your key ring.
|
1124
|
+
def generate_key(parms, pubkey = Data.new, seckey = Data.new)
|
1125
|
+
err = GPGME::gpgme_op_genkey(self, parms, pubkey, seckey)
|
1126
|
+
exc = GPGME::error_to_exception(err)
|
1127
|
+
raise exc if exc
|
1128
|
+
end
|
1129
|
+
alias genkey generate_key
|
1130
|
+
|
1131
|
+
# Extract the public keys of the recipients.
|
1132
|
+
def export_keys(recipients, keydata = Data.new)
|
1133
|
+
err = GPGME::gpgme_op_export(self, recipients, 0, keydata)
|
1134
|
+
exc = GPGME::error_to_exception(err)
|
1135
|
+
raise exc if exc
|
1136
|
+
keydata
|
1137
|
+
end
|
1138
|
+
alias export export_keys
|
1139
|
+
|
1140
|
+
# Add the keys in the data buffer to the key ring.
|
1141
|
+
def import_keys(keydata)
|
1142
|
+
err = GPGME::gpgme_op_import(self, keydata)
|
1143
|
+
exc = GPGME::error_to_exception(err)
|
1144
|
+
raise exc if exc
|
1145
|
+
end
|
1146
|
+
alias import import_keys
|
1147
|
+
|
1148
|
+
def import_result
|
1149
|
+
GPGME::gpgme_op_import_result(self)
|
1150
|
+
end
|
1151
|
+
|
1152
|
+
# Delete the key from the key ring.
|
1153
|
+
# If allow_secret is false, only public keys are deleted,
|
1154
|
+
# otherwise secret keys are deleted as well.
|
1155
|
+
def delete_key(key, allow_secret = false)
|
1156
|
+
err = GPGME::gpgme_op_delete(self, key, allow_secret ? 1 : 0)
|
1157
|
+
exc = GPGME::error_to_exception(err)
|
1158
|
+
raise exc if exc
|
1159
|
+
end
|
1160
|
+
alias delete delete_key
|
1161
|
+
|
1162
|
+
# Edit attributes of the key in the local key ring.
|
1163
|
+
def edit_key(key, editfunc, hook_value = nil, out = Data.new)
|
1164
|
+
err = GPGME::gpgme_op_edit(self, key, editfunc, hook_value, out)
|
1165
|
+
exc = GPGME::error_to_exception(err)
|
1166
|
+
raise exc if exc
|
1167
|
+
end
|
1168
|
+
alias edit edit_key
|
1169
|
+
|
1170
|
+
# Edit attributes of the key on the card.
|
1171
|
+
def edit_card_key(key, editfunc, hook_value = nil, out = Data.new)
|
1172
|
+
err = GPGME::gpgme_op_card_edit(self, key, editfunc, hook_value, out)
|
1173
|
+
exc = GPGME::error_to_exception(err)
|
1174
|
+
raise exc if exc
|
1175
|
+
end
|
1176
|
+
alias edit_card edit_card_key
|
1177
|
+
alias card_edit edit_card_key
|
1178
|
+
|
1179
|
+
# Decrypt the ciphertext and return the plaintext.
|
1180
|
+
def decrypt(cipher, plain = Data.new)
|
1181
|
+
err = GPGME::gpgme_op_decrypt(self, cipher, plain)
|
1182
|
+
exc = GPGME::error_to_exception(err)
|
1183
|
+
raise exc if exc
|
1184
|
+
plain
|
1185
|
+
end
|
1186
|
+
|
1187
|
+
def decrypt_verify(cipher, plain = Data.new)
|
1188
|
+
err = GPGME::gpgme_op_decrypt_verify(self, cipher, plain)
|
1189
|
+
exc = GPGME::error_to_exception(err)
|
1190
|
+
raise exc if exc
|
1191
|
+
plain
|
1192
|
+
end
|
1193
|
+
|
1194
|
+
def decrypt_result
|
1195
|
+
GPGME::gpgme_op_decrypt_result(self)
|
1196
|
+
end
|
1197
|
+
|
1198
|
+
# Verify that the signature in the data object is a valid signature.
|
1199
|
+
def verify(sig, signed_text = nil, plain = Data.new)
|
1200
|
+
err = GPGME::gpgme_op_verify(self, sig, signed_text, plain)
|
1201
|
+
exc = GPGME::error_to_exception(err)
|
1202
|
+
raise exc if exc
|
1203
|
+
plain
|
1204
|
+
end
|
1205
|
+
|
1206
|
+
def verify_result
|
1207
|
+
GPGME::gpgme_op_verify_result(self)
|
1208
|
+
end
|
1209
|
+
|
1210
|
+
# Decrypt the ciphertext and return the plaintext.
|
1211
|
+
def decrypt_verify(cipher, plain = Data.new)
|
1212
|
+
err = GPGME::gpgme_op_decrypt_verify(self, cipher, plain)
|
1213
|
+
exc = GPGME::error_to_exception(err)
|
1214
|
+
raise exc if exc
|
1215
|
+
plain
|
1216
|
+
end
|
1217
|
+
|
1218
|
+
# Remove the list of signers from this object.
|
1219
|
+
def clear_signers
|
1220
|
+
GPGME::gpgme_signers_clear(self)
|
1221
|
+
end
|
1222
|
+
|
1223
|
+
# Add _keys_ to the list of signers.
|
1224
|
+
def add_signer(*keys)
|
1225
|
+
keys.each do |key|
|
1226
|
+
err = GPGME::gpgme_signers_add(self, key)
|
1227
|
+
exc = GPGME::error_to_exception(err)
|
1228
|
+
raise exc if exc
|
1229
|
+
end
|
1230
|
+
end
|
1231
|
+
|
1232
|
+
# Create a signature for the text.
|
1233
|
+
# <i>plain</i> is a data object which contains the text.
|
1234
|
+
# <i>sig</i> is a data object where the generated signature is stored.
|
1235
|
+
def sign(plain, sig = Data.new, mode = GPGME::SIG_MODE_NORMAL)
|
1236
|
+
err = GPGME::gpgme_op_sign(self, plain, sig, mode)
|
1237
|
+
exc = GPGME::error_to_exception(err)
|
1238
|
+
raise exc if exc
|
1239
|
+
sig
|
1240
|
+
end
|
1241
|
+
|
1242
|
+
def sign_result
|
1243
|
+
GPGME::gpgme_op_sign_result(self)
|
1244
|
+
end
|
1245
|
+
|
1246
|
+
# Encrypt the plaintext in the data object for the recipients and
|
1247
|
+
# return the ciphertext.
|
1248
|
+
def encrypt(recp, plain, cipher = Data.new, flags = 0)
|
1249
|
+
err = GPGME::gpgme_op_encrypt(self, recp, flags, plain, cipher)
|
1250
|
+
exc = GPGME::error_to_exception(err)
|
1251
|
+
raise exc if exc
|
1252
|
+
cipher
|
1253
|
+
end
|
1254
|
+
|
1255
|
+
def encrypt_result
|
1256
|
+
GPGME::gpgme_op_encrypt_result(self)
|
1257
|
+
end
|
1258
|
+
|
1259
|
+
def encrypt_sign(recp, plain, cipher = Data.new, flags = 0)
|
1260
|
+
err = GPGME::gpgme_op_encrypt_sign(self, recp, flags, plain, cipher)
|
1261
|
+
exc = GPGME::error_to_exception(err)
|
1262
|
+
raise exc if exc
|
1263
|
+
cipher
|
1264
|
+
end
|
1265
|
+
end
|
1266
|
+
|
1267
|
+
# A public or secret key.
|
1268
|
+
class Key
|
1269
|
+
private_class_method :new
|
1270
|
+
|
1271
|
+
attr_reader :keylist_mode, :protocol, :owner_trust
|
1272
|
+
attr_reader :issuer_serial, :issuer_name, :chain_id
|
1273
|
+
attr_reader :subkeys, :uids
|
1274
|
+
|
1275
|
+
def trust
|
1276
|
+
return :revoked if @revoked == 1
|
1277
|
+
return :expired if @expired == 1
|
1278
|
+
return :disabled if @disabled == 1
|
1279
|
+
return :invalid if @invalid == 1
|
1280
|
+
end
|
1281
|
+
|
1282
|
+
def capability
|
1283
|
+
caps = Array.new
|
1284
|
+
caps << :encrypt if @can_encrypt
|
1285
|
+
caps << :sign if @can_sign
|
1286
|
+
caps << :certify if @can_certify
|
1287
|
+
caps << :authenticate if @can_authenticate
|
1288
|
+
caps
|
1289
|
+
end
|
1290
|
+
|
1291
|
+
def usable_for?(purposes)
|
1292
|
+
unless purposes.kind_of? Array
|
1293
|
+
purposes = [purposes]
|
1294
|
+
end
|
1295
|
+
return false if [:revoked, :expired, :disabled, :invalid].include? trust
|
1296
|
+
return (purposes - capability).empty?
|
1297
|
+
end
|
1298
|
+
|
1299
|
+
def secret?
|
1300
|
+
@secret == 1
|
1301
|
+
end
|
1302
|
+
|
1303
|
+
def inspect
|
1304
|
+
primary_subkey = subkeys[0]
|
1305
|
+
sprintf("#<#{self.class} %s %4d%c/%s %s trust=%s, owner_trust=%s, \
|
1306
|
+
capability=%s, subkeys=%s, uids=%s>",
|
1307
|
+
primary_subkey.secret? ? 'sec' : 'pub',
|
1308
|
+
primary_subkey.length,
|
1309
|
+
primary_subkey.pubkey_algo_letter,
|
1310
|
+
primary_subkey.fingerprint[-8 .. -1],
|
1311
|
+
primary_subkey.timestamp.strftime('%Y-%m-%d'),
|
1312
|
+
trust.inspect,
|
1313
|
+
VALIDITY_NAMES[@owner_trust].inspect,
|
1314
|
+
capability.inspect,
|
1315
|
+
subkeys.inspect,
|
1316
|
+
uids.inspect)
|
1317
|
+
end
|
1318
|
+
|
1319
|
+
def to_s
|
1320
|
+
primary_subkey = subkeys[0]
|
1321
|
+
s = sprintf("%s %4d%c/%s %s\n",
|
1322
|
+
primary_subkey.secret? ? 'sec' : 'pub',
|
1323
|
+
primary_subkey.length,
|
1324
|
+
primary_subkey.pubkey_algo_letter,
|
1325
|
+
primary_subkey.fingerprint[-8 .. -1],
|
1326
|
+
primary_subkey.timestamp.strftime('%Y-%m-%d'))
|
1327
|
+
uids.each do |user_id|
|
1328
|
+
s << "uid\t\t#{user_id.name} <#{user_id.email}>\n"
|
1329
|
+
end
|
1330
|
+
subkeys.each do |subkey|
|
1331
|
+
s << subkey.to_s
|
1332
|
+
end
|
1333
|
+
s
|
1334
|
+
end
|
1335
|
+
end
|
1336
|
+
|
1337
|
+
class SubKey
|
1338
|
+
private_class_method :new
|
1339
|
+
|
1340
|
+
attr_reader :pubkey_algo, :length, :keyid, :fpr
|
1341
|
+
alias fingerprint fpr
|
1342
|
+
|
1343
|
+
def trust
|
1344
|
+
return :revoked if @revoked == 1
|
1345
|
+
return :expired if @expired == 1
|
1346
|
+
return :disabled if @disabled == 1
|
1347
|
+
return :invalid if @invalid == 1
|
1348
|
+
end
|
1349
|
+
|
1350
|
+
def capability
|
1351
|
+
caps = Array.new
|
1352
|
+
caps << :encrypt if @can_encrypt
|
1353
|
+
caps << :sign if @can_sign
|
1354
|
+
caps << :certify if @can_certify
|
1355
|
+
caps << :authenticate if @can_authenticate
|
1356
|
+
caps
|
1357
|
+
end
|
1358
|
+
|
1359
|
+
def usable_for?(purposes)
|
1360
|
+
unless purposes.kind_of? Array
|
1361
|
+
purposes = [purposes]
|
1362
|
+
end
|
1363
|
+
return false if [:revoked, :expired, :disabled, :invalid].include? trust
|
1364
|
+
return (purposes - capability).empty?
|
1365
|
+
end
|
1366
|
+
|
1367
|
+
def secret?
|
1368
|
+
@secret == 1
|
1369
|
+
end
|
1370
|
+
|
1371
|
+
def timestamp
|
1372
|
+
Time.at(@timestamp)
|
1373
|
+
end
|
1374
|
+
|
1375
|
+
def expires
|
1376
|
+
Time.at(@expires)
|
1377
|
+
end
|
1378
|
+
|
1379
|
+
PUBKEY_ALGO_LETTERS = {
|
1380
|
+
PK_RSA => ?R,
|
1381
|
+
PK_ELG_E => ?g,
|
1382
|
+
PK_ELG => ?G,
|
1383
|
+
PK_DSA => ?D
|
1384
|
+
}
|
1385
|
+
|
1386
|
+
def pubkey_algo_letter
|
1387
|
+
PUBKEY_ALGO_LETTERS[@pubkey_algo] || ??
|
1388
|
+
end
|
1389
|
+
|
1390
|
+
def inspect
|
1391
|
+
sprintf("#<#{self.class} %s %4d%c/%s %s trust=%s, capability=%s>",
|
1392
|
+
secret? ? 'ssc' : 'sub',
|
1393
|
+
length,
|
1394
|
+
pubkey_algo_letter,
|
1395
|
+
(@fingerprint || @keyid)[-8 .. -1],
|
1396
|
+
timestamp.strftime('%Y-%m-%d'),
|
1397
|
+
trust.inspect,
|
1398
|
+
capability.inspect)
|
1399
|
+
end
|
1400
|
+
|
1401
|
+
def to_s
|
1402
|
+
sprintf("%s %4d%c/%s %s\n",
|
1403
|
+
secret? ? 'ssc' : 'sub',
|
1404
|
+
length,
|
1405
|
+
pubkey_algo_letter,
|
1406
|
+
(@fingerprint || @keyid)[-8 .. -1],
|
1407
|
+
timestamp.strftime('%Y-%m-%d'))
|
1408
|
+
end
|
1409
|
+
end
|
1410
|
+
|
1411
|
+
class UserID
|
1412
|
+
private_class_method :new
|
1413
|
+
|
1414
|
+
attr_reader :validity, :uid, :name, :comment, :email, :signatures
|
1415
|
+
|
1416
|
+
def revoked?
|
1417
|
+
@revoked == 1
|
1418
|
+
end
|
1419
|
+
|
1420
|
+
def invalid?
|
1421
|
+
@invalid == 1
|
1422
|
+
end
|
1423
|
+
|
1424
|
+
def inspect
|
1425
|
+
"#<#{self.class} #{name} <#{email}> \
|
1426
|
+
validity=#{VALIDITY_NAMES[validity]}, signatures=#{signatures.inspect}>"
|
1427
|
+
end
|
1428
|
+
end
|
1429
|
+
|
1430
|
+
class KeySig
|
1431
|
+
private_class_method :new
|
1432
|
+
|
1433
|
+
attr_reader :pubkey_algo, :keyid
|
1434
|
+
|
1435
|
+
def revoked?
|
1436
|
+
@revoked == 1
|
1437
|
+
end
|
1438
|
+
|
1439
|
+
def expired?
|
1440
|
+
@expired == 1
|
1441
|
+
end
|
1442
|
+
|
1443
|
+
def invalid?
|
1444
|
+
@invalid == 1
|
1445
|
+
end
|
1446
|
+
|
1447
|
+
def exportable?
|
1448
|
+
@exportable == 1
|
1449
|
+
end
|
1450
|
+
|
1451
|
+
def timestamp
|
1452
|
+
Time.at(@timestamp)
|
1453
|
+
end
|
1454
|
+
|
1455
|
+
def expires
|
1456
|
+
Time.at(@expires)
|
1457
|
+
end
|
1458
|
+
|
1459
|
+
def inspect
|
1460
|
+
"#<#{self.class} #{keyid} timestamp=#{timestamp}, expires=#{expires}>"
|
1461
|
+
end
|
1462
|
+
end
|
1463
|
+
|
1464
|
+
class VerifyResult
|
1465
|
+
private_class_method :new
|
1466
|
+
|
1467
|
+
attr_reader :signatures
|
1468
|
+
end
|
1469
|
+
|
1470
|
+
class Signature
|
1471
|
+
private_class_method :new
|
1472
|
+
|
1473
|
+
attr_reader :summary, :fpr, :status, :notations, :wrong_key_usage
|
1474
|
+
attr_reader :validity, :validity_reason
|
1475
|
+
attr_reader :pka_trust, :pka_address
|
1476
|
+
alias fingerprint fpr
|
1477
|
+
|
1478
|
+
def timestamp
|
1479
|
+
Time.at(@timestamp)
|
1480
|
+
end
|
1481
|
+
|
1482
|
+
def exp_timestamp
|
1483
|
+
Time.at(@exp_timestamp)
|
1484
|
+
end
|
1485
|
+
|
1486
|
+
def to_s
|
1487
|
+
ctx = Ctx.new
|
1488
|
+
if from_key = ctx.get_key(fingerprint)
|
1489
|
+
from = "#{from_key.subkeys[0].keyid} #{from_key.uids[0].uid}"
|
1490
|
+
else
|
1491
|
+
from = fingerprint
|
1492
|
+
end
|
1493
|
+
case GPGME::gpgme_err_code(status)
|
1494
|
+
when GPGME::GPG_ERR_NO_ERROR
|
1495
|
+
"Good signature from #{from}"
|
1496
|
+
when GPGME::GPG_ERR_SIG_EXPIRED
|
1497
|
+
"Expired signature from #{from}"
|
1498
|
+
when GPGME::GPG_ERR_KEY_EXPIRED
|
1499
|
+
"Signature made from expired key #{from}"
|
1500
|
+
when GPGME::GPG_ERR_CERT_REVOKED
|
1501
|
+
"Signature made from revoked key #{from}"
|
1502
|
+
when GPGME::GPG_ERR_BAD_SIGNATURE
|
1503
|
+
"Bad signature from #{from}"
|
1504
|
+
when GPGME::GPG_ERR_NO_ERROR
|
1505
|
+
"No public key for #{from}"
|
1506
|
+
end
|
1507
|
+
end
|
1508
|
+
end
|
1509
|
+
|
1510
|
+
class DecryptResult
|
1511
|
+
private_class_method :new
|
1512
|
+
|
1513
|
+
attr_reader :unsupported_algorithm, :wrong_key_usage
|
1514
|
+
end
|
1515
|
+
|
1516
|
+
class SignResult
|
1517
|
+
private_class_method :new
|
1518
|
+
|
1519
|
+
attr_reader :invalid_signers, :signatures
|
1520
|
+
end
|
1521
|
+
|
1522
|
+
class EncryptResult
|
1523
|
+
private_class_method :new
|
1524
|
+
|
1525
|
+
attr_reader :invalid_recipients
|
1526
|
+
end
|
1527
|
+
|
1528
|
+
class InvalidKey
|
1529
|
+
private_class_method :new
|
1530
|
+
|
1531
|
+
attr_reader :fpr, :reason
|
1532
|
+
alias fingerprint fpr
|
1533
|
+
end
|
1534
|
+
|
1535
|
+
class NewSignature
|
1536
|
+
private_class_method :new
|
1537
|
+
|
1538
|
+
attr_reader :type, :pubkey_algo, :hash_algo, :sig_class, :fpr
|
1539
|
+
alias fingerprint fpr
|
1540
|
+
|
1541
|
+
def timestamp
|
1542
|
+
Time.at(@timestamp)
|
1543
|
+
end
|
1544
|
+
end
|
1545
|
+
|
1546
|
+
class ImportStatus
|
1547
|
+
private_class_method :new
|
1548
|
+
|
1549
|
+
attr_reader :fpr, :result, :status
|
1550
|
+
alias fingerprint fpr
|
1551
|
+
end
|
1552
|
+
|
1553
|
+
class ImportResult
|
1554
|
+
private_class_method :new
|
1555
|
+
|
1556
|
+
attr_reader :considered, :no_user_id, :imported, :imported_rsa, :unchanged
|
1557
|
+
attr_reader :new_user_ids, :new_sub_keys, :new_signatures, :new_revocations
|
1558
|
+
attr_reader :secret_read, :secret_imported, :secret_unchanged
|
1559
|
+
attr_reader :not_imported, :imports
|
1560
|
+
end
|
1561
|
+
end
|