Files
dwroller/database/auth.js
Alex ad7ce9dc22 Security fix: GM authorized from server-side session via x-session-id header
- New database/auth.js: shared server-side GM check using session store
- database/server.js: crypto-random session generation, server-side session
  storage, GM auth from session instead of x-gm-secret header
- database/routes/playerRoutes.js: GM-only endpoints use server-side auth
- database/routes/sessionRoutes.js: session creation/lookup endpoints
- database/routes/bestiaryRoutes.js: GM auth from server-side session
- database/routes/rulesRoutes.js: GM auth from server-side session
- src/App.js: send x-session-id header with API requests
- src/components/BestiaryTab.jsx: use session-based GM auth
2026-07-16 23:03:52 +02:00

34 lines
1.0 KiB
JavaScript

// Shared GM authorization middleware
// Authorizes based on server-side session lookup via x-session-id header.
// Does NOT trust x-gm-secret header (that was the vulnerability).
//
// Usage in async route handlers:
// const { requireGM } = require('../auth');
// if (!(await requireGM(req, res))) return;
//
// Usage in sync middleware (not supported — this is async only).
const { validateSession } = require('./sessionModel');
async function requireGM(req, res) {
const sessionId = req.headers['x-session-id'];
if (!sessionId) {
res.status(401).json({ error: 'Authentication required' });
return false;
}
const session = await validateSession(sessionId);
if (!session || !session.data || !session.data.playerName) {
res.status(401).json({ error: 'Invalid or expired session' });
return false;
}
if (session.data.playerName.toLowerCase() !== 'gm') {
res.status(403).json({ error: 'GM access required' });
return false;
}
return true;
}
module.exports = { requireGM };