PHP WebShell
Текущая директория: /var/www/bitcardoApp/models/auth
Просмотр файла: reset_process.php
<?php
// models/auth/reset_process.php — Verify code, set new password, revoke sessions
require_once __DIR__ . '/../../config/bootstrap.php';
// Optional libs
$rateLib = __DIR__ . '/../../lib/rate_limit.php';
if (file_exists($rateLib)) require_once $rateLib;
$sessionLib = __DIR__ . '/../../lib/session.php';
if (file_exists($sessionLib)) require_once $sessionLib;
// Helpers
function back_with($arr){
$_SESSION['flash'] = $arr;
header('Location: /auth/reset.php'); exit;
}
function rl_on() { return function_exists('is_enabled') ? is_enabled('rate_limit_enabled', true) : true; }
function norm_login($login){
return function_exists('rl_norm_login') ? rl_norm_login($login) : strtolower(trim($login));
}
// CSRF
if (!isset($_POST['csrf'], $_SESSION['csrf']) || !hash_equals($_SESSION['csrf'], $_POST['csrf'])) {
back_with(['error' => 'Session expired. Please try again.']);
}
// Input
$login = trim($_POST['login'] ?? '');
$code = preg_replace('/\D+/', '', $_POST['code'] ?? '');
$pass1 = (string)($_POST['password'] ?? '');
$pass2 = (string)($_POST['password2'] ?? '');
if ($login === '' || $code === '') back_with(['error' => 'Enter your email/phone and code.']);
if (strlen($code) !== 6) back_with(['error' => 'Invalid code.']);
if ($pass1 === '' || strlen($pass1) < 8) back_with(['error' => 'Use at least 8 characters for your new password.']);
if (!hash_equals($pass1, $pass2)) back_with(['error' => 'Passwords do not match.']);
$loginTok = norm_login($login);
// Rate limit: verification attempts per login token
if (rl_on() && function_exists('rl_check_and_inc')) {
// 8 attempts / 15 mins; lock for 15 mins
$r = rl_check_and_inc($conn, 'reset_verify', $loginTok, 8, 900, 900);
if (!$r['ok']) back_with(['error' => "Too many attempts. Try again in {$r['locked_for']}s."]);
}
// Find user
$stmt = $conn->prepare("SELECT user_id, email FROM users WHERE email=? OR phone=? LIMIT 1");
$stmt->bind_param('ss', $login, $login);
$stmt->execute();
$stmt->bind_result($uid, $email);
$found = $stmt->fetch();
$stmt->close();
// Generic error to avoid enumeration
if (!$found || !$uid) back_with(['error' => 'Invalid or expired code. Request a new one and try again.']);
// Load latest unconsumed reset OTP
$q = $conn->prepare("SELECT uotp_id, token_hash, expires_at
FROM user_otps
WHERE user_id=? AND channel='reset' AND consumed_at IS NULL
ORDER BY uotp_id DESC LIMIT 1");
$q->bind_param('i', $uid);
$q->execute();
$q->bind_result($id, $tokenHash, $expiresAt);
$has = $q->fetch();
$q->close();
if (!$has) back_with(['error' => 'Invalid or expired code. Request a new one and try again.']);
if (new DateTimeImmutable($expiresAt) < new DateTimeImmutable()) {
$u = $conn->prepare("UPDATE user_otps SET consumed_at=NOW() WHERE uotp_id=?");
$u->bind_param('i', $id); $u->execute(); $u->close();
back_with(['error' => 'Code expired. Request a new one.']);
}
if (!hash_equals($tokenHash ?? '', hash('sha256', $code))) {
// bump attempts for telemetry (optional)
$a = $conn->prepare("UPDATE user_otps SET attempts=LEAST(attempts+1, 250) WHERE uotp_id=?");
$a->bind_param('i', $id); $a->execute(); $a->close();
back_with(['error' => 'Invalid code.']);
}
// Consume OTP
$c = $conn->prepare("UPDATE user_otps SET consumed_at=NOW() WHERE uotp_id=?");
$c->bind_param('i', $id); $c->execute(); $c->close();
// Update password
$newHash = password_hash($pass1, PASSWORD_DEFAULT);
$u = $conn->prepare("UPDATE users SET password_hash=?, updated_at=NOW() WHERE user_id=?");
$u->bind_param('si', $newHash, $uid);
$u->execute();
$u->close();
// Revoke all existing remembered sessions for this user
$conn->query("UPDATE user_sessions SET revoked_at=NOW() WHERE user_id=".(int)$uid);
// Clear remember-me cookie if supported
if (function_exists('session_revoke_cookie')) {
session_revoke_cookie($conn);
}
/**
* Log out this runtime session safely, then set a flash message.
* We avoid session_destroy() since we want to set flash; instead:
* - wipe session data,
* - regenerate ID (to drop any fixed session),
* - set flash in the new, clean session,
* - redirect.
*/
$_SESSION = [];
session_regenerate_id(true); // new empty session
$_SESSION['flash'] = ['ok' => 'Your password has been reset. Please log in with your new password.'];
// Optionally clear any prefill used in the reset form
unset($_SESSION['prefill_login']);
header('Location: /auth/login.php');
exit;
Выполнить команду
Для локальной разработки. Не используйте в интернете!