@via-profit/ability 2.0.0-rc.7 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +328 -156
- package/build/playground.js +59 -416
- package/build/playground.js.map +1 -1
- package/dist/AbilityCode.d.ts +6 -6
- package/dist/AbilityCompare.d.ts +2 -2
- package/dist/AbilityCondition.d.ts +13 -10
- package/dist/AbilityError.d.ts +0 -3
- package/dist/AbilityMatch.d.ts +2 -2
- package/dist/AbilityPolicy.d.ts +12 -11
- package/dist/AbilityPolicyEffect.d.ts +2 -2
- package/dist/AbilityResolver.d.ts +1 -1
- package/dist/AbilityRule.d.ts +18 -3
- package/dist/AbilityRuleSet.d.ts +11 -6
- package/dist/index.js +79 -68
- package/package.json +1 -2
- package/dist/AbilityPolicyResult.d.ts +0 -6
- package/dist/playground.d.ts +0 -26
package/dist/index.js
CHANGED
|
@@ -9,9 +9,12 @@
|
|
|
9
9
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
10
10
|
exports.AbilityCode = void 0;
|
|
11
11
|
class AbilityCode {
|
|
12
|
-
|
|
12
|
+
_code;
|
|
13
13
|
constructor(code) {
|
|
14
|
-
this.
|
|
14
|
+
this._code = code;
|
|
15
|
+
}
|
|
16
|
+
get code() {
|
|
17
|
+
return this._code;
|
|
15
18
|
}
|
|
16
19
|
isEqual(compareWith) {
|
|
17
20
|
return compareWith !== null && this.code === compareWith.code;
|
|
@@ -19,18 +22,6 @@ class AbilityCode {
|
|
|
19
22
|
isNotEqual(compareWith) {
|
|
20
23
|
return !this.isEqual(compareWith);
|
|
21
24
|
}
|
|
22
|
-
static fromLiteral(literal) {
|
|
23
|
-
let Code = null;
|
|
24
|
-
Object.keys(this).forEach(member => {
|
|
25
|
-
if (member === literal) {
|
|
26
|
-
Code = this[member];
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
if (!Code) {
|
|
30
|
-
throw new Error(`Mismatch error. The literal ${literal} can not be find as a member of this class`);
|
|
31
|
-
}
|
|
32
|
-
return new this(Code.code);
|
|
33
|
-
}
|
|
34
25
|
}
|
|
35
26
|
exports.AbilityCode = AbilityCode;
|
|
36
27
|
exports["default"] = AbilityCode;
|
|
@@ -68,15 +59,33 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
68
59
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
69
60
|
exports.AbilityCondition = void 0;
|
|
70
61
|
const AbilityCode_1 = __importDefault(__webpack_require__(19));
|
|
62
|
+
const AbilityError_1 = __webpack_require__(122);
|
|
71
63
|
class AbilityCondition extends AbilityCode_1.default {
|
|
72
|
-
static
|
|
73
|
-
static
|
|
74
|
-
static
|
|
75
|
-
static
|
|
76
|
-
static
|
|
77
|
-
static
|
|
78
|
-
static
|
|
79
|
-
static
|
|
64
|
+
static equal = new AbilityCondition('=');
|
|
65
|
+
static not_equal = new AbilityCondition('<>');
|
|
66
|
+
static more_than = new AbilityCondition('>');
|
|
67
|
+
static less_than = new AbilityCondition('<');
|
|
68
|
+
static less_or_equal = new AbilityCondition('<=');
|
|
69
|
+
static more_or_equal = new AbilityCondition('>=');
|
|
70
|
+
static in = new AbilityCondition('in');
|
|
71
|
+
static not_in = new AbilityCondition('not in');
|
|
72
|
+
static fromLiteral(literal) {
|
|
73
|
+
const code = AbilityCondition[literal]?.code || null;
|
|
74
|
+
if (code === null) {
|
|
75
|
+
throw new AbilityError_1.AbilityParserError(`Literal ${literal} does not found in AbilityCondition class`);
|
|
76
|
+
}
|
|
77
|
+
return new AbilityCondition(code);
|
|
78
|
+
}
|
|
79
|
+
get literal() {
|
|
80
|
+
const literal = Object.keys(AbilityCondition).find(member => {
|
|
81
|
+
const val = AbilityCondition[member];
|
|
82
|
+
return val.code === this.code;
|
|
83
|
+
});
|
|
84
|
+
if (typeof literal === 'undefined') {
|
|
85
|
+
throw new Error(`Literal value does not found in class AbilityCondition`);
|
|
86
|
+
}
|
|
87
|
+
return literal;
|
|
88
|
+
}
|
|
80
89
|
}
|
|
81
90
|
exports.AbilityCondition = AbilityCondition;
|
|
82
91
|
exports["default"] = AbilityCondition;
|
|
@@ -89,7 +98,7 @@ exports["default"] = AbilityCondition;
|
|
|
89
98
|
|
|
90
99
|
|
|
91
100
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
92
|
-
exports.
|
|
101
|
+
exports.AbilityParserError = exports.AbilityError = void 0;
|
|
93
102
|
class AbilityError extends Error {
|
|
94
103
|
constructor(message) {
|
|
95
104
|
super(message);
|
|
@@ -102,12 +111,6 @@ class AbilityParserError extends Error {
|
|
|
102
111
|
}
|
|
103
112
|
}
|
|
104
113
|
exports.AbilityParserError = AbilityParserError;
|
|
105
|
-
class PermissionError extends Error {
|
|
106
|
-
constructor(message) {
|
|
107
|
-
super(message);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
exports.PermissionError = PermissionError;
|
|
111
114
|
|
|
112
115
|
|
|
113
116
|
/***/ }),
|
|
@@ -191,18 +194,18 @@ class AbilityParser {
|
|
|
191
194
|
ruleSet.rules.forEach(rule => {
|
|
192
195
|
let value = 'any';
|
|
193
196
|
switch (true) {
|
|
194
|
-
case rule.condition.isEqual(AbilityCondition_1.default.
|
|
195
|
-
case rule.condition.isEqual(AbilityCondition_1.default.
|
|
197
|
+
case rule.condition.isEqual(AbilityCondition_1.default.not_equal):
|
|
198
|
+
case rule.condition.isEqual(AbilityCondition_1.default.equal):
|
|
196
199
|
value = typeof rule.resource;
|
|
197
200
|
break;
|
|
198
|
-
case rule.condition.isEqual(AbilityCondition_1.default.
|
|
199
|
-
case rule.condition.isEqual(AbilityCondition_1.default.
|
|
201
|
+
case rule.condition.isEqual(AbilityCondition_1.default.in):
|
|
202
|
+
case rule.condition.isEqual(AbilityCondition_1.default.not_in):
|
|
200
203
|
value = `${typeof rule.resource}[]`;
|
|
201
204
|
break;
|
|
202
|
-
case rule.condition.isEqual(AbilityCondition_1.default.
|
|
203
|
-
case rule.condition.isEqual(AbilityCondition_1.default.
|
|
204
|
-
case rule.condition.isEqual(AbilityCondition_1.default.
|
|
205
|
-
case rule.condition.isEqual(AbilityCondition_1.default.
|
|
205
|
+
case rule.condition.isEqual(AbilityCondition_1.default.more_or_equal):
|
|
206
|
+
case rule.condition.isEqual(AbilityCondition_1.default.more_than):
|
|
207
|
+
case rule.condition.isEqual(AbilityCondition_1.default.less_or_equal):
|
|
208
|
+
case rule.condition.isEqual(AbilityCondition_1.default.less_than):
|
|
206
209
|
value = 'number';
|
|
207
210
|
break;
|
|
208
211
|
}
|
|
@@ -313,7 +316,7 @@ class AbilityPolicy {
|
|
|
313
316
|
action,
|
|
314
317
|
effect: new AbilityPolicyEffect_1.default(effect),
|
|
315
318
|
});
|
|
316
|
-
policy.compareMethod = AbilityCompare_1.default
|
|
319
|
+
policy.compareMethod = new AbilityCompare_1.default(compareMethod);
|
|
317
320
|
ruleSet.forEach(ruleSetConfig => {
|
|
318
321
|
policy.addRuleSet(AbilityRuleSet_1.default.parse(ruleSetConfig));
|
|
319
322
|
});
|
|
@@ -391,10 +394,8 @@ class AbilityResolver {
|
|
|
391
394
|
}
|
|
392
395
|
enforce(action, resource) {
|
|
393
396
|
const resolver = this.resolve(action, resource);
|
|
394
|
-
if (resolver) {
|
|
395
|
-
|
|
396
|
-
throw new AbilityError_1.PermissionError(resolver.getPolicy()?.name?.toString() || 'Unknown permission error');
|
|
397
|
-
}
|
|
397
|
+
if (resolver.isDeny()) {
|
|
398
|
+
throw new AbilityError_1.AbilityError(resolver.getMatchedPolicy()?.name?.toString() || 'Unknown permission error');
|
|
398
399
|
}
|
|
399
400
|
}
|
|
400
401
|
/**
|
|
@@ -422,9 +423,10 @@ class AbilityResolver {
|
|
|
422
423
|
const effect = this.getEffect();
|
|
423
424
|
return effect !== null && effect.isEqual(AbilityPolicyEffect_1.default.deny);
|
|
424
425
|
}
|
|
425
|
-
|
|
426
|
-
const
|
|
427
|
-
|
|
426
|
+
getMatchedPolicy() {
|
|
427
|
+
const matchedPolicies = this.policies.filter(policy => policy.matchState.isEqual(AbilityMatch_1.default.match));
|
|
428
|
+
const lastPolicy = matchedPolicies.length ? matchedPolicies[matchedPolicies.length - 1] : null;
|
|
429
|
+
return lastPolicy || null;
|
|
428
430
|
}
|
|
429
431
|
/**
|
|
430
432
|
* Check if the action is contained in another action
|
|
@@ -435,13 +437,12 @@ class AbilityResolver {
|
|
|
435
437
|
const actionAArray = String(actionA).split('.');
|
|
436
438
|
const actionBArray = String(actionB).split('.');
|
|
437
439
|
const a = actionAArray.length >= actionBArray.length ? actionAArray : actionBArray;
|
|
438
|
-
const b = actionBArray.length
|
|
439
|
-
|
|
440
|
-
.reduce((acc, chunk, index) => {
|
|
440
|
+
const b = actionBArray.length <= actionAArray.length ? actionBArray : actionAArray;
|
|
441
|
+
const c = a.reduce((acc, chunk, index) => {
|
|
441
442
|
const iterationRes = chunk === b[index] || b[index] === '*' || chunk === '*';
|
|
442
443
|
return acc.concat(iterationRes);
|
|
443
|
-
}, [])
|
|
444
|
-
|
|
444
|
+
}, []);
|
|
445
|
+
return c.every(Boolean);
|
|
445
446
|
}
|
|
446
447
|
}
|
|
447
448
|
exports.AbilityResolver = AbilityResolver;
|
|
@@ -461,6 +462,9 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
|
461
462
|
exports.AbilityRule = void 0;
|
|
462
463
|
const AbilityMatch_1 = __importDefault(__webpack_require__(909));
|
|
463
464
|
const AbilityCondition_1 = __importDefault(__webpack_require__(261));
|
|
465
|
+
/**
|
|
466
|
+
* Represents a rule that defines a condition to be checked against a subject and resource.
|
|
467
|
+
*/
|
|
464
468
|
class AbilityRule {
|
|
465
469
|
/**
|
|
466
470
|
* Subject key path like a 'user.name'
|
|
@@ -474,13 +478,22 @@ class AbilityRule {
|
|
|
474
478
|
name;
|
|
475
479
|
id;
|
|
476
480
|
state = AbilityMatch_1.default.pending;
|
|
481
|
+
/**
|
|
482
|
+
* Creates an instance of AbilityRule.
|
|
483
|
+
* @param {string} options.id - The unique identifier of the rule.
|
|
484
|
+
* @param {string} options.name - The name of the rule.
|
|
485
|
+
* @param {AbilityCondition} options.condition - The condition to evaluate.
|
|
486
|
+
* @param {string} options.subject - The subject of the rule.
|
|
487
|
+
* @param {string} options.resource - The resource to compare against.
|
|
488
|
+
* @param params
|
|
489
|
+
*/
|
|
477
490
|
constructor(params) {
|
|
478
491
|
const { id, name, subject, resource, condition } = params;
|
|
479
492
|
this.id = id;
|
|
480
493
|
this.name = name;
|
|
481
494
|
this.subject = subject;
|
|
482
495
|
this.resource = resource;
|
|
483
|
-
this.condition =
|
|
496
|
+
this.condition = condition;
|
|
484
497
|
}
|
|
485
498
|
/**
|
|
486
499
|
* Check if the rule is matched
|
|
@@ -489,25 +502,25 @@ class AbilityRule {
|
|
|
489
502
|
check(resource) {
|
|
490
503
|
let is = false;
|
|
491
504
|
const [valueS, valueO] = this.extractValues(resource);
|
|
492
|
-
if (AbilityCondition_1.default.
|
|
505
|
+
if (AbilityCondition_1.default.less_than.isEqual(this.condition)) {
|
|
493
506
|
is = Number(valueS) < Number(valueO);
|
|
494
507
|
}
|
|
495
|
-
if (AbilityCondition_1.default.
|
|
508
|
+
if (AbilityCondition_1.default.less_or_equal.isEqual(this.condition)) {
|
|
496
509
|
is = Number(valueS) <= Number(valueO);
|
|
497
510
|
}
|
|
498
|
-
if (AbilityCondition_1.default.
|
|
511
|
+
if (AbilityCondition_1.default.more_than.isEqual(this.condition)) {
|
|
499
512
|
is = Number(valueS) > Number(valueO);
|
|
500
513
|
}
|
|
501
|
-
if (AbilityCondition_1.default.
|
|
514
|
+
if (AbilityCondition_1.default.more_or_equal.isEqual(this.condition)) {
|
|
502
515
|
is = Number(valueS) >= Number(valueO);
|
|
503
516
|
}
|
|
504
|
-
if (AbilityCondition_1.default.
|
|
517
|
+
if (AbilityCondition_1.default.equal.isEqual(this.condition)) {
|
|
505
518
|
is = valueS === valueO;
|
|
506
519
|
}
|
|
507
|
-
if (AbilityCondition_1.default.
|
|
520
|
+
if (AbilityCondition_1.default.not_equal.isEqual(this.condition)) {
|
|
508
521
|
is = valueS !== valueO;
|
|
509
522
|
}
|
|
510
|
-
if (AbilityCondition_1.default.
|
|
523
|
+
if (AbilityCondition_1.default.in.isEqual(this.condition)) {
|
|
511
524
|
// [<some>] and [<some>]
|
|
512
525
|
if (Array.isArray(valueS) && Array.isArray(valueO)) {
|
|
513
526
|
is = valueS.some(v => valueO.find(v1 => v1 === v));
|
|
@@ -521,7 +534,7 @@ class AbilityRule {
|
|
|
521
534
|
is = valueS.includes(valueO);
|
|
522
535
|
}
|
|
523
536
|
}
|
|
524
|
-
if (AbilityCondition_1.default.
|
|
537
|
+
if (AbilityCondition_1.default.not_in.isEqual(this.condition)) {
|
|
525
538
|
// [<some>] and [<some>]
|
|
526
539
|
if (Array.isArray(valueS) && Array.isArray(valueO)) {
|
|
527
540
|
is = !valueS.some(v => valueO.find(v1 => v1 === v));
|
|
@@ -600,7 +613,7 @@ class AbilityRule {
|
|
|
600
613
|
name,
|
|
601
614
|
subject,
|
|
602
615
|
resource,
|
|
603
|
-
condition,
|
|
616
|
+
condition: new AbilityCondition_1.default(condition),
|
|
604
617
|
});
|
|
605
618
|
}
|
|
606
619
|
/**
|
|
@@ -659,16 +672,14 @@ class AbilityRuleSet {
|
|
|
659
672
|
const { name, id, compareMethod } = params;
|
|
660
673
|
this.name = name;
|
|
661
674
|
this.id = id;
|
|
662
|
-
this.compareMethod =
|
|
663
|
-
// this.compareMethod = new AbilityCompare(compareMethod);
|
|
675
|
+
this.compareMethod = compareMethod;
|
|
664
676
|
}
|
|
665
|
-
addRule(rule
|
|
677
|
+
addRule(rule) {
|
|
666
678
|
this.rules.push(rule);
|
|
667
|
-
this.compareMethod = compareMethod;
|
|
668
679
|
return this;
|
|
669
680
|
}
|
|
670
|
-
addRules(rules
|
|
671
|
-
rules.forEach(rule => this.addRule(rule
|
|
681
|
+
addRules(rules) {
|
|
682
|
+
rules.forEach(rule => this.addRule(rule));
|
|
672
683
|
return this;
|
|
673
684
|
}
|
|
674
685
|
check(resources) {
|
|
@@ -697,14 +708,14 @@ class AbilityRuleSet {
|
|
|
697
708
|
static parse(config) {
|
|
698
709
|
const { id, name, rules, compareMethod } = config;
|
|
699
710
|
const ruleSet = new AbilityRuleSet({
|
|
700
|
-
compareMethod,
|
|
711
|
+
compareMethod: new AbilityCompare_1.default(compareMethod),
|
|
701
712
|
name,
|
|
702
713
|
id,
|
|
703
714
|
});
|
|
704
715
|
// Adding rules if exists
|
|
705
716
|
if (rules && rules.length > 0) {
|
|
706
717
|
const abilityRules = rules.map(ruleConfig => AbilityRule_1.default.parse(ruleConfig));
|
|
707
|
-
ruleSet.addRules(abilityRules
|
|
718
|
+
ruleSet.addRules(abilityRules);
|
|
708
719
|
}
|
|
709
720
|
return ruleSet;
|
|
710
721
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@via-profit/ability",
|
|
3
3
|
"support": "https://via-profit.ru",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.1.0",
|
|
5
5
|
"description": "Via-Profit Ability service",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"ability",
|
|
@@ -28,7 +28,6 @@
|
|
|
28
28
|
},
|
|
29
29
|
"author": {
|
|
30
30
|
"name": "Via Profit",
|
|
31
|
-
"email": "promo@via-profit.ru",
|
|
32
31
|
"url": "https://dev.via-profit.ru"
|
|
33
32
|
},
|
|
34
33
|
"contributors": [
|
package/dist/playground.d.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
export type Resources = {
|
|
2
|
-
readonly ['account.read']: {
|
|
3
|
-
readonly account: {
|
|
4
|
-
readonly id: string;
|
|
5
|
-
readonly roles: readonly string[];
|
|
6
|
-
} | null;
|
|
7
|
-
readonly resource: {
|
|
8
|
-
readonly id: string;
|
|
9
|
-
};
|
|
10
|
-
};
|
|
11
|
-
readonly ['access.auth']: {
|
|
12
|
-
readonly token: {
|
|
13
|
-
readonly type: string;
|
|
14
|
-
readonly id: string;
|
|
15
|
-
} | null;
|
|
16
|
-
};
|
|
17
|
-
readonly ['order.update']: {
|
|
18
|
-
readonly account: {
|
|
19
|
-
readonly roles: readonly string[];
|
|
20
|
-
readonly department: string;
|
|
21
|
-
} | null;
|
|
22
|
-
readonly order: {
|
|
23
|
-
readonly status: string;
|
|
24
|
-
} | null;
|
|
25
|
-
};
|
|
26
|
-
};
|