From a8f480f54597cf20e460b12e17bb0416a8008868 Mon Sep 17 00:00:00 2001 From: "R. David Murray" Date: Sat, 16 Jan 2010 18:30:03 +0000 Subject: Merged revisions 77517,77525 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk Merge adds an additional test for as_string with a maxheaderlen specified. ........ r77517 | r.david.murray | 2010-01-16 00:15:17 -0500 (Sat, 16 Jan 2010) | 6 lines Issue #1670765: Prevent email.generator.Generator from re-wrapping headers in multipart/signed MIME parts, which fixes one of the sources of invalid modifications to such parts by Generator. Patch and tests by Martin von Gagern. ........ r77525 | r.david.murray | 2010-01-16 11:08:32 -0500 (Sat, 16 Jan 2010) | 2 lines Fix issue number in comment. ........ --- Lib/email/generator.py | 11 +++++++++++ Lib/email/test/data/msg_45.txt | 33 +++++++++++++++++++++++++++++++++ Lib/email/test/test_email.py | 38 ++++++++++++++++++++++++++++++++++++++ Misc/NEWS | 4 ++++ 4 files changed, 86 insertions(+) create mode 100644 Lib/email/test/data/msg_45.txt diff --git a/Lib/email/generator.py b/Lib/email/generator.py index e821d00..61521b8 100644 --- a/Lib/email/generator.py +++ b/Lib/email/generator.py @@ -215,6 +215,17 @@ class Generator: print(file=self._fp) self._fp.write(msg.epilogue) + def _handle_multipart_signed(self, msg): + # The contents of signed parts has to stay unmodified in order to keep + # the signature intact per RFC1847 2.1, so we disable header wrapping. + # RDM: This isn't enough to completely preserve the part, but it helps. + old_maxheaderlen = self._maxheaderlen + try: + self._maxheaderlen = 0 + self._handle_multipart(msg) + finally: + self._maxheaderlen = old_maxheaderlen + def _handle_message_delivery_status(self, msg): # We can't just write the headers directly to self's file object # because this will leave an extra newline between the last header diff --git a/Lib/email/test/data/msg_45.txt b/Lib/email/test/data/msg_45.txt new file mode 100644 index 0000000..58fde95 --- /dev/null +++ b/Lib/email/test/data/msg_45.txt @@ -0,0 +1,33 @@ +From: +To: +Subject: test +X-Long-Line: Some really long line contains a lot of text and thus has to be rewrapped because it is some + really long + line +MIME-Version: 1.0 +Content-Type: multipart/signed; boundary="borderline"; + protocol="application/pgp-signature"; micalg=pgp-sha1 + +This is an OpenPGP/MIME signed message (RFC 2440 and 3156) +--borderline +Content-Type: text/plain +X-Long-Line: Another really long line contains a lot of text and thus has to be rewrapped because it is another + really long + line + +This is the signed contents. + +--borderline +Content-Type: application/pgp-signature; name="signature.asc" +Content-Description: OpenPGP digital signature +Content-Disposition: attachment; filename="signature.asc" + +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v2.0.6 (GNU/Linux) + +iD8DBQFG03voRhp6o4m9dFsRApSZAKCCAN3IkJlVRg6NvAiMHlvvIuMGPQCeLZtj +FGwfnRHFBFO/S4/DKysm0lI= +=t7+s +-----END PGP SIGNATURE----- + +--borderline-- diff --git a/Lib/email/test/test_email.py b/Lib/email/test/test_email.py index 4ffc8f9..7736412 100644 --- a/Lib/email/test/test_email.py +++ b/Lib/email/test/test_email.py @@ -3387,6 +3387,44 @@ Content-Type: application/x-foo; +# Tests to ensure that signed parts of an email are completely preserved, as +# required by RFC1847 section 2.1. Note that these are incomplete, because the +# email package does not currently always preserve the body. See issue 1670765. +class TestSigned(TestEmailBase): + + def _msg_and_obj(self, filename): + with openfile(findfile(filename)) as fp: + original = fp.read() + msg = email.message_from_string(original) + return original, msg + + def _signed_parts_eq(self, original, result): + # Extract the first mime part of each message + import re + repart = re.compile(r'^--([^\n]+)\n(.*?)\n--\1$', re.S | re.M) + inpart = repart.search(original).group(2) + outpart = repart.search(result).group(2) + self.assertEqual(outpart, inpart) + + def test_long_headers_as_string(self): + original, msg = self._msg_and_obj('msg_45.txt') + result = msg.as_string() + self._signed_parts_eq(original, result) + + def test_long_headers_as_string_maxheaderlen(self): + original, msg = self._msg_and_obj('msg_45.txt') + result = msg.as_string(maxheaderlen=60) + self._signed_parts_eq(original, result) + + def test_long_headers_flatten(self): + original, msg = self._msg_and_obj('msg_45.txt') + fp = StringIO() + Generator(fp).flatten(msg) + result = fp.getvalue() + self._signed_parts_eq(original, result) + + + def _testclasses(): mod = sys.modules[__name__] return [getattr(mod, name) for name in dir(mod) if name.startswith('Test')] diff --git a/Misc/NEWS b/Misc/NEWS index 1339e61..4c08298 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -215,6 +215,10 @@ C-API Library ------- +- Issue #1670765: Prevent email.generator.Generator from re-wrapping + headers in multipart/signed MIME parts, which fixes one of the sources of + invalid modifications to such parts by Generator. + - Issue #7703: Add support for the new buffer API to `binascii.a2bhqx`. Patch by Florent Xicluna, along with some additional tests. -- cgit v0.12