prepare-dovecot.sh 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. #!/usr/bin/env bash
  2. set -euo pipefail
  3. project_dir="${MAILHUB_PROJECT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)}"
  4. data_dir="${MAILHUB_DATA_DIR:-${project_dir}/data}"
  5. fail() {
  6. echo "Dovecot preparation failed: $*" >&2
  7. exit 1
  8. }
  9. command -v openssl >/dev/null 2>&1 || fail "openssl is required."
  10. [[ ! -L "${data_dir}" ]] || fail "data directory must not be a symbolic link."
  11. mkdir -p "${data_dir}"
  12. data_dir="$(cd "${data_dir}" && pwd -P)"
  13. secret_file="${MAILHUB_DOVECOT_SECRET_FILE:-${data_dir}/secrets/dovecot_auth_secret}"
  14. maildir_root="${MAILHUB_MAILDIR_ROOT:-${data_dir}/maildir}"
  15. host_uid="$(id -u)"
  16. if [[ "$(uname -s)" == "Linux" && "${host_uid}" != "0" && "${host_uid}" != "1000" ]]; then
  17. fail "Linux preparation must run as root or host uid 1000 so the rootless containers can read and write their bind mounts."
  18. fi
  19. case "${secret_file}" in
  20. "${data_dir}"/*) ;;
  21. *) fail "secret file must stay inside the MailHub data directory." ;;
  22. esac
  23. case "${maildir_root}" in
  24. "${data_dir}"/*) ;;
  25. *) fail "Maildir root must stay inside the MailHub data directory." ;;
  26. esac
  27. [[ ! -L "${secret_file}" ]] || fail "secret file must not be a symbolic link."
  28. [[ ! -L "${maildir_root}" ]] || fail "Maildir root must not be a symbolic link."
  29. mkdir -p "$(dirname "${secret_file}")" "${maildir_root}"
  30. if [[ ! -f "${secret_file}" ]]; then
  31. umask 077
  32. temporary_secret="$(mktemp "$(dirname "${secret_file}")/.dovecot-auth.XXXXXX")"
  33. trap 'rm -f -- "${temporary_secret:-}"' EXIT
  34. openssl rand -hex 32 >"${temporary_secret}"
  35. chmod 0600 "${temporary_secret}"
  36. mv "${temporary_secret}" "${secret_file}"
  37. trap - EXIT
  38. fi
  39. [[ -f "${secret_file}" ]] || fail "secret path must be a regular file."
  40. secret="$(tr -d '\r\n' <"${secret_file}")"
  41. [[ "${secret}" =~ ^[0-9a-fA-F]+$ ]] || fail "secret must contain only hexadecimal characters."
  42. (( ${#secret} >= 64 && ${#secret} <= 512 )) || fail "secret must contain 64-512 hexadecimal characters."
  43. if [[ "${host_uid}" == "0" ]]; then
  44. # Both the Node application and Dovecot's rootless mail processes use
  45. # uid/gid 1000. Compose file-backed secrets preserve host ownership on Linux.
  46. chown 1000:1000 "${secret_file}" "${maildir_root}"
  47. fi
  48. chmod 0700 "${maildir_root}"
  49. chmod 0400 "${secret_file}"
  50. echo "Dovecot storage and authentication secret are ready."