# HG changeset patch # User Paul Boddie # Date 1342828876 -7200 # Node ID cec8772ca71790309e33c12744152d581bde2a69 # Parent b2c12a4f84db38b657bef96fd0cb353252bc01a4 Added handling of PGP/GPG-encrypted messages. Split the tests into separate scripts that prepare and send messages, with gpg usage required to encrypt the initial message before sending. diff -r b2c12a4f84db -r cec8772ca717 actions/PostMessage.py --- a/actions/PostMessage.py Fri Jul 20 21:58:47 2012 +0200 +++ b/actions/PostMessage.py Sat Jul 21 02:01:16 2012 +0200 @@ -9,6 +9,7 @@ from MoinMoin.PageEditor import PageEditor from MoinSupport import * from email.parser import Parser +import os try: from cStringIO import StringIO @@ -41,6 +42,71 @@ # Get the message. message_text = StringIO(request.read(content_length)) + self.handle_message(message_text) + + def handle_message(self, message_text): + + "Handle the given 'message_text'." + + request = self.request + message = Parser().parse(message_text) + mimetype = message.get_content_type() + encoding = message.get_content_charset() + + # Detect PGP/GPG-encoded payloads. + # See: http://tools.ietf.org/html/rfc3156 + + if mimetype == "multipart/encrypted" and \ + message.get_param("protocol") == "application/pgp-encrypted": + + try: + declaration, part = message.get_payload() + except ValueError: + writeHeaders(request, "text/plain", getMetadata(self.page), "415 Unsupported Media Type") + request.write("There must be a declaration and a content part for signed uploads.") + return + + # Verify the message format. + + if part.get_content_type() != "application/octet-stream": + writeHeaders(request, "text/plain", getMetadata(self.page), "415 Unsupported Media Type") + request.write("Encrypted data must be provided as application/octet-stream.") + return + + # Locate the keyring. + + homedir = getattr(request.cfg, "postmessage_gpg_homedir") + if not homedir: + writeHeaders(request, "text/plain", getMetadata(self.page), "415 Unsupported Media Type") + request.write("Encrypted data cannot currently be understood. Please notify the site administrator.") + return + + # Decrypt the message text. + + to_child, from_child, error_child = os.popen3(["gpg", "--no-default-keyring", "--homedir", homedir, "--decrypt"]) + to_child.write(part.get_payload()) + to_child.close() + #print >>open("/tmp/log.txt", "a"), error_child.read() + + # Handle the embedded message. + + try: + self.handle_plaintext_message(from_child) + finally: + from_child.close() + error_child.close() + + # Reject unsigned payloads. + + else: + writeHeaders(request, "text/plain", getMetadata(self.page), "415 Unsupported Media Type") + request.write("Only PGP/GPG-signed payloads are supported.") + + def handle_plaintext_message(self, message_text): + + "Handle the given 'message_text'." + + request = self.request message = Parser().parse(message_text) # Handle a single part. @@ -83,7 +149,8 @@ body = [] for part in parts: - mimetype, encoding = getContentTypeAndEncoding(part.get("Content-Type")) + mimetype = part.get_content_type() + encoding = part.get_content_charset() if mimetype == "text/moin": body.append(part.get_payload()) if replace: diff -r b2c12a4f84db -r cec8772ca717 tests/test_message.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test_message.py Sat Jul 21 02:01:16 2012 +0200 @@ -0,0 +1,19 @@ +#!/usr/bin/env python + +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText + +if __name__ == "__main__": + message = MIMEMultipart() + + text1 = MIMEText("An update to the Wiki.", "moin") + + text2 = MIMEText("Another update to the Wiki.", "moin") + + message.attach(text1) + message.attach(text2) + + text = message.as_string() + print text + +# vim: tabstop=4 expandtab shiftwidth=4 diff -r b2c12a4f84db -r cec8772ca717 tests/test_post.py --- a/tests/test_post.py Fri Jul 20 21:58:47 2012 +0200 +++ b/tests/test_post.py Sat Jul 21 02:01:16 2012 +0200 @@ -1,24 +1,28 @@ #!/usr/bin/env python from email.mime.multipart import MIMEMultipart -from email.mime.text import MIMEText +from email.mime.application import MIMEApplication +from email.mime.base import MIMEBase +from email.encoders import encode_noop import httplib import sys if __name__ == "__main__": host = sys.argv[1] path = sys.argv[2] + "?action=PostMessage" + text = sys.stdin.read() - message = MIMEMultipart() - - text1 = MIMEText("An update to the Wiki.", "moin") + message = MIMEMultipart("encrypted", protocol="application/pgp-encrypted") - text2 = MIMEText("Another update to the Wiki.", "moin") + declaration = MIMEBase("application", "pgp-encrypted") + declaration.set_payload("Version: 1") + message.attach(declaration) - message.attach(text1) - message.attach(text2) + content = MIMEApplication(text, "octet-stream", encode_noop) + message.attach(content) text = message.as_string() + print text print