@elsikora/nestjs-crud-automator
Version:
A library for automating the creation of CRUD operations in NestJS.
80 lines (77 loc) • 4.29 kB
JavaScript
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