From 707c57c6f0988f52e46504dddb994d53317ffb87 Mon Sep 17 00:00:00 2001
From: Claude Paroz <claude@2xlibre.net>
Date: Sun, 14 Oct 2012 22:51:45 +0200
Subject: [PATCH] Validate email addresses with localhost as domain.
---
django/core/validators.py | 58 +++++++++++++++++++++++-----------
tests/modeltests/validators/tests.py | 1 +
2 files changed, 40 insertions(+), 19 deletions(-)
diff --git a/django/core/validators.py b/django/core/validators.py
index 251b5d8..a407c4f 100644
a
|
b
|
def validate_integer(value):
|
78 | 78 | raise ValidationError('') |
79 | 79 | |
80 | 80 | |
81 | | class EmailValidator(RegexValidator): |
| 81 | class EmailValidator(object): |
| 82 | message = _('Enter a valid e-mail address.') |
| 83 | code = 'invalid' |
| 84 | user_regex = re.compile( |
| 85 | r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*$" # dot-atom |
| 86 | r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"$)', # quoted-string |
| 87 | re.IGNORECASE) |
| 88 | domain_regex = re.compile( |
| 89 | r'(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?$)' # domain |
| 90 | # literal form, ipv4 address (SMTP 4.1.3) |
| 91 | r'|^\[(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\]$', |
| 92 | re.IGNORECASE) |
| 93 | domain_whitelist = ['localhost'] |
| 94 | |
| 95 | def __init__(self, message=None, code=None, whitelist=None): |
| 96 | if message is not None: |
| 97 | self.message = message |
| 98 | if code is not None: |
| 99 | self.code = code |
| 100 | if whitelist is not None: |
| 101 | self.domain_whitelist = whitelist |
82 | 102 | |
83 | 103 | def __call__(self, value): |
84 | | try: |
85 | | super(EmailValidator, self).__call__(value) |
86 | | except ValidationError as e: |
87 | | # Trivial case failed. Try for possible IDN domain-part |
88 | | if value and '@' in value: |
89 | | parts = value.split('@') |
| 104 | value = force_text(value) |
| 105 | if value and '@' in value: |
| 106 | user_part, domain_part = value.split('@', 1) |
| 107 | if not self.user_regex.match(user_part): |
| 108 | raise ValidationError(self.message, code=self.code) |
| 109 | if (not domain_part in self.domain_whitelist and |
| 110 | not self.domain_regex.match(domain_part)): |
| 111 | # Try for possible IDN domain-part |
90 | 112 | try: |
91 | | parts[-1] = parts[-1].encode('idna').decode('ascii') |
| 113 | domain_part = domain_part.encode('idna').decode('ascii') |
| 114 | if not self.domain_regex.match(domain_part): |
| 115 | raise ValidationError(self.message, code=self.code) |
| 116 | else: |
| 117 | return |
92 | 118 | except UnicodeError: |
93 | | raise e |
94 | | super(EmailValidator, self).__call__('@'.join(parts)) |
95 | | else: |
96 | | raise |
| 119 | pass |
| 120 | raise ValidationError(self.message, code=self.code) |
| 121 | else: |
| 122 | raise ValidationError(self.message, code=self.code) |
97 | 123 | |
98 | | email_re = re.compile( |
99 | | r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom |
100 | | # quoted-string, see also http://tools.ietf.org/html/rfc2822#section-3.2.5 |
101 | | r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"' |
102 | | r')@((?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)$)' # domain |
103 | | r'|\[(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\]$', re.IGNORECASE) # literal form, ipv4 address (SMTP 4.1.3) |
104 | | validate_email = EmailValidator(email_re, _('Enter a valid email address.'), 'invalid') |
| 124 | validate_email = EmailValidator() |
105 | 125 | |
106 | 126 | slug_re = re.compile(r'^[-a-zA-Z0-9_]+$') |
107 | 127 | validate_slug = RegexValidator(slug_re, _("Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens."), 'invalid') |
diff --git a/tests/modeltests/validators/tests.py b/tests/modeltests/validators/tests.py
index 0174a60..404bab6 100644
a
|
b
|
TEST_DATA = (
|
29 | 29 | (validate_email, 'example@valid-----hyphens.com', None), |
30 | 30 | (validate_email, 'example@valid-with-hyphens.com', None), |
31 | 31 | (validate_email, 'test@domain.with.idn.tld.उदाहरण.परीक्षा', None), |
| 32 | (validate_email, 'email@localhost', None), |
32 | 33 | |
33 | 34 | (validate_email, None, ValidationError), |
34 | 35 | (validate_email, '', ValidationError), |