<?php
if (!defined('_GNUBOARD_')) exit;

if (!defined('LOGIN_GUARD_FAIL_LIMIT')) {
    define('LOGIN_GUARD_FAIL_LIMIT', 5);
}
if (!defined('LOGIN_GUARD_LOCK_SECONDS')) {
    define('LOGIN_GUARD_LOCK_SECONDS', 1800); // 30분
}

function login_guard_state_file_path()
{
    $ip = get_real_client_ip();
    if (!$ip) {
        $ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : 'unknown';
    }

    // 공유 IP 환경(NAT/프록시)에서 사용자 간 잠금 상태가 전파되지 않도록
    // IP + 세션 단위로 키를 구성한다.
    $session_id = '';
    if (function_exists('session_id')) {
        $session_id = (string)session_id();
    }

    if ($session_id === '') {
        $session_id = isset($_SERVER['HTTP_USER_AGENT']) ? (string)$_SERVER['HTTP_USER_AGENT'] : 'no-session';
    }

    $key = sha1('login_guard|' . $ip . '|' . $session_id);
    return G5_DATA_PATH . '/cache/login_guard_' . $key . '.json';
}

function login_guard_default_state()
{
    return array(
        'fail_count' => 0,
        'lock_until' => 0,
        'updated_at' => 0,
    );
}

function login_guard_get_state()
{
    $state = login_guard_default_state();
    $file = login_guard_state_file_path();

    if (is_file($file)) {
        $raw = @file_get_contents($file);
        if ($raw !== false) {
            $decoded = json_decode($raw, true);
            if (is_array($decoded)) {
                $state['fail_count'] = (int)(isset($decoded['fail_count']) ? $decoded['fail_count'] : 0);
                $state['lock_until'] = (int)(isset($decoded['lock_until']) ? $decoded['lock_until'] : 0);
                $state['updated_at'] = (int)(isset($decoded['updated_at']) ? $decoded['updated_at'] : 0);
            }
        }
    }

    return login_guard_normalize_state($state);
}

function login_guard_save_state($state)
{
    $state = login_guard_normalize_state($state);
    $state['updated_at'] = time();

    $file = login_guard_state_file_path();
    $dir = dirname($file);
    if (!is_dir($dir)) {
        @mkdir($dir, 0777, true);
    }

    @file_put_contents($file, json_encode($state, JSON_UNESCAPED_UNICODE), LOCK_EX);
    return $state;
}

function login_guard_normalize_state($state)
{
    $state = is_array($state) ? $state : array();
    $now = time();

    $fail_count = (int)(isset($state['fail_count']) ? $state['fail_count'] : 0);
    $lock_until = (int)(isset($state['lock_until']) ? $state['lock_until'] : 0);

    if ($lock_until > 0 && $now >= $lock_until) {
        $fail_count = 0;
        $lock_until = 0;
    }

    if ($fail_count < 0) {
        $fail_count = 0;
    }

    return array(
        'fail_count' => $fail_count,
        'lock_until' => $lock_until,
        'updated_at' => (int)(isset($state['updated_at']) ? $state['updated_at'] : 0),
    );
}

function login_guard_is_captcha_required($state = null)
{
    if ($state === null) {
        $state = login_guard_get_state();
    } else {
        $state = login_guard_normalize_state($state);
    }

    return ((int)$state['lock_until'] > time());
}

function login_guard_get_remaining_attempts($state = null)
{
    if ($state === null) {
        $state = login_guard_get_state();
    } else {
        $state = login_guard_normalize_state($state);
    }

    if (login_guard_is_captcha_required($state)) {
        return 0;
    }

    $remaining = LOGIN_GUARD_FAIL_LIMIT - (int)$state['fail_count'];
    if ($remaining < 0) {
        $remaining = 0;
    }

    return $remaining;
}

function login_guard_get_remaining_lock_seconds($state = null)
{
    if ($state === null) {
        $state = login_guard_get_state();
    } else {
        $state = login_guard_normalize_state($state);
    }

    $left = (int)$state['lock_until'] - time();
    return ($left > 0) ? $left : 0;
}

function login_guard_record_failure($state = null)
{
    if ($state === null) {
        $state = login_guard_get_state();
    } else {
        $state = login_guard_normalize_state($state);
    }

    $state['fail_count'] = (int)$state['fail_count'] + 1;

    if ($state['fail_count'] >= LOGIN_GUARD_FAIL_LIMIT) {
        $state['lock_until'] = time() + LOGIN_GUARD_LOCK_SECONDS;
    }

    return login_guard_save_state($state);
}

function login_guard_record_success()
{
    $state = login_guard_default_state();
    return login_guard_save_state($state);
}

function login_guard_verify_captcha_input($captcha_key = '')
{
    if (!trim((string)$captcha_key)) {
        return false;
    }

    if (!defined('G5_CAPTCHA_PATH')) {
        return false;
    }

    @include_once(G5_CAPTCHA_PATH . '/captcha.lib.php');

    if (!function_exists('chk_captcha')) {
        return false;
    }

    $_POST['captcha_key'] = $captcha_key;
    return chk_captcha() ? true : false;
}
