summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChaitanya Rahalkar <chaitanyarahalkar4@gmail.com>2024-12-17 23:17:17 -0600
committerSarah Boyce <42296566+sarahboyce@users.noreply.github.com>2025-01-08 10:20:11 +0100
commitc068f000be7c486abb8b17fc565383679d7d4f82 (patch)
tree0ee3fc0e65ba54008f1d786735ea6ed4b36e429d
parent53e21eebf22bc05c7fa30820b453b7f345b7af40 (diff)
Fixed #36014 -- Supported international domains in EmailValidator.
-rw-r--r--django/core/validators.py20
-rw-r--r--tests/forms_tests/field_tests/test_emailfield.py3
-rw-r--r--tests/validators/tests.py14
3 files changed, 23 insertions, 14 deletions
diff --git a/django/core/validators.py b/django/core/validators.py
index c4e734c1d8..ff9573b172 100644
--- a/django/core/validators.py
+++ b/django/core/validators.py
@@ -6,7 +6,6 @@ from urllib.parse import urlsplit
from django.core.exceptions import ValidationError
from django.utils.deconstruct import deconstructible
-from django.utils.encoding import punycode
from django.utils.ipv6 import is_valid_ipv6_address
from django.utils.regex_helper import _lazy_re_compile
from django.utils.translation import gettext_lazy as _
@@ -76,14 +75,14 @@ class DomainNameValidator(RegexValidator):
# Max length for domain name labels is 63 characters per RFC 1034 sec. 3.1.
domain_re = r"(?:\.(?!-)[a-z" + ul + r"0-9-]{1,63}(?<!-))*"
# Top-level domain.
- tld_re = (
+ tld_no_fqdn_re = (
r"\." # dot
r"(?!-)" # can't start with a dash
r"(?:[a-z" + ul + "-]{2,63}" # domain label
r"|xn--[a-z0-9]{1,59})" # or punycode label
r"(?<!-)" # can't end with a dash
- r"\.?" # may have a trailing dot
)
+ tld_re = tld_no_fqdn_re + r"\.?"
ascii_only_hostname_re = r"[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?"
ascii_only_domain_re = r"(?:\.(?!-)[a-zA-Z0-9-]{1,63}(?<!-))*"
ascii_only_tld_re = (
@@ -210,6 +209,10 @@ def validate_integer(value):
class EmailValidator:
message = _("Enter a valid email address.")
code = "invalid"
+ hostname_re = DomainNameValidator.hostname_re
+ domain_re = DomainNameValidator.domain_re
+ tld_no_fqdn_re = DomainNameValidator.tld_no_fqdn_re
+
user_regex = _lazy_re_compile(
# dot-atom
r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*\Z"
@@ -219,8 +222,7 @@ class EmailValidator:
re.IGNORECASE,
)
domain_regex = _lazy_re_compile(
- # max length for domain name labels is 63 characters per RFC 1034
- r"((?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+)(?:[A-Z0-9-]{2,63}(?<!-))\Z",
+ r"^" + hostname_re + domain_re + tld_no_fqdn_re + r"\Z",
re.IGNORECASE,
)
literal_regex = _lazy_re_compile(
@@ -252,14 +254,6 @@ class EmailValidator:
if domain_part not in self.domain_allowlist and not self.validate_domain_part(
domain_part
):
- # Try for possible IDN domain-part
- try:
- domain_part = punycode(domain_part)
- except UnicodeError:
- pass
- else:
- if self.validate_domain_part(domain_part):
- return
raise ValidationError(self.message, code=self.code, params={"value": value})
def validate_domain_part(self, domain_part):
diff --git a/tests/forms_tests/field_tests/test_emailfield.py b/tests/forms_tests/field_tests/test_emailfield.py
index 601318bae3..cfebf4216d 100644
--- a/tests/forms_tests/field_tests/test_emailfield.py
+++ b/tests/forms_tests/field_tests/test_emailfield.py
@@ -31,7 +31,8 @@ class EmailFieldTest(FormFieldAssertionsMixin, SimpleTestCase):
# Check for runaway regex security problem. This will take a long time
# if the security fix isn't in place.
addr = "viewx3dtextx26qx3d@yahoo.comx26latlngx3d15854521645943074058"
- self.assertEqual(addr, f.clean(addr))
+ with self.assertRaisesMessage(ValidationError, "Enter a valid email address."):
+ f.clean(addr)
def test_emailfield_not_required(self):
f = EmailField(required=False)
diff --git a/tests/validators/tests.py b/tests/validators/tests.py
index 7455c93d40..acd867c545 100644
--- a/tests/validators/tests.py
+++ b/tests/validators/tests.py
@@ -319,6 +319,20 @@ TEST_DATA = [
(validate_email, "example@inv-.alid-.com", ValidationError),
(validate_email, "example@inv-.-alid.com", ValidationError),
(validate_email, 'test@example.com\n\n<script src="x.js">', ValidationError),
+ (validate_email, "email@xn--4ca9at.com", None),
+ (validate_email, "email@öäü.com", None),
+ (validate_email, "email@עִתוֹן.example.il", None),
+ (validate_email, "email@މިހާރު.example.mv", None),
+ (validate_email, "email@漢字.example.com", None),
+ (validate_email, "editor@މިހާރު.example.mv", None),
+ (validate_email, "@domain.com", ValidationError),
+ (validate_email, "email.domain.com", ValidationError),
+ (validate_email, "email@domain@domain.com", ValidationError),
+ (validate_email, "email@domain..com", ValidationError),
+ (validate_email, "email@.domain.com", ValidationError),
+ (validate_email, "email@-domain.com", ValidationError),
+ (validate_email, "email@domain-.com", ValidationError),
+ (validate_email, "email@domain.com-", ValidationError),
# Quoted-string format (CR not allowed)
(validate_email, '"\\\011"@here.com', None),
(validate_email, '"\\\012"@here.com', ValidationError),