import { AuthenticationInfo } from '../authentication-info.js'; import { AuthenticatedRequest } from '../authenticated-request.js'; import * as express from 'express'; import { RequestHandler } from 'express'; import { UnauthorizedException } from '../../../exceptions/unauthorized-exception.js'; import { ForbiddenException } from '../../../exceptions/forbidden-exception.js'; import { envVars, getEnvVar } from '../../../util/envVars.js'; import { AccountType } from '@dwengo-1/common/util/account-types'; /** * Middleware which rejects unauthenticated users (with HTTP 401) and authenticated users which do not fulfill * the given access condition. * @param accessCondition Predicate over the current AuthenticationInfo. Access is only granted when this evaluates * to true. */ export function authorize>( accessCondition: (auth: AuthenticationInfo, req: AuthenticatedRequest) => boolean | Promise ): RequestHandler { // Bypass authentication during testing if (getEnvVar(envVars.RunMode) === 'test') { return async ( _req: AuthenticatedRequest, _res: express.Response, next: express.NextFunction ): Promise => { next(); }; } return async ( req: AuthenticatedRequest, _res: express.Response, next: express.NextFunction ): Promise => { if (!req.auth) { throw new UnauthorizedException(); } else if (!(await accessCondition(req.auth, req))) { throw new ForbiddenException(); } else { next(); } }; } /** * Middleware which rejects all unauthenticated users, but accepts all authenticated users. */ export const authenticatedOnly = authorize((_) => true); /** * Middleware which rejects requests from unauthenticated users or users that aren't students. */ export const studentsOnly = authorize((auth) => auth.accountType === AccountType.Student); /** * Middleware which rejects requests from unauthenticated users or users that aren't teachers. */ export const teachersOnly = authorize((auth) => auth.accountType === AccountType.Teacher); /** * Middleware which is to be used on requests no normal user should be able to execute. * Since there is no concept of administrator accounts yet, currently, those requests will always be blocked. */ export const adminOnly = authorize(() => false);