@furystack/security 8.0.0 → 8.0.2

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 (38) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/esm/errors/password-complexity-error.d.ts +5 -4
  3. package/esm/errors/password-complexity-error.d.ts.map +1 -1
  4. package/esm/errors/password-complexity-error.js +5 -4
  5. package/esm/errors/password-complexity-error.js.map +1 -1
  6. package/esm/errors/unauthenticated-error.d.ts +3 -1
  7. package/esm/errors/unauthenticated-error.d.ts.map +1 -1
  8. package/esm/errors/unauthenticated-error.js +3 -1
  9. package/esm/errors/unauthenticated-error.js.map +1 -1
  10. package/esm/models/password-credential.d.ts +3 -13
  11. package/esm/models/password-credential.d.ts.map +1 -1
  12. package/esm/models/password-credential.js +3 -1
  13. package/esm/models/password-credential.js.map +1 -1
  14. package/esm/models/password-reset-token.d.ts +5 -9
  15. package/esm/models/password-reset-token.d.ts.map +1 -1
  16. package/esm/models/password-reset-token.js +5 -0
  17. package/esm/models/password-reset-token.js.map +1 -1
  18. package/esm/password-complexity-rules/contains-lowercase.d.ts +2 -2
  19. package/esm/password-complexity-rules/contains-lowercase.js +2 -2
  20. package/esm/password-complexity-rules/contains-uppercase.d.ts +2 -2
  21. package/esm/password-complexity-rules/contains-uppercase.js +2 -2
  22. package/esm/password-complexity-rules/max-length.d.ts +1 -4
  23. package/esm/password-complexity-rules/max-length.d.ts.map +1 -1
  24. package/esm/password-complexity-rules/max-length.js +1 -4
  25. package/esm/password-complexity-rules/max-length.js.map +1 -1
  26. package/esm/password-complexity-rules/min-length.d.ts +1 -4
  27. package/esm/password-complexity-rules/min-length.d.ts.map +1 -1
  28. package/esm/password-complexity-rules/min-length.js +1 -4
  29. package/esm/password-complexity-rules/min-length.js.map +1 -1
  30. package/package.json +8 -8
  31. package/src/errors/password-complexity-error.ts +7 -4
  32. package/src/errors/unauthenticated-error.ts +3 -1
  33. package/src/models/password-credential.ts +5 -15
  34. package/src/models/password-reset-token.ts +5 -9
  35. package/src/password-complexity-rules/contains-lowercase.ts +2 -2
  36. package/src/password-complexity-rules/contains-uppercase.ts +2 -2
  37. package/src/password-complexity-rules/max-length.ts +1 -4
  38. package/src/password-complexity-rules/min-length.ts +1 -4
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # Changelog
2
2
 
3
+ ## [8.0.2] - 2026-06-05
4
+
5
+ ### 👷 CI
6
+
7
+ - Raised the minimum supported Node.js to `>=24.0.0` (Node 24 LTS) in `engines`, dropping Node 22.
8
+
9
+ ### ⬆️ Dependencies
10
+
11
+ - Bumped dev `vitest` to `^4.1.8`. No source changes — dev-tooling bump only.
12
+
13
+ ## [8.0.1] - 2026-05-21
14
+
15
+ ### 📚 Documentation
16
+
17
+ - Rewrote JSDoc on the error classes (`PasswordComplexityError`, `UnauthenticatedError`), the model types (`PasswordCredential`, `PasswordResetToken`), and the bundled password-complexity rules (`containsLowercase`, `containsUppercase`, `minLength`, `maxLength`) to follow the new value-test guidance: dropped restate-the-type narration, kept intent / trade-offs / constraints.
18
+
19
+ ### ⬆️ Dependencies
20
+
21
+ - Bump dev `vitest` to `^4.1.5`.
22
+ - Bumped `@types/node` to `^25.9.1` and `vitest` to `^4.1.7`. No source changes — dev-tooling bump only.
23
+
3
24
  ## [8.0.0] - 2026-04-25
4
25
 
5
26
  ### 💥 Breaking Changes
