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 { body, param } = require('express-validator')
|
||||||
|
|
||||||
const ctrl = require('./admin.controller')
|
const ctrl = require('./admin.controller')
|
||||||
const { isLoggedIn } = require('../../../utils/auth')
|
const { isLoggedIn, requireRole } = require('../../../utils/auth')
|
||||||
const noindex = require('../../../middleware/noindex')
|
const noindex = require('../../../middleware/noindex')
|
||||||
const validate = require('../../../middleware/validate')
|
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.
|
// Every admin route requires auth and is kept out of search indexes.
|
||||||
adminRouter.use(noindex, isLoggedIn)
|
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) ───────────────────────────────
|
// ── Image uploads (screenshots/gallery) ───────────────────────────────
|
||||||
const UPLOAD_DIR =
|
const UPLOAD_DIR =
|
||||||
process.env.UPLOAD_DIR || path.join(__dirname, '..', '..', '..', '..', 'uploads')
|
process.env.UPLOAD_DIR || path.join(__dirname, '..', '..', '..', '..', 'uploads')
|
||||||
@@ -39,6 +43,7 @@ const upload = multer({
|
|||||||
adminRouter.get('/dashboard', ctrl.dashboard)
|
adminRouter.get('/dashboard', ctrl.dashboard)
|
||||||
adminRouter.put(
|
adminRouter.put(
|
||||||
'/site-mode',
|
'/site-mode',
|
||||||
|
adminOnly,
|
||||||
body('mode').isIn(['live', 'maintenance']),
|
body('mode').isIn(['live', 'maintenance']),
|
||||||
validate,
|
validate,
|
||||||
ctrl.setSiteMode,
|
ctrl.setSiteMode,
|
||||||
@@ -135,13 +140,14 @@ adminRouter.post(
|
|||||||
adminRouter.delete('/wiki/:slug', ctrl.deleteWiki)
|
adminRouter.delete('/wiki/:slug', ctrl.deleteWiki)
|
||||||
|
|
||||||
// ── Settings ──────────────────────────────────────────────────────────
|
// ── Settings ──────────────────────────────────────────────────────────
|
||||||
adminRouter.get('/settings', ctrl.getSettings)
|
adminRouter.get('/settings', adminOnly, ctrl.getSettings)
|
||||||
adminRouter.put('/settings', ctrl.updateSettings)
|
adminRouter.put('/settings', adminOnly, ctrl.updateSettings)
|
||||||
|
|
||||||
// ── Activity log ──────────────────────────────────────────────────────
|
// ── Activity log ──────────────────────────────────────────────────────
|
||||||
adminRouter.get('/activity', ctrl.listActivity)
|
adminRouter.get('/activity', ctrl.listActivity)
|
||||||
|
|
||||||
// ── User management ───────────────────────────────────────────────────
|
// ── User management (admin only) ──────────────────────────────────────
|
||||||
|
adminRouter.use('/users', adminOnly)
|
||||||
adminRouter.get('/users', ctrl.listUsers)
|
adminRouter.get('/users', ctrl.listUsers)
|
||||||
adminRouter.post(
|
adminRouter.post(
|
||||||
'/users',
|
'/users',
|
||||||
|
|||||||
@@ -85,6 +85,16 @@ function isLoggedIn(req, res, next) {
|
|||||||
return 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 = {
|
module.exports = {
|
||||||
COOKIE_NAME,
|
COOKIE_NAME,
|
||||||
signToken,
|
signToken,
|
||||||
@@ -93,4 +103,5 @@ module.exports = {
|
|||||||
clearAuthCookie,
|
clearAuthCookie,
|
||||||
getUserFromRequest,
|
getUserFromRequest,
|
||||||
isLoggedIn,
|
isLoggedIn,
|
||||||
|
requireRole,
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user