From ad622df071ecd375f81644f3f3042ccda8a0d11c Mon Sep 17 00:00:00 2001 From: Son Date: Fri, 7 Jan 2022 10:04:12 +0100 Subject: [PATCH] make sure a contact with website_email=reverse alias of another contact can't be created --- app/dashboard/views/alias_contact_manager.py | 7 ++- app/errors.py | 6 +++ app/models.py | 48 +++++++++++++++++--- email_handler.py | 12 +++-- 4 files changed, 61 insertions(+), 12 deletions(-) diff --git a/app/dashboard/views/alias_contact_manager.py b/app/dashboard/views/alias_contact_manager.py index 5d6930e5..2bae5b20 100644 --- a/app/dashboard/views/alias_contact_manager.py +++ b/app/dashboard/views/alias_contact_manager.py @@ -220,7 +220,12 @@ def alias_contact_manager(alias_id): reply_email=generate_reply_email(contact_email, current_user), ) - LOG.d("create reverse-alias for %s", contact_addr) + LOG.d( + "create reverse-alias for %s %s, reverse alias:%s", + contact_addr, + alias, + contact.reply_email, + ) Session.commit() flash(f"Reverse alias for {contact_addr} is created", "success") diff --git a/app/errors.py b/app/errors.py index 3fa14abd..2c2e17c7 100644 --- a/app/errors.py +++ b/app/errors.py @@ -14,3 +14,9 @@ class SubdomainInTrashError(Exception): """raised when a subdomain is deleted before """ pass + + +class CannotCreateContactForReverseAlias(Exception): + """raised when a contact is created that has website_email=reverse_alias of another contact""" + + pass diff --git a/app/models.py b/app/models.py index 95fdc182..d0b4b109 100644 --- a/app/models.py +++ b/app/models.py @@ -35,7 +35,12 @@ from app.config import ( MAX_NB_DIRECTORY, ) from app.db import Session -from app.errors import AliasInTrashError, DirectoryInTrashError, SubdomainInTrashError +from app.errors import ( + AliasInTrashError, + DirectoryInTrashError, + SubdomainInTrashError, + CannotCreateContactForReverseAlias, +) from app.log import LOG from app.oauth_models import Scope from app.pw_models import PasswordOracle @@ -109,7 +114,7 @@ class ModelMixin(object): @classmethod def create(cls, **kw): - # whether should call Session.commit + # whether to call Session.commit commit = kw.pop("commit", False) flush = kw.pop("flush", False) @@ -1264,8 +1269,9 @@ class Alias(Base, ModelMixin): @classmethod def create(cls, **kw): commit = kw.pop("commit", False) + flush = kw.pop("flush", False) - r = cls(**kw) + new_alias = cls(**kw) email = kw["email"] # make sure email is lowercase and doesn't have any whitespace @@ -1282,12 +1288,17 @@ class Alias(Base, ModelMixin): if "custom_domain_id" not in kw: custom_domain = Alias.get_custom_domain(email) if custom_domain: - r.custom_domain_id = custom_domain.id + new_alias.custom_domain_id = custom_domain.id + + Session.add(new_alias) - Session.add(r) if commit: Session.commit() - return r + + if flush: + Session.flush() + + return new_alias @classmethod def create_new(cls, user, prefix, note=None, mailbox_id=None): @@ -1534,6 +1545,31 @@ class Contact(Base, ModelMixin): def email(self): return self.website_email + @classmethod + def create(cls, **kw): + commit = kw.pop("commit", False) + flush = kw.pop("flush", False) + + new_contact = cls(**kw) + + website_email = kw["website_email"] + # make sure email is lowercase and doesn't have any whitespace + website_email = sanitize_email(website_email) + + # make sure alias is not in global trash, i.e. DeletedAlias table + if Contact.get_by(reply_email=website_email): + raise CannotCreateContactForReverseAlias + + Session.add(new_contact) + + if commit: + Session.commit() + + if flush: + Session.flush() + + return new_contact + def website_send_to(self): """return the email address with name. to use when user wants to send an email from the alias diff --git a/email_handler.py b/email_handler.py index a79a41e2..ad8f8473 100644 --- a/email_handler.py +++ b/email_handler.py @@ -204,11 +204,6 @@ def get_or_create_contact(from_header: str, mail_from: str, alias: Alias) -> Con contact.mail_from = mail_from Session.commit() else: - LOG.d( - "create contact %s for alias %s", - contact_email, - alias, - ) try: contact = Contact.create( @@ -225,6 +220,13 @@ def get_or_create_contact(from_header: str, mail_from: str, alias: Alias) -> Con LOG.d("Create a contact with invalid email for %s", alias) contact.invalid_email = True + LOG.d( + "create contact %s for %s, reverse alias:%s", + contact_email, + alias, + contact.reply_email, + ) + Session.commit() except IntegrityError: LOG.w("Contact %s %s already exist", alias, contact_email)