mirror of
https://github.com/mailcow/mailcow-dockerized.git
synced 2026-03-13 18:21:23 +00:00
Compare commits
15 Commits
2026-03
...
fix/7112-2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
127fb1e8f5 | ||
|
|
09f09cb850 | ||
|
|
d4bf377a96 | ||
|
|
abd6fe8c79 | ||
|
|
5f8382ef44 | ||
|
|
03eccd4e42 | ||
|
|
1da8d1c894 | ||
|
|
d1feebf164 | ||
|
|
293b885a85 | ||
|
|
1e0850193a | ||
|
|
33acf56526 | ||
|
|
bea9ad7e8f | ||
|
|
e7ea3aa608 | ||
|
|
5888e248c3 | ||
|
|
2e176339ba |
@@ -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,33 @@ 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} && ! -z ${ADDITIONAL_SAN} ]]; then
|
||||
# Extract parent domain from MAILCOW_HOSTNAME (e.g., mail.example.com -> example.com)
|
||||
MAILCOW_PARENT_DOMAIN=$(echo ${VALIDATED_MAILCOW_HOSTNAME} | cut -d. -f2-)
|
||||
# Check if ADDITIONAL_SAN contains a wildcard for this parent domain
|
||||
if [[ "${ADDITIONAL_SAN}" == *"*.${MAILCOW_PARENT_DOMAIN}"* ]]; then
|
||||
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]}
|
||||
|
||||
@@ -135,3 +135,25 @@ verify_challenge_path(){
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if a domain is covered by a wildcard in ADDITIONAL_SAN
|
||||
# Usage: is_covered_by_wildcard "subdomain.example.com"
|
||||
# Returns: 0 if covered, 1 if not covered
|
||||
is_covered_by_wildcard() {
|
||||
local DOMAIN=$1
|
||||
|
||||
# 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
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
git \
|
||||
build-essential \
|
||||
gobjc \
|
||||
pkg-config \
|
||||
gnustep-make \
|
||||
gnustep-base-runtime \
|
||||
libgnustep-base-dev \
|
||||
@@ -40,6 +41,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
libcurl4-openssl-dev \
|
||||
libzip-dev \
|
||||
libytnef0-dev \
|
||||
libwbxml2-dev \
|
||||
curl \
|
||||
ca-certificates \
|
||||
# Runtime dependencies
|
||||
@@ -68,6 +70,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
libcurl4 \
|
||||
libzip4 \
|
||||
libytnef0 \
|
||||
libwbxml2-1 \
|
||||
# Download gosu
|
||||
&& dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')" \
|
||||
&& wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch" \
|
||||
@@ -97,6 +100,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
&& ./configure --disable-debug --disable-strip \
|
||||
&& make -j$(nproc) \
|
||||
&& make install \
|
||||
&& cd /tmp/sogo/ActiveSync \
|
||||
&& . /usr/share/GNUstep/Makefiles/GNUstep.sh \
|
||||
&& make -j$(nproc) install \
|
||||
&& cd / \
|
||||
&& rm -rf /tmp/sogo \
|
||||
# Strip binaries
|
||||
@@ -146,8 +152,8 @@ RUN echo "/usr/lib64" > /etc/ld.so.conf.d/sogo.conf \
|
||||
# Create sogo user and group
|
||||
RUN groupadd -r -g 999 sogo \
|
||||
&& useradd -r -u 999 -g sogo -d /var/lib/sogo -s /bin/bash -c "SOGo Daemon" sogo \
|
||||
&& mkdir -p /var/lib/sogo /var/run/sogo /var/log/sogo \
|
||||
&& chown -R sogo:sogo /var/lib/sogo /var/run/sogo /var/log/sogo
|
||||
&& mkdir -p /var/lib/sogo /var/run/sogo /var/log/sogo /var/spool/sogo \
|
||||
&& chown -R sogo:sogo /var/lib/sogo /var/run/sogo /var/log/sogo /var/spool/sogo
|
||||
|
||||
# Create symlinks for SOGo binaries
|
||||
RUN ln -s /usr/local/sbin/sogod /usr/sbin/sogod \
|
||||
|
||||
@@ -37,5 +37,6 @@ RUN apk add --update \
|
||||
COPY watchdog.sh /watchdog.sh
|
||||
COPY check_mysql_slavestatus.sh /usr/lib/nagios/plugins/check_mysql_slavestatus.sh
|
||||
COPY check_dns.sh /usr/lib/mailcow/check_dns.sh
|
||||
COPY client.cnf /etc/my.cnf.d/client.cnf
|
||||
|
||||
CMD ["/watchdog.sh"]
|
||||
|
||||
3
data/Dockerfiles/watchdog/client.cnf
Normal file
3
data/Dockerfiles/watchdog/client.cnf
Normal file
@@ -0,0 +1,3 @@
|
||||
[client]
|
||||
ssl = false
|
||||
ssl-verify-server-cert = false
|
||||
@@ -38,7 +38,7 @@ if [[ ! -p /tmp/com_pipe ]]; then
|
||||
fi
|
||||
|
||||
# Wait for containers
|
||||
while ! mariadb-admin status --ssl=false --socket=/var/run/mysqld/mysqld.sock -u${DBUSER} -p${DBPASS} --silent; do
|
||||
while ! mariadb-admin status --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u${DBUSER} -p${DBPASS} --silent; do
|
||||
echo "Waiting for SQL..."
|
||||
sleep 2
|
||||
done
|
||||
@@ -359,8 +359,8 @@ mysql_checks() {
|
||||
while [ ${err_count} -lt ${THRESHOLD} ]; do
|
||||
touch /tmp/mysql-mailcow; echo "$(tail -50 /tmp/mysql-mailcow)" > /tmp/mysql-mailcow
|
||||
err_c_cur=${err_count}
|
||||
/usr/lib/nagios/plugins/check_mysql -s /var/run/mysqld/mysqld.sock -u ${DBUSER} -p ${DBPASS} -d ${DBNAME} 2>> /tmp/mysql-mailcow 1>&2; err_count=$(( ${err_count} + $? ))
|
||||
/usr/lib/nagios/plugins/check_mysql_query -s /var/run/mysqld/mysqld.sock -u ${DBUSER} -p ${DBPASS} -d ${DBNAME} -q "SELECT COUNT(*) FROM information_schema.tables" 2>> /tmp/mysql-mailcow 1>&2; err_count=$(( ${err_count} + $? ))
|
||||
/usr/lib/nagios/plugins/check_mysql -f /etc/my.cnf.d/client.cnf -s /var/run/mysqld/mysqld.sock -u ${DBUSER} -p ${DBPASS} -d ${DBNAME} 2>> /tmp/mysql-mailcow 1>&2; err_count=$(( ${err_count} + $? ))
|
||||
/usr/lib/nagios/plugins/check_mysql_query -f /etc/my.cnf.d/client.cnf -s /var/run/mysqld/mysqld.sock -u ${DBUSER} -p ${DBPASS} -d ${DBNAME} -q "SELECT COUNT(*) FROM information_schema.tables" 2>> /tmp/mysql-mailcow 1>&2; err_count=$(( ${err_count} + $? ))
|
||||
[ ${err_c_cur} -eq ${err_count} ] && [ ! $((${err_count} - 1)) -lt 0 ] && err_count=$((${err_count} - 1)) diff_c=1
|
||||
[ ${err_c_cur} -ne ${err_count} ] && diff_c=$(( ${err_c_cur} - ${err_count} ))
|
||||
progress "MySQL/MariaDB" ${THRESHOLD} $(( ${THRESHOLD} - ${err_count} )) ${diff_c}
|
||||
@@ -384,7 +384,7 @@ mysql_repl_checks() {
|
||||
while [ ${err_count} -lt ${THRESHOLD} ]; do
|
||||
touch /tmp/mysql_repl_checks; echo "$(tail -50 /tmp/mysql_repl_checks)" > /tmp/mysql_repl_checks
|
||||
err_c_cur=${err_count}
|
||||
/usr/lib/nagios/plugins/check_mysql_slavestatus.sh -S /var/run/mysqld/mysqld.sock -u root -p ${DBROOT} 2>> /tmp/mysql_repl_checks 1>&2; err_count=$(( ${err_count} + $? ))
|
||||
/usr/lib/nagios/plugins/check_mysql_slavestatus.sh -o /etc/my.cnf.d/client.cnf -S /var/run/mysqld/mysqld.sock -u root -p ${DBROOT} 2>> /tmp/mysql_repl_checks 1>&2; err_count=$(( ${err_count} + $? ))
|
||||
[ ${err_c_cur} -eq ${err_count} ] && [ ! $((${err_count} - 1)) -lt 0 ] && err_count=$((${err_count} - 1)) diff_c=1
|
||||
[ ${err_c_cur} -ne ${err_count} ] && diff_c=$(( ${err_c_cur} - ${err_count} ))
|
||||
progress "MySQL/MariaDB replication" ${THRESHOLD} $(( ${THRESHOLD} - ${err_count} )) ${diff_c}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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('<link id="dark-mode-theme" rel="stylesheet" type="text/css" href="/css/themes/mailcow-darkmode.css">');
|
||||
$('#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');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
<link rel="stylesheet" href="{{ css_path }}">
|
||||
<script>
|
||||
// check if darkmode is preferred by OS or set by localStorage
|
||||
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches && localStorage.getItem("theme") !== "light" ||
|
||||
localStorage.getItem("theme") === "dark") {
|
||||
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches && localStorage.getItem("mailcow_theme") !== "light" ||
|
||||
localStorage.getItem("mailcow_theme") === "dark") {
|
||||
var head = document.getElementsByTagName('head')[0];
|
||||
var link = document.createElement('link');
|
||||
link.id = 'dark-mode-theme';
|
||||
|
||||
@@ -200,7 +200,7 @@ services:
|
||||
- phpfpm
|
||||
|
||||
sogo-mailcow:
|
||||
image: ghcr.io/mailcow/sogo:5.12.5-1
|
||||
image: ghcr.io/mailcow/sogo:5.12.5-3
|
||||
environment:
|
||||
- DBNAME=${DBNAME}
|
||||
- DBUSER=${DBUSER}
|
||||
@@ -465,7 +465,7 @@ services:
|
||||
condition: service_started
|
||||
unbound-mailcow:
|
||||
condition: service_healthy
|
||||
image: ghcr.io/mailcow/acme:1.96
|
||||
image: ghcr.io/mailcow/acme:1.97
|
||||
dns:
|
||||
- ${IPV4_NETWORK:-172.22.1}.254
|
||||
environment:
|
||||
@@ -526,7 +526,7 @@ services:
|
||||
- /lib/modules:/lib/modules:ro
|
||||
|
||||
watchdog-mailcow:
|
||||
image: ghcr.io/mailcow/watchdog:2.10
|
||||
image: ghcr.io/mailcow/watchdog:2.11
|
||||
dns:
|
||||
- ${IPV4_NETWORK:-172.22.1}.254
|
||||
tmpfs:
|
||||
|
||||
Reference in New Issue
Block a user