3v324v23's picture
修复登录态:按协议设置Cookie,并提供一键演示登录
3ee84f3
Raw
History Blame Contribute Delete
2.39 kB
import type { Request, Response } from 'express'
import type { DbSchema, DbSession, SessionKind } from './db.js'
import { newId, nowIso, pruneExpiredSessions } from './db.js'
export const COOKIE_FULL = 'sid'
export const COOKIE_PENDING = 'psid'
function addMinutes(date: Date, minutes: number) {
return new Date(date.getTime() + minutes * 60_000)
}
function addDays(date: Date, days: number) {
return new Date(date.getTime() + days * 86_400_000)
}
export function createSession(db: DbSchema, userId: string, kind: SessionKind): DbSession {
pruneExpiredSessions(db)
const now = new Date()
const expires = kind === 'mfa_pending' ? addMinutes(now, 10) : addDays(now, 7)
const s: DbSession = {
id: newId(),
user_id: userId,
kind,
created_at: nowIso(),
expires_at: expires.toISOString(),
}
db.sessions.push(s)
return s
}
function isSecureRequest(req: Request) {
if (req.secure) return true
const xfp = req.headers['x-forwarded-proto']
if (typeof xfp === 'string') return xfp.split(',')[0]?.trim() === 'https'
return false
}
function cookieBaseOptions(req: Request) {
return {
httpOnly: true,
sameSite: 'lax' as const,
secure: isSecureRequest(req),
}
}
export function clearSessionCookies(req: Request, res: Response) {
const base = cookieBaseOptions(req)
res.clearCookie(COOKIE_FULL, base)
res.clearCookie(COOKIE_PENDING, base)
}
export function setSessionCookie(req: Request, res: Response, session: DbSession) {
const name = session.kind === 'mfa_pending' ? COOKIE_PENDING : COOKIE_FULL
const base = cookieBaseOptions(req)
res.cookie(name, session.id, {
...base,
expires: new Date(session.expires_at),
})
}
export function getSessionFromRequest(req: Request, kind: SessionKind) {
const cookies = (req as unknown as { cookies?: Record<string, unknown> }).cookies
const raw = cookies?.[kind === 'mfa_pending' ? COOKIE_PENDING : COOKIE_FULL]
return typeof raw === 'string' ? raw : null
}
export function removeSessionsByIds(db: DbSchema, ids: string[]) {
if (ids.length === 0) return
const set = new Set(ids)
db.sessions = db.sessions.filter((s) => !set.has(s.id))
}
export function removeOtherUserSessions(db: DbSchema, userId: string, keepSessionIds: string[]) {
const keep = new Set(keepSessionIds)
db.sessions = db.sessions.filter((s) => s.user_id !== userId || keep.has(s.id))
}