@astram/guard 0.18.0 → 0.20.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 (144) hide show
  1. package/dist/audit/audit-chain-sealer.d.ts +90 -0
  2. package/dist/audit/audit-chain-sealer.d.ts.map +1 -0
  3. package/dist/audit/audit-chain-sealer.js +520 -0
  4. package/dist/audit/audit-seal-config.d.ts +22 -0
  5. package/dist/audit/audit-seal-config.d.ts.map +1 -0
  6. package/dist/audit/audit-seal-config.js +35 -0
  7. package/dist/audit/audit-sealer.service.d.ts +62 -0
  8. package/dist/audit/audit-sealer.service.d.ts.map +1 -0
  9. package/dist/audit/audit-sealer.service.js +197 -0
  10. package/dist/audit/node-sha256-hash.d.ts +6 -0
  11. package/dist/audit/node-sha256-hash.d.ts.map +1 -0
  12. package/dist/audit/node-sha256-hash.js +16 -0
  13. package/dist/auth/account.controller.d.ts +3 -1
  14. package/dist/auth/account.controller.d.ts.map +1 -1
  15. package/dist/auth/account.controller.js +79 -6
  16. package/dist/auth/admin-signin-controls.d.ts +80 -0
  17. package/dist/auth/admin-signin-controls.d.ts.map +1 -0
  18. package/dist/auth/admin-signin-controls.js +91 -0
  19. package/dist/auth/auth-audit.d.ts +59 -0
  20. package/dist/auth/auth-audit.d.ts.map +1 -0
  21. package/dist/auth/auth-audit.js +93 -0
  22. package/dist/auth/auth.controller.d.ts +53 -6
  23. package/dist/auth/auth.controller.d.ts.map +1 -1
  24. package/dist/auth/auth.controller.js +330 -44
  25. package/dist/auth/auth.module.d.ts +49 -0
  26. package/dist/auth/auth.module.d.ts.map +1 -1
  27. package/dist/auth/auth.module.js +149 -4
  28. package/dist/auth/captcha-gate.d.ts +103 -0
  29. package/dist/auth/captcha-gate.d.ts.map +1 -0
  30. package/dist/auth/captcha-gate.js +245 -0
  31. package/dist/auth/dto.d.ts +22 -1
  32. package/dist/auth/dto.d.ts.map +1 -1
  33. package/dist/auth/login-name-count-boot.d.ts +24 -0
  34. package/dist/auth/login-name-count-boot.d.ts.map +1 -0
  35. package/dist/auth/login-name-count-boot.js +47 -0
  36. package/dist/auth/logout-proof.d.ts +55 -0
  37. package/dist/auth/logout-proof.d.ts.map +1 -0
  38. package/dist/auth/logout-proof.js +127 -0
  39. package/dist/auth/pending-mfa-store.d.ts +5 -0
  40. package/dist/auth/pending-mfa-store.d.ts.map +1 -1
  41. package/dist/auth/pending-mfa-store.js +2 -0
  42. package/dist/auth/persistence.module.d.ts +2 -2
  43. package/dist/auth/persistence.module.d.ts.map +1 -1
  44. package/dist/auth/persistence.module.js +19 -3
  45. package/dist/auth/ports/audit-sink.d.ts +5 -2
  46. package/dist/auth/ports/audit-sink.d.ts.map +1 -1
  47. package/dist/auth/ports/mfa-device-store.d.ts +7 -0
  48. package/dist/auth/ports/mfa-device-store.d.ts.map +1 -1
  49. package/dist/auth/profile-resolver.d.ts +6 -0
  50. package/dist/auth/profile-resolver.d.ts.map +1 -1
  51. package/dist/auth/rate-limit/attempt-limiter.d.ts +6 -0
  52. package/dist/auth/rate-limit/attempt-limiter.d.ts.map +1 -1
  53. package/dist/auth/rate-limit/attempt-limiter.js +14 -0
  54. package/dist/auth/tokens.d.ts +59 -0
  55. package/dist/auth/tokens.d.ts.map +1 -1
  56. package/dist/auth/tokens.js +61 -1
  57. package/dist/authentication/credential-provisioner.d.ts +7 -0
  58. package/dist/authentication/credential-provisioner.d.ts.map +1 -1
  59. package/dist/authentication/mariadb-credential-provisioner.d.ts +1 -0
  60. package/dist/authentication/mariadb-credential-provisioner.d.ts.map +1 -1
  61. package/dist/authentication/mariadb-credential-provisioner.js +7 -0
  62. package/dist/authentication/mariadb-credential-resolver.d.ts +23 -2
  63. package/dist/authentication/mariadb-credential-resolver.d.ts.map +1 -1
  64. package/dist/authentication/mariadb-credential-resolver.js +45 -1
  65. package/dist/authentication/mariadb-mfa-device-store.d.ts +7 -0
  66. package/dist/authentication/mariadb-mfa-device-store.d.ts.map +1 -1
  67. package/dist/authentication/mariadb-mfa-device-store.js +32 -0
  68. package/dist/authentication/mariadb-mfa-requirement-source.d.ts +55 -0
  69. package/dist/authentication/mariadb-mfa-requirement-source.d.ts.map +1 -0
  70. package/dist/authentication/mariadb-mfa-requirement-source.js +164 -0
  71. package/dist/authentication/mariadb-mfa-resetter.d.ts +42 -0
  72. package/dist/authentication/mariadb-mfa-resetter.d.ts.map +1 -0
  73. package/dist/authentication/mariadb-mfa-resetter.js +59 -0
  74. package/dist/authentication/mariadb-profile-writer.d.ts.map +1 -1
  75. package/dist/authentication/mariadb-profile-writer.js +5 -0
  76. package/dist/authentication/sign-in-with.d.ts +14 -0
  77. package/dist/authentication/sign-in-with.d.ts.map +1 -0
  78. package/dist/authentication/sign-in-with.js +36 -0
  79. package/dist/authz/core-access.d.ts +11 -0
  80. package/dist/authz/core-access.d.ts.map +1 -0
  81. package/dist/authz/core-access.js +14 -0
  82. package/dist/authz/list-scope-sql.d.ts.map +1 -1
  83. package/dist/authz/list-scope-sql.js +15 -5
  84. package/dist/authz/wire-record-authorization.d.ts.map +1 -1
  85. package/dist/authz/wire-record-authorization.js +21 -3
  86. package/dist/captcha/captcha.providers.d.ts +18 -0
  87. package/dist/captcha/captcha.providers.d.ts.map +1 -0
  88. package/dist/captcha/captcha.providers.js +78 -0
  89. package/dist/captcha/recaptcha-verifier.d.ts +20 -0
  90. package/dist/captcha/recaptcha-verifier.d.ts.map +1 -0
  91. package/dist/captcha/recaptcha-verifier.js +48 -0
  92. package/dist/captcha/siteverify.d.ts +47 -0
  93. package/dist/captcha/siteverify.d.ts.map +1 -0
  94. package/dist/captcha/siteverify.js +98 -0
  95. package/dist/captcha/turnstile-verifier.d.ts +18 -0
  96. package/dist/captcha/turnstile-verifier.d.ts.map +1 -0
  97. package/dist/captcha/turnstile-verifier.js +41 -0
  98. package/dist/config/captcha-config.d.ts +47 -0
  99. package/dist/config/captcha-config.d.ts.map +1 -0
  100. package/dist/config/captcha-config.js +163 -0
  101. package/dist/config/reserved-principal-ids.d.ts +15 -0
  102. package/dist/config/reserved-principal-ids.d.ts.map +1 -1
  103. package/dist/config/reserved-principal-ids.js +20 -3
  104. package/dist/enforcement/global-enforcement.guard.d.ts +9 -1
  105. package/dist/enforcement/global-enforcement.guard.d.ts.map +1 -1
  106. package/dist/enforcement/global-enforcement.guard.js +52 -10
  107. package/dist/enforcement/reenroll-allowlist.d.ts +5 -0
  108. package/dist/enforcement/reenroll-allowlist.d.ts.map +1 -1
  109. package/dist/enforcement/reenroll-allowlist.js +5 -0
  110. package/dist/identity/auth-facts.controller.d.ts +31 -4
  111. package/dist/identity/auth-facts.controller.d.ts.map +1 -1
  112. package/dist/identity/auth-facts.controller.js +46 -11
  113. package/dist/identity/identity-actions.d.ts +2 -2
  114. package/dist/identity/identity-actions.d.ts.map +1 -1
  115. package/dist/identity/module-registry.bridge.d.ts.map +1 -1
  116. package/dist/identity/module-registry.bridge.js +3 -6
  117. package/dist/identity/permission-facts.adapter.d.ts +22 -0
  118. package/dist/identity/permission-facts.adapter.d.ts.map +1 -1
  119. package/dist/identity/permission-facts.adapter.js +26 -1
  120. package/dist/index.d.ts +11 -2
  121. package/dist/index.d.ts.map +1 -1
  122. package/dist/index.js +43 -11
  123. package/dist/internal.d.ts +27 -0
  124. package/dist/internal.d.ts.map +1 -1
  125. package/dist/internal.js +36 -1
  126. package/dist/module/shield.module.d.ts +27 -0
  127. package/dist/module/shield.module.d.ts.map +1 -1
  128. package/dist/module/shield.module.js +10 -0
  129. package/dist/request-auth/request-principal.d.ts +8 -1
  130. package/dist/request-auth/request-principal.d.ts.map +1 -1
  131. package/dist/request-auth/request-principal.js +11 -4
  132. package/dist/request-auth/session-token-binder.d.ts +82 -0
  133. package/dist/request-auth/session-token-binder.d.ts.map +1 -1
  134. package/dist/request-auth/session-token-binder.js +203 -1
  135. package/dist/session/mfa-requirement-service.d.ts +168 -0
  136. package/dist/session/mfa-requirement-service.d.ts.map +1 -0
  137. package/dist/session/mfa-requirement-service.js +461 -0
  138. package/dist/session/session-restriction-store.d.ts +36 -0
  139. package/dist/session/session-restriction-store.d.ts.map +1 -1
  140. package/dist/session/session-restriction-store.js +57 -6
  141. package/dist/session/session-restriction.d.ts +22 -0
  142. package/dist/session/session-restriction.d.ts.map +1 -0
  143. package/dist/session/session-restriction.js +23 -0
  144. package/package.json +10 -5
