121 lines
4.2 KiB
Diff
121 lines
4.2 KiB
Diff
|
Index: pydantic-1.10.7/pydantic/networks.py
|
||
|
===================================================================
|
||
|
--- pydantic-1.10.7.orig/pydantic/networks.py
|
||
|
+++ pydantic-1.10.7/pydantic/networks.py
|
||
|
@@ -701,7 +701,19 @@ class IPvAnyNetwork(_BaseNetwork): # ty
|
||
|
raise errors.IPvAnyNetworkError()
|
||
|
|
||
|
|
||
|
-pretty_email_regex = re.compile(r'([\w ]*?) *<(.*)> *')
|
||
|
+def _build_pretty_email_regex() -> re.Pattern[str]:
|
||
|
+ name_chars = r'[\w!#$%&\'*+\-/=?^_`{|}~]'
|
||
|
+ unquoted_name_group = rf'((?:{name_chars}+\s+)*{name_chars}+)'
|
||
|
+ quoted_name_group = r'"((?:[^"]|\")+)"'
|
||
|
+ email_group = r'<(.+)>'
|
||
|
+ return re.compile(rf'\s*(?:{unquoted_name_group}|{quoted_name_group})?\s*{email_group}\s*')
|
||
|
+
|
||
|
+pretty_email_regex = _build_pretty_email_regex()
|
||
|
+
|
||
|
+MAX_EMAIL_LENGTH = 2048
|
||
|
+"""Maximum length for an email.
|
||
|
+A somewhat arbitrary but very generous number compared to what is allowed by most implementations.
|
||
|
+"""
|
||
|
|
||
|
|
||
|
def validate_email(value: Union[str]) -> Tuple[str, str]:
|
||
|
@@ -718,10 +730,14 @@ def validate_email(value: Union[str]) ->
|
||
|
if email_validator is None:
|
||
|
import_email_validator()
|
||
|
|
||
|
+ if len(value) > MAX_EMAIL_LENGTH:
|
||
|
+ raise errors.EmailError()
|
||
|
+
|
||
|
m = pretty_email_regex.fullmatch(value)
|
||
|
- name: Optional[str] = None
|
||
|
+ name: str | None = None
|
||
|
if m:
|
||
|
- name, value = m.groups()
|
||
|
+ unquoted_name, quoted_name, value = m.groups()
|
||
|
+ name = unquoted_name or quoted_name
|
||
|
|
||
|
email = value.strip()
|
||
|
|
||
|
Index: pydantic-1.10.7/tests/test_networks.py
|
||
|
===================================================================
|
||
|
--- pydantic-1.10.7.orig/tests/test_networks.py
|
||
|
+++ pydantic-1.10.7/tests/test_networks.py
|
||
|
@@ -1,3 +1,5 @@
|
||
|
+from typing import Union
|
||
|
+
|
||
|
import pytest
|
||
|
|
||
|
from pydantic import (
|
||
|
@@ -15,6 +17,7 @@ from pydantic import (
|
||
|
PostgresDsn,
|
||
|
RedisDsn,
|
||
|
ValidationError,
|
||
|
+ EmailError,
|
||
|
stricturl,
|
||
|
)
|
||
|
from pydantic.networks import validate_email
|
||
|
@@ -768,31 +771,37 @@ def test_address_valid(value, name, emai
|
||
|
|
||
|
@pytest.mark.skipif(not email_validator, reason='email_validator not installed')
|
||
|
@pytest.mark.parametrize(
|
||
|
- 'value',
|
||
|
+ 'value,reason',
|
||
|
[
|
||
|
- 'f oo.bar@example.com ',
|
||
|
- 'foo.bar@exam\nple.com ',
|
||
|
- 'foobar',
|
||
|
- 'foobar <foobar@example.com',
|
||
|
- '@example.com',
|
||
|
- 'foobar@.example.com',
|
||
|
- 'foobar@.com',
|
||
|
- 'foo bar@example.com',
|
||
|
- 'foo@bar@example.com',
|
||
|
- '\n@example.com',
|
||
|
- '\r@example.com',
|
||
|
- '\f@example.com',
|
||
|
- ' @example.com',
|
||
|
- '\u0020@example.com',
|
||
|
- '\u001f@example.com',
|
||
|
- '"@example.com',
|
||
|
- '\"@example.com',
|
||
|
- ',@example.com',
|
||
|
- 'foobar <foobar<@example.com>',
|
||
|
+ ('@example.com', 'There must be something before the @-sign.'),
|
||
|
+ ('f oo.bar@example.com', 'The email address contains invalid characters before the @-sign'),
|
||
|
+ ('foobar', 'An email address must have an @-sign.'),
|
||
|
+ ('foobar@localhost', 'The part after the @-sign is not valid. It should have a period.'),
|
||
|
+ ('foobar@127.0.0.1', 'The part after the @-sign is not valid. It is not within a valid top-level domain.'),
|
||
|
+ ('foo.bar@exam\nple.com ', None),
|
||
|
+ ('foobar <foobar@example.com', None),
|
||
|
+ ('foobar@.example.com', None),
|
||
|
+ ('foobar@.com', None),
|
||
|
+ ('foo bar@example.com', None),
|
||
|
+ ('foo@bar@example.com', None),
|
||
|
+ ('\n@example.com', None),
|
||
|
+ ('\r@example.com', None),
|
||
|
+ ('\f@example.com', None),
|
||
|
+ (' @example.com', None),
|
||
|
+ ('\u0020@example.com', None),
|
||
|
+ ('\u001f@example.com', None),
|
||
|
+ ('"@example.com', None),
|
||
|
+ (',@example.com', None),
|
||
|
+ ('foobar <foobar<@example.com>', None),
|
||
|
+ ('foobar <foobar@example.com>>', None),
|
||
|
+ ('foobar <<foobar<@example.com>', None),
|
||
|
+ ('foobar <>', None),
|
||
|
+ ('first.last <first.last@example.com>', None),
|
||
|
+ pytest.param('foobar <' + 'a' * 4096 + '@example.com>', 'Length must not exceed 2048 characters', id='long'),
|
||
|
],
|
||
|
)
|
||
|
-def test_address_invalid(value):
|
||
|
- with pytest.raises(ValueError):
|
||
|
+def test_address_invalid(value: str, reason: Union[str, None]):
|
||
|
+ with pytest.raises(EmailError):
|
||
|
validate_email(value)
|
||
|
|
||
|
|