<?php
// admin/security.php
// Central hardening layer: safe headers, hardened sessions, CSRF helpers, login rate-limit.

require_once __DIR__ . '/app_assets.php';
require_once __DIR__ . '/app_runtime.php';

if (!function_exists('ua_is_https')) {
  function ua_is_https(): bool {
    if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') return true;
    if (!empty($_SERVER['SERVER_PORT']) && (int)$_SERVER['SERVER_PORT'] === 443) return true;
    if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && strtolower((string)$_SERVER['HTTP_X_FORWARDED_PROTO']) === 'https') return true;
    return false;
  }
}

if (!function_exists('ua_security_headers')) {
  function ua_security_headers(): void {
    if (PHP_SAPI === 'cli' || headers_sent()) return;
    header('X-Content-Type-Options: nosniff');
    header('Referrer-Policy: same-origin');
    header('X-Frame-Options: SAMEORIGIN');
    $styleOrigins = function_exists('ua_asset_external_origins') ? implode(' ', ua_asset_external_origins('css')) : '';
    $scriptOrigins = function_exists('ua_asset_external_origins') ? implode(' ', ua_asset_external_origins('js')) : '';
    $fontOrigins = $styleOrigins;
    $csp = "default-src 'self'; " .
           "img-src 'self' data:; " .
           "media-src 'self' data: blob:; " .
           "style-src 'self' 'unsafe-inline'" . ($styleOrigins !== '' ? ' ' . $styleOrigins : '') . "; " .
           "script-src 'self' 'unsafe-inline'" . ($scriptOrigins !== '' ? ' ' . $scriptOrigins : '') . "; " .
           "font-src 'self' data:" . ($fontOrigins !== '' ? ' ' . $fontOrigins : '') . "; " .
           "connect-src 'self' http://*:9123 https://*:9123; " .
           "frame-ancestors 'self';";
    header('Content-Security-Policy: ' . $csp);
  }
}

if (!function_exists('ua_session_start')) {
  function ua_session_start(): void {
    if (session_status() === PHP_SESSION_ACTIVE) return;

    @ini_set('session.use_strict_mode', '1');
    @ini_set('session.use_only_cookies', '1');
    @ini_set('session.cookie_httponly', '1');
    @ini_set('session.cookie_samesite', 'Lax');
    if (ua_is_https()) @ini_set('session.cookie_secure', '1');

    @session_start();

    $idlePolicy = function_exists('ua_idle_timeout_policy')
      ? ua_idle_timeout_policy()
      : ['enabled' => false, 'seconds' => 1800];
    $timeout = max(300, (int)($idlePolicy['seconds'] ?? 1800));

    $now = time();
    $last = (int)($_SESSION['ua_last_activity'] ?? 0);
    if (!empty($idlePolicy['enabled']) && $last > 0 && ($now - $last) > $timeout) {
      $_SESSION = [];
      if (ini_get('session.use_cookies')) {
        $params = session_get_cookie_params();
        setcookie(session_name(), '', time() - 42000, $params['path'] ?? '/', $params['domain'] ?? '', (bool)($params['secure'] ?? false), (bool)($params['httponly'] ?? true));
      }
      @session_destroy();
      @session_start();
      $_SESSION['ua_login_err'] = 'انتهت الجلسة بسبب عدم النشاط. الرجاء تسجيل الدخول من جديد.';
      if (PHP_SAPI !== 'cli' && !headers_sent()) {
        header('Location: index.php?login=1');
        exit;
      }
    }
    if (!empty($idlePolicy['enabled'])) {
      $_SESSION['ua_last_activity'] = $now;
    } else {
      unset($_SESSION['ua_last_activity']);
    }

    $regenEvery = 900;
    $lastRegen = (int)($_SESSION['ua_last_regen'] ?? 0);
    if ($lastRegen === 0) {
      $_SESSION['ua_last_regen'] = $now;
    } elseif (($now - $lastRegen) > $regenEvery) {
      // Keep the previous id valid until PHP's normal garbage collection. A
      // dashboard issues concurrent polling requests; deleting the old session
      // here made an in-flight request appear logged out at random.
      @session_regenerate_id(false);
      $_SESSION['ua_last_regen'] = $now;
    }
  }
}

if (!function_exists('ua_csrf_token')) {
  function ua_csrf_token(): string {
    ua_session_start();
    if (empty($_SESSION['ua_csrf'])) {
      $_SESSION['ua_csrf'] = bin2hex(random_bytes(32));
    }
    return (string)$_SESSION['ua_csrf'];
  }
}

if (!function_exists('ua_csrf_field')) {
  function ua_csrf_field(): void {
    echo '<input type="hidden" name="ua_csrf" value="' . htmlspecialchars(ua_csrf_token(), ENT_QUOTES, 'UTF-8') . '">';
  }
}

if (!function_exists('ua_csrf_verify')) {
  function ua_csrf_verify(): bool {
    ua_session_start();
    $sent = (string)($_POST['ua_csrf'] ?? ($_SERVER['HTTP_X_UA_CSRF'] ?? ''));
    $real = (string)($_SESSION['ua_csrf'] ?? '');
    return $sent !== '' && $real !== '' && hash_equals($real, $sent);
  }
}

if (!function_exists('ua_login_rate_limit_fail')) {
  function ua_login_rate_limit_fail(): void {
    ua_session_start();
    $ip = (string)($_SERVER['REMOTE_ADDR'] ?? '0.0.0.0');
    $key = 'ua_login_fail_' . preg_replace('/[^0-9a-f:\\.]/i', '_', $ip);
    $_SESSION[$key] = (int)($_SESSION[$key] ?? 0) + 1;
    $_SESSION['ua_login_last_fail'] = time();
  }
}

if (!function_exists('ua_login_rate_limit_ok')) {
  function ua_login_rate_limit_ok(): void {
    ua_session_start();
    $ip = (string)($_SERVER['REMOTE_ADDR'] ?? '0.0.0.0');
    $key = 'ua_login_fail_' . preg_replace('/[^0-9a-f:\\.]/i', '_', $ip);
    unset($_SESSION[$key], $_SESSION['ua_login_last_fail']);
  }
}

if (!function_exists('ua_login_rate_limited')) {
  function ua_login_rate_limited(): bool {
    ua_session_start();
    $ip = (string)($_SERVER['REMOTE_ADDR'] ?? '0.0.0.0');
    $key = 'ua_login_fail_' . preg_replace('/[^0-9a-f:\\.]/i', '_', $ip);
    $fails = (int)($_SESSION[$key] ?? 0);
    $last  = (int)($_SESSION['ua_login_last_fail'] ?? 0);
    if ($fails >= 6 && $last > 0 && (time() - $last) < 300) return true;
    if ($fails >= 6 && $last > 0 && (time() - $last) >= 300) unset($_SESSION[$key], $_SESSION['ua_login_last_fail']);
    return false;
  }
}

ua_security_headers();
ua_session_start();
