diff --git a/qiita_db/test/test_user.py b/qiita_db/test/test_user.py index 3c2c4c502..b90917ee2 100644 --- a/qiita_db/test/test_user.py +++ b/qiita_db/test/test_user.py @@ -43,7 +43,7 @@ def test_validate_email(self): valid3 = 'w00t@123.456.789.com' invalid1 = '@stuff.com' invalid2 = 'asdasdásd@things.com' - invalid3 = 'asdas@com' + invalid3 = '.asdas@com' self.assertTrue(validate_email(valid1)) self.assertTrue(validate_email(valid2)) @@ -180,9 +180,9 @@ def test_exists(self): def test_exists_notindb(self): self.assertFalse(User.exists("notexist@foo.bar")) - def test_exists_invaid_email(self): + def test_exists_invalid_email(self): with self.assertRaises(IncorrectEmailError): - User.exists("notanemail@badformat") + User.exists("notanemail.@badformat") def test_get_email(self): self.assertEqual(self.user.email, 'admin@foo.bar') diff --git a/qiita_db/user.py b/qiita_db/user.py index 58a570469..99ecc1fb6 100644 --- a/qiita_db/user.py +++ b/qiita_db/user.py @@ -28,7 +28,7 @@ # The full license is in the file LICENSE, distributed with this software. # ----------------------------------------------------------------------------- from __future__ import division -from re import match +from re import sub from qiita_core.exceptions import (IncorrectEmailError, IncorrectPasswordError, IncompetentQiitaDeveloperError) @@ -461,10 +461,18 @@ def validate_email(email): Notes ----- - A valid email must be of the form "string AT string" where the first string - must be not empty, and consists of [a-zA-Z0-9.+]. The AT is the '@' symbol. - The second string must be not empty, consist of [a-zA-Z0-9.], and is - required to have at least one '.'. + An email address is of the form local-part@domain_part + For our purposes: + + - No quoted strings are allowed + - No unicode strings are allowed + - There must be exactly one @ symbol + - Neither local-part nor domain-part can be blank + - The local-part cannot start or end with a dot + - The local-part must be composed of the following characters: + a-zA-Z0-9#_~!$&'()*+,;=:.- + - The domain-part must be a valid hostname, composed of: + a-zA-Z0-9. Parameters ---------- @@ -476,15 +484,40 @@ def validate_email(email): bool Whether or not the email is valid """ - valid_chars = "a-zA-Z0-9\.\+\-" - pattern = r"[%s]+@[%s]+\.[%s]+" % (valid_chars, valid_chars, valid_chars) - + # Do not accept email addresses that have unicode characters try: email.encode('ascii') except UnicodeError: return False - return True if match(pattern, email) is not None else False + # we are not allowing quoted strings in the email address + if '"' in email: + return False + + # Must have exactly 1 @ symbol + if email.count('@') != 1: + return False + + local_part, domain_part = email.split('@') + + # Neither part can be blank + if not (local_part and domain_part): + return False + + # The local part cannot begin or end with a dot + if local_part.startswith('.') or local_part.endswith('.'): + return False + + # This is the full set of allowable characters for the local part. + local_valid_chars = "[a-zA-Z0-9#_~!$&'()*+,;=:.-]" + if len(sub(local_valid_chars, '', local_part)): + return False + + domain_valid_chars = "[a-zA-Z0-9.]" + if len(sub(domain_valid_chars, '', domain_part)): + return False + + return True def validate_password(password):