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",
|
"Used as an alias by {alias}.": "Word für den Alias {alias} verwendet",
|
||||||
"Invalid domain": "Invalide Domain",
|
"Invalid domain": "Invalide Domain",
|
||||||
"Can use different alias domains": "Kann unterschiedliche Aliasdomains benutzen",
|
"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}"
|
full_email = f"{self.email}@{self.domain}"
|
||||||
if not self.is_email_valid(full_email):
|
if not self.is_email_valid(full_email):
|
||||||
error = True
|
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")
|
enabled = self.request.form.get("enabled")
|
||||||
if enabled == "on":
|
if enabled == "on":
|
||||||
|
|||||||
@@ -5,14 +5,34 @@ from flask import flash
|
|||||||
from max.db import get_domains
|
from max.db import get_domains
|
||||||
from max.translations import t
|
from max.translations import t
|
||||||
|
|
||||||
|
RESERVED_LOCAL_PARTS = frozenset(
|
||||||
|
(
|
||||||
|
"admin",
|
||||||
|
"administrator",
|
||||||
|
"webmaster",
|
||||||
|
"hostmaster",
|
||||||
|
"postmaster",
|
||||||
|
"abuse",
|
||||||
|
"security",
|
||||||
|
"noc",
|
||||||
|
"root",
|
||||||
|
"mailer-daemon",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class CheckEmailMixin:
|
class CheckEmailMixin:
|
||||||
def is_email_valid(self, email: str):
|
def is_email_valid(self, email: str):
|
||||||
"""Checks for the email being valid and that it has a valid domain."""
|
"""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)
|
match = regex.match(email)
|
||||||
if not match:
|
if not match:
|
||||||
flash(t("The email is not valid"), category="error")
|
flash(t("The email is not valid"), category="error")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
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