@portaidentity/server 1.7.3 → 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 (494) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/applications/index.d.ts +2 -2
  3. package/dist/applications/index.d.ts.map +1 -1
  4. package/dist/applications/index.js +2 -2
  5. package/dist/applications/index.js.map +1 -1
  6. package/dist/applications/repository.d.ts +49 -4
  7. package/dist/applications/repository.d.ts.map +1 -1
  8. package/dist/applications/repository.js +148 -10
  9. package/dist/applications/repository.js.map +1 -1
  10. package/dist/applications/service.d.ts +35 -17
  11. package/dist/applications/service.d.ts.map +1 -1
  12. package/dist/applications/service.js +144 -35
  13. package/dist/applications/service.js.map +1 -1
  14. package/dist/applications/types.d.ts +1 -1
  15. package/dist/applications/types.d.ts.map +1 -1
  16. package/dist/applications/validators.d.ts +14 -0
  17. package/dist/applications/validators.d.ts.map +1 -0
  18. package/dist/applications/validators.js +14 -0
  19. package/dist/applications/validators.js.map +1 -0
  20. package/dist/auth/effective-branding.d.ts +35 -0
  21. package/dist/auth/effective-branding.d.ts.map +1 -0
  22. package/dist/auth/effective-branding.js +81 -0
  23. package/dist/auth/effective-branding.js.map +1 -0
  24. package/dist/auth/email-service.d.ts +3 -8
  25. package/dist/auth/email-service.d.ts.map +1 -1
  26. package/dist/auth/email-service.js +22 -30
  27. package/dist/auth/email-service.js.map +1 -1
  28. package/dist/auth/i18n.d.ts +5 -0
  29. package/dist/auth/i18n.d.ts.map +1 -1
  30. package/dist/auth/i18n.js +6 -5
  31. package/dist/auth/i18n.js.map +1 -1
  32. package/dist/auth/rate-limiter.d.ts +6 -10
  33. package/dist/auth/rate-limiter.d.ts.map +1 -1
  34. package/dist/auth/rate-limiter.js +12 -16
  35. package/dist/auth/rate-limiter.js.map +1 -1
  36. package/dist/auth/recovery-job-processor.d.ts.map +1 -1
  37. package/dist/auth/recovery-job-processor.js +1 -1
  38. package/dist/auth/recovery-job-processor.js.map +1 -1
  39. package/dist/auth/template-engine.d.ts +3 -1
  40. package/dist/auth/template-engine.d.ts.map +1 -1
  41. package/dist/auth/template-engine.js +1 -1
  42. package/dist/auth/template-engine.js.map +1 -1
  43. package/dist/auth/token-repository.d.ts +9 -3
  44. package/dist/auth/token-repository.d.ts.map +1 -1
  45. package/dist/auth/token-repository.js +17 -8
  46. package/dist/auth/token-repository.js.map +1 -1
  47. package/dist/cli/commands/init.d.ts +1 -1
  48. package/dist/cli/commands/init.d.ts.map +1 -1
  49. package/dist/cli/commands/init.js +12 -12
  50. package/dist/cli/commands/init.js.map +1 -1
  51. package/dist/cli/error-handler.d.ts +3 -2
  52. package/dist/cli/error-handler.d.ts.map +1 -1
  53. package/dist/cli/error-handler.js +9 -2
  54. package/dist/cli/error-handler.js.map +1 -1
  55. package/dist/cli/index.d.ts +1 -1
  56. package/dist/cli/index.d.ts.map +1 -1
  57. package/dist/cli/index.js +1 -1
  58. package/dist/cli/index.js.map +1 -1
  59. package/dist/clients/index.d.ts +1 -1
  60. package/dist/clients/index.js +1 -1
  61. package/dist/clients/repository.d.ts +24 -0
  62. package/dist/clients/repository.d.ts.map +1 -1
  63. package/dist/clients/repository.js +39 -0
  64. package/dist/clients/repository.js.map +1 -1
  65. package/dist/clients/secret-repository.d.ts +35 -8
  66. package/dist/clients/secret-repository.d.ts.map +1 -1
  67. package/dist/clients/secret-repository.js +69 -16
  68. package/dist/clients/secret-repository.js.map +1 -1
  69. package/dist/clients/secret-service.d.ts +5 -9
  70. package/dist/clients/secret-service.d.ts.map +1 -1
  71. package/dist/clients/secret-service.js +13 -22
  72. package/dist/clients/secret-service.js.map +1 -1
  73. package/dist/clients/service.d.ts +10 -13
  74. package/dist/clients/service.d.ts.map +1 -1
  75. package/dist/clients/service.js +121 -42
  76. package/dist/clients/service.js.map +1 -1
  77. package/dist/clients/types.d.ts +14 -1
  78. package/dist/clients/types.d.ts.map +1 -1
  79. package/dist/clients/types.js +1 -0
  80. package/dist/clients/types.js.map +1 -1
  81. package/dist/clients/validators.d.ts +83 -1
  82. package/dist/clients/validators.d.ts.map +1 -1
  83. package/dist/clients/validators.js +110 -0
  84. package/dist/clients/validators.js.map +1 -1
  85. package/dist/config/index.d.ts +1 -0
  86. package/dist/config/index.d.ts.map +1 -1
  87. package/dist/config/index.js +1 -0
  88. package/dist/config/index.js.map +1 -1
  89. package/dist/config/schema.d.ts +1 -0
  90. package/dist/config/schema.d.ts.map +1 -1
  91. package/dist/config/schema.js +23 -1
  92. package/dist/config/schema.js.map +1 -1
  93. package/dist/custom-claims/repository.d.ts +14 -9
  94. package/dist/custom-claims/repository.d.ts.map +1 -1
  95. package/dist/custom-claims/repository.js +38 -11
  96. package/dist/custom-claims/repository.js.map +1 -1
  97. package/dist/custom-claims/service.d.ts +11 -6
  98. package/dist/custom-claims/service.d.ts.map +1 -1
  99. package/dist/custom-claims/service.js +43 -20
  100. package/dist/custom-claims/service.js.map +1 -1
  101. package/dist/index.js +8 -2
  102. package/dist/index.js.map +1 -1
  103. package/dist/lib/admin-permissions.d.ts +12 -7
  104. package/dist/lib/admin-permissions.d.ts.map +1 -1
  105. package/dist/lib/admin-permissions.js +26 -16
  106. package/dist/lib/admin-permissions.js.map +1 -1
  107. package/dist/lib/audit-log.d.ts +2 -2
  108. package/dist/lib/audit-log.d.ts.map +1 -1
  109. package/dist/lib/audit-log.js +1 -1
  110. package/dist/lib/audit-log.js.map +1 -1
  111. package/dist/lib/authority-revocation.d.ts +18 -0
  112. package/dist/lib/authority-revocation.d.ts.map +1 -0
  113. package/dist/lib/authority-revocation.js +37 -0
  114. package/dist/lib/authority-revocation.js.map +1 -0
  115. package/dist/lib/branding-assets.d.ts +35 -5
  116. package/dist/lib/branding-assets.d.ts.map +1 -1
  117. package/dist/lib/branding-assets.js +33 -26
  118. package/dist/lib/branding-assets.js.map +1 -1
  119. package/dist/lib/bulk-operations.d.ts +1 -1
  120. package/dist/lib/bulk-operations.d.ts.map +1 -1
  121. package/dist/lib/bulk-operations.js +1 -13
  122. package/dist/lib/bulk-operations.js.map +1 -1
  123. package/dist/lib/cursor.d.ts +2 -0
  124. package/dist/lib/cursor.d.ts.map +1 -1
  125. package/dist/lib/cursor.js +2 -7
  126. package/dist/lib/cursor.js.map +1 -1
  127. package/dist/lib/database.d.ts.map +1 -1
  128. package/dist/lib/database.js +5 -0
  129. package/dist/lib/database.js.map +1 -1
  130. package/dist/lib/deletion-cleanup.d.ts +43 -0
  131. package/dist/lib/deletion-cleanup.d.ts.map +1 -0
  132. package/dist/lib/deletion-cleanup.js +207 -0
  133. package/dist/lib/deletion-cleanup.js.map +1 -0
  134. package/dist/lib/image-validator.d.ts +3 -1
  135. package/dist/lib/image-validator.d.ts.map +1 -1
  136. package/dist/lib/image-validator.js +32 -19
  137. package/dist/lib/image-validator.js.map +1 -1
  138. package/dist/lib/log-format.d.ts +20 -0
  139. package/dist/lib/log-format.d.ts.map +1 -0
  140. package/dist/lib/log-format.js +22 -0
  141. package/dist/lib/log-format.js.map +1 -0
  142. package/dist/lib/logger.d.ts +3 -1
  143. package/dist/lib/logger.d.ts.map +1 -1
  144. package/dist/lib/logger.js +21 -4
  145. package/dist/lib/logger.js.map +1 -1
  146. package/dist/lib/redis.d.ts.map +1 -1
  147. package/dist/lib/redis.js +3 -0
  148. package/dist/lib/redis.js.map +1 -1
  149. package/dist/lib/session-tracking.d.ts +73 -11
  150. package/dist/lib/session-tracking.d.ts.map +1 -1
  151. package/dist/lib/session-tracking.js +76 -32
  152. package/dist/lib/session-tracking.js.map +1 -1
  153. package/dist/lib/signing-key-crypto.d.ts.map +1 -1
  154. package/dist/lib/signing-key-crypto.js +4 -5
  155. package/dist/lib/signing-key-crypto.js.map +1 -1
  156. package/dist/lib/signing-keys.d.ts +3 -4
  157. package/dist/lib/signing-keys.d.ts.map +1 -1
  158. package/dist/lib/signing-keys.js +66 -41
  159. package/dist/lib/signing-keys.js.map +1 -1
  160. package/dist/lib/super-admin-protection.d.ts +5 -5
  161. package/dist/lib/super-admin-protection.d.ts.map +1 -1
  162. package/dist/lib/super-admin-protection.js +6 -9
  163. package/dist/lib/super-admin-protection.js.map +1 -1
  164. package/dist/lib/system-config-catalog.d.ts +268 -0
  165. package/dist/lib/system-config-catalog.d.ts.map +1 -0
  166. package/dist/lib/system-config-catalog.js +90 -0
  167. package/dist/lib/system-config-catalog.js.map +1 -0
  168. package/dist/lib/system-config.d.ts +30 -33
  169. package/dist/lib/system-config.d.ts.map +1 -1
  170. package/dist/lib/system-config.js +78 -93
  171. package/dist/lib/system-config.js.map +1 -1
  172. package/dist/lib/with-timeout.d.ts +32 -0
  173. package/dist/lib/with-timeout.d.ts.map +1 -0
  174. package/dist/lib/with-timeout.js +45 -0
  175. package/dist/lib/with-timeout.js.map +1 -0
  176. package/dist/middleware/admin-auth.d.ts +6 -5
  177. package/dist/middleware/admin-auth.d.ts.map +1 -1
  178. package/dist/middleware/admin-auth.js +30 -20
  179. package/dist/middleware/admin-auth.js.map +1 -1
  180. package/dist/middleware/admin-cors.d.ts +3 -3
  181. package/dist/middleware/admin-cors.js +3 -3
  182. package/dist/middleware/admin-mutation-audit.d.ts +3 -2
  183. package/dist/middleware/admin-mutation-audit.d.ts.map +1 -1
  184. package/dist/middleware/admin-mutation-audit.js +12 -5
  185. package/dist/middleware/admin-mutation-audit.js.map +1 -1
  186. package/dist/middleware/admin-rate-limiter.d.ts +7 -8
  187. package/dist/middleware/admin-rate-limiter.d.ts.map +1 -1
  188. package/dist/middleware/admin-rate-limiter.js +7 -8
  189. package/dist/middleware/admin-rate-limiter.js.map +1 -1
  190. package/dist/middleware/client-secret-hash.d.ts +10 -29
  191. package/dist/middleware/client-secret-hash.d.ts.map +1 -1
  192. package/dist/middleware/client-secret-hash.js +161 -59
  193. package/dist/middleware/client-secret-hash.js.map +1 -1
  194. package/dist/middleware/health.d.ts +17 -0
  195. package/dist/middleware/health.d.ts.map +1 -1
  196. package/dist/middleware/health.js +25 -21
  197. package/dist/middleware/health.js.map +1 -1
  198. package/dist/middleware/ready.d.ts.map +1 -1
  199. package/dist/middleware/ready.js +1 -12
  200. package/dist/middleware/ready.js.map +1 -1
  201. package/dist/middleware/require-existing-organization.d.ts +18 -0
  202. package/dist/middleware/require-existing-organization.d.ts.map +1 -0
  203. package/dist/middleware/require-existing-organization.js +38 -0
  204. package/dist/middleware/require-existing-organization.js.map +1 -0
  205. package/dist/middleware/require-permission.d.ts.map +1 -1
  206. package/dist/middleware/require-permission.js +35 -1
  207. package/dist/middleware/require-permission.js.map +1 -1
  208. package/dist/middleware/require-user-organization.d.ts.map +1 -1
  209. package/dist/middleware/require-user-organization.js +4 -2
  210. package/dist/middleware/require-user-organization.js.map +1 -1
  211. package/dist/middleware/security-headers.d.ts +18 -0
  212. package/dist/middleware/security-headers.d.ts.map +1 -1
  213. package/dist/middleware/security-headers.js +32 -1
  214. package/dist/middleware/security-headers.js.map +1 -1
  215. package/dist/middleware/tenant-resolver.d.ts +1 -2
  216. package/dist/middleware/tenant-resolver.d.ts.map +1 -1
  217. package/dist/middleware/tenant-resolver.js +1 -5
  218. package/dist/middleware/tenant-resolver.js.map +1 -1
  219. package/dist/middleware/token-rate-limiter.d.ts +37 -16
  220. package/dist/middleware/token-rate-limiter.d.ts.map +1 -1
  221. package/dist/middleware/token-rate-limiter.js +126 -54
  222. package/dist/middleware/token-rate-limiter.js.map +1 -1
  223. package/dist/oidc/account-finder.d.ts +5 -5
  224. package/dist/oidc/account-finder.d.ts.map +1 -1
  225. package/dist/oidc/account-finder.js +31 -23
  226. package/dist/oidc/account-finder.js.map +1 -1
  227. package/dist/oidc/adapter-factory.d.ts.map +1 -1
  228. package/dist/oidc/adapter-factory.js +83 -3
  229. package/dist/oidc/adapter-factory.js.map +1 -1
  230. package/dist/oidc/configuration.d.ts +3 -8
  231. package/dist/oidc/configuration.d.ts.map +1 -1
  232. package/dist/oidc/configuration.js +67 -50
  233. package/dist/oidc/configuration.js.map +1 -1
  234. package/dist/oidc/provider.d.ts.map +1 -1
  235. package/dist/oidc/provider.js +7 -0
  236. package/dist/oidc/provider.js.map +1 -1
  237. package/dist/oidc/redis-adapter.d.ts +2 -3
  238. package/dist/oidc/redis-adapter.d.ts.map +1 -1
  239. package/dist/oidc/redis-adapter.js +54 -46
  240. package/dist/oidc/redis-adapter.js.map +1 -1
  241. package/dist/organizations/branding-url.d.ts +17 -0
  242. package/dist/organizations/branding-url.d.ts.map +1 -0
  243. package/dist/organizations/branding-url.js +38 -0
  244. package/dist/organizations/branding-url.js.map +1 -0
  245. package/dist/organizations/index.d.ts +2 -2
  246. package/dist/organizations/index.d.ts.map +1 -1
  247. package/dist/organizations/index.js +1 -1
  248. package/dist/organizations/index.js.map +1 -1
  249. package/dist/organizations/repository.d.ts +22 -32
  250. package/dist/organizations/repository.d.ts.map +1 -1
  251. package/dist/organizations/repository.js +64 -45
  252. package/dist/organizations/repository.js.map +1 -1
  253. package/dist/organizations/service.d.ts +14 -46
  254. package/dist/organizations/service.d.ts.map +1 -1
  255. package/dist/organizations/service.js +60 -112
  256. package/dist/organizations/service.js.map +1 -1
  257. package/dist/organizations/types.d.ts +1 -15
  258. package/dist/organizations/types.d.ts.map +1 -1
  259. package/dist/organizations/validators.d.ts +41 -0
  260. package/dist/organizations/validators.d.ts.map +1 -0
  261. package/dist/organizations/validators.js +48 -0
  262. package/dist/organizations/validators.js.map +1 -0
  263. package/dist/portability/apply.d.ts +15 -0
  264. package/dist/portability/apply.d.ts.map +1 -0
  265. package/dist/portability/apply.js +274 -0
  266. package/dist/portability/apply.js.map +1 -0
  267. package/dist/portability/authorization.d.ts +30 -0
  268. package/dist/portability/authorization.d.ts.map +1 -0
  269. package/dist/portability/authorization.js +130 -0
  270. package/dist/portability/authorization.js.map +1 -0
  271. package/dist/portability/cleanup.d.ts +29 -0
  272. package/dist/portability/cleanup.d.ts.map +1 -0
  273. package/dist/portability/cleanup.js +167 -0
  274. package/dist/portability/cleanup.js.map +1 -0
  275. package/dist/portability/export.d.ts +18 -0
  276. package/dist/portability/export.d.ts.map +1 -0
  277. package/dist/portability/export.js +125 -0
  278. package/dist/portability/export.js.map +1 -0
  279. package/dist/portability/import-repository.d.ts +204 -0
  280. package/dist/portability/import-repository.d.ts.map +1 -0
  281. package/dist/portability/import-repository.js +348 -0
  282. package/dist/portability/import-repository.js.map +1 -0
  283. package/dist/portability/import-user-client-writers.d.ts +40 -0
  284. package/dist/portability/import-user-client-writers.d.ts.map +1 -0
  285. package/dist/portability/import-user-client-writers.js +171 -0
  286. package/dist/portability/import-user-client-writers.js.map +1 -0
  287. package/dist/portability/index.d.ts +8 -0
  288. package/dist/portability/index.d.ts.map +1 -0
  289. package/dist/portability/index.js +8 -0
  290. package/dist/portability/index.js.map +1 -0
  291. package/dist/portability/plan-support.d.ts +137 -0
  292. package/dist/portability/plan-support.d.ts.map +1 -0
  293. package/dist/portability/plan-support.js +337 -0
  294. package/dist/portability/plan-support.js.map +1 -0
  295. package/dist/portability/plan.d.ts +34 -0
  296. package/dist/portability/plan.d.ts.map +1 -0
  297. package/dist/portability/plan.js +450 -0
  298. package/dist/portability/plan.js.map +1 -0
  299. package/dist/portability/repository.d.ts +95 -0
  300. package/dist/portability/repository.d.ts.map +1 -0
  301. package/dist/portability/repository.js +390 -0
  302. package/dist/portability/repository.js.map +1 -0
  303. package/dist/portability/schema.d.ts +591 -0
  304. package/dist/portability/schema.d.ts.map +1 -0
  305. package/dist/portability/schema.js +459 -0
  306. package/dist/portability/schema.js.map +1 -0
  307. package/dist/portability/types.d.ts +382 -0
  308. package/dist/portability/types.d.ts.map +1 -0
  309. package/dist/portability/types.js +19 -0
  310. package/dist/portability/types.js.map +1 -0
  311. package/dist/rbac/errors.d.ts +4 -0
  312. package/dist/rbac/errors.d.ts.map +1 -1
  313. package/dist/rbac/errors.js +7 -0
  314. package/dist/rbac/errors.js.map +1 -1
  315. package/dist/rbac/index.d.ts +3 -3
  316. package/dist/rbac/index.d.ts.map +1 -1
  317. package/dist/rbac/index.js +3 -3
  318. package/dist/rbac/index.js.map +1 -1
  319. package/dist/rbac/mapping-repository.d.ts +84 -9
  320. package/dist/rbac/mapping-repository.d.ts.map +1 -1
  321. package/dist/rbac/mapping-repository.js +222 -55
  322. package/dist/rbac/mapping-repository.js.map +1 -1
  323. package/dist/rbac/permission-repository.d.ts +36 -19
  324. package/dist/rbac/permission-repository.d.ts.map +1 -1
  325. package/dist/rbac/permission-repository.js +93 -35
  326. package/dist/rbac/permission-repository.js.map +1 -1
  327. package/dist/rbac/permission-service.d.ts +18 -19
  328. package/dist/rbac/permission-service.d.ts.map +1 -1
  329. package/dist/rbac/permission-service.js +100 -57
  330. package/dist/rbac/permission-service.js.map +1 -1
  331. package/dist/rbac/role-repository.d.ts +29 -24
  332. package/dist/rbac/role-repository.d.ts.map +1 -1
  333. package/dist/rbac/role-repository.js +66 -43
  334. package/dist/rbac/role-repository.js.map +1 -1
  335. package/dist/rbac/role-service.d.ts +35 -32
  336. package/dist/rbac/role-service.d.ts.map +1 -1
  337. package/dist/rbac/role-service.js +210 -96
  338. package/dist/rbac/role-service.js.map +1 -1
  339. package/dist/rbac/slugs.d.ts +16 -27
  340. package/dist/rbac/slugs.d.ts.map +1 -1
  341. package/dist/rbac/slugs.js +36 -59
  342. package/dist/rbac/slugs.js.map +1 -1
  343. package/dist/rbac/types.d.ts +2 -4
  344. package/dist/rbac/types.d.ts.map +1 -1
  345. package/dist/rbac/types.js.map +1 -1
  346. package/dist/rbac/user-role-service.d.ts +23 -24
  347. package/dist/rbac/user-role-service.d.ts.map +1 -1
  348. package/dist/rbac/user-role-service.js +117 -61
  349. package/dist/rbac/user-role-service.js.map +1 -1
  350. package/dist/routes/applications.d.ts +4 -2
  351. package/dist/routes/applications.d.ts.map +1 -1
  352. package/dist/routes/applications.js +57 -19
  353. package/dist/routes/applications.js.map +1 -1
  354. package/dist/routes/audit.js +1 -1
  355. package/dist/routes/audit.js.map +1 -1
  356. package/dist/routes/branding.d.ts +3 -3
  357. package/dist/routes/branding.d.ts.map +1 -1
  358. package/dist/routes/branding.js +44 -16
  359. package/dist/routes/branding.js.map +1 -1
  360. package/dist/routes/bulk.d.ts +0 -5
  361. package/dist/routes/bulk.d.ts.map +1 -1
  362. package/dist/routes/bulk.js +3 -5
  363. package/dist/routes/bulk.js.map +1 -1
  364. package/dist/routes/clients.d.ts +4 -4
  365. package/dist/routes/clients.d.ts.map +1 -1
  366. package/dist/routes/clients.js +113 -52
  367. package/dist/routes/clients.js.map +1 -1
  368. package/dist/routes/config.d.ts +17 -12
  369. package/dist/routes/config.d.ts.map +1 -1
  370. package/dist/routes/config.js +165 -64
  371. package/dist/routes/config.js.map +1 -1
  372. package/dist/routes/custom-claims.d.ts.map +1 -1
  373. package/dist/routes/custom-claims.js +8 -2
  374. package/dist/routes/custom-claims.js.map +1 -1
  375. package/dist/routes/exports.d.ts +2 -1
  376. package/dist/routes/exports.d.ts.map +1 -1
  377. package/dist/routes/exports.js +57 -1
  378. package/dist/routes/exports.js.map +1 -1
  379. package/dist/routes/imports.d.ts +2 -2
  380. package/dist/routes/imports.d.ts.map +1 -1
  381. package/dist/routes/imports.js +95 -40
  382. package/dist/routes/imports.js.map +1 -1
  383. package/dist/routes/interactions.d.ts.map +1 -1
  384. package/dist/routes/interactions.js +113 -87
  385. package/dist/routes/interactions.js.map +1 -1
  386. package/dist/routes/invitation.d.ts.map +1 -1
  387. package/dist/routes/invitation.js +28 -27
  388. package/dist/routes/invitation.js.map +1 -1
  389. package/dist/routes/keys.d.ts.map +1 -1
  390. package/dist/routes/keys.js +26 -13
  391. package/dist/routes/keys.js.map +1 -1
  392. package/dist/routes/magic-link.d.ts.map +1 -1
  393. package/dist/routes/magic-link.js +5 -17
  394. package/dist/routes/magic-link.js.map +1 -1
  395. package/dist/routes/organizations.d.ts +1 -2
  396. package/dist/routes/organizations.d.ts.map +1 -1
  397. package/dist/routes/organizations.js +43 -104
  398. package/dist/routes/organizations.js.map +1 -1
  399. package/dist/routes/password-reset.d.ts.map +1 -1
  400. package/dist/routes/password-reset.js +13 -35
  401. package/dist/routes/password-reset.js.map +1 -1
  402. package/dist/routes/permissions.d.ts +1 -1
  403. package/dist/routes/permissions.d.ts.map +1 -1
  404. package/dist/routes/permissions.js +58 -17
  405. package/dist/routes/permissions.js.map +1 -1
  406. package/dist/routes/public-branding.d.ts +16 -0
  407. package/dist/routes/public-branding.d.ts.map +1 -0
  408. package/dist/routes/public-branding.js +52 -0
  409. package/dist/routes/public-branding.js.map +1 -0
  410. package/dist/routes/roles.d.ts +1 -1
  411. package/dist/routes/roles.d.ts.map +1 -1
  412. package/dist/routes/roles.js +63 -21
  413. package/dist/routes/roles.js.map +1 -1
  414. package/dist/routes/sessions.d.ts.map +1 -1
  415. package/dist/routes/sessions.js +23 -12
  416. package/dist/routes/sessions.js.map +1 -1
  417. package/dist/routes/two-factor.d.ts.map +1 -1
  418. package/dist/routes/two-factor.js +91 -38
  419. package/dist/routes/two-factor.js.map +1 -1
  420. package/dist/routes/user-roles.d.ts.map +1 -1
  421. package/dist/routes/user-roles.js +56 -9
  422. package/dist/routes/user-roles.js.map +1 -1
  423. package/dist/routes/users.d.ts +4 -8
  424. package/dist/routes/users.d.ts.map +1 -1
  425. package/dist/routes/users.js +108 -265
  426. package/dist/routes/users.js.map +1 -1
  427. package/dist/server.d.ts.map +1 -1
  428. package/dist/server.js +53 -37
  429. package/dist/server.js.map +1 -1
  430. package/dist/two-factor/errors.d.ts +9 -0
  431. package/dist/two-factor/errors.d.ts.map +1 -1
  432. package/dist/two-factor/errors.js +12 -0
  433. package/dist/two-factor/errors.js.map +1 -1
  434. package/dist/two-factor/index.d.ts +5 -4
  435. package/dist/two-factor/index.d.ts.map +1 -1
  436. package/dist/two-factor/index.js +4 -4
  437. package/dist/two-factor/index.js.map +1 -1
  438. package/dist/two-factor/repository.d.ts +17 -6
  439. package/dist/two-factor/repository.d.ts.map +1 -1
  440. package/dist/two-factor/repository.js +37 -9
  441. package/dist/two-factor/repository.js.map +1 -1
  442. package/dist/two-factor/service.d.ts.map +1 -1
  443. package/dist/two-factor/service.js +26 -19
  444. package/dist/two-factor/service.js.map +1 -1
  445. package/dist/two-factor/totp.d.ts +13 -2
  446. package/dist/two-factor/totp.d.ts.map +1 -1
  447. package/dist/two-factor/totp.js +20 -7
  448. package/dist/two-factor/totp.js.map +1 -1
  449. package/dist/two-factor/types.d.ts +3 -0
  450. package/dist/two-factor/types.d.ts.map +1 -1
  451. package/dist/two-factor/types.js +5 -0
  452. package/dist/two-factor/types.js.map +1 -1
  453. package/dist/users/gdpr.d.ts +2 -40
  454. package/dist/users/gdpr.d.ts.map +1 -1
  455. package/dist/users/gdpr.js +3 -110
  456. package/dist/users/gdpr.js.map +1 -1
  457. package/dist/users/index.d.ts +5 -4
  458. package/dist/users/index.d.ts.map +1 -1
  459. package/dist/users/index.js +5 -4
  460. package/dist/users/index.js.map +1 -1
  461. package/dist/users/repository.d.ts +49 -3
  462. package/dist/users/repository.d.ts.map +1 -1
  463. package/dist/users/repository.js +169 -18
  464. package/dist/users/repository.js.map +1 -1
  465. package/dist/users/service.d.ts +19 -51
  466. package/dist/users/service.d.ts.map +1 -1
  467. package/dist/users/service.js +72 -122
  468. package/dist/users/service.js.map +1 -1
  469. package/dist/users/types.d.ts +4 -5
  470. package/dist/users/types.d.ts.map +1 -1
  471. package/dist/users/types.js.map +1 -1
  472. package/dist/users/validators.d.ts +28 -0
  473. package/dist/users/validators.d.ts.map +1 -0
  474. package/dist/users/validators.js +25 -0
  475. package/dist/users/validators.js.map +1 -0
  476. package/locales/default/en/errors.json +2 -1
  477. package/migrations/024_application_client_correction.sql +39 -0
  478. package/migrations/025_record_deletion_lifecycle.sql +26 -0
  479. package/migrations/026_simplify_user_lifecycle.sql +33 -0
  480. package/migrations/027_branding_asset_size_limits.sql +19 -0
  481. package/migrations/028_totp_replay_protection.sql +17 -0
  482. package/migrations/029_public_session_identifiers.sql +16 -0
  483. package/migrations/030_global_configuration_catalog.sql +39 -0
  484. package/migrations/031_monotonic_updated_at.sql +28 -0
  485. package/migrations/032_client_require_consent.sql +15 -0
  486. package/package.json +2 -2
  487. package/dist/lib/data-import-plan.d.ts +0 -50
  488. package/dist/lib/data-import-plan.d.ts.map +0 -1
  489. package/dist/lib/data-import-plan.js +0 -235
  490. package/dist/lib/data-import-plan.js.map +0 -1
  491. package/dist/lib/data-import.d.ts +0 -276
  492. package/dist/lib/data-import.d.ts.map +0 -1
  493. package/dist/lib/data-import.js +0 -1694
  494. package/dist/lib/data-import.js.map +0 -1
