@adaas/a-utils 0.1.6 → 0.1.8
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 +393 -6
- package/dist/src/lib/A-Channel/A-Channel.component.d.ts +19 -0
- package/dist/src/lib/A-Channel/A-Channel.component.js +76 -0
- package/dist/src/lib/A-Channel/A-Channel.component.js.map +1 -1
- package/dist/src/lib/A-Channel/A-Channel.error.d.ts +1 -0
- package/dist/src/lib/A-Channel/A-Channel.error.js +1 -0
- package/dist/src/lib/A-Channel/A-Channel.error.js.map +1 -1
- package/dist/src/lib/A-Config/A-Config.container.js +1 -1
- package/dist/src/lib/A-Config/A-Config.container.js.map +1 -1
- package/dist/src/lib/A-Manifest/A-Manifest.context.d.ts +52 -0
- package/dist/src/lib/A-Manifest/A-Manifest.context.js +154 -0
- package/dist/src/lib/A-Manifest/A-Manifest.context.js.map +1 -0
- package/dist/src/lib/A-Manifest/A-Manifest.error.d.ts +4 -0
- package/dist/src/lib/A-Manifest/A-Manifest.error.js +9 -0
- package/dist/src/lib/A-Manifest/A-Manifest.error.js.map +1 -0
- package/dist/src/lib/A-Manifest/A-Manifest.types.d.ts +43 -0
- package/dist/src/lib/A-Manifest/A-Manifest.types.js +3 -0
- package/dist/src/lib/A-Manifest/A-Manifest.types.js.map +1 -0
- package/dist/src/lib/A-Manifest/classes/A-ManifestChecker.class.d.ts +13 -0
- package/dist/src/lib/A-Manifest/classes/A-ManifestChecker.class.js +24 -0
- package/dist/src/lib/A-Manifest/classes/A-ManifestChecker.class.js.map +1 -0
- package/package.json +2 -2
- package/src/lib/A-Channel/A-Channel.component.ts +70 -2
- package/src/lib/A-Channel/A-Channel.error.ts +2 -0
- package/src/lib/A-Config/A-Config.container.ts +1 -1
- package/src/lib/A-Manifest/A-Manifest.context.ts +198 -0
- package/src/lib/A-Manifest/A-Manifest.error.ts +7 -0
- package/src/lib/A-Manifest/A-Manifest.types.ts +62 -0
- package/src/lib/A-Manifest/README.md +201 -0
- package/src/lib/A-Manifest/classes/A-ManifestChecker.class.ts +24 -0
- package/tests/A-Manifest.test.ts +290 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.A_Manifest = void 0;
|
|
4
|
+
const a_concept_1 = require("@adaas/a-concept");
|
|
5
|
+
const A_Manifest_error_1 = require("./A-Manifest.error");
|
|
6
|
+
const A_ManifestChecker_class_1 = require("./classes/A-ManifestChecker.class");
|
|
7
|
+
class A_Manifest extends a_concept_1.A_Fragment {
|
|
8
|
+
/**
|
|
9
|
+
* A-Manifest is a configuration set that allows to include or exclude component application for the particular methods.
|
|
10
|
+
*
|
|
11
|
+
* For example, if A-Scope provides polymorphic A-Component that applies for All A-Entities in it but you have another component that should be used for only One particular Entity, you can use A-Manifest to specify this behavior.
|
|
12
|
+
*
|
|
13
|
+
*
|
|
14
|
+
* By default if Component is provided in the scope - it applies for all entities in it. However, if you want to exclude some entities or include only some entities for the particular component - you can use A-Manifest to define this behavior.
|
|
15
|
+
*
|
|
16
|
+
* @param config - Array of component configurations
|
|
17
|
+
*/
|
|
18
|
+
constructor(config = []) {
|
|
19
|
+
super({
|
|
20
|
+
name: 'A-Manifest',
|
|
21
|
+
});
|
|
22
|
+
this.rules = [];
|
|
23
|
+
this.prepare(config);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Should convert received configuration into internal Regexp applicable for internal storage
|
|
27
|
+
*/
|
|
28
|
+
prepare(config) {
|
|
29
|
+
if (!a_concept_1.A_TypeGuards.isArray(config))
|
|
30
|
+
throw new A_Manifest_error_1.A_ManifestError(A_Manifest_error_1.A_ManifestError.ManifestInitializationError, `A-Manifest configuration should be an array of configurations`);
|
|
31
|
+
for (const item of config) {
|
|
32
|
+
this.processConfigItem(item);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Process a single configuration item and convert it to internal rules
|
|
37
|
+
*/
|
|
38
|
+
processConfigItem(item) {
|
|
39
|
+
if (!a_concept_1.A_TypeGuards.isComponentConstructor(item.component))
|
|
40
|
+
throw new A_Manifest_error_1.A_ManifestError(A_Manifest_error_1.A_ManifestError.ManifestInitializationError, `A-Manifest configuration item should be a A-Component constructor`);
|
|
41
|
+
const componentRegex = this.constructorToRegex(item.component);
|
|
42
|
+
// Always add component-level rule first (applies to all methods)
|
|
43
|
+
if (item.apply || item.exclude) {
|
|
44
|
+
const methodRegex = /.*/; // Match all methods
|
|
45
|
+
this.rules.push({
|
|
46
|
+
componentRegex,
|
|
47
|
+
methodRegex,
|
|
48
|
+
applyRegex: item.apply ? this.allowedComponentsToRegex(item.apply) : undefined,
|
|
49
|
+
excludeRegex: item.exclude ? this.allowedComponentsToRegex(item.exclude) : undefined,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
// Then add method-level configurations (these will override component-level)
|
|
53
|
+
if (item.methods && item.methods.length > 0) {
|
|
54
|
+
for (const methodConfig of item.methods) {
|
|
55
|
+
const methodRegex = this.methodToRegex(methodConfig.method);
|
|
56
|
+
this.rules.push({
|
|
57
|
+
componentRegex,
|
|
58
|
+
methodRegex,
|
|
59
|
+
applyRegex: methodConfig.apply ? this.allowedComponentsToRegex(methodConfig.apply) : undefined,
|
|
60
|
+
excludeRegex: methodConfig.exclude ? this.allowedComponentsToRegex(methodConfig.exclude) : undefined,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Convert a constructor to a regex pattern
|
|
67
|
+
*/
|
|
68
|
+
constructorToRegex(ctor) {
|
|
69
|
+
return new RegExp(`^${this.escapeRegex(ctor.name)}$`);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Convert a method name or regex to a regex pattern
|
|
73
|
+
*/
|
|
74
|
+
methodToRegex(method) {
|
|
75
|
+
if (method instanceof RegExp) {
|
|
76
|
+
return method;
|
|
77
|
+
}
|
|
78
|
+
return new RegExp(`^${this.escapeRegex(method)}$`);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Convert allowed components array or regex to a single regex
|
|
82
|
+
*/
|
|
83
|
+
allowedComponentsToRegex(components) {
|
|
84
|
+
if (components instanceof RegExp) {
|
|
85
|
+
return components;
|
|
86
|
+
}
|
|
87
|
+
const patterns = components.map(ctor => this.escapeRegex(ctor.name));
|
|
88
|
+
return new RegExp(`^(${patterns.join('|')})$`);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Escape special regex characters in a string
|
|
92
|
+
*/
|
|
93
|
+
escapeRegex(str) {
|
|
94
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
95
|
+
}
|
|
96
|
+
configItemToRegexp(item) {
|
|
97
|
+
return this.constructorToRegex(item);
|
|
98
|
+
}
|
|
99
|
+
ID(component, method) {
|
|
100
|
+
return `${component.name}.${method}`;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Check if a component and method combination is allowed for a target
|
|
104
|
+
*/
|
|
105
|
+
isAllowed(ctor, method) {
|
|
106
|
+
const componentCtor = typeof ctor === 'function' ? ctor : ctor.constructor;
|
|
107
|
+
return new A_ManifestChecker_class_1.A_ManifestChecker(this, componentCtor, method);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Internal method to check if access is allowed
|
|
111
|
+
*/
|
|
112
|
+
internal_checkAccess(query) {
|
|
113
|
+
const componentName = query.component.name;
|
|
114
|
+
const methodName = query.method;
|
|
115
|
+
const targetName = query.target.name;
|
|
116
|
+
// Find matching rules, sorted by specificity (method-specific rules first)
|
|
117
|
+
const matchingRules = this.rules
|
|
118
|
+
.filter(rule => rule.componentRegex.test(componentName) &&
|
|
119
|
+
rule.methodRegex.test(methodName))
|
|
120
|
+
.sort((a, b) => {
|
|
121
|
+
// Method-specific rules (not .* pattern) should come before general rules
|
|
122
|
+
const aIsGeneral = a.methodRegex.source === '.*';
|
|
123
|
+
const bIsGeneral = b.methodRegex.source === '.*';
|
|
124
|
+
if (aIsGeneral && !bIsGeneral)
|
|
125
|
+
return 1; // b comes first
|
|
126
|
+
if (!aIsGeneral && bIsGeneral)
|
|
127
|
+
return -1; // a comes first
|
|
128
|
+
return 0; // same priority
|
|
129
|
+
});
|
|
130
|
+
// If no rules match, allow by default
|
|
131
|
+
if (matchingRules.length === 0) {
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
// Process rules in order of specificity (most specific first)
|
|
135
|
+
for (const rule of matchingRules) {
|
|
136
|
+
// If this rule has an exclusion that matches, deny access
|
|
137
|
+
if (rule.excludeRegex && rule.excludeRegex.test(targetName)) {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
// If this rule has an apply list, check if target is in it
|
|
141
|
+
if (rule.applyRegex) {
|
|
142
|
+
return rule.applyRegex.test(targetName);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
// If we have rules but no specific apply/exclude, allow by default
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
isExcluded(ctor, method) {
|
|
149
|
+
const componentCtor = typeof ctor === 'function' ? ctor : ctor.constructor;
|
|
150
|
+
return new A_ManifestChecker_class_1.A_ManifestChecker(this, componentCtor, method, true);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
exports.A_Manifest = A_Manifest;
|
|
154
|
+
//# sourceMappingURL=A-Manifest.context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"A-Manifest.context.js","sourceRoot":"","sources":["../../../../src/lib/A-Manifest/A-Manifest.context.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.A_ManifestError = void 0;
|
|
4
|
+
const a_concept_1 = require("@adaas/a-concept");
|
|
5
|
+
class A_ManifestError extends a_concept_1.A_Error {
|
|
6
|
+
}
|
|
7
|
+
exports.A_ManifestError = A_ManifestError;
|
|
8
|
+
A_ManifestError.ManifestInitializationError = 'A-Manifest Initialization Error';
|
|
9
|
+
//# sourceMappingURL=A-Manifest.error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"A-Manifest.error.js","sourceRoot":"","sources":["../../../../src/lib/A-Manifest/A-Manifest.error.ts"],"names":[],"mappings":";;;AAAA,gDAA2C;AAE3C,MAAa,eAAgB,SAAQ,mBAAO;;AAA5C,0CAIC;AAFmB,2CAA2B,GAAG,iCAAiC,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { A_Component, A_TYPES__Component_Constructor, A_TYPES__Entity_Constructor, A_TYPES__Fragment_Constructor } from "@adaas/a-concept";
|
|
2
|
+
import { A_TYPES__Container_Constructor } from "@adaas/a-concept/dist/src/global/A-Container/A-Container.types";
|
|
3
|
+
export type A_UTILS_TYPES__Manifest_Init = Array<A_UTILS_TYPES__Manifest_ComponentLevelConfig>;
|
|
4
|
+
export type A_UTILS_TYPES__Manifest_ComponentLevelConfig<T extends A_Component = A_Component> = {
|
|
5
|
+
/**
|
|
6
|
+
* Component constructor
|
|
7
|
+
*/
|
|
8
|
+
component: A_TYPES__Component_Constructor<T>;
|
|
9
|
+
/**
|
|
10
|
+
* Method level configurations for the component
|
|
11
|
+
*/
|
|
12
|
+
methods?: Array<A_UTILS_TYPES__Manifest_MethodLevelConfig<T>>;
|
|
13
|
+
} & Partial<A_UTILS_TYPES__Manifest_Rules>;
|
|
14
|
+
export type A_UTILS_TYPES__Manifest_MethodLevelConfig<T extends A_Component = A_Component> = {
|
|
15
|
+
/**
|
|
16
|
+
* Method name from the component provided
|
|
17
|
+
*/
|
|
18
|
+
method: string | RegExp;
|
|
19
|
+
} & Partial<A_UTILS_TYPES__Manifest_Rules>;
|
|
20
|
+
export type A_UTILS_TYPES__Manifest_Rules = {
|
|
21
|
+
/**
|
|
22
|
+
* A list of entities to which a component is applied
|
|
23
|
+
*
|
|
24
|
+
* By default is for all
|
|
25
|
+
*/
|
|
26
|
+
apply: Array<A_UTILS_TYPES__Manifest_AllowedComponents> | RegExp;
|
|
27
|
+
/**
|
|
28
|
+
* A list of entities to which a component is excluded
|
|
29
|
+
*/
|
|
30
|
+
exclude: Array<A_UTILS_TYPES__Manifest_AllowedComponents> | RegExp;
|
|
31
|
+
};
|
|
32
|
+
export type A_UTILS_TYPES__Manifest_AllowedComponents = A_TYPES__Component_Constructor | A_TYPES__Entity_Constructor | A_TYPES__Fragment_Constructor | A_TYPES__Container_Constructor;
|
|
33
|
+
export interface A_UTILS_TYPES__ManifestRule {
|
|
34
|
+
componentRegex: RegExp;
|
|
35
|
+
methodRegex: RegExp;
|
|
36
|
+
applyRegex?: RegExp;
|
|
37
|
+
excludeRegex?: RegExp;
|
|
38
|
+
}
|
|
39
|
+
export interface A_UTILS_TYPES__ManifestQuery {
|
|
40
|
+
component: A_TYPES__Component_Constructor;
|
|
41
|
+
method: string;
|
|
42
|
+
target: A_TYPES__Component_Constructor;
|
|
43
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"A-Manifest.types.js","sourceRoot":"","sources":["../../../../src/lib/A-Manifest/A-Manifest.types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { A_TYPES__Component_Constructor } from "@adaas/a-concept";
|
|
2
|
+
import { A_Manifest } from "../A-Manifest.context";
|
|
3
|
+
/**
|
|
4
|
+
* Fluent API for checking manifest permissions
|
|
5
|
+
*/
|
|
6
|
+
export declare class A_ManifestChecker {
|
|
7
|
+
private manifest;
|
|
8
|
+
private component;
|
|
9
|
+
private method;
|
|
10
|
+
private checkExclusion;
|
|
11
|
+
constructor(manifest: A_Manifest, component: A_TYPES__Component_Constructor, method: string, checkExclusion?: boolean);
|
|
12
|
+
for(target: A_TYPES__Component_Constructor): boolean;
|
|
13
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.A_ManifestChecker = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Fluent API for checking manifest permissions
|
|
6
|
+
*/
|
|
7
|
+
class A_ManifestChecker {
|
|
8
|
+
constructor(manifest, component, method, checkExclusion = false) {
|
|
9
|
+
this.manifest = manifest;
|
|
10
|
+
this.component = component;
|
|
11
|
+
this.method = method;
|
|
12
|
+
this.checkExclusion = checkExclusion;
|
|
13
|
+
}
|
|
14
|
+
for(target) {
|
|
15
|
+
const result = this.manifest.internal_checkAccess({
|
|
16
|
+
component: this.component,
|
|
17
|
+
method: this.method,
|
|
18
|
+
target: target
|
|
19
|
+
});
|
|
20
|
+
return this.checkExclusion ? !result : result;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
exports.A_ManifestChecker = A_ManifestChecker;
|
|
24
|
+
//# sourceMappingURL=A-ManifestChecker.class.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"A-ManifestChecker.class.js","sourceRoot":"","sources":["../../../../../src/lib/A-Manifest/classes/A-ManifestChecker.class.ts"],"names":[],"mappings":";;;AAGA;;GAEG;AACH,MAAa,iBAAiB;IAC1B,YACY,QAAoB,EACpB,SAAyC,EACzC,MAAc,EACd,iBAA0B,KAAK;QAH/B,aAAQ,GAAR,QAAQ,CAAY;QACpB,cAAS,GAAT,SAAS,CAAgC;QACzC,WAAM,GAAN,MAAM,CAAQ;QACd,mBAAc,GAAd,cAAc,CAAiB;IACxC,CAAC;IAEJ,GAAG,CAAC,MAAsC;QACtC,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,oBAAoB,CAAC;YAC9C,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,MAAM,EAAE,MAAM;SACjB,CAAC,CAAC;QAEH,OAAO,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;IAClD,CAAC;CACJ;AAjBD,8CAiBC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adaas/a-utils",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "A-Utils is a set of utilities that are used across the ADAAS ecosystem. This package is designed to be a collection of utilities that are used across the ADAAS ecosystem.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
},
|
|
51
51
|
"homepage": "https://github.com/ADAAS-org/adaas-adf-auth#readme",
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@adaas/a-concept": "^0.1.
|
|
53
|
+
"@adaas/a-concept": "^0.1.24"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@types/chai": "^4.3.14",
|
|
@@ -1,8 +1,76 @@
|
|
|
1
|
-
import { A_Component,
|
|
1
|
+
import { A_Component, A_Feature } from "@adaas/a-concept";
|
|
2
|
+
import { A_ChannelError } from "./A-Channel.error";
|
|
2
3
|
|
|
3
4
|
|
|
4
5
|
|
|
5
6
|
export class A_Channel extends A_Component {
|
|
6
7
|
|
|
8
|
+
/**
|
|
9
|
+
* Indicates whether the channel is processing requests
|
|
10
|
+
*/
|
|
11
|
+
protected _processing: boolean = false;
|
|
12
|
+
/**
|
|
13
|
+
* Indicates whether the channel is connected
|
|
14
|
+
*/
|
|
15
|
+
protected _initialized?: Promise<void>;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Indicates whether the channel is processing requests
|
|
19
|
+
*/
|
|
20
|
+
get processing(): boolean {
|
|
21
|
+
return this._processing;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Indicates whether the channel is connected
|
|
25
|
+
*/
|
|
26
|
+
get initialize(): Promise<void> {
|
|
27
|
+
if (!this._initialized) {
|
|
28
|
+
this._initialized = this.connect();
|
|
29
|
+
}
|
|
30
|
+
return this._initialized;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@A_Feature.Define()
|
|
35
|
+
/**
|
|
36
|
+
* Initializes the channel before use
|
|
37
|
+
*/
|
|
38
|
+
async connect() {
|
|
39
|
+
throw new A_ChannelError(
|
|
40
|
+
A_ChannelError.MethodNotImplemented,
|
|
41
|
+
`The connect method is not implemented in ${this.constructor.name} channel. This method is required to initialize the channel before use. So please implement it in the derived class.`
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@A_Feature.Define()
|
|
47
|
+
/**
|
|
48
|
+
* Allows to send a request through the channel
|
|
49
|
+
*
|
|
50
|
+
* @param req - The request parameters
|
|
51
|
+
* @returns The response from the channel
|
|
52
|
+
*/
|
|
53
|
+
async request(params: any): Promise<any> {
|
|
54
|
+
throw new A_ChannelError(
|
|
55
|
+
A_ChannelError.MethodNotImplemented,
|
|
56
|
+
`The request method is not implemented in ${this.constructor.name} channel.`
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@A_Feature.Define()
|
|
63
|
+
/**
|
|
64
|
+
* Uses for Fire-and-Forget messaging through the channel
|
|
65
|
+
*
|
|
66
|
+
* @param message - can be of any type depending on the channel implementation
|
|
67
|
+
*/
|
|
68
|
+
async send(message: any): Promise<void> {
|
|
69
|
+
throw new A_ChannelError(
|
|
70
|
+
A_ChannelError.MethodNotImplemented,
|
|
71
|
+
`The send method is not implemented in ${this.constructor.name} channel.`
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
}
|
|
7
76
|
|
|
8
|
-
}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { A_Component, A_Fragment, A_TypeGuards, A_TYPES__Component_Constructor } from "@adaas/a-concept";
|
|
2
|
+
import { A_UTILS_TYPES__Manifest_Init, A_UTILS_TYPES__Manifest_ComponentLevelConfig, A_UTILS_TYPES__Manifest_AllowedComponents, A_UTILS_TYPES__ManifestRule, A_UTILS_TYPES__ManifestQuery } from "./A-Manifest.types";
|
|
3
|
+
import { A_ManifestError } from "./A-Manifest.error";
|
|
4
|
+
import { A_ManifestChecker } from "./classes/A-ManifestChecker.class";
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
export class A_Manifest extends A_Fragment {
|
|
11
|
+
|
|
12
|
+
private rules: A_UTILS_TYPES__ManifestRule[] = [];
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* A-Manifest is a configuration set that allows to include or exclude component application for the particular methods.
|
|
16
|
+
*
|
|
17
|
+
* For example, if A-Scope provides polymorphic A-Component that applies for All A-Entities in it but you have another component that should be used for only One particular Entity, you can use A-Manifest to specify this behavior.
|
|
18
|
+
*
|
|
19
|
+
*
|
|
20
|
+
* By default if Component is provided in the scope - it applies for all entities in it. However, if you want to exclude some entities or include only some entities for the particular component - you can use A-Manifest to define this behavior.
|
|
21
|
+
*
|
|
22
|
+
* @param config - Array of component configurations
|
|
23
|
+
*/
|
|
24
|
+
constructor(config: A_UTILS_TYPES__Manifest_Init = []) {
|
|
25
|
+
super({
|
|
26
|
+
name: 'A-Manifest',
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
this.prepare(config);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Should convert received configuration into internal Regexp applicable for internal storage
|
|
35
|
+
*/
|
|
36
|
+
protected prepare(config: A_UTILS_TYPES__Manifest_Init) {
|
|
37
|
+
if (!A_TypeGuards.isArray(config))
|
|
38
|
+
throw new A_ManifestError(
|
|
39
|
+
A_ManifestError.ManifestInitializationError,
|
|
40
|
+
`A-Manifest configuration should be an array of configurations`
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
for (const item of config) {
|
|
44
|
+
this.processConfigItem(item);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Process a single configuration item and convert it to internal rules
|
|
50
|
+
*/
|
|
51
|
+
private processConfigItem(item: A_UTILS_TYPES__Manifest_ComponentLevelConfig) {
|
|
52
|
+
if (!A_TypeGuards.isComponentConstructor(item.component))
|
|
53
|
+
throw new A_ManifestError(
|
|
54
|
+
A_ManifestError.ManifestInitializationError,
|
|
55
|
+
`A-Manifest configuration item should be a A-Component constructor`
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
const componentRegex = this.constructorToRegex(item.component);
|
|
59
|
+
|
|
60
|
+
// Always add component-level rule first (applies to all methods)
|
|
61
|
+
if (item.apply || item.exclude) {
|
|
62
|
+
const methodRegex = /.*/; // Match all methods
|
|
63
|
+
|
|
64
|
+
this.rules.push({
|
|
65
|
+
componentRegex,
|
|
66
|
+
methodRegex,
|
|
67
|
+
applyRegex: item.apply ? this.allowedComponentsToRegex(item.apply) : undefined,
|
|
68
|
+
excludeRegex: item.exclude ? this.allowedComponentsToRegex(item.exclude) : undefined,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Then add method-level configurations (these will override component-level)
|
|
73
|
+
if (item.methods && item.methods.length > 0) {
|
|
74
|
+
for (const methodConfig of item.methods) {
|
|
75
|
+
const methodRegex = this.methodToRegex(methodConfig.method);
|
|
76
|
+
|
|
77
|
+
this.rules.push({
|
|
78
|
+
componentRegex,
|
|
79
|
+
methodRegex,
|
|
80
|
+
applyRegex: methodConfig.apply ? this.allowedComponentsToRegex(methodConfig.apply) : undefined,
|
|
81
|
+
excludeRegex: methodConfig.exclude ? this.allowedComponentsToRegex(methodConfig.exclude) : undefined,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Convert a constructor to a regex pattern
|
|
91
|
+
*/
|
|
92
|
+
private constructorToRegex(ctor: A_TYPES__Component_Constructor): RegExp {
|
|
93
|
+
return new RegExp(`^${this.escapeRegex(ctor.name)}$`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Convert a method name or regex to a regex pattern
|
|
98
|
+
*/
|
|
99
|
+
private methodToRegex(method: string | RegExp): RegExp {
|
|
100
|
+
if (method instanceof RegExp) {
|
|
101
|
+
return method;
|
|
102
|
+
}
|
|
103
|
+
return new RegExp(`^${this.escapeRegex(method as string)}$`);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Convert allowed components array or regex to a single regex
|
|
108
|
+
*/
|
|
109
|
+
private allowedComponentsToRegex(components: A_UTILS_TYPES__Manifest_AllowedComponents[] | RegExp): RegExp {
|
|
110
|
+
if (components instanceof RegExp) {
|
|
111
|
+
return components;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const patterns = components.map(ctor => this.escapeRegex(ctor.name));
|
|
115
|
+
return new RegExp(`^(${patterns.join('|')})$`);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Escape special regex characters in a string
|
|
120
|
+
*/
|
|
121
|
+
private escapeRegex(str: string): string {
|
|
122
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
protected configItemToRegexp(item: A_TYPES__Component_Constructor): RegExp {
|
|
126
|
+
return this.constructorToRegex(item);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
protected ID(component: A_TYPES__Component_Constructor, method: string) {
|
|
131
|
+
return `${component.name}.${method}`;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Check if a component and method combination is allowed for a target
|
|
136
|
+
*/
|
|
137
|
+
isAllowed<T extends A_Component>(
|
|
138
|
+
ctor: T | A_TYPES__Component_Constructor<T>,
|
|
139
|
+
method: string
|
|
140
|
+
): A_ManifestChecker {
|
|
141
|
+
const componentCtor = typeof ctor === 'function' ? ctor : ctor.constructor as A_TYPES__Component_Constructor;
|
|
142
|
+
return new A_ManifestChecker(this, componentCtor, method);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Internal method to check if access is allowed
|
|
147
|
+
*/
|
|
148
|
+
internal_checkAccess(query: A_UTILS_TYPES__ManifestQuery): boolean {
|
|
149
|
+
const componentName = query.component.name;
|
|
150
|
+
const methodName = query.method;
|
|
151
|
+
const targetName = query.target.name;
|
|
152
|
+
|
|
153
|
+
// Find matching rules, sorted by specificity (method-specific rules first)
|
|
154
|
+
const matchingRules = this.rules
|
|
155
|
+
.filter(rule =>
|
|
156
|
+
rule.componentRegex.test(componentName) &&
|
|
157
|
+
rule.methodRegex.test(methodName)
|
|
158
|
+
)
|
|
159
|
+
.sort((a, b) => {
|
|
160
|
+
// Method-specific rules (not .* pattern) should come before general rules
|
|
161
|
+
const aIsGeneral = a.methodRegex.source === '.*';
|
|
162
|
+
const bIsGeneral = b.methodRegex.source === '.*';
|
|
163
|
+
|
|
164
|
+
if (aIsGeneral && !bIsGeneral) return 1; // b comes first
|
|
165
|
+
if (!aIsGeneral && bIsGeneral) return -1; // a comes first
|
|
166
|
+
return 0; // same priority
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// If no rules match, allow by default
|
|
170
|
+
if (matchingRules.length === 0) {
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Process rules in order of specificity (most specific first)
|
|
175
|
+
for (const rule of matchingRules) {
|
|
176
|
+
// If this rule has an exclusion that matches, deny access
|
|
177
|
+
if (rule.excludeRegex && rule.excludeRegex.test(targetName)) {
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// If this rule has an apply list, check if target is in it
|
|
182
|
+
if (rule.applyRegex) {
|
|
183
|
+
return rule.applyRegex.test(targetName);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// If we have rules but no specific apply/exclude, allow by default
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
isExcluded<T extends A_Component>(
|
|
192
|
+
ctor: T | A_TYPES__Component_Constructor<T>,
|
|
193
|
+
method: string
|
|
194
|
+
): A_ManifestChecker {
|
|
195
|
+
const componentCtor = typeof ctor === 'function' ? ctor : ctor.constructor as A_TYPES__Component_Constructor;
|
|
196
|
+
return new A_ManifestChecker(this, componentCtor, method, true);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { A_Component, A_Container, A_TYPES__Component_Constructor, A_TYPES__Entity_Constructor, A_TYPES__Fragment_Constructor } from "@adaas/a-concept"
|
|
2
|
+
import { A_TYPES__Container_Constructor } from "@adaas/a-concept/dist/src/global/A-Container/A-Container.types"
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export type A_UTILS_TYPES__Manifest_Init = Array<A_UTILS_TYPES__Manifest_ComponentLevelConfig>
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
export type A_UTILS_TYPES__Manifest_ComponentLevelConfig<T extends A_Component = A_Component> = {
|
|
10
|
+
/**
|
|
11
|
+
* Component constructor
|
|
12
|
+
*/
|
|
13
|
+
component: A_TYPES__Component_Constructor<T>,
|
|
14
|
+
/**
|
|
15
|
+
* Method level configurations for the component
|
|
16
|
+
*/
|
|
17
|
+
methods?: Array<A_UTILS_TYPES__Manifest_MethodLevelConfig<T>>
|
|
18
|
+
} & Partial<A_UTILS_TYPES__Manifest_Rules>
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
export type A_UTILS_TYPES__Manifest_MethodLevelConfig<T extends A_Component = A_Component> = {
|
|
23
|
+
/**
|
|
24
|
+
* Method name from the component provided
|
|
25
|
+
*/
|
|
26
|
+
method: string | RegExp
|
|
27
|
+
} & Partial<A_UTILS_TYPES__Manifest_Rules>
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
export type A_UTILS_TYPES__Manifest_Rules = {
|
|
32
|
+
/**
|
|
33
|
+
* A list of entities to which a component is applied
|
|
34
|
+
*
|
|
35
|
+
* By default is for all
|
|
36
|
+
*/
|
|
37
|
+
apply: Array<A_UTILS_TYPES__Manifest_AllowedComponents> | RegExp
|
|
38
|
+
/**
|
|
39
|
+
* A list of entities to which a component is excluded
|
|
40
|
+
*/
|
|
41
|
+
exclude: Array<A_UTILS_TYPES__Manifest_AllowedComponents> | RegExp
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export type A_UTILS_TYPES__Manifest_AllowedComponents = A_TYPES__Component_Constructor
|
|
45
|
+
| A_TYPES__Entity_Constructor
|
|
46
|
+
| A_TYPES__Fragment_Constructor
|
|
47
|
+
| A_TYPES__Container_Constructor
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
export interface A_UTILS_TYPES__ManifestRule {
|
|
52
|
+
componentRegex: RegExp;
|
|
53
|
+
methodRegex: RegExp;
|
|
54
|
+
applyRegex?: RegExp;
|
|
55
|
+
excludeRegex?: RegExp;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface A_UTILS_TYPES__ManifestQuery {
|
|
59
|
+
component: A_TYPES__Component_Constructor;
|
|
60
|
+
method: string;
|
|
61
|
+
target: A_TYPES__Component_Constructor;
|
|
62
|
+
}
|