@furystack/security 1.0.0
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/CHANGELOG.md +5 -0
- package/LICENSE +339 -0
- package/README.md +4 -0
- package/dist/crypto-password-hasher.d.ts +14 -0
- package/dist/crypto-password-hasher.d.ts.map +1 -0
- package/dist/crypto-password-hasher.js +39 -0
- package/dist/crypto-password-hasher.js.map +1 -0
- package/dist/errors/index.d.ts +4 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +7 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/errors/password-complexity-error.d.ts +15 -0
- package/dist/errors/password-complexity-error.d.ts.map +1 -0
- package/dist/errors/password-complexity-error.js +15 -0
- package/dist/errors/password-complexity-error.js.map +1 -0
- package/dist/errors/unauthenticated-error.d.ts +6 -0
- package/dist/errors/unauthenticated-error.d.ts.map +1 -0
- package/dist/errors/unauthenticated-error.js +10 -0
- package/dist/errors/unauthenticated-error.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/injector-extensions.d.ts +13 -0
- package/dist/injector-extensions.d.ts.map +1 -0
- package/dist/injector-extensions.js +11 -0
- package/dist/injector-extensions.js.map +1 -0
- package/dist/models/index.d.ts +6 -0
- package/dist/models/index.d.ts.map +1 -0
- package/dist/models/index.js +9 -0
- package/dist/models/index.js.map +1 -0
- package/dist/models/password-check-result.d.ts +10 -0
- package/dist/models/password-check-result.d.ts.map +1 -0
- package/dist/models/password-check-result.js +3 -0
- package/dist/models/password-check-result.js.map +1 -0
- package/dist/models/password-complexity-result.d.ts +10 -0
- package/dist/models/password-complexity-result.d.ts.map +1 -0
- package/dist/models/password-complexity-result.js +3 -0
- package/dist/models/password-complexity-result.js.map +1 -0
- package/dist/models/password-complexity-rule.d.ts +6 -0
- package/dist/models/password-complexity-rule.d.ts.map +1 -0
- package/dist/models/password-complexity-rule.js +3 -0
- package/dist/models/password-complexity-rule.js.map +1 -0
- package/dist/models/password-credential.d.ts +22 -0
- package/dist/models/password-credential.d.ts.map +1 -0
- package/dist/models/password-credential.js +10 -0
- package/dist/models/password-credential.js.map +1 -0
- package/dist/models/password-reset-token.d.ts +15 -0
- package/dist/models/password-reset-token.d.ts.map +1 -0
- package/dist/models/password-reset-token.js +7 -0
- package/dist/models/password-reset-token.js.map +1 -0
- package/dist/password-authenticator.d.ts +38 -0
- package/dist/password-authenticator.d.ts.map +1 -0
- package/dist/password-authenticator.js +99 -0
- package/dist/password-authenticator.js.map +1 -0
- package/dist/password-authenticator.spec.d.ts +2 -0
- package/dist/password-authenticator.spec.d.ts.map +1 -0
- package/dist/password-authenticator.spec.js +309 -0
- package/dist/password-authenticator.spec.js.map +1 -0
- package/dist/password-complexity-rules/contains-lowercase.d.ts +7 -0
- package/dist/password-complexity-rules/contains-lowercase.d.ts.map +1 -0
- package/dist/password-complexity-rules/contains-lowercase.js +29 -0
- package/dist/password-complexity-rules/contains-lowercase.js.map +1 -0
- package/dist/password-complexity-rules/contains-lowercase.spec.d.ts +2 -0
- package/dist/password-complexity-rules/contains-lowercase.spec.d.ts.map +1 -0
- package/dist/password-complexity-rules/contains-lowercase.spec.js +28 -0
- package/dist/password-complexity-rules/contains-lowercase.spec.js.map +1 -0
- package/dist/password-complexity-rules/contains-uppercase.d.ts +7 -0
- package/dist/password-complexity-rules/contains-uppercase.d.ts.map +1 -0
- package/dist/password-complexity-rules/contains-uppercase.js +27 -0
- package/dist/password-complexity-rules/contains-uppercase.js.map +1 -0
- package/dist/password-complexity-rules/contains-uppercase.spec.d.ts +2 -0
- package/dist/password-complexity-rules/contains-uppercase.spec.d.ts.map +1 -0
- package/dist/password-complexity-rules/contains-uppercase.spec.js +28 -0
- package/dist/password-complexity-rules/contains-uppercase.spec.js.map +1 -0
- package/dist/password-complexity-rules/index.d.ts +5 -0
- package/dist/password-complexity-rules/index.d.ts.map +1 -0
- package/dist/password-complexity-rules/index.js +8 -0
- package/dist/password-complexity-rules/index.js.map +1 -0
- package/dist/password-complexity-rules/max-length.d.ts +7 -0
- package/dist/password-complexity-rules/max-length.d.ts.map +1 -0
- package/dist/password-complexity-rules/max-length.js +19 -0
- package/dist/password-complexity-rules/max-length.js.map +1 -0
- package/dist/password-complexity-rules/max-length.spec.d.ts +2 -0
- package/dist/password-complexity-rules/max-length.spec.d.ts.map +1 -0
- package/dist/password-complexity-rules/max-length.spec.js +17 -0
- package/dist/password-complexity-rules/max-length.spec.js.map +1 -0
- package/dist/password-complexity-rules/min-length.d.ts +7 -0
- package/dist/password-complexity-rules/min-length.d.ts.map +1 -0
- package/dist/password-complexity-rules/min-length.js +19 -0
- package/dist/password-complexity-rules/min-length.js.map +1 -0
- package/dist/password-complexity-rules/min-length.spec.d.ts +2 -0
- package/dist/password-complexity-rules/min-length.spec.d.ts.map +1 -0
- package/dist/password-complexity-rules/min-length.spec.js +17 -0
- package/dist/password-complexity-rules/min-length.spec.js.map +1 -0
- package/dist/password-hasher.d.ts +6 -0
- package/dist/password-hasher.d.ts.map +1 -0
- package/dist/password-hasher.js +18 -0
- package/dist/password-hasher.js.map +1 -0
- package/dist/security-policy-manager.d.ts +26 -0
- package/dist/security-policy-manager.d.ts.map +1 -0
- package/dist/security-policy-manager.js +55 -0
- package/dist/security-policy-manager.js.map +1 -0
- package/dist/security-policy-manager.spec.d.ts +2 -0
- package/dist/security-policy-manager.spec.d.ts.map +1 -0
- package/dist/security-policy-manager.spec.js +19 -0
- package/dist/security-policy-manager.spec.js.map +1 -0
- package/dist/security-policy.d.ts +26 -0
- package/dist/security-policy.d.ts.map +1 -0
- package/dist/security-policy.js +35 -0
- package/dist/security-policy.js.map +1 -0
- package/package.json +45 -0
- package/src/crypto-password-hasher.ts +44 -0
- package/src/errors/index.ts +3 -0
- package/src/errors/password-complexity-error.ts +9 -0
- package/src/errors/unauthenticated-error.ts +4 -0
- package/src/index.ts +9 -0
- package/src/injector-extensions.ts +21 -0
- package/src/models/index.ts +5 -0
- package/src/models/password-check-result.ts +11 -0
- package/src/models/password-complexity-result.ts +11 -0
- package/src/models/password-complexity-rule.ts +6 -0
- package/src/models/password-credential.ts +23 -0
- package/src/models/password-reset-token.ts +14 -0
- package/src/password-authenticator.spec.ts +393 -0
- package/src/password-authenticator.ts +101 -0
- package/src/password-complexity-rules/contains-lowercase.spec.ts +34 -0
- package/src/password-complexity-rules/contains-lowercase.ts +27 -0
- package/src/password-complexity-rules/contains-uppercase.spec.ts +34 -0
- package/src/password-complexity-rules/contains-uppercase.ts +24 -0
- package/src/password-complexity-rules/index.ts +4 -0
- package/src/password-complexity-rules/max-length.spec.ts +17 -0
- package/src/password-complexity-rules/max-length.ts +16 -0
- package/src/password-complexity-rules/min-length.spec.ts +19 -0
- package/src/password-complexity-rules/min-length.ts +16 -0
- package/src/password-hasher.ts +13 -0
- package/src/security-policy-manager.spec.ts +16 -0
- package/src/security-policy-manager.ts +53 -0
- package/src/security-policy.ts +32 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password-complexity-result.js","sourceRoot":"","sources":["../../src/models/password-complexity-result.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { PasswordComplexityResult } from './password-complexity-result';
|
|
2
|
+
export interface PasswordComplexityRule {
|
|
3
|
+
name: string;
|
|
4
|
+
check: (passwordString: string) => Promise<PasswordComplexityResult>;
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=password-complexity-rule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password-complexity-rule.d.ts","sourceRoot":"","sources":["../../src/models/password-complexity-rule.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAA;AAE5E,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,OAAO,CAAC,wBAAwB,CAAC,CAAA;CACrE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password-complexity-rule.js","sourceRoot":"","sources":["../../src/models/password-complexity-rule.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entry that stores credential info for password login
|
|
3
|
+
*/
|
|
4
|
+
export declare class PasswordCredential {
|
|
5
|
+
/**
|
|
6
|
+
* The unique name of the user
|
|
7
|
+
*/
|
|
8
|
+
userName: string;
|
|
9
|
+
/**
|
|
10
|
+
* The hashed password value
|
|
11
|
+
*/
|
|
12
|
+
passwordHash: string;
|
|
13
|
+
/**
|
|
14
|
+
* Salt value for password hashing // TODO
|
|
15
|
+
*/
|
|
16
|
+
salt: string;
|
|
17
|
+
/**
|
|
18
|
+
* The Creation date in ISO String format
|
|
19
|
+
*/
|
|
20
|
+
creationDate: string;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=password-credential.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password-credential.d.ts","sourceRoot":"","sources":["../../src/models/password-credential.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,kBAAkB;IAC7B;;OAEG;IACH,QAAQ,EAAG,MAAM,CAAA;IACjB;;OAEG;IACH,YAAY,EAAG,MAAM,CAAA;IAErB;;OAEG;IACH,IAAI,EAAG,MAAM,CAAA;IAEb;;OAEG;IACH,YAAY,EAAG,MAAM,CAAA;CACtB"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PasswordCredential = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Entry that stores credential info for password login
|
|
6
|
+
*/
|
|
7
|
+
class PasswordCredential {
|
|
8
|
+
}
|
|
9
|
+
exports.PasswordCredential = PasswordCredential;
|
|
10
|
+
//# sourceMappingURL=password-credential.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password-credential.js","sourceRoot":"","sources":["../../src/models/password-credential.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACH,MAAa,kBAAkB;CAmB9B;AAnBD,gDAmBC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare class PasswordResetToken {
|
|
2
|
+
/**
|
|
3
|
+
* The related user name
|
|
4
|
+
*/
|
|
5
|
+
userName: string;
|
|
6
|
+
/**
|
|
7
|
+
* The Token value - should be some kind of generated UUID that can be included e.g. in URLs
|
|
8
|
+
*/
|
|
9
|
+
token: string;
|
|
10
|
+
/**
|
|
11
|
+
* The creation date in an ISO datetime format
|
|
12
|
+
*/
|
|
13
|
+
createdAt: string;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=password-reset-token.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password-reset-token.d.ts","sourceRoot":"","sources":["../../src/models/password-reset-token.ts"],"names":[],"mappings":"AAAA,qBAAa,kBAAkB;IAC7B;;OAEG;IACH,QAAQ,EAAG,MAAM,CAAA;IACjB;;OAEG;IACH,KAAK,EAAG,MAAM,CAAA;IACd;;OAEG;IACH,SAAS,EAAG,MAAM,CAAA;CACnB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password-reset-token.js","sourceRoot":"","sources":["../../src/models/password-reset-token.ts"],"names":[],"mappings":";;;AAAA,MAAa,kBAAkB;CAa9B;AAbD,gDAaC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Injector } from '@furystack/inject';
|
|
2
|
+
import { SecurityPolicyManager } from './security-policy-manager';
|
|
3
|
+
import { PasswordCheckResult } from './models';
|
|
4
|
+
export declare class PasswordAuthenticator {
|
|
5
|
+
private readonly injector;
|
|
6
|
+
policyManager: SecurityPolicyManager;
|
|
7
|
+
private readonly getPasswordStore;
|
|
8
|
+
private readonly getTokenStore;
|
|
9
|
+
readonly getHasher: () => import("./password-hasher").PasswordHasher;
|
|
10
|
+
/**
|
|
11
|
+
* @param userName The User's unique name
|
|
12
|
+
* @param plainPassword The plain password to check
|
|
13
|
+
* @returns An object that contains an { isValid } value that indicates if the password is valid
|
|
14
|
+
*/
|
|
15
|
+
checkPasswordForUser(userName: string, plainPassword: string): Promise<PasswordCheckResult>;
|
|
16
|
+
/**
|
|
17
|
+
*
|
|
18
|
+
* Sets the password for the specific user
|
|
19
|
+
*
|
|
20
|
+
* @param userName The user to set the password for
|
|
21
|
+
* @param lastPassword The last user password
|
|
22
|
+
* @param plainPassword The password as a plain string
|
|
23
|
+
*/
|
|
24
|
+
setPasswordForUser(userName: string, lastPassword: string, plainPassword: string): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Resets the password with a Password Reset token entry
|
|
27
|
+
*
|
|
28
|
+
* @param resetToken The Reset Token value
|
|
29
|
+
* @param plainPassword The new password in plain string
|
|
30
|
+
*/
|
|
31
|
+
resetPasswordForUser(resetToken: string, plainPassword: string): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* @param injector The Injector instance
|
|
34
|
+
* @param policyManager The Password Policy Manager instance
|
|
35
|
+
*/
|
|
36
|
+
constructor(injector: Injector, policyManager: SecurityPolicyManager);
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=password-authenticator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password-authenticator.d.ts","sourceRoot":"","sources":["../src/password-authenticator.ts"],"names":[],"mappings":"AACA,OAAO,EAAc,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAA;AAEjE,OAAO,EAAE,mBAAmB,EAA0C,MAAM,UAAU,CAAA;AAGtF,qBACa,qBAAqB;IA2FpB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAAmB,aAAa,EAAE,qBAAqB;IA1F5F,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CACoD;IAErF,OAAO,CAAC,QAAQ,CAAC,aAAa,CACoD;IAElF,SAAgB,SAAS,mDAAoE;IAE7F;;;;OAIG;IACU,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAkBxG;;;;;;;OAOG;IACU,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB7G;;;;;OAKG;IACU,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAwB3F;;;OAGG;gBAC0B,QAAQ,EAAE,QAAQ,EAAS,aAAa,EAAE,qBAAqB;CAC7F"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PasswordAuthenticator = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const core_1 = require("@furystack/core");
|
|
6
|
+
const inject_1 = require("@furystack/inject");
|
|
7
|
+
const security_policy_manager_1 = require("./security-policy-manager");
|
|
8
|
+
const errors_1 = require("./errors");
|
|
9
|
+
const models_1 = require("./models");
|
|
10
|
+
const password_complexity_error_1 = require("./errors/password-complexity-error");
|
|
11
|
+
let PasswordAuthenticator = class PasswordAuthenticator {
|
|
12
|
+
/**
|
|
13
|
+
* @param injector The Injector instance
|
|
14
|
+
* @param policyManager The Password Policy Manager instance
|
|
15
|
+
*/
|
|
16
|
+
constructor(injector, policyManager) {
|
|
17
|
+
this.injector = injector;
|
|
18
|
+
this.policyManager = policyManager;
|
|
19
|
+
this.getPasswordStore = () => this.injector.getInstance(core_1.StoreManager).getStoreFor(models_1.PasswordCredential, 'userName');
|
|
20
|
+
this.getTokenStore = () => this.injector.getInstance(core_1.StoreManager).getStoreFor(models_1.PasswordResetToken, 'token');
|
|
21
|
+
this.getHasher = () => this.injector.getInstance(this.policyManager.policy.hasher);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* @param userName The User's unique name
|
|
25
|
+
* @param plainPassword The plain password to check
|
|
26
|
+
* @returns An object that contains an { isValid } value that indicates if the password is valid
|
|
27
|
+
*/
|
|
28
|
+
async checkPasswordForUser(userName, plainPassword) {
|
|
29
|
+
const entry = await this.getPasswordStore().get(userName);
|
|
30
|
+
if (!entry) {
|
|
31
|
+
return {
|
|
32
|
+
isValid: false,
|
|
33
|
+
reason: 'badUsernameOrPassword',
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const result = await this.getHasher().verifyCredential(plainPassword, entry);
|
|
37
|
+
if (result.isValid && this.policyManager.hasPasswordExpired(entry)) {
|
|
38
|
+
return {
|
|
39
|
+
isValid: false,
|
|
40
|
+
reason: 'passwordExpired',
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
*
|
|
47
|
+
* Sets the password for the specific user
|
|
48
|
+
*
|
|
49
|
+
* @param userName The user to set the password for
|
|
50
|
+
* @param lastPassword The last user password
|
|
51
|
+
* @param plainPassword The password as a plain string
|
|
52
|
+
*/
|
|
53
|
+
async setPasswordForUser(userName, lastPassword, plainPassword) {
|
|
54
|
+
const complexityResult = await this.policyManager.matchPasswordComplexityRules(plainPassword);
|
|
55
|
+
if (!complexityResult.match) {
|
|
56
|
+
throw new password_complexity_error_1.PasswordComplexityError(complexityResult.errors);
|
|
57
|
+
}
|
|
58
|
+
const lastResult = await this.checkPasswordForUser(userName, lastPassword);
|
|
59
|
+
if (!lastResult.isValid) {
|
|
60
|
+
throw new errors_1.UnauthenticatedError();
|
|
61
|
+
}
|
|
62
|
+
const store = this.getPasswordStore();
|
|
63
|
+
const newCredential = await this.getHasher().createCredential(userName, plainPassword);
|
|
64
|
+
const existing = await store.get(userName);
|
|
65
|
+
existing && (await store.remove(existing.userName));
|
|
66
|
+
await store.add(newCredential);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Resets the password with a Password Reset token entry
|
|
70
|
+
*
|
|
71
|
+
* @param resetToken The Reset Token value
|
|
72
|
+
* @param plainPassword The new password in plain string
|
|
73
|
+
*/
|
|
74
|
+
async resetPasswordForUser(resetToken, plainPassword) {
|
|
75
|
+
const token = await this.getTokenStore().get(resetToken);
|
|
76
|
+
if (!token) {
|
|
77
|
+
throw new errors_1.UnauthenticatedError();
|
|
78
|
+
}
|
|
79
|
+
if (this.policyManager.hasTokenExpired(token)) {
|
|
80
|
+
await this.getTokenStore().remove(resetToken); // clean up token
|
|
81
|
+
throw new errors_1.UnauthenticatedError();
|
|
82
|
+
}
|
|
83
|
+
const complexityResult = await this.policyManager.matchPasswordComplexityRules(plainPassword);
|
|
84
|
+
if (!complexityResult.match) {
|
|
85
|
+
throw new password_complexity_error_1.PasswordComplexityError(complexityResult.errors);
|
|
86
|
+
}
|
|
87
|
+
const newCredential = await this.getHasher().createCredential(token.userName, plainPassword);
|
|
88
|
+
const store = this.getPasswordStore();
|
|
89
|
+
const existing = await store.get(token.userName);
|
|
90
|
+
existing && (await store.remove(existing.userName));
|
|
91
|
+
await store.add(newCredential);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
PasswordAuthenticator = tslib_1.__decorate([
|
|
95
|
+
(0, inject_1.Injectable)({ lifetime: 'singleton' }),
|
|
96
|
+
tslib_1.__metadata("design:paramtypes", [inject_1.Injector, security_policy_manager_1.SecurityPolicyManager])
|
|
97
|
+
], PasswordAuthenticator);
|
|
98
|
+
exports.PasswordAuthenticator = PasswordAuthenticator;
|
|
99
|
+
//# sourceMappingURL=password-authenticator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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":"AAGA,OAAO,uBAAuB,CAAA"}
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@furystack/core");
|
|
4
|
+
const inject_1 = require("@furystack/inject");
|
|
5
|
+
const utils_1 = require("@furystack/utils");
|
|
6
|
+
require("./injector-extensions");
|
|
7
|
+
const uuid_1 = require("uuid");
|
|
8
|
+
const models_1 = require("./models");
|
|
9
|
+
const password_authenticator_1 = require("./password-authenticator");
|
|
10
|
+
const password_complexity_rules_1 = require("./password-complexity-rules");
|
|
11
|
+
const security_policy_manager_1 = require("./security-policy-manager");
|
|
12
|
+
const errors_1 = require("./errors");
|
|
13
|
+
describe('PasswordAuthenticator', () => {
|
|
14
|
+
it('Should be instantiated', () => {
|
|
15
|
+
(0, utils_1.using)(new inject_1.Injector(), (i) => {
|
|
16
|
+
const auth = i.getInstance(password_authenticator_1.PasswordAuthenticator);
|
|
17
|
+
expect(auth).toBeInstanceOf(password_authenticator_1.PasswordAuthenticator);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
it('Should inherit policy from the extension method', () => {
|
|
21
|
+
(0, utils_1.using)(new inject_1.Injector(), (i) => {
|
|
22
|
+
i.usePasswordPolicy({
|
|
23
|
+
passwordComplexityRules: [(0, password_complexity_rules_1.createMinLengthComplexityRule)(3)],
|
|
24
|
+
});
|
|
25
|
+
const auth = i.getInstance(password_authenticator_1.PasswordAuthenticator);
|
|
26
|
+
expect(auth).toBeInstanceOf(password_authenticator_1.PasswordAuthenticator);
|
|
27
|
+
expect(auth.policyManager.policy.passwordComplexityRules[0].name).toBe('minLength');
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
describe('checkPasswordForUser', () => {
|
|
31
|
+
it('Should return a truthy value for valid username and password', async () => {
|
|
32
|
+
await (0, utils_1.usingAsync)(new inject_1.Injector(), async (i) => {
|
|
33
|
+
const userName = (0, uuid_1.v4)();
|
|
34
|
+
const password = (0, uuid_1.v4)();
|
|
35
|
+
i.setupStores((sm) => sm
|
|
36
|
+
.addStore(new core_1.InMemoryStore({ model: models_1.PasswordCredential, primaryKey: 'userName' }))
|
|
37
|
+
.addStore(new core_1.InMemoryStore({ model: core_1.User, primaryKey: 'username' })));
|
|
38
|
+
i.usePasswordPolicy({});
|
|
39
|
+
const authenticator = i.getInstance(password_authenticator_1.PasswordAuthenticator);
|
|
40
|
+
const hasher = authenticator.getHasher();
|
|
41
|
+
const passwordStore = i.getInstance(core_1.StoreManager).getStoreFor(models_1.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 (0, utils_1.usingAsync)(new inject_1.Injector(), async (i) => {
|
|
50
|
+
const userName = (0, uuid_1.v4)();
|
|
51
|
+
const password = (0, uuid_1.v4)();
|
|
52
|
+
i.setupStores((sm) => sm
|
|
53
|
+
.addStore(new core_1.InMemoryStore({ model: models_1.PasswordCredential, primaryKey: 'userName' }))
|
|
54
|
+
.addStore(new core_1.InMemoryStore({ model: core_1.User, primaryKey: 'username' })));
|
|
55
|
+
i.usePasswordPolicy({});
|
|
56
|
+
const authenticator = i.getInstance(password_authenticator_1.PasswordAuthenticator);
|
|
57
|
+
const hasher = authenticator.getHasher();
|
|
58
|
+
const passwordStore = i.getInstance(core_1.StoreManager).getStoreFor(models_1.PasswordCredential, 'userName');
|
|
59
|
+
const entry = await hasher.createCredential(userName, password);
|
|
60
|
+
await passwordStore.add(entry);
|
|
61
|
+
const failResult = await authenticator.checkPasswordForUser('invalidUsername', password);
|
|
62
|
+
expect(failResult.isValid).toBeFalsy();
|
|
63
|
+
expect(failResult.reason).toBe('badUsernameOrPassword');
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
it('Should return a falsy value for invalid password', async () => {
|
|
67
|
+
await (0, utils_1.usingAsync)(new inject_1.Injector(), async (i) => {
|
|
68
|
+
const userName = (0, uuid_1.v4)();
|
|
69
|
+
const password = (0, uuid_1.v4)();
|
|
70
|
+
i.setupStores((sm) => sm
|
|
71
|
+
.addStore(new core_1.InMemoryStore({ model: models_1.PasswordCredential, primaryKey: 'userName' }))
|
|
72
|
+
.addStore(new core_1.InMemoryStore({ model: core_1.User, primaryKey: 'username' })));
|
|
73
|
+
i.usePasswordPolicy({});
|
|
74
|
+
const authenticator = i.getInstance(password_authenticator_1.PasswordAuthenticator);
|
|
75
|
+
const hasher = authenticator.getHasher();
|
|
76
|
+
const passwordStore = i.getInstance(core_1.StoreManager).getStoreFor(models_1.PasswordCredential, 'userName');
|
|
77
|
+
const entry = await hasher.createCredential(userName, password);
|
|
78
|
+
await passwordStore.add(entry);
|
|
79
|
+
const failResult = await authenticator.checkPasswordForUser(userName, 'someInvalidPassword');
|
|
80
|
+
expect(failResult.isValid).toBeFalsy();
|
|
81
|
+
expect(failResult.reason).toBe('badUsernameOrPassword');
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
it('Should return a falsy value for an expired password', async () => {
|
|
85
|
+
await (0, utils_1.usingAsync)(new inject_1.Injector(), async (i) => {
|
|
86
|
+
const userName = (0, uuid_1.v4)();
|
|
87
|
+
const password = (0, uuid_1.v4)();
|
|
88
|
+
i.setupStores((sm) => sm
|
|
89
|
+
.addStore(new core_1.InMemoryStore({ model: models_1.PasswordCredential, primaryKey: 'userName' }))
|
|
90
|
+
.addStore(new core_1.InMemoryStore({ model: core_1.User, primaryKey: 'username' })));
|
|
91
|
+
i.usePasswordPolicy({ passwordExpirationDays: 1 });
|
|
92
|
+
const authenticator = i.getInstance(password_authenticator_1.PasswordAuthenticator);
|
|
93
|
+
const hasher = authenticator.getHasher();
|
|
94
|
+
const passwordStore = i.getInstance(core_1.StoreManager).getStoreFor(models_1.PasswordCredential, 'userName');
|
|
95
|
+
const entry = await hasher.createCredential(userName, password);
|
|
96
|
+
const creationDate = new Date();
|
|
97
|
+
creationDate.setDate(creationDate.getDate() - 2);
|
|
98
|
+
entry.creationDate = creationDate.toISOString();
|
|
99
|
+
await passwordStore.add(entry);
|
|
100
|
+
const failResult = await authenticator.checkPasswordForUser(userName, password);
|
|
101
|
+
expect(failResult.isValid).toBeFalsy();
|
|
102
|
+
expect(failResult.reason).toBe('passwordExpired');
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
describe('setPasswordForUser', () => {
|
|
107
|
+
it('Should be able to set the password for the user using the last password', async () => {
|
|
108
|
+
await (0, utils_1.usingAsync)(new inject_1.Injector(), async (i) => {
|
|
109
|
+
const userName = (0, uuid_1.v4)();
|
|
110
|
+
const lastPassword = (0, uuid_1.v4)();
|
|
111
|
+
const password = (0, uuid_1.v4)();
|
|
112
|
+
i.setupStores((sm) => sm
|
|
113
|
+
.addStore(new core_1.InMemoryStore({ model: models_1.PasswordCredential, primaryKey: 'userName' }))
|
|
114
|
+
.addStore(new core_1.InMemoryStore({ model: core_1.User, primaryKey: 'username' })));
|
|
115
|
+
i.usePasswordPolicy({});
|
|
116
|
+
const authenticator = i.getInstance(password_authenticator_1.PasswordAuthenticator);
|
|
117
|
+
const hasher = authenticator.getHasher();
|
|
118
|
+
const passwordStore = i.getInstance(core_1.StoreManager).getStoreFor(models_1.PasswordCredential, 'userName');
|
|
119
|
+
const policyManager = i.getInstance(security_policy_manager_1.SecurityPolicyManager);
|
|
120
|
+
const pmSpy = jest.spyOn(policyManager, 'matchPasswordComplexityRules');
|
|
121
|
+
const entry = await hasher.createCredential(userName, lastPassword);
|
|
122
|
+
await passwordStore.add(entry);
|
|
123
|
+
await authenticator.setPasswordForUser(userName, lastPassword, password);
|
|
124
|
+
expect(pmSpy).toBeCalled();
|
|
125
|
+
const entryCount = await passwordStore.count({ userName: { $eq: userName } });
|
|
126
|
+
expect(entryCount).toBe(1); // old entry should be removed
|
|
127
|
+
const successResult = await authenticator.checkPasswordForUser(userName, password);
|
|
128
|
+
expect(successResult.isValid).toBeTruthy();
|
|
129
|
+
// Password updated, cannot use the last password
|
|
130
|
+
const failResult = await authenticator.checkPasswordForUser(userName, lastPassword);
|
|
131
|
+
expect(failResult.isValid).toBeFalsy();
|
|
132
|
+
expect(failResult.reason).toBe('badUsernameOrPassword');
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
it('Should throw PasswordComplexityError if the complexity rules are not respected', async () => {
|
|
136
|
+
await (0, utils_1.usingAsync)(new inject_1.Injector(), async (i) => {
|
|
137
|
+
const userName = (0, uuid_1.v4)();
|
|
138
|
+
const lastPassword = (0, uuid_1.v4)();
|
|
139
|
+
const password = '';
|
|
140
|
+
i.setupStores((sm) => sm
|
|
141
|
+
.addStore(new core_1.InMemoryStore({ model: models_1.PasswordCredential, primaryKey: 'userName' }))
|
|
142
|
+
.addStore(new core_1.InMemoryStore({ model: core_1.User, primaryKey: 'username' })));
|
|
143
|
+
i.usePasswordPolicy({ passwordComplexityRules: [(0, password_complexity_rules_1.createMinLengthComplexityRule)(3)] });
|
|
144
|
+
const authenticator = i.getInstance(password_authenticator_1.PasswordAuthenticator);
|
|
145
|
+
const hasher = authenticator.getHasher();
|
|
146
|
+
const passwordStore = i.getInstance(core_1.StoreManager).getStoreFor(models_1.PasswordCredential, 'userName');
|
|
147
|
+
const policyManager = i.getInstance(security_policy_manager_1.SecurityPolicyManager);
|
|
148
|
+
const pmSpy = jest.spyOn(policyManager, 'matchPasswordComplexityRules');
|
|
149
|
+
const entry = await hasher.createCredential(userName, lastPassword);
|
|
150
|
+
await passwordStore.add(entry);
|
|
151
|
+
await expect(authenticator.setPasswordForUser(userName, lastPassword, password)).rejects.toThrowError(errors_1.PasswordComplexityError);
|
|
152
|
+
expect(pmSpy).toBeCalled();
|
|
153
|
+
const entryCount = await passwordStore.count({ userName: { $eq: userName } });
|
|
154
|
+
expect(entryCount).toBe(1); // old entry should be removed
|
|
155
|
+
const failResult = await authenticator.checkPasswordForUser(userName, password);
|
|
156
|
+
// Password NOT updated, can use the last password
|
|
157
|
+
expect(failResult.isValid).toBeFalsy();
|
|
158
|
+
expect(failResult.reason).toBe('badUsernameOrPassword');
|
|
159
|
+
// Password NOT updated, cannot use the new password
|
|
160
|
+
const successResult = await authenticator.checkPasswordForUser(userName, lastPassword);
|
|
161
|
+
expect(successResult.isValid).toBeTruthy();
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
it('Should throw UnauthenticatedError if the last password is not valid', async () => {
|
|
165
|
+
await (0, utils_1.usingAsync)(new inject_1.Injector(), async (i) => {
|
|
166
|
+
const userName = (0, uuid_1.v4)();
|
|
167
|
+
const lastPassword = (0, uuid_1.v4)();
|
|
168
|
+
const password = (0, uuid_1.v4)();
|
|
169
|
+
i.setupStores((sm) => sm
|
|
170
|
+
.addStore(new core_1.InMemoryStore({ model: models_1.PasswordCredential, primaryKey: 'userName' }))
|
|
171
|
+
.addStore(new core_1.InMemoryStore({ model: core_1.User, primaryKey: 'username' })));
|
|
172
|
+
i.usePasswordPolicy();
|
|
173
|
+
const authenticator = i.getInstance(password_authenticator_1.PasswordAuthenticator);
|
|
174
|
+
const hasher = authenticator.getHasher();
|
|
175
|
+
const passwordStore = i.getInstance(core_1.StoreManager).getStoreFor(models_1.PasswordCredential, 'userName');
|
|
176
|
+
const policyManager = i.getInstance(security_policy_manager_1.SecurityPolicyManager);
|
|
177
|
+
const pmSpy = jest.spyOn(policyManager, 'matchPasswordComplexityRules');
|
|
178
|
+
const entry = await hasher.createCredential(userName, lastPassword);
|
|
179
|
+
await passwordStore.add(entry);
|
|
180
|
+
await expect(authenticator.setPasswordForUser(userName, 'someBadLastPassword', password)).rejects.toThrowError(errors_1.UnauthenticatedError);
|
|
181
|
+
expect(pmSpy).toBeCalled();
|
|
182
|
+
const entryCount = await passwordStore.count({ userName: { $eq: userName } });
|
|
183
|
+
expect(entryCount).toBe(1); // old entry should be removed
|
|
184
|
+
const failResult = await authenticator.checkPasswordForUser(userName, password);
|
|
185
|
+
// Password NOT updated, can use the last password
|
|
186
|
+
expect(failResult.isValid).toBeFalsy();
|
|
187
|
+
expect(failResult.reason).toBe('badUsernameOrPassword');
|
|
188
|
+
// Password NOT updated, cannot use the new password
|
|
189
|
+
const successResult = await authenticator.checkPasswordForUser(userName, lastPassword);
|
|
190
|
+
expect(successResult.isValid).toBeTruthy();
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
describe('resetPasswordForUser', () => {
|
|
195
|
+
it('Should reset the password with the valid token', async () => {
|
|
196
|
+
await (0, utils_1.usingAsync)(new inject_1.Injector(), async (i) => {
|
|
197
|
+
const userName = (0, uuid_1.v4)();
|
|
198
|
+
const lastPassword = (0, uuid_1.v4)();
|
|
199
|
+
const password = (0, uuid_1.v4)();
|
|
200
|
+
const token = (0, uuid_1.v4)();
|
|
201
|
+
i.setupStores((sm) => sm
|
|
202
|
+
.addStore(new core_1.InMemoryStore({ model: models_1.PasswordCredential, primaryKey: 'userName' }))
|
|
203
|
+
.addStore(new core_1.InMemoryStore({ model: core_1.User, primaryKey: 'username' }))
|
|
204
|
+
.addStore(new core_1.InMemoryStore({ model: models_1.PasswordResetToken, primaryKey: 'token' })));
|
|
205
|
+
i.usePasswordPolicy();
|
|
206
|
+
const authenticator = i.getInstance(password_authenticator_1.PasswordAuthenticator);
|
|
207
|
+
const hasher = authenticator.getHasher();
|
|
208
|
+
const passwordStore = i.getInstance(core_1.StoreManager).getStoreFor(models_1.PasswordCredential, 'userName');
|
|
209
|
+
const resetTokenStore = i.getInstance(core_1.StoreManager).getStoreFor(models_1.PasswordResetToken, 'token');
|
|
210
|
+
const entry = await hasher.createCredential(userName, lastPassword);
|
|
211
|
+
await passwordStore.add(entry);
|
|
212
|
+
await resetTokenStore.add({ userName, createdAt: new Date().toISOString(), token });
|
|
213
|
+
await authenticator.resetPasswordForUser(token, password);
|
|
214
|
+
const successResult = await authenticator.checkPasswordForUser(userName, password);
|
|
215
|
+
expect(successResult.isValid).toBeTruthy();
|
|
216
|
+
// Password updated, cannot use the last password
|
|
217
|
+
const failResult = await authenticator.checkPasswordForUser(userName, lastPassword);
|
|
218
|
+
expect(failResult.isValid).toBeFalsy();
|
|
219
|
+
expect(failResult.reason).toBe('badUsernameOrPassword');
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
it('Should throw PasswordComplexityError if the complexity rules are not respected', async () => {
|
|
223
|
+
await (0, utils_1.usingAsync)(new inject_1.Injector(), async (i) => {
|
|
224
|
+
const userName = (0, uuid_1.v4)();
|
|
225
|
+
const lastPassword = (0, uuid_1.v4)();
|
|
226
|
+
const password = '';
|
|
227
|
+
const token = (0, uuid_1.v4)();
|
|
228
|
+
i.setupStores((sm) => sm
|
|
229
|
+
.addStore(new core_1.InMemoryStore({ model: models_1.PasswordCredential, primaryKey: 'userName' }))
|
|
230
|
+
.addStore(new core_1.InMemoryStore({ model: core_1.User, primaryKey: 'username' }))
|
|
231
|
+
.addStore(new core_1.InMemoryStore({ model: models_1.PasswordResetToken, primaryKey: 'token' })));
|
|
232
|
+
i.usePasswordPolicy({ passwordComplexityRules: [(0, password_complexity_rules_1.createMinLengthComplexityRule)(3)] });
|
|
233
|
+
const authenticator = i.getInstance(password_authenticator_1.PasswordAuthenticator);
|
|
234
|
+
const hasher = authenticator.getHasher();
|
|
235
|
+
const passwordStore = i.getInstance(core_1.StoreManager).getStoreFor(models_1.PasswordCredential, 'userName');
|
|
236
|
+
const resetTokenStore = i.getInstance(core_1.StoreManager).getStoreFor(models_1.PasswordResetToken, 'token');
|
|
237
|
+
const entry = await hasher.createCredential(userName, lastPassword);
|
|
238
|
+
await passwordStore.add(entry);
|
|
239
|
+
await resetTokenStore.add({ userName, createdAt: new Date().toISOString(), token });
|
|
240
|
+
await expect(authenticator.resetPasswordForUser(token, password)).rejects.toThrowError(errors_1.PasswordComplexityError);
|
|
241
|
+
const successResult = await authenticator.checkPasswordForUser(userName, lastPassword);
|
|
242
|
+
expect(successResult.isValid).toBeTruthy();
|
|
243
|
+
// Password updated, cannot use the last password
|
|
244
|
+
const failResult = await authenticator.checkPasswordForUser(userName, password);
|
|
245
|
+
expect(failResult.isValid).toBeFalsy();
|
|
246
|
+
expect(failResult.reason).toBe('badUsernameOrPassword');
|
|
247
|
+
});
|
|
248
|
+
});
|
|
249
|
+
it('Should throw UnauthenticatedError if the token is not valid', async () => {
|
|
250
|
+
await (0, utils_1.usingAsync)(new inject_1.Injector(), async (i) => {
|
|
251
|
+
const userName = (0, uuid_1.v4)();
|
|
252
|
+
const lastPassword = (0, uuid_1.v4)();
|
|
253
|
+
const password = '';
|
|
254
|
+
const token = (0, uuid_1.v4)();
|
|
255
|
+
i.setupStores((sm) => sm
|
|
256
|
+
.addStore(new core_1.InMemoryStore({ model: models_1.PasswordCredential, primaryKey: 'userName' }))
|
|
257
|
+
.addStore(new core_1.InMemoryStore({ model: core_1.User, primaryKey: 'username' }))
|
|
258
|
+
.addStore(new core_1.InMemoryStore({ model: models_1.PasswordResetToken, primaryKey: 'token' })));
|
|
259
|
+
i.usePasswordPolicy();
|
|
260
|
+
const authenticator = i.getInstance(password_authenticator_1.PasswordAuthenticator);
|
|
261
|
+
const hasher = authenticator.getHasher();
|
|
262
|
+
const passwordStore = i.getInstance(core_1.StoreManager).getStoreFor(models_1.PasswordCredential, 'userName');
|
|
263
|
+
const resetTokenStore = i.getInstance(core_1.StoreManager).getStoreFor(models_1.PasswordResetToken, 'token');
|
|
264
|
+
const entry = await hasher.createCredential(userName, lastPassword);
|
|
265
|
+
await passwordStore.add(entry);
|
|
266
|
+
await resetTokenStore.add({ userName, createdAt: new Date().toISOString(), token });
|
|
267
|
+
await expect(authenticator.resetPasswordForUser('someBadToken', password)).rejects.toThrowError(errors_1.UnauthenticatedError);
|
|
268
|
+
const successResult = await authenticator.checkPasswordForUser(userName, lastPassword);
|
|
269
|
+
expect(successResult.isValid).toBeTruthy();
|
|
270
|
+
// Password updated, cannot use the last password
|
|
271
|
+
const failResult = await authenticator.checkPasswordForUser(userName, password);
|
|
272
|
+
expect(failResult.isValid).toBeFalsy();
|
|
273
|
+
expect(failResult.reason).toBe('badUsernameOrPassword');
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
it('Should throw UnauthenticatedError and clean up token if the token has been expired', async () => {
|
|
277
|
+
await (0, utils_1.usingAsync)(new inject_1.Injector(), async (i) => {
|
|
278
|
+
const userName = (0, uuid_1.v4)();
|
|
279
|
+
const lastPassword = (0, uuid_1.v4)();
|
|
280
|
+
const password = '';
|
|
281
|
+
const token = (0, uuid_1.v4)();
|
|
282
|
+
i.setupStores((sm) => sm
|
|
283
|
+
.addStore(new core_1.InMemoryStore({ model: models_1.PasswordCredential, primaryKey: 'userName' }))
|
|
284
|
+
.addStore(new core_1.InMemoryStore({ model: core_1.User, primaryKey: 'username' }))
|
|
285
|
+
.addStore(new core_1.InMemoryStore({ model: models_1.PasswordResetToken, primaryKey: 'token' })));
|
|
286
|
+
i.usePasswordPolicy({ resetTokenExpirationSeconds: 1 });
|
|
287
|
+
const authenticator = i.getInstance(password_authenticator_1.PasswordAuthenticator);
|
|
288
|
+
const hasher = authenticator.getHasher();
|
|
289
|
+
const passwordStore = i.getInstance(core_1.StoreManager).getStoreFor(models_1.PasswordCredential, 'userName');
|
|
290
|
+
const resetTokenStore = i.getInstance(core_1.StoreManager).getStoreFor(models_1.PasswordResetToken, 'token');
|
|
291
|
+
const entry = await hasher.createCredential(userName, lastPassword);
|
|
292
|
+
await passwordStore.add(entry);
|
|
293
|
+
const creationDate = new Date();
|
|
294
|
+
creationDate.setDate(creationDate.getDate() - 2);
|
|
295
|
+
await resetTokenStore.add({ userName, createdAt: creationDate.toISOString(), token });
|
|
296
|
+
await expect(authenticator.resetPasswordForUser(token, password)).rejects.toThrowError(errors_1.UnauthenticatedError);
|
|
297
|
+
const successResult = await authenticator.checkPasswordForUser(userName, lastPassword);
|
|
298
|
+
expect(successResult.isValid).toBeTruthy();
|
|
299
|
+
// Password updated, cannot use the last password
|
|
300
|
+
const failResult = await authenticator.checkPasswordForUser(userName, password);
|
|
301
|
+
expect(failResult.isValid).toBeFalsy();
|
|
302
|
+
expect(failResult.reason).toBe('badUsernameOrPassword');
|
|
303
|
+
const tokenCount = await resetTokenStore.count();
|
|
304
|
+
expect(tokenCount).toBe(0);
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
//# 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,7 @@
|
|
|
1
|
+
import { PasswordComplexityRule } from '../models';
|
|
2
|
+
/**
|
|
3
|
+
* @param lowerCaseCount The minimum lower case characters length
|
|
4
|
+
* @returns The created Password Policy object
|
|
5
|
+
*/
|
|
6
|
+
export declare const createContainsLowercasePolicy: (lowerCaseCount: number) => PasswordComplexityRule;
|
|
7
|
+
//# sourceMappingURL=contains-lowercase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contains-lowercase.d.ts","sourceRoot":"","sources":["../../src/password-complexity-rules/contains-lowercase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAA;AAElD;;;GAGG;AACH,eAAO,MAAM,6BAA6B,mBAAoB,MAAM,KAAG,sBAoBrE,CAAA"}
|