mirror of
https://github.com/mailcow/mailcow-dockerized.git
synced 2026-02-19 15:46:23 +00:00
Compare commits
39 Commits
feat/valke
...
backup-tri
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6e8a0c24e7 | ||
|
|
07d7e3dc30 | ||
|
|
b0f5aee628 | ||
|
|
d3065612fd | ||
|
|
9912e41f78 | ||
|
|
04200c99a4 | ||
|
|
9a806e64ce | ||
|
|
22a09b9795 | ||
|
|
04d5c43550 | ||
|
|
fbcb8cbeb9 | ||
|
|
0338a36ecf | ||
|
|
23fb5e2fca | ||
|
|
3507ff2773 | ||
|
|
a4970397f1 | ||
|
|
4132f6bd48 | ||
|
|
6af2addf3c | ||
|
|
f6eed6c441 | ||
|
|
b85837c803 | ||
|
|
653fc40d4c | ||
|
|
c17d80a6fd | ||
|
|
980bfa3aa0 | ||
|
|
664a954393 | ||
|
|
d5a27c4ccb | ||
|
|
6a8a2e2136 | ||
|
|
b859a52b8e | ||
|
|
10e0c42eff | ||
|
|
f47df263d7 | ||
|
|
2642d9109e | ||
|
|
6708b94ebb | ||
|
|
3dcacc4187 | ||
|
|
69f0552d4f | ||
|
|
c443a9400a | ||
|
|
5c9f387d94 | ||
|
|
e9414d17e4 | ||
|
|
dd160cd508 | ||
|
|
732b321962 | ||
|
|
2f8a181281 | ||
|
|
83ba8d5840 | ||
|
|
6dc90186f9 |
2
.github/workflows/pr_to_nightly.yml
vendored
2
.github/workflows/pr_to_nightly.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Run the Action
|
||||
uses: devops-infra/action-pull-request@v0.6.1
|
||||
uses: devops-infra/action-pull-request@v1.0.2
|
||||
with:
|
||||
github_token: ${{ secrets.PRTONIGHTLY_ACTION_PAT }}
|
||||
title: Automatic PR to nightly from ${{ github.event.repository.updated_at}}
|
||||
|
||||
@@ -3,14 +3,14 @@ set -o pipefail
|
||||
exec 5>&1
|
||||
|
||||
# Do not attempt to write to slave
|
||||
if [[ ! -z ${VALKEY_SLAVEOF_IP} ]]; then
|
||||
export VALKEY_CMDLINE="redis-cli -h ${VALKEY_SLAVEOF_IP} -p ${VALKEY_SLAVEOF_PORT} -a ${VALKEYPASS} --no-auth-warning"
|
||||
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
|
||||
export REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} -a ${REDISPASS} --no-auth-warning"
|
||||
else
|
||||
export VALKEY_CMDLINE="redis-cli -h valkey-mailcow -p 6379 -a ${VALKEYPASS} --no-auth-warning"
|
||||
export REDIS_CMDLINE="redis-cli -h redis -p 6379 -a ${REDISPASS} --no-auth-warning"
|
||||
fi
|
||||
|
||||
until [[ $(${VALKEY_CMDLINE} PING) == "PONG" ]]; do
|
||||
echo "Waiting for Valkey..."
|
||||
until [[ $(${REDIS_CMDLINE} PING) == "PONG" ]]; do
|
||||
echo "Waiting for Redis..."
|
||||
sleep 2
|
||||
done
|
||||
|
||||
@@ -348,7 +348,7 @@ while true; do
|
||||
if [[ -z ${VALIDATED_CERTIFICATES[*]} ]]; then
|
||||
log_f "Cannot validate any hostnames, skipping Let's Encrypt for 1 hour."
|
||||
log_f "Use SKIP_LETS_ENCRYPT=y in mailcow.conf to skip it permanently."
|
||||
${VALKEY_CMDLINE} SET ACME_FAIL_TIME "$(date +%s)"
|
||||
${REDIS_CMDLINE} SET ACME_FAIL_TIME "$(date +%s)"
|
||||
sleep 1h
|
||||
exec $(readlink -f "$0")
|
||||
fi
|
||||
@@ -389,7 +389,7 @@ while true; do
|
||||
DOVECOT_CERT_SERIAL_NEW="$(echo | openssl s_client -connect dovecot:143 -starttls imap 2>/dev/null | openssl x509 -inform pem -noout -serial | cut -d "=" -f 2)"
|
||||
if [[ ${RELOAD_LOOP_C} -gt 3 ]]; then
|
||||
log_f "Some services do return old end dates, something went wrong!"
|
||||
${VALKEY_CMDLINE} SET ACME_FAIL_TIME "$(date +%s)"
|
||||
${REDIS_CMDLINE} SET ACME_FAIL_TIME "$(date +%s)"
|
||||
break;
|
||||
fi
|
||||
done
|
||||
@@ -410,7 +410,7 @@ while true; do
|
||||
;;
|
||||
*) # non-zero
|
||||
log_f "Some errors occurred, retrying in 30 minutes..."
|
||||
${VALKEY_CMDLINE} SET ACME_FAIL_TIME "$(date +%s)"
|
||||
${REDIS_CMDLINE} SET ACME_FAIL_TIME "$(date +%s)"
|
||||
sleep 30m
|
||||
exec $(readlink -f "$0")
|
||||
;;
|
||||
|
||||
@@ -5,13 +5,13 @@ log_f() {
|
||||
echo -n "$(date) - ${1}"
|
||||
elif [[ ${2} == "no_date" ]]; then
|
||||
echo "${1}"
|
||||
elif [[ ${2} != "valkey_only" ]]; then
|
||||
elif [[ ${2} != "redis_only" ]]; then
|
||||
echo "$(date) - ${1}"
|
||||
fi
|
||||
if [[ ${3} == "b64" ]]; then
|
||||
${VALKEY_CMDLINE} LPUSH ACME_LOG "{\"time\":\"$(date +%s)\",\"message\":\"base64,$(printf '%s' "${MAILCOW_HOSTNAME} - ${1}")\"}" > /dev/null
|
||||
${REDIS_CMDLINE} LPUSH ACME_LOG "{\"time\":\"$(date +%s)\",\"message\":\"base64,$(printf '%s' "${MAILCOW_HOSTNAME} - ${1}")\"}" > /dev/null
|
||||
else
|
||||
${VALKEY_CMDLINE} LPUSH ACME_LOG "{\"time\":\"$(date +%s)\",\"message\":\"$(printf '%s' "${MAILCOW_HOSTNAME} - ${1}" | \
|
||||
${REDIS_CMDLINE} LPUSH ACME_LOG "{\"time\":\"$(date +%s)\",\"message\":\"$(printf '%s' "${MAILCOW_HOSTNAME} - ${1}" | \
|
||||
tr '%&;$"[]{}-\r\n' ' ')\"}" > /dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ ACME_RESPONSE=$(acme-tiny ${DIRECTORY_URL} \
|
||||
--acme-dir /var/www/acme/ 2>&1 > /tmp/_cert.pem | tee /dev/fd/5; exit ${PIPESTATUS[0]})
|
||||
SUCCESS="$?"
|
||||
ACME_RESPONSE_B64=$(echo "${ACME_RESPONSE}" | openssl enc -e -A -base64)
|
||||
log_f "${ACME_RESPONSE_B64}" valkey_only b64
|
||||
log_f "${ACME_RESPONSE_B64}" redis_only b64
|
||||
case "$SUCCESS" in
|
||||
0) # cert requested
|
||||
log_f "Deploying certificate ${CERT}..."
|
||||
@@ -124,7 +124,7 @@ case "$SUCCESS" in
|
||||
;;
|
||||
*) # non-zero is non-fun
|
||||
log_f "Failed to obtain certificate ${CERT} for domains '${CERT_DOMAINS[*]}'"
|
||||
redis-cli -h valkey-mailcow -a ${VALKEYPASS} --no-auth-warning SET ACME_FAIL_TIME "$(date +%s)"
|
||||
redis-cli -h redis -a ${REDISPASS} --no-auth-warning SET ACME_FAIL_TIME "$(date +%s)"
|
||||
exit 100${SUCCESS}
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
FROM debian:bookworm-slim
|
||||
FROM debian:trixie-slim
|
||||
|
||||
RUN apt update && apt install pigz -y --no-install-recommends
|
||||
@@ -32,21 +32,21 @@ async def lifespan(app: FastAPI):
|
||||
|
||||
logger.info("Init APP")
|
||||
|
||||
# Init valkey client
|
||||
if os.environ['VALKEY_SLAVEOF_IP'] != "":
|
||||
valkey_client = valkey = await aioredis.from_url(f"redis://{os.environ['VALKEY_SLAVEOF_IP']}:{os.environ['VALKEY_SLAVEOF_PORT']}/0", password=os.environ['VALKEYPASS'])
|
||||
# Init redis client
|
||||
if os.environ['REDIS_SLAVEOF_IP'] != "":
|
||||
redis_client = redis = await aioredis.from_url(f"redis://{os.environ['REDIS_SLAVEOF_IP']}:{os.environ['REDIS_SLAVEOF_PORT']}/0", password=os.environ['REDISPASS'])
|
||||
else:
|
||||
valkey_client = valkey = await aioredis.from_url("redis://valkey-mailcow:6379/0", password=os.environ['VALKEYPASS'])
|
||||
redis_client = redis = await aioredis.from_url("redis://redis-mailcow:6379/0", password=os.environ['REDISPASS'])
|
||||
|
||||
# Init docker clients
|
||||
sync_docker_client = docker.DockerClient(base_url='unix://var/run/docker.sock', version='auto')
|
||||
async_docker_client = aiodocker.Docker(url='unix:///var/run/docker.sock')
|
||||
|
||||
dockerapi = DockerApi(valkey_client, sync_docker_client, async_docker_client, logger)
|
||||
dockerapi = DockerApi(redis_client, sync_docker_client, async_docker_client, logger)
|
||||
|
||||
logger.info("Subscribe to valkey channel")
|
||||
# Subscribe to valkey channel
|
||||
dockerapi.pubsub = valkey.pubsub()
|
||||
logger.info("Subscribe to redis channel")
|
||||
# Subscribe to redis channel
|
||||
dockerapi.pubsub = redis.pubsub()
|
||||
await dockerapi.pubsub.subscribe("MC_CHANNEL")
|
||||
asyncio.create_task(handle_pubsub_messages(dockerapi.pubsub))
|
||||
|
||||
@@ -57,9 +57,9 @@ async def lifespan(app: FastAPI):
|
||||
dockerapi.sync_docker_client.close()
|
||||
await dockerapi.async_docker_client.close()
|
||||
|
||||
# Close valkey
|
||||
# Close redis
|
||||
await dockerapi.pubsub.unsubscribe("MC_CHANNEL")
|
||||
await dockerapi.valkey_client.close()
|
||||
await dockerapi.redis_client.close()
|
||||
|
||||
app = FastAPI(lifespan=lifespan)
|
||||
|
||||
@@ -73,11 +73,11 @@ async def get_host_update_stats():
|
||||
dockerapi.host_stats_isUpdating = True
|
||||
|
||||
while True:
|
||||
if await dockerapi.valkey_client.exists('host_stats'):
|
||||
if await dockerapi.redis_client.exists('host_stats'):
|
||||
break
|
||||
await asyncio.sleep(1.5)
|
||||
|
||||
stats = json.loads(await dockerapi.valkey_client.get('host_stats'))
|
||||
stats = json.loads(await dockerapi.redis_client.get('host_stats'))
|
||||
return Response(content=json.dumps(stats, indent=4), media_type="application/json")
|
||||
|
||||
@app.get("/containers/{container_id}/json")
|
||||
@@ -185,11 +185,11 @@ async def post_container_update_stats(container_id : str):
|
||||
dockerapi.containerIds_to_update.append(container_id)
|
||||
|
||||
while True:
|
||||
if await dockerapi.valkey_client.exists(container_id + '_stats'):
|
||||
if await dockerapi.redis_client.exists(container_id + '_stats'):
|
||||
break
|
||||
await asyncio.sleep(1.5)
|
||||
|
||||
stats = json.loads(await dockerapi.valkey_client.get(container_id + '_stats'))
|
||||
stats = json.loads(await dockerapi.redis_client.get(container_id + '_stats'))
|
||||
return Response(content=json.dumps(stats, indent=4), media_type="application/json")
|
||||
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@ from datetime import datetime
|
||||
from fastapi import FastAPI, Response, Request
|
||||
|
||||
class DockerApi:
|
||||
def __init__(self, valkey_client, sync_docker_client, async_docker_client, logger):
|
||||
self.valkey_client = valkey_client
|
||||
def __init__(self, redis_client, sync_docker_client, async_docker_client, logger):
|
||||
self.redis_client = redis_client
|
||||
self.sync_docker_client = sync_docker_client
|
||||
self.async_docker_client = async_docker_client
|
||||
self.logger = logger
|
||||
@@ -533,7 +533,7 @@ class DockerApi:
|
||||
"architecture": platform.machine()
|
||||
}
|
||||
|
||||
await self.valkey_client.set('host_stats', json.dumps(host_stats), ex=10)
|
||||
await self.redis_client.set('host_stats', json.dumps(host_stats), ex=10)
|
||||
except Exception as e:
|
||||
res = {
|
||||
"type": "danger",
|
||||
@@ -550,14 +550,14 @@ class DockerApi:
|
||||
if container._id == container_id:
|
||||
res = await container.stats(stream=False)
|
||||
|
||||
if await self.valkey_client.exists(container_id + '_stats'):
|
||||
stats = json.loads(await self.valkey_client.get(container_id + '_stats'))
|
||||
if await self.redis_client.exists(container_id + '_stats'):
|
||||
stats = json.loads(await self.redis_client.get(container_id + '_stats'))
|
||||
else:
|
||||
stats = []
|
||||
stats.append(res[0])
|
||||
if len(stats) > 3:
|
||||
del stats[0]
|
||||
await self.valkey_client.set(container_id + '_stats', json.dumps(stats), ex=60)
|
||||
await self.redis_client.set(container_id + '_stats', json.dumps(stats), ex=60)
|
||||
except Exception as e:
|
||||
res = {
|
||||
"type": "danger",
|
||||
|
||||
@@ -118,7 +118,7 @@ RUN addgroup -g 5000 vmail \
|
||||
COPY trim_logs.sh /usr/local/bin/trim_logs.sh
|
||||
COPY clean_q_aged.sh /usr/local/bin/clean_q_aged.sh
|
||||
COPY syslog-ng.conf /etc/syslog-ng/syslog-ng.conf
|
||||
COPY syslog-ng-valkey_slave.conf /etc/syslog-ng/syslog-ng-valkey_slave.conf
|
||||
COPY syslog-ng-redis_slave.conf /etc/syslog-ng/syslog-ng-redis_slave.conf
|
||||
COPY imapsync /usr/local/bin/imapsync
|
||||
COPY imapsync_runner.pl /usr/local/bin/imapsync_runner.pl
|
||||
COPY report-spam.sieve /usr/lib/dovecot/sieve/report-spam.sieve
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
source /source_env.sh
|
||||
|
||||
MAX_AGE=$(redis-cli --raw -h valkey-mailcow -a ${VALKEYPASS} --no-auth-warning GET Q_MAX_AGE)
|
||||
MAX_AGE=$(redis-cli --raw -h redis-mailcow -a ${REDISPASS} --no-auth-warning GET Q_MAX_AGE)
|
||||
|
||||
if [[ -z ${MAX_AGE} ]]; then
|
||||
echo "Max age for quarantine items not defined"
|
||||
|
||||
@@ -13,18 +13,18 @@ until dig +short mailcow.email > /dev/null; do
|
||||
done
|
||||
|
||||
# Do not attempt to write to slave
|
||||
if [[ ! -z ${VALKEY_SLAVEOF_IP} ]]; then
|
||||
VALKEY_CMDLINE="redis-cli -h ${VALKEY_SLAVEOF_IP} -p ${VALKEY_SLAVEOF_PORT} -a ${VALKEYPASS} --no-auth-warning"
|
||||
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
|
||||
REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} -a ${REDISPASS} --no-auth-warning"
|
||||
else
|
||||
VALKEY_CMDLINE="redis-cli -h valkey-mailcow -p 6379 -a ${VALKEYPASS} --no-auth-warning"
|
||||
REDIS_CMDLINE="redis-cli -h redis -p 6379 -a ${REDISPASS} --no-auth-warning"
|
||||
fi
|
||||
|
||||
until [[ $(${VALKEY_CMDLINE} PING) == "PONG" ]]; do
|
||||
echo "Waiting for Valkey..."
|
||||
until [[ $(${REDIS_CMDLINE} PING) == "PONG" ]]; do
|
||||
echo "Waiting for Redis..."
|
||||
sleep 2
|
||||
done
|
||||
|
||||
${VALKEY_CMDLINE} SET DOVECOT_REPL_HEALTH 1 > /dev/null
|
||||
${REDIS_CMDLINE} SET DOVECOT_REPL_HEALTH 1 > /dev/null
|
||||
|
||||
# Create missing directories
|
||||
[[ ! -d /etc/dovecot/sql/ ]] && mkdir -p /etc/dovecot/sql/
|
||||
@@ -341,8 +341,8 @@ done
|
||||
# May be related to something inside Docker, I seriously don't know
|
||||
touch /etc/dovecot/auth/passwd-verify.lua
|
||||
|
||||
if [[ ! -z ${VALKEY_SLAVEOF_IP} ]]; then
|
||||
cp /etc/syslog-ng/syslog-ng-valkey_slave.conf /etc/syslog-ng/syslog-ng.conf
|
||||
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
|
||||
cp /etc/syslog-ng/syslog-ng-redis_slave.conf /etc/syslog-ng/syslog-ng.conf
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
|
||||
@@ -32,7 +32,7 @@ try:
|
||||
|
||||
while True:
|
||||
try:
|
||||
r = redis.StrictRedis(host='valkey-mailcow', decode_responses=True, port=6379, db=0, password=os.environ['VALKEYPASS'])
|
||||
r = redis.StrictRedis(host='redis', decode_responses=True, port=6379, db=0, password=os.environ['REDISPASS'])
|
||||
r.ping()
|
||||
except Exception as ex:
|
||||
print('%s - trying again...' % (ex))
|
||||
|
||||
@@ -23,7 +23,7 @@ else:
|
||||
|
||||
while True:
|
||||
try:
|
||||
r = redis.StrictRedis(host='valkey-mailcow', decode_responses=True, port=6379, db=0, username='quota_notify', password='')
|
||||
r = redis.StrictRedis(host='redis', decode_responses=True, port=6379, db=0, username='quota_notify', password='')
|
||||
r.ping()
|
||||
except Exception as ex:
|
||||
print('%s - trying again...' % (ex))
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
source /source_env.sh
|
||||
|
||||
# Do not attempt to write to slave
|
||||
if [[ ! -z ${VALKEY_SLAVEOF_IP} ]]; then
|
||||
VALKEY_CMDLINE="redis-cli -h ${VALKEY_SLAVEOF_IP} -p ${VALKEY_SLAVEOF_PORT} -a ${VALKEYPASS} --no-auth-warning"
|
||||
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
|
||||
REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} -a ${REDISPASS} --no-auth-warning"
|
||||
else
|
||||
VALKEY_CMDLINE="redis-cli -h valkey-mailcow -p 6379 -a ${VALKEYPASS} --no-auth-warning"
|
||||
REDIS_CMDLINE="redis-cli -h redis -p 6379 -a ${REDISPASS} --no-auth-warning"
|
||||
fi
|
||||
|
||||
# Is replication active?
|
||||
# grep on file is less expensive than doveconf
|
||||
if [ -n ${MAILCOW_REPLICA_IP} ]; then
|
||||
${VALKEY_CMDLINE} SET DOVECOT_REPL_HEALTH 1 > /dev/null
|
||||
${REDIS_CMDLINE} SET DOVECOT_REPL_HEALTH 1 > /dev/null
|
||||
exit
|
||||
fi
|
||||
|
||||
@@ -22,7 +22,7 @@ FAILED_SYNCS=$(doveadm replicator status | grep "Waiting 'failed' requests" | gr
|
||||
# 1 failed job for mailcow.local is expected and healthy
|
||||
if [[ "${FAILED_SYNCS}" != 0 ]] && [[ "${FAILED_SYNCS}" != 1 ]]; then
|
||||
printf "Dovecot replicator has %d failed jobs\n" "${FAILED_SYNCS}"
|
||||
${VALKEY_CMDLINE} SET DOVECOT_REPL_HEALTH "${FAILED_SYNCS}" > /dev/null
|
||||
${REDIS_CMDLINE} SET DOVECOT_REPL_HEALTH "${FAILED_SYNCS}" > /dev/null
|
||||
else
|
||||
${VALKEY_CMDLINE} SET DOVECOT_REPL_HEALTH 1 > /dev/null
|
||||
${REDIS_CMDLINE} SET DOVECOT_REPL_HEALTH 1 > /dev/null
|
||||
fi
|
||||
|
||||
@@ -15,21 +15,21 @@ source s_dgram {
|
||||
internal();
|
||||
};
|
||||
destination d_stdout { pipe("/dev/stdout"); };
|
||||
destination d_valkey_ui_log {
|
||||
destination d_redis_ui_log {
|
||||
redis(
|
||||
host("`VALKEY_SLAVEOF_IP`")
|
||||
persist-name("valkey1")
|
||||
port(`VALKEY_SLAVEOF_PORT`)
|
||||
auth("`VALKEYPASS`")
|
||||
host("`REDIS_SLAVEOF_IP`")
|
||||
persist-name("redis1")
|
||||
port(`REDIS_SLAVEOF_PORT`)
|
||||
auth("`REDISPASS`")
|
||||
command("LPUSH" "DOVECOT_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
|
||||
);
|
||||
};
|
||||
destination d_valkey_f2b_channel {
|
||||
destination d_redis_f2b_channel {
|
||||
redis(
|
||||
host("`VALKEY_SLAVEOF_IP`")
|
||||
persist-name("valkey2")
|
||||
port(`VALKEY_SLAVEOF_PORT`)
|
||||
auth("`VALKEYPASS`")
|
||||
host("`REDIS_SLAVEOF_IP`")
|
||||
persist-name("redis2")
|
||||
port(`REDIS_SLAVEOF_PORT`)
|
||||
auth("`REDISPASS`")
|
||||
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
|
||||
);
|
||||
};
|
||||
@@ -48,6 +48,6 @@ log {
|
||||
filter(f_replica);
|
||||
destination(d_stdout);
|
||||
filter(f_mail);
|
||||
destination(d_valkey_ui_log);
|
||||
destination(d_valkey_f2b_channel);
|
||||
destination(d_redis_ui_log);
|
||||
destination(d_redis_f2b_channel);
|
||||
};
|
||||
@@ -15,21 +15,21 @@ source s_dgram {
|
||||
internal();
|
||||
};
|
||||
destination d_stdout { pipe("/dev/stdout"); };
|
||||
destination d_valkey_ui_log {
|
||||
destination d_redis_ui_log {
|
||||
redis(
|
||||
host("valkey-mailcow")
|
||||
persist-name("valkey1")
|
||||
host("redis-mailcow")
|
||||
persist-name("redis1")
|
||||
port(6379)
|
||||
auth("`VALKEYPASS`")
|
||||
auth("`REDISPASS`")
|
||||
command("LPUSH" "DOVECOT_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
|
||||
);
|
||||
};
|
||||
destination d_valkey_f2b_channel {
|
||||
destination d_redis_f2b_channel {
|
||||
redis(
|
||||
host("valkey-mailcow")
|
||||
persist-name("valkey2")
|
||||
host("redis-mailcow")
|
||||
persist-name("redis2")
|
||||
port(6379)
|
||||
auth("`VALKEYPASS`")
|
||||
auth("`REDISPASS`")
|
||||
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
|
||||
);
|
||||
};
|
||||
@@ -48,6 +48,6 @@ log {
|
||||
filter(f_replica);
|
||||
destination(d_stdout);
|
||||
filter(f_mail);
|
||||
destination(d_valkey_ui_log);
|
||||
destination(d_valkey_f2b_channel);
|
||||
destination(d_redis_ui_log);
|
||||
destination(d_redis_f2b_channel);
|
||||
};
|
||||
|
||||
@@ -9,17 +9,18 @@ catch_non_zero() {
|
||||
}
|
||||
source /source_env.sh
|
||||
# Do not attempt to write to slave
|
||||
if [[ ! -z ${VALKEY_SLAVEOF_IP} ]]; then
|
||||
VALKEY_CMDLINE="redis-cli -h ${VALKEY_SLAVEOF_IP} -p ${VALKEY_SLAVEOF_PORT} -a ${VALKEYPASS} --no-auth-warning"
|
||||
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
|
||||
REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} -a ${REDISPASS} --no-auth-warning"
|
||||
else
|
||||
VALKEY_CMDLINE="redis-cli -h valkey-mailcow -p 6379 -a ${VALKEYPASS} --no-auth-warning"
|
||||
REDIS_CMDLINE="redis-cli -h redis -p 6379 -a ${REDISPASS} --no-auth-warning"
|
||||
fi
|
||||
catch_non_zero "${VALKEY_CMDLINE} LTRIM ACME_LOG 0 ${LOG_LINES}"
|
||||
catch_non_zero "${VALKEY_CMDLINE} LTRIM POSTFIX_MAILLOG 0 ${LOG_LINES}"
|
||||
catch_non_zero "${VALKEY_CMDLINE} LTRIM DOVECOT_MAILLOG 0 ${LOG_LINES}"
|
||||
catch_non_zero "${VALKEY_CMDLINE} LTRIM SOGO_LOG 0 ${LOG_LINES}"
|
||||
catch_non_zero "${VALKEY_CMDLINE} LTRIM NETFILTER_LOG 0 ${LOG_LINES}"
|
||||
catch_non_zero "${VALKEY_CMDLINE} LTRIM AUTODISCOVER_LOG 0 ${LOG_LINES}"
|
||||
catch_non_zero "${VALKEY_CMDLINE} LTRIM API_LOG 0 ${LOG_LINES}"
|
||||
catch_non_zero "${VALKEY_CMDLINE} LTRIM RL_LOG 0 ${LOG_LINES}"
|
||||
catch_non_zero "${VALKEY_CMDLINE} LTRIM WATCHDOG_LOG 0 ${LOG_LINES}"
|
||||
catch_non_zero "${REDIS_CMDLINE} LTRIM ACME_LOG 0 ${LOG_LINES}"
|
||||
catch_non_zero "${REDIS_CMDLINE} LTRIM POSTFIX_MAILLOG 0 ${LOG_LINES}"
|
||||
catch_non_zero "${REDIS_CMDLINE} LTRIM DOVECOT_MAILLOG 0 ${LOG_LINES}"
|
||||
catch_non_zero "${REDIS_CMDLINE} LTRIM SOGO_LOG 0 ${LOG_LINES}"
|
||||
catch_non_zero "${REDIS_CMDLINE} LTRIM NETFILTER_LOG 0 ${LOG_LINES}"
|
||||
catch_non_zero "${REDIS_CMDLINE} LTRIM AUTODISCOVER_LOG 0 ${LOG_LINES}"
|
||||
catch_non_zero "${REDIS_CMDLINE} LTRIM API_LOG 0 ${LOG_LINES}"
|
||||
catch_non_zero "${REDIS_CMDLINE} LTRIM RL_LOG 0 ${LOG_LINES}"
|
||||
catch_non_zero "${REDIS_CMDLINE} LTRIM WATCHDOG_LOG 0 ${LOG_LINES}"
|
||||
catch_non_zero "${REDIS_CMDLINE} LTRIM CRON_LOG 0 ${LOG_LINES}"
|
||||
|
||||
@@ -44,24 +44,25 @@ def refreshF2boptions():
|
||||
global exit_code
|
||||
f2boptions = {}
|
||||
|
||||
if not valkey.get('F2B_OPTIONS'):
|
||||
f2boptions['ban_time'] = valkey.get('F2B_BAN_TIME')
|
||||
f2boptions['max_ban_time'] = valkey.get('F2B_MAX_BAN_TIME')
|
||||
f2boptions['ban_time_increment'] = valkey.get('F2B_BAN_TIME_INCREMENT')
|
||||
f2boptions['max_attempts'] = valkey.get('F2B_MAX_ATTEMPTS')
|
||||
f2boptions['retry_window'] = valkey.get('F2B_RETRY_WINDOW')
|
||||
f2boptions['netban_ipv4'] = valkey.get('F2B_NETBAN_IPV4')
|
||||
f2boptions['netban_ipv6'] = valkey.get('F2B_NETBAN_IPV6')
|
||||
if not r.get('F2B_OPTIONS'):
|
||||
f2boptions['ban_time'] = r.get('F2B_BAN_TIME')
|
||||
f2boptions['max_ban_time'] = r.get('F2B_MAX_BAN_TIME')
|
||||
f2boptions['ban_time_increment'] = r.get('F2B_BAN_TIME_INCREMENT')
|
||||
f2boptions['max_attempts'] = r.get('F2B_MAX_ATTEMPTS')
|
||||
f2boptions['retry_window'] = r.get('F2B_RETRY_WINDOW')
|
||||
f2boptions['netban_ipv4'] = r.get('F2B_NETBAN_IPV4')
|
||||
f2boptions['netban_ipv6'] = r.get('F2B_NETBAN_IPV6')
|
||||
else:
|
||||
try:
|
||||
f2boptions = json.loads(valkey.get('F2B_OPTIONS'))
|
||||
except ValueError:
|
||||
logger.logCrit('Error loading F2B options: F2B_OPTIONS is not json')
|
||||
f2boptions = json.loads(r.get('F2B_OPTIONS'))
|
||||
except ValueError as e:
|
||||
logger.logCrit(
|
||||
'Error loading F2B options: F2B_OPTIONS is not json. Exception: %s' % e)
|
||||
quit_now = True
|
||||
exit_code = 2
|
||||
|
||||
verifyF2boptions(f2boptions)
|
||||
valkey.set('F2B_OPTIONS', json.dumps(f2boptions, ensure_ascii=False))
|
||||
r.set('F2B_OPTIONS', json.dumps(f2boptions, ensure_ascii=False))
|
||||
|
||||
def verifyF2boptions(f2boptions):
|
||||
verifyF2boption(f2boptions, 'ban_time', 1800)
|
||||
@@ -81,7 +82,7 @@ def refreshF2bregex():
|
||||
global f2bregex
|
||||
global quit_now
|
||||
global exit_code
|
||||
if not valkey.get('F2B_REGEX'):
|
||||
if not r.get('F2B_REGEX'):
|
||||
f2bregex = {}
|
||||
f2bregex[1] = r'mailcow UI: Invalid password for .+ by ([0-9a-f\.:]+)'
|
||||
f2bregex[2] = r'Rspamd UI: Invalid password by ([0-9a-f\.:]+)'
|
||||
@@ -92,11 +93,11 @@ def refreshF2bregex():
|
||||
f2bregex[7] = r'\w+\([^,]+,([0-9a-f\.:]+),<[^>]+>\): unknown user \(SHA1 of given password: [a-f0-9]+\)'
|
||||
f2bregex[8] = r'SOGo.+ Login from \'([0-9a-f\.:]+)\' for user .+ might not have worked'
|
||||
f2bregex[9] = r'([0-9a-f\.:]+) \"GET \/SOGo\/.* HTTP.+\" 403 .+'
|
||||
valkey.set('F2B_REGEX', json.dumps(f2bregex, ensure_ascii=False))
|
||||
r.set('F2B_REGEX', json.dumps(f2bregex, ensure_ascii=False))
|
||||
else:
|
||||
try:
|
||||
f2bregex = {}
|
||||
f2bregex = json.loads(valkey.get('F2B_REGEX'))
|
||||
f2bregex = json.loads(r.get('F2B_REGEX'))
|
||||
except ValueError:
|
||||
logger.logCrit('Error loading F2B options: F2B_REGEX is not json')
|
||||
quit_now = True
|
||||
@@ -175,7 +176,7 @@ def ban(address):
|
||||
|
||||
logdebug("Updating F2B_ACTIVE_BANS[%s]=%d" %
|
||||
(net, cur_time + NET_BAN_TIME))
|
||||
valkey.hset('F2B_ACTIVE_BANS', '%s' % net, cur_time + NET_BAN_TIME)
|
||||
r.hset('F2B_ACTIVE_BANS', '%s' % net, cur_time + NET_BAN_TIME)
|
||||
else:
|
||||
logger.logWarn('%d more attempts in the next %d seconds until %s is banned' % (
|
||||
MAX_ATTEMPTS - bans[net]['attempts'], RETRY_WINDOW, net))
|
||||
@@ -186,7 +187,7 @@ def unban(net):
|
||||
if not net in bans:
|
||||
logger.logInfo(
|
||||
'%s is not banned, skipping unban and deleting from queue (if any)' % net)
|
||||
valkey.hdel('F2B_QUEUE_UNBAN', '%s' % net)
|
||||
r.hdel('F2B_QUEUE_UNBAN', '%s' % net)
|
||||
return
|
||||
logger.logInfo('Unbanning %s' % net)
|
||||
if type(ipaddress.ip_network(net)) is ipaddress.IPv4Network:
|
||||
@@ -197,8 +198,8 @@ def unban(net):
|
||||
with lock:
|
||||
logdebug("Calling tables.unbanIPv6(%s)" % net)
|
||||
tables.unbanIPv6(net)
|
||||
valkey.hdel('F2B_ACTIVE_BANS', '%s' % net)
|
||||
valkey.hdel('F2B_QUEUE_UNBAN', '%s' % net)
|
||||
r.hdel('F2B_ACTIVE_BANS', '%s' % net)
|
||||
r.hdel('F2B_QUEUE_UNBAN', '%s' % net)
|
||||
if net in bans:
|
||||
logdebug("Unban for %s, setting attempts=0, ban_counter+=1" % net)
|
||||
bans[net]['attempts'] = 0
|
||||
@@ -225,10 +226,10 @@ def permBan(net, unban=False):
|
||||
|
||||
|
||||
if is_unbanned:
|
||||
valkey.hdel('F2B_PERM_BANS', '%s' % net)
|
||||
r.hdel('F2B_PERM_BANS', '%s' % net)
|
||||
logger.logCrit('Removed host/network %s from denylist' % net)
|
||||
elif is_banned:
|
||||
valkey.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time())))
|
||||
r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time())))
|
||||
logger.logCrit('Added host/network %s to denylist' % net)
|
||||
|
||||
def clear():
|
||||
@@ -243,17 +244,17 @@ def clear():
|
||||
tables.clearIPv6Table()
|
||||
try:
|
||||
if r is not None:
|
||||
valkey.delete('F2B_ACTIVE_BANS')
|
||||
valkey.delete('F2B_PERM_BANS')
|
||||
r.delete('F2B_ACTIVE_BANS')
|
||||
r.delete('F2B_PERM_BANS')
|
||||
except Exception as ex:
|
||||
logger.logWarn('Error clearing valkey keys F2B_ACTIVE_BANS and F2B_PERM_BANS: %s' % ex)
|
||||
logger.logWarn('Error clearing redis keys F2B_ACTIVE_BANS and F2B_PERM_BANS: %s' % ex)
|
||||
|
||||
def watch():
|
||||
global pubsub
|
||||
global quit_now
|
||||
global exit_code
|
||||
|
||||
logger.logInfo('Watching Valkey channel F2B_CHANNEL')
|
||||
logger.logInfo('Watching Redis channel F2B_CHANNEL')
|
||||
pubsub.subscribe('F2B_CHANNEL')
|
||||
|
||||
while not quit_now:
|
||||
@@ -305,7 +306,7 @@ def autopurge():
|
||||
time.sleep(10)
|
||||
refreshF2boptions()
|
||||
MAX_ATTEMPTS = int(f2boptions['max_attempts'])
|
||||
QUEUE_UNBAN = valkey.hgetall('F2B_QUEUE_UNBAN')
|
||||
QUEUE_UNBAN = r.hgetall('F2B_QUEUE_UNBAN')
|
||||
logdebug("QUEUE_UNBAN: %s" % QUEUE_UNBAN)
|
||||
if QUEUE_UNBAN:
|
||||
for net in QUEUE_UNBAN:
|
||||
@@ -390,7 +391,7 @@ def whitelistUpdate():
|
||||
global WHITELIST
|
||||
while not quit_now:
|
||||
start_time = time.time()
|
||||
list = valkey.hgetall('F2B_WHITELIST')
|
||||
list = r.hgetall('F2B_WHITELIST')
|
||||
new_whitelist = []
|
||||
if list:
|
||||
new_whitelist = genNetworkList(list)
|
||||
@@ -405,7 +406,7 @@ def blacklistUpdate():
|
||||
global BLACKLIST
|
||||
while not quit_now:
|
||||
start_time = time.time()
|
||||
list = valkey.hgetall('F2B_BLACKLIST')
|
||||
list = r.hgetall('F2B_BLACKLIST')
|
||||
new_blacklist = []
|
||||
if list:
|
||||
new_blacklist = genNetworkList(list)
|
||||
@@ -466,35 +467,35 @@ if __name__ == '__main__':
|
||||
logger.logInfo(f"Setting {chain_name} isolation")
|
||||
tables.create_mailcow_isolation_rule("br-mailcow", [3306, 6379, 8983, 12345], os.getenv("MAILCOW_REPLICA_IP"))
|
||||
|
||||
# connect to valkey
|
||||
# connect to redis
|
||||
while True:
|
||||
try:
|
||||
valkey_slaveof_ip = os.getenv('VALKEY_SLAVEOF_IP', '')
|
||||
valkey_slaveof_port = os.getenv('VALKEY_SLAVEOF_PORT', '')
|
||||
redis_slaveof_ip = os.getenv('REDIS_SLAVEOF_IP', '')
|
||||
redis_slaveof_port = os.getenv('REDIS_SLAVEOF_PORT', '')
|
||||
logdebug(
|
||||
"Connecting valkey (SLAVEOF_IP:%s, PORT:%s)" % (valkey_slaveof_ip, valkey_slaveof_port))
|
||||
if "".__eq__(valkey_slaveof_ip):
|
||||
valkey = redis.StrictRedis(
|
||||
host=os.getenv('IPV4_NETWORK', '172.22.1') + '.249', decode_responses=True, port=6379, db=0, password=os.environ['VALKEYPASS'])
|
||||
"Connecting redis (SLAVEOF_IP:%s, PORT:%s)" % (redis_slaveof_ip, redis_slaveof_port))
|
||||
if "".__eq__(redis_slaveof_ip):
|
||||
r = redis.StrictRedis(
|
||||
host=os.getenv('IPV4_NETWORK', '172.22.1') + '.249', decode_responses=True, port=6379, db=0, password=os.environ['REDISPASS'])
|
||||
else:
|
||||
valkey = redis.StrictRedis(
|
||||
host=valkey_slaveof_ip, decode_responses=True, port=valkey_slaveof_port, db=0, password=os.environ['VALKEYPASS'])
|
||||
valkey.ping()
|
||||
pubsub = valkey.pubsub()
|
||||
r = redis.StrictRedis(
|
||||
host=redis_slaveof_ip, decode_responses=True, port=redis_slaveof_port, db=0, password=os.environ['REDISPASS'])
|
||||
r.ping()
|
||||
pubsub = r.pubsub()
|
||||
except Exception as ex:
|
||||
logdebug(
|
||||
'Redis connection failed: %s - trying again in 3 seconds' % (ex))
|
||||
time.sleep(3)
|
||||
else:
|
||||
break
|
||||
logger.set_valkey(valkey)
|
||||
logdebug("Valkey connection established, setting up F2B keys")
|
||||
logger.set_redis(r)
|
||||
logdebug("Redis connection established, setting up F2B keys")
|
||||
|
||||
if valkey.exists('F2B_LOG'):
|
||||
if r.exists('F2B_LOG'):
|
||||
logdebug("Renaming F2B_LOG to NETFILTER_LOG")
|
||||
valkey.rename('F2B_LOG', 'NETFILTER_LOG')
|
||||
valkey.delete('F2B_ACTIVE_BANS')
|
||||
valkey.delete('F2B_PERM_BANS')
|
||||
r.rename('F2B_LOG', 'NETFILTER_LOG')
|
||||
r.delete('F2B_ACTIVE_BANS')
|
||||
r.delete('F2B_PERM_BANS')
|
||||
|
||||
refreshF2boptions()
|
||||
|
||||
|
||||
@@ -4,19 +4,19 @@ import datetime
|
||||
|
||||
class Logger:
|
||||
def __init__(self):
|
||||
self.valkey = None
|
||||
self.r = None
|
||||
|
||||
def set_valkey(self, valkey):
|
||||
self.valkey = valkey
|
||||
def set_redis(self, redis):
|
||||
self.r = redis
|
||||
|
||||
def _format_timestamp(self):
|
||||
# Local time with milliseconds
|
||||
return datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
def log(self, priority, message):
|
||||
# build valkey-friendly dict
|
||||
# build redis-friendly dict
|
||||
tolog = {
|
||||
'time': int(round(time.time())), # keep raw timestamp for Valkey
|
||||
'time': int(round(time.time())), # keep raw timestamp for Redis
|
||||
'priority': priority,
|
||||
'message': message
|
||||
}
|
||||
@@ -26,11 +26,11 @@ class Logger:
|
||||
print(f"{ts} {priority.upper()}: {message}", flush=True)
|
||||
|
||||
# also push JSON to Redis if connected
|
||||
if self.valkey is not None:
|
||||
if self.r is not None:
|
||||
try:
|
||||
self.valkey.lpush('NETFILTER_LOG', json.dumps(tolog, ensure_ascii=False))
|
||||
self.r.lpush('NETFILTER_LOG', json.dumps(tolog, ensure_ascii=False))
|
||||
except Exception as ex:
|
||||
print(f'{ts} WARN: Failed logging to valkey: {ex}', flush=True)
|
||||
print(f'{ts} WARN: Failed logging to redis: {ex}', flush=True)
|
||||
|
||||
def logWarn(self, message):
|
||||
self.log('warn', message)
|
||||
|
||||
@@ -3,11 +3,11 @@ FROM php:8.2-fpm-alpine3.21
|
||||
LABEL maintainer = "The Infrastructure Company GmbH <info@servercow.de>"
|
||||
|
||||
# renovate: datasource=github-tags depName=krakjoe/apcu versioning=semver-coerced extractVersion=^v(?<version>.*)$
|
||||
ARG APCU_PECL_VERSION=5.1.26
|
||||
ARG APCU_PECL_VERSION=5.1.27
|
||||
# renovate: datasource=github-tags depName=Imagick/imagick versioning=semver-coerced extractVersion=(?<version>.*)$
|
||||
ARG IMAGICK_PECL_VERSION=3.8.0
|
||||
# renovate: datasource=github-tags depName=php/pecl-mail-mailparse versioning=semver-coerced extractVersion=^v(?<version>.*)$
|
||||
ARG MAILPARSE_PECL_VERSION=3.1.8
|
||||
ARG MAILPARSE_PECL_VERSION=3.1.9
|
||||
# renovate: datasource=github-tags depName=php-memcached-dev/php-memcached versioning=semver-coerced extractVersion=^v(?<version>.*)$
|
||||
ARG MEMCACHED_PECL_VERSION=3.3.0
|
||||
# renovate: datasource=github-tags depName=phpredis/phpredis versioning=semver-coerced extractVersion=(?<version>.*)$
|
||||
|
||||
@@ -9,24 +9,24 @@ while ! mariadb-admin status --ssl=false --socket=/var/run/mysqld/mysqld.sock -u
|
||||
done
|
||||
|
||||
# Do not attempt to write to slave
|
||||
if [[ ! -z ${VALKEY_SLAVEOF_IP} ]]; then
|
||||
VALKEY_HOST=$VALKEY_SLAVEOF_IP
|
||||
VALKEY_PORT=$VALKEY_SLAVEOF_PORT
|
||||
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
|
||||
REDIS_HOST=$REDIS_SLAVEOF_IP
|
||||
REDIS_PORT=$REDIS_SLAVEOF_PORT
|
||||
else
|
||||
VALKEY_HOST="valkey-mailcow"
|
||||
VALKEY_PORT="6379"
|
||||
REDIS_HOST="redis"
|
||||
REDIS_PORT="6379"
|
||||
fi
|
||||
VALKEY_CMDLINE="redis-cli -h ${VALKEY_HOST} -p ${VALKEY_PORT} -a ${VALKEYPASS} --no-auth-warning"
|
||||
REDIS_CMDLINE="redis-cli -h ${REDIS_HOST} -p ${REDIS_PORT} -a ${REDISPASS} --no-auth-warning"
|
||||
|
||||
until [[ $(${VALKEY_CMDLINE} PING) == "PONG" ]]; do
|
||||
echo "Waiting for Valkey..."
|
||||
until [[ $(${REDIS_CMDLINE} PING) == "PONG" ]]; do
|
||||
echo "Waiting for Redis..."
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Set valkey session store
|
||||
# Set redis session store
|
||||
echo -n '
|
||||
session.save_handler = redis
|
||||
session.save_path = "tcp://'${VALKEY_HOST}':'${VALKEY_PORT}'?auth='${VALKEYPASS}'"
|
||||
session.save_path = "tcp://'${REDIS_HOST}':'${REDIS_PORT}'?auth='${REDISPASS}'"
|
||||
' > /usr/local/etc/php/conf.d/session_store.ini
|
||||
|
||||
# Check mysql_upgrade (master and slave)
|
||||
@@ -91,22 +91,22 @@ fi
|
||||
if [[ "${MASTER}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
||||
echo "We are master, preparing..."
|
||||
# Set a default release format
|
||||
if [[ -z $(${VALKEY_CMDLINE} --raw GET Q_RELEASE_FORMAT) ]]; then
|
||||
${VALKEY_CMDLINE} --raw SET Q_RELEASE_FORMAT raw
|
||||
if [[ -z $(${REDIS_CMDLINE} --raw GET Q_RELEASE_FORMAT) ]]; then
|
||||
${REDIS_CMDLINE} --raw SET Q_RELEASE_FORMAT raw
|
||||
fi
|
||||
|
||||
# Set max age of q items - if unset
|
||||
if [[ -z $(${VALKEY_CMDLINE} --raw GET Q_MAX_AGE) ]]; then
|
||||
${VALKEY_CMDLINE} --raw SET Q_MAX_AGE 365
|
||||
if [[ -z $(${REDIS_CMDLINE} --raw GET Q_MAX_AGE) ]]; then
|
||||
${REDIS_CMDLINE} --raw SET Q_MAX_AGE 365
|
||||
fi
|
||||
|
||||
# Set default password policy - if unset
|
||||
if [[ -z $(${VALKEY_CMDLINE} --raw HGET PASSWD_POLICY length) ]]; then
|
||||
${VALKEY_CMDLINE} --raw HSET PASSWD_POLICY length 6
|
||||
${VALKEY_CMDLINE} --raw HSET PASSWD_POLICY chars 0
|
||||
${VALKEY_CMDLINE} --raw HSET PASSWD_POLICY special_chars 0
|
||||
${VALKEY_CMDLINE} --raw HSET PASSWD_POLICY lowerupper 0
|
||||
${VALKEY_CMDLINE} --raw HSET PASSWD_POLICY numbers 0
|
||||
if [[ -z $(${REDIS_CMDLINE} --raw HGET PASSWD_POLICY length) ]]; then
|
||||
${REDIS_CMDLINE} --raw HSET PASSWD_POLICY length 6
|
||||
${REDIS_CMDLINE} --raw HSET PASSWD_POLICY chars 0
|
||||
${REDIS_CMDLINE} --raw HSET PASSWD_POLICY special_chars 0
|
||||
${REDIS_CMDLINE} --raw HSET PASSWD_POLICY lowerupper 0
|
||||
${REDIS_CMDLINE} --raw HSET PASSWD_POLICY numbers 0
|
||||
fi
|
||||
|
||||
# Trigger db init
|
||||
@@ -114,9 +114,9 @@ if [[ "${MASTER}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
||||
php -c /usr/local/etc/php -f /web/inc/init_db.inc.php
|
||||
|
||||
# Recreating domain map
|
||||
echo "Rebuilding domain map in Valkey..."
|
||||
echo "Rebuilding domain map in Redis..."
|
||||
declare -a DOMAIN_ARR
|
||||
${VALKEY_CMDLINE} DEL DOMAIN_MAP > /dev/null
|
||||
${REDIS_CMDLINE} DEL DOMAIN_MAP > /dev/null
|
||||
while read line
|
||||
do
|
||||
DOMAIN_ARR+=("$line")
|
||||
@@ -128,7 +128,7 @@ if [[ "${MASTER}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
||||
|
||||
if [[ ! -z ${DOMAIN_ARR} ]]; then
|
||||
for domain in "${DOMAIN_ARR[@]}"; do
|
||||
${VALKEY_CMDLINE} HSET DOMAIN_MAP ${domain} 1 > /dev/null
|
||||
${REDIS_CMDLINE} HSET DOMAIN_MAP ${domain} 1 > /dev/null
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
|
||||
COPY supervisord.conf /etc/supervisor/supervisord.conf
|
||||
COPY syslog-ng.conf /etc/syslog-ng/syslog-ng.conf
|
||||
COPY syslog-ng-valkey_slave.conf /etc/syslog-ng/syslog-ng-valkey_slave.conf
|
||||
COPY syslog-ng-redis_slave.conf /etc/syslog-ng/syslog-ng-redis_slave.conf
|
||||
COPY postfix-tlspol.sh /opt/postfix-tlspol.sh
|
||||
COPY stop-supervisor.sh /usr/local/sbin/stop-supervisor.sh
|
||||
COPY docker-entrypoint.sh /docker-entrypoint.sh
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [[ ! -z ${VALKEY_SLAVEOF_IP} ]]; then
|
||||
cp /etc/syslog-ng/syslog-ng-valkey_slave.conf /etc/syslog-ng/syslog-ng.conf
|
||||
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
|
||||
cp /etc/syslog-ng/syslog-ng-redis_slave.conf /etc/syslog-ng/syslog-ng.conf
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
@@ -17,14 +17,14 @@ until dig +short mailcow.email > /dev/null; do
|
||||
done
|
||||
|
||||
# Do not attempt to write to slave
|
||||
if [[ ! -z ${VALKEY_SLAVEOF_IP} ]]; then
|
||||
export VALKEY_CMDLINE="redis-cli -h ${VALKEY_SLAVEOF_IP} -p ${VALKEY_SLAVEOF_PORT} -a ${VALKEYPASS} --no-auth-warning"
|
||||
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
|
||||
export REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} -a ${REDISPASS} --no-auth-warning"
|
||||
else
|
||||
export VALKEY_CMDLINE="redis-cli -h valkey -p 6379 -a ${VALKEYPASS} --no-auth-warning"
|
||||
export REDIS_CMDLINE="redis-cli -h redis -p 6379 -a ${REDISPASS} --no-auth-warning"
|
||||
fi
|
||||
|
||||
until [[ $(${VALKEY_CMDLINE} PING) == "PONG" ]]; do
|
||||
echo "Waiting for Valkey..."
|
||||
until [[ $(${REDIS_CMDLINE} PING) == "PONG" ]]; do
|
||||
echo "Waiting for Redis..."
|
||||
sleep 2
|
||||
done
|
||||
|
||||
|
||||
@@ -15,12 +15,12 @@ source s_src {
|
||||
internal();
|
||||
};
|
||||
destination d_stdout { pipe("/dev/stdout"); };
|
||||
destination d_valkey_ui_log {
|
||||
destination d_redis_ui_log {
|
||||
redis(
|
||||
host("`VALKEY_SLAVEOF_IP`")
|
||||
persist-name("valkey1")
|
||||
port(`VALKEY_SLAVEOF_PORT`)
|
||||
auth("`VALKEYPASS`")
|
||||
host("`REDIS_SLAVEOF_IP`")
|
||||
persist-name("redis1")
|
||||
port(`REDIS_SLAVEOF_PORT`)
|
||||
auth("`REDISPASS`")
|
||||
command("LPUSH" "POSTFIX_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
|
||||
);
|
||||
};
|
||||
@@ -41,5 +41,5 @@ log {
|
||||
filter(f_ignore);
|
||||
destination(d_stdout);
|
||||
filter(f_mail);
|
||||
destination(d_valkey_ui_log);
|
||||
destination(d_redis_ui_log);
|
||||
};
|
||||
@@ -15,12 +15,12 @@ source s_src {
|
||||
internal();
|
||||
};
|
||||
destination d_stdout { pipe("/dev/stdout"); };
|
||||
destination d_valkey_ui_log {
|
||||
destination d_redis_ui_log {
|
||||
redis(
|
||||
host("valkey-mailcow")
|
||||
persist-name("valkey1")
|
||||
host("redis-mailcow")
|
||||
persist-name("redis1")
|
||||
port(6379)
|
||||
auth("`VALKEYPASS`")
|
||||
auth("`REDISPASS`")
|
||||
command("LPUSH" "POSTFIX_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
|
||||
);
|
||||
};
|
||||
@@ -41,5 +41,5 @@ log {
|
||||
filter(f_ignore);
|
||||
destination(d_stdout);
|
||||
filter(f_mail);
|
||||
destination(d_valkey_ui_log);
|
||||
destination(d_redis_ui_log);
|
||||
};
|
||||
|
||||
@@ -41,7 +41,7 @@ RUN groupadd -g 102 postfix \
|
||||
|
||||
COPY supervisord.conf /etc/supervisor/supervisord.conf
|
||||
COPY syslog-ng.conf /etc/syslog-ng/syslog-ng.conf
|
||||
COPY syslog-ng-valkey_slave.conf /etc/syslog-ng/syslog-ng-valkey_slave.conf
|
||||
COPY syslog-ng-redis_slave.conf /etc/syslog-ng/syslog-ng-redis_slave.conf
|
||||
COPY postfix.sh /opt/postfix.sh
|
||||
COPY rspamd-pipe-ham /usr/local/bin/rspamd-pipe-ham
|
||||
COPY rspamd-pipe-spam /usr/local/bin/rspamd-pipe-spam
|
||||
|
||||
@@ -8,8 +8,8 @@ for file in /hooks/*; do
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ ! -z ${VALKEY_SLAVEOF_IP} ]]; then
|
||||
cp /etc/syslog-ng/syslog-ng-valkey_slave.conf /etc/syslog-ng/syslog-ng.conf
|
||||
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
|
||||
cp /etc/syslog-ng/syslog-ng-redis_slave.conf /etc/syslog-ng/syslog-ng.conf
|
||||
fi
|
||||
|
||||
# Fix OpenSSL 3.X TLS1.0, 1.1 support (https://community.mailcow.email/d/4062-hi-all/20)
|
||||
@@ -21,6 +21,6 @@ if grep -qE '\!SSLv2|\!SSLv3|>=TLSv1(\.[0-1])?$' /opt/postfix/conf/main.cf /opt/
|
||||
echo "[tls_system_default]" >> /etc/ssl/openssl.cnf
|
||||
echo "MinProtocol = TLSv1" >> /etc/ssl/openssl.cnf
|
||||
echo "CipherString = DEFAULT@SECLEVEL=0" >> /etc/ssl/openssl.cnf
|
||||
fi
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
|
||||
@@ -15,21 +15,21 @@ source s_src {
|
||||
internal();
|
||||
};
|
||||
destination d_stdout { pipe("/dev/stdout"); };
|
||||
destination d_valkey_ui_log {
|
||||
destination d_redis_ui_log {
|
||||
redis(
|
||||
host("`VALKEY_SLAVEOF_IP`")
|
||||
persist-name("valkey1")
|
||||
port(`VALKEY_SLAVEOF_PORT`)
|
||||
auth("`VALKEYPASS`")
|
||||
host("`REDIS_SLAVEOF_IP`")
|
||||
persist-name("redis1")
|
||||
port(`REDIS_SLAVEOF_PORT`)
|
||||
auth("`REDISPASS`")
|
||||
command("LPUSH" "POSTFIX_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
|
||||
);
|
||||
};
|
||||
destination d_valkey_f2b_channel {
|
||||
destination d_redis_f2b_channel {
|
||||
redis(
|
||||
host("`VALKEY_SLAVEOF_IP`")
|
||||
persist-name("valkey2")
|
||||
port(`VALKEY_SLAVEOF_PORT`)
|
||||
auth("`VALKEYPASS`")
|
||||
host("`REDIS_SLAVEOF_IP`")
|
||||
persist-name("redis2")
|
||||
port(`REDIS_SLAVEOF_PORT`)
|
||||
auth("`REDISPASS`")
|
||||
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
|
||||
);
|
||||
};
|
||||
@@ -50,6 +50,6 @@ log {
|
||||
filter(f_ignore);
|
||||
destination(d_stdout);
|
||||
filter(f_mail);
|
||||
destination(d_valkey_ui_log);
|
||||
destination(d_valkey_f2b_channel);
|
||||
destination(d_redis_ui_log);
|
||||
destination(d_redis_f2b_channel);
|
||||
};
|
||||
@@ -15,21 +15,21 @@ source s_src {
|
||||
internal();
|
||||
};
|
||||
destination d_stdout { pipe("/dev/stdout"); };
|
||||
destination d_valkey_ui_log {
|
||||
destination d_redis_ui_log {
|
||||
redis(
|
||||
host("valkey-mailcow")
|
||||
persist-name("valkey1")
|
||||
host("redis-mailcow")
|
||||
persist-name("redis1")
|
||||
port(6379)
|
||||
auth("`VALKEYPASS`")
|
||||
auth("`REDISPASS`")
|
||||
command("LPUSH" "POSTFIX_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
|
||||
);
|
||||
};
|
||||
destination d_valkey_f2b_channel {
|
||||
destination d_redis_f2b_channel {
|
||||
redis(
|
||||
host("valkey-mailcow")
|
||||
persist-name("valkey2")
|
||||
host("redis-mailcow")
|
||||
persist-name("redis2")
|
||||
port(6379)
|
||||
auth("`VALKEYPASS`")
|
||||
auth("`REDISPASS`")
|
||||
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
|
||||
);
|
||||
};
|
||||
@@ -50,6 +50,6 @@ log {
|
||||
filter(f_ignore);
|
||||
destination(d_stdout);
|
||||
filter(f_mail);
|
||||
destination(d_valkey_ui_log);
|
||||
destination(d_valkey_f2b_channel);
|
||||
destination(d_redis_ui_log);
|
||||
destination(d_redis_f2b_channel);
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ FROM debian:bookworm-slim
|
||||
LABEL maintainer="The Infrastructure Company GmbH <info@servercow.de>"
|
||||
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
ARG RSPAMD_VER=rspamd_3.12.1-1~6dbfca2fa
|
||||
ARG RSPAMD_VER=rspamd_3.13.2-1~8bf602278
|
||||
ARG CODENAME=bookworm
|
||||
ENV LC_ALL=C
|
||||
|
||||
@@ -14,8 +14,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
dnsutils \
|
||||
netcat-traditional \
|
||||
wget \
|
||||
redis-tools \
|
||||
procps \
|
||||
redis-tools \
|
||||
procps \
|
||||
nano \
|
||||
lua-cjson \
|
||||
&& arch=$(arch | sed s/aarch64/arm64/ | sed s/x86_64/amd64/) \
|
||||
|
||||
@@ -52,33 +52,33 @@ if [[ ! -z ${RSPAMD_V6} ]]; then
|
||||
echo ${RSPAMD_V6}/128 >> /etc/rspamd/custom/rspamd_trusted.map
|
||||
fi
|
||||
|
||||
if [[ ! -z ${VALKEY_SLAVEOF_IP} ]]; then
|
||||
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
|
||||
cat <<EOF > /etc/rspamd/local.d/redis.conf
|
||||
read_servers = "valkey-mailcow:6379";
|
||||
write_servers = "${VALKEY_SLAVEOF_IP}:${VALKEY_SLAVEOF_PORT}";
|
||||
password = "${VALKEYPASS}";
|
||||
read_servers = "redis:6379";
|
||||
write_servers = "${REDIS_SLAVEOF_IP}:${REDIS_SLAVEOF_PORT}";
|
||||
password = "${REDISPASS}";
|
||||
timeout = 10;
|
||||
EOF
|
||||
until [[ $(redis-cli -h valkey-mailcow -a ${VALKEYPASS} --no-auth-warning PING) == "PONG" ]]; do
|
||||
echo "Waiting for Valkey @valkey-mailcow..."
|
||||
until [[ $(redis-cli -h redis-mailcow -a ${REDISPASS} --no-auth-warning PING) == "PONG" ]]; do
|
||||
echo "Waiting for Redis @redis-mailcow..."
|
||||
sleep 2
|
||||
done
|
||||
until [[ $(redis-cli -h ${VALKEY_SLAVEOF_IP} -p ${VALKEY_SLAVEOF_PORT} -a ${VALKEYPASS} --no-auth-warning PING) == "PONG" ]]; do
|
||||
echo "Waiting for Valkey @${VALKEY_SLAVEOF_IP}..."
|
||||
until [[ $(redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} -a ${REDISPASS} --no-auth-warning PING) == "PONG" ]]; do
|
||||
echo "Waiting for Redis @${REDIS_SLAVEOF_IP}..."
|
||||
sleep 2
|
||||
done
|
||||
redis-cli -h valkey-mailcow -a ${VALKEYPASS} --no-auth-warning SLAVEOF ${VALKEY_SLAVEOF_IP} ${VALKEY_SLAVEOF_PORT}
|
||||
redis-cli -h redis-mailcow -a ${REDISPASS} --no-auth-warning SLAVEOF ${REDIS_SLAVEOF_IP} ${REDIS_SLAVEOF_PORT}
|
||||
else
|
||||
cat <<EOF > /etc/rspamd/local.d/redis.conf
|
||||
servers = "valkey-mailcow:6379";
|
||||
password = "${VALKEYPASS}";
|
||||
servers = "redis:6379";
|
||||
password = "${REDISPASS}";
|
||||
timeout = 10;
|
||||
EOF
|
||||
until [[ $(redis-cli -h valkey-mailcow -a ${VALKEYPASS} --no-auth-warning PING) == "PONG" ]]; do
|
||||
echo "Waiting for Valkey slave..."
|
||||
until [[ $(redis-cli -h redis-mailcow -a ${REDISPASS} --no-auth-warning PING) == "PONG" ]]; do
|
||||
echo "Waiting for Redis slave..."
|
||||
sleep 2
|
||||
done
|
||||
redis-cli -h valkey-mailcow -a ${VALKEYPASS} --no-auth-warning SLAVEOF NO ONE
|
||||
redis-cli -h redis-mailcow -a ${REDISPASS} --no-auth-warning SLAVEOF NO ONE
|
||||
fi
|
||||
|
||||
if [[ "${SKIP_OLEFY}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
||||
|
||||
@@ -44,7 +44,7 @@ RUN echo "Building from repository $SOGO_DEBIAN_REPOSITORY" \
|
||||
|
||||
COPY ./bootstrap-sogo.sh /bootstrap-sogo.sh
|
||||
COPY syslog-ng.conf /etc/syslog-ng/syslog-ng.conf
|
||||
COPY syslog-ng-valkey_slave.conf /etc/syslog-ng/syslog-ng-valkey_slave.conf
|
||||
COPY syslog-ng-redis_slave.conf /etc/syslog-ng/syslog-ng-redis_slave.conf
|
||||
COPY supervisord.conf /etc/supervisor/supervisord.conf
|
||||
COPY acl.diff /acl.diff
|
||||
COPY navMailcowBtns.diff /navMailcowBtns.diff
|
||||
|
||||
@@ -6,8 +6,8 @@ if [[ "${SKIP_SOGO}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ ! -z ${VALKEY_SLAVEOF_IP} ]]; then
|
||||
cp /etc/syslog-ng/syslog-ng-valkey_slave.conf /etc/syslog-ng/syslog-ng.conf
|
||||
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
|
||||
cp /etc/syslog-ng/syslog-ng-redis_slave.conf /etc/syslog-ng/syslog-ng.conf
|
||||
fi
|
||||
|
||||
echo "$TZ" > /etc/timezone
|
||||
|
||||
@@ -17,28 +17,28 @@ source s_sogo {
|
||||
pipe("/dev/sogo_log" owner(sogo) group(sogo));
|
||||
};
|
||||
destination d_stdout { pipe("/dev/stdout"); };
|
||||
destination d_valkey_ui_log {
|
||||
destination d_redis_ui_log {
|
||||
redis(
|
||||
host("`VALKEY_SLAVEOF_IP`")
|
||||
persist-name("valkey1")
|
||||
port(`VALKEY_SLAVEOF_PORT`)
|
||||
auth("`VALKEYPASS`")
|
||||
host("`REDIS_SLAVEOF_IP`")
|
||||
persist-name("redis1")
|
||||
port(`REDIS_SLAVEOF_PORT`)
|
||||
auth("`REDISPASS`")
|
||||
command("LPUSH" "SOGO_LOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
|
||||
);
|
||||
};
|
||||
destination d_valkey_f2b_channel {
|
||||
destination d_redis_f2b_channel {
|
||||
redis(
|
||||
host("`VALKEY_SLAVEOF_IP`")
|
||||
persist-name("valkey2")
|
||||
port(`VALKEY_SLAVEOF_PORT`)
|
||||
auth("`VALKEYPASS`")
|
||||
host("`REDIS_SLAVEOF_IP`")
|
||||
persist-name("redis2")
|
||||
port(`REDIS_SLAVEOF_PORT`)
|
||||
auth("`REDISPASS`")
|
||||
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
|
||||
);
|
||||
};
|
||||
log {
|
||||
source(s_sogo);
|
||||
destination(d_valkey_ui_log);
|
||||
destination(d_valkey_f2b_channel);
|
||||
destination(d_redis_ui_log);
|
||||
destination(d_redis_f2b_channel);
|
||||
};
|
||||
log {
|
||||
source(s_sogo);
|
||||
@@ -17,28 +17,28 @@ source s_sogo {
|
||||
pipe("/dev/sogo_log" owner(sogo) group(sogo));
|
||||
};
|
||||
destination d_stdout { pipe("/dev/stdout"); };
|
||||
destination d_valkey_ui_log {
|
||||
destination d_redis_ui_log {
|
||||
redis(
|
||||
host("valkey-mailcow")
|
||||
persist-name("valkey1")
|
||||
host("redis-mailcow")
|
||||
persist-name("redis1")
|
||||
port(6379)
|
||||
auth("`VALKEYPASS`")
|
||||
auth("`REDISPASS`")
|
||||
command("LPUSH" "SOGO_LOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
|
||||
);
|
||||
};
|
||||
destination d_valkey_f2b_channel {
|
||||
destination d_redis_f2b_channel {
|
||||
redis(
|
||||
host("valkey-mailcow")
|
||||
persist-name("valkey2")
|
||||
host("redis-mailcow")
|
||||
persist-name("redis2")
|
||||
port(6379)
|
||||
auth("`VALKEYPASS`")
|
||||
auth("`REDISPASS`")
|
||||
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
|
||||
);
|
||||
};
|
||||
log {
|
||||
source(s_sogo);
|
||||
destination(d_valkey_ui_log);
|
||||
destination(d_valkey_f2b_channel);
|
||||
destination(d_redis_ui_log);
|
||||
destination(d_redis_f2b_channel);
|
||||
};
|
||||
log {
|
||||
source(s_sogo);
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
FROM python:3.13.2-alpine3.21
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY migrate.py /app/migrate.py
|
||||
RUN pip install --no-cache-dir redis
|
||||
|
||||
CMD ["python", "/app/migrate.py"]
|
||||
@@ -1,78 +0,0 @@
|
||||
import subprocess
|
||||
import redis
|
||||
import time
|
||||
import os
|
||||
|
||||
# Container names
|
||||
SOURCE_CONTAINER = "redis-old-mailcow"
|
||||
DEST_CONTAINER = "valkey-mailcow"
|
||||
VALKEYPASS = os.getenv("VALKEYPASS")
|
||||
|
||||
|
||||
def migrate_redis():
|
||||
src_redis = redis.StrictRedis(host=SOURCE_CONTAINER, port=6379, db=0, password=VALKEYPASS, decode_responses=False)
|
||||
dest_redis = redis.StrictRedis(host=DEST_CONTAINER, port=6379, db=0, password=VALKEYPASS, decode_responses=False)
|
||||
|
||||
cursor = 0
|
||||
batch_size = 100
|
||||
migrated_count = 0
|
||||
|
||||
print("Starting migration...")
|
||||
|
||||
while True:
|
||||
cursor, keys = src_redis.scan(cursor=cursor, match="*", count=batch_size)
|
||||
keys_to_migrate = [key for key in keys if not key.startswith(b"PHPREDIS_SESSION:")]
|
||||
|
||||
for key in keys_to_migrate:
|
||||
key_type = src_redis.type(key)
|
||||
print(f"Import {key} of type {key_type}")
|
||||
|
||||
if key_type == b"string":
|
||||
value = src_redis.get(key)
|
||||
dest_redis.set(key, value)
|
||||
|
||||
elif key_type == b"hash":
|
||||
value = src_redis.hgetall(key)
|
||||
dest_redis.hset(key, mapping=value)
|
||||
|
||||
elif key_type == b"list":
|
||||
value = src_redis.lrange(key, 0, -1)
|
||||
for v in value:
|
||||
dest_redis.rpush(key, v)
|
||||
|
||||
elif key_type == b"set":
|
||||
value = src_redis.smembers(key)
|
||||
for v in value:
|
||||
dest_redis.sadd(key, v)
|
||||
|
||||
elif key_type == b"zset":
|
||||
value = src_redis.zrange(key, 0, -1, withscores=True)
|
||||
for v, score in value:
|
||||
dest_redis.zadd(key, {v: score})
|
||||
|
||||
# Preserve TTL if exists
|
||||
ttl = src_redis.ttl(key)
|
||||
if ttl > 0:
|
||||
dest_redis.expire(key, ttl)
|
||||
|
||||
migrated_count += 1
|
||||
|
||||
if cursor == 0:
|
||||
break # No more keys to scan
|
||||
|
||||
print(f"Migration completed! {migrated_count} keys migrated.")
|
||||
|
||||
print("Forcing Valkey to save data...")
|
||||
try:
|
||||
dest_redis.save() # Immediate RDB save (blocking)
|
||||
dest_redis.bgrewriteaof() # Rewrites the AOF file in the background
|
||||
print("Data successfully saved to disk.")
|
||||
except Exception as e:
|
||||
print(f"Failed to save data: {e}")
|
||||
|
||||
# Main script execution
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
migrate_redis()
|
||||
finally:
|
||||
pass
|
||||
@@ -44,18 +44,18 @@ while ! mariadb-admin status --ssl=false --socket=/var/run/mysqld/mysqld.sock -u
|
||||
done
|
||||
|
||||
# Do not attempt to write to slave
|
||||
if [[ ! -z ${VALKEY_SLAVEOF_IP} ]]; then
|
||||
VALKEY_CMDLINE="redis-cli -h ${VALKEY_SLAVEOF_IP} -p ${VALKEY_SLAVEOF_PORT} -a ${VALKEYPASS} --no-auth-warning"
|
||||
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
|
||||
REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} -a ${REDISPASS} --no-auth-warning"
|
||||
else
|
||||
VALKEY_CMDLINE="redis-cli -h valkey-mailcow -p 6379 -a ${VALKEYPASS} --no-auth-warning"
|
||||
REDIS_CMDLINE="redis-cli -h redis -p 6379 -a ${REDISPASS} --no-auth-warning"
|
||||
fi
|
||||
|
||||
until [[ $(${VALKEY_CMDLINE} PING) == "PONG" ]]; do
|
||||
echo "Waiting for Valkey..."
|
||||
until [[ $(${REDIS_CMDLINE} PING) == "PONG" ]]; do
|
||||
echo "Waiting for Redis..."
|
||||
sleep 2
|
||||
done
|
||||
|
||||
${VALKEY_CMDLINE} DEL F2B_RES > /dev/null
|
||||
${REDIS_CMDLINE} DEL F2B_RES > /dev/null
|
||||
|
||||
# Common functions
|
||||
get_ipv6(){
|
||||
@@ -90,15 +90,15 @@ progress() {
|
||||
[[ ${CURRENT} -gt ${TOTAL} ]] && return
|
||||
[[ ${CURRENT} -lt 0 ]] && CURRENT=0
|
||||
PERCENT=$(( 200 * ${CURRENT} / ${TOTAL} % 2 + 100 * ${CURRENT} / ${TOTAL} ))
|
||||
${VALKEY_CMDLINE} LPUSH WATCHDOG_LOG "{\"time\":\"$(date +%s)\",\"service\":\"${SERVICE}\",\"lvl\":\"${PERCENT}\",\"hpnow\":\"${CURRENT}\",\"hptotal\":\"${TOTAL}\",\"hpdiff\":\"${DIFF}\"}" > /dev/null
|
||||
log_msg "${SERVICE} health level: ${PERCENT}% (${CURRENT}/${TOTAL}), health trend: ${DIFF}" no_valkey
|
||||
${REDIS_CMDLINE} LPUSH WATCHDOG_LOG "{\"time\":\"$(date +%s)\",\"service\":\"${SERVICE}\",\"lvl\":\"${PERCENT}\",\"hpnow\":\"${CURRENT}\",\"hptotal\":\"${TOTAL}\",\"hpdiff\":\"${DIFF}\"}" > /dev/null
|
||||
log_msg "${SERVICE} health level: ${PERCENT}% (${CURRENT}/${TOTAL}), health trend: ${DIFF}" no_redis
|
||||
# Return 10 to indicate a dead service
|
||||
[ ${CURRENT} -le 0 ] && return 10
|
||||
}
|
||||
|
||||
log_msg() {
|
||||
if [[ ${2} != "no_valkey" ]]; then
|
||||
${VALKEY_CMDLINE} LPUSH WATCHDOG_LOG "{\"time\":\"$(date +%s)\",\"message\":\"$(printf '%s' "${1}" | \
|
||||
if [[ ${2} != "no_redis" ]]; then
|
||||
${REDIS_CMDLINE} LPUSH WATCHDOG_LOG "{\"time\":\"$(date +%s)\",\"message\":\"$(printf '%s' "${1}" | \
|
||||
tr '\r\n%&;$"_[]{}-' ' ')\"}" > /dev/null
|
||||
fi
|
||||
echo $(date) $(printf '%s\n' "${1}")
|
||||
@@ -114,10 +114,10 @@ function notify_error() {
|
||||
# If exists, mail will be throttled by argument in seconds
|
||||
[[ ! -z ${3} ]] && THROTTLE=${3}
|
||||
if [[ ! -z ${THROTTLE} ]]; then
|
||||
TTL_LEFT="$(${VALKEY_CMDLINE} TTL THROTTLE_${1} 2> /dev/null)"
|
||||
TTL_LEFT="$(${REDIS_CMDLINE} TTL THROTTLE_${1} 2> /dev/null)"
|
||||
if [[ "${TTL_LEFT}" == "-2" ]]; then
|
||||
# Delay key not found, setting a delay key now
|
||||
${VALKEY_CMDLINE} SET THROTTLE_${1} 1 EX ${THROTTLE}
|
||||
${REDIS_CMDLINE} SET THROTTLE_${1} 1 EX ${THROTTLE}
|
||||
else
|
||||
log_msg "Not sending notification email now, blocked for ${TTL_LEFT} seconds..."
|
||||
return 1
|
||||
@@ -324,21 +324,21 @@ unbound_checks() {
|
||||
return 1
|
||||
}
|
||||
|
||||
valkey_checks() {
|
||||
# A check for the local valkey container
|
||||
redis_checks() {
|
||||
# A check for the local redis container
|
||||
err_count=0
|
||||
diff_c=0
|
||||
THRESHOLD=${VALKEY_THRESHOLD}
|
||||
THRESHOLD=${REDIS_THRESHOLD}
|
||||
# Reduce error count by 2 after restarting an unhealthy container
|
||||
trap "[ ${err_count} -gt 1 ] && err_count=$(( ${err_count} - 2 ))" USR1
|
||||
while [ ${err_count} -lt ${THRESHOLD} ]; do
|
||||
touch /tmp/valkey-mailcow; echo "$(tail -50 /tmp/valkey-mailcow)" > /tmp/valkey-mailcow
|
||||
host_ip=$(get_container_ip valkey-mailcow)
|
||||
touch /tmp/redis-mailcow; echo "$(tail -50 /tmp/redis-mailcow)" > /tmp/redis-mailcow
|
||||
host_ip=$(get_container_ip redis-mailcow)
|
||||
err_c_cur=${err_count}
|
||||
/usr/lib/nagios/plugins/check_tcp -4 -H valkey-mailcow -p 6379 -E -s "AUTH ${VALKEYPASS}\nPING\n" -q "QUIT" -e "PONG" 2>> /tmp/valkey-mailcow 1>&2; err_count=$(( ${err_count} + $? ))
|
||||
/usr/lib/nagios/plugins/check_tcp -4 -H redis-mailcow -p 6379 -E -s "AUTH ${REDISPASS}\nPING\n" -q "QUIT" -e "PONG" 2>> /tmp/redis-mailcow 1>&2; err_count=$(( ${err_count} + $? ))
|
||||
[ ${err_c_cur} -eq ${err_count} ] && [ ! $((${err_count} - 1)) -lt 0 ] && err_count=$((${err_count} - 1)) diff_c=1
|
||||
[ ${err_c_cur} -ne ${err_count} ] && diff_c=$(( ${err_c_cur} - ${err_count} ))
|
||||
progress "Valkey" ${THRESHOLD} $(( ${THRESHOLD} - ${err_count} )) ${diff_c}
|
||||
progress "Redis" ${THRESHOLD} $(( ${THRESHOLD} - ${err_count} )) ${diff_c}
|
||||
if [[ $? == 10 ]]; then
|
||||
diff_c=0
|
||||
sleep 1
|
||||
@@ -533,12 +533,12 @@ dovecot_repl_checks() {
|
||||
err_count=0
|
||||
diff_c=0
|
||||
THRESHOLD=${DOVECOT_REPL_THRESHOLD}
|
||||
D_REPL_STATUS=$(redis-cli -h valkey-mailcow -a ${VALKEYPASS} --no-auth-warning -r GET DOVECOT_REPL_HEALTH)
|
||||
D_REPL_STATUS=$(redis-cli -h redis -a ${REDISPASS} --no-auth-warning -r GET DOVECOT_REPL_HEALTH)
|
||||
# Reduce error count by 2 after restarting an unhealthy container
|
||||
trap "[ ${err_count} -gt 1 ] && err_count=$(( ${err_count} - 2 ))" USR1
|
||||
while [ ${err_count} -lt ${THRESHOLD} ]; do
|
||||
err_c_cur=${err_count}
|
||||
D_REPL_STATUS=$(redis-cli --raw -h valkey-mailcow -a ${VALKEYPASS} --no-auth-warning GET DOVECOT_REPL_HEALTH)
|
||||
D_REPL_STATUS=$(redis-cli --raw -h redis -a ${REDISPASS} --no-auth-warning GET DOVECOT_REPL_HEALTH)
|
||||
if [[ "${D_REPL_STATUS}" != "1" ]]; then
|
||||
err_count=$(( ${err_count} + 1 ))
|
||||
fi
|
||||
@@ -608,19 +608,19 @@ ratelimit_checks() {
|
||||
err_count=0
|
||||
diff_c=0
|
||||
THRESHOLD=${RATELIMIT_THRESHOLD}
|
||||
RL_LOG_STATUS=$(redis-cli -h valkey-mailcow -a ${VALKEYPASS} --no-auth-warning LRANGE RL_LOG 0 0 | jq .qid)
|
||||
RL_LOG_STATUS=$(redis-cli -h redis -a ${REDISPASS} --no-auth-warning LRANGE RL_LOG 0 0 | jq .qid)
|
||||
# Reduce error count by 2 after restarting an unhealthy container
|
||||
trap "[ ${err_count} -gt 1 ] && err_count=$(( ${err_count} - 2 ))" USR1
|
||||
while [ ${err_count} -lt ${THRESHOLD} ]; do
|
||||
err_c_cur=${err_count}
|
||||
RL_LOG_STATUS_PREV=${RL_LOG_STATUS}
|
||||
RL_LOG_STATUS=$(redis-cli -h valkey-mailcow -a ${VALKEYPASS} --no-auth-warning LRANGE RL_LOG 0 0 | jq .qid)
|
||||
RL_LOG_STATUS=$(redis-cli -h redis -a ${REDISPASS} --no-auth-warning LRANGE RL_LOG 0 0 | jq .qid)
|
||||
if [[ ${RL_LOG_STATUS_PREV} != ${RL_LOG_STATUS} ]]; then
|
||||
err_count=$(( ${err_count} + 1 ))
|
||||
echo 'Last 10 applied ratelimits (may overlap with previous reports).' > /tmp/ratelimit
|
||||
echo 'Full ratelimit buckets can be emptied by deleting the ratelimit hash from within mailcow UI (see /debug -> Protocols -> Ratelimit):' >> /tmp/ratelimit
|
||||
echo >> /tmp/ratelimit
|
||||
redis-cli --raw -h valkey-mailcow -a ${VALKEYPASS} --no-auth-warning LRANGE RL_LOG 0 10 | jq . >> /tmp/ratelimit
|
||||
redis-cli --raw -h redis -a ${REDISPASS} --no-auth-warning LRANGE RL_LOG 0 10 | jq . >> /tmp/ratelimit
|
||||
fi
|
||||
[ ${err_c_cur} -eq ${err_count} ] && [ ! $((${err_count} - 1)) -lt 0 ] && err_count=$((${err_count} - 1)) diff_c=1
|
||||
[ ${err_c_cur} -ne ${err_count} ] && diff_c=$(( ${err_c_cur} - ${err_count} ))
|
||||
@@ -669,20 +669,20 @@ fail2ban_checks() {
|
||||
err_count=0
|
||||
diff_c=0
|
||||
THRESHOLD=${FAIL2BAN_THRESHOLD}
|
||||
F2B_LOG_STATUS=($(${VALKEY_CMDLINE} --raw HKEYS F2B_ACTIVE_BANS))
|
||||
F2B_LOG_STATUS=($(${REDIS_CMDLINE} --raw HKEYS F2B_ACTIVE_BANS))
|
||||
F2B_RES=
|
||||
# Reduce error count by 2 after restarting an unhealthy container
|
||||
trap "[ ${err_count} -gt 1 ] && err_count=$(( ${err_count} - 2 ))" USR1
|
||||
while [ ${err_count} -lt ${THRESHOLD} ]; do
|
||||
err_c_cur=${err_count}
|
||||
F2B_LOG_STATUS_PREV=(${F2B_LOG_STATUS[@]})
|
||||
F2B_LOG_STATUS=($(${VALKEY_CMDLINE} --raw HKEYS F2B_ACTIVE_BANS))
|
||||
F2B_LOG_STATUS=($(${REDIS_CMDLINE} --raw HKEYS F2B_ACTIVE_BANS))
|
||||
array_diff F2B_RES F2B_LOG_STATUS F2B_LOG_STATUS_PREV
|
||||
if [[ ! -z "${F2B_RES}" ]]; then
|
||||
err_count=$(( ${err_count} + 1 ))
|
||||
echo -n "${F2B_RES[@]}" | tr -cd "[a-fA-F0-9.:/] " | timeout 3s ${VALKEY_CMDLINE} -x SET F2B_RES > /dev/null
|
||||
echo -n "${F2B_RES[@]}" | tr -cd "[a-fA-F0-9.:/] " | timeout 3s ${REDIS_CMDLINE} -x SET F2B_RES > /dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
${VALKEY_CMDLINE} -x DEL F2B_RES
|
||||
${REDIS_CMDLINE} -x DEL F2B_RES
|
||||
fi
|
||||
fi
|
||||
[ ${err_c_cur} -eq ${err_count} ] && [ ! $((${err_count} - 1)) -lt 0 ] && err_count=$((${err_count} - 1)) diff_c=1
|
||||
@@ -703,9 +703,9 @@ acme_checks() {
|
||||
err_count=0
|
||||
diff_c=0
|
||||
THRESHOLD=${ACME_THRESHOLD}
|
||||
ACME_LOG_STATUS=$(redis-cli -h valkey-mailcow -a ${VALKEYPASS} --no-auth-warning GET ACME_FAIL_TIME)
|
||||
ACME_LOG_STATUS=$(redis-cli -h redis -a ${REDISPASS} --no-auth-warning GET ACME_FAIL_TIME)
|
||||
if [[ -z "${ACME_LOG_STATUS}" ]]; then
|
||||
${VALKEY_CMDLINE} SET ACME_FAIL_TIME 0
|
||||
${REDIS_CMDLINE} SET ACME_FAIL_TIME 0
|
||||
ACME_LOG_STATUS=0
|
||||
fi
|
||||
# Reduce error count by 2 after restarting an unhealthy container
|
||||
@@ -715,7 +715,7 @@ acme_checks() {
|
||||
ACME_LOG_STATUS_PREV=${ACME_LOG_STATUS}
|
||||
ACME_LC=0
|
||||
until [[ ! -z ${ACME_LOG_STATUS} ]] || [ ${ACME_LC} -ge 3 ]; do
|
||||
ACME_LOG_STATUS=$(redis-cli -h valkey-mailcow -a ${VALKEYPASS} --no-auth-warning GET ACME_FAIL_TIME 2> /dev/null)
|
||||
ACME_LOG_STATUS=$(redis-cli -h redis -a ${REDISPASS} --no-auth-warning GET ACME_FAIL_TIME 2> /dev/null)
|
||||
sleep 3
|
||||
ACME_LC=$((ACME_LC+1))
|
||||
done
|
||||
@@ -864,14 +864,14 @@ BACKGROUND_TASKS+=(${PID})
|
||||
|
||||
(
|
||||
while true; do
|
||||
if ! valkey_checks; then
|
||||
log_msg "Local Valkey hit error limit"
|
||||
echo valkey-mailcow > /tmp/com_pipe
|
||||
if ! redis_checks; then
|
||||
log_msg "Local Redis hit error limit"
|
||||
echo redis-mailcow > /tmp/com_pipe
|
||||
fi
|
||||
done
|
||||
) &
|
||||
PID=$!
|
||||
echo "Spawned valkey_checks with PID ${PID}"
|
||||
echo "Spawned redis_checks with PID ${PID}"
|
||||
BACKGROUND_TASKS+=(${PID})
|
||||
|
||||
(
|
||||
@@ -1129,9 +1129,9 @@ while true; do
|
||||
# Define $2 to override message text, else print service was restarted at ...
|
||||
notify_error "${com_pipe_answer}" "Please check acme-mailcow for further information."
|
||||
elif [[ ${com_pipe_answer} == "fail2ban" ]]; then
|
||||
F2B_RES=($(timeout 4s ${VALKEY_CMDLINE} --raw GET F2B_RES 2> /dev/null))
|
||||
F2B_RES=($(timeout 4s ${REDIS_CMDLINE} --raw GET F2B_RES 2> /dev/null))
|
||||
if [[ ! -z "${F2B_RES}" ]]; then
|
||||
${VALKEY_CMDLINE} DEL F2B_RES > /dev/null
|
||||
${REDIS_CMDLINE} DEL F2B_RES > /dev/null
|
||||
host=
|
||||
for host in "${F2B_RES[@]}"; do
|
||||
log_msg "Banned ${host}"
|
||||
|
||||
@@ -23,16 +23,16 @@ if (file_exists('../../../web/inc/vars.local.inc.php')) {
|
||||
require_once '../../../web/inc/lib/vendor/autoload.php';
|
||||
|
||||
|
||||
// Init Valkey
|
||||
$valkey = new Redis();
|
||||
// Init Redis
|
||||
$redis = new Redis();
|
||||
try {
|
||||
if (!empty(getenv('VALKEY_SLAVEOF_IP'))) {
|
||||
$valkey->connect(getenv('VALKEY_SLAVEOF_IP'), getenv('VALKEY_SLAVEOF_PORT'));
|
||||
if (!empty(getenv('REDIS_SLAVEOF_IP'))) {
|
||||
$redis->connect(getenv('REDIS_SLAVEOF_IP'), getenv('REDIS_SLAVEOF_PORT'));
|
||||
}
|
||||
else {
|
||||
$valkey->connect('valkey-mailcow', 6379);
|
||||
$redis->connect('redis-mailcow', 6379);
|
||||
}
|
||||
$valkey->auth(getenv("VALKEYPASS"));
|
||||
$redis->auth(getenv("REDISPASS"));
|
||||
}
|
||||
catch (Exception $e) {
|
||||
error_log("MAILCOWAUTH: " . $e . PHP_EOL);
|
||||
|
||||
@@ -23,16 +23,16 @@ catch (PDOException $e) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// Init Valkey
|
||||
$valkey = new Redis();
|
||||
// Init Redis
|
||||
$redis = new Redis();
|
||||
try {
|
||||
if (!empty(getenv('VALKEY_SLAVEOF_IP'))) {
|
||||
$valkey->connect(getenv('VALKEY_SLAVEOF_IP'), getenv('VALKEY_SLAVEOF_PORT'));
|
||||
if (!empty(getenv('REDIS_SLAVEOF_IP'))) {
|
||||
$redis->connect(getenv('REDIS_SLAVEOF_IP'), getenv('REDIS_SLAVEOF_PORT'));
|
||||
}
|
||||
else {
|
||||
$valkey->connect('valkey-mailcow', 6379);
|
||||
$redis->connect('redis-mailcow', 6379);
|
||||
}
|
||||
$valkey->auth(getenv("VALKEYPASS"));
|
||||
$redis->auth(getenv("REDISPASS"));
|
||||
}
|
||||
catch (Exception $e) {
|
||||
echo "Exiting: " . $e->getMessage();
|
||||
@@ -41,7 +41,7 @@ catch (Exception $e) {
|
||||
}
|
||||
|
||||
function logMsg($priority, $message, $task = "Keycloak Sync") {
|
||||
global $valkey;
|
||||
global $redis;
|
||||
|
||||
$finalMsg = array(
|
||||
"time" => time(),
|
||||
@@ -49,7 +49,7 @@ function logMsg($priority, $message, $task = "Keycloak Sync") {
|
||||
"task" => $task,
|
||||
"message" => $message
|
||||
);
|
||||
$valkey->lPush('CRON_LOG', json_encode($finalMsg));
|
||||
$redis->lPush('CRON_LOG', json_encode($finalMsg));
|
||||
}
|
||||
|
||||
// Load core functions first
|
||||
|
||||
@@ -23,16 +23,16 @@ catch (PDOException $e) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// Init Valkey
|
||||
$valkey = new Redis();
|
||||
// Init Redis
|
||||
$redis = new Redis();
|
||||
try {
|
||||
if (!empty(getenv('VALKEY_SLAVEOF_IP'))) {
|
||||
$valkey->connect(getenv('VALKEY_SLAVEOF_IP'), getenv('VALKEY_SLAVEOF_PORT'));
|
||||
if (!empty(getenv('REDIS_SLAVEOF_IP'))) {
|
||||
$redis->connect(getenv('REDIS_SLAVEOF_IP'), getenv('REDIS_SLAVEOF_PORT'));
|
||||
}
|
||||
else {
|
||||
$valkey->connect('valkey-mailcow', 6379);
|
||||
$redis->connect('redis-mailcow', 6379);
|
||||
}
|
||||
$valkey->auth(getenv("VALKEYPASS"));
|
||||
$redis->auth(getenv("REDISPASS"));
|
||||
}
|
||||
catch (Exception $e) {
|
||||
echo "Exiting: " . $e->getMessage();
|
||||
@@ -41,7 +41,7 @@ catch (Exception $e) {
|
||||
}
|
||||
|
||||
function logMsg($priority, $message, $task = "LDAP Sync") {
|
||||
global $valkey;
|
||||
global $redis;
|
||||
|
||||
$finalMsg = array(
|
||||
"time" => time(),
|
||||
@@ -49,7 +49,7 @@ function logMsg($priority, $message, $task = "LDAP Sync") {
|
||||
"task" => $task,
|
||||
"message" => $message
|
||||
);
|
||||
$valkey->lPush('CRON_LOG', json_encode($finalMsg));
|
||||
$redis->lPush('CRON_LOG', json_encode($finalMsg));
|
||||
}
|
||||
|
||||
// Load core functions first
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
; NOTE: Restart phpfpm on ANY manual changes to PHP files!
|
||||
|
||||
; opcache
|
||||
opcache.enable=1
|
||||
opcache.enable_cli=1
|
||||
opcache.interned_strings_buffer=16
|
||||
opcache.max_accelerated_files=10000
|
||||
opcache.memory_consumption=128
|
||||
opcache.save_comments=1
|
||||
opcache.revalidate_freq=1
|
||||
opcache.validate_timestamps=0
|
||||
|
||||
; JIT
|
||||
; Disabled for now due to some PHP segmentation faults observed
|
||||
; in certain environments. Possibly some PHP or PHP extension bug.
|
||||
opcache.jit=disable
|
||||
opcache.jit_buffer_size=0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Whitelist generated by Postwhite v3.4 on Wed Oct 1 00:21:33 UTC 2025
|
||||
# Whitelist generated by Postwhite v3.4 on Sat Nov 1 00:21:43 UTC 2025
|
||||
# https://github.com/stevejenkins/postwhite/
|
||||
# 2216 total rules
|
||||
# 2161 total rules
|
||||
2a00:1450:4000::/36 permit
|
||||
2a01:111:f400::/48 permit
|
||||
2a01:111:f403:2800::/53 permit
|
||||
@@ -50,14 +50,11 @@
|
||||
8.25.194.0/23 permit
|
||||
8.25.196.0/23 permit
|
||||
8.36.116.0/24 permit
|
||||
8.39.54.0/23 permit
|
||||
8.39.54.250/31 permit
|
||||
8.39.144.0/24 permit
|
||||
8.40.222.0/23 permit
|
||||
8.40.222.250/31 permit
|
||||
12.130.86.238 permit
|
||||
13.107.213.41 permit
|
||||
13.107.246.41 permit
|
||||
13.107.213.69 permit
|
||||
13.107.246.69 permit
|
||||
13.108.16.0/20 permit
|
||||
13.110.208.0/21 permit
|
||||
13.110.209.0/24 permit
|
||||
13.110.216.0/22 permit
|
||||
@@ -169,7 +166,6 @@
|
||||
34.215.104.144 permit
|
||||
34.218.115.239 permit
|
||||
34.225.212.172 permit
|
||||
34.241.242.183 permit
|
||||
35.83.148.184 permit
|
||||
35.155.198.111 permit
|
||||
35.158.23.94 permit
|
||||
@@ -193,7 +189,6 @@
|
||||
40.233.64.216 permit
|
||||
40.233.83.78 permit
|
||||
40.233.88.28 permit
|
||||
43.239.212.33 permit
|
||||
44.206.138.57 permit
|
||||
44.210.169.44 permit
|
||||
44.217.45.156 permit
|
||||
@@ -275,7 +270,6 @@
|
||||
50.112.246.219 permit
|
||||
52.1.14.157 permit
|
||||
52.5.230.59 permit
|
||||
52.6.74.205 permit
|
||||
52.12.53.23 permit
|
||||
52.13.214.179 permit
|
||||
52.26.1.71 permit
|
||||
@@ -302,7 +296,6 @@
|
||||
52.96.91.34 permit
|
||||
52.96.111.82 permit
|
||||
52.96.172.98 permit
|
||||
52.96.214.50 permit
|
||||
52.96.222.194 permit
|
||||
52.96.222.226 permit
|
||||
52.96.223.2 permit
|
||||
@@ -341,7 +334,6 @@
|
||||
54.244.54.130 permit
|
||||
54.244.242.0/24 permit
|
||||
54.255.61.23 permit
|
||||
56.124.6.228 permit
|
||||
57.103.64.0/18 permit
|
||||
57.129.93.249 permit
|
||||
62.13.128.0/24 permit
|
||||
@@ -426,7 +418,6 @@
|
||||
65.110.161.77 permit
|
||||
65.123.29.213 permit
|
||||
65.123.29.220 permit
|
||||
65.154.166.0/24 permit
|
||||
65.212.180.36 permit
|
||||
66.102.0.0/20 permit
|
||||
66.119.150.192/26 permit
|
||||
@@ -1233,8 +1224,6 @@
|
||||
99.83.190.102 permit
|
||||
103.9.96.0/22 permit
|
||||
103.28.42.0/24 permit
|
||||
103.84.217.238 permit
|
||||
103.89.75.238 permit
|
||||
103.151.192.0/23 permit
|
||||
103.168.172.128/27 permit
|
||||
103.237.104.0/22 permit
|
||||
@@ -1400,9 +1389,6 @@
|
||||
117.120.16.0/21 permit
|
||||
119.42.242.52/31 permit
|
||||
119.42.242.156 permit
|
||||
121.244.91.48 permit
|
||||
121.244.91.52 permit
|
||||
122.15.156.182 permit
|
||||
123.126.78.64/29 permit
|
||||
124.108.96.24/31 permit
|
||||
124.108.96.28/31 permit
|
||||
@@ -1430,6 +1416,7 @@
|
||||
128.245.248.0/21 permit
|
||||
129.41.77.70 permit
|
||||
129.41.169.249 permit
|
||||
129.77.16.0/20 permit
|
||||
129.80.5.164 permit
|
||||
129.80.64.36 permit
|
||||
129.80.67.121 permit
|
||||
@@ -1466,21 +1453,8 @@
|
||||
134.170.141.64/26 permit
|
||||
134.170.143.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
|
||||
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.147.128.0/20 permit
|
||||
136.147.135.0/24 permit
|
||||
136.147.176.0/20 permit
|
||||
@@ -1495,7 +1469,6 @@
|
||||
139.138.46.219 permit
|
||||
139.138.57.55 permit
|
||||
139.138.58.119 permit
|
||||
139.167.79.86 permit
|
||||
139.180.17.0/24 permit
|
||||
140.238.148.191 permit
|
||||
141.148.159.229 permit
|
||||
@@ -1618,9 +1591,6 @@
|
||||
164.152.23.32 permit
|
||||
164.152.25.241 permit
|
||||
164.177.132.168/30 permit
|
||||
165.173.128.0/24 permit
|
||||
165.173.180.250/31 permit
|
||||
165.173.182.250/31 permit
|
||||
166.78.68.0/22 permit
|
||||
166.78.68.221 permit
|
||||
166.78.69.169 permit
|
||||
@@ -1650,23 +1620,12 @@
|
||||
168.245.12.252 permit
|
||||
168.245.46.9 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.175.3 permit
|
||||
169.148.188.0/24 permit
|
||||
169.148.188.182 permit
|
||||
170.10.128.0/24 permit
|
||||
170.10.129.0/24 permit
|
||||
170.10.132.56/29 permit
|
||||
170.10.132.64/29 permit
|
||||
170.10.133.0/24 permit
|
||||
172.217.32.0/20 permit
|
||||
172.217.32.0/21 permit
|
||||
172.253.56.0/21 permit
|
||||
172.253.112.0/20 permit
|
||||
173.0.84.0/29 permit
|
||||
@@ -1846,16 +1805,7 @@
|
||||
199.16.156.0/22 permit
|
||||
199.33.145.1 permit
|
||||
199.33.145.32 permit
|
||||
199.34.22.36 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.162.0/25 permit
|
||||
199.122.120.0/21 permit
|
||||
@@ -1912,8 +1862,6 @@
|
||||
204.92.114.187 permit
|
||||
204.92.114.203 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.220.160.0/21 permit
|
||||
204.220.168.0/21 permit
|
||||
@@ -2201,9 +2149,6 @@
|
||||
2603:1030:20e:3::23c permit
|
||||
2603:1030:b:3::152 permit
|
||||
2603:1030:c02:8::14 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
|
||||
2607:f8b0:4000::/36 permit
|
||||
2620:109:c003:104::/64 permit
|
||||
2620:109:c003:104::215 permit
|
||||
|
||||
12
data/conf/redis/redis-conf.sh
Executable file
12
data/conf/redis/redis-conf.sh
Executable file
@@ -0,0 +1,12 @@
|
||||
#!/bin/sh
|
||||
|
||||
cat <<EOF > /redis.conf
|
||||
requirepass $REDISPASS
|
||||
user quota_notify on nopass ~QW_* -@all +get +hget +ping
|
||||
EOF
|
||||
|
||||
if [ -n "$REDISMASTERPASS" ]; then
|
||||
echo "masterauth $REDISMASTERPASS" >> /redis.conf
|
||||
fi
|
||||
|
||||
exec redis-server /redis.conf
|
||||
@@ -22,10 +22,10 @@ catch (PDOException $e) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// Init Valkey
|
||||
$valkey = new Redis();
|
||||
$valkey->connect('valkey-mailcow', 6379);
|
||||
$valkey->auth(getenv("VALKEYPASS"));
|
||||
// Init Redis
|
||||
$redis = new Redis();
|
||||
$redis->connect('redis-mailcow', 6379);
|
||||
$redis->auth(getenv("REDISPASS"));
|
||||
|
||||
function parse_email($email) {
|
||||
if(!filter_var($email, FILTER_VALIDATE_EMAIL)) return false;
|
||||
@@ -60,7 +60,7 @@ $rcpt_final_mailboxes = array();
|
||||
|
||||
// Skip if not a mailcow handled domain
|
||||
try {
|
||||
if (!$valkey->hGet('DOMAIN_MAP', $parsed_rcpt['domain'])) {
|
||||
if (!$redis->hGet('DOMAIN_MAP', $parsed_rcpt['domain'])) {
|
||||
exit;
|
||||
}
|
||||
}
|
||||
@@ -122,7 +122,7 @@ try {
|
||||
}
|
||||
else {
|
||||
$parsed_goto = parse_email($goto);
|
||||
if (!$valkey->hGet('DOMAIN_MAP', $parsed_goto['domain'])) {
|
||||
if (!$redis->hGet('DOMAIN_MAP', $parsed_goto['domain'])) {
|
||||
error_log("ALIAS EXPANDER:" . $goto . " is not a mailcow handled mailbox or alias address" . PHP_EOL);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
header('Content-Type: text/plain');
|
||||
ini_set('error_reporting', 0);
|
||||
|
||||
$valkey = new Redis();
|
||||
$valkey->connect('valkey-mailcow', 6379);
|
||||
$valkey->auth(getenv("VALKEYPASS"));
|
||||
$redis = new Redis();
|
||||
$redis->connect('redis-mailcow', 6379);
|
||||
$redis->auth(getenv("REDISPASS"));
|
||||
|
||||
function in_net($addr, $net) {
|
||||
$net = explode('/', $net);
|
||||
@@ -31,7 +31,7 @@ function in_net($addr, $net) {
|
||||
|
||||
if (isset($_GET['host'])) {
|
||||
try {
|
||||
foreach ($valkey->hGetAll('WHITELISTED_FWD_HOST') as $host => $source) {
|
||||
foreach ($redis->hGetAll('WHITELISTED_FWD_HOST') as $host => $source) {
|
||||
if (in_net($_GET['host'], $host)) {
|
||||
echo '200 PERMIT';
|
||||
exit;
|
||||
@@ -46,7 +46,7 @@ if (isset($_GET['host'])) {
|
||||
} else {
|
||||
try {
|
||||
echo '240.240.240.240' . PHP_EOL;
|
||||
foreach ($valkey->hGetAll('WHITELISTED_FWD_HOST') as $host => $source) {
|
||||
foreach ($redis->hGetAll('WHITELISTED_FWD_HOST') as $host => $source) {
|
||||
echo $host . PHP_EOL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,10 +21,10 @@ catch (PDOException $e) {
|
||||
http_response_code(501);
|
||||
exit;
|
||||
}
|
||||
// Init Valkey
|
||||
$valkey = new Redis();
|
||||
$valkey->connect('valkey-mailcow', 6379);
|
||||
$valkey->auth(getenv("VALKEYPASS"));
|
||||
// Init Redis
|
||||
$redis = new Redis();
|
||||
$redis->connect('redis-mailcow', 6379);
|
||||
$redis->auth(getenv("REDISPASS"));
|
||||
|
||||
// Functions
|
||||
function parse_email($email) {
|
||||
@@ -74,16 +74,16 @@ if ($fuzzy == 'unknown') {
|
||||
}
|
||||
|
||||
try {
|
||||
$max_size = (int)$valkey->Get('Q_MAX_SIZE');
|
||||
$max_size = (int)$redis->Get('Q_MAX_SIZE');
|
||||
if (($max_size * 1048576) < $raw_size) {
|
||||
error_log(sprintf("QUARANTINE: Message too large: %d b exceeds %d b", $raw_size, ($max_size * 1048576)) . PHP_EOL);
|
||||
http_response_code(505);
|
||||
exit;
|
||||
}
|
||||
if ($exclude_domains = $valkey->Get('Q_EXCLUDE_DOMAINS')) {
|
||||
if ($exclude_domains = $redis->Get('Q_EXCLUDE_DOMAINS')) {
|
||||
$exclude_domains = json_decode($exclude_domains, true);
|
||||
}
|
||||
$retention_size = (int)$valkey->Get('Q_RETENTION_SIZE');
|
||||
$retention_size = (int)$redis->Get('Q_RETENTION_SIZE');
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
error_log("QUARANTINE: " . $e . PHP_EOL);
|
||||
@@ -103,7 +103,7 @@ foreach (json_decode($rcpts, true) as $rcpt) {
|
||||
|
||||
// Skip if not a mailcow handled domain
|
||||
try {
|
||||
if (!$valkey->hGet('DOMAIN_MAP', $parsed_rcpt['domain'])) {
|
||||
if (!$redis->hGet('DOMAIN_MAP', $parsed_rcpt['domain'])) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -171,7 +171,7 @@ foreach (json_decode($rcpts, true) as $rcpt) {
|
||||
}
|
||||
else {
|
||||
$parsed_goto = parse_email($goto);
|
||||
if (!$valkey->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);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -5,16 +5,16 @@ header('Content-Type: text/plain');
|
||||
require_once "vars.inc.php";
|
||||
// Do not show errors, we log to using error_log
|
||||
ini_set('error_reporting', 0);
|
||||
// Init Valkey
|
||||
$valkey = new Redis();
|
||||
// Init Redis
|
||||
$redis = new Redis();
|
||||
try {
|
||||
if (!empty(getenv('VALKEY_SLAVEOF_IP'))) {
|
||||
$valkey->connect(getenv('VALKEY_SLAVEOF_IP'), getenv('VALKEY_SLAVEOF_PORT'));
|
||||
if (!empty(getenv('REDIS_SLAVEOF_IP'))) {
|
||||
$redis->connect(getenv('REDIS_SLAVEOF_IP'), getenv('REDIS_SLAVEOF_PORT'));
|
||||
}
|
||||
else {
|
||||
$valkey->connect('valkey-mailcow', 6379);
|
||||
$redis->connect('redis-mailcow', 6379);
|
||||
}
|
||||
$valkey->auth(getenv("VALKEYPASS"));
|
||||
$redis->auth(getenv("REDISPASS"));
|
||||
}
|
||||
catch (Exception $e) {
|
||||
exit;
|
||||
@@ -44,6 +44,6 @@ $data['message_id'] = $raw_data_decoded['message_id'];
|
||||
$data['header_subject'] = implode(' ', $raw_data_decoded['header_subject']);
|
||||
$data['header_from'] = implode(', ', $raw_data_decoded['header_from']);
|
||||
|
||||
$valkey->lpush('RL_LOG', json_encode($data));
|
||||
$redis->lpush('RL_LOG', json_encode($data));
|
||||
exit;
|
||||
|
||||
|
||||
@@ -21,10 +21,10 @@ catch (PDOException $e) {
|
||||
http_response_code(501);
|
||||
exit;
|
||||
}
|
||||
// Init Valkey
|
||||
$valkey = new Redis();
|
||||
$valkey->connect('valkey-mailcow', 6379);
|
||||
$valkey->auth(getenv("VALKEYPASS"));
|
||||
// Init Redis
|
||||
$redis = new Redis();
|
||||
$redis->connect('redis-mailcow', 6379);
|
||||
$redis->auth(getenv("REDISPASS"));
|
||||
|
||||
// Functions
|
||||
function parse_email($email) {
|
||||
@@ -94,7 +94,7 @@ foreach (json_decode($rcpts, true) as $rcpt) {
|
||||
|
||||
// Skip if not a mailcow handled domain
|
||||
try {
|
||||
if (!$valkey->hGet('DOMAIN_MAP', $parsed_rcpt['domain'])) {
|
||||
if (!$redis->hGet('DOMAIN_MAP', $parsed_rcpt['domain'])) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -156,7 +156,7 @@ foreach (json_decode($rcpts, true) as $rcpt) {
|
||||
}
|
||||
else {
|
||||
$parsed_goto = parse_email($goto);
|
||||
if (!$valkey->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);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cat <<EOF > /valkey.conf
|
||||
requirepass $VALKEYPASS
|
||||
user quota_notify on nopass ~QW_* -@all +get +hget +ping
|
||||
EOF
|
||||
|
||||
if [ -n "$VALKEYMASTERPASS" ]; then
|
||||
echo "masterauth $VALKEYMASTERPASS" >> /valkey.conf
|
||||
fi
|
||||
|
||||
exec "$@"
|
||||
@@ -1,13 +1,13 @@
|
||||
<?php
|
||||
$valkey = new Redis();
|
||||
$redis = new Redis();
|
||||
try {
|
||||
if (!empty(getenv('VALKEY_SLAVEOF_IP'))) {
|
||||
$valkey->connect(getenv('VALKEY_SLAVEOF_IP'), getenv('VALKEY_SLAVEOF_PORT'));
|
||||
if (!empty(getenv('REDIS_SLAVEOF_IP'))) {
|
||||
$redis->connect(getenv('REDIS_SLAVEOF_IP'), getenv('REDIS_SLAVEOF_PORT'));
|
||||
}
|
||||
else {
|
||||
$valkey->connect('valkey-mailcow', 6379);
|
||||
$redis->connect('redis-mailcow', 6379);
|
||||
}
|
||||
$valkey->auth(getenv("VALKEYPASS"));
|
||||
$redis->auth(getenv("REDISPASS"));
|
||||
}
|
||||
catch (Exception $e) {
|
||||
exit;
|
||||
@@ -15,4 +15,4 @@ catch (Exception $e) {
|
||||
header('Content-Type: application/json');
|
||||
echo '{"error":"Unauthorized"}';
|
||||
error_log("Rspamd UI: Invalid password by " . $_SERVER['REMOTE_ADDR']);
|
||||
$valkey->publish("F2B_CHANNEL", "Rspamd UI: Invalid password by " . $_SERVER['REMOTE_ADDR']);
|
||||
$redis->publish("F2B_CHANNEL", "Rspamd UI: Invalid password by " . $_SERVER['REMOTE_ADDR']);
|
||||
|
||||
@@ -21,7 +21,7 @@ $clamd_status = (preg_match("/^([yY][eE][sS]|[yY])+$/", $_ENV["SKIP_CLAMD"])) ?
|
||||
$olefy_status = (preg_match("/^([yY][eE][sS]|[yY])+$/", $_ENV["SKIP_OLEFY"])) ? false : true;
|
||||
|
||||
|
||||
if (!isset($_SESSION['gal']) && $license_cache = $valkey->Get('LICENSE_STATUS_CACHE')) {
|
||||
if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CACHE')) {
|
||||
$_SESSION['gal'] = json_decode($license_cache, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -5412,9 +5412,9 @@ paths:
|
||||
started_at: "2019-12-22T21:00:07.186717617Z"
|
||||
state: running
|
||||
type: info
|
||||
valkey-mailcow:
|
||||
container: valkey-mailcow
|
||||
image: "valkey:7.2.8-alpine"
|
||||
redis-mailcow:
|
||||
container: redis-mailcow
|
||||
image: "redis:5-alpine"
|
||||
started_at: "2019-12-22T20:59:56.827166834Z"
|
||||
state: running
|
||||
type: info
|
||||
|
||||
@@ -7,19 +7,21 @@ if(file_exists('inc/vars.local.inc.php')) {
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.inc.php';
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.auth.inc.php';
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/sessions.inc.php';
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.mailbox.inc.php';
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.ratelimit.inc.php';
|
||||
$default_autodiscover_config = $autodiscover_config;
|
||||
$autodiscover_config = array_merge($default_autodiscover_config, $autodiscover_config);
|
||||
|
||||
// Valkey
|
||||
$valkey = new Redis();
|
||||
// Redis
|
||||
$redis = new Redis();
|
||||
try {
|
||||
if (!empty(getenv('VALKEY_SLAVEOF_IP'))) {
|
||||
$valkey->connect(getenv('VALKEY_SLAVEOF_IP'), getenv('VALKEY_SLAVEOF_PORT'));
|
||||
if (!empty(getenv('REDIS_SLAVEOF_IP'))) {
|
||||
$redis->connect(getenv('REDIS_SLAVEOF_IP'), getenv('REDIS_SLAVEOF_PORT'));
|
||||
}
|
||||
else {
|
||||
$valkey->connect('valkey-mailcow', 6379);
|
||||
$redis->connect('redis-mailcow', 6379);
|
||||
}
|
||||
$valkey->auth(getenv("VALKEYPASS"));
|
||||
$redis->auth(getenv("REDISPASS"));
|
||||
}
|
||||
catch (Exception $e) {
|
||||
exit;
|
||||
@@ -71,7 +73,7 @@ if (empty($_SERVER['PHP_AUTH_USER']) || empty($_SERVER['PHP_AUTH_PW'])) {
|
||||
"service" => "Error: must be authenticated"
|
||||
)
|
||||
);
|
||||
$valkey->lPush('AUTODISCOVER_LOG', $json);
|
||||
$redis->lPush('AUTODISCOVER_LOG', $json);
|
||||
header('WWW-Authenticate: Basic realm="' . $_SERVER['HTTP_HOST'] . '"');
|
||||
header('HTTP/1.0 401 Unauthorized');
|
||||
exit(0);
|
||||
@@ -96,13 +98,13 @@ if ($login_role === "user") {
|
||||
"service" => "Error: invalid or missing request data"
|
||||
)
|
||||
);
|
||||
$valkey->lPush('AUTODISCOVER_LOG', $json);
|
||||
$valkey->lTrim('AUTODISCOVER_LOG', 0, 100);
|
||||
$redis->lPush('AUTODISCOVER_LOG', $json);
|
||||
$redis->lTrim('AUTODISCOVER_LOG', 0, 100);
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'Valkey: '.$e
|
||||
'msg' => 'Redis: '.$e
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -151,13 +153,13 @@ if ($login_role === "user") {
|
||||
"service" => $autodiscover_config['autodiscoverType']
|
||||
)
|
||||
);
|
||||
$valkey->lPush('AUTODISCOVER_LOG', $json);
|
||||
$valkey->lTrim('AUTODISCOVER_LOG', 0, 100);
|
||||
$redis->lPush('AUTODISCOVER_LOG', $json);
|
||||
$redis->lTrim('AUTODISCOVER_LOG', 0, 100);
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'Valkey: '.$e
|
||||
'msg' => 'Redis: '.$e
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
function check_login($user, $pass, $app_passwd_data = false, $extra = null) {
|
||||
global $pdo;
|
||||
global $valkey;
|
||||
global $redis;
|
||||
|
||||
$is_internal = $extra['is_internal'];
|
||||
$role = $extra['role'];
|
||||
@@ -62,12 +62,12 @@ function check_login($user, $pass, $app_passwd_data = false, $extra = null) {
|
||||
|
||||
if (!isset($_SESSION['ldelay'])) {
|
||||
$_SESSION['ldelay'] = "0";
|
||||
$valkey->publish("F2B_CHANNEL", "mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']);
|
||||
$redis->publish("F2B_CHANNEL", "mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']);
|
||||
error_log("mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']);
|
||||
}
|
||||
elseif (!isset($_SESSION['mailcow_cc_username'])) {
|
||||
$_SESSION['ldelay'] = $_SESSION['ldelay']+0.5;
|
||||
$valkey->publish("F2B_CHANNEL", "mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']);
|
||||
$redis->publish("F2B_CHANNEL", "mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']);
|
||||
error_log("mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']);
|
||||
}
|
||||
$_SESSION['return'][] = array(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
function customize($_action, $_item, $_data = null) {
|
||||
global $valkey;
|
||||
global $redis;
|
||||
global $lang;
|
||||
global $LOGO_LIMITS;
|
||||
|
||||
@@ -82,13 +82,13 @@ function customize($_action, $_item, $_data = null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
$valkey->Set(strtoupper($_item), 'data:' . $_data[$_item]['type'] . ';base64,' . base64_encode(file_get_contents($_data[$_item]['tmp_name'])));
|
||||
$redis->Set(strtoupper($_item), 'data:' . $_data[$_item]['type'] . ';base64,' . base64_encode(file_get_contents($_data[$_item]['tmp_name'])));
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -134,13 +134,13 @@ function customize($_action, $_item, $_data = null) {
|
||||
));
|
||||
}
|
||||
try {
|
||||
$valkey->set('APP_LINKS', json_encode($out));
|
||||
$redis->set('APP_LINKS', json_encode($out));
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -162,20 +162,20 @@ function customize($_action, $_item, $_data = null) {
|
||||
$ui_announcement_active = (!empty($_data['ui_announcement_active']) ? 1 : 0);
|
||||
|
||||
try {
|
||||
$valkey->set('TITLE_NAME', htmlspecialchars($title_name));
|
||||
$valkey->set('MAIN_NAME', htmlspecialchars($main_name));
|
||||
$valkey->set('APPS_NAME', htmlspecialchars($apps_name));
|
||||
$valkey->set('HELP_TEXT', $help_text);
|
||||
$valkey->set('UI_FOOTER', $ui_footer);
|
||||
$valkey->set('UI_ANNOUNCEMENT_TEXT', $ui_announcement_text);
|
||||
$valkey->set('UI_ANNOUNCEMENT_TYPE', $ui_announcement_type);
|
||||
$valkey->set('UI_ANNOUNCEMENT_ACTIVE', $ui_announcement_active);
|
||||
$redis->set('TITLE_NAME', htmlspecialchars($title_name));
|
||||
$redis->set('MAIN_NAME', htmlspecialchars($main_name));
|
||||
$redis->set('APPS_NAME', htmlspecialchars($apps_name));
|
||||
$redis->set('HELP_TEXT', $help_text);
|
||||
$redis->set('UI_FOOTER', $ui_footer);
|
||||
$redis->set('UI_ANNOUNCEMENT_TEXT', $ui_announcement_text);
|
||||
$redis->set('UI_ANNOUNCEMENT_TYPE', $ui_announcement_type);
|
||||
$redis->set('UI_ANNOUNCEMENT_ACTIVE', $ui_announcement_active);
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -188,13 +188,13 @@ function customize($_action, $_item, $_data = null) {
|
||||
case 'ip_check':
|
||||
$ip_check = ($_data['ip_check_opt_in'] == "1") ? 1 : 0;
|
||||
try {
|
||||
$valkey->set('IP_CHECK', $ip_check);
|
||||
$redis->set('IP_CHECK', $ip_check);
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -217,7 +217,7 @@ function customize($_action, $_item, $_data = null) {
|
||||
"force_sso" => $force_sso,
|
||||
);
|
||||
try {
|
||||
$valkey->set('CUSTOM_LOGIN', json_encode($custom_login));
|
||||
$redis->set('CUSTOM_LOGIN', json_encode($custom_login));
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
@@ -257,7 +257,7 @@ function customize($_action, $_item, $_data = null) {
|
||||
case 'main_logo':
|
||||
case 'main_logo_dark':
|
||||
try {
|
||||
if ($valkey->del(strtoupper($_item))) {
|
||||
if ($redis->del(strtoupper($_item))) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
||||
@@ -270,7 +270,7 @@ function customize($_action, $_item, $_data = null) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -281,13 +281,13 @@ function customize($_action, $_item, $_data = null) {
|
||||
switch ($_item) {
|
||||
case 'app_links':
|
||||
try {
|
||||
$app_links = json_decode($valkey->get('APP_LINKS'), true);
|
||||
$app_links = json_decode($redis->get('APP_LINKS'), true);
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -312,13 +312,13 @@ function customize($_action, $_item, $_data = null) {
|
||||
case 'main_logo':
|
||||
case 'main_logo_dark':
|
||||
try {
|
||||
return $valkey->get(strtoupper($_item));
|
||||
return $redis->get(strtoupper($_item));
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -327,25 +327,25 @@ function customize($_action, $_item, $_data = null) {
|
||||
try {
|
||||
$mailcow_hostname = strtolower(getenv("MAILCOW_HOSTNAME"));
|
||||
|
||||
$data['title_name'] = ($title_name = $valkey->get('TITLE_NAME')) ? $title_name : "$mailcow_hostname - mail UI";
|
||||
$data['main_name'] = ($main_name = $valkey->get('MAIN_NAME')) ? $main_name : "$mailcow_hostname - mail UI";
|
||||
$data['apps_name'] = ($apps_name = $valkey->get('APPS_NAME')) ? $apps_name : $lang['header']['apps'];
|
||||
$data['help_text'] = ($help_text = $valkey->get('HELP_TEXT')) ? $help_text : false;
|
||||
if (!empty($valkey->get('UI_IMPRESS'))) {
|
||||
$valkey->set('UI_FOOTER', $valkey->get('UI_IMPRESS'));
|
||||
$valkey->del('UI_IMPRESS');
|
||||
$data['title_name'] = ($title_name = $redis->get('TITLE_NAME')) ? $title_name : "$mailcow_hostname - mail UI";
|
||||
$data['main_name'] = ($main_name = $redis->get('MAIN_NAME')) ? $main_name : "$mailcow_hostname - mail UI";
|
||||
$data['apps_name'] = ($apps_name = $redis->get('APPS_NAME')) ? $apps_name : $lang['header']['apps'];
|
||||
$data['help_text'] = ($help_text = $redis->get('HELP_TEXT')) ? $help_text : false;
|
||||
if (!empty($redis->get('UI_IMPRESS'))) {
|
||||
$redis->set('UI_FOOTER', $redis->get('UI_IMPRESS'));
|
||||
$redis->del('UI_IMPRESS');
|
||||
}
|
||||
$data['ui_footer'] = ($ui_footer = $valkey->get('UI_FOOTER')) ? $ui_footer : false;
|
||||
$data['ui_announcement_text'] = ($ui_announcement_text = $valkey->get('UI_ANNOUNCEMENT_TEXT')) ? $ui_announcement_text : false;
|
||||
$data['ui_announcement_type'] = ($ui_announcement_type = $valkey->get('UI_ANNOUNCEMENT_TYPE')) ? $ui_announcement_type : false;
|
||||
$data['ui_announcement_active'] = ($valkey->get('UI_ANNOUNCEMENT_ACTIVE') == 1) ? 1 : 0;
|
||||
$data['ui_footer'] = ($ui_footer = $redis->get('UI_FOOTER')) ? $ui_footer : false;
|
||||
$data['ui_announcement_text'] = ($ui_announcement_text = $redis->get('UI_ANNOUNCEMENT_TEXT')) ? $ui_announcement_text : false;
|
||||
$data['ui_announcement_type'] = ($ui_announcement_type = $redis->get('UI_ANNOUNCEMENT_TYPE')) ? $ui_announcement_type : false;
|
||||
$data['ui_announcement_active'] = ($redis->get('UI_ANNOUNCEMENT_ACTIVE') == 1) ? 1 : 0;
|
||||
return $data;
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -376,21 +376,21 @@ function customize($_action, $_item, $_data = null) {
|
||||
break;
|
||||
case 'ip_check':
|
||||
try {
|
||||
$ip_check = ($ip_check = $valkey->get('IP_CHECK')) ? $ip_check : 0;
|
||||
$ip_check = ($ip_check = $redis->get('IP_CHECK')) ? $ip_check : 0;
|
||||
return $ip_check;
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 'custom_login':
|
||||
try {
|
||||
$custom_login = $valkey->get('CUSTOM_LOGIN');
|
||||
$custom_login = $redis->get('CUSTOM_LOGIN');
|
||||
return $custom_login ? json_decode($custom_login, true) : array();
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
function dkim($_action, $_data = null, $privkey = false) {
|
||||
global $valkey;
|
||||
global $redis;
|
||||
global $lang;
|
||||
switch ($_action) {
|
||||
case 'add':
|
||||
@@ -18,7 +18,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||
);
|
||||
continue;
|
||||
}
|
||||
if ($valkey->hGet('DKIM_PUB_KEYS', $domain)) {
|
||||
if ($redis->hGet('DKIM_PUB_KEYS', $domain)) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
@@ -54,30 +54,30 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||
explode(PHP_EOL, $key_details['key'])
|
||||
), 1, -1)
|
||||
);
|
||||
// Save public key and selector to valkey
|
||||
// Save public key and selector to redis
|
||||
try {
|
||||
$valkey->hSet('DKIM_PUB_KEYS', $domain, $pubKey);
|
||||
$valkey->hSet('DKIM_SELECTORS', $domain, $dkim_selector);
|
||||
$redis->hSet('DKIM_PUB_KEYS', $domain, $pubKey);
|
||||
$redis->hSet('DKIM_SELECTORS', $domain, $dkim_selector);
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
// Export private key and save private key to valkey
|
||||
// Export private key and save private key to redis
|
||||
openssl_pkey_export($keypair_ressource, $privKey);
|
||||
if (isset($privKey) && !empty($privKey)) {
|
||||
try {
|
||||
$valkey->hSet('DKIM_PRIV_KEYS', $dkim_selector . '.' . $domain, trim($privKey));
|
||||
$redis->hSet('DKIM_PRIV_KEYS', $dkim_selector . '.' . $domain, trim($privKey));
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
@@ -121,15 +121,15 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||
$to_domains = array_filter($to_domains);
|
||||
foreach ($to_domains as $to_domain) {
|
||||
try {
|
||||
$valkey->hSet('DKIM_PUB_KEYS', $to_domain, $from_domain_dkim['pubkey']);
|
||||
$valkey->hSet('DKIM_SELECTORS', $to_domain, $from_domain_dkim['dkim_selector']);
|
||||
$valkey->hSet('DKIM_PRIV_KEYS', $from_domain_dkim['dkim_selector'] . '.' . $to_domain, base64_decode(trim($from_domain_dkim['privkey'])));
|
||||
$redis->hSet('DKIM_PUB_KEYS', $to_domain, $from_domain_dkim['pubkey']);
|
||||
$redis->hSet('DKIM_SELECTORS', $to_domain, $from_domain_dkim['dkim_selector']);
|
||||
$redis->hSet('DKIM_PRIV_KEYS', $from_domain_dkim['dkim_selector'] . '.' . $to_domain, base64_decode(trim($from_domain_dkim['privkey'])));
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
@@ -178,7 +178,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if ($valkey->hGet('DKIM_PUB_KEYS', $domain)) {
|
||||
if ($redis->hGet('DKIM_PUB_KEYS', $domain)) {
|
||||
if ($overwrite_existing == 0) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
@@ -198,15 +198,15 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||
}
|
||||
try {
|
||||
dkim('delete', array('domains' => $domain));
|
||||
$valkey->hSet('DKIM_PUB_KEYS', $domain, $pem_public_key);
|
||||
$valkey->hSet('DKIM_SELECTORS', $domain, $dkim_selector);
|
||||
$valkey->hSet('DKIM_PRIV_KEYS', $dkim_selector . '.' . $domain, $private_key_normalized);
|
||||
$redis->hSet('DKIM_PUB_KEYS', $domain, $pem_public_key);
|
||||
$redis->hSet('DKIM_SELECTORS', $domain, $dkim_selector);
|
||||
$redis->hSet('DKIM_PRIV_KEYS', $dkim_selector . '.' . $domain, $private_key_normalized);
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -219,7 +219,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -235,8 +235,8 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||
return false;
|
||||
}
|
||||
$dkimdata = array();
|
||||
if ($valkey_dkim_key_data = $valkey->hGet('DKIM_PUB_KEYS', $_data)) {
|
||||
$dkimdata['pubkey'] = $valkey_dkim_key_data;
|
||||
if ($redis_dkim_key_data = $redis->hGet('DKIM_PUB_KEYS', $_data)) {
|
||||
$dkimdata['pubkey'] = $redis_dkim_key_data;
|
||||
if (strlen($dkimdata['pubkey']) < 391) {
|
||||
$dkimdata['length'] = "1024";
|
||||
}
|
||||
@@ -253,15 +253,15 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||
$dkimdata['length'] = ">= 8192";
|
||||
}
|
||||
if ($GLOBALS['SPLIT_DKIM_255'] === true) {
|
||||
$dkim_txt_tmp = str_split('v=DKIM1;k=rsa;t=s;s=email;p=' . $valkey_dkim_key_data, 255);
|
||||
$dkim_txt_tmp = str_split('v=DKIM1;k=rsa;t=s;s=email;p=' . $redis_dkim_key_data, 255);
|
||||
$dkimdata['dkim_txt'] = sprintf('"%s"', implode('" "', (array)$dkim_txt_tmp ) );
|
||||
}
|
||||
else {
|
||||
$dkimdata['dkim_txt'] = 'v=DKIM1;k=rsa;t=s;s=email;p=' . $valkey_dkim_key_data;
|
||||
$dkimdata['dkim_txt'] = 'v=DKIM1;k=rsa;t=s;s=email;p=' . $redis_dkim_key_data;
|
||||
}
|
||||
$dkimdata['dkim_selector'] = $valkey->hGet('DKIM_SELECTORS', $_data);
|
||||
$dkimdata['dkim_selector'] = $redis->hGet('DKIM_SELECTORS', $_data);
|
||||
if ($GLOBALS['SHOW_DKIM_PRIV_KEYS'] || $privkey == true) {
|
||||
$dkimdata['privkey'] = base64_encode($valkey->hGet('DKIM_PRIV_KEYS', $dkimdata['dkim_selector'] . '.' . $_data));
|
||||
$dkimdata['privkey'] = base64_encode($redis->hGet('DKIM_PRIV_KEYS', $dkimdata['dkim_selector'] . '.' . $_data));
|
||||
}
|
||||
else {
|
||||
$dkimdata['privkey'] = '';
|
||||
@@ -279,8 +279,8 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||
return false;
|
||||
}
|
||||
$blinddkim = array();
|
||||
foreach ($valkey->hKeys('DKIM_PUB_KEYS') as $valkey_dkim_domain) {
|
||||
$blinddkim[] = $valkey_dkim_domain;
|
||||
foreach ($redis->hKeys('DKIM_PUB_KEYS') as $redis_dkim_domain) {
|
||||
$blinddkim[] = $redis_dkim_domain;
|
||||
}
|
||||
return array_diff($blinddkim, array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains')));
|
||||
break;
|
||||
@@ -304,16 +304,16 @@ function dkim($_action, $_data = null, $privkey = false) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
$selector = $valkey->hGet('DKIM_SELECTORS', $domain);
|
||||
$valkey->hDel('DKIM_PUB_KEYS', $domain);
|
||||
$valkey->hDel('DKIM_PRIV_KEYS', $selector . '.' . $domain);
|
||||
$valkey->hDel('DKIM_SELECTORS', $domain);
|
||||
$selector = $redis->hGet('DKIM_SELECTORS', $domain);
|
||||
$redis->hDel('DKIM_PUB_KEYS', $domain);
|
||||
$redis->hDel('DKIM_PRIV_KEYS', $selector . '.' . $domain);
|
||||
$redis->hDel('DKIM_SELECTORS', $domain);
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $extra_headers = null) {
|
||||
global $DOCKER_TIMEOUT;
|
||||
global $valkey;
|
||||
global $redis;
|
||||
$curl = curl_init();
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER,array('Content-Type: application/json' ));
|
||||
// We are using our mail certificates for dockerapi, the names will not match, the certs are trusted anyway
|
||||
@@ -102,7 +102,7 @@ function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $ex
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (isset($decoded_response['Config']['Labels']['com.docker.compose.project'])
|
||||
if (isset($decoded_response['Config']['Labels']['com.docker.compose.project'])
|
||||
&& strtolower($decoded_response['Config']['Labels']['com.docker.compose.project']) == strtolower(getenv('COMPOSE_PROJECT_NAME'))) {
|
||||
unset($container['Config']['Env']);
|
||||
$out[$decoded_response['Config']['Labels']['com.docker.compose.service']]['State'] = $decoded_response['State'];
|
||||
@@ -200,7 +200,7 @@ function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $ex
|
||||
"request" => $attr2
|
||||
);
|
||||
|
||||
$valkey->publish("MC_CHANNEL", json_encode($request));
|
||||
$redis->publish("MC_CHANNEL", json_encode($request));
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
function fail2ban($_action, $_data = null, $_extra = null) {
|
||||
global $valkey;
|
||||
global $redis;
|
||||
$_data_log = $_data;
|
||||
switch ($_action) {
|
||||
case 'get':
|
||||
@@ -9,9 +9,9 @@ function fail2ban($_action, $_data = null, $_extra = null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
$f2b_options = json_decode($valkey->Get('F2B_OPTIONS'), true);
|
||||
$f2b_options['regex'] = json_decode($valkey->Get('F2B_REGEX'), true);
|
||||
$wl = $valkey->hGetAll('F2B_WHITELIST');
|
||||
$f2b_options = json_decode($redis->Get('F2B_OPTIONS'), true);
|
||||
$f2b_options['regex'] = json_decode($redis->Get('F2B_REGEX'), true);
|
||||
$wl = $redis->hGetAll('F2B_WHITELIST');
|
||||
if (is_array($wl)) {
|
||||
foreach ($wl as $key => $value) {
|
||||
$tmp_wl_data[] = $key;
|
||||
@@ -27,7 +27,7 @@ function fail2ban($_action, $_data = null, $_extra = null) {
|
||||
else {
|
||||
$f2b_options['whitelist'] = "";
|
||||
}
|
||||
$bl = $valkey->hGetAll('F2B_BLACKLIST');
|
||||
$bl = $redis->hGetAll('F2B_BLACKLIST');
|
||||
if (is_array($bl)) {
|
||||
foreach ($bl as $key => $value) {
|
||||
$tmp_bl_data[] = $key;
|
||||
@@ -43,7 +43,7 @@ function fail2ban($_action, $_data = null, $_extra = null) {
|
||||
else {
|
||||
$f2b_options['blacklist'] = "";
|
||||
}
|
||||
$pb = $valkey->hGetAll('F2B_PERM_BANS');
|
||||
$pb = $redis->hGetAll('F2B_PERM_BANS');
|
||||
if (is_array($pb)) {
|
||||
foreach ($pb as $key => $value) {
|
||||
$f2b_options['perm_bans'][] = array(
|
||||
@@ -56,8 +56,8 @@ function fail2ban($_action, $_data = null, $_extra = null) {
|
||||
else {
|
||||
$f2b_options['perm_bans'] = "";
|
||||
}
|
||||
$active_bans = $valkey->hGetAll('F2B_ACTIVE_BANS');
|
||||
$queue_unban = $valkey->hGetAll('F2B_QUEUE_UNBAN');
|
||||
$active_bans = $redis->hGetAll('F2B_ACTIVE_BANS');
|
||||
$queue_unban = $redis->hGetAll('F2B_QUEUE_UNBAN');
|
||||
if (is_array($active_bans)) {
|
||||
foreach ($active_bans as $network => $banned_until) {
|
||||
$queued_for_unban = (isset($queue_unban[$network]) && $queue_unban[$network] == 1) ? 1 : 0;
|
||||
@@ -78,7 +78,7 @@ function fail2ban($_action, $_data = null, $_extra = null) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -98,22 +98,22 @@ function fail2ban($_action, $_data = null, $_extra = null) {
|
||||
// Reset regex filters
|
||||
if ($_data['action'] == "reset-regex") {
|
||||
try {
|
||||
$valkey->Del('F2B_REGEX');
|
||||
$redis->Del('F2B_REGEX');
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
// Rules will also be recreated on log events, but rules may seem empty for a second in the UI
|
||||
docker('post', 'netfilter-mailcow', 'restart');
|
||||
$fail_count = 0;
|
||||
$regex_result = json_decode($valkey->Get('F2B_REGEX'), true);
|
||||
$regex_result = json_decode($redis->Get('F2B_REGEX'), true);
|
||||
while (empty($regex_result) && $fail_count < 10) {
|
||||
$regex_result = json_decode($valkey->Get('F2B_REGEX'), true);
|
||||
$regex_result = json_decode($redis->Get('F2B_REGEX'), true);
|
||||
$fail_count++;
|
||||
sleep(1);
|
||||
}
|
||||
@@ -135,7 +135,7 @@ function fail2ban($_action, $_data = null, $_extra = null) {
|
||||
$rule_id++;
|
||||
}
|
||||
if (!empty($regex_array)) {
|
||||
$valkey->Set('F2B_REGEX', json_encode($regex_array, JSON_UNESCAPED_SLASHES));
|
||||
$redis->Set('F2B_REGEX', json_encode($regex_array, JSON_UNESCAPED_SLASHES));
|
||||
}
|
||||
}
|
||||
$_SESSION['return'][] = array(
|
||||
@@ -154,13 +154,13 @@ function fail2ban($_action, $_data = null, $_extra = null) {
|
||||
if ($_data['action'] == "unban") {
|
||||
if (valid_network($network)) {
|
||||
try {
|
||||
$valkey->hSet('F2B_QUEUE_UNBAN', $network, 1);
|
||||
$redis->hSet('F2B_QUEUE_UNBAN', $network, 1);
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
@@ -171,15 +171,15 @@ function fail2ban($_action, $_data = null, $_extra = null) {
|
||||
if (empty($network)) { continue; }
|
||||
if (valid_network($network)) {
|
||||
try {
|
||||
$valkey->hSet('F2B_WHITELIST', $network, 1);
|
||||
$valkey->hDel('F2B_BLACKLIST', $network, 1);
|
||||
$valkey->hSet('F2B_QUEUE_UNBAN', $network, 1);
|
||||
$redis->hSet('F2B_WHITELIST', $network, 1);
|
||||
$redis->hDel('F2B_BLACKLIST', $network, 1);
|
||||
$redis->hSet('F2B_QUEUE_UNBAN', $network, 1);
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
@@ -204,15 +204,15 @@ function fail2ban($_action, $_data = null, $_extra = null) {
|
||||
getenv('IPV6_NETWORK')
|
||||
))) {
|
||||
try {
|
||||
$valkey->hSet('F2B_BLACKLIST', $network, 1);
|
||||
$valkey->hDel('F2B_WHITELIST', $network, 1);
|
||||
$redis->hSet('F2B_BLACKLIST', $network, 1);
|
||||
$redis->hDel('F2B_WHITELIST', $network, 1);
|
||||
//$response = docker('post', 'netfilter-mailcow', 'restart');
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
@@ -270,16 +270,16 @@ function fail2ban($_action, $_data = null, $_extra = null) {
|
||||
$f2b_options['banlist_id'] = $is_now['banlist_id'];
|
||||
$f2b_options['manage_external'] = ($manage_external > 0) ? 1 : 0;
|
||||
try {
|
||||
$valkey->Set('F2B_OPTIONS', json_encode($f2b_options));
|
||||
$valkey->Del('F2B_WHITELIST');
|
||||
$valkey->Del('F2B_BLACKLIST');
|
||||
$redis->Set('F2B_OPTIONS', json_encode($f2b_options));
|
||||
$redis->Del('F2B_WHITELIST');
|
||||
$redis->Del('F2B_BLACKLIST');
|
||||
if(!empty($wl)) {
|
||||
$wl_array = array_map('trim', preg_split( "/( |,|;|\n)/", $wl));
|
||||
$wl_array = array_filter($wl_array);
|
||||
if (is_array($wl_array)) {
|
||||
foreach ($wl_array as $wl_item) {
|
||||
if (valid_network($wl_item) || valid_hostname($wl_item)) {
|
||||
$valkey->hSet('F2B_WHITELIST', $wl_item, 1);
|
||||
$redis->hSet('F2B_WHITELIST', $wl_item, 1);
|
||||
}
|
||||
else {
|
||||
$_SESSION['return'][] = array(
|
||||
@@ -304,7 +304,7 @@ function fail2ban($_action, $_data = null, $_extra = null) {
|
||||
getenv('IPV4_NETWORK') . '0',
|
||||
getenv('IPV6_NETWORK')
|
||||
))) {
|
||||
$valkey->hSet('F2B_BLACKLIST', $bl_item, 1);
|
||||
$redis->hSet('F2B_BLACKLIST', $bl_item, 1);
|
||||
}
|
||||
else {
|
||||
$_SESSION['return'][] = array(
|
||||
@@ -322,7 +322,7 @@ function fail2ban($_action, $_data = null, $_extra = null) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -334,13 +334,13 @@ function fail2ban($_action, $_data = null, $_extra = null) {
|
||||
break;
|
||||
case 'banlist':
|
||||
try {
|
||||
$f2b_options = json_decode($valkey->Get('F2B_OPTIONS'), true);
|
||||
}
|
||||
$f2b_options = json_decode($redis->Get('F2B_OPTIONS'), true);
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log, $_extra),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
http_response_code(500);
|
||||
return false;
|
||||
@@ -356,14 +356,14 @@ function fail2ban($_action, $_data = null, $_extra = null) {
|
||||
switch ($_data) {
|
||||
case 'get':
|
||||
try {
|
||||
$bl = $valkey->hKeys('F2B_BLACKLIST');
|
||||
$active_bans = $valkey->hKeys('F2B_ACTIVE_BANS');
|
||||
}
|
||||
$bl = $redis->hKeys('F2B_BLACKLIST');
|
||||
$active_bans = $redis->hKeys('F2B_ACTIVE_BANS');
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log, $_extra),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
http_response_code(500);
|
||||
return false;
|
||||
@@ -378,13 +378,13 @@ function fail2ban($_action, $_data = null, $_extra = null) {
|
||||
|
||||
$f2b_options['banlist_id'] = uuid4();
|
||||
try {
|
||||
$valkey->Set('F2B_OPTIONS', json_encode($f2b_options));
|
||||
}
|
||||
$redis->Set('F2B_OPTIONS', json_encode($f2b_options));
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log, $_extra),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
function fwdhost($_action, $_data = null) {
|
||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/spf.inc.php';
|
||||
global $valkey;
|
||||
global $redis;
|
||||
global $lang;
|
||||
$_data_log = $_data;
|
||||
switch ($_action) {
|
||||
@@ -37,19 +37,19 @@ function fwdhost($_action, $_data = null) {
|
||||
}
|
||||
foreach ($hosts as $host) {
|
||||
try {
|
||||
$valkey->hSet('WHITELISTED_FWD_HOST', $host, $source);
|
||||
$redis->hSet('WHITELISTED_FWD_HOST', $host, $source);
|
||||
if ($filter_spam == 0) {
|
||||
$valkey->hSet('KEEP_SPAM', $host, 1);
|
||||
$redis->hSet('KEEP_SPAM', $host, 1);
|
||||
}
|
||||
elseif ($valkey->hGet('KEEP_SPAM', $host)) {
|
||||
$valkey->hDel('KEEP_SPAM', $host);
|
||||
elseif ($redis->hGet('KEEP_SPAM', $host)) {
|
||||
$redis->hDel('KEEP_SPAM', $host);
|
||||
}
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -86,17 +86,17 @@ function fwdhost($_action, $_data = null) {
|
||||
}
|
||||
try {
|
||||
if ($keep_spam == 1) {
|
||||
$valkey->hSet('KEEP_SPAM', $fwdhost, 1);
|
||||
$redis->hSet('KEEP_SPAM', $fwdhost, 1);
|
||||
}
|
||||
else {
|
||||
$valkey->hDel('KEEP_SPAM', $fwdhost);
|
||||
$redis->hDel('KEEP_SPAM', $fwdhost);
|
||||
}
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
@@ -111,14 +111,14 @@ function fwdhost($_action, $_data = null) {
|
||||
$hosts = (array)$_data['forwardinghost'];
|
||||
foreach ($hosts as $host) {
|
||||
try {
|
||||
$valkey->hDel('WHITELISTED_FWD_HOST', $host);
|
||||
$valkey->hDel('KEEP_SPAM', $host);
|
||||
$redis->hDel('WHITELISTED_FWD_HOST', $host);
|
||||
$redis->hDel('KEEP_SPAM', $host);
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
@@ -135,10 +135,10 @@ function fwdhost($_action, $_data = null) {
|
||||
}
|
||||
$fwdhostsdata = array();
|
||||
try {
|
||||
$fwd_hosts = $valkey->hGetAll('WHITELISTED_FWD_HOST');
|
||||
$fwd_hosts = $redis->hGetAll('WHITELISTED_FWD_HOST');
|
||||
if (!empty($fwd_hosts)) {
|
||||
foreach ($fwd_hosts as $fwd_host => $source) {
|
||||
$keep_spam = ($valkey->hGet('KEEP_SPAM', $fwd_host)) ? "yes" : "no";
|
||||
$keep_spam = ($redis->hGet('KEEP_SPAM', $fwd_host)) ? "yes" : "no";
|
||||
$fwdhostsdata[] = array(
|
||||
'host' => $fwd_host,
|
||||
'source' => $source,
|
||||
@@ -151,7 +151,7 @@ function fwdhost($_action, $_data = null) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -163,17 +163,17 @@ function fwdhost($_action, $_data = null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
if ($source = $valkey->hGet('WHITELISTED_FWD_HOST', $_data)) {
|
||||
if ($source = $redis->hGet('WHITELISTED_FWD_HOST', $_data)) {
|
||||
$fwdhostdetails['host'] = $_data;
|
||||
$fwdhostdetails['source'] = $source;
|
||||
$fwdhostdetails['keep_spam'] = ($valkey->hGet('KEEP_SPAM', $_data)) ? "yes" : "no";
|
||||
$fwdhostdetails['keep_spam'] = ($redis->hGet('KEEP_SPAM', $_data)) ? "yes" : "no";
|
||||
}
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ function hash_password($password) {
|
||||
return $pw_hash;
|
||||
}
|
||||
function password_complexity($_action, $_data = null) {
|
||||
global $valkey;
|
||||
global $redis;
|
||||
global $lang;
|
||||
switch ($_action) {
|
||||
case 'edit':
|
||||
@@ -147,7 +147,7 @@ function password_complexity($_action, $_data = null) {
|
||||
$numbers = (isset($_data['numbers'])) ? intval($_data['numbers']) : $is_now['numbers'];
|
||||
}
|
||||
try {
|
||||
$valkey->hMSet('PASSWD_POLICY', [
|
||||
$redis->hMSet('PASSWD_POLICY', [
|
||||
'length' => $length,
|
||||
'chars' => $chars,
|
||||
'special_chars' => $special_chars,
|
||||
@@ -159,7 +159,7 @@ function password_complexity($_action, $_data = null) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -171,11 +171,11 @@ function password_complexity($_action, $_data = null) {
|
||||
break;
|
||||
case 'get':
|
||||
try {
|
||||
$length = $valkey->hGet('PASSWD_POLICY', 'length');
|
||||
$chars = $valkey->hGet('PASSWD_POLICY', 'chars');
|
||||
$special_chars = $valkey->hGet('PASSWD_POLICY', 'special_chars');
|
||||
$lowerupper = $valkey->hGet('PASSWD_POLICY', 'lowerupper');
|
||||
$numbers = $valkey->hGet('PASSWD_POLICY', 'numbers');
|
||||
$length = $redis->hGet('PASSWD_POLICY', 'length');
|
||||
$chars = $redis->hGet('PASSWD_POLICY', 'chars');
|
||||
$special_chars = $redis->hGet('PASSWD_POLICY', 'special_chars');
|
||||
$lowerupper = $redis->hGet('PASSWD_POLICY', 'lowerupper');
|
||||
$numbers = $redis->hGet('PASSWD_POLICY', 'numbers');
|
||||
return array(
|
||||
'length' => $length,
|
||||
'chars' => $chars,
|
||||
@@ -188,7 +188,7 @@ function password_complexity($_action, $_data = null) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -253,7 +253,7 @@ function password_check($password1, $password2) {
|
||||
}
|
||||
function last_login($action, $username, $sasl_limit_days = 7, $ui_offset = 1) {
|
||||
global $pdo;
|
||||
global $valkey;
|
||||
global $redis;
|
||||
$sasl_limit_days = intval($sasl_limit_days);
|
||||
switch ($action) {
|
||||
case 'get':
|
||||
@@ -272,13 +272,13 @@ function last_login($action, $username, $sasl_limit_days = 7, $ui_offset = 1) {
|
||||
}
|
||||
elseif (filter_var($sasl[$k]['real_rip'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
|
||||
try {
|
||||
$sasl[$k]['location'] = $valkey->hGet('IP_SHORTCOUNTRY', $sasl[$k]['real_rip']);
|
||||
$sasl[$k]['location'] = $redis->hGet('IP_SHORTCOUNTRY', $sasl[$k]['real_rip']);
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -294,13 +294,13 @@ function last_login($action, $username, $sasl_limit_days = 7, $ui_offset = 1) {
|
||||
if ($ip_data_array !== false and !empty($ip_data_array['shortcountry'])) {
|
||||
$sasl[$k]['location'] = $ip_data_array['shortcountry'];
|
||||
try {
|
||||
$valkey->hSet('IP_SHORTCOUNTRY', $sasl[$k]['real_rip'], $ip_data_array['shortcountry']);
|
||||
$redis->hSet('IP_SHORTCOUNTRY', $sasl[$k]['real_rip'], $ip_data_array['shortcountry']);
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
curl_close($curl);
|
||||
return false;
|
||||
@@ -1006,7 +1006,7 @@ function edit_user_account($_data) {
|
||||
update_sogo_static_view();
|
||||
}
|
||||
// edit password recovery email
|
||||
elseif (isset($pw_recovery_email)) {
|
||||
elseif (!empty($password_old) && isset($pw_recovery_email)) {
|
||||
if (!isset($_SESSION['acl']['pw_reset']) || $_SESSION['acl']['pw_reset'] != "1" ) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
@@ -1016,6 +1016,21 @@ function edit_user_account($_data) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare("SELECT `password` FROM `mailbox`
|
||||
WHERE `kind` NOT REGEXP 'location|thing|group'
|
||||
AND `username` = :user AND authsource = 'mailcow'");
|
||||
$stmt->execute(array(':user' => $username));
|
||||
$row = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!verify_hash($row['password'], $password_old)) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_data_log),
|
||||
'msg' => 'access_denied'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
$pw_recovery_email = (!filter_var($pw_recovery_email, FILTER_VALIDATE_EMAIL)) ? '' : $pw_recovery_email;
|
||||
$stmt = $pdo->prepare("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.recovery_email', :recovery_email)
|
||||
WHERE `username` = :username AND authsource = 'mailcow'");
|
||||
@@ -1999,7 +2014,7 @@ function admin_api($access, $action, $data = null) {
|
||||
}
|
||||
function license($action, $data = null) {
|
||||
global $pdo;
|
||||
global $valkey;
|
||||
global $redis;
|
||||
global $lang;
|
||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||
$_SESSION['return'][] = array(
|
||||
@@ -2049,13 +2064,13 @@ function license($action, $data = null) {
|
||||
}
|
||||
try {
|
||||
// json_encode needs "true"/"false" instead of true/false, to not encode it to 0 or 1
|
||||
$valkey->Set('LICENSE_STATUS_CACHE', json_encode($_SESSION['gal']));
|
||||
$redis->Set('LICENSE_STATUS_CACHE', json_encode($_SESSION['gal']));
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -2136,7 +2151,7 @@ function rspamd_ui($action, $data = null) {
|
||||
}
|
||||
}
|
||||
function cors($action, $data = null) {
|
||||
global $valkey;
|
||||
global $redis;
|
||||
|
||||
switch ($action) {
|
||||
case "edit":
|
||||
@@ -2177,7 +2192,7 @@ function cors($action, $data = null) {
|
||||
}
|
||||
|
||||
try {
|
||||
$valkey->hMSet('CORS_SETTINGS', array(
|
||||
$redis->hMSet('CORS_SETTINGS', array(
|
||||
'allowed_origins' => implode(', ', $allowed_origins),
|
||||
'allowed_methods' => implode(', ', $allowed_methods)
|
||||
));
|
||||
@@ -2185,7 +2200,7 @@ function cors($action, $data = null) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $action, $data),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -2199,12 +2214,12 @@ function cors($action, $data = null) {
|
||||
break;
|
||||
case "get":
|
||||
try {
|
||||
$cors_settings = $valkey->hMGet('CORS_SETTINGS', array('allowed_origins', 'allowed_methods'));
|
||||
$cors_settings = $redis->hMGet('CORS_SETTINGS', array('allowed_origins', 'allowed_methods'));
|
||||
} catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $action, $data),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2967,7 +2982,7 @@ function identity_provider($_action = null, $_data = null, $_extra = null) {
|
||||
}
|
||||
function reset_password($action, $data = null) {
|
||||
global $pdo;
|
||||
global $valkey;
|
||||
global $redis;
|
||||
global $mailcow_hostname;
|
||||
global $PW_RESET_TOKEN_LIMIT;
|
||||
global $PW_RESET_TOKEN_LIFETIME;
|
||||
@@ -3203,10 +3218,10 @@ function reset_password($action, $data = null) {
|
||||
$type = $data;
|
||||
|
||||
try {
|
||||
$settings['from'] = $valkey->Get('PW_RESET_FROM');
|
||||
$settings['subject'] = $valkey->Get('PW_RESET_SUBJ');
|
||||
$settings['html_tmpl'] = $valkey->Get('PW_RESET_HTML');
|
||||
$settings['text_tmpl'] = $valkey->Get('PW_RESET_TEXT');
|
||||
$settings['from'] = $redis->Get('PW_RESET_FROM');
|
||||
$settings['subject'] = $redis->Get('PW_RESET_SUBJ');
|
||||
$settings['html_tmpl'] = $redis->Get('PW_RESET_HTML');
|
||||
$settings['text_tmpl'] = $redis->Get('PW_RESET_TEXT');
|
||||
if (empty($settings['html_tmpl']) && empty($settings['text_tmpl'])) {
|
||||
$settings['html_tmpl'] = file_get_contents("/tpls/pw_reset_html.tpl");
|
||||
$settings['text_tmpl'] = file_get_contents("/tpls/pw_reset_text.tpl");
|
||||
@@ -3221,7 +3236,7 @@ function reset_password($action, $data = null) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $action, $_data_log),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -3324,16 +3339,16 @@ function reset_password($action, $data = null) {
|
||||
$html = (empty($data['html_tmpl'])) ? "" : $data['html_tmpl'];
|
||||
|
||||
try {
|
||||
$valkey->Set('PW_RESET_FROM', $from);
|
||||
$valkey->Set('PW_RESET_SUBJ', $subject);
|
||||
$valkey->Set('PW_RESET_HTML', $html);
|
||||
$valkey->Set('PW_RESET_TEXT', $text);
|
||||
$redis->Set('PW_RESET_FROM', $from);
|
||||
$redis->Set('PW_RESET_SUBJ', $subject);
|
||||
$redis->Set('PW_RESET_HTML', $html);
|
||||
$redis->Set('PW_RESET_TEXT', $text);
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $action, $_data_log),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -3376,7 +3391,7 @@ function get_logs($application, $lines = false) {
|
||||
$to = intval($to);
|
||||
if ($from < 1 || $to < $from) { return false; }
|
||||
}
|
||||
global $valkey;
|
||||
global $redis;
|
||||
global $pdo;
|
||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||
return false;
|
||||
@@ -3425,10 +3440,10 @@ function get_logs($application, $lines = false) {
|
||||
// Redis
|
||||
if ($application == "dovecot-mailcow") {
|
||||
if (isset($from) && isset($to)) {
|
||||
$data = $valkey->lRange('DOVECOT_MAILLOG', $from - 1, $to - 1);
|
||||
$data = $redis->lRange('DOVECOT_MAILLOG', $from - 1, $to - 1);
|
||||
}
|
||||
else {
|
||||
$data = $valkey->lRange('DOVECOT_MAILLOG', 0, $lines);
|
||||
$data = $redis->lRange('DOVECOT_MAILLOG', 0, $lines);
|
||||
}
|
||||
if ($data) {
|
||||
foreach ($data as $json_line) {
|
||||
@@ -3439,10 +3454,10 @@ function get_logs($application, $lines = false) {
|
||||
}
|
||||
if ($application == "cron-mailcow") {
|
||||
if (isset($from) && isset($to)) {
|
||||
$data = $valkey->lRange('CRON_LOG', $from - 1, $to - 1);
|
||||
$data = $redis->lRange('CRON_LOG', $from - 1, $to - 1);
|
||||
}
|
||||
else {
|
||||
$data = $valkey->lRange('CRON_LOG', 0, $lines);
|
||||
$data = $redis->lRange('CRON_LOG', 0, $lines);
|
||||
}
|
||||
if ($data) {
|
||||
foreach ($data as $json_line) {
|
||||
@@ -3453,10 +3468,10 @@ function get_logs($application, $lines = false) {
|
||||
}
|
||||
if ($application == "postfix-mailcow") {
|
||||
if (isset($from) && isset($to)) {
|
||||
$data = $valkey->lRange('POSTFIX_MAILLOG', $from - 1, $to - 1);
|
||||
$data = $redis->lRange('POSTFIX_MAILLOG', $from - 1, $to - 1);
|
||||
}
|
||||
else {
|
||||
$data = $valkey->lRange('POSTFIX_MAILLOG', 0, $lines);
|
||||
$data = $redis->lRange('POSTFIX_MAILLOG', 0, $lines);
|
||||
}
|
||||
if ($data) {
|
||||
foreach ($data as $json_line) {
|
||||
@@ -3467,10 +3482,10 @@ function get_logs($application, $lines = false) {
|
||||
}
|
||||
if ($application == "sogo-mailcow") {
|
||||
if (isset($from) && isset($to)) {
|
||||
$data = $valkey->lRange('SOGO_LOG', $from - 1, $to - 1);
|
||||
$data = $redis->lRange('SOGO_LOG', $from - 1, $to - 1);
|
||||
}
|
||||
else {
|
||||
$data = $valkey->lRange('SOGO_LOG', 0, $lines);
|
||||
$data = $redis->lRange('SOGO_LOG', 0, $lines);
|
||||
}
|
||||
if ($data) {
|
||||
foreach ($data as $json_line) {
|
||||
@@ -3481,10 +3496,10 @@ function get_logs($application, $lines = false) {
|
||||
}
|
||||
if ($application == "watchdog-mailcow") {
|
||||
if (isset($from) && isset($to)) {
|
||||
$data = $valkey->lRange('WATCHDOG_LOG', $from - 1, $to - 1);
|
||||
$data = $redis->lRange('WATCHDOG_LOG', $from - 1, $to - 1);
|
||||
}
|
||||
else {
|
||||
$data = $valkey->lRange('WATCHDOG_LOG', 0, $lines);
|
||||
$data = $redis->lRange('WATCHDOG_LOG', 0, $lines);
|
||||
}
|
||||
if ($data) {
|
||||
foreach ($data as $json_line) {
|
||||
@@ -3495,10 +3510,10 @@ function get_logs($application, $lines = false) {
|
||||
}
|
||||
if ($application == "acme-mailcow") {
|
||||
if (isset($from) && isset($to)) {
|
||||
$data = $valkey->lRange('ACME_LOG', $from - 1, $to - 1);
|
||||
$data = $redis->lRange('ACME_LOG', $from - 1, $to - 1);
|
||||
}
|
||||
else {
|
||||
$data = $valkey->lRange('ACME_LOG', 0, $lines);
|
||||
$data = $redis->lRange('ACME_LOG', 0, $lines);
|
||||
}
|
||||
if ($data) {
|
||||
foreach ($data as $json_line) {
|
||||
@@ -3509,10 +3524,10 @@ function get_logs($application, $lines = false) {
|
||||
}
|
||||
if ($application == "ratelimited") {
|
||||
if (isset($from) && isset($to)) {
|
||||
$data = $valkey->lRange('RL_LOG', $from - 1, $to - 1);
|
||||
$data = $redis->lRange('RL_LOG', $from - 1, $to - 1);
|
||||
}
|
||||
else {
|
||||
$data = $valkey->lRange('RL_LOG', 0, $lines);
|
||||
$data = $redis->lRange('RL_LOG', 0, $lines);
|
||||
}
|
||||
if ($data) {
|
||||
foreach ($data as $json_line) {
|
||||
@@ -3523,10 +3538,10 @@ function get_logs($application, $lines = false) {
|
||||
}
|
||||
if ($application == "api-mailcow") {
|
||||
if (isset($from) && isset($to)) {
|
||||
$data = $valkey->lRange('API_LOG', $from - 1, $to - 1);
|
||||
$data = $redis->lRange('API_LOG', $from - 1, $to - 1);
|
||||
}
|
||||
else {
|
||||
$data = $valkey->lRange('API_LOG', 0, $lines);
|
||||
$data = $redis->lRange('API_LOG', 0, $lines);
|
||||
}
|
||||
if ($data) {
|
||||
foreach ($data as $json_line) {
|
||||
@@ -3537,10 +3552,10 @@ function get_logs($application, $lines = false) {
|
||||
}
|
||||
if ($application == "netfilter-mailcow") {
|
||||
if (isset($from) && isset($to)) {
|
||||
$data = $valkey->lRange('NETFILTER_LOG', $from - 1, $to - 1);
|
||||
$data = $redis->lRange('NETFILTER_LOG', $from - 1, $to - 1);
|
||||
}
|
||||
else {
|
||||
$data = $valkey->lRange('NETFILTER_LOG', 0, $lines);
|
||||
$data = $redis->lRange('NETFILTER_LOG', 0, $lines);
|
||||
}
|
||||
if ($data) {
|
||||
foreach ($data as $json_line) {
|
||||
@@ -3551,10 +3566,10 @@ function get_logs($application, $lines = false) {
|
||||
}
|
||||
if ($application == "autodiscover-mailcow") {
|
||||
if (isset($from) && isset($to)) {
|
||||
$data = $valkey->lRange('AUTODISCOVER_LOG', $from - 1, $to - 1);
|
||||
$data = $redis->lRange('AUTODISCOVER_LOG', $from - 1, $to - 1);
|
||||
}
|
||||
else {
|
||||
$data = $valkey->lRange('AUTODISCOVER_LOG', 0, $lines);
|
||||
$data = $redis->lRange('AUTODISCOVER_LOG', 0, $lines);
|
||||
}
|
||||
if ($data) {
|
||||
foreach ($data as $json_line) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
global $pdo;
|
||||
global $valkey;
|
||||
global $redis;
|
||||
global $lang;
|
||||
global $MAILBOX_DEFAULT_ATTRIBUTES;
|
||||
global $iam_settings;
|
||||
@@ -628,13 +628,13 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
}
|
||||
|
||||
try {
|
||||
$valkey->hSet('DOMAIN_MAP', $domain, 1);
|
||||
$redis->hSet('DOMAIN_MAP', $domain, 1);
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -646,7 +646,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
$_data['key_size'] = (isset($_data['key_size'])) ? intval($_data['key_size']) : $DOMAIN_DEFAULT_ATTRIBUTES['key_size'];
|
||||
$_data['dkim_selector'] = (isset($_data['dkim_selector'])) ? $_data['dkim_selector'] : $DOMAIN_DEFAULT_ATTRIBUTES['dkim_selector'];
|
||||
if (!empty($_data['key_size']) && !empty($_data['dkim_selector'])) {
|
||||
if (!empty($valkey->hGet('DKIM_SELECTORS', $domain))) {
|
||||
if (!empty($redis->hGet('DKIM_SELECTORS', $domain))) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||
@@ -974,13 +974,13 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
':active' => $active
|
||||
));
|
||||
try {
|
||||
$valkey->hSet('DOMAIN_MAP', $alias_domain, 1);
|
||||
$redis->hSet('DOMAIN_MAP', $alias_domain, 1);
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -988,7 +988,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
ratelimit('edit', 'domain', array('rl_value' => $_data['rl_value'], 'rl_frame' => $_data['rl_frame'], 'object' => $alias_domain));
|
||||
}
|
||||
if (!empty($_data['key_size']) && !empty($_data['dkim_selector'])) {
|
||||
if (!empty($valkey->hGet('DKIM_SELECTORS', $alias_domain))) {
|
||||
if (!empty($redis->hGet('DKIM_SELECTORS', $alias_domain))) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||
@@ -2147,42 +2147,42 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
}
|
||||
if (isset($_data['tagged_mail_handler']) && $_data['tagged_mail_handler'] == "subject") {
|
||||
try {
|
||||
$valkey->hSet('RCPT_WANTS_SUBJECT_TAG', $username, 1);
|
||||
$valkey->hDel('RCPT_WANTS_SUBFOLDER_TAG', $username);
|
||||
$redis->hSet('RCPT_WANTS_SUBJECT_TAG', $username, 1);
|
||||
$redis->hDel('RCPT_WANTS_SUBFOLDER_TAG', $username);
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (isset($_data['tagged_mail_handler']) && $_data['tagged_mail_handler'] == "subfolder") {
|
||||
try {
|
||||
$valkey->hSet('RCPT_WANTS_SUBFOLDER_TAG', $username, 1);
|
||||
$valkey->hDel('RCPT_WANTS_SUBJECT_TAG', $username);
|
||||
$redis->hSet('RCPT_WANTS_SUBFOLDER_TAG', $username, 1);
|
||||
$redis->hDel('RCPT_WANTS_SUBJECT_TAG', $username);
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
$valkey->hDel('RCPT_WANTS_SUBJECT_TAG', $username);
|
||||
$valkey->hDel('RCPT_WANTS_SUBFOLDER_TAG', $username);
|
||||
$redis->hDel('RCPT_WANTS_SUBJECT_TAG', $username);
|
||||
$redis->hDel('RCPT_WANTS_SUBFOLDER_TAG', $username);
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
@@ -4603,10 +4603,10 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
$_data = $_SESSION['mailcow_cc_username'];
|
||||
}
|
||||
try {
|
||||
if ($valkey->hGet('RCPT_WANTS_SUBJECT_TAG', $_data)) {
|
||||
if ($redis->hGet('RCPT_WANTS_SUBJECT_TAG', $_data)) {
|
||||
return "subject";
|
||||
}
|
||||
elseif ($valkey->hGet('RCPT_WANTS_SUBFOLDER_TAG', $_data)) {
|
||||
elseif ($redis->hGet('RCPT_WANTS_SUBFOLDER_TAG', $_data)) {
|
||||
return "subfolder";
|
||||
}
|
||||
else {
|
||||
@@ -4617,7 +4617,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -5636,14 +5636,14 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
$stmt = $pdo->query("DELETE FROM `admin` WHERE `superadmin` = 0 AND `username` NOT IN (SELECT `username`FROM `domain_admins`);");
|
||||
$stmt = $pdo->query("DELETE FROM `da_acl` WHERE `username` NOT IN (SELECT `username`FROM `domain_admins`);");
|
||||
try {
|
||||
$valkey->hDel('DOMAIN_MAP', $domain);
|
||||
$valkey->hDel('RL_VALUE', $domain);
|
||||
$redis->hDel('DOMAIN_MAP', $domain);
|
||||
$redis->hDel('RL_VALUE', $domain);
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
@@ -5769,14 +5769,14 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
':alias_domain' => $alias_domain,
|
||||
));
|
||||
try {
|
||||
$valkey->hDel('DOMAIN_MAP', $alias_domain);
|
||||
$valkey->hDel('RL_VALUE', $domain);
|
||||
$redis->hDel('DOMAIN_MAP', $alias_domain);
|
||||
$redis->hDel('RL_VALUE', $domain);
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
@@ -5955,13 +5955,13 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
));
|
||||
}
|
||||
try {
|
||||
$valkey->hDel('RL_VALUE', $username);
|
||||
$redis->hDel('RL_VALUE', $username);
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
function oauth2($_action, $_type, $_data = null) {
|
||||
global $pdo;
|
||||
global $valkey;
|
||||
global $redis;
|
||||
global $lang;
|
||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||
$_SESSION['return'][] = array(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
function policy($_action, $_scope, $_data = null) {
|
||||
global $pdo;
|
||||
global $valkey;
|
||||
global $redis;
|
||||
global $lang;
|
||||
$_data_log = $_data;
|
||||
switch ($_action) {
|
||||
|
||||
@@ -4,7 +4,7 @@ use PHPMailer\PHPMailer\SMTP;
|
||||
use PHPMailer\PHPMailer\Exception;
|
||||
function quarantine($_action, $_data = null) {
|
||||
global $pdo;
|
||||
global $valkey;
|
||||
global $redis;
|
||||
global $lang;
|
||||
$_data_log = $_data;
|
||||
switch ($_action) {
|
||||
@@ -102,14 +102,14 @@ function quarantine($_action, $_data = null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
$release_format = $valkey->Get('Q_RELEASE_FORMAT');
|
||||
$release_format = $redis->Get('Q_RELEASE_FORMAT');
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
logger(array('return' => array(
|
||||
array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
)
|
||||
)));
|
||||
return false;
|
||||
@@ -180,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(
|
||||
@@ -192,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;
|
||||
@@ -332,23 +332,23 @@ function quarantine($_action, $_data = null) {
|
||||
}
|
||||
$exclude_domains = (array)$_data['exclude_domains'];
|
||||
try {
|
||||
$valkey->Set('Q_RETENTION_SIZE', intval($retention_size));
|
||||
$valkey->Set('Q_MAX_SIZE', intval($max_size));
|
||||
$valkey->Set('Q_MAX_SCORE', $max_score);
|
||||
$valkey->Set('Q_MAX_AGE', $max_age);
|
||||
$valkey->Set('Q_EXCLUDE_DOMAINS', json_encode($exclude_domains));
|
||||
$valkey->Set('Q_RELEASE_FORMAT', $release_format);
|
||||
$valkey->Set('Q_SENDER', $sender);
|
||||
$valkey->Set('Q_BCC', $bcc);
|
||||
$valkey->Set('Q_REDIRECT', $redirect);
|
||||
$valkey->Set('Q_SUBJ', $subject);
|
||||
$valkey->Set('Q_HTML', $html);
|
||||
$redis->Set('Q_RETENTION_SIZE', intval($retention_size));
|
||||
$redis->Set('Q_MAX_SIZE', intval($max_size));
|
||||
$redis->Set('Q_MAX_SCORE', $max_score);
|
||||
$redis->Set('Q_MAX_AGE', $max_age);
|
||||
$redis->Set('Q_EXCLUDE_DOMAINS', json_encode($exclude_domains));
|
||||
$redis->Set('Q_RELEASE_FORMAT', $release_format);
|
||||
$redis->Set('Q_SENDER', $sender);
|
||||
$redis->Set('Q_BCC', $bcc);
|
||||
$redis->Set('Q_REDIRECT', $redirect);
|
||||
$redis->Set('Q_SUBJ', $subject);
|
||||
$redis->Set('Q_HTML', $html);
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -403,13 +403,13 @@ function quarantine($_action, $_data = null) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
$release_format = $valkey->Get('Q_RELEASE_FORMAT');
|
||||
$release_format = $redis->Get('Q_RELEASE_FORMAT');
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -475,7 +475,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) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'warning',
|
||||
@@ -485,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;
|
||||
@@ -776,18 +776,18 @@ function quarantine($_action, $_data = null) {
|
||||
case 'settings':
|
||||
try {
|
||||
if ($_SESSION['mailcow_cc_role'] == "admin") {
|
||||
$settings['exclude_domains'] = json_decode($valkey->Get('Q_EXCLUDE_DOMAINS'), true);
|
||||
$settings['exclude_domains'] = json_decode($redis->Get('Q_EXCLUDE_DOMAINS'), true);
|
||||
}
|
||||
$settings['max_size'] = $valkey->Get('Q_MAX_SIZE');
|
||||
$settings['max_score'] = $valkey->Get('Q_MAX_SCORE');
|
||||
$settings['max_age'] = $valkey->Get('Q_MAX_AGE');
|
||||
$settings['retention_size'] = $valkey->Get('Q_RETENTION_SIZE');
|
||||
$settings['release_format'] = $valkey->Get('Q_RELEASE_FORMAT');
|
||||
$settings['subject'] = $valkey->Get('Q_SUBJ');
|
||||
$settings['sender'] = $valkey->Get('Q_SENDER');
|
||||
$settings['bcc'] = $valkey->Get('Q_BCC');
|
||||
$settings['redirect'] = $valkey->Get('Q_REDIRECT');
|
||||
$settings['html_tmpl'] = htmlspecialchars($valkey->Get('Q_HTML'));
|
||||
$settings['max_size'] = $redis->Get('Q_MAX_SIZE');
|
||||
$settings['max_score'] = $redis->Get('Q_MAX_SCORE');
|
||||
$settings['max_age'] = $redis->Get('Q_MAX_AGE');
|
||||
$settings['retention_size'] = $redis->Get('Q_RETENTION_SIZE');
|
||||
$settings['release_format'] = $redis->Get('Q_RELEASE_FORMAT');
|
||||
$settings['subject'] = $redis->Get('Q_SUBJ');
|
||||
$settings['sender'] = $redis->Get('Q_SENDER');
|
||||
$settings['bcc'] = $redis->Get('Q_BCC');
|
||||
$settings['redirect'] = $redis->Get('Q_REDIRECT');
|
||||
$settings['html_tmpl'] = htmlspecialchars($redis->Get('Q_HTML'));
|
||||
if (empty($settings['html_tmpl'])) {
|
||||
$settings['html_tmpl'] = htmlspecialchars(file_get_contents("/tpls/quarantine.tpl"));
|
||||
}
|
||||
@@ -796,7 +796,7 @@ function quarantine($_action, $_data = null) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
function quota_notification($_action, $_data = null) {
|
||||
global $valkey;
|
||||
global $redis;
|
||||
$_data_log = $_data;
|
||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||
$_SESSION['return'][] = array(
|
||||
@@ -26,15 +26,15 @@ function quota_notification($_action, $_data = null) {
|
||||
}
|
||||
$html = $_data['html_tmpl'];
|
||||
try {
|
||||
$valkey->Set('QW_SENDER', $sender);
|
||||
$valkey->Set('QW_SUBJ', $subject);
|
||||
$valkey->Set('QW_HTML', $html);
|
||||
$redis->Set('QW_SENDER', $sender);
|
||||
$redis->Set('QW_SUBJ', $subject);
|
||||
$redis->Set('QW_HTML', $html);
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -46,9 +46,9 @@ function quota_notification($_action, $_data = null) {
|
||||
break;
|
||||
case 'get':
|
||||
try {
|
||||
$settings['subject'] = $valkey->Get('QW_SUBJ');
|
||||
$settings['sender'] = $valkey->Get('QW_SENDER');
|
||||
$settings['html_tmpl'] = htmlspecialchars($valkey->Get('QW_HTML'));
|
||||
$settings['subject'] = $redis->Get('QW_SUBJ');
|
||||
$settings['sender'] = $redis->Get('QW_SENDER');
|
||||
$settings['html_tmpl'] = htmlspecialchars($redis->Get('QW_HTML'));
|
||||
if (empty($settings['html_tmpl'])) {
|
||||
$settings['html_tmpl'] = htmlspecialchars(file_get_contents("/tpls/quota.tpl"));
|
||||
}
|
||||
@@ -57,7 +57,7 @@ function quota_notification($_action, $_data = null) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -66,7 +66,7 @@ function quota_notification($_action, $_data = null) {
|
||||
}
|
||||
}
|
||||
function quota_notification_bcc($_action, $_data = null) {
|
||||
global $valkey;
|
||||
global $redis;
|
||||
$_data_log = $_data;
|
||||
if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
|
||||
$_SESSION['return'][] = array(
|
||||
@@ -105,16 +105,16 @@ function quota_notification_bcc($_action, $_data = null) {
|
||||
$bcc_rcpts = array_filter($bcc_rcpts);
|
||||
if (empty($bcc_rcpts)) {
|
||||
$active = 0;
|
||||
|
||||
|
||||
}
|
||||
try {
|
||||
$valkey->hSet('QW_BCC', $domain, json_encode(array('bcc_rcpts' => $bcc_rcpts, 'active' => $active)));
|
||||
$redis->hSet('QW_BCC', $domain, json_encode(array('bcc_rcpts' => $bcc_rcpts, 'active' => $active)));
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -135,13 +135,13 @@ function quota_notification_bcc($_action, $_data = null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return json_decode($valkey->hGet('QW_BCC', $domain), true);
|
||||
return json_decode($redis->hGet('QW_BCC', $domain), true);
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
function ratelimit($_action, $_scope, $_data = null, $_extra = null) {
|
||||
global $valkey;
|
||||
global $redis;
|
||||
$_data_log = $_data;
|
||||
switch ($_action) {
|
||||
case 'edit':
|
||||
@@ -42,26 +42,26 @@ function ratelimit($_action, $_scope, $_data = null, $_extra = null) {
|
||||
}
|
||||
if (empty($rl_value)) {
|
||||
try {
|
||||
$valkey->hDel('RL_VALUE', $object);
|
||||
$redis->hDel('RL_VALUE', $object);
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
$valkey->hSet('RL_VALUE', $object, $rl_value . ' / 1' . $rl_frame);
|
||||
$redis->hSet('RL_VALUE', $object, $rl_value . ' / 1' . $rl_frame);
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
@@ -103,26 +103,26 @@ function ratelimit($_action, $_scope, $_data = null, $_extra = null) {
|
||||
}
|
||||
if (empty($rl_value)) {
|
||||
try {
|
||||
$valkey->hDel('RL_VALUE', $object);
|
||||
$redis->hDel('RL_VALUE', $object);
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
$valkey->hSet('RL_VALUE', $object, $rl_value . ' / 1' . $rl_frame);
|
||||
$redis->hSet('RL_VALUE', $object, $rl_value . ' / 1' . $rl_frame);
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
continue;
|
||||
}
|
||||
@@ -143,7 +143,7 @@ function ratelimit($_action, $_scope, $_data = null, $_extra = null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
if ($rl_value = $valkey->hGet('RL_VALUE', $_data)) {
|
||||
if ($rl_value = $redis->hGet('RL_VALUE', $_data)) {
|
||||
$rl = explode(' / 1', $rl_value);
|
||||
$data['value'] = $rl[0];
|
||||
$data['frame'] = $rl[1];
|
||||
@@ -157,7 +157,7 @@ function ratelimit($_action, $_scope, $_data = null, $_extra = null) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -169,7 +169,7 @@ function ratelimit($_action, $_scope, $_data = null, $_extra = null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
if ($rl_value = $valkey->hGet('RL_VALUE', $_data)) {
|
||||
if ($rl_value = $redis->hGet('RL_VALUE', $_data)) {
|
||||
$rl = explode(' / 1', $rl_value);
|
||||
$data['value'] = $rl[0];
|
||||
$data['frame'] = $rl[1];
|
||||
@@ -183,7 +183,7 @@ function ratelimit($_action, $_scope, $_data = null, $_extra = null) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -202,16 +202,16 @@ function ratelimit($_action, $_scope, $_data = null, $_extra = null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
$data_rllog = $valkey->lRange('RL_LOG', 0, -1);
|
||||
$data_rllog = $redis->lRange('RL_LOG', 0, -1);
|
||||
if ($data_rllog) {
|
||||
foreach ($data_rllog as $json_line) {
|
||||
if (preg_match('/' . $data['hash'] . '/i', $json_line)) {
|
||||
$valkey->lRem('RL_LOG', $json_line, 0);
|
||||
$redis->lRem('RL_LOG', $json_line, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($valkey->type($data['hash']) == Redis::REDIS_HASH) {
|
||||
$valkey->delete($data['hash']);
|
||||
if ($redis->type($data['hash']) == Redis::REDIS_HASH) {
|
||||
$redis->delete($data['hash']);
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
||||
@@ -232,7 +232,7 @@ function ratelimit($_action, $_scope, $_data = null, $_extra = null) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
||||
'msg' => array('valkey_error', $e)
|
||||
'msg' => array('redis_error', $e)
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -57,22 +57,22 @@ $WebAuthn = new lbuchs\WebAuthn\WebAuthn('WebAuthn Library', $server_name, $form
|
||||
// only include root ca's when needed
|
||||
if (getenv('WEBAUTHN_ONLY_TRUSTED_VENDORS') == 'y') $WebAuthn->addRootCertificates($_SERVER['DOCUMENT_ROOT'] . '/inc/lib/WebAuthn/rootCertificates');
|
||||
|
||||
// Valkey
|
||||
$valkey = new Redis();
|
||||
// Redis
|
||||
$redis = new Redis();
|
||||
try {
|
||||
if (!empty(getenv('VALKEY_SLAVEOF_IP'))) {
|
||||
$valkey->connect(getenv('VALKEY_SLAVEOF_IP'), getenv('VALKEY_SLAVEOF_PORT'));
|
||||
if (!empty(getenv('REDIS_SLAVEOF_IP'))) {
|
||||
$redis->connect(getenv('REDIS_SLAVEOF_IP'), getenv('REDIS_SLAVEOF_PORT'));
|
||||
}
|
||||
else {
|
||||
$valkey->connect('valkey-mailcow', 6379);
|
||||
$redis->connect('redis-mailcow', 6379);
|
||||
}
|
||||
$valkey->auth(getenv("VALKEYPASS"));
|
||||
$redis->auth(getenv("REDISPASS"));
|
||||
}
|
||||
catch (Exception $e) {
|
||||
// Stop when valkey is not available
|
||||
// Stop when redis is not available
|
||||
http_response_code(500);
|
||||
?>
|
||||
<center style='font-family:sans-serif;'>Connection to Valkey failed.<br /><br />The following error was reported:<br/><?=$e->getMessage();?></center>
|
||||
<center style='font-family:sans-serif;'>Connection to Redis failed.<br /><br />The following error was reported:<br/><?=$e->getMessage();?></center>
|
||||
<?php
|
||||
exit;
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ if (!empty($_SERVER['HTTP_X_API_KEY'])) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
$valkey->publish("F2B_CHANNEL", "mailcow UI: Invalid password for API_USER by " . $_SERVER['REMOTE_ADDR']);
|
||||
$redis->publish("F2B_CHANNEL", "mailcow UI: Invalid password for API_USER by " . $_SERVER['REMOTE_ADDR']);
|
||||
error_log("mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']);
|
||||
http_response_code(401);
|
||||
echo json_encode(array(
|
||||
@@ -81,7 +81,7 @@ if (!empty($_SERVER['HTTP_X_API_KEY'])) {
|
||||
}
|
||||
}
|
||||
else {
|
||||
$valkey->publish("F2B_CHANNEL", "mailcow UI: Invalid password for API_USER by " . $_SERVER['REMOTE_ADDR']);
|
||||
$redis->publish("F2B_CHANNEL", "mailcow UI: Invalid password for API_USER by " . $_SERVER['REMOTE_ADDR']);
|
||||
error_log("mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']);
|
||||
http_response_code(401);
|
||||
echo json_encode(array(
|
||||
|
||||
@@ -85,7 +85,7 @@ $AVAILABLE_LANGUAGES = array(
|
||||
// 'ca-es' => 'Català (Catalan)',
|
||||
'bg-bg' => 'Български (Bulgarian)',
|
||||
'cs-cz' => 'Čeština (Czech)',
|
||||
'da-dk' => 'Danish (Dansk)',
|
||||
'da-dk' => 'Dansk (Danish)',
|
||||
'de-de' => 'Deutsch (German)',
|
||||
'en-gb' => 'English',
|
||||
'es-es' => 'Español (Spanish)',
|
||||
@@ -110,6 +110,7 @@ $AVAILABLE_LANGUAGES = array(
|
||||
'sv-se' => 'Svenska (Swedish)',
|
||||
'tr-tr' => 'Türkçe (Turkish)',
|
||||
'uk-ua' => 'Українська (Ukrainian)',
|
||||
'vi-vn' => 'Tiếng Việt (Vietnamese)',
|
||||
'zh-cn' => '简体中文 (Simplified Chinese)',
|
||||
'zh-tw' => '繁體中文 (Traditional Chinese)',
|
||||
);
|
||||
|
||||
@@ -12,7 +12,7 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
|
||||
$user_details = mailbox("get", "mailbox_details", $_SESSION['mailcow_cc_username']);
|
||||
$is_dual = (!empty($_SESSION["dual-login"]["username"])) ? true : false;
|
||||
if (intval($user_details['attributes']['sogo_access']) == 1 && !$is_dual && getenv('SKIP_SOGO') != "y") {
|
||||
header("Location: /SOGo/so/{$_SESSION['mailcow_cc_username']}");
|
||||
header("Location: /SOGo/so/");
|
||||
} else {
|
||||
header("Location: /user");
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ jQuery(function($){
|
||||
var datetime = new Date(item.datetime.replace(/-/g, "/"));
|
||||
var local_datetime = datetime.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});
|
||||
var service = '<div class="badge bg-secondary">' + item.service.toUpperCase() + '</div>';
|
||||
var app_password = item.app_password ? ' <a href="/edit/app-passwd/' + item.app_password + '"><i class="bi bi-app-indicator"></i> ' + escapeHtml(item.app_password_name || "App") + '</a>' : '';
|
||||
var app_password = item.app_password ? ' <a href="/edit/app-passwd/' + item.app_password + '"><i class="bi bi-key-fill"></i><span class="ms-1">' + escapeHtml(item.app_password_name || "App") + '</span></a>' : '';
|
||||
var real_rip = item.real_rip.startsWith("Web") ? item.real_rip : '<a href="https://bgp.tools/prefix/' + item.real_rip + '" target="_blank">' + item.real_rip + "</a>";
|
||||
var ip_location = item.location ? ' <span class="flag-icon flag-icon-' + item.location.toLowerCase() + '"></span>' : '';
|
||||
var ip_data = real_rip + ip_location + app_password;
|
||||
@@ -105,10 +105,9 @@ jQuery(function($){
|
||||
$(".last-sasl-login").append(`
|
||||
<li class="list-group-item d-flex justify-content-between align-items-start">
|
||||
<div class="ms-2 me-auto d-flex flex-column">
|
||||
<div class="fw-bold">` + real_rip + `</div>
|
||||
<small class="fst-italic mt-2">` + service + ` ` + local_datetime + `</small>
|
||||
<div class="fw-bold">` + ip_location + real_rip + `</div>
|
||||
<small class="fst-italic mt-2">` + service + ` ` + local_datetime + `</small>` + app_password + `
|
||||
</div>
|
||||
<span>` + ip_location + `</span>
|
||||
</li>
|
||||
`);
|
||||
})
|
||||
|
||||
@@ -8,7 +8,7 @@ header('Content-Type: application/json');
|
||||
error_reporting(0);
|
||||
|
||||
function api_log($_data) {
|
||||
global $valkey;
|
||||
global $redis;
|
||||
$data_var = array();
|
||||
foreach ($_data as $data => &$value) {
|
||||
if ($data == 'csrf_token') {
|
||||
@@ -36,12 +36,12 @@ function api_log($_data) {
|
||||
'remote' => get_remote_ip(),
|
||||
'data' => implode(', ', $data_var)
|
||||
);
|
||||
$valkey->lPush('API_LOG', json_encode($log_line));
|
||||
$redis->lPush('API_LOG', json_encode($log_line));
|
||||
}
|
||||
catch (RedisException $e) {
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'danger',
|
||||
'msg' => 'Valkey: '.$e
|
||||
'msg' => 'Redis: '.$e
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -498,7 +498,7 @@
|
||||
"pushover_token": "Token služby Pushover nemá správný formát",
|
||||
"quota_not_0_not_numeric": "Kvóta musí být číslo >= 0",
|
||||
"recipient_map_entry_exists": "Položka mapy příjemců \"%s\" již existuje",
|
||||
"valkey_error": "Chyba Valkey: %s",
|
||||
"redis_error": "Chyba Redis: %s",
|
||||
"relayhost_invalid": "Položky %s je neplatná",
|
||||
"release_send_failed": "Zprávu nelze propustit: %s",
|
||||
"reset_f2b_regex": "Regex filtr se nepodařilo resetovat, zkuste to znovu nebo počkejte pár sekund a obnovte stránku.",
|
||||
@@ -592,7 +592,7 @@
|
||||
"history_all_servers": "Záznam (všechny servery)",
|
||||
"in_memory_logs": "Logy v paměti",
|
||||
"last_modified": "Naposledy změněn",
|
||||
"log_info": "<p><b>Logy v paměti</b> jsou shromažďovány v Valkey seznamech a jsou oříznuty na LOG_LINES (%d) každou minutu, aby se nepřetěžoval server.\r\n <br>Logy v paměti nemají být trvalé. Všechny aplikace, které logují do paměti, zároveň logují i do Docker služby podle nastavení logging driveru.\r\n <br>Logy v paměti lze použít pro ladění drobných problémů s kontejnery.</p>\r\n <p><b>Externí logy</b> jsou shromažďovány pomocí API dané aplikace.</p>\r\n <p><b>Statické logy</b> jsou většinou logy činností, které nejsou zaznamenávány do Docker služby, ale přesto je dobré je schraňovat (výjimkou jsou logy API).</p>",
|
||||
"log_info": "<p><b>Logy v paměti</b> jsou shromažďovány v Redis seznamech a jsou oříznuty na LOG_LINES (%d) každou minutu, aby se nepřetěžoval server.\r\n <br>Logy v paměti nemají být trvalé. Všechny aplikace, které logují do paměti, zároveň logují i do Docker služby podle nastavení logging driveru.\r\n <br>Logy v paměti lze použít pro ladění drobných problémů s kontejnery.</p>\r\n <p><b>Externí logy</b> jsou shromažďovány pomocí API dané aplikace.</p>\r\n <p><b>Statické logy</b> jsou většinou logy činností, které nejsou zaznamenávány do Docker služby, ale přesto je dobré je schraňovat (výjimkou jsou logy API).</p>",
|
||||
"login_time": "Čas",
|
||||
"logs": "Logy",
|
||||
"online_users": "Uživatelů online",
|
||||
|
||||
@@ -401,7 +401,7 @@
|
||||
"pushover_token": "Pushover-token har et forkert format",
|
||||
"quota_not_0_not_numeric": "Kvoten skal være numerisk og >= 0",
|
||||
"recipient_map_entry_exists": "En modtagerkortpost \"%s\" eksisterer",
|
||||
"valkey_error": "Valkey fejl: %s",
|
||||
"redis_error": "Redis fejl: %s",
|
||||
"relayhost_invalid": "Kortindtastning %s er ugyldig",
|
||||
"release_send_failed": "Beskeden kunne ikke frigives: %s",
|
||||
"reset_f2b_regex": "Regex filter kunne ikke nulstilles i tide, prøv igen eller vent et par sekunder mere, og genindlæs webstedet.",
|
||||
@@ -444,7 +444,7 @@
|
||||
"external_logs": "Eksterne logfiler",
|
||||
"history_all_servers": "Historie (alle servere)",
|
||||
"in_memory_logs": "In-memory logs",
|
||||
"log_info": "<p>mailcow <b>in-memory logs</b> er samlet i Valkey-lister og trimmet til LOG_LINES (%d) hvert minut for at reducere hamring.\r\n <br>Logbøger i hukommelsen er ikke beregnet til at være vedholdende. Alle applikationer, der logger ind i hukommelsen, logger også på Docker-dæmonen og derfor til standardlogdriveren.\r\n <br>Logtypen i hukommelsen skal bruges til fejlfinding af mindre problemer med containere.</p>\r\n <p><b>Eksterne logfiler</b> indsamles via API for den givne applikation.</p>\r\n <p><b>Statiske logfiler</b> er for det meste aktivitetslogfiler, der ikke er logget på Dockerd, men stadig skal være vedholdende (undtagen API-logfiler).</p>",
|
||||
"log_info": "<p>mailcow <b>in-memory logs</b> er samlet i Redis-lister og trimmet til LOG_LINES (%d) hvert minut for at reducere hamring.\r\n <br>Logbøger i hukommelsen er ikke beregnet til at være vedholdende. Alle applikationer, der logger ind i hukommelsen, logger også på Docker-dæmonen og derfor til standardlogdriveren.\r\n <br>Logtypen i hukommelsen skal bruges til fejlfinding af mindre problemer med containere.</p>\r\n <p><b>Eksterne logfiler</b> indsamles via API for den givne applikation.</p>\r\n <p><b>Statiske logfiler</b> er for det meste aktivitetslogfiler, der ikke er logget på Dockerd, men stadig skal være vedholdende (undtagen API-logfiler).</p>",
|
||||
"logs": "Logs",
|
||||
"restart_container": "Genstart",
|
||||
"started_on": "Startede den",
|
||||
|
||||
@@ -514,7 +514,7 @@
|
||||
"quota_not_0_not_numeric": "Speicherplatz muss numerisch und >= 0 sein",
|
||||
"recipient_map_entry_exists": "Eine Empfängerumschreibung für Objekt \"%s\" existiert bereits",
|
||||
"recovery_email_failed": "E-Mail zur Wiederherstellung konnte nicht gesendet werden. Bitte wenden Sie sich an Ihren Administrator.",
|
||||
"valkey_error": "Valkey Fehler: %s",
|
||||
"redis_error": "Redis Fehler: %s",
|
||||
"relayhost_invalid": "Map-Eintrag %s ist ungültig",
|
||||
"release_send_failed": "Die Nachricht konnte nicht versendet werden: %s",
|
||||
"reset_f2b_regex": "Regex-Filter konnten nicht in vorgegebener Zeit zurückgesetzt werden, bitte erneut versuchen oder die Webseite neu laden.",
|
||||
@@ -600,7 +600,7 @@
|
||||
"history_all_servers": "History (alle Server)",
|
||||
"in_memory_logs": "In-memory Logs",
|
||||
"last_modified": "Zuletzt geändert",
|
||||
"log_info": "<p>mailcow <b>in-memory Logs</b> werden in Valkey Listen gespeichert, die maximale Anzahl der Einträge pro Anwendung richtet sich nach LOG_LINES (%d).\r\n <br>In-memory Logs sind vergänglich und nicht zur ständigen Aufbewahrung bestimmt. Alle Anwendungen, die in-memory protokollieren, schreiben ebenso in den Docker Daemon.\r\n <br>Das in-memory Protokoll versteht sich als schnelle Übersicht zum Debugging eines Containers, für komplexere Protokolle sollte der Docker Daemon konsultiert werden.</p>\r\n <p><b>Externe Logs</b> werden via API externer Applikationen bezogen.</p>\r\n <p><b>Statische Logs</b> sind weitestgehend Aktivitätsprotokolle, die nicht in den Docker Daemon geschrieben werden, jedoch permanent verfügbar sein müssen (ausgeschlossen API Logs).</p>",
|
||||
"log_info": "<p>mailcow <b>in-memory Logs</b> werden in Redis Listen gespeichert, die maximale Anzahl der Einträge pro Anwendung richtet sich nach LOG_LINES (%d).\r\n <br>In-memory Logs sind vergänglich und nicht zur ständigen Aufbewahrung bestimmt. Alle Anwendungen, die in-memory protokollieren, schreiben ebenso in den Docker Daemon.\r\n <br>Das in-memory Protokoll versteht sich als schnelle Übersicht zum Debugging eines Containers, für komplexere Protokolle sollte der Docker Daemon konsultiert werden.</p>\r\n <p><b>Externe Logs</b> werden via API externer Applikationen bezogen.</p>\r\n <p><b>Statische Logs</b> sind weitestgehend Aktivitätsprotokolle, die nicht in den Docker Daemon geschrieben werden, jedoch permanent verfügbar sein müssen (ausgeschlossen API Logs).</p>",
|
||||
"login_time": "Zeit",
|
||||
"logs": "Protokolle",
|
||||
"memory": "Arbeitsspeicher",
|
||||
|
||||
@@ -514,7 +514,7 @@
|
||||
"quota_not_0_not_numeric": "Quota must be numeric and >= 0",
|
||||
"recipient_map_entry_exists": "A Recipient map entry \"%s\" exists",
|
||||
"recovery_email_failed": "Could not send a recovery email. Please contact your administrator.",
|
||||
"valkey_error": "Valkey error: %s",
|
||||
"redis_error": "Redis error: %s",
|
||||
"relayhost_invalid": "Map entry %s is invalid",
|
||||
"release_send_failed": "Message could not be released: %s",
|
||||
"required_data_missing": "Required data %s is missing",
|
||||
@@ -600,7 +600,7 @@
|
||||
"history_all_servers": "History (all servers)",
|
||||
"in_memory_logs": "In-memory logs",
|
||||
"last_modified": "Last modified",
|
||||
"log_info": "<p>mailcow <b>in-memory logs</b> are collected in Valkey lists and trimmed to LOG_LINES (%d) every minute to reduce hammering.\r\n <br>In-memory logs are not meant to be persistent. All applications that log in-memory, also log to the Docker daemon and therefore to the default logging driver.\r\n <br>The in-memory log type should be used for debugging minor issues with containers.</p>\r\n <p><b>External logs</b> are collected via API of the given application.</p>\r\n <p><b>Static logs</b> are mostly activity logs, that are not logged to the Dockerd but still need to be persistent (except for API logs).</p>",
|
||||
"log_info": "<p>mailcow <b>in-memory logs</b> are collected in Redis lists and trimmed to LOG_LINES (%d) every minute to reduce hammering.\r\n <br>In-memory logs are not meant to be persistent. All applications that log in-memory, also log to the Docker daemon and therefore to the default logging driver.\r\n <br>The in-memory log type should be used for debugging minor issues with containers.</p>\r\n <p><b>External logs</b> are collected via API of the given application.</p>\r\n <p><b>Static logs</b> are mostly activity logs, that are not logged to the Dockerd but still need to be persistent (except for API logs).</p>",
|
||||
"login_time": "Time",
|
||||
"logs": "Logs",
|
||||
"memory": "Memory",
|
||||
|
||||
@@ -462,7 +462,7 @@
|
||||
"private_key_error": "Error en la llave privada: %s",
|
||||
"quota_not_0_not_numeric": "Cuota debe ser numérica y >= 0",
|
||||
"recipient_map_entry_exists": "Una regla de destinatario \"%s\" existe",
|
||||
"valkey_error": "Valkey error: %s",
|
||||
"redis_error": "Redis error: %s",
|
||||
"relayhost_invalid": "relayhost %s es invalido",
|
||||
"release_send_failed": "El mensaje no pudo ser liberado: %s",
|
||||
"rl_timeframe": "Marco de tiempo del límite de velocidad esta incorrecto",
|
||||
@@ -548,7 +548,7 @@
|
||||
"disk_usage": "Utilización de disco",
|
||||
"external_logs": "Logs externos",
|
||||
"in_memory_logs": "Logs en memoria",
|
||||
"log_info": "<p>Los <b>logs en memoria</b> son recopilados en listas de Valkey y recortados a LOG_LINES (%d) cada minuto para prevenir sobrecarga en el sistema.\r\n <br>Los logs en memoria no están destinados a ser persistentes. Todas las aplicaciones que logean a la memoria, también logean en el daemon de Docker y, por lo tanto, en el controlador de registro predeterminado.\r\n El log en memoria se debe utilizar para analizar problemas menores con los contenedores.</p>\r\n <p>Los <b>logs externos</b> se recopilan a través de la API de la aplicación dada.</p>\r\n <p>Los <b>logs estáticos</b> son principalmente registros de actividad, que no están registrados en Dockerd pero que aún deben ser persistentes (excepto los registros de API).</p>",
|
||||
"log_info": "<p>Los <b>logs en memoria</b> son recopilados en listas de Redis y recortados a LOG_LINES (%d) cada minuto para prevenir sobrecarga en el sistema.\r\n <br>Los logs en memoria no están destinados a ser persistentes. Todas las aplicaciones que logean a la memoria, también logean en el daemon de Docker y, por lo tanto, en el controlador de registro predeterminado.\r\n El log en memoria se debe utilizar para analizar problemas menores con los contenedores.</p>\r\n <p>Los <b>logs externos</b> se recopilan a través de la API de la aplicación dada.</p>\r\n <p>Los <b>logs estáticos</b> son principalmente registros de actividad, que no están registrados en Dockerd pero que aún deben ser persistentes (excepto los registros de API).</p>",
|
||||
"logs": "Logs",
|
||||
"restart_container": "Reiniciar",
|
||||
"docs": "Docs",
|
||||
|
||||
@@ -344,7 +344,7 @@
|
||||
"private_key_error": "Yksityisen avaimen virhe: %s",
|
||||
"quota_not_0_not_numeric": "Kiintiön on oltava numeerinen ja >= 0",
|
||||
"recipient_map_entry_exists": "Vastaanottajan kartta merkintä \"%s\" on olemassa",
|
||||
"valkey_error": "Valkey virhe: %s",
|
||||
"redis_error": "Redis virhe: %s",
|
||||
"relayhost_invalid": "Osoite %s on väärin",
|
||||
"release_send_failed": "Viestiä ei voitu vapauttaa: %s",
|
||||
"resource_invalid": "Resurssin nimi %s on virheellinen",
|
||||
@@ -380,7 +380,7 @@
|
||||
"disk_usage": "Levyn käyttö",
|
||||
"external_logs": "Ulkoiset loki",
|
||||
"in_memory_logs": "Muistissa olevat lokit",
|
||||
"log_info": "<p>mailcow <b>muistissa olevat lokit</b> kerätään Valkey-luetteloihin ja leikataan LOG_LINES (%d) joka minuutti lyömisen vähentämiseksi.\r\n <br>Muistissa olevien lokien ei ole tarkoitus olla pysyviä. Kaikki sovellukset, jotka kirjautuvat muistiin, kirjautuvat myös Docker-daemoniin ja siten oletusarvoiseen lokitiedostoon.\r\n <br>Muistin lokityyppiä olisi käytettävä virheiden virheenkorjaukseen säilöissä.</p>\r\n <p><b>Ulkoiset lokit</b> kerätään annetun sovelluksen API: n kautta.</p>\r\n <p><b>Staattiset lokit</b> ovat useimmiten toimintalokkeja, joita ei kirjata Dockerdiin, mutta joiden on silti oltava pysyviä (paitsi API-lokit).</p>",
|
||||
"log_info": "<p>mailcow <b>muistissa olevat lokit</b> kerätään Redis-luetteloihin ja leikataan LOG_LINES (%d) joka minuutti lyömisen vähentämiseksi.\r\n <br>Muistissa olevien lokien ei ole tarkoitus olla pysyviä. Kaikki sovellukset, jotka kirjautuvat muistiin, kirjautuvat myös Docker-daemoniin ja siten oletusarvoiseen lokitiedostoon.\r\n <br>Muistin lokityyppiä olisi käytettävä virheiden virheenkorjaukseen säilöissä.</p>\r\n <p><b>Ulkoiset lokit</b> kerätään annetun sovelluksen API: n kautta.</p>\r\n <p><b>Staattiset lokit</b> ovat useimmiten toimintalokkeja, joita ei kirjata Dockerdiin, mutta joiden on silti oltava pysyviä (paitsi API-lokit).</p>",
|
||||
"logs": "Logit tausta palveluista",
|
||||
"restart_container": "Uudelleen käynnistä",
|
||||
"docs": "Docs",
|
||||
|
||||
@@ -493,7 +493,7 @@
|
||||
"pushover_token": "Le jeton Pushover a un mauvais format",
|
||||
"quota_not_0_not_numeric": "Le quota doit être numerique et >= 0",
|
||||
"recipient_map_entry_exists": "Une entrée dans la carte du destinataire « %s » existe",
|
||||
"valkey_error": "Erreur Valkey : %s",
|
||||
"redis_error": "Erreur Redis : %s",
|
||||
"relayhost_invalid": "La saisie de la carte %s est invalide",
|
||||
"release_send_failed": "Le message n’a pas pu être diffusé : %s",
|
||||
"reset_f2b_regex": "Le filtre regex n'a pas pu être réinitialisé à temps, veuillez réessayer ou attendre quelques secondes de plus et recharger le site web.",
|
||||
@@ -557,7 +557,7 @@
|
||||
"external_logs": "Logs externes",
|
||||
"history_all_servers": "Historique (tous les serveurs)",
|
||||
"in_memory_logs": "Logs En-mémoire",
|
||||
"log_info": "<p>Les logs <b>En-mémoire</b> Mailcow sont collectés dans des listes Valkey et découpées en LOG_LINES (%d) chaque minute pour réduire la charge.\n <br>Les logs En-mémoire ne sont pas destinés à être persistants. Toutes les applications qui se connectent en mémoire, se connectent également au démon Docker, et donc au pilote de journalisation par défaut.\n <br>Le type de journal en mémoire doit être utilisé pour déboguer les problèmes mineurs avec les conteneurs.</p>\n <p><b>Les logs externes</b> sont collectés via l'API de l'application concernée.</p>\n <p>Les journaux <b>statiques</b> sont principalement des journaux d’activité, qui ne sont pas enregistrés dans Dockerd, mais qui doivent toujours être persistants (sauf pour les logs API).</p>",
|
||||
"log_info": "<p>Les logs <b>En-mémoire</b> Mailcow sont collectés dans des listes Redis et découpées en LOG_LINES (%d) chaque minute pour réduire la charge.\n <br>Les logs En-mémoire ne sont pas destinés à être persistants. Toutes les applications qui se connectent en mémoire, se connectent également au démon Docker, et donc au pilote de journalisation par défaut.\n <br>Le type de journal en mémoire doit être utilisé pour déboguer les problèmes mineurs avec les conteneurs.</p>\n <p><b>Les logs externes</b> sont collectés via l'API de l'application concernée.</p>\n <p>Les journaux <b>statiques</b> sont principalement des journaux d’activité, qui ne sont pas enregistrés dans Dockerd, mais qui doivent toujours être persistants (sauf pour les logs API).</p>",
|
||||
"logs": "Logs",
|
||||
"restart_container": "Redémarrer",
|
||||
"docs": "Docs",
|
||||
|
||||
@@ -463,7 +463,7 @@
|
||||
"pushover_token": "Pushover token has a wrong format",
|
||||
"quota_not_0_not_numeric": "Lo spazio deve essere numerico e >= 0",
|
||||
"recipient_map_entry_exists": "A Recipient map entry \"%s\" exists",
|
||||
"valkey_error": "Valkey error: %s",
|
||||
"redis_error": "Redis error: %s",
|
||||
"relayhost_invalid": "Map entry %s is invalid",
|
||||
"release_send_failed": "Message could not be released: %s",
|
||||
"reset_f2b_regex": "Regex filter could not be reset in time, please try again or wait a few more seconds and reload the website.",
|
||||
@@ -522,7 +522,7 @@
|
||||
"history_all_servers": "Cronologia (tutti i server)",
|
||||
"in_memory_logs": "In-memory logs",
|
||||
"last_modified": "Ultima modifica",
|
||||
"log_info": "<p>mailcow <b>in-memory logs</b> are collected in Valkey lists and trimmed to LOG_LINES (%d) every minute to reduce hammering.\r\n <br>In-memory logs are not meant to be persistent. All applications that log in-memory, also log to the Docker daemon and therefore to the default logging driver.\r\n <br>The in-memory log type should be used for debugging minor issues with containers.</p>\r\n <p><b>External logs</b> are collected via API of the given application.</p>\r\n <p><b>Static logs</b> are mostly activity logs, that are not logged to the Dockerd but still need to be persistent (except for API logs).</p>",
|
||||
"log_info": "<p>mailcow <b>in-memory logs</b> are collected in Redis lists and trimmed to LOG_LINES (%d) every minute to reduce hammering.\r\n <br>In-memory logs are not meant to be persistent. All applications that log in-memory, also log to the Docker daemon and therefore to the default logging driver.\r\n <br>The in-memory log type should be used for debugging minor issues with containers.</p>\r\n <p><b>External logs</b> are collected via API of the given application.</p>\r\n <p><b>Static logs</b> are mostly activity logs, that are not logged to the Dockerd but still need to be persistent (except for API logs).</p>",
|
||||
"login_time": "Orario",
|
||||
"logs": "Logs",
|
||||
"online_users": "Utenti online",
|
||||
|
||||
@@ -456,7 +456,7 @@
|
||||
"quota_not_0_not_numeric": "クォータは数値で >= 0 である必要があります",
|
||||
"recipient_map_entry_exists": "受信者マップエントリ \"%s\" が存在します",
|
||||
"recovery_email_failed": "リカバリーメールを送信できませんでした。管理者にお問い合わせください。",
|
||||
"valkey_error": "Valkeyエラー: %s",
|
||||
"redis_error": "Redisエラー: %s",
|
||||
"relayhost_invalid": "マップエントリ %s は無効です",
|
||||
"release_send_failed": "メッセージをリリースできませんでした: %s",
|
||||
"reset_f2b_regex": "正規表現フィルターをタイムリーにリセットできませんでした。再試行するか、数秒待ってからウェブサイトをリロードしてください。",
|
||||
@@ -540,7 +540,7 @@
|
||||
"history_all_servers": "履歴(すべてのサーバー)",
|
||||
"in_memory_logs": "インメモリーログ",
|
||||
"last_modified": "最終更新日時",
|
||||
"log_info": "<p>mailcowの<b>インメモリーログ</b>はValkeyリストに収集され、ハンマリングを軽減するために1分ごとにLOG_LINES (%d)にトリムされます。\r\n <br>インメモリーログは永続化を目的としたものではありません。インメモリーログを記録するすべてのアプリケーションは、Dockerデーモンとデフォルトのログドライバーにもログを記録します。\r\n <br>インメモリーログタイプは、コンテナの軽微な問題をデバッグするために使用してください。</p>\r\n <p><b>外部ログ</b>は指定されたアプリケーションのAPIを介して収集されます。</p>\r\n <p><b>静的ログ</b>は主にアクティビティログであり、Dockerdには記録されませんが(APIログを除く)、永続化が必要です。</p>",
|
||||
"log_info": "<p>mailcowの<b>インメモリーログ</b>はRedisリストに収集され、ハンマリングを軽減するために1分ごとにLOG_LINES (%d)にトリムされます。\r\n <br>インメモリーログは永続化を目的としたものではありません。インメモリーログを記録するすべてのアプリケーションは、Dockerデーモンとデフォルトのログドライバーにもログを記録します。\r\n <br>インメモリーログタイプは、コンテナの軽微な問題をデバッグするために使用してください。</p>\r\n <p><b>外部ログ</b>は指定されたアプリケーションのAPIを介して収集されます。</p>\r\n <p><b>静的ログ</b>は主にアクティビティログであり、Dockerdには記録されませんが(APIログを除く)、永続化が必要です。</p>",
|
||||
"login_time": "ログイン時間",
|
||||
"logs": "ログ",
|
||||
"memory": "メモリ",
|
||||
|
||||
@@ -437,7 +437,7 @@
|
||||
"pushover_token": "Pushover 토큰 포맷이 잘못되었습니다.",
|
||||
"quota_not_0_not_numeric": "할당량은 숫자이여야 하고 0보다 크거나 같아야 합니다.",
|
||||
"recipient_map_entry_exists": "수신자 맵 항목 \"%s\"이 존재합니다",
|
||||
"valkey_error": "Valkey 에러: %s",
|
||||
"redis_error": "Redis 에러: %s",
|
||||
"relayhost_invalid": "유효하지 않은 맵 기록 %s",
|
||||
"release_send_failed": "메시지를 릴리즈할 수 없습니다.: %s",
|
||||
"resource_invalid": "리소스 이름 %s이 유효하지 않습니다.",
|
||||
@@ -499,7 +499,7 @@
|
||||
"external_logs": "External logs",
|
||||
"history_all_servers": "History (all servers)",
|
||||
"in_memory_logs": "In-memory logs",
|
||||
"log_info": "<p>mailcow <b>in-memory logs</b> are collected in Valkey lists and trimmed to LOG_LINES (%d) every minute to reduce hammering.\r\n <br>In-memory logs are not meant to be persistent. All applications that log in-memory, also log to the Docker daemon and therefore to the default logging driver.\r\n <br>The in-memory log type should be used for debugging minor issues with containers.</p>\r\n <p><b>External logs</b> are collected via API of the given application.</p>\r\n <p><b>Static logs</b> are mostly activity logs, that are not logged to the Dockerd but still need to be persistent (except for API logs).</p>",
|
||||
"log_info": "<p>mailcow <b>in-memory logs</b> are collected in Redis lists and trimmed to LOG_LINES (%d) every minute to reduce hammering.\r\n <br>In-memory logs are not meant to be persistent. All applications that log in-memory, also log to the Docker daemon and therefore to the default logging driver.\r\n <br>The in-memory log type should be used for debugging minor issues with containers.</p>\r\n <p><b>External logs</b> are collected via API of the given application.</p>\r\n <p><b>Static logs</b> are mostly activity logs, that are not logged to the Dockerd but still need to be persistent (except for API logs).</p>",
|
||||
"logs": "Logs",
|
||||
"restart_container": "Restart",
|
||||
"docs": "Docs",
|
||||
|
||||
@@ -185,11 +185,12 @@
|
||||
"protocol_access": "Endre protokolltilgang",
|
||||
"pushover": "Pushover",
|
||||
"quarantine": "Karantenehandlinger",
|
||||
"quarantine_attachments": "Sett vedlegg i karantene",
|
||||
"quarantine_attachments": "Se vedlegg i karantene",
|
||||
"quarantine_category": "Endre varslingskategori for karantene",
|
||||
"quarantine_notification": "Endre karantenevarslinger",
|
||||
"domain_desc": "Endre domenebeskrivelse",
|
||||
"extend_sender_acl": "Tillat utvidelse av sender-ACL fra eksterne adresser"
|
||||
"extend_sender_acl": "Tillat utvidelse av sender-ACL fra eksterne adresser",
|
||||
"pw_reset": "Tillat endring av brukerpassord"
|
||||
},
|
||||
"add": {
|
||||
"app_passwd_protocols": "Tillatte protokoller for app-passord",
|
||||
|
||||
@@ -423,7 +423,7 @@
|
||||
"pushover_token": "Formaat van Pushover-token is ongeldig",
|
||||
"quota_not_0_not_numeric": "Quota dient numeriek en groter dan 0 te zijn",
|
||||
"recipient_map_entry_exists": "Ontvanger-map met \"%s\" bestaat reeds",
|
||||
"valkey_error": "Valkey-error: %s",
|
||||
"redis_error": "Redis-error: %s",
|
||||
"relayhost_invalid": "Invoer %s is ongeldig",
|
||||
"release_send_failed": "Het volgende bericht kon niet worden vrijgegeven: %s",
|
||||
"reset_f2b_regex": "Regex-filters konden niet worden hersteld, probeer het opnieuw of herlaad de pagina over enkele seconden.",
|
||||
|
||||
@@ -1,50 +1,117 @@
|
||||
{
|
||||
"acl": {
|
||||
"sogo_profile_reset": "Usuń profil SOGo (webmail)",
|
||||
"syncjobs": "Polecenie synchronizacji",
|
||||
"alias_domains": "Dodaj aliasy domen",
|
||||
"delimiter_action": "Akcja oparta na separatorze"
|
||||
"sogo_profile_reset": "Zresetuj profil SOGo",
|
||||
"syncjobs": "Zadania doryczące synchronizacji kont",
|
||||
"alias_domains": "Dodaj domeny aliasowe",
|
||||
"delimiter_action": "Akcja oparta na separatorze",
|
||||
"app_passwds": "Zarządzaj hasłami do aplikacji",
|
||||
"bcc_maps": "Mapy BCC",
|
||||
"domain_desc": "Zmień opis dotyczący domeny",
|
||||
"domain_relayhost": "Zmień serwer przekazujący dla tej domeny",
|
||||
"eas_reset": "Resetuj urządzenia EAS",
|
||||
"extend_sender_acl": "Zezwalaj na rozszerzenie listy kontroli dostępu nadawców(ACL) o adresy zewnętrzne",
|
||||
"filters": "Dostępne filtry",
|
||||
"login_as": "Zaloguj się jako użytkownik poczty",
|
||||
"mailbox_relayhost": "Zmień serwer pocztowy(relayhost) dla skrzynki pocztowej",
|
||||
"prohibited": "Zakazane przez liste kontroli dostępu(ACL)",
|
||||
"protocol_access": "Zmień dostęp do protokołów",
|
||||
"pushover": "Pushover(powiadomienia push w czasie rzeczywistym)",
|
||||
"pw_reset": "Zezwalaj na resetowanie hasła użytkownika mailcow",
|
||||
"quarantine": "Akcje kwarantanny",
|
||||
"quarantine_attachments": "Załączniki do kwarantanny",
|
||||
"quarantine_category": "Zmień kategorię dotyczącą powiadomień o kwarantannie",
|
||||
"quarantine_notification": "Zmień powiadomienia o kwarantannie",
|
||||
"ratelimit": "Ograniczenie liczby zapytań",
|
||||
"recipient_maps": "Mapy odbiorców",
|
||||
"smtp_ip_access": "Zmiana dozwolonych hostów SMTP",
|
||||
"sogo_access": "Zezwól na zarządzanie dostępem SOGo",
|
||||
"spam_alias": "Tymczasowe aliasy",
|
||||
"spam_policy": "Zablokowane adresy/Dozwolone adresy",
|
||||
"spam_score": "Wskaźnik spam",
|
||||
"tls_policy": "Polityka TLS",
|
||||
"unlimited_quota": "Nieograniczony limit dla skrzynek pocztowych"
|
||||
},
|
||||
"add": {
|
||||
"active": "Aktywny",
|
||||
"add": "Dodaj",
|
||||
"alias_address": "Alias/y:",
|
||||
"alias_address": "Alias/y",
|
||||
"alias_address_info": "<small>Pełny/e adres/y email lub @example.com, aby przejąć wszystkie wiadomości dla domeny (oddzielone przecinkami). <b>tylko domeny mailcow</b>.</small>",
|
||||
"alias_domain": "Alias domeny",
|
||||
"alias_domain_info": "<small>Tylko prawidłowe nazwy domen (oddzielone przecinkami).</small>",
|
||||
"backup_mx_options": "Opcje Backup MX:",
|
||||
"backup_mx_options": "Opcje Backup MX",
|
||||
"delete1": "Usuń ze źródła po zakończeniu",
|
||||
"delete2duplicates": "Usuń duplikaty w miejscu docelowym",
|
||||
"description": "Opis:",
|
||||
"description": "Opis",
|
||||
"domain": "Domena",
|
||||
"domain_quota_m": "Łączny limit domeny (MiB):",
|
||||
"domain_quota_m": "Łączny limit domeny (MiB)",
|
||||
"enc_method": "Metoda szyfrowania",
|
||||
"exclude": "Wyklucz obiekty (regex)",
|
||||
"full_name": "Pełna nazwa:",
|
||||
"full_name": "Pełna nazwa",
|
||||
"hostname": "Nazwa hosta",
|
||||
"kind": "Rodzaj",
|
||||
"mailbox_quota_m": "Maks. wielkość skrzynki (MiB):",
|
||||
"mailbox_username": "Nazwa użytkownika (lewa strona adresu email):",
|
||||
"max_aliases": "Maks. liczba aliasów:",
|
||||
"max_mailboxes": "Maks. liczba skrzynek:",
|
||||
"mailbox_quota_m": "Maks. wielkość skrzynki (MiB)",
|
||||
"mailbox_username": "Nazwa użytkownika (lewa strona adresu email)",
|
||||
"max_aliases": "Maks. liczba aliasów",
|
||||
"max_mailboxes": "Maks. liczba skrzynek",
|
||||
"mins_interval": "Zakres pobierania (minuty)",
|
||||
"multiple_bookings": "Wielokrotne rejestracje",
|
||||
"password": "Hasło:",
|
||||
"password_repeat": "Potwierdź hasło(powtórz):",
|
||||
"password": "Hasło",
|
||||
"password_repeat": "Potwierdź hasło(powtórz)",
|
||||
"port": "Port",
|
||||
"post_domain_add": "Po dodaniu nowej domeny będziesz musiał ponownie uruchomić kontener serwisowy SOGo!",
|
||||
"quota_mb": "Limit wielkości (MiB):",
|
||||
"post_domain_add": "Kontener SOGo, \"sogo-mailcow\", musi zostać ponownie uruchomiony po dodaniu nowej domeny!<br><br>Dodatkowo należy przejrzeć konfigurację DNS domeny. Po zatwierdzeniu konfiguracji DNS uruchom ponownie \"acme-mailcow\", aby automatycznie wygenerować certyfikaty dla nowej domeny (autoconfig.<domain>, autodiscover.<domain>).<br>Ten krok jest opcjonalny i będzie ponownie wykonywany co 24 godziny.",
|
||||
"quota_mb": "Limit wielkości (MiB)",
|
||||
"relay_all": "Przekaż wszystkim odbiorcom",
|
||||
"relay_all_info": "<small>Jeśli decydujesz się <b>nie</b> przekazywać wszystkim odbiorcom, musisz dodać (\"ślepą\")skrzynkę dla każdego poszczególnego odbiorcy, któremu należy przekazać.</small>",
|
||||
"relay_all_info": "↪Jeśli wybierzesz <b>not</b>, aby przekazać wszystkich odbiorców, musisz dodać (\"ślepą\") skrzynkę pocztową dla każdego pojedynczego odbiorcy, która powinna być przekazywana.",
|
||||
"relay_domain": "Domena przekaźnikowa",
|
||||
"select": "Proszę wybrać...",
|
||||
"select_domain": "Proszę najpierw wybrać domenę",
|
||||
"syncjob": "Dodaj polecenie synchronizacji",
|
||||
"syncjob_hint": "Pamiętaj, że hasła należy zapisywać w zwykłym tekście!",
|
||||
"target_address": "Adresy Idź do:",
|
||||
"target_address": "Adresy Idź do",
|
||||
"target_address_info": "<small> Pełny/e adres/y email (oddzielone przecinkami).</small>",
|
||||
"target_domain": "Domena docelowa:",
|
||||
"username": "Nazwa użytkownika"
|
||||
"target_domain": "Domena docelowa",
|
||||
"username": "Nazwa użytkownika",
|
||||
"activate_filter_warn": "Wszystkie pozostałe filtry zostaną wyłączone, gdy opcja active zostanie zaznaczona.",
|
||||
"add_domain_only": "Dodaj wyłącznie domene",
|
||||
"add_domain_restart": "Dodaj domenę i uruchom ponownie SOGo",
|
||||
"app_name": "Nazwa aplikacji",
|
||||
"app_password": "Dodaj hasło do aplikacji",
|
||||
"app_passwd_protocols": "Dozwolone protokoły dla hasła aplikacji",
|
||||
"automap": "Spróbuj automatycznie mapować foldery (\"Wysłane elementy\", \"Wysłane\" => \"Wysłane\" itp.)",
|
||||
"bcc_dest_format": "Miejscem docelowym BCC musi być jeden prawidłowy adres e-mail.<br>Jeśli chcesz wysłać kopię do wielu adresów, utwórz alias i użyj go tutaj.",
|
||||
"comment_info": "Prywatny komentarz nie jest widoczny dla użytkownika, podczas gdy publiczny komentarz jest wyświetlany jako podpowiedź, które pojawia się, gdy użytkownik najedzie myszką nad elementem",
|
||||
"custom_params": "Niestandardowe parametry",
|
||||
"custom_params_hint": "Właściwa: --param=xy, błędna: --param xy",
|
||||
"delete2": "Usuń wiadomości w miejscu docelowym, które nie znajdują się w źródle",
|
||||
"destination": "Miejsce docelowe",
|
||||
"disable_login": "Nie pozwalaj na logowanie(poczta przychodząca jest nadal akceptowana)",
|
||||
"domain_matches_hostname": "Domena %s pasuje do nazwy hosta",
|
||||
"dry": "Symulacja synchronizacji",
|
||||
"gal": "Globalna lista adresów",
|
||||
"gal_info": "GAL zawiera wszystkie obiekty domeny i nie może być edytowany przez żadnego użytkownika. Wolne/zajęte logi w SOGo bedą nidostępne, jeśli są wyłączone! <b>Uruchom ponownie SOGo, aby zastosować zmiany.</b>",
|
||||
"generate": "generuj",
|
||||
"goto_ham": "Ucz się jako <span class=\"text-success\"><b>ham</b></span>",
|
||||
"goto_null": "Odrzucaj pocztę \"po cichu\"",
|
||||
"goto_spam": "Ucz się jako <span class=\"text-danger\"><b>spam</b></span>",
|
||||
"inactive": "Nieaktywny",
|
||||
"internal": "Wewnętrzny",
|
||||
"internal_info": "Aliasy wewnętrzne są dostępne tylko z domeny własnej lub domeny aliasów.",
|
||||
"mailbox_quota_def": "Domyślny przydział skrzynki pocztowej",
|
||||
"nexthop": "Następny hop",
|
||||
"private_comment": "Prywatny komentarz",
|
||||
"public_comment": "Komentarz publiczny",
|
||||
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Info</div>Możesz transports maps dla niestandardowego miejsca docelowego dla tej domeny. Jeśli nie jest ustawiony, zostanie aktywowany lookup MX.",
|
||||
"relay_unknown_only": "Przekaż tylko nieistniejące skrzynki pocztowe. Istniejące skrzynki pocztowe będą dostarczane lokalnie.",
|
||||
"relayhost_wrapped_tls_info": "Proszę <b>nie</b> używać portów owiniętych TLS (głównie używanych na porcie 465).<br>\nUżyj dowolnego portu niezawiniętego i uruchom STARTTLS. Polityka TLS w celu egzekwowania TLS może być utworzona w \"mapie zasad TLS\".",
|
||||
"sieve_desc": "Krótki opis",
|
||||
"sieve_type": "Typ filtra",
|
||||
"skipcrossduplicates": "Pomiń duplikaty wiadomości w folderach (na zasadzie kolejności zgłoszeń)",
|
||||
"subscribeall": "Subskrybuj wszystkie foldery",
|
||||
"tags": "Tagi",
|
||||
"timeout1": "Limit czasu połączenia z hostem zdalnym",
|
||||
"timeout2": "Limit czasu połączenia dla lokalnego hosta",
|
||||
"validate": "Zatwierdź",
|
||||
"validation_success": "Zatwierdzone z powodzeniem"
|
||||
},
|
||||
"admin": {
|
||||
"access": "Dostęp",
|
||||
@@ -100,7 +167,251 @@
|
||||
"spamfilter": "Filtr spamu",
|
||||
"time": "Czas",
|
||||
"unchanged_if_empty": "W przypadku braku zmian, nie wypełniaj",
|
||||
"username": "Nazwa użytkownika"
|
||||
"username": "Nazwa użytkownika",
|
||||
"activate_api": "Aktywuj API",
|
||||
"activate_send": "Aktywuj przycisk wysyłania",
|
||||
"active_rspamd_settings_map": "Aktywne ustawienia mapy",
|
||||
"add_admin": "Dodaj administratora",
|
||||
"add_relayhost": "Dodaj transport zależny od nadawcy",
|
||||
"add_relayhost_hint": "Miej na uwadze, że dane uwierzytelniające, jeśli takie istnieją, będą przechowywane w postaci zwykłego tekstu",
|
||||
"add_row": "Dodaj wiersz",
|
||||
"add_settings_rule": "Dodaj regułę ustawień",
|
||||
"add_transport": "Dodaj transport",
|
||||
"add_transports_hint": "Należy pamiętać, że dane uwierzytelniające, jeśli takie istnieją, będą przechowywane jako zwykły tekst.",
|
||||
"additional_rows": " Dodano kolejne rzędy",
|
||||
"admins": "Administratorzy",
|
||||
"admins_ldap": "Administratorzy LDAP",
|
||||
"admin_quicklink": "Ukryj szybki link do strony logowania administratora",
|
||||
"advanced_settings": "Ustawienia zaawansowane",
|
||||
"allowed_methods": "Dostęp-kontrola-zezwolenie-metody",
|
||||
"allowed_origins": "Dostęp-Kontrola-Zezwolenia-Pochodzenie",
|
||||
"api_allow_from": "Zezwalaj na dostęp API z tych notacji sieciowych IP/CIDR",
|
||||
"api_info": "API jest w trakcie prac. Dokumentację można znaleźć pod adresem <a href=\"/api\">/api</a>",
|
||||
"api_key": "klucz API",
|
||||
"api_read_only": "Dostęp tylko do odczytu",
|
||||
"api_read_write": "Dostęp tylko do odczytu",
|
||||
"api_skip_ip_check": "Pomiń sprawdzenie IP dla API",
|
||||
"app_hide": "Ukryj dla logowania",
|
||||
"app_links": "Linki aplikacji",
|
||||
"app_name": "Nazwa aplikacji",
|
||||
"apps_name": "Nazwa \"aplikacji mailcow\"",
|
||||
"arrival_time": "Czas serwera",
|
||||
"authed_user": "Autoryzowany użytkownik",
|
||||
"ays": "Jesteś pewien, że chcesz kontynuować?",
|
||||
"ban_list_info": "Zobacz listę zakazanych adresów IP poniżej: <b>network (pozostały czas zakazu) - [działania]</b>.<br/>IP kolejkowane do odbanowania zostaną usunięte z listy aktywnych zakazów w ciągu kilku sekund.<br/>Czerwone etykiety wskazują aktywny stałe zakazy poprzez odmowę wpisu.",
|
||||
"change_logo": "Zmień logo",
|
||||
"logo_normal_label": "Normalna",
|
||||
"logo_dark_label": "Odwrócony dla trybu ciemnego",
|
||||
"convert_html_to_text": "Konwertuj HTML na zwykły tekst",
|
||||
"copy_to_clipboard": "Tekst skopiowany do schowka!",
|
||||
"cors_settings": "Ustawienia CORS",
|
||||
"credentials_transport_warning": "Ostrzeżenie</b>: Dodanie nowego wpisu mapy transportu spowoduje aktualizację danych uwierzytelniających dla wszystkich wpisów z pasującą kolumną hop.",
|
||||
"customer_id": "Identyfikator klienta",
|
||||
"customize": "Dostosuj",
|
||||
"login_page": "Strona logowania",
|
||||
"destination": "Miejsce docelowe",
|
||||
"dkim_domains_selector": "Selektor",
|
||||
"dkim_domains_wo_keys": "Wybierz domeny z brakującymi kluczami",
|
||||
"dkim_from": "Od",
|
||||
"dkim_from_title": "Domena źródłowa do kopiowania danych z",
|
||||
"dkim_overwrite_key": "Nadpisanie istniejącego klucza DKIM",
|
||||
"dkim_to": "Do",
|
||||
"dkim_to_title": "Domeny docelowe - zostaną nadpisane",
|
||||
"domain_admin": "Administrator domeny",
|
||||
"domainadmin_quicklink": "Ukryj szybki link do strony logowania administratora domeny",
|
||||
"domain_s": "Domena/y",
|
||||
"duplicate": "Duplikat",
|
||||
"duplicate_dkim": "Duplikat rekordu DKIM",
|
||||
"excludes": "Wyklucza tych odbiorców",
|
||||
"f2b_ban_time_increment": "Czas zakazu jest zwiększany z każdym zakazem",
|
||||
"f2b_blacklist": "Lista odrzuconych sieci/hostów",
|
||||
"f2b_filter": "Filtry Regex",
|
||||
"f2b_list_info": "Odrzucony host lub sieć zawsze będzie przewyższać jednostkę zezwalającą.</b>Zastosowanie aktualizacji listy zajmie kilka sekund.</b><b>",
|
||||
"f2b_manage_external": "Zarządzaj Fail2Ban zewnętrznie",
|
||||
"f2b_manage_external_info": "Fail2ban nadal będzie utrzymywać listę banów, ale nie będzie aktywnie ustalać zasad blokowania ruchu. Użyj wygenerowane listy banów poniżej, aby zewnętrznie zablokować ruch.",
|
||||
"f2b_max_ban_time": "Max. czas bana (s)",
|
||||
"f2b_netban_ipv4": "Rozmiar podsieci IPv4 do zastosowania zakazu (8-32)",
|
||||
"f2b_netban_ipv6": "Rozmiar podsieci IPv6 do zastosowania zakazu (8-128)",
|
||||
"f2b_regex_info": "Logi brane pod uwagę: SOGo, Postfix, Dovecot, PHP-FPM.",
|
||||
"filter": "Filtr",
|
||||
"force_sso_text": "Jeśli skonfigurowany jest zewnętrzny dostawca OIDC, ta opcja ukrywa domyślne formularze logowania mailcow i pokazuje tylko przycisk logowania pojedynczego",
|
||||
"force_sso": "Wyłącz logowanie mailcow i pokaż tylko pojedyncze logowanie",
|
||||
"from": "Od",
|
||||
"generate": "Generuj",
|
||||
"guid": "GUID - unikalny identyfikator instancji",
|
||||
"guid_and_license": "GUID & licencja",
|
||||
"hash_remove_info": "Usunięcie hasha z limitem współczynnika (jeśli nadal istnieje) spowoduje całkowite zresetowanie jego licznika.<br>\n\nKażdy hash jest oznaczony indywidualnym kolorem.",
|
||||
"help_text": "Zastąp tekst pomocy poniżej maski logowania (dozwolone HTML)",
|
||||
"html": "HTML",
|
||||
"iam": "Dostawca tożsamości",
|
||||
"iam_attribute_field": "Pole atrybutów",
|
||||
"iam_authorize_url": "Punkt końcowy autoryzacji",
|
||||
"iam_auth_flow": "Przepływ uwierzytelniania",
|
||||
"iam_auth_flow_info": "Oprócz przepływu kodu autoryzacyjnego (Standardowy przepływ w Keycloak), który służy do logowania jednokrotnego logowania, mailcow obsługuje również przepływ uwierzytelniania z bezpośrednimi poświadczeniami. Mailpassword Flow próbuje zweryfikować dane uwierzytelniające użytkownika za pomocą Keycloak Admin REST API. mailcow pobiera hashowane hasło z atrybutu <code>mailcow_password</code>, który jest mapowany w Keycloak.",
|
||||
"iam_basedn": "Baza DN",
|
||||
"iam_client_id": "ID klienta",
|
||||
"iam_client_secret": "Sekret klienta",
|
||||
"iam_client_scopes": "Zakresy klientów",
|
||||
"iam_default_template": "Domyślny szablon",
|
||||
"iam_default_template_description": "Jeśli użytkownikowi nie zostanie przypisany żaden szablon, domyślny szablon zostanie użyty do utworzenia skrzynki pocztowej, ale nie do aktualizacji skrzynki pocztowej.",
|
||||
"iam_description": "Skonfiguruj zewnętrznego dostawce uwierzytelniania<br>Skrzynki pocztowe użytkownika zostaną automatycznie utworzone przy pierwszym logowaniu, pod warunkiem, że zostało ustawione mapowanie atrybutów.",
|
||||
"iam_extra_permission": "Aby następujące ustawienia działały, klient mailcow w Keycloak potrzebuje <code>konta serwisowego</code> oraz uprawnień do <code>podgląd-użytkowników</code>.",
|
||||
"iam_host": "Host",
|
||||
"iam_host_info": "Wprowadź jeden lub więcej hostów LDAP, oddzielonych przecinkami.",
|
||||
"iam_import_users": "Zaimportuj użytkowników",
|
||||
"iam_login_provisioning": "Automatyczne tworzenie użytkowników przy logowaniu",
|
||||
"iam_mapping": "Mapowanie atrybutów",
|
||||
"iam_bindpass": "Powiąż hasło",
|
||||
"iam_periodic_full_sync": "Okresowa pełna synchronizacja",
|
||||
"iam_port": "Port",
|
||||
"iam_realm": "Realm",
|
||||
"iam_redirect_url": "Przekierowanie Url",
|
||||
"iam_rest_flow": "Mailpassword Flow",
|
||||
"iam_server_url": "Adres URL serwera",
|
||||
"iam_sso": "Pojedyncze logowanie",
|
||||
"iam_sync_interval": "Interwał synchronizacji / importu (min)",
|
||||
"iam_test_connection": "Test połączenia",
|
||||
"iam_token_url": "Tokenowy punkt końcowy",
|
||||
"iam_userinfo_url": "Endpoint informacji o użytkowniku",
|
||||
"iam_username_field": "Pole nazwy użytkownika",
|
||||
"iam_binddn": "Powiąź DN",
|
||||
"iam_use_ssl": "Używaj SSL",
|
||||
"iam_use_ssl_info": "Jeśli włączysz SSL, a port zostanie ustawiony na 389, zostanie automatycznie nadpisany, aby użyć 636.",
|
||||
"iam_use_tls": "Używaj StartTLS",
|
||||
"iam_use_tls_info": "Jeśli włączono TLS, należy użyć domyślnego portu dla serwera LDAP (389). Nie można używać portów SSL.",
|
||||
"iam_version": "Wersja",
|
||||
"ignore_ssl_error": "Ignoruj błędy SSL",
|
||||
"in_use_by": "W użyciu przez",
|
||||
"include_exclude": "Uwzględnij/Nie uwzględniaj",
|
||||
"include_exclude_info": "Domyślnie - bez zaznaczenia - <b>wszystkie skrzynki pocztowe</b> są adresowane",
|
||||
"includes": "Uwzględnij tych odbiorców",
|
||||
"ip_check": "Sprawdź IP",
|
||||
"ip_check_disabled": "Sprawdzenie IP jest wyłączone. Możesz go włączyć w obszarze <br> <strong>System > Konfiguracja > Opcje > Dostosuj</strong>",
|
||||
"ip_check_opt_in": "Opt-In korzystania z usług stron trzecich <strong>ipv4.mailcow.email</strong> i <strong>ipv6.mailcow.email</strong> w celu rozwiązania zewnętrznych adresów IP.",
|
||||
"is_mx_based": "Bazuje na MX",
|
||||
"last_applied": "ostatnio zastosowany",
|
||||
"license_info": "Licencja nie jest wymagana, ale pomaga w dalszym rozwoju.<br><a href=\"https://www.servercow.de/mailcow?lang=en#sal\" target=\"_blank\" alt=\"SAL order\">Zarejestruj swój GUID tutaj</a> lub <a href=\"https://www.servercow.de/mailcow?lang=en#support\" target=\"_blank\" alt=\"Zamówienie wsparcia\">kup wsparcie dla instalacji mailcow.</a>",
|
||||
"link": "Link",
|
||||
"login_time": "Cześć logowania",
|
||||
"logo_info": "Twój obraz zostanie przeskalowany do wysokości 40px dla górnego paska nawigacyjnego i max. szerokości 250px dla strony startowej. Zalecana jest skalowalna grafika.",
|
||||
"recipients": "Odbiorcy",
|
||||
"send": "Wyślij",
|
||||
"sender": "Nadawca",
|
||||
"lookup_mx": "Destynacja jest regularnym wyrażeniem, które pasuje do nazwy MX (<code>.*\\\\.google\\.com</code>, aby przekierować całą pocztę skierowaną do MX kończącego się na google.com w tym hopie)",
|
||||
"main_name": "Nazwa \"mailcow UI\"",
|
||||
"merged_vars_hint": "Wyszarzone wiersze zostały połączone z <code>vars. (local.) inc.php</code> i nie można ich modyfikować.",
|
||||
"message_size": "Rozmiar wiadomości",
|
||||
"nexthop": "Następny hop",
|
||||
"needs_restart": "potrzebny restart",
|
||||
"no": "✕",
|
||||
"no_active_bans": "Brak aktywnych banów",
|
||||
"no_new_rows": "Brak dostępnych kolejnych wierszy",
|
||||
"oauth2_apps": "Aplikacje OAuth2",
|
||||
"oauth2_add_client": "Dodaj klienta OAuth2",
|
||||
"oauth2_client_id": "ID klienta",
|
||||
"oauth2_client_secret": "Sekret klienta",
|
||||
"oauth2_info": "Implementacja OAuth2 obsługuje typ grantu \"Kod autoryzacji\" i wydaje tokeny odświeżania.<br>\nSerwer automatycznie wydaje również nowe tokeny odświeżania, po użyciu tokena odświeżania.<br><br>\n• Domyślnym zakresem jest <i>profil</i>. Tylko użytkownicy skrzynek pocztowych mogą być uwierzytelniani w OAuth2. Jeśli parametr zakresu zostanie pominięty, wraca do <i>profil</i>.<br>\n\nParametr <i>state</i> musi zostać wysłany przez klienta w ramach żądania autoryzacji.<br><br>>\nŚcieżki zapytań do API OAuth2: <br>\n<ul>\nPunkt końcowy autoryzacji: <kod>/autoryzuj</koduj</koduj</li>\nPunkt końcowy tokena: <kod>/autoth/token</kod></li>\nStrona zasobów: <kod>/prawo/profil</kod>>\n</ul>\nRegeneracja tajemnicy klienta nie spowoduje wygaśnięcia istniejących kodów autoryzacyjnych, ale nie odnowi ich tokena.<br><br>\nOdwołanie tokenów klienta spowoduje natychmiastowe zakończenie wszystkich aktywnych sesji. Wszyscy klienci muszą się ponownie uwierzytelnić.",
|
||||
"oauth2_redirect_uri": "Przekieruj URI",
|
||||
"oauth2_renew_secret": "Wygeneruj sekret nowego klienta",
|
||||
"oauth2_revoke_tokens": "Unieważnij wszystkie tokeny klienta",
|
||||
"optional": "Opcjonalny",
|
||||
"options": "Opcje",
|
||||
"password_length": "Długość hasła",
|
||||
"password_policy": "Polityka haseł",
|
||||
"password_policy_chars": "Musi zawierać co najmniej jeden znak alfabetyczny",
|
||||
"password_policy_length": "Minimalna długość hasła to %d",
|
||||
"password_policy_lowerupper": "Musi zawierać małe i duże litery",
|
||||
"password_policy_numbers": "Musi zawierać co najmniej jeden numer",
|
||||
"password_policy_special_chars": "Musi zawierać znaki specjalne",
|
||||
"password_reset_info": "Jeśli nie jest udostępniony e-mail zapasowy, ta funkcja nie może być używana.",
|
||||
"password_reset_settings": "Ustawienia odzyskiwania haseł",
|
||||
"password_reset_tmpl_html": "Szablon HTML",
|
||||
"password_reset_tmpl_text": "Szablon tekstu",
|
||||
"password_settings": "Ustawienia hasła",
|
||||
"quarantine_bcc": "Wyślij kopię wszystkich powiadomień (BCC) do tego odbiorcy: <br><small>Pozostaw pustą aby wyłączyć. <b>Niepodpisana, niezaznaczona poczta. Powinna być dostarczana tylko wewnętrznie.</b></small>",
|
||||
"quarantine_exclude_domains": "Wyklucz domeny i domeny aliasowe",
|
||||
"quarantine_max_age": "Maksymalny wiek w dniach <br><small>Wartość musi być równa lub większa niż 1 dzień.</small>",
|
||||
"quarantine_max_score": "Odrzuć powiadomienie, jeśli wskaźnik spamu wiadomości jest wyższy niż ta wartość: <br><small>Domyślne do 9999.0</small>",
|
||||
"quarantine_max_size": "Maksymalny rozmiar w MiB (większe elementy są odrzucane):<br><small>0 oznacza, że <b>nie</b> oznacza nieograniczony.</small>",
|
||||
"quarantine_notification_html": "Szablon wiadomości e-mail z powiadomieniem:<br><small> Pozostaw puste, aby przywrócić szablon domyślny.</small>",
|
||||
"quarantine_notification_sender": "Powiadomienie nadawcy wiadomości e-mail",
|
||||
"quarantine_notification_subject": "Powiadomienie E-mail Temat",
|
||||
"quarantine_redirect": "<b>Przekieruj wszystkie powiadomienia </b> do tego odbiorcy:<br><small> Pozostaw pusty aby wyłączyć. <b>Niepodpisana, niezaznaczona poczta. Powinny być dostarczane tylko wewnętrznie.</b></small>",
|
||||
"quarantine_release_format": "Format zwolnionych przedmiotów",
|
||||
"quarantine_release_format_att": "Jako załącznik",
|
||||
"quarantine_release_format_raw": "Niezmodyfikowany oryginał",
|
||||
"quarantine_retention_size": "Retencje na skrzynkę pocztową: <br><small>0 oznacza <b>nieaktywne</b>.</small>",
|
||||
"quicklink_text": "Pokaż lub ukryj szybkie linki do innych stron logowania pod formularzem logowania",
|
||||
"quota_notification_html": "Szablon wiadomości e-mail z powiadomieniem:<br><small> Pozostaw puste, aby przywrócić szablon domyślny.</small>",
|
||||
"quota_notification_sender": "Powiadomienie nadawcy wiadomości e-mail",
|
||||
"quota_notification_subject": "Temat powiadomienia e-mail",
|
||||
"quota_notifications": "Powiadomienia o limitach",
|
||||
"quota_notifications_info": "Powiadomienia o limktach są wysyłane do użytkowników raz przy przekroczaniu 80% i raz przy przekraczaniu 95% zużycia.",
|
||||
"quota_notifications_vars": "{{percent}} równa się aktualnemu limitowi użytkownika<br>{{username}} jest nazwą skrzynki pocztowej",
|
||||
"queue_unban": "Zdejmij bana",
|
||||
"rate_name": "Nazwa oceny",
|
||||
"regen_api_key": "Regeneruj klucz API",
|
||||
"regex_maps": "Mapy Regex",
|
||||
"relay_from": "\"Od:\" adres",
|
||||
"relay_rcpt": "\"Do:\"Adres",
|
||||
"relay_run": "Uruchom test",
|
||||
"relayhosts": "Transporty zależne od nadawcy",
|
||||
"relayhosts_hint": "Zdefiniuj transporty zależne od nadawcy, aby móc wybrać je w oknie dialogowym konfiguracji domeny.<br>\nUsługa transportu jest zawsze \"smtp:\" i dlatego uruchomj TLS, gdy będzie oferowana. Owinięty TLS (SMTPS) nie jest obsługiwany. Pod uwagę brane jest indywidualne ustawienie polityki wychodzącej TLS użytkownika.<br>\nDotyczy wybranych domen, w tym domen aliasowych.",
|
||||
"remove_row": "Usuń wiersz",
|
||||
"reset_default": "Zresetuj do ustawień domyślnych",
|
||||
"reset_limit": "Usuń hash",
|
||||
"reset_password_vars": "<code>{{link}}</code> Wygenerowany link do resetu hasła <br><code>{{username}}</code> Nazwa skrzynki pocztowej użytkownika, który poprosił o zresetowanie hasła<br><code>{{username2}}</code> Nazwa skrzynki pocztowej do odzyskiwania <br><code>{{date}}</code> Data złożenia żądania resetowania hasła<br><code>{{token_lifetime}}</code>Żywotność tokena w minutach<br><code>{{hostname}}</code> Nazwa hosta mailcow",
|
||||
"restore_template": "Pozostaw puste, aby przywrócić szablon domyślny.",
|
||||
"routing": "Routing",
|
||||
"rsetting_add_rule": "Dodaj regułę",
|
||||
"rsetting_content": "Zawartość reguły",
|
||||
"rsetting_desc": "Krótki opis",
|
||||
"rsetting_no_selection": "Proszę zaznaczyć regułę",
|
||||
"rsetting_none": "Brak dostępnych reguł",
|
||||
"rsettings_insert_preset": "Wstaw przykład presetowany \"%s\"",
|
||||
"rsettings_preset_1": "Wyłącz wszystkie z wyjątkiem DKIM i limitu stawek dla uwierzytelnionych użytkowników",
|
||||
"rsettings_preset_2": "Administratorzy poczty pozwalają na spam",
|
||||
"rsettings_preset_3": "Zezwalaj tylko określonym nadawcom na skrzynkę pocztową (tj. używaj tylko jako wewnętrznej skrzynki pocztowej)",
|
||||
"rsettings_preset_4": "Wyłącz Rspamd dla domeny",
|
||||
"rspamd_com_settings": "Nazwa ustawienia zostanie automatycznie wygenerowana, zobacz przykładowe ustawienia wstępne poniżej. Aby uzyskać więcej informacji, zobacz <a href=\"https://rspamd.com/doc/configuration/settings.html#settings-structure\" target=\"_blank\">Rspamd docs</a>",
|
||||
"rspamd_global_filters": "Globalne mapy filtrów",
|
||||
"rspamd_global_filters_agree": "Będę ostrożny!",
|
||||
"rspamd_global_filters_info": "Globalne mapy filtrów zawierają różne rodzaje globalnych list dozwolonych i zablokowanych adresów.",
|
||||
"rspamd_global_filters_regex": "Ich imiona wyjaśniają ich cel. Cała zawartość musi zawierać ważne wyrażenie regularne w formacie \"/pattern/options\" (e.g. <code>/.+@domain\\.tld/i</code>).<br>\nChociaż podstawowe kontrole są wykonywane na każdej linii regex, funkcja Rspamd może zostać złamana, jeśli nie odczyta poprawnie składni.<br>>\nRspamd po zmianie spróbuje odczytać zawartość mapy. Jeśli wystąpią problemy, <a href=\"\" data-toggle=\"modal\" data-container=\"rspamd-mailcow\" data-target=\"#RestartContainer\">restart Rspamd</a>, aby wymusić ponowne ładowanie mapy.<br> Elementy z listy odrzuconych są wyłączone z kwarantanny.",
|
||||
"rspamd_settings_map": "Mapa ustawień Rspamd",
|
||||
"sal_level": "Poziom Moo",
|
||||
"service": "Usługa",
|
||||
"service_id": "Id usługi",
|
||||
"subject": "Temat",
|
||||
"success": "Sukces",
|
||||
"sys_mails": "Maile systemowe",
|
||||
"task": "Zadanie",
|
||||
"text": "Tekst",
|
||||
"title": "Tytuł",
|
||||
"title_name": "Tytuł strony internetowej \"mailcow UI\"",
|
||||
"to_top": "Powrót na górę",
|
||||
"transport_dest_format": "Regex lub syntax: example.org, .example.org, *, box@example.org\n(wiele wartości można rozdzielić przecinkami)",
|
||||
"transport_maps": "Mapy transportu",
|
||||
"transport_test_rcpt_info": "• Użyj null@hosted.mailcow.de aby przetestować przekazywanie do nieznanego miejsca docelowego.",
|
||||
"transports_hint": "• Wpis mapy transportowej <b>overrules</b> mapa transportowa zależna od nadawcy</b>.<br>\nNajlepiej stosować transporty oparte na MX •.<br>\nUstawienia zasad Outbound TLS dotyczące użytkownika są ignorowane i mogą być egzekwowane tylko przez wpisy mapy zasad TLS\n• Usługa transportu dla zdefiniowanych transportów jest zawsze \"smtp:\" i dlatego uruchomi TLS, gdy będzie oferowana. Wrapped TLS (SMTPS) nie jest obsługiwany.<br>\nAdresy pasujące do \"/localhost$/\" będą zawsze transportowane przez \"lokalne:\", dlatego miejsce docelowe \"*\" nie będzie miało zastosowania do tych adresów.<br>\n• Aby określić poświadczenia dla przykładowego następnego hopa \"[host]:25\", Postfix <b>zawsze</b> kolejkuje zapytania o \"host\" przed wyszukaniem \"[host]:25\". Takie zachowanie uniemożliwia jednoczesne użycie \"host\" i \"[host]:25.",
|
||||
"ui_footer": "Stopka (dozwolone HTML)",
|
||||
"ui_header_announcement": "Ogłoszenia",
|
||||
"ui_header_announcement_active": "Ustaw ogłoszenie jako aktywne",
|
||||
"ui_header_announcement_content": "Tekst (dozwolony HTML)",
|
||||
"ui_header_announcement_help": "Ogłoszenie jest widoczne dla wszystkich zalogowanych użytkowników oraz na ekranie logowania interfejsu użytkownika.",
|
||||
"ui_header_announcement_select": "Wybierz typ ogłoszenia",
|
||||
"ui_header_announcement_type": "Typ",
|
||||
"ui_header_announcement_type_danger": "Bardzo ważne",
|
||||
"ui_header_announcement_type_info": "Info",
|
||||
"ui_header_announcement_type_warning": "Ważne",
|
||||
"ui_texts": "Etykiety i teksty UI",
|
||||
"unban_pending": "oczekuje na odblokowanie",
|
||||
"upload": "Prześlij",
|
||||
"user_link": "Link użytkownika",
|
||||
"user_quicklink": "Ukryj Quicklink do strony logowania użytkownika",
|
||||
"validate_license_now": "Sprawdź identyfikator GUID względem serwera licencji",
|
||||
"verify": "Zweryfikuj",
|
||||
"yes": "✓"
|
||||
},
|
||||
"danger": {
|
||||
"access_denied": "Odmowa dostępu lub nieprawidłowe dane w formularzu",
|
||||
@@ -113,17 +424,17 @@
|
||||
"description_invalid": "Nieprawidłowy opis źródła",
|
||||
"dkim_domain_or_sel_invalid": "Nieprawidłowa domena lub selektor DKIM",
|
||||
"domain_exists": "Domena %s już istnieje",
|
||||
"domain_invalid": "Błędna nazwa domeny",
|
||||
"domain_invalid": "Nazwa domeny jest pusta lub nieprawidłowa",
|
||||
"domain_not_empty": "Nie można usunąć niepustej domeny",
|
||||
"domain_not_found": "Nie znaleziono domeny %s",
|
||||
"domain_quota_m_in_use": "Limit domeny %s MiB",
|
||||
"goto_empty": "Adres Idź do nie może być pusty",
|
||||
"domain_quota_m_in_use": "Limit domeny musi być większy lub równy do %s MiB",
|
||||
"goto_empty": "Adres alias musi zawierać co najmniej jeden prawidłowy adres goto",
|
||||
"goto_invalid": "Adres Idź do jest nieprawidłowy",
|
||||
"is_alias": "%s został już podany jako alias",
|
||||
"is_alias_or_mailbox": "%s podano wcześniej jako alias lub skrzynkę",
|
||||
"is_spam_alias": "%s podano wcześniej jako alias dla spam",
|
||||
"last_key": "Nie można usunąć ostatniego klucza",
|
||||
"login_failed": "Niepowodzenie logowania",
|
||||
"last_key": "Nie można usunąć ostatniego klucza, zamiast tego należy wyłączyć TFA.",
|
||||
"login_failed": "Logowanie nie powiodło się",
|
||||
"mailbox_invalid": "Nieprawidłowa nazwa skrzynki",
|
||||
"mailbox_quota_exceeded": "Wielkość przekracza limit domeny (maks. %d MiB)",
|
||||
"mailbox_quota_exceeds_domain_quota": "Maksymalna wielkość przekracza limit domeny",
|
||||
@@ -146,7 +457,106 @@
|
||||
"target_domain_invalid": "Domena Idź do jest nieprawidłowa",
|
||||
"targetd_not_found": "Nie znaleziono domeny docelowej",
|
||||
"username_invalid": "Nie można użyć nazwy użytkownika",
|
||||
"validity_missing": "Proszę wyznaczyć termin ważności"
|
||||
"validity_missing": "Proszę wyznaczyć termin ważności",
|
||||
"to_invalid": "Pole odbiorca nie może być puste",
|
||||
"app_name_empty": "Nazwa aplikacji nie może być pusta",
|
||||
"app_passwd_id_invalid": "Identyfikator hasła aplikacji %s jest niepoprawny",
|
||||
"authsource_in_use": "Nie można zmienić ani usunąć dostawcy tożsamości, ponieważ jest używany przez co najmniej jednego użytkownika.",
|
||||
"bcc_empty": "Miejsce docelowe BCC nie może być puste",
|
||||
"bcc_exists": "Mapa BCC %s istnieje dla typu %s",
|
||||
"bcc_must_be_email": "Miejsce docelowe BCC %s nie jest prawidłowym adresem e-mail",
|
||||
"comment_too_long": "Komentarz zbyt długi, maksymalnie 160 dozwolonych znaków.",
|
||||
"cors_invalid_method": "Podano nieprawidłową metodę Allow-Method",
|
||||
"cors_invalid_origin": "Podano nieprawidłową wartość Allow-Origin",
|
||||
"defquota_empty": "Domyślny limit skrzynki pocztowej nie może wynosić 0",
|
||||
"demo_mode_enabled": "Tryb demo jest włączony",
|
||||
"dkim_domain_or_sel_exists": "Klucz DKIM dla \"%s\" istnieje i nie zostanie nadpisany",
|
||||
"domain_cannot_match_hostname": "Domena nie może być taka sama jak nazwa hosta",
|
||||
"extended_sender_acl_denied": "brak ACL do ustawiania adresów nadawcy zewnętrznego",
|
||||
"extra_acl_invalid": "Adres nadawcy zewnętrznego \"%s\" jest nieważny",
|
||||
"extra_acl_invalid_domain": "Nadawca zewnętrzny \"%s\" używa nieprawidłowej domeny",
|
||||
"fido2_verification_failed": "Weryfikacja FIDO2 nie powiodła się: %s",
|
||||
"file_open_error": "Nie można otworzyć pliku do zapisu",
|
||||
"filter_type": "Niewłaściwy typ filtra",
|
||||
"from_invalid": "Nadawca nie może być pusty",
|
||||
"generic_server_error": "Wystąpił nieoczekiwany błąd serwera. Skontaktuj się z administratorem.",
|
||||
"global_filter_write_error": "Nie można zapisać pliku filtra: %s",
|
||||
"global_map_invalid": "Id mapy globalnej %s nieprawidłowe",
|
||||
"global_map_write_error": "Nie można napisać globalnej mapy ID %s: %s",
|
||||
"ham_learn_error": "Błąd uczenia ham: %s",
|
||||
"iam_test_connection": "Połączenie nie powiodło się",
|
||||
"imagick_exception": "Błąd: wyjątek Imagick podczas odczytu obrazu",
|
||||
"img_dimensions_exceeded": "Obraz przekracza maksymalny rozmiar obrazu",
|
||||
"img_invalid": "Nie można zweryfikować pliku obrazu",
|
||||
"img_size_exceeded": "Obraz przekracza maksymalny rozmiar pliku",
|
||||
"img_tmp_missing": "Nie można zweryfikować pliku obrazu: Nie znaleziono pliku tymczasowego",
|
||||
"invalid_bcc_map_type": "Nieprawidłowy typ mapy BCC",
|
||||
"invalid_destination": "Format docelowy \"%s\" jest nieprawidłowy",
|
||||
"invalid_filter_type": "Nieprawidłowy typ filtra",
|
||||
"invalid_host": "Nieprawidłowy określony host: %s",
|
||||
"invalid_mime_type": "Niepoprawny typ mime",
|
||||
"invalid_nexthop": "Następny format hop jest nieprawidłowy",
|
||||
"invalid_nexthop_authenticated": "Następny hop już istnieje z innymi danymi logowania — zaktualizuj najpierw istniejące dane uwierzytelniające dla tego hopa",
|
||||
"invalid_recipient_map_new": "Określony nieprawidłowy nowy odbiorca: %s",
|
||||
"invalid_recipient_map_old": "Określony nieprawidłowy pierwotny odbiorca: %s",
|
||||
"invalid_reset_token": "Nieprawidłowy token resetu",
|
||||
"ip_list_empty": "Lista dozwolonych adresów IP nie może być pusta",
|
||||
"mailbox_defquota_exceeds_mailbox_maxquota": "Domyślny limit skrzynki pocztowej przekracza maksymalny dozwolony limit",
|
||||
"malformed_username": "Nieprawidłowy format nazwy użytkownika.",
|
||||
"map_content_empty": "Zawartość mapy nie może być pusta",
|
||||
"max_age_invalid": "Nieprawidłowa wartość maksymalnego wieku: %s",
|
||||
"mode_invalid": "Tryb %s jest nieprawidłowy",
|
||||
"mx_invalid": "Rekord MX %s jest nieprawidłowy",
|
||||
"mysql_error": "Błąd MySQL: %s",
|
||||
"network_host_invalid": "Nieprawidłowa sieć lub host: %s",
|
||||
"next_hop_interferes": "%s powoduje konflikt z nexthop %s.",
|
||||
"next_hop_interferes_any": "Istniejący next hop koliduje z %s.”",
|
||||
"nginx_reload_failed": "Nie udało się przeładować Nginx: %s",
|
||||
"no_user_defined": "Brak zdefiniowanego użytkownika",
|
||||
"password_reset_invalid_user": "Skrzynka pocztowa nie została znaleziona lub nie ustawiono adresu e-mail do odzyskiwania",
|
||||
"password_reset_na": "Odzyskiwanie hasła jest obecnie niedostępne. Skontaktuj się ze swoim administratorem.",
|
||||
"private_key_error": "Błąd klucza prywatnego: %s",
|
||||
"pushover_credentials_missing": "Brak tokena i/lub klucza Pushover",
|
||||
"pushover_key": "Klucz Pushover ma niewłaściwy format",
|
||||
"pushover_token": "Token Pushover ma zły format",
|
||||
"recipient_map_entry_exists": "Istnieje wpis mapy odbiorcy \"%s",
|
||||
"recovery_email_failed": "Nie można wysłać e-maila odzyskiwania. Skontaktuj się ze swoim administratorem.",
|
||||
"redis_error": "Błąd Redis: %s",
|
||||
"relayhost_invalid": "Wpis mapy %s jest niepoprawny",
|
||||
"release_send_failed": "Nie udało się zwolnić wiadomości: %s.",
|
||||
"required_data_missing": "Brakuje wymaganych danych %s",
|
||||
"reset_f2b_regex": "Filtr Regex nie mógł zostać zresetowany na czas, spróbuj ponownie lub poczekaj jeszcze kilka sekund i przeładuj stronę.",
|
||||
"reset_token_limit_exceeded": "Limit tokenów Reset został przekroczony. Spróbuj ponownie później",
|
||||
"rl_timeframe": "Nieprawidłowo ustawiony przedział czasu limitu",
|
||||
"rspamd_ui_pw_length": "Hasło do Rspamd UI powinno mieć co najmniej 6 znaków długości",
|
||||
"script_empty": "Skrypt nie może być pusty",
|
||||
"set_acl_failed": "Nie udało się ustawić ACL",
|
||||
"settings_map_invalid": "Ustawienia id mapy %s są nieprawidłowe",
|
||||
"sieve_error": "Błąd podczas analizy skryptu Sieve: %s",
|
||||
"spam_learn_error": "Błąd uczenia spamu: %s.",
|
||||
"subject_empty": "Temat nie może być pusty",
|
||||
"targetd_relay_domain": "Domena docelowa %s jest skonfigurowana jako domena przekazująca relay",
|
||||
"template_exists": "Szablon %s już istnieje",
|
||||
"template_id_invalid": "Identyfikator szablonu %s niepoprawny",
|
||||
"template_name_invalid": "Nazwa szablonu niepoprawna",
|
||||
"temp_error": "Tymczasowy błąd",
|
||||
"text_empty": "Pole tekstowe nie może być puste",
|
||||
"tfa_token_invalid": "Niepoprawny token TFA",
|
||||
"tls_policy_map_dest_invalid": "Podano błędne lub nieobsługiwane miejsce docelowe dla tej polityki",
|
||||
"tls_policy_map_entry_exists": "Istnieje mapa polityki TLS \"%s",
|
||||
"tls_policy_map_parameter_invalid": "Parametr polityki jest nieprawidłowy",
|
||||
"totp_verification_failed": "Weryfikacja TOTP nie powiodła się",
|
||||
"transport_dest_exists": "Miejsce docelowe transportu „%s” już istnieje",
|
||||
"webauthn_verification_failed": "Weryfikacja WebAuthn nie powiodła się: %s",
|
||||
"webauthn_authenticator_failed": "Wybrany autoryzator nie został odnaleziony",
|
||||
"webauthn_publickey_failed": "Nie przechowywano klucza publicznego dla wybranego uwierzytelniacza",
|
||||
"webauthn_username_failed": "Wybrany autoryzator należy do innego konta",
|
||||
"unknown": "Wystąpił nieznany błąd",
|
||||
"unknown_tfa_method": "Nieznana metodą TFA",
|
||||
"unlimited_quota_acl": "Ustawienie nieograniczonego limitu przestrzeni jest zabronione przez reguły ACL",
|
||||
"value_missing": "Proszę o podanie wszystkich wartości",
|
||||
"version_invalid": "Wersja %s jest niepoprawna",
|
||||
"yotp_verification_failed": "Weryfikacja OTP Yubico nie powiodła się: %s"
|
||||
},
|
||||
"edit": {
|
||||
"active": "Aktywny",
|
||||
@@ -191,13 +601,58 @@
|
||||
"target_domain": "Domena docelowa",
|
||||
"title": "Edytuj obiekt",
|
||||
"unchanged_if_empty": "Jeżli bez zmian, nie wypełniaj",
|
||||
"username": "Nazwa użytkownika"
|
||||
"username": "Nazwa użytkownika",
|
||||
"delete_ays": "Proszę o potwierdzenie procesu usuwania.",
|
||||
"acl": "ACL (Pozwolenie)",
|
||||
"admin": "Edytyj administratora",
|
||||
"advanced_settings": "Ustawienia zaawansowane",
|
||||
"allow_from_smtp": "Zezwalaj tylko tym adresom IP na używanie <b>SMTP</b>",
|
||||
"allow_from_smtp_info": "Pozostaw puste, aby zezwolić na wszystkich nadawców.<br>adresy IPv4/IPv6 i sieci.",
|
||||
"allowed_protocols": "Dozwolone protokoły dla bezpośredniego dostępu użytkownika (nie wpływa na protokoły haseł aplikacji).",
|
||||
"app_name": "Nazwa aplikacji",
|
||||
"app_passwd": "Hasło do aplikacji",
|
||||
"app_passwd_protocols": "Dozwolone protokoły dla hasła aplikacji",
|
||||
"automap": "Spróbuj automatycznie mapować foldery (np. „Sent items”, „Sent” ⇒ „Sent” itp.)",
|
||||
"bcc_dest_format": "Miejscem docelowym BCC musi być jeden prawidłowy adres e-mail.<br>Jeśli chcesz wysłać kopię na wiele adresów, utwórz alias i użyj go tutaj.",
|
||||
"client_id": "Id klienta",
|
||||
"client_secret": "Tajny klucz klienta(sekret)",
|
||||
"comment_info": "Komentarz prywatny nie jest widoczny dla użytkownika, natomiast komentarz publiczny jest wyświetlany jako podpowiedź po najechaniu kursorem w widoku użytkownika.",
|
||||
"created_on": "Stworzony na",
|
||||
"custom_attributes": "Niestandardowe atrybuty",
|
||||
"delete2": "Usunąć wiadomości na koncie docelowym, które nie występują na koncie źródłowym?",
|
||||
"disable_login": "Zablokuj logowanie (przychodząca poczta nadal będzie przyjmowana)",
|
||||
"domain_footer": "Stopka dla całej domeny",
|
||||
"domain_footer_html": "Stopka HTML",
|
||||
"domain_footer_info": "Stopki dla całej domeny są dodawane do wszystkich wychodzących wiadomości e-mail powiązanych z adresami w tej domenie.<br>W stopce można użyć następujących zmiennych:",
|
||||
"domain_footer_info_vars": {
|
||||
"auth_user": "{= auth_user =} - Uwierzytelniona nazwa użytkownika określona przez MTA",
|
||||
"from_user": "{= from_user =} – część użytkownika (local-part) adresu nadawcy; np. dla „moo@mailcow.tld\n” zwróci „moo”",
|
||||
"from_name": "{= from_name =} – nazwa nadawcy (From name) z nagłówka wiadomości; np. dla „Mailcow <moo@mailcow.tld\n>” zwróci „Mailcow”.",
|
||||
"from_addr": "{= from_addr =} – pełny adres nadawcy (z części envelope)",
|
||||
"from_domain": "{= from_domain =} – część domenowa adresu nadawcy (z envelope).",
|
||||
"custom": "{= foo =} - jeśli skrzynka pocztowa ma niestandardowy atrybut „foo” o wartości „bar”, zwraca „bar”."
|
||||
},
|
||||
"domain_footer_plain": "Stopka w formacie tekstowym(PLAIN)",
|
||||
"domain_footer_skip_replies": "Nie dodawaj stopki do odpowiedzi na e-maile",
|
||||
"extended_sender_acl": "Adresy nadawców zewnętrznych",
|
||||
"extended_sender_acl_info": "Klucz DKIM dla domeny powinien zostać zaimportowany, jeśli jest dostępny.\nPamiętaj, aby dodać ten serwer do odpowiadającego rekordu SPF typu TXT.\nKiedy domena lub domena aliasu zostanie dodana do tego serwera i pokrywa się z zewnętrznym adresem, zewnętrzny adres zostanie usunięty.",
|
||||
"force_pw_update": "Wymuszenie aktualizacji hasła przy następnym logowaniu",
|
||||
"force_pw_update_info": "Ten użytkownik będzie mógł logować się wyłącznie do %s. Hasła aplikacyjne pozostają aktywne.",
|
||||
"footer_exclude": "Wyklucz ze stopki",
|
||||
"gal": "Globalna lista adresowa",
|
||||
"gal_info": "GAL zawiera wszystkie obiekty domeny i nie może być edytowana przez żadnego użytkownika. Informacje o dostępności (free/busy) w SOGo są niedostępne, jeśli funkcja jest wyłączona!<b>Uruchom ponownie SOGo, aby zastosować zmiany.</b>",
|
||||
"generate": "generuj",
|
||||
"grant_types": "Rodzaje grantów(Typy przyznawania dostępu)",
|
||||
"internal": "Wewnętrzny",
|
||||
"internal_info": "Aliasów wewnętrznych można używać tylko w obrębie własnej domeny lub domen aliasów.",
|
||||
"last_modified": "Ostatnio modyfikowany",
|
||||
"lookup_mx": "Destination to wyrażenie regularne dopasowujące nazwę serwera MX (np. <code>.*.google.com</code> — aby kierować całą pocztę wysyłaną do MX kończących się na google.com przez ten hop)."
|
||||
},
|
||||
"footer": {
|
||||
"cancel": "Anuluj",
|
||||
"confirm_delete": "Potwierdź usunięcie",
|
||||
"delete_now": "Usuń teraz",
|
||||
"delete_these_items": "Czy jesteś pewien, że chcesz usunąć następujące elementy?",
|
||||
"delete_these_items": "Proszę potwierdzić zmiany w poniższym identyfikatorze obiektu",
|
||||
"loading": "Proszę czekać...",
|
||||
"restart_now": "Uruchom ponownie teraz"
|
||||
},
|
||||
@@ -216,7 +671,14 @@
|
||||
"delayed": "Logowanie zostało opóźnione o %s sekund.",
|
||||
"login": "Zaloguj się",
|
||||
"password": "Hasło",
|
||||
"username": "Nazwa użytkownika"
|
||||
"username": "Nazwa użytkownika",
|
||||
"forgot_password": "Zapomniałeś hasła?",
|
||||
"login_linkstext": "Login nieprawidłowy?",
|
||||
"login_usertext": "Zaloguj się jako użytkownik",
|
||||
"login_domainadmintext": "Zaloguj się jako administrator domeny",
|
||||
"login_admintext": "Zaloguj się jako admin",
|
||||
"other_logins": "lub zaloguj za pomocą",
|
||||
"email": "Adres e-mail"
|
||||
},
|
||||
"mailbox": {
|
||||
"action": "Działanie",
|
||||
@@ -284,10 +746,15 @@
|
||||
"quarantine": "Kwarantanna",
|
||||
"quick_actions": "Szybkie działania",
|
||||
"remove": "Usuń",
|
||||
"toggle_all": "Zaznacz wszystkie"
|
||||
"toggle_all": "Zaznacz wszystkie",
|
||||
"confirm_delete": "Potwierdź usunięcie tego elementu.",
|
||||
"learn_spam_delete": "Zapamiętaj jako spam i usuwaj w przyszłości",
|
||||
"quick_delete_link": "Otwórz szybki link do usuwania"
|
||||
},
|
||||
"queue": {
|
||||
"queue_manager": "Queue Manager"
|
||||
"queue_manager": "Menedżer kolejki",
|
||||
"delete": "Usuń wszystko",
|
||||
"ays": "Potwierdź, że chcesz usunąć wszystkie elementy z bieżącej kolejki."
|
||||
},
|
||||
"start": {
|
||||
"help": "Pokaż/Ukryj panel pomocy",
|
||||
@@ -298,7 +765,7 @@
|
||||
"alias_added": "Alias/y został/y dodany/e",
|
||||
"alias_domain_removed": "Usunięto alias domeny %s",
|
||||
"alias_modified": "Zapisano zmiany w aliasie/ach %s",
|
||||
"alias_removed": "Usunięto alias %s ",
|
||||
"alias_removed": "Usunięto alias %s",
|
||||
"aliasd_added": "Dodano alias domeny %s",
|
||||
"aliasd_modified": "Zapisano zmiany w aliasie domeny %s",
|
||||
"dkim_added": "Klucz DKIM został zapisany",
|
||||
@@ -314,23 +781,32 @@
|
||||
"forwarding_host_added": "Dodano hosta przekazującego %s",
|
||||
"forwarding_host_removed": "Usunięto hosta przekazującego %s",
|
||||
"item_deleted": "",
|
||||
"items_deleted": "Item %s successfully deleted",
|
||||
"items_deleted": "Elementy %s skutecznie usunięte",
|
||||
"mailbox_added": "Dodano skrzynkę %s",
|
||||
"mailbox_modified": "Zapisano zmiany w skrzynce %s",
|
||||
"mailbox_removed": "Usunięto skrzynkę %s",
|
||||
"object_modified": "Zapisano zmiany w obiekcie %s",
|
||||
"resource_added": "Dodano śródło %s",
|
||||
"resource_modified": "Zapisano zmiany w skrzynce %s",
|
||||
"resource_removed": "Usunięto zasób %s"
|
||||
"resource_removed": "Usunięto zasób %s",
|
||||
"template_removed": "Szablon o identyfikatorze %s został usunięty.",
|
||||
"tls_policy_map_entry_deleted": "Mapa polityki TLS o identyfikatorze %s została usunięta",
|
||||
"tls_policy_map_entry_saved": "Wpis mapy polityki TLS \"%s\" został zapisany",
|
||||
"ui_texts": "Zapisane zmiany w tekstach UI",
|
||||
"upload_success": "Plik przesłany pomyślnie",
|
||||
"verified_fido2_login": "Zweryfikowany login FIDO2",
|
||||
"verified_totp_login": "Zweryfikowany login TOTP",
|
||||
"verified_webauthn_login": "Zweryfikowany login WebAuthn",
|
||||
"verified_yotp_login": "Zweryfikowany login Yubico OTP"
|
||||
},
|
||||
"tfa": {
|
||||
"api_register": "%s używa Yubico Cloud API. Proszę pobrać klucz API dla Twojego klucza <a href=\"https://upgrade.yubico.com/getapikey/\" target=\"_blank\">here</a>",
|
||||
"api_register": "%s używa Yubico Cloud API. Proszę pobrać klucz API dla Twojego klucza <a href=\"https://upgrade.yubico.com/getapikey/\" target=\"_blank\">tutaj</a>",
|
||||
"confirm": "Potwierdź",
|
||||
"confirm_totp_token": "Potwierdź zmiany przez wprowadzenie wygenerowanego tokenu",
|
||||
"delete_tfa": "Wyłącz TFA",
|
||||
"disable_tfa": "Wyłącz TFA do kolejnego udanego logowania",
|
||||
"enter_qr_code": "Twój kod TOTP, jeśli Twoje urządzenie nie skanuje kodów QR.",
|
||||
"key_id": "Identyfikator dla Twojego YubiKey",
|
||||
"key_id": "Identyfikator dla twojego urządzenia",
|
||||
"key_id_totp": "Identyfikator dla Twojego klucza",
|
||||
"none": "Deaktywuj",
|
||||
"scan_qr_code": "Zeskanuj następujący kod aplikacją uwierzytelniającą lub wprowadź kod ręcznie.",
|
||||
@@ -340,8 +816,16 @@
|
||||
"totp": "Time-based OTP (Google Authenticator itd.)",
|
||||
"webauthn": "Uwierzytelnianie WebAuthn",
|
||||
"waiting_usb_auth": "<i>Czekam na urządzenie USB...</i><br><br>Wciśnij teraz przycisk na urządzeniu WebAuthn USB.",
|
||||
"waiting_usb_register": "<i> Czekam na urządzenie USB...</i><br><br>Wprowadź swoje hasło powyżej i potwierdź rejestrację WebAuthn przez naciśnięcie przycisku na urządzeniu WebAuthn USB.",
|
||||
"yubi_otp": "Uwierzytelnianie Yubico OTP"
|
||||
"waiting_usb_register": "<i> Czekam na urządzenie USB...</i><br><br>Wprowadź swoje hasło powyżej i potwierdź rejestrację przez naciśnięcie przycisku na urządzeniu USB.",
|
||||
"yubi_otp": "Uwierzytelnianie Yubico OTP",
|
||||
"authenticators": "Uwierzytelniacze",
|
||||
"error_code": "Kod błędu",
|
||||
"init_webauthn": "Inicjalizacja, proszę czekać...",
|
||||
"reload_retry": "- (przeładuj przeglądarkę, jeśli błąd nadal występuje)",
|
||||
"start_webauthn_validation": "Rozpocznij walidację",
|
||||
"tfa_token_invalid": "Token TFA nieprawidłowy",
|
||||
"u2f_deprecated": "Wygląda na to, że Twój klucz został zarejestrowany przy użyciu przestarzałej metody U2F. Dezaktywujemy dla Ciebie uwierzytelnianie dwuskładnikowe i usuniemy Twój klucz.",
|
||||
"u2f_deprecated_important": "Zarejestruj swój klucz w panelu administracyjnym za pomocą nowej metody WebAuthn."
|
||||
},
|
||||
"user": {
|
||||
"action": "Działanie",
|
||||
@@ -371,7 +855,7 @@
|
||||
"edit": "Edytuj",
|
||||
"encryption": "Szyfrowanie",
|
||||
"excludes": "Wyłączenia",
|
||||
"force_pw_update": "<b>Musisz</b> zmienić hasło, aby używać webmaila.",
|
||||
"force_pw_update": "<b>Musisz</b> ustawić nowe hasło, aby mieć dostęp do usług groupware.",
|
||||
"hour": "Godzina",
|
||||
"hourly": "Co godzinę",
|
||||
"hours": "Godziny",
|
||||
@@ -379,7 +863,7 @@
|
||||
"interval": "Zakres",
|
||||
"is_catch_all": "Funkcja catch-all dla domen/y",
|
||||
"last_run": "Ostatnie uruchomienie",
|
||||
"mailbox_details": " Szczegóły skrzynki",
|
||||
"mailbox_details": "Szczegóły",
|
||||
"messages": "wiadomości",
|
||||
"never": "Nigdy",
|
||||
"new_password": "Nowe hasło",
|
||||
@@ -391,17 +875,17 @@
|
||||
"remove": "Usuń",
|
||||
"save_changes": "Zapisz zmiany",
|
||||
"shared_aliases": "Aliasy współdzielone",
|
||||
"shared_aliases_desc": "Na aliasy współdzielone nie wpływają filtry spamu i ustawienia TLS.",
|
||||
"show_sieve_filters": "Twój filtr sieve",
|
||||
"sogo_profile_reset": "Usuń profil SOGo (webmail)",
|
||||
"sogo_profile_reset_help": "To usunie ustawienia SOGo <b>bezpowrotnie</b>.",
|
||||
"sogo_profile_reset_now": "Usuń profil teraz",
|
||||
"spam_aliases": "Tymczasowy alias email",
|
||||
"shared_aliases_desc": "Współdzielone aliasy nie są objęte ustawieniami specyficznymi dla użytkownika, takimi jak filtr antyspamowy czy polityka szyfrowania.\nOdpowiadające im filtry antyspamowe mogą być tworzone wyłącznie przez administratora — jako polityki obowiązujące dla całej domeny.",
|
||||
"show_sieve_filters": "Pokaż filtr sieve aktywnego użytkownika",
|
||||
"sogo_profile_reset": "Zresetuj profil SOGo",
|
||||
"sogo_profile_reset_help": "Spowoduje to usunięcie profilu użytkownika SOGo oraz bezpowrotne <b>usunięcie wszystkich danych kontaktów i kalendarza.</b>",
|
||||
"sogo_profile_reset_now": "Zresetuj profil teraz",
|
||||
"spam_aliases": "Tymczasowe aliasy email",
|
||||
"spamfilter": "Filtr spamu",
|
||||
"spamfilter_behavior": "Rating",
|
||||
"spamfilter_behavior": "Ocena",
|
||||
"spamfilter_bl": "Czarna lista",
|
||||
"spamfilter_bl_desc": "Adresy email z czarnej listy <b>zawsze</b> klasyfikuj jako spam i odrzucaj. Można użyć wildcards.",
|
||||
"spamfilter_default_score": "Wartości domyślne:",
|
||||
"spamfilter_bl_desc": "Adresy e-mail znajdujące się na liście zablokowanych (denylist) są <b>zawsze</b>klasyfikowane jako spam i odrzucane.\nOdrzucone wiadomości <b>nie są</b>kopiowane do kwarantanny.\nMożna używać symboli wieloznacznych (wildcardów).\nFiltr jest stosowany wyłącznie do bezpośrednich aliasów (aliasów kierujących do jednej skrzynki pocztowej), z wyłączeniem aliasów typu „catch-all” oraz samej skrzynki.",
|
||||
"spamfilter_default_score": "Wartości domyślne",
|
||||
"spamfilter_green": "Zielony: ta wiadomość nie jest spamem",
|
||||
"spamfilter_hint": "Pierwsza wartość oznacza \"niską punktację spam\", druga wartość oznacza \"wysoką punktację spam\".",
|
||||
"spamfilter_red": "Czerwony: ta wiadomość jest spamem i zostanie odrzucona przez serwer",
|
||||
@@ -412,13 +896,13 @@
|
||||
"spamfilter_table_remove": "Usuń",
|
||||
"spamfilter_table_rule": "Zasada",
|
||||
"spamfilter_wl": "Biała lista",
|
||||
"spamfilter_wl_desc": "Adresy email z białej listy <b>nigdy</b> nie klasyfikuj jako spam. Można użyć wildcards.",
|
||||
"spamfilter_wl_desc": "Adresy e-mail znajdujące się na liście dozwolonych (allowlist) są zaprogramowane tak, aby <b> nigdy nie </b> były klasyfikowane jako spam.\nMożna używać symboli wieloznacznych (wildcardów).\nFiltr jest stosowany wyłącznie do bezpośrednich aliasów (aliasów wskazujących na jedną skrzynkę pocztową), z wyłączeniem aliasów typu „catch-all” oraz samej skrzynki pocztowej",
|
||||
"spamfilter_yellow": "Żółty: ta wiadomość może być spamem, zostanie oznaczona jako spam i przeniesiona do folderu spam",
|
||||
"sync_jobs": "Polecenie synchronizacji",
|
||||
"sync_jobs": "Zadania synchronizacji",
|
||||
"tag_handling": "Ustaw obsługę znaczników pocztowych",
|
||||
"tag_help_example": "Przykład adresu email z etykietą: ja<b>+Facebook</b>@example.org",
|
||||
"tag_help_explain": "W podfolderze: tworzy nowy podfolder z nazwą taką jak etykieta, który zostanie umieszczony pod Skrzynką odbiorczą (\"Skrzynka odbiorcza/Facebook\").<br>\r\nW temacie: nazwy etykiet zostaną dodane na początku tematów wiadomości, np.: \"[Facebook] Moje wiadomości\".",
|
||||
"tag_in_none": "Nic nie robić",
|
||||
"tag_in_none": "Nie wykonuj żadnej akcji",
|
||||
"tag_in_subfolder": "W podfolderze",
|
||||
"tag_in_subject": "W temacie",
|
||||
"tls_enforce_in": "Uruchom TLS przychodzące",
|
||||
@@ -429,6 +913,176 @@
|
||||
"username": "Nazwa użytkownika",
|
||||
"week": "Tydzień",
|
||||
"weekly": "Co tydzień",
|
||||
"weeks": "Tygodnie"
|
||||
"weeks": "Tygodnie",
|
||||
"q_add_header": "Spam",
|
||||
"advanced_settings": "Ustawienia zaawansowane",
|
||||
"app_hint": "Hasła aplikacji są alternatywnymi hasłami dla logowania IMAP, SMTP, CalDAV, CardDAV i EAS. Nazwa użytkownika pozostaje niezmieniona. Webmail SOGo nie jest dostępny za pośrednictwem haseł aplikacji.",
|
||||
"allowed_protocols": "Dozwolone protokoły",
|
||||
"app_name": "Nazwa aplikacji",
|
||||
"app_passwds": "Hasła do aplikacji",
|
||||
"apple_connection_profile": "Profil połączenia Apple",
|
||||
"apple_connection_profile_complete": "Ten profil połączenia obejmuje parametry IMAP i SMTP, a także ścieżki CalDAV (kalendarze) i CardDAV (kontakty) dla urządzenia Apple.",
|
||||
"apple_connection_profile_mailonly": "Ten profil połączenia zawiera parametry konfiguracji IMAP i SMTP dla urządzenia Apple.",
|
||||
"apple_connection_profile_with_app_password": "Nowe hasło aplikacji jest generowane i dodawane do profilu, dzięki czemu nie trzeba wprowadzać hasła podczas konfigurowania urządzenia. Proszę nie udostępniaj tego pliku, ponieważ zapewnia on pełny dostęp do skrzynki pocztowej.",
|
||||
"attribute": "Atrybut",
|
||||
"authentication": "Uwierzytelnianie",
|
||||
"change_password_hint_app_passwords": "Twoje konto ma %d hasła aplikacji, które nie zostaną zmienione. Aby nimi zarządzać, przejdź do zakładki Hasła aplikacji.",
|
||||
"clear_recent_successful_connections": "Wyczyść udane połączenia",
|
||||
"create_app_passwd": "Stwórz hasło do aplikacji",
|
||||
"created_on": "Stworzony na",
|
||||
"delete_ays": "Proszę o potwierdzenie procesu usuwania.",
|
||||
"direct_protocol_access": "Ten użytkownik skrzynki pocztowej ma <b>bezpośredni, zewnętrzny dostęp</b> do następujących protokołów i aplikacji. To ustawienie jest kontrolowane przez administratora. Można tworzyć hasła aplikacji, aby przyznać dostęp do poszczególnych protokołów i aplikacji.Przycisk „Webmail” umożliwia jednokrotne logowanie (SSO) do SOGo i jest zawsze dostępny.",
|
||||
"email": "Email",
|
||||
"email_and_dav": "E-maile, kalendarze i kontakty",
|
||||
"empty": "Brak wyników",
|
||||
"expire_in": "wygasa w",
|
||||
"fido2_webauthn": "FIDO2/WebAuthn",
|
||||
"from": "od",
|
||||
"generate": "generuj",
|
||||
"last_mail_login": "Ostatni login na skrzynkę pocztową",
|
||||
"last_pw_change": "Ostatnia zmiana hasła",
|
||||
"last_ui_login": "Ostatni login UI",
|
||||
"loading": "Ładowanie...",
|
||||
"login_history": "Historia logowania",
|
||||
"mailbox": "Skrzynka pocztowa",
|
||||
"mailbox_general": "Ogólne ustawienia skrzynki",
|
||||
"mailbox_settings": "Ustawienia",
|
||||
"month": "miesiąc",
|
||||
"months": "miesiące",
|
||||
"no_last_login": "Brak ostatnich danych logowania do interfejsu użytkownika",
|
||||
"open_logs": "Otwórz logi użytkownika",
|
||||
"open_webmail_sso": "Webmail",
|
||||
"overview": "Przegląd",
|
||||
"password": "Hasło",
|
||||
"password_repeat": "Hasło (powtórz)",
|
||||
"password_reset_info": "Jeśli nie ma wiadomości e-mail do odzyskiwania hasła, ta funkcja nie może być używana.",
|
||||
"protocols": "Protokoły",
|
||||
"pushover_evaluate_x_prio": "Eskaluj wiadomości o wysokim priorytecie [<code>X-Priority: 1</code>]",
|
||||
"pushover_info": "Ustawienia powiadomień push będą stosowane do wszystkich czystych (niebędących spamem) wiadomości dostarczonych do <b>%s</b>, w tym aliasów (współdzielonych, niewspółdzielonych i oznaczonych).",
|
||||
"pushover_only_x_prio": "Uwzględniaj tylko wiadomości o wysokim priorytecie [<code>X-Priority: 1</code>]",
|
||||
"pushover_sender_array": "Uwzględnij następujące adresy e-mail nadawców <small>(oddzielone przecinkami)</small>",
|
||||
"pushover_sender_regex": "Dopasuj nadawców według następującego regexu",
|
||||
"pushover_text": "Tekst powiadomienia",
|
||||
"pushover_title": "Tytuł powiadomienia",
|
||||
"pushover_sound": "Dźwięk powiadomienia",
|
||||
"pushover_vars": "Jeśli nie zdefiniowano filtra nadawcy, wszystkie wiadomości będą brane pod uwagę.<br>Filtry regex oraz dokładne sprawdzanie nadawców można definiować indywidualnie – są one przetwarzane kolejno i nie zależą od siebie.</br>Dostępne zmienne dla treści i tytułu (prosimy pamiętać o zasadach ochrony danych osobowych).",
|
||||
"pushover_verify": "Zweryfikuj dane logowania",
|
||||
"pw_recovery_email": "E-mail do odzyskiwania hasła",
|
||||
"q_all": "Wszystkie kategorie",
|
||||
"q_reject": "Odrzucono",
|
||||
"quarantine_category": "Kategoria powiadomień o kwarantannie",
|
||||
"quarantine_category_info": "Kategoria powiadomień „Odrzucone” obejmuje wiadomości, które zostały odrzucone, natomiast „Folder spam” powiadamia użytkownika o wiadomościach umieszczonych w folderze spam.",
|
||||
"quarantine_notification_info": "Po wysłaniu powiadomienia elementy zostaną oznaczone jako „powiadomione” i żadne kolejne powiadomienia nie zostaną wysłane dla danego elementu.",
|
||||
"recent_successful_connections": "Zarejestrowano udane połączenia",
|
||||
"running": "Uruchomiony",
|
||||
"save": "Zapisz zmiany",
|
||||
"sender_acl_disabled": "<span class=\"badge fs-6 bg-danger\">Sprawdzenie nadawcy jest wyłączone</span>",
|
||||
"spam_score_reset": "Przywróć domyślne ustawienia serwera",
|
||||
"status": "Status",
|
||||
"syncjob_check_log": "Sprawdź log",
|
||||
"syncjob_last_run_result": "Wynik ostatniego uruchomienia",
|
||||
"syncjob_EX_OK": "Sukces",
|
||||
"syncjob_EXIT_CONNECTION_FAILURE": "Problem z połączeniem",
|
||||
"syncjob_EXIT_TLS_FAILURE": "Problem z szyfrowanym połączeniem",
|
||||
"syncjob_EXIT_AUTHENTICATION_FAILURE": "Problem uwierzytelniania",
|
||||
"syncjob_EXIT_OVERQUOTA": "Docelowa skrzynka pocztowa przekroczyła limit pojemności",
|
||||
"syncjob_EXIT_CONNECTION_FAILURE_HOST1": "Nie można połączyć się ze zdalnym serwerem",
|
||||
"syncjob_EXIT_AUTHENTICATION_FAILURE_USER1": "Niewłaściwa nazwa użytkownika lub hasło",
|
||||
"text": "Tekst",
|
||||
"tfa_info": "Uwierzytelnianie dwuskładnikowe pomaga chronić Twoje konto.\nJeśli je włączysz, będziesz potrzebować haseł aplikacji, aby logować się do programów lub usług, które nie obsługują uwierzytelniania dwuskładnikowego (np. klientów poczty).",
|
||||
"title": "Tytuł",
|
||||
"value": "Wartość",
|
||||
"verify": "Zweryfikuj",
|
||||
"waiting": "Oczekuje",
|
||||
"with_app_password": "z hasłem aplikacji",
|
||||
"year": "rok",
|
||||
"years": "lata"
|
||||
},
|
||||
"warning": {
|
||||
"session_ua": "Nieprawidłowy token formularza: Błąd walidacji User-Agent",
|
||||
"cannot_delete_self": "Nie można usunąć zalogowanego użytkownika",
|
||||
"domain_added_sogo_failed": "Dodano domenę, ale nie udało się ponownie uruchomić SOGo, sprawdź logi serwera.",
|
||||
"dovecot_restart_failed": "Nie udało się ponownie uruchomić Dovecota, sprawdź logi",
|
||||
"fuzzy_learn_error": "Błąd uczenia fuzzy hash: %s",
|
||||
"hash_not_found": "Hash nie został odnaleziony lub został już usunięty",
|
||||
"ip_invalid": "Pominięto nieprawidłowe IP: %s",
|
||||
"is_not_primary_alias": "Pominięto alias niebędący głównym: %s",
|
||||
"no_active_admin": "Nie można dezaktywować ostatniego aktywnego administratora",
|
||||
"quota_exceeded_scope": "Przekroczono limit pojemności domeny: w tym zakresie domeny można tworzyć tylko skrzynki o nieograniczonej pojemności.",
|
||||
"session_token": "Nieprawidłowy token formularza: niedopasowanie tokenów"
|
||||
},
|
||||
"datatables": {
|
||||
"collapse_all": "Zwiń wszystko",
|
||||
"decimal": ".",
|
||||
"emptyTable": "Brak danych w tabeli",
|
||||
"expand_all": "Rozszerz wszystko",
|
||||
"info": "Wyświetlanie od START do END z TOTAL wpisów.",
|
||||
"infoEmpty": "Wyświetlanie od 0 do 0 z 0 wpisów",
|
||||
"infoFiltered": "(filtrowane z _MAX_ suma wpisów)",
|
||||
"thousands": ",",
|
||||
"lengthMenu": "Pokaż wpisy _MENU_",
|
||||
"loadingRecords": "Ładowanie...",
|
||||
"processing": "Proszę czekać...",
|
||||
"search": "Szukaj:",
|
||||
"zeroRecords": "Nie znaleziono pasujących rekordów",
|
||||
"paginate": {
|
||||
"first": "Pierwszy",
|
||||
"last": "Ostatni",
|
||||
"next": "Następny",
|
||||
"previous": "Poprzedni"
|
||||
},
|
||||
"aria": {
|
||||
"sortAscending": "Aktywuj, aby posortować kolumnę rosnąco",
|
||||
"sortDescending": "Aktywuj, aby posortować kolumnę malejąco"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"architecture": "Architektura",
|
||||
"chart_this_server": "Wykres (ten serwer)",
|
||||
"containers_info": "Informacje o kontenerze",
|
||||
"container_running": "uruchomiony",
|
||||
"container_disabled": "Kontener zatrzymany lub wyłączony",
|
||||
"container_stopped": "Zatrzymany",
|
||||
"cores": "rdzenie",
|
||||
"current_time": "Czas systemowy",
|
||||
"disk_usage": "Użycie dysku",
|
||||
"docs": "Dokumentacja",
|
||||
"error_show_ip": "Nie można ustalić publicznych adresów IP.",
|
||||
"external_logs": "Logi zewnętrzne",
|
||||
"history_all_servers": "Historia (wszystkie serwery)",
|
||||
"in_memory_logs": "Logi w pamięci",
|
||||
"last_modified": "Ostatnia modyfikacja",
|
||||
"log_info": "<p>mailcow <b>logi w pamięci</b> są gromadzone na listach Redis i przycinane do wartości <code>LOG_LINES</code> (%d) co minutę, aby ograniczyć nadmierne obciążenie systemu.</p> <p>Logi w pamięci nie są przeznaczone do trwałego przechowywania. Wszystkie aplikacje, które zapisują logi w pamięci, wysyłają je również do daemon Dockera, a więc do domyślnego sterownika logowania.</p> <p>Ten typ logów należy wykorzystywać do <b>debugowania drobnych problemów z kontenerami</b>.</p> <p><b>Logi zewnętrzne</b> są zbierane za pośrednictwem API danej aplikacji.</p> <p><b>Logi statyczne</b> to głównie dzienniki aktywności, które nie są zapisywane przez Dockerd, ale powinny być trwałe (z wyjątkiem logów API).</p>",
|
||||
"login_time": "Czas",
|
||||
"logs": "Logi",
|
||||
"memory": "Pamięć",
|
||||
"online_users": "Użytkownik online",
|
||||
"restart_container": "Restart",
|
||||
"service": "Usługa",
|
||||
"show_ip": "Pokaż publiczne IP",
|
||||
"size": "Rozmiar",
|
||||
"started_at": "Zaczęło się od",
|
||||
"started_on": "Zaczęło się od",
|
||||
"static_logs": "Logi statyczne",
|
||||
"success": "Sukces",
|
||||
"system_containers": "System i kontenery",
|
||||
"timezone": "Strefa czasowa",
|
||||
"uptime": "Czas pracy",
|
||||
"update_available": "Dostępna jest aktualizacja",
|
||||
"no_update_available": "System jest w najnowszej wersji",
|
||||
"update_failed": "Nie można było sprawdzić aktualizacji",
|
||||
"username": "Nazwa użytkownika",
|
||||
"wip": "Obecnie praca w toku"
|
||||
},
|
||||
"diagnostics": {
|
||||
"cname_from_a": "Wartość pochodzi z rekordu A/AAAA. Obsługiwane, o ile rekord wskazuje na prawidłowy zasób.",
|
||||
"dns_records": "Rekordy DNS",
|
||||
"dns_records_24hours": "Pamiętaj, że zmiany wprowadzone w DNS mogą zająć nawet do 24 godzin, zanim ich aktualny stan zostanie poprawnie odzwierciedlony na tej stronie.\nTa sekcja ma na celu ułatwienie Ci konfiguracji rekordów DNS oraz sprawdzenie, czy wszystkie rekordy zostały prawidłowo zapisane w DNS.",
|
||||
"dns_records_data": "Poprawne dane",
|
||||
"dns_records_docs": "Proszę skonsultuj również <a target=\"_blank\" href=\"https://docs.mailcow.email/getstarted/prerequisite-dns\">dokumnetację</a>",
|
||||
"dns_records_name": "Nazwa",
|
||||
"dns_records_status": "Aktualny stan",
|
||||
"dns_records_type": "Typ",
|
||||
"optional": "Ten rekord jest opcjonalny."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -508,7 +508,7 @@
|
||||
"quota_not_0_not_numeric": "A cota deve ser numérica e >= 0",
|
||||
"recipient_map_entry_exists": "Existe uma entrada de mapa de destinatários “%s”",
|
||||
"recovery_email_failed": "Não foi possível enviar um email de recuperação. Por favor, contacte seu administrador.",
|
||||
"valkey_error": "Erro do Valkey: %s",
|
||||
"redis_error": "Erro do Redis: %s",
|
||||
"relayhost_invalid": "A entrada de mapa %s é inválida",
|
||||
"release_send_failed": "A mensagem não pôde ser liberada: %s",
|
||||
"reset_f2b_regex": "O filtro Regex não pôde ser redefinido a tempo. Tente novamente ou aguarde mais alguns segundos e recarregue o site.",
|
||||
@@ -600,7 +600,7 @@
|
||||
"history_all_servers": "Histórico (todos os servidores)",
|
||||
"in_memory_logs": "Registros na memória",
|
||||
"last_modified": "Última modificação",
|
||||
"log_info": "<p>Os <b>registros na memória do</b> mailcow são coletados em listas do Valkey e reduzidos para LOG_LINES (%d) a cada minuto para reduzir o martelamento.\r\n Os <br>registros na memória não devem ser persistentes. Todos os aplicativos que fazem login na memória também fazem login no daemon do Docker e, portanto, no driver de registro padrão.\r\n </p><br>O tipo de registro na memória deve ser usado para depurar pequenos problemas com contêineres.\r\n <p>Os <b>registros externos</b> são coletados por meio da API do aplicativo em questão.</p>\r\n <p>Os <b>registros estáticos</b> são principalmente registros de atividades, que não são registrados no Dockerd, mas ainda precisam ser persistentes (exceto os registros da API).</p>",
|
||||
"log_info": "<p>Os <b>registros na memória do</b> mailcow são coletados em listas do Redis e reduzidos para LOG_LINES (%d) a cada minuto para reduzir o martelamento.\r\n Os <br>registros na memória não devem ser persistentes. Todos os aplicativos que fazem login na memória também fazem login no daemon do Docker e, portanto, no driver de registro padrão.\r\n </p><br>O tipo de registro na memória deve ser usado para depurar pequenos problemas com contêineres.\r\n <p>Os <b>registros externos</b> são coletados por meio da API do aplicativo em questão.</p>\r\n <p>Os <b>registros estáticos</b> são principalmente registros de atividades, que não são registrados no Dockerd, mas ainda precisam ser persistentes (exceto os registros da API).</p>",
|
||||
"login_time": "Hora",
|
||||
"logs": "Registros",
|
||||
"memory": "Memória",
|
||||
|
||||
@@ -429,7 +429,7 @@
|
||||
"pushover_token": "Jetonul pushover are formatul greșit",
|
||||
"quota_not_0_not_numeric": "Cota trebuie să fie numerică și >= 0",
|
||||
"recipient_map_entry_exists": "O intrare a hărții destinatarului \"%s\" există",
|
||||
"valkey_error": "Eroare Valkey: %s",
|
||||
"redis_error": "Eroare Redis: %s",
|
||||
"relayhost_invalid": "Intrarea hărții %s este invalidă",
|
||||
"release_send_failed": "Mesajul nu a putut fi eliberat: %s",
|
||||
"reset_f2b_regex": "Filtrul regex nu a putut fi resetat la timp, încercați din nou sau așteptați câteva secunde și reîncărcați pagina.",
|
||||
@@ -482,7 +482,7 @@
|
||||
"history_all_servers": "Istoric (toate serverele)",
|
||||
"in_memory_logs": "Jurnale din memorie",
|
||||
"last_modified": "Ultima modificare",
|
||||
"log_info": "<p><b>jurnalele din memorie</b> pentru mailcow sunt colectate în listele Valkey și trimise la LOG_LINES (%d) în fiecare minut pentru a reduce ciocnirea.\n <br>Jurnalele din memorie nu sunt menite a fi persistente. Toate aplicațiile care înregistrează jurnale în memorie, înregistrează de asemenea jurnale în daemonul Docker și, prin urmare, în driverul de jurnale implicit.\n <br>Tipul de jurnal din memorie trebuie utilizat pentru depanarea problemelor minore cu containerele.</p>\n <p><b>Jurnalele externe</b> sunt colectate prin API-ul aplicației respective.</p>\n <p><b>Jurnalele statice</b> sunt, în majoritate, jurnale de activitate care nu sunt înregistrate în Docker, dar trebuie să fie persistente (cu excepția jurnalelor API).</p>",
|
||||
"log_info": "<p><b>jurnalele din memorie</b> pentru mailcow sunt colectate în listele Redis și trimise la LOG_LINES (%d) în fiecare minut pentru a reduce ciocnirea.\n <br>Jurnalele din memorie nu sunt menite a fi persistente. Toate aplicațiile care înregistrează jurnale în memorie, înregistrează de asemenea jurnale în daemonul Docker și, prin urmare, în driverul de jurnale implicit.\n <br>Tipul de jurnal din memorie trebuie utilizat pentru depanarea problemelor minore cu containerele.</p>\n <p><b>Jurnalele externe</b> sunt colectate prin API-ul aplicației respective.</p>\n <p><b>Jurnalele statice</b> sunt, în majoritate, jurnale de activitate care nu sunt înregistrate în Docker, dar trebuie să fie persistente (cu excepția jurnalelor API).</p>",
|
||||
"login_time": "Moment",
|
||||
"logs": "Jurnale",
|
||||
"online_users": "Utilizatori online",
|
||||
|
||||
@@ -506,7 +506,7 @@
|
||||
"quota_not_0_not_numeric": "Размер квоты должен быть больше или равен нулю",
|
||||
"recipient_map_entry_exists": "Правило перезаписи \"%s\" уже существует",
|
||||
"recovery_email_failed": "Не удалось отправить письмо для восстановления. Пожалуйста, свяжитесь с вашим администратором.",
|
||||
"valkey_error": "Ошибка в Valkey: %s",
|
||||
"redis_error": "Ошибка в Redis: %s",
|
||||
"relayhost_invalid": "Недопустимое правило %s",
|
||||
"release_send_failed": "Сообщение не может быть восстановлено: %s",
|
||||
"reset_f2b_regex": "Сброс фильтров не был выполнен за отведённый промежуток времени, пожалуйста, повторите попытку или подождите еще несколько секунд и перезагрузите веб страницу.",
|
||||
@@ -594,7 +594,7 @@
|
||||
"history_all_servers": "История (все серверы)",
|
||||
"in_memory_logs": "Журналы контейнеров",
|
||||
"last_modified": "Последние изменения",
|
||||
"log_info": "<p><b>Журналы контейнеров</b> mailcow сохраняются в Valkey, и раз в минуту строки журнала за пределами <code>LOG_LINES (%d)</code> удаляются, чтобы уменьшить нагрузку на сервер.\r\n <br>Сами журналы контейнеров не сохраняются после перезагрузки контейнера. Все контейнеры дополнительно пишут логи в службу Docker, и, следовательно, используют драйвер логирования по умолчанию. Журналы контейнеров предусмотрены только для отладки мелких проблем. Для других задач, пожалуйста, настройте драйвер логирования Docker самостоятельно.</p>\r\n <p><b>Внешние журналы</b> собираются через API приложений.</p>\r\n <p><b>Статические журналы</b> – это, в основном, журналы активности, которые не записываются в Dockerd, но все равно должны быть постоянными (за исключением журналов API).</p>",
|
||||
"log_info": "<p><b>Журналы контейнеров</b> mailcow сохраняются в Redis, и раз в минуту строки журнала за пределами <code>LOG_LINES (%d)</code> удаляются, чтобы уменьшить нагрузку на сервер.\r\n <br>Сами журналы контейнеров не сохраняются после перезагрузки контейнера. Все контейнеры дополнительно пишут логи в службу Docker, и, следовательно, используют драйвер логирования по умолчанию. Журналы контейнеров предусмотрены только для отладки мелких проблем. Для других задач, пожалуйста, настройте драйвер логирования Docker самостоятельно.</p>\r\n <p><b>Внешние журналы</b> собираются через API приложений.</p>\r\n <p><b>Статические журналы</b> – это, в основном, журналы активности, которые не записываются в Dockerd, но все равно должны быть постоянными (за исключением журналов API).</p>",
|
||||
"login_time": "Время входа",
|
||||
"logs": "Журналы",
|
||||
"memory": "Память",
|
||||
|
||||
@@ -505,7 +505,7 @@
|
||||
"pushover_token": "Pushover žeton ni v pravilni obliki",
|
||||
"quota_not_0_not_numeric": "Kvota mora biti numerična in >= 0",
|
||||
"recipient_map_entry_exists": "Preslikava prejemnika \"%s\" že obstaja",
|
||||
"valkey_error": "Napaka Valkey: %s",
|
||||
"redis_error": "Napaka Redis: %s",
|
||||
"relayhost_invalid": "Vnos preslikave %s ni pravilen",
|
||||
"resource_invalid": "Ime vira %s je neveljavno",
|
||||
"rl_timeframe": "Časovni okvir omejitve je nepravilen",
|
||||
@@ -589,7 +589,7 @@
|
||||
"update_failed": "Ni mogoče preveriti za posodobitve",
|
||||
"username": "Uporabniško ime",
|
||||
"wip": "Trenutno delo v teku",
|
||||
"log_info": "<p>Dnevniki v pomnilniku mailcow se zbirajo na seznamih Valkey in vsako minuto skrajšajo na LOG_LINES (%d), da se zmanjša preobremenitev.\n <br>Dnevniki v pomnilniku niso namenjeni trajnemu beleženju. Vse aplikacije, ki se beležijo v pomnilnik, se beležijo tudi v Dockerjev demon in s tem v privzeti gonilnik beleženja.</p>\n </p>Vrsta dnevnika v pomnilniku se mora uporabljati za odpravljanje manjših težav s kontejnerji.</p>\n <p><b>Zunanji dnevniki</b> se zbirajo prek API-ja dane aplikacije.</p>\n <p><b>Statični dnevniki</b> so večinoma dnevniki dejavnosti, ki se ne beležijo v Dockerd, vendar morajo biti še vedno trajni (razen dnevnikov API-ja).</p>",
|
||||
"log_info": "<p>Dnevniki v pomnilniku mailcow se zbirajo na seznamih Redis in vsako minuto skrajšajo na LOG_LINES (%d), da se zmanjša preobremenitev.\n <br>Dnevniki v pomnilniku niso namenjeni trajnemu beleženju. Vse aplikacije, ki se beležijo v pomnilnik, se beležijo tudi v Dockerjev demon in s tem v privzeti gonilnik beleženja.</p>\n </p>Vrsta dnevnika v pomnilniku se mora uporabljati za odpravljanje manjših težav s kontejnerji.</p>\n <p><b>Zunanji dnevniki</b> se zbirajo prek API-ja dane aplikacije.</p>\n <p><b>Statični dnevniki</b> so večinoma dnevniki dejavnosti, ki se ne beležijo v Dockerd, vendar morajo biti še vedno trajni (razen dnevnikov API-ja).</p>",
|
||||
"login_time": "Čas",
|
||||
"logs": "Dnevniki",
|
||||
"memory": "Spomin",
|
||||
|
||||
@@ -429,7 +429,7 @@
|
||||
"pushover_token": "Pushover token má chybný formát",
|
||||
"quota_not_0_not_numeric": "Kvóty musia byť numerické a >= 0",
|
||||
"recipient_map_entry_exists": "Táto mapa \"%s\" už existuje",
|
||||
"valkey_error": "Valkey chyba: %s",
|
||||
"redis_error": "Redis chyba: %s",
|
||||
"relayhost_invalid": "Položka %s je neplatná",
|
||||
"release_send_failed": "Správa nemohla byť uvoľnená: %s",
|
||||
"reset_f2b_regex": "Regex filter sa nepodarilo resetovať, skúste to znovu alebo počkajte pár sekúnd a obnovte stránku.",
|
||||
@@ -500,7 +500,7 @@
|
||||
"history_all_servers": "História (všetky servery)",
|
||||
"in_memory_logs": "Logy uložené v pamäti",
|
||||
"last_modified": "Naposledy upravené",
|
||||
"log_info": "<b>Logy v pamäti</b> sú zbierané do Valkey listu s max. limitom LOG_LINES (%d) riadkov každú minútu, čo bráni nadmernej záťaži servera.\r\n <br>Logy v pamäti nemajú trvalý charakter. Všetky aplikácie ktoré vedú logy v pamäti, tiež logujú do Docker démona a súčasne do nastaveného logging drivera.\r\n <br>Logy v pamäti sa môžu použiť na ladenie menších problémov s kontajnermi.</p>\r\n <p><b>Externé logy</b> sú zbierané cez API danej aplikácie.</p>\r\n <p><b>Statické logy</b> sú väčšinou aktivity, ktoré nie sú logované do Docker démona, ale musia byť trvalo zaznamenané (s výnimkou API záznamov).</p>",
|
||||
"log_info": "<b>Logy v pamäti</b> sú zbierané do Redis listu s max. limitom LOG_LINES (%d) riadkov každú minútu, čo bráni nadmernej záťaži servera.\r\n <br>Logy v pamäti nemajú trvalý charakter. Všetky aplikácie ktoré vedú logy v pamäti, tiež logujú do Docker démona a súčasne do nastaveného logging drivera.\r\n <br>Logy v pamäti sa môžu použiť na ladenie menších problémov s kontajnermi.</p>\r\n <p><b>Externé logy</b> sú zbierané cez API danej aplikácie.</p>\r\n <p><b>Statické logy</b> sú väčšinou aktivity, ktoré nie sú logované do Docker démona, ale musia byť trvalo zaznamenané (s výnimkou API záznamov).</p>",
|
||||
"login_time": "Čas",
|
||||
"logs": "Logy",
|
||||
"online_users": "Používateľov online",
|
||||
|
||||
@@ -411,7 +411,7 @@
|
||||
"pushover_token": "Pushover nyckeln har ett felaktigt format",
|
||||
"quota_not_0_not_numeric": "Lagringsutrymmet ska vara numeriskt och större än noll (>=0)",
|
||||
"recipient_map_entry_exists": "Adress omskrivningen \"%s\" existerar redan",
|
||||
"valkey_error": "Valkey fel: %s",
|
||||
"redis_error": "Redis fel: %s",
|
||||
"relayhost_invalid": "Posten %s är ogiltig",
|
||||
"release_send_failed": "Meddelandet kunde inte skickas: %s",
|
||||
"reset_f2b_regex": "Regex-filtret kunde inte återställas inom en rimlig tid, försök igen eller ladda om sidan.",
|
||||
@@ -453,7 +453,7 @@
|
||||
"external_logs": "Externa loggar",
|
||||
"history_all_servers": "Historik (alla servrar)",
|
||||
"in_memory_logs": "Loggar sparade i minnet",
|
||||
"log_info": "<p>mailcow <b>loggar sparade i minnet</b> samlas in i Valkey-listor och trimmas till LOG_LINES (%d) varje minut för att minska lasten.\r\n <br>Loggar sparade i minnet är inte tänkta att vara beständiga. Alla applikationer som loggar i minnet loggar också till Docker-demonen och därefter till standardrutinen för loggning.\r\n <br>Loggar sparade i minnet bör användas för felsökning av mindre problem med olika behållare.</p>\r\n <p><b>Externa loggar</b> samlas in via ett API på den givna applikationen.</p>\r\n <p><b>Statiska loggar</b> är mestadels aktivitetsloggar som inte är loggas i Docker, men som fortfarande måste vara beständiga (utom API-loggar).</p>",
|
||||
"log_info": "<p>mailcow <b>loggar sparade i minnet</b> samlas in i Redis-listor och trimmas till LOG_LINES (%d) varje minut för att minska lasten.\r\n <br>Loggar sparade i minnet är inte tänkta att vara beständiga. Alla applikationer som loggar i minnet loggar också till Docker-demonen och därefter till standardrutinen för loggning.\r\n <br>Loggar sparade i minnet bör användas för felsökning av mindre problem med olika behållare.</p>\r\n <p><b>Externa loggar</b> samlas in via ett API på den givna applikationen.</p>\r\n <p><b>Statiska loggar</b> är mestadels aktivitetsloggar som inte är loggas i Docker, men som fortfarande måste vara beständiga (utom API-loggar).</p>",
|
||||
"logs": "Loggar",
|
||||
"restart_container": "Omstart",
|
||||
"online_users": "Användare online",
|
||||
|
||||
@@ -635,7 +635,7 @@
|
||||
"pushover_key": "Pushover anahtarı yanlış formatta",
|
||||
"pushover_token": "Pushover token yanlış formatta",
|
||||
"recipient_map_entry_exists": "Alıcı haritası girişi \\\"%s\\\" var",
|
||||
"valkey_error": "Valkey hatası: %s",
|
||||
"redis_error": "Redis hatası: %s",
|
||||
"relayhost_invalid": "%s harita girişi geçersiz",
|
||||
"template_exists": "%s isimli şablon zaten mevcut",
|
||||
"template_id_invalid": "Şablon kimliği %s geçersiz",
|
||||
@@ -675,7 +675,7 @@
|
||||
"debug": {
|
||||
"container_disabled": "Container durduruldu veya devre dışı bırakıldı",
|
||||
"last_modified": "Son değişiklik",
|
||||
"log_info": "<p>mailcow <b>bellek içi günlükler</b>, Valkey listelerinde toplanır ve çekiçlemeyi azaltmak için her dakika LOG_LINES (%d) olacak şekilde kırpılır.\\r\\n <br>Bellek içi günlükler ısrarcı. Bellekte oturum açan tüm uygulamalar, ayrıca Docker arka plan programında ve dolayısıyla varsayılan günlük sürücüsünde oturum açar.\\r\\n <br>Bellek içi günlük türü, kapsayıcılarla ilgili küçük sorunları ayıklamak için kullanılmalıdır.</p>\\r\\n <p><b>Harici günlükler</b>, verilen uygulamanın API'si aracılığıyla toplanır.</p>\\r\\n <p><b>Statik günlükler</b> çoğunlukla etkinlik günlükleridir. Dockerd'da günlüğe kaydedilmez ancak yine de kalıcı olmaları gerekir (API günlükleri hariç).</p>",
|
||||
"log_info": "<p>mailcow <b>bellek içi günlükler</b>, Redis listelerinde toplanır ve çekiçlemeyi azaltmak için her dakika LOG_LINES (%d) olacak şekilde kırpılır.\\r\\n <br>Bellek içi günlükler ısrarcı. Bellekte oturum açan tüm uygulamalar, ayrıca Docker arka plan programında ve dolayısıyla varsayılan günlük sürücüsünde oturum açar.\\r\\n <br>Bellek içi günlük türü, kapsayıcılarla ilgili küçük sorunları ayıklamak için kullanılmalıdır.</p>\\r\\n <p><b>Harici günlükler</b>, verilen uygulamanın API'si aracılığıyla toplanır.</p>\\r\\n <p><b>Statik günlükler</b> çoğunlukla etkinlik günlükleridir. Dockerd'da günlüğe kaydedilmez ancak yine de kalıcı olmaları gerekir (API günlükleri hariç).</p>",
|
||||
"architecture": "Mimari",
|
||||
"chart_this_server": "Grafik (bu sunucu)",
|
||||
"containers_info": "Kapsayıcı bilgileri",
|
||||
|
||||
@@ -418,7 +418,7 @@
|
||||
"pushover_key": "Ключ Pushover вказано у неправильному форматі",
|
||||
"quota_not_0_not_numeric": "Розмір квоти повинен бути більшим або дорівнювати нулю",
|
||||
"recipient_map_entry_exists": "Правило перезапису \"%s\" вже існує",
|
||||
"valkey_error": "Ошибка в Valkey: %s",
|
||||
"redis_error": "Ошибка в Redis: %s",
|
||||
"release_send_failed": "Повідомлення не може бути відновлено: %s",
|
||||
"resource_invalid": "Неприпустиме ім'я ресурсу %s",
|
||||
"rl_timeframe": "Невірний часовий інтервал для ліміту відправлення",
|
||||
@@ -511,7 +511,7 @@
|
||||
"uptime": "Час роботи",
|
||||
"username": "Ім'я користувача",
|
||||
"external_logs": "Зовнішні журнали",
|
||||
"log_info": "<p><b>Журнали контейнерів</b> mailcow зберігаються в Valkey, і раз на хвилину рядки журналу за межами <code>LOG_LINES (%d)</code> видаляються, щоб зменшити навантаження на сервер.\n <br>Самі журнали контейнерів не зберігаються після перезавантаження контейнера. Усі контейнери додатково пишуть логи у службу Docker, і, отже, використовують драйвер логування за промовчанням. Журнали контейнерів призначені лише для налагодження дрібних проблем. Для інших завдань, будь ласка, настройте драйвер логування Docker самостійно.</p>\n <p><b>Зовнішні журнали</b> збираються через API програм.</p>\n <p><b>Статичні журнали</b> – це в основному журнали активності, які не записуються в Dockerd, але все одно повинні бути постійними (за винятком журналів API).</p>",
|
||||
"log_info": "<p><b>Журнали контейнерів</b> mailcow зберігаються в Redis, і раз на хвилину рядки журналу за межами <code>LOG_LINES (%d)</code> видаляються, щоб зменшити навантаження на сервер.\n <br>Самі журнали контейнерів не зберігаються після перезавантаження контейнера. Усі контейнери додатково пишуть логи у службу Docker, і, отже, використовують драйвер логування за промовчанням. Журнали контейнерів призначені лише для налагодження дрібних проблем. Для інших завдань, будь ласка, настройте драйвер логування Docker самостійно.</p>\n <p><b>Зовнішні журнали</b> збираються через API програм.</p>\n <p><b>Статичні журнали</b> – це в основному журнали активності, які не записуються в Dockerd, але все одно повинні бути постійними (за винятком журналів API).</p>",
|
||||
"error_show_ip": "Не вдалося розпізнати публічні IP-адреси",
|
||||
"no_update_available": "Система працює на останній версії",
|
||||
"architecture": "Архітектура",
|
||||
|
||||
697
data/web/lang/lang.vi-vn.json
Normal file
697
data/web/lang/lang.vi-vn.json
Normal file
@@ -0,0 +1,697 @@
|
||||
{
|
||||
"acl": {
|
||||
"alias_domains": "Thêm tên miền bí danh",
|
||||
"app_passwds": "Quản lý mật khẩu ứng dụng",
|
||||
"bcc_maps": "Ánh xạ BCC",
|
||||
"delimiter_action": "Hành động phân cách",
|
||||
"domain_desc": "Thay đổi mô tả tên miền",
|
||||
"domain_relayhost": "Thay đổi máy chủ chuyển tiếp cho tên miền",
|
||||
"eas_reset": "Đặt lại thiết bị EAS",
|
||||
"extend_sender_acl": "Cho phép mở rộng ACL người gửi bằng địa chỉ bên ngoài",
|
||||
"filters": "Bộ lọc",
|
||||
"login_as": "Đăng nhập với tư cách người dùng hộp thư",
|
||||
"mailbox_relayhost": "Thay đổi máy chủ chuyển tiếp cho hộp thư",
|
||||
"prohibited": "Bị cấm bởi ACL",
|
||||
"protocol_access": "Thay đổi quyền truy cập giao thức",
|
||||
"pushover": "Thông báo đẩy",
|
||||
"pw_reset": "Cho phép đặt lại mật khẩu người dùng mailcow",
|
||||
"quarantine": "Hành động cách ly",
|
||||
"quarantine_attachments": "Cách ly tệp đính kèm",
|
||||
"quarantine_category": "Thay đổi danh mục thông báo cách ly",
|
||||
"quarantine_notification": "Thay đổi thông báo cách ly",
|
||||
"ratelimit": "Giới hạn tốc độ",
|
||||
"recipient_maps": "Ánh xạ người nhận",
|
||||
"smtp_ip_access": "Thay đổi máy chủ được phép cho SMTP",
|
||||
"sogo_access": "Cho phép quản lý truy cập SOGo",
|
||||
"sogo_profile_reset": "Đặt lại hồ sơ SOGo",
|
||||
"spam_alias": "Bí danh tạm thời",
|
||||
"spam_policy": "Danh sách chặn/Danh sách cho phép",
|
||||
"spam_score": "Điểm thư rác",
|
||||
"syncjobs": "Công việc đồng bộ",
|
||||
"tls_policy": "Chính sách TLS",
|
||||
"unlimited_quota": "Hạn ngạch không giới hạn cho hộp thư"
|
||||
},
|
||||
"add": {
|
||||
"activate_filter_warn": "Tất cả các bộ lọc khác sẽ bị vô hiệu hóa khi tùy chọn kích hoạt được chọn.",
|
||||
"active": "Đang hoạt động",
|
||||
"add": "Thêm",
|
||||
"add_domain_only": "Chỉ thêm tên miền",
|
||||
"add_domain_restart": "Thêm tên miền và khởi động lại SOGo",
|
||||
"alias_address": "Địa chỉ bí danh",
|
||||
"alias_address_info": "<small>Địa chỉ email đầy đủ hoặc @example.com để bắt tất cả thư cho một tên miền (phân cách bằng dấu phẩy). <b>Chỉ áp dụng cho tên miền mailcow</b>.</small>",
|
||||
"alias_domain": "Tên miền bí danh",
|
||||
"alias_domain_info": "<small>Chỉ cho phép tên miền hợp lệ (phân cách bằng dấu phẩy).</small>",
|
||||
"app_name": "Tên ứng dụng",
|
||||
"app_password": "Thêm mật khẩu ứng dụng",
|
||||
"app_passwd_protocols": "Các giao thức được phép cho mật khẩu ứng dụng",
|
||||
"automap": "Thử tự động ánh xạ thư mục (\"Mục đã gửi\", \"Đã gửi\" => \"Đã gửi\" v.v.)",
|
||||
"backup_mx_options": "Tùy chọn chuyển tiếp",
|
||||
"bcc_dest_format": "Địa chỉ BCC phải là một địa chỉ email hợp lệ duy nhất.<br>Nếu bạn cần gửi bản sao đến nhiều địa chỉ, hãy tạo một bí danh và sử dụng nó ở đây.",
|
||||
"comment_info": "Bình luận riêng tư không hiển thị với người dùng, trong khi bình luận công khai được hiển thị dưới dạng chú thích khi di chuột qua trong tổng quan người dùng",
|
||||
"custom_params": "Tham số tùy chỉnh",
|
||||
"custom_params_hint": "Đúng: --param=xy, sai: --param xy",
|
||||
"delete1": "Xóa từ nguồn khi hoàn thành",
|
||||
"delete2": "Xóa thư ở đích không có ở nguồn",
|
||||
"delete2duplicates": "Xóa các bản sao ở đích",
|
||||
"description": "Mô tả",
|
||||
"destination": "Đích",
|
||||
"disable_login": "Không cho phép đăng nhập (vẫn nhận được thư đến)",
|
||||
"domain": "Tên miền",
|
||||
"domain_matches_hostname": "Tên miền %s khớp với tên máy chủ",
|
||||
"domain_quota_m": "Tổng hạn ngạch tên miền (MiB)",
|
||||
"dry": "Mô phỏng đồng bộ hóa",
|
||||
"enc_method": "Phương thức mã hóa",
|
||||
"exclude": "Loại trừ đối tượng (biểu thức chính quy)",
|
||||
"full_name": "Tên đầy đủ",
|
||||
"gal": "Danh sách địa chỉ toàn cục",
|
||||
"gal_info": "GAL chứa tất cả các đối tượng của một tên miền và không thể được chỉnh sửa bởi bất kỳ người dùng nào. Thông tin rảnh/bận trong SOGo sẽ bị thiếu nếu vô hiệu hóa! <b>Khởi động lại SOGo để áp dụng thay đổi.</b>",
|
||||
"generate": "Tạo",
|
||||
"goto_ham": "\"Học là <span class=\"text-success\"><b>thư bình thường</b></span>",
|
||||
"goto_null": "Loại bỏ thư một cách thầm lặng",
|
||||
"goto_spam": "Học là <span class=\"text-danger\"><b>thư rác</b></span>",
|
||||
"hostname": "Máy chủ",
|
||||
"inactive": "Không hoạt động",
|
||||
"internal": "Nội bộ",
|
||||
"internal_info": "Bí danh nội bộ chỉ có thể truy cập từ tên miền sở hữu hoặc tên miền bí danh.",
|
||||
"kind": "Loại",
|
||||
"mailbox_quota_def": "Hạn ngạch hộp thư mặc định",
|
||||
"mailbox_quota_m": "Hạn ngạch tối đa mỗi hộp thư (MiB)",
|
||||
"mailbox_username": "Tên người dùng (phần bên trái của địa chỉ email)",
|
||||
"max_aliases": "Số lượng bí danh tối đa có thể tạo",
|
||||
"max_mailboxes": "Số lượng hộp thư tối đa có thể tạo",
|
||||
"mins_interval": "Khoảng thời gian kiểm tra (phút)",
|
||||
"multiple_bookings": "Đặt chỗ nhiều lần",
|
||||
"nexthop": "Bước nhảy tiếp theo",
|
||||
"password": "Mật khẩu",
|
||||
"password_repeat": "Xác nhận mật khẩu (nhập lại)",
|
||||
"port": "Cổng",
|
||||
"post_domain_add": "Container SOGo, \\\"sogo-mailcow\\\", cần được khởi động lại sau khi thêm tên miền mới!<br><br>Ngoài ra, cấu hình DNS của tên miền cần được xem xét. Khi cấu hình DNS được phê duyệt, khởi động lại \\\"acme-mailcow\\\" để tự động tạo chứng chỉ cho tên miền mới của bạn (autoconfig.<domain>, autodiscover.<domain>).<br>Bước này là tùy chọn và sẽ được thử lại sau mỗi 24 giờ.",
|
||||
"private_comment": "Bình luận riêng tư",
|
||||
"public_comment": "Bình luận công khai",
|
||||
"quota_mb": "Hạn ngạch (MiB)",
|
||||
"relay_all": "Chuyển tiếp tất cả người nhận",
|
||||
"relay_all_info": "↪ Nếu bạn chọn <b>không</b> chuyển tiếp tất cả người nhận, bạn sẽ cần thêm một hộp thư (\"ẩn\") cho từng người nhận cần được chuyển tiếp.",
|
||||
"relay_domain": "Chuyển tiếp tên miền này",
|
||||
"relay_transport_info": "<div class=\"badge fs-6 bg-info\">Thông tin</div> Bạn có thể định nghĩa ánh xạ vận chuyển cho đích tùy chỉnh cho tên miền này. Nếu không được đặt, tra cứu MX sẽ được thực hiện.",
|
||||
"relay_unknown_only": "Chỉ chuyển tiếp hộp thư không tồn tại. Hộp thư hiện có sẽ được gửi cục bộ.",
|
||||
"relayhost_wrapped_tls_info": "Vui lòng <b>không</b> sử dụng các cổng được bọc TLS (thường được sử dụng trên cổng 465).<br>\nSử dụng bất kỳ cổng không được bọc nào và sử dụng STARTTLS. Chính sách TLS để thực thi TLS có thể được tạo trong \"Ánh xạ chính sách TLS\".",
|
||||
"select": "Vui lòng chọn...",
|
||||
"select_domain": "Vui lòng chọn tên miền trước",
|
||||
"sieve_desc": "Mô tả ngắn",
|
||||
"sieve_type": "Loại bộ lọc",
|
||||
"skipcrossduplicates": "Bỏ qua tin nhắn trùng lặp giữa các thư mục (ai đến trước được phục vụ trước)",
|
||||
"subscribeall": "Đăng ký tất cả thư mục",
|
||||
"syncjob": "Thêm công việc đồng bộ",
|
||||
"syncjob_hint": "Lưu ý rằng mật khẩu cần được lưu dưới dạng văn bản thuần!",
|
||||
"tags": "Thẻ",
|
||||
"target_address": "Địa chỉ chuyển tiếp",
|
||||
"target_address_info": "<small>Địa chỉ email đầy đủ (phân cách bằng dấu phẩy).</small>",
|
||||
"target_domain": "Tên miền đích",
|
||||
"timeout1": "Thời gian chờ kết nối đến máy chủ từ xa",
|
||||
"timeout2": "Thời gian chờ kết nối đến máy chủ cục bộ",
|
||||
"username": "Tên người dùng",
|
||||
"validate": "Xác thực",
|
||||
"validation_success": "Xác thực thành công"
|
||||
},
|
||||
"admin": {
|
||||
"access": "Truy cập",
|
||||
"action": "Hành động",
|
||||
"activate_api": "Kích hoạt API",
|
||||
"activate_send": "Kích hoạt nút gửi",
|
||||
"active": "Đang hoạt động",
|
||||
"active_rspamd_settings_map": "Ánh xạ cài đặt đang hoạt động",
|
||||
"add": "Thêm",
|
||||
"add_admin": "Thêm quản trị viên",
|
||||
"add_domain_admin": "Thêm quản trị viên tên miền",
|
||||
"add_forwarding_host": "Thêm máy chủ chuyển tiếp",
|
||||
"add_relayhost": "Thêm vận chuyển phụ thuộc người gửi",
|
||||
"add_relayhost_hint": "Vui lòng lưu ý rằng dữ liệu xác thực, nếu có, sẽ được lưu trữ dưới dạng văn bản thuần.",
|
||||
"add_row": "Thêm hàng",
|
||||
"add_settings_rule": "Thêm quy tắc cài đặt",
|
||||
"add_transport": "Thêm vận chuyển",
|
||||
"add_transports_hint": "Vui lòng lưu ý rằng dữ liệu xác thực, nếu có, sẽ được lưu trữ dưới dạng văn bản thuần.",
|
||||
"additional_rows": " hàng bổ sung đã được thêm",
|
||||
"admin": "Quản trị viên",
|
||||
"admin_details": "Chỉnh sửa chi tiết quản trị viên",
|
||||
"admin_domains": "Gán tên miền",
|
||||
"admins": "Những quản trị viên",
|
||||
"admins_ldap": "Quản trị viên LDAP",
|
||||
"admin_quicklink": "Ẩn liên kết nhanh đến trang đăng nhập quản trị",
|
||||
"advanced_settings": "Cài đặt nâng cao",
|
||||
"allowed_methods": "Phương thức cho phép kiểm soát truy cập",
|
||||
"allowed_origins": "Nguồn gốc cho phép kiểm soát truy cập",
|
||||
"api_allow_from": "Cho phép truy cập API từ các IP/ký hiệu mạng CIDR này",
|
||||
"api_info": "API đang được phát triển. Tài liệu có thể được tìm thấy tại <a href=\"/api\">/api</a>",
|
||||
"api_key": "Khóa API",
|
||||
"api_read_only": "Truy cập chỉ đọc",
|
||||
"api_read_write": "Truy cập đọc-ghi",
|
||||
"api_skip_ip_check": "Bỏ qua kiểm tra IP cho API",
|
||||
"app_hide": "Ẩn khi đăng nhập",
|
||||
"app_links": "Liên kết ứng dụng",
|
||||
"app_name": "Tên ứng dụng",
|
||||
"apps_name": "Tên \"Ứng dụng mailcow\"",
|
||||
"arrival_time": "Thời gian đến (giờ máy chủ)",
|
||||
"authed_user": "Người dùng đã xác thực",
|
||||
"ays": "Bạn có chắc chắn muốn tiếp tục không?",
|
||||
"ban_list_info": "Xem danh sách IP bị cấm bên dưới: <b>mạng (thời gian cấm còn lại) - [hành động]</b>.<br />IP trong hàng đợi bỏ cấm sẽ được xóa khỏi danh sách cấm hoạt động trong vài giây.<br />Nhãn đỏ cho biết lệnh cấm vĩnh viễn đang hoạt động bởi danh sách từ chối.",
|
||||
"change_logo": "Thay đổi logo",
|
||||
"logo_normal_label": "Bình thường",
|
||||
"logo_dark_label": "Đảo ngược cho chế độ tối",
|
||||
"configuration": "Cấu hình",
|
||||
"convert_html_to_text": "Chuyển đổi HTML thành văn bản thuần",
|
||||
"copy_to_clipboard": "Văn bản đã được sao chép vào bộ nhớ tạm!",
|
||||
"cors_settings": "Cài đặt CORS",
|
||||
"credentials_transport_warning": "<b>Cảnh báo</b>: Thêm một mục ánh xạ vận chuyển mới sẽ cập nhật thông tin xác thực cho tất cả các mục có cột bước nhảy tiếp theo khớp.",
|
||||
"customer_id": "ID Khách hàng",
|
||||
"customize": "Tùy chỉnh",
|
||||
"login_page": "Trang đăng nhập",
|
||||
"destination": "Đích đến",
|
||||
"dkim_add_key": "Thêm khóa ARC/DKIM",
|
||||
"dkim_domains_selector": "Bộ chọn",
|
||||
"dkim_domains_wo_keys": "Chọn tên miền thiếu khóa",
|
||||
"dkim_from": "Từ",
|
||||
"dkim_from_title": "Tên miền nguồn để sao chép dữ liệu",
|
||||
"dkim_key_length": "Độ dài khóa DKIM (bits)",
|
||||
"dkim_key_missing": "Thiếu khóa",
|
||||
"dkim_key_unused": "Khóa không được sử dụng",
|
||||
"dkim_key_valid": "Khóa hợp lệ",
|
||||
"dkim_keys": "Khóa ARC/DKIM",
|
||||
"dkim_overwrite_key": "Ghi đè khóa DKIM hiện có",
|
||||
"dkim_private_key": "Khóa riêng tư",
|
||||
"dkim_to": "Đến",
|
||||
"dkim_to_title": "Tên miền đích - sẽ bị ghi đè",
|
||||
"domain": "Tên miền",
|
||||
"domain_admin": "Quản trị viên tên miền",
|
||||
"domain_admins": "Các quản trị viên tên miền",
|
||||
"domainadmin_quicklink": "Ẩn liên kết nhanh đến trang đăng nhập quản trị viên tên miền",
|
||||
"domain_s": "Tên miền/s",
|
||||
"duplicate": "Nhân bản",
|
||||
"duplicate_dkim": "Nhân bản bản ghi DKIM",
|
||||
"edit": "Chỉnh sửa",
|
||||
"empty": "Không có kết quả",
|
||||
"excludes": "Loại trừ những người nhận này",
|
||||
"f2b_ban_time": "Thời gian cấm (giây)",
|
||||
"f2b_ban_time_increment": "Thời gian cấm tăng dần với mỗi lần cấm",
|
||||
"f2b_blacklist": "Mạng/máy chủ bị từ chối",
|
||||
"f2b_filter": "Bộ lọc biểu thức chính quy",
|
||||
"f2b_list_info": "Một máy chủ hoặc mạng bị từ chối sẽ luôn có quyền ưu tiên cao hơn một thực thể trong danh sách cho phép. <b>Cập nhật danh sách sẽ mất vài giây để được áp dụng.</b>",
|
||||
"f2b_manage_external": "Quản lý Fail2Ban từ bên ngoài",
|
||||
"f2b_manage_external_info": "Fail2ban sẽ vẫn duy trì danh sách cấm, nhưng sẽ không chủ động đặt quy tắc để chặn lưu lượng. Sử dụng danh sách cấm được tạo bên dưới để chặn lưu lượng từ bên ngoài.",
|
||||
"f2b_max_attempts": "Số lần thử tối đa",
|
||||
"f2b_max_ban_time": "Thời gian cấm tối đa (giây)",
|
||||
"f2b_netban_ipv4": "Kích thước mạng con IPv4 để áp dụng lệnh cấm (8-32)",
|
||||
"f2b_netban_ipv6": "Kích thước mạng con IPv6 để áp dụng lệnh cấm (8-128",
|
||||
"f2b_parameters": "Tham số Fail2ban",
|
||||
"f2b_regex_info": "Nhật ký được xem xét: SOGo, Postfix, Dovecot, PHP-FPM.",
|
||||
"f2b_retry_window": "Cửa sổ thử lại (giây) cho số lần thử tối đa",
|
||||
"f2b_whitelist": "Mạng/máy chủ được cho phép",
|
||||
"filter": "Bộ lọc",
|
||||
"filter_table": "Bảng bộ lọc",
|
||||
"force_sso_text": "Nếu nhà cung cấp OIDC bên ngoài được cấu hình, tùy chọn này sẽ ẩn biểu mẫu đăng nhập mailcow mặc định và chỉ hiển thị nút Đăng nhập một lần",
|
||||
"force_sso": "Vô hiệu hóa đăng nhập mailcow và chỉ hiển thị Đăng nhập một lần",
|
||||
"forwarding_hosts": "Máy chủ chuyển tiếp",
|
||||
"forwarding_hosts_add_hint": "Bạn có thể chỉ định địa chỉ IPv4/IPv6, mạng theo ký hiệu CIDR, tên máy chủ (sẽ được phân giải thành địa chỉ IP), hoặc tên miền (sẽ được phân giải thành địa chỉ IP bằng cách truy vấn bản ghi SPF hoặc, nếu không có, bản ghi MX).",
|
||||
"forwarding_hosts_hint": "Tin nhắn đến được chấp nhận vô điều kiện từ bất kỳ máy chủ nào được liệt kê ở đây. Các máy chủ này sau đó không bị kiểm tra với DNSBL hoặc danh sách xám. Thư rác nhận từ chúng không bao giờ bị từ chối, nhưng có thể được chuyển vào thư mục Rác. Công dụng phổ biến nhất cho việc này là chỉ định các máy chủ thư mà bạn đã thiết lập quy tắc chuyển tiếp email đến cho máy chủ mailcow của bạn.",
|
||||
"from": "Từ",
|
||||
"generate": "tạo",
|
||||
"guid": "GUID - ID phiên bản duy nhất",
|
||||
"guid_and_license": "GUID & Giấy phép",
|
||||
"hash_remove_info": "Xóa một giá trị băm giới hạn tốc độ (nếu vẫn tồn tại) sẽ đặt lại hoàn toàn bộ đếm của nó.<br\n Mỗi giá trị băm được chỉ định bằng một màu riêng biệt.",
|
||||
"help_text": "Ghi đè văn bản trợ giúp bên dưới mặt nạ đăng nhập (cho phép HTML)",
|
||||
"host": "Máy chủ",
|
||||
"html": "HTML",
|
||||
"iam": "Nhà cung cấp danh tính",
|
||||
"iam_attribute_field": "Trường thuộc tính",
|
||||
"iam_authorize_url": "Điểm cuối ủy quyền",
|
||||
"iam_auth_flow": "Luồng xác thực",
|
||||
"iam_auth_flow_info": "Ngoài Luồng mã ủy quyền (Luồng chuẩn trong Keycloak), được sử dụng cho đăng nhập một lần, mailcow còn hỗ trợ Luồng xác thực với thông tin xác thực trực tiếp. Luồng mật khẩu thư cố gắng xác thực thông tin người dùng bằng cách sử dụng API REST quản trị Keycloak. mailcow lấy mật khẩu đã băm từ thuộc tính <code>mailcow_password</code>, được ánh xạ trong Keycloak.",
|
||||
"iam_basedn": "DN cơ sở",
|
||||
"iam_client_id": "ID khách hàng",
|
||||
"iam_client_secret": "Bí mật khách hàng",
|
||||
"iam_client_scopes": "Phạm vi khách hàng",
|
||||
"iam_default_template": "Mẫu mặc định",
|
||||
"iam_default_template_description": "Nếu không có mẫu nào được gán cho người dùng, mẫu mặc định sẽ được sử dụng để tạo hộp thư, nhưng không dùng để cập nhật hộp thư.",
|
||||
"iam_description": "Cấu hình Nhà cung cấp bên ngoài cho Xác thực<br>Hộp thư của người dùng sẽ được tự động tạo khi họ đăng nhập lần đầu, với điều kiện ánh xạ thuộc tính đã được thiết lập.",
|
||||
"iam_extra_permission": "Để các cài đặt sau hoạt động, ứng dụng khách mailcow trong Keycloak cần một <code>Tài khoản dịch vụ</code> và quyền <code>xem người dùng</code>.",
|
||||
"iam_host": "Máy chủ",
|
||||
"iam_host_info": "Nhập một hoặc nhiều máy chủ LDAP, phân cách bằng dấu phẩy.",
|
||||
"iam_import_users": "Nhập người dùng",
|
||||
"iam_login_provisioning": "Tự động tạo người dùng khi đăng nhập",
|
||||
"iam_mapping": "Ánh xạ thuộc tính",
|
||||
"iam_bindpass": "Mật khẩu ràng buộc",
|
||||
"iam_periodic_full_sync": "Đồng bộ hóa đầy đủ định kỳ",
|
||||
"iam_port": "Cổng",
|
||||
"iam_realm": "Vùng",
|
||||
"iam_redirect_url": "URL chuyển hướng",
|
||||
"iam_rest_flow": "Luồng mật khẩu thư",
|
||||
"iam_server_url": "URL máy chủ",
|
||||
"iam_sso": "Đăng nhập một lần",
|
||||
"iam_sync_interval": "Khoảng thời gian đồng bộ / nhập (phút)",
|
||||
"iam_test_connection": "Kiểm tra kết nối",
|
||||
"iam_token_url": "Điểm cuối token",
|
||||
"iam_userinfo_url": "Điểm cuối thông tin người dùng",
|
||||
"iam_username_field": "Trường tên người dùng",
|
||||
"iam_binddn": "DN ràng buộc",
|
||||
"iam_use_ssl": "Sử dụng SSL",
|
||||
"iam_use_ssl_info": "Nếu bật SSL và cổng được đặt là 389, nó sẽ tự động được ghi đè để sử dụng cổng 636.",
|
||||
"iam_use_tls": "Sử dụng StartTLS",
|
||||
"iam_use_tls_info": "Nếu bật TLS, bạn phải sử dụng cổng mặc định cho máy chủ LDAP của bạn (389). Không thể sử dụng các cổng SSL.",
|
||||
"iam_version": "Phiên bản",
|
||||
"ignore_ssl_error": "Bỏ qua lỗi SSL",
|
||||
"import": "Nhập",
|
||||
"import_private_key": "Nhập khóa riêng tư",
|
||||
"in_use_by": "Đang được sử dụng bởi",
|
||||
"inactive": "Không hoạt động",
|
||||
"include_exclude": "Bao gồm/Loại trừ",
|
||||
"include_exclude_info": "Mặc định - khi không có lựa chọn - <b>tất cả hộp thư</b> được đề cập",
|
||||
"includes": "Bao gồm những người nhận này",
|
||||
"ip_check": "Kiểm tra IP",
|
||||
"ip_check_disabled": "Kiểm tra IP đã bị vô hiệu hóa. Bạn có thể bật nó trong<br> <strong>Hệ thống > Cấu hình > Tùy chọn > Tùy chỉnh</strong>",
|
||||
"ip_check_opt_in": "Chọn tham gia sử dụng dịch vụ bên thứ ba <strong>ipv4.mailcow.email</strong> và <strong>ipv6.mailcow.email</strong> để phân giải địa chỉ IP bên ngoài.",
|
||||
"is_mx_based": "Dựa trên MX",
|
||||
"last_applied": "Áp dụng lần cuối",
|
||||
"license_info": "Giấy phép không bắt buộc nhưng giúp phát triển thêm.<br><a href=\"https://www.servercow.de/mailcow?lang=en#sal\" target=\"_blank\" alt=\"Đặt hàng SAL\">Đăng ký GUID của bạn tại đây</a> hoặc <a href=\"https://www.servercow.de/mailcow?lang=en#support\" target=\"_blank\" alt=\"Đặt hàng hỗ trợ\">mua hỗ trợ cho cài đặt mailcow của bạn.</a>",
|
||||
"link": "Liên kết",
|
||||
"loading": "Vui lòng đợi...",
|
||||
"login_time": "Thời gian đăng nhập",
|
||||
"logo_info": "Hình ảnh của bạn sẽ được điều chỉnh theo chiều cao 40px cho thanh điều hướng trên cùng và chiều rộng tối đa 250px cho trang bắt đầu. Khuyến nghị sử dụng đồ họa có thể thay đổi kích thước.",
|
||||
"lookup_mx": "Đích đến là một biểu thức chính quy để so khớp với tên MX (<code>.*.google.com</code> để định tuyến tất cả thư nhắm đến MX kết thúc bằng google.com qua bước nhảy này)",
|
||||
"main_name": "Tên \"Giao diện mailcow\"",
|
||||
"merged_vars_hint": "Các hàng bị mờ đã được hợp nhất từ <code>vars.(local.)inc.php</code> và không thể sửa đổi.",
|
||||
"message": "Tin nhắn",
|
||||
"message_size": "Kích thước tin nhắn",
|
||||
"nexthop": "Bước nhảy tiếp theo",
|
||||
"needs_restart": "cần khởi động lại",
|
||||
"no_active_bans": "Không có lệnh cấm đang hoạt động",
|
||||
"no_new_rows": "Không có hàng nào khác",
|
||||
"no_record": "Không có bản ghi",
|
||||
"oauth2_apps": "Ứng dụng OAuth2",
|
||||
"oauth2_add_client": "Thêm ứng dụng khách OAuth2",
|
||||
"oauth2_client_id": "ID ứng dụng khách",
|
||||
"oauth2_client_secret": "Bí mật ứng dụng khách",
|
||||
"oauth2_info": "Triển khai OAuth2 hỗ trợ loại cấp phép \"Mã ủy quyền\" và cấp token làm mới.<br>\nMáy chủ cũng tự động cấp token làm mới mới sau khi token làm mới đã được sử dụng.<br><br>\n• Phạm vi mặc định là <i>profile</i>. Chỉ người dùng hộp thư mới có thể được xác thực qua OAuth2. Nếu tham số phạm vi bị bỏ qua, nó sẽ trở về <i>profile</i>.<br>\n• Tham số <i>state</i> phải được gửi bởi ứng dụng khách như một phần của yêu cầu ủy quyền.<br><br>\nĐường dẫn cho các yêu cầu đến API OAuth2: <br>\n<ul>\n<li>Điểm cuối ủy quyền: <code>/oauth/authorize</code></li>\n<li>Điểm cuối token: <code>/oauth/token</code></li>\n<li>Trang tài nguyên: <code>/oauth/profile</code></li>\n</ul>\nTạo lại bí mật ứng dụng khách sẽ không làm hết hạn các mã ủy quyền hiện có, nhưng chúng sẽ không thể làm mới token của họ.<br><br>\nThu hồi token ứng dụng khách sẽ gây ra việc chấm dứt ngay lập tức tất cả các phiên hoạt động. Tất cả ứng dụng khách cần xác thực lại.",
|
||||
"oauth2_redirect_uri": "URI chuyển hướng",
|
||||
"oauth2_renew_secret": "Tạo bí mật ứng dụng khách mới",
|
||||
"oauth2_revoke_tokens": "Thu hồi tất cả token ứng dụng khách",
|
||||
"optional": "tùy chọn",
|
||||
"options": "Các tùy chọn",
|
||||
"password": "Mật khẩu",
|
||||
"password_length": "Độ dài mật khẩu",
|
||||
"password_policy": "Chính sách mật khẩu",
|
||||
"password_policy_chars": "Phải chứa ít nhất một ký tự chữ cái",
|
||||
"password_policy_length": "Độ dài mật khẩu tối thiểu là %d",
|
||||
"password_policy_lowerupper": "Phải chứa ký tự viết thường và viết hoa",
|
||||
"password_policy_numbers": "Phải chứa ít nhất một số",
|
||||
"password_policy_special_chars": "Phải chứa ký tự đặc biệt",
|
||||
"password_repeat": "Xác nhận mật khẩu (nhập lại)",
|
||||
"password_reset_info": "Nếu không cung cấp email khôi phục, chức năng này không thể được sử dụng.",
|
||||
"password_reset_settings": "Cài đặt khôi phục mật khẩu",
|
||||
"password_reset_tmpl_html": "Mẫu HTML",
|
||||
"password_reset_tmpl_text": "Mẫu văn bản",
|
||||
"password_settings": "Cài đặt mật khẩu",
|
||||
"priority": "Độ ưu tiên",
|
||||
"private_key": "Khóa riêng tư",
|
||||
"quarantine": "Cách ly",
|
||||
"quarantine_bcc": "Gửi một bản sao của tất cả thông báo (BCC) đến người nhận này:<br><small>Để trống để vô hiệu hóa. <b>Thư không ký, không kiểm tra. Chỉ nên gửi nội bộ.</b></small>",
|
||||
"quarantine_exclude_domains": "Loại trừ tên miền và tên miền bí danh",
|
||||
"quarantine_max_age": "Tuổi tối đa theo ngày<br><small>Giá trị phải bằng hoặc lớn hơn 1 ngày.</small>",
|
||||
"quarantine_max_score": "Bỏ thông báo nếu điểm thư rác của một thư cao hơn giá trị này:<br><small>Mặc định là 9999.0</small>",
|
||||
"quarantine_max_size": "Kích thước tối đa tính bằng MiB (các phần tử lớn hơn sẽ bị loại bỏ):<br><small>0 <b>không</b> có nghĩa là không giới hạn.</small>",
|
||||
"quarantine_notification_html": "Mẫu email thông báo:<br><small>Để trống để khôi phục mẫu mặc định.</small>",
|
||||
"quarantine_notification_sender": "Người gửi email thông báo",
|
||||
"quarantine_notification_subject": "Chủ đề email thông báo",
|
||||
"quarantine_redirect": "<b>Chuyển hướng tất cả thông báo</b> đến người nhận này:<br><small>Để trống để vô hiệu hóa. <b>Thư không ký, không kiểm tra. Chỉ nên gửi nội bộ.</b></small>",
|
||||
"quarantine_release_format": "Định dạng của các mục được phát hành",
|
||||
"quarantine_release_format_att": "Dưới dạng tệp đính kèm",
|
||||
"quarantine_release_format_raw": "Bản gốc không sửa đổi",
|
||||
"quarantine_retention_size": "ưu giữ cho mỗi hộp thư:<br><small>0 có nghĩa là <b>không hoạt động</b>.</small>",
|
||||
"quicklink_text": "Hiển thị hoặc ẩn liên kết nhanh đến các trang đăng nhập khác dưới biểu mẫu đăng nhập",
|
||||
"quota_notification_html": "Mẫu email thông báo:<br><small>Để trống để khôi phục mẫu mặc định.</small>",
|
||||
"quota_notification_sender": "Người gửi email thông báo",
|
||||
"quota_notification_subject": "Chủ đề email thông báo",
|
||||
"quota_notifications": "Thông báo hạn ngạch",
|
||||
"quota_notifications_info": "Thông báo hạn ngạch được gửi cho người dùng một lần khi vượt quá 80% và một lần khi vượt quá 95% mức sử dụng.",
|
||||
"quota_notifications_vars": "{{percent}} bằng hạn ngạch hiện tại của người dùng<br>{{username}} là tên hộp thư",
|
||||
"queue_unban": "bỏ cấm",
|
||||
"r_active": "Hạn chế đang hoạt động",
|
||||
"r_inactive": "Hạn chế không hoạt động",
|
||||
"r_info": "Các phần tử bị mờ/vô hiệu hóa trong danh sách hạn chế đang hoạt động không được mailcow công nhận là hạn chế hợp lệ và không thể di chuyển. Các hạn chế không xác định sẽ vẫn được đặt theo thứ tự xuất hiện. <br>Bạn có thể thêm phần tử mới trong <code>inc/vars.local.inc.php</code> để có thể bật/tắt chúng.",
|
||||
"rate_name": "Tên tỷ lệ",
|
||||
"recipients": "Người nhận",
|
||||
"refresh": "Làm mới",
|
||||
"regen_api_key": "Tạo lại khóa API",
|
||||
"regex_maps": "Ánh xạ biểu thức chính quy",
|
||||
"relay_from": "Địa chỉ \"Từ:\"",
|
||||
"relay_rcpt": "Địa chỉ \"Đến:\"",
|
||||
"relay_run": "Chạy thử",
|
||||
"relayhosts": "Vận chuyển phụ thuộc người gửi",
|
||||
"relayhosts_hint": "Xác định vận chuyển phụ thuộc người gửi để có thể chọn chúng trong hộp thoại cấu hình tên miền.<br>\nDịch vụ vận chuyển luôn là \"smtp:\" và do đó sẽ thử TLS khi được cung cấp. TLS được bọc (SMTPS) không được hỗ trợ. Cài đặt chính sách TLS gửi đi riêng của người dùng được tính đến.<br>\nẢnh hưởng đến các tên miền được chọn bao gồm cả tên miền bí danh.",
|
||||
"remove": "Xóa",
|
||||
"remove_row": "Xóa hàng",
|
||||
"reset_default": "Đặt lại về mặc định",
|
||||
"reset_limit": "Xóa giá trị băm",
|
||||
"reset_password_vars": "<code>{{link}}</code> Liên kết đặt lại mật khẩu đã tạo<br><code>{{username}}</code> Tên hộp thư của người dùng yêu cầu đặt lại mật khẩu<br><code>{{username2}}</code> Tên hộp thư khôi phục<br><code>{{date}}</code> Ngày yêu cầu đặt lại mật khẩu được thực hiện<br><code>{{token_lifetime}}</code> Thời gian sống của token tính bằng phút<br><code>{{hostname}}</code> Tên máy chủ mailcow",
|
||||
"restore_template": "Để trống để khôi phục mẫu mặc định.",
|
||||
"routing": "Định tuyến",
|
||||
"rsetting_add_rule": "Thêm quy tắc",
|
||||
"rsetting_content": "Nội dung quy tắc",
|
||||
"rsetting_desc": "Mô tả ngắn",
|
||||
"rsetting_no_selection": "Vui lòng chọn một quy tắc",
|
||||
"rsetting_none": "Không có quy tắc nào",
|
||||
"rsettings_insert_preset": "Chèn mẫu ví dụ \"%s\"",
|
||||
"rsettings_preset_1": "Vô hiệu hóa tất cả trừ DKIM và giới hạn tốc độ cho người dùng đã xác thực",
|
||||
"rsettings_preset_2": "Quản trị viên bưu điện muốn thư rác",
|
||||
"rsettings_preset_3": "Chỉ cho phép người gửi cụ thể cho một hộp thư (ví dụ: sử dụng như hộp thư nội bộ)",
|
||||
"rsettings_preset_4": "Vô hiệu hóa Rspamd cho một tên miền",
|
||||
"rspamd_com_settings": "Tên cài đặt sẽ được tự động tạo, vui lòng xem các mẫu ví dụ bên dưới. Để biết thêm chi tiết, xem <a href=\"https://rspamd.com/doc/configuration/settings.html#settings-structure\" target=\"_blank\">Tài liệu Rspamd</a>",
|
||||
"rspamd_global_filters": "Ánh xạ bộ lọc toàn cục",
|
||||
"rspamd_global_filters_agree": "Tôi sẽ cẩn thận!",
|
||||
"rspamd_global_filters_info": "Ánh xạ bộ lọc toàn cục chứa các loại danh sách từ chối và cho phép toàn cục khác nhau.",
|
||||
"rspamd_global_filters_regex": "Tên của chúng giải thích mục đích sử dụng. Tất cả nội dung phải chứa biểu thức chính quy hợp lệ theo định dạng \"/mẫu/tùy chọn\" (ví dụ: <code>/.+@domain.tld/i</code>).<br>\nMặc dù kiểm tra cơ bản được thực hiện trên mỗi dòng của regex, chức năng của Rspamd có thể bị hỏng nếu nó không đọc được cú pháp chính xác.<br>\nRspamd sẽ cố gắng đọc nội dung ánh xạ khi thay đổi. Nếu bạn gặp vấn đề, <a href=\"\" data-toggle=\"modal\" data-container=\"rspamd-mailcow\" data-target=\"#RestartContainer\">khởi động lại Rspamd</a> để bắt buộc tải lại ánh xạ.<br>Các phần tử trong danh sách từ chối được loại trừ khỏi cách ly.",
|
||||
"rspamd_settings_map": "Ánh xạ cài đặt Rspamd",
|
||||
"sal_level": "Cấp độ Moo",
|
||||
"save": "Lưu thay đổi",
|
||||
"search_domain_da": "Tìm kiếm tên miền",
|
||||
"send": "Gửi",
|
||||
"sender": "Người gửi",
|
||||
"service": "Dịch vụ",
|
||||
"service_id": "ID Dịch vụ",
|
||||
"source": "Nguồn",
|
||||
"spamfilter": "Bộ lọc thư rác",
|
||||
"subject": "Chủ đề",
|
||||
"success": "Thành công",
|
||||
"sys_mails": "Thư hệ thống",
|
||||
"task": "Nhiệm vụ",
|
||||
"text": "Văn bản",
|
||||
"time": "Thời gian",
|
||||
"title": "Tiêu đề",
|
||||
"title_name": "Tiêu đề trang web \"Giao diện mailcow\"",
|
||||
"to_top": "Về đầu trang",
|
||||
"transport_dest_format": "Regex hoặc cú pháp: example.org, .example.org, *, box@example.org (nhiều giá trị có thể được phân cách bằng dấu phẩy)",
|
||||
"transport_maps": "Ánh xạ vận chuyển",
|
||||
"transport_test_rcpt_info": "• Sử dụng null@hosted.mailcow.de để kiểm tra chuyển tiếp đến đích nước ngoài.",
|
||||
"transports_hint": "• Một mục ánh xạ vận chuyển <b>ghi đè</b> một ánh xạ vận chuyển phụ thuộc người gửi</b>.<br>\n• Vận chuyển dựa trên MX được ưu tiên sử dụng.<br>\n• Cài đặt chính sách TLS gửi đi cho từng người dùng bị bỏ qua và chỉ có thể được thực thi bởi các mục ánh xạ chính sách TLS.<br>\n• Dịch vụ vận chuyển cho các vận chuyển đã định nghĩa luôn là \"smtp:\" và do đó sẽ thử TLS khi được cung cấp. TLS được bọc (SMTPS) không được hỗ trợ.<br>\n• Địa chỉ khớp với \"/localhost$/\" sẽ luôn được vận chuyển qua \"local:\", do đó đích \"*\" sẽ không áp dụng cho những địa chỉ đó.<br>\n• Để xác định thông tin xác thực cho bước nhảy tiếp theo ví dụ \"[host]:25\", Postfix <b>luôn</b> truy vấn \"host\" trước khi tìm kiếm \"[host]:25\". Hành vi này khiến không thể sử dụng \"host\" và \"[host]:25\" cùng một lúc.",
|
||||
"ui_footer": "Chân trang (cho phép HTML)",
|
||||
"ui_header_announcement": "Thông báo",
|
||||
"ui_header_announcement_active": "Đặt thông báo hoạt động",
|
||||
"ui_header_announcement_content": "Văn bản (cho phép HTML)",
|
||||
"ui_header_announcement_help": "Thông báo hiển thị cho tất cả người dùng đã đăng nhập và trên màn hình đăng nhập của giao diện người dùng.",
|
||||
"ui_header_announcement_select": "Chọn loại thông báo",
|
||||
"ui_header_announcement_type": "Loại",
|
||||
"ui_header_announcement_type_danger": "Rất quan trọng",
|
||||
"ui_header_announcement_type_info": "Thông tin",
|
||||
"ui_header_announcement_type_warning": "Quan trọng",
|
||||
"ui_texts": "Nhãn và văn bản giao diện người dùng",
|
||||
"unban_pending": "đang chờ bỏ cấm",
|
||||
"unchanged_if_empty": "Nếu không thay đổi hãy để trống",
|
||||
"upload": "Tải lên",
|
||||
"username": "Tên người dùng",
|
||||
"user_link": "Liên kết người dùng",
|
||||
"user_quicklink": "Ẩn liên kết nhanh đến trang đăng nhập người dùng",
|
||||
"validate_license_now": "Xác thực GUID với máy chủ giấy phép",
|
||||
"verify": "Xác minh",
|
||||
"yes": "✓"
|
||||
},
|
||||
"danger": {
|
||||
"access_denied": "Truy cập bị từ chối hoặc dữ liệu biểu mẫu không hợp lệ",
|
||||
"alias_domain_invalid": "Tên miền bí danh %s không hợp lệ",
|
||||
"alias_empty": "Địa chỉ bí danh không được để trống",
|
||||
"alias_goto_identical": "Địa chỉ bí danh và địa chỉ chuyển tiếp không được giống nhau",
|
||||
"alias_invalid": "Địa chỉ bí danh %s không hợp lệ",
|
||||
"aliasd_targetd_identical": "Tên miền bí danh không được giống với tên miền đích: %s",
|
||||
"aliases_in_use": "Số bí danh tối đa phải lớn hơn hoặc bằng %d",
|
||||
"app_name_empty": "Tên ứng dụng không được để trống",
|
||||
"app_passwd_id_invalid": "ID mật khẩu ứng dụng %s không hợp lệ",
|
||||
"authsource_in_use": "Nhà cung cấp danh tính không thể thay đổi hoặc xóa vì hiện đang được sử dụng bởi một hoặc nhiều người dùng.",
|
||||
"bcc_empty": "Đích BCC không được để trống",
|
||||
"bcc_exists": "Một ánh xạ BCC %s đã tồn tại cho loại %s",
|
||||
"bcc_must_be_email": "Đích BCC %s không phải là địa chỉ email hợp lệ",
|
||||
"comment_too_long": "Bình luận quá dài, cho phép tối đa 160 ký tự",
|
||||
"cors_invalid_method": "Phương thức Allow-Method được chỉ định không hợp lệ",
|
||||
"cors_invalid_origin": "Allow-Origin được chỉ định không hợp lệ",
|
||||
"defquota_empty": "Hạn ngạch mặc định cho mỗi hộp thư không được là 0.",
|
||||
"demo_mode_enabled": "Chế độ Demo đang được bật",
|
||||
"description_invalid": "Mô tả tài nguyên cho %s không hợp lệ",
|
||||
"dkim_domain_or_sel_exists": "Một khóa DKIM cho \"%s\" đã tồn tại và sẽ không bị ghi đè",
|
||||
"dkim_domain_or_sel_invalid": "Tên miền hoặc bộ chọn DKIM không hợp lệ: %s",
|
||||
"domain_cannot_match_hostname": "Tên miền không thể trùng với tên máy chủ",
|
||||
"domain_exists": "Tên miền %s đã tồn tại",
|
||||
"domain_invalid": "Tên miền trống hoặc không hợp lệ",
|
||||
"domain_not_empty": "Không thể xóa tên miền %s không trống",
|
||||
"domain_not_found": "Không tìm thấy tên miền %s",
|
||||
"domain_quota_m_in_use": "Hạn ngạch tên miền phải lớn hơn hoặc bằng %s MiB",
|
||||
"extended_sender_acl_denied": "thiếu ACL để đặt địa chỉ người gửi bên ngoài",
|
||||
"extra_acl_invalid": "Địa chỉ người gửi bên ngoài \"%s\" không hợp lệ",
|
||||
"extra_acl_invalid_domain": "Người gửi bên ngoài \"%s\" sử dụng tên miền không hợp lệ",
|
||||
"fido2_verification_failed": "Xác minh FIDO2 thất bại: %s",
|
||||
"file_open_error": "Không thể mở tệp để ghi",
|
||||
"filter_type": "Loại bộ lọc không đúng",
|
||||
"from_invalid": "Người gửi không được để trống",
|
||||
"generic_server_error": "Đã xảy ra lỗi máy chủ không mong đợi. Vui lòng liên hệ quản trị viên của bạn.",
|
||||
"global_filter_write_error": "Không thể ghi tệp bộ lọc: %s",
|
||||
"global_map_invalid": "ID ánh xạ toàn cục %s không hợp lệ",
|
||||
"global_map_write_error": "Không thể ghi ID ánh xạ toàn cục %s: %s",
|
||||
"goto_empty": "Một địa chỉ bí danh phải chứa ít nhất một địa chỉ chuyển tiếp hợp lệ",
|
||||
"goto_invalid": "Địa chỉ chuyển tiếp %s không hợp lệ",
|
||||
"ham_learn_error": "Lỗi học thư hợp lệ: %s",
|
||||
"iam_test_connection": "Kết nối thất bại",
|
||||
"imagick_exception": "Lỗi: Ngoại lệ Imagick khi đọc hình ảnh",
|
||||
"img_dimensions_exceeded": "Hình ảnh vượt quá kích thước tối đa cho phép",
|
||||
"img_invalid": "Không thể xác thực tệp hình ảnh",
|
||||
"img_size_exceeded": "Hình ảnh vượt quá kích thước tệp tối đa",
|
||||
"img_tmp_missing": "Không thể xác thực tệp hình ảnh: Không tìm thấy tệp tạm thời",
|
||||
"invalid_bcc_map_type": "Loại ánh xạ BCC không hợp lệ",
|
||||
"invalid_destination": "Định dạng đích \"%s\" không hợp lệ",
|
||||
"invalid_filter_type": "Loại bộ lọc không hợp lệ",
|
||||
"invalid_host": "Máy chủ được chỉ định không hợp lệ: %s",
|
||||
"invalid_mime_type": "Kiểu MIME không hợp lệ",
|
||||
"invalid_nexthop": "Định dạng bước nhảy tiếp theo không hợp lệ",
|
||||
"invalid_nexthop_authenticated": "Bước nhảy tiếp theo tồn tại với thông tin xác thực khác, vui lòng cập nhật thông tin xác thực hiện có cho bước nhảy này trước.",
|
||||
"invalid_recipient_map_new": "Người nhận mới được chỉ định không hợp lệ: %s",
|
||||
"invalid_recipient_map_old": "Người nhận gốc được chỉ định không hợp lệ: %s",
|
||||
"invalid_reset_token": "Token đặt lại không hợp lệ",
|
||||
"ip_list_empty": "Danh sách IP được phép không được để trống",
|
||||
"is_alias": "%s đã được biết đến như một địa chỉ bí danh",
|
||||
"is_alias_or_mailbox": "%s đã được biết đến như một bí danh, một hộp thư hoặc một địa chỉ bí danh được mở rộng từ một tên miền bí danh.",
|
||||
"is_spam_alias": "%s đã được biết đến như một địa chỉ bí danh tạm thời (địa chỉ bí danh thư rác)",
|
||||
"last_key": "Không thể xóa khóa cuối cùng, vui lòng vô hiệu hóa TFA thay thế.",
|
||||
"login_failed": "Đăng nhập không thành công",
|
||||
"mailbox_defquota_exceeds_mailbox_maxquota": "Hạn ngạch mặc định vượt quá giới hạn hạn ngạch tối đa",
|
||||
"mailbox_invalid": "Tên hộp thư không hợp lệ",
|
||||
"mailbox_quota_exceeded": "Hạn ngạch vượt quá giới hạn tên miền (tối đa %d MiB)",
|
||||
"mailbox_quota_exceeds_domain_quota": "Hạn ngạch tối đa vượt quá giới hạn hạn ngạch tên miền",
|
||||
"mailbox_quota_left_exceeded": "Không đủ dung lượng còn lại (dung lượng còn lại: %d MiB)",
|
||||
"mailboxes_in_use": "Số hộp thư tối đa phải lớn hơn hoặc bằng %d",
|
||||
"malformed_username": "Tên người dùng không đúng định dạng",
|
||||
"map_content_empty": "Nội dung ánh xạ không được để trống",
|
||||
"max_age_invalid": "Tuổi tối đa %s không hợp lệ",
|
||||
"max_alias_exceeded": "Vượt quá số bí danh tối đa",
|
||||
"max_mailbox_exceeded": "Vượt quá số hộp thư tối đa (%d trên %d)",
|
||||
"max_quota_in_use": "Hạn ngạch hộp thư phải lớn hơn hoặc bằng %d MiB",
|
||||
"maxquota_empty": "Hạn ngạch tối đa cho mỗi hộp thư không được là 0.",
|
||||
"mode_invalid": "Chế độ %s không hợp lệ",
|
||||
"mx_invalid": "Bản ghi MX %s không hợp lệ",
|
||||
"mysql_error": "Lỗi MySQL: %s",
|
||||
"network_host_invalid": "Mạng hoặc máy chủ không hợp lệ: %s",
|
||||
"next_hop_interferes": "%s xung đột với bước nhảy tiếp theo %s",
|
||||
"next_hop_interferes_any": "Một bước nhảy tiếp theo hiện có xung đột với %s",
|
||||
"nginx_reload_failed": "Tải lại Nginx thất bại: %s",
|
||||
"no_user_defined": "Không có người dùng được định nghĩa",
|
||||
"object_exists": "Đối tượng %s đã tồn tại",
|
||||
"object_is_not_numeric": "Giá trị %s không phải là số",
|
||||
"password_complexity": "Mật khẩu không đáp ứng chính sách",
|
||||
"password_empty": "Mật khẩu không được để trống",
|
||||
"password_mismatch": "Mật khẩu xác nhận không khớp",
|
||||
"password_reset_invalid_user": "Không tìm thấy hộp thư hoặc không có email khôi phục được thiết lập",
|
||||
"password_reset_na": "Tính năng khôi phục mật khẩu hiện không khả dụng. Vui lòng liên hệ quản trị viên của bạn.",
|
||||
"policy_list_from_exists": "Một bản ghi với tên đã cho tồn tại",
|
||||
"policy_list_from_invalid": "Bản ghi có định dạng không hợp lệ",
|
||||
"private_key_error": "Lỗi khóa riêng tư: %s",
|
||||
"pushover_credentials_missing": "Thiếu token hoặc khóa Pushover",
|
||||
"pushover_key": "Khóa Pushover có định dạng không đúng",
|
||||
"pushover_token": "Token Pushover có định dạng không đúng",
|
||||
"quota_not_0_not_numeric": "Hạn ngạch phải là số và >= 0",
|
||||
"recipient_map_entry_exists": "Mục ánh xạ người nhận \"%s\" đã tồn tại",
|
||||
"recovery_email_failed": "Không thể gửi email khôi phục. Vui lòng liên hệ quản trị viên của bạn.",
|
||||
"redis_error": "Lỗi Redis: %s",
|
||||
"relayhost_invalid": "Mục ánh xạ %s không hợp lệ",
|
||||
"release_send_failed": "Không thể phát hành thư: %s",
|
||||
"required_data_missing": "Thiếu dữ liệu bắt buộc %s",
|
||||
"reset_f2b_regex": "Không thể đặt lại bộ lọc biểu thức chính quy kịp thời, vui lòng thử lại hoặc đợi thêm vài giây và tải lại trang web.",
|
||||
"reset_token_limit_exceeded": "Đã vượt quá giới hạn token đặt lại. Vui lòng thử lại sau.",
|
||||
"resource_invalid": "Tên tài nguyên %s không hợp lệ",
|
||||
"rl_timeframe": "Khung thời gian giới hạn tốc độ không chính xác",
|
||||
"rspamd_ui_pw_length": "Mật khẩu giao diện Rspamd phải có ít nhất 6 ký tự",
|
||||
"script_empty": "Tập lệnh không được để trống",
|
||||
"sender_acl_invalid": "Giá trị ACL người gửi %s không hợp lệ",
|
||||
"set_acl_failed": "Không thể thiết lập ACL",
|
||||
"settings_map_invalid": "ID ánh xạ cài đặt %s không hợp lệ",
|
||||
"sieve_error": "Lỗi phân tích cú pháp Sieve: %s",
|
||||
"spam_learn_error": "Lỗi học thư rác: %s",
|
||||
"subject_empty": "Tiêu đề không được để trống",
|
||||
"target_domain_invalid": "Tên miền đích %s không hợp lệ",
|
||||
"targetd_not_found": "Không tìm thấy tên miền đích %s",
|
||||
"targetd_relay_domain": "Tên miền đích %s là tên miền chuyển tiếp",
|
||||
"template_exists": "Mẫu %s đã tồn tại",
|
||||
"template_id_invalid": "ID mẫu %s không hợp lệ",
|
||||
"template_name_invalid": "Tên mẫu không hợp lệ",
|
||||
"temp_error": "Lỗi tạm thời",
|
||||
"text_empty": "Văn bản không được để trống",
|
||||
"tfa_token_invalid": "Token xác thực hai yếu tố không hợp lệ",
|
||||
"tls_policy_map_dest_invalid": "Đích chính sách TLS không hợp lệ",
|
||||
"tls_policy_map_entry_exists": "Mục ánh xạ chính sách TLS \"%s\" đã tồn tại",
|
||||
"tls_policy_map_parameter_invalid": "Tham số chính sách không hợp lệ",
|
||||
"to_invalid": "Người nhận không được để trống",
|
||||
"totp_verification_failed": "Xác thực TOTP thất bại",
|
||||
"transport_dest_exists": "Đích vận chuyển \"%s\" đã tồn tại",
|
||||
"webauthn_verification_failed": "Xác thực WebAuthn thất bại: %s",
|
||||
"webauthn_authenticator_failed": "Không tìm thấy trình xác thực đã chọn",
|
||||
"webauthn_publickey_failed": "Không có khóa công khai nào được lưu cho trình xác thực đã chọn",
|
||||
"webauthn_username_failed": "Trình xác thực đã chọn thuộc về tài khoản khác",
|
||||
"unknown": "Đã xảy ra lỗi không xác định",
|
||||
"unknown_tfa_method": "Phương thức xác thực hai yếu tố không xác định",
|
||||
"unlimited_quota_acl": "Hạn ngạch không giới hạn bị cấm bởi ACL",
|
||||
"username_invalid": "Tên người dùng %s không thể sử dụng được",
|
||||
"validity_missing": "Vui lòng gán thời hạn hiệu lực",
|
||||
"value_missing": "Vui lòng cung cấp tất cả các giá trị",
|
||||
"version_invalid": "Phiên bản %s không hợp lệ",
|
||||
"yotp_verification_failed": "Xác thực Yubico OTP thất bại: %s"
|
||||
},
|
||||
"datatables": {
|
||||
"collapse_all": "Thu gọn tất cả",
|
||||
"emptyTable": "Không có dữ liệu trong bảng",
|
||||
"expand_all": "Mở rộng tất cả",
|
||||
"info": "Hiển thị từ _START_ đến _END_ của _TOTAL_ mục",
|
||||
"infoEmpty": "Hiển thị 0 đến 0 của 0 mục",
|
||||
"infoFiltered": "(được lọc từ tổng số _MAX_ mục)",
|
||||
"lengthMenu": "Hiển thị _MENU_ mục",
|
||||
"loadingRecords": "Đang tải...",
|
||||
"processing": "Vui lòng đợi...",
|
||||
"search": "Tìm kiếm:",
|
||||
"zeroRecords": "Không tìm thấy bản ghi phù hợp",
|
||||
"paginate": {
|
||||
"first": "Đầu",
|
||||
"last": "Cuối",
|
||||
"next": "Tiếp",
|
||||
"previous": "Trước"
|
||||
},
|
||||
"aria": {
|
||||
"sortAscending": ": kích hoạt để sắp xếp cột tăng dần",
|
||||
"sortDescending": ": kích hoạt để sắp xếp cột giảm dần"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"architecture": "Kiến trúc",
|
||||
"chart_this_server": "Biểu đồ (máy chủ này)",
|
||||
"containers_info": "Thông tin container",
|
||||
"container_running": "Đang chạy",
|
||||
"container_disabled": "Container đã dừng hoặc bị vô hiệu hóa",
|
||||
"container_stopped": "Đã dừng",
|
||||
"cores": "Nhân CPU",
|
||||
"current_time": "Thời gian hệ thống",
|
||||
"disk_usage": "Sử dụng ổ đĩa",
|
||||
"docs": "Tài liệu",
|
||||
"error_show_ip": "Không thể phân giải địa chỉ IP công khai",
|
||||
"external_logs": "Nhật ký ngoài",
|
||||
"history_all_servers": "Lịch sử (tất cả máy chủ)",
|
||||
"in_memory_logs": "Nhật ký trong bộ nhớ",
|
||||
"last_modified": "Sửa đổi lần cuối",
|
||||
"log_info": "<p>mailcow <b>nhật ký trong bộ nhớ</b> được thu thập trong danh sách Redis và được cắt giảm xuống LOG_LINES (%d) mỗi phút để giảm tải.\n<br>Nhật ký trong bộ nhớ không nhằm mục đích lưu trữ lâu dài. Tất cả các ứng dụng ghi nhật ký trong bộ nhớ cũng ghi vào Docker daemon và do đó vào trình điều khiển ghi nhật ký mặc định.r\n<br>Loại nhật ký trong bộ nhớ nên được sử dụng để gỡ lỗi các vấn đề nhỏ với các container.</p>\n<p><b>Nhật ký bên ngoài</b> được thu thập thông qua API của ứng dụng đã cho.</p>\n<p><b>Nhật ký tĩnh</b> chủ yếu là nhật ký hoạt động, không được ghi vào Dockerd nhưng vẫn cần được lưu trữ lâu dài (ngoại trừ nhật ký API).</p>",
|
||||
"login_time": "Thời gian",
|
||||
"logs": "Nhật ký",
|
||||
"memory": "Bộ nhớ",
|
||||
"online_users": "Người dùng trực tuyến",
|
||||
"restart_container": "Khởi động lại",
|
||||
"service": "Dịch vụ",
|
||||
"show_ip": "Hiển thị IP công khai",
|
||||
"size": "Kích thước",
|
||||
"started_at": "Bắt đầu lúc",
|
||||
"started_on": "Bắt đầu vào",
|
||||
"static_logs": "Nhật ký tĩnh",
|
||||
"success": "Thành công",
|
||||
"system_containers": "Hệ thống & Container",
|
||||
"timezone": "Múi giờ",
|
||||
"uptime": "Thời gian hoạt động",
|
||||
"update_available": "Có bản cập nhật mới",
|
||||
"no_update_available": "Hệ thống đang ở phiên bản mới nhất",
|
||||
"update_failed": "Không thể kiểm tra cập nhật",
|
||||
"username": "Tên người dùng",
|
||||
"wip": "Đang trong quá trình phát triển"
|
||||
},
|
||||
"diagnostics": {
|
||||
"cname_from_a": "Giá trị được lấy từ bản ghi A/AAAA. Điều này được hỗ trợ miễn là bản ghi trỏ đến tài nguyên chính xác.",
|
||||
"dns_records": "Bản ghi DNS",
|
||||
"dns_records_24hours": "Xin lưu ý rằng các thay đổi được thực hiện đối với DNS có thể mất tới 24 giờ để phản ánh chính xác trạng thái hiện tại của chúng trên trang này. Trang này nhằm giúp bạn dễ dàng xem cách cấu hình bản ghi DNS và kiểm tra xem tất cả bản ghi của bạn có được lưu trữ chính xác trong DNS hay không.",
|
||||
"dns_records_data": "Dữ liệu chính xác",
|
||||
"dns_records_docs": "Vui lòng tham khảo thêm <a target=\"_blank\" href=\"https://docs.mailcow.email/getstarted/prerequisite-dns\">tài liệu hướng dẫn</a>.",
|
||||
"dns_records_name": "Tên",
|
||||
"dns_records_status": "Trạng thái hiện tại",
|
||||
"dns_records_type": "Loại",
|
||||
"optional": "Bản ghi này là tùy chọn."
|
||||
},
|
||||
"edit": {
|
||||
"acl": "ACL (Quyền hạn)",
|
||||
"active": "Hoạt động",
|
||||
"admin": "Chỉnh sửa quản trị viên",
|
||||
"advanced_settings": "Cài đặt nâng cao",
|
||||
"alias": "Chỉnh sửa bí danh",
|
||||
"allow_from_smtp": "Chỉ cho phép các IP sau sử dụng <b>SMTP</b>",
|
||||
"allow_from_smtp_info": "Để trống để cho phép tất cả người gửi.<br>Địa chỉ và mạng IPv4/IPv6.",
|
||||
"allowed_protocols": "Các giao thức được phép truy cập trực tiếp của người dùng (không ảnh hưởng đến giao thức mật khẩu ứng dụng)",
|
||||
"app_name": "Tên ứng dụng",
|
||||
"app_passwd": "Mật khẩu ứng dụng",
|
||||
"app_passwd_protocols": "Các giao thức được phép cho mật khẩu ứng dụng",
|
||||
"automap": "Thử tự động ánh xạ thư mục (\"Mục đã gửi\", \"Đã gửi\" => \"Đã gửi\" v.v.)",
|
||||
"backup_mx_options": "Tùy chọn chuyển tiếp",
|
||||
"bcc_dest_format": "Đích BCC phải là một địa chỉ email hợp lệ duy nhất.<br>Nếu bạn cần gửi bản sao đến nhiều địa chỉ, hãy tạo một bí danh và sử dụng nó ở đây.",
|
||||
"client_id": "ID khách hàng",
|
||||
"client_secret": "Khóa bí mật khách hàng",
|
||||
"comment_info": "Bình luận riêng tư không hiển thị với người dùng, trong khi bình luận công khai được hiển thị dưới dạng chú thích khi di chuột qua trong tổng quan người dùng",
|
||||
"created_on": "Được tạo vào",
|
||||
"custom_attributes": "Thuộc tính tùy chỉnh",
|
||||
"delete1": "Xóa từ nguồn khi hoàn thành",
|
||||
"delete2": "Xóa thư ở đích không có ở nguồn",
|
||||
"delete2duplicates": "Xóa các bản sao ở đích",
|
||||
"delete_ays": "Vui lòng xác nhận quá trình xóa.",
|
||||
"description": "Mô tả",
|
||||
"disable_login": "Không cho phép đăng nhập (vẫn nhận được thư đến)",
|
||||
"domain": "Chỉnh sửa tên miền",
|
||||
"domain_admin": "Chỉnh sửa quản trị viên tên miền",
|
||||
"domain_footer": "Chân trang toàn tên miền",
|
||||
"domain_footer_html": "Chân trang HTML",
|
||||
"domain_footer_info": "Chân trang toàn tên miền được thêm vào tất cả các email gửi đi liên quan đến một địa chỉ trong tên miền này. <br> Các biến sau có thể được sử dụng cho chân trang:",
|
||||
"domain_footer_info_vars": {
|
||||
"auth_user": "{= auth_user =} - Tên người dùng đã xác thực được chỉ định bởi MTA",
|
||||
"from_user": "{= from_user =} - Phần người dùng của phong bì, ví dụ \"moo@mailcow.tld\" sẽ trả về \"moo\"",
|
||||
"from_name": "{= from_name =} - Tên từ phong bì, ví dụ \"Mailcow <moo@mailcow.tld>\" sẽ trả về \"Mailcow\"",
|
||||
"from_addr": "{= from_addr =} - Phần địa chỉ của phong bì",
|
||||
"from_domain": "{= from_domain =} - Phần tên miền của phong bì",
|
||||
"custom": "{= foo =} - Nếu hộp thư có thuộc tính tùy chỉnh \"foo\" với giá trị \"bar\" sẽ trả về \"bar\""
|
||||
},
|
||||
"domain_footer_plain": "Chân trang văn bản thuần",
|
||||
"domain_footer_skip_replies": "Bỏ qua chân trang trong email trả lời",
|
||||
"domain_quota": "Hạn ngạch tên miền",
|
||||
"domains": "Các tên miền",
|
||||
"dont_check_sender_acl": "Tắt kiểm tra người gửi cho tên miền %s (+ tên miền bí danh)",
|
||||
"edit_alias_domain": "Chỉnh sửa tên miền bí danh",
|
||||
"encryption": "Mã hóa",
|
||||
"exclude": "Loại trừ đối tượng (biểu thức chính quy)",
|
||||
"extended_sender_acl": "Địa chỉ người gửi bên ngoài",
|
||||
"extended_sender_acl_info": "Khóa tên miền DKIM nên được nhập vào, nếu có sẵn.<br>\n Nhớ thêm máy chủ này vào bản ghi SPF TXT tương ứng.<br>\n Khi một tên miền hoặc tên miền bí danh được thêm vào máy chủ này, mà trùng với một địa chỉ bên ngoài, địa chỉ bên ngoài sẽ bị xóa.<br>\n Sử dụng @domain.tld để cho phép gửi dưới dạng *@domain.tld.",
|
||||
"force_pw_update": "Bắt buộc cập nhật mật khẩu trong lần đăng nhập tiếp theo",
|
||||
"force_pw_update_info": "Người dùng này sẽ chỉ có thể đăng nhập vào %s. Mật khẩu ứng dụng vẫn có thể sử dụng được.",
|
||||
"footer_exclude": "Loại trừ khỏi chân trang",
|
||||
"full_name": "Tên đầy đủ",
|
||||
"gal": "Danh sách địa chỉ toàn cục",
|
||||
"gal_info": "GAL chứa tất cả các đối tượng của một tên miền và không thể được chỉnh sửa bởi bất kỳ người dùng nào. Thông tin rảnh/bận trong SOGo sẽ bị thiếu nếu vô hiệu hóa! <b>Khởi động lại SOGo để áp dụng thay đổi.</b>",
|
||||
"generate": "tạo",
|
||||
"grant_types": "Các loại cấp quyền",
|
||||
"hostname": "Tên máy chủ",
|
||||
"inactive": "Không hoạt động",
|
||||
"internal": "Nội bộ",
|
||||
"internal_info": "Bí danh nội bộ chỉ có thể truy cập từ tên miền sở hữu hoặc tên miền bí danh.",
|
||||
"kind": "Loại",
|
||||
"last_modified": "Sửa đổi lần cuối",
|
||||
"lookup_mx": "Đích là một biểu thức chính quy để khớp với tên MX (<code>.*.google.com</code> để định tuyến tất cả thư nhắm đến MX kết thúc bằng google.com qua bước nhảy này)"
|
||||
}
|
||||
}
|
||||
@@ -497,7 +497,7 @@
|
||||
"pushover_token": "Pushover token 格式错误",
|
||||
"quota_not_0_not_numeric": "配额必须为数字且 >= 0",
|
||||
"recipient_map_entry_exists": "收件人映射条目 \"%s\" 已存在",
|
||||
"valkey_error": "Valkey 错误: %s",
|
||||
"redis_error": "Redis 错误: %s",
|
||||
"relayhost_invalid": "中继主机条目 %s 已存在",
|
||||
"release_send_failed": "消息不能被释放: %s",
|
||||
"reset_f2b_regex": "暂时不能重置正则表达式过滤器,请重试或在几秒后重载网页。",
|
||||
@@ -566,7 +566,7 @@
|
||||
"history_all_servers": "历史 (所有服务器)",
|
||||
"in_memory_logs": "内存日志",
|
||||
"last_modified": "最后修改",
|
||||
"log_info": "<p>Mailcow 的<b>内存日志</b>储存于 Valkey 列表中,并且每分钟自动降低到 LOG_LINES (%d) 以减少错误。\r\n <br>内存日志不是为了持久化储存的,所有使用内存日志的应用同时也会写入日志到 Docker 的守护进程的默认日志驱动中。\r\n <br>内存日志应该用于分析 (Debug) 容器中不明显的问题。</p>\r\n <p><b>外部日志</b>通过相应应用提供的 API 收集。</p>\r\n <p><b>静态日志</b>大多数为不写入日志到 Docker ,但仍然需要被持久化的活动日志 (API 日志外的)。</p>",
|
||||
"log_info": "<p>Mailcow 的<b>内存日志</b>储存于 Redis 列表中,并且每分钟自动降低到 LOG_LINES (%d) 以减少错误。\r\n <br>内存日志不是为了持久化储存的,所有使用内存日志的应用同时也会写入日志到 Docker 的守护进程的默认日志驱动中。\r\n <br>内存日志应该用于分析 (Debug) 容器中不明显的问题。</p>\r\n <p><b>外部日志</b>通过相应应用提供的 API 收集。</p>\r\n <p><b>静态日志</b>大多数为不写入日志到 Docker ,但仍然需要被持久化的活动日志 (API 日志外的)。</p>",
|
||||
"login_time": "时间",
|
||||
"logs": "日志",
|
||||
"online_users": "在线用户",
|
||||
|
||||
@@ -446,7 +446,7 @@
|
||||
"pushover_token": "Pushover 權杖格式錯誤",
|
||||
"quota_not_0_not_numeric": "容量配額必須為數值且 >= 0",
|
||||
"recipient_map_entry_exists": "收件人規則條目 \"%s\" 已存在",
|
||||
"valkey_error": "Valkey 錯誤: %s",
|
||||
"redis_error": "Redis 錯誤: %s",
|
||||
"relayhost_invalid": "無效的中繼主機規則 %s",
|
||||
"release_send_failed": "郵件無法被釋放: %s",
|
||||
"reset_f2b_regex": "暫時無法重設正規表示式過濾器,請重試或在稍後重新載入網頁。",
|
||||
@@ -506,7 +506,7 @@
|
||||
"history_all_servers": "歷史 (所有伺服器)",
|
||||
"in_memory_logs": "記憶體紀錄",
|
||||
"last_modified": "上次修改時間",
|
||||
"log_info": "<p>mailcow 的<b>記憶體紀錄</b>會被收集到 Valkey 清單中並且每分鐘自動縮減到 LOG_LINES (%d) 以避免重複撞擊 (hammering) 造成的大量記錄。\r\n<br>記憶體紀錄並不會永久保存。所有記錄到記憶體的應用程式也會同時透過預設紀錄的驅動程式寫入紀錄到 Docker 常駐程式中。\r\n<br>記憶體紀錄是設計用來為容器中的小問題除錯的。</p>\r\n<p><b>外部紀錄</b>透過應用程式提供的 API 收集。</p>\r\n<p><b>靜態紀錄</b>大多為不寫入到 Dockerd,但仍然需要被保存的活動紀錄 (API 紀錄除外)。</p>",
|
||||
"log_info": "<p>mailcow 的<b>記憶體紀錄</b>會被收集到 Redis 清單中並且每分鐘自動縮減到 LOG_LINES (%d) 以避免重複撞擊 (hammering) 造成的大量記錄。\r\n<br>記憶體紀錄並不會永久保存。所有記錄到記憶體的應用程式也會同時透過預設紀錄的驅動程式寫入紀錄到 Docker 常駐程式中。\r\n<br>記憶體紀錄是設計用來為容器中的小問題除錯的。</p>\r\n<p><b>外部紀錄</b>透過應用程式提供的 API 收集。</p>\r\n<p><b>靜態紀錄</b>大多為不寫入到 Dockerd,但仍然需要被保存的活動紀錄 (API 紀錄除外)。</p>",
|
||||
"login_time": "時間",
|
||||
"logs": "紀錄",
|
||||
"online_users": "在線使用者",
|
||||
|
||||
@@ -326,6 +326,12 @@
|
||||
<small class="text-muted">{{ lang.user.password_reset_info }}</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-4">
|
||||
<label class="control-label col-sm-3" for="user_old_pass">{{ lang.user.password_now }}</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="password" class="form-control" name="user_old_pass" autocomplete="off" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="offset-sm-3 col-sm-9">
|
||||
<button class="btn btn-xs-lg d-block d-sm-inline btn-success" data-action="edit_selected" data-id="pw_recovery_change" data-item="null" data-api-url='edit/self' data-api-attr='{}' href="#">{{ lang.user.save }}</button>
|
||||
|
||||
@@ -41,29 +41,28 @@ services:
|
||||
aliases:
|
||||
- mysql
|
||||
|
||||
valkey-mailcow:
|
||||
image: valkey/valkey:7.2.8-alpine
|
||||
entrypoint: ["/bin/sh","/valkey-conf.sh"]
|
||||
command: ["valkey-server", "/valkey.conf"]
|
||||
redis-mailcow:
|
||||
image: redis:7.4.6-alpine
|
||||
entrypoint: ["/bin/sh","/redis-conf.sh"]
|
||||
volumes:
|
||||
- valkey-vol-1:/data/
|
||||
- ./data/conf/valkey/valkey-conf.sh:/valkey-conf.sh:z
|
||||
- redis-vol-1:/data/
|
||||
- ./data/conf/redis/redis-conf.sh:/redis-conf.sh:z
|
||||
restart: always
|
||||
depends_on:
|
||||
- netfilter-mailcow
|
||||
ports:
|
||||
- "${VALKEY_PORT:-127.0.0.1:7654}:6379"
|
||||
- "${REDIS_PORT:-127.0.0.1:7654}:6379"
|
||||
environment:
|
||||
- TZ=${TZ}
|
||||
- VALKEYPASS=${VALKEYPASS}
|
||||
- VALKEYMASTERPASS=${VALKEYMASTERPASS:-}
|
||||
- REDISPASS=${REDISPASS}
|
||||
- REDISMASTERPASS=${REDISMASTERPASS:-}
|
||||
sysctls:
|
||||
- net.core.somaxconn=4096
|
||||
networks:
|
||||
mailcow-network:
|
||||
ipv4_address: ${IPV4_NETWORK:-172.22.1}.249
|
||||
aliases:
|
||||
- valkey
|
||||
- redis
|
||||
|
||||
clamd-mailcow:
|
||||
image: ghcr.io/mailcow/clamd:1.71
|
||||
@@ -94,9 +93,9 @@ services:
|
||||
- TZ=${TZ}
|
||||
- IPV4_NETWORK=${IPV4_NETWORK:-172.22.1}
|
||||
- IPV6_NETWORK=${IPV6_NETWORK:-fd4d:6169:6c63:6f77::/64}
|
||||
- VALKEY_SLAVEOF_IP=${VALKEY_SLAVEOF_IP:-}
|
||||
- VALKEY_SLAVEOF_PORT=${VALKEY_SLAVEOF_PORT:-}
|
||||
- VALKEYPASS=${VALKEYPASS}
|
||||
- REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-}
|
||||
- REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
|
||||
- REDISPASS=${REDISPASS}
|
||||
- SPAMHAUS_DQS_KEY=${SPAMHAUS_DQS_KEY:-}
|
||||
volumes:
|
||||
- ./data/hooks/rspamd:/hooks:Z
|
||||
@@ -121,7 +120,7 @@ services:
|
||||
image: ghcr.io/mailcow/phpfpm:1.94
|
||||
command: "php-fpm -d date.timezone=${TZ} -d expose_php=0"
|
||||
depends_on:
|
||||
- valkey-mailcow
|
||||
- redis-mailcow
|
||||
volumes:
|
||||
- ./data/hooks/phpfpm:/hooks:Z
|
||||
- ./data/web:/web:z
|
||||
@@ -151,9 +150,9 @@ services:
|
||||
dns:
|
||||
- ${IPV4_NETWORK:-172.22.1}.254
|
||||
environment:
|
||||
- VALKEY_SLAVEOF_IP=${VALKEY_SLAVEOF_IP:-}
|
||||
- VALKEY_SLAVEOF_PORT=${VALKEY_SLAVEOF_PORT:-}
|
||||
- VALKEYPASS=${VALKEYPASS}
|
||||
- REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-}
|
||||
- REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
|
||||
- REDISPASS=${REDISPASS}
|
||||
- LOG_LINES=${LOG_LINES:-9999}
|
||||
- TZ=${TZ}
|
||||
- DBNAME=${DBNAME}
|
||||
@@ -201,7 +200,7 @@ services:
|
||||
- phpfpm
|
||||
|
||||
sogo-mailcow:
|
||||
image: ghcr.io/mailcow/sogo:1.137
|
||||
image: ghcr.io/mailcow/sogo:1.136
|
||||
environment:
|
||||
- DBNAME=${DBNAME}
|
||||
- DBUSER=${DBUSER}
|
||||
@@ -217,9 +216,9 @@ services:
|
||||
- SOGO_URL_ENCRYPTION_KEY=${SOGO_URL_ENCRYPTION_KEY:-SOGoSuperSecret0}
|
||||
- SKIP_SOGO=${SKIP_SOGO:-n}
|
||||
- MASTER=${MASTER:-y}
|
||||
- VALKEY_SLAVEOF_IP=${VALKEY_SLAVEOF_IP:-}
|
||||
- VALKEY_SLAVEOF_PORT=${VALKEY_SLAVEOF_PORT:-}
|
||||
- VALKEYPASS=${VALKEYPASS}
|
||||
- REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-}
|
||||
- REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
|
||||
- REDISPASS=${REDISPASS}
|
||||
dns:
|
||||
- ${IPV4_NETWORK:-172.22.1}.254
|
||||
volumes:
|
||||
@@ -253,11 +252,11 @@ services:
|
||||
- sogo
|
||||
|
||||
dovecot-mailcow:
|
||||
image: ghcr.io/mailcow/dovecot:2.36
|
||||
image: ghcr.io/mailcow/dovecot:2.35
|
||||
depends_on:
|
||||
- mysql-mailcow
|
||||
- netfilter-mailcow
|
||||
- valkey-mailcow
|
||||
- redis-mailcow
|
||||
dns:
|
||||
- ${IPV4_NETWORK:-172.22.1}.254
|
||||
cap_add:
|
||||
@@ -296,9 +295,9 @@ services:
|
||||
- FTS_PROCS=${FTS_PROCS:-3}
|
||||
- MAILDIR_SUB=${MAILDIR_SUB:-}
|
||||
- MASTER=${MASTER:-y}
|
||||
- VALKEY_SLAVEOF_IP=${VALKEY_SLAVEOF_IP:-}
|
||||
- VALKEY_SLAVEOF_PORT=${VALKEY_SLAVEOF_PORT:-}
|
||||
- VALKEYPASS=${VALKEYPASS}
|
||||
- REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-}
|
||||
- REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
|
||||
- REDISPASS=${REDISPASS}
|
||||
- COMPOSE_PROJECT_NAME=${COMPOSE_PROJECT_NAME:-mailcow-dockerized}
|
||||
ports:
|
||||
- "${DOVEADM_PORT:-127.0.0.1:19991}:12345"
|
||||
@@ -340,7 +339,7 @@ services:
|
||||
- dovecot
|
||||
|
||||
postfix-mailcow:
|
||||
image: ghcr.io/mailcow/postfix:1.82
|
||||
image: ghcr.io/mailcow/postfix:1.81
|
||||
depends_on:
|
||||
mysql-mailcow:
|
||||
condition: service_started
|
||||
@@ -362,9 +361,9 @@ services:
|
||||
- DBNAME=${DBNAME}
|
||||
- DBUSER=${DBUSER}
|
||||
- DBPASS=${DBPASS}
|
||||
- VALKEY_SLAVEOF_IP=${VALKEY_SLAVEOF_IP:-}
|
||||
- VALKEY_SLAVEOF_PORT=${VALKEY_SLAVEOF_PORT:-}
|
||||
- VALKEYPASS=${VALKEYPASS}
|
||||
- REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-}
|
||||
- REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
|
||||
- REDISPASS=${REDISPASS}
|
||||
- MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME}
|
||||
- SPAMHAUS_DQS_KEY=${SPAMHAUS_DQS_KEY:-}
|
||||
cap_add:
|
||||
@@ -383,7 +382,7 @@ services:
|
||||
- postfix
|
||||
|
||||
postfix-tlspol-mailcow:
|
||||
image: ghcr.io/mailcow/postfix-tlspol:1.1
|
||||
image: ghcr.io/mailcow/postfix-tlspol:1.0
|
||||
depends_on:
|
||||
unbound-mailcow:
|
||||
condition: service_healthy
|
||||
@@ -392,9 +391,9 @@ services:
|
||||
environment:
|
||||
- LOG_LINES=${LOG_LINES:-9999}
|
||||
- TZ=${TZ}
|
||||
- VALKEY_SLAVEOF_IP=${VALKEY_SLAVEOF_IP:-}
|
||||
- VALKEY_SLAVEOF_PORT=${VALKEY_SLAVEOF_PORT:-}
|
||||
- VALKEYPASS=${VALKEYPASS}
|
||||
- REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-}
|
||||
- REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
|
||||
- REDISPASS=${REDISPASS}
|
||||
- DEV_MODE=${DEV_MODE:-n}
|
||||
restart: always
|
||||
dns:
|
||||
@@ -416,7 +415,7 @@ services:
|
||||
|
||||
nginx-mailcow:
|
||||
depends_on:
|
||||
- valkey-mailcow
|
||||
- redis-mailcow
|
||||
- php-fpm-mailcow
|
||||
- sogo-mailcow
|
||||
- rspamd-mailcow
|
||||
@@ -436,7 +435,7 @@ services:
|
||||
- PHPFPMHOST=${PHPFPMHOST:-}
|
||||
- SOGOHOST=${SOGOHOST:-}
|
||||
- RSPAMDHOST=${RSPAMDHOST:-}
|
||||
- VALKEYHOST=${VALKEYHOST:-}
|
||||
- REDISHOST=${REDISHOST:-}
|
||||
- IPV4_NETWORK=${IPV4_NETWORK:-172.22.1}
|
||||
- NGINX_USE_PROXY_PROTOCOL=${NGINX_USE_PROXY_PROTOCOL:-n}
|
||||
- TRUSTED_PROXIES=${TRUSTED_PROXIES:-}
|
||||
@@ -466,7 +465,7 @@ services:
|
||||
condition: service_started
|
||||
unbound-mailcow:
|
||||
condition: service_healthy
|
||||
image: ghcr.io/mailcow/acme:1.95
|
||||
image: ghcr.io/mailcow/acme:1.94
|
||||
dns:
|
||||
- ${IPV4_NETWORK:-172.22.1}.254
|
||||
environment:
|
||||
@@ -486,9 +485,9 @@ services:
|
||||
- ONLY_MAILCOW_HOSTNAME=${ONLY_MAILCOW_HOSTNAME:-n}
|
||||
- LE_STAGING=${LE_STAGING:-n}
|
||||
- TZ=${TZ}
|
||||
- VALKEY_SLAVEOF_IP=${VALKEY_SLAVEOF_IP:-}
|
||||
- VALKEY_SLAVEOF_PORT=${VALKEY_SLAVEOF_PORT:-}
|
||||
- VALKEYPASS=${VALKEYPASS}
|
||||
- REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-}
|
||||
- REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
|
||||
- REDISPASS=${REDISPASS}
|
||||
- SNAT_TO_SOURCE=${SNAT_TO_SOURCE:-n}
|
||||
- SNAT6_TO_SOURCE=${SNAT6_TO_SOURCE:-n}
|
||||
volumes:
|
||||
@@ -503,7 +502,7 @@ services:
|
||||
- acme
|
||||
|
||||
netfilter-mailcow:
|
||||
image: ghcr.io/mailcow/netfilter:1.64
|
||||
image: ghcr.io/mailcow/netfilter:1.63
|
||||
stop_grace_period: 30s
|
||||
restart: always
|
||||
privileged: true
|
||||
@@ -513,9 +512,9 @@ services:
|
||||
- IPV6_NETWORK=${IPV6_NETWORK:-fd4d:6169:6c63:6f77::/64}
|
||||
- SNAT_TO_SOURCE=${SNAT_TO_SOURCE:-n}
|
||||
- SNAT6_TO_SOURCE=${SNAT6_TO_SOURCE:-n}
|
||||
- VALKEY_SLAVEOF_IP=${VALKEY_SLAVEOF_IP:-}
|
||||
- VALKEY_SLAVEOF_PORT=${VALKEY_SLAVEOF_PORT:-}
|
||||
- VALKEYPASS=${VALKEYPASS}
|
||||
- REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-}
|
||||
- REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
|
||||
- REDISPASS=${REDISPASS}
|
||||
- MAILCOW_REPLICA_IP=${MAILCOW_REPLICA_IP:-}
|
||||
- DISABLE_NETFILTER_ISOLATION_RULE=${DISABLE_NETFILTER_ISOLATION_RULE:-n}
|
||||
network_mode: "host"
|
||||
@@ -539,7 +538,7 @@ services:
|
||||
- dovecot-mailcow
|
||||
- mysql-mailcow
|
||||
- acme-mailcow
|
||||
- valkey-mailcow
|
||||
- redis-mailcow
|
||||
environment:
|
||||
- IPV6_NETWORK=${IPV6_NETWORK:-fd4d:6169:6c63:6f77::/64}
|
||||
- LOG_LINES=${LOG_LINES:-9999}
|
||||
@@ -568,13 +567,13 @@ services:
|
||||
- SKIP_LETS_ENCRYPT=${SKIP_LETS_ENCRYPT:-n}
|
||||
- SKIP_SOGO=${SKIP_SOGO:-n}
|
||||
- HTTPS_PORT=${HTTPS_PORT:-443}
|
||||
- VALKEY_SLAVEOF_IP=${VALKEY_SLAVEOF_IP:-}
|
||||
- VALKEY_SLAVEOF_PORT=${VALKEY_SLAVEOF_PORT:-}
|
||||
- VALKEYPASS=${VALKEYPASS}
|
||||
- REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-}
|
||||
- REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
|
||||
- REDISPASS=${REDISPASS}
|
||||
- EXTERNAL_CHECKS_THRESHOLD=${EXTERNAL_CHECKS_THRESHOLD:-1}
|
||||
- NGINX_THRESHOLD=${NGINX_THRESHOLD:-5}
|
||||
- UNBOUND_THRESHOLD=${UNBOUND_THRESHOLD:-5}
|
||||
- VALKEY_THRESHOLD=${VALKEY_THRESHOLD:-5}
|
||||
- REDIS_THRESHOLD=${REDIS_THRESHOLD:-5}
|
||||
- MYSQL_THRESHOLD=${MYSQL_THRESHOLD:-5}
|
||||
- MYSQL_REPLICATION_THRESHOLD=${MYSQL_REPLICATION_THRESHOLD:-1}
|
||||
- SOGO_THRESHOLD=${SOGO_THRESHOLD:-3}
|
||||
@@ -598,7 +597,7 @@ services:
|
||||
- watchdog
|
||||
|
||||
dockerapi-mailcow:
|
||||
image: ghcr.io/mailcow/dockerapi:2.12
|
||||
image: ghcr.io/mailcow/dockerapi:2.11
|
||||
security_opt:
|
||||
- label=disable
|
||||
restart: always
|
||||
@@ -607,12 +606,11 @@ services:
|
||||
environment:
|
||||
- DBROOT=${DBROOT}
|
||||
- TZ=${TZ}
|
||||
- VALKEY_SLAVEOF_IP=${VALKEY_SLAVEOF_IP:-}
|
||||
- VALKEY_SLAVEOF_PORT=${VALKEY_SLAVEOF_PORT:-}
|
||||
- VALKEYPASS=${VALKEYPASS}
|
||||
- REDIS_SLAVEOF_IP=${REDIS_SLAVEOF_IP:-}
|
||||
- REDIS_SLAVEOF_PORT=${REDIS_SLAVEOF_PORT:-}
|
||||
- REDISPASS=${REDISPASS}
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- redis-vol-1:/redis-data/
|
||||
networks:
|
||||
mailcow-network:
|
||||
aliases:
|
||||
@@ -676,7 +674,6 @@ volumes:
|
||||
mysql-vol-1:
|
||||
mysql-socket-vol-1:
|
||||
redis-vol-1:
|
||||
valkey-vol-1:
|
||||
rspamd-vol-1:
|
||||
postfix-vol-1:
|
||||
postfix-tlspol-vol-1:
|
||||
|
||||
@@ -190,10 +190,9 @@ DBPASS=$(LC_ALL=C </dev/urandom tr -dc A-Za-z0-9 2> /dev/null | head -c 28)
|
||||
DBROOT=$(LC_ALL=C </dev/urandom tr -dc A-Za-z0-9 2> /dev/null | head -c 28)
|
||||
|
||||
# ------------------------------
|
||||
# VALKEY configuration
|
||||
# REDIS configuration
|
||||
# ------------------------------
|
||||
|
||||
VALKEYPASS=$(LC_ALL=C </dev/urandom tr -dc A-Za-z0-9 2> /dev/null | head -c 28)
|
||||
REDISPASS=$(LC_ALL=C </dev/urandom tr -dc A-Za-z0-9 2> /dev/null | head -c 28)
|
||||
|
||||
# ------------------------------
|
||||
# HTTP/S Bindings
|
||||
@@ -231,7 +230,7 @@ POPS_PORT=995
|
||||
SIEVE_PORT=4190
|
||||
DOVEADM_PORT=127.0.0.1:19991
|
||||
SQL_PORT=127.0.0.1:13306
|
||||
VALKEY_PORT=127.0.0.1:7654
|
||||
REDIS_PORT=127.0.0.1:7654
|
||||
|
||||
# Your timezone
|
||||
# See https://en.wikipedia.org/wiki/List_of_tz_database_time_zones for a list of timezones
|
||||
@@ -372,8 +371,7 @@ WATCHDOG_EXTERNAL_CHECKS=n
|
||||
# Enable watchdog verbose logging
|
||||
WATCHDOG_VERBOSE=n
|
||||
|
||||
# Max log lines per service to keep in Valkey logs
|
||||
|
||||
# Max log lines per service to keep in Redis logs
|
||||
LOG_LINES=9999
|
||||
|
||||
# Internal IPv4 /24 subnet, format n.n.n (expands to n.n.n.0/24)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user