mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-19 14:20:31 +00:00
fix(server): premissions guard for read and write endpoints
This commit is contained in:
67
packages/server/src/modules/Roles/Permission.guard.ts
Normal file
67
packages/server/src/modules/Roles/Permission.guard.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import {
|
||||
Injectable,
|
||||
CanActivate,
|
||||
ExecutionContext,
|
||||
ForbiddenException,
|
||||
} from '@nestjs/common';
|
||||
import { Reflector } from '@nestjs/core';
|
||||
import { Request } from 'express';
|
||||
import { REQUIRED_PERMISSION_KEY, RequiredPermission } from './RequirePermission.decorator';
|
||||
import { AbilitySubject } from './Roles.types';
|
||||
|
||||
/**
|
||||
* Guard that checks if the user has the required permission to access a route.
|
||||
* Uses CASL ability instance attached to the request by AuthorizationGuard.
|
||||
*/
|
||||
@Injectable()
|
||||
export class PermissionGuard implements CanActivate {
|
||||
constructor(private readonly reflector: Reflector) {}
|
||||
|
||||
/**
|
||||
* Checks if the user has the required permission to access the route.
|
||||
* @param context - The execution context
|
||||
* @returns A boolean indicating if the user can access the route
|
||||
* @throws ForbiddenException if the user doesn't have the required permission
|
||||
*/
|
||||
canActivate(context: ExecutionContext): boolean {
|
||||
const requiredPermission = this.reflector.getAllAndOverride<RequiredPermission>(
|
||||
REQUIRED_PERMISSION_KEY,
|
||||
[context.getHandler(), context.getClass()],
|
||||
);
|
||||
|
||||
// If no permission is required, allow access
|
||||
if (!requiredPermission) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const request = context.switchToHttp().getRequest<Request>();
|
||||
const ability = (request as any).ability;
|
||||
|
||||
// If no ability instance is attached to the request, deny access
|
||||
if (!ability) {
|
||||
throw new ForbiddenException('Ability instance not found. Ensure AuthorizationGuard is applied.');
|
||||
}
|
||||
|
||||
const { ability: action, subject } = requiredPermission;
|
||||
|
||||
// Check if the user has the required permission using CASL ability
|
||||
const hasPermission = ability.can(action, subject);
|
||||
|
||||
if (!hasPermission) {
|
||||
throw new ForbiddenException(
|
||||
`You do not have permission to ${action} ${subject}`,
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to check if a subject value is a valid AbilitySubject.
|
||||
* @param subject - The subject value to check
|
||||
* @returns True if the subject is a valid AbilitySubject enum value
|
||||
*/
|
||||
private isValidSubject(subject: string): subject is AbilitySubject {
|
||||
return Object.values(AbilitySubject).includes(subject as AbilitySubject);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user