diff --git a/tests/test_validators.py b/tests/test_validators.py index 57073b934..b20c82d01 100644 --- a/tests/test_validators.py +++ b/tests/test_validators.py @@ -263,6 +263,21 @@ def test_email_validator_invalid_allowed_domains(): validator("user@invalid..com") +def test_email_validator_rejects_domain_outside_allowed_domains(): + # a well-formed address whose domain is not allowlisted must be rejected + validator = EmailValidator(allowed_domains=["example.com"]) + with pytest.raises(InvalidEmailAddress): + validator("attacker@evil.com") + with pytest.raises(InvalidEmailAddress): + validator("user@totally-unrelated.co.uk") + + +def test_email_validator_allowed_domains_bypass_domain_syntax(): + # an allowlisted domain is accepted even if it is not a valid public domain + validator = EmailValidator(allowed_domains=["localhost"]) + validator("user@localhost") + + @pytest.mark.parametrize( "value", [ diff --git a/tortoise/validators.py b/tortoise/validators.py index d2d0ae055..6083e9965 100644 --- a/tortoise/validators.py +++ b/tortoise/validators.py @@ -324,7 +324,6 @@ def _user_regex(self) -> re.Pattern[str]: @cached_property def _domain_regex(self) -> re.Pattern[str]: - print("evaluating domain regex!!!") return re.compile( r"^" + HOSTNAME_REGEX + DOMAIN_REGEX + TLD_NO_FQDN_REGEX + r"\Z", re.IGNORECASE ) @@ -358,7 +357,10 @@ def __call__(self, value: str) -> None: if not self._user_regex.match(user_part): raise InvalidEmailAddress() - if domain_part not in self.allowed_domains and not self._validate_domain_part(domain_part): + if self.allowed_domains: + if domain_part not in self.allowed_domains: + raise InvalidEmailAddress() + elif not self._validate_domain_part(domain_part): raise InvalidEmailAddress()