#!/bin/bash
# /usr/lib/nmg/nmg-fix-permissions
#
# Single-source-of-truth permission repair for every file the nmg
# stack touches. Idempotent. Called at the end of every postinst run
# so that *upgrades* repair drift introduced by old versions, and
# *fresh installs* land in a known-good state.
#
# Layout matches docs/permissions.md — when adding a new managed file
# update both this script AND the doc.
set -e

NMG_USER="nmg"
NMG_GROUP="nmg"

# Helper: chown+chmod only if path exists. Avoids spurious errors on
# fresh installs where some files don't exist yet (e.g. peer.crt
# before any cluster-join).
fix() {
    local path="$1" owner="$2" group="$3" mode="$4"
    [ -e "$path" ] || return 0
    chown "$owner:$group" "$path" 2>/dev/null || true
    chmod "$mode" "$path" 2>/dev/null || true
}

fix_dir() {
    local path="$1" owner="$2" group="$3" mode="$4"
    [ -d "$path" ] || return 0
    chown "$owner:$group" "$path" 2>/dev/null || true
    chmod "$mode" "$path" 2>/dev/null || true
}

# ── /var/lib/nmg ─────────────────────────────────────────────────────
fix_dir /var/lib/nmg                          "$NMG_USER" "$NMG_GROUP" 0750
fix     /var/lib/nmg/setup.json               "$NMG_USER" "$NMG_GROUP" 0600
fix     /var/lib/nmg/cluster.json             "$NMG_USER" "$NMG_GROUP" 0640
fix     /var/lib/nmg/node-id                  "$NMG_USER" "$NMG_GROUP" 0644
fix     /var/lib/nmg/license_key              "$NMG_USER" "$NMG_GROUP" 0600
fix     /var/lib/nmg/trial.json               "$NMG_USER" "$NMG_GROUP" 0644
fix     /var/lib/nmg/license_cache.json       "$NMG_USER" "$NMG_GROUP" 0644

for d in sandbox sandbox/queue quarantine yara-rules delivered queue state; do
    fix_dir "/var/lib/nmg/$d"                 "$NMG_USER" "$NMG_GROUP" 0750
done

# ── ACME webroot (root-owned parents, nmg-owned challenge leaf) ──
[ -d /var/lib/letsencrypt ] && {
    install -d -o root      -g root       -m 0755 /var/lib/letsencrypt
    install -d -o root      -g root       -m 0755 /var/lib/letsencrypt/.well-known
    install -d -o "$NMG_USER" -g "$NMG_GROUP" -m 0755 /var/lib/letsencrypt/.well-known/acme-challenge
}

# ── /etc/nmg ────────────────────────────────────────────────────────
fix_dir /etc/nmg                              "$NMG_USER" "$NMG_GROUP" 0755
fix_dir /etc/nmg/secret                       "$NMG_USER" "$NMG_GROUP" 0750
fix     /etc/nmg/secret/session.key           "$NMG_USER" "$NMG_GROUP" 0600
fix     /etc/nmg/secret/portal-session.key    "$NMG_USER" "$NMG_GROUP" 0600
# Cluster CA: cert is group-readable, key is root-owned but nmg-readable
fix     /etc/nmg/secret/cluster-ca.crt        root        "$NMG_GROUP" 0644
fix     /etc/nmg/secret/cluster-ca.key        root        "$NMG_GROUP" 0640
# Peer cert + key: fully nmg-owned, peer.key never world-readable
fix     /etc/nmg/secret/peer.crt              "$NMG_USER" "$NMG_GROUP" 0644
fix     /etc/nmg/secret/peer.key              "$NMG_USER" "$NMG_GROUP" 0600

fix_dir /etc/nmg/banner                       "$NMG_USER" "$NMG_GROUP" 0755
fix_dir /etc/nmg/postfix.d                    "$NMG_USER" "$NMG_GROUP" 0750
fix_dir /etc/nmg/rspamd.d                     "$NMG_USER" "$NMG_GROUP" 0750
fix_dir /etc/nmg/rspamd-maps                  "$NMG_USER" "$NMG_GROUP" 0755

