# 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;
      }
    }