Skip to content

Commit

Permalink
Fixed bug in 3.12.6+ after [CVE-2023-27043]
Browse files Browse the repository at this point in the history
  • Loading branch information
ikvk committed Oct 4, 2024
1 parent 967408f commit 017208a
Show file tree
Hide file tree
Showing 5 changed files with 24 additions and 5 deletions.
3 changes: 2 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,8 @@ Big thanks to people who helped develop this library:
`meetttttt <https://github.com/meetttttt>`_,
`sapristi <https://github.com/sapristi>`_,
`thomwiggers <https://github.com/thomwiggers>`_,
`histogal <https://github.com/histogal>`_
`histogal <https://github.com/histogal>`_,
`K900 <https://github.com/K900>`_

Help the project
----------------
Expand Down
4 changes: 4 additions & 0 deletions docs/release_notes.rst
Original file line number Diff line number Diff line change
@@ -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
Expand Down
2 changes: 1 addition & 1 deletion imap_tools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@
from .utils import EmailAddress
from .errors import *

__version__ = '1.7.2'
__version__ = '1.7.3'
7 changes: 6 additions & 1 deletion imap_tools/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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):
Expand Down
13 changes: 11 additions & 2 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -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')
Expand Down Expand Up @@ -149,7 +159,6 @@ def test_replace_html_ct_charset(self):
</head>
"""
res1 = replace_html_ct_charset(data1, 'utf-8')
print(res1)
self.assertIn(target, res1)
self.assertTrue(res1.count(target) == 1)

Expand Down

0 comments on commit 017208a

Please sign in to comment.