- Add optionalAuth middleware: attaches session when present, never blocks (guests pass through) - Make game endpoints (start/answer) accept optional auth - GameSessionStore.userId: string → string | null - Rate limiter falls back to IP for unauthenticated users - Frontend: remove /play route guard, show 'Create account' CTA on score screen for guests - Add tests for guest session creation, answer submission, and cross-user session isolation
55 lines
1.5 KiB
TypeScript
55 lines
1.5 KiB
TypeScript
import rateLimit, { ipKeyGenerator } from "express-rate-limit";
|
|
import type { Request } from "express";
|
|
|
|
// TODO: When Valkey is wired up, swap the default in-memory store for
|
|
// rate-limit-redis to persist limits across restarts:
|
|
//
|
|
// import { RedisStore } from "rate-limit-redis";
|
|
// import { valkey } from "../lib/valkey.js";
|
|
// Then add to each limiter: store: new RedisStore({ sendCommand: (...args) => valkey.call(...args) })
|
|
|
|
export const authLimiter = rateLimit({
|
|
windowMs: 15 * 60 * 1000,
|
|
limit: 20,
|
|
standardHeaders: "draft-8",
|
|
legacyHeaders: false,
|
|
skip: (req) => {
|
|
const path = req.path;
|
|
return (
|
|
path.includes("/get-session") ||
|
|
path.includes("/sign-out") ||
|
|
path.startsWith("/callback/") ||
|
|
path.includes("/callback/")
|
|
);
|
|
},
|
|
message: {
|
|
success: false,
|
|
error: "Too many requests, please try again later.",
|
|
},
|
|
});
|
|
|
|
export const gameLimiter = rateLimit({
|
|
windowMs: 15 * 60 * 1000,
|
|
limit: 150,
|
|
standardHeaders: "draft-8",
|
|
legacyHeaders: false,
|
|
keyGenerator: (req: Request) =>
|
|
req.session?.user.id ?? ipKeyGenerator(req.ip ?? "unknown"),
|
|
message: {
|
|
success: false,
|
|
error: "Too many requests, please try again later.",
|
|
},
|
|
});
|
|
|
|
export const lobbyLimiter = rateLimit({
|
|
windowMs: 15 * 60 * 1000,
|
|
limit: 20,
|
|
standardHeaders: "draft-8",
|
|
legacyHeaders: false,
|
|
keyGenerator: (req: Request) =>
|
|
req.session?.user.id ?? ipKeyGenerator(req.ip ?? "unknown"),
|
|
message: {
|
|
success: false,
|
|
error: "Too many requests, please try again later.",
|
|
},
|
|
});
|