@furystack/security 7.0.9 → 8.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.
Files changed (54) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +9 -3
  3. package/esm/crypto-password-hasher.d.ts +10 -12
  4. package/esm/crypto-password-hasher.d.ts.map +1 -1
  5. package/esm/crypto-password-hasher.js +43 -36
  6. package/esm/crypto-password-hasher.js.map +1 -1
  7. package/esm/helpers.d.ts +20 -7
  8. package/esm/helpers.d.ts.map +1 -1
  9. package/esm/helpers.js +27 -13
  10. package/esm/helpers.js.map +1 -1
  11. package/esm/index.d.ts +3 -1
  12. package/esm/index.d.ts.map +1 -1
  13. package/esm/index.js +3 -1
  14. package/esm/index.js.map +1 -1
  15. package/esm/password-authenticator.d.ts +26 -15
  16. package/esm/password-authenticator.d.ts.map +1 -1
  17. package/esm/password-authenticator.js +73 -109
  18. package/esm/password-authenticator.js.map +1 -1
  19. package/esm/password-authenticator.spec.js +122 -212
  20. package/esm/password-authenticator.spec.js.map +1 -1
  21. package/esm/password-credential-store.d.ts +50 -0
  22. package/esm/password-credential-store.d.ts.map +1 -0
  23. package/esm/password-credential-store.js +73 -0
  24. package/esm/password-credential-store.js.map +1 -0
  25. package/esm/password-credential-store.spec.d.ts +2 -0
  26. package/esm/password-credential-store.spec.d.ts.map +1 -0
  27. package/esm/password-credential-store.spec.js +64 -0
  28. package/esm/password-credential-store.spec.js.map +1 -0
  29. package/esm/password-hasher.d.ts +21 -3
  30. package/esm/password-hasher.d.ts.map +1 -1
  31. package/esm/password-hasher.js +1 -19
  32. package/esm/password-hasher.js.map +1 -1
  33. package/esm/security-policy-manager.d.ts +46 -14
  34. package/esm/security-policy-manager.d.ts.map +1 -1
  35. package/esm/security-policy-manager.js +48 -52
  36. package/esm/security-policy-manager.js.map +1 -1
  37. package/esm/security-policy-manager.spec.js +58 -7
  38. package/esm/security-policy-manager.spec.js.map +1 -1
  39. package/esm/security-policy.d.ts +35 -9
  40. package/esm/security-policy.d.ts.map +1 -1
  41. package/esm/security-policy.js +23 -33
  42. package/esm/security-policy.js.map +1 -1
  43. package/package.json +5 -5
  44. package/src/crypto-password-hasher.ts +46 -39
  45. package/src/helpers.ts +27 -15
  46. package/src/index.ts +3 -2
  47. package/src/password-authenticator.spec.ts +134 -254
  48. package/src/password-authenticator.ts +92 -86
  49. package/src/password-credential-store.spec.ts +77 -0
  50. package/src/password-credential-store.ts +79 -0
  51. package/src/password-hasher.ts +21 -9
  52. package/src/security-policy-manager.spec.ts +63 -7
  53. package/src/security-policy-manager.ts +91 -42
  54. package/src/security-policy.ts +50 -18
@@ -1,33 +1,65 @@
1
- import type { Constructable } from '@furystack/inject'
2
- import { Injectable } from '@furystack/inject'
1
+ import { defineService, type Token } from '@furystack/inject'
3
2
  import { CryptoPasswordHasher } from './crypto-password-hasher.js'
4
3
  import type { PasswordComplexityRule } from './models/password-complexity-rule.js'
5
4
  import type { PasswordHasher } from './password-hasher.js'
6
5
 
7
- @Injectable({ lifetime: 'singleton' })
8
- export class SecurityPolicy {
6
+ /**
7
+ * Application-wide policy that governs password hashing, complexity rules,
8
+ * expiration and second-factor requirements.
9
+ *
10
+ * The default policy shipped by `@furystack/security` uses
11
+ * {@link CryptoPasswordHasher}, enforces no complexity rules, disables
12
+ * password and reset-token expiration by default and does not require
13
+ * second factor authentication. Override via {@link usePasswordPolicy}.
14
+ */
15
+ export type SecurityPolicy = {
9
16
  /**
10
- * A Hasher instance for password hash generation
17
+ * Token resolving to the {@link PasswordHasher} used for generating and
18
+ * verifying password credentials.
11
19
  */
12
- hasher: Constructable<PasswordHasher> = CryptoPasswordHasher
13
-
20
+ hasher: Token<PasswordHasher, 'singleton'>
14
21
  /**
15
- * Array of password complexity rules to apply
22
+ * Ordered list of password complexity rules applied to every new or
23
+ * changed password.
16
24
  */
17
- passwordComplexityRules: PasswordComplexityRule[] = []
18
-
25
+ passwordComplexityRules: PasswordComplexityRule[]
19
26
  /**
20
- * The password expiration in days
27
+ * Number of days after which a stored password credential is considered
28
+ * expired. `0` disables expiration entirely.
21
29
  */
22
- passwordExpirationDays = 0
23
-
30
+ passwordExpirationDays: number
24
31
  /**
25
- * Defines if the login needs a second factor authentication
32
+ * Second-factor authentication policy. `'always'` forces a second factor
33
+ * on every login; `'never'` disables it. Trusted-device-aware policies
34
+ * are not yet implemented.
26
35
  */
27
- requireSecondFactor: 'never' | 'always' = 'never' // TODO - Challenge based on trusted devices
28
-
36
+ requireSecondFactor: 'never' | 'always'
29
37
  /**
30
- * The Password Reset Token expiration in seconds
38
+ * Lifetime of a password reset token in seconds.
31
39
  */
32
- resetTokenExpirationSeconds = 15
40
+ resetTokenExpirationSeconds: number
33
41
  }
42
+
43
+ /**
44
+ * Returns a fresh copy of the default {@link SecurityPolicy}. Useful as a
45
+ * starting point for `Object.assign`-style overrides or spec fixtures.
46
+ */
47
+ export const defaultSecurityPolicy = (): SecurityPolicy => ({
48
+ hasher: CryptoPasswordHasher,
49
+ passwordComplexityRules: [],
50
+ passwordExpirationDays: 0,
51
+ requireSecondFactor: 'never',
52
+ resetTokenExpirationSeconds: 15,
53
+ })
54
+
55
+ /**
56
+ * DI token that resolves the current {@link SecurityPolicy}. Rebind this
57
+ * token via {@link usePasswordPolicy} (preferred) or directly through
58
+ * {@link Injector.bind} to customise the policy per-application or
59
+ * per-scope.
60
+ */
61
+ export const SecurityPolicy: Token<SecurityPolicy, 'singleton'> = defineService({
62
+ name: 'furystack/security/SecurityPolicy',
63
+ lifetime: 'singleton',
64
+ factory: () => defaultSecurityPolicy(),
65
+ })