mirror of
https://github.com/mailcow/mailcow-dockerized.git
synced 2026-06-17 12:00:35 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7e6003ef24 | |||
| 2b38f348a5 | |||
| c5906dfb2f | |||
| 0221c4ccf2 |
@@ -246,25 +246,6 @@ while true; do
|
|||||||
done
|
done
|
||||||
VALIDATED_CONFIG_DOMAINS+=("${VALIDATED_CONFIG_DOMAINS_SUBDOMAINS[*]}")
|
VALIDATED_CONFIG_DOMAINS+=("${VALIDATED_CONFIG_DOMAINS_SUBDOMAINS[*]}")
|
||||||
done
|
done
|
||||||
|
|
||||||
# Fetch alias domains where target domain has MTA-STS enabled
|
|
||||||
if [[ ${AUTODISCOVER_SAN} == "y" ]]; then
|
|
||||||
SQL_ALIAS_DOMAINS=$(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT ad.alias_domain FROM alias_domain ad INNER JOIN mta_sts m ON ad.target_domain = m.domain WHERE ad.active = 1 AND m.active = 1" -Bs)
|
|
||||||
if [[ $? -eq 0 ]]; then
|
|
||||||
while read alias_domain; do
|
|
||||||
if [[ -z "${alias_domain}" ]]; then
|
|
||||||
# ignore empty lines
|
|
||||||
continue
|
|
||||||
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
|
|
||||||
VALIDATED_CONFIG_DOMAINS+=("mta-sts.${alias_domain}")
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done <<< "${SQL_ALIAS_DOMAINS}"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if check_domain ${MAILCOW_HOSTNAME}; then
|
if check_domain ${MAILCOW_HOSTNAME}; then
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ FROM debian:trixie-slim
|
|||||||
LABEL maintainer="The Infrastructure Company GmbH <info@servercow.de>"
|
LABEL maintainer="The Infrastructure Company GmbH <info@servercow.de>"
|
||||||
|
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
ARG RSPAMD_VER=rspamd_3.14.2-82~90302bc
|
ARG RSPAMD_VER=rspamd_3.14.1-1~46a758617
|
||||||
ARG CODENAME=trixie
|
ARG CODENAME=trixie
|
||||||
ENV LC_ALL=C
|
ENV LC_ALL=C
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
{%- if env.SKIP_CLAMD == "n" or env.SKIP_CLAMD == "no" -%}
|
|
||||||
clamav {
|
clamav {
|
||||||
# Scan whole message
|
# Scan whole message
|
||||||
scan_mime_parts = false;
|
scan_mime_parts = false;
|
||||||
@@ -10,4 +9,3 @@ clamav {
|
|||||||
servers = "clamd:3310";
|
servers = "clamd:3310";
|
||||||
max_size = 20971520;
|
max_size = 20971520;
|
||||||
}
|
}
|
||||||
{% endif %}
|
|
||||||
|
|||||||
@@ -129,16 +129,7 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if domain is an alias domain and get target domain's MTA-STS
|
$mta_sts = mailbox('get', 'mta_sts', $domain);
|
||||||
$alias_domain_details = mailbox('get', 'alias_domain_details', $domain);
|
|
||||||
$mta_sts_domain = $domain;
|
|
||||||
|
|
||||||
if ($alias_domain_details !== false && !empty($alias_domain_details['target_domain'])) {
|
|
||||||
// This is an alias domain, check target domain for MTA-STS
|
|
||||||
$mta_sts_domain = $alias_domain_details['target_domain'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$mta_sts = mailbox('get', 'mta_sts', $mta_sts_domain);
|
|
||||||
if (count($mta_sts) > 0 && $mta_sts['active'] == 1) {
|
if (count($mta_sts) > 0 && $mta_sts['active'] == 1) {
|
||||||
if (!in_array($domain, $alias_domains)) {
|
if (!in_array($domain, $alias_domains)) {
|
||||||
$records[] = array(
|
$records[] = array(
|
||||||
|
|||||||
@@ -251,6 +251,73 @@ function password_check($password1, $password2) {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
function generate_app_passwd($length = 32) {
|
||||||
|
// Get password complexity requirements
|
||||||
|
$password_complexity = password_complexity('get');
|
||||||
|
|
||||||
|
// Determine the actual length to use
|
||||||
|
$required_length = max($length, intval($password_complexity['length']));
|
||||||
|
|
||||||
|
// Define character sets
|
||||||
|
$lowercase = 'abcdefghijklmnopqrstuvwxyz';
|
||||||
|
$uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||||
|
$digits = '0123456789';
|
||||||
|
$special = '!@#$%^&*()-_=+[]{}|;:,.<>?';
|
||||||
|
|
||||||
|
// Build the character pool and required chars based on policy
|
||||||
|
$pool = '';
|
||||||
|
$required_chars = '';
|
||||||
|
|
||||||
|
// Add digits to pool and ensure at least one if required
|
||||||
|
if ($password_complexity['numbers'] == 1) {
|
||||||
|
$pool .= $digits;
|
||||||
|
$required_chars .= $digits[random_int(0, strlen($digits) - 1)];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add alphabetic characters if required
|
||||||
|
if ($password_complexity['chars'] == 1) {
|
||||||
|
$pool .= $lowercase;
|
||||||
|
// Only add required char if not already added by lowerupper requirement
|
||||||
|
if ($password_complexity['lowerupper'] != 1) {
|
||||||
|
$required_chars .= $lowercase[random_int(0, strlen($lowercase) - 1)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add both uppercase and lowercase letters if lowerupper required
|
||||||
|
if ($password_complexity['lowerupper'] == 1) {
|
||||||
|
$pool .= $lowercase . $uppercase;
|
||||||
|
$required_chars .= $uppercase[random_int(0, strlen($uppercase) - 1)];
|
||||||
|
$required_chars .= $lowercase[random_int(0, strlen($lowercase) - 1)];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add special characters if required
|
||||||
|
if ($password_complexity['special_chars'] == 1) {
|
||||||
|
$pool .= $special;
|
||||||
|
$required_chars .= $special[random_int(0, strlen($special) - 1)];
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no requirements specified, use alphanumeric as default
|
||||||
|
if (empty($pool)) {
|
||||||
|
$pool = $lowercase . $uppercase . $digits;
|
||||||
|
$required_chars .= $digits[random_int(0, strlen($digits) - 1)];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the password is at least as long as the required characters
|
||||||
|
$final_length = max($required_length, strlen($required_chars));
|
||||||
|
|
||||||
|
// Generate remaining characters from the pool
|
||||||
|
$remaining_length = $final_length - strlen($required_chars);
|
||||||
|
$password = $required_chars;
|
||||||
|
|
||||||
|
for ($i = 0; $i < $remaining_length; $i++) {
|
||||||
|
$password .= $pool[random_int(0, strlen($pool) - 1)];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shuffle the password to mix required chars with random ones
|
||||||
|
$password = str_shuffle($password);
|
||||||
|
|
||||||
|
return $password;
|
||||||
|
}
|
||||||
function last_login($action, $username, $sasl_limit_days = 7, $ui_offset = 1) {
|
function last_login($action, $username, $sasl_limit_days = 7, $ui_offset = 1) {
|
||||||
global $pdo;
|
global $pdo;
|
||||||
global $redis;
|
global $redis;
|
||||||
|
|||||||
@@ -54,16 +54,7 @@ jQuery(function($){
|
|||||||
$.get("/inc/ajax/show_rspamd_global_filters.php");
|
$.get("/inc/ajax/show_rspamd_global_filters.php");
|
||||||
$("#confirm_show_rspamd_global_filters").hide();
|
$("#confirm_show_rspamd_global_filters").hide();
|
||||||
$("#rspamd_global_filters").removeClass("d-none");
|
$("#rspamd_global_filters").removeClass("d-none");
|
||||||
localStorage.setItem('rspamd_global_filters_confirmed', 'true');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).ready(function() {
|
|
||||||
if (localStorage.getItem('rspamd_global_filters_confirmed') === 'true') {
|
|
||||||
$("#confirm_show_rspamd_global_filters").hide();
|
|
||||||
$("#rspamd_global_filters").removeClass("d-none");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#super_delete").click(function() { return confirm(lang.queue_ays); });
|
$("#super_delete").click(function() { return confirm(lang.queue_ays); });
|
||||||
|
|
||||||
$(".refresh_table").on('click', function(e) {
|
$(".refresh_table").on('click', function(e) {
|
||||||
|
|||||||
@@ -1266,7 +1266,7 @@
|
|||||||
"no_last_login": "Aucune dernière information de connexion à l'interface",
|
"no_last_login": "Aucune dernière information de connexion à l'interface",
|
||||||
"no_record": "Pas d'enregistrement",
|
"no_record": "Pas d'enregistrement",
|
||||||
"password": "Mot de passe",
|
"password": "Mot de passe",
|
||||||
"password_now": "Mot de passe actuel (confirmer les changements)",
|
"password_now": "Mot de passe courant (confirmer les changements)",
|
||||||
"password_repeat": "Mot de passe (répéter)",
|
"password_repeat": "Mot de passe (répéter)",
|
||||||
"pushover_evaluate_x_prio": "Acheminement du courrier hautement prioritaire [<code>X-Priority: 1</code>]",
|
"pushover_evaluate_x_prio": "Acheminement du courrier hautement prioritaire [<code>X-Priority: 1</code>]",
|
||||||
"pushover_info": "Les paramètres de notification push s’appliqueront à tout le courrier propre (non spam) livré à <b>%s</b> y compris les alias (partagés, non partagés, étiquetés).",
|
"pushover_info": "Les paramètres de notification push s’appliqueront à tout le courrier propre (non spam) livré à <b>%s</b> y compris les alias (partagés, non partagés, étiquetés).",
|
||||||
|
|||||||
@@ -240,7 +240,7 @@
|
|||||||
"generate": "Generuj",
|
"generate": "Generuj",
|
||||||
"guid": "GUID - unikalny identyfikator instancji",
|
"guid": "GUID - unikalny identyfikator instancji",
|
||||||
"guid_and_license": "GUID & licencja",
|
"guid_and_license": "GUID & licencja",
|
||||||
"hash_remove_info": "Usunięcie hasha z limitem współczynnika (jeśli nadal istnieje) spowoduje całkowite zresetowanie jego licznika.<br> Każdy hash jest oznaczony indywidualnym kolorem.",
|
"hash_remove_info": "Usunięcie hasha z limitem współczynnika (jeśli nadal istnieje) spowoduje całkowite zresetowanie jego licznika.<br>\n\n\n\n Każdy hash jest oznaczony indywidualnym kolorem.",
|
||||||
"help_text": "Zastąp tekst pomocy poniżej maski logowania (dozwolone HTML)",
|
"help_text": "Zastąp tekst pomocy poniżej maski logowania (dozwolone HTML)",
|
||||||
"html": "HTML",
|
"html": "HTML",
|
||||||
"iam": "Dostawca tożsamości",
|
"iam": "Dostawca tożsamości",
|
||||||
@@ -683,11 +683,7 @@
|
|||||||
"mailbox_rename_agree": "Stworzyłem kopię zapasową.",
|
"mailbox_rename_agree": "Stworzyłem kopię zapasową.",
|
||||||
"mailbox_rename_warning": "WAŻNE! Utwórz kopię zapasową przed zmianą nazwy skrzynki pocztowej.",
|
"mailbox_rename_warning": "WAŻNE! Utwórz kopię zapasową przed zmianą nazwy skrzynki pocztowej.",
|
||||||
"mailbox_rename_alias": "Tworzenie aliasów automatycznie",
|
"mailbox_rename_alias": "Tworzenie aliasów automatycznie",
|
||||||
"mailbox_rename_title": "Nowa nazwa lokalnej skrzynki pocztowej",
|
"mailbox_rename_title": "Nowa nazwa lokalnej skrzynki pocztowej"
|
||||||
"mbox_rl_info": "Ten limit szybkości dotyczy nazwy logowania SASL i odpowiada dowolnemu adresowi „from” używanemu przez zalogowanego użytkownika. Limit szybkości dla skrzynki pocztowej nadpisuje limit szybkości dla całej domeny.",
|
|
||||||
"nexthop": "Następny hop",
|
|
||||||
"private_comment": "Prywatny komentarz",
|
|
||||||
"public_comment": "Komentarz publiczny"
|
|
||||||
},
|
},
|
||||||
"footer": {
|
"footer": {
|
||||||
"cancel": "Anuluj",
|
"cancel": "Anuluj",
|
||||||
@@ -1079,7 +1075,7 @@
|
|||||||
"spamfilter_table_remove": "Usuń",
|
"spamfilter_table_remove": "Usuń",
|
||||||
"spamfilter_table_rule": "Zasada",
|
"spamfilter_table_rule": "Zasada",
|
||||||
"spamfilter_wl": "Biała lista",
|
"spamfilter_wl": "Biała lista",
|
||||||
"spamfilter_wl_desc": "Adresy e-mail znajdujące się na liście dozwolonych (allowlist) są zaprogramowane tak, aby <b> nigdy nie </b> były klasyfikowane jako spam. Można używać symboli wieloznacznych (wildcardów).Filtr jest stosowany wyłącznie do bezpośrednich aliasów (aliasów wskazujących na jedną skrzynkę pocztową), z wyłączeniem aliasów typu „catch-all” oraz samej skrzynki pocztowej",
|
"spamfilter_wl_desc": "Adresy e-mail znajdujące się na liście dozwolonych (allowlist) są zaprogramowane tak, aby <b> nigdy nie </b> były klasyfikowane jako spam.\nMożna używać symboli wieloznacznych (wildcardów).\nFiltr jest stosowany wyłącznie do bezpośrednich aliasów (aliasów wskazujących na jedną skrzynkę pocztową), z wyłączeniem aliasów typu „catch-all” oraz samej skrzynki pocztowej",
|
||||||
"spamfilter_yellow": "Żółty: ta wiadomość może być spamem, zostanie oznaczona jako spam i przeniesiona do folderu spam",
|
"spamfilter_yellow": "Żółty: ta wiadomość może być spamem, zostanie oznaczona jako spam i przeniesiona do folderu spam",
|
||||||
"sync_jobs": "Zadania synchronizacji",
|
"sync_jobs": "Zadania synchronizacji",
|
||||||
"tag_handling": "Ustaw obsługę znaczników pocztowych",
|
"tag_handling": "Ustaw obsługę znaczników pocztowych",
|
||||||
|
|||||||
@@ -340,8 +340,7 @@
|
|||||||
"tls_policy": "Política de TLS",
|
"tls_policy": "Política de TLS",
|
||||||
"quarantine_attachments": "Anexos de quarentena",
|
"quarantine_attachments": "Anexos de quarentena",
|
||||||
"filters": "Filtros",
|
"filters": "Filtros",
|
||||||
"smtp_ip_access": "Mudar anfitriões permitidos para SMTP",
|
"smtp_ip_access": "Mudar anfitriões permitidos para SMTP"
|
||||||
"app_passwds": "Gerenciar senhas de aplicativos"
|
|
||||||
},
|
},
|
||||||
"warning": {
|
"warning": {
|
||||||
"no_active_admin": "Não é possível desactivar o último administrador activo"
|
"no_active_admin": "Não é possível desactivar o último administrador activo"
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ if (isset($_GET['app_password'])) {
|
|||||||
else
|
else
|
||||||
$platform = $_SERVER['HTTP_USER_AGENT'];
|
$platform = $_SERVER['HTTP_USER_AGENT'];
|
||||||
|
|
||||||
$password = bin2hex(openssl_random_pseudo_bytes(16));
|
$password = generate_app_passwd();
|
||||||
$attr = array(
|
$attr = array(
|
||||||
'app_name' => $platform,
|
'app_name' => $platform,
|
||||||
'app_passwd' => $password,
|
'app_passwd' => $password,
|
||||||
|
|||||||
+1
-24
@@ -7,30 +7,7 @@ if (!isset($_SERVER['HTTP_HOST']) || strpos($_SERVER['HTTP_HOST'], 'mta-sts.') !
|
|||||||
}
|
}
|
||||||
|
|
||||||
$host = preg_replace('/:[0-9]+$/', '', $_SERVER['HTTP_HOST']);
|
$host = preg_replace('/:[0-9]+$/', '', $_SERVER['HTTP_HOST']);
|
||||||
$domain = idn_to_ascii(strtolower(str_replace('mta-sts.', '', $host)), 0, INTL_IDNA_VARIANT_UTS46);
|
$domain = str_replace('mta-sts.', '', $host);
|
||||||
|
|
||||||
// Validate domain or return 404 on error
|
|
||||||
if ($domain === false || empty($domain)) {
|
|
||||||
http_response_code(404);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if domain is an alias domain and resolve to target domain
|
|
||||||
try {
|
|
||||||
$stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :domain");
|
|
||||||
$stmt->execute(array(':domain' => $domain));
|
|
||||||
$alias_row = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
||||||
|
|
||||||
if ($alias_row !== false && !empty($alias_row['target_domain'])) {
|
|
||||||
// This is an alias domain, use the target domain for MTA-STS lookup
|
|
||||||
$domain = $alias_row['target_domain'];
|
|
||||||
}
|
|
||||||
} catch (PDOException $e) {
|
|
||||||
// On database error, return 404
|
|
||||||
http_response_code(404);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$mta_sts = mailbox('get', 'mta_sts', $domain);
|
$mta_sts = mailbox('get', 'mta_sts', $domain);
|
||||||
|
|
||||||
if (count($mta_sts) == 0 ||
|
if (count($mta_sts) == 0 ||
|
||||||
|
|||||||
+2
-3
@@ -84,7 +84,7 @@ services:
|
|||||||
- clamd
|
- clamd
|
||||||
|
|
||||||
rspamd-mailcow:
|
rspamd-mailcow:
|
||||||
image: ghcr.io/mailcow/rspamd:3.14.2
|
image: ghcr.io/mailcow/rspamd:3.14.1
|
||||||
stop_grace_period: 30s
|
stop_grace_period: 30s
|
||||||
depends_on:
|
depends_on:
|
||||||
- dovecot-mailcow
|
- dovecot-mailcow
|
||||||
@@ -97,7 +97,6 @@ services:
|
|||||||
- REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
|
- REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
|
||||||
- REDISPASS=${REDISPASS}
|
- REDISPASS=${REDISPASS}
|
||||||
- SPAMHAUS_DQS_KEY=${SPAMHAUS_DQS_KEY:-}
|
- SPAMHAUS_DQS_KEY=${SPAMHAUS_DQS_KEY:-}
|
||||||
- RSPAMD_SKIP_CLAMD=${SKIP_CLAMD:-n}
|
|
||||||
volumes:
|
volumes:
|
||||||
- ./data/hooks/rspamd:/hooks:Z
|
- ./data/hooks/rspamd:/hooks:Z
|
||||||
- ./data/conf/rspamd/custom/:/etc/rspamd/custom:z
|
- ./data/conf/rspamd/custom/:/etc/rspamd/custom:z
|
||||||
@@ -466,7 +465,7 @@ services:
|
|||||||
condition: service_started
|
condition: service_started
|
||||||
unbound-mailcow:
|
unbound-mailcow:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
image: ghcr.io/mailcow/acme:1.95
|
image: ghcr.io/mailcow/acme:1.94
|
||||||
dns:
|
dns:
|
||||||
- ${IPV4_NETWORK:-172.22.1}.254
|
- ${IPV4_NETWORK:-172.22.1}.254
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
Reference in New Issue
Block a user