@cairs-npm/express-auth-2fa 0.1.3 → 0.1.4

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.cjs CHANGED
@@ -186,11 +186,15 @@ var configSchema = import_zod.z.object({
186
186
  )
187
187
  ]).default(false),
188
188
  /**
189
- * Project-wide 2-Step Verification switch. False: password sign-in never asks for a code
190
- * (whatever each user chose) and the two-step setting can't be turned on. Passwordless
191
- * sign-in still sends a code — it's the only factor there.
189
+ * 2-Step Verification switch above each user's own choice. False: password sign-in never
190
+ * asks for a code and the two-step setting can't be turned on. Passwordless sign-in still
191
+ * sends a code — it's the only factor there. Pass a function to decide per user, e.g. from
192
+ * an organization setting.
192
193
  */
193
- twoStepEnabled: import_zod.z.boolean().default(true),
194
+ twoStepEnabled: import_zod.z.union([
195
+ import_zod.z.boolean(),
196
+ import_zod.z.custom((v) => typeof v === "function")
197
+ ]).default(true),
194
198
  /** 2-Step Verification state for users who have not chosen one yet. */
195
199
  twoStepDefault: import_zod.z.boolean().default(false),
196
200
  limits: limitSchema.default({}),
@@ -391,6 +395,12 @@ async function migrate(db, prefix = "auth_", auditDays = 365) {
391
395
  return c;
392
396
  }
393
397
 
398
+ // src/config/twoStep.ts
399
+ async function twoStepAvailableFor(config, userId) {
400
+ const v = config.twoStepEnabled;
401
+ return typeof v === "function" ? Boolean(await v({ userId })) : v;
402
+ }
403
+
394
404
  // src/services/auth.service.ts
395
405
  init_hash();
396
406
 
@@ -653,14 +663,14 @@ var MethodService = class {
653
663
  const cred = await this.cols.credentials.findOne({ userId });
654
664
  const docs = await this.cols.methods.find({ userId, status: "active" }).toArray();
655
665
  const methods = docs.sort((a, b) => Number(b.isDefault) - Number(a.isDefault) || a.createdAt.getTime() - b.createdAt.getTime()).map(toApiMethod);
656
- const available = this.config.twoStepEnabled;
666
+ const available = await twoStepAvailableFor(this.config, userId);
657
667
  const twoStepEnabled = available && (cred?.twoStepEnabled ?? this.config.twoStepDefault);
658
668
  return { twoStepEnabled, twoStepAvailable: available, methods };
659
669
  }
660
670
  /** BR-15 — enable needs ≥1 active method; disable needs step-up + revokes trusted devices. */
661
671
  async setTwoStep(userId, sid, enabled, stepUpToken) {
662
672
  const now = this.config.clock();
663
- if (enabled && !this.config.twoStepEnabled) {
673
+ if (enabled && !await twoStepAvailableFor(this.config, userId)) {
664
674
  throw apiError(409, "VALIDATION_ERROR", "2-Step Verification is turned off for this application.");
665
675
  }
666
676
  if (enabled) {
@@ -902,7 +912,7 @@ var AuthService = class {
902
912
  throw apiError(423, "LOCKED", "Too many attempts. Try again later.", { retryAt: cred.lockedUntil });
903
913
  }
904
914
  await this.resetFailedLogins(cred, now);
905
- const twoStep = this.config.twoStepEnabled && cred.twoStepEnabled;
915
+ const twoStep = cred.twoStepEnabled && await twoStepAvailableFor(this.config, user.id);
906
916
  const trustedOk = twoStep && await this.checkTrustedDevice(req, user.id);
907
917
  if (!twoStep || trustedOk) {
908
918
  await this.audit.record(user.id, "login_success", ctx);