@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,153 @@
1
+ import { AuthenticationError } from "../errors/AuthenticationError.js";
2
+ import { defineSecurityConfig } from "../config/defineModuleConfig.js";
3
+ import { getOAuthProviderFactory, listOAuthProviders } from "../src/oauth/oauthProviderRegistry.js";
4
+ import { Service } from "nodefony";
5
+ //#region nodefony/service/oauth2.ts
6
+ const serviceName = "oauth2";
7
+ /**
8
+ * **Social login OAuth 2.0** (P6 J9) — orchestrateur du flux *Authorization Code*
9
+ * au-dessus d'`arctic`.
10
+ *
11
+ * Posture OAuth 2.1 (RFC 9700) : Authorization Code uniquement (jamais implicit /
12
+ * ROPC), **PKCE S256** quand le fournisseur le supporte (RFC 7636), **state**
13
+ * anti-CSRF, **iss** anti-mix-up (RFC 9207) ; aucun jeton n'atteint le navigateur
14
+ * (le login produit une **session BFF**, gérée hors de ce service par le
15
+ * controller + `AuthFlow`).
16
+ *
17
+ * `arctic` est **importé paresseusement** au premier login (cold path — jamais au
18
+ * boot ni par requête), comme `@simplewebauthn`/`jose`. Au boot (si
19
+ * `oauth2.enabled`) : seule la config est validée et les fournisseurs configurés
20
+ * sont confrontés au registre (un nom inconnu = WARNING, pas fatal).
21
+ *
22
+ * Le service ne touche **ni HTTP ni session** : il rend à l'appelant les éléments
23
+ * (URL, state, verifier) que le controller persiste en session — testable sans
24
+ * transport, comme `AuthFlow`.
25
+ */
26
+ var OAuth2Service = class extends Service {
27
+ module;
28
+ #config = null;
29
+ #lib = null;
30
+ #providers = null;
31
+ #ready = false;
32
+ constructor(module) {
33
+ super(serviceName, module.container, module.notificationsCenter, module.options);
34
+ this.module = module;
35
+ this.kernel?.once("onBoot", () => this.#build());
36
+ }
37
+ #build() {
38
+ let config;
39
+ try {
40
+ config = defineSecurityConfig(this.options);
41
+ } catch {
42
+ return;
43
+ }
44
+ if (!config.oauth2.enabled) {
45
+ this.log("oauth2 idle — social login désactivé en config", "DEBUG");
46
+ return;
47
+ }
48
+ this.#config = config;
49
+ const known = new Set(listOAuthProviders());
50
+ const configured = Object.keys(config.oauth2.providers);
51
+ for (const name of configured) if (!known.has(name)) this.log(`oauth2 provider "${name}" inconnu du registre — ignoré (registerOAuthProvider manquant ?)`, "WARNING");
52
+ this.#ready = true;
53
+ const active = configured.filter((n) => known.has(n));
54
+ this.log(`oauth2 ready — providers: [${active.join(", ") || "aucun"}]`, "DEBUG");
55
+ }
56
+ /** `true` si le social login est opérationnel (activé + boot OK). */
57
+ isEnabled() {
58
+ return this.#ready;
59
+ }
60
+ /** Noms des fournisseurs configurés ET connus du registre (UI : boutons à afficher). */
61
+ listProviders() {
62
+ if (!this.#ready || this.#config === null) return [];
63
+ const known = new Set(listOAuthProviders());
64
+ return Object.keys(this.#config.oauth2.providers).filter((n) => known.has(n));
65
+ }
66
+ /**
67
+ * Redirections post-login (succès / échec) — lues par le controller.
68
+ * Surcharge PAR FOURNISSEUR si fournie, sinon valeur globale, sinon défaut.
69
+ */
70
+ getRedirects(provider) {
71
+ const o = this.#config?.oauth2;
72
+ const p = provider ? o?.providers[provider] : void 0;
73
+ return {
74
+ success: p?.successRedirect ?? o?.successRedirect ?? "/",
75
+ failure: p?.failureRedirect ?? o?.failureRedirect ?? "/login"
76
+ };
77
+ }
78
+ /**
79
+ * Étape 1 — prépare l'URL d'autorisation + les éléments anti-replay à stocker
80
+ * en session (`state`, et `code_verifier` si PKCE).
81
+ *
82
+ * @throws AuthenticationError — fournisseur non configuré / inconnu du registre.
83
+ */
84
+ async createAuthorization(provider) {
85
+ const resolved = await this.#resolveProvider(provider);
86
+ const lib = await this.#ensureLib();
87
+ const state = lib.generateState();
88
+ const codeVerifier = resolved.provider.usesPkce ? lib.generateCodeVerifier() : null;
89
+ return {
90
+ url: resolved.provider.createAuthorizationURL(state, codeVerifier, resolved.scopes).toString(),
91
+ state,
92
+ codeVerifier
93
+ };
94
+ }
95
+ /**
96
+ * Étape 2 — valide la réponse, échange le `code`, lit le profil et provisionne
97
+ * l'utilisateur local (Shadow User). Retourne l'identifiant à ouvrir en session.
98
+ *
99
+ * @param returnedIss - paramètre `iss` reçu (anti-mix-up RFC 9207), ou `null`.
100
+ * @throws AuthenticationError — `iss` invalide, échange refusé, ou provisioning
101
+ * impossible (lien inconnu + signup interdit).
102
+ */
103
+ async exchangeAndProvision(provider, code, codeVerifier, returnedIss) {
104
+ const { provider: p } = await this.#resolveProvider(provider);
105
+ if (p.expectedIssuer !== null) {
106
+ if (returnedIss === null || returnedIss !== p.expectedIssuer) throw new AuthenticationError("OAuth issuer mismatch");
107
+ }
108
+ const tokens = await p.validateAuthorizationCode(code, codeVerifier);
109
+ const profile = await p.fetchProfile(tokens);
110
+ const cfg = this.#config.oauth2;
111
+ const defaultRoles = cfg.providers[provider]?.defaultRoles ?? cfg.defaultRoles;
112
+ return { identifier: (await this.#resolveProvisioner().provisionOAuthUser(profile, {
113
+ defaultRoles: [...defaultRoles],
114
+ allowSignup: cfg.allowSignup
115
+ })).identifier };
116
+ }
117
+ async #resolveProvider(name) {
118
+ this.#ensureReady();
119
+ this.#providers ??= /* @__PURE__ */ new Map();
120
+ const cached = this.#providers.get(name);
121
+ if (cached) return cached;
122
+ const cfg = this.#config.oauth2.providers[name];
123
+ if (!cfg) throw new AuthenticationError(`OAuth provider "${name}" non configuré`);
124
+ const factory = getOAuthProviderFactory(name);
125
+ if (!factory) throw new AuthenticationError(`OAuth provider "${name}" inconnu du registre`);
126
+ const provider = factory({
127
+ arctic: await this.#ensureLib(),
128
+ clientId: cfg.clientId,
129
+ clientSecret: cfg.clientSecret,
130
+ redirectUri: cfg.redirectUri,
131
+ issuer: cfg.issuer
132
+ });
133
+ const resolved = {
134
+ provider,
135
+ scopes: cfg.scopes.length > 0 ? cfg.scopes : provider.defaultScopes
136
+ };
137
+ this.#providers.set(name, resolved);
138
+ return resolved;
139
+ }
140
+ #resolveProvisioner() {
141
+ const users = this.get("users");
142
+ if (!users || typeof users.provisionOAuthUser !== "function") throw new AuthenticationError("OAuth provisioning indisponible (le service users n'implémente pas IOAuthUserProvisioner)");
143
+ return users;
144
+ }
145
+ async #ensureLib() {
146
+ return this.#lib ??= await import("arctic");
147
+ }
148
+ #ensureReady() {
149
+ if (!this.#ready || this.#config === null) throw new Error("OAuth2Service: non initialisé (social login désactivé ou boot échoué)");
150
+ }
151
+ };
152
+ //#endregion
153
+ export { OAuth2Service, OAuth2Service as default };
@@ -0,0 +1,80 @@
1
+ import { mergeCspFragments } from "../src/csp.js";
2
+ //#region nodefony/service/securityHeaders.ts
3
+ /** Marqueur substitué par le nonce CSP de la requête (cf `Context.cspNonce`). */
4
+ const NONCE_PLACEHOLDER = "{{nonce}}";
5
+ /**
6
+ * En-têtes de sécurité **applicatifs** de Nodefony (couche `@nodefony/security`,
7
+ * complémentaire du socle transport de `@nodefony/http`). Pré-calcule une fois au
8
+ * boot la table d'en-têtes CONSTANTS (CSP statique, Referrer-Policy, isolation
9
+ * cross-origin COOP/COEP/CORP, Origin-Agent-Cluster, Permissions-Policy) → zéro
10
+ * alloc, zéro concat par requête (le firewall la pose telle quelle).
11
+ *
12
+ * **Étape A+B** : en-têtes constants pré-calculés au boot (Referrer/COOP/…). Pour le
13
+ * CSP, deux régimes mutuellement exclusifs : **statique** (posé tel quel via `headers`,
14
+ * 0 alloc/req) OU **nonce par requête** (`cspNonces` + placeholder `{{nonce}}` dans le
15
+ * CSP) → segments pré-split au boot, recomposés par requête via `cspFor(nonce)` (1
16
+ * `join`, aucun parse/regex dans le hot-path). Le nonce lui-même vit sur `Context`.
17
+ *
18
+ * @see Fetch Metadata · W3C CSP Level 3 · WHATWG (COOP/COEP/CORP).
19
+ */
20
+ var SecurityHeaders = class {
21
+ #headers;
22
+ #cspParts;
23
+ #cspRaw;
24
+ constructor(o) {
25
+ const h = {};
26
+ let cspParts = null;
27
+ if (o.csp) {
28
+ if (o.cspNonces && o.csp.includes(NONCE_PLACEHOLDER)) cspParts = o.csp.split(NONCE_PLACEHOLDER);
29
+ else {
30
+ const csp = o.cspNonces ? o.csp : o.csp.replace(/\s*'nonce-\{\{nonce\}\}'/g, "");
31
+ if (csp) h["Content-Security-Policy"] = csp;
32
+ }
33
+ }
34
+ if (o.referrerPolicy) h["Referrer-Policy"] = o.referrerPolicy;
35
+ if (o.coop) h["Cross-Origin-Opener-Policy"] = o.coop;
36
+ if (o.coep) h["Cross-Origin-Embedder-Policy"] = o.coep;
37
+ if (o.corp) h["Cross-Origin-Resource-Policy"] = o.corp;
38
+ if (o.originAgentCluster) h["Origin-Agent-Cluster"] = "?1";
39
+ if (o.permissionsPolicy) h["Permissions-Policy"] = o.permissionsPolicy;
40
+ this.#headers = Object.freeze(h);
41
+ this.#cspParts = cspParts ? Object.freeze(cspParts) : null;
42
+ this.#cspRaw = o.csp ?? "";
43
+ }
44
+ /** Table d'en-têtes applicatifs CONSTANTS (figée), posée telle quelle par le firewall. */
45
+ get headers() {
46
+ return this.#headers;
47
+ }
48
+ /** `true` si le CSP est recomposé par requête avec un nonce (→ `cspFor`). */
49
+ get hasNonce() {
50
+ return this.#cspParts !== null;
51
+ }
52
+ /**
53
+ * Recompose le CSP en injectant le `nonce` de la requête aux emplacements
54
+ * `{{nonce}}`. 1 `join` (segments pré-split au boot). Le nonce est base64 (jamais
55
+ * `'`/`;`/espace) → aucune évasion possible du token CSP.
56
+ *
57
+ * @param nonce - nonce base64 de la requête (`Context.cspNonce`).
58
+ * @returns la valeur `Content-Security-Policy` à poser sur la réponse.
59
+ */
60
+ cspFor(nonce) {
61
+ return this.#cspParts.join(nonce);
62
+ }
63
+ /**
64
+ * Recompose le CSP en fusionnant ADDITIVEMENT les directives `extra` d'une
65
+ * route (`@Csp`) dans le CSP de base, PUIS en substituant le `nonce`. Le merge
66
+ * (parse/serialize) n'est payé QUE sur les routes décorées `@Csp` (rares) — le
67
+ * cas courant reste {@link cspFor} (1 `join`). Une directive déjà présente voit
68
+ * ses sources complétées (jamais dupliquée — W3C CSP3 §3).
69
+ *
70
+ * @param nonce - nonce base64 de la requête (ignoré si le CSP n'a pas de nonce).
71
+ * @param extra - directives additionnelles de la route (`directive → sources`).
72
+ * @returns la valeur `Content-Security-Policy` à poser sur la réponse.
73
+ */
74
+ cspForExtra(nonce, extra) {
75
+ const merged = mergeCspFragments(this.#cspRaw, [extra]);
76
+ return this.#cspParts !== null ? merged.split(NONCE_PLACEHOLDER).join(nonce) : merged.replace(/\s*'nonce-\{\{nonce\}\}'/g, "");
77
+ }
78
+ };
79
+ //#endregion
80
+ export { SecurityHeaders, SecurityHeaders as default };