Merge pull request 'Enforce role-based authorization on admin-only routes (fixes #10)' (#15) from fix/role-authorization into main
Reviewed-on: UOM/website#15 Reviewed-by: Colby Whitlock <whitlocktech@gmail.com>
This commit is contained in:
@@ -5,7 +5,7 @@ const multer = require('multer')
|
||||
const { body, param } = require('express-validator')
|
||||
|
||||
const ctrl = require('./admin.controller')
|
||||
const { isLoggedIn } = require('../../../utils/auth')
|
||||
const { isLoggedIn, requireRole } = require('../../../utils/auth')
|
||||
const noindex = require('../../../middleware/noindex')
|
||||
const validate = require('../../../middleware/validate')
|
||||
|
||||
@@ -14,6 +14,10 @@ const adminRouter = express.Router()
|
||||
// Every admin route requires auth and is kept out of search indexes.
|
||||
adminRouter.use(noindex, isLoggedIn)
|
||||
|
||||
// Admin-only gate. Editors may manage content (posts/wiki), but user
|
||||
// management, site mode, and settings are restricted to the admin role.
|
||||
const adminOnly = requireRole('admin')
|
||||
|
||||
// ── Image uploads (screenshots/gallery) ───────────────────────────────
|
||||
const UPLOAD_DIR =
|
||||
process.env.UPLOAD_DIR || path.join(__dirname, '..', '..', '..', '..', 'uploads')
|
||||
@@ -39,6 +43,7 @@ const upload = multer({
|
||||
adminRouter.get('/dashboard', ctrl.dashboard)
|
||||
adminRouter.put(
|
||||
'/site-mode',
|
||||
adminOnly,
|
||||
body('mode').isIn(['live', 'maintenance']),
|
||||
validate,
|
||||
ctrl.setSiteMode,
|
||||
@@ -135,13 +140,14 @@ adminRouter.post(
|
||||
adminRouter.delete('/wiki/:slug', ctrl.deleteWiki)
|
||||
|
||||
// ── Settings ──────────────────────────────────────────────────────────
|
||||
adminRouter.get('/settings', ctrl.getSettings)
|
||||
adminRouter.put('/settings', ctrl.updateSettings)
|
||||
adminRouter.get('/settings', adminOnly, ctrl.getSettings)
|
||||
adminRouter.put('/settings', adminOnly, ctrl.updateSettings)
|
||||
|
||||
// ── Activity log ──────────────────────────────────────────────────────
|
||||
adminRouter.get('/activity', ctrl.listActivity)
|
||||
|
||||
// ── User management ───────────────────────────────────────────────────
|
||||
// ── User management (admin only) ──────────────────────────────────────
|
||||
adminRouter.use('/users', adminOnly)
|
||||
adminRouter.get('/users', ctrl.listUsers)
|
||||
adminRouter.post(
|
||||
'/users',
|
||||
|
||||
@@ -85,6 +85,16 @@ function isLoggedIn(req, res, next) {
|
||||
return next()
|
||||
}
|
||||
|
||||
// Gate middleware factory: allow only the listed roles. Assumes isLoggedIn ran
|
||||
// first so req.user is populated. Use for admin-only endpoints (users, site
|
||||
// mode, settings) so a lower-privilege editor cannot reach them.
|
||||
function requireRole(...roles) {
|
||||
return (req, res, next) => {
|
||||
if (roles.includes(req.user?.role)) return next()
|
||||
return res.status(403).json({ message: 'Forbidden' })
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
COOKIE_NAME,
|
||||
signToken,
|
||||
@@ -93,4 +103,5 @@ module.exports = {
|
||||
clearAuthCookie,
|
||||
getUserFromRequest,
|
||||
isLoggedIn,
|
||||
requireRole,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user