Change 'Rack' to 'Bin'

This commit is contained in:
Thanakorn S
2026-05-27 17:14:53 +07:00
parent b8798bc02d
commit 8f57ab5570
41 changed files with 931 additions and 933 deletions
+16 -18
View File
@@ -23,8 +23,9 @@
* b. The elapsed time since otpTime is ≤ 5 minutes.
* Fail either → return "Wrong OTP! Please try again."
* 5. On success:
* a. Check session_token in DB — if non-NULL, another session is active;
* reject login with "account already logged in" message.
* a. Force-replace session_token in DB — writing a new token invalidates
* any prior session (old device gets kicked out by db_auth.php on its
* next request). No block: password + OTP is full 2FA proof of identity.
* b. session_regenerate_id(true) — prevents session fixation attack by
* issuing a new session ID and deleting the old one.
* c. Generate a fresh CSRF token and store in session.
@@ -105,31 +106,28 @@ if (empty($_SESSION['skip_otp'])) {
}
}
// ── Step 4b: Claim session atomically ─────────────────────────────────────────
// The WHERE clause is the concurrency gate: only a free or stale token can be
// replaced. session_last_seen is set immediately so a fresh login is live before
// the first authenticated heartbeat in db_auth.php.
// ── Step 4b: Claim session — always replace existing token ────────────────────
// Password + OTP is full 2FA proof of identity, so we always grant the login.
// Writing a new token here also invalidates any prior session: db_auth.php
// compares session_token in the DB to the one stored in the PHP session, so the
// old device is kicked out on its next request. This also fixes the case where
// a PHP session expired without clearing the DB token, which would otherwise
// permanently block re-login.
$session_token = bin2hex(random_bytes(32));
$sth_claim = $pdo1->prepare(
"UPDATE user
SET session_token = :token,
session_token_at = NOW(),
SET session_token = :token,
session_token_at = NOW(),
session_last_seen = NOW()
WHERE user_id = :uid
AND (
session_token IS NULL
OR session_last_seen IS NULL
OR TIMESTAMPDIFF(SECOND, session_last_seen, NOW()) >= :gc_maxlifetime
)"
WHERE user_id = :uid"
);
$sth_claim->execute([
':token' => $session_token,
':uid' => $user_id,
':gc_maxlifetime' => (int)ini_get('session.gc_maxlifetime'),
':token' => $session_token,
':uid' => $user_id,
]);
if ($sth_claim->rowCount() !== 1) {
$answer["message"] = "This account is currently logged in on another device. Please wait for the other session to end.";
$answer["message"] = "Login failed: user record not found.";
exit(json_encode($answer));
}