Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions tests/test_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
[
Expand Down
6 changes: 4 additions & 2 deletions tortoise/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
Expand Down Expand Up @@ -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()


Expand Down
Loading