import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; import { AuthGuard } from '@nestjs/passport'; import { IS_PUBLIC_KEY, PERMISSIONS_KEY } from '../../shared/common/decorators'; import { appForbidden, appUnauthorized } from '../../shared/common/app-error'; @Injectable() export class JwtAuthGuard extends AuthGuard('jwt') { constructor(private reflector: Reflector) { super(); } canActivate(context: ExecutionContext) { const isPublic = this.reflector.getAllAndOverride(IS_PUBLIC_KEY, [ context.getHandler(), context.getClass(), ]); if (isPublic) return true; return super.canActivate(context); } handleRequest(err: Error | null, user: TUser): TUser { if (err || !user) throw err || appUnauthorized('INVALID_CREDENTIALS'); return user; } } @Injectable() export class PermissionsGuard implements CanActivate { constructor(private reflector: Reflector) {} canActivate(context: ExecutionContext): boolean { const required = this.reflector.getAllAndOverride(PERMISSIONS_KEY, [ context.getHandler(), context.getClass(), ]); const { user } = context.switchToHttp().getRequest(); if (!user || user.userType !== 'ADMIN') { throw appForbidden('ADMIN_ACCESS_REQUIRED'); } if (user.role === 'SUPER_ADMIN') return true; if (!required?.length) { throw appForbidden('INSUFFICIENT_PERMISSIONS'); } const userPerms: string[] = user.permissions ?? []; const hasAccess = required.some((p) => userPerms.includes(p)); if (!hasAccess) throw appForbidden('INSUFFICIENT_PERMISSIONS'); return true; } } export function UserTypeGuard(...types: string[]) { @Injectable() class MixedUserTypeGuard implements CanActivate { canActivate(context: ExecutionContext): boolean { const { user } = context.switchToHttp().getRequest(); if (!types.includes(user?.userType)) { throw appForbidden('ACCESS_DENIED_PORTAL'); } return true; } } return MixedUserTypeGuard; } @Injectable() export class PlayerGuard implements CanActivate { constructor(private reflector: Reflector) {} canActivate(context: ExecutionContext): boolean { const isPublic = this.reflector.getAllAndOverride(IS_PUBLIC_KEY, [ context.getHandler(), context.getClass(), ]); if (isPublic) return true; const { user } = context.switchToHttp().getRequest(); if (user?.userType !== 'PLAYER') throw appForbidden('PLAYER_ACCESS_ONLY'); return true; } } @Injectable() export class AdminGuard implements CanActivate { canActivate(context: ExecutionContext): boolean { const { user } = context.switchToHttp().getRequest(); if (user?.userType !== 'ADMIN') throw appForbidden('ADMIN_ACCESS_ONLY'); return true; } } @Injectable() export class AgentGuard implements CanActivate { canActivate(context: ExecutionContext): boolean { const { user } = context.switchToHttp().getRequest(); if (user?.userType !== 'AGENT') throw appForbidden('AGENT_ACCESS_ONLY'); return true; } }