1
0
mirror of https://github.com/mailcow/mailcow-dockerized.git synced 2026-06-26 08:14:16 +00:00

Compare commits

..

27 Commits

Author SHA1 Message Date
FreddleSpl0it 1f8b4679cc [Nignx] Update to 1.30.3 2026-06-25 12:17:37 +02:00
milkmaker 9e723e942d Translations update from Weblate (#7302)
* [Web] Updated lang.fr-fr.json

Co-authored-by: Romain Ayme <ayme.romain@hotmail.fr>

* [Web] Updated lang.si-si.json

Co-authored-by: Matjaž Tekavec <matjaz@moj-svet.si>

---------

Co-authored-by: Romain Ayme <ayme.romain@hotmail.fr>
Co-authored-by: Matjaž Tekavec <matjaz@moj-svet.si>
2026-06-20 13:57:15 +02:00
renovate[bot] 47e4552b44 Update actions/checkout action to v7 (#7300) 2026-06-19 08:34:02 +02:00
renovate[bot] 7e6c36dce1 Update alpine Docker tag to v3.24 (#7280) 2026-06-11 11:35:03 +02:00
FreddleSpl0it fa154c71f3 [PHP] Rebuild Image 2026-06-11 10:29:01 +02:00
FreddleSpl0it 83a045ed3e Merge pull request #7193 from mailcow/renovate/composer-composer-2.x
Update dependency composer/composer to v2.10.1
2026-06-11 10:07:19 +02:00
FreddleSpl0it 064817ac70 Merge pull request #7189 from mailcow/renovate/php-pecl-mail-mailparse-3.x
Update dependency php/pecl-mail-mailparse to v3.2.0
2026-06-11 10:06:49 +02:00
FreddleSpl0it 2bd7a24b8c Merge pull request #7212 from mailcow/mkuron-patch-mobileconfig
Escape generated password in mobileconfig
2026-06-11 10:05:17 +02:00
FreddleSpl0it ecc2462e4c Merge pull request #7267 from goodygh/7249-update-sogo
[SOGo] Update to 5.12.9
2026-06-11 10:04:30 +02:00
FreddleSpl0it 2d8db72d46 Merge pull request #7275 from Snafu/fix/admin-mailbox-tfa-missing
Fix force_tfa not available in mailbox template #7216
2026-06-11 10:03:39 +02:00
FreddleSpl0it 277a307fb9 [Web] Fix refresh SOGo view on mailbox deletion 2026-06-11 09:55:32 +02:00
FreddleSpl0it d455555621 Merge pull request #7277 from ibobgunardi/bobi/mailcow-7136-sogo-active-refresh
Refresh SOGo view after mailbox activation
2026-06-11 09:53:30 +02:00
FreddleSpl0it 9ea2ff1dff Merge pull request #7283 from mailcow/feat/update-metadata-exporter
[Rspamd] Migrate metadata_exporter to multipart formatter
2026-06-11 09:40:34 +02:00
FreddleSpl0it 24cc369d84 [Rspamd] Migrate metadata_exporter to multipart formatter 2026-06-11 09:34:27 +02:00
FreddleSpl0it 5f5367f2f9 Merge pull request #7172 from mailcow/dragoangel-patch-4
Update RSPAMD version to 4.1.0 in Dockerfile
2026-06-11 09:04:19 +02:00
milkmaker 03c31f825a update postscreen_access.cidr (#7269) 2026-06-09 12:20:53 +02:00
renovate[bot] c0050e8836 Update devops-infra/action-pull-request action to v1.3.0 (#7272) 2026-06-09 12:19:09 +02:00
Dmytro Alieksieiev 15891960f7 Update RSPAMD version to 4.1.0 2026-06-09 01:19:06 +02:00
Bobby cce02e2b15 Refresh SOGo view after mailbox activation 2026-06-08 00:01:43 +07:00
Snafu 0fafda696b Fix force_tfa not available in mailbox template #7216 2026-06-07 17:03:52 +02:00
renovate[bot] 843db5854c Update dependency composer/composer to v2.10.1
Signed-off-by: milkmaker <milkmaker@mailcow.de>
2026-06-04 11:04:42 +00:00
goodygh 23e4e4f373 [SOGo] Update to 5.12.9 2026-05-29 01:39:38 +02:00
Michael Kuron ffbc37a00c Escape generated password in mobileconfig
Escape ampersand, less than, greater than to avoid generating invalid XML.

Fixes #7171
2026-05-24 11:52:12 +02:00
renovate[bot] 104af58628 Update dependency php/pecl-mail-mailparse to v3.2.0
Signed-off-by: milkmaker <milkmaker@mailcow.de>
2026-05-14 18:33:03 +00:00
Dmitriy Alekseev b0873edb6a Update RSPAMD version in Dockerfile 2026-04-06 17:28:32 +02:00
Dmitriy Alekseev 694d751915 Update RSPAMD version in Dockerfile 2026-04-06 17:28:14 +02:00
Dmitriy Alekseev 08278a8be9 Update RSPAMD version to 4.0.0 in Dockerfile 2026-03-30 23:51:05 +02:00
21 changed files with 123 additions and 89 deletions
+1 -1
View File
@@ -27,7 +27,7 @@ jobs:
- "watchdog-mailcow" - "watchdog-mailcow"
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v7
- name: Setup Docker - name: Setup Docker
run: | run: |
curl -sSL https://get.docker.com/ | CHANNEL=stable sudo sh curl -sSL https://get.docker.com/ | CHANNEL=stable sudo sh
+2 -2
View File
@@ -8,11 +8,11 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v6 uses: actions/checkout@v7
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Run the Action - name: Run the Action
uses: devops-infra/action-pull-request@v1.2.1 uses: devops-infra/action-pull-request@v1.3.0
with: with:
github_token: ${{ secrets.PRTONIGHTLY_ACTION_PAT }} github_token: ${{ secrets.PRTONIGHTLY_ACTION_PAT }}
title: Automatic PR to nightly from ${{ github.event.repository.updated_at}} title: Automatic PR to nightly from ${{ github.event.repository.updated_at}}
+1 -1
View File
@@ -13,7 +13,7 @@ jobs:
packages: write packages: write
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v4 uses: docker/setup-qemu-action@v4
@@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v7
- name: Generate postscreen_access.cidr - name: Generate postscreen_access.cidr
run: | run: |
+1 -1
View File
@@ -1,4 +1,4 @@
FROM nginx:1.30.2-alpine FROM nginx:1.30.3-alpine
LABEL maintainer "The Infrastructure Company GmbH <info@servercow.de>" LABEL maintainer "The Infrastructure Company GmbH <info@servercow.de>"
ENV PIP_BREAK_SYSTEM_PACKAGES=1 ENV PIP_BREAK_SYSTEM_PACKAGES=1
+2 -2
View File
@@ -7,13 +7,13 @@ ARG APCU_PECL_VERSION=5.1.28
# renovate: datasource=github-tags depName=Imagick/imagick versioning=semver-coerced extractVersion=(?<version>.*)$ # renovate: datasource=github-tags depName=Imagick/imagick versioning=semver-coerced extractVersion=(?<version>.*)$
ARG IMAGICK_PECL_VERSION=3.8.1 ARG IMAGICK_PECL_VERSION=3.8.1
# renovate: datasource=github-tags depName=php/pecl-mail-mailparse versioning=semver-coerced extractVersion=^v(?<version>.*)$ # renovate: datasource=github-tags depName=php/pecl-mail-mailparse versioning=semver-coerced extractVersion=^v(?<version>.*)$
ARG MAILPARSE_PECL_VERSION=3.1.9 ARG MAILPARSE_PECL_VERSION=3.2.0
# renovate: datasource=github-tags depName=php-memcached-dev/php-memcached versioning=semver-coerced extractVersion=^v(?<version>.*)$ # renovate: datasource=github-tags depName=php-memcached-dev/php-memcached versioning=semver-coerced extractVersion=^v(?<version>.*)$
ARG MEMCACHED_PECL_VERSION=3.4.0 ARG MEMCACHED_PECL_VERSION=3.4.0
# renovate: datasource=github-tags depName=phpredis/phpredis versioning=semver-coerced extractVersion=(?<version>.*)$ # renovate: datasource=github-tags depName=phpredis/phpredis versioning=semver-coerced extractVersion=(?<version>.*)$
ARG REDIS_PECL_VERSION=6.3.0 ARG REDIS_PECL_VERSION=6.3.0
# renovate: datasource=github-tags depName=composer/composer versioning=semver-coerced extractVersion=(?<version>.*)$ # renovate: datasource=github-tags depName=composer/composer versioning=semver-coerced extractVersion=(?<version>.*)$
ARG COMPOSER_VERSION=2.9.5 ARG COMPOSER_VERSION=2.10.1
RUN apk add -U --no-cache autoconf \ RUN apk add -U --no-cache autoconf \
aspell-dev \ aspell-dev \
+1 -1
View File
@@ -2,7 +2,7 @@ FROM debian:trixie-slim
LABEL maintainer="The Infrastructure Company GmbH <info@servercow.de>" LABEL maintainer="The Infrastructure Company GmbH <info@servercow.de>"
ARG DEBIAN_FRONTEND=noninteractive ARG DEBIAN_FRONTEND=noninteractive
ARG RSPAMD_VER=rspamd_3.14.3-1~236eb65 ARG RSPAMD_VER=rspamd_4.1.0-1~e2b0b18
ARG CODENAME=trixie ARG CODENAME=trixie
ENV LC_ALL=C ENV LC_ALL=C
+3 -3
View File
@@ -1,6 +1,6 @@
# SOGo built from source to enable security patch application # SOGo built from source to enable security patch application
# Repository: https://github.com/Alinto/sogo # Repository: https://github.com/Alinto/sogo
# Version: SOGo-5.12.8 # Version: SOGo-5.12.9
# #
# Applied security patches: # Applied security patches:
# - # -
@@ -12,8 +12,8 @@ FROM debian:bookworm
LABEL maintainer="The Infrastructure Company GmbH <info@servercow.de>" LABEL maintainer="The Infrastructure Company GmbH <info@servercow.de>"
ARG DEBIAN_FRONTEND=noninteractive ARG DEBIAN_FRONTEND=noninteractive
ARG SOGO_VERSION=SOGo-5.12.8 ARG SOGO_VERSION=SOGo-5.12.9
ARG SOPE_VERSION=SOPE-5.12.8 ARG SOPE_VERSION=SOPE-5.12.9
# Security patches to apply (space-separated commit hashes) # Security patches to apply (space-separated commit hashes)
ARG SOGO_SECURITY_PATCHES="" ARG SOGO_SECURITY_PATCHES=""
# renovate: datasource=github-releases depName=tianon/gosu versioning=semver-coerced extractVersion=^(?<version>.*)$ # renovate: datasource=github-releases depName=tianon/gosu versioning=semver-coerced extractVersion=^(?<version>.*)$
@@ -3,8 +3,7 @@ rules {
backend = "http"; backend = "http";
url = "http://nginx:9081/pipe.php"; url = "http://nginx:9081/pipe.php";
selector = "reject_no_global_bl"; selector = "reject_no_global_bl";
formatter = "default"; formatter = "multipart";
meta_headers = true;
} }
RLINFO { RLINFO {
backend = "http"; backend = "http";
@@ -16,8 +15,7 @@ rules {
backend = "http"; backend = "http";
url = "http://nginx:9081/pushover.php"; url = "http://nginx:9081/pushover.php";
selector = "mailcow_rcpt"; selector = "mailcow_rcpt";
formatter = "json"; formatter = "multipart";
meta_headers = true;
} }
} }
+27 -32
View File
@@ -32,47 +32,42 @@ function parse_email($email) {
$a = strrpos($email, '@'); $a = strrpos($email, '@');
return array('local' => substr($email, 0, $a), 'domain' => substr(substr($email, $a), 1)); return array('local' => substr($email, 0, $a), 'domain' => substr(substr($email, $a), 1));
} }
if (!function_exists('getallheaders')) { // rspamd metadata_exporter (multipart formatter):
function getallheaders() { // - $_POST['metadata'] JSON with the rspamd metadata
if (!is_array($_SERVER)) { // - $_FILES['message'] raw RFC822 message
return array(); if (empty($_POST['metadata']) || !isset($_FILES['message']) || $_FILES['message']['error'] !== UPLOAD_ERR_OK) {
} error_log("QUARANTINE: missing multipart parts from rspamd" . PHP_EOL);
$headers = array(); http_response_code(400);
foreach ($_SERVER as $name => $value) { exit;
if (substr($name, 0, 5) == 'HTTP_') {
$headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
}
}
return $headers;
}
} }
$raw_data_content = file_get_contents('php://input'); $meta = json_decode($_POST['metadata'], true);
if (!is_array($meta)) {
error_log("QUARANTINE: cannot decode metadata JSON" . PHP_EOL);
http_response_code(400);
exit;
}
$raw_data_content = file_get_contents($_FILES['message']['tmp_name']);
$raw_data = mb_convert_encoding($raw_data_content, 'HTML-ENTITIES', "UTF-8"); $raw_data = mb_convert_encoding($raw_data_content, 'HTML-ENTITIES', "UTF-8");
$headers = getallheaders(); $raw_size = (int)$_FILES['message']['size'];
$qid = $headers['X-Rspamd-Qid']; $qid = $meta['qid'] ?? 'unknown';
$fuzzy = $headers['X-Rspamd-Fuzzy']; $subject = iconv_mime_decode($meta['subject'] ?? '');
$subject = iconv_mime_decode($headers['X-Rspamd-Subject']); $score = $meta['score'] ?? 0;
$score = $headers['X-Rspamd-Score']; $rcpts = $meta['rcpt'] ?? array();
$rcpts = $headers['X-Rspamd-Rcpt']; $user = $meta['user'] ?? 'unknown';
$user = $headers['X-Rspamd-User']; $ip = $meta['ip'] ?? 'unknown';
$ip = $headers['X-Rspamd-Ip']; $action = $meta['action'] ?? 'no action';
$action = $headers['X-Rspamd-Action']; $sender = $meta['from'] ?? '';
$sender = $headers['X-Rspamd-From']; $symbols = json_encode($meta['symbols'] ?? array());
$symbols = $headers['X-Rspamd-Symbols']; $fuzzy = json_encode(is_array($meta['fuzzy'] ?? null) ? $meta['fuzzy'] : array());
$raw_size = (int)$_SERVER['CONTENT_LENGTH'];
if (empty($sender)) { if (empty($sender)) {
error_log("QUARANTINE: Unknown sender, assuming empty-env-from@localhost" . PHP_EOL); error_log("QUARANTINE: Unknown sender, assuming empty-env-from@localhost" . PHP_EOL);
$sender = 'empty-env-from@localhost'; $sender = 'empty-env-from@localhost';
} }
if ($fuzzy == 'unknown') {
$fuzzy = '[]';
}
try { try {
$max_size = (int)$redis->Get('Q_MAX_SIZE'); $max_size = (int)$redis->Get('Q_MAX_SIZE');
if (($max_size * 1048576) < $raw_size) { if (($max_size * 1048576) < $raw_size) {
@@ -94,7 +89,7 @@ catch (RedisException $e) {
$rcpt_final_mailboxes = array(); $rcpt_final_mailboxes = array();
// Loop through all rcpts // Loop through all rcpts
foreach (json_decode($rcpts, true) as $rcpt) { foreach ($rcpts as $rcpt) {
// Remove tag // Remove tag
$rcpt = preg_replace('/^(.*?)\+.*(@.*)$/', '$1$2', $rcpt); $rcpt = preg_replace('/^(.*?)\+.*(@.*)$/', '$1$2', $rcpt);
+22 -26
View File
@@ -32,50 +32,46 @@ function parse_email($email) {
$a = strrpos($email, '@'); $a = strrpos($email, '@');
return array('local' => substr($email, 0, $a), 'domain' => substr(substr($email, $a), 1)); return array('local' => substr($email, 0, $a), 'domain' => substr(substr($email, $a), 1));
} }
if (!function_exists('getallheaders')) { // rspamd metadata_exporter (multipart formatter): metadata JSON arrives as $_POST['metadata'].
function getallheaders() { if (empty($_POST['metadata'])) {
if (!is_array($_SERVER)) { error_log("NOTIFY: missing metadata part from rspamd" . PHP_EOL);
return array(); http_response_code(400);
} exit;
$headers = array();
foreach ($_SERVER as $name => $value) {
if (substr($name, 0, 5) == 'HTTP_') {
$headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
}
}
return $headers;
}
} }
$headers = getallheaders(); $meta = json_decode($_POST['metadata'], true);
$json_body = json_decode(file_get_contents('php://input')); if (!is_array($meta)) {
error_log("NOTIFY: cannot decode metadata JSON" . PHP_EOL);
http_response_code(400);
exit;
}
$qid = $headers['X-Rspamd-Qid']; $qid = $meta['qid'] ?? 'unknown';
$rcpts = $headers['X-Rspamd-Rcpt']; $rcpts = $meta['rcpt'] ?? array();
$sender = $headers['X-Rspamd-From']; $sender = $meta['from'] ?? '';
$ip = $headers['X-Rspamd-Ip']; $ip = $meta['ip'] ?? 'unknown';
$subject = iconv_mime_decode($headers['X-Rspamd-Subject']); $subject = iconv_mime_decode($meta['subject'] ?? '');
$messageid= $json_body->message_id; $messageid= $meta['message_id'] ?? '';
$priority = 0; $priority = 0;
$symbols_array = json_decode($headers['X-Rspamd-Symbols'], true); $symbols_array = $meta['symbols'] ?? array();
if (is_array($symbols_array)) { if (is_array($symbols_array)) {
foreach ($symbols_array as $symbol) { foreach ($symbols_array as $symbol) {
if ($symbol['name'] == 'HAS_X_PRIO_ONE') { if (($symbol['name'] ?? null) == 'HAS_X_PRIO_ONE') {
$priority = 1; $priority = 1;
break; break;
} }
} }
} }
$sender_address = $json_body->header_from[0]; $sender_address = $meta['header_from'][0] ?? '';
$sender_name = '-'; $sender_name = '-';
if (preg_match('/(?<name>.*?)<(?<address>.*?)>/i', $sender_address, $matches)) { if (preg_match('/(?<name>.*?)<(?<address>.*?)>/i', $sender_address, $matches)) {
$sender_address = $matches['address']; $sender_address = $matches['address'];
$sender_name = trim($matches['name'], '"\' '); $sender_name = trim($matches['name'], '"\' ');
} }
$to_address = $json_body->header_to[0]; $to_address = $meta['header_to'][0] ?? '';
$to_name = '-'; $to_name = '-';
if (preg_match('/(?<name>.*?)<(?<address>.*?)>/i', $to_address, $matches)) { if (preg_match('/(?<name>.*?)<(?<address>.*?)>/i', $to_address, $matches)) {
$to_address = $matches['address']; $to_address = $matches['address'];
@@ -85,7 +81,7 @@ if (preg_match('/(?<name>.*?)<(?<address>.*?)>/i', $to_address, $matches)) {
$rcpt_final_mailboxes = array(); $rcpt_final_mailboxes = array();
// Loop through all rcpts // Loop through all rcpts
foreach (json_decode($rcpts, true) as $rcpt) { foreach ($rcpts as $rcpt) {
// Remove tag // Remove tag
$rcpt = preg_replace('/^(.*?)\+.*(@.*)$/', '$1$2', $rcpt); $rcpt = preg_replace('/^(.*?)\+.*(@.*)$/', '$1$2', $rcpt);
+12
View File
@@ -1072,6 +1072,7 @@ paths:
password2: "*" password2: "*"
quota: "3072" quota: "3072"
force_pw_update: "1" force_pw_update: "1"
force_tfa: "1"
tls_enforce_in: "1" tls_enforce_in: "1"
tls_enforce_out: "1" tls_enforce_out: "1"
tags: ["tag1", "tag2"] tags: ["tag1", "tag2"]
@@ -1118,6 +1119,7 @@ paths:
password2: atedismonsin password2: atedismonsin
quota: "3072" quota: "3072"
force_pw_update: "1" force_pw_update: "1"
force_tfa: "1"
tls_enforce_in: "1" tls_enforce_in: "1"
tls_enforce_out: "1" tls_enforce_out: "1"
tags: ["tag1", "tag2"] tags: ["tag1", "tag2"]
@@ -1151,6 +1153,9 @@ paths:
force_pw_update: force_pw_update:
description: forces the user to update its password on first login description: forces the user to update its password on first login
type: boolean type: boolean
force_tfa:
description: force 2FA enrollment at login
type: boolean
tls_enforce_in: tls_enforce_in:
description: force inbound email tls encryption description: force inbound email tls encryption
type: boolean type: boolean
@@ -3414,6 +3419,7 @@ paths:
- mailbox - mailbox
- active: "1" - active: "1"
force_pw_update: "0" force_pw_update: "0"
force_tfa: "0"
name: Full name name: Full name
password: "*" password: "*"
password2: "*" password2: "*"
@@ -3464,6 +3470,7 @@ paths:
attr: attr:
active: "1" active: "1"
force_pw_update: "0" force_pw_update: "0"
force_tfa: "0"
name: Full name name: Full name
authsource: mailcow authsource: mailcow
password: "" password: ""
@@ -3487,6 +3494,9 @@ paths:
force_pw_update: force_pw_update:
description: force user to change password on next login description: force user to change password on next login
type: boolean type: boolean
force_tfa:
description: force 2FA enrollment at login
type: boolean
name: name:
description: Full name of the mailbox user description: Full name of the mailbox user
type: string type: string
@@ -4881,6 +4891,7 @@ paths:
- active: "1" - active: "1"
attributes: attributes:
force_pw_update: "0" force_pw_update: "0"
force_tfa: "0"
mailbox_format: "maildir:" mailbox_format: "maildir:"
quarantine_notification: never quarantine_notification: never
sogo_access: "1" sogo_access: "1"
@@ -5805,6 +5816,7 @@ paths:
- active: "1" - active: "1"
attributes: attributes:
force_pw_update: "0" force_pw_update: "0"
force_tfa: "0"
mailbox_format: "maildir:" mailbox_format: "maildir:"
quarantine_notification: never quarantine_notification: never
sogo_access: "1" sogo_access: "1"
+1 -2
View File
@@ -3505,7 +3505,6 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
// Track affected mailboxes for SOGo update // Track affected mailboxes for SOGo update
$update_sogo_mailboxes[] = $username; $update_sogo_mailboxes[] = $username;
} }
return true;
break; break;
case 'mailbox_rename': case 'mailbox_rename':
$domain = $_data['domain']; $domain = $_data['domain'];
@@ -3828,6 +3827,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$attr["rl_frame"] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : $is_now['rl_frame']; $attr["rl_frame"] = (!empty($_data['rl_frame'])) ? $_data['rl_frame'] : $is_now['rl_frame'];
$attr["rl_value"] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : $is_now['rl_value']; $attr["rl_value"] = (!empty($_data['rl_value'])) ? $_data['rl_value'] : $is_now['rl_value'];
$attr["force_pw_update"] = isset($_data['force_pw_update']) ? intval($_data['force_pw_update']) : $is_now['force_pw_update']; $attr["force_pw_update"] = isset($_data['force_pw_update']) ? intval($_data['force_pw_update']) : $is_now['force_pw_update'];
$attr["force_tfa"] = isset($_data['force_tfa']) ? intval($_data['force_tfa']) : $is_now['force_tfa'];
$attr["sogo_access"] = isset($_data['sogo_access']) ? intval($_data['sogo_access']) : $is_now['sogo_access']; $attr["sogo_access"] = isset($_data['sogo_access']) ? intval($_data['sogo_access']) : $is_now['sogo_access'];
$attr["active"] = isset($_data['active']) ? intval($_data['active']) : $is_now['active']; $attr["active"] = isset($_data['active']) ? intval($_data['active']) : $is_now['active'];
$attr["tls_enforce_in"] = isset($_data['tls_enforce_in']) ? intval($_data['tls_enforce_in']) : $is_now['tls_enforce_in']; $attr["tls_enforce_in"] = isset($_data['tls_enforce_in']) ? intval($_data['tls_enforce_in']) : $is_now['tls_enforce_in'];
@@ -6127,7 +6127,6 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
// Track affected mailboxes for SOGo update // Track affected mailboxes for SOGo update
$update_sogo_mailboxes[] = $username; $update_sogo_mailboxes[] = $username;
} }
return true;
break; break;
case 'mailbox_templates': case 'mailbox_templates':
if ($_SESSION['mailcow_cc_role'] != "admin") { if ($_SESSION['mailcow_cc_role'] != "admin") {
+11
View File
@@ -424,6 +424,11 @@ $(document).ready(function() {
} else { } else {
$('#force_pw_update').prop('checked', false); $('#force_pw_update').prop('checked', false);
} }
if (template.force_tfa == 1){
$('#force_tfa').prop('checked', true);
} else {
$('#force_tfa').prop('checked', false);
}
if (template.sogo_access == 1){ if (template.sogo_access == 1){
$('#sogo_access').prop('checked', true); $('#sogo_access').prop('checked', true);
} else { } else {
@@ -1242,6 +1247,7 @@ jQuery(function($){
item.attributes.eas_access = '<i class="text-' + (item.attributes.eas_access == 1 ? 'success' : 'danger') + ' bi bi-' + (item.attributes.eas_access == 1 ? 'check-lg' : 'x-lg') + '"><span class="sorting-value">' + (item.attributes.eas_access == 1 ? '1' : '0') + '</span></i>'; item.attributes.eas_access = '<i class="text-' + (item.attributes.eas_access == 1 ? 'success' : 'danger') + ' bi bi-' + (item.attributes.eas_access == 1 ? 'check-lg' : 'x-lg') + '"><span class="sorting-value">' + (item.attributes.eas_access == 1 ? '1' : '0') + '</span></i>';
item.attributes.dav_access = '<i class="text-' + (item.attributes.dav_access == 1 ? 'success' : 'danger') + ' bi bi-' + (item.attributes.dav_access == 1 ? 'check-lg' : 'x-lg') + '"><span class="sorting-value">' + (item.attributes.dav_access == 1 ? '1' : '0') + '</span></i>'; item.attributes.dav_access = '<i class="text-' + (item.attributes.dav_access == 1 ? 'success' : 'danger') + ' bi bi-' + (item.attributes.dav_access == 1 ? 'check-lg' : 'x-lg') + '"><span class="sorting-value">' + (item.attributes.dav_access == 1 ? '1' : '0') + '</span></i>';
item.attributes.sogo_access = '<i class="text-' + (item.attributes.sogo_access == 1 ? 'success' : 'danger') + ' bi bi-' + (item.attributes.sogo_access == 1 ? 'check-lg' : 'x-lg') + '"><span class="sorting-value">' + (item.attributes.sogo_access == 1 ? '1' : '0') + '</span></i>'; item.attributes.sogo_access = '<i class="text-' + (item.attributes.sogo_access == 1 ? 'success' : 'danger') + ' bi bi-' + (item.attributes.sogo_access == 1 ? 'check-lg' : 'x-lg') + '"><span class="sorting-value">' + (item.attributes.sogo_access == 1 ? '1' : '0') + '</span></i>';
item.attributes.force_tfa = '<i class="text-' + (item.attributes.force_tfa == 1 ? 'success' : 'danger') + ' bi bi-' + (item.attributes.force_tfa == 1 ? 'check-lg' : 'x-lg') + '"><span class="sorting-value">' + (item.attributes.force_tfa == 1 ? '1' : '0') + '</span></i>';
if (item.attributes.quarantine_notification === 'never') { if (item.attributes.quarantine_notification === 'never') {
item.attributes.quarantine_notification = lang.never; item.attributes.quarantine_notification = lang.never;
} else if (item.attributes.quarantine_notification === 'hourly') { } else if (item.attributes.quarantine_notification === 'hourly') {
@@ -1385,6 +1391,11 @@ jQuery(function($){
return 1==data?'<i class="bi bi-check-lg"></i>':'<i class="bi bi-x-lg"></i>'; return 1==data?'<i class="bi bi-check-lg"></i>':'<i class="bi bi-x-lg"></i>';
} }
}, },
{
title: lang.force_tfa,
data: 'attributes.force_tfa',
defaultContent: ''
},
{ {
title: lang_edit.ratelimit, title: lang_edit.ratelimit,
data: 'attributes.ratelimit', data: 'attributes.ratelimit',
+1
View File
@@ -929,6 +929,7 @@
"filters": "Filters", "filters": "Filters",
"fname": "Full name", "fname": "Full name",
"force_pw_update": "Force password update at next login", "force_pw_update": "Force password update at next login",
"force_tfa": "TFA",
"gal": "Global Address List", "gal": "Global Address List",
"goto_ham": "Learn as <b>ham</b>", "goto_ham": "Learn as <b>ham</b>",
"goto_spam": "Learn as <b>spam</b>", "goto_spam": "Learn as <b>spam</b>",
+17 -6
View File
@@ -111,7 +111,8 @@
"app_passwd_protocols": "Protocoles autorisés pour le mot de passe de l'application", "app_passwd_protocols": "Protocoles autorisés pour le mot de passe de l'application",
"dry": "Simuler la synchronisation", "dry": "Simuler la synchronisation",
"internal": "Interne", "internal": "Interne",
"internal_info": "Les alias internes sont accessibles uniquement depuis le domaine ou les alias du domaine." "internal_info": "Les alias internes sont accessibles uniquement depuis le domaine ou les alias du domaine.",
"sender_allowed": "Autoriser l'envoi sous cet alias"
}, },
"admin": { "admin": {
"access": "Accès", "access": "Accès",
@@ -556,7 +557,9 @@
"max_age_invalid": "L'âge maximum %s est invalide", "max_age_invalid": "L'âge maximum %s est invalide",
"mode_invalid": "Le mode %s est invalide", "mode_invalid": "Le mode %s est invalide",
"mx_invalid": "L'enregistrement MX %s est invalide", "mx_invalid": "L'enregistrement MX %s est invalide",
"version_invalid": "La version %s est invalide" "version_invalid": "La version %s est invalide",
"tfa_removal_blocked": "Lauthentification à deux facteurs ne peut pas être supprimée, car elle est requise pour votre compte.",
"quarantine_category_invalid": "La catégorie de quarantaine doit être lune des suivantes : add_header, reject, all\""
}, },
"debug": { "debug": {
"chart_this_server": "Graphique (ce serveur)", "chart_this_server": "Graphique (ce serveur)",
@@ -755,7 +758,9 @@
"mta_sts_info": "<a href='https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol#SMTP_MTA_Strict_Transport_Security' target='_blank'>MTA-STS</a> est un standard qui oblige la délivrance des courriels entre les serveurs de courriels à utiliser TLS avec des certificats valides. <br>Il est utilisé quand <a target='_blank' href='https://en.wikipedia.org/wiki/DNS-based_Authentication_of_Named_Entities'>DANE</a> n'est pas possible à cause d'un manque ou d'un non support de DNSSEC.<br><b>Note</b> : Si le domaine du destinataire supporte DANE avec DNSSEC, DANE est <b>toujours</b> préféré MTA-STS sert seulement en secours.", "mta_sts_info": "<a href='https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol#SMTP_MTA_Strict_Transport_Security' target='_blank'>MTA-STS</a> est un standard qui oblige la délivrance des courriels entre les serveurs de courriels à utiliser TLS avec des certificats valides. <br>Il est utilisé quand <a target='_blank' href='https://en.wikipedia.org/wiki/DNS-based_Authentication_of_Named_Entities'>DANE</a> n'est pas possible à cause d'un manque ou d'un non support de DNSSEC.<br><b>Note</b> : Si le domaine du destinataire supporte DANE avec DNSSEC, DANE est <b>toujours</b> préféré MTA-STS sert seulement en secours.",
"mta_sts_mode_info": "Il y a trois modes parmi lesquels choisir :<ul><li><em>testing</em> la politique est seulement surveillée, les violations n'ont pas d'impact.</li><li><em>enforce</em> la politique est appliquée strictement, les connexions sans TLS valide sont rejetées.</li><li><em>none</em> la politique est publiée mais non appliquée.</li></ul>", "mta_sts_mode_info": "Il y a trois modes parmi lesquels choisir :<ul><li><em>testing</em> la politique est seulement surveillée, les violations n'ont pas d'impact.</li><li><em>enforce</em> la politique est appliquée strictement, les connexions sans TLS valide sont rejetées.</li><li><em>none</em> la politique est publiée mais non appliquée.</li></ul>",
"mta_sts_max_age_info": "Durée en secondes pendant laquelle les serveurs de courriel peuvent mettre en cache cette politique avant de revérifier.", "mta_sts_max_age_info": "Durée en secondes pendant laquelle les serveurs de courriel peuvent mettre en cache cette politique avant de revérifier.",
"mta_sts_mx_info": "Autoriser l'envoi uniquement aux noms d'hôtes des serveurs de courriels indiqués explicitement ; le MTA émetteur vérifie si le nom d'hôte DNS du MX correspond à la liste de la politique, et autorise la délivrance seulement avec un certificat TLS valide (protège contre le MITM)." "mta_sts_mx_info": "Autoriser l'envoi uniquement aux noms d'hôtes des serveurs de courriels indiqués explicitement ; le MTA émetteur vérifie si le nom d'hôte DNS du MX correspond à la liste de la politique, et autorise la délivrance seulement avec un certificat TLS valide (protège contre le MITM).",
"sender_allowed": "Autoriser l'envoi sous cet alias",
"sender_allowed_info": "Si cette option est désactivée, cet alias peut uniquement recevoir des courriels. Utilisez les ACL dexpéditeur pour autoriser certaines boîtes aux lettres à envoyer des messages via cet alias."
}, },
"footer": { "footer": {
"cancel": "Annuler", "cancel": "Annuler",
@@ -988,7 +993,8 @@
"recipient": "Destinataire", "recipient": "Destinataire",
"open_logs": "Afficher les journaux", "open_logs": "Afficher les journaux",
"iam": "Fournisseur d'identité", "iam": "Fournisseur d'identité",
"internal": "Interne" "internal": "Interne",
"force_tfa": "TFA"
}, },
"oauth2": { "oauth2": {
"access_denied": "Veuillez vous connecter en tant que propriétaire de la boîte de réception pour accorder laccès via Oauth2.", "access_denied": "Veuillez vous connecter en tant que propriétaire de la boîte de réception pour accorder laccès via Oauth2.",
@@ -1189,7 +1195,11 @@
"yubi_otp": "Authentification OTP Yubico", "yubi_otp": "Authentification OTP Yubico",
"authenticators": "Authentificateurs", "authenticators": "Authentificateurs",
"u2f_deprecated_important": "Veuillez enregistrer votre clé dans le panneau d'administration avec la nouvelle méthode WebAuthn.", "u2f_deprecated_important": "Veuillez enregistrer votre clé dans le panneau d'administration avec la nouvelle méthode WebAuthn.",
"u2f_deprecated": "Il semble que votre clé ait été enregistrée à l'aide de la méthode U2F obsolète. Nous allons désactiver l'authentification à deux facteurs pour vous et supprimer votre clé." "u2f_deprecated": "Il semble que votre clé ait été enregistrée à l'aide de la méthode U2F obsolète. Nous allons désactiver l'authentification à deux facteurs pour vous et supprimer votre clé.",
"force_tfa": "Imposer l'authentification à deux facteurs lors de la connexion",
"force_tfa_info": "Lutilisateur doit configurer lauthentification à deux facteurs avant de pouvoir accéder à linterface.",
"setup_title": "Authentification à deux facteurs requise",
"setup_required": "Votre compte nécessite lauthentification à deux facteurs. Veuillez configurer une méthode 2FA pour continuer."
}, },
"fido2": { "fido2": {
"set_fn": "Définir un nom", "set_fn": "Définir un nom",
@@ -1378,7 +1388,8 @@
"forever": "Pour toujours", "forever": "Pour toujours",
"spam_aliases_info": "Un alias de spam est une adresse de courriel temporaire qui peut être utilisée pour protéger les véritables adresses de courriel. <br> De manière optionnelle, une durée d'expiration peut être définie afin que l'alias soit automatiquement désactivé après la période définie, éliminant ainsi les adresses étant abusées ou ayant fuité.", "spam_aliases_info": "Un alias de spam est une adresse de courriel temporaire qui peut être utilisée pour protéger les véritables adresses de courriel. <br> De manière optionnelle, une durée d'expiration peut être définie afin que l'alias soit automatiquement désactivé après la période définie, éliminant ainsi les adresses étant abusées ou ayant fuité.",
"authentication": "Authentification", "authentication": "Authentification",
"protocols": "Protocoles" "protocols": "Protocoles",
"pw_update_required": "Votre compte nécessite un changement de mot de passe. Veuillez définir un nouveau mot de passe pour continuer."
}, },
"warning": { "warning": {
"cannot_delete_self": "Impossible de supprimer lutilisateur connecté", "cannot_delete_self": "Impossible de supprimer lutilisateur connecté",
+2 -1
View File
@@ -1001,7 +1001,8 @@
"weekly": "Tedensko", "weekly": "Tedensko",
"sieve_info": "Na uporabnika lahko shranite več filtrov, vendar je lahko hkrati aktiven le en predfilter in en postfilter.<br>\nVsak filter bo obdelan v opisanem vrstnem redu. Niti neuspešen skript niti izdan ukaz »keep;« ne bosta ustavila obdelave nadaljnjih skript. Spremembe globalnih skriptov sita bodo sprožile ponovni zagon Dovecota.<br><br>Globalni predfilter sita &#8226; Predfilter &#8226; Uporabniški skripti &#8226; Postfilter &#8226; Globalni postfilter sita", "sieve_info": "Na uporabnika lahko shranite več filtrov, vendar je lahko hkrati aktiven le en predfilter in en postfilter.<br>\nVsak filter bo obdelan v opisanem vrstnem redu. Niti neuspešen skript niti izdan ukaz »keep;« ne bosta ustavila obdelave nadaljnjih skript. Spremembe globalnih skriptov sita bodo sprožile ponovni zagon Dovecota.<br><br>Globalni predfilter sita &#8226; Predfilter &#8226; Uporabniški skripti &#8226; Postfilter &#8226; Globalni postfilter sita",
"tls_policy_maps_info": "Ta preslikava pravilnikov preglasi pravila odhodnega prenosa TLS neodvisno od uporabnikovih nastavitev pravilnikov TLS.<br>\n Za več informacij preverite <a href=\"http://www.postfix.org/postconf.5.html#smtp_tls_policy_maps\" target=\"_blank\">dokumentacijo »smtp_tls_policy_maps«</a>.", "tls_policy_maps_info": "Ta preslikava pravilnikov preglasi pravila odhodnega prenosa TLS neodvisno od uporabnikovih nastavitev pravilnikov TLS.<br>\n Za več informacij preverite <a href=\"http://www.postfix.org/postconf.5.html#smtp_tls_policy_maps\" target=\"_blank\">dokumentacijo »smtp_tls_policy_maps«</a>.",
"internal": "Notranje" "internal": "Notranje",
"force_tfa": "TFA"
}, },
"fido2": { "fido2": {
"known_ids": "Znani ID-ji", "known_ids": "Znani ID-ji",
+1
View File
@@ -65,6 +65,7 @@ if (isset($_GET['app_password'])) {
$attr['protocols'][] = 'dav_access'; $attr['protocols'][] = 'dav_access';
} }
app_passwd("add", $attr); app_passwd("add", $attr);
$password = htmlspecialchars($password, ENT_NOQUOTES);
} else { } else {
$app_password = false; $app_password = false;
} }
@@ -8,6 +8,7 @@
<input type="hidden" value="default" name="sender_acl"> <input type="hidden" value="default" name="sender_acl">
<input type="hidden" value="0" name="force_pw_update"> <input type="hidden" value="0" name="force_pw_update">
<input type="hidden" value="0" name="force_tfa">
<input type="hidden" value="0" name="sogo_access"> <input type="hidden" value="0" name="sogo_access">
<input type="hidden" value="0" name="protocol_access"> <input type="hidden" value="0" name="protocol_access">
@@ -165,6 +166,14 @@
</div> </div>
</div> </div>
</div> </div>
<div class="row">
<div class="offset-sm-2 col-sm-10">
<div class="form-check">
<label><input type="checkbox" class="form-check-input" value="1" name="force_tfa" id="force_tfa"{% if template.attributes.force_tfa == '1' %} checked{% endif %}> {{ lang.tfa.force_tfa }}</label>
<small class="text-muted">{{ lang.tfa.force_tfa_info }}</small>
</div>
</div>
</div>
{% if not skip_sogo %} {% if not skip_sogo %}
<div class="row"> <div class="row">
<div class="offset-sm-2 col-sm-10"> <div class="offset-sm-2 col-sm-10">
+4 -4
View File
@@ -84,7 +84,7 @@ services:
- clamd - clamd
rspamd-mailcow: rspamd-mailcow:
image: ghcr.io/mailcow/rspamd:3.14.3-1 image: ghcr.io/mailcow/rspamd:4.1.0-1
stop_grace_period: 30s stop_grace_period: 30s
depends_on: depends_on:
- dovecot-mailcow - dovecot-mailcow
@@ -117,7 +117,7 @@ services:
- rspamd - rspamd
php-fpm-mailcow: php-fpm-mailcow:
image: ghcr.io/mailcow/phpfpm:8.2.29-2 image: ghcr.io/mailcow/phpfpm:8.2.29-3
command: "php-fpm -d date.timezone=${TZ} -d expose_php=0" command: "php-fpm -d date.timezone=${TZ} -d expose_php=0"
depends_on: depends_on:
- redis-mailcow - redis-mailcow
@@ -200,7 +200,7 @@ services:
- phpfpm - phpfpm
sogo-mailcow: sogo-mailcow:
image: ghcr.io/mailcow/sogo:5.12.8-1 image: ghcr.io/mailcow/sogo:5.12.9-1
environment: environment:
- DBNAME=${DBNAME} - DBNAME=${DBNAME}
- DBUSER=${DBUSER} - DBUSER=${DBUSER}
@@ -419,7 +419,7 @@ services:
- php-fpm-mailcow - php-fpm-mailcow
- sogo-mailcow - sogo-mailcow
- rspamd-mailcow - rspamd-mailcow
image: ghcr.io/mailcow/nginx:1.30.2-1 image: ghcr.io/mailcow/nginx:1.30.3-1
dns: dns:
- ${IPV4_NETWORK:-172.22.1}.254 - ${IPV4_NETWORK:-172.22.1}.254
environment: environment:
@@ -25,6 +25,6 @@ services:
- /var/run/mysqld/mysqld.sock:/var/run/mysqld/mysqld.sock - /var/run/mysqld/mysqld.sock:/var/run/mysqld/mysqld.sock
mysql-mailcow: mysql-mailcow:
image: alpine:3.23 image: alpine:3.24
command: /bin/true command: /bin/true
restart: "no" restart: "no"