#!/usr/bin/env bash set -euo pipefail project_dir="${MAILHUB_PROJECT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)}" data_dir="${MAILHUB_DATA_DIR:-${project_dir}/data}" fail() { echo "Dovecot preparation failed: $*" >&2 exit 1 } command -v openssl >/dev/null 2>&1 || fail "openssl is required." [[ ! -L "${data_dir}" ]] || fail "data directory must not be a symbolic link." mkdir -p "${data_dir}" data_dir="$(cd "${data_dir}" && pwd -P)" secret_file="${MAILHUB_DOVECOT_SECRET_FILE:-${data_dir}/secrets/dovecot_auth_secret}" maildir_root="${MAILHUB_MAILDIR_ROOT:-${data_dir}/maildir}" host_uid="$(id -u)" if [[ "$(uname -s)" == "Linux" && "${host_uid}" != "0" && "${host_uid}" != "1000" ]]; then fail "Linux preparation must run as root or host uid 1000 so the rootless containers can read and write their bind mounts." fi case "${secret_file}" in "${data_dir}"/*) ;; *) fail "secret file must stay inside the MailHub data directory." ;; esac case "${maildir_root}" in "${data_dir}"/*) ;; *) fail "Maildir root must stay inside the MailHub data directory." ;; esac [[ ! -L "${secret_file}" ]] || fail "secret file must not be a symbolic link." [[ ! -L "${maildir_root}" ]] || fail "Maildir root must not be a symbolic link." mkdir -p "$(dirname "${secret_file}")" "${maildir_root}" if [[ ! -f "${secret_file}" ]]; then umask 077 temporary_secret="$(mktemp "$(dirname "${secret_file}")/.dovecot-auth.XXXXXX")" trap 'rm -f -- "${temporary_secret:-}"' EXIT openssl rand -hex 32 >"${temporary_secret}" chmod 0600 "${temporary_secret}" mv "${temporary_secret}" "${secret_file}" trap - EXIT fi [[ -f "${secret_file}" ]] || fail "secret path must be a regular file." secret="$(tr -d '\r\n' <"${secret_file}")" [[ "${secret}" =~ ^[0-9a-fA-F]+$ ]] || fail "secret must contain only hexadecimal characters." (( ${#secret} >= 64 && ${#secret} <= 512 )) || fail "secret must contain 64-512 hexadecimal characters." if [[ "${host_uid}" == "0" ]]; then # Both the Node application and Dovecot's rootless mail processes use # uid/gid 1000. Compose file-backed secrets preserve host ownership on Linux. chown 1000:1000 "${secret_file}" "${maildir_root}" fi chmod 0700 "${maildir_root}" chmod 0400 "${secret_file}" echo "Dovecot storage and authentication secret are ready."