Use the same design as on extension for custom alias: domains are presented in a dropdown list
This commit is contained in:
parent
2c53bf8315
commit
c969e6919a
|
@ -9,82 +9,47 @@
|
||||||
{% block default_content %}
|
{% block default_content %}
|
||||||
|
|
||||||
<div class="bg-white p-6" style="max-width: 60em; margin: auto">
|
<div class="bg-white p-6" style="max-width: 60em; margin: auto">
|
||||||
<h1 class="h2 mb-5">New Email Alias</h1>
|
<h1 class="h3 mb-5">New Email Alias</h1>
|
||||||
{% if error %}
|
|
||||||
<div class="text-danger text-center mb-4">{{ error }}</div>
|
{% if user_custom_domains|length == 0 %}
|
||||||
|
<div class="alert alert-primary" role="alert">
|
||||||
|
You might notice a random word after the <em>.</em> in the alias.
|
||||||
|
This part is to avoid a person taking all the "nice" aliases 😉. <br>
|
||||||
|
If you add your own domain, you could fully customize the alias. <br>
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<form method="post">
|
<form method="post">
|
||||||
<input type="hidden" name="form-name" value="non-custom-domain-name">
|
<div class="row mb-2">
|
||||||
|
<div class="col-sm-6 pr-1 mb-1" style="min-width: 5em">
|
||||||
<div class="container p-0">
|
<input name="prefix" class="form-control"#}
|
||||||
{% if custom_domains %}
|
pattern="[0-9a-z-_]{1,}"
|
||||||
<div class="row col">
|
title="Only lowercase letter, number, dash (-), underscore (_) can be used in alias prefix."
|
||||||
<div class="font-weight-bold h4">With SimpleLogin domain</div>
|
placeholder="email alias"
|
||||||
</div>
|
autofocus required>
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-6 pr-1 mb-1" style="min-width: 5em">
|
|
||||||
<input name="email-prefix" class="form-control"
|
|
||||||
pattern="[0-9a-z-_]{1,}"
|
|
||||||
title="Only lowercase letter, number, dash (-), underscore (_) can be used in alias prefix."
|
|
||||||
placeholder="email alias"
|
|
||||||
autofocus required>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-6 align-self-center" style="height:1.5rem">
|
|
||||||
<input type="hidden" name="email-suffix" value="{{ email_suffix }}">
|
|
||||||
<h4>
|
|
||||||
{{ email_suffix }}@{{ EMAIL_DOMAIN }}
|
|
||||||
</h4>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row col">
|
|
||||||
<div class="small-text">
|
|
||||||
<span class="badge badge-info">Hint</span>
|
|
||||||
You can use the name of the website that you plan to use the alias on here.<br>
|
|
||||||
This way you can remember where the alias is used.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<div class="col-sm-6 {% if suffixes|length == 1 %} align-self-center {% endif %}"
|
||||||
|
style="padding-left: 5px">
|
||||||
|
{% if suffixes|length > 1 %}
|
||||||
|
<select class="form-control" name="suffix">
|
||||||
|
{% for suffix in suffixes %}
|
||||||
|
<option value="{{ suffix }}">
|
||||||
|
{{ suffix }}
|
||||||
|
</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
{% else %}
|
||||||
|
<span>{{ suffixes[0] }}</span>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="row col">
|
<div class="row col">
|
||||||
<button class="btn btn-primary mt-1">Create</button>
|
<button class="btn btn-primary mt-1">Create</button>
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{% if custom_domains %}
|
|
||||||
<hr>
|
|
||||||
<p class="font-weight-bold h4">Or with your custom domains</p>
|
|
||||||
<div class="container p-0">
|
|
||||||
{% for custom_domain in custom_domains %}
|
|
||||||
<form method="post" class="mb-6">
|
|
||||||
<input type="hidden" name="form-name" value="custom-domain-name">
|
|
||||||
<input type="hidden" name="custom-domain-id" value="{{ custom_domain.id }}">
|
|
||||||
|
|
||||||
<div class="row mt-4">
|
|
||||||
<div class="col" style="min-width: 10em">
|
|
||||||
<input name="email" class="form-control">
|
|
||||||
<div>
|
|
||||||
<span style="font-weight: 600">
|
|
||||||
@{{ custom_domain.domain }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col">
|
|
||||||
<button class="submit btn btn-success">Create</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</form>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
from flask import render_template, redirect, url_for, flash, request, session
|
from flask import render_template, redirect, url_for, flash, request, session
|
||||||
from flask_login import login_required, current_user
|
from flask_login import login_required, current_user
|
||||||
|
from flask_wtf import FlaskForm
|
||||||
|
from wtforms import StringField, validators, SelectField
|
||||||
|
|
||||||
from app.config import EMAIL_DOMAIN, HIGHLIGHT_GEN_EMAIL_ID, DISABLE_ALIAS_SUFFIX
|
from app.config import EMAIL_DOMAIN, HIGHLIGHT_GEN_EMAIL_ID, DISABLE_ALIAS_SUFFIX
|
||||||
from app.dashboard.base import dashboard_bp
|
from app.dashboard.base import dashboard_bp
|
||||||
|
@ -12,96 +14,93 @@ from app.utils import convert_to_id, random_word, word_exist
|
||||||
@dashboard_bp.route("/custom_alias", methods=["GET", "POST"])
|
@dashboard_bp.route("/custom_alias", methods=["GET", "POST"])
|
||||||
@login_required
|
@login_required
|
||||||
def custom_alias():
|
def custom_alias():
|
||||||
# check if user has the right to create custom alias
|
# check if user has not exceeded the alias quota
|
||||||
if not current_user.can_create_new_alias():
|
if not current_user.can_create_new_alias():
|
||||||
# notify admin
|
# notify admin
|
||||||
LOG.error("user %s tries to create custom alias", current_user)
|
LOG.error("user %s tries to create custom alias", current_user)
|
||||||
flash("ony premium user can choose custom alias", "warning")
|
flash("ony premium user can choose custom alias", "warning")
|
||||||
return redirect(url_for("dashboard.index"))
|
return redirect(url_for("dashboard.index"))
|
||||||
|
|
||||||
error = ""
|
user_custom_domains = [cd.domain for cd in current_user.verified_custom_domains()]
|
||||||
|
suffixes = []
|
||||||
|
|
||||||
|
# put custom domain first
|
||||||
|
for alias_domain in user_custom_domains:
|
||||||
|
suffixes.append("@" + alias_domain)
|
||||||
|
|
||||||
|
# then default domain
|
||||||
|
suffixes.append(
|
||||||
|
("" if DISABLE_ALIAS_SUFFIX else ".") + random_word() + "@" + EMAIL_DOMAIN
|
||||||
|
)
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
if request.form.get("form-name") == "non-custom-domain-name":
|
alias_prefix = request.form.get("prefix")
|
||||||
email_prefix = request.form.get("email-prefix")
|
alias_suffix = request.form.get("suffix")
|
||||||
email_prefix = convert_to_id(email_prefix)
|
|
||||||
email_suffix = request.form.get("email-suffix")
|
|
||||||
|
|
||||||
# verify email_suffix: do not verify when DISABLE_ALIAS_SUFFIX is set
|
if verify_prefix_suffix(
|
||||||
if not DISABLE_ALIAS_SUFFIX:
|
current_user, alias_prefix, alias_suffix, user_custom_domains
|
||||||
# email suffix must be in the format ".{word}"
|
):
|
||||||
if email_suffix[0] != "." or not word_exist(email_suffix[1:]):
|
full_alias = alias_prefix + alias_suffix
|
||||||
flash(
|
if GenEmail.get_by(email=full_alias):
|
||||||
"nice try :). The suffix is there so no one can take all the *nice* aliases though",
|
LOG.d("full alias already used %s", full_alias)
|
||||||
"warning",
|
flash(
|
||||||
)
|
f"Alias {full_alias} already exists, please choose another one",
|
||||||
return redirect(url_for("dashboard.custom_alias"))
|
"warning",
|
||||||
|
|
||||||
if not email_prefix:
|
|
||||||
error = "alias prefix cannot be empty"
|
|
||||||
else:
|
|
||||||
full_email = f"{email_prefix}{email_suffix}@{EMAIL_DOMAIN}"
|
|
||||||
# check if email already exists
|
|
||||||
if GenEmail.get_by(email=full_email) or DeletedAlias.get_by(
|
|
||||||
email=full_email
|
|
||||||
):
|
|
||||||
error = "email already chosen, please choose another one"
|
|
||||||
else:
|
|
||||||
# create the new alias
|
|
||||||
LOG.d(
|
|
||||||
"create custom alias %s for user %s", full_email, current_user
|
|
||||||
)
|
|
||||||
gen_email = GenEmail.create(
|
|
||||||
email=full_email, user_id=current_user.id
|
|
||||||
)
|
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
flash(f"Alias {full_email} has been created", "success")
|
|
||||||
session[HIGHLIGHT_GEN_EMAIL_ID] = gen_email.id
|
|
||||||
|
|
||||||
return redirect(url_for("dashboard.index"))
|
|
||||||
elif request.form.get("form-name") == "custom-domain-name":
|
|
||||||
custom_domain_id = request.form.get("custom-domain-id")
|
|
||||||
email = request.form.get("email").lower()
|
|
||||||
|
|
||||||
custom_domain = CustomDomain.get(custom_domain_id)
|
|
||||||
|
|
||||||
if not custom_domain:
|
|
||||||
flash("Unknown error. Refresh the page", "warning")
|
|
||||||
return redirect(url_for("dashboard.custom_alias"))
|
|
||||||
elif custom_domain.user_id != current_user.id:
|
|
||||||
flash("Unknown error. Refresh the page", "warning")
|
|
||||||
return redirect(url_for("dashboard.custom_alias"))
|
|
||||||
elif not custom_domain.verified:
|
|
||||||
flash("Unknown error. Refresh the page", "warning")
|
|
||||||
return redirect(url_for("dashboard.custom_alias"))
|
|
||||||
|
|
||||||
full_email = f"{email}@{custom_domain.domain}"
|
|
||||||
|
|
||||||
if GenEmail.get_by(email=full_email):
|
|
||||||
error = f"{full_email} already exist, please choose another one"
|
|
||||||
else:
|
|
||||||
LOG.d(
|
|
||||||
"create custom alias %s for custom domain %s",
|
|
||||||
full_email,
|
|
||||||
custom_domain.domain,
|
|
||||||
)
|
|
||||||
gen_email = GenEmail.create(
|
|
||||||
email=full_email,
|
|
||||||
user_id=current_user.id,
|
|
||||||
custom_domain_id=custom_domain.id,
|
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
gen_email = GenEmail.create(user_id=current_user.id, email=full_alias)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
flash(f"Alias {full_email} has been created", "success")
|
flash(f"Alias {full_alias} has been created", "success")
|
||||||
|
|
||||||
session[HIGHLIGHT_GEN_EMAIL_ID] = gen_email.id
|
session[HIGHLIGHT_GEN_EMAIL_ID] = gen_email.id
|
||||||
return redirect(url_for("dashboard.index"))
|
|
||||||
|
|
||||||
email_suffix = "" if DISABLE_ALIAS_SUFFIX else "." + random_word()
|
return redirect(url_for("dashboard.index"))
|
||||||
return render_template(
|
# only happen if the request has been "hacked"
|
||||||
"dashboard/custom_alias.html",
|
else:
|
||||||
error=error,
|
flash("something went wrong", "warning")
|
||||||
email_suffix=email_suffix,
|
|
||||||
EMAIL_DOMAIN=EMAIL_DOMAIN,
|
return render_template("dashboard/custom_alias.html", **locals())
|
||||||
custom_domains=current_user.verified_custom_domains(),
|
|
||||||
)
|
|
||||||
|
def verify_prefix_suffix(user, alias_prefix, alias_suffix, user_custom_domains) -> bool:
|
||||||
|
"""verify if user could create an alias with the given prefix and suffix"""
|
||||||
|
alias_prefix = alias_prefix.strip()
|
||||||
|
alias_prefix = convert_to_id(alias_prefix)
|
||||||
|
if not alias_prefix: # should be caught on frontend
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 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, EMAIL_DOMAIN
|
||||||
|
if DISABLE_ALIAS_SUFFIX:
|
||||||
|
if alias_domain not in user_custom_domains and alias_domain != EMAIL_DOMAIN:
|
||||||
|
LOG.error("wrong alias suffix %s, user %s", alias_suffix, user)
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
if alias_domain not in user_custom_domains:
|
||||||
|
LOG.error("wrong alias suffix %s, user %s", alias_suffix, user)
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
if not alias_suffix.startswith("."):
|
||||||
|
LOG.error("User %s submits a wrong alias suffix %s", user, alias_suffix)
|
||||||
|
return False
|
||||||
|
if not alias_suffix.endswith(EMAIL_DOMAIN):
|
||||||
|
LOG.error(
|
||||||
|
"Alias suffix should end with default alias domain %s",
|
||||||
|
user,
|
||||||
|
alias_suffix,
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
|
random_word_part = alias_suffix[1 : alias_suffix.find("@")]
|
||||||
|
if not word_exist(random_word_part):
|
||||||
|
LOG.error(
|
||||||
|
"alias suffix %s needs to start with a random word, user %s",
|
||||||
|
alias_suffix,
|
||||||
|
user,
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
Loading…
Reference in a new issue