﻿<?php

declare(strict_types=1);

/**
 * Hack Detection Service Tester v1.2
 * Enhanced with SSRF testing capabilities
 */

final class HackDetectionTester {
    private const TEST_KEY_HEADER = 'X-Security-Test';
    private string $testKey;
    private array $testResults = [];
    private float $startTime;

    public function __construct() {
        $this->startTime = microtime(true);
        $this->initializeTestEnvironment();
    }

    private function initializeTestEnvironment(): void {
        $testKeyFile = __DIR__ . '/.test_key';
        
        if (!file_exists($testKeyFile)) {
            $this->testKey = $this->generateSecureTestKey();
            file_put_contents($testKeyFile, $this->testKey, LOCK_EX);
            chmod($testKeyFile, 0600);
            echo "Generated new test key: " . substr($this->testKey, 0, 16) . "...\n";
        } else {
            $this->testKey = trim(file_get_contents($testKeyFile));
        }

        $_SERVER['HTTP_X_SECURITY_TEST'] = $this->testKey;
    }

    private function generateSecureTestKey(): string {
        return bin2hex(random_bytes(32));
    }

    /**
     * Run comprehensive test suite including SSRF tests
     */
    public function runAllTests(): array {
        echo "Starting Hack Detection Service Tests...\n";
        echo "Test Key: " . substr($this->testKey, 0, 16) . "...\n\n";

        $this->testPatternValidation();
        $this->testDetectionVectors();
        $this->testProtocolInjectionSpecific();
        $this->testSSRFSpecific();
        $this->testFalsePositives();
        $this->testPerformance();
        $this->testSecurity();

        return $this->generateTestReport();
    }

    /**
     * Specialized SSRF testing
     */
    private function testSSRFSpecific(): void {
        echo "2b. Testing SSRF Specific Vectors...\n";

        $ssrfTests = [
            [
                'category' => 'cloud_metadata',
                'tests' => [
                    ['input' => "http://169.254.169.254/latest/meta-data/", 'expected_score' => 98],
                    ['input' => "http://metadata.google.internal/computeMetadata/v1/", 'expected_score' => 99],
                    ['input' => "http://169.254.169.254/latest/meta-data/iam/security-credentials/", 'expected_score' => 92],
                ]
            ],
            [
                'category' => 'internal_networks',
                'tests' => [
                    ['input' => "http://192.168.1.1/admin", 'expected_score' => 92],
                    ['input' => "http://10.0.0.1:8080/internal", 'expected_score' => 92],
                    ['input' => "http://172.16.1.1:443/api", 'expected_score' => 92],
                ]
            ],
            [
                'category' => 'kubernetes',
                'tests' => [
                    ['input' => "https://kubernetes.default.svc.cluster.local/api/v1/", 'expected_score' => 96],
                    ['input' => "http://10.96.0.1:443/api/v1/namespaces", 'expected_score' => 95],
                ]
            ],
            [
                'category' => 'dangerous_protocols',
                'tests' => [
                    ['input' => "gopher://internal:3306/_mysql", 'expected_score' => 89],
                    ['input' => "dict://localhost:11211/info", 'expected_score' => 87],
                    ['input' => "file:///etc/passwd", 'expected_score' => 93],
                ]
            ],
            [
                'category' => 'bypass_techniques',
                'tests' => [
                    ['input' => "http://2130706433/admin", 'expected_score' => 72],
                    ['input' => "http://0x7f000001/api", 'expected_score' => 70],
                    ['input' => "http://127.0.0.1.xip.io/dashboard", 'expected_score' => 75],
                    ['input' => "http://l0calh0st:8080/internal", 'expected_score' => 59],
                ]
            ],
            [
                'category' => 'container_networks',
                'tests' => [
                    ['input' => "http://host.docker.internal:2375/containers", 'expected_score' => 66],
                    ['input' => "http://172.17.0.1:8080/management", 'expected_score' => 69],
                ]
            ]
        ];

        $this->testResults['ssrf_tests'] = [
            'categories_tested' => count($ssrfTests),
            'total_tests' => 0,
            'passed_tests' => 0,
            'category_results' => []
        ];

        foreach ($ssrfTests as $category) {
            $categoryResults = [
                'category' => $category['category'],
                'tests' => [],
                'passed' => 0,
                'failed' => 0
            ];

            foreach ($category['tests'] as $test) {
                $this->setupTestEnvironment([
                    'get' => ['url' => $test['input']],
                    'server' => [
                        'REQUEST_URI' => '/fetch?url=' . urlencode($test['input']),
                        'HTTP_USER_AGENT' => 'Security-Tester/1.0'
                    ]
                ]);

                $result = HackDetectionService::detectHackAttempt();
                $passed = $result['confidence_score'] >= $test['expected_score'];

                $testResult = [
                    'input' => $test['input'],
                    'expected_score' => $test['expected_score'],
                    'actual_score' => $result['confidence_score'],
                    'passed' => $passed,
                    'detected_vectors' => $result['detected_vectors']
                ];

                $categoryResults['tests'][] = $testResult;

                if ($passed) {
                    $categoryResults['passed']++;
                    $this->testResults['ssrf_tests']['passed_tests']++;
                } else {
                    $categoryResults['failed']++;
                }

                $this->testResults['ssrf_tests']['total_tests']++;
            }

            $this->testResults['ssrf_tests']['category_results'][] = $categoryResults;
        }

        echo "   ✓ Tested " . $this->testResults['ssrf_tests']['total_tests'] . " SSRF vectors\n";
    }

