import { CanActivate, ExecutionContext, ForbiddenException, Injectable, } from "@nestjs/common"; import { Reflector } from "@nestjs/core"; import { Request } from "express"; import { IS_PUBLIC_KEY, ROLES_KEY } from "../decorators"; import { Role } from "../enums"; import { JwtPayload } from "../types"; @Injectable() export class RolesGuard implements CanActivate { constructor(private readonly reflector: Reflector) {} canActivate(context: ExecutionContext): boolean { const isPublic = this.reflector.getAllAndOverride(IS_PUBLIC_KEY, [ context.getHandler(), context.getClass(), ]); if (isPublic) return true; const requiredRoles = this.reflector.getAllAndOverride(ROLES_KEY, [ context.getHandler(), context.getClass(), ]); if (!requiredRoles || requiredRoles.length === 0) return true; const request = context.switchToHttp().getRequest(); const user: JwtPayload = request["user"] as JwtPayload | undefined; if (!user?.role) { throw new ForbiddenException("No role found in token"); } const hasRole = requiredRoles.includes(user.role as Role); if (!hasRole) { throw new ForbiddenException( `Access denied. Required: [${requiredRoles.join(", ")}]. Your role: ${user.role}`, ); } return true; } }