/*********************************************************************************************************************************************************************** * File Name: rbac.middleware.js * Type of Program: Middleware * Description: Role-Based Access Control (RBAC) guards. * Hierarchy: admin > staff > user (client) * * Exported guards: * - requireClient() → acc_type in ['user', 'staff', 'admin'] * - requireStaff() → acc_type in ['staff', 'admin'] * - requireAdmin() → acc_type === 'admin' only * - requireOwnerOrStaff() → owns the resource OR is staff/admin * - requireOwnerOrAdmin() → owns the resource OR is admin * * Author: rgrgogu * Date Created: Oct. 6, 2025 *********************************************************************************************************************************************************************** * HOW TO USE: * const { requireAdmin, requireStaff } = require('../middleware/rbac.middleware'); * // Must be used AFTER authenticate middleware * router.get('/users', authenticate, requireStaff(), handler); * router.delete('/users/:id', authenticate, requireAdmin(), handler); ***********************************************************************************************************************************************************************/ const R = require('../utils/response.util'); const ROLES = { user: 1, staff: 2, admin: 3 }; /** * Generic role guard factory. * @param {string[]} allowed - list of acc_type values that can pass */ const requireRole = (allowed) => (req, res, next) => { if (!req.user) return R.error(res, 'Authentication required.', 401); if (!allowed.includes(req.user.acc_type)) return R.error(res, 'You do not have permission to access this resource.', 403); next(); }; /** Any logged-in user (client, staff, admin) */ const requireClient = () => requireRole(['user', 'staff', 'admin']); /** Staff or Admin */ const requireStaff = () => requireRole(['staff', 'admin']); /** Admin only */ const requireAdmin = () => requireRole(['admin']); /** * Allows resource owner OR staff/admin. * Reads the owner's user_id from req.params.user_id or req.params.id. */ const requireOwnerOrStaff = () => (req, res, next) => { if (!req.user) return R.error(res, 'Authentication required.', 401); const targetId = Number(req.params.user_id || req.params.id); const isOwner = req.user.user_id === targetId; const elevated = ['staff', 'admin'].includes(req.user.acc_type); if (!isOwner && !elevated) return R.error(res, 'You do not have permission.', 403); next(); }; /** * Allows resource owner OR admin only. */ const requireOwnerOrAdmin = () => (req, res, next) => { if (!req.user) return R.error(res, 'Authentication required.', 401); const targetId = Number(req.params.user_id || req.params.id); const isOwner = req.user.user_id === targetId; const isAdmin = req.user.acc_type === 'admin'; if (!isOwner && !isAdmin) return R.error(res, 'You do not have permission.', 403); next(); }; module.exports = { requireClient, requireStaff, requireAdmin, requireOwnerOrStaff, requireOwnerOrAdmin };