benburkert-gpgme 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,66 @@
1
+ module GPGME
2
+ class Error < StandardError
3
+ def initialize(error)
4
+ @error = error
5
+ end
6
+ attr_reader :error
7
+
8
+ # Return the error code.
9
+ #
10
+ # The error code indicates the type of an error, or the reason why
11
+ # an operation failed.
12
+ def code
13
+ GPGME::gpgme_err_code(@error)
14
+ end
15
+
16
+ # Return the error source.
17
+ #
18
+ # The error source has not a precisely defined meaning. Sometimes
19
+ # it is the place where the error happened, sometimes it is the
20
+ # place where an error was encoded into an error value. Usually
21
+ # the error source will give an indication to where to look for
22
+ # the problem. This is not always true, but it is attempted to
23
+ # achieve this goal.
24
+ def source
25
+ GPGME::gpgme_err_source(@error)
26
+ end
27
+
28
+ # Return a description of the error code.
29
+ def message
30
+ GPGME::gpgme_strerror(@error)
31
+ end
32
+
33
+ class General < self; end
34
+ class InvalidValue < self; end
35
+ class UnusablePublicKey < self
36
+ attr_accessor :keys
37
+ end
38
+ class UnusableSecretKey < self
39
+ attr_accessor :keys
40
+ end
41
+ class NoData < self; end
42
+ class Conflict < self; end
43
+ class NotImplemented < self; end
44
+ class DecryptFailed < self; end
45
+ class BadPassphrase < self; end
46
+ class Canceled < self; end
47
+ class InvalidEngine < self; end
48
+ class AmbiguousName < self; end
49
+ class WrongKeyUsage < self
50
+ attr_accessor :key_usage
51
+ end
52
+ class CertificateRevoked < self; end
53
+ class CertificateExpired < self; end
54
+ class NoCRLKnown < self; end
55
+ class NoPolicyMatch < self; end
56
+ class NoSecretKey < self; end
57
+ class MissingCertificate < self; end
58
+ class BadCertificateChain < self; end
59
+ class UnsupportedAlgorithm < self
60
+ attr_accessor :algorithm
61
+ end
62
+ class BadSignature < self; end
63
+ class NoPublicKey < self; end
64
+ class InvalidVersion < self; end
65
+ end
66
+ end
@@ -0,0 +1,21 @@
1
+ module GPGME
2
+ class IOCallbacks
3
+ def initialize(io)
4
+ @io = io
5
+ end
6
+
7
+ def read(hook, length)
8
+ @io.read(length)
9
+ end
10
+
11
+ def write(hook, buffer, length)
12
+ @io.write(buffer[0 .. length])
13
+ end
14
+
15
+ def seek(hook, offset, whence)
16
+ return @io.pos if offset == 0 && whence == IO::SEEK_CUR
17
+ @io.seek(offset, whence)
18
+ @io.pos
19
+ end
20
+ end
21
+ end
data/lib/gpgme/key.rb ADDED
@@ -0,0 +1,242 @@
1
+ module GPGME
2
+
3
+ ##
4
+ # A ruby representation of a public or a secret key.
5
+ #
6
+ # Every key has two instances of {GPGME::SubKey}, accessible through
7
+ # {.subkeys}, and with a {.primary_subkey} where most attributes are
8
+ # derived from, like the +fingerprint+.
9
+ #
10
+ # Also, every key has at least a {GPGME::UserID}, accessible through
11
+ # {.uids}, with a {.primary_uid}, where other attributes are derived from,
12
+ # like +email+ or +name+
13
+ class Key
14
+ private_class_method :new
15
+
16
+ attr_reader :keylist_mode, :protocol, :owner_trust
17
+ attr_reader :issuer_serial, :issuer_name, :chain_id
18
+ attr_reader :subkeys, :uids
19
+
20
+ include KeyCommon
21
+
22
+ class << self
23
+
24
+ ##
25
+ # Returns an array of {GPGME::Key} objects that match the parameters.
26
+ # * +secret+ set to +:secret+ to get only secret keys, or to +:public+ to
27
+ # get only public keys.
28
+ # * +keys_or_names+ an array or an item that can be either {GPGME::Key}
29
+ # elements, or string identifiers like the email or the sha. Leave
30
+ # blank to get all.
31
+ # * +purposes+ get only keys that are usable for any of these purposes.
32
+ # See {GPGME::Key} for a list of possible key capabilities.
33
+ #
34
+ # @example
35
+ # GPGME::Key.find :secret # => first secret key found
36
+ #
37
+ # @example
38
+ # GPGME::Key.find(:public, "mrsimo@example.com")
39
+ # # => return only public keys that match mrsimo@example.com
40
+ #
41
+ # @example
42
+ # GPGME::Key.find(:public, "mrsimo@example.com", :sign)
43
+ # # => return the public keys that match mrsimo@exampl.com and are
44
+ # # capable of signing
45
+ def find(secret, keys_or_names = nil, purposes = [])
46
+ secret = (secret == :secret)
47
+ keys_or_names = [""] if keys_or_names.nil? || (keys_or_names.is_a?(Array) && keys_or_names.empty?)
48
+ keys_or_names = [keys_or_names].flatten
49
+ purposes = [purposes].flatten.compact.uniq
50
+
51
+ keys = []
52
+ keys_or_names.each do |key_or_name|
53
+ case key_or_name
54
+ when Key then keys << key_or_name
55
+ when String
56
+ GPGME::Ctx.new do |ctx|
57
+ keys += ctx.keys(key_or_name, secret).select do |k|
58
+ k.usable_for?(purposes)
59
+ end
60
+ end
61
+ end
62
+ end
63
+ keys
64
+ end
65
+
66
+ def get(fingerprint)
67
+ Ctx.new do |ctx|
68
+ ctx.get_key(fingerprint)
69
+ end
70
+ end
71
+
72
+ # Exports public keys
73
+ #
74
+ # GPGME::Key.export pattern, options
75
+ #
76
+ # Private keys cannot be exported due to GPGME restrictions.
77
+ #
78
+ # @param pattern
79
+ # Identifier of the key to export.
80
+ #
81
+ # @param [Hash] options
82
+ # * +:output+ specify where to write the key to. It will be converted to
83
+ # a {GPGME::Data}, so it could be a file, for example.
84
+ # * Any other option accepted by {GPGME::Ctx.new}
85
+ #
86
+ # @return [GPGME::Data] the exported key.
87
+ #
88
+ # @example
89
+ # key = GPGME::Key.export "mrsimo@example.com"
90
+ #
91
+ # @example writing to a file
92
+ # out = File.open("my.key", "w+")
93
+ # GPGME::Key.export "mrsimo@example.com", :output => out
94
+ #
95
+ def export(pattern, options = {})
96
+ output = Data.new(options[:output])
97
+
98
+ GPGME::Ctx.new(options) do |ctx|
99
+ ctx.export_keys(pattern, output)
100
+ end
101
+
102
+ output.seek(0)
103
+ output
104
+ end
105
+
106
+ # Imports a key
107
+ #
108
+ # GPGME::Key.import keydata, options
109
+ #
110
+ # @param keydata
111
+ # The key to import. It will be converted to a {GPGME::Data} object,
112
+ # so could be a file, for example.
113
+ # @param options
114
+ # Any other option accepted by {GPGME::Ctx.new}
115
+ #
116
+ # @example
117
+ # GPGME::Key.import(File.open("my.key"))
118
+ #
119
+ def import(keydata, options = {})
120
+ GPGME::Ctx.new(options) do |ctx|
121
+ ctx.import_keys(Data.new(keydata))
122
+ ctx.import_result
123
+ end
124
+ end
125
+ end
126
+
127
+ ##
128
+ # Exports this key. Accepts the same options as {GPGME::Ctx.new}, and
129
+ # +options[:output]+, where you can specify something that can become a
130
+ # {GPGME::Data}, where the output will go.
131
+ #
132
+ # @example
133
+ # key.export(:armor => true)
134
+ # # => GPGME::Data you can read with ASCII armored format
135
+ #
136
+ # @example
137
+ # file = File.open("key.asc", "w+")
138
+ # key.export(:output => file)
139
+ # # => the key will be written to the file.
140
+ #
141
+ def export(options = {})
142
+ Key.export self.sha, options
143
+ end
144
+
145
+ ##
146
+ # Delete this key. If it's public, and has a secret one it will fail unless
147
+ # +allow_secret+ is specified as true.
148
+ def delete!(allow_secret = false)
149
+ GPGME::Ctx.new do |ctx|
150
+ ctx.delete_key self, allow_secret
151
+ end
152
+ end
153
+
154
+ ##
155
+ # Returns the expiry date for this key
156
+ def expires
157
+ primary_subkey.expires
158
+ end
159
+
160
+ ##
161
+ # Returns true if the key is expired
162
+ def expired
163
+ subkeys.any?(&:expired)
164
+ end
165
+
166
+ def primary_subkey
167
+ @primary_subkey ||= subkeys.first
168
+ end
169
+
170
+ ##
171
+ # Short descriptive value. Can be used to identify the key.
172
+ def sha
173
+ primary_subkey.sha
174
+ end
175
+
176
+ ##
177
+ # Longer descriptive value. Can be used to identify the key.
178
+ def fingerprint
179
+ primary_subkey.fingerprint
180
+ end
181
+
182
+ ##
183
+ # Returns the main {GPGME::UserID} for this key.
184
+ def primary_uid
185
+ uids.first
186
+ end
187
+
188
+ ##
189
+ # Returns the email for this key.
190
+ def email
191
+ primary_uid.email
192
+ end
193
+
194
+ ##
195
+ # Returns the issuer name for this key.
196
+ def name
197
+ primary_uid.name
198
+ end
199
+
200
+ ##
201
+ # Returns the issuer comment for this key.
202
+ def comment
203
+ primary_uid.comment
204
+ end
205
+
206
+ def ==(another_key)
207
+ fingerprint == another_key.fingerprint
208
+ end
209
+
210
+ def inspect
211
+ sprintf("#<#{self.class} %s %4d%s/%s %s trust=%s, owner_trust=%s, \
212
+ capability=%s, subkeys=%s, uids=%s>",
213
+ primary_subkey.secret? ? 'sec' : 'pub',
214
+ primary_subkey.length,
215
+ primary_subkey.pubkey_algo_letter,
216
+ primary_subkey.fingerprint[-8 .. -1],
217
+ primary_subkey.timestamp.strftime('%Y-%m-%d'),
218
+ trust.inspect,
219
+ VALIDITY_NAMES[@owner_trust].inspect,
220
+ capability.inspect,
221
+ subkeys.inspect,
222
+ uids.inspect)
223
+ end
224
+
225
+ def to_s
226
+ primary_subkey = subkeys[0]
227
+ s = sprintf("%s %4d%s/%s %s\n",
228
+ primary_subkey.secret? ? 'sec' : 'pub',
229
+ primary_subkey.length,
230
+ primary_subkey.pubkey_algo_letter,
231
+ primary_subkey.fingerprint[-8 .. -1],
232
+ primary_subkey.timestamp.strftime('%Y-%m-%d'))
233
+ uids.each do |user_id|
234
+ s << "uid\t\t#{user_id.name} <#{user_id.email}>\n"
235
+ end
236
+ subkeys.each do |subkey|
237
+ s << subkey.to_s
238
+ end
239
+ s
240
+ end
241
+ end
242
+ end
@@ -0,0 +1,43 @@
1
+ module GPGME
2
+ module KeyCommon
3
+
4
+ ##
5
+ # Returns nil if the trust is valid.
6
+ # Returns one of +:revoked+, +:expired+, +:disabled+, +:invalid+
7
+ def trust
8
+ return :revoked if @revoked == 1
9
+ return :expired if @expired == 1
10
+ return :disabled if @disabled == 1
11
+ return :invalid if @invalid == 1
12
+ end
13
+
14
+ ##
15
+ # Array of capabilities for this key. It can contain any combination of
16
+ # +:encrypt+, +:sign+, +:certify+ or +:authenticate+
17
+ def capability
18
+ caps = []
19
+ caps << :encrypt if @can_encrypt
20
+ caps << :sign if @can_sign
21
+ caps << :certify if @can_certify
22
+ caps << :authenticate if @can_authenticate
23
+ caps
24
+ end
25
+
26
+ ##
27
+ # Checks if the key is capable of all of these actions. If empty array
28
+ # is passed then will return true.
29
+ #
30
+ # Returns false if the keys trust has been invalidated.
31
+ def usable_for?(purposes)
32
+ unless purposes.kind_of? Array
33
+ purposes = [purposes]
34
+ end
35
+ return false if [:revoked, :expired, :disabled, :invalid].include? trust
36
+ return (purposes - capability).empty?
37
+ end
38
+
39
+ def secret?
40
+ @secret == 1
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,35 @@
1
+ module GPGME
2
+ class KeySig
3
+ private_class_method :new
4
+
5
+ attr_reader :pubkey_algo, :keyid
6
+
7
+ def revoked?
8
+ @revoked == 1
9
+ end
10
+
11
+ def expired?
12
+ @expired == 1
13
+ end
14
+
15
+ def invalid?
16
+ @invalid == 1
17
+ end
18
+
19
+ def exportable?
20
+ @exportable == 1
21
+ end
22
+
23
+ def timestamp
24
+ Time.at(@timestamp)
25
+ end
26
+
27
+ def expires
28
+ Time.at(@expires)
29
+ end
30
+
31
+ def inspect
32
+ "#<#{self.class} #{keyid} timestamp=#{timestamp}, expires=#{expires}>"
33
+ end
34
+ end
35
+ end
data/lib/gpgme/misc.rb ADDED
@@ -0,0 +1,66 @@
1
+ module GPGME
2
+ class EngineInfo
3
+ private_class_method :new
4
+
5
+ attr_reader :protocol, :file_name, :version, :req_version, :home_dir
6
+ alias required_version req_version
7
+ end
8
+
9
+ class VerifyResult
10
+ private_class_method :new
11
+
12
+ attr_reader :signatures
13
+ end
14
+
15
+ class DecryptResult
16
+ private_class_method :new
17
+
18
+ attr_reader :unsupported_algorithm, :wrong_key_usage
19
+ end
20
+
21
+ class SignResult
22
+ private_class_method :new
23
+
24
+ attr_reader :invalid_signers, :signatures
25
+ end
26
+
27
+ class EncryptResult
28
+ private_class_method :new
29
+
30
+ attr_reader :invalid_recipients
31
+ end
32
+
33
+ class InvalidKey
34
+ private_class_method :new
35
+
36
+ attr_reader :fpr, :reason
37
+ alias fingerprint fpr
38
+ end
39
+
40
+ class NewSignature
41
+ private_class_method :new
42
+
43
+ attr_reader :type, :pubkey_algo, :hash_algo, :sig_class, :fpr
44
+ alias fingerprint fpr
45
+
46
+ def timestamp
47
+ Time.at(@timestamp)
48
+ end
49
+ end
50
+
51
+ class ImportStatus
52
+ private_class_method :new
53
+
54
+ attr_reader :fpr, :result, :status
55
+ alias fingerprint fpr
56
+ end
57
+
58
+ class ImportResult
59
+ private_class_method :new
60
+
61
+ attr_reader :considered, :no_user_id, :imported, :imported_rsa, :unchanged
62
+ attr_reader :new_user_ids, :new_sub_keys, :new_signatures, :new_revocations
63
+ attr_reader :secret_read, :secret_imported, :secret_unchanged
64
+ attr_reader :not_imported, :imports
65
+ end
66
+ end
@@ -0,0 +1,85 @@
1
+ module GPGME
2
+ class Signature
3
+ private_class_method :new
4
+
5
+ attr_reader :summary, :fpr, :status, :notations, :wrong_key_usage
6
+ attr_reader :validity, :validity_reason
7
+ attr_reader :pka_trust, :pka_address
8
+ alias fingerprint fpr
9
+
10
+ ##
11
+ # Returns true if the signature is correct
12
+ def valid?
13
+ status_code == GPGME::GPG_ERR_NO_ERROR
14
+ end
15
+
16
+ def expired_signature?
17
+ status_code == GPGME::GPG_ERR_SIG_EXPIRED
18
+ end
19
+
20
+ def expired_key?
21
+ status_code == GPGME::GPG_ERR_KEY_EXPIRED
22
+ end
23
+
24
+ def revoked_key?
25
+ status_code == GPGME::GPG_ERR_CERT_REVOKED
26
+ end
27
+
28
+ def bad?
29
+ status_code == GPGME::GPG_ERR_BAD_SIGNATURE
30
+ end
31
+
32
+ def no_key?
33
+ status_code == GPGME::GPG_ERR_NO_PUBKEY
34
+ end
35
+
36
+ def status_code
37
+ GPGME::gpgme_err_code(status)
38
+ end
39
+
40
+ def from
41
+ @from ||= begin
42
+ Ctx.new do |ctx|
43
+ if from_key = ctx.get_key(fingerprint)
44
+ "#{from_key.subkeys[0].keyid} #{from_key.uids[0].uid}"
45
+ else
46
+ fingerprint
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ def key
53
+ @key ||= begin
54
+ Ctx.new do |ctx|
55
+ @key = ctx.get_key(fingerprint)
56
+ end
57
+ end
58
+ end
59
+
60
+ def timestamp
61
+ Time.at(@timestamp)
62
+ end
63
+
64
+ def exp_timestamp
65
+ Time.at(@exp_timestamp)
66
+ end
67
+
68
+ def to_s
69
+ case status_code
70
+ when GPGME::GPG_ERR_NO_ERROR
71
+ "Good signature from #{from}"
72
+ when GPGME::GPG_ERR_SIG_EXPIRED
73
+ "Expired signature from #{from}"
74
+ when GPGME::GPG_ERR_KEY_EXPIRED
75
+ "Signature made from expired key #{from}"
76
+ when GPGME::GPG_ERR_CERT_REVOKED
77
+ "Signature made from revoked key #{from}"
78
+ when GPGME::GPG_ERR_BAD_SIGNATURE
79
+ "Bad signature from #{from}"
80
+ when GPGME::GPG_ERR_NO_PUBKEY
81
+ "No public key for #{from}"
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,58 @@
1
+ module GPGME
2
+ class SubKey
3
+ private_class_method :new
4
+
5
+ attr_reader :pubkey_algo, :length, :keyid, :fpr
6
+ alias fingerprint fpr
7
+
8
+ include KeyCommon
9
+
10
+ def timestamp
11
+ Time.at(@timestamp)
12
+ end
13
+
14
+ def expires
15
+ Time.at(@expires)
16
+ end
17
+
18
+ def expired
19
+ return false if @expires == 0
20
+ @expires < Time.now.to_i
21
+ end
22
+
23
+ def sha
24
+ (@fingerprint || @keyid)[-8 .. -1]
25
+ end
26
+
27
+ PUBKEY_ALGO_LETTERS = {
28
+ PK_RSA => "R",
29
+ PK_ELG_E => "g",
30
+ PK_ELG => "G",
31
+ PK_DSA => "D"
32
+ }
33
+
34
+ def pubkey_algo_letter
35
+ PUBKEY_ALGO_LETTERS[@pubkey_algo] || "?"
36
+ end
37
+
38
+ def inspect
39
+ sprintf("#<#{self.class} %s %4d%s/%s %s trust=%s, capability=%s>",
40
+ secret? ? 'ssc' : 'sub',
41
+ length,
42
+ pubkey_algo_letter,
43
+ (@fingerprint || @keyid)[-8 .. -1],
44
+ timestamp.strftime('%Y-%m-%d'),
45
+ trust.inspect,
46
+ capability.inspect)
47
+ end
48
+
49
+ def to_s
50
+ sprintf("%s %4d%s/%s %s\n",
51
+ secret? ? 'ssc' : 'sub',
52
+ length,
53
+ pubkey_algo_letter,
54
+ (@fingerprint || @keyid)[-8 .. -1],
55
+ timestamp.strftime('%Y-%m-%d'))
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,20 @@
1
+ module GPGME
2
+ class UserID
3
+ private_class_method :new
4
+
5
+ attr_reader :validity, :uid, :name, :comment, :email, :signatures
6
+
7
+ def revoked?
8
+ @revoked == 1
9
+ end
10
+
11
+ def invalid?
12
+ @invalid == 1
13
+ end
14
+
15
+ def inspect
16
+ "#<#{self.class} #{name} <#{email}> \
17
+ validity=#{VALIDITY_NAMES[validity]}, signatures=#{signatures.inspect}>"
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,3 @@
1
+ module GPGME
2
+ VERSION = "1.0.8"
3
+ end