<?php
/**
 * CQtrBruteForcePolicy — Configurable protection policies for different hosting environments
 *
 * WHAT IT DOES
 *  - Centralized policy management for brute-force protection
 *  - Support for two hosting environments:
 *      1) SHARED HOSTING: Limited worker processes (5-10), must avoid blocking workers
 *      2) DEDICATED SERVER: Many worker processes, can afford short delays
 *  - Hosting type is provided by caller (CQtrBruteForce) via QutteraSettings
 *
 * POLICIES
 *  - Shared Hosting:   Aggressive locking, minimal delays, low failure thresholds
 *  - Dedicated Server: Progressive delays, higher failure thresholds, forgiving approach
 *
 * USAGE
 *  $hosting_type = $settings->GetHostingType();  // QutteraSettings::SHARED_HOSTING or DEDICATED_SERVER
 *  $policy = CQtrBruteForcePolicy::GetPolicy($hosting_type);
 *  $delay_threshold = $policy['delay_threshold'];
 */

if (!defined('ABSPATH')) exit;

require_once('qtrSettings.php');

final class CQtrBruteForcePolicy
{

    /**
     * GetPolicy()
     * -----------
     * Returns the appropriate policy array based on hosting type.
     *
     * @param string $hosting_type Hosting type from QutteraSettings (e.g., QutteraSettings::SHARED_HOSTING)
     * @return array<string,mixed> Policy configuration
     */
    public static function GetPolicy(string $hosting_type): array
    {
        if ($hosting_type === QutteraSettings::SHARED_HOSTING) {
            return self::GetSharedHostingPolicy();
        }

        return self::GetDedicatedServerPolicy();
    }


    /**
     * GetSharedHostingPolicy()
     * -----------------------
     * Policy optimized for shared hosting with limited worker processes.
     *
     * Design philosophy:
     *  - AVOID sleeping/delays (they block precious worker processes)
     *  - Lock FAST after minimal failures
     *  - Fail-fast with HTTP 403 (no sleep before checking locks)
     *  - Short lock durations (unlock email helps legitimate users)
     *
     * Thresholds:
     *  - Delays disabled (threshold set very high to skip)
     *  - Soft lock at 2 failures (vs 5 on dedicated)
     *  - Hard lock at 5 failures (vs 10 on dedicated)
     *  - Spam detection at 5 distinct users (vs 10 on dedicated)
     *
     * @return array<string,mixed>
     */
    private static function GetSharedHostingPolicy(): array
    {
        return [
            // Rolling windows / TTLs
            'ttl_10m' => 10 * MINUTE_IN_SECONDS,
            'ttl_1h'  => HOUR_IN_SECONDS,
            'ttl_24h' => DAY_IN_SECONDS,

            // Progressive delay
            // DISABLED: Set threshold very high so delays are skipped
            // This prevents blocking limited worker processes
            'delay_threshold'   => 999,  // Never triggers (before soft lock anyway)
            'delay_cap_seconds' => 0,    // No sleep

            // Lock thresholds (based mainly on failures in last 10 minutes)
            // Much lower thresholds to lock fast
            'soft_threshold_10m' => 4,   // Lock after 4 failures vs 5 (dedicated)
            'hard_threshold_10m' => 6,   // Lock after 6 failures vs 10 (dedicated)

            // Spray attack detection (many usernames from a single IP)
            // More sensitive to detect distributed attacks
            'spray_distinct_users_10m' => 5,   // vs 10 (dedicated)
            'spray_total_fails_10m'    => 10,  // vs 20 (dedicated)

            // Lock durations
            // Shorter to minimize false positives hurting legitimate users
            'soft_lock' => 5 * MINUTE_IN_SECONDS,    // 5 min vs 10 (dedicated)
            'hard_lock' => 30 * MINUTE_IN_SECONDS,   // 30 min vs 1 hour (dedicated)
            'day_lock'  => 4 * HOUR_IN_SECONDS,      // 4 hours vs 24 (dedicated)

            // Escalation: repeat hard lock within 24h => day lock
            'repeat_hard_within' => DAY_IN_SECONDS,

            // Unlock email behavior
            'send_unlock_email' => true,
            'unlock_token_ttl'  => 10 * MINUTE_IN_SECONDS,

            // Hosting type identifier for logging
            'hosting_type' => QutteraSettings::SHARED_HOSTING,
        ];
    }

