@absolutejs/auth 0.27.0-beta.6 → 0.27.0-beta.7
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/credentials/config.d.ts +1 -0
- package/dist/credentials/login.d.ts +2 -1
- package/dist/credentials/routes.d.ts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +55 -53
- package/dist/index.js.map +6 -6
- package/package.json +1 -1
|
@@ -19,6 +19,7 @@ export type CredentialEmailMessage = {
|
|
|
19
19
|
type: CredentialEmailType;
|
|
20
20
|
};
|
|
21
21
|
export type CredentialsConfig<UserType> = {
|
|
22
|
+
checkBreachesOnLogin?: boolean;
|
|
22
23
|
credentialStore: CredentialStore;
|
|
23
24
|
getUserByEmail: (email: string) => Promise<UserType | null | undefined> | UserType | null | undefined;
|
|
24
25
|
isMfaRequired?: (user: UserType) => boolean | Promise<boolean>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Elysia } from 'elysia';
|
|
2
2
|
import { type CredentialRouteProps } from './config';
|
|
3
|
-
export declare const credentialsLogin: <UserType>({ authSessionStore, credentialStore, getUserByEmail, isMfaRequired, lockoutGuard, loginRoute, onCredentialsLoginError, onCredentialsLoginSuccess, requireEmailVerification, sessionDurationMs }: CredentialRouteProps<UserType>) => Elysia<"", {
|
|
3
|
+
export declare const credentialsLogin: <UserType>({ authSessionStore, checkBreachesOnLogin, credentialStore, getUserByEmail, isMfaRequired, lockoutGuard, loginRoute, onCredentialsLoginError, onCredentialsLoginSuccess, requireEmailVerification, sessionDurationMs }: CredentialRouteProps<UserType>) => Elysia<"", {
|
|
4
4
|
decorator: {};
|
|
5
5
|
store: {
|
|
6
6
|
session: import("..").SessionRecord<UserType>;
|
|
@@ -32,6 +32,7 @@ export declare const credentialsLogin: <UserType>({ authSessionStore, credential
|
|
|
32
32
|
200: {
|
|
33
33
|
readonly status: "mfa_required";
|
|
34
34
|
} | {
|
|
35
|
+
readonly passwordCompromised: boolean;
|
|
35
36
|
readonly status: "authenticated";
|
|
36
37
|
};
|
|
37
38
|
401: "Invalid email or password";
|
|
@@ -100,6 +100,7 @@ export declare const credentialRoutes: <UserType>(config: CredentialRouteProps<U
|
|
|
100
100
|
200: {
|
|
101
101
|
readonly status: "mfa_required";
|
|
102
102
|
} | {
|
|
103
|
+
readonly passwordCompromised: boolean;
|
|
103
104
|
readonly status: "authenticated";
|
|
104
105
|
};
|
|
105
106
|
401: "Invalid email or password";
|
package/dist/index.d.ts
CHANGED
|
@@ -12725,6 +12725,7 @@ export declare const auth: <UserType>({ providersConfiguration, authorizeRoute,
|
|
|
12725
12725
|
200: {
|
|
12726
12726
|
readonly status: "mfa_required";
|
|
12727
12727
|
} | {
|
|
12728
|
+
readonly passwordCompromised: boolean;
|
|
12728
12729
|
readonly status: "authenticated";
|
|
12729
12730
|
};
|
|
12730
12731
|
401: "Invalid email or password";
|
package/dist/index.js
CHANGED
|
@@ -3391,8 +3391,60 @@ var credentialsEmailVerification = ({
|
|
|
3391
3391
|
|
|
3392
3392
|
// src/credentials/login.ts
|
|
3393
3393
|
import { Elysia as Elysia6, t as t6 } from "elysia";
|
|
3394
|
+
|
|
3395
|
+
// src/credentials/passwordPolicy.ts
|
|
3396
|
+
var DEFAULT_MIN_LENGTH = 12;
|
|
3397
|
+
var HEX_RADIX = 16;
|
|
3398
|
+
var HIBP_PREFIX_LENGTH = 5;
|
|
3399
|
+
var HIBP_RANGE_URL = "https://api.pwnedpasswords.com/range/";
|
|
3400
|
+
var sha1Hex = async (input) => {
|
|
3401
|
+
const digest = await crypto.subtle.digest("SHA-1", new TextEncoder().encode(input));
|
|
3402
|
+
return [...new Uint8Array(digest)].map((byte) => byte.toString(HEX_RADIX).padStart(2, "0")).join("").toUpperCase();
|
|
3403
|
+
};
|
|
3404
|
+
var isPasswordBreached = async (password) => {
|
|
3405
|
+
try {
|
|
3406
|
+
const hash = await sha1Hex(password);
|
|
3407
|
+
const prefix = hash.slice(0, HIBP_PREFIX_LENGTH);
|
|
3408
|
+
const suffix = hash.slice(HIBP_PREFIX_LENGTH);
|
|
3409
|
+
const response = await fetch(`${HIBP_RANGE_URL}${prefix}`);
|
|
3410
|
+
if (!response.ok)
|
|
3411
|
+
return false;
|
|
3412
|
+
const body = await response.text();
|
|
3413
|
+
return body.split(`
|
|
3414
|
+
`).some((line) => line.split(":")[0]?.trim() === suffix);
|
|
3415
|
+
} catch {
|
|
3416
|
+
return false;
|
|
3417
|
+
}
|
|
3418
|
+
};
|
|
3419
|
+
var evaluatePassword = async (password, policy = {}) => {
|
|
3420
|
+
const minLength = policy.minLength ?? DEFAULT_MIN_LENGTH;
|
|
3421
|
+
const violations = [];
|
|
3422
|
+
if (password.length < minLength) {
|
|
3423
|
+
violations.push("too_short");
|
|
3424
|
+
}
|
|
3425
|
+
if (policy.requireUppercase && !/[A-Z]/u.test(password)) {
|
|
3426
|
+
violations.push("missing_uppercase");
|
|
3427
|
+
}
|
|
3428
|
+
if (policy.requireLowercase && !/[a-z]/u.test(password)) {
|
|
3429
|
+
violations.push("missing_lowercase");
|
|
3430
|
+
}
|
|
3431
|
+
if (policy.requireDigit && !/\d/u.test(password)) {
|
|
3432
|
+
violations.push("missing_digit");
|
|
3433
|
+
}
|
|
3434
|
+
if (policy.requireSymbol && !/[^A-Za-z0-9]/u.test(password)) {
|
|
3435
|
+
violations.push("missing_symbol");
|
|
3436
|
+
}
|
|
3437
|
+
if (policy.checkBreaches && await isPasswordBreached(password)) {
|
|
3438
|
+
violations.push("breached");
|
|
3439
|
+
}
|
|
3440
|
+
return { ok: violations.length === 0, violations };
|
|
3441
|
+
};
|
|
3442
|
+
var isPasswordCompromised = (password) => isPasswordBreached(password);
|
|
3443
|
+
|
|
3444
|
+
// src/credentials/login.ts
|
|
3394
3445
|
var credentialsLogin = ({
|
|
3395
3446
|
authSessionStore,
|
|
3447
|
+
checkBreachesOnLogin,
|
|
3396
3448
|
credentialStore,
|
|
3397
3449
|
getUserByEmail,
|
|
3398
3450
|
isMfaRequired,
|
|
@@ -3451,6 +3503,7 @@ var credentialsLogin = ({
|
|
|
3451
3503
|
await persistWhen(authSessionStore !== undefined, compatibilityLayer.persist);
|
|
3452
3504
|
return status("OK", { status: "mfa_required" });
|
|
3453
3505
|
}
|
|
3506
|
+
const passwordCompromised = checkBreachesOnLogin ? await isPasswordCompromised(password) : false;
|
|
3454
3507
|
const userSessionId = await promoteToSession({
|
|
3455
3508
|
authSessionStore,
|
|
3456
3509
|
cookie: user_session_id,
|
|
@@ -3459,7 +3512,7 @@ var credentialsLogin = ({
|
|
|
3459
3512
|
user
|
|
3460
3513
|
});
|
|
3461
3514
|
await onCredentialsLoginSuccess?.({ user, userSessionId });
|
|
3462
|
-
return status("OK", { status: "authenticated" });
|
|
3515
|
+
return status("OK", { passwordCompromised, status: "authenticated" });
|
|
3463
3516
|
}, {
|
|
3464
3517
|
body: t6.Object({ email: t6.String(), password: t6.String() }),
|
|
3465
3518
|
cookie: t6.Cookie({ user_session_id: userSessionIdTypebox })
|
|
@@ -3467,57 +3520,6 @@ var credentialsLogin = ({
|
|
|
3467
3520
|
|
|
3468
3521
|
// src/credentials/passwordReset.ts
|
|
3469
3522
|
import { Elysia as Elysia7, t as t7 } from "elysia";
|
|
3470
|
-
|
|
3471
|
-
// src/credentials/passwordPolicy.ts
|
|
3472
|
-
var DEFAULT_MIN_LENGTH = 12;
|
|
3473
|
-
var HEX_RADIX = 16;
|
|
3474
|
-
var HIBP_PREFIX_LENGTH = 5;
|
|
3475
|
-
var HIBP_RANGE_URL = "https://api.pwnedpasswords.com/range/";
|
|
3476
|
-
var sha1Hex = async (input) => {
|
|
3477
|
-
const digest = await crypto.subtle.digest("SHA-1", new TextEncoder().encode(input));
|
|
3478
|
-
return [...new Uint8Array(digest)].map((byte) => byte.toString(HEX_RADIX).padStart(2, "0")).join("").toUpperCase();
|
|
3479
|
-
};
|
|
3480
|
-
var isPasswordBreached = async (password) => {
|
|
3481
|
-
try {
|
|
3482
|
-
const hash = await sha1Hex(password);
|
|
3483
|
-
const prefix = hash.slice(0, HIBP_PREFIX_LENGTH);
|
|
3484
|
-
const suffix = hash.slice(HIBP_PREFIX_LENGTH);
|
|
3485
|
-
const response = await fetch(`${HIBP_RANGE_URL}${prefix}`);
|
|
3486
|
-
if (!response.ok)
|
|
3487
|
-
return false;
|
|
3488
|
-
const body = await response.text();
|
|
3489
|
-
return body.split(`
|
|
3490
|
-
`).some((line) => line.split(":")[0]?.trim() === suffix);
|
|
3491
|
-
} catch {
|
|
3492
|
-
return false;
|
|
3493
|
-
}
|
|
3494
|
-
};
|
|
3495
|
-
var evaluatePassword = async (password, policy = {}) => {
|
|
3496
|
-
const minLength = policy.minLength ?? DEFAULT_MIN_LENGTH;
|
|
3497
|
-
const violations = [];
|
|
3498
|
-
if (password.length < minLength) {
|
|
3499
|
-
violations.push("too_short");
|
|
3500
|
-
}
|
|
3501
|
-
if (policy.requireUppercase && !/[A-Z]/u.test(password)) {
|
|
3502
|
-
violations.push("missing_uppercase");
|
|
3503
|
-
}
|
|
3504
|
-
if (policy.requireLowercase && !/[a-z]/u.test(password)) {
|
|
3505
|
-
violations.push("missing_lowercase");
|
|
3506
|
-
}
|
|
3507
|
-
if (policy.requireDigit && !/\d/u.test(password)) {
|
|
3508
|
-
violations.push("missing_digit");
|
|
3509
|
-
}
|
|
3510
|
-
if (policy.requireSymbol && !/[^A-Za-z0-9]/u.test(password)) {
|
|
3511
|
-
violations.push("missing_symbol");
|
|
3512
|
-
}
|
|
3513
|
-
if (policy.checkBreaches && await isPasswordBreached(password)) {
|
|
3514
|
-
violations.push("breached");
|
|
3515
|
-
}
|
|
3516
|
-
return { ok: violations.length === 0, violations };
|
|
3517
|
-
};
|
|
3518
|
-
var isPasswordCompromised = (password) => isPasswordBreached(password);
|
|
3519
|
-
|
|
3520
|
-
// src/credentials/passwordReset.ts
|
|
3521
3523
|
var credentialsPasswordReset = ({
|
|
3522
3524
|
credentialStore,
|
|
3523
3525
|
onPasswordReset,
|
|
@@ -20974,5 +20976,5 @@ export {
|
|
|
20974
20976
|
AuthIdentityConflictError
|
|
20975
20977
|
};
|
|
20976
20978
|
|
|
20977
|
-
//# debugId=
|
|
20979
|
+
//# debugId=580D3E8ACE9EF4E864756E2164756E21
|
|
20978
20980
|
//# sourceMappingURL=index.js.map
|