@@ -64,6 +64,8 @@
64
64
  */
65
65
  import { type DynamicModule, type Provider } from '@nestjs/common';
66
66
  import type { CredentialResolver, HmacSha1, FactorVerifier } from '@astram/core';
67
+ import { type SignInMethod } from '../authentication/sign-in-with.js';
68
+ import { type ShieldCaptchaOption } from '../captcha/captcha.providers.js';
67
69
  import type { SessionFactsProjector } from './ports/session-facts-projector.js';
68
70
  import type { ScopeSubtreeResolver } from './ports/scope-subtree-resolver.js';
69
71
  import type { MembershipChecker } from './ports/membership-checker.js';
@@ -107,6 +109,26 @@ export declare function resolveTotpVerifier(override: FactorVerifier | null | un
107
109
  * consumer's built CJS dist. Async because of {@link loadCore}.
108
110
  */
109
111
  export declare function makeDefaultTotpVerifier(): Promise<FactorVerifier>;
112
+ /**
113
+ * Mandatory 2FA (R2.3–R2.5, R2.7): the service the login, the request path, device confirm and
114
+ * device removal use — bound ONLY when `@astram/identity` signals its security-policy feature
115
+ * ({@link SHIELD_MFA_POLICY_FEATURE}); otherwise `null` and the guard behaves exactly as before (no
116
+ * evaluation, no extra read, no new claim). Grants come from the session-facts projector (the
117
+ * decision authority's own `loadCoarseGrants`); the self-authenticating routes read the version
118
+ * from Redis (miss ⇒ one DB fill, Redis error ⇒ deny), as gate 5 does.
119
+ */
120
+ export declare const mfaRequirementProvider: Provider;
121
+ /**
122
+ * Admin sign-in controls (auth capabilities R11.2): the admin's own TOTP step-up, over the device
123
+ * store, the replay-guarded login verifier and the `mfa:pid` limiter (the same three the code-gated
124
+ * `/account` routes use). For `@astram/identity`'s `/identity/users/:uuid/*` controls.
125
+ */
126
+ export declare const adminStepUpProvider: Provider;
127
+ /**
128
+ * Admin sign-in controls (R11.1 unlock): clears one principal's `login:pid`, `mfa:pid`,
129
+ * `recovery:` and CAPTCHA account counters on the guard's one Redis client (fails closed).
130
+ */
131
+ export declare const accountUnlockerProvider: Provider;
110
132
  /** DI token for the single-layout privilege probe hook (a no-op in the four layout). */
111
133
  export declare const SHIELD_SINGLE_LAYOUT_PROBE: unique symbol;
112
134
  /**
@@ -238,6 +260,27 @@ export interface AuthModuleOptions {
238
260
  * `emailSender: 'disabled'` (Phase 13 #1; `RESET_LINK_BASE_URL` follows the same rule).
239
261
  */
240
262
  readonly emailChangeLinkBaseUrl?: string;
263
+ /**
264
+ * R15.1 / D-9: require proof for `POST /auth/logout` (a refresh token of the session, or an
265
+ * access token bound to it). `false` (default, this release): an unproven logout still revokes,
266
+ * counted as `auth.logout.unproven` with a one-time deprecation warning. `true`: an unproven
267
+ * logout revokes nothing (204). Becomes `true` by default at the next guard major.
268
+ */
269
+ readonly logoutRequiresProof?: boolean;
270
+ /**
271
+ * R1.8: the sign-in forms `POST /auth/login` accepts. `['email']` (default) is today's
272
+ * behaviour; `['email', 'username']` also accepts the user's login name (`users.u_login_name`,
273
+ * set by an admin or `bootstrap:org`). Validated at registration: an unknown value, an empty
274
+ * list or a list without `'email'` throws. Applies to the framework-default credential
275
+ * resolver; a consumer `credentialResolver` decides for itself.
276
+ */
277
+ readonly signInWith?: readonly SignInMethod[];
278
+ /**
279
+ * Auth capabilities R7: `'env'` turns CAPTCHA on for `/auth/login`, `/auth/forgot-password` and
280
+ * `/auth/reset-password` from `CAPTCHA_*` (`loadCaptchaConfig`; a missing or invalid value fails
281
+ * the boot). Omitted ⇒ off, every route answers exactly as before.
282
+ */
283
+ readonly captcha?: ShieldCaptchaOption;
241
284
  }
