@nodefony/security 10.0.0-alpha.1

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 (258) hide show
  1. package/LICENSE +544 -0
  2. package/README.md +182 -0
  3. package/dist/_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js +9 -0
  4. package/dist/_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorateMetadata.js +6 -0
  5. package/dist/index.js +151 -0
  6. package/dist/nodefony/command/security-secrets.js +158 -0
  7. package/dist/nodefony/command/security-token.js +335 -0
  8. package/dist/nodefony/command/security-user-add.js +131 -0
  9. package/dist/nodefony/command/security-user-delete.js +102 -0
  10. package/dist/nodefony/command/security-user-list.js +77 -0
  11. package/dist/nodefony/config/config.js +366 -0
  12. package/dist/nodefony/config/defineModuleConfig.js +35 -0
  13. package/dist/nodefony/contracts/IAccessVoter.js +13 -0
  14. package/dist/nodefony/contracts/IApiKey.js +1 -0
  15. package/dist/nodefony/contracts/IAuditEvent.js +1 -0
  16. package/dist/nodefony/contracts/IAuditStore.js +1 -0
  17. package/dist/nodefony/contracts/IAuthenticator.js +1 -0
  18. package/dist/nodefony/contracts/IAuthorizationService.js +1 -0
  19. package/dist/nodefony/contracts/IFirewall.js +1 -0
  20. package/dist/nodefony/contracts/IFirewallDescription.js +1 -0
  21. package/dist/nodefony/contracts/IJwtKeystore.js +1 -0
  22. package/dist/nodefony/contracts/IOAuthProvider.js +1 -0
  23. package/dist/nodefony/contracts/ISecuredArea.js +1 -0
  24. package/dist/nodefony/contracts/IToken.js +1 -0
  25. package/dist/nodefony/contracts/ITokenStore.js +1 -0
  26. package/dist/nodefony/contracts/ITotpSecret.js +1 -0
  27. package/dist/nodefony/contracts/ITotpSecretStore.js +1 -0
  28. package/dist/nodefony/contracts/IWebAuthnCredential.js +1 -0
  29. package/dist/nodefony/contracts/IWebAuthnCredentialStore.js +1 -0
  30. package/dist/nodefony/contracts/IWebhookEndpoint.js +1 -0
  31. package/dist/nodefony/contracts/IWebhookStore.js +1 -0
  32. package/dist/nodefony/contracts/index.js +2 -0
  33. package/dist/nodefony/errors/AccessDeniedError.js +14 -0
  34. package/dist/nodefony/errors/ApiKeyError.js +21 -0
  35. package/dist/nodefony/errors/AuthenticationError.js +14 -0
  36. package/dist/nodefony/errors/CsrfError.js +23 -0
  37. package/dist/nodefony/errors/InvalidTargetError.js +39 -0
  38. package/dist/nodefony/errors/SsrfError.js +17 -0
  39. package/dist/nodefony/errors/ThrottledError.js +21 -0
  40. package/dist/nodefony/errors/UnverifiableTokenError.js +42 -0
  41. package/dist/nodefony/errors/WebAuthnError.js +21 -0
  42. package/dist/nodefony/errors/index.js +9 -0
  43. package/dist/nodefony/service/accessTokenVerifier.js +77 -0
  44. package/dist/nodefony/service/apiKeys.js +310 -0
  45. package/dist/nodefony/service/auditService.js +145 -0
  46. package/dist/nodefony/service/authFlow.js +332 -0
  47. package/dist/nodefony/service/authorization.js +95 -0
  48. package/dist/nodefony/service/cors.js +81 -0
  49. package/dist/nodefony/service/csrf.js +97 -0
  50. package/dist/nodefony/service/firewall.js +699 -0
  51. package/dist/nodefony/service/oauth2.js +153 -0
  52. package/dist/nodefony/service/securityHeaders.js +80 -0
  53. package/dist/nodefony/service/tokenService.js +486 -0
  54. package/dist/nodefony/service/totp.js +209 -0
  55. package/dist/nodefony/service/webAuthn.js +343 -0
  56. package/dist/nodefony/service/webhooks.js +539 -0
  57. package/dist/nodefony/src/RoleHierarchyWalker.js +77 -0
  58. package/dist/nodefony/src/SecuredArea.js +51 -0
  59. package/dist/nodefony/src/admin/SecurityAdminApi.js +495 -0
  60. package/dist/nodefony/src/admin/WebhookAdminApi.js +378 -0
  61. package/dist/nodefony/src/admin/adminAudit.js +37 -0
  62. package/dist/nodefony/src/admin/userRevocationCascade.js +40 -0
  63. package/dist/nodefony/src/apikey/apiKeyFormat.js +107 -0
  64. package/dist/nodefony/src/audit/MemoryAuditStore.js +121 -0
  65. package/dist/nodefony/src/audit/auditBridge.js +82 -0
  66. package/dist/nodefony/src/audit/auditFilters.js +60 -0
  67. package/dist/nodefony/src/audit/auditStoreRegistry.js +25 -0
  68. package/dist/nodefony/src/audit/readAuditContext.js +24 -0
  69. package/dist/nodefony/src/audit/recordAudit.js +16 -0
  70. package/dist/nodefony/src/authenticator/AnonymousAuthenticator.js +36 -0
  71. package/dist/nodefony/src/authenticator/ApiKeyAuthenticator.js +164 -0
  72. package/dist/nodefony/src/authenticator/ExternalJwtAuthenticator.js +224 -0
  73. package/dist/nodefony/src/authenticator/FirewallRealtimeAuthenticator.js +174 -0
  74. package/dist/nodefony/src/authenticator/JwtAuthenticator.js +176 -0
  75. package/dist/nodefony/src/authenticator/SessionAuthenticator.js +92 -0
  76. package/dist/nodefony/src/authenticator/UserPasswordAuthenticator.js +95 -0
  77. package/dist/nodefony/src/authenticator/authenticatorRegistry.js +63 -0
  78. package/dist/nodefony/src/authenticator/bearer.js +2 -0
  79. package/dist/nodefony/src/authenticator/externalSubject.js +36 -0
  80. package/dist/nodefony/src/authenticator/peekIssuer.js +56 -0
  81. package/dist/nodefony/src/crypto/secretCipher.js +79 -0
  82. package/dist/nodefony/src/csp.js +54 -0
  83. package/dist/nodefony/src/csrfToken.js +65 -0
  84. package/dist/nodefony/src/net/ssrfGuard.js +130 -0
  85. package/dist/nodefony/src/oauth/oauthProviderRegistry.js +37 -0
  86. package/dist/nodefony/src/oauth/providers/github.js +65 -0
  87. package/dist/nodefony/src/oauth/providers/oidc.js +48 -0
  88. package/dist/nodefony/src/realtime/UserRealtimeToken.js +94 -0
  89. package/dist/nodefony/src/realtime/frameAuthorizer.js +279 -0
  90. package/dist/nodefony/src/realtime/realtimeContracts.js +1 -0
  91. package/dist/nodefony/src/sessionIdentity.js +35 -0
  92. package/dist/nodefony/src/throttle/LoginThrottler.js +97 -0
  93. package/dist/nodefony/src/token/AnonymousToken.js +40 -0
  94. package/dist/nodefony/src/token/JwtKeystore.js +160 -0
  95. package/dist/nodefony/src/token/MemoryTokenStore.js +236 -0
  96. package/dist/nodefony/src/token/RemoteJwtVerifier.js +231 -0
  97. package/dist/nodefony/src/token/UserToken.js +67 -0
  98. package/dist/nodefony/src/token/jwtRuntime.js +19 -0
  99. package/dist/nodefony/src/token/secretFile.js +134 -0
  100. package/dist/nodefony/src/token/tokenCriteria.js +35 -0
  101. package/dist/nodefony/src/token/tokenFilters.js +72 -0
  102. package/dist/nodefony/src/token/tokenSort.js +40 -0
  103. package/dist/nodefony/src/token/tokenStatus.js +35 -0
  104. package/dist/nodefony/src/token/tokenStoreRegistry.js +25 -0
  105. package/dist/nodefony/src/totp/MemoryTotpSecretStore.js +97 -0
  106. package/dist/nodefony/src/totp/totpCipher.js +30 -0
  107. package/dist/nodefony/src/totp/totpCrypto.js +226 -0
  108. package/dist/nodefony/src/totp/totpOperations.js +129 -0
  109. package/dist/nodefony/src/totp/totpSecretStoreRegistry.js +18 -0
  110. package/dist/nodefony/src/voter/RoleVoter.js +32 -0
  111. package/dist/nodefony/src/voter/ScopeVoter.js +52 -0
  112. package/dist/nodefony/src/voter/voterRegistry.js +20 -0
  113. package/dist/nodefony/src/webauthn/MemoryWebAuthnCredentialStore.js +121 -0
  114. package/dist/nodefony/src/webauthn/webAuthnCredentialStoreRegistry.js +18 -0
  115. package/dist/nodefony/src/webhook/MemoryWebhookStore.js +87 -0
  116. package/dist/nodefony/src/webhook/WebhookDispatcher.js +208 -0
  117. package/dist/nodefony/src/webhook/webhookCipher.js +27 -0
  118. package/dist/nodefony/src/webhook/webhookDelivery.js +102 -0
  119. package/dist/nodefony/src/webhook/webhookFilters.js +56 -0
  120. package/dist/nodefony/src/webhook/webhookSignature.js +51 -0
  121. package/dist/nodefony/src/webhook/webhookSort.js +48 -0
  122. package/dist/nodefony/src/webhook/webhookStoreRegistry.js +18 -0
  123. package/dist/types/index.d.ts +157 -0
  124. package/dist/types/nodefony/command/security-secrets.d.ts +24 -0
  125. package/dist/types/nodefony/command/security-token.d.ts +44 -0
  126. package/dist/types/nodefony/command/security-user-add.d.ts +28 -0
  127. package/dist/types/nodefony/command/security-user-delete.d.ts +25 -0
  128. package/dist/types/nodefony/command/security-user-list.d.ts +28 -0
  129. package/dist/types/nodefony/config/config.d.ts +295 -0
  130. package/dist/types/nodefony/config/defineModuleConfig.d.ts +27 -0
  131. package/dist/types/nodefony/contracts/IAccessVoter.d.ts +23 -0
  132. package/dist/types/nodefony/contracts/IApiKey.d.ts +75 -0
  133. package/dist/types/nodefony/contracts/IAuditEvent.d.ts +94 -0
  134. package/dist/types/nodefony/contracts/IAuditStore.d.ts +80 -0
  135. package/dist/types/nodefony/contracts/IAuthenticator.d.ts +66 -0
  136. package/dist/types/nodefony/contracts/IAuthorizationService.d.ts +28 -0
  137. package/dist/types/nodefony/contracts/IFirewall.d.ts +64 -0
  138. package/dist/types/nodefony/contracts/IFirewallDescription.d.ts +120 -0
  139. package/dist/types/nodefony/contracts/IJwtKeystore.d.ts +40 -0
  140. package/dist/types/nodefony/contracts/IOAuthProvider.d.ts +51 -0
  141. package/dist/types/nodefony/contracts/ISecuredArea.d.ts +57 -0
  142. package/dist/types/nodefony/contracts/IToken.d.ts +41 -0
  143. package/dist/types/nodefony/contracts/ITokenStore.d.ts +240 -0
  144. package/dist/types/nodefony/contracts/ITotpSecret.d.ts +41 -0
  145. package/dist/types/nodefony/contracts/ITotpSecretStore.d.ts +88 -0
  146. package/dist/types/nodefony/contracts/IWebAuthnCredential.d.ts +56 -0
  147. package/dist/types/nodefony/contracts/IWebAuthnCredentialStore.d.ts +118 -0
  148. package/dist/types/nodefony/contracts/IWebhookEndpoint.d.ts +82 -0
  149. package/dist/types/nodefony/contracts/IWebhookStore.d.ts +85 -0
  150. package/dist/types/nodefony/contracts/index.d.ts +9 -0
  151. package/dist/types/nodefony/errors/AccessDeniedError.d.ts +10 -0
  152. package/dist/types/nodefony/errors/ApiKeyError.d.ts +17 -0
  153. package/dist/types/nodefony/errors/AuthenticationError.d.ts +10 -0
  154. package/dist/types/nodefony/errors/CsrfError.d.ts +19 -0
  155. package/dist/types/nodefony/errors/InvalidTargetError.d.ts +34 -0
  156. package/dist/types/nodefony/errors/SsrfError.d.ts +13 -0
  157. package/dist/types/nodefony/errors/ThrottledError.d.ts +16 -0
  158. package/dist/types/nodefony/errors/UnverifiableTokenError.d.ts +37 -0
  159. package/dist/types/nodefony/errors/WebAuthnError.d.ts +17 -0
  160. package/dist/types/nodefony/errors/index.d.ts +8 -0
  161. package/dist/types/nodefony/service/accessTokenVerifier.d.ts +29 -0
  162. package/dist/types/nodefony/service/apiKeys.d.ts +103 -0
  163. package/dist/types/nodefony/service/auditService.d.ts +30 -0
  164. package/dist/types/nodefony/service/authFlow.d.ts +123 -0
  165. package/dist/types/nodefony/service/authorization.d.ts +33 -0
  166. package/dist/types/nodefony/service/cors.d.ts +48 -0
  167. package/dist/types/nodefony/service/csrf.d.ts +57 -0
  168. package/dist/types/nodefony/service/firewall.d.ts +148 -0
  169. package/dist/types/nodefony/service/oauth2.d.ts +66 -0
  170. package/dist/types/nodefony/service/securityHeaders.d.ts +66 -0
  171. package/dist/types/nodefony/service/tokenService.d.ts +103 -0
  172. package/dist/types/nodefony/service/totp.d.ts +58 -0
  173. package/dist/types/nodefony/service/webAuthn.d.ts +123 -0
  174. package/dist/types/nodefony/service/webhooks.d.ts +160 -0
  175. package/dist/types/nodefony/src/RoleHierarchyWalker.d.ts +21 -0
  176. package/dist/types/nodefony/src/SecuredArea.d.ts +31 -0
  177. package/dist/types/nodefony/src/admin/SecurityAdminApi.d.ts +82 -0
  178. package/dist/types/nodefony/src/admin/WebhookAdminApi.d.ts +30 -0
  179. package/dist/types/nodefony/src/admin/adminAudit.d.ts +27 -0
  180. package/dist/types/nodefony/src/admin/userRevocationCascade.d.ts +31 -0
  181. package/dist/types/nodefony/src/apikey/apiKeyFormat.d.ts +43 -0
  182. package/dist/types/nodefony/src/audit/MemoryAuditStore.d.ts +33 -0
  183. package/dist/types/nodefony/src/audit/auditBridge.d.ts +49 -0
  184. package/dist/types/nodefony/src/audit/auditFilters.d.ts +56 -0
  185. package/dist/types/nodefony/src/audit/auditStoreRegistry.d.ts +37 -0
  186. package/dist/types/nodefony/src/audit/readAuditContext.d.ts +17 -0
  187. package/dist/types/nodefony/src/audit/recordAudit.d.ts +13 -0
  188. package/dist/types/nodefony/src/authenticator/AnonymousAuthenticator.d.ts +26 -0
  189. package/dist/types/nodefony/src/authenticator/ApiKeyAuthenticator.d.ts +74 -0
  190. package/dist/types/nodefony/src/authenticator/ExternalJwtAuthenticator.d.ts +132 -0
  191. package/dist/types/nodefony/src/authenticator/FirewallRealtimeAuthenticator.d.ts +78 -0
  192. package/dist/types/nodefony/src/authenticator/JwtAuthenticator.d.ts +69 -0
  193. package/dist/types/nodefony/src/authenticator/SessionAuthenticator.d.ts +70 -0
  194. package/dist/types/nodefony/src/authenticator/UserPasswordAuthenticator.d.ts +53 -0
  195. package/dist/types/nodefony/src/authenticator/authenticatorRegistry.d.ts +39 -0
  196. package/dist/types/nodefony/src/authenticator/bearer.d.ts +22 -0
  197. package/dist/types/nodefony/src/authenticator/externalSubject.d.ts +27 -0
  198. package/dist/types/nodefony/src/authenticator/peekIssuer.d.ts +31 -0
  199. package/dist/types/nodefony/src/crypto/secretCipher.d.ts +31 -0
  200. package/dist/types/nodefony/src/csp.d.ts +39 -0
  201. package/dist/types/nodefony/src/csrfToken.d.ts +36 -0
  202. package/dist/types/nodefony/src/net/ssrfGuard.d.ts +43 -0
  203. package/dist/types/nodefony/src/oauth/oauthProviderRegistry.d.ts +45 -0
  204. package/dist/types/nodefony/src/oauth/providers/github.d.ts +9 -0
  205. package/dist/types/nodefony/src/oauth/providers/oidc.d.ts +35 -0
  206. package/dist/types/nodefony/src/realtime/UserRealtimeToken.d.ts +62 -0
  207. package/dist/types/nodefony/src/realtime/frameAuthorizer.d.ts +171 -0
  208. package/dist/types/nodefony/src/realtime/realtimeContracts.d.ts +139 -0
  209. package/dist/types/nodefony/src/sessionIdentity.d.ts +20 -0
  210. package/dist/types/nodefony/src/throttle/LoginThrottler.d.ts +68 -0
  211. package/dist/types/nodefony/src/token/AnonymousToken.d.ts +23 -0
  212. package/dist/types/nodefony/src/token/JwtKeystore.d.ts +43 -0
  213. package/dist/types/nodefony/src/token/MemoryTokenStore.d.ts +66 -0
  214. package/dist/types/nodefony/src/token/RemoteJwtVerifier.d.ts +149 -0
  215. package/dist/types/nodefony/src/token/UserToken.d.ts +41 -0
  216. package/dist/types/nodefony/src/token/jwtRuntime.d.ts +28 -0
  217. package/dist/types/nodefony/src/token/secretFile.d.ts +70 -0
  218. package/dist/types/nodefony/src/token/tokenCriteria.d.ts +20 -0
  219. package/dist/types/nodefony/src/token/tokenFilters.d.ts +76 -0
  220. package/dist/types/nodefony/src/token/tokenSort.d.ts +33 -0
  221. package/dist/types/nodefony/src/token/tokenStatus.d.ts +38 -0
  222. package/dist/types/nodefony/src/token/tokenStoreRegistry.d.ts +38 -0
  223. package/dist/types/nodefony/src/totp/MemoryTotpSecretStore.d.ts +43 -0
  224. package/dist/types/nodefony/src/totp/totpCipher.d.ts +9 -0
  225. package/dist/types/nodefony/src/totp/totpCrypto.d.ts +164 -0
  226. package/dist/types/nodefony/src/totp/totpOperations.d.ts +73 -0
  227. package/dist/types/nodefony/src/totp/totpSecretStoreRegistry.d.ts +27 -0
  228. package/dist/types/nodefony/src/voter/RoleVoter.d.ts +25 -0
  229. package/dist/types/nodefony/src/voter/ScopeVoter.d.ts +30 -0
  230. package/dist/types/nodefony/src/voter/voterRegistry.d.ts +33 -0
  231. package/dist/types/nodefony/src/webauthn/MemoryWebAuthnCredentialStore.d.ts +39 -0
  232. package/dist/types/nodefony/src/webauthn/webAuthnCredentialStoreRegistry.d.ts +26 -0
  233. package/dist/types/nodefony/src/webhook/MemoryWebhookStore.d.ts +37 -0
  234. package/dist/types/nodefony/src/webhook/WebhookDispatcher.d.ts +69 -0
  235. package/dist/types/nodefony/src/webhook/webhookCipher.d.ts +8 -0
  236. package/dist/types/nodefony/src/webhook/webhookDelivery.d.ts +28 -0
  237. package/dist/types/nodefony/src/webhook/webhookFilters.d.ts +64 -0
  238. package/dist/types/nodefony/src/webhook/webhookSignature.d.ts +20 -0
  239. package/dist/types/nodefony/src/webhook/webhookSort.d.ts +39 -0
  240. package/dist/types/nodefony/src/webhook/webhookStoreRegistry.d.ts +31 -0
  241. package/docs/api-keys.md +691 -0
  242. package/docs/audit.md +751 -0
  243. package/docs/authenticators.md +487 -0
  244. package/docs/authorization.md +497 -0
  245. package/docs/cors.md +497 -0
  246. package/docs/csrf.md +392 -0
  247. package/docs/external-jwt.md +181 -0
  248. package/docs/firewall.md +546 -0
  249. package/docs/headers.md +616 -0
  250. package/docs/index.md +207 -0
  251. package/docs/lexique.md +190 -0
  252. package/docs/oauth2.md +575 -0
  253. package/docs/obtenir-un-jeton.md +225 -0
  254. package/docs/tokens.md +520 -0
  255. package/docs/totp.md +804 -0
  256. package/docs/webauthn.md +733 -0
  257. package/docs/webhooks.md +1016 -0
  258. package/package.json +83 -0
