@via-profit/ability 1.1.0 → 2.0.0-rc.3
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 +155 -310
- package/assets/ability-01.drawio.png +0 -0
- package/build/playground.js +910 -0
- package/build/playground.js.map +1 -0
- package/dist/AbilityCode.d.ts +7 -0
- package/dist/AbilityCompare.d.ts +6 -0
- package/dist/AbilityCondition.d.ts +12 -0
- package/dist/AbilityError.d.ts +9 -0
- package/dist/AbilityMatch.d.ts +7 -0
- package/dist/AbilityParser.d.ts +33 -0
- package/dist/AbilityPolicy.d.ts +44 -53
- package/dist/AbilityPolicyEffect.d.ts +6 -0
- package/dist/AbilityPolicyResult.d.ts +6 -0
- package/dist/AbilityResolver.d.ts +30 -0
- package/dist/AbilityRule.d.ts +29 -97
- package/dist/AbilityRuleSet.d.ts +44 -0
- package/dist/index.d.ts +9 -3
- package/dist/index.js +624 -380
- package/dist/playground.d.ts +26 -0
- package/package.json +4 -2
- package/dist/AbilityService.d.ts +0 -74
package/dist/index.js
CHANGED
|
@@ -2,6 +2,254 @@
|
|
|
2
2
|
/******/ "use strict";
|
|
3
3
|
/******/ var __webpack_modules__ = ({
|
|
4
4
|
|
|
5
|
+
/***/ 19:
|
|
6
|
+
/***/ ((__unused_webpack_module, exports) => {
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
10
|
+
exports.AbilityCode = void 0;
|
|
11
|
+
class AbilityCode {
|
|
12
|
+
code;
|
|
13
|
+
constructor(code) {
|
|
14
|
+
this.code = code;
|
|
15
|
+
}
|
|
16
|
+
isEqual(compareWith) {
|
|
17
|
+
return compareWith !== null && this.code === compareWith.code;
|
|
18
|
+
}
|
|
19
|
+
isNotEqual(compareWith) {
|
|
20
|
+
return !this.isEqual(compareWith);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
exports.AbilityCode = AbilityCode;
|
|
24
|
+
exports["default"] = AbilityCode;
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
/***/ }),
|
|
28
|
+
|
|
29
|
+
/***/ 923:
|
|
30
|
+
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
34
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
35
|
+
};
|
|
36
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
37
|
+
exports.AbilityCompare = void 0;
|
|
38
|
+
const AbilityCode_1 = __importDefault(__webpack_require__(19));
|
|
39
|
+
class AbilityCompare extends AbilityCode_1.default {
|
|
40
|
+
static OR = new AbilityCompare(0);
|
|
41
|
+
static AND = new AbilityCompare(1);
|
|
42
|
+
}
|
|
43
|
+
exports.AbilityCompare = AbilityCompare;
|
|
44
|
+
exports["default"] = AbilityCompare;
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
/***/ }),
|
|
48
|
+
|
|
49
|
+
/***/ 261:
|
|
50
|
+
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
54
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
55
|
+
};
|
|
56
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
57
|
+
exports.AbilityCondition = void 0;
|
|
58
|
+
const AbilityCode_1 = __importDefault(__webpack_require__(19));
|
|
59
|
+
class AbilityCondition extends AbilityCode_1.default {
|
|
60
|
+
static EQUAL = new AbilityCondition('=');
|
|
61
|
+
static NOT_EQUAL = new AbilityCondition('<>');
|
|
62
|
+
static MORE_THAN = new AbilityCondition('>');
|
|
63
|
+
static LESS_THAN = new AbilityCondition('<');
|
|
64
|
+
static LESS_OR_EQUAL = new AbilityCondition('<=');
|
|
65
|
+
static MORE_OR_EQUAL = new AbilityCondition('>=');
|
|
66
|
+
static IN = new AbilityCondition('in');
|
|
67
|
+
static NOT_IN = new AbilityCondition('not in');
|
|
68
|
+
}
|
|
69
|
+
exports.AbilityCondition = AbilityCondition;
|
|
70
|
+
exports["default"] = AbilityCondition;
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
/***/ }),
|
|
74
|
+
|
|
75
|
+
/***/ 122:
|
|
76
|
+
/***/ ((__unused_webpack_module, exports) => {
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
80
|
+
exports.PermissionError = exports.AbilityParserError = exports.AbilityError = void 0;
|
|
81
|
+
class AbilityError extends Error {
|
|
82
|
+
constructor(message) {
|
|
83
|
+
super(message);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
exports.AbilityError = AbilityError;
|
|
87
|
+
class AbilityParserError extends Error {
|
|
88
|
+
constructor(message) {
|
|
89
|
+
super(message);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
exports.AbilityParserError = AbilityParserError;
|
|
93
|
+
class PermissionError extends Error {
|
|
94
|
+
constructor(message) {
|
|
95
|
+
super(message);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
exports.PermissionError = PermissionError;
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
/***/ }),
|
|
102
|
+
|
|
103
|
+
/***/ 909:
|
|
104
|
+
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
108
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
109
|
+
};
|
|
110
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
111
|
+
exports.AbilityMatch = void 0;
|
|
112
|
+
const AbilityCode_1 = __importDefault(__webpack_require__(19));
|
|
113
|
+
class AbilityMatch extends AbilityCode_1.default {
|
|
114
|
+
static PENDING = new AbilityMatch(2);
|
|
115
|
+
static MATCH = new AbilityMatch(1);
|
|
116
|
+
static MISMATCH = new AbilityMatch(0);
|
|
117
|
+
}
|
|
118
|
+
exports.AbilityMatch = AbilityMatch;
|
|
119
|
+
exports["default"] = AbilityMatch;
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
/***/ }),
|
|
123
|
+
|
|
124
|
+
/***/ 189:
|
|
125
|
+
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
129
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
130
|
+
};
|
|
131
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
132
|
+
exports.AbilityParser = void 0;
|
|
133
|
+
const AbilityError_1 = __webpack_require__(122);
|
|
134
|
+
const AbilityCondition_1 = __importDefault(__webpack_require__(261));
|
|
135
|
+
class AbilityParser {
|
|
136
|
+
/**
|
|
137
|
+
* Validates the configuration object based on the provided field validation configurations.
|
|
138
|
+
* @param config - The configuration object to validate.
|
|
139
|
+
* @param fields - An array of field validation configurations.
|
|
140
|
+
* @throws {AbilityParserError} If a required field is missing or if a field has an incorrect type.
|
|
141
|
+
*/
|
|
142
|
+
static validateConfig(config, fields) {
|
|
143
|
+
fields.forEach(([field, type, isRequired]) => {
|
|
144
|
+
const value = config[field];
|
|
145
|
+
if (isRequired) {
|
|
146
|
+
if (typeof value === 'undefined') {
|
|
147
|
+
throw new AbilityError_1.AbilityParserError(`Missing required field [${field}]`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
switch (type) {
|
|
151
|
+
case 'array':
|
|
152
|
+
if (typeof value !== 'object' || !Array.isArray(value)) {
|
|
153
|
+
throw new AbilityError_1.AbilityParserError(`Field [${field}] must be an type of [${type}], bit got [${typeof value}]`);
|
|
154
|
+
}
|
|
155
|
+
break;
|
|
156
|
+
default:
|
|
157
|
+
if (typeof value !== type && typeof value !== 'undefined') {
|
|
158
|
+
throw new AbilityError_1.AbilityParserError(`Field [${field}] must be a type of [${type}], bit got [${typeof value}]`);
|
|
159
|
+
}
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Prepares and validates the configuration object or JSON string.
|
|
166
|
+
* @param configOrJson - The configuration object or JSON string to validate.
|
|
167
|
+
* @param fields - An array of field validation configurations.
|
|
168
|
+
* @returns The validated configuration object.
|
|
169
|
+
*/
|
|
170
|
+
static prepareAndValidateConfig(configOrJson, fields) {
|
|
171
|
+
const config = typeof configOrJson === 'string'
|
|
172
|
+
? (JSON.parse(configOrJson))
|
|
173
|
+
: configOrJson;
|
|
174
|
+
AbilityParser.validateConfig(config, fields);
|
|
175
|
+
return config;
|
|
176
|
+
}
|
|
177
|
+
/*
|
|
178
|
+
*
|
|
179
|
+
* readonly ['order.update']: {
|
|
180
|
+
* readonly user: {
|
|
181
|
+
* readonly roles: readonly string[];
|
|
182
|
+
* readonly department: string;
|
|
183
|
+
* };
|
|
184
|
+
* readonly order: {
|
|
185
|
+
* readonly estimatedArrivalAt: number;
|
|
186
|
+
* readonly status: string;
|
|
187
|
+
* }
|
|
188
|
+
* }
|
|
189
|
+
*
|
|
190
|
+
* */
|
|
191
|
+
/**
|
|
192
|
+
* Sets a value in a nested object structure based on a dot/bracket notation path.
|
|
193
|
+
* @param object - The target object to modify.
|
|
194
|
+
* @param path - The path to the property in dot/bracket notation.
|
|
195
|
+
* @param value - The value to set at the specified path.
|
|
196
|
+
*/
|
|
197
|
+
static setValueDotValue(object, path, value) {
|
|
198
|
+
const way = path.replace(/\[/g, '.').replace(/\]/g, '').split('.');
|
|
199
|
+
const last = way.pop();
|
|
200
|
+
if (!last) {
|
|
201
|
+
throw new AbilityError_1.AbilityParserError(`Invalid path provided on a [${path}]`);
|
|
202
|
+
}
|
|
203
|
+
way.reduce((o, k, i, kk) => {
|
|
204
|
+
if (!o[k]) {
|
|
205
|
+
o[k] = isFinite(Number(kk[i + 1])) ? [] : {};
|
|
206
|
+
}
|
|
207
|
+
return o[k];
|
|
208
|
+
}, object)[last] = value;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Generates TypeScript type definitions based on the provided policies.
|
|
212
|
+
* @param policies - An array of AbilityPolicy instances.
|
|
213
|
+
* @param outPath - The output path for the generated type definitions.
|
|
214
|
+
* @returns A record containing the generated type definitions.
|
|
215
|
+
*/
|
|
216
|
+
static generateTypeDefs(policies, outPath) {
|
|
217
|
+
const record = {};
|
|
218
|
+
policies.forEach(policy => {
|
|
219
|
+
policy.ruleSet.forEach(ruleSet => {
|
|
220
|
+
ruleSet.rules.forEach(rule => {
|
|
221
|
+
const [leftFieldPath, condition, rightFiledPath] = rule.matches;
|
|
222
|
+
let value = 'any';
|
|
223
|
+
switch (true) {
|
|
224
|
+
case condition.isEqual(AbilityCondition_1.default.NOT_EQUAL):
|
|
225
|
+
case condition.isEqual(AbilityCondition_1.default.EQUAL):
|
|
226
|
+
value = typeof rightFiledPath;
|
|
227
|
+
break;
|
|
228
|
+
case condition.isEqual(AbilityCondition_1.default.IN):
|
|
229
|
+
case condition.isEqual(AbilityCondition_1.default.NOT_IN):
|
|
230
|
+
value = `${typeof rightFiledPath}[]`;
|
|
231
|
+
break;
|
|
232
|
+
case condition.isEqual(AbilityCondition_1.default.MORE_OR_EQUAL):
|
|
233
|
+
case condition.isEqual(AbilityCondition_1.default.MORE_THAN):
|
|
234
|
+
case condition.isEqual(AbilityCondition_1.default.LESS_OR_EQUAL):
|
|
235
|
+
case condition.isEqual(AbilityCondition_1.default.LESS_THAN):
|
|
236
|
+
value = 'number';
|
|
237
|
+
break;
|
|
238
|
+
}
|
|
239
|
+
AbilityParser.setValueDotValue(record, leftFieldPath, value);
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
console.log(JSON.stringify(record));
|
|
244
|
+
return record;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
exports.AbilityParser = AbilityParser;
|
|
248
|
+
exports["default"] = AbilityParser;
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
/***/ }),
|
|
252
|
+
|
|
5
253
|
/***/ 844:
|
|
6
254
|
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
|
|
7
255
|
|
|
@@ -11,184 +259,129 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
11
259
|
};
|
|
12
260
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
13
261
|
exports.AbilityPolicy = void 0;
|
|
14
|
-
const
|
|
262
|
+
const AbilityRuleSet_1 = __importDefault(__webpack_require__(402));
|
|
263
|
+
const AbilityMatch_1 = __importDefault(__webpack_require__(909));
|
|
264
|
+
const AbilityCompare_1 = __importDefault(__webpack_require__(923));
|
|
265
|
+
const AbilityPolicyEffect_1 = __importDefault(__webpack_require__(277));
|
|
266
|
+
const AbilityParser_1 = __importDefault(__webpack_require__(189));
|
|
15
267
|
class AbilityPolicy {
|
|
268
|
+
matchState = AbilityMatch_1.default.PENDING;
|
|
16
269
|
/**
|
|
17
270
|
* List of rules
|
|
18
271
|
*/
|
|
19
|
-
|
|
272
|
+
ruleSet = [];
|
|
20
273
|
/**
|
|
21
|
-
*
|
|
274
|
+
* Policy effect
|
|
22
275
|
*/
|
|
23
|
-
|
|
276
|
+
effect;
|
|
24
277
|
/**
|
|
25
278
|
* Rules compare method.\
|
|
26
279
|
* For the «and» method the rule will be permitted if all\
|
|
27
280
|
* rules will be returns «permit» status and for the «or» - if\
|
|
28
281
|
* one of the rules returns as «permit»
|
|
29
282
|
*/
|
|
30
|
-
|
|
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';
|
|
283
|
+
compareMethod = AbilityCompare_1.default.AND;
|
|
38
284
|
/**
|
|
39
285
|
* Policy name
|
|
40
286
|
*/
|
|
41
287
|
name;
|
|
42
|
-
/**
|
|
43
|
-
* Policy description
|
|
44
|
-
*/
|
|
45
|
-
description = null;
|
|
46
288
|
/**
|
|
47
289
|
* Policy ID
|
|
48
290
|
*/
|
|
49
291
|
id;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
this.
|
|
57
|
-
this.
|
|
58
|
-
|
|
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;
|
|
292
|
+
/**
|
|
293
|
+
* Soon
|
|
294
|
+
*/
|
|
295
|
+
action;
|
|
296
|
+
constructor(params) {
|
|
297
|
+
const { name, id, action, effect } = params;
|
|
298
|
+
this.name = name;
|
|
299
|
+
this.id = id;
|
|
300
|
+
this.action = action;
|
|
301
|
+
this.effect = effect;
|
|
68
302
|
}
|
|
69
|
-
|
|
70
|
-
|
|
303
|
+
/**
|
|
304
|
+
* Add rule set to the policy
|
|
305
|
+
* @param ruleSet - The rule set to add
|
|
306
|
+
*/
|
|
307
|
+
addRuleSet(ruleSet) {
|
|
308
|
+
this.ruleSet.push(ruleSet);
|
|
71
309
|
return this;
|
|
72
310
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
getRules() {
|
|
83
|
-
return this.rules;
|
|
84
|
-
}
|
|
85
|
-
setDescription(description) {
|
|
86
|
-
this.description = description;
|
|
311
|
+
/**
|
|
312
|
+
* Add rule to the policy
|
|
313
|
+
* @param rule - The rule to add
|
|
314
|
+
*/
|
|
315
|
+
addRule(rule) {
|
|
316
|
+
this.addRuleSet(new AbilityRuleSet_1.default({
|
|
317
|
+
id: rule.id,
|
|
318
|
+
name: rule.name,
|
|
319
|
+
}).addRule(rule, AbilityCompare_1.default.AND));
|
|
87
320
|
return this;
|
|
88
321
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
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);
|
|
322
|
+
/**
|
|
323
|
+
* Check if the policy is matched
|
|
324
|
+
* @param resource - The resource to check
|
|
325
|
+
*/
|
|
326
|
+
check(resource) {
|
|
327
|
+
this.matchState = AbilityMatch_1.default.MISMATCH;
|
|
328
|
+
/**
|
|
329
|
+
* If policy contain a rules
|
|
330
|
+
*/
|
|
331
|
+
if (this.ruleSet.length) {
|
|
332
|
+
const ruleCheckStates = [];
|
|
333
|
+
this.ruleSet.forEach(rule => {
|
|
334
|
+
const ruleCheckState = rule.check(resource);
|
|
335
|
+
ruleCheckStates.push(ruleCheckState);
|
|
117
336
|
});
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
337
|
+
if (AbilityCompare_1.default.AND.isEqual(this.compareMethod)) {
|
|
338
|
+
if (ruleCheckStates.every(ruleState => AbilityMatch_1.default.MATCH.isEqual(ruleState))) {
|
|
339
|
+
this.matchState = AbilityMatch_1.default.MATCH;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
if (AbilityCompare_1.default.OR.isEqual(this.compareMethod)) {
|
|
343
|
+
if (ruleCheckStates.some(ruleState => AbilityMatch_1.default.MATCH.isEqual(ruleState))) {
|
|
344
|
+
this.matchState = AbilityMatch_1.default.MATCH;
|
|
345
|
+
}
|
|
125
346
|
}
|
|
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
347
|
}
|
|
138
|
-
return
|
|
139
|
-
permission: res,
|
|
140
|
-
deniedRules,
|
|
141
|
-
deniedPolicies,
|
|
142
|
-
};
|
|
348
|
+
return this.matchState;
|
|
143
349
|
}
|
|
144
350
|
/**
|
|
145
351
|
* Parse the config JSON format to Policy class instance
|
|
146
352
|
*/
|
|
147
353
|
static parse(configOrJson) {
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
354
|
+
const config = AbilityParser_1.default.prepareAndValidateConfig(configOrJson, [
|
|
355
|
+
['id', 'string', true],
|
|
356
|
+
['name', 'string', true],
|
|
357
|
+
['action', 'string', true],
|
|
358
|
+
['effect', 'number', true],
|
|
359
|
+
['compareMethod', 'number', true],
|
|
360
|
+
['ruleSet', 'array', true],
|
|
361
|
+
]);
|
|
362
|
+
const { id, name, ruleSet, compareMethod, action, effect } = config;
|
|
151
363
|
// Create the empty policy
|
|
152
|
-
const policy = new AbilityPolicy(
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
policy.
|
|
161
|
-
}
|
|
162
|
-
// Adding rules if exists
|
|
163
|
-
if (rules && rules.length > 0) {
|
|
164
|
-
const abilityRules = rules.map(ruleConfig => AbilityRule_1.default.parse(ruleConfig));
|
|
165
|
-
policy.addRules(abilityRules, rulesCompareMethod);
|
|
166
|
-
}
|
|
167
|
-
// Adding policies if exixts
|
|
168
|
-
if (policies && policies.length > 0) {
|
|
169
|
-
const nestedPolicies = policies.map(nestedConfig => AbilityPolicy.parse(nestedConfig));
|
|
170
|
-
policy.addPolicies(nestedPolicies, policiesCompareMethod);
|
|
171
|
-
}
|
|
364
|
+
const policy = new AbilityPolicy({
|
|
365
|
+
name,
|
|
366
|
+
id,
|
|
367
|
+
action,
|
|
368
|
+
effect: new AbilityPolicyEffect_1.default(effect),
|
|
369
|
+
});
|
|
370
|
+
policy.compareMethod = new AbilityCompare_1.default(compareMethod);
|
|
371
|
+
ruleSet.forEach(ruleSetConfig => {
|
|
372
|
+
policy.addRuleSet(AbilityRuleSet_1.default.parse(ruleSetConfig));
|
|
373
|
+
});
|
|
172
374
|
return policy;
|
|
173
375
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
id:
|
|
177
|
-
name:
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
376
|
+
export() {
|
|
377
|
+
return {
|
|
378
|
+
id: this.id.toString(),
|
|
379
|
+
name: this.name.toString(),
|
|
380
|
+
compareMethod: this.compareMethod.code,
|
|
381
|
+
ruleSet: this.ruleSet.map(rule => rule.export()),
|
|
382
|
+
action: this.action,
|
|
383
|
+
effect: this.effect.code,
|
|
182
384
|
};
|
|
183
|
-
return config;
|
|
184
|
-
}
|
|
185
|
-
static validatePolicy(policy) {
|
|
186
|
-
if (policy.policies.length > 0 && policy.rules.length > 0) {
|
|
187
|
-
throw new Error("The policy can't have a policies and rules at the same time");
|
|
188
|
-
}
|
|
189
|
-
if (policy.policies.length === 0 && policy.rules.length === 0) {
|
|
190
|
-
throw new Error('The policy must have a nested policies or rules');
|
|
191
|
-
}
|
|
192
385
|
}
|
|
193
386
|
}
|
|
194
387
|
exports.AbilityPolicy = AbilityPolicy;
|
|
@@ -197,129 +390,168 @@ exports["default"] = AbilityPolicy;
|
|
|
197
390
|
|
|
198
391
|
/***/ }),
|
|
199
392
|
|
|
200
|
-
/***/
|
|
201
|
-
/***/ ((__unused_webpack_module, exports)
|
|
393
|
+
/***/ 277:
|
|
394
|
+
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
|
|
202
395
|
|
|
203
396
|
|
|
397
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
398
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
399
|
+
};
|
|
204
400
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
205
|
-
exports.
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
401
|
+
exports.AbilityPolicyEffect = void 0;
|
|
402
|
+
const AbilityCode_1 = __importDefault(__webpack_require__(19));
|
|
403
|
+
class AbilityPolicyEffect extends AbilityCode_1.default {
|
|
404
|
+
static DENY = new AbilityPolicyEffect(0);
|
|
405
|
+
static PERMIT = new AbilityPolicyEffect(1);
|
|
406
|
+
}
|
|
407
|
+
exports.AbilityPolicyEffect = AbilityPolicyEffect;
|
|
408
|
+
exports["default"] = AbilityPolicyEffect;
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
/***/ }),
|
|
412
|
+
|
|
413
|
+
/***/ 668:
|
|
414
|
+
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
418
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
419
|
+
};
|
|
420
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
421
|
+
exports.AbilityResolver = void 0;
|
|
422
|
+
const AbilityPolicyEffect_1 = __importDefault(__webpack_require__(277));
|
|
423
|
+
const AbilityMatch_1 = __importDefault(__webpack_require__(909));
|
|
424
|
+
const AbilityError_1 = __webpack_require__(122);
|
|
425
|
+
class AbilityResolver {
|
|
426
|
+
policies;
|
|
427
|
+
constructor(policies) {
|
|
428
|
+
this.policies = policies;
|
|
429
|
+
}
|
|
210
430
|
/**
|
|
211
|
-
*
|
|
212
|
-
*
|
|
213
|
-
* @param ruleName {string} - The rule name
|
|
214
|
-
* @param effect {AbilityRuleStatus} - Return value
|
|
215
|
-
* @param matches {AbilityRuleMatches} - The matching rule he matching rule can be on of the format:
|
|
216
|
-
* \
|
|
217
|
-
* For example, be compared two's data\
|
|
218
|
-
* \
|
|
219
|
-
* _The subject_
|
|
220
|
-
* ```json
|
|
221
|
-
* {"userID": "1", "userDepartament": "NBC"}
|
|
222
|
-
* ```
|
|
223
|
-
* and _The resource_
|
|
224
|
-
* ```json
|
|
225
|
-
* {"departamentID": "154", "departamentName": "NBC"}
|
|
226
|
-
* ```
|
|
227
|
-
* \
|
|
228
|
-
* Now we can make the matching rule:
|
|
229
|
-
* ```json
|
|
230
|
-
* ["subject.userDepartament", "=", "resource.departamentName"]
|
|
231
|
-
* ```
|
|
431
|
+
* Resolve policy for the resource and action
|
|
232
432
|
*
|
|
233
|
-
|
|
234
|
-
*
|
|
235
|
-
* In this case will be compared resource and string:
|
|
236
|
-
* \
|
|
237
|
-
* _The subject_
|
|
238
|
-
* ```json
|
|
239
|
-
* {"userID": "1", "userDepartament": "NBC"}
|
|
240
|
-
* ```
|
|
241
|
-
* and _The resource_ will be «undefined».\
|
|
242
|
-
* Now we can make the matching rule:
|
|
243
|
-
* ```json
|
|
244
|
-
* ["subject.userDepartament", "=", "NBC"]
|
|
245
|
-
* ```
|
|
246
|
-
* \
|
|
247
|
-
* **Example 3.**\
|
|
248
|
-
* In this case will be compared resource and array of string:\
|
|
249
|
-
* \
|
|
250
|
-
* _The subject_
|
|
251
|
-
* ```json
|
|
252
|
-
* {"userID": "1", "userDepartament": "NBC"}
|
|
253
|
-
* ```
|
|
254
|
-
* and _The resource_
|
|
255
|
-
* ```json
|
|
256
|
-
* ["FOX", "NBC", "AONE"]
|
|
257
|
-
* ```
|
|
258
|
-
* \
|
|
259
|
-
* Now we can make the matching rule:
|
|
260
|
-
* ```json
|
|
261
|
-
* ["subject.userDepartament", "=", "resource"]
|
|
262
|
-
* ```
|
|
263
|
-
* **Note: In this rule whe set the resource field as the «resource» string.\
|
|
264
|
-
* This means that we will compare the entire resource as a whole,\
|
|
265
|
-
* and not search for it by field name.**
|
|
266
|
-
* \
|
|
267
|
-
* **Example 4.**\
|
|
268
|
-
* In this case will be compared resource and array of string:\
|
|
269
|
-
* \
|
|
270
|
-
* _The subject_
|
|
271
|
-
* ```json
|
|
272
|
-
* {"user": {"account": {"roles": ["admin", "viewer"]}}}
|
|
273
|
-
* ```
|
|
274
|
-
* and _The resource_
|
|
275
|
-
* ```json
|
|
276
|
-
* undefined
|
|
277
|
-
* ```
|
|
278
|
-
* \
|
|
279
|
-
* Now we can make the matching rule:
|
|
280
|
-
* ```json
|
|
281
|
-
* ["subject.user.account.roles", "in", "admin"]
|
|
433
|
+
@param action - Action
|
|
434
|
+
* @param resource - Resource
|
|
282
435
|
*/
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
436
|
+
resolve(action, resource) {
|
|
437
|
+
const filteredPolicies = this.policies.filter(policy => {
|
|
438
|
+
return AbilityResolver.isInActionContain(policy.action, String(action));
|
|
439
|
+
});
|
|
440
|
+
filteredPolicies.map(policy => policy.check(resource));
|
|
441
|
+
this.policies = filteredPolicies;
|
|
442
|
+
return this;
|
|
287
443
|
}
|
|
288
|
-
|
|
289
|
-
|
|
444
|
+
enforce(action, resource) {
|
|
445
|
+
const resolver = this.resolve(action, resource);
|
|
446
|
+
if (resolver) {
|
|
447
|
+
if (resolver.isDeny()) {
|
|
448
|
+
throw new AbilityError_1.PermissionError(resolver.getPolicy()?.name?.toString() || 'Unknown permission error');
|
|
449
|
+
}
|
|
450
|
+
}
|
|
290
451
|
}
|
|
452
|
+
/**
|
|
453
|
+
* Get the last effect of the policy
|
|
454
|
+
*
|
|
455
|
+
* @returns {AbilityPolicyEffect | null}
|
|
456
|
+
*/
|
|
291
457
|
getEffect() {
|
|
292
|
-
|
|
458
|
+
const effects = this.policies.reduce((collect, policy, _index) => {
|
|
459
|
+
if (policy.matchState.isEqual(AbilityMatch_1.default.MATCH)) {
|
|
460
|
+
return collect.concat(policy.effect);
|
|
461
|
+
}
|
|
462
|
+
return collect;
|
|
463
|
+
}, []);
|
|
464
|
+
if (effects.length) {
|
|
465
|
+
return effects[effects.length - 1];
|
|
466
|
+
}
|
|
467
|
+
return null;
|
|
293
468
|
}
|
|
294
|
-
isPermit(
|
|
295
|
-
|
|
469
|
+
isPermit() {
|
|
470
|
+
const effect = this.getEffect();
|
|
471
|
+
return effect !== null && effect.isEqual(AbilityPolicyEffect_1.default.PERMIT);
|
|
296
472
|
}
|
|
297
|
-
isDeny(
|
|
298
|
-
|
|
473
|
+
isDeny() {
|
|
474
|
+
const effect = this.getEffect();
|
|
475
|
+
return effect !== null && effect.isEqual(AbilityPolicyEffect_1.default.DENY);
|
|
476
|
+
}
|
|
477
|
+
getPolicy() {
|
|
478
|
+
const lastPolicy = this.policies.length ? this.policies[this.policies.length - 1] : null;
|
|
479
|
+
return lastPolicy && lastPolicy.matchState.isEqual(AbilityMatch_1.default.MATCH) ? lastPolicy : null;
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* Check if the action is contained in another action
|
|
483
|
+
* @param actionA - The first action to check
|
|
484
|
+
* @param actionB - The second action to check
|
|
485
|
+
*/
|
|
486
|
+
static isInActionContain(actionA, actionB) {
|
|
487
|
+
const actionAArray = String(actionA).split('.');
|
|
488
|
+
const actionBArray = String(actionB).split('.');
|
|
489
|
+
const a = actionAArray.length >= actionBArray.length ? actionAArray : actionBArray;
|
|
490
|
+
const b = actionBArray.length >= actionAArray.length ? actionBArray : actionAArray;
|
|
491
|
+
return a
|
|
492
|
+
.reduce((acc, chunk, index) => {
|
|
493
|
+
const iterationRes = chunk === b[index] || b[index] === '*' || chunk === '*';
|
|
494
|
+
return acc.concat(iterationRes);
|
|
495
|
+
}, [])
|
|
496
|
+
.every(Boolean);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
exports.AbilityResolver = AbilityResolver;
|
|
500
|
+
exports["default"] = AbilityResolver;
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
/***/ }),
|
|
504
|
+
|
|
505
|
+
/***/ 476:
|
|
506
|
+
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
510
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
511
|
+
};
|
|
512
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
513
|
+
exports.AbilityRule = void 0;
|
|
514
|
+
const AbilityMatch_1 = __importDefault(__webpack_require__(909));
|
|
515
|
+
const AbilityCondition_1 = __importDefault(__webpack_require__(261));
|
|
516
|
+
const AbilityParser_1 = __importDefault(__webpack_require__(189));
|
|
517
|
+
class AbilityRule {
|
|
518
|
+
matches;
|
|
519
|
+
name;
|
|
520
|
+
id;
|
|
521
|
+
state = AbilityMatch_1.default.PENDING;
|
|
522
|
+
constructor(params) {
|
|
523
|
+
const { id, name, matches } = params;
|
|
524
|
+
this.id = id;
|
|
525
|
+
this.name = name;
|
|
526
|
+
this.matches = matches;
|
|
299
527
|
}
|
|
300
|
-
|
|
301
|
-
|
|
528
|
+
/**
|
|
529
|
+
* Check if the rule is matched
|
|
530
|
+
* @param resource - The resource to check
|
|
531
|
+
*/
|
|
532
|
+
check(resource) {
|
|
533
|
+
const [_subjectPathName, condition, _staticValueOrPathName] = this.matches;
|
|
302
534
|
let is = false;
|
|
303
|
-
const [valueS, valueO] = this.extractValues(
|
|
304
|
-
if (condition
|
|
535
|
+
const [valueS, valueO] = this.extractValues(resource);
|
|
536
|
+
if (AbilityCondition_1.default.LESS_THAN.isEqual(condition)) {
|
|
305
537
|
is = Number(valueS) < Number(valueO);
|
|
306
538
|
}
|
|
307
|
-
if (condition
|
|
539
|
+
if (AbilityCondition_1.default.LESS_OR_EQUAL.isEqual(condition)) {
|
|
308
540
|
is = Number(valueS) <= Number(valueO);
|
|
309
541
|
}
|
|
310
|
-
if (condition
|
|
542
|
+
if (AbilityCondition_1.default.MORE_THAN.isEqual(condition)) {
|
|
311
543
|
is = Number(valueS) > Number(valueO);
|
|
312
544
|
}
|
|
313
|
-
if (condition
|
|
545
|
+
if (AbilityCondition_1.default.MORE_OR_EQUAL.isEqual(condition)) {
|
|
314
546
|
is = Number(valueS) >= Number(valueO);
|
|
315
547
|
}
|
|
316
|
-
if (condition
|
|
548
|
+
if (AbilityCondition_1.default.EQUAL.isEqual(condition)) {
|
|
317
549
|
is = valueS === valueO;
|
|
318
550
|
}
|
|
319
|
-
if (condition
|
|
551
|
+
if (AbilityCondition_1.default.NOT_EQUAL.isEqual(condition)) {
|
|
320
552
|
is = valueS !== valueO;
|
|
321
553
|
}
|
|
322
|
-
if (condition
|
|
554
|
+
if (AbilityCondition_1.default.IN.isEqual(condition)) {
|
|
323
555
|
// [<some>] and [<some>]
|
|
324
556
|
if (Array.isArray(valueS) && Array.isArray(valueO)) {
|
|
325
557
|
is = valueS.some(v => valueO.find(v1 => v1 === v));
|
|
@@ -333,41 +565,53 @@ class AbilityRule {
|
|
|
333
565
|
is = valueS.includes(valueO);
|
|
334
566
|
}
|
|
335
567
|
}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
568
|
+
if (AbilityCondition_1.default.NOT_IN.isEqual(condition)) {
|
|
569
|
+
// [<some>] and [<some>]
|
|
570
|
+
if (Array.isArray(valueS) && Array.isArray(valueO)) {
|
|
571
|
+
is = !valueS.some(v => valueO.find(v1 => v1 === v));
|
|
572
|
+
}
|
|
573
|
+
// <some> and [<some>]
|
|
574
|
+
if ((typeof valueS === 'string' || typeof valueS === 'number') && Array.isArray(valueO)) {
|
|
575
|
+
is = !valueO.includes(valueS);
|
|
576
|
+
}
|
|
577
|
+
// [<some>] and <some>
|
|
578
|
+
if ((typeof valueO === 'string' || typeof valueO === 'number') && Array.isArray(valueS)) {
|
|
579
|
+
is = !valueS.includes(valueO);
|
|
580
|
+
}
|
|
344
581
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
return [sValue, resource];
|
|
582
|
+
this.state = is ? AbilityMatch_1.default.MATCH : AbilityMatch_1.default.MISMATCH;
|
|
583
|
+
return this.state;
|
|
584
|
+
}
|
|
585
|
+
/**
|
|
586
|
+
* Extract values from the resource
|
|
587
|
+
* @param resource - The resource to extract values from
|
|
588
|
+
*/
|
|
589
|
+
extractValues(resource) {
|
|
590
|
+
const [subjectPathName, _condition, staticValueOrPathName] = this.matches;
|
|
591
|
+
let leftSideValue;
|
|
592
|
+
let rightSideValue;
|
|
593
|
+
if (resource === null || typeof resource === 'undefined') {
|
|
594
|
+
return [NaN, NaN];
|
|
359
595
|
}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
596
|
+
const isPath = (str) => {
|
|
597
|
+
return typeof str === 'string' && str.match(/\./g) !== null;
|
|
598
|
+
};
|
|
599
|
+
if (isPath(subjectPathName)) {
|
|
600
|
+
leftSideValue = this.getDotNotationValue(resource, subjectPathName);
|
|
364
601
|
}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
return [sValue, resourceFieldName];
|
|
602
|
+
if (isPath(staticValueOrPathName)) {
|
|
603
|
+
rightSideValue = this.getDotNotationValue(resource, staticValueOrPathName);
|
|
368
604
|
}
|
|
369
|
-
|
|
605
|
+
else {
|
|
606
|
+
rightSideValue = staticValueOrPathName;
|
|
607
|
+
}
|
|
608
|
+
return [leftSideValue, rightSideValue];
|
|
370
609
|
}
|
|
610
|
+
/**
|
|
611
|
+
* Get the value of the object by dot notation
|
|
612
|
+
* @param resource - The object to get the value from
|
|
613
|
+
* @param desc - The dot notation string
|
|
614
|
+
*/
|
|
371
615
|
getDotNotationValue(resource, desc) {
|
|
372
616
|
const arr = desc.split('.');
|
|
373
617
|
while (arr.length && resource) {
|
|
@@ -391,26 +635,30 @@ class AbilityRule {
|
|
|
391
635
|
}
|
|
392
636
|
return resource;
|
|
393
637
|
}
|
|
394
|
-
/**
|
|
395
|
-
* Parsing the rule config object or JSON string\
|
|
396
|
-
* of config and returns the AbilityRule class instance
|
|
397
|
-
*/
|
|
398
638
|
static parse(configOrJson) {
|
|
399
|
-
const
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
639
|
+
const config = AbilityParser_1.default.prepareAndValidateConfig(configOrJson, [
|
|
640
|
+
['id', 'string', true],
|
|
641
|
+
['name', 'string', true],
|
|
642
|
+
['matches', 'array', true],
|
|
643
|
+
]);
|
|
644
|
+
const { id, name, matches } = config;
|
|
645
|
+
const [leftField, condition, rightField] = matches;
|
|
646
|
+
return new AbilityRule({
|
|
647
|
+
id,
|
|
648
|
+
name,
|
|
649
|
+
matches: [leftField, new AbilityCondition_1.default(condition), rightField],
|
|
650
|
+
});
|
|
403
651
|
}
|
|
404
652
|
/**
|
|
405
653
|
* Export the rule to config object
|
|
406
654
|
*/
|
|
407
|
-
|
|
408
|
-
const
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
655
|
+
export() {
|
|
656
|
+
const [leftField, condition, rightField] = this.matches;
|
|
657
|
+
return {
|
|
658
|
+
id: this.id,
|
|
659
|
+
name: this.name,
|
|
660
|
+
matches: [leftField, condition.code, rightField],
|
|
412
661
|
};
|
|
413
|
-
return config;
|
|
414
662
|
}
|
|
415
663
|
}
|
|
416
664
|
exports.AbilityRule = AbilityRule;
|
|
@@ -419,7 +667,7 @@ exports["default"] = AbilityRule;
|
|
|
419
667
|
|
|
420
668
|
/***/ }),
|
|
421
669
|
|
|
422
|
-
/***/
|
|
670
|
+
/***/ 402:
|
|
423
671
|
/***/ (function(__unused_webpack_module, exports, __webpack_require__) {
|
|
424
672
|
|
|
425
673
|
|
|
@@ -427,107 +675,100 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
427
675
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
428
676
|
};
|
|
429
677
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
678
|
+
exports.AbilityRuleSet = void 0;
|
|
430
679
|
const AbilityRule_1 = __importDefault(__webpack_require__(476));
|
|
431
|
-
const
|
|
432
|
-
|
|
680
|
+
const AbilityCompare_1 = __importDefault(__webpack_require__(923));
|
|
681
|
+
const AbilityMatch_1 = __importDefault(__webpack_require__(909));
|
|
682
|
+
const AbilityParser_1 = __importDefault(__webpack_require__(189));
|
|
683
|
+
class AbilityRuleSet {
|
|
684
|
+
state = AbilityMatch_1.default.PENDING;
|
|
433
685
|
/**
|
|
434
|
-
*
|
|
435
|
-
*
|
|
436
|
-
* @param ruleName {string} - The rule name
|
|
437
|
-
* @param effect {AbilityRuleStatus} - Return value
|
|
438
|
-
* @param matches {AbilityRuleMatches} - The matching rule he matching rule can be on of the format:
|
|
439
|
-
* \
|
|
440
|
-
* For example, be compared two's data\
|
|
441
|
-
* \
|
|
442
|
-
* _The subject_
|
|
443
|
-
* ```json
|
|
444
|
-
* {"userID": "1", "userDepartament": "NBC"}
|
|
445
|
-
* ```
|
|
446
|
-
* and _The resource_
|
|
447
|
-
* ```json
|
|
448
|
-
* {"departamentID": "154", "departamentName": "NBC"}
|
|
449
|
-
* ```
|
|
450
|
-
* \
|
|
451
|
-
* Now we can make the matching rule:
|
|
452
|
-
* ```json
|
|
453
|
-
* ["subject.userDepartament", "=", "resource.departamentName"]
|
|
454
|
-
* ```
|
|
455
|
-
*
|
|
456
|
-
* \
|
|
457
|
-
* **Example 2.**\
|
|
458
|
-
* In this case will be compared resource and string:
|
|
459
|
-
* \
|
|
460
|
-
* _The subject_
|
|
461
|
-
* ```json
|
|
462
|
-
* {"userID": "1", "userDepartament": "NBC"}
|
|
463
|
-
* ```
|
|
464
|
-
* and _The resource_ will be «undefined».\
|
|
465
|
-
* Now we can make the matching rule:
|
|
466
|
-
* ```json
|
|
467
|
-
* ["subject.userDepartament", "=", "NBC"]
|
|
468
|
-
* ```
|
|
469
|
-
* \
|
|
470
|
-
* **Example 3.**\
|
|
471
|
-
* In this case will be compared resource and array of string:\
|
|
472
|
-
* \
|
|
473
|
-
* _The subject_
|
|
474
|
-
* ```json
|
|
475
|
-
* {"userID": "1", "userDepartament": "NBC"}
|
|
476
|
-
* ```
|
|
477
|
-
* and _The resource_
|
|
478
|
-
* ```json
|
|
479
|
-
* ["FOX", "NBC", "AONE"]
|
|
480
|
-
* ```
|
|
481
|
-
* \
|
|
482
|
-
* Now we can make the matching rule:
|
|
483
|
-
* ```json
|
|
484
|
-
* ["subject.userDepartament", "=", "resource"]
|
|
485
|
-
* ```
|
|
486
|
-
* **Note: In this rule whe set the resource field as the «resource» string.\
|
|
487
|
-
* This means that we will compare the entire resource as a whole,\
|
|
488
|
-
* and not search for it by field name.**
|
|
686
|
+
* List of rules
|
|
489
687
|
*/
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
688
|
+
rules = [];
|
|
689
|
+
/**
|
|
690
|
+
* Rules compare method.\
|
|
691
|
+
* For the «and» method the rule will be permitted if all\
|
|
692
|
+
* rules will be returns «permit» status and for the «or» - if\
|
|
693
|
+
* one of the rules returns as «permit»
|
|
694
|
+
*/
|
|
695
|
+
compareMethod = AbilityCompare_1.default.AND;
|
|
493
696
|
/**
|
|
494
|
-
*
|
|
697
|
+
* Group name
|
|
495
698
|
*/
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
const
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
699
|
+
name;
|
|
700
|
+
/**
|
|
701
|
+
* Group ID
|
|
702
|
+
*/
|
|
703
|
+
id;
|
|
704
|
+
constructor(params) {
|
|
705
|
+
const { name, id } = params;
|
|
706
|
+
this.name = name;
|
|
707
|
+
this.id = id;
|
|
708
|
+
}
|
|
709
|
+
addRule(rule, compareMethod) {
|
|
710
|
+
this.rules.push(rule);
|
|
711
|
+
this.compareMethod = compareMethod;
|
|
712
|
+
return this;
|
|
713
|
+
}
|
|
714
|
+
addRules(rules, compareMethod) {
|
|
715
|
+
rules.forEach(rule => this.addRule(rule, compareMethod));
|
|
716
|
+
return this;
|
|
717
|
+
}
|
|
718
|
+
check(resources) {
|
|
719
|
+
this.state = AbilityMatch_1.default.MISMATCH;
|
|
720
|
+
if (!this.rules.length) {
|
|
721
|
+
return this.state;
|
|
722
|
+
}
|
|
723
|
+
const ruleCheckStates = this.rules.reduce((collect, rule) => {
|
|
724
|
+
return collect.concat(rule.check(resources));
|
|
725
|
+
}, []);
|
|
726
|
+
if (AbilityCompare_1.default.AND.isEqual(this.compareMethod)) {
|
|
727
|
+
if (ruleCheckStates.every(ruleState => AbilityMatch_1.default.MATCH.isEqual(ruleState))) {
|
|
728
|
+
this.state = AbilityMatch_1.default.MATCH;
|
|
512
729
|
}
|
|
730
|
+
}
|
|
731
|
+
if (AbilityCompare_1.default.OR.isEqual(this.compareMethod)) {
|
|
732
|
+
if (ruleCheckStates.some(ruleState => AbilityMatch_1.default.MATCH.isEqual(ruleState))) {
|
|
733
|
+
this.state = AbilityMatch_1.default.MATCH;
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
return this.state;
|
|
737
|
+
}
|
|
738
|
+
/**
|
|
739
|
+
* Parse the config JSON format to Group class instance
|
|
740
|
+
*/
|
|
741
|
+
static parse(configOrJson) {
|
|
742
|
+
const config = AbilityParser_1.default.prepareAndValidateConfig(configOrJson, [
|
|
743
|
+
['id', 'string', true],
|
|
744
|
+
['name', 'string', true],
|
|
745
|
+
['compareMethod', 'number', true],
|
|
746
|
+
['rules', 'array', true],
|
|
747
|
+
]);
|
|
748
|
+
const { id, name, rules, compareMethod } = config;
|
|
749
|
+
const ruleSet = new AbilityRuleSet({
|
|
750
|
+
name,
|
|
751
|
+
id,
|
|
513
752
|
});
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
753
|
+
ruleSet.compareMethod = new AbilityCompare_1.default(compareMethod);
|
|
754
|
+
// Adding rules if exists
|
|
755
|
+
if (rules && rules.length > 0) {
|
|
756
|
+
const abilityRules = rules.map(ruleConfig => AbilityRule_1.default.parse(ruleConfig));
|
|
757
|
+
ruleSet.addRules(abilityRules, ruleSet.compareMethod);
|
|
758
|
+
}
|
|
759
|
+
return ruleSet;
|
|
760
|
+
}
|
|
761
|
+
export() {
|
|
517
762
|
return {
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
763
|
+
id: this.id.toString(),
|
|
764
|
+
name: this.name.toString(),
|
|
765
|
+
compareMethod: this.compareMethod.code,
|
|
766
|
+
rules: this.rules.map(rule => rule.export()),
|
|
521
767
|
};
|
|
522
768
|
}
|
|
523
|
-
enforcePolicies(policiesResult, compareMethod) {
|
|
524
|
-
const { permission, deniedRules } = this.checkPolicies(policiesResult, compareMethod);
|
|
525
|
-
if (permission === 'deny') {
|
|
526
|
-
throw new Error(`Permission denied. ${deniedRules[0].getName().toString()}`);
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
769
|
}
|
|
530
|
-
exports
|
|
770
|
+
exports.AbilityRuleSet = AbilityRuleSet;
|
|
771
|
+
exports["default"] = AbilityRuleSet;
|
|
531
772
|
|
|
532
773
|
|
|
533
774
|
/***/ }),
|
|
@@ -550,15 +791,18 @@ var __createBinding = (this && this.__createBinding) || (Object.create ? (functi
|
|
|
550
791
|
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
551
792
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
552
793
|
};
|
|
553
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
554
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
555
|
-
};
|
|
556
794
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
557
|
-
|
|
795
|
+
__exportStar(__webpack_require__(19), exports);
|
|
796
|
+
__exportStar(__webpack_require__(923), exports);
|
|
797
|
+
__exportStar(__webpack_require__(261), exports);
|
|
798
|
+
__exportStar(__webpack_require__(122), exports);
|
|
799
|
+
__exportStar(__webpack_require__(909), exports);
|
|
800
|
+
__exportStar(__webpack_require__(189), exports);
|
|
558
801
|
__exportStar(__webpack_require__(844), exports);
|
|
559
|
-
__exportStar(__webpack_require__(
|
|
802
|
+
__exportStar(__webpack_require__(277), exports);
|
|
803
|
+
__exportStar(__webpack_require__(668), exports);
|
|
560
804
|
__exportStar(__webpack_require__(476), exports);
|
|
561
|
-
exports
|
|
805
|
+
__exportStar(__webpack_require__(402), exports);
|
|
562
806
|
|
|
563
807
|
|
|
564
808
|
/***/ })
|