PHP WebShell

Текущая директория: /var/www/bitcardoApp/models/auth

Просмотр файла: login_process.php

<?php
/**
 * models/auth/login_process.php
 *
 * (unchanged header comment)
 */

////////////////////////////////////////////
// 0) Bootstrap (required)
////////////////////////////////////////////
$__bootstrap = __DIR__ . '/../../config/bootstrap.php';
if (!file_exists($__bootstrap)) {
    if (session_status() === PHP_SESSION_NONE) { session_start(); }
    require_once __DIR__ . '/../../config/serv_config.php';
    require_once __DIR__ . '/../../config/db_config.php';
    $__settings = __DIR__ . '/../../config/settings.php';
    if (file_exists($__settings)) { require_once $__settings; }
    unset($__settings);
} else {
    require_once $__bootstrap;
}
unset($__bootstrap);

////////////////////////////////////////////
// 0.1) Small helpers
////////////////////////////////////////////
function safe_redirect(string $location) {
    if (!headers_sent()) {
        header('Location: ' . $location);
    } else {
        echo '<script>location.href=' . json_encode($location) . ';</script>';
    }
    exit;
}

function fail_with(string $msg) {
    $_SESSION['error'] = $msg;
    safe_redirect('../../auth/login.php');
}

// CSRF check
if (!isset($_POST['csrf'], $_SESSION['csrf']) || !hash_equals($_SESSION['csrf'], $_POST['csrf'])) {
    $_SESSION['error'] = 'Session expired. Please try again.';
    header('Location: ../../auth/login.php'); exit;
}

////////////////////////////////////////////
// 1) Collect + normalize input
////////////////////////////////////////////
$loginRaw = $_POST['login']    ?? '';
$passRaw  = $_POST['password'] ?? '';

$login    = trim(preg_replace('/\s+/', ' ', (string)$loginRaw));
$password = (string)$passRaw;

$_SESSION['form_data'] = ['login' => $login];

////////////////////////////////////////////
// 2) Validate reCAPTCHA (server-side)
////////////////////////////////////////////
$recaptchaResponse = $_POST['g-recaptcha-response'] ?? '';
$secret = defined('RECAPTCHA_SECRET') ? RECAPTCHA_SECRET : '';

if ($secret === '') {
    fail_with('Captcha is not configured. Please try again later.');
}

$ctx = stream_context_create([
    'http' => [
        'method'  => 'POST',
        'header'  => "Content-type: application/x-www-form-urlencoded\r\n",
        'content' => http_build_query([
            'secret'   => $secret,
            'response' => $recaptchaResponse,
        ]),
        'timeout' => 5,
    ]
]);

$verify  = @file_get_contents('https://www.google.com/recaptcha/api/siteverify', false, $ctx);
$captcha = $verify ? json_decode($verify, true) : ['success' => false];

if (empty($captcha['success'])) {
    fail_with('Captcha verification failed.');
}

////////////////////////////////////////////
// 3) Quick sanity checks
////////////////////////////////////////////
if (!($conn instanceof mysqli)) {
    fail_with('Service temporarily unavailable. Please try again.');
}
if ($login === '' || $password === '') {
    fail_with('Please enter your login and password.');
}

////////////////////////////////////////////
// 3.5) Rate-limit (unchanged)
////////////////////////////////////////////
$rateLib = __DIR__ . '/../../lib/rate_limit.php';
$rlActive = false;
if (file_exists($rateLib)) {
    require_once $rateLib;
    $rlActive = function_exists('is_enabled') ? is_enabled('rate_limit_enabled', true) : true;

    if ($rlActive) {
        $IP_LIMIT      = 10;
        $IP_WINDOW_SEC = 900;
        $IP_LOCK_SEC   = 900;

        $ID_LIMIT      = 7;
        $ID_WINDOW_SEC = 900;
        $ID_LOCK_SEC   = 900;

        $ipToken  = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
        $loginTok = function_exists('rl_norm_login') ? rl_norm_login($login) : mb_strtolower(trim($login));

        if (function_exists('rl_check_and_inc')) {
            $r = rl_check_and_inc($conn, 'ip', $ipToken, $IP_LIMIT, $IP_WINDOW_SEC, $IP_LOCK_SEC);
            if (!$r['ok']) {
                fail_with("Too many attempts from your network. Try again in {$r['locked_for']}s.");
            }
        }

        if ($loginTok !== '' && function_exists('rl_check_and_inc')) {
            $r = rl_check_and_inc($conn, 'login', $loginTok, $ID_LIMIT, $ID_WINDOW_SEC, $ID_LOCK_SEC);
            if (!$r['ok']) {
                fail_with("Too many attempts on this account. Try again in {$r['locked_for']}s.");
            }
        }
    }
}
unset($rateLib);

