mirror of
https://github.com/mailcow/mailcow-dockerized.git
synced 2026-06-18 12:30:36 +00:00
Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 281cf93db3 | |||
| ec24825280 | |||
| 5a00b5124b | |||
| 8c039f694f | |||
| 95bf46c1e4 | |||
| edde35156d | |||
| 84e3c32f13 | |||
| ecb848493b | |||
| 8a65b9d1c6 | |||
| f399c07c85 | |||
| ed9264fd2a | |||
| a693325fe6 | |||
| 7817dda43f | |||
| 018e292854 | |||
| 127fb1e8f5 | |||
| 09f09cb850 | |||
| d4bf377a96 | |||
| abd6fe8c79 | |||
| 5f8382ef44 | |||
| 03eccd4e42 | |||
| 1da8d1c894 | |||
| d1feebf164 | |||
| 293b885a85 | |||
| 9ad84eee92 | |||
| 1e0850193a | |||
| 33acf56526 | |||
| b59869b720 | |||
| bea9ad7e8f | |||
| e7ea3aa608 | |||
| 7515bef66c | |||
| 5888e248c3 | |||
| 2e176339ba |
@@ -253,10 +253,20 @@ while true; do
|
|||||||
unset VALIDATED_CONFIG_DOMAINS_SUBDOMAINS
|
unset VALIDATED_CONFIG_DOMAINS_SUBDOMAINS
|
||||||
declare -a VALIDATED_CONFIG_DOMAINS_SUBDOMAINS
|
declare -a VALIDATED_CONFIG_DOMAINS_SUBDOMAINS
|
||||||
for SUBDOMAIN in "${ADDITIONAL_WC_ARR[@]}"; do
|
for SUBDOMAIN in "${ADDITIONAL_WC_ARR[@]}"; do
|
||||||
if [[ "${SUBDOMAIN}.${SQL_DOMAIN}" != "${MAILCOW_HOSTNAME}" ]]; then
|
FULL_SUBDOMAIN="${SUBDOMAIN}.${SQL_DOMAIN}"
|
||||||
if check_domain "${SUBDOMAIN}.${SQL_DOMAIN}"; then
|
|
||||||
VALIDATED_CONFIG_DOMAINS_SUBDOMAINS+=("${SUBDOMAIN}.${SQL_DOMAIN}")
|
# Skip if subdomain matches MAILCOW_HOSTNAME
|
||||||
fi
|
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
|
fi
|
||||||
done
|
done
|
||||||
VALIDATED_CONFIG_DOMAINS+=("${VALIDATED_CONFIG_DOMAINS_SUBDOMAINS[*]}")
|
VALIDATED_CONFIG_DOMAINS+=("${VALIDATED_CONFIG_DOMAINS_SUBDOMAINS[*]}")
|
||||||
@@ -273,7 +283,10 @@ while true; do
|
|||||||
fi
|
fi
|
||||||
# Only add mta-sts subdomain for alias domains
|
# Only add mta-sts subdomain for alias domains
|
||||||
if [[ "mta-sts.${alias_domain}" != "${MAILCOW_HOSTNAME}" ]]; then
|
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}")
|
VALIDATED_CONFIG_DOMAINS+=("mta-sts.${alias_domain}")
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@@ -308,13 +321,31 @@ while true; do
|
|||||||
done
|
done
|
||||||
fi
|
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
|
# Unique domains for server certificate
|
||||||
if [[ ${ENABLE_SSL_SNI} == "y" ]]; then
|
if [[ ${ENABLE_SSL_SNI} == "y" ]]; then
|
||||||
# create certificate for server name and fqdn SANs only
|
# 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
|
else
|
||||||
# create certificate for all domains, including all subdomains from other domains [*]
|
# 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
|
fi
|
||||||
if [[ ! -z ${SERVER_SAN_VALIDATED[*]} ]]; then
|
if [[ ! -z ${SERVER_SAN_VALIDATED[*]} ]]; then
|
||||||
CERT_NAME=${SERVER_SAN_VALIDATED[0]}
|
CERT_NAME=${SERVER_SAN_VALIDATED[0]}
|
||||||
|
|||||||
@@ -135,3 +135,32 @@ verify_challenge_path(){
|
|||||||
return 1
|
return 1
|
||||||
fi
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ try:
|
|||||||
if max_score == "":
|
if max_score == "":
|
||||||
max_score = 9999.0
|
max_score = 9999.0
|
||||||
|
|
||||||
def query_mysql(query, headers = True, update = False):
|
def query_mysql(query, params = None, headers = True, update = False):
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
cnx = MySQLdb.connect(user=os.environ.get('DBUSER'), password=os.environ.get('DBPASS'), database=os.environ.get('DBNAME'), charset="utf8mb4", collation="utf8mb4_general_ci")
|
cnx = MySQLdb.connect(user=os.environ.get('DBUSER'), password=os.environ.get('DBPASS'), database=os.environ.get('DBNAME'), charset="utf8mb4", collation="utf8mb4_general_ci")
|
||||||
@@ -57,7 +57,10 @@ try:
|
|||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
cur = cnx.cursor()
|
cur = cnx.cursor()
|
||||||
cur.execute(query)
|
if params:
|
||||||
|
cur.execute(query, params)
|
||||||
|
else:
|
||||||
|
cur.execute(query)
|
||||||
if not update:
|
if not update:
|
||||||
result = []
|
result = []
|
||||||
columns = tuple( [d[0] for d in cur.description] )
|
columns = tuple( [d[0] for d in cur.description] )
|
||||||
@@ -76,7 +79,7 @@ try:
|
|||||||
|
|
||||||
def notify_rcpt(rcpt, msg_count, quarantine_acl, category):
|
def notify_rcpt(rcpt, msg_count, quarantine_acl, category):
|
||||||
if category == "add_header": category = "add header"
|
if category == "add_header": category = "add header"
|
||||||
meta_query = query_mysql('SELECT `qhash`, id, subject, score, sender, created, action FROM quarantine WHERE notified = 0 AND rcpt = "%s" AND score < %f AND (action = "%s" OR "all" = "%s")' % (rcpt, max_score, category, category))
|
meta_query = query_mysql('SELECT `qhash`, id, subject, score, sender, created, action FROM quarantine WHERE notified = 0 AND rcpt = %s AND score < %s AND (action = %s OR "all" = %s)', (rcpt, max_score, category, category))
|
||||||
print("%s: %d of %d messages qualify for notification" % (rcpt, len(meta_query), msg_count))
|
print("%s: %d of %d messages qualify for notification" % (rcpt, len(meta_query), msg_count))
|
||||||
if len(meta_query) == 0:
|
if len(meta_query) == 0:
|
||||||
return
|
return
|
||||||
@@ -130,7 +133,7 @@ try:
|
|||||||
server.sendmail(msg['From'], [str(redirect)] + [str(bcc)], text)
|
server.sendmail(msg['From'], [str(redirect)] + [str(bcc)], text)
|
||||||
server.quit()
|
server.quit()
|
||||||
for res in meta_query:
|
for res in meta_query:
|
||||||
query_mysql('UPDATE quarantine SET notified = 1 WHERE id = "%d"' % (res['id']), update = True)
|
query_mysql('UPDATE quarantine SET notified = 1 WHERE id = %s', (res['id'],), update = True)
|
||||||
r.hset('Q_LAST_NOTIFIED', record['rcpt'], time_now)
|
r.hset('Q_LAST_NOTIFIED', record['rcpt'], time_now)
|
||||||
break
|
break
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
@@ -138,7 +141,7 @@ try:
|
|||||||
print('%s' % (ex))
|
print('%s' % (ex))
|
||||||
time.sleep(3)
|
time.sleep(3)
|
||||||
|
|
||||||
records = query_mysql('SELECT IFNULL(user_acl.quarantine, 0) AS quarantine_acl, count(id) AS counter, rcpt FROM quarantine LEFT OUTER JOIN user_acl ON user_acl.username = rcpt WHERE notified = 0 AND score < %f AND rcpt in (SELECT username FROM mailbox) GROUP BY rcpt' % (max_score))
|
records = query_mysql('SELECT IFNULL(user_acl.quarantine, 0) AS quarantine_acl, count(id) AS counter, rcpt FROM quarantine LEFT OUTER JOIN user_acl ON user_acl.username = rcpt WHERE notified = 0 AND score < %s AND rcpt in (SELECT username FROM mailbox) GROUP BY rcpt', (max_score,))
|
||||||
|
|
||||||
for record in records:
|
for record in records:
|
||||||
attrs = ''
|
attrs = ''
|
||||||
@@ -156,7 +159,7 @@ try:
|
|||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
print('Could not determine last notification for %s, assuming never' % (record['rcpt']))
|
print('Could not determine last notification for %s, assuming never' % (record['rcpt']))
|
||||||
last_notification = 0
|
last_notification = 0
|
||||||
attrs_json = query_mysql('SELECT attributes FROM mailbox WHERE username = "%s"' % (record['rcpt']))
|
attrs_json = query_mysql('SELECT attributes FROM mailbox WHERE username = %s', (record['rcpt'],))
|
||||||
attrs = attrs_json[0]['attributes']
|
attrs = attrs_json[0]['attributes']
|
||||||
if isinstance(attrs, str):
|
if isinstance(attrs, str):
|
||||||
# if attr is str then just load it
|
# if attr is str then just load it
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||||||
git \
|
git \
|
||||||
build-essential \
|
build-essential \
|
||||||
gobjc \
|
gobjc \
|
||||||
|
pkg-config \
|
||||||
gnustep-make \
|
gnustep-make \
|
||||||
gnustep-base-runtime \
|
gnustep-base-runtime \
|
||||||
libgnustep-base-dev \
|
libgnustep-base-dev \
|
||||||
@@ -40,6 +41,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||||||
libcurl4-openssl-dev \
|
libcurl4-openssl-dev \
|
||||||
libzip-dev \
|
libzip-dev \
|
||||||
libytnef0-dev \
|
libytnef0-dev \
|
||||||
|
libwbxml2-dev \
|
||||||
curl \
|
curl \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
# Runtime dependencies
|
# Runtime dependencies
|
||||||
@@ -68,6 +70,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||||||
libcurl4 \
|
libcurl4 \
|
||||||
libzip4 \
|
libzip4 \
|
||||||
libytnef0 \
|
libytnef0 \
|
||||||
|
libwbxml2-1 \
|
||||||
# Download gosu
|
# Download gosu
|
||||||
&& dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')" \
|
&& 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" \
|
&& 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 \
|
&& ./configure --disable-debug --disable-strip \
|
||||||
&& make -j$(nproc) \
|
&& make -j$(nproc) \
|
||||||
&& make install \
|
&& make install \
|
||||||
|
&& cd /tmp/sogo/ActiveSync \
|
||||||
|
&& . /usr/share/GNUstep/Makefiles/GNUstep.sh \
|
||||||
|
&& make -j$(nproc) install \
|
||||||
&& cd / \
|
&& cd / \
|
||||||
&& rm -rf /tmp/sogo \
|
&& rm -rf /tmp/sogo \
|
||||||
# Strip binaries
|
# Strip binaries
|
||||||
@@ -146,8 +152,8 @@ RUN echo "/usr/lib64" > /etc/ld.so.conf.d/sogo.conf \
|
|||||||
# Create sogo user and group
|
# Create sogo user and group
|
||||||
RUN groupadd -r -g 999 sogo \
|
RUN groupadd -r -g 999 sogo \
|
||||||
&& useradd -r -u 999 -g sogo -d /var/lib/sogo -s /bin/bash -c "SOGo Daemon" 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 \
|
&& 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
|
&& chown -R sogo:sogo /var/lib/sogo /var/run/sogo /var/log/sogo /var/spool/sogo
|
||||||
|
|
||||||
# Create symlinks for SOGo binaries
|
# Create symlinks for SOGo binaries
|
||||||
RUN ln -s /usr/local/sbin/sogod /usr/sbin/sogod \
|
RUN ln -s /usr/local/sbin/sogod /usr/sbin/sogod \
|
||||||
|
|||||||
@@ -37,5 +37,6 @@ RUN apk add --update \
|
|||||||
COPY watchdog.sh /watchdog.sh
|
COPY watchdog.sh /watchdog.sh
|
||||||
COPY check_mysql_slavestatus.sh /usr/lib/nagios/plugins/check_mysql_slavestatus.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 check_dns.sh /usr/lib/mailcow/check_dns.sh
|
||||||
|
COPY client.cnf /etc/my.cnf.d/client.cnf
|
||||||
|
|
||||||
CMD ["/watchdog.sh"]
|
CMD ["/watchdog.sh"]
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
[client]
|
||||||
|
ssl = false
|
||||||
|
ssl-verify-server-cert = false
|
||||||
@@ -38,7 +38,7 @@ if [[ ! -p /tmp/com_pipe ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Wait for containers
|
# 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..."
|
echo "Waiting for SQL..."
|
||||||
sleep 2
|
sleep 2
|
||||||
done
|
done
|
||||||
@@ -359,8 +359,8 @@ mysql_checks() {
|
|||||||
while [ ${err_count} -lt ${THRESHOLD} ]; do
|
while [ ${err_count} -lt ${THRESHOLD} ]; do
|
||||||
touch /tmp/mysql-mailcow; echo "$(tail -50 /tmp/mysql-mailcow)" > /tmp/mysql-mailcow
|
touch /tmp/mysql-mailcow; echo "$(tail -50 /tmp/mysql-mailcow)" > /tmp/mysql-mailcow
|
||||||
err_c_cur=${err_count}
|
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 -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 -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_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} -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} ))
|
[ ${err_c_cur} -ne ${err_count} ] && diff_c=$(( ${err_c_cur} - ${err_count} ))
|
||||||
progress "MySQL/MariaDB" ${THRESHOLD} $(( ${THRESHOLD} - ${err_count} )) ${diff_c}
|
progress "MySQL/MariaDB" ${THRESHOLD} $(( ${THRESHOLD} - ${err_count} )) ${diff_c}
|
||||||
@@ -384,7 +384,7 @@ mysql_repl_checks() {
|
|||||||
while [ ${err_count} -lt ${THRESHOLD} ]; do
|
while [ ${err_count} -lt ${THRESHOLD} ]; do
|
||||||
touch /tmp/mysql_repl_checks; echo "$(tail -50 /tmp/mysql_repl_checks)" > /tmp/mysql_repl_checks
|
touch /tmp/mysql_repl_checks; echo "$(tail -50 /tmp/mysql_repl_checks)" > /tmp/mysql_repl_checks
|
||||||
err_c_cur=${err_count}
|
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} -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} ))
|
[ ${err_c_cur} -ne ${err_count} ] && diff_c=$(( ${err_c_cur} - ${err_count} ))
|
||||||
progress "MySQL/MariaDB replication" ${THRESHOLD} $(( ${THRESHOLD} - ${err_count} )) ${diff_c}
|
progress "MySQL/MariaDB replication" ${THRESHOLD} $(( ${THRESHOLD} - ${err_count} )) ${diff_c}
|
||||||
|
|||||||
@@ -287,6 +287,8 @@ function user_login($user, $pass, $extra = null){
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$row['attributes'] = json_decode($row['attributes'], true);
|
||||||
|
|
||||||
// check for tfa authenticators
|
// check for tfa authenticators
|
||||||
$authenticators = get_tfa($user);
|
$authenticators = get_tfa($user);
|
||||||
if (isset($authenticators['additional']) && is_array($authenticators['additional']) && count($authenticators['additional']) > 0 && !$is_internal) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$row['attributes'] = json_decode($row['attributes'], true);
|
||||||
|
|
||||||
// check for tfa authenticators
|
// check for tfa authenticators
|
||||||
$authenticators = get_tfa($user);
|
$authenticators = get_tfa($user);
|
||||||
if (isset($authenticators['additional']) && is_array($authenticators['additional']) && count($authenticators['additional']) > 0 && !$is_internal) {
|
if (isset($authenticators['additional']) && is_array($authenticators['additional']) && count($authenticators['additional']) > 0 && !$is_internal) {
|
||||||
|
|||||||
@@ -108,6 +108,14 @@ function fwdhost($_action, $_data = null) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'delete':
|
case 'delete':
|
||||||
|
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
|
'msg' => 'access_denied'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
$hosts = (array)$_data['forwardinghost'];
|
$hosts = (array)$_data['forwardinghost'];
|
||||||
foreach ($hosts as $host) {
|
foreach ($hosts as $host) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1111,10 +1111,21 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
$relayhost = (isset($_data['relayhost'])) ? intval($_data['relayhost']) : 0;
|
$relayhost = (isset($_data['relayhost'])) ? intval($_data['relayhost']) : 0;
|
||||||
$quarantine_notification = (isset($_data['quarantine_notification'])) ? strval($_data['quarantine_notification']) : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_notification']);
|
$quarantine_notification = (isset($_data['quarantine_notification'])) ? strval($_data['quarantine_notification']) : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_notification']);
|
||||||
$quarantine_category = (isset($_data['quarantine_category'])) ? strval($_data['quarantine_category']) : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_category']);
|
$quarantine_category = (isset($_data['quarantine_category'])) ? strval($_data['quarantine_category']) : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_category']);
|
||||||
|
// Validate quarantine_category
|
||||||
|
if (!in_array($quarantine_category, array('add_header', 'reject', 'all'))) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
|
'msg' => 'quarantine_category_invalid'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
$quota_b = ($quota_m * 1048576);
|
$quota_b = ($quota_m * 1048576);
|
||||||
$attribute_hash = (!empty($_data['attribute_hash'])) ? $_data['attribute_hash'] : '';
|
$attribute_hash = (!empty($_data['attribute_hash'])) ? $_data['attribute_hash'] : '';
|
||||||
if (in_array($authsource, array('keycloak', 'generic-oidc', 'ldap'))){
|
if (in_array($authsource, array('keycloak', 'generic-oidc', 'ldap'))){
|
||||||
$force_pw_update = 0;
|
$force_pw_update = 0;
|
||||||
|
}
|
||||||
|
if ($authsource == 'generic-oidc'){
|
||||||
$force_tfa = 0;
|
$force_tfa = 0;
|
||||||
}
|
}
|
||||||
$mailbox_attrs = json_encode(
|
$mailbox_attrs = json_encode(
|
||||||
@@ -1731,6 +1742,15 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
$attr["tagged_mail_handler"] = (!empty($_data['tagged_mail_handler'])) ? $_data['tagged_mail_handler'] : strval($MAILBOX_DEFAULT_ATTRIBUTES['tagged_mail_handler']);
|
$attr["tagged_mail_handler"] = (!empty($_data['tagged_mail_handler'])) ? $_data['tagged_mail_handler'] : strval($MAILBOX_DEFAULT_ATTRIBUTES['tagged_mail_handler']);
|
||||||
$attr["quarantine_notification"] = (!empty($_data['quarantine_notification'])) ? $_data['quarantine_notification'] : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_notification']);
|
$attr["quarantine_notification"] = (!empty($_data['quarantine_notification'])) ? $_data['quarantine_notification'] : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_notification']);
|
||||||
$attr["quarantine_category"] = (!empty($_data['quarantine_category'])) ? $_data['quarantine_category'] : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_category']);
|
$attr["quarantine_category"] = (!empty($_data['quarantine_category'])) ? $_data['quarantine_category'] : strval($MAILBOX_DEFAULT_ATTRIBUTES['quarantine_category']);
|
||||||
|
// Validate quarantine_category
|
||||||
|
if (!in_array($attr["quarantine_category"], array('add_header', 'reject', 'all'))) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
|
||||||
|
'msg' => 'quarantine_category_invalid'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
$attr["rl_frame"] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : "s";
|
$attr["rl_frame"] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : "s";
|
||||||
$attr["rl_value"] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : "";
|
$attr["rl_value"] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : "";
|
||||||
$attr["force_pw_update"] = isset($_data['force_pw_update']) ? intval($_data['force_pw_update']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['force_pw_update']);
|
$attr["force_pw_update"] = isset($_data['force_pw_update']) ? intval($_data['force_pw_update']) : intval($MAILBOX_DEFAULT_ATTRIBUTES['force_pw_update']);
|
||||||
@@ -2060,6 +2080,14 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
foreach ($usernames as $username) {
|
foreach ($usernames as $username) {
|
||||||
|
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $username)) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
|
'msg' => 'access_denied'
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if ($_data['spam_score'] == "default") {
|
if ($_data['spam_score'] == "default") {
|
||||||
$stmt = $pdo->prepare("DELETE FROM `filterconf` WHERE `object` = :username
|
$stmt = $pdo->prepare("DELETE FROM `filterconf` WHERE `object` = :username
|
||||||
AND (`option` = 'lowspamlevel' OR `option` = 'highspamlevel')");
|
AND (`option` = 'lowspamlevel' OR `option` = 'highspamlevel')");
|
||||||
@@ -3126,6 +3154,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
}
|
}
|
||||||
if (in_array($authsource, array('keycloak', 'generic-oidc', 'ldap'))){
|
if (in_array($authsource, array('keycloak', 'generic-oidc', 'ldap'))){
|
||||||
$force_pw_update = 0;
|
$force_pw_update = 0;
|
||||||
|
}
|
||||||
|
if ($authsource == 'generic-oidc'){
|
||||||
$force_tfa = 0;
|
$force_tfa = 0;
|
||||||
}
|
}
|
||||||
$pw_recovery_email = (isset($_data['pw_recovery_email']) && $authsource == 'mailcow') ? $_data['pw_recovery_email'] : $is_now['attributes']['recovery_email'];
|
$pw_recovery_email = (isset($_data['pw_recovery_email']) && $authsource == 'mailcow') ? $_data['pw_recovery_email'] : $is_now['attributes']['recovery_email'];
|
||||||
@@ -3786,6 +3816,15 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
$attr["tagged_mail_handler"] = (!empty($_data['tagged_mail_handler'])) ? $_data['tagged_mail_handler'] : $is_now['tagged_mail_handler'];
|
$attr["tagged_mail_handler"] = (!empty($_data['tagged_mail_handler'])) ? $_data['tagged_mail_handler'] : $is_now['tagged_mail_handler'];
|
||||||
$attr["quarantine_notification"] = (!empty($_data['quarantine_notification'])) ? $_data['quarantine_notification'] : $is_now['quarantine_notification'];
|
$attr["quarantine_notification"] = (!empty($_data['quarantine_notification'])) ? $_data['quarantine_notification'] : $is_now['quarantine_notification'];
|
||||||
$attr["quarantine_category"] = (!empty($_data['quarantine_category'])) ? $_data['quarantine_category'] : $is_now['quarantine_category'];
|
$attr["quarantine_category"] = (!empty($_data['quarantine_category'])) ? $_data['quarantine_category'] : $is_now['quarantine_category'];
|
||||||
|
// Validate quarantine_category
|
||||||
|
if (!in_array($attr["quarantine_category"], array('add_header', 'reject', 'all'))) {
|
||||||
|
$_SESSION['return'][] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_extra),
|
||||||
|
'msg' => 'quarantine_category_invalid'
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
$attr["rl_frame"] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : $is_now['rl_frame'];
|
$attr["rl_frame"] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : $is_now['rl_frame'];
|
||||||
$attr["rl_value"] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : $is_now['rl_value'];
|
$attr["rl_value"] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : $is_now['rl_value'];
|
||||||
$attr["force_pw_update"] = isset($_data['force_pw_update']) ? intval($_data['force_pw_update']) : $is_now['force_pw_update'];
|
$attr["force_pw_update"] = isset($_data['force_pw_update']) ? intval($_data['force_pw_update']) : $is_now['force_pw_update'];
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ $globalVariables = [
|
|||||||
'app_links' => $app_links,
|
'app_links' => $app_links,
|
||||||
'app_links_processed' => $app_links_processed,
|
'app_links_processed' => $app_links_processed,
|
||||||
'is_root_uri' => (parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) == '/'),
|
'is_root_uri' => (parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) == '/'),
|
||||||
'uri' => $_SERVER['REQUEST_URI'],
|
'uri' => parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) ?: '/',
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($globalVariables as $globalVariableName => $globalVariableValue) {
|
foreach ($globalVariables as $globalVariableName => $globalVariableValue) {
|
||||||
|
|||||||
@@ -13,7 +13,9 @@ $twig = new Environment($loader, [
|
|||||||
|
|
||||||
// functions
|
// functions
|
||||||
$twig->addFunction(new TwigFunction('query_string', function (array $params = []) {
|
$twig->addFunction(new TwigFunction('query_string', function (array $params = []) {
|
||||||
return http_build_query(array_merge($_GET, $params));
|
$allowed = ['lang', 'mobileconfig'];
|
||||||
|
$filtered = array_intersect_key($_GET, array_flip($allowed));
|
||||||
|
return http_build_query(array_merge($filtered, $params));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
$twig->addFunction(new TwigFunction('is_uri', function (string $uri, string $where = null) {
|
$twig->addFunction(new TwigFunction('is_uri', function (string $uri, string $where = null) {
|
||||||
|
|||||||
@@ -345,7 +345,7 @@ $(document).ready(function() {
|
|||||||
$('.main-logo-dark').addClass('d-none');
|
$('.main-logo-dark').addClass('d-none');
|
||||||
if ($('#rspamd_logo').length) $('#rspamd_logo').attr('src', '/img/rspamd_logo_dark.png');
|
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');
|
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{
|
}else{
|
||||||
$('head').append('<link id="dark-mode-theme" rel="stylesheet" type="text/css" href="/css/themes/mailcow-darkmode.css">');
|
$('head').append('<link id="dark-mode-theme" rel="stylesheet" type="text/css" href="/css/themes/mailcow-darkmode.css">');
|
||||||
$('#dark-mode-toggle').prop('checked', true);
|
$('#dark-mode-toggle').prop('checked', true);
|
||||||
@@ -353,7 +353,7 @@ $(document).ready(function() {
|
|||||||
$('.main-logo-dark').removeClass('d-none');
|
$('.main-logo-dark').removeClass('d-none');
|
||||||
if ($('#rspamd_logo').length) $('#rspamd_logo').attr('src', '/img/rspamd_logo_light.png');
|
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');
|
if ($('#rspamd_logo_sm').length) $('#rspamd_logo_sm').attr('src', '/img/rspamd_logo_light.png');
|
||||||
localStorage.setItem('theme', 'dark');
|
localStorage.setItem('mailcow_theme', 'dark');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1128,6 +1128,11 @@ jQuery(function($){
|
|||||||
item.ua = escapeHtml(item.ua);
|
item.ua = escapeHtml(item.ua);
|
||||||
}
|
}
|
||||||
item.ua = '<span style="font-size:small">' + item.ua + '</span>';
|
item.ua = '<span style="font-size:small">' + item.ua + '</span>';
|
||||||
|
if (item.user == null) {
|
||||||
|
item.user = 'unknown';
|
||||||
|
} else {
|
||||||
|
item.user = escapeHtml(item.user);
|
||||||
|
}
|
||||||
if (item.service == "activesync") {
|
if (item.service == "activesync") {
|
||||||
item.service = '<span class="badge fs-6 bg-info">ActiveSync</span>';
|
item.service = '<span class="badge fs-6 bg-info">ActiveSync</span>';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
var theme = localStorage.getItem("theme");
|
var theme = localStorage.getItem("mailcow_theme");
|
||||||
localStorage.clear();
|
if (theme !== null) {
|
||||||
localStorage.setItem("theme", theme);
|
localStorage.setItem("mailcow_theme", theme);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -226,18 +226,18 @@ jQuery(function($){
|
|||||||
}
|
}
|
||||||
if (typeof data.fuzzy_hashes === 'object' && data.fuzzy_hashes !== null && data.fuzzy_hashes.length !== 0) {
|
if (typeof data.fuzzy_hashes === 'object' && data.fuzzy_hashes !== null && data.fuzzy_hashes.length !== 0) {
|
||||||
$.each(data.fuzzy_hashes, function (index, value) {
|
$.each(data.fuzzy_hashes, function (index, value) {
|
||||||
$('#qid_detail_fuzzy').append('<p style="font-family:monospace">' + value + '</p>');
|
$('#qid_detail_fuzzy').append('<p style="font-family:monospace">' + escapeHtml(value) + '</p>');
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
$('#qid_detail_fuzzy').append('-');
|
$('#qid_detail_fuzzy').append('-');
|
||||||
}
|
}
|
||||||
if (typeof data.score !== 'undefined' && typeof data.action !== 'undefined') {
|
if (typeof data.score !== 'undefined' && typeof data.action !== 'undefined') {
|
||||||
if (data.action == "add header") {
|
if (data.action == "add header") {
|
||||||
$('#qid_detail_score').append('<span class="label-rspamd-action badge fs-6 bg-warning"><b>' + data.score + '</b> - ' + lang.junk_folder + '</span>');
|
$('#qid_detail_score').append('<span class="label-rspamd-action badge fs-6 bg-warning"><b>' + escapeHtml(data.score) + '</b> - ' + lang.junk_folder + '</span>');
|
||||||
} else if (data.action == "reject") {
|
} else if (data.action == "reject") {
|
||||||
$('#qid_detail_score').append('<span class="label-rspamd-action badge fs-6 bg-danger"><b>' + data.score + '</b> - ' + lang.rejected + '</span>');
|
$('#qid_detail_score').append('<span class="label-rspamd-action badge fs-6 bg-danger"><b>' + escapeHtml(data.score) + '</b> - ' + lang.rejected + '</span>');
|
||||||
} else if (data.action == "rewrite subject") {
|
} else if (data.action == "rewrite subject") {
|
||||||
$('#qid_detail_score').append('<span class="label-rspamd-action badge fs-6 bg-warning"><b>' + data.score + '</b> - ' + lang.rewrite_subject + '</span>');
|
$('#qid_detail_score').append('<span class="label-rspamd-action badge fs-6 bg-warning"><b>' + escapeHtml(data.score) + '</b> - ' + lang.rewrite_subject + '</span>');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (typeof data.recipients !== 'undefined') {
|
if (typeof data.recipients !== 'undefined') {
|
||||||
@@ -254,8 +254,8 @@ jQuery(function($){
|
|||||||
qAtts.text('');
|
qAtts.text('');
|
||||||
$.each(data.attachments, function(index, value) {
|
$.each(data.attachments, function(index, value) {
|
||||||
qAtts.append(
|
qAtts.append(
|
||||||
'<p><a href="/inc/ajax/qitem_details.php?id=' + qitem + '&att=' + index + '" target="_blank">' + value[0] + '</a> (' + value[1] + ')' +
|
'<p><a href="/inc/ajax/qitem_details.php?id=' + escapeHtml(qitem) + '&att=' + index + '" target="_blank">' + escapeHtml(value[0]) + '</a> (' + escapeHtml(value[1]) + ')' +
|
||||||
' - <small><a href="' + value[3] + '" target="_blank">' + lang.check_hash + '</a></small></p>'
|
' - <small><a href="' + escapeHtml(value[3]) + '" target="_blank">' + lang.check_hash + '</a></small></p>'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,8 +98,8 @@ jQuery(function($){
|
|||||||
var local_datetime = datetime.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});
|
var local_datetime = datetime.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});
|
||||||
var service = '<div class="badge bg-secondary">' + item.service.toUpperCase() + '</div>';
|
var service = '<div class="badge bg-secondary">' + item.service.toUpperCase() + '</div>';
|
||||||
var app_password = item.app_password ? ' <a href="/edit/app-passwd/' + item.app_password + '"><i class="bi bi-key-fill"></i><span class="ms-1">' + escapeHtml(item.app_password_name || "App") + '</span></a>' : '';
|
var app_password = item.app_password ? ' <a href="/edit/app-passwd/' + item.app_password + '"><i class="bi bi-key-fill"></i><span class="ms-1">' + escapeHtml(item.app_password_name || "App") + '</span></a>' : '';
|
||||||
var real_rip = item.real_rip.startsWith("Web") ? item.real_rip : '<a href="https://bgp.tools/prefix/' + item.real_rip + '" target="_blank">' + item.real_rip + "</a>";
|
var real_rip = item.real_rip.startsWith("Web") ? escapeHtml(item.real_rip) : '<a href="https://bgp.tools/prefix/' + escapeHtml(item.real_rip) + '" target="_blank">' + escapeHtml(item.real_rip) + "</a>";
|
||||||
var ip_location = item.location ? ' <span class="flag-icon flag-icon-' + item.location.toLowerCase() + '"></span>' : '';
|
var ip_location = item.location ? ' <span class="flag-icon flag-icon-' + escapeHtml(item.location.toLowerCase()) + '"></span>' : '';
|
||||||
var ip_data = real_rip + ip_location + app_password;
|
var ip_data = real_rip + ip_location + app_password;
|
||||||
|
|
||||||
$(".last-sasl-login").append(`
|
$(".last-sasl-login").append(`
|
||||||
|
|||||||
@@ -512,6 +512,7 @@
|
|||||||
"pushover_credentials_missing": "Pushover Token und/oder Key fehlen",
|
"pushover_credentials_missing": "Pushover Token und/oder Key fehlen",
|
||||||
"pushover_key": "Pushover Key hat das falsche Format",
|
"pushover_key": "Pushover Key hat das falsche Format",
|
||||||
"pushover_token": "Pushover Token hat das falsche Format",
|
"pushover_token": "Pushover Token hat das falsche Format",
|
||||||
|
"quarantine_category_invalid": "Quarantäne-Kategorie muss eine der folgenden sein: add_header, reject, all",
|
||||||
"quota_not_0_not_numeric": "Speicherplatz muss numerisch und >= 0 sein",
|
"quota_not_0_not_numeric": "Speicherplatz muss numerisch und >= 0 sein",
|
||||||
"recipient_map_entry_exists": "Eine Empfängerumschreibung für Objekt \"%s\" existiert bereits",
|
"recipient_map_entry_exists": "Eine Empfängerumschreibung für Objekt \"%s\" existiert bereits",
|
||||||
"recovery_email_failed": "E-Mail zur Wiederherstellung konnte nicht gesendet werden. Bitte wenden Sie sich an Ihren Administrator.",
|
"recovery_email_failed": "E-Mail zur Wiederherstellung konnte nicht gesendet werden. Bitte wenden Sie sich an Ihren Administrator.",
|
||||||
|
|||||||
@@ -513,6 +513,7 @@
|
|||||||
"pushover_credentials_missing": "Pushover token and or key missing",
|
"pushover_credentials_missing": "Pushover token and or key missing",
|
||||||
"pushover_key": "Pushover key has a wrong format",
|
"pushover_key": "Pushover key has a wrong format",
|
||||||
"pushover_token": "Pushover token has a wrong format",
|
"pushover_token": "Pushover token has a wrong format",
|
||||||
|
"quarantine_category_invalid": "Quarantine category must be one of: add_header, reject, all",
|
||||||
"quota_not_0_not_numeric": "Quota must be numeric and >= 0",
|
"quota_not_0_not_numeric": "Quota must be numeric and >= 0",
|
||||||
"recipient_map_entry_exists": "A Recipient map entry \"%s\" exists",
|
"recipient_map_entry_exists": "A Recipient map entry \"%s\" exists",
|
||||||
"recovery_email_failed": "Could not send a recovery email. Please contact your administrator.",
|
"recovery_email_failed": "Could not send a recovery email. Please contact your administrator.",
|
||||||
|
|||||||
@@ -1144,7 +1144,8 @@
|
|||||||
"subscribeall": "Feliratkozás minden mappára",
|
"subscribeall": "Feliratkozás minden mappára",
|
||||||
"syncjob": "Szinkronizálási feladat hozzáadása",
|
"syncjob": "Szinkronizálási feladat hozzáadása",
|
||||||
"internal": "Belső",
|
"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": {
|
"danger": {
|
||||||
"access_denied": "Hozzáférés megtagatva vagy nem megfelelő űrlap adat",
|
"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_key": "A pushover kulcs rossz formátumú",
|
||||||
"pushover_token": "A Pushover token 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.",
|
"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 }}">
|
<link rel="stylesheet" href="{{ css_path }}">
|
||||||
<script>
|
<script>
|
||||||
// check if darkmode is preferred by OS or set by localStorage
|
// 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" ||
|
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches && localStorage.getItem("mailcow_theme") !== "light" ||
|
||||||
localStorage.getItem("theme") === "dark") {
|
localStorage.getItem("mailcow_theme") === "dark") {
|
||||||
var head = document.getElementsByTagName('head')[0];
|
var head = document.getElementsByTagName('head')[0];
|
||||||
var link = document.createElement('link');
|
var link = document.createElement('link');
|
||||||
link.id = 'dark-mode-theme';
|
link.id = 'dark-mode-theme';
|
||||||
@@ -193,7 +193,7 @@ $(window).scroll(function() {
|
|||||||
});
|
});
|
||||||
// Select language and reopen active URL without POST
|
// Select language and reopen active URL without POST
|
||||||
function setLang(sel) {
|
function setLang(sel) {
|
||||||
$.post( '{{ uri }}', {lang: sel} );
|
$.post( '{{ uri|escape("js") }}', {lang: sel} );
|
||||||
window.location.href = window.location.pathname + window.location.search;
|
window.location.href = window.location.pathname + window.location.search;
|
||||||
}
|
}
|
||||||
// FIDO2 functions
|
// FIDO2 functions
|
||||||
|
|||||||
+4
-4
@@ -200,7 +200,7 @@ services:
|
|||||||
- phpfpm
|
- phpfpm
|
||||||
|
|
||||||
sogo-mailcow:
|
sogo-mailcow:
|
||||||
image: ghcr.io/mailcow/sogo:5.12.5-1
|
image: ghcr.io/mailcow/sogo:5.12.5-3
|
||||||
environment:
|
environment:
|
||||||
- DBNAME=${DBNAME}
|
- DBNAME=${DBNAME}
|
||||||
- DBUSER=${DBUSER}
|
- DBUSER=${DBUSER}
|
||||||
@@ -252,7 +252,7 @@ services:
|
|||||||
- sogo
|
- sogo
|
||||||
|
|
||||||
dovecot-mailcow:
|
dovecot-mailcow:
|
||||||
image: ghcr.io/mailcow/dovecot:2.3.21.1-1
|
image: ghcr.io/mailcow/dovecot:2.3.21.1-2
|
||||||
depends_on:
|
depends_on:
|
||||||
- mysql-mailcow
|
- mysql-mailcow
|
||||||
- netfilter-mailcow
|
- netfilter-mailcow
|
||||||
@@ -465,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.96
|
image: ghcr.io/mailcow/acme:1.97
|
||||||
dns:
|
dns:
|
||||||
- ${IPV4_NETWORK:-172.22.1}.254
|
- ${IPV4_NETWORK:-172.22.1}.254
|
||||||
environment:
|
environment:
|
||||||
@@ -526,7 +526,7 @@ services:
|
|||||||
- /lib/modules:/lib/modules:ro
|
- /lib/modules:/lib/modules:ro
|
||||||
|
|
||||||
watchdog-mailcow:
|
watchdog-mailcow:
|
||||||
image: ghcr.io/mailcow/watchdog:2.10
|
image: ghcr.io/mailcow/watchdog:2.11
|
||||||
dns:
|
dns:
|
||||||
- ${IPV4_NETWORK:-172.22.1}.254
|
- ${IPV4_NETWORK:-172.22.1}.254
|
||||||
tmpfs:
|
tmpfs:
|
||||||
|
|||||||
Reference in New Issue
Block a user