@nebular/security
Version:
@nebular/security
248 lines (238 loc) • 10.2 kB
JavaScript
import * as i0 from '@angular/core';
import { InjectionToken, Injectable, Optional, Inject, Directive, Input, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { map, takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs';
const NB_SECURITY_OPTIONS_TOKEN = new InjectionToken('Nebular Security Options');
/**
* @license
* Copyright Akveo. All Rights Reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/
const shallowObjectClone = (o) => Object.assign({}, o);
const shallowArrayClone = (a) => Object.assign([], a);
const popParent = (abilities) => {
const parent = abilities.parent;
delete abilities.parent;
return parent;
};
/**
* Common acl service.
*/
class NbAclService {
static { this.ANY_RESOURCE = '*'; }
constructor(settings = {}) {
this.settings = settings;
this.state = {};
if (settings.accessControl) {
this.setAccessControl(settings.accessControl);
}
}
/**
* Set/Reset ACL list
* @param {NbAccessControl} list
*/
setAccessControl(list) {
for (const [role, value] of Object.entries(list)) {
const abilities = shallowObjectClone(value);
const parent = popParent(abilities);
this.register(role, parent, abilities);
}
}
/**
* Register a new role with a list of abilities (permission/resources combinations)
* @param {string} role
* @param {string} parent
* @param {[permission: string]: string|string[]} abilities
*/
register(role, parent = null, abilities = {}) {
this.validateRole(role);
this.state[role] = {
parent: parent,
};
for (const [permission, value] of Object.entries(abilities)) {
const resources = typeof value === 'string' ? [value] : value;
this.allow(role, permission, shallowArrayClone(resources));
}
}
/**
* Allow a permission for specific resources to a role
* @param {string} role
* @param {string} permission
* @param {string | string[]} resource
*/
allow(role, permission, resource) {
this.validateRole(role);
if (!this.getRole(role)) {
this.register(role, null, {});
}
resource = typeof resource === 'string' ? [resource] : resource;
let resources = shallowArrayClone(this.getRoleResources(role, permission));
resources = resources.concat(resource);
this.state[role][permission] = resources.filter((item, pos) => resources.indexOf(item) === pos);
}
/**
* Check whether the role has a permission to a resource
* @param {string} role
* @param {string} permission
* @param {string} resource
* @returns {boolean}
*/
can(role, permission, resource) {
this.validateResource(resource);
const parentRole = this.getRoleParent(role);
const parentCan = parentRole && this.can(this.getRoleParent(role), permission, resource);
return parentCan || this.exactCan(role, permission, resource);
}
getRole(role) {
return this.state[role];
}
validateRole(role) {
if (!role) {
throw new Error('NbAclService: role name cannot be empty');
}
}
validateResource(resource) {
if (!resource || [NbAclService.ANY_RESOURCE].includes(resource)) {
throw new Error(`NbAclService: cannot use empty or bulk '*' resource placeholder with 'can' method`);
}
}
exactCan(role, permission, resource) {
const resources = this.getRoleResources(role, permission);
return resources.includes(resource) || resources.includes(NbAclService.ANY_RESOURCE);
}
getRoleResources(role, permission) {
return this.getRoleAbilities(role)[permission] || [];
}
getRoleAbilities(role) {
const abilities = shallowObjectClone(this.state[role] || {});
popParent(shallowObjectClone(this.state[role] || {}));
return abilities;
}
getRoleParent(role) {
return this.state[role] ? this.state[role].parent : null;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: NbAclService, deps: [{ token: NB_SECURITY_OPTIONS_TOKEN, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: NbAclService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: NbAclService, decorators: [{
type: Injectable
}], ctorParameters: () => [{ type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: [NB_SECURITY_OPTIONS_TOKEN]
}] }] });
class NbRoleProvider {
}
/**
* @license
* Copyright Akveo. All Rights Reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/
/**
* Access checker service.
*
* Injects `NbRoleProvider` to determine current user role, and checks access permissions using `NbAclService`
*/
class NbAccessChecker {
constructor(roleProvider, acl) {
this.roleProvider = roleProvider;
this.acl = acl;
}
/**
* Checks whether access is granted or not
*
* @param {string} permission
* @param {string} resource
* @returns {Observable<boolean>}
*/
isGranted(permission, resource) {
return this.roleProvider.getRole()
.pipe(map((role) => Array.isArray(role) ? role : [role]), map((roles) => {
return roles.some(role => this.acl.can(role, permission, resource));
}));
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: NbAccessChecker, deps: [{ token: NbRoleProvider }, { token: NbAclService }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: NbAccessChecker }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: NbAccessChecker, decorators: [{
type: Injectable
}], ctorParameters: () => [{ type: NbRoleProvider }, { type: NbAclService }] });
class NbIsGrantedDirective {
constructor(templateRef, viewContainer, accessChecker) {
this.templateRef = templateRef;
this.viewContainer = viewContainer;
this.accessChecker = accessChecker;
this.destroy$ = new Subject();
this.hasView = false;
}
set nbIsGranted([permission, resource]) {
this.accessChecker.isGranted(permission, resource)
.pipe(takeUntil(this.destroy$))
.subscribe((can) => {
if (can && !this.hasView) {
this.viewContainer.createEmbeddedView(this.templateRef);
this.hasView = true;
}
else if (!can && this.hasView) {
this.viewContainer.clear();
this.hasView = false;
}
});
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: NbIsGrantedDirective, deps: [{ token: i0.TemplateRef }, { token: i0.ViewContainerRef }, { token: NbAccessChecker }], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.1.6", type: NbIsGrantedDirective, isStandalone: false, selector: "[nbIsGranted]", inputs: { nbIsGranted: "nbIsGranted" }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: NbIsGrantedDirective, decorators: [{
type: Directive,
args: [{
selector: '[nbIsGranted]',
standalone: false
}]
}], ctorParameters: () => [{ type: i0.TemplateRef }, { type: i0.ViewContainerRef }, { type: NbAccessChecker }], propDecorators: { nbIsGranted: [{
type: Input
}] } });
class NbSecurityModule {
static forRoot(nbSecurityOptions) {
return {
ngModule: NbSecurityModule,
providers: [
{ provide: NB_SECURITY_OPTIONS_TOKEN, useValue: nbSecurityOptions },
NbAclService,
NbAccessChecker,
],
};
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: NbSecurityModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.1.6", ngImport: i0, type: NbSecurityModule, declarations: [NbIsGrantedDirective], imports: [CommonModule], exports: [NbIsGrantedDirective] }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: NbSecurityModule, imports: [CommonModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.6", ngImport: i0, type: NbSecurityModule, decorators: [{
type: NgModule,
args: [{
imports: [
CommonModule,
],
declarations: [
NbIsGrantedDirective,
],
exports: [
NbIsGrantedDirective,
],
}]
}] });
/**
* @license
* Copyright Akveo. All Rights Reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*/
/**
* Generated bundle index. Do not edit.
*/
export { NB_SECURITY_OPTIONS_TOKEN, NbAccessChecker, NbAclService, NbIsGrantedDirective, NbRoleProvider, NbSecurityModule };
//# sourceMappingURL=nebular-security.mjs.map