@voltro/plugin-auth 0.32.0 → 0.34.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/dist/index.js CHANGED
@@ -1,28 +1,28 @@
1
1
  import { PasswordEmptyError as e, PasswordHashError as t, hashPassword as n, needsRehash as r, parseScryptParams as i, verifyPassword as a, verifyPasswordWithRehash as o } from "./password.js";
2
2
  import { SESSION_COOKIE_NAME as s, clearSessionCookie as c, issueSession as l, readSession as u, readSessionKeyed as d, resolveSessionSecret as f, resolveSessionSecrets as p, sessionSecretsOf as m } from "./session.js";
3
- import { a as h, c as g, i as _, l as v, n as y, o as b, r as x, s as S, t as C } from "./strategy-Ce4FlGi4.js";
4
- import { A as w, C as T, D as E, E as D, F as O, I as k, L as A, M as ee, N as te, O as j, P as M, S as N, T as P, _ as F, a as I, b as L, c as R, d as z, f as B, g as V, h as H, i as U, j as W, k as G, l as K, m as q, n as J, o as Y, p as X, r as ne, s as Z, t as re, u as ie, v as ae, w as oe, x as se, y as ce } from "./plugin-ZXs8LFn0.js";
5
- import { MAGIC_LINK_TTL_S as le, PASSWORD_RESET_TTL_S as ue, hashToken as de, mintToken as fe } from "./tokens.js";
6
- import { CSRF_COOKIE_NAME as pe, CSRF_HEADER_NAME as me, isCsrfTokenWellFormed as Q, issueCsrfToken as he, verifyCsrf as ge } from "./csrf.js";
7
- import { generateChallenge as _e, verifyAssertion as ve, verifyRegistration as ye } from "./webauthn.js";
3
+ import { a as h, c as g, i as _, l as v, n as y, o as b, r as x, s as S, t as C } from "./strategy-Bty6_XUj.js";
4
+ import { $ as w, A as T, B as E, C as D, D as O, E as k, F as A, G as j, H as M, I as N, J as P, K as F, L as I, M as L, N as R, O as z, P as B, Q as V, R as H, S as ee, T as te, U as ne, V as U, W, X as G, Y as K, Z as q, _ as J, a as Y, at as X, b as Z, c as re, ct as ie, d as ae, dt as oe, et as se, f as ce, g as le, h as ue, i as de, it as fe, j as pe, k as me, l as he, lt as ge, m as _e, n as ve, nt as ye, o as be, ot as xe, p as Se, q as Ce, r as we, rt as Te, s as Ee, st as De, t as Oe, tt as ke, u as Ae, ut as je, v as Me, w as Ne, x as Pe, y as Fe, z as Ie } from "./plugin-BZm5Semm.js";
5
+ import { EMAIL_VERIFY_TTL_S as Le, MAGIC_LINK_TTL_S as Re, MFA_PENDING_TTL_S as ze, PASSWORD_RESET_TTL_S as Be, hashToken as Ve, mintSecret as He, mintToken as Q } from "./tokens.js";
6
+ import { CSRF_COOKIE_NAME as Ue, CSRF_HEADER_NAME as We, isCsrfTokenWellFormed as Ge, issueCsrfToken as Ke, verifyCsrf as qe } from "./csrf.js";
7
+ import { generateChallenge as Je, verifyAssertion as Ye, verifyRegistration as Xe } from "./webauthn.js";
8
8
  import { Effect as $ } from "effect";
9
9
  //#region src/postgresUserStore.ts
