import { Request, Response, RequestHandler } from "express"; import { config } from "../config"; const ADMIN_KEY = config.adminKey; const failedAttempts = new Map(); type AuthorizeParams = { via: "cookie" | "header" }; export const authorize: ({ via }: AuthorizeParams) => RequestHandler = ({ via }) => (req, res, next) => { const bearerToken = req.headers.authorization?.slice("Bearer ".length); const cookieToken = req.session.adminToken; const token = via === "cookie" ? cookieToken : bearerToken; const attempts = failedAttempts.get(req.ip) ?? 0; if (!ADMIN_KEY) { req.log.warn( { ip: req.ip }, `Blocked admin request because no admin key is configured` ); return res.status(401).json({ error: "Unauthorized" }); } if (attempts > 5) { req.log.warn( { ip: req.ip, token: bearerToken }, `Blocked admin request due to too many failed attempts` ); return res.status(401).json({ error: "Too many attempts" }); } if (token && token === ADMIN_KEY) { return next(); } req.log.warn( { ip: req.ip, attempts, invalidToken: String(token) }, `Attempted admin request with invalid token` ); return handleFailedLogin(req, res); }; function handleFailedLogin(req: Request, res: Response) { const attempts = failedAttempts.get(req.ip) ?? 0; const newAttempts = attempts + 1; failedAttempts.set(req.ip, newAttempts); if (req.accepts("json", "html") === "json") { return res.status(401).json({ error: "Unauthorized" }); } delete req.session.adminToken; req.session.flash = { type: "error", message: `Invalid admin key.` }; return res.redirect("/admin/login"); }