mirror of
https://github.com/mailcow/mailcow-dockerized.git
synced 2026-08-08 16:13:18 +00:00
Compare commits
19
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
96a70652c3 | ||
|
|
2ac4b1deae | ||
|
|
1eb6d2e26c | ||
|
|
384e2f6ac1 | ||
|
|
32156a337a | ||
|
|
281cf93db3 | ||
|
|
f399c07c85 | ||
|
|
a693325fe6 | ||
|
|
9ad84eee92 | ||
|
|
b59869b720 | ||
|
|
7515bef66c | ||
|
|
b84ba8ded1 | ||
|
|
4845928e7a | ||
|
|
4ccfedd6b3 | ||
|
|
e8d9315d4a | ||
|
|
d977ddb501 | ||
|
|
e76f5237ed | ||
|
|
c11ed5dd1e | ||
|
|
4ef65fc382 |
@@ -14,7 +14,7 @@ jobs:
|
|||||||
pull-requests: write
|
pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
- name: Mark/Close Stale Issues and Pull Requests 🗑️
|
- name: Mark/Close Stale Issues and Pull Requests 🗑️
|
||||||
uses: actions/stale@v11.0.0
|
uses: actions/stale@v10.4.0
|
||||||
with:
|
with:
|
||||||
repo-token: ${{ secrets.STALE_ACTION_PAT }}
|
repo-token: ${{ secrets.STALE_ACTION_PAT }}
|
||||||
days-before-stale: 60
|
days-before-stale: 60
|
||||||
|
|||||||
@@ -23,15 +23,10 @@ A big thank you to everyone supporting us on GitHub Sponsors—your contribution
|
|||||||
<a href="https://www.maehdros.com/" target=_blank><img
|
<a href="https://www.maehdros.com/" target=_blank><img
|
||||||
src="https://avatars.githubusercontent.com/u/173894712" height="58"
|
src="https://avatars.githubusercontent.com/u/173894712" height="58"
|
||||||
/></a>
|
/></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
|
### 50$/Month Sponsors
|
||||||
<a href="https://github.com/vnukhr" target=_blank><img
|
<a href="https://github.com/vnukhr" target=_blank><img
|
||||||
src="https://avatars.githubusercontent.com/u/7805987?s=52&v=4" height="58"
|
src="https://avatars.githubusercontent.com/u/7805987?s=52&v=4" height="58"
|
||||||
/></a><a href="https://github.com/humiico" target=_blank><img
|
|
||||||
src="https://avatars.githubusercontent.com/u/110134705?s=52&v=4" height="58"
|
|
||||||
/></a>
|
/></a>
|
||||||
|
|
||||||
## Info, documentation and support
|
## Info, documentation and support
|
||||||
|
|||||||
@@ -249,33 +249,12 @@ while true; do
|
|||||||
done <<< "${SQL_DOMAINS}"
|
done <<< "${SQL_DOMAINS}"
|
||||||
|
|
||||||
if [[ ${ONLY_MAILCOW_HOSTNAME} != "y" ]]; then
|
if [[ ${ONLY_MAILCOW_HOSTNAME} != "y" ]]; then
|
||||||
# Fetch all domains with an active MTA-STS policy once.
|
|
||||||
unset MTA_STS_ACTIVE_DOMAINS
|
|
||||||
declare -A MTA_STS_ACTIVE_DOMAINS
|
|
||||||
if [[ ${AUTODISCOVER_SAN} == "y" ]]; then
|
|
||||||
SQL_MTA_STS_DOMAINS=$(mariadb --skip-ssl --socket=/var/run/mysqld/mysqld.sock -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT domain FROM mta_sts WHERE active = 1" -Bs)
|
|
||||||
if [[ $? -eq 0 ]]; then
|
|
||||||
while read mta_sts_domain; do
|
|
||||||
if [[ -z "${mta_sts_domain}" ]]; then
|
|
||||||
# ignore empty lines
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
MTA_STS_ACTIVE_DOMAINS["${mta_sts_domain}"]=1
|
|
||||||
done <<< "${SQL_MTA_STS_DOMAINS}"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
for SQL_DOMAIN in "${SQL_DOMAIN_ARR[@]}"; do
|
for SQL_DOMAIN in "${SQL_DOMAIN_ARR[@]}"; do
|
||||||
unset VALIDATED_CONFIG_DOMAINS_SUBDOMAINS
|
unset VALIDATED_CONFIG_DOMAINS_SUBDOMAINS
|
||||||
declare -a VALIDATED_CONFIG_DOMAINS_SUBDOMAINS
|
declare -a VALIDATED_CONFIG_DOMAINS_SUBDOMAINS
|
||||||
for SUBDOMAIN in "${ADDITIONAL_WC_ARR[@]}"; do
|
for SUBDOMAIN in "${ADDITIONAL_WC_ARR[@]}"; do
|
||||||
FULL_SUBDOMAIN="${SUBDOMAIN}.${SQL_DOMAIN}"
|
FULL_SUBDOMAIN="${SUBDOMAIN}.${SQL_DOMAIN}"
|
||||||
|
|
||||||
# Skip mta-sts subdomain unless MTA-STS is enabled (active) for this domain
|
|
||||||
if [[ "${SUBDOMAIN}" == "mta-sts" && -z "${MTA_STS_ACTIVE_DOMAINS[${SQL_DOMAIN}]}" ]]; then
|
|
||||||
log_f "MTA-STS is not enabled for ${SQL_DOMAIN} - skipping mta-sts subdomain certificate"
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Skip if subdomain matches MAILCOW_HOSTNAME
|
# Skip if subdomain matches MAILCOW_HOSTNAME
|
||||||
if [[ "${FULL_SUBDOMAIN}" == "${MAILCOW_HOSTNAME}" ]]; then
|
if [[ "${FULL_SUBDOMAIN}" == "${MAILCOW_HOSTNAME}" ]]; then
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM nginx:1.30.4-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,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.4-1~beb659b
|
ARG RSPAMD_VER=rspamd_4.1.0-1~e2b0b18
|
||||||
ARG CODENAME=trixie
|
ARG CODENAME=trixie
|
||||||
ENV LC_ALL=C
|
ENV LC_ALL=C
|
||||||
|
|
||||||
|
|||||||
@@ -42,19 +42,12 @@ http {
|
|||||||
https https;
|
https https;
|
||||||
}
|
}
|
||||||
|
|
||||||
map $server_port $sogo_auth_internal {
|
|
||||||
65510 "1";
|
|
||||||
default "";
|
|
||||||
}
|
|
||||||
|
|
||||||
{% if HTTP_REDIRECT %}
|
{% if HTTP_REDIRECT %}
|
||||||
# HTTP to HTTPS redirect
|
# HTTP to HTTPS redirect
|
||||||
server {
|
server {
|
||||||
root /web;
|
root /web;
|
||||||
listen {{ HTTP_PORT }} default_server;
|
listen {{ HTTP_PORT }} default_server;
|
||||||
{% if ENABLE_IPV6 %}
|
|
||||||
listen [::]:{{ HTTP_PORT }} default_server;
|
listen [::]:{{ HTTP_PORT }} default_server;
|
||||||
{%endif%}
|
|
||||||
|
|
||||||
server_name {{ MAILCOW_HOSTNAME }} autodiscover.* autoconfig.* mta-sts.* {{ ADDITIONAL_SERVER_NAMES | join(' ') }};
|
server_name {{ MAILCOW_HOSTNAME }} autodiscover.* autoconfig.* mta-sts.* {{ ADDITIONAL_SERVER_NAMES | join(' ') }};
|
||||||
|
|
||||||
|
|||||||
@@ -116,8 +116,6 @@ location ~ \.php$ {
|
|||||||
include /etc/nginx/fastcgi_params;
|
include /etc/nginx/fastcgi_params;
|
||||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||||
fastcgi_param PATH_INFO $fastcgi_path_info;
|
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_read_timeout 3600;
|
||||||
fastcgi_send_timeout 3600;
|
fastcgi_send_timeout 3600;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Whitelist generated by Postwhite v3.4 on Sat Aug 1 00:35:20 UTC 2026
|
# Whitelist generated by Postwhite v3.4 on Wed Jul 1 00:51:20 UTC 2026
|
||||||
# https://github.com/stevejenkins/postwhite/
|
# https://github.com/stevejenkins/postwhite/
|
||||||
# 2256 total rules
|
# 2251 total rules
|
||||||
2a00:1450:4000::/36 permit
|
2a00:1450:4000::/36 permit
|
||||||
2a00:1450:4864::/56 permit
|
2a00:1450:4864::/56 permit
|
||||||
2a01:111:f400::/48 permit
|
2a01:111:f400::/48 permit
|
||||||
@@ -29,7 +29,6 @@
|
|||||||
2a01:b747:3004:200::/56 permit
|
2a01:b747:3004:200::/56 permit
|
||||||
2a01:b747:3005:200::/56 permit
|
2a01:b747:3005:200::/56 permit
|
||||||
2a01:b747:3006:200::/56 permit
|
2a01:b747:3006:200::/56 permit
|
||||||
2a01:b747:3007::/56 permit
|
|
||||||
2a02:a60:0:5::/64 permit
|
2a02:a60:0:5::/64 permit
|
||||||
2a0f:f640::/56 permit
|
2a0f:f640::/56 permit
|
||||||
2c0f:fb50:4000::/36 permit
|
2c0f:fb50:4000::/36 permit
|
||||||
@@ -57,14 +56,7 @@
|
|||||||
8.25.194.0/23 permit
|
8.25.194.0/23 permit
|
||||||
8.25.196.0/23 permit
|
8.25.196.0/23 permit
|
||||||
8.36.116.0/24 permit
|
8.36.116.0/24 permit
|
||||||
8.39.54.0/23 permit
|
|
||||||
8.39.54.240/29 permit
|
|
||||||
8.39.54.250/31 permit
|
|
||||||
8.39.144.0/24 permit
|
8.39.144.0/24 permit
|
||||||
8.40.222.0/23 permit
|
|
||||||
8.40.222.240/29 permit
|
|
||||||
8.40.222.250/31 permit
|
|
||||||
8.47.10.9 permit
|
|
||||||
12.130.86.238 permit
|
12.130.86.238 permit
|
||||||
13.108.16.0/20 permit
|
13.108.16.0/20 permit
|
||||||
13.110.208.0/21 permit
|
13.110.208.0/21 permit
|
||||||
@@ -75,7 +67,6 @@
|
|||||||
13.111.191.0/24 permit
|
13.111.191.0/24 permit
|
||||||
13.216.7.111 permit
|
13.216.7.111 permit
|
||||||
13.216.54.180 permit
|
13.216.54.180 permit
|
||||||
13.247.164.219 permit
|
|
||||||
15.200.21.50 permit
|
15.200.21.50 permit
|
||||||
15.200.44.248 permit
|
15.200.44.248 permit
|
||||||
15.200.201.185 permit
|
15.200.201.185 permit
|
||||||
@@ -179,7 +170,6 @@
|
|||||||
34.215.104.144 permit
|
34.215.104.144 permit
|
||||||
34.218.115.239 permit
|
34.218.115.239 permit
|
||||||
34.225.212.172 permit
|
34.225.212.172 permit
|
||||||
34.241.242.183 permit
|
|
||||||
35.83.148.184 permit
|
35.83.148.184 permit
|
||||||
35.155.198.111 permit
|
35.155.198.111 permit
|
||||||
35.158.23.94 permit
|
35.158.23.94 permit
|
||||||
@@ -203,7 +193,6 @@
|
|||||||
40.233.64.216 permit
|
40.233.64.216 permit
|
||||||
40.233.83.78 permit
|
40.233.83.78 permit
|
||||||
40.233.88.28 permit
|
40.233.88.28 permit
|
||||||
43.239.212.33 permit
|
|
||||||
44.206.138.57 permit
|
44.206.138.57 permit
|
||||||
44.210.169.44 permit
|
44.210.169.44 permit
|
||||||
44.217.45.156 permit
|
44.217.45.156 permit
|
||||||
@@ -286,7 +275,6 @@
|
|||||||
51.83.17.38 permit
|
51.83.17.38 permit
|
||||||
52.1.14.157 permit
|
52.1.14.157 permit
|
||||||
52.5.230.59 permit
|
52.5.230.59 permit
|
||||||
52.6.74.205 permit
|
|
||||||
52.12.53.23 permit
|
52.12.53.23 permit
|
||||||
52.13.214.179 permit
|
52.13.214.179 permit
|
||||||
52.26.1.71 permit
|
52.26.1.71 permit
|
||||||
@@ -343,7 +331,6 @@
|
|||||||
54.244.54.130 permit
|
54.244.54.130 permit
|
||||||
54.244.242.0/24 permit
|
54.244.242.0/24 permit
|
||||||
54.255.61.23 permit
|
54.255.61.23 permit
|
||||||
56.124.6.228 permit
|
|
||||||
57.103.64.0/18 permit
|
57.103.64.0/18 permit
|
||||||
57.129.93.249 permit
|
57.129.93.249 permit
|
||||||
62.13.128.0/24 permit
|
62.13.128.0/24 permit
|
||||||
@@ -410,7 +397,6 @@
|
|||||||
65.110.161.77 permit
|
65.110.161.77 permit
|
||||||
65.123.29.213 permit
|
65.123.29.213 permit
|
||||||
65.123.29.220 permit
|
65.123.29.220 permit
|
||||||
65.154.166.0/24 permit
|
|
||||||
65.212.180.36 permit
|
65.212.180.36 permit
|
||||||
66.102.0.0/20 permit
|
66.102.0.0/20 permit
|
||||||
66.119.150.192/26 permit
|
66.119.150.192/26 permit
|
||||||
@@ -1224,9 +1210,6 @@
|
|||||||
99.78.197.208/28 permit
|
99.78.197.208/28 permit
|
||||||
103.9.96.0/22 permit
|
103.9.96.0/22 permit
|
||||||
103.28.42.0/24 permit
|
103.28.42.0/24 permit
|
||||||
103.84.217.15 permit
|
|
||||||
103.84.217.238 permit
|
|
||||||
103.89.75.238 permit
|
|
||||||
103.151.192.0/23 permit
|
103.151.192.0/23 permit
|
||||||
103.168.172.128/27 permit
|
103.168.172.128/27 permit
|
||||||
103.237.104.0/22 permit
|
103.237.104.0/22 permit
|
||||||
@@ -1387,10 +1370,6 @@
|
|||||||
117.120.16.0/21 permit
|
117.120.16.0/21 permit
|
||||||
119.42.242.52/31 permit
|
119.42.242.52/31 permit
|
||||||
119.42.242.156 permit
|
119.42.242.156 permit
|
||||||
121.244.91.31 permit
|
|
||||||
121.244.91.48 permit
|
|
||||||
121.244.91.52 permit
|
|
||||||
122.15.156.182 permit
|
|
||||||
123.126.78.64/29 permit
|
123.126.78.64/29 permit
|
||||||
124.108.96.24/31 permit
|
124.108.96.24/31 permit
|
||||||
124.108.96.28/31 permit
|
124.108.96.28/31 permit
|
||||||
@@ -1473,21 +1452,7 @@
|
|||||||
134.170.141.64/26 permit
|
134.170.141.64/26 permit
|
||||||
134.170.143.0/24 permit
|
134.170.143.0/24 permit
|
||||||
134.170.174.0/24 permit
|
134.170.174.0/24 permit
|
||||||
135.84.80.0/24 permit
|
|
||||||
135.84.81.0/24 permit
|
|
||||||
135.84.82.0/24 permit
|
|
||||||
135.84.83.0/24 permit
|
|
||||||
135.84.216.0/22 permit
|
135.84.216.0/22 permit
|
||||||
136.143.160.0/24 permit
|
|
||||||
136.143.161.0/24 permit
|
|
||||||
136.143.162.0/24 permit
|
|
||||||
136.143.176.0/24 permit
|
|
||||||
136.143.177.0/24 permit
|
|
||||||
136.143.178.49 permit
|
|
||||||
136.143.182.0/23 permit
|
|
||||||
136.143.184.0/24 permit
|
|
||||||
136.143.188.0/24 permit
|
|
||||||
136.143.190.0/23 permit
|
|
||||||
136.146.128.0/20 permit
|
136.146.128.0/20 permit
|
||||||
136.147.128.0/20 permit
|
136.147.128.0/20 permit
|
||||||
136.147.135.0/24 permit
|
136.147.135.0/24 permit
|
||||||
@@ -1507,7 +1472,6 @@
|
|||||||
139.138.46.219 permit
|
139.138.46.219 permit
|
||||||
139.138.57.55 permit
|
139.138.57.55 permit
|
||||||
139.138.58.119 permit
|
139.138.58.119 permit
|
||||||
139.167.79.86 permit
|
|
||||||
139.177.108.0/25 permit
|
139.177.108.0/25 permit
|
||||||
139.180.17.0/24 permit
|
139.180.17.0/24 permit
|
||||||
140.238.148.191 permit
|
140.238.148.191 permit
|
||||||
@@ -1564,7 +1528,7 @@
|
|||||||
149.97.173.180 permit
|
149.97.173.180 permit
|
||||||
149.118.160.128/25 permit
|
149.118.160.128/25 permit
|
||||||
150.136.21.199 permit
|
150.136.21.199 permit
|
||||||
150.171.109.72 permit
|
150.171.109.183 permit
|
||||||
150.230.98.160 permit
|
150.230.98.160 permit
|
||||||
151.145.38.14 permit
|
151.145.38.14 permit
|
||||||
152.67.105.195 permit
|
152.67.105.195 permit
|
||||||
@@ -1679,19 +1643,6 @@
|
|||||||
168.245.12.252 permit
|
168.245.12.252 permit
|
||||||
168.245.46.9 permit
|
168.245.46.9 permit
|
||||||
168.245.127.231 permit
|
168.245.127.231 permit
|
||||||
169.148.129.0/24 permit
|
|
||||||
169.148.131.0/24 permit
|
|
||||||
169.148.138.0/24 permit
|
|
||||||
169.148.142.10 permit
|
|
||||||
169.148.142.33 permit
|
|
||||||
169.148.144.0/25 permit
|
|
||||||
169.148.144.10 permit
|
|
||||||
169.148.146.0/23 permit
|
|
||||||
169.148.174.10 permit
|
|
||||||
169.148.175.3 permit
|
|
||||||
169.148.179.3 permit
|
|
||||||
169.148.188.0/24 permit
|
|
||||||
169.148.188.182 permit
|
|
||||||
170.9.232.254 permit
|
170.9.232.254 permit
|
||||||
170.10.128.0/24 permit
|
170.10.128.0/24 permit
|
||||||
170.10.129.0/24 permit
|
170.10.129.0/24 permit
|
||||||
@@ -1898,16 +1849,7 @@
|
|||||||
199.16.156.0/22 permit
|
199.16.156.0/22 permit
|
||||||
199.33.145.1 permit
|
199.33.145.1 permit
|
||||||
199.33.145.32 permit
|
199.33.145.32 permit
|
||||||
199.34.22.36 permit
|
|
||||||
199.59.148.0/22 permit
|
199.59.148.0/22 permit
|
||||||
199.67.80.2 permit
|
|
||||||
199.67.80.20 permit
|
|
||||||
199.67.82.2 permit
|
|
||||||
199.67.82.20 permit
|
|
||||||
199.67.84.0/24 permit
|
|
||||||
199.67.86.0/24 permit
|
|
||||||
199.67.88.0/24 permit
|
|
||||||
199.67.90.0/24 permit
|
|
||||||
199.101.161.130 permit
|
199.101.161.130 permit
|
||||||
199.101.162.0/25 permit
|
199.101.162.0/25 permit
|
||||||
199.122.120.0/21 permit
|
199.122.120.0/21 permit
|
||||||
@@ -1963,8 +1905,6 @@
|
|||||||
204.92.114.187 permit
|
204.92.114.187 permit
|
||||||
204.92.114.203 permit
|
204.92.114.203 permit
|
||||||
204.92.114.204/31 permit
|
204.92.114.204/31 permit
|
||||||
204.141.32.0/23 permit
|
|
||||||
204.141.42.0/23 permit
|
|
||||||
204.216.164.202 permit
|
204.216.164.202 permit
|
||||||
204.220.160.0/21 permit
|
204.220.160.0/21 permit
|
||||||
204.220.168.0/21 permit
|
204.220.168.0/21 permit
|
||||||
@@ -2238,7 +2178,7 @@
|
|||||||
2001:748:400:3301::4 permit
|
2001:748:400:3301::4 permit
|
||||||
2404:6800:4000::/36 permit
|
2404:6800:4000::/36 permit
|
||||||
2404:6800:4864::/56 permit
|
2404:6800:4864::/56 permit
|
||||||
2603:1061:14:75::1 permit
|
2603:1061:14:1c2::1 permit
|
||||||
2607:13c0:0001:0000:0000:0000:0000:7000/116 permit
|
2607:13c0:0001:0000:0000:0000:0000:7000/116 permit
|
||||||
2607:13c0:0002:0000:0000:0000:0000:1000/116 permit
|
2607:13c0:0002:0000:0000:0000:0000:1000/116 permit
|
||||||
2607:13c0:0004:0000:0000:0000:0000:0000/116 permit
|
2607:13c0:0004:0000:0000:0000:0000:0000/116 permit
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ $raw_data = mb_convert_encoding($raw_data_content, 'HTML-ENTITIES', "UTF-8");
|
|||||||
$raw_size = (int)$_FILES['message']['size'];
|
$raw_size = (int)$_FILES['message']['size'];
|
||||||
|
|
||||||
$qid = $meta['qid'] ?? 'unknown';
|
$qid = $meta['qid'] ?? 'unknown';
|
||||||
$subject = $meta['subject'] ?? '';
|
$subject = iconv_mime_decode($meta['subject'] ?? '');
|
||||||
$score = $meta['score'] ?? 0;
|
$score = $meta['score'] ?? 0;
|
||||||
$rcpts = $meta['rcpt'] ?? array();
|
$rcpts = $meta['rcpt'] ?? array();
|
||||||
$user = $meta['user'] ?? 'unknown';
|
$user = $meta['user'] ?? 'unknown';
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ $qid = $meta['qid'] ?? 'unknown';
|
|||||||
$rcpts = $meta['rcpt'] ?? array();
|
$rcpts = $meta['rcpt'] ?? array();
|
||||||
$sender = $meta['from'] ?? '';
|
$sender = $meta['from'] ?? '';
|
||||||
$ip = $meta['ip'] ?? 'unknown';
|
$ip = $meta['ip'] ?? 'unknown';
|
||||||
$subject = $meta['subject'] ?? '';
|
$subject = iconv_mime_decode($meta['subject'] ?? '');
|
||||||
$messageid= $meta['message_id'] ?? '';
|
$messageid= $meta['message_id'] ?? '';
|
||||||
$priority = 0;
|
$priority = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -185,9 +185,6 @@ paths:
|
|||||||
example:
|
example:
|
||||||
username: info@domain.tld
|
username: info@domain.tld
|
||||||
domain: domain.tld
|
domain: domain.tld
|
||||||
description: my time limited alias
|
|
||||||
validity: 8760
|
|
||||||
permanent: false
|
|
||||||
properties:
|
properties:
|
||||||
username:
|
username:
|
||||||
description: 'the mailbox an alias should be created for'
|
description: 'the mailbox an alias should be created for'
|
||||||
@@ -195,15 +192,6 @@ paths:
|
|||||||
domain:
|
domain:
|
||||||
description: "the domain"
|
description: "the domain"
|
||||||
type: string
|
type: string
|
||||||
description:
|
|
||||||
description: "a description for the alias, defaults to an empty string"
|
|
||||||
type: string
|
|
||||||
validity:
|
|
||||||
description: "how many hours the alias stays valid, 1 to 87600, defaults to 8760 (one year)"
|
|
||||||
type: integer
|
|
||||||
permanent:
|
|
||||||
description: "keep the alias after it expired, defaults to false"
|
|
||||||
type: boolean
|
|
||||||
type: object
|
type: object
|
||||||
summary: Create time limited alias
|
summary: Create time limited alias
|
||||||
/api/v1/add/app-passwd:
|
/api/v1/add/app-passwd:
|
||||||
@@ -4920,7 +4908,6 @@ paths:
|
|||||||
quota: 3221225472
|
quota: 3221225472
|
||||||
quota_used: 0
|
quota_used: 0
|
||||||
rl: false
|
rl: false
|
||||||
sender_acl: ["otherbox@doman3.tld", "@aliasdomain.tld"]
|
|
||||||
spam_aliases: 0
|
spam_aliases: 0
|
||||||
username: info@doman3.tld
|
username: info@doman3.tld
|
||||||
tags: ["tag1", "tag2"]
|
tags: ["tag1", "tag2"]
|
||||||
@@ -5847,7 +5834,6 @@ paths:
|
|||||||
quota: 3221225472
|
quota: 3221225472
|
||||||
quota_used: 0
|
quota_used: 0
|
||||||
rl: false
|
rl: false
|
||||||
sender_acl: ["otherbox@domain3.tld", "@aliasdomain.tld"]
|
|
||||||
spam_aliases: 0
|
spam_aliases: 0
|
||||||
username: info@domain3.tld
|
username: info@domain3.tld
|
||||||
tags: ["tag1", "tag2"]
|
tags: ["tag1", "tag2"]
|
||||||
@@ -5870,7 +5856,7 @@ paths:
|
|||||||
response:
|
response:
|
||||||
value:
|
value:
|
||||||
- type: "success"
|
- type: "success"
|
||||||
log: ["cors", "edit", {"allowed_origins": ["*", "https://mail.mailcow.tld"], "allowed_methods": ["POST", "GET", "DELETE", "PUT"]}]
|
log: ["cors", "edit", {"allowed_origins": ["*", "mail.mailcow.tld"], "allowed_methods": ["POST", "GET", "DELETE", "PUT"]}]
|
||||||
msg: "cors_headers_edited"
|
msg: "cors_headers_edited"
|
||||||
description: OK
|
description: OK
|
||||||
headers: { }
|
headers: { }
|
||||||
@@ -5887,7 +5873,7 @@ paths:
|
|||||||
schema:
|
schema:
|
||||||
example:
|
example:
|
||||||
attr:
|
attr:
|
||||||
allowed_origins: ["*", "https://mail.mailcow.tld"]
|
allowed_origins: ["*", "mail.mailcow.tld"]
|
||||||
allowed_methods: ["POST", "GET", "DELETE", "PUT"]
|
allowed_methods: ["POST", "GET", "DELETE", "PUT"]
|
||||||
properties:
|
properties:
|
||||||
attr:
|
attr:
|
||||||
|
|||||||
@@ -1,67 +0,0 @@
|
|||||||
<?php
|
|
||||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php';
|
|
||||||
|
|
||||||
header('Content-Type: application/json');
|
|
||||||
|
|
||||||
// Admins only
|
|
||||||
if (!isset($_SESSION['mailcow_cc_role']) || $_SESSION['mailcow_cc_role'] !== 'admin') {
|
|
||||||
http_response_code(403);
|
|
||||||
echo json_encode(array('status' => 'error', 'message' => 'access denied'));
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$owner = $GLOBALS['MAILCOW_GIT_OWNER'];
|
|
||||||
$repo = $GLOBALS['MAILCOW_GIT_REPO'];
|
|
||||||
$current = $GLOBALS['MAILCOW_GIT_VERSION'];
|
|
||||||
|
|
||||||
// Cache key is bound to the running version, so an update invalidates it naturally
|
|
||||||
$cache_key = 'MAILCOW_UPDATE_CHECK/' . $current;
|
|
||||||
|
|
||||||
// Serve cached result if present (one GitHub call per TTL, not one per page load)
|
|
||||||
$cached = $redis->get($cache_key);
|
|
||||||
if ($cached !== false) {
|
|
||||||
echo $cached;
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// GitHub requires a User-Agent and rate-limits unauthenticated requests to 60/h per IP
|
|
||||||
function github_get($url) {
|
|
||||||
$ch = curl_init($url);
|
|
||||||
curl_setopt_array($ch, array(
|
|
||||||
CURLOPT_RETURNTRANSFER => true,
|
|
||||||
CURLOPT_USERAGENT => 'mailcow-update-check',
|
|
||||||
CURLOPT_TIMEOUT => 10,
|
|
||||||
CURLOPT_HTTPHEADER => array('Accept: application/vnd.github+json'),
|
|
||||||
));
|
|
||||||
$body = curl_exec($ch);
|
|
||||||
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
||||||
curl_close($ch);
|
|
||||||
if ($body === false || $code !== 200) return false;
|
|
||||||
$json = json_decode($body, true);
|
|
||||||
return is_array($json) ? $json : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$latest = github_get("https://api.github.com/repos/{$owner}/{$repo}/releases/latest");
|
|
||||||
$release = github_get("https://api.github.com/repos/{$owner}/{$repo}/releases/tags/{$current}");
|
|
||||||
|
|
||||||
// Any failure (rate limit, offline, unexpected payload) -> honest error, cached briefly
|
|
||||||
if ($latest === false || $release === false ||
|
|
||||||
empty($latest['tag_name']) || empty($latest['created_at']) || empty($release['created_at'])) {
|
|
||||||
$result = json_encode(array('status' => 'error', 'message' => 'could not reach GitHub API'));
|
|
||||||
$redis->setex($cache_key, 300, $result);
|
|
||||||
echo $result;
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
$date_latest = strtotime($latest['created_at']);
|
|
||||||
$date_current = strtotime($release['created_at']);
|
|
||||||
|
|
||||||
if ($date_latest <= $date_current) {
|
|
||||||
$result = json_encode(array('status' => 'no_update'));
|
|
||||||
} else {
|
|
||||||
$result = json_encode(array('status' => 'update_available', 'latest_tag' => $latest['tag_name']));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cache the positive result for an hour
|
|
||||||
$redis->setex($cache_key, 3600, $result);
|
|
||||||
echo $result;
|
|
||||||
@@ -429,25 +429,14 @@ function domain_admin_sso($_action, $_data) {
|
|||||||
|
|
||||||
switch ($_action) {
|
switch ($_action) {
|
||||||
case 'check':
|
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 = $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(
|
$stmt->execute(array(
|
||||||
':token' => $token
|
':token' => preg_replace('/[^a-zA-Z0-9-]/', '', $token)
|
||||||
));
|
));
|
||||||
$return = $stmt->fetch(PDO::FETCH_ASSOC);
|
$return = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
if (empty($return['username'])) {
|
return empty($return['username']) ? false : $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'];
|
|
||||||
case 'issue':
|
case 'issue':
|
||||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
|
|||||||
@@ -53,39 +53,6 @@ function valid_network($network) {
|
|||||||
function valid_hostname($hostname) {
|
function valid_hostname($hostname) {
|
||||||
return filter_var($hostname, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME);
|
return filter_var($hostname, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME);
|
||||||
}
|
}
|
||||||
// Validates a browser-style Origin: scheme://host[:port], no path/query/fragment/credentials
|
|
||||||
function valid_origin($origin) {
|
|
||||||
$parts = parse_url($origin);
|
|
||||||
if ($parts === false || !isset($parts['scheme']) || !isset($parts['host'])) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!in_array(strtolower($parts['scheme']), array('http', 'https'), true)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (isset($parts['user']) || isset($parts['pass']) || isset($parts['path']) || isset($parts['query']) || isset($parts['fragment'])) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$host = $parts['host'];
|
|
||||||
$host_without_brackets = trim($host, '[]');
|
|
||||||
if (!valid_hostname($host_without_brackets) && !filter_var($host_without_brackets, FILTER_VALIDATE_IP)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Reject anything that doesn't round-trip to the exact same origin (e.g. stray trailing slash)
|
|
||||||
$port = isset($parts['port']) ? ':' . $parts['port'] : '';
|
|
||||||
$rebuilt = strtolower($parts['scheme']) . '://' . strtolower($host) . $port;
|
|
||||||
return strtolower($origin) === $rebuilt;
|
|
||||||
}
|
|
||||||
// Bring an origin into the exact form a browser sends it (scheme://host[:port], lowercase).
|
|
||||||
function normalize_cors_origin($origin) {
|
|
||||||
$origin = trim($origin);
|
|
||||||
if ($origin === '*') {
|
|
||||||
return '*';
|
|
||||||
}
|
|
||||||
if ($origin !== '' && !preg_match('~^[a-z][a-z0-9+.-]*://~i', $origin)) {
|
|
||||||
$origin = 'https://' . $origin;
|
|
||||||
}
|
|
||||||
return valid_origin($origin) ? strtolower($origin) : false;
|
|
||||||
}
|
|
||||||
// Thanks to https://stackoverflow.com/a/49373789
|
// Thanks to https://stackoverflow.com/a/49373789
|
||||||
// Validates exact ip matches and ip-in-cidr, ipv4 and ipv6
|
// Validates exact ip matches and ip-in-cidr, ipv4 and ipv6
|
||||||
function ip_acl($ip, $networks) {
|
function ip_acl($ip, $networks) {
|
||||||
@@ -2316,13 +2283,10 @@ function cors($action, $data = null) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$allowed_origins = isset($data['allowed_origins']) ? $data['allowed_origins'] : array(getBaseURL());
|
$allowed_origins = isset($data['allowed_origins']) ? $data['allowed_origins'] : array($_SERVER['SERVER_NAME']);
|
||||||
$allowed_origins = !is_array($allowed_origins) ? array_filter(array_map('trim', explode("\n", $allowed_origins))) : $allowed_origins;
|
$allowed_origins = !is_array($allowed_origins) ? array_filter(array_map('trim', explode("\n", $allowed_origins))) : $allowed_origins;
|
||||||
foreach ($allowed_origins as &$origin) {
|
foreach ($allowed_origins as $origin) {
|
||||||
if ($origin === '*') {
|
if (!filter_var($origin, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME) && $origin != '*') {
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!valid_origin($origin)) {
|
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $action, $data),
|
'log' => array(__FUNCTION__, $action, $data),
|
||||||
@@ -2330,10 +2294,7 @@ function cors($action, $data = null) {
|
|||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// browsers always send a lowercase scheme/host in the Origin header, so normalize to match
|
|
||||||
$origin = strtolower($origin);
|
|
||||||
}
|
}
|
||||||
unset($origin);
|
|
||||||
|
|
||||||
$allowed_methods = isset($data['allowed_methods']) ? $data['allowed_methods'] : array('GET', 'POST', 'PUT', 'DELETE');
|
$allowed_methods = isset($data['allowed_methods']) ? $data['allowed_methods'] : array('GET', 'POST', 'PUT', 'DELETE');
|
||||||
$allowed_methods = !is_array($allowed_methods) ? array_map('trim', preg_split( "/( |,|;|\n)/", $allowed_methods)) : $allowed_methods;
|
$allowed_methods = !is_array($allowed_methods) ? array_map('trim', preg_split( "/( |,|;|\n)/", $allowed_methods)) : $allowed_methods;
|
||||||
@@ -2381,35 +2342,26 @@ function cors($action, $data = null) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$cors_settings = !$cors_settings ? array('allowed_origins' => getBaseURL(), 'allowed_methods' => 'GET, POST, PUT, DELETE') : $cors_settings;
|
$cors_settings = !$cors_settings ? array('allowed_origins' => $_SERVER['SERVER_NAME'], 'allowed_methods' => 'GET, POST, PUT, DELETE') : $cors_settings;
|
||||||
$cors_settings['allowed_origins'] = empty($cors_settings['allowed_origins']) ? getBaseURL() : $cors_settings['allowed_origins'];
|
$cors_settings['allowed_origins'] = empty($cors_settings['allowed_origins']) ? $_SERVER['SERVER_NAME'] : $cors_settings['allowed_origins'];
|
||||||
$cors_settings['allowed_methods'] = empty($cors_settings['allowed_methods']) ? 'GET, POST, PUT, DELETE, OPTION' : $cors_settings['allowed_methods'];
|
$cors_settings['allowed_methods'] = empty($cors_settings['allowed_methods']) ? 'GET, POST, PUT, DELETE, OPTION' : $cors_settings['allowed_methods'];
|
||||||
|
|
||||||
return $cors_settings;
|
return $cors_settings;
|
||||||
break;
|
break;
|
||||||
case "set_headers":
|
case "set_headers":
|
||||||
$cors_settings = cors('get');
|
$cors_settings = cors('get');
|
||||||
// normalize the stored list; it may still hold bare hostnames written before origins were validated as origins
|
|
||||||
$allowed_origins = array_filter(array_map('normalize_cors_origin', explode(',', $cors_settings['allowed_origins'])));
|
|
||||||
$origin = isset($_SERVER['HTTP_ORIGIN']) ? normalize_cors_origin($_SERVER['HTTP_ORIGIN']) : false;
|
|
||||||
// check if requested origin is in allowed origins
|
// check if requested origin is in allowed origins
|
||||||
$allow_origin = null;
|
$allowed_origins = explode(', ', $cors_settings['allowed_origins']);
|
||||||
if (in_array('*', $allowed_origins, true)) {
|
$cors_settings['allowed_origins'] = $allowed_origins[0];
|
||||||
$allow_origin = '*';
|
if (in_array('*', $allowed_origins)){
|
||||||
} else if ($origin !== false && in_array($origin, $allowed_origins, true)) {
|
$cors_settings['allowed_origins'] = '*';
|
||||||
$allow_origin = $origin;
|
} else if (array_key_exists('HTTP_ORIGIN', $_SERVER) && in_array($_SERVER['HTTP_ORIGIN'], $allowed_origins)) {
|
||||||
|
$cors_settings['allowed_origins'] = $_SERVER['HTTP_ORIGIN'];
|
||||||
}
|
}
|
||||||
// always allow OPTIONS for preflight request
|
// always allow OPTIONS for preflight request
|
||||||
$cors_settings["allowed_methods"] = empty($cors_settings["allowed_methods"]) ? 'OPTIONS' : $cors_settings["allowed_methods"] . ', ' . 'OPTIONS';
|
$cors_settings["allowed_methods"] = empty($cors_settings["allowed_methods"]) ? 'OPTIONS' : $cors_settings["allowed_methods"] . ', ' . 'OPTIONS';
|
||||||
|
|
||||||
// a disallowed origin gets no Access-Control-Allow-Origin at all; echoing a different origin than the requesting one tells a browser nothing
|
header('Access-Control-Allow-Origin: ' . $cors_settings['allowed_origins']);
|
||||||
if ($allow_origin !== null) {
|
|
||||||
header('Access-Control-Allow-Origin: ' . $allow_origin);
|
|
||||||
}
|
|
||||||
if ($allow_origin !== '*') {
|
|
||||||
// the response depends on the request origin, keep caches from mixing them up
|
|
||||||
header('Vary: Origin', false);
|
|
||||||
}
|
|
||||||
header('Access-Control-Allow-Methods: '. $cors_settings['allowed_methods']);
|
header('Access-Control-Allow-Methods: '. $cors_settings['allowed_methods']);
|
||||||
header('Access-Control-Allow-Headers: Accept, Content-Type, X-Api-Key, Origin');
|
header('Access-Control-Allow-Headers: Accept, Content-Type, X-Api-Key, Origin');
|
||||||
|
|
||||||
|
|||||||
@@ -41,15 +41,13 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
else {
|
else {
|
||||||
$username = $_SESSION['mailcow_cc_username'];
|
$username = $_SESSION['mailcow_cc_username'];
|
||||||
}
|
}
|
||||||
if (isset($_data["validity"])) {
|
if (isset($_data["validity"]) && !filter_var($_data["validity"], FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 87600)))) {
|
||||||
if (!filter_var($_data["validity"], FILTER_VALIDATE_INT, array('options' => array('min_range' => 1, 'max_range' => 87600)))) {
|
$_SESSION['return'][] = array(
|
||||||
$_SESSION['return'][] = array(
|
'type' => 'danger',
|
||||||
'type' => 'danger',
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
'msg' => 'validity_missing'
|
||||||
'msg' => 'validity_missing'
|
);
|
||||||
);
|
return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Default to 1 yr
|
// Default to 1 yr
|
||||||
@@ -62,8 +60,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
$permanent = 0;
|
$permanent = 0;
|
||||||
}
|
}
|
||||||
$domain = $_data['domain'];
|
$domain = $_data['domain'];
|
||||||
// spamalias.description is NOT NULL, an absent description must not become a null insert
|
$description = $_data['description'];
|
||||||
$description = $_data['description'] ?? '';
|
|
||||||
$valid_domains[] = mailbox('get', 'mailbox_details', $username)['domain'];
|
$valid_domains[] = mailbox('get', 'mailbox_details', $username)['domain'];
|
||||||
$valid_alias_domains = user_get_alias_details($username)['alias_domains'];
|
$valid_alias_domains = user_get_alias_details($username)['alias_domains'];
|
||||||
if (!empty($valid_alias_domains)) {
|
if (!empty($valid_alias_domains)) {
|
||||||
@@ -5323,14 +5320,6 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
$mailboxdata['rl_scope'] = 'domain';
|
$mailboxdata['rl_scope'] = 'domain';
|
||||||
}
|
}
|
||||||
$mailboxdata['is_relayed'] = $row['backupmx'];
|
$mailboxdata['is_relayed'] = $row['backupmx'];
|
||||||
// Internal send-as ACL for this mailbox, mirrors the sender_acl field accepted by edit/mailbox
|
|
||||||
$mailboxdata['sender_acl'] = array();
|
|
||||||
$stmt = $pdo->prepare("SELECT `send_as` FROM `sender_acl` WHERE `logged_in_as` = :username AND `external` = '0'");
|
|
||||||
$stmt->execute(array(':username' => $_data));
|
|
||||||
$sender_acl_rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
||||||
foreach ($sender_acl_rows as $sender_acl_row) {
|
|
||||||
$mailboxdata['sender_acl'][] = $sender_acl_row['send_as'];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$stmt = $pdo->prepare("SELECT `tag_name`
|
$stmt = $pdo->prepare("SELECT `tag_name`
|
||||||
FROM `tags_mailbox` WHERE `username`= :username");
|
FROM `tags_mailbox` WHERE `username`= :username");
|
||||||
@@ -5658,11 +5647,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
$stmt->execute(array(
|
$stmt->execute(array(
|
||||||
':username' => $username
|
':username' => $username
|
||||||
));
|
));
|
||||||
// bind LIKE pattern + escape LIKE wildcards so the value matches literally (no SQLi, no over-match)
|
$stmt = $pdo->prepare("DELETE FROM `sogo_acl` WHERE `c_object` LIKE '%/" . $username . "/%' OR `c_uid` = :username");
|
||||||
$c_object_like = '%/' . addcslashes($username, '\\%_') . '/%';
|
|
||||||
$stmt = $pdo->prepare("DELETE FROM `sogo_acl` WHERE `c_object` LIKE :c_object_like OR `c_uid` = :username");
|
|
||||||
$stmt->execute(array(
|
$stmt->execute(array(
|
||||||
':c_object_like' => $c_object_like,
|
|
||||||
':username' => $username
|
':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)");
|
$stmt = $pdo->prepare("DELETE FROM `sogo_store` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
|
||||||
@@ -6058,11 +6044,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
$stmt->execute(array(
|
$stmt->execute(array(
|
||||||
':username' => $username
|
':username' => $username
|
||||||
));
|
));
|
||||||
// bind LIKE pattern + escape LIKE wildcards so the value matches literally (no SQLi, no over-match)
|
$stmt = $pdo->prepare("DELETE FROM `sogo_acl` WHERE `c_object` LIKE '%/" . str_replace('%', '\%', $username) . "/%' OR `c_uid` = :username");
|
||||||
$c_object_like = '%/' . addcslashes($username, '\\%_') . '/%';
|
|
||||||
$stmt = $pdo->prepare("DELETE FROM `sogo_acl` WHERE `c_object` LIKE :c_object_like OR `c_uid` = :username");
|
|
||||||
$stmt->execute(array(
|
$stmt->execute(array(
|
||||||
':c_object_like' => $c_object_like,
|
|
||||||
':username' => $username
|
':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)");
|
$stmt = $pdo->prepare("DELETE FROM `sogo_store` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
|
||||||
@@ -6218,11 +6201,8 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
$stmt->execute(array(
|
$stmt->execute(array(
|
||||||
':username' => $name
|
':username' => $name
|
||||||
));
|
));
|
||||||
// bind LIKE pattern + escape LIKE wildcards so the value matches literally (no SQLi, no over-match)
|
$stmt = $pdo->prepare("DELETE FROM `sogo_acl` WHERE `c_object` LIKE '%/" . $name . "/%' OR `c_uid` = :username");
|
||||||
$c_object_like = '%/' . addcslashes($name, '\\%_') . '/%';
|
|
||||||
$stmt = $pdo->prepare("DELETE FROM `sogo_acl` WHERE `c_object` LIKE :c_object_like OR `c_uid` = :username");
|
|
||||||
$stmt->execute(array(
|
$stmt->execute(array(
|
||||||
':c_object_like' => $c_object_like,
|
|
||||||
':username' => $name
|
':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)");
|
$stmt = $pdo->prepare("DELETE FROM `sogo_store` WHERE `c_folder_id` IN (SELECT `c_folder_id` FROM `sogo_folder_info` WHERE `c_path2` = :username)");
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ function quarantine($_action, $_data = null) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$stmt = $pdo->prepare('SELECT `id` FROM `quarantine` LEFT OUTER JOIN `user_acl` ON `user_acl`.`username` = `rcpt`
|
$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 user_acl.quarantine = 1
|
||||||
AND rcpt IN (SELECT username FROM mailbox)');
|
AND rcpt IN (SELECT username FROM mailbox)');
|
||||||
$stmt->execute(array(':hash' => $hash));
|
$stmt->execute(array(':hash' => $hash));
|
||||||
@@ -65,7 +65,7 @@ function quarantine($_action, $_data = null) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$stmt = $pdo->prepare('SELECT `id` FROM `quarantine` LEFT OUTER JOIN `user_acl` ON `user_acl`.`username` = `rcpt`
|
$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 `user_acl`.`quarantine` = 1
|
||||||
AND `username` IN (SELECT `username` FROM `mailbox`)');
|
AND `username` IN (SELECT `username` FROM `mailbox`)');
|
||||||
$stmt->execute(array(':hash' => $hash));
|
$stmt->execute(array(':hash' => $hash));
|
||||||
@@ -170,8 +170,6 @@ function quarantine($_action, $_data = null) {
|
|||||||
}
|
}
|
||||||
elseif ($release_format == 'raw') {
|
elseif ($release_format == 'raw') {
|
||||||
$detail_row['msg'] = preg_replace('/^X-Spam-Flag: (.*)/m', 'X-Pre-Release-Spam-Flag: $1', $detail_row['msg']);
|
$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(
|
$postfix_talk = array(
|
||||||
array('220', 'HELO quarantine' . chr(10)),
|
array('220', 'HELO quarantine' . chr(10)),
|
||||||
array('250', 'MAIL FROM: ' . $sender . chr(10)),
|
array('250', 'MAIL FROM: ' . $sender . chr(10)),
|
||||||
@@ -182,7 +180,7 @@ function quarantine($_action, $_data = null) {
|
|||||||
array('221', '')
|
array('221', '')
|
||||||
);
|
);
|
||||||
// Thanks to https://stackoverflow.com/questions/6632399/given-an-email-as-raw-text-how-can-i-send-it-using-php
|
// 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) {
|
if (!$smtp_connection) {
|
||||||
logger(array('return' => array(
|
logger(array('return' => array(
|
||||||
array(
|
array(
|
||||||
@@ -194,7 +192,7 @@ function quarantine($_action, $_data = null) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for ($i=0; $i < count($postfix_talk); $i++) {
|
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]) {
|
if (substr($smtp_resource, 0, 3) !== $postfix_talk[$i][0]) {
|
||||||
$ret = substr($smtp_resource, 0, 3);
|
$ret = substr($smtp_resource, 0, 3);
|
||||||
$ret = (empty($ret)) ? '-' : $ret;
|
$ret = (empty($ret)) ? '-' : $ret;
|
||||||
@@ -467,19 +465,17 @@ function quarantine($_action, $_data = null) {
|
|||||||
}
|
}
|
||||||
elseif ($release_format == 'raw') {
|
elseif ($release_format == 'raw') {
|
||||||
$row['msg'] = preg_replace('/^X-Spam-Flag: (.*)/m', 'X-Pre-Release-Spam-Flag: $1', $row['msg']);
|
$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(
|
$postfix_talk = array(
|
||||||
array('220', 'HELO quarantine' . chr(10)),
|
array('220', 'HELO quarantine' . chr(10)),
|
||||||
array('250', 'MAIL FROM: ' . $sender . chr(10)),
|
array('250', 'MAIL FROM: ' . $sender . chr(10)),
|
||||||
array('250', 'RCPT TO: ' . $row['rcpt'] . chr(10)),
|
array('250', 'RCPT TO: ' . $row['rcpt'] . chr(10)),
|
||||||
array('250', 'DATA' . 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('250', 'QUIT' . chr(10)),
|
||||||
array('221', '')
|
array('221', '')
|
||||||
);
|
);
|
||||||
// Thanks to https://stackoverflow.com/questions/6632399/given-an-email-as-raw-text-how-can-i-send-it-using-php
|
// 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) {
|
if (!$smtp_connection) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'warning',
|
'type' => 'warning',
|
||||||
@@ -489,7 +485,7 @@ function quarantine($_action, $_data = null) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for ($i=0; $i < count($postfix_talk); $i++) {
|
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]) {
|
if (substr($smtp_resource, 0, 3) !== $postfix_talk[$i][0]) {
|
||||||
$ret = substr($smtp_resource, 0, 3);
|
$ret = substr($smtp_resource, 0, 3);
|
||||||
$ret = (empty($ret)) ? '-' : $ret;
|
$ret = (empty($ret)) ? '-' : $ret;
|
||||||
@@ -837,7 +833,7 @@ function quarantine($_action, $_data = null) {
|
|||||||
)));
|
)));
|
||||||
return false;
|
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));
|
$stmt->execute(array(':hash' => $hash));
|
||||||
return $stmt->fetch(PDO::FETCH_ASSOC);
|
return $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1464,8 +1464,6 @@ function init_db_schema()
|
|||||||
"pop3_access" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['pop3_access']),
|
"pop3_access" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['pop3_access']),
|
||||||
"smtp_access" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['smtp_access']),
|
"smtp_access" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['smtp_access']),
|
||||||
"sieve_access" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['sieve_access']),
|
"sieve_access" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['sieve_access']),
|
||||||
"eas_access" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['eas_access']),
|
|
||||||
"dav_access" => intval($GLOBALS['MAILBOX_DEFAULT_ATTRIBUTES']['dav_access']),
|
|
||||||
"acl_spam_alias" => 1,
|
"acl_spam_alias" => 1,
|
||||||
"acl_tls_policy" => 1,
|
"acl_tls_policy" => 1,
|
||||||
"acl_spam_score" => 1,
|
"acl_spam_score" => 1,
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ $(document).ready(function() {
|
|||||||
// create host cpu and mem charts
|
// create host cpu and mem charts
|
||||||
createHostCpuAndMemChart();
|
createHostCpuAndMemChart();
|
||||||
// check for new version
|
// check for new version
|
||||||
if (mailcow_info.branch === "master" && mailcow_cc_role === "admin"){
|
if (mailcow_info.branch === "master"){
|
||||||
check_update(mailcow_info.version_tag, mailcow_info.project_url);
|
check_update(mailcow_info.version_tag, mailcow_info.project_url);
|
||||||
}
|
}
|
||||||
$("#mailcow_version").click(function(){
|
$("#mailcow_version").click(function(){
|
||||||
@@ -1089,8 +1089,6 @@ jQuery(function($){
|
|||||||
return str;
|
return str;
|
||||||
}).join('<br>\n');
|
}).join('<br>\n');
|
||||||
item.subject = escapeHtml(item.subject);
|
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);
|
var scan_time = item.time_real.toFixed(3);
|
||||||
if (item.time_virtual) {
|
if (item.time_virtual) {
|
||||||
scan_time += ' / ' + item.time_virtual.toFixed(3);
|
scan_time += ' / ' + item.time_virtual.toFixed(3);
|
||||||
@@ -1214,11 +1212,6 @@ jQuery(function($){
|
|||||||
});
|
});
|
||||||
} else if (table == 'rllog') {
|
} else if (table == 'rllog') {
|
||||||
$.each(data, function (i, item) {
|
$.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) {
|
if (item.user == null) {
|
||||||
item.user = "none";
|
item.user = "none";
|
||||||
}
|
}
|
||||||
@@ -1676,26 +1669,41 @@ function createHostCpuAndMemChart(){
|
|||||||
function check_update(current_version, github_repo_url){
|
function check_update(current_version, github_repo_url){
|
||||||
if (!current_version || !github_repo_url) return false;
|
if (!current_version || !github_repo_url) return false;
|
||||||
|
|
||||||
|
var github_account = github_repo_url.split("/")[3];
|
||||||
|
var github_repo_name = github_repo_url.split("/")[4];
|
||||||
|
|
||||||
window.fetch("/inc/ajax/update_check.php", {method:'GET',cache:'no-cache'}).then(function(response) {
|
// get details about latest release
|
||||||
if (!response.ok) throw new Error("update check returned " + response.status);
|
window.fetch("https://api.github.com/repos/"+github_account+"/"+github_repo_name+"/releases/latest", {method:'GET',cache:'no-cache'}).then(function(response) {
|
||||||
return response.json();
|
return response.json();
|
||||||
}).then(function(data) {
|
}).then(function(latest_data) {
|
||||||
if (data.status === "no_update") {
|
// get details about current release
|
||||||
$("#mailcow_update").removeClass("text-warning text-danger").addClass("text-success");
|
window.fetch("https://api.github.com/repos/"+github_account+"/"+github_repo_name+"/releases/tags/"+current_version, {method:'GET',cache:'no-cache'}).then(function(response) {
|
||||||
$("#mailcow_update").html("<b>" + lang_debug.no_update_available + "</b>");
|
return response.json();
|
||||||
} else if (data.status === "update_available") {
|
}).then(function(current_data) {
|
||||||
$("#mailcow_update").removeClass("text-danger text-success").addClass("text-warning");
|
// compare releases
|
||||||
$("#mailcow_update").html(lang_debug.update_available + ` <a href="#" id="mailcow_update_changelog">`+data.latest_tag+`</a>`);
|
var date_current = new Date(current_data.created_at);
|
||||||
$("#mailcow_update_changelog").click(function(){
|
var date_latest = new Date(latest_data.created_at);
|
||||||
if (mailcow_cc_role !== "admin" && mailcow_cc_role !== "domainadmin")
|
if (date_latest.getTime() <= date_current.getTime()){
|
||||||
return;
|
// no update available
|
||||||
|
$("#mailcow_update").removeClass("text-warning text-danger").addClass("text-success");
|
||||||
|
$("#mailcow_update").html("<b>" + lang_debug.no_update_available + "</b>");
|
||||||
|
} else {
|
||||||
|
// update available
|
||||||
|
$("#mailcow_update").removeClass("text-danger text-success").addClass("text-warning");
|
||||||
|
$("#mailcow_update").html(lang_debug.update_available + ` <a href="#" id="mailcow_update_changelog">`+latest_data.tag_name+`</a>`);
|
||||||
|
$("#mailcow_update_changelog").click(function(){
|
||||||
|
if (mailcow_cc_role !== "admin" && mailcow_cc_role !== "domainadmin")
|
||||||
|
return;
|
||||||
|
|
||||||
showVersionModal("New Release " + data.latest_tag, data.latest_tag);
|
showVersionModal("New Release " + latest_data.tag_name, latest_data.tag_name);
|
||||||
})
|
})
|
||||||
} else {
|
}
|
||||||
throw new Error(data.message || "update check failed");
|
}).catch(err => {
|
||||||
}
|
// err
|
||||||
|
console.log(err);
|
||||||
|
$("#mailcow_update").removeClass("text-success text-warning").addClass("text-danger");
|
||||||
|
$("#mailcow_update").html("<b>"+ lang_debug.update_failed +"</b>");
|
||||||
|
});
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
// err
|
// err
|
||||||
console.log(err);
|
console.log(err);
|
||||||
|
|||||||
@@ -996,7 +996,6 @@ jQuery(function($){
|
|||||||
'style="min-width:2em;width:' + item.percent_in_use + '%">' + item.percent_in_use + '%' + '</div></div>'
|
'style="min-width:2em;width:' + item.percent_in_use + '%">' + item.percent_in_use + '%' + '</div></div>'
|
||||||
};
|
};
|
||||||
item.username = escapeHtml(item.username);
|
item.username = escapeHtml(item.username);
|
||||||
item.name = escapeHtml(item.name);
|
|
||||||
|
|
||||||
if (Array.isArray(item.tags)){
|
if (Array.isArray(item.tags)){
|
||||||
var tags = '';
|
var tags = '';
|
||||||
|
|||||||
@@ -728,7 +728,6 @@
|
|||||||
"mta_sts_mx": "MX-Server",
|
"mta_sts_mx": "MX-Server",
|
||||||
"mta_sts_mx_info": "Erlaubt das Senden nur an explizit aufgeführte Mailserver-Hostnamen; der sendende MTA überprüft, ob der DNS-MX-Hostname mit der Richtlinienliste übereinstimmt, und erlaubt die Zustellung nur mit einem gültigen TLS-Zertifikat (schützt vor MITM).",
|
"mta_sts_mx_info": "Erlaubt das Senden nur an explizit aufgeführte Mailserver-Hostnamen; der sendende MTA überprüft, ob der DNS-MX-Hostname mit der Richtlinienliste übereinstimmt, und erlaubt die Zustellung nur mit einem gültigen TLS-Zertifikat (schützt vor MITM).",
|
||||||
"mta_sts_mx_notice": "Es können mehrere MX-Server angegeben werden (durch Kommas getrennt).",
|
"mta_sts_mx_notice": "Es können mehrere MX-Server angegeben werden (durch Kommas getrennt).",
|
||||||
"mta_sts_active_info": "Wenn nicht angehakt, wird die MTA-STS-Richtlinie nicht veröffentlicht und für die mta-sts-Subdomain kein Zertifikat über ACME angefordert.",
|
|
||||||
"multiple_bookings": "Mehrfaches Buchen",
|
"multiple_bookings": "Mehrfaches Buchen",
|
||||||
"nexthop": "Next Hop",
|
"nexthop": "Next Hop",
|
||||||
"none_inherit": "Keine Auswahl / Erben",
|
"none_inherit": "Keine Auswahl / Erben",
|
||||||
|
|||||||
@@ -728,7 +728,6 @@
|
|||||||
"mta_sts_mx": "MX server",
|
"mta_sts_mx": "MX server",
|
||||||
"mta_sts_mx_info": "Allows sending only to explicitly listed mail server hostnames; the sending MTA checks if the DNS MX hostname matches the policy list, and only allows delivery with a valid TLS certificate (guards against MITM).",
|
"mta_sts_mx_info": "Allows sending only to explicitly listed mail server hostnames; the sending MTA checks if the DNS MX hostname matches the policy list, and only allows delivery with a valid TLS certificate (guards against MITM).",
|
||||||
"mta_sts_mx_notice": "Multiple MX servers can be specified (separated by commas).",
|
"mta_sts_mx_notice": "Multiple MX servers can be specified (separated by commas).",
|
||||||
"mta_sts_active_info": "If unchecked, the MTA-STS policy will not be published and no certificate will be requested for the mta-sts subdomain via ACME.",
|
|
||||||
"multiple_bookings": "Multiple bookings",
|
"multiple_bookings": "Multiple bookings",
|
||||||
"none_inherit": "None / Inherit",
|
"none_inherit": "None / Inherit",
|
||||||
"nexthop": "Next hop",
|
"nexthop": "Next hop",
|
||||||
|
|||||||
+2
-11
@@ -8,12 +8,8 @@ $ALLOW_ADMIN_EMAIL_LOGIN = (preg_match(
|
|||||||
$session_var_user_allowed = 'sogo-sso-user-allowed';
|
$session_var_user_allowed = 'sogo-sso-user-allowed';
|
||||||
$session_var_pass = 'sogo-sso-pass';
|
$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
|
// 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
|
// load prerequisites only when required
|
||||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/prerequisites.inc.php';
|
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']))) {
|
(($_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 (filter_var($login, FILTER_VALIDATE_EMAIL)) {
|
||||||
if (user_get_alias_details($login) !== false) {
|
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)
|
// Block SOGo access if pending actions (2FA setup, password update)
|
||||||
if (!empty($_SESSION['pending_tfa_setup']) || !empty($_SESSION['pending_pw_update'])) {
|
if (!empty($_SESSION['pending_tfa_setup']) || !empty($_SESSION['pending_pw_update'])) {
|
||||||
header("Location: /");
|
header("Location: /");
|
||||||
@@ -89,7 +80,7 @@ elseif (isset($_GET['login'])) {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
// only check for admin-login on sogo GUI requests
|
// 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
|
// this is an nginx auth_request call, we check for existing sogo-sso session variables
|
||||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/vars.inc.php';
|
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/vars.inc.php';
|
||||||
if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/inc/vars.local.inc.php')) {
|
if (file_exists($_SERVER['DOCUMENT_ROOT'] . '/inc/vars.local.inc.php')) {
|
||||||
|
|||||||
@@ -340,7 +340,7 @@
|
|||||||
<div class="row mb-4">
|
<div class="row mb-4">
|
||||||
<div class="offset-sm-2 col-sm-10">
|
<div class="offset-sm-2 col-sm-10">
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<label><i style="font-size: 16px; cursor: pointer;" class="bi bi-patch-question-fill m-2 ms-0" data-bs-toggle="tooltip" data-bs-html="true" data-bs-placement="bottom" title="{{ lang.edit.mta_sts_active_info|raw }}"></i><input type="checkbox" class="form-check-input" value="1" name="active"{% if mta_sts.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
|
<label><input type="checkbox" class="form-check-input" value="1" name="active"{% if mta_sts.active == '1' %} checked{% endif %}> {{ lang.edit.active }}</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+3
-3
@@ -84,7 +84,7 @@ services:
|
|||||||
- clamd
|
- clamd
|
||||||
|
|
||||||
rspamd-mailcow:
|
rspamd-mailcow:
|
||||||
image: ghcr.io/mailcow/rspamd:4.1.4-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
|
||||||
@@ -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.4-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:
|
||||||
@@ -465,7 +465,7 @@ services:
|
|||||||
condition: service_started
|
condition: service_started
|
||||||
unbound-mailcow:
|
unbound-mailcow:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
image: ghcr.io/mailcow/acme:1.98
|
image: ghcr.io/mailcow/acme:1.97
|
||||||
dns:
|
dns:
|
||||||
- ${IPV4_NETWORK:-172.22.1}.254
|
- ${IPV4_NETWORK:-172.22.1}.254
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
Reference in New Issue
Block a user