    /**
     * GetDedicatedServerPolicy()
     * --------------------------
     * Policy optimized for dedicated servers with many worker processes.
     *
     * Design philosophy:
     *  - Progressive delays throttle bots before locks activate
     *  - Exponential backoff: 2^(n-3) seconds (1s, 2s, 4s, 8s, 12s)
     *  - Higher failure thresholds (fewer false positives)
     *  - Longer lock durations (attacker can't bypass by retrying next day)
     *
     * Thresholds:
     *  - Delays enabled with threshold=3
     *  - Soft lock at 5 failures
     *  - Hard lock at 10 failures
     *  - Spam detection at 10 distinct users
     *
     * @return array<string,mixed>
     */
    private static function GetDedicatedServerPolicy(): array
    {
        return [
            // Rolling windows / TTLs
            'ttl_10m' => 10 * MINUTE_IN_SECONDS,
            'ttl_1h'  => HOUR_IN_SECONDS,
            'ttl_24h' => DAY_IN_SECONDS,

            // Progressive delay
            // Enabled: Exponential backoff throttles bots before hard locks
            // Progression: fails10m 3,4,5,6,7 => delay 1s, 2s, 4s, 8s, 12s
            'delay_threshold'   => 3,
            'delay_cap_seconds' => 12,

            // Lock thresholds (based mainly on failures in last 10 minutes)
            'soft_threshold_10m' => 5,   // triggers ~5m lock
            'hard_threshold_10m' => 10,  // triggers ~1h lock

            // Spray attack detection (many usernames from a single IP)
            'spray_distinct_users_10m' => 10,
            'spray_total_fails_10m'    => 20,

            // Lock durations
            'soft_lock' => 10 * MINUTE_IN_SECONDS,
            'hard_lock' => HOUR_IN_SECONDS,
            'day_lock'  => DAY_IN_SECONDS,

            // Escalation: repeat hard lock within 24h => day lock
            'repeat_hard_within' => DAY_IN_SECONDS,

            // Unlock email behavior
            'send_unlock_email' => true,
            'unlock_token_ttl'  => 10 * MINUTE_IN_SECONDS,

            // Hosting type identifier for logging
            'hosting_type' => QutteraSettings::DEDICATED_SERVER,
        ];
    }

    /**
     * GetPolicyDescription()
     * ---------------------
     * Returns a human-readable description of the current policy.
     *
     * @return string Description including hosting type and key thresholds
     */
    public static function GetPolicyDescription(string $hosting_type): string
    {
        $policy = self::GetPolicy($hosting_type);
        $hosting = $policy['hosting_type'];

        if ($hosting === QutteraSettings::SHARED_HOSTING) {
            return sprintf(
                'Shared Hosting Policy: '
              . 'Soft lock after %d failures (%d min), '
              . 'Hard lock after %d failures (%d min), '
              . 'Delays DISABLED to preserve worker processes',
                $policy['soft_threshold_10m'],
                $policy['soft_lock'] / MINUTE_IN_SECONDS,
                $policy['hard_threshold_10m'],
                $policy['hard_lock'] / MINUTE_IN_SECONDS
            );
        }

        return sprintf(
            'Dedicated Server Policy: '
          . 'Soft lock after %d failures (%d min), '
          . 'Hard lock after %d failures (%d hour), '
          . 'Progressive delays enabled (1-12s exponential backoff)',
            $policy['soft_threshold_10m'],
            $policy['soft_lock'] / MINUTE_IN_SECONDS,
            $policy['hard_threshold_10m'],
            $policy['hard_lock'] / HOUR_IN_SECONDS
        );
    }
}
