@spinajs/rbac 2.0.474 → 2.0.475
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/config/rbac.d.ts +0 -35
- package/lib/cjs/config/rbac.d.ts.map +1 -1
- package/lib/cjs/config/rbac.js +0 -31
- package/lib/cjs/config/rbac.js.map +1 -1
- package/lib/cjs/events/index.d.ts +0 -2
- package/lib/cjs/events/index.d.ts.map +1 -1
- package/lib/cjs/events/index.js +0 -2
- package/lib/cjs/events/index.js.map +1 -1
- package/lib/cjs/index.d.ts +0 -1
- package/lib/cjs/index.d.ts.map +1 -1
- package/lib/cjs/index.js +0 -1
- package/lib/cjs/index.js.map +1 -1
- package/lib/cjs/interfaces.d.ts +0 -12
- package/lib/cjs/interfaces.d.ts.map +1 -1
- package/lib/cjs/middleware.d.ts +0 -2
- package/lib/cjs/middleware.d.ts.map +1 -1
- package/lib/cjs/middleware.js +75 -51
- package/lib/cjs/middleware.js.map +1 -1
- package/lib/cjs/models/User.d.ts.map +1 -1
- package/lib/cjs/models/User.js.map +1 -1
- package/lib/mjs/config/rbac.d.ts +0 -35
- package/lib/mjs/config/rbac.d.ts.map +1 -1
- package/lib/mjs/config/rbac.js +0 -31
- package/lib/mjs/config/rbac.js.map +1 -1
- package/lib/mjs/events/index.d.ts +0 -2
- package/lib/mjs/events/index.d.ts.map +1 -1
- package/lib/mjs/events/index.js +0 -2
- package/lib/mjs/events/index.js.map +1 -1
- package/lib/mjs/index.d.ts +0 -1
- package/lib/mjs/index.d.ts.map +1 -1
- package/lib/mjs/index.js +0 -1
- package/lib/mjs/index.js.map +1 -1
- package/lib/mjs/interfaces.d.ts +0 -12
- package/lib/mjs/interfaces.d.ts.map +1 -1
- package/lib/mjs/middleware.d.ts +0 -2
- package/lib/mjs/middleware.d.ts.map +1 -1
- package/lib/mjs/middleware.js +76 -52
- package/lib/mjs/middleware.js.map +1 -1
- package/lib/mjs/models/User.d.ts.map +1 -1
- package/lib/mjs/models/User.js.map +1 -1
- package/lib/tsconfig.cjs.tsbuildinfo +1 -1
- package/lib/tsconfig.mjs.tsbuildinfo +1 -1
- package/package.json +11 -11
- package/lib/cjs/events/UserImpersonationEnded.d.ts +0 -12
- package/lib/cjs/events/UserImpersonationEnded.d.ts.map +0 -1
- package/lib/cjs/events/UserImpersonationEnded.js +0 -32
- package/lib/cjs/events/UserImpersonationEnded.js.map +0 -1
- package/lib/cjs/events/UserImpersonationStarted.d.ts +0 -12
- package/lib/cjs/events/UserImpersonationStarted.d.ts.map +0 -1
- package/lib/cjs/events/UserImpersonationStarted.js +0 -32
- package/lib/cjs/events/UserImpersonationStarted.js.map +0 -1
- package/lib/cjs/impersonation.d.ts +0 -32
- package/lib/cjs/impersonation.d.ts.map +0 -1
- package/lib/cjs/impersonation.js +0 -97
- package/lib/cjs/impersonation.js.map +0 -1
- package/lib/mjs/events/UserImpersonationEnded.d.ts +0 -12
- package/lib/mjs/events/UserImpersonationEnded.d.ts.map +0 -1
- package/lib/mjs/events/UserImpersonationEnded.js +0 -29
- package/lib/mjs/events/UserImpersonationEnded.js.map +0 -1
- package/lib/mjs/events/UserImpersonationStarted.d.ts +0 -12
- package/lib/mjs/events/UserImpersonationStarted.d.ts.map +0 -1
- package/lib/mjs/events/UserImpersonationStarted.js +0 -29
- package/lib/mjs/events/UserImpersonationStarted.js.map +0 -1
- package/lib/mjs/impersonation.d.ts +0 -32
- package/lib/mjs/impersonation.d.ts.map +0 -1
- package/lib/mjs/impersonation.js +0 -94
- package/lib/mjs/impersonation.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spinajs/rbac",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.475",
|
|
4
4
|
"description": "Role and Attribute based Access Control for SpinaJS framework",
|
|
5
5
|
"main": "lib/cjs/index.js",
|
|
6
6
|
"module": "lib/mjs/index.js",
|
|
@@ -47,15 +47,15 @@
|
|
|
47
47
|
},
|
|
48
48
|
"homepage": "https://github.com/spinajs/main#readme",
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@spinajs/configuration": "^2.0.
|
|
51
|
-
"@spinajs/di": "^2.0.
|
|
52
|
-
"@spinajs/exceptions": "^2.0.
|
|
53
|
-
"@spinajs/log": "^2.0.
|
|
54
|
-
"@spinajs/orm": "^2.0.
|
|
55
|
-
"@spinajs/queue": "^2.0.
|
|
56
|
-
"@spinajs/reflection": "^2.0.
|
|
57
|
-
"@spinajs/util": "^2.0.
|
|
58
|
-
"@spinajs/validation": "^2.0.
|
|
50
|
+
"@spinajs/configuration": "^2.0.475",
|
|
51
|
+
"@spinajs/di": "^2.0.475",
|
|
52
|
+
"@spinajs/exceptions": "^2.0.475",
|
|
53
|
+
"@spinajs/log": "^2.0.475",
|
|
54
|
+
"@spinajs/orm": "^2.0.475",
|
|
55
|
+
"@spinajs/queue": "^2.0.475",
|
|
56
|
+
"@spinajs/reflection": "^2.0.475",
|
|
57
|
+
"@spinajs/util": "^2.0.475",
|
|
58
|
+
"@spinajs/validation": "^2.0.475",
|
|
59
59
|
"accesscontrol": "^2.2.1",
|
|
60
60
|
"argon2": "^0.44.0",
|
|
61
61
|
"cron": "^2.2.0",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"uuid": "^9.0.0"
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
|
68
|
-
"@spinajs/orm-sqlite": "^2.0.
|
|
68
|
+
"@spinajs/orm-sqlite": "^2.0.475",
|
|
69
69
|
"@types/cron": "^2.0.0",
|
|
70
70
|
"@types/entropy-string": "^4.2.0"
|
|
71
71
|
},
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { UserEvent } from './UserEvent.js';
|
|
2
|
-
import { User } from '../models/User.js';
|
|
3
|
-
/**
|
|
4
|
-
* Emitted when an active impersonation ends (explicit stop, logout while
|
|
5
|
-
* impersonating, or session expiry handling). UserUUID is the impersonator
|
|
6
|
-
* who initiated the impersonation; TargetUUID is whoever they were acting as.
|
|
7
|
-
*/
|
|
8
|
-
export declare class UserImpersonationEnded extends UserEvent {
|
|
9
|
-
TargetUUID: string;
|
|
10
|
-
constructor(original: User, target: User);
|
|
11
|
-
}
|
|
12
|
-
//# sourceMappingURL=UserImpersonationEnded.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"UserImpersonationEnded.d.ts","sourceRoot":"","sources":["../../../src/events/UserImpersonationEnded.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAEzC;;;;GAIG;AACH,qBACa,sBAAuB,SAAQ,SAAS;IAC5C,UAAU,EAAE,MAAM,CAAC;gBAEd,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI;CAIzC"}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
-
};
|
|
8
|
-
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
-
};
|
|
11
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.UserImpersonationEnded = void 0;
|
|
13
|
-
const queue_1 = require("@spinajs/queue");
|
|
14
|
-
const UserEvent_js_1 = require("./UserEvent.js");
|
|
15
|
-
const User_js_1 = require("../models/User.js");
|
|
16
|
-
/**
|
|
17
|
-
* Emitted when an active impersonation ends (explicit stop, logout while
|
|
18
|
-
* impersonating, or session expiry handling). UserUUID is the impersonator
|
|
19
|
-
* who initiated the impersonation; TargetUUID is whoever they were acting as.
|
|
20
|
-
*/
|
|
21
|
-
let UserImpersonationEnded = class UserImpersonationEnded extends UserEvent_js_1.UserEvent {
|
|
22
|
-
constructor(original, target) {
|
|
23
|
-
super(original);
|
|
24
|
-
this.TargetUUID = target.Uuid;
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
exports.UserImpersonationEnded = UserImpersonationEnded;
|
|
28
|
-
exports.UserImpersonationEnded = UserImpersonationEnded = __decorate([
|
|
29
|
-
(0, queue_1.Event)(),
|
|
30
|
-
__metadata("design:paramtypes", [User_js_1.User, User_js_1.User])
|
|
31
|
-
], UserImpersonationEnded);
|
|
32
|
-
//# sourceMappingURL=UserImpersonationEnded.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"UserImpersonationEnded.js","sourceRoot":"","sources":["../../../src/events/UserImpersonationEnded.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,0CAAuC;AACvC,iDAA2C;AAC3C,+CAAyC;AAEzC;;;;GAIG;AAEI,IAAM,sBAAsB,GAA5B,MAAM,sBAAuB,SAAQ,wBAAS;IAGnD,YAAY,QAAc,EAAE,MAAY;QACtC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAChB,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC;IAChC,CAAC;CACF,CAAA;AAPY,wDAAsB;iCAAtB,sBAAsB;IADlC,IAAA,aAAK,GAAE;qCAIgB,cAAI,EAAU,cAAI;GAH7B,sBAAsB,CAOlC"}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { UserEvent } from './UserEvent.js';
|
|
2
|
-
import { User } from '../models/User.js';
|
|
3
|
-
/**
|
|
4
|
-
* Emitted when `original` starts impersonating `target`. UserUUID (from the
|
|
5
|
-
* base class) holds the impersonator's UUID — the actor who triggered the
|
|
6
|
-
* event — and TargetUUID holds whoever they impersonated.
|
|
7
|
-
*/
|
|
8
|
-
export declare class UserImpersonationStarted extends UserEvent {
|
|
9
|
-
TargetUUID: string;
|
|
10
|
-
constructor(original: User, target: User);
|
|
11
|
-
}
|
|
12
|
-
//# sourceMappingURL=UserImpersonationStarted.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"UserImpersonationStarted.d.ts","sourceRoot":"","sources":["../../../src/events/UserImpersonationStarted.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAEzC;;;;GAIG;AACH,qBACa,wBAAyB,SAAQ,SAAS;IAC9C,UAAU,EAAE,MAAM,CAAC;gBAEd,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI;CAIzC"}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
-
};
|
|
8
|
-
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
-
};
|
|
11
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.UserImpersonationStarted = void 0;
|
|
13
|
-
const queue_1 = require("@spinajs/queue");
|
|
14
|
-
const UserEvent_js_1 = require("./UserEvent.js");
|
|
15
|
-
const User_js_1 = require("../models/User.js");
|
|
16
|
-
/**
|
|
17
|
-
* Emitted when `original` starts impersonating `target`. UserUUID (from the
|
|
18
|
-
* base class) holds the impersonator's UUID — the actor who triggered the
|
|
19
|
-
* event — and TargetUUID holds whoever they impersonated.
|
|
20
|
-
*/
|
|
21
|
-
let UserImpersonationStarted = class UserImpersonationStarted extends UserEvent_js_1.UserEvent {
|
|
22
|
-
constructor(original, target) {
|
|
23
|
-
super(original);
|
|
24
|
-
this.TargetUUID = target.Uuid;
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
exports.UserImpersonationStarted = UserImpersonationStarted;
|
|
28
|
-
exports.UserImpersonationStarted = UserImpersonationStarted = __decorate([
|
|
29
|
-
(0, queue_1.Event)(),
|
|
30
|
-
__metadata("design:paramtypes", [User_js_1.User, User_js_1.User])
|
|
31
|
-
], UserImpersonationStarted);
|
|
32
|
-
//# sourceMappingURL=UserImpersonationStarted.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"UserImpersonationStarted.js","sourceRoot":"","sources":["../../../src/events/UserImpersonationStarted.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,0CAAuC;AACvC,iDAA2C;AAC3C,+CAAyC;AAEzC;;;;GAIG;AAEI,IAAM,wBAAwB,GAA9B,MAAM,wBAAyB,SAAQ,wBAAS;IAGrD,YAAY,QAAc,EAAE,MAAY;QACtC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAChB,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC;IAChC,CAAC;CACF,CAAA;AAPY,4DAAwB;mCAAxB,wBAAwB;IADpC,IAAA,aAAK,GAAE;qCAIgB,cAAI,EAAU,cAAI;GAH7B,wBAAwB,CAOpC"}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { AccessControl } from 'accesscontrol';
|
|
2
|
-
export type ImpersonationDenialReason = 'PROTECTED_ROLE' | 'PRIVILEGE_ESCALATION' | 'SELF_TARGET';
|
|
3
|
-
export interface IImpersonationCheckOptions {
|
|
4
|
-
/** Roles of the user who wants to impersonate */
|
|
5
|
-
originalRoles: string[];
|
|
6
|
-
/** Roles of the target user */
|
|
7
|
-
targetRoles: string[];
|
|
8
|
-
/** Roles that may never be impersonated (default: ['system']) */
|
|
9
|
-
protectedRoles: string[];
|
|
10
|
-
/** AccessControl instance — used to compare effective grants */
|
|
11
|
-
ac: AccessControl;
|
|
12
|
-
}
|
|
13
|
-
export interface IImpersonationCheckResult {
|
|
14
|
-
allowed: boolean;
|
|
15
|
-
reason?: ImpersonationDenialReason;
|
|
16
|
-
detail?: string;
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Decides whether `originalRoles` may impersonate a user with `targetRoles`.
|
|
20
|
-
*
|
|
21
|
-
* Rules:
|
|
22
|
-
* 1. If target has any role in `protectedRoles` → denied (PROTECTED_ROLE).
|
|
23
|
-
* 2. If target has any effective grant the original does NOT have, that's an
|
|
24
|
-
* escalation and impersonation is denied (PRIVILEGE_ESCALATION). This
|
|
25
|
-
* blocks equal-or-higher targets — admin cannot impersonate admin, user
|
|
26
|
-
* cannot impersonate admin, but admin can impersonate user.
|
|
27
|
-
*
|
|
28
|
-
* The grant comparison walks accesscontrol's resolved grants, so $extend is
|
|
29
|
-
* honored transitively.
|
|
30
|
-
*/
|
|
31
|
-
export declare function canImpersonate(opts: IImpersonationCheckOptions): IImpersonationCheckResult;
|
|
32
|
-
//# sourceMappingURL=impersonation.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"impersonation.d.ts","sourceRoot":"","sources":["../../src/impersonation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,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
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.canImpersonate = canImpersonate;
|
|
4
|
-
/**
|
|
5
|
-
* Decides whether `originalRoles` may impersonate a user with `targetRoles`.
|
|
6
|
-
*
|
|
7
|
-
* Rules:
|
|
8
|
-
* 1. If target has any role in `protectedRoles` → denied (PROTECTED_ROLE).
|
|
9
|
-
* 2. If target has any effective grant the original does NOT have, that's an
|
|
10
|
-
* escalation and impersonation is denied (PRIVILEGE_ESCALATION). This
|
|
11
|
-
* blocks equal-or-higher targets — admin cannot impersonate admin, user
|
|
12
|
-
* cannot impersonate admin, but admin can impersonate user.
|
|
13
|
-
*
|
|
14
|
-
* The grant comparison walks accesscontrol's resolved grants, so $extend is
|
|
15
|
-
* honored transitively.
|
|
16
|
-
*/
|
|
17
|
-
function canImpersonate(opts) {
|
|
18
|
-
const { originalRoles, targetRoles, protectedRoles, ac } = opts;
|
|
19
|
-
const protectedHit = targetRoles.find(r => protectedRoles.includes(r));
|
|
20
|
-
if (protectedHit) {
|
|
21
|
-
return { allowed: false, reason: 'PROTECTED_ROLE', detail: protectedHit };
|
|
22
|
-
}
|
|
23
|
-
// accesscontrol throws if a role is unknown; guard so unknown target roles
|
|
24
|
-
// (e.g. orphaned data) don't crash the check — treat them as 'no grants'.
|
|
25
|
-
const safePermissions = (roles) => {
|
|
26
|
-
try {
|
|
27
|
-
return collectPermissions(ac, roles);
|
|
28
|
-
}
|
|
29
|
-
catch {
|
|
30
|
-
return new Set();
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
const targetPerms = safePermissions(targetRoles);
|
|
34
|
-
const originalPerms = safePermissions(originalRoles);
|
|
35
|
-
for (const perm of targetPerms) {
|
|
36
|
-
if (!originalPerms.has(perm)) {
|
|
37
|
-
return { allowed: false, reason: 'PRIVILEGE_ESCALATION', detail: perm };
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
// Equal privileges count as escalation per the spec: an impersonator should
|
|
41
|
-
// be strictly more privileged than the target. If target has no role at all
|
|
42
|
-
// (empty grants) we still allow — impersonating a permissionless user is
|
|
43
|
-
// safe by definition.
|
|
44
|
-
if (targetPerms.size > 0 && targetPerms.size === originalPerms.size) {
|
|
45
|
-
return { allowed: false, reason: 'PRIVILEGE_ESCALATION', detail: 'equal privileges' };
|
|
46
|
-
}
|
|
47
|
-
return { allowed: true };
|
|
48
|
-
}
|
|
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
|
-
//# sourceMappingURL=impersonation.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"impersonation.js","sourceRoot":"","sources":["../../src/impersonation.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { UserEvent } from './UserEvent.js';
|
|
2
|
-
import { User } from '../models/User.js';
|
|
3
|
-
/**
|
|
4
|
-
* Emitted when an active impersonation ends (explicit stop, logout while
|
|
5
|
-
* impersonating, or session expiry handling). UserUUID is the impersonator
|
|
6
|
-
* who initiated the impersonation; TargetUUID is whoever they were acting as.
|
|
7
|
-
*/
|
|
8
|
-
export declare class UserImpersonationEnded extends UserEvent {
|
|
9
|
-
TargetUUID: string;
|
|
10
|
-
constructor(original: User, target: User);
|
|
11
|
-
}
|
|
12
|
-
//# sourceMappingURL=UserImpersonationEnded.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"UserImpersonationEnded.d.ts","sourceRoot":"","sources":["../../../src/events/UserImpersonationEnded.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAEzC;;;;GAIG;AACH,qBACa,sBAAuB,SAAQ,SAAS;IAC5C,UAAU,EAAE,MAAM,CAAC;gBAEd,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI;CAIzC"}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
-
};
|
|
7
|
-
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
-
};
|
|
10
|
-
import { Event } from '@spinajs/queue';
|
|
11
|
-
import { UserEvent } from './UserEvent.js';
|
|
12
|
-
import { User } from '../models/User.js';
|
|
13
|
-
/**
|
|
14
|
-
* Emitted when an active impersonation ends (explicit stop, logout while
|
|
15
|
-
* impersonating, or session expiry handling). UserUUID is the impersonator
|
|
16
|
-
* who initiated the impersonation; TargetUUID is whoever they were acting as.
|
|
17
|
-
*/
|
|
18
|
-
let UserImpersonationEnded = class UserImpersonationEnded extends UserEvent {
|
|
19
|
-
constructor(original, target) {
|
|
20
|
-
super(original);
|
|
21
|
-
this.TargetUUID = target.Uuid;
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
UserImpersonationEnded = __decorate([
|
|
25
|
-
Event(),
|
|
26
|
-
__metadata("design:paramtypes", [User, User])
|
|
27
|
-
], UserImpersonationEnded);
|
|
28
|
-
export { UserImpersonationEnded };
|
|
29
|
-
//# sourceMappingURL=UserImpersonationEnded.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"UserImpersonationEnded.js","sourceRoot":"","sources":["../../../src/events/UserImpersonationEnded.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAEzC;;;;GAIG;AAEI,IAAM,sBAAsB,GAA5B,MAAM,sBAAuB,SAAQ,SAAS;IAGnD,YAAY,QAAc,EAAE,MAAY;QACtC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAChB,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC;IAChC,CAAC;CACF,CAAA;AAPY,sBAAsB;IADlC,KAAK,EAAE;qCAIgB,IAAI,EAAU,IAAI;GAH7B,sBAAsB,CAOlC"}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { UserEvent } from './UserEvent.js';
|
|
2
|
-
import { User } from '../models/User.js';
|
|
3
|
-
/**
|
|
4
|
-
* Emitted when `original` starts impersonating `target`. UserUUID (from the
|
|
5
|
-
* base class) holds the impersonator's UUID — the actor who triggered the
|
|
6
|
-
* event — and TargetUUID holds whoever they impersonated.
|
|
7
|
-
*/
|
|
8
|
-
export declare class UserImpersonationStarted extends UserEvent {
|
|
9
|
-
TargetUUID: string;
|
|
10
|
-
constructor(original: User, target: User);
|
|
11
|
-
}
|
|
12
|
-
//# sourceMappingURL=UserImpersonationStarted.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"UserImpersonationStarted.d.ts","sourceRoot":"","sources":["../../../src/events/UserImpersonationStarted.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAEzC;;;;GAIG;AACH,qBACa,wBAAyB,SAAQ,SAAS;IAC9C,UAAU,EAAE,MAAM,CAAC;gBAEd,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI;CAIzC"}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
-
};
|
|
7
|
-
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
-
};
|
|
10
|
-
import { Event } from '@spinajs/queue';
|
|
11
|
-
import { UserEvent } from './UserEvent.js';
|
|
12
|
-
import { User } from '../models/User.js';
|
|
13
|
-
/**
|
|
14
|
-
* Emitted when `original` starts impersonating `target`. UserUUID (from the
|
|
15
|
-
* base class) holds the impersonator's UUID — the actor who triggered the
|
|
16
|
-
* event — and TargetUUID holds whoever they impersonated.
|
|
17
|
-
*/
|
|
18
|
-
let UserImpersonationStarted = class UserImpersonationStarted extends UserEvent {
|
|
19
|
-
constructor(original, target) {
|
|
20
|
-
super(original);
|
|
21
|
-
this.TargetUUID = target.Uuid;
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
UserImpersonationStarted = __decorate([
|
|
25
|
-
Event(),
|
|
26
|
-
__metadata("design:paramtypes", [User, User])
|
|
27
|
-
], UserImpersonationStarted);
|
|
28
|
-
export { UserImpersonationStarted };
|
|
29
|
-
//# sourceMappingURL=UserImpersonationStarted.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"UserImpersonationStarted.js","sourceRoot":"","sources":["../../../src/events/UserImpersonationStarted.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAEzC;;;;GAIG;AAEI,IAAM,wBAAwB,GAA9B,MAAM,wBAAyB,SAAQ,SAAS;IAGrD,YAAY,QAAc,EAAE,MAAY;QACtC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAChB,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC;IAChC,CAAC;CACF,CAAA;AAPY,wBAAwB;IADpC,KAAK,EAAE;qCAIgB,IAAI,EAAU,IAAI;GAH7B,wBAAwB,CAOpC"}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { AccessControl } from 'accesscontrol';
|
|
2
|
-
export type ImpersonationDenialReason = 'PROTECTED_ROLE' | 'PRIVILEGE_ESCALATION' | 'SELF_TARGET';
|
|
3
|
-
export interface IImpersonationCheckOptions {
|
|
4
|
-
/** Roles of the user who wants to impersonate */
|
|
5
|
-
originalRoles: string[];
|
|
6
|
-
/** Roles of the target user */
|
|
7
|
-
targetRoles: string[];
|
|
8
|
-
/** Roles that may never be impersonated (default: ['system']) */
|
|
9
|
-
protectedRoles: string[];
|
|
10
|
-
/** AccessControl instance — used to compare effective grants */
|
|
11
|
-
ac: AccessControl;
|
|
12
|
-
}
|
|
13
|
-
export interface IImpersonationCheckResult {
|
|
14
|
-
allowed: boolean;
|
|
15
|
-
reason?: ImpersonationDenialReason;
|
|
16
|
-
detail?: string;
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Decides whether `originalRoles` may impersonate a user with `targetRoles`.
|
|
20
|
-
*
|
|
21
|
-
* Rules:
|
|
22
|
-
* 1. If target has any role in `protectedRoles` → denied (PROTECTED_ROLE).
|
|
23
|
-
* 2. If target has any effective grant the original does NOT have, that's an
|
|
24
|
-
* escalation and impersonation is denied (PRIVILEGE_ESCALATION). This
|
|
25
|
-
* blocks equal-or-higher targets — admin cannot impersonate admin, user
|
|
26
|
-
* cannot impersonate admin, but admin can impersonate user.
|
|
27
|
-
*
|
|
28
|
-
* The grant comparison walks accesscontrol's resolved grants, so $extend is
|
|
29
|
-
* honored transitively.
|
|
30
|
-
*/
|
|
31
|
-
export declare function canImpersonate(opts: IImpersonationCheckOptions): IImpersonationCheckResult;
|
|
32
|
-
//# sourceMappingURL=impersonation.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"impersonation.d.ts","sourceRoot":"","sources":["../../src/impersonation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,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
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Decides whether `originalRoles` may impersonate a user with `targetRoles`.
|
|
3
|
-
*
|
|
4
|
-
* Rules:
|
|
5
|
-
* 1. If target has any role in `protectedRoles` → denied (PROTECTED_ROLE).
|
|
6
|
-
* 2. If target has any effective grant the original does NOT have, that's an
|
|
7
|
-
* escalation and impersonation is denied (PRIVILEGE_ESCALATION). This
|
|
8
|
-
* blocks equal-or-higher targets — admin cannot impersonate admin, user
|
|
9
|
-
* cannot impersonate admin, but admin can impersonate user.
|
|
10
|
-
*
|
|
11
|
-
* The grant comparison walks accesscontrol's resolved grants, so $extend is
|
|
12
|
-
* honored transitively.
|
|
13
|
-
*/
|
|
14
|
-
export function canImpersonate(opts) {
|
|
15
|
-
const { originalRoles, targetRoles, protectedRoles, ac } = opts;
|
|
16
|
-
const protectedHit = targetRoles.find(r => protectedRoles.includes(r));
|
|
17
|
-
if (protectedHit) {
|
|
18
|
-
return { allowed: false, reason: 'PROTECTED_ROLE', detail: protectedHit };
|
|
19
|
-
}
|
|
20
|
-
// accesscontrol throws if a role is unknown; guard so unknown target roles
|
|
21
|
-
// (e.g. orphaned data) don't crash the check — treat them as 'no grants'.
|
|
22
|
-
const safePermissions = (roles) => {
|
|
23
|
-
try {
|
|
24
|
-
return collectPermissions(ac, roles);
|
|
25
|
-
}
|
|
26
|
-
catch {
|
|
27
|
-
return new Set();
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
const targetPerms = safePermissions(targetRoles);
|
|
31
|
-
const originalPerms = safePermissions(originalRoles);
|
|
32
|
-
for (const perm of targetPerms) {
|
|
33
|
-
if (!originalPerms.has(perm)) {
|
|
34
|
-
return { allowed: false, reason: 'PRIVILEGE_ESCALATION', detail: perm };
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
// Equal privileges count as escalation per the spec: an impersonator should
|
|
38
|
-
// be strictly more privileged than the target. If target has no role at all
|
|
39
|
-
// (empty grants) we still allow — impersonating a permissionless user is
|
|
40
|
-
// safe by definition.
|
|
41
|
-
if (targetPerms.size > 0 && targetPerms.size === originalPerms.size) {
|
|
42
|
-
return { allowed: false, reason: 'PRIVILEGE_ESCALATION', detail: 'equal privileges' };
|
|
43
|
-
}
|
|
44
|
-
return { allowed: true };
|
|
45
|
-
}
|
|
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
|
-
//# sourceMappingURL=impersonation.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"impersonation.js","sourceRoot":"","sources":["../../src/impersonation.ts"],"names":[],"mappings":"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"}
|