@cairs-npm/express-auth-2fa 0.1.2 → 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 +25 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +25 -3
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -208,6 +208,17 @@ declare const configSchema: z.ZodObject<{
|
|
|
208
208
|
username: string;
|
|
209
209
|
type?: string;
|
|
210
210
|
}) => boolean | Promise<boolean>>]>>;
|
|
211
|
+
/**
|
|
212
|
+
* 2-Step Verification switch above each user's own choice. False: password sign-in never
|
|
213
|
+
* asks for a code and the two-step setting can't be turned on. Passwordless sign-in still
|
|
214
|
+
* sends a code — it's the only factor there. Pass a function to decide per user, e.g. from
|
|
215
|
+
* an organization setting.
|
|
216
|
+
*/
|
|
217
|
+
twoStepEnabled: z.ZodDefault<z.ZodUnion<[z.ZodBoolean, z.ZodType<(input: {
|
|
218
|
+
userId: string;
|
|
219
|
+
}) => boolean | Promise<boolean>, z.ZodTypeDef, (input: {
|
|
220
|
+
userId: string;
|
|
221
|
+
}) => boolean | Promise<boolean>>]>>;
|
|
211
222
|
/** 2-Step Verification state for users who have not chosen one yet. */
|
|
212
223
|
twoStepDefault: z.ZodDefault<z.ZodBoolean>;
|
|
213
224
|
limits: z.ZodDefault<z.ZodObject<{
|
|
@@ -333,6 +344,9 @@ declare const configSchema: z.ZodObject<{
|
|
|
333
344
|
username: string;
|
|
334
345
|
type?: string;
|
|
335
346
|
}) => boolean | Promise<boolean>);
|
|
347
|
+
twoStepEnabled: boolean | ((input: {
|
|
348
|
+
userId: string;
|
|
349
|
+
}) => boolean | Promise<boolean>);
|
|
336
350
|
twoStepDefault: boolean;
|
|
337
351
|
limits: {
|
|
338
352
|
loginMaxAttempts: number;
|
|
@@ -402,6 +416,9 @@ declare const configSchema: z.ZodObject<{
|
|
|
402
416
|
username: string;
|
|
403
417
|
type?: string;
|
|
404
418
|
}) => boolean | Promise<boolean>) | undefined;
|
|
419
|
+
twoStepEnabled?: boolean | ((input: {
|
|
420
|
+
userId: string;
|
|
421
|
+
}) => boolean | Promise<boolean>) | undefined;
|
|
405
422
|
twoStepDefault?: boolean | undefined;
|
|
406
423
|
limits?: {
|
|
407
424
|
loginMaxAttempts?: number | undefined;
|
package/dist/index.d.ts
CHANGED
|
@@ -208,6 +208,17 @@ declare const configSchema: z.ZodObject<{
|
|
|
208
208
|
username: string;
|
|
209
209
|
type?: string;
|
|
210
210
|
}) => boolean | Promise<boolean>>]>>;
|
|
211
|
+
/**
|
|
212
|
+
* 2-Step Verification switch above each user's own choice. False: password sign-in never
|
|
213
|
+
* asks for a code and the two-step setting can't be turned on. Passwordless sign-in still
|
|
214
|
+
* sends a code — it's the only factor there. Pass a function to decide per user, e.g. from
|
|
215
|
+
* an organization setting.
|
|
216
|
+
*/
|
|
217
|
+
twoStepEnabled: z.ZodDefault<z.ZodUnion<[z.ZodBoolean, z.ZodType<(input: {
|
|
218
|
+
userId: string;
|
|
219
|
+
}) => boolean | Promise<boolean>, z.ZodTypeDef, (input: {
|
|
220
|
+
userId: string;
|
|
221
|
+
}) => boolean | Promise<boolean>>]>>;
|
|
211
222
|
/** 2-Step Verification state for users who have not chosen one yet. */
|
|
212
223
|
twoStepDefault: z.ZodDefault<z.ZodBoolean>;
|
|
213
224
|
limits: z.ZodDefault<z.ZodObject<{
|
|
@@ -333,6 +344,9 @@ declare const configSchema: z.ZodObject<{
|
|
|
333
344
|
username: string;
|
|
334
345
|
type?: string;
|
|
335
346
|
}) => boolean | Promise<boolean>);
|
|
347
|
+
twoStepEnabled: boolean | ((input: {
|
|
348
|
+
userId: string;
|
|
349
|
+
}) => boolean | Promise<boolean>);
|
|
336
350
|
twoStepDefault: boolean;
|
|
337
351
|
limits: {
|
|
338
352
|
loginMaxAttempts: number;
|
|
@@ -402,6 +416,9 @@ declare const configSchema: z.ZodObject<{
|
|
|
402
416
|
username: string;
|
|
403
417
|
type?: string;
|
|
404
418
|
}) => boolean | Promise<boolean>) | undefined;
|
|
419
|
+
twoStepEnabled?: boolean | ((input: {
|
|
420
|
+
userId: string;
|
|
421
|
+
}) => boolean | Promise<boolean>) | undefined;
|
|
405
422
|
twoStepDefault?: boolean | undefined;
|
|
406
423
|
limits?: {
|
|
407
424
|
loginMaxAttempts?: number | undefined;
|
package/dist/index.js
CHANGED
|
@@ -99,6 +99,16 @@ var configSchema = z.object({
|
|
|
99
99
|
(v) => typeof v === "function"
|
|
100
100
|
)
|
|
101
101
|
]).default(false),
|
|
102
|
+
/**
|
|
103
|
+
* 2-Step Verification switch above each user's own choice. False: password sign-in never
|
|
104
|
+
* asks for a code and the two-step setting can't be turned on. Passwordless sign-in still
|
|
105
|
+
* sends a code — it's the only factor there. Pass a function to decide per user, e.g. from
|
|
106
|
+
* an organization setting.
|
|
107
|
+
*/
|
|
108
|
+
twoStepEnabled: z.union([
|
|
109
|
+
z.boolean(),
|
|
110
|
+
z.custom((v) => typeof v === "function")
|
|
111
|
+
]).default(true),
|
|
102
112
|
/** 2-Step Verification state for users who have not chosen one yet. */
|
|
103
113
|
twoStepDefault: z.boolean().default(false),
|
|
104
114
|
limits: limitSchema.default({}),
|
|
@@ -299,6 +309,12 @@ async function migrate(db, prefix = "auth_", auditDays = 365) {
|
|
|
299
309
|
return c;
|
|
300
310
|
}
|
|
301
311
|
|
|
312
|
+
// src/config/twoStep.ts
|
|
313
|
+
async function twoStepAvailableFor(config, userId) {
|
|
314
|
+
const v = config.twoStepEnabled;
|
|
315
|
+
return typeof v === "function" ? Boolean(await v({ userId })) : v;
|
|
316
|
+
}
|
|
317
|
+
|
|
302
318
|
// src/middleware/errors.ts
|
|
303
319
|
import { ZodError } from "zod";
|
|
304
320
|
var ApiErrorException = class extends Error {
|
|
@@ -555,11 +571,16 @@ var MethodService = class {
|
|
|
555
571
|
const cred = await this.cols.credentials.findOne({ userId });
|
|
556
572
|
const docs = await this.cols.methods.find({ userId, status: "active" }).toArray();
|
|
557
573
|
const methods = docs.sort((a, b) => Number(b.isDefault) - Number(a.isDefault) || a.createdAt.getTime() - b.createdAt.getTime()).map(toApiMethod);
|
|
558
|
-
|
|
574
|
+
const available = await twoStepAvailableFor(this.config, userId);
|
|
575
|
+
const twoStepEnabled = available && (cred?.twoStepEnabled ?? this.config.twoStepDefault);
|
|
576
|
+
return { twoStepEnabled, twoStepAvailable: available, methods };
|
|
559
577
|
}
|
|
560
578
|
/** BR-15 — enable needs ≥1 active method; disable needs step-up + revokes trusted devices. */
|
|
561
579
|
async setTwoStep(userId, sid, enabled, stepUpToken) {
|
|
562
580
|
const now = this.config.clock();
|
|
581
|
+
if (enabled && !await twoStepAvailableFor(this.config, userId)) {
|
|
582
|
+
throw apiError(409, "VALIDATION_ERROR", "2-Step Verification is turned off for this application.");
|
|
583
|
+
}
|
|
563
584
|
if (enabled) {
|
|
564
585
|
await ensureEmailMethod(this.config, this.cols, userId);
|
|
565
586
|
const count = await this.cols.methods.countDocuments({ userId, status: "active" });
|
|
@@ -799,8 +820,9 @@ var AuthService = class {
|
|
|
799
820
|
throw apiError(423, "LOCKED", "Too many attempts. Try again later.", { retryAt: cred.lockedUntil });
|
|
800
821
|
}
|
|
801
822
|
await this.resetFailedLogins(cred, now);
|
|
802
|
-
const
|
|
803
|
-
|
|
823
|
+
const twoStep = cred.twoStepEnabled && await twoStepAvailableFor(this.config, user.id);
|
|
824
|
+
const trustedOk = twoStep && await this.checkTrustedDevice(req, user.id);
|
|
825
|
+
if (!twoStep || trustedOk) {
|
|
804
826
|
await this.audit.record(user.id, "login_success", ctx);
|
|
805
827
|
return this.authenticate(user.id, req, res, ["pwd"], { rememberMe: input.rememberMe });
|
|
806
828
|
}
|