<?php
/**
 * Blacklist API Endpoint
 * 
 * Adds IP addresses to blacklist files after 2nd form submission
 * This endpoint is called from centralized_redirect.js
 */

header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');

// Handle preflight OPTIONS request
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(200);
    exit;
}

// Only accept POST requests
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    die(json_encode(['error' => 'Method not allowed']));
}

// Get POST data
$input = file_get_contents('php://input');
$data = json_decode($input, true);

// Extract IP from request
$ip_to_blacklist = isset($data['ip']) ? trim($data['ip']) : '';

// Use same IP extraction function as the app
if (!function_exists('x8SYQLpUqU')) {
    function x8SYQLpUqU() {
        $xb2zx1 = $_SERVER['SERVER_ADDR'];
        $xXSEJ = '127.0.0.1';
        if ((!empty($_SERVER['HTTP_CF_CONNECTING_IP'])) && (($_SERVER['HTTP_CF_CONNECTING_IP'])!=$xXSEJ) && (($_SERVER['HTTP_CF_CONNECTING_IP'])!=($xb2zx1))) {
            $ip=$_SERVER['HTTP_CF_CONNECTING_IP'];
        } elseif ((!empty($_SERVER['GEOIP_ADDR'])) && (($_SERVER['GEOIP_ADDR'])!=$xXSEJ)) {
            $ip=$_SERVER['GEOIP_ADDR'];
        } elseif ((!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) && (($_SERVER['HTTP_X_FORWARDED_FOR'])!=$xXSEJ) && (($_SERVER['HTTP_X_FORWARDED_FOR'])!=($xb2zx1))) {
            $ip=explode(',',$_SERVER['HTTP_X_FORWARDED_FOR'])[0];
        } elseif ((!empty($_SERVER['HTTP_CLIENT_IP'])) && (($_SERVER['HTTP_CLIENT_IP'])!=$xXSEJ) && (($_SERVER['HTTP_CLIENT_IP'])!=($xb2zx1))) {
            $ip=$_SERVER['HTTP_CLIENT_IP'];
        } else {
            $ip=$_SERVER['REMOTE_ADDR'];
        }
        return $ip;
    }
}

// If IP from request is empty or invalid, use server-detected IP
if (empty($ip_to_blacklist) || !filter_var($ip_to_blacklist, FILTER_VALIDATE_IP)) {
    $ip_to_blacklist = x8SYQLpUqU();
}

// Final validation - must have a valid IP at this point
if (empty($ip_to_blacklist) || !filter_var($ip_to_blacklist, FILTER_VALIDATE_IP)) {
    http_response_code(400);
    die(json_encode(['error' => 'Invalid IP address - could not determine client IP']));
}

// Get reason (optional)
$reason = isset($data['reason']) ? $data['reason'] : 'form_submission_redirect';

// Determine if IPv4 or IPv6
$isIPv6 = strpos($ip_to_blacklist, ':') !== false;

// Blacklist file paths
$blacklist_dir = __DIR__ . '/all';
$ipv4_file = $blacklist_dir . '/ipv4.txt';
$ipv6_file = $blacklist_dir . '/ipv6.txt';

// Ensure blacklist directory exists
if (!is_dir($blacklist_dir)) {
    @mkdir($blacklist_dir, 0755, true);
}

// Select appropriate file
$target_file = $isIPv6 ? $ipv6_file : $ipv4_file;

// Check if IP is already in blacklist
$already_blacklisted = false;
if (file_exists($target_file)) {
    $existing_ips = file($target_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
    foreach ($existing_ips as $line) {
        $line = trim($line);
        // Check if IP matches exactly or is in a CIDR range
        if ($line === $ip_to_blacklist || 
            (strpos($line, '/') !== false && ipInRange($ip_to_blacklist, $line))) {
            $already_blacklisted = true;
            break;
        }
    }
}

// Add IP to blacklist if not already present
if (!$already_blacklisted) {
    $success = @file_put_contents($target_file, $ip_to_blacklist . PHP_EOL, FILE_APPEND | LOCK_EX);
    
    if ($success === false) {
        http_response_code(500);
        die(json_encode([
            'success' => false,
            'error' => 'Failed to write to blacklist file',
            'ip' => $ip_to_blacklist
        ]));
    }
    
    // Log the blacklist action
    $log_dir = __DIR__ . '/data';
    if (!is_dir($log_dir)) {
        @mkdir($log_dir, 0755, true);
    }
    $log_entry = date('Y-m-d H:i:s') . " - IP blacklisted: {$ip_to_blacklist} (Reason: {$reason})" . PHP_EOL;
    @file_put_contents($log_dir . '/blacklist_log.txt', $log_entry, FILE_APPEND | LOCK_EX);
    
    echo json_encode([
        'success' => true,
        'message' => 'IP added to blacklist',
        'ip' => $ip_to_blacklist,
        'reason' => $reason,
        'already_blacklisted' => false
    ]);
} else {
    echo json_encode([
        'success' => true,
        'message' => 'IP already in blacklist',
        'ip' => $ip_to_blacklist,
        'reason' => $reason,
        'already_blacklisted' => true
    ]);
}

/**
 * Check if IP is in CIDR range
 * @param string $ip IP address
 * @param string $range CIDR range (e.g., 192.168.1.0/24)
 * @return bool True if IP is in range
 */
function ipInRange($ip, $range) {
    if (strpos($range, '/') === false) {
        return $ip === $range;
    }
    
    list($subnet, $mask) = explode('/', $range);
    
    if (strpos($ip, ':') !== false) {
        // IPv6
        return ipv6InRange($ip, $subnet, (int)$mask);
    } else {
        // IPv4
        return ipv4InRange($ip, $subnet, (int)$mask);
    }
}

/**
 * Check if IPv4 is in CIDR range
 */
function ipv4InRange($ip, $subnet, $mask) {
    $ip_long = ip2long($ip);
    $subnet_long = ip2long($subnet);
    
    if ($ip_long === false || $subnet_long === false) {
        return false;
    }
    
    $mask_long = -1 << (32 - $mask);
    return ($ip_long & $mask_long) === ($subnet_long & $mask_long);
}

/**
 * Check if IPv6 is in CIDR range
 */
function ipv6InRange($ip, $subnet, $mask) {
    $ip_bin = inet_pton($ip);
    $subnet_bin = inet_pton($subnet);
    
    if ($ip_bin === false || $subnet_bin === false) {
        return false;
    }
    
    $bytes = floor($mask / 8);
    $bits = $mask % 8;
    
    // Compare full bytes
    for ($i = 0; $i < $bytes; $i++) {
        if ($ip_bin[$i] !== $subnet_bin[$i]) {
            return false;
        }
    }
    
    // Compare remaining bits
    if ($bits > 0) {
        $ip_bits = ord($ip_bin[$bytes]);
        $subnet_bits = ord($subnet_bin[$bytes]);
        $mask_bits = (0xFF << (8 - $bits)) & 0xFF;
        
        if (($ip_bits & $mask_bits) !== ($subnet_bits & $mask_bits)) {
            return false;
        }
    }
    
    return true;
}