@@ -15,7 +15,37 @@
15
15
  * @module middleware/require-permission
16
16
  */
17
17
  import { hasPermissions } from '../lib/admin-permissions.js';
18
- import { recordSecurityDecision } from '../security/decision-context.js';
18
+ import { recordSecurityDecision, recordSecurityReference } from '../security/decision-context.js';
19
+ /**
20
+ * Route parameter names, in priority order, that identify the target of an
21
+ * administrative action. The most specific identifier wins so the recorded
22
+ * digest names the acted-on resource rather than a generic container.
23
+ */
24
+ const TARGET_PARAMETER_KEYS = ['userId', 'id', 'key', 'type', 'organizationId'];
25
+ /**
26
+ * Resolve the target identifier for a denied administrative action.
27
+ *
28
+ * Entity routes expose the acted-on resource id in a route parameter. List and
29
+ * collection routes have none, so the actor's organization is the acted-on
30
+ * scope. The value is always protected before it reaches any event.
31
+ *
32
+ * @param ctx - Request context carrying the matched route parameters.
33
+ * @returns A raw identifier for privacy-preserving protection, or `undefined`.
34
+ */
35
+ function denialTargetIdentifier(ctx) {
36
+ const params = Reflect.get(ctx, 'params');
37
+ if (params !== undefined) {
38
+ for (const key of TARGET_PARAMETER_KEYS) {
39
+ const value = params[key];
40
+ if (typeof value === 'string' && value.length > 0)
41
+ return value;
42
+ }
43
+ }
44
+ const organizationId = ctx.state.adminUser?.organizationId;
45
+ return typeof organizationId === 'string' && organizationId.length > 0
46
+ ? organizationId
47
+ : undefined;
48
+ }
19
49
  /**
20
50
  * Create middleware that requires specific admin permission(s).
21
51
  *
@@ -50,6 +80,10 @@ export function requirePermission(...requiredPermissions) {
50
80
  outcome: 'deny',
51
81
  detail: { permissions: requiredPermissions },
52
82
  });
83
+ const target = denialTargetIdentifier(ctx);
84
+ if (target !== undefined) {
85
+ recordSecurityReference(ctx, 'resource', target);
86
+ }
53
87
  ctx.status = 403;
54
88
  ctx.body = {
55
89
  error: 'Forbidden',
@@ -1 +1 @@
1
- {"version":3,"file":"require-permission.js","sourceRoot":"","sources":["../../src/middleware/require-permission.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAEzE;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAG,mBAA6B;IAChE,OAAO,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACzB,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC;QAEtC,uDAAuD;QACvD,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,sBAAsB,CAAC,GAAG,EAAE;gBAC1B,aAAa,EAAE,gBAAgB;gBAC/B,UAAU,EAAE,yBAAyB;gBACrC,OAAO,EAAE,MAAM;aAChB,CAAC,CAAC;YACH,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC;YACjB,GAAG,CAAC,IAAI,GAAG;gBACT,KAAK,EAAE,yBAAyB;gBAChC,OAAO,EAAE,uDAAuD;aACjE,CAAC;YACF,OAAO;QACT,CAAC;QAED,iDAAiD;QACjD,IAAI,CAAC,cAAc,CAAC,CAAC,GAAG,SAAS,CAAC,WAAW,CAAC,EAAE,mBAAmB,CAAC,EAAE,CAAC;YACrE,sBAAsB,CAAC,GAAG,EAAE;gBAC1B,aAAa,EAAE,YAAY;gBAC3B,UAAU,EAAE,qBAAqB;gBACjC,OAAO,EAAE,MAAM;gBACf,MAAM,EAAE,EAAE,WAAW,EAAE,mBAAmB,EAAE;aAC7C,CAAC,CAAC;YACH,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC;YACjB,GAAG,CAAC,IAAI,GAAG;gBACT,KAAK,EAAE,WAAW;gBAClB,OAAO,EAAE,0CAA0C;aACpD,CAAC;YACF,OAAO;QACT,CAAC;QAED,MAAM,IAAI,EAAE,CAAC;IACf,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"require-permission.js","sourceRoot":"","sources":["../../src/middleware/require-permission.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAElG;;;;GAIG;AACH,MAAM,qBAAqB,GAAG,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,CAAU,CAAC;AAEzF;;;;;;;;;GASG;AACH,SAAS,sBAAsB,CAAC,GAAY;IAC1C,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAwC,CAAC;IACjF,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,KAAK,MAAM,GAAG,IAAI,qBAAqB,EAAE,CAAC;YACxC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;YAC1B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;gBAAE,OAAO,KAAK,CAAC;QAClE,CAAC;IACH,CAAC;IACD,MAAM,cAAc,GAAG,GAAG,CAAC,KAAK,CAAC,SAAS,EAAE,cAAc,CAAC;IAC3D,OAAO,OAAO,cAAc,KAAK,QAAQ,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC;QACpE,CAAC,CAAC,cAAc;QAChB,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAG,mBAA6B;IAChE,OAAO,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACzB,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC;QAEtC,uDAAuD;QACvD,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,sBAAsB,CAAC,GAAG,EAAE;gBAC1B,aAAa,EAAE,gBAAgB;gBAC/B,UAAU,EAAE,yBAAyB;gBACrC,OAAO,EAAE,MAAM;aAChB,CAAC,CAAC;YACH,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC;YACjB,GAAG,CAAC,IAAI,GAAG;gBACT,KAAK,EAAE,yBAAyB;gBAChC,OAAO,EAAE,uDAAuD;aACjE,CAAC;YACF,OAAO;QACT,CAAC;QAED,iDAAiD;QACjD,IAAI,CAAC,cAAc,CAAC,CAAC,GAAG,SAAS,CAAC,WAAW,CAAC,EAAE,mBAAmB,CAAC,EAAE,CAAC;YACrE,sBAAsB,CAAC,GAAG,EAAE;gBAC1B,aAAa,EAAE,YAAY;gBAC3B,UAAU,EAAE,qBAAqB;gBACjC,OAAO,EAAE,MAAM;gBACf,MAAM,EAAE,EAAE,WAAW,EAAE,mBAAmB,EAAE;aAC7C,CAAC,CAAC;YACH,MAAM,MAAM,GAAG,sBAAsB,CAAC,GAAG,CAAC,CAAC;YAC3C,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBACzB,uBAAuB,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;YACnD,CAAC;YACD,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC;YACjB,GAAG,CAAC,IAAI,GAAG;gBACT,KAAK,EAAE,WAAW;gBAClB,OAAO,EAAE,0CAA0C;aACpD,CAAC;YACF,OAAO;QACT,CAAC;QAED,MAAM,IAAI,EAAE,CAAC;IACf,CAAC,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"require-user-organization.d.ts","sourceRoot":"","sources":["../../src/middleware/require-user-organization.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAWtC;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,IAAI,UAAU,CAgCpD"}
1
+ {"version":3,"file":"require-user-organization.d.ts","sourceRoot":"","sources":["../../src/middleware/require-user-organization.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAWtC;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,IAAI,UAAU,CAkCpD"}
@@ -6,7 +6,7 @@
6
6
  * organization-prefixed API from becoming a cross-tenant object lookup or membership oracle.
7
7
  */