10
- var be = (e) => {
10
+ var Ze = (e) => {
11
11
  let t = e?.code;
12
12
  if (typeof t == "string") return t;
13
13
  let n = e?.cause?.code;
14
14
  return typeof n == "string" ? n : void 0;
15
- }, xe = (e) => {
15
+ }, Qe = (e) => {
16
16
  let t = (t) => $.gen(function* () {
17
17
  return (yield* e`
18
- SELECT id, email, "passwordHash", "tenantId", "createdAt", "mfaSecret", "mfaEnrolledAt"
18
+ SELECT id, email, "passwordHash", "tenantId", "createdAt", "mfaSecret", "mfaEnrolledAt", "emailVerifiedAt"
19
19
  FROM users
20
20
  WHERE email = ${t.toLowerCase()}
21
21
  LIMIT 1
22
22
  `)[0] ?? null;
23
23
  }).pipe($.orElseSucceed(() => null)), n = (t) => $.gen(function* () {
24
24
  return (yield* e`
25
- SELECT id, email, "passwordHash", "tenantId", "createdAt", "mfaSecret", "mfaEnrolledAt"
25
+ SELECT id, email, "passwordHash", "tenantId", "createdAt", "mfaSecret", "mfaEnrolledAt", "emailVerifiedAt"
26
26
  FROM users
27
27
  WHERE id = ${t}
28
28
  LIMIT 1
@@ -36,10 +36,10 @@ var be = (e) => {
36
36
  ...t,
37
37
  email: n,
38
38
  createdAt: r
39
- })), $.catchAll((e) => be(e) === "23505" ? $.fail(new y({ email: n })) : $.die(e)));
39
+ })), $.catchAll((e) => Ze(e) === "23505" ? $.fail(new y({ email: n })) : $.die(e)));
40
40
  }), i = (t) => $.gen(function* () {
41
41
  return (yield* e`
42
- SELECT id, email, "passwordHash", "tenantId", "createdAt", "mfaSecret", "mfaEnrolledAt"
42
+ SELECT id, email, "passwordHash", "tenantId", "createdAt", "mfaSecret", "mfaEnrolledAt", "emailVerifiedAt"
43
43
  FROM users WHERE id = ${t} LIMIT 1
44
44
  `)[0] || (yield* $.fail(new x({ userId: t })));
45
45
  }).pipe($.catchTag("SqlError", (e) => $.die(e))), a = (t, n) => $.gen(function* () {
@@ -66,12 +66,18 @@ var be = (e) => {
66
66
  WHERE id = ${t}
67
67
  `.pipe($.catchTag("SqlError", (e) => $.die(e))), yield* i(t);
68
68
  }), l = (t) => $.gen(function* () {
69
+ return yield* e`
70
+ UPDATE users
71
+ SET "emailVerifiedAt" = ${/* @__PURE__ */ new Date()}, "updatedAt" = ${/* @__PURE__ */ new Date()}
72
+ WHERE id = ${t} AND "emailVerifiedAt" IS NULL
73
+ `.pipe($.catchTag("SqlError", (e) => $.die(e))), yield* i(t);
74
+ }), u = (t) => $.gen(function* () {
69
75
  return (yield* e`
70
76
  SELECT "userId", "tenantId", role, "joinedAt"
71
77
  FROM memberships WHERE "userId" = ${t}
72
78
  ORDER BY "joinedAt" ASC
73
79
  `).map((e) => ({ ...e }));
74
- }).pipe($.orElseSucceed(() => [])), u = (t) => $.gen(function* () {
80
+ }).pipe($.orElseSucceed(() => [])), d = (t) => $.gen(function* () {
75
81
  let n = /* @__PURE__ */ new Date();
76
82
  yield* e`
77
83
  UPDATE memberships SET role = ${t.role}
@@ -93,18 +99,18 @@ var be = (e) => {
93
99
  }).pipe($.catchAll(() => $.succeed({
94
100
  ...t,
95
101
  joinedAt: /* @__PURE__ */ new Date()
96
- }))), d = (t, n) => $.gen(function* () {
102
+ }))), f = (t, n) => $.gen(function* () {
97
103
  return (yield* e`
98
104
  SELECT role FROM memberships
99
105
  WHERE "userId" = ${t} AND "tenantId" = ${n} LIMIT 1
100
106
  `)[0]?.role ?? null;
101
- }).pipe($.orElseSucceed(() => null)), f = (t) => $.gen(function* () {
107
+ }).pipe($.orElseSucceed(() => null)), p = (t) => $.gen(function* () {
102
108
  return (yield* e`
103
109
  SELECT id, "userId", "tenantId", "expiresAt", "ipAddress", "userAgent", "createdAt", "lastSeenAt"
104
110
  FROM sessions WHERE "userId" = ${t}
105
111
  ORDER BY "createdAt" DESC
106
112
  `).map((e) => ({ ...e }));
107
- }).pipe($.orElseSucceed(() => [])), p = (t) => $.gen(function* () {
113
+ }).pipe($.orElseSucceed(() => [])), m = (t) => $.gen(function* () {
108
114
  let n = /* @__PURE__ */ new Date();
109
115
  return yield* e`
110
116
  INSERT INTO sessions (id, "userId", "tenantId", "expiresAt", "ipAddress", "userAgent", "createdAt", "lastSeenAt")
@@ -121,28 +127,28 @@ var be = (e) => {
121
127
  ...t,
122
128
  createdAt: /* @__PURE__ */ new Date(),
123
129
  lastSeenAt: /* @__PURE__ */ new Date()
124
- }))), m = (t) => $.gen(function* () {
130
+ }))), g = (t) => $.gen(function* () {
125
131
  let n = yield* e`
126
132
  SELECT id, "userId", "tenantId", "expiresAt", "ipAddress", "userAgent", "createdAt", "lastSeenAt"
127
133
  FROM sessions WHERE id = ${t} LIMIT 1
128
134
  `;
129
135
  return n[0] ? { ...n[0] } : null;
130
- }).pipe($.orElseSucceed(() => null)), g = (t, n) => $.gen(function* () {
136
+ }).pipe($.orElseSucceed(() => null)), _ = (t, n) => $.gen(function* () {
131
137
  yield* e`
132
138
  UPDATE sessions SET "expiresAt" = ${n}, "lastSeenAt" = ${/* @__PURE__ */ new Date()}
133
139
  WHERE id = ${t}
134
140
  `;
135
- }).pipe($.asVoid, $.orElseSucceed(() => void 0)), _ = (t, n) => $.gen(function* () {
141
+ }).pipe($.asVoid, $.orElseSucceed(() => void 0)), v = (t, n) => $.gen(function* () {
136
142
  return (yield* e`
137
143
  DELETE FROM sessions WHERE id = ${n} AND "userId" = ${t}
138
144
  RETURNING id
139
145
  `).length > 0;
140
- }).pipe($.orElseSucceed(() => !1)), v = (t, n) => $.gen(function* () {
146
+ }).pipe($.orElseSucceed(() => !1)), b = (t, n) => $.gen(function* () {
141
147
  return (yield* e`
142
148
  DELETE FROM sessions WHERE "userId" = ${t} AND id <> ${n}
143
149
  RETURNING id
144
150
  `).length;
145
- }).pipe($.orElseSucceed(() => 0)), b = (t) => $.gen(function* () {
151
+ }).pipe($.orElseSucceed(() => 0)), S = (t) => $.gen(function* () {
146
152
  let n = /* @__PURE__ */ new Date();
147
153
  return yield* e`
148
154
  INSERT INTO "authTokens" (id, "tokenHash", "userId", purpose, "expiresAt", "consumedAt", "createdAt")
@@ -156,7 +162,7 @@ var be = (e) => {
156
162
  ...t,
157
163
  consumedAt: null,
158
164
  createdAt: /* @__PURE__ */ new Date()
159
- }))), S = (t, n) => $.gen(function* () {
165
+ }))), C = (t, n) => $.gen(function* () {
160
166
  let r = yield* e`
161
167
  UPDATE "authTokens"
162
168
  SET "consumedAt" = ${/* @__PURE__ */ new Date()}
@@ -167,18 +173,130 @@ var be = (e) => {
167
173
  RETURNING id, "tokenHash", "userId", purpose, "expiresAt", "consumedAt", "createdAt"
168
174
  `;
169
175
  return r[0] ? { ...r[0] } : null;
170
- }).pipe($.orElseSucceed(() => null)), C = (t) => $.gen(function* () {
176
+ }).pipe($.orElseSucceed(() => null)), w = (t, n) => $.gen(function* () {
177
+ let r = yield* e`
178
+ SELECT id, "tokenHash", "userId", purpose, "expiresAt", "consumedAt", "createdAt"
179
+ FROM "authTokens"
180
+ WHERE "userId" = ${t} AND purpose = ${n}
181
+ ORDER BY "createdAt" DESC
182
+ LIMIT 1
183
+ `;
184
+ return r[0] ? { ...r[0] } : null;
185
+ }).pipe($.orElseSucceed(() => null)), T = (t) => $.gen(function* () {
186
+ let n = /* @__PURE__ */ new Date(), r = t.email.toLowerCase();
187
+ return yield* e`
188
+ INSERT INTO invitations (
189
+ id, "tokenHash", email, "tenantId", role, "invitedByUserId",
190
+ "expiresAt", "acceptedAt", "acceptedByUserId", "revokedAt", "revokedByUserId", "createdAt"
191
+ ) VALUES (
192
+ ${t.id}, ${t.tokenHash}, ${r}, ${t.tenantId},
193
+ ${t.role}, ${t.invitedByUserId}, ${t.expiresAt},
194
+ ${null}, ${null}, ${null}, ${null}, ${n}
195
+ )
196
+ `, {
197
+ ...t,
198
+ email: r,
199
+ acceptedAt: null,
200
+ acceptedByUserId: null,
201
+ revokedAt: null,
202
+ revokedByUserId: null,
203
+ createdAt: n
204
+ };
205
+ }).pipe($.catchAll((e) => $.die(e))), E = (t) => $.gen(function* () {
206
+ let n = yield* e`
207
+ SELECT id, "tokenHash", email, "tenantId", role, "invitedByUserId", "expiresAt",
208
+ "acceptedAt", "acceptedByUserId", "revokedAt", "revokedByUserId", "createdAt"
209
+ FROM invitations WHERE "tokenHash" = ${t} LIMIT 1
210
+ `;
211
+ return n[0] ? { ...n[0] } : null;
212
+ }).pipe($.orElseSucceed(() => null)), D = (t, n, r) => $.gen(function* () {
213
+ let i = yield* e`
214
+ UPDATE invitations
215
+ SET "acceptedAt" = ${r}, "acceptedByUserId" = ${n}
216
+ WHERE "tokenHash" = ${t}
217
+ AND "acceptedAt" IS NULL
218
+ AND "revokedAt" IS NULL
219
+ AND "expiresAt" > ${r}
220
+ RETURNING id, "tokenHash", email, "tenantId", role, "invitedByUserId", "expiresAt",
221
+ "acceptedAt", "acceptedByUserId", "revokedAt", "revokedByUserId", "createdAt"
222
+ `;
223
+ return i[0] ? { ...i[0] } : null;
224
+ }).pipe($.catchAll((e) => $.die(e))), O = (t, n, r, i) => $.gen(function* () {
225
+ return (yield* e`
226
+ UPDATE invitations
227
+ SET "revokedAt" = ${i}, "revokedByUserId" = ${r}
228
+ WHERE id = ${t}
229
+ AND "tenantId" = ${n}
230
+ AND "acceptedAt" IS NULL
231
+ AND "revokedAt" IS NULL
232
+ RETURNING id
233
+ `).length > 0;
234
+ }).pipe($.catchAll((e) => $.die(e))), k = (t) => $.gen(function* () {
235
+ return (yield* e`
236
+ SELECT id, "tokenHash", email, "tenantId", role, "invitedByUserId", "expiresAt",
237
+ "acceptedAt", "acceptedByUserId", "revokedAt", "revokedByUserId", "createdAt"
238
+ FROM invitations WHERE "tenantId" = ${t}
239
+ ORDER BY "createdAt" DESC
240
+ `).map((e) => ({ ...e }));
241
+ }).pipe($.orElseSucceed(() => [])), A = (t, n) => $.gen(function* () {
242
+ return (yield* e`
243
+ SELECT COUNT(*)::int AS n FROM invitations
244
+ WHERE "tenantId" = ${t}
245
+ AND "acceptedAt" IS NULL AND "revokedAt" IS NULL AND "expiresAt" > ${n}
246
+ `)[0]?.n ?? 0;
247
+ }).pipe($.catchAll((e) => $.die(e))), j = (t, n, r, i) => $.gen(function* () {
248
+ return (yield* e`
249
+ UPDATE invitations
250
+ SET "revokedAt" = ${i}, "revokedByUserId" = ${r}
251
+ WHERE "tenantId" = ${t}
252
+ AND email = ${n.toLowerCase()}
253
+ AND "acceptedAt" IS NULL
254
+ AND "revokedAt" IS NULL
255
+ RETURNING id
256
+ `).length;
257
+ }).pipe($.catchAll((e) => $.die(e))), M = (t) => $.gen(function* () {
258
+ let n = /* @__PURE__ */ new Date();
259
+ return yield* e`
260
+ INSERT INTO "impersonationGrants" (
261
+ id, "sessionId", "actorUserId", "actorSessionId", "targetUserId", "tenantId",
262
+ reason, "startedAt", "expiresAt", "endedAt", "endedReason", "ipAddress", "userAgent"
263
+ ) VALUES (
264
+ ${t.id}, ${t.sessionId}, ${t.actorUserId}, ${t.actorSessionId},
265
+ ${t.targetUserId}, ${t.tenantId}, ${t.reason ?? null}, ${n},
266
+ ${t.expiresAt}, ${null}, ${null}, ${t.ipAddress ?? null}, ${t.userAgent ?? null}
267
+ )
268
+ `, {
269
+ ...t,
270
+ startedAt: n,
271
+ endedAt: null,
272
+ endedReason: null
273
+ };
274
+ }).pipe($.catchAll((e) => $.die(e))), N = (t) => $.gen(function* () {
275
+ let n = yield* e`
276
+ SELECT id, "sessionId", "actorUserId", "actorSessionId", "targetUserId", "tenantId",
277
+ reason, "startedAt", "expiresAt", "endedAt", "endedReason", "ipAddress", "userAgent"
278
+ FROM "impersonationGrants" WHERE "sessionId" = ${t} LIMIT 1
279
+ `;
280
+ return n[0] ? { ...n[0] } : null;
281
+ }).pipe($.orElseSucceed(() => null)), P = (t, n, r) => $.gen(function* () {
282
+ return (yield* e`
283
+ UPDATE "impersonationGrants"
284
+ SET "endedAt" = ${r}, "endedReason" = ${n}
285
+ WHERE "sessionId" = ${t} AND "endedAt" IS NULL
286
+ RETURNING id
287
+ `).length > 0;
288
+ }).pipe($.catchAll((e) => $.die(e))), F = (t) => $.gen(function* () {
171
289
  return (yield* e`
172
290
  SELECT id, "credentialId", "userId", "publicKey", counter, transports, "createdAt", "lastUsedAt"
173
291
  FROM passkeys WHERE "userId" = ${t}
174
292
  `).map((e) => ({ ...e }));
175
- }).pipe($.orElseSucceed(() => [])), w = (t) => $.gen(function* () {
293
+ }).pipe($.orElseSucceed(() => [])), I = (t) => $.gen(function* () {
176
294
  let n = yield* e`
177
295
  SELECT id, "credentialId", "userId", "publicKey", counter, transports, "createdAt", "lastUsedAt"
178
296
  FROM passkeys WHERE "credentialId" = ${t} LIMIT 1
179
297
  `;
180
298
  return n[0] ? { ...n[0] } : null;
181
- }).pipe($.orElseSucceed(() => null)), T = (t) => $.gen(function* () {
299
+ }).pipe($.orElseSucceed(() => null)), L = (t) => $.gen(function* () {
182
300
  let n = /* @__PURE__ */ new Date();
183
301
  return yield* e`
184
302
  INSERT INTO passkeys (id, "credentialId", "userId", "publicKey", counter, transports, "createdAt", "lastUsedAt")
@@ -195,7 +313,7 @@ var be = (e) => {
195
313
  ...t,
196
314
  createdAt: /* @__PURE__ */ new Date(),
197
315
  lastUsedAt: null
198
- }))), E = (t, n) => $.gen(function* () {
316
+ }))), R = (t, n) => $.gen(function* () {
199
317
  return (yield* e`
200
318
  UPDATE passkeys
201
319
  SET counter = ${n}, "lastUsedAt" = ${/* @__PURE__ */ new Date()}
@@ -203,14 +321,14 @@ var be = (e) => {
203
321
  AND counter < ${n}
204
322
  RETURNING id
205
323
  `).length > 0;
206
- }).pipe($.orElseSucceed(() => !1)), D = (t, n) => $.gen(function* () {
324
+ }).pipe($.orElseSucceed(() => !1)), z = (t, n) => $.gen(function* () {
207
325
  let r = /* @__PURE__ */ new Date();
208
326
  yield* e`DELETE FROM "recoveryCodes" WHERE "userId" = ${t}`;
209
327
  for (let i of n) yield* e`
210
328
  INSERT INTO "recoveryCodes" (id, "userId", "codeHash", "consumedAt", "createdAt")
211
329
  VALUES (${h("rc")}, ${t}, ${i}, ${null}, ${r})
212
330
  `;
213
- }).pipe($.asVoid, $.orElseSucceed(() => void 0)), O = (t, n) => $.gen(function* () {
331
+ }).pipe($.asVoid, $.orElseSucceed(() => void 0)), B = (t, n) => $.gen(function* () {
214
332
  return (yield* e`
215
333
  UPDATE "recoveryCodes"
216
334
  SET "consumedAt" = ${/* @__PURE__ */ new Date()}
@@ -219,12 +337,12 @@ var be = (e) => {
219
337
  AND "consumedAt" IS NULL
220
338
  RETURNING id
221
339
  `).length > 0;
222
- }).pipe($.orElseSucceed(() => !1)), k = (t) => $.gen(function* () {
340
+ }).pipe($.orElseSucceed(() => !1)), V = (t) => $.gen(function* () {
223
341
  return (yield* e`
224
342
  SELECT COUNT(*)::int AS n FROM "recoveryCodes"
225
343
  WHERE "userId" = ${t} AND "consumedAt" IS NULL
226
344
  `)[0]?.n ?? 0;
227
- }).pipe($.orElseSucceed(() => 0)), A = (e, t) => $.catchAll((n) => $.logWarning(`[auth] lockout ${e} failed — brute-force protection is not counting`).pipe($.annotateLogs("cause", String(n)), $.as(t)));
345
+ }).pipe($.orElseSucceed(() => 0)), H = (e, t) => $.catchAll((n) => $.logWarning(`[auth] lockout ${e} failed — brute-force protection is not counting`).pipe($.annotateLogs("cause", String(n)), $.as(t)));
228
346
  return {
229
347
  findByEmail: t,
230
348
  findById: n,
@@ -233,24 +351,36 @@ var be = (e) => {
233
351
  setMfaSecret: o,
234
352
  markMfaEnrolled: s,
235
353
  clearMfa: c,
236
- listMemberships: l,
237
- addMembership: u,
238
- membershipRole: d,
239
- listSessions: f,
240
- insertSession: p,
241
- findSession: m,
242
- touchSession: g,
243
- revokeSession: _,
244
- revokeAllOtherSessions: v,
245
- insertToken: b,
246
- consumeToken: S,
247
- replaceRecoveryCodes: D,
248
- consumeRecoveryCode: O,
249
- countRecoveryCodes: k,
250
- listPasskeys: C,
251
- findPasskey: w,
252
- insertPasskey: T,
253
- advancePasskeyCounter: E,
354
+ markEmailVerified: l,
355
+ listMemberships: u,
356
+ addMembership: d,
357
+ membershipRole: f,
358
+ listSessions: p,
359
+ insertSession: m,
360
+ findSession: g,
361
+ touchSession: _,
362
+ revokeSession: v,
363
+ revokeAllOtherSessions: b,
364
+ insertToken: S,
365
+ consumeToken: C,
366
+ latestToken: w,
367
+ insertInvitation: T,
368
+ findInvitationByHash: E,
369
+ acceptInvitation: D,
370
+ revokeInvitation: O,
371
+ listInvitations: k,
372
+ countPendingInvitations: A,
373
+ supersedePendingInvitations: j,
374
+ insertImpersonationGrant: M,
375
+ findImpersonationGrantBySession: N,
376
+ endImpersonationGrant: P,
377
+ replaceRecoveryCodes: z,
378
+ consumeRecoveryCode: B,
379
+ countRecoveryCodes: V,
380
+ listPasskeys: F,
381
+ findPasskey: I,
382
+ insertPasskey: L,
383
+ advancePasskeyCounter: R,
254
384
  isLockedOut: (t, n) => $.gen(function* () {
255
385
  let r = (yield* e`
256
386
  SELECT "lockedUntil" FROM "loginAttempts"
@@ -263,7 +393,7 @@ var be = (e) => {
263
393
  locked: !1,
264
394
  retryAfterSeconds: 0
265
395
  };
266
- }).pipe(A("read", {
396
+ }).pipe(H("read", {
267
397
  locked: !1,
268
398
  retryAfterSeconds: 0
269
399
  })),
@@ -281,16 +411,16 @@ var be = (e) => {
281
411
  "lockedUntil" = ${f},
282
412
  "updatedAt" = ${p}
283
413
  `;
284
- }).pipe($.asVoid, A("record", void 0)),
414
+ }).pipe($.asVoid, H("record", void 0)),
285
415
  clearLoginFailures: (t) => $.gen(function* () {
286
416
  yield* e`DELETE FROM "loginAttempts" WHERE email = ${t.toLowerCase()}`;
287
- }).pipe($.asVoid, A("clear", void 0))
417
+ }).pipe($.asVoid, H("clear", void 0))
288
418
  };
