mail-gpg 0.3.1 → 0.3.2
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.
- checksums.yaml +4 -4
- data/History.txt +8 -0
- data/README.md +54 -46
- data/lib/mail/gpg/gpgme_helper.rb +10 -3
- data/lib/mail/gpg/inline_decrypted_message.rb +22 -0
- data/lib/mail/gpg/mime_signed_message.rb +1 -3
- data/lib/mail/gpg/sign_part.rb +1 -1
- data/lib/mail/gpg/version.rb +1 -1
- data/test/inline_decrypted_message_test.rb +19 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0fa28ac570f95bf31e58025d3e29c4d8fe15c43a
|
4
|
+
data.tar.gz: 3a4afd5b7c7847333c364135aba9acb20fc9762d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d96da3558cb0b0ed814dce389d0e969e19edf718712adcecc0dc5bad04c6d1a35ed8da20acbf9427212072daf1c462e48a9391d5fc0c6d5b63c4e6a9e3593052
|
7
|
+
data.tar.gz: 3a8e23f13198857aa5fe9f533a08d7209d55ee0ba9839d913b977fbea59841315c211c1f87f3440e0c7a1d3a239419ed84dcb0b593efa6590aa85aadfce129cd
|
data/History.txt
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
== 0.3.2 2018-03-30
|
2
|
+
|
3
|
+
* do not attempt to decrypt inline-encrypted HTML parts #52
|
4
|
+
* fixes possible double decoding of quoted printable bodies #57
|
5
|
+
* fixes a bug which occured in some environments that led to encryption with
|
6
|
+
all available public keys (#31, #55)
|
7
|
+
|
8
|
+
|
1
9
|
== 0.3.1 2017-04-13
|
2
10
|
|
3
11
|
* fixes a bug with signature verification that only surfaced in environments
|
data/README.md
CHANGED
@@ -14,7 +14,9 @@ wild as described in this [Know your PGP implementation](http://binblog.info/200
|
|
14
14
|
|
15
15
|
Add this line to your application's Gemfile:
|
16
16
|
|
17
|
-
|
17
|
+
```ruby
|
18
|
+
gem 'mail-gpg'
|
19
|
+
```
|
18
20
|
|
19
21
|
And then execute:
|
20
22
|
|
@@ -31,48 +33,51 @@ Or install it yourself as:
|
|
31
33
|
Construct your Mail object as usual and specify you want it to be encrypted
|
32
34
|
with the gpg method:
|
33
35
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
# encrypt message, no signing
|
42
|
-
gpg encrypt: true
|
36
|
+
```ruby
|
37
|
+
Mail.new do
|
38
|
+
to 'jane@doe.net'
|
39
|
+
from 'john@doe.net'
|
40
|
+
subject 'gpg test'
|
41
|
+
body "encrypt me!"
|
42
|
+
add_file "some_attachment.zip"
|
43
43
|
|
44
|
-
|
45
|
-
|
46
|
-
gpg encrypt: true, sign: true, password: 'secret'
|
44
|
+
# encrypt message, no signing
|
45
|
+
gpg encrypt: true
|
47
46
|
|
48
|
-
|
49
|
-
|
47
|
+
# encrypt and sign message with sender's private key, using the given
|
48
|
+
# passphrase to decrypt the key
|
49
|
+
gpg encrypt: true, sign: true, password: 'secret'
|
50
50
|
|
51
|
+
# encrypt and sign message using a different key
|
52
|
+
gpg encrypt: true, sign_as: 'joe@otherdomain.com', password: 'secret'
|
51
53
|
|
52
|
-
# encrypt and sign message and use a callback function to provide the
|
53
|
-
# passphrase.
|
54
|
-
gpg encrypt: true, sign_as: 'joe@otherdomain.com',
|
55
|
-
passphrase_callback: ->(obj, uid_hint, passphrase_info, prev_was_bad, fd){puts "Enter passphrase for #{passphrase_info}: "; (IO.for_fd(fd, 'w') << readline.chomp).flush }
|
56
|
-
end.deliver
|
57
54
|
|
55
|
+
# encrypt and sign message and use a callback function to provide the
|
56
|
+
# passphrase.
|
57
|
+
gpg encrypt: true, sign_as: 'joe@otherdomain.com',
|
58
|
+
passphrase_callback: ->(obj, uid_hint, passphrase_info, prev_was_bad, fd){puts "Enter passphrase for #{passphrase_info}: "; (IO.for_fd(fd, 'w') << readline.chomp).flush }
|
59
|
+
end.deliver
|
60
|
+
```
|
58
61
|
|
59
62
|
Make sure all recipients' public keys are present in your local gpg keychain.
|
60
63
|
You will get errors in case encryption is not possible due to missing keys.
|
61
64
|
If you collect public key data from your users, you can specify the ascii
|
62
65
|
armored key data for recipients using the `:keys` option like this:
|
63
66
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
+
```ruby
|
68
|
+
johns_key = <<-END
|
69
|
+
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
70
|
+
Version: GnuPG v1.4.12 (GNU/Linux)
|
67
71
|
|
68
|
-
|
69
|
-
|
70
|
-
|
72
|
+
mQGiBEk39msRBADw1ExmrLD1OUMdfvA7cnVVYTC7CyqfNvHUVuuBDhV7azs
|
73
|
+
....
|
74
|
+
END
|
71
75
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
+
Mail.new do
|
77
|
+
to 'john@foo.bar'
|
78
|
+
gpg encrypt: true, keys: { 'john@foo.bar' => johns_key }
|
79
|
+
end
|
80
|
+
```
|
76
81
|
|
77
82
|
The key will then be imported before actually trying to encrypt/send the mail.
|
78
83
|
In theory you only need to specify the key once like that, however doing it
|
@@ -101,16 +106,18 @@ Set the `:verify` option to `true` when calling `decrypt` to decrypt *and* verif
|
|
101
106
|
A `GPGME::Error::BadPassphrase` will be raised if the password for the private key is incorrect.
|
102
107
|
A `EncodingError` will be raised if the encrypted mails is not encoded correctly as a [RFC 3156](http://www.ietf.org/rfc/rfc3156.txt) message.
|
103
108
|
|
109
|
+
Please note that in case of a multipart/alternative-message where both parts are inline-encrypted, the HTML-part will be dropped during decryption. Handling the HTML-part would require parsing HTML and guessing about the decrypted contents, which is brittle and out of the scope of this library. If you need the HTML-part of multipart/alternative-messages, use pgp/mime-encryption.
|
104
110
|
|
105
111
|
### Signing only
|
106
112
|
|
107
113
|
Just leave the `:encrypt` option out or pass `encrypt: false`, i.e.
|
108
114
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
115
|
+
```ruby
|
116
|
+
Mail.new do
|
117
|
+
to 'jane@doe.net'
|
118
|
+
gpg sign: true
|
119
|
+
end.deliver
|
120
|
+
```
|
114
121
|
|
115
122
|
### Verify signature(s)
|
116
123
|
|
@@ -147,14 +154,14 @@ signature with the key id of the expected sender.
|
|
147
154
|
The Hkp class can be used to lookup and import public keys from public key servers.
|
148
155
|
You can specify the keyserver url when initializing the class:
|
149
156
|
|
150
|
-
```
|
157
|
+
```ruby
|
151
158
|
hkp = Hkp.new("hkp://my-key-server.de")
|
152
159
|
```
|
153
160
|
|
154
161
|
Or, if you want to override how ssl certificates should be treated in case of
|
155
162
|
TLS-secured keyservers (the default is `VERIFY_PEER`):
|
156
163
|
|
157
|
-
```
|
164
|
+
```ruby
|
158
165
|
hkp = Hkp.new(keyserver: "hkps://another.key-server.com",
|
159
166
|
ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE)
|
160
167
|
```
|
@@ -170,13 +177,13 @@ parsing the `gpg.conf` file). As a last resort, the server-pool at
|
|
170
177
|
|
171
178
|
Lookup key ids by searching the keyserver for an email address
|
172
179
|
|
173
|
-
```
|
180
|
+
```ruby
|
174
181
|
hkp.search('jane@doe.net')
|
175
182
|
```
|
176
183
|
|
177
184
|
You can lookup (and import) a specific key by its id:
|
178
185
|
|
179
|
-
```
|
186
|
+
```ruby
|
180
187
|
key = hkp.fetch(id)
|
181
188
|
GPGME::Key.import(key)
|
182
189
|
|
@@ -186,12 +193,14 @@ hkp.fetch_and_import(id)
|
|
186
193
|
|
187
194
|
## Rails / ActionMailer integration
|
188
195
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
196
|
+
```ruby
|
197
|
+
class MyMailer < ActionMailer::Base
|
198
|
+
default from: 'baz@bar.com'
|
199
|
+
def some_mail
|
200
|
+
mail to: 'foo@bar.com', subject: 'subject!', gpg: { encrypt: true }
|
201
|
+
end
|
202
|
+
end
|
203
|
+
```
|
195
204
|
|
196
205
|
The gpg option takes the same arguments as outlined above for the
|
197
206
|
Mail::Message#gpg method.
|
@@ -228,7 +237,6 @@ Open3.popen3(gppbin, '--preset', fpr) do |stdin, stdout, stderr|
|
|
228
237
|
end
|
229
238
|
# Hook to kill our gpg-agent when script finishes.
|
230
239
|
Signal.trap(0, proc { Process.kill('TERM', ENV['GPG_AGENT_INFO'].split(':')[1]) })
|
231
|
-
|
232
240
|
```
|
233
241
|
|
234
242
|
|
@@ -23,7 +23,7 @@ module Mail
|
|
23
23
|
GPGME::Ctx.new(options) do |ctx|
|
24
24
|
begin
|
25
25
|
if options[:sign]
|
26
|
-
if options[:signers]
|
26
|
+
if options[:signers] && options[:signers].size > 0
|
27
27
|
signers = GPGME::Key.find(:secret, options[:signers], :sign)
|
28
28
|
ctx.add_signer(*signers)
|
29
29
|
end
|
@@ -122,12 +122,19 @@ module Mail
|
|
122
122
|
k = key_data[r]
|
123
123
|
if k and k =~ /-----BEGIN PGP/
|
124
124
|
k = GPGME::Key.import(k).imports.map(&:fpr)
|
125
|
+
k = nil if k.size == 0
|
126
|
+
end
|
127
|
+
key_id = k || r
|
128
|
+
unless key_id.nil? || key_id.empty?
|
129
|
+
GPGME::Key.find(:public, key_id, :encrypt)
|
125
130
|
end
|
126
|
-
GPGME::Key.find(:public, k || r, :encrypt)
|
127
131
|
end.flatten
|
128
|
-
|
132
|
+
elsif emails_or_shas_or_keys.size > 0
|
129
133
|
# key lookup in keychain for all receivers
|
130
134
|
GPGME::Key.find :public, emails_or_shas_or_keys, :encrypt
|
135
|
+
else
|
136
|
+
# empty array given
|
137
|
+
[]
|
131
138
|
end
|
132
139
|
end
|
133
140
|
end
|
@@ -16,6 +16,28 @@ module Mail
|
|
16
16
|
if cipher_mail.multipart?
|
17
17
|
self.new do
|
18
18
|
Mail::Gpg.copy_headers cipher_mail, self
|
19
|
+
|
20
|
+
# Drop the HTML-part of a multipart/alternative-message if it is
|
21
|
+
# inline-encrypted: that ciphertext is probably wrapped in HTML,
|
22
|
+
# which GnuPG chokes upon, so we would have to parse the HTML to
|
23
|
+
# handle the message-part properly.
|
24
|
+
# Also it's not clear how to handle the resulting plain-text: is
|
25
|
+
# it HTML or simple text? That depends on the sending MUA and
|
26
|
+
# the original input.
|
27
|
+
# In summary, that's too much complications.
|
28
|
+
if cipher_mail.mime_type == 'multipart/alternative' &&
|
29
|
+
cipher_mail.html_part.present? &&
|
30
|
+
cipher_mail.html_part.body.decoded.include?('-----BEGIN PGP MESSAGE-----')
|
31
|
+
cipher_mail.parts.delete_if do |part|
|
32
|
+
part[:content_type].content_type == 'text/html'
|
33
|
+
end
|
34
|
+
# Set the content-type of the newly generated message to
|
35
|
+
# something less confusing.
|
36
|
+
content_type 'multipart/mixed'
|
37
|
+
# Leave a marker for other code.
|
38
|
+
header['X-MailGpg-Deleted-Html-Part'] = 'true'
|
39
|
+
end
|
40
|
+
|
19
41
|
cipher_mail.parts.each do |part|
|
20
42
|
p = VerifiedPart.new do |p|
|
21
43
|
if part.has_content_type? && /application\/(?:octet-stream|pgp-encrypted)/ =~ part.mime_type
|
data/lib/mail/gpg/sign_part.rb
CHANGED
@@ -25,7 +25,7 @@ module Mail
|
|
25
25
|
end
|
26
26
|
|
27
27
|
# Work around the problem that plain_part.raw_source prefixes an
|
28
|
-
#
|
28
|
+
# erroneous CRLF, <https://github.com/mikel/mail/issues/702>.
|
29
29
|
if ! plain_part.raw_source.empty?
|
30
30
|
plaintext = [ plain_part.header.raw_source,
|
31
31
|
"\r\n\r\n",
|
data/lib/mail/gpg/version.rb
CHANGED
@@ -33,6 +33,25 @@ class InlineDecryptedMessageTest < Test::Unit::TestCase
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
+
context "multipart/alternative message" do
|
37
|
+
should "have dropped HTML-part" do
|
38
|
+
mail = Mail.new(@mail)
|
39
|
+
mail.body = InlineDecryptedMessageTest.encrypt(mail, mail.body.to_s)
|
40
|
+
mail.html_part do |p|
|
41
|
+
p.body "<pre>#{InlineDecryptedMessageTest.encrypt(mail, mail.body.to_s)}</pre>"
|
42
|
+
end
|
43
|
+
|
44
|
+
assert mail.multipart?
|
45
|
+
assert mail.encrypted?
|
46
|
+
assert decrypted = mail.decrypt(:password => 'abc', verify: true)
|
47
|
+
assert !decrypted.encrypted?
|
48
|
+
assert decrypted.mime_type == 'multipart/mixed'
|
49
|
+
assert decrypted.parts.size == 1
|
50
|
+
assert decrypted.parts.first.mime_type == 'text/plain'
|
51
|
+
assert decrypted.header['X-MailGpg-Deleted-Html-Part'].value == 'true'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
36
55
|
context "attachment message" do
|
37
56
|
should "decrypt attachment" do
|
38
57
|
rakefile = File.open('Rakefile') { |file| file.read }
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mail-gpg
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jens Kraemer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-03-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mail
|