@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,34 @@
|
|
|
1
|
+
import { PasswordComplexityFailedResult } from '../models'
|
|
2
|
+
import { createContainsLowercasePolicy } from './contains-lowercase'
|
|
3
|
+
|
|
4
|
+
describe('Contains-lowercase', () => {
|
|
5
|
+
it('Should fail if the password is shorter than expected', async () => {
|
|
6
|
+
const policy = createContainsLowercasePolicy(3)
|
|
7
|
+
const result = await policy.check('')
|
|
8
|
+
expect(result.success).toBe(false)
|
|
9
|
+
expect((result as PasswordComplexityFailedResult).message).toBe(
|
|
10
|
+
'The password should contain at least 3 lower case characters',
|
|
11
|
+
)
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('Should fail if the password does not contain enough lowercase chars', async () => {
|
|
15
|
+
const policy = createContainsLowercasePolicy(3)
|
|
16
|
+
const result = await policy.check('ASD12345(=/!+')
|
|
17
|
+
expect(result.success).toBe(false)
|
|
18
|
+
expect((result as PasswordComplexityFailedResult).message).toBe(
|
|
19
|
+
'The password should contain at least 3 lower case characters',
|
|
20
|
+
)
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('Should succeed if the password contains enough lowercase chars', async () => {
|
|
24
|
+
const policy = createContainsLowercasePolicy(3)
|
|
25
|
+
const result = await policy.check('asd')
|
|
26
|
+
expect(result.success).toBe(true)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('Should succeed if the password contains enough lowercase chars supporting special ones', async () => {
|
|
30
|
+
const policy = createContainsLowercasePolicy(3)
|
|
31
|
+
const result = await policy.check('éáő')
|
|
32
|
+
expect(result.success).toBe(true)
|
|
33
|
+
})
|
|
34
|
+
})
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { PasswordComplexityRule } from '../models'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @param lowerCaseCount The minimum lower case characters length
|
|
5
|
+
* @returns The created Password Policy object
|
|
6
|
+
*/
|
|
7
|
+
export const createContainsLowercasePolicy = (lowerCaseCount: number): PasswordComplexityRule => ({
|
|
8
|
+
name: 'containsLowercase' as const,
|
|
9
|
+
check: async (passwordString: string) => {
|
|
10
|
+
const actualLowerCaseCount =
|
|
11
|
+
passwordString.length >= lowerCaseCount
|
|
12
|
+
? passwordString
|
|
13
|
+
.normalize('NFD')
|
|
14
|
+
.replace(/\p{Diacritic}/gu, '')
|
|
15
|
+
.replace(/[^a-z]/g, '').length
|
|
16
|
+
: 0
|
|
17
|
+
const success = actualLowerCaseCount >= lowerCaseCount
|
|
18
|
+
if (success) {
|
|
19
|
+
return { success }
|
|
20
|
+
}
|
|
21
|
+
return {
|
|
22
|
+
success,
|
|
23
|
+
message: `The password should contain at least ${lowerCaseCount} lower case characters`,
|
|
24
|
+
rule: 'containsLowercase',
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
})
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { PasswordComplexityFailedResult } from '../models'
|
|
2
|
+
import { createContainsUppercasePolicy } from './contains-uppercase'
|
|
3
|
+
|
|
4
|
+
describe('Contains-uppercase', () => {
|
|
5
|
+
it('Should fail if the password is shorter than expected', async () => {
|
|
6
|
+
const policy = createContainsUppercasePolicy(3)
|
|
7
|
+
const result = await policy.check('')
|
|
8
|
+
expect(result.success).toBe(false)
|
|
9
|
+
expect((result as PasswordComplexityFailedResult).message).toBe(
|
|
10
|
+
'The password should contain at least 3 upper case characters',
|
|
11
|
+
)
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('Should fail if the password does not contain enough lowercase chars', async () => {
|
|
15
|
+
const policy = createContainsUppercasePolicy(3)
|
|
16
|
+
const result = await policy.check('asd12345(=/!+')
|
|
17
|
+
expect(result.success).toBe(false)
|
|
18
|
+
expect((result as PasswordComplexityFailedResult).message).toBe(
|
|
19
|
+
'The password should contain at least 3 upper case characters',
|
|
20
|
+
)
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('Should succeed if the password contains enough lowercase chars', async () => {
|
|
24
|
+
const policy = createContainsUppercasePolicy(3)
|
|
25
|
+
const result = await policy.check('ASD')
|
|
26
|
+
expect(result.success).toBe(true)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('Should succeed if the password contains enough lowercase chars supporting special ones', async () => {
|
|
30
|
+
const policy = createContainsUppercasePolicy(3)
|
|
31
|
+
const result = await policy.check('ÉÁÍ')
|
|
32
|
+
expect(result.success).toBe(true)
|
|
33
|
+
})
|
|
34
|
+
})
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { PasswordComplexityRule } from '../models'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @param upperCaseCount The minimum upper case characters length
|
|
5
|
+
* @returns The created Password Policy object
|
|
6
|
+
*/
|
|
7
|
+
export const createContainsUppercasePolicy = (upperCaseCount: number): PasswordComplexityRule => ({
|
|
8
|
+
name: 'containsUppercase' as const,
|
|
9
|
+
check: async (passwordString: string) => {
|
|
10
|
+
const actualUpperCaseCount = passwordString
|
|
11
|
+
.normalize('NFD')
|
|
12
|
+
.replace(/\p{Diacritic}/gu, '')
|
|
13
|
+
.replace(/[^A-Z]/g, '').length
|
|
14
|
+
const success = actualUpperCaseCount >= upperCaseCount
|
|
15
|
+
if (success) {
|
|
16
|
+
return { success }
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
success,
|
|
20
|
+
message: `The password should contain at least ${upperCaseCount} upper case characters`,
|
|
21
|
+
rule: 'containsUppercase',
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
})
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { PasswordComplexityFailedResult } from '../models'
|
|
2
|
+
import { createMaxLengthComplexityRule } from './max-length'
|
|
3
|
+
|
|
4
|
+
describe('max-length', () => {
|
|
5
|
+
it('Should fail if the password is longer than expected', async () => {
|
|
6
|
+
const policy = createMaxLengthComplexityRule(3)
|
|
7
|
+
const result = await policy.check('asdasd123')
|
|
8
|
+
expect(result.success).toBe(false)
|
|
9
|
+
expect((result as PasswordComplexityFailedResult).message).toBe('The password has to be maximum 3 character length')
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
it('Should fail if the password does not contain enough lowercase chars', async () => {
|
|
13
|
+
const policy = createMaxLengthComplexityRule(3)
|
|
14
|
+
const result = await policy.check('asd')
|
|
15
|
+
expect(result.success).toBe(true)
|
|
16
|
+
})
|
|
17
|
+
})
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { PasswordComplexityRule } from '../models'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @param maxLength The maximum password length
|
|
5
|
+
* @returns The created Password Policy object
|
|
6
|
+
*/
|
|
7
|
+
export const createMaxLengthComplexityRule = (maxLength: number): PasswordComplexityRule => ({
|
|
8
|
+
name: 'maxLength' as const,
|
|
9
|
+
check: async (passwordString: string) => {
|
|
10
|
+
const success = passwordString.length <= maxLength
|
|
11
|
+
if (success) {
|
|
12
|
+
return { success }
|
|
13
|
+
}
|
|
14
|
+
return { success, message: `The password has to be maximum ${maxLength} character length`, rule: 'maxLength' }
|
|
15
|
+
},
|
|
16
|
+
})
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { PasswordComplexityFailedResult } from '../models'
|
|
2
|
+
import { createMinLengthComplexityRule } from './min-length'
|
|
3
|
+
|
|
4
|
+
describe('min-length', () => {
|
|
5
|
+
it('Should fail if the password is shorter than expected', async () => {
|
|
6
|
+
const policy = createMinLengthComplexityRule(3)
|
|
7
|
+
const result = await policy.check('')
|
|
8
|
+
expect(result.success).toBe(false)
|
|
9
|
+
expect((result as PasswordComplexityFailedResult).message).toBe(
|
|
10
|
+
'The password has to be at least 3 character length',
|
|
11
|
+
)
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('Should fail if the password does not contain enough lowercase chars', async () => {
|
|
15
|
+
const policy = createMinLengthComplexityRule(3)
|
|
16
|
+
const result = await policy.check('asd12345(=/!+')
|
|
17
|
+
expect(result.success).toBe(true)
|
|
18
|
+
})
|
|
19
|
+
})
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { PasswordComplexityRule } from '../models'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @param minLength The minimum password length
|
|
5
|
+
* @returns The created Password Policy object
|
|
6
|
+
*/
|
|
7
|
+
export const createMinLengthComplexityRule = (minLength: number): PasswordComplexityRule => ({
|
|
8
|
+
name: 'minLength' as const,
|
|
9
|
+
check: async (passwordString: string) => {
|
|
10
|
+
const success = passwordString.length >= minLength
|
|
11
|
+
if (success) {
|
|
12
|
+
return { success }
|
|
13
|
+
}
|
|
14
|
+
return { success, message: `The password has to be at least ${minLength} character length`, rule: 'minLength' }
|
|
15
|
+
},
|
|
16
|
+
})
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Injectable } from '@furystack/inject'
|
|
2
|
+
import { PasswordCheckResult, PasswordCredential } from './models'
|
|
3
|
+
|
|
4
|
+
@Injectable({ lifetime: 'singleton' })
|
|
5
|
+
export class PasswordHasher {
|
|
6
|
+
public createCredential(_userName: string, _password: string): Promise<PasswordCredential> {
|
|
7
|
+
throw Error('Set up hasher - TODO')
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
public verifyCredential(_password: string, _credential: PasswordCredential): Promise<PasswordCheckResult> {
|
|
11
|
+
throw Error('Set up hasher - TODO')
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Injector } from '@furystack/inject'
|
|
2
|
+
import { using } from '@furystack/utils'
|
|
3
|
+
import { v4 } from 'uuid'
|
|
4
|
+
import './injector-extensions'
|
|
5
|
+
import { SecurityPolicyManager } from './security-policy-manager'
|
|
6
|
+
describe('SecurityPolicyManager', () => {
|
|
7
|
+
it('Should return false when no token expiration has been set', () => {
|
|
8
|
+
using(new Injector(), (i) => {
|
|
9
|
+
i.usePasswordPolicy({ resetTokenExpirationSeconds: 0 })
|
|
10
|
+
const result = i
|
|
11
|
+
.getInstance(SecurityPolicyManager)
|
|
12
|
+
.hasTokenExpired({ createdAt: new Date().toISOString(), token: v4(), userName: v4() })
|
|
13
|
+
expect(result).toBeFalsy()
|
|
14
|
+
})
|
|
15
|
+
})
|
|
16
|
+
})
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Injectable } from '@furystack/inject'
|
|
2
|
+
import { PasswordCredential, PasswordResetToken } from './models'
|
|
3
|
+
import { SecurityPolicy } from './security-policy'
|
|
4
|
+
|
|
5
|
+
@Injectable({ lifetime: 'singleton' })
|
|
6
|
+
export class SecurityPolicyManager {
|
|
7
|
+
/**
|
|
8
|
+
* @param password The Plain password string
|
|
9
|
+
* @returns if the password matches the complexity rules
|
|
10
|
+
*/
|
|
11
|
+
public async matchPasswordComplexityRules(password: string) {
|
|
12
|
+
const result = await Promise.all(this.policy.passwordComplexityRules.map((rule) => rule.check(password)))
|
|
13
|
+
const failed = result.filter((r) => r.success === false)
|
|
14
|
+
if (failed.length) {
|
|
15
|
+
return {
|
|
16
|
+
match: false as const,
|
|
17
|
+
errors: failed.map((f) => f.success === false && { message: f.message, rule: f.rule }) as Array<{
|
|
18
|
+
message: string
|
|
19
|
+
rule: string
|
|
20
|
+
}>,
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
match: true as const,
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public hasPasswordExpired(credential: PasswordCredential) {
|
|
30
|
+
if (!this.policy.passwordExpirationDays) {
|
|
31
|
+
return false
|
|
32
|
+
}
|
|
33
|
+
const credentialExpiration = new Date(credential.creationDate)
|
|
34
|
+
credentialExpiration.setDate(credentialExpiration.getDate() + this.policy.passwordExpirationDays)
|
|
35
|
+
const now = new Date()
|
|
36
|
+
return now > credentialExpiration
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public hasTokenExpired(token: PasswordResetToken) {
|
|
40
|
+
if (!this.policy.resetTokenExpirationSeconds) {
|
|
41
|
+
return false
|
|
42
|
+
}
|
|
43
|
+
const tokenExpiration = new Date(token.createdAt)
|
|
44
|
+
tokenExpiration.setSeconds(tokenExpiration.getSeconds() + this.policy.resetTokenExpirationSeconds)
|
|
45
|
+
const now = new Date()
|
|
46
|
+
return now > tokenExpiration
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @param policy The related Password Policy object
|
|
51
|
+
*/
|
|
52
|
+
constructor(public readonly policy: SecurityPolicy) {}
|
|
53
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Constructable, Injectable } from '@furystack/inject'
|
|
2
|
+
import { CryptoPasswordHasher } from './crypto-password-hasher'
|
|
3
|
+
import { PasswordComplexityRule } from './models'
|
|
4
|
+
import { PasswordHasher } from './password-hasher'
|
|
5
|
+
|
|
6
|
+
@Injectable({ lifetime: 'singleton' })
|
|
7
|
+
export class SecurityPolicy {
|
|
8
|
+
/**
|
|
9
|
+
* A Hasher instance for password hash generation
|
|
10
|
+
*/
|
|
11
|
+
hasher: Constructable<PasswordHasher> = CryptoPasswordHasher
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Array of password complexity rules to apply
|
|
15
|
+
*/
|
|
16
|
+
passwordComplexityRules: PasswordComplexityRule[] = []
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The password expiration in days
|
|
20
|
+
*/
|
|
21
|
+
passwordExpirationDays = 0
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Defines if the login needs a second factor authentication
|
|
25
|
+
*/
|
|
26
|
+
requireSecondFactor: 'never' | 'always' = 'never' // TODO - Challenge based on trusted devices
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The Password Reset Token expiration in seconds
|
|
30
|
+
*/
|
|
31
|
+
resetTokenExpirationSeconds = 15
|
|
32
|
+
}
|