    /**
     * Test SSRF false positives
     */
    private function testSSRFFalsePositives(): void {
        echo "3b. Testing SSRF False Positives...\n";

        $legitimateUrls = [
            [
                'description' => 'Public API endpoint',
                'input' => [
                    'get' => ['api' => 'https://api.github.com/users/octocat'],
                    'server' => [
                        'REQUEST_URI' => '/github?api=https://api.github.com/users/octocat',
                        'HTTP_USER_AGENT' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
                    ]
                ],
                'should_detect' => false
            ],
            [
                'description' => 'Public CDN resource',
                'input' => [
                    'get' => ['css' => 'https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/5.1.3/css/bootstrap.min.css'],
                    'server' => [
                        'REQUEST_URI' => '/cdn?css=https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/5.1.3/css/bootstrap.min.css',
                        'HTTP_USER_AGENT' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36'
                    ]
                ],
                'should_detect' => false
            ],
            [
                'description' => 'External image',
                'input' => [
                    'get' => ['img' => 'https://picsum.photos/200/300'],
                    'server' => [
                        'REQUEST_URI' => '/image?img=https://picsum.photos/200/300',
                        'HTTP_USER_AGENT' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36'
                    ]
                ],
                'should_detect' => false
            ],
            [
                'description' => 'Public weather API',
                'input' => [
                    'get' => ['weather' => 'https://api.openweathermap.org/data/2.5/weather?q=London'],
                    'server' => [
                        'REQUEST_URI' => '/weather?weather=https://api.openweathermap.org/data/2.5/weather?q=London',
                        'HTTP_USER_AGENT' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
                    ]
                ],
                'should_detect' => false
            ]
        ];

        $this->testResults['ssrf_false_positives'] = [
            'total_tests' => count($legitimateUrls),
            'passed_tests' => 0,
            'failed_tests' => 0,
            'test_results' => []
        ];

        foreach ($legitimateUrls as $test) {
            $this->setupTestEnvironment($test['input']);
            
            $result = HackDetectionService::detectHackAttempt();
            $passed = $result['is_hack'] === $test['should_detect'];

            $testResult = [
                'description' => $test['description'],
                'expected_detection' => $test['should_detect'],
                'actual_detection' => $result['is_hack'],
                'confidence_score' => $result['confidence_score'],
                'passed' => $passed
            ];

            $this->testResults['ssrf_false_positives']['test_results'][] = $testResult;

            if ($passed) {
                $this->testResults['ssrf_false_positives']['passed_tests']++;
            } else {
                $this->testResults['ssrf_false_positives']['failed_tests']++;
            }
        }

        echo "   ✓ Tested " . count($legitimateUrls) . " legitimate external URLs\n";
    }

