#!/usr/bin/env bash
# =============================================================================
# VCS Akadémia — Level 1 / Chapter 2: Sudo user setup
# -----------------------------------------------------------------------------
# Web:    https://vcs-akademia.net/kurz/level-1/sudo-user
# GitHub: github.com/virtucybersecurity/vcs-akademia
#
# Usage (run on the VPS, as root):
#   curl -O https://vcs-akademia.net/script/level-1/sudo-user/setup-sudo-user.sh
#   bash setup-sudo-user.sh
#
# =============================================================================
# PREČO TENTO SKRIPT EXISTUJE
# =============================================================================
#
# Root login je bezpečnostné riziko z troch konkrétnych dôvodov:
#
#   1. Žiadny audit trail.
#      Logy zobrazujú "root logged in", "root ran command X" — bez
#      informácie o tom, kto reálne za týmto bol. Pri incidente
#      forenzná analýza prakticky nemožná.
#
#   2. Univerzálny cieľ botnetov.
#      90% pokusov o brute-force SSH login mieri na 'root'. Premenovať
#      sa nedá, ale prihlasovanie ako root sa dá vypnúť (CH 4).
#
#   3. Katastrofické chyby.
#      'rm -rf /tmp/cache' ako root pri preklepe = celý filesystem.
#      Sudo vyžaduje vedomé povolenie pred deštruktívnymi operáciami.
#
# Tento skript rieši všetky tri:
#   - Vytvorí non-root používateľa s vlastným menom a heslom
#   - Pridá ho do sudo skupiny
#   - Otestuje, že sudo funguje pre nový účet
#   - Aktualizuje baseline dokumentáciu
#
# Skript NEVYPÍNA root SSH login — to robí CH 4 (SSH hardening),
# kde sa to dá robiť bezpečne so záložným plánom.
#
# =============================================================================
# AKO TO TENTO SKRIPT ROBÍ
# =============================================================================
#
# Skript beží PRIAMO NA VPS ako root. V 4 krokoch:
#
#   1. Overenie — bežíme ako root? Existuje balík sudo?
#   2. Vytvorenie používateľa cez adduser (interaktívne, pýta heslo).
#   3. Pridanie do sudo skupiny cez usermod -aG sudo (append, nie replace).
#   4. Test sudo z nového účtu (overí, že sudo skutočne funguje).
#
# Po úspešnom dokončení skript aktualizuje /root/server-baseline.txt
# o informáciu o novom používateľovi a vypíše ďalšie kroky.
#
# =============================================================================

set -u
set -o pipefail

# -----------------------------------------------------------------------------
# Colors (ANSI escape codes)
# -----------------------------------------------------------------------------
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

# -----------------------------------------------------------------------------
# Output helpers
# -----------------------------------------------------------------------------
print_info()    { printf "${BLUE}[INFO]${NC} %s\n" "$*"; }
print_success() { printf "${GREEN}[OK]${NC} %s\n" "$*"; }
print_warning() { printf "${YELLOW}[VAROVANIE]${NC} %s\n" "$*" >&2; }
print_error()   { printf "${RED}[CHYBA]${NC} %s\n" "$*" >&2; }
print_fatal()   { print_error "$*"; cleanup_on_exit; exit 1; }

# -----------------------------------------------------------------------------
# Cleanup — remove the script file when we're done (success or failure).
# -----------------------------------------------------------------------------
SCRIPT_SOURCE="${BASH_SOURCE[0]:-$0}"

