diff --git a/app/dashboard/templates/dashboard/domain_detail/info.html b/app/dashboard/templates/dashboard/domain_detail/info.html index 6274e85f..f279e91e 100644 --- a/app/dashboard/templates/dashboard/domain_detail/info.html +++ b/app/dashboard/templates/dashboard/domain_detail/info.html @@ -57,7 +57,7 @@
-
Default Alias name
+
Default Alias Name
This name will be used as the default alias name when you send or reply from an alias, unless overwritten by the alias specific name. @@ -76,6 +76,32 @@
+
+
Random Prefix Generation
+
+ A random prefix can be generated for this domain for usage in the New Alias + feature. +
+ +
+
+ + +
+
+

Delete Domain

Please note that this operation is irreversible. @@ -119,4 +145,4 @@ }) }); -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/app/dashboard/views/custom_alias.py b/app/dashboard/views/custom_alias.py index 55ad0f6a..ad89c0f4 100644 --- a/app/dashboard/views/custom_alias.py +++ b/app/dashboard/views/custom_alias.py @@ -8,7 +8,6 @@ from app.config import ( CUSTOM_ALIAS_SECRET, ) from app.dashboard.base import dashboard_bp -from app.email_utils import email_belongs_to_alias_domains from app.extensions import db from app.log import LOG from app.models import ( @@ -27,15 +26,19 @@ signer = TimestampSigner(CUSTOM_ALIAS_SECRET) def available_suffixes(user: User) -> [bool, str, str]: """Return (is_custom_domain, alias-suffix, time-signed alias-suffix)""" - user_custom_domains = [cd.domain for cd in user.verified_custom_domains()] + user_custom_domains = user.verified_custom_domains() # List of (is_custom_domain, alias-suffix, time-signed alias-suffix) suffixes = [] # put custom domain first + # for each user domain, generate both the domain and a random suffix version for alias_domain in user_custom_domains: - suffix = "@" + alias_domain + suffix = "@" + alias_domain.domain suffixes.append((True, suffix, signer.sign(suffix).decode())) + if alias_domain.random_prefix_generation: + suffix = "." + random_word() + "@" + alias_domain.domain + suffixes.append((True, suffix, signer.sign(suffix).decode())) # then default domain for domain in ALIAS_DOMAINS: @@ -193,35 +196,23 @@ def verify_prefix_suffix(user, alias_prefix, alias_suffix) -> bool: # make sure alias_suffix is either .random_word@simplelogin.co or @my-domain.com alias_suffix = alias_suffix.strip() - if alias_suffix.startswith("@"): - alias_domain = alias_suffix[1:] - # alias_domain can be either custom_domain or if DISABLE_ALIAS_SUFFIX, one of the default ALIAS_DOMAINS - if DISABLE_ALIAS_SUFFIX: - if ( - alias_domain not in user_custom_domains - and alias_domain not in ALIAS_DOMAINS - ): - LOG.exception("wrong alias suffix %s, user %s", alias_suffix, user) - return False - else: - if alias_domain not in user_custom_domains: - LOG.exception("wrong alias suffix %s, user %s", alias_suffix, user) - return False - else: - if not alias_suffix.startswith("."): + # alias_domain_prefix is either a .random_word or "" + alias_domain_prefix, alias_domain = alias_suffix.split("@", 1) + + # alias_domain must be either one of user custom domains or built-in domains + if alias_domain not in user_custom_domains and alias_domain not in ALIAS_DOMAINS: + LOG.exception("wrong alias suffix %s, user %s", alias_suffix, user) + return False + + # built-in domain case: + # 1) alias_suffix must start with "." and + # 2) alias_domain_prefix must come from the word list + if alias_domain in ALIAS_DOMAINS and alias_domain not in user_custom_domains: + if not alias_domain_prefix.startswith("."): LOG.exception("User %s submits a wrong alias suffix %s", user, alias_suffix) return False - full_alias = alias_prefix + alias_suffix - if not email_belongs_to_alias_domains(full_alias): - LOG.exception( - "Alias suffix should end with one of the alias domains %s", - user, - alias_suffix, - ) - return False - - random_word_part = alias_suffix[1 : alias_suffix.find("@")] + random_word_part = alias_domain_prefix[1:] if not word_exist(random_word_part): LOG.exception( "alias suffix %s needs to start with a random word, user %s", @@ -229,5 +220,14 @@ def verify_prefix_suffix(user, alias_prefix, alias_suffix) -> bool: user, ) return False + else: + if alias_domain not in user_custom_domains: + if not DISABLE_ALIAS_SUFFIX: + LOG.exception("wrong alias suffix %s, user %s", alias_suffix, user) + return False + + if alias_domain not in ALIAS_DOMAINS: + LOG.exception("wrong alias suffix %s, user %s", alias_suffix, user) + return False return True diff --git a/app/dashboard/views/domain_detail.py b/app/dashboard/views/domain_detail.py index 4d539175..09f5c604 100644 --- a/app/dashboard/views/domain_detail.py +++ b/app/dashboard/views/domain_detail.py @@ -160,6 +160,25 @@ def domain_detail(custom_domain_id): return redirect( url_for("dashboard.domain_detail", custom_domain_id=custom_domain.id) ) + elif request.form.get("form-name") == "switch-random-prefix-generation": + custom_domain.random_prefix_generation = ( + not custom_domain.random_prefix_generation + ) + db.session.commit() + + if custom_domain.random_prefix_generation: + flash( + f"Random prefix generation has been enabled for {custom_domain.domain}", + "success", + ) + else: + flash( + f"Random prefix generation has been disabled for {custom_domain.domain}", + "warning", + ) + return redirect( + url_for("dashboard.domain_detail", custom_domain_id=custom_domain.id) + ) elif request.form.get("form-name") == "delete": name = custom_domain.domain CustomDomain.delete(custom_domain_id) diff --git a/app/models.py b/app/models.py index e34b89a6..9b558a9a 100644 --- a/app/models.py +++ b/app/models.py @@ -1449,6 +1449,11 @@ class CustomDomain(db.Model, ModelMixin): # an alias is created automatically the first time it receives an email catch_all = db.Column(db.Boolean, nullable=False, default=False, server_default="0") + # option to generate random prefix version automatically + random_prefix_generation = db.Column( + db.Boolean, nullable=False, default=False, server_default="0" + ) + user = db.relationship(User, foreign_keys=[user_id]) @property diff --git a/migrations/versions/2020_100922_a90e423c6763_.py b/migrations/versions/2020_100922_a90e423c6763_.py new file mode 100644 index 00000000..1014020c --- /dev/null +++ b/migrations/versions/2020_100922_a90e423c6763_.py @@ -0,0 +1,29 @@ +"""empty message + +Revision ID: a90e423c6763 +Revises: 1abfc9e14d7e +Create Date: 2020-10-09 22:35:11.359186 + +""" +import sqlalchemy_utils +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'a90e423c6763' +down_revision = '1abfc9e14d7e' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('custom_domain', sa.Column('random_prefix_generation', sa.Boolean(), server_default='0', nullable=False)) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('custom_domain', 'random_prefix_generation') + # ### end Alembic commands ###