    /**
     * Test cloud metadata service detection
     */
    private function testCloudMetadataDetection(): void {
        echo "2c. Testing Cloud Metadata Service Detection...\n";

        $cloudTests = [
            'aws' => [
                ['input' => 'http://169.254.169.254/latest/meta-data/', 'expected_score' => 98],
                ['input' => 'http://169.254.169.254/latest/user-data/', 'expected_score' => 98],
                ['input' => 'http://169.254.169.254/latest/meta-data/iam/security-credentials/', 'expected_score' => 92],
                ['input' => 'http://169.254.169.254/latest/dynamic/instance-identity/document', 'expected_score' => 98],
            ],
            'gcp' => [
                ['input' => 'http://metadata.google.internal/computeMetadata/v1/', 'expected_score' => 99],
                ['input' => 'http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/', 'expected_score' => 99],
                ['input' => 'http://169.254.169.254/computeMetadata/v1/', 'expected_score' => 99],
            ],
            'azure' => [
                ['input' => 'http://169.254.169.254/metadata/instance?api-version=2021-02-01', 'expected_score' => 98],
                ['input' => 'http://169.254.169.254/metadata/attested/document?api-version=2021-02-01', 'expected_score' => 98],
            ],
            'oracle' => [
                ['input' => 'http://192.0.0.192/latest/', 'expected_score' => 97],
                ['input' => 'http://192.0.0.192/latest/meta-data/', 'expected_score' => 97],
            ]
        ];

        $this->testResults['cloud_metadata_tests'] = [
            'providers_tested' => count($cloudTests),
            'total_tests' => 0,
            'passed_tests' => 0,
            'provider_results' => []
        ];

        foreach ($cloudTests as $provider => $tests) {
            $providerResults = [
                'provider' => $provider,
                'tests' => [],
                'passed' => 0,
                'failed' => 0
            ];

            foreach ($tests as $test) {
                $this->setupTestEnvironment([
                    'get' => ['endpoint' => $test['input']],
                    'server' => [
                        'REQUEST_URI' => '/cloud?endpoint=' . urlencode($test['input']),
                        'HTTP_USER_AGENT' => 'Security-Tester/1.0'
                    ]
                ]);

                $result = HackDetectionService::detectHackAttempt();
                $passed = $result['confidence_score'] >= $test['expected_score'];

                $testResult = [
                    'input' => $test['input'],
                    'expected_score' => $test['expected_score'],
                    'actual_score' => $result['confidence_score'],
                    'passed' => $passed,
                    'detected' => $result['is_hack']
                ];

                $providerResults['tests'][] = $testResult;

                if ($passed) {
                    $providerResults['passed']++;
                    $this->testResults['cloud_metadata_tests']['passed_tests']++;
                } else {
                    $providerResults['failed']++;
                }

                $this->testResults['cloud_metadata_tests']['total_tests']++;
            }

            $this->testResults['cloud_metadata_tests']['provider_results'][] = $providerResults;
        }

        echo "   ✓ Tested " . $this->testResults['cloud_metadata_tests']['total_tests'] . " cloud metadata endpoints\n";
    }

    // ... (rest of the methods remain similar to previous implementation with enhancements)

    private function testPatternValidation(): void {
        echo "1. Testing Pattern Validation...\n";

        $patternDetails = HackDetectionService::getPatternDetails();
        
        $this->testResults['pattern_validation'] = [
            'total_categories' => count($patternDetails),
            'categories_tested' => [],
            'test_cases_found' => 0,
            'regex_errors' => 0
        ];

        foreach ($patternDetails as $category => $details) {
            $categoryResults = [
                'category' => $category,
                'patterns_count' => $details['total_patterns'],
                'test_cases_count' => count($details['test_cases'] ?? []),
                'score_range' => $details['score_range'],
                'test_results' => []
            ];

            if (!empty($details['test_cases'])) {
                foreach ($details['test_cases'] as $testCase) {
                    $testResult = $this->runTestCase($category, $testCase);
                    $categoryResults['test_results'][] = $testResult;
                    
                    if (!$testResult['passed']) {
                        $categoryResults['failed_tests'] = ($categoryResults['failed_tests'] ?? 0) + 1;
                    }
                }
            }

            $this->testResults['pattern_validation']['categories_tested'][] = $categoryResults;
            $this->testResults['pattern_validation']['test_cases_found'] += count($details['test_cases'] ?? []);
        }

        echo "   ✓ Tested " . count($patternDetails) . " pattern categories\n";
        echo "   ✓ Found " . $this->testResults['pattern_validation']['test_cases_found'] . " test cases\n";
    }

