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 ###