@voltro/plugin-auth 0.86.0 → 0.87.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5321 -0
- package/README.md +83 -0
- package/THIRD-PARTY-NOTICES.md +1130 -11
- package/dist/authExtensions.js +9 -0
- package/dist/emailVerification.js +13 -11
- package/dist/guest.d.ts +99 -0
- package/dist/guest.js +3 -0
- package/dist/guestClient.js +237 -0
- package/dist/guestCredential.js +12 -0
- package/dist/guestPasswordUpgrade.js +85 -0
- package/dist/guestPlugin.js +166 -0
- package/dist/guestSchema.js +20 -0
- package/dist/guestSecrets.js +10 -0
- package/dist/guestService.js +224 -0
- package/dist/handlers.js +113 -113
- package/dist/impersonation.js +79 -78
- package/dist/index.d.ts +265 -15
- package/dist/index.js +27 -19
- package/dist/invitations.js +23 -23
- package/dist/native/guestStorage.js +41 -0
- package/dist/native.d.ts +110 -0
- package/dist/native.js +45 -43
- package/dist/nativeRoutes.js +61 -72
- package/dist/overlayPlugin.js +167 -0
- package/dist/plugin.d.ts +119 -10
- package/dist/plugin.js +99 -78
- package/dist/postgresUserStore.js +19 -7
- package/dist/revocation.js +40 -23
- package/dist/schema.d.ts +41 -1
- package/dist/schema.js +99 -98
- package/dist/sessionFamily.js +15 -0
- package/dist/sessionRegistry.js +93 -78
- package/dist/signedClaims.js +24 -0
- package/dist/strategy.d.ts +13 -9
- package/dist/strategy.js +26 -22
- package/dist/userStore.js +145 -138
- package/dist/web/guestStorage.js +47 -0
- package/dist/web.d.ts +94 -0
- package/dist/web.js +4 -2
- package/package.json +8 -3
package/dist/impersonation.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { isSessionCredentialLiveFor as e } from "./sessionFamily.js";
|
|
2
|
+
import { newAuthId as t, subjectFromUser as n } from "./userStore.js";
|
|
3
|
+
import { Effect as r } from "effect";
|
|
4
|
+
import { IMPERSONATION_METADATA_KEY as i, rawImpersonationMark as a } from "@voltro/protocol";
|
|
4
5
|
//#region src/impersonation.ts
|
|
5
|
-
var
|
|
6
|
+
var o = 900, s = [
|
|
6
7
|
"/mfa/enroll/start",
|
|
7
8
|
"/mfa/enroll/verify",
|
|
8
9
|
"/mfa/unenroll",
|
|
@@ -12,7 +13,7 @@ var a = 900, o = [
|
|
|
12
13
|
"/sessions/revoke-others",
|
|
13
14
|
"/switch-tenant",
|
|
14
15
|
"/impersonate/start"
|
|
15
|
-
],
|
|
16
|
+
], c = (e) => {
|
|
16
17
|
if (typeof e != "object" || !e) return null;
|
|
17
18
|
let t = e;
|
|
18
19
|
return typeof t.actorUserId != "string" || t.actorUserId.length === 0 || typeof t.grantId != "string" || typeof t.expiresAt != "string" || typeof t.actorSessionId != "string" || typeof t.startedAt != "string" ? null : {
|
|
@@ -23,93 +24,93 @@ var a = 900, o = [
|
|
|
23
24
|
expiresAt: t.expiresAt,
|
|
24
25
|
...typeof t.reason == "string" ? { reason: t.reason } : {}
|
|
25
26
|
};
|
|
26
|
-
},
|
|
27
|
+
}, l = (e) => e.type === "user" ? c(a(e)) : null, u = (e) => l(e) !== null, d = () => (e) => {
|
|
27
28
|
if (e.type !== "user" || e.metadata === void 0) return e;
|
|
28
|
-
let t =
|
|
29
|
+
let t = c(e.metadata[i]), { metadata: n, ...r } = e;
|
|
29
30
|
return {
|
|
30
|
-
...
|
|
31
|
+
...r,
|
|
31
32
|
metadata: t === null ? { __redacted: "all" } : {
|
|
32
33
|
__redacted: "all-except-impersonation",
|
|
33
|
-
[
|
|
34
|
+
[i]: t
|
|
34
35
|
}
|
|
35
36
|
};
|
|
36
|
-
},
|
|
37
|
+
}, f = (e, t, n = {}) => ({
|
|
37
38
|
status: e,
|
|
38
39
|
body: JSON.stringify(t),
|
|
39
40
|
contentType: "application/json; charset=utf-8",
|
|
40
41
|
...n
|
|
41
|
-
}),
|
|
42
|
-
let
|
|
43
|
-
return
|
|
44
|
-
try: () => Promise.resolve(
|
|
42
|
+
}), p = (e, t) => r.suspend(() => {
|
|
43
|
+
let n = e.audit(t);
|
|
44
|
+
return n === void 0 ? r.void : r.isEffect(n) ? n : r.tryPromise({
|
|
45
|
+
try: () => Promise.resolve(n),
|
|
45
46
|
catch: (e) => e
|
|
46
47
|
});
|
|
47
|
-
}).pipe(
|
|
48
|
-
let s = o.impersonation, c = (o.now ?? Date.now)(),
|
|
48
|
+
}).pipe(r.catchCause(() => r.void)), m = (e, a, o) => r.gen(function* () {
|
|
49
|
+
let s = o.impersonation, c = (o.now ?? Date.now)(), l = new Date(c), d = e.actorSubject, m = (t, n, i = {}) => p(s, {
|
|
49
50
|
kind: "refused",
|
|
50
|
-
at:
|
|
51
|
-
actorUserId:
|
|
52
|
-
actorEmail:
|
|
53
|
-
targetUserId:
|
|
54
|
-
targetEmail:
|
|
55
|
-
tenantId:
|
|
56
|
-
reason:
|
|
57
|
-
refusal:
|
|
58
|
-
ipAddress:
|
|
59
|
-
userAgent:
|
|
60
|
-
}).pipe(
|
|
61
|
-
error:
|
|
62
|
-
...
|
|
51
|
+
at: l,
|
|
52
|
+
actorUserId: i.actorUser?.id ?? (d.type === "user" ? d.id : null),
|
|
53
|
+
actorEmail: i.actorUser?.email ?? null,
|
|
54
|
+
targetUserId: i.target?.id ?? null,
|
|
55
|
+
targetEmail: i.target?.email ?? null,
|
|
56
|
+
tenantId: d.tenantId ?? null,
|
|
57
|
+
reason: e.reason ?? null,
|
|
58
|
+
refusal: n,
|
|
59
|
+
ipAddress: e.ipAddress ?? null,
|
|
60
|
+
userAgent: e.userAgent ?? null
|
|
61
|
+
}).pipe(r.as(f(t, {
|
|
62
|
+
error: n,
|
|
63
|
+
...i.message === void 0 ? {} : { message: i.message }
|
|
63
64
|
})));
|
|
64
|
-
if (
|
|
65
|
-
if (
|
|
66
|
-
if (!
|
|
67
|
-
let h = yield* a.findById(
|
|
65
|
+
if (d.type !== "user") return yield* m(401, "unauthenticated");
|
|
66
|
+
if (u(d)) return yield* m(403, "nested_impersonation", { message: "An impersonated session may not start another impersonation. Stop the current one first." });
|
|
67
|
+
if (!e.actorSessionId) return yield* m(400, "no_actor_session");
|
|
68
|
+
let h = yield* a.findById(d.id);
|
|
68
69
|
if (!h) return yield* m(401, "unauthenticated");
|
|
69
|
-
if (!
|
|
70
|
-
let g =
|
|
70
|
+
if (!e.targetUserId && !e.targetEmail) return yield* m(400, "target_required", { actorUser: h });
|
|
71
|
+
let g = e.targetUserId ? yield* a.findById(e.targetUserId) : yield* a.findByEmail(e.targetEmail);
|
|
71
72
|
if (!g) return yield* m(404, "target_not_found", { actorUser: h });
|
|
72
73
|
if (g.id === h.id) return yield* m(400, "self_impersonation", {
|
|
73
74
|
actorUser: h,
|
|
74
75
|
target: g
|
|
75
76
|
});
|
|
76
|
-
let _ =
|
|
77
|
+
let _ = e.reason?.trim() ?? "";
|
|
77
78
|
if ((s.requireReason ?? !0) && _.length === 0) return yield* m(400, "reason_required", {
|
|
78
79
|
actorUser: h,
|
|
79
80
|
target: g,
|
|
80
81
|
message: "A reason is required to impersonate a user."
|
|
81
82
|
});
|
|
82
83
|
if (!(yield* s.authority({
|
|
83
|
-
actor:
|
|
84
|
+
actor: d,
|
|
84
85
|
actorUser: h,
|
|
85
86
|
target: g
|
|
86
|
-
}).pipe(
|
|
87
|
+
}).pipe(r.catchCause(() => r.succeed(!1))))) return yield* m(403, "not_permitted", {
|
|
87
88
|
actorUser: h,
|
|
88
89
|
target: g
|
|
89
90
|
});
|
|
90
91
|
if (yield* s.authority({
|
|
91
|
-
actor:
|
|
92
|
+
actor: n(g),
|
|
92
93
|
actorUser: g,
|
|
93
94
|
target: h
|
|
94
|
-
}).pipe(
|
|
95
|
+
}).pipe(r.catchCause(() => r.succeed(!0)))) return yield* m(403, "target_may_impersonate", {
|
|
95
96
|
actorUser: h,
|
|
96
97
|
target: g,
|
|
97
98
|
message: "This user may themselves impersonate others and cannot be impersonated."
|
|
98
99
|
});
|
|
99
|
-
let v = s.maxDurationSeconds ?? 900, y = Math.max(1, Math.min(
|
|
100
|
-
id:
|
|
100
|
+
let v = s.maxDurationSeconds ?? 900, y = Math.max(1, Math.min(e.durationSeconds ?? v, v)), b = new Date(c + y * 1e3), x = t("sess"), S = yield* a.insertImpersonationGrant({
|
|
101
|
+
id: t("imp"),
|
|
101
102
|
sessionId: x,
|
|
102
103
|
actorUserId: h.id,
|
|
103
|
-
actorSessionId:
|
|
104
|
+
actorSessionId: e.actorSessionId,
|
|
104
105
|
targetUserId: g.id,
|
|
105
106
|
tenantId: g.tenantId,
|
|
106
107
|
reason: _.length > 0 ? _ : null,
|
|
107
108
|
expiresAt: b,
|
|
108
|
-
ipAddress:
|
|
109
|
-
userAgent:
|
|
109
|
+
ipAddress: e.ipAddress ?? null,
|
|
110
|
+
userAgent: e.userAgent ?? null
|
|
110
111
|
}), C = {
|
|
111
112
|
actorUserId: h.id,
|
|
112
|
-
actorSessionId:
|
|
113
|
+
actorSessionId: e.actorSessionId,
|
|
113
114
|
grantId: S.id,
|
|
114
115
|
startedAt: S.startedAt.toISOString(),
|
|
115
116
|
expiresAt: b.toISOString(),
|
|
@@ -117,13 +118,13 @@ var a = 900, o = [
|
|
|
117
118
|
}, w = yield* o.issuer.issue(g, {
|
|
118
119
|
sessionId: x,
|
|
119
120
|
ttlSeconds: y,
|
|
120
|
-
metadata: { [
|
|
121
|
-
ipAddress:
|
|
122
|
-
userAgent:
|
|
121
|
+
metadata: { [i]: C },
|
|
122
|
+
ipAddress: e.ipAddress ?? null,
|
|
123
|
+
userAgent: e.userAgent ?? null
|
|
123
124
|
});
|
|
124
|
-
return yield*
|
|
125
|
+
return yield* p(s, {
|
|
125
126
|
kind: "started",
|
|
126
|
-
at:
|
|
127
|
+
at: l,
|
|
127
128
|
actorUserId: h.id,
|
|
128
129
|
actorEmail: h.email,
|
|
129
130
|
targetUserId: g.id,
|
|
@@ -133,43 +134,43 @@ var a = 900, o = [
|
|
|
133
134
|
grantId: S.id,
|
|
134
135
|
reason: _.length > 0 ? _ : null,
|
|
135
136
|
expiresAt: b,
|
|
136
|
-
ipAddress:
|
|
137
|
-
userAgent:
|
|
138
|
-
}),
|
|
137
|
+
ipAddress: e.ipAddress ?? null,
|
|
138
|
+
userAgent: e.userAgent ?? null
|
|
139
|
+
}), f(200, {
|
|
139
140
|
ok: !0,
|
|
140
141
|
impersonation: C,
|
|
141
142
|
subject: w.subject
|
|
142
143
|
}, { setCookie: w.setCookie });
|
|
143
|
-
}),
|
|
144
|
-
let
|
|
145
|
-
if (!
|
|
146
|
-
let
|
|
147
|
-
yield*
|
|
148
|
-
let
|
|
149
|
-
if (yield*
|
|
144
|
+
}), h = (t, n, i) => r.gen(function* () {
|
|
145
|
+
let a = i.impersonation, o = (i.now ?? Date.now)(), s = new Date(o), c = l(t.subject);
|
|
146
|
+
if (!c || !t.sessionId) return f(400, { error: "not_impersonating" });
|
|
147
|
+
let u = yield* n.findImpersonationGrantBySession(t.sessionId);
|
|
148
|
+
yield* n.endImpersonationGrant(t.sessionId, "stopped", s).pipe(r.ignore), t.subject.type === "user" && (yield* n.revokeSession(t.subject.id, t.sessionId).pipe(r.ignore)), i.invalidateSession?.(t.sessionId);
|
|
149
|
+
let d = yield* n.findById(c.actorUserId), m = yield* n.findSession(c.actorSessionId), h = m ? Math.floor((m.expiresAt.getTime() - o) / 1e3) : 0;
|
|
150
|
+
if (yield* p(a, {
|
|
150
151
|
kind: "stopped",
|
|
151
|
-
at:
|
|
152
|
-
actorUserId:
|
|
153
|
-
actorEmail:
|
|
154
|
-
targetUserId:
|
|
152
|
+
at: s,
|
|
153
|
+
actorUserId: c.actorUserId,
|
|
154
|
+
actorEmail: d?.email ?? null,
|
|
155
|
+
targetUserId: t.subject.type === "user" ? t.subject.id : null,
|
|
155
156
|
targetEmail: null,
|
|
156
|
-
tenantId:
|
|
157
|
-
sessionId:
|
|
158
|
-
...
|
|
159
|
-
reason:
|
|
160
|
-
}), !
|
|
157
|
+
tenantId: u?.tenantId ?? t.subject.tenantId ?? null,
|
|
158
|
+
sessionId: t.sessionId,
|
|
159
|
+
...u ? { grantId: u.id } : {},
|
|
160
|
+
reason: u?.reason ?? null
|
|
161
|
+
}), !d || !e(m, c.actorSessionId, d.id, o) || !Number.isSafeInteger(h) || h <= 0) return f(200, {
|
|
161
162
|
ok: !0,
|
|
162
163
|
restored: !1
|
|
163
|
-
}, { setCookie:
|
|
164
|
-
let
|
|
165
|
-
sessionId:
|
|
166
|
-
ttlSeconds:
|
|
164
|
+
}, { setCookie: i.issuer.clear() });
|
|
165
|
+
let g = yield* i.issuer.reissue(d, {
|
|
166
|
+
sessionId: c.actorSessionId,
|
|
167
|
+
ttlSeconds: h
|
|
167
168
|
});
|
|
168
|
-
return
|
|
169
|
+
return f(200, {
|
|
169
170
|
ok: !0,
|
|
170
171
|
restored: !0,
|
|
171
|
-
subject:
|
|
172
|
-
}, { setCookie:
|
|
172
|
+
subject: g.subject
|
|
173
|
+
}, { setCookie: g.setCookie });
|
|
173
174
|
});
|
|
174
175
|
//#endregion
|
|
175
|
-
export {
|
|
176
|
+
export { o as IMPERSONATION_DEFAULT_DURATION_S, s as IMPERSONATION_FORBIDDEN_SUBPATHS, m as handleImpersonationStart, h as handleImpersonationStop, d as impersonationAuditRedactor, l as impersonationOf, u as isImpersonated };
|