mirror of
https://github.com/mailcow/mailcow-dockerized.git
synced 2026-06-20 21:40:43 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dafde866ff |
@@ -27,7 +27,7 @@ jobs:
|
|||||||
- "watchdog-mailcow"
|
- "watchdog-mailcow"
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v7
|
- uses: actions/checkout@v6
|
||||||
- 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
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v7
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Run the Action
|
- name: Run the Action
|
||||||
uses: devops-infra/action-pull-request@v1.3.0
|
uses: devops-infra/action-pull-request@v1.2.1
|
||||||
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}}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ jobs:
|
|||||||
packages: write
|
packages: write
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v7
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- 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@v7
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Generate postscreen_access.cidr
|
- name: Generate postscreen_access.cidr
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -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.2.0
|
ARG MAILPARSE_PECL_VERSION=3.1.9
|
||||||
# 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.10.1
|
ARG COMPOSER_VERSION=2.9.5
|
||||||
|
|
||||||
RUN apk add -U --no-cache autoconf \
|
RUN apk add -U --no-cache autoconf \
|
||||||
aspell-dev \
|
aspell-dev \
|
||||||
|
|||||||
@@ -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_4.1.0-1~e2b0b18
|
ARG RSPAMD_VER=rspamd_3.14.3-1~236eb65
|
||||||
ARG CODENAME=trixie
|
ARG CODENAME=trixie
|
||||||
ENV LC_ALL=C
|
ENV LC_ALL=C
|
||||||
|
|
||||||
|
|||||||
@@ -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.9
|
# Version: SOGo-5.12.8
|
||||||
#
|
#
|
||||||
# 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.9
|
ARG SOGO_VERSION=SOGo-5.12.8
|
||||||
ARG SOPE_VERSION=SOPE-5.12.9
|
ARG SOPE_VERSION=SOPE-5.12.8
|
||||||
# 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,7 +3,8 @@ 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 = "multipart";
|
formatter = "default";
|
||||||
|
meta_headers = true;
|
||||||
}
|
}
|
||||||
RLINFO {
|
RLINFO {
|
||||||
backend = "http";
|
backend = "http";
|
||||||
@@ -15,7 +16,8 @@ rules {
|
|||||||
backend = "http";
|
backend = "http";
|
||||||
url = "http://nginx:9081/pushover.php";
|
url = "http://nginx:9081/pushover.php";
|
||||||
selector = "mailcow_rcpt";
|
selector = "mailcow_rcpt";
|
||||||
formatter = "multipart";
|
formatter = "json";
|
||||||
|
meta_headers = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,42 +32,47 @@ 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));
|
||||||
}
|
}
|
||||||
// rspamd metadata_exporter (multipart formatter):
|
if (!function_exists('getallheaders')) {
|
||||||
// - $_POST['metadata'] JSON with the rspamd metadata
|
function getallheaders() {
|
||||||
// - $_FILES['message'] raw RFC822 message
|
if (!is_array($_SERVER)) {
|
||||||
if (empty($_POST['metadata']) || !isset($_FILES['message']) || $_FILES['message']['error'] !== UPLOAD_ERR_OK) {
|
return array();
|
||||||
error_log("QUARANTINE: missing multipart parts from rspamd" . PHP_EOL);
|
}
|
||||||
http_response_code(400);
|
$headers = array();
|
||||||
exit;
|
foreach ($_SERVER as $name => $value) {
|
||||||
|
if (substr($name, 0, 5) == 'HTTP_') {
|
||||||
|
$headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))))] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $headers;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$meta = json_decode($_POST['metadata'], true);
|
$raw_data_content = file_get_contents('php://input');
|
||||||
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");
|
||||||
$raw_size = (int)$_FILES['message']['size'];
|
$headers = getallheaders();
|
||||||
|
|
||||||
$qid = $meta['qid'] ?? 'unknown';
|
$qid = $headers['X-Rspamd-Qid'];
|
||||||
$subject = iconv_mime_decode($meta['subject'] ?? '');
|
$fuzzy = $headers['X-Rspamd-Fuzzy'];
|
||||||
$score = $meta['score'] ?? 0;
|
$subject = iconv_mime_decode($headers['X-Rspamd-Subject']);
|
||||||
$rcpts = $meta['rcpt'] ?? array();
|
$score = $headers['X-Rspamd-Score'];
|
||||||
$user = $meta['user'] ?? 'unknown';
|
$rcpts = $headers['X-Rspamd-Rcpt'];
|
||||||
$ip = $meta['ip'] ?? 'unknown';
|
$user = $headers['X-Rspamd-User'];
|
||||||
$action = $meta['action'] ?? 'no action';
|
$ip = $headers['X-Rspamd-Ip'];
|
||||||
$sender = $meta['from'] ?? '';
|
$action = $headers['X-Rspamd-Action'];
|
||||||
$symbols = json_encode($meta['symbols'] ?? array());
|
$sender = $headers['X-Rspamd-From'];
|
||||||
$fuzzy = json_encode(is_array($meta['fuzzy'] ?? null) ? $meta['fuzzy'] : array());
|
$symbols = $headers['X-Rspamd-Symbols'];
|
||||||
|
|
||||||
|
$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) {
|
||||||
@@ -89,7 +94,7 @@ catch (RedisException $e) {
|
|||||||
$rcpt_final_mailboxes = array();
|
$rcpt_final_mailboxes = array();
|
||||||
|
|
||||||
// Loop through all rcpts
|
// Loop through all rcpts
|
||||||
foreach ($rcpts as $rcpt) {
|
foreach (json_decode($rcpts, true) as $rcpt) {
|
||||||
// Remove tag
|
// Remove tag
|
||||||
$rcpt = preg_replace('/^(.*?)\+.*(@.*)$/', '$1$2', $rcpt);
|
$rcpt = preg_replace('/^(.*?)\+.*(@.*)$/', '$1$2', $rcpt);
|
||||||
|
|
||||||
|
|||||||
@@ -32,46 +32,50 @@ 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));
|
||||||
}
|
}
|
||||||
// rspamd metadata_exporter (multipart formatter): metadata JSON arrives as $_POST['metadata'].
|
if (!function_exists('getallheaders')) {
|
||||||
if (empty($_POST['metadata'])) {
|
function getallheaders() {
|
||||||
error_log("NOTIFY: missing metadata part from rspamd" . PHP_EOL);
|
if (!is_array($_SERVER)) {
|
||||||
http_response_code(400);
|
return array();
|
||||||
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$meta = json_decode($_POST['metadata'], true);
|
$headers = getallheaders();
|
||||||
if (!is_array($meta)) {
|
$json_body = json_decode(file_get_contents('php://input'));
|
||||||
error_log("NOTIFY: cannot decode metadata JSON" . PHP_EOL);
|
|
||||||
http_response_code(400);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$qid = $meta['qid'] ?? 'unknown';
|
$qid = $headers['X-Rspamd-Qid'];
|
||||||
$rcpts = $meta['rcpt'] ?? array();
|
$rcpts = $headers['X-Rspamd-Rcpt'];
|
||||||
$sender = $meta['from'] ?? '';
|
$sender = $headers['X-Rspamd-From'];
|
||||||
$ip = $meta['ip'] ?? 'unknown';
|
$ip = $headers['X-Rspamd-Ip'];
|
||||||
$subject = iconv_mime_decode($meta['subject'] ?? '');
|
$subject = iconv_mime_decode($headers['X-Rspamd-Subject']);
|
||||||
$messageid= $meta['message_id'] ?? '';
|
$messageid= $json_body->message_id;
|
||||||
$priority = 0;
|
$priority = 0;
|
||||||
|
|
||||||
$symbols_array = $meta['symbols'] ?? array();
|
$symbols_array = json_decode($headers['X-Rspamd-Symbols'], true);
|
||||||
if (is_array($symbols_array)) {
|
if (is_array($symbols_array)) {
|
||||||
foreach ($symbols_array as $symbol) {
|
foreach ($symbols_array as $symbol) {
|
||||||
if (($symbol['name'] ?? null) == 'HAS_X_PRIO_ONE') {
|
if ($symbol['name'] == 'HAS_X_PRIO_ONE') {
|
||||||
$priority = 1;
|
$priority = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$sender_address = $meta['header_from'][0] ?? '';
|
$sender_address = $json_body->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 = $meta['header_to'][0] ?? '';
|
$to_address = $json_body->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'];
|
||||||
@@ -81,7 +85,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 ($rcpts as $rcpt) {
|
foreach (json_decode($rcpts, true) as $rcpt) {
|
||||||
// Remove tag
|
// Remove tag
|
||||||
$rcpt = preg_replace('/^(.*?)\+.*(@.*)$/', '$1$2', $rcpt);
|
$rcpt = preg_replace('/^(.*?)\+.*(@.*)$/', '$1$2', $rcpt);
|
||||||
|
|
||||||
|
|||||||
@@ -1072,7 +1072,6 @@ 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"]
|
||||||
@@ -1119,7 +1118,6 @@ 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"]
|
||||||
@@ -1153,9 +1151,6 @@ 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
|
||||||
@@ -3419,7 +3414,6 @@ 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: "*"
|
||||||
@@ -3470,7 +3464,6 @@ 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: ""
|
||||||
@@ -3494,9 +3487,6 @@ 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
|
||||||
@@ -4891,7 +4881,6 @@ 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"
|
||||||
@@ -5816,7 +5805,6 @@ 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"
|
||||||
|
|||||||
@@ -3505,6 +3505,7 @@ 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'];
|
||||||
@@ -3827,7 +3828,6 @@ 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,6 +6127,7 @@ 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") {
|
||||||
|
|||||||
@@ -424,11 +424,6 @@ $(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 {
|
||||||
@@ -1247,7 +1242,6 @@ 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') {
|
||||||
@@ -1391,11 +1385,6 @@ 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',
|
||||||
|
|||||||
@@ -929,7 +929,6 @@
|
|||||||
"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>",
|
||||||
|
|||||||
@@ -111,8 +111,7 @@
|
|||||||
"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",
|
||||||
@@ -557,9 +556,7 @@
|
|||||||
"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": "L’authentification à 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 l’une des suivantes : add_header, reject, all\""
|
|
||||||
},
|
},
|
||||||
"debug": {
|
"debug": {
|
||||||
"chart_this_server": "Graphique (ce serveur)",
|
"chart_this_server": "Graphique (ce serveur)",
|
||||||
@@ -758,9 +755,7 @@
|
|||||||
"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 d’expéditeur pour autoriser certaines boîtes aux lettres à envoyer des messages via cet alias."
|
|
||||||
},
|
},
|
||||||
"footer": {
|
"footer": {
|
||||||
"cancel": "Annuler",
|
"cancel": "Annuler",
|
||||||
@@ -993,8 +988,7 @@
|
|||||||
"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 l’accès via Oauth2.",
|
"access_denied": "Veuillez vous connecter en tant que propriétaire de la boîte de réception pour accorder l’accès via Oauth2.",
|
||||||
@@ -1195,11 +1189,7 @@
|
|||||||
"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": "L’utilisateur doit configurer l’authentification à deux facteurs avant de pouvoir accéder à l’interface.",
|
|
||||||
"setup_title": "Authentification à deux facteurs requise",
|
|
||||||
"setup_required": "Votre compte nécessite l’authentification à deux facteurs. Veuillez configurer une méthode 2FA pour continuer."
|
|
||||||
},
|
},
|
||||||
"fido2": {
|
"fido2": {
|
||||||
"set_fn": "Définir un nom",
|
"set_fn": "Définir un nom",
|
||||||
@@ -1388,8 +1378,7 @@
|
|||||||
"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 l’utilisateur connecté",
|
"cannot_delete_self": "Impossible de supprimer l’utilisateur connecté",
|
||||||
|
|||||||
@@ -1001,8 +1001,7 @@
|
|||||||
"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 • Predfilter • Uporabniški skripti • Postfilter • 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 • Predfilter • Uporabniški skripti • Postfilter • 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",
|
||||||
|
|||||||
@@ -65,7 +65,6 @@ 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,7 +8,6 @@
|
|||||||
|
|
||||||
<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">
|
||||||
|
|
||||||
@@ -166,14 +165,6 @@
|
|||||||
</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">
|
||||||
|
|||||||
+3
-3
@@ -84,7 +84,7 @@ services:
|
|||||||
- clamd
|
- clamd
|
||||||
|
|
||||||
rspamd-mailcow:
|
rspamd-mailcow:
|
||||||
image: ghcr.io/mailcow/rspamd:4.1.0-1
|
image: ghcr.io/mailcow/rspamd:3.14.3-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-3
|
image: ghcr.io/mailcow/phpfpm:8.2.29-2
|
||||||
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.9-1
|
image: ghcr.io/mailcow/sogo:5.12.8-1
|
||||||
environment:
|
environment:
|
||||||
- DBNAME=${DBNAME}
|
- DBNAME=${DBNAME}
|
||||||
- DBUSER=${DBUSER}
|
- DBUSER=${DBUSER}
|
||||||
|
|||||||
+1
-1
@@ -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.24
|
image: alpine:3.23
|
||||||
command: /bin/true
|
command: /bin/true
|
||||||
restart: "no"
|
restart: "no"
|
||||||
|
|||||||
Reference in New Issue
Block a user