#!/usr/bin/env bash
# audit_ssh_config
# ----------------
# Audita la configuración de sshd_config evaluando parámetros de seguridad,
# revisa intentos de login fallidos y lista las claves autorizadas del usuario.
#
# USO (directo):
#   audit_ssh_config [/ruta/a/sshd_config]
#
# Depende de: grep, ssh (opcional para validación), journalctl o /var/log/auth.log

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/../shell/bash_colors.sh"
source "$SCRIPT_DIR/../shell/bash_log.sh"
bash_colors
bash_log_init

# ─── Funciones puras ──────────────────────────────────────────────────────────

_ssh_get_value() {
    local config="$1"
    local key="$2"
    grep -iE "^[[:space:]]*${key}[[:space:]]" "$config" 2>/dev/null \
        | tail -1 | awk '{print $2}' | xargs
}

_ssh_eval_permit_root() {
    local val="${1:-yes}"
    case "${val,,}" in
        no|prohibit-password) echo "ok" ;;
        without-password)     echo "warn" ;;
        *)                    echo "bad" ;;
    esac
}

_ssh_eval_password_auth() {
    local val="${1:-yes}"
    [[ "${val,,}" == "no" ]] && echo "ok" || echo "bad"
}

_ssh_eval_max_auth_tries() {
    local val="${1:-6}"
    [[ "$val" -le 3 ]] && echo "ok" || echo "warn"
}

_ssh_eval_x11_forwarding() {
    local val="${1:-no}"
    [[ "${val,,}" == "no" ]] && echo "ok" || echo "warn"
}

# ─── Funciones de presentación ────────────────────────────────────────────────

_ssh_print_check() {
    local level="$1"
    local label="$2"
    local value="$3"
    local note="$4"

    case "$level" in
        ok)   echo -e "  ${GREEN}[ok]${NC} ${label}: ${value}" ;;
        warn) echo -e "  ${YELLOW}[!] ${NC} ${label}: ${value} -- ${note}" ;;
        bad)  echo -e "  ${RED}[x] ${NC} ${label}: ${value} -- ${note}" ;;
    esac
}

_ssh_show_config_checks() {
    local config="$1"

    echo -e "${PURPLE}════════ Configuración sshd_config ════════════${NC}"
    echo ""

    local permit_root
    permit_root="$(_ssh_get_value "$config" "PermitRootLogin")"
    permit_root="${permit_root:-yes (por defecto)}"
    _ssh_print_check "$(_ssh_eval_permit_root "$permit_root")" \
        "PermitRootLogin" "$permit_root" "debería ser 'no' o 'prohibit-password'"

    local pass_auth
    pass_auth="$(_ssh_get_value "$config" "PasswordAuthentication")"
    pass_auth="${pass_auth:-yes (por defecto)}"
    _ssh_print_check "$(_ssh_eval_password_auth "$pass_auth")" \
        "PasswordAuthentication" "$pass_auth" "debería ser 'no' (usar claves)"

    local port
    port="$(_ssh_get_value "$config" "Port")"
    port="${port:-22 (por defecto)}"
    if [[ "$port" == "22"* ]]; then
        _ssh_print_check "warn" "Port" "$port" "considera cambiar el puerto 22"
    else
        _ssh_print_check "ok" "Port" "$port" ""
    fi

    local max_tries
    max_tries="$(_ssh_get_value "$config" "MaxAuthTries")"
    max_tries="${max_tries:-6 (por defecto)}"
    _ssh_print_check "$(_ssh_eval_max_auth_tries "${max_tries%% *}")" \
        "MaxAuthTries" "$max_tries" "recomendado <= 3"

    local x11
    x11="$(_ssh_get_value "$config" "X11Forwarding")"
    x11="${x11:-no (por defecto)}"
    _ssh_print_check "$(_ssh_eval_x11_forwarding "$x11")" \
        "X11Forwarding" "$x11" "deshabilitar si no se usa"

    local allow_users allow_groups
    allow_users="$(_ssh_get_value "$config" "AllowUsers")"
    allow_groups="$(_ssh_get_value "$config" "AllowGroups")"
    if [[ -z "$allow_users" && -z "$allow_groups" ]]; then
        _ssh_print_check "warn" "AllowUsers/AllowGroups" "(no definidos)" "considera restringir acceso por usuario o grupo"
    else
        [[ -n "$allow_users"  ]] && _ssh_print_check "ok" "AllowUsers"  "$allow_users" ""
        [[ -n "$allow_groups" ]] && _ssh_print_check "ok" "AllowGroups" "$allow_groups" ""
    fi

    echo ""
}

_ssh_show_failed_logins() {
    echo -e "${PURPLE}════════ Últimos intentos de login fallidos ════${NC}"
    echo ""

    if command -v journalctl &>/dev/null; then
        journalctl -u ssh -u sshd --no-pager -q 2>/dev/null \
            | grep -i "failed\|invalid\|error" | tail -10 \
            | while IFS= read -r line; do echo -e "  ${DIM_GRAY}${line}${NC}"; done || true
    elif [[ -f /var/log/auth.log ]]; then
        grep -i "failed\|invalid" /var/log/auth.log 2>/dev/null | tail -10 \
            | while IFS= read -r line; do echo -e "  ${DIM_GRAY}${line}${NC}"; done || true
    else
        info "No se encontró fuente de logs de autenticación"
    fi

    echo ""
}

_ssh_show_authorized_keys() {
    echo -e "${PURPLE}════════ Claves autorizadas (~/.ssh) ═══════════${NC}"
    echo ""

    local auth_keys="$HOME/.ssh/authorized_keys"
    if [[ -f "$auth_keys" ]]; then
        local count
        count="$(wc -l < "$auth_keys")"
        info "${count} clave(s) en authorized_keys:"
        while IFS= read -r line; do
            [[ -z "$line" || "$line" == "#"* ]] && continue
            local key_type key_comment
            key_type="$(echo "$line" | awk '{print $1}')"
            key_comment="$(echo "$line" | awk '{print $NF}')"
            echo -e "  ${GREEN}*${NC} ${key_type} -- ${key_comment}"
        done < "$auth_keys"
    else
        info "No existe $auth_keys"
    fi

    echo ""
}

# ─── Punto de entrada ─────────────────────────────────────────────────────────

audit_ssh_config() {
    local config_path="${1:-/etc/ssh/sshd_config}"

    if [[ ! -f "$config_path" ]]; then
        warning "audit_ssh_config: no se encontró $config_path -- ¿está instalado sshd?"
    else
        _ssh_show_config_checks "$config_path"
    fi

    _ssh_show_failed_logins
    _ssh_show_authorized_keys
}

# Ejecutar si se llama directamente
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    audit_ssh_config "$@"
fi
