Compare commits

..

2 Commits

Author SHA1 Message Date
milkmaker e818e81b82 [Web] Updated lang.si-si.json
Co-authored-by: Matjaž Tekavec <matjaz@moj-svet.si>
2026-06-20 11:47:25 +00:00
milkmaker 8c8bca51d3 [Web] Updated lang.fr-fr.json
Co-authored-by: Romain Ayme <ayme.romain@hotmail.fr>
2026-06-20 11:47:25 +00:00
22 changed files with 38 additions and 95 deletions
@@ -14,7 +14,7 @@ jobs:
pull-requests: write
steps:
- name: Mark/Close Stale Issues and Pull Requests 🗑️
uses: actions/stale@v10.4.0
uses: actions/stale@v10.3.0
with:
repo-token: ${{ secrets.STALE_ACTION_PAT }}
days-before-stale: 60
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
with:
fetch-depth: 0
- name: Run the Action
uses: devops-infra/action-pull-request@v1.4.0
uses: devops-infra/action-pull-request@v1.3.0
with:
github_token: ${{ secrets.PRTONIGHTLY_ACTION_PAT }}
title: Automatic PR to nightly from ${{ github.event.repository.updated_at}}
-3
View File
@@ -23,9 +23,6 @@ A big thank you to everyone supporting us on GitHub Sponsors—your contribution
<a href="https://www.maehdros.com/" target=_blank><img
src="https://avatars.githubusercontent.com/u/173894712" height="58"
/></a>
<a href="https://garske-systems.de/" target=_blank><img
src="https://garske-systems.de/img/logo_min.png" height="58"
/></a>
### 50$/Month Sponsors
<a href="https://github.com/vnukhr" target=_blank><img
+1 -1
View File
@@ -1,4 +1,4 @@
FROM nginx:1.30.3-alpine
FROM nginx:1.30.2-alpine
LABEL maintainer "The Infrastructure Company GmbH <info@servercow.de>"
ENV PIP_BREAK_SYSTEM_PACKAGES=1
+1 -1
View File
@@ -13,7 +13,7 @@ ARG MEMCACHED_PECL_VERSION=3.4.0
# renovate: datasource=github-tags depName=phpredis/phpredis versioning=semver-coerced extractVersion=(?<version>.*)$
ARG REDIS_PECL_VERSION=6.3.0
# renovate: datasource=github-tags depName=composer/composer versioning=semver-coerced extractVersion=(?<version>.*)$
ARG COMPOSER_VERSION=2.10.2
ARG COMPOSER_VERSION=2.10.1
RUN apk add -U --no-cache autoconf \
aspell-dev \
+1 -1
View File
@@ -1,4 +1,4 @@
FROM debian:trixie-slim
FROM debian:bookworm-slim
LABEL maintainer="The Infrastructure Company GmbH <info@servercow.de>"
@@ -1,4 +1,4 @@
@version: 4.8
@version: 3.38
@include "scl.conf"
options {
chain_hostnames(off);
@@ -7,7 +7,7 @@ options {
dns_cache(no);
use_fqdn(no);
owner("root"); group("adm"); perm(0640);
stats(freq(0));
stats_freq(0);
bad_hostname("^gconfd$");
};
source s_src {
+2 -2
View File
@@ -1,4 +1,4 @@
@version: 4.8
@version: 3.38
@include "scl.conf"
options {
chain_hostnames(off);
@@ -7,7 +7,7 @@ options {
dns_cache(no);
use_fqdn(no);
owner("root"); group("adm"); perm(0640);
stats(freq(0));
stats_freq(0);
bad_hostname("^gconfd$");
};
source s_src {
-5
View File
@@ -42,11 +42,6 @@ http {
https https;
}
map $server_port $sogo_auth_internal {
65510 "1";
default "";
}
{% if HTTP_REDIRECT %}
# HTTP to HTTPS redirect
server {
@@ -116,8 +116,6 @@ location ~ \.php$ {
include /etc/nginx/fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
# trusted internal-auth marker; empty for external clients (see nginx.conf map)
fastcgi_param SOGO_AUTH_INTERNAL $sogo_auth_internal;
fastcgi_read_timeout 3600;
fastcgi_send_timeout 3600;
}
+3 -1
View File
@@ -37,7 +37,7 @@ postscreen_access_list = permit_mynetworks,
cidr:/opt/postfix/conf/postscreen_access.cidr,
tcp:127.0.0.1:10027
postscreen_bare_newline_enable = no
postscreen_denylist_action = drop
postscreen_blacklist_action = drop
postscreen_cache_cleanup_interval = 24h
postscreen_cache_map = proxy:btree:$data_directory/postscreen_cache
postscreen_dnsbl_action = enforce
@@ -107,6 +107,8 @@ smtpd_sender_restrictions = reject_authenticated_sender_login_mismatch,
reject_unknown_sender_domain
smtpd_soft_error_limit = 3
smtpd_tls_auth_only = yes
smtpd_tls_dh1024_param_file = /etc/ssl/mail/dhparams.pem
smtpd_tls_eecdh_grade = auto
smtpd_tls_exclude_ciphers = ECDHE-RSA-RC4-SHA, RC4, aNULL, DES-CBC3-SHA, ECDHE-RSA-DES-CBC3-SHA, EDH-RSA-DES-CBC3-SHA
smtpd_tls_loglevel = 1
+2
View File
@@ -29,6 +29,7 @@ smtps inet n - n - - smtpd
# TLS protocol can be modified by setting submission_smtpd_tls_mandatory_protocols in extra.cf
submission inet n - n - - smtpd
-o smtpd_client_restrictions=permit_mynetworks,permit_sasl_authenticated,reject
-o smtpd_enforce_tls=yes
-o smtpd_tls_security_level=encrypt
-o smtpd_tls_mandatory_protocols=$submission_smtpd_tls_mandatory_protocols
-o tls_preempt_cipherlist=yes
@@ -37,6 +38,7 @@ submission inet n - n - - smtpd
10587 inet n - n - - smtpd
-o smtpd_upstream_proxy_protocol=haproxy
-o smtpd_client_restrictions=permit_mynetworks,permit_sasl_authenticated,reject
-o smtpd_enforce_tls=yes
-o smtpd_tls_security_level=encrypt
-o smtpd_tls_mandatory_protocols=$submission_smtpd_tls_mandatory_protocols
-o tls_preempt_cipherlist=yes
+4 -14
View File
@@ -1,6 +1,6 @@
# Whitelist generated by Postwhite v3.4 on Wed Jul 1 00:51:20 UTC 2026
# Whitelist generated by Postwhite v3.4 on Mon Jun 1 00:52:17 UTC 2026
# https://github.com/stevejenkins/postwhite/
# 2251 total rules
# 2186 total rules
2a00:1450:4000::/36 permit
2a00:1450:4864::/56 permit
2a01:111:f400::/48 permit
@@ -1528,7 +1528,7 @@
149.97.173.180 permit
149.118.160.128/25 permit
150.136.21.199 permit
150.171.109.183 permit
150.171.109.118 permit
150.230.98.160 permit
151.145.38.14 permit
152.67.105.195 permit
@@ -1605,12 +1605,6 @@
164.152.25.241 permit
164.177.132.168/30 permit
165.1.100.0/25 permit
165.173.128.0/24 permit
165.173.180.0/24 permit
165.173.180.250/31 permit
165.173.182.0/24 permit
165.173.182.250/31 permit
165.173.189.205 permit
166.78.68.0/22 permit
166.78.68.221 permit
166.78.69.169 permit
@@ -1657,7 +1651,6 @@
173.203.81.39 permit
173.224.161.128/25 permit
173.224.165.0/26 permit
173.224.166.48/28 permit
174.36.84.8/29 permit
174.36.84.16/29 permit
174.36.84.32/29 permit
@@ -2178,10 +2171,7 @@
2001:748:400:3301::4 permit
2404:6800:4000::/36 permit
2404:6800:4864::/56 permit
2603:1061:14:1c2::1 permit
2607:13c0:0001:0000:0000:0000:0000:7000/116 permit
2607:13c0:0002:0000:0000:0000:0000:1000/116 permit
2607:13c0:0004:0000:0000:0000:0000:0000/116 permit
2603:1061:14:40::1 permit
2607:f8b0:4000::/36 permit
2607:f8b0:4864::/56 permit
2620:109:c003:104::/64 permit
+3 -14
View File
@@ -429,25 +429,14 @@ function domain_admin_sso($_action, $_data) {
switch ($_action) {
case 'check':
$token = preg_replace('/[^a-zA-Z0-9-]/', '', $_data);
$token = $_data;
$stmt = $pdo->prepare("SELECT `t1`.`username` FROM `da_sso` AS `t1` JOIN `admin` AS `t2` ON `t1`.`username` = `t2`.`username` WHERE `t1`.`token` = :token AND `t1`.`created` > DATE_SUB(NOW(), INTERVAL '30' SECOND) AND `t2`.`active` = 1 AND `t2`.`superadmin` = 0;");
$stmt->execute(array(
':token' => $token
':token' => preg_replace('/[^a-zA-Z0-9-]/', '', $token)
));
$return = $stmt->fetch(PDO::FETCH_ASSOC);
if (empty($return['username'])) {
return false;
}
// single-use: consume the token; if a concurrent request already used it, deny
$del = $pdo->prepare("DELETE FROM `da_sso` WHERE `token` = :token");
$del->execute(array(
':token' => $token
));
if ($del->rowCount() < 1) {
return false;
}
return $return['username'];
return empty($return['username']) ? false : $return['username'];
case 'issue':
if ($_SESSION['mailcow_cc_role'] != "admin") {
$_SESSION['return'][] = array(
+3 -12
View File
@@ -5647,11 +5647,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$stmt->execute(array(
':username' => $username
));
// bind LIKE pattern + escape LIKE wildcards so the value matches literally (no SQLi, no over-match)
$c_object_like = '%/' . addcslashes($username, '\\%_') . '/%';
$stmt = $pdo->prepare("DELETE FROM `sogo_acl` WHERE `c_object` LIKE :c_object_like OR `c_uid` = :username");
$stmt = $pdo->prepare("DELETE FROM `sogo_acl` WHERE `c_object` LIKE '%/" . $username . "/%' OR `c_uid` = :username");
$stmt->execute(array(
':c_object_like' => $c_object_like,
':username' => $username
));
$stmt = $pdo->prepare("DELETE FROM `sogo_store` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
@@ -6047,11 +6044,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$stmt->execute(array(
':username' => $username
));
// bind LIKE pattern + escape LIKE wildcards so the value matches literally (no SQLi, no over-match)
$c_object_like = '%/' . addcslashes($username, '\\%_') . '/%';
$stmt = $pdo->prepare("DELETE FROM `sogo_acl` WHERE `c_object` LIKE :c_object_like OR `c_uid` = :username");
$stmt = $pdo->prepare("DELETE FROM `sogo_acl` WHERE `c_object` LIKE '%/" . str_replace('%', '\%', $username) . "/%' OR `c_uid` = :username");
$stmt->execute(array(
':c_object_like' => $c_object_like,
':username' => $username
));
$stmt = $pdo->prepare("DELETE FROM `sogo_store` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
@@ -6207,11 +6201,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
$stmt->execute(array(
':username' => $name
));
// bind LIKE pattern + escape LIKE wildcards so the value matches literally (no SQLi, no over-match)
$c_object_like = '%/' . addcslashes($name, '\\%_') . '/%';
$stmt = $pdo->prepare("DELETE FROM `sogo_acl` WHERE `c_object` LIKE :c_object_like OR `c_uid` = :username");
$stmt = $pdo->prepare("DELETE FROM `sogo_acl` WHERE `c_object` LIKE '%/" . $name . "/%' OR `c_uid` = :username");
$stmt->execute(array(
':c_object_like' => $c_object_like,
':username' => $name
));
$stmt = $pdo->prepare("DELETE FROM `sogo_store` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
+8 -12
View File
@@ -22,7 +22,7 @@ function quarantine($_action, $_data = null) {
return false;
}
$stmt = $pdo->prepare('SELECT `id` FROM `quarantine` LEFT OUTER JOIN `user_acl` ON `user_acl`.`username` = `rcpt`
WHERE `qhash` = :hash
WHERE `qhash` = :hash
AND user_acl.quarantine = 1
AND rcpt IN (SELECT username FROM mailbox)');
$stmt->execute(array(':hash' => $hash));
@@ -65,7 +65,7 @@ function quarantine($_action, $_data = null) {
return false;
}
$stmt = $pdo->prepare('SELECT `id` FROM `quarantine` LEFT OUTER JOIN `user_acl` ON `user_acl`.`username` = `rcpt`
WHERE `qhash` = :hash
WHERE `qhash` = :hash
AND `user_acl`.`quarantine` = 1
AND `username` IN (SELECT `username` FROM `mailbox`)');
$stmt->execute(array(':hash' => $hash));
@@ -170,8 +170,6 @@ function quarantine($_action, $_data = null) {
}
elseif ($release_format == 'raw') {
$detail_row['msg'] = preg_replace('/^X-Spam-Flag: (.*)/m', 'X-Pre-Release-Spam-Flag: $1', $detail_row['msg']);
// dot-stuffing per RFC5321 4.5.2: escape leading dots
$detail_row['msg'] = preg_replace('~^\.~m', '..', $detail_row['msg']);
$postfix_talk = array(
array('220', 'HELO quarantine' . chr(10)),
array('250', 'MAIL FROM: ' . $sender . chr(10)),
@@ -182,7 +180,7 @@ function quarantine($_action, $_data = null) {
array('221', '')
);
// Thanks to https://stackoverflow.com/questions/6632399/given-an-email-as-raw-text-how-can-i-send-it-using-php
$smtp_connection = fsockopen($postfix, 590, $errno, $errstr, 1);
$smtp_connection = fsockopen($postfix, 590, $errno, $errstr, 1);
if (!$smtp_connection) {
logger(array('return' => array(
array(
@@ -194,7 +192,7 @@ function quarantine($_action, $_data = null) {
return false;
}
for ($i=0; $i < count($postfix_talk); $i++) {
$smtp_resource = fgets($smtp_connection, 256);
$smtp_resource = fgets($smtp_connection, 256);
if (substr($smtp_resource, 0, 3) !== $postfix_talk[$i][0]) {
$ret = substr($smtp_resource, 0, 3);
$ret = (empty($ret)) ? '-' : $ret;
@@ -467,19 +465,17 @@ function quarantine($_action, $_data = null) {
}
elseif ($release_format == 'raw') {
$row['msg'] = preg_replace('/^X-Spam-Flag: (.*)/m', 'X-Pre-Release-Spam-Flag: $1', $row['msg']);
// dot-stuffing per RFC5321 4.5.2: escape leading dots
$row['msg'] = preg_replace('~^\.~m', '..', $row['msg']);
$postfix_talk = array(
array('220', 'HELO quarantine' . chr(10)),
array('250', 'MAIL FROM: ' . $sender . chr(10)),
array('250', 'RCPT TO: ' . $row['rcpt'] . chr(10)),
array('250', 'DATA' . chr(10)),
array('354', $row['msg'] . chr(10) . '.' . chr(10)),
array('354', str_replace("\n.", '', $row['msg']) . chr(10) . '.' . chr(10)),
array('250', 'QUIT' . chr(10)),
array('221', '')
);
// Thanks to https://stackoverflow.com/questions/6632399/given-an-email-as-raw-text-how-can-i-send-it-using-php
$smtp_connection = fsockopen($postfix, 590, $errno, $errstr, 1);
$smtp_connection = fsockopen($postfix, 590, $errno, $errstr, 1);
if (!$smtp_connection) {
$_SESSION['return'][] = array(
'type' => 'warning',
@@ -489,7 +485,7 @@ function quarantine($_action, $_data = null) {
return false;
}
for ($i=0; $i < count($postfix_talk); $i++) {
$smtp_resource = fgets($smtp_connection, 256);
$smtp_resource = fgets($smtp_connection, 256);
if (substr($smtp_resource, 0, 3) !== $postfix_talk[$i][0]) {
$ret = substr($smtp_resource, 0, 3);
$ret = (empty($ret)) ? '-' : $ret;
@@ -837,7 +833,7 @@ function quarantine($_action, $_data = null) {
)));
return false;
}
$stmt = $pdo->prepare('SELECT * FROM `quarantine` WHERE `qhash` = :hash');
$stmt = $pdo->prepare('SELECT * FROM `quarantine` WHERE `qhash` = :hash');
$stmt->execute(array(':hash' => $hash));
return $stmt->fetch(PDO::FETCH_ASSOC);
break;
-7
View File
@@ -1089,8 +1089,6 @@ jQuery(function($){
return str;
}).join('<br>\n');
item.subject = escapeHtml(item.subject);
if (item.sender_mime != null) item.sender_mime = escapeHtml(item.sender_mime);
if (item['message-id'] != null) item['message-id'] = escapeHtml(item['message-id']);
var scan_time = item.time_real.toFixed(3);
if (item.time_virtual) {
scan_time += ' / ' + item.time_virtual.toFixed(3);
@@ -1214,11 +1212,6 @@ jQuery(function($){
});
} else if (table == 'rllog') {
$.each(data, function (i, item) {
if (item.header_from != null) item.header_from = escapeHtml(item.header_from);
if (item.header_subject != null) item.header_subject = escapeHtml(item.header_subject);
if (item.from != null) item.from = escapeHtml(item.from);
if (item.rcpt != null) item.rcpt = escapeHtml(item.rcpt);
if (item.message_id != null) item.message_id = escapeHtml(item.message_id);
if (item.user == null) {
item.user = "none";
}
-1
View File
@@ -996,7 +996,6 @@ jQuery(function($){
'style="min-width:2em;width:' + item.percent_in_use + '%">' + item.percent_in_use + '%' + '</div></div>'
};
item.username = escapeHtml(item.username);
item.name = escapeHtml(item.name);
if (Array.isArray(item.tags)){
var tags = '';
+1 -1
View File
@@ -1086,7 +1086,7 @@
"rspamd_result": "Rspamd-Ergebnis",
"sender": "Sender (SMTP)",
"sender_header": "Sender (\"From\"-Header)",
"settings_info": "Maximale Anzahl der zurückgehaltenen E-Mails (pro Mailbox): %s<br>Maximale Größe einer zu speichernden E-Mail: %s MiB",
"settings_info": "Maximale Anzahl der zurückgehaltenen E-Mails: %s<br>Maximale Größe einer zu speichernden E-Mail: %s MiB",
"show_item": "Details",
"spam": "Spam",
"spam_score": "Bewertung",
+1 -1
View File
@@ -1087,7 +1087,7 @@
"rspamd_result": "Rspamd result",
"sender": "Sender (SMTP)",
"sender_header": "Sender (\"From\" header)",
"settings_info": "Maximum amount of elements to be quarantined (per mailbox): %s<br>Maximum email size: %s MiB",
"settings_info": "Maximum amount of elements to be quarantined: %s<br>Maximum email size: %s MiB",
"show_item": "Show item",
"spam": "Spam",
"spam_score": "Score",
+2 -11
View File
@@ -8,12 +8,8 @@ $ALLOW_ADMIN_EMAIL_LOGIN = (preg_match(
$session_var_user_allowed = 'sogo-sso-user-allowed';
$session_var_pass = 'sogo-sso-pass';
// only the internal nginx auth_request loopback (127.0.0.1:65510) sets this;
// external clients can never supply it (bare fastcgi param, not an HTTP header)
$is_internal_auth = (($_SERVER['SOGO_AUTH_INTERNAL'] ?? '') === '1');
// validate credentials for basic auth requests
if ($is_internal_auth && isset($_SERVER['PHP_AUTH_USER'])) {
if (isset($_SERVER['PHP_AUTH_USER'])) {
// load prerequisites only when required
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php';
@@ -54,11 +50,6 @@ elseif (isset($_GET['login'])) {
(($_SESSION['acl']['login_as'] == "1" && $ALLOW_ADMIN_EMAIL_LOGIN !== 0) || ($is_dual === false && $login == $_SESSION['mailcow_cc_username']))) {
if (filter_var($login, FILTER_VALIDATE_EMAIL)) {
if (user_get_alias_details($login) !== false) {
// enforce tenant boundary
if (!hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $login)) {
header("Location: /");
exit;
}
// Block SOGo access if pending actions (2FA setup, password update)
if (!empty($_SESSION['pending_tfa_setup']) || !empty($_SESSION['pending_pw_update'])) {
header("Location: /");
@@ -89,7 +80,7 @@ elseif (isset($_GET['login'])) {
exit;
}
// only check for admin-login on sogo GUI requests
elseif ($is_internal_auth && isset($_SERVER['HTTP_X_ORIGINAL_URI']) && strcasecmp(substr($_SERVER['HTTP_X_ORIGINAL_URI'], 0, 9), "/SOGo/so/") === 0) {
elseif (isset($_SERVER['HTTP_X_ORIGINAL_URI']) && strcasecmp(substr($_SERVER['HTTP_X_ORIGINAL_URI'], 0, 9), "/SOGo/so/") === 0) {
// this is an nginx auth_request call, we check for existing sogo-sso session variables
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/vars.inc.php';
if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/inc/vars.local.inc.php')) {
+2 -2
View File
@@ -339,7 +339,7 @@ services:
- dovecot
postfix-mailcow:
image: ghcr.io/mailcow/postfix:3.10.12-1
image: ghcr.io/mailcow/postfix:3.7.11-2
depends_on:
mysql-mailcow:
condition: service_started
@@ -419,7 +419,7 @@ services:
- php-fpm-mailcow
- sogo-mailcow
- rspamd-mailcow
image: ghcr.io/mailcow/nginx:1.30.3-1
image: ghcr.io/mailcow/nginx:1.30.2-1
dns:
- ${IPV4_NETWORK:-172.22.1}.254
environment: