@maestro-js/password 1.0.0-alpha.23 → 1.0.0-alpha.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.d.ts +5 -4
- package/dist/index.js +14 -10
- package/package.json +5 -5
package/dist/index.d.ts
CHANGED
|
@@ -40,13 +40,12 @@ declare namespace Password {
|
|
|
40
40
|
password: string;
|
|
41
41
|
}> {
|
|
42
42
|
verifyCredentials(credentials: Credentials): Promise<Password.Authenticatable<Id> | null>;
|
|
43
|
-
createPasswordResetToken: (authenticatableId: Id
|
|
44
|
-
expirationMinutes: number;
|
|
45
|
-
}) => Promise<string>;
|
|
43
|
+
createPasswordResetToken: (authenticatableId: Id) => Promise<string>;
|
|
46
44
|
resetPassword: (options: {
|
|
45
|
+
authenticatableId: Id;
|
|
47
46
|
token: string;
|
|
48
47
|
newPassword: string;
|
|
49
|
-
}) => Promise<
|
|
48
|
+
}) => Promise<void>;
|
|
50
49
|
}
|
|
51
50
|
interface Config<Id, Credentials extends {
|
|
52
51
|
password: string;
|
|
@@ -77,6 +76,8 @@ declare namespace Password {
|
|
|
77
76
|
getBySelector(selector: string): Promise<Password.ResetTokenRecord<Id> | null>;
|
|
78
77
|
getByAuthenticatableId(authenticatableId: Id): Promise<Password.ResetTokenRecord<Id> | null>;
|
|
79
78
|
deleteByAuthenticatableId(authenticatableId: Id): Promise<void>;
|
|
79
|
+
/** Token lifetime in minutes. Default: 60 */
|
|
80
|
+
tokenExpirationMinutes?: number;
|
|
80
81
|
/** Minimum seconds between createToken calls for the same authenticatable. Default: 60 */
|
|
81
82
|
throttleSeconds?: number;
|
|
82
83
|
}
|
package/dist/index.js
CHANGED
|
@@ -6,13 +6,11 @@ import { instantFns } from "iso-fns2";
|
|
|
6
6
|
function create(config) {
|
|
7
7
|
const hashService = config.hash;
|
|
8
8
|
const passwordResetOptions = config.passwordResetOptions;
|
|
9
|
-
let dummyHash;
|
|
10
9
|
async function verifyCredentials(credentials) {
|
|
11
10
|
const { password, ...input } = credentials;
|
|
12
11
|
const authenticatable = await config.getAuthenticatableByCredentials(input);
|
|
13
12
|
if (!authenticatable) {
|
|
14
|
-
|
|
15
|
-
await hashService.verify({ plaintext: password, hash: dummyHash });
|
|
13
|
+
await hashService.verify({ hash: await hashService.hash("password"), plaintext: "password" });
|
|
16
14
|
return null;
|
|
17
15
|
}
|
|
18
16
|
const isValid = await hashService.verify({ plaintext: password, hash: authenticatable.passwordHash });
|
|
@@ -26,7 +24,7 @@ function create(config) {
|
|
|
26
24
|
}
|
|
27
25
|
return { id: authenticatable.id, credentialsInvalidBefore: authenticatable.credentialsInvalidBefore };
|
|
28
26
|
}
|
|
29
|
-
async function createPasswordResetToken(authenticatableId
|
|
27
|
+
async function createPasswordResetToken(authenticatableId) {
|
|
30
28
|
if (!passwordResetOptions) {
|
|
31
29
|
throw new Error("Password reset is not configured. Provide `passwordResetOptions` when creating the password service.");
|
|
32
30
|
}
|
|
@@ -41,7 +39,7 @@ function create(config) {
|
|
|
41
39
|
const verifier = crypto.randomBytes(32).toString("base64url");
|
|
42
40
|
const verifierHash = await config.hash.hash(verifier);
|
|
43
41
|
const now = instantFns.now();
|
|
44
|
-
const expirationDate = instantFns.add(now, { minutes:
|
|
42
|
+
const expirationDate = instantFns.add(now, { minutes: passwordResetOptions.tokenExpirationMinutes ?? 60 });
|
|
45
43
|
await passwordResetOptions.create({
|
|
46
44
|
authenticatableId,
|
|
47
45
|
selector,
|
|
@@ -51,7 +49,11 @@ function create(config) {
|
|
|
51
49
|
});
|
|
52
50
|
return `${selector}|${verifier}`;
|
|
53
51
|
}
|
|
54
|
-
async function resetPassword({
|
|
52
|
+
async function resetPassword({
|
|
53
|
+
authenticatableId,
|
|
54
|
+
token,
|
|
55
|
+
newPassword
|
|
56
|
+
}) {
|
|
55
57
|
if (!passwordResetOptions) {
|
|
56
58
|
throw new Error("Password reset is not configured. Provide `passwordResetOptions` when creating the password service.");
|
|
57
59
|
}
|
|
@@ -70,11 +72,13 @@ function create(config) {
|
|
|
70
72
|
if (record.expirationDate < instantFns.now()) {
|
|
71
73
|
throw new PasswordResetExpiredTokenError();
|
|
72
74
|
}
|
|
75
|
+
if (record.authenticatableId !== authenticatableId) {
|
|
76
|
+
throw new PasswordResetInvalidTokenError();
|
|
77
|
+
}
|
|
73
78
|
const passwordHash = await config.hash.hash(newPassword);
|
|
74
|
-
await config.updatePasswordHash(
|
|
75
|
-
await config.updateCredentialsInvalidBefore(
|
|
76
|
-
await passwordResetOptions.deleteByAuthenticatableId(
|
|
77
|
-
return record.authenticatableId;
|
|
79
|
+
await config.updatePasswordHash(authenticatableId, passwordHash);
|
|
80
|
+
await config.updateCredentialsInvalidBefore(authenticatableId, instantFns.now());
|
|
81
|
+
await passwordResetOptions.deleteByAuthenticatableId(authenticatableId);
|
|
78
82
|
}
|
|
79
83
|
return {
|
|
80
84
|
verifyCredentials,
|
package/package.json
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"default": "./dist/index.js"
|
|
8
8
|
}
|
|
9
9
|
},
|
|
10
|
-
"version": "1.0.0-alpha.
|
|
10
|
+
"version": "1.0.0-alpha.4",
|
|
11
11
|
"publishConfig": {
|
|
12
12
|
"access": "restricted"
|
|
13
13
|
},
|
|
@@ -16,15 +16,15 @@
|
|
|
16
16
|
],
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"iso-fns2": "npm:iso-fns@2.0.0-alpha.26",
|
|
19
|
-
"@maestro-js/
|
|
20
|
-
"@maestro-js/
|
|
19
|
+
"@maestro-js/service-registry": "1.0.0-alpha.4",
|
|
20
|
+
"@maestro-js/custom-errors": "1.0.0-alpha.4"
|
|
21
21
|
},
|
|
22
22
|
"peerDependencies": {
|
|
23
|
-
"@maestro-js/hash": "1.0.0-alpha.
|
|
23
|
+
"@maestro-js/hash": "1.0.0-alpha.4"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@types/node": "^22.19.11",
|
|
27
|
-
"@maestro-js/hash": "1.0.0-alpha.
|
|
27
|
+
"@maestro-js/hash": "1.0.0-alpha.4"
|
|
28
28
|
},
|
|
29
29
|
"license": "UNLICENSED",
|
|
30
30
|
"engines": {
|