////////////////////////////////////////////
// 4) Find user
////////////////////////////////////////////
$sql = "SELECT user_id, email, first_name, last_name, password_hash, level_id
        FROM users
        WHERE email = ? OR phone = ?
        LIMIT 1";
$stmt = $conn->prepare($sql);
if (!$stmt) {
    fail_with('Service temporarily unavailable. Please try again.');
}
$stmt->bind_param('ss', $login, $login);
$stmt->execute();
$stmt->store_result();

if ($stmt->num_rows !== 1) {
    $stmt->close();
    fail_with('Invalid login credentials.');
}

$stmt->bind_result($userId, $email, $firstName, $lastName, $hash, $levelId);
$stmt->fetch();

////////////////////////////////////////////
// 5) Verify password
////////////////////////////////////////////
if (!is_string($hash) || $hash === '' || !password_verify($password, $hash)) {
    $stmt->close();
    fail_with('Invalid login credentials.');
}

$stmt->close();

////////////////////////////////////////////
// 6) Establish session identity
////////////////////////////////////////////
if (session_status() !== PHP_SESSION_ACTIVE) { session_start(); }
session_regenerate_id(true);

$_SESSION['user_id']    = (int)$userId;
$_SESSION['email']      = $email;
$_SESSION['first_name'] = $firstName ?? '';
$_SESSION['last_name']  = $lastName ?? '';
$_SESSION['loggedIn']   = true;

$_SESSION['level_id']   = is_null($levelId) ? null : (int)$levelId;
$_SESSION['is_admin']   = (!is_null($levelId) && (int)$levelId >= 6);

unset($_SESSION['form_data']);

////////////////////////////////////////////
// 6.5) Rate-limit reset on success
////////////////////////////////////////////
if (!empty($rlActive) && function_exists('rl_reset')) {
    $ipToken  = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
    $loginTok = function_exists('rl_norm_login') ? rl_norm_login($login) : mb_strtolower(trim($login));
    rl_reset($conn, 'ip', $ipToken);
    if ($loginTok !== '') rl_reset($conn, 'login', $loginTok);
}

////////////////////////////////////////////
// 7) Session record + remember-me
////////////////////////////////////////////
// We now use the user-selected duration from the login form.
$libDevice  = __DIR__ . '/../../lib/device.php';
$libSession = __DIR__ . '/../../lib/session.php';

// Read and sanitise remember duration (in seconds)
$rememberDurationRaw = $_POST['remember_duration'] ?? '0';
$rememberDurationSec = (int)$rememberDurationRaw;

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

// Cap at 30 days for safety
$MAX_DURATION = 30 * 24 * 60 * 60;
if ($rememberDurationSec > $MAX_DURATION) {
    $rememberDurationSec = $MAX_DURATION;
}

// If > 0, we consider it a "remember me" login
$rememberRequested = ($rememberDurationSec > 0);

if (file_exists($libSession)) {
    require_once $libSession;

    $rememberAllowed = true;
    if (function_exists('is_enabled')) {
        $rememberAllowed = is_enabled('remember_me', true);
    }

    if (function_exists('session_record_create')) {
        // Writes user_sessions row + sets remember cookie, with duration
        session_record_create(
            $conn,
            (int)$userId,
            ($rememberAllowed && $rememberRequested),
            $rememberDurationSec  // NEW: pass duration in seconds
        );
    }
}
unset($libSession);

// NOTE: Keeping your existing order intact.
$hasGrace = !empty($_SESSION['first_session_grace']);
if ($otpEnabled && $requireOnNew && !$trusted && !$hasGrace) {
    safe_redirect('/auth/challenge.php');
}
unset($_SESSION['first_session_grace']);

////////////////////////////////////////////
// 8) Optional Phase 2: device trust + TOTP challenge gate
////////////////////////////////////////////
if (file_exists($libDevice)) {
    require_once $libDevice;

    $otpEnabled   = function_exists('is_enabled') ? is_enabled('otp_enabled', true) : true;
    $requireOnNew = function_exists('is_enabled') ? is_enabled('otp_require_on_new_dev', true) : false;

    if ($otpEnabled && $requireOnNew && function_exists('device_is_trusted')) {
        $trusted = device_is_trusted($conn, (int)$userId);
        if (!$trusted) {
            safe_redirect('/auth/challenge.php');
        }
    }
}
unset($libDevice);

////////////////////////////////////////////
// 9) Success → Dashboard
////////////////////////////////////////////
if (!empty($_SESSION['is_admin'])) {
    safe_redirect('../../backyard/user/dashboard/index.php');
}

safe_redirect('../../user/dashboard/index.php');

Выполнить команду


Для локальной разработки. Не используйте в интернете!