@furystack/security 3.0.9 → 3.0.11
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/esm/crypto-password-hasher.js +4 -5
- package/esm/crypto-password-hasher.js.map +1 -1
- package/esm/errors/password-complexity-error.js +1 -0
- package/esm/errors/password-complexity-error.js.map +1 -1
- package/esm/models/password-credential.js +16 -0
- package/esm/models/password-credential.js.map +1 -1
- package/esm/models/password-reset-token.js +12 -0
- package/esm/models/password-reset-token.js.map +1 -1
- package/esm/password-authenticator.js +7 -6
- package/esm/password-authenticator.js.map +1 -1
- package/esm/password-authenticator.spec.d.ts +2 -0
- package/esm/password-authenticator.spec.d.ts.map +1 -0
- package/esm/password-authenticator.spec.js +293 -0
- package/esm/password-authenticator.spec.js.map +1 -0
- package/esm/password-complexity-rules/contains-lowercase.spec.d.ts +2 -0
- package/esm/password-complexity-rules/contains-lowercase.spec.d.ts.map +1 -0
- package/esm/password-complexity-rules/contains-lowercase.spec.js +27 -0
- package/esm/password-complexity-rules/contains-lowercase.spec.js.map +1 -0
- package/esm/password-complexity-rules/contains-uppercase.spec.d.ts +2 -0
- package/esm/password-complexity-rules/contains-uppercase.spec.d.ts.map +1 -0
- package/esm/password-complexity-rules/contains-uppercase.spec.js +27 -0
- package/esm/password-complexity-rules/contains-uppercase.spec.js.map +1 -0
- package/esm/password-complexity-rules/max-length.spec.d.ts +2 -0
- package/esm/password-complexity-rules/max-length.spec.d.ts.map +1 -0
- package/esm/password-complexity-rules/max-length.spec.js +16 -0
- package/esm/password-complexity-rules/max-length.spec.js.map +1 -0
- package/esm/password-complexity-rules/min-length.spec.d.ts +2 -0
- package/esm/password-complexity-rules/min-length.spec.d.ts.map +1 -0
- package/esm/password-complexity-rules/min-length.spec.js +16 -0
- package/esm/password-complexity-rules/min-length.spec.js.map +1 -0
- package/esm/password-hasher.js +2 -1
- package/esm/password-hasher.js.map +1 -1
- package/esm/security-policy-manager.js +3 -1
- package/esm/security-policy-manager.js.map +1 -1
- package/esm/security-policy-manager.spec.d.ts +2 -0
- package/esm/security-policy-manager.spec.d.ts.map +1 -0
- package/esm/security-policy-manager.spec.js +17 -0
- package/esm/security-policy-manager.spec.js.map +1 -0
- package/esm/security-policy.js +22 -23
- package/esm/security-policy.js.map +1 -1
- package/package.json +7 -7
- package/src/password-authenticator.spec.ts +9 -7
- package/src/password-complexity-rules/contains-lowercase.spec.ts +2 -2
- package/src/password-complexity-rules/contains-uppercase.spec.ts +2 -2
- package/src/password-complexity-rules/max-length.spec.ts +2 -2
- package/src/password-complexity-rules/min-length.spec.ts +2 -2
- package/src/security-policy-manager.spec.ts +2 -2
|
@@ -6,11 +6,9 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
6
6
|
};
|
|
7
7
|
import { Injectable } from '@furystack/inject';
|
|
8
8
|
import { randomBytes, pbkdf2 } from 'crypto';
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
this.keylen = 64;
|
|
13
|
-
}
|
|
9
|
+
let CryptoPasswordHasher = class CryptoPasswordHasher {
|
|
10
|
+
iterations = 1000;
|
|
11
|
+
keylen = 64;
|
|
14
12
|
async verifyCredential(password, { passwordHash, salt }) {
|
|
15
13
|
const newHash = await new Promise((resolve, reject) => pbkdf2(password, salt, this.iterations, this.keylen, 'sha512', (err, key) => err ? reject(err) : resolve(key.toString('hex'))));
|
|
16
14
|
if (newHash === passwordHash) {
|
|
@@ -37,4 +35,5 @@ export let CryptoPasswordHasher = class CryptoPasswordHasher {
|
|
|
37
35
|
CryptoPasswordHasher = __decorate([
|
|
38
36
|
Injectable({ lifetime: 'singleton' })
|
|
39
37
|
], CryptoPasswordHasher);
|
|
38
|
+
export { CryptoPasswordHasher };
|
|
40
39
|
//# sourceMappingURL=crypto-password-hasher.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crypto-password-hasher.js","sourceRoot":"","sources":["../src/crypto-password-hasher.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAE9C,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAIrC,
|
|
1
|
+
{"version":3,"file":"crypto-password-hasher.js","sourceRoot":"","sources":["../src/crypto-password-hasher.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAE9C,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAIrC,IAAM,oBAAoB,GAA1B,MAAM,oBAAoB;IACd,UAAU,GAAG,IAAI,CAAA;IACjB,MAAM,GAAG,EAAE,CAAA;IAErB,KAAK,CAAC,gBAAgB,CAC3B,QAAgB,EAChB,EAAE,YAAY,EAAE,IAAI,EAAsB;QAE1C,MAAM,OAAO,GAAG,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CACpD,MAAM,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAC1E,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CACjD,CACF,CAAA;QACD,IAAI,OAAO,KAAK,YAAY,EAAE;YAC5B,OAAO;gBACL,OAAO,EAAE,IAAI;aACd,CAAA;SACF;QACD,OAAO;YACL,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,uBAAuB;SAChC,CAAA;IACH,CAAC;IACM,KAAK,CAAC,gBAAgB,CAAC,QAAgB,EAAE,QAAgB;QAC9D,MAAM,IAAI,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;QAC5C,MAAM,YAAY,GAAG,MAAM,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CACjE,MAAM,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAC1E,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CACjD,CACF,CAAA;QACD,OAAO;YACL,QAAQ;YACR,IAAI;YACJ,YAAY;YACZ,YAAY,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACvC,CAAA;IACH,CAAC;CACF,CAAA;AArCY,oBAAoB;IADhC,UAAU,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;GACzB,oBAAoB,CAqChC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"password-complexity-error.js","sourceRoot":"","sources":["../../src/errors/password-complexity-error.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,uBAAwB,SAAQ,KAAK;
|
|
1
|
+
{"version":3,"file":"password-complexity-error.js","sourceRoot":"","sources":["../../src/errors/password-complexity-error.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,uBAAwB,SAAQ,KAAK;IAM9B;IALlB;;;OAGG;IACH,YACkB,MAAgD,EAChE,OAAgB;QAEhB,KAAK,CAAC,OAAO,CAAC,CAAA;QAHE,WAAM,GAAN,MAAM,CAA0C;IAIlE,CAAC;CACF"}
|
|
@@ -2,5 +2,21 @@
|
|
|
2
2
|
* Entry that stores credential info for password login
|
|
3
3
|
*/
|
|
4
4
|
export class PasswordCredential {
|
|
5
|
+
/**
|
|
6
|
+
* The unique name of the user
|
|
7
|
+
*/
|
|
8
|
+
userName;
|
|
9
|
+
/**
|
|
10
|
+
* The hashed password value
|
|
11
|
+
*/
|
|
12
|
+
passwordHash;
|
|
13
|
+
/**
|
|
14
|
+
* Salt value for password hashing // TODO
|
|
15
|
+
*/
|
|
16
|
+
salt;
|
|
17
|
+
/**
|
|
18
|
+
* The Creation date in ISO String format
|
|
19
|
+
*/
|
|
20
|
+
creationDate;
|
|
5
21
|
}
|
|
6
22
|
//# sourceMappingURL=password-credential.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"password-credential.js","sourceRoot":"","sources":["../../src/models/password-credential.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,OAAO,kBAAkB;
|
|
1
|
+
{"version":3,"file":"password-credential.js","sourceRoot":"","sources":["../../src/models/password-credential.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,OAAO,kBAAkB;IAC7B;;OAEG;IACH,QAAQ,CAAS;IACjB;;OAEG;IACH,YAAY,CAAS;IAErB;;OAEG;IACH,IAAI,CAAS;IAEb;;OAEG;IACH,YAAY,CAAS;CACtB"}
|
|
@@ -1,3 +1,15 @@
|
|
|
1
1
|
export class PasswordResetToken {
|
|
2
|
+
/**
|
|
3
|
+
* The related user name
|
|
4
|
+
*/
|
|
5
|
+
userName;
|
|
6
|
+
/**
|
|
7
|
+
* The Token value - should be some kind of generated UUID that can be included e.g. in URLs
|
|
8
|
+
*/
|
|
9
|
+
token;
|
|
10
|
+
/**
|
|
11
|
+
* The creation date in an ISO datetime format
|
|
12
|
+
*/
|
|
13
|
+
createdAt;
|
|
2
14
|
}
|
|
3
15
|
//# sourceMappingURL=password-reset-token.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"password-reset-token.js","sourceRoot":"","sources":["../../src/models/password-reset-token.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,kBAAkB;
|
|
1
|
+
{"version":3,"file":"password-reset-token.js","sourceRoot":"","sources":["../../src/models/password-reset-token.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,kBAAkB;IAC7B;;OAEG;IACH,QAAQ,CAAS;IACjB;;OAEG;IACH,KAAK,CAAS;IACd;;OAEG;IACH,SAAS,CAAS;CACnB"}
|
|
@@ -13,12 +13,10 @@ import { SecurityPolicyManager } from './security-policy-manager.js';
|
|
|
13
13
|
import { UnauthenticatedError } from './errors/index.js';
|
|
14
14
|
import { PasswordCredential, PasswordResetToken } from './models/index.js';
|
|
15
15
|
import { PasswordComplexityError } from './errors/password-complexity-error.js';
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
this.getHasher = () => this.injector.getInstance(this.policyManager.policy.hasher);
|
|
21
|
-
}
|
|
16
|
+
let PasswordAuthenticator = class PasswordAuthenticator {
|
|
17
|
+
getPasswordStore = () => this.injector.getInstance(StoreManager).getStoreFor(PasswordCredential, 'userName');
|
|
18
|
+
getTokenStore = () => this.injector.getInstance(StoreManager).getStoreFor(PasswordResetToken, 'token');
|
|
19
|
+
getHasher = () => this.injector.getInstance(this.policyManager.policy.hasher);
|
|
22
20
|
/**
|
|
23
21
|
* @param userName The User's unique name
|
|
24
22
|
* @param plainPassword The plain password to check
|
|
@@ -87,6 +85,8 @@ export let PasswordAuthenticator = class PasswordAuthenticator {
|
|
|
87
85
|
existing && (await store.remove(existing.userName));
|
|
88
86
|
await store.add(newCredential);
|
|
89
87
|
}
|
|
88
|
+
injector;
|
|
89
|
+
policyManager;
|
|
90
90
|
};
|
|
91
91
|
__decorate([
|
|
92
92
|
Injected(Injector),
|
|
@@ -99,4 +99,5 @@ __decorate([
|
|
|
99
99
|
PasswordAuthenticator = __decorate([
|
|
100
100
|
Injectable({ lifetime: 'singleton' })
|
|
101
101
|
], PasswordAuthenticator);
|
|
102
|
+
export { PasswordAuthenticator };
|
|
102
103
|
//# sourceMappingURL=password-authenticator.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"password-authenticator.js","sourceRoot":"","sources":["../src/password-authenticator.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAC9C,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAA;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AAExD,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAC1E,OAAO,EAAE,uBAAuB,EAAE,MAAM,uCAAuC,CAAA;AAGxE,
|
|
1
|
+
{"version":3,"file":"password-authenticator.js","sourceRoot":"","sources":["../src/password-authenticator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password-authenticator.spec.d.ts","sourceRoot":"","sources":["../src/password-authenticator.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
import { addStore, InMemoryStore, StoreManager, User } from '@furystack/core';
|
|
2
|
+
import { Injector } from '@furystack/inject';
|
|
3
|
+
import { using, usingAsync } from '@furystack/utils';
|
|
4
|
+
import { usePasswordPolicy } from './helpers.js';
|
|
5
|
+
import { PasswordAuthenticator } from './password-authenticator.js';
|
|
6
|
+
import { createMinLengthComplexityRule } from './password-complexity-rules/min-length.js';
|
|
7
|
+
import { SecurityPolicyManager } from './security-policy-manager.js';
|
|
8
|
+
import { PasswordComplexityError } from './errors/password-complexity-error.js';
|
|
9
|
+
import { randomBytes } from 'crypto';
|
|
10
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
11
|
+
import { PasswordCredential } from './models/password-credential.js';
|
|
12
|
+
import { UnauthenticatedError } from './errors/unauthenticated-error.js';
|
|
13
|
+
import { PasswordResetToken } from './models/password-reset-token.js';
|
|
14
|
+
const randomString = () => randomBytes(32).toString('hex');
|
|
15
|
+
describe('PasswordAuthenticator', () => {
|
|
16
|
+
it('Should be instantiated', () => {
|
|
17
|
+
using(new Injector(), (i) => {
|
|
18
|
+
const auth = i.getInstance(PasswordAuthenticator);
|
|
19
|
+
expect(auth).toBeInstanceOf(PasswordAuthenticator);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
it('Should inherit policy from the extension method', () => {
|
|
23
|
+
using(new Injector(), (i) => {
|
|
24
|
+
usePasswordPolicy(i, {
|
|
25
|
+
passwordComplexityRules: [createMinLengthComplexityRule(3)],
|
|
26
|
+
});
|
|
27
|
+
const auth = i.getInstance(PasswordAuthenticator);
|
|
28
|
+
expect(auth).toBeInstanceOf(PasswordAuthenticator);
|
|
29
|
+
expect(auth.policyManager.policy.passwordComplexityRules[0].name).toBe('minLength');
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
describe('checkPasswordForUser', () => {
|
|
33
|
+
it('Should return a truthy value for valid username and password', async () => {
|
|
34
|
+
await usingAsync(new Injector(), async (i) => {
|
|
35
|
+
const userName = randomString();
|
|
36
|
+
const password = randomString();
|
|
37
|
+
addStore(i, new InMemoryStore({ model: PasswordCredential, primaryKey: 'userName' })).addStore(new InMemoryStore({ model: User, primaryKey: 'username' }));
|
|
38
|
+
usePasswordPolicy(i, {});
|
|
39
|
+
const authenticator = i.getInstance(PasswordAuthenticator);
|
|
40
|
+
const hasher = authenticator.getHasher();
|
|
41
|
+
const passwordStore = i.getInstance(StoreManager).getStoreFor(PasswordCredential, 'userName');
|
|
42
|
+
const entry = await hasher.createCredential(userName, password);
|
|
43
|
+
await passwordStore.add(entry);
|
|
44
|
+
const successResult = await authenticator.checkPasswordForUser(userName, password);
|
|
45
|
+
expect(successResult.isValid).toBeTruthy();
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
it('Should return a falsy value for invalid username', async () => {
|
|
49
|
+
await usingAsync(new Injector(), async (i) => {
|
|
50
|
+
const userName = randomString();
|
|
51
|
+
const password = randomString();
|
|
52
|
+
addStore(i, new InMemoryStore({ model: PasswordCredential, primaryKey: 'userName' })).addStore(new InMemoryStore({ model: User, primaryKey: 'username' }));
|
|
53
|
+
usePasswordPolicy(i);
|
|
54
|
+
const authenticator = i.getInstance(PasswordAuthenticator);
|
|
55
|
+
const hasher = authenticator.getHasher();
|
|
56
|
+
const passwordStore = i.getInstance(StoreManager).getStoreFor(PasswordCredential, 'userName');
|
|
57
|
+
const entry = await hasher.createCredential(userName, password);
|
|
58
|
+
await passwordStore.add(entry);
|
|
59
|
+
const failResult = await authenticator.checkPasswordForUser('invalidUsername', password);
|
|
60
|
+
expect(failResult.isValid).toBeFalsy();
|
|
61
|
+
expect(failResult.reason).toBe('badUsernameOrPassword');
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
it('Should return a falsy value for invalid password', async () => {
|
|
65
|
+
await usingAsync(new Injector(), async (i) => {
|
|
66
|
+
const userName = randomString();
|
|
67
|
+
const password = randomString();
|
|
68
|
+
addStore(i, new InMemoryStore({ model: PasswordCredential, primaryKey: 'userName' })).addStore(new InMemoryStore({ model: User, primaryKey: 'username' }));
|
|
69
|
+
usePasswordPolicy(i);
|
|
70
|
+
const authenticator = i.getInstance(PasswordAuthenticator);
|
|
71
|
+
const hasher = authenticator.getHasher();
|
|
72
|
+
const passwordStore = i.getInstance(StoreManager).getStoreFor(PasswordCredential, 'userName');
|
|
73
|
+
const entry = await hasher.createCredential(userName, password);
|
|
74
|
+
await passwordStore.add(entry);
|
|
75
|
+
const failResult = await authenticator.checkPasswordForUser(userName, 'someInvalidPassword');
|
|
76
|
+
expect(failResult.isValid).toBeFalsy();
|
|
77
|
+
expect(failResult.reason).toBe('badUsernameOrPassword');
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
it('Should return a falsy value for an expired password', async () => {
|
|
81
|
+
await usingAsync(new Injector(), async (i) => {
|
|
82
|
+
const userName = randomString();
|
|
83
|
+
const password = randomString();
|
|
84
|
+
addStore(i, new InMemoryStore({ model: PasswordCredential, primaryKey: 'userName' })).addStore(new InMemoryStore({ model: User, primaryKey: 'username' }));
|
|
85
|
+
usePasswordPolicy(i, { passwordExpirationDays: 1 });
|
|
86
|
+
const authenticator = i.getInstance(PasswordAuthenticator);
|
|
87
|
+
const hasher = authenticator.getHasher();
|
|
88
|
+
const passwordStore = i.getInstance(StoreManager).getStoreFor(PasswordCredential, 'userName');
|
|
89
|
+
const entry = await hasher.createCredential(userName, password);
|
|
90
|
+
const creationDate = new Date();
|
|
91
|
+
creationDate.setDate(creationDate.getDate() - 2);
|
|
92
|
+
entry.creationDate = creationDate.toISOString();
|
|
93
|
+
await passwordStore.add(entry);
|
|
94
|
+
const failResult = await authenticator.checkPasswordForUser(userName, password);
|
|
95
|
+
expect(failResult.isValid).toBeFalsy();
|
|
96
|
+
expect(failResult.reason).toBe('passwordExpired');
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
describe('setPasswordForUser', () => {
|
|
101
|
+
it('Should be able to set the password for the user using the last password', async () => {
|
|
102
|
+
await usingAsync(new Injector(), async (i) => {
|
|
103
|
+
const userName = randomString();
|
|
104
|
+
const lastPassword = randomString();
|
|
105
|
+
const password = randomString();
|
|
106
|
+
addStore(i, new InMemoryStore({ model: PasswordCredential, primaryKey: 'userName' })).addStore(new InMemoryStore({ model: User, primaryKey: 'username' }));
|
|
107
|
+
usePasswordPolicy(i);
|
|
108
|
+
const authenticator = i.getInstance(PasswordAuthenticator);
|
|
109
|
+
const hasher = authenticator.getHasher();
|
|
110
|
+
const passwordStore = i.getInstance(StoreManager).getStoreFor(PasswordCredential, 'userName');
|
|
111
|
+
const policyManager = i.getInstance(SecurityPolicyManager);
|
|
112
|
+
const pmSpy = vi.spyOn(policyManager, 'matchPasswordComplexityRules');
|
|
113
|
+
const entry = await hasher.createCredential(userName, lastPassword);
|
|
114
|
+
await passwordStore.add(entry);
|
|
115
|
+
await authenticator.setPasswordForUser(userName, lastPassword, password);
|
|
116
|
+
expect(pmSpy).toBeCalled();
|
|
117
|
+
const entryCount = await passwordStore.count({ userName: { $eq: userName } });
|
|
118
|
+
expect(entryCount).toBe(1); // old entry should be removed
|
|
119
|
+
const successResult = await authenticator.checkPasswordForUser(userName, password);
|
|
120
|
+
expect(successResult.isValid).toBeTruthy();
|
|
121
|
+
// Password updated, cannot use the last password
|
|
122
|
+
const failResult = await authenticator.checkPasswordForUser(userName, lastPassword);
|
|
123
|
+
expect(failResult.isValid).toBeFalsy();
|
|
124
|
+
expect(failResult.reason).toBe('badUsernameOrPassword');
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
it('Should throw PasswordComplexityError if the complexity rules are not respected', async () => {
|
|
128
|
+
await usingAsync(new Injector(), async (i) => {
|
|
129
|
+
const userName = randomString();
|
|
130
|
+
const lastPassword = randomString();
|
|
131
|
+
const password = '';
|
|
132
|
+
addStore(i, new InMemoryStore({ model: PasswordCredential, primaryKey: 'userName' })).addStore(new InMemoryStore({ model: User, primaryKey: 'username' }));
|
|
133
|
+
usePasswordPolicy(i, { passwordComplexityRules: [createMinLengthComplexityRule(3)] });
|
|
134
|
+
const authenticator = i.getInstance(PasswordAuthenticator);
|
|
135
|
+
const hasher = authenticator.getHasher();
|
|
136
|
+
const passwordStore = i.getInstance(StoreManager).getStoreFor(PasswordCredential, 'userName');
|
|
137
|
+
const policyManager = i.getInstance(SecurityPolicyManager);
|
|
138
|
+
const pmSpy = vi.spyOn(policyManager, 'matchPasswordComplexityRules');
|
|
139
|
+
const entry = await hasher.createCredential(userName, lastPassword);
|
|
140
|
+
await passwordStore.add(entry);
|
|
141
|
+
await expect(authenticator.setPasswordForUser(userName, lastPassword, password)).rejects.toThrowError(PasswordComplexityError);
|
|
142
|
+
expect(pmSpy).toBeCalled();
|
|
143
|
+
const entryCount = await passwordStore.count({ userName: { $eq: userName } });
|
|
144
|
+
expect(entryCount).toBe(1); // old entry should be removed
|
|
145
|
+
const failResult = await authenticator.checkPasswordForUser(userName, password);
|
|
146
|
+
// Password NOT updated, can use the last password
|
|
147
|
+
expect(failResult.isValid).toBeFalsy();
|
|
148
|
+
expect(failResult.reason).toBe('badUsernameOrPassword');
|
|
149
|
+
// Password NOT updated, cannot use the new password
|
|
150
|
+
const successResult = await authenticator.checkPasswordForUser(userName, lastPassword);
|
|
151
|
+
expect(successResult.isValid).toBeTruthy();
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
it('Should throw UnauthenticatedError if the last password is not valid', async () => {
|
|
155
|
+
await usingAsync(new Injector(), async (i) => {
|
|
156
|
+
const userName = randomString();
|
|
157
|
+
const lastPassword = randomString();
|
|
158
|
+
const password = randomString();
|
|
159
|
+
addStore(i, new InMemoryStore({ model: PasswordCredential, primaryKey: 'userName' })).addStore(new InMemoryStore({ model: User, primaryKey: 'username' }));
|
|
160
|
+
usePasswordPolicy(i);
|
|
161
|
+
const authenticator = i.getInstance(PasswordAuthenticator);
|
|
162
|
+
const hasher = authenticator.getHasher();
|
|
163
|
+
const passwordStore = i.getInstance(StoreManager).getStoreFor(PasswordCredential, 'userName');
|
|
164
|
+
const policyManager = i.getInstance(SecurityPolicyManager);
|
|
165
|
+
const pmSpy = vi.spyOn(policyManager, 'matchPasswordComplexityRules');
|
|
166
|
+
const entry = await hasher.createCredential(userName, lastPassword);
|
|
167
|
+
await passwordStore.add(entry);
|
|
168
|
+
await expect(authenticator.setPasswordForUser(userName, 'someBadLastPassword', password)).rejects.toThrowError(UnauthenticatedError);
|
|
169
|
+
expect(pmSpy).toBeCalled();
|
|
170
|
+
const entryCount = await passwordStore.count({ userName: { $eq: userName } });
|
|
171
|
+
expect(entryCount).toBe(1); // old entry should be removed
|
|
172
|
+
const failResult = await authenticator.checkPasswordForUser(userName, password);
|
|
173
|
+
// Password NOT updated, can use the last password
|
|
174
|
+
expect(failResult.isValid).toBeFalsy();
|
|
175
|
+
expect(failResult.reason).toBe('badUsernameOrPassword');
|
|
176
|
+
// Password NOT updated, cannot use the new password
|
|
177
|
+
const successResult = await authenticator.checkPasswordForUser(userName, lastPassword);
|
|
178
|
+
expect(successResult.isValid).toBeTruthy();
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
describe('resetPasswordForUser', () => {
|
|
183
|
+
it('Should reset the password with the valid token', async () => {
|
|
184
|
+
await usingAsync(new Injector(), async (i) => {
|
|
185
|
+
const userName = randomString();
|
|
186
|
+
const lastPassword = randomString();
|
|
187
|
+
const password = randomString();
|
|
188
|
+
const token = randomString();
|
|
189
|
+
addStore(i, new InMemoryStore({ model: PasswordCredential, primaryKey: 'userName' }))
|
|
190
|
+
.addStore(new InMemoryStore({ model: User, primaryKey: 'username' }))
|
|
191
|
+
.addStore(new InMemoryStore({ model: PasswordResetToken, primaryKey: 'token' }));
|
|
192
|
+
usePasswordPolicy(i);
|
|
193
|
+
const authenticator = i.getInstance(PasswordAuthenticator);
|
|
194
|
+
const hasher = authenticator.getHasher();
|
|
195
|
+
const passwordStore = i.getInstance(StoreManager).getStoreFor(PasswordCredential, 'userName');
|
|
196
|
+
const resetTokenStore = i.getInstance(StoreManager).getStoreFor(PasswordResetToken, 'token');
|
|
197
|
+
const entry = await hasher.createCredential(userName, lastPassword);
|
|
198
|
+
await passwordStore.add(entry);
|
|
199
|
+
await resetTokenStore.add({ userName, createdAt: new Date().toISOString(), token });
|
|
200
|
+
await authenticator.resetPasswordForUser(token, password);
|
|
201
|
+
const successResult = await authenticator.checkPasswordForUser(userName, password);
|
|
202
|
+
expect(successResult.isValid).toBeTruthy();
|
|
203
|
+
// Password updated, cannot use the last password
|
|
204
|
+
const failResult = await authenticator.checkPasswordForUser(userName, lastPassword);
|
|
205
|
+
expect(failResult.isValid).toBeFalsy();
|
|
206
|
+
expect(failResult.reason).toBe('badUsernameOrPassword');
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
it('Should throw PasswordComplexityError if the complexity rules are not respected', async () => {
|
|
210
|
+
await usingAsync(new Injector(), async (i) => {
|
|
211
|
+
const userName = randomString();
|
|
212
|
+
const lastPassword = randomString();
|
|
213
|
+
const password = '';
|
|
214
|
+
const token = randomString();
|
|
215
|
+
addStore(i, new InMemoryStore({ model: PasswordCredential, primaryKey: 'userName' }))
|
|
216
|
+
.addStore(new InMemoryStore({ model: User, primaryKey: 'username' }))
|
|
217
|
+
.addStore(new InMemoryStore({ model: PasswordResetToken, primaryKey: 'token' }));
|
|
218
|
+
usePasswordPolicy(i, { passwordComplexityRules: [createMinLengthComplexityRule(3)] });
|
|
219
|
+
const authenticator = i.getInstance(PasswordAuthenticator);
|
|
220
|
+
const hasher = authenticator.getHasher();
|
|
221
|
+
const passwordStore = i.getInstance(StoreManager).getStoreFor(PasswordCredential, 'userName');
|
|
222
|
+
const resetTokenStore = i.getInstance(StoreManager).getStoreFor(PasswordResetToken, 'token');
|
|
223
|
+
const entry = await hasher.createCredential(userName, lastPassword);
|
|
224
|
+
await passwordStore.add(entry);
|
|
225
|
+
await resetTokenStore.add({ userName, createdAt: new Date().toISOString(), token });
|
|
226
|
+
await expect(authenticator.resetPasswordForUser(token, password)).rejects.toThrowError(PasswordComplexityError);
|
|
227
|
+
const successResult = await authenticator.checkPasswordForUser(userName, lastPassword);
|
|
228
|
+
expect(successResult.isValid).toBeTruthy();
|
|
229
|
+
// Password updated, cannot use the last password
|
|
230
|
+
const failResult = await authenticator.checkPasswordForUser(userName, password);
|
|
231
|
+
expect(failResult.isValid).toBeFalsy();
|
|
232
|
+
expect(failResult.reason).toBe('badUsernameOrPassword');
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
it('Should throw UnauthenticatedError if the token is not valid', async () => {
|
|
236
|
+
await usingAsync(new Injector(), async (i) => {
|
|
237
|
+
const userName = randomString();
|
|
238
|
+
const lastPassword = randomString();
|
|
239
|
+
const password = '';
|
|
240
|
+
const token = randomString();
|
|
241
|
+
addStore(i, new InMemoryStore({ model: PasswordCredential, primaryKey: 'userName' }))
|
|
242
|
+
.addStore(new InMemoryStore({ model: User, primaryKey: 'username' }))
|
|
243
|
+
.addStore(new InMemoryStore({ model: PasswordResetToken, primaryKey: 'token' }));
|
|
244
|
+
usePasswordPolicy(i);
|
|
245
|
+
const authenticator = i.getInstance(PasswordAuthenticator);
|
|
246
|
+
const hasher = authenticator.getHasher();
|
|
247
|
+
const passwordStore = i.getInstance(StoreManager).getStoreFor(PasswordCredential, 'userName');
|
|
248
|
+
const resetTokenStore = i.getInstance(StoreManager).getStoreFor(PasswordResetToken, 'token');
|
|
249
|
+
const entry = await hasher.createCredential(userName, lastPassword);
|
|
250
|
+
await passwordStore.add(entry);
|
|
251
|
+
await resetTokenStore.add({ userName, createdAt: new Date().toISOString(), token });
|
|
252
|
+
await expect(authenticator.resetPasswordForUser('someBadToken', password)).rejects.toThrowError(UnauthenticatedError);
|
|
253
|
+
const successResult = await authenticator.checkPasswordForUser(userName, lastPassword);
|
|
254
|
+
expect(successResult.isValid).toBeTruthy();
|
|
255
|
+
// Password updated, cannot use the last password
|
|
256
|
+
const failResult = await authenticator.checkPasswordForUser(userName, password);
|
|
257
|
+
expect(failResult.isValid).toBeFalsy();
|
|
258
|
+
expect(failResult.reason).toBe('badUsernameOrPassword');
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
it('Should throw UnauthenticatedError and clean up token if the token has been expired', async () => {
|
|
262
|
+
await usingAsync(new Injector(), async (i) => {
|
|
263
|
+
const userName = randomString();
|
|
264
|
+
const lastPassword = randomString();
|
|
265
|
+
const password = '';
|
|
266
|
+
const token = randomString();
|
|
267
|
+
addStore(i, new InMemoryStore({ model: PasswordCredential, primaryKey: 'userName' }))
|
|
268
|
+
.addStore(new InMemoryStore({ model: User, primaryKey: 'username' }))
|
|
269
|
+
.addStore(new InMemoryStore({ model: PasswordResetToken, primaryKey: 'token' }));
|
|
270
|
+
usePasswordPolicy(i, { resetTokenExpirationSeconds: 1 });
|
|
271
|
+
const authenticator = i.getInstance(PasswordAuthenticator);
|
|
272
|
+
const hasher = authenticator.getHasher();
|
|
273
|
+
const passwordStore = i.getInstance(StoreManager).getStoreFor(PasswordCredential, 'userName');
|
|
274
|
+
const resetTokenStore = i.getInstance(StoreManager).getStoreFor(PasswordResetToken, 'token');
|
|
275
|
+
const entry = await hasher.createCredential(userName, lastPassword);
|
|
276
|
+
await passwordStore.add(entry);
|
|
277
|
+
const creationDate = new Date();
|
|
278
|
+
creationDate.setDate(creationDate.getDate() - 2);
|
|
279
|
+
await resetTokenStore.add({ userName, createdAt: creationDate.toISOString(), token });
|
|
280
|
+
await expect(authenticator.resetPasswordForUser(token, password)).rejects.toThrowError(UnauthenticatedError);
|
|
281
|
+
const successResult = await authenticator.checkPasswordForUser(userName, lastPassword);
|
|
282
|
+
expect(successResult.isValid).toBeTruthy();
|
|
283
|
+
// Password updated, cannot use the last password
|
|
284
|
+
const failResult = await authenticator.checkPasswordForUser(userName, password);
|
|
285
|
+
expect(failResult.isValid).toBeFalsy();
|
|
286
|
+
expect(failResult.reason).toBe('badUsernameOrPassword');
|
|
287
|
+
const tokenCount = await resetTokenStore.count();
|
|
288
|
+
expect(tokenCount).toBe(0);
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
//# sourceMappingURL=password-authenticator.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password-authenticator.spec.js","sourceRoot":"","sources":["../src/password-authenticator.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contains-lowercase.spec.d.ts","sourceRoot":"","sources":["../../src/password-complexity-rules/contains-lowercase.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { createContainsLowercasePolicy } from './contains-lowercase.js';
|
|
2
|
+
import { describe, it, expect } from 'vitest';
|
|
3
|
+
describe('Contains-lowercase', () => {
|
|
4
|
+
it('Should fail if the password is shorter than expected', async () => {
|
|
5
|
+
const policy = createContainsLowercasePolicy(3);
|
|
6
|
+
const result = await policy.check('');
|
|
7
|
+
expect(result.success).toBe(false);
|
|
8
|
+
expect(result.message).toBe('The password should contain at least 3 lower case characters');
|
|
9
|
+
});
|
|
10
|
+
it('Should fail if the password does not contain enough lowercase chars', async () => {
|
|
11
|
+
const policy = createContainsLowercasePolicy(3);
|
|
12
|
+
const result = await policy.check('ASD12345(=/!+');
|
|
13
|
+
expect(result.success).toBe(false);
|
|
14
|
+
expect(result.message).toBe('The password should contain at least 3 lower case characters');
|
|
15
|
+
});
|
|
16
|
+
it('Should succeed if the password contains enough lowercase chars', async () => {
|
|
17
|
+
const policy = createContainsLowercasePolicy(3);
|
|
18
|
+
const result = await policy.check('asd');
|
|
19
|
+
expect(result.success).toBe(true);
|
|
20
|
+
});
|
|
21
|
+
it('Should succeed if the password contains enough lowercase chars supporting special ones', async () => {
|
|
22
|
+
const policy = createContainsLowercasePolicy(3);
|
|
23
|
+
const result = await policy.check('éáő');
|
|
24
|
+
expect(result.success).toBe(true);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
//# sourceMappingURL=contains-lowercase.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contains-lowercase.spec.js","sourceRoot":"","sources":["../../src/password-complexity-rules/contains-lowercase.spec.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAA;AACvE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE7C,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;QACpE,MAAM,MAAM,GAAG,6BAA6B,CAAC,CAAC,CAAC,CAAA;QAC/C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QACrC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAClC,MAAM,CAAE,MAAyC,CAAC,OAAO,CAAC,CAAC,IAAI,CAC7D,8DAA8D,CAC/D,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qEAAqE,EAAE,KAAK,IAAI,EAAE;QACnF,MAAM,MAAM,GAAG,6BAA6B,CAAC,CAAC,CAAC,CAAA;QAC/C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,CAAA;QAClD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAClC,MAAM,CAAE,MAAyC,CAAC,OAAO,CAAC,CAAC,IAAI,CAC7D,8DAA8D,CAC/D,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,gEAAgE,EAAE,KAAK,IAAI,EAAE;QAC9E,MAAM,MAAM,GAAG,6BAA6B,CAAC,CAAC,CAAC,CAAA;QAC/C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QACxC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACnC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,wFAAwF,EAAE,KAAK,IAAI,EAAE;QACtG,MAAM,MAAM,GAAG,6BAA6B,CAAC,CAAC,CAAC,CAAA;QAC/C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QACxC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACnC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contains-uppercase.spec.d.ts","sourceRoot":"","sources":["../../src/password-complexity-rules/contains-uppercase.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { createContainsUppercasePolicy } from './contains-uppercase.js';
|
|
2
|
+
import { describe, it, expect } from 'vitest';
|
|
3
|
+
describe('Contains-uppercase', () => {
|
|
4
|
+
it('Should fail if the password is shorter than expected', async () => {
|
|
5
|
+
const policy = createContainsUppercasePolicy(3);
|
|
6
|
+
const result = await policy.check('');
|
|
7
|
+
expect(result.success).toBe(false);
|
|
8
|
+
expect(result.message).toBe('The password should contain at least 3 upper case characters');
|
|
9
|
+
});
|
|
10
|
+
it('Should fail if the password does not contain enough lowercase chars', async () => {
|
|
11
|
+
const policy = createContainsUppercasePolicy(3);
|
|
12
|
+
const result = await policy.check('asd12345(=/!+');
|
|
13
|
+
expect(result.success).toBe(false);
|
|
14
|
+
expect(result.message).toBe('The password should contain at least 3 upper case characters');
|
|
15
|
+
});
|
|
16
|
+
it('Should succeed if the password contains enough lowercase chars', async () => {
|
|
17
|
+
const policy = createContainsUppercasePolicy(3);
|
|
18
|
+
const result = await policy.check('ASD');
|
|
19
|
+
expect(result.success).toBe(true);
|
|
20
|
+
});
|
|
21
|
+
it('Should succeed if the password contains enough lowercase chars supporting special ones', async () => {
|
|
22
|
+
const policy = createContainsUppercasePolicy(3);
|
|
23
|
+
const result = await policy.check('ÉÁÍ');
|
|
24
|
+
expect(result.success).toBe(true);
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
//# sourceMappingURL=contains-uppercase.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contains-uppercase.spec.js","sourceRoot":"","sources":["../../src/password-complexity-rules/contains-uppercase.spec.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAA;AACvE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE7C,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;QACpE,MAAM,MAAM,GAAG,6BAA6B,CAAC,CAAC,CAAC,CAAA;QAC/C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QACrC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAClC,MAAM,CAAE,MAAyC,CAAC,OAAO,CAAC,CAAC,IAAI,CAC7D,8DAA8D,CAC/D,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qEAAqE,EAAE,KAAK,IAAI,EAAE;QACnF,MAAM,MAAM,GAAG,6BAA6B,CAAC,CAAC,CAAC,CAAA;QAC/C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,CAAA;QAClD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAClC,MAAM,CAAE,MAAyC,CAAC,OAAO,CAAC,CAAC,IAAI,CAC7D,8DAA8D,CAC/D,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,gEAAgE,EAAE,KAAK,IAAI,EAAE;QAC9E,MAAM,MAAM,GAAG,6BAA6B,CAAC,CAAC,CAAC,CAAA;QAC/C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QACxC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACnC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,wFAAwF,EAAE,KAAK,IAAI,EAAE;QACtG,MAAM,MAAM,GAAG,6BAA6B,CAAC,CAAC,CAAC,CAAA;QAC/C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QACxC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACnC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"max-length.spec.d.ts","sourceRoot":"","sources":["../../src/password-complexity-rules/max-length.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createMaxLengthComplexityRule } from './max-length.js';
|
|
2
|
+
import { describe, it, expect } from 'vitest';
|
|
3
|
+
describe('max-length', () => {
|
|
4
|
+
it('Should fail if the password is longer than expected', async () => {
|
|
5
|
+
const policy = createMaxLengthComplexityRule(3);
|
|
6
|
+
const result = await policy.check('asdasd123');
|
|
7
|
+
expect(result.success).toBe(false);
|
|
8
|
+
expect(result.message).toBe('The password has to be maximum 3 character length');
|
|
9
|
+
});
|
|
10
|
+
it('Should fail if the password does not contain enough lowercase chars', async () => {
|
|
11
|
+
const policy = createMaxLengthComplexityRule(3);
|
|
12
|
+
const result = await policy.check('asd');
|
|
13
|
+
expect(result.success).toBe(true);
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
//# sourceMappingURL=max-length.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"max-length.spec.js","sourceRoot":"","sources":["../../src/password-complexity-rules/max-length.spec.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,6BAA6B,EAAE,MAAM,iBAAiB,CAAA;AAC/D,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE7C,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,EAAE,CAAC,qDAAqD,EAAE,KAAK,IAAI,EAAE;QACnE,MAAM,MAAM,GAAG,6BAA6B,CAAC,CAAC,CAAC,CAAA;QAC/C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA;QAC9C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAClC,MAAM,CAAE,MAAyC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,mDAAmD,CAAC,CAAA;IACtH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qEAAqE,EAAE,KAAK,IAAI,EAAE;QACnF,MAAM,MAAM,GAAG,6BAA6B,CAAC,CAAC,CAAC,CAAA;QAC/C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;QACxC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACnC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"min-length.spec.d.ts","sourceRoot":"","sources":["../../src/password-complexity-rules/min-length.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createMinLengthComplexityRule } from './min-length.js';
|
|
2
|
+
import { describe, it, expect } from 'vitest';
|
|
3
|
+
describe('min-length', () => {
|
|
4
|
+
it('Should fail if the password is shorter than expected', async () => {
|
|
5
|
+
const policy = createMinLengthComplexityRule(3);
|
|
6
|
+
const result = await policy.check('');
|
|
7
|
+
expect(result.success).toBe(false);
|
|
8
|
+
expect(result.message).toBe('The password has to be at least 3 character length');
|
|
9
|
+
});
|
|
10
|
+
it('Should fail if the password does not contain enough lowercase chars', async () => {
|
|
11
|
+
const policy = createMinLengthComplexityRule(3);
|
|
12
|
+
const result = await policy.check('asd12345(=/!+');
|
|
13
|
+
expect(result.success).toBe(true);
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
//# sourceMappingURL=min-length.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"min-length.spec.js","sourceRoot":"","sources":["../../src/password-complexity-rules/min-length.spec.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,6BAA6B,EAAE,MAAM,iBAAiB,CAAA;AAC/D,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE7C,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,EAAE,CAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;QACpE,MAAM,MAAM,GAAG,6BAA6B,CAAC,CAAC,CAAC,CAAA;QAC/C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QACrC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAClC,MAAM,CAAE,MAAyC,CAAC,OAAO,CAAC,CAAC,IAAI,CAC7D,oDAAoD,CACrD,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qEAAqE,EAAE,KAAK,IAAI,EAAE;QACnF,MAAM,MAAM,GAAG,6BAA6B,CAAC,CAAC,CAAC,CAAA;QAC/C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,CAAA;QAClD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACnC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
package/esm/password-hasher.js
CHANGED
|
@@ -5,7 +5,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
7
|
import { Injectable } from '@furystack/inject';
|
|
8
|
-
|
|
8
|
+
let PasswordHasher = class PasswordHasher {
|
|
9
9
|
createCredential(_userName, _password) {
|
|
10
10
|
throw Error('Set up hasher - TODO');
|
|
11
11
|
}
|
|
@@ -16,4 +16,5 @@ export let PasswordHasher = class PasswordHasher {
|
|
|
16
16
|
PasswordHasher = __decorate([
|
|
17
17
|
Injectable({ lifetime: 'singleton' })
|
|
18
18
|
], PasswordHasher);
|
|
19
|
+
export { PasswordHasher };
|
|
19
20
|
//# sourceMappingURL=password-hasher.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"password-hasher.js","sourceRoot":"","sources":["../src/password-hasher.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAIvC,
|
|
1
|
+
{"version":3,"file":"password-hasher.js","sourceRoot":"","sources":["../src/password-hasher.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAIvC,IAAM,cAAc,GAApB,MAAM,cAAc;IAClB,gBAAgB,CAAC,SAAiB,EAAE,SAAiB;QAC1D,MAAM,KAAK,CAAC,sBAAsB,CAAC,CAAA;IACrC,CAAC;IAEM,gBAAgB,CAAC,SAAiB,EAAE,WAA+B;QACxE,MAAM,KAAK,CAAC,sBAAsB,CAAC,CAAA;IACrC,CAAC;CACF,CAAA;AARY,cAAc;IAD1B,UAAU,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;GACzB,cAAc,CAQ1B"}
|
|
@@ -9,7 +9,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
9
9
|
};
|
|
10
10
|
import { Injectable, Injected } from '@furystack/inject';
|
|
11
11
|
import { SecurityPolicy } from './security-policy.js';
|
|
12
|
-
|
|
12
|
+
let SecurityPolicyManager = class SecurityPolicyManager {
|
|
13
13
|
/**
|
|
14
14
|
* @param password The Plain password string
|
|
15
15
|
* @returns if the password matches the complexity rules
|
|
@@ -45,6 +45,7 @@ export let SecurityPolicyManager = class SecurityPolicyManager {
|
|
|
45
45
|
const now = new Date();
|
|
46
46
|
return now > tokenExpiration;
|
|
47
47
|
}
|
|
48
|
+
policy;
|
|
48
49
|
};
|
|
49
50
|
__decorate([
|
|
50
51
|
Injected(SecurityPolicy),
|
|
@@ -53,4 +54,5 @@ __decorate([
|
|
|
53
54
|
SecurityPolicyManager = __decorate([
|
|
54
55
|
Injectable({ lifetime: 'singleton' })
|
|
55
56
|
], SecurityPolicyManager);
|
|
57
|
+
export { SecurityPolicyManager };
|
|
56
58
|
//# sourceMappingURL=security-policy-manager.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"security-policy-manager.js","sourceRoot":"","sources":["../src/security-policy-manager.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAExD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAG9C,
|
|
1
|
+
{"version":3,"file":"security-policy-manager.js","sourceRoot":"","sources":["../src/security-policy-manager.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAExD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAG9C,IAAM,qBAAqB,GAA3B,MAAM,qBAAqB;IAChC;;;OAGG;IACI,KAAK,CAAC,4BAA4B,CAAC,QAAgB;QACxD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,uBAAuB,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;QACzG,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,KAAK,CAAC,CAAA;QACxD,IAAI,MAAM,CAAC,MAAM,EAAE;YACjB,OAAO;gBACL,KAAK,EAAE,KAAc;gBACrB,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,KAAK,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAGnF;aACH,CAAA;SACF;QAED,OAAO;YACL,KAAK,EAAE,IAAa;SACrB,CAAA;IACH,CAAC;IAEM,kBAAkB,CAAC,UAA8B;QACtD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,sBAAsB,EAAE;YACvC,OAAO,KAAK,CAAA;SACb;QACD,MAAM,oBAAoB,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,CAAA;QAC9D,oBAAoB,CAAC,OAAO,CAAC,oBAAoB,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAA;QACjG,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAA;QACtB,OAAO,GAAG,GAAG,oBAAoB,CAAA;IACnC,CAAC;IAEM,eAAe,CAAC,KAAyB;QAC9C,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,2BAA2B,EAAE;YAC5C,OAAO,KAAK,CAAA;SACb;QACD,MAAM,eAAe,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;QACjD,eAAe,CAAC,UAAU,CAAC,eAAe,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,2BAA2B,CAAC,CAAA;QAClG,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAA;QACtB,OAAO,GAAG,GAAG,eAAe,CAAA;IAC9B,CAAC;IAGe,MAAM,CAAiB;CACxC,CAAA;AADiB;IADf,QAAQ,CAAC,cAAc,CAAC;8BACA,cAAc;qDAAA;AA5C5B,qBAAqB;IADjC,UAAU,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;GACzB,qBAAqB,CA6CjC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security-policy-manager.spec.d.ts","sourceRoot":"","sources":["../src/security-policy-manager.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Injector } from '@furystack/inject';
|
|
2
|
+
import { using } from '@furystack/utils';
|
|
3
|
+
import { usePasswordPolicy } from './helpers.js';
|
|
4
|
+
import { SecurityPolicyManager } from './security-policy-manager.js';
|
|
5
|
+
import { describe, it, expect } from 'vitest';
|
|
6
|
+
describe('SecurityPolicyManager', () => {
|
|
7
|
+
it('Should return false when no token expiration has been set', () => {
|
|
8
|
+
using(new Injector(), (i) => {
|
|
9
|
+
usePasswordPolicy(i, { resetTokenExpirationSeconds: 0 });
|
|
10
|
+
const result = i
|
|
11
|
+
.getInstance(SecurityPolicyManager)
|
|
12
|
+
.hasTokenExpired({ createdAt: new Date().toISOString(), token: 'token', userName: 'user' });
|
|
13
|
+
expect(result).toBeFalsy();
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
//# sourceMappingURL=security-policy-manager.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security-policy-manager.spec.js","sourceRoot":"","sources":["../src/security-policy-manager.spec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC5C,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AACxC,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAA;AACpE,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE7C,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,KAAK,CAAC,IAAI,QAAQ,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE;YAC1B,iBAAiB,CAAC,CAAC,EAAE,EAAE,2BAA2B,EAAE,CAAC,EAAE,CAAC,CAAA;YACxD,MAAM,MAAM,GAAG,CAAC;iBACb,WAAW,CAAC,qBAAqB,CAAC;iBAClC,eAAe,CAAC,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAA;YAC7F,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,CAAA;QAC5B,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
package/esm/security-policy.js
CHANGED
|
@@ -6,31 +6,30 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
6
6
|
};
|
|
7
7
|
import { Injectable } from '@furystack/inject';
|
|
8
8
|
import { CryptoPasswordHasher } from './crypto-password-hasher.js';
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
this.resetTokenExpirationSeconds = 15;
|
|
31
|
-
}
|
|
9
|
+
let SecurityPolicy = class SecurityPolicy {
|
|
10
|
+
/**
|
|
11
|
+
* A Hasher instance for password hash generation
|
|
12
|
+
*/
|
|
13
|
+
hasher = CryptoPasswordHasher;
|
|
14
|
+
/**
|
|
15
|
+
* Array of password complexity rules to apply
|
|
16
|
+
*/
|
|
17
|
+
passwordComplexityRules = [];
|
|
18
|
+
/**
|
|
19
|
+
* The password expiration in days
|
|
20
|
+
*/
|
|
21
|
+
passwordExpirationDays = 0;
|
|
22
|
+
/**
|
|
23
|
+
* Defines if the login needs a second factor authentication
|
|
24
|
+
*/
|
|
25
|
+
requireSecondFactor = 'never'; // TODO - Challenge based on trusted devices
|
|
26
|
+
/**
|
|
27
|
+
* The Password Reset Token expiration in seconds
|
|
28
|
+
*/
|
|
29
|
+
resetTokenExpirationSeconds = 15;
|
|
32
30
|
};
|
|
33
31
|
SecurityPolicy = __decorate([
|
|
34
32
|
Injectable({ lifetime: 'singleton' })
|
|
35
33
|
], SecurityPolicy);
|
|
34
|
+
export { SecurityPolicy };
|
|
36
35
|
//# sourceMappingURL=security-policy.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"security-policy.js","sourceRoot":"","sources":["../src/security-policy.ts"],"names":[],"mappings":";;;;;;AACA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAK3D,
|
|
1
|
+
{"version":3,"file":"security-policy.js","sourceRoot":"","sources":["../src/security-policy.ts"],"names":[],"mappings":";;;;;;AACA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAK3D,IAAM,cAAc,GAApB,MAAM,cAAc;IACzB;;OAEG;IACH,MAAM,GAAkC,oBAAoB,CAAA;IAE5D;;OAEG;IACH,uBAAuB,GAA6B,EAAE,CAAA;IAEtD;;OAEG;IACH,sBAAsB,GAAG,CAAC,CAAA;IAE1B;;OAEG;IACH,mBAAmB,GAAuB,OAAO,CAAA,CAAC,4CAA4C;IAE9F;;OAEG;IACH,2BAA2B,GAAG,EAAE,CAAA;CACjC,CAAA;AAzBY,cAAc;IAD1B,UAAU,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;GACzB,cAAc,CAyB1B"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@furystack/security",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.11",
|
|
4
4
|
"description": "Security, password management and authorization related stuff for FuryStack",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -35,14 +35,14 @@
|
|
|
35
35
|
"url": "https://github.com/furystack/furystack/issues"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@furystack/core": "^12.0.
|
|
39
|
-
"@furystack/inject": "^8.
|
|
40
|
-
"@furystack/utils": "^4.0.
|
|
38
|
+
"@furystack/core": "^12.0.11",
|
|
39
|
+
"@furystack/inject": "^8.1.1",
|
|
40
|
+
"@furystack/utils": "^4.0.10"
|
|
41
41
|
},
|
|
42
42
|
"homepage": "https://github.com/furystack/furystack",
|
|
43
43
|
"devDependencies": {
|
|
44
|
-
"@types/node": "^20.
|
|
45
|
-
"typescript": "^5.
|
|
46
|
-
"vitest": "^0.34.
|
|
44
|
+
"@types/node": "^20.8.10",
|
|
45
|
+
"typescript": "^5.2.2",
|
|
46
|
+
"vitest": "^0.34.6"
|
|
47
47
|
}
|
|
48
48
|
}
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { addStore, InMemoryStore, StoreManager, User } from '@furystack/core'
|
|
2
2
|
import { Injector } from '@furystack/inject'
|
|
3
3
|
import { using, usingAsync } from '@furystack/utils'
|
|
4
|
-
import { usePasswordPolicy } from './helpers'
|
|
5
|
-
import type { PasswordCheckFailedResult } from './models'
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { PasswordComplexityError, UnauthenticatedError } from './errors'
|
|
4
|
+
import { usePasswordPolicy } from './helpers.js'
|
|
5
|
+
import type { PasswordCheckFailedResult } from './models/password-check-result.js'
|
|
6
|
+
import { PasswordAuthenticator } from './password-authenticator.js'
|
|
7
|
+
import { createMinLengthComplexityRule } from './password-complexity-rules/min-length.js'
|
|
8
|
+
import { SecurityPolicyManager } from './security-policy-manager.js'
|
|
9
|
+
import { PasswordComplexityError } from './errors/password-complexity-error.js'
|
|
11
10
|
import { randomBytes } from 'crypto'
|
|
12
11
|
import { describe, it, expect, vi } from 'vitest'
|
|
12
|
+
import { PasswordCredential } from './models/password-credential.js'
|
|
13
|
+
import { UnauthenticatedError } from './errors/unauthenticated-error.js'
|
|
14
|
+
import { PasswordResetToken } from './models/password-reset-token.js'
|
|
13
15
|
|
|
14
16
|
const randomString = () => randomBytes(32).toString('hex')
|
|
15
17
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { PasswordComplexityFailedResult } from '../models'
|
|
2
|
-
import { createContainsLowercasePolicy } from './contains-lowercase'
|
|
1
|
+
import type { PasswordComplexityFailedResult } from '../models/password-complexity-result.js'
|
|
2
|
+
import { createContainsLowercasePolicy } from './contains-lowercase.js'
|
|
3
3
|
import { describe, it, expect } from 'vitest'
|
|
4
4
|
|
|
5
5
|
describe('Contains-lowercase', () => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { PasswordComplexityFailedResult } from '../models'
|
|
2
|
-
import { createContainsUppercasePolicy } from './contains-uppercase'
|
|
1
|
+
import type { PasswordComplexityFailedResult } from '../models/password-complexity-result.js'
|
|
2
|
+
import { createContainsUppercasePolicy } from './contains-uppercase.js'
|
|
3
3
|
import { describe, it, expect } from 'vitest'
|
|
4
4
|
|
|
5
5
|
describe('Contains-uppercase', () => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { PasswordComplexityFailedResult } from '../models'
|
|
2
|
-
import { createMaxLengthComplexityRule } from './max-length'
|
|
1
|
+
import type { PasswordComplexityFailedResult } from '../models/password-complexity-result.js'
|
|
2
|
+
import { createMaxLengthComplexityRule } from './max-length.js'
|
|
3
3
|
import { describe, it, expect } from 'vitest'
|
|
4
4
|
|
|
5
5
|
describe('max-length', () => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { PasswordComplexityFailedResult } from '../models'
|
|
2
|
-
import { createMinLengthComplexityRule } from './min-length'
|
|
1
|
+
import type { PasswordComplexityFailedResult } from '../models/password-complexity-result.js'
|
|
2
|
+
import { createMinLengthComplexityRule } from './min-length.js'
|
|
3
3
|
import { describe, it, expect } from 'vitest'
|
|
4
4
|
|
|
5
5
|
describe('min-length', () => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Injector } from '@furystack/inject'
|
|
2
2
|
import { using } from '@furystack/utils'
|
|
3
|
-
import { usePasswordPolicy } from './helpers'
|
|
4
|
-
import { SecurityPolicyManager } from './security-policy-manager'
|
|
3
|
+
import { usePasswordPolicy } from './helpers.js'
|
|
4
|
+
import { SecurityPolicyManager } from './security-policy-manager.js'
|
|
5
5
|
import { describe, it, expect } from 'vitest'
|
|
6
6
|
|
|
7
7
|
describe('SecurityPolicyManager', () => {
|