289
- }, Se = (e) => (t) => $.runPromise(e.send({
419
+ }, $e = (e) => (t) => $.runPromise(e.send({
290
420
  to: t.to,
291
421
  subject: t.subject,
292
422
  html: t.html,
293
423
  text: t.text
294
424
  }).pipe($.asVoid, $.orElseSucceed(() => void 0)));
295
425
  //#endregion
296
- export { pe as CSRF_COOKIE_NAME, me as CSRF_HEADER_NAME, le as MAGIC_LINK_TTL_S, K as MFA_PENDING_TTL_S, ue as PASSWORD_RESET_TTL_S, e as PasswordEmptyError, t as PasswordHashError, s as SESSION_COOKIE_NAME, W as TotpVerifyError, y as UserAlreadyExistsError, x as UserNotFoundError, re as authRoutesPlugin, c as clearSessionCookie, ie as configSessionSecrets, ne as dataStoreChallengeStore, _e as generateChallenge, ee as generateRecoveryCodes, te as generateTotpCode, M as generateTotpSecret, J as getAuthSessionStrategy, z as guardSubject, B as handleCsrf, X as handleListMemberships, q as handleListSessions, H as handleMagicLinkConsume, V as handleMagicLinkRequest, F as handleMfaEnrollStart, ae as handleMfaEnrollVerify, ce as handleMfaRegenerateRecoveryCodes, L as handleMfaUnenroll, se as handleMfaVerify, U as handlePasskeyAssertOptions, I as handlePasskeyAssertVerify, Y as handlePasskeyRegisterOptions, Z as handlePasskeyRegisterVerify, N as handlePasswordResetConfirm, T as handlePasswordResetRequest, oe as handleRevokeAllOtherSessions, P as handleRevokeSession, D as handleSignIn, E as handleSignOut, j as handleSignUp, G as handleSwitchTenant, n as hashPassword, de as hashToken, Q as isCsrfTokenWellFormed, he as issueCsrfToken, l as issueSession, w as issueUserSession, Se as mailSender, v as makeSessionRevocationChecker, R as memoryChallengeStore, _ as memoryUserStore, fe as mintToken, r as needsRehash, h as newAuthId, O as otpauthUrl, i as parseScryptParams, xe as postgresUserStore, u as readSession, d as readSessionKeyed, f as resolveSessionSecret, p as resolveSessionSecrets, A as runSubjectGuards, b as sessionIdOfSubject, m as sessionSecretsOf, S as subjectFromUser, g as subjectMemberships, ve as verifyAssertion, ge as verifyCsrf, a as verifyPassword, o as verifyPasswordWithRehash, ye as verifyRegistration, k as verifyTotpCode, C as voltroPasswordStrategy };
426
+ export { Ue as CSRF_COOKIE_NAME, We as CSRF_HEADER_NAME, ae as DEFAULT_INVITER_ROLES, ce as DEFAULT_ROLE_RANK, K as EMAIL_NOT_VERIFIED_CODE, G as EMAIL_VERIFIED_METADATA_KEY, q as EMAIL_VERIFY_RESEND_COOLDOWN_S, Le as EMAIL_VERIFY_TTL_S, we as IMPERSONATION_DEFAULT_DURATION_S, de as IMPERSONATION_FORBIDDEN_SUBPATHS, Y as IMPERSONATION_METADATA_KEY, Se as INVITATION_MAX_PENDING, _e as INVITATION_TTL_S, Re as MAGIC_LINK_TTL_S, ze as MFA_PENDING_TTL_S, Be as PASSWORD_RESET_TTL_S, e as PasswordEmptyError, t as PasswordHashError, s as SESSION_COOKIE_NAME, X as TotpVerifyError, y as UserAlreadyExistsError, x as UserNotFoundError, Oe as authRoutesPlugin, c as clearSessionCookie, z as configSessionSecrets, ee as dataStoreChallengeStore, ue as defaultCanGrantRole, V as emailVerificationActive, w as emailVerificationGuard, Je as generateChallenge, xe as generateRecoveryCodes, De as generateTotpCode, ie as generateTotpSecret, ve as getAuthSessionStrategy, me as guardSubject, le as handleAcceptInvitation, J as handleAcceptInvitationWithSignUp, Me as handleCreateInvitation, T as handleCsrf, se as handleEmailVerifyConfirm, ke as handleEmailVerifyRequest, be as handleImpersonationStart, Ee as handleImpersonationStop, Fe as handleListInvitations, pe as handleListMemberships, L as handleListSessions, R as handleMagicLinkConsume, B as handleMagicLinkRequest, A as handleMfaEnrollStart, N as handleMfaEnrollVerify, I as handleMfaRegenerateRecoveryCodes, H as handleMfaUnenroll, Ie as handleMfaVerify, D as handlePasskeyAssertOptions, Ne as handlePasskeyAssertVerify, te as handlePasskeyRegisterOptions, k as handlePasskeyRegisterVerify, E as handlePasswordResetConfirm, U as handlePasswordResetRequest, Z as handlePreviewInvitation, M as handleRevokeAllOtherSessions, Pe as handleRevokeInvitation, ne as handleRevokeSession, W as handleSignIn, j as handleSignOut, F as handleSignUp, Ce as handleSwitchTenant, n as hashPassword, Ve as hashToken, re as impersonationAuditRedactor, he as impersonationOf, Ge as isCsrfTokenWellFormed, ye as isEmailVerified, Ae as isImpersonated, Ke as issueCsrfToken, l as issueSession, P as issueUserSession, $e as mailSender, v as makeSessionRevocationChecker, O as memoryChallengeStore, _ as memoryUserStore, He as mintSecret, Q as mintToken, r as needsRehash, h as newAuthId, ge as otpauthUrl, i as parseScryptParams, Qe as postgresUserStore, u as readSession, d as readSessionKeyed, f as resolveSessionSecret, p as resolveSessionSecrets, oe as runSubjectGuards, Te as sendEmailVerification, b as sessionIdOfSubject, m as sessionSecretsOf, S as subjectFromUser, g as subjectMemberships, fe as userEmailVerified, Ye as verifyAssertion, qe as verifyCsrf, a as verifyPassword, o as verifyPasswordWithRehash, Xe as verifyRegistration, je as verifyTotpCode, C as voltroPasswordStrategy };
@@ -24,7 +24,8 @@ declare interface ParsedHash {
24
24
  }
25
25
 
26
26
  /** Parse the scrypt parameters out of a stored hash. Returns null when the
27
- * string isn't a well-formed `scrypt$N$r$p$salt$derived`. */
27
+ * string isn't a well-formed `scrypt$N$r$p$salt$derived`, or when its
28
+ * parameters exceed the derivation ceiling. */
28
29
  export declare const parseScryptParams: (stored: string) => ParsedHash | null;
29
30
 
30
31
  export declare class PasswordEmptyError extends PasswordEmptyError_base<{
package/dist/password.js CHANGED
@@ -1,16 +1,19 @@
1
1
  import { randomBytes as e, scrypt as t, timingSafeEqual as n } from "node:crypto";
2
2
  import { Data as r, Effect as i } from "effect";
3
3
  //#region src/password.ts
4
- var a = 16384, o = 8, s = 1, c = 32, l = 16, u = class extends r.TaggedError("PasswordEmptyError") {}, d = class extends r.TaggedError("PasswordHashError") {}, f = (e, n, r, a) => i.async((o) => {
5
- t(e, n, r, a, (e, t) => {
6
- o(e ? i.fail(new d({
4
+ var a = 32768, o = 8, s = 1, c = 32, l = 16, u = (e, t) => 128 * e * t * 2, d = 256 * 1024 * 1024, f = class extends r.TaggedError("PasswordEmptyError") {}, p = class extends r.TaggedError("PasswordHashError") {}, m = (e, n, r, a) => i.async((o) => {
5
+ t(e, n, r, {
6
+ ...a,
7
+ maxmem: u(a.N, a.r)
8
+ }, (e, t) => {
9
+ o(e ? i.fail(new p({
7
10
  message: e.message,
8
11
  cause: e
9
12
  })) : i.succeed(t));
10
13
  });
11
- }), p = (t) => i.gen(function* () {
12
- if (t.length === 0) return yield* i.fail(new u({ message: "password must be non-empty" }));
13
- let n = e(l), r = yield* f(t, n, c, {
14
+ }), h = (t) => i.gen(function* () {
15
+ if (t.length === 0) return yield* i.fail(new f({ message: "password must be non-empty" }));
16
+ let n = e(l), r = yield* m(t, n, c, {
14
17
  N: a,
15
18
  r: o,
16
19
  p: s
@@ -23,44 +26,50 @@ var a = 16384, o = 8, s = 1, c = 32, l = 16, u = class extends r.TaggedError("Pa
23
26
  n.toString("base64"),
24
27
  r.toString("base64")
25
28
  ].join("$");
26
- }), m = (e, t) => i.gen(function* () {
27
- let r = t.split("$");
28
- if (r.length !== 6) return !1;
29
- let [i, a, o, s, c, l] = r;
30
- if (i !== "scrypt") return !1;
31
- let u = Number(a), d = Number(o), p = Number(s);
32
- if (!Number.isFinite(u) || !Number.isFinite(d) || !Number.isFinite(p)) return !1;
33
- let m = Buffer.from(c, "base64"), h = Buffer.from(l, "base64"), g = yield* f(e, m, h.length, {
34
- N: u,
35
- r: d,
36
- p
29
+ }), g = (e, t) => i.gen(function* () {
30
+ let r = _(t);
31
+ if (!r) return !1;
32
+ let { N: i, r: a, p: o, salt: s, expected: c } = r, l = yield* m(e, s, c.length, {
33
+ N: i,
34
+ r: a,
35
+ p: o
37
36
  });
38
- return g.length === h.length && n(g, h);
39
- }).pipe(i.catchAll(() => i.succeed(!1))), h = (e) => {
37
+ return l.length === c.length && n(l, c);
38
+ }).pipe(i.catchAll(() => i.succeed(!1))), _ = (e) => {
40
39
  let t = e.split("$");
41
40
  if (t.length !== 6) return null;
42
- let [n, r, i, a, , o] = t;
41
+ let [n, r, i, a, o, s] = t;
43
42
  if (n !== "scrypt") return null;
44
- let s = Number(r), c = Number(i), l = Number(a);
45
- if (!Number.isFinite(s) || !Number.isFinite(c) || !Number.isFinite(l)) return null;
46
- let u = Buffer.from(o, "base64").length;
47
- return u === 0 ? null : {
48
- N: s,
49
- r: c,
50
- p: l,
51
- keyLen: u
43
+ let c = Number(r), l = Number(i), u = Number(a);
44
+ if (!Number.isInteger(c) || !Number.isInteger(l) || !Number.isInteger(u) || c < 2 || l < 1 || u < 1 || 128 * c * l > d) return null;
45
+ let f = Buffer.from(s, "base64");
46
+ return f.length === 0 ? null : {
47
+ N: c,
48
+ r: l,
49
+ p: u,
50
+ keyLen: f.length,
51
+ salt: Buffer.from(o, "base64"),
52
+ expected: f
52
53
  };
53
- }, g = (e) => {
54
- let t = h(e);
54
+ }, v = (e) => {
55
+ let t = _(e);
56
+ return t ? {
57
+ N: t.N,
58
+ r: t.r,
59
+ p: t.p,
60
+ keyLen: t.keyLen
61
+ } : null;
62
+ }, y = (e) => {
63
+ let t = v(e);
55
64
  return !t || t.N !== a || t.r !== o || t.p !== s || t.keyLen !== c;
56
- }, _ = (e, t) => i.gen(function* () {
57
- if (!(yield* m(e, t))) return { valid: !1 };
58
- if (!g(t)) return { valid: !0 };
59
- let n = yield* p(e).pipe(i.orElseSucceed(() => ""));
65
+ }, b = (e, t) => i.gen(function* () {
66
+ if (!(yield* g(e, t))) return { valid: !1 };
67
+ if (!y(t)) return { valid: !0 };
68
+ let n = yield* h(e).pipe(i.orElseSucceed(() => ""));
60
69
  return n ? {
61
70
  valid: !0,
62
71
  rehash: n
63
72
  } : { valid: !0 };
64
73
  });
65
74
  //#endregion
66
- export { u as PasswordEmptyError, d as PasswordHashError, p as hashPassword, g as needsRehash, h as parseScryptParams, m as verifyPassword, _ as verifyPasswordWithRehash };
75
+ export { f as PasswordEmptyError, p as PasswordHashError, h as hashPassword, y as needsRehash, v as parseScryptParams, g as verifyPassword, b as verifyPasswordWithRehash };