<?php
// File: includes/security.php
// Utilitas keamanan: CSRF token, session hardening, rate limiting

// ================================================================
// SESSION HARDENING
// ================================================================

/**
 * Inisialisasi session yang aman.
 * Panggil ini SEBELUM session_start() di setiap file admin.
 */
function secureSessionStart() {
    if (session_status() === PHP_SESSION_NONE) {
        session_set_cookie_params([
            'lifetime' => 0,
            'path'     => '/',
            'secure'   => isset($_SERVER['HTTPS']),
            'httponly' => true,
            'samesite' => 'Strict',
        ]);
        session_start();
    }
}

/**
 * Regenerate session ID setelah login berhasil.
 * Mencegah session fixation attack.
 */
function regenerateSession($userId, $username) {
    session_regenerate_id(true);
    $_SESSION['admin_id']   = $userId;
    $_SESSION['admin_user'] = $username;
    $_SESSION['login_time'] = time();
    $_SESSION['ip']         = $_SERVER['REMOTE_ADDR'] ?? '';
    $_SESSION['ua']         = substr($_SERVER['HTTP_USER_AGENT'] ?? '', 0, 200);
}

/**
 * Validasi session masih valid (IP & UA tidak berubah drastis).
 * Panggil di setiap halaman admin yang membutuhkan autentikasi.
 */
function validateAdminSession() {
    if (!isset($_SESSION['admin_id'])) return false;
    // Cek session timeout 8 jam
    if (isset($_SESSION['login_time']) && (time() - $_SESSION['login_time']) > 28800) {
        session_destroy();
        return false;
    }
    // Refresh timer setiap request
    $_SESSION['login_time'] = time();
    return true;
}

// ================================================================
// CSRF PROTECTION
// ================================================================

/**
 * Generate CSRF token baru jika belum ada.
 * Simpan di session.
 */
function csrfToken() {
    if (empty($_SESSION['csrf_token'])) {
        $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
    }
    return $_SESSION['csrf_token'];
}

/**
 * Render hidden input CSRF untuk form.
 * Pakai: <?= csrfInput() ?>
 */
function csrfInput() {
    return '<input type="hidden" name="csrf_token" value="' . htmlspecialchars(csrfToken()) . '">';
}

/**
 * Verifikasi CSRF token dari POST request.
 * Lempar exception jika gagal.
 */
function verifyCsrf() {
    $tokenPost    = $_POST['csrf_token']    ?? '';
    $tokenSession = $_SESSION['csrf_token'] ?? '';
    if (empty($tokenPost) || !hash_equals($tokenSession, $tokenPost)) {
        http_response_code(403);
        die('<div style="font-family:sans-serif;padding:40px;text-align:center"><h2>403 — Permintaan Tidak Valid</h2><p>Token keamanan tidak cocok. Silakan muat ulang halaman.</p><a href="javascript:history.back()" style="color:#2563eb">← Kembali</a></div>');
    }
    // Rotate token setelah dipakai (opsional, uncomment untuk paranoid mode)
    // $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}

// ================================================================
// RATE LIMITING (File-based, tanpa Redis/Memcached)
// ================================================================

/**
 * Cek apakah IP tertentu melebihi batas request.
 * @param string $action   Nama aksi, contoh: 'track_lead', 'login'
 * @param int    $limit    Maks request per window
 * @param int    $window   Window waktu dalam detik
 * @return bool  true = masih dalam batas, false = kena limit
 */
function checkRateLimit($action, $limit = 30, $window = 60) {
    $cacheDir = __DIR__ . '/../cache/';
    if (!file_exists($cacheDir)) @mkdir($cacheDir, 0755, true);

    $ip   = preg_replace('/[^0-9a-f:.]/', '', $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0');
    $key  = 'rl_' . md5($action . '_' . $ip);
    $file = $cacheDir . $key . '.json';

    $now  = time();
    $data = ['count' => 0, 'start' => $now];

    if (file_exists($file)) {
        $raw = @file_get_contents($file);
        if ($raw) $data = json_decode($raw, true) ?? $data;
    }

    // Reset window jika sudah lewat
    if (($now - $data['start']) >= $window) {
        $data = ['count' => 0, 'start' => $now];
    }

    $data['count']++;
    @file_put_contents($file, json_encode($data), LOCK_EX);

    return $data['count'] <= $limit;
}

// ================================================================
// INPUT SANITIZATION HELPERS
// ================================================================

/**
 * Sanitasi string input — strip tags + trim + encode khusus
 */
function sanitizeInput($val, $maxLen = 255) {
    return htmlspecialchars(trim(strip_tags(substr($val, 0, $maxLen))), ENT_QUOTES, 'UTF-8');
}

/**
 * Sanitasi integer input
 */
function sanitizeInt($val, $min = 0, $max = PHP_INT_MAX) {
    $v = intval($val);
    return max($min, min($max, $v));
}
?>
