#!/bin/bash
# Exit immediately if a command exits with a non-zero status.
set -euo pipefail

# helper to rewrite
configure_from_template() {
    local file="$1"
    local placeholder="$2"
    local value="$3"

    local escaped_value
    escaped_value=$(sed 's/[&|\\]/\\&/g' <<<"$value")

    sed -i "s|$placeholder|$escaped_value|g" "$file"
}

exit_with_error() {
    local message="$1"
    echo "ERROR: ${message}" >&2
    echo -e "\e[0m"
    exit 1
}

################################################################################
# SCRIPT LOGIC FUNCTIONS
################################################################################

# Checks OS version, root privileges, and configuration sanity.
check_prerequisites() {
    echo "--- 1. Checking Prerequisites ---"

    # --- OS Check ---
    source /etc/os-release
    local expected_dist="debian"
    local expected_release="bookworm"

    if [[ "$ID" != "$expected_dist" || "$VERSION_CODENAME" != "$expected_release" ]]; then
        exit_with_error "ERROR: This script is only for a fresh install on $expected_dist $expected_release."
    fi
    echo "  -> OS check passed (Debian 12 Bookworm)."

    # --- Root User Check ---
    if [ "$(id -u)" -ne 0 ]; then
        exit_with_error "ERROR: This script must be run as root."
    fi
    echo "  -> Root privileges check passed."

    # --- Config Sanity Checks ---
    if [ ${#MASTERONION} -lt 62 ]; then
        exit_with_error "ERROR: MASTERONION in endgame.config must be at least 62 characters (including .onion)."
    fi

    if [ "$KEY" = "encryption_key" ]; then
        exit_with_error "ERROR: Change the default 'encryption_key' in endgame.config."
    fi

    if [ ${#SALT} -ne 8 ]; then
        exit_with_error "ERROR: The 'SALT' variable in endgame.config must be exactly 8 characters long."
    fi

    if [ -z "$TORAUTHPASSWORD" ]; then
        exit_with_error "ERROR: The 'TORAUTHPASSWORD' variable in endgame.config cannot be empty."
    fi
    echo "  -> endgame.config sanity checks passed."
}

generate_master_key() {
    echo "--- 2. Generating Master Key ---"
    local salt_hex
    salt_hex=$(echo -n "$SALT" | od -A n -t x1 | sed 's/ *//g')
    MASTER_KEY=$(openssl enc -aes-256-cbc -pbkdf2 -pass pass:"$KEY" -S "$salt_hex" -iter 2000000 -md sha256 -P | grep "key" | sed 's/key=//g')
    echo "  -> Master key generated successfully."
}

# Generates the master key from the user's config values.
generate_ssl_certificate() {
    # Check if hostname argument is provided
    if [[ -z "$1" ]]; then
        echo "Error: Hostname argument is required." >&2
        return 1
    fi

    local onion_hostname="$1"
    local ssl_path="${2:-/etc/nginx/ssl}"

    echo "  -> Hostname: ${onion_hostname}"
    echo "  -> Path:     ${ssl_path}"

    mkdir -p "${ssl_path}"

    local key_path="${ssl_path}/${onion_hostname}.key"
    local cert_path="${ssl_path}/${onion_hostname}.crt"

    # We are using ECC not RSA for speed here. Clients should handle it fine.
    openssl req -x509 -nodes -days 3650 \
        -newkey ec:<(openssl ecparam -name secp384r1) \
        -keyout "${key_path}" \
        -out "${cert_path}" \
        -subj "/CN=${onion_hostname}" \
        -addext "subjectAltName = DNS:${onion_hostname}" > /dev/null 2>&1

    chown root:root "${key_path}" "${cert_path}"
    chmod 600 "${key_path}"
    chmod 644 "${cert_path}"
    echo "  -> SSL certificate and key generated successfully."
}

# Replaces all placeholders in application files with values from the endgame.config.
configure_files() {
    echo "--- 4. Configuring Application Files ---"

    # --- Nginx/Lua Configuration ---
    configure_from_template "lua/cap.lua" "encryption_key" "$KEY"
    configure_from_template "lua/cap.lua" "salt1234" "$SALT"
    configure_from_template "lua/cap.lua" "masterkeymasterkeymasterkey" "$MASTER_KEY"
    configure_from_template "lua/cap.lua" "sessionconfigvalue" "$SESSION_LENGTH"
    configure_from_template "site.conf" "sessionconfigvalue" "$SESSION_LENGTH"
    configure_from_template "site.conf" "requestratelimitvalue" "$REQUESTRATELIMIT"
    configure_from_template "site.conf" "streamratelimitvalue" "$STREAMRATELIMIT"
    configure_from_template "torrc" "streamratelimitvalue" "$STREAMRATELIMIT"

    # --- Styling Configuration ---
    configure_from_template "resty/cap_d.css" "HEXCOLORDARK" "$HEXCOLORDARK"
    configure_from_template "resty/cap_d.css" "HEXCOLOR" "$HEXCOLOR"
    configure_from_template "resty/cap_d.css" "SQUARELOGO" "$SQUARELOGO"
    configure_from_template "resty/cap_d.css" "NETWORKLOGO" "$NETWORKLOGO"
    configure_from_template "resty/queue.html" "HEXCOLORDARK" "$HEXCOLORDARK"
    configure_from_template "resty/queue.html" "HEXCOLOR" "$HEXCOLOR"
    configure_from_template "resty/queue.html" "SITENAME" "$SITENAME"
    configure_from_template "resty/queue.html" "FAVICON" "$FAVICON"
    configure_from_template "resty/queue.html" "SQUARELOGO" "$SQUARELOGO"

    configure_from_template "resty/caphtml.lua" "SITENAME" "$SITENAME"
    configure_from_template "resty/caphtml.lua" "SITETAGLINE" "$SITETAGLINE"
    configure_from_template "resty/caphtml.lua" "SITESINCE" "$SITESINCE"
    configure_from_template "resty/caphtml.lua" "FAVICON" "$FAVICON"

    echo "  -> Configured application and styles."

    # --- Proxy/Backend Configuration ---
    if $LOCALPROXY; then
        echo "  -> Configuring for local proxy pass."
        configure_from_template "site.conf" "backendurl" "$PROXYPASSURL"
    else
        echo "  -> Configuring for Tor backend onions."
        configure_from_template "startup.sh" "HOSTNAME1" "$BACKENDONION1"
        configure_from_template "startup.sh" "HOSTNAME2" "$BACKENDONION2"
        sed -i 's/#t/t/' startup.sh > /dev/null 2>&1
        sed -i 's/#n/n/' startup.sh > /dev/null 2>&1
        configure_from_template "site.conf" "backendurl" "tor"
    fi

    # --- Tor Configuration ---
    echo "  -> Configuring for Tor OnionBalance setup."
    configure_from_template "site.conf" "masterbalanceonion" "$MASTERONION"
    configure_from_template "site.conf" "torauthpassword" "$TORAUTHPASSWORD"
}

# Sets up APT repositories for Nginx, Tor, and optionally the unstable Kernel.
setup_repositories() {
    echo "--- 5. Setting up APT Repositories ---"
    apt update > /dev/null 2>&1
    apt install -y -q apt-transport-https lsb-release ca-certificates gpg > /dev/null 2>&1

    # --- Nginx Repository ---
    echo "deb [signed-by=/etc/apt/trusted.gpg.d/nginx.gpg] https://nginx.org/packages/$ID/ $VERSION_CODENAME nginx" > /etc/apt/sources.list.d/nginx.list
    mv "repokeys/nginx.gpg" "/etc/apt/trusted.gpg.d/nginx.gpg"
    echo "  -> Nginx repository configured."

    # --- Tor Repository ---
    echo "deb [signed-by=/usr/share/keyrings/deb.torproject.org-keyring.gpg] https://deb.torproject.org/torproject.org bookworm main" > /etc/apt/sources.list.d/tor.list
    mv "repokeys/deb.torproject.org-keyring.gpg" "/usr/share/keyrings/deb.torproject.org-keyring.gpg"
    echo "  -> Tor Project repository configured."

    # --- Unstable Kernel Repository ---
    if $LATESTKERNEL; then
        echo "  -> Configuring repository for latest unstable kernel."
        echo "deb https://deb.debian.org/debian unstable main contrib non-free" > /etc/apt/sources.list.d/kernel.list
        mv aptpreferences /etc/apt/preferences
    fi

    echo "  -> Updating package lists..."
    apt update > /dev/null 2>&1
}

# Installs all required packages and performs a system upgrade.
install_dependencies() {
    echo "--- 6. Installing Dependencies and Upgrading System ---"

    # Define common silent apt options
    local APT_SILENT_OPTS="-y -qq -o Dpkg::Options::=--force-confdef"

    echo "  -> Installing Core Dependencies..."
    # --- Core Dependencies ---
    DEBIAN_FRONTEND=noninteractive apt install $APT_SILENT_OPTS nginx build-essential zlib1g-dev libpcre3-dev uuid-dev gcc git wget curl libpcre2-dev > /dev/null 2>&1

    # --- Tor Dependencies ---
    echo "  -> Installing Tor Dependencies..."
    DEBIAN_FRONTEND=noninteractive apt install $APT_SILENT_OPTS tor nyx socat deb.torproject.org-keyring > /dev/null 2>&1

    # --- System Hardening Tools ---
    echo "  -> Installing Hardening Tools..."
    DEBIAN_FRONTEND=noninteractive apt install $APT_SILENT_OPTS apt-listbugs needrestart debsecan debsums fail2ban libpam-tmpdir rkhunter chkrootkit rng-tools > /dev/null 2>&1

    # --- System Upgrade ---
    echo "  -> Performing full system upgrade (this may take a while)..."
    DEBIAN_FRONTEND=noninteractive apt $APT_SILENT_OPTS full-upgrade > /dev/null 2>&1

    # --- Latest Kernel Install ---
    if $LATESTKERNEL; then
        echo "  -> Installing latest kernel from unstable..."
        DEBIAN_FRONTEND=noninteractive apt install $APT_SILENT_OPTS -t unstable linux-image-amd64 > /dev/null 2>&1
    fi
}

# Builds and installs custom LuaJIT and OpenResty modules.
build_and_install_modules() {
    echo "--- 7. Building and Installing Custom Lua Modules ---"

    export LD_LIBRARY_PATH=/usr/local/lib
    export LUAJIT_LIB=/usr/local/lib
    export LUAJIT_INC=/usr/local/include/luajit-2.1

    # Persist environment variables for system-wide access
    echo "LD_LIBRARY_PATH=/usr/local/lib" > /etc/environment
    echo "LUAJIT_LIB=/usr/local/lib" >> /etc/environment
    echo "LUAJIT_INC=/usr/local/include/luajit-2.1" >> /etc/environment

    mkdir -p building
    cp -R dependencies/* building/
    cd building

    echo "  -> Building LuaJIT..."
    (cd luajit2 && make -j"$(nproc)" && make install) > /dev/null 2>&1

    echo "  -> Installing resty-string..."
    (cd lua-resty-string && make install) > /dev/null 2>&1

    echo "  -> Installing resty-cookie..."
    (cd lua-resty-cookie && make install) > /dev/null 2>&1

    echo "  -> Installing resty-session..."
    mkdir -p /usr/local/share/lua/5.1/resty/
    cp -a lua-resty-session/lib/resty/* /usr/local/share/lua/5.1/resty/

    cd ..
    echo "  -> Custom modules installed."
}

# Configures system services, hardening, and file placements.
configure_system() {
    echo "--- 8. Performing System Configuration and Hardening ---"

    # --- Build and Place Nginx/Lua files ---
    tar zxf resty.tgz -C /usr/local/share/lua/5.1/resty
    ./nginx-update.sh > /dev/null 2>&1
    mv nginx.conf /etc/nginx/nginx.conf
    mv naxsi_core.rules /etc/nginx/naxsi_core.rules
    mv naxsi_whitelist.rules /etc/nginx/naxsi_whitelist.rules

    if [ $CAPTCHA == false ]; then
        configure_from_template "resty/nocaphtml.lua" "sessionconfigvalue" "$SESSION_LENGTH"
        configure_from_template "resty/nocaphtml.lua" "SITENAME" "$SITENAME"
        configure_from_template "lua/cap.lua" "caphtml" "nocaphtml"
    fi

    rm -rf /etc/nginx/lua
    mv lua /etc/nginx/
    mkdir -p /etc/nginx/resty/

    mv resty/* /etc/nginx/resty/
    mkdir -p /etc/nginx/sites-enabled/
    mv site.conf /etc/nginx/sites-enabled/site.conf

    # --- Create Cache Dirs and Set Permissions ---
    mkdir -p /etc/nginx/cache/
    chown -R www-data:www-data /etc/nginx/
    chown -R www-data:www-data /usr/local/lib/lua /usr/local/share/lua/

    # --- Fail2ban ---
    mv jail.local /etc/fail2ban/jail.local
    systemctl restart fail2ban > /dev/null 2>&1
    systemctl enable fail2ban > /dev/null 2>&1
    echo "  -> Fail2ban configured and enabled."

    # --- Set TimeZone to UTC ---
    timedatectl set-timezone UTC

    # --- Custom Startup Service ---
    chmod 500 startup.sh
    chown debian-tor:debian-tor startup.sh
    mv startup.sh /startup.sh
    cat <<EOF > /etc/systemd/system/endgame.service
[Unit]
Description=Endgame Startup Script Service
[Service]
Type=forking
ExecStart=/startup.sh
[Install]
WantedBy=multi-user.target
EOF
    chown root:root /etc/systemd/system/endgame.service
    chmod 600 /etc/systemd/system/endgame.service
    echo "  -> Endgame startup service created."

    # --- Harden Nginx Service ---
    cat <<EOF > /lib/systemd/system/nginx.service
[Unit]
Description=nginx - high performance web server
Documentation=https://nginx.org/en/docs/
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target
[Service]
Type=forking
PIDFile=/var/run/nginx.pid
ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf
ExecReload=/bin/kill -s HUP $(cat /var/run/nginx.pid)
ExecStop=/bin/kill -s TERM $(cat /var/run/nginx.pid)
Environment="LD_LIBRARY_PATH=/usr/local/lib"
ProtectHome=true
NoNewPrivileges=true
ProtectKernelTunables=true
ProtectKernelLogs=true
ProtectControlGroups=true
ProtectKernelModules=yes
KeyringMode=private
ProtectClock=true
ProtectHostname=true
[Install]
WantedBy=multi-user.target
EOF
    echo "  -> Nginx systemd service hardened."

    # --- System Limits and Kernel Parameters ---
    mv sysctl.conf /etc/sysctl.conf
    mv limits.conf /etc/security/limits.conf
    echo "  -> System limits and sysctl parameters applied."

    # --- Cron Jobs ---
    echo "*/5 * * * * root cd /etc/nginx/resty/ && ./captcha && nginx -s reload" > /etc/cron.d/endgame
    echo "0 0 * * * root /usr/sbin/logrotate -f /etc/logrotate.conf" > /etc/cron.d/logrotate
    echo "  -> Cron jobs for captcha generation and log rotation created."

    # --- Logrotate Config ---
    rm -f /etc/logrotate.d/nginx
    cat << EOF > /etc/logrotate.d/nginx
/var/log/nginx/*.log {
  daily
  rotate 7
  missingok
  notifempty
  compress
  sharedscripts
  postrotate
    if [ -f /var/run/nginx.pid ]; then
      kill -USR1 \`cat /var/run/nginx.pid\`
    fi
  endscript
}
EOF
    rm -rf /var/log/nginx/
    mkdir /var/log/nginx/
    chown www-data:www-data /var/log/nginx
    echo "  -> Nginx log rotation configured."

    systemctl daemon-reload > /dev/null 2>&1
    systemctl enable endgame.service > /dev/null 2>&1
    systemctl enable nginx.service > /dev/null 2>&1
}

# Configures and launches the Tor front's instance.
configure_and_start_tor() {
    echo "--- 9. Configuring Tor OnionBalance Instance ---"

    if $TORMINWORK; then
        (cd tor-patch && ./tor-build.sh) > /dev/null 2>&1
    fi

    mv torrc /etc/tor/torrc
    mv torrc2 /etc/tor/torrc2
    mv torrc3 /etc/tor/torrc3

    chown -R debian-tor:debian-tor /etc/tor/

    local torhash
    torhash=$(tor --hash-password "$TORAUTHPASSWORD" | tail -c 62)
    configure_from_template "/etc/tor/torrc" "hashedpassword" "$torhash"

    echo "  -> Starting Tor to generate hidden service files..."
    tor >/dev/null 2>&1
    sleep 10

    if [ -d hidden_service ]; then
        rm -rf /etc/tor/hidden_service
        cp -r hidden_service /etc/tor/
        chown -R debian-tor:debian-tor /etc/tor/hidden_service
        chmod -R 700 /etc/tor/hidden_service
    fi

    TORHOSTNAME=$(cat /etc/tor/hidden_service/hostname)

    echo "  -> Generating Self-Signed SSL Certificate for instance onion..."
    generate_ssl_certificate "$TORHOSTNAME"
    mv ssl/* /etc/nginx/ssl/

    echo "  -> Generating Strong Diffie-Hellman with safe prime (can take a long time)..."
    openssl dhparam -dsaparam -out /etc/nginx/ssl/dhparams.pem 4096

    chown -R www-data:www-data /etc/nginx/

    configure_from_template "/etc/nginx/sites-enabled/site.conf" "mainonion" "$TORHOSTNAME"
    echo "MasterOnionAddress $MASTERONION" > /etc/tor/hidden_service/ob_config

    echo "  -> Applying final OnionBalance configuration..."
    sed -i "s/#HiddenServiceOnionBalanceInstance/HiddenServiceOnionBalanceInstance/g" /etc/tor/torrc > /dev/null 2>&1
    if $TORINTRODEFENSE; then
      sed -i "s/#HiddenServiceEnableIntroDoS/HiddenServiceEnableIntroDoS/g" /etc/tor/torrc > /dev/null 2>&1
    fi
    if $TORPOWDEFENSE; then
      sed -i "s/#HiddenServicePoWDefensesEnabled/HiddenServicePoWDefensesEnabled/g" /etc/tor/torrc > /dev/null 2>&1
    fi
    if $TORMINWORK; then
      sed -i "s/#HiddenServicePoWEffort/HiddenServicePoWEffort/g" /etc/tor/torrc > /dev/null 2>&1
    fi

    echo "  -> Restarting Tor with final configuration..."
    pkill tor
    sleep 3
    tor >/dev/null 2>&1
    echo "  -> Tor setup complete."
}

# Finalizes the setup by starting services.
finalize_setup() {
    echo "--- 10. Finalizing Setup ---"

    echo "  -> Generating initial captcha set..."
    (cd /etc/nginx/resty/ && ./captcha) > /dev/null 2>&1

    echo "  -> Starting services..."
    systemctl start nginx.service > /dev/null 2>&1
    systemctl start endgame.service > /dev/null 2>&1

    #remove the tor service autostart so the endgame script can run it
    systemctl disable tor

    echo "================================================"
    echo "EndGame Setup Script Finished!"
    echo "================================================"

    echo "Tor Onion Service Hostname: $TORHOSTNAME"
    if $TORPOWDEFENSE; then
        echo "POW DEFENSES ENABLED. YOU CAN'T USE THIS WITH GOBALANCE AS IT DOESN'T SUPPORT POW! Just provide the URL to your users."
    else
        echo "Add this address to your gobalance config.yaml file!"
    fi

    if $REBOOT; then
        echo -e "--- The system will now reboot in 10 seconds as requested! ---"
        sleep 10
        reboot
    fi
    echo -e "\e[0m" #exit purple color
}


################################################################################
# MAIN EXECUTION
################################################################################

main() {
    echo -e "\e[1;35m" #purple color

    ART="███████╗███╗   ██╗██████╗  ██████╗  █████╗ ███╗   ███╗███████╗    ██╗   ██╗██████╗    ███████╗\n"
    ART+="██╔════╝████╗  ██║██╔══██╗██╔════╝ ██╔══██╗████╗ ████║██╔════╝    ██║   ██║╚════██╗   ██╔════╝\n"
    ART+="█████╗  ██╔██╗ ██║██║  ██║██║  ███╗███████║██╔████╔██║█████╗      ██║   ██║ █████╔╝   ███████╗\n"
    ART+="██╔══╝  ██║╚██╗██║██║  ██║██║   ██║██╔══██║██║╚██╔╝██║██╔══╝      ╚██╗ ██╔╝ ╚═══██╗   ╚════██║\n"
    ART+="███████╗██║ ╚████║██████╔╝╚██████╔╝██║  ██║██║ ╚═╝ ██║███████╗     ╚████╔╝ ██████╔╝██╗███████║\n"
    ART+="╚══════╝╚═╝  ╚═══╝╚═════╝  ╚═════╝ ╚═╝  ╚═╝╚═╝     ╚═╝╚══════╝      ╚═══╝  ╚═════╝ ╚═╝╚══════╝\n"

    export ENDGAME_ART="$ART"
    echo -e "$ENDGAME_ART"

    echo "Welcome To The EndGame DDOS Prevention Setup..."
    sleep 1
    echo "This anti-ddos script was created with help from multiple individuals including:"
    echo "/u/Paris (admin of dread)"
    echo "/u/MrWhite (admin of WHM)"
    echo "/u/Drughub (admin of Drughub)"
    echo "/u/InfinityProject"
    echo "/u/francium87"
    sleep 1

    if ! source endgame.config; then
        echo "FATAL: endgame.config not found or contains errors. Exiting." >&2
        exit 1
    fi

    echo "Welcome To The EndGame DDOS Prevention Setup..."
    if $REBOOT; then
        echo "--- The system will reboot after finishing setup! ---"
    fi
    sleep 1

    check_prerequisites
    generate_master_key
    if [ -d "ssl" ]; then
        echo "--- 3. Using Configured SSL Certificate ---"
    else
        echo "--- 3. Generating Self-Signed SSL Certificate ---"
        generate_ssl_certificate "$MASTERONION" "ssl";
    fi
    configure_files
    setup_repositories
    install_dependencies
    build_and_install_modules
    configure_system
    configure_and_start_tor
    finalize_setup

    exit 0
}

main "$@"
