From 1c3b8d861db49ee723a7470301a63a8ca2994f5c Mon Sep 17 00:00:00 2001
From: Giovane <giovaneliberato@gmail.com>
Date: Thu, 21 Jan 2016 16:31:14 -0200
Subject: [feat] Validate signature with attachments

- Create a new Generator that doesn't trim the headers
- Extract detached signature from message
- Convert message to the body an attachments level
- Add coment to the generator workaround and shows which python version
  has the patch
---
 src/leap/mail/generator.py        | 21 +++++++++++++++++++++
 src/leap/mail/incoming/service.py | 25 ++++++++++++++++++-------
 2 files changed, 39 insertions(+), 7 deletions(-)
 create mode 100644 src/leap/mail/generator.py

(limited to 'src/leap')

diff --git a/src/leap/mail/generator.py b/src/leap/mail/generator.py
new file mode 100644
index 0000000..28db8da
--- /dev/null
+++ b/src/leap/mail/generator.py
@@ -0,0 +1,21 @@
+from email.generator import Generator as EmailGenerator
+
+class Generator(EmailGenerator):
+    """
+    Generates output from a Message object tree, keeping signatures.
+
+    This code was extracted from Mailman.Generator.Generator, version 2.1.4:
+
+    Most other Generator will be created not setting the foldheader flag,
+    as we do not overwrite clone(). The original clone() does not
+    set foldheaders.
+
+    So you need to set foldheaders if you want the toplevel to fold headers
+
+    TODO: Python 3.3 is patched against this problems. See issue 1590744 on python bug tracker.
+    """
+    def _write_headers(self, msg):
+        for h, v in msg.items():
+            print >> self._fp, '%s:' % h,
+            print >> self._fp, v
+        print >> self._fp
diff --git a/src/leap/mail/incoming/service.py b/src/leap/mail/incoming/service.py
index 1716816..49bca50 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
@@ -394,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)
 
@@ -525,8 +525,8 @@ class IncomingMail(Service):
             return (msg, signkey)
 
         d = self._keymanager.decrypt(
-                encdata, self._userid, OpenPGPKey,
-                verify=senderAddress)
+            encdata, self._userid, OpenPGPKey,
+            verify=senderAddress)
         d.addCallbacks(build_msg, self._decryption_error, errbackArgs=(msg,))
         return d
 
@@ -593,9 +593,10 @@ class IncomingMail(Service):
         :rtype: Deferred
         """
         msg = copy.deepcopy(origmsg)
-        data = msg.get_payload()[0].as_string()
-        detached_sig = msg.get_payload()[1].get_payload()
-        d = self._keymanager.verify(data, sender_address, OpenPGPKey, detached_sig)
+        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()))
@@ -607,6 +608,16 @@ class IncomingMail(Service):
         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
-- 
cgit v1.2.3