@@ -0,0 +1,295 @@
1
+ import { z } from "zod";
2
+ declare const areaSchema: z.ZodObject<{
3
+ pattern: z.ZodString;
4
+ security: z.ZodDefault<z.ZodBoolean>;
5
+ stateless: z.ZodDefault<z.ZodBoolean>;
6
+ mode: z.ZodDefault<z.ZodEnum<{
7
+ all: "all";
8
+ first: "first";
9
+ }>>;
10
+ authenticators: z.ZodDefault<z.ZodArray<z.ZodString>>;
11
+ entryPoint: z.ZodOptional<z.ZodString>;
12
+ host: z.ZodOptional<z.ZodString>;
13
+ resource: z.ZodOptional<z.ZodString>;
14
+ realtime: z.ZodDefault<z.ZodBoolean>;
15
+ }, z.core.$strict>;
16
+ export declare const securityConfigSchema: z.ZodObject<{
17
+ encoders: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
18
+ type: z.ZodDefault<z.ZodEnum<{
19
+ argon2id: "argon2id";
20
+ bcrypt: "bcrypt";
21
+ }>>;
22
+ memoryKiB: z.ZodDefault<z.ZodNumber>;
23
+ timeCost: z.ZodDefault<z.ZodNumber>;
24
+ parallelism: z.ZodDefault<z.ZodNumber>;
25
+ rounds: z.ZodDefault<z.ZodNumber>;
26
+ }, z.core.$strict>>>;
27
+ roleHierarchy: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>>;
28
+ areas: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
29
+ pattern: z.ZodString;
30
+ security: z.ZodDefault<z.ZodBoolean>;
31
+ stateless: z.ZodDefault<z.ZodBoolean>;
32
+ mode: z.ZodDefault<z.ZodEnum<{
33
+ all: "all";
34
+ first: "first";
35
+ }>>;
36
+ authenticators: z.ZodDefault<z.ZodArray<z.ZodString>>;
37
+ entryPoint: z.ZodOptional<z.ZodString>;
38
+ host: z.ZodOptional<z.ZodString>;
39
+ resource: z.ZodOptional<z.ZodString>;
40
+ realtime: z.ZodDefault<z.ZodBoolean>;
41
+ }, z.core.$strict>>>;
42
+ realtimeChannels: z.ZodDefault<z.ZodArray<z.ZodObject<{
43
+ pattern: z.ZodString;
44
+ authenticated: z.ZodOptional<z.ZodBoolean>;
45
+ roles: z.ZodOptional<z.ZodArray<z.ZodString>>;
46
+ scopes: z.ZodOptional<z.ZodArray<z.ZodString>>;
47
+ }, z.core.$strict>>>;
48
+ cors: z.ZodDefault<z.ZodObject<{
49
+ enabled: z.ZodDefault<z.ZodBoolean>;
50
+ origins: z.ZodDefault<z.ZodArray<z.ZodString>>;
51
+ credentials: z.ZodDefault<z.ZodBoolean>;
52
+ methods: z.ZodDefault<z.ZodArray<z.ZodString>>;
53
+ allowedHeaders: z.ZodDefault<z.ZodArray<z.ZodString>>;
54
+ exposedHeaders: z.ZodDefault<z.ZodArray<z.ZodString>>;
55
+ maxAgeS: z.ZodDefault<z.ZodNumber>;
56
+ }, z.core.$strict>>;
57
+ csrf: z.ZodDefault<z.ZodObject<{
58
+ enabled: z.ZodDefault<z.ZodBoolean>;
59
+ fetchMetadata: z.ZodDefault<z.ZodBoolean>;
60
+ sameSite: z.ZodDefault<z.ZodEnum<{
61
+ Lax: "Lax";
62
+ None: "None";
63
+ Strict: "Strict";
64
+ }>>;
65
+ checkOrigin: z.ZodDefault<z.ZodBoolean>;
66
+ strictSameSite: z.ZodDefault<z.ZodBoolean>;
67
+ trustedOrigins: z.ZodDefault<z.ZodArray<z.ZodString>>;
68
+ secret: z.ZodOptional<z.ZodString>;
69
+ }, z.core.$strict>>;
70
+ headers: z.ZodDefault<z.ZodObject<{
71
+ enabled: z.ZodDefault<z.ZodBoolean>;
72
+ hsts: z.ZodDefault<z.ZodBoolean>;
73
+ hstsMaxAgeS: z.ZodDefault<z.ZodNumber>;
74
+ csp: z.ZodDefault<z.ZodString>;
75
+ cspNonces: z.ZodDefault<z.ZodBoolean>;
76
+ frameguard: z.ZodDefault<z.ZodEnum<{
77
+ deny: "deny";
78
+ sameorigin: "sameorigin";
79
+ }>>;
80
+ noSniff: z.ZodDefault<z.ZodBoolean>;
81
+ referrerPolicy: z.ZodDefault<z.ZodEnum<{
82
+ "no-referrer": "no-referrer";
83
+ "no-referrer-when-downgrade": "no-referrer-when-downgrade";
84
+ origin: "origin";
85
+ "origin-when-cross-origin": "origin-when-cross-origin";
86
+ "same-origin": "same-origin";
87
+ "strict-origin": "strict-origin";
88
+ "strict-origin-when-cross-origin": "strict-origin-when-cross-origin";
89
+ "unsafe-url": "unsafe-url";
90
+ }>>;
91
+ hidePoweredBy: z.ZodDefault<z.ZodBoolean>;
92
+ coop: z.ZodOptional<z.ZodEnum<{
93
+ "same-origin": "same-origin";
94
+ "same-origin-allow-popups": "same-origin-allow-popups";
95
+ "unsafe-none": "unsafe-none";
96
+ }>>;
97
+ coep: z.ZodOptional<z.ZodEnum<{
98
+ credentialless: "credentialless";
99
+ "require-corp": "require-corp";
100
+ "unsafe-none": "unsafe-none";
101
+ }>>;
102
+ corp: z.ZodOptional<z.ZodEnum<{
103
+ "cross-origin": "cross-origin";
104
+ "same-origin": "same-origin";
105
+ "same-site": "same-site";
106
+ }>>;
107
+ originAgentCluster: z.ZodOptional<z.ZodBoolean>;
108
+ permissionsPolicy: z.ZodOptional<z.ZodString>;
109
+ }, z.core.$strict>>;
110
+ rateLimit: z.ZodDefault<z.ZodObject<{
111
+ enabled: z.ZodDefault<z.ZodBoolean>;
112
+ freeAttempts: z.ZodDefault<z.ZodNumber>;
113
+ baseDelayS: z.ZodDefault<z.ZodNumber>;
114
+ capDelayS: z.ZodDefault<z.ZodNumber>;
115
+ maxTracked: z.ZodDefault<z.ZodNumber>;
116
+ }, z.core.$strict>>;
117
+ jwt: z.ZodDefault<z.ZodObject<{
118
+ enabled: z.ZodDefault<z.ZodBoolean>;
119
+ alg: z.ZodDefault<z.ZodEnum<{
120
+ EdDSA: "EdDSA";
121
+ RS256: "RS256";
122
+ }>>;
123
+ accessTtlS: z.ZodDefault<z.ZodNumber>;
124
+ refreshTtlS: z.ZodDefault<z.ZodNumber>;
125
+ rotateRefresh: z.ZodDefault<z.ZodBoolean>;
126
+ jwks: z.ZodDefault<z.ZodBoolean>;
127
+ audiences: z.ZodDefault<z.ZodArray<z.ZodString>>;
128
+ issuer: z.ZodOptional<z.ZodString>;
129
+ keystore: z.ZodDefault<z.ZodObject<{
130
+ keySetJson: z.ZodOptional<z.ZodString>;
131
+ dir: z.ZodOptional<z.ZodString>;
132
+ }, z.core.$strict>>;
133
+ }, z.core.$strict>>;
134
+ tokenStore: z.ZodDefault<z.ZodObject<{
135
+ store: z.ZodDefault<z.ZodString>;
136
+ gcIntervalS: z.ZodDefault<z.ZodNumber>;
137
+ gcJitter: z.ZodDefault<z.ZodBoolean>;
138
+ retentionRevokedDays: z.ZodDefault<z.ZodNumber>;
139
+ }, z.core.$strict>>;
140
+ passkeys: z.ZodDefault<z.ZodObject<{
141
+ enabled: z.ZodDefault<z.ZodBoolean>;
142
+ rpId: z.ZodOptional<z.ZodString>;
143
+ rpName: z.ZodOptional<z.ZodString>;
144
+ origins: z.ZodDefault<z.ZodArray<z.ZodString>>;
145
+ userVerification: z.ZodDefault<z.ZodEnum<{
146
+ discouraged: "discouraged";
147
+ preferred: "preferred";
148
+ required: "required";
149
+ }>>;
150
+ residentKey: z.ZodDefault<z.ZodEnum<{
151
+ discouraged: "discouraged";
152
+ preferred: "preferred";
153
+ required: "required";
154
+ }>>;
155
+ authenticatorAttachment: z.ZodDefault<z.ZodEnum<{
156
+ any: "any";
157
+ "cross-platform": "cross-platform";
158
+ platform: "platform";
159
+ }>>;
160
+ attestation: z.ZodDefault<z.ZodEnum<{
161
+ direct: "direct";
162
+ enterprise: "enterprise";
163
+ none: "none";
164
+ }>>;
165
+ timeoutMs: z.ZodDefault<z.ZodNumber>;
166
+ maxPerUser: z.ZodDefault<z.ZodNumber>;
167
+ challengeTtlS: z.ZodDefault<z.ZodNumber>;
168
+ store: z.ZodDefault<z.ZodString>;
169
+ }, z.core.$strict>>;
170
+ totp: z.ZodDefault<z.ZodObject<{
171
+ enabled: z.ZodDefault<z.ZodBoolean>;
172
+ issuer: z.ZodOptional<z.ZodString>;
173
+ algorithm: z.ZodDefault<z.ZodEnum<{
174
+ SHA1: "SHA1";
175
+ SHA256: "SHA256";
176
+ SHA512: "SHA512";
177
+ }>>;
178
+ digits: z.ZodDefault<z.ZodNumber>;
179
+ period: z.ZodDefault<z.ZodNumber>;
180
+ window: z.ZodDefault<z.ZodNumber>;
181
+ recoveryCodes: z.ZodDefault<z.ZodNumber>;
182
+ encryptionKey: z.ZodOptional<z.ZodString>;
183
+ store: z.ZodDefault<z.ZodString>;
184
+ }, z.core.$strict>>;
185
+ resourceServer: z.ZodDefault<z.ZodObject<{
186
+ issuers: z.ZodDefault<z.ZodArray<z.ZodObject<{
187
+ issuer: z.ZodString;
188
+ jwksUri: z.ZodOptional<z.ZodString>;
189
+ algorithms: z.ZodDefault<z.ZodArray<z.ZodEnum<{
190
+ ES256: "ES256";
191
+ ES384: "ES384";
192
+ ES512: "ES512";
193
+ Ed25519: "Ed25519";
194
+ EdDSA: "EdDSA";
195
+ PS256: "PS256";
196
+ PS384: "PS384";
197
+ PS512: "PS512";
198
+ RS256: "RS256";
199
+ RS384: "RS384";
200
+ RS512: "RS512";
201
+ }>>>;
202
+ typ: z.ZodOptional<z.ZodString>;
203
+ requiredClaims: z.ZodDefault<z.ZodArray<z.ZodString>>;
204
+ subjectMapping: z.ZodDefault<z.ZodEnum<{
205
+ prefixed: "prefixed";
206
+ subject: "subject";
207
+ }>>;
208
+ }, z.core.$strict>>>;
209
+ subjectPolicy: z.ZodDefault<z.ZodEnum<{
210
+ ephemeral: "ephemeral";
211
+ require: "require";
212
+ }>>;
213
+ ephemeralRoles: z.ZodDefault<z.ZodArray<z.ZodString>>;
214
+ timeoutMs: z.ZodDefault<z.ZodNumber>;
215
+ cooldownMs: z.ZodDefault<z.ZodNumber>;
216
+ cacheMaxAgeMs: z.ZodDefault<z.ZodNumber>;
217
+ clockToleranceS: z.ZodDefault<z.ZodNumber>;
218
+ }, z.core.$strict>>;
219
+ tokenExchange: z.ZodDefault<z.ZodObject<{
220
+ enabled: z.ZodDefault<z.ZodBoolean>;
221
+ }, z.core.$strict>>;
222
+ oauth2: z.ZodDefault<z.ZodObject<{
223
+ enabled: z.ZodDefault<z.ZodBoolean>;
224
+ defaultRoles: z.ZodDefault<z.ZodArray<z.ZodString>>;
225
+ allowSignup: z.ZodDefault<z.ZodBoolean>;
226
+ successRedirect: z.ZodDefault<z.ZodString>;
227
+ failureRedirect: z.ZodDefault<z.ZodString>;
228
+ providers: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
229
+ clientId: z.ZodString;
230
+ clientSecret: z.ZodString;
231
+ redirectUri: z.ZodString;
232
+ issuer: z.ZodOptional<z.ZodString>;
233
+ scopes: z.ZodDefault<z.ZodArray<z.ZodString>>;
234
+ successRedirect: z.ZodOptional<z.ZodString>;
235
+ failureRedirect: z.ZodOptional<z.ZodString>;
236
+ defaultRoles: z.ZodOptional<z.ZodArray<z.ZodString>>;
237
+ }, z.core.$strict>>>;
238
+ }, z.core.$strict>>;
239
+ apiKeys: z.ZodDefault<z.ZodObject<{
240
+ enabled: z.ZodDefault<z.ZodBoolean>;
241
+ prefix: z.ZodDefault<z.ZodString>;
242
+ defaultExpiryDays: z.ZodDefault<z.ZodNullable<z.ZodNumber>>;
243
+ lastUsedThrottleS: z.ZodDefault<z.ZodNumber>;
244
+ maxPerSubject: z.ZodDefault<z.ZodNumber>;
245
+ allowedScopes: z.ZodDefault<z.ZodNullable<z.ZodArray<z.ZodString>>>;
246
+ }, z.core.$strict>>;
247
+ webhooks: z.ZodDefault<z.ZodObject<{
248
+ enabled: z.ZodDefault<z.ZodBoolean>;
249
+ signAlg: z.ZodDefault<z.ZodEnum<{
250
+ sha256: "sha256";
251
+ }>>;
252
+ timestampToleranceS: z.ZodDefault<z.ZodNumber>;
253
+ denyPrivateIps: z.ZodDefault<z.ZodBoolean>;
254
+ snapshotTtlS: z.ZodDefault<z.ZodNumber>;
255
+ maxRetries: z.ZodDefault<z.ZodNumber>;
256
+ autoDisableThreshold: z.ZodDefault<z.ZodNumber>;
257
+ deliveryTimeoutMs: z.ZodDefault<z.ZodNumber>;
258
+ maxConcurrent: z.ZodDefault<z.ZodNumber>;
259
+ maxQueue: z.ZodDefault<z.ZodNumber>;
260
+ allowHttp: z.ZodDefault<z.ZodBoolean>;
261
+ store: z.ZodDefault<z.ZodString>;
262
+ encryptionKey: z.ZodOptional<z.ZodString>;
263
+ }, z.core.$strict>>;
264
+ audit: z.ZodDefault<z.ZodObject<{
265
+ enabled: z.ZodDefault<z.ZodBoolean>;
266
+ store: z.ZodDefault<z.ZodString>;
267
+ immutable: z.ZodDefault<z.ZodBoolean>;
268
+ stream: z.ZodDefault<z.ZodBoolean>;
269
+ retentionDays: z.ZodDefault<z.ZodNumber>;
270
+ }, z.core.$strict>>;
271
+ studio: z.ZodDefault<z.ZodObject<{
272
+ enabled: z.ZodDefault<z.ZodBoolean>;
273
+ exposure: z.ZodDefault<z.ZodEnum<{
274
+ localhost: "localhost";
275
+ private: "private";
276
+ public: "public";
277
+ }>>;
278
+ allowedIps: z.ZodDefault<z.ZodArray<z.ZodString>>;
279
+ requireMfa: z.ZodDefault<z.ZodBoolean>;
280
+ auditAllActions: z.ZodDefault<z.ZodBoolean>;
281
+ }, z.core.$strict>>;
282
+ }, z.core.$strict>;
283
+ /** Entrée du builder (champs avec défaut optionnels). */
284
+ export type ISecurityConfigInput = z.input<typeof securityConfigSchema>;
285
+ /** Config normalisée et gelée (sortie du builder, lue par le firewall). */
286
+ export type ISecurityConfig = z.output<typeof securityConfigSchema>;
287
+ /** Config d'une zone normalisée. */
288
+ export type ISecurityAreaConfig = z.output<typeof areaSchema>;
289
+ /**
290
+ * Défauts du module, matérialisés depuis le schéma (source unique — tous les
291
+ * `.default()` : Zero Trust, CORS strict, Studio OFF). Toujours valides par
292
+ * construction ; passés au `super(..., config)` du Module class.
293
+ */
294
+ declare const config: ISecurityConfig;
295
+ export default config;
@@ -0,0 +1,27 @@
1
+ import type { ISecurityConfig, ISecurityConfigInput } from "./config.js";
2
+ /**
3
+ * Builder type-safe de la configuration de sécurité Nodefony (PUR — ne retape
4
+ * JAMAIS un défaut : source unique = `./config.ts`, le schéma Zod commenté).
5
+ *
6
+ * ⭐ TL;DR : MACHINERIE DE BOOT — on n'édite (presque) jamais ce fichier. Même
7
+ * pattern que `nodefony.config.ts` ↔ `defineConfig()` du core : `config.ts` PORTE
8
+ * la config (schéma + défauts), `define<X>Config()` la VALIDE au boot (parse +
9
+ * env + freeze) et publie le JSON Schema Studio.
10
+ *
11
+ * Valide + normalise + gèle ; conflits de patterns de zones détectés au boot.
12
+ */
13
+ export type { ISecurityConfig, ISecurityConfigInput, ISecurityAreaConfig, } from "./config.js";
14
+ /**
15
+ * Valide + normalise + gèle la configuration de sécurité.
16
+ *
17
+ * @param config - configuration brute de l'app (sections omises = défauts sûrs).
18
+ * @returns config gelée prête pour le firewall.
19
+ * @throws ZodError si invalide ; Error si deux zones partagent un pattern.
20
+ */
21
+ export declare function defineSecurityConfig(config?: ISecurityConfigInput): ISecurityConfig;
22
+ /**
23
+ * JSON Schema introspectable de la config sécurité — **Studio génère son
24
+ * formulaire d'édition depuis ça** (labels/types/défauts/descriptions),
25
+ * sans UI hardcodée. Surface du data plane `/nodefony/security/api/config/schema`.
26
+ */
27
+ export declare function securityConfigJsonSchema(): unknown;
@@ -0,0 +1,23 @@
1
+ import type { IToken } from "./IToken.js";
2
+ /**
3
+ * Vote d'un {@link IAccessVoter}. Stratégie firewall = affirmative + DENY veto :
4
+ * un seul DENY bloque ; sinon un GRANT suffit ; tous ABSTAIN → DENY (Zero Trust).
5
+ */
6
+ export declare enum VoterVote {
7
+ GRANT = "GRANT",
8
+ DENY = "DENY",
9
+ ABSTAIN = "ABSTAIN"
10
+ }
11
+ /**
12
+ * Voter contextuel (niveau C de l'autorisation, P6.8) — décide d'un accès en
13
+ * fonction du token ET du sujet (ex. « cet user édite-t-il SON projet ? »).
14
+ *
15
+ * Découverts par DI au boot (`@injectable`), indexés par `supports()`. Killer
16
+ * feature pour le métier complexe (multi-tenant, ownership).
17
+ */
18
+ export interface IAccessVoter {
19
+ /** Ce voter sait-il décider de cet attribut/sujet ? */
20
+ supports(attribute: string, subject?: unknown): boolean;
21
+ /** Vote pour l'attribut donné sur le sujet donné. */
22
+ vote(token: IToken, attribute: string, subject?: unknown): Promise<VoterVote>;
23
+ }
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Vue **publique** d'une clé API (PAT) — projection de `IAccessTokenRecord`
3
+ * **sans le secret ni son hash** (jamais exposés après création). C'est la forme
4
+ * renvoyée par la console (« mes clés ») et le data plane Studio.
5
+ */
6
+ export interface IApiKeyView {
7
+ /** Identifiant public de la clé (révocation, affichage). */
8
+ id: string;
9
+ /** Préfixe public affichable (`<prefix>_<pubid>`, ex. `nf_a1b2c3d4`). */
10
+ prefix: string | null;
11
+ /** Libellé humain (« CI deploy », « app mobile »). */
12
+ name: string;
13
+ /** Capacités accordées (axe distinct des rôles RBAC). */
14
+ scopes: string[];
15
+ /** Porteur (id utilisateur ou service account). */
16
+ subjectId: string;
17
+ /** Discriminant du porteur. */
18
+ subjectType: "user" | "service";
19
+ /** Organisation/tenant (`null` = global). */
20
+ tenantId: string | null;
21
+ /** Création (epoch ms). */
22
+ createdAt: number;
23
+ /** Expiration (epoch ms) ou `null` (sans expiration). */
24
+ expiresAt: number | null;
25
+ /** Dernier usage (epoch ms) ou `null` (jamais utilisée). */
26
+ lastUsedAt: number | null;
27
+ /**
28
+ * Adresse du dernier usage, ou `null`. C'est ce qui permet à un porteur de
29
+ * reconnaître une clé qui a servi ailleurs que là où il l'a déployée — donc de
30
+ * dater une fuite. Dépouillée de `X-Forwarded-For` selon `trustProxy`.
31
+ */
32
+ lastUsedIp: string | null;
33
+ /** Agent du dernier usage, ou `null` (même usage : reconnaître l'inattendu). */
34
+ lastUsedUserAgent: string | null;
35
+ /** Révocation (epoch ms) ou `null` (active). */
36
+ revokedAt: number | null;
37
+ }
38
+ /**
39
+ * Résultat d'une **création** de clé — la vue publique **+ le token en clair**.
40
+ * Le `token` n'est disponible qu'ICI, une seule fois : il n'est jamais stocké
41
+ * (seul son `sha256` l'est) ni re-dérivable. La console l'affiche puis l'oublie.
42
+ */
43
+ export interface IApiKeyCreated extends IApiKeyView {
44
+ /** Secret EN CLAIR — affiché UNE seule fois (RFC : « shown once »). */
45
+ token: string;
46
+ }
47
+ /**
48
+ * Capacités/contraintes d'émission des clés API — exposées à la console (« Mes
49
+ * clés ») pour un formulaire de création **honnête** : plafond par porteur,
50
+ * catalogue de scopes, préfixe public, durée par défaut. **Aucune valeur
51
+ * sensible** (config publique : le préfixe figure déjà dans chaque clé).
52
+ */
53
+ export interface IApiKeyCapabilities {
54
+ /** Émission de clés activée en config (`apiKeys.enabled`). */
55
+ enabled: boolean;
56
+ /** Marqueur public des clés (`<prefix>_…`, ex. `nf`). */
57
+ prefix: string;
58
+ /** Expiration par défaut en jours (`null` = sans expiration). */
59
+ defaultExpiryDays: number | null;
60
+ /** Plafond de clés ACTIVES par porteur (création au-delà → 409). */
61
+ maxPerSubject: number;
62
+ /** Catalogue de scopes autorisés (`null` = libre : tout scope non vide accepté). */
63
+ allowedScopes: string[] | null;
64
+ }
65
+ /** Options de création d'une clé API. */
66
+ export interface ICreateApiKeyOptions {
67
+ /** Libellé humain (obligatoire, non vide). */
68
+ name: string;
69
+ /** Capacités demandées (⊆ `apiKeys.allowedScopes` si un catalogue est défini). */
70
+ scopes?: string[];
71
+ /** Durée de vie en jours ; `null` = sans expiration ; omis = défaut config. */
72
+ expiresInDays?: number | null;
73
+ /** Tenant/organisation (multi-tenant) ; `null` = global. */
74
+ tenantId?: string | null;
75
+ }
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Modèle d'un **événement de sécurité** auditable (P6.14) — login, refus d'accès,
3
+ * émission/révocation de jeton, défense CSRF/CORS, verrou de frame WS. Vocabulaire
4
+ * MÉTIER de sécurité, distinct du log technique du trafic (`AuditLogEntry`,
5
+ * `@nodefony/http` P3.1, 1 PDU/requête) : ici on trace une **transition d'état**
6
+ * de sécurité, pas chaque requête. Sérialisable JSON (stream WS + persistance).
7
+ *
8
+ * Règle d'or : un **secret n'entre JAMAIS** dans un événement (ni mot de passe, ni
9
+ * jeton, ni cookie) — seule sa *présence* est tracée via {@link IAuditEvent.flags}.
10
+ */
11
+ /**
12
+ * Sous-système de sécurité concerné — axe de filtrage principal de la console
13
+ * d'audit (Studio P6.15). Fermé : la liste des sous-systèmes est stable.
14
+ *
15
+ * ⚠️ Quatre catégories sont RÉSERVÉES — déclarées au contrat mais **sans émetteur à
16
+ * ce jour** (aucun `record({ category: … })` ne les produit) : `oauth`, `csrf`,
17
+ * `cors`, `config`. La console Studio ne propose donc PAS de filtre pour elles (un
18
+ * filtre qui ne rend jamais rien induit en erreur — cf `studio/.../auditModel.ts`).
19
+ * En câbler une = ajouter son émetteur ICI (l'émetteur), puis la métadonnée
20
+ * d'affichage dans `AUDIT_CATEGORIES`. Émettent réellement : auth, authz, token,
21
+ * session, webauthn, ws, webhook.
22
+ */
23
+ export type AuditCategory = "auth" | "authz" | "token" | "session" | "oauth" | "webauthn" | "csrf" | "cors" | "ws" | "webhook" | "config";
24
+ /**
25
+ * Issue d'une action de sécurité. La distinction `failure`/`denied` est utile à
26
+ * l'auditeur : `failure` = l'acteur a échoué une preuve (brute-force, signature
27
+ * invalide) ; `denied` = une **politique** a refusé un acteur même bien formé
28
+ * (rôle manquant, origine interdite, plancher WS) — signal d'accès non autorisé.
29
+ */
30
+ export type AuditOutcome = "success" | "failure" | "denied";
31
+ /** Drapeaux de **présence** de matériel sensible (jamais la valeur). */
32
+ export interface IAuditEventFlags {
33
+ /** Un en-tête `Authorization` était présent. */
34
+ hasAuthorization?: boolean;
35
+ /** Un cookie était présent. */
36
+ hasCookie?: boolean;
37
+ }
38
+ /**
39
+ * Un événement de sécurité journalisé. `id`/`ts` sont posés par l'`AuditService`
40
+ * (l'émetteur ne fournit qu'un {@link IAuditEventDraft}) → un seul appel système
41
+ * d'horodatage, centralisé hors des points d'émission.
42
+ */
43
+ export interface IAuditEvent {
44
+ /** Identifiant unique dans le process (corrélation + curseur de pagination). */
45
+ id: string;
46
+ /** Horodatage (epoch ms, `Date.now()`), posé par le service. */
47
+ ts: number;
48
+ /** Sous-système concerné — axe de filtrage principal. */
49
+ category: AuditCategory;
50
+ /**
51
+ * Action conventionnée `<sujet>.<verbe>` (ex. `"login.success"`,
52
+ * `"access.denied"`, `"token.revoked"`, `"session.opened"`). String **ouverte**
53
+ * (la liste grandit lot par lot) — PAS un enum fermé, qui coupleraient
54
+ * `IAuditEvent` à chaque point d'émission. Table de référence : README §Audit.
55
+ */
56
+ action: string;
57
+ /** Issue de l'action. */
58
+ outcome: AuditOutcome;
59
+ /**
60
+ * Acteur : identité (`token.getUserIdentifier()`) ou `null` si anonyme/non
61
+ * identifié (tentative pré-authentification). Un **libellé d'identité**, jamais
62
+ * un secret.
63
+ */
64
+ actor: string | null;
65
+ /**
66
+ * Ressource visée (zone firewall, route, canal WS, attribut d'autorisation) —
67
+ * descripteur léger ; jamais le corps ni les en-têtes de la requête.
68
+ */
69
+ resource?: string | null;
70
+ /**
71
+ * Raison **machine** stable et filtrable (ex. `"invalid_credentials"`,
72
+ * `"throttled"`, `"veto"`, `"origin_mismatch"`) — PAS un message libre traduit.
73
+ */
74
+ reason?: string | null;
75
+ /** IP source si disponible (audit « from where »). */
76
+ ip?: string | null;
77
+ /** User-Agent source si disponible. */
78
+ userAgent?: string | null;
79
+ /** Id de requête (corrélation log ↔ audit via l'ALS, P1.4) ; `null` hors requête. */
80
+ requestId?: string | null;
81
+ /**
82
+ * **Présence** (jamais la valeur) de matériel sensible au moment de l'événement
83
+ * — calque `AuditLogEntry.hasAuthorization`. Trace « un cookie / un Authorization
84
+ * était là » sans jamais journaliser le secret lui-même.
85
+ */
86
+ flags?: IAuditEventFlags;
87
+ /** Extras applicatifs libres (anti-migration) ; absents par défaut. */
88
+ metadata?: Record<string, unknown>;
89
+ }
90
+ /**
91
+ * Champs fournis par l'**émetteur** d'un événement — l'`AuditService` y ajoute
92
+ * `id` + `ts`. Garde les points d'émission concis et sans appel système d'horloge.
93
+ */
94
+ export type IAuditEventDraft = Omit<IAuditEvent, "id" | "ts">;
@@ -0,0 +1,80 @@
1
+ import type { IPage, IPageQuery } from "nodefony";
2
+ import type { AuditCategory, AuditOutcome, IAuditEvent, IAuditEventDraft } from "./IAuditEvent.js";
3
+ /**
4
+ * Filtre de lecture du journal d'audit (console Studio P6.15, data plane P6.14
5
+ * Lot 3) — {@link IPageQuery} + les critères propres au journal. Tous les
6
+ * critères sont **AND** ; absents = non filtrant.
7
+ *
8
+ * Pagination par **curseur** (jamais `offset`) : un journal reçoit des écritures
9
+ * pendant qu'on le parcourt, un décalage numérique glisserait d'une page à
10
+ * l'autre. Le curseur est **opaque** — sa forme appartient au store, l'appelant
11
+ * ne fait que repasser le {@link IPage.nextCursor} reçu.
12
+ *
13
+ * `q` (hérité) n'est **pas** appliqué : filtrer un journal se fait par ses axes
14
+ * (catégorie / issue / acteur / action / requête / fenêtre), pas en plein texte.
15
+ */
16
+ export interface IAuditListQuery extends IPageQuery {
17
+ /** Restreint à un sous-système. */
18
+ category?: AuditCategory;
19
+ /** Restreint à une issue (`success`/`failure`/`denied`). */
20
+ outcome?: AuditOutcome;
21
+ /** Restreint à un acteur (égalité exacte de l'identifiant). */
22
+ actor?: string;
23
+ /** Restreint à une action conventionnée (`"login.success"`…). */
24
+ action?: string;
25
+ /** Restreint aux événements d'une **requête** (corrélation trace ↔ audit, P6.15). */
26
+ requestId?: string;
27
+ /** Borne basse d'horodatage (epoch ms, inclus). */
28
+ since?: number;
29
+ /** Borne haute d'horodatage (epoch ms, inclus). */
30
+ until?: number;
31
+ }
32
+ /**
33
+ * Journal d'audit **append-only** (tamper-evident) — état serveur des événements
34
+ * de sécurité. **Pluggable** par backend (mémoire/fichier/ORM/Loki) comme
35
+ * `ITokenStore`. La référence mémoire borne le volume (anti-fuite) ; un backend
36
+ * partagé (ORM/Redis) sert le multi-pod et la rétention longue.
37
+ *
38
+ * `append` est la SEULE écriture : pas d'`update` ni de `delete` ciblé — seul le
39
+ * `gc` (rétention) retire des entrées. L'immuabilité est la garantie d'audit.
40
+ */
41
+ export interface IAuditStore {
42
+ /** Ajoute un événement (immuable, jamais modifié ensuite). */
43
+ append(event: IAuditEvent): Promise<void>;
44
+ /**
45
+ * Lit **une page** d'événements filtrés, du plus récent au plus ancien —
46
+ * l'implémentation ne matérialise jamais plus que `limit` événements.
47
+ *
48
+ * `total` n'est renseigné que si `withTotal` n'est pas `false` (un `COUNT`
49
+ * filtré sur un journal de rétention longue se paie) ; {@link IPage.hasNext}
50
+ * et {@link IPage.nextCursor} sont fiables dans les deux cas.
51
+ */
52
+ listPage(query: IAuditListQuery): Promise<IPage<IAuditEvent>>;
53
+ /**
54
+ * Purge les événements au-delà de la fenêtre de rétention. À planifier
55
+ * périodiquement par le propriétaire du store (timer `unref`). Sans appel, un
56
+ * backend sans TTL natif s'accumule jusqu'à sa borne de volume.
57
+ *
58
+ * @returns nombre d'événements purgés.
59
+ */
60
+ gc(now?: number): Promise<number>;
61
+ }
62
+ /**
63
+ * Face **émission** du journal, vue par les points sensibles (firewall,
64
+ * authenticators, controllers OAuth/WebAuthn). `record` est **synchrone et
65
+ * fire-and-forget** : l'audit ne doit JAMAIS bloquer ni faire échouer le flux
66
+ * métier (un store en panne se solde par un log d'erreur, pas par un login KO).
67
+ * No-op à coût nul si l'audit est désactivé.
68
+ */
69
+ export interface IAuditSink {
70
+ /**
71
+ * Journalise un événement : pose `id`+`ts`, persiste (best-effort) et notifie
72
+ * les abonnés live. Aucun effet (aucune allocation côté service) si désactivé.
73
+ */
74
+ record(event: IAuditEventDraft): void;
75
+ /**
76
+ * S'abonne au flux live des événements (bridge WS, P6.14 Lot 4). Renvoie une
77
+ * fonction de désabonnement (cleanup obligatoire — pas de listener orphelin).
78
+ */
79
+ subscribe(listener: (event: IAuditEvent) => void): () => void;
80
+ }
@@ -0,0 +1,66 @@
1
+ import type { ContextType } from "@nodefony/http";
2
+ import type { IToken } from "./IToken.js";
3
+ import type { ISecuredArea } from "./ISecuredArea.js";
4
+ /**
5
+ * Stratégie d'authentification — pattern « authenticator » : une classe = une
6
+ * façon de prouver qui on est. Pas de Bridge/Factory (héritage Passport/YAML
7
+ * abandonné).
8
+ *
9
+ * Une zone sécurisée ({@link ISecuredArea}) liste les noms d'authenticators à
10
+ * exécuter selon son `mode` : `"first"` (le premier dont `supports()` est vrai
11
+ * authentifie) ou `"all"` (tous doivent passer — MFA, le dernier porte
12
+ * l'identité). Cycle : `createToken()` extrait le credential (token non
13
+ * authentifié), `authenticate()` valide et promeut ou `throw` (→ 401).
14
+ *
15
+ * Implémentations : `AnonymousAuthenticator`, `UserPasswordAuthenticator`,
16
+ * `SessionAuthenticator`, `JwtAuthenticator`, `ApiKeyAuthenticator`.
17
+ *
18
+ * Le login social ne passe **pas** par un authenticator : `OAuth2Service`
19
+ * échange le code, provisionne l'utilisateur et ouvre une session BFF — c'est
20
+ * ensuite `SessionAuthenticator` qui ré-authentifie les requêtes suivantes.
21
+ */
22
+ export interface IAuthenticator {
23
+ /** Nom logique (référencé dans `area.authenticators`). */
24
+ readonly name: string;
25
+ /** Peut-on extraire un credential de cette requête ? (sinon authenticator suivant). */
26
+ supports(context: ContextType): boolean;
27
+ /** Construit un token NON authentifié depuis la requête (extraction credential). */
28
+ createToken(context: ContextType): Promise<IToken>;
29
+ /** Valide le token (vérifie le credential) ou `throw` une AuthenticationError. */
30
+ authenticate(token: IToken): Promise<IToken>;
31
+ /** Hook succès — pose le token (cookie JWT, log audit S1…). */
32
+ onSuccess(context: ContextType, token: IToken): Promise<void>;
33
+ /** Hook échec — log audit, throttling (J2)… Le 401 + challenge sont posés par le firewall. */
34
+ onFailure(context: ContextType, error: Error): Promise<void>;
35
+ /**
36
+ * Challenge `WWW-Authenticate` (RFC 7235 : tout 401 DOIT en porter un).
37
+ * Le firewall pose celui du premier authenticator de la zone qui en déclare.
38
+ * Ex. `'Basic realm="nodefony", charset="UTF-8"'`, `'Bearer'`.
39
+ *
40
+ * La ZONE est passée parce qu'un défi peut dépendre d'elle — le pointeur
41
+ * `resource_metadata` de la RFC 9728 nomme la ressource, et une instance
42
+ * d'authenticator est partagée entre toutes les zones qui la listent. Sans
43
+ * cet argument, un authenticator ne pouvait rendre qu'un défi constant, donc
44
+ * muet sur la ressource réellement visée.
45
+ *
46
+ * @param area - zone qui a refusé ; absente si l'appelant n'en a pas
47
+ */
48
+ challenge?(area?: ISecuredArea): string;
49
+ /**
50
+ * Vérifie AU BOOT que la zone qui référence cet authenticator lui donne ce
51
+ * dont il a besoin — sinon `throw`, et la configuration n'existe pas.
52
+ *
53
+ * Appelée une fois par zone qui le liste, avant la première requête. C'est
54
+ * l'authenticator qui dit ce qu'il exige, jamais le firewall : celui-ci ne
55
+ * connaît aucun nom en dur, et un plugin tiers doit pouvoir poser ses propres
56
+ * exigences sans qu'on touche au cœur.
57
+ *
58
+ * Le contrôle vaut d'être fait ici plutôt qu'à la première requête, où il se
59
+ * manifesterait par un 401 sans cause visible, chez un seul appelant, un jour
60
+ * quelconque.
61
+ *
62
+ * @param area - la zone qui référence cet authenticator
63
+ * @throws Error si la zone ne remplit pas les conditions d'emploi
64
+ */
65
+ validateArea?(area: ISecuredArea): void;
66
+ }