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), |