@spinajs/rbac-http-user 2.0.486 → 2.0.487
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-http.d.ts +0 -15
- package/lib/cjs/config/rbac-http.d.ts.map +1 -1
- package/lib/cjs/config/rbac-http.js +6 -16
- package/lib/cjs/config/rbac-http.js.map +1 -1
- package/lib/cjs/controllers/ActiveRoleController.d.ts +2 -1
- package/lib/cjs/controllers/ActiveRoleController.d.ts.map +1 -1
- package/lib/cjs/controllers/ActiveRoleController.js +7 -17
- package/lib/cjs/controllers/ActiveRoleController.js.map +1 -1
- package/lib/cjs/controllers/ImpersonationController.d.ts +7 -9
- package/lib/cjs/controllers/ImpersonationController.d.ts.map +1 -1
- package/lib/cjs/controllers/ImpersonationController.js +31 -56
- package/lib/cjs/controllers/ImpersonationController.js.map +1 -1
- package/lib/cjs/controllers/LoginController.d.ts +10 -3
- package/lib/cjs/controllers/LoginController.d.ts.map +1 -1
- package/lib/cjs/controllers/LoginController.js +39 -40
- package/lib/cjs/controllers/LoginController.js.map +1 -1
- package/lib/cjs/controllers/PasswordResetController.d.ts +54 -0
- package/lib/cjs/controllers/PasswordResetController.d.ts.map +1 -0
- package/lib/cjs/controllers/PasswordResetController.js +129 -0
- package/lib/cjs/controllers/PasswordResetController.js.map +1 -0
- package/lib/cjs/controllers/SessionsController.d.ts +65 -0
- package/lib/cjs/controllers/SessionsController.d.ts.map +1 -0
- package/lib/cjs/controllers/SessionsController.js +143 -0
- package/lib/cjs/controllers/SessionsController.js.map +1 -0
- package/lib/cjs/controllers/TwoFactorAuthController.d.ts +24 -23
- package/lib/cjs/controllers/TwoFactorAuthController.d.ts.map +1 -1
- package/lib/cjs/controllers/TwoFactorAuthController.js +39 -72
- package/lib/cjs/controllers/TwoFactorAuthController.js.map +1 -1
- package/lib/cjs/controllers/TwoFactorAuthUserController.d.ts +98 -0
- package/lib/cjs/controllers/TwoFactorAuthUserController.d.ts.map +1 -0
- package/lib/cjs/controllers/TwoFactorAuthUserController.js +195 -0
- package/lib/cjs/controllers/TwoFactorAuthUserController.js.map +1 -0
- package/lib/cjs/controllers/UserController.d.ts +10 -7
- package/lib/cjs/controllers/UserController.d.ts.map +1 -1
- package/lib/cjs/controllers/UserController.js +56 -58
- package/lib/cjs/controllers/UserController.js.map +1 -1
- package/lib/cjs/controllers/UserMetadataController.d.ts +6 -12
- package/lib/cjs/controllers/UserMetadataController.d.ts.map +1 -1
- package/lib/cjs/controllers/UserMetadataController.js +23 -72
- package/lib/cjs/controllers/UserMetadataController.js.map +1 -1
- package/lib/cjs/dto/confirm-password-dto.d.ts +23 -0
- package/lib/cjs/dto/confirm-password-dto.d.ts.map +1 -0
- package/lib/cjs/dto/{restore-password-dto.js → confirm-password-dto.js} +16 -12
- package/lib/cjs/dto/confirm-password-dto.js.map +1 -0
- package/lib/cjs/dto/password-reset-dto.d.ts +58 -0
- package/lib/cjs/dto/password-reset-dto.d.ts.map +1 -0
- package/lib/cjs/dto/password-reset-dto.js +57 -0
- package/lib/cjs/dto/password-reset-dto.js.map +1 -0
- package/lib/cjs/handlers/DefaultLogoutHandler.d.ts +4 -1
- package/lib/cjs/handlers/DefaultLogoutHandler.d.ts.map +1 -1
- package/lib/cjs/handlers/DefaultLogoutHandler.js +20 -13
- package/lib/cjs/handlers/DefaultLogoutHandler.js.map +1 -1
- package/lib/cjs/handlers/ImpersonationLogoutHandler.d.ts +4 -7
- package/lib/cjs/handlers/ImpersonationLogoutHandler.d.ts.map +1 -1
- package/lib/cjs/handlers/ImpersonationLogoutHandler.js +30 -31
- package/lib/cjs/handlers/ImpersonationLogoutHandler.js.map +1 -1
- package/lib/cjs/index.d.ts +20 -0
- package/lib/cjs/index.d.ts.map +1 -1
- package/lib/cjs/index.js +22 -0
- package/lib/cjs/index.js.map +1 -1
- package/lib/cjs/logout.d.ts +7 -0
- package/lib/cjs/logout.d.ts.map +1 -1
- package/lib/cjs/logout.js.map +1 -1
- package/lib/cjs/policies/2FaPolicy.d.ts +21 -1
- package/lib/cjs/policies/2FaPolicy.d.ts.map +1 -1
- package/lib/cjs/policies/2FaPolicy.js +31 -7
- package/lib/cjs/policies/2FaPolicy.js.map +1 -1
- package/lib/cjs/services/ImpersonationService.d.ts +90 -0
- package/lib/cjs/services/ImpersonationService.d.ts.map +1 -0
- package/lib/cjs/services/ImpersonationService.js +147 -0
- package/lib/cjs/services/ImpersonationService.js.map +1 -0
- package/lib/cjs/services/SessionCookies.d.ts +41 -0
- package/lib/cjs/services/SessionCookies.d.ts.map +1 -0
- package/lib/cjs/services/SessionCookies.js +62 -0
- package/lib/cjs/services/SessionCookies.js.map +1 -0
- package/lib/cjs/services/UserMetadataService.d.ts +53 -0
- package/lib/cjs/services/UserMetadataService.d.ts.map +1 -0
- package/lib/cjs/services/UserMetadataService.js +94 -0
- package/lib/cjs/services/UserMetadataService.js.map +1 -0
- package/lib/cjs/services/grants.d.ts +29 -0
- package/lib/cjs/services/grants.d.ts.map +1 -0
- package/lib/cjs/services/grants.js +43 -0
- package/lib/cjs/services/grants.js.map +1 -0
- package/lib/mjs/config/rbac-http.d.ts +0 -15
- package/lib/mjs/config/rbac-http.d.ts.map +1 -1
- package/lib/mjs/config/rbac-http.js +6 -16
- package/lib/mjs/config/rbac-http.js.map +1 -1
- package/lib/mjs/controllers/ActiveRoleController.d.ts +2 -1
- package/lib/mjs/controllers/ActiveRoleController.d.ts.map +1 -1
- package/lib/mjs/controllers/ActiveRoleController.js +8 -18
- package/lib/mjs/controllers/ActiveRoleController.js.map +1 -1
- package/lib/mjs/controllers/ImpersonationController.d.ts +7 -9
- package/lib/mjs/controllers/ImpersonationController.d.ts.map +1 -1
- package/lib/mjs/controllers/ImpersonationController.js +32 -57
- package/lib/mjs/controllers/ImpersonationController.js.map +1 -1
- package/lib/mjs/controllers/LoginController.d.ts +10 -3
- package/lib/mjs/controllers/LoginController.d.ts.map +1 -1
- package/lib/mjs/controllers/LoginController.js +42 -43
- package/lib/mjs/controllers/LoginController.js.map +1 -1
- package/lib/mjs/controllers/PasswordResetController.d.ts +54 -0
- package/lib/mjs/controllers/PasswordResetController.d.ts.map +1 -0
- package/lib/mjs/controllers/PasswordResetController.js +126 -0
- package/lib/mjs/controllers/PasswordResetController.js.map +1 -0
- package/lib/mjs/controllers/SessionsController.d.ts +65 -0
- package/lib/mjs/controllers/SessionsController.d.ts.map +1 -0
- package/lib/mjs/controllers/SessionsController.js +140 -0
- package/lib/mjs/controllers/SessionsController.js.map +1 -0
- package/lib/mjs/controllers/TwoFactorAuthController.d.ts +24 -23
- package/lib/mjs/controllers/TwoFactorAuthController.d.ts.map +1 -1
- package/lib/mjs/controllers/TwoFactorAuthController.js +43 -76
- package/lib/mjs/controllers/TwoFactorAuthController.js.map +1 -1
- package/lib/mjs/controllers/TwoFactorAuthUserController.d.ts +98 -0
- package/lib/mjs/controllers/TwoFactorAuthUserController.d.ts.map +1 -0
- package/lib/mjs/controllers/TwoFactorAuthUserController.js +192 -0
- package/lib/mjs/controllers/TwoFactorAuthUserController.js.map +1 -0
- package/lib/mjs/controllers/UserController.d.ts +10 -7
- package/lib/mjs/controllers/UserController.d.ts.map +1 -1
- package/lib/mjs/controllers/UserController.js +59 -28
- package/lib/mjs/controllers/UserController.js.map +1 -1
- package/lib/mjs/controllers/UserMetadataController.d.ts +6 -12
- package/lib/mjs/controllers/UserMetadataController.d.ts.map +1 -1
- package/lib/mjs/controllers/UserMetadataController.js +23 -72
- package/lib/mjs/controllers/UserMetadataController.js.map +1 -1
- package/lib/mjs/dto/confirm-password-dto.d.ts +23 -0
- package/lib/mjs/dto/confirm-password-dto.d.ts.map +1 -0
- package/lib/mjs/dto/{user-dto.js → confirm-password-dto.js} +15 -10
- package/lib/mjs/dto/confirm-password-dto.js.map +1 -0
- package/lib/mjs/dto/password-reset-dto.d.ts +58 -0
- package/lib/mjs/dto/password-reset-dto.d.ts.map +1 -0
- package/lib/mjs/dto/password-reset-dto.js +54 -0
- package/lib/mjs/dto/password-reset-dto.js.map +1 -0
- package/lib/mjs/handlers/DefaultLogoutHandler.d.ts +4 -1
- package/lib/mjs/handlers/DefaultLogoutHandler.d.ts.map +1 -1
- package/lib/mjs/handlers/DefaultLogoutHandler.js +23 -16
- package/lib/mjs/handlers/DefaultLogoutHandler.js.map +1 -1
- package/lib/mjs/handlers/ImpersonationLogoutHandler.d.ts +4 -7
- package/lib/mjs/handlers/ImpersonationLogoutHandler.d.ts.map +1 -1
- package/lib/mjs/handlers/ImpersonationLogoutHandler.js +31 -32
- package/lib/mjs/handlers/ImpersonationLogoutHandler.js.map +1 -1
- package/lib/mjs/index.d.ts +20 -0
- package/lib/mjs/index.d.ts.map +1 -1
- package/lib/mjs/index.js +22 -0
- package/lib/mjs/index.js.map +1 -1
- package/lib/mjs/logout.d.ts +7 -0
- package/lib/mjs/logout.d.ts.map +1 -1
- package/lib/mjs/logout.js.map +1 -1
- package/lib/mjs/policies/2FaPolicy.d.ts +21 -1
- package/lib/mjs/policies/2FaPolicy.d.ts.map +1 -1
- package/lib/mjs/policies/2FaPolicy.js +29 -6
- package/lib/mjs/policies/2FaPolicy.js.map +1 -1
- package/lib/mjs/services/ImpersonationService.d.ts +90 -0
- package/lib/mjs/services/ImpersonationService.d.ts.map +1 -0
- package/lib/mjs/services/ImpersonationService.js +144 -0
- package/lib/mjs/services/ImpersonationService.js.map +1 -0
- package/lib/mjs/services/SessionCookies.d.ts +41 -0
- package/lib/mjs/services/SessionCookies.d.ts.map +1 -0
- package/lib/mjs/services/SessionCookies.js +59 -0
- package/lib/mjs/services/SessionCookies.js.map +1 -0
- package/lib/mjs/services/UserMetadataService.d.ts +53 -0
- package/lib/mjs/services/UserMetadataService.d.ts.map +1 -0
- package/lib/mjs/services/UserMetadataService.js +91 -0
- package/lib/mjs/services/UserMetadataService.js.map +1 -0
- package/lib/mjs/services/grants.d.ts +29 -0
- package/lib/mjs/services/grants.d.ts.map +1 -0
- package/lib/mjs/services/grants.js +38 -0
- package/lib/mjs/services/grants.js.map +1 -0
- package/lib/tsconfig.cjs.tsbuildinfo +1 -1
- package/lib/tsconfig.mjs.tsbuildinfo +1 -1
- package/package.json +17 -11
- package/lib/cjs/controllers/AuthController.d.ts +0 -1
- package/lib/cjs/controllers/AuthController.d.ts.map +0 -1
- package/lib/cjs/controllers/AuthController.js +0 -211
- package/lib/cjs/controllers/AuthController.js.map +0 -1
- package/lib/cjs/controllers/FederatedLoginController.d.ts +0 -1
- package/lib/cjs/controllers/FederatedLoginController.d.ts.map +0 -1
- package/lib/cjs/controllers/FederatedLoginController.js +0 -38
- package/lib/cjs/controllers/FederatedLoginController.js.map +0 -1
- package/lib/cjs/dto/login-dto.d.ts +0 -17
- package/lib/cjs/dto/login-dto.d.ts.map +0 -1
- package/lib/cjs/dto/login-dto.js +0 -33
- package/lib/cjs/dto/login-dto.js.map +0 -1
- package/lib/cjs/dto/restore-password-dto.d.ts +0 -24
- package/lib/cjs/dto/restore-password-dto.d.ts.map +0 -1
- package/lib/cjs/dto/restore-password-dto.js.map +0 -1
- package/lib/cjs/dto/user-dto.d.ts +0 -22
- package/lib/cjs/dto/user-dto.d.ts.map +0 -1
- package/lib/cjs/dto/user-dto.js +0 -33
- package/lib/cjs/dto/user-dto.js.map +0 -1
- package/lib/cjs/fingerprint/FingerprintJs.d.ts +0 -1
- package/lib/cjs/fingerprint/FingerprintJs.d.ts.map +0 -1
- package/lib/cjs/fingerprint/FingerprintJs.js +0 -5
- package/lib/cjs/fingerprint/FingerprintJs.js.map +0 -1
- package/lib/cjs/middlewares/AttributeFilter.d.ts +0 -11
- package/lib/cjs/middlewares/AttributeFilter.d.ts.map +0 -1
- package/lib/cjs/middlewares/AttributeFilter.js +0 -19
- package/lib/cjs/middlewares/AttributeFilter.js.map +0 -1
- package/lib/cjs/policies/AllowFederatedLoginPolicy.d.ts +0 -7
- package/lib/cjs/policies/AllowFederatedLoginPolicy.d.ts.map +0 -1
- package/lib/cjs/policies/AllowFederatedLoginPolicy.js +0 -32
- package/lib/cjs/policies/AllowFederatedLoginPolicy.js.map +0 -1
- package/lib/cjs/policies/CaptchaPolicy.d.ts +0 -1
- package/lib/cjs/policies/CaptchaPolicy.d.ts.map +0 -1
- package/lib/cjs/policies/CaptchaPolicy.js +0 -1
- package/lib/cjs/policies/CaptchaPolicy.js.map +0 -1
- package/lib/mjs/controllers/AuthController.d.ts +0 -2
- package/lib/mjs/controllers/AuthController.d.ts.map +0 -1
- package/lib/mjs/controllers/AuthController.js +0 -212
- package/lib/mjs/controllers/AuthController.js.map +0 -1
- package/lib/mjs/controllers/FederatedLoginController.d.ts +0 -2
- package/lib/mjs/controllers/FederatedLoginController.d.ts.map +0 -1
- package/lib/mjs/controllers/FederatedLoginController.js +0 -39
- package/lib/mjs/controllers/FederatedLoginController.js.map +0 -1
- package/lib/mjs/dto/login-dto.d.ts +0 -17
- package/lib/mjs/dto/login-dto.d.ts.map +0 -1
- package/lib/mjs/dto/login-dto.js +0 -30
- package/lib/mjs/dto/login-dto.js.map +0 -1
- package/lib/mjs/dto/restore-password-dto.d.ts +0 -24
- package/lib/mjs/dto/restore-password-dto.d.ts.map +0 -1
- package/lib/mjs/dto/restore-password-dto.js +0 -31
- package/lib/mjs/dto/restore-password-dto.js.map +0 -1
- package/lib/mjs/dto/user-dto.d.ts +0 -22
- package/lib/mjs/dto/user-dto.d.ts.map +0 -1
- package/lib/mjs/dto/user-dto.js.map +0 -1
- package/lib/mjs/fingerprint/FingerprintJs.d.ts +0 -2
- package/lib/mjs/fingerprint/FingerprintJs.d.ts.map +0 -1
- package/lib/mjs/fingerprint/FingerprintJs.js +0 -6
- package/lib/mjs/fingerprint/FingerprintJs.js.map +0 -1
- package/lib/mjs/middlewares/AttributeFilter.d.ts +0 -11
- package/lib/mjs/middlewares/AttributeFilter.d.ts.map +0 -1
- package/lib/mjs/middlewares/AttributeFilter.js +0 -15
- package/lib/mjs/middlewares/AttributeFilter.js.map +0 -1
- package/lib/mjs/policies/AllowFederatedLoginPolicy.d.ts +0 -7
- package/lib/mjs/policies/AllowFederatedLoginPolicy.d.ts.map +0 -1
- package/lib/mjs/policies/AllowFederatedLoginPolicy.js +0 -28
- package/lib/mjs/policies/AllowFederatedLoginPolicy.js.map +0 -1
- package/lib/mjs/policies/CaptchaPolicy.d.ts +0 -2
- package/lib/mjs/policies/CaptchaPolicy.d.ts.map +0 -1
- package/lib/mjs/policies/CaptchaPolicy.js +0 -2
- package/lib/mjs/policies/CaptchaPolicy.js.map +0 -1
|
@@ -0,0 +1,147 @@
|
|
|
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.ImpersonationService = exports.IMPERSONATION_KEYS = void 0;
|
|
13
|
+
const di_1 = require("@spinajs/di");
|
|
14
|
+
const configuration_1 = require("@spinajs/configuration");
|
|
15
|
+
const rbac_1 = require("@spinajs/rbac");
|
|
16
|
+
const queue_1 = require("@spinajs/queue");
|
|
17
|
+
/** Session keys holding the impersonation block. */
|
|
18
|
+
exports.IMPERSONATION_KEYS = {
|
|
19
|
+
IMPERSONATOR: 'Impersonator',
|
|
20
|
+
STARTED_AT: 'ImpersonationStartedAt',
|
|
21
|
+
ORIGINAL_ACTIVE_ROLE: 'OriginalActiveRole',
|
|
22
|
+
/**
|
|
23
|
+
* Numeric id of the impersonator, stashed because `session.UserId` is handed
|
|
24
|
+
* over to the target for the duration — see {@link ImpersonationService.start}.
|
|
25
|
+
*/
|
|
26
|
+
ORIGINAL_USER_ID: 'OriginalUserId',
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Owns the impersonation session block.
|
|
30
|
+
*
|
|
31
|
+
* The revert path is reachable two ways — explicitly via `DELETE /auth/impersonate`
|
|
32
|
+
* and implicitly when an impersonating user logs out — and both used to carry
|
|
33
|
+
* their own copy of the key juggling. The copies had already drifted: the logout
|
|
34
|
+
* handler dereferenced a deleted impersonator without a guard and answered a
|
|
35
|
+
* logout with a 500, while the controller handled that same case.
|
|
36
|
+
*/
|
|
37
|
+
let ImpersonationService = class ImpersonationService {
|
|
38
|
+
/** True when the session is currently acting as somebody else. */
|
|
39
|
+
isActive(session) {
|
|
40
|
+
return Boolean(session?.Data.get(exports.IMPERSONATION_KEYS.IMPERSONATOR));
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Begin acting as `target`. The impersonator's own ActiveRole is stashed so
|
|
44
|
+
* `revert` can restore it, and the effective ActiveRole becomes the target's
|
|
45
|
+
* first role.
|
|
46
|
+
*
|
|
47
|
+
* Two things beyond the key juggling:
|
|
48
|
+
*
|
|
49
|
+
* - the session id is REGENERATED. Assuming another identity is a privilege
|
|
50
|
+
* change, and a privilege change on a session id that an attacker may
|
|
51
|
+
* already know is the definition of session fixation.
|
|
52
|
+
* - `session.UserId` is handed over to the target and the impersonator's own
|
|
53
|
+
* id is stashed. Ownership is what `deleteByUser` keys on, so while the
|
|
54
|
+
* impersonation runs, "log this user out everywhere" aimed at the target
|
|
55
|
+
* reaches the impersonating session too — which is exactly what an
|
|
56
|
+
* administrator killing a compromised account expects.
|
|
57
|
+
*
|
|
58
|
+
* @returns the regenerated session and the ActiveRole now in effect
|
|
59
|
+
*/
|
|
60
|
+
async start(session, impersonator, target, startedAt) {
|
|
61
|
+
const previousActiveRole = session.Data.get('ActiveRole');
|
|
62
|
+
session.Data.set(exports.IMPERSONATION_KEYS.IMPERSONATOR, impersonator.Uuid);
|
|
63
|
+
session.Data.set(exports.IMPERSONATION_KEYS.ORIGINAL_USER_ID, session.UserId ?? impersonator.Id);
|
|
64
|
+
session.Data.set('User', target.Uuid);
|
|
65
|
+
session.Data.set(exports.IMPERSONATION_KEYS.STARTED_AT, startedAt);
|
|
66
|
+
if (previousActiveRole !== undefined) {
|
|
67
|
+
session.Data.set(exports.IMPERSONATION_KEYS.ORIGINAL_ACTIVE_ROLE, previousActiveRole);
|
|
68
|
+
}
|
|
69
|
+
const targetActiveRole = target.Role?.[0];
|
|
70
|
+
if (targetActiveRole) {
|
|
71
|
+
session.Data.set('ActiveRole', targetActiveRole);
|
|
72
|
+
}
|
|
73
|
+
session.UserId = target.Id;
|
|
74
|
+
const regenerated = await (0, rbac_1.regenerateSession)(this.SessionProvider, session);
|
|
75
|
+
return { Session: regenerated, ActiveRole: targetActiveRole };
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* End an active impersonation and put the original user back in the session.
|
|
79
|
+
*
|
|
80
|
+
* The session survives either way — reverting is not a logout. When the
|
|
81
|
+
* original user is gone the impersonation block is still cleared, so the
|
|
82
|
+
* session stops claiming an identity that cannot be resolved, and the caller
|
|
83
|
+
* is told to re-authenticate rather than being handed a 500.
|
|
84
|
+
*/
|
|
85
|
+
async revert(session, target) {
|
|
86
|
+
if (!session) {
|
|
87
|
+
return { Status: 'not-impersonating' };
|
|
88
|
+
}
|
|
89
|
+
const impersonatorUuid = session.Data.get(exports.IMPERSONATION_KEYS.IMPERSONATOR);
|
|
90
|
+
if (!impersonatorUuid) {
|
|
91
|
+
return { Status: 'not-impersonating' };
|
|
92
|
+
}
|
|
93
|
+
const original = await this.loadOriginal(impersonatorUuid);
|
|
94
|
+
if (!original) {
|
|
95
|
+
await this.clearBlock(session);
|
|
96
|
+
return { Status: 'impersonator-gone' };
|
|
97
|
+
}
|
|
98
|
+
session.Data.set('User', original.Uuid);
|
|
99
|
+
const restoredActiveRole = session.Data.get(exports.IMPERSONATION_KEYS.ORIGINAL_ACTIVE_ROLE) ?? original.Role?.[0];
|
|
100
|
+
if (restoredActiveRole) {
|
|
101
|
+
session.Data.set('ActiveRole', restoredActiveRole);
|
|
102
|
+
}
|
|
103
|
+
// ownership goes back to the impersonator along with the identity
|
|
104
|
+
session.UserId = session.Data.get(exports.IMPERSONATION_KEYS.ORIGINAL_USER_ID) ?? original.Id;
|
|
105
|
+
this.dropBlockKeys(session);
|
|
106
|
+
// Dropping an identity is a privilege change too — the id the target's
|
|
107
|
+
// session was reachable under does not survive into the impersonator's.
|
|
108
|
+
const regenerated = await (0, rbac_1.regenerateSession)(this.SessionProvider, session);
|
|
109
|
+
await this.emitEnded(original, target);
|
|
110
|
+
return { Status: 'reverted', Original: original, ActiveRole: restoredActiveRole, Session: regenerated };
|
|
111
|
+
}
|
|
112
|
+
/** Drops the impersonation keys and persists the session under the same id. */
|
|
113
|
+
async clearBlock(session) {
|
|
114
|
+
this.dropBlockKeys(session);
|
|
115
|
+
await this.SessionProvider.save(session);
|
|
116
|
+
}
|
|
117
|
+
/** Removes the impersonation keys from session data without persisting. */
|
|
118
|
+
dropBlockKeys(session) {
|
|
119
|
+
session.Data.delete(exports.IMPERSONATION_KEYS.IMPERSONATOR);
|
|
120
|
+
session.Data.delete(exports.IMPERSONATION_KEYS.STARTED_AT);
|
|
121
|
+
session.Data.delete(exports.IMPERSONATION_KEYS.ORIGINAL_ACTIVE_ROLE);
|
|
122
|
+
session.Data.delete(exports.IMPERSONATION_KEYS.ORIGINAL_USER_ID);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Load the original (impersonator) user, or undefined when the account is
|
|
126
|
+
* gone. Extracted so tests can stub it without a database.
|
|
127
|
+
*/
|
|
128
|
+
async loadOriginal(uuid) {
|
|
129
|
+
return (await rbac_1.User.getByUuid(uuid));
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Hook for tests to intercept event emission without stubbing the
|
|
133
|
+
* module-level `_ev` ESM binding.
|
|
134
|
+
*/
|
|
135
|
+
emitEnded(original, target) {
|
|
136
|
+
return (0, queue_1._ev)(new rbac_1.UserImpersonationEnded(original, target))();
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
exports.ImpersonationService = ImpersonationService;
|
|
140
|
+
__decorate([
|
|
141
|
+
(0, configuration_1.AutoinjectService)('rbac.session'),
|
|
142
|
+
__metadata("design:type", rbac_1.SessionProvider)
|
|
143
|
+
], ImpersonationService.prototype, "SessionProvider", void 0);
|
|
144
|
+
exports.ImpersonationService = ImpersonationService = __decorate([
|
|
145
|
+
(0, di_1.Injectable)()
|
|
146
|
+
], ImpersonationService);
|
|
147
|
+
//# sourceMappingURL=ImpersonationService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ImpersonationService.js","sourceRoot":"","sources":["../../../src/services/ImpersonationService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ISession, ISessionCookieConfig } from '@spinajs/rbac';
|
|
2
|
+
/** Cookie descriptor accepted by the http `Coockies` response option. */
|
|
3
|
+
export interface ISessionCookie {
|
|
4
|
+
Name: string;
|
|
5
|
+
Value: string;
|
|
6
|
+
Options: Record<string, unknown>;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Default name of the session cookie. Kept for callers that only need the
|
|
10
|
+
* literal; the ACTIVE name comes from configuration and may carry a `__Host-`
|
|
11
|
+
* prefix, so read {@link SessionCookieFactory.Name} instead of assuming this.
|
|
12
|
+
*/
|
|
13
|
+
export declare const SESSION_COOKIE_NAME = "ssid";
|
|
14
|
+
/**
|
|
15
|
+
* Builds the session cookie.
|
|
16
|
+
*
|
|
17
|
+
* Every place that opens, rotates, or clears a session used to inline the same
|
|
18
|
+
* literal — login, 2FA verify, active-role switch and logout each carried their
|
|
19
|
+
* own copy, and each had to remember `signed`, `httpOnly`, the configured
|
|
20
|
+
* overrides, and to derive maxAge from the session's real expiration. A drift in
|
|
21
|
+
* any one of them silently produces a cookie the next request cannot restore.
|
|
22
|
+
*
|
|
23
|
+
* The attributes themselves are decided by `@spinajs/rbac` so the session
|
|
24
|
+
* middleware — which renews the very same cookie on every request, from a
|
|
25
|
+
* package that cannot import this one — produces a byte-identical set.
|
|
26
|
+
*/
|
|
27
|
+
export declare class SessionCookieFactory {
|
|
28
|
+
protected SessionCookieConfig: ISessionCookieConfig;
|
|
29
|
+
/** Configured cookie name, `__Host-` prefix included when enabled. */
|
|
30
|
+
get Name(): string;
|
|
31
|
+
/**
|
|
32
|
+
* Cookie carrying an active session. `maxAge` tracks the session's real
|
|
33
|
+
* expiration rather than a fixed constant, so sliding and absolute
|
|
34
|
+
* expiration strategies both produce a cookie that outlives exactly as long
|
|
35
|
+
* as the session behind it.
|
|
36
|
+
*/
|
|
37
|
+
issue(session: ISession): ISessionCookie;
|
|
38
|
+
/** Same cookie, expired — clears the session client-side on logout. */
|
|
39
|
+
clear(): ISessionCookie;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=SessionCookies.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SessionCookies.d.ts","sourceRoot":"","sources":["../../../src/services/SessionCookies.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAGpE,yEAAyE;AACzE,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,SAAS,CAAC;AAE1C;;;;;;;;;;;;GAYG;AACH,qBACa,oBAAoB;IAE/B,SAAS,CAAC,mBAAmB,EAAE,oBAAoB,CAAC;IAEpD,sEAAsE;IACtE,IAAW,IAAI,IAAI,MAAM,CAExB;IAED;;;;;OAKG;IACI,KAAK,CAAC,OAAO,EAAE,QAAQ,GAAG,cAAc;IAI/C,uEAAuE;IAChE,KAAK,IAAI,cAAc;CAG/B"}
|
|
@@ -0,0 +1,62 @@
|
|
|
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.SessionCookieFactory = exports.SESSION_COOKIE_NAME = void 0;
|
|
13
|
+
const configuration_1 = require("@spinajs/configuration");
|
|
14
|
+
const di_1 = require("@spinajs/di");
|
|
15
|
+
const rbac_1 = require("@spinajs/rbac");
|
|
16
|
+
/**
|
|
17
|
+
* Default name of the session cookie. Kept for callers that only need the
|
|
18
|
+
* literal; the ACTIVE name comes from configuration and may carry a `__Host-`
|
|
19
|
+
* prefix, so read {@link SessionCookieFactory.Name} instead of assuming this.
|
|
20
|
+
*/
|
|
21
|
+
exports.SESSION_COOKIE_NAME = 'ssid';
|
|
22
|
+
/**
|
|
23
|
+
* Builds the session cookie.
|
|
24
|
+
*
|
|
25
|
+
* Every place that opens, rotates, or clears a session used to inline the same
|
|
26
|
+
* literal — login, 2FA verify, active-role switch and logout each carried their
|
|
27
|
+
* own copy, and each had to remember `signed`, `httpOnly`, the configured
|
|
28
|
+
* overrides, and to derive maxAge from the session's real expiration. A drift in
|
|
29
|
+
* any one of them silently produces a cookie the next request cannot restore.
|
|
30
|
+
*
|
|
31
|
+
* The attributes themselves are decided by `@spinajs/rbac` so the session
|
|
32
|
+
* middleware — which renews the very same cookie on every request, from a
|
|
33
|
+
* package that cannot import this one — produces a byte-identical set.
|
|
34
|
+
*/
|
|
35
|
+
let SessionCookieFactory = class SessionCookieFactory {
|
|
36
|
+
/** Configured cookie name, `__Host-` prefix included when enabled. */
|
|
37
|
+
get Name() {
|
|
38
|
+
return (0, rbac_1.sessionCookieName)(this.SessionCookieConfig);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Cookie carrying an active session. `maxAge` tracks the session's real
|
|
42
|
+
* expiration rather than a fixed constant, so sliding and absolute
|
|
43
|
+
* expiration strategies both produce a cookie that outlives exactly as long
|
|
44
|
+
* as the session behind it.
|
|
45
|
+
*/
|
|
46
|
+
issue(session) {
|
|
47
|
+
return (0, rbac_1.sessionCookie)(session, this.SessionCookieConfig);
|
|
48
|
+
}
|
|
49
|
+
/** Same cookie, expired — clears the session client-side on logout. */
|
|
50
|
+
clear() {
|
|
51
|
+
return (0, rbac_1.clearSessionCookie)(this.SessionCookieConfig);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
exports.SessionCookieFactory = SessionCookieFactory;
|
|
55
|
+
__decorate([
|
|
56
|
+
(0, configuration_1.Config)('rbac.session.cookie', {}),
|
|
57
|
+
__metadata("design:type", Object)
|
|
58
|
+
], SessionCookieFactory.prototype, "SessionCookieConfig", void 0);
|
|
59
|
+
exports.SessionCookieFactory = SessionCookieFactory = __decorate([
|
|
60
|
+
(0, di_1.Injectable)()
|
|
61
|
+
], SessionCookieFactory);
|
|
62
|
+
//# sourceMappingURL=SessionCookies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SessionCookies.js","sourceRoot":"","sources":["../../../src/services/SessionCookies.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,0DAAgD;AAChD,oCAAyC;AAEzC,wCAAqF;AASrF;;;;GAIG;AACU,QAAA,mBAAmB,GAAG,MAAM,CAAC;AAE1C;;;;;;;;;;;;GAYG;AAEI,IAAM,oBAAoB,GAA1B,MAAM,oBAAoB;IAI/B,sEAAsE;IACtE,IAAW,IAAI;QACb,OAAO,IAAA,wBAAiB,EAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IACrD,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,OAAiB;QAC5B,OAAO,IAAA,oBAAa,EAAC,OAAO,EAAE,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAC1D,CAAC;IAED,uEAAuE;IAChE,KAAK;QACV,OAAO,IAAA,yBAAkB,EAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IACtD,CAAC;CACF,CAAA;AAvBY,oDAAoB;AAErB;IADT,IAAA,sBAAM,EAAC,qBAAqB,EAAE,EAAE,CAAC;;iEACkB;+BAFzC,oBAAoB;IADhC,IAAA,eAAU,GAAE;GACA,oBAAoB,CAuBhC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { UserMetadata } from '@spinajs/rbac';
|
|
2
|
+
import type { IFilterRequest, OrderDTO, PaginationDTO } from '@spinajs/orm-http';
|
|
3
|
+
import { FilterableUserMetadata } from '../models/FilterableUserMetadata.js';
|
|
4
|
+
import type { UserMetadataDto } from '../dto/metadata-dto.js';
|
|
5
|
+
/**
|
|
6
|
+
* Fallback page size. A request without a `limit` used to reach `take(0)`,
|
|
7
|
+
* which the query builder rejects ( "take count should be a positive number" ),
|
|
8
|
+
* so plain listing requests failed instead of returning the first page.
|
|
9
|
+
*/
|
|
10
|
+
export declare const DEFAULT_PAGE_SIZE = 10;
|
|
11
|
+
/**
|
|
12
|
+
* User metadata access, always scoped to one owner.
|
|
13
|
+
*
|
|
14
|
+
* The controller exposes each operation twice — once for the caller's own
|
|
15
|
+
* metadata and once for an administrator addressing a user by UUID — and the
|
|
16
|
+
* two differed only in where the owner id came from. Keeping the queries here
|
|
17
|
+
* means the ownership predicate is written once.
|
|
18
|
+
*
|
|
19
|
+
* Ownership is filtered explicitly rather than left to the rbac query
|
|
20
|
+
* middleware: metadata queries resolve to the unsafe base model, so no
|
|
21
|
+
* automatic owner scoping fires for them.
|
|
22
|
+
*/
|
|
23
|
+
export declare class UserMetadataService {
|
|
24
|
+
/** Paginated, filtered, ordered listing of one user's metadata. */
|
|
25
|
+
list(ownerId: number, pagination?: PaginationDTO, order?: OrderDTO, filter?: IFilterRequest): import("@spinajs/orm").ISelectQueryBuilder<FilterableUserMetadata[]> & import("@spinajs/orm").QueryScope;
|
|
26
|
+
/** A single entry of one user, by key. Rejects when absent. */
|
|
27
|
+
getByKey(ownerId: number, key: string): Promise<UserMetadata>;
|
|
28
|
+
/**
|
|
29
|
+
* Insert an entry, or update it when the key already exists.
|
|
30
|
+
*
|
|
31
|
+
* Ownership is forced onto the model — a `user_id` arriving in the request
|
|
32
|
+
* body is never trusted.
|
|
33
|
+
*/
|
|
34
|
+
upsert(ownerId: number, metadata: UserMetadata): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Update an entry addressed by either its Id or its Key.
|
|
37
|
+
*
|
|
38
|
+
* The Key/Id lookup is grouped and AND-ed with the ownership filter. Without
|
|
39
|
+
* the grouping the flat `Key = ? OR Id = ? AND user_id = ?` binds as
|
|
40
|
+
* `Key = ? OR (Id = ? AND user_id = ?)`, which would let any caller update
|
|
41
|
+
* another user's entry by its Key.
|
|
42
|
+
*/
|
|
43
|
+
update(ownerId: number, idOrKey: string | number, data: UserMetadataDto): Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Delete an entry by id, scoped to its owner.
|
|
46
|
+
*
|
|
47
|
+
* `destroy()` refuses to build an unbounded DELETE, so the entry id goes in
|
|
48
|
+
* as the primary key and ownership is AND-ed on top of it — deleting by id
|
|
49
|
+
* alone would let any caller remove anybody's entry.
|
|
50
|
+
*/
|
|
51
|
+
delete(ownerId: number, id: number): Promise<void>;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=UserMetadataService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UserMetadataService.d.ts","sourceRoot":"","sources":["../../../src/services/UserMetadataService.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACjF,OAAO,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAC7E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,KAAK,CAAC;AAEpC;;;;;;;;;;;GAWG;AACH,qBACa,mBAAmB;IAC9B,mEAAmE;IAC5D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,aAAa,EAAE,KAAK,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,cAAc;IAWlG,+DAA+D;IACxD,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;IAO5C;;;;;OAKG;IACU,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAK3E;;;;;;;OAOG;IACU,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAYpG;;;;;;OAMG;IACU,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGhE"}
|
|
@@ -0,0 +1,94 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.UserMetadataService = exports.DEFAULT_PAGE_SIZE = void 0;
|
|
10
|
+
const di_1 = require("@spinajs/di");
|
|
11
|
+
const rbac_1 = require("@spinajs/rbac");
|
|
12
|
+
const orm_1 = require("@spinajs/orm");
|
|
13
|
+
const FilterableUserMetadata_js_1 = require("../models/FilterableUserMetadata.js");
|
|
14
|
+
/**
|
|
15
|
+
* Fallback page size. A request without a `limit` used to reach `take(0)`,
|
|
16
|
+
* which the query builder rejects ( "take count should be a positive number" ),
|
|
17
|
+
* so plain listing requests failed instead of returning the first page.
|
|
18
|
+
*/
|
|
19
|
+
exports.DEFAULT_PAGE_SIZE = 10;
|
|
20
|
+
/**
|
|
21
|
+
* User metadata access, always scoped to one owner.
|
|
22
|
+
*
|
|
23
|
+
* The controller exposes each operation twice — once for the caller's own
|
|
24
|
+
* metadata and once for an administrator addressing a user by UUID — and the
|
|
25
|
+
* two differed only in where the owner id came from. Keeping the queries here
|
|
26
|
+
* means the ownership predicate is written once.
|
|
27
|
+
*
|
|
28
|
+
* Ownership is filtered explicitly rather than left to the rbac query
|
|
29
|
+
* middleware: metadata queries resolve to the unsafe base model, so no
|
|
30
|
+
* automatic owner scoping fires for them.
|
|
31
|
+
*/
|
|
32
|
+
let UserMetadataService = class UserMetadataService {
|
|
33
|
+
/** Paginated, filtered, ordered listing of one user's metadata. */
|
|
34
|
+
list(ownerId, pagination, order, filter) {
|
|
35
|
+
const limit = pagination?.limit || exports.DEFAULT_PAGE_SIZE;
|
|
36
|
+
return FilterableUserMetadata_js_1.FilterableUserMetadata.select()
|
|
37
|
+
.where('user_id', ownerId)
|
|
38
|
+
.filter(filter?.filters ?? [], filter?.op)
|
|
39
|
+
.take(limit)
|
|
40
|
+
.skip(limit * (pagination?.page ?? 0))
|
|
41
|
+
.order(order?.column ?? 'Id', order?.order ?? orm_1.SortOrder.DESC);
|
|
42
|
+
}
|
|
43
|
+
/** A single entry of one user, by key. Rejects when absent. */
|
|
44
|
+
getByKey(ownerId, key) {
|
|
45
|
+
return rbac_1.UserMetadata.where({
|
|
46
|
+
Key: key,
|
|
47
|
+
user_id: ownerId,
|
|
48
|
+
}).firstOrFail();
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Insert an entry, or update it when the key already exists.
|
|
52
|
+
*
|
|
53
|
+
* Ownership is forced onto the model — a `user_id` arriving in the request
|
|
54
|
+
* body is never trusted.
|
|
55
|
+
*/
|
|
56
|
+
async upsert(ownerId, metadata) {
|
|
57
|
+
metadata.user_id = ownerId;
|
|
58
|
+
await metadata.insert(orm_1.InsertBehaviour.InsertOrUpdate);
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Update an entry addressed by either its Id or its Key.
|
|
62
|
+
*
|
|
63
|
+
* The Key/Id lookup is grouped and AND-ed with the ownership filter. Without
|
|
64
|
+
* the grouping the flat `Key = ? OR Id = ? AND user_id = ?` binds as
|
|
65
|
+
* `Key = ? OR (Id = ? AND user_id = ?)`, which would let any caller update
|
|
66
|
+
* another user's entry by its Key.
|
|
67
|
+
*/
|
|
68
|
+
async update(ownerId, idOrKey, data) {
|
|
69
|
+
await rbac_1.UserMetadata.update({
|
|
70
|
+
Key: data.Key,
|
|
71
|
+
Value: data.Value,
|
|
72
|
+
Type: data.Type,
|
|
73
|
+
})
|
|
74
|
+
.where(function () {
|
|
75
|
+
this.where('Key', idOrKey).orWhere('Id', idOrKey);
|
|
76
|
+
})
|
|
77
|
+
.andWhere('user_id', ownerId);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Delete an entry by id, scoped to its owner.
|
|
81
|
+
*
|
|
82
|
+
* `destroy()` refuses to build an unbounded DELETE, so the entry id goes in
|
|
83
|
+
* as the primary key and ownership is AND-ed on top of it — deleting by id
|
|
84
|
+
* alone would let any caller remove anybody's entry.
|
|
85
|
+
*/
|
|
86
|
+
async delete(ownerId, id) {
|
|
87
|
+
await rbac_1.UserMetadata.destroy(id).andWhere('user_id', ownerId);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
exports.UserMetadataService = UserMetadataService;
|
|
91
|
+
exports.UserMetadataService = UserMetadataService = __decorate([
|
|
92
|
+
(0, di_1.Injectable)()
|
|
93
|
+
], UserMetadataService);
|
|
94
|
+
//# sourceMappingURL=UserMetadataService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UserMetadataService.js","sourceRoot":"","sources":["../../../src/services/UserMetadataService.ts"],"names":[],"mappings":";;;;;;;;;AAAA,oCAAyC;AACzC,wCAA6C;AAC7C,sCAA0D;AAE1D,mFAA6E;AAG7E;;;;GAIG;AACU,QAAA,iBAAiB,GAAG,EAAE,CAAC;AAEpC;;;;;;;;;;;GAWG;AAEI,IAAM,mBAAmB,GAAzB,MAAM,mBAAmB;IAC9B,mEAAmE;IAC5D,IAAI,CAAC,OAAe,EAAE,UAA0B,EAAE,KAAgB,EAAE,MAAuB;QAChG,MAAM,KAAK,GAAG,UAAU,EAAE,KAAK,IAAI,yBAAiB,CAAC;QAErD,OAAO,kDAAsB,CAAC,MAAM,EAAE;aACnC,KAAK,CAAC,SAAS,EAAE,OAAO,CAAC;aACzB,MAAM,CAAC,MAAM,EAAE,OAAO,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC;aACzC,IAAI,CAAC,KAAK,CAAC;aACX,IAAI,CAAC,KAAK,GAAG,CAAC,UAAU,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC;aACrC,KAAK,CAAC,KAAK,EAAE,MAAM,IAAI,IAAI,EAAE,KAAK,EAAE,KAAK,IAAI,eAAS,CAAC,IAAI,CAAC,CAAC;IAClE,CAAC;IAED,+DAA+D;IACxD,QAAQ,CAAC,OAAe,EAAE,GAAW;QAC1C,OAAO,mBAAY,CAAC,KAAK,CAAC;YACxB,GAAG,EAAE,GAAG;YACR,OAAO,EAAE,OAAO;SACjB,CAAC,CAAC,WAAW,EAAE,CAAC;IACnB,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,MAAM,CAAC,OAAe,EAAE,QAAsB;QACzD,QAAQ,CAAC,OAAO,GAAG,OAAO,CAAC;QAC3B,MAAM,QAAQ,CAAC,MAAM,CAAC,qBAAe,CAAC,cAAc,CAAC,CAAC;IACxD,CAAC;IAED;;;;;;;OAOG;IACI,KAAK,CAAC,MAAM,CAAC,OAAe,EAAE,OAAwB,EAAE,IAAqB;QAClF,MAAM,mBAAY,CAAC,MAAM,CAAC;YACxB,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,IAAI,EAAE,IAAI,CAAC,IAAI;SAChB,CAAC;aACC,KAAK,CAAC;YACL,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACpD,CAAC,CAAC;aACD,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAClC,CAAC;IAED;;;;;;OAMG;IACI,KAAK,CAAC,MAAM,CAAC,OAAe,EAAE,EAAU;QAC7C,MAAM,mBAAY,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAC9D,CAAC;CACF,CAAA;AA9DY,kDAAmB;8BAAnB,mBAAmB;IAD/B,IAAA,eAAU,GAAE;GACA,mBAAmB,CA8D/B"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { AccessControl, User } from '@spinajs/rbac';
|
|
2
|
+
import type { ISession } from '@spinajs/rbac';
|
|
3
|
+
import type { IGrantsMap, IUserWithGrants } from '@spinajs/rbac-http';
|
|
4
|
+
/**
|
|
5
|
+
* Role whose grants are in effect for a session.
|
|
6
|
+
*
|
|
7
|
+
* Enforcement (see the rbac http middleware) resolves permissions from the
|
|
8
|
+
* session's ActiveRole and falls back to the first assigned role, so anything
|
|
9
|
+
* reported to a client has to resolve it the same way — otherwise the client is
|
|
10
|
+
* told about actions the server will refuse.
|
|
11
|
+
*/
|
|
12
|
+
export declare function activeRoleOf(user: User, session?: ISession | null): string | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* Grants in effect for a single role, flattened through its `$extend` chain.
|
|
15
|
+
* An absent role yields an empty map rather than throwing — a user with no role
|
|
16
|
+
* assigned simply has no grants.
|
|
17
|
+
*/
|
|
18
|
+
export declare function grantsFor(ac: AccessControl, activeRole: string | undefined): IGrantsMap;
|
|
19
|
+
/**
|
|
20
|
+
* The login-style user payload: the dehydrated user plus their active role and
|
|
21
|
+
* the grants that role resolves to.
|
|
22
|
+
*
|
|
23
|
+
* Login, 2FA verification and ending an impersonation all hand the client the
|
|
24
|
+
* same shape, and all three previously assembled it by hand. `Role` is restored
|
|
25
|
+
* explicitly because `dehydrateWithRelations` flattens the relation to a string
|
|
26
|
+
* while clients expect the array they can switch between.
|
|
27
|
+
*/
|
|
28
|
+
export declare function buildUserWithGrants(user: User, activeRole: string | undefined, ac: AccessControl): IUserWithGrants;
|
|
29
|
+
//# sourceMappingURL=grants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grants.d.ts","sourceRoot":"","sources":["../../../src/services/grants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,IAAI,EAAiB,MAAM,eAAe,CAAC;AACnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAEtE;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE,QAAQ,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,CAEtF;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,CAEvF;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,GAAG,SAAS,EAAE,EAAE,EAAE,aAAa,GAAG,eAAe,CAOlH"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.activeRoleOf = activeRoleOf;
|
|
4
|
+
exports.grantsFor = grantsFor;
|
|
5
|
+
exports.buildUserWithGrants = buildUserWithGrants;
|
|
6
|
+
const rbac_1 = require("@spinajs/rbac");
|
|
7
|
+
/**
|
|
8
|
+
* Role whose grants are in effect for a session.
|
|
9
|
+
*
|
|
10
|
+
* Enforcement (see the rbac http middleware) resolves permissions from the
|
|
11
|
+
* session's ActiveRole and falls back to the first assigned role, so anything
|
|
12
|
+
* reported to a client has to resolve it the same way — otherwise the client is
|
|
13
|
+
* told about actions the server will refuse.
|
|
14
|
+
*/
|
|
15
|
+
function activeRoleOf(user, session) {
|
|
16
|
+
return session?.Data.get('ActiveRole') ?? user.Role?.[0];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Grants in effect for a single role, flattened through its `$extend` chain.
|
|
20
|
+
* An absent role yields an empty map rather than throwing — a user with no role
|
|
21
|
+
* assigned simply has no grants.
|
|
22
|
+
*/
|
|
23
|
+
function grantsFor(ac, activeRole) {
|
|
24
|
+
return (activeRole ? (0, rbac_1._unwindGrants)(activeRole, ac.getGrants()) : {});
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The login-style user payload: the dehydrated user plus their active role and
|
|
28
|
+
* the grants that role resolves to.
|
|
29
|
+
*
|
|
30
|
+
* Login, 2FA verification and ending an impersonation all hand the client the
|
|
31
|
+
* same shape, and all three previously assembled it by hand. `Role` is restored
|
|
32
|
+
* explicitly because `dehydrateWithRelations` flattens the relation to a string
|
|
33
|
+
* while clients expect the array they can switch between.
|
|
34
|
+
*/
|
|
35
|
+
function buildUserWithGrants(user, activeRole, ac) {
|
|
36
|
+
return {
|
|
37
|
+
...user.dehydrateWithRelations({ dateTimeFormat: 'iso' }),
|
|
38
|
+
Role: user.Role,
|
|
39
|
+
ActiveRole: activeRole,
|
|
40
|
+
Grants: grantsFor(ac, activeRole),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=grants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grants.js","sourceRoot":"","sources":["../../../src/services/grants.ts"],"names":[],"mappings":";;AAYA,oCAEC;AAOD,8BAEC;AAWD,kDAOC;AAzCD,wCAAmE;AAInE;;;;;;;GAOG;AACH,SAAgB,YAAY,CAAC,IAAU,EAAE,OAAyB;IAChE,OAAQ,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,YAAY,CAAwB,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AACnF,CAAC;AAED;;;;GAIG;AACH,SAAgB,SAAS,CAAC,EAAiB,EAAE,UAA8B;IACzE,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,IAAA,oBAAa,EAAC,UAAU,EAAE,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAe,CAAC;AACrF,CAAC;AAED;;;;;;;;GAQG;AACH,SAAgB,mBAAmB,CAAC,IAAU,EAAE,UAA8B,EAAE,EAAiB;IAC/F,OAAO;QACL,GAAG,IAAI,CAAC,sBAAsB,CAAC,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC;QACzD,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,UAAU,EAAE,UAAU;QACtB,MAAM,EAAE,SAAS,CAAC,EAAE,EAAE,UAAU,CAAC;KACJ,CAAC;AAClC,CAAC"}
|
|
@@ -40,27 +40,12 @@ declare const rbacHttp: {
|
|
|
40
40
|
forceUser: boolean;
|
|
41
41
|
service: string;
|
|
42
42
|
};
|
|
43
|
-
fingerprint: {
|
|
44
|
-
enabled: boolean;
|
|
45
|
-
maxDevices: number;
|
|
46
|
-
service: string;
|
|
47
|
-
};
|
|
48
|
-
session: {
|
|
49
|
-
cookie: {
|
|
50
|
-
sameSite: string;
|
|
51
|
-
};
|
|
52
|
-
};
|
|
53
43
|
password: {
|
|
54
|
-
tokenTTL: number;
|
|
55
44
|
/**
|
|
56
45
|
* Block account after invalid login attempts
|
|
57
46
|
*/
|
|
58
47
|
blockAfterAttempts: number;
|
|
59
48
|
};
|
|
60
|
-
/**
|
|
61
|
-
* Should federated login be enabled ? eg. facebook
|
|
62
|
-
*/
|
|
63
|
-
allowFederated: boolean;
|
|
64
49
|
};
|
|
65
50
|
http: {};
|
|
66
51
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rbac-http.d.ts","sourceRoot":"","sources":["../../../src/config/rbac-http.ts"],"names":[],"mappings":"AAQA,QAAA,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;YAiBR;;eAEG;;YAGH;;eAEG
|
|
1
|
+
{"version":3,"file":"rbac-http.d.ts","sourceRoot":"","sources":["../../../src/config/rbac-http.ts"],"names":[],"mappings":"AAQA,QAAA,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;YAiBR;;eAEG;;YAGH;;eAEG;;;;;;;;;;;;YAmBH;;eAEG;;;;;CASR,CAAC;AAEF,eAAe,QAAQ,CAAC"}
|
|
@@ -37,28 +37,18 @@ const rbacHttp = {
|
|
|
37
37
|
forceUser: false,
|
|
38
38
|
service: 'Default2FaToken',
|
|
39
39
|
},
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
},
|
|
45
|
-
session: {
|
|
46
|
-
cookie: {
|
|
47
|
-
sameSite: 'lax'
|
|
48
|
-
}
|
|
49
|
-
},
|
|
40
|
+
// NOTE: the session cookie ( `rbac.session.cookie` ) is configured by
|
|
41
|
+
// @spinajs/rbac and defaults to Secure + SameSite=Strict + HttpOnly. This
|
|
42
|
+
// package used to weaken it to SameSite=Lax here, which is what let a
|
|
43
|
+
// cross-site GET reach the logout route.
|
|
50
44
|
password: {
|
|
51
|
-
// password reset token
|
|
52
|
-
|
|
45
|
+
// NOTE: the password reset token's lifetime is `rbac.password.passwordResetWaitTime`
|
|
46
|
+
// ( seconds, defined by @spinajs/rbac ) — this package does not restate it.
|
|
53
47
|
/**
|
|
54
48
|
* Block account after invalid login attempts
|
|
55
49
|
*/
|
|
56
50
|
blockAfterAttempts: 3,
|
|
57
51
|
},
|
|
58
|
-
/**
|
|
59
|
-
* Should federated login be enabled ? eg. facebook
|
|
60
|
-
*/
|
|
61
|
-
allowFederated: false,
|
|
62
52
|
},
|
|
63
53
|
http: {
|
|
64
54
|
// middlewares: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rbac-http.js","sourceRoot":"","sources":["../../../src/config/rbac-http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAEhD,SAAS,GAAG,CAAC,IAAY;IACvB,MAAM,UAAU,GAAG,OAAO,MAAM,KAAK,WAAW,CAAC;IACjD,OAAO,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,UAAU,EAAE,gBAAgB,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;AAC3K,CAAC;AAGD,MAAM,QAAQ,GAAG;IACf,MAAM,EAAE;QACN,IAAI,EAAE;YACJ,WAAW,EAAE,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;YACjC,GAAG,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;SAClB;KACF;IACD,KAAK,EAAE;QACL,OAAO,EAAE;YACP,eAAe,EAAE,EAAE,UAAU,EAAE,uBAAuB,EAAE;YACxD,cAAc,EAAE,EAAE,UAAU,EAAE,uBAAuB,EAAE;YACvD,aAAa,EAAE,EAAE,UAAU,EAAE,uBAAuB,EAAE;YACtD,YAAY,EAAE,EAAE,UAAU,EAAE,uBAAuB,EAAE;SACtD;KACF;IACD,IAAI,EAAE;QACJ,OAAO,EAAE;YACP;;eAEG;YACH,MAAM,EAAE,SAAS;YAEjB;;eAEG;YACH,SAAS,EAAE,MAAM;YACjB,MAAM,EAAE,CAAC;YACT,MAAM,EAAE,EAAE;YACV,MAAM,EAAE,CAAC;SACV;QACD,aAAa,EAAE;YACb,OAAO,EAAE,IAAI;YACb,SAAS,EAAE,KAAK;YAChB,OAAO,EAAE,iBAAiB;SAC3B;QACD,
|
|
1
|
+
{"version":3,"file":"rbac-http.js","sourceRoot":"","sources":["../../../src/config/rbac-http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAEhD,SAAS,GAAG,CAAC,IAAY;IACvB,MAAM,UAAU,GAAG,OAAO,MAAM,KAAK,WAAW,CAAC;IACjD,OAAO,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,UAAU,EAAE,gBAAgB,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;AAC3K,CAAC;AAGD,MAAM,QAAQ,GAAG;IACf,MAAM,EAAE;QACN,IAAI,EAAE;YACJ,WAAW,EAAE,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;YACjC,GAAG,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;SAClB;KACF;IACD,KAAK,EAAE;QACL,OAAO,EAAE;YACP,eAAe,EAAE,EAAE,UAAU,EAAE,uBAAuB,EAAE;YACxD,cAAc,EAAE,EAAE,UAAU,EAAE,uBAAuB,EAAE;YACvD,aAAa,EAAE,EAAE,UAAU,EAAE,uBAAuB,EAAE;YACtD,YAAY,EAAE,EAAE,UAAU,EAAE,uBAAuB,EAAE;SACtD;KACF;IACD,IAAI,EAAE;QACJ,OAAO,EAAE;YACP;;eAEG;YACH,MAAM,EAAE,SAAS;YAEjB;;eAEG;YACH,SAAS,EAAE,MAAM;YACjB,MAAM,EAAE,CAAC;YACT,MAAM,EAAE,EAAE;YACV,MAAM,EAAE,CAAC;SACV;QACD,aAAa,EAAE;YACb,OAAO,EAAE,IAAI;YACb,SAAS,EAAE,KAAK;YAChB,OAAO,EAAE,iBAAiB;SAC3B;QACD,sEAAsE;QACtE,0EAA0E;QAC1E,sEAAsE;QACtE,yCAAyC;QACzC,QAAQ,EAAE;YACR,qFAAqF;YACrF,4EAA4E;YAE5E;;eAEG;YACH,kBAAkB,EAAE,CAAC;SACtB;KACF;IACD,IAAI,EAAE;IACJ,iBAAiB;IACjB,+CAA+C;IAC/C,KAAK;KACN;CACF,CAAC;AAEF,eAAe,QAAQ,CAAC"}
|
|
@@ -3,6 +3,7 @@ import { BaseController, Ok, BadRequestResponse, Unauthorized } from '@spinajs/h
|
|
|
3
3
|
import { AccessControl, AuthProvider, PasswordProvider, SessionProvider } from '@spinajs/rbac';
|
|
4
4
|
import type { ISession, User } from '@spinajs/rbac';
|
|
5
5
|
import { IActiveRoleResponse } from '@spinajs/rbac-http';
|
|
6
|
+
import { SessionCookieFactory } from '../services/SessionCookies.js';
|
|
6
7
|
/**
|
|
7
8
|
* Active role endpoints.
|
|
8
9
|
* Let users with multiple roles inspect and switch the currently active role.
|
|
@@ -16,7 +17,7 @@ export declare class ActiveRoleController extends BaseController {
|
|
|
16
17
|
protected PasswordProvider: PasswordProvider;
|
|
17
18
|
protected SessionProvider: SessionProvider;
|
|
18
19
|
protected RolesRequiringPassword: string[];
|
|
19
|
-
protected
|
|
20
|
+
protected SessionCookies: SessionCookieFactory;
|
|
20
21
|
/**
|
|
21
22
|
* Get active role
|
|
22
23
|
* Returns the currently active role for the session and the RBAC grants
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ActiveRoleController.d.ts","sourceRoot":"","sources":["../../../src/controllers/ActiveRoleController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,cAAc,EAAwB,EAAE,EAAO,kBAAkB,EAAE,YAAY,EAAU,MAAM,eAAe,CAAC;AACxH,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,gBAAgB,EAAE,eAAe,
|
|
1
|
+
{"version":3,"file":"ActiveRoleController.d.ts","sourceRoot":"","sources":["../../../src/controllers/ActiveRoleController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,cAAc,EAAwB,EAAE,EAAO,kBAAkB,EAAE,YAAY,EAAU,MAAM,eAAe,CAAC;AACxH,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAqB,MAAM,eAAe,CAAC;AAClH,OAAO,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAGpD,OAAO,EAA+E,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACtI,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAGrE;;;;;;GAMG;AACH,qBACa,oBAAqB,SAAQ,cAAc;IAEtD,SAAS,CAAC,EAAE,EAAE,aAAa,CAAC;IAG5B,SAAS,CAAC,YAAY,EAAE,YAAY,CAAC;IAGrC,SAAS,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;IAG7C,SAAS,CAAC,eAAe,EAAE,eAAe,CAAC;IAG3C,SAAS,CAAC,sBAAsB,EAAE,MAAM,EAAE,CAAC;IAG3C,SAAS,CAAC,cAAc,EAAE,oBAAoB,CAAC;IAE/C;;;;;;;OAOG;IAGU,aAAa,CAAiB,IAAI,EAAE,IAAI,EAAiB,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC,mBAAmB,CAAC,CAAC;IAI3H;;;;;;;;;OASG;IAGU,gBAAgB,CACX,IAAI,EAAE,IAAI,EACP,OAAO,EAAE,QAAQ,EAC5B,OAAO,EAAE,aAAa,GAC7B,OAAO,CAAC,EAAE,CAAC,mBAAmB,CAAC,GAAG,kBAAkB,GAAG,YAAY,CAAC;IA0CvE,SAAS,CAAC,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,mBAAmB;CAMjE"}
|