@hilbras/keystone 1.6.0 → 1.9.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 (559) hide show
  1. package/CHANGELOG.md +239 -0
  2. package/README.md +55 -25
  3. package/dist/cli.js +25 -27
  4. package/dist/cli.js.map +1 -1
  5. package/dist/config.d.ts +15 -1
  6. package/dist/config.d.ts.map +1 -1
  7. package/dist/config.js +45 -8
  8. package/dist/config.js.map +1 -1
  9. package/dist/container.d.ts +4 -1
  10. package/dist/container.d.ts.map +1 -1
  11. package/dist/container.js.map +1 -1
  12. package/dist/db/migrations/0008_flashy_firestar.sql +5 -0
  13. package/dist/db/migrations/0009_daffy_changeling.sql +1 -0
  14. package/dist/db/migrations/0010_wealthy_shadow_king.sql +37 -0
  15. package/dist/db/migrations/0011_overrated_vector.sql +18 -0
  16. package/dist/db/migrations/0012_brave_darkhawk.sql +28 -0
  17. package/dist/db/migrations/0013_wonderful_chimera.sql +5 -0
  18. package/dist/db/migrations/0014_magical_morph.sql +48 -0
  19. package/{src/db/migrations/meta/0007_snapshot.json → dist/db/migrations/meta/0008_snapshot.json} +136 -32
  20. package/{src/db/migrations/meta/0006_snapshot.json → dist/db/migrations/meta/0009_snapshot.json} +359 -30
  21. package/{src/db/migrations/meta/0005_snapshot.json → dist/db/migrations/meta/0010_snapshot.json} +459 -29
  22. package/{src/db/migrations/meta/0004_snapshot.json → dist/db/migrations/meta/0011_snapshot.json} +594 -30
  23. package/dist/db/migrations/meta/0012_snapshot.json +3891 -0
  24. package/dist/db/migrations/meta/0013_snapshot.json +3919 -0
  25. package/dist/db/migrations/meta/0014_snapshot.json +4311 -0
  26. package/dist/db/migrations/meta/_journal.json +49 -0
  27. package/dist/db/reencryptOidcSecrets.d.ts +2 -0
  28. package/dist/db/reencryptOidcSecrets.d.ts.map +1 -0
  29. package/dist/db/reencryptOidcSecrets.js +41 -0
  30. package/dist/db/reencryptOidcSecrets.js.map +1 -0
  31. package/dist/db/schema.d.ts +2521 -53
  32. package/dist/db/schema.d.ts.map +1 -1
  33. package/dist/db/schema.js +118 -3
  34. package/dist/db/schema.js.map +1 -1
  35. package/dist/db/seed.js +67 -40
  36. package/dist/db/seed.js.map +1 -1
  37. package/dist/di.d.ts.map +1 -1
  38. package/dist/di.js +11 -3
  39. package/dist/di.js.map +1 -1
  40. package/dist/index.d.ts +2 -2
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +26 -2
  43. package/dist/index.js.map +1 -1
  44. package/dist/lib/errors.d.ts +2 -1
  45. package/dist/lib/errors.d.ts.map +1 -1
  46. package/dist/lib/errors.js +10 -0
  47. package/dist/lib/errors.js.map +1 -1
  48. package/dist/plugins/appContext.d.ts.map +1 -1
  49. package/dist/plugins/appContext.js +3 -12
  50. package/dist/plugins/appContext.js.map +1 -1
  51. package/dist/plugins/audit.d.ts.map +1 -1
  52. package/dist/plugins/audit.js +26 -6
  53. package/dist/plugins/audit.js.map +1 -1
  54. package/dist/plugins/auth.d.ts.map +1 -1
  55. package/dist/plugins/auth.js +32 -7
  56. package/dist/plugins/auth.js.map +1 -1
  57. package/dist/plugins/metrics.d.ts.map +1 -1
  58. package/dist/plugins/mtls.d.ts.map +1 -1
  59. package/dist/plugins/permissions.d.ts.map +1 -1
  60. package/dist/plugins/permissions.js +29 -9
  61. package/dist/plugins/permissions.js.map +1 -1
  62. package/dist/plugins/rateLimit.d.ts +15 -0
  63. package/dist/plugins/rateLimit.d.ts.map +1 -1
  64. package/dist/plugins/rateLimit.js +11 -1
  65. package/dist/plugins/rateLimit.js.map +1 -1
  66. package/dist/plugins/requestLogger.d.ts.map +1 -1
  67. package/dist/repositories/apiKey.d.ts.map +1 -1
  68. package/dist/repositories/application.d.ts.map +1 -1
  69. package/dist/repositories/application.js +1 -1
  70. package/dist/repositories/application.js.map +1 -1
  71. package/dist/repositories/audit.d.ts.map +1 -1
  72. package/dist/repositories/index.d.ts +3 -0
  73. package/dist/repositories/index.d.ts.map +1 -1
  74. package/dist/repositories/index.js +3 -0
  75. package/dist/repositories/index.js.map +1 -1
  76. package/dist/repositories/mfaChallenge.d.ts +23 -0
  77. package/dist/repositories/mfaChallenge.d.ts.map +1 -0
  78. package/dist/repositories/mfaChallenge.js +71 -0
  79. package/dist/repositories/mfaChallenge.js.map +1 -0
  80. package/dist/repositories/oidcConnection.d.ts +27 -43
  81. package/dist/repositories/oidcConnection.d.ts.map +1 -1
  82. package/dist/repositories/oidcConnection.js +15 -6
  83. package/dist/repositories/oidcConnection.js.map +1 -1
  84. package/dist/repositories/organization.d.ts +9 -9
  85. package/dist/repositories/organization.d.ts.map +1 -1
  86. package/dist/repositories/organization.js +91 -37
  87. package/dist/repositories/organization.js.map +1 -1
  88. package/dist/repositories/permission.d.ts.map +1 -1
  89. package/dist/repositories/permission.js +27 -5
  90. package/dist/repositories/permission.js.map +1 -1
  91. package/dist/repositories/samlConnection.d.ts +28 -28
  92. package/dist/repositories/samlConnection.d.ts.map +1 -1
  93. package/dist/repositories/samlConnection.js +12 -4
  94. package/dist/repositories/samlConnection.js.map +1 -1
  95. package/dist/repositories/scimConnection.d.ts +38 -0
  96. package/dist/repositories/scimConnection.d.ts.map +1 -0
  97. package/dist/repositories/scimConnection.js +123 -0
  98. package/dist/repositories/scimConnection.js.map +1 -0
  99. package/dist/repositories/scimGroup.d.ts +36 -0
  100. package/dist/repositories/scimGroup.d.ts.map +1 -0
  101. package/dist/repositories/scimGroup.js +113 -0
  102. package/dist/repositories/scimGroup.js.map +1 -0
  103. package/dist/repositories/session.d.ts +23 -13
  104. package/dist/repositories/session.d.ts.map +1 -1
  105. package/dist/repositories/session.js +13 -1
  106. package/dist/repositories/session.js.map +1 -1
  107. package/dist/repositories/types.d.ts +112 -5
  108. package/dist/repositories/types.d.ts.map +1 -1
  109. package/dist/repositories/types.js +7 -1
  110. package/dist/repositories/types.js.map +1 -1
  111. package/dist/repositories/user.d.ts +23 -1
  112. package/dist/repositories/user.d.ts.map +1 -1
  113. package/dist/repositories/user.js +180 -4
  114. package/dist/repositories/user.js.map +1 -1
  115. package/dist/routes/admin/billing.js +4 -4
  116. package/dist/routes/admin/billing.js.map +1 -1
  117. package/dist/routes/admin/helpers.d.ts +16 -20
  118. package/dist/routes/admin/helpers.d.ts.map +1 -1
  119. package/dist/routes/admin/helpers.js +53 -10
  120. package/dist/routes/admin/helpers.js.map +1 -1
  121. package/dist/routes/admin/organizations.d.ts.map +1 -1
  122. package/dist/routes/admin/organizations.js +76 -69
  123. package/dist/routes/admin/organizations.js.map +1 -1
  124. package/dist/routes/admin/permissions.d.ts.map +1 -1
  125. package/dist/routes/admin/permissions.js +48 -14
  126. package/dist/routes/admin/permissions.js.map +1 -1
  127. package/dist/routes/admin/platform.d.ts.map +1 -1
  128. package/dist/routes/admin/platform.js +86 -35
  129. package/dist/routes/admin/platform.js.map +1 -1
  130. package/dist/routes/admin/sso.d.ts.map +1 -1
  131. package/dist/routes/admin/sso.js +143 -12
  132. package/dist/routes/admin/sso.js.map +1 -1
  133. package/dist/routes/admin/webhooks.js +8 -8
  134. package/dist/routes/admin/webhooks.js.map +1 -1
  135. package/dist/routes/apiKeys.d.ts.map +1 -1
  136. package/dist/routes/apiKeys.js +23 -5
  137. package/dist/routes/apiKeys.js.map +1 -1
  138. package/dist/routes/auth.d.ts.map +1 -1
  139. package/dist/routes/auth.js +112 -22
  140. package/dist/routes/auth.js.map +1 -1
  141. package/dist/routes/authz.d.ts.map +1 -1
  142. package/dist/routes/authz.js +16 -4
  143. package/dist/routes/authz.js.map +1 -1
  144. package/dist/routes/config.d.ts.map +1 -1
  145. package/dist/routes/config.js +16 -14
  146. package/dist/routes/config.js.map +1 -1
  147. package/dist/routes/federation.d.ts.map +1 -1
  148. package/dist/routes/federation.js +17 -3
  149. package/dist/routes/federation.js.map +1 -1
  150. package/dist/routes/magicLinks.d.ts.map +1 -1
  151. package/dist/routes/magicLinks.js +15 -3
  152. package/dist/routes/magicLinks.js.map +1 -1
  153. package/dist/routes/oauth.d.ts.map +1 -1
  154. package/dist/routes/oauth.js +22 -3
  155. package/dist/routes/oauth.js.map +1 -1
  156. package/dist/routes/oauth2.d.ts.map +1 -1
  157. package/dist/routes/oauth2.js +104 -11
  158. package/dist/routes/oauth2.js.map +1 -1
  159. package/dist/routes/oidcEnterprise.d.ts.map +1 -1
  160. package/dist/routes/oidcEnterprise.js +67 -21
  161. package/dist/routes/oidcEnterprise.js.map +1 -1
  162. package/dist/routes/password.d.ts.map +1 -1
  163. package/dist/routes/password.js.map +1 -1
  164. package/dist/routes/profile.js +4 -4
  165. package/dist/routes/profile.js.map +1 -1
  166. package/dist/routes/saml.d.ts +9 -0
  167. package/dist/routes/saml.d.ts.map +1 -1
  168. package/dist/routes/saml.js +187 -11
  169. package/dist/routes/saml.js.map +1 -1
  170. package/dist/routes/scim.d.ts +13 -0
  171. package/dist/routes/scim.d.ts.map +1 -1
  172. package/dist/routes/scim.js +885 -110
  173. package/dist/routes/scim.js.map +1 -1
  174. package/dist/routes/sdk.d.ts.map +1 -1
  175. package/dist/routes/sdk.js +24 -8
  176. package/dist/routes/sdk.js.map +1 -1
  177. package/dist/routes/serviceAccounts.d.ts.map +1 -1
  178. package/dist/routes/serviceAccounts.js +2 -1
  179. package/dist/routes/serviceAccounts.js.map +1 -1
  180. package/dist/routes/setup.d.ts.map +1 -1
  181. package/dist/routes/setup.js +15 -16
  182. package/dist/routes/setup.js.map +1 -1
  183. package/dist/routes/smsOtp.js +1 -1
  184. package/dist/routes/smsOtp.js.map +1 -1
  185. package/dist/routes/totp.d.ts.map +1 -1
  186. package/dist/routes/totp.js +113 -23
  187. package/dist/routes/totp.js.map +1 -1
  188. package/dist/routes/webauthn.d.ts.map +1 -1
  189. package/dist/routes/webauthn.js +44 -8
  190. package/dist/routes/webauthn.js.map +1 -1
  191. package/dist/routes/workflows.d.ts.map +1 -1
  192. package/dist/routes/workflows.js +58 -25
  193. package/dist/routes/workflows.js.map +1 -1
  194. package/dist/sdk/index.d.ts.map +1 -1
  195. package/dist/sdk/index.js +141 -40
  196. package/dist/sdk/index.js.map +1 -1
  197. package/dist/sdk/types.d.ts +60 -29
  198. package/dist/sdk/types.d.ts.map +1 -1
  199. package/dist/services/application/authentication.d.ts +39 -1
  200. package/dist/services/application/authentication.d.ts.map +1 -1
  201. package/dist/services/application/authentication.js +43 -1
  202. package/dist/services/application/authentication.js.map +1 -1
  203. package/dist/services/application/identity.d.ts +10 -7
  204. package/dist/services/application/identity.d.ts.map +1 -1
  205. package/dist/services/application/identity.js +13 -10
  206. package/dist/services/application/identity.js.map +1 -1
  207. package/dist/services/application/organization.d.ts +11 -7
  208. package/dist/services/application/organization.d.ts.map +1 -1
  209. package/dist/services/application/organization.js +160 -12
  210. package/dist/services/application/organization.js.map +1 -1
  211. package/dist/services/applications.js +2 -2
  212. package/dist/services/applications.js.map +1 -1
  213. package/dist/services/audit.d.ts +1 -0
  214. package/dist/services/audit.d.ts.map +1 -1
  215. package/dist/services/audit.js +13 -0
  216. package/dist/services/audit.js.map +1 -1
  217. package/dist/services/cache.d.ts.map +1 -1
  218. package/dist/services/configuration/profiles.d.ts +4 -0
  219. package/dist/services/configuration/profiles.d.ts.map +1 -1
  220. package/dist/services/configuration/profiles.js +50 -0
  221. package/dist/services/configuration/profiles.js.map +1 -1
  222. package/dist/services/configuration.d.ts.map +1 -1
  223. package/dist/services/configuration.js.map +1 -1
  224. package/dist/services/connectors/google.d.ts.map +1 -1
  225. package/dist/services/connectors/google.js +3 -2
  226. package/dist/services/connectors/google.js.map +1 -1
  227. package/dist/services/connectors/oidc.d.ts.map +1 -1
  228. package/dist/services/connectors/oidc.js +6 -3
  229. package/dist/services/connectors/oidc.js.map +1 -1
  230. package/dist/services/connectors/zitadel.d.ts.map +1 -1
  231. package/dist/services/connectors/zitadel.js +4 -3
  232. package/dist/services/connectors/zitadel.js.map +1 -1
  233. package/dist/services/domain/authentication.d.ts +43 -4
  234. package/dist/services/domain/authentication.d.ts.map +1 -1
  235. package/dist/services/domain/authentication.js +82 -20
  236. package/dist/services/domain/authentication.js.map +1 -1
  237. package/dist/services/domain/authorization.d.ts +11 -0
  238. package/dist/services/domain/authorization.d.ts.map +1 -1
  239. package/dist/services/domain/authorization.js +36 -1
  240. package/dist/services/domain/authorization.js.map +1 -1
  241. package/dist/services/domain/identity.d.ts +21 -9
  242. package/dist/services/domain/identity.d.ts.map +1 -1
  243. package/dist/services/domain/identity.js +187 -10
  244. package/dist/services/domain/identity.js.map +1 -1
  245. package/dist/services/domain/organization.d.ts +6 -9
  246. package/dist/services/domain/organization.d.ts.map +1 -1
  247. package/dist/services/domain/organization.js +48 -30
  248. package/dist/services/domain/organization.js.map +1 -1
  249. package/dist/services/emailVerification.d.ts +2 -2
  250. package/dist/services/enterpriseSso.d.ts +13 -6
  251. package/dist/services/enterpriseSso.d.ts.map +1 -1
  252. package/dist/services/enterpriseSso.js +75 -6
  253. package/dist/services/enterpriseSso.js.map +1 -1
  254. package/dist/services/events/subscribers/auditLog.js +1 -1
  255. package/dist/services/events/subscribers/auditLog.js.map +1 -1
  256. package/dist/services/events/types.d.ts +7 -1
  257. package/dist/services/events/types.d.ts.map +1 -1
  258. package/dist/services/events/types.js.map +1 -1
  259. package/dist/services/events/validate.d.ts.map +1 -1
  260. package/dist/services/events/validate.js +27 -0
  261. package/dist/services/events/validate.js.map +1 -1
  262. package/dist/services/features.d.ts.map +1 -1
  263. package/dist/services/features.js.map +1 -1
  264. package/dist/services/federation.d.ts +6 -1
  265. package/dist/services/federation.d.ts.map +1 -1
  266. package/dist/services/federation.js +31 -4
  267. package/dist/services/federation.js.map +1 -1
  268. package/dist/services/ipControls.js +2 -2
  269. package/dist/services/ipControls.js.map +1 -1
  270. package/dist/services/magicLinks.d.ts +2 -2
  271. package/dist/services/mfa.d.ts +53 -0
  272. package/dist/services/mfa.d.ts.map +1 -0
  273. package/dist/services/mfa.js +157 -0
  274. package/dist/services/mfa.js.map +1 -0
  275. package/dist/services/oauth2.d.ts +16 -12
  276. package/dist/services/oauth2.d.ts.map +1 -1
  277. package/dist/services/oauth2.js +22 -13
  278. package/dist/services/oauth2.js.map +1 -1
  279. package/dist/services/oidcSecretFormat.d.ts +3 -0
  280. package/dist/services/oidcSecretFormat.d.ts.map +1 -0
  281. package/dist/services/oidcSecretFormat.js +5 -0
  282. package/dist/services/oidcSecretFormat.js.map +1 -0
  283. package/dist/services/organizations.d.ts +4 -16
  284. package/dist/services/organizations.d.ts.map +1 -1
  285. package/dist/services/organizations.js +0 -62
  286. package/dist/services/organizations.js.map +1 -1
  287. package/dist/services/permissions.d.ts.map +1 -1
  288. package/dist/services/permissions.js +9 -1
  289. package/dist/services/permissions.js.map +1 -1
  290. package/dist/services/plugins/registry.d.ts.map +1 -1
  291. package/dist/services/plugins/registry.js.map +1 -1
  292. package/dist/services/plugins/types.d.ts.map +1 -1
  293. package/dist/services/queue/bullmq.d.ts.map +1 -1
  294. package/dist/services/queue/inProcess.d.ts.map +1 -1
  295. package/dist/services/redis.d.ts +1 -1
  296. package/dist/services/redis.d.ts.map +1 -1
  297. package/dist/services/scimCredentials.d.ts +46 -0
  298. package/dist/services/scimCredentials.d.ts.map +1 -0
  299. package/dist/services/scimCredentials.js +123 -0
  300. package/dist/services/scimCredentials.js.map +1 -0
  301. package/dist/services/scimLegacyMigration.d.ts +12 -0
  302. package/dist/services/scimLegacyMigration.d.ts.map +1 -0
  303. package/dist/services/scimLegacyMigration.js +44 -0
  304. package/dist/services/scimLegacyMigration.js.map +1 -0
  305. package/dist/services/secrets/awsKms.d.ts +2 -2
  306. package/dist/services/secrets/awsKms.d.ts.map +1 -1
  307. package/dist/services/secrets/awsKms.js +3 -5
  308. package/dist/services/secrets/awsKms.js.map +1 -1
  309. package/dist/services/secrets/azureKeyVault.d.ts.map +1 -1
  310. package/dist/services/secrets/database.d.ts.map +1 -1
  311. package/dist/services/secrets/database.js.map +1 -1
  312. package/dist/services/secrets/environment.d.ts.map +1 -1
  313. package/dist/services/secrets/environment.js.map +1 -1
  314. package/dist/services/secrets/index.d.ts.map +1 -1
  315. package/dist/services/secrets/password.d.ts.map +1 -1
  316. package/dist/services/secrets/password.js +0 -4
  317. package/dist/services/secrets/password.js.map +1 -1
  318. package/dist/services/secrets/provider.d.ts +2 -3
  319. package/dist/services/secrets/provider.d.ts.map +1 -1
  320. package/dist/services/secrets/vault.d.ts.map +1 -1
  321. package/dist/services/setup/configWriter.d.ts.map +1 -1
  322. package/dist/services/setup/configWriter.js.map +1 -1
  323. package/dist/services/ssoEndpointPolicy.d.ts +8 -0
  324. package/dist/services/ssoEndpointPolicy.d.ts.map +1 -0
  325. package/dist/services/ssoEndpointPolicy.js +136 -0
  326. package/dist/services/ssoEndpointPolicy.js.map +1 -0
  327. package/dist/services/stepUp.d.ts +35 -0
  328. package/dist/services/stepUp.d.ts.map +1 -0
  329. package/dist/services/stepUp.js +65 -0
  330. package/dist/services/stepUp.js.map +1 -0
  331. package/dist/services/tokens.d.ts +37 -11
  332. package/dist/services/tokens.d.ts.map +1 -1
  333. package/dist/services/tokens.js +75 -14
  334. package/dist/services/tokens.js.map +1 -1
  335. package/dist/services/totp.d.ts +46 -0
  336. package/dist/services/totp.d.ts.map +1 -1
  337. package/dist/services/totp.js +178 -41
  338. package/dist/services/totp.js.map +1 -1
  339. package/dist/services/users.d.ts +20 -12
  340. package/dist/services/users.d.ts.map +1 -1
  341. package/dist/services/users.js +24 -51
  342. package/dist/services/users.js.map +1 -1
  343. package/dist/services/webauthn.d.ts +8 -4
  344. package/dist/services/webauthn.d.ts.map +1 -1
  345. package/dist/services/webauthn.js +4 -4
  346. package/dist/services/webauthn.js.map +1 -1
  347. package/dist/services/webhooks.d.ts +20 -20
  348. package/dist/services/workflows/engine.d.ts +4 -2
  349. package/dist/services/workflows/engine.d.ts.map +1 -1
  350. package/dist/services/workflows/engine.js +181 -12
  351. package/dist/services/workflows/engine.js.map +1 -1
  352. package/dist/services/workflows/steps.d.ts +2 -0
  353. package/dist/services/workflows/steps.d.ts.map +1 -1
  354. package/dist/services/workflows/steps.js +8 -75
  355. package/dist/services/workflows/steps.js.map +1 -1
  356. package/dist/setup-server.js.map +1 -1
  357. package/dist/types.d.ts +33 -4
  358. package/dist/types.d.ts.map +1 -1
  359. package/dist/types.js +26 -2
  360. package/dist/types.js.map +1 -1
  361. package/package.json +26 -3
  362. package/dist/tests/errors.test.d.ts +0 -2
  363. package/dist/tests/errors.test.d.ts.map +0 -1
  364. package/dist/tests/errors.test.js +0 -64
  365. package/dist/tests/errors.test.js.map +0 -1
  366. package/dist/tests/events.test.d.ts +0 -2
  367. package/dist/tests/events.test.d.ts.map +0 -1
  368. package/dist/tests/events.test.js +0 -45
  369. package/dist/tests/events.test.js.map +0 -1
  370. package/dist/tests/featureFlags.test.d.ts +0 -2
  371. package/dist/tests/featureFlags.test.d.ts.map +0 -1
  372. package/dist/tests/featureFlags.test.js +0 -24
  373. package/dist/tests/featureFlags.test.js.map +0 -1
  374. package/dist/tests/integration/queue.test.d.ts +0 -2
  375. package/dist/tests/integration/queue.test.d.ts.map +0 -1
  376. package/dist/tests/integration/queue.test.js +0 -49
  377. package/dist/tests/integration/queue.test.js.map +0 -1
  378. package/dist/tests/plugins.test.d.ts +0 -2
  379. package/dist/tests/plugins.test.d.ts.map +0 -1
  380. package/dist/tests/plugins.test.js +0 -56
  381. package/dist/tests/plugins.test.js.map +0 -1
  382. package/dist/tests/result.test.d.ts +0 -2
  383. package/dist/tests/result.test.d.ts.map +0 -1
  384. package/dist/tests/result.test.js +0 -46
  385. package/dist/tests/result.test.js.map +0 -1
  386. package/dist/tests/setup/configWriter.test.d.ts +0 -2
  387. package/dist/tests/setup/configWriter.test.d.ts.map +0 -1
  388. package/dist/tests/setup/configWriter.test.js +0 -55
  389. package/dist/tests/setup/configWriter.test.js.map +0 -1
  390. package/dist/tests/setup/validation.test.d.ts +0 -2
  391. package/dist/tests/setup/validation.test.d.ts.map +0 -1
  392. package/dist/tests/setup/validation.test.js +0 -26
  393. package/dist/tests/setup/validation.test.js.map +0 -1
  394. package/dist/tests/smoke.test.d.ts +0 -2
  395. package/dist/tests/smoke.test.d.ts.map +0 -1
  396. package/dist/tests/smoke.test.js +0 -124
  397. package/dist/tests/smoke.test.js.map +0 -1
  398. package/src/cli.ts +0 -172
  399. package/src/config.ts +0 -143
  400. package/src/container.ts +0 -48
  401. package/src/db/index.ts +0 -53
  402. package/src/db/migrations/0000_skinny_ben_parker.sql +0 -553
  403. package/src/db/migrations/0001_brief_joseph.sql +0 -10
  404. package/src/db/migrations/0002_add_account_lockout.sql +0 -3
  405. package/src/db/migrations/0003_steep_rachel_grey.sql +0 -1
  406. package/src/db/migrations/0004_clever_bill_hollister.sql +0 -20
  407. package/src/db/migrations/0005_steep_the_call.sql +0 -2
  408. package/src/db/migrations/0006_ambitious_boomer.sql +0 -17
  409. package/src/db/migrations/0007_greedy_vindicator.sql +0 -40
  410. package/src/db/migrations/meta/0000_snapshot.json +0 -2964
  411. package/src/db/migrations/meta/0001_snapshot.json +0 -3031
  412. package/src/db/migrations/meta/0003_snapshot.json +0 -3051
  413. package/src/db/migrations/meta/_journal.json +0 -62
  414. package/src/db/schema.ts +0 -676
  415. package/src/db/seed.ts +0 -146
  416. package/src/di.ts +0 -81
  417. package/src/index.ts +0 -326
  418. package/src/lib/errors.ts +0 -139
  419. package/src/lib/result.ts +0 -44
  420. package/src/lib/webhookSignature.ts +0 -41
  421. package/src/plugins/appContext.ts +0 -76
  422. package/src/plugins/audit.ts +0 -42
  423. package/src/plugins/auth.ts +0 -230
  424. package/src/plugins/metrics.ts +0 -41
  425. package/src/plugins/mtls.ts +0 -94
  426. package/src/plugins/permissions.ts +0 -29
  427. package/src/plugins/rateLimit.ts +0 -133
  428. package/src/plugins/requestLogger.ts +0 -25
  429. package/src/plugins/tracing.ts +0 -22
  430. package/src/repositories/apiKey.ts +0 -158
  431. package/src/repositories/application.ts +0 -70
  432. package/src/repositories/audit.ts +0 -32
  433. package/src/repositories/index.ts +0 -9
  434. package/src/repositories/oidcConnection.ts +0 -111
  435. package/src/repositories/organization.ts +0 -167
  436. package/src/repositories/permission.ts +0 -153
  437. package/src/repositories/samlConnection.ts +0 -96
  438. package/src/repositories/session.ts +0 -86
  439. package/src/repositories/types.ts +0 -134
  440. package/src/repositories/user.ts +0 -161
  441. package/src/routes/admin/billing.ts +0 -48
  442. package/src/routes/admin/helpers.ts +0 -50
  443. package/src/routes/admin/index.ts +0 -16
  444. package/src/routes/admin/organizations.ts +0 -299
  445. package/src/routes/admin/permissions.ts +0 -80
  446. package/src/routes/admin/platform.ts +0 -335
  447. package/src/routes/admin/sso.ts +0 -138
  448. package/src/routes/admin/webhooks.ts +0 -73
  449. package/src/routes/admin.ts +0 -1
  450. package/src/routes/apiKeys.ts +0 -60
  451. package/src/routes/auth.ts +0 -214
  452. package/src/routes/authz.ts +0 -38
  453. package/src/routes/config.ts +0 -67
  454. package/src/routes/emailVerification.ts +0 -73
  455. package/src/routes/federation.ts +0 -156
  456. package/src/routes/helpers.ts +0 -17
  457. package/src/routes/magicLinks.ts +0 -107
  458. package/src/routes/oauth.ts +0 -167
  459. package/src/routes/oauth2.ts +0 -284
  460. package/src/routes/oidcEnterprise.ts +0 -166
  461. package/src/routes/password.ts +0 -90
  462. package/src/routes/profile.ts +0 -44
  463. package/src/routes/saml.ts +0 -209
  464. package/src/routes/scim.ts +0 -199
  465. package/src/routes/sdk.ts +0 -141
  466. package/src/routes/serviceAccounts.ts +0 -124
  467. package/src/routes/sessions.ts +0 -62
  468. package/src/routes/setup.ts +0 -315
  469. package/src/routes/smsOtp.ts +0 -67
  470. package/src/routes/totp.ts +0 -122
  471. package/src/routes/webauthn.ts +0 -147
  472. package/src/routes/workflows.ts +0 -157
  473. package/src/sdk/index.ts +0 -152
  474. package/src/sdk/types.ts +0 -54
  475. package/src/services/anomalyDetection.ts +0 -73
  476. package/src/services/application/authentication.ts +0 -75
  477. package/src/services/application/identity.ts +0 -56
  478. package/src/services/application/index.ts +0 -3
  479. package/src/services/application/organization.ts +0 -77
  480. package/src/services/applications.ts +0 -89
  481. package/src/services/audit.ts +0 -41
  482. package/src/services/auditExport.ts +0 -59
  483. package/src/services/billing.ts +0 -87
  484. package/src/services/cache.ts +0 -131
  485. package/src/services/configuration/profiles.ts +0 -115
  486. package/src/services/configuration.ts +0 -120
  487. package/src/services/connectors/google.ts +0 -92
  488. package/src/services/connectors/oidc.ts +0 -111
  489. package/src/services/connectors/registry.ts +0 -124
  490. package/src/services/connectors/types.ts +0 -38
  491. package/src/services/connectors/zitadel.ts +0 -77
  492. package/src/services/devices.ts +0 -76
  493. package/src/services/domain/authentication.ts +0 -279
  494. package/src/services/domain/authorization.ts +0 -49
  495. package/src/services/domain/identity.ts +0 -108
  496. package/src/services/domain/index.ts +0 -4
  497. package/src/services/domain/organization.ts +0 -114
  498. package/src/services/email.ts +0 -167
  499. package/src/services/emailVerification.ts +0 -75
  500. package/src/services/enterpriseSso.ts +0 -58
  501. package/src/services/events/bus.ts +0 -43
  502. package/src/services/events/subscribers/anomaly.ts +0 -13
  503. package/src/services/events/subscribers/auditLog.ts +0 -21
  504. package/src/services/events/subscribers/webhook.ts +0 -39
  505. package/src/services/events/subscribers/webhookDispatch.ts +0 -14
  506. package/src/services/events/types.ts +0 -106
  507. package/src/services/events/validate.ts +0 -118
  508. package/src/services/featureFlags.ts +0 -90
  509. package/src/services/features.ts +0 -22
  510. package/src/services/federation.ts +0 -30
  511. package/src/services/hibp.ts +0 -28
  512. package/src/services/ipControls.ts +0 -99
  513. package/src/services/magicLinks.ts +0 -51
  514. package/src/services/oauth2.ts +0 -216
  515. package/src/services/organizations.ts +0 -171
  516. package/src/services/permissions.ts +0 -146
  517. package/src/services/plugins/registry.ts +0 -242
  518. package/src/services/plugins/types.ts +0 -98
  519. package/src/services/queue/bullmq.ts +0 -104
  520. package/src/services/queue/inProcess.ts +0 -75
  521. package/src/services/queue/index.ts +0 -19
  522. package/src/services/queue/types.ts +0 -26
  523. package/src/services/redis.ts +0 -16
  524. package/src/services/secrets/awsKms.ts +0 -97
  525. package/src/services/secrets/azureKeyVault.ts +0 -171
  526. package/src/services/secrets/database.ts +0 -166
  527. package/src/services/secrets/environment.ts +0 -117
  528. package/src/services/secrets/index.ts +0 -50
  529. package/src/services/secrets/password.ts +0 -73
  530. package/src/services/secrets/provider.ts +0 -36
  531. package/src/services/secrets/vault.ts +0 -149
  532. package/src/services/secrets.ts +0 -2
  533. package/src/services/serviceAccounts.ts +0 -74
  534. package/src/services/setup/configWriter.ts +0 -200
  535. package/src/services/setup/diagnostics.ts +0 -76
  536. package/src/services/setup/token.ts +0 -42
  537. package/src/services/setup/types.ts +0 -40
  538. package/src/services/setup/validation.ts +0 -205
  539. package/src/services/sms.ts +0 -81
  540. package/src/services/smsOtp.ts +0 -74
  541. package/src/services/tokens.ts +0 -287
  542. package/src/services/totp.ts +0 -113
  543. package/src/services/users.ts +0 -239
  544. package/src/services/webauthn.ts +0 -193
  545. package/src/services/webhooks.ts +0 -190
  546. package/src/services/workflows/engine.ts +0 -125
  547. package/src/services/workflows/steps.ts +0 -129
  548. package/src/services/zitadel.ts +0 -277
  549. package/src/setup-server.ts +0 -71
  550. package/src/tests/errors.test.ts +0 -74
  551. package/src/tests/events.test.ts +0 -52
  552. package/src/tests/featureFlags.test.ts +0 -26
  553. package/src/tests/integration/queue.test.ts +0 -54
  554. package/src/tests/plugins.test.ts +0 -73
  555. package/src/tests/result.test.ts +0 -52
  556. package/src/tests/setup/configWriter.test.ts +0 -69
  557. package/src/tests/setup/validation.test.ts +0 -29
  558. package/src/tests/smoke.test.ts +0 -136
  559. package/src/types.ts +0 -70
