@klerick/acl-json-api-nestjs 0.1.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/CHANGELOG.md +15 -0
- package/README.md +3556 -0
- package/package.json +41 -0
- package/src/index.d.ts +8 -0
- package/src/index.js +15 -0
- package/src/index.js.map +1 -0
- package/src/lib/constants/index.d.ts +14 -0
- package/src/lib/constants/index.js +18 -0
- package/src/lib/constants/index.js.map +1 -0
- package/src/lib/decorators/acl-controller.decorator.d.ts +4 -0
- package/src/lib/decorators/acl-controller.decorator.js +19 -0
- package/src/lib/decorators/acl-controller.decorator.js.map +1 -0
- package/src/lib/decorators/index.d.ts +1 -0
- package/src/lib/decorators/index.js +6 -0
- package/src/lib/decorators/index.js.map +1 -0
- package/src/lib/factories/ability-proxy.factory.d.ts +17 -0
- package/src/lib/factories/ability-proxy.factory.js +100 -0
- package/src/lib/factories/ability-proxy.factory.js.map +1 -0
- package/src/lib/factories/ability.factory.d.ts +49 -0
- package/src/lib/factories/ability.factory.js +235 -0
- package/src/lib/factories/ability.factory.js.map +1 -0
- package/src/lib/factories/index.d.ts +2 -0
- package/src/lib/factories/index.js +6 -0
- package/src/lib/factories/index.js.map +1 -0
- package/src/lib/guards/acl.guard.d.ts +21 -0
- package/src/lib/guards/acl.guard.js +68 -0
- package/src/lib/guards/acl.guard.js.map +1 -0
- package/src/lib/guards/index.d.ts +1 -0
- package/src/lib/guards/index.js +5 -0
- package/src/lib/guards/index.js.map +1 -0
- package/src/lib/nestjs-acl-permissions.module.d.ts +9 -0
- package/src/lib/nestjs-acl-permissions.module.js +56 -0
- package/src/lib/nestjs-acl-permissions.module.js.map +1 -0
- package/src/lib/services/acl-authorization.service.d.ts +10 -0
- package/src/lib/services/acl-authorization.service.js +100 -0
- package/src/lib/services/acl-authorization.service.js.map +1 -0
- package/src/lib/services/index.d.ts +2 -0
- package/src/lib/services/index.js +6 -0
- package/src/lib/services/index.js.map +1 -0
- package/src/lib/services/rule-materializer.service.d.ts +73 -0
- package/src/lib/services/rule-materializer.service.js +251 -0
- package/src/lib/services/rule-materializer.service.js.map +1 -0
- package/src/lib/types/acl-context.types.d.ts +14 -0
- package/src/lib/types/acl-context.types.js +3 -0
- package/src/lib/types/acl-context.types.js.map +1 -0
- package/src/lib/types/acl-options.types.d.ts +97 -0
- package/src/lib/types/acl-options.types.js +3 -0
- package/src/lib/types/acl-options.types.js.map +1 -0
- package/src/lib/types/acl-rules.types.d.ts +201 -0
- package/src/lib/types/acl-rules.types.js +27 -0
- package/src/lib/types/acl-rules.types.js.map +1 -0
- package/src/lib/types/decorator-options.types.d.ts +64 -0
- package/src/lib/types/decorator-options.types.js +3 -0
- package/src/lib/types/decorator-options.types.js.map +1 -0
- package/src/lib/types/index.d.ts +4 -0
- package/src/lib/types/index.js +8 -0
- package/src/lib/types/index.js.map +1 -0
- package/src/lib/utils/index.d.ts +10 -0
- package/src/lib/utils/index.js +53 -0
- package/src/lib/utils/index.js.map +1 -0
- package/src/lib/utils/orm-proxy/extract-field-paths.d.ts +73 -0
- package/src/lib/utils/orm-proxy/extract-field-paths.js +155 -0
- package/src/lib/utils/orm-proxy/extract-field-paths.js.map +1 -0
- package/src/lib/utils/orm-proxy/handle-acl-query-error.d.ts +19 -0
- package/src/lib/utils/orm-proxy/handle-acl-query-error.js +53 -0
- package/src/lib/utils/orm-proxy/handle-acl-query-error.js.map +1 -0
- package/src/lib/utils/orm-proxy/index.d.ts +9 -0
- package/src/lib/utils/orm-proxy/index.js +24 -0
- package/src/lib/utils/orm-proxy/index.js.map +1 -0
- package/src/lib/utils/orm-proxy/merge-query-with-acl-data.d.ts +27 -0
- package/src/lib/utils/orm-proxy/merge-query-with-acl-data.js +78 -0
- package/src/lib/utils/orm-proxy/merge-query-with-acl-data.js.map +1 -0
- package/src/lib/utils/orm-proxy/prepare-acl-query.d.ts +11 -0
- package/src/lib/utils/orm-proxy/prepare-acl-query.js +35 -0
- package/src/lib/utils/orm-proxy/prepare-acl-query.js.map +1 -0
- package/src/lib/utils/orm-proxy/process-item-field-restrictions.d.ts +24 -0
- package/src/lib/utils/orm-proxy/process-item-field-restrictions.js +42 -0
- package/src/lib/utils/orm-proxy/process-item-field-restrictions.js.map +1 -0
- package/src/lib/utils/orm-proxy/remove-acl-added-fields.d.ts +31 -0
- package/src/lib/utils/orm-proxy/remove-acl-added-fields.js +104 -0
- package/src/lib/utils/orm-proxy/remove-acl-added-fields.js.map +1 -0
- package/src/lib/utils/orm-proxy/unset-deep.d.ts +13 -0
- package/src/lib/utils/orm-proxy/unset-deep.js +41 -0
- package/src/lib/utils/orm-proxy/unset-deep.js.map +1 -0
- package/src/lib/utils/orm-proxy/validate-no-current-in-rules.d.ts +19 -0
- package/src/lib/utils/orm-proxy/validate-no-current-in-rules.js +33 -0
- package/src/lib/utils/orm-proxy/validate-no-current-in-rules.js.map +1 -0
- package/src/lib/utils/orm-proxy/validate-rules-for-orm.d.ts +16 -0
- package/src/lib/utils/orm-proxy/validate-rules-for-orm.js +35 -0
- package/src/lib/utils/orm-proxy/validate-rules-for-orm.js.map +1 -0
- package/src/lib/wrappers/index.d.ts +9 -0
- package/src/lib/wrappers/index.js +32 -0
- package/src/lib/wrappers/index.js.map +1 -0
- package/src/lib/wrappers/logger-init.d.ts +2 -0
- package/src/lib/wrappers/logger-init.js +9 -0
- package/src/lib/wrappers/logger-init.js.map +1 -0
- package/src/lib/wrappers/wrapper-json-method-controller/get-proxy-orm.d.ts +4 -0
- package/src/lib/wrappers/wrapper-json-method-controller/get-proxy-orm.js +47 -0
- package/src/lib/wrappers/wrapper-json-method-controller/get-proxy-orm.js.map +1 -0
- package/src/lib/wrappers/wrapper-json-method-controller/index.d.ts +3 -0
- package/src/lib/wrappers/wrapper-json-method-controller/index.js +21 -0
- package/src/lib/wrappers/wrapper-json-method-controller/index.js.map +1 -0
- package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/delete-one-proxy.d.ts +3 -0
- package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/delete-one-proxy.js +51 -0
- package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/delete-one-proxy.js.map +1 -0
- package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/delete-relationship-proxy.d.ts +4 -0
- package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/delete-relationship-proxy.js +59 -0
- package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/delete-relationship-proxy.js.map +1 -0
- package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/get-all-proxy.d.ts +13 -0
- package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/get-all-proxy.js +67 -0
- package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/get-all-proxy.js.map +1 -0
- package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/get-one-proxy.d.ts +12 -0
- package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/get-one-proxy.js +50 -0
- package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/get-one-proxy.js.map +1 -0
- package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/get-relationship-proxy.d.ts +4 -0
- package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/get-relationship-proxy.js +50 -0
- package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/get-relationship-proxy.js.map +1 -0
- package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/index.d.ts +9 -0
- package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/index.js +13 -0
- package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/index.js.map +1 -0
- package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/patch-one-proxy.d.ts +3 -0
- package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/patch-one-proxy.js +132 -0
- package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/patch-one-proxy.js.map +1 -0
- package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/patch-relationship-proxy.d.ts +4 -0
- package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/patch-relationship-proxy.js +68 -0
- package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/patch-relationship-proxy.js.map +1 -0
- package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/post-one-proxy.d.ts +3 -0
- package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/post-one-proxy.js +73 -0
- package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/post-one-proxy.js.map +1 -0
- package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/post-relationship-proxy.d.ts +4 -0
- package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/post-relationship-proxy.js +66 -0
- package/src/lib/wrappers/wrapper-json-method-controller/method-proxy/post-relationship-proxy.js.map +1 -0
- package/src/lib/wrappers/wrapper-json-method-controller/on-module-init.d.ts +2 -0
- package/src/lib/wrappers/wrapper-json-method-controller/on-module-init.js +16 -0
- package/src/lib/wrappers/wrapper-json-method-controller/on-module-init.js.map +1 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ExtractFieldPaths = void 0;
|
|
4
|
+
exports.getCurrentEntityAndParamMap = getCurrentEntityAndParamMap;
|
|
5
|
+
exports.extractFieldsForCheck = extractFieldsForCheck;
|
|
6
|
+
const json_api_nestjs_1 = require("@klerick/json-api-nestjs");
|
|
7
|
+
const remove_acl_added_fields_1 = require("./remove-acl-added-fields");
|
|
8
|
+
const handle_acl_query_error_1 = require("./handle-acl-query-error");
|
|
9
|
+
/**
|
|
10
|
+
* Singleton class for extracting field paths from entity objects
|
|
11
|
+
*
|
|
12
|
+
* Features:
|
|
13
|
+
* - Skips primary keys (they are always accessible, no ACL check needed)
|
|
14
|
+
* - Recursively processes relationships
|
|
15
|
+
* - Returns flat array of dot-notation paths
|
|
16
|
+
* - Handles one-to-many (arrays) and one-to-one (objects) relationships
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* const extractor = ExtractFieldPaths.getInstance(entityParamMap);
|
|
20
|
+
* const obj = {
|
|
21
|
+
* id: 1, // primary key - will be skipped
|
|
22
|
+
* login: 'user',
|
|
23
|
+
* profile: { id: 10, phone: '123' } // profile.id also skipped
|
|
24
|
+
* };
|
|
25
|
+
*
|
|
26
|
+
* const paths = extractor.fields(obj, User);
|
|
27
|
+
* // Returns: ['login', 'profile.phone']
|
|
28
|
+
*/
|
|
29
|
+
class ExtractFieldPaths {
|
|
30
|
+
entityParamMap;
|
|
31
|
+
constructor(entityParamMap) {
|
|
32
|
+
this.entityParamMap = entityParamMap;
|
|
33
|
+
}
|
|
34
|
+
extractField(obj, nameEntity, prefix = '') {
|
|
35
|
+
const fields = [];
|
|
36
|
+
const entityParam = this.entityParamMap.get(nameEntity);
|
|
37
|
+
if (!entityParam) {
|
|
38
|
+
throw new Error(`Entity ${nameEntity.name} not found in EntityParamMap`);
|
|
39
|
+
}
|
|
40
|
+
// Add all properties (fields)
|
|
41
|
+
for (const prop of entityParam.props) {
|
|
42
|
+
if (!(prop in obj) || entityParam.primaryColumnName === prop) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const path = (prefix ? `${prefix}.${prop.toString()}` : prop).toString();
|
|
46
|
+
fields.push(path);
|
|
47
|
+
}
|
|
48
|
+
for (const relation of entityParam.relations) {
|
|
49
|
+
const value = obj[relation];
|
|
50
|
+
const path = (prefix ? `${prefix}.${relation.toString()}` : relation).toString();
|
|
51
|
+
if (value === null || value === undefined) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
// Get relation metadata
|
|
55
|
+
const relationMeta = entityParam.relationProperty[relation];
|
|
56
|
+
if (!relationMeta || !('entityClass' in relationMeta)) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
// Handle arrays (one-to-many)
|
|
60
|
+
if (Array.isArray(value)) {
|
|
61
|
+
if (value.length > 0 &&
|
|
62
|
+
typeof value[0] === 'object' &&
|
|
63
|
+
value[0] !== null) {
|
|
64
|
+
const relObject = value[0];
|
|
65
|
+
fields.push(...this.extractField(relObject, relationMeta.entityClass, path));
|
|
66
|
+
}
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
// Handle single object (one-to-one, many-to-one)
|
|
70
|
+
if (typeof value === 'object') {
|
|
71
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
72
|
+
fields.push(...this.extractField(value, relationMeta.entityClass, path));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return fields;
|
|
76
|
+
}
|
|
77
|
+
fields(obj, entityClass) {
|
|
78
|
+
return this.extractField(obj, entityClass);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Extracts only props (entity fields) from object, excluding relationships and primary key
|
|
82
|
+
* Skips primary key (same as fields() method)
|
|
83
|
+
*
|
|
84
|
+
* Use case: Create merged entity with only base fields for ACL checks
|
|
85
|
+
*
|
|
86
|
+
* @param obj - Source entity object (may contain loaded relationships)
|
|
87
|
+
* @param entityClass - Entity class
|
|
88
|
+
* @returns New object with only entity props (no relationships, no primary key)
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* const entity = { id: 1, login: 'user', role: 'admin', profile: { phone: '123' } };
|
|
92
|
+
* const propsOnly = extractor.props(entity, User);
|
|
93
|
+
* // Returns: { login: 'user', role: 'admin' }
|
|
94
|
+
* // Note: id (primary key) and profile (relationship) excluded
|
|
95
|
+
*/
|
|
96
|
+
props(obj, entityClass) {
|
|
97
|
+
const entityParam = this.entityParamMap.get(entityClass);
|
|
98
|
+
if (!entityParam) {
|
|
99
|
+
throw new Error(`Entity ${entityClass.name} not found in EntityParamMap`);
|
|
100
|
+
}
|
|
101
|
+
const propsOnly = {};
|
|
102
|
+
// Copy all props (excluding primary key)
|
|
103
|
+
for (const prop of entityParam.props) {
|
|
104
|
+
// Skip if prop not in object OR prop is primary key
|
|
105
|
+
if (!(prop in obj) || entityParam.primaryColumnName === prop) {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
propsOnly[prop] = obj[prop];
|
|
109
|
+
}
|
|
110
|
+
return propsOnly;
|
|
111
|
+
}
|
|
112
|
+
static instance;
|
|
113
|
+
static getInstance(entityParamMap) {
|
|
114
|
+
if (!ExtractFieldPaths.instance) {
|
|
115
|
+
ExtractFieldPaths.instance = new ExtractFieldPaths(entityParamMap);
|
|
116
|
+
}
|
|
117
|
+
return ExtractFieldPaths.instance;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
exports.ExtractFieldPaths = ExtractFieldPaths;
|
|
121
|
+
function getCurrentEntityAndParamMap(moduleRef) {
|
|
122
|
+
const currentEntity = moduleRef.get(json_api_nestjs_1.CURRENT_ENTITY);
|
|
123
|
+
const entityParamMapService = moduleRef.get(json_api_nestjs_1.ENTITY_PARAM_MAP, {
|
|
124
|
+
strict: false,
|
|
125
|
+
});
|
|
126
|
+
const entityParamMap = entityParamMapService.get(currentEntity);
|
|
127
|
+
if (!entityParamMap) {
|
|
128
|
+
throw (0, handle_acl_query_error_1.handleAclQueryError)(new Error(`EntityParamMap not found for ${currentEntity.name}`), currentEntity.name, 'extractFieldsForCheck');
|
|
129
|
+
}
|
|
130
|
+
return { currentEntity, entityParamMap, entityParamMapService };
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Extracts field paths for ACL checking
|
|
134
|
+
*
|
|
135
|
+
* This function:
|
|
136
|
+
* 1. Gets entity metadata from moduleRef
|
|
137
|
+
* 2. Clones the sample item
|
|
138
|
+
* 3. Removes ACL-added fields that weren't requested by user
|
|
139
|
+
* 4. Extracts field paths for checking
|
|
140
|
+
*
|
|
141
|
+
* @param moduleRef - NestJS module reference
|
|
142
|
+
* @param sampleItem - Sample entity item (first item for getAll, result for getOne)
|
|
143
|
+
* @param userQuery - Original user query
|
|
144
|
+
* @param aclQueryData - ACL query data (fields and include that were added by ACL)
|
|
145
|
+
* @returns Array of field paths to check
|
|
146
|
+
*/
|
|
147
|
+
function extractFieldsForCheck(moduleRef, sampleItem, userQuery, aclQueryData) {
|
|
148
|
+
const { currentEntity, entityParamMapService } = getCurrentEntityAndParamMap(moduleRef);
|
|
149
|
+
const copyItemForGetFieldCheck = structuredClone(sampleItem);
|
|
150
|
+
if (aclQueryData) {
|
|
151
|
+
(0, remove_acl_added_fields_1.removeAclAddedFields)(copyItemForGetFieldCheck, userQuery['fields'], aclQueryData.fields, userQuery['include'], aclQueryData.include);
|
|
152
|
+
}
|
|
153
|
+
return ExtractFieldPaths.getInstance(entityParamMapService).fields(copyItemForGetFieldCheck, currentEntity);
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=extract-field-paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extract-field-paths.js","sourceRoot":"","sources":["../../../../../../../../libs/acl-permissions/nestjs-acl-permissions/src/lib/utils/orm-proxy/extract-field-paths.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { HttpException } from '@nestjs/common/exceptions/http.exception';
|
|
2
|
+
/**
|
|
3
|
+
* Handles errors that occur during ACL query execution
|
|
4
|
+
*
|
|
5
|
+
* In development mode:
|
|
6
|
+
* - Logs detailed error information
|
|
7
|
+
* - Throws InternalServerErrorException with error details
|
|
8
|
+
*
|
|
9
|
+
* In production mode:
|
|
10
|
+
* - Logs error without details
|
|
11
|
+
* - Throws ForbiddenException without revealing ACL logic
|
|
12
|
+
*
|
|
13
|
+
* @param error - The error that occurred
|
|
14
|
+
* @param subject - The subject (entity name) being queried
|
|
15
|
+
* @param methodName - The proxy method name (for logging context)
|
|
16
|
+
* @return {InternalServerErrorException} In development mode
|
|
17
|
+
* @return {ForbiddenException} In production mode
|
|
18
|
+
*/
|
|
19
|
+
export declare function handleAclQueryError(error: unknown, subject: string, methodName: string): HttpException;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handleAclQueryError = handleAclQueryError;
|
|
4
|
+
const common_1 = require("@nestjs/common");
|
|
5
|
+
const http_exception_1 = require("@nestjs/common/exceptions/http.exception");
|
|
6
|
+
/**
|
|
7
|
+
* Handles errors that occur during ACL query execution
|
|
8
|
+
*
|
|
9
|
+
* In development mode:
|
|
10
|
+
* - Logs detailed error information
|
|
11
|
+
* - Throws InternalServerErrorException with error details
|
|
12
|
+
*
|
|
13
|
+
* In production mode:
|
|
14
|
+
* - Logs error without details
|
|
15
|
+
* - Throws ForbiddenException without revealing ACL logic
|
|
16
|
+
*
|
|
17
|
+
* @param error - The error that occurred
|
|
18
|
+
* @param subject - The subject (entity name) being queried
|
|
19
|
+
* @param methodName - The proxy method name (for logging context)
|
|
20
|
+
* @return {InternalServerErrorException} In development mode
|
|
21
|
+
* @return {ForbiddenException} In production mode
|
|
22
|
+
*/
|
|
23
|
+
function handleAclQueryError(error, subject, methodName) {
|
|
24
|
+
const isDevelopment = process.env['NODE_ENV'] === 'development';
|
|
25
|
+
// Log error for debugging
|
|
26
|
+
common_1.Logger.error(`ACL query execution failed for subject "${subject}": ${error instanceof Error ? error.message : String(error)}`, error instanceof Error ? error.stack : undefined, methodName);
|
|
27
|
+
if (error instanceof http_exception_1.HttpException) {
|
|
28
|
+
throw error;
|
|
29
|
+
}
|
|
30
|
+
if (isDevelopment) {
|
|
31
|
+
// Development: 500 with error details for debugging
|
|
32
|
+
return new common_1.InternalServerErrorException([
|
|
33
|
+
{
|
|
34
|
+
code: 'internal_server_error',
|
|
35
|
+
message: `ACL query failed: ${error instanceof Error ? error.message : 'unknown error'}`,
|
|
36
|
+
path: [],
|
|
37
|
+
},
|
|
38
|
+
], {
|
|
39
|
+
description: `Failed to execute ACL query for subject "${subject}"`,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
// Production: 403 without details to avoid leaking ACL logic
|
|
43
|
+
return new common_1.ForbiddenException([
|
|
44
|
+
{
|
|
45
|
+
code: 'forbidden',
|
|
46
|
+
message: 'not allow access',
|
|
47
|
+
path: [],
|
|
48
|
+
},
|
|
49
|
+
], {
|
|
50
|
+
description: `Access denied for subject "${subject}"`,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=handle-acl-query-error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handle-acl-query-error.js","sourceRoot":"","sources":["../../../../../../../../libs/acl-permissions/nestjs-acl-permissions/src/lib/utils/orm-proxy/handle-acl-query-error.ts"],"names":[],"mappings":";;AAwBA,kDAmDC;AA3ED,2CAIwB;AACxB,6EAAyE;AAEzE;;;;;;;;;;;;;;;;GAgBG;AACH,SAAgB,mBAAmB,CACjC,KAAc,EACd,OAAe,EACf,UAAkB;IAElB,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,aAAa,CAAC;IAEhE,0BAA0B;IAC1B,eAAM,CAAC,KAAK,CACV,2CAA2C,OAAO,MAChD,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CACvD,EAAE,EACF,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,EAChD,UAAU,CACX,CAAC;IAEF,IAAI,KAAK,YAAY,8BAAa,EAAE,CAAC;QACnC,MAAM,KAAK,CAAA;IACb,CAAC;IAED,IAAI,aAAa,EAAE,CAAC;QAClB,oDAAoD;QACpD,OAAO,IAAI,qCAA4B,CACrC;YACE;gBACE,IAAI,EAAE,uBAAuB;gBAC7B,OAAO,EAAE,qBACP,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAC3C,EAAE;gBACF,IAAI,EAAE,EAAE;aACT;SACF,EACD;YACE,WAAW,EAAE,4CAA4C,OAAO,GAAG;SACpE,CACF,CAAC;IACJ,CAAC;IAED,6DAA6D;IAC7D,OAAO,IAAI,2BAAkB,CAC3B;QACE;YACE,IAAI,EAAE,WAAW;YACjB,OAAO,EAAE,kBAAkB;YAC3B,IAAI,EAAE,EAAE;SACT;KACF,EACD;QACE,WAAW,EAAE,8BAA8B,OAAO,GAAG;KACtD,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { unsetDeep } from './unset-deep';
|
|
2
|
+
export { mergeQueryWithAclData } from './merge-query-with-acl-data';
|
|
3
|
+
export { removeAclAddedFields } from './remove-acl-added-fields';
|
|
4
|
+
export { ExtractFieldPaths, extractFieldsForCheck, getCurrentEntityAndParamMap } from './extract-field-paths';
|
|
5
|
+
export { handleAclQueryError } from './handle-acl-query-error';
|
|
6
|
+
export { prepareAclQuery } from './prepare-acl-query';
|
|
7
|
+
export { processItemFieldRestrictions } from './process-item-field-restrictions';
|
|
8
|
+
export { validateRulesForORM } from './validate-rules-for-orm';
|
|
9
|
+
export { validateNoCurrentInRules } from './validate-no-current-in-rules';
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateNoCurrentInRules = exports.validateRulesForORM = exports.processItemFieldRestrictions = exports.prepareAclQuery = exports.handleAclQueryError = exports.getCurrentEntityAndParamMap = exports.extractFieldsForCheck = exports.ExtractFieldPaths = exports.removeAclAddedFields = exports.mergeQueryWithAclData = exports.unsetDeep = void 0;
|
|
4
|
+
var unset_deep_1 = require("./unset-deep");
|
|
5
|
+
Object.defineProperty(exports, "unsetDeep", { enumerable: true, get: function () { return unset_deep_1.unsetDeep; } });
|
|
6
|
+
var merge_query_with_acl_data_1 = require("./merge-query-with-acl-data");
|
|
7
|
+
Object.defineProperty(exports, "mergeQueryWithAclData", { enumerable: true, get: function () { return merge_query_with_acl_data_1.mergeQueryWithAclData; } });
|
|
8
|
+
var remove_acl_added_fields_1 = require("./remove-acl-added-fields");
|
|
9
|
+
Object.defineProperty(exports, "removeAclAddedFields", { enumerable: true, get: function () { return remove_acl_added_fields_1.removeAclAddedFields; } });
|
|
10
|
+
var extract_field_paths_1 = require("./extract-field-paths");
|
|
11
|
+
Object.defineProperty(exports, "ExtractFieldPaths", { enumerable: true, get: function () { return extract_field_paths_1.ExtractFieldPaths; } });
|
|
12
|
+
Object.defineProperty(exports, "extractFieldsForCheck", { enumerable: true, get: function () { return extract_field_paths_1.extractFieldsForCheck; } });
|
|
13
|
+
Object.defineProperty(exports, "getCurrentEntityAndParamMap", { enumerable: true, get: function () { return extract_field_paths_1.getCurrentEntityAndParamMap; } });
|
|
14
|
+
var handle_acl_query_error_1 = require("./handle-acl-query-error");
|
|
15
|
+
Object.defineProperty(exports, "handleAclQueryError", { enumerable: true, get: function () { return handle_acl_query_error_1.handleAclQueryError; } });
|
|
16
|
+
var prepare_acl_query_1 = require("./prepare-acl-query");
|
|
17
|
+
Object.defineProperty(exports, "prepareAclQuery", { enumerable: true, get: function () { return prepare_acl_query_1.prepareAclQuery; } });
|
|
18
|
+
var process_item_field_restrictions_1 = require("./process-item-field-restrictions");
|
|
19
|
+
Object.defineProperty(exports, "processItemFieldRestrictions", { enumerable: true, get: function () { return process_item_field_restrictions_1.processItemFieldRestrictions; } });
|
|
20
|
+
var validate_rules_for_orm_1 = require("./validate-rules-for-orm");
|
|
21
|
+
Object.defineProperty(exports, "validateRulesForORM", { enumerable: true, get: function () { return validate_rules_for_orm_1.validateRulesForORM; } });
|
|
22
|
+
var validate_no_current_in_rules_1 = require("./validate-no-current-in-rules");
|
|
23
|
+
Object.defineProperty(exports, "validateNoCurrentInRules", { enumerable: true, get: function () { return validate_no_current_in_rules_1.validateNoCurrentInRules; } });
|
|
24
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../../../libs/acl-permissions/nestjs-acl-permissions/src/lib/utils/orm-proxy/index.ts"],"names":[],"mappings":";;;AAAA,2CAAyC;AAAhC,uGAAA,SAAS,OAAA;AAClB,yEAAoE;AAA3D,kIAAA,qBAAqB,OAAA;AAC9B,qEAAiE;AAAxD,+HAAA,oBAAoB,OAAA;AAC7B,6DAA8G;AAArG,wHAAA,iBAAiB,OAAA;AAAE,4HAAA,qBAAqB,OAAA;AAAE,kIAAA,2BAA2B,OAAA;AAC9E,mEAA+D;AAAtD,6HAAA,mBAAmB,OAAA;AAC5B,yDAAsD;AAA7C,oHAAA,eAAe,OAAA;AACxB,qFAAiF;AAAxE,+IAAA,4BAA4B,OAAA;AACrC,mEAA+D;AAAtD,6HAAA,mBAAmB,OAAA;AAC5B,+EAA0E;AAAjE,wIAAA,wBAAwB,OAAA"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Query, QueryOne } from '@klerick/json-api-nestjs';
|
|
2
|
+
import { QueryField } from '@klerick/json-api-nestjs-shared';
|
|
3
|
+
/**
|
|
4
|
+
* Merges user query with ACL fields and includes
|
|
5
|
+
*
|
|
6
|
+
* IMPORTANT: fields: null or missing relation key means "select ALL fields"
|
|
7
|
+
* We should NOT add ACL fields in such cases to avoid turning "all fields" into "specific fields"
|
|
8
|
+
*
|
|
9
|
+
* @param query - Original user query
|
|
10
|
+
* @param aclFields - ACL fields to add (fields structure with target and relations)
|
|
11
|
+
* @param aclInclude - ACL includes to add
|
|
12
|
+
* @returns Merged query
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* // Case 1: fields: null → select all, don't add ACL fields
|
|
16
|
+
* mergeQueryWithAclData({ fields: null }, { target: ['role'] })
|
|
17
|
+
* // → { fields: null } (unchanged)
|
|
18
|
+
*
|
|
19
|
+
* // Case 2: fields: { target: ['id'] } → add ACL fields to target
|
|
20
|
+
* mergeQueryWithAclData({ fields: { target: ['id'] } }, { target: ['role'] })
|
|
21
|
+
* // → { fields: { target: ['id', 'role'] } }
|
|
22
|
+
*
|
|
23
|
+
* // Case 3: fields: { target: ['id'] } + ACL needs profile → don't add profile fields
|
|
24
|
+
* mergeQueryWithAclData({ fields: { target: ['id'] } }, { profile: ['isPublic'] })
|
|
25
|
+
* // → { fields: { target: ['id'] } } (profile missing = all fields)
|
|
26
|
+
*/
|
|
27
|
+
export declare function mergeQueryWithAclData<E extends object, IdKey extends string, Q extends QueryOne<E, IdKey> | Query<E, IdKey>>(query: Q, aclFields?: Q[QueryField.fields], aclInclude?: Q[QueryField.include]): Q;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mergeQueryWithAclData = mergeQueryWithAclData;
|
|
4
|
+
/**
|
|
5
|
+
* Merges user query with ACL fields and includes
|
|
6
|
+
*
|
|
7
|
+
* IMPORTANT: fields: null or missing relation key means "select ALL fields"
|
|
8
|
+
* We should NOT add ACL fields in such cases to avoid turning "all fields" into "specific fields"
|
|
9
|
+
*
|
|
10
|
+
* @param query - Original user query
|
|
11
|
+
* @param aclFields - ACL fields to add (fields structure with target and relations)
|
|
12
|
+
* @param aclInclude - ACL includes to add
|
|
13
|
+
* @returns Merged query
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* // Case 1: fields: null → select all, don't add ACL fields
|
|
17
|
+
* mergeQueryWithAclData({ fields: null }, { target: ['role'] })
|
|
18
|
+
* // → { fields: null } (unchanged)
|
|
19
|
+
*
|
|
20
|
+
* // Case 2: fields: { target: ['id'] } → add ACL fields to target
|
|
21
|
+
* mergeQueryWithAclData({ fields: { target: ['id'] } }, { target: ['role'] })
|
|
22
|
+
* // → { fields: { target: ['id', 'role'] } }
|
|
23
|
+
*
|
|
24
|
+
* // Case 3: fields: { target: ['id'] } + ACL needs profile → don't add profile fields
|
|
25
|
+
* mergeQueryWithAclData({ fields: { target: ['id'] } }, { profile: ['isPublic'] })
|
|
26
|
+
* // → { fields: { target: ['id'] } } (profile missing = all fields)
|
|
27
|
+
*/
|
|
28
|
+
function mergeQueryWithAclData(query, aclFields, aclInclude) {
|
|
29
|
+
// Start with merged query
|
|
30
|
+
const mergedQuery = { ...query };
|
|
31
|
+
// 1. Always merge includes (add ACL includes to user includes)
|
|
32
|
+
if (aclInclude &&
|
|
33
|
+
'length' in aclInclude &&
|
|
34
|
+
parseInt(`${aclInclude.length}`) > 0) {
|
|
35
|
+
const userInclude = Array.isArray(query.include) ? query.include : [];
|
|
36
|
+
const aclIncludeArray = Array.isArray(aclInclude) ? aclInclude : [];
|
|
37
|
+
mergedQuery.include = Array.from(new Set([...userInclude, ...aclIncludeArray]));
|
|
38
|
+
}
|
|
39
|
+
// 2. Merge fields (complex logic for null/undefined handling)
|
|
40
|
+
if (!aclFields) {
|
|
41
|
+
return mergedQuery; // No ACL fields to merge
|
|
42
|
+
}
|
|
43
|
+
// CASE 1: fields === null → "select ALL fields everywhere"
|
|
44
|
+
if (query.fields === null) {
|
|
45
|
+
return mergedQuery; // Don't modify, null already includes all ACL fields
|
|
46
|
+
}
|
|
47
|
+
// CASE 2: fields === undefined → "select ALL fields everywhere"
|
|
48
|
+
if (query.fields === undefined) {
|
|
49
|
+
return mergedQuery; // Don't modify
|
|
50
|
+
}
|
|
51
|
+
// CASE 3: fields === {} (empty object) → "select ALL fields everywhere"
|
|
52
|
+
if (Object.keys(query.fields).length === 0) {
|
|
53
|
+
return mergedQuery; // Don't modify
|
|
54
|
+
}
|
|
55
|
+
// CASE 4: fields is object with keys → merge selectively
|
|
56
|
+
mergedQuery.fields = { ...query.fields };
|
|
57
|
+
for (const [relation, aclFieldsList] of Object.entries(aclFields)) {
|
|
58
|
+
if (!Array.isArray(aclFieldsList)) {
|
|
59
|
+
continue; // Skip invalid ACL fields
|
|
60
|
+
}
|
|
61
|
+
const userFieldsList = query.fields[relation];
|
|
62
|
+
// Sub-case 1: relation key missing in user fields → "all fields for this relation"
|
|
63
|
+
if (userFieldsList === undefined) {
|
|
64
|
+
continue; // Don't add ACL fields, user wants all fields for this relation
|
|
65
|
+
}
|
|
66
|
+
// Sub-case 2: relation: null → "all fields for this relation"
|
|
67
|
+
if (userFieldsList === null) {
|
|
68
|
+
continue; // Don't add ACL fields
|
|
69
|
+
}
|
|
70
|
+
// Sub-case 3: relation is array → merge with ACL fields
|
|
71
|
+
if (Array.isArray(userFieldsList)) {
|
|
72
|
+
const merged = [...new Set([...userFieldsList, ...aclFieldsList])];
|
|
73
|
+
mergedQuery.fields[relation] = merged;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return mergedQuery;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=merge-query-with-acl-data.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge-query-with-acl-data.js","sourceRoot":"","sources":["../../../../../../../../libs/acl-permissions/nestjs-acl-permissions/src/lib/utils/orm-proxy/merge-query-with-acl-data.ts"],"names":[],"mappings":";;AA0BA,sDAyEC;AAjGD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,SAAgB,qBAAqB,CAKnC,KAAQ,EACR,SAAgC,EAChC,UAAkC;IAElC,0BAA0B;IAC1B,MAAM,WAAW,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC;IAEjC,+DAA+D;IAC/D,IACE,UAAU;QACV,QAAQ,IAAI,UAAU;QACtB,QAAQ,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EACpC,CAAC;QACD,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QACtE,MAAM,eAAe,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;QACpE,WAAW,CAAC,OAAO,GAAG,KAAK,CAAC,IAAI,CAC9B,IAAI,GAAG,CAAC,CAAC,GAAG,WAAW,EAAE,GAAG,eAAe,CAAC,CAAC,CACvC,CAAC;IACX,CAAC;IAED,8DAA8D;IAC9D,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,WAAW,CAAC,CAAC,yBAAyB;IAC/C,CAAC;IAED,2DAA2D;IAC3D,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;QAC1B,OAAO,WAAW,CAAC,CAAC,qDAAqD;IAC3E,CAAC;IAED,gEAAgE;IAChE,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAC/B,OAAO,WAAW,CAAC,CAAC,eAAe;IACrC,CAAC;IAED,wEAAwE;IACxE,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3C,OAAO,WAAW,CAAC,CAAC,eAAe;IACrC,CAAC;IAED,yDAAyD;IACzD,WAAW,CAAC,MAAM,GAAG,EAAE,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;IAEzC,KAAK,MAAM,CAAC,QAAQ,EAAE,aAAa,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QAClE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC;YAClC,SAAS,CAAC,0BAA0B;QACtC,CAAC;QAED,MAAM,cAAc,GAAI,KAAK,CAAC,MAAc,CAAC,QAAQ,CAAC,CAAC;QAEvD,mFAAmF;QACnF,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;YACjC,SAAS,CAAC,gEAAgE;QAC5E,CAAC;QAED,8DAA8D;QAC9D,IAAI,cAAc,KAAK,IAAI,EAAE,CAAC;YAC5B,SAAS,CAAC,uBAAuB;QACnC,CAAC;QAED,wDAAwD;QACxD,IAAI,KAAK,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC;YAClC,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,cAAc,EAAE,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;YAClE,WAAW,CAAC,MAAc,CAAC,QAAQ,CAAC,GAAG,MAAM,CAAC;QACjD,CAAC;IACH,CAAC;IAED,OAAO,WAAW,CAAC;AACrB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ExtendAbility } from '../../factories';
|
|
2
|
+
import { Query, QueryOne } from '@klerick/json-api-nestjs';
|
|
3
|
+
export declare function prepareAclQuery<E extends object, IdKey extends string, Q extends QueryOne<E, IdKey> | Query<E, IdKey>>(extendAbility: ExtendAbility, query: Q, needValidateRules?: boolean): {
|
|
4
|
+
transformToJsonApi: boolean;
|
|
5
|
+
aclQueryData: {
|
|
6
|
+
fields?: Q[import("dist/libs/json-api/json-api-nestjs-shared/cjs/src").QueryField.fields] | undefined;
|
|
7
|
+
include?: Q[import("dist/libs/json-api/json-api-nestjs-shared/cjs/src").QueryField.include] | undefined;
|
|
8
|
+
rulesForQuery?: Record<string, unknown>;
|
|
9
|
+
} | undefined;
|
|
10
|
+
mergedQuery: Q;
|
|
11
|
+
} | null;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.prepareAclQuery = prepareAclQuery;
|
|
4
|
+
const merge_query_with_acl_data_1 = require("./merge-query-with-acl-data");
|
|
5
|
+
const validate_rules_for_orm_1 = require("./validate-rules-for-orm");
|
|
6
|
+
function prepareAclQuery(extendAbility, query, needValidateRules = true) {
|
|
7
|
+
// Fast path: no rules or no restrictions
|
|
8
|
+
if (!extendAbility ||
|
|
9
|
+
extendAbility.rules.length === 0 ||
|
|
10
|
+
(!extendAbility.hasConditions && !extendAbility.hasFields)) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
// Determine strategy
|
|
14
|
+
const hasConditions = extendAbility.hasConditions;
|
|
15
|
+
const hasFields = extendAbility.hasFields;
|
|
16
|
+
const transformToJsonApi = hasConditions && !hasFields;
|
|
17
|
+
// Validate rules for ORM compatibility if there are conditions
|
|
18
|
+
if (needValidateRules && hasConditions) {
|
|
19
|
+
(0, validate_rules_for_orm_1.validateRulesForORM)(extendAbility);
|
|
20
|
+
}
|
|
21
|
+
// Fetch with ACL query
|
|
22
|
+
const aclQueryData = hasConditions
|
|
23
|
+
? extendAbility.getQueryObject()
|
|
24
|
+
: undefined;
|
|
25
|
+
// Merge ACL query with user query
|
|
26
|
+
const mergedQuery = aclQueryData
|
|
27
|
+
? (0, merge_query_with_acl_data_1.mergeQueryWithAclData)(query, aclQueryData.fields, aclQueryData.include)
|
|
28
|
+
: query;
|
|
29
|
+
return {
|
|
30
|
+
transformToJsonApi,
|
|
31
|
+
aclQueryData,
|
|
32
|
+
mergedQuery,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=prepare-acl-query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prepare-acl-query.js","sourceRoot":"","sources":["../../../../../../../../libs/acl-permissions/nestjs-acl-permissions/src/lib/utils/orm-proxy/prepare-acl-query.ts"],"names":[],"mappings":";;AAKA,0CA2CC;AA/CD,2EAAoE;AACpE,qEAA+D;AAG/D,SAAgB,eAAe,CAC7B,aAA4B,EAC5B,KAAQ,EACR,iBAAiB,GAAG,IAAI;IAExB,yCAAyC;IACzC,IACE,CAAC,aAAa;QACd,aAAa,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;QAChC,CAAC,CAAC,aAAa,CAAC,aAAa,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,EAC1D,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,qBAAqB;IACrB,MAAM,aAAa,GAAG,aAAa,CAAC,aAAa,CAAC;IAClD,MAAM,SAAS,GAAG,aAAa,CAAC,SAAS,CAAC;IAC1C,MAAM,kBAAkB,GAAG,aAAa,IAAI,CAAC,SAAS,CAAC;IAEvD,+DAA+D;IAC/D,IAAI,iBAAiB,IAAI,aAAa,EAAE,CAAC;QACvC,IAAA,4CAAmB,EAAC,aAAa,CAAC,CAAC;IACrC,CAAC;IAED,uBAAuB;IACvB,MAAM,YAAY,GAAG,aAAa;QAChC,CAAC,CAAC,aAAa,CAAC,cAAc,EAAe;QAC7C,CAAC,CAAC,SAAS,CAAC;IAEd,kCAAkC;IAClC,MAAM,WAAW,GAAG,YAAY;QAC9B,CAAC,CAAC,IAAA,iDAAqB,EACnB,KAAK,EACL,YAAY,CAAC,MAAM,EACnB,YAAY,CAAC,OAAO,CACrB;QACH,CAAC,CAAC,KAAK,CAAC;IAEV,OAAO;QACL,kBAAkB;QAClB,YAAY;QACZ,WAAW;KACZ,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ExtendAbility } from '../../factories';
|
|
2
|
+
import { QueryField } from '@klerick/json-api-nestjs-shared';
|
|
3
|
+
import { Query, QueryOne } from '@klerick/json-api-nestjs';
|
|
4
|
+
/**
|
|
5
|
+
* Processes field restrictions for a single item
|
|
6
|
+
*
|
|
7
|
+
* This function:
|
|
8
|
+
* 1. Updates ability with item data for @input templates
|
|
9
|
+
* 2. Checks each field against ACL rules
|
|
10
|
+
* 3. Removes restricted fields from the item
|
|
11
|
+
* 4. Removes ACL-added fields that weren't requested by user
|
|
12
|
+
*
|
|
13
|
+
* @param item - Entity item to process (mutated in place)
|
|
14
|
+
* @param fieldsForCheck - Array of field paths to check
|
|
15
|
+
* @param extendAbility - ExtendAbility instance for permission checking
|
|
16
|
+
* @param query - Original user query
|
|
17
|
+
* @param aclQueryData - ACL query data (fields and include added by ACL)
|
|
18
|
+
* @returns Array of restricted field names
|
|
19
|
+
*/
|
|
20
|
+
export declare function processItemFieldRestrictions<E extends object, IdKey extends string, Q extends QueryOne<E, IdKey> | Query<E, IdKey>>(item: E, fieldsForCheck: string[], extendAbility: ExtendAbility, query: Q, aclQueryData?: {
|
|
21
|
+
fields?: Q[QueryField.fields];
|
|
22
|
+
include?: Q[QueryField.include];
|
|
23
|
+
rulesForQuery?: Record<string, unknown>;
|
|
24
|
+
}): string[];
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.processItemFieldRestrictions = processItemFieldRestrictions;
|
|
4
|
+
const ability_1 = require("@casl/ability");
|
|
5
|
+
const unset_deep_1 = require("./unset-deep");
|
|
6
|
+
const remove_acl_added_fields_1 = require("./remove-acl-added-fields");
|
|
7
|
+
/**
|
|
8
|
+
* Processes field restrictions for a single item
|
|
9
|
+
*
|
|
10
|
+
* This function:
|
|
11
|
+
* 1. Updates ability with item data for @input templates
|
|
12
|
+
* 2. Checks each field against ACL rules
|
|
13
|
+
* 3. Removes restricted fields from the item
|
|
14
|
+
* 4. Removes ACL-added fields that weren't requested by user
|
|
15
|
+
*
|
|
16
|
+
* @param item - Entity item to process (mutated in place)
|
|
17
|
+
* @param fieldsForCheck - Array of field paths to check
|
|
18
|
+
* @param extendAbility - ExtendAbility instance for permission checking
|
|
19
|
+
* @param query - Original user query
|
|
20
|
+
* @param aclQueryData - ACL query data (fields and include added by ACL)
|
|
21
|
+
* @returns Array of restricted field names
|
|
22
|
+
*/
|
|
23
|
+
function processItemFieldRestrictions(item, fieldsForCheck, extendAbility, query, aclQueryData) {
|
|
24
|
+
// Update ability with item data for @input templates
|
|
25
|
+
extendAbility.updateWithInput(item);
|
|
26
|
+
const currentAction = extendAbility.action;
|
|
27
|
+
const restrictedFieldsForItem = [];
|
|
28
|
+
// Check each field
|
|
29
|
+
for (const field of fieldsForCheck) {
|
|
30
|
+
if (!extendAbility.can(currentAction, (0, ability_1.subject)(extendAbility.subject, item), field)) {
|
|
31
|
+
// Remove field from item
|
|
32
|
+
(0, unset_deep_1.unsetDeep)(item, field);
|
|
33
|
+
restrictedFieldsForItem.push(field);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// Remove ACL-added fields and relations that were not requested by user
|
|
37
|
+
if (aclQueryData) {
|
|
38
|
+
(0, remove_acl_added_fields_1.removeAclAddedFields)(item, query['fields'], aclQueryData.fields, query['include'], aclQueryData.include);
|
|
39
|
+
}
|
|
40
|
+
return restrictedFieldsForItem;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=process-item-field-restrictions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-item-field-restrictions.js","sourceRoot":"","sources":["../../../../../../../../libs/acl-permissions/nestjs-acl-permissions/src/lib/utils/orm-proxy/process-item-field-restrictions.ts"],"names":[],"mappings":";;AAuBA,oEAgDC;AAvED,2CAA0D;AAE1D,6CAAyC;AACzC,uEAAiE;AAIjE;;;;;;;;;;;;;;;GAeG;AACH,SAAgB,4BAA4B,CAK1C,IAAO,EACP,cAAwB,EACxB,aAA4B,EAC5B,KAAQ,EACR,YAIC;IAED,qDAAqD;IACrD,aAAa,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;IAEpC,MAAM,aAAa,GAAG,aAAa,CAAC,MAAM,CAAC;IAC3C,MAAM,uBAAuB,GAAa,EAAE,CAAC;IAE7C,mBAAmB;IACnB,KAAK,MAAM,KAAK,IAAI,cAAc,EAAE,CAAC;QACnC,IACE,CAAC,aAAa,CAAC,GAAG,CAChB,aAAa,EACb,IAAA,iBAAc,EAAC,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,EAC3C,KAAK,CACN,EACD,CAAC;YACD,yBAAyB;YACzB,IAAA,sBAAS,EAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YACvB,uBAAuB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAED,wEAAwE;IACxE,IAAI,YAAY,EAAE,CAAC;QACjB,IAAA,8CAAoB,EAClB,IAAI,EACJ,KAAK,CAAC,QAAQ,CAAC,EACf,YAAY,CAAC,MAAM,EACnB,KAAK,CAAC,SAAS,CAAC,EAChB,YAAY,CAAC,OAAO,CACrB,CAAC;IACJ,CAAC;IAED,OAAO,uBAAuB,CAAC;AACjC,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Query, QueryOne } from '@klerick/json-api-nestjs';
|
|
2
|
+
import { QueryField } from '@klerick/json-api-nestjs-shared';
|
|
3
|
+
/**
|
|
4
|
+
* Removes ACL-added fields and relations from item that were not requested by user
|
|
5
|
+
*
|
|
6
|
+
* IMPORTANT: Must match the logic of mergeQueryWithAclData!
|
|
7
|
+
* Only removes fields/relations that were ACTUALLY ADDED by mergeQueryWithAclData.
|
|
8
|
+
*
|
|
9
|
+
* mergeQueryWithAclData adds ACL fields ONLY when userFields[relation] is an array.
|
|
10
|
+
* It does NOT add when: null, undefined, {}, missing key, or relation: null.
|
|
11
|
+
*
|
|
12
|
+
* @param item - Entity item to clean
|
|
13
|
+
* @param userFields - Fields requested by user (query.fields)
|
|
14
|
+
* @param aclFields - Fields added by ACL (aclQueryData.fields)
|
|
15
|
+
* @param userInclude - Relations requested by user (query.include)
|
|
16
|
+
* @param aclInclude - Relations added by ACL (aclQueryData.include)
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* // Case 1: userFields: null → ACL didn't add fields, don't remove
|
|
20
|
+
* removeAclAddedFields(item, null, { target: ['role'] })
|
|
21
|
+
* // → nothing removed (null = all fields requested)
|
|
22
|
+
*
|
|
23
|
+
* // Case 2: userFields: { target: ['id'] } → ACL added 'role', remove it
|
|
24
|
+
* removeAclAddedFields(item, { target: ['id'] }, { target: ['role'] })
|
|
25
|
+
* // → removes 'role' from item
|
|
26
|
+
*
|
|
27
|
+
* // Case 3: ACL added include → remove entire relation
|
|
28
|
+
* removeAclAddedFields(item, null, null, [], ['profile'])
|
|
29
|
+
* // → removes profile relation (not requested by user)
|
|
30
|
+
*/
|
|
31
|
+
export declare function removeAclAddedFields<E extends object, IdKey extends string, Q extends QueryOne<E, IdKey> | Query<E, IdKey>>(item: E, userFields?: Q[QueryField.fields], aclFields?: Q[QueryField.fields], userInclude?: Q[QueryField.include], aclInclude?: Q[QueryField.include]): void;
|