    private function runTestCase(string $category, array $testCase): array {
        $this->setupTestEnvironment($testCase['input'] ?? []);
        $result = HackDetectionService::detectHackAttempt();
        $expectedScore = $testCase['expected_score'] ?? 0;
        $actualScore = $result['confidence_score'];
        
        $passed = $this->evaluateTestResult($testCase, $result);

        return [
            'description' => $testCase['description'] ?? 'Unknown test',
            'expected_score' => $expectedScore,
            'actual_score' => $actualScore,
            'passed' => $passed,
            'detected_vectors' => $result['detected_vectors'],
            'risk_level' => $result['risk_level'],
            'is_hack' => $result['is_hack']
        ];
    }

    private function setupTestEnvironment(array $input): void {
        $_GET = $input['get'] ?? [];
        $_POST = $input['post'] ?? [];
        $_COOKIE = $input['cookie'] ?? [];
        $_SERVER = array_merge($_SERVER, $input['server'] ?? []);
        $_FILES = $input['files'] ?? [];
        $_SERVER['HTTP_X_SECURITY_TEST'] = $this->testKey;
    }

    private function evaluateTestResult(array $testCase, array $result): bool {
        $expectedScore = $testCase['expected_score'] ?? 0;
        $expectedDetection = $testCase['should_detect'] ?? ($expectedScore > 0);
        
        $actualScore = $result['confidence_score'];
        $actualDetection = $result['is_hack'];

        $scoreTolerance = 10;
        $scoreMatch = abs($expectedScore - $actualScore) <= $scoreTolerance;
        $detectionMatch = $expectedDetection === $actualDetection;

        return $scoreMatch && $detectionMatch;
    }

    private function testDetectionVectors(): void {
        echo "2. Testing Detection Vectors...\n";

        $vectors = [
            'sql_injection' => [
                ['input' => "1' OR '1'='1", 'expected_score' => 85],
                ['input' => "1; DROP TABLE users", 'expected_score' => 95],
            ],
            'xss_attack' => [
                ['input' => "<script>alert('XSS')</script>", 'expected_score' => 90],
                ['input' => "<img src=x onerror=alert(1)>", 'expected_score' => 85]
            ],
            'rce_attempt' => [
                ['input' => "'; system('id');", 'expected_score' => 95],
                ['input' => "| ls -la", 'expected_score' => 80]
            ]
        ];

        $this->testResults['detection_vectors'] = [
            'vectors_tested' => count($vectors),
            'total_tests' => 0,
            'passed_tests' => 0
        ];

        foreach ($vectors as $vectorName => $tests) {
            $vectorResults = [
                'vector' => $vectorName,
                'tests' => [],
                'passed' => 0,
                'failed' => 0
            ];

            foreach ($tests as $test) {
                $this->setupTestEnvironment([
                    'get' => ['input' => $test['input']],
                    'server' => [
                        'REQUEST_URI' => '/test',
                        'HTTP_USER_AGENT' => 'Security-Tester/1.0'
                    ]
                ]);

                $result = HackDetectionService::detectHackAttempt();
                $passed = $result['confidence_score'] >= $test['expected_score'];

                $vectorResults['tests'][] = [
                    'input' => $test['input'],
                    'expected_score' => $test['expected_score'],
                    'actual_score' => $result['confidence_score'],
                    'passed' => $passed,
                    'detected' => $result['is_hack']
                ];

                if ($passed) {
                    $vectorResults['passed']++;
                    $this->testResults['detection_vectors']['passed_tests']++;
                } else {
                    $vectorResults['failed']++;
                }

                $this->testResults['detection_vectors']['total_tests']++;
            }

            $this->testResults['detection_vectors']['vector_results'][] = $vectorResults;
        }

        echo "   ✓ Tested " . count($vectors) . " detection vectors\n";
    }

