From 649f40ff374fd63cb5ea6abe2d8a442f6a779694 Mon Sep 17 00:00:00 2001 From: ra939 Date: Sun, 5 Oct 2025 08:56:20 +0000 Subject: [PATCH] Commit middlewear to read login (cookie/JWT) and sets req.user, and requireAuth blocks anyone not logged in with a 401 error. --- server/middleware/requireAuth.js | 13 ++++++++ server/middleware/sessionOrJwt.js | 49 +++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 server/middleware/requireAuth.js create mode 100644 server/middleware/sessionOrJwt.js diff --git a/server/middleware/requireAuth.js b/server/middleware/requireAuth.js new file mode 100644 index 000000000..f760634ed --- /dev/null +++ b/server/middleware/requireAuth.js @@ -0,0 +1,13 @@ +// server/middleware/requireAuth.js +// +// Tiny guard that ensures req.user is present AFTER sessionOrJwt has run. +// Sends a clean 401 instead of leaking as a 500. +module.exports = (auth) => { + return (req, res, next) => { + // If Auth added a user (via cookie session or Bearer) we proceed. + if (req.user && req.user.id) return next() + + // Otherwise make it explicit that this route requires auth. + res.status(401).send('Unauthorized') + } +} diff --git a/server/middleware/sessionOrJwt.js b/server/middleware/sessionOrJwt.js new file mode 100644 index 000000000..5c21ab0ec --- /dev/null +++ b/server/middleware/sessionOrJwt.js @@ -0,0 +1,49 @@ +// server/middleware/sessionOrJwt.js +let AchievementManager = null; +try { + // If you actually have an achievements manager, require it here. + // Otherwise keep this try/catch and we'll simply no-op below. + AchievementManager = require('../managers/AchievementManager'); +} catch (_) { + // optional; safely ignored when absent +} + +function fireLoginEvent(req) { + try { + // Only call if the module exists AND exposes applyEvent + if (!AchievementManager || typeof AchievementManager.applyEvent !== 'function') return; + if (req._absLoginEventSent) return; + + const user = req.user; + const uid = user && (user.id || user.userId); + if (!uid) return; + + req._absLoginEventSent = true; + AchievementManager.applyEvent(String(uid), 'userLoggedIn').catch(() => {}); + } catch (_) { + // never break auth flow + } +} + +module.exports = (auth) => { + if (!auth || typeof auth.isAuthenticated !== 'function') { + throw new Error('[sessionOrJwt] auth.isAuthenticated missing'); + } + return (req, res, next) => { + // If something upstream already attached req.user, fire and continue. + if (req.user && (req.user.id || req.user.userId)) { + fireLoginEvent(req); + return next(); + } + + auth.isAuthenticated(req, res, (err) => { + if (err) return next(err); + if (req.user && (req.user.id || req.user.userId)) { + fireLoginEvent(req); + return next(); + } + // IMPORTANT: 401 here (not 500) when no credentials + return res.status(401).send('Unauthorized'); + }); + }; +};