gpgme-ffi 3.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.
- data/examples/edit.rb +77 -0
- data/examples/genkey.rb +55 -0
- data/examples/keylist.rb +7 -0
- data/examples/roundtrip.rb +42 -0
- data/examples/sign.rb +31 -0
- data/examples/verify.rb +8 -0
- data/ext/gpgme/Makefile.in +55 -0
- data/ext/gpgme/extconf.rb +8 -0
- data/ext/gpgme/extract_enums.rb +88 -0
- data/ext/gpgme/gpgme-1.3.1.tar.bz2 +0 -0
- data/ext/gpgme/libassuan-2.0.2.tar.bz2 +0 -0
- data/ext/gpgme/libgpg-error-1.10.tar.bz2 +0 -0
- data/ext/gpgme/libgpgme_gem.so +0 -0
- data/lib/gpgme/compat.rb +48 -0
- data/lib/gpgme/constants.rb +187 -0
- data/lib/gpgme/crypto.rb +357 -0
- data/lib/gpgme/ctx.rb +462 -0
- data/lib/gpgme/data.rb +189 -0
- data/lib/gpgme/engine.rb +76 -0
- data/lib/gpgme/error.rb +66 -0
- data/lib/gpgme/ffi/ctx.rb +36 -0
- data/lib/gpgme/ffi/data.rb +24 -0
- data/lib/gpgme/ffi/decrypt_result.rb +14 -0
- data/lib/gpgme/ffi/encrypt_result.rb +22 -0
- data/lib/gpgme/ffi/engine_info.rb +17 -0
- data/lib/gpgme/ffi/enums.rb +687 -0
- data/lib/gpgme/ffi/functions.rb +364 -0
- data/lib/gpgme/ffi/import_result.rb +35 -0
- data/lib/gpgme/ffi/import_status.rb +15 -0
- data/lib/gpgme/ffi/invalid_key.rb +14 -0
- data/lib/gpgme/ffi/key.rb +60 -0
- data/lib/gpgme/ffi/key_sig.rb +20 -0
- data/lib/gpgme/ffi/library.rb +279 -0
- data/lib/gpgme/ffi/meta.rb +57 -0
- data/lib/gpgme/ffi/new_signature.rb +18 -0
- data/lib/gpgme/ffi/sig_notation.rb +12 -0
- data/lib/gpgme/ffi/sign_result.rb +33 -0
- data/lib/gpgme/ffi/signature.rb +35 -0
- data/lib/gpgme/ffi/sub_key.rb +27 -0
- data/lib/gpgme/ffi/trust_item.rb +31 -0
- data/lib/gpgme/ffi/user_id.rb +30 -0
- data/lib/gpgme/ffi/verify_result.rb +22 -0
- data/lib/gpgme/ffi.rb +22 -0
- data/lib/gpgme/io_callbacks.rb +21 -0
- data/lib/gpgme/key.rb +242 -0
- data/lib/gpgme/key_common.rb +43 -0
- data/lib/gpgme/key_sig.rb +35 -0
- data/lib/gpgme/misc.rb +66 -0
- data/lib/gpgme/signature.rb +85 -0
- data/lib/gpgme/sub_key.rb +58 -0
- data/lib/gpgme/user_id.rb +20 -0
- data/lib/gpgme/version.rb +3 -0
- data/lib/gpgme.rb +106 -0
- data/test/crypto_test.rb +246 -0
- data/test/ctx_test.rb +432 -0
- data/test/data_test.rb +129 -0
- data/test/files/testkey_pub.gpg +52 -0
- data/test/files/testkey_sec.gpg +54 -0
- data/test/gpgme_test.rb +12 -0
- data/test/key_test.rb +209 -0
- data/test/signature_test.rb +52 -0
- data/test/sub_key_test.rb +48 -0
- data/test/support/resources.rb +516 -0
- data/test/test_helper.rb +84 -0
- metadata +203 -0
data/lib/gpgme/ctx.rb
ADDED
@@ -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 = ::FFI::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 = ::FFI::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 = ::FFI::IO.for_fd(fd, 'w')
|
457
|
+
io.puts pass
|
458
|
+
io.flush
|
459
|
+
end
|
460
|
+
|
461
|
+
end
|
462
|
+
end
|
data/lib/gpgme/data.rb
ADDED
@@ -0,0 +1,189 @@
|
|
1
|
+
module GPGME
|
2
|
+
|
3
|
+
##
|
4
|
+
# A class whose purpose is to unify the way we work with the data (both input
|
5
|
+
# and output). Most of the calls expect instances of this class, or will try
|
6
|
+
# to create one from your parameters.
|
7
|
+
#
|
8
|
+
# Read the {#read}, {#write} and {#seek} methods for the most commonly used
|
9
|
+
# methods.
|
10
|
+
class Data
|
11
|
+
|
12
|
+
BLOCK_SIZE = 4096
|
13
|
+
|
14
|
+
class << self
|
15
|
+
|
16
|
+
##
|
17
|
+
# We implement +self.new+ instead of initialize because objects are actually
|
18
|
+
# instantiated through the C API with stuff like +gpgme_data_new+.
|
19
|
+
#
|
20
|
+
# We try to create a {GPGME::Data} smartly depending on the object passed, and if
|
21
|
+
# another {GPGME::Data} object is passed, it just returns it, so when in
|
22
|
+
# doubt, you can always pass a {GPGME::Data} object.
|
23
|
+
#
|
24
|
+
# @example empty
|
25
|
+
# data = GPGME::Data.new
|
26
|
+
# data.write("stuff")
|
27
|
+
#
|
28
|
+
# @example from a string
|
29
|
+
# data = GPGME::Data.new("From a string")
|
30
|
+
#
|
31
|
+
# @example from a file
|
32
|
+
# data = GPGME::Data.new(File.open("secure.pass"))
|
33
|
+
#
|
34
|
+
# @example from a file descriptor
|
35
|
+
# data = GPGME::Data.new(0) # Standard input
|
36
|
+
# data = GPGME::Data.new(1) # Standard output
|
37
|
+
#
|
38
|
+
# file = File.open("secure.pass")
|
39
|
+
# data = GPGME::Data.new(file.fileno) # file descriptor
|
40
|
+
#
|
41
|
+
def new(object = nil)
|
42
|
+
if object.nil?
|
43
|
+
empty!
|
44
|
+
elsif object.is_a?(Data)
|
45
|
+
object
|
46
|
+
elsif object.is_a?(Integer)
|
47
|
+
from_fd(object)
|
48
|
+
elsif object.respond_to? :to_str
|
49
|
+
from_str(object.to_str)
|
50
|
+
elsif object.respond_to? :to_io
|
51
|
+
from_io(object.to_io)
|
52
|
+
elsif object.respond_to? :open
|
53
|
+
from_io(object.open)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Create a new instance with an empty buffer.
|
58
|
+
def empty!
|
59
|
+
rdh = []
|
60
|
+
err = GPGME::gpgme_data_new(rdh)
|
61
|
+
exc = GPGME::error_to_exception(err)
|
62
|
+
raise exc if exc
|
63
|
+
rdh.first
|
64
|
+
end
|
65
|
+
|
66
|
+
# Create a new instance with internal buffer.
|
67
|
+
def from_str(string)
|
68
|
+
rdh = []
|
69
|
+
err = GPGME::gpgme_data_new_from_mem(rdh, string, string.length)
|
70
|
+
exc = GPGME::error_to_exception(err)
|
71
|
+
raise exc if exc
|
72
|
+
rdh.first
|
73
|
+
end
|
74
|
+
|
75
|
+
# Create a new instance associated with a given IO.
|
76
|
+
def from_io(io)
|
77
|
+
from_callbacks(IOCallbacks.new(io))
|
78
|
+
end
|
79
|
+
|
80
|
+
# Create a new instance from the specified file descriptor.
|
81
|
+
def from_fd(fd)
|
82
|
+
rdh = []
|
83
|
+
err = GPGME::gpgme_data_new_from_fd(rdh, fd)
|
84
|
+
exc = GPGME::error_to_exception(err)
|
85
|
+
raise exc if exc
|
86
|
+
rdh.first
|
87
|
+
end
|
88
|
+
|
89
|
+
# Create a new instance from the specified callbacks.
|
90
|
+
def from_callbacks(callbacks, hook_value = nil)
|
91
|
+
rdh = []
|
92
|
+
err = GPGME::gpgme_data_new_from_cbs(rdh, callbacks, hook_value)
|
93
|
+
exc = GPGME::error_to_exception(err)
|
94
|
+
raise exc if exc
|
95
|
+
rdh.first
|
96
|
+
end
|
97
|
+
end # class << self
|
98
|
+
|
99
|
+
# Read at most +length+ bytes from the data object, or to the end
|
100
|
+
# of file if +length+ is omitted or is +nil+.
|
101
|
+
#
|
102
|
+
# @example
|
103
|
+
# data = GPGME::Data.new("From a string")
|
104
|
+
# data.read # => "From a string"
|
105
|
+
#
|
106
|
+
# @example
|
107
|
+
# data = GPGME::Data.new("From a string")
|
108
|
+
# data.read(4) # => "From"
|
109
|
+
#
|
110
|
+
def read(length = nil)
|
111
|
+
if length
|
112
|
+
GPGME::gpgme_data_read(self, length)
|
113
|
+
else
|
114
|
+
buf = String.new
|
115
|
+
loop do
|
116
|
+
s = GPGME::gpgme_data_read(self, BLOCK_SIZE)
|
117
|
+
break unless s
|
118
|
+
buf << s
|
119
|
+
end
|
120
|
+
buf
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
##
|
125
|
+
# Seek to a given +offset+ in the data object according to the
|
126
|
+
# value of +whence+.
|
127
|
+
#
|
128
|
+
# @example going to the beginning of the buffer after writing something
|
129
|
+
# data = GPGME::Data.new("Some data")
|
130
|
+
# data.read # => "Some data"
|
131
|
+
# data.read # => ""
|
132
|
+
# data.seek 0
|
133
|
+
# data.read # => "Some data"
|
134
|
+
#
|
135
|
+
def seek(offset, whence = IO::SEEK_SET)
|
136
|
+
GPGME::gpgme_data_seek(self, offset, IO::SEEK_SET)
|
137
|
+
end
|
138
|
+
|
139
|
+
##
|
140
|
+
# Writes +length+ bytes from +buffer+ into the data object.
|
141
|
+
# Writes the full buffer if no length passed.
|
142
|
+
#
|
143
|
+
# @example
|
144
|
+
# data = GPGME::Data.new
|
145
|
+
# data.write "hola"
|
146
|
+
# data.seek 0
|
147
|
+
# data.read # => "hola"
|
148
|
+
#
|
149
|
+
# @example
|
150
|
+
# data = GPGME::Data.new
|
151
|
+
# data.write "hola", 2
|
152
|
+
# data.seek 0
|
153
|
+
# data.read # => "ho"
|
154
|
+
#
|
155
|
+
def write(buffer, length = buffer.length)
|
156
|
+
GPGME::gpgme_data_write(self, buffer, length)
|
157
|
+
end
|
158
|
+
|
159
|
+
##
|
160
|
+
# Return the encoding of the underlying data.
|
161
|
+
def encoding
|
162
|
+
GPGME::gpgme_data_get_encoding(self)
|
163
|
+
end
|
164
|
+
|
165
|
+
##
|
166
|
+
# Sets the encoding for this buffer. Accepts only values in one of the
|
167
|
+
# DATA_ENCODING_* constants.
|
168
|
+
#
|
169
|
+
# @raise [GPGME::Error::InvalidValue] if the value isn't accepted.
|
170
|
+
def encoding=(encoding)
|
171
|
+
err = GPGME::gpgme_data_set_encoding(self, encoding)
|
172
|
+
exc = GPGME::error_to_exception(err)
|
173
|
+
raise exc if exc
|
174
|
+
encoding
|
175
|
+
end
|
176
|
+
|
177
|
+
##
|
178
|
+
# Return the entire content of the data object as string.
|
179
|
+
def to_s
|
180
|
+
pos = seek(0, IO::SEEK_CUR)
|
181
|
+
begin
|
182
|
+
seek(0)
|
183
|
+
read
|
184
|
+
ensure
|
185
|
+
seek(pos)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|