Mark Sapiro pushed to branch master at GNU Mailman / Mailman Core
Commits: 59049e41 by TommyLike Hu at 2021-04-28T18:45:31+00:00 Fix encoding issue in command handler - - - - - b87ca121 by Mark Sapiro at 2021-04-28T18:45:40+00:00 Merge branch 'bug/fix-encoding-issue' into 'master' Fix encoding issue in command handler Closes #858 and #859 See merge request mailman/mailman!822 - - - - - 3 changed files: - src/mailman/docs/NEWS.rst - src/mailman/runners/command.py - src/mailman/runners/tests/test_confirm.py Changes: ===================================== src/mailman/docs/NEWS.rst ===================================== @@ -50,6 +50,10 @@ Bugs says. (Closes #169) * Some exceptions in ARC signing of some posts from HyperKitty and some from prod.outlook.com are now handled without shunting the message. (Closes #885) +* Command runner now will remove all non-ascii characters in the message + subject before processing it.(Closes #858) +* Command runner now will decode the message body before processing it. + (Closes #859) Command line ------------ ===================================== src/mailman/runners/command.py ===================================== @@ -84,7 +84,9 @@ class CommandFinder: try: subject = str(make_header(decode_header(raw_subject))) # Mail commands must be ASCII. - self.command_lines.append(subject.encode('us-ascii')) + # NOTE(tommylikehu): remove all none ascii characters via encoding + # with ignore option. + self.command_lines.append(subject.encode('us-ascii', 'ignore')) except (HeaderParseError, UnicodeError, LookupError): # The Subject header was unparseable or not ASCII. If the raw # subject is a unicode object, convert it to ASCII ignoring all @@ -104,9 +106,11 @@ class CommandFinder: if part is None: # There was no text/plain part to be found. return - body = part.get_payload() + body = part.get_payload(decode=True) # text/plain parts better have string payloads. - assert isinstance(body, (bytes, str)), 'Non-string decoded payload' + assert body is not None, 'Non-text payload' + body = body.decode(part.get_content_charset('us-ascii'), + errors='replace') lines = body.splitlines() # Use no more lines than specified max_lines = int(config.mailman.email_commands_max_lines) ===================================== src/mailman/runners/tests/test_confirm.py ===================================== @@ -17,6 +17,7 @@ """Test the `confirm` command.""" +import base64 import unittest from datetime import datetime @@ -89,6 +90,61 @@ To: test-conf...@example.com address = manager.get_address('a...@example.org') self.assertEqual(address.email, 'a...@example.org') + def test_confirm_with_non_ascii_prefix(self): + confirm_subject = str("confirm {}".format(self._token)) + subject = '=?utf-8?b?5Zue5aSN?= =?utf-8?b?{0}?='.format( + base64.encodebytes(confirm_subject.encode()).decode().rstrip()) + msg = mfs("""\ +From: a...@example.org +To: test-conf...@example.com +""") + msg['Subject'] = subject + self._commandq.enqueue(msg, dict(listid='test.example.com')) + self._runner.run() + # Anne is now a confirmed member so her user record and email address + # should exist in the database. + manager = getUtility(IUserManager) + user = manager.get_user('a...@example.org') + address = list(user.addresses)[0] + self.assertEqual(address.email, 'a...@example.org') + self.assertEqual(address.verified_on, + datetime(2005, 8, 1, 7, 49, 23)) + address = manager.get_address('a...@example.org') + self.assertEqual(address.email, 'a...@example.org') + + def test_confirm_with_base64_encoded_body(self): + # Clear out the virgin queue so that the test below only sees the + # reply to the confirmation message. + mail_content = "hello from mailman fake user" + get_queue_messages('virgin') + subject = 'Re: confirm {}'.format(self._token) + to = 'test-confirm+{}@example.com'.format(self._token) + msg = mfs("""\ +From: Anne Person <a...@example.org> +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: base64 +Content-Disposition: inline + +{} +""".format(base64.encodebytes(mail_content.encode()).decode())) + msg['Subject'] = subject + msg['To'] = to + self._commandq.enqueue(msg, dict(listid='test.example.com')) + self._runner.run() + # Anne is now a confirmed member so her user record and email address + # should exist in the database. + manager = getUtility(IUserManager) + user = manager.get_user('a...@example.org') + address = list(user.addresses)[0] + self.assertEqual(address.email, 'a...@example.org') + address = manager.get_address('a...@example.org') + self.assertEqual(address.email, 'a...@example.org') + items = get_queue_messages('virgin', expected_count=1) + self.assertEqual(items[0].msgdata['recipients'], + set(['a...@example.org'])) + self.assertIn(mail_content, str(items[0].msg)) + def test_confirm_with_folded_to_header(self): # Test that a folded To: header is properly parsed. msg = mfs("""\ View it on GitLab: https://gitlab.com/mailman/mailman/-/compare/af3570376f3e691e70a2a7be656edac8ad288289...b87ca1217402e70d0eceb499c7db97540f746b9e -- View it on GitLab: https://gitlab.com/mailman/mailman/-/compare/af3570376f3e691e70a2a7be656edac8ad288289...b87ca1217402e70d0eceb499c7db97540f746b9e You're receiving this email because of your account on gitlab.com.
_______________________________________________ Mailman-checkins mailing list -- mailman-checkins@python.org To unsubscribe send an email to mailman-checkins-le...@python.org https://mail.python.org/mailman3/lists/mailman-checkins.python.org/ Member address: arch...@jab.org