1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/parsers/pgp.py Wed Jul 10 16:11:18 2013 +0200
1.3 @@ -0,0 +1,127 @@
1.4 +# -*- coding: iso-8859-1 -*-
1.5 +"""
1.6 + MoinMoin - pgp (MoinMessage)
1.7 +
1.8 + @copyright: 2012, 2013 by Paul Boddie <paul@boddie.org.uk>
1.9 + @license: GNU GPL (v2 or later), see COPYING.txt for details.
1.10 +"""
1.11 +
1.12 +from MoinSupport import parseAttributes
1.13 +from MoinMessage import GPG, is_signed, is_encrypted, \
1.14 + MoinMessageDecodingError, MoinMessageError
1.15 +from MoinMessageSupport import get_homedir
1.16 +import email.parser
1.17 +
1.18 +try:
1.19 + from cStringIO import StringIO
1.20 +except ImportError:
1.21 + from StringIO import StringIO
1.22 +
1.23 +Dependencies = ["pages"]
1.24 +
1.25 +# Parser support.
1.26 +
1.27 +class Parser:
1.28 +
1.29 + """
1.30 + Extract information from PGP-encrypted content, subject to key availability.
1.31 + """
1.32 +
1.33 + Dependencies = Dependencies
1.34 + extensions = []
1.35 +
1.36 + # Input content types understood by this parser.
1.37 +
1.38 + input_mimetypes = ["multipart/encrypted"]
1.39 +
1.40 + # Output content types preferred by this parser.
1.41 +
1.42 + output_mimetypes = []
1.43 +
1.44 + def __init__(self, raw, request, **kw):
1.45 +
1.46 + """
1.47 + Initialise the parser with the given 'raw' data, 'request' and any
1.48 + keyword arguments that may have been supplied.
1.49 + """
1.50 +
1.51 + self.raw = raw
1.52 + self.request = request
1.53 + attrs = parseAttributes(kw.get("format_args", ""), False)
1.54 +
1.55 + self.fragment = attrs.get("fragment")
1.56 +
1.57 + def _decrypt(self, text):
1.58 +
1.59 + "Decrypt the content."
1.60 +
1.61 + homedir = get_homedir(self.request)
1.62 + gpg = GPG(homedir)
1.63 +
1.64 + # Obtain a message from the text.
1.65 +
1.66 + message = email.parser.Parser().parse(StringIO(text))
1.67 +
1.68 + # Decrypt the message.
1.69 +
1.70 + if is_encrypted(message):
1.71 + message_text = gpg.decryptMessage(message)
1.72 + message = email.parser.Parser().parse(StringIO(message_text))
1.73 +
1.74 + # Extract any signature details.
1.75 +
1.76 + if is_signed(message):
1.77 + result = gpg.verifyMessage(message)
1.78 + if result:
1.79 + return result
1.80 + else:
1.81 + return None, None, message
1.82 +
1.83 + def _decode(self, part):
1.84 +
1.85 + "Decode the given 'part'."
1.86 +
1.87 + charset = part.get_content_charset()
1.88 + payload = part.get_payload(decode=True)
1.89 + return charset and unicode(payload, charset) or payload
1.90 +
1.91 + def format(self, fmt, write=None):
1.92 +
1.93 + """
1.94 + Format content using the given formatter 'fmt'. If the 'write'
1.95 + parameter is specified, use it to write output; otherwise, write output
1.96 + using the request.
1.97 + """
1.98 +
1.99 + write = write or self.request.write
1.100 +
1.101 + try:
1.102 + fingerprint, identity, content = self._decrypt(self.raw)
1.103 + write(fmt.text(self._decode(content)))
1.104 +
1.105 + except MoinMessageDecodingError:
1.106 + write(fmt.text(_("Encrypted content was improperly encoded.")))
1.107 +
1.108 + except MoinMessageError:
1.109 + write(fmt.text(_("Encrypted content could not be decrypted/verified.")))
1.110 +
1.111 + # Extra API methods.
1.112 +
1.113 + def formatForOutputType(self, mimetype, write=None):
1.114 +
1.115 + """
1.116 + Format content for the given 'mimetype'. If the 'write' parameter is
1.117 + specified, use it to write output; otherwise, write output using the
1.118 + request.
1.119 + """
1.120 +
1.121 + self.format(self.request.html_formatter, write)
1.122 +
1.123 + # Class methods.
1.124 +
1.125 + def getOutputTypes(self):
1.126 + return self.output_mimetypes
1.127 +
1.128 + getOutputTypes = classmethod(getOutputTypes)
1.129 +
1.130 +# vim: tabstop=4 expandtab shiftwidth=4