242
285
  /**
243
286
  * The per-account email-change REQUEST limiter (Phase 12) — `email-change:pid:<id>`, 3 per 60-min
@@ -251,6 +294,12 @@ export declare const attemptLimiterFactoryProvider: Provider;
251
294
  * the unit test only — not part of the package's public surface.
252
295
  */
253
296
  export declare function resolveDefaultEmailSender(rawNodeEnv: string | undefined): EmailSender;
297
+ /**
298
+ * The auth audit sink (R12.1, B-3): the app-supplied `auditSink` wins; else the framework default
299
+ * on {@link SHIELD_DEFAULT_AUTH_AUDIT_SINK} (bound globally by `@astram/identity`), injected
300
+ * optionally; else `null` (un-audited, as before).
301
+ */
302
+ export declare function makeAuditSinkProvider(override?: AuditSink): Provider;
254
303
  /**
255
304
  * The auth composition module. Imports {@link PersistenceModule} (the live
256
305
  * connections) and provides the adapters + composed engines. Exports the two
@@ -1 +1 @@
1
- {"version":3,"file":"auth.module.d.ts","sourceRoot":"","sources":["../../src/auth/auth.module.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auth.module.d.ts","sourceRoot":"","sources":["../../src/auth/auth.module.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+DG;AAEH,OAAO,EAGL,KAAK,aAAa,EAElB,KAAK,QAAQ,EACd,MAAM,gBAAgB,CAAC;AAaxB,OAAO,KAAK,EAGV,kBAAkB,EAOlB,QAAQ,EACR,cAAc,EAKf,MAAM,cAAc,CAAC;AA4HtB,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACzF,OAAO,EAAoB,KAAK,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAQ7F,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAGhF,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,KAAK,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAE5F,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAGpE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAsBvD;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,EAAE,QACqE,CAAC;AAE7F;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,EAC3C,eAAe,EAAE,cAAc,GAC9B,cAAc,CAEhB;AAED;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,cAAc,CAAC,CAGvE;AA8JD;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,EAAE,QAwCpC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,QAiBjC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,uBAAuB,EAAE,QAerC,CAAC;AAyGF,wFAAwF;AACxF,eAAO,MAAM,0BAA0B,eAAuC,CAAC;AAE/E;;;GAGG;AACH,eAAO,MAAM,yBAAyB,EAAE,QAWvC,CAAC;AAyUF;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;;;;OAMG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACjD;;;;;;OAMG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,eAAe,CAAC;IAC3C;;;;;;OAMG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAC7C,QAAQ,CAAC,eAAe,CAAC,EAAE,eAAe,CAAC;IAC3C;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,GAAG,UAAU,GAAG,KAAK,CAAC;IACxD,QAAQ,CAAC,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IAC/C,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC;IACvC,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,CAAC;IACzC;;;;;;OAMG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC;IAC/B;;;;;OAKG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,CAAC;IACzC;;;;;;;;OAQG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,cAAc,CAAC;IACvC;;;;;;;;OAQG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC;;oGAEgG;IAChG,QAAQ,CAAC,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChD,uGAAuG;IACvG,QAAQ,CAAC,wBAAwB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtD;;;;;;;OAOG;IACH,QAAQ,CAAC,qBAAqB,CAAC,EAAE,qBAAqB,CAAC;IACvD;;;;;;;;OAQG;IACH,QAAQ,CAAC,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;IACrD;;;;;;;OAOG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IAC/C;;;;;;OAMG;IACH,QAAQ,CAAC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IACzC;;;;;OAKG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IACvC;;;;;;OAMG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;IAC9C;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,mBAAmB,CAAC;CACxC;AAyFD;;;GAGG;AACH,2GAA2G;AAC3G,MAAM,MAAM,qBAAqB,GAAG,CAAC,GAAG,EAAE,oBAAoB,KAAK,cAAc,CAAC;AAClF,eAAO,MAAM,6BAA6B,EAAE,QAO3C,CAAC;AAmEF;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,WAAW,CAcrF;AAsFD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,CAAC,EAAE,SAAS,GAAG,QAAQ,CAQpE;AAwDD;;;;;;GAMG;AACH,qBACa,UAAU;IACrB;;;;;OAKG;IACH,MAAM,CAAC,OAAO,CAAC,OAAO,GAAE,iBAAsB,GAAG,aAAa;CAkN/D"}
@@ -104,10 +104,11 @@ var __importStar = (this && this.__importStar) || (function () {
104
104
  })();
105
105
  var AuthModule_1;
106
106
  Object.defineProperty(exports, "__esModule", { value: true });
107
- exports.AuthModule = exports.attemptLimiterFactoryProvider = exports.singleLayoutProbeProvider = exports.SHIELD_SINGLE_LAYOUT_PROBE = exports.hmacSha1 = void 0;
107
+ exports.AuthModule = exports.attemptLimiterFactoryProvider = exports.singleLayoutProbeProvider = exports.SHIELD_SINGLE_LAYOUT_PROBE = exports.accountUnlockerProvider = exports.adminStepUpProvider = exports.mfaRequirementProvider = exports.hmacSha1 = void 0;
108
108
  exports.resolveTotpVerifier = resolveTotpVerifier;
109
109
  exports.makeDefaultTotpVerifier = makeDefaultTotpVerifier;
110
110
  exports.resolveDefaultEmailSender = resolveDefaultEmailSender;
111
+ exports.makeAuditSinkProvider = makeAuditSinkProvider;
111
112
  const common_1 = require("@nestjs/common");
112
113
  const node_crypto_1 = require("node:crypto");
113
114
  const app_config_js_1 = require("../config/app-config.js");
@@ -136,13 +137,22 @@ const index_js_1 = require("../session/index.js");
136
137
  const replay_outcome_js_1 = require("../session/replay-outcome.js");
137
138
  const persistence_module_js_1 = require("./persistence.module.js");
138
139
  const auth_controller_js_1 = require("./auth.controller.js");
140
+ const logout_proof_js_1 = require("./logout-proof.js");
139
141
  const account_controller_js_1 = require("./account.controller.js");
140
142
  const confirm_email_controller_js_1 = require("./confirm-email.controller.js");
141
143
  const pending_mfa_store_js_1 = require("./pending-mfa-store.js");
142
144
  const mfa_step_up_js_1 = require("./mfa-step-up.js");
143
145
  const tokens_js_1 = require("./tokens.js");
146
+ const admin_signin_controls_js_1 = require("./admin-signin-controls.js");
147
+ const captcha_gate_js_1 = require("./captcha-gate.js");
148
+ const sign_in_with_js_1 = require("../authentication/sign-in-with.js");
149
+ const captcha_providers_js_1 = require("../captcha/captcha.providers.js");
150
+ const login_name_count_boot_js_1 = require("./login-name-count-boot.js");
151
+ const framework_schema_names_js_1 = require("../config/framework-schema-names.js");
144
152
  const permission_version_cache_js_1 = require("../authz/permission-version-cache.js");
145
153
  const session_restriction_store_js_1 = require("../session/session-restriction-store.js");
154
+ const mariadb_mfa_requirement_source_js_1 = require("../authentication/mariadb-mfa-requirement-source.js");
155
+ const mfa_requirement_service_js_1 = require("../session/mfa-requirement-service.js");
146
156
  const attempt_limiter_js_1 = require("./rate-limit/attempt-limiter.js");
147
157
  const trust_proxy_check_js_1 = require("./rate-limit/trust-proxy-check.js");
148
158
  const email_delivery_js_1 = require("../messaging/email-delivery.js");
@@ -256,8 +266,11 @@ function makeCredentialResolverProvider(override) {
256
266
  provide: tokens_js_1.SHIELD_CREDENTIAL_RESOLVER,
257
267
  // #7: the default resolver folds the principal's CONFIRMED MFA devices into a
258
268
  // `totp` required factor, so enrolled MFA is enforced at every password login.
259
- useFactory: (pool, devices, config) => new mariadb_credential_resolver_js_1.MariaDbCredentialResolver(pool, devices, undefined, (0, app_config_js_1.frameworkSchemasOf)(config)),
260
- inject: [tokens_js_1.SHIELD_DB_POOL, tokens_js_1.SHIELD_MFA_DEVICE_STORE, config_module_js_1.APP_CONFIG],
269
+ // R1.8: `signInWith` decides whether a hint without `@` may resolve by login name.
270
+ useFactory: (pool, devices, config, signInWith) => new mariadb_credential_resolver_js_1.MariaDbCredentialResolver(pool, devices, undefined, (0, app_config_js_1.frameworkSchemasOf)(config), {
271
+ signInWith,
272
+ }),
273
+ inject: [tokens_js_1.SHIELD_DB_POOL, tokens_js_1.SHIELD_MFA_DEVICE_STORE, config_module_js_1.APP_CONFIG, tokens_js_1.SHIELD_SIGN_IN_WITH],
261
274
  };
262
275
  }
263
276
  /**
@@ -303,6 +316,88 @@ const sessionRestrictionStoreProvider = {
303
316
  useFactory: (pool, config) => new session_restriction_store_js_1.MariaDbSessionRestrictionStore(pool, (0, app_config_js_1.frameworkSchemasOf)(config)),
304
317
  inject: [tokens_js_1.SHIELD_DB_POOL, config_module_js_1.APP_CONFIG],
305
318
  };
319
+ /**
320
+ * The guard's MariaDB {@link MfaRequirementSource} (auth capabilities B-1) over the runtime pool:
321
+ * policies, scope chain, confirmed devices, the per-user grace clock. Reads nothing until asked.
322
+ */
323
+ const mfaRequirementSourceProvider = {
324
+ provide: tokens_js_1.SHIELD_MFA_REQUIREMENT_SOURCE,
325
+ useFactory: (pool, config) => new mariadb_mfa_requirement_source_js_1.MariaDbMfaRequirementSource(pool, (0, app_config_js_1.frameworkSchemasOf)(config)),
326
+ inject: [tokens_js_1.SHIELD_DB_POOL, config_module_js_1.APP_CONFIG],
327
+ };
328
+ /**
329
+ * Mandatory 2FA (R2.3–R2.5, R2.7): the service the login, the request path, device confirm and
330
+ * device removal use — bound ONLY when `@astram/identity` signals its security-policy feature
331
+ * ({@link SHIELD_MFA_POLICY_FEATURE}); otherwise `null` and the guard behaves exactly as before (no
332
+ * evaluation, no extra read, no new claim). Grants come from the session-facts projector (the
333
+ * decision authority's own `loadCoarseGrants`); the self-authenticating routes read the version
334
+ * from Redis (miss ⇒ one DB fill, Redis error ⇒ deny), as gate 5 does.
335
+ */
336
+ exports.mfaRequirementProvider = {
337
+ provide: tokens_js_1.SHIELD_MFA_REQUIREMENT,
338
+ useFactory: (feature, pool, config, projector, versionCache, permissionFacts, binder, restrictions) => {
339
+ if (feature !== true)
340
+ return null;
341
+ const source = new mariadb_mfa_requirement_source_js_1.MariaDbMfaRequirementSource(pool, (0, app_config_js_1.frameworkSchemasOf)(config));
342
+ return new mfa_requirement_service_js_1.MfaRequirementService({
343
+ source,
344
+ // R11.3: the admin users list's batched page reads.
345
+ batch: source,
346
+ loadGrants: async (principalId, tenantId) => {
347
+ if (projector === null || projector === undefined)
348
+ return null;
349
+ if (typeof projector.isActive === 'function' && projector.isActive() !== true)
350
+ return null;
351
+ return projector.project(principalId, tenantId);
352
+ },
353
+ currentVersion: (0, mfa_requirement_service_js_1.currentVersionReader)(versionCache, (tenantId) => permissionFacts.currentVersionFor('', tenantId)),
354
+ binder,
355
+ restrictions,
356
+ });
357
+ },
358
+ inject: [
359
+ { token: tokens_js_1.SHIELD_MFA_POLICY_FEATURE, optional: true },
360
+ tokens_js_1.SHIELD_DB_POOL,
361
+ config_module_js_1.APP_CONFIG,
362
+ tokens_js_1.SHIELD_SESSION_FACTS_PROJECTOR,
363
+ tokens_js_1.SHIELD_PERMISSION_VERSION_CACHE,
364
+ tokens_js_1.SHIELD_PERMISSION_FACTS,
365
+ tokens_js_2.SHIELD_SESSION_TOKEN_BINDER,
366
+ tokens_js_1.SHIELD_SESSION_RESTRICTIONS,
367
+ ],
368
+ };
369
+ /**
370
+ * Admin sign-in controls (auth capabilities R11.2): the admin's own TOTP step-up, over the device
371
+ * store, the replay-guarded login verifier and the `mfa:pid` limiter (the same three the code-gated
372
+ * `/account` routes use). For `@astram/identity`'s `/identity/users/:uuid/*` controls.
373
+ */
374
+ exports.adminStepUpProvider = {
375
+ provide: tokens_js_1.SHIELD_ADMIN_STEP_UP,
376
+ useFactory: (devices, verifier, limiter) => new admin_signin_controls_js_1.TotpAdminStepUp({
377
+ devices: devices ?? null,
378
+ verifier: verifier ?? null,
379
+ limiter: limiter ?? null,
380
+ }),
381
+ inject: [
382
+ { token: tokens_js_1.SHIELD_MFA_DEVICE_STORE, optional: true },
383
+ { token: tokens_js_1.SHIELD_LOGIN_TOTP_VERIFIER, optional: true },
384
+ { token: tokens_js_1.SHIELD_MFA_LIMITER, optional: true },
385
+ ],
386
+ };
387
+ /**
388
+ * Admin sign-in controls (R11.1 unlock): clears one principal's `login:pid`, `mfa:pid`,
389
+ * `recovery:` and CAPTCHA account counters on the guard's one Redis client (fails closed).
390
+ */
391
+ exports.accountUnlockerProvider = {
392
+ provide: tokens_js_1.SHIELD_ACCOUNT_UNLOCKER,
393
+ useFactory: (redis, login, mfa, recovery) => new admin_signin_controls_js_1.RedisAccountUnlocker({
394
+ login,
395
+ mfa,
396
+ recovery,
397
+ captcha: new captcha_gate_js_1.RedisCaptchaCounterStore(redis),
398
+ }),
399
+ inject: [tokens_js_1.SHIELD_REDIS, tokens_js_1.SHIELD_LOGIN_LIMITER, tokens_js_1.SHIELD_MFA_LIMITER, tokens_js_1.SHIELD_RECOVERY_LIMITER],
400
+ };
306
401
  /** Hot session store (Redis adapter, injected with the live client). */
