summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mailman/email/validate.py15
-rw-r--r--src/mailman/model/tests/test_address.py36
2 files changed, 44 insertions, 7 deletions
diff --git a/src/mailman/email/validate.py b/src/mailman/email/validate.py
index 3d80b3a51..99371d9e5 100644
--- a/src/mailman/email/validate.py
+++ b/src/mailman/email/validate.py
@@ -26,10 +26,11 @@ from mailman.utilities.email import split_email
from zope.interface import implementer
-# What other characters should be disallowed?
-_badchars = re.compile(r'[][()<>|:;^,\\"\000-\037\177-\377]')
-# Strictly speaking, some of the above are allowed in quoted local parts, but
-# this can open the door to certain web exploits so we don't allow them.
+# What other characters should be allowed?
+_valid_local = re.compile("[-0-9a-z!#$%&'*+./=?@_`{}~]", re.IGNORECASE)
+# Strictly speaking, both ^ and | are allowed and others are allowed in quoted
+# local parts, but this can open the door to certain web exploits so we don't
+# allow them.
_valid_domain = re.compile('[-a-z0-9]', re.IGNORECASE)
# These are the only characters allowed in domain parts.
@@ -41,11 +42,11 @@ class Validator:
def is_valid(self, email):
"""See `IEmailValidator`."""
- if not email or ' ' in email:
- return False
- if _badchars.search(email):
+ if not email:
return False
user, domain_parts = split_email(email)
+ if not user or len(_valid_local.sub('', user)) > 0:
+ return False
# Local, unqualified addresses are not allowed.
if not domain_parts:
return False
diff --git a/src/mailman/model/tests/test_address.py b/src/mailman/model/tests/test_address.py
index 896310796..3336dcea6 100644
--- a/src/mailman/model/tests/test_address.py
+++ b/src/mailman/model/tests/test_address.py
@@ -40,6 +40,42 @@ class TestAddress(unittest.TestCase):
self.assertRaises(InvalidEmailAddressError,
Address, 'not_a_valid_email_string', '')
+ def test_no_local_email_string_raises_exception(self):
+ self.assertRaises(InvalidEmailAddressError,
+ Address, '@example.com', '')
+
+ def test_space_in_email_string_raises_exception(self):
+ self.assertRaises(InvalidEmailAddressError,
+ Address, 'us er@example.com', '')
+
+ def test_non_ascii_email_local_part_raises_exception(self):
+ self.assertRaises(InvalidEmailAddressError,
+ Address, 'us\xe9r@example.com', '')
+
+ def test_non_ascii_email_domain_raises_exception(self):
+ self.assertRaises(InvalidEmailAddressError,
+ Address, 'user@\xe9xample.com', '')
+
+ def test_leading_hyphen_email_domain_raises_exception(self):
+ self.assertRaises(InvalidEmailAddressError,
+ Address, 'user@example.-com', '')
+
+ def test_empty_part_email_domain_raises_exception(self):
+ self.assertRaises(InvalidEmailAddressError,
+ Address, 'user@example..com', '')
+
+ def test_bad_ascii_email_domain_raises_exception(self):
+ self.assertRaises(InvalidEmailAddressError,
+ Address, 'user@x_example.com', '')
+
+ def test_high_unicode_email_local_part_raises_exception(self):
+ self.assertRaises(InvalidEmailAddressError,
+ Address, 'us\u0117r@example.com', '')
+
+ def test_non_ascii_email_domain_raises_exception(self):
+ self.assertRaises(InvalidEmailAddressError,
+ Address, 'user@\u0117xample.com', '')
+
def test_local_part_differs_only_by_case(self):
with self.assertRaises(ExistingAddressError) as cm:
self._usermgr.create_address('fperson@example.com')