Reserve privileged alias addresses for admins
Any user could create aliases like postmaster@, webmaster@ or abuse@ on their domain. CAs use these addresses to validate domains, so a family account (or a compromised one) could obtain TLS certificates or catch abuse and system mails. - Only admins may create aliases with a reserved local part (admin, administrator, webmaster, hostmaster, postmaster, abuse, security, noc, root, mailer-daemon). The acting user counts, so admins can still assign such aliases to other users. - Escape the domains in the email regex, so "finn.st" no longer matches "finnXst". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
fc24ba068d
commit
4a03b5c1a1
3 files changed
+29
-2
No files matched your search
@@ -65,5 +65,6 @@
|
||||
"Used as an alias by {alias}.": "Word für den Alias {alias} verwendet",
|
||||
"Invalid domain": "Invalide Domain",
|
||||
"Can use different alias domains": "Kann unterschiedliche Aliasdomains benutzen",
|
||||
"Can use different alias domains is not set": "Kann unterschiedliche Aliasdomains benutzen ist nicht gesetzt"
|
||||
"Can use different alias domains is not set": "Kann unterschiedliche Aliasdomains benutzen ist nicht gesetzt",
|
||||
"This address is reserved and can only be created by an admin.": "Diese Adresse ist reserviert und kann nur von einem Admin angelegt werden."
|
||||
}
|
||||
@@ -42,6 +42,12 @@ class AliasCreate(
|
||||
full_email = f"{self.email}@{self.domain}"
|
||||
if not self.is_email_valid(full_email):
|
||||
error = True
|
||||
elif not self.auth_user.is_admin and self.is_reserved_email(full_email):
|
||||
flash(
|
||||
t("This address is reserved and can only be created by an admin."),
|
||||
category="error",
|
||||
)
|
||||
error = True
|
||||
|
||||
enabled = self.request.form.get("enabled")
|
||||
if enabled == "on":
|
||||
|
||||
@@ -5,14 +5,34 @@ from flask import flash
|
||||
from max.db import get_domains
|
||||
from max.translations import t
|
||||
|
||||
RESERVED_LOCAL_PARTS = frozenset(
|
||||
(
|
||||
"admin",
|
||||
"administrator",
|
||||
"webmaster",
|
||||
"hostmaster",
|
||||
"postmaster",
|
||||
"abuse",
|
||||
"security",
|
||||
"noc",
|
||||
"root",
|
||||
"mailer-daemon",
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class CheckEmailMixin:
|
||||
def is_email_valid(self, email: str):
|
||||
"""Checks for the email being valid and that it has a valid domain."""
|
||||
regex = re.compile(f"^[a-zA-Z0-9+_-]+@({'|'.join(get_domains())})$")
|
||||
domains = "|".join(map(re.escape, get_domains()))
|
||||
regex = re.compile(f"^[a-zA-Z0-9+_-]+@({domains})$")
|
||||
match = regex.match(email)
|
||||
if not match:
|
||||
flash(t("The email is not valid"), category="error")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def is_reserved_email(self, email: str):
|
||||
local_part = email.split("@")[0]
|
||||
return local_part.lower() in RESERVED_LOCAL_PARTS
|
||||
Reference in new issue
Block a user