- Modify CVE-2023-27043-email-parsing-errors.patch to fix the

unicode string handling in email.utils.parseaddr()
  (bsc#1222537).

OBS-URL: https://build.opensuse.org/package/show/devel:languages:python:Factory/python?expand=0&rev=407
This commit is contained in:
Matej Cepl 2024-04-16 20:26:40 +00:00 committed by Git OBS Bridge
parent c8f2c7a003
commit 7ccba948f3
8 changed files with 302 additions and 342 deletions

View File

@ -1,14 +1,13 @@
--- ---
Doc/library/email.utils.rst | 19 - Doc/library/email.utils.rst | 19
Lib/email/utils.py | 151 +++++++- Lib/email/test/test_email.py | 192 +++++++++-
Lib/test/test_email/test_email.py | 187 +++++++++- Lib/email/test/test_email_renamed.py | 50 ++
Lib/email/utils.py | 155 +++++++-
Misc/NEWS.d/next/Library/2023-10-20-15-28-08.gh-issue-102988.dStNO7.rst | 8 Misc/NEWS.d/next/Library/2023-10-20-15-28-08.gh-issue-102988.dStNO7.rst | 8
4 files changed, 344 insertions(+), 21 deletions(-) 5 files changed, 393 insertions(+), 31 deletions(-)
Index: Python-2.7.18/Doc/library/email.utils.rst --- a/Doc/library/email.utils.rst
=================================================================== +++ b/Doc/library/email.utils.rst
--- Python-2.7.18.orig/Doc/library/email.utils.rst
+++ Python-2.7.18/Doc/library/email.utils.rst
@@ -21,13 +21,18 @@ There are several useful utilities provi @@ -21,13 +21,18 @@ There are several useful utilities provi
begins with angle brackets, they are stripped off. begins with angle brackets, they are stripped off.
@ -58,10 +57,284 @@ Index: Python-2.7.18/Doc/library/email.utils.rst
.. function:: parsedate(date) .. function:: parsedate(date)
Index: Python-2.7.18/Lib/email/utils.py --- a/Lib/email/test/test_email.py
=================================================================== +++ b/Lib/email/test/test_email.py
--- Python-2.7.18.orig/Lib/email/utils.py @@ -1,3 +1,4 @@
+++ Python-2.7.18/Lib/email/utils.py +# -*- coding: utf-8 -*-
# Copyright (C) 2001-2010 Python Software Foundation
# Contact: email-sig@python.org
# email package unit tests
@@ -2414,15 +2415,142 @@ Foo
[('Al Person', 'aperson@dom.ain'),
('Bud Person', 'bperson@dom.ain')])
+ def test_parsing_errors(self):
+ """Test for parsing errors from CVE-2023-27043 and CVE-2019-16056"""
+ alice = 'alice@example.org'
+ bob = 'bob@example.com'
+ empty = ('', '')
+
+ # Test Utils.getaddresses() and Utils.parseaddr() on malformed email
+ # addresses: default behavior (strict=True) rejects malformed address,
+ # and strict=False which tolerates malformed address.
+ for invalid_separator, expected_non_strict in (
+ ('(', [('<%s>' % bob, alice)]),
+ (')', [('', alice), empty, ('', bob)]),
+ ('<', [('', alice), empty, ('', bob), empty]),
+ ('>', [('', alice), empty, ('', bob)]),
+ ('[', [('', '%s[<%s>]' % (alice, bob))]),
+ (']', [('', alice), empty, ('', bob)]),
+ ('@', [empty, empty, ('', bob)]),
+ (';', [('', alice), empty, ('', bob)]),
+ (':', [('', alice), ('', bob)]),
+ ('.', [('', alice + '.'), ('', bob)]),
+ ('"', [('', alice), ('', '<%s>' % bob)]),
+ ):
+ address = '%s%s<%s>' % (alice, invalid_separator, bob)
+ self.assertEqual(Utils.getaddresses([address]),
+ [empty])
+ self.assertEqual(Utils.getaddresses([address], strict=False),
+ expected_non_strict)
+
+ self.assertEqual(Utils.parseaddr([address]),
+ empty)
+ self.assertEqual(Utils.parseaddr([address], strict=False),
+ ('', address))
+
+ # Comma (',') is treated differently depending on strict parameter.
+ # Comma without quotes.
+ address = '%s,<%s>' % (alice, bob)
+ self.assertEqual(Utils.getaddresses([address]),
+ [('', alice), ('', bob)])
+ self.assertEqual(Utils.getaddresses([address], strict=False),
+ [('', alice), ('', bob)])
+ self.assertEqual(Utils.parseaddr([address]),
+ empty)
+ self.assertEqual(Utils.parseaddr([address], strict=False),
+ ('', address))
+
+ # Real name between quotes containing comma.
+ address = '"Alice, alice@example.org" <bob@example.com>'
+ expected_strict = ('Alice, alice@example.org', 'bob@example.com')
+ self.assertEqual(Utils.getaddresses([address]), [expected_strict])
+ self.assertEqual(Utils.getaddresses([address], strict=False), [expected_strict])
+ self.assertEqual(Utils.parseaddr([address]), expected_strict)
+ self.assertEqual(Utils.parseaddr([address], strict=False),
+ ('', address))
+
+ # Valid parenthesis in comments.
+ address = 'alice@example.org (Alice)'
+ expected_strict = ('Alice', 'alice@example.org')
+ self.assertEqual(Utils.getaddresses([address]), [expected_strict])
+ self.assertEqual(Utils.getaddresses([address], strict=False), [expected_strict])
+ self.assertEqual(Utils.parseaddr([address]), expected_strict)
+ self.assertEqual(Utils.parseaddr([address], strict=False),
+ ('', address))
+
+ # Invalid parenthesis in comments.
+ address = 'alice@example.org )Alice('
+ self.assertEqual(Utils.getaddresses([address]), [empty])
+ self.assertEqual(Utils.getaddresses([address], strict=False),
+ [('', 'alice@example.org'), ('', ''), ('', 'Alice')])
+ self.assertEqual(Utils.parseaddr([address]), empty)
+ self.assertEqual(Utils.parseaddr([address], strict=False),
+ ('', address))
+
+ # Two addresses with quotes separated by comma.
+ address = '"Jane Doe" <jane@example.net>, "John Doe" <john@example.net>'
+ self.assertEqual(Utils.getaddresses([address]),
+ [('Jane Doe', 'jane@example.net'),
+ ('John Doe', 'john@example.net')])
+ self.assertEqual(Utils.getaddresses([address], strict=False),
+ [('Jane Doe', 'jane@example.net'),
+ ('John Doe', 'john@example.net')])
+ self.assertEqual(Utils.parseaddr([address]), empty)
+ self.assertEqual(Utils.parseaddr([address], strict=False),
+ ('', address))
+
+ # Test Utils.supports_strict_parsing attribute
+ self.assertEqual(Utils.supports_strict_parsing, True)
+
+ def test_parsing_unicode_str(self):
+ email_in = "Honza Novák <honza@example.com>"
+ self.assertEqual(Utils.parseaddr("Honza str Novák <honza@example.com>"),
+ ('Honza str Nov\xc3\xa1k', 'honza@example.com'))
+ self.assertEqual(Utils.parseaddr(u"Honza unicode Novák <honza@example.com>"),
+ (u'Honza unicode Nov\xe1k', u'honza@example.com'))
+
def test_getaddresses_nasty(self):
- eq = self.assertEqual
- eq(Utils.getaddresses(['foo: ;']), [('', '')])
- eq(Utils.getaddresses(
- ['[]*-- =~$']),
- [('', ''), ('', ''), ('', '*--')])
- eq(Utils.getaddresses(
- ['foo: ;', '"Jason R. Mastaler" <jason@dom.ain>']),
- [('', ''), ('Jason R. Mastaler', 'jason@dom.ain')])
+ for addresses, expected in (
+ ([u'"Sürname, Firstname" <to@example.com>'],
+ [(u'Sürname, Firstname', 'to@example.com')]),
+
+ (['foo: ;'],
+ [('', '')]),
+
+ (['foo: ;', '"Jason R. Mastaler" <jason@dom.ain>'],
+ [('', ''), ('Jason R. Mastaler', 'jason@dom.ain')]),
+
+ ([r'Pete(A nice \) chap) <pete(his account)@silly.test(his host)>'],
+ [('Pete (A nice ) chap his account his host)', 'pete@silly.test')]),
+
+ (['(Empty list)(start)Undisclosed recipients :(nobody(I know))'],
+ [('', '')]),
+
+ (['Mary <@machine.tld:mary@example.net>, , jdoe@test . example'],
+ [('Mary', 'mary@example.net'), ('', ''), ('', 'jdoe@test.example')]),
+
+ (['John Doe <jdoe@machine(comment). example>'],
+ [('John Doe (comment)', 'jdoe@machine.example')]),
+
+ (['"Mary Smith: Personal Account" <smith@home.example>'],
+ [('Mary Smith: Personal Account', 'smith@home.example')]),
+
+ (['Undisclosed recipients:;'],
+ [('', '')]),
+
+ ([r'<boss@nil.test>, "Giant; \"Big\" Box" <bob@example.net>'],
+ [('', 'boss@nil.test'), ('Giant; "Big" Box', 'bob@example.net')]),
+ ):
+ self.assertEqual(Utils.getaddresses(addresses),
+ expected)
+ self.assertEqual(Utils.getaddresses(addresses, strict=False),
+ expected)
+
+ addresses = ['[]*-- =~$']
+ self.assertEqual(Utils.getaddresses(addresses),
+ [('', '')])
+ self.assertEqual(Utils.getaddresses(addresses, strict=False),
+ [('', ''), ('', ''), ('', '*--')])
def test_getaddresses_embedded_comment(self):
"""Test proper handling of a nested comment"""
@@ -2430,6 +2558,54 @@ Foo
addrs = Utils.getaddresses(['User ((nested comment)) <foo@bar.com>'])
eq(addrs[0][1], 'foo@bar.com')
+ def test_iter_escaped_chars(self):
+ self.assertEqual(list(Utils._iter_escaped_chars(r'a\\b\"c\\"d')),
+ [(0, 'a'),
+ (2, '\\\\'),
+ (3, 'b'),
+ (5, '\\"'),
+ (6, 'c'),
+ (8, '\\\\'),
+ (9, '"'),
+ (10, 'd')])
+ self.assertEqual(list(Utils._iter_escaped_chars('a\\')),
+ [(0, 'a'), (1, '\\')])
+
+ def test_strip_quoted_realnames(self):
+ def check(addr, expected):
+ self.assertEqual(Utils._strip_quoted_realnames(addr), expected)
+
+ check('"Jane Doe" <jane@example.net>, "John Doe" <john@example.net>',
+ ' <jane@example.net>, <john@example.net>')
+ check(r'"Jane \"Doe\"." <jane@example.net>',
+ ' <jane@example.net>')
+
+ # special cases
+ check(r'before"name"after', 'beforeafter')
+ check(r'before"name"', 'before')
+ check(r'b"name"', 'b') # single char
+ check(r'"name"after', 'after')
+ check(r'"name"a', 'a') # single char
+ check(r'"name"', '')
+
+ # no change
+ for addr in (
+ 'Jane Doe <jane@example.net>, John Doe <john@example.net>',
+ 'lone " quote',
+ ):
+ self.assertEqual(Utils._strip_quoted_realnames(addr), addr)
+
+ def test_check_parenthesis(self):
+ addr = 'alice@example.net'
+ self.assertTrue(Utils._check_parenthesis('%s (Alice)' % addr))
+ self.assertFalse(Utils._check_parenthesis('%s )Alice(' % addr))
+ self.assertFalse(Utils._check_parenthesis('%s (Alice))' % addr))
+ self.assertFalse(Utils._check_parenthesis('%s ((Alice)' % addr))
+
+ # Ignore real name between quotes
+ self.assertTrue(Utils._check_parenthesis('")Alice((" %s' % addr))
+
+
def test_make_msgid_collisions(self):
# Test make_msgid uniqueness, even with multiple threads
class MsgidsThread(Thread):
--- a/Lib/email/test/test_email_renamed.py
+++ b/Lib/email/test/test_email_renamed.py
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
# Copyright (C) 2001-2007 Python Software Foundation
# Contact: email-sig@python.org
# email package unit tests
@@ -2276,14 +2277,47 @@ Foo
('Bud Person', 'bperson@dom.ain')])
def test_getaddresses_nasty(self):
- eq = self.assertEqual
- eq(utils.getaddresses(['foo: ;']), [('', '')])
- eq(utils.getaddresses(
- ['[]*-- =~$']),
- [('', ''), ('', ''), ('', '*--')])
- eq(utils.getaddresses(
- ['foo: ;', '"Jason R. Mastaler" <jason@dom.ain>']),
- [('', ''), ('Jason R. Mastaler', 'jason@dom.ain')])
+ for addresses, expected in (
+ ([u'"Sürname, Firstname" <to@example.com>'],
+ [(u'Sürname, Firstname', 'to@example.com')]),
+
+ (['foo: ;'],
+ [('', '')]),
+
+ (['foo: ;', '"Jason R. Mastaler" <jason@dom.ain>'],
+ [('', ''), ('Jason R. Mastaler', 'jason@dom.ain')]),
+
+ ([r'Pete(A nice \) chap) <pete(his account)@silly.test(his host)>'],
+ [('Pete (A nice ) chap his account his host)', 'pete@silly.test')]),
+
+ (['(Empty list)(start)Undisclosed recipients :(nobody(I know))'],
+ [('', '')]),
+
+ (['Mary <@machine.tld:mary@example.net>, , jdoe@test . example'],
+ [('Mary', 'mary@example.net'), ('', ''), ('', 'jdoe@test.example')]),
+
+ (['John Doe <jdoe@machine(comment). example>'],
+ [('John Doe (comment)', 'jdoe@machine.example')]),
+
+ (['"Mary Smith: Personal Account" <smith@home.example>'],
+ [('Mary Smith: Personal Account', 'smith@home.example')]),
+
+ (['Undisclosed recipients:;'],
+ [('', '')]),
+
+ ([r'<boss@nil.test>, "Giant; \"Big\" Box" <bob@example.net>'],
+ [('', 'boss@nil.test'), ('Giant; "Big" Box', 'bob@example.net')]),
+ ):
+ self.assertEqual(utils.getaddresses(addresses),
+ expected)
+ self.assertEqual(utils.getaddresses(addresses, strict=False),
+ expected)
+
+ addresses = ['[]*-- =~$']
+ self.assertEqual(utils.getaddresses(addresses),
+ [('', '')])
+ self.assertEqual(utils.getaddresses(addresses, strict=False),
+ [('', ''), ('', ''), ('', '*--')])
def test_getaddresses_embedded_comment(self):
"""Test proper handling of a nested comment"""
--- a/Lib/email/utils.py
+++ b/Lib/email/utils.py
@@ -100,15 +100,93 @@ def formataddr(pair): @@ -100,15 +100,93 @@ def formataddr(pair):
return address return address
@ -190,7 +463,7 @@ Index: Python-2.7.18/Lib/email/utils.py
+ if isinstance(addr, list): + if isinstance(addr, list):
+ addr = addr[0] + addr = addr[0]
+ +
+ if not isinstance(addr, str): + if not isinstance(addr, basestring):
+ return ('', '') + return ('', '')
+ +
+ addr = _pre_parse_validation([addr])[0] + addr = _pre_parse_validation([addr])[0]
@ -242,10 +515,8 @@ Index: Python-2.7.18/Lib/email/utils.py
# rfc822.unquote() doesn't properly de-backslash-ify in Python pre-2.3. # rfc822.unquote() doesn't properly de-backslash-ify in Python pre-2.3.
def unquote(str): def unquote(str):
"""Remove quotes from a string.""" """Remove quotes from a string."""
Index: Python-2.7.18/Misc/NEWS.d/next/Library/2023-10-20-15-28-08.gh-issue-102988.dStNO7.rst
===================================================================
--- /dev/null --- /dev/null
+++ Python-2.7.18/Misc/NEWS.d/next/Library/2023-10-20-15-28-08.gh-issue-102988.dStNO7.rst +++ b/Misc/NEWS.d/next/Library/2023-10-20-15-28-08.gh-issue-102988.dStNO7.rst
@@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
+:func:`email.utils.getaddresses` and :func:`email.utils.parseaddr` now +:func:`email.utils.getaddresses` and :func:`email.utils.parseaddr` now
+return ``('', '')`` 2-tuples in more situations where invalid email +return ``('', '')`` 2-tuples in more situations where invalid email
@ -255,276 +526,3 @@ Index: Python-2.7.18/Misc/NEWS.d/next/Library/2023-10-20-15-28-08.gh-issue-10298
+``getattr(email.utils, 'supports_strict_parsing', False)`` can be use to check +``getattr(email.utils, 'supports_strict_parsing', False)`` can be use to check
+if the *strict* paramater is available. Patch by Thomas Dwyer and Victor +if the *strict* paramater is available. Patch by Thomas Dwyer and Victor
+Stinner to improve the CVE-2023-27043 fix. +Stinner to improve the CVE-2023-27043 fix.
Index: Python-2.7.18/Lib/email/test/test_email.py
===================================================================
--- Python-2.7.18.orig/Lib/email/test/test_email.py
+++ Python-2.7.18/Lib/email/test/test_email.py
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
# Copyright (C) 2001-2010 Python Software Foundation
# Contact: email-sig@python.org
# email package unit tests
@@ -2414,15 +2415,135 @@ Foo
[('Al Person', 'aperson@dom.ain'),
('Bud Person', 'bperson@dom.ain')])
+ def test_parsing_errors(self):
+ """Test for parsing errors from CVE-2023-27043 and CVE-2019-16056"""
+ alice = 'alice@example.org'
+ bob = 'bob@example.com'
+ empty = ('', '')
+
+ # Test Utils.getaddresses() and Utils.parseaddr() on malformed email
+ # addresses: default behavior (strict=True) rejects malformed address,
+ # and strict=False which tolerates malformed address.
+ for invalid_separator, expected_non_strict in (
+ ('(', [('<%s>' % bob, alice)]),
+ (')', [('', alice), empty, ('', bob)]),
+ ('<', [('', alice), empty, ('', bob), empty]),
+ ('>', [('', alice), empty, ('', bob)]),
+ ('[', [('', '%s[<%s>]' % (alice, bob))]),
+ (']', [('', alice), empty, ('', bob)]),
+ ('@', [empty, empty, ('', bob)]),
+ (';', [('', alice), empty, ('', bob)]),
+ (':', [('', alice), ('', bob)]),
+ ('.', [('', alice + '.'), ('', bob)]),
+ ('"', [('', alice), ('', '<%s>' % bob)]),
+ ):
+ address = '%s%s<%s>' % (alice, invalid_separator, bob)
+ self.assertEqual(Utils.getaddresses([address]),
+ [empty])
+ self.assertEqual(Utils.getaddresses([address], strict=False),
+ expected_non_strict)
+
+ self.assertEqual(Utils.parseaddr([address]),
+ empty)
+ self.assertEqual(Utils.parseaddr([address], strict=False),
+ ('', address))
+
+ # Comma (',') is treated differently depending on strict parameter.
+ # Comma without quotes.
+ address = '%s,<%s>' % (alice, bob)
+ self.assertEqual(Utils.getaddresses([address]),
+ [('', alice), ('', bob)])
+ self.assertEqual(Utils.getaddresses([address], strict=False),
+ [('', alice), ('', bob)])
+ self.assertEqual(Utils.parseaddr([address]),
+ empty)
+ self.assertEqual(Utils.parseaddr([address], strict=False),
+ ('', address))
+
+ # Real name between quotes containing comma.
+ address = '"Alice, alice@example.org" <bob@example.com>'
+ expected_strict = ('Alice, alice@example.org', 'bob@example.com')
+ self.assertEqual(Utils.getaddresses([address]), [expected_strict])
+ self.assertEqual(Utils.getaddresses([address], strict=False), [expected_strict])
+ self.assertEqual(Utils.parseaddr([address]), expected_strict)
+ self.assertEqual(Utils.parseaddr([address], strict=False),
+ ('', address))
+
+ # Valid parenthesis in comments.
+ address = 'alice@example.org (Alice)'
+ expected_strict = ('Alice', 'alice@example.org')
+ self.assertEqual(Utils.getaddresses([address]), [expected_strict])
+ self.assertEqual(Utils.getaddresses([address], strict=False), [expected_strict])
+ self.assertEqual(Utils.parseaddr([address]), expected_strict)
+ self.assertEqual(Utils.parseaddr([address], strict=False),
+ ('', address))
+
+ # Invalid parenthesis in comments.
+ address = 'alice@example.org )Alice('
+ self.assertEqual(Utils.getaddresses([address]), [empty])
+ self.assertEqual(Utils.getaddresses([address], strict=False),
+ [('', 'alice@example.org'), ('', ''), ('', 'Alice')])
+ self.assertEqual(Utils.parseaddr([address]), empty)
+ self.assertEqual(Utils.parseaddr([address], strict=False),
+ ('', address))
+
+ # Two addresses with quotes separated by comma.
+ address = '"Jane Doe" <jane@example.net>, "John Doe" <john@example.net>'
+ self.assertEqual(Utils.getaddresses([address]),
+ [('Jane Doe', 'jane@example.net'),
+ ('John Doe', 'john@example.net')])
+ self.assertEqual(Utils.getaddresses([address], strict=False),
+ [('Jane Doe', 'jane@example.net'),
+ ('John Doe', 'john@example.net')])
+ self.assertEqual(Utils.parseaddr([address]), empty)
+ self.assertEqual(Utils.parseaddr([address], strict=False),
+ ('', address))
+
+ # Test Utils.supports_strict_parsing attribute
+ self.assertEqual(Utils.supports_strict_parsing, True)
+
def test_getaddresses_nasty(self):
- eq = self.assertEqual
- eq(Utils.getaddresses(['foo: ;']), [('', '')])
- eq(Utils.getaddresses(
- ['[]*-- =~$']),
- [('', ''), ('', ''), ('', '*--')])
- eq(Utils.getaddresses(
- ['foo: ;', '"Jason R. Mastaler" <jason@dom.ain>']),
- [('', ''), ('Jason R. Mastaler', 'jason@dom.ain')])
+ for addresses, expected in (
+ ([u'"Sürname, Firstname" <to@example.com>'],
+ [(u'Sürname, Firstname', 'to@example.com')]),
+
+ (['foo: ;'],
+ [('', '')]),
+
+ (['foo: ;', '"Jason R. Mastaler" <jason@dom.ain>'],
+ [('', ''), ('Jason R. Mastaler', 'jason@dom.ain')]),
+
+ ([r'Pete(A nice \) chap) <pete(his account)@silly.test(his host)>'],
+ [('Pete (A nice ) chap his account his host)', 'pete@silly.test')]),
+
+ (['(Empty list)(start)Undisclosed recipients :(nobody(I know))'],
+ [('', '')]),
+
+ (['Mary <@machine.tld:mary@example.net>, , jdoe@test . example'],
+ [('Mary', 'mary@example.net'), ('', ''), ('', 'jdoe@test.example')]),
+
+ (['John Doe <jdoe@machine(comment). example>'],
+ [('John Doe (comment)', 'jdoe@machine.example')]),
+
+ (['"Mary Smith: Personal Account" <smith@home.example>'],
+ [('Mary Smith: Personal Account', 'smith@home.example')]),
+
+ (['Undisclosed recipients:;'],
+ [('', '')]),
+
+ ([r'<boss@nil.test>, "Giant; \"Big\" Box" <bob@example.net>'],
+ [('', 'boss@nil.test'), ('Giant; "Big" Box', 'bob@example.net')]),
+ ):
+ self.assertEqual(Utils.getaddresses(addresses),
+ expected)
+ self.assertEqual(Utils.getaddresses(addresses, strict=False),
+ expected)
+
+ addresses = ['[]*-- =~$']
+ self.assertEqual(Utils.getaddresses(addresses),
+ [('', '')])
+ self.assertEqual(Utils.getaddresses(addresses, strict=False),
+ [('', ''), ('', ''), ('', '*--')])
def test_getaddresses_embedded_comment(self):
"""Test proper handling of a nested comment"""
@@ -2430,6 +2551,54 @@ Foo
addrs = Utils.getaddresses(['User ((nested comment)) <foo@bar.com>'])
eq(addrs[0][1], 'foo@bar.com')
+ def test_iter_escaped_chars(self):
+ self.assertEqual(list(Utils._iter_escaped_chars(r'a\\b\"c\\"d')),
+ [(0, 'a'),
+ (2, '\\\\'),
+ (3, 'b'),
+ (5, '\\"'),
+ (6, 'c'),
+ (8, '\\\\'),
+ (9, '"'),
+ (10, 'd')])
+ self.assertEqual(list(Utils._iter_escaped_chars('a\\')),
+ [(0, 'a'), (1, '\\')])
+
+ def test_strip_quoted_realnames(self):
+ def check(addr, expected):
+ self.assertEqual(Utils._strip_quoted_realnames(addr), expected)
+
+ check('"Jane Doe" <jane@example.net>, "John Doe" <john@example.net>',
+ ' <jane@example.net>, <john@example.net>')
+ check(r'"Jane \"Doe\"." <jane@example.net>',
+ ' <jane@example.net>')
+
+ # special cases
+ check(r'before"name"after', 'beforeafter')
+ check(r'before"name"', 'before')
+ check(r'b"name"', 'b') # single char
+ check(r'"name"after', 'after')
+ check(r'"name"a', 'a') # single char
+ check(r'"name"', '')
+
+ # no change
+ for addr in (
+ 'Jane Doe <jane@example.net>, John Doe <john@example.net>',
+ 'lone " quote',
+ ):
+ self.assertEqual(Utils._strip_quoted_realnames(addr), addr)
+
+ def test_check_parenthesis(self):
+ addr = 'alice@example.net'
+ self.assertTrue(Utils._check_parenthesis('%s (Alice)' % addr))
+ self.assertFalse(Utils._check_parenthesis('%s )Alice(' % addr))
+ self.assertFalse(Utils._check_parenthesis('%s (Alice))' % addr))
+ self.assertFalse(Utils._check_parenthesis('%s ((Alice)' % addr))
+
+ # Ignore real name between quotes
+ self.assertTrue(Utils._check_parenthesis('")Alice((" %s' % addr))
+
+
def test_make_msgid_collisions(self):
# Test make_msgid uniqueness, even with multiple threads
class MsgidsThread(Thread):
Index: Python-2.7.18/Lib/email/test/test_email_renamed.py
===================================================================
--- Python-2.7.18.orig/Lib/email/test/test_email_renamed.py
+++ Python-2.7.18/Lib/email/test/test_email_renamed.py
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
# Copyright (C) 2001-2007 Python Software Foundation
# Contact: email-sig@python.org
# email package unit tests
@@ -2276,14 +2277,47 @@ Foo
('Bud Person', 'bperson@dom.ain')])
def test_getaddresses_nasty(self):
- eq = self.assertEqual
- eq(utils.getaddresses(['foo: ;']), [('', '')])
- eq(utils.getaddresses(
- ['[]*-- =~$']),
- [('', ''), ('', ''), ('', '*--')])
- eq(utils.getaddresses(
- ['foo: ;', '"Jason R. Mastaler" <jason@dom.ain>']),
- [('', ''), ('Jason R. Mastaler', 'jason@dom.ain')])
+ for addresses, expected in (
+ ([u'"Sürname, Firstname" <to@example.com>'],
+ [(u'Sürname, Firstname', 'to@example.com')]),
+
+ (['foo: ;'],
+ [('', '')]),
+
+ (['foo: ;', '"Jason R. Mastaler" <jason@dom.ain>'],
+ [('', ''), ('Jason R. Mastaler', 'jason@dom.ain')]),
+
+ ([r'Pete(A nice \) chap) <pete(his account)@silly.test(his host)>'],
+ [('Pete (A nice ) chap his account his host)', 'pete@silly.test')]),
+
+ (['(Empty list)(start)Undisclosed recipients :(nobody(I know))'],
+ [('', '')]),
+
+ (['Mary <@machine.tld:mary@example.net>, , jdoe@test . example'],
+ [('Mary', 'mary@example.net'), ('', ''), ('', 'jdoe@test.example')]),
+
+ (['John Doe <jdoe@machine(comment). example>'],
+ [('John Doe (comment)', 'jdoe@machine.example')]),
+
+ (['"Mary Smith: Personal Account" <smith@home.example>'],
+ [('Mary Smith: Personal Account', 'smith@home.example')]),
+
+ (['Undisclosed recipients:;'],
+ [('', '')]),
+
+ ([r'<boss@nil.test>, "Giant; \"Big\" Box" <bob@example.net>'],
+ [('', 'boss@nil.test'), ('Giant; "Big" Box', 'bob@example.net')]),
+ ):
+ self.assertEqual(utils.getaddresses(addresses),
+ expected)
+ self.assertEqual(utils.getaddresses(addresses, strict=False),
+ expected)
+
+ addresses = ['[]*-- =~$']
+ self.assertEqual(utils.getaddresses(addresses),
+ [('', '')])
+ self.assertEqual(utils.getaddresses(addresses, strict=False),
+ [('', ''), ('', ''), ('', '*--')])
def test_getaddresses_embedded_comment(self):
"""Test proper handling of a nested comment"""