307
402
  const hotSessionStoreProvider = {
308
403
  provide: index_js_1.SHIELD_HOT_SESSION_STORE,
@@ -680,6 +775,17 @@ const totpVerifierProvider = {
680
775
  return createTotpFactorVerifier({ hmacSha1: exports.hmacSha1 });
681
776
  },
682
777
  };
778
+ /** DI token for the R1.9 boot count of users with a login name. */
779
+ const SHIELD_LOGIN_NAME_COUNT_BOOT = Symbol('SHIELD_LOGIN_NAME_COUNT_BOOT');
780
+ /**
781
+ * Auth capabilities R1.9: with `signInWith` including `'username'`, log once at boot how many
782
+ * active users have a login name (count only) through the runtime pool. A no-op otherwise.
783
+ */
784
+ const loginNameCountBootProvider = {
785
+ provide: SHIELD_LOGIN_NAME_COUNT_BOOT,
786
+ useFactory: (pool, config, signInWith) => new login_name_count_boot_js_1.LoginNameCountBoot(async (sql) => (await pool.query(sql)), (0, framework_schema_names_js_1.qualifiedTableName)((0, app_config_js_1.frameworkSchemasOf)(config).app, 'users'), signInWith),
787
+ inject: [tokens_js_1.SHIELD_DB_POOL, config_module_js_1.APP_CONFIG, tokens_js_1.SHIELD_SIGN_IN_WITH],
788
+ };
683
789
  /**
684
790
  * Bind the current-user profile resolver backing `GET /auth/me`.
685
791
  *
@@ -895,8 +1001,19 @@ function makeMfaDeviceStoreProvider(override) {
895
1001
  inject: [tokens_js_1.SHIELD_DB_POOL, config_module_js_1.APP_CONFIG],
896
1002
  };
897
1003
  }
1004
+ /**
1005
+ * The auth audit sink (R12.1, B-3): the app-supplied `auditSink` wins; else the framework default
1006
+ * on {@link SHIELD_DEFAULT_AUTH_AUDIT_SINK} (bound globally by `@astram/identity`), injected
1007
+ * optionally; else `null` (un-audited, as before).
1008
+ */
898
1009
  function makeAuditSinkProvider(override) {
899
- return { provide: tokens_js_1.SHIELD_AUDIT_SINK, useValue: override ?? null };
1010
+ return override
1011
+ ? { provide: tokens_js_1.SHIELD_AUDIT_SINK, useValue: override }
1012
+ : {
1013
+ provide: tokens_js_1.SHIELD_AUDIT_SINK,
1014
+ useFactory: (defaultSink) => defaultSink ?? null,
1015
+ inject: [{ token: tokens_js_1.SHIELD_DEFAULT_AUTH_AUDIT_SINK, optional: true }],
1016
+ };
900
1017
  }
