Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: follow mx records back to pointers #16814

Merged
merged 4 commits into from
Oct 10, 2024
Merged
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
1 change: 1 addition & 0 deletions requirements/main.in
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ click
cryptography>=43.0.1
datadog>=0.19.0
disposable-email-domains
dnspython
email-validator
first
forcediphttpsadapter
Expand Down
4 changes: 3 additions & 1 deletion requirements/main.txt
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,9 @@ disposable-email-domains==0.0.107 \
dnspython==2.7.0 \
--hash=sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86 \
--hash=sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1
# via email-validator
# via
# -r requirements/main.in
# email-validator
docutils==0.21.2 \
--hash=sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f \
--hash=sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2
Expand Down
18 changes: 17 additions & 1 deletion warehouse/accounts/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@

from __future__ import annotations

import contextlib
import json
import re

import disposable_email_domains
import dns.resolver
import email_validator
import humanize
import markupsafe
Expand Down Expand Up @@ -301,6 +303,20 @@ def validate_email(self, field):
for _prio, mx_host in resp.mx
}

# Resolve the returned MX domain's IP address to a PTR record, to a domain
all_mx_domains = set()
for mx_domain in mx_domains:
with contextlib.suppress(dns.resolver.NoAnswer, dns.resolver.NXDOMAIN):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this cover slow/broken responses? Do we need to wrap this in some kind of timeout?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm reading the source of dnspython correctly, when it's initialized it sets a default timeout of 2 seconds. https://github.com/rthalley/dnspython/blob/889385e71021f53e1dc4f117d92aed66bb90d087/dns/resolver.py#L958

mx_ip = dns.resolver.resolve(mx_domain, "A")
mx_ptr = dns.resolver.resolve_address(mx_ip[0].address)
mx_ptr_domain = extractor(
mx_ptr[0].target.to_text().lower()
).registered_domain
all_mx_domains.add(mx_ptr_domain)

# combine both sets
all_mx_domains.update(mx_domains)

if (
domain in disposable_email_domains.blocklist
or self.request.db.query(
Expand All @@ -309,7 +325,7 @@ def validate_email(self, field):
& (ProhibitedEmailDomain.is_mx_record == False) # noqa: E712
)
| exists().where(
(ProhibitedEmailDomain.domain.in_(mx_domains))
(ProhibitedEmailDomain.domain.in_(all_mx_domains))
& (ProhibitedEmailDomain.is_mx_record == True) # noqa: E712
)
).scalar()
Expand Down
48 changes: 24 additions & 24 deletions warehouse/locale/messages.pot
Original file line number Diff line number Diff line change
Expand Up @@ -14,108 +14,108 @@ msgstr ""
msgid "Locale updated"
msgstr ""

#: warehouse/accounts/forms.py:52 warehouse/accounts/forms.py:290
#: warehouse/accounts/forms.py:54 warehouse/accounts/forms.py:292
msgid "The email address isn't valid. Try again."
msgstr ""

#: warehouse/accounts/forms.py:53
#: warehouse/accounts/forms.py:55
msgid "The password is invalid. Try again."
msgstr ""

#: warehouse/accounts/forms.py:54
#: warehouse/accounts/forms.py:56
msgid ""
"The username is invalid. Usernames must be composed of letters, numbers, "
"dots, hyphens and underscores. And must also start and finish with a "
"letter or number. Choose a different username."
msgstr ""

#: warehouse/accounts/forms.py:72
#: warehouse/accounts/forms.py:74
msgid "Null bytes are not allowed."
msgstr ""

#: warehouse/accounts/forms.py:86
#: warehouse/accounts/forms.py:88
msgid "No user found with that username"
msgstr ""

#: warehouse/accounts/forms.py:106
#: warehouse/accounts/forms.py:108
msgid "TOTP code must be ${totp_length} digits."
msgstr ""

#: warehouse/accounts/forms.py:126
#: warehouse/accounts/forms.py:128
msgid "Recovery Codes must be ${recovery_code_length} characters."
msgstr ""

#: warehouse/accounts/forms.py:141
#: warehouse/accounts/forms.py:143
msgid "Choose a username with 50 characters or less."
msgstr ""

#: warehouse/accounts/forms.py:158
#: warehouse/accounts/forms.py:160
msgid ""
"This username is already being used by another account. Choose a "
"different username."
msgstr ""

#: warehouse/accounts/forms.py:172 warehouse/accounts/forms.py:221
#: warehouse/accounts/forms.py:234
#: warehouse/accounts/forms.py:174 warehouse/accounts/forms.py:223
#: warehouse/accounts/forms.py:236
msgid "Password too long."
msgstr ""

#: warehouse/accounts/forms.py:208
#: warehouse/accounts/forms.py:210
msgid ""
"There have been too many unsuccessful login attempts. You have been "
"locked out for ${time}. Please try again later."
msgstr ""

#: warehouse/accounts/forms.py:237
#: warehouse/accounts/forms.py:239
msgid "Your passwords don't match. Try again."
msgstr ""

#: warehouse/accounts/forms.py:271
#: warehouse/accounts/forms.py:273
msgid "The email address is too long. Try again."
msgstr ""

#: warehouse/accounts/forms.py:322
#: warehouse/accounts/forms.py:338
msgid "You can't use an email address from this domain. Use a different email."
msgstr ""

#: warehouse/accounts/forms.py:337
#: warehouse/accounts/forms.py:353
msgid ""
"This email address is already being used by this account. Use a different"
" email."
msgstr ""

#: warehouse/accounts/forms.py:348
#: warehouse/accounts/forms.py:364
msgid ""
"This email address is already being used by another account. Use a "
"different email."
msgstr ""

#: warehouse/accounts/forms.py:388 warehouse/manage/forms.py:139
#: warehouse/accounts/forms.py:404 warehouse/manage/forms.py:139
#: warehouse/manage/forms.py:728
msgid "The name is too long. Choose a name with 100 characters or less."
msgstr ""

#: warehouse/accounts/forms.py:395
#: warehouse/accounts/forms.py:411
msgid "URLs are not allowed in the name field."
msgstr ""

#: warehouse/accounts/forms.py:484
#: warehouse/accounts/forms.py:500
msgid "Invalid TOTP code."
msgstr ""

#: warehouse/accounts/forms.py:501
#: warehouse/accounts/forms.py:517
msgid "Invalid WebAuthn assertion: Bad payload"
msgstr ""

#: warehouse/accounts/forms.py:570
#: warehouse/accounts/forms.py:586
msgid "Invalid recovery code."
msgstr ""

#: warehouse/accounts/forms.py:579
#: warehouse/accounts/forms.py:595
msgid "Recovery code has been previously used."
msgstr ""

#: warehouse/accounts/forms.py:609
#: warehouse/accounts/forms.py:625
msgid "The username isn't valid. Try again."
msgstr ""

Expand Down