All files / modules/rbac/guards permissions.guard.ts

36.36% Statements 20/55
10.52% Branches 2/19
37.5% Functions 3/8
28.57% Lines 14/49

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 1234x           4x 4x   4x 4x   4x 25x 25x 25x     4x             4x   50x 50x                                                                                                                   4x                                                                        
import {
  Injectable,
  CanActivate,
  ExecutionContext,
  ForbiddenException,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { RbacService } from '../services/rbac.service';
 
export const PERMISSIONS_KEY = 'permissions';
export const ROLES_KEY = 'roles';
 
export const RequirePermissions = (...permissions: string[]) =>
  (target: any, key?: string, descriptor?: PropertyDescriptor) => {
    Reflect.defineMetadata(PERMISSIONS_KEY, permissions, descriptor?.value || target);
    return descriptor || target;
  };
 
export const RequireRoles = (...roles: string[]) =>
  (target: any, key?: string, descriptor?: PropertyDescriptor) => {
    Reflect.defineMetadata(ROLES_KEY, roles, descriptor?.value || target);
    return descriptor || target;
  };
 
@Injectable()
export class PermissionsGuard implements CanActivate {
  constructor(
    private reflector: Reflector,
    private rbacService: RbacService,
  ) {}
 
  async canActivate(context: ExecutionContext): Promise<boolean> {
    // Get required permissions from decorator
    const requiredPermissions = this.reflector.getAllAndOverride<string[]>(
      PERMISSIONS_KEY,
      [context.getHandler(), context.getClass()],
    );
 
    // Get required roles from decorator
    const requiredRoles = this.reflector.getAllAndOverride<string[]>(ROLES_KEY, [
      context.getHandler(),
      context.getClass(),
    ]);
 
    // If no requirements, allow access
    Iif (!requiredPermissions?.length && !requiredRoles?.length) {
      return true;
    }
 
    const request = context.switchToHttp().getRequest();
    const user = request.user;
 
    Iif (!user) {
      throw new ForbiddenException('Usuario no autenticado');
    }
 
    const { id: userId, tenant_id: tenantId } = user;
 
    // Check roles if required
    Iif (requiredRoles?.length) {
      for (const role of requiredRoles) {
        const hasRole = await this.rbacService.userHasRole(userId, tenantId, role);
        Iif (hasRole) {
          return true; // User has at least one required role
        }
      }
    }
 
    // Check permissions if required
    Iif (requiredPermissions?.length) {
      const hasPermission = await this.rbacService.userHasAnyPermission(
        userId,
        tenantId,
        requiredPermissions,
      );
 
      Iif (hasPermission) {
        return true;
      }
    }
 
    throw new ForbiddenException('No tiene permisos suficientes para esta acción');
  }
}
 
@Injectable()
export class AllPermissionsGuard implements CanActivate {
  constructor(
    private reflector: Reflector,
    private rbacService: RbacService,
  ) {}
 
  async canActivate(context: ExecutionContext): Promise<boolean> {
    const requiredPermissions = this.reflector.getAllAndOverride<string[]>(
      PERMISSIONS_KEY,
      [context.getHandler(), context.getClass()],
    );
 
    Iif (!requiredPermissions?.length) {
      return true;
    }
 
    const request = context.switchToHttp().getRequest();
    const user = request.user;
 
    Iif (!user) {
      throw new ForbiddenException('Usuario no autenticado');
    }
 
    const hasAll = await this.rbacService.userHasAllPermissions(
      user.id,
      user.tenant_id,
      requiredPermissions,
    );
 
    Iif (!hasAll) {
      throw new ForbiddenException('No tiene todos los permisos requeridos');
    }
 
    return true;
  }
}