Revision c0979b3e
Added by Marc Dequènes over 15 years ago
- ID c0979b3eb0412e410e1215171c043eeb29253823
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
[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)