From 41371e5fc5a751446fa98939eb562a8d6c022244 Mon Sep 17 00:00:00 2001 From: Stefan Wojcik Date: Mon, 10 Apr 2017 10:00:49 -0400 Subject: [PATCH] empty whitelist by default + allow_ip_domain option --- mongoengine/fields.py | 23 ++++++------- tests/document/instance.py | 2 +- tests/fields/fields.py | 67 +++++++++++++++++++++++++++++--------- 3 files changed, 64 insertions(+), 28 deletions(-) diff --git a/mongoengine/fields.py b/mongoengine/fields.py index d364185d..2c583551 100644 --- a/mongoengine/fields.py +++ b/mongoengine/fields.py @@ -177,27 +177,24 @@ class EmailField(StringField): re.IGNORECASE ) - domain_whitelist = ['localhost'] - error_msg = u'Invalid email address: %s' - def __init__(self, domain_whitelist=None, allow_utf8_user=False, *args, - **kwargs): + def __init__(self, domain_whitelist=None, allow_utf8_user=False, + allow_ip_domain=False, *args, **kwargs): """Initialize the EmailField. Args: domain_whitelist (list) - list of otherwise invalid domain names which you'd like to support. - Includes "localhost" by default. allow_utf8_user (bool) - if True, the user part of the email address can contain UTF8 characters. False by default. + allow_ip_domain (bool) - if True, the domain part of the email + can be a valid IPv4 or IPv6 address. """ - if domain_whitelist is not None: - self.domain_whitelist = domain_whitelist - + self.domain_whitelist = domain_whitelist or [] self.allow_utf8_user = allow_utf8_user - + self.allow_ip_domain = allow_ip_domain super(EmailField, self).__init__(*args, **kwargs) def validate_user_part(self, user_part): @@ -220,8 +217,12 @@ class EmailField(StringField): return True # Validate IPv4/IPv6, e.g. user@[192.168.0.1] - if domain_part[0] == '[' and domain_part[-1] == ']': - for addr_family in socket.AF_INET, socket.AF_INET6: + if ( + self.allow_ip_domain and + domain_part[0] == '[' and + domain_part[-1] == ']' + ): + for addr_family in (socket.AF_INET, socket.AF_INET6): try: socket.inet_pton(addr_family, domain_part[1:-1]) return True diff --git a/tests/document/instance.py b/tests/document/instance.py index 78d326fc..c59de96f 100644 --- a/tests/document/instance.py +++ b/tests/document/instance.py @@ -844,7 +844,7 @@ class InstanceTest(unittest.TestCase): class Recipient(Document): email = EmailField(required=True) - recipient = Recipient(email='root@localhost') + recipient = Recipient(email='not-an-email') self.assertRaises(ValidationError, recipient.save) recipient.save(validate=False) diff --git a/tests/fields/fields.py b/tests/fields/fields.py index 78c1ccb5..87a1a21a 100644 --- a/tests/fields/fields.py +++ b/tests/fields/fields.py @@ -3468,22 +3468,6 @@ class FieldTest(MongoDBTestCase): user = User(email='ross@example.com.') self.assertRaises(ValidationError, user.validate) - # localhost should be whitelisted by default - user = User(email='me@localhost') - user.validate() - - # valid IPv4 domain - user = User(email='email@[127.0.0.1]') - user.validate() - - # valid IPv6 domain - user = User(email='email@[2001:dB8::1]') - user.validate() - - # invalid IP - user = User(email='email@[324.0.0.1]') - self.assertRaises(ValidationError, user.validate) - # unicode domain user = User(email=u'user@пример.рф') user.validate() @@ -3492,6 +3476,10 @@ class FieldTest(MongoDBTestCase): user = User(email=u'user@пример') self.assertRaises(ValidationError, user.validate) + def test_email_field_unicode_user(self): + class User(Document): + email = EmailField() + # unicode user shouldn't validate by default... user = User(email=u'Dörte@Sörensen.example.com') self.assertRaises(ValidationError, user.validate) @@ -3503,6 +3491,53 @@ class FieldTest(MongoDBTestCase): user = User(email=u'Dörte@Sörensen.example.com') user.validate() + def test_email_field_domain_whitelist(self): + class User(Document): + email = EmailField() + + # localhost domain shouldn't validate by default... + user = User(email='me@localhost') + self.assertRaises(ValidationError, user.validate) + + # ...but it should be fine if it's whitelisted + class User(Document): + email = EmailField(domain_whitelist=['localhost']) + + user = User(email='me@localhost') + user.validate() + + def test_email_field_ip_domain(self): + class User(Document): + email = EmailField() + + valid_ipv4 = 'email@[127.0.0.1]' + valid_ipv6 = 'email@[2001:dB8::1]' + invalid_ip = 'email@[324.0.0.1]' + + # IP address as a domain shouldn't validate by default... + user = User(email=valid_ipv4) + self.assertRaises(ValidationError, user.validate) + + user = User(email=valid_ipv6) + self.assertRaises(ValidationError, user.validate) + + user = User(email=invalid_ip) + self.assertRaises(ValidationError, user.validate) + + # ...but it should be fine with allow_ip_domain set to True + class User(Document): + email = EmailField(allow_ip_domain=True) + + user = User(email=valid_ipv4) + user.validate() + + user = User(email=valid_ipv6) + user.validate() + + # invalid IP should still fail validation + user = User(email=invalid_ip) + self.assertRaises(ValidationError, user.validate) + def test_email_field_honors_regex(self): class User(Document): email = EmailField(regex=r'\w+@example.com')