@spinajs/rbac 2.0.512 → 2.0.514
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/lib/cjs/impersonation.d.ts.map +1 -1
- package/lib/cjs/impersonation.js +2 -49
- package/lib/cjs/impersonation.js.map +1 -1
- package/lib/cjs/util.d.ts +20 -0
- package/lib/cjs/util.d.ts.map +1 -1
- package/lib/cjs/util.js +65 -1
- package/lib/cjs/util.js.map +1 -1
- package/lib/mjs/impersonation.d.ts.map +1 -1
- package/lib/mjs/impersonation.js +2 -49
- package/lib/mjs/impersonation.js.map +1 -1
- package/lib/mjs/util.d.ts +20 -0
- package/lib/mjs/util.d.ts.map +1 -1
- package/lib/mjs/util.js +63 -0
- package/lib/mjs/util.js.map +1 -1
- package/lib/tsconfig.cjs.tsbuildinfo +1 -1
- package/lib/tsconfig.mjs.tsbuildinfo +1 -1
- package/package.json +11 -11
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"impersonation.d.ts","sourceRoot":"","sources":["../../src/impersonation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"impersonation.d.ts","sourceRoot":"","sources":["../../src/impersonation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAI9C,MAAM,MAAM,yBAAyB,GAAG,gBAAgB,GAAG,sBAAsB,GAAG,aAAa,CAAC;AAElG,MAAM,WAAW,0BAA0B;IACzC,iDAAiD;IACjD,aAAa,EAAE,MAAM,EAAE,CAAC;IAExB,+BAA+B;IAC/B,WAAW,EAAE,MAAM,EAAE,CAAC;IAEtB,iEAAiE;IACjE,cAAc,EAAE,MAAM,EAAE,CAAC;IAEzB,gEAAgE;IAChE,EAAE,EAAE,aAAa,CAAC;CACnB;AAED,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,yBAAyB,CAAC;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,0BAA0B,GAAG,yBAAyB,CAoC1F"}
|
package/lib/cjs/impersonation.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.canImpersonate = canImpersonate;
|
|
4
|
+
const util_js_1 = require("./util.js");
|
|
4
5
|
/**
|
|
5
6
|
* Decides whether `originalRoles` may impersonate a user with `targetRoles`.
|
|
6
7
|
*
|
|
@@ -24,7 +25,7 @@ function canImpersonate(opts) {
|
|
|
24
25
|
// (e.g. orphaned data) don't crash the check — treat them as 'no grants'.
|
|
25
26
|
const safePermissions = (roles) => {
|
|
26
27
|
try {
|
|
27
|
-
return
|
|
28
|
+
return (0, util_js_1._collectPermissions)(ac, roles);
|
|
28
29
|
}
|
|
29
30
|
catch {
|
|
30
31
|
return new Set();
|
|
@@ -46,52 +47,4 @@ function canImpersonate(opts) {
|
|
|
46
47
|
}
|
|
47
48
|
return { allowed: true };
|
|
48
49
|
}
|
|
49
|
-
/**
|
|
50
|
-
* Build a flat set of "resource::action" strings representing every permission
|
|
51
|
-
* granted to the union of `roles`. Used so we can compare two role sets by
|
|
52
|
-
* simple set inclusion.
|
|
53
|
-
*/
|
|
54
|
-
function collectPermissions(ac, roles) {
|
|
55
|
-
const out = new Set();
|
|
56
|
-
if (roles.length === 0)
|
|
57
|
-
return out;
|
|
58
|
-
const grants = ac.getGrants();
|
|
59
|
-
const actions = [
|
|
60
|
-
'createAny', 'createOwn', 'readAny', 'readOwn', 'updateAny', 'updateOwn', 'deleteAny', 'deleteOwn',
|
|
61
|
-
];
|
|
62
|
-
// Resources are not enumerable directly via the can() API — read them from
|
|
63
|
-
// the raw grants map and walk every $extend chain reachable from `roles`.
|
|
64
|
-
const visited = new Set();
|
|
65
|
-
const stack = [...roles];
|
|
66
|
-
const resources = new Set();
|
|
67
|
-
while (stack.length) {
|
|
68
|
-
const role = stack.pop();
|
|
69
|
-
if (visited.has(role))
|
|
70
|
-
continue;
|
|
71
|
-
visited.add(role);
|
|
72
|
-
const roleGrants = grants[role];
|
|
73
|
-
if (!roleGrants)
|
|
74
|
-
continue;
|
|
75
|
-
for (const key of Object.keys(roleGrants)) {
|
|
76
|
-
if (key === '$extend') {
|
|
77
|
-
for (const inherited of roleGrants[key])
|
|
78
|
-
stack.push(inherited);
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
resources.add(key);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
for (const resource of resources) {
|
|
86
|
-
for (const action of actions) {
|
|
87
|
-
// ac.can(roles)[action](resource).granted is true if ANY of the roles
|
|
88
|
-
// (or their $extend chain) grants the action — exactly the "union of
|
|
89
|
-
// effective permissions" we want.
|
|
90
|
-
if (ac.can(roles)[action](resource).granted) {
|
|
91
|
-
out.add(`${resource}::${action}`);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
return out;
|
|
96
|
-
}
|
|
97
50
|
//# sourceMappingURL=impersonation.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"impersonation.js","sourceRoot":"","sources":["../../src/impersonation.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"impersonation.js","sourceRoot":"","sources":["../../src/impersonation.ts"],"names":[],"mappings":";;;AAEA,uCAAgD;AAwBhD;;;;;;;;;;;;GAYG;AACH,wBAA+B,IAAgC;IAC7D,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,cAAc,EAAE,EAAE,EAAE,GAAG,IAAI,CAAC;IAEhE,MAAM,YAAY,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IACvE,IAAI,YAAY,EAAE,CAAC;QACjB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;IAC5E,CAAC;IAED,2EAA2E;IAC3E,0EAA0E;IAC1E,MAAM,eAAe,GAAG,CAAC,KAAe,EAAE,EAAE;QAC1C,IAAI,CAAC;YACH,OAAO,IAAA,6BAAmB,EAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QACxC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,GAAG,EAAU,CAAC;QAC3B,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,WAAW,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;IACjD,MAAM,aAAa,GAAG,eAAe,CAAC,aAAa,CAAC,CAAC;IAErD,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7B,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,sBAAsB,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QAC1E,CAAC;IACH,CAAC;IAED,4EAA4E;IAC5E,4EAA4E;IAC5E,yEAAyE;IACzE,sBAAsB;IACtB,IAAI,WAAW,CAAC,IAAI,GAAG,CAAC,IAAI,WAAW,CAAC,IAAI,KAAK,aAAa,CAAC,IAAI,EAAE,CAAC;QACpE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,sBAAsB,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC;IACxF,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC3B,CAAC"}
|
package/lib/cjs/util.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AccessControl } from 'accesscontrol';
|
|
1
2
|
/**
|
|
2
3
|
* Recursively unwinds and combines grants for a given role, including inherited roles.
|
|
3
4
|
*
|
|
@@ -30,4 +31,23 @@ export declare const _combineGrants: (...grants: {
|
|
|
30
31
|
}[]) => {
|
|
31
32
|
[key: string]: any;
|
|
32
33
|
};
|
|
34
|
+
/**
|
|
35
|
+
* Flat set of `"resource::action"` strings covering everything the union of
|
|
36
|
+
* `roles` is permitted to do, `$extend` chains included.
|
|
37
|
+
*
|
|
38
|
+
* Used by the impersonation check ( an impersonator must be strictly more
|
|
39
|
+
* privileged than their target ) to compare role sets by plain set inclusion.
|
|
40
|
+
* Also available to an `AccessTokenRolePolicy` implementation ( see
|
|
41
|
+
* `@spinajs/rbac-http-token` ) that wants to permit a token role by comparing
|
|
42
|
+
* permission sets rather than role names - the shipped default policy does
|
|
43
|
+
* not do this, it compares `owner.Role` directly and never touches
|
|
44
|
+
* `AccessControl`, but an application's own policy is free to.
|
|
45
|
+
*
|
|
46
|
+
* Resources are not enumerable through the `can()` API, so they are read from
|
|
47
|
+
* the raw grants map by walking every `$extend` edge reachable from `roles`.
|
|
48
|
+
*
|
|
49
|
+
* @param ac - the AccessControl instance holding the application's grants
|
|
50
|
+
* @param roles - role names; unknown names contribute nothing
|
|
51
|
+
*/
|
|
52
|
+
export declare const _collectPermissions: (ac: AccessControl, roles: string[]) => Set<string>;
|
|
33
53
|
//# sourceMappingURL=util.d.ts.map
|
package/lib/cjs/util.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../src/util.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../src/util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AA8B9C;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,aAAa,SAAU,MAAM,UAAU;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,SAAQ,GAAG,CAAC,MAAM,CAAC;;CAiB5F,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,cAAc,cAAe;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,EAAE;;CAEjE,CAAA;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,mBAAmB,OAAQ,aAAa,SAAS,MAAM,EAAE,KAAG,GAAG,CAAC,MAAM,CAkDlF,CAAC"}
|
package/lib/cjs/util.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports._combineGrants = exports._unwindGrants = void 0;
|
|
3
|
+
exports._collectPermissions = exports._combineGrants = exports._unwindGrants = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* Merges a grants fragment into an accumulator, one resource at a time.
|
|
6
6
|
*
|
|
@@ -64,4 +64,68 @@ const _combineGrants = (...grants) => {
|
|
|
64
64
|
return grants.reduce((acc, g) => _mergeResourceGrants(acc, g), {});
|
|
65
65
|
};
|
|
66
66
|
exports._combineGrants = _combineGrants;
|
|
67
|
+
/**
|
|
68
|
+
* Flat set of `"resource::action"` strings covering everything the union of
|
|
69
|
+
* `roles` is permitted to do, `$extend` chains included.
|
|
70
|
+
*
|
|
71
|
+
* Used by the impersonation check ( an impersonator must be strictly more
|
|
72
|
+
* privileged than their target ) to compare role sets by plain set inclusion.
|
|
73
|
+
* Also available to an `AccessTokenRolePolicy` implementation ( see
|
|
74
|
+
* `@spinajs/rbac-http-token` ) that wants to permit a token role by comparing
|
|
75
|
+
* permission sets rather than role names - the shipped default policy does
|
|
76
|
+
* not do this, it compares `owner.Role` directly and never touches
|
|
77
|
+
* `AccessControl`, but an application's own policy is free to.
|
|
78
|
+
*
|
|
79
|
+
* Resources are not enumerable through the `can()` API, so they are read from
|
|
80
|
+
* the raw grants map by walking every `$extend` edge reachable from `roles`.
|
|
81
|
+
*
|
|
82
|
+
* @param ac - the AccessControl instance holding the application's grants
|
|
83
|
+
* @param roles - role names; unknown names contribute nothing
|
|
84
|
+
*/
|
|
85
|
+
const _collectPermissions = (ac, roles) => {
|
|
86
|
+
const out = new Set();
|
|
87
|
+
if (roles.length === 0) {
|
|
88
|
+
return out;
|
|
89
|
+
}
|
|
90
|
+
const grants = ac.getGrants();
|
|
91
|
+
const actions = [
|
|
92
|
+
'createAny', 'createOwn', 'readAny', 'readOwn', 'updateAny', 'updateOwn', 'deleteAny', 'deleteOwn',
|
|
93
|
+
];
|
|
94
|
+
const visited = new Set();
|
|
95
|
+
const stack = [...roles];
|
|
96
|
+
const resources = new Set();
|
|
97
|
+
while (stack.length) {
|
|
98
|
+
const role = stack.pop();
|
|
99
|
+
if (visited.has(role)) {
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
visited.add(role);
|
|
103
|
+
const roleGrants = grants[role];
|
|
104
|
+
if (!roleGrants) {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
for (const key of Object.keys(roleGrants)) {
|
|
108
|
+
if (key === '$extend') {
|
|
109
|
+
for (const inherited of roleGrants[key]) {
|
|
110
|
+
stack.push(inherited);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
resources.add(key);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
for (const resource of resources) {
|
|
119
|
+
for (const action of actions) {
|
|
120
|
+
// `ac.can(roles)[action](resource).granted` is true when ANY of the
|
|
121
|
+
// roles - or their `$extend` chain - grants it, which is exactly the
|
|
122
|
+
// union this function reports.
|
|
123
|
+
if (ac.can(roles)[action](resource).granted) {
|
|
124
|
+
out.add(`${resource}::${action}`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return out;
|
|
129
|
+
};
|
|
130
|
+
exports._collectPermissions = _collectPermissions;
|
|
67
131
|
//# sourceMappingURL=util.js.map
|
package/lib/cjs/util.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.js","sourceRoot":"","sources":["../../src/util.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../../src/util.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"impersonation.d.ts","sourceRoot":"","sources":["../../src/impersonation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"impersonation.d.ts","sourceRoot":"","sources":["../../src/impersonation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAI9C,MAAM,MAAM,yBAAyB,GAAG,gBAAgB,GAAG,sBAAsB,GAAG,aAAa,CAAC;AAElG,MAAM,WAAW,0BAA0B;IACzC,iDAAiD;IACjD,aAAa,EAAE,MAAM,EAAE,CAAC;IAExB,+BAA+B;IAC/B,WAAW,EAAE,MAAM,EAAE,CAAC;IAEtB,iEAAiE;IACjE,cAAc,EAAE,MAAM,EAAE,CAAC;IAEzB,gEAAgE;IAChE,EAAE,EAAE,aAAa,CAAC;CACnB;AAED,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,yBAAyB,CAAC;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,0BAA0B,GAAG,yBAAyB,CAoC1F"}
|
package/lib/mjs/impersonation.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { _collectPermissions } from './util.js';
|
|
1
2
|
/**
|
|
2
3
|
* Decides whether `originalRoles` may impersonate a user with `targetRoles`.
|
|
3
4
|
*
|
|
@@ -21,7 +22,7 @@ export function canImpersonate(opts) {
|
|
|
21
22
|
// (e.g. orphaned data) don't crash the check — treat them as 'no grants'.
|
|
22
23
|
const safePermissions = (roles) => {
|
|
23
24
|
try {
|
|
24
|
-
return
|
|
25
|
+
return _collectPermissions(ac, roles);
|
|
25
26
|
}
|
|
26
27
|
catch {
|
|
27
28
|
return new Set();
|
|
@@ -43,52 +44,4 @@ export function canImpersonate(opts) {
|
|
|
43
44
|
}
|
|
44
45
|
return { allowed: true };
|
|
45
46
|
}
|
|
46
|
-
/**
|
|
47
|
-
* Build a flat set of "resource::action" strings representing every permission
|
|
48
|
-
* granted to the union of `roles`. Used so we can compare two role sets by
|
|
49
|
-
* simple set inclusion.
|
|
50
|
-
*/
|
|
51
|
-
function collectPermissions(ac, roles) {
|
|
52
|
-
const out = new Set();
|
|
53
|
-
if (roles.length === 0)
|
|
54
|
-
return out;
|
|
55
|
-
const grants = ac.getGrants();
|
|
56
|
-
const actions = [
|
|
57
|
-
'createAny', 'createOwn', 'readAny', 'readOwn', 'updateAny', 'updateOwn', 'deleteAny', 'deleteOwn',
|
|
58
|
-
];
|
|
59
|
-
// Resources are not enumerable directly via the can() API — read them from
|
|
60
|
-
// the raw grants map and walk every $extend chain reachable from `roles`.
|
|
61
|
-
const visited = new Set();
|
|
62
|
-
const stack = [...roles];
|
|
63
|
-
const resources = new Set();
|
|
64
|
-
while (stack.length) {
|
|
65
|
-
const role = stack.pop();
|
|
66
|
-
if (visited.has(role))
|
|
67
|
-
continue;
|
|
68
|
-
visited.add(role);
|
|
69
|
-
const roleGrants = grants[role];
|
|
70
|
-
if (!roleGrants)
|
|
71
|
-
continue;
|
|
72
|
-
for (const key of Object.keys(roleGrants)) {
|
|
73
|
-
if (key === '$extend') {
|
|
74
|
-
for (const inherited of roleGrants[key])
|
|
75
|
-
stack.push(inherited);
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
resources.add(key);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
for (const resource of resources) {
|
|
83
|
-
for (const action of actions) {
|
|
84
|
-
// ac.can(roles)[action](resource).granted is true if ANY of the roles
|
|
85
|
-
// (or their $extend chain) grants the action — exactly the "union of
|
|
86
|
-
// effective permissions" we want.
|
|
87
|
-
if (ac.can(roles)[action](resource).granted) {
|
|
88
|
-
out.add(`${resource}::${action}`);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
return out;
|
|
93
|
-
}
|
|
94
47
|
//# sourceMappingURL=impersonation.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"impersonation.js","sourceRoot":"","sources":["../../src/impersonation.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"impersonation.js","sourceRoot":"","sources":["../../src/impersonation.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAwBhD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,cAAc,CAAC,IAAgC;IAC7D,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,cAAc,EAAE,EAAE,EAAE,GAAG,IAAI,CAAC;IAEhE,MAAM,YAAY,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IACvE,IAAI,YAAY,EAAE,CAAC;QACjB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;IAC5E,CAAC;IAED,2EAA2E;IAC3E,0EAA0E;IAC1E,MAAM,eAAe,GAAG,CAAC,KAAe,EAAE,EAAE;QAC1C,IAAI,CAAC;YACH,OAAO,mBAAmB,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QACxC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,GAAG,EAAU,CAAC;QAC3B,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,WAAW,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;IACjD,MAAM,aAAa,GAAG,eAAe,CAAC,aAAa,CAAC,CAAC;IAErD,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7B,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,sBAAsB,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QAC1E,CAAC;IACH,CAAC;IAED,4EAA4E;IAC5E,4EAA4E;IAC5E,yEAAyE;IACzE,sBAAsB;IACtB,IAAI,WAAW,CAAC,IAAI,GAAG,CAAC,IAAI,WAAW,CAAC,IAAI,KAAK,aAAa,CAAC,IAAI,EAAE,CAAC;QACpE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,sBAAsB,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC;IACxF,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC3B,CAAC"}
|
package/lib/mjs/util.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AccessControl } from 'accesscontrol';
|
|
1
2
|
/**
|
|
2
3
|
* Recursively unwinds and combines grants for a given role, including inherited roles.
|
|
3
4
|
*
|
|
@@ -30,4 +31,23 @@ export declare const _combineGrants: (...grants: {
|
|
|
30
31
|
}[]) => {
|
|
31
32
|
[key: string]: any;
|
|
32
33
|
};
|
|
34
|
+
/**
|
|
35
|
+
* Flat set of `"resource::action"` strings covering everything the union of
|
|
36
|
+
* `roles` is permitted to do, `$extend` chains included.
|
|
37
|
+
*
|
|
38
|
+
* Used by the impersonation check ( an impersonator must be strictly more
|
|
39
|
+
* privileged than their target ) to compare role sets by plain set inclusion.
|
|
40
|
+
* Also available to an `AccessTokenRolePolicy` implementation ( see
|
|
41
|
+
* `@spinajs/rbac-http-token` ) that wants to permit a token role by comparing
|
|
42
|
+
* permission sets rather than role names - the shipped default policy does
|
|
43
|
+
* not do this, it compares `owner.Role` directly and never touches
|
|
44
|
+
* `AccessControl`, but an application's own policy is free to.
|
|
45
|
+
*
|
|
46
|
+
* Resources are not enumerable through the `can()` API, so they are read from
|
|
47
|
+
* the raw grants map by walking every `$extend` edge reachable from `roles`.
|
|
48
|
+
*
|
|
49
|
+
* @param ac - the AccessControl instance holding the application's grants
|
|
50
|
+
* @param roles - role names; unknown names contribute nothing
|
|
51
|
+
*/
|
|
52
|
+
export declare const _collectPermissions: (ac: AccessControl, roles: string[]) => Set<string>;
|
|
33
53
|
//# sourceMappingURL=util.d.ts.map
|
package/lib/mjs/util.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../src/util.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../src/util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AA8B9C;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,aAAa,SAAU,MAAM,UAAU;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,SAAQ,GAAG,CAAC,MAAM,CAAC;;CAiB5F,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,cAAc,cAAe;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CAAE,EAAE;;CAEjE,CAAA;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,mBAAmB,OAAQ,aAAa,SAAS,MAAM,EAAE,KAAG,GAAG,CAAC,MAAM,CAkDlF,CAAC"}
|
package/lib/mjs/util.js
CHANGED
|
@@ -59,4 +59,67 @@ export const _unwindGrants = (role, grants, seen = new Set()) => {
|
|
|
59
59
|
export const _combineGrants = (...grants) => {
|
|
60
60
|
return grants.reduce((acc, g) => _mergeResourceGrants(acc, g), {});
|
|
61
61
|
};
|
|
62
|
+
/**
|
|
63
|
+
* Flat set of `"resource::action"` strings covering everything the union of
|
|
64
|
+
* `roles` is permitted to do, `$extend` chains included.
|
|
65
|
+
*
|
|
66
|
+
* Used by the impersonation check ( an impersonator must be strictly more
|
|
67
|
+
* privileged than their target ) to compare role sets by plain set inclusion.
|
|
68
|
+
* Also available to an `AccessTokenRolePolicy` implementation ( see
|
|
69
|
+
* `@spinajs/rbac-http-token` ) that wants to permit a token role by comparing
|
|
70
|
+
* permission sets rather than role names - the shipped default policy does
|
|
71
|
+
* not do this, it compares `owner.Role` directly and never touches
|
|
72
|
+
* `AccessControl`, but an application's own policy is free to.
|
|
73
|
+
*
|
|
74
|
+
* Resources are not enumerable through the `can()` API, so they are read from
|
|
75
|
+
* the raw grants map by walking every `$extend` edge reachable from `roles`.
|
|
76
|
+
*
|
|
77
|
+
* @param ac - the AccessControl instance holding the application's grants
|
|
78
|
+
* @param roles - role names; unknown names contribute nothing
|
|
79
|
+
*/
|
|
80
|
+
export const _collectPermissions = (ac, roles) => {
|
|
81
|
+
const out = new Set();
|
|
82
|
+
if (roles.length === 0) {
|
|
83
|
+
return out;
|
|
84
|
+
}
|
|
85
|
+
const grants = ac.getGrants();
|
|
86
|
+
const actions = [
|
|
87
|
+
'createAny', 'createOwn', 'readAny', 'readOwn', 'updateAny', 'updateOwn', 'deleteAny', 'deleteOwn',
|
|
88
|
+
];
|
|
89
|
+
const visited = new Set();
|
|
90
|
+
const stack = [...roles];
|
|
91
|
+
const resources = new Set();
|
|
92
|
+
while (stack.length) {
|
|
93
|
+
const role = stack.pop();
|
|
94
|
+
if (visited.has(role)) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
visited.add(role);
|
|
98
|
+
const roleGrants = grants[role];
|
|
99
|
+
if (!roleGrants) {
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
for (const key of Object.keys(roleGrants)) {
|
|
103
|
+
if (key === '$extend') {
|
|
104
|
+
for (const inherited of roleGrants[key]) {
|
|
105
|
+
stack.push(inherited);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
resources.add(key);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
for (const resource of resources) {
|
|
114
|
+
for (const action of actions) {
|
|
115
|
+
// `ac.can(roles)[action](resource).granted` is true when ANY of the
|
|
116
|
+
// roles - or their `$extend` chain - grants it, which is exactly the
|
|
117
|
+
// union this function reports.
|
|
118
|
+
if (ac.can(roles)[action](resource).granted) {
|
|
119
|
+
out.add(`${resource}::${action}`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return out;
|
|
124
|
+
};
|
|
62
125
|
//# sourceMappingURL=util.js.map
|
package/lib/mjs/util.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.js","sourceRoot":"","sources":["../../src/util.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../../src/util.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;GAaG;AACH,MAAM,oBAAoB,GAAG,CAAC,IAA4B,EAAE,GAA2B,EAAE,EAAE;IACvF,MAAM,MAAM,GAAG,EAAE,GAAG,IAAI,EAAE,CAAC;IAE3B,KAAK,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACpD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YACzB,SAAS;QACb,CAAC;QAED,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,OAAO,EAAE,CAAC;IACnE,CAAC;IAED,OAAO,MAAM,CAAC;AAClB,CAAC,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,IAAY,EAAE,MAA8B,EAAE,IAAI,GAAgB,IAAI,GAAG,EAAE,EAAE,EAAE;IACzG,qFAAqF;IACrF,+DAA+D;IAC/D,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QACjB,OAAO,EAAE,CAAC;IACd,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAEf,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IACtC,MAAM,cAAc,GAAG,UAAU,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;IAEnD,MAAM,SAAS,GAAG,cAAc,CAAC,MAAM,CACnC,CAAC,GAAQ,EAAE,aAAkB,EAAE,EAAE,CAAC,oBAAoB,CAAC,GAAG,EAAE,aAAa,CAAC,aAAa,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,EACvG,EAAE,CACL,CAAC;IAEF,OAAO,oBAAoB,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;AACvD,CAAC,CAAA;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,GAAG,MAAgC,EAAE,EAAE;IAClE,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,oBAAoB,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACvE,CAAC,CAAA;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,EAAiB,EAAE,KAAe,EAAe,EAAE;IACnF,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO,GAAG,CAAC;IACf,CAAC;IAED,MAAM,MAAM,GAAG,EAAE,CAAC,SAAS,EAAE,CAAC;IAC9B,MAAM,OAAO,GAAqH;QAC9H,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW;KACrG,CAAC;IAEF,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,MAAM,KAAK,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC;IACzB,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;IAEpC,OAAO,KAAK,CAAC,MAAM,EAAE,CAAC;QAClB,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,EAAG,CAAC;QAC1B,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACpB,SAAS;QACb,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAElB,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;QAChC,IAAI,CAAC,UAAU,EAAE,CAAC;YACd,SAAS;QACb,CAAC;QAED,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;YACxC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;gBACpB,KAAK,MAAM,SAAS,IAAI,UAAU,CAAC,GAAG,CAAwB,EAAE,CAAC;oBAC7D,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBAC1B,CAAC;YACL,CAAC;iBAAM,CAAC;gBACJ,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACvB,CAAC;QACL,CAAC;IACL,CAAC;IAED,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QAC/B,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC3B,oEAAoE;YACpE,qEAAqE;YACrE,+BAA+B;YAC/B,IAAK,EAAE,CAAC,GAAG,CAAC,KAAK,CAAS,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,CAAC;gBACnD,GAAG,CAAC,GAAG,CAAC,GAAG,QAAQ,KAAK,MAAM,EAAE,CAAC,CAAC;YACtC,CAAC;QACL,CAAC;IACL,CAAC;IAED,OAAO,GAAG,CAAC;AACf,CAAC,CAAC"}
|