Skip to content

Commit

Permalink
Add possibility to allow/disallow main email, email alias and email f…
Browse files Browse the repository at this point in the history
…orward form portal
  • Loading branch information
Josue-T committed Nov 9, 2024
1 parent 49a8563 commit fb3cc9e
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 6 deletions.
8 changes: 8 additions & 0 deletions locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,13 @@
"global_settings_setting_pop3_enabled": "Enable POP3",
"global_settings_setting_pop3_enabled_help": "Enable the POP3 protocol for the mail server. POP3 is an older protocol to access mailboxes from email clients and is more lightweight, but has less features than IMAP (enabled by default)",
"global_settings_setting_pop3_name": "POP3",
"global_settings_setting_portal_name": "Portal",
"global_settings_setting_portal_allow_edit_email": "Allow users to edit email",
"global_settings_setting_portal_allow_edit_email_alias": "Allow users to edit mail alias",
"global_settings_setting_portal_allow_edit_email_alias_help": "Allow users to edit their email address alias.",
"global_settings_setting_portal_allow_edit_email_forward": "Allow users to edit email forward",
"global_settings_setting_portal_allow_edit_email_forward_help": "Allow users to edit their main email forward.",
"global_settings_setting_portal_allow_edit_email_help": "Allow users to edit their main email address.",
"global_settings_setting_postfix_compatibility": "Postfix Compatibility",
"global_settings_setting_postfix_compatibility_help": "Compatibility vs. security tradeoff for the Postfix server. Affects the ciphers (and other security-related aspects)",
"global_settings_setting_postfix_name": "Postfix (SMTP email server)",
Expand Down Expand Up @@ -603,6 +610,7 @@
"log_user_update": "Update info for user '{}'",
"mail_alias_remove_failed": "Could not remove e-mail alias '{mail}'",
"mail_alias_unauthorized": "You are not authorized to add aliases related to domain '{domain}'",
"mail_edit_operation_unauthorized": "You are not authorized to do this change for your account.",
"mail_already_exists": "Mail address '{mail}' already exists",
"mail_domain_unknown": "Invalid e-mail address for domain '{domain}'. Please, use a domain administrated by this server.",
"mail_forward_remove_failed": "Could not remove e-mail forwarding '{mail}'",
Expand Down
10 changes: 7 additions & 3 deletions share/actionsmap-portal.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ portal:
pattern: &pattern_fullname
- !!str ^([^\W_]{1,30}[ ,.'-]{0,3})+$
- "pattern_fullname"
--mainemail:
help: Main email
extra:
pattern: &pattern_email
- !!str ^[\w.-]+@([^\W_A-Z]+([-]*[^\W_A-Z]+)*\.)+((xn--)?[^\W_]{2,})$
- "pattern_email"
--mailforward:
help: Mailforward addresses to add
nargs: "*"
Expand All @@ -44,9 +50,7 @@ portal:
nargs: "*"
metavar: MAIL
extra:
pattern: &pattern_email
- !!str ^[\w.-]+@([^\W_A-Z]+([-]*[^\W_A-Z]+)*\.)+((xn--)?[^\W_]{2,})$
- "pattern_email"
pattern: *pattern_email
--currentpassword:
help: Current password
nargs: "?"
Expand Down
12 changes: 12 additions & 0 deletions share/config_global.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,18 @@ i18n = "global_settings_setting"
optional = true
default = ""

[security.portal]
[security.portal.portal_allow_edit_email]
type = "boolean"

[security.portal.portal_allow_edit_email_alias]
type = "boolean"
default = 1

[security.portal.portal_allow_edit_email_forward]
type = "boolean"
default = 1

[security.root_access]
[security.root_access.root_access_explain]
type = "alert"
Expand Down
52 changes: 49 additions & 3 deletions src/portal.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
assert_password_is_strong_enough,
_hash_user_password,
)
from yunohost.settings import settings_get

logger = logging.getLogger("portal")

Expand Down Expand Up @@ -150,6 +151,10 @@ def portal_me():
for infos in apps.values():
del infos["users"]

is_allowed_to_edit_main_email = settings_get("security.portal.portal_allow_edit_email")
is_allowed_to_edit_mail_alias = settings_get("security.portal.portal_allow_edit_email_alias")
is_allowed_to_edit_mail_forward = settings_get("security.portal.portal_allow_edit_email_forward")

result_dict = {
"username": username,
"fullname": user["cn"][0],
Expand All @@ -158,6 +163,9 @@ def portal_me():
"mailforward": user["maildrop"][1:],
"groups": groups,
"apps": apps,
"can_edit_main_email": is_allowed_to_edit_main_email,
"can_edit_email_alias": is_allowed_to_edit_mail_alias,
"can_edit_email_forward": is_allowed_to_edit_mail_forward,
}

# FIXME / TODO : add mail quota status ?
Expand All @@ -173,6 +181,7 @@ def portal_me():

def portal_update(
fullname: Union[str, None] = None,
mainemail: Union[str, None] = None,
mailforward: Union[list[str], None] = None,
mailalias: Union[list[str], None] = None,
currentpassword: Union[str, None] = None,
Expand All @@ -198,14 +207,47 @@ def portal_update(
(firstname + " " + lastname).strip()
]

new_mails = current_user["mail"]

if mainemail is not None:
is_allowed_to_edit_main_email = settings_get("security.portal.portal_allow_edit_email")
if is_allowed_to_edit_main_email != 1:
raise YunohostValidationError("mail_edit_operation_unauthorized")

if mainemail not in new_mails:
local_part, domain = mainemail.split("@")
if local_part in ADMIN_ALIASES:
raise YunohostValidationError("mail_unavailable")

try:
_get_ldap_interface().validate_uniqueness({"mail": mainemail})
except YunohostError:
raise YunohostValidationError(
"mail_already_exists", mail=mainemail
)

if domain not in domains or not user_is_allowed_on_domain(username, domain):
raise YunohostValidationError("mail_alias_unauthorized", domain=domain)
new_mails[0] = mainemail
else:
# email already exist in the list we just move it on the first place
new_mails.remove(mainemail)
new_mails.insert(0, mainemail)

new_attr_dict["mail"] = new_mails

if mailalias is not None:
is_allowed_to_edit_mail_alias = settings_get("security.portal.portal_allow_edit_email_alias")
if is_allowed_to_edit_mail_alias != 1:
raise YunohostValidationError("mail_edit_operation_unauthorized")

mailalias = [mail.strip() for mail in mailalias if mail and mail.strip()]
# keep first current mail unaltered
mails = [current_user["mail"][0]]
mails = [new_mails[0]]

for index, mail in enumerate(mailalias):
if mail in current_user["mail"]:
if mail != current_user["mail"][0] and mail not in mails:
if mail in new_mails:
if mail != new_mails[0] and mail not in mails:
mails.append(mail)
continue # already in mails, skip validation

Expand All @@ -230,6 +272,10 @@ def portal_update(
new_attr_dict["mail"] = mails

if mailforward is not None:
is_allowed_to_edit_mail_forward = settings_get("security.portal.portal_allow_edit_email_forward")
if is_allowed_to_edit_mail_forward != 1:
raise YunohostValidationError("mail_edit_operation_unauthorized")

new_attr_dict["maildrop"] = [current_user["maildrop"][0]] + [
mail.strip()
for mail in mailforward
Expand Down

0 comments on commit fb3cc9e

Please sign in to comment.