mirror of
https://github.com/mailcow/mailcow-dockerized.git
synced 2026-10-06 20:27:12 +00:00
Compare commits
33
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
81f6f7b002 | ||
|
|
8cd231c9b9 | ||
|
|
74facc4b5b | ||
|
|
ff6329d01b | ||
|
|
e8209d6504 | ||
|
|
626d006a3d | ||
|
|
e88c734d0a | ||
|
|
86bba266f6 | ||
|
|
e3ed8d2fc2 | ||
|
|
ca07d8d333 | ||
|
|
02552ffefd | ||
|
|
06424670fa | ||
|
|
489db90512 | ||
|
|
641ed63782 | ||
|
|
96a70652c3 | ||
|
|
2ac4b1deae | ||
|
|
1eb6d2e26c | ||
|
|
384e2f6ac1 | ||
|
|
32156a337a | ||
|
|
281cf93db3 | ||
|
|
f399c07c85 | ||
|
|
a693325fe6 | ||
|
|
9ad84eee92 | ||
|
|
b59869b720 | ||
|
|
7515bef66c | ||
|
|
b84ba8ded1 | ||
|
|
4845928e7a | ||
|
|
4ccfedd6b3 | ||
|
|
e8d9315d4a | ||
|
|
d977ddb501 | ||
|
|
e76f5237ed | ||
|
|
c11ed5dd1e | ||
|
|
4ef65fc382 |
No files matched your search
@@ -4,7 +4,7 @@ WORKDIR /src
|
|||||||
ENV CGO_ENABLED=0 \
|
ENV CGO_ENABLED=0 \
|
||||||
GO111MODULE=on \
|
GO111MODULE=on \
|
||||||
NOOPT=1 \
|
NOOPT=1 \
|
||||||
VERSION=1.11.0
|
VERSION=1.14.0
|
||||||
|
|
||||||
RUN git clone --branch v${VERSION} https://github.com/Zuplu/postfix-tlspol && \
|
RUN git clone --branch v${VERSION} https://github.com/Zuplu/postfix-tlspol && \
|
||||||
cd /src/postfix-tlspol && \
|
cd /src/postfix-tlspol && \
|
||||||
|
|||||||
@@ -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.2.1-1~b7a16ae
|
||||||
ARG CODENAME=trixie
|
ARG CODENAME=trixie
|
||||||
ENV LC_ALL=C
|
ENV LC_ALL=C
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Whitelist generated by Postwhite v3.4 on Tue Sep 1 00:34:07 UTC 2026
|
# Whitelist generated by Postwhite v3.4 on Thu Oct 1 00:35:20 UTC 2026
|
||||||
# https://github.com/stevejenkins/postwhite/
|
# https://github.com/stevejenkins/postwhite/
|
||||||
# 2243 total rules
|
# 2246 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
|
||||||
@@ -358,6 +358,7 @@
|
|||||||
64.127.115.252 permit
|
64.127.115.252 permit
|
||||||
64.132.88.0/23 permit
|
64.132.88.0/23 permit
|
||||||
64.132.92.0/24 permit
|
64.132.92.0/24 permit
|
||||||
|
64.181.136.241 permit
|
||||||
64.181.194.190 permit
|
64.181.194.190 permit
|
||||||
64.181.213.254 permit
|
64.181.213.254 permit
|
||||||
64.207.219.7 permit
|
64.207.219.7 permit
|
||||||
@@ -1451,8 +1452,7 @@
|
|||||||
132.226.49.32 permit
|
132.226.49.32 permit
|
||||||
132.226.56.24 permit
|
132.226.56.24 permit
|
||||||
134.98.248.128/25 permit
|
134.98.248.128/25 permit
|
||||||
134.128.64.0/19 permit
|
134.128.64.0/18 permit
|
||||||
134.128.96.0/19 permit
|
|
||||||
134.170.27.8 permit
|
134.170.27.8 permit
|
||||||
134.170.113.0/26 permit
|
134.170.113.0/26 permit
|
||||||
134.170.141.64/26 permit
|
134.170.141.64/26 permit
|
||||||
@@ -1546,7 +1546,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.183 permit
|
150.171.109.178 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
|
||||||
@@ -1573,6 +1573,7 @@
|
|||||||
158.247.100.0/25 permit
|
158.247.100.0/25 permit
|
||||||
159.13.4.0/25 permit
|
159.13.4.0/25 permit
|
||||||
159.13.33.181 permit
|
159.13.33.181 permit
|
||||||
|
159.26.176.0/20 permit
|
||||||
159.92.154.0/24 permit
|
159.92.154.0/24 permit
|
||||||
159.92.155.0/24 permit
|
159.92.155.0/24 permit
|
||||||
159.92.157.0/24 permit
|
159.92.157.0/24 permit
|
||||||
@@ -1706,6 +1707,8 @@
|
|||||||
175.41.215.51 permit
|
175.41.215.51 permit
|
||||||
176.32.105.0/24 permit
|
176.32.105.0/24 permit
|
||||||
176.32.127.0/24 permit
|
176.32.127.0/24 permit
|
||||||
|
176.94.34.32/27 permit
|
||||||
|
176.94.34.64/27 permit
|
||||||
178.236.10.128/26 permit
|
178.236.10.128/26 permit
|
||||||
182.50.76.0/22 permit
|
182.50.76.0/22 permit
|
||||||
182.50.78.64/28 permit
|
182.50.78.64/28 permit
|
||||||
@@ -2225,7 +2228,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:102::1 permit
|
2603:1061:14:1d0::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
|
||||||
|
|||||||
@@ -856,6 +856,8 @@ rspamd_config:register_symbol({
|
|||||||
|
|
||||||
local seen_cte
|
local seen_cte
|
||||||
local newline_s = newline(task)
|
local newline_s = newline(task)
|
||||||
|
-- use the CTE add_text_footer actually applied
|
||||||
|
local new_cte = rewrite.new_cte or 'quoted-printable'
|
||||||
|
|
||||||
local function rewrite_ct_cb(name, hdr)
|
local function rewrite_ct_cb(name, hdr)
|
||||||
if rewrite.need_rewrite_ct then
|
if rewrite.need_rewrite_ct then
|
||||||
@@ -877,13 +879,13 @@ rspamd_config:register_symbol({
|
|||||||
return
|
return
|
||||||
elseif name:lower() == 'content-transfer-encoding' then
|
elseif name:lower() == 'content-transfer-encoding' then
|
||||||
out[#out + 1] = string.format('%s: %s',
|
out[#out + 1] = string.format('%s: %s',
|
||||||
'Content-Transfer-Encoding', 'quoted-printable')
|
'Content-Transfer-Encoding', new_cte)
|
||||||
-- update Content-Transfer-Encoding header
|
-- update Content-Transfer-Encoding header
|
||||||
task:set_milter_reply({
|
task:set_milter_reply({
|
||||||
remove_headers = {['Content-Transfer-Encoding'] = 0},
|
remove_headers = {['Content-Transfer-Encoding'] = 0},
|
||||||
})
|
})
|
||||||
task:set_milter_reply({
|
task:set_milter_reply({
|
||||||
add_headers = {['Content-Transfer-Encoding'] = 'quoted-printable'}
|
add_headers = {['Content-Transfer-Encoding'] = new_cte}
|
||||||
})
|
})
|
||||||
seen_cte = true
|
seen_cte = true
|
||||||
return
|
return
|
||||||
@@ -895,7 +897,7 @@ rspamd_config:register_symbol({
|
|||||||
task:headers_foreach(rewrite_ct_cb, {full = true})
|
task:headers_foreach(rewrite_ct_cb, {full = true})
|
||||||
|
|
||||||
if not seen_cte and rewrite.need_rewrite_ct then
|
if not seen_cte and rewrite.need_rewrite_ct then
|
||||||
out[#out + 1] = string.format('%s: %s', 'Content-Transfer-Encoding', 'quoted-printable')
|
out[#out + 1] = string.format('%s: %s', 'Content-Transfer-Encoding', new_cte)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- End of headers
|
-- End of headers
|
||||||
@@ -914,7 +916,7 @@ rspamd_config:register_symbol({
|
|||||||
out_parts[#out_parts + 1] = o
|
out_parts[#out_parts + 1] = o
|
||||||
out_parts[#out_parts + 1] = newline_s
|
out_parts[#out_parts + 1] = newline_s
|
||||||
else
|
else
|
||||||
local removePrefix = "--\x0D\x0AContent-Type"
|
local removePrefix = "--\x0D\x0AContent-"
|
||||||
if string.lower(string.sub(tostring(o[1]), 1, string.len(removePrefix))) == string.lower(removePrefix) then
|
if string.lower(string.sub(tostring(o[1]), 1, string.len(removePrefix))) == string.lower(removePrefix) then
|
||||||
o[1] = string.sub(tostring(o[1]), string.len("--\x0D\x0A") + 1)
|
o[1] = string.sub(tostring(o[1]), string.len("--\x0D\x0A") + 1)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -153,12 +153,12 @@ foreach ($rcpts as $rcpt) {
|
|||||||
|
|
||||||
// Loop through all found gotos
|
// Loop through all found gotos
|
||||||
foreach ($gotos_array as $index => &$goto) {
|
foreach ($gotos_array as $index => &$goto) {
|
||||||
error_log("RCPT RESOVLER: http pipe: query " . $goto . " as username from mailbox" . PHP_EOL);
|
error_log("RCPT RESOLVER: http pipe: query " . $goto . " as username from mailbox" . PHP_EOL);
|
||||||
$stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `username` = :goto AND (`active`= '1' OR `active`= '2');");
|
$stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `username` = :goto AND (`active`= '1' OR `active`= '2');");
|
||||||
$stmt->execute(array(':goto' => $goto));
|
$stmt->execute(array(':goto' => $goto));
|
||||||
$username = $stmt->fetch(PDO::FETCH_ASSOC)['username'];
|
$username = $stmt->fetch(PDO::FETCH_ASSOC)['username'];
|
||||||
if (!empty($username)) {
|
if (!empty($username)) {
|
||||||
error_log("RCPT RESOVLER: http pipe: mailbox found: " . $username . PHP_EOL);
|
error_log("RCPT RESOLVER: http pipe: mailbox found: " . $username . PHP_EOL);
|
||||||
// Current goto is a mailbox, save to rcpt_final_mailboxes if not a duplicate
|
// Current goto is a mailbox, save to rcpt_final_mailboxes if not a duplicate
|
||||||
if (!in_array($username, $rcpt_final_mailboxes)) {
|
if (!in_array($username, $rcpt_final_mailboxes)) {
|
||||||
$rcpt_final_mailboxes[] = $username;
|
$rcpt_final_mailboxes[] = $username;
|
||||||
@@ -167,21 +167,21 @@ foreach ($rcpts as $rcpt) {
|
|||||||
else {
|
else {
|
||||||
$parsed_goto = parse_email($goto);
|
$parsed_goto = parse_email($goto);
|
||||||
if (!$redis->hGet('DOMAIN_MAP', $parsed_goto['domain'])) {
|
if (!$redis->hGet('DOMAIN_MAP', $parsed_goto['domain'])) {
|
||||||
error_log("RCPT RESOVLER:" . $goto . " is not a mailcow handled mailbox or alias address" . PHP_EOL);
|
error_log("RCPT RESOLVER:" . $goto . " is not a mailcow handled mailbox or alias address" . PHP_EOL);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :goto AND `active` = '1'");
|
$stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :goto AND `active` = '1'");
|
||||||
$stmt->execute(array(':goto' => $goto));
|
$stmt->execute(array(':goto' => $goto));
|
||||||
$goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['goto'];
|
$goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['goto'];
|
||||||
if ($goto_branch) {
|
if ($goto_branch) {
|
||||||
error_log("RCPT RESOVLER: http pipe: goto address " . $goto . " is an alias branch for " . $goto_branch . PHP_EOL);
|
error_log("RCPT RESOLVER: http pipe: goto address " . $goto . " is an alias branch for " . $goto_branch . PHP_EOL);
|
||||||
$goto_branch_array = explode(',', $goto_branch);
|
$goto_branch_array = explode(',', $goto_branch);
|
||||||
} else {
|
} else {
|
||||||
$stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :domain AND `active` = '1'");
|
$stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :domain AND `active` = '1'");
|
||||||
$stmt->execute(array(':domain' => $parsed_goto['domain']));
|
$stmt->execute(array(':domain' => $parsed_goto['domain']));
|
||||||
$goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['target_domain'];
|
$goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['target_domain'];
|
||||||
if ($goto_branch) {
|
if ($goto_branch) {
|
||||||
error_log("RCPT RESOVLER: http pipe: goto domain " . $parsed_goto['domain'] . " is a domain alias branch for " . $goto_branch . PHP_EOL);
|
error_log("RCPT RESOLVER: http pipe: goto domain " . $parsed_goto['domain'] . " is a domain alias branch for " . $goto_branch . PHP_EOL);
|
||||||
$goto_branch_array = array($parsed_goto['local'] . '@' . $goto_branch);
|
$goto_branch_array = array($parsed_goto['local'] . '@' . $goto_branch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -203,11 +203,11 @@ foreach ($rcpts as $rcpt) {
|
|||||||
// Force exit if loop cannot be solved
|
// Force exit if loop cannot be solved
|
||||||
// Postfix does not allow for alias loops, so this should never happen.
|
// Postfix does not allow for alias loops, so this should never happen.
|
||||||
$loop_c++;
|
$loop_c++;
|
||||||
error_log("RCPT RESOVLER: http pipe: goto array count on loop #". $loop_c . " is " . count($gotos_array) . PHP_EOL);
|
error_log("RCPT RESOLVER: http pipe: goto array count on loop #". $loop_c . " is " . count($gotos_array) . PHP_EOL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (PDOException $e) {
|
catch (PDOException $e) {
|
||||||
error_log("RCPT RESOVLER: " . $e->getMessage() . PHP_EOL);
|
error_log("RCPT RESOLVER: " . $e->getMessage() . PHP_EOL);
|
||||||
http_response_code(502);
|
http_response_code(502);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -139,12 +139,12 @@ foreach ($rcpts as $rcpt) {
|
|||||||
|
|
||||||
// Loop through all found gotos
|
// Loop through all found gotos
|
||||||
foreach ($gotos_array as $index => &$goto) {
|
foreach ($gotos_array as $index => &$goto) {
|
||||||
error_log("RCPT RESOVLER: http pipe: query " . $goto . " as username from mailbox" . PHP_EOL);
|
error_log("RCPT RESOLVER: http pipe: query " . $goto . " as username from mailbox" . PHP_EOL);
|
||||||
$stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `username` = :goto AND (`active`= '1' OR `active`= '2');");
|
$stmt = $pdo->prepare("SELECT `username` FROM `mailbox` WHERE `username` = :goto AND (`active`= '1' OR `active`= '2');");
|
||||||
$stmt->execute(array(':goto' => $goto));
|
$stmt->execute(array(':goto' => $goto));
|
||||||
$username = $stmt->fetch(PDO::FETCH_ASSOC)['username'];
|
$username = $stmt->fetch(PDO::FETCH_ASSOC)['username'];
|
||||||
if (!empty($username)) {
|
if (!empty($username)) {
|
||||||
error_log("RCPT RESOVLER: http pipe: mailbox found: " . $username . PHP_EOL);
|
error_log("RCPT RESOLVER: http pipe: mailbox found: " . $username . PHP_EOL);
|
||||||
// Current goto is a mailbox, save to rcpt_final_mailboxes if not a duplicate
|
// Current goto is a mailbox, save to rcpt_final_mailboxes if not a duplicate
|
||||||
if (!in_array($username, $rcpt_final_mailboxes)) {
|
if (!in_array($username, $rcpt_final_mailboxes)) {
|
||||||
$rcpt_final_mailboxes[] = $username;
|
$rcpt_final_mailboxes[] = $username;
|
||||||
@@ -153,21 +153,21 @@ foreach ($rcpts as $rcpt) {
|
|||||||
else {
|
else {
|
||||||
$parsed_goto = parse_email($goto);
|
$parsed_goto = parse_email($goto);
|
||||||
if (!$redis->hGet('DOMAIN_MAP', $parsed_goto['domain'])) {
|
if (!$redis->hGet('DOMAIN_MAP', $parsed_goto['domain'])) {
|
||||||
error_log("RCPT RESOVLER:" . $goto . " is not a mailcow handled mailbox or alias address" . PHP_EOL);
|
error_log("RCPT RESOLVER:" . $goto . " is not a mailcow handled mailbox or alias address" . PHP_EOL);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :goto AND `active` = '1'");
|
$stmt = $pdo->prepare("SELECT `goto` FROM `alias` WHERE `address` = :goto AND `active` = '1'");
|
||||||
$stmt->execute(array(':goto' => $goto));
|
$stmt->execute(array(':goto' => $goto));
|
||||||
$goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['goto'];
|
$goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['goto'];
|
||||||
if ($goto_branch) {
|
if ($goto_branch) {
|
||||||
error_log("RCPT RESOVLER: http pipe: goto address " . $goto . " is an alias branch for " . $goto_branch . PHP_EOL);
|
error_log("RCPT RESOLVER: http pipe: goto address " . $goto . " is an alias branch for " . $goto_branch . PHP_EOL);
|
||||||
$goto_branch_array = explode(',', $goto_branch);
|
$goto_branch_array = explode(',', $goto_branch);
|
||||||
} else {
|
} else {
|
||||||
$stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :domain AND `active` = '1'");
|
$stmt = $pdo->prepare("SELECT `target_domain` FROM `alias_domain` WHERE `alias_domain` = :domain AND `active` = '1'");
|
||||||
$stmt->execute(array(':domain' => $parsed_goto['domain']));
|
$stmt->execute(array(':domain' => $parsed_goto['domain']));
|
||||||
$goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['target_domain'];
|
$goto_branch = $stmt->fetch(PDO::FETCH_ASSOC)['target_domain'];
|
||||||
if ($goto_branch) {
|
if ($goto_branch) {
|
||||||
error_log("RCPT RESOVLER: http pipe: goto domain " . $parsed_goto['domain'] . " is a domain alias branch for " . $goto_branch . PHP_EOL);
|
error_log("RCPT RESOLVER: http pipe: goto domain " . $parsed_goto['domain'] . " is a domain alias branch for " . $goto_branch . PHP_EOL);
|
||||||
$goto_branch_array = array($parsed_goto['local'] . '@' . $goto_branch);
|
$goto_branch_array = array($parsed_goto['local'] . '@' . $goto_branch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -189,11 +189,11 @@ foreach ($rcpts as $rcpt) {
|
|||||||
// Force exit if loop cannot be solved
|
// Force exit if loop cannot be solved
|
||||||
// Postfix does not allow for alias loops, so this should never happen.
|
// Postfix does not allow for alias loops, so this should never happen.
|
||||||
$loop_c++;
|
$loop_c++;
|
||||||
error_log("RCPT RESOVLER: http pipe: goto array count on loop #". $loop_c . " is " . count($gotos_array) . PHP_EOL);
|
error_log("RCPT RESOLVER: http pipe: goto array count on loop #". $loop_c . " is " . count($gotos_array) . PHP_EOL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (PDOException $e) {
|
catch (PDOException $e) {
|
||||||
error_log("RCPT RESOVLER: " . $e->getMessage() . PHP_EOL);
|
error_log("RCPT RESOLVER: " . $e->getMessage() . PHP_EOL);
|
||||||
http_response_code(502);
|
http_response_code(502);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -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.2.1-1
|
||||||
stop_grace_period: 30s
|
stop_grace_period: 30s
|
||||||
depends_on:
|
depends_on:
|
||||||
- dovecot-mailcow
|
- dovecot-mailcow
|
||||||
@@ -382,7 +382,7 @@ services:
|
|||||||
- postfix
|
- postfix
|
||||||
|
|
||||||
postfix-tlspol-mailcow:
|
postfix-tlspol-mailcow:
|
||||||
image: ghcr.io/mailcow/postfix-tlspol:1.11.0
|
image: ghcr.io/mailcow/postfix-tlspol:1.14.0
|
||||||
depends_on:
|
depends_on:
|
||||||
unbound-mailcow:
|
unbound-mailcow:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|||||||
Reference in new issue
Block a user