View File

@ -1,32 +0,0 @@
---
Lib/email/test/test_email.py | 7 +++++++
Lib/email/utils.py | 2 +-
2 files changed, 8 insertions(+), 1 deletion(-)
--- a/Lib/email/test/test_email.py
+++ b/Lib/email/test/test_email.py
@@ -2502,6 +2502,13 @@ Foo
# Test Utils.supports_strict_parsing attribute
self.assertEqual(Utils.supports_strict_parsing, True)
+ def test_parsing_unicode_str(self):
+ email_in = "Honza Novák <honza@example.com>"
+ self.assertEqual(Utils.parseaddr("Honza str Novák <honza@example.com>"),
+ ('Honza str Nov\xc3\xa1k', 'honza@example.com'))
+ self.assertEqual(Utils.parseaddr(u"Honza unicode Novák <honza@example.com>"),
+ (u'Honza unicode Nov\xe1k', u'honza@example.com'))
+
def test_getaddresses_nasty(self):
for addresses, expected in (
([u'"Sürname, Firstname" <to@example.com>'],
--- a/Lib/email/utils.py
+++ b/Lib/email/utils.py
@@ -307,7 +307,7 @@ def parseaddr(addr, strict=True):
if isinstance(addr, list):
addr = addr[0]
- if not isinstance(addr, str):
+ if not isinstance(addr, basestring):
return ('', '')
addr = _pre_parse_validation([addr])[0]

View File

@ -2,8 +2,9 @@
Tue Apr 16 15:39:24 UTC 2024 - Matej Cepl <mcepl@cepl.eu> Tue Apr 16 15:39:24 UTC 2024 - Matej Cepl <mcepl@cepl.eu>
- Switch on tests again. - Switch on tests again.
- Add bsc1222537-py2-email-addr-parse.patch to fix the unicode - Modify CVE-2023-27043-email-parsing-errors.patch to fix the
string handling in email.utils.parseaddr() (bsc#1222537). unicode string handling in email.utils.parseaddr()
(bsc#1222537).
------------------------------------------------------------------- -------------------------------------------------------------------
Mon Mar 18 09:54:20 UTC 2024 - Matej Cepl <mcepl@cepl.eu> Mon Mar 18 09:54:20 UTC 2024 - Matej Cepl <mcepl@cepl.eu>

View File

@ -154,7 +154,8 @@ Patch75: CVE-2023-24329-blank-URL-bypass.patch
Patch76: PygmentsBridge-trime_doctest_flags.patch Patch76: PygmentsBridge-trime_doctest_flags.patch
# PATCH-FIX-UPSTREAM CVE-2023-27043-email-parsing-errors.patch bsc#1210638 mcepl@suse.com # PATCH-FIX-UPSTREAM CVE-2023-27043-email-parsing-errors.patch bsc#1210638 mcepl@suse.com
# Detect email address parsing errors and return empty tuple to # Detect email address parsing errors and return empty tuple to
# indicate the parsing error (old API) # indicate the parsing error (old API), modified for fixing bsc#1222537,
# so that email.utils.parseaddr accepts unicode string
Patch77: CVE-2023-27043-email-parsing-errors.patch Patch77: CVE-2023-27043-email-parsing-errors.patch
# PATCH-FIX-UPSTREAM CVE-2022-48565-plistlib-XML-vulns.patch bsc#1214685 mcepl@suse.com # PATCH-FIX-UPSTREAM CVE-2022-48565-plistlib-XML-vulns.patch bsc#1214685 mcepl@suse.com
# Reject entity declarations in plists # Reject entity declarations in plists
@ -167,9 +168,6 @@ Patch80: CVE-2022-48566-compare_digest-more-constant.patch
# PATCH-FIX-UPSTREAM CVE-2022-48560-after-free-heappushpop.patch bsc#1214675 mcepl@suse.com # PATCH-FIX-UPSTREAM CVE-2022-48560-after-free-heappushpop.patch bsc#1214675 mcepl@suse.com
# fix use after free in heapq.heappushpop() # fix use after free in heapq.heappushpop()
Patch81: CVE-2022-48560-after-free-heappushpop.patch Patch81: CVE-2022-48560-after-free-heappushpop.patch
# PATCH-FIX-UPSTREAM bsc1222537-py2-email-addr-parse.patch bsc#1222537 mcepl@suse.com
# email.utils.parseaddr should accept unicode string
Patch82: bsc1222537-py2-email-addr-parse.patch
# COMMON-PATCH-END # COMMON-PATCH-END
%define python_version %(echo %{tarversion} | head -c 3) %define python_version %(echo %{tarversion} | head -c 3)
BuildRequires: automake BuildRequires: automake
@ -327,7 +325,6 @@ other applications.
%patch -P 79 -p1 %patch -P 79 -p1
%patch -P 80 -p1 %patch -P 80 -p1
%patch -P 81 -p1 %patch -P 81 -p1
%patch -P 82 -p1
# For patch 66 # For patch 66
cp -v %{SOURCE66} Lib/test/recursion.tar cp -v %{SOURCE66} Lib/test/recursion.tar

View File

@ -2,8 +2,9 @@
Tue Apr 16 15:39:24 UTC 2024 - Matej Cepl <mcepl@cepl.eu> Tue Apr 16 15:39:24 UTC 2024 - Matej Cepl <mcepl@cepl.eu>
- Switch on tests again. - Switch on tests again.
- Add bsc1222537-py2-email-addr-parse.patch to fix the unicode - Modify CVE-2023-27043-email-parsing-errors.patch to fix the
string handling in email.utils.parseaddr() (bsc#1222537). unicode string handling in email.utils.parseaddr()
(bsc#1222537).
------------------------------------------------------------------- -------------------------------------------------------------------
Mon Mar 18 09:54:20 UTC 2024 - Matej Cepl <mcepl@cepl.eu> Mon Mar 18 09:54:20 UTC 2024 - Matej Cepl <mcepl@cepl.eu>

View File

@ -150,7 +150,8 @@ Patch75: CVE-2023-24329-blank-URL-bypass.patch
Patch76: PygmentsBridge-trime_doctest_flags.patch Patch76: PygmentsBridge-trime_doctest_flags.patch
# PATCH-FIX-UPSTREAM CVE-2023-27043-email-parsing-errors.patch bsc#1210638 mcepl@suse.com # PATCH-FIX-UPSTREAM CVE-2023-27043-email-parsing-errors.patch bsc#1210638 mcepl@suse.com
# Detect email address parsing errors and return empty tuple to # Detect email address parsing errors and return empty tuple to
# indicate the parsing error (old API) # indicate the parsing error (old API), modified for fixing bsc#1222537,
# so that email.utils.parseaddr accepts unicode string
Patch77: CVE-2023-27043-email-parsing-errors.patch Patch77: CVE-2023-27043-email-parsing-errors.patch
# PATCH-FIX-UPSTREAM CVE-2022-48565-plistlib-XML-vulns.patch bsc#1214685 mcepl@suse.com # PATCH-FIX-UPSTREAM CVE-2022-48565-plistlib-XML-vulns.patch bsc#1214685 mcepl@suse.com
# Reject entity declarations in plists # Reject entity declarations in plists
@ -163,9 +164,6 @@ Patch80: CVE-2022-48566-compare_digest-more-constant.patch
# PATCH-FIX-UPSTREAM CVE-2022-48560-after-free-heappushpop.patch bsc#1214675 mcepl@suse.com # PATCH-FIX-UPSTREAM CVE-2022-48560-after-free-heappushpop.patch bsc#1214675 mcepl@suse.com
# fix use after free in heapq.heappushpop() # fix use after free in heapq.heappushpop()
Patch81: CVE-2022-48560-after-free-heappushpop.patch Patch81: CVE-2022-48560-after-free-heappushpop.patch
# PATCH-FIX-UPSTREAM bsc1222537-py2-email-addr-parse.patch bsc#1222537 mcepl@suse.com
# email.utils.parseaddr should accept unicode string
Patch82: bsc1222537-py2-email-addr-parse.patch
# COMMON-PATCH-END # COMMON-PATCH-END
Provides: pyth_doc = %{version} Provides: pyth_doc = %{version}
Provides: pyth_ps = %{version} Provides: pyth_ps = %{version}
@ -258,7 +256,6 @@ Python, and Macintosh Module Reference in PDF format.
%patch -P 79 -p1 %patch -P 79 -p1
%patch -P 80 -p1 %patch -P 80 -p1
%patch -P 81 -p1 %patch -P 81 -p1
%patch -P 82 -p1
# For patch 66 # For patch 66
cp -v %{SOURCE66} Lib/test/recursion.tar cp -v %{SOURCE66} Lib/test/recursion.tar

View File

@ -2,8 +2,9 @@
Tue Apr 16 15:39:24 UTC 2024 - Matej Cepl <mcepl@cepl.eu> Tue Apr 16 15:39:24 UTC 2024 - Matej Cepl <mcepl@cepl.eu>
- Switch on tests again. - Switch on tests again.
- Add bsc1222537-py2-email-addr-parse.patch to fix the unicode - Modify CVE-2023-27043-email-parsing-errors.patch to fix the
string handling in email.utils.parseaddr() (bsc#1222537). unicode string handling in email.utils.parseaddr()
(bsc#1222537).
------------------------------------------------------------------- -------------------------------------------------------------------
Mon Mar 18 09:54:20 UTC 2024 - Matej Cepl <mcepl@cepl.eu> Mon Mar 18 09:54:20 UTC 2024 - Matej Cepl <mcepl@cepl.eu>

View File

@ -150,7 +150,8 @@ Patch75: CVE-2023-24329-blank-URL-bypass.patch
Patch76: PygmentsBridge-trime_doctest_flags.patch Patch76: PygmentsBridge-trime_doctest_flags.patch
# PATCH-FIX-UPSTREAM CVE-2023-27043-email-parsing-errors.patch bsc#1210638 mcepl@suse.com # PATCH-FIX-UPSTREAM CVE-2023-27043-email-parsing-errors.patch bsc#1210638 mcepl@suse.com
# Detect email address parsing errors and return empty tuple to # Detect email address parsing errors and return empty tuple to
# indicate the parsing error (old API) # indicate the parsing error (old API), modified for fixing bsc#1222537,
# so that email.utils.parseaddr accepts unicode string
Patch77: CVE-2023-27043-email-parsing-errors.patch Patch77: CVE-2023-27043-email-parsing-errors.patch
# PATCH-FIX-UPSTREAM CVE-2022-48565-plistlib-XML-vulns.patch bsc#1214685 mcepl@suse.com # PATCH-FIX-UPSTREAM CVE-2022-48565-plistlib-XML-vulns.patch bsc#1214685 mcepl@suse.com
# Reject entity declarations in plists # Reject entity declarations in plists
@ -163,9 +164,6 @@ Patch80: CVE-2022-48566-compare_digest-more-constant.patch
# PATCH-FIX-UPSTREAM CVE-2022-48560-after-free-heappushpop.patch bsc#1214675 mcepl@suse.com # PATCH-FIX-UPSTREAM CVE-2022-48560-after-free-heappushpop.patch bsc#1214675 mcepl@suse.com
# fix use after free in heapq.heappushpop() # fix use after free in heapq.heappushpop()
Patch81: CVE-2022-48560-after-free-heappushpop.patch Patch81: CVE-2022-48560-after-free-heappushpop.patch
# PATCH-FIX-UPSTREAM bsc1222537-py2-email-addr-parse.patch bsc#1222537 mcepl@suse.com
# email.utils.parseaddr should accept unicode string
Patch82: bsc1222537-py2-email-addr-parse.patch
# COMMON-PATCH-END # COMMON-PATCH-END
BuildRequires: automake BuildRequires: automake
BuildRequires: db-devel BuildRequires: db-devel
@ -378,7 +376,6 @@ that rely on earlier non-verification behavior.
%patch -P 79 -p1 %patch -P 79 -p1
%patch -P 80 -p1 %patch -P 80 -p1
%patch -P 81 -p1 %patch -P 81 -p1
%patch -P 82 -p1
# For patch 66 # For patch 66
cp -v %{SOURCE66} Lib/test/recursion.tar cp -v %{SOURCE66} Lib/test/recursion.tar