1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
|
require 'mail/gpg/verified_part'
# decryption of the so called 'PGP-Inline' message types
# this is not a standard, so the implementation is based on the notes
# here http://binblog.info/2008/03/12/know-your-pgp-implementation/
# and on test messages generated with the Mozilla Enigmail OpenPGP
# plugin https://www.enigmail.net
module Mail
module Gpg
class InlineDecryptedMessage < Mail::Message
# options are:
#
# :verify: decrypt and verify
def self.setup(cipher_mail, options = {})
if cipher_mail.multipart?
self.new do
Mail::Gpg.copy_headers cipher_mail, self
# Drop the HTML-part of a multipart/alternative-message if it is
# inline-encrypted: that ciphertext is probably wrapped in HTML,
# which GnuPG chokes upon, so we would have to parse the HTML to
# handle the message-part properly.
# Also it's not clear how to handle the resulting plain-text: is
# it HTML or simple text? That depends on the sending MUA and
# the original input.
# In summary, that's too much complications.
if cipher_mail.mime_type == 'multipart/alternative' &&
cipher_mail.html_part.present? &&
cipher_mail.html_part.body.decoded.include?('-----BEGIN PGP MESSAGE-----')
cipher_mail.parts.delete_if do |part|
part[:content_type].content_type == 'text/html'
end
# Set the content-type of the newly generated message to
# something less confusing.
content_type 'multipart/mixed'
# Leave a marker for other code.
header['X-MailGpg-Deleted-Html-Part'] = 'true'
end
cipher_mail.parts.each do |part|
p = VerifiedPart.new do |p|
if part.has_content_type? && /application\/(?:octet-stream|pgp-encrypted)/ =~ part.mime_type
# encrypted attachment, we set the content_type to the generic 'application/octet-stream'
# and remove the .pgp/gpg/asc from name/filename in header fields
decrypted = GpgmeHelper.decrypt(part.decoded, options)
p.verify_result decrypted.verify_result if options[:verify]
p.content_type part.content_type.sub(/application\/(?:octet-stream|pgp-encrypted)/, 'application/octet-stream')
.sub(/name=(?:"')?(.*)\.(?:pgp|gpg|asc)(?:"')?/, 'name="\1"')
p.content_disposition part.content_disposition.sub(/filename=(?:"')?(.*)\.(?:pgp|gpg|asc)(?:"')?/, 'filename="\1"')
p.content_transfer_encoding Mail::Encodings::Base64
p.body Mail::Encodings::Base64::encode(decrypted.to_s)
else
body = part.body.decoded
if body.include?('-----BEGIN PGP MESSAGE-----')
decrypted = GpgmeHelper.decrypt(body, options)
p.verify_result decrypted.verify_result if options[:verify]
p.body decrypted.to_s
else
p.content_type part.content_type
p.content_transfer_encoding part.content_transfer_encoding
p.body part.body.to_s
end
end
end
add_part p
end
end # of multipart
else
decrypted = cipher_mail.body.empty? ? '' : GpgmeHelper.decrypt(cipher_mail.body.decoded, options)
self.new do
cipher_mail.header.fields.each do |field|
header[field.name] = field.value
end
body decrypted.to_s
verify_result decrypted.verify_result if options[:verify] && '' != decrypted
end
end
end
end
end
end
|