#!/usr/bin/env bash
#
# One-shot reconcile: compact /etc/ssh/whp_blocked_ips.conf and
# /etc/proftpd/conf.d/whp_blocked_ips.conf to match active blocks in
# /docker/whp/sql/security.db.
#
# Background: cleanup_expired_service_blocks() previously deleted expired
# rows from service_blocked_ips but never rewrote the sshd / proftpd block
# files, so DenyUsers / Deny lines accumulated indefinitely. On servers
# where this list grew huge, sshd parsing/reload became slow enough to
# drop incoming SSH connections. The PHP fix prevents new accumulation;
# this script compacts the existing files on each server once.
#
# Idempotent: safe to re-run. If the file already matches DB state, no
# write or service reload happens.

set -euo pipefail

SECURITY_DB="/docker/whp/sql/security.db"
SSH_CONF="/etc/ssh/whp_blocked_ips.conf"
FTP_CONF="/etc/proftpd/conf.d/whp_blocked_ips.conf"
LOG_FILE="/var/log/whp-compact-block-configs.log"

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}

if [[ ! -f "$SECURITY_DB" ]]; then
    log "Security DB not found at $SECURITY_DB — skipping (server has not run log monitor yet)"
    exit 0
fi

# Make sure the table exists; if not, the log monitor was never initialized
# on this server and there is nothing to compact.
if ! /usr/bin/sqlite3 "$SECURITY_DB" \
        "SELECT name FROM sqlite_master WHERE type='table' AND name='service_blocked_ips';" \
        | /usr/bin/grep -q service_blocked_ips; then
    log "service_blocked_ips table not present — skipping"
    exit 0
fi

NOW="$(date +%s)"

active_ips_for() {
    local service="$1"
    /usr/bin/sqlite3 "$SECURITY_DB" \
        "SELECT DISTINCT ip_address FROM service_blocked_ips
         WHERE service_type = '$service'
         AND (unblock_time > $NOW OR unblock_time = -1)
         ORDER BY ip_address;"
}

# --- SSH ---
SSH_TMP="$(mktemp)"
trap 'rm -f "$SSH_TMP" "$FTP_TMP"' EXIT
{
    echo "# WHP SSH Blocked IPs - Auto-generated"
    while IFS= read -r ip; do
        [[ -z "$ip" ]] && continue
        echo "DenyUsers *@$ip"
    done < <(active_ips_for ssh)
} > "$SSH_TMP"

ssh_existing_lines=0
ssh_new_lines=$(/usr/bin/wc -l < "$SSH_TMP")
if [[ -f "$SSH_CONF" ]]; then
    ssh_existing_lines=$(/usr/bin/wc -l < "$SSH_CONF")
fi

if [[ -f "$SSH_CONF" ]] && /usr/bin/cmp -s "$SSH_CONF" "$SSH_TMP"; then
    log "SSH conf already compact (${ssh_existing_lines} lines) — no change"
else
    /usr/bin/install -m 0600 "$SSH_TMP" "$SSH_CONF"
    log "SSH conf compacted: ${ssh_existing_lines} lines -> ${ssh_new_lines} lines"
    if /usr/bin/systemctl is-active --quiet sshd; then
        if /usr/bin/systemctl reload sshd; then
            log "Reloaded sshd"
        else
            log "WARNING: sshd reload failed (config may be invalid; check 'sshd -t')"
        fi
    else
        log "sshd not active — skipping reload"
    fi
fi

# --- FTP ---
FTP_TMP="$(mktemp)"
{
    echo "# WHP FTP Blocked IPs - Auto-generated"
    echo "# Global FTP access restrictions"
    echo "<Global>"
    echo "  <Limit LOGIN>"
    echo "    Order allow,deny"
    echo "    Allow from all"
    while IFS= read -r ip; do
        [[ -z "$ip" ]] && continue
        echo "    Deny from $ip"
    done < <(active_ips_for ftp)
    echo "  </Limit>"
    echo "</Global>"
} > "$FTP_TMP"

ftp_existing_lines=0
ftp_new_lines=$(/usr/bin/wc -l < "$FTP_TMP")
if [[ -f "$FTP_CONF" ]]; then
    ftp_existing_lines=$(/usr/bin/wc -l < "$FTP_CONF")
fi

if [[ -f "$FTP_CONF" ]] && /usr/bin/cmp -s "$FTP_CONF" "$FTP_TMP"; then
    log "FTP conf already compact (${ftp_existing_lines} lines) — no change"
elif [[ ! -d /etc/proftpd ]]; then
    log "proftpd not installed — skipping FTP compact"
else
    /usr/bin/install -m 0600 "$FTP_TMP" "$FTP_CONF"
    log "FTP conf compacted: ${ftp_existing_lines} lines -> ${ftp_new_lines} lines"
    if /usr/bin/systemctl is-active --quiet proftpd; then
        if /usr/bin/systemctl reload proftpd; then
            log "Reloaded proftpd"
        else
            log "WARNING: proftpd reload failed"
        fi
    else
        log "proftpd not active — skipping reload"
    fi
fi

log "Done"
