mirror of
https://github.com/docker-mailserver/docker-mailserver.git
synced 2024-01-19 02:48:50 +00:00
refactoring: split helper functions into smaller scripts (#2420)
This commit is contained in:
parent
2927cc47c7
commit
b61dfe1e24
|
@ -279,6 +279,7 @@ COPY \
|
||||||
./target/bin/* \
|
./target/bin/* \
|
||||||
./target/scripts/*.sh \
|
./target/scripts/*.sh \
|
||||||
./target/scripts/startup/*.sh \
|
./target/scripts/startup/*.sh \
|
||||||
|
./target/scripts/wrapper/*.sh \
|
||||||
./target/docker-configomat/configomat.sh \
|
./target/docker-configomat/configomat.sh \
|
||||||
/usr/local/bin/
|
/usr/local/bin/
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,6 @@ def retrieve_data():
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# No match == 'None', we convert to empty string for
|
# No match == 'None', we convert to empty string for
|
||||||
# existing error handling by `helper-functions.sh`:
|
# existing error handling:
|
||||||
result = retrieve_data() or ''
|
result = retrieve_data() or ''
|
||||||
print(result)
|
print(result)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
|
|
||||||
# shellcheck source=../scripts/helper-functions.sh
|
# shellcheck source=../scripts/helpers/index.sh
|
||||||
. /usr/local/bin/helper-functions.sh
|
source /usr/local/bin/helpers/index.sh
|
||||||
|
|
||||||
DATABASE=${DATABASE:-/tmp/docker-mailserver/postfix-virtual.cf}
|
DATABASE=${DATABASE:-/tmp/docker-mailserver/postfix-virtual.cf}
|
||||||
|
|
||||||
|
@ -36,14 +36,14 @@ function __usage
|
||||||
EMAIL="${1}"
|
EMAIL="${1}"
|
||||||
RECIPIENT="${2}"
|
RECIPIENT="${2}"
|
||||||
|
|
||||||
[[ -z ${EMAIL} ]] && { __usage ; errex 'No alias specified' ; }
|
[[ -z ${EMAIL} ]] && { __usage ; _errex 'No alias specified' ; }
|
||||||
[[ -z ${RECIPIENT} ]] && { __usage ; errex 'No recipient specified' ; }
|
[[ -z ${RECIPIENT} ]] && { __usage ; _errex 'No recipient specified' ; }
|
||||||
|
|
||||||
grep \
|
grep \
|
||||||
-qi "^$(escape "${EMAIL}")[a-zA-Z@.\ ]*$(escape "${RECIPIENT}")" \
|
-qi "^$(_escape "${EMAIL}")[a-zA-Z@.\ ]*$(_escape "${RECIPIENT}")" \
|
||||||
"${DATABASE}" 2>/dev/null && errex "Alias \"${EMAIL} ${RECIPIENT}\" already exists"
|
"${DATABASE}" 2>/dev/null && _errex "Alias \"${EMAIL} ${RECIPIENT}\" already exists"
|
||||||
|
|
||||||
if grep -qi "^$(escape "${EMAIL}")" "${DATABASE}" 2>/dev/null
|
if grep -qi "^$(_escape "${EMAIL}")" "${DATABASE}" 2>/dev/null
|
||||||
then
|
then
|
||||||
sed -i "/${EMAIL}/s/$/,${RECIPIENT}/" "${DATABASE}"
|
sed -i "/${EMAIL}/s/$/,${RECIPIENT}/" "${DATABASE}"
|
||||||
else
|
else
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
# shellcheck disable=SC2094
|
# shellcheck disable=SC2094
|
||||||
|
|
||||||
# shellcheck source=../scripts/helper-functions.sh
|
# shellcheck source=../scripts/helpers/index.sh
|
||||||
. /usr/local/bin/helper-functions.sh
|
source /usr/local/bin/helpers/index.sh
|
||||||
|
|
||||||
DATABASE=${DATABASE:-/tmp/docker-mailserver/postfix-accounts.cf}
|
DATABASE=${DATABASE:-/tmp/docker-mailserver/postfix-accounts.cf}
|
||||||
|
|
||||||
|
@ -39,12 +39,12 @@ FULL_EMAIL="${1}"
|
||||||
shift
|
shift
|
||||||
PASSWD="${*}"
|
PASSWD="${*}"
|
||||||
|
|
||||||
[[ -z ${FULL_EMAIL} ]] && { __usage ; errex 'No username specified' ; }
|
[[ -z ${FULL_EMAIL} ]] && { __usage ; _errex 'No username specified' ; }
|
||||||
[[ ${FULL_EMAIL} =~ .*\@.* ]] || { __usage ; errex 'Username must include the domain' ; }
|
[[ ${FULL_EMAIL} =~ .*\@.* ]] || { __usage ; _errex 'Username must include the domain' ; }
|
||||||
|
|
||||||
touch "${DATABASE}"
|
touch "${DATABASE}"
|
||||||
create_lock # Protect config file with lock to avoid race conditions
|
_create_lock # Protect config file with lock to avoid race conditions
|
||||||
if grep -qi "^$(escape "${FULL_EMAIL}")|" "${DATABASE}"
|
if grep -qi "^$(_escape "${FULL_EMAIL}")|" "${DATABASE}"
|
||||||
then
|
then
|
||||||
echo "User '${FULL_EMAIL}' already exists."
|
echo "User '${FULL_EMAIL}' already exists."
|
||||||
exit 1
|
exit 1
|
||||||
|
@ -54,7 +54,7 @@ if [[ -z ${PASSWD} ]]
|
||||||
then
|
then
|
||||||
read -r -s -p "Enter Password: " PASSWD
|
read -r -s -p "Enter Password: " PASSWD
|
||||||
echo
|
echo
|
||||||
[[ -z ${PASSWD} ]] && errex "Password must not be empty"
|
[[ -z ${PASSWD} ]] && _errex "Password must not be empty"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
HASH="$(doveadm pw -s SHA512-CRYPT -u "${FULL_EMAIL}" -p "${PASSWD}")"
|
HASH="$(doveadm pw -s SHA512-CRYPT -u "${FULL_EMAIL}" -p "${PASSWD}")"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
|
|
||||||
# shellcheck source=../scripts/helper-functions.sh
|
# shellcheck source=../scripts/helpers/index.sh
|
||||||
. /usr/local/bin/helper-functions.sh
|
source /usr/local/bin/helpers/index.sh
|
||||||
|
|
||||||
DATABASE=${DATABASE:-/tmp/docker-mailserver/postfix-relaymap.cf}
|
DATABASE=${DATABASE:-/tmp/docker-mailserver/postfix-relaymap.cf}
|
||||||
|
|
||||||
|
@ -32,8 +32,8 @@ DOMAIN="${1}"
|
||||||
HOST="${2}"
|
HOST="${2}"
|
||||||
PORT="${3}"
|
PORT="${3}"
|
||||||
|
|
||||||
[[ -z ${DOMAIN} ]] && { __usage ; errex 'No domain specified' ; }
|
[[ -z ${DOMAIN} ]] && { __usage ; _errex 'No domain specified' ; }
|
||||||
[[ -z ${HOST} ]] && { __usage ; errex 'No relay host specified' ; }
|
[[ -z ${HOST} ]] && { __usage ; _errex 'No relay host specified' ; }
|
||||||
[[ -z ${PORT} ]] && PORT=25
|
[[ -z ${PORT} ]] && PORT=25
|
||||||
|
|
||||||
if grep -qi "^@${DOMAIN}" "${DATABASE}" 2>/dev/null
|
if grep -qi "^@${DOMAIN}" "${DATABASE}" 2>/dev/null
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
|
|
||||||
# shellcheck source=../scripts/helper-functions.sh
|
# shellcheck source=../scripts/helpers/index.sh
|
||||||
. /usr/local/bin/helper-functions.sh
|
source /usr/local/bin/helpers/index.sh
|
||||||
|
|
||||||
DATABASE=${DATABASE:-/tmp/docker-mailserver/postfix-sasl-password.cf}
|
DATABASE=${DATABASE:-/tmp/docker-mailserver/postfix-sasl-password.cf}
|
||||||
|
|
||||||
|
@ -13,14 +13,14 @@ DOMAIN="${1}"
|
||||||
USER="${2}"
|
USER="${2}"
|
||||||
PASSWD="${3}"
|
PASSWD="${3}"
|
||||||
|
|
||||||
[[ -z ${DOMAIN} ]] && { __usage ; errex 'No domain specified' ; }
|
[[ -z ${DOMAIN} ]] && { __usage ; _errex 'No domain specified' ; }
|
||||||
[[ -z ${USER} ]] && { __usage ; errex 'No username specified' ; }
|
[[ -z ${USER} ]] && { __usage ; _errex 'No username specified' ; }
|
||||||
|
|
||||||
if [[ -z ${PASSWD} ]]
|
if [[ -z ${PASSWD} ]]
|
||||||
then
|
then
|
||||||
read -r -s -p "Enter Password: " PASSWD
|
read -r -s -p "Enter Password: " PASSWD
|
||||||
echo
|
echo
|
||||||
[[ -z ${PASSWD} ]] && errex 'Password must not be empty'
|
[[ -z ${PASSWD} ]] && _errex 'Password must not be empty'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if grep -qi "^@${DOMAIN}" "${DATABASE}" 2>/dev/null
|
if grep -qi "^@${DOMAIN}" "${DATABASE}" 2>/dev/null
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
|
|
||||||
# shellcheck source=../scripts/helper-functions.sh
|
# shellcheck source=../scripts/helpers/index.sh
|
||||||
. /usr/local/bin/helper-functions.sh
|
source /usr/local/bin/helpers/index.sh
|
||||||
|
|
||||||
DATABASE=${DATABASE:-/tmp/docker-mailserver/postfix-virtual.cf}
|
DATABASE=${DATABASE:-/tmp/docker-mailserver/postfix-virtual.cf}
|
||||||
|
|
||||||
|
@ -12,8 +12,8 @@ function __usage { echo "Usage: delalias <alias@domain> <recipient@other>" ; }
|
||||||
|
|
||||||
[[ ${1:-} == 'help' ]] && { __usage ; exit 0 ; }
|
[[ ${1:-} == 'help' ]] && { __usage ; exit 0 ; }
|
||||||
|
|
||||||
[[ -z ${EMAIL} ]] && { __usage ; errex "Error: No alias specified" ; }
|
[[ -z ${EMAIL} ]] && { __usage ; _errex "Error: No alias specified" ; }
|
||||||
[[ -z ${RECIPIENT} ]] && { __usage ; errex "Error: No recipient specified" ; }
|
[[ -z ${RECIPIENT} ]] && { __usage ; _errex "Error: No recipient specified" ; }
|
||||||
[[ -s ${DATABASE} ]] || exit 0
|
[[ -s ${DATABASE} ]] || exit 0
|
||||||
|
|
||||||
sed -i \
|
sed -i \
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
# ? the same file in the same pipeline", which is a result of ${DATABASE}
|
# ? the same file in the same pipeline", which is a result of ${DATABASE}
|
||||||
# ? being used below. (This disables the message file-wide.)
|
# ? being used below. (This disables the message file-wide.)
|
||||||
|
|
||||||
# shellcheck source=../scripts/helper-functions.sh
|
# shellcheck source=../scripts/helpers/index.sh
|
||||||
. /usr/local/bin/helper-functions.sh
|
source /usr/local/bin/helpers/index.sh
|
||||||
|
|
||||||
DATABASE=${DATABASE:-/tmp/docker-mailserver/postfix-accounts.cf}
|
DATABASE=${DATABASE:-/tmp/docker-mailserver/postfix-accounts.cf}
|
||||||
ALIAS_DATABASE="/tmp/docker-mailserver/postfix-virtual.cf"
|
ALIAS_DATABASE="/tmp/docker-mailserver/postfix-virtual.cf"
|
||||||
|
@ -67,14 +67,14 @@ do
|
||||||
|
|
||||||
* )
|
* )
|
||||||
__usage
|
__usage
|
||||||
errex "The option ${OPT} is unknown."
|
_errex "The option ${OPT} is unknown."
|
||||||
;;
|
;;
|
||||||
|
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
shift $((OPTIND-1))
|
shift $((OPTIND-1))
|
||||||
|
|
||||||
[[ -z ${*} ]] && { __usage ; errex "No user specifed" ; }
|
[[ -z ${*} ]] && { __usage ; _errex "No user specifed" ; }
|
||||||
[[ -s ${DATABASE} ]] || exit 0
|
[[ -s ${DATABASE} ]] || exit 0
|
||||||
|
|
||||||
if ! ${MAILDEL}
|
if ! ${MAILDEL}
|
||||||
|
@ -86,7 +86,7 @@ then
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
create_lock # Protect config file with lock to avoid race conditions
|
_create_lock # Protect config file with lock to avoid race conditions
|
||||||
|
|
||||||
for EMAIL in "${@}"
|
for EMAIL in "${@}"
|
||||||
do
|
do
|
||||||
|
@ -97,7 +97,7 @@ do
|
||||||
|
|
||||||
# ${EMAIL} must not contain /s and other syntactic characters
|
# ${EMAIL} must not contain /s and other syntactic characters
|
||||||
UNESCAPED_EMAIL="${EMAIL}"
|
UNESCAPED_EMAIL="${EMAIL}"
|
||||||
EMAIL=$(escape "${EMAIL}")
|
EMAIL=$(_escape "${EMAIL}")
|
||||||
|
|
||||||
if [[ -f ${DATABASE} ]]
|
if [[ -f ${DATABASE} ]]
|
||||||
then
|
then
|
||||||
|
@ -155,6 +155,6 @@ use 'sudo docker exec mailserver rm -R /var/mail/${DOMAIN}/${USER}'"
|
||||||
ERROR=true
|
ERROR=true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
${ERROR} && errex 'See the messages above.'
|
${ERROR} && _errex 'See the messages above.'
|
||||||
done
|
done
|
||||||
exit 0
|
exit 0
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
|
|
||||||
# shellcheck source=../scripts/helper-functions.sh
|
# shellcheck source=../scripts/helpers/index.sh
|
||||||
. /usr/local/bin/helper-functions.sh
|
source /usr/local/bin/helpers/index.sh
|
||||||
|
|
||||||
DATABASE=${DATABASE:-/tmp/docker-mailserver/dovecot-quotas.cf}
|
DATABASE=${DATABASE:-/tmp/docker-mailserver/dovecot-quotas.cf}
|
||||||
USER_DATABASE=${USER_DATABASE:-/tmp/docker-mailserver/postfix-accounts.cf}
|
USER_DATABASE=${USER_DATABASE:-/tmp/docker-mailserver/postfix-accounts.cf}
|
||||||
|
@ -12,13 +12,13 @@ function __usage { echo "Usage: delquota <username@domain>" ; }
|
||||||
|
|
||||||
USER="${1}"
|
USER="${1}"
|
||||||
|
|
||||||
[[ -z ${USER} ]] && { __usage ; errex "No username specified" ; }
|
[[ -z ${USER} ]] && { __usage ; _errex "No username specified" ; }
|
||||||
[[ ${USER} =~ .*\@.* ]] || { __usage ; errex "Username must include the domain"; }
|
[[ ${USER} =~ .*\@.* ]] || { __usage ; _errex "Username must include the domain"; }
|
||||||
|
|
||||||
if ! grep -qE "^${USER}\|" "${USER_DATABASE}"
|
if ! grep -qE "^${USER}\|" "${USER_DATABASE}"
|
||||||
then
|
then
|
||||||
__usage
|
__usage
|
||||||
errex "user ${USER} does not exist"
|
_errex "user ${USER} does not exist"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
[[ -s ${DATABASE} ]] || exit 0
|
[[ -s ${DATABASE} ]] || exit 0
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
|
|
||||||
# shellcheck source=../scripts/helper-functions.sh
|
# shellcheck source=../scripts/helpers/index.sh
|
||||||
. /usr/local/bin/helper-functions.sh
|
source /usr/local/bin/helpers/index.sh
|
||||||
|
|
||||||
DATABASE=${DATABASE:-/tmp/docker-mailserver/postfix-relaymap.cf}
|
DATABASE=${DATABASE:-/tmp/docker-mailserver/postfix-relaymap.cf}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ DOMAIN="${1}"
|
||||||
|
|
||||||
function usage { echo "Usage: excluderelayhost <domain>" ; }
|
function usage { echo "Usage: excluderelayhost <domain>" ; }
|
||||||
|
|
||||||
[[ -z ${DOMAIN} ]] && { usage ; errex "no domain specified" ; }
|
[[ -z ${DOMAIN} ]] && { usage ; _errex "no domain specified" ; }
|
||||||
|
|
||||||
if grep -qi "^@${DOMAIN}" "${DATABASE}" 2>/dev/null
|
if grep -qi "^@${DOMAIN}" "${DATABASE}" 2>/dev/null
|
||||||
then
|
then
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
|
|
||||||
# shellcheck source=../scripts/helper-functions.sh
|
# shellcheck source=../scripts/helpers/index.sh
|
||||||
. /usr/local/bin/helper-functions.sh
|
source /usr/local/bin/helpers/index.sh
|
||||||
|
|
||||||
if ! IPTABLES_OUTPUT=$(iptables -L -n 2>&1)
|
if ! IPTABLES_OUTPUT=$(iptables -L -n 2>&1)
|
||||||
then
|
then
|
||||||
|
@ -75,7 +75,7 @@ else
|
||||||
|
|
||||||
*)
|
*)
|
||||||
usage
|
usage
|
||||||
errex "unknown command: ${1}"
|
_errex "unknown command: ${1}"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
esac
|
esac
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
|
|
||||||
# shellcheck source=../scripts/helper-functions.sh
|
# shellcheck source=../scripts/helpers/index.sh
|
||||||
. /usr/local/bin/helper-functions.sh
|
source /usr/local/bin/helpers/index.sh
|
||||||
|
|
||||||
DATABASE=${DATABASE:-/tmp/docker-mailserver/postfix-virtual.cf}
|
DATABASE=${DATABASE:-/tmp/docker-mailserver/postfix-virtual.cf}
|
||||||
|
|
||||||
[[ -f ${DATABASE} ]] || errex "Error: No postfix-virtual.cf file"
|
[[ -f ${DATABASE} ]] || _errex "Error: No postfix-virtual.cf file"
|
||||||
[[ -s ${DATABASE} ]] || errex "Error: Empty postfix-virtual.cf - no aliases have been added"
|
[[ -s ${DATABASE} ]] || _errex "Error: Empty postfix-virtual.cf - no aliases have been added"
|
||||||
|
|
||||||
grep -v "^\s*$\|^\s*\#" "${DATABASE}"
|
grep -v "^\s*$\|^\s*\#" "${DATABASE}"
|
||||||
exit 0
|
exit 0
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
|
|
||||||
# shellcheck source=../scripts/helper-functions.sh
|
# shellcheck source=../scripts/helpers/index.sh
|
||||||
. /usr/local/bin/helper-functions.sh
|
source /usr/local/bin/helpers/index.sh
|
||||||
|
|
||||||
# suppress error output, e.g. when listmailuser runs in a fresh container (DMS not running)
|
# suppress error output, e.g. when listmailuser runs in a fresh container (DMS not running)
|
||||||
# shellcheck source=/dev/null
|
# shellcheck source=/dev/null
|
||||||
. /etc/dms-settings 2>/dev/null
|
source /etc/dms-settings 2>/dev/null
|
||||||
|
|
||||||
function dovecot_quota_to_hr()
|
function dovecot_quota_to_hr()
|
||||||
{
|
{
|
||||||
|
@ -23,8 +23,8 @@ function dovecot_quota_to_hr()
|
||||||
DATABASE="/tmp/docker-mailserver/postfix-accounts.cf"
|
DATABASE="/tmp/docker-mailserver/postfix-accounts.cf"
|
||||||
ALIASES="/tmp/docker-mailserver/postfix-virtual.cf"
|
ALIASES="/tmp/docker-mailserver/postfix-virtual.cf"
|
||||||
|
|
||||||
[[ -f ${DATABASE} ]] || errex "Error: No postfix-accounts.cf file"
|
[[ -f ${DATABASE} ]] || _errex "Error: No postfix-accounts.cf file"
|
||||||
[[ -s ${DATABASE} ]] || errex "Error: Empty postfix-accounts.cf - no accounts have been added"
|
[[ -s ${DATABASE} ]] || _errex "Error: Empty postfix-accounts.cf - no accounts have been added"
|
||||||
|
|
||||||
while read -r LINE
|
while read -r LINE
|
||||||
do
|
do
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
|
|
||||||
# shellcheck source=../scripts/helper-functions.sh
|
# shellcheck source=../scripts/helpers/index.sh
|
||||||
. /usr/local/bin/helper-functions.sh
|
source /usr/local/bin/helpers/index.sh
|
||||||
|
|
||||||
HOSTNAME=${1}
|
HOSTNAME=${1}
|
||||||
RECIPIENT=${2}
|
RECIPIENT=${2}
|
||||||
SENDER=${3}
|
SENDER=${3}
|
||||||
|
|
||||||
[[ -x /usr/sbin/pflogsumm ]] || errex "Critical: /usr/sbin/pflogsumm not found"
|
[[ -x /usr/sbin/pflogsumm ]] || _errex "Critical: /usr/sbin/pflogsumm not found"
|
||||||
|
|
||||||
# The case that the mail.log.1 file isn't readable shouldn't
|
# The case that the mail.log.1 file isn't readable shouldn't
|
||||||
# actually be possible with logrotate not rotating empty files..
|
# actually be possible with logrotate not rotating empty files..
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
|
|
||||||
# shellcheck source=../scripts/helper-functions.sh
|
# shellcheck source=../scripts/helpers/index.sh
|
||||||
. /usr/local/bin/helper-functions.sh
|
source /usr/local/bin/helpers/index.sh
|
||||||
|
|
||||||
_notify 'inf' 'Printing environment variables. Make sure no sensitive data is copied.'
|
_notify 'inf' 'Printing environment variables. Make sure no sensitive data is copied.'
|
||||||
cat /etc/dms-settings
|
cat /etc/dms-settings
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
|
|
||||||
# shellcheck source=../scripts/helper-functions.sh
|
# shellcheck source=../scripts/helpers/index.sh
|
||||||
. /usr/local/bin/helper-functions.sh
|
source /usr/local/bin/helpers/index.sh
|
||||||
|
|
||||||
set -o errexit
|
set -o errexit
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
|
@ -11,7 +11,7 @@ HOSTNAME=${1}
|
||||||
RECIPIENT=${2}
|
RECIPIENT=${2}
|
||||||
SENDER=${3}
|
SENDER=${3}
|
||||||
|
|
||||||
[[ -x /usr/sbin/pflogsumm ]] || errex "Critical: /usr/sbin/pflogsumm not found"
|
[[ -x /usr/sbin/pflogsumm ]] || _errex "Critical: /usr/sbin/pflogsumm not found"
|
||||||
|
|
||||||
# shellcheck disable=SC2046
|
# shellcheck disable=SC2046
|
||||||
BODY=$(gzip -cdfq $(ls -tr /var/log/mail/mail.log*) | /usr/sbin/pflogsumm --problems_first -d yesterday)
|
BODY=$(gzip -cdfq $(ls -tr /var/log/mail/mail.log*) | /usr/sbin/pflogsumm --problems_first -d yesterday)
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
|
|
||||||
# shellcheck source=../scripts/helper-functions.sh
|
# shellcheck source=../scripts/helpers/index.sh
|
||||||
. /usr/local/bin/helper-functions.sh
|
source /usr/local/bin/helpers/index.sh
|
||||||
|
|
||||||
MODE="${1}"
|
MODE="${1}"
|
||||||
USER="${3}"
|
USER="${3}"
|
||||||
|
|
||||||
function usage { echo "Usage: ${0} <add|del|list> <send|receive> [<email@domain.com>]" ; }
|
function usage { echo "Usage: ${0} <add|del|list> <send|receive> [<email@domain.com>]" ; }
|
||||||
|
|
||||||
[[ -z ${MODE} ]] && errex "missing parameters: <add|del|list> <send|receive> [<email@domain.com>]"
|
[[ -z ${MODE} ]] && _errex "missing parameters: <add|del|list> <send|receive> [<email@domain.com>]"
|
||||||
|
|
||||||
case ${2} in
|
case ${2} in
|
||||||
send)
|
send)
|
||||||
|
@ -19,7 +19,7 @@ case ${2} in
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
usage
|
usage
|
||||||
errex "missing parameters. Specify \"send\" or \"receive\""
|
_errex "missing parameters. Specify \"send\" or \"receive\""
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
@ -27,12 +27,12 @@ if [[ -z ${USER} ]] && [[ ${MODE} != list ]]
|
||||||
then
|
then
|
||||||
read -r -p "User(user@domain.com): " USER
|
read -r -p "User(user@domain.com): " USER
|
||||||
echo
|
echo
|
||||||
[[ -z ${USER} ]] && errex "User must not be empty"
|
[[ -z ${USER} ]] && _errex "User must not be empty"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
case ${MODE} in
|
case ${MODE} in
|
||||||
add)
|
add)
|
||||||
grep -qi "^$(escape "${USER}")" "${DATABASE}" 2>/dev/null && errex "User \"${USER}\" already denied to ${2} mails"
|
grep -qi "^$(_escape "${USER}")" "${DATABASE}" 2>/dev/null && _errex "User \"${USER}\" already denied to ${2} mails"
|
||||||
|
|
||||||
if [[ ! -f ${DATABASE} ]]
|
if [[ ! -f ${DATABASE} ]]
|
||||||
then
|
then
|
||||||
|
@ -48,7 +48,7 @@ case ${MODE} in
|
||||||
;;
|
;;
|
||||||
|
|
||||||
del)
|
del)
|
||||||
sed -ie "/^$(escape "${USER}")/d" "${DATABASE}" 2>/dev/null || errex "User \"${USER}\" not found."
|
sed -ie "/^$(_escape "${USER}")/d" "${DATABASE}" 2>/dev/null || _errex "User \"${USER}\" not found."
|
||||||
;;
|
;;
|
||||||
|
|
||||||
list)
|
list)
|
||||||
|
@ -56,7 +56,7 @@ case ${MODE} in
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
usage
|
usage
|
||||||
errex "missing mode. Specify \"add\", \"del\" or \"list\""
|
_errex "missing mode. Specify \"add\", \"del\" or \"list\""
|
||||||
;;
|
;;
|
||||||
|
|
||||||
esac
|
esac
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
# ? being used below. (This disables the message file-wide.)
|
# ? being used below. (This disables the message file-wide.)
|
||||||
# shellcheck disable=SC2094
|
# shellcheck disable=SC2094
|
||||||
|
|
||||||
# shellcheck source=../scripts/helper-functions.sh
|
# shellcheck source=../scripts/helpers/index.sh
|
||||||
. /usr/local/bin/helper-functions.sh
|
source /usr/local/bin/helpers/index.sh
|
||||||
|
|
||||||
DATABASE=${DATABASE:-/tmp/docker-mailserver/dovecot-quotas.cf}
|
DATABASE=${DATABASE:-/tmp/docker-mailserver/dovecot-quotas.cf}
|
||||||
USER_DATABASE=${USER_DATABASE:-/tmp/docker-mailserver/postfix-accounts.cf}
|
USER_DATABASE=${USER_DATABASE:-/tmp/docker-mailserver/postfix-accounts.cf}
|
||||||
|
@ -17,36 +17,36 @@ QUOTA="${*}"
|
||||||
|
|
||||||
function usage { echo "Usage: setquota <user@domain> [<quota>]" ; }
|
function usage { echo "Usage: setquota <user@domain> [<quota>]" ; }
|
||||||
|
|
||||||
[[ -z ${USER} ]] && { usage ; errex "no username specified" ; }
|
[[ -z ${USER} ]] && { usage ; _errex "no username specified" ; }
|
||||||
[[ ${USER} =~ .*\@.* ]] || { usage ; errex "username must include the domain" ; }
|
[[ ${USER} =~ .*\@.* ]] || { usage ; _errex "username must include the domain" ; }
|
||||||
|
|
||||||
if ! grep -qE "^${USER}\|" "${USER_DATABASE}"
|
if ! grep -qE "^${USER}\|" "${USER_DATABASE}"
|
||||||
then
|
then
|
||||||
usage; errex "user ${USER} does not exist"
|
usage; _errex "user ${USER} does not exist"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# check quota
|
# check quota
|
||||||
if [[ -n ${QUOTA} ]] && ! echo "${QUOTA}" | grep -qE "^([0-9]+(B|k|M|G|T)|0)\$"
|
if [[ -n ${QUOTA} ]] && ! echo "${QUOTA}" | grep -qE "^([0-9]+(B|k|M|G|T)|0)\$"
|
||||||
then
|
then
|
||||||
usage
|
usage
|
||||||
errex "invalid quota format. e.g. 302M (B (byte), k (kilobyte), M (megabyte), G (gigabyte) or T (terabyte))"
|
_errex "invalid quota format. e.g. 302M (B (byte), k (kilobyte), M (megabyte), G (gigabyte) or T (terabyte))"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
create_lock # Protect config file with lock to avoid race conditions
|
_create_lock # Protect config file with lock to avoid race conditions
|
||||||
|
|
||||||
touch "${DATABASE}"
|
touch "${DATABASE}"
|
||||||
if [[ -z ${QUOTA} ]]
|
if [[ -z ${QUOTA} ]]
|
||||||
then
|
then
|
||||||
read -r -s "Enter quota (e.g. 10M): " QUOTA
|
read -r -s "Enter quota (e.g. 10M): " QUOTA
|
||||||
echo
|
echo
|
||||||
[[ -z "${QUOTA}" ]] && errex "Quota must not be empty. Use 0 for unlimited quota"
|
[[ -z "${QUOTA}" ]] && _errex "Quota must not be empty. Use 0 for unlimited quota"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# check quota
|
# check quota
|
||||||
if [[ -n ${QUOTA} ]] && ! echo "${QUOTA}" | grep -qE "^([0-9]+(B|k|M|G|T)|0)\$"
|
if [[ -n ${QUOTA} ]] && ! echo "${QUOTA}" | grep -qE "^([0-9]+(B|k|M|G|T)|0)\$"
|
||||||
then
|
then
|
||||||
usage
|
usage
|
||||||
errex "invalid quota format. e.g. 302M (B (byte), k (kilobyte), M (megabyte), G (gigabyte) or T (terabyte))"
|
_errex "invalid quota format. e.g. 302M (B (byte), k (kilobyte), M (megabyte), G (gigabyte) or T (terabyte))"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
delquota "${USER}"
|
delquota "${USER}"
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
# ? being used below. (This disables the message file-wide.)
|
# ? being used below. (This disables the message file-wide.)
|
||||||
# shellcheck disable=SC2094
|
# shellcheck disable=SC2094
|
||||||
|
|
||||||
# shellcheck source=../scripts/helper-functions.sh
|
# shellcheck source=../scripts/helpers/index.sh
|
||||||
. /usr/local/bin/helper-functions.sh
|
source /usr/local/bin/helpers/index.sh
|
||||||
|
|
||||||
DATABASE=${DATABASE:-/tmp/docker-mailserver/postfix-accounts.cf}
|
DATABASE=${DATABASE:-/tmp/docker-mailserver/postfix-accounts.cf}
|
||||||
|
|
||||||
|
@ -16,18 +16,18 @@ PASSWD="${*}"
|
||||||
|
|
||||||
function usage { echo "Usage: updatemailuser <user@domain.tld> [password]" ; }
|
function usage { echo "Usage: updatemailuser <user@domain.tld> [password]" ; }
|
||||||
|
|
||||||
[[ -z ${USER} ]] && { usage ; errex "no username specified" ; }
|
[[ -z ${USER} ]] && { usage ; _errex "no username specified" ; }
|
||||||
|
|
||||||
if [[ -z ${PASSWD} ]]
|
if [[ -z ${PASSWD} ]]
|
||||||
then
|
then
|
||||||
read -r -s -p "Enter Password: " PASSWD
|
read -r -s -p "Enter Password: " PASSWD
|
||||||
echo
|
echo
|
||||||
[[ -z ${PASSWD} ]] && errex "Password must not be empty"
|
[[ -z ${PASSWD} ]] && _errex "Password must not be empty"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
HASH="$(doveadm pw -s SHA512-CRYPT -u "${USER}" -p "${PASSWD}")"
|
HASH="$(doveadm pw -s SHA512-CRYPT -u "${USER}" -p "${PASSWD}")"
|
||||||
|
|
||||||
touch "${DATABASE}"
|
touch "${DATABASE}"
|
||||||
create_lock # Protect config file with lock to avoid race conditions
|
_create_lock # Protect config file with lock to avoid race conditions
|
||||||
grep -qi "^$(escape "${USER}")|" "${DATABASE}" 2>/dev/null || errex "User \"${USER}\" does not exist"
|
grep -qi "^$(_escape "${USER}")|" "${DATABASE}" 2>/dev/null || _errex "User \"${USER}\" does not exist"
|
||||||
sed -i "s ^""${USER}""|.* ""${USER}""|""${HASH}"" " "${DATABASE}"
|
sed -i "s ^""${USER}""|.* ""${USER}""|""${HASH}"" " "${DATABASE}"
|
||||||
|
|
|
@ -3,6 +3,6 @@
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
# shellcheck source=/dev/null
|
# shellcheck source=/dev/null
|
||||||
. /etc/dms-settings
|
source /etc/dms-settings
|
||||||
|
|
||||||
find /var/lib/amavis/virusmails/ -type f -mtime +"${VIRUSMAILS_DELETE_DELAY}" -delete
|
find /var/lib/amavis/virusmails/ -type f -mtime +"${VIRUSMAILS_DELETE_DELAY}" -delete
|
||||||
|
|
|
@ -30,7 +30,7 @@ plugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
service quota-warning {
|
service quota-warning {
|
||||||
executable = script /usr/local/bin/quota-warning.sh
|
executable = script /usr/local/bin/quota-warning
|
||||||
unix_listener quota-warning {
|
unix_listener quota-warning {
|
||||||
user = dovecot
|
user = dovecot
|
||||||
group = dovecot
|
group = dovecot
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
|
|
||||||
# TODO: Adapt for compatibility with LDAP
|
# TODO: Adapt for compatibility with LDAP
|
||||||
# Only the cert renewal change detection may be relevant for LDAP?
|
# Only the cert renewal change detection may be relevant for LDAP?
|
||||||
|
|
||||||
# shellcheck source=./helper-functions.sh
|
# shellcheck source=./helpers/index.sh
|
||||||
. /usr/local/bin/helper-functions.sh
|
source /usr/local/bin/helpers/index.sh
|
||||||
|
|
||||||
function _log_date
|
function _log_date
|
||||||
{
|
{
|
||||||
|
@ -60,7 +61,7 @@ do
|
||||||
if [[ ${?} -eq 1 ]]
|
if [[ ${?} -eq 1 ]]
|
||||||
then
|
then
|
||||||
_notify 'inf' "$(_log_date) Change detected"
|
_notify 'inf' "$(_log_date) Change detected"
|
||||||
create_lock # Shared config safety lock
|
_create_lock # Shared config safety lock
|
||||||
CHANGED=$(grep -Fxvf "${CHKSUM_FILE}" "${CHKSUM_FILE}.new" | sed 's/^[^ ]\+ //')
|
CHANGED=$(grep -Fxvf "${CHKSUM_FILE}" "${CHKSUM_FILE}.new" | sed 's/^[^ ]\+ //')
|
||||||
|
|
||||||
# TODO Perform updates below conditionally too
|
# TODO Perform updates below conditionally too
|
||||||
|
@ -91,7 +92,7 @@ do
|
||||||
# This breaks early as we only need the first successful extraction.
|
# This breaks early as we only need the first successful extraction.
|
||||||
# For more details see the `SSL_TYPE=letsencrypt` case handling in `setup-stack.sh`.
|
# For more details see the `SSL_TYPE=letsencrypt` case handling in `setup-stack.sh`.
|
||||||
#
|
#
|
||||||
# NOTE: HOSTNAME is set via `helper-functions.sh`, it is not the original system HOSTNAME ENV anymore.
|
# NOTE: HOSTNAME is set via `helpers/dns.sh`, it is not the original system HOSTNAME ENV anymore.
|
||||||
# TODO: SSL_DOMAIN is Traefik specific, it no longer seems relevant and should be considered for removal.
|
# TODO: SSL_DOMAIN is Traefik specific, it no longer seems relevant and should be considered for removal.
|
||||||
FQDN_LIST=("${SSL_DOMAIN}" "${HOSTNAME}" "${DOMAINNAME}")
|
FQDN_LIST=("${SSL_DOMAIN}" "${HOSTNAME}" "${DOMAINNAME}")
|
||||||
for CERT_DOMAIN in "${FQDN_LIST[@]}"
|
for CERT_DOMAIN in "${FQDN_LIST[@]}"
|
||||||
|
@ -141,7 +142,7 @@ do
|
||||||
# prevent restart of dovecot when smtp_only=1
|
# prevent restart of dovecot when smtp_only=1
|
||||||
[[ ${SMTP_ONLY} -ne 1 ]] && supervisorctl restart dovecot
|
[[ ${SMTP_ONLY} -ne 1 ]] && supervisorctl restart dovecot
|
||||||
|
|
||||||
remove_lock
|
_remove_lock
|
||||||
_notify 'inf' "$(_log_date) Completed handling of detected change"
|
_notify 'inf' "$(_log_date) Completed handling of detected change"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
@ -1,266 +0,0 @@
|
||||||
#! /bin/bash
|
|
||||||
|
|
||||||
# TODO this file may be split up in the future
|
|
||||||
# into separate files under `target/scripts/helper/`
|
|
||||||
# which is a more fitting place
|
|
||||||
|
|
||||||
# These helpers are used by `setup-stack.sh` and `check-for-changes.sh`,
|
|
||||||
# not by anything within `helper-functions.sh` itself:
|
|
||||||
# shellcheck source=target/scripts/helpers/index.sh
|
|
||||||
. /usr/local/bin/helpers/index.sh
|
|
||||||
|
|
||||||
DMS_DEBUG="${DMS_DEBUG:=0}"
|
|
||||||
SCRIPT_NAME="$(basename "$0")" # This becomes the sourcing script name (Example: check-for-changes.sh)
|
|
||||||
LOCK_ID="$(uuid)" # Used inside of lock files to identify them and prevent removal by other instances of docker-mailserver
|
|
||||||
|
|
||||||
# file storing the checksums of the monitored files.
|
|
||||||
# shellcheck disable=SC2034
|
|
||||||
CHKSUM_FILE=/tmp/docker-mailserver-config-chksum
|
|
||||||
|
|
||||||
# ? --------------------------------------------- BIN HELPER
|
|
||||||
|
|
||||||
function errex
|
|
||||||
{
|
|
||||||
echo -e "Error :: ${*}\nAborting." >&2
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# `dms_panic` methods are appropriate when the type of error is a not recoverable,
|
|
||||||
# or needs to be very clear to the user about misconfiguration.
|
|
||||||
#
|
|
||||||
# Method is called with args:
|
|
||||||
# PANIC_TYPE => (Internal value for matching). You should use the convenience methods below based on your panic type.
|
|
||||||
# PANIC_INFO => Provide your own message string to insert into the error message for that PANIC_TYPE.
|
|
||||||
# PANIC_SCOPE => Optionally provide a string for debugging to better identify/locate the source of the panic.
|
|
||||||
function dms_panic
|
|
||||||
{
|
|
||||||
local PANIC_TYPE=${1}
|
|
||||||
local PANIC_INFO=${2}
|
|
||||||
local PANIC_SCOPE=${3} #optional
|
|
||||||
|
|
||||||
local SHUTDOWN_MESSAGE
|
|
||||||
|
|
||||||
case "${PANIC_TYPE:-}" in
|
|
||||||
( 'fail-init' ) # PANIC_INFO == <name of service or process that failed to start / initialize>
|
|
||||||
SHUTDOWN_MESSAGE="Failed to start ${PANIC_INFO}!"
|
|
||||||
;;
|
|
||||||
|
|
||||||
( 'no-env' ) # PANIC_INFO == <ENV VAR name>
|
|
||||||
SHUTDOWN_MESSAGE="Environment Variable: ${PANIC_INFO} is not set!"
|
|
||||||
;;
|
|
||||||
|
|
||||||
( 'no-file' ) # PANIC_INFO == <invalid filepath>
|
|
||||||
SHUTDOWN_MESSAGE="File ${PANIC_INFO} does not exist!"
|
|
||||||
;;
|
|
||||||
|
|
||||||
( 'misconfigured' ) # PANIC_INFO == <something possibly misconfigured, eg an ENV var>
|
|
||||||
SHUTDOWN_MESSAGE="${PANIC_INFO} appears to be misconfigured, please verify."
|
|
||||||
;;
|
|
||||||
|
|
||||||
( 'invalid-value' ) # PANIC_INFO == <an unsupported or invalid value, eg in a case match>
|
|
||||||
SHUTDOWN_MESSAGE="Invalid value for ${PANIC_INFO}!"
|
|
||||||
;;
|
|
||||||
|
|
||||||
( * ) # `dms_panic` was called directly without a valid PANIC_TYPE
|
|
||||||
SHUTDOWN_MESSAGE='Something broke :('
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
if [[ -n ${PANIC_SCOPE:-} ]]
|
|
||||||
then
|
|
||||||
_shutdown "${PANIC_SCOPE} | ${SHUTDOWN_MESSAGE}"
|
|
||||||
else
|
|
||||||
_shutdown "${SHUTDOWN_MESSAGE}"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Convenience wrappers based on type:
|
|
||||||
function dms_panic__fail_init { dms_panic 'fail-init' "${1}" "${2}"; }
|
|
||||||
function dms_panic__no_env { dms_panic 'no-env' "${1}" "${2}"; }
|
|
||||||
function dms_panic__no_file { dms_panic 'no-file' "${1}" "${2}"; }
|
|
||||||
function dms_panic__misconfigured { dms_panic 'misconfigured' "${1}" "${2}"; }
|
|
||||||
function dms_panic__invalid_value { dms_panic 'invalid-value' "${1}" "${2}"; }
|
|
||||||
|
|
||||||
function escape
|
|
||||||
{
|
|
||||||
echo "${1//./\\.}"
|
|
||||||
}
|
|
||||||
|
|
||||||
function create_lock
|
|
||||||
{
|
|
||||||
LOCK_FILE="/tmp/docker-mailserver/${SCRIPT_NAME}.lock"
|
|
||||||
while [[ -e "${LOCK_FILE}" ]]
|
|
||||||
do
|
|
||||||
_notify 'warn' "Lock file ${LOCK_FILE} exists. Another ${SCRIPT_NAME} execution is happening. Trying again shortly..."
|
|
||||||
# Handle stale lock files left behind on crashes
|
|
||||||
# or premature/non-graceful exits of containers while they're making changes
|
|
||||||
if [[ -n "$(find "${LOCK_FILE}" -mmin +1 2>/dev/null)" ]]
|
|
||||||
then
|
|
||||||
_notify 'warn' "Lock file older than 1 minute. Removing stale lock file."
|
|
||||||
rm -f "${LOCK_FILE}"
|
|
||||||
_notify 'inf' "Removed stale lock ${LOCK_FILE}."
|
|
||||||
fi
|
|
||||||
sleep 5
|
|
||||||
done
|
|
||||||
trap remove_lock EXIT
|
|
||||||
echo "${LOCK_ID}" > "${LOCK_FILE}"
|
|
||||||
}
|
|
||||||
|
|
||||||
function remove_lock
|
|
||||||
{
|
|
||||||
LOCK_FILE="${LOCK_FILE:-"/tmp/docker-mailserver/${SCRIPT_NAME}.lock"}"
|
|
||||||
[[ -z "${LOCK_ID}" ]] && errex "Cannot remove ${LOCK_FILE} as there is no LOCK_ID set"
|
|
||||||
if [[ -e "${LOCK_FILE}" ]] && grep -q "${LOCK_ID}" "${LOCK_FILE}" # Ensure we don't delete a lock that's not ours
|
|
||||||
then
|
|
||||||
rm -f "${LOCK_FILE}"
|
|
||||||
_notify 'inf' "Removed lock ${LOCK_FILE}."
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# ? --------------------------------------------- IP & CIDR
|
|
||||||
|
|
||||||
function _mask_ip_digit
|
|
||||||
{
|
|
||||||
if [[ ${1} -ge 8 ]]
|
|
||||||
then
|
|
||||||
MASK=255
|
|
||||||
elif [[ ${1} -le 0 ]]
|
|
||||||
then
|
|
||||||
MASK=0
|
|
||||||
else
|
|
||||||
VALUES=(0 128 192 224 240 248 252 254 255)
|
|
||||||
MASK=${VALUES[${1}]}
|
|
||||||
fi
|
|
||||||
|
|
||||||
local DVAL=${2}
|
|
||||||
((DVAL&=MASK))
|
|
||||||
|
|
||||||
echo "${DVAL}"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Transforms a specific IP with CIDR suffix
|
|
||||||
# like 1.2.3.4/16 to subnet with cidr suffix
|
|
||||||
# like 1.2.0.0/16.
|
|
||||||
# Assumes correct IP and subnet are provided.
|
|
||||||
function _sanitize_ipv4_to_subnet_cidr
|
|
||||||
{
|
|
||||||
local DIGIT_PREFIX_LENGTH="${1#*/}"
|
|
||||||
|
|
||||||
declare -a MASKED_DIGITS DIGITS
|
|
||||||
IFS='.' ; read -r -a DIGITS < <(echo "${1%%/*}") ; unset IFS
|
|
||||||
|
|
||||||
for ((i = 0 ; i < 4 ; i++))
|
|
||||||
do
|
|
||||||
MASKED_DIGITS[i]=$(_mask_ip_digit "${DIGIT_PREFIX_LENGTH}" "${DIGITS[i]}")
|
|
||||||
DIGIT_PREFIX_LENGTH=$((DIGIT_PREFIX_LENGTH - 8))
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "${MASKED_DIGITS[0]}.${MASKED_DIGITS[1]}.${MASKED_DIGITS[2]}.${MASKED_DIGITS[3]}/${1#*/}"
|
|
||||||
}
|
|
||||||
export -f _sanitize_ipv4_to_subnet_cidr
|
|
||||||
|
|
||||||
# ? --------------------------------------------- Notifications
|
|
||||||
|
|
||||||
function _notify
|
|
||||||
{
|
|
||||||
{ [[ -z ${1:-} ]] || [[ -z ${2:-} ]] ; } && return 0
|
|
||||||
|
|
||||||
local RESET LGREEN LYELLOW LRED RED LBLUE LGREY LMAGENTA
|
|
||||||
|
|
||||||
RESET='\e[0m' ; LGREEN='\e[92m' ; LYELLOW='\e[93m'
|
|
||||||
LRED='\e[31m' ; RED='\e[91m' ; LBLUE='\e[34m'
|
|
||||||
LGREY='\e[37m' ; LMAGENTA='\e[95m'
|
|
||||||
|
|
||||||
case "${1}" in
|
|
||||||
'tasklog' ) echo "-e${3:-}" "[ ${LGREEN}TASKLOG${RESET} ] ${2}" ;;
|
|
||||||
'warn' ) echo "-e${3:-}" "[ ${LYELLOW}WARNING${RESET} ] ${2}" ;;
|
|
||||||
'err' ) echo "-e${3:-}" "[ ${LRED}ERROR${RESET} ] ${2}" ;;
|
|
||||||
'fatal' ) echo "-e${3:-}" "[ ${RED}FATAL${RESET} ] ${2}" ;;
|
|
||||||
'inf' ) [[ ${DMS_DEBUG} -eq 1 ]] && echo "-e${3:-}" "[[ ${LBLUE}INF${RESET} ]] ${2}" ;;
|
|
||||||
'task' ) [[ ${DMS_DEBUG} -eq 1 ]] && echo "-e${3:-}" "[[ ${LGREY}TASKS${RESET} ]] ${2}" ;;
|
|
||||||
* ) echo "-e${3:-}" "[ ${LMAGENTA}UNKNOWN${RESET} ] ${2}" ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
export -f _notify
|
|
||||||
|
|
||||||
# ? --------------------------------------------- General
|
|
||||||
|
|
||||||
# Outputs the DNS label count (delimited by `.`) for the given input string.
|
|
||||||
# Useful for determining an FQDN like `mail.example.com` (3), vs `example.com` (2).
|
|
||||||
function _get_label_count
|
|
||||||
{
|
|
||||||
awk -F '.' '{ print NF }' <<< "${1}"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Sets HOSTNAME and DOMAINNAME globals used throughout the scripts,
|
|
||||||
# and any subprocesses called that intereact with it.
|
|
||||||
function _obtain_hostname_and_domainname
|
|
||||||
{
|
|
||||||
# Normally this value would match the output of `hostname` which mirrors `/proc/sys/kernel/hostname`,
|
|
||||||
# However for legacy reasons, the system ENV `HOSTNAME` was replaced here with `hostname -f` instead.
|
|
||||||
#
|
|
||||||
# TODO: Consider changing to `DMS_FQDN`; a more accurate name, and removing the `export`, assuming no
|
|
||||||
# subprocess like postconf would be called that would need access to the same value via `$HOSTNAME` ENV.
|
|
||||||
#
|
|
||||||
# TODO: `OVERRIDE_HOSTNAME` was introduced for non-Docker runtimes that could not configure an explicit hostname.
|
|
||||||
# k8s was the particular runtime in 2017. This does not update `/etc/hosts` or other locations, thus risking
|
|
||||||
# inconsistency with expected behaviour. Investigate if it's safe to remove support. (--net=host also uses this as a workaround)
|
|
||||||
export HOSTNAME="${OVERRIDE_HOSTNAME:-$(hostname -f)}"
|
|
||||||
|
|
||||||
# If the container is misconfigured.. `hostname -f` (which derives it's return value from `/etc/hosts` or DNS query),
|
|
||||||
# will result in an error that returns an empty value. This warrants a panic.
|
|
||||||
if [[ -z ${HOSTNAME} ]]
|
|
||||||
then
|
|
||||||
dms_panic__misconfigured 'obtain_hostname' '/etc/hosts'
|
|
||||||
fi
|
|
||||||
|
|
||||||
# If the `HOSTNAME` is more than 2 labels long (eg: mail.example.com),
|
|
||||||
# We take the FQDN from it, minus the 1st label (aka _short hostname_, `hostname -s`).
|
|
||||||
#
|
|
||||||
# TODO: For some reason we're explicitly separating out a domain name from our FQDN,
|
|
||||||
# `hostname -d` was probably not the correct command for this intention either.
|
|
||||||
# Needs further investigation for relevance, and if `/etc/hosts` is important for consumers
|
|
||||||
# of this variable or if a more deterministic approach with `cut` should be relied on.
|
|
||||||
if [[ $(_get_label_count "${HOSTNAME}") -gt 2 ]]
|
|
||||||
then
|
|
||||||
if [[ -n ${OVERRIDE_HOSTNAME} ]]
|
|
||||||
then
|
|
||||||
# Emulates the intended behaviour of `hostname -d`:
|
|
||||||
# Assign the HOSTNAME value minus everything up to and including the first `.`
|
|
||||||
DOMAINNAME=${HOSTNAME#*.}
|
|
||||||
else
|
|
||||||
# Operates on the FQDN returned from querying `/etc/hosts` or fallback DNS:
|
|
||||||
#
|
|
||||||
# Note if you want the actual NIS `domainname`, use the `domainname` command,
|
|
||||||
# or `cat /proc/sys/kernel/domainname`.
|
|
||||||
# Our usage of `domainname` is under consideration as legacy, and not advised
|
|
||||||
# going forward. In future our docs should drop any mention of it.
|
|
||||||
|
|
||||||
#shellcheck disable=SC2034
|
|
||||||
DOMAINNAME="$(hostname -d)"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Otherwise we assign the same value (eg: example.com):
|
|
||||||
# Not an else statement in the previous conditional in the event that `hostname -d` fails.
|
|
||||||
DOMAINNAME="${DOMAINNAME:-${HOSTNAME}}"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Check if string input is an empty line, only whitespaces or `#` as the first non-whitespace character.
|
|
||||||
function _is_comment
|
|
||||||
{
|
|
||||||
grep -q -E "^\s*$|^\s*#" <<< "${1}"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Call this method when you want to panic (emit a 'FATAL' log level error, and exit uncleanly).
|
|
||||||
# `dms_panic` methods should be preferred if your failure type is supported.
|
|
||||||
function _shutdown
|
|
||||||
{
|
|
||||||
local FATAL_ERROR_MESSAGE=$1
|
|
||||||
|
|
||||||
_notify 'fatal' "${FATAL_ERROR_MESSAGE}"
|
|
||||||
_notify 'err' "Shutting down.."
|
|
||||||
kill 1
|
|
||||||
}
|
|
62
target/scripts/helpers/dns.sh
Executable file
62
target/scripts/helpers/dns.sh
Executable file
|
@ -0,0 +1,62 @@
|
||||||
|
#! /bin/bash
|
||||||
|
|
||||||
|
# Outputs the DNS label count (delimited by `.`) for the given input string.
|
||||||
|
# Useful for determining an FQDN like `mail.example.com` (3), vs `example.com` (2).
|
||||||
|
function _get_label_count
|
||||||
|
{
|
||||||
|
awk -F '.' '{ print NF }' <<< "${1}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Sets HOSTNAME and DOMAINNAME globals used throughout the scripts,
|
||||||
|
# and any subprocesses called that intereact with it.
|
||||||
|
function _obtain_hostname_and_domainname
|
||||||
|
{
|
||||||
|
# Normally this value would match the output of `hostname` which mirrors `/proc/sys/kernel/hostname`,
|
||||||
|
# However for legacy reasons, the system ENV `HOSTNAME` was replaced here with `hostname -f` instead.
|
||||||
|
#
|
||||||
|
# TODO: Consider changing to `DMS_FQDN`; a more accurate name, and removing the `export`, assuming no
|
||||||
|
# subprocess like postconf would be called that would need access to the same value via `$HOSTNAME` ENV.
|
||||||
|
#
|
||||||
|
# TODO: `OVERRIDE_HOSTNAME` was introduced for non-Docker runtimes that could not configure an explicit hostname.
|
||||||
|
# k8s was the particular runtime in 2017. This does not update `/etc/hosts` or other locations, thus risking
|
||||||
|
# inconsistency with expected behaviour. Investigate if it's safe to remove support. (--net=host also uses this as a workaround)
|
||||||
|
export HOSTNAME="${OVERRIDE_HOSTNAME:-$(hostname -f)}"
|
||||||
|
|
||||||
|
# If the container is misconfigured.. `hostname -f` (which derives it's return value from `/etc/hosts` or DNS query),
|
||||||
|
# will result in an error that returns an empty value. This warrants a panic.
|
||||||
|
if [[ -z ${HOSTNAME} ]]
|
||||||
|
then
|
||||||
|
dms_panic__misconfigured 'obtain_hostname' '/etc/hosts'
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If the `HOSTNAME` is more than 2 labels long (eg: mail.example.com),
|
||||||
|
# We take the FQDN from it, minus the 1st label (aka _short hostname_, `hostname -s`).
|
||||||
|
#
|
||||||
|
# TODO: For some reason we're explicitly separating out a domain name from our FQDN,
|
||||||
|
# `hostname -d` was probably not the correct command for this intention either.
|
||||||
|
# Needs further investigation for relevance, and if `/etc/hosts` is important for consumers
|
||||||
|
# of this variable or if a more deterministic approach with `cut` should be relied on.
|
||||||
|
if [[ $(_get_label_count "${HOSTNAME}") -gt 2 ]]
|
||||||
|
then
|
||||||
|
if [[ -n ${OVERRIDE_HOSTNAME} ]]
|
||||||
|
then
|
||||||
|
# Emulates the intended behaviour of `hostname -d`:
|
||||||
|
# Assign the HOSTNAME value minus everything up to and including the first `.`
|
||||||
|
DOMAINNAME=${HOSTNAME#*.}
|
||||||
|
else
|
||||||
|
# Operates on the FQDN returned from querying `/etc/hosts` or fallback DNS:
|
||||||
|
#
|
||||||
|
# Note if you want the actual NIS `domainname`, use the `domainname` command,
|
||||||
|
# or `cat /proc/sys/kernel/domainname`.
|
||||||
|
# Our usage of `domainname` is under consideration as legacy, and not advised
|
||||||
|
# going forward. In future our docs should drop any mention of it.
|
||||||
|
|
||||||
|
#shellcheck disable=SC2034
|
||||||
|
DOMAINNAME="$(hostname -d)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Otherwise we assign the same value (eg: example.com):
|
||||||
|
# Not an else statement in the previous conditional in the event that `hostname -d` fails.
|
||||||
|
DOMAINNAME="${DOMAINNAME:-${HOSTNAME}}"
|
||||||
|
}
|
74
target/scripts/helpers/error.sh
Executable file
74
target/scripts/helpers/error.sh
Executable file
|
@ -0,0 +1,74 @@
|
||||||
|
#! /bin/bash
|
||||||
|
|
||||||
|
function _errex
|
||||||
|
{
|
||||||
|
echo -e "Error :: ${*}\nAborting." >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# `dms_panic` methods are appropriate when the type of error is a not recoverable,
|
||||||
|
# or needs to be very clear to the user about misconfiguration.
|
||||||
|
#
|
||||||
|
# Method is called with args:
|
||||||
|
# PANIC_TYPE => (Internal value for matching). You should use the convenience methods below based on your panic type.
|
||||||
|
# PANIC_INFO => Provide your own message string to insert into the error message for that PANIC_TYPE.
|
||||||
|
# PANIC_SCOPE => Optionally provide a string for debugging to better identify/locate the source of the panic.
|
||||||
|
function dms_panic
|
||||||
|
{
|
||||||
|
local PANIC_TYPE=${1}
|
||||||
|
local PANIC_INFO=${2}
|
||||||
|
local PANIC_SCOPE=${3} #optional
|
||||||
|
|
||||||
|
local SHUTDOWN_MESSAGE
|
||||||
|
|
||||||
|
case "${PANIC_TYPE:-}" in
|
||||||
|
( 'fail-init' ) # PANIC_INFO == <name of service or process that failed to start / initialize>
|
||||||
|
SHUTDOWN_MESSAGE="Failed to start ${PANIC_INFO}!"
|
||||||
|
;;
|
||||||
|
|
||||||
|
( 'no-env' ) # PANIC_INFO == <ENV VAR name>
|
||||||
|
SHUTDOWN_MESSAGE="Environment Variable: ${PANIC_INFO} is not set!"
|
||||||
|
;;
|
||||||
|
|
||||||
|
( 'no-file' ) # PANIC_INFO == <invalid filepath>
|
||||||
|
SHUTDOWN_MESSAGE="File ${PANIC_INFO} does not exist!"
|
||||||
|
;;
|
||||||
|
|
||||||
|
( 'misconfigured' ) # PANIC_INFO == <something possibly misconfigured, eg an ENV var>
|
||||||
|
SHUTDOWN_MESSAGE="${PANIC_INFO} appears to be misconfigured, please verify."
|
||||||
|
;;
|
||||||
|
|
||||||
|
( 'invalid-value' ) # PANIC_INFO == <an unsupported or invalid value, eg in a case match>
|
||||||
|
SHUTDOWN_MESSAGE="Invalid value for ${PANIC_INFO}!"
|
||||||
|
;;
|
||||||
|
|
||||||
|
( * ) # `dms_panic` was called directly without a valid PANIC_TYPE
|
||||||
|
SHUTDOWN_MESSAGE='Something broke :('
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [[ -n ${PANIC_SCOPE:-} ]]
|
||||||
|
then
|
||||||
|
_shutdown "${PANIC_SCOPE} | ${SHUTDOWN_MESSAGE}"
|
||||||
|
else
|
||||||
|
_shutdown "${SHUTDOWN_MESSAGE}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Convenience wrappers based on type:
|
||||||
|
function dms_panic__fail_init { dms_panic 'fail-init' "${1}" "${2}"; }
|
||||||
|
function dms_panic__no_env { dms_panic 'no-env' "${1}" "${2}"; }
|
||||||
|
function dms_panic__no_file { dms_panic 'no-file' "${1}" "${2}"; }
|
||||||
|
function dms_panic__misconfigured { dms_panic 'misconfigured' "${1}" "${2}"; }
|
||||||
|
function dms_panic__invalid_value { dms_panic 'invalid-value' "${1}" "${2}"; }
|
||||||
|
|
||||||
|
# Call this method when you want to panic (emit a 'FATAL' log level error, and exit uncleanly).
|
||||||
|
# `dms_panic` methods should be preferred if your failure type is supported.
|
||||||
|
function _shutdown
|
||||||
|
{
|
||||||
|
local FATAL_ERROR_MESSAGE=$1
|
||||||
|
|
||||||
|
_notify 'fatal' "${FATAL_ERROR_MESSAGE}"
|
||||||
|
_notify 'err' "Shutting down.."
|
||||||
|
kill 1
|
||||||
|
}
|
|
@ -1,16 +1,35 @@
|
||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
|
|
||||||
# shellcheck source-path=target/scripts/helpers
|
# shellcheck source-path=target/scripts/helpers
|
||||||
# This file serves as a single import for all helpers
|
# This file serves as a single import for all helpers
|
||||||
|
|
||||||
|
# Global checksum file mainly needed for the changedetector.
|
||||||
|
# Used in the folling scripts:
|
||||||
|
#
|
||||||
|
# - ../check-for-changes.sh
|
||||||
|
# - ../start-mailserver.sh
|
||||||
|
# - ../startup/setup-stack.sh
|
||||||
|
# - ../../../test/test_helper/common.bash
|
||||||
|
#
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
CHKSUM_FILE=/tmp/docker-mailserver-config-chksum
|
||||||
|
|
||||||
function _import_scripts
|
function _import_scripts
|
||||||
{
|
{
|
||||||
local PATH_TO_SCRIPTS='/usr/local/bin/helpers'
|
local PATH_TO_SCRIPTS='/usr/local/bin/helpers'
|
||||||
|
|
||||||
. "${PATH_TO_SCRIPTS}/postfix.sh"
|
source "${PATH_TO_SCRIPTS}/accounts.sh"
|
||||||
. "${PATH_TO_SCRIPTS}/accounts.sh"
|
source "${PATH_TO_SCRIPTS}/aliases.sh"
|
||||||
. "${PATH_TO_SCRIPTS}/aliases.sh"
|
source "${PATH_TO_SCRIPTS}/dns.sh"
|
||||||
. "${PATH_TO_SCRIPTS}/relay.sh"
|
source "${PATH_TO_SCRIPTS}/error.sh"
|
||||||
. "${PATH_TO_SCRIPTS}/sasl.sh"
|
source "${PATH_TO_SCRIPTS}/lock.sh"
|
||||||
. "${PATH_TO_SCRIPTS}/ssl.sh"
|
source "${PATH_TO_SCRIPTS}/log.sh"
|
||||||
|
source "${PATH_TO_SCRIPTS}/network.sh"
|
||||||
|
source "${PATH_TO_SCRIPTS}/postfix.sh"
|
||||||
|
source "${PATH_TO_SCRIPTS}/relay.sh"
|
||||||
|
source "${PATH_TO_SCRIPTS}/sasl.sh"
|
||||||
|
source "${PATH_TO_SCRIPTS}/ssl.sh"
|
||||||
|
source "${PATH_TO_SCRIPTS}/utils.sh"
|
||||||
}
|
}
|
||||||
|
|
||||||
_import_scripts
|
_import_scripts
|
||||||
|
|
39
target/scripts/helpers/lock.sh
Normal file
39
target/scripts/helpers/lock.sh
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#! /bin/bash
|
||||||
|
|
||||||
|
# This becomes the sourcing script name
|
||||||
|
# (example: check-for-changes.sh)
|
||||||
|
SCRIPT_NAME="$(basename "$0")"
|
||||||
|
# Used inside of lock files to identify them and
|
||||||
|
# prevent removal by other instances of docker-mailserver
|
||||||
|
LOCK_ID="$(uuid)"
|
||||||
|
|
||||||
|
function _create_lock
|
||||||
|
{
|
||||||
|
LOCK_FILE="/tmp/docker-mailserver/${SCRIPT_NAME}.lock"
|
||||||
|
while [[ -e "${LOCK_FILE}" ]]
|
||||||
|
do
|
||||||
|
_notify 'warn' "Lock file ${LOCK_FILE} exists. Another ${SCRIPT_NAME} execution is happening. Trying again shortly..."
|
||||||
|
# Handle stale lock files left behind on crashes
|
||||||
|
# or premature/non-graceful exits of containers while they're making changes
|
||||||
|
if [[ -n "$(find "${LOCK_FILE}" -mmin +1 2>/dev/null)" ]]
|
||||||
|
then
|
||||||
|
_notify 'warn' "Lock file older than 1 minute. Removing stale lock file."
|
||||||
|
rm -f "${LOCK_FILE}"
|
||||||
|
_notify 'inf' "Removed stale lock ${LOCK_FILE}."
|
||||||
|
fi
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
trap _remove_lock EXIT
|
||||||
|
echo "${LOCK_ID}" > "${LOCK_FILE}"
|
||||||
|
}
|
||||||
|
|
||||||
|
function _remove_lock
|
||||||
|
{
|
||||||
|
LOCK_FILE="${LOCK_FILE:-"/tmp/docker-mailserver/${SCRIPT_NAME}.lock"}"
|
||||||
|
[[ -z "${LOCK_ID}" ]] && _errex "Cannot remove ${LOCK_FILE} as there is no LOCK_ID set"
|
||||||
|
if [[ -e "${LOCK_FILE}" ]] && grep -q "${LOCK_ID}" "${LOCK_FILE}" # Ensure we don't delete a lock that's not ours
|
||||||
|
then
|
||||||
|
rm -f "${LOCK_FILE}"
|
||||||
|
_notify 'inf' "Removed lock ${LOCK_FILE}."
|
||||||
|
fi
|
||||||
|
}
|
24
target/scripts/helpers/log.sh
Executable file
24
target/scripts/helpers/log.sh
Executable file
|
@ -0,0 +1,24 @@
|
||||||
|
#! /bin/bash
|
||||||
|
|
||||||
|
function _notify
|
||||||
|
{
|
||||||
|
{ [[ -z ${1:-} ]] || [[ -z ${2:-} ]] ; } && return 0
|
||||||
|
|
||||||
|
local RESET LGREEN LYELLOW LRED RED LBLUE LGREY LMAGENTA
|
||||||
|
|
||||||
|
RESET='\e[0m' ; LGREEN='\e[92m' ; LYELLOW='\e[93m'
|
||||||
|
LRED='\e[31m' ; RED='\e[91m' ; LBLUE='\e[34m'
|
||||||
|
LGREY='\e[37m' ; LMAGENTA='\e[95m'
|
||||||
|
|
||||||
|
case "${1}" in
|
||||||
|
'tasklog' ) echo "-e${3:-}" "[ ${LGREEN}TASKLOG${RESET} ] ${2}" ;;
|
||||||
|
'warn' ) echo "-e${3:-}" "[ ${LYELLOW}WARNING${RESET} ] ${2}" ;;
|
||||||
|
'err' ) echo "-e${3:-}" "[ ${LRED}ERROR${RESET} ] ${2}" ;;
|
||||||
|
'fatal' ) echo "-e${3:-}" "[ ${RED}FATAL${RESET} ] ${2}" ;;
|
||||||
|
'inf' ) [[ ${DMS_DEBUG} -eq 1 ]] && echo "-e${3:-}" "[[ ${LBLUE}INF${RESET} ]] ${2}" ;;
|
||||||
|
'task' ) [[ ${DMS_DEBUG} -eq 1 ]] && echo "-e${3:-}" "[[ ${LGREY}TASKS${RESET} ]] ${2}" ;;
|
||||||
|
* ) echo "-e${3:-}" "[ ${LMAGENTA}UNKNOWN${RESET} ] ${2}" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
40
target/scripts/helpers/network.sh
Executable file
40
target/scripts/helpers/network.sh
Executable file
|
@ -0,0 +1,40 @@
|
||||||
|
#! /bin/bash
|
||||||
|
|
||||||
|
function _mask_ip_digit
|
||||||
|
{
|
||||||
|
if [[ ${1} -ge 8 ]]
|
||||||
|
then
|
||||||
|
MASK=255
|
||||||
|
elif [[ ${1} -le 0 ]]
|
||||||
|
then
|
||||||
|
MASK=0
|
||||||
|
else
|
||||||
|
VALUES=(0 128 192 224 240 248 252 254 255)
|
||||||
|
MASK=${VALUES[${1}]}
|
||||||
|
fi
|
||||||
|
|
||||||
|
local DVAL=${2}
|
||||||
|
((DVAL&=MASK))
|
||||||
|
|
||||||
|
echo "${DVAL}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Transforms a specific IP with CIDR suffix
|
||||||
|
# like 1.2.3.4/16 to subnet with cidr suffix
|
||||||
|
# like 1.2.0.0/16.
|
||||||
|
# Assumes correct IP and subnet are provided.
|
||||||
|
function _sanitize_ipv4_to_subnet_cidr
|
||||||
|
{
|
||||||
|
local DIGIT_PREFIX_LENGTH="${1#*/}"
|
||||||
|
|
||||||
|
declare -a MASKED_DIGITS DIGITS
|
||||||
|
IFS='.' ; read -r -a DIGITS < <(echo "${1%%/*}") ; unset IFS
|
||||||
|
|
||||||
|
for ((i = 0 ; i < 4 ; i++))
|
||||||
|
do
|
||||||
|
MASKED_DIGITS[i]=$(_mask_ip_digit "${DIGIT_PREFIX_LENGTH}" "${DIGITS[i]}")
|
||||||
|
DIGIT_PREFIX_LENGTH=$((DIGIT_PREFIX_LENGTH - 8))
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "${MASKED_DIGITS[0]}.${MASKED_DIGITS[1]}.${MASKED_DIGITS[2]}.${MASKED_DIGITS[3]}/${1#*/}"
|
||||||
|
}
|
|
@ -94,9 +94,6 @@ function _relayhost_configure_postfix
|
||||||
"smtp_sender_dependent_authentication = yes"
|
"smtp_sender_dependent_authentication = yes"
|
||||||
}
|
}
|
||||||
|
|
||||||
# ? --------------------------------------------- Callers
|
|
||||||
|
|
||||||
# setup-stack.sh:
|
|
||||||
function _setup_relayhost
|
function _setup_relayhost
|
||||||
{
|
{
|
||||||
_notify 'task' 'Setting up Postfix Relay Hosts'
|
_notify 'task' 'Setting up Postfix Relay Hosts'
|
||||||
|
@ -120,7 +117,6 @@ function _setup_relayhost
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# check-for-changes.sh:
|
|
||||||
function _rebuild_relayhost
|
function _rebuild_relayhost
|
||||||
{
|
{
|
||||||
if [[ -n ${RELAY_HOST} ]]
|
if [[ -n ${RELAY_HOST} ]]
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
# Support for SASL
|
|
||||||
|
|
||||||
function _sasl_passwd_create
|
function _sasl_passwd_create
|
||||||
{
|
{
|
||||||
|
|
8
target/scripts/helpers/ssl.sh
Normal file → Executable file
8
target/scripts/helpers/ssl.sh
Normal file → Executable file
|
@ -94,7 +94,7 @@ function _setup_ssl
|
||||||
# 2020 feature intended for Traefik v2 support only:
|
# 2020 feature intended for Traefik v2 support only:
|
||||||
# https://github.com/docker-mailserver/docker-mailserver/pull/1553
|
# https://github.com/docker-mailserver/docker-mailserver/pull/1553
|
||||||
# Extracts files `key.pem` and `fullchain.pem`.
|
# Extracts files `key.pem` and `fullchain.pem`.
|
||||||
# `_extract_certs_from_acme` is located in `helper-functions.sh`
|
# `_extract_certs_from_acme` is located in `helpers/ssl.sh`
|
||||||
# NOTE: See the `SSL_TYPE=letsencrypt` case below for more details.
|
# NOTE: See the `SSL_TYPE=letsencrypt` case below for more details.
|
||||||
function _traefik_support
|
function _traefik_support
|
||||||
{
|
{
|
||||||
|
@ -180,7 +180,7 @@ function _setup_ssl
|
||||||
# SSL_DOMAIN will have any wildcard prefix stripped for the output FQDN folder it is stored in.
|
# SSL_DOMAIN will have any wildcard prefix stripped for the output FQDN folder it is stored in.
|
||||||
# TODO: A wildcard cert needs to be provisioned via Traefik to validate if acme.json contains any other value for `main` or `sans` beyond the wildcard.
|
# TODO: A wildcard cert needs to be provisioned via Traefik to validate if acme.json contains any other value for `main` or `sans` beyond the wildcard.
|
||||||
#
|
#
|
||||||
# NOTE: HOSTNAME is set via `helper-functions.sh`, it is not the original system HOSTNAME ENV anymore.
|
# NOTE: HOSTNAME is set via `helpers/dns.sh`, it is not the original system HOSTNAME ENV anymore.
|
||||||
# TODO: SSL_DOMAIN is Traefik specific, it no longer seems relevant and should be considered for removal.
|
# TODO: SSL_DOMAIN is Traefik specific, it no longer seems relevant and should be considered for removal.
|
||||||
|
|
||||||
_traefik_support
|
_traefik_support
|
||||||
|
@ -407,7 +407,6 @@ function _setup_ssl
|
||||||
|
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
export -f _setup_ssl
|
|
||||||
|
|
||||||
function _extract_certs_from_acme
|
function _extract_certs_from_acme
|
||||||
{
|
{
|
||||||
|
@ -441,13 +440,11 @@ function _extract_certs_from_acme
|
||||||
|
|
||||||
_notify 'inf' "_extract_certs_from_acme | Certificate successfully extracted for '${CERT_DOMAIN}'"
|
_notify 'inf' "_extract_certs_from_acme | Certificate successfully extracted for '${CERT_DOMAIN}'"
|
||||||
}
|
}
|
||||||
export -f _extract_certs_from_acme
|
|
||||||
|
|
||||||
# Remove the `*.` prefix if it exists, else returns the input value
|
# Remove the `*.` prefix if it exists, else returns the input value
|
||||||
function _strip_wildcard_prefix {
|
function _strip_wildcard_prefix {
|
||||||
[[ ${1} == "*."* ]] && echo "${1:2}" || echo "${1}"
|
[[ ${1} == "*."* ]] && echo "${1:2}" || echo "${1}"
|
||||||
}
|
}
|
||||||
export -f _strip_wildcard_prefix
|
|
||||||
|
|
||||||
# Compute checksums of monitored files,
|
# Compute checksums of monitored files,
|
||||||
# returned output on `stdout`: hash + filepath tuple on each line
|
# returned output on `stdout`: hash + filepath tuple on each line
|
||||||
|
@ -496,4 +493,3 @@ function _monitored_files_checksums
|
||||||
|
|
||||||
sha512sum -- "${CHANGED_FILES[@]}"
|
sha512sum -- "${CHANGED_FILES[@]}"
|
||||||
}
|
}
|
||||||
export -f _monitored_files_checksums
|
|
||||||
|
|
13
target/scripts/helpers/utils.sh
Executable file
13
target/scripts/helpers/utils.sh
Executable file
|
@ -0,0 +1,13 @@
|
||||||
|
#! /bin/bash
|
||||||
|
|
||||||
|
function _escape
|
||||||
|
{
|
||||||
|
echo "${1//./\\.}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if string input is an empty line, only whitespaces
|
||||||
|
# or `#` as the first non-whitespace character.
|
||||||
|
function _is_comment
|
||||||
|
{
|
||||||
|
grep -q -E "^\s*$|^\s*#" <<< "${1}"
|
||||||
|
}
|
|
@ -1,10 +1,10 @@
|
||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
|
|
||||||
# shellcheck source=./helper-functions.sh
|
# shellcheck source=./helpers/index.sh
|
||||||
. /usr/local/bin/helper-functions.sh
|
source /usr/local/bin/helpers/index.sh
|
||||||
|
|
||||||
unset FUNCS_SETUP FUNCS_FIX FUNCS_CHECK FUNCS_MISC
|
unset FUNCS_SETUP FUNCS_FIX FUNCS_CHECK FUNCS_MISC
|
||||||
unset DAEMONS_START HOSTNAME DOMAINNAME CHKSUM_FILE
|
unset DAEMONS_START HOSTNAME DOMAINNAME
|
||||||
|
|
||||||
#shellcheck disable=SC2034
|
#shellcheck disable=SC2034
|
||||||
declare -A VARS
|
declare -A VARS
|
||||||
|
@ -72,12 +72,8 @@ VARS[UPDATE_CHECK_INTERVAL]="${UPDATE_CHECK_INTERVAL:=1d}"
|
||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
VARS[VIRUSMAILS_DELETE_DELAY]="${VIRUSMAILS_DELETE_DELAY:=7}"
|
VARS[VIRUSMAILS_DELETE_DELAY]="${VIRUSMAILS_DELETE_DELAY:=7}"
|
||||||
|
|
||||||
export HOSTNAME DOMAINNAME CHKSUM_FILE
|
|
||||||
|
|
||||||
_obtain_hostname_and_domainname
|
_obtain_hostname_and_domainname
|
||||||
|
|
||||||
CHKSUM_FILE=/tmp/docker-mailserver-config-chksum
|
|
||||||
|
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
# ? << Setup of default and global values / variables
|
# ? << Setup of default and global values / variables
|
||||||
# --
|
# --
|
||||||
|
@ -236,19 +232,19 @@ function _register_misc_function
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
|
|
||||||
# shellcheck source=./startup/check-stack.sh
|
# shellcheck source=./startup/check-stack.sh
|
||||||
. /usr/local/bin/check-stack.sh
|
source /usr/local/bin/check-stack.sh
|
||||||
|
|
||||||
# shellcheck source=./startup/setup-stack.sh
|
# shellcheck source=./startup/setup-stack.sh
|
||||||
. /usr/local/bin/setup-stack.sh
|
source /usr/local/bin/setup-stack.sh
|
||||||
|
|
||||||
# shellcheck source=./startup/fixes-stack.sh
|
# shellcheck source=./startup/fixes-stack.sh
|
||||||
. /usr/local/bin/fixes-stack.sh
|
source /usr/local/bin/fixes-stack.sh
|
||||||
|
|
||||||
# shellcheck source=./startup/misc-stack.sh
|
# shellcheck source=./startup/misc-stack.sh
|
||||||
. /usr/local/bin/misc-stack.sh
|
source /usr/local/bin/misc-stack.sh
|
||||||
|
|
||||||
# shellcheck source=./startup/daemons-stack.sh
|
# shellcheck source=./startup/daemons-stack.sh
|
||||||
. /usr/local/bin/daemons-stack.sh
|
source /usr/local/bin/daemons-stack.sh
|
||||||
|
|
||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
# ? << Sourcing all stacks
|
# ? << Sourcing all stacks
|
||||||
|
|
|
@ -947,7 +947,6 @@ function _setup_security_stack
|
||||||
cp /tmp/docker-mailserver/spamassassin-rules.cf /etc/spamassassin/
|
cp /tmp/docker-mailserver/spamassassin-rules.cf /etc/spamassassin/
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
if [[ ${SPAMASSASSIN_SPAM_TO_INBOX} -eq 1 ]]
|
if [[ ${SPAMASSASSIN_SPAM_TO_INBOX} -eq 1 ]]
|
||||||
then
|
then
|
||||||
_notify 'inf' 'Configuring Spamassassin/Amavis to send SPAM to inbox'
|
_notify 'inf' 'Configuring Spamassassin/Amavis to send SPAM to inbox'
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#! /bin/bash
|
#! /bin/bash
|
||||||
|
|
||||||
# shellcheck source=./helper-functions.sh
|
# shellcheck source=../helpers/index.sh
|
||||||
. /usr/local/bin/helper-functions.sh
|
source /usr/local/bin/helpers/index.sh
|
||||||
|
|
||||||
function _generate_secret { ( umask 0077 ; dd if=/dev/urandom bs=24 count=1 2>/dev/null | base64 -w0 > "${1}" ; ) ; }
|
function _generate_secret { ( umask 0077 ; dd if=/dev/urandom bs=24 count=1 2>/dev/null | base64 -w0 > "${1}" ; ) ; }
|
||||||
|
|
|
@ -29,12 +29,12 @@ function teardown_file() {
|
||||||
skip 'this test must come first to reliably identify when to run setup_file'
|
skip 'this test must come first to reliably identify when to run setup_file'
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "check helper-functions.sh: _sanitize_ipv4_to_subnet_cidr" {
|
@test "check helper functions (network.sh): _sanitize_ipv4_to_subnet_cidr" {
|
||||||
run docker exec mail_helper_functions bash -c ". /usr/local/bin/helper-functions.sh; _sanitize_ipv4_to_subnet_cidr 255.255.255.255/0"
|
run docker exec mail_helper_functions bash -c "source /usr/local/bin/helpers/index.sh; _sanitize_ipv4_to_subnet_cidr 255.255.255.255/0"
|
||||||
assert_output "0.0.0.0/0"
|
assert_output "0.0.0.0/0"
|
||||||
run docker exec mail_helper_functions bash -c ". /usr/local/bin/helper-functions.sh; _sanitize_ipv4_to_subnet_cidr 192.168.255.14/20"
|
run docker exec mail_helper_functions bash -c "source /usr/local/bin/helpers/index.sh; _sanitize_ipv4_to_subnet_cidr 192.168.255.14/20"
|
||||||
assert_output "192.168.240.0/20"
|
assert_output "192.168.240.0/20"
|
||||||
run docker exec mail_helper_functions bash -c ". /usr/local/bin/helper-functions.sh; _sanitize_ipv4_to_subnet_cidr 192.168.255.14/32"
|
run docker exec mail_helper_functions bash -c "source /usr/local/bin/helpers/index.sh; _sanitize_ipv4_to_subnet_cidr 192.168.255.14/32"
|
||||||
assert_output "192.168.255.14/32"
|
assert_output "192.168.255.14/32"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -196,7 +196,7 @@ function wait_for_changes_to_be_detected_in_container() {
|
||||||
local TIMEOUT=${TEST_TIMEOUT_IN_SECONDS}
|
local TIMEOUT=${TEST_TIMEOUT_IN_SECONDS}
|
||||||
|
|
||||||
# shellcheck disable=SC2016
|
# shellcheck disable=SC2016
|
||||||
repeat_in_container_until_success_or_timeout "${TIMEOUT}" "${CONTAINER_NAME}" bash -c 'source /usr/local/bin/helper-functions.sh; cmp --silent -- <(_monitored_files_checksums) "${CHKSUM_FILE}" >/dev/null'
|
repeat_in_container_until_success_or_timeout "${TIMEOUT}" "${CONTAINER_NAME}" bash -c 'source /usr/local/bin/helpers/index.sh; cmp --silent -- <(_monitored_files_checksums) "${CHKSUM_FILE}" >/dev/null'
|
||||||
}
|
}
|
||||||
|
|
||||||
function wait_for_empty_mail_queue_in_container() {
|
function wait_for_empty_mail_queue_in_container() {
|
||||||
|
|
Loading…
Reference in a new issue