    private function testFalsePositives(): void {
        echo "3. Testing False Positive Prevention...\n";

        $legitimateRequests = [
            [
                'description' => 'Normal search query',
                'input' => [
                    'get' => ['q' => 'normal search term'],
                    'server' => [
                        'REQUEST_URI' => '/search?q=normal+search+term',
                        'HTTP_USER_AGENT' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
                    ]
                ],
                'should_detect' => false
            ]
        ];

        $this->testResults['false_positive_tests'] = [
            'total_tests' => count($legitimateRequests),
            'passed_tests' => 0,
            'failed_tests' => 0,
            'test_results' => []
        ];

        foreach ($legitimateRequests as $test) {
            $this->setupTestEnvironment($test['input']);
            
            $result = HackDetectionService::detectHackAttempt();
            $passed = $result['is_hack'] === $test['should_detect'];

            $testResult = [
                'description' => $test['description'],
                'expected_detection' => $test['should_detect'],
                'actual_detection' => $result['is_hack'],
                'confidence_score' => $result['confidence_score'],
                'passed' => $passed
            ];

            $this->testResults['false_positive_tests']['test_results'][] = $testResult;

            if ($passed) {
                $this->testResults['false_positive_tests']['passed_tests']++;
            } else {
                $this->testResults['false_positive_tests']['failed_tests']++;
            }
        }

        echo "   ✓ Tested " . count($legitimateRequests) . " legitimate requests\n";
    }

    private function testPerformance(): void {
        echo "4. Testing Performance...\n";

        $performanceTests = [];
        $totalTime = 0;
        $testCount = 10;

        for ($i = 0; $i < $testCount; $i++) {
            $this->setupTestEnvironment([
                'get' => ['test' => 'performance'],
                'server' => [
                    'REQUEST_URI' => '/test/performance',
                    'HTTP_USER_AGENT' => 'Performance-Tester/1.0'
                ]
            ]);

            $startTime = microtime(true);
            $result = HackDetectionService::detectHackAttempt();
            $endTime = microtime(true);

            $executionTime = $endTime - $startTime;
            $totalTime += $executionTime;

            $performanceTests[] = [
                'iteration' => $i + 1,
                'execution_time' => $executionTime,
                'memory_usage' => memory_get_peak_usage(true),
                'vectors_detected' => count($result['detected_vectors'])
            ];
        }

        $this->testResults['performance_tests'] = [
            'iterations' => $testCount,
            'average_time' => $totalTime / $testCount,
            'total_time' => $totalTime,
            'tests' => $performanceTests,
            'memory_usage' => memory_get_peak_usage(true)
        ];

        echo "   ✓ Completed " . $testCount . " performance iterations\n";
    }

    private function testSecurity(): void {
        echo "5. Testing Security Measures...\n";

        $securityTests = [];

        // Test 1: Verify test mode requires valid key
        $originalKey = $_SERVER['HTTP_X_SECURITY_TEST'];
        $_SERVER['HTTP_X_SECURITY_TEST'] = 'invalid-key';
        $resultWithoutKey = HackDetectionService::detectHackAttempt();
        $_SERVER['HTTP_X_SECURITY_TEST'] = $originalKey;

        $securityTests[] = [
            'test' => 'Test mode requires valid key',
            'passed' => !$resultWithoutKey['test_mode'],
            'description' => 'System should not be in test mode with invalid key'
        ];

        $this->testResults['security_tests'] = [
            'total_tests' => count($securityTests),
            'passed_tests' => count(array_filter($securityTests, fn($test) => $test['passed'])),
            'tests' => $securityTests
        ];

        echo "   ✓ Completed " . count($securityTests) . " security tests\n";
    }

