2022-01-09 20:22:41 +01:00
|
|
|
from email_validator import validate_email, EmailNotValidError
|
2020-01-29 17:57:11 +01:00
|
|
|
from flask import render_template, redirect, url_for, flash, request
|
2019-07-06 23:25:52 +02:00
|
|
|
from flask_login import login_required, current_user
|
2020-10-24 15:50:29 +02:00
|
|
|
from sqlalchemy.exc import IntegrityError
|
2019-07-06 23:25:52 +02:00
|
|
|
|
2022-10-27 10:07:02 +02:00
|
|
|
from app import parallel_limiter
|
2022-07-27 17:40:22 +02:00
|
|
|
from app.alias_suffix import (
|
|
|
|
get_alias_suffixes,
|
|
|
|
check_suffix_signature,
|
|
|
|
verify_prefix_suffix,
|
|
|
|
)
|
2020-11-03 10:39:08 +01:00
|
|
|
from app.alias_utils import check_alias_prefix
|
2020-05-02 12:15:03 +02:00
|
|
|
from app.config import (
|
2021-03-24 16:52:05 +01:00
|
|
|
ALIAS_LIMIT,
|
2020-05-02 12:15:03 +02:00
|
|
|
)
|
2019-07-06 23:25:52 +02:00
|
|
|
from app.dashboard.base import dashboard_bp
|
2021-10-12 14:36:47 +02:00
|
|
|
from app.db import Session
|
|
|
|
from app.extensions import limiter
|
2019-07-06 23:25:52 +02:00
|
|
|
from app.log import LOG
|
2020-05-23 11:51:35 +02:00
|
|
|
from app.models import (
|
|
|
|
Alias,
|
|
|
|
DeletedAlias,
|
|
|
|
Mailbox,
|
|
|
|
AliasMailbox,
|
|
|
|
DomainDeletedAlias,
|
|
|
|
)
|
2023-12-20 16:15:01 +01:00
|
|
|
from app.utils import CSRFValidationForm
|
2019-07-06 23:25:52 +02:00
|
|
|
|
2021-07-19 20:14:59 +02:00
|
|
|
|
2019-07-06 23:25:52 +02:00
|
|
|
@dashboard_bp.route("/custom_alias", methods=["GET", "POST"])
|
2021-03-24 16:52:05 +01:00
|
|
|
@limiter.limit(ALIAS_LIMIT, methods=["POST"])
|
2019-07-06 23:25:52 +02:00
|
|
|
@login_required
|
2022-10-27 10:07:02 +02:00
|
|
|
@parallel_limiter.lock(name="alias_creation")
|
2019-07-06 23:25:52 +02:00
|
|
|
def custom_alias():
|
2020-01-22 00:03:25 +01:00
|
|
|
# check if user has not exceeded the alias quota
|
2019-12-22 17:27:55 +01:00
|
|
|
if not current_user.can_create_new_alias():
|
2021-04-09 12:40:55 +02:00
|
|
|
LOG.d("%s can't create new alias", current_user)
|
2020-01-30 04:52:56 +01:00
|
|
|
flash(
|
|
|
|
"You have reached free plan limit, please upgrade to create new aliases",
|
|
|
|
"warning",
|
|
|
|
)
|
2019-07-06 23:25:52 +02:00
|
|
|
return redirect(url_for("dashboard.index"))
|
|
|
|
|
2020-01-22 00:03:25 +01:00
|
|
|
user_custom_domains = [cd.domain for cd in current_user.verified_custom_domains()]
|
2021-07-19 20:14:59 +02:00
|
|
|
alias_suffixes = get_alias_suffixes(current_user)
|
2020-10-20 16:44:22 +02:00
|
|
|
at_least_a_premium_domain = False
|
2021-07-19 20:14:59 +02:00
|
|
|
for alias_suffix in alias_suffixes:
|
|
|
|
if not alias_suffix.is_custom and alias_suffix.is_premium:
|
2020-10-20 16:44:22 +02:00
|
|
|
at_least_a_premium_domain = True
|
|
|
|
break
|
2019-07-06 23:25:52 +02:00
|
|
|
|
2023-12-20 16:15:01 +01:00
|
|
|
csrf_form = CSRFValidationForm()
|
2020-05-03 16:50:39 +02:00
|
|
|
mailboxes = current_user.mailboxes()
|
2020-02-10 17:19:42 +01:00
|
|
|
|
2019-12-02 01:34:54 +01:00
|
|
|
if request.method == "POST":
|
2023-12-20 16:15:01 +01:00
|
|
|
if not csrf_form.validate():
|
|
|
|
flash("Invalid request", "warning")
|
|
|
|
return redirect(request.url)
|
2020-09-02 09:56:16 +02:00
|
|
|
alias_prefix = request.form.get("prefix").strip().lower().replace(" ", "")
|
2021-07-19 20:14:59 +02:00
|
|
|
signed_alias_suffix = request.form.get("signed-alias-suffix")
|
2020-05-03 16:50:39 +02:00
|
|
|
mailbox_ids = request.form.getlist("mailboxes")
|
2020-02-05 11:36:06 +01:00
|
|
|
alias_note = request.form.get("note")
|
2020-01-22 00:03:25 +01:00
|
|
|
|
2020-11-03 10:39:08 +01:00
|
|
|
if not check_alias_prefix(alias_prefix):
|
|
|
|
flash(
|
2021-04-30 11:37:17 +02:00
|
|
|
"Only lowercase letters, numbers, dashes (-), dots (.) and underscores (_) "
|
2020-11-18 10:38:35 +01:00
|
|
|
"are currently supported for alias prefix. Cannot be more than 40 letters",
|
2020-11-03 10:39:08 +01:00
|
|
|
"error",
|
|
|
|
)
|
2022-01-09 20:22:41 +01:00
|
|
|
return redirect(request.url)
|
2020-11-03 10:39:08 +01:00
|
|
|
|
2020-02-10 17:19:42 +01:00
|
|
|
# check if mailbox is not tempered with
|
2020-05-03 16:50:39 +02:00
|
|
|
mailboxes = []
|
|
|
|
for mailbox_id in mailbox_ids:
|
|
|
|
mailbox = Mailbox.get(mailbox_id)
|
|
|
|
if (
|
|
|
|
not mailbox
|
|
|
|
or mailbox.user_id != current_user.id
|
|
|
|
or not mailbox.verified
|
|
|
|
):
|
2020-02-10 17:19:42 +01:00
|
|
|
flash("Something went wrong, please retry", "warning")
|
2022-01-09 20:22:41 +01:00
|
|
|
return redirect(request.url)
|
2020-05-03 16:50:39 +02:00
|
|
|
mailboxes.append(mailbox)
|
|
|
|
|
|
|
|
if not mailboxes:
|
|
|
|
flash("At least one mailbox must be selected", "error")
|
2022-01-09 20:22:41 +01:00
|
|
|
return redirect(request.url)
|
2020-02-10 17:19:42 +01:00
|
|
|
|
2020-05-02 12:15:03 +02:00
|
|
|
try:
|
2022-07-27 17:40:22 +02:00
|
|
|
suffix = check_suffix_signature(signed_alias_suffix)
|
|
|
|
if not suffix:
|
|
|
|
LOG.w("Alias creation time expired for %s", current_user)
|
|
|
|
flash("Alias creation time is expired, please retry", "warning")
|
|
|
|
return redirect(request.url)
|
2020-05-02 12:15:03 +02:00
|
|
|
except Exception:
|
2021-09-08 11:29:55 +02:00
|
|
|
LOG.w("Alias suffix is tampered, user %s", current_user)
|
2020-05-02 12:15:03 +02:00
|
|
|
flash("Unknown error, refresh the page", "error")
|
2022-01-09 20:22:41 +01:00
|
|
|
return redirect(request.url)
|
2020-05-02 12:15:03 +02:00
|
|
|
|
2022-07-27 17:40:22 +02:00
|
|
|
if verify_prefix_suffix(current_user, alias_prefix, suffix):
|
|
|
|
full_alias = alias_prefix + suffix
|
2020-01-23 11:45:52 +01:00
|
|
|
|
2022-01-09 20:22:41 +01:00
|
|
|
if ".." in full_alias:
|
|
|
|
flash("Your alias can't contain 2 consecutive dots (..)", "error")
|
|
|
|
return redirect(request.url)
|
|
|
|
|
|
|
|
try:
|
|
|
|
validate_email(
|
|
|
|
full_alias, check_deliverability=False, allow_smtputf8=False
|
|
|
|
)
|
|
|
|
except EmailNotValidError as e:
|
|
|
|
flash(str(e), "error")
|
|
|
|
return redirect(request.url)
|
|
|
|
|
2020-10-09 11:48:52 +02:00
|
|
|
general_error_msg = f"{full_alias} cannot be used"
|
|
|
|
|
|
|
|
if Alias.get_by(email=full_alias):
|
|
|
|
alias = Alias.get_by(email=full_alias)
|
|
|
|
if alias.user_id == current_user.id:
|
|
|
|
flash(f"You already have this alias {full_alias}", "error")
|
|
|
|
else:
|
|
|
|
flash(general_error_msg, "error")
|
|
|
|
elif DomainDeletedAlias.get_by(email=full_alias):
|
|
|
|
domain_deleted_alias: DomainDeletedAlias = DomainDeletedAlias.get_by(
|
|
|
|
email=full_alias
|
2019-08-30 22:42:06 +02:00
|
|
|
)
|
2020-10-09 11:48:52 +02:00
|
|
|
custom_domain = domain_deleted_alias.domain
|
2023-03-17 15:39:59 +01:00
|
|
|
flash(
|
|
|
|
f"You have deleted this alias before. You can restore it on "
|
|
|
|
f"{custom_domain.domain} 'Deleted Alias' page",
|
|
|
|
"error",
|
|
|
|
)
|
2020-10-09 11:48:52 +02:00
|
|
|
|
|
|
|
elif DeletedAlias.get_by(email=full_alias):
|
|
|
|
flash(general_error_msg, "error")
|
|
|
|
|
2020-01-22 00:03:25 +01:00
|
|
|
else:
|
2020-10-24 15:50:29 +02:00
|
|
|
try:
|
|
|
|
alias = Alias.create(
|
|
|
|
user_id=current_user.id,
|
|
|
|
email=full_alias,
|
|
|
|
note=alias_note,
|
|
|
|
mailbox_id=mailboxes[0].id,
|
|
|
|
)
|
2021-10-12 14:36:47 +02:00
|
|
|
Session.flush()
|
2020-10-24 15:50:29 +02:00
|
|
|
except IntegrityError:
|
2021-09-08 11:29:55 +02:00
|
|
|
LOG.w("Alias %s already exists", full_alias)
|
2021-10-12 14:36:47 +02:00
|
|
|
Session.rollback()
|
2020-10-24 15:50:29 +02:00
|
|
|
flash("Unknown error, please retry", "error")
|
|
|
|
return redirect(url_for("dashboard.custom_alias"))
|
2020-05-03 16:50:39 +02:00
|
|
|
|
|
|
|
for i in range(1, len(mailboxes)):
|
|
|
|
AliasMailbox.create(
|
2020-08-27 10:20:48 +02:00
|
|
|
alias_id=alias.id,
|
|
|
|
mailbox_id=mailboxes[i].id,
|
2020-05-03 16:50:39 +02:00
|
|
|
)
|
2020-01-23 11:45:52 +01:00
|
|
|
|
2021-10-12 14:36:47 +02:00
|
|
|
Session.commit()
|
2020-01-22 00:03:25 +01:00
|
|
|
flash(f"Alias {full_alias} has been created", "success")
|
2019-07-06 23:25:52 +02:00
|
|
|
|
2020-03-17 11:51:40 +01:00
|
|
|
return redirect(url_for("dashboard.index", highlight_alias_id=alias.id))
|
2020-01-22 00:03:25 +01:00
|
|
|
# only happen if the request has been "hacked"
|
|
|
|
else:
|
|
|
|
flash("something went wrong", "warning")
|
2019-07-06 23:25:52 +02:00
|
|
|
|
2020-05-02 12:34:11 +02:00
|
|
|
return render_template(
|
|
|
|
"dashboard/custom_alias.html",
|
|
|
|
user_custom_domains=user_custom_domains,
|
2022-07-27 17:40:22 +02:00
|
|
|
alias_suffixes=alias_suffixes,
|
2020-10-20 16:44:22 +02:00
|
|
|
at_least_a_premium_domain=at_least_a_premium_domain,
|
2020-05-02 12:34:11 +02:00
|
|
|
mailboxes=mailboxes,
|
2023-12-20 16:15:01 +01:00
|
|
|
csrf_form=csrf_form,
|
2020-05-02 12:34:11 +02:00
|
|
|
)
|