@via-profit/ability 1.0.1
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 +421 -0
- package/dist/AbilityPolicy.d.ts +78 -0
- package/dist/AbilityRule.d.ts +108 -0
- package/dist/AbilityService.d.ts +74 -0
- package/dist/AbilityStatement.d.ts +98 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +573 -0
- package/package.json +74 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
export type AbilityStatementStatus = 'permit' | 'deny';
|
|
2
|
+
type SubjectPrefix = 'subject.' | 'environment.';
|
|
3
|
+
export type AbilityStatementMatches = [
|
|
4
|
+
`${SubjectPrefix}${string}`,
|
|
5
|
+
AbilityCondition,
|
|
6
|
+
string | number | boolean
|
|
7
|
+
];
|
|
8
|
+
export type AbilityCondition = '=' | '<>' | '>' | '<' | '<=' | '>=' | 'in';
|
|
9
|
+
declare class AbilityStatement {
|
|
10
|
+
matches: AbilityStatementMatches;
|
|
11
|
+
name: string;
|
|
12
|
+
effect: AbilityStatementStatus;
|
|
13
|
+
/**
|
|
14
|
+
* Create the statement to compare
|
|
15
|
+
*
|
|
16
|
+
* @param statementName {string} - The statement name
|
|
17
|
+
* @param effect {AbilityStatementStatus} - Return value
|
|
18
|
+
* @param matches {AbilityStatementMatches} - The matching rule he matching rule can be on of the format:
|
|
19
|
+
* \
|
|
20
|
+
* For example, be compared two's data\
|
|
21
|
+
* \
|
|
22
|
+
* _The subject_
|
|
23
|
+
* ```json
|
|
24
|
+
* {"userID": "1", "userDepartament": "NBC"}
|
|
25
|
+
* ```
|
|
26
|
+
* and _The resource_
|
|
27
|
+
* ```json
|
|
28
|
+
* {"departamentID": "154", "departamentName": "NBC"}
|
|
29
|
+
* ```
|
|
30
|
+
* \
|
|
31
|
+
* Now we can make the matching rule:
|
|
32
|
+
* ```json
|
|
33
|
+
* ["subject.userDepartament", "=", "resource.departamentName"]
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* \
|
|
37
|
+
* **Example 2.**\
|
|
38
|
+
* In this case will be compared resource and string:
|
|
39
|
+
* \
|
|
40
|
+
* _The subject_
|
|
41
|
+
* ```json
|
|
42
|
+
* {"userID": "1", "userDepartament": "NBC"}
|
|
43
|
+
* ```
|
|
44
|
+
* and _The resource_ will be «undefined».\
|
|
45
|
+
* Now we can make the matching rule:
|
|
46
|
+
* ```json
|
|
47
|
+
* ["subject.userDepartament", "=", "NBC"]
|
|
48
|
+
* ```
|
|
49
|
+
* \
|
|
50
|
+
* **Example 3.**\
|
|
51
|
+
* In this case will be compared resource and array of string:\
|
|
52
|
+
* \
|
|
53
|
+
* _The subject_
|
|
54
|
+
* ```json
|
|
55
|
+
* {"userID": "1", "userDepartament": "NBC"}
|
|
56
|
+
* ```
|
|
57
|
+
* and _The resource_
|
|
58
|
+
* ```json
|
|
59
|
+
* ["FOX", "NBC", "AONE"]
|
|
60
|
+
* ```
|
|
61
|
+
* \
|
|
62
|
+
* Now we can make the matching rule:
|
|
63
|
+
* ```json
|
|
64
|
+
* ["subject.userDepartament", "=", "resource"]
|
|
65
|
+
* ```
|
|
66
|
+
* **Note: In this rule whe set the resource field as the «resource» string.\
|
|
67
|
+
* This means that we will compare the entire resource as a whole,\
|
|
68
|
+
* and not search for it by field name.**
|
|
69
|
+
* \
|
|
70
|
+
* **Example 4.**\
|
|
71
|
+
* In this case will be compared resource and array of string:\
|
|
72
|
+
* \
|
|
73
|
+
* _The subject_
|
|
74
|
+
* ```json
|
|
75
|
+
* {"user": {"account": {"roles": ["admin", "viewer"]}}}
|
|
76
|
+
* ```
|
|
77
|
+
* and _The resource_
|
|
78
|
+
* ```json
|
|
79
|
+
* undefined
|
|
80
|
+
* ```
|
|
81
|
+
* \
|
|
82
|
+
* Now we can make the matching rule:
|
|
83
|
+
* ```json
|
|
84
|
+
* ["subject.user.account.roles", "in", "admin"]
|
|
85
|
+
*/
|
|
86
|
+
constructor(statementName: string, matches: AbilityStatementMatches, effect?: AbilityStatementStatus);
|
|
87
|
+
getName(): string;
|
|
88
|
+
getEffect(): AbilityStatementStatus;
|
|
89
|
+
isPermit(...args: Parameters<AbilityStatement['check']>): boolean;
|
|
90
|
+
isDeny(...args: Parameters<AbilityStatement['check']>): boolean;
|
|
91
|
+
check(subject: unknown, resource?: unknown | undefined, environment?: unknown | undefined): AbilityStatementStatus;
|
|
92
|
+
extractValues(sub: unknown, res?: unknown | undefined, env?: unknown | undefined): [
|
|
93
|
+
string | number | boolean | (string | number)[] | null | undefined,
|
|
94
|
+
string | number | boolean | (string | number)[] | null | undefined
|
|
95
|
+
];
|
|
96
|
+
getDotNotationValue(resource: unknown, desc: string): unknown;
|
|
97
|
+
}
|
|
98
|
+
export default AbilityStatement;
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,573 @@
|
|
|
1
|
+
/******/ (() => { // webpackBootstrap
|
|
2
|
+
/******/ "use strict";
|
|
3
|
+
/******/ var __webpack_modules__ = ({
|
|
4
|
+
|
|
5
|
+
/***/ 844:
|
|
6
|
+
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
10
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
13
|
+
exports.AbilityPolicy = void 0;
|
|
14
|
+
const AbilityRule_1 = __importDefault(__webpack_require__(476));
|
|
15
|
+
class AbilityPolicy {
|
|
16
|
+
/**
|
|
17
|
+
* List of rules
|
|
18
|
+
*/
|
|
19
|
+
rules = [];
|
|
20
|
+
/**
|
|
21
|
+
* Nested policies
|
|
22
|
+
*/
|
|
23
|
+
policies = [];
|
|
24
|
+
/**
|
|
25
|
+
* Rules compare method.\
|
|
26
|
+
* For the «and» method the rule will be permitted if all\
|
|
27
|
+
* rules will be returns «permit» status and for the «or» - if\
|
|
28
|
+
* one of the rules returns as «permit»
|
|
29
|
+
*/
|
|
30
|
+
rulesCompareMethod = 'and';
|
|
31
|
+
/**
|
|
32
|
+
* Policies compare method.\
|
|
33
|
+
* For the «and» method the policy will be permitted if all\
|
|
34
|
+
* policies will be returns «permit» status and for the «or» - if\
|
|
35
|
+
* one of the policies returns as «permit»
|
|
36
|
+
*/
|
|
37
|
+
policiesCompareMethod = 'and';
|
|
38
|
+
/**
|
|
39
|
+
* Policy name
|
|
40
|
+
*/
|
|
41
|
+
name;
|
|
42
|
+
/**
|
|
43
|
+
* Policy description
|
|
44
|
+
*/
|
|
45
|
+
description = null;
|
|
46
|
+
/**
|
|
47
|
+
* Policy ID
|
|
48
|
+
*/
|
|
49
|
+
id;
|
|
50
|
+
constructor(policyName, policyID, description) {
|
|
51
|
+
this.name = policyName || Symbol('name');
|
|
52
|
+
this.id = policyID || Symbol('id');
|
|
53
|
+
this.description = typeof description === 'string' ? description : null;
|
|
54
|
+
}
|
|
55
|
+
addRule(rule, compareMethod = 'and') {
|
|
56
|
+
this.rules.push(rule);
|
|
57
|
+
this.rulesCompareMethod = compareMethod;
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
addRules(rules, compareMethod = 'and') {
|
|
61
|
+
rules.forEach(rule => this.addRule(rule, compareMethod));
|
|
62
|
+
return this;
|
|
63
|
+
}
|
|
64
|
+
addPolicy(policy, compareMethod = 'and') {
|
|
65
|
+
this.policies.push(policy);
|
|
66
|
+
this.policiesCompareMethod = compareMethod;
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
addPolicies(policies, compareMethod = 'and') {
|
|
70
|
+
policies.forEach(policy => this.addPolicy(policy, compareMethod));
|
|
71
|
+
return this;
|
|
72
|
+
}
|
|
73
|
+
getName() {
|
|
74
|
+
return this.name;
|
|
75
|
+
}
|
|
76
|
+
getID() {
|
|
77
|
+
return this.id;
|
|
78
|
+
}
|
|
79
|
+
getPolicies() {
|
|
80
|
+
return this.policies;
|
|
81
|
+
}
|
|
82
|
+
getRules() {
|
|
83
|
+
return this.rules;
|
|
84
|
+
}
|
|
85
|
+
setDescription(description) {
|
|
86
|
+
this.description = description;
|
|
87
|
+
return this;
|
|
88
|
+
}
|
|
89
|
+
enforce(subject, resource, environment) {
|
|
90
|
+
const { permission, deniedPolicies } = this.check(subject, resource, environment);
|
|
91
|
+
if (permission === 'deny') {
|
|
92
|
+
throw new Error(`Permission denied. ${deniedPolicies[0].getName().toString()}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
isPermit(subject, resource, environment) {
|
|
96
|
+
const { permission } = this.check(subject, resource, environment);
|
|
97
|
+
return permission === 'permit';
|
|
98
|
+
}
|
|
99
|
+
isDeny(subject, resource, environment) {
|
|
100
|
+
const { permission } = this.check(subject, resource, environment);
|
|
101
|
+
return permission === 'deny';
|
|
102
|
+
}
|
|
103
|
+
check(subject, resource, environment) {
|
|
104
|
+
const deniedRules = [];
|
|
105
|
+
const deniedPolicies = [];
|
|
106
|
+
const ruleStatuses = [];
|
|
107
|
+
const policyStatuses = [];
|
|
108
|
+
AbilityPolicy.validatePolicy(this);
|
|
109
|
+
this.policies.forEach(policy => {
|
|
110
|
+
const policyResult = policy.check(subject, resource, environment);
|
|
111
|
+
policyStatuses.push(policyResult.permission);
|
|
112
|
+
if (policyResult.permission === 'deny') {
|
|
113
|
+
deniedPolicies.push(policy);
|
|
114
|
+
}
|
|
115
|
+
policyResult.deniedRules.forEach(rule => {
|
|
116
|
+
deniedRules.push(rule);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
this.rules.forEach(rule => {
|
|
120
|
+
const permission = rule.check(subject, resource, environment);
|
|
121
|
+
ruleStatuses.push(permission);
|
|
122
|
+
if (permission === 'deny') {
|
|
123
|
+
deniedRules.push(rule);
|
|
124
|
+
deniedPolicies.push(this);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
let res = 'deny';
|
|
128
|
+
if (policyStatuses.length) {
|
|
129
|
+
res = policyStatuses[this.policiesCompareMethod === 'and' ? 'every' : 'some'](status => status === 'permit')
|
|
130
|
+
? 'permit'
|
|
131
|
+
: 'deny';
|
|
132
|
+
}
|
|
133
|
+
if (ruleStatuses.length) {
|
|
134
|
+
res = ruleStatuses[this.rulesCompareMethod === 'and' ? 'every' : 'some'](status => status === 'permit')
|
|
135
|
+
? 'permit'
|
|
136
|
+
: 'deny';
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
permission: res,
|
|
140
|
+
deniedRules,
|
|
141
|
+
deniedPolicies,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Parse the config JSON format to Policy class instance
|
|
146
|
+
*/
|
|
147
|
+
static parse(configOrJson) {
|
|
148
|
+
const { id, name, description, rules, policies, rulesCompareMethod, policiesCompareMethod } = typeof configOrJson === 'string'
|
|
149
|
+
? JSON.parse(configOrJson)
|
|
150
|
+
: configOrJson;
|
|
151
|
+
// Create the empty policy
|
|
152
|
+
const policy = new AbilityPolicy(name, id, description);
|
|
153
|
+
if (description) {
|
|
154
|
+
policy.setDescription(description);
|
|
155
|
+
}
|
|
156
|
+
// Adding rules if exists
|
|
157
|
+
if (rules && rules.length > 0) {
|
|
158
|
+
const abilityRules = rules.map(ruleConfig => AbilityRule_1.default.parse(ruleConfig));
|
|
159
|
+
policy.addRules(abilityRules, rulesCompareMethod);
|
|
160
|
+
}
|
|
161
|
+
// Adding policies if exixts
|
|
162
|
+
if (policies && policies.length > 0) {
|
|
163
|
+
const nestedPolicies = policies.map(nestedConfig => AbilityPolicy.parse(nestedConfig));
|
|
164
|
+
policy.addPolicies(nestedPolicies, policiesCompareMethod);
|
|
165
|
+
}
|
|
166
|
+
return policy;
|
|
167
|
+
}
|
|
168
|
+
static validatePolicy(policy) {
|
|
169
|
+
if (policy.policies.length > 0 && policy.rules.length > 0) {
|
|
170
|
+
throw new Error("The policy can't have a policies and rules at the same time");
|
|
171
|
+
}
|
|
172
|
+
if (policy.policies.length === 0 && policy.rules.length === 0) {
|
|
173
|
+
throw new Error('The policy must have a nested policies or rules');
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
exports.AbilityPolicy = AbilityPolicy;
|
|
178
|
+
exports["default"] = AbilityPolicy;
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
/***/ }),
|
|
182
|
+
|
|
183
|
+
/***/ 476:
|
|
184
|
+
/***/ ((__unused_webpack_module, exports) => {
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
188
|
+
exports.AbilityRule = void 0;
|
|
189
|
+
class AbilityRule {
|
|
190
|
+
matches;
|
|
191
|
+
name;
|
|
192
|
+
effect;
|
|
193
|
+
/**
|
|
194
|
+
* Create the rule to compare
|
|
195
|
+
*
|
|
196
|
+
* @param ruleName {string} - The rule name
|
|
197
|
+
* @param effect {AbilityRuleStatus} - Return value
|
|
198
|
+
* @param matches {AbilityRuleMatches} - The matching rule he matching rule can be on of the format:
|
|
199
|
+
* \
|
|
200
|
+
* For example, be compared two's data\
|
|
201
|
+
* \
|
|
202
|
+
* _The subject_
|
|
203
|
+
* ```json
|
|
204
|
+
* {"userID": "1", "userDepartament": "NBC"}
|
|
205
|
+
* ```
|
|
206
|
+
* and _The resource_
|
|
207
|
+
* ```json
|
|
208
|
+
* {"departamentID": "154", "departamentName": "NBC"}
|
|
209
|
+
* ```
|
|
210
|
+
* \
|
|
211
|
+
* Now we can make the matching rule:
|
|
212
|
+
* ```json
|
|
213
|
+
* ["subject.userDepartament", "=", "resource.departamentName"]
|
|
214
|
+
* ```
|
|
215
|
+
*
|
|
216
|
+
* \
|
|
217
|
+
* **Example 2.**\
|
|
218
|
+
* In this case will be compared resource and string:
|
|
219
|
+
* \
|
|
220
|
+
* _The subject_
|
|
221
|
+
* ```json
|
|
222
|
+
* {"userID": "1", "userDepartament": "NBC"}
|
|
223
|
+
* ```
|
|
224
|
+
* and _The resource_ will be «undefined».\
|
|
225
|
+
* Now we can make the matching rule:
|
|
226
|
+
* ```json
|
|
227
|
+
* ["subject.userDepartament", "=", "NBC"]
|
|
228
|
+
* ```
|
|
229
|
+
* \
|
|
230
|
+
* **Example 3.**\
|
|
231
|
+
* In this case will be compared resource and array of string:\
|
|
232
|
+
* \
|
|
233
|
+
* _The subject_
|
|
234
|
+
* ```json
|
|
235
|
+
* {"userID": "1", "userDepartament": "NBC"}
|
|
236
|
+
* ```
|
|
237
|
+
* and _The resource_
|
|
238
|
+
* ```json
|
|
239
|
+
* ["FOX", "NBC", "AONE"]
|
|
240
|
+
* ```
|
|
241
|
+
* \
|
|
242
|
+
* Now we can make the matching rule:
|
|
243
|
+
* ```json
|
|
244
|
+
* ["subject.userDepartament", "=", "resource"]
|
|
245
|
+
* ```
|
|
246
|
+
* **Note: In this rule whe set the resource field as the «resource» string.\
|
|
247
|
+
* This means that we will compare the entire resource as a whole,\
|
|
248
|
+
* and not search for it by field name.**
|
|
249
|
+
* \
|
|
250
|
+
* **Example 4.**\
|
|
251
|
+
* In this case will be compared resource and array of string:\
|
|
252
|
+
* \
|
|
253
|
+
* _The subject_
|
|
254
|
+
* ```json
|
|
255
|
+
* {"user": {"account": {"roles": ["admin", "viewer"]}}}
|
|
256
|
+
* ```
|
|
257
|
+
* and _The resource_
|
|
258
|
+
* ```json
|
|
259
|
+
* undefined
|
|
260
|
+
* ```
|
|
261
|
+
* \
|
|
262
|
+
* Now we can make the matching rule:
|
|
263
|
+
* ```json
|
|
264
|
+
* ["subject.user.account.roles", "in", "admin"]
|
|
265
|
+
*/
|
|
266
|
+
constructor(matches, effect = 'permit', ruleName) {
|
|
267
|
+
this.name = ruleName || Symbol('name');
|
|
268
|
+
this.effect = effect;
|
|
269
|
+
this.matches = matches;
|
|
270
|
+
}
|
|
271
|
+
getName() {
|
|
272
|
+
return this.name;
|
|
273
|
+
}
|
|
274
|
+
getEffect() {
|
|
275
|
+
return this.effect;
|
|
276
|
+
}
|
|
277
|
+
isPermit(subject, resource, environment) {
|
|
278
|
+
return 'permit' === this.check(subject, resource, environment);
|
|
279
|
+
}
|
|
280
|
+
isDeny(subject, resource, environment) {
|
|
281
|
+
return 'deny' === this.check(subject, resource, environment);
|
|
282
|
+
}
|
|
283
|
+
check(subject, resource, environment) {
|
|
284
|
+
const [_subjectFieldName, condition, _resourceFieldName] = this.matches;
|
|
285
|
+
let is = false;
|
|
286
|
+
const [valueS, valueO] = this.extractValues(subject, resource, environment);
|
|
287
|
+
if (condition === '<') {
|
|
288
|
+
is = Number(valueS) < Number(valueO);
|
|
289
|
+
}
|
|
290
|
+
if (condition === '<=') {
|
|
291
|
+
is = Number(valueS) <= Number(valueO);
|
|
292
|
+
}
|
|
293
|
+
if (condition === '>') {
|
|
294
|
+
is = Number(valueS) > Number(valueO);
|
|
295
|
+
}
|
|
296
|
+
if (condition === '>=') {
|
|
297
|
+
is = Number(valueS) >= Number(valueO);
|
|
298
|
+
}
|
|
299
|
+
if (condition === '=') {
|
|
300
|
+
is = valueS === valueO;
|
|
301
|
+
}
|
|
302
|
+
if (condition === '<>') {
|
|
303
|
+
is = valueS !== valueO;
|
|
304
|
+
}
|
|
305
|
+
if (condition === 'in') {
|
|
306
|
+
// [<some>] and [<some>]
|
|
307
|
+
if (Array.isArray(valueS) && Array.isArray(valueO)) {
|
|
308
|
+
is = valueS.some(v => valueO.find(v1 => v1 === v));
|
|
309
|
+
}
|
|
310
|
+
// <some> and [<some>]
|
|
311
|
+
if ((typeof valueS === 'string' || typeof valueS === 'number') && Array.isArray(valueO)) {
|
|
312
|
+
is = valueO.includes(valueS);
|
|
313
|
+
}
|
|
314
|
+
// [<some>] and <some>
|
|
315
|
+
if ((typeof valueO === 'string' || typeof valueO === 'number') && Array.isArray(valueS)) {
|
|
316
|
+
is = valueS.includes(valueO);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return is ? this.effect : this.effect === 'permit' ? 'deny' : 'permit';
|
|
320
|
+
}
|
|
321
|
+
extractValues(sub, res, env) {
|
|
322
|
+
const [subjectFieldName, _condition, resourceFieldName] = this.matches;
|
|
323
|
+
const REGEXP = /^(subject|resource|environment)\./;
|
|
324
|
+
// The subject field must be named at «subject.<field-name>»
|
|
325
|
+
if (!subjectFieldName.match(/^(subject|environment)\./)) {
|
|
326
|
+
throw new Error(`Matches error. The subject field must be named at «subject.<field-name>», but got ${subjectFieldName}`);
|
|
327
|
+
}
|
|
328
|
+
const sFieldName = subjectFieldName.replace(/^(subject|environment)\./, '');
|
|
329
|
+
const subject = typeof sub === 'undefined' || sub === null ? {} : sub;
|
|
330
|
+
const resource = typeof res === 'undefined' || res === null ? {} : res;
|
|
331
|
+
const sValue = subject
|
|
332
|
+
? this.getDotNotationValue(subjectFieldName.match(/^subject\./)
|
|
333
|
+
? subject
|
|
334
|
+
: subjectFieldName.match(/^environment\./)
|
|
335
|
+
? env
|
|
336
|
+
: {}, sFieldName)
|
|
337
|
+
: subject;
|
|
338
|
+
// The resource field name can be «resource».
|
|
339
|
+
// In this case the resource be compare as is
|
|
340
|
+
if (resourceFieldName === 'resource') {
|
|
341
|
+
return [sValue, resource];
|
|
342
|
+
}
|
|
343
|
+
// Object field name - is a «resource.<field-name>»
|
|
344
|
+
if (resource && String(resourceFieldName).match(REGEXP)) {
|
|
345
|
+
const oFieldName = String(resourceFieldName).replace(REGEXP, '');
|
|
346
|
+
return [sValue, this.getDotNotationValue(resource, oFieldName)];
|
|
347
|
+
}
|
|
348
|
+
// The resource field abne can be «<some-value>» only
|
|
349
|
+
if (String(resourceFieldName).match(REGEXP) === null) {
|
|
350
|
+
return [sValue, resourceFieldName];
|
|
351
|
+
}
|
|
352
|
+
return [NaN, NaN];
|
|
353
|
+
}
|
|
354
|
+
getDotNotationValue(resource, desc) {
|
|
355
|
+
const arr = desc.split('.');
|
|
356
|
+
while (arr.length && resource) {
|
|
357
|
+
const comp = arr.shift() || '';
|
|
358
|
+
const match = new RegExp('(.+)\\[([0-9]*)\\]').exec(comp);
|
|
359
|
+
if (match !== null && match.length == 3) {
|
|
360
|
+
const arrayData = {
|
|
361
|
+
arrName: match[1],
|
|
362
|
+
arrIndex: match[2],
|
|
363
|
+
};
|
|
364
|
+
if (resource[arrayData.arrName] !== undefined) {
|
|
365
|
+
resource = resource[arrayData.arrName][arrayData.arrIndex];
|
|
366
|
+
}
|
|
367
|
+
else {
|
|
368
|
+
resource = undefined;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
else {
|
|
372
|
+
resource = resource[comp];
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
return resource;
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Parsing the rule config object or JSON string\
|
|
379
|
+
* of config and returns the AbilityRule class instance
|
|
380
|
+
*/
|
|
381
|
+
static parse(configOrJson) {
|
|
382
|
+
const { name, effect, matches } = typeof configOrJson === 'string'
|
|
383
|
+
? JSON.parse(configOrJson)
|
|
384
|
+
: configOrJson;
|
|
385
|
+
return new AbilityRule(matches, effect, name);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
exports.AbilityRule = AbilityRule;
|
|
389
|
+
exports["default"] = AbilityRule;
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
/***/ }),
|
|
393
|
+
|
|
394
|
+
/***/ 31:
|
|
395
|
+
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
399
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
400
|
+
};
|
|
401
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
402
|
+
const AbilityRule_1 = __importDefault(__webpack_require__(476));
|
|
403
|
+
const AbilityPolicy_1 = __importDefault(__webpack_require__(844));
|
|
404
|
+
class AbilityService {
|
|
405
|
+
/**
|
|
406
|
+
* Create the rule to compare
|
|
407
|
+
*
|
|
408
|
+
* @param ruleName {string} - The rule name
|
|
409
|
+
* @param effect {AbilityRuleStatus} - Return value
|
|
410
|
+
* @param matches {AbilityRuleMatches} - The matching rule he matching rule can be on of the format:
|
|
411
|
+
* \
|
|
412
|
+
* For example, be compared two's data\
|
|
413
|
+
* \
|
|
414
|
+
* _The subject_
|
|
415
|
+
* ```json
|
|
416
|
+
* {"userID": "1", "userDepartament": "NBC"}
|
|
417
|
+
* ```
|
|
418
|
+
* and _The resource_
|
|
419
|
+
* ```json
|
|
420
|
+
* {"departamentID": "154", "departamentName": "NBC"}
|
|
421
|
+
* ```
|
|
422
|
+
* \
|
|
423
|
+
* Now we can make the matching rule:
|
|
424
|
+
* ```json
|
|
425
|
+
* ["subject.userDepartament", "=", "resource.departamentName"]
|
|
426
|
+
* ```
|
|
427
|
+
*
|
|
428
|
+
* \
|
|
429
|
+
* **Example 2.**\
|
|
430
|
+
* In this case will be compared resource and string:
|
|
431
|
+
* \
|
|
432
|
+
* _The subject_
|
|
433
|
+
* ```json
|
|
434
|
+
* {"userID": "1", "userDepartament": "NBC"}
|
|
435
|
+
* ```
|
|
436
|
+
* and _The resource_ will be «undefined».\
|
|
437
|
+
* Now we can make the matching rule:
|
|
438
|
+
* ```json
|
|
439
|
+
* ["subject.userDepartament", "=", "NBC"]
|
|
440
|
+
* ```
|
|
441
|
+
* \
|
|
442
|
+
* **Example 3.**\
|
|
443
|
+
* In this case will be compared resource and array of string:\
|
|
444
|
+
* \
|
|
445
|
+
* _The subject_
|
|
446
|
+
* ```json
|
|
447
|
+
* {"userID": "1", "userDepartament": "NBC"}
|
|
448
|
+
* ```
|
|
449
|
+
* and _The resource_
|
|
450
|
+
* ```json
|
|
451
|
+
* ["FOX", "NBC", "AONE"]
|
|
452
|
+
* ```
|
|
453
|
+
* \
|
|
454
|
+
* Now we can make the matching rule:
|
|
455
|
+
* ```json
|
|
456
|
+
* ["subject.userDepartament", "=", "resource"]
|
|
457
|
+
* ```
|
|
458
|
+
* **Note: In this rule whe set the resource field as the «resource» string.\
|
|
459
|
+
* This means that we will compare the entire resource as a whole,\
|
|
460
|
+
* and not search for it by field name.**
|
|
461
|
+
*/
|
|
462
|
+
createRule(...args) {
|
|
463
|
+
return new AbilityRule_1.default(...args);
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* Create the Policy class instance
|
|
467
|
+
*/
|
|
468
|
+
createPolicy(...args) {
|
|
469
|
+
return new AbilityPolicy_1.default(...args);
|
|
470
|
+
}
|
|
471
|
+
checkPolicies(policiesResult, compareMethod) {
|
|
472
|
+
const deniedRules = [];
|
|
473
|
+
const deniedPolicies = [];
|
|
474
|
+
const statuses = [];
|
|
475
|
+
policiesResult.forEach(policyResult => {
|
|
476
|
+
statuses.push(policyResult.permission);
|
|
477
|
+
if (policyResult.permission === 'deny') {
|
|
478
|
+
policyResult.deniedRules.forEach(rule => {
|
|
479
|
+
deniedRules.push(rule);
|
|
480
|
+
});
|
|
481
|
+
policyResult.deniedRules.forEach(st => {
|
|
482
|
+
deniedRules.push(st);
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
});
|
|
486
|
+
const permission = statuses[compareMethod === 'and' ? 'every' : 'some'](status => status === 'permit')
|
|
487
|
+
? 'permit'
|
|
488
|
+
: 'deny';
|
|
489
|
+
return {
|
|
490
|
+
permission,
|
|
491
|
+
deniedRules,
|
|
492
|
+
deniedPolicies,
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
enforcePolicies(policiesResult, compareMethod) {
|
|
496
|
+
const { permission, deniedRules } = this.checkPolicies(policiesResult, compareMethod);
|
|
497
|
+
if (permission === 'deny') {
|
|
498
|
+
throw new Error(`Permission denied. ${deniedRules[0].getName().toString()}`);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
exports["default"] = AbilityService;
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
/***/ }),
|
|
506
|
+
|
|
507
|
+
/***/ 156:
|
|
508
|
+
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
512
|
+
if (k2 === undefined) k2 = k;
|
|
513
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
514
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
515
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
516
|
+
}
|
|
517
|
+
Object.defineProperty(o, k2, desc);
|
|
518
|
+
}) : (function(o, m, k, k2) {
|
|
519
|
+
if (k2 === undefined) k2 = k;
|
|
520
|
+
o[k2] = m[k];
|
|
521
|
+
}));
|
|
522
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
523
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
524
|
+
};
|
|
525
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
526
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
527
|
+
};
|
|
528
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
529
|
+
const AbilityService_1 = __importDefault(__webpack_require__(31));
|
|
530
|
+
__exportStar(__webpack_require__(844), exports);
|
|
531
|
+
__exportStar(__webpack_require__(31), exports);
|
|
532
|
+
__exportStar(__webpack_require__(476), exports);
|
|
533
|
+
exports["default"] = AbilityService_1.default;
|
|
534
|
+
|
|
535
|
+
|
|
536
|
+
/***/ })
|
|
537
|
+
|
|
538
|
+
/******/ });
|
|
539
|
+
/************************************************************************/
|
|
540
|
+
/******/ // The module cache
|
|
541
|
+
/******/ var __webpack_module_cache__ = {};
|
|
542
|
+
/******/
|
|
543
|
+
/******/ // The require function
|
|
544
|
+
/******/ function __webpack_require__(moduleId) {
|
|
545
|
+
/******/ // Check if module is in cache
|
|
546
|
+
/******/ var cachedModule = __webpack_module_cache__[moduleId];
|
|
547
|
+
/******/ if (cachedModule !== undefined) {
|
|
548
|
+
/******/ return cachedModule.exports;
|
|
549
|
+
/******/ }
|
|
550
|
+
/******/ // Create a new module (and put it into the cache)
|
|
551
|
+
/******/ var module = __webpack_module_cache__[moduleId] = {
|
|
552
|
+
/******/ // no module.id needed
|
|
553
|
+
/******/ // no module.loaded needed
|
|
554
|
+
/******/ exports: {}
|
|
555
|
+
/******/ };
|
|
556
|
+
/******/
|
|
557
|
+
/******/ // Execute the module function
|
|
558
|
+
/******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
|
559
|
+
/******/
|
|
560
|
+
/******/ // Return the exports of the module
|
|
561
|
+
/******/ return module.exports;
|
|
562
|
+
/******/ }
|
|
563
|
+
/******/
|
|
564
|
+
/************************************************************************/
|
|
565
|
+
/******/
|
|
566
|
+
/******/ // startup
|
|
567
|
+
/******/ // Load entry module and return exports
|
|
568
|
+
/******/ // This entry module is referenced by other modules so it can't be inlined
|
|
569
|
+
/******/ var __webpack_exports__ = __webpack_require__(156);
|
|
570
|
+
/******/ module.exports = __webpack_exports__;
|
|
571
|
+
/******/
|
|
572
|
+
/******/ })()
|
|
573
|
+
;
|