mirror of
https://github.com/mailcow/mailcow-dockerized.git
synced 2026-02-18 07:06:24 +00:00
Compare commits
49 Commits
feat/valke
...
dragoangel
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
156cfbeb4d | ||
|
|
0413d26855 | ||
|
|
7b29c1f304 | ||
|
|
ae3ef391ee | ||
|
|
7313f996d3 | ||
|
|
62d16c9e56 | ||
|
|
674b41ce08 | ||
|
|
1b833be760 | ||
|
|
88adb1adf5 | ||
|
|
ec472f13cf | ||
|
|
2e1d98cc7c | ||
|
|
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}}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# Contribution Guidelines
|
||||
**_Last modified on 15th August 2024_**
|
||||
**_Last modified on 12th November 2025_**
|
||||
|
||||
First of all, thank you for wanting to provide a bugfix or a new feature for the mailcow community, it's because of your help that the project can continue to grow!
|
||||
|
||||
As we want to keep mailcow's development structured we setup these Guidelines which helps you to create your issue/pull request accordingly.
|
||||
|
||||
**PLEASE NOTE, THAT WE MIGHT CLOSE ISSUES/PULL REQUESTS IF THEY DON'T FULLFIL OUR WRITTEN GUIDELINES WRITTEN INSIDE THIS DOCUMENT**. So please check this guidelines before you propose a Issue/Pull Request.
|
||||
**PLEASE NOTE, THAT WE WILL CLOSE ISSUES/PULL REQUESTS IF THEY DON'T FULLFIL OUR WRITTEN GUIDELINES WRITTEN INSIDE THIS DOCUMENT**. So please check this guidelines before you propose a Issue/Pull Request.
|
||||
|
||||
## Topics
|
||||
|
||||
@@ -27,14 +27,18 @@ However, please note the following regarding pull requests:
|
||||
6. Please **ALWAYS** create the actual pull request against the staging branch and **NEVER** directly against the master branch. *If you forget to do this, our moobot will remind you to switch the branch to staging.*
|
||||
7. Wait for a merge commit: It may happen that we do not accept your pull request immediately or sometimes not at all for various reasons. Please do not be disappointed if this is the case. We always endeavor to incorporate any meaningful changes from the community into the mailcow project.
|
||||
8. If you are planning larger and therefore more complex pull requests, it would be advisable to first announce this in a separate issue and then start implementing it after the idea has been accepted in order to avoid unnecessary frustration and effort!
|
||||
9. If your PR requires a Docker image rebuild (changes to Dockerfiles or files in data/Dockerfiles/), update the image tag in docker-compose.yml. Use the base-image versioning (e.g. ghcr.io/mailcow/sogo:5.12.4 → :5.12.5 for version bumps; append a letter for patch fixes, e.g. :5.12.4a). Follow this scheme.
|
||||
|
||||
---
|
||||
|
||||
## Issue Reporting
|
||||
**_Last modified on 15th August 2024_**
|
||||
**_Last modified on 12th November 2025_**
|
||||
|
||||
If you plan to report a issue within mailcow please read and understand the following rules:
|
||||
|
||||
### Security disclosures / Security-related fixes
|
||||
- Security vulnerabilities and security fixes must always be reported confidentially first to the contact address specified in SECURITY.md before they are integrated, published, or publicly disclosed in issues/PRs. Please wait for a response from the specified contact to ensure coordinated and responsible disclosure.
|
||||
|
||||
### Issue Reporting Guidelines
|
||||
|
||||
1. **ONLY** use the issue tracker for bug reports or improvement requests and NOT for support questions. For support questions you can either contact the [mailcow community on Telegram](https://docs.mailcow.email/#community-support-and-chat) or the mailcow team directly in exchange for a [support fee](https://docs.mailcow.email/#commercial-support).
|
||||
|
||||
@@ -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
|
||||
RUN apt update && apt install pigz zstd -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/
|
||||
@@ -204,16 +204,17 @@ EOF
|
||||
# Create random master Password for SOGo SSO
|
||||
RAND_PASS=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 32 | head -n 1)
|
||||
echo -n ${RAND_PASS} > /etc/phpfpm/sogo-sso.pass
|
||||
# Creating additional creds file for SOGo notify crons (calendars, etc)
|
||||
echo -n ${RAND_USER}@mailcow.local:${RAND_PASS} > /etc/sogo/cron.creds
|
||||
cat <<EOF > /etc/dovecot/sogo-sso.conf
|
||||
# Autogenerated by mailcow
|
||||
passdb {
|
||||
driver = static
|
||||
args = allow_real_nets=${IPV4_NETWORK}.248/32 password={plain}${RAND_PASS}
|
||||
args = allow_nets=${IPV4_NETWORK}.248/32 password={plain}${RAND_PASS}
|
||||
}
|
||||
EOF
|
||||
|
||||
# Creating additional creds file for SOGo notify crons (calendars, etc) (dummy user, sso password)
|
||||
echo -n ${RAND_USER}@mailcow.local:${RAND_PASS} > /etc/sogo/cron.creds
|
||||
|
||||
if [[ "${MASTER}" =~ ^([nN][oO]|[nN])+$ ]]; then
|
||||
# Toggling MASTER will result in a rebuild of containers, so the quota script will be recreated
|
||||
cat <<'EOF' > /usr/local/bin/quota_notify.py
|
||||
@@ -341,8 +342,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
|
||||
|
||||
@@ -167,7 +167,7 @@ DELIMITER //
|
||||
CREATE EVENT clean_spamalias
|
||||
ON SCHEDULE EVERY 1 DAY DO
|
||||
BEGIN
|
||||
DELETE FROM spamalias WHERE validity < UNIX_TIMESTAMP();
|
||||
DELETE FROM spamalias WHERE validity < UNIX_TIMESTAMP() AND permanent = 0;
|
||||
END;
|
||||
//
|
||||
DELIMITER ;
|
||||
|
||||
@@ -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,18 @@ 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_SERVER="${REDIS_SLAVEOF_IP}"
|
||||
export REDIS_PORT="${REDIS_SLAVEOF_PORT}"
|
||||
else
|
||||
export VALKEY_CMDLINE="redis-cli -h valkey -p 6379 -a ${VALKEYPASS} --no-auth-warning"
|
||||
export REDIS_SERVER="redis"
|
||||
export REDIS_PORT="6379"
|
||||
fi
|
||||
|
||||
until [[ $(${VALKEY_CMDLINE} PING) == "PONG" ]]; do
|
||||
echo "Waiting for Valkey..."
|
||||
export REDIS_CMDLINE="redis-cli -h ${REDIS_SERVER} -p ${REDIS_PORT} -a ${REDISPASS} --no-auth-warning"
|
||||
|
||||
until [[ $(${REDIS_CMDLINE} PING) == "PONG" ]]; do
|
||||
echo "Waiting for Redis..."
|
||||
sleep 2
|
||||
done
|
||||
|
||||
@@ -37,16 +41,13 @@ echo "Postfix OK"
|
||||
cat <<EOF > /etc/postfix-tlspol/config.yaml
|
||||
server:
|
||||
address: 0.0.0.0:8642
|
||||
|
||||
log-level: ${LOGLVL}
|
||||
|
||||
prefetch: true
|
||||
|
||||
cache-file: /var/lib/postfix-tlspol/cache.db
|
||||
|
||||
dns:
|
||||
# must support DNSSEC
|
||||
address: 127.0.0.11:53
|
||||
redis:
|
||||
address: ${REDIS_SERVER}:${REDIS_PORT}
|
||||
db: 2
|
||||
EOF
|
||||
|
||||
/usr/local/bin/postfix-tlspol -config /etc/postfix-tlspol/config.yaml
|
||||
/usr/local/bin/postfix-tlspol -config /etc/postfix-tlspol/config.yaml
|
||||
|
||||
@@ -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 "$@"
|
||||
|
||||
@@ -390,7 +390,7 @@ hosts = unix:/var/run/mysqld/mysqld.sock
|
||||
dbname = ${DBNAME}
|
||||
query = SELECT goto FROM spamalias
|
||||
WHERE address='%s'
|
||||
AND validity >= UNIX_TIMESTAMP()
|
||||
AND (validity >= UNIX_TIMESTAMP() OR permanent != 0)
|
||||
EOF
|
||||
|
||||
if [ ! -f /opt/postfix/conf/dns_blocklists.cf ]; then
|
||||
@@ -524,4 +524,4 @@ if [[ $? != 0 ]]; then
|
||||
else
|
||||
postfix -c /opt/postfix/conf start
|
||||
sleep 126144000
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -50,10 +50,6 @@ cat <<EOF > /var/lib/sogo/GNUstep/Defaults/sogod.plist
|
||||
<string>YES</string>
|
||||
<key>SOGoEncryptionKey</key>
|
||||
<string>${RAND_PASS}</string>
|
||||
<key>SOGoURLEncryptionEnabled</key>
|
||||
<string>YES</string>
|
||||
<key>SOGoURLEncryptionPassphrase</key>
|
||||
<string>${SOGO_URL_ENCRYPTION_KEY}</string>
|
||||
<key>OCSAdminURL</key>
|
||||
<string>mysql://${DBUSER}:${DBPASS}@%2Fvar%2Frun%2Fmysqld%2Fmysqld.sock/${DBNAME}/sogo_admin</string>
|
||||
<key>OCSCacheFolderURL</key>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -13,6 +13,7 @@ events {
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
server_tokens off;
|
||||
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
|
||||
@@ -14,7 +14,6 @@ ssl_session_tickets off;
|
||||
|
||||
add_header Strict-Transport-Security "max-age=15768000;";
|
||||
add_header X-Content-Type-Options nosniff;
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
add_header X-Robots-Tag none;
|
||||
add_header X-Download-Options noopen;
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -86,6 +86,12 @@
|
||||
SOGoMaximumFailedLoginInterval = 900;
|
||||
SOGoFailedLoginBlockInterval = 900;
|
||||
|
||||
// Enable SOGo URL Description for GDPR compliance, this may cause some issues with calendars and contacts. Also uncomment the encryption key below to use it.
|
||||
//SOGoURLEncryptionEnabled = NO;
|
||||
|
||||
// Set a 16 character encryption key for SOGo URL Description, change this to your own value
|
||||
//SOGoURLPathEncryptionKey = "SOGoSuperSecret0";
|
||||
|
||||
GCSChannelCollectionTimer = 60;
|
||||
GCSChannelExpireAge = 60;
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -49,6 +49,12 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
// Default to 1 yr
|
||||
$_data["validity"] = 8760;
|
||||
}
|
||||
if (isset($_data["permanent"]) && filter_var($_data["permanent"], FILTER_VALIDATE_BOOL)) {
|
||||
$permanent = 1;
|
||||
}
|
||||
else {
|
||||
$permanent = 0;
|
||||
}
|
||||
$domain = $_data['domain'];
|
||||
$description = $_data['description'];
|
||||
$valid_domains[] = mailbox('get', 'mailbox_details', $username)['domain'];
|
||||
@@ -65,13 +71,14 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
return false;
|
||||
}
|
||||
$validity = strtotime("+" . $_data["validity"] . " hour");
|
||||
$stmt = $pdo->prepare("INSERT INTO `spamalias` (`address`, `description`, `goto`, `validity`) VALUES
|
||||
(:address, :description, :goto, :validity)");
|
||||
$stmt = $pdo->prepare("INSERT INTO `spamalias` (`address`, `description`, `goto`, `validity`, `permanent`) VALUES
|
||||
(:address, :description, :goto, :validity, :permanent)");
|
||||
$stmt->execute(array(
|
||||
':address' => readable_random_string(rand(rand(3, 9), rand(3, 9))) . '.' . readable_random_string(rand(rand(3, 9), rand(3, 9))) . '@' . $domain,
|
||||
':description' => $description,
|
||||
':goto' => $username,
|
||||
':validity' => $validity
|
||||
':validity' => $validity,
|
||||
':permanent' => $permanent
|
||||
));
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
@@ -628,13 +635,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 +653,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 +981,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 +995,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),
|
||||
@@ -2103,15 +2110,23 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
);
|
||||
continue;
|
||||
}
|
||||
if (empty($_data['validity'])) {
|
||||
if (empty($_data['validity']) && empty($_data['permanent'])) {
|
||||
continue;
|
||||
}
|
||||
$validity = round((int)time() + ($_data['validity'] * 3600));
|
||||
$stmt = $pdo->prepare("UPDATE `spamalias` SET `validity` = :validity WHERE
|
||||
if (isset($_data['permanent']) && filter_var($_data['permanent'], FILTER_VALIDATE_BOOL)) {
|
||||
$permanent = 1;
|
||||
$validity = 0;
|
||||
}
|
||||
else if (isset($_data['validity'])) {
|
||||
$permanent = 0;
|
||||
$validity = round((int)time() + ($_data['validity'] * 3600));
|
||||
}
|
||||
$stmt = $pdo->prepare("UPDATE `spamalias` SET `validity` = :validity, `permanent` = :permanent WHERE
|
||||
`address` = :address");
|
||||
$stmt->execute(array(
|
||||
':address' => $address,
|
||||
':validity' => $validity
|
||||
':validity' => $validity,
|
||||
':permanent' => $permanent
|
||||
));
|
||||
$_SESSION['return'][] = array(
|
||||
'type' => 'success',
|
||||
@@ -2147,42 +2162,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;
|
||||
}
|
||||
@@ -4584,10 +4599,12 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
`description`,
|
||||
`validity`,
|
||||
`created`,
|
||||
`modified`
|
||||
`modified`,
|
||||
`permanent`
|
||||
FROM `spamalias`
|
||||
WHERE `goto` = :username
|
||||
AND `validity` >= :unixnow");
|
||||
AND (`validity` >= :unixnow
|
||||
OR `permanent` != 0)");
|
||||
$stmt->execute(array(':username' => $_data, ':unixnow' => time()));
|
||||
$tladata = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
return $tladata;
|
||||
@@ -4603,10 +4620,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 +4634,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;
|
||||
}
|
||||
@@ -5162,7 +5179,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||
$stmt = $pdo->prepare("SELECT COALESCE(SUM(`quota`), 0) as `in_use` FROM `mailbox` WHERE (`kind` = '' OR `kind` = NULL) AND `domain` = :domain AND `username` != :username");
|
||||
$stmt->execute(array(':domain' => $row['domain'], ':username' => $_data));
|
||||
$MailboxUsage = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$stmt = $pdo->prepare("SELECT IFNULL(COUNT(`address`), 0) AS `sa_count` FROM `spamalias` WHERE `goto` = :address AND `validity` >= :unixnow");
|
||||
$stmt = $pdo->prepare("SELECT IFNULL(COUNT(`address`), 0) AS `sa_count` FROM `spamalias` WHERE `goto` = :address AND (`validity` >= :unixnow OR `permanent` != 0)");
|
||||
$stmt->execute(array(':address' => $_data, ':unixnow' => time()));
|
||||
$SpamaliasUsage = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
$mailboxdata['max_new_quota'] = ($DomainQuota['quota'] * 1048576) - $MailboxUsage['in_use'];
|
||||
@@ -5636,14 +5653,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 +5786,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 +5972,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;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ function init_db_schema()
|
||||
try {
|
||||
global $pdo;
|
||||
|
||||
$db_version = "07102025_1015";
|
||||
$db_version = "10312025_0525";
|
||||
|
||||
$stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
|
||||
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||
@@ -554,7 +554,8 @@ function init_db_schema()
|
||||
"description" => "TEXT NOT NULL",
|
||||
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
|
||||
"modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP",
|
||||
"validity" => "INT(11)"
|
||||
"validity" => "INT(11)",
|
||||
"permanent" => "TINYINT(1) NOT NULL DEFAULT '0'"
|
||||
),
|
||||
"keys" => array(
|
||||
"primary" => array(
|
||||
|
||||
@@ -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>
|
||||
`);
|
||||
})
|
||||
@@ -176,6 +175,10 @@ jQuery(function($){
|
||||
'</div>';
|
||||
item.chkbox = '<input type="checkbox" class="form-check-input" data-id="tla" name="multi_select" value="' + encodeURIComponent(item.address) + '" />';
|
||||
item.address = escapeHtml(item.address);
|
||||
item.validity = {
|
||||
value: item.validity,
|
||||
permanent: item.permanent
|
||||
};
|
||||
}
|
||||
else {
|
||||
item.chkbox = '<input type="checkbox" class="form-check-input" disabled />';
|
||||
@@ -219,9 +222,21 @@ jQuery(function($){
|
||||
title: lang.alias_valid_until,
|
||||
data: 'validity',
|
||||
defaultContent: '',
|
||||
createdCell: function(td, cellData) {
|
||||
createSortableDate(td, cellData)
|
||||
}
|
||||
render: function (data, type) {
|
||||
var date = new Date(data.value ? data.value * 1000 : 0);
|
||||
switch (type) {
|
||||
case "sort":
|
||||
if (data.permanent) {
|
||||
return 0;
|
||||
}
|
||||
return date.getTime();
|
||||
default:
|
||||
if (data.permanent) {
|
||||
return lang.forever;
|
||||
}
|
||||
return date.toLocaleDateString(LOCALE, DATETIME_FORMAT);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: lang.created_on,
|
||||
|
||||
@@ -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",
|
||||
@@ -987,7 +987,7 @@
|
||||
"sogo_visible": "Alias Sichtbarkeit in SOGo",
|
||||
"sogo_visible_n": "Alias in SOGo verbergen",
|
||||
"sogo_visible_y": "Alias in SOGo anzeigen",
|
||||
"spam_aliases": "Temp. Alias",
|
||||
"spam_aliases": "Spam-Alias",
|
||||
"stats": "Statistik",
|
||||
"status": "Status",
|
||||
"sync_jobs": "Synchronisationen",
|
||||
@@ -1281,7 +1281,9 @@
|
||||
"encryption": "Verschlüsselung",
|
||||
"excludes": "Ausschlüsse",
|
||||
"expire_in": "Ungültig in",
|
||||
"expire_never": "Niemals ungültig",
|
||||
"fido2_webauthn": "FIDO2/WebAuthn",
|
||||
"forever": "Für immer",
|
||||
"force_pw_update": "Das Passwort für diesen Benutzer <b>muss</b> geändert werden, damit die Zugriffssperre auf die Groupware-Komponenten wieder freigeschaltet wird.",
|
||||
"from": "von",
|
||||
"generate": "generieren",
|
||||
@@ -1346,7 +1348,8 @@
|
||||
"sogo_profile_reset": "SOGo-Profil zurücksetzen",
|
||||
"sogo_profile_reset_help": "Das Profil wird inklusive <b>aller</b> Kalender- und Kontaktdaten <b>unwiederbringlich gelöscht</b>.",
|
||||
"sogo_profile_reset_now": "Profil jetzt zurücksetzen",
|
||||
"spam_aliases": "Temporäre E-Mail-Aliasse",
|
||||
"spam_aliases": "Spam E-Mail-Aliasse",
|
||||
"spam_aliases_info": "Ein Spam-Alias ist eine temporäre E-Mailadresse, die benutzt werden kann, um eine echte E-Mail Adressen zu schützen. <br>Optional kann eine Ablaufzeit gesetzt werden, sodass der Alias nach dem definierten Zeitraum automatisch deaktiviert wird, was missbrauchte oder geleakte Adressen effektiv entsorgt.",
|
||||
"spam_score_reset": "Auf Server-Standard zurücksetzen",
|
||||
"spamfilter": "Spamfilter",
|
||||
"spamfilter_behavior": "Bewertung",
|
||||
|
||||
@@ -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",
|
||||
@@ -1288,7 +1288,9 @@
|
||||
"encryption": "Encryption",
|
||||
"excludes": "Excludes",
|
||||
"expire_in": "Expire in",
|
||||
"expire_never": "Never Expire",
|
||||
"fido2_webauthn": "FIDO2/WebAuthn",
|
||||
"forever": "Forever",
|
||||
"force_pw_update": "You <b>must</b> set a new password to be able to access groupware related services.",
|
||||
"from": "from",
|
||||
"generate": "generate",
|
||||
@@ -1355,7 +1357,8 @@
|
||||
"sogo_profile_reset": "Reset SOGo profile",
|
||||
"sogo_profile_reset_help": "This will destroy a user's SOGo profile and <b>delete all contact and calendar data irretrievable</b>.",
|
||||
"sogo_profile_reset_now": "Reset profile now",
|
||||
"spam_aliases": "Temporary email aliases",
|
||||
"spam_aliases": "Spam email aliases",
|
||||
"spam_aliases_info": "A spam alias is a temporary email address that can be used to protect real email addresses. <br>Optionally, an expiration time can be set so that the alias is automatically deactivated after the defined period, effectively disposing of abused or leaked addresses.",
|
||||
"spam_score_reset": "Reset to server default",
|
||||
"spamfilter": "Spam filter",
|
||||
"spamfilter_behavior": "Rating",
|
||||
|
||||
@@ -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",
|
||||
@@ -1084,6 +1084,7 @@
|
||||
"aliases_send_as_all": "No verificar permisos del remitente para los siguientes dominios (y sus aliases)",
|
||||
"change_password": "Cambiar contraseña",
|
||||
"create_syncjob": "Crear nuevo trabajo de sincronización",
|
||||
"created_on": "Creado",
|
||||
"daily": "Cada día",
|
||||
"day": "Día",
|
||||
"description": "Descripción",
|
||||
@@ -1095,6 +1096,9 @@
|
||||
"edit": "Editar",
|
||||
"encryption": "Cifrado",
|
||||
"excludes": "Excluye",
|
||||
"expire_in": "Expirará en",
|
||||
"expire_never": "Nunca expirará",
|
||||
"forever": "Siempre",
|
||||
"hour": "Hora",
|
||||
"hourly": "Cada hora",
|
||||
"hours": "Horas",
|
||||
@@ -1115,7 +1119,8 @@
|
||||
"shared_aliases": "Alias compartidos",
|
||||
"shared_aliases_desc": "Los alias compartidos no se ven afectados por la configuración específica del usuario, como el filtro de correo no deseado o la política de cifrado. Los filtros de spam correspondientes solo pueden ser realizados por un administrador como una política de dominio.",
|
||||
"sogo_profile_reset": "Resetear perfil SOGo",
|
||||
"spam_aliases": "Alias de email temporales",
|
||||
"spam_aliases": "Alias de email de spam",
|
||||
"spam_aliases_info": "Un alias de spam es una dirección de correo electrónico temporal que se puede usar para proteger direcciones de correo electrónico reales. <br>Opcionalmente, se puede establecer un tiempo de expiración para que el alias se desactive automáticamente después del período definido, eliminando efectivamente las direcciones abusadas o filtradas.",
|
||||
"spamfilter": "Filtro anti-spam",
|
||||
"spamfilter_behavior": "Clasificación",
|
||||
"spamfilter_bl": "Lista negra",
|
||||
|
||||
@@ -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": "メモリ",
|
||||
@@ -1187,6 +1187,7 @@
|
||||
"created_on": "作成日",
|
||||
"daily": "毎日",
|
||||
"day": "日",
|
||||
"description": "説明",
|
||||
"delete_ays": "削除プロセスを確認してください。",
|
||||
"direct_aliases": "直接エイリアスアドレス",
|
||||
"direct_aliases_desc": "直接エイリアスアドレスは、スパムフィルターおよびTLSポリシー設定の影響を受けます。",
|
||||
@@ -1201,7 +1202,9 @@
|
||||
"encryption": "暗号化",
|
||||
"excludes": "除外",
|
||||
"expire_in": "有効期限まで",
|
||||
"expire_never": "有効期限なし",
|
||||
"fido2_webauthn": "FIDO2/WebAuthn",
|
||||
"forever": "有効期限なし",
|
||||
"force_pw_update": "グループウェア関連サービスにアクセスするには、新しいパスワードを<b>必ず</b>設定する必要があります。",
|
||||
"from": "送信元",
|
||||
"generate": "生成",
|
||||
|
||||
@@ -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.",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user