gpgme 1.0.8 → 2.0.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.
Files changed (49) hide show
  1. data/examples/genkey.rb +1 -1
  2. data/examples/keylist.rb +2 -1
  3. data/examples/roundtrip.rb +7 -4
  4. data/examples/sign.rb +5 -3
  5. data/examples/verify.rb +4 -2
  6. data/ext/gpgme/extconf.rb +58 -0
  7. data/ext/gpgme/gpgme-1.3.1.tar.bz2 +0 -0
  8. data/{gpgme_n.c → ext/gpgme/gpgme_n.c} +8 -8
  9. data/ext/gpgme/libassuan-2.0.2.tar.bz2 +0 -0
  10. data/ext/gpgme/libgpg-error-1.10.tar.bz2 +0 -0
  11. data/lib/gpgme.rb +88 -1541
  12. data/lib/gpgme/compat.rb +2 -0
  13. data/lib/gpgme/constants.rb +23 -0
  14. data/lib/gpgme/crypto.rb +357 -0
  15. data/lib/gpgme/ctx.rb +462 -0
  16. data/lib/gpgme/data.rb +177 -0
  17. data/lib/gpgme/engine.rb +76 -0
  18. data/lib/gpgme/error.rb +66 -0
  19. data/lib/gpgme/io_callbacks.rb +21 -0
  20. data/lib/gpgme/key.rb +242 -0
  21. data/lib/gpgme/key_common.rb +43 -0
  22. data/lib/gpgme/key_sig.rb +35 -0
  23. data/lib/gpgme/misc.rb +66 -0
  24. data/lib/gpgme/signature.rb +85 -0
  25. data/lib/gpgme/sub_key.rb +58 -0
  26. data/lib/gpgme/user_id.rb +20 -0
  27. data/lib/gpgme/version.rb +3 -0
  28. data/test/crypto_test.rb +242 -0
  29. data/test/ctx_test.rb +426 -0
  30. data/test/data_test.rb +116 -0
  31. data/test/files/testkey_pub.gpg +52 -0
  32. data/test/files/testkey_sec.gpg +54 -0
  33. data/test/gpgme_test.rb +12 -0
  34. data/test/key_test.rb +201 -0
  35. data/test/signature_test.rb +48 -0
  36. data/test/sub_key_test.rb +45 -0
  37. data/test/support/resources.rb +516 -0
  38. data/test/test_helper.rb +83 -0
  39. metadata +144 -65
  40. data.tar.gz.sig +0 -3
  41. data/COPYING +0 -340
  42. data/COPYING.LESSER +0 -510
  43. data/Makefile +0 -172
  44. data/Manifest.txt +0 -18
  45. data/README +0 -86
  46. data/Rakefile +0 -17
  47. data/THANKS +0 -15
  48. data/extconf.rb +0 -26
  49. metadata.gz.sig +0 -0
@@ -1,5 +1,7 @@
1
1
  require 'gpgme'
2
2
 
3
+ # TODO: Find why is this needed. I guess the name compat means it's just
4
+ # backwards compatibility. Consider removing?
3
5
  module GPGME
4
6
  GpgmeError = Error
5
7
  GpgmeData = Data
@@ -1,4 +1,5 @@
1
1
  module GPGME
2
+
2
3
  ATTR_ALGO = GPGME_ATTR_ALGO
3
4
  ATTR_CAN_CERTIFY = GPGME_ATTR_CAN_CERTIFY
4
5
  ATTR_CAN_ENCRYPT = GPGME_ATTR_CAN_ENCRYPT
@@ -161,4 +162,26 @@ module GPGME
161
162
  VALIDITY_ULTIMATE = GPGME_VALIDITY_ULTIMATE
162
163
  VALIDITY_UNDEFINED = GPGME_VALIDITY_UNDEFINED
163
164
  VALIDITY_UNKNOWN = GPGME_VALIDITY_UNKNOWN
165
+
166
+ PROTOCOL_NAMES = {
167
+ PROTOCOL_OpenPGP => :OpenPGP,
168
+ PROTOCOL_CMS => :CMS
169
+ }
170
+
171
+ KEYLIST_MODE_NAMES = {
172
+ KEYLIST_MODE_LOCAL => :local,
173
+ KEYLIST_MODE_EXTERN => :extern,
174
+ KEYLIST_MODE_SIGS => :sigs,
175
+ KEYLIST_MODE_VALIDATE => :validate
176
+ }
177
+
178
+ VALIDITY_NAMES = {
179
+ VALIDITY_UNKNOWN => :unknown,
180
+ VALIDITY_UNDEFINED => :undefined,
181
+ VALIDITY_NEVER => :never,
182
+ VALIDITY_MARGINAL => :marginal,
183
+ VALIDITY_FULL => :full,
184
+ VALIDITY_ULTIMATE => :ultimate
185
+ }
186
+
164
187
  end
