diff options
author | Kali Kaneko <kali@leap.se> | 2016-04-25 21:16:02 -0400 |
---|---|---|
committer | Kali Kaneko <kali@leap.se> | 2016-04-25 21:16:02 -0400 |
commit | f2740a79d9da0fbe1ac1c205173d78cc30479950 (patch) | |
tree | f9c76cfc60748152121a0dd64e1ee4e630fa6c41 /src/leap/mail/incoming/service.py | |
parent | 7d0adc5be4f1b3a0e25b91c011b91a7f8e55a8c6 (diff) | |
parent | d6f260f85f8464c6db6b9e158ecc85cfc02761ac (diff) |
Merge tag '0.4.1' into debian/experimental
Tag version 0.4.1
Diffstat (limited to 'src/leap/mail/incoming/service.py')
-rw-r--r-- | src/leap/mail/incoming/service.py | 74 |
1 files changed, 58 insertions, 16 deletions
diff --git a/src/leap/mail/incoming/service.py b/src/leap/mail/incoming/service.py index d8b91ba..c7d194d 100644 --- a/src/leap/mail/incoming/service.py +++ b/src/leap/mail/incoming/service.py @@ -24,7 +24,6 @@ import time import warnings from email.parser import Parser -from email.generator import Generator from email.utils import parseaddr from email.utils import formatdate from StringIO import StringIO @@ -43,6 +42,7 @@ from leap.common.mail import get_email_charset from leap.keymanager import errors as keymanager_errors from leap.keymanager.openpgp import OpenPGPKey from leap.mail.adaptors import soledad_indexes as fields +from leap.mail.generator import Generator from leap.mail.utils import json_loads, empty from leap.soledad.client import Soledad from leap.soledad.common.crypto import ENC_SCHEME_KEY, ENC_JSON_KEY @@ -233,7 +233,7 @@ class IncomingMail(Service): failure.trap(InvalidAuthTokenError) # if the token is invalid, send an event so the GUI can # disable mail and show an error message. - emit_async(catalog.SOLEDAD_INVALID_AUTH_TOKEN) + emit_async(catalog.SOLEDAD_INVALID_AUTH_TOKEN, self._userid) log.msg('FETCH: syncing soledad...') d = self._soledad.sync() @@ -254,7 +254,7 @@ class IncomingMail(Service): num_mails = len(doclist) if doclist is not None else 0 if num_mails != 0: log.msg("there are %s mails" % (num_mails,)) - emit_async(catalog.MAIL_FETCHED_INCOMING, + emit_async(catalog.MAIL_FETCHED_INCOMING, self._userid, str(num_mails), str(fetched_ts)) return doclist @@ -262,7 +262,7 @@ class IncomingMail(Service): """ Sends unread event to ui. """ - emit_async(catalog.MAIL_UNREAD_MESSAGES, + emit_async(catalog.MAIL_UNREAD_MESSAGES, self._userid, str(self._inbox_collection.count_unseen())) # process incoming mail. @@ -286,7 +286,7 @@ class IncomingMail(Service): deferreds = [] for index, doc in enumerate(doclist): logger.debug("processing doc %d of %d" % (index + 1, num_mails)) - emit_async(catalog.MAIL_MSG_PROCESSING, + emit_async(catalog.MAIL_MSG_PROCESSING, self._userid, str(index), str(num_mails)) keys = doc.content.keys() @@ -336,7 +336,8 @@ class IncomingMail(Service): decrdata = "" success = False - emit_async(catalog.MAIL_MSG_DECRYPTED, "1" if success else "0") + emit_async(catalog.MAIL_MSG_DECRYPTED, self._userid, + "1" if success else "0") return self._process_decrypted_doc(doc, decrdata) d = self._keymanager.decrypt( @@ -393,7 +394,7 @@ class IncomingMail(Service): # ok, this is an incoming message rawmsg = msg.get(self.CONTENT_KEY, None) - if not rawmsg: + if rawmsg is None: return "" return self._maybe_decrypt_msg(rawmsg) @@ -439,6 +440,7 @@ class IncomingMail(Service): fromHeader = msg.get('from', None) senderAddress = None + if (fromHeader is not None and (msg.get_content_type() == MULTIPART_ENCRYPTED or msg.get_content_type() == MULTIPART_SIGNED)): @@ -459,12 +461,14 @@ class IncomingMail(Service): decrmsg.add_header( self.LEAP_SIGNATURE_HEADER, self.LEAP_SIGNATURE_VALID, - pubkey=signkey.key_id) + pubkey=signkey.fingerprint) return decrmsg.as_string() if msg.get_content_type() == MULTIPART_ENCRYPTED: d = self._decrypt_multipart_encrypted_msg( msg, encoding, senderAddress) + elif msg.get_content_type() == MULTIPART_SIGNED: + d = self._verify_signature_not_encrypted_msg(msg, senderAddress) else: d = self._maybe_decrypt_inline_encrypted_msg( msg, encoding, senderAddress) @@ -544,11 +548,8 @@ class IncomingMail(Service): :rtype: Deferred """ log.msg('maybe decrypting inline encrypted msg') - # serialize the original message - buf = StringIO() - g = Generator(buf) - g.flatten(origmsg) - data = buf.getvalue() + + data = self._serialize_msg(origmsg) def decrypted_data(res): decrdata, signkey = res @@ -577,6 +578,46 @@ class IncomingMail(Service): d.addCallback(encode_and_return) return d + def _verify_signature_not_encrypted_msg(self, origmsg, sender_address): + """ + Possibly decrypt an inline OpenPGP encrypted message. + + :param origmsg: The original, possibly encrypted message. + :type origmsg: Message + :param sender_address: The email address of the sender of the message. + :type sender_address: str + + :return: A Deferred that will be fired with a tuple containing a + signed Message and the signing OpenPGPKey if the signature + is valid or InvalidSignature. + :rtype: Deferred + """ + msg = copy.deepcopy(origmsg) + data = self._serialize_msg(msg.get_payload(0)) + detached_sig = self._extract_signature(msg) + d = self._keymanager.verify(data, sender_address, OpenPGPKey, + detached_sig) + + d.addCallback(lambda sign_key: (msg, sign_key)) + d.addErrback(lambda _: (msg, keymanager_errors.InvalidSignature())) + return d + + def _serialize_msg(self, origmsg): + buf = StringIO() + g = Generator(buf) + g.flatten(origmsg) + return buf.getvalue() + + def _extract_signature(self, msg): + body = msg.get_payload(0).get_payload() + + if isinstance(body, str): + body = msg.get_payload(0) + + detached_sig = msg.get_payload(1).get_payload() + msg.set_payload(body) + return detached_sig + def _decryption_error(self, failure, msg): """ Check for known decryption errors @@ -708,7 +749,7 @@ class IncomingMail(Service): for attachment in attachments: if MIME_KEY == attachment.get_content_type(): d = self._keymanager.put_raw_key( - attachment.get_payload(), + attachment.get_payload(decode=True), OpenPGPKey, address=address) d.addCallbacks(log_key_added, failed_put_key) @@ -743,10 +784,11 @@ class IncomingMail(Service): listener(result) def signal_deleted(doc_id): - emit_async(catalog.MAIL_MSG_DELETED_INCOMING) + emit_async(catalog.MAIL_MSG_DELETED_INCOMING, + self._userid) return doc_id - emit_async(catalog.MAIL_MSG_SAVED_LOCALLY) + emit_async(catalog.MAIL_MSG_SAVED_LOCALLY, self._userid) d = self._delete_incoming_message(doc) d.addCallback(signal_deleted) return d |