summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordrebs <drebs@leap.se>2013-11-11 18:18:45 -0200
committerdrebs <drebs@leap.se>2013-11-11 18:19:07 -0200
commit1ab414618aeba7c3b6f3f765e074fff35011229f (patch)
tree45bf3fbb1d023029e1c2bf7a242a86327b21f7ed
parent04bd32160ffdb7cd96354dd25be1777c6970c832 (diff)
Correcly handle message headers when gatewaying. Closes #4322 and #4447.
-rw-r--r--mail/changes/feature_4447-4322-fix-headers-when-gatewaying-messages2
-rw-r--r--mail/src/leap/mail/smtp/gateway.py83
2 files changed, 66 insertions, 19 deletions
diff --git a/mail/changes/feature_4447-4322-fix-headers-when-gatewaying-messages b/mail/changes/feature_4447-4322-fix-headers-when-gatewaying-messages
new file mode 100644
index 00000000..986937cc
--- /dev/null
+++ b/mail/changes/feature_4447-4322-fix-headers-when-gatewaying-messages
@@ -0,0 +1,2 @@
+ o Correctly handle email headers when gatewaying messages. Also add
+ OpenPGP header. Closes #4322 and #4447.
diff --git a/mail/src/leap/mail/smtp/gateway.py b/mail/src/leap/mail/smtp/gateway.py
index f6366afa..f09ee141 100644
--- a/mail/src/leap/mail/smtp/gateway.py
+++ b/mail/src/leap/mail/smtp/gateway.py
@@ -210,8 +210,6 @@ class SMTPDelivery(object):
"""
self._userid = userid
self._km = keymanager
- self._userid = userid
- self._km = keymanager
self._host = host
self._port = port
self._cert = cert
@@ -236,10 +234,10 @@ class SMTPDelivery(object):
:type: str
"""
myHostname, clientIP = helo
- headerValue = "by %s from %s with ESMTP ; %s" % (
- myHostname, clientIP, smtp.rfc822date())
+ headerValue = "by bitmask.local from %s with ESMTP ; %s" % (
+ clientIP, smtp.rfc822date())
# email.Header.Header used for automatic wrapping of long lines
- return "Received: %s" % Header(headerValue)
+ return "Received: %s" % Header(s=headerValue, header_name='Received')
def validateTo(self, user):
"""
@@ -328,16 +326,6 @@ class SSLContextFactory(ssl.ClientContextFactory):
return ctx
-def move_headers(origmsg, newmsg):
- headers = origmsg.items()
- unwanted_headers = ['content-type', 'mime-version', 'content-disposition',
- 'content-transfer-encoding']
- headers = filter(lambda x: x[0].lower() not in unwanted_headers, headers)
- for hkey, hval in headers:
- newmsg.add_header(hkey, hval)
- del(origmsg[hkey])
-
-
class EncryptedMessage(object):
"""
Receive plaintext from client, encrypt it and send message to a
@@ -518,14 +506,14 @@ class EncryptedMessage(object):
C{pubkey} to encrypt and C{signkey} to sign.
:param pubkey: The public key used to encrypt the message.
- :type pubkey: leap.common.keymanager.openpgp.OpenPGPKey
+ :type pubkey: OpenPGPKey
:param signkey: The private key used to sign the message.
- :type signkey: leap.common.keymanager.openpgp.OpenPGPKey
+ :type signkey: OpenPGPKey
"""
# create new multipart/encrypted message with 'pgp-encrypted' protocol
newmsg = MultipartEncrypted('application/pgp-encrypted')
# move (almost) all headers from original message to the new message
- move_headers(self._origmsg, newmsg)
+ self._fix_headers(self._origmsg, newmsg, signkey)
# create 'application/octet-stream' encrypted message
encmsg = MIMEApplication(
self._km.encrypt(self._origmsg.as_string(unixfrom=False), pubkey,
@@ -551,7 +539,7 @@ class EncryptedMessage(object):
# create new multipart/signed message
newmsg = MultipartSigned('application/pgp-signature', 'pgp-sha512')
# move (almost) all headers from original message to the new message
- move_headers(self._origmsg, newmsg)
+ self._fix_headers(self._origmsg, newmsg, signkey)
# apply base64 content-transfer-encoding
encode_base64_rec(self._origmsg)
# get message text with headers and replace \n for \r\n
@@ -630,3 +618,60 @@ class EncryptedMessage(object):
signal(proto.SMTP_START_SIGN, self._fromAddress.addrstr)
self._sign(signkey)
signal(proto.SMTP_END_SIGN, self._fromAddress.addrstr)
+
+ def _fix_headers(self, origmsg, newmsg, signkey):
+ """
+ Move some headers from C{origmsg} to C{newmsg}, delete unwanted
+ headers from C{origmsg} and add new headers to C{newms}.
+
+ Outgoing messages are either encrypted and signed or just signed
+ before being sent. Because of that, they are packed inside new
+ messages and some manipulation has to be made on their headers.
+
+ Allowed headers for passing through:
+
+ - From
+ - Date
+ - To
+ - Subject
+ - Reply-To
+ - References
+ - In-Reply-To
+ - Cc
+
+ Headers to be added:
+
+ - Message-ID (i.e. should not use origmsg's Message-Id)
+ - Received (this is added automatically by twisted smtp API)
+ - OpenPGP (see #4447)
+
+ Headers to be deleted:
+
+ - User-Agent
+
+ :param origmsg: The original message.
+ :type origmsg: email.message.Message
+ :param newmsg: The new message being created.
+ :type newmsg: email.message.Message
+ :param signkey: The key used to sign C{newmsg}
+ :type signkey: OpenPGPKey
+ """
+ # move headers from origmsg to newmsg
+ headers = origmsg.items()
+ passthrough = [
+ 'from', 'date', 'to', 'subject', 'reply-to', 'references',
+ 'in-reply-to', 'cc'
+ ]
+ headers = filter(lambda x: x[0].lower() in passthrough, headers)
+ for hkey, hval in headers:
+ newmsg.add_header(hkey, hval)
+ del(origmsg[hkey])
+ # add a new message-id to newmsg
+ newmsg.add_header('Message-Id', smtp.messageid())
+ # add openpgp header to newmsg
+ username, domain = signkey.address.split('@')
+ newmsg.add_header(
+ 'OpenPGP', 'id=%s' % signkey.key_id,
+ url='https://%s/openpgp/%s' % (domain, username))
+ # delete user-agent from origmsg
+ del(origmsg['user-agent'])