@flusys/nestjs-iam 1.0.0-rc → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +219 -118
- package/cjs/controllers/company-action-permission.controller.js +2 -17
- package/cjs/controllers/my-permission.controller.js +1 -2
- package/cjs/controllers/role-permission.controller.js +3 -9
- package/cjs/controllers/user-action-permission.controller.js +3 -9
- package/cjs/dtos/action.dto.js +0 -27
- package/cjs/dtos/permission.dto.js +81 -27
- package/cjs/dtos/role.dto.js +0 -27
- package/cjs/helpers/company-access.helper.js +19 -0
- package/cjs/helpers/index.js +1 -1
- package/cjs/interfaces/iam-module-options.interface.js +0 -14
- package/cjs/interfaces/index.js +0 -1
- package/cjs/modules/iam.module.js +38 -106
- package/cjs/services/action.service.js +30 -41
- package/cjs/services/iam-config.service.js +2 -5
- package/cjs/services/{iam-datasource.provider.js → iam-datasource.service.js} +33 -36
- package/cjs/services/index.js +1 -1
- package/cjs/services/permission-cache.service.js +6 -46
- package/cjs/services/permission.service.js +52 -41
- package/cjs/services/role.service.js +3 -3
- package/controllers/company-action-permission.controller.d.ts +2 -5
- package/controllers/role-permission.controller.d.ts +0 -1
- package/controllers/user-action-permission.controller.d.ts +0 -1
- package/dtos/action.dto.d.ts +0 -4
- package/dtos/role.dto.d.ts +0 -4
- package/fesm/controllers/company-action-permission.controller.js +4 -19
- package/fesm/controllers/my-permission.controller.js +1 -2
- package/fesm/controllers/role-permission.controller.js +4 -10
- package/fesm/controllers/user-action-permission.controller.js +4 -10
- package/fesm/dtos/action.dto.js +0 -24
- package/fesm/dtos/permission.dto.js +81 -27
- package/fesm/dtos/role.dto.js +0 -24
- package/fesm/helpers/company-access.helper.js +14 -0
- package/fesm/helpers/index.js +1 -1
- package/fesm/interfaces/iam-module-options.interface.js +3 -1
- package/fesm/interfaces/index.js +0 -1
- package/fesm/modules/iam.module.js +40 -108
- package/fesm/services/action.service.js +31 -42
- package/fesm/services/iam-config.service.js +2 -5
- package/fesm/services/{iam-datasource.provider.js → iam-datasource.service.js} +31 -34
- package/fesm/services/index.js +1 -1
- package/fesm/services/permission-cache.service.js +6 -46
- package/fesm/services/permission.service.js +53 -42
- package/fesm/services/role.service.js +3 -3
- package/helpers/company-access.helper.d.ts +3 -0
- package/helpers/index.d.ts +1 -1
- package/interfaces/iam-module-options.interface.d.ts +9 -1
- package/interfaces/index.d.ts +0 -1
- package/modules/iam.module.d.ts +1 -2
- package/package.json +3 -3
- package/services/action.service.d.ts +6 -4
- package/services/iam-config.service.d.ts +0 -1
- package/services/{iam-datasource.provider.d.ts → iam-datasource.service.d.ts} +4 -5
- package/services/index.d.ts +1 -1
- package/services/permission-cache.service.d.ts +1 -4
- package/services/permission.service.d.ts +4 -2
- package/services/role.service.d.ts +3 -3
- package/cjs/helpers/permission-evaluator.helper.js +0 -175
- package/cjs/interfaces/iam-module-async-options.interface.js +0 -4
- package/fesm/helpers/permission-evaluator.helper.js +0 -165
- package/fesm/interfaces/iam-module-async-options.interface.js +0 -3
- package/helpers/permission-evaluator.helper.d.ts +0 -26
- package/interfaces/iam-module-async-options.interface.d.ts +0 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flusys/nestjs-iam",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Identity and Access Management (IAM) module for NestJS applications",
|
|
5
5
|
"main": "cjs/index.js",
|
|
6
6
|
"module": "fesm/index.js",
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"typeorm": "^0.3.0"
|
|
90
90
|
},
|
|
91
91
|
"dependencies": {
|
|
92
|
-
"@flusys/nestjs-core": "
|
|
93
|
-
"@flusys/nestjs-shared": "
|
|
92
|
+
"@flusys/nestjs-core": "2.0.0",
|
|
93
|
+
"@flusys/nestjs-shared": "2.0.0"
|
|
94
94
|
}
|
|
95
95
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { HybridCache, RequestScopedApiService } from '@flusys/nestjs-shared/classes';
|
|
2
2
|
import { ILoggedUserInfo } from '@flusys/nestjs-shared/interfaces';
|
|
3
3
|
import { UtilsService } from '@flusys/nestjs-shared/modules';
|
|
4
4
|
import { EntityTarget, Repository, SelectQueryBuilder } from 'typeorm';
|
|
@@ -6,7 +6,7 @@ import { CreateActionDto, UpdateActionDto } from '../dtos/action.dto';
|
|
|
6
6
|
import { ActionBase } from '../entities/action-base.entity';
|
|
7
7
|
import { IAction, IActionTree } from '../interfaces/action.interface';
|
|
8
8
|
import { IAMConfigService } from './iam-config.service';
|
|
9
|
-
import {
|
|
9
|
+
import { IAMDataSourceService } from './iam-datasource.service';
|
|
10
10
|
import { PermissionService } from './permission.service';
|
|
11
11
|
export declare class ActionService extends RequestScopedApiService<CreateActionDto, UpdateActionDto, IAction, ActionBase, Repository<ActionBase>> {
|
|
12
12
|
protected cacheManager: HybridCache;
|
|
@@ -14,9 +14,9 @@ export declare class ActionService extends RequestScopedApiService<CreateActionD
|
|
|
14
14
|
private readonly iamConfigService;
|
|
15
15
|
private readonly dataSourceProvider;
|
|
16
16
|
private readonly permissionService;
|
|
17
|
-
constructor(cacheManager: HybridCache, utilsService: UtilsService, iamConfigService: IAMConfigService, dataSourceProvider:
|
|
17
|
+
constructor(cacheManager: HybridCache, utilsService: UtilsService, iamConfigService: IAMConfigService, dataSourceProvider: IAMDataSourceService, permissionService: PermissionService);
|
|
18
18
|
protected resolveEntity(): EntityTarget<ActionBase>;
|
|
19
|
-
protected getDataSourceProvider():
|
|
19
|
+
protected getDataSourceProvider(): IAMDataSourceService;
|
|
20
20
|
getSelectQuery(query: SelectQueryBuilder<ActionBase>, _user: ILoggedUserInfo | null, select?: string[]): Promise<{
|
|
21
21
|
query: SelectQueryBuilder<ActionBase>;
|
|
22
22
|
isRaw: boolean;
|
|
@@ -26,6 +26,8 @@ export declare class ActionService extends RequestScopedApiService<CreateActionD
|
|
|
26
26
|
isRaw: boolean;
|
|
27
27
|
}>;
|
|
28
28
|
protected convertEntityToResponseDto(entity: ActionBase, _isRaw: boolean): IAction;
|
|
29
|
+
private readonly actionSelectFields;
|
|
30
|
+
private requireUser;
|
|
29
31
|
getActionsForPermission(user: ILoggedUserInfo): Promise<IAction[]>;
|
|
30
32
|
getActionTree(user: ILoggedUserInfo, search?: string, isActive?: boolean, withDeleted?: boolean): Promise<IActionTree[]>;
|
|
31
33
|
private buildActionTree;
|
|
@@ -7,7 +7,6 @@ export declare class IAMConfigService implements IModuleConfigService {
|
|
|
7
7
|
constructor(injectedOptions?: IAMModuleOptions);
|
|
8
8
|
getDatabaseMode(): DatabaseMode;
|
|
9
9
|
isMultiTenant(): boolean;
|
|
10
|
-
getEnableCompanyFeature(): boolean;
|
|
11
10
|
isCompanyFeatureEnabled(): boolean;
|
|
12
11
|
getPermissionMode(): IAMPermissionMode;
|
|
13
12
|
isRbacEnabled(): boolean;
|
|
@@ -3,9 +3,9 @@ import { IDatabaseConfig, ITenantDatabaseConfig } from '@flusys/nestjs-core';
|
|
|
3
3
|
import { Logger } from '@nestjs/common';
|
|
4
4
|
import { Request } from 'express';
|
|
5
5
|
import { DataSource } from 'typeorm';
|
|
6
|
-
import {
|
|
7
|
-
export declare class
|
|
8
|
-
private readonly
|
|
6
|
+
import { IAMConfigService } from './iam-config.service';
|
|
7
|
+
export declare class IAMDataSourceService extends MultiTenantDataSourceService {
|
|
8
|
+
private readonly configService;
|
|
9
9
|
protected readonly logger: Logger;
|
|
10
10
|
protected static readonly tenantConnections: Map<string, DataSource>;
|
|
11
11
|
protected static singleDataSource: DataSource | null;
|
|
@@ -13,9 +13,8 @@ export declare class IAMDataSourceProvider extends MultiTenantDataSourceService
|
|
|
13
13
|
protected static initialized: boolean;
|
|
14
14
|
protected static readonly connectionLocks: Map<string, Promise<DataSource>>;
|
|
15
15
|
protected static singleConnectionLock: Promise<DataSource> | null;
|
|
16
|
-
constructor(
|
|
16
|
+
constructor(configService: IAMConfigService, request?: Request);
|
|
17
17
|
private static buildParentOptions;
|
|
18
|
-
getEnableCompanyFeature(): boolean;
|
|
19
18
|
getEnableCompanyFeatureForTenant(tenant?: ITenantDatabaseConfig): boolean;
|
|
20
19
|
getEnableCompanyFeatureForCurrentTenant(): boolean;
|
|
21
20
|
getIAMEntities(): Promise<any[]>;
|
package/services/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export * from './action.service';
|
|
2
2
|
export * from './iam-config.service';
|
|
3
|
-
export * from './iam-datasource.
|
|
3
|
+
export * from './iam-datasource.service';
|
|
4
4
|
export * from './permission-cache.service';
|
|
5
5
|
export * from './permission.service';
|
|
6
6
|
export * from './role.service';
|
|
@@ -26,17 +26,14 @@ export declare class PermissionCacheService {
|
|
|
26
26
|
constructor(cacheManager: HybridCache);
|
|
27
27
|
generateCacheKey(options: PermissionCacheKeyOptions): string;
|
|
28
28
|
generateMyPermissionsCacheKey(options: PermissionCacheKeyOptions): string;
|
|
29
|
+
private buildCacheKey;
|
|
29
30
|
setPermissions(options: PermissionCacheKeyOptions, permissions: string[]): Promise<void>;
|
|
30
|
-
getPermissions(options: PermissionCacheKeyOptions): Promise<string[] | null>;
|
|
31
31
|
setMyPermissions(options: PermissionCacheKeyOptions, data: CachedMyPermissions): Promise<void>;
|
|
32
32
|
getMyPermissions(options: PermissionCacheKeyOptions): Promise<CachedMyPermissions | null>;
|
|
33
33
|
private generateActionCodeCacheKey;
|
|
34
34
|
setActionCodeMap(codeToIdMap: Record<string, string>, tenantId?: string): Promise<void>;
|
|
35
35
|
getActionIdsByCodes(codes: string[], tenantId?: string): Promise<Record<string, string> | null>;
|
|
36
|
-
invalidateActionCodeCache(tenantId?: string): Promise<void>;
|
|
37
36
|
invalidateUser(userId: string, companyId?: string | null, branchIds?: (string | null)[]): Promise<void>;
|
|
38
37
|
invalidateUsers(userIds: string[], companyId?: string | null, branchIds?: (string | null)[]): Promise<number>;
|
|
39
|
-
invalidateCompany(companyId: string): Promise<number>;
|
|
40
38
|
invalidateRole(roleId: string, userIds: string[], companyId?: string | null, branchIds?: (string | null)[]): Promise<number>;
|
|
41
|
-
clearAll(): Promise<void>;
|
|
42
39
|
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { AssignCompanyActionsDto, AssignRoleActionsDto, AssignUserActionsDto, AssignUserRolesDto, CompanyActionResponseDto, MyPermissionsResponseDto, PermissionOperationResultDto, RoleActionResponseDto, UserActionResponseDto, UserRoleResponseDto } from '../dtos/permission.dto';
|
|
2
2
|
import { IAMConfigService } from './iam-config.service';
|
|
3
|
-
import {
|
|
3
|
+
import { IAMDataSourceService } from './iam-datasource.service';
|
|
4
4
|
import { PermissionCacheService } from './permission-cache.service';
|
|
5
5
|
export declare class PermissionService {
|
|
6
6
|
private readonly permissionCacheService;
|
|
7
7
|
private readonly iamConfigService;
|
|
8
8
|
private readonly dataSourceProvider;
|
|
9
9
|
private readonly logger;
|
|
10
|
-
constructor(permissionCacheService: PermissionCacheService, iamConfigService: IAMConfigService, dataSourceProvider:
|
|
10
|
+
constructor(permissionCacheService: PermissionCacheService, iamConfigService: IAMConfigService, dataSourceProvider: IAMDataSourceService);
|
|
11
11
|
private getPermissionRepository;
|
|
12
12
|
private getActionRepository;
|
|
13
13
|
private getRoleRepository;
|
|
@@ -30,6 +30,8 @@ export declare class PermissionService {
|
|
|
30
30
|
private collectAllActionIds;
|
|
31
31
|
private applyCompanyWhitelist;
|
|
32
32
|
private buildAndCachePermissionData;
|
|
33
|
+
private splitItemsByAction;
|
|
34
|
+
private buildOperationResult;
|
|
33
35
|
private getUserRoleIds;
|
|
34
36
|
private getRoleActionIds;
|
|
35
37
|
private getUserActionIds;
|
|
@@ -6,15 +6,15 @@ import { CreateRoleDto, UpdateRoleDto } from '../dtos/role.dto';
|
|
|
6
6
|
import { RoleBase } from '../entities/role-base.entity';
|
|
7
7
|
import { IRole } from '../interfaces/role.interface';
|
|
8
8
|
import { IAMConfigService } from './iam-config.service';
|
|
9
|
-
import {
|
|
9
|
+
import { IAMDataSourceService } from './iam-datasource.service';
|
|
10
10
|
export declare class RoleService extends RequestScopedApiService<CreateRoleDto, UpdateRoleDto, IRole, RoleBase, Repository<RoleBase>> {
|
|
11
11
|
protected cacheManager: HybridCache;
|
|
12
12
|
protected utilsService: UtilsService;
|
|
13
13
|
private readonly iamConfigService;
|
|
14
14
|
private readonly dataSourceProvider;
|
|
15
|
-
constructor(cacheManager: HybridCache, utilsService: UtilsService, iamConfigService: IAMConfigService, dataSourceProvider:
|
|
15
|
+
constructor(cacheManager: HybridCache, utilsService: UtilsService, iamConfigService: IAMConfigService, dataSourceProvider: IAMDataSourceService);
|
|
16
16
|
protected resolveEntity(): EntityTarget<RoleBase>;
|
|
17
|
-
protected getDataSourceProvider():
|
|
17
|
+
protected getDataSourceProvider(): IAMDataSourceService;
|
|
18
18
|
convertSingleDtoToEntity(dto: CreateRoleDto | UpdateRoleDto, user: ILoggedUserInfo | null): Promise<RoleBase>;
|
|
19
19
|
getSelectQuery(query: SelectQueryBuilder<RoleBase>, _user: ILoggedUserInfo | null, select?: string[]): Promise<{
|
|
20
20
|
query: SelectQueryBuilder<RoleBase>;
|
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", {
|
|
3
|
-
value: true
|
|
4
|
-
});
|
|
5
|
-
Object.defineProperty(exports, "PermissionEvaluatorHelper", {
|
|
6
|
-
enumerable: true,
|
|
7
|
-
get: function() {
|
|
8
|
-
return PermissionEvaluatorHelper;
|
|
9
|
-
}
|
|
10
|
-
});
|
|
11
|
-
const _common = require("@nestjs/common");
|
|
12
|
-
function _ts_decorate(decorators, target, key, desc) {
|
|
13
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
14
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
15
|
-
else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
16
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
17
|
-
}
|
|
18
|
-
let PermissionEvaluatorHelper = class PermissionEvaluatorHelper {
|
|
19
|
-
/**
|
|
20
|
-
* Evaluate if user has access based on permission logic
|
|
21
|
-
*
|
|
22
|
-
* @param logic - Permission logic to evaluate
|
|
23
|
-
* @param context - User permission context
|
|
24
|
-
* @returns true if user has access, false otherwise
|
|
25
|
-
*/ evaluate(logic, context) {
|
|
26
|
-
// If no logic defined, access is granted
|
|
27
|
-
if (!logic) {
|
|
28
|
-
return true;
|
|
29
|
-
}
|
|
30
|
-
return this.evaluateNode(logic, context);
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Evaluate a single logic node
|
|
34
|
-
*/ evaluateNode(node, context) {
|
|
35
|
-
switch(node.type){
|
|
36
|
-
case 'action':
|
|
37
|
-
return this.evaluateAction(node.actionId, context);
|
|
38
|
-
case 'group':
|
|
39
|
-
return this.evaluateGroup(node, context);
|
|
40
|
-
default:
|
|
41
|
-
// Unknown node type, deny access
|
|
42
|
-
return false;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Evaluate action permission
|
|
47
|
-
* Priority: Deny > Grant > Inherited
|
|
48
|
-
*/ evaluateAction(actionId, context) {
|
|
49
|
-
// 1. Check explicit deny (highest priority)
|
|
50
|
-
if (context.deniedActionIds.has(actionId)) {
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
53
|
-
// 2. Check explicit grant
|
|
54
|
-
if (context.grantedActionIds.has(actionId)) {
|
|
55
|
-
return true;
|
|
56
|
-
}
|
|
57
|
-
// 3. Check inherited actions (from parent actions)
|
|
58
|
-
if (context.inheritedActionIds?.has(actionId)) {
|
|
59
|
-
return true;
|
|
60
|
-
}
|
|
61
|
-
// No permission found
|
|
62
|
-
return false;
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Evaluate group (AND/OR logic)
|
|
66
|
-
*/ evaluateGroup(node, context) {
|
|
67
|
-
if (!node.children || node.children.length === 0) {
|
|
68
|
-
return false;
|
|
69
|
-
}
|
|
70
|
-
const results = node.children.map((child)=>this.evaluateNode(child, context));
|
|
71
|
-
if (node.operator === 'AND') {
|
|
72
|
-
// ALL children must be true
|
|
73
|
-
return results.every((result)=>result === true);
|
|
74
|
-
} else if (node.operator === 'OR') {
|
|
75
|
-
// ANY child must be true
|
|
76
|
-
return results.some((result)=>result === true);
|
|
77
|
-
}
|
|
78
|
-
// Unknown operator, deny access
|
|
79
|
-
return false;
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* Batch evaluate multiple logic nodes
|
|
83
|
-
* Useful for checking multiple permissions at once
|
|
84
|
-
*
|
|
85
|
-
* @param logics - Array of logic nodes to evaluate
|
|
86
|
-
* @param context - User permission context
|
|
87
|
-
* @returns Map of logic ID to evaluation result
|
|
88
|
-
*/ batchEvaluate(logics, context) {
|
|
89
|
-
const results = new Map();
|
|
90
|
-
for (const item of logics){
|
|
91
|
-
results.set(item.id, this.evaluate(item.logic, context));
|
|
92
|
-
}
|
|
93
|
-
return results;
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Check if user has ANY of the specified actions
|
|
97
|
-
*
|
|
98
|
-
* @param actionIds - Array of action IDs
|
|
99
|
-
* @param context - User permission context
|
|
100
|
-
* @returns true if user has at least one action
|
|
101
|
-
*/ hasAnyAction(actionIds, context) {
|
|
102
|
-
return actionIds.some((actionId)=>this.evaluateAction(actionId, context));
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* Check if user has ALL of the specified actions
|
|
106
|
-
*
|
|
107
|
-
* @param actionIds - Array of action IDs
|
|
108
|
-
* @param context - User permission context
|
|
109
|
-
* @returns true if user has all actions
|
|
110
|
-
*/ hasAllActions(actionIds, context) {
|
|
111
|
-
return actionIds.every((actionId)=>this.evaluateAction(actionId, context));
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Check if user has ANY of the specified roles
|
|
115
|
-
*
|
|
116
|
-
* @param roleIds - Array of role IDs
|
|
117
|
-
* @param context - User permission context
|
|
118
|
-
* @returns true if user has at least one role
|
|
119
|
-
*/ hasAnyRole(roleIds, context) {
|
|
120
|
-
return roleIds.some((roleId)=>context.roleIds.has(roleId));
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* Check if user has ALL of the specified roles
|
|
124
|
-
*
|
|
125
|
-
* @param roleIds - Array of role IDs
|
|
126
|
-
* @param context - User permission context
|
|
127
|
-
* @returns true if user has all roles
|
|
128
|
-
*/ hasAllRoles(roleIds, context) {
|
|
129
|
-
return roleIds.every((roleId)=>context.roleIds.has(roleId));
|
|
130
|
-
}
|
|
131
|
-
/**
|
|
132
|
-
* Simplified evaluation for menu filtering
|
|
133
|
-
* Uses action codes instead of action IDs
|
|
134
|
-
*
|
|
135
|
-
* @param logic - Permission logic to evaluate
|
|
136
|
-
* @param actionCodes - Set of action codes the user has
|
|
137
|
-
* @returns true if user has access, false otherwise
|
|
138
|
-
*/ evaluateLogicNode(logic, actionCodes) {
|
|
139
|
-
if (!logic) {
|
|
140
|
-
return true;
|
|
141
|
-
}
|
|
142
|
-
return this.evaluateNodeSimple(logic, actionCodes);
|
|
143
|
-
}
|
|
144
|
-
/**
|
|
145
|
-
* Simplified node evaluation using codes
|
|
146
|
-
*/ evaluateNodeSimple(node, actionCodes) {
|
|
147
|
-
switch(node.type){
|
|
148
|
-
case 'action':
|
|
149
|
-
// Check if user has action by actionId (which matches action.code)
|
|
150
|
-
return node.actionId ? actionCodes.has(node.actionId) : false;
|
|
151
|
-
case 'group':
|
|
152
|
-
return this.evaluateGroupSimple(node, actionCodes);
|
|
153
|
-
default:
|
|
154
|
-
return false;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
/**
|
|
158
|
-
* Simplified group evaluation
|
|
159
|
-
*/ evaluateGroupSimple(node, actionCodes) {
|
|
160
|
-
if (!node.children || node.children.length === 0) {
|
|
161
|
-
// Empty AND = true, Empty OR = false
|
|
162
|
-
return node.operator === 'AND';
|
|
163
|
-
}
|
|
164
|
-
const results = node.children.map((child)=>this.evaluateNodeSimple(child, actionCodes));
|
|
165
|
-
if (node.operator === 'AND') {
|
|
166
|
-
return results.every((result)=>result === true);
|
|
167
|
-
} else if (node.operator === 'OR') {
|
|
168
|
-
return results.some((result)=>result === true);
|
|
169
|
-
}
|
|
170
|
-
return false;
|
|
171
|
-
}
|
|
172
|
-
};
|
|
173
|
-
PermissionEvaluatorHelper = _ts_decorate([
|
|
174
|
-
(0, _common.Injectable)()
|
|
175
|
-
], PermissionEvaluatorHelper);
|
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
function _ts_decorate(decorators, target, key, desc) {
|
|
2
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
-
else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
-
}
|
|
7
|
-
import { Injectable } from '@nestjs/common';
|
|
8
|
-
export class PermissionEvaluatorHelper {
|
|
9
|
-
/**
|
|
10
|
-
* Evaluate if user has access based on permission logic
|
|
11
|
-
*
|
|
12
|
-
* @param logic - Permission logic to evaluate
|
|
13
|
-
* @param context - User permission context
|
|
14
|
-
* @returns true if user has access, false otherwise
|
|
15
|
-
*/ evaluate(logic, context) {
|
|
16
|
-
// If no logic defined, access is granted
|
|
17
|
-
if (!logic) {
|
|
18
|
-
return true;
|
|
19
|
-
}
|
|
20
|
-
return this.evaluateNode(logic, context);
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Evaluate a single logic node
|
|
24
|
-
*/ evaluateNode(node, context) {
|
|
25
|
-
switch(node.type){
|
|
26
|
-
case 'action':
|
|
27
|
-
return this.evaluateAction(node.actionId, context);
|
|
28
|
-
case 'group':
|
|
29
|
-
return this.evaluateGroup(node, context);
|
|
30
|
-
default:
|
|
31
|
-
// Unknown node type, deny access
|
|
32
|
-
return false;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Evaluate action permission
|
|
37
|
-
* Priority: Deny > Grant > Inherited
|
|
38
|
-
*/ evaluateAction(actionId, context) {
|
|
39
|
-
// 1. Check explicit deny (highest priority)
|
|
40
|
-
if (context.deniedActionIds.has(actionId)) {
|
|
41
|
-
return false;
|
|
42
|
-
}
|
|
43
|
-
// 2. Check explicit grant
|
|
44
|
-
if (context.grantedActionIds.has(actionId)) {
|
|
45
|
-
return true;
|
|
46
|
-
}
|
|
47
|
-
// 3. Check inherited actions (from parent actions)
|
|
48
|
-
if (context.inheritedActionIds?.has(actionId)) {
|
|
49
|
-
return true;
|
|
50
|
-
}
|
|
51
|
-
// No permission found
|
|
52
|
-
return false;
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Evaluate group (AND/OR logic)
|
|
56
|
-
*/ evaluateGroup(node, context) {
|
|
57
|
-
if (!node.children || node.children.length === 0) {
|
|
58
|
-
return false;
|
|
59
|
-
}
|
|
60
|
-
const results = node.children.map((child)=>this.evaluateNode(child, context));
|
|
61
|
-
if (node.operator === 'AND') {
|
|
62
|
-
// ALL children must be true
|
|
63
|
-
return results.every((result)=>result === true);
|
|
64
|
-
} else if (node.operator === 'OR') {
|
|
65
|
-
// ANY child must be true
|
|
66
|
-
return results.some((result)=>result === true);
|
|
67
|
-
}
|
|
68
|
-
// Unknown operator, deny access
|
|
69
|
-
return false;
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Batch evaluate multiple logic nodes
|
|
73
|
-
* Useful for checking multiple permissions at once
|
|
74
|
-
*
|
|
75
|
-
* @param logics - Array of logic nodes to evaluate
|
|
76
|
-
* @param context - User permission context
|
|
77
|
-
* @returns Map of logic ID to evaluation result
|
|
78
|
-
*/ batchEvaluate(logics, context) {
|
|
79
|
-
const results = new Map();
|
|
80
|
-
for (const item of logics){
|
|
81
|
-
results.set(item.id, this.evaluate(item.logic, context));
|
|
82
|
-
}
|
|
83
|
-
return results;
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* Check if user has ANY of the specified actions
|
|
87
|
-
*
|
|
88
|
-
* @param actionIds - Array of action IDs
|
|
89
|
-
* @param context - User permission context
|
|
90
|
-
* @returns true if user has at least one action
|
|
91
|
-
*/ hasAnyAction(actionIds, context) {
|
|
92
|
-
return actionIds.some((actionId)=>this.evaluateAction(actionId, context));
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Check if user has ALL of the specified actions
|
|
96
|
-
*
|
|
97
|
-
* @param actionIds - Array of action IDs
|
|
98
|
-
* @param context - User permission context
|
|
99
|
-
* @returns true if user has all actions
|
|
100
|
-
*/ hasAllActions(actionIds, context) {
|
|
101
|
-
return actionIds.every((actionId)=>this.evaluateAction(actionId, context));
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* Check if user has ANY of the specified roles
|
|
105
|
-
*
|
|
106
|
-
* @param roleIds - Array of role IDs
|
|
107
|
-
* @param context - User permission context
|
|
108
|
-
* @returns true if user has at least one role
|
|
109
|
-
*/ hasAnyRole(roleIds, context) {
|
|
110
|
-
return roleIds.some((roleId)=>context.roleIds.has(roleId));
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* Check if user has ALL of the specified roles
|
|
114
|
-
*
|
|
115
|
-
* @param roleIds - Array of role IDs
|
|
116
|
-
* @param context - User permission context
|
|
117
|
-
* @returns true if user has all roles
|
|
118
|
-
*/ hasAllRoles(roleIds, context) {
|
|
119
|
-
return roleIds.every((roleId)=>context.roleIds.has(roleId));
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Simplified evaluation for menu filtering
|
|
123
|
-
* Uses action codes instead of action IDs
|
|
124
|
-
*
|
|
125
|
-
* @param logic - Permission logic to evaluate
|
|
126
|
-
* @param actionCodes - Set of action codes the user has
|
|
127
|
-
* @returns true if user has access, false otherwise
|
|
128
|
-
*/ evaluateLogicNode(logic, actionCodes) {
|
|
129
|
-
if (!logic) {
|
|
130
|
-
return true;
|
|
131
|
-
}
|
|
132
|
-
return this.evaluateNodeSimple(logic, actionCodes);
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* Simplified node evaluation using codes
|
|
136
|
-
*/ evaluateNodeSimple(node, actionCodes) {
|
|
137
|
-
switch(node.type){
|
|
138
|
-
case 'action':
|
|
139
|
-
// Check if user has action by actionId (which matches action.code)
|
|
140
|
-
return node.actionId ? actionCodes.has(node.actionId) : false;
|
|
141
|
-
case 'group':
|
|
142
|
-
return this.evaluateGroupSimple(node, actionCodes);
|
|
143
|
-
default:
|
|
144
|
-
return false;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* Simplified group evaluation
|
|
149
|
-
*/ evaluateGroupSimple(node, actionCodes) {
|
|
150
|
-
if (!node.children || node.children.length === 0) {
|
|
151
|
-
// Empty AND = true, Empty OR = false
|
|
152
|
-
return node.operator === 'AND';
|
|
153
|
-
}
|
|
154
|
-
const results = node.children.map((child)=>this.evaluateNodeSimple(child, actionCodes));
|
|
155
|
-
if (node.operator === 'AND') {
|
|
156
|
-
return results.every((result)=>result === true);
|
|
157
|
-
} else if (node.operator === 'OR') {
|
|
158
|
-
return results.some((result)=>result === true);
|
|
159
|
-
}
|
|
160
|
-
return false;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
PermissionEvaluatorHelper = _ts_decorate([
|
|
164
|
-
Injectable()
|
|
165
|
-
], PermissionEvaluatorHelper);
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { LogicNode } from '../types';
|
|
2
|
-
export interface UserPermissionContext {
|
|
3
|
-
userId: string;
|
|
4
|
-
branchId?: string | null;
|
|
5
|
-
grantedActionIds: Set<string>;
|
|
6
|
-
deniedActionIds: Set<string>;
|
|
7
|
-
roleIds: Set<string>;
|
|
8
|
-
inheritedActionIds?: Set<string>;
|
|
9
|
-
}
|
|
10
|
-
export declare class PermissionEvaluatorHelper {
|
|
11
|
-
evaluate(logic: LogicNode | null, context: UserPermissionContext): boolean;
|
|
12
|
-
private evaluateNode;
|
|
13
|
-
evaluateAction(actionId: string, context: UserPermissionContext): boolean;
|
|
14
|
-
private evaluateGroup;
|
|
15
|
-
batchEvaluate(logics: Array<{
|
|
16
|
-
id: string;
|
|
17
|
-
logic: LogicNode | null;
|
|
18
|
-
}>, context: UserPermissionContext): Map<string, boolean>;
|
|
19
|
-
hasAnyAction(actionIds: string[], context: UserPermissionContext): boolean;
|
|
20
|
-
hasAllActions(actionIds: string[], context: UserPermissionContext): boolean;
|
|
21
|
-
hasAnyRole(roleIds: string[], context: UserPermissionContext): boolean;
|
|
22
|
-
hasAllRoles(roleIds: string[], context: UserPermissionContext): boolean;
|
|
23
|
-
evaluateLogicNode(logic: LogicNode | null, actionCodes: Set<string>): boolean;
|
|
24
|
-
private evaluateNodeSimple;
|
|
25
|
-
private evaluateGroupSimple;
|
|
26
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { IBootstrapAppConfig, IDynamicModuleConfig } from '@flusys/nestjs-core';
|
|
2
|
-
import { ModuleMetadata, Type } from '@nestjs/common';
|
|
3
|
-
import { IIAMModuleConfig, IAMOptionsFactory } from './iam-module-options.interface';
|
|
4
|
-
export interface IAMModuleAsyncOptions extends Pick<ModuleMetadata, 'imports'>, IDynamicModuleConfig {
|
|
5
|
-
bootstrapAppConfig?: IBootstrapAppConfig;
|
|
6
|
-
config?: IIAMModuleConfig;
|
|
7
|
-
useFactory?: (...args: any[]) => Promise<IIAMModuleConfig> | IIAMModuleConfig;
|
|
8
|
-
inject?: any[];
|
|
9
|
-
useClass?: Type<IAMOptionsFactory>;
|
|
10
|
-
useExisting?: Type<IAMOptionsFactory>;
|
|
11
|
-
}
|