<?php
defined('ABSPATH') || exit;

/**
 * WPFort Advanced Firewall
 * 
 * This file contains functions for implementing a firewall based on advanced definitions,
 * allowing real-time protection against potential attacks.
 */

/**
 * Initialize the WPFort advanced firewall
 * 
 * This function loads firewall definitions and applies them to incoming requests.
 * It should be called very early in the WordPress lifecycle.
 */
function wpsec_initialize_firewall() {
    // Skip for admin users
    if (current_user_can('manage_options')) {
        return;
    }
    
    // Skip during plugin scan operations
    if (isset($_REQUEST['wpsec_api_key']) || (isset($_SERVER['REQUEST_URI']) && strpos($_SERVER['REQUEST_URI'], '/wpsec/v1/') !== false)) {
        return;
    }
    
    // Load advanced definitions
    if (!function_exists('wpsec_load_advanced_definitions')) {
        require_once dirname(__FILE__) . '/advanced.php';
    }
    
    $definitions = wpsec_load_advanced_definitions();
    
    if (!$definitions || !isset($definitions['firewall']) || empty($definitions['firewall'])) {
        return;
    }
    
    // Trigger tracking hook for firewall usage (if tracking is enabled)
    do_action('wpsec_firewall_check');
    
    // Process firewall rules
    wpsec_apply_firewall_rules($definitions['firewall']);
}

/**
 * Apply firewall rules to the current request
 * 
 * @param array $firewall_rules The firewall rules from advanced definitions
 */
function wpsec_apply_firewall_rules($firewall_rules) {
    foreach ($firewall_rules as $rule_id => $rule_data) {
        // Extract rule details
        $name = isset($rule_data[1]) ? $rule_data[1] : 'Unnamed Rule';
        $description = isset($rule_data[2]) ? $rule_data[2] : '';
        
        // Skip incomplete rules
        if (count($rule_data) < 5) {
            continue;
        }
        
        $target = $rule_data[3]; // SERVER, REQUEST, FILES, etc.
        $pattern = $rule_data[4];
        
        // Skip rules with invalid patterns
        if (!$pattern || !is_string($pattern) || empty($pattern)) {
            continue;
        }
        
        // Check based on target type
        switch ($target) {
            case 'SERVER':
                // Process the second condition if present
                if (isset($rule_data[5]) && isset($rule_data[6])) {
                    $server_var = $rule_data[5];
                    $check_pattern = $rule_data[6];
                    
                    // Only apply the rule if the server variable exists and matches the pattern
                    if (isset($_SERVER[$server_var]) && 
                        @preg_match($check_pattern, $_SERVER[$server_var]) &&
                        isset($_REQUEST) && 
                        @preg_match($pattern, json_encode($_REQUEST))) {
                        
                        wpsec_block_request($rule_id, $name, $description);
                    }
                }
                break;
                
            case 'REQUEST':
                // Check for pattern in the request data
                if (isset($_REQUEST) && @preg_match($pattern, json_encode($_REQUEST))) {
                    wpsec_block_request($rule_id, $name, $description);
                }
                break;
                
            case 'FILES':
                // Check for pattern in uploaded files
                if (!empty($_FILES) && @preg_match($pattern, json_encode($_FILES))) {
                    wpsec_block_request($rule_id, $name, $description);
                }
                break;
                
            case 'HEADERS':
                // Check for pattern in request headers
                $headers = getallheaders();
                if ($headers && @preg_match($pattern, json_encode($headers))) {
                    wpsec_block_request($rule_id, $name, $description);
                }
                break;
                
            case 'URI':
                // Check for pattern in request URI
                if (isset($_SERVER['REQUEST_URI']) && @preg_match($pattern, $_SERVER['REQUEST_URI'])) {
                    wpsec_block_request($rule_id, $name, $description);
                }
                break;
                
            case 'METHOD':
                // Check for pattern in request method
                if (isset($_SERVER['REQUEST_METHOD']) && @preg_match($pattern, $_SERVER['REQUEST_METHOD'])) {
                    wpsec_block_request($rule_id, $name, $description);
                }
                break;
        }
    }
}

/**
 * Block a request that has triggered a firewall rule
 * 
 * @param string $rule_id The ID of the rule that was triggered
 * @param string $name The name of the rule
 * @param string $description The description of the rule
 */
function wpsec_block_request($rule_id, $name, $description) {
    // Log the blocked request (only in verbose mode to reduce log noise)
    if (defined('WPSEC_VERBOSE_LOGGING') && WPSEC_VERBOSE_LOGGING) {
        wpsec_debug_log(sprintf(
            '🛡️ WPFort Firewall: Blocked request - Rule: %s (%s), IP: %s, URI: %s, Method: %s',
            $name,
            $rule_id,
            isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : 'unknown',
            isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : 'unknown',
            isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'unknown'
        ), 'info');
    }
    
    // Record the block in the database
    $block_data = [
        'time' => time(),
        'ip' => isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : 'unknown',
        'uri' => isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : 'unknown',
        'method' => isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'unknown',
        'rule_id' => $rule_id,
        'rule_name' => $name
    ];
    
    // Store the last 100 blocks
    $recent_blocks = get_option('wpsec_recent_firewall_blocks', []);
    array_unshift($recent_blocks, $block_data);
    $recent_blocks = array_slice($recent_blocks, 0, 100);
    update_option('wpsec_recent_firewall_blocks', $recent_blocks);
    
    // Increment block counter
    $block_count = get_option('wpsec_firewall_block_count', 0);
    update_option('wpsec_firewall_block_count', $block_count + 1);
    
    // Output block message and exit
    $site_url = get_home_url();
    http_response_code(403);
    header('Content-Type: text/html; charset=utf-8');
    echo '<!DOCTYPE html>
    <html>
    <head>
        <title>Security Violation Detected</title>
        <style>
            body { font-family: Arial, sans-serif; line-height: 1.6; margin: 0; padding: 20px; color: #333; }
            .container { max-width: 800px; margin: 0 auto; background: #f9f9f9; padding: 20px; border-radius: 5px; border: 1px solid #ddd; }
            h1 { color: #d9534f; }
            .footer { margin-top: 30px; font-size: 12px; color: #777; text-align: center; }
        </style>
    </head>
    <body>
        <div class="container">
            <h1>Security Violation Detected</h1>
            <p>The requested action has been blocked by WPFort Security.</p>
            <p>If you believe this is an error, please contact the site administrator.</p>
            <p>Reference ID: ' . esc_html($rule_id) . '</p>
            <div class="footer">
                Protected by WPFort Security | <a href="' . esc_url($site_url) . '">Return to Homepage</a>
            </div>
        </div>
    </body>
    </html>';
    exit;
}

// Initialize the firewall early
add_action('plugins_loaded', 'wpsec_initialize_firewall', 1); // Priority 1 to run early
