# HG changeset patch # User Paul Boddie # Date 1389282725 -3600 # Node ID 32695db2924f70fc2ef1777fb069884e20d603fe # Parent 5798c36178755fc40116f408f8b789df3da98d45 Introduced an "idempotent" serialisation function for messages. Removed the representation-insensitive wrapping of signed content. Fixed the verification test to decode signature parts, should this ever be necessary. diff -r 5798c3617875 -r 32695db2924f MoinMessage.py --- a/MoinMessage.py Wed Jan 08 01:55:57 2014 +0100 +++ b/MoinMessage.py Thu Jan 09 16:52:05 2014 +0100 @@ -8,6 +8,7 @@ from email import message_from_string from email.encoders import encode_noop +from email.generator import Generator from email.mime.multipart import MIMEMultipart from email.mime.application import MIMEApplication from email.mime.base import MIMEBase @@ -20,6 +21,11 @@ import httplib import os +try: + from cStringIO import StringIO +except ImportError: + from StringIO import StringIO + def is_collection(message): return message.get("Update-Type") == "collection" @@ -279,8 +285,8 @@ # Verify the message. - fingerprint, identity = self.verifyMessageText(signature.get_payload(decode=True), content.as_string()) - return fingerprint, identity, getOriginalContent(content) + fingerprint, identity = self.verifyMessageText(signature.get_payload(decode=True), as_string(content)) + return fingerprint, identity, content def signMessage(self, message, keyid): @@ -288,18 +294,14 @@ Return a signed version of 'message' using the given 'keyid'. """ - # Make a representation-insensitive container for the message. - - content = MIMEApplication(message.as_string()) - # Sign the container's representation. - signature = self.run(["--armor", "-u", keyid, "--detach-sig"], content.as_string()) + signature = self.run(["--armor", "-u", keyid, "--detach-sig"], as_string(message)) # Make the container for the message. signed_message = MIMEMultipart("signed", protocol="application/pgp-signature") - signed_message.attach(content) + signed_message.attach(message) signature_part = MIMEBase("application", "pgp-signature") signature_part.set_payload(signature) @@ -339,7 +341,7 @@ Return an encrypted version of 'message' using the given 'keyid'. """ - text = message.as_string() + text = as_string(message) encrypted = self.run(["--armor", "-r", keyid, "--encrypt", "--trust-model", "always"], text) # Make the container for the message. @@ -450,6 +452,20 @@ return keys +# Message serialisation functions, working around email module problems. + +def as_string(message): + + """ + Return the string representation of 'message', attempting to preserve the + precise original formatting. + """ + + out = StringIO() + generator = Generator(out, False, 0) # disable reformatting measures + generator.flatten(message) + return out.getvalue() + # Message decoding functions. # Detect PGP/GPG-encoded payloads. @@ -486,15 +502,6 @@ except ValueError: raise MoinMessageMissingPart -def getOriginalContent(content): - - """ - Extract the actual content inside the signed message. This reverses the - wrapping up of signed content in a representation-insensitive container. - """ - - return Parser().parsestr(content.get_payload(decode=True)) - # Communications functions. def timestamp(message): @@ -530,7 +537,7 @@ """ scheme, host, port, path = parseURL(url) - text = message.as_string() + text = as_string(message) req = _getConnection(scheme)(host, port) req.request(method, path, text) diff -r 5798c3617875 -r 32695db2924f MoinMessageSupport.py --- a/MoinMessageSupport.py Wed Jan 08 01:55:57 2014 +0100 +++ b/MoinMessageSupport.py Thu Jan 09 16:52:05 2014 +0100 @@ -16,8 +16,7 @@ from TokenSupport import getIdentifiers from MoinMessage import GPG, Message, MoinMessageError, \ MoinMessageMissingPart, MoinMessageBadContent, \ - is_signed, is_encrypted, getContentAndSignature, \ - getOriginalContent + is_signed, is_encrypted, getContentAndSignature from email.parser import Parser import time @@ -167,7 +166,7 @@ # Handle the embedded message. content, signature = getContentAndSignature(message) - self.handle_message_content(getOriginalContent(content)) + self.handle_message_content(content) # Reject any unverified message. diff -r 5798c3617875 -r 32695db2924f README.txt --- a/README.txt Wed Jan 08 01:55:57 2014 +0100 +++ b/README.txt Thu Jan 09 16:52:05 2014 +0100 @@ -342,7 +342,6 @@ python tests/test_message.py collection update 'An update to the wiki.' \ 'Another update.' \ -| python tests/test_message_wrap.py \ > test.txt \ && cat test.txt \ | gpg --armor -u 1C1AAF83 --detach-sig \ diff -r 5798c3617875 -r 32695db2924f actions/PostMessage.py --- a/actions/PostMessage.py Wed Jan 08 01:55:57 2014 +0100 +++ b/actions/PostMessage.py Thu Jan 09 16:52:05 2014 +0100 @@ -2,14 +2,15 @@ """ MoinMoin - PostMessage Action - @copyright: 2012, 2013 by Paul Boddie + @copyright: 2012, 2013, 2014 by Paul Boddie @license: GNU GPL (v2 or later), see COPYING.txt for details. """ from MoinMoin.Page import Page from MoinMoin.PageEditor import PageEditor from MoinSupport import getMetadata, writeHeaders -from MoinMessage import is_collection, to_replace, to_store, get_update_action +from MoinMessage import is_collection, to_replace, to_store, get_update_action, \ + as_string from MoinMessageSupport import MoinMessageAction Dependencies = ['pages'] @@ -83,7 +84,7 @@ if message.date: update["Date"] = message.date.as_RFC2822_datetime_string() - self.store.append(update.as_string()) + self.store.append(as_string(update)) # Update the page. diff -r 5798c3617875 -r 32695db2924f actions/SendMessage.py --- a/actions/SendMessage.py Wed Jan 08 01:55:57 2014 +0100 +++ b/actions/SendMessage.py Thu Jan 09 16:52:05 2014 +0100 @@ -2,7 +2,7 @@ """ MoinMoin - SendMessage Action - @copyright: 2012, 2013 by Paul Boddie + @copyright: 2012, 2013, 2014 by Paul Boddie @license: GNU GPL (v2 or later), see COPYING.txt for details. """ @@ -11,7 +11,8 @@ from MoinMoin.log import getLogger from MoinMoin.Page import Page from MoinMoin import config -from MoinMessage import GPG, MoinMessageError, Message, sendMessage, timestamp +from MoinMessage import GPG, MoinMessageError, Message, sendMessage, timestamp, \ + as_string from MoinMessageSupport import get_signing_users, get_recipients, get_relays, \ get_recipient_details, MoinMessageRecipientError from MoinSupport import * @@ -330,13 +331,13 @@ elif type == "page": page = Page(request, location) outbox = ItemStore(page, "messages", "message-locks") - outbox.append(message.as_string()) + outbox.append(as_string(message)) # Or queue the message in a special outbox. else: outbox = ItemStore(request.page, "outgoing-messages", "outgoing-message-locks") - outbox.append(message.as_string()) + outbox.append(as_string(message)) return 1, _("Message sent!") diff -r 5798c3617875 -r 32695db2924f tests/test_message_wrap.py --- a/tests/test_message_wrap.py Wed Jan 08 01:55:57 2014 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -#!/usr/bin/env python - -from email.mime.application import MIMEApplication -import sys - -if __name__ == "__main__": - text = sys.stdin.read() - - # Make a representation-insensitive container for the message. - - content = MIMEApplication(text) - - # Show the resulting message text. - - text = content.as_string() - - print text - -# vim: tabstop=4 expandtab shiftwidth=4 diff -r 5798c3617875 -r 32695db2924f tests/test_sign_wrap.py --- a/tests/test_sign_wrap.py Wed Jan 08 01:55:57 2014 +0100 +++ b/tests/test_sign_wrap.py Thu Jan 09 16:52:05 2014 +0100 @@ -4,6 +4,7 @@ from email.mime.application import MIMEApplication from email.mime.base import MIMEBase from email import message_from_string +from MoinMessage import as_string import sys if __name__ == "__main__": @@ -26,7 +27,7 @@ # Show the resulting message text. - text = message.as_string() + text = as_string(message) print text diff -r 5798c3617875 -r 32695db2924f tests/test_verify.py --- a/tests/test_verify.py Wed Jan 08 01:55:57 2014 +0100 +++ b/tests/test_verify.py Thu Jan 09 16:52:05 2014 +0100 @@ -1,6 +1,6 @@ #!/usr/bin/env python -from MoinMessage import GPG +from MoinMessage import GPG, as_string from email.parser import Parser import sys @@ -12,6 +12,6 @@ gpg = GPG(sys.argv[1]) else: gpg = GPG() - print gpg.verifyMessageText(signature.get_payload(), content.as_string()) + print gpg.verifyMessageText(signature.get_payload(decode=True), as_string(content)) # vim: tabstop=4 expandtab shiftwidth=4