    private function generateTestReport(): array {
        $endTime = microtime(true);
        $totalTime = $endTime - $this->startTime;

        $report = [
            'test_summary' => [
                'total_execution_time' => $totalTime,
                'memory_peak_usage' => memory_get_peak_usage(true),
                'test_timestamp' => date('Y-m-d H:i:s'),
                'php_version' => PHP_VERSION,
                'test_mode_verified' => true
            ],
            'detailed_results' => $this->testResults
        ];

        $totalTests = 0;
        $passedTests = 0;

        foreach ($this->testResults as $category => $results) {
            if (isset($results['passed_tests']) && isset($results['total_tests'])) {
                $totalTests += $results['total_tests'];
                $passedTests += $results['passed_tests'];
            }
        }

        $report['test_summary']['total_tests'] = $totalTests;
        $report['test_summary']['passed_tests'] = $passedTests;
        $report['test_summary']['success_rate'] = $totalTests > 0 ? ($passedTests / $totalTests) * 100 : 0;

        $this->printReport($report);

        return $report;
    }

    private function printReport(array $report): void {
        echo "\n" . str_repeat("=", 60) . "\n";
        echo "HACK DETECTION SERVICE TEST REPORT\n";
        echo str_repeat("=", 60) . "\n";

        $summary = $report['test_summary'];
        
        printf("Execution Time: %.3f seconds\n", $summary['total_execution_time']);
        printf("Memory Usage: %.2f MB\n", $summary['memory_peak_usage'] / 1024 / 1024);
        printf("PHP Version: %s\n", $summary['php_version']);
        printf("Total Tests: %d\n", $summary['total_tests']);
        printf("Passed Tests: %d\n", $summary['passed_tests']);
        printf("Success Rate: %.1f%%\n", $summary['success_rate']);

        echo "\nDETAILED RESULTS:\n";
        echo str_repeat("-", 40) . "\n";

        foreach ($report['detailed_results'] as $category => $results) {
            $categoryName = str_replace('_', ' ', ucfirst($category));
            printf("%-25s: ", $categoryName);

            if (isset($results['passed_tests']) && isset($results['total_tests'])) {
                printf("%d/%d passed\n", $results['passed_tests'], $results['total_tests']);
            } else {
                echo "Completed\n";
            }
        }

        echo str_repeat("=", 60) . "\n";

        if ($summary['success_rate'] < 90) {
            echo "RECOMMENDATIONS:\n";
            echo "- Review failed test cases\n";
            echo "- Check pattern validation results\n";
            echo "- Verify detection thresholds\n";
        } else {
            echo "✓ All tests completed successfully. System is ready for production.\n";
        }
    }

    public function runSpecificTest(string $testCategory): array {
        switch ($testCategory) {
            case 'patterns':
                $this->testPatternValidation();
                break;
            case 'vectors':
                $this->testDetectionVectors();
                break;
            case 'protocols':
                $this->testProtocolInjectionSpecific();
                break;
            case 'ssrf':
                $this->testSSRFSpecific();
                break;
            case 'cloud':
                $this->testCloudMetadataDetection();
                break;
            case 'falsepositives':
                $this->testFalsePositives();
                break;
            case 'performance':
                $this->testPerformance();
                break;
            case 'security':
                $this->testSecurity();
                break;
            default:
                throw new InvalidArgumentException("Unknown test category: $testCategory");
        }

        return $this->testResults[$testCategory . '_tests'] ?? [];
    }

    public function cleanup(): void {
        $_GET = $_POST = $_COOKIE = $_FILES = [];
        $_SERVER = array_filter($_SERVER, fn($key) => !str_starts_with($key, 'HTTP_X_SECURITY'), ARRAY_FILTER_USE_KEY);
        $this->testResults = [];
    }
}

// Command line interface
if (php_sapi_name() === 'cli' && basename(__FILE__) === basename($_SERVER['argv'][0] ?? '')) {
    $tester = new HackDetectionTester();
    
    $options = getopt('', ['category:', 'help']);
    
    if (isset($options['help'])) {
        echo "Hack Detection Service Tester\n";
        echo "Usage: php HackDetectionTester.php [--category=name]\n";
        echo "Categories: patterns, vectors, protocols, ssrf, cloud, falsepositives, performance, security\n";
        exit(0);
    }
    
    if (isset($options['category'])) {
        $result = $tester->runSpecificTest($options['category']);
    } else {
        $result = $tester->runAllTests();
    }
    
    $tester->cleanup();
    exit($result['test_summary']['success_rate'] >= 90 ? 0 : 1);
}