8
8
  import { z } from 'zod';
9
- import { getUserById } from '../users/service.js';
9
+ import { findUserById } from '../users/repository.js';
10
10
  import { recordSecurityDecision, recordSecurityReference } from '../security/decision-context.js';
11
11
  const organizationUserParamsSchema = z.object({
12
12
  orgId: z.string().uuid(),
@@ -34,7 +34,9 @@ export function requireUserOrganization() {
34
34
  ctx.body = { error: 'User not found' };
35
35
  return;
36
36
  }
37
- const user = await getUserById(parsed.data.userId);
37
+ // Authorization must use the live row. A cache miss inside a mutation transaction would
38
+ // otherwise register a post-commit cache write for a user the same request may delete.
39
+ const user = await findUserById(parsed.data.userId);
38
40
  if (user === null || user.organizationId !== parsed.data.orgId) {
39
41
  recordSecurityDecision(ctx, {
40
42
  decisionPoint: 'resource',
@@ -1 +1 @@
1
- {"version":3,"file":"require-user-organization.js","sourceRoot":"","sources":["../../src/middleware/require-user-organization.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAElG,MAAM,4BAA4B,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE;IACxB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE;CAC1B,CAAC,CAAC;AAEH;;;;;;;GAOG;AACH,MAAM,UAAU,uBAAuB;IACrC,OAAO,KAAK,UAAU,iCAAiC,CAAC,GAAG,EAAE,IAAI;QAC/D,MAAM,MAAM,GAAG,4BAA4B,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAClE,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,sBAAsB,CAAC,GAAG,EAAE;gBAC1B,aAAa,EAAE,UAAU;gBACzB,UAAU,EAAE,oBAAoB;gBAChC,OAAO,EAAE,MAAM;gBACf,MAAM,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE;aACjC,CAAC,CAAC;YACH,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC;YACjB,GAAG,CAAC,IAAI,GAAG,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC;YACvC,OAAO;QACT,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACnD,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,cAAc,KAAK,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YAC/D,sBAAsB,CAAC,GAAG,EAAE;gBAC1B,aAAa,EAAE,UAAU;gBACzB,UAAU,EAAE,oBAAoB;gBAChC,OAAO,EAAE,MAAM;gBACf,MAAM,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE;aACjC,CAAC,CAAC;YACH,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC;YACjB,GAAG,CAAC,IAAI,GAAG,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC;YACvC,OAAO;QACT,CAAC;QAED,uBAAuB,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAE7D,MAAM,IAAI,EAAE,CAAC;IACf,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"require-user-organization.js","sourceRoot":"","sources":["../../src/middleware/require-user-organization.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAElG,MAAM,4BAA4B,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE;IACxB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE;CAC1B,CAAC,CAAC;AAEH;;;;;;;GAOG;AACH,MAAM,UAAU,uBAAuB;IACrC,OAAO,KAAK,UAAU,iCAAiC,CAAC,GAAG,EAAE,IAAI;QAC/D,MAAM,MAAM,GAAG,4BAA4B,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAClE,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,sBAAsB,CAAC,GAAG,EAAE;gBAC1B,aAAa,EAAE,UAAU;gBACzB,UAAU,EAAE,oBAAoB;gBAChC,OAAO,EAAE,MAAM;gBACf,MAAM,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE;aACjC,CAAC,CAAC;YACH,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC;YACjB,GAAG,CAAC,IAAI,GAAG,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC;YACvC,OAAO;QACT,CAAC;QAED,wFAAwF;QACxF,uFAAuF;QACvF,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACpD,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,cAAc,KAAK,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YAC/D,sBAAsB,CAAC,GAAG,EAAE;gBAC1B,aAAa,EAAE,UAAU;gBACzB,UAAU,EAAE,oBAAoB;gBAChC,OAAO,EAAE,MAAM;gBACf,MAAM,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE;aACjC,CAAC,CAAC;YACH,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC;YACjB,GAAG,CAAC,IAAI,GAAG,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC;YACvC,OAAO;QACT,CAAC;QAED,uBAAuB,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAE7D,MAAM,IAAI,EAAE,CAAC;IACf,CAAC,CAAC;AACJ,CAAC"}
@@ -33,6 +33,8 @@
33
33
  * inject custom branding CSS via `{{{branding.customCss}}}`, hence
34
34
  * `style-src 'unsafe-inline'` is required. Login pages must never
35
35
  * be embedded in iframes (`frame-ancestors 'none'`).
36
+ * The final HTML policy also permits same-origin images, data-backed QR images, and only the
37
+ * validated external origins required by effective organization branding.
36
38
  *
37
39
  * Note: `form-action` is intentionally omitted. Chrome enforces
38
40
  * `form-action` on the entire redirect chain of a form submission,
@@ -51,6 +53,12 @@
51
53
  * ensures headers are present even on error responses.
52
54
  */
53
55
  import type { Middleware } from 'koa';
56
+ declare module 'koa' {
57
+ interface DefaultState {
58
+ /** Validated image origins required by the authentication HTML response. */
59
+ brandingImageSources?: readonly string[];
60
+ }
61
+ }
54
62
  /**
55
63
  * Static security headers applied to every response regardless of
56
64
  * content type or route.
@@ -79,6 +87,16 @@ export declare const DEFAULT_CSP = "default-src 'none'";
79
87
  * `form-action` is intentionally omitted — see module-level doc comment.
80
88
  */
81
89
  export declare const HTML_CSP = "default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; frame-ancestors 'none'";
90
+ /**
91
+ * Build the authentication-page CSP with only validated image origins.
92
+ *
93
+ * Same-origin uploads and data-backed QR images are always permitted for authentication HTML.
94
+ * Additional external sources must be exact origins accepted by the branding URL validator.
95
+ *
96
+ * @param imageSources - Candidate image sources from effective organization branding.
97
+ * @returns Complete HTML Content-Security-Policy value.
98
+ */
99
+ export declare function buildHtmlCsp(imageSources?: readonly string[]): string;
82
100
  /**
83
101
  * HSTS header value — one year, include subdomains.
84
102
  * Only emitted when the configured issuer URL uses https.
@@ -1 +1 @@
1
- {"version":3,"file":"security-headers.d.ts","sourceRoot":"","sources":["../../src/middleware/security-headers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAQtC;;;GAGG;AACH,eAAO,MAAM,uBAAuB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMnE,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,WAAW,uBAAuB,CAAC;AAEhD;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,QAAQ,sGACgF,CAAC;AAEtG;;;GAGG;AACH,eAAO,MAAM,UAAU,wCAAwC,CAAC;AAsBhE;;;;;;;;;GASG;AACH,wBAAgB,eAAe,IAAI,UAAU,CAqC5C"}
1
+ {"version":3,"file":"security-headers.d.ts","sourceRoot":"","sources":["../../src/middleware/security-headers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAItC,OAAO,QAAQ,KAAK,CAAC;IACnB,UAAU,YAAY;QACpB,4EAA4E;QAC5E,oBAAoB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;KAC1C;CACF;AAOD;;;GAGG;AACH,eAAO,MAAM,uBAAuB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMnE,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,WAAW,uBAAuB,CAAC;AAEhD;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,QAAQ,sGACgF,CAAC;AAatG;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,YAAY,GAAE,SAAS,MAAM,EAAO,GAAG,MAAM,CAOzE;AAED;;;GAGG;AACH,eAAO,MAAM,UAAU,wCAAwC,CAAC;AAsBhE;;;;;;;;;GASG;AACH,wBAAgB,eAAe,IAAI,UAAU,CAqC5C"}
@@ -33,6 +33,8 @@
33
33
  * inject custom branding CSS via `{{{branding.customCss}}}`, hence
34
34
  * `style-src 'unsafe-inline'` is required. Login pages must never
35
35
  * be embedded in iframes (`frame-ancestors 'none'`).
36
+ * The final HTML policy also permits same-origin images, data-backed QR images, and only the
37
+ * validated external origins required by effective organization branding.
36
38
  *
37
39
  * Note: `form-action` is intentionally omitted. Chrome enforces
38
40
  * `form-action` on the entire redirect chain of a form submission,
@@ -51,6 +53,7 @@
51
53
  * ensures headers are present even on error responses.
52
54
  */
53
55
  import { config } from '../config/index.js';
56
+ import { validateBrandingImageUrl } from '../organizations/branding-url.js';
54
57
  // ---------------------------------------------------------------------------
55
58
  // Exported constants — consumed by tests and by other middleware that may
56
59
  // need to reference or override specific values.
@@ -89,6 +92,34 @@ export const DEFAULT_CSP = "default-src 'none'";
89
92
  * `form-action` is intentionally omitted — see module-level doc comment.
90
93
  */
91
94
  export const HTML_CSP = "default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; frame-ancestors 'none'";
95
+ /** Return one safe external origin, rejecting paths and malformed or disallowed URLs. */
96
+ function validatedExternalImageOrigin(candidate) {
97
+ try {
98
+ const validated = validateBrandingImageUrl(candidate);
99
+ const origin = new URL(validated).origin;
100
+ return validated === origin ? origin : null;
101
+ }
102
+ catch {
103
+ return null;
104
+ }
105
+ }
106
+ /**
107
+ * Build the authentication-page CSP with only validated image origins.
108
+ *
109
+ * Same-origin uploads and data-backed QR images are always permitted for authentication HTML.
110
+ * Additional external sources must be exact origins accepted by the branding URL validator.
111
+ *
112
+ * @param imageSources - Candidate image sources from effective organization branding.
113
+ * @returns Complete HTML Content-Security-Policy value.
114
+ */
115
+ export function buildHtmlCsp(imageSources = []) {
116
+ const externalOrigins = imageSources
117
+ .map(validatedExternalImageOrigin)
118
+ .filter((origin) => origin !== null)
119
+ .sort();
120
+ const sources = ["'self'", 'data:', ...new Set(externalOrigins)];
121
+ return `${HTML_CSP}; img-src ${sources.join(' ')}`;
122
+ }
92
123
  /**
93
124
  * HSTS header value — one year, include subdomains.
94
125
  * Only emitted when the configured issuer URL uses https.
@@ -152,7 +183,7 @@ export function securityHeaders() {
152
183
  // -----------------------------------------------------------------------
153
184
  const contentType = ctx.response.get('Content-Type') || '';
154
185
  if (contentType.includes('text/html')) {
155
- ctx.set('Content-Security-Policy', HTML_CSP);
186
+ ctx.set('Content-Security-Policy', buildHtmlCsp(ctx.state?.brandingImageSources));
156
187
  }
157
188
  };
158
189
  }
@@ -1 +1 @@
1
- {"version":3,"file":"security-headers.js","sourceRoot":"","sources":["../../src/middleware/security-headers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,8EAA8E;AAC9E,0EAA0E;AAC1E,iDAAiD;AACjD,8EAA8E;AAE9E;;;GAGG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAqC,MAAM,CAAC,MAAM,CAAC;IACrF,wBAAwB,EAAE,SAAS;IACnC,iBAAiB,EAAE,MAAM;IACzB,iBAAiB,EAAE,iCAAiC;IACpD,kBAAkB,EAAE,GAAG;IACvB,oBAAoB,EAAE,sDAAsD;CAC7E,CAAC,CAAC;AAEH;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,oBAAoB,CAAC;AAEhD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,QAAQ,GACnB,mGAAmG,CAAC;AAEtG;;;GAGG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,qCAAqC,CAAC;AAEhE,8EAA8E;AAC9E,qBAAqB;AACrB,8EAA8E;AAE9E;;;;;;GAMG;AACH,SAAS,cAAc;IACrB,IAAI,CAAC;QACH,OAAO,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;IACrD,CAAC;IAAC,MAAM,CAAC;QACP,mEAAmE;QACnE,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,QAAQ,GAAG,cAAc,EAAE,CAAC;IAElC,OAAO,KAAK,UAAU,yBAAyB,CAAC,GAAG,EAAE,IAAI;QACvD,0EAA0E;QAC1E,iEAAiE;QACjE,kEAAkE;QAClE,6DAA6D;QAC7D,0EAA0E;QAC1E,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,uBAAuB,CAAC,EAAE,CAAC;YACpE,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACvB,CAAC;QAED,gEAAgE;QAChE,GAAG,CAAC,GAAG,CAAC,yBAAyB,EAAE,WAAW,CAAC,CAAC;QAEhD,8CAA8C;QAC9C,IAAI,QAAQ,EAAE,CAAC;YACb,GAAG,CAAC,GAAG,CAAC,2BAA2B,EAAE,UAAU,CAAC,CAAC;QACnD,CAAC;QAED,0EAA0E;QAC1E,wDAAwD;QACxD,0EAA0E;QAC1E,MAAM,IAAI,EAAE,CAAC;QAEb,0EAA0E;QAC1E,2CAA2C;QAC3C,sEAAsE;QACtE,mEAAmE;QACnE,kDAAkD;QAClD,0EAA0E;QAC1E,MAAM,WAAW,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC;QAC3D,IAAI,WAAW,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;YACtC,GAAG,CAAC,GAAG,CAAC,yBAAyB,EAAE,QAAQ,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"security-headers.js","sourceRoot":"","sources":["../../src/middleware/security-headers.ts"],"names":[],"mappings":"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"}
@@ -14,14 +14,13 @@
14
14
  * 3. If cache miss, query DB: findOrganizationBySlug(orgSlug)
15
15
  * 4. If found from DB, cache it: cacheOrganization(org)
16
16
  * 5. Validate status:
17
- * - archived → 404 "Organization not found"
18
17
  * - suspended → 403 "Organization is suspended"
19
18
  * - active → continue
20
19
  * 6. Set ctx.state.organization (full Organization object)
21
20
  * 7. Set ctx.state.issuer
22
21
  *
23
22
  * Returns:
24
- * - 404 if organization not found or archived
23
+ * - 404 if organization is not found
25
24
  * - 403 if organization is suspended
26
25
  */
27
26
  import type { Middleware } from 'koa';
@@ -1 +1 @@
1
- {"version":3,"file":"tenant-resolver.d.ts","sourceRoot":"","sources":["../../src/middleware/tenant-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAStC;;;;;;;GAOG;AACH,wBAAgB,cAAc,IAAI,UAAU,CAyC3C"}
1
+ {"version":3,"file":"tenant-resolver.d.ts","sourceRoot":"","sources":["../../src/middleware/tenant-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAStC;;;;;;;GAOG;AACH,wBAAgB,cAAc,IAAI,UAAU,CAqC3C"}
@@ -14,14 +14,13 @@
14
14
  * 3. If cache miss, query DB: findOrganizationBySlug(orgSlug)
15
15
  * 4. If found from DB, cache it: cacheOrganization(org)
16
16
  * 5. Validate status:
17
- * - archived → 404 "Organization not found"
18
17
  * - suspended → 403 "Organization is suspended"
19
18
  * - active → continue
20
19
  * 6. Set ctx.state.organization (full Organization object)
21
20
  * 7. Set ctx.state.issuer
22
21
  *
23
22
  * Returns:
24
- * - 404 if organization not found or archived
23
+ * - 404 if organization is not found
25
24
  * - 403 if organization is suspended
26
25
  */
27
26
  import { config } from '../config/index.js';
@@ -56,9 +55,6 @@ export function tenantResolver() {
56
55
  return ctx.throw(404, 'Organization not found');
57
56
  }
58
57
  // 5. Status-dependent responses
59
- if (org.status === 'archived') {
60
- return ctx.throw(404, 'Organization not found');
61
- }
62
58
  if (org.status === 'suspended') {
63
59
  return ctx.throw(403, 'Organization is suspended');
64
60
  }
@@ -1 +1 @@
1
- {"version":3,"file":"tenant-resolver.js","sourceRoot":"","sources":["../../src/middleware/tenant-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EACL,2BAA2B,EAC3B,iBAAiB,GAClB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAGxE;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACzB,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC;QAEpC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,wBAAwB,CAAC,CAAC;QAC3C,CAAC;QAED,2BAA2B;QAC3B,IAAI,GAAG,GAAwB,MAAM,2BAA2B,CAAC,OAAO,CAAC,CAAC;QAE1E,wDAAwD;QACxD,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,GAAG,GAAG,MAAM,sBAAsB,CAAC,OAAO,CAAC,CAAC;YAE5C,8CAA8C;YAC9C,IAAI,GAAG,EAAE,CAAC;gBACR,MAAM,iBAAiB,CAAC,GAAG,CAAC,CAAC;YAC/B,CAAC;QACH,CAAC;QAED,sBAAsB;QACtB,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,OAAO,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,wBAAwB,CAAC,CAAC;QAClD,CAAC;QAED,gCAAgC;QAChC,IAAI,GAAG,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YAC9B,OAAO,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,wBAAwB,CAAC,CAAC;QAClD,CAAC;QAED,IAAI,GAAG,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YAC/B,OAAO,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,2BAA2B,CAAC,CAAC;QACrD,CAAC;QAED,oEAAoE;QACpE,GAAG,CAAC,KAAK,CAAC,YAAY,GAAG,GAAG,CAAC;QAC7B,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,MAAM,CAAC,aAAa,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;QAEzD,MAAM,IAAI,EAAE,CAAC;IACf,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"tenant-resolver.js","sourceRoot":"","sources":["../../src/middleware/tenant-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EACL,2BAA2B,EAC3B,iBAAiB,GAClB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAGxE;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACzB,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC;QAEpC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,wBAAwB,CAAC,CAAC;QAC3C,CAAC;QAED,2BAA2B;QAC3B,IAAI,GAAG,GAAwB,MAAM,2BAA2B,CAAC,OAAO,CAAC,CAAC;QAE1E,wDAAwD;QACxD,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,GAAG,GAAG,MAAM,sBAAsB,CAAC,OAAO,CAAC,CAAC;YAE5C,8CAA8C;YAC9C,IAAI,GAAG,EAAE,CAAC;gBACR,MAAM,iBAAiB,CAAC,GAAG,CAAC,CAAC;YAC/B,CAAC;QACH,CAAC;QAED,sBAAsB;QACtB,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,OAAO,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,wBAAwB,CAAC,CAAC;QAClD,CAAC;QAED,gCAAgC;QAChC,IAAI,GAAG,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YAC/B,OAAO,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,2BAA2B,CAAC,CAAC;QACrD,CAAC;QAED,oEAAoE;QACpE,GAAG,CAAC,KAAK,CAAC,YAAY,GAAG,GAAG,CAAC;QAC7B,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,MAAM,CAAC,aAAa,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;QAEzD,MAAM,IAAI,EAAE,CAAC;IACf,CAAC,CAAC;AACJ,CAAC"}
@@ -1,23 +1,26 @@
1
1
  /**
2
2
  * Token and introspection endpoint rate limiter middleware.
3
3
  *
4
- * Protects the OAuth token endpoint (`POST /:orgSlug/oidc/token`) and
5
- * token introspection endpoint (`POST /:orgSlug/oidc/token/introspection`)
4
+ * Protects the OAuth token endpoint (`POST /:orgSlug/token`) and
5
+ * token introspection endpoint (`POST /:orgSlug/token/introspection`)
6
6
  * against abuse: client-credentials flooding, authorization-code
7
7
  * brute-forcing, token enumeration, and general endpoint spam.
8
8
  *
9
- * Rate limiting is per-IP + per-client_id composite key. If `client_id`
10
- * is not present in the request body (e.g. `client_secret_basic` auth
11
- * sends credentials in the `Authorization` header), the key falls back
12
- * to `unknown` — all such requests from the same IP share one counter.
9
+ * Rate limiting is per-IP + per-client_id composite key. The client
10
+ * identifier is read from the parsed body or from HTTP Basic credentials;
11
+ * when neither is present (unauthenticated spam) the key falls back to
12
+ * `unknown`. Because that identifier is unauthenticated and caller-controlled,
13
+ * an aggregate per-IP counter runs alongside it, so one address cannot flood
14
+ * the endpoint by varying the client identifier.
13
15
  *
14
16
  * Reuses the existing `checkRateLimit()` infrastructure from
15
17
  * `src/auth/rate-limiter.ts` which provides Redis INCR+EXPIRE sliding
16
18
  * window and graceful degradation on Redis failure.
17
19
  *
18
- * Placement: mount as global middleware **before** the OIDC provider
19
- * router in `src/server.ts`. The path regex ensures only matching
20
- * requests are rate-limited — all other paths pass through untouched.
20
+ * Placement: mounted on the OIDC router **after** the request body parser so
21
+ * the client identifier is available, and before the provider callback. The
22
+ * path regex ensures only the token and introspection endpoints are limited —
23
+ * every other path passes through untouched.
21
24
  *
22
25
  * @module middleware/token-rate-limiter
23
26
  */
@@ -26,22 +29,32 @@ import type { RateLimitConfig } from '../auth/rate-limiter.js';
26
29
  /**
27
30
  * Regex matching the OIDC token endpoint path.
28
31
  *
29
- * Pattern: `/<orgSlug>/oidc/token` where orgSlug starts with a
32
+ * Pattern: `/<orgSlug>/token` where orgSlug starts with a
30
33
  * lowercase alphanumeric character followed by zero or more lowercase
31
34
  * alphanumeric or hyphen characters.
32
35
  *
33
- * Matches: `/acme/oidc/token`, `/my-org/oidc/token`
34
- * Rejects: `/api/admin/something`, `/acme/oidc/token/extra`
36
+ * Matches: `/acme/token`, `/my-org/token`
37
+ * Rejects: `/api/admin/something`, `/acme/token/extra`
35
38
  */
36
39
  export declare const TOKEN_PATH_REGEX: RegExp;
37
40
  /**
38
- * Rate limit configuration for the token endpoint.
41
+ * Rate limit configuration for the token endpoint, per client.
39
42
  *
40
43
  * 30 requests per 5-minute window — generous enough for legitimate
41
44
  * applications (SPAs refreshing tokens, server-side token exchanges)
42
45
  * while catching automated abuse.
43
46
  */
44
47
  export declare const TOKEN_RATE_LIMIT: RateLimitConfig;
48
+ /**
49
+ * Aggregate token limit for one client address.
50
+ *
51
+ * The per-client key comes from an unauthenticated value, so a caller can vary
52
+ * the client identifier to open a fresh counter for every request. This
53
+ * aggregate bounds the total token traffic from one address, so the endpoint
54
+ * cannot be flooded with junk requests, while many legitimate clients behind
55
+ * one address still receive their own per-client budgets.
56
+ */
57
+ export declare const TOKEN_IP_RATE_LIMIT: RateLimitConfig;
45
58
  /**
46
59
  * Create the token endpoint rate limiter middleware.
47
60
  *
@@ -56,11 +69,11 @@ export declare function tokenRateLimiter(): Middleware;
56
69
  /**
57
70
  * Regex matching the OIDC token introspection endpoint path.
58
71
  *
59
- * Pattern: `/<orgSlug>/oidc/token/introspection` where orgSlug uses
72
+ * Pattern: `/<orgSlug>/token/introspection` where orgSlug uses
60
73
  * the same slug format as TOKEN_PATH_REGEX.
61
74
  *
62
- * Matches: `/acme/oidc/token/introspection`, `/my-org/oidc/token/introspection`
63
- * Rejects: `/acme/oidc/token`, `/api/admin/introspection`
75
+ * Matches: `/acme/token/introspection`, `/my-org/token/introspection`
76
+ * Rejects: `/acme/token`, `/api/admin/introspection`
64
77
  */
65
78
  export declare const INTROSPECTION_PATH_REGEX: RegExp;
66
79
  /**
@@ -72,6 +85,14 @@ export declare const INTROSPECTION_PATH_REGEX: RegExp;
72
85
  * while still preventing token enumeration attacks.
73
86
  */
74
87
  export declare const INTROSPECTION_RATE_LIMIT: RateLimitConfig;
88
+ /**
89
+ * Aggregate introspection limit for one client address.
90
+ *
91
+ * As on the token endpoint, the per-client key comes from an unauthenticated
92
+ * value and can be varied per request, so this aggregate bounds the total
93
+ * introspection traffic from one address independently of the client value.
94
+ */
95
+ export declare const INTROSPECTION_IP_RATE_LIMIT: RateLimitConfig;
75
96
  /**
76
97
  * Create the introspection endpoint rate limiter middleware.
77
98
  *
@@ -1 +1 @@
1
- {"version":3,"file":"token-rate-limiter.d.ts","sourceRoot":"","sources":["../../src/middleware/token-rate-limiter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAEtC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAO/D;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,QAAwC,CAAC;AAEtE;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,EAAE,eAG9B,CAAC;AAMF;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,IAAI,UAAU,CAwD7C;AAMD;;;;;;;;GAQG;AACH,eAAO,MAAM,wBAAwB,QAAuD,CAAC;AAE7F;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,EAAE,eAGtC,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,wBAAgB,wBAAwB,IAAI,UAAU,CAqDrD"}
1
+ {"version":3,"file":"token-rate-limiter.d.ts","sourceRoot":"","sources":["../../src/middleware/token-rate-limiter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAW,UAAU,EAAE,MAAM,KAAK,CAAC;AAE/C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAO/D;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,QAAkC,CAAC;AA2ChE;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,EAAE,eAG9B,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,EAAE,eAGjC,CAAC;AAgCF;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,IAAI,UAAU,CAoD7C;AAMD;;;;;;;;GAQG;AACH,eAAO,MAAM,wBAAwB,QAAiD,CAAC;AAEvF;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,EAAE,eAGtC,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,EAAE,eAGzC,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,wBAAgB,wBAAwB,IAAI,UAAU,CA0DrD"}