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');
Выполнить команду
Для локальной разработки. Не используйте в интернете!