UNPKG

@elsikora/nestjs-crud-automator

Version:

A library for automating the creation of CRUD operations in NestJS.

80 lines (77 loc) 4.29 kB
import { __decorate, __param, __metadata } from '../../../external/tslib/tslib.es6.js'; import { ApiAuthorizationEngine } from './engine.class.js'; import { AUTHORIZATION_DECISION_METADATA_CONSTANT } from '../../../constant/class/authorization/metadata/decision.constant.js'; import { AUTHORIZATION_POLICY_REGISTRY_TOKEN } from '../../../constant/class/authorization/token/registry.constant.js'; import { CONTROLLER_API_DECORATOR_CONSTANT } from '../../../constant/decorator/api/controller.constant.js'; import { EAuthorizationEffect } from '../../../enum/class/authorization/effect.enum.js'; import { Injectable, Inject, ForbiddenException } from '@nestjs/common'; import { AuthorizationResolveDefaultSubject } from '../../../utility/authorization/subject/resolve-default-subject.utility.js'; import { LoggerUtility } from '../../../utility/logger.utility.js'; const authorizationGuardLogger = LoggerUtility.getLogger("ApiAuthorizationGuard"); let ApiAuthorizationGuard = class ApiAuthorizationGuard { policyRegistry; authorizationEngine; constructor(policyRegistry, authorizationEngine) { this.policyRegistry = policyRegistry; this.authorizationEngine = authorizationEngine; } async canActivate(context) { if (!this.isControllerSecurable(context)) { authorizationGuardLogger.debug("Controller is not marked as @ApiControllerSecurable, skipping authorization"); return true; } const entityConstructor = this.resolveEntityConstructor(context); if (!entityConstructor) { authorizationGuardLogger.debug("No entity constructor found in controller metadata, skipping authorization"); return true; } const action = this.resolveAction(context); authorizationGuardLogger.verbose(`Evaluating authorization for entity "${entityConstructor.name}" action "${action}"`); const policy = await this.policyRegistry.buildAggregatedPolicy(entityConstructor, action); if (!policy) { authorizationGuardLogger.debug(`No policy found for entity "${entityConstructor.name}" action "${action}", allowing access`); return true; } authorizationGuardLogger.verbose(`Found policy "${policy.policyId}" with ${policy.rules.length} rules for entity "${entityConstructor.name}" action "${action}"`); const request = context.switchToHttp().getRequest(); const subject = AuthorizationResolveDefaultSubject(request.user); const decision = await this.authorizationEngine.evaluate({ action, policy, resource: undefined, subject, }); this.attachDecisionToRequest(request, decision); if (decision.effect === EAuthorizationEffect.DENY) { authorizationGuardLogger.warn(`Access denied for entity "${entityConstructor.name}" action "${action}" subject "${subject.id}"`); throw new ForbiddenException("Access denied"); } authorizationGuardLogger.verbose(`Access granted for entity "${entityConstructor.name}" action "${action}" subject "${subject.id}"`); return true; } attachDecisionToRequest(request, decision) { request.authorizationDecision = decision; request[AUTHORIZATION_DECISION_METADATA_CONSTANT.REQUEST_KEY] = decision; } isControllerSecurable(context) { return Boolean(Reflect.getMetadata(CONTROLLER_API_DECORATOR_CONSTANT.SECURABLE_METADATA_KEY, context.getClass())); } resolveAction(context) { const handlerName = context.getHandler().name; const prefix = CONTROLLER_API_DECORATOR_CONSTANT.RESERVED_METHOD_PREFIX ?? ""; if (handlerName.startsWith(prefix)) { return handlerName.slice(prefix.length); } return handlerName; } resolveEntityConstructor(context) { return Reflect.getMetadata(CONTROLLER_API_DECORATOR_CONSTANT.ENTITY_METADATA_KEY, context.getClass()); } }; ApiAuthorizationGuard = __decorate([ Injectable(), __param(0, Inject(AUTHORIZATION_POLICY_REGISTRY_TOKEN)), __metadata("design:paramtypes", [Object, ApiAuthorizationEngine]) ], ApiAuthorizationGuard); export { ApiAuthorizationGuard }; //# sourceMappingURL=guard.class.js.map