diff --git a/data/Dockerfiles/acme/acme.sh b/data/Dockerfiles/acme/acme.sh index c09569cd..271de4fc 100755 --- a/data/Dockerfiles/acme/acme.sh +++ b/data/Dockerfiles/acme/acme.sh @@ -253,10 +253,20 @@ while true; do unset VALIDATED_CONFIG_DOMAINS_SUBDOMAINS declare -a VALIDATED_CONFIG_DOMAINS_SUBDOMAINS for SUBDOMAIN in "${ADDITIONAL_WC_ARR[@]}"; do - if [[ "${SUBDOMAIN}.${SQL_DOMAIN}" != "${MAILCOW_HOSTNAME}" ]]; then - if check_domain "${SUBDOMAIN}.${SQL_DOMAIN}"; then - VALIDATED_CONFIG_DOMAINS_SUBDOMAINS+=("${SUBDOMAIN}.${SQL_DOMAIN}") - fi + FULL_SUBDOMAIN="${SUBDOMAIN}.${SQL_DOMAIN}" + + # Skip if subdomain matches MAILCOW_HOSTNAME + if [[ "${FULL_SUBDOMAIN}" == "${MAILCOW_HOSTNAME}" ]]; then + continue + fi + # Skip if subdomain is covered by a wildcard in ADDITIONAL_SAN + if is_covered_by_wildcard "${FULL_SUBDOMAIN}"; then + log_f "Subdomain '${FULL_SUBDOMAIN}' is covered by wildcard - skipping explicit subdomain" + continue + fi + # Validate and add subdomain + if check_domain "${FULL_SUBDOMAIN}"; then + VALIDATED_CONFIG_DOMAINS_SUBDOMAINS+=("${FULL_SUBDOMAIN}") fi done VALIDATED_CONFIG_DOMAINS+=("${VALIDATED_CONFIG_DOMAINS_SUBDOMAINS[*]}") @@ -273,7 +283,10 @@ while true; do fi # Only add mta-sts subdomain for alias domains if [[ "mta-sts.${alias_domain}" != "${MAILCOW_HOSTNAME}" ]]; then - if check_domain "mta-sts.${alias_domain}"; then + # Skip if mta-sts subdomain is covered by a wildcard + if is_covered_by_wildcard "mta-sts.${alias_domain}"; then + log_f "Alias domain mta-sts subdomain 'mta-sts.${alias_domain}' is covered by wildcard - skipping" + elif check_domain "mta-sts.${alias_domain}"; then VALIDATED_CONFIG_DOMAINS+=("mta-sts.${alias_domain}") fi fi @@ -308,13 +321,31 @@ while true; do done fi + # Check if MAILCOW_HOSTNAME is covered by a wildcard in ADDITIONAL_SAN + MAILCOW_HOSTNAME_COVERED=0 + if [[ ! -z ${VALIDATED_MAILCOW_HOSTNAME} ]]; then + if is_covered_by_wildcard "${VALIDATED_MAILCOW_HOSTNAME}"; then + MAILCOW_PARENT_DOMAIN=$(echo ${VALIDATED_MAILCOW_HOSTNAME} | cut -d. -f2-) + log_f "MAILCOW_HOSTNAME '${VALIDATED_MAILCOW_HOSTNAME}' is covered by wildcard '*.${MAILCOW_PARENT_DOMAIN}' - skipping explicit hostname" + MAILCOW_HOSTNAME_COVERED=1 + fi + fi + # Unique domains for server certificate if [[ ${ENABLE_SSL_SNI} == "y" ]]; then # create certificate for server name and fqdn SANs only - SERVER_SAN_VALIDATED=(${VALIDATED_MAILCOW_HOSTNAME} $(echo ${ADDITIONAL_VALIDATED_SAN[*]} | xargs -n1 | sort -u | xargs)) + if [[ ${MAILCOW_HOSTNAME_COVERED} == "1" ]]; then + SERVER_SAN_VALIDATED=($(echo ${ADDITIONAL_VALIDATED_SAN[*]} | xargs -n1 | sort -u | xargs)) + else + SERVER_SAN_VALIDATED=(${VALIDATED_MAILCOW_HOSTNAME} $(echo ${ADDITIONAL_VALIDATED_SAN[*]} | xargs -n1 | sort -u | xargs)) + fi else # create certificate for all domains, including all subdomains from other domains [*] - SERVER_SAN_VALIDATED=(${VALIDATED_MAILCOW_HOSTNAME} $(echo ${VALIDATED_CONFIG_DOMAINS[*]} ${ADDITIONAL_VALIDATED_SAN[*]} | xargs -n1 | sort -u | xargs)) + if [[ ${MAILCOW_HOSTNAME_COVERED} == "1" ]]; then + SERVER_SAN_VALIDATED=($(echo ${VALIDATED_CONFIG_DOMAINS[*]} ${ADDITIONAL_VALIDATED_SAN[*]} | xargs -n1 | sort -u | xargs)) + else + SERVER_SAN_VALIDATED=(${VALIDATED_MAILCOW_HOSTNAME} $(echo ${VALIDATED_CONFIG_DOMAINS[*]} ${ADDITIONAL_VALIDATED_SAN[*]} | xargs -n1 | sort -u | xargs)) + fi fi if [[ ! -z ${SERVER_SAN_VALIDATED[*]} ]]; then CERT_NAME=${SERVER_SAN_VALIDATED[0]} diff --git a/data/Dockerfiles/acme/functions.sh b/data/Dockerfiles/acme/functions.sh index 9db83291..707f4695 100644 --- a/data/Dockerfiles/acme/functions.sh +++ b/data/Dockerfiles/acme/functions.sh @@ -135,3 +135,32 @@ verify_challenge_path(){ return 1 fi } + +# Check if a domain is covered by a wildcard (*.example.com) in ADDITIONAL_SAN +# Usage: is_covered_by_wildcard "subdomain.example.com" +# Returns: 0 if covered, 1 if not covered +# Note: Only returns 0 (covered) when DNS-01 challenge is enabled, +# as wildcards cannot be validated with HTTP-01 challenge +is_covered_by_wildcard() { + local DOMAIN=$1 + + # Only skip if DNS challenge is enabled (wildcards require DNS-01) + if [[ ${ACME_DNS_CHALLENGE} != "y" ]]; then + return 1 + fi + + # Return early if no ADDITIONAL_SAN is set + if [[ -z ${ADDITIONAL_SAN} ]]; then + return 1 + fi + + # Extract parent domain (e.g., mail.example.com -> example.com) + local PARENT_DOMAIN=$(echo ${DOMAIN} | cut -d. -f2-) + + # Check if ADDITIONAL_SAN contains a wildcard for this parent domain + if [[ "${ADDITIONAL_SAN}" == *"*.${PARENT_DOMAIN}"* ]]; then + return 0 # Covered by wildcard + fi + + return 1 # Not covered +} diff --git a/data/web/inc/functions.auth.inc.php b/data/web/inc/functions.auth.inc.php index 91a8c55f..e5a303f9 100644 --- a/data/web/inc/functions.auth.inc.php +++ b/data/web/inc/functions.auth.inc.php @@ -287,6 +287,8 @@ function user_login($user, $pass, $extra = null){ return false; } + $row['attributes'] = json_decode($row['attributes'], true); + // check for tfa authenticators $authenticators = get_tfa($user); if (isset($authenticators['additional']) && is_array($authenticators['additional']) && count($authenticators['additional']) > 0 && !$is_internal) { @@ -343,6 +345,8 @@ function user_login($user, $pass, $extra = null){ return false; } + $row['attributes'] = json_decode($row['attributes'], true); + // check for tfa authenticators $authenticators = get_tfa($user); if (isset($authenticators['additional']) && is_array($authenticators['additional']) && count($authenticators['additional']) > 0 && !$is_internal) { diff --git a/data/web/js/build/013-mailcow.js b/data/web/js/build/013-mailcow.js index d897f23e..e4893d7a 100644 --- a/data/web/js/build/013-mailcow.js +++ b/data/web/js/build/013-mailcow.js @@ -345,7 +345,7 @@ $(document).ready(function() { $('.main-logo-dark').addClass('d-none'); if ($('#rspamd_logo').length) $('#rspamd_logo').attr('src', '/img/rspamd_logo_dark.png'); if ($('#rspamd_logo_sm').length) $('#rspamd_logo_sm').attr('src', '/img/rspamd_logo_dark.png'); - localStorage.setItem('theme', 'light'); + localStorage.setItem('mailcow_theme', 'light'); }else{ $('head').append(''); $('#dark-mode-toggle').prop('checked', true); @@ -353,7 +353,7 @@ $(document).ready(function() { $('.main-logo-dark').removeClass('d-none'); if ($('#rspamd_logo').length) $('#rspamd_logo').attr('src', '/img/rspamd_logo_light.png'); if ($('#rspamd_logo_sm').length) $('#rspamd_logo_sm').attr('src', '/img/rspamd_logo_light.png'); - localStorage.setItem('theme', 'dark'); + localStorage.setItem('mailcow_theme', 'dark'); } } diff --git a/data/web/js/site/index.js b/data/web/js/site/index.js index 4c812a37..29b72f0d 100644 --- a/data/web/js/site/index.js +++ b/data/web/js/site/index.js @@ -1,5 +1,6 @@ $(document).ready(function() { - var theme = localStorage.getItem("theme"); - localStorage.clear(); - localStorage.setItem("theme", theme); + var theme = localStorage.getItem("mailcow_theme"); + if (theme !== null) { + localStorage.setItem("mailcow_theme", theme); + } }); diff --git a/data/web/lang/lang.hu-hu.json b/data/web/lang/lang.hu-hu.json index e51748c4..ff49bc5e 100644 --- a/data/web/lang/lang.hu-hu.json +++ b/data/web/lang/lang.hu-hu.json @@ -1144,7 +1144,8 @@ "subscribeall": "Feliratkozás minden mappára", "syncjob": "Szinkronizálási feladat hozzáadása", "internal": "Belső", - "internal_info": "Belső álnevek csak a saját domain vagy domain álnév számára elérhető." + "internal_info": "Belső álnevek csak a saját domain vagy domain álnév számára elérhető.", + "sender_allowed": "Küldés engedélyezése ezzel az aliasszal" }, "danger": { "access_denied": "Hozzáférés megtagatva vagy nem megfelelő űrlap adat", @@ -1245,6 +1246,21 @@ "pushover_key": "A pushover kulcs rossz formátumú", "pushover_token": "A Pushover token rossz formátumú", "quota_not_0_not_numeric": "A kvótának numerikusnak és >= 0-nak kell lennie.", - "recipient_map_entry_exists": "Létezik egy \"%s\" címzett-térkép bejegyzés" + "recipient_map_entry_exists": "Létezik egy \"%s\" címzett-térkép bejegyzés", + "redis_error": "Redis hiba lépett fel: %s", + "relayhost_invalid": "A(z) %s elem érvénytelen a leképezésben.", + "release_send_failed": "Az üzenet felszabadítása sikertelen: %s", + "reset_f2b_regex": "A regex-szűrő időtúllépés miatt nem állt le. Próbálja újra, vagy várjon egy kicsit, és töltse újra az oldalt.", + "resource_invalid": "A(z) %s erőforrásnév érvénytelen", + "rl_timeframe": "Érvénytelen időkeret a lekérdezési korláthoz", + "rspamd_ui_pw_length": "A Rspamd UI jelszónak legalább 6 karakter hosszúnak kell lennie.", + "script_empty": "A szkript nem lehet üres", + "sender_acl_invalid": "A küldőhöz tartozó ACL-érték (%s) érvénytelen", + "set_acl_failed": "Az ACL beállítása meghiúsult", + "settings_map_invalid": "Érvénytelen beállítás-leképezési azonosító: %s", + "recovery_email_failed": "A helyreállítási email kiküldése sikertelen. Kérlek, lépj kapcsolatba az adminisztrátorral!", + "reset_token_limit_exceeded": "Túl sok visszaállítási kísérlet. Kérjük, várjon, mielőtt újra próbálkozna.", + "required_data_missing": "Hiányzik a(z) szükséges %s adat", + "tfa_removal_blocked": "A kétfaktoros hitelesítés nem távolítható el, mert elengedhetetlen a fiókod használatához." } } diff --git a/data/web/templates/base.twig b/data/web/templates/base.twig index 4290edae..e1708950 100644 --- a/data/web/templates/base.twig +++ b/data/web/templates/base.twig @@ -11,8 +11,8 @@