feat(auth): access 24ч, jti против гонок ротации, транзакционная ротация, отзыв сессий по sid

This commit is contained in:
2026-09-21 18:13:46 +03:00
parent 2f9d049718
commit c957a70260
8 changed files with 221 additions and 31 deletions

View File

@@ -0,0 +1,30 @@
import { eq } from 'drizzle-orm';
import { db } from '../db';
import { userSessions } from '@shared/schema';
/**
* Проверка отзыва сессии (user_sessions.is_revoked) для access-токенов с claim sid.
* In-memory кэш ~30 сек: неизменный ответ не дёргает БД на каждый запрос,
* отозванная сессия умирает в течение ~30 секунд на всех инстансах приложения.
*/
const CACHE_TTL_MS = 30_000;
const cache = new Map<number, { revoked: boolean; ts: number }>();
export async function isSessionRevoked(sid: number): Promise<boolean> {
const hit = cache.get(sid);
if (hit && Date.now() - hit.ts < CACHE_TTL_MS) return hit.revoked;
const [row] = await db
.select({ isRevoked: userSessions.isRevoked })
.from(userSessions)
.where(eq(userSessions.id, sid));
// Неизвестная/удалённая сессия считается отозванной
const revoked = row ? row.isRevoked : true;
cache.set(sid, { revoked, ts: Date.now() });
return revoked;
}
/** Сброс кэша после явного отзыва (logout, отзыв устройства, смена пароля) */
export function invalidateSessionRevocationCache(sid?: number): void {
if (sid === undefined) cache.clear();
else cache.delete(sid);
}