From 325207d6ba6e9e7d0161a843722d91794f79472a Mon Sep 17 00:00:00 2001 From: Son Date: Mon, 3 Jan 2022 10:33:21 +0100 Subject: [PATCH] Use InvalidMailboxDomain instead of DISPOSABLE_EMAIL_DOMAINS --- app/config.py | 6 ------ app/email_utils.py | 26 +++++++++++++++----------- init_app.py | 26 ++++++++++++++++++++++++-- tests/test_email_utils.py | 21 ++++++++++++++++++++- 4 files changed, 59 insertions(+), 20 deletions(-) diff --git a/app/config.py b/app/config.py index 52e4fe02..cdb54dd5 100644 --- a/app/config.py +++ b/app/config.py @@ -293,12 +293,6 @@ DISPOSABLE_FILE_PATH = get_abs_path( os.environ.get("DISPOSABLE_FILE_PATH", "local_data/local_disposable_domains.txt") ) -with open(get_abs_path(DISPOSABLE_FILE_PATH), "r") as f: - DISPOSABLE_EMAIL_DOMAINS = f.readlines() - DISPOSABLE_EMAIL_DOMAINS = [d.strip().lower() for d in DISPOSABLE_EMAIL_DOMAINS] - DISPOSABLE_EMAIL_DOMAINS = [ - d for d in DISPOSABLE_EMAIL_DOMAINS if not d.startswith("#") - ] # Used when querying info on Apple API # for iOS App diff --git a/app/email_utils.py b/app/email_utils.py index 8a07e8be..ea992936 100644 --- a/app/email_utils.py +++ b/app/email_utils.py @@ -42,7 +42,6 @@ from app.config import ( SUPPORT_NAME, POSTFIX_SUBMISSION_TLS, MAX_NB_EMAIL_FREE_PLAN, - DISPOSABLE_EMAIL_DOMAINS, MAX_ALERT_24H, POSTFIX_PORT, URL, @@ -70,6 +69,7 @@ from app.models import ( EmailLog, TransactionalEmail, IgnoreBounceSender, + InvalidMailboxDomain, ) from app.utils import ( random_string, @@ -548,8 +548,8 @@ def email_can_be_used_as_mailbox(email_address: str) -> bool: LOG.d("domain %s is a SimpleLogin custom domain", domain) return False - if is_disposable_domain(domain): - LOG.d("Domain %s is disposable", domain) + if is_invalid_mailbox_domain(domain): + LOG.d("Domain %s is invalid mailbox domain", domain) return False # check if email MX domain is disposable @@ -561,19 +561,23 @@ def email_can_be_used_as_mailbox(email_address: str) -> bool: return False for mx_domain in mx_domains: - if is_disposable_domain(mx_domain): - LOG.d("MX Domain %s %s is disposable", mx_domain, domain) + if is_invalid_mailbox_domain(mx_domain): + LOG.d("MX Domain %s %s is invalid mailbox domain", mx_domain, domain) return False return True -def is_disposable_domain(domain): - for d in DISPOSABLE_EMAIL_DOMAINS: - if domain == d: - return True - # subdomain - if domain.endswith("." + d): +def is_invalid_mailbox_domain(domain): + """ + Whether a domain is invalid mailbox domain + Also return True if `domain` is a subdomain of an invalid mailbox domain + """ + parts = domain.split(".") + for i in range(0, len(parts) - 1): + parent_domain = ".".join(parts[i:]) + + if InvalidMailboxDomain.get_by(domain=parent_domain): return True return False diff --git a/init_app.py b/init_app.py index ce2c08d5..36d6e3a5 100644 --- a/init_app.py +++ b/init_app.py @@ -1,7 +1,12 @@ -from app.config import ALIAS_DOMAINS, PREMIUM_ALIAS_DOMAINS +from app.config import ( + ALIAS_DOMAINS, + PREMIUM_ALIAS_DOMAINS, + get_abs_path, + DISPOSABLE_FILE_PATH, +) from app.db import Session from app.log import LOG -from app.models import Mailbox, Contact, SLDomain +from app.models import Mailbox, Contact, SLDomain, InvalidMailboxDomain from app.pgp_utils import load_public_key from server import create_light_app @@ -50,8 +55,25 @@ def add_sl_domains(): Session.commit() +def add_invalid_mailbox_domains(): + with open(get_abs_path(DISPOSABLE_FILE_PATH), "r") as f: + disposable_email_domains = f.readlines() + disposable_email_domains = [d.strip().lower() for d in disposable_email_domains] + disposable_email_domains = [ + d for d in disposable_email_domains if not d.startswith("#") + ] + + for domain in disposable_email_domains: + if InvalidMailboxDomain.get_by(domain=domain) is None: + LOG.i("Add disposable domain %s as invalid mailbox domain", domain) + InvalidMailboxDomain.create(domain=domain) + + Session.commit() + + if __name__ == "__main__": # wrap in an app context to benefit from app setup like database cleanup, sentry integration, etc with create_light_app().app_context(): load_pgp_public_keys() add_sl_domains() + add_invalid_mailbox_domains() diff --git a/tests/test_email_utils.py b/tests/test_email_utils.py index 0d2e93dd..642819f1 100644 --- a/tests/test_email_utils.py +++ b/tests/test_email_utils.py @@ -35,8 +35,17 @@ from app.email_utils import ( parse_full_address, get_orig_message_from_bounce, get_mailbox_bounce_info, + is_invalid_mailbox_domain, +) +from app.models import ( + User, + CustomDomain, + Alias, + Contact, + EmailLog, + IgnoreBounceSender, + InvalidMailboxDomain, ) -from app.models import User, CustomDomain, Alias, Contact, EmailLog, IgnoreBounceSender # flake8: noqa: E101, W191 from tests.utils import login @@ -766,3 +775,13 @@ def test_get_mailbox_bounce_info(): orig_msg = get_mailbox_bounce_info(bounce_report) assert orig_msg["Final-Recipient"] == "rfc822; not-existing@gmail.com" assert orig_msg["Original-Recipient"] == "rfc822;not-existing@gmail.com" + + +def test_is_invalid_mailbox_domain(flask_client): + InvalidMailboxDomain.create(domain="ab.cd", commit=True) + + assert is_invalid_mailbox_domain("ab.cd") + assert is_invalid_mailbox_domain("sub.ab.cd") + assert is_invalid_mailbox_domain("sub1.sub2.ab.cd") + + assert not is_invalid_mailbox_domain("xy.zt")