#!/usr/bin/env bash
#
# onx-fail2ban-settings-write — Global fail2ban ayarlarını /etc/fail2ban/jail.local'a yaz.
#
# Input (stdin JSON):
#   {
#     "default_bantime": 3600,
#     "default_findtime": 600,
#     "default_maxretry": 5,
#     "default_action": "%(action_mwl)s",
#     "destemail": "admin@example.com",
#     "sender": "fail2ban@example.com",
#     "dbpurgeage": 86400,
#     "dbmaxmatches": 10,
#     "logtarget": "/var/log/fail2ban.log",
#     "loglevel": "INFO",
#     "notify_on_ban": "1"|"0",
#     "recidive_enabled": "1"|"0"
#   }
#
# Output: {"ok":true,"updated_keys":[...],"reloaded":true,"recidive_enabled":bool}

set -euo pipefail

input="$(cat)"
readonly JAIL_LOCAL="/etc/fail2ban/jail.local"
readonly RECIDIVE_FILE="/etc/fail2ban/jail.d/recidive.local"
readonly LOG_TAG="onox-fail2ban-cfg"

get() { echo "$input" | jq -r ".$1 // empty"; }

# Mevcut ignoreip'i koru
existing_ignoreip=""
if [[ -f "$JAIL_LOCAL" ]] && grep -qE '^[[:space:]]*ignoreip[[:space:]]*=' "$JAIL_LOCAL"; then
    existing_ignoreip="$(grep -E '^[[:space:]]*ignoreip[[:space:]]*=' "$JAIL_LOCAL" | head -1 | sed -E 's/^[^=]+=[[:space:]]*//')"
fi
[[ -z "$existing_ignoreip" ]] && existing_ignoreip="127.0.0.1/8 ::1"

# ── Build new jail.local [DEFAULT] section ────────────────────────────────
default_bantime="$(get default_bantime)"
default_findtime="$(get default_findtime)"
default_maxretry="$(get default_maxretry)"
default_action="$(get default_action)"
destemail="$(get destemail)"
notify_on_ban="$(get notify_on_ban)"

# v57 ACTION SANITIZE — AlmaLinux/RHEL jail.conf'unda SADECE %(action_)s var.
# action_m/_mw/_mwl interpolation key'leri tanimli degil → "Bad value substitution" crash.
#
# Mail icin DOGRU yontem: multi-line action — action_ + sendmail inline:
#   action = %(action_)s
#            sendmail[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s"]
#
# INI multi-line: ikinci satir BOSLUK ile baslamak zorunda (RFC).
#
# Mantik:
#   notify_on_ban=1 + destemail dolu → multi-line (ban + mail)
#   diger durumda                    → tek satir %(action_)s (ban, mail yok)
#
# Eski action_m/_mw/_mwl istekleri sessizce reset → mantik yeniden hesaplar.
if [[ "$default_action" == *"action_mwl"* || "$default_action" == *"action_mw"* || "$default_action" == *"action_m)"* ]]; then
    logger -t "$LOG_TAG" "Refused unavailable mail interpolation key, recomputing action"
    default_action=""
