From f77c65411ded33a6815e63bb958e6e9b77b0c288 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20L=C3=A9on?= Date: Mon, 27 Feb 2023 12:04:32 +0100 Subject: [PATCH 01/29] Fix SNAT never being added because of exception Some firewall rule object (iptc) do not have a parameter attribute, which results in an exception being triggered, and the mailcow SNAT rule to never be created. Firewall rules that trigger such exception are: - -A POSTROUTING -s 192.168.122.0/24 -d 224.0.0.0/24 -j RETURN This commit just verify attribute presence, and skip the rule properly instead of triggering an exception. --- data/Dockerfiles/netfilter/server.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/data/Dockerfiles/netfilter/server.py b/data/Dockerfiles/netfilter/server.py index 0b0e2a41..b1a9f336 100644 --- a/data/Dockerfiles/netfilter/server.py +++ b/data/Dockerfiles/netfilter/server.py @@ -366,6 +366,8 @@ def snat4(snat_target): chain.insert_rule(new_rule) else: for position, rule in enumerate(chain.rules): + if not hasattr(rule.target, 'parameter'): + continue match = all(( new_rule.get_src() == rule.get_src(), new_rule.get_dst() == rule.get_dst(), From a5b8f1b7f75e135adc7739fc46d67d8298b72413 Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 28 Feb 2023 20:08:33 +0100 Subject: [PATCH 02/29] Update to PHP 8.2 --- data/Dockerfiles/phpfpm/Dockerfile | 4 +++- docker-compose.yml | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/data/Dockerfiles/phpfpm/Dockerfile b/data/Dockerfiles/phpfpm/Dockerfile index c8713e04..ef50ab4b 100644 --- a/data/Dockerfiles/phpfpm/Dockerfile +++ b/data/Dockerfiles/phpfpm/Dockerfile @@ -1,4 +1,4 @@ -FROM php:8.1-fpm-alpine3.17 +FROM php:8.2-fpm-alpine3.17 LABEL maintainer "Andre Peters " # renovate: datasource=github-tags depName=krakjoe/apcu versioning=semver-coerced @@ -52,6 +52,7 @@ RUN apk add -U --no-cache autoconf \ libxpm-dev \ libzip \ libzip-dev \ + linux-headers \ make \ mysql-client \ openldap-dev \ @@ -99,6 +100,7 @@ RUN apk add -U --no-cache autoconf \ libxml2-dev \ libxpm-dev \ libzip-dev \ + linux-headers \ make \ openldap-dev \ pcre-dev \ diff --git a/docker-compose.yml b/docker-compose.yml index 7c6c5d6a..c9b03d4f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -106,7 +106,7 @@ services: - rspamd php-fpm-mailcow: - image: mailcow/phpfpm:1.82 + image: mailcow/phpfpm:1.83 command: "php-fpm -d date.timezone=${TZ} -d expose_php=0" depends_on: - redis-mailcow From 310c01aac24d70f4d925b366429b409cd73e1900 Mon Sep 17 00:00:00 2001 From: Felix Kaechele Date: Fri, 3 Mar 2023 22:57:10 -0500 Subject: [PATCH 03/29] Fix SELinux labelling of init_db.inc.php for SOGo init_db.inc.php is currently labelled as exclusive for SOGo while in truth it is shared among containers. This breaks the admin interface but also any of the DAV features of SOGo. Signed-off-by: Felix Kaechele --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 40d22ce0..ad3053ae 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -191,7 +191,7 @@ services: volumes: - ./data/hooks/sogo:/hooks:Z - ./data/conf/sogo/:/etc/sogo/:z - - ./data/web/inc/init_db.inc.php:/init_db.inc.php:Z + - ./data/web/inc/init_db.inc.php:/init_db.inc.php:z - ./data/conf/sogo/custom-favicon.ico:/usr/lib/GNUstep/SOGo/WebServerResources/img/sogo.ico:z - ./data/conf/sogo/custom-theme.js:/usr/lib/GNUstep/SOGo/WebServerResources/js/theme.js:z - ./data/conf/sogo/custom-sogo.js:/usr/lib/GNUstep/SOGo/WebServerResources/js/custom-sogo.js:z From 1a9294b58f0c1756c4e61451e4a7103e34640998 Mon Sep 17 00:00:00 2001 From: Dmitriy Alekseev <1865999+dragoangel@users.noreply.github.com> Date: Sat, 4 Mar 2023 17:57:52 +0200 Subject: [PATCH 04/29] [Rspamd] Fix cases of forwarding via freemail Excluding FREEMAIL_ENVFROM from the FREEMAIL_POLICY_FAILURE expression will allow forwarding mail via freemail services when the initial sender did not have a DKIM signature. --- data/conf/rspamd/local.d/composites.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/conf/rspamd/local.d/composites.conf b/data/conf/rspamd/local.d/composites.conf index 337a2eb1..02ff955b 100644 --- a/data/conf/rspamd/local.d/composites.conf +++ b/data/conf/rspamd/local.d/composites.conf @@ -8,7 +8,7 @@ VIRUS_FOUND { } # Bad policy from free mail providers FREEMAIL_POLICY_FAILURE { - expression = "-g+:policies & !DMARC_POLICY_ALLOW & !MAILLIST & ( FREEMAIL_ENVFROM | FREEMAIL_FROM ) & !WHITELISTED_FWD_HOST"; + expression = "FREEMAIL_FROM & !DMARC_POLICY_ALLOW & !MAILLIST& !WHITELISTED_FWD_HOST & -g+:policies"; score = 16.0; } # Applies to freemail with undisclosed recipients From 81fcbdd1047c12811b3235f714dbc9dab97eaa9c Mon Sep 17 00:00:00 2001 From: Dmitriy Alekseev <1865999+dragoangel@users.noreply.github.com> Date: Sat, 4 Mar 2023 18:06:26 +0200 Subject: [PATCH 05/29] [SOGo] Disable password change option It doesn't work with ProxyAuth and in general not honor password policy set via mailcow UI. SOGo also do not provide own settings to provide any password policy. Due to this two issues I think that it's better have it disabled by default. People who need it can turn it back easily. We can update https://docs.mailcow.email/manual-guides/SOGo/u_e-sogo/#disable-password-changing to `enable-password-changin` and explanations of reasons why it is disabled. --- data/conf/sogo/sogo.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/conf/sogo/sogo.conf b/data/conf/sogo/sogo.conf index 97a34e9e..2c042c30 100644 --- a/data/conf/sogo/sogo.conf +++ b/data/conf/sogo/sogo.conf @@ -62,7 +62,7 @@ SOGoFirstDayOfWeek = "1"; SOGoSieveFolderEncoding = "UTF-8"; - SOGoPasswordChangeEnabled = YES; + SOGoPasswordChangeEnabled = NO; SOGoSentFolderName = "Sent"; SOGoMailShowSubscribedFoldersOnly = NO; NGImap4ConnectionStringSeparator = "/"; From cbe1c97a82ccf64d29ebed8c344a4acdaa782882 Mon Sep 17 00:00:00 2001 From: milkmaker Date: Tue, 7 Mar 2023 05:39:22 +0100 Subject: [PATCH 06/29] Translations update from Weblate (#5114) * [Web] Updated lang.da-dk.json [Web] Updated lang.da-dk.json [Web] Updated lang.da-dk.json Co-authored-by: Tacaly Co-authored-by: milkmaker * [Web] Updated lang.fr-fr.json Co-authored-by: Matthieu Leboeuf Co-authored-by: milkmaker --------- Co-authored-by: Tacaly Co-authored-by: Matthieu Leboeuf --- data/web/lang/lang.da-dk.json | 10 +++++++--- data/web/lang/lang.fr-fr.json | 11 +++++++++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/data/web/lang/lang.da-dk.json b/data/web/lang/lang.da-dk.json index 6ff8e9b7..61a553e6 100644 --- a/data/web/lang/lang.da-dk.json +++ b/data/web/lang/lang.da-dk.json @@ -83,7 +83,7 @@ "private_comment": "Privat kommentar", "public_comment": "Offentlig kommentar", "quota_mb": "Kvota (Mb)", - "relay_all": "Send alle modtagere videre", + "relay_all": "Besvar alle modtager", "relay_all_info": "↪ Hvis du vælger ikke at videresende alle modtagere, skal du tilføje et (\"blind\") postkasse til hver enkelt modtager, der skal videresendes.", "relay_domain": "Send dette domæne videre", "relay_transport_info": "
Info
Du kan definere transportkort til en tilpasset destination for dette domæne. Hvis ikke indstillet, foretages der et MX-opslag.", @@ -104,7 +104,10 @@ "timeout2": "Timeout for forbindelse til lokal vært", "username": "Brugernavn", "validate": "Bekræft", - "validation_success": "Valideret med succes" + "validation_success": "Valideret med succes", + "bcc_dest_format": "BCC-destination skal være en enkelt gyldig e-mail-adresse.
Hvis du har brug for at sende en kopi til flere adresser, kan du oprette et alias og bruge det her.", + "app_passwd_protocols": "Tilladte protokoller for app adgangskode", + "tags": "Tag's" }, "admin": { "access": "Adgang", @@ -313,7 +316,8 @@ "verify": "Verificere", "yes": "✓", "ip_check_opt_in": "Opt-In for brug af tredjepartstjeneste ipv4.mailcow.email og ipv6.mailcow.email til at finde eksterne IP-adresser.", - "queue_unban": "unban" + "queue_unban": "unban", + "admins": "Administratorer" }, "danger": { "access_denied": "Adgang nægtet eller ugyldig formular data", diff --git a/data/web/lang/lang.fr-fr.json b/data/web/lang/lang.fr-fr.json index 4db773e0..ef19d186 100644 --- a/data/web/lang/lang.fr-fr.json +++ b/data/web/lang/lang.fr-fr.json @@ -321,7 +321,9 @@ "admins": "Administrateurs", "api_read_only": "Accès lecture-seule", "password_policy_lowerupper": "Doit contenir des caractères minuscules et majuscules", - "password_policy_numbers": "Doit contenir au moins un chiffre" + "password_policy_numbers": "Doit contenir au moins un chiffre", + "ip_check": "Vérification IP", + "ip_check_disabled": "La vérification IP est désactivée. Vous pouvez l'activer sous
Système > Configuration > Options > Personnaliser" }, "danger": { "access_denied": "Accès refusé ou données de formulaire non valides", @@ -440,7 +442,12 @@ "username_invalid": "Le nom d'utilisateur %s ne peut pas être utilisé", "validity_missing": "Veuillez attribuer une période de validité", "value_missing": "Veuillez fournir toutes les valeurs", - "yotp_verification_failed": "La vérification Yubico OTP a échoué : %s" + "yotp_verification_failed": "La vérification Yubico OTP a échoué : %s", + "webauthn_authenticator_failed": "L'authentificateur selectionné est introuvable", + "demo_mode_enabled": "Le mode de démonstration est activé", + "template_exists": "La template %s existe déja", + "template_id_invalid": "Le numéro de template %s est invalide", + "template_name_invalid": "Le nom de la template est invalide" }, "debug": { "chart_this_server": "Graphique (ce serveur)", From f36bc16ca7bccbff3c1e649ce84eaaa61c0d5a95 Mon Sep 17 00:00:00 2001 From: BD <51322242+bdwebnet@users.noreply.github.com> Date: Wed, 8 Mar 2023 10:35:23 +0100 Subject: [PATCH 07/29] Fix Bug with button to load more logs --- data/web/js/site/debug.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/web/js/site/debug.js b/data/web/js/site/debug.js index e0b9a5ab..55b6660b 100644 --- a/data/web/js/site/debug.js +++ b/data/web/js/site/debug.js @@ -1181,7 +1181,7 @@ jQuery(function($){ if (table = $('#' + log_table).DataTable()) { var heading = $('#' + log_table).closest('.card').find('.card-header'); - var load_rows = (table.page.len() + 1) + '-' + (table.page.len() + new_nrows) + var load_rows = (table.data().length + 1) + '-' + (table.data().length + new_nrows) $.get('/api/v1/get/logs/' + log_url + '/' + load_rows).then(function(data){ if (data.length === undefined) { mailcow_alert_box(lang.no_new_rows, "info"); return; } From 0f59d4952be2c001100021080c9253dc9008b427 Mon Sep 17 00:00:00 2001 From: milkmaker Date: Fri, 17 Mar 2023 19:13:49 +0100 Subject: [PATCH 08/29] Translations update from Weblate (#5131) * [Web] Updated lang.da-dk.json Co-authored-by: Victor Pahuus Petersen Co-authored-by: milkmaker * [Web] Updated lang.fr-fr.json Co-authored-by: UpSilot Co-authored-by: milkmaker --------- Co-authored-by: Victor Pahuus Petersen Co-authored-by: UpSilot --- data/web/lang/lang.da-dk.json | 2 +- data/web/lang/lang.fr-fr.json | 14 +++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/data/web/lang/lang.da-dk.json b/data/web/lang/lang.da-dk.json index 61a553e6..5846181b 100644 --- a/data/web/lang/lang.da-dk.json +++ b/data/web/lang/lang.da-dk.json @@ -1048,7 +1048,7 @@ "spamfilter_table_empty": "Intet data at vise", "spamfilter_table_remove": "slet", "spamfilter_table_rule": "Regl", - "spamfilter_wl": "Hvisliste", + "spamfilter_wl": "Hvidliste", "spamfilter_wl_desc": "Hvidlistede e-mail-adresser til aldrig at klassificeres som spam. Wildcards kan bruges. Et filter anvendes kun på direkte aliaser (aliaser med en enkelt målpostkasse) eksklusive catch-aliaser og selve en postkasse.", "spamfilter_yellow": "Gul: denne besked kan være spam, vil blive tagget som spam og flyttes til din junk-mappe", "status": "Status", diff --git a/data/web/lang/lang.fr-fr.json b/data/web/lang/lang.fr-fr.json index ef19d186..402e66f9 100644 --- a/data/web/lang/lang.fr-fr.json +++ b/data/web/lang/lang.fr-fr.json @@ -24,7 +24,7 @@ "spam_policy": "Liste Noire/Liste Blanche", "spam_score": "Score SPAM", "syncjobs": "Tâches de synchronisation", - "tls_policy": "Police TLS", + "tls_policy": "Politique TLS", "unlimited_quota": "Quota illimité pour les boites de courriel", "domain_desc": "Modifier la description du domaine", "domain_relayhost": "Changer le relais pour un domaine", @@ -106,7 +106,8 @@ "validate": "Valider", "validation_success": "Validation réussie", "bcc_dest_format": "La destination Cci doit être une seule adresse e-mail valide.
Si vous avez besoin d'envoyer une copie à plusieurs adresses, créez un alias et utilisez-le ici.", - "tags": "Etiquettes" + "tags": "Etiquettes", + "app_passwd_protocols": "Protocoles autorisés pour le mot de passe de l'application" }, "admin": { "access": "Accès", @@ -585,7 +586,7 @@ "unchanged_if_empty": "Si non modifié, laisser en blanc", "username": "Nom d'utilisateur", "validate_save": "Valider et sauver", - "lookup_mx": "La destination est une expression régulière qui doit correspondre avec le nom du MX (.*google\\.com pour acheminer tout le courrier destiné à un MX se terminant par google.com via ce saut).", + "lookup_mx": "La destination est une expression régulière qui doit correspondre avec le nom du MX (.*google\\.com pour acheminer tout le courrier destiné à un MX se terminant par google.com via ce saut)", "mailbox_relayhost_info": "S'applique uniquement à la boîte aux lettres et aux alias directs, remplace le relayhost du domaine." }, "footer": { @@ -1088,9 +1089,12 @@ "username": "Nom d'utilisateur", "verify": "Vérification", "waiting": "En attente", - "week": "Semaine", + "week": "semaine", "weekly": "Hebdomadaire", - "weeks": "semaines" + "weeks": "semaines", + "months": "mois", + "year": "année", + "years": "années" }, "warning": { "cannot_delete_self": "Impossible de supprimer l’utilisateur connecté", From e6ce5e88f748f61e2952176391da820db5d4d699 Mon Sep 17 00:00:00 2001 From: DerLinkman Date: Mon, 20 Mar 2023 10:57:40 +0100 Subject: [PATCH 09/29] [Generate.sh] Fixed broken pipe error message --- generate_config.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/generate_config.sh b/generate_config.sh index 89af0f64..23e7036b 100755 --- a/generate_config.sh +++ b/generate_config.sh @@ -205,8 +205,8 @@ DBUSER=mailcow # Please use long, random alphanumeric strings (A-Za-z0-9) -DBPASS=$(LC_ALL=C /dev/null | head -c 28) +DBROOT=$(LC_ALL=C /dev/null | head -c 28) # ------------------------------ # HTTP/S Bindings From f6d135fbad5407b9dd8b7111fbc0ce20a964ae51 Mon Sep 17 00:00:00 2001 From: DerLinkman Date: Mon, 20 Mar 2023 12:05:11 +0100 Subject: [PATCH 10/29] [Update.sh] Fix docker compose detection + added failover --- update.sh | 77 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 58 insertions(+), 19 deletions(-) diff --git a/update.sh b/update.sh index 34d17354..73ee975c 100755 --- a/update.sh +++ b/update.sh @@ -176,18 +176,19 @@ remove_obsolete_nginx_ports() { } detect_docker_compose_command(){ -if ! [ "${DOCKER_COMPOSE_VERSION}" == "native" ] && ! [ "${DOCKER_COMPOSE_VERSION}" == "standalone" ]; then +if ! [[ "${DOCKER_COMPOSE_VERSION}" =~ ^(native|standalone)$ ]]; then if docker compose > /dev/null 2>&1; then if docker compose version --short | grep "2." > /dev/null 2>&1; then DOCKER_COMPOSE_VERSION=native COMPOSE_COMMAND="docker compose" echo -e "\e[31mFound Docker Compose Plugin (native).\e[0m" echo -e "\e[31mSetting the DOCKER_COMPOSE_VERSION Variable to native\e[0m" + sed -i 's/^DOCKER_COMPOSE_VERSION=.*/DOCKER_COMPOSE_VERSION=native/' $SCRIPT_DIR/mailcow.conf sleep 2 echo -e "\e[33mNotice: You'll have to update this Compose Version via your Package Manager manually!\e[0m" else echo -e "\e[31mCannot find Docker Compose with a Version Higher than 2.X.X.\e[0m" - echo -e "\e[31mPlease update/install it manually regarding to this doc site: https://mailcow.github.io/mailcow-dockerized-docs/i_u_m/i_u_m_install/\e[0m" + echo -e "\e[31mPlease update/install it manually regarding to this doc site: https://docs.mailcow.email/mailcow-dockerized-docs/i_u_m/i_u_m_install/\e[0m" exit 1 fi elif docker-compose > /dev/null 2>&1; then @@ -197,26 +198,60 @@ if ! [ "${DOCKER_COMPOSE_VERSION}" == "native" ] && ! [ "${DOCKER_COMPOSE_VERSIO COMPOSE_COMMAND="docker-compose" echo -e "\e[31mFound Docker Compose Standalone.\e[0m" echo -e "\e[31mSetting the DOCKER_COMPOSE_VERSION Variable to standalone\e[0m" + sed -i 's/^DOCKER_COMPOSE_VERSION=.*/DOCKER_COMPOSE_VERSION=standalone/' $SCRIPT_DIR/mailcow.conf sleep 2 echo -e "\e[33mNotice: For an automatic update of docker-compose please use the update_compose.sh scripts located at the helper-scripts folder.\e[0m" else echo -e "\e[31mCannot find Docker Compose with a Version Higher than 2.X.X.\e[0m" - echo -e "\e[31mPlease update/install regarding to this doc site: https://mailcow.github.io/mailcow-dockerized-docs/i_u_m/i_u_m_install/\e[0m" + echo -e "\e[31mPlease update/install regarding to this doc site: https://docs.mailcow.email/mailcow-dockerized-docs/i_u_m/i_u_m_install/\e[0m" exit 1 fi fi else echo -e "\e[31mCannot find Docker Compose.\e[0m" - echo -e "\e[31mPlease install it regarding to this doc site: https://mailcow.github.io/mailcow-dockerized-docs/i_u_m/i_u_m_install/\e[0m" + echo -e "\e[31mPlease install it regarding to this doc site: https://docs.mailcow.email/mailcow-dockerized-docs/i_u_m/i_u_m_install/\e[0m" exit 1 fi elif [ "${DOCKER_COMPOSE_VERSION}" == "native" ]; then COMPOSE_COMMAND="docker compose" + # Check if Native Compose works and has not been deleted + if ! $COMPOSE_COMMAND > /dev/null 2>&1; then + # IF it not exists/work anymore try the other command + COMPOSE_COMMAND="docker-compose" + if ! $COMPOSE_COMMAND > /dev/null 2>&1 || ! $COMPOSE_COMMAND --version | grep "^2." > /dev/null 2>&1; then + # IF it cannot find Standalone in > 2.X, then script stops + echo -e "\e[31mCannot find Docker Compose or the Version is lower then 2.X.X.\e[0m" + echo -e "\e[31mPlease install it regarding to this doc site: https://docs.mailcow.email/mailcow-dockerized-docs/i_u_m/i_u_m_install/\e[0m" + exit 1 + fi + # If it finds the standalone Plugin it will use this instead and change the mailcow.conf Variable accordingly + echo -e "\e[31mFound different Docker Compose Version then declared in mailcow.conf!\e[0m" + echo -e "\e[31mSetting the DOCKER_COMPOSE_VERSION Variable from native to standalone\e[0m" + sed -i 's/^DOCKER_COMPOSE_VERSION=.*/DOCKER_COMPOSE_VERSION=standalone/' $SCRIPT_DIR/mailcow.conf + sleep 2 + fi + elif [ "${DOCKER_COMPOSE_VERSION}" == "standalone" ]; then COMPOSE_COMMAND="docker-compose" + # Check if Standalone Compose works and has not been deleted + if ! $COMPOSE_COMMAND > /dev/null 2>&1 && ! $COMPOSE_COMMAND --version > /dev/null 2>&1 | grep "^2." > /dev/null 2>&1; then + # IF it not exists/work anymore try the other command + COMPOSE_COMMAND="docker compose" + if ! $COMPOSE_COMMAND > /dev/null 2>&1; then + # IF it cannot find Native in > 2.X, then script stops + echo -e "\e[31mCannot find Docker Compose.\e[0m" + echo -e "\e[31mPlease install it regarding to this doc site: https://docs.mailcow.email/mailcow-dockerized-docs/i_u_m/i_u_m_install/\e[0m" + exit 1 + fi + # If it finds the native Plugin it will use this instead and change the mailcow.conf Variable accordingly + echo -e "\e[31mFound different Docker Compose Version then declared in mailcow.conf!\e[0m" + echo -e "\e[31mSetting the DOCKER_COMPOSE_VERSION Variable from standalone to native\e[0m" + sed -i 's/^DOCKER_COMPOSE_VERSION=.*/DOCKER_COMPOSE_VERSION=native/' $SCRIPT_DIR/mailcow.conf + sleep 2 + fi fi } @@ -326,8 +361,12 @@ while (($#)); do echo -e "\e[32mRunning in forced mode...\e[0m" FORCE=y ;; + -d|--dev) + echo -e "\e[32mRunning in Developer mode...\e[0m" + DEV=y + ;; --help|-h) - echo './update.sh [-c|--check, --ours, --gc, --nightly, --prefetch, --skip-start, --skip-ping-check, --stable, -f|--force, -h|--help] + echo './update.sh [-c|--check, --ours, --gc, --nightly, --prefetch, --skip-start, --skip-ping-check, --stable, -f|--force, -d|--dev, -h|--help] -c|--check - Check for updates and exit (exit codes => 0: update available, 3: no updates) --ours - Use merge strategy option "ours" to solve conflicts in favor of non-mailcow code (local changes over remote changes), not recommended! @@ -338,6 +377,7 @@ while (($#)); do --skip-ping-check - Skip ICMP Check to public DNS resolvers (Use it only if you´ve blocked any ICMP Connections to your mailcow machine) --stable - Switch your mailcow updates to the stable (master) branch. Default unless you changed it with --nightly. -f|--force - Force update, do not ask questions + -d|--dev - Enables Developer Mode (No Checkout of update.sh for tests) ' exit 1 esac @@ -597,7 +637,7 @@ for option in ${CONFIG_ARRAY[@]}; do echo "Adding new option \"${option}\" to mailcow.conf" echo '# Password hash algorithm' >> mailcow.conf echo '# Only certain password hash algorithm are supported. For a fully list of supported schemes,' >> mailcow.conf - echo '# see https://mailcow.github.io/mailcow-dockerized-docs/models/model-passwd/' >> mailcow.conf + echo '# see https://docs.mailcow.email/models/model-passwd/' >> mailcow.conf echo "MAILCOW_PASS_SCHEME=BLF-CRYPT" >> mailcow.conf fi elif [[ ${option} == "ADDITIONAL_SERVER_NAMES" ]]; then @@ -617,7 +657,7 @@ for option in ${CONFIG_ARRAY[@]}; do echo '# Optional: Leave empty for none' >> mailcow.conf echo '# This value is only used on first order!' >> mailcow.conf echo '# Setting it at a later point will require the following steps:' >> mailcow.conf - echo '# https://mailcow.github.io/mailcow-dockerized-docs/troubleshooting/debug-reset_tls/' >> mailcow.conf + echo '# https://docs.mailcow.email/troubleshooting/debug-reset_tls/' >> mailcow.conf echo 'ACME_CONTACT=' >> mailcow.conf fi elif [[ ${option} == "WEBAUTHN_ONLY_TRUSTED_VENDORS" ]]; then @@ -727,15 +767,17 @@ elif [ $NEW_BRANCH == "nightly" ] && [ $CURRENT_BRANCH != "nightly" ]; then git checkout -f ${BRANCH} fi -echo -e "\e[32mChecking for newer update script...\e[0m" -SHA1_1=$(sha1sum update.sh) -git fetch origin #${BRANCH} -git checkout origin/${BRANCH} update.sh -SHA1_2=$(sha1sum update.sh) -if [[ ${SHA1_1} != ${SHA1_2} ]]; then - echo "update.sh changed, please run this script again, exiting." - chmod +x update.sh - exit 2 +if [ ! $DEV ]; then + echo -e "\e[32mChecking for newer update script...\e[0m" + SHA1_1=$(sha1sum update.sh) + git fetch origin #${BRANCH} + git checkout origin/${BRANCH} update.sh + SHA1_2=$(sha1sum update.sh) + if [[ ${SHA1_1} != ${SHA1_2} ]]; then + echo "update.sh changed, please run this script again, exiting." + chmod +x update.sh + exit 2 + fi fi if [ ! $FORCE ]; then @@ -902,9 +944,6 @@ else echo -e "\e[33mCannot determine current git repository version...\e[0m" fi -# Set DOCKER_COMPOSE_VERSION -sed -i 's/^DOCKER_COMPOSE_VERSION=$/DOCKER_COMPOSE_VERSION='$DOCKER_COMPOSE_VERSION'/g' mailcow.conf - if [[ ${SKIP_START} == "y" ]]; then echo -e "\e[33mNot starting mailcow, please run \"$COMPOSE_COMMAND up -d --remove-orphans\" to start mailcow.\e[0m" else From 0206e0886c70f242c8f8c92fe1b0f30006639f5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B6rn=20J=C3=B6rger?= Date: Fri, 17 Mar 2023 01:33:40 +0100 Subject: [PATCH 11/29] implemented exponentially incrementing bantime, removed active_window code that did nothing, cleanly initialized dictionary --- data/Dockerfiles/netfilter/server.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/data/Dockerfiles/netfilter/server.py b/data/Dockerfiles/netfilter/server.py index 0b0e2a41..de4b1766 100644 --- a/data/Dockerfiles/netfilter/server.py +++ b/data/Dockerfiles/netfilter/server.py @@ -174,20 +174,15 @@ def ban(address): net = ipaddress.ip_network((address + (NETBAN_IPV4 if type(ip) is ipaddress.IPv4Address else NETBAN_IPV6)), strict=False) net = str(net) - if not net in bans or time.time() - bans[net]['last_attempt'] > RETRY_WINDOW: - bans[net] = { 'attempts': 0 } - active_window = RETRY_WINDOW - else: - active_window = time.time() - bans[net]['last_attempt'] + if not net in bans: + bans[net] = {'attempts': 0, 'last_attempt': 0, 'ban_counter': 0} bans[net]['attempts'] += 1 bans[net]['last_attempt'] = time.time() - active_window = time.time() - bans[net]['last_attempt'] - if bans[net]['attempts'] >= MAX_ATTEMPTS: cur_time = int(round(time.time())) - logCrit('Banning %s for %d minutes' % (net, BAN_TIME / 60)) + logCrit('Banning %s for %d minutes' % (net, BAN_TIME / 60 * 2 ** bans[net]['ban_counter'])) if type(ip) is ipaddress.IPv4Address: with lock: chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), 'MAILCOW') @@ -206,7 +201,7 @@ def ban(address): rule.target = target if rule not in chain.rules: chain.insert_rule(rule) - r.hset('F2B_ACTIVE_BANS', '%s' % net, cur_time + BAN_TIME) + r.hset('F2B_ACTIVE_BANS', '%s' % net, cur_time + BAN_TIME * 2 ** bans[net]['ban_counter']) else: logWarn('%d more attempts in the next %d seconds until %s is banned' % (MAX_ATTEMPTS - bans[net]['attempts'], RETRY_WINDOW, net)) @@ -238,7 +233,8 @@ def unban(net): r.hdel('F2B_ACTIVE_BANS', '%s' % net) r.hdel('F2B_QUEUE_UNBAN', '%s' % net) if net in bans: - del bans[net] + bans[net]['attempts'] = 0 + bans[net]['ban_counter'] += 1 def permBan(net, unban=False): global lock @@ -432,7 +428,7 @@ def autopurge(): unban(str(net)) for net in bans.copy(): if bans[net]['attempts'] >= MAX_ATTEMPTS: - if time.time() - bans[net]['last_attempt'] > BAN_TIME: + if time.time() - bans[net]['last_attempt'] > BAN_TIME * 2 ** bans[net]['ban_counter']: unban(net) def isIpNetwork(address): From 1233613bea73a22442eb000dd36376f59d7b1ebb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B6rn=20J=C3=B6rger?= Date: Fri, 17 Mar 2023 14:41:37 +0100 Subject: [PATCH 12/29] implemented handling of max_bantime and ban_time_increment flag --- data/Dockerfiles/netfilter/server.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/data/Dockerfiles/netfilter/server.py b/data/Dockerfiles/netfilter/server.py index de4b1766..5533b4b3 100644 --- a/data/Dockerfiles/netfilter/server.py +++ b/data/Dockerfiles/netfilter/server.py @@ -67,11 +67,15 @@ def refreshF2boptions(): if not r.get('F2B_OPTIONS'): f2boptions = {} f2boptions['ban_time'] = int + f2boptions['max_ban_time'] = int + f2boptions['ban_time_increment'] = bool f2boptions['max_attempts'] = int f2boptions['retry_window'] = int f2boptions['netban_ipv4'] = int f2boptions['netban_ipv6'] = int f2boptions['ban_time'] = r.get('F2B_BAN_TIME') or 1800 + f2boptions['max_ban_time'] = r.get('F2B_MAX_BAN_TIME') or 10000 + f2boptions['ban_time_increment'] = r.get('F2B_BAN_TIME_INCREMENT') or True f2boptions['max_attempts'] = r.get('F2B_MAX_ATTEMPTS') or 10 f2boptions['retry_window'] = r.get('F2B_RETRY_WINDOW') or 600 f2boptions['netban_ipv4'] = r.get('F2B_NETBAN_IPV4') or 32 @@ -147,6 +151,7 @@ def ban(address): global lock refreshF2boptions() BAN_TIME = int(f2boptions['ban_time']) + BAN_TIME_INCREMENT = bool(f2boptions['ban_time_increment']) MAX_ATTEMPTS = int(f2boptions['max_attempts']) RETRY_WINDOW = int(f2boptions['retry_window']) NETBAN_IPV4 = '/' + str(f2boptions['netban_ipv4']) @@ -182,7 +187,8 @@ def ban(address): if bans[net]['attempts'] >= MAX_ATTEMPTS: cur_time = int(round(time.time())) - logCrit('Banning %s for %d minutes' % (net, BAN_TIME / 60 * 2 ** bans[net]['ban_counter'])) + NET_BAN_TIME = BAN_TIME if not BAN_TIME_INCREMENT else BAN_TIME * 2 ** bans[net]['ban_counter'] + logCrit('Banning %s for %d minutes' % (net, NET_BAN_TIME / 60 )) if type(ip) is ipaddress.IPv4Address: with lock: chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), 'MAILCOW') @@ -201,7 +207,7 @@ def ban(address): rule.target = target if rule not in chain.rules: chain.insert_rule(rule) - r.hset('F2B_ACTIVE_BANS', '%s' % net, cur_time + BAN_TIME * 2 ** bans[net]['ban_counter']) + r.hset('F2B_ACTIVE_BANS', '%s' % net, cur_time + NET_BAN_TIME) else: logWarn('%d more attempts in the next %d seconds until %s is banned' % (MAX_ATTEMPTS - bans[net]['attempts'], RETRY_WINDOW, net)) @@ -421,6 +427,8 @@ def autopurge(): time.sleep(10) refreshF2boptions() BAN_TIME = int(f2boptions['ban_time']) + MAX_BAN_TIME = int(f2boptions['max_ban_time']) + BAN_TIME_INCREMENT = bool(f2boptions['ban_time_increment']) MAX_ATTEMPTS = int(f2boptions['max_attempts']) QUEUE_UNBAN = r.hgetall('F2B_QUEUE_UNBAN') if QUEUE_UNBAN: @@ -428,7 +436,9 @@ def autopurge(): unban(str(net)) for net in bans.copy(): if bans[net]['attempts'] >= MAX_ATTEMPTS: - if time.time() - bans[net]['last_attempt'] > BAN_TIME * 2 ** bans[net]['ban_counter']: + NET_BAN_TIME = BAN_TIME if not BAN_TIME_INCREMENT else BAN_TIME * 2 ** bans[net]['ban_counter'] + TIME_SINCE_LAST_ATTEMPT = time.time() - bans[net]['last_attempt'] + if TIME_SINCE_LAST_ATTEMPT > NET_BAN_TIME or TIME_SINCE_LAST_ATTEMPT > MAX_BAN_TIME: unban(net) def isIpNetwork(address): From c28a6b89f030caca6e208790f80751588d1868ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B6rn=20J=C3=B6rger?= Date: Fri, 17 Mar 2023 18:22:16 +0100 Subject: [PATCH 13/29] Added ban_time_increment and max_ban_time to UI --- data/web/api/openapi.yaml | 12 +++++++++++- data/web/inc/functions.fail2ban.inc.php | 4 ++++ data/web/lang/lang.de-de.json | 2 ++ data/web/lang/lang.en-gb.json | 2 ++ data/web/lang/lang.es-es.json | 2 ++ data/web/lang/lang.fr-fr.json | 4 +++- data/web/lang/lang.it-it.json | 2 ++ data/web/lang/lang.nl-nl.json | 2 ++ data/web/templates/admin/tab-config-f2b.twig | 8 ++++++++ 9 files changed, 36 insertions(+), 2 deletions(-) diff --git a/data/web/api/openapi.yaml b/data/web/api/openapi.yaml index 5e07c4b3..65bd1211 100644 --- a/data/web/api/openapi.yaml +++ b/data/web/api/openapi.yaml @@ -3176,8 +3176,10 @@ paths: example: attr: ban_time: "86400" + ban_time_increment: "1" blacklist: "10.100.6.5/32,10.100.8.4/32" max_attempts: "5" + max_ban_time: "86400" netban_ipv4: "24" netban_ipv6: "64" retry_window: "600" @@ -3191,11 +3193,17 @@ paths: description: the backlisted ips or hostnames separated by comma type: string ban_time: - description: the time a ip should be banned + description: the time an ip should be banned type: number + ban_time_increment: + description: if the time of the ban should increase each time + type: boolean max_attempts: description: the maximum numbe of wrong logins before a ip is banned type: number + max_ban_time: + description: the maximum time an ip should be banned + type: number netban_ipv4: description: the networks mask to ban for ipv4 type: number @@ -4113,10 +4121,12 @@ paths: response: value: ban_time: 604800 + ban_time_increment: 1 blacklist: |- 45.82.153.37/32 92.118.38.52/32 max_attempts: 1 + max_ban_time: 604800 netban_ipv4: 32 netban_ipv6: 128 perm_bans: diff --git a/data/web/inc/functions.fail2ban.inc.php b/data/web/inc/functions.fail2ban.inc.php index 2a7f11e8..2c4aa41d 100644 --- a/data/web/inc/functions.fail2ban.inc.php +++ b/data/web/inc/functions.fail2ban.inc.php @@ -239,7 +239,9 @@ function fail2ban($_action, $_data = null) { $is_now = fail2ban('get'); if (!empty($is_now)) { $ban_time = intval((isset($_data['ban_time'])) ? $_data['ban_time'] : $is_now['ban_time']); + $ban_time_increment = (isset($_data['ban_time_increment']) && $_data['ban_time_increment'] == "1") ? 1 : 0; $max_attempts = intval((isset($_data['max_attempts'])) ? $_data['max_attempts'] : $is_now['max_attempts']); + $max_ban_time = intval((isset($_data['max_ban_time'])) ? $_data['max_ban_time'] : $is_now['max_ban_time']); $retry_window = intval((isset($_data['retry_window'])) ? $_data['retry_window'] : $is_now['retry_window']); $netban_ipv4 = intval((isset($_data['netban_ipv4'])) ? $_data['netban_ipv4'] : $is_now['netban_ipv4']); $netban_ipv6 = intval((isset($_data['netban_ipv6'])) ? $_data['netban_ipv6'] : $is_now['netban_ipv6']); @@ -256,6 +258,8 @@ function fail2ban($_action, $_data = null) { } $f2b_options = array(); $f2b_options['ban_time'] = ($ban_time < 60) ? 60 : $ban_time; + $f2b_options['ban_time_increment'] = ($ban_time_increment == 1) ? true : false; + $f2b_options['max_ban_time'] = ($max_ban_time < 60) ? 60 : $max_ban_time; $f2b_options['netban_ipv4'] = ($netban_ipv4 < 8) ? 8 : $netban_ipv4; $f2b_options['netban_ipv6'] = ($netban_ipv6 < 8) ? 8 : $netban_ipv6; $f2b_options['netban_ipv4'] = ($netban_ipv4 > 32) ? 32 : $netban_ipv4; diff --git a/data/web/lang/lang.de-de.json b/data/web/lang/lang.de-de.json index 8ff1cf06..4bd4b3fa 100644 --- a/data/web/lang/lang.de-de.json +++ b/data/web/lang/lang.de-de.json @@ -175,10 +175,12 @@ "empty": "Keine Einträge vorhanden", "excludes": "Diese Empfänger ausschließen", "f2b_ban_time": "Bannzeit in Sekunden", + "f2b_ban_time_increment": "Bannzeit erhöht sich mit jedem Bann", "f2b_blacklist": "Blacklist für Netzwerke und Hosts", "f2b_filter": "Regex-Filter", "f2b_list_info": "Ein Host oder Netzwerk auf der Blacklist wird immer eine Whitelist-Einheit überwiegen. Die Aktualisierung der Liste dauert einige Sekunden.", "f2b_max_attempts": "Max. Versuche", + "f2b_max_ban_time": "Maximale Bannzeit in Sekunden", "f2b_netban_ipv4": "Netzbereich für IPv4-Banns (8-32)", "f2b_netban_ipv6": "Netzbereich für IPv6-Banns (8-128)", "f2b_parameters": "Fail2ban-Parameter", diff --git a/data/web/lang/lang.en-gb.json b/data/web/lang/lang.en-gb.json index bfac011e..df83987c 100644 --- a/data/web/lang/lang.en-gb.json +++ b/data/web/lang/lang.en-gb.json @@ -177,10 +177,12 @@ "empty": "No results", "excludes": "Excludes these recipients", "f2b_ban_time": "Ban time (s)", + "f2b_ban_time_increment": "Ban time is incremented with each ban", "f2b_blacklist": "Blacklisted networks/hosts", "f2b_filter": "Regex filters", "f2b_list_info": "A blacklisted host or network will always outweigh a whitelist entity. List updates will take a few seconds to be applied.", "f2b_max_attempts": "Max. attempts", + "f2b_max_ban_time": "Max. ban time (s)", "f2b_netban_ipv4": "IPv4 subnet size to apply ban on (8-32)", "f2b_netban_ipv6": "IPv6 subnet size to apply ban on (8-128)", "f2b_parameters": "Fail2ban parameters", diff --git a/data/web/lang/lang.es-es.json b/data/web/lang/lang.es-es.json index d9c3bfd3..e56e6bdd 100644 --- a/data/web/lang/lang.es-es.json +++ b/data/web/lang/lang.es-es.json @@ -141,9 +141,11 @@ "empty": "Sin resultados", "excludes": "Excluye a estos destinatarios", "f2b_ban_time": "Tiempo de restricción (s)", + "f2b_ban_time_increment": "Tiempo de restricción se incrementa con cada restricción", "f2b_blacklist": "Redes y hosts en lista negra", "f2b_list_info": "Un host o red en lista negra siempre superará a una entidad de la lista blanca. Las actualizaciones de la lista tardarán unos segundos en aplicarse.", "f2b_max_attempts": "Max num. de intentos", + "f2b_max_ban_time": "Max tiempo de restricción (s)", "f2b_netban_ipv4": "Tamaño de subred IPv4 para aplicar la restricción (8-32)", "f2b_netban_ipv6": "Tamaño de subred IPv6 para aplicar la restricción (8-128)", "f2b_parameters": "Parametros Fail2ban", diff --git a/data/web/lang/lang.fr-fr.json b/data/web/lang/lang.fr-fr.json index 402e66f9..d64f62f7 100644 --- a/data/web/lang/lang.fr-fr.json +++ b/data/web/lang/lang.fr-fr.json @@ -172,11 +172,13 @@ "edit": "Editer", "empty": "Aucun résultat", "excludes": "Exclure ces destinataires", - "f2b_ban_time": "Durée du bannissement(s)", + "f2b_ban_time": "Durée du bannissement (s)", + "f2b_ban_time_increment": "Durée du bannissement est augmentée à chaque bannissement", "f2b_blacklist": "Réseaux/Domaines sur Liste Noire", "f2b_filter": "Filtre(s) Regex", "f2b_list_info": "Un hôte ou un réseau sur liste noire l'emportera toujours sur une entité de liste blanche. L'application des mises à jour de liste prendra quelques secondes.", "f2b_max_attempts": "Nb max. de tentatives", + "f2b_max_ban_time": "Max. durée du bannissement (s)", "f2b_netban_ipv4": "Taille du sous-réseau IPv4 pour l'application du bannissement (8-32)", "f2b_netban_ipv6": "Taille du sous-réseau IPv6 pour l'application du bannissement (8-128)", "f2b_parameters": "Paramètres Fail2ban", diff --git a/data/web/lang/lang.it-it.json b/data/web/lang/lang.it-it.json index d8d6978c..4d21547c 100644 --- a/data/web/lang/lang.it-it.json +++ b/data/web/lang/lang.it-it.json @@ -175,10 +175,12 @@ "empty": "Nessun risultato", "excludes": "Esclude questi destinatari", "f2b_ban_time": "Tempo di blocco (s)", + "f2b_ban_time_increment": "Tempo di blocco aumenta ad ogni blocco", "f2b_blacklist": "Host/reti in blacklist", "f2b_filter": "Filtri Regex", "f2b_list_info": "Un host oppure una rete in blacklist, avrà sempre un peso maggiore rispetto ad una in whitelist. L'aggiornamento della lista richiede alcuni secondi per la sua entrata in azione.", "f2b_max_attempts": "Tentativi massimi", + "f2b_max_ban_time": "Tempo massimo di blocco (s)", "f2b_netban_ipv4": "IPv4 subnet size to apply ban on (8-32)", "f2b_netban_ipv6": "IPv6 subnet size to apply ban on (8-128)", "f2b_parameters": "Parametri Fail2ban", diff --git a/data/web/lang/lang.nl-nl.json b/data/web/lang/lang.nl-nl.json index 774627ca..4c2ea0b1 100644 --- a/data/web/lang/lang.nl-nl.json +++ b/data/web/lang/lang.nl-nl.json @@ -168,10 +168,12 @@ "empty": "Geen resultaten", "excludes": "Exclusief", "f2b_ban_time": "Verbanningstijd (s)", + "f2b_ban_time_increment": "Verbanningstijd wordt verhoogd met elk verbanning", "f2b_blacklist": "Netwerken/hosts op de blacklist", "f2b_filter": "Regex-filters", "f2b_list_info": "Een host of netwerk op de blacklist staat altijd boven eenzelfde op de whitelist. Het doorvoeren van wijzigingen kan enkele seconden in beslag nemen.", "f2b_max_attempts": "Maximaal aantal pogingen", + "f2b_max_ban_time": "Maximaal verbanningstijd (s)", "f2b_netban_ipv4": "Voer de IPv4-subnetgrootte in waar de verbanning van kracht moet zijn (8-32)", "f2b_netban_ipv6": "Voer de IPv6-subnetgrootte in waar de verbanning van kracht moet zijn (8-128)", "f2b_parameters": "Fail2ban", diff --git a/data/web/templates/admin/tab-config-f2b.twig b/data/web/templates/admin/tab-config-f2b.twig index bbd3e367..c15fb72f 100644 --- a/data/web/templates/admin/tab-config-f2b.twig +++ b/data/web/templates/admin/tab-config-f2b.twig @@ -12,6 +12,14 @@ +
+ + +
+
+ + +
From 5bc3d93545f9f0d24773477022cf8fa0315983d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B6rn=20J=C3=B6rger?= Date: Tue, 21 Mar 2023 11:12:07 +0100 Subject: [PATCH 14/29] log exception of redis pubsub subscription --- data/Dockerfiles/netfilter/server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/Dockerfiles/netfilter/server.py b/data/Dockerfiles/netfilter/server.py index 0b0e2a41..4b6b3820 100644 --- a/data/Dockerfiles/netfilter/server.py +++ b/data/Dockerfiles/netfilter/server.py @@ -332,7 +332,7 @@ def watch(): logWarn('%s matched rule id %s (%s)' % (addr, rule_id, item['data'])) ban(addr) except Exception as ex: - logWarn('Error reading log line from pubsub') + logWarn('Error reading log line from pubsub: %s' % ex) quit_now = True exit_code = 2 From 9fd4aa93e9136f88a68f97f7ed6d55265f4c9450 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 21 Mar 2023 10:32:21 +0000 Subject: [PATCH 15/29] Update mailcow/rspamd Docker tag to v1.93 Signed-off-by: milkmaker --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index ad3053ae..d40933f8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -76,7 +76,7 @@ services: - clamd rspamd-mailcow: - image: mailcow/rspamd:1.92 + image: mailcow/rspamd:1.93 stop_grace_period: 30s depends_on: - dovecot-mailcow From 62f3603588ce9484d8e9faf30884c3e083b49829 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 22 Mar 2023 15:00:55 +0100 Subject: [PATCH 16/29] Update actions/stale action to v8 (#5143) Signed-off-by: milkmaker Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/close_old_issues_and_prs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/close_old_issues_and_prs.yml b/.github/workflows/close_old_issues_and_prs.yml index 64002617..21ab3a8e 100644 --- a/.github/workflows/close_old_issues_and_prs.yml +++ b/.github/workflows/close_old_issues_and_prs.yml @@ -14,7 +14,7 @@ jobs: pull-requests: write steps: - name: Mark/Close Stale Issues and Pull Requests 🗑️ - uses: actions/stale@v7.0.0 + uses: actions/stale@v8.0.0 with: repo-token: ${{ secrets.STALE_ACTION_PAT }} days-before-stale: 60 From cf3dc584d0390e05fe449306e516f941e8d8cbcc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 23 Mar 2023 14:18:29 +0000 Subject: [PATCH 17/29] Update dependency nextcloud/server to v25.0.5 Signed-off-by: milkmaker --- helper-scripts/nextcloud.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helper-scripts/nextcloud.sh b/helper-scripts/nextcloud.sh index 9377ddbb..262be218 100755 --- a/helper-scripts/nextcloud.sh +++ b/helper-scripts/nextcloud.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # renovate: datasource=github-releases depName=nextcloud/server versioning=semver extractVersion=^v(?.*)$ -NEXTCLOUD_VERSION=25.0.4 +NEXTCLOUD_VERSION=25.0.5 echo -ne "Checking prerequisites..." sleep 1 From e808e595eb4864c5beed87b3519195f1be1ad7e4 Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 24 Mar 2023 16:05:35 +0100 Subject: [PATCH 18/29] Update dependency composer/composer to v2.5.5 --- data/Dockerfiles/phpfpm/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/Dockerfiles/phpfpm/Dockerfile b/data/Dockerfiles/phpfpm/Dockerfile index ef50ab4b..937eec6c 100644 --- a/data/Dockerfiles/phpfpm/Dockerfile +++ b/data/Dockerfiles/phpfpm/Dockerfile @@ -12,7 +12,7 @@ ARG MEMCACHED_PECL_VERSION=3.2.0 # renovate: datasource=github-tags depName=phpredis/phpredis versioning=semver-coerced ARG REDIS_PECL_VERSION=5.3.7 # renovate: datasource=github-tags depName=composer/composer versioning=semver-coerced -ARG COMPOSER_VERSION=2.5.4 +ARG COMPOSER_VERSION=2.5.5 RUN apk add -U --no-cache autoconf \ aspell-dev \ From db2fb12837d95660680fc9eb5e84b22991abd161 Mon Sep 17 00:00:00 2001 From: Peter Date: Fri, 24 Mar 2023 16:08:19 +0100 Subject: [PATCH 19/29] Install sysvsem for Nextcloud 26 --- data/Dockerfiles/phpfpm/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/Dockerfiles/phpfpm/Dockerfile b/data/Dockerfiles/phpfpm/Dockerfile index 937eec6c..0ff47206 100644 --- a/data/Dockerfiles/phpfpm/Dockerfile +++ b/data/Dockerfiles/phpfpm/Dockerfile @@ -76,7 +76,7 @@ RUN apk add -U --no-cache autoconf \ --with-webp \ --with-xpm \ --with-avif \ - && docker-php-ext-install -j 4 exif gd gettext intl ldap opcache pcntl pdo pdo_mysql pspell soap sockets zip bcmath gmp \ + && docker-php-ext-install -j 4 exif gd gettext intl ldap opcache pcntl pdo pdo_mysql pspell soap sockets sysvsem zip bcmath gmp \ && docker-php-ext-configure imap --with-imap --with-imap-ssl \ && docker-php-ext-install -j 4 imap \ && curl --silent --show-error https://getcomposer.org/installer | php -- --version=${COMPOSER_VERSION} \ From 22cd12f37b28e2906839b9b6a596c28944e6d902 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 25 Mar 2023 18:48:22 +0000 Subject: [PATCH 20/29] Update dependency nextcloud/server to v26 Signed-off-by: milkmaker --- helper-scripts/nextcloud.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helper-scripts/nextcloud.sh b/helper-scripts/nextcloud.sh index 262be218..03913b64 100755 --- a/helper-scripts/nextcloud.sh +++ b/helper-scripts/nextcloud.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # renovate: datasource=github-releases depName=nextcloud/server versioning=semver extractVersion=^v(?.*)$ -NEXTCLOUD_VERSION=25.0.5 +NEXTCLOUD_VERSION=26.0.0 echo -ne "Checking prerequisites..." sleep 1 From 4021613059694356d1a5659c3ba0dc6759b35881 Mon Sep 17 00:00:00 2001 From: FreddleSpl0it Date: Tue, 28 Mar 2023 10:59:08 +0200 Subject: [PATCH 21/29] delete vmail_index when mbox is deleted --- data/Dockerfiles/dockerapi/dockerapi.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/data/Dockerfiles/dockerapi/dockerapi.py b/data/Dockerfiles/dockerapi/dockerapi.py index 9e699c22..6d3b1012 100644 --- a/data/Dockerfiles/dockerapi/dockerapi.py +++ b/data/Dockerfiles/dockerapi/dockerapi.py @@ -380,7 +380,12 @@ class DockerUtils: if 'maildir' in request_json: for container in self.docker_client.containers.list(filters={"id": container_id}): sane_name = re.sub(r'\W+', '', request_json['maildir']) - cmd = ["/bin/bash", "-c", "if [[ -d '/var/vmail/" + request_json['maildir'].replace("'", "'\\''") + "' ]]; then /bin/mv '/var/vmail/" + request_json['maildir'].replace("'", "'\\''") + "' '/var/vmail/_garbage/" + str(int(time.time())) + "_" + sane_name + "'; fi"] + vmail_name = request_json['maildir'].replace("'", "'\\''") + index_name = request_json['maildir'].split("/") + index_name = index_name[1].replace("'", "'\\''") + "@" + index_name[0].replace("'", "'\\''") + cmd_vmail = "if [[ -d '/var/vmail/" + vmail_name + "' ]]; then /bin/mv '/var/vmail/" + vmail_name + "' '/var/vmail/_garbage/" + str(int(time.time())) + "_" + sane_name + "'; fi" + cmd_vmail_index = "if [[ -d '/var/vmail_index/" + index_name + "' ]]; then /bin/mv '/var/vmail_index/" + index_name + "' '/var/vmail/_garbage/" + str(int(time.time())) + "_" + sane_name + "_index'; fi" + cmd = ["/bin/bash", "-c", cmd_vmail + " && " + cmd_vmail_index] maildir_cleanup = container.exec_run(cmd, user='vmail') return exec_run_handler('generic', maildir_cleanup) # api call: container_post - post_action: exec - cmd: rspamd - task: worker_password From 26c34b484a87e3690451567ab97cf096f4c8f4fd Mon Sep 17 00:00:00 2001 From: FreddleSpl0it Date: Tue, 28 Mar 2023 11:01:14 +0200 Subject: [PATCH 22/29] increase dockerapi image --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index b8b9a0d1..493b8877 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -510,7 +510,7 @@ services: - watchdog dockerapi-mailcow: - image: mailcow/dockerapi:2.01 + image: mailcow/dockerapi:2.02 security_opt: - label=disable restart: always From 67955779b03ee807a9cd3463159c774e7c89c4db Mon Sep 17 00:00:00 2001 From: DerLinkman Date: Tue, 28 Mar 2023 11:17:59 +0200 Subject: [PATCH 23/29] Fix broken pipe error in reset-admin.sh --- helper-scripts/mailcow-reset-admin.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helper-scripts/mailcow-reset-admin.sh b/helper-scripts/mailcow-reset-admin.sh index ee95d3e9..ea8a4a43 100755 --- a/helper-scripts/mailcow-reset-admin.sh +++ b/helper-scripts/mailcow-reset-admin.sh @@ -19,7 +19,7 @@ read -r -p "Are you sure you want to reset the mailcow administrator account? [y response=${response,,} # tolower if [[ "$response" =~ ^(yes|y)$ ]]; then echo -e "\nWorking, please wait..." - random=$( /dev/null | head -c${1:-16}) password=$(docker exec -it $(docker ps -qf name=dovecot-mailcow) doveadm pw -s SSHA256 -p ${random} | tr -d '\r') docker exec -it $(docker ps -qf name=mysql-mailcow) mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "DELETE FROM admin WHERE username='admin';" docker exec -it $(docker ps -qf name=mysql-mailcow) mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "DELETE FROM domain_admins WHERE username='admin';" From 4cd5f93cdfbced2627d3445775965a322599fb9b Mon Sep 17 00:00:00 2001 From: DerLinkman Date: Tue, 28 Mar 2023 11:22:49 +0200 Subject: [PATCH 24/29] Fixed broken pipe errors in nextcloud.sh --- helper-scripts/nextcloud.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/helper-scripts/nextcloud.sh b/helper-scripts/nextcloud.sh index 03913b64..71c9a73f 100755 --- a/helper-scripts/nextcloud.sh +++ b/helper-scripts/nextcloud.sh @@ -122,7 +122,7 @@ elif [[ ${NC_INSTALL} == "y" ]]; then && chmod +x ./data/web/nextcloud/occ echo -e "\033[33mCreating 'nextcloud' database...\033[0m" - NC_DBPASS=$( /dev/null | head -c 28) NC_DBUSER=nextcloud NC_DBNAME=nextcloud @@ -138,7 +138,7 @@ elif [[ ${NC_INSTALL} == "y" ]]; then echo "" echo -e "\033[33mInstalling Nextcloud...\033[0m" - ADMIN_NC_PASS=$( /dev/null | head -c 28) echo -ne "[1/4] Setting correct permissions for www-data" docker exec -it $(docker ps -f name=php-fpm-mailcow -q) /bin/bash -c "chown -R www-data:www-data /web/nextcloud" From 4336a99c6a3dbdb94195915f5949949dd8450f86 Mon Sep 17 00:00:00 2001 From: DerLinkman Date: Tue, 28 Mar 2023 11:40:00 +0200 Subject: [PATCH 25/29] [Nextcloud] Changed default X-Robots Tag behavior --- data/assets/nextcloud/nextcloud.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/assets/nextcloud/nextcloud.conf b/data/assets/nextcloud/nextcloud.conf index 3755c4a7..eda2c779 100644 --- a/data/assets/nextcloud/nextcloud.conf +++ b/data/assets/nextcloud/nextcloud.conf @@ -24,7 +24,7 @@ server { add_header X-Download-Options "noopen" always; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Permitted-Cross-Domain-Policies "none" always; - add_header X-Robots-Tag "none" always; + add_header X-Robots-Tag "noindex, nofollow" always; add_header X-XSS-Protection "1; mode=block" always; fastcgi_hide_header X-Powered-By; From e010f0814321cafe65be6c0e932df2fb99a2dd68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B6rn=20J=C3=B6rger?= Date: Wed, 29 Mar 2023 15:18:11 +0200 Subject: [PATCH 26/29] verify options after loading them, set defaults if options are missing or invalid --- data/Dockerfiles/netfilter/server.py | 35 +++++++++++++++++----------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/data/Dockerfiles/netfilter/server.py b/data/Dockerfiles/netfilter/server.py index 5533b4b3..2bf8b2b4 100644 --- a/data/Dockerfiles/netfilter/server.py +++ b/data/Dockerfiles/netfilter/server.py @@ -66,30 +66,37 @@ def refreshF2boptions(): global exit_code if not r.get('F2B_OPTIONS'): f2boptions = {} - f2boptions['ban_time'] = int - f2boptions['max_ban_time'] = int - f2boptions['ban_time_increment'] = bool - f2boptions['max_attempts'] = int - f2boptions['retry_window'] = int - f2boptions['netban_ipv4'] = int - f2boptions['netban_ipv6'] = int - f2boptions['ban_time'] = r.get('F2B_BAN_TIME') or 1800 - f2boptions['max_ban_time'] = r.get('F2B_MAX_BAN_TIME') or 10000 - f2boptions['ban_time_increment'] = r.get('F2B_BAN_TIME_INCREMENT') or True - f2boptions['max_attempts'] = r.get('F2B_MAX_ATTEMPTS') or 10 - f2boptions['retry_window'] = r.get('F2B_RETRY_WINDOW') or 600 - f2boptions['netban_ipv4'] = r.get('F2B_NETBAN_IPV4') or 32 - f2boptions['netban_ipv6'] = r.get('F2B_NETBAN_IPV6') or 128 + f2boptions['ban_time'] = r.get('F2B_BAN_TIME') + f2boptions['max_ban_time'] = r.get('F2B_MAX_BAN_TIME') + f2boptions['ban_time_increment'] = r.get('F2B_BAN_TIME_INCREMENT') + f2boptions['max_attempts'] = r.get('F2B_MAX_ATTEMPTS') + f2boptions['retry_window'] = r.get('F2B_RETRY_WINDOW') + f2boptions['netban_ipv4'] = r.get('F2B_NETBAN_IPV4') + f2boptions['netban_ipv6'] = r.get('F2B_NETBAN_IPV6') + verifyF2boptions(f2boptions) r.set('F2B_OPTIONS', json.dumps(f2boptions, ensure_ascii=False)) else: try: f2boptions = {} f2boptions = json.loads(r.get('F2B_OPTIONS')) + verifyF2boptions(f2boptions) except ValueError: print('Error loading F2B options: F2B_OPTIONS is not json') quit_now = True exit_code = 2 +def verifyF2boptions(f2boptions): + verifyF2boption(f2boptions,'ban_time', 1800) + verifyF2boption(f2boptions,'max_ban_time', 10000) + verifyF2boption(f2boptions,'ban_time_increment', True) + verifyF2boption(f2boptions,'max_attempts', 10) + verifyF2boption(f2boptions,'retry_window', 600) + verifyF2boption(f2boptions,'netban_ipv4', 32) + verifyF2boption(f2boptions,'netban_ipv6', 128) + +def verifyF2boption(f2boptions, f2boption, f2bdefault): + f2boptions[f2boption] = f2boptions[f2boption] if f2boption in f2boptions and f2boptions[f2boption] is not None else f2bdefault + def refreshF2bregex(): global f2bregex global quit_now From 096e2a41e96c981bccf4629d0df4803d5f756481 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thorbj=C3=B6rn=20J=C3=B6rger?= Date: Wed, 29 Mar 2023 17:09:25 +0200 Subject: [PATCH 27/29] Push verified options to redis after each check --- data/Dockerfiles/netfilter/server.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/data/Dockerfiles/netfilter/server.py b/data/Dockerfiles/netfilter/server.py index 2bf8b2b4..d0c652e2 100644 --- a/data/Dockerfiles/netfilter/server.py +++ b/data/Dockerfiles/netfilter/server.py @@ -64,8 +64,10 @@ def refreshF2boptions(): global f2boptions global quit_now global exit_code + + f2boptions = {} + if not r.get('F2B_OPTIONS'): - f2boptions = {} f2boptions['ban_time'] = r.get('F2B_BAN_TIME') f2boptions['max_ban_time'] = r.get('F2B_MAX_BAN_TIME') f2boptions['ban_time_increment'] = r.get('F2B_BAN_TIME_INCREMENT') @@ -73,18 +75,17 @@ def refreshF2boptions(): f2boptions['retry_window'] = r.get('F2B_RETRY_WINDOW') f2boptions['netban_ipv4'] = r.get('F2B_NETBAN_IPV4') f2boptions['netban_ipv6'] = r.get('F2B_NETBAN_IPV6') - verifyF2boptions(f2boptions) - r.set('F2B_OPTIONS', json.dumps(f2boptions, ensure_ascii=False)) else: try: - f2boptions = {} f2boptions = json.loads(r.get('F2B_OPTIONS')) - verifyF2boptions(f2boptions) except ValueError: print('Error loading F2B options: F2B_OPTIONS is not json') quit_now = True exit_code = 2 + verifyF2boptions(f2boptions) + r.set('F2B_OPTIONS', json.dumps(f2boptions, ensure_ascii=False)) + def verifyF2boptions(f2boptions): verifyF2boption(f2boptions,'ban_time', 1800) verifyF2boption(f2boptions,'max_ban_time', 10000) From 400939faf676af0c08940402d62339f173d1f17c Mon Sep 17 00:00:00 2001 From: FreddleSpl0it Date: Thu, 30 Mar 2023 08:44:38 +0200 Subject: [PATCH 28/29] [Netfilter] Update to 1.52 --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index db9c0241..63341865 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -425,7 +425,7 @@ services: - acme netfilter-mailcow: - image: mailcow/netfilter:1.51 + image: mailcow/netfilter:1.52 stop_grace_period: 30s depends_on: - dovecot-mailcow From f53ca24bb08ecd11188b4943d774816859aab0cc Mon Sep 17 00:00:00 2001 From: FreddleSpl0it Date: Thu, 30 Mar 2023 16:00:21 +0200 Subject: [PATCH 29/29] [SOGo] Update to 5.8.2 --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 63341865..a2d40cd8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -169,7 +169,7 @@ services: - phpfpm sogo-mailcow: - image: mailcow/sogo:1.115 + image: mailcow/sogo:1.116 environment: - DBNAME=${DBNAME} - DBUSER=${DBUSER}