@absolutejs/auth 0.27.0-beta.1 → 0.27.0-beta.2

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.d.ts CHANGED
@@ -8437,6 +8437,8 @@ export { consumeBackupCode, generateBackupCodes } from './mfa/backupCodes';
8437
8437
  export { createMfaGate } from './mfa/gate';
8438
8438
  export { mfaChallenge } from './mfa/challenge';
8439
8439
  export { mfaRoutes } from './mfa/routes';
8440
+ export { rotateMfaEncryptionKey } from './mfa/rotation';
8441
+ export type { MfaKeyRotationResult } from './mfa/rotation';
8440
8442
  export { mfaTotpRoutes } from './mfa/totp';
8441
8443
  export { decryptTotpSecret, encryptTotpSecret } from './mfa/secret';
8442
8444
  export { createInMemoryMfaStore } from './mfa/inMemoryMfaStore';
package/dist/index.js CHANGED
@@ -17843,6 +17843,56 @@ var createPostgresCredentialStore = (db) => ({
17843
17843
  await db.update(credentialsTable).set({ email_verified: true, updated_at_ms: Date.now() }).where(eq(credentialsTable.email, email.toLowerCase()));
17844
17844
  }
17845
17845
  });
17846
+ // src/mfa/rotation.ts
17847
+ var tryDecrypt = async (ciphertext, key) => {
17848
+ try {
17849
+ return await decryptTotpSecret(ciphertext, key);
17850
+ } catch {
17851
+ return;
17852
+ }
17853
+ };
17854
+ var ensureReadable = async (ciphertext, key, userId) => {
17855
+ if (await tryDecrypt(ciphertext, key) === undefined) {
17856
+ throw new Error(`TOTP secret for ${userId} decrypts with neither the old nor the new key`);
17857
+ }
17858
+ };
17859
+ var planEnrollment = async (enrollment, oldKey, newKey) => {
17860
+ const ciphertext = enrollment.totpSecretCiphertext;
17861
+ if (ciphertext === undefined || ciphertext.length === 0) {
17862
+ const plan2 = { kind: "skip" };
17863
+ return plan2;
17864
+ }
17865
+ const secret = await tryDecrypt(ciphertext, oldKey);
17866
+ if (secret === undefined) {
17867
+ await ensureReadable(ciphertext, newKey, enrollment.userId);
17868
+ const plan2 = { kind: "already" };
17869
+ return plan2;
17870
+ }
17871
+ const plan = {
17872
+ enrollment: {
17873
+ ...enrollment,
17874
+ totpSecretCiphertext: await encryptTotpSecret(secret, newKey),
17875
+ updatedAt: Date.now()
17876
+ },
17877
+ kind: "rotate"
17878
+ };
17879
+ return plan;
17880
+ };
17881
+ var rotateMfaEncryptionKey = async ({
17882
+ mfaStore,
17883
+ newKey,
17884
+ oldKey
17885
+ }) => {
17886
+ const enrollments = await mfaStore.listEnrollments();
17887
+ const plans = await Promise.all(enrollments.map((enrollment) => planEnrollment(enrollment, oldKey, newKey)));
17888
+ await Promise.all(plans.map((plan) => plan.kind === "rotate" ? mfaStore.saveEnrollment(plan.enrollment) : Promise.resolve()));
17889
+ return {
17890
+ alreadyRotated: plans.filter((plan) => plan.kind === "already").length,
17891
+ rotated: plans.filter((plan) => plan.kind === "rotate").length,
17892
+ skippedNoSecret: plans.filter((plan) => plan.kind === "skip").length,
17893
+ total: plans.length
17894
+ };
17895
+ };
17846
17896
  // src/mfa/inMemoryMfaStore.ts
17847
17897
  var cloneEnrollment = (value) => ({
17848
17898
  ...value,
@@ -17855,6 +17905,7 @@ var createInMemoryMfaStore = () => {
17855
17905
  const enrollment = enrollments.get(userId);
17856
17906
  return enrollment ? cloneEnrollment(enrollment) : undefined;
17857
17907
  },
17908
+ listEnrollments: async () => Array.from(enrollments.values()).map(cloneEnrollment),
17858
17909
  removeEnrollment: async (userId) => {
17859
17910
  enrollments.delete(userId);
17860
17911
  },
@@ -17889,6 +17940,10 @@ var createPostgresMfaStore = (db) => ({
17889
17940
  const [row] = await db.select().from(mfaEnrollmentsTable).where(eq(mfaEnrollmentsTable.user_id, userId)).limit(1);
17890
17941
  return row ? toEnrollment(row) : undefined;
17891
17942
  },
17943
+ listEnrollments: async () => {
17944
+ const rows = await db.select().from(mfaEnrollmentsTable);
17945
+ return rows.map(toEnrollment);
17946
+ },
17892
17947
  removeEnrollment: async (userId) => {
17893
17948
  await db.delete(mfaEnrollmentsTable).where(eq(mfaEnrollmentsTable.user_id, userId));
17894
17949
  },
@@ -19438,6 +19493,7 @@ export {
19438
19493
  scimTokensTable,
19439
19494
  scimRoutes,
19440
19495
  samlSsoRoutes,
19496
+ rotateMfaEncryptionKey,
19441
19497
  rolesTable,
19442
19498
  roleRoutes,
19443
19499
  revokeUserSessions,
@@ -19639,5 +19695,5 @@ export {
19639
19695
  AuthIdentityConflictError
19640
19696
  };
19641
19697
 
19642
- //# debugId=E141C00026B64EA864756E2164756E21
19698
+ //# debugId=F0BD7B32BDA8B43664756E2164756E21
19643
19699
  //# sourceMappingURL=index.js.map