@@ -1,214 +0,0 @@
1
- import { z } from "zod";
2
- import type { FastifyInstance } from "fastify";
3
- import { getSdk } from "../sdk/index.js";
4
- import {
5
- setSessionCookies,
6
- clearSessionCookies,
7
- getRefreshToken,
8
- } from "../plugins/auth.js";
9
- import { rateLimit } from "../plugins/rateLimit.js";
10
- import { checkImpossibleTravel } from "../services/anomalyDetection.js";
11
- import { sendSuspiciousLoginAlert } from "../services/email.js";
12
- import { checkIpAllowed } from "../services/ipControls.js";
13
- import { toPublicUser } from "../types.js";
14
- import { verifyTOTP } from "../services/totp.js";
15
- import { sendResultError } from "./helpers.js";
16
-
17
- /**
18
- * Fire-and-forget impossible-travel check after a successful login.
19
- * Emits a suspicious-login email when the user's previous login came from a
20
- * different IP within the anomaly window.
21
- */
22
- function detectImpossibleTravel(user: { id: string; email: string }, ip?: string, userAgent?: string): void {
23
- checkImpossibleTravel(user.id, ip)
24
- .then(async (suspicious) => {
25
- if (!suspicious) return;
26
- await sendSuspiciousLoginAlert({
27
- email: user.email,
28
- ipAddress: ip,
29
- userAgent,
30
- reason: "Sign-in from a new location within minutes of the previous one",
31
- });
32
- })
33
- .catch((err: unknown) => {
34
- console.error("[anomaly] impossible-travel check failed:", err);
35
- });
36
- }
37
-
38
- const RegisterSchema = z.object({
39
- username: z.string().min(3).max(32).regex(/^[a-zA-Z0-9_-]+$/),
40
- email: z.string().email().max(255),
41
- password: z.string().min(8).max(128),
42
- name: z.string().max(255).optional(),
43
- client_id: z.string().optional(),
44
- metadata: z.record(z.string(), z.unknown()).optional(),
45
- });
46
-
47
- const LoginSchema = z.object({
48
- email: z.string().email().max(255),
49
- password: z.string().min(1).max(128),
50
- client_id: z.string().optional(),
51
- totp_code: z.string().min(6).max(8).optional(),
52
- });
53
-
54
- const RefreshSchema = z.object({
55
- client_id: z.string().optional(),
56
- });
57
-
58
- export default async function authRoutes(app: FastifyInstance) {
59
- const sdk = getSdk();
60
-
61
- app.post(
62
- "/register",
63
- {
64
- preHandler: [
65
- rateLimit({
66
- keyPrefix: "register",
67
- maxAttempts: 5,
68
- windowSeconds: 900,
69
- }),
70
- ],
71
- },
72
- async (request, reply) => {
73
- const body = RegisterSchema.parse(request.body);
74
-
75
- const ipCheck = await checkIpAllowed(body.client_id, request.ip);
76
- if (!ipCheck.allowed) {
77
- return reply.status(403).send({ error: ipCheck.reason, code: "IP_NOT_ALLOWED" });
78
- }
79
-
80
- const result = await sdk.authentication.register({
81
- username: body.username,
82
- email: body.email,
83
- password: body.password,
84
- name: body.name,
85
- clientId: body.client_id,
86
- metadata: body.metadata,
87
- });
88
-
89
- if (!result.success) return sendResultError(reply, result);
90
-
91
- await request.audit("user_registered", { userId: result.data.user.id, email: result.data.user.email });
92
- setSessionCookies(reply, result.data.accessToken, result.data.refreshToken, body.client_id);
93
- return { user: toPublicUser(result.data.user) };
94
- }
95
- );
96
-
97
- app.post(
98
- "/login",
99
- {
100
- preHandler: [
101
- rateLimit({
102
- keyPrefix: "login",
103
- maxAttempts: 5,
104
- windowSeconds: 900,
105
- }),
106
- ],
107
- },
108
- async (request, reply) => {
109
- const body = LoginSchema.parse(request.body);
110
-
111
- const ipCheck = await checkIpAllowed(body.client_id, request.ip);
112
- if (!ipCheck.allowed) {
113
- return reply.status(403).send({ error: ipCheck.reason, code: "IP_NOT_ALLOWED" });
114
- }
115
-
116
- const result = await sdk.authentication.login({
117
- email: body.email,
118
- password: body.password,
119
- clientId: body.client_id,
120
- });
121
-
122
- if (!result.success) return sendResultError(reply, result);
123
-
124
- if (body.totp_code) {
125
- const validTotp = await verifyTOTP(result.data.user.id, body.totp_code);
126
- if (!validTotp) {
127
- return reply.status(401).send({ error: "Invalid two-factor code." });
128
- }
129
- }
130
-
131
- await request.audit("user_login", { userId: result.data.user.id });
132
- detectImpossibleTravel(result.data.user, request.ip, request.headers["user-agent"]);
133
- setSessionCookies(reply, result.data.accessToken, result.data.refreshToken, body.client_id);
134
- return { user: toPublicUser(result.data.user) };
135
- }
136
- );
137
-
138
- app.post(
139
- "/token-login",
140
- {
141
- preHandler: [
142
- rateLimit({
143
- keyPrefix: "login",
144
- maxAttempts: 5,
145
- windowSeconds: 900,
146
- }),
147
- ],
148
- },
149
- async (request, reply) => {
150
- const body = LoginSchema.parse(request.body);
151
-
152
- const ipCheck = await checkIpAllowed(body.client_id, request.ip);
153
- if (!ipCheck.allowed) {
154
- return reply.status(403).send({ error: ipCheck.reason, code: "IP_NOT_ALLOWED" });
155
- }
156
-
157
- const result = await sdk.authentication.login({
158
- email: body.email,
159
- password: body.password,
160
- clientId: body.client_id,
161
- });
162
-
163
- if (!result.success) return sendResultError(reply, result);
164
-
165
- if (body.totp_code) {
166
- const validTotp = await verifyTOTP(result.data.user.id, body.totp_code);
167
- if (!validTotp) {
168
- return reply.status(401).send({ error: "Invalid two-factor code." });
169
- }
170
- }
171
-
172
- await request.audit("user_token_login", { userId: result.data.user.id });
173
- detectImpossibleTravel(result.data.user, request.ip, request.headers["user-agent"]);
174
- return {
175
- accessToken: result.data.accessToken,
176
- user: toPublicUser(result.data.user),
177
- };
178
- }
179
- );
180
-
181
- app.get("/me", { preHandler: [app.authenticate] }, async (request) => {
182
- return { user: request.user ? toPublicUser(request.user) : null };
183
- });
184
-
185
- app.post("/refresh", async (request, reply) => {
186
- const body = RefreshSchema.parse(request.body ?? {});
187
- const clientId = body.client_id;
188
-
189
- const refreshToken = getRefreshToken(request, clientId) || getRefreshToken(request);
190
- if (!refreshToken) {
191
- return reply.status(401).send({ error: "Unauthorized" });
192
- }
193
-
194
- const result = await sdk.authentication.refresh(refreshToken, clientId);
195
- if (!result.success) return sendResultError(reply, result);
196
-
197
- await request.audit("token_refresh", {});
198
- setSessionCookies(reply, result.data.accessToken, result.data.refreshToken, clientId);
199
- return { success: true };
200
- });
201
-
202
- app.post("/logout", async (request, reply) => {
203
- const appClientId = request.state?.app?.clientId;
204
- const refreshToken =
205
- getRefreshToken(request, appClientId) || getRefreshToken(request);
206
- const result = await sdk.authentication.logout(refreshToken);
207
- if (!result.success) return sendResultError(reply, result);
208
-
209
- await request.audit("user_logout", { userId: request.user?.id });
210
- clearSessionCookies(reply, appClientId);
211
- clearSessionCookies(reply);
212
- return { success: true };
213
- });
214
- }
@@ -1,38 +0,0 @@
1
- import { z } from "zod";
2
- import type { FastifyInstance, FastifyRequest, FastifyReply } from "fastify";
3
- import { getSdk } from "../sdk/index.js";
4
-
5
- const CheckSchema = z.object({
6
- resource: z.string().min(1),
7
- action: z.string().min(1),
8
- });
9
-
10
- export default async function authzRoutes(app: FastifyInstance) {
11
- const sdk = getSdk();
12
-
13
- app.post(
14
- "/authz/check",
15
- { preHandler: [app.authenticate] },
16
- async (request: FastifyRequest, reply: FastifyReply) => {
17
- const body = CheckSchema.parse(request.body);
18
- const membership = request.state?.membership;
19
-
20
- if (!membership) {
21
- return reply.status(403).send({
22
- allowed: false,
23
- reason: "No organization context",
24
- });
25
- }
26
-
27
- const allowed = await sdk.authorization.hasPermission(membership.role, body.resource, body.action);
28
- await request.audit("authz_check", {
29
- resource: body.resource,
30
- action: body.action,
31
- role: membership.role,
32
- allowed,
33
- });
34
-
35
- return { allowed };
36
- }
37
- );
38
- }
@@ -1,67 +0,0 @@
1
- import type { FastifyInstance, FastifyRequest, FastifyReply } from "fastify";
2
- import { z } from "zod";
3
- import { createConfigWriter } from "../services/setup/configWriter.js";
4
- import { queue } from "../services/queue/index.js";
5
-
6
- const UpdateConfigSchema = z.object({
7
- values: z.record(z.string(), z.string()),
8
- });
9
-
10
- async function requireOwner(request: FastifyRequest, reply: FastifyReply) {
11
- await request.server.authenticate(request, reply);
12
- if (reply.sent) return;
13
- if (request.user!.role !== "owner") {
14
- return reply.status(403).send({ error: "Forbidden: owner access required" });
15
- }
16
- }
17
-
18
- export default async function configRoutes(app: FastifyInstance) {
19
- // Read current configuration values from the configured store (.env by default).
20
- app.get("/", { preHandler: [requireOwner] }, async (_request: FastifyRequest, reply: FastifyReply) => {
21
- try {
22
- const writer = createConfigWriter();
23
- const values = await writer.read();
24
- return reply.send({ values });
25
- } catch (err) {
26
- app.log.error({ err }, "Failed to read configuration");
27
- return reply.status(500).send({ error: "Failed to read configuration" });
28
- }
29
- });
30
-
31
- // Update configuration values. A restart is required for most changes to take effect.
32
- app.put("/", { preHandler: [requireOwner] }, async (request: FastifyRequest, reply: FastifyReply) => {
33
- const parsed = UpdateConfigSchema.safeParse(request.body);
34
- if (!parsed.success) {
35
- return reply.status(400).send({ error: "Invalid input", details: parsed.error.issues });
36
- }
37
-
38
- try {
39
- const writer = createConfigWriter();
40
- const backup = await writer.backup();
41
- if (!backup.success) {
42
- return reply.status(500).send({ error: backup.error.message, code: backup.error.code });
43
- }
44
-
45
- const writeResult = await writer.write(parsed.data.values);
46
- if (!writeResult.success) {
47
- return reply.status(500).send({ error: writeResult.error.message, code: writeResult.error.code });
48
- }
49
-
50
- return reply.send({ ok: true, backupPath: backup.data || undefined });
51
- } catch (err) {
52
- request.log.error({ err }, "Failed to update configuration");
53
- return reply.status(500).send({ error: "Failed to update configuration" });
54
- }
55
- });
56
-
57
- // Restart the server so new configuration is loaded.
58
- app.post("/restart", { preHandler: [requireOwner] }, async (_request: FastifyRequest, reply: FastifyReply) => {
59
- reply.status(202).send({ ok: true, message: "Server is restarting" });
60
- try {
61
- await queue.close?.();
62
- } catch {
63
- // ignore
64
- }
65
- setTimeout(() => process.exit(0), 500);
66
- });
67
- }
@@ -1,73 +0,0 @@
1
- import { z } from "zod";
2
- import type { FastifyInstance, FastifyRequest, FastifyReply } from "fastify";
3
- import { findUserByEmail } from "../services/users.js";
4
- import {
5
- sendVerificationEmail,
6
- consumeVerificationToken,
7
- } from "../services/emailVerification.js";
8
- import { rateLimit } from "../plugins/rateLimit.js";
9
-
10
- const SendSchema = z.object({
11
- email: z.string().email(),
12
- });
13
-
14
- export default async function emailVerificationRoutes(app: FastifyInstance) {
15
- // Authenticated: resend the verification email for the signed-in user.
16
- app.post("/email-verification/send", { preHandler: [app.authenticate] }, async (request: FastifyRequest, reply: FastifyReply) => {
17
- const user = request.user;
18
- if (!user) return reply.status(401).send({ error: "Unauthorized" });
19
- if (user.emailVerified) return { success: true, alreadyVerified: true };
20
-
21
- try {
22
- await sendVerificationEmail(user);
23
- } catch (err) {
24
- request.log.error({ err }, "Failed to send verification email");
25
- return reply.status(500).send({ error: "Failed to send verification email" });
26
- }
27
-
28
- await request.audit("email_verification_sent", { userId: user.id });
29
- return { success: true };
30
- });
31
-
32
- // Unauthenticated: request a verification email by address.
33
- // Always returns success to avoid user enumeration.
34
- app.post("/email-verification/request", {
35
- preHandler: [
36
- rateLimit({
37
- keyPrefix: "email-verification",
38
- maxAttempts: 3,
39
- windowSeconds: 900,
40
- }),
41
- ],
42
- }, async (request: FastifyRequest, reply: FastifyReply) => {
43
- const body = SendSchema.parse(request.body);
44
- const user = await findUserByEmail(body.email);
45
- if (!user || user.emailVerified) {
46
- return reply.status(200).send({ success: true });
47
- }
48
-
49
- try {
50
- await sendVerificationEmail(user);
51
- await request.audit("email_verification_sent", { userId: user.id });
52
- } catch (err) {
53
- request.log.error({ err }, "Failed to send verification email");
54
- }
55
-
56
- return { success: true };
57
- });
58
-
59
- app.get("/email-verification/verify", async (request: FastifyRequest, reply: FastifyReply) => {
60
- const query = request.query as { token?: string };
61
- if (!query.token) {
62
- return reply.status(400).send({ error: "Missing token" });
63
- }
64
-
65
- const user = await consumeVerificationToken(query.token);
66
- if (!user) {
67
- return reply.status(400).send({ error: "Invalid or expired token" });
68
- }
69
-
70
- await request.audit("email_verified", { userId: user.id });
71
- return { success: true, email: user.email };
72
- });
73
- }
@@ -1,156 +0,0 @@
1
- import crypto from "node:crypto";
2
- import { z } from "zod";
3
- import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
4
- import { config } from "../config.js";
5
- import { listSupportedProviders, listConfiguredProviders } from "../services/connectors/registry.js";
6
- import { getSdk } from "../sdk/index.js";
7
- import { setSessionCookies, clearSessionCookies } from "../plugins/auth.js";
8
- import { findApplicationByClientId } from "../services/applications.js";
9
- import type { Application } from "../db/schema.js";
10
- import { buildOAuthErrorRedirect, buildOAuthErrorResponse } from "../lib/errors.js";
11
- import { sendResultError } from "./helpers.js";
12
-
13
- function isProvider(value: string): boolean {
14
- return listSupportedProviders().includes(value);
15
- }
16
-
17
- function randomState(): string {
18
- return crypto.randomBytes(24).toString("base64url");
19
- }
20
-
21
- function publicUrl(): string {
22
- return config.AUTH_API_PUBLIC_URL || `http://localhost:${config.PORT}`;
23
- }
24
-
25
- function callbackRedirectUri(provider: string): string {
26
- return `${publicUrl()}/federation/${provider}/callback`;
27
- }
28
-
29
- function setFederationState(reply: FastifyReply, state: string, clientId?: string): void {
30
- reply.setCookie("fed_state", state, {
31
- path: "/",
32
- httpOnly: true,
33
- secure: config.COOKIE_SECURE,
34
- sameSite: "lax" as const,
35
- domain: config.COOKIE_DOMAIN || undefined,
36
- maxAge: 600,
37
- });
38
- if (clientId) {
39
- reply.setCookie("fed_client_id", clientId, {
40
- path: "/",
41
- httpOnly: true,
42
- secure: config.COOKIE_SECURE,
43
- sameSite: "lax" as const,
44
- domain: config.COOKIE_DOMAIN || undefined,
45
- maxAge: 600,
46
- });
47
- }
48
- }
49
-
50
- function clearFederationCookies(reply: FastifyReply): void {
51
- const opts = {
52
- path: "/",
53
- httpOnly: true,
54
- secure: config.COOKIE_SECURE,
55
- sameSite: "lax" as const,
56
- domain: config.COOKIE_DOMAIN || undefined,
57
- };
58
- reply.clearCookie("fed_state", opts);
59
- reply.clearCookie("fed_client_id", opts);
60
- }
61
-
62
- function redirectTargetUrl(clientId?: string, app?: Application): string {
63
- if (app?.redirectUris?.length) return app.redirectUris[0];
64
- return process.env.CLIENT_APP_URL || "http://localhost:5173";
65
- }
66
-
67
- const LinkIdentitySchema = z.object({
68
- providerType: z.string(),
69
- providerId: z.string().uuid(),
70
- externalSub: z.string(),
71
- email: z.string().email().optional(),
72
- });
73
-
74
- export default async function federationRoutes(app: FastifyInstance) {
75
- const sdk = getSdk();
76
-
77
- app.get("/:provider/start", async (request, reply) => {
78
- const { provider } = request.params as { provider: string };
79
- if (!isProvider(provider)) {
80
- return reply.status(400).send({ error: "Unsupported federation provider" });
81
- }
82
- const query = request.query as { client_id?: string; redirect_uri?: string };
83
- const state = randomState();
84
- setFederationState(reply, state, query.client_id);
85
-
86
- try {
87
- const result = await sdk.identity.getFederationAuthorizeUrl(provider, state, callbackRedirectUri(provider));
88
- if (!result.success) return sendResultError(reply, result);
89
- return reply.redirect(result.data.url);
90
- } catch (err) {
91
- request.log.error({ err }, "Federation start failed");
92
- clearFederationCookies(reply);
93
- const { statusCode, body } = buildOAuthErrorResponse(err);
94
- return reply.status(statusCode).send(body);
95
- }
96
- });
97
-
98
- app.get("/:provider/callback", async (request, reply) => {
99
- const { provider } = request.params as { provider: string };
100
- if (!isProvider(provider)) {
101
- return reply.status(400).send({ error: "Unsupported federation provider" });
102
- }
103
-
104
- const { code, state } = request.query as { code?: string; state?: string };
105
- const cookieState = request.cookies.fed_state;
106
- const clientId = request.cookies.fed_client_id;
107
-
108
- if (!code || !state || state !== cookieState) {
109
- clearFederationCookies(reply);
110
- return reply.redirect(`${redirectTargetUrl(clientId)}?error=${encodeURIComponent("Invalid federation state")}`);
111
- }
112
- clearFederationCookies(reply);
113
-
114
- try {
115
- const result = await sdk.identity.completeFederationLogin(provider, code, callbackRedirectUri(provider));
116
- if (!result.success) return sendResultError(reply, result);
117
- const app = clientId ? await findApplicationByClientId(clientId) : undefined;
118
- setSessionCookies(reply, result.data.tokens.accessToken, result.data.tokens.refreshToken, app?.clientId);
119
- return reply.redirect(redirectTargetUrl(clientId, app));
120
- } catch (err) {
121
- request.log.error({ err }, "Federation callback failed");
122
- clearSessionCookies(reply);
123
- const url = buildOAuthErrorRedirect(err, redirectTargetUrl(clientId), { state });
124
- return reply.redirect(url);
125
- }
126
- });
127
-
128
- app.get("/providers", async () => {
129
- return {
130
- providers: listConfiguredProviders(),
131
- };
132
- });
133
-
134
- app.post(
135
- "/link",
136
- { preHandler: [app.authenticate] },
137
- async (request: FastifyRequest, reply) => {
138
- const body = LinkIdentitySchema.parse(request.body);
139
- const result = await sdk.identity.linkUserIdentity(
140
- request.user!.id,
141
- body.providerId,
142
- body.providerType,
143
- body.externalSub,
144
- body.email
145
- );
146
- if (!result.success) return sendResultError(reply, result);
147
- await request.audit("federation_identity_linked", { userId: request.user!.id, providerType: body.providerType, providerId: body.providerId });
148
- return reply.status(201).send({ success: true });
149
- }
150
- );
151
-
152
- app.get("/identities", { preHandler: [app.authenticate] }, async (request: FastifyRequest) => {
153
- const rows = await app.container.identityRepository.listByUserId(request.user!.id);
154
- return { identities: rows };
155
- });
156
- }
@@ -1,17 +0,0 @@
1
- import type { FastifyReply } from "fastify";
2
-
3
- export function sendResultError(reply: FastifyReply, result: { success: false; error: { statusCode?: number; message: string; code: string } }) {
4
- return reply.status(result.error.statusCode ?? 400).send({ error: result.error.message, code: result.error.code });
5
- }
6
-
7
- /**
8
- * Escape special XML characters to prevent XML injection.
9
- */
10
- export function escapeXml(value: string): string {
11
- return value
12
- .replace(/&/g, "&")
13
- .replace(/</g, "&lt;")
14
- .replace(/>/g, "&gt;")
15
- .replace(/"/g, "&quot;")
16
- .replace(/'/g, "&apos;");
17
- }
@@ -1,107 +0,0 @@
1
- import { z } from "zod";
2
- import type { FastifyInstance, FastifyRequest } from "fastify";
3
- import { findUserByEmail } from "../services/users.js";
4
- import {
5
- generateMagicLink,
6
- storeMagicLink,
7
- consumeMagicLink,
8
- magicLinkExpiresAt,
9
- } from "../services/magicLinks.js";
10
- import { createTokenSet } from "../services/tokens.js";
11
- import { fingerprintFromRequest, recordDevice } from "../services/devices.js";
12
- import { setSessionCookies } from "../plugins/auth.js";
13
- import { emailProvider } from "../services/email.js";
14
- import { toPublicUser } from "../types.js";
15
- import { config } from "../config.js";
16
- import { rateLimit } from "../plugins/rateLimit.js";
17
-
18
- const SendSchema = z.object({
19
- email: z.string().email(),
20
- });
21
-
22
- function magicLinkUrl(token: string): string {
23
- // The link lands on the client app (Keystone admin UI or a client
24
- // application), which exchanges the token via the verify endpoint.
25
- const base = process.env.CLIENT_APP_URL || "http://localhost:5173";
26
- return `${base}/#magic-link=${encodeURIComponent(token)}`;
27
- }
28
-
29
- function postLoginRedirect(): string {
30
- return process.env.CLIENT_APP_URL || "http://localhost:5173";
31
- }
32
-
33
- export default async function magicLinkRoutes(app: FastifyInstance) {
34
- app.post("/magic-link/send", {
35
- preHandler: [
36
- rateLimit({
37
- keyPrefix: "magic-link",
38
- maxAttempts: 3,
39
- windowSeconds: 900,
40
- }),
41
- ],
42
- }, async (request, reply) => {
43
- const body = SendSchema.parse(request.body);
44
- const user = await findUserByEmail(body.email);
45
- if (!user) {
46
- return reply.status(200).send({ success: true });
47
- }
48
-
49
- const { token, tokenHash } = generateMagicLink();
50
- await storeMagicLink(user.id, tokenHash, magicLinkExpiresAt());
51
-
52
- try {
53
- const url = magicLinkUrl(token);
54
- const ttlMinutes = Math.round(config.MAGIC_LINK_TTL_SECONDS / 60);
55
- await emailProvider.send({
56
- to: user.email,
57
- subject: "Your sign-in link",
58
- text: `Click the link to sign in:\n\n${url}\n\nThis link expires in ${ttlMinutes} minutes and can only be used once.`,
59
- html: `<p>Click <a href="${url}">here</a> to sign in.</p><p>This link expires in ${ttlMinutes} minutes and can only be used once.</p>`,
60
- });
61
- } catch (err) {
62
- request.log.error({ err }, "Failed to send magic link email");
63
- }
64
-
65
- await request.audit("magic_link_sent", { userId: user.id });
66
-
67
- return { success: true };
68
- });
69
-
70
- app.get("/magic-link/verify", async (request: FastifyRequest, reply) => {
71
- const query = request.query as { token?: string; redirect?: string };
72
- if (!query.token) {
73
- return reply.status(400).send({ error: "Missing token" });
74
- }
75
-
76
- const user = await consumeMagicLink(query.token);
77
- if (!user) {
78
- return reply.status(400).send({ error: "Invalid or expired token" });
79
- }
80
-
81
- const fingerprint = fingerprintFromRequest(request);
82
- await recordDevice(user.id, fingerprint, request.ip, request.headers["user-agent"]);
83
-
84
- const tokens = await createTokenSet(
85
- user,
86
- request.ip,
87
- request.headers["user-agent"],
88
- {},
89
- fingerprint
90
- );
91
- setSessionCookies(reply, tokens.accessToken, tokens.refreshToken);
92
-
93
- await request.audit("magic_link_verified", { userId: user.id });
94
-
95
- // Browser flow: redirect back to the app after setting session cookies.
96
- const accept = request.headers.accept || "";
97
- if (accept.includes("text/html")) {
98
- return reply.redirect(postLoginRedirect());
99
- }
100
-
101
- return {
102
- user: toPublicUser(user),
103
- accessToken: tokens.accessToken,
104
- refreshToken: tokens.refreshToken,
105
- };
106
- });
107
- }