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

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.cts CHANGED
@@ -208,6 +208,12 @@ declare const configSchema: z.ZodObject<{
208
208
  username: string;
209
209
  type?: string;
210
210
  }) => boolean | Promise<boolean>>]>>;
211
+ /**
212
+ * Project-wide 2-Step Verification switch. False: password sign-in never asks for a code
213
+ * (whatever each user chose) and the two-step setting can't be turned on. Passwordless
214
+ * sign-in still sends a code — it's the only factor there.
215
+ */
216
+ twoStepEnabled: z.ZodDefault<z.ZodBoolean>;
211
217
  /** 2-Step Verification state for users who have not chosen one yet. */
212
218
  twoStepDefault: z.ZodDefault<z.ZodBoolean>;
213
219
  limits: z.ZodDefault<z.ZodObject<{
@@ -333,6 +339,7 @@ declare const configSchema: z.ZodObject<{
333
339
  username: string;
334
340
  type?: string;
335
341
  }) => boolean | Promise<boolean>);
342
+ twoStepEnabled: boolean;
336
343
  twoStepDefault: boolean;
337
344
  limits: {
338
345
  loginMaxAttempts: number;
@@ -402,6 +409,7 @@ declare const configSchema: z.ZodObject<{
402
409
  username: string;
403
410
  type?: string;
404
411
  }) => boolean | Promise<boolean>) | undefined;
412
+ twoStepEnabled?: boolean | undefined;
405
413
  twoStepDefault?: boolean | undefined;
406
414
  limits?: {
407
415
  loginMaxAttempts?: number | undefined;
package/dist/index.d.ts CHANGED
@@ -208,6 +208,12 @@ declare const configSchema: z.ZodObject<{
208
208
  username: string;
209
209
  type?: string;
210
210
  }) => boolean | Promise<boolean>>]>>;
211
+ /**
212
+ * Project-wide 2-Step Verification switch. False: password sign-in never asks for a code
213
+ * (whatever each user chose) and the two-step setting can't be turned on. Passwordless
214
+ * sign-in still sends a code — it's the only factor there.
215
+ */
216
+ twoStepEnabled: z.ZodDefault<z.ZodBoolean>;
211
217
  /** 2-Step Verification state for users who have not chosen one yet. */
212
218
  twoStepDefault: z.ZodDefault<z.ZodBoolean>;
213
219
  limits: z.ZodDefault<z.ZodObject<{
@@ -333,6 +339,7 @@ declare const configSchema: z.ZodObject<{
333
339
  username: string;
334
340
  type?: string;
335
341
  }) => boolean | Promise<boolean>);
342
+ twoStepEnabled: boolean;
336
343
  twoStepDefault: boolean;
337
344
  limits: {
338
345
  loginMaxAttempts: number;
@@ -402,6 +409,7 @@ declare const configSchema: z.ZodObject<{
402
409
  username: string;
403
410
  type?: string;
404
411
  }) => boolean | Promise<boolean>) | undefined;
412
+ twoStepEnabled?: boolean | undefined;
405
413
  twoStepDefault?: boolean | undefined;
406
414
  limits?: {
407
415
  loginMaxAttempts?: number | undefined;
package/dist/index.js CHANGED
@@ -99,6 +99,12 @@ var configSchema = z.object({
99
99
  (v) => typeof v === "function"
100
100
  )
101
101
  ]).default(false),
102
+ /**
103
+ * Project-wide 2-Step Verification switch. False: password sign-in never asks for a code
104
+ * (whatever each user chose) and the two-step setting can't be turned on. Passwordless
105
+ * sign-in still sends a code — it's the only factor there.
106
+ */
107
+ twoStepEnabled: z.boolean().default(true),
102
108
  /** 2-Step Verification state for users who have not chosen one yet. */
103
109
  twoStepDefault: z.boolean().default(false),
104
110
  limits: limitSchema.default({}),
@@ -555,11 +561,16 @@ var MethodService = class {
555
561
  const cred = await this.cols.credentials.findOne({ userId });
556
562
  const docs = await this.cols.methods.find({ userId, status: "active" }).toArray();
557
563
  const methods = docs.sort((a, b) => Number(b.isDefault) - Number(a.isDefault) || a.createdAt.getTime() - b.createdAt.getTime()).map(toApiMethod);
558
- return { twoStepEnabled: cred?.twoStepEnabled ?? this.config.twoStepDefault, methods };
564
+ const available = this.config.twoStepEnabled;
565
+ const twoStepEnabled = available && (cred?.twoStepEnabled ?? this.config.twoStepDefault);
566
+ return { twoStepEnabled, twoStepAvailable: available, methods };
559
567
  }
560
568
  /** BR-15 — enable needs ≥1 active method; disable needs step-up + revokes trusted devices. */
561
569
  async setTwoStep(userId, sid, enabled, stepUpToken) {
562
570
  const now = this.config.clock();
571
+ if (enabled && !this.config.twoStepEnabled) {
572
+ throw apiError(409, "VALIDATION_ERROR", "2-Step Verification is turned off for this application.");
573
+ }
563
574
  if (enabled) {
564
575
  await ensureEmailMethod(this.config, this.cols, userId);
565
576
  const count = await this.cols.methods.countDocuments({ userId, status: "active" });
@@ -799,8 +810,9 @@ var AuthService = class {
799
810
  throw apiError(423, "LOCKED", "Too many attempts. Try again later.", { retryAt: cred.lockedUntil });
800
811
  }
801
812
  await this.resetFailedLogins(cred, now);
802
- const trustedOk = cred.twoStepEnabled && await this.checkTrustedDevice(req, user.id);
803
- if (!cred.twoStepEnabled || trustedOk) {
813
+ const twoStep = this.config.twoStepEnabled && cred.twoStepEnabled;
814
+ const trustedOk = twoStep && await this.checkTrustedDevice(req, user.id);
815
+ if (!twoStep || trustedOk) {
804
816
  await this.audit.record(user.id, "login_success", ctx);
805
817
  return this.authenticate(user.id, req, res, ["pwd"], { rememberMe: input.rememberMe });
806
818
  }