import express from 'express'; import { StatusCodes } from 'http-status-codes'; import SecurityCheckType from '../types/SecurityCheckType.js'; import logger from '../shared/logging/WinstonLogger.js'; import AssignmentManager from '../managers/AssignmentManager.js'; class SecurityMiddleware { private checkIfConnected(checkIfConnected: boolean, req: express.Request): boolean { return !checkIfConnected || (req.session.profile !== null && req.session.profile !== undefined); } private async checkType(checkType: SecurityCheckType, req: express.Request): Promise<boolean> { try { switch ( String(checkType) ) { case SecurityCheckType.ADMIN.valueOf(): return req.session.profile.isAdmin; case SecurityCheckType.TEACHING_STAFF.valueOf(): return req.session.profile.isTeachingStaff; case SecurityCheckType.ASSIGNMENT_STAFF.valueOf(): return await AssignmentManager.isUserAllowedToAccessAssignment(req.boundParams.assignment!, req.session.profile); case SecurityCheckType.ASSIGNMENT_IS_PUBLISHED.valueOf(): return req.boundParams.assignment?.published ?? false; case SecurityCheckType.EXERCISE_SECRET.valueOf(): return (req.headers.exercisesecret as string | undefined) === req.boundParams.exercise!.secret; default: return false; } } catch ( e ) { logger.error('Security check failed !!! => ' + JSON.stringify(e)); return false; } } // First check if connected then check if at least ONE rule match. It's NOT an AND but it's a OR function. check(checkIfConnected: boolean, ...checkTypes: Array<SecurityCheckType>): (req: express.Request, res: express.Response, next: express.NextFunction) => void { return (req: express.Request, res: express.Response, next: express.NextFunction) => { if ( !this.checkIfConnected(checkIfConnected, req) ) { return req.session.sendResponse(res, StatusCodes.UNAUTHORIZED); } const isAllowed: boolean = checkTypes.length === 0 ? true : checkTypes.find(async checkType => this.checkType(checkType, req)) !== undefined; if ( !isAllowed ) { return req.session.sendResponse(res, StatusCodes.FORBIDDEN); } return next(); }; } } export default new SecurityMiddleware();