import express from 'express'; import { StatusCodes } from 'http-status-codes'; import SecurityCheckType from '../types/SecurityCheckType'; import logger from '../shared/logging/WinstonLogger'; import ApiRequest from '../types/ApiRequest'; import EnonceManager from '../managers/EnonceManager'; class SecurityMiddleware { // 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.id === 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; case SecurityCheckType.ENONCE_STAFF: isAllowed = isAllowed || await EnonceManager.isUserAllowedToAccessEnonce(req.boundParams.enonce, req.session.profile); break; case SecurityCheckType.ENONCE_IS_PUBLISHED: isAllowed = isAllowed || req.boundParams.enonce.published; 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 new SecurityMiddleware();