mirror of
https://github.com/mailcow/mailcow-dockerized.git
synced 2026-03-22 22:42:44 +00:00
Compare commits
3 Commits
copilot/fi
...
feat/valke
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c0f06bfc52 | ||
|
|
0698159f07 | ||
|
|
c27000215e |
@@ -14,7 +14,7 @@ jobs:
|
|||||||
pull-requests: write
|
pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
- name: Mark/Close Stale Issues and Pull Requests 🗑️
|
- name: Mark/Close Stale Issues and Pull Requests 🗑️
|
||||||
uses: actions/stale@v10.1.1
|
uses: actions/stale@v10.1.0
|
||||||
with:
|
with:
|
||||||
repo-token: ${{ secrets.STALE_ACTION_PAT }}
|
repo-token: ${{ secrets.STALE_ACTION_PAT }}
|
||||||
days-before-stale: 60
|
days-before-stale: 60
|
||||||
|
|||||||
2
.github/workflows/image_builds.yml
vendored
2
.github/workflows/image_builds.yml
vendored
@@ -27,7 +27,7 @@ jobs:
|
|||||||
- "watchdog-mailcow"
|
- "watchdog-mailcow"
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v5
|
||||||
- name: Setup Docker
|
- name: Setup Docker
|
||||||
run: |
|
run: |
|
||||||
curl -sSL https://get.docker.com/ | CHANNEL=stable sudo sh
|
curl -sSL https://get.docker.com/ | CHANNEL=stable sudo sh
|
||||||
|
|||||||
4
.github/workflows/pr_to_nightly.yml
vendored
4
.github/workflows/pr_to_nightly.yml
vendored
@@ -8,11 +8,11 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v5
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Run the Action
|
- name: Run the Action
|
||||||
uses: devops-infra/action-pull-request@v1.0.2
|
uses: devops-infra/action-pull-request@v0.6.1
|
||||||
with:
|
with:
|
||||||
github_token: ${{ secrets.PRTONIGHTLY_ACTION_PAT }}
|
github_token: ${{ secrets.PRTONIGHTLY_ACTION_PAT }}
|
||||||
title: Automatic PR to nightly from ${{ github.event.repository.updated_at}}
|
title: Automatic PR to nightly from ${{ github.event.repository.updated_at}}
|
||||||
|
|||||||
2
.github/workflows/rebuild_backup_image.yml
vendored
2
.github/workflows/rebuild_backup_image.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
|||||||
packages: write
|
packages: write
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v3
|
uses: docker/setup-qemu-action@v3
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v6
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Generate postscreen_access.cidr
|
- name: Generate postscreen_access.cidr
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
# Contribution Guidelines
|
# Contribution Guidelines
|
||||||
**_Last modified on 12th November 2025_**
|
**_Last modified on 15th August 2024_**
|
||||||
|
|
||||||
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!
|
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.
|
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 WILL CLOSE ISSUES/PULL REQUESTS IF THEY DON'T FULFILL OUR WRITTEN GUIDELINES WRITTEN INSIDE THIS DOCUMENT**. So please check this guidelines before you propose a Issue/Pull Request.
|
**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.
|
||||||
|
|
||||||
## Topics
|
## Topics
|
||||||
|
|
||||||
@@ -27,18 +27,14 @@ 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.*
|
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.
|
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!
|
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
|
## Issue Reporting
|
||||||
**_Last modified on 12th November 2025_**
|
**_Last modified on 15th August 2024_**
|
||||||
|
|
||||||
If you plan to report a issue within mailcow please read and understand the following rules:
|
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
|
### 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).
|
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).
|
||||||
|
|||||||
@@ -38,45 +38,45 @@ get_docker_version(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
get_compose_type(){
|
get_compose_type(){
|
||||||
if docker compose > /dev/null 2>&1; then
|
if docker compose > /dev/null 2>&1; then
|
||||||
if docker compose version --short | grep -e "^[2-9]\." -e "^v[2-9]\." -e "^[1-9][0-9]\." -e "^v[1-9][0-9]\." > /dev/null 2>&1; then
|
if docker compose version --short | grep -e "^2." -e "^v2." > /dev/null 2>&1; then
|
||||||
COMPOSE_VERSION=native
|
COMPOSE_VERSION=native
|
||||||
COMPOSE_COMMAND="docker compose"
|
COMPOSE_COMMAND="docker compose"
|
||||||
if [[ "$caller" == "update.sh" ]]; then
|
if [[ "$caller" == "update.sh" ]]; then
|
||||||
sed -i 's/^DOCKER_COMPOSE_VERSION=.*/DOCKER_COMPOSE_VERSION=native/' "$SCRIPT_DIR/mailcow.conf"
|
sed -i 's/^DOCKER_COMPOSE_VERSION=.*/DOCKER_COMPOSE_VERSION=native/' "$SCRIPT_DIR/mailcow.conf"
|
||||||
fi
|
fi
|
||||||
echo -e "\e[33mFound Docker Compose Plugin (native).\e[0m"
|
echo -e "\e[33mFound Docker Compose Plugin (native).\e[0m"
|
||||||
echo -e "\e[33mSetting the DOCKER_COMPOSE_VERSION Variable to native\e[0m"
|
echo -e "\e[33mSetting the DOCKER_COMPOSE_VERSION Variable to native\e[0m"
|
||||||
sleep 2
|
sleep 2
|
||||||
echo -e "\e[33mNotice: You'll have to update this Compose Version via your Package Manager manually!\e[0m"
|
echo -e "\e[33mNotice: You'll have to update this Compose Version via your Package Manager manually!\e[0m"
|
||||||
else
|
else
|
||||||
echo -e "\e[31mCannot find Docker Compose with a Version Higher than 2.X.X.\e[0m"
|
echo -e "\e[31mCannot find Docker Compose with a Version Higher than 2.X.X.\e[0m"
|
||||||
echo -e "\e[31mPlease update/install it manually regarding to this doc site: https://docs.mailcow.email/install/\e[0m"
|
echo -e "\e[31mPlease update/install it manually regarding to this doc site: https://docs.mailcow.email/install/\e[0m"
|
||||||
exit 1
|
exit 1
|
||||||
|
fi
|
||||||
|
elif docker-compose > /dev/null 2>&1; then
|
||||||
|
if ! [[ $(alias docker-compose 2> /dev/null) ]] ; then
|
||||||
|
if docker-compose version --short | grep "^2." > /dev/null 2>&1; then
|
||||||
|
COMPOSE_VERSION=standalone
|
||||||
|
COMPOSE_COMMAND="docker-compose"
|
||||||
|
if [[ "$caller" == "update.sh" ]]; then
|
||||||
|
sed -i 's/^DOCKER_COMPOSE_VERSION=.*/DOCKER_COMPOSE_VERSION=standalone/' "$SCRIPT_DIR/mailcow.conf"
|
||||||
|
fi
|
||||||
|
echo -e "\e[33mFound Docker Compose Standalone.\e[0m"
|
||||||
|
echo -e "\e[33mSetting the DOCKER_COMPOSE_VERSION Variable to standalone\e[0m"
|
||||||
|
sleep 2
|
||||||
|
echo -e "\e[33mNotice: For an automatic update of docker-compose please use the update_compose.sh scripts located at the helper-scripts folder.\e[0m"
|
||||||
|
else
|
||||||
|
echo -e "\e[31mCannot find Docker Compose with a Version Higher than 2.X.X.\e[0m"
|
||||||
|
echo -e "\e[31mPlease update/install manually regarding to this doc site: https://docs.mailcow.email/install/\e[0m"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
elif docker-compose > /dev/null 2>&1; then
|
|
||||||
if ! [[ $(alias docker-compose 2> /dev/null) ]] ; then
|
|
||||||
if docker-compose version --short | grep -e "^[2-9]\." -e "^[1-9][0-9]\." > /dev/null 2>&1; then
|
|
||||||
COMPOSE_VERSION=standalone
|
|
||||||
COMPOSE_COMMAND="docker-compose"
|
|
||||||
if [[ "$caller" == "update.sh" ]]; then
|
|
||||||
sed -i 's/^DOCKER_COMPOSE_VERSION=.*/DOCKER_COMPOSE_VERSION=standalone/' "$SCRIPT_DIR/mailcow.conf"
|
|
||||||
fi
|
|
||||||
echo -e "\e[33mFound Docker Compose Standalone.\e[0m"
|
|
||||||
echo -e "\e[33mSetting the DOCKER_COMPOSE_VERSION Variable to standalone\e[0m"
|
|
||||||
sleep 2
|
|
||||||
echo -e "\e[33mNotice: For an automatic update of docker-compose please use the update_compose.sh scripts located at the helper-scripts folder.\e[0m"
|
|
||||||
else
|
else
|
||||||
echo -e "\e[31mCannot find Docker Compose with a Version Higher than 2.X.X.\e[0m"
|
echo -e "\e[31mCannot find Docker Compose.\e[0m"
|
||||||
echo -e "\e[31mPlease update/install manually regarding to this doc site: https://docs.mailcow.email/install/\e[0m"
|
echo -e "\e[31mPlease install it regarding to this doc site: https://docs.mailcow.email/install/\e[0m"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo -e "\e[31mCannot find Docker Compose.\e[0m"
|
|
||||||
echo -e "\e[31mPlease install it regarding to this doc site: https://docs.mailcow.email/install/\e[0m"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
detect_bad_asn() {
|
detect_bad_asn() {
|
||||||
|
|||||||
@@ -139,13 +139,9 @@ docker_daemon_edit(){
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo -e "${YELLOW}User declined Docker update – skipping Docker daemon configuration.${NC}"
|
echo -e "${YELLOW}User declined Docker update – please insert these changes manually:${NC}"
|
||||||
echo -e "${YELLOW}IPv6 will be disabled for mailcow.${NC}"
|
|
||||||
echo ""
|
|
||||||
echo -e "${YELLOW}If you change your mind later, please insert these changes manually to $DOCKER_DAEMON_CONFIG:${NC}"
|
|
||||||
echo "${MISSING[*]}"
|
echo "${MISSING[*]}"
|
||||||
echo ""
|
exit 1
|
||||||
return 1
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -189,23 +185,9 @@ EOF
|
|||||||
(command -v systemctl &>/dev/null && systemctl restart docker) || service docker restart
|
(command -v systemctl &>/dev/null && systemctl restart docker) || service docker restart
|
||||||
echo "Docker restarted."
|
echo "Docker restarted."
|
||||||
else
|
else
|
||||||
echo -e "${YELLOW}User declined to create daemon.json – skipping Docker daemon configuration.${NC}"
|
echo "User declined to create daemon.json – please manually merge the docker daemon with these configs:"
|
||||||
echo -e "${YELLOW}IPv6 will be disabled for mailcow.${NC}"
|
echo "${MISSING[*]}"
|
||||||
echo ""
|
exit 1
|
||||||
echo -e "${YELLOW}If you change your mind later, please create $DOCKER_DAEMON_CONFIG with these settings:${NC}"
|
|
||||||
if [[ -n "$DOCKER_MAJOR" && "$DOCKER_MAJOR" -lt 27 ]]; then
|
|
||||||
echo ' "ipv6": true,'
|
|
||||||
echo ' "fixed-cidr-v6": "fd00:dead:beef:c0::/80",'
|
|
||||||
echo ' "ip6tables": true,'
|
|
||||||
echo ' "experimental": true'
|
|
||||||
elif [[ -n "$DOCKER_MAJOR" && "$DOCKER_MAJOR" -lt 28 ]]; then
|
|
||||||
echo ' "ipv6": true,'
|
|
||||||
echo ' "fixed-cidr-v6": "fd00:dead:beef:c0::/80"'
|
|
||||||
else
|
|
||||||
echo ' "ipv6": true'
|
|
||||||
fi
|
|
||||||
echo ""
|
|
||||||
return 1
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@@ -241,22 +223,7 @@ configure_ipv6() {
|
|||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! docker_daemon_edit; then
|
docker_daemon_edit
|
||||||
# User declined Docker daemon configuration
|
|
||||||
# When called from update.sh, MAILCOW_CONF is set and we modify the existing file
|
|
||||||
# When called from generate_config.sh, MAILCOW_CONF is not set and we export IPV6_BOOL
|
|
||||||
if [[ -n "$MAILCOW_CONF" && -f "$MAILCOW_CONF" ]]; then
|
|
||||||
if grep -q '^ENABLE_IPV6=' "$MAILCOW_CONF"; then
|
|
||||||
sed -i 's/^ENABLE_IPV6=.*/ENABLE_IPV6=false/' "$MAILCOW_CONF"
|
|
||||||
else
|
|
||||||
echo "ENABLE_IPV6=false" >> "$MAILCOW_CONF"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
export IPV6_BOOL=false
|
|
||||||
fi
|
|
||||||
echo "IPv6 configuration complete: ENABLE_IPV6=false"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ -n "$MAILCOW_CONF" && -f "$MAILCOW_CONF" ]]; then
|
if [[ -n "$MAILCOW_CONF" && -f "$MAILCOW_CONF" ]]; then
|
||||||
if grep -q '^ENABLE_IPV6=' "$MAILCOW_CONF"; then
|
if grep -q '^ENABLE_IPV6=' "$MAILCOW_CONF"; then
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ set -o pipefail
|
|||||||
exec 5>&1
|
exec 5>&1
|
||||||
|
|
||||||
# Do not attempt to write to slave
|
# Do not attempt to write to slave
|
||||||
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
|
if [[ ! -z ${VALKEY_SLAVEOF_IP} ]]; then
|
||||||
export REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} -a ${REDISPASS} --no-auth-warning"
|
export VALKEY_CMDLINE="redis-cli -h ${VALKEY_SLAVEOF_IP} -p ${VALKEY_SLAVEOF_PORT} -a ${VALKEYPASS} --no-auth-warning"
|
||||||
else
|
else
|
||||||
export REDIS_CMDLINE="redis-cli -h redis -p 6379 -a ${REDISPASS} --no-auth-warning"
|
export VALKEY_CMDLINE="redis-cli -h valkey-mailcow -p 6379 -a ${VALKEYPASS} --no-auth-warning"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
until [[ $(${REDIS_CMDLINE} PING) == "PONG" ]]; do
|
until [[ $(${VALKEY_CMDLINE} PING) == "PONG" ]]; do
|
||||||
echo "Waiting for Redis..."
|
echo "Waiting for Valkey..."
|
||||||
sleep 2
|
sleep 2
|
||||||
done
|
done
|
||||||
|
|
||||||
@@ -348,7 +348,7 @@ while true; do
|
|||||||
if [[ -z ${VALIDATED_CERTIFICATES[*]} ]]; then
|
if [[ -z ${VALIDATED_CERTIFICATES[*]} ]]; then
|
||||||
log_f "Cannot validate any hostnames, skipping Let's Encrypt for 1 hour."
|
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."
|
log_f "Use SKIP_LETS_ENCRYPT=y in mailcow.conf to skip it permanently."
|
||||||
${REDIS_CMDLINE} SET ACME_FAIL_TIME "$(date +%s)"
|
${VALKEY_CMDLINE} SET ACME_FAIL_TIME "$(date +%s)"
|
||||||
sleep 1h
|
sleep 1h
|
||||||
exec $(readlink -f "$0")
|
exec $(readlink -f "$0")
|
||||||
fi
|
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)"
|
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
|
if [[ ${RELOAD_LOOP_C} -gt 3 ]]; then
|
||||||
log_f "Some services do return old end dates, something went wrong!"
|
log_f "Some services do return old end dates, something went wrong!"
|
||||||
${REDIS_CMDLINE} SET ACME_FAIL_TIME "$(date +%s)"
|
${VALKEY_CMDLINE} SET ACME_FAIL_TIME "$(date +%s)"
|
||||||
break;
|
break;
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
@@ -410,7 +410,7 @@ while true; do
|
|||||||
;;
|
;;
|
||||||
*) # non-zero
|
*) # non-zero
|
||||||
log_f "Some errors occurred, retrying in 30 minutes..."
|
log_f "Some errors occurred, retrying in 30 minutes..."
|
||||||
${REDIS_CMDLINE} SET ACME_FAIL_TIME "$(date +%s)"
|
${VALKEY_CMDLINE} SET ACME_FAIL_TIME "$(date +%s)"
|
||||||
sleep 30m
|
sleep 30m
|
||||||
exec $(readlink -f "$0")
|
exec $(readlink -f "$0")
|
||||||
;;
|
;;
|
||||||
|
|||||||
@@ -5,13 +5,13 @@ log_f() {
|
|||||||
echo -n "$(date) - ${1}"
|
echo -n "$(date) - ${1}"
|
||||||
elif [[ ${2} == "no_date" ]]; then
|
elif [[ ${2} == "no_date" ]]; then
|
||||||
echo "${1}"
|
echo "${1}"
|
||||||
elif [[ ${2} != "redis_only" ]]; then
|
elif [[ ${2} != "valkey_only" ]]; then
|
||||||
echo "$(date) - ${1}"
|
echo "$(date) - ${1}"
|
||||||
fi
|
fi
|
||||||
if [[ ${3} == "b64" ]]; then
|
if [[ ${3} == "b64" ]]; then
|
||||||
${REDIS_CMDLINE} LPUSH ACME_LOG "{\"time\":\"$(date +%s)\",\"message\":\"base64,$(printf '%s' "${MAILCOW_HOSTNAME} - ${1}")\"}" > /dev/null
|
${VALKEY_CMDLINE} LPUSH ACME_LOG "{\"time\":\"$(date +%s)\",\"message\":\"base64,$(printf '%s' "${MAILCOW_HOSTNAME} - ${1}")\"}" > /dev/null
|
||||||
else
|
else
|
||||||
${REDIS_CMDLINE} LPUSH ACME_LOG "{\"time\":\"$(date +%s)\",\"message\":\"$(printf '%s' "${MAILCOW_HOSTNAME} - ${1}" | \
|
${VALKEY_CMDLINE} LPUSH ACME_LOG "{\"time\":\"$(date +%s)\",\"message\":\"$(printf '%s' "${MAILCOW_HOSTNAME} - ${1}" | \
|
||||||
tr '%&;$"[]{}-\r\n' ' ')\"}" > /dev/null
|
tr '%&;$"[]{}-\r\n' ' ')\"}" > /dev/null
|
||||||
fi
|
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]})
|
--acme-dir /var/www/acme/ 2>&1 > /tmp/_cert.pem | tee /dev/fd/5; exit ${PIPESTATUS[0]})
|
||||||
SUCCESS="$?"
|
SUCCESS="$?"
|
||||||
ACME_RESPONSE_B64=$(echo "${ACME_RESPONSE}" | openssl enc -e -A -base64)
|
ACME_RESPONSE_B64=$(echo "${ACME_RESPONSE}" | openssl enc -e -A -base64)
|
||||||
log_f "${ACME_RESPONSE_B64}" redis_only b64
|
log_f "${ACME_RESPONSE_B64}" valkey_only b64
|
||||||
case "$SUCCESS" in
|
case "$SUCCESS" in
|
||||||
0) # cert requested
|
0) # cert requested
|
||||||
log_f "Deploying certificate ${CERT}..."
|
log_f "Deploying certificate ${CERT}..."
|
||||||
@@ -124,7 +124,7 @@ case "$SUCCESS" in
|
|||||||
;;
|
;;
|
||||||
*) # non-zero is non-fun
|
*) # non-zero is non-fun
|
||||||
log_f "Failed to obtain certificate ${CERT} for domains '${CERT_DOMAINS[*]}'"
|
log_f "Failed to obtain certificate ${CERT} for domains '${CERT_DOMAINS[*]}'"
|
||||||
redis-cli -h redis -a ${REDISPASS} --no-auth-warning SET ACME_FAIL_TIME "$(date +%s)"
|
redis-cli -h valkey-mailcow -a ${VALKEYPASS} --no-auth-warning SET ACME_FAIL_TIME "$(date +%s)"
|
||||||
exit 100${SUCCESS}
|
exit 100${SUCCESS}
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
FROM debian:trixie-slim
|
FROM debian:bookworm-slim
|
||||||
|
|
||||||
RUN apt update && apt install pigz zstd -y --no-install-recommends
|
RUN apt update && apt install pigz -y --no-install-recommends
|
||||||
@@ -32,21 +32,21 @@ async def lifespan(app: FastAPI):
|
|||||||
|
|
||||||
logger.info("Init APP")
|
logger.info("Init APP")
|
||||||
|
|
||||||
# Init redis client
|
# Init valkey client
|
||||||
if os.environ['REDIS_SLAVEOF_IP'] != "":
|
if os.environ['VALKEY_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'])
|
valkey_client = valkey = await aioredis.from_url(f"redis://{os.environ['VALKEY_SLAVEOF_IP']}:{os.environ['VALKEY_SLAVEOF_PORT']}/0", password=os.environ['VALKEYPASS'])
|
||||||
else:
|
else:
|
||||||
redis_client = redis = await aioredis.from_url("redis://redis-mailcow:6379/0", password=os.environ['REDISPASS'])
|
valkey_client = valkey = await aioredis.from_url("redis://valkey-mailcow:6379/0", password=os.environ['VALKEYPASS'])
|
||||||
|
|
||||||
# Init docker clients
|
# Init docker clients
|
||||||
sync_docker_client = docker.DockerClient(base_url='unix://var/run/docker.sock', version='auto')
|
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')
|
async_docker_client = aiodocker.Docker(url='unix:///var/run/docker.sock')
|
||||||
|
|
||||||
dockerapi = DockerApi(redis_client, sync_docker_client, async_docker_client, logger)
|
dockerapi = DockerApi(valkey_client, sync_docker_client, async_docker_client, logger)
|
||||||
|
|
||||||
logger.info("Subscribe to redis channel")
|
logger.info("Subscribe to valkey channel")
|
||||||
# Subscribe to redis channel
|
# Subscribe to valkey channel
|
||||||
dockerapi.pubsub = redis.pubsub()
|
dockerapi.pubsub = valkey.pubsub()
|
||||||
await dockerapi.pubsub.subscribe("MC_CHANNEL")
|
await dockerapi.pubsub.subscribe("MC_CHANNEL")
|
||||||
asyncio.create_task(handle_pubsub_messages(dockerapi.pubsub))
|
asyncio.create_task(handle_pubsub_messages(dockerapi.pubsub))
|
||||||
|
|
||||||
@@ -57,9 +57,9 @@ async def lifespan(app: FastAPI):
|
|||||||
dockerapi.sync_docker_client.close()
|
dockerapi.sync_docker_client.close()
|
||||||
await dockerapi.async_docker_client.close()
|
await dockerapi.async_docker_client.close()
|
||||||
|
|
||||||
# Close redis
|
# Close valkey
|
||||||
await dockerapi.pubsub.unsubscribe("MC_CHANNEL")
|
await dockerapi.pubsub.unsubscribe("MC_CHANNEL")
|
||||||
await dockerapi.redis_client.close()
|
await dockerapi.valkey_client.close()
|
||||||
|
|
||||||
app = FastAPI(lifespan=lifespan)
|
app = FastAPI(lifespan=lifespan)
|
||||||
|
|
||||||
@@ -73,11 +73,11 @@ async def get_host_update_stats():
|
|||||||
dockerapi.host_stats_isUpdating = True
|
dockerapi.host_stats_isUpdating = True
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
if await dockerapi.redis_client.exists('host_stats'):
|
if await dockerapi.valkey_client.exists('host_stats'):
|
||||||
break
|
break
|
||||||
await asyncio.sleep(1.5)
|
await asyncio.sleep(1.5)
|
||||||
|
|
||||||
stats = json.loads(await dockerapi.redis_client.get('host_stats'))
|
stats = json.loads(await dockerapi.valkey_client.get('host_stats'))
|
||||||
return Response(content=json.dumps(stats, indent=4), media_type="application/json")
|
return Response(content=json.dumps(stats, indent=4), media_type="application/json")
|
||||||
|
|
||||||
@app.get("/containers/{container_id}/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)
|
dockerapi.containerIds_to_update.append(container_id)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
if await dockerapi.redis_client.exists(container_id + '_stats'):
|
if await dockerapi.valkey_client.exists(container_id + '_stats'):
|
||||||
break
|
break
|
||||||
await asyncio.sleep(1.5)
|
await asyncio.sleep(1.5)
|
||||||
|
|
||||||
stats = json.loads(await dockerapi.redis_client.get(container_id + '_stats'))
|
stats = json.loads(await dockerapi.valkey_client.get(container_id + '_stats'))
|
||||||
return Response(content=json.dumps(stats, indent=4), media_type="application/json")
|
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
|
from fastapi import FastAPI, Response, Request
|
||||||
|
|
||||||
class DockerApi:
|
class DockerApi:
|
||||||
def __init__(self, redis_client, sync_docker_client, async_docker_client, logger):
|
def __init__(self, valkey_client, sync_docker_client, async_docker_client, logger):
|
||||||
self.redis_client = redis_client
|
self.valkey_client = valkey_client
|
||||||
self.sync_docker_client = sync_docker_client
|
self.sync_docker_client = sync_docker_client
|
||||||
self.async_docker_client = async_docker_client
|
self.async_docker_client = async_docker_client
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
@@ -533,7 +533,7 @@ class DockerApi:
|
|||||||
"architecture": platform.machine()
|
"architecture": platform.machine()
|
||||||
}
|
}
|
||||||
|
|
||||||
await self.redis_client.set('host_stats', json.dumps(host_stats), ex=10)
|
await self.valkey_client.set('host_stats', json.dumps(host_stats), ex=10)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
res = {
|
res = {
|
||||||
"type": "danger",
|
"type": "danger",
|
||||||
@@ -550,14 +550,14 @@ class DockerApi:
|
|||||||
if container._id == container_id:
|
if container._id == container_id:
|
||||||
res = await container.stats(stream=False)
|
res = await container.stats(stream=False)
|
||||||
|
|
||||||
if await self.redis_client.exists(container_id + '_stats'):
|
if await self.valkey_client.exists(container_id + '_stats'):
|
||||||
stats = json.loads(await self.redis_client.get(container_id + '_stats'))
|
stats = json.loads(await self.valkey_client.get(container_id + '_stats'))
|
||||||
else:
|
else:
|
||||||
stats = []
|
stats = []
|
||||||
stats.append(res[0])
|
stats.append(res[0])
|
||||||
if len(stats) > 3:
|
if len(stats) > 3:
|
||||||
del stats[0]
|
del stats[0]
|
||||||
await self.redis_client.set(container_id + '_stats', json.dumps(stats), ex=60)
|
await self.valkey_client.set(container_id + '_stats', json.dumps(stats), ex=60)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
res = {
|
res = {
|
||||||
"type": "danger",
|
"type": "danger",
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ RUN addgroup -g 5000 vmail \
|
|||||||
COPY trim_logs.sh /usr/local/bin/trim_logs.sh
|
COPY trim_logs.sh /usr/local/bin/trim_logs.sh
|
||||||
COPY clean_q_aged.sh /usr/local/bin/clean_q_aged.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.conf /etc/syslog-ng/syslog-ng.conf
|
||||||
COPY syslog-ng-redis_slave.conf /etc/syslog-ng/syslog-ng-redis_slave.conf
|
COPY syslog-ng-valkey_slave.conf /etc/syslog-ng/syslog-ng-valkey_slave.conf
|
||||||
COPY imapsync /usr/local/bin/imapsync
|
COPY imapsync /usr/local/bin/imapsync
|
||||||
COPY imapsync_runner.pl /usr/local/bin/imapsync_runner.pl
|
COPY imapsync_runner.pl /usr/local/bin/imapsync_runner.pl
|
||||||
COPY report-spam.sieve /usr/lib/dovecot/sieve/report-spam.sieve
|
COPY report-spam.sieve /usr/lib/dovecot/sieve/report-spam.sieve
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
source /source_env.sh
|
source /source_env.sh
|
||||||
|
|
||||||
MAX_AGE=$(redis-cli --raw -h redis-mailcow -a ${REDISPASS} --no-auth-warning GET Q_MAX_AGE)
|
MAX_AGE=$(redis-cli --raw -h valkey-mailcow -a ${VALKEYPASS} --no-auth-warning GET Q_MAX_AGE)
|
||||||
|
|
||||||
if [[ -z ${MAX_AGE} ]]; then
|
if [[ -z ${MAX_AGE} ]]; then
|
||||||
echo "Max age for quarantine items not defined"
|
echo "Max age for quarantine items not defined"
|
||||||
|
|||||||
@@ -13,18 +13,18 @@ until dig +short mailcow.email > /dev/null; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
# Do not attempt to write to slave
|
# Do not attempt to write to slave
|
||||||
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
|
if [[ ! -z ${VALKEY_SLAVEOF_IP} ]]; then
|
||||||
REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} -a ${REDISPASS} --no-auth-warning"
|
VALKEY_CMDLINE="redis-cli -h ${VALKEY_SLAVEOF_IP} -p ${VALKEY_SLAVEOF_PORT} -a ${VALKEYPASS} --no-auth-warning"
|
||||||
else
|
else
|
||||||
REDIS_CMDLINE="redis-cli -h redis -p 6379 -a ${REDISPASS} --no-auth-warning"
|
VALKEY_CMDLINE="redis-cli -h valkey-mailcow -p 6379 -a ${VALKEYPASS} --no-auth-warning"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
until [[ $(${REDIS_CMDLINE} PING) == "PONG" ]]; do
|
until [[ $(${VALKEY_CMDLINE} PING) == "PONG" ]]; do
|
||||||
echo "Waiting for Redis..."
|
echo "Waiting for Valkey..."
|
||||||
sleep 2
|
sleep 2
|
||||||
done
|
done
|
||||||
|
|
||||||
${REDIS_CMDLINE} SET DOVECOT_REPL_HEALTH 1 > /dev/null
|
${VALKEY_CMDLINE} SET DOVECOT_REPL_HEALTH 1 > /dev/null
|
||||||
|
|
||||||
# Create missing directories
|
# Create missing directories
|
||||||
[[ ! -d /etc/dovecot/sql/ ]] && mkdir -p /etc/dovecot/sql/
|
[[ ! -d /etc/dovecot/sql/ ]] && mkdir -p /etc/dovecot/sql/
|
||||||
@@ -204,17 +204,16 @@ EOF
|
|||||||
# Create random master Password for SOGo SSO
|
# Create random master Password for SOGo SSO
|
||||||
RAND_PASS=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 32 | head -n 1)
|
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
|
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
|
cat <<EOF > /etc/dovecot/sogo-sso.conf
|
||||||
# Autogenerated by mailcow
|
# Autogenerated by mailcow
|
||||||
passdb {
|
passdb {
|
||||||
driver = static
|
driver = static
|
||||||
args = allow_nets=${IPV4_NETWORK}.248/32 password={plain}${RAND_PASS}
|
args = allow_real_nets=${IPV4_NETWORK}.248/32 password={plain}${RAND_PASS}
|
||||||
}
|
}
|
||||||
EOF
|
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
|
if [[ "${MASTER}" =~ ^([nN][oO]|[nN])+$ ]]; then
|
||||||
# Toggling MASTER will result in a rebuild of containers, so the quota script will be recreated
|
# Toggling MASTER will result in a rebuild of containers, so the quota script will be recreated
|
||||||
cat <<'EOF' > /usr/local/bin/quota_notify.py
|
cat <<'EOF' > /usr/local/bin/quota_notify.py
|
||||||
@@ -342,8 +341,8 @@ done
|
|||||||
# May be related to something inside Docker, I seriously don't know
|
# May be related to something inside Docker, I seriously don't know
|
||||||
touch /etc/dovecot/auth/passwd-verify.lua
|
touch /etc/dovecot/auth/passwd-verify.lua
|
||||||
|
|
||||||
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
|
if [[ ! -z ${VALKEY_SLAVEOF_IP} ]]; then
|
||||||
cp /etc/syslog-ng/syslog-ng-redis_slave.conf /etc/syslog-ng/syslog-ng.conf
|
cp /etc/syslog-ng/syslog-ng-valkey_slave.conf /etc/syslog-ng/syslog-ng.conf
|
||||||
fi
|
fi
|
||||||
|
|
||||||
exec "$@"
|
exec "$@"
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ try:
|
|||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
r = redis.StrictRedis(host='redis', decode_responses=True, port=6379, db=0, password=os.environ['REDISPASS'])
|
r = redis.StrictRedis(host='valkey-mailcow', decode_responses=True, port=6379, db=0, password=os.environ['VALKEYPASS'])
|
||||||
r.ping()
|
r.ping()
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
print('%s - trying again...' % (ex))
|
print('%s - trying again...' % (ex))
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ else:
|
|||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
r = redis.StrictRedis(host='redis', decode_responses=True, port=6379, db=0, username='quota_notify', password='')
|
r = redis.StrictRedis(host='valkey-mailcow', decode_responses=True, port=6379, db=0, username='quota_notify', password='')
|
||||||
r.ping()
|
r.ping()
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
print('%s - trying again...' % (ex))
|
print('%s - trying again...' % (ex))
|
||||||
|
|||||||
@@ -3,16 +3,16 @@
|
|||||||
source /source_env.sh
|
source /source_env.sh
|
||||||
|
|
||||||
# Do not attempt to write to slave
|
# Do not attempt to write to slave
|
||||||
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
|
if [[ ! -z ${VALKEY_SLAVEOF_IP} ]]; then
|
||||||
REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} -a ${REDISPASS} --no-auth-warning"
|
VALKEY_CMDLINE="redis-cli -h ${VALKEY_SLAVEOF_IP} -p ${VALKEY_SLAVEOF_PORT} -a ${VALKEYPASS} --no-auth-warning"
|
||||||
else
|
else
|
||||||
REDIS_CMDLINE="redis-cli -h redis -p 6379 -a ${REDISPASS} --no-auth-warning"
|
VALKEY_CMDLINE="redis-cli -h valkey-mailcow -p 6379 -a ${VALKEYPASS} --no-auth-warning"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Is replication active?
|
# Is replication active?
|
||||||
# grep on file is less expensive than doveconf
|
# grep on file is less expensive than doveconf
|
||||||
if [ -n ${MAILCOW_REPLICA_IP} ]; then
|
if [ -n ${MAILCOW_REPLICA_IP} ]; then
|
||||||
${REDIS_CMDLINE} SET DOVECOT_REPL_HEALTH 1 > /dev/null
|
${VALKEY_CMDLINE} SET DOVECOT_REPL_HEALTH 1 > /dev/null
|
||||||
exit
|
exit
|
||||||
fi
|
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
|
# 1 failed job for mailcow.local is expected and healthy
|
||||||
if [[ "${FAILED_SYNCS}" != 0 ]] && [[ "${FAILED_SYNCS}" != 1 ]]; then
|
if [[ "${FAILED_SYNCS}" != 0 ]] && [[ "${FAILED_SYNCS}" != 1 ]]; then
|
||||||
printf "Dovecot replicator has %d failed jobs\n" "${FAILED_SYNCS}"
|
printf "Dovecot replicator has %d failed jobs\n" "${FAILED_SYNCS}"
|
||||||
${REDIS_CMDLINE} SET DOVECOT_REPL_HEALTH "${FAILED_SYNCS}" > /dev/null
|
${VALKEY_CMDLINE} SET DOVECOT_REPL_HEALTH "${FAILED_SYNCS}" > /dev/null
|
||||||
else
|
else
|
||||||
${REDIS_CMDLINE} SET DOVECOT_REPL_HEALTH 1 > /dev/null
|
${VALKEY_CMDLINE} SET DOVECOT_REPL_HEALTH 1 > /dev/null
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -15,21 +15,21 @@ source s_dgram {
|
|||||||
internal();
|
internal();
|
||||||
};
|
};
|
||||||
destination d_stdout { pipe("/dev/stdout"); };
|
destination d_stdout { pipe("/dev/stdout"); };
|
||||||
destination d_redis_ui_log {
|
destination d_valkey_ui_log {
|
||||||
redis(
|
redis(
|
||||||
host("`REDIS_SLAVEOF_IP`")
|
host("`VALKEY_SLAVEOF_IP`")
|
||||||
persist-name("redis1")
|
persist-name("valkey1")
|
||||||
port(`REDIS_SLAVEOF_PORT`)
|
port(`VALKEY_SLAVEOF_PORT`)
|
||||||
auth("`REDISPASS`")
|
auth("`VALKEYPASS`")
|
||||||
command("LPUSH" "DOVECOT_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
|
command("LPUSH" "DOVECOT_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
destination d_redis_f2b_channel {
|
destination d_valkey_f2b_channel {
|
||||||
redis(
|
redis(
|
||||||
host("`REDIS_SLAVEOF_IP`")
|
host("`VALKEY_SLAVEOF_IP`")
|
||||||
persist-name("redis2")
|
persist-name("valkey2")
|
||||||
port(`REDIS_SLAVEOF_PORT`)
|
port(`VALKEY_SLAVEOF_PORT`)
|
||||||
auth("`REDISPASS`")
|
auth("`VALKEYPASS`")
|
||||||
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
|
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -48,6 +48,6 @@ log {
|
|||||||
filter(f_replica);
|
filter(f_replica);
|
||||||
destination(d_stdout);
|
destination(d_stdout);
|
||||||
filter(f_mail);
|
filter(f_mail);
|
||||||
destination(d_redis_ui_log);
|
destination(d_valkey_ui_log);
|
||||||
destination(d_redis_f2b_channel);
|
destination(d_valkey_f2b_channel);
|
||||||
};
|
};
|
||||||
@@ -15,21 +15,21 @@ source s_dgram {
|
|||||||
internal();
|
internal();
|
||||||
};
|
};
|
||||||
destination d_stdout { pipe("/dev/stdout"); };
|
destination d_stdout { pipe("/dev/stdout"); };
|
||||||
destination d_redis_ui_log {
|
destination d_valkey_ui_log {
|
||||||
redis(
|
redis(
|
||||||
host("redis-mailcow")
|
host("valkey-mailcow")
|
||||||
persist-name("redis1")
|
persist-name("valkey1")
|
||||||
port(6379)
|
port(6379)
|
||||||
auth("`REDISPASS`")
|
auth("`VALKEYPASS`")
|
||||||
command("LPUSH" "DOVECOT_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
|
command("LPUSH" "DOVECOT_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
destination d_redis_f2b_channel {
|
destination d_valkey_f2b_channel {
|
||||||
redis(
|
redis(
|
||||||
host("redis-mailcow")
|
host("valkey-mailcow")
|
||||||
persist-name("redis2")
|
persist-name("valkey2")
|
||||||
port(6379)
|
port(6379)
|
||||||
auth("`REDISPASS`")
|
auth("`VALKEYPASS`")
|
||||||
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
|
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -48,6 +48,6 @@ log {
|
|||||||
filter(f_replica);
|
filter(f_replica);
|
||||||
destination(d_stdout);
|
destination(d_stdout);
|
||||||
filter(f_mail);
|
filter(f_mail);
|
||||||
destination(d_redis_ui_log);
|
destination(d_valkey_ui_log);
|
||||||
destination(d_redis_f2b_channel);
|
destination(d_valkey_f2b_channel);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,18 +9,17 @@ catch_non_zero() {
|
|||||||
}
|
}
|
||||||
source /source_env.sh
|
source /source_env.sh
|
||||||
# Do not attempt to write to slave
|
# Do not attempt to write to slave
|
||||||
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
|
if [[ ! -z ${VALKEY_SLAVEOF_IP} ]]; then
|
||||||
REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} -a ${REDISPASS} --no-auth-warning"
|
VALKEY_CMDLINE="redis-cli -h ${VALKEY_SLAVEOF_IP} -p ${VALKEY_SLAVEOF_PORT} -a ${VALKEYPASS} --no-auth-warning"
|
||||||
else
|
else
|
||||||
REDIS_CMDLINE="redis-cli -h redis -p 6379 -a ${REDISPASS} --no-auth-warning"
|
VALKEY_CMDLINE="redis-cli -h valkey-mailcow -p 6379 -a ${VALKEYPASS} --no-auth-warning"
|
||||||
fi
|
fi
|
||||||
catch_non_zero "${REDIS_CMDLINE} LTRIM ACME_LOG 0 ${LOG_LINES}"
|
catch_non_zero "${VALKEY_CMDLINE} LTRIM ACME_LOG 0 ${LOG_LINES}"
|
||||||
catch_non_zero "${REDIS_CMDLINE} LTRIM POSTFIX_MAILLOG 0 ${LOG_LINES}"
|
catch_non_zero "${VALKEY_CMDLINE} LTRIM POSTFIX_MAILLOG 0 ${LOG_LINES}"
|
||||||
catch_non_zero "${REDIS_CMDLINE} LTRIM DOVECOT_MAILLOG 0 ${LOG_LINES}"
|
catch_non_zero "${VALKEY_CMDLINE} LTRIM DOVECOT_MAILLOG 0 ${LOG_LINES}"
|
||||||
catch_non_zero "${REDIS_CMDLINE} LTRIM SOGO_LOG 0 ${LOG_LINES}"
|
catch_non_zero "${VALKEY_CMDLINE} LTRIM SOGO_LOG 0 ${LOG_LINES}"
|
||||||
catch_non_zero "${REDIS_CMDLINE} LTRIM NETFILTER_LOG 0 ${LOG_LINES}"
|
catch_non_zero "${VALKEY_CMDLINE} LTRIM NETFILTER_LOG 0 ${LOG_LINES}"
|
||||||
catch_non_zero "${REDIS_CMDLINE} LTRIM AUTODISCOVER_LOG 0 ${LOG_LINES}"
|
catch_non_zero "${VALKEY_CMDLINE} LTRIM AUTODISCOVER_LOG 0 ${LOG_LINES}"
|
||||||
catch_non_zero "${REDIS_CMDLINE} LTRIM API_LOG 0 ${LOG_LINES}"
|
catch_non_zero "${VALKEY_CMDLINE} LTRIM API_LOG 0 ${LOG_LINES}"
|
||||||
catch_non_zero "${REDIS_CMDLINE} LTRIM RL_LOG 0 ${LOG_LINES}"
|
catch_non_zero "${VALKEY_CMDLINE} LTRIM RL_LOG 0 ${LOG_LINES}"
|
||||||
catch_non_zero "${REDIS_CMDLINE} LTRIM WATCHDOG_LOG 0 ${LOG_LINES}"
|
catch_non_zero "${VALKEY_CMDLINE} LTRIM WATCHDOG_LOG 0 ${LOG_LINES}"
|
||||||
catch_non_zero "${REDIS_CMDLINE} LTRIM CRON_LOG 0 ${LOG_LINES}"
|
|
||||||
|
|||||||
@@ -44,25 +44,24 @@ def refreshF2boptions():
|
|||||||
global exit_code
|
global exit_code
|
||||||
f2boptions = {}
|
f2boptions = {}
|
||||||
|
|
||||||
if not r.get('F2B_OPTIONS'):
|
if not valkey.get('F2B_OPTIONS'):
|
||||||
f2boptions['ban_time'] = r.get('F2B_BAN_TIME')
|
f2boptions['ban_time'] = valkey.get('F2B_BAN_TIME')
|
||||||
f2boptions['max_ban_time'] = r.get('F2B_MAX_BAN_TIME')
|
f2boptions['max_ban_time'] = valkey.get('F2B_MAX_BAN_TIME')
|
||||||
f2boptions['ban_time_increment'] = r.get('F2B_BAN_TIME_INCREMENT')
|
f2boptions['ban_time_increment'] = valkey.get('F2B_BAN_TIME_INCREMENT')
|
||||||
f2boptions['max_attempts'] = r.get('F2B_MAX_ATTEMPTS')
|
f2boptions['max_attempts'] = valkey.get('F2B_MAX_ATTEMPTS')
|
||||||
f2boptions['retry_window'] = r.get('F2B_RETRY_WINDOW')
|
f2boptions['retry_window'] = valkey.get('F2B_RETRY_WINDOW')
|
||||||
f2boptions['netban_ipv4'] = r.get('F2B_NETBAN_IPV4')
|
f2boptions['netban_ipv4'] = valkey.get('F2B_NETBAN_IPV4')
|
||||||
f2boptions['netban_ipv6'] = r.get('F2B_NETBAN_IPV6')
|
f2boptions['netban_ipv6'] = valkey.get('F2B_NETBAN_IPV6')
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
f2boptions = json.loads(r.get('F2B_OPTIONS'))
|
f2boptions = json.loads(valkey.get('F2B_OPTIONS'))
|
||||||
except ValueError as e:
|
except ValueError:
|
||||||
logger.logCrit(
|
logger.logCrit('Error loading F2B options: F2B_OPTIONS is not json')
|
||||||
'Error loading F2B options: F2B_OPTIONS is not json. Exception: %s' % e)
|
|
||||||
quit_now = True
|
quit_now = True
|
||||||
exit_code = 2
|
exit_code = 2
|
||||||
|
|
||||||
verifyF2boptions(f2boptions)
|
verifyF2boptions(f2boptions)
|
||||||
r.set('F2B_OPTIONS', json.dumps(f2boptions, ensure_ascii=False))
|
valkey.set('F2B_OPTIONS', json.dumps(f2boptions, ensure_ascii=False))
|
||||||
|
|
||||||
def verifyF2boptions(f2boptions):
|
def verifyF2boptions(f2boptions):
|
||||||
verifyF2boption(f2boptions, 'ban_time', 1800)
|
verifyF2boption(f2boptions, 'ban_time', 1800)
|
||||||
@@ -82,7 +81,7 @@ def refreshF2bregex():
|
|||||||
global f2bregex
|
global f2bregex
|
||||||
global quit_now
|
global quit_now
|
||||||
global exit_code
|
global exit_code
|
||||||
if not r.get('F2B_REGEX'):
|
if not valkey.get('F2B_REGEX'):
|
||||||
f2bregex = {}
|
f2bregex = {}
|
||||||
f2bregex[1] = r'mailcow UI: Invalid password for .+ by ([0-9a-f\.:]+)'
|
f2bregex[1] = r'mailcow UI: Invalid password for .+ by ([0-9a-f\.:]+)'
|
||||||
f2bregex[2] = r'Rspamd UI: Invalid password by ([0-9a-f\.:]+)'
|
f2bregex[2] = r'Rspamd UI: Invalid password by ([0-9a-f\.:]+)'
|
||||||
@@ -93,11 +92,11 @@ def refreshF2bregex():
|
|||||||
f2bregex[7] = r'\w+\([^,]+,([0-9a-f\.:]+),<[^>]+>\): unknown user \(SHA1 of given password: [a-f0-9]+\)'
|
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[8] = r'SOGo.+ Login from \'([0-9a-f\.:]+)\' for user .+ might not have worked'
|
||||||
f2bregex[9] = r'([0-9a-f\.:]+) \"GET \/SOGo\/.* HTTP.+\" 403 .+'
|
f2bregex[9] = r'([0-9a-f\.:]+) \"GET \/SOGo\/.* HTTP.+\" 403 .+'
|
||||||
r.set('F2B_REGEX', json.dumps(f2bregex, ensure_ascii=False))
|
valkey.set('F2B_REGEX', json.dumps(f2bregex, ensure_ascii=False))
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
f2bregex = {}
|
f2bregex = {}
|
||||||
f2bregex = json.loads(r.get('F2B_REGEX'))
|
f2bregex = json.loads(valkey.get('F2B_REGEX'))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
logger.logCrit('Error loading F2B options: F2B_REGEX is not json')
|
logger.logCrit('Error loading F2B options: F2B_REGEX is not json')
|
||||||
quit_now = True
|
quit_now = True
|
||||||
@@ -176,7 +175,7 @@ def ban(address):
|
|||||||
|
|
||||||
logdebug("Updating F2B_ACTIVE_BANS[%s]=%d" %
|
logdebug("Updating F2B_ACTIVE_BANS[%s]=%d" %
|
||||||
(net, cur_time + NET_BAN_TIME))
|
(net, cur_time + NET_BAN_TIME))
|
||||||
r.hset('F2B_ACTIVE_BANS', '%s' % net, cur_time + NET_BAN_TIME)
|
valkey.hset('F2B_ACTIVE_BANS', '%s' % net, cur_time + NET_BAN_TIME)
|
||||||
else:
|
else:
|
||||||
logger.logWarn('%d more attempts in the next %d seconds until %s is banned' % (
|
logger.logWarn('%d more attempts in the next %d seconds until %s is banned' % (
|
||||||
MAX_ATTEMPTS - bans[net]['attempts'], RETRY_WINDOW, net))
|
MAX_ATTEMPTS - bans[net]['attempts'], RETRY_WINDOW, net))
|
||||||
@@ -187,7 +186,7 @@ def unban(net):
|
|||||||
if not net in bans:
|
if not net in bans:
|
||||||
logger.logInfo(
|
logger.logInfo(
|
||||||
'%s is not banned, skipping unban and deleting from queue (if any)' % net)
|
'%s is not banned, skipping unban and deleting from queue (if any)' % net)
|
||||||
r.hdel('F2B_QUEUE_UNBAN', '%s' % net)
|
valkey.hdel('F2B_QUEUE_UNBAN', '%s' % net)
|
||||||
return
|
return
|
||||||
logger.logInfo('Unbanning %s' % net)
|
logger.logInfo('Unbanning %s' % net)
|
||||||
if type(ipaddress.ip_network(net)) is ipaddress.IPv4Network:
|
if type(ipaddress.ip_network(net)) is ipaddress.IPv4Network:
|
||||||
@@ -198,8 +197,8 @@ def unban(net):
|
|||||||
with lock:
|
with lock:
|
||||||
logdebug("Calling tables.unbanIPv6(%s)" % net)
|
logdebug("Calling tables.unbanIPv6(%s)" % net)
|
||||||
tables.unbanIPv6(net)
|
tables.unbanIPv6(net)
|
||||||
r.hdel('F2B_ACTIVE_BANS', '%s' % net)
|
valkey.hdel('F2B_ACTIVE_BANS', '%s' % net)
|
||||||
r.hdel('F2B_QUEUE_UNBAN', '%s' % net)
|
valkey.hdel('F2B_QUEUE_UNBAN', '%s' % net)
|
||||||
if net in bans:
|
if net in bans:
|
||||||
logdebug("Unban for %s, setting attempts=0, ban_counter+=1" % net)
|
logdebug("Unban for %s, setting attempts=0, ban_counter+=1" % net)
|
||||||
bans[net]['attempts'] = 0
|
bans[net]['attempts'] = 0
|
||||||
@@ -226,10 +225,10 @@ def permBan(net, unban=False):
|
|||||||
|
|
||||||
|
|
||||||
if is_unbanned:
|
if is_unbanned:
|
||||||
r.hdel('F2B_PERM_BANS', '%s' % net)
|
valkey.hdel('F2B_PERM_BANS', '%s' % net)
|
||||||
logger.logCrit('Removed host/network %s from denylist' % net)
|
logger.logCrit('Removed host/network %s from denylist' % net)
|
||||||
elif is_banned:
|
elif is_banned:
|
||||||
r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time())))
|
valkey.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time())))
|
||||||
logger.logCrit('Added host/network %s to denylist' % net)
|
logger.logCrit('Added host/network %s to denylist' % net)
|
||||||
|
|
||||||
def clear():
|
def clear():
|
||||||
@@ -244,17 +243,17 @@ def clear():
|
|||||||
tables.clearIPv6Table()
|
tables.clearIPv6Table()
|
||||||
try:
|
try:
|
||||||
if r is not None:
|
if r is not None:
|
||||||
r.delete('F2B_ACTIVE_BANS')
|
valkey.delete('F2B_ACTIVE_BANS')
|
||||||
r.delete('F2B_PERM_BANS')
|
valkey.delete('F2B_PERM_BANS')
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
logger.logWarn('Error clearing redis keys F2B_ACTIVE_BANS and F2B_PERM_BANS: %s' % ex)
|
logger.logWarn('Error clearing valkey keys F2B_ACTIVE_BANS and F2B_PERM_BANS: %s' % ex)
|
||||||
|
|
||||||
def watch():
|
def watch():
|
||||||
global pubsub
|
global pubsub
|
||||||
global quit_now
|
global quit_now
|
||||||
global exit_code
|
global exit_code
|
||||||
|
|
||||||
logger.logInfo('Watching Redis channel F2B_CHANNEL')
|
logger.logInfo('Watching Valkey channel F2B_CHANNEL')
|
||||||
pubsub.subscribe('F2B_CHANNEL')
|
pubsub.subscribe('F2B_CHANNEL')
|
||||||
|
|
||||||
while not quit_now:
|
while not quit_now:
|
||||||
@@ -306,7 +305,7 @@ def autopurge():
|
|||||||
time.sleep(10)
|
time.sleep(10)
|
||||||
refreshF2boptions()
|
refreshF2boptions()
|
||||||
MAX_ATTEMPTS = int(f2boptions['max_attempts'])
|
MAX_ATTEMPTS = int(f2boptions['max_attempts'])
|
||||||
QUEUE_UNBAN = r.hgetall('F2B_QUEUE_UNBAN')
|
QUEUE_UNBAN = valkey.hgetall('F2B_QUEUE_UNBAN')
|
||||||
logdebug("QUEUE_UNBAN: %s" % QUEUE_UNBAN)
|
logdebug("QUEUE_UNBAN: %s" % QUEUE_UNBAN)
|
||||||
if QUEUE_UNBAN:
|
if QUEUE_UNBAN:
|
||||||
for net in QUEUE_UNBAN:
|
for net in QUEUE_UNBAN:
|
||||||
@@ -391,7 +390,7 @@ def whitelistUpdate():
|
|||||||
global WHITELIST
|
global WHITELIST
|
||||||
while not quit_now:
|
while not quit_now:
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
list = r.hgetall('F2B_WHITELIST')
|
list = valkey.hgetall('F2B_WHITELIST')
|
||||||
new_whitelist = []
|
new_whitelist = []
|
||||||
if list:
|
if list:
|
||||||
new_whitelist = genNetworkList(list)
|
new_whitelist = genNetworkList(list)
|
||||||
@@ -406,7 +405,7 @@ def blacklistUpdate():
|
|||||||
global BLACKLIST
|
global BLACKLIST
|
||||||
while not quit_now:
|
while not quit_now:
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
list = r.hgetall('F2B_BLACKLIST')
|
list = valkey.hgetall('F2B_BLACKLIST')
|
||||||
new_blacklist = []
|
new_blacklist = []
|
||||||
if list:
|
if list:
|
||||||
new_blacklist = genNetworkList(list)
|
new_blacklist = genNetworkList(list)
|
||||||
@@ -467,35 +466,35 @@ if __name__ == '__main__':
|
|||||||
logger.logInfo(f"Setting {chain_name} isolation")
|
logger.logInfo(f"Setting {chain_name} isolation")
|
||||||
tables.create_mailcow_isolation_rule("br-mailcow", [3306, 6379, 8983, 12345], os.getenv("MAILCOW_REPLICA_IP"))
|
tables.create_mailcow_isolation_rule("br-mailcow", [3306, 6379, 8983, 12345], os.getenv("MAILCOW_REPLICA_IP"))
|
||||||
|
|
||||||
# connect to redis
|
# connect to valkey
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
redis_slaveof_ip = os.getenv('REDIS_SLAVEOF_IP', '')
|
valkey_slaveof_ip = os.getenv('VALKEY_SLAVEOF_IP', '')
|
||||||
redis_slaveof_port = os.getenv('REDIS_SLAVEOF_PORT', '')
|
valkey_slaveof_port = os.getenv('VALKEY_SLAVEOF_PORT', '')
|
||||||
logdebug(
|
logdebug(
|
||||||
"Connecting redis (SLAVEOF_IP:%s, PORT:%s)" % (redis_slaveof_ip, redis_slaveof_port))
|
"Connecting valkey (SLAVEOF_IP:%s, PORT:%s)" % (valkey_slaveof_ip, valkey_slaveof_port))
|
||||||
if "".__eq__(redis_slaveof_ip):
|
if "".__eq__(valkey_slaveof_ip):
|
||||||
r = redis.StrictRedis(
|
valkey = redis.StrictRedis(
|
||||||
host=os.getenv('IPV4_NETWORK', '172.22.1') + '.249', decode_responses=True, port=6379, db=0, password=os.environ['REDISPASS'])
|
host=os.getenv('IPV4_NETWORK', '172.22.1') + '.249', decode_responses=True, port=6379, db=0, password=os.environ['VALKEYPASS'])
|
||||||
else:
|
else:
|
||||||
r = redis.StrictRedis(
|
valkey = redis.StrictRedis(
|
||||||
host=redis_slaveof_ip, decode_responses=True, port=redis_slaveof_port, db=0, password=os.environ['REDISPASS'])
|
host=valkey_slaveof_ip, decode_responses=True, port=valkey_slaveof_port, db=0, password=os.environ['VALKEYPASS'])
|
||||||
r.ping()
|
valkey.ping()
|
||||||
pubsub = r.pubsub()
|
pubsub = valkey.pubsub()
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
logdebug(
|
logdebug(
|
||||||
'Redis connection failed: %s - trying again in 3 seconds' % (ex))
|
'Redis connection failed: %s - trying again in 3 seconds' % (ex))
|
||||||
time.sleep(3)
|
time.sleep(3)
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
logger.set_redis(r)
|
logger.set_valkey(valkey)
|
||||||
logdebug("Redis connection established, setting up F2B keys")
|
logdebug("Valkey connection established, setting up F2B keys")
|
||||||
|
|
||||||
if r.exists('F2B_LOG'):
|
if valkey.exists('F2B_LOG'):
|
||||||
logdebug("Renaming F2B_LOG to NETFILTER_LOG")
|
logdebug("Renaming F2B_LOG to NETFILTER_LOG")
|
||||||
r.rename('F2B_LOG', 'NETFILTER_LOG')
|
valkey.rename('F2B_LOG', 'NETFILTER_LOG')
|
||||||
r.delete('F2B_ACTIVE_BANS')
|
valkey.delete('F2B_ACTIVE_BANS')
|
||||||
r.delete('F2B_PERM_BANS')
|
valkey.delete('F2B_PERM_BANS')
|
||||||
|
|
||||||
refreshF2boptions()
|
refreshF2boptions()
|
||||||
|
|
||||||
|
|||||||
@@ -4,19 +4,19 @@ import datetime
|
|||||||
|
|
||||||
class Logger:
|
class Logger:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.r = None
|
self.valkey = None
|
||||||
|
|
||||||
def set_redis(self, redis):
|
def set_valkey(self, valkey):
|
||||||
self.r = redis
|
self.valkey = valkey
|
||||||
|
|
||||||
def _format_timestamp(self):
|
def _format_timestamp(self):
|
||||||
# Local time with milliseconds
|
# Local time with milliseconds
|
||||||
return datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
return datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
|
||||||
def log(self, priority, message):
|
def log(self, priority, message):
|
||||||
# build redis-friendly dict
|
# build valkey-friendly dict
|
||||||
tolog = {
|
tolog = {
|
||||||
'time': int(round(time.time())), # keep raw timestamp for Redis
|
'time': int(round(time.time())), # keep raw timestamp for Valkey
|
||||||
'priority': priority,
|
'priority': priority,
|
||||||
'message': message
|
'message': message
|
||||||
}
|
}
|
||||||
@@ -26,11 +26,11 @@ class Logger:
|
|||||||
print(f"{ts} {priority.upper()}: {message}", flush=True)
|
print(f"{ts} {priority.upper()}: {message}", flush=True)
|
||||||
|
|
||||||
# also push JSON to Redis if connected
|
# also push JSON to Redis if connected
|
||||||
if self.r is not None:
|
if self.valkey is not None:
|
||||||
try:
|
try:
|
||||||
self.r.lpush('NETFILTER_LOG', json.dumps(tolog, ensure_ascii=False))
|
self.valkey.lpush('NETFILTER_LOG', json.dumps(tolog, ensure_ascii=False))
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
print(f'{ts} WARN: Failed logging to redis: {ex}', flush=True)
|
print(f'{ts} WARN: Failed logging to valkey: {ex}', flush=True)
|
||||||
|
|
||||||
def logWarn(self, message):
|
def logWarn(self, message):
|
||||||
self.log('warn', 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>"
|
LABEL maintainer = "The Infrastructure Company GmbH <info@servercow.de>"
|
||||||
|
|
||||||
# renovate: datasource=github-tags depName=krakjoe/apcu versioning=semver-coerced extractVersion=^v(?<version>.*)$
|
# renovate: datasource=github-tags depName=krakjoe/apcu versioning=semver-coerced extractVersion=^v(?<version>.*)$
|
||||||
ARG APCU_PECL_VERSION=5.1.27
|
ARG APCU_PECL_VERSION=5.1.26
|
||||||
# renovate: datasource=github-tags depName=Imagick/imagick versioning=semver-coerced extractVersion=(?<version>.*)$
|
# renovate: datasource=github-tags depName=Imagick/imagick versioning=semver-coerced extractVersion=(?<version>.*)$
|
||||||
ARG IMAGICK_PECL_VERSION=3.8.0
|
ARG IMAGICK_PECL_VERSION=3.8.0
|
||||||
# renovate: datasource=github-tags depName=php/pecl-mail-mailparse versioning=semver-coerced extractVersion=^v(?<version>.*)$
|
# renovate: datasource=github-tags depName=php/pecl-mail-mailparse versioning=semver-coerced extractVersion=^v(?<version>.*)$
|
||||||
ARG MAILPARSE_PECL_VERSION=3.1.9
|
ARG MAILPARSE_PECL_VERSION=3.1.8
|
||||||
# renovate: datasource=github-tags depName=php-memcached-dev/php-memcached versioning=semver-coerced extractVersion=^v(?<version>.*)$
|
# renovate: datasource=github-tags depName=php-memcached-dev/php-memcached versioning=semver-coerced extractVersion=^v(?<version>.*)$
|
||||||
ARG MEMCACHED_PECL_VERSION=3.3.0
|
ARG MEMCACHED_PECL_VERSION=3.3.0
|
||||||
# renovate: datasource=github-tags depName=phpredis/phpredis versioning=semver-coerced extractVersion=(?<version>.*)$
|
# 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
|
done
|
||||||
|
|
||||||
# Do not attempt to write to slave
|
# Do not attempt to write to slave
|
||||||
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
|
if [[ ! -z ${VALKEY_SLAVEOF_IP} ]]; then
|
||||||
REDIS_HOST=$REDIS_SLAVEOF_IP
|
VALKEY_HOST=$VALKEY_SLAVEOF_IP
|
||||||
REDIS_PORT=$REDIS_SLAVEOF_PORT
|
VALKEY_PORT=$VALKEY_SLAVEOF_PORT
|
||||||
else
|
else
|
||||||
REDIS_HOST="redis"
|
VALKEY_HOST="valkey-mailcow"
|
||||||
REDIS_PORT="6379"
|
VALKEY_PORT="6379"
|
||||||
fi
|
fi
|
||||||
REDIS_CMDLINE="redis-cli -h ${REDIS_HOST} -p ${REDIS_PORT} -a ${REDISPASS} --no-auth-warning"
|
VALKEY_CMDLINE="redis-cli -h ${VALKEY_HOST} -p ${VALKEY_PORT} -a ${VALKEYPASS} --no-auth-warning"
|
||||||
|
|
||||||
until [[ $(${REDIS_CMDLINE} PING) == "PONG" ]]; do
|
until [[ $(${VALKEY_CMDLINE} PING) == "PONG" ]]; do
|
||||||
echo "Waiting for Redis..."
|
echo "Waiting for Valkey..."
|
||||||
sleep 2
|
sleep 2
|
||||||
done
|
done
|
||||||
|
|
||||||
# Set redis session store
|
# Set valkey session store
|
||||||
echo -n '
|
echo -n '
|
||||||
session.save_handler = redis
|
session.save_handler = redis
|
||||||
session.save_path = "tcp://'${REDIS_HOST}':'${REDIS_PORT}'?auth='${REDISPASS}'"
|
session.save_path = "tcp://'${VALKEY_HOST}':'${VALKEY_PORT}'?auth='${VALKEYPASS}'"
|
||||||
' > /usr/local/etc/php/conf.d/session_store.ini
|
' > /usr/local/etc/php/conf.d/session_store.ini
|
||||||
|
|
||||||
# Check mysql_upgrade (master and slave)
|
# Check mysql_upgrade (master and slave)
|
||||||
@@ -91,22 +91,22 @@ fi
|
|||||||
if [[ "${MASTER}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
if [[ "${MASTER}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
||||||
echo "We are master, preparing..."
|
echo "We are master, preparing..."
|
||||||
# Set a default release format
|
# Set a default release format
|
||||||
if [[ -z $(${REDIS_CMDLINE} --raw GET Q_RELEASE_FORMAT) ]]; then
|
if [[ -z $(${VALKEY_CMDLINE} --raw GET Q_RELEASE_FORMAT) ]]; then
|
||||||
${REDIS_CMDLINE} --raw SET Q_RELEASE_FORMAT raw
|
${VALKEY_CMDLINE} --raw SET Q_RELEASE_FORMAT raw
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Set max age of q items - if unset
|
# Set max age of q items - if unset
|
||||||
if [[ -z $(${REDIS_CMDLINE} --raw GET Q_MAX_AGE) ]]; then
|
if [[ -z $(${VALKEY_CMDLINE} --raw GET Q_MAX_AGE) ]]; then
|
||||||
${REDIS_CMDLINE} --raw SET Q_MAX_AGE 365
|
${VALKEY_CMDLINE} --raw SET Q_MAX_AGE 365
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Set default password policy - if unset
|
# Set default password policy - if unset
|
||||||
if [[ -z $(${REDIS_CMDLINE} --raw HGET PASSWD_POLICY length) ]]; then
|
if [[ -z $(${VALKEY_CMDLINE} --raw HGET PASSWD_POLICY length) ]]; then
|
||||||
${REDIS_CMDLINE} --raw HSET PASSWD_POLICY length 6
|
${VALKEY_CMDLINE} --raw HSET PASSWD_POLICY length 6
|
||||||
${REDIS_CMDLINE} --raw HSET PASSWD_POLICY chars 0
|
${VALKEY_CMDLINE} --raw HSET PASSWD_POLICY chars 0
|
||||||
${REDIS_CMDLINE} --raw HSET PASSWD_POLICY special_chars 0
|
${VALKEY_CMDLINE} --raw HSET PASSWD_POLICY special_chars 0
|
||||||
${REDIS_CMDLINE} --raw HSET PASSWD_POLICY lowerupper 0
|
${VALKEY_CMDLINE} --raw HSET PASSWD_POLICY lowerupper 0
|
||||||
${REDIS_CMDLINE} --raw HSET PASSWD_POLICY numbers 0
|
${VALKEY_CMDLINE} --raw HSET PASSWD_POLICY numbers 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Trigger db init
|
# 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
|
php -c /usr/local/etc/php -f /web/inc/init_db.inc.php
|
||||||
|
|
||||||
# Recreating domain map
|
# Recreating domain map
|
||||||
echo "Rebuilding domain map in Redis..."
|
echo "Rebuilding domain map in Valkey..."
|
||||||
declare -a DOMAIN_ARR
|
declare -a DOMAIN_ARR
|
||||||
${REDIS_CMDLINE} DEL DOMAIN_MAP > /dev/null
|
${VALKEY_CMDLINE} DEL DOMAIN_MAP > /dev/null
|
||||||
while read line
|
while read line
|
||||||
do
|
do
|
||||||
DOMAIN_ARR+=("$line")
|
DOMAIN_ARR+=("$line")
|
||||||
@@ -128,7 +128,7 @@ if [[ "${MASTER}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
|||||||
|
|
||||||
if [[ ! -z ${DOMAIN_ARR} ]]; then
|
if [[ ! -z ${DOMAIN_ARR} ]]; then
|
||||||
for domain in "${DOMAIN_ARR[@]}"; do
|
for domain in "${DOMAIN_ARR[@]}"; do
|
||||||
${REDIS_CMDLINE} HSET DOMAIN_MAP ${domain} 1 > /dev/null
|
${VALKEY_CMDLINE} HSET DOMAIN_MAP ${domain} 1 > /dev/null
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -167,7 +167,7 @@ DELIMITER //
|
|||||||
CREATE EVENT clean_spamalias
|
CREATE EVENT clean_spamalias
|
||||||
ON SCHEDULE EVERY 1 DAY DO
|
ON SCHEDULE EVERY 1 DAY DO
|
||||||
BEGIN
|
BEGIN
|
||||||
DELETE FROM spamalias WHERE validity < UNIX_TIMESTAMP() AND permanent = 0;
|
DELETE FROM spamalias WHERE validity < UNIX_TIMESTAMP();
|
||||||
END;
|
END;
|
||||||
//
|
//
|
||||||
DELIMITER ;
|
DELIMITER ;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ WORKDIR /src
|
|||||||
ENV CGO_ENABLED=0 \
|
ENV CGO_ENABLED=0 \
|
||||||
GO111MODULE=on \
|
GO111MODULE=on \
|
||||||
NOOPT=1 \
|
NOOPT=1 \
|
||||||
VERSION=1.8.22
|
VERSION=1.8.14
|
||||||
|
|
||||||
RUN git clone --branch v${VERSION} https://github.com/Zuplu/postfix-tlspol && \
|
RUN git clone --branch v${VERSION} https://github.com/Zuplu/postfix-tlspol && \
|
||||||
cd /src/postfix-tlspol && \
|
cd /src/postfix-tlspol && \
|
||||||
@@ -34,7 +34,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||||||
|
|
||||||
COPY supervisord.conf /etc/supervisor/supervisord.conf
|
COPY supervisord.conf /etc/supervisor/supervisord.conf
|
||||||
COPY syslog-ng.conf /etc/syslog-ng/syslog-ng.conf
|
COPY syslog-ng.conf /etc/syslog-ng/syslog-ng.conf
|
||||||
COPY syslog-ng-redis_slave.conf /etc/syslog-ng/syslog-ng-redis_slave.conf
|
COPY syslog-ng-valkey_slave.conf /etc/syslog-ng/syslog-ng-valkey_slave.conf
|
||||||
COPY postfix-tlspol.sh /opt/postfix-tlspol.sh
|
COPY postfix-tlspol.sh /opt/postfix-tlspol.sh
|
||||||
COPY stop-supervisor.sh /usr/local/sbin/stop-supervisor.sh
|
COPY stop-supervisor.sh /usr/local/sbin/stop-supervisor.sh
|
||||||
COPY docker-entrypoint.sh /docker-entrypoint.sh
|
COPY docker-entrypoint.sh /docker-entrypoint.sh
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
|
if [[ ! -z ${VALKEY_SLAVEOF_IP} ]]; then
|
||||||
cp /etc/syslog-ng/syslog-ng-redis_slave.conf /etc/syslog-ng/syslog-ng.conf
|
cp /etc/syslog-ng/syslog-ng-valkey_slave.conf /etc/syslog-ng/syslog-ng.conf
|
||||||
fi
|
fi
|
||||||
|
|
||||||
exec "$@"
|
exec "$@"
|
||||||
@@ -17,14 +17,14 @@ until dig +short mailcow.email > /dev/null; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
# Do not attempt to write to slave
|
# Do not attempt to write to slave
|
||||||
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
|
if [[ ! -z ${VALKEY_SLAVEOF_IP} ]]; then
|
||||||
export REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} -a ${REDISPASS} --no-auth-warning"
|
export VALKEY_CMDLINE="redis-cli -h ${VALKEY_SLAVEOF_IP} -p ${VALKEY_SLAVEOF_PORT} -a ${VALKEYPASS} --no-auth-warning"
|
||||||
else
|
else
|
||||||
export REDIS_CMDLINE="redis-cli -h redis -p 6379 -a ${REDISPASS} --no-auth-warning"
|
export VALKEY_CMDLINE="redis-cli -h valkey -p 6379 -a ${VALKEYPASS} --no-auth-warning"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
until [[ $(${REDIS_CMDLINE} PING) == "PONG" ]]; do
|
until [[ $(${VALKEY_CMDLINE} PING) == "PONG" ]]; do
|
||||||
echo "Waiting for Redis..."
|
echo "Waiting for Valkey..."
|
||||||
sleep 2
|
sleep 2
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|||||||
@@ -15,12 +15,12 @@ source s_src {
|
|||||||
internal();
|
internal();
|
||||||
};
|
};
|
||||||
destination d_stdout { pipe("/dev/stdout"); };
|
destination d_stdout { pipe("/dev/stdout"); };
|
||||||
destination d_redis_ui_log {
|
destination d_valkey_ui_log {
|
||||||
redis(
|
redis(
|
||||||
host("`REDIS_SLAVEOF_IP`")
|
host("`VALKEY_SLAVEOF_IP`")
|
||||||
persist-name("redis1")
|
persist-name("valkey1")
|
||||||
port(`REDIS_SLAVEOF_PORT`)
|
port(`VALKEY_SLAVEOF_PORT`)
|
||||||
auth("`REDISPASS`")
|
auth("`VALKEYPASS`")
|
||||||
command("LPUSH" "POSTFIX_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
|
command("LPUSH" "POSTFIX_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -41,5 +41,5 @@ log {
|
|||||||
filter(f_ignore);
|
filter(f_ignore);
|
||||||
destination(d_stdout);
|
destination(d_stdout);
|
||||||
filter(f_mail);
|
filter(f_mail);
|
||||||
destination(d_redis_ui_log);
|
destination(d_valkey_ui_log);
|
||||||
};
|
};
|
||||||
@@ -15,12 +15,12 @@ source s_src {
|
|||||||
internal();
|
internal();
|
||||||
};
|
};
|
||||||
destination d_stdout { pipe("/dev/stdout"); };
|
destination d_stdout { pipe("/dev/stdout"); };
|
||||||
destination d_redis_ui_log {
|
destination d_valkey_ui_log {
|
||||||
redis(
|
redis(
|
||||||
host("redis-mailcow")
|
host("valkey-mailcow")
|
||||||
persist-name("redis1")
|
persist-name("valkey1")
|
||||||
port(6379)
|
port(6379)
|
||||||
auth("`REDISPASS`")
|
auth("`VALKEYPASS`")
|
||||||
command("LPUSH" "POSTFIX_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
|
command("LPUSH" "POSTFIX_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -41,5 +41,5 @@ log {
|
|||||||
filter(f_ignore);
|
filter(f_ignore);
|
||||||
destination(d_stdout);
|
destination(d_stdout);
|
||||||
filter(f_mail);
|
filter(f_mail);
|
||||||
destination(d_redis_ui_log);
|
destination(d_valkey_ui_log);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ RUN groupadd -g 102 postfix \
|
|||||||
|
|
||||||
COPY supervisord.conf /etc/supervisor/supervisord.conf
|
COPY supervisord.conf /etc/supervisor/supervisord.conf
|
||||||
COPY syslog-ng.conf /etc/syslog-ng/syslog-ng.conf
|
COPY syslog-ng.conf /etc/syslog-ng/syslog-ng.conf
|
||||||
COPY syslog-ng-redis_slave.conf /etc/syslog-ng/syslog-ng-redis_slave.conf
|
COPY syslog-ng-valkey_slave.conf /etc/syslog-ng/syslog-ng-valkey_slave.conf
|
||||||
COPY postfix.sh /opt/postfix.sh
|
COPY postfix.sh /opt/postfix.sh
|
||||||
COPY rspamd-pipe-ham /usr/local/bin/rspamd-pipe-ham
|
COPY rspamd-pipe-ham /usr/local/bin/rspamd-pipe-ham
|
||||||
COPY rspamd-pipe-spam /usr/local/bin/rspamd-pipe-spam
|
COPY rspamd-pipe-spam /usr/local/bin/rspamd-pipe-spam
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ for file in /hooks/*; do
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
|
if [[ ! -z ${VALKEY_SLAVEOF_IP} ]]; then
|
||||||
cp /etc/syslog-ng/syslog-ng-redis_slave.conf /etc/syslog-ng/syslog-ng.conf
|
cp /etc/syslog-ng/syslog-ng-valkey_slave.conf /etc/syslog-ng/syslog-ng.conf
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Fix OpenSSL 3.X TLS1.0, 1.1 support (https://community.mailcow.email/d/4062-hi-all/20)
|
# Fix OpenSSL 3.X TLS1.0, 1.1 support (https://community.mailcow.email/d/4062-hi-all/20)
|
||||||
|
|||||||
@@ -390,7 +390,7 @@ hosts = unix:/var/run/mysqld/mysqld.sock
|
|||||||
dbname = ${DBNAME}
|
dbname = ${DBNAME}
|
||||||
query = SELECT goto FROM spamalias
|
query = SELECT goto FROM spamalias
|
||||||
WHERE address='%s'
|
WHERE address='%s'
|
||||||
AND (validity >= UNIX_TIMESTAMP() OR permanent != 0)
|
AND validity >= UNIX_TIMESTAMP()
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
if [ ! -f /opt/postfix/conf/dns_blocklists.cf ]; then
|
if [ ! -f /opt/postfix/conf/dns_blocklists.cf ]; then
|
||||||
|
|||||||
@@ -15,21 +15,21 @@ source s_src {
|
|||||||
internal();
|
internal();
|
||||||
};
|
};
|
||||||
destination d_stdout { pipe("/dev/stdout"); };
|
destination d_stdout { pipe("/dev/stdout"); };
|
||||||
destination d_redis_ui_log {
|
destination d_valkey_ui_log {
|
||||||
redis(
|
redis(
|
||||||
host("`REDIS_SLAVEOF_IP`")
|
host("`VALKEY_SLAVEOF_IP`")
|
||||||
persist-name("redis1")
|
persist-name("valkey1")
|
||||||
port(`REDIS_SLAVEOF_PORT`)
|
port(`VALKEY_SLAVEOF_PORT`)
|
||||||
auth("`REDISPASS`")
|
auth("`VALKEYPASS`")
|
||||||
command("LPUSH" "POSTFIX_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
|
command("LPUSH" "POSTFIX_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
destination d_redis_f2b_channel {
|
destination d_valkey_f2b_channel {
|
||||||
redis(
|
redis(
|
||||||
host("`REDIS_SLAVEOF_IP`")
|
host("`VALKEY_SLAVEOF_IP`")
|
||||||
persist-name("redis2")
|
persist-name("valkey2")
|
||||||
port(`REDIS_SLAVEOF_PORT`)
|
port(`VALKEY_SLAVEOF_PORT`)
|
||||||
auth("`REDISPASS`")
|
auth("`VALKEYPASS`")
|
||||||
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
|
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -50,6 +50,6 @@ log {
|
|||||||
filter(f_ignore);
|
filter(f_ignore);
|
||||||
destination(d_stdout);
|
destination(d_stdout);
|
||||||
filter(f_mail);
|
filter(f_mail);
|
||||||
destination(d_redis_ui_log);
|
destination(d_valkey_ui_log);
|
||||||
destination(d_redis_f2b_channel);
|
destination(d_valkey_f2b_channel);
|
||||||
};
|
};
|
||||||
@@ -15,21 +15,21 @@ source s_src {
|
|||||||
internal();
|
internal();
|
||||||
};
|
};
|
||||||
destination d_stdout { pipe("/dev/stdout"); };
|
destination d_stdout { pipe("/dev/stdout"); };
|
||||||
destination d_redis_ui_log {
|
destination d_valkey_ui_log {
|
||||||
redis(
|
redis(
|
||||||
host("redis-mailcow")
|
host("valkey-mailcow")
|
||||||
persist-name("redis1")
|
persist-name("valkey1")
|
||||||
port(6379)
|
port(6379)
|
||||||
auth("`REDISPASS`")
|
auth("`VALKEYPASS`")
|
||||||
command("LPUSH" "POSTFIX_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
|
command("LPUSH" "POSTFIX_MAILLOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
destination d_redis_f2b_channel {
|
destination d_valkey_f2b_channel {
|
||||||
redis(
|
redis(
|
||||||
host("redis-mailcow")
|
host("valkey-mailcow")
|
||||||
persist-name("redis2")
|
persist-name("valkey2")
|
||||||
port(6379)
|
port(6379)
|
||||||
auth("`REDISPASS`")
|
auth("`VALKEYPASS`")
|
||||||
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
|
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -50,6 +50,6 @@ log {
|
|||||||
filter(f_ignore);
|
filter(f_ignore);
|
||||||
destination(d_stdout);
|
destination(d_stdout);
|
||||||
filter(f_mail);
|
filter(f_mail);
|
||||||
destination(d_redis_ui_log);
|
destination(d_valkey_ui_log);
|
||||||
destination(d_redis_f2b_channel);
|
destination(d_valkey_f2b_channel);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ FROM debian:bookworm-slim
|
|||||||
LABEL maintainer="The Infrastructure Company GmbH <info@servercow.de>"
|
LABEL maintainer="The Infrastructure Company GmbH <info@servercow.de>"
|
||||||
|
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
ARG RSPAMD_VER=rspamd_3.13.2-1~8bf602278
|
ARG RSPAMD_VER=rspamd_3.12.1-1~6dbfca2fa
|
||||||
ARG CODENAME=bookworm
|
ARG CODENAME=bookworm
|
||||||
ENV LC_ALL=C
|
ENV LC_ALL=C
|
||||||
|
|
||||||
|
|||||||
@@ -52,33 +52,33 @@ if [[ ! -z ${RSPAMD_V6} ]]; then
|
|||||||
echo ${RSPAMD_V6}/128 >> /etc/rspamd/custom/rspamd_trusted.map
|
echo ${RSPAMD_V6}/128 >> /etc/rspamd/custom/rspamd_trusted.map
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
|
if [[ ! -z ${VALKEY_SLAVEOF_IP} ]]; then
|
||||||
cat <<EOF > /etc/rspamd/local.d/redis.conf
|
cat <<EOF > /etc/rspamd/local.d/redis.conf
|
||||||
read_servers = "redis:6379";
|
read_servers = "valkey-mailcow:6379";
|
||||||
write_servers = "${REDIS_SLAVEOF_IP}:${REDIS_SLAVEOF_PORT}";
|
write_servers = "${VALKEY_SLAVEOF_IP}:${VALKEY_SLAVEOF_PORT}";
|
||||||
password = "${REDISPASS}";
|
password = "${VALKEYPASS}";
|
||||||
timeout = 10;
|
timeout = 10;
|
||||||
EOF
|
EOF
|
||||||
until [[ $(redis-cli -h redis-mailcow -a ${REDISPASS} --no-auth-warning PING) == "PONG" ]]; do
|
until [[ $(redis-cli -h valkey-mailcow -a ${VALKEYPASS} --no-auth-warning PING) == "PONG" ]]; do
|
||||||
echo "Waiting for Redis @redis-mailcow..."
|
echo "Waiting for Valkey @valkey-mailcow..."
|
||||||
sleep 2
|
sleep 2
|
||||||
done
|
done
|
||||||
until [[ $(redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} -a ${REDISPASS} --no-auth-warning PING) == "PONG" ]]; do
|
until [[ $(redis-cli -h ${VALKEY_SLAVEOF_IP} -p ${VALKEY_SLAVEOF_PORT} -a ${VALKEYPASS} --no-auth-warning PING) == "PONG" ]]; do
|
||||||
echo "Waiting for Redis @${REDIS_SLAVEOF_IP}..."
|
echo "Waiting for Valkey @${VALKEY_SLAVEOF_IP}..."
|
||||||
sleep 2
|
sleep 2
|
||||||
done
|
done
|
||||||
redis-cli -h redis-mailcow -a ${REDISPASS} --no-auth-warning SLAVEOF ${REDIS_SLAVEOF_IP} ${REDIS_SLAVEOF_PORT}
|
redis-cli -h valkey-mailcow -a ${VALKEYPASS} --no-auth-warning SLAVEOF ${VALKEY_SLAVEOF_IP} ${VALKEY_SLAVEOF_PORT}
|
||||||
else
|
else
|
||||||
cat <<EOF > /etc/rspamd/local.d/redis.conf
|
cat <<EOF > /etc/rspamd/local.d/redis.conf
|
||||||
servers = "redis:6379";
|
servers = "valkey-mailcow:6379";
|
||||||
password = "${REDISPASS}";
|
password = "${VALKEYPASS}";
|
||||||
timeout = 10;
|
timeout = 10;
|
||||||
EOF
|
EOF
|
||||||
until [[ $(redis-cli -h redis-mailcow -a ${REDISPASS} --no-auth-warning PING) == "PONG" ]]; do
|
until [[ $(redis-cli -h valkey-mailcow -a ${VALKEYPASS} --no-auth-warning PING) == "PONG" ]]; do
|
||||||
echo "Waiting for Redis slave..."
|
echo "Waiting for Valkey slave..."
|
||||||
sleep 2
|
sleep 2
|
||||||
done
|
done
|
||||||
redis-cli -h redis-mailcow -a ${REDISPASS} --no-auth-warning SLAVEOF NO ONE
|
redis-cli -h valkey-mailcow -a ${VALKEYPASS} --no-auth-warning SLAVEOF NO ONE
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${SKIP_OLEFY}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
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 ./bootstrap-sogo.sh /bootstrap-sogo.sh
|
||||||
COPY syslog-ng.conf /etc/syslog-ng/syslog-ng.conf
|
COPY syslog-ng.conf /etc/syslog-ng/syslog-ng.conf
|
||||||
COPY syslog-ng-redis_slave.conf /etc/syslog-ng/syslog-ng-redis_slave.conf
|
COPY syslog-ng-valkey_slave.conf /etc/syslog-ng/syslog-ng-valkey_slave.conf
|
||||||
COPY supervisord.conf /etc/supervisor/supervisord.conf
|
COPY supervisord.conf /etc/supervisor/supervisord.conf
|
||||||
COPY acl.diff /acl.diff
|
COPY acl.diff /acl.diff
|
||||||
COPY navMailcowBtns.diff /navMailcowBtns.diff
|
COPY navMailcowBtns.diff /navMailcowBtns.diff
|
||||||
|
|||||||
@@ -50,6 +50,10 @@ cat <<EOF > /var/lib/sogo/GNUstep/Defaults/sogod.plist
|
|||||||
<string>YES</string>
|
<string>YES</string>
|
||||||
<key>SOGoEncryptionKey</key>
|
<key>SOGoEncryptionKey</key>
|
||||||
<string>${RAND_PASS}</string>
|
<string>${RAND_PASS}</string>
|
||||||
|
<key>SOGoURLEncryptionEnabled</key>
|
||||||
|
<string>YES</string>
|
||||||
|
<key>SOGoURLEncryptionPassphrase</key>
|
||||||
|
<string>${SOGO_URL_ENCRYPTION_KEY}</string>
|
||||||
<key>OCSAdminURL</key>
|
<key>OCSAdminURL</key>
|
||||||
<string>mysql://${DBUSER}:${DBPASS}@%2Fvar%2Frun%2Fmysqld%2Fmysqld.sock/${DBNAME}/sogo_admin</string>
|
<string>mysql://${DBUSER}:${DBPASS}@%2Fvar%2Frun%2Fmysqld%2Fmysqld.sock/${DBNAME}/sogo_admin</string>
|
||||||
<key>OCSCacheFolderURL</key>
|
<key>OCSCacheFolderURL</key>
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ if [[ "${SKIP_SOGO}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
|
if [[ ! -z ${VALKEY_SLAVEOF_IP} ]]; then
|
||||||
cp /etc/syslog-ng/syslog-ng-redis_slave.conf /etc/syslog-ng/syslog-ng.conf
|
cp /etc/syslog-ng/syslog-ng-valkey_slave.conf /etc/syslog-ng/syslog-ng.conf
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "$TZ" > /etc/timezone
|
echo "$TZ" > /etc/timezone
|
||||||
|
|||||||
@@ -17,28 +17,28 @@ source s_sogo {
|
|||||||
pipe("/dev/sogo_log" owner(sogo) group(sogo));
|
pipe("/dev/sogo_log" owner(sogo) group(sogo));
|
||||||
};
|
};
|
||||||
destination d_stdout { pipe("/dev/stdout"); };
|
destination d_stdout { pipe("/dev/stdout"); };
|
||||||
destination d_redis_ui_log {
|
destination d_valkey_ui_log {
|
||||||
redis(
|
redis(
|
||||||
host("`REDIS_SLAVEOF_IP`")
|
host("`VALKEY_SLAVEOF_IP`")
|
||||||
persist-name("redis1")
|
persist-name("valkey1")
|
||||||
port(`REDIS_SLAVEOF_PORT`)
|
port(`VALKEY_SLAVEOF_PORT`)
|
||||||
auth("`REDISPASS`")
|
auth("`VALKEYPASS`")
|
||||||
command("LPUSH" "SOGO_LOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
|
command("LPUSH" "SOGO_LOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
destination d_redis_f2b_channel {
|
destination d_valkey_f2b_channel {
|
||||||
redis(
|
redis(
|
||||||
host("`REDIS_SLAVEOF_IP`")
|
host("`VALKEY_SLAVEOF_IP`")
|
||||||
persist-name("redis2")
|
persist-name("valkey2")
|
||||||
port(`REDIS_SLAVEOF_PORT`)
|
port(`VALKEY_SLAVEOF_PORT`)
|
||||||
auth("`REDISPASS`")
|
auth("`VALKEYPASS`")
|
||||||
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
|
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
log {
|
log {
|
||||||
source(s_sogo);
|
source(s_sogo);
|
||||||
destination(d_redis_ui_log);
|
destination(d_valkey_ui_log);
|
||||||
destination(d_redis_f2b_channel);
|
destination(d_valkey_f2b_channel);
|
||||||
};
|
};
|
||||||
log {
|
log {
|
||||||
source(s_sogo);
|
source(s_sogo);
|
||||||
@@ -17,28 +17,28 @@ source s_sogo {
|
|||||||
pipe("/dev/sogo_log" owner(sogo) group(sogo));
|
pipe("/dev/sogo_log" owner(sogo) group(sogo));
|
||||||
};
|
};
|
||||||
destination d_stdout { pipe("/dev/stdout"); };
|
destination d_stdout { pipe("/dev/stdout"); };
|
||||||
destination d_redis_ui_log {
|
destination d_valkey_ui_log {
|
||||||
redis(
|
redis(
|
||||||
host("redis-mailcow")
|
host("valkey-mailcow")
|
||||||
persist-name("redis1")
|
persist-name("valkey1")
|
||||||
port(6379)
|
port(6379)
|
||||||
auth("`REDISPASS`")
|
auth("`VALKEYPASS`")
|
||||||
command("LPUSH" "SOGO_LOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
|
command("LPUSH" "SOGO_LOG" "$(format-json time=\"$S_UNIXTIME\" priority=\"$PRIORITY\" program=\"$PROGRAM\" message=\"$MESSAGE\")\n")
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
destination d_redis_f2b_channel {
|
destination d_valkey_f2b_channel {
|
||||||
redis(
|
redis(
|
||||||
host("redis-mailcow")
|
host("valkey-mailcow")
|
||||||
persist-name("redis2")
|
persist-name("valkey2")
|
||||||
port(6379)
|
port(6379)
|
||||||
auth("`REDISPASS`")
|
auth("`VALKEYPASS`")
|
||||||
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
|
command("PUBLISH" "F2B_CHANNEL" "$(sanitize $MESSAGE)")
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
log {
|
log {
|
||||||
source(s_sogo);
|
source(s_sogo);
|
||||||
destination(d_redis_ui_log);
|
destination(d_valkey_ui_log);
|
||||||
destination(d_redis_f2b_channel);
|
destination(d_valkey_f2b_channel);
|
||||||
};
|
};
|
||||||
log {
|
log {
|
||||||
source(s_sogo);
|
source(s_sogo);
|
||||||
|
|||||||
8
data/Dockerfiles/valkeymigrator/Dockerfile
Normal file
8
data/Dockerfiles/valkeymigrator/Dockerfile
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
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"]
|
||||||
78
data/Dockerfiles/valkeymigrator/migrate.py
Normal file
78
data/Dockerfiles/valkeymigrator/migrate.py
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
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
|
done
|
||||||
|
|
||||||
# Do not attempt to write to slave
|
# Do not attempt to write to slave
|
||||||
if [[ ! -z ${REDIS_SLAVEOF_IP} ]]; then
|
if [[ ! -z ${VALKEY_SLAVEOF_IP} ]]; then
|
||||||
REDIS_CMDLINE="redis-cli -h ${REDIS_SLAVEOF_IP} -p ${REDIS_SLAVEOF_PORT} -a ${REDISPASS} --no-auth-warning"
|
VALKEY_CMDLINE="redis-cli -h ${VALKEY_SLAVEOF_IP} -p ${VALKEY_SLAVEOF_PORT} -a ${VALKEYPASS} --no-auth-warning"
|
||||||
else
|
else
|
||||||
REDIS_CMDLINE="redis-cli -h redis -p 6379 -a ${REDISPASS} --no-auth-warning"
|
VALKEY_CMDLINE="redis-cli -h valkey-mailcow -p 6379 -a ${VALKEYPASS} --no-auth-warning"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
until [[ $(${REDIS_CMDLINE} PING) == "PONG" ]]; do
|
until [[ $(${VALKEY_CMDLINE} PING) == "PONG" ]]; do
|
||||||
echo "Waiting for Redis..."
|
echo "Waiting for Valkey..."
|
||||||
sleep 2
|
sleep 2
|
||||||
done
|
done
|
||||||
|
|
||||||
${REDIS_CMDLINE} DEL F2B_RES > /dev/null
|
${VALKEY_CMDLINE} DEL F2B_RES > /dev/null
|
||||||
|
|
||||||
# Common functions
|
# Common functions
|
||||||
get_ipv6(){
|
get_ipv6(){
|
||||||
@@ -90,15 +90,15 @@ progress() {
|
|||||||
[[ ${CURRENT} -gt ${TOTAL} ]] && return
|
[[ ${CURRENT} -gt ${TOTAL} ]] && return
|
||||||
[[ ${CURRENT} -lt 0 ]] && CURRENT=0
|
[[ ${CURRENT} -lt 0 ]] && CURRENT=0
|
||||||
PERCENT=$(( 200 * ${CURRENT} / ${TOTAL} % 2 + 100 * ${CURRENT} / ${TOTAL} ))
|
PERCENT=$(( 200 * ${CURRENT} / ${TOTAL} % 2 + 100 * ${CURRENT} / ${TOTAL} ))
|
||||||
${REDIS_CMDLINE} LPUSH WATCHDOG_LOG "{\"time\":\"$(date +%s)\",\"service\":\"${SERVICE}\",\"lvl\":\"${PERCENT}\",\"hpnow\":\"${CURRENT}\",\"hptotal\":\"${TOTAL}\",\"hpdiff\":\"${DIFF}\"}" > /dev/null
|
${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_redis
|
log_msg "${SERVICE} health level: ${PERCENT}% (${CURRENT}/${TOTAL}), health trend: ${DIFF}" no_valkey
|
||||||
# Return 10 to indicate a dead service
|
# Return 10 to indicate a dead service
|
||||||
[ ${CURRENT} -le 0 ] && return 10
|
[ ${CURRENT} -le 0 ] && return 10
|
||||||
}
|
}
|
||||||
|
|
||||||
log_msg() {
|
log_msg() {
|
||||||
if [[ ${2} != "no_redis" ]]; then
|
if [[ ${2} != "no_valkey" ]]; then
|
||||||
${REDIS_CMDLINE} LPUSH WATCHDOG_LOG "{\"time\":\"$(date +%s)\",\"message\":\"$(printf '%s' "${1}" | \
|
${VALKEY_CMDLINE} LPUSH WATCHDOG_LOG "{\"time\":\"$(date +%s)\",\"message\":\"$(printf '%s' "${1}" | \
|
||||||
tr '\r\n%&;$"_[]{}-' ' ')\"}" > /dev/null
|
tr '\r\n%&;$"_[]{}-' ' ')\"}" > /dev/null
|
||||||
fi
|
fi
|
||||||
echo $(date) $(printf '%s\n' "${1}")
|
echo $(date) $(printf '%s\n' "${1}")
|
||||||
@@ -114,10 +114,10 @@ function notify_error() {
|
|||||||
# If exists, mail will be throttled by argument in seconds
|
# If exists, mail will be throttled by argument in seconds
|
||||||
[[ ! -z ${3} ]] && THROTTLE=${3}
|
[[ ! -z ${3} ]] && THROTTLE=${3}
|
||||||
if [[ ! -z ${THROTTLE} ]]; then
|
if [[ ! -z ${THROTTLE} ]]; then
|
||||||
TTL_LEFT="$(${REDIS_CMDLINE} TTL THROTTLE_${1} 2> /dev/null)"
|
TTL_LEFT="$(${VALKEY_CMDLINE} TTL THROTTLE_${1} 2> /dev/null)"
|
||||||
if [[ "${TTL_LEFT}" == "-2" ]]; then
|
if [[ "${TTL_LEFT}" == "-2" ]]; then
|
||||||
# Delay key not found, setting a delay key now
|
# Delay key not found, setting a delay key now
|
||||||
${REDIS_CMDLINE} SET THROTTLE_${1} 1 EX ${THROTTLE}
|
${VALKEY_CMDLINE} SET THROTTLE_${1} 1 EX ${THROTTLE}
|
||||||
else
|
else
|
||||||
log_msg "Not sending notification email now, blocked for ${TTL_LEFT} seconds..."
|
log_msg "Not sending notification email now, blocked for ${TTL_LEFT} seconds..."
|
||||||
return 1
|
return 1
|
||||||
@@ -324,21 +324,21 @@ unbound_checks() {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
redis_checks() {
|
valkey_checks() {
|
||||||
# A check for the local redis container
|
# A check for the local valkey container
|
||||||
err_count=0
|
err_count=0
|
||||||
diff_c=0
|
diff_c=0
|
||||||
THRESHOLD=${REDIS_THRESHOLD}
|
THRESHOLD=${VALKEY_THRESHOLD}
|
||||||
# Reduce error count by 2 after restarting an unhealthy container
|
# Reduce error count by 2 after restarting an unhealthy container
|
||||||
trap "[ ${err_count} -gt 1 ] && err_count=$(( ${err_count} - 2 ))" USR1
|
trap "[ ${err_count} -gt 1 ] && err_count=$(( ${err_count} - 2 ))" USR1
|
||||||
while [ ${err_count} -lt ${THRESHOLD} ]; do
|
while [ ${err_count} -lt ${THRESHOLD} ]; do
|
||||||
touch /tmp/redis-mailcow; echo "$(tail -50 /tmp/redis-mailcow)" > /tmp/redis-mailcow
|
touch /tmp/valkey-mailcow; echo "$(tail -50 /tmp/valkey-mailcow)" > /tmp/valkey-mailcow
|
||||||
host_ip=$(get_container_ip redis-mailcow)
|
host_ip=$(get_container_ip valkey-mailcow)
|
||||||
err_c_cur=${err_count}
|
err_c_cur=${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} + $? ))
|
/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} + $? ))
|
||||||
[ ${err_c_cur} -eq ${err_count} ] && [ ! $((${err_count} - 1)) -lt 0 ] && err_count=$((${err_count} - 1)) diff_c=1
|
[ ${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} ))
|
[ ${err_c_cur} -ne ${err_count} ] && diff_c=$(( ${err_c_cur} - ${err_count} ))
|
||||||
progress "Redis" ${THRESHOLD} $(( ${THRESHOLD} - ${err_count} )) ${diff_c}
|
progress "Valkey" ${THRESHOLD} $(( ${THRESHOLD} - ${err_count} )) ${diff_c}
|
||||||
if [[ $? == 10 ]]; then
|
if [[ $? == 10 ]]; then
|
||||||
diff_c=0
|
diff_c=0
|
||||||
sleep 1
|
sleep 1
|
||||||
@@ -533,12 +533,12 @@ dovecot_repl_checks() {
|
|||||||
err_count=0
|
err_count=0
|
||||||
diff_c=0
|
diff_c=0
|
||||||
THRESHOLD=${DOVECOT_REPL_THRESHOLD}
|
THRESHOLD=${DOVECOT_REPL_THRESHOLD}
|
||||||
D_REPL_STATUS=$(redis-cli -h redis -a ${REDISPASS} --no-auth-warning -r GET DOVECOT_REPL_HEALTH)
|
D_REPL_STATUS=$(redis-cli -h valkey-mailcow -a ${VALKEYPASS} --no-auth-warning -r GET DOVECOT_REPL_HEALTH)
|
||||||
# Reduce error count by 2 after restarting an unhealthy container
|
# Reduce error count by 2 after restarting an unhealthy container
|
||||||
trap "[ ${err_count} -gt 1 ] && err_count=$(( ${err_count} - 2 ))" USR1
|
trap "[ ${err_count} -gt 1 ] && err_count=$(( ${err_count} - 2 ))" USR1
|
||||||
while [ ${err_count} -lt ${THRESHOLD} ]; do
|
while [ ${err_count} -lt ${THRESHOLD} ]; do
|
||||||
err_c_cur=${err_count}
|
err_c_cur=${err_count}
|
||||||
D_REPL_STATUS=$(redis-cli --raw -h redis -a ${REDISPASS} --no-auth-warning GET DOVECOT_REPL_HEALTH)
|
D_REPL_STATUS=$(redis-cli --raw -h valkey-mailcow -a ${VALKEYPASS} --no-auth-warning GET DOVECOT_REPL_HEALTH)
|
||||||
if [[ "${D_REPL_STATUS}" != "1" ]]; then
|
if [[ "${D_REPL_STATUS}" != "1" ]]; then
|
||||||
err_count=$(( ${err_count} + 1 ))
|
err_count=$(( ${err_count} + 1 ))
|
||||||
fi
|
fi
|
||||||
@@ -608,19 +608,19 @@ ratelimit_checks() {
|
|||||||
err_count=0
|
err_count=0
|
||||||
diff_c=0
|
diff_c=0
|
||||||
THRESHOLD=${RATELIMIT_THRESHOLD}
|
THRESHOLD=${RATELIMIT_THRESHOLD}
|
||||||
RL_LOG_STATUS=$(redis-cli -h redis -a ${REDISPASS} --no-auth-warning LRANGE RL_LOG 0 0 | jq .qid)
|
RL_LOG_STATUS=$(redis-cli -h valkey-mailcow -a ${VALKEYPASS} --no-auth-warning LRANGE RL_LOG 0 0 | jq .qid)
|
||||||
# Reduce error count by 2 after restarting an unhealthy container
|
# Reduce error count by 2 after restarting an unhealthy container
|
||||||
trap "[ ${err_count} -gt 1 ] && err_count=$(( ${err_count} - 2 ))" USR1
|
trap "[ ${err_count} -gt 1 ] && err_count=$(( ${err_count} - 2 ))" USR1
|
||||||
while [ ${err_count} -lt ${THRESHOLD} ]; do
|
while [ ${err_count} -lt ${THRESHOLD} ]; do
|
||||||
err_c_cur=${err_count}
|
err_c_cur=${err_count}
|
||||||
RL_LOG_STATUS_PREV=${RL_LOG_STATUS}
|
RL_LOG_STATUS_PREV=${RL_LOG_STATUS}
|
||||||
RL_LOG_STATUS=$(redis-cli -h redis -a ${REDISPASS} --no-auth-warning LRANGE RL_LOG 0 0 | jq .qid)
|
RL_LOG_STATUS=$(redis-cli -h valkey-mailcow -a ${VALKEYPASS} --no-auth-warning LRANGE RL_LOG 0 0 | jq .qid)
|
||||||
if [[ ${RL_LOG_STATUS_PREV} != ${RL_LOG_STATUS} ]]; then
|
if [[ ${RL_LOG_STATUS_PREV} != ${RL_LOG_STATUS} ]]; then
|
||||||
err_count=$(( ${err_count} + 1 ))
|
err_count=$(( ${err_count} + 1 ))
|
||||||
echo 'Last 10 applied ratelimits (may overlap with previous reports).' > /tmp/ratelimit
|
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 'Full ratelimit buckets can be emptied by deleting the ratelimit hash from within mailcow UI (see /debug -> Protocols -> Ratelimit):' >> /tmp/ratelimit
|
||||||
echo >> /tmp/ratelimit
|
echo >> /tmp/ratelimit
|
||||||
redis-cli --raw -h redis -a ${REDISPASS} --no-auth-warning LRANGE RL_LOG 0 10 | jq . >> /tmp/ratelimit
|
redis-cli --raw -h valkey-mailcow -a ${VALKEYPASS} --no-auth-warning LRANGE RL_LOG 0 10 | jq . >> /tmp/ratelimit
|
||||||
fi
|
fi
|
||||||
[ ${err_c_cur} -eq ${err_count} ] && [ ! $((${err_count} - 1)) -lt 0 ] && err_count=$((${err_count} - 1)) diff_c=1
|
[ ${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} ))
|
[ ${err_c_cur} -ne ${err_count} ] && diff_c=$(( ${err_c_cur} - ${err_count} ))
|
||||||
@@ -669,20 +669,20 @@ fail2ban_checks() {
|
|||||||
err_count=0
|
err_count=0
|
||||||
diff_c=0
|
diff_c=0
|
||||||
THRESHOLD=${FAIL2BAN_THRESHOLD}
|
THRESHOLD=${FAIL2BAN_THRESHOLD}
|
||||||
F2B_LOG_STATUS=($(${REDIS_CMDLINE} --raw HKEYS F2B_ACTIVE_BANS))
|
F2B_LOG_STATUS=($(${VALKEY_CMDLINE} --raw HKEYS F2B_ACTIVE_BANS))
|
||||||
F2B_RES=
|
F2B_RES=
|
||||||
# Reduce error count by 2 after restarting an unhealthy container
|
# Reduce error count by 2 after restarting an unhealthy container
|
||||||
trap "[ ${err_count} -gt 1 ] && err_count=$(( ${err_count} - 2 ))" USR1
|
trap "[ ${err_count} -gt 1 ] && err_count=$(( ${err_count} - 2 ))" USR1
|
||||||
while [ ${err_count} -lt ${THRESHOLD} ]; do
|
while [ ${err_count} -lt ${THRESHOLD} ]; do
|
||||||
err_c_cur=${err_count}
|
err_c_cur=${err_count}
|
||||||
F2B_LOG_STATUS_PREV=(${F2B_LOG_STATUS[@]})
|
F2B_LOG_STATUS_PREV=(${F2B_LOG_STATUS[@]})
|
||||||
F2B_LOG_STATUS=($(${REDIS_CMDLINE} --raw HKEYS F2B_ACTIVE_BANS))
|
F2B_LOG_STATUS=($(${VALKEY_CMDLINE} --raw HKEYS F2B_ACTIVE_BANS))
|
||||||
array_diff F2B_RES F2B_LOG_STATUS F2B_LOG_STATUS_PREV
|
array_diff F2B_RES F2B_LOG_STATUS F2B_LOG_STATUS_PREV
|
||||||
if [[ ! -z "${F2B_RES}" ]]; then
|
if [[ ! -z "${F2B_RES}" ]]; then
|
||||||
err_count=$(( ${err_count} + 1 ))
|
err_count=$(( ${err_count} + 1 ))
|
||||||
echo -n "${F2B_RES[@]}" | tr -cd "[a-fA-F0-9.:/] " | timeout 3s ${REDIS_CMDLINE} -x SET F2B_RES > /dev/null
|
echo -n "${F2B_RES[@]}" | tr -cd "[a-fA-F0-9.:/] " | timeout 3s ${VALKEY_CMDLINE} -x SET F2B_RES > /dev/null
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
${REDIS_CMDLINE} -x DEL F2B_RES
|
${VALKEY_CMDLINE} -x DEL F2B_RES
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
[ ${err_c_cur} -eq ${err_count} ] && [ ! $((${err_count} - 1)) -lt 0 ] && err_count=$((${err_count} - 1)) diff_c=1
|
[ ${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
|
err_count=0
|
||||||
diff_c=0
|
diff_c=0
|
||||||
THRESHOLD=${ACME_THRESHOLD}
|
THRESHOLD=${ACME_THRESHOLD}
|
||||||
ACME_LOG_STATUS=$(redis-cli -h redis -a ${REDISPASS} --no-auth-warning GET ACME_FAIL_TIME)
|
ACME_LOG_STATUS=$(redis-cli -h valkey-mailcow -a ${VALKEYPASS} --no-auth-warning GET ACME_FAIL_TIME)
|
||||||
if [[ -z "${ACME_LOG_STATUS}" ]]; then
|
if [[ -z "${ACME_LOG_STATUS}" ]]; then
|
||||||
${REDIS_CMDLINE} SET ACME_FAIL_TIME 0
|
${VALKEY_CMDLINE} SET ACME_FAIL_TIME 0
|
||||||
ACME_LOG_STATUS=0
|
ACME_LOG_STATUS=0
|
||||||
fi
|
fi
|
||||||
# Reduce error count by 2 after restarting an unhealthy container
|
# Reduce error count by 2 after restarting an unhealthy container
|
||||||
@@ -715,7 +715,7 @@ acme_checks() {
|
|||||||
ACME_LOG_STATUS_PREV=${ACME_LOG_STATUS}
|
ACME_LOG_STATUS_PREV=${ACME_LOG_STATUS}
|
||||||
ACME_LC=0
|
ACME_LC=0
|
||||||
until [[ ! -z ${ACME_LOG_STATUS} ]] || [ ${ACME_LC} -ge 3 ]; do
|
until [[ ! -z ${ACME_LOG_STATUS} ]] || [ ${ACME_LC} -ge 3 ]; do
|
||||||
ACME_LOG_STATUS=$(redis-cli -h redis -a ${REDISPASS} --no-auth-warning GET ACME_FAIL_TIME 2> /dev/null)
|
ACME_LOG_STATUS=$(redis-cli -h valkey-mailcow -a ${VALKEYPASS} --no-auth-warning GET ACME_FAIL_TIME 2> /dev/null)
|
||||||
sleep 3
|
sleep 3
|
||||||
ACME_LC=$((ACME_LC+1))
|
ACME_LC=$((ACME_LC+1))
|
||||||
done
|
done
|
||||||
@@ -864,14 +864,14 @@ BACKGROUND_TASKS+=(${PID})
|
|||||||
|
|
||||||
(
|
(
|
||||||
while true; do
|
while true; do
|
||||||
if ! redis_checks; then
|
if ! valkey_checks; then
|
||||||
log_msg "Local Redis hit error limit"
|
log_msg "Local Valkey hit error limit"
|
||||||
echo redis-mailcow > /tmp/com_pipe
|
echo valkey-mailcow > /tmp/com_pipe
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
) &
|
) &
|
||||||
PID=$!
|
PID=$!
|
||||||
echo "Spawned redis_checks with PID ${PID}"
|
echo "Spawned valkey_checks with PID ${PID}"
|
||||||
BACKGROUND_TASKS+=(${PID})
|
BACKGROUND_TASKS+=(${PID})
|
||||||
|
|
||||||
(
|
(
|
||||||
@@ -1129,9 +1129,9 @@ while true; do
|
|||||||
# Define $2 to override message text, else print service was restarted at ...
|
# Define $2 to override message text, else print service was restarted at ...
|
||||||
notify_error "${com_pipe_answer}" "Please check acme-mailcow for further information."
|
notify_error "${com_pipe_answer}" "Please check acme-mailcow for further information."
|
||||||
elif [[ ${com_pipe_answer} == "fail2ban" ]]; then
|
elif [[ ${com_pipe_answer} == "fail2ban" ]]; then
|
||||||
F2B_RES=($(timeout 4s ${REDIS_CMDLINE} --raw GET F2B_RES 2> /dev/null))
|
F2B_RES=($(timeout 4s ${VALKEY_CMDLINE} --raw GET F2B_RES 2> /dev/null))
|
||||||
if [[ ! -z "${F2B_RES}" ]]; then
|
if [[ ! -z "${F2B_RES}" ]]; then
|
||||||
${REDIS_CMDLINE} DEL F2B_RES > /dev/null
|
${VALKEY_CMDLINE} DEL F2B_RES > /dev/null
|
||||||
host=
|
host=
|
||||||
for host in "${F2B_RES[@]}"; do
|
for host in "${F2B_RES[@]}"; do
|
||||||
log_msg "Banned ${host}"
|
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';
|
require_once '../../../web/inc/lib/vendor/autoload.php';
|
||||||
|
|
||||||
|
|
||||||
// Init Redis
|
// Init Valkey
|
||||||
$redis = new Redis();
|
$valkey = new Redis();
|
||||||
try {
|
try {
|
||||||
if (!empty(getenv('REDIS_SLAVEOF_IP'))) {
|
if (!empty(getenv('VALKEY_SLAVEOF_IP'))) {
|
||||||
$redis->connect(getenv('REDIS_SLAVEOF_IP'), getenv('REDIS_SLAVEOF_PORT'));
|
$valkey->connect(getenv('VALKEY_SLAVEOF_IP'), getenv('VALKEY_SLAVEOF_PORT'));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$redis->connect('redis-mailcow', 6379);
|
$valkey->connect('valkey-mailcow', 6379);
|
||||||
}
|
}
|
||||||
$redis->auth(getenv("REDISPASS"));
|
$valkey->auth(getenv("VALKEYPASS"));
|
||||||
}
|
}
|
||||||
catch (Exception $e) {
|
catch (Exception $e) {
|
||||||
error_log("MAILCOWAUTH: " . $e . PHP_EOL);
|
error_log("MAILCOWAUTH: " . $e . PHP_EOL);
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ events {
|
|||||||
http {
|
http {
|
||||||
include /etc/nginx/mime.types;
|
include /etc/nginx/mime.types;
|
||||||
default_type application/octet-stream;
|
default_type application/octet-stream;
|
||||||
server_tokens off;
|
|
||||||
|
|
||||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||||
'$status $body_bytes_sent "$http_referer" '
|
'$status $body_bytes_sent "$http_referer" '
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ ssl_session_tickets off;
|
|||||||
|
|
||||||
add_header Strict-Transport-Security "max-age=15768000;";
|
add_header Strict-Transport-Security "max-age=15768000;";
|
||||||
add_header X-Content-Type-Options nosniff;
|
add_header X-Content-Type-Options nosniff;
|
||||||
|
add_header X-XSS-Protection "1; mode=block";
|
||||||
add_header X-Robots-Tag none;
|
add_header X-Robots-Tag none;
|
||||||
add_header X-Download-Options noopen;
|
add_header X-Download-Options noopen;
|
||||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||||
|
|||||||
@@ -23,16 +23,16 @@ catch (PDOException $e) {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init Redis
|
// Init Valkey
|
||||||
$redis = new Redis();
|
$valkey = new Redis();
|
||||||
try {
|
try {
|
||||||
if (!empty(getenv('REDIS_SLAVEOF_IP'))) {
|
if (!empty(getenv('VALKEY_SLAVEOF_IP'))) {
|
||||||
$redis->connect(getenv('REDIS_SLAVEOF_IP'), getenv('REDIS_SLAVEOF_PORT'));
|
$valkey->connect(getenv('VALKEY_SLAVEOF_IP'), getenv('VALKEY_SLAVEOF_PORT'));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$redis->connect('redis-mailcow', 6379);
|
$valkey->connect('valkey-mailcow', 6379);
|
||||||
}
|
}
|
||||||
$redis->auth(getenv("REDISPASS"));
|
$valkey->auth(getenv("VALKEYPASS"));
|
||||||
}
|
}
|
||||||
catch (Exception $e) {
|
catch (Exception $e) {
|
||||||
echo "Exiting: " . $e->getMessage();
|
echo "Exiting: " . $e->getMessage();
|
||||||
@@ -41,7 +41,7 @@ catch (Exception $e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function logMsg($priority, $message, $task = "Keycloak Sync") {
|
function logMsg($priority, $message, $task = "Keycloak Sync") {
|
||||||
global $redis;
|
global $valkey;
|
||||||
|
|
||||||
$finalMsg = array(
|
$finalMsg = array(
|
||||||
"time" => time(),
|
"time" => time(),
|
||||||
@@ -49,7 +49,7 @@ function logMsg($priority, $message, $task = "Keycloak Sync") {
|
|||||||
"task" => $task,
|
"task" => $task,
|
||||||
"message" => $message
|
"message" => $message
|
||||||
);
|
);
|
||||||
$redis->lPush('CRON_LOG', json_encode($finalMsg));
|
$valkey->lPush('CRON_LOG', json_encode($finalMsg));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load core functions first
|
// Load core functions first
|
||||||
|
|||||||
@@ -23,16 +23,16 @@ catch (PDOException $e) {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init Redis
|
// Init Valkey
|
||||||
$redis = new Redis();
|
$valkey = new Redis();
|
||||||
try {
|
try {
|
||||||
if (!empty(getenv('REDIS_SLAVEOF_IP'))) {
|
if (!empty(getenv('VALKEY_SLAVEOF_IP'))) {
|
||||||
$redis->connect(getenv('REDIS_SLAVEOF_IP'), getenv('REDIS_SLAVEOF_PORT'));
|
$valkey->connect(getenv('VALKEY_SLAVEOF_IP'), getenv('VALKEY_SLAVEOF_PORT'));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$redis->connect('redis-mailcow', 6379);
|
$valkey->connect('valkey-mailcow', 6379);
|
||||||
}
|
}
|
||||||
$redis->auth(getenv("REDISPASS"));
|
$valkey->auth(getenv("VALKEYPASS"));
|
||||||
}
|
}
|
||||||
catch (Exception $e) {
|
catch (Exception $e) {
|
||||||
echo "Exiting: " . $e->getMessage();
|
echo "Exiting: " . $e->getMessage();
|
||||||
@@ -41,7 +41,7 @@ catch (Exception $e) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function logMsg($priority, $message, $task = "LDAP Sync") {
|
function logMsg($priority, $message, $task = "LDAP Sync") {
|
||||||
global $redis;
|
global $valkey;
|
||||||
|
|
||||||
$finalMsg = array(
|
$finalMsg = array(
|
||||||
"time" => time(),
|
"time" => time(),
|
||||||
@@ -49,7 +49,7 @@ function logMsg($priority, $message, $task = "LDAP Sync") {
|
|||||||
"task" => $task,
|
"task" => $task,
|
||||||
"message" => $message
|
"message" => $message
|
||||||
);
|
);
|
||||||
$redis->lPush('CRON_LOG', json_encode($finalMsg));
|
$valkey->lPush('CRON_LOG', json_encode($finalMsg));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load core functions first
|
// Load core functions first
|
||||||
|
|||||||
@@ -1,16 +1,7 @@
|
|||||||
; NOTE: Restart phpfpm on ANY manual changes to PHP files!
|
|
||||||
|
|
||||||
; opcache
|
|
||||||
opcache.enable=1
|
opcache.enable=1
|
||||||
opcache.enable_cli=1
|
opcache.enable_cli=1
|
||||||
opcache.interned_strings_buffer=16
|
opcache.interned_strings_buffer=16
|
||||||
opcache.max_accelerated_files=10000
|
opcache.max_accelerated_files=10000
|
||||||
opcache.memory_consumption=128
|
opcache.memory_consumption=128
|
||||||
opcache.save_comments=1
|
opcache.save_comments=1
|
||||||
opcache.validate_timestamps=0
|
opcache.revalidate_freq=1
|
||||||
|
|
||||||
; 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 Mon Dec 1 00:24:43 UTC 2025
|
# Whitelist generated by Postwhite v3.4 on Wed Oct 1 00:21:33 UTC 2025
|
||||||
# https://github.com/stevejenkins/postwhite/
|
# https://github.com/stevejenkins/postwhite/
|
||||||
# 2186 total rules
|
# 2216 total rules
|
||||||
2a00:1450:4000::/36 permit
|
2a00:1450:4000::/36 permit
|
||||||
2a01:111:f400::/48 permit
|
2a01:111:f400::/48 permit
|
||||||
2a01:111:f403:2800::/53 permit
|
2a01:111:f403:2800::/53 permit
|
||||||
@@ -29,9 +29,7 @@
|
|||||||
2a01:b747:3005:200::/56 permit
|
2a01:b747:3005:200::/56 permit
|
||||||
2a01:b747:3006:200::/56 permit
|
2a01:b747:3006:200::/56 permit
|
||||||
2a02:a60:0:5::/64 permit
|
2a02:a60:0:5::/64 permit
|
||||||
2a0f:f640::/56 permit
|
|
||||||
2c0f:fb50:4000::/36 permit
|
2c0f:fb50:4000::/36 permit
|
||||||
2.207.151.53 permit
|
|
||||||
2.207.217.30 permit
|
2.207.217.30 permit
|
||||||
3.64.237.68 permit
|
3.64.237.68 permit
|
||||||
3.65.3.180 permit
|
3.65.3.180 permit
|
||||||
@@ -52,11 +50,14 @@
|
|||||||
8.25.194.0/23 permit
|
8.25.194.0/23 permit
|
||||||
8.25.196.0/23 permit
|
8.25.196.0/23 permit
|
||||||
8.36.116.0/24 permit
|
8.36.116.0/24 permit
|
||||||
|
8.39.54.0/23 permit
|
||||||
|
8.39.54.250/31 permit
|
||||||
8.39.144.0/24 permit
|
8.39.144.0/24 permit
|
||||||
|
8.40.222.0/23 permit
|
||||||
|
8.40.222.250/31 permit
|
||||||
12.130.86.238 permit
|
12.130.86.238 permit
|
||||||
13.107.213.69 permit
|
13.107.213.41 permit
|
||||||
13.107.246.69 permit
|
13.107.246.41 permit
|
||||||
13.108.16.0/20 permit
|
|
||||||
13.110.208.0/21 permit
|
13.110.208.0/21 permit
|
||||||
13.110.209.0/24 permit
|
13.110.209.0/24 permit
|
||||||
13.110.216.0/22 permit
|
13.110.216.0/22 permit
|
||||||
@@ -65,7 +66,6 @@
|
|||||||
13.111.191.0/24 permit
|
13.111.191.0/24 permit
|
||||||
13.216.7.111 permit
|
13.216.7.111 permit
|
||||||
13.216.54.180 permit
|
13.216.54.180 permit
|
||||||
13.247.164.219 permit
|
|
||||||
15.200.21.50 permit
|
15.200.21.50 permit
|
||||||
15.200.44.248 permit
|
15.200.44.248 permit
|
||||||
15.200.201.185 permit
|
15.200.201.185 permit
|
||||||
@@ -169,6 +169,7 @@
|
|||||||
34.215.104.144 permit
|
34.215.104.144 permit
|
||||||
34.218.115.239 permit
|
34.218.115.239 permit
|
||||||
34.225.212.172 permit
|
34.225.212.172 permit
|
||||||
|
34.241.242.183 permit
|
||||||
35.83.148.184 permit
|
35.83.148.184 permit
|
||||||
35.155.198.111 permit
|
35.155.198.111 permit
|
||||||
35.158.23.94 permit
|
35.158.23.94 permit
|
||||||
@@ -192,6 +193,7 @@
|
|||||||
40.233.64.216 permit
|
40.233.64.216 permit
|
||||||
40.233.83.78 permit
|
40.233.83.78 permit
|
||||||
40.233.88.28 permit
|
40.233.88.28 permit
|
||||||
|
43.239.212.33 permit
|
||||||
44.206.138.57 permit
|
44.206.138.57 permit
|
||||||
44.210.169.44 permit
|
44.210.169.44 permit
|
||||||
44.217.45.156 permit
|
44.217.45.156 permit
|
||||||
@@ -273,6 +275,7 @@
|
|||||||
50.112.246.219 permit
|
50.112.246.219 permit
|
||||||
52.1.14.157 permit
|
52.1.14.157 permit
|
||||||
52.5.230.59 permit
|
52.5.230.59 permit
|
||||||
|
52.6.74.205 permit
|
||||||
52.12.53.23 permit
|
52.12.53.23 permit
|
||||||
52.13.214.179 permit
|
52.13.214.179 permit
|
||||||
52.26.1.71 permit
|
52.26.1.71 permit
|
||||||
@@ -299,6 +302,7 @@
|
|||||||
52.96.91.34 permit
|
52.96.91.34 permit
|
||||||
52.96.111.82 permit
|
52.96.111.82 permit
|
||||||
52.96.172.98 permit
|
52.96.172.98 permit
|
||||||
|
52.96.214.50 permit
|
||||||
52.96.222.194 permit
|
52.96.222.194 permit
|
||||||
52.96.222.226 permit
|
52.96.222.226 permit
|
||||||
52.96.223.2 permit
|
52.96.223.2 permit
|
||||||
@@ -337,6 +341,7 @@
|
|||||||
54.244.54.130 permit
|
54.244.54.130 permit
|
||||||
54.244.242.0/24 permit
|
54.244.242.0/24 permit
|
||||||
54.255.61.23 permit
|
54.255.61.23 permit
|
||||||
|
56.124.6.228 permit
|
||||||
57.103.64.0/18 permit
|
57.103.64.0/18 permit
|
||||||
57.129.93.249 permit
|
57.129.93.249 permit
|
||||||
62.13.128.0/24 permit
|
62.13.128.0/24 permit
|
||||||
@@ -397,15 +402,23 @@
|
|||||||
64.207.219.143 permit
|
64.207.219.143 permit
|
||||||
64.233.160.0/19 permit
|
64.233.160.0/19 permit
|
||||||
65.52.80.137 permit
|
65.52.80.137 permit
|
||||||
|
65.54.51.64/26 permit
|
||||||
|
65.54.61.64/26 permit
|
||||||
65.54.121.120/29 permit
|
65.54.121.120/29 permit
|
||||||
|
65.54.190.0/24 permit
|
||||||
|
65.54.241.0/24 permit
|
||||||
65.55.29.77 permit
|
65.55.29.77 permit
|
||||||
65.55.33.64/28 permit
|
65.55.33.64/28 permit
|
||||||
|
65.55.34.0/24 permit
|
||||||
65.55.42.224/28 permit
|
65.55.42.224/28 permit
|
||||||
65.55.52.224/27 permit
|
65.55.52.224/27 permit
|
||||||
65.55.78.128/25 permit
|
65.55.78.128/25 permit
|
||||||
65.55.81.48/28 permit
|
65.55.81.48/28 permit
|
||||||
|
65.55.90.0/24 permit
|
||||||
65.55.94.0/25 permit
|
65.55.94.0/25 permit
|
||||||
|
65.55.111.0/24 permit
|
||||||
65.55.113.64/26 permit
|
65.55.113.64/26 permit
|
||||||
|
65.55.116.0/25 permit
|
||||||
65.55.126.0/25 permit
|
65.55.126.0/25 permit
|
||||||
65.55.174.0/25 permit
|
65.55.174.0/25 permit
|
||||||
65.55.178.128/27 permit
|
65.55.178.128/27 permit
|
||||||
@@ -413,6 +426,7 @@
|
|||||||
65.110.161.77 permit
|
65.110.161.77 permit
|
||||||
65.123.29.213 permit
|
65.123.29.213 permit
|
||||||
65.123.29.220 permit
|
65.123.29.220 permit
|
||||||
|
65.154.166.0/24 permit
|
||||||
65.212.180.36 permit
|
65.212.180.36 permit
|
||||||
66.102.0.0/20 permit
|
66.102.0.0/20 permit
|
||||||
66.119.150.192/26 permit
|
66.119.150.192/26 permit
|
||||||
@@ -626,6 +640,7 @@
|
|||||||
74.208.4.220 permit
|
74.208.4.220 permit
|
||||||
74.208.4.221 permit
|
74.208.4.221 permit
|
||||||
74.209.250.0/24 permit
|
74.209.250.0/24 permit
|
||||||
|
75.2.70.75 permit
|
||||||
76.223.128.0/19 permit
|
76.223.128.0/19 permit
|
||||||
76.223.176.0/20 permit
|
76.223.176.0/20 permit
|
||||||
77.238.176.0/24 permit
|
77.238.176.0/24 permit
|
||||||
@@ -654,12 +669,18 @@
|
|||||||
81.169.146.245 permit
|
81.169.146.245 permit
|
||||||
81.169.146.246 permit
|
81.169.146.246 permit
|
||||||
81.223.46.0/27 permit
|
81.223.46.0/27 permit
|
||||||
|
82.165.159.2 permit
|
||||||
|
82.165.159.3 permit
|
||||||
|
82.165.159.4 permit
|
||||||
82.165.159.12 permit
|
82.165.159.12 permit
|
||||||
82.165.159.13 permit
|
82.165.159.13 permit
|
||||||
82.165.159.14 permit
|
82.165.159.14 permit
|
||||||
|
82.165.159.34 permit
|
||||||
|
82.165.159.35 permit
|
||||||
82.165.159.40 permit
|
82.165.159.40 permit
|
||||||
82.165.159.41 permit
|
82.165.159.41 permit
|
||||||
82.165.159.42 permit
|
82.165.159.42 permit
|
||||||
|
82.165.159.45 permit
|
||||||
82.165.159.130 permit
|
82.165.159.130 permit
|
||||||
82.165.159.131 permit
|
82.165.159.131 permit
|
||||||
85.9.206.169 permit
|
85.9.206.169 permit
|
||||||
@@ -1209,8 +1230,11 @@
|
|||||||
98.139.245.208/30 permit
|
98.139.245.208/30 permit
|
||||||
98.139.245.212/31 permit
|
98.139.245.212/31 permit
|
||||||
99.78.197.208/28 permit
|
99.78.197.208/28 permit
|
||||||
|
99.83.190.102 permit
|
||||||
103.9.96.0/22 permit
|
103.9.96.0/22 permit
|
||||||
103.28.42.0/24 permit
|
103.28.42.0/24 permit
|
||||||
|
103.84.217.238 permit
|
||||||
|
103.89.75.238 permit
|
||||||
103.151.192.0/23 permit
|
103.151.192.0/23 permit
|
||||||
103.168.172.128/27 permit
|
103.168.172.128/27 permit
|
||||||
103.237.104.0/22 permit
|
103.237.104.0/22 permit
|
||||||
@@ -1376,6 +1400,9 @@
|
|||||||
117.120.16.0/21 permit
|
117.120.16.0/21 permit
|
||||||
119.42.242.52/31 permit
|
119.42.242.52/31 permit
|
||||||
119.42.242.156 permit
|
119.42.242.156 permit
|
||||||
|
121.244.91.48 permit
|
||||||
|
121.244.91.52 permit
|
||||||
|
122.15.156.182 permit
|
||||||
123.126.78.64/29 permit
|
123.126.78.64/29 permit
|
||||||
124.108.96.24/31 permit
|
124.108.96.24/31 permit
|
||||||
124.108.96.28/31 permit
|
124.108.96.28/31 permit
|
||||||
@@ -1403,7 +1430,6 @@
|
|||||||
128.245.248.0/21 permit
|
128.245.248.0/21 permit
|
||||||
129.41.77.70 permit
|
129.41.77.70 permit
|
||||||
129.41.169.249 permit
|
129.41.169.249 permit
|
||||||
129.77.16.0/20 permit
|
|
||||||
129.80.5.164 permit
|
129.80.5.164 permit
|
||||||
129.80.64.36 permit
|
129.80.64.36 permit
|
||||||
129.80.67.121 permit
|
129.80.67.121 permit
|
||||||
@@ -1440,6 +1466,10 @@
|
|||||||
134.170.141.64/26 permit
|
134.170.141.64/26 permit
|
||||||
134.170.143.0/24 permit
|
134.170.143.0/24 permit
|
||||||
134.170.174.0/24 permit
|
134.170.174.0/24 permit
|
||||||
|
135.84.80.0/24 permit
|
||||||
|
135.84.81.0/24 permit
|
||||||
|
135.84.82.0/24 permit
|
||||||
|
135.84.83.0/24 permit
|
||||||
135.84.216.0/22 permit
|
135.84.216.0/22 permit
|
||||||
136.143.160.0/24 permit
|
136.143.160.0/24 permit
|
||||||
136.143.161.0/24 permit
|
136.143.161.0/24 permit
|
||||||
@@ -1451,7 +1481,6 @@
|
|||||||
136.143.184.0/24 permit
|
136.143.184.0/24 permit
|
||||||
136.143.188.0/24 permit
|
136.143.188.0/24 permit
|
||||||
136.143.190.0/23 permit
|
136.143.190.0/23 permit
|
||||||
136.146.128.0/20 permit
|
|
||||||
136.147.128.0/20 permit
|
136.147.128.0/20 permit
|
||||||
136.147.135.0/24 permit
|
136.147.135.0/24 permit
|
||||||
136.147.176.0/20 permit
|
136.147.176.0/20 permit
|
||||||
@@ -1466,6 +1495,7 @@
|
|||||||
139.138.46.219 permit
|
139.138.46.219 permit
|
||||||
139.138.57.55 permit
|
139.138.57.55 permit
|
||||||
139.138.58.119 permit
|
139.138.58.119 permit
|
||||||
|
139.167.79.86 permit
|
||||||
139.180.17.0/24 permit
|
139.180.17.0/24 permit
|
||||||
140.238.148.191 permit
|
140.238.148.191 permit
|
||||||
141.148.159.229 permit
|
141.148.159.229 permit
|
||||||
@@ -1522,6 +1552,9 @@
|
|||||||
155.248.220.138 permit
|
155.248.220.138 permit
|
||||||
155.248.234.149 permit
|
155.248.234.149 permit
|
||||||
155.248.237.141 permit
|
155.248.237.141 permit
|
||||||
|
157.55.0.192/26 permit
|
||||||
|
157.55.1.128/26 permit
|
||||||
|
157.55.2.0/25 permit
|
||||||
157.55.9.128/25 permit
|
157.55.9.128/25 permit
|
||||||
157.55.11.0/25 permit
|
157.55.11.0/25 permit
|
||||||
157.55.49.0/25 permit
|
157.55.49.0/25 permit
|
||||||
@@ -1585,6 +1618,9 @@
|
|||||||
164.152.23.32 permit
|
164.152.23.32 permit
|
||||||
164.152.25.241 permit
|
164.152.25.241 permit
|
||||||
164.177.132.168/30 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.0/22 permit
|
||||||
166.78.68.221 permit
|
166.78.68.221 permit
|
||||||
166.78.69.169 permit
|
166.78.69.169 permit
|
||||||
@@ -1614,16 +1650,29 @@
|
|||||||
168.245.12.252 permit
|
168.245.12.252 permit
|
||||||
168.245.46.9 permit
|
168.245.46.9 permit
|
||||||
168.245.127.231 permit
|
168.245.127.231 permit
|
||||||
|
169.148.129.0/24 permit
|
||||||
|
169.148.131.0/24 permit
|
||||||
|
169.148.138.0/24 permit
|
||||||
|
169.148.142.10 permit
|
||||||
|
169.148.142.33 permit
|
||||||
|
169.148.144.0/25 permit
|
||||||
|
169.148.144.10 permit
|
||||||
|
169.148.146.0/23 permit
|
||||||
|
169.148.175.3 permit
|
||||||
|
169.148.188.0/24 permit
|
||||||
|
169.148.188.182 permit
|
||||||
170.10.128.0/24 permit
|
170.10.128.0/24 permit
|
||||||
170.10.129.0/24 permit
|
170.10.129.0/24 permit
|
||||||
170.10.132.56/29 permit
|
170.10.132.56/29 permit
|
||||||
170.10.132.64/29 permit
|
170.10.132.64/29 permit
|
||||||
170.10.133.0/24 permit
|
170.10.133.0/24 permit
|
||||||
|
172.217.32.0/20 permit
|
||||||
|
172.253.56.0/21 permit
|
||||||
|
172.253.112.0/20 permit
|
||||||
173.0.84.0/29 permit
|
173.0.84.0/29 permit
|
||||||
173.0.84.224/27 permit
|
173.0.84.224/27 permit
|
||||||
173.0.94.244/30 permit
|
173.0.94.244/30 permit
|
||||||
173.194.0.0/16 permit
|
173.194.0.0/16 permit
|
||||||
173.194.0.0/17 permit
|
|
||||||
173.203.79.182 permit
|
173.203.79.182 permit
|
||||||
173.203.81.39 permit
|
173.203.81.39 permit
|
||||||
173.224.161.128/25 permit
|
173.224.161.128/25 permit
|
||||||
@@ -1763,7 +1812,6 @@
|
|||||||
194.97.212.12 permit
|
194.97.212.12 permit
|
||||||
194.106.220.0/23 permit
|
194.106.220.0/23 permit
|
||||||
194.113.24.0/22 permit
|
194.113.24.0/22 permit
|
||||||
194.113.42.0/26 permit
|
|
||||||
194.154.193.192/27 permit
|
194.154.193.192/27 permit
|
||||||
195.4.92.0/23 permit
|
195.4.92.0/23 permit
|
||||||
195.54.172.0/23 permit
|
195.54.172.0/23 permit
|
||||||
@@ -1777,7 +1825,6 @@
|
|||||||
198.61.254.21 permit
|
198.61.254.21 permit
|
||||||
198.61.254.231 permit
|
198.61.254.231 permit
|
||||||
198.178.234.57 permit
|
198.178.234.57 permit
|
||||||
198.202.211.1 permit
|
|
||||||
198.244.48.0/20 permit
|
198.244.48.0/20 permit
|
||||||
198.244.56.107 permit
|
198.244.56.107 permit
|
||||||
198.244.56.108 permit
|
198.244.56.108 permit
|
||||||
@@ -1799,7 +1846,16 @@
|
|||||||
199.16.156.0/22 permit
|
199.16.156.0/22 permit
|
||||||
199.33.145.1 permit
|
199.33.145.1 permit
|
||||||
199.33.145.32 permit
|
199.33.145.32 permit
|
||||||
|
199.34.22.36 permit
|
||||||
199.59.148.0/22 permit
|
199.59.148.0/22 permit
|
||||||
|
199.67.80.2 permit
|
||||||
|
199.67.80.20 permit
|
||||||
|
199.67.82.2 permit
|
||||||
|
199.67.82.20 permit
|
||||||
|
199.67.84.0/24 permit
|
||||||
|
199.67.86.0/24 permit
|
||||||
|
199.67.88.0/24 permit
|
||||||
|
199.67.90.0/24 permit
|
||||||
199.101.161.130 permit
|
199.101.161.130 permit
|
||||||
199.101.162.0/25 permit
|
199.101.162.0/25 permit
|
||||||
199.122.120.0/21 permit
|
199.122.120.0/21 permit
|
||||||
@@ -1856,6 +1912,8 @@
|
|||||||
204.92.114.187 permit
|
204.92.114.187 permit
|
||||||
204.92.114.203 permit
|
204.92.114.203 permit
|
||||||
204.92.114.204/31 permit
|
204.92.114.204/31 permit
|
||||||
|
204.141.32.0/23 permit
|
||||||
|
204.141.42.0/23 permit
|
||||||
204.216.164.202 permit
|
204.216.164.202 permit
|
||||||
204.220.160.0/21 permit
|
204.220.160.0/21 permit
|
||||||
204.220.168.0/21 permit
|
204.220.168.0/21 permit
|
||||||
@@ -1888,6 +1946,7 @@
|
|||||||
207.46.52.79 permit
|
207.46.52.79 permit
|
||||||
207.46.58.128/25 permit
|
207.46.58.128/25 permit
|
||||||
207.46.116.128/29 permit
|
207.46.116.128/29 permit
|
||||||
|
207.46.117.0/24 permit
|
||||||
207.46.132.128/27 permit
|
207.46.132.128/27 permit
|
||||||
207.46.198.0/25 permit
|
207.46.198.0/25 permit
|
||||||
207.46.200.0/27 permit
|
207.46.200.0/27 permit
|
||||||
@@ -1993,11 +2052,19 @@
|
|||||||
212.82.111.228/31 permit
|
212.82.111.228/31 permit
|
||||||
212.82.111.230 permit
|
212.82.111.230 permit
|
||||||
212.123.28.40 permit
|
212.123.28.40 permit
|
||||||
|
212.227.15.3 permit
|
||||||
|
212.227.15.4 permit
|
||||||
|
212.227.15.5 permit
|
||||||
|
212.227.15.6 permit
|
||||||
212.227.15.7 permit
|
212.227.15.7 permit
|
||||||
212.227.15.8 permit
|
212.227.15.8 permit
|
||||||
|
212.227.15.14 permit
|
||||||
212.227.15.15 permit
|
212.227.15.15 permit
|
||||||
212.227.15.18 permit
|
212.227.15.18 permit
|
||||||
212.227.15.19 permit
|
212.227.15.19 permit
|
||||||
|
212.227.15.25 permit
|
||||||
|
212.227.15.26 permit
|
||||||
|
212.227.15.29 permit
|
||||||
212.227.15.44 permit
|
212.227.15.44 permit
|
||||||
212.227.15.45 permit
|
212.227.15.45 permit
|
||||||
212.227.15.46 permit
|
212.227.15.46 permit
|
||||||
@@ -2005,11 +2072,17 @@
|
|||||||
212.227.15.50 permit
|
212.227.15.50 permit
|
||||||
212.227.15.52 permit
|
212.227.15.52 permit
|
||||||
212.227.15.53 permit
|
212.227.15.53 permit
|
||||||
|
212.227.15.54 permit
|
||||||
|
212.227.15.55 permit
|
||||||
212.227.17.1 permit
|
212.227.17.1 permit
|
||||||
212.227.17.2 permit
|
212.227.17.2 permit
|
||||||
212.227.17.7 permit
|
212.227.17.7 permit
|
||||||
|
212.227.17.11 permit
|
||||||
|
212.227.17.12 permit
|
||||||
212.227.17.16 permit
|
212.227.17.16 permit
|
||||||
212.227.17.17 permit
|
212.227.17.17 permit
|
||||||
|
212.227.17.18 permit
|
||||||
|
212.227.17.19 permit
|
||||||
212.227.17.20 permit
|
212.227.17.20 permit
|
||||||
212.227.17.21 permit
|
212.227.17.21 permit
|
||||||
212.227.17.22 permit
|
212.227.17.22 permit
|
||||||
@@ -2094,6 +2167,8 @@
|
|||||||
216.205.24.0/24 permit
|
216.205.24.0/24 permit
|
||||||
216.221.160.0/19 permit
|
216.221.160.0/19 permit
|
||||||
216.239.32.0/19 permit
|
216.239.32.0/19 permit
|
||||||
|
217.72.192.77 permit
|
||||||
|
217.72.192.78 permit
|
||||||
217.77.141.52 permit
|
217.77.141.52 permit
|
||||||
217.77.141.59 permit
|
217.77.141.59 permit
|
||||||
217.175.194.0/24 permit
|
217.175.194.0/24 permit
|
||||||
@@ -2126,6 +2201,9 @@
|
|||||||
2603:1030:20e:3::23c permit
|
2603:1030:20e:3::23c permit
|
||||||
2603:1030:b:3::152 permit
|
2603:1030:b:3::152 permit
|
||||||
2603:1030:c02:8::14 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
|
2607:f8b0:4000::/36 permit
|
||||||
2620:109:c003:104::/64 permit
|
2620:109:c003:104::/64 permit
|
||||||
2620:109:c003:104::215 permit
|
2620:109:c003:104::215 permit
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
#!/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;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init Redis
|
// Init Valkey
|
||||||
$redis = new Redis();
|
$valkey = new Redis();
|
||||||
$redis->connect('redis-mailcow', 6379);
|
$valkey->connect('valkey-mailcow', 6379);
|
||||||
$redis->auth(getenv("REDISPASS"));
|
$valkey->auth(getenv("VALKEYPASS"));
|
||||||
|
|
||||||
function parse_email($email) {
|
function parse_email($email) {
|
||||||
if(!filter_var($email, FILTER_VALIDATE_EMAIL)) return false;
|
if(!filter_var($email, FILTER_VALIDATE_EMAIL)) return false;
|
||||||
@@ -60,7 +60,7 @@ $rcpt_final_mailboxes = array();
|
|||||||
|
|
||||||
// Skip if not a mailcow handled domain
|
// Skip if not a mailcow handled domain
|
||||||
try {
|
try {
|
||||||
if (!$redis->hGet('DOMAIN_MAP', $parsed_rcpt['domain'])) {
|
if (!$valkey->hGet('DOMAIN_MAP', $parsed_rcpt['domain'])) {
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -122,7 +122,7 @@ try {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$parsed_goto = parse_email($goto);
|
$parsed_goto = parse_email($goto);
|
||||||
if (!$redis->hGet('DOMAIN_MAP', $parsed_goto['domain'])) {
|
if (!$valkey->hGet('DOMAIN_MAP', $parsed_goto['domain'])) {
|
||||||
error_log("ALIAS EXPANDER:" . $goto . " is not a mailcow handled mailbox or alias address" . PHP_EOL);
|
error_log("ALIAS EXPANDER:" . $goto . " is not a mailcow handled mailbox or alias address" . PHP_EOL);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
header('Content-Type: text/plain');
|
header('Content-Type: text/plain');
|
||||||
ini_set('error_reporting', 0);
|
ini_set('error_reporting', 0);
|
||||||
|
|
||||||
$redis = new Redis();
|
$valkey = new Redis();
|
||||||
$redis->connect('redis-mailcow', 6379);
|
$valkey->connect('valkey-mailcow', 6379);
|
||||||
$redis->auth(getenv("REDISPASS"));
|
$valkey->auth(getenv("VALKEYPASS"));
|
||||||
|
|
||||||
function in_net($addr, $net) {
|
function in_net($addr, $net) {
|
||||||
$net = explode('/', $net);
|
$net = explode('/', $net);
|
||||||
@@ -31,7 +31,7 @@ function in_net($addr, $net) {
|
|||||||
|
|
||||||
if (isset($_GET['host'])) {
|
if (isset($_GET['host'])) {
|
||||||
try {
|
try {
|
||||||
foreach ($redis->hGetAll('WHITELISTED_FWD_HOST') as $host => $source) {
|
foreach ($valkey->hGetAll('WHITELISTED_FWD_HOST') as $host => $source) {
|
||||||
if (in_net($_GET['host'], $host)) {
|
if (in_net($_GET['host'], $host)) {
|
||||||
echo '200 PERMIT';
|
echo '200 PERMIT';
|
||||||
exit;
|
exit;
|
||||||
@@ -46,7 +46,7 @@ if (isset($_GET['host'])) {
|
|||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
echo '240.240.240.240' . PHP_EOL;
|
echo '240.240.240.240' . PHP_EOL;
|
||||||
foreach ($redis->hGetAll('WHITELISTED_FWD_HOST') as $host => $source) {
|
foreach ($valkey->hGetAll('WHITELISTED_FWD_HOST') as $host => $source) {
|
||||||
echo $host . PHP_EOL;
|
echo $host . PHP_EOL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,10 +21,10 @@ catch (PDOException $e) {
|
|||||||
http_response_code(501);
|
http_response_code(501);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
// Init Redis
|
// Init Valkey
|
||||||
$redis = new Redis();
|
$valkey = new Redis();
|
||||||
$redis->connect('redis-mailcow', 6379);
|
$valkey->connect('valkey-mailcow', 6379);
|
||||||
$redis->auth(getenv("REDISPASS"));
|
$valkey->auth(getenv("VALKEYPASS"));
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
function parse_email($email) {
|
function parse_email($email) {
|
||||||
@@ -74,16 +74,16 @@ if ($fuzzy == 'unknown') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$max_size = (int)$redis->Get('Q_MAX_SIZE');
|
$max_size = (int)$valkey->Get('Q_MAX_SIZE');
|
||||||
if (($max_size * 1048576) < $raw_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);
|
error_log(sprintf("QUARANTINE: Message too large: %d b exceeds %d b", $raw_size, ($max_size * 1048576)) . PHP_EOL);
|
||||||
http_response_code(505);
|
http_response_code(505);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
if ($exclude_domains = $redis->Get('Q_EXCLUDE_DOMAINS')) {
|
if ($exclude_domains = $valkey->Get('Q_EXCLUDE_DOMAINS')) {
|
||||||
$exclude_domains = json_decode($exclude_domains, true);
|
$exclude_domains = json_decode($exclude_domains, true);
|
||||||
}
|
}
|
||||||
$retention_size = (int)$redis->Get('Q_RETENTION_SIZE');
|
$retention_size = (int)$valkey->Get('Q_RETENTION_SIZE');
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
error_log("QUARANTINE: " . $e . PHP_EOL);
|
error_log("QUARANTINE: " . $e . PHP_EOL);
|
||||||
@@ -103,7 +103,7 @@ foreach (json_decode($rcpts, true) as $rcpt) {
|
|||||||
|
|
||||||
// Skip if not a mailcow handled domain
|
// Skip if not a mailcow handled domain
|
||||||
try {
|
try {
|
||||||
if (!$redis->hGet('DOMAIN_MAP', $parsed_rcpt['domain'])) {
|
if (!$valkey->hGet('DOMAIN_MAP', $parsed_rcpt['domain'])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -171,7 +171,7 @@ foreach (json_decode($rcpts, true) as $rcpt) {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$parsed_goto = parse_email($goto);
|
$parsed_goto = parse_email($goto);
|
||||||
if (!$redis->hGet('DOMAIN_MAP', $parsed_goto['domain'])) {
|
if (!$valkey->hGet('DOMAIN_MAP', $parsed_goto['domain'])) {
|
||||||
error_log("RCPT RESOVLER:" . $goto . " is not a mailcow handled mailbox or alias address" . PHP_EOL);
|
error_log("RCPT RESOVLER:" . $goto . " is not a mailcow handled mailbox or alias address" . PHP_EOL);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -5,16 +5,16 @@ header('Content-Type: text/plain');
|
|||||||
require_once "vars.inc.php";
|
require_once "vars.inc.php";
|
||||||
// Do not show errors, we log to using error_log
|
// Do not show errors, we log to using error_log
|
||||||
ini_set('error_reporting', 0);
|
ini_set('error_reporting', 0);
|
||||||
// Init Redis
|
// Init Valkey
|
||||||
$redis = new Redis();
|
$valkey = new Redis();
|
||||||
try {
|
try {
|
||||||
if (!empty(getenv('REDIS_SLAVEOF_IP'))) {
|
if (!empty(getenv('VALKEY_SLAVEOF_IP'))) {
|
||||||
$redis->connect(getenv('REDIS_SLAVEOF_IP'), getenv('REDIS_SLAVEOF_PORT'));
|
$valkey->connect(getenv('VALKEY_SLAVEOF_IP'), getenv('VALKEY_SLAVEOF_PORT'));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$redis->connect('redis-mailcow', 6379);
|
$valkey->connect('valkey-mailcow', 6379);
|
||||||
}
|
}
|
||||||
$redis->auth(getenv("REDISPASS"));
|
$valkey->auth(getenv("VALKEYPASS"));
|
||||||
}
|
}
|
||||||
catch (Exception $e) {
|
catch (Exception $e) {
|
||||||
exit;
|
exit;
|
||||||
@@ -44,6 +44,6 @@ $data['message_id'] = $raw_data_decoded['message_id'];
|
|||||||
$data['header_subject'] = implode(' ', $raw_data_decoded['header_subject']);
|
$data['header_subject'] = implode(' ', $raw_data_decoded['header_subject']);
|
||||||
$data['header_from'] = implode(', ', $raw_data_decoded['header_from']);
|
$data['header_from'] = implode(', ', $raw_data_decoded['header_from']);
|
||||||
|
|
||||||
$redis->lpush('RL_LOG', json_encode($data));
|
$valkey->lpush('RL_LOG', json_encode($data));
|
||||||
exit;
|
exit;
|
||||||
|
|
||||||
|
|||||||
@@ -21,10 +21,10 @@ catch (PDOException $e) {
|
|||||||
http_response_code(501);
|
http_response_code(501);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
// Init Redis
|
// Init Valkey
|
||||||
$redis = new Redis();
|
$valkey = new Redis();
|
||||||
$redis->connect('redis-mailcow', 6379);
|
$valkey->connect('valkey-mailcow', 6379);
|
||||||
$redis->auth(getenv("REDISPASS"));
|
$valkey->auth(getenv("VALKEYPASS"));
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
function parse_email($email) {
|
function parse_email($email) {
|
||||||
@@ -94,7 +94,7 @@ foreach (json_decode($rcpts, true) as $rcpt) {
|
|||||||
|
|
||||||
// Skip if not a mailcow handled domain
|
// Skip if not a mailcow handled domain
|
||||||
try {
|
try {
|
||||||
if (!$redis->hGet('DOMAIN_MAP', $parsed_rcpt['domain'])) {
|
if (!$valkey->hGet('DOMAIN_MAP', $parsed_rcpt['domain'])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -156,7 +156,7 @@ foreach (json_decode($rcpts, true) as $rcpt) {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$parsed_goto = parse_email($goto);
|
$parsed_goto = parse_email($goto);
|
||||||
if (!$redis->hGet('DOMAIN_MAP', $parsed_goto['domain'])) {
|
if (!$valkey->hGet('DOMAIN_MAP', $parsed_goto['domain'])) {
|
||||||
error_log("RCPT RESOVLER:" . $goto . " is not a mailcow handled mailbox or alias address" . PHP_EOL);
|
error_log("RCPT RESOVLER:" . $goto . " is not a mailcow handled mailbox or alias address" . PHP_EOL);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -86,12 +86,6 @@
|
|||||||
SOGoMaximumFailedLoginInterval = 900;
|
SOGoMaximumFailedLoginInterval = 900;
|
||||||
SOGoFailedLoginBlockInterval = 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;
|
GCSChannelCollectionTimer = 60;
|
||||||
GCSChannelExpireAge = 60;
|
GCSChannelExpireAge = 60;
|
||||||
|
|
||||||
|
|||||||
12
data/conf/valkey/valkey-conf.sh
Executable file
12
data/conf/valkey/valkey-conf.sh
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
#!/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
|
<?php
|
||||||
$redis = new Redis();
|
$valkey = new Redis();
|
||||||
try {
|
try {
|
||||||
if (!empty(getenv('REDIS_SLAVEOF_IP'))) {
|
if (!empty(getenv('VALKEY_SLAVEOF_IP'))) {
|
||||||
$redis->connect(getenv('REDIS_SLAVEOF_IP'), getenv('REDIS_SLAVEOF_PORT'));
|
$valkey->connect(getenv('VALKEY_SLAVEOF_IP'), getenv('VALKEY_SLAVEOF_PORT'));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$redis->connect('redis-mailcow', 6379);
|
$valkey->connect('valkey-mailcow', 6379);
|
||||||
}
|
}
|
||||||
$redis->auth(getenv("REDISPASS"));
|
$valkey->auth(getenv("VALKEYPASS"));
|
||||||
}
|
}
|
||||||
catch (Exception $e) {
|
catch (Exception $e) {
|
||||||
exit;
|
exit;
|
||||||
@@ -15,4 +15,4 @@ catch (Exception $e) {
|
|||||||
header('Content-Type: application/json');
|
header('Content-Type: application/json');
|
||||||
echo '{"error":"Unauthorized"}';
|
echo '{"error":"Unauthorized"}';
|
||||||
error_log("Rspamd UI: Invalid password by " . $_SERVER['REMOTE_ADDR']);
|
error_log("Rspamd UI: Invalid password by " . $_SERVER['REMOTE_ADDR']);
|
||||||
$redis->publish("F2B_CHANNEL", "Rspamd UI: Invalid password by " . $_SERVER['REMOTE_ADDR']);
|
$valkey->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;
|
$olefy_status = (preg_match("/^([yY][eE][sS]|[yY])+$/", $_ENV["SKIP_OLEFY"])) ? false : true;
|
||||||
|
|
||||||
|
|
||||||
if (!isset($_SESSION['gal']) && $license_cache = $redis->Get('LICENSE_STATUS_CACHE')) {
|
if (!isset($_SESSION['gal']) && $license_cache = $valkey->Get('LICENSE_STATUS_CACHE')) {
|
||||||
$_SESSION['gal'] = json_decode($license_cache, true);
|
$_SESSION['gal'] = json_decode($license_cache, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5412,9 +5412,9 @@ paths:
|
|||||||
started_at: "2019-12-22T21:00:07.186717617Z"
|
started_at: "2019-12-22T21:00:07.186717617Z"
|
||||||
state: running
|
state: running
|
||||||
type: info
|
type: info
|
||||||
redis-mailcow:
|
valkey-mailcow:
|
||||||
container: redis-mailcow
|
container: valkey-mailcow
|
||||||
image: "redis:5-alpine"
|
image: "valkey:7.2.8-alpine"
|
||||||
started_at: "2019-12-22T20:59:56.827166834Z"
|
started_at: "2019-12-22T20:59:56.827166834Z"
|
||||||
state: running
|
state: running
|
||||||
type: info
|
type: info
|
||||||
|
|||||||
@@ -7,21 +7,19 @@ if(file_exists('inc/vars.local.inc.php')) {
|
|||||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.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/functions.auth.inc.php';
|
||||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/sessions.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;
|
$default_autodiscover_config = $autodiscover_config;
|
||||||
$autodiscover_config = array_merge($default_autodiscover_config, $autodiscover_config);
|
$autodiscover_config = array_merge($default_autodiscover_config, $autodiscover_config);
|
||||||
|
|
||||||
// Redis
|
// Valkey
|
||||||
$redis = new Redis();
|
$valkey = new Redis();
|
||||||
try {
|
try {
|
||||||
if (!empty(getenv('REDIS_SLAVEOF_IP'))) {
|
if (!empty(getenv('VALKEY_SLAVEOF_IP'))) {
|
||||||
$redis->connect(getenv('REDIS_SLAVEOF_IP'), getenv('REDIS_SLAVEOF_PORT'));
|
$valkey->connect(getenv('VALKEY_SLAVEOF_IP'), getenv('VALKEY_SLAVEOF_PORT'));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$redis->connect('redis-mailcow', 6379);
|
$valkey->connect('valkey-mailcow', 6379);
|
||||||
}
|
}
|
||||||
$redis->auth(getenv("REDISPASS"));
|
$valkey->auth(getenv("VALKEYPASS"));
|
||||||
}
|
}
|
||||||
catch (Exception $e) {
|
catch (Exception $e) {
|
||||||
exit;
|
exit;
|
||||||
@@ -73,7 +71,7 @@ if (empty($_SERVER['PHP_AUTH_USER']) || empty($_SERVER['PHP_AUTH_PW'])) {
|
|||||||
"service" => "Error: must be authenticated"
|
"service" => "Error: must be authenticated"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$redis->lPush('AUTODISCOVER_LOG', $json);
|
$valkey->lPush('AUTODISCOVER_LOG', $json);
|
||||||
header('WWW-Authenticate: Basic realm="' . $_SERVER['HTTP_HOST'] . '"');
|
header('WWW-Authenticate: Basic realm="' . $_SERVER['HTTP_HOST'] . '"');
|
||||||
header('HTTP/1.0 401 Unauthorized');
|
header('HTTP/1.0 401 Unauthorized');
|
||||||
exit(0);
|
exit(0);
|
||||||
@@ -98,13 +96,13 @@ if ($login_role === "user") {
|
|||||||
"service" => "Error: invalid or missing request data"
|
"service" => "Error: invalid or missing request data"
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$redis->lPush('AUTODISCOVER_LOG', $json);
|
$valkey->lPush('AUTODISCOVER_LOG', $json);
|
||||||
$redis->lTrim('AUTODISCOVER_LOG', 0, 100);
|
$valkey->lTrim('AUTODISCOVER_LOG', 0, 100);
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'msg' => 'Redis: '.$e
|
'msg' => 'Valkey: '.$e
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -153,13 +151,13 @@ if ($login_role === "user") {
|
|||||||
"service" => $autodiscover_config['autodiscoverType']
|
"service" => $autodiscover_config['autodiscoverType']
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$redis->lPush('AUTODISCOVER_LOG', $json);
|
$valkey->lPush('AUTODISCOVER_LOG', $json);
|
||||||
$redis->lTrim('AUTODISCOVER_LOG', 0, 100);
|
$valkey->lTrim('AUTODISCOVER_LOG', 0, 100);
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'msg' => 'Redis: '.$e
|
'msg' => 'Valkey: '.$e
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
function check_login($user, $pass, $app_passwd_data = false, $extra = null) {
|
function check_login($user, $pass, $app_passwd_data = false, $extra = null) {
|
||||||
global $pdo;
|
global $pdo;
|
||||||
global $redis;
|
global $valkey;
|
||||||
|
|
||||||
$is_internal = $extra['is_internal'];
|
$is_internal = $extra['is_internal'];
|
||||||
$role = $extra['role'];
|
$role = $extra['role'];
|
||||||
@@ -62,12 +62,12 @@ function check_login($user, $pass, $app_passwd_data = false, $extra = null) {
|
|||||||
|
|
||||||
if (!isset($_SESSION['ldelay'])) {
|
if (!isset($_SESSION['ldelay'])) {
|
||||||
$_SESSION['ldelay'] = "0";
|
$_SESSION['ldelay'] = "0";
|
||||||
$redis->publish("F2B_CHANNEL", "mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']);
|
$valkey->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']);
|
error_log("mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']);
|
||||||
}
|
}
|
||||||
elseif (!isset($_SESSION['mailcow_cc_username'])) {
|
elseif (!isset($_SESSION['mailcow_cc_username'])) {
|
||||||
$_SESSION['ldelay'] = $_SESSION['ldelay']+0.5;
|
$_SESSION['ldelay'] = $_SESSION['ldelay']+0.5;
|
||||||
$redis->publish("F2B_CHANNEL", "mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']);
|
$valkey->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']);
|
error_log("mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']);
|
||||||
}
|
}
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
function customize($_action, $_item, $_data = null) {
|
function customize($_action, $_item, $_data = null) {
|
||||||
global $redis;
|
global $valkey;
|
||||||
global $lang;
|
global $lang;
|
||||||
global $LOGO_LIMITS;
|
global $LOGO_LIMITS;
|
||||||
|
|
||||||
@@ -82,13 +82,13 @@ function customize($_action, $_item, $_data = null) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
$redis->Set(strtoupper($_item), 'data:' . $_data[$_item]['type'] . ';base64,' . base64_encode(file_get_contents($_data[$_item]['tmp_name'])));
|
$valkey->Set(strtoupper($_item), 'data:' . $_data[$_item]['type'] . ';base64,' . base64_encode(file_get_contents($_data[$_item]['tmp_name'])));
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -134,13 +134,13 @@ function customize($_action, $_item, $_data = null) {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
$redis->set('APP_LINKS', json_encode($out));
|
$valkey->set('APP_LINKS', json_encode($out));
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -162,20 +162,20 @@ function customize($_action, $_item, $_data = null) {
|
|||||||
$ui_announcement_active = (!empty($_data['ui_announcement_active']) ? 1 : 0);
|
$ui_announcement_active = (!empty($_data['ui_announcement_active']) ? 1 : 0);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$redis->set('TITLE_NAME', htmlspecialchars($title_name));
|
$valkey->set('TITLE_NAME', htmlspecialchars($title_name));
|
||||||
$redis->set('MAIN_NAME', htmlspecialchars($main_name));
|
$valkey->set('MAIN_NAME', htmlspecialchars($main_name));
|
||||||
$redis->set('APPS_NAME', htmlspecialchars($apps_name));
|
$valkey->set('APPS_NAME', htmlspecialchars($apps_name));
|
||||||
$redis->set('HELP_TEXT', $help_text);
|
$valkey->set('HELP_TEXT', $help_text);
|
||||||
$redis->set('UI_FOOTER', $ui_footer);
|
$valkey->set('UI_FOOTER', $ui_footer);
|
||||||
$redis->set('UI_ANNOUNCEMENT_TEXT', $ui_announcement_text);
|
$valkey->set('UI_ANNOUNCEMENT_TEXT', $ui_announcement_text);
|
||||||
$redis->set('UI_ANNOUNCEMENT_TYPE', $ui_announcement_type);
|
$valkey->set('UI_ANNOUNCEMENT_TYPE', $ui_announcement_type);
|
||||||
$redis->set('UI_ANNOUNCEMENT_ACTIVE', $ui_announcement_active);
|
$valkey->set('UI_ANNOUNCEMENT_ACTIVE', $ui_announcement_active);
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -188,13 +188,13 @@ function customize($_action, $_item, $_data = null) {
|
|||||||
case 'ip_check':
|
case 'ip_check':
|
||||||
$ip_check = ($_data['ip_check_opt_in'] == "1") ? 1 : 0;
|
$ip_check = ($_data['ip_check_opt_in'] == "1") ? 1 : 0;
|
||||||
try {
|
try {
|
||||||
$redis->set('IP_CHECK', $ip_check);
|
$valkey->set('IP_CHECK', $ip_check);
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -217,7 +217,7 @@ function customize($_action, $_item, $_data = null) {
|
|||||||
"force_sso" => $force_sso,
|
"force_sso" => $force_sso,
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
$redis->set('CUSTOM_LOGIN', json_encode($custom_login));
|
$valkey->set('CUSTOM_LOGIN', json_encode($custom_login));
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
@@ -257,7 +257,7 @@ function customize($_action, $_item, $_data = null) {
|
|||||||
case 'main_logo':
|
case 'main_logo':
|
||||||
case 'main_logo_dark':
|
case 'main_logo_dark':
|
||||||
try {
|
try {
|
||||||
if ($redis->del(strtoupper($_item))) {
|
if ($valkey->del(strtoupper($_item))) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'success',
|
'type' => 'success',
|
||||||
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
||||||
@@ -270,7 +270,7 @@ function customize($_action, $_item, $_data = null) {
|
|||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -281,13 +281,13 @@ function customize($_action, $_item, $_data = null) {
|
|||||||
switch ($_item) {
|
switch ($_item) {
|
||||||
case 'app_links':
|
case 'app_links':
|
||||||
try {
|
try {
|
||||||
$app_links = json_decode($redis->get('APP_LINKS'), true);
|
$app_links = json_decode($valkey->get('APP_LINKS'), true);
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -312,13 +312,13 @@ function customize($_action, $_item, $_data = null) {
|
|||||||
case 'main_logo':
|
case 'main_logo':
|
||||||
case 'main_logo_dark':
|
case 'main_logo_dark':
|
||||||
try {
|
try {
|
||||||
return $redis->get(strtoupper($_item));
|
return $valkey->get(strtoupper($_item));
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -327,25 +327,25 @@ function customize($_action, $_item, $_data = null) {
|
|||||||
try {
|
try {
|
||||||
$mailcow_hostname = strtolower(getenv("MAILCOW_HOSTNAME"));
|
$mailcow_hostname = strtolower(getenv("MAILCOW_HOSTNAME"));
|
||||||
|
|
||||||
$data['title_name'] = ($title_name = $redis->get('TITLE_NAME')) ? $title_name : "$mailcow_hostname - mail UI";
|
$data['title_name'] = ($title_name = $valkey->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['main_name'] = ($main_name = $valkey->get('MAIN_NAME')) ? $main_name : "$mailcow_hostname - mail UI";
|
||||||
$data['apps_name'] = ($apps_name = $redis->get('APPS_NAME')) ? $apps_name : $lang['header']['apps'];
|
$data['apps_name'] = ($apps_name = $valkey->get('APPS_NAME')) ? $apps_name : $lang['header']['apps'];
|
||||||
$data['help_text'] = ($help_text = $redis->get('HELP_TEXT')) ? $help_text : false;
|
$data['help_text'] = ($help_text = $valkey->get('HELP_TEXT')) ? $help_text : false;
|
||||||
if (!empty($redis->get('UI_IMPRESS'))) {
|
if (!empty($valkey->get('UI_IMPRESS'))) {
|
||||||
$redis->set('UI_FOOTER', $redis->get('UI_IMPRESS'));
|
$valkey->set('UI_FOOTER', $valkey->get('UI_IMPRESS'));
|
||||||
$redis->del('UI_IMPRESS');
|
$valkey->del('UI_IMPRESS');
|
||||||
}
|
}
|
||||||
$data['ui_footer'] = ($ui_footer = $redis->get('UI_FOOTER')) ? $ui_footer : false;
|
$data['ui_footer'] = ($ui_footer = $valkey->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_text'] = ($ui_announcement_text = $valkey->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_type'] = ($ui_announcement_type = $valkey->get('UI_ANNOUNCEMENT_TYPE')) ? $ui_announcement_type : false;
|
||||||
$data['ui_announcement_active'] = ($redis->get('UI_ANNOUNCEMENT_ACTIVE') == 1) ? 1 : 0;
|
$data['ui_announcement_active'] = ($valkey->get('UI_ANNOUNCEMENT_ACTIVE') == 1) ? 1 : 0;
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -376,21 +376,21 @@ function customize($_action, $_item, $_data = null) {
|
|||||||
break;
|
break;
|
||||||
case 'ip_check':
|
case 'ip_check':
|
||||||
try {
|
try {
|
||||||
$ip_check = ($ip_check = $redis->get('IP_CHECK')) ? $ip_check : 0;
|
$ip_check = ($ip_check = $valkey->get('IP_CHECK')) ? $ip_check : 0;
|
||||||
return $ip_check;
|
return $ip_check;
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
'log' => array(__FUNCTION__, $_action, $_item, $_data),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'custom_login':
|
case 'custom_login':
|
||||||
try {
|
try {
|
||||||
$custom_login = $redis->get('CUSTOM_LOGIN');
|
$custom_login = $valkey->get('CUSTOM_LOGIN');
|
||||||
return $custom_login ? json_decode($custom_login, true) : array();
|
return $custom_login ? json_decode($custom_login, true) : array();
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
function dkim($_action, $_data = null, $privkey = false) {
|
function dkim($_action, $_data = null, $privkey = false) {
|
||||||
global $redis;
|
global $valkey;
|
||||||
global $lang;
|
global $lang;
|
||||||
switch ($_action) {
|
switch ($_action) {
|
||||||
case 'add':
|
case 'add':
|
||||||
@@ -18,7 +18,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
|||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ($redis->hGet('DKIM_PUB_KEYS', $domain)) {
|
if ($valkey->hGet('DKIM_PUB_KEYS', $domain)) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data),
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
@@ -54,30 +54,30 @@ function dkim($_action, $_data = null, $privkey = false) {
|
|||||||
explode(PHP_EOL, $key_details['key'])
|
explode(PHP_EOL, $key_details['key'])
|
||||||
), 1, -1)
|
), 1, -1)
|
||||||
);
|
);
|
||||||
// Save public key and selector to redis
|
// Save public key and selector to valkey
|
||||||
try {
|
try {
|
||||||
$redis->hSet('DKIM_PUB_KEYS', $domain, $pubKey);
|
$valkey->hSet('DKIM_PUB_KEYS', $domain, $pubKey);
|
||||||
$redis->hSet('DKIM_SELECTORS', $domain, $dkim_selector);
|
$valkey->hSet('DKIM_SELECTORS', $domain, $dkim_selector);
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data),
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Export private key and save private key to redis
|
// Export private key and save private key to valkey
|
||||||
openssl_pkey_export($keypair_ressource, $privKey);
|
openssl_pkey_export($keypair_ressource, $privKey);
|
||||||
if (isset($privKey) && !empty($privKey)) {
|
if (isset($privKey) && !empty($privKey)) {
|
||||||
try {
|
try {
|
||||||
$redis->hSet('DKIM_PRIV_KEYS', $dkim_selector . '.' . $domain, trim($privKey));
|
$valkey->hSet('DKIM_PRIV_KEYS', $dkim_selector . '.' . $domain, trim($privKey));
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data),
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -121,15 +121,15 @@ function dkim($_action, $_data = null, $privkey = false) {
|
|||||||
$to_domains = array_filter($to_domains);
|
$to_domains = array_filter($to_domains);
|
||||||
foreach ($to_domains as $to_domain) {
|
foreach ($to_domains as $to_domain) {
|
||||||
try {
|
try {
|
||||||
$redis->hSet('DKIM_PUB_KEYS', $to_domain, $from_domain_dkim['pubkey']);
|
$valkey->hSet('DKIM_PUB_KEYS', $to_domain, $from_domain_dkim['pubkey']);
|
||||||
$redis->hSet('DKIM_SELECTORS', $to_domain, $from_domain_dkim['dkim_selector']);
|
$valkey->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'])));
|
$valkey->hSet('DKIM_PRIV_KEYS', $from_domain_dkim['dkim_selector'] . '.' . $to_domain, base64_decode(trim($from_domain_dkim['privkey'])));
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data),
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -178,7 +178,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
|||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ($redis->hGet('DKIM_PUB_KEYS', $domain)) {
|
if ($valkey->hGet('DKIM_PUB_KEYS', $domain)) {
|
||||||
if ($overwrite_existing == 0) {
|
if ($overwrite_existing == 0) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
@@ -198,15 +198,15 @@ function dkim($_action, $_data = null, $privkey = false) {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
dkim('delete', array('domains' => $domain));
|
dkim('delete', array('domains' => $domain));
|
||||||
$redis->hSet('DKIM_PUB_KEYS', $domain, $pem_public_key);
|
$valkey->hSet('DKIM_PUB_KEYS', $domain, $pem_public_key);
|
||||||
$redis->hSet('DKIM_SELECTORS', $domain, $dkim_selector);
|
$valkey->hSet('DKIM_SELECTORS', $domain, $dkim_selector);
|
||||||
$redis->hSet('DKIM_PRIV_KEYS', $dkim_selector . '.' . $domain, $private_key_normalized);
|
$valkey->hSet('DKIM_PRIV_KEYS', $dkim_selector . '.' . $domain, $private_key_normalized);
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data),
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -219,7 +219,7 @@ function dkim($_action, $_data = null, $privkey = false) {
|
|||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data),
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -235,8 +235,8 @@ function dkim($_action, $_data = null, $privkey = false) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$dkimdata = array();
|
$dkimdata = array();
|
||||||
if ($redis_dkim_key_data = $redis->hGet('DKIM_PUB_KEYS', $_data)) {
|
if ($valkey_dkim_key_data = $valkey->hGet('DKIM_PUB_KEYS', $_data)) {
|
||||||
$dkimdata['pubkey'] = $redis_dkim_key_data;
|
$dkimdata['pubkey'] = $valkey_dkim_key_data;
|
||||||
if (strlen($dkimdata['pubkey']) < 391) {
|
if (strlen($dkimdata['pubkey']) < 391) {
|
||||||
$dkimdata['length'] = "1024";
|
$dkimdata['length'] = "1024";
|
||||||
}
|
}
|
||||||
@@ -253,15 +253,15 @@ function dkim($_action, $_data = null, $privkey = false) {
|
|||||||
$dkimdata['length'] = ">= 8192";
|
$dkimdata['length'] = ">= 8192";
|
||||||
}
|
}
|
||||||
if ($GLOBALS['SPLIT_DKIM_255'] === true) {
|
if ($GLOBALS['SPLIT_DKIM_255'] === true) {
|
||||||
$dkim_txt_tmp = str_split('v=DKIM1;k=rsa;t=s;s=email;p=' . $redis_dkim_key_data, 255);
|
$dkim_txt_tmp = str_split('v=DKIM1;k=rsa;t=s;s=email;p=' . $valkey_dkim_key_data, 255);
|
||||||
$dkimdata['dkim_txt'] = sprintf('"%s"', implode('" "', (array)$dkim_txt_tmp ) );
|
$dkimdata['dkim_txt'] = sprintf('"%s"', implode('" "', (array)$dkim_txt_tmp ) );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$dkimdata['dkim_txt'] = 'v=DKIM1;k=rsa;t=s;s=email;p=' . $redis_dkim_key_data;
|
$dkimdata['dkim_txt'] = 'v=DKIM1;k=rsa;t=s;s=email;p=' . $valkey_dkim_key_data;
|
||||||
}
|
}
|
||||||
$dkimdata['dkim_selector'] = $redis->hGet('DKIM_SELECTORS', $_data);
|
$dkimdata['dkim_selector'] = $valkey->hGet('DKIM_SELECTORS', $_data);
|
||||||
if ($GLOBALS['SHOW_DKIM_PRIV_KEYS'] || $privkey == true) {
|
if ($GLOBALS['SHOW_DKIM_PRIV_KEYS'] || $privkey == true) {
|
||||||
$dkimdata['privkey'] = base64_encode($redis->hGet('DKIM_PRIV_KEYS', $dkimdata['dkim_selector'] . '.' . $_data));
|
$dkimdata['privkey'] = base64_encode($valkey->hGet('DKIM_PRIV_KEYS', $dkimdata['dkim_selector'] . '.' . $_data));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$dkimdata['privkey'] = '';
|
$dkimdata['privkey'] = '';
|
||||||
@@ -279,8 +279,8 @@ function dkim($_action, $_data = null, $privkey = false) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$blinddkim = array();
|
$blinddkim = array();
|
||||||
foreach ($redis->hKeys('DKIM_PUB_KEYS') as $redis_dkim_domain) {
|
foreach ($valkey->hKeys('DKIM_PUB_KEYS') as $valkey_dkim_domain) {
|
||||||
$blinddkim[] = $redis_dkim_domain;
|
$blinddkim[] = $valkey_dkim_domain;
|
||||||
}
|
}
|
||||||
return array_diff($blinddkim, array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains')));
|
return array_diff($blinddkim, array_merge(mailbox('get', 'domains'), mailbox('get', 'alias_domains')));
|
||||||
break;
|
break;
|
||||||
@@ -304,16 +304,16 @@ function dkim($_action, $_data = null, $privkey = false) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
$selector = $redis->hGet('DKIM_SELECTORS', $domain);
|
$selector = $valkey->hGet('DKIM_SELECTORS', $domain);
|
||||||
$redis->hDel('DKIM_PUB_KEYS', $domain);
|
$valkey->hDel('DKIM_PUB_KEYS', $domain);
|
||||||
$redis->hDel('DKIM_PRIV_KEYS', $selector . '.' . $domain);
|
$valkey->hDel('DKIM_PRIV_KEYS', $selector . '.' . $domain);
|
||||||
$redis->hDel('DKIM_SELECTORS', $domain);
|
$valkey->hDel('DKIM_SELECTORS', $domain);
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data),
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $extra_headers = null) {
|
function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $extra_headers = null) {
|
||||||
global $DOCKER_TIMEOUT;
|
global $DOCKER_TIMEOUT;
|
||||||
global $redis;
|
global $valkey;
|
||||||
$curl = curl_init();
|
$curl = curl_init();
|
||||||
curl_setopt($curl, CURLOPT_HTTPHEADER,array('Content-Type: application/json' ));
|
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
|
// We are using our mail certificates for dockerapi, the names will not match, the certs are trusted anyway
|
||||||
@@ -200,7 +200,7 @@ function docker($action, $service_name = null, $attr1 = null, $attr2 = null, $ex
|
|||||||
"request" => $attr2
|
"request" => $attr2
|
||||||
);
|
);
|
||||||
|
|
||||||
$redis->publish("MC_CHANNEL", json_encode($request));
|
$valkey->publish("MC_CHANNEL", json_encode($request));
|
||||||
return true;
|
return true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
function fail2ban($_action, $_data = null, $_extra = null) {
|
function fail2ban($_action, $_data = null, $_extra = null) {
|
||||||
global $redis;
|
global $valkey;
|
||||||
$_data_log = $_data;
|
$_data_log = $_data;
|
||||||
switch ($_action) {
|
switch ($_action) {
|
||||||
case 'get':
|
case 'get':
|
||||||
@@ -9,9 +9,9 @@ function fail2ban($_action, $_data = null, $_extra = null) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
$f2b_options = json_decode($redis->Get('F2B_OPTIONS'), true);
|
$f2b_options = json_decode($valkey->Get('F2B_OPTIONS'), true);
|
||||||
$f2b_options['regex'] = json_decode($redis->Get('F2B_REGEX'), true);
|
$f2b_options['regex'] = json_decode($valkey->Get('F2B_REGEX'), true);
|
||||||
$wl = $redis->hGetAll('F2B_WHITELIST');
|
$wl = $valkey->hGetAll('F2B_WHITELIST');
|
||||||
if (is_array($wl)) {
|
if (is_array($wl)) {
|
||||||
foreach ($wl as $key => $value) {
|
foreach ($wl as $key => $value) {
|
||||||
$tmp_wl_data[] = $key;
|
$tmp_wl_data[] = $key;
|
||||||
@@ -27,7 +27,7 @@ function fail2ban($_action, $_data = null, $_extra = null) {
|
|||||||
else {
|
else {
|
||||||
$f2b_options['whitelist'] = "";
|
$f2b_options['whitelist'] = "";
|
||||||
}
|
}
|
||||||
$bl = $redis->hGetAll('F2B_BLACKLIST');
|
$bl = $valkey->hGetAll('F2B_BLACKLIST');
|
||||||
if (is_array($bl)) {
|
if (is_array($bl)) {
|
||||||
foreach ($bl as $key => $value) {
|
foreach ($bl as $key => $value) {
|
||||||
$tmp_bl_data[] = $key;
|
$tmp_bl_data[] = $key;
|
||||||
@@ -43,7 +43,7 @@ function fail2ban($_action, $_data = null, $_extra = null) {
|
|||||||
else {
|
else {
|
||||||
$f2b_options['blacklist'] = "";
|
$f2b_options['blacklist'] = "";
|
||||||
}
|
}
|
||||||
$pb = $redis->hGetAll('F2B_PERM_BANS');
|
$pb = $valkey->hGetAll('F2B_PERM_BANS');
|
||||||
if (is_array($pb)) {
|
if (is_array($pb)) {
|
||||||
foreach ($pb as $key => $value) {
|
foreach ($pb as $key => $value) {
|
||||||
$f2b_options['perm_bans'][] = array(
|
$f2b_options['perm_bans'][] = array(
|
||||||
@@ -56,8 +56,8 @@ function fail2ban($_action, $_data = null, $_extra = null) {
|
|||||||
else {
|
else {
|
||||||
$f2b_options['perm_bans'] = "";
|
$f2b_options['perm_bans'] = "";
|
||||||
}
|
}
|
||||||
$active_bans = $redis->hGetAll('F2B_ACTIVE_BANS');
|
$active_bans = $valkey->hGetAll('F2B_ACTIVE_BANS');
|
||||||
$queue_unban = $redis->hGetAll('F2B_QUEUE_UNBAN');
|
$queue_unban = $valkey->hGetAll('F2B_QUEUE_UNBAN');
|
||||||
if (is_array($active_bans)) {
|
if (is_array($active_bans)) {
|
||||||
foreach ($active_bans as $network => $banned_until) {
|
foreach ($active_bans as $network => $banned_until) {
|
||||||
$queued_for_unban = (isset($queue_unban[$network]) && $queue_unban[$network] == 1) ? 1 : 0;
|
$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(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -98,22 +98,22 @@ function fail2ban($_action, $_data = null, $_extra = null) {
|
|||||||
// Reset regex filters
|
// Reset regex filters
|
||||||
if ($_data['action'] == "reset-regex") {
|
if ($_data['action'] == "reset-regex") {
|
||||||
try {
|
try {
|
||||||
$redis->Del('F2B_REGEX');
|
$valkey->Del('F2B_REGEX');
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Rules will also be recreated on log events, but rules may seem empty for a second in the UI
|
// Rules will also be recreated on log events, but rules may seem empty for a second in the UI
|
||||||
docker('post', 'netfilter-mailcow', 'restart');
|
docker('post', 'netfilter-mailcow', 'restart');
|
||||||
$fail_count = 0;
|
$fail_count = 0;
|
||||||
$regex_result = json_decode($redis->Get('F2B_REGEX'), true);
|
$regex_result = json_decode($valkey->Get('F2B_REGEX'), true);
|
||||||
while (empty($regex_result) && $fail_count < 10) {
|
while (empty($regex_result) && $fail_count < 10) {
|
||||||
$regex_result = json_decode($redis->Get('F2B_REGEX'), true);
|
$regex_result = json_decode($valkey->Get('F2B_REGEX'), true);
|
||||||
$fail_count++;
|
$fail_count++;
|
||||||
sleep(1);
|
sleep(1);
|
||||||
}
|
}
|
||||||
@@ -135,7 +135,7 @@ function fail2ban($_action, $_data = null, $_extra = null) {
|
|||||||
$rule_id++;
|
$rule_id++;
|
||||||
}
|
}
|
||||||
if (!empty($regex_array)) {
|
if (!empty($regex_array)) {
|
||||||
$redis->Set('F2B_REGEX', json_encode($regex_array, JSON_UNESCAPED_SLASHES));
|
$valkey->Set('F2B_REGEX', json_encode($regex_array, JSON_UNESCAPED_SLASHES));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
@@ -154,13 +154,13 @@ function fail2ban($_action, $_data = null, $_extra = null) {
|
|||||||
if ($_data['action'] == "unban") {
|
if ($_data['action'] == "unban") {
|
||||||
if (valid_network($network)) {
|
if (valid_network($network)) {
|
||||||
try {
|
try {
|
||||||
$redis->hSet('F2B_QUEUE_UNBAN', $network, 1);
|
$valkey->hSet('F2B_QUEUE_UNBAN', $network, 1);
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -171,15 +171,15 @@ function fail2ban($_action, $_data = null, $_extra = null) {
|
|||||||
if (empty($network)) { continue; }
|
if (empty($network)) { continue; }
|
||||||
if (valid_network($network)) {
|
if (valid_network($network)) {
|
||||||
try {
|
try {
|
||||||
$redis->hSet('F2B_WHITELIST', $network, 1);
|
$valkey->hSet('F2B_WHITELIST', $network, 1);
|
||||||
$redis->hDel('F2B_BLACKLIST', $network, 1);
|
$valkey->hDel('F2B_BLACKLIST', $network, 1);
|
||||||
$redis->hSet('F2B_QUEUE_UNBAN', $network, 1);
|
$valkey->hSet('F2B_QUEUE_UNBAN', $network, 1);
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -204,15 +204,15 @@ function fail2ban($_action, $_data = null, $_extra = null) {
|
|||||||
getenv('IPV6_NETWORK')
|
getenv('IPV6_NETWORK')
|
||||||
))) {
|
))) {
|
||||||
try {
|
try {
|
||||||
$redis->hSet('F2B_BLACKLIST', $network, 1);
|
$valkey->hSet('F2B_BLACKLIST', $network, 1);
|
||||||
$redis->hDel('F2B_WHITELIST', $network, 1);
|
$valkey->hDel('F2B_WHITELIST', $network, 1);
|
||||||
//$response = docker('post', 'netfilter-mailcow', 'restart');
|
//$response = docker('post', 'netfilter-mailcow', 'restart');
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -270,16 +270,16 @@ function fail2ban($_action, $_data = null, $_extra = null) {
|
|||||||
$f2b_options['banlist_id'] = $is_now['banlist_id'];
|
$f2b_options['banlist_id'] = $is_now['banlist_id'];
|
||||||
$f2b_options['manage_external'] = ($manage_external > 0) ? 1 : 0;
|
$f2b_options['manage_external'] = ($manage_external > 0) ? 1 : 0;
|
||||||
try {
|
try {
|
||||||
$redis->Set('F2B_OPTIONS', json_encode($f2b_options));
|
$valkey->Set('F2B_OPTIONS', json_encode($f2b_options));
|
||||||
$redis->Del('F2B_WHITELIST');
|
$valkey->Del('F2B_WHITELIST');
|
||||||
$redis->Del('F2B_BLACKLIST');
|
$valkey->Del('F2B_BLACKLIST');
|
||||||
if(!empty($wl)) {
|
if(!empty($wl)) {
|
||||||
$wl_array = array_map('trim', preg_split( "/( |,|;|\n)/", $wl));
|
$wl_array = array_map('trim', preg_split( "/( |,|;|\n)/", $wl));
|
||||||
$wl_array = array_filter($wl_array);
|
$wl_array = array_filter($wl_array);
|
||||||
if (is_array($wl_array)) {
|
if (is_array($wl_array)) {
|
||||||
foreach ($wl_array as $wl_item) {
|
foreach ($wl_array as $wl_item) {
|
||||||
if (valid_network($wl_item) || valid_hostname($wl_item)) {
|
if (valid_network($wl_item) || valid_hostname($wl_item)) {
|
||||||
$redis->hSet('F2B_WHITELIST', $wl_item, 1);
|
$valkey->hSet('F2B_WHITELIST', $wl_item, 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
@@ -304,7 +304,7 @@ function fail2ban($_action, $_data = null, $_extra = null) {
|
|||||||
getenv('IPV4_NETWORK') . '0',
|
getenv('IPV4_NETWORK') . '0',
|
||||||
getenv('IPV6_NETWORK')
|
getenv('IPV6_NETWORK')
|
||||||
))) {
|
))) {
|
||||||
$redis->hSet('F2B_BLACKLIST', $bl_item, 1);
|
$valkey->hSet('F2B_BLACKLIST', $bl_item, 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
@@ -322,7 +322,7 @@ function fail2ban($_action, $_data = null, $_extra = null) {
|
|||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -334,13 +334,13 @@ function fail2ban($_action, $_data = null, $_extra = null) {
|
|||||||
break;
|
break;
|
||||||
case 'banlist':
|
case 'banlist':
|
||||||
try {
|
try {
|
||||||
$f2b_options = json_decode($redis->Get('F2B_OPTIONS'), true);
|
$f2b_options = json_decode($valkey->Get('F2B_OPTIONS'), true);
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log, $_extra),
|
'log' => array(__FUNCTION__, $_action, $_data_log, $_extra),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
http_response_code(500);
|
http_response_code(500);
|
||||||
return false;
|
return false;
|
||||||
@@ -356,14 +356,14 @@ function fail2ban($_action, $_data = null, $_extra = null) {
|
|||||||
switch ($_data) {
|
switch ($_data) {
|
||||||
case 'get':
|
case 'get':
|
||||||
try {
|
try {
|
||||||
$bl = $redis->hKeys('F2B_BLACKLIST');
|
$bl = $valkey->hKeys('F2B_BLACKLIST');
|
||||||
$active_bans = $redis->hKeys('F2B_ACTIVE_BANS');
|
$active_bans = $valkey->hKeys('F2B_ACTIVE_BANS');
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log, $_extra),
|
'log' => array(__FUNCTION__, $_action, $_data_log, $_extra),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
http_response_code(500);
|
http_response_code(500);
|
||||||
return false;
|
return false;
|
||||||
@@ -378,13 +378,13 @@ function fail2ban($_action, $_data = null, $_extra = null) {
|
|||||||
|
|
||||||
$f2b_options['banlist_id'] = uuid4();
|
$f2b_options['banlist_id'] = uuid4();
|
||||||
try {
|
try {
|
||||||
$redis->Set('F2B_OPTIONS', json_encode($f2b_options));
|
$valkey->Set('F2B_OPTIONS', json_encode($f2b_options));
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log, $_extra),
|
'log' => array(__FUNCTION__, $_action, $_data_log, $_extra),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
function fwdhost($_action, $_data = null) {
|
function fwdhost($_action, $_data = null) {
|
||||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/spf.inc.php';
|
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/spf.inc.php';
|
||||||
global $redis;
|
global $valkey;
|
||||||
global $lang;
|
global $lang;
|
||||||
$_data_log = $_data;
|
$_data_log = $_data;
|
||||||
switch ($_action) {
|
switch ($_action) {
|
||||||
@@ -37,19 +37,19 @@ function fwdhost($_action, $_data = null) {
|
|||||||
}
|
}
|
||||||
foreach ($hosts as $host) {
|
foreach ($hosts as $host) {
|
||||||
try {
|
try {
|
||||||
$redis->hSet('WHITELISTED_FWD_HOST', $host, $source);
|
$valkey->hSet('WHITELISTED_FWD_HOST', $host, $source);
|
||||||
if ($filter_spam == 0) {
|
if ($filter_spam == 0) {
|
||||||
$redis->hSet('KEEP_SPAM', $host, 1);
|
$valkey->hSet('KEEP_SPAM', $host, 1);
|
||||||
}
|
}
|
||||||
elseif ($redis->hGet('KEEP_SPAM', $host)) {
|
elseif ($valkey->hGet('KEEP_SPAM', $host)) {
|
||||||
$redis->hDel('KEEP_SPAM', $host);
|
$valkey->hDel('KEEP_SPAM', $host);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -86,17 +86,17 @@ function fwdhost($_action, $_data = null) {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if ($keep_spam == 1) {
|
if ($keep_spam == 1) {
|
||||||
$redis->hSet('KEEP_SPAM', $fwdhost, 1);
|
$valkey->hSet('KEEP_SPAM', $fwdhost, 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$redis->hDel('KEEP_SPAM', $fwdhost);
|
$valkey->hDel('KEEP_SPAM', $fwdhost);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -111,14 +111,14 @@ function fwdhost($_action, $_data = null) {
|
|||||||
$hosts = (array)$_data['forwardinghost'];
|
$hosts = (array)$_data['forwardinghost'];
|
||||||
foreach ($hosts as $host) {
|
foreach ($hosts as $host) {
|
||||||
try {
|
try {
|
||||||
$redis->hDel('WHITELISTED_FWD_HOST', $host);
|
$valkey->hDel('WHITELISTED_FWD_HOST', $host);
|
||||||
$redis->hDel('KEEP_SPAM', $host);
|
$valkey->hDel('KEEP_SPAM', $host);
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -135,10 +135,10 @@ function fwdhost($_action, $_data = null) {
|
|||||||
}
|
}
|
||||||
$fwdhostsdata = array();
|
$fwdhostsdata = array();
|
||||||
try {
|
try {
|
||||||
$fwd_hosts = $redis->hGetAll('WHITELISTED_FWD_HOST');
|
$fwd_hosts = $valkey->hGetAll('WHITELISTED_FWD_HOST');
|
||||||
if (!empty($fwd_hosts)) {
|
if (!empty($fwd_hosts)) {
|
||||||
foreach ($fwd_hosts as $fwd_host => $source) {
|
foreach ($fwd_hosts as $fwd_host => $source) {
|
||||||
$keep_spam = ($redis->hGet('KEEP_SPAM', $fwd_host)) ? "yes" : "no";
|
$keep_spam = ($valkey->hGet('KEEP_SPAM', $fwd_host)) ? "yes" : "no";
|
||||||
$fwdhostsdata[] = array(
|
$fwdhostsdata[] = array(
|
||||||
'host' => $fwd_host,
|
'host' => $fwd_host,
|
||||||
'source' => $source,
|
'source' => $source,
|
||||||
@@ -151,7 +151,7 @@ function fwdhost($_action, $_data = null) {
|
|||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -163,17 +163,17 @@ function fwdhost($_action, $_data = null) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if ($source = $redis->hGet('WHITELISTED_FWD_HOST', $_data)) {
|
if ($source = $valkey->hGet('WHITELISTED_FWD_HOST', $_data)) {
|
||||||
$fwdhostdetails['host'] = $_data;
|
$fwdhostdetails['host'] = $_data;
|
||||||
$fwdhostdetails['source'] = $source;
|
$fwdhostdetails['source'] = $source;
|
||||||
$fwdhostdetails['keep_spam'] = ($redis->hGet('KEEP_SPAM', $_data)) ? "yes" : "no";
|
$fwdhostdetails['keep_spam'] = ($valkey->hGet('KEEP_SPAM', $_data)) ? "yes" : "no";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ function hash_password($password) {
|
|||||||
return $pw_hash;
|
return $pw_hash;
|
||||||
}
|
}
|
||||||
function password_complexity($_action, $_data = null) {
|
function password_complexity($_action, $_data = null) {
|
||||||
global $redis;
|
global $valkey;
|
||||||
global $lang;
|
global $lang;
|
||||||
switch ($_action) {
|
switch ($_action) {
|
||||||
case 'edit':
|
case 'edit':
|
||||||
@@ -147,7 +147,7 @@ function password_complexity($_action, $_data = null) {
|
|||||||
$numbers = (isset($_data['numbers'])) ? intval($_data['numbers']) : $is_now['numbers'];
|
$numbers = (isset($_data['numbers'])) ? intval($_data['numbers']) : $is_now['numbers'];
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
$redis->hMSet('PASSWD_POLICY', [
|
$valkey->hMSet('PASSWD_POLICY', [
|
||||||
'length' => $length,
|
'length' => $length,
|
||||||
'chars' => $chars,
|
'chars' => $chars,
|
||||||
'special_chars' => $special_chars,
|
'special_chars' => $special_chars,
|
||||||
@@ -159,7 +159,7 @@ function password_complexity($_action, $_data = null) {
|
|||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data),
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -171,11 +171,11 @@ function password_complexity($_action, $_data = null) {
|
|||||||
break;
|
break;
|
||||||
case 'get':
|
case 'get':
|
||||||
try {
|
try {
|
||||||
$length = $redis->hGet('PASSWD_POLICY', 'length');
|
$length = $valkey->hGet('PASSWD_POLICY', 'length');
|
||||||
$chars = $redis->hGet('PASSWD_POLICY', 'chars');
|
$chars = $valkey->hGet('PASSWD_POLICY', 'chars');
|
||||||
$special_chars = $redis->hGet('PASSWD_POLICY', 'special_chars');
|
$special_chars = $valkey->hGet('PASSWD_POLICY', 'special_chars');
|
||||||
$lowerupper = $redis->hGet('PASSWD_POLICY', 'lowerupper');
|
$lowerupper = $valkey->hGet('PASSWD_POLICY', 'lowerupper');
|
||||||
$numbers = $redis->hGet('PASSWD_POLICY', 'numbers');
|
$numbers = $valkey->hGet('PASSWD_POLICY', 'numbers');
|
||||||
return array(
|
return array(
|
||||||
'length' => $length,
|
'length' => $length,
|
||||||
'chars' => $chars,
|
'chars' => $chars,
|
||||||
@@ -188,7 +188,7 @@ function password_complexity($_action, $_data = null) {
|
|||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data),
|
'log' => array(__FUNCTION__, $_action, $_data),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -253,7 +253,7 @@ function password_check($password1, $password2) {
|
|||||||
}
|
}
|
||||||
function last_login($action, $username, $sasl_limit_days = 7, $ui_offset = 1) {
|
function last_login($action, $username, $sasl_limit_days = 7, $ui_offset = 1) {
|
||||||
global $pdo;
|
global $pdo;
|
||||||
global $redis;
|
global $valkey;
|
||||||
$sasl_limit_days = intval($sasl_limit_days);
|
$sasl_limit_days = intval($sasl_limit_days);
|
||||||
switch ($action) {
|
switch ($action) {
|
||||||
case 'get':
|
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)) {
|
elseif (filter_var($sasl[$k]['real_rip'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
|
||||||
try {
|
try {
|
||||||
$sasl[$k]['location'] = $redis->hGet('IP_SHORTCOUNTRY', $sasl[$k]['real_rip']);
|
$sasl[$k]['location'] = $valkey->hGet('IP_SHORTCOUNTRY', $sasl[$k]['real_rip']);
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
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'])) {
|
if ($ip_data_array !== false and !empty($ip_data_array['shortcountry'])) {
|
||||||
$sasl[$k]['location'] = $ip_data_array['shortcountry'];
|
$sasl[$k]['location'] = $ip_data_array['shortcountry'];
|
||||||
try {
|
try {
|
||||||
$redis->hSet('IP_SHORTCOUNTRY', $sasl[$k]['real_rip'], $ip_data_array['shortcountry']);
|
$valkey->hSet('IP_SHORTCOUNTRY', $sasl[$k]['real_rip'], $ip_data_array['shortcountry']);
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
curl_close($curl);
|
curl_close($curl);
|
||||||
return false;
|
return false;
|
||||||
@@ -1006,7 +1006,7 @@ function edit_user_account($_data) {
|
|||||||
update_sogo_static_view();
|
update_sogo_static_view();
|
||||||
}
|
}
|
||||||
// edit password recovery email
|
// edit password recovery email
|
||||||
elseif (!empty($password_old) && isset($pw_recovery_email)) {
|
elseif (isset($pw_recovery_email)) {
|
||||||
if (!isset($_SESSION['acl']['pw_reset']) || $_SESSION['acl']['pw_reset'] != "1" ) {
|
if (!isset($_SESSION['acl']['pw_reset']) || $_SESSION['acl']['pw_reset'] != "1" ) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
@@ -1016,21 +1016,6 @@ function edit_user_account($_data) {
|
|||||||
return false;
|
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;
|
$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)
|
$stmt = $pdo->prepare("UPDATE `mailbox` SET `attributes` = JSON_SET(`attributes`, '$.recovery_email', :recovery_email)
|
||||||
WHERE `username` = :username AND authsource = 'mailcow'");
|
WHERE `username` = :username AND authsource = 'mailcow'");
|
||||||
@@ -2014,7 +1999,7 @@ function admin_api($access, $action, $data = null) {
|
|||||||
}
|
}
|
||||||
function license($action, $data = null) {
|
function license($action, $data = null) {
|
||||||
global $pdo;
|
global $pdo;
|
||||||
global $redis;
|
global $valkey;
|
||||||
global $lang;
|
global $lang;
|
||||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
@@ -2064,13 +2049,13 @@ function license($action, $data = null) {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// json_encode needs "true"/"false" instead of true/false, to not encode it to 0 or 1
|
// json_encode needs "true"/"false" instead of true/false, to not encode it to 0 or 1
|
||||||
$redis->Set('LICENSE_STATUS_CACHE', json_encode($_SESSION['gal']));
|
$valkey->Set('LICENSE_STATUS_CACHE', json_encode($_SESSION['gal']));
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2151,7 +2136,7 @@ function rspamd_ui($action, $data = null) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
function cors($action, $data = null) {
|
function cors($action, $data = null) {
|
||||||
global $redis;
|
global $valkey;
|
||||||
|
|
||||||
switch ($action) {
|
switch ($action) {
|
||||||
case "edit":
|
case "edit":
|
||||||
@@ -2192,7 +2177,7 @@ function cors($action, $data = null) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$redis->hMSet('CORS_SETTINGS', array(
|
$valkey->hMSet('CORS_SETTINGS', array(
|
||||||
'allowed_origins' => implode(', ', $allowed_origins),
|
'allowed_origins' => implode(', ', $allowed_origins),
|
||||||
'allowed_methods' => implode(', ', $allowed_methods)
|
'allowed_methods' => implode(', ', $allowed_methods)
|
||||||
));
|
));
|
||||||
@@ -2200,7 +2185,7 @@ function cors($action, $data = null) {
|
|||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $action, $data),
|
'log' => array(__FUNCTION__, $action, $data),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2214,12 +2199,12 @@ function cors($action, $data = null) {
|
|||||||
break;
|
break;
|
||||||
case "get":
|
case "get":
|
||||||
try {
|
try {
|
||||||
$cors_settings = $redis->hMGet('CORS_SETTINGS', array('allowed_origins', 'allowed_methods'));
|
$cors_settings = $valkey->hMGet('CORS_SETTINGS', array('allowed_origins', 'allowed_methods'));
|
||||||
} catch (RedisException $e) {
|
} catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $action, $data),
|
'log' => array(__FUNCTION__, $action, $data),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2982,7 +2967,7 @@ function identity_provider($_action = null, $_data = null, $_extra = null) {
|
|||||||
}
|
}
|
||||||
function reset_password($action, $data = null) {
|
function reset_password($action, $data = null) {
|
||||||
global $pdo;
|
global $pdo;
|
||||||
global $redis;
|
global $valkey;
|
||||||
global $mailcow_hostname;
|
global $mailcow_hostname;
|
||||||
global $PW_RESET_TOKEN_LIMIT;
|
global $PW_RESET_TOKEN_LIMIT;
|
||||||
global $PW_RESET_TOKEN_LIFETIME;
|
global $PW_RESET_TOKEN_LIFETIME;
|
||||||
@@ -3218,10 +3203,10 @@ function reset_password($action, $data = null) {
|
|||||||
$type = $data;
|
$type = $data;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$settings['from'] = $redis->Get('PW_RESET_FROM');
|
$settings['from'] = $valkey->Get('PW_RESET_FROM');
|
||||||
$settings['subject'] = $redis->Get('PW_RESET_SUBJ');
|
$settings['subject'] = $valkey->Get('PW_RESET_SUBJ');
|
||||||
$settings['html_tmpl'] = $redis->Get('PW_RESET_HTML');
|
$settings['html_tmpl'] = $valkey->Get('PW_RESET_HTML');
|
||||||
$settings['text_tmpl'] = $redis->Get('PW_RESET_TEXT');
|
$settings['text_tmpl'] = $valkey->Get('PW_RESET_TEXT');
|
||||||
if (empty($settings['html_tmpl']) && empty($settings['text_tmpl'])) {
|
if (empty($settings['html_tmpl']) && empty($settings['text_tmpl'])) {
|
||||||
$settings['html_tmpl'] = file_get_contents("/tpls/pw_reset_html.tpl");
|
$settings['html_tmpl'] = file_get_contents("/tpls/pw_reset_html.tpl");
|
||||||
$settings['text_tmpl'] = file_get_contents("/tpls/pw_reset_text.tpl");
|
$settings['text_tmpl'] = file_get_contents("/tpls/pw_reset_text.tpl");
|
||||||
@@ -3236,7 +3221,7 @@ function reset_password($action, $data = null) {
|
|||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $action, $_data_log),
|
'log' => array(__FUNCTION__, $action, $_data_log),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -3339,16 +3324,16 @@ function reset_password($action, $data = null) {
|
|||||||
$html = (empty($data['html_tmpl'])) ? "" : $data['html_tmpl'];
|
$html = (empty($data['html_tmpl'])) ? "" : $data['html_tmpl'];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$redis->Set('PW_RESET_FROM', $from);
|
$valkey->Set('PW_RESET_FROM', $from);
|
||||||
$redis->Set('PW_RESET_SUBJ', $subject);
|
$valkey->Set('PW_RESET_SUBJ', $subject);
|
||||||
$redis->Set('PW_RESET_HTML', $html);
|
$valkey->Set('PW_RESET_HTML', $html);
|
||||||
$redis->Set('PW_RESET_TEXT', $text);
|
$valkey->Set('PW_RESET_TEXT', $text);
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $action, $_data_log),
|
'log' => array(__FUNCTION__, $action, $_data_log),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -3391,7 +3376,7 @@ function get_logs($application, $lines = false) {
|
|||||||
$to = intval($to);
|
$to = intval($to);
|
||||||
if ($from < 1 || $to < $from) { return false; }
|
if ($from < 1 || $to < $from) { return false; }
|
||||||
}
|
}
|
||||||
global $redis;
|
global $valkey;
|
||||||
global $pdo;
|
global $pdo;
|
||||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||||
return false;
|
return false;
|
||||||
@@ -3440,10 +3425,10 @@ function get_logs($application, $lines = false) {
|
|||||||
// Redis
|
// Redis
|
||||||
if ($application == "dovecot-mailcow") {
|
if ($application == "dovecot-mailcow") {
|
||||||
if (isset($from) && isset($to)) {
|
if (isset($from) && isset($to)) {
|
||||||
$data = $redis->lRange('DOVECOT_MAILLOG', $from - 1, $to - 1);
|
$data = $valkey->lRange('DOVECOT_MAILLOG', $from - 1, $to - 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$data = $redis->lRange('DOVECOT_MAILLOG', 0, $lines);
|
$data = $valkey->lRange('DOVECOT_MAILLOG', 0, $lines);
|
||||||
}
|
}
|
||||||
if ($data) {
|
if ($data) {
|
||||||
foreach ($data as $json_line) {
|
foreach ($data as $json_line) {
|
||||||
@@ -3454,10 +3439,10 @@ function get_logs($application, $lines = false) {
|
|||||||
}
|
}
|
||||||
if ($application == "cron-mailcow") {
|
if ($application == "cron-mailcow") {
|
||||||
if (isset($from) && isset($to)) {
|
if (isset($from) && isset($to)) {
|
||||||
$data = $redis->lRange('CRON_LOG', $from - 1, $to - 1);
|
$data = $valkey->lRange('CRON_LOG', $from - 1, $to - 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$data = $redis->lRange('CRON_LOG', 0, $lines);
|
$data = $valkey->lRange('CRON_LOG', 0, $lines);
|
||||||
}
|
}
|
||||||
if ($data) {
|
if ($data) {
|
||||||
foreach ($data as $json_line) {
|
foreach ($data as $json_line) {
|
||||||
@@ -3468,10 +3453,10 @@ function get_logs($application, $lines = false) {
|
|||||||
}
|
}
|
||||||
if ($application == "postfix-mailcow") {
|
if ($application == "postfix-mailcow") {
|
||||||
if (isset($from) && isset($to)) {
|
if (isset($from) && isset($to)) {
|
||||||
$data = $redis->lRange('POSTFIX_MAILLOG', $from - 1, $to - 1);
|
$data = $valkey->lRange('POSTFIX_MAILLOG', $from - 1, $to - 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$data = $redis->lRange('POSTFIX_MAILLOG', 0, $lines);
|
$data = $valkey->lRange('POSTFIX_MAILLOG', 0, $lines);
|
||||||
}
|
}
|
||||||
if ($data) {
|
if ($data) {
|
||||||
foreach ($data as $json_line) {
|
foreach ($data as $json_line) {
|
||||||
@@ -3482,10 +3467,10 @@ function get_logs($application, $lines = false) {
|
|||||||
}
|
}
|
||||||
if ($application == "sogo-mailcow") {
|
if ($application == "sogo-mailcow") {
|
||||||
if (isset($from) && isset($to)) {
|
if (isset($from) && isset($to)) {
|
||||||
$data = $redis->lRange('SOGO_LOG', $from - 1, $to - 1);
|
$data = $valkey->lRange('SOGO_LOG', $from - 1, $to - 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$data = $redis->lRange('SOGO_LOG', 0, $lines);
|
$data = $valkey->lRange('SOGO_LOG', 0, $lines);
|
||||||
}
|
}
|
||||||
if ($data) {
|
if ($data) {
|
||||||
foreach ($data as $json_line) {
|
foreach ($data as $json_line) {
|
||||||
@@ -3496,10 +3481,10 @@ function get_logs($application, $lines = false) {
|
|||||||
}
|
}
|
||||||
if ($application == "watchdog-mailcow") {
|
if ($application == "watchdog-mailcow") {
|
||||||
if (isset($from) && isset($to)) {
|
if (isset($from) && isset($to)) {
|
||||||
$data = $redis->lRange('WATCHDOG_LOG', $from - 1, $to - 1);
|
$data = $valkey->lRange('WATCHDOG_LOG', $from - 1, $to - 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$data = $redis->lRange('WATCHDOG_LOG', 0, $lines);
|
$data = $valkey->lRange('WATCHDOG_LOG', 0, $lines);
|
||||||
}
|
}
|
||||||
if ($data) {
|
if ($data) {
|
||||||
foreach ($data as $json_line) {
|
foreach ($data as $json_line) {
|
||||||
@@ -3510,10 +3495,10 @@ function get_logs($application, $lines = false) {
|
|||||||
}
|
}
|
||||||
if ($application == "acme-mailcow") {
|
if ($application == "acme-mailcow") {
|
||||||
if (isset($from) && isset($to)) {
|
if (isset($from) && isset($to)) {
|
||||||
$data = $redis->lRange('ACME_LOG', $from - 1, $to - 1);
|
$data = $valkey->lRange('ACME_LOG', $from - 1, $to - 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$data = $redis->lRange('ACME_LOG', 0, $lines);
|
$data = $valkey->lRange('ACME_LOG', 0, $lines);
|
||||||
}
|
}
|
||||||
if ($data) {
|
if ($data) {
|
||||||
foreach ($data as $json_line) {
|
foreach ($data as $json_line) {
|
||||||
@@ -3524,10 +3509,10 @@ function get_logs($application, $lines = false) {
|
|||||||
}
|
}
|
||||||
if ($application == "ratelimited") {
|
if ($application == "ratelimited") {
|
||||||
if (isset($from) && isset($to)) {
|
if (isset($from) && isset($to)) {
|
||||||
$data = $redis->lRange('RL_LOG', $from - 1, $to - 1);
|
$data = $valkey->lRange('RL_LOG', $from - 1, $to - 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$data = $redis->lRange('RL_LOG', 0, $lines);
|
$data = $valkey->lRange('RL_LOG', 0, $lines);
|
||||||
}
|
}
|
||||||
if ($data) {
|
if ($data) {
|
||||||
foreach ($data as $json_line) {
|
foreach ($data as $json_line) {
|
||||||
@@ -3538,10 +3523,10 @@ function get_logs($application, $lines = false) {
|
|||||||
}
|
}
|
||||||
if ($application == "api-mailcow") {
|
if ($application == "api-mailcow") {
|
||||||
if (isset($from) && isset($to)) {
|
if (isset($from) && isset($to)) {
|
||||||
$data = $redis->lRange('API_LOG', $from - 1, $to - 1);
|
$data = $valkey->lRange('API_LOG', $from - 1, $to - 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$data = $redis->lRange('API_LOG', 0, $lines);
|
$data = $valkey->lRange('API_LOG', 0, $lines);
|
||||||
}
|
}
|
||||||
if ($data) {
|
if ($data) {
|
||||||
foreach ($data as $json_line) {
|
foreach ($data as $json_line) {
|
||||||
@@ -3552,10 +3537,10 @@ function get_logs($application, $lines = false) {
|
|||||||
}
|
}
|
||||||
if ($application == "netfilter-mailcow") {
|
if ($application == "netfilter-mailcow") {
|
||||||
if (isset($from) && isset($to)) {
|
if (isset($from) && isset($to)) {
|
||||||
$data = $redis->lRange('NETFILTER_LOG', $from - 1, $to - 1);
|
$data = $valkey->lRange('NETFILTER_LOG', $from - 1, $to - 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$data = $redis->lRange('NETFILTER_LOG', 0, $lines);
|
$data = $valkey->lRange('NETFILTER_LOG', 0, $lines);
|
||||||
}
|
}
|
||||||
if ($data) {
|
if ($data) {
|
||||||
foreach ($data as $json_line) {
|
foreach ($data as $json_line) {
|
||||||
@@ -3566,10 +3551,10 @@ function get_logs($application, $lines = false) {
|
|||||||
}
|
}
|
||||||
if ($application == "autodiscover-mailcow") {
|
if ($application == "autodiscover-mailcow") {
|
||||||
if (isset($from) && isset($to)) {
|
if (isset($from) && isset($to)) {
|
||||||
$data = $redis->lRange('AUTODISCOVER_LOG', $from - 1, $to - 1);
|
$data = $valkey->lRange('AUTODISCOVER_LOG', $from - 1, $to - 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$data = $redis->lRange('AUTODISCOVER_LOG', 0, $lines);
|
$data = $valkey->lRange('AUTODISCOVER_LOG', 0, $lines);
|
||||||
}
|
}
|
||||||
if ($data) {
|
if ($data) {
|
||||||
foreach ($data as $json_line) {
|
foreach ($data as $json_line) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
||||||
global $pdo;
|
global $pdo;
|
||||||
global $redis;
|
global $valkey;
|
||||||
global $lang;
|
global $lang;
|
||||||
global $MAILBOX_DEFAULT_ATTRIBUTES;
|
global $MAILBOX_DEFAULT_ATTRIBUTES;
|
||||||
global $iam_settings;
|
global $iam_settings;
|
||||||
@@ -49,12 +49,6 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
// Default to 1 yr
|
// Default to 1 yr
|
||||||
$_data["validity"] = 8760;
|
$_data["validity"] = 8760;
|
||||||
}
|
}
|
||||||
if (isset($_data["permanent"]) && filter_var($_data["permanent"], FILTER_VALIDATE_BOOL)) {
|
|
||||||
$permanent = 1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$permanent = 0;
|
|
||||||
}
|
|
||||||
$domain = $_data['domain'];
|
$domain = $_data['domain'];
|
||||||
$description = $_data['description'];
|
$description = $_data['description'];
|
||||||
$valid_domains[] = mailbox('get', 'mailbox_details', $username)['domain'];
|
$valid_domains[] = mailbox('get', 'mailbox_details', $username)['domain'];
|
||||||
@@ -71,14 +65,13 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$validity = strtotime("+" . $_data["validity"] . " hour");
|
$validity = strtotime("+" . $_data["validity"] . " hour");
|
||||||
$stmt = $pdo->prepare("INSERT INTO `spamalias` (`address`, `description`, `goto`, `validity`, `permanent`) VALUES
|
$stmt = $pdo->prepare("INSERT INTO `spamalias` (`address`, `description`, `goto`, `validity`) VALUES
|
||||||
(:address, :description, :goto, :validity, :permanent)");
|
(:address, :description, :goto, :validity)");
|
||||||
$stmt->execute(array(
|
$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,
|
':address' => readable_random_string(rand(rand(3, 9), rand(3, 9))) . '.' . readable_random_string(rand(rand(3, 9), rand(3, 9))) . '@' . $domain,
|
||||||
':description' => $description,
|
':description' => $description,
|
||||||
':goto' => $username,
|
':goto' => $username,
|
||||||
':validity' => $validity,
|
':validity' => $validity
|
||||||
':permanent' => $permanent
|
|
||||||
));
|
));
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'success',
|
'type' => 'success',
|
||||||
@@ -635,13 +628,13 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$redis->hSet('DOMAIN_MAP', $domain, 1);
|
$valkey->hSet('DOMAIN_MAP', $domain, 1);
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -653,7 +646,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
$_data['key_size'] = (isset($_data['key_size'])) ? intval($_data['key_size']) : $DOMAIN_DEFAULT_ATTRIBUTES['key_size'];
|
$_data['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'];
|
$_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($_data['key_size']) && !empty($_data['dkim_selector'])) {
|
||||||
if (!empty($redis->hGet('DKIM_SELECTORS', $domain))) {
|
if (!empty($valkey->hGet('DKIM_SELECTORS', $domain))) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'success',
|
'type' => 'success',
|
||||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
@@ -981,13 +974,13 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
':active' => $active
|
':active' => $active
|
||||||
));
|
));
|
||||||
try {
|
try {
|
||||||
$redis->hSet('DOMAIN_MAP', $alias_domain, 1);
|
$valkey->hSet('DOMAIN_MAP', $alias_domain, 1);
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -995,7 +988,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
ratelimit('edit', 'domain', array('rl_value' => $_data['rl_value'], 'rl_frame' => $_data['rl_frame'], 'object' => $alias_domain));
|
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($_data['key_size']) && !empty($_data['dkim_selector'])) {
|
||||||
if (!empty($redis->hGet('DKIM_SELECTORS', $alias_domain))) {
|
if (!empty($valkey->hGet('DKIM_SELECTORS', $alias_domain))) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'success',
|
'type' => 'success',
|
||||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
@@ -2110,23 +2103,15 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (empty($_data['validity']) && empty($_data['permanent'])) {
|
if (empty($_data['validity'])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (isset($_data['permanent']) && filter_var($_data['permanent'], FILTER_VALIDATE_BOOL)) {
|
$validity = round((int)time() + ($_data['validity'] * 3600));
|
||||||
$permanent = 1;
|
$stmt = $pdo->prepare("UPDATE `spamalias` SET `validity` = :validity WHERE
|
||||||
$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");
|
`address` = :address");
|
||||||
$stmt->execute(array(
|
$stmt->execute(array(
|
||||||
':address' => $address,
|
':address' => $address,
|
||||||
':validity' => $validity,
|
':validity' => $validity
|
||||||
':permanent' => $permanent
|
|
||||||
));
|
));
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'success',
|
'type' => 'success',
|
||||||
@@ -2162,42 +2147,42 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
}
|
}
|
||||||
if (isset($_data['tagged_mail_handler']) && $_data['tagged_mail_handler'] == "subject") {
|
if (isset($_data['tagged_mail_handler']) && $_data['tagged_mail_handler'] == "subject") {
|
||||||
try {
|
try {
|
||||||
$redis->hSet('RCPT_WANTS_SUBJECT_TAG', $username, 1);
|
$valkey->hSet('RCPT_WANTS_SUBJECT_TAG', $username, 1);
|
||||||
$redis->hDel('RCPT_WANTS_SUBFOLDER_TAG', $username);
|
$valkey->hDel('RCPT_WANTS_SUBFOLDER_TAG', $username);
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (isset($_data['tagged_mail_handler']) && $_data['tagged_mail_handler'] == "subfolder") {
|
else if (isset($_data['tagged_mail_handler']) && $_data['tagged_mail_handler'] == "subfolder") {
|
||||||
try {
|
try {
|
||||||
$redis->hSet('RCPT_WANTS_SUBFOLDER_TAG', $username, 1);
|
$valkey->hSet('RCPT_WANTS_SUBFOLDER_TAG', $username, 1);
|
||||||
$redis->hDel('RCPT_WANTS_SUBJECT_TAG', $username);
|
$valkey->hDel('RCPT_WANTS_SUBJECT_TAG', $username);
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
try {
|
try {
|
||||||
$redis->hDel('RCPT_WANTS_SUBJECT_TAG', $username);
|
$valkey->hDel('RCPT_WANTS_SUBJECT_TAG', $username);
|
||||||
$redis->hDel('RCPT_WANTS_SUBFOLDER_TAG', $username);
|
$valkey->hDel('RCPT_WANTS_SUBFOLDER_TAG', $username);
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -4599,12 +4584,10 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
`description`,
|
`description`,
|
||||||
`validity`,
|
`validity`,
|
||||||
`created`,
|
`created`,
|
||||||
`modified`,
|
`modified`
|
||||||
`permanent`
|
|
||||||
FROM `spamalias`
|
FROM `spamalias`
|
||||||
WHERE `goto` = :username
|
WHERE `goto` = :username
|
||||||
AND (`validity` >= :unixnow
|
AND `validity` >= :unixnow");
|
||||||
OR `permanent` != 0)");
|
|
||||||
$stmt->execute(array(':username' => $_data, ':unixnow' => time()));
|
$stmt->execute(array(':username' => $_data, ':unixnow' => time()));
|
||||||
$tladata = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$tladata = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
return $tladata;
|
return $tladata;
|
||||||
@@ -4620,10 +4603,10 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
$_data = $_SESSION['mailcow_cc_username'];
|
$_data = $_SESSION['mailcow_cc_username'];
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if ($redis->hGet('RCPT_WANTS_SUBJECT_TAG', $_data)) {
|
if ($valkey->hGet('RCPT_WANTS_SUBJECT_TAG', $_data)) {
|
||||||
return "subject";
|
return "subject";
|
||||||
}
|
}
|
||||||
elseif ($redis->hGet('RCPT_WANTS_SUBFOLDER_TAG', $_data)) {
|
elseif ($valkey->hGet('RCPT_WANTS_SUBFOLDER_TAG', $_data)) {
|
||||||
return "subfolder";
|
return "subfolder";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -4634,7 +4617,7 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -5179,7 +5162,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 = $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));
|
$stmt->execute(array(':domain' => $row['domain'], ':username' => $_data));
|
||||||
$MailboxUsage = $stmt->fetch(PDO::FETCH_ASSOC);
|
$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 OR `permanent` != 0)");
|
$stmt = $pdo->prepare("SELECT IFNULL(COUNT(`address`), 0) AS `sa_count` FROM `spamalias` WHERE `goto` = :address AND `validity` >= :unixnow");
|
||||||
$stmt->execute(array(':address' => $_data, ':unixnow' => time()));
|
$stmt->execute(array(':address' => $_data, ':unixnow' => time()));
|
||||||
$SpamaliasUsage = $stmt->fetch(PDO::FETCH_ASSOC);
|
$SpamaliasUsage = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
$mailboxdata['max_new_quota'] = ($DomainQuota['quota'] * 1048576) - $MailboxUsage['in_use'];
|
$mailboxdata['max_new_quota'] = ($DomainQuota['quota'] * 1048576) - $MailboxUsage['in_use'];
|
||||||
@@ -5653,14 +5636,14 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
$stmt = $pdo->query("DELETE FROM `admin` WHERE `superadmin` = 0 AND `username` NOT IN (SELECT `username`FROM `domain_admins`);");
|
$stmt = $pdo->query("DELETE FROM `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`);");
|
$stmt = $pdo->query("DELETE FROM `da_acl` WHERE `username` NOT IN (SELECT `username`FROM `domain_admins`);");
|
||||||
try {
|
try {
|
||||||
$redis->hDel('DOMAIN_MAP', $domain);
|
$valkey->hDel('DOMAIN_MAP', $domain);
|
||||||
$redis->hDel('RL_VALUE', $domain);
|
$valkey->hDel('RL_VALUE', $domain);
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -5786,14 +5769,14 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
':alias_domain' => $alias_domain,
|
':alias_domain' => $alias_domain,
|
||||||
));
|
));
|
||||||
try {
|
try {
|
||||||
$redis->hDel('DOMAIN_MAP', $alias_domain);
|
$valkey->hDel('DOMAIN_MAP', $alias_domain);
|
||||||
$redis->hDel('RL_VALUE', $domain);
|
$valkey->hDel('RL_VALUE', $domain);
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -5972,13 +5955,13 @@ function mailbox($_action, $_type, $_data = null, $_extra = null) {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
$redis->hDel('RL_VALUE', $username);
|
$valkey->hDel('RL_VALUE', $username);
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
'log' => array(__FUNCTION__, $_action, $_type, $_data_log, $_attr),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
function oauth2($_action, $_type, $_data = null) {
|
function oauth2($_action, $_type, $_data = null) {
|
||||||
global $pdo;
|
global $pdo;
|
||||||
global $redis;
|
global $valkey;
|
||||||
global $lang;
|
global $lang;
|
||||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
function policy($_action, $_scope, $_data = null) {
|
function policy($_action, $_scope, $_data = null) {
|
||||||
global $pdo;
|
global $pdo;
|
||||||
global $redis;
|
global $valkey;
|
||||||
global $lang;
|
global $lang;
|
||||||
$_data_log = $_data;
|
$_data_log = $_data;
|
||||||
switch ($_action) {
|
switch ($_action) {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use PHPMailer\PHPMailer\SMTP;
|
|||||||
use PHPMailer\PHPMailer\Exception;
|
use PHPMailer\PHPMailer\Exception;
|
||||||
function quarantine($_action, $_data = null) {
|
function quarantine($_action, $_data = null) {
|
||||||
global $pdo;
|
global $pdo;
|
||||||
global $redis;
|
global $valkey;
|
||||||
global $lang;
|
global $lang;
|
||||||
$_data_log = $_data;
|
$_data_log = $_data;
|
||||||
switch ($_action) {
|
switch ($_action) {
|
||||||
@@ -102,14 +102,14 @@ function quarantine($_action, $_data = null) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
$release_format = $redis->Get('Q_RELEASE_FORMAT');
|
$release_format = $valkey->Get('Q_RELEASE_FORMAT');
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
logger(array('return' => array(
|
logger(array('return' => array(
|
||||||
array(
|
array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
)
|
)
|
||||||
)));
|
)));
|
||||||
return false;
|
return false;
|
||||||
@@ -332,23 +332,23 @@ function quarantine($_action, $_data = null) {
|
|||||||
}
|
}
|
||||||
$exclude_domains = (array)$_data['exclude_domains'];
|
$exclude_domains = (array)$_data['exclude_domains'];
|
||||||
try {
|
try {
|
||||||
$redis->Set('Q_RETENTION_SIZE', intval($retention_size));
|
$valkey->Set('Q_RETENTION_SIZE', intval($retention_size));
|
||||||
$redis->Set('Q_MAX_SIZE', intval($max_size));
|
$valkey->Set('Q_MAX_SIZE', intval($max_size));
|
||||||
$redis->Set('Q_MAX_SCORE', $max_score);
|
$valkey->Set('Q_MAX_SCORE', $max_score);
|
||||||
$redis->Set('Q_MAX_AGE', $max_age);
|
$valkey->Set('Q_MAX_AGE', $max_age);
|
||||||
$redis->Set('Q_EXCLUDE_DOMAINS', json_encode($exclude_domains));
|
$valkey->Set('Q_EXCLUDE_DOMAINS', json_encode($exclude_domains));
|
||||||
$redis->Set('Q_RELEASE_FORMAT', $release_format);
|
$valkey->Set('Q_RELEASE_FORMAT', $release_format);
|
||||||
$redis->Set('Q_SENDER', $sender);
|
$valkey->Set('Q_SENDER', $sender);
|
||||||
$redis->Set('Q_BCC', $bcc);
|
$valkey->Set('Q_BCC', $bcc);
|
||||||
$redis->Set('Q_REDIRECT', $redirect);
|
$valkey->Set('Q_REDIRECT', $redirect);
|
||||||
$redis->Set('Q_SUBJ', $subject);
|
$valkey->Set('Q_SUBJ', $subject);
|
||||||
$redis->Set('Q_HTML', $html);
|
$valkey->Set('Q_HTML', $html);
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -403,13 +403,13 @@ function quarantine($_action, $_data = null) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
$release_format = $redis->Get('Q_RELEASE_FORMAT');
|
$release_format = $valkey->Get('Q_RELEASE_FORMAT');
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -776,18 +776,18 @@ function quarantine($_action, $_data = null) {
|
|||||||
case 'settings':
|
case 'settings':
|
||||||
try {
|
try {
|
||||||
if ($_SESSION['mailcow_cc_role'] == "admin") {
|
if ($_SESSION['mailcow_cc_role'] == "admin") {
|
||||||
$settings['exclude_domains'] = json_decode($redis->Get('Q_EXCLUDE_DOMAINS'), true);
|
$settings['exclude_domains'] = json_decode($valkey->Get('Q_EXCLUDE_DOMAINS'), true);
|
||||||
}
|
}
|
||||||
$settings['max_size'] = $redis->Get('Q_MAX_SIZE');
|
$settings['max_size'] = $valkey->Get('Q_MAX_SIZE');
|
||||||
$settings['max_score'] = $redis->Get('Q_MAX_SCORE');
|
$settings['max_score'] = $valkey->Get('Q_MAX_SCORE');
|
||||||
$settings['max_age'] = $redis->Get('Q_MAX_AGE');
|
$settings['max_age'] = $valkey->Get('Q_MAX_AGE');
|
||||||
$settings['retention_size'] = $redis->Get('Q_RETENTION_SIZE');
|
$settings['retention_size'] = $valkey->Get('Q_RETENTION_SIZE');
|
||||||
$settings['release_format'] = $redis->Get('Q_RELEASE_FORMAT');
|
$settings['release_format'] = $valkey->Get('Q_RELEASE_FORMAT');
|
||||||
$settings['subject'] = $redis->Get('Q_SUBJ');
|
$settings['subject'] = $valkey->Get('Q_SUBJ');
|
||||||
$settings['sender'] = $redis->Get('Q_SENDER');
|
$settings['sender'] = $valkey->Get('Q_SENDER');
|
||||||
$settings['bcc'] = $redis->Get('Q_BCC');
|
$settings['bcc'] = $valkey->Get('Q_BCC');
|
||||||
$settings['redirect'] = $redis->Get('Q_REDIRECT');
|
$settings['redirect'] = $valkey->Get('Q_REDIRECT');
|
||||||
$settings['html_tmpl'] = htmlspecialchars($redis->Get('Q_HTML'));
|
$settings['html_tmpl'] = htmlspecialchars($valkey->Get('Q_HTML'));
|
||||||
if (empty($settings['html_tmpl'])) {
|
if (empty($settings['html_tmpl'])) {
|
||||||
$settings['html_tmpl'] = htmlspecialchars(file_get_contents("/tpls/quarantine.tpl"));
|
$settings['html_tmpl'] = htmlspecialchars(file_get_contents("/tpls/quarantine.tpl"));
|
||||||
}
|
}
|
||||||
@@ -796,7 +796,7 @@ function quarantine($_action, $_data = null) {
|
|||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
function quota_notification($_action, $_data = null) {
|
function quota_notification($_action, $_data = null) {
|
||||||
global $redis;
|
global $valkey;
|
||||||
$_data_log = $_data;
|
$_data_log = $_data;
|
||||||
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
@@ -26,15 +26,15 @@ function quota_notification($_action, $_data = null) {
|
|||||||
}
|
}
|
||||||
$html = $_data['html_tmpl'];
|
$html = $_data['html_tmpl'];
|
||||||
try {
|
try {
|
||||||
$redis->Set('QW_SENDER', $sender);
|
$valkey->Set('QW_SENDER', $sender);
|
||||||
$redis->Set('QW_SUBJ', $subject);
|
$valkey->Set('QW_SUBJ', $subject);
|
||||||
$redis->Set('QW_HTML', $html);
|
$valkey->Set('QW_HTML', $html);
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -46,9 +46,9 @@ function quota_notification($_action, $_data = null) {
|
|||||||
break;
|
break;
|
||||||
case 'get':
|
case 'get':
|
||||||
try {
|
try {
|
||||||
$settings['subject'] = $redis->Get('QW_SUBJ');
|
$settings['subject'] = $valkey->Get('QW_SUBJ');
|
||||||
$settings['sender'] = $redis->Get('QW_SENDER');
|
$settings['sender'] = $valkey->Get('QW_SENDER');
|
||||||
$settings['html_tmpl'] = htmlspecialchars($redis->Get('QW_HTML'));
|
$settings['html_tmpl'] = htmlspecialchars($valkey->Get('QW_HTML'));
|
||||||
if (empty($settings['html_tmpl'])) {
|
if (empty($settings['html_tmpl'])) {
|
||||||
$settings['html_tmpl'] = htmlspecialchars(file_get_contents("/tpls/quota.tpl"));
|
$settings['html_tmpl'] = htmlspecialchars(file_get_contents("/tpls/quota.tpl"));
|
||||||
}
|
}
|
||||||
@@ -57,7 +57,7 @@ function quota_notification($_action, $_data = null) {
|
|||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -66,7 +66,7 @@ function quota_notification($_action, $_data = null) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
function quota_notification_bcc($_action, $_data = null) {
|
function quota_notification_bcc($_action, $_data = null) {
|
||||||
global $redis;
|
global $valkey;
|
||||||
$_data_log = $_data;
|
$_data_log = $_data;
|
||||||
if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
|
if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
@@ -108,13 +108,13 @@ function quota_notification_bcc($_action, $_data = null) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
$redis->hSet('QW_BCC', $domain, json_encode(array('bcc_rcpts' => $bcc_rcpts, 'active' => $active)));
|
$valkey->hSet('QW_BCC', $domain, json_encode(array('bcc_rcpts' => $bcc_rcpts, 'active' => $active)));
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -135,13 +135,13 @@ function quota_notification_bcc($_action, $_data = null) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return json_decode($redis->hGet('QW_BCC', $domain), true);
|
return json_decode($valkey->hGet('QW_BCC', $domain), true);
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_data_log),
|
'log' => array(__FUNCTION__, $_action, $_data_log),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
function ratelimit($_action, $_scope, $_data = null, $_extra = null) {
|
function ratelimit($_action, $_scope, $_data = null, $_extra = null) {
|
||||||
global $redis;
|
global $valkey;
|
||||||
$_data_log = $_data;
|
$_data_log = $_data;
|
||||||
switch ($_action) {
|
switch ($_action) {
|
||||||
case 'edit':
|
case 'edit':
|
||||||
@@ -42,26 +42,26 @@ function ratelimit($_action, $_scope, $_data = null, $_extra = null) {
|
|||||||
}
|
}
|
||||||
if (empty($rl_value)) {
|
if (empty($rl_value)) {
|
||||||
try {
|
try {
|
||||||
$redis->hDel('RL_VALUE', $object);
|
$valkey->hDel('RL_VALUE', $object);
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
try {
|
try {
|
||||||
$redis->hSet('RL_VALUE', $object, $rl_value . ' / 1' . $rl_frame);
|
$valkey->hSet('RL_VALUE', $object, $rl_value . ' / 1' . $rl_frame);
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -103,26 +103,26 @@ function ratelimit($_action, $_scope, $_data = null, $_extra = null) {
|
|||||||
}
|
}
|
||||||
if (empty($rl_value)) {
|
if (empty($rl_value)) {
|
||||||
try {
|
try {
|
||||||
$redis->hDel('RL_VALUE', $object);
|
$valkey->hDel('RL_VALUE', $object);
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
try {
|
try {
|
||||||
$redis->hSet('RL_VALUE', $object, $rl_value . ' / 1' . $rl_frame);
|
$valkey->hSet('RL_VALUE', $object, $rl_value . ' / 1' . $rl_frame);
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -143,7 +143,7 @@ function ratelimit($_action, $_scope, $_data = null, $_extra = null) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if ($rl_value = $redis->hGet('RL_VALUE', $_data)) {
|
if ($rl_value = $valkey->hGet('RL_VALUE', $_data)) {
|
||||||
$rl = explode(' / 1', $rl_value);
|
$rl = explode(' / 1', $rl_value);
|
||||||
$data['value'] = $rl[0];
|
$data['value'] = $rl[0];
|
||||||
$data['frame'] = $rl[1];
|
$data['frame'] = $rl[1];
|
||||||
@@ -157,7 +157,7 @@ function ratelimit($_action, $_scope, $_data = null, $_extra = null) {
|
|||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -169,7 +169,7 @@ function ratelimit($_action, $_scope, $_data = null, $_extra = null) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if ($rl_value = $redis->hGet('RL_VALUE', $_data)) {
|
if ($rl_value = $valkey->hGet('RL_VALUE', $_data)) {
|
||||||
$rl = explode(' / 1', $rl_value);
|
$rl = explode(' / 1', $rl_value);
|
||||||
$data['value'] = $rl[0];
|
$data['value'] = $rl[0];
|
||||||
$data['frame'] = $rl[1];
|
$data['frame'] = $rl[1];
|
||||||
@@ -183,7 +183,7 @@ function ratelimit($_action, $_scope, $_data = null, $_extra = null) {
|
|||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -202,16 +202,16 @@ function ratelimit($_action, $_scope, $_data = null, $_extra = null) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
$data_rllog = $redis->lRange('RL_LOG', 0, -1);
|
$data_rllog = $valkey->lRange('RL_LOG', 0, -1);
|
||||||
if ($data_rllog) {
|
if ($data_rllog) {
|
||||||
foreach ($data_rllog as $json_line) {
|
foreach ($data_rllog as $json_line) {
|
||||||
if (preg_match('/' . $data['hash'] . '/i', $json_line)) {
|
if (preg_match('/' . $data['hash'] . '/i', $json_line)) {
|
||||||
$redis->lRem('RL_LOG', $json_line, 0);
|
$valkey->lRem('RL_LOG', $json_line, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($redis->type($data['hash']) == Redis::REDIS_HASH) {
|
if ($valkey->type($data['hash']) == Redis::REDIS_HASH) {
|
||||||
$redis->delete($data['hash']);
|
$valkey->delete($data['hash']);
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'success',
|
'type' => 'success',
|
||||||
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
||||||
@@ -232,7 +232,7 @@ function ratelimit($_action, $_scope, $_data = null, $_extra = null) {
|
|||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
'log' => array(__FUNCTION__, $_action, $_scope, $_data_log),
|
||||||
'msg' => array('redis_error', $e)
|
'msg' => array('valkey_error', $e)
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ function init_db_schema()
|
|||||||
try {
|
try {
|
||||||
global $pdo;
|
global $pdo;
|
||||||
|
|
||||||
$db_version = "10312025_0525";
|
$db_version = "07102025_1015";
|
||||||
|
|
||||||
$stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
|
$stmt = $pdo->query("SHOW TABLES LIKE 'versions'");
|
||||||
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||||
@@ -554,8 +554,7 @@ function init_db_schema()
|
|||||||
"description" => "TEXT NOT NULL",
|
"description" => "TEXT NOT NULL",
|
||||||
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
|
"created" => "DATETIME(0) NOT NULL DEFAULT NOW(0)",
|
||||||
"modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP",
|
"modified" => "DATETIME ON UPDATE CURRENT_TIMESTAMP",
|
||||||
"validity" => "INT(11)",
|
"validity" => "INT(11)"
|
||||||
"permanent" => "TINYINT(1) NOT NULL DEFAULT '0'"
|
|
||||||
),
|
),
|
||||||
"keys" => array(
|
"keys" => array(
|
||||||
"primary" => array(
|
"primary" => array(
|
||||||
|
|||||||
@@ -57,22 +57,22 @@ $WebAuthn = new lbuchs\WebAuthn\WebAuthn('WebAuthn Library', $server_name, $form
|
|||||||
// only include root ca's when needed
|
// only include root ca's when needed
|
||||||
if (getenv('WEBAUTHN_ONLY_TRUSTED_VENDORS') == 'y') $WebAuthn->addRootCertificates($_SERVER['DOCUMENT_ROOT'] . '/inc/lib/WebAuthn/rootCertificates');
|
if (getenv('WEBAUTHN_ONLY_TRUSTED_VENDORS') == 'y') $WebAuthn->addRootCertificates($_SERVER['DOCUMENT_ROOT'] . '/inc/lib/WebAuthn/rootCertificates');
|
||||||
|
|
||||||
// Redis
|
// Valkey
|
||||||
$redis = new Redis();
|
$valkey = new Redis();
|
||||||
try {
|
try {
|
||||||
if (!empty(getenv('REDIS_SLAVEOF_IP'))) {
|
if (!empty(getenv('VALKEY_SLAVEOF_IP'))) {
|
||||||
$redis->connect(getenv('REDIS_SLAVEOF_IP'), getenv('REDIS_SLAVEOF_PORT'));
|
$valkey->connect(getenv('VALKEY_SLAVEOF_IP'), getenv('VALKEY_SLAVEOF_PORT'));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$redis->connect('redis-mailcow', 6379);
|
$valkey->connect('valkey-mailcow', 6379);
|
||||||
}
|
}
|
||||||
$redis->auth(getenv("REDISPASS"));
|
$valkey->auth(getenv("VALKEYPASS"));
|
||||||
}
|
}
|
||||||
catch (Exception $e) {
|
catch (Exception $e) {
|
||||||
// Stop when redis is not available
|
// Stop when valkey is not available
|
||||||
http_response_code(500);
|
http_response_code(500);
|
||||||
?>
|
?>
|
||||||
<center style='font-family:sans-serif;'>Connection to Redis failed.<br /><br />The following error was reported:<br/><?=$e->getMessage();?></center>
|
<center style='font-family:sans-serif;'>Connection to Valkey failed.<br /><br />The following error was reported:<br/><?=$e->getMessage();?></center>
|
||||||
<?php
|
<?php
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ if (!empty($_SERVER['HTTP_X_API_KEY'])) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$redis->publish("F2B_CHANNEL", "mailcow UI: Invalid password for API_USER by " . $_SERVER['REMOTE_ADDR']);
|
$valkey->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']);
|
error_log("mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']);
|
||||||
http_response_code(401);
|
http_response_code(401);
|
||||||
echo json_encode(array(
|
echo json_encode(array(
|
||||||
@@ -81,7 +81,7 @@ if (!empty($_SERVER['HTTP_X_API_KEY'])) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$redis->publish("F2B_CHANNEL", "mailcow UI: Invalid password for API_USER by " . $_SERVER['REMOTE_ADDR']);
|
$valkey->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']);
|
error_log("mailcow UI: Invalid password for " . $user . " by " . $_SERVER['REMOTE_ADDR']);
|
||||||
http_response_code(401);
|
http_response_code(401);
|
||||||
echo json_encode(array(
|
echo json_encode(array(
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ $AVAILABLE_LANGUAGES = array(
|
|||||||
// 'ca-es' => 'Català (Catalan)',
|
// 'ca-es' => 'Català (Catalan)',
|
||||||
'bg-bg' => 'Български (Bulgarian)',
|
'bg-bg' => 'Български (Bulgarian)',
|
||||||
'cs-cz' => 'Čeština (Czech)',
|
'cs-cz' => 'Čeština (Czech)',
|
||||||
'da-dk' => 'Dansk (Danish)',
|
'da-dk' => 'Danish (Dansk)',
|
||||||
'de-de' => 'Deutsch (German)',
|
'de-de' => 'Deutsch (German)',
|
||||||
'en-gb' => 'English',
|
'en-gb' => 'English',
|
||||||
'es-es' => 'Español (Spanish)',
|
'es-es' => 'Español (Spanish)',
|
||||||
@@ -110,7 +110,6 @@ $AVAILABLE_LANGUAGES = array(
|
|||||||
'sv-se' => 'Svenska (Swedish)',
|
'sv-se' => 'Svenska (Swedish)',
|
||||||
'tr-tr' => 'Türkçe (Turkish)',
|
'tr-tr' => 'Türkçe (Turkish)',
|
||||||
'uk-ua' => 'Українська (Ukrainian)',
|
'uk-ua' => 'Українська (Ukrainian)',
|
||||||
'vi-vn' => 'Tiếng Việt (Vietnamese)',
|
|
||||||
'zh-cn' => '简体中文 (Simplified Chinese)',
|
'zh-cn' => '简体中文 (Simplified Chinese)',
|
||||||
'zh-tw' => '繁體中文 (Traditional 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']);
|
$user_details = mailbox("get", "mailbox_details", $_SESSION['mailcow_cc_username']);
|
||||||
$is_dual = (!empty($_SESSION["dual-login"]["username"])) ? true : false;
|
$is_dual = (!empty($_SESSION["dual-login"]["username"])) ? true : false;
|
||||||
if (intval($user_details['attributes']['sogo_access']) == 1 && !$is_dual && getenv('SKIP_SOGO') != "y") {
|
if (intval($user_details['attributes']['sogo_access']) == 1 && !$is_dual && getenv('SKIP_SOGO') != "y") {
|
||||||
header("Location: /SOGo/so/");
|
header("Location: /SOGo/so/{$_SESSION['mailcow_cc_username']}");
|
||||||
} else {
|
} else {
|
||||||
header("Location: /user");
|
header("Location: /user");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ jQuery(function($){
|
|||||||
var datetime = new Date(item.datetime.replace(/-/g, "/"));
|
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 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 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-key-fill"></i><span class="ms-1">' + escapeHtml(item.app_password_name || "App") + '</span></a>' : '';
|
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 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 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_location = item.location ? ' <span class="flag-icon flag-icon-' + item.location.toLowerCase() + '"></span>' : '';
|
||||||
var ip_data = real_rip + ip_location + app_password;
|
var ip_data = real_rip + ip_location + app_password;
|
||||||
@@ -105,9 +105,10 @@ jQuery(function($){
|
|||||||
$(".last-sasl-login").append(`
|
$(".last-sasl-login").append(`
|
||||||
<li class="list-group-item d-flex justify-content-between align-items-start">
|
<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="ms-2 me-auto d-flex flex-column">
|
||||||
<div class="fw-bold">` + ip_location + real_rip + `</div>
|
<div class="fw-bold">` + real_rip + `</div>
|
||||||
<small class="fst-italic mt-2">` + service + ` ` + local_datetime + `</small>` + app_password + `
|
<small class="fst-italic mt-2">` + service + ` ` + local_datetime + `</small>
|
||||||
</div>
|
</div>
|
||||||
|
<span>` + ip_location + `</span>
|
||||||
</li>
|
</li>
|
||||||
`);
|
`);
|
||||||
})
|
})
|
||||||
@@ -175,10 +176,6 @@ jQuery(function($){
|
|||||||
'</div>';
|
'</div>';
|
||||||
item.chkbox = '<input type="checkbox" class="form-check-input" data-id="tla" name="multi_select" value="' + encodeURIComponent(item.address) + '" />';
|
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.address = escapeHtml(item.address);
|
||||||
item.validity = {
|
|
||||||
value: item.validity,
|
|
||||||
permanent: item.permanent
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
item.chkbox = '<input type="checkbox" class="form-check-input" disabled />';
|
item.chkbox = '<input type="checkbox" class="form-check-input" disabled />';
|
||||||
@@ -222,21 +219,9 @@ jQuery(function($){
|
|||||||
title: lang.alias_valid_until,
|
title: lang.alias_valid_until,
|
||||||
data: 'validity',
|
data: 'validity',
|
||||||
defaultContent: '',
|
defaultContent: '',
|
||||||
render: function (data, type) {
|
createdCell: function(td, cellData) {
|
||||||
var date = new Date(data.value ? data.value * 1000 : 0);
|
createSortableDate(td, cellData)
|
||||||
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,
|
title: lang.created_on,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ header('Content-Type: application/json');
|
|||||||
error_reporting(0);
|
error_reporting(0);
|
||||||
|
|
||||||
function api_log($_data) {
|
function api_log($_data) {
|
||||||
global $redis;
|
global $valkey;
|
||||||
$data_var = array();
|
$data_var = array();
|
||||||
foreach ($_data as $data => &$value) {
|
foreach ($_data as $data => &$value) {
|
||||||
if ($data == 'csrf_token') {
|
if ($data == 'csrf_token') {
|
||||||
@@ -36,12 +36,12 @@ function api_log($_data) {
|
|||||||
'remote' => get_remote_ip(),
|
'remote' => get_remote_ip(),
|
||||||
'data' => implode(', ', $data_var)
|
'data' => implode(', ', $data_var)
|
||||||
);
|
);
|
||||||
$redis->lPush('API_LOG', json_encode($log_line));
|
$valkey->lPush('API_LOG', json_encode($log_line));
|
||||||
}
|
}
|
||||||
catch (RedisException $e) {
|
catch (RedisException $e) {
|
||||||
$_SESSION['return'][] = array(
|
$_SESSION['return'][] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'msg' => 'Redis: '.$e
|
'msg' => 'Valkey: '.$e
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1992,7 +1992,6 @@ if (isset($_GET['query'])) {
|
|||||||
break;
|
break;
|
||||||
case "cors":
|
case "cors":
|
||||||
process_edit_return(cors('edit', $attr));
|
process_edit_return(cors('edit', $attr));
|
||||||
break;
|
|
||||||
case "identity-provider":
|
case "identity-provider":
|
||||||
process_edit_return(identity_provider('edit', $attr));
|
process_edit_return(identity_provider('edit', $attr));
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -19,16 +19,7 @@
|
|||||||
"spam_alias": "Àlies temporals",
|
"spam_alias": "Àlies temporals",
|
||||||
"spam_score": "Puntuació de correu brossa",
|
"spam_score": "Puntuació de correu brossa",
|
||||||
"tls_policy": "Política TLS",
|
"tls_policy": "Política TLS",
|
||||||
"unlimited_quota": "Quota ilimitada per bústies de correo",
|
"unlimited_quota": "Quota ilimitada per bústies de correo"
|
||||||
"delimiter_action": "Acció delimitadora",
|
|
||||||
"domain_relayhost": "Canviar relayhost per un domini",
|
|
||||||
"extend_sender_acl": "Permetre extendre l'ACL del remitent per adreces externes",
|
|
||||||
"mailbox_relayhost": "Canvia el host de reenviament per una bústia",
|
|
||||||
"pushover": "Pushover",
|
|
||||||
"pw_reset": "Permetre el restabliment de la contrasenya de l'usuari mailcow",
|
|
||||||
"ratelimit": "Límit de peticions",
|
|
||||||
"smtp_ip_access": "Canvia hosts permesos per SMTP",
|
|
||||||
"sogo_access": "Permetre la gestió d'accés a SOGo"
|
|
||||||
},
|
},
|
||||||
"add": {
|
"add": {
|
||||||
"activate_filter_warn": "All other filters will be deactivated, when active is checked.",
|
"activate_filter_warn": "All other filters will be deactivated, when active is checked.",
|
||||||
@@ -82,25 +73,7 @@
|
|||||||
"validate": "Validar",
|
"validate": "Validar",
|
||||||
"validation_success": "Validated successfully",
|
"validation_success": "Validated successfully",
|
||||||
"app_name": "Nom de l'aplicació",
|
"app_name": "Nom de l'aplicació",
|
||||||
"app_password": "Afegir contrasenya a l'aplicació",
|
"app_password": "Afegir contrasenya a l'aplicació"
|
||||||
"app_passwd_protocols": "Protocols autoritzats per la contrasenya de l'aplicació",
|
|
||||||
"bcc_dest_format": "La destinació c/o ha de ser una única adreça de correu vàlida.<br>Si necessiteu enviar una còpia a diverses adreces, creeu un àlies i utilitzeu-lo aquí.",
|
|
||||||
"comment_info": "Els comentaris privats no són visibles per l'usuari, mentre que els comentaris públics apareixen com una descripció emergent a la informació de l'usuari",
|
|
||||||
"custom_params": "Paràmetres personalitzats",
|
|
||||||
"custom_params_hint": "Correcte: --param=xy, incorrecte: --param xy",
|
|
||||||
"destination": "Destí",
|
|
||||||
"disable_login": "No permetre l'inici de sessió (els missatges entrants continuen sent acceptats)",
|
|
||||||
"domain_matches_hostname": "El domini %s coincideix amb el nom del servidor",
|
|
||||||
"dry": "Simular la sincronització",
|
|
||||||
"gal": "Llista d'adreces global",
|
|
||||||
"generate": "genereu",
|
|
||||||
"inactive": "Inactiu",
|
|
||||||
"internal": "Intern",
|
|
||||||
"internal_info": "Els àlies interns són només accessibles des del mateix domini o els àlies de dominis.",
|
|
||||||
"mailbox_quota_def": "Quota per defecte de la bústia",
|
|
||||||
"nexthop": "Següent salt",
|
|
||||||
"private_comment": "Comentari privat",
|
|
||||||
"public_comment": "Comentari púlbic"
|
|
||||||
},
|
},
|
||||||
"admin": {
|
"admin": {
|
||||||
"access": "Accés",
|
"access": "Accés",
|
||||||
|
|||||||
@@ -149,7 +149,7 @@
|
|||||||
"arrival_time": "Čas zařazení do fronty (čas na serveru)",
|
"arrival_time": "Čas zařazení do fronty (čas na serveru)",
|
||||||
"authed_user": "Přihlášený uživatel",
|
"authed_user": "Přihlášený uživatel",
|
||||||
"ays": "Opravdu chcete pokračovat?",
|
"ays": "Opravdu chcete pokračovat?",
|
||||||
"ban_list_info": "Viz seznam zablokovaných IP níže: <b>síť (zbývající doba zablokování) - [akce]</b>.<br />IP adresy zařazené pro odblokování budou z aktivního seznamu odebrány během pár sekund.<br />Červeně označeny jsou položky z trvalých seznamů.",
|
"ban_list_info": "Seznam blokovaných IP adres je zobrazen níže: <b>síť (zbývající čas blokování) - [akce]</b>.<br />IP adresy zařazené pro odblokování budou z aktivního seznamu odebrány během několika sekund.<br />Červeně označené položky jsou pernamentní bloky z blacklistu.",
|
||||||
"change_logo": "Změnit logo",
|
"change_logo": "Změnit logo",
|
||||||
"logo_normal_label": "Normální",
|
"logo_normal_label": "Normální",
|
||||||
"logo_dark_label": "Inverzní pro tmavý režim",
|
"logo_dark_label": "Inverzní pro tmavý režim",
|
||||||
@@ -183,16 +183,16 @@
|
|||||||
"empty": "Žádné výsledky",
|
"empty": "Žádné výsledky",
|
||||||
"excludes": "Vyloučit tyto příjemce",
|
"excludes": "Vyloučit tyto příjemce",
|
||||||
"f2b_ban_time": "Doba blokování (s)",
|
"f2b_ban_time": "Doba blokování (s)",
|
||||||
"f2b_blacklist": "Sítě či hostitelé na seznamu zákazů",
|
"f2b_blacklist": "Sítě/hostitelé na blacklistu",
|
||||||
"f2b_filter": "Regex filtre",
|
"f2b_filter": "Regex filtre",
|
||||||
"f2b_list_info": "Sítě či hostitelé na seznamu zákazů mají vždy větší váhu než položky na seznamu povolení. <b>Každá úprava seznamu trvá pár sekund.</b>",
|
"f2b_list_info": "Síť nebo hostitelé na blacklistu mají vždy větší váhu než položky na whitelistu. <b>Každá úprava seznamů trvá pár sekund.</b>",
|
||||||
"f2b_max_attempts": "Max. pokusů",
|
"f2b_max_attempts": "Max. pokusů",
|
||||||
"f2b_netban_ipv4": "Rozsah IPv4 podsítě k zablokování (8-32)",
|
"f2b_netban_ipv4": "Rozsah IPv4 podsítě k zablokování (8-32)",
|
||||||
"f2b_netban_ipv6": "Rozsah IPv6 podsítě k zablokování (8-128)",
|
"f2b_netban_ipv6": "Rozsah IPv6 podsítě k zablokování (8-128)",
|
||||||
"f2b_parameters": "Parametry automatického firewallu",
|
"f2b_parameters": "Parametry automatického firewallu",
|
||||||
"f2b_regex_info": "Záznamy které se berou v úvahu: SOGo, Postfix, Dovecot, PHP-FPM.",
|
"f2b_regex_info": "Záznamy které se berou v úvahu: SOGo, Postfix, Dovecot, PHP-FPM.",
|
||||||
"f2b_retry_window": "Časový horizont pro maximum pokusů (s)",
|
"f2b_retry_window": "Časový horizont pro maximum pokusů (s)",
|
||||||
"f2b_whitelist": "Sítě či hostitelé na seznamu povolení",
|
"f2b_whitelist": "Sítě/hostitelé na whitelistu",
|
||||||
"filter_table": "Tabulka filtrů",
|
"filter_table": "Tabulka filtrů",
|
||||||
"forwarding_hosts": "Předávající servery",
|
"forwarding_hosts": "Předávající servery",
|
||||||
"forwarding_hosts_add_hint": "Lze zadat IPv4/IPv6 adresy, sítě ve formátu CIDR, názvy serverů (budou převedeny na IP adresy) nebo názvy domén (budou převedeny na IP pomocí SPF záznamů, příp. MX záznamů).",
|
"forwarding_hosts_add_hint": "Lze zadat IPv4/IPv6 adresy, sítě ve formátu CIDR, názvy serverů (budou převedeny na IP adresy) nebo názvy domén (budou převedeny na IP pomocí SPF záznamů, příp. MX záznamů).",
|
||||||
@@ -304,7 +304,7 @@
|
|||||||
"rspamd_com_settings": "Název nastavení se vygeneruje automaticky, viz ukázky nastavení níže. Více informací viz <a href=\"https://rspamd.com/doc/configuration/settings.html#settings-structure\" target=\"_blank\">Rspamd dokumentace</a>",
|
"rspamd_com_settings": "Název nastavení se vygeneruje automaticky, viz ukázky nastavení níže. Více informací viz <a href=\"https://rspamd.com/doc/configuration/settings.html#settings-structure\" target=\"_blank\">Rspamd dokumentace</a>",
|
||||||
"rspamd_global_filters": "Mapa globálních filtrů",
|
"rspamd_global_filters": "Mapa globálních filtrů",
|
||||||
"rspamd_global_filters_agree": "Budu opatrný!",
|
"rspamd_global_filters_agree": "Budu opatrný!",
|
||||||
"rspamd_global_filters_info": "Mapa globálních filtrů obsahuje různé seznamy povolených a zakázaných serverů",
|
"rspamd_global_filters_info": "Mapa globálních filtrů obsahuje jiné globální black- a whitelisty.",
|
||||||
"rspamd_global_filters_regex": "Názvy stačí k vysvětlení. Položky musejí obsahovat jen platné regulární výrazy ve tvaru \"/vyraz/parametry\" (e.g. <code>/.+@domena\\.tld/i</code>).<br>\n Každý výraz bude podroben základní kontrole, přesto je možné Rspamd 'rozbít', nebude-li syntax zcela korektní.<br>\n Rspamd se pokusí po každé změně načíst mapu znovu. V případě potíží <a href=\"\" data-toggle=\"modal\" data-container=\"rspamd-mailcow\" data-target=\"#RestartContainer\">restartujte Rspamd</a>, aby se konfigurace načetla explicitně.",
|
"rspamd_global_filters_regex": "Názvy stačí k vysvětlení. Položky musejí obsahovat jen platné regulární výrazy ve tvaru \"/vyraz/parametry\" (e.g. <code>/.+@domena\\.tld/i</code>).<br>\n Každý výraz bude podroben základní kontrole, přesto je možné Rspamd 'rozbít', nebude-li syntax zcela korektní.<br>\n Rspamd se pokusí po každé změně načíst mapu znovu. V případě potíží <a href=\"\" data-toggle=\"modal\" data-container=\"rspamd-mailcow\" data-target=\"#RestartContainer\">restartujte Rspamd</a>, aby se konfigurace načetla explicitně.",
|
||||||
"rspamd_settings_map": "Nastavení Rspamd",
|
"rspamd_settings_map": "Nastavení Rspamd",
|
||||||
"sal_level": "Úroveň 'Moo'",
|
"sal_level": "Úroveň 'Moo'",
|
||||||
@@ -498,7 +498,7 @@
|
|||||||
"pushover_token": "Token služby Pushover nemá správný formát",
|
"pushover_token": "Token služby Pushover nemá správný formát",
|
||||||
"quota_not_0_not_numeric": "Kvóta musí být číslo >= 0",
|
"quota_not_0_not_numeric": "Kvóta musí být číslo >= 0",
|
||||||
"recipient_map_entry_exists": "Položka mapy příjemců \"%s\" již existuje",
|
"recipient_map_entry_exists": "Položka mapy příjemců \"%s\" již existuje",
|
||||||
"redis_error": "Chyba Redis: %s",
|
"valkey_error": "Chyba Valkey: %s",
|
||||||
"relayhost_invalid": "Položky %s je neplatná",
|
"relayhost_invalid": "Položky %s je neplatná",
|
||||||
"release_send_failed": "Zprávu nelze propustit: %s",
|
"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.",
|
"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)",
|
"history_all_servers": "Záznam (všechny servery)",
|
||||||
"in_memory_logs": "Logy v paměti",
|
"in_memory_logs": "Logy v paměti",
|
||||||
"last_modified": "Naposledy změněn",
|
"last_modified": "Naposledy změněn",
|
||||||
"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>",
|
"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>",
|
||||||
"login_time": "Čas",
|
"login_time": "Čas",
|
||||||
"logs": "Logy",
|
"logs": "Logy",
|
||||||
"online_users": "Uživatelů online",
|
"online_users": "Uživatelů online",
|
||||||
@@ -733,7 +733,7 @@
|
|||||||
"sogo_visible_info": "Tato volba určuje objekty, jež lze zobrazit v SOGo (sdílené nebo nesdílené aliasy, jež ukazuje alespoň na jednu schránku).",
|
"sogo_visible_info": "Tato volba určuje objekty, jež lze zobrazit v SOGo (sdílené nebo nesdílené aliasy, jež ukazuje alespoň na jednu schránku).",
|
||||||
"spam_alias": "Vytvořit nebo změnit dočasné aliasy",
|
"spam_alias": "Vytvořit nebo změnit dočasné aliasy",
|
||||||
"spam_filter": "Spam filtr",
|
"spam_filter": "Spam filtr",
|
||||||
"spam_policy": "Přidat nebo odebrat položky seznamu",
|
"spam_policy": "Přidat nebo odebrat položky whitelistu/blacklistu",
|
||||||
"spam_score": "Nastavte vlastní skóre spamu",
|
"spam_score": "Nastavte vlastní skóre spamu",
|
||||||
"subfolder2": "Synchronizace do podsložky v cílovém umístění<br><small>(prázdné = nepoužívat podsložku)</small>",
|
"subfolder2": "Synchronizace do podsložky v cílovém umístění<br><small>(prázdné = nepoužívat podsložku)</small>",
|
||||||
"syncjob": "Upravit synchronizační úlohu",
|
"syncjob": "Upravit synchronizační úlohu",
|
||||||
@@ -883,7 +883,7 @@
|
|||||||
"bcc": "BCC",
|
"bcc": "BCC",
|
||||||
"bcc_destination": "Cíl kopie",
|
"bcc_destination": "Cíl kopie",
|
||||||
"bcc_destinations": "Cíl kopií",
|
"bcc_destinations": "Cíl kopií",
|
||||||
"bcc_info": "Skrytá kopie (mapa BCC) se používá pro tiché předávání kopií všech zpráv na jinou adresu. Mapa příjemců se použije, funguje-li je místní cíl jako adresát zprávy. Totéž platí pro mapy odesílatelů.<br/>\n Místní cíl se nedozví, selže-li doručení na cíl BCC.",
|
"bcc_info": "<br/>Skrytá kopie (mapa BCC) se používá pro tiché předávání kopií všech zpráv na jinou adresu. Mapa příjemců se použije, funguje-li je místní cíl jako adresát zprávy. Totéž platí pro mapy odesílatelů.<br/>\n Místní cíl se nedozví, selže-li doručení na cíl BCC.",
|
||||||
"bcc_local_dest": "Týká se",
|
"bcc_local_dest": "Týká se",
|
||||||
"bcc_map": "Skrytá kopie",
|
"bcc_map": "Skrytá kopie",
|
||||||
"bcc_map_type": "Typ skryté kopie",
|
"bcc_map_type": "Typ skryté kopie",
|
||||||
@@ -1060,7 +1060,7 @@
|
|||||||
"notified": "Oznámeno",
|
"notified": "Oznámeno",
|
||||||
"qhandler_success": "Požadavek úspěšně přijat. Můžete nyní zavřít okno.",
|
"qhandler_success": "Požadavek úspěšně přijat. Můžete nyní zavřít okno.",
|
||||||
"qid": "Rspamd QID",
|
"qid": "Rspamd QID",
|
||||||
"qinfo": "Karanténa uloží do databáze odmítnutou poštu (odesílatel se <em>nedozví</em>, že pošta byla doručena) jakož i poštu, jež se jako kopie doručuje do složky Nevyžádaná pošta.\n <br>\"Naučit jako spam a smazat\" předá zprávu systému k naučení bayesiánskou analýzou jako spam a současně stanoví fuzzy hashe pro odmítání podobných zpráv v budoucnosti.\n <br> Vezměte na vědomí, že učení více zpráv může být podle výkonnosti systému zabrat více času. <br> Položky na seznamu zákazů jsou z karantény vyloučeny.",
|
"qinfo": "Karanténní systém uloží odmítnutou poštu do databáze (odesílatel se <em>nedozví</em>, že pošta byla doručena) jakož i pošta, která bude jako kopie doručena do složky Nevyžádaná pošta. \r\n<br>\"Naučit jako spam a smazat\" naučí zprávu jako spam přes Bayesian theorem a současně vypočítá fuzzy hashes pro odmítnutí podobných zpráv v budoucnosti. \r\n<br> Prosím, berte na vědomí, že naučení více zpráv může být - záleží na vašem systému - časově náročné . <br> Položky na černé listině jsou z karantény vyloučeny.",
|
||||||
"qitem": "Položka v karanténě",
|
"qitem": "Položka v karanténě",
|
||||||
"quarantine": "Karanténa",
|
"quarantine": "Karanténa",
|
||||||
"quick_actions": "Akce",
|
"quick_actions": "Akce",
|
||||||
@@ -1347,12 +1347,12 @@
|
|||||||
"sogo_profile_reset": "Resetovat profil SOGo",
|
"sogo_profile_reset": "Resetovat profil SOGo",
|
||||||
"sogo_profile_reset_help": "Tato volba odstraní uživatelský profil SOGo a <b>nenávratně vymaže všechna data</b>.",
|
"sogo_profile_reset_help": "Tato volba odstraní uživatelský profil SOGo a <b>nenávratně vymaže všechna data</b>.",
|
||||||
"sogo_profile_reset_now": "Resetovat profil",
|
"sogo_profile_reset_now": "Resetovat profil",
|
||||||
"spam_aliases": "Spam aliasy",
|
"spam_aliases": "Dočasné e-mailové aliasy",
|
||||||
"spam_score_reset": "Obnovit výchozí nastavení serveru",
|
"spam_score_reset": "Obnovit výchozí nastavení serveru",
|
||||||
"spamfilter": "Filtr spamu",
|
"spamfilter": "Filtr spamu",
|
||||||
"spamfilter_behavior": "Hodnocení",
|
"spamfilter_behavior": "Hodnocení",
|
||||||
"spamfilter_bl": "Seznam zákazů",
|
"spamfilter_bl": "Seznam zakázaných adres (blacklist)",
|
||||||
"spamfilter_bl_desc": "Zakázané emailové adresy budou <b>vždy</b> klasifikovány jako spam a odmítnuty. Odmítnutá pošta <b>se neukládá</b> do karantény. Lze použít zástupné znaky (*). Filtr se použije pouze na přímé aliasy (s jednou cílovou poštovní schránkou), s výjimkou doménových košů a samotné poštovní schránky.",
|
"spamfilter_bl_desc": "Zakázané emailové adresy budou <b>vždy</b> klasifikovány jako spam a odmítnuty. Odmítnutá pošta <b>nebude</b> uložena do karantény. Lze použít zástupné znaky (*). Filtr se použije pouze na přímé aliasy (s jednou cílovou poštovní schránkou), s výjimkou doménových košů a samotné poštovní schránky.",
|
||||||
"spamfilter_default_score": "Výchozí hodnoty",
|
"spamfilter_default_score": "Výchozí hodnoty",
|
||||||
"spamfilter_green": "Zelená: tato zpráva není spam",
|
"spamfilter_green": "Zelená: tato zpráva není spam",
|
||||||
"spamfilter_hint": "První hodnota představuje \"nízké spam skóre\" a druhá \"vysoké spam skóre\".",
|
"spamfilter_hint": "První hodnota představuje \"nízké spam skóre\" a druhá \"vysoké spam skóre\".",
|
||||||
@@ -1363,7 +1363,7 @@
|
|||||||
"spamfilter_table_empty": "Žádná data k zobrazení",
|
"spamfilter_table_empty": "Žádná data k zobrazení",
|
||||||
"spamfilter_table_remove": "smazat",
|
"spamfilter_table_remove": "smazat",
|
||||||
"spamfilter_table_rule": "Pravidlo",
|
"spamfilter_table_rule": "Pravidlo",
|
||||||
"spamfilter_wl": "Seznam povolení",
|
"spamfilter_wl": "Seznam povolených adres (whitelist)",
|
||||||
"spamfilter_wl_desc": "Povolené emailové adresy <b>nebudou nikdy klasifikovány jako spam</b>. Lze použít zástupné znaky (*). Filtr se použije pouze na přímé aliasy (s jednou cílovou mailovou schránkou), s výjimkou doménových košů a samotné mailové schránky.",
|
"spamfilter_wl_desc": "Povolené emailové adresy <b>nebudou nikdy klasifikovány jako spam</b>. Lze použít zástupné znaky (*). Filtr se použije pouze na přímé aliasy (s jednou cílovou mailovou schránkou), s výjimkou doménových košů a samotné mailové schránky.",
|
||||||
"spamfilter_yellow": "Žlutá: tato zpráva může být spam, bude označena jako spam a přesunuta do složky nevyžádané pošty",
|
"spamfilter_yellow": "Žlutá: tato zpráva může být spam, bude označena jako spam a přesunuta do složky nevyžádané pošty",
|
||||||
"status": "Stav",
|
"status": "Stav",
|
||||||
@@ -1407,10 +1407,7 @@
|
|||||||
"authentication": "Autentifikace",
|
"authentication": "Autentifikace",
|
||||||
"overview": "Přehled",
|
"overview": "Přehled",
|
||||||
"protocols": "Protokoly",
|
"protocols": "Protokoly",
|
||||||
"value": "Hodnota",
|
"value": "Hodnota"
|
||||||
"expire_never": "Nikdy nevyprší",
|
|
||||||
"forever": "Navždy",
|
|
||||||
"spam_aliases_info": "Spam alias je dočasná adresa, již lze použít k ochraně skutečných adres. <br>Případně lze nastavit také dobu platnosti, po níž je alias automaticky deaktivován, čímž se řeší případy zneužitých či odcizených adres."
|
|
||||||
},
|
},
|
||||||
"warning": {
|
"warning": {
|
||||||
"cannot_delete_self": "Nelze smazat právě přihlášeného uživatele",
|
"cannot_delete_self": "Nelze smazat právě přihlášeného uživatele",
|
||||||
|
|||||||
@@ -401,7 +401,7 @@
|
|||||||
"pushover_token": "Pushover-token har et forkert format",
|
"pushover_token": "Pushover-token har et forkert format",
|
||||||
"quota_not_0_not_numeric": "Kvoten skal være numerisk og >= 0",
|
"quota_not_0_not_numeric": "Kvoten skal være numerisk og >= 0",
|
||||||
"recipient_map_entry_exists": "En modtagerkortpost \"%s\" eksisterer",
|
"recipient_map_entry_exists": "En modtagerkortpost \"%s\" eksisterer",
|
||||||
"redis_error": "Redis fejl: %s",
|
"valkey_error": "Valkey fejl: %s",
|
||||||
"relayhost_invalid": "Kortindtastning %s er ugyldig",
|
"relayhost_invalid": "Kortindtastning %s er ugyldig",
|
||||||
"release_send_failed": "Beskeden kunne ikke frigives: %s",
|
"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.",
|
"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",
|
"external_logs": "Eksterne logfiler",
|
||||||
"history_all_servers": "Historie (alle servere)",
|
"history_all_servers": "Historie (alle servere)",
|
||||||
"in_memory_logs": "In-memory logs",
|
"in_memory_logs": "In-memory logs",
|
||||||
"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>",
|
"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>",
|
||||||
"logs": "Logs",
|
"logs": "Logs",
|
||||||
"restart_container": "Genstart",
|
"restart_container": "Genstart",
|
||||||
"started_on": "Startede den",
|
"started_on": "Startede den",
|
||||||
|
|||||||
@@ -514,7 +514,7 @@
|
|||||||
"quota_not_0_not_numeric": "Speicherplatz muss numerisch und >= 0 sein",
|
"quota_not_0_not_numeric": "Speicherplatz muss numerisch und >= 0 sein",
|
||||||
"recipient_map_entry_exists": "Eine Empfängerumschreibung für Objekt \"%s\" existiert bereits",
|
"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.",
|
"recovery_email_failed": "E-Mail zur Wiederherstellung konnte nicht gesendet werden. Bitte wenden Sie sich an Ihren Administrator.",
|
||||||
"redis_error": "Redis Fehler: %s",
|
"valkey_error": "Valkey Fehler: %s",
|
||||||
"relayhost_invalid": "Map-Eintrag %s ist ungültig",
|
"relayhost_invalid": "Map-Eintrag %s ist ungültig",
|
||||||
"release_send_failed": "Die Nachricht konnte nicht versendet werden: %s",
|
"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.",
|
"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)",
|
"history_all_servers": "History (alle Server)",
|
||||||
"in_memory_logs": "In-memory Logs",
|
"in_memory_logs": "In-memory Logs",
|
||||||
"last_modified": "Zuletzt geändert",
|
"last_modified": "Zuletzt geändert",
|
||||||
"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>",
|
"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>",
|
||||||
"login_time": "Zeit",
|
"login_time": "Zeit",
|
||||||
"logs": "Protokolle",
|
"logs": "Protokolle",
|
||||||
"memory": "Arbeitsspeicher",
|
"memory": "Arbeitsspeicher",
|
||||||
@@ -987,7 +987,7 @@
|
|||||||
"sogo_visible": "Alias Sichtbarkeit in SOGo",
|
"sogo_visible": "Alias Sichtbarkeit in SOGo",
|
||||||
"sogo_visible_n": "Alias in SOGo verbergen",
|
"sogo_visible_n": "Alias in SOGo verbergen",
|
||||||
"sogo_visible_y": "Alias in SOGo anzeigen",
|
"sogo_visible_y": "Alias in SOGo anzeigen",
|
||||||
"spam_aliases": "Spam-Alias",
|
"spam_aliases": "Temp. Alias",
|
||||||
"stats": "Statistik",
|
"stats": "Statistik",
|
||||||
"status": "Status",
|
"status": "Status",
|
||||||
"sync_jobs": "Synchronisationen",
|
"sync_jobs": "Synchronisationen",
|
||||||
@@ -1281,9 +1281,7 @@
|
|||||||
"encryption": "Verschlüsselung",
|
"encryption": "Verschlüsselung",
|
||||||
"excludes": "Ausschlüsse",
|
"excludes": "Ausschlüsse",
|
||||||
"expire_in": "Ungültig in",
|
"expire_in": "Ungültig in",
|
||||||
"expire_never": "Niemals ungültig",
|
|
||||||
"fido2_webauthn": "FIDO2/WebAuthn",
|
"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.",
|
"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",
|
"from": "von",
|
||||||
"generate": "generieren",
|
"generate": "generieren",
|
||||||
@@ -1348,8 +1346,7 @@
|
|||||||
"sogo_profile_reset": "SOGo-Profil zurücksetzen",
|
"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_help": "Das Profil wird inklusive <b>aller</b> Kalender- und Kontaktdaten <b>unwiederbringlich gelöscht</b>.",
|
||||||
"sogo_profile_reset_now": "Profil jetzt zurücksetzen",
|
"sogo_profile_reset_now": "Profil jetzt zurücksetzen",
|
||||||
"spam_aliases": "Spam E-Mail-Aliasse",
|
"spam_aliases": "Temporäre 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",
|
"spam_score_reset": "Auf Server-Standard zurücksetzen",
|
||||||
"spamfilter": "Spamfilter",
|
"spamfilter": "Spamfilter",
|
||||||
"spamfilter_behavior": "Bewertung",
|
"spamfilter_behavior": "Bewertung",
|
||||||
|
|||||||
@@ -514,7 +514,7 @@
|
|||||||
"quota_not_0_not_numeric": "Quota must be numeric and >= 0",
|
"quota_not_0_not_numeric": "Quota must be numeric and >= 0",
|
||||||
"recipient_map_entry_exists": "A Recipient map entry \"%s\" exists",
|
"recipient_map_entry_exists": "A Recipient map entry \"%s\" exists",
|
||||||
"recovery_email_failed": "Could not send a recovery email. Please contact your administrator.",
|
"recovery_email_failed": "Could not send a recovery email. Please contact your administrator.",
|
||||||
"redis_error": "Redis error: %s",
|
"valkey_error": "Valkey error: %s",
|
||||||
"relayhost_invalid": "Map entry %s is invalid",
|
"relayhost_invalid": "Map entry %s is invalid",
|
||||||
"release_send_failed": "Message could not be released: %s",
|
"release_send_failed": "Message could not be released: %s",
|
||||||
"required_data_missing": "Required data %s is missing",
|
"required_data_missing": "Required data %s is missing",
|
||||||
@@ -600,7 +600,7 @@
|
|||||||
"history_all_servers": "History (all servers)",
|
"history_all_servers": "History (all servers)",
|
||||||
"in_memory_logs": "In-memory logs",
|
"in_memory_logs": "In-memory logs",
|
||||||
"last_modified": "Last modified",
|
"last_modified": "Last modified",
|
||||||
"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>",
|
"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>",
|
||||||
"login_time": "Time",
|
"login_time": "Time",
|
||||||
"logs": "Logs",
|
"logs": "Logs",
|
||||||
"memory": "Memory",
|
"memory": "Memory",
|
||||||
@@ -1288,9 +1288,7 @@
|
|||||||
"encryption": "Encryption",
|
"encryption": "Encryption",
|
||||||
"excludes": "Excludes",
|
"excludes": "Excludes",
|
||||||
"expire_in": "Expire in",
|
"expire_in": "Expire in",
|
||||||
"expire_never": "Never Expire",
|
|
||||||
"fido2_webauthn": "FIDO2/WebAuthn",
|
"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.",
|
"force_pw_update": "You <b>must</b> set a new password to be able to access groupware related services.",
|
||||||
"from": "from",
|
"from": "from",
|
||||||
"generate": "generate",
|
"generate": "generate",
|
||||||
@@ -1357,8 +1355,7 @@
|
|||||||
"sogo_profile_reset": "Reset SOGo profile",
|
"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_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",
|
"sogo_profile_reset_now": "Reset profile now",
|
||||||
"spam_aliases": "Spam email aliases",
|
"spam_aliases": "Temporary 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",
|
"spam_score_reset": "Reset to server default",
|
||||||
"spamfilter": "Spam filter",
|
"spamfilter": "Spam filter",
|
||||||
"spamfilter_behavior": "Rating",
|
"spamfilter_behavior": "Rating",
|
||||||
|
|||||||
@@ -462,7 +462,7 @@
|
|||||||
"private_key_error": "Error en la llave privada: %s",
|
"private_key_error": "Error en la llave privada: %s",
|
||||||
"quota_not_0_not_numeric": "Cuota debe ser numérica y >= 0",
|
"quota_not_0_not_numeric": "Cuota debe ser numérica y >= 0",
|
||||||
"recipient_map_entry_exists": "Una regla de destinatario \"%s\" existe",
|
"recipient_map_entry_exists": "Una regla de destinatario \"%s\" existe",
|
||||||
"redis_error": "Redis error: %s",
|
"valkey_error": "Valkey error: %s",
|
||||||
"relayhost_invalid": "relayhost %s es invalido",
|
"relayhost_invalid": "relayhost %s es invalido",
|
||||||
"release_send_failed": "El mensaje no pudo ser liberado: %s",
|
"release_send_failed": "El mensaje no pudo ser liberado: %s",
|
||||||
"rl_timeframe": "Marco de tiempo del límite de velocidad esta incorrecto",
|
"rl_timeframe": "Marco de tiempo del límite de velocidad esta incorrecto",
|
||||||
@@ -548,7 +548,7 @@
|
|||||||
"disk_usage": "Utilización de disco",
|
"disk_usage": "Utilización de disco",
|
||||||
"external_logs": "Logs externos",
|
"external_logs": "Logs externos",
|
||||||
"in_memory_logs": "Logs en memoria",
|
"in_memory_logs": "Logs en memoria",
|
||||||
"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>",
|
"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>",
|
||||||
"logs": "Logs",
|
"logs": "Logs",
|
||||||
"restart_container": "Reiniciar",
|
"restart_container": "Reiniciar",
|
||||||
"docs": "Docs",
|
"docs": "Docs",
|
||||||
@@ -1084,7 +1084,6 @@
|
|||||||
"aliases_send_as_all": "No verificar permisos del remitente para los siguientes dominios (y sus aliases)",
|
"aliases_send_as_all": "No verificar permisos del remitente para los siguientes dominios (y sus aliases)",
|
||||||
"change_password": "Cambiar contraseña",
|
"change_password": "Cambiar contraseña",
|
||||||
"create_syncjob": "Crear nuevo trabajo de sincronización",
|
"create_syncjob": "Crear nuevo trabajo de sincronización",
|
||||||
"created_on": "Creado",
|
|
||||||
"daily": "Cada día",
|
"daily": "Cada día",
|
||||||
"day": "Día",
|
"day": "Día",
|
||||||
"description": "Descripción",
|
"description": "Descripción",
|
||||||
@@ -1096,9 +1095,6 @@
|
|||||||
"edit": "Editar",
|
"edit": "Editar",
|
||||||
"encryption": "Cifrado",
|
"encryption": "Cifrado",
|
||||||
"excludes": "Excluye",
|
"excludes": "Excluye",
|
||||||
"expire_in": "Expirará en",
|
|
||||||
"expire_never": "Nunca expirará",
|
|
||||||
"forever": "Siempre",
|
|
||||||
"hour": "Hora",
|
"hour": "Hora",
|
||||||
"hourly": "Cada hora",
|
"hourly": "Cada hora",
|
||||||
"hours": "Horas",
|
"hours": "Horas",
|
||||||
@@ -1119,8 +1115,7 @@
|
|||||||
"shared_aliases": "Alias compartidos",
|
"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.",
|
"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",
|
"sogo_profile_reset": "Resetear perfil SOGo",
|
||||||
"spam_aliases": "Alias de email de spam",
|
"spam_aliases": "Alias de email temporales",
|
||||||
"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": "Filtro anti-spam",
|
||||||
"spamfilter_behavior": "Clasificación",
|
"spamfilter_behavior": "Clasificación",
|
||||||
"spamfilter_bl": "Lista negra",
|
"spamfilter_bl": "Lista negra",
|
||||||
|
|||||||
@@ -344,7 +344,7 @@
|
|||||||
"private_key_error": "Yksityisen avaimen virhe: %s",
|
"private_key_error": "Yksityisen avaimen virhe: %s",
|
||||||
"quota_not_0_not_numeric": "Kiintiön on oltava numeerinen ja >= 0",
|
"quota_not_0_not_numeric": "Kiintiön on oltava numeerinen ja >= 0",
|
||||||
"recipient_map_entry_exists": "Vastaanottajan kartta merkintä \"%s\" on olemassa",
|
"recipient_map_entry_exists": "Vastaanottajan kartta merkintä \"%s\" on olemassa",
|
||||||
"redis_error": "Redis virhe: %s",
|
"valkey_error": "Valkey virhe: %s",
|
||||||
"relayhost_invalid": "Osoite %s on väärin",
|
"relayhost_invalid": "Osoite %s on väärin",
|
||||||
"release_send_failed": "Viestiä ei voitu vapauttaa: %s",
|
"release_send_failed": "Viestiä ei voitu vapauttaa: %s",
|
||||||
"resource_invalid": "Resurssin nimi %s on virheellinen",
|
"resource_invalid": "Resurssin nimi %s on virheellinen",
|
||||||
@@ -380,7 +380,7 @@
|
|||||||
"disk_usage": "Levyn käyttö",
|
"disk_usage": "Levyn käyttö",
|
||||||
"external_logs": "Ulkoiset loki",
|
"external_logs": "Ulkoiset loki",
|
||||||
"in_memory_logs": "Muistissa olevat lokit",
|
"in_memory_logs": "Muistissa olevat lokit",
|
||||||
"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>",
|
"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>",
|
||||||
"logs": "Logit tausta palveluista",
|
"logs": "Logit tausta palveluista",
|
||||||
"restart_container": "Uudelleen käynnistä",
|
"restart_container": "Uudelleen käynnistä",
|
||||||
"docs": "Docs",
|
"docs": "Docs",
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
"quarantine_notification": "Modifier la notification de quarantaine",
|
"quarantine_notification": "Modifier la notification de quarantaine",
|
||||||
"quarantine_category": "Modifier la catégorie de la notification de quarantaine",
|
"quarantine_category": "Modifier la catégorie de la notification de quarantaine",
|
||||||
"ratelimit": "Limite d'envoi",
|
"ratelimit": "Limite d'envoi",
|
||||||
"recipient_maps": "Cartes des destinataires",
|
"recipient_maps": "Cartes destinataire",
|
||||||
"smtp_ip_access": "Changer les hôtes autorisés pour SMTP",
|
"smtp_ip_access": "Changer les hôtes autorisés pour SMTP",
|
||||||
"sogo_access": "Autoriser la gestion des accès à SOGo",
|
"sogo_access": "Autoriser la gestion des accès à SOGo",
|
||||||
"sogo_profile_reset": "Réinitialiser le profil SOGo",
|
"sogo_profile_reset": "Réinitialiser le profil SOGo",
|
||||||
@@ -109,9 +109,7 @@
|
|||||||
"bcc_dest_format": "La destination Cci doit être une seule adresse de courriel valide.<br>Si vous avez besoin d'envoyer une copie à plusieurs adresses, créez un alias et utilisez-le ici.",
|
"bcc_dest_format": "La destination Cci doit être une seule adresse de courriel valide.<br>Si vous avez besoin d'envoyer une copie à plusieurs adresses, créez un alias et utilisez-le ici.",
|
||||||
"tags": "Etiquettes",
|
"tags": "Etiquettes",
|
||||||
"app_passwd_protocols": "Protocoles autorisés pour le mot de passe de l'application",
|
"app_passwd_protocols": "Protocoles autorisés pour le mot de passe de l'application",
|
||||||
"dry": "Simuler la synchronisation",
|
"dry": "Simuler la synchronisation"
|
||||||
"internal": "Interne",
|
|
||||||
"internal_info": "Les alias internes sont accessibles uniquement depuis le domaine ou les alias du domaine."
|
|
||||||
},
|
},
|
||||||
"admin": {
|
"admin": {
|
||||||
"access": "Accès",
|
"access": "Accès",
|
||||||
@@ -409,9 +407,7 @@
|
|||||||
"iam_host": "Hôte",
|
"iam_host": "Hôte",
|
||||||
"iam_host_info": "Saisissez un ou plusieurs hôtes LDAP, séparés par des virgules.",
|
"iam_host_info": "Saisissez un ou plusieurs hôtes LDAP, séparés par des virgules.",
|
||||||
"iam_import_users": "Importer des utilisateurs",
|
"iam_import_users": "Importer des utilisateurs",
|
||||||
"filter": "Filtrer",
|
"filter": "Filtrer"
|
||||||
"needs_restart": "nécessite un redémarrage",
|
|
||||||
"iam": "Fournisseur d'identité"
|
|
||||||
},
|
},
|
||||||
"danger": {
|
"danger": {
|
||||||
"access_denied": "Accès refusé ou données de formulaire non valides",
|
"access_denied": "Accès refusé ou données de formulaire non valides",
|
||||||
@@ -445,7 +441,7 @@
|
|||||||
"global_filter_write_error": "Impossible d’écrire le fichier de filtre : %s",
|
"global_filter_write_error": "Impossible d’écrire le fichier de filtre : %s",
|
||||||
"global_map_invalid": "ID de carte globale %s non valide",
|
"global_map_invalid": "ID de carte globale %s non valide",
|
||||||
"global_map_write_error": "Impossible d’écrire l’ID de la carte globale %s : %s",
|
"global_map_write_error": "Impossible d’écrire l’ID de la carte globale %s : %s",
|
||||||
"goto_empty": "Une adresse alias doit contenir au moins une adresse 'goto' valide",
|
"goto_empty": "Une adresse alias doit contenir au moins une adresse 'goto'valide",
|
||||||
"goto_invalid": "Adresse Goto %s non valide",
|
"goto_invalid": "Adresse Goto %s non valide",
|
||||||
"ham_learn_error": "Erreur d'apprentissage Ham : %s",
|
"ham_learn_error": "Erreur d'apprentissage Ham : %s",
|
||||||
"imagick_exception": "Erreur : Exception Imagick lors de la lecture de l’image",
|
"imagick_exception": "Erreur : Exception Imagick lors de la lecture de l’image",
|
||||||
@@ -497,7 +493,7 @@
|
|||||||
"pushover_token": "Le jeton Pushover a un mauvais format",
|
"pushover_token": "Le jeton Pushover a un mauvais format",
|
||||||
"quota_not_0_not_numeric": "Le quota doit être numerique et >= 0",
|
"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",
|
"recipient_map_entry_exists": "Une entrée dans la carte du destinataire « %s » existe",
|
||||||
"redis_error": "Erreur Redis : %s",
|
"valkey_error": "Erreur Valkey : %s",
|
||||||
"relayhost_invalid": "La saisie de la carte %s est invalide",
|
"relayhost_invalid": "La saisie de la carte %s est invalide",
|
||||||
"release_send_failed": "Le message n’a pas pu être diffusé : %s",
|
"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.",
|
"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.",
|
||||||
@@ -552,11 +548,7 @@
|
|||||||
"generic_server_error": "Une erreur de serveur inattendue s'est produite. Veuillez contacter votre administrateur.",
|
"generic_server_error": "Une erreur de serveur inattendue s'est produite. Veuillez contacter votre administrateur.",
|
||||||
"authsource_in_use": "Le fournisseur d'identité ne peut pas être modifié ou supprimé car il est actuellement utilisé par un ou plusieurs utilisateurs.",
|
"authsource_in_use": "Le fournisseur d'identité ne peut pas être modifié ou supprimé car il est actuellement utilisé par un ou plusieurs utilisateurs.",
|
||||||
"iam_test_connection": "Échec de la connexion",
|
"iam_test_connection": "Échec de la connexion",
|
||||||
"required_data_missing": "La donnée requise %s est manquante",
|
"required_data_missing": "La donnée requise %s est manquante"
|
||||||
"max_age_invalid": "L'âge maximum %s est invalide",
|
|
||||||
"mode_invalid": "Le mode %s est invalide",
|
|
||||||
"mx_invalid": "L'enregistrement MX %s est invalide",
|
|
||||||
"version_invalid": "La version %s est invalide"
|
|
||||||
},
|
},
|
||||||
"debug": {
|
"debug": {
|
||||||
"chart_this_server": "Graphique (ce serveur)",
|
"chart_this_server": "Graphique (ce serveur)",
|
||||||
@@ -565,7 +557,7 @@
|
|||||||
"external_logs": "Logs externes",
|
"external_logs": "Logs externes",
|
||||||
"history_all_servers": "Historique (tous les serveurs)",
|
"history_all_servers": "Historique (tous les serveurs)",
|
||||||
"in_memory_logs": "Logs En-mémoire",
|
"in_memory_logs": "Logs En-mémoire",
|
||||||
"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>",
|
"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>",
|
||||||
"logs": "Logs",
|
"logs": "Logs",
|
||||||
"restart_container": "Redémarrer",
|
"restart_container": "Redémarrer",
|
||||||
"docs": "Docs",
|
"docs": "Docs",
|
||||||
@@ -701,7 +693,7 @@
|
|||||||
"spam_score": "Définir un score spam personnalisé",
|
"spam_score": "Définir un score spam personnalisé",
|
||||||
"subfolder2": "Synchronisation dans le sous-dossier sur la destination<br><small>(vide = ne pas utiliser de sous-dossier)</small>",
|
"subfolder2": "Synchronisation dans le sous-dossier sur la destination<br><small>(vide = ne pas utiliser de sous-dossier)</small>",
|
||||||
"syncjob": "Modifier la tâche de synchronisation",
|
"syncjob": "Modifier la tâche de synchronisation",
|
||||||
"target_address": "Adresse(s) Goto <small>(séparé(s) par des virgules)</small>",
|
"target_address": "Adresse(s) Goto<small>(séparé(s) par des virgules)</small>",
|
||||||
"target_domain": "Domaine cible",
|
"target_domain": "Domaine cible",
|
||||||
"timeout1": "Délai de connexion à l’hôte distant",
|
"timeout1": "Délai de connexion à l’hôte distant",
|
||||||
"timeout2": "Délai de connexion à l’hôte local",
|
"timeout2": "Délai de connexion à l’hôte local",
|
||||||
@@ -742,20 +734,7 @@
|
|||||||
"mailbox_rename_alias": "Créer un alias automatiquement",
|
"mailbox_rename_alias": "Créer un alias automatiquement",
|
||||||
"sogo_access": "Redirection directe vers SOGo",
|
"sogo_access": "Redirection directe vers SOGo",
|
||||||
"pushover": "Pushover",
|
"pushover": "Pushover",
|
||||||
"pushover_sound": "Son",
|
"pushover_sound": "Son"
|
||||||
"internal": "Interne",
|
|
||||||
"internal_info": "Les alias internes sont accessibles uniquement depuis le domaine ou les alias du domaine.",
|
|
||||||
"mta_sts": "MTA-STS",
|
|
||||||
"mta_sts_version": "Version",
|
|
||||||
"mta_sts_version_info": "Défini la version du standard MTA-STS – actuellement seul <code>STSv1</code> est valide.",
|
|
||||||
"mta_sts_mode": "Mode",
|
|
||||||
"mta_sts_max_age": "Âge maximum",
|
|
||||||
"mta_sts_mx": "Serveur MX",
|
|
||||||
"mta_sts_mx_notice": "Plusieurs serveurs MX peuvent être spécifiés (séparés par des virgules).",
|
|
||||||
"mta_sts_info": "<a href='https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol#SMTP_MTA_Strict_Transport_Security' target='_blank'>MTA-STS</a> est un standard qui oblige la délivrance des courriels entre les serveurs de courriels à utiliser TLS avec des certificats valides. <br>Il est utilisé quand <a target='_blank' href='https://en.wikipedia.org/wiki/DNS-based_Authentication_of_Named_Entities'>DANE</a> n'est pas possible à cause d'un manque ou d'un non support de DNSSEC.<br><b>Note</b> : Si le domaine du destinataire supporte DANE avec DNSSEC, DANE est <b>toujours</b> préféré – MTA-STS sert seulement en secours.",
|
|
||||||
"mta_sts_mode_info": "Il y a trois modes parmi lesquels choisir :<ul><li><em>testing</em> – la politique est seulement surveillée, les violations n'ont pas d'impact.</li><li><em>enforce</em> – la politique est appliquée strictement, les connexions sans TLS valide sont rejetées.</li><li><em>none</em> – la politique est publiée mais non appliquée.</li></ul>",
|
|
||||||
"mta_sts_max_age_info": "Durée en secondes pendant laquelle les serveurs de courriel peuvent mettre en cache cette politique avant de revérifier.",
|
|
||||||
"mta_sts_mx_info": "Autoriser l'envoi uniquement aux noms d'hôtes des serveurs de courriels indiqués explicitement ; le MTA émetteur vérifie si le nom d'hôte DNS du MX correspond à la liste de la politique, et autorise la délivrance seulement avec un certificat TLS valide (protège contre le MITM)."
|
|
||||||
},
|
},
|
||||||
"footer": {
|
"footer": {
|
||||||
"cancel": "Annuler",
|
"cancel": "Annuler",
|
||||||
@@ -810,8 +789,7 @@
|
|||||||
"login_linkstext": "L'identifiant n'est pas correct ?",
|
"login_linkstext": "L'identifiant n'est pas correct ?",
|
||||||
"login_usertext": "Se connecter en tant qu'utilisateur",
|
"login_usertext": "Se connecter en tant qu'utilisateur",
|
||||||
"login_domainadmintext": "Se connecter en tant qu'administrateur du domaine",
|
"login_domainadmintext": "Se connecter en tant qu'administrateur du domaine",
|
||||||
"login_admintext": "Se connecter en tant qu'administrateur",
|
"login_admintext": "Se connecter en tant qu'administrateur"
|
||||||
"email": "Adresse de courriel"
|
|
||||||
},
|
},
|
||||||
"mailbox": {
|
"mailbox": {
|
||||||
"action": "Action",
|
"action": "Action",
|
||||||
@@ -918,7 +896,7 @@
|
|||||||
"recipient_map_new_info": "La destination de la carte du destinataire doit être une adresse de courriel valide ou un nom de domaine.",
|
"recipient_map_new_info": "La destination de la carte du destinataire doit être une adresse de courriel valide ou un nom de domaine.",
|
||||||
"recipient_map_old": "Destinataire original",
|
"recipient_map_old": "Destinataire original",
|
||||||
"recipient_map_old_info": "La destination originale des cartes des destinataires doit être une adresse de courriel valide ou un nom de domaine.",
|
"recipient_map_old_info": "La destination originale des cartes des destinataires doit être une adresse de courriel valide ou un nom de domaine.",
|
||||||
"recipient_maps": "Cartes des destinataires",
|
"recipient_maps": "Cartes des bénéficiaires",
|
||||||
"relay_all": "Relayer tous les destinataires",
|
"relay_all": "Relayer tous les destinataires",
|
||||||
"remove": "Supprimer",
|
"remove": "Supprimer",
|
||||||
"resources": "Ressources",
|
"resources": "Ressources",
|
||||||
@@ -987,8 +965,7 @@
|
|||||||
"syncjob_check_log": "Vérifier le journal",
|
"syncjob_check_log": "Vérifier le journal",
|
||||||
"recipient": "Destinataire",
|
"recipient": "Destinataire",
|
||||||
"open_logs": "Afficher les journaux",
|
"open_logs": "Afficher les journaux",
|
||||||
"iam": "Fournisseur d'identité",
|
"iam": "Fournisseur d'identité"
|
||||||
"internal": "Interne"
|
|
||||||
},
|
},
|
||||||
"oauth2": {
|
"oauth2": {
|
||||||
"access_denied": "Veuillez vous connecter en tant que propriétaire de la boîte de réception pour accorder l’accès via Oauth2.",
|
"access_denied": "Veuillez vous connecter en tant que propriétaire de la boîte de réception pour accorder l’accès via Oauth2.",
|
||||||
@@ -1245,7 +1222,7 @@
|
|||||||
"email_and_dav": "Courriel, calendriers et contacts",
|
"email_and_dav": "Courriel, calendriers et contacts",
|
||||||
"encryption": "Chiffrement",
|
"encryption": "Chiffrement",
|
||||||
"excludes": "Exclus",
|
"excludes": "Exclus",
|
||||||
"expire_in": "Expirer dans",
|
"expire_in": "Expire dans",
|
||||||
"force_pw_update": "Vous <b>devez</b> définir un nouveau mot de passe pour pouvoir accéder aux services liés aux logiciels de groupe.",
|
"force_pw_update": "Vous <b>devez</b> définir un nouveau mot de passe pour pouvoir accéder aux services liés aux logiciels de groupe.",
|
||||||
"generate": "générer",
|
"generate": "générer",
|
||||||
"hour": "heure",
|
"hour": "heure",
|
||||||
@@ -1373,12 +1350,7 @@
|
|||||||
"mailbox_general": "Général",
|
"mailbox_general": "Général",
|
||||||
"mailbox_settings": "Paramètres",
|
"mailbox_settings": "Paramètres",
|
||||||
"tfa_info": "L'authentification à deux facteurs permet de protéger votre compte. Si vous l'activez, vous aurez besoin de mots de passe d'application pour vous connecter à des applications ou des services qui ne prennent pas en charge l'authentification à deux facteurs (par exemple les clients e-mails).",
|
"tfa_info": "L'authentification à deux facteurs permet de protéger votre compte. Si vous l'activez, vous aurez besoin de mots de passe d'application pour vous connecter à des applications ou des services qui ne prennent pas en charge l'authentification à deux facteurs (par exemple les clients e-mails).",
|
||||||
"overview": "Vue d'ensemble",
|
"overview": "Vue d'ensemble"
|
||||||
"expire_never": "Ne jamais expirer",
|
|
||||||
"forever": "Pour toujours",
|
|
||||||
"spam_aliases_info": "Un alias de spam est une adresse de courriel temporaire qui peut être utilisée pour protéger les véritables adresses de courriel. <br> De manière optionnelle, une durée d'expiration peut être définie afin que l'alias soit automatiquement désactivé après la période définie, éliminant ainsi les adresses étant abusées ou ayant fuité.",
|
|
||||||
"authentication": "Authentification",
|
|
||||||
"protocols": "Protocoles"
|
|
||||||
},
|
},
|
||||||
"warning": {
|
"warning": {
|
||||||
"cannot_delete_self": "Impossible de supprimer l’utilisateur connecté",
|
"cannot_delete_self": "Impossible de supprimer l’utilisateur connecté",
|
||||||
|
|||||||
@@ -6,8 +6,7 @@
|
|||||||
"weeks": "Εβδομάδες",
|
"weeks": "Εβδομάδες",
|
||||||
"with_app_password": "με κωδικό εφαρμογής",
|
"with_app_password": "με κωδικό εφαρμογής",
|
||||||
"year": "χρόνος",
|
"year": "χρόνος",
|
||||||
"years": "χρόνια",
|
"years": "χρόνια"
|
||||||
"value": "Τιμή"
|
|
||||||
},
|
},
|
||||||
"warning": {
|
"warning": {
|
||||||
"cannot_delete_self": "Αδυναμία διαγραφής συνδεδεμένου χρήστη",
|
"cannot_delete_self": "Αδυναμία διαγραφής συνδεδεμένου χρήστη",
|
||||||
@@ -17,170 +16,5 @@
|
|||||||
"hash_not_found": "Η κατακερματισμένη τιμή (hash value) δεν βρέθηκε ή έχει είδη διαγραφεί.",
|
"hash_not_found": "Η κατακερματισμένη τιμή (hash value) δεν βρέθηκε ή έχει είδη διαγραφεί.",
|
||||||
"ip_invalid": "Παραλείφθηκε μη έγκυρη διεύθυνση IP: %s",
|
"ip_invalid": "Παραλείφθηκε μη έγκυρη διεύθυνση IP: %s",
|
||||||
"is_not_primary_alias": "Παραλείφθηκε μη πρωτεύον ψευδώνυμο %s"
|
"is_not_primary_alias": "Παραλείφθηκε μη πρωτεύον ψευδώνυμο %s"
|
||||||
},
|
|
||||||
"acl": {
|
|
||||||
"alias_domains": "Προσθήκη ψευδωνύμων τομέων",
|
|
||||||
"app_passwds": "Διαχείριση κωδικών εφαρμογής",
|
|
||||||
"bcc_maps": "χαρτογράφηση BCC",
|
|
||||||
"delimiter_action": "Ενέργεια οριοθέτη",
|
|
||||||
"domain_desc": "Αλλαγή περιγραφής τομέα",
|
|
||||||
"domain_relayhost": "Αλλαγή του διακομιστή αναμετάδοσης για ένα τομέα",
|
|
||||||
"eas_reset": "Επαναφορά συσκευών EAS",
|
|
||||||
"extend_sender_acl": "Να επιτρέπεται η επέκταση ACL του αποστολέα με εξωτερικές διευθύνσεις",
|
|
||||||
"filters": "Φίλτρα",
|
|
||||||
"login_as": "Είσοδος ως χρήστης e-mail",
|
|
||||||
"mailbox_relayhost": "Αλλαγή διακομιστή αναμετάδοσης για ένα γραμματοκιβώτιο",
|
|
||||||
"prohibited": "Απαγορεύεται από την ACL",
|
|
||||||
"protocol_access": "Αλλαγή πρόσβασης πρωτοκόλλου",
|
|
||||||
"pushover": "Pushover",
|
|
||||||
"pw_reset": "Επιτρέψτε την επαναφορά κωδικού πρόσβασης του χρήστη",
|
|
||||||
"quarantine": "Ενέργειες καραντίνας",
|
|
||||||
"quarantine_attachments": "Συνημμένα καραντίνας",
|
|
||||||
"quarantine_category": "Αλλαγή κατηγορίας ειδοποιήσεων καραντίνας",
|
|
||||||
"quarantine_notification": "Αλλαγή ειδοποιήσεων καραντίνας",
|
|
||||||
"ratelimit": "Όριο τιμής",
|
|
||||||
"recipient_maps": "Χάρτες παραληπτών",
|
|
||||||
"smtp_ip_access": "Αλλαγή επιτρεπόμενων διακομιστών SMTP",
|
|
||||||
"sogo_access": "Επιτρέψτε τη διαχείριση της πρόσβασης στο SOGo",
|
|
||||||
"sogo_profile_reset": "Επαναφορά του προφίλ SOGo",
|
|
||||||
"spam_alias": "Προσωρινά ψευδώνυμα",
|
|
||||||
"spam_policy": "Λίστα απορρίψεων/Λίστα επιτρεπόμενων",
|
|
||||||
"spam_score": "Βαθμολογία ανεπιθύμητης αλληλογραφίας",
|
|
||||||
"syncjobs": "Εργασίες συγχρονισμού",
|
|
||||||
"tls_policy": "Πολιτική TLS",
|
|
||||||
"unlimited_quota": "Απεριόριστο όριο για γραμματοκιβώτια"
|
|
||||||
},
|
|
||||||
"add": {
|
|
||||||
"activate_filter_warn": "Όλα τα άλλα φίλτρα θα απενεργοποιηθούν, όταν επιλεγεί η επιλογή \"ενεργό\".",
|
|
||||||
"active": "Ενεργό",
|
|
||||||
"add": "Προσθήκη",
|
|
||||||
"add_domain_only": "Προσθήκη μόνο του τομέα",
|
|
||||||
"add_domain_restart": "Προσθήκη του τομέα και επανεκκίνηση του SOGo",
|
|
||||||
"alias_address": "Διευθύνσεις ψευδωνύμων",
|
|
||||||
"alias_address_info": "<small>Πλήρης διεύθυνση(εις) e-mail ή @example.com, για να λαμβάνετε ΟΛΑ τα μηνύματα ενός τομέα (χωρισμένα με κόμα). <b>μόνο τομείς του mailcow</b>.</small>",
|
|
||||||
"alias_domain": "Ψευδώνυμο τομέα",
|
|
||||||
"alias_domain_info": "<small>Μόνο έγκυρα ονόματα τομέα (χωρισμένα με κόμα).</small>",
|
|
||||||
"app_name": "Όνομα εφαρμογής",
|
|
||||||
"app_password": "Προσθήκη κωδικού εφαρμογής",
|
|
||||||
"app_passwd_protocols": "Επιτρεπόμενα πρωτόκολλα για κωδικούς εφαρμογών",
|
|
||||||
"automap": "Αυτόματη αντιστοίχηση φακέλων (\"Απεσταλμένα μηνύματα\", \"Απεσταλμένα\" => \"Στάλθηκαν\" κ.τ.λ.)",
|
|
||||||
"backup_mx_options": "Επιλογές αναμετάδοσης",
|
|
||||||
"bcc_dest_format": "Η BCC διεύθυνση πρέπει να είναι μία και έγκυρη διεύθυνση e-mail.<br>Αν θέλετε να στείλετε αντίγραφα σε πολλούς παραλήπτες, δημιουργήστε ένα ψευδόνυμο για όλους και χρησιμοποιήστε το εδώ.",
|
|
||||||
"comment_info": "Τα προσωπικά σχόλια δεν είναι ορατά στον χρήστη. Τα δημόσια σχόλια εμφανίζονται ως tooltips.",
|
|
||||||
"custom_params": "Προσαρμοσμένες παράμετροι",
|
|
||||||
"custom_params_hint": "Σωστή σύνταξη: --param=xy, λάθος σύνταξη: --param xy",
|
|
||||||
"delete1": "Διαγραφή όταν ολοκληρωθεί",
|
|
||||||
"delete2": "Διαγραφή μηνυμάτων στον προορισμό που δεν βρίσκονται στην πηγή",
|
|
||||||
"delete2duplicates": "Διαγραφή διπλότυπων στον προορισμό",
|
|
||||||
"description": "Περιγραφή",
|
|
||||||
"destination": "Προορισμός",
|
|
||||||
"disable_login": "Απαγόρευση εισόδου (η εισερχόμενη αλληλογραφία εξακολουθεί να γίνεται δεκτή)",
|
|
||||||
"domain": "Τομέας",
|
|
||||||
"domain_matches_hostname": "Ο τομέας %s είναι ο ίδιος με το όνομα του διακομιστή",
|
|
||||||
"domain_quota_m": "Συνολικό όριο τομέα (MiB)",
|
|
||||||
"dry": "Προσομοίωση συγχρονισμού",
|
|
||||||
"enc_method": "Μέθοδος κρυπτογράφησης",
|
|
||||||
"exclude": "Εξαίρεση αντικειμένων (regex)",
|
|
||||||
"full_name": "Πλήρες όνομα",
|
|
||||||
"gal": "Κοινόχρηστη λίστα διευθύνσεων"
|
|
||||||
},
|
|
||||||
"danger": {
|
|
||||||
"unknown": "Παρουσιάστηκε κάποιο άγωνστο σφάλμα",
|
|
||||||
"unknown_tfa_method": "Άγνωστη μέθοδος TFA",
|
|
||||||
"unlimited_quota_acl": "Το απεριόριστο όριο απαγορεύεται από την ACL",
|
|
||||||
"username_invalid": "Το όνομα χρήστη %s δεν μπορεί να χρησιμοποιηθεί",
|
|
||||||
"validity_missing": "Παρακαλώ ορίστε μία περίοδο εγκυρότητας",
|
|
||||||
"value_missing": "Παρακαλώ συμπληρώστε όλα τα δεδομένα",
|
|
||||||
"version_invalid": "Η έκδοση %s δεν είναι έγκυρη",
|
|
||||||
"yotp_verification_failed": "Η επαλήθευση μέσω Yubico OTP απέτυχε: %s"
|
|
||||||
},
|
|
||||||
"datatables": {
|
|
||||||
"collapse_all": "Σύμπτυξη όλων",
|
|
||||||
"decimal": ".",
|
|
||||||
"emptyTable": "Δεν υπάρχουν εγγραφές",
|
|
||||||
"expand_all": "Επέκταση όλων",
|
|
||||||
"info": "Εμφανίζονται _START_ εώς _END_ από _TOTAL_ εγγραφές",
|
|
||||||
"infoEmpty": "Εμφανίζονται 0 εώς 0 από 0 εγγραφές",
|
|
||||||
"infoFiltered": "(φιλτραρισμένες από _MAX_ συνολικές εγγραφές)",
|
|
||||||
"thousands": ",",
|
|
||||||
"lengthMenu": "Εμφάνιση _MENU_ εγγραφών",
|
|
||||||
"loadingRecords": "Γίνεται φόρτωση...",
|
|
||||||
"processing": "Παρακαλώ περιμένετε...",
|
|
||||||
"search": "Αναζήτηση:",
|
|
||||||
"zeroRecords": "Δε βρέθηκαν εγγραφές",
|
|
||||||
"paginate": {
|
|
||||||
"first": "Πρώτη",
|
|
||||||
"last": "Τελευταία",
|
|
||||||
"next": "Επόμενη",
|
|
||||||
"previous": "Προηγούμενη"
|
|
||||||
},
|
|
||||||
"aria": {
|
|
||||||
"sortAscending": ": ενεργοποίηση αύξουσας ταξινόμησης",
|
|
||||||
"sortDescending": ": ενεργοποίηση φθίνουσας ταξινόμησης"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"debug": {
|
|
||||||
"architecture": "Αρχιτεκτονική",
|
|
||||||
"chart_this_server": "Γράφημα (αυτός ο διακομιστής)",
|
|
||||||
"containers_info": "Πληροφορίες για τον container",
|
|
||||||
"container_running": "Εκτελείται",
|
|
||||||
"container_disabled": "Ο container έχει σταματήσει ή απενεργοποιηθεί",
|
|
||||||
"container_stopped": "Σταματημένος",
|
|
||||||
"cores": "Πυρήνες",
|
|
||||||
"current_time": "Ώρα συστήματος",
|
|
||||||
"disk_usage": "Χρήση αποθ. χώρου",
|
|
||||||
"docs": "Έγγραφα",
|
|
||||||
"error_show_ip": "Δεν είναι δυνατή η επίλυση της δημόσιας IP διεύθυνσης",
|
|
||||||
"external_logs": "Εξωτερικά αρχεία καταγραφής",
|
|
||||||
"history_all_servers": "Ιστορικό (Όλοι οι διακομιστές)",
|
|
||||||
"in_memory_logs": "Αρχεία καταγραφής στη μνήμη",
|
|
||||||
"last_modified": "Τελευταία τροποποίηση",
|
|
||||||
"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.\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.\n <br>The in-memory log type should be used for debugging minor issues with containers.</p>\n <p><b>External logs</b> are collected via API of the given application.</p>\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": "Ώρα",
|
|
||||||
"logs": "Αρχεία καταγραφής",
|
|
||||||
"memory": "Μνήμη",
|
|
||||||
"online_users": "Συνδεδεμένοι χρήστες",
|
|
||||||
"restart_container": "Επανεκκίνηση",
|
|
||||||
"service": "Υπηρεσία",
|
|
||||||
"show_ip": "Εμφάνιση δημόσιας IP",
|
|
||||||
"size": "Μέγεθος",
|
|
||||||
"started_at": "Ξεκίνησε στις",
|
|
||||||
"started_on": "Ξεκίνησε στις",
|
|
||||||
"static_logs": "Στατικά αρχεία καταγραφής",
|
|
||||||
"success": "Επιτυχία",
|
|
||||||
"system_containers": "Σύστημα και Containers",
|
|
||||||
"timezone": "Ζώνη ώρας",
|
|
||||||
"uptime": "Χρόνος λειτουργίας",
|
|
||||||
"update_available": "Υπάρχει διαθέσιμη ενημέρωση",
|
|
||||||
"no_update_available": "Έχετε τη τελευταία έκδοση του συστήματος",
|
|
||||||
"update_failed": "Δεν ήταν δυνατός ο έλεγχος για ενημερώσεις",
|
|
||||||
"username": "Όνομα χρήστη",
|
|
||||||
"wip": "Currently Work in Progress"
|
|
||||||
},
|
|
||||||
"diagnostics": {
|
|
||||||
"cname_from_a": "Value derived from A/AAAA record. This is supported as long as the record points to the correct resource.",
|
|
||||||
"dns_records": "Εγγραφές DNS",
|
|
||||||
"dns_records_24hours": "Παρακαλώ σημειώστε ότι οι αλλαγές στο DNS μπορεί να χρειαστούν μέχρι 24 ώρες για να ενημερωθούν σωστά και να εμφανιστούν σε αυτή τη σελίδα. Ο σκοπός της είναι να δείτε πως μπορείτε να ρυθμίσετε σωστά τις εγγραφές DNS και να ελέγξετε αν είναι σωστές.",
|
|
||||||
"dns_records_data": "Σωστά δεδομένα",
|
|
||||||
"dns_records_docs": "Παρακαλώ συμβουλευτείτε επίσης <a target=\"_blank\" href=\"https://docs.mailcow.email/getstarted/prerequisite-dns\">την τεκμηρίωση</a>.",
|
|
||||||
"dns_records_name": "Όνομα",
|
|
||||||
"dns_records_status": "Τρέχουσα κατάσταση",
|
|
||||||
"dns_records_type": "Τύπος",
|
|
||||||
"optional": "Αυτή η εγγραφή είναι προαιρετική."
|
|
||||||
},
|
|
||||||
"edit": {
|
|
||||||
"acl": "ACL (Δικαίωμα)",
|
|
||||||
"active": "Ενεργό",
|
|
||||||
"admin": "Επεξεργασία διαχειριστή",
|
|
||||||
"advanced_settings": "Ρυθμίσεις για προχωρημένους",
|
|
||||||
"alias": "Επεξεργασία ψευδώνυμου",
|
|
||||||
"allow_from_smtp": "Επέτρεψε μόνο σε αυτές τις IPs να χρησιμοποιήσουν το <b>SMTP</b>",
|
|
||||||
"allow_from_smtp_info": "Αφήστε το κενό για να επιτρέψετε όλους τους αποστολείς.<br>IPv4/IPv6 διευθύνσεις και δίκτυα.",
|
|
||||||
"allowed_protocols": "Επιτρεπόμενα πρωτόκολλα για απ' ευθείας πρόσβαση από τους χρήστες (δεν επηρεάζει τα πρωτόκολλα κωδικών πρόσβασης εφαρμογής)",
|
|
||||||
"app_name": "Όνομα εφαρμογής",
|
|
||||||
"app_passwd": "Κωδικός πρόσβασης εφαρμογής",
|
|
||||||
"app_passwd_protocols": "Επιτρέπομενα πρωτόκολλα για τον κωδικό εφαρμογής",
|
|
||||||
"automap": "Αυτόματη αντιστοίχηση φακέλων (\"Απεσταλμένα μηνύματα\", \"Απεσταλμένα\" => \"Στάλθηκαν\" κ.τ.λ.)",
|
|
||||||
"backup_mx_options": "Επιλογές αναμετάδοσης"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -463,7 +463,7 @@
|
|||||||
"pushover_token": "Pushover token has a wrong format",
|
"pushover_token": "Pushover token has a wrong format",
|
||||||
"quota_not_0_not_numeric": "Lo spazio deve essere numerico e >= 0",
|
"quota_not_0_not_numeric": "Lo spazio deve essere numerico e >= 0",
|
||||||
"recipient_map_entry_exists": "A Recipient map entry \"%s\" exists",
|
"recipient_map_entry_exists": "A Recipient map entry \"%s\" exists",
|
||||||
"redis_error": "Redis error: %s",
|
"valkey_error": "Valkey error: %s",
|
||||||
"relayhost_invalid": "Map entry %s is invalid",
|
"relayhost_invalid": "Map entry %s is invalid",
|
||||||
"release_send_failed": "Message could not be released: %s",
|
"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.",
|
"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)",
|
"history_all_servers": "Cronologia (tutti i server)",
|
||||||
"in_memory_logs": "In-memory logs",
|
"in_memory_logs": "In-memory logs",
|
||||||
"last_modified": "Ultima modifica",
|
"last_modified": "Ultima modifica",
|
||||||
"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>",
|
"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>",
|
||||||
"login_time": "Orario",
|
"login_time": "Orario",
|
||||||
"logs": "Logs",
|
"logs": "Logs",
|
||||||
"online_users": "Utenti online",
|
"online_users": "Utenti online",
|
||||||
|
|||||||
@@ -456,7 +456,7 @@
|
|||||||
"quota_not_0_not_numeric": "クォータは数値で >= 0 である必要があります",
|
"quota_not_0_not_numeric": "クォータは数値で >= 0 である必要があります",
|
||||||
"recipient_map_entry_exists": "受信者マップエントリ \"%s\" が存在します",
|
"recipient_map_entry_exists": "受信者マップエントリ \"%s\" が存在します",
|
||||||
"recovery_email_failed": "リカバリーメールを送信できませんでした。管理者にお問い合わせください。",
|
"recovery_email_failed": "リカバリーメールを送信できませんでした。管理者にお問い合わせください。",
|
||||||
"redis_error": "Redisエラー: %s",
|
"valkey_error": "Valkeyエラー: %s",
|
||||||
"relayhost_invalid": "マップエントリ %s は無効です",
|
"relayhost_invalid": "マップエントリ %s は無効です",
|
||||||
"release_send_failed": "メッセージをリリースできませんでした: %s",
|
"release_send_failed": "メッセージをリリースできませんでした: %s",
|
||||||
"reset_f2b_regex": "正規表現フィルターをタイムリーにリセットできませんでした。再試行するか、数秒待ってからウェブサイトをリロードしてください。",
|
"reset_f2b_regex": "正規表現フィルターをタイムリーにリセットできませんでした。再試行するか、数秒待ってからウェブサイトをリロードしてください。",
|
||||||
@@ -540,7 +540,7 @@
|
|||||||
"history_all_servers": "履歴(すべてのサーバー)",
|
"history_all_servers": "履歴(すべてのサーバー)",
|
||||||
"in_memory_logs": "インメモリーログ",
|
"in_memory_logs": "インメモリーログ",
|
||||||
"last_modified": "最終更新日時",
|
"last_modified": "最終更新日時",
|
||||||
"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>",
|
"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>",
|
||||||
"login_time": "ログイン時間",
|
"login_time": "ログイン時間",
|
||||||
"logs": "ログ",
|
"logs": "ログ",
|
||||||
"memory": "メモリ",
|
"memory": "メモリ",
|
||||||
@@ -1187,7 +1187,6 @@
|
|||||||
"created_on": "作成日",
|
"created_on": "作成日",
|
||||||
"daily": "毎日",
|
"daily": "毎日",
|
||||||
"day": "日",
|
"day": "日",
|
||||||
"description": "説明",
|
|
||||||
"delete_ays": "削除プロセスを確認してください。",
|
"delete_ays": "削除プロセスを確認してください。",
|
||||||
"direct_aliases": "直接エイリアスアドレス",
|
"direct_aliases": "直接エイリアスアドレス",
|
||||||
"direct_aliases_desc": "直接エイリアスアドレスは、スパムフィルターおよびTLSポリシー設定の影響を受けます。",
|
"direct_aliases_desc": "直接エイリアスアドレスは、スパムフィルターおよびTLSポリシー設定の影響を受けます。",
|
||||||
@@ -1202,9 +1201,7 @@
|
|||||||
"encryption": "暗号化",
|
"encryption": "暗号化",
|
||||||
"excludes": "除外",
|
"excludes": "除外",
|
||||||
"expire_in": "有効期限まで",
|
"expire_in": "有効期限まで",
|
||||||
"expire_never": "有効期限なし",
|
|
||||||
"fido2_webauthn": "FIDO2/WebAuthn",
|
"fido2_webauthn": "FIDO2/WebAuthn",
|
||||||
"forever": "有効期限なし",
|
|
||||||
"force_pw_update": "グループウェア関連サービスにアクセスするには、新しいパスワードを<b>必ず</b>設定する必要があります。",
|
"force_pw_update": "グループウェア関連サービスにアクセスするには、新しいパスワードを<b>必ず</b>設定する必要があります。",
|
||||||
"from": "送信元",
|
"from": "送信元",
|
||||||
"generate": "生成",
|
"generate": "生成",
|
||||||
|
|||||||
@@ -437,7 +437,7 @@
|
|||||||
"pushover_token": "Pushover 토큰 포맷이 잘못되었습니다.",
|
"pushover_token": "Pushover 토큰 포맷이 잘못되었습니다.",
|
||||||
"quota_not_0_not_numeric": "할당량은 숫자이여야 하고 0보다 크거나 같아야 합니다.",
|
"quota_not_0_not_numeric": "할당량은 숫자이여야 하고 0보다 크거나 같아야 합니다.",
|
||||||
"recipient_map_entry_exists": "수신자 맵 항목 \"%s\"이 존재합니다",
|
"recipient_map_entry_exists": "수신자 맵 항목 \"%s\"이 존재합니다",
|
||||||
"redis_error": "Redis 에러: %s",
|
"valkey_error": "Valkey 에러: %s",
|
||||||
"relayhost_invalid": "유효하지 않은 맵 기록 %s",
|
"relayhost_invalid": "유효하지 않은 맵 기록 %s",
|
||||||
"release_send_failed": "메시지를 릴리즈할 수 없습니다.: %s",
|
"release_send_failed": "메시지를 릴리즈할 수 없습니다.: %s",
|
||||||
"resource_invalid": "리소스 이름 %s이 유효하지 않습니다.",
|
"resource_invalid": "리소스 이름 %s이 유효하지 않습니다.",
|
||||||
@@ -499,7 +499,7 @@
|
|||||||
"external_logs": "External logs",
|
"external_logs": "External logs",
|
||||||
"history_all_servers": "History (all servers)",
|
"history_all_servers": "History (all servers)",
|
||||||
"in_memory_logs": "In-memory logs",
|
"in_memory_logs": "In-memory logs",
|
||||||
"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>",
|
"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>",
|
||||||
"logs": "Logs",
|
"logs": "Logs",
|
||||||
"restart_container": "Restart",
|
"restart_container": "Restart",
|
||||||
"docs": "Docs",
|
"docs": "Docs",
|
||||||
|
|||||||
@@ -185,12 +185,11 @@
|
|||||||
"protocol_access": "Endre protokolltilgang",
|
"protocol_access": "Endre protokolltilgang",
|
||||||
"pushover": "Pushover",
|
"pushover": "Pushover",
|
||||||
"quarantine": "Karantenehandlinger",
|
"quarantine": "Karantenehandlinger",
|
||||||
"quarantine_attachments": "Se vedlegg i karantene",
|
"quarantine_attachments": "Sett vedlegg i karantene",
|
||||||
"quarantine_category": "Endre varslingskategori for karantene",
|
"quarantine_category": "Endre varslingskategori for karantene",
|
||||||
"quarantine_notification": "Endre karantenevarslinger",
|
"quarantine_notification": "Endre karantenevarslinger",
|
||||||
"domain_desc": "Endre domenebeskrivelse",
|
"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": {
|
"add": {
|
||||||
"app_passwd_protocols": "Tillatte protokoller for app-passord",
|
"app_passwd_protocols": "Tillatte protokoller for app-passord",
|
||||||
|
|||||||
@@ -423,7 +423,7 @@
|
|||||||
"pushover_token": "Formaat van Pushover-token is ongeldig",
|
"pushover_token": "Formaat van Pushover-token is ongeldig",
|
||||||
"quota_not_0_not_numeric": "Quota dient numeriek en groter dan 0 te zijn",
|
"quota_not_0_not_numeric": "Quota dient numeriek en groter dan 0 te zijn",
|
||||||
"recipient_map_entry_exists": "Ontvanger-map met \"%s\" bestaat reeds",
|
"recipient_map_entry_exists": "Ontvanger-map met \"%s\" bestaat reeds",
|
||||||
"redis_error": "Redis-error: %s",
|
"valkey_error": "Valkey-error: %s",
|
||||||
"relayhost_invalid": "Invoer %s is ongeldig",
|
"relayhost_invalid": "Invoer %s is ongeldig",
|
||||||
"release_send_failed": "Het volgende bericht kon niet worden vrijgegeven: %s",
|
"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.",
|
"reset_f2b_regex": "Regex-filters konden niet worden hersteld, probeer het opnieuw of herlaad de pagina over enkele seconden.",
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user