import { CanActivate, ExecutionContext, ForbiddenException, Injectable, } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; import { ROLES_KEY } from '../decorators/roles.decorators'; import { Roles } from '.prisma/client'; interface RequestWithUser extends Request { // TODO: Create an actual user model based on OAuth signin user: any; } @Injectable() export class RolesGuard implements CanActivate { constructor(private reflector: Reflector) { } /** * @swagger * @function canActivate * @description * Authorization guard that checks whether the current user has one of the required roles * to access a specific route handler. It uses metadata defined by the `@Roles()` decorator * and verifies the user's role accordingly. * * If no roles are specified for the route, access is granted by default. * If the user is not authenticated or does not have a required role, access is denied. * * @param {ExecutionContext} ctx - The current execution context, which provides access * to route metadata and the HTTP request. * * @returns {boolean} - Returns `true` if access is allowed, otherwise throws a `ForbiddenException` * or returns `false` if the user is not authenticated. */ canActivate(ctx: ExecutionContext): boolean { const requiredRoles = this.reflector.getAllAndOverride( ROLES_KEY, [ctx.getHandler(), ctx.getClass()], ); //for "deny-by-default" when role is wrong or unavailable if (!requiredRoles || requiredRoles.length === 0) { return true; } const request = ctx.switchToHttp().getRequest(); const user = request.user; if (!user) { return false; } if (!requiredRoles.includes(user.role)) { throw new ForbiddenException( `The role ${user.role} is not authorized to access this resource.`, ); } return true; } }