import express from 'express'; import { StatusCodes } from 'http-status-codes'; import SecurityCheckType from '../types/SecurityCheckType'; import logger from '../shared/logging/WinstonLogger'; import ApiRequest from '../models/ApiRequest'; class SecurityMiddleware { private static _instance: SecurityMiddleware; private constructor() { } public static get instance(): SecurityMiddleware { if ( !SecurityMiddleware._instance ) { SecurityMiddleware._instance = new SecurityMiddleware(); } return SecurityMiddleware._instance; } // 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: ApiRequest, res: express.Response, next: express.NextFunction) => void { return async (req: ApiRequest, res: express.Response, next: express.NextFunction) => { if ( checkIfConnected ) { if ( req.session.profile.userID === null ) { return req.session.sendResponse(res, StatusCodes.UNAUTHORIZED); } } let isAllowed = checkTypes.length === 0; if ( !isAllowed ) { for ( let checkType of checkTypes ) { try { switch ( checkType ) { case SecurityCheckType.TEACHING_STAFF: isAllowed = isAllowed || req.session.profile.isTeachingStaff; break; default: isAllowed = isAllowed || false; break; } } catch ( e ) { logger.error('Security check failed !!! => ' + e); isAllowed = isAllowed || false; } } } if ( !isAllowed ) { return req.session.sendResponse(res, StatusCodes.FORBIDDEN); } return next(); }; } } export default SecurityMiddleware.instance;