Project

General

Profile

« Previous | Next » 

Revision c0979b3e

Added by Marc Dequènes about 15 years ago

  • ID c0979b3eb0412e410e1215171c043eeb29253823

[evol] moved signed/encrypted mail creation from original mail to TMail class, and removed mail object duplication in the process (references to inners objects caused original mail to be altered, copying original headers instead)

View differences:

lib/cyborghood/mail.rb
end
def crypt(fingerprint)
clear_data = build_intermediate_mail()
encrypted_data = clear_data.pgp_crypt(fingerprint)
# build properly encrypted mail
# (modify original mail parts)
@mail.set_content_type("multipart", "encrypted", {'boundary' => TMail.new_boundary, "protocol" => "application/pgp-encrypted"})
@mail.transfer_encoding = "7bit"
@mail['content-disposition'] = nil
@mail.body = "This mail is a RFC3156 encrypted message.\n"
@mail.parts.clear
p_pgp = TMail::Mail.new
p_pgp.set_content_type("application", "pgp-encrypted")
p_pgp.transfer_encoding = "7bit"
p_pgp.content_disposition = "inline"
p_pgp.body = "Version: 1\n"
@mail.parts << p_pgp
p_encrypted = TMail::Mail.new
p_encrypted.set_content_type("application", "octet-stream")
p_encrypted.transfer_encoding = "7bit"
p_encrypted.content_disposition = "inline"
p_encrypted.body = encrypted_data
@mail.parts << p_encrypted
@mail = @mail.create_encrypted(fingerprint)
end
def sign
data = build_intermediate_mail()
sign_data = data.pgp_sign([@config.mail.key_id]) do |uid_hint, passphrase_info, prev_was_bad|
# we don't check the uid, as their is only one signer
@mail = @mail.create_signed(@config.mail.key_id) do |uid_hint, passphrase_info, prev_was_bad|
@config.mail.key_passphrase
end
original_content_type = @mail.content_type
original_content_transfer_encoding = @mail.content_transfer_encoding
original_content_disposition = @mail.content_disposition
# build properly signed mail
# (modify original mail parts)
@mail.set_content_type("multipart", "signed", {'boundary' => TMail.new_boundary, 'protocol' => "application/pgp-signature", 'micalg' => sign_data[:micalg]})
@mail.transfer_encoding = "7bit"
@mail['content-disposition'] = nil
@mail.body = "This mail is a RFC3156 signed message.\n"
@mail.parts.clear
p_signed = data
@mail.parts << p_signed
p_signature = TMail::Mail.new
p_signature.set_content_type("application", "pgp-signature")
p_signature.transfer_encoding = "7bit"
p_signature.content_disposition = "inline"
p_signature.body = sign_data[:signature]
@mail.parts << p_signature
end
def sign_and_crypt(fingerprint)
# not using sign_and_crypt(), to avoid repeating code
sign()
crypt(fingerprint)
end
......
private
def build_intermediate_mail
# build a fake mail to get the generated content to be crypted/signed
fake_mail = TMail::Mail.new
fake_mail['content-type'] = @mail['content-type'].to_s
fake_mail.transfer_encoding = @mail.transfer_encoding if @mail.transfer_encoding
fake_mail.content_disposition = @mail.content_disposition if @mail.content_disposition
if @mail.multipart?
@mail.each_part {|p| fake_mail.parts << p }
else
fake_mail.body = @mail.body
end
# store the calculated content, to be able to use the raw() method
fake_mail.write_back
fake_mail
end
def parse_signed
order = {:ok => false, :msg => "mail not formatted correctly"}
lib/tmail_extra.rb
:passphrase_callback_value => passphrase_callback, :textmode => true})
end
def pgp_crypt(fingerprint)
GPGME.encrypt([gpg_key(fingerprint)], self.to_s, {:armor => true, :always_trust => true})
def pgp_crypt(crypters_id)
crypters_id = [crypters_id] unless crypters_id.is_a? Array
crypters = crypters_id.collect{|key_id| gpg_key(key_id, false) }
GPGME.encrypt(crypters, self.to_s, {:armor => true, :always_trust => true})
end
def pgp_sign(signers_id, &passphrase_callback)
signers_id = [signers_id] unless signers_id.is_a? Array
signers = signers_id.collect{|key_id| gpg_key(key_id, true) }
# we don't use GPGME.sign(), because we need to get operation information to get the hash_algo and compute the micalg parameter
gpg = GPGME::Ctx.new({:signers => signers, :passphrase_callback => method(:gpg_passphrase_callback_wrapper),
......
raw.chomp.gsub(/\r?\n/, "\r\n")
end
def create_encrypted(crypters_id)
clear_data = build_intermediate_mail()
encrypted_data = clear_data.pgp_crypt(crypters_id)
# build properly encrypted mail
# (preserving headers from original mail)
mail = TMail::Mail.new
mail.copy_headers_from(self)
mail.set_content_type("multipart", "encrypted", {'boundary' => TMail.new_boundary, "protocol" => "application/pgp-encrypted"})
mail.transfer_encoding = "7bit"
mail['content-disposition'] = nil
mail.body = "This mail is a RFC3156 encrypted message.\n"
mail.parts.clear
# cryptographic info
p_pgp = TMail::Mail.new
p_pgp.set_content_type("application", "pgp-encrypted")
p_pgp.transfer_encoding = "7bit"
p_pgp.content_disposition = "inline"
p_pgp.body = "Version: 1\n"
mail.parts << p_pgp
# encrypted message
p_encrypted = TMail::Mail.new
p_encrypted.set_content_type("application", "octet-stream")
p_encrypted.transfer_encoding = "7bit"
p_encrypted.content_disposition = "inline"
p_encrypted.body = encrypted_data
mail.parts << p_encrypted
# store the calculated content, to be able to use parsing methods
mail.write_back
mail
end
def create_signed(signers_id)
data = build_intermediate_mail()
sign_data = data.pgp_sign(signers_id) do |uid_hint, passphrase_info, prev_was_bad|
yield(uid_hint, passphrase_info, prev_was_bad)
end
# build properly signed mail
# (preserving headers from original mail)
mail = TMail::Mail.new
mail.copy_headers_from(self)
mail.set_content_type("multipart", "signed", {'boundary' => TMail.new_boundary, 'protocol' => "application/pgp-signature", 'micalg' => sign_data[:micalg]})
mail.transfer_encoding = "7bit"
mail['content-disposition'] = nil
mail.body = "This mail is a RFC3156 signed message.\n"
mail.parts.clear
# signed message
p_signed = data
mail.parts << p_signed
# signature
p_signature = TMail::Mail.new
p_signature.set_content_type("application", "pgp-signature")
p_signature.transfer_encoding = "7bit"
p_signature.content_disposition = "inline"
p_signature.body = sign_data[:signature]
mail.parts << p_signature
# store the calculated content, to be able to use parsing methods
mail.write_back
mail
end
def create_signed_and_encrypted(signers_id, crypters_id)
create_signed(signers_id) do |uid_hint, passphrase_info, prev_was_bad|
yield(uid_hint, passphrase_info, prev_was_bad)
end.create_encrypted(crypters_id)
end
def copy_headers_from(mail)
mail.header.keys.each do |h|
self[h] = mail[h].to_s
end
end
protected
def build_intermediate_mail
# build a fake mail to get the generated content to be crypted/signed
fake_mail = TMail::Mail.new
fake_mail['content-type'] = self['content-type'].to_s
fake_mail.transfer_encoding = self.transfer_encoding if self.transfer_encoding
fake_mail.content_disposition = self.content_disposition if self.content_disposition
if self.multipart?
self.each_part {|p| fake_mail.parts << p }
else
fake_mail.body = self.body
end
# store the calculated content, to be able to use parsing methods
fake_mail.write_back
fake_mail
end
def gpg_key(fingerprint, secret = false)
gpg = GPGME::Ctx.new
gpg.get_key(fingerprint, secret)

Also available in: Unified diff