1 # -*- coding: iso-8859-1 -*- 2 """ 3 MoinMoin - pgp (MoinMessage) 4 5 @copyright: 2012, 2013 by Paul Boddie <paul@boddie.org.uk> 6 @license: GNU GPL (v2 or later), see COPYING.txt for details. 7 """ 8 9 from MoinSupport import parseAttributes 10 from MoinMessage import GPG, is_signed, is_encrypted, \ 11 MoinMessageDecodingError, MoinMessageError 12 from MoinMessageSupport import get_homedir 13 import email.parser 14 15 try: 16 from cStringIO import StringIO 17 except ImportError: 18 from StringIO import StringIO 19 20 Dependencies = ["pages"] 21 22 # Parser support. 23 24 class Parser: 25 26 """ 27 Extract information from PGP-encrypted content, subject to key availability. 28 """ 29 30 Dependencies = Dependencies 31 extensions = [] 32 33 # Input content types understood by this parser. 34 35 input_mimetypes = ["multipart/encrypted"] 36 37 # Output content types preferred by this parser. 38 39 output_mimetypes = [] 40 41 def __init__(self, raw, request, **kw): 42 43 """ 44 Initialise the parser with the given 'raw' data, 'request' and any 45 keyword arguments that may have been supplied. 46 """ 47 48 self.raw = raw 49 self.request = request 50 attrs = parseAttributes(kw.get("format_args", ""), False) 51 52 self.fragment = attrs.get("fragment") 53 54 def _decrypt(self, text): 55 56 "Decrypt the content." 57 58 homedir = get_homedir(self.request) 59 gpg = GPG(homedir) 60 61 # Obtain a message from the text. 62 63 message = email.parser.Parser().parse(StringIO(text)) 64 65 # Decrypt the message. 66 67 if is_encrypted(message): 68 message_text = gpg.decryptMessage(message) 69 message = email.parser.Parser().parse(StringIO(message_text)) 70 71 # Extract any signature details. 72 73 if is_signed(message): 74 result = gpg.verifyMessage(message) 75 if result: 76 return result 77 else: 78 return None, None, message 79 80 def _decode(self, part): 81 82 "Decode the given 'part'." 83 84 charset = part.get_content_charset() 85 payload = part.get_payload(decode=True) 86 return charset and unicode(payload, charset) or payload 87 88 def format(self, fmt, write=None): 89 90 """ 91 Format content using the given formatter 'fmt'. If the 'write' 92 parameter is specified, use it to write output; otherwise, write output 93 using the request. 94 """ 95 96 write = write or self.request.write 97 98 try: 99 fingerprint, identity, content = self._decrypt(self.raw) 100 write(fmt.text(self._decode(content))) 101 102 except MoinMessageDecodingError: 103 write(fmt.text(_("Encrypted content was improperly encoded."))) 104 105 except MoinMessageError: 106 write(fmt.text(_("Encrypted content could not be decrypted/verified."))) 107 108 # Extra API methods. 109 110 def formatForOutputType(self, mimetype, write=None): 111 112 """ 113 Format content for the given 'mimetype'. If the 'write' parameter is 114 specified, use it to write output; otherwise, write output using the 115 request. 116 """ 117 118 self.format(self.request.html_formatter, write) 119 120 # Class methods. 121 122 def getOutputTypes(self): 123 return self.output_mimetypes 124 125 getOutputTypes = classmethod(getOutputTypes) 126 127 # vim: tabstop=4 expandtab shiftwidth=4