@@ -0,0 +1,357 @@
1
+ module GPGME
2
+
3
+ ##
4
+ # Different, independent methods providing the simplest possible API to
5
+ # execute crypto operations via GPG. All methods accept as options the same
6
+ # common options as {GPGME::Ctx.new}. Read the documentation for that class to
7
+ # know how to customize things further (like output stuff in ASCII armored
8
+ # format, for example).
9
+ #
10
+ # @example
11
+ # crypto = GPGME::Crypto.new :armor => true
12
+ # encrypted = crypto.encrypt 'Plain text'
13
+ #
14
+ class Crypto
15
+
16
+ attr_reader :default_options
17
+
18
+ def initialize(options = {})
19
+ @default_options = options
20
+ end
21
+
22
+ ##
23
+ # Encrypts an element
24
+ #
25
+ # crypto.encrypt something, options
26
+ #
27
+ # Will return a {GPGME::Data} element which can then be read.
28
+ #
29
+ # Must have some key imported, look for {GPGME::Key.import} to know how
30
+ # to import one, or the gpg documentation to know how to create one
31
+ #
32
+ # @param plain
33
+ # Must be something that can be converted into a {GPGME::Data} object, or
34
+ # a {GPGME::Data} object itself.
35
+ #
36
+ # @param [Hash] options
37
+ # The optional parameters are as follows:
38
+ # * +:recipients+ for which recipient do you want to encrypt this file. It
39
+ # will pick the first one available if none specified. Can be an array of
40
+ # identifiers or just one (a string).
41
+ # * +:symmetric+ if set to true, will ignore +:recipients+, and will perform
42
+ # a symmetric encryption. Must provide a password via the +:password+
43
+ # option.
44
+ # * +:always_trust+ if set to true specifies all the recipients to be
45
+ # trusted, thus not requiring confirmation.
46
+ # * +:sign+ if set to true, performs a combined sign and encrypt operation.
47
+ # * +:signers+ if +:sign+ specified to true, a list of additional possible
48
+ # signers. Must be an array of sign identifiers.
49
+ # * +:output+ if specified, it will write the output into it. It will be
50
+ # converted to a {GPGME::Data} object, so it could be a file for example.
51
+ # * Any other option accepted by {GPGME::Ctx.new}
52
+ #
53
+ # @return [GPGME::Data] a {GPGME::Data} object that can be read.
54
+ #
55
+ # @example returns a {GPGME::Data} that can be later encrypted
56
+ # encrypted = crypto.encrypt "Hello world!"
57
+ # encrypted.read # => Encrypted stuff
58
+ #
59
+ # @example to be decrypted by someone@example.com.
60
+ # crypto.encrypt "Hello", :recipients => "someone@example.com"
61
+ #
62
+ # @example If I didn't trust any of my keys by default
63
+ # crypto.encrypt "Hello" # => GPGME::Error::General
64
+ # crypto.encrypt "Hello", :always_trust => true # => Will work fine
65
+ #
66
+ # @example encrypted string that can be decrypted and/or *verified*
67
+ # crypto.encrypt "Hello", :sign => true
68
+ #
69
+ # @example multiple signers
70
+ # crypto.encrypt "Hello", :sign => true, :signers => "extra@example.com"
71
+ #
72
+ # @example writing to a file instead
73
+ # file = File.open("signed.sec","w+")
74
+ # crypto.encrypt "Hello", :output => file # output written to signed.sec
75
+ #
76
+ # @raise [GPGME::Error::General] when trying to encrypt with a key that is
77
+ # not trusted, and +:always_trust+ wasn't specified
78
+ #
79
+ def encrypt(plain, options = {})
80
+ options = @default_options.merge options
81
+
82
+ plain_data = Data.new(plain)
83
+ cipher_data = Data.new(options[:output])
84
+ keys = Key.find(:public, options[:recipients])
85
+ keys = nil if options[:symmetric]
86
+
87
+ flags = 0
88
+ flags |= GPGME::ENCRYPT_ALWAYS_TRUST if options[:always_trust]
89
+
90
+ GPGME::Ctx.new(options) do |ctx|
91
+ begin
92
+ if options[:sign]
93
+ if options[:signers]
94
+ signers = Key.find(:public, options[:signers], :sign)
95
+ ctx.add_signer(*signers)
96
+ end
97
+ ctx.encrypt_sign(keys, plain_data, cipher_data, flags)
98
+ else
99
+ ctx.encrypt(keys, plain_data, cipher_data, flags)
100
+ end
101
+ rescue GPGME::Error::UnusablePublicKey => exc
102
+ exc.keys = ctx.encrypt_result.invalid_recipients
103
+ raise exc
104
+ rescue GPGME::Error::UnusableSecretKey => exc
105
+ exc.keys = ctx.sign_result.invalid_signers
106
+ raise exc
107
+ end
108
+ end
109
+
110
+ cipher_data.seek(0)
111
+ cipher_data
112
+ end
113
+
114
+ ##
115
+ # Decrypts a previously encrypted element
116
+ #
117
+ # crypto.decrypt cipher, options, &block
118
+ #
119
+ # Must have the appropiate key to be able to decrypt, of course. Returns
120
+ # a {GPGME::Data} object which can then be read.
121
+ #
122
+ # @param cipher
123
+ # Must be something that can be converted into a {GPGME::Data} object,
124
+ # or a {GPGME::Data} object itself. It is the element that will be
125
+ # decrypted.
126
+ #
127
+ # @param [Hash] options
128
+ # The optional parameters:
129
+ # * +:output+ if specified, it will write the output into it. It will
130
+ # me converted to a {GPGME::Data} object, so it can also be a file,
131
+ # for example.
132
+ # * If the file was encrypted with symmentric encryption, must provide
133
+ # a :password option.
134
+ # * Any other option accepted by {GPGME::Ctx.new}
135
+ #
136
+ # @param &block
137
+ # In the block all the signatures are yielded, so one could verify them.
138
+ # See examples.
139
+ #
140
+ # @return [GPGME::Data] a {GPGME::Data} that can be read.
141
+ #
142
+ # @example Simple decrypt
143
+ # crypto.decrypt encrypted_data
144
+ #
145
+ # @example symmetric encryption, or passwored key
146
+ # crypto.decrypt encrypted_data, :password => "gpgme"
147
+ #
148
+ # @example Output to file
149
+ # file = File.open("decrypted.txt", "w+")
150
+ # crypto.decrypt encrypted_data, :output => file
151
+ #
152
+ # @example Verifying signatures
153
+ # crypto.decrypt encrypted_data do |signature|
154
+ # raise "Signature could not be verified" unless signature.valid?
155
+ # end
156
+ #
157
+ # @raise [GPGME::Error::UnsupportedAlgorithm] when the cipher was encrypted
158
+ # using an algorithm that's not supported currently.
159
+ #
160
+ # @raise [GPGME::Error::WrongKeyUsage] TODO Don't know when
161
+ #
162
+ # @raise [GPGME::Error::DecryptFailed] when the cipher was encrypted
163
+ # for a key that's not available currently.
164
+ def decrypt(cipher, options = {})
165
+ options = @default_options.merge options
166
+
167
+ plain_data = Data.new(options[:output])
168
+ cipher_data = Data.new(cipher)
169
+
170
+ GPGME::Ctx.new(options) do |ctx|
171
+ begin
172
+ ctx.decrypt_verify(cipher_data, plain_data)
173
+ rescue GPGME::Error::UnsupportedAlgorithm => exc
174
+ exc.algorithm = ctx.decrypt_result.unsupported_algorithm
175
+ raise exc
176
+ rescue GPGME::Error::WrongKeyUsage => exc
177
+ exc.key_usage = ctx.decrypt_result.wrong_key_usage
178
+ raise exc
179
+ end
180
+
181
+ verify_result = ctx.verify_result
182
+ if verify_result && block_given?
183
+ verify_result.signatures.each do |signature|
184
+ yield signature
185
+ end
186
+ end
187
+
188
+ end
189
+
190
+ plain_data.seek(0)
191
+ plain_data
192
+ end
193
+
194
+ ##
195
+ # Creates a signature of a text
196
+ #
197
+ # crypto.sign text, options
198
+ #
199
+ # Must have the appropiate key to be able to decrypt, of course. Returns
200
+ # a {GPGME::Data} object which can then be read.
201
+ #
202
+ # @param text
203
+ # The object that will be signed. Must be something that can be converted
204
+ # to {GPGME::Data}.
205
+ #
206
+ # @param [Hash] options
207
+ # Optional parameters.
208
+ # * +:signer+ sign identifier to sign the text with. Will use the first
209
+ # key it finds if none specified.
210
+ # * +:output+ if specified, it will write the output into it. It will be
211
+ # converted to a {GPGME::Data} object, so it could be a file for example.
212
+ # * +:mode+ Desired type of signature. Options are:
213
+ # - +GPGME::SIG_MODE_NORMAL+ for a normal signature. The default one if
214
+ # not specified.
215
+ # - +GPGME::SIG_MODE_DETACH+ for a detached signature
216
+ # - +GPGME::SIG_MODE_CLEAR+ for a cleartext signature
217
+ # * Any other option accepted by {GPGME::Ctx.new}
218
+ #
219
+ # @return [GPGME::Data] a {GPGME::Data} that can be read.
220
+ #
221
+ # @example normal sign
222
+ # crypto.sign "Hi there"
223
+ #
224
+ # @example outputing to a file
225
+ # file = File.open("text.sign", "w+")
226
+ # crypto.sign "Hi there", :options => file
227
+ #
228
+ # @example doing a detached signature
229
+ # crypto.sign "Hi there", :mode => GPGME::SIG_MODE_DETACH
230
+ #
231
+ # @example specifying the signer
232
+ # crypto.sign "Hi there", :signer => "mrsimo@example.com"
233
+ #
234
+ # @raise [GPGME::Error::UnusableSecretKey] TODO don't know when
235
+ def sign(text, options = {})
236
+ options = @default_options.merge options
237
+
238
+ plain = Data.new(text)
239
+ output = Data.new(options[:output])
240
+ mode = options[:mode] || GPGME::SIG_MODE_NORMAL
241
+
242
+ GPGME::Ctx.new(options) do |ctx|
243
+ if options[:signer]
244
+ signers = Key.find(:secret, options[:signer], :sign)
245
+ ctx.add_signer(*signers)
246
+ end
247
+
248
+ begin
249
+ ctx.sign(plain, output, mode)
250
+ rescue GPGME::Error::UnusableSecretKey => exc
251
+ exc.keys = ctx.sign_result.invalid_signers
252
+ raise exc
253
+ end
254
+ end
255
+
256
+ output.seek(0)
257
+ output
258
+ end
259
+
260
+ # Verifies a previously signed element
261
+ #
262
+ # crypto.verify sig, options, &block
263
+ #
264
+ # Must have the proper keys available.
265
+ #
266
+ # @param sig
267
+ # The signature itself. Must be possible to convert into a {GPGME::Data}
268
+ # object, so can be a file.
269
+ #
270
+ # @param [Hash] options
271
+ # * +:signed_text+ if the sign is detached, then must be the plain text
272
+ # for which the signature was created.
273
+ # * +:output+ where to store the result of the signature. Will be
274
+ # converted to a {GPGME::Data} object.
275
+ # * Any other option accepted by {GPGME::Ctx.new}
276
+ #
277
+ # @param &block
278
+ # In the block all the signatures are yielded, so one could verify them.
279
+ # See examples.
280
+ #
281
+ # @return [GPGME::Data] unless the sign is detached, the {GPGME::Data}
282
+ # object with the plain text. If the sign is detached, will return nil.
283
+ #
284
+ # @example simple verification
285
+ # sign = crypto.sign("Hi there")
286
+ # data = crypto.verify(sign) { |signature| signature.valid? }
287
+ # data.read # => "Hi there"
288
+ #
289
+ # @example saving output to file
290
+ # sign = crypto.sign("Hi there")
291
+ # out = File.open("test.asc", "w+")
292
+ # crypto.verify(sign, :output => out) {|signature| signature.valid?}
293
+ # out.read # => "Hi there"
294
+ #
295
+ # @example verifying a detached signature
296
+ # sign = crypto.detach_sign("Hi there")
297
+ # # Will fail
298
+ # crypto.verify(sign) { |signature| signature.valid? }
299
+ # # Will succeed
300
+ # crypto.verify(sign, :signed_text => "hi there") do |signature|
301
+ # signature.valid?
302
+ # end
303
+ #
304
+ def verify(sig, options = {})
305
+ options = @default_options.merge options
306
+
307
+ sig = Data.new(sig)
308
+ signed_text = Data.new(options[:signed_text])
309
+ output = Data.new(options[:output]) unless options[:signed_text]
310
+
311
+ GPGME::Ctx.new(options) do |ctx|
312
+ ctx.verify(sig, signed_text, output)
313
+ ctx.verify_result.signatures.each do |signature|
314
+ yield signature
315
+ end
316
+ end
317
+
318
+ if output
319
+ output.seek(0)
320
+ output
321
+ end
322
+ end
323
+
324
+ # Clearsigns an element
325
+ #
326
+ # crypto.clearsign text, options
327
+ #
328
+ # Same functionality of {.sign} only doing clearsigns by default.
329
+ #
330
+ def clearsign(text, options = {})
331
+ sign text, options.merge(:mode => GPGME::SIG_MODE_CLEAR)
332
+ end
333
+
334
+ # Creates a detached signature of an element
335
+ #
336
+ # crypto.detach_sign text, options
337
+ #
338
+ # Same functionality of {.sign} only doing detached signs by default.
339
+ #
340
+ def detach_sign(text, options = {})
341
+ sign text, options.merge(:mode => GPGME::SIG_MODE_DETACH)
342
+ end
343
+
344
+ ##
345
+ # Allows calling of methods directly in the module without the need to
346
+ # create a new instance.
347
+ def self.method_missing(method, *args, &block)
348
+ if GPGME::Crypto.instance_methods(false).include?(method)
349
+ crypto = GPGME::Crypto.new
350
+ crypto.send method, *args, &block
351
+ else
352
+ super
353
+ end
354
+ end
355
+
356
+ end # module Crypto
357
+ end # module GPGME
@@ -0,0 +1,462 @@
1
+ module GPGME
2
+
3
+ ##
4
+ # A context within which all cryptographic operations are performed.
5
+ #
6
+ # More operations can be done which are not available in the higher level
7
+ # API. Note how to create a new instance of this class in {GPGME::Ctx.new}.
8
+ #
9
+ class Ctx
10
+
11
+ ##
12
+ # Create a new instance from the given +options+. Must be released either
13
+ # executing the operations inside a block, or executing {GPGME::Ctx#release}
14
+ # afterwards.
15
+ #
16
+ # @param [Hash] options
17
+ # The optional parameters are as follows:
18
+ # * +:protocol+ Either +PROTOCOL_OpenPGP+ or +PROTOCOL_CMS+.
19
+ # * +:armor+ will return ASCII armored outputs if specified true.
20
+ # * +:textmode+ if +true+, inform the recipient that the input is text.
21
+ # * +:keylist_mode+ One of: +KEYLIST_MODE_LOCAL+, +KEYLIST_MODE_EXTERN+,
22
+ # +KEYLIST_MODE_SIGS+ or +KEYLIST_MODE_VALIDATE+.
23
+ # * +:password+ password of the passphrased password being used.
24
+ # * +:passphrase_callback+ A callback function. See {#set_passphrase_callback}.
25
+ # * +:passphrase_callback_value+ An object passed to passphrase_callback.
26
+ # * +:progress_callback+ A callback function. See {#set_progress_callback}.
27
+ # * +:progress_callback_value+ An object passed to progress_callback.
28
+ #
29
+ # @example
30
+ # ctx = GPGME::Ctx.new
31
+ # # operate on ctx
32
+ # ctx.release
33
+ #
34
+ # @example
35
+ # GPGME::Ctx.new do |ctx|
36
+ # # operate on ctx
37
+ # end
38
+ #
39
+ def self.new(options = {})
40
+ rctx = []
41
+ err = GPGME::gpgme_new(rctx)
42
+ exc = GPGME::error_to_exception(err)
43
+ raise exc if exc
44
+ ctx = rctx[0]
45
+
46
+ ctx.protocol = options[:protocol] if options[:protocol]
47
+ ctx.armor = options[:armor] if options[:armor]
48
+ ctx.textmode = options[:textmode] if options[:textmode]
49
+ ctx.keylist_mode = options[:keylist_mode] if options[:keylist_mode]
50
+
51
+ if options[:password]
52
+ ctx.set_passphrase_callback GPGME::Ctx.method(:pass_function),
53
+ options[:password]
54
+ else
55
+ if options[:passphrase_callback]
56
+ ctx.set_passphrase_callback options[:passphrase_callback],
57
+ options[:passphrase_callback_value]
58
+ end
59
+ end
60
+ if options[:progress_callback]
61
+ ctx.set_progress_callback options[:progress_callback],
62
+ options[:progress_callback_value]
63
+ end
64
+
65
+ if block_given?
66
+ begin
67
+ yield ctx
68
+ ensure
69
+ GPGME::gpgme_release(ctx)
70
+ end
71
+ else
72
+ ctx
73
+ end
74
+ end
75
+
76
+
77
+ ##
78
+ # Releases the Ctx instance. Must be called if it was initialized without
79
+ # a block.
80
+ #
81
+ # @example
82
+ # ctx = GPGME::Ctx.new
83
+ # # operate on ctx
84
+ # ctx.release
85
+ #
86
+ def release
87
+ GPGME::gpgme_release(self)
88
+ end
89
+
90
+ ##
91
+ # Getters and setters
92
+ ##
93
+
94
+ # Set the +protocol+ used within this context. See {GPGME::Ctx.new} for
95
+ # possible values.
96
+ def protocol=(proto)
97
+ err = GPGME::gpgme_set_protocol(self, proto)
98
+ exc = GPGME::error_to_exception(err)
99
+ raise exc if exc
100
+ proto
101
+ end
102
+
103
+ # Return the +protocol+ used within this context.
104
+ def protocol
105
+ GPGME::gpgme_get_protocol(self)
106
+ end
107
+
108
+ # Tell whether the output should be ASCII armored.
109
+ def armor=(yes)
110
+ GPGME::gpgme_set_armor(self, yes ? 1 : 0)
111
+ yes
112
+ end
113
+
114
+ # Return true if the output is ASCII armored.
115
+ def armor
116
+ GPGME::gpgme_get_armor(self) == 1 ? true : false
117
+ end
118
+
119
+ # Tell whether canonical text mode should be used.
120
+ def textmode=(yes)
121
+ GPGME::gpgme_set_textmode(self, yes ? 1 : 0)
122
+ yes
123
+ end
124
+
125
+ # Return true if canonical text mode is enabled.
126
+ def textmode
127
+ GPGME::gpgme_get_textmode(self) == 1 ? true : false
128
+ end
129
+
130
+ # Change the default behaviour of the key listing functions.
131
+ def keylist_mode=(mode)
132
+ GPGME::gpgme_set_keylist_mode(self, mode)
133
+ mode
134
+ end
135
+
136
+ # Return the current key listing mode.
137
+ def keylist_mode
138
+ GPGME::gpgme_get_keylist_mode(self)
139
+ end
140
+
141
+ ##
142
+ # Passphrase and progress callbacks
143
+ ##
144
+
145
+ # Set the passphrase callback with given hook value.
146
+ # +passfunc+ should respond to +call+ with 5 arguments.
147
+ #
148
+ # * +obj+ the parameter +:passphrase_callback_value+ passed when creating
149
+ # the {GPGME::Ctx} object.
150
+ # * +uid_hint+ hint as to what key are we asking the password for. Ex:
151
+ #
152
+ # +CFB3294A50C2CFD7 Albert Llop <mrsimo@example.com>+
153
+ #
154
+ # * +passphrase_info+
155
+ # * +prev_was_bad+ 0 if it's the first time the password is being asked,
156
+ # 1 otherwise.
157
+ # * +fd+ file descriptor where the password must be written too.
158
+ #
159
+ # Expects a Method object which can be obtained by the +method+ method
160
+ # (really..).
161
+ #
162
+ # ctx.set_passphrase_callback(MyModule.method(:passfunc))
163
+ #
164
+ # @example this method will simply return +maria+ as password.
165
+ # def pass_function(obj, uid_hint, passphrase_info, prev_was_bad, fd)
166
+ # io = IO.for_fd(fd, 'w')
167
+ # io.puts "maria"
168
+ # io.flush
169
+ # end
170
+ #
171
+ # @example this will interactively ask for the password
172
+ # def passfunc(obj, uid_hint, passphrase_info, prev_was_bad, fd)
173
+ # $stderr.write("Passphrase for #{uid_hint}: ")
174
+ # $stderr.flush
175
+ # begin
176
+ # system('stty -echo')
177
+ # io = IO.for_fd(fd, 'w')
178
+ # io.puts(gets)
179
+ # io.flush
180
+ # ensure
181
+ # (0 ... $_.length).each do |i| $_[i] = ?0 end if $_
182
+ # system('stty echo')
183
+ # end
184
+ # $stderr.puts
185
+ # end
186
+ #
187
+ def set_passphrase_callback(passfunc, hook_value = nil)
188
+ GPGME::gpgme_set_passphrase_cb(self, passfunc, hook_value)
189
+ end
190
+ alias set_passphrase_cb set_passphrase_callback
191
+
192
+ # Set the progress callback with given hook value.
193
+ # <i>progfunc</i> should respond to <code>call</code> with 5 arguments.
194
+ #
195
+ # def progfunc(hook, what, type, current, total)
196
+ # $stderr.write("#{what}: #{current}/#{total}\r")
197
+ # $stderr.flush
198
+ # end
199
+ #
200
+ # ctx.set_progress_callback(method(:progfunc))
201
+ #
202
+ def set_progress_callback(progfunc, hook_value = nil)
203
+ GPGME::gpgme_set_progress_cb(self, progfunc, hook_value)
204
+ end
205
+ alias set_progress_cb set_progress_callback
206
+
207
+ ##
208
+ # Searching and iterating through keys. Used by {GPGME::Key.find}
209
+ ##
210
+
211
+ # Initiate a key listing operation for given pattern. If +pattern+ is
212
+ # +nil+, all available keys are returned. If +secret_only<+ is +true+,
213
+ # only secret keys are returned.
214
+ #
215
+ # Used by {GPGME::Ctx#each_key}
216
+ def keylist_start(pattern = nil, secret_only = false)
217
+ err = GPGME::gpgme_op_keylist_start(self, pattern, secret_only ? 1 : 0)
218
+ exc = GPGME::error_to_exception(err)
219
+ raise exc if exc
220
+ end
221
+
222
+ # Advance to the next key in the key listing operation.
223
+ #
224
+ # Used by {GPGME::Ctx#each_key}
225
+ def keylist_next
226
+ rkey = []
227
+ err = GPGME::gpgme_op_keylist_next(self, rkey)
228
+ exc = GPGME::error_to_exception(err)
229
+ raise exc if exc
230
+ rkey[0]
231
+ end
232
+
233
+ # End a pending key list operation.
234
+ #
235
+ # Used by {GPGME::Ctx#each_key}
236
+ def keylist_end
237
+ err = GPGME::gpgme_op_keylist_end(self)
238
+ exc = GPGME::error_to_exception(err)
239
+ raise exc if exc
240
+ end
241
+
242
+ # Convenient method to iterate over keys.
243
+ #
244
+ # If +pattern+ is +nil+, all available keys are returned. If +secret_only+
245
+ # is +true+, only secret keys are returned.
246
+ #
247
+ # See {GPGME::Key.find} for an example of how to use, or for an easier way
248
+ # to use.
249
+ def each_key(pattern = nil, secret_only = false, &block)
250
+ keylist_start(pattern, secret_only)
251
+ begin
252
+ loop { yield keylist_next }
253
+ rescue EOFError
254
+ # The last key in the list has already been returned.
255
+ ensure
256
+ keylist_end
257
+ end
258
+ end
259
+ alias each_keys each_key
260
+
261
+ # Returns the keys that match the +pattern+, or all if +pattern+ is nil.
262
+ # Returns only secret keys if +secret_only+ is true.
263
+ def keys(pattern = nil, secret_only = nil)
264
+ keys = []
265
+ each_key(pattern, secret_only) do |key|
266
+ keys << key
267
+ end
268
+ keys
269
+ end
270
+
271
+ # Get the key with the +fingerprint+.
272
+ # If +secret+ is +true+, secret key is returned.
273
+ def get_key(fingerprint, secret = false)
274
+ rkey = []
275
+ err = GPGME::gpgme_get_key(self, fingerprint, rkey, secret ? 1 : 0)
276
+ exc = GPGME::error_to_exception(err)
277
+ raise exc if exc
278
+ rkey[0]
279
+ end
280
+
281
+ ##
282
+ # Import/export and generation/deletion of keys
283
+ ##
284
+
285
+ # Generate a new key pair.
286
+ # +parms+ is a string which looks like
287
+ #
288
+ # <GnupgKeyParms format="internal">
289
+ # Key-Type: DSA
290
+ # Key-Length: 1024
291
+ # Subkey-Type: ELG-E
292
+ # Subkey-Length: 1024
293
+ # Name-Real: Joe Tester
294
+ # Name-Comment: with stupid passphrase
295
+ # Name-Email: joe@foo.bar
296
+ # Expire-Date: 0
297
+ # Passphrase: abc
298
+ # </GnupgKeyParms>
299
+ #
300
+ # If +pubkey+ and +seckey+ are both set to +nil+, it stores the generated
301
+ # key pair into your key ring.
302
+ def generate_key(parms, pubkey = nil, seckey = nil)
303
+ err = GPGME::gpgme_op_genkey(self, parms, pubkey, seckey)
304
+ exc = GPGME::error_to_exception(err)
305
+ raise exc if exc
306
+ end
307
+ alias genkey generate_key
308
+
309
+ # Extract the public keys that match the +recipients+. Returns a
310
+ # {GPGME::Data} object which is not rewinded (should do +seek(0)+
311
+ # before reading).
312
+ #
313
+ # Private keys cannot be exported due to GPGME restrictions.
314
+ #
315
+ # If passed, the key will be exported to +keydata+, which must be
316
+ # a {GPGME::Data} object.
317
+ def export_keys(recipients, keydata = Data.new)
318
+ err = GPGME::gpgme_op_export(self, recipients, 0, keydata)
319
+ exc = GPGME::error_to_exception(err)
320
+ raise exc if exc
321
+ keydata
322
+ end
323
+ alias export export_keys
324
+
325
+ # Add the keys in the data buffer to the key ring.
326
+ def import_keys(keydata)
327
+ err = GPGME::gpgme_op_import(self, keydata)
328
+ exc = GPGME::error_to_exception(err)
329
+ raise exc if exc
330
+ end
331
+ alias import import_keys
332
+
333
+ def import_result
334
+ GPGME::gpgme_op_import_result(self)
335
+ end
336
+
337
+ # Delete the key from the key ring.
338
+ # If allow_secret is false, only public keys are deleted,
339
+ # otherwise secret keys are deleted as well.
340
+ def delete_key(key, allow_secret = false)
341
+ err = GPGME::gpgme_op_delete(self, key, allow_secret ? 1 : 0)
342
+ exc = GPGME::error_to_exception(err)
343
+ raise exc if exc
344
+ end
345
+ alias delete delete_key
346
+
347
+ # Edit attributes of the key in the local key ring.
348
+ def edit_key(key, editfunc, hook_value = nil, out = Data.new)
349
+ err = GPGME::gpgme_op_edit(self, key, editfunc, hook_value, out)
350
+ exc = GPGME::error_to_exception(err)
351
+ raise exc if exc
352
+ end
353
+ alias edit edit_key
354
+
355
+ # Edit attributes of the key on the card.
356
+ def edit_card_key(key, editfunc, hook_value = nil, out = Data.new)
357
+ err = GPGME::gpgme_op_card_edit(self, key, editfunc, hook_value, out)
358
+ exc = GPGME::error_to_exception(err)
359
+ raise exc if exc
360
+ end
361
+ alias edit_card edit_card_key
362
+ alias card_edit edit_card_key
363
+
364
+ ##
365
+ # Crypto operations
366
+ ##
367
+
368
+ # Decrypt the ciphertext and return the plaintext.
369
+ def decrypt(cipher, plain = Data.new)
370
+ err = GPGME::gpgme_op_decrypt(self, cipher, plain)
371
+ exc = GPGME::error_to_exception(err)
372
+ raise exc if exc
373
+ plain
374
+ end
375
+
376
+ def decrypt_verify(cipher, plain = Data.new)
377
+ err = GPGME::gpgme_op_decrypt_verify(self, cipher, plain)
378
+ exc = GPGME::error_to_exception(err)
379
+ raise exc if exc
380
+ plain
381
+ end
382
+
383
+ def decrypt_result
384
+ GPGME::gpgme_op_decrypt_result(self)
385
+ end
386
+
387
+ # Verify that the signature in the data object is a valid signature.
388
+ def verify(sig, signed_text = nil, plain = Data.new)
389
+ err = GPGME::gpgme_op_verify(self, sig, signed_text, plain)
390
+ exc = GPGME::error_to_exception(err)
391
+ raise exc if exc
392
+ plain
393
+ end
394
+
395
+ def verify_result
396
+ GPGME::gpgme_op_verify_result(self)
397
+ end
398
+
399
+ # Remove the list of signers from this object.
400
+ def clear_signers
401
+ GPGME::gpgme_signers_clear(self)
402
+ end
403
+
404
+ # Add _keys_ to the list of signers.
405
+ def add_signer(*keys)
406
+ keys.each do |key|
407
+ err = GPGME::gpgme_signers_add(self, key)
408
+ exc = GPGME::error_to_exception(err)
409
+ raise exc if exc
410
+ end
411
+ end
412
+
413
+ # Create a signature for the text.
414
+ # +plain+ is a data object which contains the text.
415
+ # +sig+ is a data object where the generated signature is stored.
416
+ def sign(plain, sig = Data.new, mode = GPGME::SIG_MODE_NORMAL)
417
+ err = GPGME::gpgme_op_sign(self, plain, sig, mode)
418
+ exc = GPGME::error_to_exception(err)
419
+ raise exc if exc
420
+ sig
421
+ end
422
+
423
+ def sign_result
424
+ GPGME::gpgme_op_sign_result(self)
425
+ end
426
+
427
+ # Encrypt the plaintext in the data object for the recipients and
428
+ # return the ciphertext.
429
+ def encrypt(recp, plain, cipher = Data.new, flags = 0)
430
+ err = GPGME::gpgme_op_encrypt(self, recp, flags, plain, cipher)
431
+ exc = GPGME::error_to_exception(err)
432
+ raise exc if exc
433
+ cipher
434
+ end
435
+
436
+ def encrypt_result
437
+ GPGME::gpgme_op_encrypt_result(self)
438
+ end
439
+
440
+ def encrypt_sign(recp, plain, cipher = Data.new, flags = 0)
441
+ err = GPGME::gpgme_op_encrypt_sign(self, recp, flags, plain, cipher)
442
+ exc = GPGME::error_to_exception(err)
443
+ raise exc if exc
444
+ cipher
445
+ end
446
+
447
+ def inspect
448
+ "#<#{self.class} protocol=#{PROTOCOL_NAMES[protocol] || protocol}, \
449
+ armor=#{armor}, textmode=#{textmode}, \
450
+ keylist_mode=#{KEYLIST_MODE_NAMES[keylist_mode]}>"
451
+ end
452
+
453
+ private
454
+
455
+ def self.pass_function(pass, uid_hint, passphrase_info, prev_was_bad, fd)
456
+ io = IO.for_fd(fd, 'w')
457
+ io.puts pass
458
+ io.flush
459
+ end
460
+
461
+ end
462
+ end