cleanup_on_exit() {
    [ -f "$SCRIPT_SOURCE" ] || return 0

    local script_dir script_name script_path
    script_dir="$(cd "$(dirname "$SCRIPT_SOURCE")" 2>/dev/null && pwd)" || return 0
    script_name="$(basename "$SCRIPT_SOURCE")"
    script_path="${script_dir}/${script_name}"

    case "$script_name" in
        setup-sudo-user.sh) ;;
        *) return 0 ;;
    esac

    case "$script_path" in
        /|/bin/*|/sbin/*|/usr/*|/etc/*|/var/*|/lib/*|/lib64/*|/boot/*)
            return 0 ;;
    esac

    [ -f "$script_path" ] && rm -f "$script_path" 2>/dev/null && \
        print_info "Skript bol odstránený: $script_path"
    return 0
}

trap cleanup_on_exit EXIT

# -----------------------------------------------------------------------------
# Pre-flight checks
# -----------------------------------------------------------------------------
preflight() {
    # Must be Linux
    if [ "$(uname -s)" != "Linux" ]; then
        print_fatal "Tento skript sa spúšťa NA serveri (Linux), nie lokálne."
    fi

    # Must be root (we create users and modify groups)
    if [ "$(id -u)" -ne 0 ]; then
        print_fatal "Tento skript musí byť spustený ako root.

Ak si na serveri ako bežný používateľ, prepni sa:
  sudo bash setup-sudo-user.sh

Ak si stratil root prístup, využi rescue mode poskytovateľa."
    fi

    # Must be Debian/Ubuntu based (uses adduser, apt)
    if ! command -v adduser >/dev/null 2>&1; then
        print_fatal "Tento skript podporuje len Debian/Ubuntu (adduser). Pre iné distribúcie použi ručný postup z kapitoly."
    fi

    # Check sudo is installed
    if ! command -v sudo >/dev/null 2>&1; then
        print_warning "Balík 'sudo' nie je nainštalovaný."
        print_info "Inštalujem ho..."
        if ! apt update >/dev/null 2>&1 || ! apt install -y sudo >/dev/null 2>&1; then
            print_fatal "Nepodarilo sa nainštalovať sudo. Skontroluj sieť alebo apt."
        fi
        print_success "Balík sudo nainštalovaný."
    fi
}

# -----------------------------------------------------------------------------
# Confirmation prompt
# -----------------------------------------------------------------------------
confirm() {
    local prompt="${1:-Pokračovať?}"
    local reply
    printf "${YELLOW}%s [y/N]:${NC} " "$prompt"
    read -r reply </dev/tty
    case "$reply" in
        y|Y|yes|YES|ano|ANO) return 0 ;;
        *) printf "${BLUE}[INFO]${NC} Zrušené.\n"; exit 0 ;;
    esac
}

# -----------------------------------------------------------------------------
# Ask for user input with optional default and validation
# -----------------------------------------------------------------------------
ask() {
    local prompt="$1"
    local default="${2:-}"
    local reply
    if [ -n "$default" ]; then
        printf "%s [%s]: " "$prompt" "$default" >&2
    else
        printf "%s: " "$prompt" >&2
    fi
    read -r reply </dev/tty
    if [ -z "$reply" ]; then
        echo "$default"
    else
        echo "$reply"
    fi
}

# -----------------------------------------------------------------------------
# Validate username
# Linux username conventions: lowercase, alphanumeric + hyphens, start with letter
# -----------------------------------------------------------------------------
validate_username() {
    local name="$1"

    # Check length (1-32 chars)
    if [ -z "$name" ] || [ ${#name} -gt 32 ]; then
        echo "Meno musí mať 1–32 znakov."
        return 1
    fi

    # Check pattern: starts with lowercase letter, then alphanumeric/hyphen/underscore
    if ! echo "$name" | grep -qE '^[a-z][a-z0-9_-]*$'; then
        echo "Meno musí začínať malým písmenom a obsahovať len malé písmená, čísla, '_' a '-'."
        return 1
    fi

    # Reject obvious bad names
    case "$name" in
        root|admin|administrator|superuser|god|toor|sudo)
            echo "Meno '$name' je zlá voľba — provokuješ útočníkov. Použi tvoje skutočné meno."
            return 1
            ;;
    esac

    # Check if user already exists
    if id "$name" >/dev/null 2>&1; then
        echo "Používateľ '$name' už existuje."
        return 1
    fi

    return 0
}

# -----------------------------------------------------------------------------
# Create the new user (interactive — adduser asks for password)
# -----------------------------------------------------------------------------
create_user() {
    local username="$1"

    print_info "Vytváram používateľa '$username' cez adduser..."
    print_info "adduser sa ťa opýta na heslo a pár nepovinných polí."
    echo

    # adduser is interactive — handles password prompt, home dir, default files
    if ! adduser --gecos "" "$username"; then
        print_fatal "adduser zlyhal."
    fi

    print_success "Používateľ '$username' vytvorený."
}

# -----------------------------------------------------------------------------
# Add user to sudo group
# -----------------------------------------------------------------------------
add_to_sudo_group() {
    local username="$1"

    print_info "Pridávam '$username' do sudo skupiny..."

    # -aG: append (a) to group(s) (G). Without -a, would replace all groups.
    if ! usermod -aG sudo "$username"; then
        print_fatal "usermod zlyhal."
    fi

    # Verify
    if ! groups "$username" | grep -q '\bsudo\b'; then
        print_fatal "Pridanie do sudo skupiny zlyhalo — '$username' nie je v skupine sudo."
    fi

    print_success "'$username' je teraz v skupine sudo."
    print_info "Skupiny: $(groups "$username" | cut -d: -f2 | xargs)"
}

# -----------------------------------------------------------------------------
# Test sudo functionality for new user
# This is critical — we want to verify sudo actually works before celebrating.
# -----------------------------------------------------------------------------
test_sudo() {
    local username="$1"

    print_info "Testujem sudo z účtu '$username'..."
    print_info "(Krátky príkaz, ktorý vyžaduje root práva.)"
    echo

    # Run 'true' (no-op) as the user via sudo. This forces password prompt.
    # We capture output so we can interpret the result.
    print_info "Zadaj heslo pre '$username' (nie root heslo):"

    if su - "$username" -c 'sudo -k; sudo -p "[sudo] heslo pre %u: " true' 2>&1; then
        print_success "Sudo funguje pre '$username'."
        return 0
    else
        print_error "Sudo test zlyhal."
        print_warning "Možné príčiny:"
        print_warning "  - Nesprávne heslo (skús ešte raz spustením skriptu)"
        print_warning "  - '$username' nie je v sudo skupine (overiť: 'groups $username')"
        print_warning "  - Konfigurácia sudo zakazuje skupinu (overiť: '/etc/sudoers')"
        return 1
    fi
}

# -----------------------------------------------------------------------------
# Update baseline document (if it exists)
# -----------------------------------------------------------------------------
update_baseline() {
    local username="$1"
    local baseline="/root/server-baseline.txt"

    if [ ! -f "$baseline" ]; then
        print_info "Baseline dokument neexistuje ($baseline)."
        print_info "Ak si CH 1 ešte nedotiahol, môžeš ho pridať neskôr."
        return 0
    fi

    print_info "Aktualizujem baseline ($baseline)..."

    {
        echo ""
        echo "=== Sudo používateľ ==="
        echo "Pridaný: $(date +%Y-%m-%d)"
        echo "Meno: $username"
        echo "UID: $(id -u "$username")"
        echo "GID: $(id -g "$username")"
        echo "Skupiny: $(groups "$username" | cut -d: -f2 | xargs)"
        echo "Domov: $(getent passwd "$username" | cut -d: -f6)"
    } >> "$baseline"

    print_success "Baseline aktualizovaný."
}

# -----------------------------------------------------------------------------
# Final summary
# -----------------------------------------------------------------------------
print_summary() {
    local username="$1"

    echo
    printf "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}\n"
    printf "${GREEN}  Sudo používateľ pripravený: HOTOVO${NC}\n"
    printf "${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}\n"
    echo
    printf "  Nový účet:          ${BLUE}%s${NC}\n" "$username"
    printf "  Domovský adresár:   %s\n" "$(getent passwd "$username" | cut -d: -f6)"
    printf "  Prístup k sudo:     ${GREEN}Áno${NC}\n"
    echo
    printf "${YELLOW}  ČO ROBIŤ TERAZ:${NC}\n"
    echo
    printf "  1. Odhlás sa z root účtu:\n"
    printf "     ${BLUE}exit${NC}\n"
    echo
    printf "  2. Prihlás sa z lokálneho počítača ako '%s':\n" "$username"
    printf "     ${BLUE}ssh %s@TVOJA_IP${NC}\n" "$username"
    echo
    printf "  3. Otestuj sudo z novej session:\n"
    printf "     ${BLUE}sudo whoami${NC}\n"
    printf "     (mal by si dostať 'root')\n"
    echo
    printf "${YELLOW}  Ďalej:${NC} CH 3 — SSH key authentication\n"
    printf "  Pridáme SSH kľúč pre nový non-root účet, aby si sa\n"
    printf "  prihlasoval bez hesla.\n"
    printf "  https://vcs-akademia.net/kurz/level-1/ssh-key\n"
    echo
    print_warning "ZATIAĽ NEVYPÍNAJ root SSH login!"
    print_warning "To robí CH 4 — bezpečne, so záložným plánom."
    echo
}

# -----------------------------------------------------------------------------
# MAIN
# -----------------------------------------------------------------------------
main() {
    printf "\n${BLUE}=== VCS Akadémia — CH 2: Sudo používateľ ===${NC}\n\n"

    cat <<EOF
Tento skript urobí 4 kroky:
  1. Overí, že bežíme ako root a máme nainštalovaný 'sudo'.
  2. Vytvorí nového non-root používateľa (pýta meno + heslo).
  3. Pridá ho do sudo skupiny.
  4. Otestuje, že sudo z nového účtu skutočne funguje.

BEZPEČNOSTNÁ POZNÁMKA:
  Skript NEVYPÍNA root SSH login. Root účet zostane funkčný.
  Vypnutie root SSH je obsahom CH 4 (SSH hardening), kde sa
  to robí bezpečne, s testovaním pred vypnutím.

EOF

    confirm "Chceš pokračovať?"

    printf "\n${BLUE}-- Pre-flight kontrola --${NC}\n"
    preflight
    print_success "Pripravený na vytvorenie používateľa."

    printf "\n${BLUE}-- Krok 1/4 — Voľba mena --${NC}\n"
    print_info "Konvencia pre meno používateľa:"
    print_info "  - 1–32 znakov, len malé písmená, čísla, '_' a '-'"
    print_info "  - Začína malým písmenom"
    print_info "  - Rozumné: 'peter', 'mike', 'admin1', 'deploy-bot'"
    print_info "  - Vyhni sa: 'root2', 'superuser', 'admin' (provokácia útočníkov)"
    echo

    local username
    local validation_error
    while true; do
        username=$(ask "Meno nového používateľa" "")
        validation_error=$(validate_username "$username")
        if [ $? -eq 0 ]; then
            break
        fi
        print_warning "$validation_error"
        if ! confirm "Skúsiť znova?"; then
            print_fatal "Zrušené."
        fi
    done

    echo
    print_info "Použijem meno: $username"
    confirm "Pokračovať?"

    printf "\n${BLUE}-- Krok 2/4 — Vytvorenie účtu --${NC}\n"
    create_user "$username"

    printf "\n${BLUE}-- Krok 3/4 — Sudo skupina --${NC}\n"
    add_to_sudo_group "$username"

    printf "\n${BLUE}-- Krok 4/4 — Test sudo --${NC}\n"
    if ! test_sudo "$username"; then
        print_warning "Sudo test zlyhal, ale účet '$username' bol vytvorený a pridaný do sudo skupiny."
        print_warning "Skús sa prihlásiť ako '$username' manuálne a otestuj 'sudo whoami'."
        # Don't fatal — user account exists, just couldn't verify
    fi

    # Update baseline (non-fatal if missing)
    echo
    update_baseline "$username"

    print_summary "$username"
}

main "$@"