fi
if [[ -z "$default_action" || "$default_action" == "%(action_)s" ]]; then
    if [[ "$notify_on_ban" == "1" && -n "$destemail" ]]; then
        # v59: ONOXSOFT brandli HTML mail — hem action.d/onox-mail.conf hem mail-notify binary lazim.
        # INI multi-line: ikinci satir ' ' (bosluk) ile baslar.
        if [[ -f /etc/fail2ban/action.d/onox-mail.conf && -x /usr/local/onoxsoft/bin/onx-fail2ban-mail-notify ]]; then
            default_action='%(action_)s
         onox-mail[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s", bantime="%(bantime)s"]'
        else
            # Fallback: standart sendmail (plain text)
            default_action='%(action_)s
         sendmail[name=%(__name__)s, sender="%(sender)s", dest="%(destemail)s"]'
        fi
    else
        default_action='%(action_)s'
    fi
fi
sender="$(get sender)"
dbpurgeage="$(get dbpurgeage)"
dbmaxmatches="$(get dbmaxmatches)"
logtarget="$(get logtarget)"
loglevel="$(get loglevel)"
# v56: notify_on_ban + destemail logic v56 sanitize bloğunda işlendi (yukari).
# Eski "notify_on_ban=1 → action_mwl" mantigi kaldirildi — AlmaLinux mail için action_m kullanir.

# Validate numerics
for v in default_bantime default_findtime default_maxretry dbpurgeage dbmaxmatches; do
    val="${!v}"
    if [[ -n "$val" ]] && ! [[ "$val" =~ ^[0-9]+$ ]]; then
        jq -nc --arg k "$v" --arg val "$val" '{ok:false,error:"not a number",key:$k,value:$val}' >&2
        exit 1
    fi
done

# Backup current
[[ -f "$JAIL_LOCAL" ]] && cp -a "$JAIL_LOCAL" "${JAIL_LOCAL}.bak.$(date +%s)"

# Write new file
{
    echo "# /etc/fail2ban/jail.local — Managed by ONOX panel"
    echo "# Use the panel UI under Security → fail2ban to edit these values."
    echo ""
    echo "[DEFAULT]"
    echo "ignoreip = ${existing_ignoreip}"
    [[ -n "$default_bantime"  ]] && echo "bantime  = ${default_bantime}"
    [[ -n "$default_findtime" ]] && echo "findtime = ${default_findtime}"
    [[ -n "$default_maxretry" ]] && echo "maxretry = ${default_maxretry}"
    [[ -n "$destemail"        ]] && echo "destemail = ${destemail}"
    [[ -n "$sender"           ]] && echo "sender   = ${sender}"
    [[ -n "$default_action"   ]] && echo "action   = ${default_action}"
} > "$JAIL_LOCAL"

# ── fail2ban.local (logtarget, loglevel, dbpurgeage) ──────────────────────
if [[ -n "$logtarget" || -n "$loglevel" || -n "$dbpurgeage" || -n "$dbmaxmatches" ]]; then
    cat > /etc/fail2ban/fail2ban.local <<EOF
# /etc/fail2ban/fail2ban.local — Managed by ONOX panel
[Definition]
$([[ -n "$loglevel"     ]] && echo "loglevel  = $loglevel")
$([[ -n "$logtarget"    ]] && echo "logtarget = $logtarget")
$([[ -n "$dbpurgeage"   ]] && echo "dbpurgeage = $dbpurgeage")
$([[ -n "$dbmaxmatches" ]] && echo "dbmaxmatches = $dbmaxmatches")
EOF
fi

# ── Recidive jail toggle ──────────────────────────────────────────────────
recidive_enabled="$(get recidive_enabled)"
if [[ "$recidive_enabled" == "1" ]]; then
    cat > "$RECIDIVE_FILE" <<EOF
[recidive]
enabled  = true
logpath  = /var/log/fail2ban.log
banaction = %(banaction_allports)s
bantime  = 604800
findtime = 86400
maxretry = 3
EOF
else
    [[ -f "$RECIDIVE_FILE" ]] && rm -f "$RECIDIVE_FILE"
fi

# ── Reload / restart ──────────────────────────────────────────────────────
reloaded=true
if command -v fail2ban-client &>/dev/null; then
    # Some changes (logtarget) require restart, not reload
    if [[ -n "$logtarget" ]] && command -v systemctl &>/dev/null; then
        systemctl restart fail2ban 2>/dev/null || reloaded=false
    else
        fail2ban-client reload 2>/dev/null || reloaded=false
    fi
fi

updated_keys="$(echo "$input" | jq -c 'keys')"

logger -t "$LOG_TAG" "Settings updated (keys=$updated_keys)"

jq -nc \
    --argjson updated_keys "$updated_keys" \
    --argjson reloaded "$reloaded" \
    --argjson recidive "$([[ "$recidive_enabled" == "1" ]] && echo true || echo false)" \
    '{ok:true,updated_keys:$updated_keys,reloaded:$reloaded,recidive_enabled:$recidive}'
