Fix metrics
commit
25ee53289b
|
@ -7,14 +7,18 @@ data/conf/nginx/listen*active
|
||||||
data/conf/nginx/server_name.active
|
data/conf/nginx/server_name.active
|
||||||
data/conf/postfix/sql
|
data/conf/postfix/sql
|
||||||
data/conf/dovecot/sql
|
data/conf/dovecot/sql
|
||||||
|
data/conf/nextcloud-*.bak
|
||||||
data/web/inc/vars.local.inc.php
|
data/web/inc/vars.local.inc.php
|
||||||
data/assets/ssl/*
|
data/assets/ssl/*
|
||||||
.vscode/*
|
.vscode/*
|
||||||
data/web/.well-known/acme-challenge
|
data/web/.well-known/acme-challenge
|
||||||
|
data/web/nextcloud/
|
||||||
data/conf/rspamd/local.d/*
|
data/conf/rspamd/local.d/*
|
||||||
data/conf/rspamd/override.d/*
|
data/conf/rspamd/override.d/*
|
||||||
!data/conf/nginx/dynmaps.conf
|
!data/conf/nginx/dynmaps.conf
|
||||||
!data/conf/nginx/site.conf
|
!data/conf/nginx/site.conf
|
||||||
data/conf/nginx/*.conf
|
data/conf/nginx/*.conf
|
||||||
|
data/conf/nginx/*.custom
|
||||||
|
data/conf/nginx/*.bak
|
||||||
data/conf/dovecot/extra.conf
|
data/conf/dovecot/extra.conf
|
||||||
data/conf/rspamd/custom/*
|
data/conf/rspamd/custom/*
|
||||||
|
|
|
@ -9,8 +9,9 @@ RUN apk add --update --no-cache \
|
||||||
openssl \
|
openssl \
|
||||||
bind-tools \
|
bind-tools \
|
||||||
jq \
|
jq \
|
||||||
mariadb-client
|
mariadb-client \
|
||||||
|
tini
|
||||||
|
|
||||||
COPY docker-entrypoint.sh /srv/docker-entrypoint.sh
|
COPY docker-entrypoint.sh /srv/docker-entrypoint.sh
|
||||||
|
|
||||||
ENTRYPOINT ["/srv/docker-entrypoint.sh"]
|
CMD ["/sbin/tini", "-g", "--", "/srv/docker-entrypoint.sh"]
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
set -o pipefail
|
||||||
|
exec 5>&1
|
||||||
|
|
||||||
ACME_BASE=/var/lib/acme
|
ACME_BASE=/var/lib/acme
|
||||||
SSL_EXAMPLE=/var/lib/ssl-example
|
SSL_EXAMPLE=/var/lib/ssl-example
|
||||||
|
@ -6,24 +8,40 @@ SSL_EXAMPLE=/var/lib/ssl-example
|
||||||
mkdir -p ${ACME_BASE}/acme/private
|
mkdir -p ${ACME_BASE}/acme/private
|
||||||
|
|
||||||
restart_containers(){
|
restart_containers(){
|
||||||
for container in $*; do
|
for container in $*; do
|
||||||
echo "Restarting ${container}..."
|
echo "Restarting ${container}..."
|
||||||
curl -X POST \
|
curl -X POST http://dockerapi:8080/containers/${container}/restart
|
||||||
--unix-socket /var/run/docker.sock \
|
done
|
||||||
"http/containers/${container}/restart"
|
}
|
||||||
done
|
|
||||||
|
log_f() {
|
||||||
|
if [[ ${2} == "no_nl" ]]; then
|
||||||
|
echo -n "$(date) - ${1}"
|
||||||
|
elif [[ ${2} == "no_date" ]]; then
|
||||||
|
echo "${1}"
|
||||||
|
else
|
||||||
|
echo "$(date) - ${1}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
array_diff() {
|
||||||
|
# https://stackoverflow.com/questions/2312762, Alex Offshore
|
||||||
|
eval local ARR1=\(\"\${$2[@]}\"\)
|
||||||
|
eval local ARR2=\(\"\${$3[@]}\"\)
|
||||||
|
local IFS=$'\n'
|
||||||
|
mapfile -t $1 < <(comm -23 <(echo "${ARR1[*]}" | sort) <(echo "${ARR2[*]}" | sort))
|
||||||
}
|
}
|
||||||
|
|
||||||
verify_hash_match(){
|
verify_hash_match(){
|
||||||
CERT_HASH=$(openssl x509 -noout -modulus -in "${1}" | openssl md5)
|
CERT_HASH=$(openssl x509 -noout -modulus -in "${1}" | openssl md5)
|
||||||
KEY_HASH=$(openssl rsa -noout -modulus -in "${2}" | openssl md5)
|
KEY_HASH=$(openssl rsa -noout -modulus -in "${2}" | openssl md5)
|
||||||
if [[ ${CERT_HASH} != ${KEY_HASH} ]]; then
|
if [[ ${CERT_HASH} != ${KEY_HASH} ]]; then
|
||||||
echo "Certificate and key hashes do not match!"
|
log_f "Certificate and key hashes do not match!"
|
||||||
return 1
|
return 1
|
||||||
else
|
else
|
||||||
echo "Verified hashes."
|
log_f "Verified hashes."
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
get_ipv4(){
|
get_ipv4(){
|
||||||
|
@ -31,7 +49,7 @@ get_ipv4(){
|
||||||
local IPV4_SRCS=
|
local IPV4_SRCS=
|
||||||
local TRY=
|
local TRY=
|
||||||
IPV4_SRCS[0]="api.ipify.org"
|
IPV4_SRCS[0]="api.ipify.org"
|
||||||
IPV4_SRCS[1]="ifconfig.co"
|
IPV4_SRCS[1]="ifconfig.co"-
|
||||||
IPV4_SRCS[2]="icanhazip.com"
|
IPV4_SRCS[2]="icanhazip.com"
|
||||||
IPV4_SRCS[3]="v4.ident.me"
|
IPV4_SRCS[3]="v4.ident.me"
|
||||||
IPV4_SRCS[4]="ipecho.net/plain"
|
IPV4_SRCS[4]="ipecho.net/plain"
|
||||||
|
@ -47,224 +65,243 @@ get_ipv4(){
|
||||||
[[ ! -f ${ACME_BASE}/dhparams.pem ]] && cp ${SSL_EXAMPLE}/dhparams.pem ${ACME_BASE}/dhparams.pem
|
[[ ! -f ${ACME_BASE}/dhparams.pem ]] && cp ${SSL_EXAMPLE}/dhparams.pem ${ACME_BASE}/dhparams.pem
|
||||||
|
|
||||||
if [[ -f ${ACME_BASE}/cert.pem ]] && [[ -f ${ACME_BASE}/key.pem ]]; then
|
if [[ -f ${ACME_BASE}/cert.pem ]] && [[ -f ${ACME_BASE}/key.pem ]]; then
|
||||||
ISSUER=$(openssl x509 -in ${ACME_BASE}/cert.pem -noout -issuer)
|
ISSUER=$(openssl x509 -in ${ACME_BASE}/cert.pem -noout -issuer)
|
||||||
if [[ ${ISSUER} != *"Let's Encrypt"* && ${ISSUER} != *"mailcow"* ]]; then
|
if [[ ${ISSUER} != *"Let's Encrypt"* && ${ISSUER} != *"mailcow"* ]]; then
|
||||||
echo "Found certificate with issuer other than mailcow snake-oil CA and Let's Encrypt, skipping ACME client..."
|
log_f "Found certificate with issuer other than mailcow snake-oil CA and Let's Encrypt, skipping ACME client..."
|
||||||
sleep 3650d
|
sleep 3650d
|
||||||
exec $(readlink -f "$0")
|
exec $(readlink -f "$0")
|
||||||
else
|
else
|
||||||
declare -a SAN_ARRAY_NOW
|
declare -a SAN_ARRAY_NOW
|
||||||
SAN_NAMES=$(openssl x509 -noout -text -in ${ACME_BASE}/cert.pem | awk '/X509v3 Subject Alternative Name/ {getline;gsub(/ /, "", $0); print}' | tr -d "DNS:")
|
SAN_NAMES=$(openssl x509 -noout -text -in ${ACME_BASE}/cert.pem | awk '/X509v3 Subject Alternative Name/ {getline;gsub(/ /, "", $0); print}' | tr -d "DNS:")
|
||||||
if [[ ! -z ${SAN_NAMES} ]]; then
|
if [[ ! -z ${SAN_NAMES} ]]; then
|
||||||
IFS=',' read -a SAN_ARRAY_NOW <<< ${SAN_NAMES}
|
IFS=',' read -a SAN_ARRAY_NOW <<< ${SAN_NAMES}
|
||||||
echo "Found Let's Encrypt or mailcow snake-oil CA issued certificate with SANs: ${SAN_ARRAY_NOW[*]}"
|
log_f "Found Let's Encrypt or mailcow snake-oil CA issued certificate with SANs: ${SAN_ARRAY_NOW[*]}"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
if [[ -f ${ACME_BASE}/acme/fullchain.pem ]] && [[ -f ${ACME_BASE}/acme/private/privkey.pem ]]; then
|
if [[ -f ${ACME_BASE}/acme/fullchain.pem ]] && [[ -f ${ACME_BASE}/acme/private/privkey.pem ]]; then
|
||||||
if verify_hash_match ${ACME_BASE}/acme/fullchain.pem ${ACME_BASE}/acme/private/privkey.pem; then
|
if verify_hash_match ${ACME_BASE}/acme/fullchain.pem ${ACME_BASE}/acme/private/privkey.pem; then
|
||||||
echo "Restoring previous acme certificate and restarting script..."
|
log_f "Restoring previous acme certificate and restarting script..."
|
||||||
cp ${ACME_BASE}/acme/fullchain.pem ${ACME_BASE}/cert.pem
|
cp ${ACME_BASE}/acme/fullchain.pem ${ACME_BASE}/cert.pem
|
||||||
cp ${ACME_BASE}/acme/private/privkey.pem ${ACME_BASE}/key.pem
|
cp ${ACME_BASE}/acme/private/privkey.pem ${ACME_BASE}/key.pem
|
||||||
exec env TRIGGER_RESTART=1 $(readlink -f "$0")
|
# Restarting with env var set to trigger a restart,
|
||||||
fi
|
exec env TRIGGER_RESTART=1 $(readlink -f "$0")
|
||||||
ISSUER="mailcow"
|
fi
|
||||||
else
|
ISSUER="mailcow"
|
||||||
echo "Restoring mailcow snake-oil certificates and restarting script..."
|
else
|
||||||
cp ${SSL_EXAMPLE}/cert.pem ${ACME_BASE}/cert.pem
|
log_f "Restoring mailcow snake-oil certificates and restarting script..."
|
||||||
cp ${SSL_EXAMPLE}/key.pem ${ACME_BASE}/key.pem
|
cp ${SSL_EXAMPLE}/cert.pem ${ACME_BASE}/cert.pem
|
||||||
exec env TRIGGER_RESTART=1 $(readlink -f "$0")
|
cp ${SSL_EXAMPLE}/key.pem ${ACME_BASE}/key.pem
|
||||||
fi
|
exec env TRIGGER_RESTART=1 $(readlink -f "$0")
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
while ! mysqladmin ping --host mysql -u${DBUSER} -p${DBPASS} --silent; do
|
||||||
|
echo "Waiting for database to come up..."
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
if [[ "${SKIP_LETS_ENCRYPT}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
if [[ "${SKIP_LETS_ENCRYPT}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
||||||
echo "SKIP_LETS_ENCRYPT=y, skipping Let's Encrypt..."
|
log_f "SKIP_LETS_ENCRYPT=y, skipping Let's Encrypt..."
|
||||||
sleep 3650d
|
sleep 365d
|
||||||
exec $(readlink -f "$0")
|
exec $(readlink -f "$0")
|
||||||
fi
|
fi
|
||||||
if [[ "${SKIP_IP_CHECK}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
if [[ "${SKIP_IP_CHECK}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
||||||
SKIP_IP_CHECK=y
|
SKIP_IP_CHECK=y
|
||||||
fi
|
fi
|
||||||
unset SQL_DOMAIN_ARR
|
unset SQL_DOMAIN_ARR
|
||||||
unset VALIDATED_CONFIG_DOMAINS
|
unset VALIDATED_CONFIG_DOMAINS
|
||||||
unset ADDITIONAL_VALIDATED_SAN
|
unset ADDITIONAL_VALIDATED_SAN
|
||||||
declare -a SQL_DOMAIN_ARR
|
declare -a SQL_DOMAIN_ARR
|
||||||
declare -a VALIDATED_CONFIG_DOMAINS
|
declare -a VALIDATED_CONFIG_DOMAINS
|
||||||
declare -a ADDITIONAL_VALIDATED_SAN
|
declare -a ADDITIONAL_VALIDATED_SAN
|
||||||
IFS=',' read -r -a ADDITIONAL_SAN_ARR <<< "${ADDITIONAL_SAN}"
|
IFS=',' read -r -a ADDITIONAL_SAN_ARR <<< "${ADDITIONAL_SAN}"
|
||||||
IPV4=$(get_ipv4)
|
IPV4=$(get_ipv4)
|
||||||
# Container ids may have changed
|
# Container ids may have changed
|
||||||
CONTAINERS_RESTART=($(curl --silent --unix-socket /var/run/docker.sock http/containers/json | jq -rc 'map(select(.Names[] | contains ("nginx-mailcow") or contains ("postfix-mailcow") or contains ("dovecot-mailcow"))) | .[] .Id' | tr "\n" " "))
|
CONTAINERS_RESTART=($(curl --silent http://dockerapi:8080/containers/json | jq -r '.[] | {name: .Config.Labels["com.docker.compose.service"], id: .Id}' | jq -rc 'select( .name | tostring | contains("nginx-mailcow") or contains("postfix-mailcow") or contains("dovecot-mailcow")) | .id' | tr "\n" " "))
|
||||||
|
|
||||||
while read domain; do
|
log_f "Waiting for domain tables... " no_nl
|
||||||
SQL_DOMAIN_ARR+=("${domain}")
|
while [[ -z ${DOMAIN_TABLE} ]]; do
|
||||||
done < <(mysql -h mysql-mailcow -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT domain FROM domain WHERE backupmx=0" -Bs)
|
DOMAIN_TABLE=$(mysql -h mysql-mailcow -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SHOW TABLES LIKE 'domain'" -Bs)
|
||||||
while read alias_domain; do
|
[[ -z ${DOMAIN_TABLE} ]] && sleep 10
|
||||||
SQL_DOMAIN_ARR+=("${alias_domain}")
|
done
|
||||||
done < <(mysql -h mysql-mailcow -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT alias_domain FROM alias_domain" -Bs)
|
log_f "OK" no_date
|
||||||
|
|
||||||
for SQL_DOMAIN in "${SQL_DOMAIN_ARR[@]}"; do
|
while read domains; do
|
||||||
A_CONFIG=$(dig A autoconfig.${SQL_DOMAIN} +short | tail -n 1)
|
SQL_DOMAIN_ARR+=("${domains}")
|
||||||
if [[ ! -z ${A_CONFIG} ]]; then
|
done < <(mysql -h mysql-mailcow -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SELECT domain FROM domain WHERE backupmx=0 UNION SELECT alias_domain FROM alias_domain" -Bs)
|
||||||
echo "Found A record for autoconfig.${SQL_DOMAIN}: ${A_CONFIG}"
|
|
||||||
if [[ ${IPV4:-ERR} == ${A_CONFIG} ]] || [[ ${SKIP_IP_CHECK} == "y" ]]; then
|
for SQL_DOMAIN in "${SQL_DOMAIN_ARR[@]}"; do
|
||||||
echo "Confirmed A record autoconfig.${SQL_DOMAIN}"
|
A_CONFIG=$(dig A autoconfig.${SQL_DOMAIN} +short | tail -n 1)
|
||||||
VALIDATED_CONFIG_DOMAINS+=("autoconfig.${SQL_DOMAIN}")
|
if [[ ! -z ${A_CONFIG} ]]; then
|
||||||
else
|
log_f "Found A record for autoconfig.${SQL_DOMAIN}: ${A_CONFIG}"
|
||||||
echo "Cannot match your IP ${IPV4} against hostname autoconfig.${SQL_DOMAIN} (${A_CONFIG})"
|
if [[ ${IPV4:-ERR} == ${A_CONFIG} ]] || [[ ${SKIP_IP_CHECK} == "y" ]]; then
|
||||||
fi
|
log_f "Confirmed A record autoconfig.${SQL_DOMAIN}"
|
||||||
else
|
VALIDATED_CONFIG_DOMAINS+=("autoconfig.${SQL_DOMAIN}")
|
||||||
echo "No A record for autoconfig.${SQL_DOMAIN} found"
|
else
|
||||||
fi
|
log_f "Cannot match your IP ${IPV4} against hostname autoconfig.${SQL_DOMAIN} (${A_CONFIG})"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log_f "No A record for autoconfig.${SQL_DOMAIN} found"
|
||||||
|
fi
|
||||||
|
|
||||||
A_DISCOVER=$(dig A autodiscover.${SQL_DOMAIN} +short | tail -n 1)
|
A_DISCOVER=$(dig A autodiscover.${SQL_DOMAIN} +short | tail -n 1)
|
||||||
if [[ ! -z ${A_DISCOVER} ]]; then
|
if [[ ! -z ${A_DISCOVER} ]]; then
|
||||||
echo "Found A record for autodiscover.${SQL_DOMAIN}: ${A_DISCOVER}"
|
log_f "Found A record for autodiscover.${SQL_DOMAIN}: ${A_DISCOVER}"
|
||||||
if [[ ${IPV4:-ERR} == ${A_DISCOVER} ]] || [[ ${SKIP_IP_CHECK} == "y" ]]; then
|
if [[ ${IPV4:-ERR} == ${A_DISCOVER} ]] || [[ ${SKIP_IP_CHECK} == "y" ]]; then
|
||||||
echo "Confirmed A record autodiscover.${SQL_DOMAIN}"
|
log_f "Confirmed A record autodiscover.${SQL_DOMAIN}"
|
||||||
VALIDATED_CONFIG_DOMAINS+=("autodiscover.${SQL_DOMAIN}")
|
VALIDATED_CONFIG_DOMAINS+=("autodiscover.${SQL_DOMAIN}")
|
||||||
else
|
else
|
||||||
echo "Cannot match your IP ${IPV4} against hostname autodiscover.${SQL_DOMAIN} (${A_DISCOVER})"
|
log_f "Cannot match your IP ${IPV4} against hostname autodiscover.${SQL_DOMAIN} (${A_DISCOVER})"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo "No A record for autodiscover.${SQL_DOMAIN} found"
|
log_f "No A record for autodiscover.${SQL_DOMAIN} found"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
A_MAILCOW_HOSTNAME=$(dig A ${MAILCOW_HOSTNAME} +short | tail -n 1)
|
A_MAILCOW_HOSTNAME=$(dig A ${MAILCOW_HOSTNAME} +short | tail -n 1)
|
||||||
if [[ ! -z ${A_MAILCOW_HOSTNAME} ]]; then
|
if [[ ! -z ${A_MAILCOW_HOSTNAME} ]]; then
|
||||||
echo "Found A record for ${MAILCOW_HOSTNAME}: ${A_MAILCOW_HOSTNAME}"
|
log_f "Found A record for ${MAILCOW_HOSTNAME}: ${A_MAILCOW_HOSTNAME}"
|
||||||
if [[ ${IPV4:-ERR} == ${A_MAILCOW_HOSTNAME} ]] || [[ ${SKIP_IP_CHECK} == "y" ]]; then
|
if [[ ${IPV4:-ERR} == ${A_MAILCOW_HOSTNAME} ]] || [[ ${SKIP_IP_CHECK} == "y" ]]; then
|
||||||
echo "Confirmed A record ${MAILCOW_HOSTNAME}"
|
log_f "Confirmed A record ${MAILCOW_HOSTNAME}"
|
||||||
VALIDATED_MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME}
|
VALIDATED_MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME}
|
||||||
else
|
else
|
||||||
echo "Cannot match your IP ${IPV4} against hostname ${MAILCOW_HOSTNAME} (${A_MAILCOW_HOSTNAME}) "
|
log_f "Cannot match your IP ${IPV4} against hostname ${MAILCOW_HOSTNAME} (${A_MAILCOW_HOSTNAME}) "
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo "No A record for ${MAILCOW_HOSTNAME} found"
|
log_f "No A record for ${MAILCOW_HOSTNAME} found"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
for SAN in "${ADDITIONAL_SAN_ARR[@]}"; do
|
for SAN in "${ADDITIONAL_SAN_ARR[@]}"; do
|
||||||
if [[ ${SAN} == ${MAILCOW_HOSTNAME} ]]; then
|
if [[ ${SAN} == ${MAILCOW_HOSTNAME} ]]; then
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
A_SAN=$(dig A ${SAN} +short | tail -n 1)
|
A_SAN=$(dig A ${SAN} +short | tail -n 1)
|
||||||
if [[ ! -z ${A_SAN} ]]; then
|
if [[ ! -z ${A_SAN} ]]; then
|
||||||
echo "Found A record for ${SAN}: ${A_SAN}"
|
log_f "Found A record for ${SAN}: ${A_SAN}"
|
||||||
if [[ ${IPV4:-ERR} == ${A_SAN} ]] || [[ ${SKIP_IP_CHECK} == "y" ]]; then
|
if [[ ${IPV4:-ERR} == ${A_SAN} ]] || [[ ${SKIP_IP_CHECK} == "y" ]]; then
|
||||||
echo "Confirmed A record ${SAN}"
|
log_f "Confirmed A record ${SAN}"
|
||||||
ADDITIONAL_VALIDATED_SAN+=("${SAN}")
|
ADDITIONAL_VALIDATED_SAN+=("${SAN}")
|
||||||
else
|
else
|
||||||
echo "Cannot match your IP against hostname ${SAN}"
|
log_f "Cannot match your IP against hostname ${SAN}"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo "No A record for ${SAN} found"
|
log_f "No A record for ${SAN} found"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# Unique elements
|
# Unique elements
|
||||||
ALL_VALIDATED=(${VALIDATED_MAILCOW_HOSTNAME} $(echo ${VALIDATED_CONFIG_DOMAINS[*]} ${ADDITIONAL_VALIDATED_SAN[*]} | xargs -n1 | sort -u | xargs))
|
ALL_VALIDATED=(${VALIDATED_MAILCOW_HOSTNAME} $(echo ${VALIDATED_CONFIG_DOMAINS[*]} ${ADDITIONAL_VALIDATED_SAN[*]} | xargs -n1 | sort -u | xargs))
|
||||||
if [[ -z ${ALL_VALIDATED[*]} ]]; then
|
if [[ -z ${ALL_VALIDATED[*]} ]]; then
|
||||||
echo "Cannot validate hostnames, skipping Let's Encrypt for 1 hour."
|
log_f "Cannot validate hostnames, skipping Let's Encrypt for 1 hour."
|
||||||
echo "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."
|
||||||
sleep 1h
|
sleep 1h
|
||||||
exec $(readlink -f "$0")
|
exec $(readlink -f "$0")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ORPHANED_SAN=($(echo ${SAN_ARRAY_NOW[*]} ${ALL_VALIDATED[*]} | tr ' ' '\n' | sort | uniq -u ))
|
array_diff ORPHANED_SAN SAN_ARRAY_NOW ALL_VALIDATED
|
||||||
if [[ ! -z ${ORPHANED_SAN[*]} ]] && [[ ${ISSUER} != *"mailcow"* ]]; then
|
if [[ ! -z ${ORPHANED_SAN[*]} ]] && [[ ${ISSUER} != *"mailcow"* ]]; then
|
||||||
DATE=$(date +%Y-%m-%d_%H_%M_%S)
|
DATE=$(date +%Y-%m-%d_%H_%M_%S)
|
||||||
echo "Found orphaned SAN ${ORPHANED_SAN[*]} in certificate, moving old files to ${ACME_BASE}/acme/private/${DATE}.bak/, keeping key file..."
|
log_f "Found orphaned SAN ${ORPHANED_SAN[*]} in certificate, moving old files to ${ACME_BASE}/acme/private/${DATE}.bak/, keeping key file..."
|
||||||
mkdir -p ${ACME_BASE}/acme/private/${DATE}.bak/
|
mkdir -p ${ACME_BASE}/acme/private/${DATE}.bak/
|
||||||
[[ -f ${ACME_BASE}/acme/private/account.key ]] && mv ${ACME_BASE}/acme/private/account.key ${ACME_BASE}/acme/private/${DATE}.bak/
|
[[ -f ${ACME_BASE}/acme/private/account.key ]] && mv ${ACME_BASE}/acme/private/account.key ${ACME_BASE}/acme/private/${DATE}.bak/
|
||||||
[[ -f ${ACME_BASE}/acme/fullchain.pem ]] && mv ${ACME_BASE}/acme/fullchain.pem ${ACME_BASE}/acme/private/${DATE}.bak/
|
[[ -f ${ACME_BASE}/acme/fullchain.pem ]] && mv ${ACME_BASE}/acme/fullchain.pem ${ACME_BASE}/acme/private/${DATE}.bak/
|
||||||
[[ -f ${ACME_BASE}/acme/cert.pem ]] && mv ${ACME_BASE}/acme/cert.pem ${ACME_BASE}/acme/private/${DATE}.bak/
|
[[ -f ${ACME_BASE}/acme/cert.pem ]] && mv ${ACME_BASE}/acme/cert.pem ${ACME_BASE}/acme/private/${DATE}.bak/
|
||||||
cp ${ACME_BASE}/acme/private/privkey.pem ${ACME_BASE}/acme/private/${DATE}.bak/ # Keep key for TLSA 3 1 1 records
|
cp ${ACME_BASE}/acme/private/privkey.pem ${ACME_BASE}/acme/private/${DATE}.bak/ # Keep key for TLSA 3 1 1 records
|
||||||
fi
|
fi
|
||||||
|
|
||||||
acme-client \
|
ACME_RESPONSE=$(acme-client \
|
||||||
-v -e -b -N -n \
|
-v -e -b -N -n \
|
||||||
-f ${ACME_BASE}/acme/private/account.key \
|
-f ${ACME_BASE}/acme/private/account.key \
|
||||||
-k ${ACME_BASE}/acme/private/privkey.pem \
|
-k ${ACME_BASE}/acme/private/privkey.pem \
|
||||||
-c ${ACME_BASE}/acme \
|
-c ${ACME_BASE}/acme \
|
||||||
${ALL_VALIDATED[*]}
|
${ALL_VALIDATED[*]} 2>&1 | tee /dev/fd/5)
|
||||||
|
|
||||||
case "$?" in
|
case "$?" in
|
||||||
0) # new certs
|
0) # new certs
|
||||||
# cp the new certificates and keys
|
# cp the new certificates and keys
|
||||||
cp ${ACME_BASE}/acme/fullchain.pem ${ACME_BASE}/cert.pem
|
cp ${ACME_BASE}/acme/fullchain.pem ${ACME_BASE}/cert.pem
|
||||||
cp ${ACME_BASE}/acme/private/privkey.pem ${ACME_BASE}/key.pem
|
cp ${ACME_BASE}/acme/private/privkey.pem ${ACME_BASE}/key.pem
|
||||||
|
|
||||||
# restart docker containers
|
# restart docker containers
|
||||||
if ! verify_hash_match ${ACME_BASE}/cert.pem ${ACME_BASE}/key.pem; then
|
if ! verify_hash_match ${ACME_BASE}/cert.pem ${ACME_BASE}/key.pem; then
|
||||||
echo "Certificate was successfully requested, but key and certificate have non-matching hashes, restoring mailcow snake-oil and restarting containers..."
|
log_f "Certificate was successfully requested, but key and certificate have non-matching hashes, restoring mailcow snake-oil and restarting containers..."
|
||||||
cp ${SSL_EXAMPLE}/cert.pem ${ACME_BASE}/cert.pem
|
cp ${SSL_EXAMPLE}/cert.pem ${ACME_BASE}/cert.pem
|
||||||
cp ${SSL_EXAMPLE}/key.pem ${ACME_BASE}/key.pem
|
cp ${SSL_EXAMPLE}/key.pem ${ACME_BASE}/key.pem
|
||||||
fi
|
fi
|
||||||
restart_containers ${CONTAINERS_RESTART[*]}
|
restart_containers ${CONTAINERS_RESTART[*]}
|
||||||
;;
|
;;
|
||||||
1) # failure
|
1) # failure
|
||||||
if [[ -f ${ACME_BASE}/acme/private/${DATE}.bak/fullchain.pem ]] && [[ -f ${ACME_BASE}/acme/private/${DATE}.bak/privkey.pem ]]; then
|
if [[ $ACME_RESPONSE =~ "No registration exists" ]]; then
|
||||||
echo "Error requesting certificate, restoring previous certificate from backup and restarting containers...."
|
log_f "Registration keys are invalid, deleting old keys and restarting..."
|
||||||
cp ${ACME_BASE}/acme/private/${DATE}.bak/fullchain.pem ${ACME_BASE}/cert.pem
|
rm ${ACME_BASE}/acme/private/account.key
|
||||||
cp ${ACME_BASE}/acme/private/${DATE}.bak/privkey.pem ${ACME_BASE}/key.pem
|
rm ${ACME_BASE}/acme/private/privkey.pem
|
||||||
TRIGGER_RESTART=1
|
exec $(readlink -f "$0")
|
||||||
|
fi
|
||||||
|
if [[ -f ${ACME_BASE}/acme/private/${DATE}.bak/fullchain.pem ]] && [[ -f ${ACME_BASE}/acme/private/${DATE}.bak/privkey.pem ]]; then
|
||||||
|
log_f "Error requesting certificate, restoring previous certificate from backup and restarting containers...."
|
||||||
|
cp ${ACME_BASE}/acme/private/${DATE}.bak/fullchain.pem ${ACME_BASE}/cert.pem
|
||||||
|
cp ${ACME_BASE}/acme/private/${DATE}.bak/privkey.pem ${ACME_BASE}/key.pem
|
||||||
|
TRIGGER_RESTART=1
|
||||||
|
elif [[ -f ${ACME_BASE}/acme/fullchain.pem ]] && [[ -f ${ACME_BASE}/acme/private/privkey.pem ]]; then
|
||||||
|
log_f "Error requesting certificate, restoring from previous acme request and restarting containers..."
|
||||||
|
cp ${ACME_BASE}/acme/fullchain.pem ${ACME_BASE}/cert.pem
|
||||||
|
cp ${ACME_BASE}/acme/private/privkey.pem ${ACME_BASE}/key.pem
|
||||||
|
TRIGGER_RESTART=1
|
||||||
|
fi
|
||||||
|
if ! verify_hash_match ${ACME_BASE}/cert.pem ${ACME_BASE}/key.pem; then
|
||||||
|
log_f "Error verifying certificates, restoring mailcow snake-oil and restarting containers..."
|
||||||
|
cp ${SSL_EXAMPLE}/cert.pem ${ACME_BASE}/cert.pem
|
||||||
|
cp ${SSL_EXAMPLE}/key.pem ${ACME_BASE}/key.pem
|
||||||
|
TRIGGER_RESTART=1
|
||||||
|
fi
|
||||||
|
[[ ${TRIGGER_RESTART} == 1 ]] && restart_containers ${CONTAINERS_RESTART[*]}
|
||||||
|
log_f "Retrying in 30 minutes..."
|
||||||
|
sleep 30m
|
||||||
|
exec $(readlink -f "$0")
|
||||||
|
;;
|
||||||
|
2) # no change
|
||||||
|
if ! diff ${ACME_BASE}/acme/fullchain.pem ${ACME_BASE}/cert.pem; then
|
||||||
|
log_f "Certificate was not changed, but active certificate does not match the verified certificate, fixing and restarting containers..."
|
||||||
|
cp ${ACME_BASE}/acme/fullchain.pem ${ACME_BASE}/cert.pem
|
||||||
|
cp ${ACME_BASE}/acme/private/privkey.pem ${ACME_BASE}/key.pem
|
||||||
|
TRIGGER_RESTART=1
|
||||||
|
fi
|
||||||
|
if ! verify_hash_match ${ACME_BASE}/cert.pem ${ACME_BASE}/key.pem; then
|
||||||
|
log_f "Certificate was not changed, but hashes do not match, restoring from previous acme request and restarting containers..."
|
||||||
|
cp ${ACME_BASE}/acme/fullchain.pem ${ACME_BASE}/cert.pem
|
||||||
|
cp ${ACME_BASE}/acme/private/privkey.pem ${ACME_BASE}/key.pem
|
||||||
|
TRIGGER_RESTART=1
|
||||||
|
fi
|
||||||
|
[[ ${TRIGGER_RESTART} == 1 ]] && restart_containers ${CONTAINERS_RESTART[*]}
|
||||||
|
;;
|
||||||
|
*) # unspecified
|
||||||
|
if [[ -f ${ACME_BASE}/acme/private/${DATE}.bak/fullchain.pem ]] && [[ -f ${ACME_BASE}/acme/private/${DATE}.bak/privkey.pem ]]; then
|
||||||
|
log_f "Error requesting certificate, restoring previous certificate from backup and restarting containers...."
|
||||||
|
cp ${ACME_BASE}/acme/private/${DATE}.bak/fullchain.pem ${ACME_BASE}/cert.pem
|
||||||
|
cp ${ACME_BASE}/acme/private/${DATE}.bak/privkey.pem ${ACME_BASE}/key.pem
|
||||||
|
TRIGGER_RESTART=1
|
||||||
elif [[ -f ${ACME_BASE}/acme/fullchain.pem ]] && [[ -f ${ACME_BASE}/acme/private/privkey.pem ]]; then
|
elif [[ -f ${ACME_BASE}/acme/fullchain.pem ]] && [[ -f ${ACME_BASE}/acme/private/privkey.pem ]]; then
|
||||||
echo "Error requesting certificate, restoring from previous acme request and restarting containers..."
|
log_f "Error requesting certificate, restoring from previous acme request and restarting containers..."
|
||||||
cp ${ACME_BASE}/acme/fullchain.pem ${ACME_BASE}/cert.pem
|
cp ${ACME_BASE}/acme/fullchain.pem ${ACME_BASE}/cert.pem
|
||||||
cp ${ACME_BASE}/acme/private/privkey.pem ${ACME_BASE}/key.pem
|
cp ${ACME_BASE}/acme/private/privkey.pem ${ACME_BASE}/key.pem
|
||||||
TRIGGER_RESTART=1
|
TRIGGER_RESTART=1
|
||||||
fi
|
fi
|
||||||
if ! verify_hash_match ${ACME_BASE}/cert.pem ${ACME_BASE}/key.pem; then
|
if ! verify_hash_match ${ACME_BASE}/cert.pem ${ACME_BASE}/key.pem; then
|
||||||
echo "Error verifying certificates, restoring mailcow snake-oil and restarting containers..."
|
log_f "Error verifying certificates, restoring mailcow snake-oil..."
|
||||||
cp ${SSL_EXAMPLE}/cert.pem ${ACME_BASE}/cert.pem
|
cp ${SSL_EXAMPLE}/cert.pem ${ACME_BASE}/cert.pem
|
||||||
cp ${SSL_EXAMPLE}/key.pem ${ACME_BASE}/key.pem
|
cp ${SSL_EXAMPLE}/key.pem ${ACME_BASE}/key.pem
|
||||||
TRIGGER_RESTART=1
|
TRIGGER_RESTART=1
|
||||||
fi
|
fi
|
||||||
[[ ${TRIGGER_RESTART} == 1 ]] && restart_containers ${CONTAINERS_RESTART[*]}
|
[[ ${TRIGGER_RESTART} == 1 ]] && restart_containers ${CONTAINERS_RESTART[*]}
|
||||||
echo "Retrying in 30 minutes..."
|
log_f "Retrying in 30 minutes..."
|
||||||
sleep 30m
|
sleep 30m
|
||||||
exec $(readlink -f "$0")
|
exec $(readlink -f "$0")
|
||||||
;;
|
;;
|
||||||
2) # no change
|
esac
|
||||||
if ! diff ${ACME_BASE}/acme/fullchain.pem ${ACME_BASE}/cert.pem; then
|
|
||||||
echo "Certificate was not changed, but active certificate does not match the verified certificate, fixing and restarting containers..."
|
|
||||||
cp ${ACME_BASE}/acme/fullchain.pem ${ACME_BASE}/cert.pem
|
|
||||||
cp ${ACME_BASE}/acme/private/privkey.pem ${ACME_BASE}/key.pem
|
|
||||||
restart_containers ${CONTAINERS_RESTART[*]}
|
|
||||||
fi
|
|
||||||
if ! verify_hash_match ${ACME_BASE}/cert.pem ${ACME_BASE}/key.pem; then
|
|
||||||
echo "Certificate was not changed, but hashes do not match, restoring from previous acme request and restarting containers..."
|
|
||||||
cp ${ACME_BASE}/acme/fullchain.pem ${ACME_BASE}/cert.pem
|
|
||||||
cp ${ACME_BASE}/acme/private/privkey.pem ${ACME_BASE}/key.pem
|
|
||||||
restart_containers ${CONTAINERS_RESTART[*]}
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
*) # unspecified
|
|
||||||
if [[ -f ${ACME_BASE}/acme/private/${DATE}.bak/fullchain.pem ]] && [[ -f ${ACME_BASE}/acme/private/${DATE}.bak/privkey.pem ]]; then
|
|
||||||
echo "Error requesting certificate, restoring previous certificate from backup and restarting containers...."
|
|
||||||
cp ${ACME_BASE}/acme/private/${DATE}.bak/fullchain.pem ${ACME_BASE}/cert.pem
|
|
||||||
cp ${ACME_BASE}/acme/private/${DATE}.bak/privkey.pem ${ACME_BASE}/key.pem
|
|
||||||
TRIGGER_RESTART=1
|
|
||||||
elif [[ -f ${ACME_BASE}/acme/fullchain.pem ]] && [[ -f ${ACME_BASE}/acme/private/privkey.pem ]]; then
|
|
||||||
echo "Error requesting certificate, restoring from previous acme request and restarting containers..."
|
|
||||||
cp ${ACME_BASE}/acme/fullchain.pem ${ACME_BASE}/cert.pem
|
|
||||||
cp ${ACME_BASE}/acme/private/privkey.pem ${ACME_BASE}/key.pem
|
|
||||||
TRIGGER_RESTART=1
|
|
||||||
fi
|
|
||||||
if ! verify_hash_match ${ACME_BASE}/cert.pem ${ACME_BASE}/key.pem; then
|
|
||||||
echo "Error verifying certificates, restoring mailcow snake-oil..."
|
|
||||||
cp ${SSL_EXAMPLE}/cert.pem ${ACME_BASE}/cert.pem
|
|
||||||
cp ${SSL_EXAMPLE}/key.pem ${ACME_BASE}/key.pem
|
|
||||||
TRIGGER_RESTART=1
|
|
||||||
fi
|
|
||||||
[[ ${TRIGGER_RESTART} == 1 ]] && restart_containers ${CONTAINERS_RESTART[*]}
|
|
||||||
sleep 3650d
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
echo "ACME certificate validation done. Sleeping for another day."
|
log_f "ACME certificate validation done. Sleeping for another day."
|
||||||
sleep 1d
|
sleep 1d
|
||||||
|
|
||||||
done
|
done
|
||||||
|
|
Binary file not shown.
|
@ -7,7 +7,7 @@ COPY dl_files.sh bootstrap.sh ./
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
RUN apk add --update \
|
RUN apk add --update \
|
||||||
&& apk add --no-cache clamav clamav-libunrar curl bash \
|
&& apk add --no-cache clamav clamav-libunrar curl bash tini \
|
||||||
&& chmod +x /dl_files.sh \
|
&& chmod +x /dl_files.sh \
|
||||||
&& set -ex; /bin/bash /dl_files.sh \
|
&& set -ex; /bin/bash /dl_files.sh \
|
||||||
&& mkdir /run/clamav \
|
&& mkdir /run/clamav \
|
||||||
|
@ -15,12 +15,14 @@ RUN apk add --update \
|
||||||
&& chmod 750 /run/clamav \
|
&& chmod 750 /run/clamav \
|
||||||
&& sed -i '/Foreground yes/s/^#//g' /etc/clamav/clamd.conf \
|
&& sed -i '/Foreground yes/s/^#//g' /etc/clamav/clamd.conf \
|
||||||
&& sed -i '/TCPSocket 3310/s/^#//g' /etc/clamav/clamd.conf \
|
&& sed -i '/TCPSocket 3310/s/^#//g' /etc/clamav/clamd.conf \
|
||||||
|
&& sed -i 's#LogFile /var/log/clamav/clamd.log#LogFile /tmp/logpipe_clamd#g' /etc/clamav/clamd.conf \
|
||||||
&& sed -i 's/#PhishingSignatures yes/PhishingSignatures no/g' /etc/clamav/clamd.conf \
|
&& sed -i 's/#PhishingSignatures yes/PhishingSignatures no/g' /etc/clamav/clamd.conf \
|
||||||
&& sed -i 's/#PhishingScanURLs yes/PhishingScanURLs no/g' /etc/clamav/clamd.conf \
|
&& sed -i 's/#PhishingScanURLs yes/PhishingScanURLs no/g' /etc/clamav/clamd.conf \
|
||||||
|
&& sed -i 's#UpdateLogFile /var/log/clamav/freshclam.log#UpdateLogFile /tmp/logpipe_freshclam#g' /etc/clamav/freshclam.conf \
|
||||||
&& sed -i '/Foreground yes/s/^#//g' /etc/clamav/freshclam.conf
|
&& sed -i '/Foreground yes/s/^#//g' /etc/clamav/freshclam.conf
|
||||||
|
|
||||||
# Port provision
|
# Port provision
|
||||||
EXPOSE 3310
|
EXPOSE 3310
|
||||||
|
|
||||||
# AV daemon bootstrapping
|
# AV daemon bootstrapping
|
||||||
CMD ["/bootstrap.sh"]
|
CMD ["/sbin/tini", "-g", "--", "/bootstrap.sh"]
|
||||||
|
|
|
@ -1,13 +1,34 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
touch /var/log/clamav/clamd.log /var/log/clamav/freshclam.log
|
|
||||||
chown -R clamav:clamav /var/log/clamav/
|
|
||||||
|
|
||||||
if [[ "${SKIP_CLAMD}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
if [[ "${SKIP_CLAMD}" =~ ^([yY][eE][sS]|[yY])+$ ]]; then
|
||||||
echo "SKIP_CLAMD=y, skipping ClamAV..."
|
echo "SKIP_CLAMD=y, skipping ClamAV..."
|
||||||
exit 0
|
sleep 365d
|
||||||
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
freshclam -d &
|
# Create log pipes
|
||||||
clamd &
|
touch /var/log/clamav/clamd.log /var/log/clamav/freshclam.log
|
||||||
|
mkfifo -m 600 /tmp/logpipe_clamd
|
||||||
|
mkfifo -m 600 /tmp/logpipe_freshclam
|
||||||
|
chown -R clamav:clamav /var/log/clamav/ /tmp/logpipe_*
|
||||||
|
cat <> /tmp/logpipe_clamd 1>&2 &
|
||||||
|
cat <> /tmp/logpipe_freshclam 1>&2 &
|
||||||
|
|
||||||
tail -f /var/log/clamav/clamd.log /var/log/clamav/freshclam.log
|
# Prepare
|
||||||
|
BACKGROUND_TASKS=()
|
||||||
|
|
||||||
|
freshclam -d &
|
||||||
|
BACKGROUND_TASKS+=($!)
|
||||||
|
|
||||||
|
clamd &
|
||||||
|
BACKGROUND_TASKS+=($!)
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
for bg_task in ${BACKGROUND_TASKS[*]}; do
|
||||||
|
if ! kill -0 ${bg_task} 1>&2; then
|
||||||
|
echo "Worker ${bg_task} died, stopping container waiting for respawn..."
|
||||||
|
kill -TERM 1
|
||||||
|
fi
|
||||||
|
sleep 10
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
FROM python:2-alpine
|
||||||
|
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
|
||||||
|
|
||||||
|
RUN apk add -U --no-cache iptables ip6tables
|
||||||
|
RUN pip install docker flask flask-restful
|
||||||
|
|
||||||
|
COPY server.py /
|
||||||
|
CMD ["python2", "-u", "/server.py"]
|
|
@ -0,0 +1,62 @@
|
||||||
|
from flask import Flask
|
||||||
|
from flask_restful import Resource, Api
|
||||||
|
from flask import jsonify
|
||||||
|
import docker
|
||||||
|
|
||||||
|
docker_client = docker.DockerClient(base_url='unix://var/run/docker.sock')
|
||||||
|
app = Flask(__name__)
|
||||||
|
api = Api(app)
|
||||||
|
|
||||||
|
class containers_get(Resource):
|
||||||
|
def get(self):
|
||||||
|
containers = {}
|
||||||
|
for container in docker_client.containers.list(all=True):
|
||||||
|
containers.update({container.attrs['Id']: container.attrs})
|
||||||
|
return containers
|
||||||
|
|
||||||
|
class container_get(Resource):
|
||||||
|
def get(self, container_id):
|
||||||
|
if container_id and container_id.isalnum():
|
||||||
|
for container in docker_client.containers.list(all=True, filters={"id": container_id}):
|
||||||
|
return container.attrs
|
||||||
|
else:
|
||||||
|
return jsonify(message='No or invalid id defined')
|
||||||
|
|
||||||
|
class container_post(Resource):
|
||||||
|
def post(self, container_id, post_action):
|
||||||
|
if container_id and container_id.isalnum() and post_action:
|
||||||
|
if post_action == 'stop':
|
||||||
|
try:
|
||||||
|
for container in docker_client.containers.list(all=True, filters={"id": container_id}):
|
||||||
|
container.stop()
|
||||||
|
except:
|
||||||
|
return 'Error'
|
||||||
|
else:
|
||||||
|
return 'OK'
|
||||||
|
elif post_action == 'start':
|
||||||
|
try:
|
||||||
|
for container in docker_client.containers.list(all=True, filters={"id": container_id}):
|
||||||
|
container.start()
|
||||||
|
except:
|
||||||
|
return 'Error'
|
||||||
|
else:
|
||||||
|
return 'OK'
|
||||||
|
elif post_action == 'restart':
|
||||||
|
try:
|
||||||
|
for container in docker_client.containers.list(all=True, filters={"id": container_id}):
|
||||||
|
container.restart()
|
||||||
|
except:
|
||||||
|
return 'Error'
|
||||||
|
else:
|
||||||
|
return 'OK'
|
||||||
|
else:
|
||||||
|
return jsonify(message='Invalid action')
|
||||||
|
else:
|
||||||
|
return jsonify(message='Invalid container id or missing action')
|
||||||
|
|
||||||
|
api.add_resource(containers_get, '/containers/json')
|
||||||
|
api.add_resource(container_get, '/containers/<string:container_id>/json')
|
||||||
|
api.add_resource(container_post, '/containers/<string:container_id>/<string:post_action>')
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app.run(debug=False, host='0.0.0.0', port='8080')
|
|
@ -39,12 +39,13 @@ destination d_redis_cleanup {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
filter f_mail { facility(mail); };
|
filter f_mail { facility(mail); };
|
||||||
|
filter f_not_watchdog { not message("172\.22\.1\.248"); };
|
||||||
log {
|
log {
|
||||||
source(s_src);
|
source(s_src);
|
||||||
|
filter(f_not_watchdog);
|
||||||
destination(d_stdout);
|
destination(d_stdout);
|
||||||
filter(f_mail);
|
filter(f_mail);
|
||||||
destination(d_redis_ui_log);
|
destination(d_redis_ui_log);
|
||||||
destination(d_redis_f2b_channel);
|
destination(d_redis_f2b_channel);
|
||||||
destination(d_redis_cleanup);
|
destination(d_redis_cleanup);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,7 +14,8 @@ import json
|
||||||
|
|
||||||
yes_regex = re.compile(r'([yY][eE][sS]|[yY])+$')
|
yes_regex = re.compile(r'([yY][eE][sS]|[yY])+$')
|
||||||
if re.search(yes_regex, os.getenv('SKIP_FAIL2BAN', 0)):
|
if re.search(yes_regex, os.getenv('SKIP_FAIL2BAN', 0)):
|
||||||
print "Skipping Fail2ban container..."
|
print "SKIP_FAIL2BAN=y, Skipping Fail2ban container..."
|
||||||
|
time.sleep(31536000)
|
||||||
raise SystemExit
|
raise SystemExit
|
||||||
|
|
||||||
r = redis.StrictRedis(host='172.22.1.249', decode_responses=True, port=6379, db=0)
|
r = redis.StrictRedis(host='172.22.1.249', decode_responses=True, port=6379, db=0)
|
||||||
|
|
|
@ -1,8 +1,17 @@
|
||||||
FROM php:7.1-fpm-alpine
|
FROM php:7.1-fpm-alpine
|
||||||
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
|
LABEL maintainer "Andre Peters <andre.peters@servercow.de>"
|
||||||
|
|
||||||
|
ENV REDIS_PECL 3.1.4
|
||||||
|
ENV MEMCACHED_PECL 3.0.3
|
||||||
|
ENV APCU_PECL 5.1.8
|
||||||
|
ENV IMAGICK_PECL 3.4.3
|
||||||
|
|
||||||
RUN apk add -U --no-cache libxml2-dev \
|
RUN apk add -U --no-cache libxml2-dev \
|
||||||
icu-dev \
|
icu-dev \
|
||||||
|
imap-dev \
|
||||||
|
libmemcached-dev \
|
||||||
|
cyrus-sasl-dev \
|
||||||
|
pcre-dev \
|
||||||
icu-libs \
|
icu-libs \
|
||||||
redis \
|
redis \
|
||||||
mysql-client \
|
mysql-client \
|
||||||
|
@ -11,13 +20,42 @@ RUN apk add -U --no-cache libxml2-dev \
|
||||||
g++ \
|
g++ \
|
||||||
make \
|
make \
|
||||||
openssl \
|
openssl \
|
||||||
&& pecl install redis \
|
openssl-dev \
|
||||||
|
samba-client \
|
||||||
|
libpng \
|
||||||
|
libpng-dev \
|
||||||
|
libjpeg-turbo-dev \
|
||||||
|
libwebp-dev \
|
||||||
|
zlib-dev \
|
||||||
|
libxpm-dev \
|
||||||
|
c-client \
|
||||||
|
imagemagick-dev \
|
||||||
|
imagemagick \
|
||||||
|
libtool \
|
||||||
|
librsvg \
|
||||||
|
&& pear install channel://pear.php.net/Net_IDNA2-0.2.0 \
|
||||||
|
channel://pear.php.net/Auth_SASL-1.1.0 \
|
||||||
|
Net_IMAP \
|
||||||
|
NET_SMTP \
|
||||||
|
Mail_mime \
|
||||||
|
&& pecl install redis-${REDIS_PECL} memcached-${MEMCACHED_PECL} APCu-${APCU_PECL} imagick-${IMAGICK_PECL} \
|
||||||
|
&& docker-php-ext-enable redis apcu memcached imagick \
|
||||||
&& pecl clear-cache \
|
&& pecl clear-cache \
|
||||||
&& docker-php-ext-configure intl \
|
&& docker-php-ext-configure intl \
|
||||||
&& docker-php-ext-install intl pdo pdo_mysql xmlrpc \
|
&& docker-php-ext-install -j 4 intl pdo pdo_mysql xmlrpc gd zip pcntl opcache \
|
||||||
&& docker-php-ext-enable redis \
|
&& docker-php-ext-configure imap --with-imap --with-imap-ssl \
|
||||||
&& pear install channel://pear.php.net/Net_IDNA2-0.1.1 Auth_SASL Net_IMAP NET_SMTP Net_IDNA2 Mail_mime \
|
&& docker-php-ext-install -j 4 imap \
|
||||||
&& apk del autoconf g++ make libxml2-dev icu-dev
|
&& apk del --purge autoconf g++ make libxml2-dev icu-dev imap-dev openssl-dev cyrus-sasl-dev pcre-dev libpng-dev libpng-dev libjpeg-turbo-dev libwebp-dev zlib-dev imagemagick-dev \
|
||||||
|
&& { \
|
||||||
|
echo 'opcache.enable=1'; \
|
||||||
|
echo 'opcache.enable_cli=1'; \
|
||||||
|
echo 'opcache.interned_strings_buffer=8'; \
|
||||||
|
echo 'opcache.max_accelerated_files=10000'; \
|
||||||
|
echo 'opcache.memory_consumption=128'; \
|
||||||
|
echo 'opcache.save_comments=1'; \
|
||||||
|
echo 'opcache.revalidate_freq=1'; \
|
||||||
|
} > /usr/local/etc/php/conf.d/opcache-recommended.ini
|
||||||
|
|
||||||
|
|
||||||
COPY ./docker-entrypoint.sh /
|
COPY ./docker-entrypoint.sh /
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,8 @@ trap "postfix stop" EXIT
|
||||||
|
|
||||||
[[ ! -d /opt/postfix/conf/sql/ ]] && mkdir -p /opt/postfix/conf/sql/
|
[[ ! -d /opt/postfix/conf/sql/ ]] && mkdir -p /opt/postfix/conf/sql/
|
||||||
if [[ -z $(grep null /etc/aliases) ]]; then
|
if [[ -z $(grep null /etc/aliases) ]]; then
|
||||||
echo null: /dev/null >> /etc/aliases;
|
echo null: /dev/null >> /etc/aliases;
|
||||||
newaliases;
|
newaliases;
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cat <<EOF > /opt/postfix/conf/sql/mysql_relay_recipient_maps.cf
|
cat <<EOF > /opt/postfix/conf/sql/mysql_relay_recipient_maps.cf
|
||||||
|
@ -13,7 +13,17 @@ user = ${DBUSER}
|
||||||
password = ${DBPASS}
|
password = ${DBPASS}
|
||||||
hosts = mysql
|
hosts = mysql
|
||||||
dbname = ${DBNAME}
|
dbname = ${DBNAME}
|
||||||
query = SELECT DISTINCT CASE WHEN '%d' IN (SELECT domain FROM domain WHERE relay_all_recipients=1 AND domain='%d' AND backupmx=1) THEN '%s' ELSE (SELECT goto FROM alias WHERE address='%s' AND active='1') END AS result;
|
query = SELECT DISTINCT
|
||||||
|
CASE WHEN '%d' IN (
|
||||||
|
SELECT domain FROM domain
|
||||||
|
WHERE relay_all_recipients=1
|
||||||
|
AND domain='%d'
|
||||||
|
AND backupmx=1
|
||||||
|
)
|
||||||
|
THEN '%s' ELSE (
|
||||||
|
SELECT goto FROM alias WHERE address='%s' AND active='1'
|
||||||
|
)
|
||||||
|
END AS result;
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
cat <<EOF > /opt/postfix/conf/sql/mysql_tls_enforce_in_policy.cf
|
cat <<EOF > /opt/postfix/conf/sql/mysql_tls_enforce_in_policy.cf
|
||||||
|
@ -21,7 +31,16 @@ user = ${DBUSER}
|
||||||
password = ${DBPASS}
|
password = ${DBPASS}
|
||||||
hosts = mysql
|
hosts = mysql
|
||||||
dbname = ${DBNAME}
|
dbname = ${DBNAME}
|
||||||
query = SELECT IF( EXISTS( SELECT 'TLS_ACTIVE' FROM alias LEFT OUTER JOIN mailbox ON mailbox.username = alias.goto WHERE (address='%s' OR address IN (SELECT CONCAT('%u', '@', target_domain) FROM alias_domain WHERE alias_domain='%d')) AND mailbox.tls_enforce_in = '1' AND mailbox.active = '1'), 'reject_plaintext_session', NULL) AS 'tls_enforce_in';
|
query = SELECT IF(EXISTS(
|
||||||
|
SELECT 'TLS_ACTIVE' FROM alias
|
||||||
|
LEFT OUTER JOIN mailbox ON mailbox.username = alias.goto
|
||||||
|
WHERE (address='%s'
|
||||||
|
OR address IN (
|
||||||
|
SELECT CONCAT('%u', '@', target_domain) FROM alias_domain
|
||||||
|
WHERE alias_domain='%d'
|
||||||
|
)
|
||||||
|
) AND mailbox.tls_enforce_in = '1' AND mailbox.active = '1'
|
||||||
|
), 'reject_plaintext_session', NULL) AS 'tls_enforce_in';
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
cat <<EOF > /opt/postfix/conf/sql/mysql_sender_dependent_default_transport_maps.cf
|
cat <<EOF > /opt/postfix/conf/sql/mysql_sender_dependent_default_transport_maps.cf
|
||||||
|
@ -31,9 +50,26 @@ hosts = mysql
|
||||||
dbname = ${DBNAME}
|
dbname = ${DBNAME}
|
||||||
query = SELECT GROUP_CONCAT(transport SEPARATOR '') AS transport_maps
|
query = SELECT GROUP_CONCAT(transport SEPARATOR '') AS transport_maps
|
||||||
FROM (
|
FROM (
|
||||||
SELECT IF(EXISTS(SELECT 'smtp_type' FROM alias LEFT OUTER JOIN mailbox ON mailbox.username = alias.goto WHERE (address = '%s' OR address IN (SELECT CONCAT('%u', '@', target_domain) FROM alias_domain WHERE alias_domain = '%d')) AND mailbox.tls_enforce_out = '1' AND mailbox.active = '1'), 'smtp_enforced_tls:', 'smtp:') AS 'transport'
|
SELECT IF(EXISTS(SELECT 'smtp_type' FROM alias
|
||||||
|
LEFT OUTER JOIN mailbox ON mailbox.username = alias.goto
|
||||||
|
WHERE (address = '%s'
|
||||||
|
OR address IN (
|
||||||
|
SELECT CONCAT('%u', '@', target_domain) FROM alias_domain
|
||||||
|
WHERE alias_domain = '%d'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
AND mailbox.tls_enforce_out = '1'
|
||||||
|
AND mailbox.active = '1'
|
||||||
|
), 'smtp_enforced_tls:', 'smtp:') AS 'transport'
|
||||||
UNION ALL
|
UNION ALL
|
||||||
SELECT hostname AS transport FROM relayhosts LEFT OUTER JOIN domain ON domain.relayhost = relayhosts.id WHERE relayhosts.active = '1' AND domain = '%d' OR domain IN (SELECT target_domain FROM alias_domain WHERE alias_domain = '%d')
|
SELECT hostname AS transport FROM relayhosts
|
||||||
|
LEFT OUTER JOIN domain ON domain.relayhost = relayhosts.id
|
||||||
|
WHERE relayhosts.active = '1'
|
||||||
|
AND domain = '%d'
|
||||||
|
OR domain IN (
|
||||||
|
SELECT target_domain FROM alias_domain
|
||||||
|
WHERE alias_domain = '%d'
|
||||||
|
)
|
||||||
)
|
)
|
||||||
AS transport_view;
|
AS transport_view;
|
||||||
EOF
|
EOF
|
||||||
|
@ -43,7 +79,11 @@ user = ${DBUSER}
|
||||||
password = ${DBPASS}
|
password = ${DBPASS}
|
||||||
hosts = mysql
|
hosts = mysql
|
||||||
dbname = ${DBNAME}
|
dbname = ${DBNAME}
|
||||||
query = SELECT CONCAT_WS(':', username, password) AS auth_data FROM relayhosts WHERE id IN (SELECT relayhost FROM domain WHERE CONCAT('@', domain) = '%s');
|
query = SELECT CONCAT_WS(':', username, password) AS auth_data FROM relayhosts
|
||||||
|
WHERE id IN (
|
||||||
|
SELECT relayhost FROM domain
|
||||||
|
WHERE CONCAT('@', domain) = '%s'
|
||||||
|
);
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_alias_domain_catchall_maps.cf
|
cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_alias_domain_catchall_maps.cf
|
||||||
|
@ -51,7 +91,10 @@ user = ${DBUSER}
|
||||||
password = ${DBPASS}
|
password = ${DBPASS}
|
||||||
hosts = mysql
|
hosts = mysql
|
||||||
dbname = ${DBNAME}
|
dbname = ${DBNAME}
|
||||||
query = SELECT goto FROM alias,alias_domain WHERE alias_domain.alias_domain = '%d' and alias.address = CONCAT('@', alias_domain.target_domain) AND alias.active = 1 AND alias_domain.active='1'
|
query = SELECT goto FROM alias, alias_domain
|
||||||
|
WHERE alias_domain.alias_domain = '%d'
|
||||||
|
AND alias.address = CONCAT('@', alias_domain.target_domain)
|
||||||
|
AND alias.active = 1 AND alias_domain.active='1'
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_alias_domain_maps.cf
|
cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_alias_domain_maps.cf
|
||||||
|
@ -59,7 +102,11 @@ user = ${DBUSER}
|
||||||
password = ${DBPASS}
|
password = ${DBPASS}
|
||||||
hosts = mysql
|
hosts = mysql
|
||||||
dbname = ${DBNAME}
|
dbname = ${DBNAME}
|
||||||
query = SELECT username FROM mailbox,alias_domain WHERE alias_domain.alias_domain = '%d' and mailbox.username = CONCAT('%u', '@', alias_domain.target_domain) AND mailbox.active = 1 AND alias_domain.active='1'
|
query = SELECT username FROM mailbox, alias_domain
|
||||||
|
WHERE alias_domain.alias_domain = '%d'
|
||||||
|
AND mailbox.username = CONCAT('%u', '@', alias_domain.target_domain)
|
||||||
|
AND mailbox.active = '1'
|
||||||
|
AND alias_domain.active='1'
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_alias_maps.cf
|
cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_alias_maps.cf
|
||||||
|
@ -67,7 +114,9 @@ user = ${DBUSER}
|
||||||
password = ${DBPASS}
|
password = ${DBPASS}
|
||||||
hosts = mysql
|
hosts = mysql
|
||||||
dbname = ${DBNAME}
|
dbname = ${DBNAME}
|
||||||
query = SELECT goto FROM alias WHERE address='%s' AND active='1';
|
query = SELECT goto FROM alias
|
||||||
|
WHERE address='%s'
|
||||||
|
AND active='1';
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_domains_maps.cf
|
cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_domains_maps.cf
|
||||||
|
@ -75,7 +124,12 @@ user = ${DBUSER}
|
||||||
password = ${DBPASS}
|
password = ${DBPASS}
|
||||||
hosts = mysql
|
hosts = mysql
|
||||||
dbname = ${DBNAME}
|
dbname = ${DBNAME}
|
||||||
query = SELECT alias_domain from alias_domain WHERE alias_domain='%s' AND active='1' UNION SELECT domain FROM domain WHERE domain='%s' AND active = '1' AND backupmx = '0'
|
query = SELECT alias_domain from alias_domain WHERE alias_domain='%s' AND active='1'
|
||||||
|
UNION
|
||||||
|
SELECT domain FROM domain
|
||||||
|
WHERE domain='%s'
|
||||||
|
AND active = '1'
|
||||||
|
AND backupmx = '0'
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_mailbox_maps.cf
|
cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_mailbox_maps.cf
|
||||||
|
@ -99,7 +153,39 @@ user = ${DBUSER}
|
||||||
password = ${DBPASS}
|
password = ${DBPASS}
|
||||||
hosts = mysql
|
hosts = mysql
|
||||||
dbname = ${DBNAME}
|
dbname = ${DBNAME}
|
||||||
query = SELECT goto FROM alias WHERE address='%s' AND active='1' AND (domain IN (SELECT domain FROM domain WHERE domain='%d' AND active='1') OR domain in (SELECT target_domain FROM alias_domain WHERE alias_domain='%d' AND active='1')) UNION SELECT logged_in_as FROM sender_acl WHERE send_as='@%d' OR send_as='%s' OR send_as IN ( SELECT CONCAT ('@',target_domain) FROM alias_domain WHERE alias_domain = '%d') OR send_as IN ( SELECT CONCAT ('%u','@',target_domain) FROM alias_domain WHERE alias_domain = '%d' ) AND logged_in_as NOT IN (SELECT goto FROM alias WHERE address='%s') UNION SELECT username FROM mailbox,alias_domain WHERE alias_domain.alias_domain = '%d' AND mailbox.username = CONCAT('%u','@',alias_domain.target_domain) AND mailbox.active ='1' AND alias_domain.active='1'
|
# First select queries domain and alias_domain to determine if domains are active.
|
||||||
|
query = SELECT goto FROM alias
|
||||||
|
WHERE address='%s'
|
||||||
|
AND active='1'
|
||||||
|
AND (domain IN
|
||||||
|
(SELECT domain FROM domain
|
||||||
|
WHERE domain='%d'
|
||||||
|
AND active='1')
|
||||||
|
OR domain in (
|
||||||
|
SELECT alias_domain FROM alias_domain
|
||||||
|
WHERE alias_domain='%d'
|
||||||
|
AND active='1'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
UNION
|
||||||
|
SELECT logged_in_as FROM sender_acl
|
||||||
|
WHERE send_as='@%d'
|
||||||
|
OR send_as='%s'
|
||||||
|
OR send_as IN (
|
||||||
|
SELECT CONCAT('@',target_domain) FROM alias_domain
|
||||||
|
WHERE alias_domain = '%d')
|
||||||
|
OR send_as IN (
|
||||||
|
SELECT CONCAT('%u','@',target_domain) FROM alias_domain
|
||||||
|
WHERE alias_domain = '%d')
|
||||||
|
AND logged_in_as NOT IN (
|
||||||
|
SELECT goto FROM alias
|
||||||
|
WHERE address='%s')
|
||||||
|
UNION
|
||||||
|
SELECT username FROM mailbox, alias_domain
|
||||||
|
WHERE alias_domain.alias_domain = '%d'
|
||||||
|
AND mailbox.username = CONCAT('%u','@',alias_domain.target_domain)
|
||||||
|
AND mailbox.active ='1'
|
||||||
|
AND alias_domain.active='1'
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_spamalias_maps.cf
|
cat <<EOF > /opt/postfix/conf/sql/mysql_virtual_spamalias_maps.cf
|
||||||
|
@ -107,7 +193,9 @@ user = ${DBUSER}
|
||||||
password = ${DBPASS}
|
password = ${DBPASS}
|
||||||
hosts = mysql
|
hosts = mysql
|
||||||
dbname = ${DBNAME}
|
dbname = ${DBNAME}
|
||||||
query = SELECT goto FROM spamalias WHERE address='%s' AND validity >= UNIX_TIMESTAMP()
|
query = SELECT goto FROM spamalias
|
||||||
|
WHERE address='%s'
|
||||||
|
AND validity >= UNIX_TIMESTAMP()
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Reset GPG key permissions
|
# Reset GPG key permissions
|
||||||
|
@ -124,9 +212,9 @@ postfix set-permissions
|
||||||
postconf -c /opt/postfix/conf
|
postconf -c /opt/postfix/conf
|
||||||
|
|
||||||
if [[ $? != 0 ]]; then
|
if [[ $? != 0 ]]; then
|
||||||
echo "Postfix configuration error, refusing to start."
|
echo "Postfix configuration error, refusing to start."
|
||||||
exit 1
|
exit 1
|
||||||
else
|
else
|
||||||
postfix -c /opt/postfix/conf start
|
postfix -c /opt/postfix/conf start
|
||||||
sleep 126144000
|
sleep 126144000
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
[supervisord]
|
[supervisord]
|
||||||
nodaemon=true
|
nodaemon=true
|
||||||
|
user=root
|
||||||
|
|
||||||
[program:syslog-ng]
|
[program:syslog-ng]
|
||||||
command=/usr/sbin/syslog-ng --foreground --no-caps
|
command=/usr/sbin/syslog-ng --foreground --no-caps
|
||||||
|
@ -12,14 +13,3 @@ autostart=true
|
||||||
[program:postfix]
|
[program:postfix]
|
||||||
command=/opt/postfix.sh
|
command=/opt/postfix.sh
|
||||||
autorestart=true
|
autorestart=true
|
||||||
|
|
||||||
[unix_http_server]
|
|
||||||
file=/var/tmp/supervisord.sock
|
|
||||||
chmod=0770
|
|
||||||
chown=nobody:nogroup
|
|
||||||
|
|
||||||
[supervisorctl]
|
|
||||||
serverurl=unix:///var/tmp/supervisord.sock
|
|
||||||
|
|
||||||
[rpcinterface:supervisor]
|
|
||||||
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
|
|
||||||
|
|
|
@ -39,8 +39,10 @@ destination d_redis_cleanup {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
filter f_mail { facility(mail); };
|
filter f_mail { facility(mail); };
|
||||||
|
filter f_skip_local { not facility (local0, local1, local2, local3, local4, local5, local6, local7); };
|
||||||
log {
|
log {
|
||||||
source(s_src);
|
source(s_src);
|
||||||
|
filter(f_skip_local);
|
||||||
destination(d_stdout);
|
destination(d_stdout);
|
||||||
filter(f_mail);
|
filter(f_mail);
|
||||||
destination(d_redis_ui_log);
|
destination(d_redis_ui_log);
|
||||||
|
|
|
@ -22,7 +22,8 @@ COPY settings.conf /etc/rspamd/modules.d/settings.conf
|
||||||
#COPY ratelimit.lua /usr/share/rspamd/lua/ratelimit.lua
|
#COPY ratelimit.lua /usr/share/rspamd/lua/ratelimit.lua
|
||||||
#COPY lua_util.lua /usr/share/rspamd/lib/lua_util.lua
|
#COPY lua_util.lua /usr/share/rspamd/lib/lua_util.lua
|
||||||
COPY docker-entrypoint.sh /docker-entrypoint.sh
|
COPY docker-entrypoint.sh /docker-entrypoint.sh
|
||||||
|
COPY tini /sbin/tini
|
||||||
|
|
||||||
ENTRYPOINT ["/docker-entrypoint.sh"]
|
ENTRYPOINT ["/docker-entrypoint.sh"]
|
||||||
|
|
||||||
CMD /usr/bin/rspamd -f -u _rspamd -g _rspamd
|
CMD ["/usr/bin/rspamd", "-f", "-u", "_rspamd", "-g", "_rspamd"]
|
||||||
|
|
|
@ -2,4 +2,4 @@
|
||||||
|
|
||||||
chown -R _rspamd:_rspamd /var/lib/rspamd
|
chown -R _rspamd:_rspamd /var/lib/rspamd
|
||||||
|
|
||||||
exec "$@"
|
exec /sbin/tini -- "$@"
|
||||||
|
|
Binary file not shown.
|
@ -28,8 +28,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
|
||||||
RUN mkdir /usr/share/doc/sogo \
|
RUN mkdir /usr/share/doc/sogo \
|
||||||
&& touch /usr/share/doc/sogo/empty.sh \
|
&& touch /usr/share/doc/sogo/empty.sh \
|
||||||
&& apt-key adv --keyserver sks.labs.nic.cz --recv-key A04BE668 \
|
&& apt-key adv --keyserver keys.gnupg.net --recv-key 0x810273C4 \
|
||||||
&& echo "deb http://www.axis.cz/linux/debian stretch sogo-v3" > /etc/apt/sources.list.d/sogo.list \
|
&& echo "deb http://packages.inverse.ca/SOGo/nightly/3/debian/ stretch stretch" > /etc/apt/sources.list.d/sogo.list \
|
||||||
&& apt-get update && apt-get install -y --force-yes \
|
&& apt-get update && apt-get install -y --force-yes \
|
||||||
sogo \
|
sogo \
|
||||||
sogo-activesync \
|
sogo-activesync \
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
[supervisord]
|
[supervisord]
|
||||||
nodaemon=true
|
nodaemon=true
|
||||||
|
user=root
|
||||||
|
|
||||||
[program:syslog-ng]
|
[program:syslog-ng]
|
||||||
command=/usr/sbin/syslog-ng --foreground --no-caps
|
command=/usr/sbin/syslog-ng --foreground --no-caps
|
||||||
|
@ -32,12 +33,3 @@ priority=3
|
||||||
startretries=10
|
startretries=10
|
||||||
autorestart=true
|
autorestart=true
|
||||||
stopwaitsecs=120
|
stopwaitsecs=120
|
||||||
|
|
||||||
[inet_http_server]
|
|
||||||
port=9191
|
|
||||||
|
|
||||||
[rpcinterface:supervisor]
|
|
||||||
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
|
|
||||||
|
|
||||||
[supervisorctl]
|
|
||||||
serverurl=http://localhost:9191
|
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
FROM alpine:3.6
|
||||||
|
LABEL maintainer "André Peters <andre.peters@servercow.de>"
|
||||||
|
|
||||||
|
# Installation
|
||||||
|
RUN apk add --update \
|
||||||
|
&& apk add --no-cache nagios-plugins-smtp \
|
||||||
|
nagios-plugins-tcp \
|
||||||
|
nagios-plugins-http \
|
||||||
|
nagios-plugins-ping \
|
||||||
|
curl \
|
||||||
|
bash \
|
||||||
|
jq \
|
||||||
|
fcgi \
|
||||||
|
nagios-plugins-mysql \
|
||||||
|
nagios-plugins-dns \
|
||||||
|
nagios-plugins-disk \
|
||||||
|
bind-tools \
|
||||||
|
redis \
|
||||||
|
perl \
|
||||||
|
perl-io-socket-ssl \
|
||||||
|
perl-socket \
|
||||||
|
perl-socket6 \
|
||||||
|
perl-mime-lite \
|
||||||
|
perl-term-readkey \
|
||||||
|
tini \
|
||||||
|
&& curl https://raw.githubusercontent.com/mludvig/smtp-cli/v3.8/smtp-cli -o /smtp-cli \
|
||||||
|
&& chmod +x smtp-cli
|
||||||
|
|
||||||
|
COPY watchdog.sh /watchdog.sh
|
||||||
|
|
||||||
|
ENTRYPOINT ["/sbin/tini", "-g", "--"]
|
||||||
|
# Less verbose
|
||||||
|
CMD /watchdog.sh 2> /dev/null
|
Binary file not shown.
|
@ -0,0 +1,381 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
trap "exit" INT TERM
|
||||||
|
trap "kill 0" EXIT
|
||||||
|
|
||||||
|
# Prepare
|
||||||
|
BACKGROUND_TASKS=()
|
||||||
|
|
||||||
|
if [[ "${USE_WATCHDOG}" =~ ^([nN][oO]|[nN])+$ ]]; then
|
||||||
|
echo -e "$(date) - USE_WATCHDOG=n, skipping watchdog..."
|
||||||
|
sleep 365d
|
||||||
|
exec $(readlink -f "$0")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Checks pipe their corresponding container name in this pipe
|
||||||
|
if [[ ! -p /tmp/com_pipe ]]; then
|
||||||
|
mkfifo /tmp/com_pipe
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Common functions
|
||||||
|
progress() {
|
||||||
|
SERVICE=${1}
|
||||||
|
TOTAL=${2}
|
||||||
|
CURRENT=${3}
|
||||||
|
DIFF=${4}
|
||||||
|
[[ -z ${DIFF} ]] && DIFF=0
|
||||||
|
[[ -z ${TOTAL} || -z ${CURRENT} ]] && return
|
||||||
|
[[ ${CURRENT} -gt ${TOTAL} ]] && return
|
||||||
|
[[ ${CURRENT} -lt 0 ]] && CURRENT=0
|
||||||
|
PERCENT=$(( 200 * ${CURRENT} / ${TOTAL} % 2 + 100 * ${CURRENT} / ${TOTAL} ))
|
||||||
|
echo -ne "$(date) - ${SERVICE} health level: \e[7m${PERCENT}%\e[0m (${CURRENT}/${TOTAL}), health trend: "
|
||||||
|
[[ ${DIFF} =~ ^-[1-9] ]] && echo -en '[\e[41m \e[0m] ' || echo -en '[\e[42m \e[0m] '
|
||||||
|
echo "(${DIFF})"
|
||||||
|
}
|
||||||
|
|
||||||
|
log_to_redis() {
|
||||||
|
redis-cli -h redis LPUSH WATCHDOG_LOG "{\"time\":\"$(date +%s)\",\"message\":\"$(printf '%s' "${1}")\"}"
|
||||||
|
}
|
||||||
|
|
||||||
|
function mail_error() {
|
||||||
|
[[ -z ${1} ]] && return 1
|
||||||
|
[[ -z ${2} ]] && return 2
|
||||||
|
RCPT_DOMAIN=$(echo ${1} | awk -F @ {'print $NF'})
|
||||||
|
RCPT_MX=$(dig +short ${RCPT_DOMAIN} mx | sort -n | awk '{print $2; exit}')
|
||||||
|
if [[ -z ${RCPT_MX} ]]; then
|
||||||
|
log_to_redis "Cannot determine MX for ${1}, skipping email notification..."
|
||||||
|
echo "Cannot determine MX for ${1}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
./smtp-cli --missing-modules-ok \
|
||||||
|
--subject="Watchdog: ${2} service hit the error rate limit" \
|
||||||
|
--body-plain="Service was restarted, please check your mailcow installation." \
|
||||||
|
--to=${1} \
|
||||||
|
--from="watchdog@${MAILCOW_HOSTNAME}" \
|
||||||
|
--server="${RCPT_MX}" \
|
||||||
|
--hello-host=${MAILCOW_HOSTNAME}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
get_container_ip() {
|
||||||
|
# ${1} is container
|
||||||
|
CONTAINER_ID=
|
||||||
|
CONTAINER_IP=
|
||||||
|
LOOP_C=1
|
||||||
|
until [[ ${CONTAINER_IP} =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]] || [[ ${LOOP_C} -gt 5 ]]; do
|
||||||
|
sleep 1
|
||||||
|
CONTAINER_ID=$(curl --silent http://dockerapi:8080/containers/json | jq -r ".[] | {name: .Config.Labels[\"com.docker.compose.service\"], id: .Id}" | jq -rc "select( .name | tostring | contains(\"${1}\")) | .id")
|
||||||
|
if [[ ! -z ${CONTAINER_ID} ]]; then
|
||||||
|
CONTAINER_IP=$(curl --silent http://dockerapi:8080/containers/${CONTAINER_ID}/json | jq -r '.NetworkSettings.Networks[].IPAddress')
|
||||||
|
fi
|
||||||
|
LOOP_C=$((LOOP_C + 1))
|
||||||
|
done
|
||||||
|
[[ ${LOOP_C} -gt 5 ]] && echo 240.0.0.0 || echo ${CONTAINER_IP}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check functions
|
||||||
|
nginx_checks() {
|
||||||
|
err_count=0
|
||||||
|
diff_c=0
|
||||||
|
THRESHOLD=16
|
||||||
|
# Reduce error count by 2 after restarting an unhealthy container
|
||||||
|
trap "[ ${err_count} -gt 1 ] && err_count=$(( ${err_count} - 2 ))" USR1
|
||||||
|
while [ ${err_count} -lt ${THRESHOLD} ]; do
|
||||||
|
host_ip=$(get_container_ip nginx-mailcow)
|
||||||
|
err_c_cur=${err_count}
|
||||||
|
/usr/lib/nagios/plugins/check_ping -4 -H ${host_ip} -w 2000,10% -c 4000,100% -p2 1>&2; err_count=$(( ${err_count} + $? ))
|
||||||
|
/usr/lib/nagios/plugins/check_http -4 -H ${host_ip} -u / -p 8081 1>&2; err_count=$(( ${err_count} + $? ))
|
||||||
|
[ ${err_c_cur} -eq ${err_count} ] && [ ! $((${err_count} - 1)) -lt 0 ] && err_count=$((${err_count} - 1)) diff_c=1
|
||||||
|
[ ${err_c_cur} -ne ${err_count} ] && diff_c=$(( ${err_c_cur} - ${err_count} ))
|
||||||
|
progress "Nginx" ${THRESHOLD} $(( ${THRESHOLD} - ${err_count} )) ${diff_c}
|
||||||
|
diff_c=0
|
||||||
|
sleep $(( ( RANDOM % 30 ) + 10 ))
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
mysql_checks() {
|
||||||
|
err_count=0
|
||||||
|
diff_c=0
|
||||||
|
THRESHOLD=12
|
||||||
|
# Reduce error count by 2 after restarting an unhealthy container
|
||||||
|
trap "[ ${err_count} -gt 1 ] && err_count=$(( ${err_count} - 2 ))" USR1
|
||||||
|
while [ ${err_count} -lt ${THRESHOLD} ]; do
|
||||||
|
host_ip=$(get_container_ip mysql-mailcow)
|
||||||
|
err_c_cur=${err_count}
|
||||||
|
/usr/lib/nagios/plugins/check_mysql -H ${host_ip} -P 3306 -u ${DBUSER} -p ${DBPASS} -d ${DBNAME} 1>&2; err_count=$(( ${err_count} + $? ))
|
||||||
|
/usr/lib/nagios/plugins/check_mysql_query -H ${host_ip} -P 3306 -u ${DBUSER} -p ${DBPASS} -d ${DBNAME} -q "SELECT COUNT(*) FROM information_schema.tables" 1>&2; err_count=$(( ${err_count} + $? ))
|
||||||
|
[ ${err_c_cur} -eq ${err_count} ] && [ ! $((${err_count} - 1)) -lt 0 ] && err_count=$((${err_count} - 1)) diff_c=1
|
||||||
|
[ ${err_c_cur} -ne ${err_count} ] && diff_c=$(( ${err_c_cur} - ${err_count} ))
|
||||||
|
progress "MySQL/MariaDB" ${THRESHOLD} $(( ${THRESHOLD} - ${err_count} )) ${diff_c}
|
||||||
|
diff_c=0
|
||||||
|
sleep $(( ( RANDOM % 30 ) + 10 ))
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
sogo_checks() {
|
||||||
|
err_count=0
|
||||||
|
diff_c=0
|
||||||
|
THRESHOLD=20
|
||||||
|
# Reduce error count by 2 after restarting an unhealthy container
|
||||||
|
trap "[ ${err_count} -gt 1 ] && err_count=$(( ${err_count} - 2 ))" USR1
|
||||||
|
while [ ${err_count} -lt ${THRESHOLD} ]; do
|
||||||
|
host_ip=$(get_container_ip sogo-mailcow)
|
||||||
|
err_c_cur=${err_count}
|
||||||
|
/usr/lib/nagios/plugins/check_http -4 -H ${host_ip} -u /WebServerResources/css/theme-default.css -p 9192 -R md-default-theme 1>&2; err_count=$(( ${err_count} + $? ))
|
||||||
|
/usr/lib/nagios/plugins/check_http -4 -H ${host_ip} -u /SOGo.index/ -p 20000 -R "SOGo\sGroupware" 1>&2; err_count=$(( ${err_count} + $? ))
|
||||||
|
[ ${err_c_cur} -eq ${err_count} ] && [ ! $((${err_count} - 1)) -lt 0 ] && err_count=$((${err_count} - 1)) diff_c=1
|
||||||
|
[ ${err_c_cur} -ne ${err_count} ] && diff_c=$(( ${err_c_cur} - ${err_count} ))
|
||||||
|
progress "SOGo" ${THRESHOLD} $(( ${THRESHOLD} - ${err_count} )) ${diff_c}
|
||||||
|
diff_c=0
|
||||||
|
sleep $(( ( RANDOM % 30 ) + 10 ))
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
postfix_checks() {
|
||||||
|
err_count=0
|
||||||
|
diff_c=0
|
||||||
|
THRESHOLD=16
|
||||||
|
# Reduce error count by 2 after restarting an unhealthy container
|
||||||
|
trap "[ ${err_count} -gt 1 ] && err_count=$(( ${err_count} - 2 ))" USR1
|
||||||
|
while [ ${err_count} -lt ${THRESHOLD} ]; do
|
||||||
|
host_ip=$(get_container_ip postfix-mailcow)
|
||||||
|
err_c_cur=${err_count}
|
||||||
|
/usr/lib/nagios/plugins/check_smtp -4 -H ${host_ip} -p 589 -f watchdog -C "RCPT TO:null@localhost" -C DATA -C . -R 250 1>&2; err_count=$(( ${err_count} + $? ))
|
||||||
|
/usr/lib/nagios/plugins/check_smtp -4 -H ${host_ip} -p 589 -S 1>&2; err_count=$(( ${err_count} + $? ))
|
||||||
|
[ ${err_c_cur} -eq ${err_count} ] && [ ! $((${err_count} - 1)) -lt 0 ] && err_count=$((${err_count} - 1)) diff_c=1
|
||||||
|
[ ${err_c_cur} -ne ${err_count} ] && diff_c=$(( ${err_c_cur} - ${err_count} ))
|
||||||
|
progress "Postfix" ${THRESHOLD} $(( ${THRESHOLD} - ${err_count} )) ${diff_c}
|
||||||
|
diff_c=0
|
||||||
|
sleep $(( ( RANDOM % 30 ) + 10 ))
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
dovecot_checks() {
|
||||||
|
err_count=0
|
||||||
|
diff_c=0
|
||||||
|
THRESHOLD=24
|
||||||
|
# Reduce error count by 2 after restarting an unhealthy container
|
||||||
|
trap "[ ${err_count} -gt 1 ] && err_count=$(( ${err_count} - 2 ))" USR1
|
||||||
|
while [ ${err_count} -lt ${THRESHOLD} ]; do
|
||||||
|
host_ip=$(get_container_ip dovecot-mailcow)
|
||||||
|
err_c_cur=${err_count}
|
||||||
|
/usr/lib/nagios/plugins/check_smtp -4 -H ${host_ip} -p 24 -f "watchdog" -C "RCPT TO:<watchdog@invalid>" -L -R "User doesn't exist" 1>&2; err_count=$(( ${err_count} + $? ))
|
||||||
|
/usr/lib/nagios/plugins/check_imap -4 -H ${host_ip} -p 993 -S -e "OK " 1>&2; err_count=$(( ${err_count} + $? ))
|
||||||
|
/usr/lib/nagios/plugins/check_imap -4 -H ${host_ip} -p 143 -e "OK " 1>&2; err_count=$(( ${err_count} + $? ))
|
||||||
|
/usr/lib/nagios/plugins/check_tcp -4 -H ${host_ip} -p 10001 -e "VERSION" 1>&2; err_count=$(( ${err_count} + $? ))
|
||||||
|
/usr/lib/nagios/plugins/check_tcp -4 -H ${host_ip} -p 4190 -e "Dovecot ready" 1>&2; err_count=$(( ${err_count} + $? ))
|
||||||
|
[ ${err_c_cur} -eq ${err_count} ] && [ ! $((${err_count} - 1)) -lt 0 ] && err_count=$((${err_count} - 1)) diff_c=1
|
||||||
|
[ ${err_c_cur} -ne ${err_count} ] && diff_c=$(( ${err_c_cur} - ${err_count} ))
|
||||||
|
progress "Dovecot" ${THRESHOLD} $(( ${THRESHOLD} - ${err_count} )) ${diff_c}
|
||||||
|
diff_c=0
|
||||||
|
sleep $(( ( RANDOM % 30 ) + 10 ))
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
phpfpm_checks() {
|
||||||
|
err_count=0
|
||||||
|
diff_c=0
|
||||||
|
THRESHOLD=10
|
||||||
|
# Reduce error count by 2 after restarting an unhealthy container
|
||||||
|
trap "[ ${err_count} -gt 1 ] && err_count=$(( ${err_count} - 2 ))" USR1
|
||||||
|
while [ ${err_count} -lt ${THRESHOLD} ]; do
|
||||||
|
host_ip=$(get_container_ip php-fpm-mailcow)
|
||||||
|
err_c_cur=${err_count}
|
||||||
|
cgi-fcgi -bind -connect ${host_ip}:9000 | grep "Content-type" 1>&2; err_count=$(( ${err_count} + ($? * 2)))
|
||||||
|
/usr/lib/nagios/plugins/check_ping -4 -H ${host_ip} -w 2000,10% -c 4000,100% -p2 1>&2; err_count=$(( ${err_count} + $? ))
|
||||||
|
[ ${err_c_cur} -eq ${err_count} ] && [ ! $((${err_count} - 1)) -lt 0 ] && err_count=$((${err_count} - 1)) diff_c=1
|
||||||
|
[ ${err_c_cur} -ne ${err_count} ] && diff_c=$(( ${err_c_cur} - ${err_count} ))
|
||||||
|
progress "PHP-FPM" ${THRESHOLD} $(( ${THRESHOLD} - ${err_count} )) ${diff_c}
|
||||||
|
diff_c=0
|
||||||
|
sleep $(( ( RANDOM % 30 ) + 10 ))
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
rspamd_checks() {
|
||||||
|
err_count=0
|
||||||
|
diff_c=0
|
||||||
|
THRESHOLD=10
|
||||||
|
# Reduce error count by 2 after restarting an unhealthy container
|
||||||
|
trap "[ ${err_count} -gt 1 ] && err_count=$(( ${err_count} - 2 ))" USR1
|
||||||
|
while [ ${err_count} -lt ${THRESHOLD} ]; do
|
||||||
|
host_ip=$(get_container_ip rspamd-mailcow)
|
||||||
|
err_c_cur=${err_count}
|
||||||
|
SCORE=$(curl --silent ${host_ip}:11333/scan -d '
|
||||||
|
To: null@localhost
|
||||||
|
From: watchdog@localhost
|
||||||
|
|
||||||
|
Empty
|
||||||
|
' | jq -rc .required_score)
|
||||||
|
if [[ ${SCORE} != "9999" ]]; then
|
||||||
|
echo "Rspamd settings check failed" 1>&2
|
||||||
|
err_count=$(( ${err_count} + 1))
|
||||||
|
else
|
||||||
|
echo "Rspamd settings check succeeded" 1>&2
|
||||||
|
fi
|
||||||
|
/usr/lib/nagios/plugins/check_ping -4 -H ${host_ip} -w 2000,10% -c 4000,100% -p2 1>&2; err_count=$(( ${err_count} + $? ))
|
||||||
|
[ ${err_c_cur} -eq ${err_count} ] && [ ! $((${err_count} - 1)) -lt 0 ] && err_count=$((${err_count} - 1)) diff_c=1
|
||||||
|
[ ${err_c_cur} -ne ${err_count} ] && diff_c=$(( ${err_c_cur} - ${err_count} ))
|
||||||
|
progress "Rspamd" ${THRESHOLD} $(( ${THRESHOLD} - ${err_count} )) ${diff_c}
|
||||||
|
diff_c=0
|
||||||
|
sleep $(( ( RANDOM % 30 ) + 10 ))
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
dns_checks() {
|
||||||
|
err_count=0
|
||||||
|
diff_c=0
|
||||||
|
THRESHOLD=28
|
||||||
|
# Reduce error count by 2 after restarting an unhealthy container
|
||||||
|
trap "[ ${err_count} -gt 1 ] && err_count=$(( ${err_count} - 2 ))" USR1
|
||||||
|
while [ ${err_count} -lt ${THRESHOLD} ]; do
|
||||||
|
host_ip=$(get_container_ip unbound-mailcow)
|
||||||
|
err_c_cur=${err_count}
|
||||||
|
/usr/lib/nagios/plugins/check_dns -H google.com 1>&2; err_count=$(( ${err_count} + ($? * 2)))
|
||||||
|
/usr/lib/nagios/plugins/check_dns -s ${host_ip} -H google.com 1>&2; err_count=$(( ${err_count} + ($? * 2)))
|
||||||
|
dig +dnssec org. @${host_ip} | grep -E 'flags:.+ad' 1>&2; err_count=$(( ${err_count} + ($? * 2)))
|
||||||
|
[ ${err_c_cur} -eq ${err_count} ] && [ ! $((${err_count} - 1)) -lt 0 ] && err_count=$((${err_count} - 1)) diff_c=1
|
||||||
|
[ ${err_c_cur} -ne ${err_count} ] && diff_c=$(( ${err_c_cur} - ${err_count} ))
|
||||||
|
progress "Unbound" ${THRESHOLD} $(( ${THRESHOLD} - ${err_count} )) ${diff_c}
|
||||||
|
diff_c=0
|
||||||
|
sleep $(( ( RANDOM % 30 ) + 10 ))
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create watchdog agents
|
||||||
|
(
|
||||||
|
while true; do
|
||||||
|
if ! nginx_checks; then
|
||||||
|
log_to_redis "Nginx hit error limit"
|
||||||
|
[[ ! -z ${WATCHDOG_NOTIFY_EMAIL} ]] && mail_error "${WATCHDOG_NOTIFY_EMAIL}" "nginx-mailcow"
|
||||||
|
echo -e "\e[31m$(date) - Nginx hit error limit\e[0m"
|
||||||
|
echo nginx-mailcow > /tmp/com_pipe
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
) &
|
||||||
|
BACKGROUND_TASKS+=($!)
|
||||||
|
|
||||||
|
(
|
||||||
|
while true; do
|
||||||
|
if ! mysql_checks; then
|
||||||
|
log_to_redis "MySQL hit error limit"
|
||||||
|
[[ ! -z ${WATCHDOG_NOTIFY_EMAIL} ]] && mail_error "${WATCHDOG_NOTIFY_EMAIL}" "mysql-mailcow"
|
||||||
|
echo -e "\e[31m$(date) - MySQL hit error limit\e[0m"
|
||||||
|
echo mysql-mailcow > /tmp/com_pipe
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
) &
|
||||||
|
BACKGROUND_TASKS+=($!)
|
||||||
|
|
||||||
|
(
|
||||||
|
while true; do
|
||||||
|
if ! phpfpm_checks; then
|
||||||
|
log_to_redis "PHP-FPM hit error limit"
|
||||||
|
[[ ! -z ${WATCHDOG_NOTIFY_EMAIL} ]] && mail_error "${WATCHDOG_NOTIFY_EMAIL}" "php-fpm-mailcow"
|
||||||
|
echo -e "\e[31m$(date) - PHP-FPM hit error limit\e[0m"
|
||||||
|
echo php-fpm-mailcow > /tmp/com_pipe
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
) &
|
||||||
|
BACKGROUND_TASKS+=($!)
|
||||||
|
|
||||||
|
(
|
||||||
|
while true; do
|
||||||
|
if ! sogo_checks; then
|
||||||
|
log_to_redis "SOGo hit error limit"
|
||||||
|
[[ ! -z ${WATCHDOG_NOTIFY_EMAIL} ]] && mail_error "${WATCHDOG_NOTIFY_EMAIL}" "sogo-mailcow"
|
||||||
|
echo -e "\e[31m$(date) - SOGo hit error limit\e[0m"
|
||||||
|
echo sogo-mailcow > /tmp/com_pipe
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
) &
|
||||||
|
BACKGROUND_TASKS+=($!)
|
||||||
|
|
||||||
|
(
|
||||||
|
while true; do
|
||||||
|
if ! postfix_checks; then
|
||||||
|
log_to_redis "Postfix hit error limit"
|
||||||
|
[[ ! -z ${WATCHDOG_NOTIFY_EMAIL} ]] && mail_error "${WATCHDOG_NOTIFY_EMAIL}" "postfix-mailcow"
|
||||||
|
echo -e "\e[31m$(date) - Postfix hit error limit\e[0m"
|
||||||
|
echo postfix-mailcow > /tmp/com_pipe
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
) &
|
||||||
|
BACKGROUND_TASKS+=($!)
|
||||||
|
|
||||||
|
(
|
||||||
|
while true; do
|
||||||
|
if ! dovecot_checks; then
|
||||||
|
log_to_redis "Dovecot hit error limit"
|
||||||
|
[[ ! -z ${WATCHDOG_NOTIFY_EMAIL} ]] && mail_error "${WATCHDOG_NOTIFY_EMAIL}" "dovecot-mailcow"
|
||||||
|
echo -e "\e[31m$(date) - Dovecot hit error limit\e[0m"
|
||||||
|
echo dovecot-mailcow > /tmp/com_pipe
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
) &
|
||||||
|
BACKGROUND_TASKS+=($!)
|
||||||
|
|
||||||
|
(
|
||||||
|
while true; do
|
||||||
|
if ! dns_checks; then
|
||||||
|
log_to_redis "Unbound hit error limit"
|
||||||
|
[[ ! -z ${WATCHDOG_NOTIFY_EMAIL} ]] && mail_error "${WATCHDOG_NOTIFY_EMAIL}" "unbound-mailcow"
|
||||||
|
echo -e "\e[31m$(date) - Unbound hit error limit\e[0m"
|
||||||
|
#echo unbound-mailcow > /tmp/com_pipe
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
) &
|
||||||
|
BACKGROUND_TASKS+=($!)
|
||||||
|
|
||||||
|
(
|
||||||
|
while true; do
|
||||||
|
if ! rspamd_checks; then
|
||||||
|
log_to_redis "Rspamd hit error limit"
|
||||||
|
[[ ! -z ${WATCHDOG_NOTIFY_EMAIL} ]] && mail_error "${WATCHDOG_NOTIFY_EMAIL}" "rspamd-mailcow"
|
||||||
|
echo -e "\e[31m$(date) - Rspamd hit error limit\e[0m"
|
||||||
|
echo rspamd-mailcow > /tmp/com_pipe
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
) &
|
||||||
|
BACKGROUND_TASKS+=($!)
|
||||||
|
|
||||||
|
# Monitor watchdog agents, stop script when agents fails and wait for respawn by Docker (restart:always:n)
|
||||||
|
(
|
||||||
|
while true; do
|
||||||
|
for bg_task in ${BACKGROUND_TASKS[*]}; do
|
||||||
|
if ! kill -0 ${bg_task} 1>&2; then
|
||||||
|
echo "Worker ${bg_task} died, stopping watchdog and waiting for respawn..."
|
||||||
|
log_to_redis "Worker ${bg_task} died, stopping watchdog and waiting for respawn..."
|
||||||
|
kill -TERM 1
|
||||||
|
fi
|
||||||
|
sleep 10
|
||||||
|
done
|
||||||
|
done
|
||||||
|
) &
|
||||||
|
|
||||||
|
# Restart container when threshold limit reached
|
||||||
|
while true; do
|
||||||
|
CONTAINER_ID=
|
||||||
|
read com_pipe_answer </tmp/com_pipe
|
||||||
|
if [[ ${com_pipe_answer} =~ .+-mailcow ]]; then
|
||||||
|
kill -STOP ${BACKGROUND_TASKS[*]}
|
||||||
|
sleep 3
|
||||||
|
CONTAINER_ID=$(curl --silent http://dockerapi:8080/containers/json | jq -r ".[] | {name: .Config.Labels[\"com.docker.compose.service\"], id: .Id}" | jq -rc "select( .name | tostring | contains(\"${com_pipe_answer}\")) | .id")
|
||||||
|
if [[ ! -z ${CONTAINER_ID} ]]; then
|
||||||
|
log_to_redis "Sending restart command to ${CONTAINER_ID}..."
|
||||||
|
echo "Sending restart command to ${CONTAINER_ID}..."
|
||||||
|
curl --silent -XPOST http://dockerapi:8080/containers/${CONTAINER_ID}/restart
|
||||||
|
fi
|
||||||
|
echo "Wait for restarted container to settle and continue watching..."
|
||||||
|
sleep 30s
|
||||||
|
kill -CONT ${BACKGROUND_TASKS[*]}
|
||||||
|
kill -USR1 ${BACKGROUND_TASKS[*]}
|
||||||
|
fi
|
||||||
|
done
|
|
@ -0,0 +1,186 @@
|
||||||
|
map $http_x_forwarded_proto $client_req_scheme_nc {
|
||||||
|
default $scheme;
|
||||||
|
https https;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
include /etc/nginx/conf.d/listen_ssl.active;
|
||||||
|
include /etc/nginx/mime.types;
|
||||||
|
charset utf-8;
|
||||||
|
override_charset on;
|
||||||
|
|
||||||
|
ssl on;
|
||||||
|
ssl_certificate /etc/ssl/mail/cert.pem;
|
||||||
|
ssl_certificate_key /etc/ssl/mail/key.pem;
|
||||||
|
ssl_protocols TLSv1.2;
|
||||||
|
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
|
||||||
|
ssl_prefer_server_ciphers on;
|
||||||
|
ssl_session_cache shared:SSL:50m;
|
||||||
|
ssl_session_timeout 1d;
|
||||||
|
ssl_session_tickets off;
|
||||||
|
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains";
|
||||||
|
add_header X-Content-Type-Options nosniff;
|
||||||
|
add_header X-XSS-Protection "1; mode=block";
|
||||||
|
add_header X-Robots-Tag none;
|
||||||
|
add_header X-Download-Options noopen;
|
||||||
|
add_header X-Permitted-Cross-Domain-Policies none;
|
||||||
|
|
||||||
|
server_name NC_SERVER_SUB;
|
||||||
|
|
||||||
|
root /web/nextcloud/;
|
||||||
|
|
||||||
|
location = /robots.txt {
|
||||||
|
allow all;
|
||||||
|
log_not_found off;
|
||||||
|
access_log off;
|
||||||
|
}
|
||||||
|
|
||||||
|
location = /.well-known/carddav {
|
||||||
|
return 301 $client_req_scheme_nc://$host/remote.php/dav;
|
||||||
|
}
|
||||||
|
location = /.well-known/caldav {
|
||||||
|
return 301 $client_req_scheme_nc://$host/remote.php/dav;
|
||||||
|
}
|
||||||
|
|
||||||
|
gzip on;
|
||||||
|
gzip_vary on;
|
||||||
|
gzip_comp_level 4;
|
||||||
|
gzip_min_length 256;
|
||||||
|
gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
|
||||||
|
gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
|
||||||
|
|
||||||
|
set_real_ip_from 172.22.1.1;
|
||||||
|
real_ip_header X-Forwarded-For;
|
||||||
|
real_ip_recursive on;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
rewrite ^ /index.php$uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/ {
|
||||||
|
deny all;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) {
|
||||||
|
deny all;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+)\.php(?:$|/) {
|
||||||
|
fastcgi_split_path_info ^(.+\.php)(/.*)$;
|
||||||
|
include fastcgi_params;
|
||||||
|
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||||
|
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||||
|
#Avoid sending the security headers twice
|
||||||
|
fastcgi_param modHeadersAvailable true;
|
||||||
|
fastcgi_param front_controller_active true;
|
||||||
|
fastcgi_pass phpfpm:9000;
|
||||||
|
fastcgi_intercept_errors on;
|
||||||
|
fastcgi_request_buffering off;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ ^/(?:updater|ocs-provider)(?:$|/) {
|
||||||
|
try_files $uri/ =404;
|
||||||
|
index index.php;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ \.(?:css|js|woff|svg|gif)$ {
|
||||||
|
try_files $uri /index.php$uri$is_args$args;
|
||||||
|
add_header Cache-Control "public, max-age=15778463";
|
||||||
|
add_header X-Content-Type-Options nosniff;
|
||||||
|
add_header X-XSS-Protection "1; mode=block";
|
||||||
|
add_header X-Robots-Tag none;
|
||||||
|
add_header X-Download-Options noopen;
|
||||||
|
add_header X-Permitted-Cross-Domain-Policies none;
|
||||||
|
access_log off;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ \.(?:png|html|ttf|ico|jpg|jpeg)$ {
|
||||||
|
try_files $uri /index.php$uri$is_args$args;
|
||||||
|
access_log off;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
server {
|
||||||
|
include /etc/nginx/conf.d/listen_ssl.active;
|
||||||
|
include /etc/nginx/mime.types;
|
||||||
|
charset utf-8;
|
||||||
|
override_charset on;
|
||||||
|
|
||||||
|
add_header X-Content-Type-Options nosniff;
|
||||||
|
add_header X-XSS-Protection "1; mode=block";
|
||||||
|
add_header X-Robots-Tag none;
|
||||||
|
add_header X-Download-Options noopen;
|
||||||
|
add_header X-Permitted-Cross-Domain-Policies none;
|
||||||
|
|
||||||
|
server_name NC_SERVER_SUB;
|
||||||
|
|
||||||
|
root /web/nextcloud/;
|
||||||
|
|
||||||
|
location = /robots.txt {
|
||||||
|
allow all;
|
||||||
|
log_not_found off;
|
||||||
|
access_log off;
|
||||||
|
}
|
||||||
|
|
||||||
|
location = /.well-known/carddav {
|
||||||
|
return 301 $client_req_scheme_nc://$host/remote.php/dav;
|
||||||
|
}
|
||||||
|
location = /.well-known/caldav {
|
||||||
|
return 301 $client_req_scheme_nc://$host/remote.php/dav;
|
||||||
|
}
|
||||||
|
|
||||||
|
gzip on;
|
||||||
|
gzip_vary on;
|
||||||
|
gzip_comp_level 4;
|
||||||
|
gzip_min_length 256;
|
||||||
|
gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
|
||||||
|
gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
|
||||||
|
|
||||||
|
set_real_ip_from 172.22.1.1;
|
||||||
|
real_ip_header X-Forwarded-For;
|
||||||
|
real_ip_recursive on;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
rewrite ^ /index.php$uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/ {
|
||||||
|
deny all;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) {
|
||||||
|
deny all;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+)\.php(?:$|/) {
|
||||||
|
fastcgi_split_path_info ^(.+\.php)(/.*)$;
|
||||||
|
include fastcgi_params;
|
||||||
|
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||||
|
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||||
|
fastcgi_param modHeadersAvailable true;
|
||||||
|
fastcgi_param front_controller_active true;
|
||||||
|
fastcgi_pass phpfpm:9000;
|
||||||
|
fastcgi_intercept_errors on;
|
||||||
|
fastcgi_request_buffering off;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ ^/(?:updater|ocs-provider)(?:$|/) {
|
||||||
|
try_files $uri/ =404;
|
||||||
|
index index.php;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ \.(?:css|js|woff|svg|gif)$ {
|
||||||
|
try_files $uri /index.php$uri$is_args$args;
|
||||||
|
add_header Cache-Control "public, max-age=15778463";
|
||||||
|
add_header X-Content-Type-Options nosniff;
|
||||||
|
add_header X-XSS-Protection "1; mode=block";
|
||||||
|
add_header X-Robots-Tag none;
|
||||||
|
add_header X-Download-Options noopen;
|
||||||
|
add_header X-Permitted-Cross-Domain-Policies none;
|
||||||
|
access_log off;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ \.(?:png|html|ttf|ico|jpg|jpeg)$ {
|
||||||
|
try_files $uri /index.php$uri$is_args$args;
|
||||||
|
access_log off;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
#!/bin/bash
|
||||||
|
docker exec -it -u www-data $(docker ps -f name=php-fpm-mailcow -q) /web/nextcloud/occ ${@}
|
|
@ -0,0 +1,41 @@
|
||||||
|
location ^~ /nextcloud {
|
||||||
|
location /nextcloud {
|
||||||
|
rewrite ^ /nextcloud/index.php$uri;
|
||||||
|
}
|
||||||
|
location ~ ^/nextcloud/(?:build|tests|config|lib|3rdparty|templates|data)/ {
|
||||||
|
deny all;
|
||||||
|
}
|
||||||
|
location ~ ^/nextcloud/(?:\.|autotest|occ|issue|indie|db_|console) {
|
||||||
|
deny all;
|
||||||
|
}
|
||||||
|
location ~ ^/nextcloud/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+)\.php(?:$|/) {
|
||||||
|
fastcgi_split_path_info ^(.+\.php)(/.*)$;
|
||||||
|
include fastcgi_params;
|
||||||
|
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||||
|
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||||
|
fastcgi_param HTTPS on;
|
||||||
|
fastcgi_param modHeadersAvailable true;
|
||||||
|
fastcgi_param front_controller_active true;
|
||||||
|
fastcgi_pass phpfpm:9000;
|
||||||
|
fastcgi_intercept_errors on;
|
||||||
|
fastcgi_request_buffering off;
|
||||||
|
}
|
||||||
|
location ~ ^/nextcloud/(?:updater|ocs-provider)(?:$|/) {
|
||||||
|
try_files $uri/ =404;
|
||||||
|
index index.php;
|
||||||
|
}
|
||||||
|
location ~ \.(?:css|js|woff|svg|gif)$ {
|
||||||
|
try_files $uri /nextcloud/index.php$uri$is_args$args;
|
||||||
|
add_header Cache-Control "public, max-age=15778463";
|
||||||
|
add_header X-Content-Type-Options nosniff;
|
||||||
|
add_header X-XSS-Protection "1; mode=block";
|
||||||
|
add_header X-Robots-Tag none;
|
||||||
|
add_header X-Download-Options noopen;
|
||||||
|
add_header X-Permitted-Cross-Domain-Policies none;
|
||||||
|
access_log off;
|
||||||
|
}
|
||||||
|
location ~ \.(?:png|html|ttf|ico|jpg|jpeg)$ {
|
||||||
|
try_files $uri /nextcloud/index.php$uri$is_args$args;
|
||||||
|
access_log off;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,6 @@
|
||||||
server_tokens off;
|
server_tokens off;
|
||||||
|
|
||||||
# includes to http {
|
|
||||||
proxy_cache_path /tmp levels=1:2 keys_zone=sogo:10m inactive=24h max_size=1g;
|
proxy_cache_path /tmp levels=1:2 keys_zone=sogo:10m inactive=24h max_size=1g;
|
||||||
server_names_hash_bucket_size 64;
|
server_names_hash_bucket_size 64;
|
||||||
# }
|
|
||||||
|
|
||||||
map $http_x_forwarded_proto $client_req_scheme {
|
map $http_x_forwarded_proto $client_req_scheme {
|
||||||
default $scheme;
|
default $scheme;
|
||||||
|
@ -11,7 +8,174 @@ map $http_x_forwarded_proto $client_req_scheme {
|
||||||
}
|
}
|
||||||
|
|
||||||
server {
|
server {
|
||||||
include /etc/nginx/conf.d/listen_ssl.active;
|
include /etc/nginx/mime.types;
|
||||||
|
charset utf-8;
|
||||||
|
override_charset on;
|
||||||
|
|
||||||
|
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains";
|
||||||
|
add_header X-Content-Type-Options nosniff;
|
||||||
|
add_header X-XSS-Protection "1; mode=block";
|
||||||
|
add_header X-Robots-Tag none;
|
||||||
|
add_header X-Download-Options noopen;
|
||||||
|
add_header X-Permitted-Cross-Domain-Policies none;
|
||||||
|
|
||||||
|
index index.php index.html;
|
||||||
|
|
||||||
|
include /etc/nginx/conf.d/listen_plain.active;
|
||||||
|
include /etc/nginx/conf.d/server_name.active;
|
||||||
|
|
||||||
|
error_log /var/log/nginx/error.log;
|
||||||
|
access_log /var/log/nginx/access.log;
|
||||||
|
absolute_redirect off;
|
||||||
|
root /web;
|
||||||
|
|
||||||
|
location ~ ^/api/v1/(.*)$ {
|
||||||
|
try_files $uri $uri/ /json_api.php?query=$1;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ^~ /.well-known/acme-challenge/ {
|
||||||
|
allow all;
|
||||||
|
default_type "text/plain";
|
||||||
|
}
|
||||||
|
|
||||||
|
# If behind reverse proxy, forwards the correct IP
|
||||||
|
set_real_ip_from 172.22.1.1;
|
||||||
|
real_ip_header X-Forwarded-For;
|
||||||
|
real_ip_recursive on;
|
||||||
|
|
||||||
|
rewrite ^/.well-known/caldav$ /SOGo/dav/ permanent;
|
||||||
|
rewrite ^/.well-known/carddav$ /SOGo/dav/ permanent;
|
||||||
|
|
||||||
|
location ^~ /principals {
|
||||||
|
return 301 /SOGo/dav;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ \.php$ {
|
||||||
|
try_files $uri =404;
|
||||||
|
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||||
|
fastcgi_pass phpfpm:9000;
|
||||||
|
fastcgi_index index.php;
|
||||||
|
include /etc/nginx/fastcgi_params;
|
||||||
|
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||||
|
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||||
|
fastcgi_param PHP_VALUE "max_execution_time = 1200
|
||||||
|
max_input_time = 1200
|
||||||
|
memory_limit = 64M";
|
||||||
|
fastcgi_read_timeout 1200;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /rspamd/ {
|
||||||
|
proxy_pass http://172.22.1.253:11334/;
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_redirect off;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~* ^/Autodiscover/Autodiscover.xml {
|
||||||
|
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||||
|
fastcgi_pass phpfpm:9000;
|
||||||
|
include /etc/nginx/fastcgi_params;
|
||||||
|
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||||
|
try_files /autodiscover.php =404;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~* ^/Autodiscover/Autodiscover.json {
|
||||||
|
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||||
|
fastcgi_pass phpfpm:9000;
|
||||||
|
include /etc/nginx/fastcgi_params;
|
||||||
|
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||||
|
try_files /autodiscover-json.php =404;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ /(?:m|M)ail/(?:c|C)onfig-v1.1.xml {
|
||||||
|
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||||
|
fastcgi_pass phpfpm:9000;
|
||||||
|
include /etc/nginx/fastcgi_params;
|
||||||
|
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||||
|
try_files /autoconfig.php =404;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ^~ /Microsoft-Server-ActiveSync {
|
||||||
|
proxy_pass http://172.22.1.252:20000/SOGo/Microsoft-Server-ActiveSync;
|
||||||
|
proxy_connect_timeout 1000;
|
||||||
|
proxy_next_upstream timeout error;
|
||||||
|
proxy_send_timeout 1000;
|
||||||
|
proxy_read_timeout 1000;
|
||||||
|
proxy_buffer_size 8k;
|
||||||
|
proxy_buffers 4 32k;
|
||||||
|
proxy_temp_file_write_size 64k;
|
||||||
|
proxy_busy_buffers_size 64k;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_set_header x-webobjects-server-protocol HTTP/1.0;
|
||||||
|
proxy_set_header x-webobjects-remote-host $remote_addr;
|
||||||
|
proxy_set_header x-webobjects-server-name $server_name;
|
||||||
|
proxy_set_header x-webobjects-server-url $client_req_scheme://$http_host;
|
||||||
|
proxy_set_header x-webobjects-server-port $server_port;
|
||||||
|
client_body_buffer_size 128k;
|
||||||
|
client_max_body_size 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ^~ /SOGo {
|
||||||
|
proxy_pass http://172.22.1.252:20000;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_set_header x-webobjects-server-protocol HTTP/1.0;
|
||||||
|
proxy_set_header x-webobjects-remote-host $remote_addr;
|
||||||
|
proxy_set_header x-webobjects-server-name $server_name;
|
||||||
|
proxy_set_header x-webobjects-server-url $client_req_scheme://$http_host;
|
||||||
|
proxy_set_header x-webobjects-server-port $server_port;
|
||||||
|
client_body_buffer_size 128k;
|
||||||
|
client_max_body_size 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /SOGo.woa/WebServerResources/ {
|
||||||
|
proxy_pass http://172.22.1.252:9192/WebServerResources/;
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_cache sogo;
|
||||||
|
proxy_cache_valid 200 1d;
|
||||||
|
proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;
|
||||||
|
#alias /usr/lib/GNUstep/SOGo/WebServerResources/;
|
||||||
|
allow all;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /.woa/WebServerResources/ {
|
||||||
|
proxy_pass http://172.22.1.252:9192/WebServerResources/;
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_cache sogo;
|
||||||
|
proxy_cache_valid 200 1d;
|
||||||
|
proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;
|
||||||
|
#alias /usr/lib/GNUstep/SOGo/WebServerResources/;
|
||||||
|
allow all;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /SOGo/WebServerResources/ {
|
||||||
|
proxy_pass http://172.22.1.252:9192/WebServerResources/;
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_cache sogo;
|
||||||
|
proxy_cache_valid 200 1d;
|
||||||
|
proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;
|
||||||
|
#alias /usr/lib/GNUstep/SOGo/WebServerResources/;
|
||||||
|
allow all;
|
||||||
|
}
|
||||||
|
|
||||||
|
location (^/SOGo/so/ControlPanel/Products/[^/]*UI/Resources/.*\.(jpg|png|gif|css|js)$ {
|
||||||
|
proxy_pass http://172.22.1.252:9192/$1.SOGo/Resources/$2;
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_cache sogo;
|
||||||
|
proxy_cache_valid 200 1d;
|
||||||
|
proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;
|
||||||
|
#alias /usr/lib/GNUstep/SOGo/$1.SOGo/Resources/$2;
|
||||||
|
}
|
||||||
|
|
||||||
|
include /etc/nginx/conf.d/site.*.custom;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
include /etc/nginx/mime.types;
|
include /etc/nginx/mime.types;
|
||||||
charset utf-8;
|
charset utf-8;
|
||||||
override_charset on;
|
override_charset on;
|
||||||
|
@ -22,14 +186,22 @@ server {
|
||||||
ssl_protocols TLSv1.2;
|
ssl_protocols TLSv1.2;
|
||||||
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
|
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
|
||||||
ssl_prefer_server_ciphers on;
|
ssl_prefer_server_ciphers on;
|
||||||
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains";
|
|
||||||
ssl_session_cache shared:SSL:50m;
|
ssl_session_cache shared:SSL:50m;
|
||||||
ssl_session_timeout 1d;
|
ssl_session_timeout 1d;
|
||||||
ssl_session_tickets off;
|
ssl_session_tickets off;
|
||||||
add_header Strict-Transport-Security max-age=15768000;
|
|
||||||
|
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains";
|
||||||
|
add_header X-Content-Type-Options nosniff;
|
||||||
|
add_header X-XSS-Protection "1; mode=block";
|
||||||
|
add_header X-Robots-Tag none;
|
||||||
|
add_header X-Download-Options noopen;
|
||||||
|
add_header X-Permitted-Cross-Domain-Policies none;
|
||||||
|
|
||||||
index index.php index.html;
|
index index.php index.html;
|
||||||
|
|
||||||
|
include /etc/nginx/conf.d/listen_ssl.active;
|
||||||
include /etc/nginx/conf.d/server_name.active;
|
include /etc/nginx/conf.d/server_name.active;
|
||||||
|
|
||||||
error_log /var/log/nginx/error.log;
|
error_log /var/log/nginx/error.log;
|
||||||
access_log /var/log/nginx/access.log;
|
access_log /var/log/nginx/access.log;
|
||||||
absolute_redirect off;
|
absolute_redirect off;
|
||||||
|
@ -86,151 +258,12 @@ server {
|
||||||
try_files /autodiscover.php =404;
|
try_files /autodiscover.php =404;
|
||||||
}
|
}
|
||||||
|
|
||||||
location ~ /(?:m|M)ail/(?:c|C)onfig-v1.1.xml {
|
location ~* ^/Autodiscover/Autodiscover.json {
|
||||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||||
fastcgi_pass phpfpm:9000;
|
fastcgi_pass phpfpm:9000;
|
||||||
include /etc/nginx/fastcgi_params;
|
include /etc/nginx/fastcgi_params;
|
||||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||||
try_files /autoconfig.php =404;
|
try_files /autodiscover-json.php =404;
|
||||||
}
|
|
||||||
|
|
||||||
location ^~ /Microsoft-Server-ActiveSync {
|
|
||||||
proxy_pass http://172.22.1.252:20000/SOGo/Microsoft-Server-ActiveSync;
|
|
||||||
proxy_connect_timeout 1000;
|
|
||||||
proxy_next_upstream timeout error;
|
|
||||||
proxy_send_timeout 1000;
|
|
||||||
proxy_read_timeout 1000;
|
|
||||||
proxy_buffer_size 8k;
|
|
||||||
proxy_buffers 4 32k;
|
|
||||||
proxy_temp_file_write_size 64k;
|
|
||||||
proxy_busy_buffers_size 64k;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header Host $http_host;
|
|
||||||
proxy_set_header x-webobjects-server-protocol HTTP/1.0;
|
|
||||||
proxy_set_header x-webobjects-remote-host $remote_addr;
|
|
||||||
proxy_set_header x-webobjects-server-name $server_name;
|
|
||||||
proxy_set_header x-webobjects-server-url $client_req_scheme://$http_host;
|
|
||||||
proxy_set_header x-webobjects-server-port $server_port;
|
|
||||||
client_body_buffer_size 128k;
|
|
||||||
client_max_body_size 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
location ^~ /SOGo {
|
|
||||||
proxy_pass http://172.22.1.252:20000;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header Host $http_host;
|
|
||||||
proxy_set_header x-webobjects-server-protocol HTTP/1.0;
|
|
||||||
proxy_set_header x-webobjects-remote-host $remote_addr;
|
|
||||||
proxy_set_header x-webobjects-server-name $server_name;
|
|
||||||
proxy_set_header x-webobjects-server-url $client_req_scheme://$http_host;
|
|
||||||
proxy_set_header x-webobjects-server-port $server_port;
|
|
||||||
client_body_buffer_size 128k;
|
|
||||||
client_max_body_size 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
location /SOGo.woa/WebServerResources/ {
|
|
||||||
proxy_pass http://172.22.1.252:9192/WebServerResources/;
|
|
||||||
proxy_set_header Host $http_host;
|
|
||||||
proxy_cache sogo;
|
|
||||||
proxy_cache_valid 200 1d;
|
|
||||||
proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;
|
|
||||||
#alias /usr/lib/GNUstep/SOGo/WebServerResources/;
|
|
||||||
allow all;
|
|
||||||
}
|
|
||||||
|
|
||||||
location /.woa/WebServerResources/ {
|
|
||||||
proxy_pass http://172.22.1.252:9192/WebServerResources/;
|
|
||||||
proxy_set_header Host $http_host;
|
|
||||||
proxy_cache sogo;
|
|
||||||
proxy_cache_valid 200 1d;
|
|
||||||
proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;
|
|
||||||
#alias /usr/lib/GNUstep/SOGo/WebServerResources/;
|
|
||||||
allow all;
|
|
||||||
}
|
|
||||||
|
|
||||||
location /SOGo/WebServerResources/ {
|
|
||||||
proxy_pass http://172.22.1.252:9192/WebServerResources/;
|
|
||||||
proxy_set_header Host $http_host;
|
|
||||||
proxy_cache sogo;
|
|
||||||
proxy_cache_valid 200 1d;
|
|
||||||
proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;
|
|
||||||
#alias /usr/lib/GNUstep/SOGo/WebServerResources/;
|
|
||||||
allow all;
|
|
||||||
}
|
|
||||||
|
|
||||||
location (^/SOGo/so/ControlPanel/Products/[^/]*UI/Resources/.*\.(jpg|png|gif|css|js)$ {
|
|
||||||
proxy_pass http://172.22.1.252:9192/$1.SOGo/Resources/$2;
|
|
||||||
proxy_set_header Host $http_host;
|
|
||||||
proxy_cache sogo;
|
|
||||||
proxy_cache_valid 200 1d;
|
|
||||||
proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;
|
|
||||||
#alias /usr/lib/GNUstep/SOGo/$1.SOGo/Resources/$2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
server {
|
|
||||||
include /etc/nginx/conf.d/listen_plain.active;
|
|
||||||
include /etc/nginx/mime.types;
|
|
||||||
charset utf-8;
|
|
||||||
override_charset on;
|
|
||||||
index index.php index.html;
|
|
||||||
include /etc/nginx/conf.d/server_name.active;
|
|
||||||
error_log /var/log/nginx/error.log;
|
|
||||||
access_log /var/log/nginx/access.log;
|
|
||||||
absolute_redirect off;
|
|
||||||
root /web;
|
|
||||||
|
|
||||||
location ~ ^/api/v1/(.*)$ {
|
|
||||||
try_files $uri $uri/ /json_api.php?query=$1;
|
|
||||||
}
|
|
||||||
|
|
||||||
location ^~ /.well-known/acme-challenge/ {
|
|
||||||
allow all;
|
|
||||||
default_type "text/plain";
|
|
||||||
}
|
|
||||||
|
|
||||||
# If behind reverse proxy, forwards the correct IP
|
|
||||||
set_real_ip_from 172.22.1.1;
|
|
||||||
real_ip_header X-Forwarded-For;
|
|
||||||
real_ip_recursive on;
|
|
||||||
|
|
||||||
rewrite ^/.well-known/caldav$ /SOGo/dav/ permanent;
|
|
||||||
rewrite ^/.well-known/carddav$ /SOGo/dav/ permanent;
|
|
||||||
|
|
||||||
location ^~ /principals {
|
|
||||||
return 301 /SOGo/dav;
|
|
||||||
}
|
|
||||||
|
|
||||||
location ~ \.php$ {
|
|
||||||
try_files $uri =404;
|
|
||||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
|
||||||
fastcgi_pass phpfpm:9000;
|
|
||||||
fastcgi_index index.php;
|
|
||||||
include /etc/nginx/fastcgi_params;
|
|
||||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
|
||||||
fastcgi_param PATH_INFO $fastcgi_path_info;
|
|
||||||
fastcgi_param PHP_VALUE "max_execution_time = 1200
|
|
||||||
max_input_time = 1200
|
|
||||||
memory_limit = 64M";
|
|
||||||
fastcgi_read_timeout 1200;
|
|
||||||
}
|
|
||||||
|
|
||||||
location /rspamd/ {
|
|
||||||
proxy_pass http://172.22.1.253:11334/;
|
|
||||||
proxy_set_header Host $http_host;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_redirect off;
|
|
||||||
}
|
|
||||||
|
|
||||||
location ~* ^/Autodiscover/Autodiscover.xml {
|
|
||||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
|
||||||
fastcgi_pass phpfpm:9000;
|
|
||||||
include /etc/nginx/fastcgi_params;
|
|
||||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
|
||||||
try_files /autodiscover.php =404;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
location ~ /(?:m|M)ail/(?:c|C)onfig-v1.1.xml {
|
location ~ /(?:m|M)ail/(?:c|C)onfig-v1.1.xml {
|
||||||
|
@ -317,4 +350,5 @@ server {
|
||||||
#alias /usr/lib/GNUstep/SOGo/$1.SOGo/Resources/$2;
|
#alias /usr/lib/GNUstep/SOGo/$1.SOGo/Resources/$2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
include /etc/nginx/conf.d/site.*.custom;
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ smtpd_sasl_authenticated_header = yes
|
||||||
smtpd_sasl_path = inet:dovecot:10001
|
smtpd_sasl_path = inet:dovecot:10001
|
||||||
smtpd_sasl_type = dovecot
|
smtpd_sasl_type = dovecot
|
||||||
smtpd_sender_login_maps = proxy:mysql:/opt/postfix/conf/sql/mysql_virtual_sender_acl.cf
|
smtpd_sender_login_maps = proxy:mysql:/opt/postfix/conf/sql/mysql_virtual_sender_acl.cf
|
||||||
smtpd_sender_restrictions = reject_authenticated_sender_login_mismatch, permit_mynetworks, reject_sender_login_mismatch, permit_sasl_authenticated, reject_unlisted_sender, reject_unknown_sender_domain
|
smtpd_sender_restrictions = reject_authenticated_sender_login_mismatch, permit_mynetworks, permit_sasl_authenticated, reject_unlisted_sender, reject_unknown_sender_domain
|
||||||
smtpd_soft_error_limit = 3
|
smtpd_soft_error_limit = 3
|
||||||
smtpd_tls_auth_only = yes
|
smtpd_tls_auth_only = yes
|
||||||
smtpd_tls_dh1024_param_file = /etc/ssl/mail/dhparams.pem
|
smtpd_tls_dh1024_param_file = /etc/ssl/mail/dhparams.pem
|
||||||
|
|
|
@ -44,6 +44,8 @@ anvil unix - - n - 1 anvil
|
||||||
scache unix - - n - 1 scache
|
scache unix - - n - 1 scache
|
||||||
maildrop unix - n n - - pipe flags=DRhu
|
maildrop unix - n n - - pipe flags=DRhu
|
||||||
user=vmail argv=/usr/bin/maildrop -d ${recipient}
|
user=vmail argv=/usr/bin/maildrop -d ${recipient}
|
||||||
|
|
||||||
|
# start zeyple
|
||||||
zeyple unix - n n - - pipe
|
zeyple unix - n n - - pipe
|
||||||
user=zeyple argv=/usr/local/bin/zeyple.py ${recipient}
|
user=zeyple argv=/usr/local/bin/zeyple.py ${recipient}
|
||||||
127.0.0.1:10026 inet n - n - 10 smtpd
|
127.0.0.1:10026 inet n - n - 10 smtpd
|
||||||
|
@ -55,5 +57,34 @@ zeyple unix - n n - - pipe
|
||||||
-o smtpd_recipient_restrictions=permit_mynetworks,reject
|
-o smtpd_recipient_restrictions=permit_mynetworks,reject
|
||||||
-o mynetworks=127.0.0.0/8
|
-o mynetworks=127.0.0.0/8
|
||||||
-o smtpd_authorized_xforward_hosts=127.0.0.0/8
|
-o smtpd_authorized_xforward_hosts=127.0.0.0/8
|
||||||
|
# end zeyple
|
||||||
|
|
||||||
|
# start whitelist_fwd
|
||||||
127.0.0.1:10027 inet n n n - 0 spawn user=nobody argv=/usr/local/bin/whitelist_forwardinghosts.sh
|
127.0.0.1:10027 inet n n n - 0 spawn user=nobody argv=/usr/local/bin/whitelist_forwardinghosts.sh
|
||||||
|
# end whitelist_fwd
|
||||||
|
|
||||||
|
# start watchdog-specific
|
||||||
|
589 inet n - n - - smtpd
|
||||||
|
-o smtpd_client_restrictions=permit_mynetworks,reject
|
||||||
|
-o syslog_name=watchdog
|
||||||
|
-o syslog_facility=local7
|
||||||
|
-o smtpd_milters=
|
||||||
|
-o cleanup_service_name=watchdog_cleanup
|
||||||
|
-o non_smtpd_milters=
|
||||||
|
watchdog_cleanup unix n - n - 0 cleanup
|
||||||
|
-o syslog_name=watchdog
|
||||||
|
-o syslog_facility=local7
|
||||||
|
-o queue_service_name=watchdog_qmgr
|
||||||
|
watchdog_qmgr fifo n - n 300 1 qmgr
|
||||||
|
-o syslog_facility=local7
|
||||||
|
-o syslog_name=watchdog
|
||||||
|
-o rewrite_service_name=watchdog_rewrite
|
||||||
|
watchdog_rewrite unix - - n - - trivial-rewrite
|
||||||
|
-o syslog_facility=local7
|
||||||
|
-o syslog_name=watchdog
|
||||||
|
-o local_transport=watchdog_discard
|
||||||
|
watchdog_discard unix - - n - - discard
|
||||||
|
-o syslog_facility=local7
|
||||||
|
-o syslog_name=watchdog
|
||||||
|
|
||||||
|
# end watchdog-specific
|
||||||
|
|
|
@ -28,17 +28,28 @@ function in_net($addr, $net) {
|
||||||
return substr($addr_bin, 0, $mask) == substr($net_bin, 0, $mask);
|
return substr($addr_bin, 0, $mask) == substr($net_bin, 0, $mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
if (isset($_GET['host'])) {
|
||||||
foreach ($redis->hGetAll('WHITELISTED_FWD_HOST') as $host => $source) {
|
try {
|
||||||
if (in_net($_GET['host'], $host)) {
|
foreach ($redis->hGetAll('WHITELISTED_FWD_HOST') as $host => $source) {
|
||||||
echo '200 PERMIT';
|
if (in_net($_GET['host'], $host)) {
|
||||||
exit;
|
echo '200 PERMIT';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
echo '200 DUNNO';
|
||||||
|
}
|
||||||
|
catch (RedisException $e) {
|
||||||
|
echo '200 DUNNO';
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
foreach ($redis->hGetAll('WHITELISTED_FWD_HOST') as $host => $source) {
|
||||||
|
echo $host . "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
echo '200 DUNNO';
|
catch (RedisException $e) {
|
||||||
}
|
exit;
|
||||||
catch (RedisException $e) {
|
}
|
||||||
echo '200 DUNNO';
|
|
||||||
exit;
|
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
<html>
|
||||||
|
</html>
|
|
@ -97,6 +97,18 @@ function ucl_rcpts($object, $type) {
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
settings {
|
settings {
|
||||||
|
watchdog {
|
||||||
|
priority = 10;
|
||||||
|
rcpt = "/null@localhost/i";
|
||||||
|
from = "/watchdog@localhost/i";
|
||||||
|
apply "default" {
|
||||||
|
actions {
|
||||||
|
reject = 9999.0;
|
||||||
|
greylist = 9998.0;
|
||||||
|
"add header" = 9997.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -2,7 +2,7 @@ rules {
|
||||||
DKIM_FAIL {
|
DKIM_FAIL {
|
||||||
action = "add header";
|
action = "add header";
|
||||||
expression = "R_DKIM_REJECT & !MAILLIST & !MAILCOW_WHITE & !MAILCOW_BLACK";
|
expression = "R_DKIM_REJECT & !MAILLIST & !MAILCOW_WHITE & !MAILCOW_BLACK";
|
||||||
require_action = ["no action", "greylist"];
|
require_action = ["no action", "greylist", "soft reject"];
|
||||||
}
|
}
|
||||||
VIRUS_FOUND {
|
VIRUS_FOUND {
|
||||||
action = "reject";
|
action = "reject";
|
||||||
|
@ -19,4 +19,9 @@ rules {
|
||||||
expression = "WHITELISTED_FWD_HOST";
|
expression = "WHITELISTED_FWD_HOST";
|
||||||
require_action = ["greylist", "soft reject"];
|
require_action = ["greylist", "soft reject"];
|
||||||
}
|
}
|
||||||
|
ADD_UNAUTH_SUBJ {
|
||||||
|
action = "rewrite subject";
|
||||||
|
subject = "[Unauth] %s";
|
||||||
|
expression = "SPOOFED_SENDER";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
whitelisted_ip = "http://172.22.1.251:8081/forwardinghosts.php";
|
|
@ -34,3 +34,7 @@ group "MX" {
|
||||||
one_shot = "true";
|
one_shot = "true";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
symbol "SPOOFED_SENDER" {
|
||||||
|
description = "Sender is not authenticated but part of mailcow managed domains";
|
||||||
|
score = 1.0;
|
||||||
|
}
|
||||||
|
|
|
@ -1,22 +1,29 @@
|
||||||
RCPT_MAILCOW_DOMAIN {
|
RCPT_MAILCOW_DOMAIN {
|
||||||
type = "rcpt";
|
type = "rcpt";
|
||||||
filter = "email:domain"
|
filter = "email:domain";
|
||||||
map = "redis://DOMAIN_MAP"
|
map = "redis://DOMAIN_MAP";
|
||||||
}
|
}
|
||||||
|
|
||||||
RCPT_WANTS_SUBJECT_TAG {
|
RCPT_WANTS_SUBJECT_TAG {
|
||||||
type = "rcpt";
|
type = "rcpt";
|
||||||
filter = "email:addr"
|
filter = "email:addr"
|
||||||
map = "redis://RCPT_WANTS_SUBJECT_TAG"
|
map = "redis://RCPT_WANTS_SUBJECT_TAG";
|
||||||
}
|
}
|
||||||
|
|
||||||
WHITELISTED_FWD_HOST {
|
WHITELISTED_FWD_HOST {
|
||||||
type = "ip";
|
type = "ip";
|
||||||
map = "redis://WHITELISTED_FWD_HOST"
|
map = "redis://WHITELISTED_FWD_HOST";
|
||||||
}
|
}
|
||||||
|
|
||||||
KEEP_SPAM {
|
KEEP_SPAM {
|
||||||
type = "ip";
|
type = "ip";
|
||||||
map = "redis://KEEP_SPAM"
|
map = "redis://KEEP_SPAM";
|
||||||
action = "accept";
|
action = "accept";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SPOOFED_SENDER {
|
||||||
|
type = "rcpt";
|
||||||
|
filter = "email:domain:tld";
|
||||||
|
map = "redis://DOMAIN_MAP";
|
||||||
|
require_symbols = "AUTH_NA | !RCVD_VIA_SMTP_AUTH";
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1 @@
|
||||||
# rspamd.conf.local
|
# rspamd.conf.local
|
||||||
history_redis {}
|
|
||||||
worker "log_helper" {
|
|
||||||
count = 1;
|
|
||||||
}
|
|
||||||
|
|
|
@ -58,6 +58,9 @@ rspamd_config:register_symbol({
|
||||||
local redis_params = rspamd_parse_redis_server('dyn_rl')
|
local redis_params = rspamd_parse_redis_server('dyn_rl')
|
||||||
local rspamd_logger = require "rspamd_logger"
|
local rspamd_logger = require "rspamd_logger"
|
||||||
local envfrom = task:get_from(1)
|
local envfrom = task:get_from(1)
|
||||||
|
if not envfrom then
|
||||||
|
return false
|
||||||
|
end
|
||||||
local env_from_domain = envfrom[1].domain:lower() -- get smtp from domain in lower case
|
local env_from_domain = envfrom[1].domain:lower() -- get smtp from domain in lower case
|
||||||
local env_from_addr = envfrom[1].addr:lower() -- get smtp from addr in lower case
|
local env_from_addr = envfrom[1].addr:lower() -- get smtp from addr in lower case
|
||||||
|
|
||||||
|
@ -107,4 +110,16 @@ rspamd_config:register_symbol({
|
||||||
return true
|
return true
|
||||||
end,
|
end,
|
||||||
priority = 20
|
priority = 20
|
||||||
})
|
})
|
||||||
|
|
||||||
|
rspamd_config:register_symbol({
|
||||||
|
name = 'NO_LOG_STAT',
|
||||||
|
type = 'postfilter',
|
||||||
|
callback = function(task)
|
||||||
|
local from = task:get_header('From')
|
||||||
|
if from and (from == 'monitoring-system@everycloudtech.us' or from == 'watchdog@localhost') then
|
||||||
|
task:set_flag('no_log')
|
||||||
|
task:set_flag('no_stat')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
})
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
rates {
|
||||||
|
# Format: "1 / 1h" or "20 / 1m" etc. - global ratelimits are disabled by default
|
||||||
|
to = "100 / 1s";
|
||||||
|
to_ip = "100 / 1s";
|
||||||
|
to_ip_from = "100 / 1s";
|
||||||
|
bounce_to = "100 / 1s";
|
||||||
|
bounce_to_ip = "100 / 1s";
|
||||||
|
user = "100 / 1s";
|
||||||
|
}
|
||||||
|
whitelisted_rcpts = "postmaster,mailer-daemon";
|
||||||
|
max_rcpt = 5;
|
||||||
|
custom_keywords = "/etc/rspamd/custom/ratelimit.lua";
|
||||||
|
user_keywords = ["user", "customrl"];
|
||||||
|
dynamic_rates = { customrl = "customrl"}
|
|
@ -43,8 +43,8 @@
|
||||||
SOGoInternalSyncInterval = 30;
|
SOGoInternalSyncInterval = 30;
|
||||||
SOGoMaximumSyncInterval = 354;
|
SOGoMaximumSyncInterval = 354;
|
||||||
|
|
||||||
SOGoMaximumSyncWindowSize = 0;
|
SOGoMaximumSyncWindowSize = 100;
|
||||||
SOGoMaximumSyncResponseSize = 1024;
|
SOGoMaximumSyncResponseSize = 5172;
|
||||||
|
|
||||||
WOWatchDogRequestTimeout = 10;
|
WOWatchDogRequestTimeout = 10;
|
||||||
WOListenQueueSize = 300;
|
WOListenQueueSize = 300;
|
||||||
|
|
|
@ -19,6 +19,7 @@ server:
|
||||||
private-address: 169.254.0.0/16
|
private-address: 169.254.0.0/16
|
||||||
private-address: fd00::/8
|
private-address: fd00::/8
|
||||||
private-address: fe80::/10
|
private-address: fe80::/10
|
||||||
|
private-address: fd4d:6169:6c63:6f77::/64
|
||||||
root-hints: "/etc/unbound/root.hints"
|
root-hints: "/etc/unbound/root.hints"
|
||||||
hide-identity: yes
|
hide-identity: yes
|
||||||
hide-version: yes
|
hide-version: yes
|
||||||
|
|
|
@ -24,6 +24,7 @@ $tfa_data = get_tfa();
|
||||||
<li role="presentation"><a href="#tab-sogo-logs" aria-controls="tab-sogo-logs" role="tab" data-toggle="tab">SOGo</a></li>
|
<li role="presentation"><a href="#tab-sogo-logs" aria-controls="tab-sogo-logs" role="tab" data-toggle="tab">SOGo</a></li>
|
||||||
<li role="presentation"><a href="#tab-fail2ban-logs" aria-controls="tab-fail2ban-logs" role="tab" data-toggle="tab">Fail2ban</a></li>
|
<li role="presentation"><a href="#tab-fail2ban-logs" aria-controls="tab-fail2ban-logs" role="tab" data-toggle="tab">Fail2ban</a></li>
|
||||||
<li role="presentation"><a href="#tab-rspamd-history" aria-controls="tab-rspamd-history" role="tab" data-toggle="tab">Rspamd</a></li>
|
<li role="presentation"><a href="#tab-rspamd-history" aria-controls="tab-rspamd-history" role="tab" data-toggle="tab">Rspamd</a></li>
|
||||||
|
<li role="presentation"><a href="#tab-autodiscover-logs" aria-controls="tab-autodiscover-logs" role="tab" data-toggle="tab">Autodiscover</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -128,6 +129,7 @@ $tfa_data = get_tfa();
|
||||||
<a href="#fwdhosts" class="list-group-item"><?=$lang['admin']['forwarding_hosts'];?></a>
|
<a href="#fwdhosts" class="list-group-item"><?=$lang['admin']['forwarding_hosts'];?></a>
|
||||||
<a href="#f2bparams" class="list-group-item"><?=$lang['admin']['f2b_parameters'];?></a>
|
<a href="#f2bparams" class="list-group-item"><?=$lang['admin']['f2b_parameters'];?></a>
|
||||||
<a href="#relayhosts" class="list-group-item">Relayhosts</a>
|
<a href="#relayhosts" class="list-group-item">Relayhosts</a>
|
||||||
|
<a href="#customize" class="list-group-item"><?=$lang['admin']['customize'];?></a>
|
||||||
<a href="#top" class="list-group-item" style="border-top:1px dashed #dadada">↸ <?=$lang['admin']['to_top'];?></a>
|
<a href="#top" class="list-group-item" style="border-top:1px dashed #dadada">↸ <?=$lang['admin']['to_top'];?></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -149,10 +151,10 @@ $tfa_data = get_tfa();
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-1"><input type="checkbox" data-id="dkim" name="multi_select" value="<?=$domain;?>" /></div>
|
<div class="col-xs-1"><input type="checkbox" data-id="dkim" name="multi_select" value="<?=$domain;?>" /></div>
|
||||||
<div class="col-xs-2">
|
<div class="col-xs-2">
|
||||||
<p>Domain: <strong><?=htmlspecialchars($domain);?></strong><br />
|
<p>Domain: <strong><?=htmlspecialchars($domain);?></strong>
|
||||||
<span class="label label-success"><?=$lang['admin']['dkim_key_valid'];?></span>
|
<p><span class="label label-success"><?=$lang['admin']['dkim_key_valid'];?></span></p>
|
||||||
<span class="label label-primary">Selector '<?=$dkim['dkim_selector'];?>'</span>
|
<p><span class="label label-primary">Selector '<?=$dkim['dkim_selector'];?>'</span></p>
|
||||||
<span class="label label-info"><?=$dkim['length'];?> bit</span>
|
<p><span class="label label-info"><?=$dkim['length'];?> bit</span></p>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-9">
|
<div class="col-xs-9">
|
||||||
|
@ -179,10 +181,10 @@ $tfa_data = get_tfa();
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-1"><input type="checkbox" data-id="dkim" name="multi_select" value="<?=$alias_domain;?>" /></div>
|
<div class="col-xs-1"><input type="checkbox" data-id="dkim" name="multi_select" value="<?=$alias_domain;?>" /></div>
|
||||||
<div class="col-xs-1 col-xs-offset-1">
|
<div class="col-xs-1 col-xs-offset-1">
|
||||||
<p><small>↳ Alias-Domain: <strong><?=htmlspecialchars($alias_domain);?></strong><br /></small>
|
<p><small>↳ Alias-Domain: <strong><?=htmlspecialchars($alias_domain);?></strong></small>
|
||||||
<span class="label label-success"><?=$lang['admin']['dkim_key_valid'];?></span>
|
<p><span class="label label-success"><?=$lang['admin']['dkim_key_valid'];?></span></p>
|
||||||
<span class="label label-primary">Selector '<?=$dkim['dkim_selector'];?>'</span>
|
<p><span class="label label-primary">Selector '<?=$dkim['dkim_selector'];?>'</span></p>
|
||||||
<span class="label label-info"><?=$dkim['length'];?> bit</span>
|
<p><span class="label label-info"><?=$dkim['length'];?> bit</span></p>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-9">
|
<div class="col-xs-9">
|
||||||
|
@ -211,10 +213,10 @@ $tfa_data = get_tfa();
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-1"><input type="checkbox" data-id="dkim" name="multi_select" value="<?=$blind;?>" /></div>
|
<div class="col-xs-1"><input type="checkbox" data-id="dkim" name="multi_select" value="<?=$blind;?>" /></div>
|
||||||
<div class="col-xs-2">
|
<div class="col-xs-2">
|
||||||
<p>Domain: <strong><?=htmlspecialchars($blind);?></strong><br />
|
<p>Domain: <strong><?=htmlspecialchars($blind);?></strong>
|
||||||
<span class="label label-warning"><?=$lang['admin']['dkim_key_unused'];?></span>
|
<p><span class="label label-warning"><?=$lang['admin']['dkim_key_unused'];?></span></p>
|
||||||
<span class="label label-primary">Selector '<?=$dkim['dkim_selector'];?>'</span>
|
<p><span class="label label-primary">Selector '<?=$dkim['dkim_selector'];?>'</span></p>
|
||||||
<span class="label label-info"><?=$dkim['length'];?> bit</span>
|
<p><span class="label label-info"><?=$dkim['length'];?> bit</span></p>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-9">
|
<div class="col-xs-9">
|
||||||
|
@ -259,9 +261,7 @@ $tfa_data = get_tfa();
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="private_key_file"><?=$lang['admin']['private_key'];?>:</label>
|
<label for="private_key_file"><?=$lang['admin']['private_key'];?>:</label>
|
||||||
<textarea class="form-control" rows="5" name="private_key_file" id="private_key_file" required placeholder="-----BEGIN RSA PRIVATE KEY-----
|
<textarea class="form-control" rows="5" name="private_key_file" id="private_key_file" required placeholder="-----BEGIN RSA KEY-----"></textarea>
|
||||||
XYZ
|
|
||||||
-----END RSA PRIVATE KEY-----"></textarea>
|
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-default" id="add_item" data-id="dkim_import" data-api-url='add/dkim_import' data-api-attr='{}' href="#"><span class="glyphicon glyphicon-plus"></span> <?=$lang['admin']['import'];?></button>
|
<button class="btn btn-default" id="add_item" data-id="dkim_import" data-api-url='add/dkim_import' data-api-attr='{}' href="#"><span class="glyphicon glyphicon-plus"></span> <?=$lang['admin']['import'];?></button>
|
||||||
</form>
|
</form>
|
||||||
|
@ -375,6 +375,82 @@ XYZ
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<span class="anchor" id="customize"></span>
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading"><?=$lang['admin']['customize'];?></div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<legend><?=$lang['admin']['change_logo'];?></legend>
|
||||||
|
<p class="help-block"><?=$lang['admin']['logo_info'];?></p>
|
||||||
|
<form class="form-inline" role="form" method="post" enctype="multipart/form-data">
|
||||||
|
<p>
|
||||||
|
<input type="file" name="main_logo" class="filestyle" data-buttonName="btn-default" data-buttonText="Select" accept="image/gif, image/jpeg, image/pjpeg, image/x-png, image/png, image/svg+xml">
|
||||||
|
<button name="submit_main_logo" type="submit" class="btn btn-success"><span class="glyphicon glyphicon-cloud-upload"></span> <?=$lang['admin']['upload'];?></button>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
<?php
|
||||||
|
if ($main_logo = customize('get', 'main_logo')):
|
||||||
|
$specs = customize('get', 'main_logo_specs');
|
||||||
|
?>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-3">
|
||||||
|
<div class="thumbnail">
|
||||||
|
<img class="img-thumbnail" src="<?=$main_logo;?>" alt="mailcow logo">
|
||||||
|
<div class="caption">
|
||||||
|
<span class="label label-info"><?=$specs['geometry']['width'];?>x<?=$specs['geometry']['height'];?> px</span>
|
||||||
|
<span class="label label-info"><?=$specs['mimetype'];?></span>
|
||||||
|
<span class="label label-info"><?=$specs['fileSize'];?></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<form class="form-inline" role="form" method="post">
|
||||||
|
<p><button name="reset_main_logo" type="submit" class="btn btn-xs btn-default"><?=$lang['admin']['reset_default'];?></button></p>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
endif;
|
||||||
|
?>
|
||||||
|
<legend><?=$lang['admin']['app_links'];?></legend>
|
||||||
|
<p class="help-block"><?=$lang['admin']['merged_vars_hint'];?></p>
|
||||||
|
<form class="form-inline" data-id="app_links" role="form" method="post">
|
||||||
|
<table class="table table-condensed" style="width:1%;white-space: nowrap;" id="app_link_table">
|
||||||
|
<tr>
|
||||||
|
<th><?=$lang['admin']['app_name'];?></th>
|
||||||
|
<th><?=$lang['admin']['link'];?></th>
|
||||||
|
<th> </th>
|
||||||
|
</tr>
|
||||||
|
<?php
|
||||||
|
$app_links = customize('get', 'app_links');
|
||||||
|
foreach ($app_links as $row) {
|
||||||
|
foreach ($row as $key => $val):
|
||||||
|
?>
|
||||||
|
<tr>
|
||||||
|
<td><input class="input-sm form-control" data-id="app_links" type="text" name="app" required value="<?=$key;?>"></td>
|
||||||
|
<td><input class="input-sm form-control" data-id="app_links" type="text" name="href" required value="<?=$val;?>"></td>
|
||||||
|
<td><a href="#" role="button" class="btn btn-xs btn-default" type="button"><?=$lang['admin']['remove_row'];?></a></td>
|
||||||
|
</tr>
|
||||||
|
<?php
|
||||||
|
endforeach;
|
||||||
|
}
|
||||||
|
foreach ($MAILCOW_APPS as $app):
|
||||||
|
?>
|
||||||
|
<tr>
|
||||||
|
<td><input class="input-sm form-control" value="<?=htmlspecialchars($app['name']);?>" disabled></td>
|
||||||
|
<td><input class="input-sm form-control" value="<?=htmlspecialchars($app['link']);?>" disabled></td>
|
||||||
|
<td> </td>
|
||||||
|
</tr>
|
||||||
|
<?php
|
||||||
|
endforeach;
|
||||||
|
?>
|
||||||
|
</table>
|
||||||
|
<div class="btn-group">
|
||||||
|
<button class="btn btn-success" id="edit_selected" data-item="admin" data-id="app_links" data-reload="no" data-api-url='edit/app_links' data-api-attr='{}' href="#"><?=$lang['admin']['save'];?></button>
|
||||||
|
<button class="btn btn-default" type="button" id="add_app_link_row"><?=$lang['admin']['add_row'];?></button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -469,6 +545,24 @@ XYZ
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div role="tabpanel" class="tab-pane" id="tab-autodiscover-logs">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">Autodiscover
|
||||||
|
<div class="btn-group pull-right">
|
||||||
|
<a class="btn btn-xs btn-default dropdown-toggle" data-toggle="dropdown" href="#"><?=$lang['admin']['action'];?> <span class="caret"></span></a>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li><a href="#" id="refresh_autodiscover_log"><?=$lang['admin']['refresh'];?></a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped table-condensed" id="autodiscover_log"></table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div> <!-- /container -->
|
</div> <!-- /container -->
|
||||||
<?php
|
<?php
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
set_time_limit (0);
|
||||||
|
|
||||||
|
$address = '0.0.0.0';
|
||||||
|
|
||||||
|
$port = 7777;
|
||||||
|
$con = 1;
|
||||||
|
$word = "";
|
||||||
|
|
||||||
|
$sock = socket_create(AF_INET, SOCK_STREAM, 0);
|
||||||
|
$bind = socket_bind($sock, $address, $port);
|
||||||
|
|
||||||
|
socket_listen($sock);
|
||||||
|
|
||||||
|
while ($con == 1)
|
||||||
|
{
|
||||||
|
$client = socket_accept($sock);
|
||||||
|
$input = socket_read($client, 2024);
|
||||||
|
|
||||||
|
if ($input == 'exit')
|
||||||
|
{
|
||||||
|
$close = socket_close($sock);
|
||||||
|
$con = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($con == 1)
|
||||||
|
{
|
||||||
|
$word .= $input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
echo $word;
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?php
|
||||||
|
require_once 'inc/vars.inc.php';
|
||||||
|
require_once 'inc/functions.inc.php';
|
||||||
|
$default_autodiscover_config = $autodiscover_config;
|
||||||
|
if(file_exists('inc/vars.local.inc.php')) {
|
||||||
|
include_once 'inc/vars.local.inc.php';
|
||||||
|
}
|
||||||
|
$autodiscover_config = array_merge($default_autodiscover_config, $autodiscover_config);
|
||||||
|
|
||||||
|
header('Content-type: application/json');
|
||||||
|
if ($_GET['Protocol'] == 'ActiveSync') {
|
||||||
|
echo '{"Protocol":"ActiveSync","Url":"' . $autodiscover_config['activesync']['url'] . '"}';
|
||||||
|
}
|
||||||
|
elseif ($_GET['Protocol'] == 'AutodiscoverV1') {
|
||||||
|
echo '{"Protocol":"AutodiscoverV1","Url":"https://' . $_SERVER['HTTP_HOST'] . '/autodiscover/autodiscover.xml"}';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
http_response_code(400);
|
||||||
|
echo '{"ErrorCode":"InvalidProtocol","ErrorMessage":"The given protocol value \u0027' . $_GET['Protocol'] . '\u0027 is invalid. Supported values are \u0027ActiveSync,AutodiscoverV1\u0027"}';
|
||||||
|
}
|
||||||
|
?>
|
|
@ -15,14 +15,13 @@ error_reporting(0);
|
||||||
|
|
||||||
$data = trim(file_get_contents("php://input"));
|
$data = trim(file_get_contents("php://input"));
|
||||||
|
|
||||||
// Desktop client needs IMAP, unless it's Outlook 2013 or higher on Windows
|
if (strpos($data, 'autodiscover/outlook/responseschema') !== false) {
|
||||||
if (strpos($data, 'autodiscover/outlook/responseschema') !== false) { // desktop client
|
|
||||||
$autodiscover_config['autodiscoverType'] = 'imap';
|
$autodiscover_config['autodiscoverType'] = 'imap';
|
||||||
if ($autodiscover_config['useEASforOutlook'] == 'yes' &&
|
if ($autodiscover_config['useEASforOutlook'] == 'yes' &&
|
||||||
// Office for macOS does not support EAS
|
// Office for macOS does not support EAS
|
||||||
strpos($_SERVER['HTTP_USER_AGENT'], 'Mac') === false &&
|
strpos($_SERVER['HTTP_USER_AGENT'], 'Mac') === false &&
|
||||||
// Outlook 2013 (version 15) or higher
|
// Outlook 2013 (version 15) or higher
|
||||||
preg_match('/(Outlook|Office).+1[5-9]\./', $_SERVER['HTTP_USER_AGENT'])
|
preg_match('/(Outlook|Office).+15\./', $_SERVER['HTTP_USER_AGENT'])
|
||||||
) {
|
) {
|
||||||
$autodiscover_config['autodiscoverType'] = 'activesync';
|
$autodiscover_config['autodiscoverType'] = 'activesync';
|
||||||
}
|
}
|
||||||
|
@ -39,7 +38,26 @@ $login_user = strtolower(trim($_SERVER['PHP_AUTH_USER']));
|
||||||
$login_role = check_login($login_user, $_SERVER['PHP_AUTH_PW']);
|
$login_role = check_login($login_user, $_SERVER['PHP_AUTH_PW']);
|
||||||
|
|
||||||
if (!isset($_SERVER['PHP_AUTH_USER']) OR $login_role !== "user") {
|
if (!isset($_SERVER['PHP_AUTH_USER']) OR $login_role !== "user") {
|
||||||
header('WWW-Authenticate: Basic realm=""');
|
try {
|
||||||
|
$json = json_encode(
|
||||||
|
array(
|
||||||
|
"time" => time(),
|
||||||
|
"ua" => $_SERVER['HTTP_USER_AGENT'],
|
||||||
|
"user" => "none",
|
||||||
|
"service" => "Error: must be authenticated"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$redis->lPush('AUTODISCOVER_LOG', $json);
|
||||||
|
$redis->lTrim('AUTODISCOVER_LOG', 0, 100);
|
||||||
|
}
|
||||||
|
catch (RedisException $e) {
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'msg' => 'Redis: '.$e
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
header('WWW-Authenticate: Basic realm="' . $_SERVER['HTTP_HOST'] . '"');
|
||||||
header('HTTP/1.0 401 Unauthorized');
|
header('HTTP/1.0 401 Unauthorized');
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
@ -52,6 +70,25 @@ else {
|
||||||
<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/responseschema/2006">
|
<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/responseschema/2006">
|
||||||
<?php
|
<?php
|
||||||
if(!$data) {
|
if(!$data) {
|
||||||
|
try {
|
||||||
|
$json = json_encode(
|
||||||
|
array(
|
||||||
|
"time" => time(),
|
||||||
|
"ua" => $_SERVER['HTTP_USER_AGENT'],
|
||||||
|
"user" => $_SERVER['PHP_AUTH_USER'],
|
||||||
|
"service" => "Error: invalid or missing request data"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$redis->lPush('AUTODISCOVER_LOG', $json);
|
||||||
|
$redis->lTrim('AUTODISCOVER_LOG', 0, 100);
|
||||||
|
}
|
||||||
|
catch (RedisException $e) {
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'msg' => 'Redis: '.$e
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
list($usec, $sec) = explode(' ', microtime());
|
list($usec, $sec) = explode(' ', microtime());
|
||||||
?>
|
?>
|
||||||
<Response>
|
<Response>
|
||||||
|
@ -82,12 +119,30 @@ else {
|
||||||
die("Failed to determine name from SQL");
|
die("Failed to determine name from SQL");
|
||||||
}
|
}
|
||||||
if (!empty($MailboxData['name'])) {
|
if (!empty($MailboxData['name'])) {
|
||||||
$displayname = utf8_encode($MailboxData['name']);
|
$displayname = $MailboxData['name'];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$displayname = $email;
|
$displayname = $email;
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
$json = json_encode(
|
||||||
|
array(
|
||||||
|
"time" => time(),
|
||||||
|
"ua" => $_SERVER['HTTP_USER_AGENT'],
|
||||||
|
"user" => $_SERVER['PHP_AUTH_USER'],
|
||||||
|
"service" => $autodiscover_config['autodiscoverType']
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$redis->lPush('AUTODISCOVER_LOG', $json);
|
||||||
|
$redis->lTrim('AUTODISCOVER_LOG', 0, 100);
|
||||||
|
}
|
||||||
|
catch (RedisException $e) {
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'msg' => 'Redis: '.$e
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if ($autodiscover_config['autodiscoverType'] == 'imap') {
|
if ($autodiscover_config['autodiscoverType'] == 'imap') {
|
||||||
?>
|
?>
|
||||||
<Response xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a">
|
<Response xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a">
|
||||||
|
@ -121,13 +176,13 @@ else {
|
||||||
</Protocol>
|
</Protocol>
|
||||||
<Protocol>
|
<Protocol>
|
||||||
<Type>CalDAV</Type>
|
<Type>CalDAV</Type>
|
||||||
<Server>https://<?=$autodiscover_config['caldav']['server'];?><?php if ($autodiscover_config['caldav']['port'] != 443) echo ':'.$autodiscover_config['caldav']['port']; ?>/SOGo/dav/<?=$email;?>/Calendar</Server>
|
<Server>https://<?=$autodiscover_config['caldav']['server'];?><?php if ($autodiscover_config['caldav']['port'] != 443) echo ':'.$autodiscover_config['caldav']['port']; ?>/SOGo/dav/<?=$email;?>/</Server>
|
||||||
<DomainRequired>off</DomainRequired>
|
<DomainRequired>off</DomainRequired>
|
||||||
<LoginName><?=$email;?></LoginName>
|
<LoginName><?=$email;?></LoginName>
|
||||||
</Protocol>
|
</Protocol>
|
||||||
<Protocol>
|
<Protocol>
|
||||||
<Type>CardDAV</Type>
|
<Type>CardDAV</Type>
|
||||||
<Server>https://<?=$autodiscover_config['carddav']['server'];?><?php if ($autodiscover_config['caldav']['port'] != 443) echo ':'.$autodiscover_config['carddav']['port']; ?>/SOGo/dav/<?=$email;?>/Contacts</Server>
|
<Server>https://<?=$autodiscover_config['carddav']['server'];?><?php if ($autodiscover_config['caldav']['port'] != 443) echo ':'.$autodiscover_config['carddav']['port']; ?>/SOGo/dav/<?=$email;?>/</Server>
|
||||||
<DomainRequired>off</DomainRequired>
|
<DomainRequired>off</DomainRequired>
|
||||||
<LoginName><?=$email;?></LoginName>
|
<LoginName><?=$email;?></LoginName>
|
||||||
</Protocol>
|
</Protocol>
|
||||||
|
|
|
@ -53,3 +53,7 @@ body.modal-open {
|
||||||
top: 65px;
|
top: 65px;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
.thumbnail img {
|
||||||
|
min-height:100px;
|
||||||
|
height:100px;
|
||||||
|
}
|
|
@ -83,6 +83,9 @@ body.modal-open {
|
||||||
overflow: inherit;
|
overflow: inherit;
|
||||||
padding-right: inherit !important;
|
padding-right: inherit !important;
|
||||||
}
|
}
|
||||||
|
body {
|
||||||
|
font-size:11pt;
|
||||||
|
}
|
||||||
#mailcow-alert {
|
#mailcow-alert {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 8px;
|
bottom: 8px;
|
||||||
|
@ -98,4 +101,13 @@ legend {
|
||||||
-ms-user-select: none
|
-ms-user-select: none
|
||||||
-o-user-select: none;
|
-o-user-select: none;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
}
|
||||||
|
.navbar .navbar-brand {
|
||||||
|
padding-top: 5px;
|
||||||
|
}
|
||||||
|
.navbar .navbar-brand img {
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
.mailcow-logo img {
|
||||||
|
max-width: 250px;
|
||||||
}
|
}
|
|
@ -457,6 +457,23 @@ if (isset($_SESSION['mailcow_cc_role'])) {
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<?php
|
||||||
|
$mailbox_acl = get_acl($mailbox);
|
||||||
|
?>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-sm-2" for="sender_acl">ACL:</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<select multiple data-width="100%" style="width:100%" >
|
||||||
|
<?php
|
||||||
|
foreach ($mailbox_acl as $key => $val) {
|
||||||
|
?>
|
||||||
|
<option value="<?=$key;?>" <?=($val == 1) ? 'selected' : null;?>><?=$lang['edit'][$key];?></option>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="control-label col-sm-2" for="password"><?=$lang['edit']['password'];?></label>
|
<label class="control-label col-sm-2" for="password"><?=$lang['edit']['password'];?></label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
|
|
|
@ -5,36 +5,117 @@ if (!isset($_SESSION['mailcow_cc_role']) OR !in_array($_SESSION['mailcow_cc_role
|
||||||
echo "Not allowed." . PHP_EOL;
|
echo "Not allowed." . PHP_EOL;
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
if ($_GET['ACTION'] == "start") {
|
|
||||||
$request = xmlrpc_encode_request("supervisor.startProcess", 'bootstrap-sogo', array('encoding'=>'utf-8'));
|
function docker($service_name, $action, $post_action = null, $post_fields = null) {
|
||||||
$context = stream_context_create(array('http' => array(
|
$curl = curl_init();
|
||||||
'method' => "POST",
|
curl_setopt($curl, CURLOPT_HTTPHEADER,array( 'Content-Type: application/json' ));
|
||||||
'header' => "Content-Length: " . strlen($request),
|
switch($action) {
|
||||||
'content' => $request
|
case 'get_id':
|
||||||
)));
|
curl_setopt($curl, CURLOPT_URL, 'http://dockerapi:8080/containers/json');
|
||||||
$file = @file_get_contents("http://sogo:9191/RPC2", false, $context) or die("Cannot connect to $remote_server:$listener_port");
|
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||||||
$response = xmlrpc_decode($file);
|
curl_setopt($curl, CURLOPT_POST, 0);
|
||||||
if (isset($response['faultString'])) {
|
$response = curl_exec($curl);
|
||||||
echo '<b><span class="pull-right text-warning">' . $response['faultString'] . '</span></b>';
|
if ($response === false) {
|
||||||
}
|
$err = curl_error($curl);
|
||||||
else {
|
curl_close($curl);
|
||||||
echo '<b><span class="pull-right text-success">OK</span></b>';
|
return $err;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
curl_close($curl);
|
||||||
|
$containers = json_decode($response, true);
|
||||||
|
if (!empty($containers)) {
|
||||||
|
foreach ($containers as $container) {
|
||||||
|
if ($container['Config']['Labels']['com.docker.compose.service'] == $service_name) {
|
||||||
|
return trim($container['Id']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case 'info':
|
||||||
|
$container_id = docker($service_name, 'get_id');
|
||||||
|
if (ctype_xdigit($container_id)) {
|
||||||
|
curl_setopt($curl, CURLOPT_URL, 'http://dockerapi:8080/containers/' . $container_id . '/json');
|
||||||
|
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||||||
|
curl_setopt($curl, CURLOPT_POST, 0);
|
||||||
|
$response = curl_exec($curl);
|
||||||
|
if ($response === false) {
|
||||||
|
$err = curl_error($curl);
|
||||||
|
curl_close($curl);
|
||||||
|
return $err;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
curl_close($curl);
|
||||||
|
if (empty($response)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return json_decode($response, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'post':
|
||||||
|
if (!empty($post_action)) {
|
||||||
|
$container_id = docker($service_name, 'get_id');
|
||||||
|
if (ctype_xdigit($container_id) && ctype_alnum($post_action)) {
|
||||||
|
curl_setopt($curl, CURLOPT_URL, 'http://dockerapi:8080/containers/' . $container_id . '/' . $post_action);
|
||||||
|
curl_setopt($curl, CURLOPT_POST, 1);
|
||||||
|
if (!empty($post_fields)) {
|
||||||
|
curl_setopt( $curl, CURLOPT_POSTFIELDS, json_encode($post_fields));
|
||||||
|
}
|
||||||
|
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||||||
|
$response = curl_exec($curl);
|
||||||
|
if ($response === false) {
|
||||||
|
$err = curl_error($curl);
|
||||||
|
curl_close($curl);
|
||||||
|
return $err;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
curl_close($curl);
|
||||||
|
if (empty($response)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elseif ($_GET['ACTION'] == "stop") {
|
|
||||||
$request = xmlrpc_encode_request("supervisor.stopProcess", 'bootstrap-sogo', array('encoding'=>'utf-8'));
|
if ($_GET['ACTION'] == "start") {
|
||||||
$context = stream_context_create(array('http' => array(
|
$retry = 0;
|
||||||
'method' => "POST",
|
while (docker('sogo-mailcow', 'info')['State']['Running'] != 1 && $retry <= 3) {
|
||||||
'header' => "Content-Length: " . strlen($request),
|
$response = docker('sogo-mailcow', 'post', 'start');
|
||||||
'content' => $request
|
$last_response = (trim($response) == "\"OK\"") ? '<b><span class="pull-right text-success">OK</span></b>' : '<b><span class="pull-right text-danger">Error: ' . $response . '</span></b>';
|
||||||
)));
|
if (trim($response) == "\"OK\"") {
|
||||||
$file = @file_get_contents("http://sogo:9191/RPC2", false, $context) or die("Cannot connect to $remote_server:$listener_port");
|
break;
|
||||||
$response = xmlrpc_decode($file);
|
}
|
||||||
if (isset($response['faultString'])) {
|
usleep(1500000);
|
||||||
echo '<b><span class="pull-right text-warning">' . $response['faultString'] . '</span></b>';
|
$retry++;
|
||||||
}
|
}
|
||||||
else {
|
echo (!isset($last_response)) ? '<b><span class="pull-right text-warning">Already running</span></b>' : $last_response;
|
||||||
echo '<b><span class="pull-right text-success">OK</span></b>';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($_GET['ACTION'] == "stop") {
|
||||||
|
$retry = 0;
|
||||||
|
while (docker('sogo-mailcow', 'info')['State']['Running'] == 1 && $retry <= 3) {
|
||||||
|
$response = docker('sogo-mailcow', 'post', 'stop');
|
||||||
|
$last_response = (trim($response) == "\"OK\"") ? '<b><span class="pull-right text-success">OK</span></b>' : '<b><span class="pull-right text-danger">Error: ' . $response . '</span></b>';
|
||||||
|
if (trim($response) == "\"OK\"") {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
usleep(1500000);
|
||||||
|
$retry++;
|
||||||
|
}
|
||||||
|
echo (!isset($last_response)) ? '<b><span class="pull-right text-warning">Not running</span></b>' : $last_response;
|
||||||
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -6,10 +6,14 @@ require_once $_SERVER['DOCUMENT_ROOT'] . '/modals/footer.php';
|
||||||
<script src="/js/bootstrap-switch.min.js"></script>
|
<script src="/js/bootstrap-switch.min.js"></script>
|
||||||
<script src="/js/bootstrap-slider.min.js"></script>
|
<script src="/js/bootstrap-slider.min.js"></script>
|
||||||
<script src="/js/bootstrap-select.min.js"></script>
|
<script src="/js/bootstrap-select.min.js"></script>
|
||||||
|
<script src="/js/bootstrap-filestyle.min.js"></script>
|
||||||
<script src="/js/notifications.min.js"></script>
|
<script src="/js/notifications.min.js"></script>
|
||||||
<script src="/js/u2f-api.js"></script>
|
<script src="/js/u2f-api.js"></script>
|
||||||
<script src="/js/api.js"></script>
|
<script src="/js/api.js"></script>
|
||||||
<script>
|
<script>
|
||||||
|
$(window).scroll(function() {
|
||||||
|
sessionStorage.scrollTop = $(this).scrollTop();
|
||||||
|
});
|
||||||
// Select language and reopen active URL without POST
|
// Select language and reopen active URL without POST
|
||||||
function setLang(sel) {
|
function setLang(sel) {
|
||||||
$.post( "<?= $_SERVER['REQUEST_URI']; ?>", {lang: sel} );
|
$.post( "<?= $_SERVER['REQUEST_URI']; ?>", {lang: sel} );
|
||||||
|
@ -192,6 +196,9 @@ $(document).ready(function() {
|
||||||
|
|
||||||
// CSRF
|
// CSRF
|
||||||
$('<input type="hidden" value="<?= $_SESSION['CSRF']['TOKEN']; ?>">').attr('id', 'csrf_token').attr('name', 'csrf_token').appendTo('form');
|
$('<input type="hidden" value="<?= $_SESSION['CSRF']['TOKEN']; ?>">').attr('id', 'csrf_token').attr('name', 'csrf_token').appendTo('form');
|
||||||
|
if (sessionStorage.scrollTop != "undefined") {
|
||||||
|
$(window).scrollTop(sessionStorage.scrollTop);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,119 @@
|
||||||
|
<?php
|
||||||
|
function autoconfiguration($_action, $_type, $_data = null) {
|
||||||
|
global $pdo;
|
||||||
|
global $lang;
|
||||||
|
switch ($_action) {
|
||||||
|
case 'edit':
|
||||||
|
if (!isset($_SESSION['acl']['eas_autoconfig']) || $_SESSION['acl']['eas_autoconfig'] != "1" ) {
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'msg' => sprintf($lang['danger']['access_denied'])
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
switch ($_type) {
|
||||||
|
case 'autodiscover':
|
||||||
|
$objects = (array)$_data['object'];
|
||||||
|
foreach ($objects as $object) {
|
||||||
|
if (is_valid_domain_name($object) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $object)) {
|
||||||
|
$exclude_regex = (isset($_data['exclude_regex'])) ? $_data['exclude_regex'] : null;
|
||||||
|
$exclude_regex = (isset($_data['exclude_regex'])) ? $_data['exclude_regex'] : null;
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->prepare("SELECT COUNT(`domain`) AS `domain_c` FROM `autodiscover`
|
||||||
|
WHERE `domain` = :domain");
|
||||||
|
$stmt->execute(array(':domain' => $object));
|
||||||
|
$num_results = $stmt->fetchColumn();
|
||||||
|
if ($num_results > 0) {
|
||||||
|
$stmt = $pdo->prepare("SELECT COUNT(`domain`) AS `domain_c` FROM `autodiscover`
|
||||||
|
WHERE `domain` = :domain");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(PDOException $e) {
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'msg' => 'MySQL: '.$e
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif (filter_var($object, FILTER_VALIDATE_EMAIL) === true && hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $object)) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'success',
|
||||||
|
'msg' => sprintf($lang['success']['domain_modified'], htmlspecialchars(implode(', ', $objects)))
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'get':
|
||||||
|
switch ($_type) {
|
||||||
|
case 'autodiscover':
|
||||||
|
$autodiscover = array();
|
||||||
|
if (is_valid_domain_name($_data) && hasDomainAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->prepare("SELECT * FROM `autodiscover`
|
||||||
|
WHERE `domain` = :domain");
|
||||||
|
$stmt->execute(array(':domain' => $_data));
|
||||||
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
while($row = array_shift($rows)) {
|
||||||
|
$autodiscover['mailbox'] = $row['mailbox'];
|
||||||
|
$autodiscover['domain'] = $row['domain'];
|
||||||
|
$autodiscover['service'] = $row['service'];
|
||||||
|
$autodiscover['exclude_regex'] = $row['exclude_regex'];
|
||||||
|
$autodiscover['created'] = $row['created'];
|
||||||
|
$autodiscover['modified'] = $row['modified'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(PDOException $e) {
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'msg' => 'MySQL: '.$e
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif (filter_var($_data, FILTER_VALIDATE_EMAIL) === true && hasMailboxObjectAccess($_SESSION['mailcow_cc_username'], $_SESSION['mailcow_cc_role'], $_data)) {
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->prepare("SELECT * FROM `autodiscover`
|
||||||
|
WHERE `mailbox` = :mailbox");
|
||||||
|
$stmt->execute(array(':mailbox' => $_data));
|
||||||
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
while($row = array_shift($rows)) {
|
||||||
|
$autodiscover['mailbox'] = $row['mailbox'];
|
||||||
|
$autodiscover['domain'] = $row['domain'];
|
||||||
|
$autodiscover['service'] = $row['service'];
|
||||||
|
$autodiscover['exclude_regex'] = $row['exclude_regex'];
|
||||||
|
$autodiscover['created'] = $row['created'];
|
||||||
|
$autodiscover['modified'] = $row['modified'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(PDOException $e) {
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'msg' => 'MySQL: '.$e
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $autodiscover;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'reset':
|
||||||
|
switch ($_type) {
|
||||||
|
case 'autodiscover':
|
||||||
|
if ($_SESSION['mailcow_cc_role'] != "admin" && $_SESSION['mailcow_cc_role'] != "domainadmin") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$miau = "Microsoft Office/15.0 (Windows NT 5.1; macOS Outlook 16.0.4734; Pro)";
|
||||||
|
preg_match("/^((?!.*Mac|.*emClient).)*(Outlook|Office).+1[5-9].*/i", $miau, $output_array);
|
||||||
|
if (empty($output_array)) {
|
||||||
|
echo "imap";
|
||||||
|
}
|
|
@ -0,0 +1,180 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
function customize($_action, $_item, $_data = null) {
|
||||||
|
global $redis;
|
||||||
|
global $lang;
|
||||||
|
switch ($_action) {
|
||||||
|
case 'add':
|
||||||
|
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'msg' => sprintf($lang['danger']['access_denied'])
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
switch ($_item) {
|
||||||
|
case 'main_logo':
|
||||||
|
if (in_array($_data['main_logo']['type'], array('image/gif', 'image/jpeg', 'image/pjpeg', 'image/x-png', 'image/png', 'image/svg+xml'))) {
|
||||||
|
try {
|
||||||
|
if (file_exists($_data['main_logo']['tmp_name']) !== true) {
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'msg' => 'Cannot validate image file: Temporary file not found'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$image = new Imagick($_data['main_logo']['tmp_name']);
|
||||||
|
if ($image->valid() !== true) {
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'msg' => 'Cannot validate image file'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$image->destroy();
|
||||||
|
}
|
||||||
|
catch (ImagickException $e) {
|
||||||
|
$image->destroy();
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'msg' => 'Cannot validate image file'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'msg' => 'Invalid mime type'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$redis->Set('MAIN_LOGO', 'data:' . $_data['main_logo']['type'] . ';base64,' . base64_encode(file_get_contents($_data['main_logo']['tmp_name'])));
|
||||||
|
}
|
||||||
|
catch (RedisException $e) {
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'msg' => 'Redis: '.$e
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'success',
|
||||||
|
'msg' => 'File uploaded successfully'
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'edit':
|
||||||
|
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'msg' => sprintf($lang['danger']['access_denied'])
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
switch ($_item) {
|
||||||
|
case 'app_links':
|
||||||
|
$apps = (array)$_data['app'];
|
||||||
|
$links = (array)$_data['href'];
|
||||||
|
$out = array();
|
||||||
|
if (count($apps) == count($links)) {;
|
||||||
|
for ($i = 0; $i < count($apps); $i++) {
|
||||||
|
$out[] = array($apps[$i] => $links[$i]);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$redis->set('APP_LINKS', json_encode($out));
|
||||||
|
}
|
||||||
|
catch (RedisException $e) {
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'msg' => 'Redis: '.$e
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'success',
|
||||||
|
'msg' => 'Saved changes to app links'
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'delete':
|
||||||
|
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'msg' => sprintf($lang['danger']['access_denied'])
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
switch ($_item) {
|
||||||
|
case 'main_logo':
|
||||||
|
try {
|
||||||
|
if ($redis->del('MAIN_LOGO')) {
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'success',
|
||||||
|
'msg' => 'Reset default logo'
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (RedisException $e) {
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'msg' => 'Redis: '.$e
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'get':
|
||||||
|
switch ($_item) {
|
||||||
|
case 'app_links':
|
||||||
|
try {
|
||||||
|
$app_links = json_decode($redis->get('APP_LINKS'), true);
|
||||||
|
}
|
||||||
|
catch (RedisException $e) {
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'msg' => 'Redis: '.$e
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return ($app_links) ? $app_links : false;
|
||||||
|
break;
|
||||||
|
case 'main_logo':
|
||||||
|
try {
|
||||||
|
return $redis->get('MAIN_LOGO');
|
||||||
|
}
|
||||||
|
catch (RedisException $e) {
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'msg' => 'Redis: '.$e
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'main_logo_specs':
|
||||||
|
try {
|
||||||
|
$image = new Imagick();
|
||||||
|
$img_data = explode('base64,', customize('get', 'main_logo'));
|
||||||
|
if ($img_data[1]) {
|
||||||
|
$image->readImageBlob(base64_decode($img_data[1]));
|
||||||
|
}
|
||||||
|
return $image->identifyImage();
|
||||||
|
}
|
||||||
|
catch (ImagickException $e) {
|
||||||
|
$_SESSION['return'] = array(
|
||||||
|
'type' => 'danger',
|
||||||
|
'msg' => 'Error: Imagick exception while reading image'
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
|
@ -244,6 +244,23 @@ function set_acl() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function get_acl($username) {
|
||||||
|
global $pdo;
|
||||||
|
if ($_SESSION['mailcow_cc_role'] != "admin") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$username = strtolower(trim($username));
|
||||||
|
$stmt = $pdo->prepare("SELECT * FROM `user_acl` WHERE `username` = :username");
|
||||||
|
$stmt->execute(array(':username' => $username));
|
||||||
|
$acl = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
unset($acl['username']);
|
||||||
|
if (!empty($acl)) {
|
||||||
|
return $acl;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
function formatBytes($size, $precision = 2) {
|
function formatBytes($size, $precision = 2) {
|
||||||
if(!is_numeric($size)) {
|
if(!is_numeric($size)) {
|
||||||
return "0";
|
return "0";
|
||||||
|
@ -900,6 +917,14 @@ function get_logs($container, $lines = 100) {
|
||||||
return $data_array;
|
return $data_array;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ($container == "autodiscover-mailcow") {
|
||||||
|
if ($data = $redis->lRange('AUTODISCOVER_LOG', 0, $lines)) {
|
||||||
|
foreach ($data as $json_line) {
|
||||||
|
$data_array[] = json_decode($json_line, true);
|
||||||
|
}
|
||||||
|
return $data_array;
|
||||||
|
}
|
||||||
|
}
|
||||||
if ($container == "rspamd-history") {
|
if ($container == "rspamd-history") {
|
||||||
$curl = curl_init();
|
$curl = curl_init();
|
||||||
curl_setopt($curl, CURLOPT_URL,"http://rspamd-mailcow:11334/history");
|
curl_setopt($curl, CURLOPT_URL,"http://rspamd-mailcow:11334/history");
|
||||||
|
|
|
@ -755,7 +755,7 @@ function mailbox($_action, $_type, $_data = null) {
|
||||||
':active' => $active
|
':active' => $active
|
||||||
));
|
));
|
||||||
$stmt = $pdo->prepare("INSERT INTO `quota2` (`username`, `bytes`, `messages`)
|
$stmt = $pdo->prepare("INSERT INTO `quota2` (`username`, `bytes`, `messages`)
|
||||||
VALUES (:username, '0', '0')");
|
VALUES (:username, '0', '0') ON DUPLICATE KEY UPDATE `bytes` = '0', `messages` = '0';");
|
||||||
$stmt->execute(array(':username' => $username));
|
$stmt->execute(array(':username' => $username));
|
||||||
$stmt = $pdo->prepare("INSERT INTO `alias` (`address`, `goto`, `domain`, `active`)
|
$stmt = $pdo->prepare("INSERT INTO `alias` (`address`, `goto`, `domain`, `active`)
|
||||||
VALUES (:username1, :username2, :domain, :active)");
|
VALUES (:username1, :username2, :domain, :active)");
|
||||||
|
@ -1291,11 +1291,11 @@ function mailbox($_action, $_type, $_data = null) {
|
||||||
$port1 = (!empty($_data['port1'])) ? $_data['port1'] : $is_now['port1'];
|
$port1 = (!empty($_data['port1'])) ? $_data['port1'] : $is_now['port1'];
|
||||||
$password1 = (!empty($_data['password1'])) ? $_data['password1'] : $is_now['password1'];
|
$password1 = (!empty($_data['password1'])) ? $_data['password1'] : $is_now['password1'];
|
||||||
$host1 = (!empty($_data['host1'])) ? $_data['host1'] : $is_now['host1'];
|
$host1 = (!empty($_data['host1'])) ? $_data['host1'] : $is_now['host1'];
|
||||||
$subfolder2 = (!empty($_data['subfolder2'])) ? $_data['subfolder2'] : $is_now['subfolder2'];
|
$subfolder2 = (isset($_data['subfolder2'])) ? $_data['subfolder2'] : $is_now['subfolder2'];
|
||||||
$enc1 = (!empty($_data['enc1'])) ? $_data['enc1'] : $is_now['enc1'];
|
$enc1 = (!empty($_data['enc1'])) ? $_data['enc1'] : $is_now['enc1'];
|
||||||
$mins_interval = (!empty($_data['mins_interval'])) ? $_data['mins_interval'] : $is_now['mins_interval'];
|
$mins_interval = (!empty($_data['mins_interval'])) ? $_data['mins_interval'] : $is_now['mins_interval'];
|
||||||
$exclude = (!empty($_data['exclude'])) ? $_data['exclude'] : $is_now['exclude'];
|
$exclude = (!empty($_data['exclude'])) ? $_data['exclude'] : '';
|
||||||
$maxage = (!empty($_data['maxage'])) ? $_data['maxage'] : $is_now['maxage'];
|
$maxage = (isset($_data['maxage']) && $_data['maxage'] != "") ? intval($_data['maxage']) : $is_now['maxage'];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$_SESSION['return'] = array(
|
$_SESSION['return'] = array(
|
||||||
|
|
|
@ -32,7 +32,7 @@ function policy($_action, $_scope, $_data = null) {
|
||||||
$object_list = "whitelist_from";
|
$object_list = "whitelist_from";
|
||||||
}
|
}
|
||||||
$object_from = preg_replace('/\.+/', '.', rtrim(preg_replace("/\.\*/", "*", trim(strtolower($_data['object_from']))), '.'));
|
$object_from = preg_replace('/\.+/', '.', rtrim(preg_replace("/\.\*/", "*", trim(strtolower($_data['object_from']))), '.'));
|
||||||
if (!ctype_alnum(str_replace(array('@', '.', '-', '*'), '', $object_from))) {
|
if (!ctype_alnum(str_replace(array('@', '_', '.', '-', '*'), '', $object_from))) {
|
||||||
$_SESSION['return'] = array(
|
$_SESSION['return'] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'msg' => sprintf($lang['danger']['policy_list_from_invalid'])
|
'msg' => sprintf($lang['danger']['policy_list_from_invalid'])
|
||||||
|
@ -112,7 +112,7 @@ function policy($_action, $_scope, $_data = null) {
|
||||||
$object_list = "whitelist_from";
|
$object_list = "whitelist_from";
|
||||||
}
|
}
|
||||||
$object_from = preg_replace('/\.+/', '.', rtrim(preg_replace("/\.\*/", "*", trim(strtolower($_data['object_from']))), '.'));
|
$object_from = preg_replace('/\.+/', '.', rtrim(preg_replace("/\.\*/", "*", trim(strtolower($_data['object_from']))), '.'));
|
||||||
if (!ctype_alnum(str_replace(array('@', '.', '-', '*'), '', $object_from))) {
|
if (!ctype_alnum(str_replace(array('@', '_', '.', '-', '*'), '', $object_from))) {
|
||||||
$_SESSION['return'] = array(
|
$_SESSION['return'] = array(
|
||||||
'type' => 'danger',
|
'type' => 'danger',
|
||||||
'msg' => sprintf($lang['danger']['policy_list_from_invalid'])
|
'msg' => sprintf($lang['danger']['policy_list_from_invalid'])
|
||||||
|
|
|
@ -27,7 +27,7 @@ function relayhost($_action, $_data = null) {
|
||||||
$stmt->execute(array(
|
$stmt->execute(array(
|
||||||
':hostname' => $hostname,
|
':hostname' => $hostname,
|
||||||
':username' => $username,
|
':username' => $username,
|
||||||
':password' => $password,
|
':password' => str_replace(':', '\:', $password),
|
||||||
':active' => '1'
|
':active' => '1'
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
<span class="icon-bar"></span>
|
<span class="icon-bar"></span>
|
||||||
<span class="icon-bar"></span>
|
<span class="icon-bar"></span>
|
||||||
</button>
|
</button>
|
||||||
<a class="navbar-brand" href="/"><img height="32" alt="mailcow-logo" style="margin-top: -5px;" src="/img/cow_mailcow.svg"></a>
|
<a class="navbar-brand" href="/"><img alt="mailcow-logo" src="<?=($main_logo = customize('get', 'main_logo')) ? $main_logo : '/img/cow_mailcow.svg';?>"></a>
|
||||||
</div>
|
</div>
|
||||||
<div id="navbar" class="navbar-collapse collapse">
|
<div id="navbar" class="navbar-collapse collapse">
|
||||||
<ul class="nav navbar-nav navbar-right">
|
<ul class="nav navbar-nav navbar-right">
|
||||||
|
@ -102,6 +102,14 @@
|
||||||
<li title="<?= htmlspecialchars($app['description']); ?>"><a href="<?= htmlspecialchars($app['link']); ?>"><?= htmlspecialchars($app['name']); ?></a></li>
|
<li title="<?= htmlspecialchars($app['description']); ?>"><a href="<?= htmlspecialchars($app['link']); ?>"><?= htmlspecialchars($app['name']); ?></a></li>
|
||||||
<?php
|
<?php
|
||||||
endforeach;
|
endforeach;
|
||||||
|
$app_links = customize('get', 'app_links');
|
||||||
|
foreach ($app_links as $row) {
|
||||||
|
foreach ($row as $key => $val):
|
||||||
|
?>
|
||||||
|
<li><a href="<?= htmlspecialchars($val); ?>"><?= htmlspecialchars($key); ?></a></li>
|
||||||
|
<?php
|
||||||
|
endforeach;
|
||||||
|
}
|
||||||
?>
|
?>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -3,7 +3,7 @@ function init_db_schema() {
|
||||||
try {
|
try {
|
||||||
global $pdo;
|
global $pdo;
|
||||||
|
|
||||||
$db_version = "15092017_0754";
|
$db_version = "25102017_0748";
|
||||||
|
|
||||||
$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));
|
||||||
|
@ -165,7 +165,6 @@ function init_db_schema() {
|
||||||
"delimiter_action" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
"delimiter_action" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||||
"syncjobs" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
"syncjobs" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||||
"eas_reset" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
"eas_reset" => "TINYINT(1) NOT NULL DEFAULT '1'",
|
||||||
"eas_autoconfig" => "TINYINT(1) NOT NULL DEFAULT '1'"
|
|
||||||
),
|
),
|
||||||
"keys" => array(
|
"keys" => array(
|
||||||
"fkey" => array(
|
"fkey" => array(
|
||||||
|
@ -498,6 +497,13 @@ function init_db_schema() {
|
||||||
$stmt = $pdo->query("SHOW TABLES LIKE '" . $table . "'");
|
$stmt = $pdo->query("SHOW TABLES LIKE '" . $table . "'");
|
||||||
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||||
if ($num_results != 0) {
|
if ($num_results != 0) {
|
||||||
|
$stmt = $pdo->prepare("SELECT CONCAT('ALTER TABLE ', `table_schema`, '.', `table_name`, ' DROP FOREIGN KEY ', `constraint_name`, ';') AS `FKEY_DROP` FROM `information_schema`.`table_constraints`
|
||||||
|
WHERE `constraint_type` = 'FOREIGN KEY' AND `table_name` = :table;");
|
||||||
|
$stmt->execute(array(':table' => $table));
|
||||||
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
while ($row = array_shift($rows)) {
|
||||||
|
$pdo->query($row['FKEY_DROP']);
|
||||||
|
}
|
||||||
foreach($properties['cols'] as $column => $type) {
|
foreach($properties['cols'] as $column => $type) {
|
||||||
$stmt = $pdo->query("SHOW COLUMNS FROM `" . $table . "` LIKE '" . $column . "'");
|
$stmt = $pdo->query("SHOW COLUMNS FROM `" . $table . "` LIKE '" . $column . "'");
|
||||||
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||||
|
@ -542,7 +548,7 @@ function init_db_schema() {
|
||||||
$stmt = $pdo->query("SHOW KEYS FROM `" . $table . "` WHERE Key_name = '" . $key_name . "'");
|
$stmt = $pdo->query("SHOW KEYS FROM `" . $table . "` WHERE Key_name = '" . $key_name . "'");
|
||||||
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
$num_results = count($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||||
if ($num_results != 0) {
|
if ($num_results != 0) {
|
||||||
$pdo->query("ALTER TABLE `" . $table . "` DROP FOREIGN KEY `" . $key_name . "`");
|
$pdo->query("ALTER TABLE `" . $table . "` DROP INDEX `" . $key_name . "`");
|
||||||
}
|
}
|
||||||
@list($table_ref, $field_ref) = explode('.', $key_values['ref']);
|
@list($table_ref, $field_ref) = explode('.', $key_values['ref']);
|
||||||
$pdo->query("ALTER TABLE `" . $table . "` ADD FOREIGN KEY `" . $key_name . "` (" . $key_values['col'] . ") REFERENCES `" . $table_ref . "` (`" . $field_ref . "`)
|
$pdo->query("ALTER TABLE `" . $table . "` ADD FOREIGN KEY `" . $key_name . "` (" . $key_values['col'] . ") REFERENCES `" . $table_ref . "` (`" . $field_ref . "`)
|
||||||
|
@ -582,12 +588,7 @@ function init_db_schema() {
|
||||||
// Step 2: Drop all vanished indexes
|
// Step 2: Drop all vanished indexes
|
||||||
while ($row = array_shift($keys_in_table)) {
|
while ($row = array_shift($keys_in_table)) {
|
||||||
if (!in_array($row['Key_name'], $keys_to_exist)) {
|
if (!in_array($row['Key_name'], $keys_to_exist)) {
|
||||||
try {
|
$pdo->query("ALTER TABLE `" . $table . "` DROP INDEX `" . $row['Key_name'] . "`");
|
||||||
$pdo->query("ALTER TABLE `" . $table . "` DROP FOREIGN KEY `" . $row['Key_name'] . "`");
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
$pdo->query("ALTER TABLE `" . $table . "` DROP INDEX `" . $row['Key_name'] . "`");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Step 3: Drop all vanished primary keys
|
// Step 3: Drop all vanished primary keys
|
||||||
|
|
|
@ -8,19 +8,20 @@
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "phpmailer/phpmailer",
|
"name": "phpmailer/phpmailer",
|
||||||
"version": "v5.2.23",
|
"version": "v5.2.25",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/PHPMailer/PHPMailer.git",
|
"url": "https://github.com/PHPMailer/PHPMailer.git",
|
||||||
"reference": "7115df4a6f76281109ebe352900c42403b728bb4"
|
"reference": "2baf20b01690fba8cf720c1ebcf9b988eda50915"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/7115df4a6f76281109ebe352900c42403b728bb4",
|
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/2baf20b01690fba8cf720c1ebcf9b988eda50915",
|
||||||
"reference": "7115df4a6f76281109ebe352900c42403b728bb4",
|
"reference": "2baf20b01690fba8cf720c1ebcf9b988eda50915",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
"ext-ctype": "*",
|
||||||
"php": ">=5.0.0"
|
"php": ">=5.0.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
|
@ -80,7 +81,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "PHPMailer is a full-featured email creation and transfer class for PHP",
|
"description": "PHPMailer is a full-featured email creation and transfer class for PHP",
|
||||||
"time": "2017-03-15T19:32:56+00:00"
|
"time": "2017-08-28T11:12:07+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "robthree/twofactorauth",
|
"name": "robthree/twofactorauth",
|
||||||
|
|
|
@ -91,20 +91,21 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpmailer/phpmailer",
|
"name": "phpmailer/phpmailer",
|
||||||
"version": "v5.2.23",
|
"version": "v5.2.25",
|
||||||
"version_normalized": "5.2.23.0",
|
"version_normalized": "5.2.25.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/PHPMailer/PHPMailer.git",
|
"url": "https://github.com/PHPMailer/PHPMailer.git",
|
||||||
"reference": "7115df4a6f76281109ebe352900c42403b728bb4"
|
"reference": "2baf20b01690fba8cf720c1ebcf9b988eda50915"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/7115df4a6f76281109ebe352900c42403b728bb4",
|
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/2baf20b01690fba8cf720c1ebcf9b988eda50915",
|
||||||
"reference": "7115df4a6f76281109ebe352900c42403b728bb4",
|
"reference": "2baf20b01690fba8cf720c1ebcf9b988eda50915",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
"ext-ctype": "*",
|
||||||
"php": ">=5.0.0"
|
"php": ">=5.0.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
|
@ -130,7 +131,7 @@
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"league/oauth2-google": "Needed for Google XOAUTH2 authentication"
|
"league/oauth2-google": "Needed for Google XOAUTH2 authentication"
|
||||||
},
|
},
|
||||||
"time": "2017-03-15T19:32:56+00:00",
|
"time": "2017-08-28T11:12:07+00:00",
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"installation-source": "dist",
|
"installation-source": "dist",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Non-security issues and pull requests are no longer being accepted for the legacy PHPMailer 5.2 branch. Migrate to PHPMailer 6.0 (or later) and report your issue there.
|
|
@ -0,0 +1 @@
|
||||||
|
Non-security issues and pull requests are no longer being accepted for the legacy PHPMailer 5.2 branch. Migrate to PHPMailer 6.0 (or later) and report your issue there.
|
|
@ -1 +1 @@
|
||||||
5.2.23
|
5.2.25
|
||||||
|
|
|
@ -31,7 +31,7 @@ class PHPMailer
|
||||||
* The PHPMailer Version number.
|
* The PHPMailer Version number.
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
public $Version = '5.2.23';
|
public $Version = '5.2.25';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Email priority.
|
* Email priority.
|
||||||
|
@ -440,9 +440,9 @@ class PHPMailer
|
||||||
*
|
*
|
||||||
* Parameters:
|
* Parameters:
|
||||||
* boolean $result result of the send action
|
* boolean $result result of the send action
|
||||||
* string $to email address of the recipient
|
* array $to email addresses of the recipients
|
||||||
* string $cc cc email addresses
|
* array $cc cc email addresses
|
||||||
* string $bcc bcc email addresses
|
* array $bcc bcc email addresses
|
||||||
* string $subject the subject
|
* string $subject the subject
|
||||||
* string $body the email body
|
* string $body the email body
|
||||||
* string $from email address of sender
|
* string $from email address of sender
|
||||||
|
@ -1622,8 +1622,13 @@ class PHPMailer
|
||||||
|
|
||||||
foreach ($hosts as $hostentry) {
|
foreach ($hosts as $hostentry) {
|
||||||
$hostinfo = array();
|
$hostinfo = array();
|
||||||
if (!preg_match('/^((ssl|tls):\/\/)*([a-zA-Z0-9\.-]*):?([0-9]*)$/', trim($hostentry), $hostinfo)) {
|
if (!preg_match(
|
||||||
|
'/^((ssl|tls):\/\/)*([a-zA-Z0-9\.-]*|\[[a-fA-F0-9:]+\]):?([0-9]*)$/',
|
||||||
|
trim($hostentry),
|
||||||
|
$hostinfo
|
||||||
|
)) {
|
||||||
// Not a valid host entry
|
// Not a valid host entry
|
||||||
|
$this->edebug('Ignoring invalid host: ' . $hostentry);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// $hostinfo[2]: optional ssl or tls prefix
|
// $hostinfo[2]: optional ssl or tls prefix
|
||||||
|
@ -1742,6 +1747,7 @@ class PHPMailer
|
||||||
'dk' => 'da',
|
'dk' => 'da',
|
||||||
'no' => 'nb',
|
'no' => 'nb',
|
||||||
'se' => 'sv',
|
'se' => 'sv',
|
||||||
|
'sr' => 'rs'
|
||||||
);
|
);
|
||||||
|
|
||||||
if (isset($renamed_langcodes[$langcode])) {
|
if (isset($renamed_langcodes[$langcode])) {
|
||||||
|
@ -2024,10 +2030,7 @@ class PHPMailer
|
||||||
{
|
{
|
||||||
$result = '';
|
$result = '';
|
||||||
|
|
||||||
if ($this->MessageDate == '') {
|
$result .= $this->headerLine('Date', $this->MessageDate == '' ? self::rfcDate() : $this->MessageDate);
|
||||||
$this->MessageDate = self::rfcDate();
|
|
||||||
}
|
|
||||||
$result .= $this->headerLine('Date', $this->MessageDate);
|
|
||||||
|
|
||||||
// To be created automatically by mail()
|
// To be created automatically by mail()
|
||||||
if ($this->SingleTo) {
|
if ($this->SingleTo) {
|
||||||
|
@ -4033,7 +4036,7 @@ class phpmailerException extends Exception
|
||||||
*/
|
*/
|
||||||
public function errorMessage()
|
public function errorMessage()
|
||||||
{
|
{
|
||||||
$errorMsg = '<strong>' . $this->getMessage() . "</strong><br />\n";
|
$errorMsg = '<strong>' . htmlspecialchars($this->getMessage()) . "</strong><br />\n";
|
||||||
return $errorMsg;
|
return $errorMsg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ class POP3
|
||||||
* @var string
|
* @var string
|
||||||
* @access public
|
* @access public
|
||||||
*/
|
*/
|
||||||
public $Version = '5.2.23';
|
public $Version = '5.2.25';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default POP3 port number.
|
* Default POP3 port number.
|
||||||
|
|
|
@ -30,7 +30,7 @@ class SMTP
|
||||||
* The PHPMailer SMTP version number.
|
* The PHPMailer SMTP version number.
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
const VERSION = '5.2.23';
|
const VERSION = '5.2.25';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SMTP line break constant.
|
* SMTP line break constant.
|
||||||
|
@ -81,7 +81,7 @@ class SMTP
|
||||||
* @deprecated Use the `VERSION` constant instead
|
* @deprecated Use the `VERSION` constant instead
|
||||||
* @see SMTP::VERSION
|
* @see SMTP::VERSION
|
||||||
*/
|
*/
|
||||||
public $Version = '5.2.23';
|
public $Version = '5.2.25';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SMTP server port number.
|
* SMTP server port number.
|
||||||
|
@ -151,9 +151,8 @@ class SMTP
|
||||||
public $Timelimit = 300;
|
public $Timelimit = 300;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array patterns to extract smtp transaction id from smtp reply
|
* @var array Patterns to extract an SMTP transaction id from reply to a DATA command.
|
||||||
* Only first capture group will be use, use non-capturing group to deal with it
|
* The first capture group in each regex will be used as the ID.
|
||||||
* Extend this class to override this property to fulfil your needs.
|
|
||||||
*/
|
*/
|
||||||
protected $smtp_transaction_id_patterns = array(
|
protected $smtp_transaction_id_patterns = array(
|
||||||
'exim' => '/[0-9]{3} OK id=(.*)/',
|
'exim' => '/[0-9]{3} OK id=(.*)/',
|
||||||
|
@ -161,6 +160,12 @@ class SMTP
|
||||||
'postfix' => '/[0-9]{3} 2.0.0 Ok: queued as (.*)/'
|
'postfix' => '/[0-9]{3} 2.0.0 Ok: queued as (.*)/'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string The last transaction ID issued in response to a DATA command,
|
||||||
|
* if one was detected
|
||||||
|
*/
|
||||||
|
protected $last_smtp_transaction_id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The socket for the server connection.
|
* The socket for the server connection.
|
||||||
* @var resource
|
* @var resource
|
||||||
|
@ -227,7 +232,7 @@ class SMTP
|
||||||
break;
|
break;
|
||||||
case 'html':
|
case 'html':
|
||||||
//Cleans up output a bit for a better looking, HTML-safe output
|
//Cleans up output a bit for a better looking, HTML-safe output
|
||||||
echo htmlentities(
|
echo gmdate('Y-m-d H:i:s') . ' ' . htmlentities(
|
||||||
preg_replace('/[\r\n]+/', '', $str),
|
preg_replace('/[\r\n]+/', '', $str),
|
||||||
ENT_QUOTES,
|
ENT_QUOTES,
|
||||||
'UTF-8'
|
'UTF-8'
|
||||||
|
@ -709,6 +714,7 @@ class SMTP
|
||||||
$savetimelimit = $this->Timelimit;
|
$savetimelimit = $this->Timelimit;
|
||||||
$this->Timelimit = $this->Timelimit * 2;
|
$this->Timelimit = $this->Timelimit * 2;
|
||||||
$result = $this->sendCommand('DATA END', '.', 250);
|
$result = $this->sendCommand('DATA END', '.', 250);
|
||||||
|
$this->recordLastTransactionID();
|
||||||
//Restore timelimit
|
//Restore timelimit
|
||||||
$this->Timelimit = $savetimelimit;
|
$this->Timelimit = $savetimelimit;
|
||||||
return $result;
|
return $result;
|
||||||
|
@ -989,7 +995,10 @@ class SMTP
|
||||||
public function client_send($data)
|
public function client_send($data)
|
||||||
{
|
{
|
||||||
$this->edebug("CLIENT -> SERVER: $data", self::DEBUG_CLIENT);
|
$this->edebug("CLIENT -> SERVER: $data", self::DEBUG_CLIENT);
|
||||||
return fwrite($this->smtp_conn, $data);
|
set_error_handler(array($this, 'errorHandler'));
|
||||||
|
$result = fwrite($this->smtp_conn, $data);
|
||||||
|
restore_error_handler();
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1089,8 +1098,10 @@ class SMTP
|
||||||
$this->edebug("SMTP -> get_lines(): \$data is \"$data\"", self::DEBUG_LOWLEVEL);
|
$this->edebug("SMTP -> get_lines(): \$data is \"$data\"", self::DEBUG_LOWLEVEL);
|
||||||
$this->edebug("SMTP -> get_lines(): \$str is \"$str\"", self::DEBUG_LOWLEVEL);
|
$this->edebug("SMTP -> get_lines(): \$str is \"$str\"", self::DEBUG_LOWLEVEL);
|
||||||
$data .= $str;
|
$data .= $str;
|
||||||
// If 4th character is a space, we are done reading, break the loop, micro-optimisation over strlen
|
// If response is only 3 chars (not valid, but RFC5321 S4.2 says it must be handled),
|
||||||
if ((isset($str[3]) and $str[3] == ' ')) {
|
// or 4th character is a space, we are done reading, break the loop,
|
||||||
|
// string array access is a micro-optimisation over strlen
|
||||||
|
if (!isset($str[3]) or (isset($str[3]) and $str[3] == ' ')) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// Timed-out? Log and break
|
// Timed-out? Log and break
|
||||||
|
@ -1226,26 +1237,40 @@ class SMTP
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will return the ID of the last smtp transaction based on a list of patterns provided
|
* Extract and return the ID of the last SMTP transaction based on
|
||||||
* in SMTP::$smtp_transaction_id_patterns.
|
* a list of patterns provided in SMTP::$smtp_transaction_id_patterns.
|
||||||
|
* Relies on the host providing the ID in response to a DATA command.
|
||||||
* If no reply has been received yet, it will return null.
|
* If no reply has been received yet, it will return null.
|
||||||
* If no pattern has been matched, it will return false.
|
* If no pattern was matched, it will return false.
|
||||||
* @return bool|null|string
|
* @return bool|null|string
|
||||||
*/
|
*/
|
||||||
public function getLastTransactionID()
|
protected function recordLastTransactionID()
|
||||||
{
|
{
|
||||||
$reply = $this->getLastReply();
|
$reply = $this->getLastReply();
|
||||||
|
|
||||||
if (empty($reply)) {
|
if (empty($reply)) {
|
||||||
return null;
|
$this->last_smtp_transaction_id = null;
|
||||||
}
|
} else {
|
||||||
|
$this->last_smtp_transaction_id = false;
|
||||||
foreach ($this->smtp_transaction_id_patterns as $smtp_transaction_id_pattern) {
|
foreach ($this->smtp_transaction_id_patterns as $smtp_transaction_id_pattern) {
|
||||||
if (preg_match($smtp_transaction_id_pattern, $reply, $matches)) {
|
if (preg_match($smtp_transaction_id_pattern, $reply, $matches)) {
|
||||||
return $matches[1];
|
$this->last_smtp_transaction_id = $matches[1];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return $this->last_smtp_transaction_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the queue/transaction ID of the last SMTP transaction
|
||||||
|
* If no reply has been received yet, it will return null.
|
||||||
|
* If no pattern was matched, it will return false.
|
||||||
|
* @return bool|null|string
|
||||||
|
* @see recordLastTransactionID()
|
||||||
|
*/
|
||||||
|
public function getLastTransactionID()
|
||||||
|
{
|
||||||
|
return $this->last_smtp_transaction_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"require": {
|
"require": {
|
||||||
|
"ext-ctype": "*",
|
||||||
"php": ">=5.0.0"
|
"php": ">=5.0.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
|
|
|
@ -58,46 +58,53 @@ class phpmailerAppException extends phpmailerException
|
||||||
$example_code .= "\n\nclass phpmailerAppException extends phpmailerException {}";
|
$example_code .= "\n\nclass phpmailerAppException extends phpmailerException {}";
|
||||||
$example_code .= "\n\ntry {";
|
$example_code .= "\n\ntry {";
|
||||||
|
|
||||||
|
// Convert a string to its JavaScript representation.
|
||||||
|
function JSString($s) {
|
||||||
|
static $from = array("\\", "/", "\n", "\t", "\r", "\b", "\f", '"');
|
||||||
|
static $to = array('\\\\', '\\/', '\\n', '\\t', '\\r', '\\b', '\\f', '\\"');
|
||||||
|
return is_null($s)? 'null': '"' . str_replace($from, $to, "$s") . '"';
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (isset($_POST["submit"]) && $_POST['submit'] == "Submit") {
|
if (isset($_POST["submit"]) && $_POST['submit'] == "Submit") {
|
||||||
$to = $_POST['To_Email'];
|
$to = $to_email;
|
||||||
if (!PHPMailer::validateAddress($to)) {
|
if (!PHPMailer::validateAddress($to)) {
|
||||||
throw new phpmailerAppException("Email address " . $to . " is invalid -- aborting!");
|
throw new phpmailerAppException("Email address " . $to . " is invalid -- aborting!");
|
||||||
}
|
}
|
||||||
|
|
||||||
$example_code .= "\n\$to = '{$_POST['To_Email']}';";
|
$example_code .= "\n\$to = '" . addslashes($to_email) . "';";
|
||||||
$example_code .= "\nif(!PHPMailer::validateAddress(\$to)) {";
|
$example_code .= "\nif(!PHPMailer::validateAddress(\$to)) {";
|
||||||
$example_code .= "\n throw new phpmailerAppException(\"Email address \" . " .
|
$example_code .= "\n throw new phpmailerAppException(\"Email address \" . " .
|
||||||
"\$to . \" is invalid -- aborting!\");";
|
"\$to . \" is invalid -- aborting!\");";
|
||||||
$example_code .= "\n}";
|
$example_code .= "\n}";
|
||||||
|
|
||||||
switch ($_POST['test_type']) {
|
switch ($test_type) {
|
||||||
case 'smtp':
|
case 'smtp':
|
||||||
$mail->isSMTP(); // telling the class to use SMTP
|
$mail->isSMTP(); // telling the class to use SMTP
|
||||||
$mail->SMTPDebug = (integer)$_POST['smtp_debug'];
|
$mail->SMTPDebug = (integer)$smtp_debug;
|
||||||
$mail->Host = $_POST['smtp_server']; // SMTP server
|
$mail->Host = $smtp_server; // SMTP server
|
||||||
$mail->Port = (integer)$_POST['smtp_port']; // set the SMTP port
|
$mail->Port = (integer)$smtp_port; // set the SMTP port
|
||||||
if ($_POST['smtp_secure']) {
|
if ($smtp_secure) {
|
||||||
$mail->SMTPSecure = strtolower($_POST['smtp_secure']);
|
$mail->SMTPSecure = strtolower($smtp_secure);
|
||||||
}
|
}
|
||||||
$mail->SMTPAuth = array_key_exists('smtp_authenticate', $_POST); // enable SMTP authentication?
|
$mail->SMTPAuth = array_key_exists('smtp_authenticate', $_POST); // enable SMTP authentication?
|
||||||
if (array_key_exists('smtp_authenticate', $_POST)) {
|
if (array_key_exists('smtp_authenticate', $_POST)) {
|
||||||
$mail->Username = $_POST['authenticate_username']; // SMTP account username
|
$mail->Username = $authenticate_username; // SMTP account username
|
||||||
$mail->Password = $_POST['authenticate_password']; // SMTP account password
|
$mail->Password = $authenticate_password; // SMTP account password
|
||||||
}
|
}
|
||||||
|
|
||||||
$example_code .= "\n\$mail->isSMTP();";
|
$example_code .= "\n\$mail->isSMTP();";
|
||||||
$example_code .= "\n\$mail->SMTPDebug = " . $_POST['smtp_debug'] . ";";
|
$example_code .= "\n\$mail->SMTPDebug = " . (integer) $smtp_debug . ";";
|
||||||
$example_code .= "\n\$mail->Host = \"" . $_POST['smtp_server'] . "\";";
|
$example_code .= "\n\$mail->Host = \"" . addslashes($smtp_server) . "\";";
|
||||||
$example_code .= "\n\$mail->Port = \"" . $_POST['smtp_port'] . "\";";
|
$example_code .= "\n\$mail->Port = \"" . addslashes($smtp_port) . "\";";
|
||||||
$example_code .= "\n\$mail->SMTPSecure = \"" . strtolower($_POST['smtp_secure']) . "\";";
|
$example_code .= "\n\$mail->SMTPSecure = \"" . addslashes(strtolower($smtp_secure)) . "\";";
|
||||||
$example_code .= "\n\$mail->SMTPAuth = " . (array_key_exists(
|
$example_code .= "\n\$mail->SMTPAuth = " . (array_key_exists(
|
||||||
'smtp_authenticate',
|
'smtp_authenticate',
|
||||||
$_POST
|
$_POST
|
||||||
) ? 'true' : 'false') . ";";
|
) ? 'true' : 'false') . ";";
|
||||||
if (array_key_exists('smtp_authenticate', $_POST)) {
|
if (array_key_exists('smtp_authenticate', $_POST)) {
|
||||||
$example_code .= "\n\$mail->Username = \"" . $_POST['authenticate_username'] . "\";";
|
$example_code .= "\n\$mail->Username = \"" . addslashes($authenticate_username) . "\";";
|
||||||
$example_code .= "\n\$mail->Password = \"" . $_POST['authenticate_password'] . "\";";
|
$example_code .= "\n\$mail->Password = \"" . addslashes($authenticate_password) . "\";";
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'mail':
|
case 'mail':
|
||||||
|
@ -118,59 +125,59 @@ try {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if ($_POST['From_Name'] != '') {
|
if ($_POST['From_Name'] != '') {
|
||||||
$mail->addReplyTo($_POST['From_Email'], $_POST['From_Name']);
|
$mail->addReplyTo($from_email, $from_name);
|
||||||
$mail->setFrom($_POST['From_Email'], $_POST['From_Name']);
|
$mail->setFrom($from_email, $from_name);
|
||||||
|
|
||||||
$example_code .= "\n\$mail->addReplyTo(\"" .
|
$example_code .= "\n\$mail->addReplyTo(\"" .
|
||||||
$_POST['From_Email'] . "\", \"" . $_POST['From_Name'] . "\");";
|
addslashes($from_email) . "\", \"" . addslashes($from_name) . "\");";
|
||||||
$example_code .= "\n\$mail->setFrom(\"" .
|
$example_code .= "\n\$mail->setFrom(\"" .
|
||||||
$_POST['From_Email'] . "\", \"" . $_POST['From_Name'] . "\");";
|
addslashes($from_email) . "\", \"" . addslashes($from_name) . "\");";
|
||||||
} else {
|
} else {
|
||||||
$mail->addReplyTo($_POST['From_Email']);
|
$mail->addReplyTo($from_email);
|
||||||
$mail->setFrom($_POST['From_Email'], $_POST['From_Email']);
|
$mail->setFrom($from_email, $from_email);
|
||||||
|
|
||||||
$example_code .= "\n\$mail->addReplyTo(\"" . $_POST['From_Email'] . "\");";
|
$example_code .= "\n\$mail->addReplyTo(\"" . addslashes($from_email) . "\");";
|
||||||
$example_code .= "\n\$mail->setFrom(\"" .
|
$example_code .= "\n\$mail->setFrom(\"" .
|
||||||
$_POST['From_Email'] . "\", \"" . $_POST['From_Email'] . "\");";
|
addslashes($from_email) . "\", \"" . addslashes($from_email) . "\");";
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($_POST['To_Name'] != '') {
|
if ($_POST['To_Name'] != '') {
|
||||||
$mail->addAddress($to, $_POST['To_Name']);
|
$mail->addAddress($to, $to_name);
|
||||||
$example_code .= "\n\$mail->addAddress(\"$to\", \"" . $_POST['To_Name'] . "\");";
|
$example_code .= "\n\$mail->addAddress(\"$to\", \"" . addslashes($to_name) . "\");";
|
||||||
} else {
|
} else {
|
||||||
$mail->addAddress($to);
|
$mail->addAddress($to);
|
||||||
$example_code .= "\n\$mail->addAddress(\"$to\");";
|
$example_code .= "\n\$mail->addAddress(\"$to\");";
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($_POST['bcc_Email'] != '') {
|
if ($_POST['bcc_Email'] != '') {
|
||||||
$indiBCC = explode(" ", $_POST['bcc_Email']);
|
$indiBCC = explode(" ", $bcc_email);
|
||||||
foreach ($indiBCC as $key => $value) {
|
foreach ($indiBCC as $key => $value) {
|
||||||
$mail->addBCC($value);
|
$mail->addBCC($value);
|
||||||
$example_code .= "\n\$mail->addBCC(\"$value\");";
|
$example_code .= "\n\$mail->addBCC(\"" . addslashes($value) . "\");";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($_POST['cc_Email'] != '') {
|
if ($_POST['cc_Email'] != '') {
|
||||||
$indiCC = explode(" ", $_POST['cc_Email']);
|
$indiCC = explode(" ", $cc_Email);
|
||||||
foreach ($indiCC as $key => $value) {
|
foreach ($indiCC as $key => $value) {
|
||||||
$mail->addCC($value);
|
$mail->addCC($value);
|
||||||
$example_code .= "\n\$mail->addCC(\"$value\");";
|
$example_code .= "\n\$mail->addCC(\"" . addslashes($value) . "\");";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (phpmailerException $e) { //Catch all kinds of bad addressing
|
} catch (phpmailerException $e) { //Catch all kinds of bad addressing
|
||||||
throw new phpmailerAppException($e->getMessage());
|
throw new phpmailerAppException($e->getMessage());
|
||||||
}
|
}
|
||||||
$mail->Subject = $_POST['Subject'] . ' (PHPMailer test using ' . strtoupper($_POST['test_type']) . ')';
|
$mail->Subject = $subject . ' (PHPMailer test using ' . strtoupper($test_type) . ')';
|
||||||
$example_code .= "\n\$mail->Subject = \"" . $_POST['Subject'] .
|
$example_code .= "\n\$mail->Subject = \"" . addslashes($subject) .
|
||||||
' (PHPMailer test using ' . strtoupper($_POST['test_type']) . ')";';
|
' (PHPMailer test using ' . addslashes(strtoupper($test_type)) . ')";';
|
||||||
|
|
||||||
if ($_POST['Message'] == '') {
|
if ($_POST['Message'] == '') {
|
||||||
$body = file_get_contents('contents.html');
|
$body = file_get_contents('contents.html');
|
||||||
} else {
|
} else {
|
||||||
$body = $_POST['Message'];
|
$body = $message;
|
||||||
}
|
}
|
||||||
|
|
||||||
$example_code .= "\n\$body = <<<'EOT'\n" . htmlentities($body) . "\nEOT;";
|
$example_code .= "\n\$body = <<<'EOT'\n$body\nEOT;";
|
||||||
|
|
||||||
$mail->WordWrap = 78; // set word wrap to the RFC2822 limit
|
$mail->WordWrap = 78; // set word wrap to the RFC2822 limit
|
||||||
$mail->msgHTML($body, dirname(__FILE__), true); //Create message bodies and embed images
|
$mail->msgHTML($body, dirname(__FILE__), true); //Create message bodies and embed images
|
||||||
|
@ -187,7 +194,7 @@ try {
|
||||||
$example_code .= "\n\ntry {";
|
$example_code .= "\n\ntry {";
|
||||||
$example_code .= "\n \$mail->send();";
|
$example_code .= "\n \$mail->send();";
|
||||||
$example_code .= "\n \$results_messages[] = \"Message has been sent using " .
|
$example_code .= "\n \$results_messages[] = \"Message has been sent using " .
|
||||||
strtoupper($_POST['test_type']) . "\";";
|
addslashes(strtoupper($test_type)) . "\";";
|
||||||
$example_code .= "\n}";
|
$example_code .= "\n}";
|
||||||
$example_code .= "\ncatch (phpmailerException \$e) {";
|
$example_code .= "\ncatch (phpmailerException \$e) {";
|
||||||
$example_code .= "\n throw new phpmailerAppException('Unable to send to: ' . \$to. ': '.\$e->getMessage());";
|
$example_code .= "\n throw new phpmailerAppException('Unable to send to: ' . \$to. ': '.\$e->getMessage());";
|
||||||
|
@ -195,7 +202,7 @@ try {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$mail->send();
|
$mail->send();
|
||||||
$results_messages[] = "Message has been sent using " . strtoupper($_POST["test_type"]);
|
$results_messages[] = "Message has been sent using " . strtoupper($test_type);
|
||||||
} catch (phpmailerException $e) {
|
} catch (phpmailerException $e) {
|
||||||
throw new phpmailerAppException("Unable to send to: " . $to . ': ' . $e->getMessage());
|
throw new phpmailerAppException("Unable to send to: " . $to . ': ' . $e->getMessage());
|
||||||
}
|
}
|
||||||
|
@ -309,22 +316,22 @@ $example_code .= "\n}";
|
||||||
|
|
||||||
function startAgain() {
|
function startAgain() {
|
||||||
var post_params = {
|
var post_params = {
|
||||||
"From_Name": "<?php echo $from_name; ?>",
|
"From_Name": <?php echo JSString($from_name); ?>,
|
||||||
"From_Email": "<?php echo $from_email; ?>",
|
"From_Email": <?php echo JSString($from_email); ?>,
|
||||||
"To_Name": "<?php echo $to_name; ?>",
|
"To_Name": <?php echo JSString($to_name); ?>,
|
||||||
"To_Email": "<?php echo $to_email; ?>",
|
"To_Email": <?php echo JSString($to_email); ?>,
|
||||||
"cc_Email": "<?php echo $cc_email; ?>",
|
"cc_Email": <?php echo JSString($cc_email); ?>,
|
||||||
"bcc_Email": "<?php echo $bcc_email; ?>",
|
"bcc_Email": <?php echo JSString($bcc_email); ?>,
|
||||||
"Subject": "<?php echo $subject; ?>",
|
"Subject": <?php echo JSString($subject); ?>,
|
||||||
"Message": "<?php echo $message; ?>",
|
"Message": <?php echo JSString($message); ?>,
|
||||||
"test_type": "<?php echo $test_type; ?>",
|
"test_type": <?php echo JSString($test_type); ?>,
|
||||||
"smtp_debug": "<?php echo $smtp_debug; ?>",
|
"smtp_debug": <?php echo JSString($smtp_debug); ?>,
|
||||||
"smtp_server": "<?php echo $smtp_server; ?>",
|
"smtp_server": <?php echo JSString($smtp_server); ?>,
|
||||||
"smtp_port": "<?php echo $smtp_port; ?>",
|
"smtp_port": <?php echo JSString($smtp_port); ?>,
|
||||||
"smtp_secure": "<?php echo $smtp_secure; ?>",
|
"smtp_secure": <?php echo JSString($smtp_secure); ?>,
|
||||||
"smtp_authenticate": "<?php echo $smtp_authenticate; ?>",
|
"smtp_authenticate": <?php echo JSString($smtp_authenticate); ?>,
|
||||||
"authenticate_username": "<?php echo $authenticate_username; ?>",
|
"authenticate_username": <?php echo JSString($authenticate_username); ?>,
|
||||||
"authenticate_password": "<?php echo $authenticate_password; ?>"
|
"authenticate_password": <?php echo JSString($authenticate_password); ?>
|
||||||
};
|
};
|
||||||
|
|
||||||
var resetForm = document.createElement("form");
|
var resetForm = document.createElement("form");
|
||||||
|
@ -374,7 +381,7 @@ if (isset($_POST["submit"]) && $_POST["submit"] == "Submit") {
|
||||||
echo "<button type=\"submit\" onclick=\"startAgain();\">Start Over</button><br>\n";
|
echo "<button type=\"submit\" onclick=\"startAgain();\">Start Over</button><br>\n";
|
||||||
echo "<br><span>Script:</span>\n";
|
echo "<br><span>Script:</span>\n";
|
||||||
echo "<pre class=\"brush: php;\">\n";
|
echo "<pre class=\"brush: php;\">\n";
|
||||||
echo $example_code;
|
echo htmlentities($example_code);
|
||||||
echo "\n</pre>\n";
|
echo "\n</pre>\n";
|
||||||
echo "\n<hr style=\"margin: 3em;\">\n";
|
echo "\n<hr style=\"margin: 3em;\">\n";
|
||||||
}
|
}
|
||||||
|
@ -390,7 +397,7 @@ if (isset($_POST["submit"]) && $_POST["submit"] == "Submit") {
|
||||||
<label for="From_Name"><strong>From</strong> Name</label>
|
<label for="From_Name"><strong>From</strong> Name</label>
|
||||||
</td>
|
</td>
|
||||||
<td class="colrite">
|
<td class="colrite">
|
||||||
<input type="text" id="From_Name" name="From_Name" value="<?php echo $from_name; ?>"
|
<input type="text" id="From_Name" name="From_Name" value="<?php echo htmlentities($from_name); ?>"
|
||||||
style="width:95%;" autofocus placeholder="Your Name">
|
style="width:95%;" autofocus placeholder="Your Name">
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -399,7 +406,7 @@ if (isset($_POST["submit"]) && $_POST["submit"] == "Submit") {
|
||||||
<label for="From_Email"><strong>From</strong> Email Address</label>
|
<label for="From_Email"><strong>From</strong> Email Address</label>
|
||||||
</td>
|
</td>
|
||||||
<td class="colrite">
|
<td class="colrite">
|
||||||
<input type="text" id="From_Email" name="From_Email" value="<?php echo $from_email; ?>"
|
<input type="text" id="From_Email" name="From_Email" value="<?php echo htmlentities($from_email); ?>"
|
||||||
style="width:95%;" required placeholder="Your.Email@example.com">
|
style="width:95%;" required placeholder="Your.Email@example.com">
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -408,7 +415,7 @@ if (isset($_POST["submit"]) && $_POST["submit"] == "Submit") {
|
||||||
<label for="To_Name"><strong>To</strong> Name</label>
|
<label for="To_Name"><strong>To</strong> Name</label>
|
||||||
</td>
|
</td>
|
||||||
<td class="colrite">
|
<td class="colrite">
|
||||||
<input type="text" id="To_Name" name="To_Name" value="<?php echo $to_name; ?>"
|
<input type="text" id="To_Name" name="To_Name" value="<?php echo htmlentities($to_name); ?>"
|
||||||
style="width:95%;" placeholder="Recipient's Name">
|
style="width:95%;" placeholder="Recipient's Name">
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -417,7 +424,7 @@ if (isset($_POST["submit"]) && $_POST["submit"] == "Submit") {
|
||||||
<label for="To_Email"><strong>To</strong> Email Address</label>
|
<label for="To_Email"><strong>To</strong> Email Address</label>
|
||||||
</td>
|
</td>
|
||||||
<td class="colrite">
|
<td class="colrite">
|
||||||
<input type="text" id="To_Email" name="To_Email" value="<?php echo $to_email; ?>"
|
<input type="text" id="To_Email" name="To_Email" value="<?php echo htmlentities($to_email); ?>"
|
||||||
style="width:95%;" required placeholder="Recipients.Email@example.com">
|
style="width:95%;" required placeholder="Recipients.Email@example.com">
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -428,7 +435,7 @@ if (isset($_POST["submit"]) && $_POST["submit"] == "Submit") {
|
||||||
</label>
|
</label>
|
||||||
</td>
|
</td>
|
||||||
<td class="colrite">
|
<td class="colrite">
|
||||||
<input type="text" id="cc_Email" name="cc_Email" value="<?php echo $cc_email; ?>"
|
<input type="text" id="cc_Email" name="cc_Email" value="<?php echo htmlentities($cc_email); ?>"
|
||||||
style="width:95%;" placeholder="cc1@example.com, cc2@example.com">
|
style="width:95%;" placeholder="cc1@example.com, cc2@example.com">
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -439,7 +446,7 @@ if (isset($_POST["submit"]) && $_POST["submit"] == "Submit") {
|
||||||
</label>
|
</label>
|
||||||
</td>
|
</td>
|
||||||
<td class="colrite">
|
<td class="colrite">
|
||||||
<input type="text" id="bcc_Email" name="bcc_Email" value="<?php echo $bcc_email; ?>"
|
<input type="text" id="bcc_Email" name="bcc_Email" value="<?php echo htmlentities($bcc_email); ?>"
|
||||||
style="width:95%;" placeholder="bcc1@example.com, bcc2@example.com">
|
style="width:95%;" placeholder="bcc1@example.com, bcc2@example.com">
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -448,7 +455,7 @@ if (isset($_POST["submit"]) && $_POST["submit"] == "Submit") {
|
||||||
<label for="Subject"><strong>Subject</strong></label>
|
<label for="Subject"><strong>Subject</strong></label>
|
||||||
</td>
|
</td>
|
||||||
<td class="colrite">
|
<td class="colrite">
|
||||||
<input type="text" name="Subject" id="Subject" value="<?php echo $subject; ?>"
|
<input type="text" name="Subject" id="Subject" value="<?php echo htmlentities($subject); ?>"
|
||||||
style="width:95%;" placeholder="Email Subject">
|
style="width:95%;" placeholder="Email Subject">
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -460,7 +467,7 @@ if (isset($_POST["submit"]) && $_POST["submit"] == "Submit") {
|
||||||
</td>
|
</td>
|
||||||
<td class="colrite">
|
<td class="colrite">
|
||||||
<textarea name="Message" id="Message" style="width:95%;height:5em;"
|
<textarea name="Message" id="Message" style="width:95%;height:5em;"
|
||||||
placeholder="Body of your email"><?php echo $message; ?></textarea>
|
placeholder="Body of your email"><?php echo htmlentities($message); ?></textarea>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
@ -531,7 +538,7 @@ if (isset($_POST["submit"]) && $_POST["submit"] == "Submit") {
|
||||||
<td class="colleft"><label for="smtp_server">SMTP Server</label></td>
|
<td class="colleft"><label for="smtp_server">SMTP Server</label></td>
|
||||||
<td class="colrite">
|
<td class="colrite">
|
||||||
<input type="text" id="smtp_server" name="smtp_server"
|
<input type="text" id="smtp_server" name="smtp_server"
|
||||||
value="<?php echo $smtp_server; ?>" style="width:95%;"
|
value="<?php echo htmlentities($smtp_server); ?>" style="width:95%;"
|
||||||
placeholder="smtp.server.com">
|
placeholder="smtp.server.com">
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -539,7 +546,7 @@ if (isset($_POST["submit"]) && $_POST["submit"] == "Submit") {
|
||||||
<td class="colleft" style="width: 5em;"><label for="smtp_port">SMTP Port</label></td>
|
<td class="colleft" style="width: 5em;"><label for="smtp_port">SMTP Port</label></td>
|
||||||
<td class="colrite">
|
<td class="colrite">
|
||||||
<input type="text" name="smtp_port" id="smtp_port" size="3"
|
<input type="text" name="smtp_port" id="smtp_port" size="3"
|
||||||
value="<?php echo $smtp_port; ?>" placeholder="Port">
|
value="<?php echo htmlentities($smtp_port); ?>" placeholder="Port">
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -560,14 +567,14 @@ if (isset($_POST["submit"]) && $_POST["submit"] == "Submit") {
|
||||||
<?php if ($smtp_authenticate != '') {
|
<?php if ($smtp_authenticate != '') {
|
||||||
echo "checked";
|
echo "checked";
|
||||||
} ?>
|
} ?>
|
||||||
value="<?php echo $smtp_authenticate; ?>">
|
value="true">
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="colleft"><label for="authenticate_username">Authenticate Username</label></td>
|
<td class="colleft"><label for="authenticate_username">Authenticate Username</label></td>
|
||||||
<td class="colrite">
|
<td class="colrite">
|
||||||
<input type="text" id="authenticate_username" name="authenticate_username"
|
<input type="text" id="authenticate_username" name="authenticate_username"
|
||||||
value="<?php echo $authenticate_username; ?>" style="width:95%;"
|
value="<?php echo htmlentities($authenticate_username); ?>" style="width:95%;"
|
||||||
placeholder="SMTP Server Username">
|
placeholder="SMTP Server Username">
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -575,7 +582,7 @@ if (isset($_POST["submit"]) && $_POST["submit"] == "Submit") {
|
||||||
<td class="colleft"><label for="authenticate_password">Authenticate Password</label></td>
|
<td class="colleft"><label for="authenticate_password">Authenticate Password</label></td>
|
||||||
<td class="colrite">
|
<td class="colrite">
|
||||||
<input type="password" name="authenticate_password" id="authenticate_password"
|
<input type="password" name="authenticate_password" id="authenticate_password"
|
||||||
value="<?php echo $authenticate_password; ?>" style="width:95%;"
|
value="<?php echo htmlentities($authenticate_password); ?>" style="width:95%;"
|
||||||
placeholder="SMTP Server Password">
|
placeholder="SMTP Server Password">
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* This example shows settings to use when sending via Google's Gmail servers.
|
* This example shows settings to use when sending via Google's Gmail servers.
|
||||||
|
* The IMAP section shows how to save this message to the 'Sent Mail' folder using IMAP commands.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//SMTP needs accurate times, and the PHP time zone MUST be set
|
//SMTP needs accurate times, and the PHP time zone MUST be set
|
||||||
|
@ -72,4 +73,27 @@ if (!$mail->send()) {
|
||||||
echo "Mailer Error: " . $mail->ErrorInfo;
|
echo "Mailer Error: " . $mail->ErrorInfo;
|
||||||
} else {
|
} else {
|
||||||
echo "Message sent!";
|
echo "Message sent!";
|
||||||
|
//Section 2: IMAP
|
||||||
|
//Uncomment these to save your message in the 'Sent Mail' folder.
|
||||||
|
#if (save_mail($mail)) {
|
||||||
|
# echo "Message saved!";
|
||||||
|
#}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Section 2: IMAP
|
||||||
|
//IMAP commands requires the PHP IMAP Extension, found at: https://php.net/manual/en/imap.setup.php
|
||||||
|
//Function to call which uses the PHP imap_*() functions to save messages: https://php.net/manual/en/book.imap.php
|
||||||
|
//You can use imap_getmailboxes($imapStream, '/imap/ssl') to get a list of available folders or labels, this can
|
||||||
|
//be useful if you are trying to get this working on a non-Gmail IMAP server.
|
||||||
|
function save_mail($mail) {
|
||||||
|
//You can change 'Sent Mail' to any other folder or tag
|
||||||
|
$path = "{imap.gmail.com:993/imap/ssl}[Gmail]/Sent Mail";
|
||||||
|
|
||||||
|
//Tell your server to open an IMAP connection using the same username and password as you used for SMTP
|
||||||
|
$imapStream = imap_open($path, $mail->Username, $mail->Password);
|
||||||
|
|
||||||
|
$result = imap_append($imapStream, $path, $mail->getSentMIMEMessage());
|
||||||
|
imap_close($imapStream);
|
||||||
|
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,8 +43,8 @@ $mail->SMTPAuth = true;
|
||||||
//Set AuthType
|
//Set AuthType
|
||||||
$mail->AuthType = 'XOAUTH2';
|
$mail->AuthType = 'XOAUTH2';
|
||||||
|
|
||||||
//User Email to use for SMTP authentication - Use the same Email used in Google Developer Console
|
//User Email to use for SMTP authentication - user who gave consent to our app
|
||||||
$mail->oauthUserEmail = "someone@gmail.com";
|
$mail->oauthUserEmail = "from@gmail.com";
|
||||||
|
|
||||||
//Obtained From Google Developer Console
|
//Obtained From Google Developer Console
|
||||||
$mail->oauthClientId = "RANDOMCHARS-----duv1n2.apps.googleusercontent.com";
|
$mail->oauthClientId = "RANDOMCHARS-----duv1n2.apps.googleusercontent.com";
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
#PHPMailer Extras
|
# PHPMailer Extras
|
||||||
|
|
||||||
These classes provide optional additional functions to PHPMailer.
|
These classes provide optional additional functions to PHPMailer.
|
||||||
|
|
||||||
These are not loaded by the PHPMailer autoloader, so in some cases you may need to `require` them yourself before using them.
|
These are not loaded by the PHPMailer autoloader, so in some cases you may need to `require` them yourself before using them.
|
||||||
|
|
||||||
##EasyPeasyICS
|
## EasyPeasyICS
|
||||||
|
|
||||||
This class was originally written by Manuel Reinhard and provides a simple means of generating ICS/vCal files that are used in sending calendar events. PHPMailer does not use it directly, but you can use it to generate content appropriate for placing in the `Ical` property of PHPMailer. The PHPMailer project is now its official home as Manuel has given permission for that and is no longer maintaining it himself.
|
This class was originally written by Manuel Reinhard and provides a simple means of generating ICS/vCal files that are used in sending calendar events. PHPMailer does not use it directly, but you can use it to generate content appropriate for placing in the `Ical` property of PHPMailer. The PHPMailer project is now its official home as Manuel has given permission for that and is no longer maintaining it himself.
|
||||||
|
|
||||||
##htmlfilter
|
## htmlfilter
|
||||||
|
|
||||||
This class by Konstantin Riabitsev and Jim Jagielski implements HTML filtering to remove potentially malicious tags, such as `<script>` or `onclick=` attributes that can result in XSS attacks. This is a simple filter and is not as comprehensive as [HTMLawed](http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed/) or [HTMLPurifier](http://htmlpurifier.org), but it's easier to use and considerably better than nothing! PHPMailer does not use it directly, but you may want to apply it to user-supplied HTML before using it as a message body.
|
This class by Konstantin Riabitsev and Jim Jagielski implements HTML filtering to remove potentially malicious tags, such as `<script>` or `onclick=` attributes that can result in XSS attacks. This is a simple filter and is not as comprehensive as [HTMLawed](http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed/) or [HTMLPurifier](http://htmlpurifier.org), but it's easier to use and considerably better than nothing! PHPMailer does not use it directly, but you may want to apply it to user-supplied HTML before using it as a message body.
|
||||||
|
|
||||||
##NTLM_SASL_client
|
## NTLM_SASL_client
|
||||||
|
|
||||||
This class by Manuel Lemos (bundled with permission) adds the ability to authenticate with Microsoft Windows mail servers that use NTLM-based authentication. It is used by PHPMailer if you send via SMTP and set the `AuthType` property to `NTLM`; you will also need to use the `Realm` and `Workstation` properties. The original source is [here](http://www.phpclasses.org/browse/file/7495.html).
|
This class by Manuel Lemos (bundled with permission) adds the ability to authenticate with Microsoft Windows mail servers that use NTLM-based authentication. It is used by PHPMailer if you send via SMTP and set the `AuthType` property to `NTLM`; you will also need to use the `Realm` and `Workstation` properties. The original source is [here](http://www.phpclasses.org/browse/file/7495.html).
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Bosnian PHPMailer language file: refer to English translation for definitive list
|
||||||
|
* @package PHPMailer
|
||||||
|
* @author Ermin Islamagić <ermin@islamagic.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
$PHPMAILER_LANG['authenticate'] = 'SMTP Greška: Neuspjela prijava.';
|
||||||
|
$PHPMAILER_LANG['connect_host'] = 'SMTP Greška: Ne moguće se spojiti sa SMTP serverom.';
|
||||||
|
$PHPMAILER_LANG['data_not_accepted'] = 'SMTP Greška: Podatci nisu prihvaćeni.';
|
||||||
|
$PHPMAILER_LANG['empty_message'] = 'Sadržaj poruke je prazan.';
|
||||||
|
$PHPMAILER_LANG['encoding'] = 'Nepoznata kriptografija: ';
|
||||||
|
$PHPMAILER_LANG['execute'] = 'Nije moguće izvršiti naredbu: ';
|
||||||
|
$PHPMAILER_LANG['file_access'] = 'Nije moguće pristupiti datoteci: ';
|
||||||
|
$PHPMAILER_LANG['file_open'] = 'Nije moguće otvoriti datoteku: ';
|
||||||
|
$PHPMAILER_LANG['from_failed'] = 'SMTP Greška: Slanje sa navedenih e-mail adresa nije uspjelo: ';
|
||||||
|
$PHPMAILER_LANG['recipients_failed'] = 'SMTP Greška: Slanje na navedene e-mail adrese nije uspjelo: ';
|
||||||
|
$PHPMAILER_LANG['instantiate'] = 'Ne mogu pokrenuti mail funkcionalnost.';
|
||||||
|
$PHPMAILER_LANG['invalid_address'] = 'E-mail nije poslan. Neispravna e-mail adresa: ';
|
||||||
|
$PHPMAILER_LANG['mailer_not_supported'] = ' mailer nije podržan.';
|
||||||
|
$PHPMAILER_LANG['provide_address'] = 'Definišite barem jednu adresu primaoca.';
|
||||||
|
$PHPMAILER_LANG['signing'] = 'Greška prilikom prijave: ';
|
||||||
|
$PHPMAILER_LANG['smtp_connect_failed'] = 'Spajanje na SMTP server nije uspjelo.';
|
||||||
|
$PHPMAILER_LANG['smtp_error'] = 'SMTP greška: ';
|
||||||
|
$PHPMAILER_LANG['variable_set'] = 'Nije moguće postaviti varijablu ili je vratiti nazad: ';
|
||||||
|
$PHPMAILER_LANG['extension_missing'] = 'Nedostaje ekstenzija: ';
|
|
@ -1,25 +1,25 @@
|
||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Norwegian PHPMailer language file: refer to English translation for definitive list
|
* Norwegian Bokmål PHPMailer language file: refer to English translation for definitive list
|
||||||
* @package PHPMailer
|
* @package PHPMailer
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$PHPMAILER_LANG['authenticate'] = 'SMTP Feil: Kunne ikke autentisere.';
|
$PHPMAILER_LANG['authenticate'] = 'SMTP Feil: Kunne ikke autentisere.';
|
||||||
$PHPMAILER_LANG['connect_host'] = 'SMTP Feil: Kunne ikke koble til SMTP tjener.';
|
$PHPMAILER_LANG['connect_host'] = 'SMTP Feil: Kunne ikke koble til SMTP tjener.';
|
||||||
$PHPMAILER_LANG['data_not_accepted'] = 'SMTP Feil: Data ble ikke akseptert.';
|
$PHPMAILER_LANG['data_not_accepted'] = 'SMTP Feil: Datainnhold ikke akseptert.';
|
||||||
$PHPMAILER_LANG['empty_message'] = 'Meldingsinnholdet er tomt';
|
$PHPMAILER_LANG['empty_message'] = 'Melding kropp tomt';
|
||||||
$PHPMAILER_LANG['encoding'] = 'Ukjent tegnkoding: ';
|
$PHPMAILER_LANG['encoding'] = 'Ukjent koding: ';
|
||||||
$PHPMAILER_LANG['execute'] = 'Kunne ikke utføre: ';
|
$PHPMAILER_LANG['execute'] = 'Kunne ikke utføre: ';
|
||||||
$PHPMAILER_LANG['file_access'] = 'Får ikke tilgang til filen: ';
|
$PHPMAILER_LANG['file_access'] = 'Får ikke tilgang til filen: ';
|
||||||
$PHPMAILER_LANG['file_open'] = 'Fil feil: Kunne ikke åpne filen: ';
|
$PHPMAILER_LANG['file_open'] = 'Fil Feil: Kunne ikke åpne filen: ';
|
||||||
$PHPMAILER_LANG['from_failed'] = 'Følgende avsenderadresse feilet: ';
|
$PHPMAILER_LANG['from_failed'] = 'Følgende Frå adresse feilet: ';
|
||||||
$PHPMAILER_LANG['instantiate'] = 'Kunne ikke initialisere mailfunksjonen.';
|
$PHPMAILER_LANG['instantiate'] = 'Kunne ikke initialisere post funksjon.';
|
||||||
$PHPMAILER_LANG['invalid_address'] = 'Meldingen ble ikke sendt, følgende adresse er ugyldig: ';
|
$PHPMAILER_LANG['invalid_address'] = 'Ugyldig adresse: ';
|
||||||
$PHPMAILER_LANG['provide_address'] = 'Du må angi minst en mottakeradresse.';
|
$PHPMAILER_LANG['mailer_not_supported'] = ' sender er ikke støttet.';
|
||||||
$PHPMAILER_LANG['mailer_not_supported'] = ' mailer er ikke supportert.';
|
$PHPMAILER_LANG['provide_address'] = 'Du må opppgi minst en mottakeradresse.';
|
||||||
$PHPMAILER_LANG['recipients_failed'] = 'SMTP Feil: Følgende mottagere feilet: ';
|
$PHPMAILER_LANG['recipients_failed'] = 'SMTP Feil: Følgende mottakeradresse feilet: ';
|
||||||
$PHPMAILER_LANG['signing'] = 'Signeringsfeil: ';
|
$PHPMAILER_LANG['signing'] = 'Signering Feil: ';
|
||||||
$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() feilet.';
|
$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP connect() feilet.';
|
||||||
$PHPMAILER_LANG['smtp_error'] = 'SMTP-serverfeil: ';
|
$PHPMAILER_LANG['smtp_error'] = 'SMTP server feil: ';
|
||||||
$PHPMAILER_LANG['variable_set'] = 'Kan ikke sette eller resette variabelen: ';
|
$PHPMAILER_LANG['variable_set'] = 'Kan ikke skrive eller omskrive variabel: ';
|
||||||
//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: ';
|
$PHPMAILER_LANG['extension_missing'] = 'Utvidelse mangler: ';
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
* @author Paulo Henrique Garcia <paulo@controllerweb.com.br>
|
* @author Paulo Henrique Garcia <paulo@controllerweb.com.br>
|
||||||
* @author Lucas Guimarães <lucas@lucasguimaraes.com>
|
* @author Lucas Guimarães <lucas@lucasguimaraes.com>
|
||||||
* @author Phelipe Alves <phelipealvesdesouza@gmail.com>
|
* @author Phelipe Alves <phelipealvesdesouza@gmail.com>
|
||||||
|
* @author Fabio Beneditto <fabiobeneditto@gmail.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$PHPMAILER_LANG['authenticate'] = 'Erro de SMTP: Não foi possível autenticar.';
|
$PHPMAILER_LANG['authenticate'] = 'Erro de SMTP: Não foi possível autenticar.';
|
||||||
|
@ -15,7 +16,7 @@ $PHPMAILER_LANG['encoding'] = 'Codificação desconhecida: ';
|
||||||
$PHPMAILER_LANG['execute'] = 'Não foi possível executar: ';
|
$PHPMAILER_LANG['execute'] = 'Não foi possível executar: ';
|
||||||
$PHPMAILER_LANG['file_access'] = 'Não foi possível acessar o arquivo: ';
|
$PHPMAILER_LANG['file_access'] = 'Não foi possível acessar o arquivo: ';
|
||||||
$PHPMAILER_LANG['file_open'] = 'Erro de Arquivo: Não foi possível abrir o arquivo: ';
|
$PHPMAILER_LANG['file_open'] = 'Erro de Arquivo: Não foi possível abrir o arquivo: ';
|
||||||
$PHPMAILER_LANG['from_failed'] = 'Os seguintes remententes falharam: ';
|
$PHPMAILER_LANG['from_failed'] = 'Os seguintes remetentes falharam: ';
|
||||||
$PHPMAILER_LANG['instantiate'] = 'Não foi possível instanciar a função mail.';
|
$PHPMAILER_LANG['instantiate'] = 'Não foi possível instanciar a função mail.';
|
||||||
$PHPMAILER_LANG['invalid_address'] = 'Endereço de e-mail inválido: ';
|
$PHPMAILER_LANG['invalid_address'] = 'Endereço de e-mail inválido: ';
|
||||||
$PHPMAILER_LANG['mailer_not_supported'] = ' mailer não é suportado.';
|
$PHPMAILER_LANG['mailer_not_supported'] = ' mailer não é suportado.';
|
||||||
|
|
|
@ -23,4 +23,4 @@ $PHPMAILER_LANG['signing'] = 'Грешка приликом при
|
||||||
$PHPMAILER_LANG['smtp_connect_failed'] = 'Повезивање са SMTP сервером није успело.';
|
$PHPMAILER_LANG['smtp_connect_failed'] = 'Повезивање са SMTP сервером није успело.';
|
||||||
$PHPMAILER_LANG['smtp_error'] = 'Грешка SMTP сервера: ';
|
$PHPMAILER_LANG['smtp_error'] = 'Грешка SMTP сервера: ';
|
||||||
$PHPMAILER_LANG['variable_set'] = 'Није могуће задати променљиву, нити је вратити уназад: ';
|
$PHPMAILER_LANG['variable_set'] = 'Није могуће задати променљиву, нити је вратити уназад: ';
|
||||||
//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: ';
|
$PHPMAILER_LANG['extension_missing'] = 'Недостаје проширење: ';
|
|
@ -6,6 +6,7 @@
|
||||||
* @author Can Yılmaz
|
* @author Can Yılmaz
|
||||||
* @author Mehmet Benlioğlu
|
* @author Mehmet Benlioğlu
|
||||||
* @author @yasinaydin
|
* @author @yasinaydin
|
||||||
|
* @author Ogün Karakuş
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$PHPMAILER_LANG['authenticate'] = 'SMTP Hatası: Oturum açılamadı.';
|
$PHPMAILER_LANG['authenticate'] = 'SMTP Hatası: Oturum açılamadı.';
|
||||||
|
@ -26,4 +27,4 @@ $PHPMAILER_LANG['signing'] = 'İmzalama hatası: ';
|
||||||
$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP connect() fonksiyonu başarısız.';
|
$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP connect() fonksiyonu başarısız.';
|
||||||
$PHPMAILER_LANG['smtp_error'] = 'SMTP sunucu hatası: ';
|
$PHPMAILER_LANG['smtp_error'] = 'SMTP sunucu hatası: ';
|
||||||
$PHPMAILER_LANG['variable_set'] = 'Değişken ayarlanamadı ya da sıfırlanamadı: ';
|
$PHPMAILER_LANG['variable_set'] = 'Değişken ayarlanamadı ya da sıfırlanamadı: ';
|
||||||
//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: ';
|
$PHPMAILER_LANG['extension_missing'] = 'Eklenti bulunamadı: ';
|
||||||
|
|
|
@ -4,13 +4,14 @@
|
||||||
* @package PHPMailer
|
* @package PHPMailer
|
||||||
* @author liqwei <liqwei@liqwei.com>
|
* @author liqwei <liqwei@liqwei.com>
|
||||||
* @author young <masxy@foxmail.com>
|
* @author young <masxy@foxmail.com>
|
||||||
|
* @author Teddysun <i@teddysun.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$PHPMAILER_LANG['authenticate'] = 'SMTP 错误:登录失败。';
|
$PHPMAILER_LANG['authenticate'] = 'SMTP 错误:登录失败。';
|
||||||
$PHPMAILER_LANG['connect_host'] = 'SMTP 错误:无法连接到 SMTP 主机。';
|
$PHPMAILER_LANG['connect_host'] = 'SMTP 错误:无法连接到 SMTP 主机。';
|
||||||
$PHPMAILER_LANG['data_not_accepted'] = 'SMTP 错误:数据不被接受。';
|
$PHPMAILER_LANG['data_not_accepted'] = 'SMTP 错误:数据不被接受。';
|
||||||
$PHPMAILER_LANG['empty_message'] = '邮件正文为空。';
|
$PHPMAILER_LANG['empty_message'] = '邮件正文为空。';
|
||||||
$PHPMAILER_LANG['encoding'] = '未知编码: ';
|
$PHPMAILER_LANG['encoding'] = '未知编码:';
|
||||||
$PHPMAILER_LANG['execute'] = '无法执行:';
|
$PHPMAILER_LANG['execute'] = '无法执行:';
|
||||||
$PHPMAILER_LANG['file_access'] = '无法访问文件:';
|
$PHPMAILER_LANG['file_access'] = '无法访问文件:';
|
||||||
$PHPMAILER_LANG['file_open'] = '文件错误:无法打开文件:';
|
$PHPMAILER_LANG['file_open'] = '文件错误:无法打开文件:';
|
||||||
|
@ -22,6 +23,6 @@ $PHPMAILER_LANG['provide_address'] = '必须提供至少一个收件人地
|
||||||
$PHPMAILER_LANG['recipients_failed'] = 'SMTP 错误:收件人地址错误:';
|
$PHPMAILER_LANG['recipients_failed'] = 'SMTP 错误:收件人地址错误:';
|
||||||
$PHPMAILER_LANG['signing'] = '登录失败:';
|
$PHPMAILER_LANG['signing'] = '登录失败:';
|
||||||
$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP服务器连接失败。';
|
$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP服务器连接失败。';
|
||||||
$PHPMAILER_LANG['smtp_error'] = 'SMTP服务器出错: ';
|
$PHPMAILER_LANG['smtp_error'] = 'SMTP服务器出错:';
|
||||||
$PHPMAILER_LANG['variable_set'] = '无法设置或重置变量:';
|
$PHPMAILER_LANG['variable_set'] = '无法设置或重置变量:';
|
||||||
//$PHPMAILER_LANG['extension_missing'] = 'Extension missing: ';
|
$PHPMAILER_LANG['extension_missing'] = '丢失模块 Extension:';
|
||||||
|
|
|
@ -63,6 +63,7 @@ require_once $_SERVER['DOCUMENT_ROOT'] . '/lang/lang.en.php';
|
||||||
include $_SERVER['DOCUMENT_ROOT'] . '/lang/lang.'.$_SESSION['mailcow_locale'].'.php';
|
include $_SERVER['DOCUMENT_ROOT'] . '/lang/lang.'.$_SESSION['mailcow_locale'].'.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.mailbox.inc.php';
|
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.mailbox.inc.php';
|
||||||
|
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.customize.inc.php';
|
||||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.domain_admin.inc.php';
|
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.domain_admin.inc.php';
|
||||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.policy.inc.php';
|
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.policy.inc.php';
|
||||||
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.dkim.inc.php';
|
require_once $_SERVER['DOCUMENT_ROOT'] . '/inc/functions.dkim.inc.php';
|
||||||
|
|
|
@ -53,6 +53,7 @@ if (isset($_SESSION['mailcow_cc_role']) && session_check() === false) {
|
||||||
'msg' => 'Form token invalid or timed out'
|
'msg' => 'Form token invalid or timed out'
|
||||||
);
|
);
|
||||||
$_POST = array();
|
$_POST = array();
|
||||||
|
$_FILES = array();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle logouts
|
// Handle logouts
|
||||||
|
|
|
@ -63,4 +63,14 @@ if (isset($_SESSION['mailcow_cc_role']) && ($_SESSION['mailcow_cc_role'] == "adm
|
||||||
unset_tfa_key($_POST);
|
unset_tfa_key($_POST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == "admin") {
|
||||||
|
if (isset($_POST["submit_main_logo"])) {
|
||||||
|
if ($_FILES['main_logo']['error'] == 0) {
|
||||||
|
customize('add', 'main_logo', $_FILES);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isset($_POST["reset_main_logo"])) {
|
||||||
|
customize('delete', 'main_logo');
|
||||||
|
}
|
||||||
|
}
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -30,10 +30,12 @@ if ($https_port === FALSE) {
|
||||||
//$https_port = 1234;
|
//$https_port = 1234;
|
||||||
// Other settings =>
|
// Other settings =>
|
||||||
$autodiscover_config = array(
|
$autodiscover_config = array(
|
||||||
// Enable the autodiscover service for Outlook desktop clients
|
|
||||||
'useEASforOutlook' => 'yes',
|
|
||||||
// General autodiscover service type: "activesync" or "imap"
|
// General autodiscover service type: "activesync" or "imap"
|
||||||
|
// emClient uses autodiscover, but does not support ActiveSync. mailcow excludes emClient from ActiveSync.
|
||||||
'autodiscoverType' => 'activesync',
|
'autodiscoverType' => 'activesync',
|
||||||
|
// If autodiscoverType => activesync, also use ActiveSync (EAS) for Outlook desktop clients (>= Outlook 2013 on Windows)
|
||||||
|
// Outlook for Mac does not support ActiveSync
|
||||||
|
'useEASforOutlook' => 'yes',
|
||||||
// Please don't use STARTTLS-enabled service ports in the "port" variable.
|
// Please don't use STARTTLS-enabled service ports in the "port" variable.
|
||||||
// The autodiscover service will always point to SMTPS and IMAPS (TLS-wrapped services).
|
// The autodiscover service will always point to SMTPS and IMAPS (TLS-wrapped services).
|
||||||
// The autoconfig service will additionally announce the STARTTLS-enabled ports, specified in the "tlsport" variable.
|
// The autoconfig service will additionally announce the STARTTLS-enabled ports, specified in the "tlsport" variable.
|
||||||
|
|
|
@ -23,7 +23,7 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading"><span class="glyphicon glyphicon-user" aria-hidden="true"></span> <?= $lang['login']['login']; ?></div>
|
<div class="panel-heading"><span class="glyphicon glyphicon-user" aria-hidden="true"></span> <?= $lang['login']['login']; ?></div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<div class="text-center"><img style="max-width: 250px;" src="/img/cow_mailcow.svg" alt="mailcow"></div>
|
<div class="text-center mailcow-logo"><img src="<?=($main_logo = customize('get', 'main_logo')) ? $main_logo : '/img/cow_mailcow.svg';?>" alt="mailcow"></div>
|
||||||
<legend>mailcow UI</legend>
|
<legend>mailcow UI</legend>
|
||||||
<form method="post" autofill="off">
|
<form method="post" autofill="off">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
@ -72,6 +72,14 @@ $_SESSION['return_to'] = $_SERVER['REQUEST_URI'];
|
||||||
<a href="<?= htmlspecialchars($app['link']); ?>" role="button" title="<?= htmlspecialchars($app['description']); ?>" class="btn btn-lg btn-default"><?= htmlspecialchars($app['name']); ?></a>
|
<a href="<?= htmlspecialchars($app['link']); ?>" role="button" title="<?= htmlspecialchars($app['description']); ?>" class="btn btn-lg btn-default"><?= htmlspecialchars($app['name']); ?></a>
|
||||||
<?php
|
<?php
|
||||||
endforeach;
|
endforeach;
|
||||||
|
$app_links = customize('get', 'app_links');
|
||||||
|
foreach ($app_links as $row) {
|
||||||
|
foreach ($row as $key => $val):
|
||||||
|
?>
|
||||||
|
<a href="<?= htmlspecialchars($val); ?>" role="button" class="btn btn-lg btn-default"><?= htmlspecialchars($key); ?></a>
|
||||||
|
<?php
|
||||||
|
endforeach;
|
||||||
|
}
|
||||||
?>
|
?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -90,7 +90,7 @@ var Base64 = {
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jQuery(function($){
|
jQuery(function($){
|
||||||
// http://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery
|
// http://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery
|
||||||
var entityMap = {
|
var entityMap = {
|
||||||
|
@ -124,6 +124,10 @@ jQuery(function($){
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
draw_postfix_logs();
|
draw_postfix_logs();
|
||||||
});
|
});
|
||||||
|
$("#refresh_autodiscover_log").on('click', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
draw_autodiscover_logs();
|
||||||
|
});
|
||||||
$("#refresh_dovecot_log").on('click', function(e) {
|
$("#refresh_dovecot_log").on('click', function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
draw_dovecot_logs();
|
draw_dovecot_logs();
|
||||||
|
@ -192,6 +196,52 @@ jQuery(function($){
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
function draw_autodiscover_logs() {
|
||||||
|
ft_autodiscover_logs = FooTable.init('#autodiscover_log', {
|
||||||
|
"columns": [
|
||||||
|
{"name":"time","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleString();},"title":lang.time,"style":{"width":"170px"}},
|
||||||
|
{"name":"ua","title":"User-Agent","style":{"min-width":"200px"}},
|
||||||
|
{"name":"user","title":"Username","style":{"min-width":"200px"}},
|
||||||
|
{"name":"service","title":"Service"},
|
||||||
|
],
|
||||||
|
"rows": $.ajax({
|
||||||
|
dataType: 'json',
|
||||||
|
url: '/api/v1/get/logs/autodiscover/100',
|
||||||
|
jsonp: false,
|
||||||
|
error: function () {
|
||||||
|
console.log('Cannot draw autodiscover log table');
|
||||||
|
},
|
||||||
|
success: function (data) {
|
||||||
|
$.each(data, function (i, item) {
|
||||||
|
item.ua = '<span style="font-size:small">' + item.ua + '</span>';
|
||||||
|
if (item.service == "activesync") {
|
||||||
|
item.service = '<span class="label label-info">ActiveSync</span>';
|
||||||
|
}
|
||||||
|
else if (item.service == "imap") {
|
||||||
|
item.service = '<span class="label label-success">IMAP, SMTP, Cal-/CardDAV</span>';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
item.service = '<span class="label label-danger">' + item.service + '</span>';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
"empty": lang.empty,
|
||||||
|
"paging": {
|
||||||
|
"enabled": true,
|
||||||
|
"limit": 5,
|
||||||
|
"size": log_pagination_size
|
||||||
|
},
|
||||||
|
"filtering": {
|
||||||
|
"enabled": true,
|
||||||
|
"position": "left",
|
||||||
|
"placeholder": lang.filter_table
|
||||||
|
},
|
||||||
|
"sorting": {
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
function draw_fail2ban_logs() {
|
function draw_fail2ban_logs() {
|
||||||
ft_fail2ban_logs = FooTable.init('#fail2ban_log', {
|
ft_fail2ban_logs = FooTable.init('#fail2ban_log', {
|
||||||
"columns": [
|
"columns": [
|
||||||
|
@ -637,6 +687,7 @@ jQuery(function($){
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
draw_postfix_logs();
|
draw_postfix_logs();
|
||||||
|
draw_autodiscover_logs();
|
||||||
draw_dovecot_logs();
|
draw_dovecot_logs();
|
||||||
draw_sogo_logs();
|
draw_sogo_logs();
|
||||||
draw_fail2ban_logs();
|
draw_fail2ban_logs();
|
||||||
|
@ -679,6 +730,24 @@ jQuery(function($){
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function add_table_row(table_id) {
|
||||||
|
var row = $('<tr />');
|
||||||
|
cols = '<td><input class="input-sm form-control" data-id="app_links" type="text" name="app" required></td>';
|
||||||
|
cols += '<td><input class="input-sm form-control" data-id="app_links" type="text" name="href" required></td>';
|
||||||
|
cols += '<td><a href="#" role="button" class="btn btn-xs btn-default" type="button">Remove row</a></td>';
|
||||||
|
row.append(cols);
|
||||||
|
table_id.append(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#app_link_table').on('click', 'tr a', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
$(this).parents('tr').remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#add_app_link_row').click(function() {
|
||||||
|
add_table_row($('#app_link_table'));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$(window).load(function(){
|
$(window).load(function(){
|
||||||
|
|
|
@ -14,7 +14,7 @@ $(document).ready(function() {
|
||||||
});
|
});
|
||||||
return o;
|
return o;
|
||||||
};
|
};
|
||||||
// Collect values of input fields with name "multi_select" an same data-id to js array multi_data[data-id]
|
// Collect values of input fields with name "multi_select" and same data-id to js array multi_data[data-id]
|
||||||
var multi_data = [];
|
var multi_data = [];
|
||||||
$(document).on('change', 'input[name=multi_select]:checkbox', function() {
|
$(document).on('change', 'input[name=multi_select]:checkbox', function() {
|
||||||
if ($(this).is(':checked') && $(this).data('id')) {
|
if ($(this).is(':checked') && $(this).data('id')) {
|
||||||
|
@ -105,7 +105,8 @@ $(document).ready(function() {
|
||||||
url: '/api/v1/' + api_url,
|
url: '/api/v1/' + api_url,
|
||||||
jsonp: false,
|
jsonp: false,
|
||||||
complete: function(data) {
|
complete: function(data) {
|
||||||
// var reponse = (JSON.parse(data.responseText));
|
var response = (data.responseText);
|
||||||
|
// alert(response);
|
||||||
// console.log(reponse.type);
|
// console.log(reponse.type);
|
||||||
// console.log(reponse.msg);
|
// console.log(reponse.msg);
|
||||||
window.location = window.location.href.split("#")[0];
|
window.location = window.location.href.split("#")[0];
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -769,6 +769,21 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
|
||||||
echo '{}';
|
echo '{}';
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case "autodiscover":
|
||||||
|
if (isset($extra) && !empty($extra)) {
|
||||||
|
$extra = intval($extra);
|
||||||
|
$logs = get_logs('autodiscover-mailcow', $extra);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$logs = get_logs('autodiscover-mailcow', -1);
|
||||||
|
}
|
||||||
|
if (isset($logs) && !empty($logs)) {
|
||||||
|
echo json_encode($logs, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
echo '{}';
|
||||||
|
}
|
||||||
|
break;
|
||||||
case "sogo":
|
case "sogo":
|
||||||
if (isset($extra) && !empty($extra)) {
|
if (isset($extra) && !empty($extra)) {
|
||||||
$extra = intval($extra);
|
$extra = intval($extra);
|
||||||
|
@ -1780,6 +1795,48 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case "app_links":
|
||||||
|
if (isset($_POST['attr'])) {
|
||||||
|
$attr = (array)json_decode($_POST['attr'], true);
|
||||||
|
if (is_array($attr)) {
|
||||||
|
if (customize('edit', 'app_links', $attr) === false) {
|
||||||
|
if (isset($_SESSION['return'])) {
|
||||||
|
echo json_encode($_SESSION['return']);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
echo json_encode(array(
|
||||||
|
'type' => 'error',
|
||||||
|
'msg' => 'Edit failed'
|
||||||
|
));
|
||||||
|
}
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (isset($_SESSION['return'])) {
|
||||||
|
echo json_encode($_SESSION['return']);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
echo json_encode(array(
|
||||||
|
'type' => 'success',
|
||||||
|
'msg' => 'Task completed'
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
echo json_encode(array(
|
||||||
|
'type' => 'error',
|
||||||
|
'msg' => 'Incomplete post data'
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
echo json_encode(array(
|
||||||
|
'type' => 'error',
|
||||||
|
'msg' => 'Incomplete post data'
|
||||||
|
));
|
||||||
|
}
|
||||||
|
break;
|
||||||
case "relayhost":
|
case "relayhost":
|
||||||
if (isset($_POST['items']) && isset($_POST['attr'])) {
|
if (isset($_POST['items']) && isset($_POST['attr'])) {
|
||||||
$items = (array)json_decode($_POST['items'], true);
|
$items = (array)json_decode($_POST['items'], true);
|
||||||
|
|
|
@ -512,3 +512,14 @@ $lang['success']['relayhost_removed'] = "Relayhost %s wurde entfernt";
|
||||||
$lang['success']['relayhost_added'] = "Relayhost %s wurde hinzugefügt";
|
$lang['success']['relayhost_added'] = "Relayhost %s wurde hinzugefügt";
|
||||||
$lang['admin']['relay_from'] = "Absenderadresse";
|
$lang['admin']['relay_from'] = "Absenderadresse";
|
||||||
$lang['admin']['relay_run'] = "Test durchführen";
|
$lang['admin']['relay_run'] = "Test durchführen";
|
||||||
|
$lang['admin']['customize'] = "Anpassung";
|
||||||
|
$lang['admin']['change_logo'] = "Logo ändern";
|
||||||
|
$lang['admin']['logo_info'] = "Die hochgeladene Grafik wird für die Navigationsleiste auf eine Höhe von 40px skaliert. Für die Startseite ist eine Skalierung auf eine maximale Breite von 250px programmiert. Eine frei skalierbare Grafik (etwa SVG) wird empfohlen.";
|
||||||
|
$lang['admin']['upload'] = "Hochladen";
|
||||||
|
$lang['admin']['app_links'] = "App Links";
|
||||||
|
$lang['admin']['app_name'] = "App Name";
|
||||||
|
$lang['admin']['link'] = "Link";
|
||||||
|
$lang['admin']['remove_row'] = "Zeile entfernen";
|
||||||
|
$lang['admin']['add_row'] = "Zeile hinzufügen";
|
||||||
|
$lang['admin']['reset_default'] = "Auf Standard zurücksetzen";
|
||||||
|
$lang['admin']['merged_vars_hint'] = 'Ausgegraute Zeilen wurden aus der Datei <code>vars.inc.(local.)php</code> gelesen und können nicht mittels UI verändert werden.';
|
||||||
|
|
|
@ -141,9 +141,9 @@ $lang['user']['weeks'] = 'Weeks';
|
||||||
$lang['user']['spamfilter'] = 'Spam filter';
|
$lang['user']['spamfilter'] = 'Spam filter';
|
||||||
$lang['admin']['spamfilter'] = 'Spam filter';
|
$lang['admin']['spamfilter'] = 'Spam filter';
|
||||||
$lang['user']['spamfilter_wl'] = 'Whitelist';
|
$lang['user']['spamfilter_wl'] = 'Whitelist';
|
||||||
$lang['user']['spamfilter_wl_desc'] = 'Whitelisted email addresses to <b>never</b> classify as spam. Wildcards maybe used.';
|
$lang['user']['spamfilter_wl_desc'] = 'Whitelisted email addresses to <b>never</b> classify as spam. Wildcards may be used.';
|
||||||
$lang['user']['spamfilter_bl'] = 'Blacklist';
|
$lang['user']['spamfilter_bl'] = 'Blacklist';
|
||||||
$lang['user']['spamfilter_bl_desc'] = 'Blacklisted email addresses to <b>always</b> classify as spam and reject. Wildcards maybe used.';
|
$lang['user']['spamfilter_bl_desc'] = 'Blacklisted email addresses to <b>always</b> classify as spam and reject. Wildcards may be used.';
|
||||||
$lang['user']['spamfilter_behavior'] = 'Rating';
|
$lang['user']['spamfilter_behavior'] = 'Rating';
|
||||||
$lang['user']['spamfilter_table_rule'] = 'Rule';
|
$lang['user']['spamfilter_table_rule'] = 'Rule';
|
||||||
$lang['user']['spamfilter_table_action'] = 'Action';
|
$lang['user']['spamfilter_table_action'] = 'Action';
|
||||||
|
@ -525,3 +525,23 @@ $lang['success']['relayhost_removed'] = "Relayhost %s has been removed";
|
||||||
$lang['success']['relayhost_added'] = "Relayhost %s has been added";
|
$lang['success']['relayhost_added'] = "Relayhost %s has been added";
|
||||||
$lang['admin']['relay_from'] = '"From:" address';
|
$lang['admin']['relay_from'] = '"From:" address';
|
||||||
$lang['admin']['relay_run'] = "Run test";
|
$lang['admin']['relay_run'] = "Run test";
|
||||||
|
|
||||||
|
$lang['admin']['customize'] = "Customize";
|
||||||
|
$lang['admin']['change_logo'] = "Change logo";
|
||||||
|
$lang['admin']['logo_info'] = "Your image will be scaled to a height of 40px for the top navigation bar and a max. width of 250px for the start page. A scalable graphic is highly recommended.";
|
||||||
|
$lang['admin']['upload'] = "Upload";
|
||||||
|
$lang['admin']['app_links'] = "App links";
|
||||||
|
$lang['admin']['app_name'] = "App name";
|
||||||
|
$lang['admin']['link'] = "Link";
|
||||||
|
$lang['admin']['remove_row'] = "Remove row";
|
||||||
|
$lang['admin']['add_row'] = "Add row";
|
||||||
|
$lang['admin']['reset_default'] = "Reset to default";
|
||||||
|
$lang['admin']['merged_vars_hint'] = 'Greyed out rows were merged from <code>vars.inc.(local.)php</code> and cannot be modified.';
|
||||||
|
|
||||||
|
$lang['edit']['tls_policy'] = "Change TLS policy";
|
||||||
|
$lang['edit']['spam_score'] = "Set a custom spam score";
|
||||||
|
$lang['edit']['spam_policy'] = "Add or remove items to white-/blacklist";
|
||||||
|
$lang['edit']['delimiter_action'] = "Change delimiter action";
|
||||||
|
$lang['edit']['syncjobs'] = "Add or change sync jobs";
|
||||||
|
$lang['edit']['eas_reset'] = "Reset EAS devices";
|
||||||
|
$lang['edit']['spam_alias'] = "Create or change time limited alias addresses";
|
||||||
|
|
|
@ -406,6 +406,13 @@ if (!isset($_SESSION['mailcow_cc_role'])) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
|
<div class="checkbox">
|
||||||
|
<label><input type="checkbox" value="1" name="delete2"> <?=$lang['add']['delete2'];?></label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-sm-offset-2 col-sm-10">
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
|
|
|
@ -268,8 +268,8 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
|
||||||
<h4><?=$lang['user']['spamfilter_behavior'];?></h4>
|
<h4><?=$lang['user']['spamfilter_behavior'];?></h4>
|
||||||
<form class="form-horizontal" role="form" data-id="spam_score" method="post">
|
<form class="form-horizontal" role="form" data-id="spam_score" method="post">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-sm-12">
|
<div class="col-lg-6 col-sm-12">
|
||||||
<input name="spam_score" id="spam_score" type="text" style="width: 100% !important;"
|
<input name="spam_score" id="spam_score" type="text" style="width: 100%;"
|
||||||
data-provide="slider"
|
data-provide="slider"
|
||||||
data-slider-min="1"
|
data-slider-min="1"
|
||||||
data-slider-max="2000"
|
data-slider-max="2000"
|
||||||
|
@ -321,14 +321,13 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="policy_wl_mailbox" href="#"><span class="glyphicon glyphicon-check" aria-hidden="true"></span> <?=$lang['mailbox']['toggle_all'];?></a>
|
<a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="policy_wl_mailbox" href="#"><span class="glyphicon glyphicon-check" aria-hidden="true"></span> <?=$lang['mailbox']['toggle_all'];?></a>
|
||||||
<a class="btn btn-sm btn-danger" id="delete_selected" data-id="policy_wl_mailbox" data-api-url='delete/mailbox-policy' href="#"><?=$lang['mailbox']['remove'];?></a></li>
|
<a class="btn btn-sm btn-danger" id="delete_selected" data-id="policy_wl_mailbox" data-api-url='delete/mailbox-policy' href="#"><?=$lang['mailbox']['remove'];?></a></li>
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<form class="form-inline" data-id="add_wl_policy_mailbox">
|
<form class="form-inline" data-id="add_wl_policy_mailbox">
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="text" class="form-control" name="object_from" id="object_from" placeholder="*@example.org" required>
|
<input type="text" class="form-control" name="object_from" id="object_from" placeholder="*@example.org" required>
|
||||||
<span class="input-group-btn">
|
<span class="input-group-btn">
|
||||||
<button class="btn btn-success" id="add_item" data-id="add_wl_policy_mailbox" data-api-url='add/mailbox-policy' data-api-attr='{"username":"<?= $username; ?>","object_list":"wl"}' href="#"><span class="glyphicon glyphicon-plus"></span> <?=$lang['user']['spamfilter_table_add'];?></button>
|
<button class="btn btn-default" id="add_item" data-id="add_wl_policy_mailbox" data-api-url='add/mailbox-policy' data-api-attr='{"username":"<?= $username; ?>","object_list":"wl"}' href="#"><span class="glyphicon glyphicon-plus"></span> <?=$lang['user']['spamfilter_table_add'];?></button>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
@ -349,7 +348,6 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="policy_bl_mailbox" href="#"><span class="glyphicon glyphicon-check" aria-hidden="true"></span> <?=$lang['mailbox']['toggle_all'];?></a>
|
<a class="btn btn-sm btn-default" id="toggle_multi_select_all" data-id="policy_bl_mailbox" href="#"><span class="glyphicon glyphicon-check" aria-hidden="true"></span> <?=$lang['mailbox']['toggle_all'];?></a>
|
||||||
<a class="btn btn-sm btn-danger" id="delete_selected" data-id="policy_bl_mailbox" data-api-url='delete/mailbox-policy' href="#"><?=$lang['mailbox']['remove'];?></a></li>
|
<a class="btn btn-sm btn-danger" id="delete_selected" data-id="policy_bl_mailbox" data-api-url='delete/mailbox-policy' href="#"><?=$lang['mailbox']['remove'];?></a></li>
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<form class="form-inline" data-id="add_bl_policy_mailbox">
|
<form class="form-inline" data-id="add_bl_policy_mailbox">
|
||||||
|
@ -358,7 +356,7 @@ elseif (isset($_SESSION['mailcow_cc_role']) && $_SESSION['mailcow_cc_role'] == '
|
||||||
<input type="hidden" name="username" value="<?= $username ;?>">
|
<input type="hidden" name="username" value="<?= $username ;?>">
|
||||||
<input type="hidden" name="object_list" value="bl">
|
<input type="hidden" name="object_list" value="bl">
|
||||||
<span class="input-group-btn">
|
<span class="input-group-btn">
|
||||||
<button class="btn btn-success" id="add_item" data-id="add_bl_policy_mailbox" data-api-url='add/mailbox-policy' data-api-attr='{"username":"<?= $username; ?>","object_list":"bl"}' href="#"><span class="glyphicon glyphicon-plus"></span> <?=$lang['user']['spamfilter_table_add'];?></button>
|
<button class="btn btn-default" id="add_item" data-id="add_bl_policy_mailbox" data-api-url='add/mailbox-policy' data-api-attr='{"username":"<?= $username; ?>","object_list":"bl"}' href="#"><span class="glyphicon glyphicon-plus"></span> <?=$lang['user']['spamfilter_table_add'];?></button>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -5,7 +5,6 @@ services:
|
||||||
image: mailcow/unbound:1.0
|
image: mailcow/unbound:1.0
|
||||||
build: ./data/Dockerfiles/unbound
|
build: ./data/Dockerfiles/unbound
|
||||||
command: /usr/sbin/unbound
|
command: /usr/sbin/unbound
|
||||||
init: true
|
|
||||||
depends_on:
|
depends_on:
|
||||||
mysql-mailcow:
|
mysql-mailcow:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
@ -34,11 +33,9 @@ services:
|
||||||
- MYSQL_DATABASE=${DBNAME}
|
- MYSQL_DATABASE=${DBNAME}
|
||||||
- MYSQL_USER=${DBUSER}
|
- MYSQL_USER=${DBUSER}
|
||||||
- MYSQL_PASSWORD=${DBPASS}
|
- MYSQL_PASSWORD=${DBPASS}
|
||||||
init: true
|
|
||||||
restart: always
|
restart: always
|
||||||
dns:
|
dns:
|
||||||
- 172.22.1.254
|
- 172.22.1.254
|
||||||
dns_search: mailcow-network
|
|
||||||
networks:
|
networks:
|
||||||
mailcow-network:
|
mailcow-network:
|
||||||
ipv4_address: 172.22.1.250
|
ipv4_address: 172.22.1.250
|
||||||
|
@ -52,7 +49,6 @@ services:
|
||||||
restart: always
|
restart: always
|
||||||
dns:
|
dns:
|
||||||
- 172.22.1.254
|
- 172.22.1.254
|
||||||
dns_search: mailcow-network
|
|
||||||
networks:
|
networks:
|
||||||
mailcow-network:
|
mailcow-network:
|
||||||
ipv4_address: 172.22.1.249
|
ipv4_address: 172.22.1.249
|
||||||
|
@ -60,24 +56,22 @@ services:
|
||||||
- redis
|
- redis
|
||||||
|
|
||||||
clamd-mailcow:
|
clamd-mailcow:
|
||||||
image: mailcow/clamd:1.3
|
image: mailcow/clamd:1.5
|
||||||
build: ./data/Dockerfiles/clamd
|
build: ./data/Dockerfiles/clamd
|
||||||
restart: on-failure
|
restart: always
|
||||||
environment:
|
environment:
|
||||||
- SKIP_CLAMD=${SKIP_CLAMD:-n}
|
- SKIP_CLAMD=${SKIP_CLAMD:-n}
|
||||||
init: true
|
|
||||||
dns:
|
dns:
|
||||||
- 172.22.1.254
|
- 172.22.1.254
|
||||||
dns_search: mailcow-network
|
|
||||||
networks:
|
networks:
|
||||||
mailcow-network:
|
mailcow-network:
|
||||||
aliases:
|
aliases:
|
||||||
- clamd
|
- clamd
|
||||||
|
|
||||||
rspamd-mailcow:
|
rspamd-mailcow:
|
||||||
image: mailcow/rspamd:1.8
|
image: mailcow/rspamd:1.12
|
||||||
build: ./data/Dockerfiles/rspamd
|
build: ./data/Dockerfiles/rspamd
|
||||||
command: "/usr/bin/rspamd -f -u _rspamd -g _rspamd"
|
stop_grace_period: 30s
|
||||||
depends_on:
|
depends_on:
|
||||||
- nginx-mailcow
|
- nginx-mailcow
|
||||||
volumes:
|
volumes:
|
||||||
|
@ -88,10 +82,8 @@ services:
|
||||||
- dkim-vol-1:/data/dkim
|
- dkim-vol-1:/data/dkim
|
||||||
- rspamd-vol-1:/var/lib/rspamd
|
- rspamd-vol-1:/var/lib/rspamd
|
||||||
restart: always
|
restart: always
|
||||||
init: true
|
|
||||||
dns:
|
dns:
|
||||||
- 172.22.1.254
|
- 172.22.1.254
|
||||||
dns_search: mailcow-network
|
|
||||||
hostname: rspamd
|
hostname: rspamd
|
||||||
networks:
|
networks:
|
||||||
mailcow-network:
|
mailcow-network:
|
||||||
|
@ -100,13 +92,13 @@ services:
|
||||||
- rspamd
|
- rspamd
|
||||||
|
|
||||||
php-fpm-mailcow:
|
php-fpm-mailcow:
|
||||||
image: mailcow/phpfpm:1.1
|
image: mailcow/phpfpm:1.3
|
||||||
build: ./data/Dockerfiles/phpfpm
|
build: ./data/Dockerfiles/phpfpm
|
||||||
command: "php-fpm -d date.timezone=${TZ}"
|
command: "php-fpm -d date.timezone=${TZ} -d expose_php=0"
|
||||||
depends_on:
|
depends_on:
|
||||||
- redis-mailcow
|
- redis-mailcow
|
||||||
volumes:
|
volumes:
|
||||||
- ./data/web:/web:ro
|
- ./data/web:/web:rw
|
||||||
- ./data/conf/rspamd/dynmaps:/dynmaps:ro
|
- ./data/conf/rspamd/dynmaps:/dynmaps:ro
|
||||||
- dkim-vol-1:/data/dkim
|
- dkim-vol-1:/data/dkim
|
||||||
environment:
|
environment:
|
||||||
|
@ -125,14 +117,13 @@ services:
|
||||||
restart: always
|
restart: always
|
||||||
dns:
|
dns:
|
||||||
- 172.22.1.254
|
- 172.22.1.254
|
||||||
dns_search: mailcow-network
|
|
||||||
networks:
|
networks:
|
||||||
mailcow-network:
|
mailcow-network:
|
||||||
aliases:
|
aliases:
|
||||||
- phpfpm
|
- phpfpm
|
||||||
|
|
||||||
sogo-mailcow:
|
sogo-mailcow:
|
||||||
image: mailcow/sogo:1.8
|
image: mailcow/sogo:1.10
|
||||||
build: ./data/Dockerfiles/sogo
|
build: ./data/Dockerfiles/sogo
|
||||||
environment:
|
environment:
|
||||||
- DBNAME=${DBNAME}
|
- DBNAME=${DBNAME}
|
||||||
|
@ -145,7 +136,6 @@ services:
|
||||||
restart: always
|
restart: always
|
||||||
dns:
|
dns:
|
||||||
- 172.22.1.254
|
- 172.22.1.254
|
||||||
dns_search: mailcow-network
|
|
||||||
networks:
|
networks:
|
||||||
mailcow-network:
|
mailcow-network:
|
||||||
ipv4_address: 172.22.1.252
|
ipv4_address: 172.22.1.252
|
||||||
|
@ -153,7 +143,7 @@ services:
|
||||||
- sogo
|
- sogo
|
||||||
|
|
||||||
dovecot-mailcow:
|
dovecot-mailcow:
|
||||||
image: mailcow/dovecot:1.8
|
image: mailcow/dovecot:1.9
|
||||||
build: ./data/Dockerfiles/dovecot
|
build: ./data/Dockerfiles/dovecot
|
||||||
volumes:
|
volumes:
|
||||||
- ./data/conf/dovecot:/usr/local/etc/dovecot
|
- ./data/conf/dovecot:/usr/local/etc/dovecot
|
||||||
|
@ -180,7 +170,6 @@ services:
|
||||||
hard: 40000
|
hard: 40000
|
||||||
dns:
|
dns:
|
||||||
- 172.22.1.254
|
- 172.22.1.254
|
||||||
dns_search: mailcow-network
|
|
||||||
hostname: ${MAILCOW_HOSTNAME}
|
hostname: ${MAILCOW_HOSTNAME}
|
||||||
networks:
|
networks:
|
||||||
mailcow-network:
|
mailcow-network:
|
||||||
|
@ -188,7 +177,7 @@ services:
|
||||||
- dovecot
|
- dovecot
|
||||||
|
|
||||||
postfix-mailcow:
|
postfix-mailcow:
|
||||||
image: mailcow/postfix:1.4
|
image: mailcow/postfix:1.7
|
||||||
build: ./data/Dockerfiles/postfix
|
build: ./data/Dockerfiles/postfix
|
||||||
volumes:
|
volumes:
|
||||||
- ./data/conf/postfix:/opt/postfix/conf
|
- ./data/conf/postfix:/opt/postfix/conf
|
||||||
|
@ -206,7 +195,6 @@ services:
|
||||||
restart: always
|
restart: always
|
||||||
dns:
|
dns:
|
||||||
- 172.22.1.254
|
- 172.22.1.254
|
||||||
dns_search: mailcow-network
|
|
||||||
hostname: ${MAILCOW_HOSTNAME}
|
hostname: ${MAILCOW_HOSTNAME}
|
||||||
networks:
|
networks:
|
||||||
mailcow-network:
|
mailcow-network:
|
||||||
|
@ -218,7 +206,6 @@ services:
|
||||||
restart: always
|
restart: always
|
||||||
dns:
|
dns:
|
||||||
- 172.22.1.254
|
- 172.22.1.254
|
||||||
dns_search: mailcow-network
|
|
||||||
networks:
|
networks:
|
||||||
mailcow-network:
|
mailcow-network:
|
||||||
aliases:
|
aliases:
|
||||||
|
@ -232,6 +219,7 @@ services:
|
||||||
command: /bin/sh -c "envsubst < /etc/nginx/conf.d/templates/listen_plain.template > /etc/nginx/conf.d/listen_plain.active &&
|
command: /bin/sh -c "envsubst < /etc/nginx/conf.d/templates/listen_plain.template > /etc/nginx/conf.d/listen_plain.active &&
|
||||||
envsubst < /etc/nginx/conf.d/templates/listen_ssl.template > /etc/nginx/conf.d/listen_ssl.active &&
|
envsubst < /etc/nginx/conf.d/templates/listen_ssl.template > /etc/nginx/conf.d/listen_ssl.active &&
|
||||||
envsubst < /etc/nginx/conf.d/templates/server_name.template > /etc/nginx/conf.d/server_name.active &&
|
envsubst < /etc/nginx/conf.d/templates/server_name.template > /etc/nginx/conf.d/server_name.active &&
|
||||||
|
nginx -qt &&
|
||||||
until ping phpfpm -c1 > /dev/null; do sleep 1; done &&
|
until ping phpfpm -c1 > /dev/null; do sleep 1; done &&
|
||||||
exec nginx -g 'daemon off;'"
|
exec nginx -g 'daemon off;'"
|
||||||
environment:
|
environment:
|
||||||
|
@ -249,7 +237,6 @@ services:
|
||||||
restart: always
|
restart: always
|
||||||
dns:
|
dns:
|
||||||
- 172.22.1.254
|
- 172.22.1.254
|
||||||
dns_search: mailcow-network
|
|
||||||
networks:
|
networks:
|
||||||
mailcow-network:
|
mailcow-network:
|
||||||
ipv4_address: 172.22.1.251
|
ipv4_address: 172.22.1.251
|
||||||
|
@ -259,12 +246,11 @@ services:
|
||||||
acme-mailcow:
|
acme-mailcow:
|
||||||
depends_on:
|
depends_on:
|
||||||
- nginx-mailcow
|
- nginx-mailcow
|
||||||
image: mailcow/acme:1.17
|
- mysql-mailcow
|
||||||
|
image: mailcow/acme:1.22
|
||||||
build: ./data/Dockerfiles/acme
|
build: ./data/Dockerfiles/acme
|
||||||
init: true
|
|
||||||
dns:
|
dns:
|
||||||
- 172.22.1.254
|
- 172.22.1.254
|
||||||
dns_search: mailcow-network
|
|
||||||
environment:
|
environment:
|
||||||
- ADDITIONAL_SAN=${ADDITIONAL_SAN}
|
- ADDITIONAL_SAN=${ADDITIONAL_SAN}
|
||||||
- MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME}
|
- MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME}
|
||||||
|
@ -277,17 +263,16 @@ services:
|
||||||
- ./data/web/.well-known/acme-challenge:/var/www/acme:rw
|
- ./data/web/.well-known/acme-challenge:/var/www/acme:rw
|
||||||
- ./data/assets/ssl:/var/lib/acme/:rw
|
- ./data/assets/ssl:/var/lib/acme/:rw
|
||||||
- ./data/assets/ssl-example:/var/lib/ssl-example/:ro
|
- ./data/assets/ssl-example:/var/lib/ssl-example/:ro
|
||||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
restart: always
|
||||||
# do not restart the container too often. Things get worse when we hit let's encrypt's ratelimit.
|
|
||||||
restart: on-failure:1
|
|
||||||
networks:
|
networks:
|
||||||
mailcow-network:
|
mailcow-network:
|
||||||
aliases:
|
aliases:
|
||||||
- acme
|
- acme
|
||||||
|
|
||||||
fail2ban-mailcow:
|
fail2ban-mailcow:
|
||||||
image: mailcow/fail2ban:1.6
|
image: mailcow/fail2ban:1.7
|
||||||
build: ./data/Dockerfiles/fail2ban
|
build: ./data/Dockerfiles/fail2ban
|
||||||
|
stop_grace_period: 30s
|
||||||
depends_on:
|
depends_on:
|
||||||
- dovecot-mailcow
|
- dovecot-mailcow
|
||||||
- postfix-mailcow
|
- postfix-mailcow
|
||||||
|
@ -296,17 +281,45 @@ services:
|
||||||
- redis-mailcow
|
- redis-mailcow
|
||||||
restart: always
|
restart: always
|
||||||
privileged: true
|
privileged: true
|
||||||
init: true
|
|
||||||
environment:
|
environment:
|
||||||
- TZ=${TZ}
|
- TZ=${TZ}
|
||||||
- SKIP_FAIL2BAN=${SKIP_FAIL2BAN:-no}
|
- SKIP_FAIL2BAN=${SKIP_FAIL2BAN:-n}
|
||||||
network_mode: "host"
|
network_mode: "host"
|
||||||
dns:
|
dns:
|
||||||
- 172.22.1.254
|
- 172.22.1.254
|
||||||
dns_search: mailcow-network
|
|
||||||
volumes:
|
volumes:
|
||||||
- /lib/modules:/lib/modules:ro
|
- /lib/modules:/lib/modules:ro
|
||||||
|
|
||||||
|
watchdog-mailcow:
|
||||||
|
image: mailcow/watchdog:1.8
|
||||||
|
build: ./data/Dockerfiles/watchdog
|
||||||
|
volumes:
|
||||||
|
- vmail-vol-1:/vmail:ro
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
- DBNAME=${DBNAME}
|
||||||
|
- DBUSER=${DBUSER}
|
||||||
|
- DBPASS=${DBPASS}
|
||||||
|
- USE_WATCHDOG=${USE_WATCHDOG:-n}
|
||||||
|
- WATCHDOG_NOTIFY_EMAIL=${WATCHDOG_NOTIFY_EMAIL}
|
||||||
|
- MAILCOW_HOSTNAME=${MAILCOW_HOSTNAME}
|
||||||
|
networks:
|
||||||
|
mailcow-network:
|
||||||
|
ipv4_address: 172.22.1.248
|
||||||
|
aliases:
|
||||||
|
- watchdog
|
||||||
|
|
||||||
|
dockerapi-mailcow:
|
||||||
|
image: mailcow/dockerapi:1.0
|
||||||
|
stop_grace_period: 3s
|
||||||
|
build: ./data/Dockerfiles/dockerapi
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
networks:
|
||||||
|
mailcow-network:
|
||||||
|
aliases:
|
||||||
|
- dockerapi
|
||||||
|
|
||||||
ipv6nat:
|
ipv6nat:
|
||||||
image: robbertkl/ipv6nat
|
image: robbertkl/ipv6nat
|
||||||
restart: always
|
restart: always
|
||||||
|
|
|
@ -16,10 +16,10 @@ if [ -z "$MAILCOW_HOSTNAME" ]; then
|
||||||
read -p "Hostname (FQDN): " -ei "mx.example.org" MAILCOW_HOSTNAME
|
read -p "Hostname (FQDN): " -ei "mx.example.org" MAILCOW_HOSTNAME
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -a /etc/timezone ]]; then
|
if [[ -a /etc/timezone ]]; then
|
||||||
TZ=$(cat /etc/timezone)
|
TZ=$(cat /etc/timezone)
|
||||||
elif [[ -a /etc/localtime ]]; then
|
elif [[ -a /etc/localtime ]]; then
|
||||||
TZ=$(readlink /etc/localtime|sed -n 's|^.*zoneinfo/||p')
|
TZ=$(readlink /etc/localtime|sed -n 's|^.*zoneinfo/||p')
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "$TZ" ]; then
|
if [ -z "$TZ" ]; then
|
||||||
|
@ -84,18 +84,23 @@ COMPOSE_PROJECT_NAME=mailcow-dockerized
|
||||||
# Additional SAN for the certificate
|
# Additional SAN for the certificate
|
||||||
ADDITIONAL_SAN=
|
ADDITIONAL_SAN=
|
||||||
|
|
||||||
# To never run acme-mailcow for Let's Encrypt, set this to y
|
|
||||||
SKIP_LETS_ENCRYPT=n
|
|
||||||
|
|
||||||
# Skip IPv4 check in ACME container
|
# Skip running ACME (acme-mailcow, Let's Encrypt certs) - y/n
|
||||||
|
SKIP_LETS_ENCRYPT=n
|
||||||
|
# Skip IPv4 check in ACME container - y/n
|
||||||
SKIP_IP_CHECK=n
|
SKIP_IP_CHECK=n
|
||||||
|
|
||||||
# To never run fail2ban-mailcow
|
# Skip Fail2ban implementation (fail2ban-mailcow) - y/n
|
||||||
SKIP_FAIL2BAN=n
|
SKIP_FAIL2BAN=n
|
||||||
|
|
||||||
# To never run clamd-mailcow
|
# Skip ClamAV (clamd-mailcow) anti-virus (Rspamd will auto-detect a missing ClamAV container) - y/n
|
||||||
SKIP_CLAMD=n
|
SKIP_CLAMD=n
|
||||||
|
|
||||||
|
# Enable watchdog (watchdog-mailcow) to restart unhealthy containers (experimental)
|
||||||
|
USE_WATCHDOG=n
|
||||||
|
# Send notifications by mail (no DKIM signature, sent from watchdog@MAILCOW_HOSTNAME)
|
||||||
|
#WATCHDOG_NOTIFY_EMAIL=
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
mkdir -p data/assets/ssl
|
mkdir -p data/assets/ssl
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
#/bin/bash
|
||||||
|
[[ -f mailcow.conf ]] && source mailcow.conf
|
||||||
|
[[ -f ../mailcow.conf ]] && source ../mailcow.conf
|
||||||
|
|
||||||
|
if [[ -z ${DBUSER} ]] || [[ -z ${DBPASS} ]] || [[ -z ${DBNAME} ]]; then
|
||||||
|
echo "Cannot find mailcow.conf, make sure this script is run from within the mailcow folder."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -n "Checking MySQL service... "
|
||||||
|
if [[ -z $(docker ps -qf name=mysql-mailcow) ]]; then
|
||||||
|
echo "failed"
|
||||||
|
echo "MySQL (mysql-mailcow) is not up and running, exiting..."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "OK"
|
||||||
|
read -r -p "Are you sure you want to reset the mailcow administrator account? [y/N] " response
|
||||||
|
response=${response,,} # tolower
|
||||||
|
if [[ "$response" =~ ^(yes|y)$ ]]; then
|
||||||
|
echo -e "\nWorking, please wait..."
|
||||||
|
docker exec -it $(docker ps -qf name=mysql-mailcow) mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "DELETE FROM admin;"
|
||||||
|
docker exec -it $(docker ps -qf name=mysql-mailcow) mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "INSERT INTO admin (username, password, superadmin, created, modified, active) VALUES ('admin', '{SSHA256}K8eVJ6YsZbQCfuJvSUbaQRLr0HPLz5rC9IAp0PAFl0tmNDBkMDc0NDAyOTAxN2Rk', 1, NOW(), NOW(), 1);"
|
||||||
|
docker exec -it $(docker ps -qf name=mysql-mailcow) mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "DELETE FROM domain_admins WHERE username='admin';"
|
||||||
|
docker exec -it $(docker ps -qf name=mysql-mailcow) mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "INSERT INTO domain_admins (username, domain, created, active) VALUES ('admin', 'ALL', NOW(), 1);"
|
||||||
|
docker exec -it $(docker ps -qf name=mysql-mailcow) mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "DELETE FROM tfa WHERE username='admin';"
|
||||||
|
echo "
|
||||||
|
Reset credentials:
|
||||||
|
---
|
||||||
|
Username: admin
|
||||||
|
Password: moohoo
|
||||||
|
TFA: none
|
||||||
|
"
|
||||||
|
else
|
||||||
|
echo "Operation canceled."
|
||||||
|
fi
|
|
@ -0,0 +1,116 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
[[ -z ${1} ]] && { echo "No parameters given"; exit 1; }
|
||||||
|
|
||||||
|
for bin in curl dirmngr; do
|
||||||
|
if [[ -z $(which ${bin}) ]]; then echo "Cannot find ${bin}, exiting..."; exit 1; fi
|
||||||
|
done
|
||||||
|
|
||||||
|
while [ "$1" != '' ]; do
|
||||||
|
case "${1}" in
|
||||||
|
-p|--purge) NC_PURGE=y && shift;;
|
||||||
|
-i|--install) NC_INSTALL=y && shift;;
|
||||||
|
*) echo "Unknown parameter: ${1}" && shift;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
[[ ${NC_PURGE} == "y" ]] && [[ ${NC_INSTALL} == "y" ]] && { echo "Cannot use -p and -i at the same time"; }
|
||||||
|
|
||||||
|
source ./mailcow.conf
|
||||||
|
|
||||||
|
if [[ ${NC_PURGE} == "y" ]]; then
|
||||||
|
|
||||||
|
docker exec -it $(docker ps -f name=mysql-mailcow -q) mysql -uroot -p${DBROOT} -e \
|
||||||
|
"$(docker exec -it $(docker ps -f name=mysql-mailcow -q) mysql -uroot -p${DBROOT} -e "SELECT GROUP_CONCAT('DROP TABLE ', TABLE_SCHEMA, '.', TABLE_NAME SEPARATOR ';') FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME LIKE 'nc_%' AND TABLE_SCHEMA = '${DBNAME}';" -BN)"
|
||||||
|
docker exec -it $(docker ps -f name=redis-mailcow -q) /bin/sh -c 'redis-cli KEYS "*nextcloud*" | xargs redis-cli DEL'
|
||||||
|
if [ -d ./data/web/nextcloud/config ]; then
|
||||||
|
mv ./data/web/nextcloud/config/ ./data/conf/nextcloud-config-folder-$(date +%s).bak
|
||||||
|
fi
|
||||||
|
[[ -d ./data/web/nextcloud ]] && rm -rf ./data/web/nextcloud
|
||||||
|
|
||||||
|
[[ -f ./data/conf/nginx/site.nextcloud.custom ]] && mv ./data/conf/nginx/site.nextcloud.custom ./data/conf/nginx/site.nextcloud.custom-$(date +%s).bak
|
||||||
|
[[ -f ./data/conf/nginx/nextcloud.conf ]] && mv ./data/conf/nginx/nextcloud.conf ./data/conf/nginx/nextcloud.conf-$(date +%s).bak
|
||||||
|
|
||||||
|
docker-compose restart nginx-mailcow
|
||||||
|
|
||||||
|
elif [[ ${NC_INSTALL} == "y" ]]; then
|
||||||
|
|
||||||
|
NC_TYPE=
|
||||||
|
while [[ ! ${NC_TYPE} =~ ^subfolder$|^subdomain$ ]]; do
|
||||||
|
read -p "Configure as subdomain or subfolder? [subdomain/subfolder] " NC_TYPE
|
||||||
|
done
|
||||||
|
|
||||||
|
|
||||||
|
if [[ ${NC_TYPE} == "subdomain" ]]; then
|
||||||
|
NC_SUBD=
|
||||||
|
while [[ -z ${NC_SUBD} ]]; do
|
||||||
|
read -p "Which subdomain? [format: nextcloud.domain.tld] " NC_SUBD
|
||||||
|
done
|
||||||
|
if ! ping -q -c2 ${NC_SUBD} > /dev/null 2>&1 ; then
|
||||||
|
read -p "Cannot ping subdomain, continue anyway? [y|N] " NC_CONT_FAIL
|
||||||
|
[[ ! ${NC_CONT_FAIL,,} =~ ^(yes|y)$ ]] && { echo "Ok, exiting..."; exit 1; }
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
ADMIN_NC_PASS=$(</dev/urandom tr -dc A-Za-z0-9 | head -c 28)
|
||||||
|
NEXTCLOUD_VERSION=$(curl -s https://www.servercow.de/nextcloud/latest.php)
|
||||||
|
|
||||||
|
[[ -z ${NEXTCLOUD_VERSION} ]] && { echo "Error, cannot determine nextcloud version, exiting..."; exit 1; }
|
||||||
|
|
||||||
|
curl -L# -o nextcloud.tar.bz2 "https://download.nextcloud.com/server/releases/nextcloud-${NEXTCLOUD_VERSION}.tar.bz2" \
|
||||||
|
&& curl -L# -o nextcloud.tar.bz2.asc "https://download.nextcloud.com/server/releases/nextcloud-${NEXTCLOUD_VERSION}.tar.bz2.asc" \
|
||||||
|
&& export GNUPGHOME="$(mktemp -d)" \
|
||||||
|
&& gpg --keyserver ha.pool.sks-keyservers.net --recv-keys 28806A878AE423A28372792ED75899B9A724937A \
|
||||||
|
&& gpg --batch --verify nextcloud.tar.bz2.asc nextcloud.tar.bz2 \
|
||||||
|
&& rm -r "$GNUPGHOME" nextcloud.tar.bz2.asc \
|
||||||
|
&& tar -xjf nextcloud.tar.bz2 -C ./data/web/ \
|
||||||
|
&& rm nextcloud.tar.bz2 \
|
||||||
|
&& rm -rf ./data/web/nextcloud/updater \
|
||||||
|
&& mkdir -p ./data/web/nextcloud/data \
|
||||||
|
&& mkdir -p ./data/web/nextcloud/custom_apps \
|
||||||
|
&& chmod +x ./data/web/nextcloud/occ
|
||||||
|
|
||||||
|
docker exec -it $(docker ps -f name=php-fpm-mailcow -q) /bin/bash -c "chown -R www-data:www-data /web/nextcloud/data /web/nextcloud/config /web/nextcloud/apps /web/nextcloud/custom_apps"
|
||||||
|
docker exec -it -u www-data $(docker ps -f name=php-fpm-mailcow -q) /web/nextcloud/occ maintenance:install \
|
||||||
|
--database mysql \
|
||||||
|
--database-host mysql \
|
||||||
|
--database-name ${DBNAME} \
|
||||||
|
--database-user ${DBUSER} \
|
||||||
|
--database-pass ${DBPASS} \
|
||||||
|
--database-table-prefix nc_ \
|
||||||
|
--admin-user admin \
|
||||||
|
--admin-pass ${ADMIN_NC_PASS} \
|
||||||
|
--data-dir /web/nextcloud/data
|
||||||
|
|
||||||
|
docker exec -it -u www-data $(docker ps -f name=php-fpm-mailcow -q) bash -c "/web/nextcloud/occ config:system:set redis host --value=redis --type=string; \
|
||||||
|
/web/nextcloud/occ config:system:set redis port --value=6379 --type=integer; \
|
||||||
|
/web/nextcloud/occ config:system:set memcache.locking --value='\OC\Memcache\Redis' --type=string; \
|
||||||
|
/web/nextcloud/occ config:system:set memcache.local --value='\OC\Memcache\Redis' --type=string; \
|
||||||
|
/web/nextcloud/occ config:system:set trusted_proxies 0 --value=fd4d:6169:6c63:6f77::1; \
|
||||||
|
/web/nextcloud/occ config:system:set trusted_proxies 1 --value=172.22.1.0/24; \
|
||||||
|
/web/nextcloud/occ config:system:set overwritewebroot --value=/nextcloud; \
|
||||||
|
/web/nextcloud/occ config:system:set overwritehost --value=${MAILCOW_HOSTNAME}; \
|
||||||
|
/web/nextcloud/occ config:system:set mail_smtpmode --value=smtp; \
|
||||||
|
/web/nextcloud/occ config:system:set mail_smtpauthtype --value=LOGIN; \
|
||||||
|
/web/nextcloud/occ config:system:set mail_from_address --value=nextcloud; \
|
||||||
|
/web/nextcloud/occ config:system:set mail_domain --value=${MAILCOW_HOSTNAME}; \
|
||||||
|
/web/nextcloud/occ config:system:set mail_smtphost --value=postfix; \
|
||||||
|
/web/nextcloud/occ config:system:set mail_smtpport --value=588
|
||||||
|
/web/nextcloud/occ app:enable user_external
|
||||||
|
/web/nextcloud/occ config:system:set user_backends 0 arguments 0 --value={dovecot:143/imap/tls/novalidate-cert}
|
||||||
|
/web/nextcloud/occ config:system:set user_backends 0 class --value=OC_User_IMAP"
|
||||||
|
|
||||||
|
if [[ ${NC_TYPE} == "subdomain" ]]; then
|
||||||
|
docker exec -it -u www-data $(docker ps -f name=php-fpm-mailcow -q) /web/nextcloud/occ config:system:set overwritewebroot --value=/
|
||||||
|
docker exec -it -u www-data $(docker ps -f name=php-fpm-mailcow -q) /web/nextcloud/occ config:system:set overwritehost --value=nextcloud.develcow.de
|
||||||
|
cp ./data/assets/nextcloud/nextcloud.conf ./data/conf/nginx/
|
||||||
|
sed sed -i 's/NC_SUBD/${NC_SUBD}/g' ./data/assets/nextcloud/nextcloud.conf
|
||||||
|
elif [[ ${NC_TYPE} == "subfolder" ]]; then
|
||||||
|
cp ./data/assets/nextcloud/site.nextcloud.custom ./data/conf/nginx/
|
||||||
|
fi
|
||||||
|
|
||||||
|
docker-compose restart nginx-mailcow
|
||||||
|
|
||||||
|
echo "Login as admin with password: ${ADMIN_NC_PASS}"
|
||||||
|
|
||||||
|
fi
|
|
@ -1,36 +0,0 @@
|
||||||
#/bin/bash
|
|
||||||
if [[ ! -f mailcow.conf ]]; then
|
|
||||||
echo "Cannot find mailcow.conf, make sure this script is run from within the mailcow folder."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -n "Checking MySQL service... "
|
|
||||||
docker-compose ps -q mysql-mailcow > /dev/null 2>&1
|
|
||||||
|
|
||||||
if [[ $? -ne 0 ]]; then
|
|
||||||
echo "failed"
|
|
||||||
echo "MySQL (mysql-mailcow) is not up and running, exiting..."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "OK"
|
|
||||||
read -r -p "Are you sure you want to reset the mailcow administrator account? [y/N] " response
|
|
||||||
response=${response,,} # tolower
|
|
||||||
if [[ "$response" =~ ^(yes|y)$ ]]; then
|
|
||||||
echo -e "\nWorking, please wait..."
|
|
||||||
source mailcow.conf
|
|
||||||
docker-compose exec -T mysql-mailcow mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "DELETE FROM admin;"
|
|
||||||
docker-compose exec -T mysql-mailcow mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "INSERT INTO admin (username, password, superadmin, created, modified, active) VALUES ('admin', '{SSHA256}K8eVJ6YsZbQCfuJvSUbaQRLr0HPLz5rC9IAp0PAFl0tmNDBkMDc0NDAyOTAxN2Rk', 1, NOW(), NOW(), 1);"
|
|
||||||
docker-compose exec -T mysql-mailcow mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "DELETE FROM domain_admins WHERE username='admin';"
|
|
||||||
docker-compose exec -T mysql-mailcow mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "INSERT INTO domain_admins (username, domain, created, active) VALUES ('admin', 'ALL', NOW(), 1);"
|
|
||||||
docker-compose exec -T mysql-mailcow mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "DELETE FROM tfa WHERE username='admin';"
|
|
||||||
echo "
|
|
||||||
Reset credentials:
|
|
||||||
---
|
|
||||||
Username: admin
|
|
||||||
Password: moohoo
|
|
||||||
TFA: none
|
|
||||||
"
|
|
||||||
else
|
|
||||||
echo "Operation canceled."
|
|
||||||
fi
|
|
|
@ -1,76 +0,0 @@
|
||||||
#/bin/bash
|
|
||||||
if [[ ! -f mailcow.conf ]]; then
|
|
||||||
echo "Cannot find mailcow.conf, make sure this script is run from within the mailcow folder."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -n "Checking Postfix service... "
|
|
||||||
docker-compose ps -q postfix-mailcow > /dev/null 2>&1
|
|
||||||
|
|
||||||
if [[ $? -ne 0 ]]; then
|
|
||||||
echo "failed"
|
|
||||||
echo "Postfix (postifx-mailcow) is not up and running, exiting..."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "OK"
|
|
||||||
|
|
||||||
if [[ -z ${1} ]]; then
|
|
||||||
echo "Usage:"
|
|
||||||
echo
|
|
||||||
echo "Setup a relayhost:"
|
|
||||||
echo "${0} relayhost port (username) (password)"
|
|
||||||
echo "Username and password are optional parameters."
|
|
||||||
echo
|
|
||||||
echo "Reset to defaults:"
|
|
||||||
echo "${0} reset"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ${1} == "reset" ]]; then
|
|
||||||
# Reset modified values to their defaults
|
|
||||||
sed -i "s/^relayhost\ \=.*/relayhost\ \=/" data/conf/postfix/main.cf
|
|
||||||
sed -i "s/^smtp\_sasl\_password\_maps.*/smtp\_sasl\_password\_maps\ \=/" data/conf/postfix/main.cf
|
|
||||||
sed -i "s/^smtp\_sasl\_security\_options.*/smtp\_sasl\_security\_options\ \=\ noplaintext\,\ noanonymous/" data/conf/postfix/main.cf
|
|
||||||
sed -i "s/^smtp\_sasl\_auth\_enable.*/smtp\_sasl\_auth\_enable\ \=\ no/" data/conf/postfix/main.cf
|
|
||||||
# Also delete the plaintext password file
|
|
||||||
rm -f data/conf/postfix/smarthost_passwd*
|
|
||||||
docker-compose exec postfix-mailcow postfix reload
|
|
||||||
# Exit with dc exit code
|
|
||||||
exit $?
|
|
||||||
else
|
|
||||||
# Try a simple connection to host:port but don't recieve any data
|
|
||||||
# Abort after 3 seconds
|
|
||||||
if ! nc -z -v -w3 ${1} ${2} 2>/dev/null; then
|
|
||||||
echo "Connection to relayhost ${1} failed, aborting..."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
# Use exact hostname as relayhost, don't lookup the MX record of relayhost
|
|
||||||
sed -i "s/relayhost\ \=.*/relayhost\ \=\ \[${1}\]\:${2}/" data/conf/postfix/main.cf
|
|
||||||
if grep -q "smtp_sasl_password_maps" data/conf/postfix/main.cf
|
|
||||||
then
|
|
||||||
sed -i "s/^smtp\_sasl\_password\_maps.*/smtp\_sasl\_password\_maps\ \=\ hash\:\/opt\/postfix\/conf\/smarthost\_passwd/" data/conf/postfix/main.cf
|
|
||||||
else
|
|
||||||
echo "smtp_sasl_password_maps = hash:/opt/postfix/conf/smarthost_passwd" >> data/conf/postfix/main.cf
|
|
||||||
fi
|
|
||||||
if grep -q "smtp_sasl_auth_enable" data/conf/postfix/main.cf
|
|
||||||
then
|
|
||||||
sed -i "s/^smtp\_sasl\_auth\_enable.*/smtp\_sasl\_auth\_enable\ \=\ yes/" data/conf/postfix/main.cf
|
|
||||||
else
|
|
||||||
echo "smtp_sasl_auth_enable = yes" >> data/conf/postfix/main.cf
|
|
||||||
fi
|
|
||||||
if grep -q "smtp_sasl_security_options" data/conf/postfix/main.cf
|
|
||||||
then
|
|
||||||
sed -i "s/^smtp\_sasl\_security\_options.*/smtp\_sasl\_security\_options\ \=/" data/conf/postfix/main.cf
|
|
||||||
else
|
|
||||||
echo "smtp_sasl_security_options =" >> data/conf/postfix/main.cf
|
|
||||||
fi
|
|
||||||
if [[ ! -z ${3} ]]; then
|
|
||||||
echo ${1} ${3}:${4} > data/conf/postfix/smarthost_passwd
|
|
||||||
docker-compose exec postfix-mailcow postmap /opt/postfix/conf/smarthost_passwd
|
|
||||||
fi
|
|
||||||
docker-compose exec postfix-mailcow chown root:postfix /opt/postfix/conf/smarthost_passwd /opt/postfix/conf/smarthost_passwd.db
|
|
||||||
docker-compose exec postfix-mailcow chmod 660 /opt/postfix/conf/smarthost_passwd /opt/postfix/conf/smarthost_passwd.db
|
|
||||||
docker-compose exec postfix-mailcow postfix reload
|
|
||||||
exit $?
|
|
||||||
fi
|
|
|
@ -4,7 +4,7 @@ for bin in curl docker-compose docker git awk sha1sum; do
|
||||||
if [[ -z $(which ${bin}) ]]; then echo "Cannot find ${bin}, exiting..."; exit 1; fi
|
if [[ -z $(which ${bin}) ]]; then echo "Cannot find ${bin}, exiting..."; exit 1; fi
|
||||||
done
|
done
|
||||||
|
|
||||||
CONFIG_ARRAY=("SKIP_LETS_ENCRYPT" "SKIP_CLAMD" "SKIP_IP_CHECK" "SKIP_FAIL2BAN" "ADDITIONAL_SAN" "DOVEADM_PORT")
|
CONFIG_ARRAY=("SKIP_LETS_ENCRYPT" "USE_WATCHDOG" "WATCHDOG_NOTIFY_EMAIL" "SKIP_CLAMD" "SKIP_IP_CHECK" "SKIP_FAIL2BAN" "ADDITIONAL_SAN" "DOVEADM_PORT")
|
||||||
echo >> mailcow.conf
|
echo >> mailcow.conf
|
||||||
for option in ${CONFIG_ARRAY[@]}; do
|
for option in ${CONFIG_ARRAY[@]}; do
|
||||||
if [[ ${option} == "ADDITIONAL_SAN" ]]; then
|
if [[ ${option} == "ADDITIONAL_SAN" ]]; then
|
||||||
|
@ -22,6 +22,11 @@ for option in ${CONFIG_ARRAY[@]}; do
|
||||||
echo "Adding new option \"${option}\" to mailcow.conf"
|
echo "Adding new option \"${option}\" to mailcow.conf"
|
||||||
echo "DOVEADM_PORT=127.0.0.1:19991" >> mailcow.conf
|
echo "DOVEADM_PORT=127.0.0.1:19991" >> mailcow.conf
|
||||||
fi
|
fi
|
||||||
|
elif [[ ${option} == "WATCHDOG_NOTIFY_EMAIL" ]]; then
|
||||||
|
if ! grep -q ${option} mailcow.conf; then
|
||||||
|
echo "Adding new option \"${option}\" to mailcow.conf"
|
||||||
|
echo "WATCHDOG_NOTIFY_EMAIL=" >> mailcow.conf
|
||||||
|
fi
|
||||||
elif ! grep -q ${option} mailcow.conf; then
|
elif ! grep -q ${option} mailcow.conf; then
|
||||||
echo "Adding new option \"${option}\" to mailcow.conf"
|
echo "Adding new option \"${option}\" to mailcow.conf"
|
||||||
echo "${option}=n" >> mailcow.conf
|
echo "${option}=n" >> mailcow.conf
|
||||||
|
|
Loading…
Reference in New Issue