901
1018
  /**
902
1019
  * Bind the OPTIONAL eager session-facts projector (ADR-0011). Same value-provider
@@ -973,6 +1090,10 @@ let AuthModule = AuthModule_1 = class AuthModule {
973
1090
  // `resolveDefaultEmailSender` (that clearer error is kept; in development/test the rule is off).
974
1091
  // G-010: `'env'` is a real sender unless `EMAIL_PROVIDER=disabled` (read after resolveBootSecrets).
975
1092
  const mailDisabled = (0, email_delivery_js_1.isMailDisabled)(options.emailSender, process.env);
1093
+ // R1.8: validated here so a bad value fails the boot with a clear message.
1094
+ const signInWith = (0, sign_in_with_js_1.resolveSignInWith)(options.signInWith);
1095
+ // R7: validated here too, so a bad value fails the boot with a clear message.
1096
+ const captcha = (0, captcha_providers_js_1.captchaProviders)(options.captcha);
976
1097
  return {
977
1098
  module: AuthModule_1,
978
1099
  imports: [persistence_module_js_1.PersistenceModule.forRoot()],
@@ -986,6 +1107,11 @@ let AuthModule = AuthModule_1 = class AuthModule {
986
1107
  controllers: [auth_controller_js_1.AuthController, confirm_email_controller_js_1.ConfirmEmailController, account_controller_js_1.AccountController, auth_facts_controller_js_1.AuthFactsController],
987
1108
  providers: [
988
1109
  passwordHasherProvider,
1110
+ { provide: tokens_js_1.SHIELD_SIGN_IN_WITH, useValue: signInWith },
1111
+ // R1.9: boot count of active users with a login name (only with `username`).
1112
+ loginNameCountBootProvider,
1113
+ // R7: the CAPTCHA config, verifier and gate (`null` gate when the option is absent).
1114
+ ...captcha,
989
1115
  makeCredentialResolverProvider(options.credentialResolver),
990
1116
  // The current-user profile seam backing `GET /auth/me` (null when absent).
991
1117
  makeProfileResolverProvider(options.profileResolver),
@@ -1024,6 +1150,9 @@ let AuthModule = AuthModule_1 = class AuthModule {
1024
1150
  // fails closed, denying every switch — cannot verify the target binding). Consumed by
1025
1151
  // AuthController's scopeSwitch handler.
1026
1152
  makeMembershipCheckerProvider(options.membershipChecker),
1153
+ // R15.1: the logout proof check + the `logoutRequiresProof` option (default false).
1154
+ logout_proof_js_1.logoutProofVerifierProvider,
1155
+ (0, logout_proof_js_1.makeLogoutRequiresProofProvider)(options.logoutRequiresProof),
1027
1156
  // The framework-DEFAULT permission-facts adapter backing AuthFactsController
1028
1157
  // (`/identity/auth-facts` + `/identity/permissions-version`). Reads role grants +
1029
1158
  // per-tenant version from the pool; expands `identity:*` wildcards against the
@@ -1045,6 +1174,13 @@ let AuthModule = AuthModule_1 = class AuthModule {
1045
1174
  permissionVersionCacheProvider,
1046
1175
  // Phase 3B review P1: the durable re-enroll marker + account status for the rebuild.
1047
1176
  sessionRestrictionStoreProvider,
1177
+ // Auth capabilities R2: the MariaDB requirement source and the mandatory-2FA service
1178
+ // (`null` unless identity signals the security-policy feature).
1179
+ mfaRequirementSourceProvider,
1180
+ exports.mfaRequirementProvider,
1181
+ // R11: identity's admin sign-in controls (step-up and unlock).
1182
+ exports.adminStepUpProvider,
1183
+ exports.accountUnlockerProvider,
1048
1184
  hotSessionStoreProvider,
1049
1185
  tokenGeneratorProvider,
1050
1186
  refreshHasherProvider,
@@ -1132,6 +1268,15 @@ let AuthModule = AuthModule_1 = class AuthModule {
1132
1268
  // reads it (gate 5) and `@astram/identity`'s bumper publishes to it after commit.
1133
1269
  tokens_js_1.SHIELD_PERMISSION_VERSION_CACHE,
1134
1270
  tokens_js_1.SHIELD_SESSION_RESTRICTIONS,
1271
+ // Auth capabilities R2: the enforcement guard injects the service (gate-5 recompute).
1272
+ tokens_js_1.SHIELD_MFA_REQUIREMENT,
1273
+ tokens_js_1.SHIELD_MFA_REQUIREMENT_SOURCE,
1274
+ tokens_js_1.SHIELD_SIGN_IN_WITH,
1275
+ // R7: exported for inspection and for later endpoints (OTP request, R7.2).
1276
+ tokens_js_1.SHIELD_CAPTCHA_GATE,
1277
+ // R11: identity's admin sign-in controls inject these (through @astram/guard/internal).
1278
+ tokens_js_1.SHIELD_ADMIN_STEP_UP,
1279
+ tokens_js_1.SHIELD_ACCOUNT_UNLOCKER,
1135
1280
  ],
1136
1281
  };
1137
1282
  }
@@ -0,0 +1,103 @@
1
+ import type Redis from 'ioredis';
2
+ import { type CaptchaProvider, type CaptchaVerifier } from '@astram/core';
3
+ import type { CaptchaConfig, CaptchaEndpoint, CaptchaMode } from '../config/captcha-config.js';
4
+ import type { AuditSink } from './ports/audit-sink.js';
5
+ /** Fixed counter window (ms). */
6
+ export declare const CAPTCHA_WINDOW_MS: number;
7
+ export declare const AUTH_CAPTCHA_FAILED = "auth.captcha.failed";
8
+ export declare const AUTH_CAPTCHA_FAIL_OPEN = "auth.captcha.fail_open";
9
+ /**
10
+ * Bump every key and arm the window on the first hit (or a key left without a TTL). Returns the
11
+ * new counts, in key order. KEYS = the counter keys; ARGV[1] = window ms.
12
+ */
13
+ export declare const CAPTCHA_BUMP_SCRIPT = "local out = {}\nfor i, k in ipairs(KEYS) do\n local n = redis.call('INCR', k)\n if n == 1 or redis.call('PTTL', k) == -1 then\n redis.call('PEXPIRE', k, ARGV[1])\n end\n out[i] = n\nend\nreturn out";
14
+ /** The counters behind the adaptive decision. */
15
+ export interface CaptchaCounterStore {
16
+ /** Current counts (missing = 0). REJECTS on a store error. */
17
+ counts(keys: readonly string[]): Promise<readonly number[]>;
18
+ /** Increment each key (fixed window); returns the new counts. REJECTS on a store error. */
19
+ bump(keys: readonly string[]): Promise<readonly number[]>;
20
+ /** Remove keys. Best-effort. */
21
+ clear(keys: readonly string[]): Promise<void>;
22
+ /** `true` the first time `key` is seen in a window (audit bounding). Best-effort: error ⇒ false. */
23
+ firstInWindow(key: string): Promise<boolean>;
24
+ }
25
+ /** {@link CaptchaCounterStore} over the guard's bounded ioredis client. */
26
+ export declare class RedisCaptchaCounterStore implements CaptchaCounterStore {
27
+ private readonly redis;
28
+ private readonly windowMs;
29
+ constructor(redis: Pick<Redis, 'mget' | 'eval' | 'del' | 'set'>, windowMs?: number);
30
+ private k;
31
+ counts(keys: readonly string[]): Promise<readonly number[]>;
32
+ bump(keys: readonly string[]): Promise<readonly number[]>;
33
+ clear(keys: readonly string[]): Promise<void>;
34
+ /**
35
+ * Remove keys and REJECT on a store error (auth capabilities R11.1: an admin unlock clears the
36
+ * account counters and must not report a success it did not achieve). Not on the port: only the
37
+ * unlocker uses it.
38
+ */
39
+ clearStrict(keys: readonly string[]): Promise<void>;
40
+ firstInWindow(key: string): Promise<boolean>;
41
+ }
42
+ /** Who/what an attempt is about. `ip` is set only when per-IP limiting is on. */
43
+ export interface CaptchaSubject {
44
+ readonly accountId?: string | null;
45
+ readonly tenantId?: string | null;
46
+ readonly typedText?: string | null;
47
+ readonly ip?: string | null;
48
+ }
49
+ /** The gate's verdict for one request. */
50
+ export type CaptchaVerdict = {
51
+ readonly kind: 'not_required';
52
+ } | {
53
+ readonly kind: 'passed';
54
+ } | {
55
+ readonly kind: 'fail_open';
56
+ } | {
57
+ readonly kind: 'failed';
58
+ };
59
+ /** What `GET /auth/login-options` publishes (never the secret). */
60
+ export interface CaptchaPublicOptions {
61
+ readonly provider: CaptchaProvider;
62
+ readonly siteKey: string;
63
+ readonly mode: CaptchaMode;
64
+ }
65
+ export interface CaptchaGateDeps {
66
+ readonly config: CaptchaConfig;
67
+ readonly verifier: CaptchaVerifier;
68
+ readonly counters: CaptchaCounterStore;
69
+ readonly auditSink?: AuditSink | null;
70
+ readonly logger?: {
71
+ log(message: unknown): void;
72
+ warn(message: string): void;
73
+ };
74
+ }
75
+ export declare class CaptchaGate {
76
+ private readonly deps;
77
+ private readonly logger;
78
+ constructor(deps: CaptchaGateDeps);
79
+ /** The public part of the config (provider, site key, mode). */
80
+ get publicOptions(): CaptchaPublicOptions;
81
+ /** True when this endpoint is protected (`CAPTCHA_ENDPOINTS`). */
82
+ covers(endpoint: CaptchaEndpoint): boolean;
83
+ /** True when the mode is `always` (every attempt is challenged). */
84
+ get always(): boolean;
85
+ private keys;
86
+ private overThreshold;
87
+ /** Is a challenge required now? A store error ⇒ `true` (fail closed). */
88
+ required(endpoint: CaptchaEndpoint, subject: CaptchaSubject): Promise<boolean>;
89
+ /**
90
+ * Decide and, when required, verify `token`. Call BEFORE any hash / code check. Never throws.
91
+ */
92
+ check(endpoint: CaptchaEndpoint, subject: CaptchaSubject, token: unknown, remoteIp?: string): Promise<CaptchaVerdict>;
93
+ /**
94
+ * Count one failure (login: wrong password; forgot: every request; reset: bad token). Returns
95
+ * whether the NEXT attempt needs a challenge (the failure body's `captcha: 'required'` flag). A
96
+ * store error ⇒ `true` (fail closed, consistent with {@link required}).
97
+ */
98
+ recordFailure(endpoint: CaptchaEndpoint, subject: CaptchaSubject): Promise<boolean>;
99
+ /** A success clears the account and typed-text counters (never the IP one). Best-effort. */
100
+ recordSuccess(endpoint: CaptchaEndpoint, subject: CaptchaSubject): Promise<void>;
101
+ private count;
102
+ }
103
+ //# sourceMappingURL=captcha-gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"captcha-gate.d.ts","sourceRoot":"","sources":["../../src/auth/captcha-gate.ts"],"names":[],"mappings":"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"}