From 017208a87d497aae6fe90f6d250a1c786615e241 Mon Sep 17 00:00:00 2001 From: "v.kaukin" Date: Fri, 4 Oct 2024 10:32:50 +0500 Subject: [PATCH] Fixed bug in 3.12.6+ after [CVE-2023-27043] --- README.rst | 3 ++- docs/release_notes.rst | 4 ++++ imap_tools/__init__.py | 2 +- imap_tools/utils.py | 7 ++++++- tests/test_utils.py | 13 +++++++++++-- 5 files changed, 24 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index 296e951..6889b54 100644 --- a/README.rst +++ b/README.rst @@ -418,7 +418,8 @@ Big thanks to people who helped develop this library: `meetttttt `_, `sapristi `_, `thomwiggers `_, -`histogal `_ +`histogal `_, +`K900 `_ Help the project ---------------- diff --git a/docs/release_notes.rst b/docs/release_notes.rst index 2e1f725..6710faa 100644 --- a/docs/release_notes.rst +++ b/docs/release_notes.rst @@ -1,3 +1,7 @@ +1.7.3 +===== +* Fixed: bug in 3.12.6+ after [[3.12] [CVE-2023-27043] gh-102988: Reject malformed addresses in email.parseaddr()] + 1.7.2 ===== * Fixed: MailBoxFolderManager.list double quotes bug diff --git a/imap_tools/__init__.py b/imap_tools/__init__.py index 3829576..879e9e8 100644 --- a/imap_tools/__init__.py +++ b/imap_tools/__init__.py @@ -11,4 +11,4 @@ from .utils import EmailAddress from .errors import * -__version__ = '1.7.2' +__version__ = '1.7.3' diff --git a/imap_tools/utils.py b/imap_tools/utils.py index 6854663..0a78097 100644 --- a/imap_tools/utils.py +++ b/imap_tools/utils.py @@ -78,6 +78,11 @@ def __eq__(self, other): return all(getattr(self, i) == getattr(other, i) for i in self.__slots__) +def remove_non_printable(value: str) -> str: + """Remove non-printable character from value""" + return ''.join(i for i in value if i.isprintable()) + + def parse_email_addresses(raw_header: Union[str, Header]) -> Tuple[EmailAddress, ...]: """ Parse email addresses from header @@ -87,7 +92,7 @@ def parse_email_addresses(raw_header: Union[str, Header]) -> Tuple[EmailAddress, result = [] if type(raw_header) is Header: raw_header = decode_value(*decode_header(raw_header)[0]) - for raw_name, email in getaddresses([raw_header.replace('\r\n', '').replace('\n', '')]): + for raw_name, email in getaddresses([remove_non_printable(raw_header)]): name = decode_value(*decode_header(raw_name)[0]).strip() email = email.strip() if not (name or email): diff --git a/tests/test_utils.py b/tests/test_utils.py index 6cc1c94..870fea6 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,14 +1,24 @@ import unittest import datetime +import unicodedata from imap_tools.errors import ImapToolsError, UnexpectedCommandStatusError, MailboxCopyError from imap_tools.consts import MailMessageFlags from imap_tools.utils import clean_flags, chunks, quote, pairs_to_dict, decode_value, check_command_status, \ - parse_email_date, parse_email_addresses, EmailAddress, clean_uids, replace_html_ct_charset, chunks_crop + parse_email_date, parse_email_addresses, EmailAddress, clean_uids, replace_html_ct_charset, chunks_crop, \ + remove_non_printable class UtilsTest(unittest.TestCase): + def test_remove_non_printable(self): + all_non_printable_chars = [] + for i in range(0x110000): # Диапазон всех кодовых точек Unicode + char = chr(i) + if unicodedata.category(char).startswith('C'): + all_non_printable_chars.append(char) + self.assertEqual(remove_non_printable('123{}'.format(''.join(all_non_printable_chars))), '123') + def test_clean_uids(self): # *clean_uids also implicitly tested in test_query.py self.assertEqual(clean_uids('11'), '11') @@ -149,7 +159,6 @@ def test_replace_html_ct_charset(self): """ res1 = replace_html_ct_charset(data1, 'utf-8') - print(res1) self.assertIn(target, res1) self.assertTrue(res1.count(target) == 1)