# ── /etc/nmg/tls ────────────────────────────────────────────────────
fix_dir /etc/nmg/tls                          "$NMG_USER" "$NMG_GROUP" 0755
# cert.pem may be a symlink (ACME) or a regular file (custom upload).
# Symlinks ignore chmod; the target's mode is what matters. We still
# adjust the link's owner so a `ls -l` reads cleanly.
if [ -L /etc/nmg/tls/cert.pem ]; then
    chown -h "$NMG_USER:$NMG_GROUP" /etc/nmg/tls/cert.pem 2>/dev/null || true
elif [ -f /etc/nmg/tls/cert.pem ]; then
    fix /etc/nmg/tls/cert.pem                 "$NMG_USER" "$NMG_GROUP" 0644
fi
if [ -L /etc/nmg/tls/key.pem ]; then
    chown -h "$NMG_USER:$NMG_GROUP" /etc/nmg/tls/key.pem 2>/dev/null || true
elif [ -f /etc/nmg/tls/key.pem ]; then
    fix /etc/nmg/tls/key.pem                  "$NMG_USER" "$NMG_GROUP" 0600
fi

# ── /etc/postfix — group-write on dir + main.cf so postconf works ──
if [ -d /etc/postfix ]; then
    chgrp "$NMG_GROUP" /etc/postfix 2>/dev/null || true
    chmod 2775         /etc/postfix 2>/dev/null || true
fi
[ -f /etc/postfix/main.cf ] && {
    chgrp "$NMG_GROUP" /etc/postfix/main.cf 2>/dev/null || true
    chmod 0660         /etc/postfix/main.cf 2>/dev/null || true
}

# ── /etc/rspamd/{local.d,lua.local.d,override.d} — shared between
#    rspamd (_rspamd, reads) and nmg-api (nmg, writes). Setgid so any
#    new file inherits the nmg group; mode 2775 so both groups RW.
for d in /etc/rspamd/local.d /etc/rspamd/lua.local.d /etc/rspamd/override.d; do
    if [ -d "$d" ]; then
        chgrp -R "$NMG_GROUP" "$d" 2>/dev/null || true
        chmod 2775            "$d" 2>/dev/null || true
        chmod -R g+rw         "$d" 2>/dev/null || true
    fi
done

# ── Let's Encrypt: certbot creates {live,archive} as 0700; relax so
#    nginx (www-data) and postfix (root → drop) can follow the
#    /etc/nmg/tls symlinks. privkey.pem itself stays 0640 root:root.
[ -d /etc/letsencrypt/live ]    && chmod 0755 /etc/letsencrypt/live    2>/dev/null || true
[ -d /etc/letsencrypt/archive ] && chmod 0755 /etc/letsencrypt/archive 2>/dev/null || true

# ── /etc/nginx/conf.d — per-portal-domain SSL vhost includes
if [ -d /etc/nginx/conf.d ]; then
    chown root:"$NMG_GROUP" /etc/nginx/conf.d 2>/dev/null || true
    chmod 2775              /etc/nginx/conf.d 2>/dev/null || true
fi

# ── /etc/nftables.d — nmg-api regenerates nmg-custom.nft on every
#    firewall_rules CRUD. Directory needs setgid so the temp-rename
#    in os.Rename() lands under the nmg group; the placeholder file
#    itself is group-writable so Apply() can rewrite it in place.
if [ -d /etc/nftables.d ]; then
    chown root:"$NMG_GROUP" /etc/nftables.d 2>/dev/null || true
    chmod 2775              /etc/nftables.d 2>/dev/null || true
fi
[ -f /etc/nftables.d/nmg-custom.nft ] && {
    chown root:"$NMG_GROUP" /etc/nftables.d/nmg-custom.nft 2>/dev/null || true
    chmod 0664              /etc/nftables.d/nmg-custom.nft 2>/dev/null || true
}

exit 0