@@ -1,12 +1,13 @@
1
+ /**
2
+ * Thrown by password-setting flows when the candidate password fails one or
3
+ * more configured {@link PasswordComplexityRule}s. `result` carries the
4
+ * per-rule failures so callers can render targeted user feedback.
5
+ */
1
6
  export declare class PasswordComplexityError extends Error {
2
7
  readonly result: Array<{
3
8
  message: string;
4
9
  rule: string;
5
10
  }>;
6
- /**
7
- * @param result A detailed error result array
8
- * @param message The Error message
9
- */
10
11
  constructor(result: Array<{
11
12
  message: string;
12
13
  rule: string;
@@ -1 +1 @@
1
- {"version":3,"file":"password-complexity-error.d.ts","sourceRoot":"","sources":["../../src/errors/password-complexity-error.ts"],"names":[],"mappings":"AAAA,qBAAa,uBAAwB,SAAQ,KAAK;aAM9B,MAAM,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IALlE;;;OAGG;gBAEe,MAAM,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,EAChE,OAAO,CAAC,EAAE,MAAM;CAInB"}
1
+ {"version":3,"file":"password-complexity-error.d.ts","sourceRoot":"","sources":["../../src/errors/password-complexity-error.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;aAE9B,MAAM,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;gBAAhD,MAAM,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,EAChE,OAAO,CAAC,EAAE,MAAM;CAInB"}
@@ -1,9 +1,10 @@
1
+ /**
2
+ * Thrown by password-setting flows when the candidate password fails one or
3
+ * more configured {@link PasswordComplexityRule}s. `result` carries the
4
+ * per-rule failures so callers can render targeted user feedback.
5
+ */
1
6
  export class PasswordComplexityError extends Error {
2
7
  result;
3
- /**
4
- * @param result A detailed error result array
5
- * @param message The Error message
6
- */
7
8
  constructor(result, message) {
8
9
  super(message);
9
10
  this.result = result;
@@ -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;IAM9B;IALlB;;;OAGG;IACH,YACkB,MAAgD,EAChE,OAAgB;QAEhB,KAAK,CAAC,OAAO,CAAC,CAAA;QAHE,WAAM,GAAN,MAAM,CAA0C;IAIlE,CAAC;CACF"}
1
+ {"version":3,"file":"password-complexity-error.js","sourceRoot":"","sources":["../../src/errors/password-complexity-error.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,OAAO,uBAAwB,SAAQ,KAAK;IAE9B;IADlB,YACkB,MAAgD,EAChE,OAAgB;QAEhB,KAAK,CAAC,OAAO,CAAC,CAAA;QAHE,WAAM,GAAN,MAAM,CAA0C;IAIlE,CAAC;CACF"}
@@ -1,5 +1,7 @@
1
1
  /**
2
- * Error that can be thrown if an authentication is required but not provided
2
+ * Thrown when credential verification fails: bad username/password, expired
3
+ * password, or expired/invalid reset token. REST handlers should map this
4
+ * to a 401 response.
3
5
  */
4
6
  export declare class UnauthenticatedError extends Error {
5
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"unauthenticated-error.d.ts","sourceRoot":"","sources":["../../src/errors/unauthenticated-error.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;CAAG"}
1
+ {"version":3,"file":"unauthenticated-error.d.ts","sourceRoot":"","sources":["../../src/errors/unauthenticated-error.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;CAAG"}
@@ -1,5 +1,7 @@
1
1
  /**
2
- * Error that can be thrown if an authentication is required but not provided
2
+ * Thrown when credential verification fails: bad username/password, expired
3
+ * password, or expired/invalid reset token. REST handlers should map this
4
+ * to a 401 response.
3
5
  */
4
6
  export class UnauthenticatedError extends Error {
5
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"unauthenticated-error.js","sourceRoot":"","sources":["../../src/errors/unauthenticated-error.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,OAAO,oBAAqB,SAAQ,KAAK;CAAG"}
1
+ {"version":3,"file":"unauthenticated-error.js","sourceRoot":"","sources":["../../src/errors/unauthenticated-error.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,OAAO,oBAAqB,SAAQ,KAAK;CAAG"}
@@ -1,22 +1,12 @@
1
1
  /**
2
- * Entry that stores credential info for password login
2
+ * Persisted password credential. `passwordHash` and `salt` are produced by
3
+ * the configured {@link PasswordHasher}; `creationDate` (ISO 8601 string)
4
+ * is the source of truth for password-expiration policies.
3
5
  */
4
6
  export declare class PasswordCredential {
5
- /**
6
- * The unique name of the user
7
- */
8
7
  userName: string;
9
- /**
10
- * The hashed password value
11
- */
12
8
  passwordHash: string;
13
- /**
14
- * Salt value for password hashing // TODO
15
- */
16
9
  salt: string;
17
- /**
18
- * The Creation date in ISO String format
19
- */
20
10
  creationDate: string;
21
11
  }
22
12
  //# sourceMappingURL=password-credential.d.ts.map
@@ -1 +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;IACK,QAAQ,EAAE,MAAM,CAAA;IACxB;;OAEG;IACK,YAAY,EAAE,MAAM,CAAA;IAE5B;;OAEG;IACK,IAAI,EAAE,MAAM,CAAA;IAEpB;;OAEG;IACK,YAAY,EAAE,MAAM,CAAA;CAC7B"}
1
+ {"version":3,"file":"password-credential.d.ts","sourceRoot":"","sources":["../../src/models/password-credential.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,qBAAa,kBAAkB;IACrB,QAAQ,EAAE,MAAM,CAAA;IAChB,YAAY,EAAE,MAAM,CAAA;IACpB,IAAI,EAAE,MAAM,CAAA;IACZ,YAAY,EAAE,MAAM,CAAA;CAC7B"}
@@ -1,5 +1,7 @@
1
1
  /**
2
- * Entry that stores credential info for password login
2
+ * Persisted password credential. `passwordHash` and `salt` are produced by
3
+ * the configured {@link PasswordHasher}; `creationDate` (ISO 8601 string)
4
+ * is the source of truth for password-expiration policies.
3
5
  */
4
6
  export class PasswordCredential {
5
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"password-credential.js","sourceRoot":"","sources":["../../src/models/password-credential.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,OAAO,kBAAkB;CAmB9B"}
1
+ {"version":3,"file":"password-credential.js","sourceRoot":"","sources":["../../src/models/password-credential.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,OAAO,kBAAkB;CAK9B"}
@@ -1,15 +1,11 @@
1
+ /**
2
+ * Single-use password reset token. `token` is the URL-safe identifier
3
+ * shared with the user (e.g. via email). `createdAt` (ISO 8601) is the
4
+ * expiration anchor honoured by `SecurityPolicyManager.hasTokenExpired`.
5
+ */
1
6
  export declare class PasswordResetToken {
2
- /**
3
- * The related user name
4
- */
5
7
  userName: string;
6
- /**
7
- * The Token value - should be some kind of generated UUID that can be included e.g. in URLs
8
- */
9
8
  token: string;
10
- /**
11
- * The creation date in an ISO datetime format
12
- */
13
9
  createdAt: string;
14
10
  }
15
11
  //# sourceMappingURL=password-reset-token.d.ts.map
@@ -1 +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;IACK,QAAQ,EAAE,MAAM,CAAA;IACxB;;OAEG;IACK,KAAK,EAAE,MAAM,CAAA;IACrB;;OAEG;IACK,SAAS,EAAE,MAAM,CAAA;CAC1B"}
1
+ {"version":3,"file":"password-reset-token.d.ts","sourceRoot":"","sources":["../../src/models/password-reset-token.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,qBAAa,kBAAkB;IACrB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;CAC1B"}
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Single-use password reset token. `token` is the URL-safe identifier
3
+ * shared with the user (e.g. via email). `createdAt` (ISO 8601) is the
4
+ * expiration anchor honoured by `SecurityPolicyManager.hasTokenExpired`.
5
+ */
1
6
  export class PasswordResetToken {
2
7
  }
3
8
  //# 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;CAa9B"}
1
+ {"version":3,"file":"password-reset-token.js","sourceRoot":"","sources":["../../src/models/password-reset-token.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,OAAO,kBAAkB;CAI9B"}
@@ -1,7 +1,7 @@
1
1
  import type { PasswordComplexityRule } from '../models/password-complexity-rule.js';
2
2
  /**
3
- * @param lowerCaseCount The minimum lower case characters length
4
- * @returns The created Password Policy object
3
+ * Builds a complexity rule that requires at least `lowerCaseCount` lowercase
4
+ * characters. Diacritics are stripped before counting.
5
5
  */
6
6
  export declare const createContainsLowercasePolicy: (lowerCaseCount: number) => PasswordComplexityRule;
7
7
  //# sourceMappingURL=contains-lowercase.d.ts.map
@@ -1,6 +1,6 @@
1
1
  /**
2
- * @param lowerCaseCount The minimum lower case characters length
3
- * @returns The created Password Policy object
2
+ * Builds a complexity rule that requires at least `lowerCaseCount` lowercase
3
+ * characters. Diacritics are stripped before counting.
4
4
  */
5
5
  export const createContainsLowercasePolicy = (lowerCaseCount) => ({
6
6
  name: 'containsLowercase',
@@ -1,7 +1,7 @@
1
1
  import type { PasswordComplexityRule } from '../models/password-complexity-rule.js';
2
2
  /**
3
- * @param upperCaseCount The minimum upper case characters length
4
- * @returns The created Password Policy object
3
+ * Builds a complexity rule that requires at least `upperCaseCount` uppercase
4
+ * characters. Diacritics are stripped before counting (`Á` counts as `A`).
5
5
  */
6
6
  export declare const createContainsUppercasePolicy: (upperCaseCount: number) => PasswordComplexityRule;
7
7
  //# sourceMappingURL=contains-uppercase.d.ts.map
@@ -1,6 +1,6 @@
1
1
  /**
2
- * @param upperCaseCount The minimum upper case characters length
3
- * @returns The created Password Policy object
2
+ * Builds a complexity rule that requires at least `upperCaseCount` uppercase
3
+ * characters. Diacritics are stripped before counting (`Á` counts as `A`).
4
4
  */
5
5
  export const createContainsUppercasePolicy = (upperCaseCount) => ({
6
6
  name: 'containsUppercase',
@@ -1,7 +1,4 @@
1
1
  import type { PasswordComplexityRule } from '../models/password-complexity-rule.js';
2
- /**
3
- * @param maxLength The maximum password length
4
- * @returns The created Password Policy object
5
- */
2
+ /** Builds a complexity rule that fails when the password is longer than `maxLength`. */
6
3
  export declare const createMaxLengthComplexityRule: (maxLength: number) => PasswordComplexityRule;
7
4
  //# sourceMappingURL=max-length.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"max-length.d.ts","sourceRoot":"","sources":["../../src/password-complexity-rules/max-length.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAA;AAEnF;;;GAGG;AACH,eAAO,MAAM,6BAA6B,GAAI,WAAW,MAAM,KAAG,sBAShE,CAAA"}
1
+ {"version":3,"file":"max-length.d.ts","sourceRoot":"","sources":["../../src/password-complexity-rules/max-length.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAA;AAEnF,wFAAwF;AACxF,eAAO,MAAM,6BAA6B,GAAI,WAAW,MAAM,KAAG,sBAShE,CAAA"}
@@ -1,7 +1,4 @@
1
- /**
2
- * @param maxLength The maximum password length
3
- * @returns The created Password Policy object
4
- */
1
+ /** Builds a complexity rule that fails when the password is longer than `maxLength`. */
5
2
  export const createMaxLengthComplexityRule = (maxLength) => ({
6
3
  name: 'maxLength',
7
4
  check: async (passwordString) => {
@@ -1 +1 @@
1
- {"version":3,"file":"max-length.js","sourceRoot":"","sources":["../../src/password-complexity-rules/max-length.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,SAAiB,EAA0B,EAAE,CAAC,CAAC;IAC3F,IAAI,EAAE,WAAoB;IAC1B,KAAK,EAAE,KAAK,EAAE,cAAsB,EAAE,EAAE;QACtC,MAAM,OAAO,GAAG,cAAc,CAAC,MAAM,IAAI,SAAS,CAAA;QAClD,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,EAAE,OAAO,EAAE,CAAA;QACpB,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,kCAAkC,SAAS,mBAAmB,EAAE,IAAI,EAAE,WAAW,EAAE,CAAA;IAChH,CAAC;CACF,CAAC,CAAA"}
1
+ {"version":3,"file":"max-length.js","sourceRoot":"","sources":["../../src/password-complexity-rules/max-length.ts"],"names":[],"mappings":"AAEA,wFAAwF;AACxF,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,SAAiB,EAA0B,EAAE,CAAC,CAAC;IAC3F,IAAI,EAAE,WAAoB;IAC1B,KAAK,EAAE,KAAK,EAAE,cAAsB,EAAE,EAAE;QACtC,MAAM,OAAO,GAAG,cAAc,CAAC,MAAM,IAAI,SAAS,CAAA;QAClD,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,EAAE,OAAO,EAAE,CAAA;QACpB,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,kCAAkC,SAAS,mBAAmB,EAAE,IAAI,EAAE,WAAW,EAAE,CAAA;IAChH,CAAC;CACF,CAAC,CAAA"}
@@ -1,7 +1,4 @@
1
1
  import type { PasswordComplexityRule } from '../models/password-complexity-rule.js';
2
- /**
3
- * @param minLength The minimum password length
4
- * @returns The created Password Policy object
5
- */
2
+ /** Builds a complexity rule that fails when the password is shorter than `minLength`. */
6
3
  export declare const createMinLengthComplexityRule: (minLength: number) => PasswordComplexityRule;
7
4
  //# sourceMappingURL=min-length.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"min-length.d.ts","sourceRoot":"","sources":["../../src/password-complexity-rules/min-length.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAA;AAEnF;;;GAGG;AACH,eAAO,MAAM,6BAA6B,GAAI,WAAW,MAAM,KAAG,sBAShE,CAAA"}
1
+ {"version":3,"file":"min-length.d.ts","sourceRoot":"","sources":["../../src/password-complexity-rules/min-length.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAA;AAEnF,yFAAyF;AACzF,eAAO,MAAM,6BAA6B,GAAI,WAAW,MAAM,KAAG,sBAShE,CAAA"}
@@ -1,7 +1,4 @@
1
- /**
2
- * @param minLength The minimum password length
3
- * @returns The created Password Policy object
4
- */
1
+ /** Builds a complexity rule that fails when the password is shorter than `minLength`. */
5
2
  export const createMinLengthComplexityRule = (minLength) => ({
6
3
  name: 'minLength',
7
4
  check: async (passwordString) => {
@@ -1 +1 @@
1
- {"version":3,"file":"min-length.js","sourceRoot":"","sources":["../../src/password-complexity-rules/min-length.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,SAAiB,EAA0B,EAAE,CAAC,CAAC;IAC3F,IAAI,EAAE,WAAoB;IAC1B,KAAK,EAAE,KAAK,EAAE,cAAsB,EAAE,EAAE;QACtC,MAAM,OAAO,GAAG,cAAc,CAAC,MAAM,IAAI,SAAS,CAAA;QAClD,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,EAAE,OAAO,EAAE,CAAA;QACpB,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,mCAAmC,SAAS,mBAAmB,EAAE,IAAI,EAAE,WAAW,EAAE,CAAA;IACjH,CAAC;CACF,CAAC,CAAA"}
1
+ {"version":3,"file":"min-length.js","sourceRoot":"","sources":["../../src/password-complexity-rules/min-length.ts"],"names":[],"mappings":"AAEA,yFAAyF;AACzF,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,SAAiB,EAA0B,EAAE,CAAC,CAAC;IAC3F,IAAI,EAAE,WAAoB;IAC1B,KAAK,EAAE,KAAK,EAAE,cAAsB,EAAE,EAAE;QACtC,MAAM,OAAO,GAAG,cAAc,CAAC,MAAM,IAAI,SAAS,CAAA;QAClD,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,EAAE,OAAO,EAAE,CAAA;QACpB,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,mCAAmC,SAAS,mBAAmB,EAAE,IAAI,EAAE,WAAW,EAAE,CAAA;IACjH,CAAC;CACF,CAAC,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@furystack/security",
3
- "version": "8.0.0",
3
+ "version": "8.0.2",
4
4
  "description": "Security, password management and authorization related stuff for FuryStack",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -37,19 +37,19 @@
37
37
  "url": "https://github.com/furystack/furystack/issues"
38
38
  },
39
39
  "dependencies": {
40
- "@furystack/core": "^17.0.0",
41
- "@furystack/inject": "^13.0.0",
42
- "@furystack/repository": "^11.0.0"
40
+ "@furystack/core": "^17.1.1",
41
+ "@furystack/inject": "^13.0.2",
42
+ "@furystack/repository": "^11.0.2"
43
43
  },
44
44
  "homepage": "https://github.com/furystack/furystack",
45
45
  "devDependencies": {
46
- "@furystack/utils": "^9.0.0",
47
- "@types/node": "^25.6.0",
46
+ "@furystack/utils": "^9.0.2",
47
+ "@types/node": "^25.9.1",
48
48
  "typescript": "^6.0.3",
49
- "vitest": "^4.1.4"
49
+ "vitest": "^4.1.8"
50
50
  },
51
51
  "engines": {
52
- "node": ">=22.0.0"
52
+ "node": ">=24.0.0"
53
53
  },
54
54
  "sideEffects": false
55
55
  }
@@ -1,8 +1,11 @@
1
+ import type { PasswordComplexityRule } from '../models/password-complexity-rule.js'
2
+
3
+ /**
4
+ * Thrown by password-setting flows when the candidate password fails one or
5
+ * more configured {@link PasswordComplexityRule}s. `result` carries the
6
+ * per-rule failures so callers can render targeted user feedback.
7
+ */
1
8
  export class PasswordComplexityError extends Error {
2
- /**
3
- * @param result A detailed error result array
4
- * @param message The Error message
5
- */
6
9
  constructor(
7
10
  public readonly result: Array<{ message: string; rule: string }>,
8
11
  message?: string,
@@ -1,4 +1,6 @@
1
1
  /**
2
- * Error that can be thrown if an authentication is required but not provided
2
+ * Thrown when credential verification fails: bad username/password, expired
3
+ * password, or expired/invalid reset token. REST handlers should map this
4
+ * to a 401 response.
3
5
  */
4
6
  export class UnauthenticatedError extends Error {}
@@ -1,23 +1,13 @@
1
+ import type { PasswordHasher } from '../password-hasher.js'
2
+
1
3
  /**
2
- * Entry that stores credential info for password login
4
+ * Persisted password credential. `passwordHash` and `salt` are produced by
5
+ * the configured {@link PasswordHasher}; `creationDate` (ISO 8601 string)
6
+ * is the source of truth for password-expiration policies.
3
7
  */
4
8
  export class PasswordCredential {
5
- /**
6
- * The unique name of the user
7
- */
8
9
  declare userName: string
9
- /**
10
- * The hashed password value
11
- */
12
10
  declare passwordHash: string
13
-
14
- /**
15
- * Salt value for password hashing // TODO
16
- */
17
11
  declare salt: string
18
-
19
- /**
20
- * The Creation date in ISO String format
21
- */
22
12
  declare creationDate: string
23
13
  }
@@ -1,14 +1,10 @@
1
+ /**
2
+ * Single-use password reset token. `token` is the URL-safe identifier
3
+ * shared with the user (e.g. via email). `createdAt` (ISO 8601) is the
4
+ * expiration anchor honoured by `SecurityPolicyManager.hasTokenExpired`.
5
+ */
1
6
  export class PasswordResetToken {
2
- /**
3
- * The related user name
4
- */
5
7
  declare userName: string
6
- /**
7
- * The Token value - should be some kind of generated UUID that can be included e.g. in URLs
8
- */
9
8
  declare token: string
10
- /**
11
- * The creation date in an ISO datetime format
12
- */
13
9
  declare createdAt: string
14
10
  }
@@ -1,8 +1,8 @@
1
1
  import type { PasswordComplexityRule } from '../models/password-complexity-rule.js'
2
2
 
3
3
  /**
4
- * @param lowerCaseCount The minimum lower case characters length
5
- * @returns The created Password Policy object
4
+ * Builds a complexity rule that requires at least `lowerCaseCount` lowercase
5
+ * characters. Diacritics are stripped before counting.
6
6
  */
7
7
  export const createContainsLowercasePolicy = (lowerCaseCount: number): PasswordComplexityRule => ({
8
8
  name: 'containsLowercase' as const,
@@ -1,8 +1,8 @@
1
1
  import type { PasswordComplexityRule } from '../models/password-complexity-rule.js'
2
2
 
3
3
  /**
4
- * @param upperCaseCount The minimum upper case characters length
5
- * @returns The created Password Policy object
4
+ * Builds a complexity rule that requires at least `upperCaseCount` uppercase
5
+ * characters. Diacritics are stripped before counting (`Á` counts as `A`).
6
6
  */
7
7
  export const createContainsUppercasePolicy = (upperCaseCount: number): PasswordComplexityRule => ({
8
8
  name: 'containsUppercase' as const,
@@ -1,9 +1,6 @@
1
1
  import type { PasswordComplexityRule } from '../models/password-complexity-rule.js'
2
2
 
3
- /**
4
- * @param maxLength The maximum password length
5
- * @returns The created Password Policy object
6
- */
3
+ /** Builds a complexity rule that fails when the password is longer than `maxLength`. */
7
4
  export const createMaxLengthComplexityRule = (maxLength: number): PasswordComplexityRule => ({
8
5
  name: 'maxLength' as const,
9
6
  check: async (passwordString: string) => {
@@ -1,9 +1,6 @@
1
1
  import type { PasswordComplexityRule } from '../models/password-complexity-rule.js'
2
2
 
3
- /**
4
- * @param minLength The minimum password length
5
- * @returns The created Password Policy object
6
- */
3
+ /** Builds a complexity rule that fails when the password is shorter than `minLength`. */
7
4
  export const createMinLengthComplexityRule = (minLength: number): PasswordComplexityRule => ({
8
5
  name: 'minLength' as const,
9
6
  check: async (passwordString: string) => {