#!/usr/bin/env bash
#
# onx-mail-cert-link — Domain'in mail.* subdomain'i için Dovecot+Postfix SNI
# cert konfigürasyonu (multi-tenant TLS).
#
# Problem: Tek bir Dovecot/Postfix instance her domain için doğru TLS cert
# sunmalı. Apple Mail / Outlook / Thunderbird `mail.<domain>` ile bağlanır
# ve cert'in SAN'larında bu hostname'i bekler.
#
# Çözüm: Per-domain SNI config
#   Dovecot:  conf.d/91-onoxsoft-sni-<domain>.conf  → local_name mail.<domain>
#   Postfix:  /etc/postfix/tls_sni_map               → mail.<domain> → cert paths
#
# Stdin (JSON):
#   {"domain":"example.com","cert_path":"/etc/letsencrypt/live/example.com/fullchain.pem","key_path":"...privkey.pem"}
#
# Eğer cert_path verilmezse /etc/letsencrypt/live/<domain>/ default kullanılır.
#
# Stdout (JSON):
#   {"ok":true,"domain":"example.com","sni_host":"mail.example.com","dovecot_conf":"...","postfix_sni_map":"..."}
#
# Exit codes: 0=ok, 1=invalid, 2=preflight, 3=exec

set -uo pipefail

SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
source "${SCRIPT_DIR}/_lib/common.sh"

onx_json_input
DOMAIN=$(onx_json_field "domain")
CERT_PATH=$(onx_json_field "cert_path")
KEY_PATH=$(onx_json_field "key_path")

[[ -z "${DOMAIN}" ]] && onx_die 1 "domain gerekli"
[[ "${DOMAIN}" =~ ^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$ ]] \
    || onx_die 1 "geçersiz domain"

# Default cert paths
[[ -z "${CERT_PATH}" ]] && CERT_PATH="/etc/letsencrypt/live/${DOMAIN}/fullchain.pem"
[[ -z "${KEY_PATH}" ]]  && KEY_PATH="/etc/letsencrypt/live/${DOMAIN}/privkey.pem"

[[ -r "${CERT_PATH}" ]] || onx_die 2 "cert dosyası okunamıyor: ${CERT_PATH}"
[[ -r "${KEY_PATH}" ]]  || onx_die 2 "key dosyası okunamıyor: ${KEY_PATH}"

SNI_HOST="mail.${DOMAIN}"

# Cert'in SAN'larında mail.${DOMAIN} var mı verify et
CERT_SANS=$(openssl x509 -in "${CERT_PATH}" -noout -text 2>/dev/null | grep -A1 "Subject Alternative Name" | tail -1)
if ! echo "${CERT_SANS}" | grep -q "DNS:${SNI_HOST}"; then
    onx_die 2 "Cert SAN'ında ${SNI_HOST} yok. Cert SAN'lar: ${CERT_SANS}. Önce 'cert-issue' ile mail.* dahil yeni cert al."
fi

# ── Dovecot SNI config ─────────────────────────────────────────────────────
DOVECOT_SNI_DIR="/etc/dovecot/conf.d"
DOVECOT_SNI_FILE="${DOVECOT_SNI_DIR}/91-onoxsoft-sni-${DOMAIN//./_}.conf"

cat > "${DOVECOT_SNI_FILE}" <<DOVECOT_EOF
# ONOXSOFT SNI cert — mail.${DOMAIN}
# Auto-generated by onx-mail-cert-link. Manuel düzenleme!
local_name ${SNI_HOST} {
    ssl_cert = <${CERT_PATH}
    ssl_key = <${KEY_PATH}
}

local_name autodiscover.${DOMAIN} {
    ssl_cert = <${CERT_PATH}
    ssl_key = <${KEY_PATH}
}

local_name autoconfig.${DOMAIN} {
    ssl_cert = <${CERT_PATH}
    ssl_key = <${KEY_PATH}
}
DOVECOT_EOF

chown root:dovecot "${DOVECOT_SNI_FILE}" 2>/dev/null || chown root:root "${DOVECOT_SNI_FILE}"
chmod 640 "${DOVECOT_SNI_FILE}"

# ── Postfix SNI map ────────────────────────────────────────────────────────
POSTFIX_SNI_MAP="/etc/postfix/tls_sni_map"

# Maps format: <hostname> <key_file> <cert_file>
# Update or insert
if [[ -f "${POSTFIX_SNI_MAP}" ]]; then
    # Remove existing entries for this SNI host
    sed -i "/^${SNI_HOST} /d" "${POSTFIX_SNI_MAP}"
    sed -i "/^autodiscover.${DOMAIN} /d" "${POSTFIX_SNI_MAP}"
    sed -i "/^autoconfig.${DOMAIN} /d" "${POSTFIX_SNI_MAP}"
else
    touch "${POSTFIX_SNI_MAP}"
fi

cat >> "${POSTFIX_SNI_MAP}" <<POSTFIX_EOF
${SNI_HOST} ${KEY_PATH} ${CERT_PATH}
autodiscover.${DOMAIN} ${KEY_PATH} ${CERT_PATH}
autoconfig.${DOMAIN} ${KEY_PATH} ${CERT_PATH}
POSTFIX_EOF

chmod 644 "${POSTFIX_SNI_MAP}"

# Postmap (postfix hash db güncelle)
postmap -F "hash:${POSTFIX_SNI_MAP}" 2>/dev/null || true

# postconf — SNI map aktif et (idempotent)
postconf -e "tls_server_sni_maps = hash:${POSTFIX_SNI_MAP}"

# Reload services
systemctl reload dovecot 2>/dev/null || true
systemctl reload postfix 2>/dev/null || true

# Verify (Dovecot config valid mi?)
if ! doveconf -n >/dev/null 2>&1; then
    onx_die 3 "Dovecot config invalid (SNI ekleme sonrası)"
fi

# ── Output ─────────────────────────────────────────────────────────────────
jq -nc \
    --arg domain "${DOMAIN}" \
    --arg sni "${SNI_HOST}" \
    --arg cert "${CERT_PATH}" \
    --arg key "${KEY_PATH}" \
    --arg dovecot_conf "${DOVECOT_SNI_FILE}" \
    --arg postfix_sni "${POSTFIX_SNI_MAP}" \
    '{
        ok: true,
        domain: $domain,
        sni_host: $sni,
        cert_path: $cert,
        key_path: $key,
        dovecot_conf: $dovecot_conf,
        postfix_sni_map: $postfix_sni
    }'

exit 0
