From 6dc0bdbfa377eef1198063bccd41bd86a0858800 Mon Sep 17 00:00:00 2001 From: Tomasz Orzechowski Date: Tue, 9 Jan 2024 22:03:24 +0100 Subject: [PATCH 001/755] Proper number of threads regex. --- helper-scripts/backup_and_restore.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/helper-scripts/backup_and_restore.sh b/helper-scripts/backup_and_restore.sh index ee9f0202d..9a0561059 100755 --- a/helper-scripts/backup_and_restore.sh +++ b/helper-scripts/backup_and_restore.sh @@ -54,10 +54,10 @@ COMPOSE_FILE=${SCRIPT_DIR}/../docker-compose.yml ENV_FILE=${SCRIPT_DIR}/../.env THREADS=$(echo ${THREADS:-1}) -if ! [[ "${THREADS}" =~ ^[1-9]+$ ]] ; then +if ! [[ "${THREADS}" =~ ^[1-9][0-9]?$ ]] ; then echo "Thread input is not a number!" exit 1 -elif [[ "${THREADS}" =~ ^[1-9]+$ ]] ; then +elif [[ "${THREADS}" =~ ^[1-9][0-9]?$ ]] ; then echo "Using ${THREADS} Thread(s) for this run." echo "Notice: You can set the Thread count with the THREADS Variable before you run this script." fi From ed493f9c3a63d94ef10b149829fe3a752c3532e3 Mon Sep 17 00:00:00 2001 From: KagurazakaNyaa Date: Thu, 18 Jan 2024 23:28:03 +0800 Subject: [PATCH 002/755] Allow user skip unbound healthcheck --- data/Dockerfiles/unbound/healthcheck.sh | 10 ++++++++++ generate_config.sh | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/data/Dockerfiles/unbound/healthcheck.sh b/data/Dockerfiles/unbound/healthcheck.sh index ea94f63b3..760aa02bb 100644 --- a/data/Dockerfiles/unbound/healthcheck.sh +++ b/data/Dockerfiles/unbound/healthcheck.sh @@ -1,5 +1,10 @@ #!/bin/bash +# Skipping DNS check +if [[ "${SKIP_DNS_CHECK}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then + SKIP_DNS_CHECK=y +fi + # Declare log function for logfile inside container function log_to_file() { echo "$(date +"%Y-%m-%d %H:%M:%S"): $1" > /var/log/healthcheck.log @@ -66,6 +71,11 @@ function check_netcat() { } +if [[ ${SKIP_DNS_CHECK} == "y" ]]; then + log_to_file "Healthcheck: ALL CHECKS WERE SKIPPED! Unbound is healthy!" + exit 0 +fi + # run checks, if check is not returning 0 (return value if check is ok), healthcheck will exit with 1 (marked in docker as unhealthy) check_ping diff --git a/generate_config.sh b/generate_config.sh index 2986f1689..0c8a9bcfe 100755 --- a/generate_config.sh +++ b/generate_config.sh @@ -363,6 +363,10 @@ SKIP_IP_CHECK=n SKIP_HTTP_VERIFICATION=n +# Skip DNS check in Unbound container - y/n + +SKIP_DNS_CHECK=n + # Skip ClamAV (clamd-mailcow) anti-virus (Rspamd will auto-detect a missing ClamAV container) - y/n SKIP_CLAMD=${SKIP_CLAMD} From b89d71e6e4d42d1082f92914ff453d1272c67088 Mon Sep 17 00:00:00 2001 From: KagurazakaNyaa Date: Thu, 18 Jan 2024 23:48:59 +0800 Subject: [PATCH 003/755] change variable name --- data/Dockerfiles/unbound/healthcheck.sh | 8 ++++---- generate_config.sh | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/data/Dockerfiles/unbound/healthcheck.sh b/data/Dockerfiles/unbound/healthcheck.sh index 760aa02bb..a96eaab41 100644 --- a/data/Dockerfiles/unbound/healthcheck.sh +++ b/data/Dockerfiles/unbound/healthcheck.sh @@ -1,8 +1,8 @@ #!/bin/bash -# Skipping DNS check -if [[ "${SKIP_DNS_CHECK}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then - SKIP_DNS_CHECK=y +# Skip Unbound (DNS Resolver) Healthchecks (NOT Recommended!) +if [[ "${SKIP_UNBOUND_HEALTHCHECK}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then + SKIP_UNBOUND_HEALTHCHECK=y fi # Declare log function for logfile inside container @@ -71,7 +71,7 @@ function check_netcat() { } -if [[ ${SKIP_DNS_CHECK} == "y" ]]; then +if [[ ${SKIP_UNBOUND_HEALTHCHECK} == "y" ]]; then log_to_file "Healthcheck: ALL CHECKS WERE SKIPPED! Unbound is healthy!" exit 0 fi diff --git a/generate_config.sh b/generate_config.sh index 0c8a9bcfe..e936348ec 100755 --- a/generate_config.sh +++ b/generate_config.sh @@ -365,7 +365,7 @@ SKIP_HTTP_VERIFICATION=n # Skip DNS check in Unbound container - y/n -SKIP_DNS_CHECK=n +SKIP_UNBOUND_HEALTHCHECK=n # Skip ClamAV (clamd-mailcow) anti-virus (Rspamd will auto-detect a missing ClamAV container) - y/n From aa1d92dfbbcb555caf5f1a39032b7361254240aa Mon Sep 17 00:00:00 2001 From: KagurazakaNyaa Date: Thu, 18 Jan 2024 23:50:26 +0800 Subject: [PATCH 004/755] add SKIP_UNBOUND_HEALTHCHECK to docker-compose.yml --- docker-compose.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/docker-compose.yml b/docker-compose.yml index 5a0730c7e..4f5a4d31c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,6 +5,7 @@ services: image: mailcow/unbound:1.19.1 environment: - TZ=${TZ} + - SKIP_UNBOUND_HEALTHCHECK=${SKIP_UNBOUND_HEALTHCHECK:-n} volumes: - ./data/hooks/unbound:/hooks:Z - ./data/conf/unbound/unbound.conf:/etc/unbound/unbound.conf:ro,Z From d2edf359ac3ebdc51d56aab488ffc5dd927db13b Mon Sep 17 00:00:00 2001 From: KagurazakaNyaa Date: Thu, 18 Jan 2024 23:53:08 +0800 Subject: [PATCH 005/755] update config comment --- generate_config.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generate_config.sh b/generate_config.sh index e936348ec..e62d16892 100755 --- a/generate_config.sh +++ b/generate_config.sh @@ -363,7 +363,7 @@ SKIP_IP_CHECK=n SKIP_HTTP_VERIFICATION=n -# Skip DNS check in Unbound container - y/n +# Skip Unbound (DNS Resolver) Healthchecks (NOT Recommended!) - y/n SKIP_UNBOUND_HEALTHCHECK=n From 9d4055fc4d3a67221160f0d8342f41f77e28dd8e Mon Sep 17 00:00:00 2001 From: KagurazakaNyaa Date: Fri, 19 Jan 2024 00:07:51 +0800 Subject: [PATCH 006/755] add parameter SKIP_UNBOUND_HEALTHCHECK to old installations --- update.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/update.sh b/update.sh index 623242d5b..ad77beac7 100755 --- a/update.sh +++ b/update.sh @@ -480,6 +480,7 @@ CONFIG_ARRAY=( "WATCHDOG_VERBOSE" "WEBAUTHN_ONLY_TRUSTED_VENDORS" "SPAMHAUS_DQS_KEY" + "SKIP_UNBOUND_HEALTHCHECK" ) detect_bad_asn @@ -747,6 +748,12 @@ for option in ${CONFIG_ARRAY[@]}; do echo '# Enable watchdog verbose logging' >> mailcow.conf echo 'WATCHDOG_VERBOSE=n' >> mailcow.conf fi + elif [[ ${option} == "SKIP_UNBOUND_HEALTHCHECK" ]]; then + if ! grep -q ${option} mailcow.conf; then + echo "Adding new option \"${option}\" to mailcow.conf" + echo '# Skip Unbound (DNS Resolver) Healthchecks (NOT Recommended!) - y/n' >> mailcow.conf + echo 'SKIP_UNBOUND_HEALTHCHECK=n' >> mailcow.conf + fi elif ! grep -q ${option} mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo "${option}=n" >> mailcow.conf From 25bdc4c9ed93392e71ee0b32bcdb51572bd75172 Mon Sep 17 00:00:00 2001 From: Luca Barbato Date: Mon, 22 Jan 2024 09:50:24 +0100 Subject: [PATCH 007/755] Test for openrc configuration file instead of alpine This way other distro using openrc can be supported. --- update.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/update.sh b/update.sh index 623242d5b..4e16f1193 100755 --- a/update.sh +++ b/update.sh @@ -116,11 +116,11 @@ migrate_docker_nat() { echo "Working on IPv6 NAT, please wait..." echo ${NAT_CONFIG} > /etc/docker/daemon.json ip6tables -F -t nat - [[ -e /etc/alpine-release ]] && rc-service docker restart || systemctl restart docker.service + [[ -e /etc/rc.conf ]] && rc-service docker restart || systemctl restart docker.service if [[ $? -ne 0 ]]; then echo -e "\e[31mError:\e[0m Failed to activate IPv6 NAT! Reverting and exiting." rm /etc/docker/daemon.json - if [[ -e /etc/alpine-release ]]; then + if [[ -e /etc/rc.conf ]]; then rc-service docker restart else systemctl reset-failed docker.service From 53be119e39b0db25c45bb0f058f5259e6b9d1347 Mon Sep 17 00:00:00 2001 From: DerLinkman Date: Mon, 22 Jan 2024 10:22:24 +0100 Subject: [PATCH 008/755] compose: bump unbound version --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 4f5a4d31c..4e7420567 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,7 +2,7 @@ version: '2.1' services: unbound-mailcow: - image: mailcow/unbound:1.19.1 + image: mailcow/unbound:1.20 environment: - TZ=${TZ} - SKIP_UNBOUND_HEALTHCHECK=${SKIP_UNBOUND_HEALTHCHECK:-n} From 6e7a0eb66222e52d8144802c132c2131d1badd45 Mon Sep 17 00:00:00 2001 From: Nya Candy Date: Thu, 18 Jan 2024 15:00:54 +0800 Subject: [PATCH 009/755] fix: watchdog webhook body variables injector --- data/Dockerfiles/watchdog/watchdog.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/Dockerfiles/watchdog/watchdog.sh b/data/Dockerfiles/watchdog/watchdog.sh index d43cb38ac..cb342c138 100755 --- a/data/Dockerfiles/watchdog/watchdog.sh +++ b/data/Dockerfiles/watchdog/watchdog.sh @@ -170,7 +170,7 @@ function notify_error() { fi # Replace subject and body placeholders - WEBHOOK_BODY=$(echo ${WATCHDOG_NOTIFY_WEBHOOK_BODY} | sed "s|\$SUBJECT\|\${SUBJECT}|$SUBJECT|g" | sed "s|\$BODY\|\${BODY}|$BODY|") + WEBHOOK_BODY=$(echo ${WATCHDOG_NOTIFY_WEBHOOK_BODY} | sed "s/\$SUBJECT\|\${SUBJECT}/$SUBJECT/g" | sed "s/\$BODY\|\${BODY}/$BODY/g") # POST to webhook curl -X POST -H "Content-Type: application/json" ${CURL_VERBOSE} -d "${WEBHOOK_BODY}" ${WATCHDOG_NOTIFY_WEBHOOK} From 7da5e3697e4373fb8220bbc5bcfa79aa98793743 Mon Sep 17 00:00:00 2001 From: DerLinkman Date: Mon, 22 Jan 2024 10:31:27 +0100 Subject: [PATCH 010/755] compose: bump watchdog version --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 5a0730c7e..7dbfe0e5f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -457,7 +457,7 @@ services: - /lib/modules:/lib/modules:ro watchdog-mailcow: - image: mailcow/watchdog:2.01 + image: mailcow/watchdog:2.02 dns: - ${IPV4_NETWORK:-172.22.1}.254 tmpfs: From a0613e4b1085d3a4de8f5872b0a6deeed8efc066 Mon Sep 17 00:00:00 2001 From: DerLinkman Date: Mon, 22 Jan 2024 11:26:26 +0100 Subject: [PATCH 011/755] fix: rollback of Alpine 3.19 were possible --- data/Dockerfiles/acme/Dockerfile | 2 +- data/Dockerfiles/phpfpm/Dockerfile | 2 +- data/Dockerfiles/unbound/Dockerfile | 2 +- data/Dockerfiles/watchdog/Dockerfile | 2 +- docker-compose.yml | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/data/Dockerfiles/acme/Dockerfile b/data/Dockerfiles/acme/Dockerfile index 08271bddb..254b5b331 100644 --- a/data/Dockerfiles/acme/Dockerfile +++ b/data/Dockerfiles/acme/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.19 +FROM alpine:3.18 LABEL maintainer "The Infrastructure Company GmbH GmbH " diff --git a/data/Dockerfiles/phpfpm/Dockerfile b/data/Dockerfiles/phpfpm/Dockerfile index c1a35f4d3..22036b9b3 100644 --- a/data/Dockerfiles/phpfpm/Dockerfile +++ b/data/Dockerfiles/phpfpm/Dockerfile @@ -1,4 +1,4 @@ -FROM php:8.2-fpm-alpine3.19 +FROM php:8.2-fpm-alpine3.18 LABEL maintainer "The Infrastructure Company GmbH " # renovate: datasource=github-tags depName=krakjoe/apcu versioning=semver-coerced extractVersion=^v(?.*)$ diff --git a/data/Dockerfiles/unbound/Dockerfile b/data/Dockerfiles/unbound/Dockerfile index 4411a1d26..f56cbc6e5 100644 --- a/data/Dockerfiles/unbound/Dockerfile +++ b/data/Dockerfiles/unbound/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.19 +FROM alpine:3.18 LABEL maintainer "The Infrastructure Company GmbH GmbH " diff --git a/data/Dockerfiles/watchdog/Dockerfile b/data/Dockerfiles/watchdog/Dockerfile index b94789aac..73acde68f 100644 --- a/data/Dockerfiles/watchdog/Dockerfile +++ b/data/Dockerfiles/watchdog/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.19 +FROM alpine:3.18 LABEL maintainer "The Infrastructure Company GmbH " # Installation diff --git a/docker-compose.yml b/docker-compose.yml index 739108bcb..c1883f907 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -108,7 +108,7 @@ services: - rspamd php-fpm-mailcow: - image: mailcow/phpfpm:1.86 + image: mailcow/phpfpm:1.87 command: "php-fpm -d date.timezone=${TZ} -d expose_php=0" depends_on: - redis-mailcow @@ -399,7 +399,7 @@ services: condition: service_started unbound-mailcow: condition: service_healthy - image: mailcow/acme:1.86 + image: mailcow/acme:1.87 dns: - ${IPV4_NETWORK:-172.22.1}.254 environment: From deb6f0babc5017a2d140d971a8dbab289e5f3072 Mon Sep 17 00:00:00 2001 From: DerLinkman Date: Tue, 23 Jan 2024 08:46:06 +0100 Subject: [PATCH 012/755] issue: added architecture as dropdown --- .github/ISSUE_TEMPLATE/Bug_report.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/Bug_report.yml b/.github/ISSUE_TEMPLATE/Bug_report.yml index 3cfbbe0dc..afa1a27f8 100644 --- a/.github/ISSUE_TEMPLATE/Bug_report.yml +++ b/.github/ISSUE_TEMPLATE/Bug_report.yml @@ -62,6 +62,16 @@ body: - nightly validations: required: true + - type: dropdown + attributes: + label: "Which architecture are you using?" + description: "#### `uname -m`" + multiple: false + options: + - x86 + - ARM64 (aarch64) + validations: + required: true - type: input attributes: label: "Operating System:" From f74573f5d04cf578e4101a5e32a0814d9fd849ae Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 31 Jan 2024 16:14:42 +0100 Subject: [PATCH 013/755] chore(deps): update peter-evans/create-pull-request action to v6 (#5683) Signed-off-by: milkmaker Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/update_postscreen_access_list.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update_postscreen_access_list.yml b/.github/workflows/update_postscreen_access_list.yml index 42502f303..ddfa7ac86 100644 --- a/.github/workflows/update_postscreen_access_list.yml +++ b/.github/workflows/update_postscreen_access_list.yml @@ -22,7 +22,7 @@ jobs: bash helper-scripts/update_postscreen_whitelist.sh - name: Create Pull Request - uses: peter-evans/create-pull-request@v5 + uses: peter-evans/create-pull-request@v6 with: token: ${{ secrets.mailcow_action_Update_postscreen_access_cidr_pat }} commit-message: update postscreen_access.cidr From cc77caad671f0ae40068351861d81712da8f2b9e Mon Sep 17 00:00:00 2001 From: milkmaker Date: Thu, 1 Feb 2024 00:13:51 +0000 Subject: [PATCH 014/755] update postscreen_access.cidr --- data/conf/postfix/postscreen_access.cidr | 81 +++++++++++++++++------- 1 file changed, 59 insertions(+), 22 deletions(-) diff --git a/data/conf/postfix/postscreen_access.cidr b/data/conf/postfix/postscreen_access.cidr index 0497e64a0..e8273ecc5 100644 --- a/data/conf/postfix/postscreen_access.cidr +++ b/data/conf/postfix/postscreen_access.cidr @@ -1,9 +1,10 @@ -# Whitelist generated by Postwhite v3.4 on Mon Jan 1 00:15:22 UTC 2024 +# Whitelist generated by Postwhite v3.4 on Thu Feb 1 00:13:50 UTC 2024 # https://github.com/stevejenkins/postwhite/ -# 2052 total rules +# 2089 total rules 2a00:1450:4000::/36 permit 2a01:111:f400::/48 permit 2a01:111:f403:8000::/50 permit +2a01:111:f403:8000::/51 permit 2a01:111:f403::/49 permit 2a01:111:f403:c000::/51 permit 2a01:111:f403:f000::/52 permit @@ -116,7 +117,6 @@ 40.92.0.0/16 permit 40.107.0.0/16 permit 40.112.65.63 permit -40.117.80.0/24 permit 43.228.184.0/22 permit 44.206.138.57 permit 44.209.42.157 permit @@ -206,7 +206,6 @@ 52.95.49.88/29 permit 52.96.91.34 permit 52.96.111.82 permit -52.96.172.98 permit 52.96.214.50 permit 52.96.222.194 permit 52.96.222.226 permit @@ -405,7 +404,6 @@ 66.196.81.228/30 permit 66.196.81.232/31 permit 66.196.81.234 permit -66.211.168.230/31 permit 66.211.170.88/29 permit 66.211.184.0/23 permit 66.218.74.64/30 permit @@ -594,9 +592,10 @@ 74.112.67.243 permit 74.125.0.0/16 permit 74.202.227.40 permit -74.208.4.192/26 permit -74.208.5.64/26 permit -74.208.122.0/26 permit +74.208.4.200 permit +74.208.4.201 permit +74.208.4.220 permit +74.208.4.221 permit 74.209.250.0/24 permit 75.2.70.75 permit 76.223.128.0/19 permit @@ -624,12 +623,20 @@ 77.238.189.148/30 permit 81.7.169.128/25 permit 81.223.46.0/27 permit -82.165.159.0/24 permit -82.165.159.0/26 permit -82.165.229.31 permit -82.165.229.130 permit -82.165.230.21 permit -82.165.230.22 permit +82.165.159.2 permit +82.165.159.3 permit +82.165.159.4 permit +82.165.159.12 permit +82.165.159.13 permit +82.165.159.14 permit +82.165.159.34 permit +82.165.159.35 permit +82.165.159.40 permit +82.165.159.41 permit +82.165.159.42 permit +82.165.159.45 permit +82.165.159.130 permit +82.165.159.131 permit 84.116.6.0/23 permit 84.116.36.0/24 permit 84.116.50.0/23 permit @@ -1430,6 +1437,7 @@ 135.84.216.0/22 permit 136.143.160.0/24 permit 136.143.161.0/24 permit +136.143.178.49 permit 136.143.182.0/23 permit 136.143.184.0/24 permit 136.143.188.0/24 permit @@ -1952,12 +1960,41 @@ 212.82.111.228/31 permit 212.82.111.230 permit 212.123.28.40 permit -212.227.15.0/24 permit -212.227.15.0/25 permit -212.227.17.0/27 permit -212.227.126.128/25 permit +212.227.15.3 permit +212.227.15.4 permit +212.227.15.5 permit +212.227.15.6 permit +212.227.15.14 permit +212.227.15.15 permit +212.227.15.18 permit +212.227.15.19 permit +212.227.15.25 permit +212.227.15.26 permit +212.227.15.29 permit +212.227.15.44 permit +212.227.15.45 permit +212.227.15.46 permit +212.227.15.47 permit +212.227.15.50 permit +212.227.15.52 permit +212.227.15.53 permit +212.227.15.54 permit +212.227.15.55 permit +212.227.17.11 permit +212.227.17.12 permit +212.227.17.18 permit +212.227.17.19 permit +212.227.17.20 permit +212.227.17.21 permit +212.227.17.22 permit +212.227.17.26 permit +212.227.17.28 permit +212.227.17.29 permit +212.227.126.224 permit +212.227.126.225 permit +212.227.126.226 permit +212.227.126.227 permit 213.46.255.0/24 permit -213.165.64.0/23 permit 213.199.128.139 permit 213.199.128.145 permit 213.199.138.181 permit @@ -2021,10 +2058,10 @@ 216.203.30.55 permit 216.203.33.178/31 permit 216.205.24.0/24 permit +216.221.160.0/19 permit 216.239.32.0/19 permit -217.72.192.64/26 permit -217.72.192.248/29 permit -217.72.207.0/27 permit +217.72.192.77 permit +217.72.192.78 permit 217.77.141.52 permit 217.77.141.59 permit 217.175.194.0/24 permit From 93e4d586060aa1045395aae1bcf7a7126bbdc9f1 Mon Sep 17 00:00:00 2001 From: DerLinkman Date: Thu, 1 Feb 2024 08:41:11 +0100 Subject: [PATCH 015/755] sogo: fix ACL allow authenticated users + rebuild on Bookworm --- data/Dockerfiles/sogo/Dockerfile | 7 ++++--- docker-compose.yml | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/data/Dockerfiles/sogo/Dockerfile b/data/Dockerfiles/sogo/Dockerfile index 54d676b9a..a4601c405 100644 --- a/data/Dockerfiles/sogo/Dockerfile +++ b/data/Dockerfiles/sogo/Dockerfile @@ -1,7 +1,8 @@ -FROM debian:bullseye-slim +FROM debian:bookworm-slim LABEL maintainer "The Infrastructure Company GmbH GmbH " ARG DEBIAN_FRONTEND=noninteractive +ARG DEBIAN_VERSION=bookworm ARG SOGO_DEBIAN_REPOSITORY=http://www.axis.cz/linux/debian # renovate: datasource=github-releases depName=tianon/gosu versioning=semver-coerced extractVersion=^(?.*)$ ARG GOSU_VERSION=1.17 @@ -21,7 +22,7 @@ RUN echo "Building from repository $SOGO_DEBIAN_REPOSITORY" \ syslog-ng-core \ syslog-ng-mod-redis \ dirmngr \ - netcat \ + netcat-traditional \ psmisc \ wget \ patch \ @@ -32,7 +33,7 @@ RUN echo "Building from repository $SOGO_DEBIAN_REPOSITORY" \ && mkdir /usr/share/doc/sogo \ && touch /usr/share/doc/sogo/empty.sh \ && apt-key adv --keyserver keys.openpgp.org --recv-key 74FFC6D72B925A34B5D356BDF8A27B36A6E2EAE9 \ - && echo "deb [trusted=yes] ${SOGO_DEBIAN_REPOSITORY} bullseye sogo-v5" > /etc/apt/sources.list.d/sogo.list \ + && echo "deb [trusted=yes] ${SOGO_DEBIAN_REPOSITORY} ${DEBIAN_VERSION} sogo-v5" > /etc/apt/sources.list.d/sogo.list \ && apt-get update && apt-get install -y --no-install-recommends \ sogo \ sogo-activesync \ diff --git a/docker-compose.yml b/docker-compose.yml index c1883f907..8dc193ebe 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -172,7 +172,7 @@ services: - phpfpm sogo-mailcow: - image: mailcow/sogo:1.121 + image: mailcow/sogo:1.122 environment: - DBNAME=${DBNAME} - DBUSER=${DBUSER} From b236fd3ac683ea1434521807c5d118040b54882c Mon Sep 17 00:00:00 2001 From: FreddleSpl0it Date: Tue, 30 Jan 2024 10:15:33 +0100 Subject: [PATCH 016/755] [Netfilter] add mailcow isolation rule to MAILCOW chain [Netfilter] add mailcow rule to docker-user chain [Netfilter] add mailcow isolation rule to MAILCOW chain [Netfilter] add mailcow isolation rule to MAILCOW chain [Netfilter] set mailcow isolation rule before redis [Netfilter] clear bans in redis after connecting [Netfilter] simplify mailcow isolation rule for compatibility with iptables-nft [Netfilter] stop container after mariadb, redis, dovecot, solr [Netfilter] simplify mailcow isolation rule for compatibility with iptables-nft [Netfilter] add exception for mailcow isolation rule for HA setups [Netfilter] add exception for mailcow isolation rule for HA setups [Netfilter] add DISABLE_NETFILTER_ISOLATION_RULE [Netfilter] fix wrong var name [Netfilter] add DISABLE_NETFILTER_ISOLATION_RULE to update and generate_config sh --- .gitignore | 1 + data/Dockerfiles/dovecot/docker-entrypoint.sh | 9 + data/Dockerfiles/netfilter/main.py | 90 ++++++---- .../Dockerfiles/netfilter/modules/IPTables.py | 39 +++++ data/Dockerfiles/netfilter/modules/Logger.py | 3 +- .../Dockerfiles/netfilter/modules/NFTables.py | 165 +++++++++++++++++- data/conf/dovecot/dovecot.conf | 3 + docker-compose.yml | 16 +- generate_config.sh | 3 + update.sh | 8 + 10 files changed, 290 insertions(+), 47 deletions(-) diff --git a/.gitignore b/.gitignore index 3595ecb1e..e25639a70 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ data/conf/dovecot/acl_anyone data/conf/dovecot/dovecot-master.passwd data/conf/dovecot/dovecot-master.userdb data/conf/dovecot/extra.conf +data/conf/dovecot/mail_replica.conf data/conf/dovecot/global_sieve_* data/conf/dovecot/last_login data/conf/dovecot/lua diff --git a/data/Dockerfiles/dovecot/docker-entrypoint.sh b/data/Dockerfiles/dovecot/docker-entrypoint.sh index f1e2e9668..a9545f338 100755 --- a/data/Dockerfiles/dovecot/docker-entrypoint.sh +++ b/data/Dockerfiles/dovecot/docker-entrypoint.sh @@ -335,6 +335,15 @@ sys.exit() EOF fi +# Set mail_replica for HA setups +if [[ -n ${MAILCOW_REPLICA_IP} && -n ${DOVEADM_REPLICA_PORT} ]]; then + cat < /etc/dovecot/mail_replica.conf +# Autogenerated by mailcow +mail_replica = tcp:${MAILCOW_REPLICA_IP}:${DOVEADM_REPLICA_PORT} +EOF +fi + + # 401 is user dovecot if [[ ! -s /mail_crypt/ecprivkey.pem || ! -s /mail_crypt/ecpubkey.pem ]]; then openssl ecparam -name prime256v1 -genkey | openssl pkey -out /mail_crypt/ecprivkey.pem diff --git a/data/Dockerfiles/netfilter/main.py b/data/Dockerfiles/netfilter/main.py index d5c1db502..8480c9efa 100644 --- a/data/Dockerfiles/netfilter/main.py +++ b/data/Dockerfiles/netfilter/main.py @@ -21,28 +21,6 @@ from modules.IPTables import IPTables from modules.NFTables import NFTables -# connect to redis -while True: - try: - redis_slaveof_ip = os.getenv('REDIS_SLAVEOF_IP', '') - redis_slaveof_port = os.getenv('REDIS_SLAVEOF_PORT', '') - if "".__eq__(redis_slaveof_ip): - r = redis.StrictRedis(host=os.getenv('IPV4_NETWORK', '172.22.1') + '.249', decode_responses=True, port=6379, db=0) - else: - r = redis.StrictRedis(host=redis_slaveof_ip, decode_responses=True, port=redis_slaveof_port, db=0) - r.ping() - except Exception as ex: - print('%s - trying again in 3 seconds' % (ex)) - time.sleep(3) - else: - break -pubsub = r.pubsub() - -# rename fail2ban to netfilter -if r.exists('F2B_LOG'): - r.rename('F2B_LOG', 'NETFILTER_LOG') - - # globals WHITELIST = [] BLACKLIST= [] @@ -50,18 +28,8 @@ bans = {} quit_now = False exit_code = 0 lock = Lock() - - -# init Logger -logger = Logger(r) -# init backend -backend = sys.argv[1] -if backend == "nftables": - logger.logInfo('Using NFTables backend') - tables = NFTables("MAILCOW", logger) -else: - logger.logInfo('Using IPTables backend') - tables = IPTables("MAILCOW", logger) +chain_name = "MAILCOW" +r = None def refreshF2boptions(): @@ -250,9 +218,10 @@ def clear(): with lock: tables.clearIPv4Table() tables.clearIPv6Table() - r.delete('F2B_ACTIVE_BANS') - r.delete('F2B_PERM_BANS') - pubsub.unsubscribe() + if r: + r.delete('F2B_ACTIVE_BANS') + r.delete('F2B_PERM_BANS') + pubsub.unsubscribe() def watch(): logger.logInfo('Watching Redis channel F2B_CHANNEL') @@ -409,15 +378,60 @@ def quit(signum, frame): if __name__ == '__main__': - refreshF2boptions() + # init Logger + logger = Logger(None) + + # init backend + backend = sys.argv[1] + if backend == "nftables": + logger.logInfo('Using NFTables backend') + tables = NFTables(chain_name, logger) + else: + logger.logInfo('Using IPTables backend') + tables = IPTables(chain_name, logger) + # In case a previous session was killed without cleanup clear() + # Reinit MAILCOW chain # Is called before threads start, no locking logger.logInfo("Initializing mailcow netfilter chain") tables.initChainIPv4() tables.initChainIPv6() + if os.getenv("DISABLE_NETFILTER_ISOLATION_RULE").lower() in ("y", "yes"): + logger.logInfo(f"Skipping {chain_name} isolation") + else: + logger.logInfo(f"Setting {chain_name} isolation") + tables.create_mailcow_isolation_rule("br-mailcow", [3306, 6379, 8983, 12345], os.getenv("MAILCOW_REPLICA_IP")) + + # connect to redis + while True: + try: + redis_slaveof_ip = os.getenv('REDIS_SLAVEOF_IP', '') + redis_slaveof_port = os.getenv('REDIS_SLAVEOF_PORT', '') + if "".__eq__(redis_slaveof_ip): + r = redis.StrictRedis(host=os.getenv('IPV4_NETWORK', '172.22.1') + '.249', decode_responses=True, port=6379, db=0) + else: + r = redis.StrictRedis(host=redis_slaveof_ip, decode_responses=True, port=redis_slaveof_port, db=0) + r.ping() + except Exception as ex: + print('%s - trying again in 3 seconds' % (ex)) + time.sleep(3) + else: + break + pubsub = r.pubsub() + Logger.r = r + + # rename fail2ban to netfilter + if r.exists('F2B_LOG'): + r.rename('F2B_LOG', 'NETFILTER_LOG') + # clear bans in redis + r.delete('F2B_ACTIVE_BANS') + r.delete('F2B_PERM_BANS') + + refreshF2boptions() + watch_thread = Thread(target=watch) watch_thread.daemon = True watch_thread.start() diff --git a/data/Dockerfiles/netfilter/modules/IPTables.py b/data/Dockerfiles/netfilter/modules/IPTables.py index c60ecc613..29a9fb65a 100644 --- a/data/Dockerfiles/netfilter/modules/IPTables.py +++ b/data/Dockerfiles/netfilter/modules/IPTables.py @@ -1,5 +1,6 @@ import iptc import time +import os class IPTables: def __init__(self, chain_name, logger): @@ -211,3 +212,41 @@ class IPTables: target = rule.create_target("SNAT") target.to_source = snat_target return rule + + def create_mailcow_isolation_rule(self, _interface:str, _dports:list, _allow:str = ""): + try: + chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), self.chain_name) + + # insert mailcow isolation rule + rule = iptc.Rule() + rule.in_interface = f'! {_interface}' + rule.out_interface = _interface + rule.protocol = 'tcp' + rule.create_target("DROP") + match = rule.create_match("multiport") + match.dports = ','.join(map(str, _dports)) + + if rule in chain.rules: + chain.delete_rule(rule) + chain.insert_rule(rule, position=0) + + # insert mailcow isolation exception rule + if _allow != "": + rule = iptc.Rule() + rule.src = _allow + rule.in_interface = f'! {_interface}' + rule.out_interface = _interface + rule.protocol = 'tcp' + rule.create_target("ACCEPT") + match = rule.create_match("multiport") + match.dports = ','.join(map(str, _dports)) + + if rule in chain.rules: + chain.delete_rule(rule) + chain.insert_rule(rule, position=0) + + + return True + except Exception as e: + self.logger.logCrit(f"Error adding {self.chain_name} isolation: {e}") + return False \ No newline at end of file diff --git a/data/Dockerfiles/netfilter/modules/Logger.py b/data/Dockerfiles/netfilter/modules/Logger.py index d60d52fad..2a40de0ce 100644 --- a/data/Dockerfiles/netfilter/modules/Logger.py +++ b/data/Dockerfiles/netfilter/modules/Logger.py @@ -10,7 +10,8 @@ class Logger: tolog['time'] = int(round(time.time())) tolog['priority'] = priority tolog['message'] = message - self.r.lpush('NETFILTER_LOG', json.dumps(tolog, ensure_ascii=False)) + if self.r: + self.r.lpush('NETFILTER_LOG', json.dumps(tolog, ensure_ascii=False)) print(message) def logWarn(self, message): diff --git a/data/Dockerfiles/netfilter/modules/NFTables.py b/data/Dockerfiles/netfilter/modules/NFTables.py index d341dc36b..e8e02c476 100644 --- a/data/Dockerfiles/netfilter/modules/NFTables.py +++ b/data/Dockerfiles/netfilter/modules/NFTables.py @@ -1,5 +1,6 @@ import nftables import ipaddress +import os class NFTables: def __init__(self, chain_name, logger): @@ -266,6 +267,17 @@ class NFTables: return self.nft_exec_dict(delete_command) + def delete_filter_rule(self, _family:str, _chain: str, _handle:str): + delete_command = self.get_base_dict() + _rule_opts = {'family': _family, + 'table': 'filter', + 'chain': _chain, + 'handle': _handle } + _delete = {'delete': {'rule': _rule_opts} } + delete_command["nftables"].append(_delete) + + return self.nft_exec_dict(delete_command) + def snat_rule(self, _family: str, snat_target: str, source_address: str): chain_name = self.nft_chain_names[_family]['nat']['postrouting'] @@ -381,7 +393,7 @@ class NFTables: break return chain_handle - def get_rules_handle(self, _family: str, _table: str, chain_name: str): + def get_rules_handle(self, _family: str, _table: str, chain_name: str, _comment_filter = "mailcow"): rule_handle = [] # Command: 'nft list chain {family} {table} {chain_name}' _chain_opts = {'family': _family, 'table': _table, 'name': chain_name} @@ -397,7 +409,7 @@ class NFTables: rule = _object["rule"] if rule["family"] == _family and rule["table"] == _table and rule["chain"] == chain_name: - if rule.get("comment") and rule["comment"] == "mailcow": + if rule.get("comment") and rule["comment"] == _comment_filter: rule_handle.append(rule["handle"]) return rule_handle @@ -493,3 +505,152 @@ class NFTables: position+=1 return position if rule_found else False + + def create_mailcow_isolation_rule(self, _interface:str, _dports:list, _allow:str = ""): + family = "ip" + table = "filter" + comment_filter_drop = "mailcow isolation" + comment_filter_allow = "mailcow isolation allow" + json_command = self.get_base_dict() + + # Delete old mailcow isolation rules + handles = self.get_rules_handle(family, table, self.chain_name, comment_filter_drop) + for handle in handles: + self.delete_filter_rule(family, self.chain_name, handle) + handles = self.get_rules_handle(family, table, self.chain_name, comment_filter_allow) + for handle in handles: + self.delete_filter_rule(family, self.chain_name, handle) + + # insert mailcow isolation rule + _match_dict_drop = [ + { + "match": { + "op": "!=", + "left": { + "meta": { + "key": "iifname" + } + }, + "right": _interface + } + }, + { + "match": { + "op": "==", + "left": { + "meta": { + "key": "oifname" + } + }, + "right": _interface + } + }, + { + "match": { + "op": "==", + "left": { + "payload": { + "protocol": "tcp", + "field": "dport" + } + }, + "right": { + "set": _dports + } + } + }, + { + "counter": { + "packets": 0, + "bytes": 0 + } + }, + { + "drop": None + } + ] + rule_drop = { "insert": { "rule": { + "family": family, + "table": table, + "chain": self.chain_name, + "comment": comment_filter_drop, + "expr": _match_dict_drop + }}} + json_command["nftables"].append(rule_drop) + + # insert mailcow isolation allow rule + if _allow != "": + _match_dict_allow = [ + { + "match": { + "op": "==", + "left": { + "payload": { + "protocol": "ip", + "field": "saddr" + } + }, + "right": _allow + } + }, + { + "match": { + "op": "!=", + "left": { + "meta": { + "key": "iifname" + } + }, + "right": _interface + } + }, + { + "match": { + "op": "==", + "left": { + "meta": { + "key": "oifname" + } + }, + "right": _interface + } + }, + { + "match": { + "op": "==", + "left": { + "payload": { + "protocol": "tcp", + "field": "dport" + } + }, + "right": { + "set": _dports + } + } + }, + { + "counter": { + "packets": 0, + "bytes": 0 + } + }, + { + "accept": None + } + ] + rule_allow = { "insert": { "rule": { + "family": family, + "table": table, + "chain": self.chain_name, + "comment": comment_filter_allow, + "expr": _match_dict_allow + }}} + json_command["nftables"].append(rule_allow) + + success = self.nft_exec_dict(json_command) + if success == False: + self.logger.logCrit(f"Error adding {self.chain_name} isolation") + return False + + return True \ No newline at end of file diff --git a/data/conf/dovecot/dovecot.conf b/data/conf/dovecot/dovecot.conf index 159e39f41..729686fb1 100644 --- a/data/conf/dovecot/dovecot.conf +++ b/data/conf/dovecot/dovecot.conf @@ -247,6 +247,9 @@ plugin { mail_log_events = delete undelete expunge copy mailbox_delete mailbox_rename mail_log_fields = uid box msgid size mail_log_cached_only = yes + + # Try set mail_replica + !include_try /etc/dovecot/mail_replica.conf } service quota-warning { executable = script /usr/local/bin/quota_notify.py diff --git a/docker-compose.yml b/docker-compose.yml index c1883f907..fa92546ad 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -21,6 +21,7 @@ services: image: mariadb:10.5 depends_on: - unbound-mailcow + - netfilter-mailcow stop_grace_period: 45s volumes: - mysql-vol-1:/var/lib/mysql/ @@ -46,6 +47,8 @@ services: volumes: - redis-vol-1:/data/ restart: always + depends_on: + - netfilter-mailcow ports: - "${REDIS_PORT:-127.0.0.1:7654}:6379" environment: @@ -222,6 +225,7 @@ services: image: mailcow/dovecot:1.27 depends_on: - mysql-mailcow + - netfilter-mailcow dns: - ${IPV4_NETWORK:-172.22.1}.254 cap_add: @@ -242,6 +246,8 @@ services: environment: - DOVECOT_MASTER_USER=${DOVECOT_MASTER_USER:-} - DOVECOT_MASTER_PASS=${DOVECOT_MASTER_PASS:-} + - MAILCOW_REPLICA_IP=${MAILCOW_REPLICA_IP:-} + - DOVEADM_REPLICA_PORT=${DOVEADM_REPLICA_PORT:-} - LOG_LINES=${LOG_LINES:-9999} - DBNAME=${DBNAME} - DBUSER=${DBUSER} @@ -437,12 +443,6 @@ services: netfilter-mailcow: image: mailcow/netfilter:1.55 stop_grace_period: 30s - depends_on: - - dovecot-mailcow - - postfix-mailcow - - sogo-mailcow - - php-fpm-mailcow - - redis-mailcow restart: always privileged: true environment: @@ -453,6 +453,8 @@ services: - SNAT6_TO_SOURCE=${SNAT6_TO_SOURCE:-n} - REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-} - REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-} + - MAILCOW_REPLICA_IP=${MAILCOW_REPLICA_IP:-} + - DISABLE_NETFILTER_ISOLATION_RULE=${DISABLE_NETFILTER_ISOLATION_RULE:-n} network_mode: "host" volumes: - /lib/modules:/lib/modules:ro @@ -553,6 +555,8 @@ services: solr-mailcow: image: mailcow/solr:1.8.2 restart: always + depends_on: + - netfilter-mailcow volumes: - solr-vol-1:/opt/solr/server/solr/dovecot-fts/data ports: diff --git a/generate_config.sh b/generate_config.sh index e62d16892..05d9ee2f1 100755 --- a/generate_config.sh +++ b/generate_config.sh @@ -494,6 +494,9 @@ WEBAUTHN_ONLY_TRUSTED_VENDORS=n # Otherwise it will work normally. SPAMHAUS_DQS_KEY= +# Prevent netfilter from setting an iptables/nftables rule to isolate the mailcow docker network - y/n +# CAUTION: Disabling this may expose container ports to other neighbors on the same subnet, even if the ports are bound to localhost +DISABLE_NETFILTER_ISOLATION_RULE=n EOF mkdir -p data/assets/ssl diff --git a/update.sh b/update.sh index 5df32e00e..f1e31652c 100755 --- a/update.sh +++ b/update.sh @@ -481,6 +481,7 @@ CONFIG_ARRAY=( "WEBAUTHN_ONLY_TRUSTED_VENDORS" "SPAMHAUS_DQS_KEY" "SKIP_UNBOUND_HEALTHCHECK" + "DISABLE_NETFILTER_ISOLATION_RULE" ) detect_bad_asn @@ -754,6 +755,13 @@ for option in ${CONFIG_ARRAY[@]}; do echo '# Skip Unbound (DNS Resolver) Healthchecks (NOT Recommended!) - y/n' >> mailcow.conf echo 'SKIP_UNBOUND_HEALTHCHECK=n' >> mailcow.conf fi + elif [[ ${option} == "DISABLE_NETFILTER_ISOLATION_RULE" ]]; then + if ! grep -q ${option} mailcow.conf; then + echo "Adding new option \"${option}\" to mailcow.conf" + echo '# Prevent netfilter from setting an iptables/nftables rule to isolate the mailcow docker network - y/n' >> mailcow.conf + echo '# CAUTION: Disabling this may expose container ports to other neighbors on the same subnet, even if the ports are bound to localhost' >> mailcow.conf + echo 'DISABLE_NETFILTER_ISOLATION_RULE=n' >> mailcow.conf + fi elif ! grep -q ${option} mailcow.conf; then echo "Adding new option \"${option}\" to mailcow.conf" echo "${option}=n" >> mailcow.conf From 2072301d89683cdbe9a398150b199630d1109d81 Mon Sep 17 00:00:00 2001 From: FreddleSpl0it Date: Fri, 2 Feb 2024 11:08:44 +0100 Subject: [PATCH 017/755] [Netfilter] only perform cleanup at exit if SIGTERM was recieved --- data/Dockerfiles/netfilter/main.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/data/Dockerfiles/netfilter/main.py b/data/Dockerfiles/netfilter/main.py index 8480c9efa..7f8dd9fbf 100644 --- a/data/Dockerfiles/netfilter/main.py +++ b/data/Dockerfiles/netfilter/main.py @@ -376,6 +376,11 @@ def quit(signum, frame): global quit_now quit_now = True +def quit_clear(signum, frame): + global exit_code + clear() + sys.exit(exit_code) + if __name__ == '__main__': # init Logger @@ -474,8 +479,7 @@ if __name__ == '__main__': whitelistupdate_thread.daemon = True whitelistupdate_thread.start() - signal.signal(signal.SIGTERM, quit) - atexit.register(clear) + signal.signal(signal.SIGTERM, quit_clear) while not quit_now: time.sleep(0.5) From 2e57325dde15062fbecdf5ca49e29072f70a4814 Mon Sep 17 00:00:00 2001 From: DerLinkman Date: Fri, 2 Feb 2024 11:27:46 +0100 Subject: [PATCH 018/755] docker-compose.yml: Bump dovecot + netfilter version --- docker-compose.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index fa92546ad..31923d46c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -222,7 +222,7 @@ services: - sogo dovecot-mailcow: - image: mailcow/dovecot:1.27 + image: mailcow/dovecot:1.28 depends_on: - mysql-mailcow - netfilter-mailcow @@ -441,7 +441,7 @@ services: - acme netfilter-mailcow: - image: mailcow/netfilter:1.55 + image: mailcow/netfilter:1.56 stop_grace_period: 30s restart: always privileged: true From 39589bd441291c7068f6642782be6edff0bcb371 Mon Sep 17 00:00:00 2001 From: FreddleSpl0it Date: Fri, 2 Feb 2024 12:46:50 +0100 Subject: [PATCH 019/755] [Netfilter] only perform cleanup at exit if SIGTERM was recieved --- data/Dockerfiles/netfilter/main.py | 37 +++++++++++++++++++----------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/data/Dockerfiles/netfilter/main.py b/data/Dockerfiles/netfilter/main.py index 7f8dd9fbf..c3b19c4e8 100644 --- a/data/Dockerfiles/netfilter/main.py +++ b/data/Dockerfiles/netfilter/main.py @@ -30,6 +30,8 @@ exit_code = 0 lock = Lock() chain_name = "MAILCOW" r = None +pubsub = None +clear_before_quit = False def refreshF2boptions(): @@ -218,10 +220,12 @@ def clear(): with lock: tables.clearIPv4Table() tables.clearIPv6Table() - if r: - r.delete('F2B_ACTIVE_BANS') - r.delete('F2B_PERM_BANS') - pubsub.unsubscribe() + try: + if r is not None: + r.delete('F2B_ACTIVE_BANS') + r.delete('F2B_PERM_BANS') + except Exception as ex: + logger.logWarn('Error clearing redis keys F2B_ACTIVE_BANS and F2B_PERM_BANS: %s' % ex) def watch(): logger.logInfo('Watching Redis channel F2B_CHANNEL') @@ -229,6 +233,7 @@ def watch(): global quit_now global exit_code + global pubsub while not quit_now: try: @@ -249,6 +254,7 @@ def watch(): ban(addr) except Exception as ex: logger.logWarn('Error reading log line from pubsub: %s' % ex) + pubsub = None quit_now = True exit_code = 2 @@ -372,17 +378,22 @@ def blacklistUpdate(): permBan(net=net, unban=True) time.sleep(60.0 - ((time.time() - start_time) % 60.0)) -def quit(signum, frame): - global quit_now - quit_now = True - -def quit_clear(signum, frame): - global exit_code - clear() +def sigterm_quit(signum, frame): + global clear_before_quit + clear_before_quit = True sys.exit(exit_code) +def berfore_quit(): + if clear_before_quit: + clear() + if pubsub is not None: + pubsub.unsubscribe() + if __name__ == '__main__': + atexit.register(berfore_quit) + signal.signal(signal.SIGTERM, sigterm_quit) + # init Logger logger = Logger(None) @@ -420,12 +431,12 @@ if __name__ == '__main__': else: r = redis.StrictRedis(host=redis_slaveof_ip, decode_responses=True, port=redis_slaveof_port, db=0) r.ping() + pubsub = r.pubsub() except Exception as ex: print('%s - trying again in 3 seconds' % (ex)) time.sleep(3) else: break - pubsub = r.pubsub() Logger.r = r # rename fail2ban to netfilter @@ -479,8 +490,6 @@ if __name__ == '__main__': whitelistupdate_thread.daemon = True whitelistupdate_thread.start() - signal.signal(signal.SIGTERM, quit_clear) - while not quit_now: time.sleep(0.5) From c941e802d4177a7d8278f3a80359d833d9770bec Mon Sep 17 00:00:00 2001 From: FreddleSpl0it Date: Fri, 2 Feb 2024 12:57:21 +0100 Subject: [PATCH 020/755] [Netfilter] only perform cleanup at exit if SIGTERM was recieved --- data/Dockerfiles/netfilter/main.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/data/Dockerfiles/netfilter/main.py b/data/Dockerfiles/netfilter/main.py index c3b19c4e8..f4acd4612 100644 --- a/data/Dockerfiles/netfilter/main.py +++ b/data/Dockerfiles/netfilter/main.py @@ -228,12 +228,12 @@ def clear(): logger.logWarn('Error clearing redis keys F2B_ACTIVE_BANS and F2B_PERM_BANS: %s' % ex) def watch(): - logger.logInfo('Watching Redis channel F2B_CHANNEL') - pubsub.subscribe('F2B_CHANNEL') - + global pubsub global quit_now global exit_code - global pubsub + + logger.logInfo('Watching Redis channel F2B_CHANNEL') + pubsub.subscribe('F2B_CHANNEL') while not quit_now: try: From a3104934850cd6663c9e7347478f6f8902def03a Mon Sep 17 00:00:00 2001 From: FreddleSpl0it Date: Fri, 2 Feb 2024 16:52:41 +0100 Subject: [PATCH 021/755] [Dovecot] fix repl_health.sh --- data/Dockerfiles/dovecot/repl_health.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/Dockerfiles/dovecot/repl_health.sh b/data/Dockerfiles/dovecot/repl_health.sh index 05d891421..93b66da49 100755 --- a/data/Dockerfiles/dovecot/repl_health.sh +++ b/data/Dockerfiles/dovecot/repl_health.sh @@ -11,7 +11,7 @@ fi # Is replication active? # grep on file is less expensive than doveconf -if ! grep -qi mail_replica /etc/dovecot/dovecot.conf; then +if [ -n ${MAILCOW_REPLICA_IP} ]; then ${REDIS_CMDLINE} SET DOVECOT_REPL_HEALTH 1 > /dev/null exit fi From 909f07939e93af0135cc9bd6b5aeb2f9ee50d8fe Mon Sep 17 00:00:00 2001 From: DerLinkman Date: Fri, 2 Feb 2024 17:06:31 +0100 Subject: [PATCH 022/755] dovecot: bump version for repl fix --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index d75d61cb2..26a224b53 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -222,7 +222,7 @@ services: - sogo dovecot-mailcow: - image: mailcow/dovecot:1.28 + image: mailcow/dovecot:1.28.1 depends_on: - mysql-mailcow - netfilter-mailcow From 57e67ea8f79a1fe218cb0f0ea8ad95a53b9f0179 Mon Sep 17 00:00:00 2001 From: FreddleSpl0it Date: Fri, 2 Feb 2024 17:40:44 +0100 Subject: [PATCH 023/755] [Netfilter] fix mailcow isolation rule for iptables --- data/Dockerfiles/netfilter/modules/IPTables.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/Dockerfiles/netfilter/modules/IPTables.py b/data/Dockerfiles/netfilter/modules/IPTables.py index 29a9fb65a..3d3d43974 100644 --- a/data/Dockerfiles/netfilter/modules/IPTables.py +++ b/data/Dockerfiles/netfilter/modules/IPTables.py @@ -219,7 +219,7 @@ class IPTables: # insert mailcow isolation rule rule = iptc.Rule() - rule.in_interface = f'! {_interface}' + rule.in_interface = f'!{_interface}' rule.out_interface = _interface rule.protocol = 'tcp' rule.create_target("DROP") @@ -234,7 +234,7 @@ class IPTables: if _allow != "": rule = iptc.Rule() rule.src = _allow - rule.in_interface = f'! {_interface}' + rule.in_interface = f'!{_interface}' rule.out_interface = _interface rule.protocol = 'tcp' rule.create_target("ACCEPT") From 464b6f2e9328b64b0548deba7ab1c9edb096bf62 Mon Sep 17 00:00:00 2001 From: FreddleSpl0it Date: Mon, 5 Feb 2024 09:47:19 +0100 Subject: [PATCH 024/755] [Netfilter] fix redis logs --- data/Dockerfiles/netfilter/main.py | 4 ++-- data/Dockerfiles/netfilter/modules/Logger.py | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/data/Dockerfiles/netfilter/main.py b/data/Dockerfiles/netfilter/main.py index f4acd4612..62e0dda75 100644 --- a/data/Dockerfiles/netfilter/main.py +++ b/data/Dockerfiles/netfilter/main.py @@ -395,7 +395,7 @@ if __name__ == '__main__': signal.signal(signal.SIGTERM, sigterm_quit) # init Logger - logger = Logger(None) + logger = Logger() # init backend backend = sys.argv[1] @@ -437,7 +437,7 @@ if __name__ == '__main__': time.sleep(3) else: break - Logger.r = r + logger.set_redis(r) # rename fail2ban to netfilter if r.exists('F2B_LOG'): diff --git a/data/Dockerfiles/netfilter/modules/Logger.py b/data/Dockerfiles/netfilter/modules/Logger.py index 2a40de0ce..25562965f 100644 --- a/data/Dockerfiles/netfilter/modules/Logger.py +++ b/data/Dockerfiles/netfilter/modules/Logger.py @@ -2,7 +2,10 @@ import time import json class Logger: - def __init__(self, redis): + def __init__(self): + self.r = None + + def set_redis(self, redis): self.r = redis def log(self, priority, message): @@ -10,7 +13,7 @@ class Logger: tolog['time'] = int(round(time.time())) tolog['priority'] = priority tolog['message'] = message - if self.r: + if self.r is not None: self.r.lpush('NETFILTER_LOG', json.dumps(tolog, ensure_ascii=False)) print(message) From 77e6ef218c9d5b0ceeb873b43435aee4173cc86c Mon Sep 17 00:00:00 2001 From: FreddleSpl0it Date: Mon, 5 Feb 2024 09:54:16 +0100 Subject: [PATCH 025/755] [Netfilter] Update to 1.57 --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 26a224b53..17559bedd 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -441,7 +441,7 @@ services: - acme netfilter-mailcow: - image: mailcow/netfilter:1.56 + image: mailcow/netfilter:1.57 stop_grace_period: 30s restart: always privileged: true From 38cc85fa4ca08723363c7a672a36383fccf259e2 Mon Sep 17 00:00:00 2001 From: vicente Date: Wed, 7 Feb 2024 15:36:04 +0100 Subject: [PATCH 026/755] set strict=False --- data/Dockerfiles/netfilter/modules/NFTables.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/data/Dockerfiles/netfilter/modules/NFTables.py b/data/Dockerfiles/netfilter/modules/NFTables.py index e8e02c476..38b31ebff 100644 --- a/data/Dockerfiles/netfilter/modules/NFTables.py +++ b/data/Dockerfiles/netfilter/modules/NFTables.py @@ -309,8 +309,8 @@ class NFTables: rule_handle = rule["handle"] break - dest_net = ipaddress.ip_network(source_address) - target_net = ipaddress.ip_network(snat_target) + dest_net = ipaddress.ip_network(source_address, strict=False) + target_net = ipaddress.ip_network(snat_target, strict=False) if rule_found: saddr_ip = rule["expr"][0]["match"]["right"]["prefix"]["addr"] @@ -321,9 +321,9 @@ class NFTables: target_ip = rule["expr"][3]["snat"]["addr"] - saddr_net = ipaddress.ip_network(saddr_ip + '/' + str(saddr_len)) - daddr_net = ipaddress.ip_network(daddr_ip + '/' + str(daddr_len)) - current_target_net = ipaddress.ip_network(target_ip) + saddr_net = ipaddress.ip_network(saddr_ip + '/' + str(saddr_len), strict=False) + daddr_net = ipaddress.ip_network(daddr_ip + '/' + str(daddr_len), strict=False) + current_target_net = ipaddress.ip_network(target_ip, strict=False) match = all(( dest_net == saddr_net, @@ -417,7 +417,7 @@ class NFTables: json_command = self.get_base_dict() expr_opt = [] - ipaddr_net = ipaddress.ip_network(ipaddr) + ipaddr_net = ipaddress.ip_network(ipaddr, strict=False) right_dict = {'prefix': {'addr': str(ipaddr_net.network_address), 'len': int(ipaddr_net.prefixlen) } } left_dict = {'payload': {'protocol': _family, 'field': 'saddr'} } @@ -466,7 +466,7 @@ class NFTables: current_rule_net = ipaddress.ip_network(current_rule_ip) # ip to ban - candidate_net = ipaddress.ip_network(ipaddr) + candidate_net = ipaddress.ip_network(ipaddr, strict=False) if current_rule_net == candidate_net: rule_handle = _object["rule"]["handle"] From eb91d9905bc1f4dbdde486e635592bea4ee02726 Mon Sep 17 00:00:00 2001 From: vicente Date: Wed, 7 Feb 2024 15:48:49 +0100 Subject: [PATCH 027/755] fix typpo in chain order message --- data/Dockerfiles/netfilter/modules/NFTables.py | 1 + 1 file changed, 1 insertion(+) diff --git a/data/Dockerfiles/netfilter/modules/NFTables.py b/data/Dockerfiles/netfilter/modules/NFTables.py index 38b31ebff..4cb0110ae 100644 --- a/data/Dockerfiles/netfilter/modules/NFTables.py +++ b/data/Dockerfiles/netfilter/modules/NFTables.py @@ -41,6 +41,7 @@ class NFTables: exit_code = 2 if chain_position > 0: + chain_position += 1 self.logger.logCrit(f'MAILCOW target is in position {chain_position} in the {filter_table} {chain} table, restarting container to fix it...') err = True exit_code = 2 From 5a9702771cba4fedbc79331e92ff757f734df58e Mon Sep 17 00:00:00 2001 From: DerLinkman Date: Wed, 7 Feb 2024 17:18:20 +0100 Subject: [PATCH 028/755] [SOGo] Fixed SOGo crash on older kernels < 5.10.0-X --- data/Dockerfiles/sogo/Dockerfile | 4 ++-- docker-compose.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/data/Dockerfiles/sogo/Dockerfile b/data/Dockerfiles/sogo/Dockerfile index a4601c405..59fc66804 100644 --- a/data/Dockerfiles/sogo/Dockerfile +++ b/data/Dockerfiles/sogo/Dockerfile @@ -1,8 +1,8 @@ -FROM debian:bookworm-slim +FROM debian:bullseye-slim LABEL maintainer "The Infrastructure Company GmbH GmbH " ARG DEBIAN_FRONTEND=noninteractive -ARG DEBIAN_VERSION=bookworm +ARG DEBIAN_VERSION=bullseye ARG SOGO_DEBIAN_REPOSITORY=http://www.axis.cz/linux/debian # renovate: datasource=github-releases depName=tianon/gosu versioning=semver-coerced extractVersion=^(?.*)$ ARG GOSU_VERSION=1.17 diff --git a/docker-compose.yml b/docker-compose.yml index 17559bedd..b36f45b8b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -175,7 +175,7 @@ services: - phpfpm sogo-mailcow: - image: mailcow/sogo:1.122 + image: mailcow/sogo:1.122.1 environment: - DBNAME=${DBNAME} - DBUSER=${DBUSER} From d08ccbce789880eb81ebebca48d440637ab36983 Mon Sep 17 00:00:00 2001 From: DerLinkman Date: Wed, 7 Feb 2024 17:28:49 +0100 Subject: [PATCH 029/755] dovecot: fix wrong timestamps inside logs --- data/Dockerfiles/dovecot/syslog-ng-redis_slave.conf | 1 + data/Dockerfiles/dovecot/syslog-ng.conf | 1 + 2 files changed, 2 insertions(+) diff --git a/data/Dockerfiles/dovecot/syslog-ng-redis_slave.conf b/data/Dockerfiles/dovecot/syslog-ng-redis_slave.conf index f7fc20b7e..519928954 100644 --- a/data/Dockerfiles/dovecot/syslog-ng-redis_slave.conf +++ b/data/Dockerfiles/dovecot/syslog-ng-redis_slave.conf @@ -7,6 +7,7 @@ options { use_fqdn(no); owner("root"); group("adm"); perm(0640); stats(freq(0)); + keep_timestamp(no); bad_hostname("^gconfd$"); }; source s_dgram { diff --git a/data/Dockerfiles/dovecot/syslog-ng.conf b/data/Dockerfiles/dovecot/syslog-ng.conf index fcc13587d..3e929e7b9 100644 --- a/data/Dockerfiles/dovecot/syslog-ng.conf +++ b/data/Dockerfiles/dovecot/syslog-ng.conf @@ -7,6 +7,7 @@ options { use_fqdn(no); owner("root"); group("adm"); perm(0640); stats(freq(0)); + keep_timestamp(no); bad_hostname("^gconfd$"); }; source s_dgram { From 583c5b48a00bb1f1a61cbc411bc90532fce3ca3b Mon Sep 17 00:00:00 2001 From: DerLinkman Date: Wed, 7 Feb 2024 17:29:36 +0100 Subject: [PATCH 030/755] dovecot: bump to docker image 1.28.1 --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index b36f45b8b..0dfd344b5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -222,7 +222,7 @@ services: - sogo dovecot-mailcow: - image: mailcow/dovecot:1.28.1 + image: mailcow/dovecot:1.28.2 depends_on: - mysql-mailcow - netfilter-mailcow From 63bb8e8cefb4afebd50f12a485f6af5d12c98125 Mon Sep 17 00:00:00 2001 From: DerLinkman Date: Thu, 8 Feb 2024 12:23:46 +0100 Subject: [PATCH 031/755] unbound: increase check interval to 30s --- data/Dockerfiles/unbound/Dockerfile | 4 ++-- docker-compose.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/data/Dockerfiles/unbound/Dockerfile b/data/Dockerfiles/unbound/Dockerfile index f56cbc6e5..f6d072cc6 100644 --- a/data/Dockerfiles/unbound/Dockerfile +++ b/data/Dockerfiles/unbound/Dockerfile @@ -20,10 +20,10 @@ EXPOSE 53/udp 53/tcp COPY docker-entrypoint.sh /docker-entrypoint.sh -# healthcheck (nslookup) +# healthcheck (dig, ping, nc) COPY healthcheck.sh /healthcheck.sh RUN chmod +x /healthcheck.sh -HEALTHCHECK --interval=5s --timeout=30s CMD [ "/healthcheck.sh" ] +HEALTHCHECK --interval=30s --timeout=30s CMD [ "/healthcheck.sh" ] ENTRYPOINT ["/docker-entrypoint.sh"] diff --git a/docker-compose.yml b/docker-compose.yml index 0dfd344b5..df545c15e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,7 +2,7 @@ version: '2.1' services: unbound-mailcow: - image: mailcow/unbound:1.20 + image: mailcow/unbound:1.21 environment: - TZ=${TZ} - SKIP_UNBOUND_HEALTHCHECK=${SKIP_UNBOUND_HEALTHCHECK:-n} From c90d637a48cdac86363e4937bdd787db8bc94c37 Mon Sep 17 00:00:00 2001 From: FreddleSpl0it Date: Thu, 16 Feb 2023 15:32:53 +0100 Subject: [PATCH 032/755] [Web] redirect to sogo after failed sogo-auth --- data/web/sogo-auth.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/data/web/sogo-auth.php b/data/web/sogo-auth.php index 40fff5856..c34a60def 100644 --- a/data/web/sogo-auth.php +++ b/data/web/sogo-auth.php @@ -65,8 +65,7 @@ elseif (isset($_GET['login'])) { } } } - header('HTTP/1.0 403 Forbidden'); - echo "Forbidden"; + header("Location: /SOGo/"); exit; } // only check for admin-login on sogo GUI requests From cfce7086a578bc4d3883527b969d80a3067b00fb Mon Sep 17 00:00:00 2001 From: FreddleSpl0it Date: Thu, 16 Feb 2023 15:34:47 +0100 Subject: [PATCH 033/755] [Web] few style changes --- data/web/css/build/013-datatables.css | 3 --- data/web/css/build/014-mailcow.css | 20 ++++++++++++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/data/web/css/build/013-datatables.css b/data/web/css/build/013-datatables.css index 57e2b6d94..2b19ba24e 100644 --- a/data/web/css/build/013-datatables.css +++ b/data/web/css/build/013-datatables.css @@ -8,9 +8,6 @@ .dtr-details { width: 100%; } -.table-striped>tbody>tr:nth-of-type(odd) { - background-color: #F2F2F2; -} td.child>ul>li { display: flex; } diff --git a/data/web/css/build/014-mailcow.css b/data/web/css/build/014-mailcow.css index 6c70a2a55..8c1d7c2af 100644 --- a/data/web/css/build/014-mailcow.css +++ b/data/web/css/build/014-mailcow.css @@ -33,6 +33,13 @@ url('/fonts/noto-sans-v12-latin_greek_cyrillic-700italic.woff2') format('woff2'), url('/fonts/noto-sans-v12-latin_greek_cyrillic-700italic.woff') format('woff'); } + +body { + min-height: 100vh; + display: flex; + flex-direction: column; + background-color: #fbfbfb; +} #maxmsgsize { min-width: 80px; } #slider1 .slider-selection { background: #FFD700; @@ -78,6 +85,19 @@ .navbar-fixed-top .navbar-collapse { max-height: 1000px } +.nav-tabs .nav-link, .nav-tabs .nav-link.disabled, .nav-tabs .nav-link.disabled:hover, .nav-tabs .nav-link.disabled:focus { + border-color: #dfdfdf; +} +.nav-tabs .nav-link.active, .nav-tabs .nav-item.show .nav-link { + border-color: #dfdfdf; + border-bottom: 1px solid #ffffff; +} +.nav-tabs .nav-link:hover, .nav-tabs .nav-link:focus { + border-color: #dfdfdf; +} +.nav-tabs { + border-bottom: 1px solid #dfdfdf; +} .bi { display: inline-block; font-size: 12pt; From 415c1d057499a4f927d4eb4edbca467785fee6a7 Mon Sep 17 00:00:00 2001 From: FreddleSpl0it Date: Thu, 16 Feb 2023 15:39:12 +0100 Subject: [PATCH 034/755] [Web] add seperate link for logged in users --- data/web/inc/functions.customize.inc.php | 25 +++++++++-- data/web/inc/header.inc.php | 9 ++++ data/web/js/site/admin.js | 1 + .../templates/admin/tab-config-customize.twig | 5 ++- data/web/templates/base.twig | 41 +++++++++++-------- data/web/templates/index.twig | 4 +- 6 files changed, 64 insertions(+), 21 deletions(-) diff --git a/data/web/inc/functions.customize.inc.php b/data/web/inc/functions.customize.inc.php index b72923573..c4df924d9 100644 --- a/data/web/inc/functions.customize.inc.php +++ b/data/web/inc/functions.customize.inc.php @@ -122,10 +122,14 @@ function customize($_action, $_item, $_data = null) { case 'app_links': $apps = (array)$_data['app']; $links = (array)$_data['href']; + $user_links = (array)$_data['user_href']; $out = array(); - if (count($apps) == count($links)) { + if (count($apps) == count($links) && count($apps) == count($user_links)) { for ($i = 0; $i < count($apps); $i++) { - $out[] = array($apps[$i] => $links[$i]); + $out[] = array($apps[$i] => array( + 'link' => $links[$i], + 'user_link' => $user_links[$i] + )); } try { $redis->set('APP_LINKS', json_encode($out)); @@ -256,7 +260,22 @@ function customize($_action, $_item, $_data = null) { ); return false; } - return ($app_links) ? $app_links : false; + + if (empty($app_links)){ + return false; + } + + foreach($app_links as $key => $value){ + foreach($value as $app => $details){ + if (empty($details['user_link']) || empty($_SESSION['mailcow_cc_username'])){ + $app_links[$key][$app]['user_link'] = $app_links[$key][$app]['link']; + } else { + $app_links[$key][$app]['user_link'] = str_replace('%u', $_SESSION['mailcow_cc_username'], $app_links[$key][$app]['user_link']); + } + } + } + + return $app_links; break; case 'main_logo': case 'main_logo_dark': diff --git a/data/web/inc/header.inc.php b/data/web/inc/header.inc.php index 9afc288dd..c0e166403 100644 --- a/data/web/inc/header.inc.php +++ b/data/web/inc/header.inc.php @@ -30,6 +30,14 @@ if(!file_exists($CSSPath)) { cleanupCSS($hash); } +$mailcow_apps_processed = $MAILCOW_APPS; +for ($i = 0; $i < count($mailcow_apps_processed); $i++) { + if (!empty($_SESSION['mailcow_cc_username'])){ + $mailcow_apps_processed[$i]['user_link'] = str_replace('%u', $_SESSION['mailcow_cc_username'], $mailcow_apps_processed[$i]['user_link']); + } +} + + $globalVariables = [ 'mailcow_hostname' => getenv('MAILCOW_HOSTNAME'), 'mailcow_locale' => @$_SESSION['mailcow_locale'], @@ -45,6 +53,7 @@ $globalVariables = [ 'lang' => $lang, 'skip_sogo' => (getenv('SKIP_SOGO') == 'y'), 'allow_admin_email_login' => (getenv('ALLOW_ADMIN_EMAIL_LOGIN') == 'n'), + 'mailcow_apps_processed' => $mailcow_apps_processed, 'mailcow_apps' => $MAILCOW_APPS, 'app_links' => customize('get', 'app_links'), 'is_root_uri' => (parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) == '/'), diff --git a/data/web/js/site/admin.js b/data/web/js/site/admin.js index 80da64167..095557311 100644 --- a/data/web/js/site/admin.js +++ b/data/web/js/site/admin.js @@ -711,6 +711,7 @@ jQuery(function($){ if (type == "app_link") { cols = ''; cols += ''; + cols += ''; cols += '' + lang.remove_row + ''; } else if (type == "f2b_regex") { cols = ''; diff --git a/data/web/templates/admin/tab-config-customize.twig b/data/web/templates/admin/tab-config-customize.twig index 7fc990a64..4b8f53231 100644 --- a/data/web/templates/admin/tab-config-customize.twig +++ b/data/web/templates/admin/tab-config-customize.twig @@ -58,13 +58,15 @@ {{ lang.admin.app_name }} {{ lang.admin.link }} + {{ lang.admin.user_link }}   {% for row in app_links %} {% for key, val in row %} - + + {{ lang.admin.remove_row }} {% endfor %} @@ -73,6 +75,7 @@ + {{ lang.admin.remove_row }} {% endfor %} diff --git a/data/web/templates/base.twig b/data/web/templates/base.twig index ca744d2a3..1c027138c 100644 --- a/data/web/templates/base.twig +++ b/data/web/templates/base.twig @@ -29,7 +29,7 @@
{% block navbar %} -