palaryn 0.1.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 (607) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +716 -0
  3. package/dist/sdk/typescript/src/client.d.ts +71 -0
  4. package/dist/sdk/typescript/src/client.d.ts.map +1 -0
  5. package/dist/sdk/typescript/src/client.js +176 -0
  6. package/dist/sdk/typescript/src/client.js.map +1 -0
  7. package/dist/sdk/typescript/src/errors.d.ts +50 -0
  8. package/dist/sdk/typescript/src/errors.d.ts.map +1 -0
  9. package/dist/sdk/typescript/src/errors.js +103 -0
  10. package/dist/sdk/typescript/src/errors.js.map +1 -0
  11. package/dist/sdk/typescript/src/index.d.ts +4 -0
  12. package/dist/sdk/typescript/src/index.d.ts.map +1 -0
  13. package/dist/sdk/typescript/src/index.js +15 -0
  14. package/dist/sdk/typescript/src/index.js.map +1 -0
  15. package/dist/sdk/typescript/src/types.d.ts +101 -0
  16. package/dist/sdk/typescript/src/types.d.ts.map +1 -0
  17. package/dist/sdk/typescript/src/types.js +6 -0
  18. package/dist/sdk/typescript/src/types.js.map +1 -0
  19. package/dist/src/admin/index.d.ts +2 -0
  20. package/dist/src/admin/index.d.ts.map +1 -0
  21. package/dist/src/admin/index.js +6 -0
  22. package/dist/src/admin/index.js.map +1 -0
  23. package/dist/src/admin/routes.d.ts +5 -0
  24. package/dist/src/admin/routes.d.ts.map +1 -0
  25. package/dist/src/admin/routes.js +471 -0
  26. package/dist/src/admin/routes.js.map +1 -0
  27. package/dist/src/admin/templates.d.ts +51 -0
  28. package/dist/src/admin/templates.d.ts.map +1 -0
  29. package/dist/src/admin/templates.js +500 -0
  30. package/dist/src/admin/templates.js.map +1 -0
  31. package/dist/src/anomaly/detector.d.ts +141 -0
  32. package/dist/src/anomaly/detector.d.ts.map +1 -0
  33. package/dist/src/anomaly/detector.js +554 -0
  34. package/dist/src/anomaly/detector.js.map +1 -0
  35. package/dist/src/anomaly/index.d.ts +2 -0
  36. package/dist/src/anomaly/index.d.ts.map +1 -0
  37. package/dist/src/anomaly/index.js +7 -0
  38. package/dist/src/anomaly/index.js.map +1 -0
  39. package/dist/src/approval/manager.d.ts +147 -0
  40. package/dist/src/approval/manager.d.ts.map +1 -0
  41. package/dist/src/approval/manager.js +511 -0
  42. package/dist/src/approval/manager.js.map +1 -0
  43. package/dist/src/approval/webhook.d.ts +36 -0
  44. package/dist/src/approval/webhook.d.ts.map +1 -0
  45. package/dist/src/approval/webhook.js +135 -0
  46. package/dist/src/approval/webhook.js.map +1 -0
  47. package/dist/src/audit/logger.d.ts +70 -0
  48. package/dist/src/audit/logger.d.ts.map +1 -0
  49. package/dist/src/audit/logger.js +440 -0
  50. package/dist/src/audit/logger.js.map +1 -0
  51. package/dist/src/auth/index.d.ts +6 -0
  52. package/dist/src/auth/index.d.ts.map +1 -0
  53. package/dist/src/auth/index.js +22 -0
  54. package/dist/src/auth/index.js.map +1 -0
  55. package/dist/src/auth/password.d.ts +3 -0
  56. package/dist/src/auth/password.d.ts.map +1 -0
  57. package/dist/src/auth/password.js +25 -0
  58. package/dist/src/auth/password.js.map +1 -0
  59. package/dist/src/auth/pkce.d.ts +13 -0
  60. package/dist/src/auth/pkce.d.ts.map +1 -0
  61. package/dist/src/auth/pkce.js +58 -0
  62. package/dist/src/auth/pkce.js.map +1 -0
  63. package/dist/src/auth/providers.d.ts +28 -0
  64. package/dist/src/auth/providers.d.ts.map +1 -0
  65. package/dist/src/auth/providers.js +198 -0
  66. package/dist/src/auth/providers.js.map +1 -0
  67. package/dist/src/auth/routes.d.ts +14 -0
  68. package/dist/src/auth/routes.d.ts.map +1 -0
  69. package/dist/src/auth/routes.js +431 -0
  70. package/dist/src/auth/routes.js.map +1 -0
  71. package/dist/src/auth/session.d.ts +24 -0
  72. package/dist/src/auth/session.d.ts.map +1 -0
  73. package/dist/src/auth/session.js +105 -0
  74. package/dist/src/auth/session.js.map +1 -0
  75. package/dist/src/billing/index.d.ts +7 -0
  76. package/dist/src/billing/index.d.ts.map +1 -0
  77. package/dist/src/billing/index.js +14 -0
  78. package/dist/src/billing/index.js.map +1 -0
  79. package/dist/src/billing/plan-enforcer.d.ts +44 -0
  80. package/dist/src/billing/plan-enforcer.d.ts.map +1 -0
  81. package/dist/src/billing/plan-enforcer.js +110 -0
  82. package/dist/src/billing/plan-enforcer.js.map +1 -0
  83. package/dist/src/billing/routes.d.ts +15 -0
  84. package/dist/src/billing/routes.d.ts.map +1 -0
  85. package/dist/src/billing/routes.js +193 -0
  86. package/dist/src/billing/routes.js.map +1 -0
  87. package/dist/src/billing/stripe-client.d.ts +14 -0
  88. package/dist/src/billing/stripe-client.d.ts.map +1 -0
  89. package/dist/src/billing/stripe-client.js +51 -0
  90. package/dist/src/billing/stripe-client.js.map +1 -0
  91. package/dist/src/billing/webhook-handler.d.ts +19 -0
  92. package/dist/src/billing/webhook-handler.d.ts.map +1 -0
  93. package/dist/src/billing/webhook-handler.js +169 -0
  94. package/dist/src/billing/webhook-handler.js.map +1 -0
  95. package/dist/src/billing/webhook-routes.d.ts +5 -0
  96. package/dist/src/billing/webhook-routes.d.ts.map +1 -0
  97. package/dist/src/billing/webhook-routes.js +30 -0
  98. package/dist/src/billing/webhook-routes.js.map +1 -0
  99. package/dist/src/budget/manager.d.ts +95 -0
  100. package/dist/src/budget/manager.d.ts.map +1 -0
  101. package/dist/src/budget/manager.js +547 -0
  102. package/dist/src/budget/manager.js.map +1 -0
  103. package/dist/src/budget/usage-extractor.d.ts +38 -0
  104. package/dist/src/budget/usage-extractor.d.ts.map +1 -0
  105. package/dist/src/budget/usage-extractor.js +165 -0
  106. package/dist/src/budget/usage-extractor.js.map +1 -0
  107. package/dist/src/cli.d.ts +3 -0
  108. package/dist/src/cli.d.ts.map +1 -0
  109. package/dist/src/cli.js +115 -0
  110. package/dist/src/cli.js.map +1 -0
  111. package/dist/src/config/defaults.d.ts +3 -0
  112. package/dist/src/config/defaults.d.ts.map +1 -0
  113. package/dist/src/config/defaults.js +243 -0
  114. package/dist/src/config/defaults.js.map +1 -0
  115. package/dist/src/config/validate.d.ts +15 -0
  116. package/dist/src/config/validate.d.ts.map +1 -0
  117. package/dist/src/config/validate.js +105 -0
  118. package/dist/src/config/validate.js.map +1 -0
  119. package/dist/src/dlp/composite-scanner.d.ts +47 -0
  120. package/dist/src/dlp/composite-scanner.d.ts.map +1 -0
  121. package/dist/src/dlp/composite-scanner.js +186 -0
  122. package/dist/src/dlp/composite-scanner.js.map +1 -0
  123. package/dist/src/dlp/index.d.ts +10 -0
  124. package/dist/src/dlp/index.d.ts.map +1 -0
  125. package/dist/src/dlp/index.js +26 -0
  126. package/dist/src/dlp/index.js.map +1 -0
  127. package/dist/src/dlp/interfaces.d.ts +33 -0
  128. package/dist/src/dlp/interfaces.d.ts.map +1 -0
  129. package/dist/src/dlp/interfaces.js +3 -0
  130. package/dist/src/dlp/interfaces.js.map +1 -0
  131. package/dist/src/dlp/patterns.d.ts +9 -0
  132. package/dist/src/dlp/patterns.d.ts.map +1 -0
  133. package/dist/src/dlp/patterns.js +25 -0
  134. package/dist/src/dlp/patterns.js.map +1 -0
  135. package/dist/src/dlp/prompt-injection-backend.d.ts +68 -0
  136. package/dist/src/dlp/prompt-injection-backend.d.ts.map +1 -0
  137. package/dist/src/dlp/prompt-injection-backend.js +148 -0
  138. package/dist/src/dlp/prompt-injection-backend.js.map +1 -0
  139. package/dist/src/dlp/prompt-injection-patterns.d.ts +32 -0
  140. package/dist/src/dlp/prompt-injection-patterns.d.ts.map +1 -0
  141. package/dist/src/dlp/prompt-injection-patterns.js +290 -0
  142. package/dist/src/dlp/prompt-injection-patterns.js.map +1 -0
  143. package/dist/src/dlp/regex-backend.d.ts +32 -0
  144. package/dist/src/dlp/regex-backend.d.ts.map +1 -0
  145. package/dist/src/dlp/regex-backend.js +153 -0
  146. package/dist/src/dlp/regex-backend.js.map +1 -0
  147. package/dist/src/dlp/scanner.d.ts +122 -0
  148. package/dist/src/dlp/scanner.d.ts.map +1 -0
  149. package/dist/src/dlp/scanner.js +444 -0
  150. package/dist/src/dlp/scanner.js.map +1 -0
  151. package/dist/src/dlp/text-normalizer.d.ts +41 -0
  152. package/dist/src/dlp/text-normalizer.d.ts.map +1 -0
  153. package/dist/src/dlp/text-normalizer.js +203 -0
  154. package/dist/src/dlp/text-normalizer.js.map +1 -0
  155. package/dist/src/dlp/trufflehog-backend.d.ts +64 -0
  156. package/dist/src/dlp/trufflehog-backend.d.ts.map +1 -0
  157. package/dist/src/dlp/trufflehog-backend.js +151 -0
  158. package/dist/src/dlp/trufflehog-backend.js.map +1 -0
  159. package/dist/src/executor/http-executor.d.ts +25 -0
  160. package/dist/src/executor/http-executor.d.ts.map +1 -0
  161. package/dist/src/executor/http-executor.js +333 -0
  162. package/dist/src/executor/http-executor.js.map +1 -0
  163. package/dist/src/executor/index.d.ts +6 -0
  164. package/dist/src/executor/index.d.ts.map +1 -0
  165. package/dist/src/executor/index.js +12 -0
  166. package/dist/src/executor/index.js.map +1 -0
  167. package/dist/src/executor/interfaces.d.ts +11 -0
  168. package/dist/src/executor/interfaces.d.ts.map +1 -0
  169. package/dist/src/executor/interfaces.js +3 -0
  170. package/dist/src/executor/interfaces.js.map +1 -0
  171. package/dist/src/executor/noop-executor.d.ts +13 -0
  172. package/dist/src/executor/noop-executor.d.ts.map +1 -0
  173. package/dist/src/executor/noop-executor.js +21 -0
  174. package/dist/src/executor/noop-executor.js.map +1 -0
  175. package/dist/src/executor/registry.d.ts +30 -0
  176. package/dist/src/executor/registry.d.ts.map +1 -0
  177. package/dist/src/executor/registry.js +62 -0
  178. package/dist/src/executor/registry.js.map +1 -0
  179. package/dist/src/executor/slack-executor.d.ts +24 -0
  180. package/dist/src/executor/slack-executor.d.ts.map +1 -0
  181. package/dist/src/executor/slack-executor.js +147 -0
  182. package/dist/src/executor/slack-executor.js.map +1 -0
  183. package/dist/src/index.d.ts +25 -0
  184. package/dist/src/index.d.ts.map +1 -0
  185. package/dist/src/index.js +74 -0
  186. package/dist/src/index.js.map +1 -0
  187. package/dist/src/mcp/auth-verifier.d.ts +23 -0
  188. package/dist/src/mcp/auth-verifier.d.ts.map +1 -0
  189. package/dist/src/mcp/auth-verifier.js +162 -0
  190. package/dist/src/mcp/auth-verifier.js.map +1 -0
  191. package/dist/src/mcp/bridge.d.ts +132 -0
  192. package/dist/src/mcp/bridge.d.ts.map +1 -0
  193. package/dist/src/mcp/bridge.js +734 -0
  194. package/dist/src/mcp/bridge.js.map +1 -0
  195. package/dist/src/mcp/http-transport.d.ts +32 -0
  196. package/dist/src/mcp/http-transport.d.ts.map +1 -0
  197. package/dist/src/mcp/http-transport.js +538 -0
  198. package/dist/src/mcp/http-transport.js.map +1 -0
  199. package/dist/src/mcp/index.d.ts +10 -0
  200. package/dist/src/mcp/index.d.ts.map +1 -0
  201. package/dist/src/mcp/index.js +17 -0
  202. package/dist/src/mcp/index.js.map +1 -0
  203. package/dist/src/mcp/oauth-pages.d.ts +23 -0
  204. package/dist/src/mcp/oauth-pages.d.ts.map +1 -0
  205. package/dist/src/mcp/oauth-pages.js +121 -0
  206. package/dist/src/mcp/oauth-pages.js.map +1 -0
  207. package/dist/src/mcp/oauth-postgres-stores.d.ts +55 -0
  208. package/dist/src/mcp/oauth-postgres-stores.d.ts.map +1 -0
  209. package/dist/src/mcp/oauth-postgres-stores.js +226 -0
  210. package/dist/src/mcp/oauth-postgres-stores.js.map +1 -0
  211. package/dist/src/mcp/oauth-provider.d.ts +95 -0
  212. package/dist/src/mcp/oauth-provider.d.ts.map +1 -0
  213. package/dist/src/mcp/oauth-provider.js +360 -0
  214. package/dist/src/mcp/oauth-provider.js.map +1 -0
  215. package/dist/src/mcp/oauth-stores.d.ts +62 -0
  216. package/dist/src/mcp/oauth-stores.d.ts.map +1 -0
  217. package/dist/src/mcp/oauth-stores.js +154 -0
  218. package/dist/src/mcp/oauth-stores.js.map +1 -0
  219. package/dist/src/mcp/server.d.ts +18 -0
  220. package/dist/src/mcp/server.d.ts.map +1 -0
  221. package/dist/src/mcp/server.js +51 -0
  222. package/dist/src/mcp/server.js.map +1 -0
  223. package/dist/src/metrics/collector.d.ts +106 -0
  224. package/dist/src/metrics/collector.d.ts.map +1 -0
  225. package/dist/src/metrics/collector.js +311 -0
  226. package/dist/src/metrics/collector.js.map +1 -0
  227. package/dist/src/metrics/index.d.ts +2 -0
  228. package/dist/src/metrics/index.d.ts.map +1 -0
  229. package/dist/src/metrics/index.js +6 -0
  230. package/dist/src/metrics/index.js.map +1 -0
  231. package/dist/src/middleware/auth.d.ts +77 -0
  232. package/dist/src/middleware/auth.d.ts.map +1 -0
  233. package/dist/src/middleware/auth.js +720 -0
  234. package/dist/src/middleware/auth.js.map +1 -0
  235. package/dist/src/middleware/session.d.ts +18 -0
  236. package/dist/src/middleware/session.d.ts.map +1 -0
  237. package/dist/src/middleware/session.js +67 -0
  238. package/dist/src/middleware/session.js.map +1 -0
  239. package/dist/src/middleware/validate.d.ts +3 -0
  240. package/dist/src/middleware/validate.d.ts.map +1 -0
  241. package/dist/src/middleware/validate.js +85 -0
  242. package/dist/src/middleware/validate.js.map +1 -0
  243. package/dist/src/policy/engine.d.ts +107 -0
  244. package/dist/src/policy/engine.d.ts.map +1 -0
  245. package/dist/src/policy/engine.js +646 -0
  246. package/dist/src/policy/engine.js.map +1 -0
  247. package/dist/src/policy/index.d.ts +3 -0
  248. package/dist/src/policy/index.d.ts.map +1 -0
  249. package/dist/src/policy/index.js +8 -0
  250. package/dist/src/policy/index.js.map +1 -0
  251. package/dist/src/policy/opa-engine.d.ts +176 -0
  252. package/dist/src/policy/opa-engine.d.ts.map +1 -0
  253. package/dist/src/policy/opa-engine.js +790 -0
  254. package/dist/src/policy/opa-engine.js.map +1 -0
  255. package/dist/src/proxy/forward-proxy.d.ts +30 -0
  256. package/dist/src/proxy/forward-proxy.d.ts.map +1 -0
  257. package/dist/src/proxy/forward-proxy.js +580 -0
  258. package/dist/src/proxy/forward-proxy.js.map +1 -0
  259. package/dist/src/proxy/index.d.ts +2 -0
  260. package/dist/src/proxy/index.d.ts.map +1 -0
  261. package/dist/src/proxy/index.js +8 -0
  262. package/dist/src/proxy/index.js.map +1 -0
  263. package/dist/src/ratelimit/limiter.d.ts +45 -0
  264. package/dist/src/ratelimit/limiter.d.ts.map +1 -0
  265. package/dist/src/ratelimit/limiter.js +158 -0
  266. package/dist/src/ratelimit/limiter.js.map +1 -0
  267. package/dist/src/replay/engine.d.ts +40 -0
  268. package/dist/src/replay/engine.d.ts.map +1 -0
  269. package/dist/src/replay/engine.js +106 -0
  270. package/dist/src/replay/engine.js.map +1 -0
  271. package/dist/src/replay/index.d.ts +2 -0
  272. package/dist/src/replay/index.d.ts.map +1 -0
  273. package/dist/src/replay/index.js +6 -0
  274. package/dist/src/replay/index.js.map +1 -0
  275. package/dist/src/saas/index.d.ts +2 -0
  276. package/dist/src/saas/index.d.ts.map +1 -0
  277. package/dist/src/saas/index.js +18 -0
  278. package/dist/src/saas/index.js.map +1 -0
  279. package/dist/src/saas/routes.d.ts +18 -0
  280. package/dist/src/saas/routes.d.ts.map +1 -0
  281. package/dist/src/saas/routes.js +1566 -0
  282. package/dist/src/saas/routes.js.map +1 -0
  283. package/dist/src/server/app.d.ts +44 -0
  284. package/dist/src/server/app.d.ts.map +1 -0
  285. package/dist/src/server/app.js +854 -0
  286. package/dist/src/server/app.js.map +1 -0
  287. package/dist/src/server/errors.d.ts +32 -0
  288. package/dist/src/server/errors.d.ts.map +1 -0
  289. package/dist/src/server/errors.js +39 -0
  290. package/dist/src/server/errors.js.map +1 -0
  291. package/dist/src/server/gateway.d.ts +165 -0
  292. package/dist/src/server/gateway.d.ts.map +1 -0
  293. package/dist/src/server/gateway.js +964 -0
  294. package/dist/src/server/gateway.js.map +1 -0
  295. package/dist/src/server/index.d.ts +2 -0
  296. package/dist/src/server/index.d.ts.map +1 -0
  297. package/dist/src/server/index.js +295 -0
  298. package/dist/src/server/index.js.map +1 -0
  299. package/dist/src/server/logger.d.ts +33 -0
  300. package/dist/src/server/logger.d.ts.map +1 -0
  301. package/dist/src/server/logger.js +230 -0
  302. package/dist/src/server/logger.js.map +1 -0
  303. package/dist/src/server/stream-proxy.d.ts +32 -0
  304. package/dist/src/server/stream-proxy.d.ts.map +1 -0
  305. package/dist/src/server/stream-proxy.js +184 -0
  306. package/dist/src/server/stream-proxy.js.map +1 -0
  307. package/dist/src/storage/file-persistence.d.ts +48 -0
  308. package/dist/src/storage/file-persistence.d.ts.map +1 -0
  309. package/dist/src/storage/file-persistence.js +280 -0
  310. package/dist/src/storage/file-persistence.js.map +1 -0
  311. package/dist/src/storage/index.d.ts +5 -0
  312. package/dist/src/storage/index.d.ts.map +1 -0
  313. package/dist/src/storage/index.js +21 -0
  314. package/dist/src/storage/index.js.map +1 -0
  315. package/dist/src/storage/interfaces.d.ts +237 -0
  316. package/dist/src/storage/interfaces.d.ts.map +1 -0
  317. package/dist/src/storage/interfaces.js +3 -0
  318. package/dist/src/storage/interfaces.js.map +1 -0
  319. package/dist/src/storage/memory.d.ts +162 -0
  320. package/dist/src/storage/memory.d.ts.map +1 -0
  321. package/dist/src/storage/memory.js +603 -0
  322. package/dist/src/storage/memory.js.map +1 -0
  323. package/dist/src/storage/postgres.d.ts +267 -0
  324. package/dist/src/storage/postgres.d.ts.map +1 -0
  325. package/dist/src/storage/postgres.js +1555 -0
  326. package/dist/src/storage/postgres.js.map +1 -0
  327. package/dist/src/storage/redis.d.ts +202 -0
  328. package/dist/src/storage/redis.d.ts.map +1 -0
  329. package/dist/src/storage/redis.js +629 -0
  330. package/dist/src/storage/redis.js.map +1 -0
  331. package/dist/src/tracing/index.d.ts +2 -0
  332. package/dist/src/tracing/index.d.ts.map +1 -0
  333. package/dist/src/tracing/index.js +6 -0
  334. package/dist/src/tracing/index.js.map +1 -0
  335. package/dist/src/tracing/provider.d.ts +43 -0
  336. package/dist/src/tracing/provider.d.ts.map +1 -0
  337. package/dist/src/tracing/provider.js +74 -0
  338. package/dist/src/tracing/provider.js.map +1 -0
  339. package/dist/src/trust/calculator.d.ts +54 -0
  340. package/dist/src/trust/calculator.d.ts.map +1 -0
  341. package/dist/src/trust/calculator.js +102 -0
  342. package/dist/src/trust/calculator.js.map +1 -0
  343. package/dist/src/trust/index.d.ts +2 -0
  344. package/dist/src/trust/index.d.ts.map +1 -0
  345. package/dist/src/trust/index.js +7 -0
  346. package/dist/src/trust/index.js.map +1 -0
  347. package/dist/src/types/budget.d.ts +30 -0
  348. package/dist/src/types/budget.d.ts.map +1 -0
  349. package/dist/src/types/budget.js +3 -0
  350. package/dist/src/types/budget.js.map +1 -0
  351. package/dist/src/types/config.d.ts +176 -0
  352. package/dist/src/types/config.d.ts.map +1 -0
  353. package/dist/src/types/config.js +3 -0
  354. package/dist/src/types/config.js.map +1 -0
  355. package/dist/src/types/events.d.ts +24 -0
  356. package/dist/src/types/events.d.ts.map +1 -0
  357. package/dist/src/types/events.js +3 -0
  358. package/dist/src/types/events.js.map +1 -0
  359. package/dist/src/types/index.d.ts +8 -0
  360. package/dist/src/types/index.d.ts.map +1 -0
  361. package/dist/src/types/index.js +24 -0
  362. package/dist/src/types/index.js.map +1 -0
  363. package/dist/src/types/policy.d.ts +60 -0
  364. package/dist/src/types/policy.d.ts.map +1 -0
  365. package/dist/src/types/policy.js +3 -0
  366. package/dist/src/types/policy.js.map +1 -0
  367. package/dist/src/types/stripe-config.d.ts +12 -0
  368. package/dist/src/types/stripe-config.d.ts.map +1 -0
  369. package/dist/src/types/stripe-config.js +3 -0
  370. package/dist/src/types/stripe-config.js.map +1 -0
  371. package/dist/src/types/subscription.d.ts +24 -0
  372. package/dist/src/types/subscription.d.ts.map +1 -0
  373. package/dist/src/types/subscription.js +38 -0
  374. package/dist/src/types/subscription.js.map +1 -0
  375. package/dist/src/types/tool-call.d.ts +42 -0
  376. package/dist/src/types/tool-call.d.ts.map +1 -0
  377. package/dist/src/types/tool-call.js +3 -0
  378. package/dist/src/types/tool-call.js.map +1 -0
  379. package/dist/src/types/tool-result.d.ts +58 -0
  380. package/dist/src/types/tool-result.d.ts.map +1 -0
  381. package/dist/src/types/tool-result.js +3 -0
  382. package/dist/src/types/tool-result.js.map +1 -0
  383. package/dist/src/types/user.d.ts +101 -0
  384. package/dist/src/types/user.d.ts.map +1 -0
  385. package/dist/src/types/user.js +6 -0
  386. package/dist/src/types/user.js.map +1 -0
  387. package/dist/tests/integration/api.test.d.ts +2 -0
  388. package/dist/tests/integration/api.test.d.ts.map +1 -0
  389. package/dist/tests/integration/api.test.js +1199 -0
  390. package/dist/tests/integration/api.test.js.map +1 -0
  391. package/dist/tests/integration/proxy.test.d.ts +2 -0
  392. package/dist/tests/integration/proxy.test.d.ts.map +1 -0
  393. package/dist/tests/integration/proxy.test.js +251 -0
  394. package/dist/tests/integration/proxy.test.js.map +1 -0
  395. package/dist/tests/integration/storage.test.d.ts +16 -0
  396. package/dist/tests/integration/storage.test.d.ts.map +1 -0
  397. package/dist/tests/integration/storage.test.js +826 -0
  398. package/dist/tests/integration/storage.test.js.map +1 -0
  399. package/dist/tests/unit/admin.test.d.ts +2 -0
  400. package/dist/tests/unit/admin.test.d.ts.map +1 -0
  401. package/dist/tests/unit/admin.test.js +698 -0
  402. package/dist/tests/unit/admin.test.js.map +1 -0
  403. package/dist/tests/unit/anomaly-detector.test.d.ts +2 -0
  404. package/dist/tests/unit/anomaly-detector.test.d.ts.map +1 -0
  405. package/dist/tests/unit/anomaly-detector.test.js +903 -0
  406. package/dist/tests/unit/anomaly-detector.test.js.map +1 -0
  407. package/dist/tests/unit/approval-manager.test.d.ts +2 -0
  408. package/dist/tests/unit/approval-manager.test.d.ts.map +1 -0
  409. package/dist/tests/unit/approval-manager.test.js +528 -0
  410. package/dist/tests/unit/approval-manager.test.js.map +1 -0
  411. package/dist/tests/unit/approval-webhook.test.d.ts +2 -0
  412. package/dist/tests/unit/approval-webhook.test.d.ts.map +1 -0
  413. package/dist/tests/unit/approval-webhook.test.js +355 -0
  414. package/dist/tests/unit/approval-webhook.test.js.map +1 -0
  415. package/dist/tests/unit/audit-logger.test.d.ts +2 -0
  416. package/dist/tests/unit/audit-logger.test.d.ts.map +1 -0
  417. package/dist/tests/unit/audit-logger.test.js +635 -0
  418. package/dist/tests/unit/audit-logger.test.js.map +1 -0
  419. package/dist/tests/unit/auth-routes.test.d.ts +2 -0
  420. package/dist/tests/unit/auth-routes.test.d.ts.map +1 -0
  421. package/dist/tests/unit/auth-routes.test.js +281 -0
  422. package/dist/tests/unit/auth-routes.test.js.map +1 -0
  423. package/dist/tests/unit/auth.test.d.ts +2 -0
  424. package/dist/tests/unit/auth.test.d.ts.map +1 -0
  425. package/dist/tests/unit/auth.test.js +1382 -0
  426. package/dist/tests/unit/auth.test.js.map +1 -0
  427. package/dist/tests/unit/billing.test.d.ts +2 -0
  428. package/dist/tests/unit/billing.test.d.ts.map +1 -0
  429. package/dist/tests/unit/billing.test.js +579 -0
  430. package/dist/tests/unit/billing.test.js.map +1 -0
  431. package/dist/tests/unit/budget-manager.test.d.ts +2 -0
  432. package/dist/tests/unit/budget-manager.test.d.ts.map +1 -0
  433. package/dist/tests/unit/budget-manager.test.js +778 -0
  434. package/dist/tests/unit/budget-manager.test.js.map +1 -0
  435. package/dist/tests/unit/budget-race.test.d.ts +2 -0
  436. package/dist/tests/unit/budget-race.test.d.ts.map +1 -0
  437. package/dist/tests/unit/budget-race.test.js +58 -0
  438. package/dist/tests/unit/budget-race.test.js.map +1 -0
  439. package/dist/tests/unit/cli.test.d.ts +2 -0
  440. package/dist/tests/unit/cli.test.d.ts.map +1 -0
  441. package/dist/tests/unit/cli.test.js +93 -0
  442. package/dist/tests/unit/cli.test.js.map +1 -0
  443. package/dist/tests/unit/concurrency.test.d.ts +2 -0
  444. package/dist/tests/unit/concurrency.test.d.ts.map +1 -0
  445. package/dist/tests/unit/concurrency.test.js +1270 -0
  446. package/dist/tests/unit/concurrency.test.js.map +1 -0
  447. package/dist/tests/unit/config-validate.test.d.ts +2 -0
  448. package/dist/tests/unit/config-validate.test.d.ts.map +1 -0
  449. package/dist/tests/unit/config-validate.test.js +230 -0
  450. package/dist/tests/unit/config-validate.test.js.map +1 -0
  451. package/dist/tests/unit/defaults.test.d.ts +2 -0
  452. package/dist/tests/unit/defaults.test.d.ts.map +1 -0
  453. package/dist/tests/unit/defaults.test.js +364 -0
  454. package/dist/tests/unit/defaults.test.js.map +1 -0
  455. package/dist/tests/unit/dlp-backends.test.d.ts +2 -0
  456. package/dist/tests/unit/dlp-backends.test.d.ts.map +1 -0
  457. package/dist/tests/unit/dlp-backends.test.js +563 -0
  458. package/dist/tests/unit/dlp-backends.test.js.map +1 -0
  459. package/dist/tests/unit/dlp-scanner.test.d.ts +2 -0
  460. package/dist/tests/unit/dlp-scanner.test.d.ts.map +1 -0
  461. package/dist/tests/unit/dlp-scanner.test.js +739 -0
  462. package/dist/tests/unit/dlp-scanner.test.js.map +1 -0
  463. package/dist/tests/unit/error-responses.test.d.ts +2 -0
  464. package/dist/tests/unit/error-responses.test.d.ts.map +1 -0
  465. package/dist/tests/unit/error-responses.test.js +101 -0
  466. package/dist/tests/unit/error-responses.test.js.map +1 -0
  467. package/dist/tests/unit/executor-registry.test.d.ts +2 -0
  468. package/dist/tests/unit/executor-registry.test.d.ts.map +1 -0
  469. package/dist/tests/unit/executor-registry.test.js +390 -0
  470. package/dist/tests/unit/executor-registry.test.js.map +1 -0
  471. package/dist/tests/unit/forward-proxy.test.d.ts +2 -0
  472. package/dist/tests/unit/forward-proxy.test.d.ts.map +1 -0
  473. package/dist/tests/unit/forward-proxy.test.js +621 -0
  474. package/dist/tests/unit/forward-proxy.test.js.map +1 -0
  475. package/dist/tests/unit/gateway-features.test.d.ts +2 -0
  476. package/dist/tests/unit/gateway-features.test.d.ts.map +1 -0
  477. package/dist/tests/unit/gateway-features.test.js +753 -0
  478. package/dist/tests/unit/gateway-features.test.js.map +1 -0
  479. package/dist/tests/unit/http-executor.test.d.ts +2 -0
  480. package/dist/tests/unit/http-executor.test.d.ts.map +1 -0
  481. package/dist/tests/unit/http-executor.test.js +310 -0
  482. package/dist/tests/unit/http-executor.test.js.map +1 -0
  483. package/dist/tests/unit/mcp-bridge.test.d.ts +2 -0
  484. package/dist/tests/unit/mcp-bridge.test.d.ts.map +1 -0
  485. package/dist/tests/unit/mcp-bridge.test.js +1136 -0
  486. package/dist/tests/unit/mcp-bridge.test.js.map +1 -0
  487. package/dist/tests/unit/mcp-http-transport.test.d.ts +2 -0
  488. package/dist/tests/unit/mcp-http-transport.test.d.ts.map +1 -0
  489. package/dist/tests/unit/mcp-http-transport.test.js +899 -0
  490. package/dist/tests/unit/mcp-http-transport.test.js.map +1 -0
  491. package/dist/tests/unit/mcp-oauth.test.d.ts +2 -0
  492. package/dist/tests/unit/mcp-oauth.test.d.ts.map +1 -0
  493. package/dist/tests/unit/mcp-oauth.test.js +759 -0
  494. package/dist/tests/unit/mcp-oauth.test.js.map +1 -0
  495. package/dist/tests/unit/mcp-server.test.d.ts +15 -0
  496. package/dist/tests/unit/mcp-server.test.d.ts.map +1 -0
  497. package/dist/tests/unit/mcp-server.test.js +158 -0
  498. package/dist/tests/unit/mcp-server.test.js.map +1 -0
  499. package/dist/tests/unit/metrics.test.d.ts +2 -0
  500. package/dist/tests/unit/metrics.test.d.ts.map +1 -0
  501. package/dist/tests/unit/metrics.test.js +208 -0
  502. package/dist/tests/unit/metrics.test.js.map +1 -0
  503. package/dist/tests/unit/oauth.test.d.ts +2 -0
  504. package/dist/tests/unit/oauth.test.d.ts.map +1 -0
  505. package/dist/tests/unit/oauth.test.js +281 -0
  506. package/dist/tests/unit/oauth.test.js.map +1 -0
  507. package/dist/tests/unit/opa-circuit-breaker.test.d.ts +2 -0
  508. package/dist/tests/unit/opa-circuit-breaker.test.d.ts.map +1 -0
  509. package/dist/tests/unit/opa-circuit-breaker.test.js +297 -0
  510. package/dist/tests/unit/opa-circuit-breaker.test.js.map +1 -0
  511. package/dist/tests/unit/opa-engine.test.d.ts +2 -0
  512. package/dist/tests/unit/opa-engine.test.d.ts.map +1 -0
  513. package/dist/tests/unit/opa-engine.test.js +1813 -0
  514. package/dist/tests/unit/opa-engine.test.js.map +1 -0
  515. package/dist/tests/unit/pipeline-timing.test.d.ts +2 -0
  516. package/dist/tests/unit/pipeline-timing.test.d.ts.map +1 -0
  517. package/dist/tests/unit/pipeline-timing.test.js +528 -0
  518. package/dist/tests/unit/pipeline-timing.test.js.map +1 -0
  519. package/dist/tests/unit/policy-engine.test.d.ts +2 -0
  520. package/dist/tests/unit/policy-engine.test.d.ts.map +1 -0
  521. package/dist/tests/unit/policy-engine.test.js +1345 -0
  522. package/dist/tests/unit/policy-engine.test.js.map +1 -0
  523. package/dist/tests/unit/policy-store.test.d.ts +2 -0
  524. package/dist/tests/unit/policy-store.test.d.ts.map +1 -0
  525. package/dist/tests/unit/policy-store.test.js +60 -0
  526. package/dist/tests/unit/policy-store.test.js.map +1 -0
  527. package/dist/tests/unit/postgres-storage.test.d.ts +2 -0
  528. package/dist/tests/unit/postgres-storage.test.d.ts.map +1 -0
  529. package/dist/tests/unit/postgres-storage.test.js +614 -0
  530. package/dist/tests/unit/postgres-storage.test.js.map +1 -0
  531. package/dist/tests/unit/prompt-injection-backend.test.d.ts +2 -0
  532. package/dist/tests/unit/prompt-injection-backend.test.d.ts.map +1 -0
  533. package/dist/tests/unit/prompt-injection-backend.test.js +621 -0
  534. package/dist/tests/unit/prompt-injection-backend.test.js.map +1 -0
  535. package/dist/tests/unit/proxy-hardening.test.d.ts +2 -0
  536. package/dist/tests/unit/proxy-hardening.test.d.ts.map +1 -0
  537. package/dist/tests/unit/proxy-hardening.test.js +166 -0
  538. package/dist/tests/unit/proxy-hardening.test.js.map +1 -0
  539. package/dist/tests/unit/rate-limiter.test.d.ts +2 -0
  540. package/dist/tests/unit/rate-limiter.test.d.ts.map +1 -0
  541. package/dist/tests/unit/rate-limiter.test.js +443 -0
  542. package/dist/tests/unit/rate-limiter.test.js.map +1 -0
  543. package/dist/tests/unit/redis-storage.test.d.ts +2 -0
  544. package/dist/tests/unit/redis-storage.test.d.ts.map +1 -0
  545. package/dist/tests/unit/redis-storage.test.js +766 -0
  546. package/dist/tests/unit/redis-storage.test.js.map +1 -0
  547. package/dist/tests/unit/replay-engine.test.d.ts +2 -0
  548. package/dist/tests/unit/replay-engine.test.d.ts.map +1 -0
  549. package/dist/tests/unit/replay-engine.test.js +371 -0
  550. package/dist/tests/unit/replay-engine.test.js.map +1 -0
  551. package/dist/tests/unit/saas-routes.test.d.ts +2 -0
  552. package/dist/tests/unit/saas-routes.test.d.ts.map +1 -0
  553. package/dist/tests/unit/saas-routes.test.js +1399 -0
  554. package/dist/tests/unit/saas-routes.test.js.map +1 -0
  555. package/dist/tests/unit/session.test.d.ts +2 -0
  556. package/dist/tests/unit/session.test.d.ts.map +1 -0
  557. package/dist/tests/unit/session.test.js +532 -0
  558. package/dist/tests/unit/session.test.js.map +1 -0
  559. package/dist/tests/unit/slack-executor.test.d.ts +2 -0
  560. package/dist/tests/unit/slack-executor.test.d.ts.map +1 -0
  561. package/dist/tests/unit/slack-executor.test.js +209 -0
  562. package/dist/tests/unit/slack-executor.test.js.map +1 -0
  563. package/dist/tests/unit/storage-hardening.test.d.ts +2 -0
  564. package/dist/tests/unit/storage-hardening.test.d.ts.map +1 -0
  565. package/dist/tests/unit/storage-hardening.test.js +165 -0
  566. package/dist/tests/unit/storage-hardening.test.js.map +1 -0
  567. package/dist/tests/unit/storage.test.d.ts +2 -0
  568. package/dist/tests/unit/storage.test.d.ts.map +1 -0
  569. package/dist/tests/unit/storage.test.js +698 -0
  570. package/dist/tests/unit/storage.test.js.map +1 -0
  571. package/dist/tests/unit/text-normalizer.test.d.ts +2 -0
  572. package/dist/tests/unit/text-normalizer.test.d.ts.map +1 -0
  573. package/dist/tests/unit/text-normalizer.test.js +229 -0
  574. package/dist/tests/unit/text-normalizer.test.js.map +1 -0
  575. package/dist/tests/unit/tracing.test.d.ts +2 -0
  576. package/dist/tests/unit/tracing.test.d.ts.map +1 -0
  577. package/dist/tests/unit/tracing.test.js +611 -0
  578. package/dist/tests/unit/tracing.test.js.map +1 -0
  579. package/dist/tests/unit/trust-calculator.test.d.ts +2 -0
  580. package/dist/tests/unit/trust-calculator.test.d.ts.map +1 -0
  581. package/dist/tests/unit/trust-calculator.test.js +497 -0
  582. package/dist/tests/unit/trust-calculator.test.js.map +1 -0
  583. package/dist/tests/unit/ts-sdk.test.d.ts +2 -0
  584. package/dist/tests/unit/ts-sdk.test.d.ts.map +1 -0
  585. package/dist/tests/unit/ts-sdk.test.js +421 -0
  586. package/dist/tests/unit/ts-sdk.test.js.map +1 -0
  587. package/dist/tests/unit/usage-extractor-llm.test.d.ts +2 -0
  588. package/dist/tests/unit/usage-extractor-llm.test.d.ts.map +1 -0
  589. package/dist/tests/unit/usage-extractor-llm.test.js +139 -0
  590. package/dist/tests/unit/usage-extractor-llm.test.js.map +1 -0
  591. package/dist/tests/unit/usage-extractor.test.d.ts +2 -0
  592. package/dist/tests/unit/usage-extractor.test.d.ts.map +1 -0
  593. package/dist/tests/unit/usage-extractor.test.js +271 -0
  594. package/dist/tests/unit/usage-extractor.test.js.map +1 -0
  595. package/dist/tests/unit/user-stores.test.d.ts +2 -0
  596. package/dist/tests/unit/user-stores.test.d.ts.map +1 -0
  597. package/dist/tests/unit/user-stores.test.js +687 -0
  598. package/dist/tests/unit/user-stores.test.js.map +1 -0
  599. package/dist/tests/unit/validate.test.d.ts +2 -0
  600. package/dist/tests/unit/validate.test.d.ts.map +1 -0
  601. package/dist/tests/unit/validate.test.js +545 -0
  602. package/dist/tests/unit/validate.test.js.map +1 -0
  603. package/package.json +86 -0
  604. package/policy-packs/README.md +42 -0
  605. package/policy-packs/default.yaml +46 -0
  606. package/policy-packs/dev_fast.yaml +54 -0
  607. package/policy-packs/prod_strict.yaml +83 -0
@@ -0,0 +1,720 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.failedAuthAttempts = void 0;
40
+ exports.stopBruteForceCleanup = stopBruteForceCleanup;
41
+ exports.resolvePermissions = resolvePermissions;
42
+ exports.hasPermission = hasPermission;
43
+ exports.hashKeyWithSalt = hashKeyWithSalt;
44
+ exports.generateSalt = generateSalt;
45
+ exports.verifySaasKeyHash = verifySaasKeyHash;
46
+ exports.createSaltedKeyHash = createSaltedKeyHash;
47
+ exports.createAuthMiddleware = createAuthMiddleware;
48
+ exports.parseProxyAuth = parseProxyAuth;
49
+ exports.createRBACMiddleware = createRBACMiddleware;
50
+ const crypto = __importStar(require("crypto"));
51
+ const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
52
+ const jwks_rsa_1 = __importDefault(require("jwks-rsa"));
53
+ const errors_1 = require("../server/errors");
54
+ const logger_1 = require("../server/logger");
55
+ const BRUTE_FORCE_WINDOW_MS = 15 * 60 * 1000; // 15 minutes
56
+ const BRUTE_FORCE_MAX_ATTEMPTS = 5;
57
+ const BRUTE_FORCE_CLEANUP_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes
58
+ const BRUTE_FORCE_MAX_ENTRIES = 100000;
59
+ exports.failedAuthAttempts = new Map();
60
+ let bruteForceCleanupTimer = null;
61
+ function startBruteForceCleanup() {
62
+ if (bruteForceCleanupTimer)
63
+ return;
64
+ bruteForceCleanupTimer = setInterval(() => {
65
+ const now = Date.now();
66
+ for (const [ip, entry] of exports.failedAuthAttempts) {
67
+ if (now - entry.firstAttempt > BRUTE_FORCE_WINDOW_MS && entry.lockedUntil < now) {
68
+ exports.failedAuthAttempts.delete(ip);
69
+ }
70
+ }
71
+ }, BRUTE_FORCE_CLEANUP_INTERVAL_MS);
72
+ // Allow the process to exit even if the interval is running
73
+ if (bruteForceCleanupTimer && typeof bruteForceCleanupTimer === 'object' && 'unref' in bruteForceCleanupTimer) {
74
+ bruteForceCleanupTimer.unref();
75
+ }
76
+ }
77
+ function stopBruteForceCleanup() {
78
+ if (bruteForceCleanupTimer) {
79
+ clearInterval(bruteForceCleanupTimer);
80
+ bruteForceCleanupTimer = null;
81
+ }
82
+ }
83
+ function getClientIp(req, trustedProxies) {
84
+ const socketIp = req.socket?.remoteAddress || req.ip || 'unknown';
85
+ // Only trust X-Forwarded-For when the direct connection is from a trusted proxy
86
+ if (trustedProxies && trustedProxies.length > 0) {
87
+ const normalizedSocketIp = socketIp.replace(/^::ffff:/, '');
88
+ if (trustedProxies.includes(normalizedSocketIp)) {
89
+ const forwarded = req.headers['x-forwarded-for'];
90
+ if (typeof forwarded === 'string') {
91
+ return forwarded.split(',')[0].trim();
92
+ }
93
+ }
94
+ }
95
+ return socketIp;
96
+ }
97
+ function evictBruteForceEntries() {
98
+ const now = Date.now();
99
+ const aggressiveWindowMs = 5 * 60 * 1000; // 5 minutes (stricter than normal 15 min)
100
+ // First pass: delete entries older than 5 minutes
101
+ for (const [ip, entry] of exports.failedAuthAttempts) {
102
+ if (now - entry.firstAttempt > aggressiveWindowMs && entry.lockedUntil < now) {
103
+ exports.failedAuthAttempts.delete(ip);
104
+ }
105
+ }
106
+ // If still over limit, delete the oldest half
107
+ if (exports.failedAuthAttempts.size > BRUTE_FORCE_MAX_ENTRIES) {
108
+ const entries = Array.from(exports.failedAuthAttempts.entries())
109
+ .sort((a, b) => a[1].firstAttempt - b[1].firstAttempt);
110
+ const toDelete = Math.ceil(entries.length / 2);
111
+ for (let i = 0; i < toDelete; i++) {
112
+ exports.failedAuthAttempts.delete(entries[i][0]);
113
+ }
114
+ }
115
+ }
116
+ function recordAuthFailure(ip) {
117
+ const now = Date.now();
118
+ // Cap map size to prevent unbounded memory growth
119
+ if (exports.failedAuthAttempts.size >= BRUTE_FORCE_MAX_ENTRIES) {
120
+ evictBruteForceEntries();
121
+ }
122
+ const entry = exports.failedAuthAttempts.get(ip);
123
+ if (!entry || now - entry.firstAttempt > BRUTE_FORCE_WINDOW_MS) {
124
+ // Start a new window
125
+ exports.failedAuthAttempts.set(ip, { count: 1, firstAttempt: now, lockedUntil: 0 });
126
+ return;
127
+ }
128
+ entry.count++;
129
+ if (entry.count >= BRUTE_FORCE_MAX_ATTEMPTS) {
130
+ // Exponential backoff: 1s, 2s, 4s, 8s, 16s for subsequent failures
131
+ const excessFailures = entry.count - BRUTE_FORCE_MAX_ATTEMPTS;
132
+ const backoffMs = Math.min(1000 * Math.pow(2, excessFailures), 16000);
133
+ entry.lockedUntil = now + backoffMs;
134
+ }
135
+ }
136
+ function clearAuthFailures(ip) {
137
+ exports.failedAuthAttempts.delete(ip);
138
+ }
139
+ function checkBruteForce(ip) {
140
+ const entry = exports.failedAuthAttempts.get(ip);
141
+ if (!entry)
142
+ return { locked: false };
143
+ const now = Date.now();
144
+ if (entry.lockedUntil > now) {
145
+ return { locked: true, retryAfterSec: Math.ceil((entry.lockedUntil - now) / 1000) };
146
+ }
147
+ return { locked: false };
148
+ }
149
+ // ---------------------------------------------------------------------------
150
+ // Helpers
151
+ // ---------------------------------------------------------------------------
152
+ /**
153
+ * Resolve a set of role names into a flat Permission[] array using the RBAC config.
154
+ */
155
+ function resolvePermissions(roles, rbacConfig) {
156
+ if (!rbacConfig || !rbacConfig.enabled) {
157
+ return [];
158
+ }
159
+ const permissionSet = new Set();
160
+ for (const roleName of roles) {
161
+ const roleDef = rbacConfig.roles[roleName];
162
+ if (roleDef) {
163
+ for (const p of roleDef.permissions) {
164
+ permissionSet.add(p);
165
+ }
166
+ }
167
+ }
168
+ return Array.from(permissionSet);
169
+ }
170
+ /**
171
+ * Check whether a given set of permissions satisfies a required permission.
172
+ * - `admin:full` always satisfies any permission.
173
+ * - `tool:execute` satisfies any `tool:execute:*` check.
174
+ */
175
+ function hasPermission(permissions, required) {
176
+ if (permissions.includes('admin:full'))
177
+ return true;
178
+ if (permissions.includes(required))
179
+ return true;
180
+ // tool:execute grants all tool:execute:* sub-permissions
181
+ if (required.startsWith('tool:execute:') && permissions.includes('tool:execute')) {
182
+ return true;
183
+ }
184
+ return false;
185
+ }
186
+ // ---------------------------------------------------------------------------
187
+ // JWKS signing key retrieval (cached per jwks_uri)
188
+ // ---------------------------------------------------------------------------
189
+ const jwksClients = new Map();
190
+ function getJwksClient(uri) {
191
+ let client = jwksClients.get(uri);
192
+ if (!client) {
193
+ client = new jwks_rsa_1.default.JwksClient({
194
+ jwksUri: uri,
195
+ cache: true,
196
+ cacheMaxAge: 600000, // 10 min
197
+ rateLimit: true,
198
+ jwksRequestsPerMinute: 10,
199
+ });
200
+ jwksClients.set(uri, client);
201
+ }
202
+ return client;
203
+ }
204
+ function getJwksSigningKey(uri, header) {
205
+ const client = getJwksClient(uri);
206
+ return new Promise((resolve, reject) => {
207
+ client.getSigningKey(header.kid, (err, key) => {
208
+ if (err)
209
+ return reject(err);
210
+ if (!key)
211
+ return reject(new Error('No signing key found'));
212
+ const signingKey = key.getPublicKey();
213
+ resolve(signingKey);
214
+ });
215
+ });
216
+ }
217
+ // ---------------------------------------------------------------------------
218
+ // JWT verification
219
+ // ---------------------------------------------------------------------------
220
+ async function verifyJWT(token, config) {
221
+ const jwtConfig = config.jwt;
222
+ if (!jwtConfig || !jwtConfig.enabled) {
223
+ return { error: 'JWT authentication is not configured' };
224
+ }
225
+ // Determine the secret or key
226
+ // IMPORTANT: Prevent algorithm confusion attacks by restricting algorithms
227
+ // based on the verification method. Never allow symmetric (HS*) algorithms
228
+ // when using JWKS (asymmetric keys), and vice versa.
229
+ if (jwtConfig.jwks_uri) {
230
+ // JWKS-based: only asymmetric algorithms allowed
231
+ const ASYMMETRIC_ALGOS = ['RS256', 'RS384', 'RS512', 'ES256', 'ES384', 'ES512', 'PS256', 'PS384', 'PS512'];
232
+ const userAlgos = jwtConfig.algorithms;
233
+ const algorithms = userAlgos
234
+ ? userAlgos.filter(a => ASYMMETRIC_ALGOS.includes(a))
235
+ : ['RS256'];
236
+ if (algorithms.length === 0) {
237
+ return { error: 'No valid asymmetric algorithms configured for JWKS verification' };
238
+ }
239
+ try {
240
+ const decoded = jsonwebtoken_1.default.decode(token, { complete: true });
241
+ if (!decoded || typeof decoded === 'string') {
242
+ return { error: 'Invalid JWT format' };
243
+ }
244
+ const signingKey = await getJwksSigningKey(jwtConfig.jwks_uri, decoded.header);
245
+ const payload = jsonwebtoken_1.default.verify(token, signingKey, {
246
+ algorithms,
247
+ issuer: jwtConfig.issuer,
248
+ audience: jwtConfig.audience,
249
+ });
250
+ return { payload };
251
+ }
252
+ catch (err) {
253
+ const msg = err instanceof Error ? err.message : 'JWT verification failed';
254
+ return { error: msg };
255
+ }
256
+ }
257
+ else if (jwtConfig.secret) {
258
+ // Static secret: only symmetric algorithms allowed
259
+ const SYMMETRIC_ALGOS = ['HS256', 'HS384', 'HS512'];
260
+ const userAlgos = jwtConfig.algorithms;
261
+ const algorithms = userAlgos
262
+ ? userAlgos.filter(a => SYMMETRIC_ALGOS.includes(a))
263
+ : ['HS256'];
264
+ if (algorithms.length === 0) {
265
+ return { error: 'No valid symmetric algorithms configured for secret-based verification' };
266
+ }
267
+ try {
268
+ const payload = jsonwebtoken_1.default.verify(token, jwtConfig.secret, {
269
+ algorithms,
270
+ issuer: jwtConfig.issuer,
271
+ audience: jwtConfig.audience,
272
+ });
273
+ return { payload };
274
+ }
275
+ catch (err) {
276
+ const msg = err instanceof Error ? err.message : 'JWT verification failed';
277
+ return { error: msg };
278
+ }
279
+ }
280
+ return { error: 'JWT auth enabled but no secret or jwks_uri configured' };
281
+ }
282
+ // ---------------------------------------------------------------------------
283
+ // Hash-based API key lookup helpers (constant-time, prevents timing attacks)
284
+ // ---------------------------------------------------------------------------
285
+ /** SHA-256 hash a key for constant-time lookup (legacy unsalted) */
286
+ function hashKey(key) {
287
+ return crypto.createHash('sha256').update(key).digest('hex');
288
+ }
289
+ /** SHA-256 hash a key with a salt */
290
+ function hashKeyWithSalt(key, salt) {
291
+ return crypto.createHash('sha256').update(salt + key).digest('hex');
292
+ }
293
+ /** Generate a 16-byte random salt as hex string */
294
+ function generateSalt() {
295
+ return crypto.randomBytes(16).toString('hex');
296
+ }
297
+ /** Dummy buffer used for constant-time comparison when no match is found */
298
+ const DUMMY_HASH = crypto.createHash('sha256').update('dummy-no-match-sentinel').digest('hex');
299
+ /**
300
+ * Build a hash map from config API keys for O(1) lookup.
301
+ * Maps SHA-256(key) -> original key string.
302
+ */
303
+ function buildKeyHashMap(apiKeys) {
304
+ const map = new Map();
305
+ for (const key of Object.keys(apiKeys)) {
306
+ map.set(hashKey(key), key);
307
+ }
308
+ return map;
309
+ }
310
+ /** Cache for buildKeyHashMap to avoid rebuilding per-request (e.g. in proxy auth) */
311
+ const keyHashMapCache = new WeakMap();
312
+ /** Get or build a cached key hash map for the given api_keys config object */
313
+ function getCachedKeyHashMap(apiKeys) {
314
+ let cached = keyHashMapCache.get(apiKeys);
315
+ if (!cached) {
316
+ cached = buildKeyHashMap(apiKeys);
317
+ keyHashMapCache.set(apiKeys, cached);
318
+ }
319
+ return cached;
320
+ }
321
+ /**
322
+ * Look up an API key by its hash. Uses timingSafeEqual for final verification
323
+ * and always performs a comparison (even on miss) to prevent timing leaks.
324
+ */
325
+ function lookupApiKey(token, apiKeys, keyHashMap) {
326
+ const tokenHash = hashKey(token);
327
+ const candidateKey = keyHashMap.get(tokenHash);
328
+ // Always do a timingSafeEqual comparison regardless of match to prevent
329
+ // timing leaks between "no keys match" vs "a key matched"
330
+ const a = Buffer.from(tokenHash);
331
+ const b = Buffer.from(candidateKey ? hashKey(candidateKey) : DUMMY_HASH);
332
+ const isMatch = crypto.timingSafeEqual(a, b);
333
+ return isMatch && candidateKey ? candidateKey : undefined;
334
+ }
335
+ // ---------------------------------------------------------------------------
336
+ // Salted SaaS key lookup (backward compatible with unsalted hashes)
337
+ // ---------------------------------------------------------------------------
338
+ /**
339
+ * Compute the hash for a token given a stored key_hash value.
340
+ * Supports salted format "salt:hash" and legacy unsalted plain hex format.
341
+ * Returns true if the token matches the stored hash.
342
+ */
343
+ function verifySaasKeyHash(token, storedKeyHash) {
344
+ if (storedKeyHash.includes(':')) {
345
+ // Salted format: "salt:hash"
346
+ const colonIndex = storedKeyHash.indexOf(':');
347
+ const salt = storedKeyHash.slice(0, colonIndex);
348
+ const expectedHash = storedKeyHash.slice(colonIndex + 1);
349
+ const computedHash = hashKeyWithSalt(token, salt);
350
+ // Constant-time comparison
351
+ const a = Buffer.from(computedHash, 'hex');
352
+ const b = Buffer.from(expectedHash, 'hex');
353
+ if (a.length !== b.length)
354
+ return false;
355
+ return crypto.timingSafeEqual(a, b);
356
+ }
357
+ // Legacy unsalted format: plain hex
358
+ const computedHash = hashKey(token);
359
+ const a = Buffer.from(computedHash, 'hex');
360
+ const b = Buffer.from(storedKeyHash, 'hex');
361
+ if (a.length !== b.length)
362
+ return false;
363
+ return crypto.timingSafeEqual(a, b);
364
+ }
365
+ /**
366
+ * Create a salted key hash for storage. Returns "salt:hash" format.
367
+ */
368
+ function createSaltedKeyHash(key) {
369
+ const salt = generateSalt();
370
+ const hash = hashKeyWithSalt(key, salt);
371
+ return `${salt}:${hash}`;
372
+ }
373
+ /**
374
+ * Look up a SaaS-generated API key. Uses verifyToken if available (supports
375
+ * both salted and unsalted hashes), otherwise falls back to unsalted hash lookup.
376
+ */
377
+ function lookupSaasKey(token, store) {
378
+ // Prefer verifyToken which handles both salted and unsalted formats
379
+ if (store.verifyToken) {
380
+ return store.verifyToken(token);
381
+ }
382
+ // Fallback: legacy unsalted hash lookup
383
+ const unsaltedHash = hashKey(token);
384
+ return store.getByKeyHash(unsaltedHash);
385
+ }
386
+ // ---------------------------------------------------------------------------
387
+ // Main auth middleware
388
+ // ---------------------------------------------------------------------------
389
+ function createAuthMiddleware(config, userApiKeyStore) {
390
+ // Pre-build hash map for O(1) key lookup
391
+ const keyHashMap = buildKeyHashMap(config.api_keys);
392
+ // Start brute-force cleanup timer
393
+ startBruteForceCleanup();
394
+ return async (req, res, next) => {
395
+ // -----------------------------------------------------------------------
396
+ // Session auth: if session middleware already set req.auth, pass through
397
+ // -----------------------------------------------------------------------
398
+ if (req.auth) {
399
+ return next();
400
+ }
401
+ // -----------------------------------------------------------------------
402
+ // Auth disabled: pass through with defaults
403
+ // -----------------------------------------------------------------------
404
+ if (!config.enabled) {
405
+ const authCtx = {
406
+ workspace_id: 'ws_default',
407
+ actor_id: 'anonymous',
408
+ roles: [],
409
+ permissions: [],
410
+ auth_method: 'none',
411
+ };
412
+ req.auth = authCtx;
413
+ // Backward compat
414
+ req.workspace_id = authCtx.workspace_id;
415
+ return next();
416
+ }
417
+ // -----------------------------------------------------------------------
418
+ // Brute-force protection: check if IP is locked
419
+ // -----------------------------------------------------------------------
420
+ const clientIp = getClientIp(req, config.trusted_proxies);
421
+ const bruteForceCheck = checkBruteForce(clientIp);
422
+ if (bruteForceCheck.locked) {
423
+ res.setHeader('Retry-After', String(bruteForceCheck.retryAfterSec));
424
+ (0, errors_1.sendError)(res, 429, errors_1.ErrorCode.RATE_LIMIT_EXCEEDED, 'Too many failed authentication attempts. Try again later.', {
425
+ hint: `Retry after ${bruteForceCheck.retryAfterSec} seconds`,
426
+ });
427
+ return;
428
+ }
429
+ // -----------------------------------------------------------------------
430
+ // Extract token from headers
431
+ // -----------------------------------------------------------------------
432
+ const apiKeyHeader = req.headers['x-api-key'];
433
+ const authHeader = req.headers['authorization'];
434
+ const bearerToken = authHeader?.startsWith('Bearer ') ? authHeader.slice(7) : undefined;
435
+ const token = apiKeyHeader || bearerToken;
436
+ if (!token) {
437
+ recordAuthFailure(clientIp);
438
+ (0, errors_1.sendError)(res, 401, errors_1.ErrorCode.AUTH_REQUIRED, 'Missing API key. Provide X-API-Key header or Bearer token.', {
439
+ hint: 'Provide X-API-Key header or Authorization: Bearer <token>',
440
+ });
441
+ return;
442
+ }
443
+ // -----------------------------------------------------------------------
444
+ // Try API key auth first (hash-based lookup to prevent timing attacks)
445
+ // -----------------------------------------------------------------------
446
+ const matchedKey = lookupApiKey(token, config.api_keys, keyHashMap);
447
+ const keyConfig = matchedKey ? config.api_keys[matchedKey] : undefined;
448
+ if (keyConfig) {
449
+ // Check revocation
450
+ if (keyConfig.revoked) {
451
+ recordAuthFailure(clientIp);
452
+ (0, errors_1.sendError)(res, 403, errors_1.ErrorCode.AUTH_KEY_REVOKED, 'API key has been revoked.', {
453
+ hint: 'Generate a new key via /admin/api-keys',
454
+ });
455
+ return;
456
+ }
457
+ // Check expiration
458
+ if (keyConfig.expires_at) {
459
+ const expiresAt = new Date(keyConfig.expires_at);
460
+ if (expiresAt.getTime() <= Date.now()) {
461
+ recordAuthFailure(clientIp);
462
+ (0, errors_1.sendError)(res, 403, errors_1.ErrorCode.AUTH_KEY_EXPIRED, 'API key has expired.', {
463
+ hint: 'Renew the key or create a new one via /admin/api-keys',
464
+ });
465
+ return;
466
+ }
467
+ }
468
+ // Auth success: clear brute-force entry
469
+ clearAuthFailures(clientIp);
470
+ // Fire-and-forget: update last_used_at
471
+ keyConfig.last_used_at = new Date().toISOString();
472
+ // Resolve roles and permissions
473
+ const roles = keyConfig.roles || [];
474
+ const permissions = resolvePermissions(roles, config.rbac);
475
+ const authCtx = {
476
+ workspace_id: keyConfig.workspace_id,
477
+ actor_id: `apikey:${crypto.createHash('sha256').update(token).digest('hex').slice(0, 12)}`,
478
+ roles,
479
+ permissions,
480
+ auth_method: 'api_key',
481
+ api_key_id: token,
482
+ };
483
+ req.auth = authCtx;
484
+ // Backward compat
485
+ req.workspace_id = keyConfig.workspace_id;
486
+ req.api_key_description = keyConfig.description;
487
+ return next();
488
+ }
489
+ // -----------------------------------------------------------------------
490
+ // Try SaaS-generated API key (UserApiKeyStore, salted or legacy hash lookup)
491
+ // -----------------------------------------------------------------------
492
+ if (userApiKeyStore) {
493
+ const saasKey = lookupSaasKey(token, userApiKeyStore);
494
+ if (saasKey) {
495
+ if (saasKey.revoked) {
496
+ recordAuthFailure(clientIp);
497
+ (0, errors_1.sendError)(res, 403, errors_1.ErrorCode.AUTH_KEY_REVOKED, 'API key has been revoked.', {
498
+ hint: 'Generate a new key via /admin/api-keys',
499
+ });
500
+ return;
501
+ }
502
+ // Auth success: clear brute-force entry
503
+ clearAuthFailures(clientIp);
504
+ // Fire-and-forget: update last_used_at
505
+ userApiKeyStore.update(saasKey.id, { last_used_at: new Date().toISOString() });
506
+ const roles = saasKey.roles || [];
507
+ const permissions = resolvePermissions(roles, config.rbac);
508
+ const authCtx = {
509
+ workspace_id: saasKey.workspace_id,
510
+ actor_id: `apikey:${crypto.createHash('sha256').update(token).digest('hex').slice(0, 12)}`,
511
+ roles,
512
+ permissions,
513
+ auth_method: 'api_key',
514
+ api_key_id: saasKey.id,
515
+ user_id: saasKey.user_id,
516
+ api_key_tags: saasKey.tags && saasKey.tags.length > 0 ? saasKey.tags : undefined,
517
+ };
518
+ req.auth = authCtx;
519
+ req.workspace_id = saasKey.workspace_id;
520
+ return next();
521
+ }
522
+ }
523
+ // -----------------------------------------------------------------------
524
+ // Try JWT auth (only if bearer token and JWT is configured)
525
+ // -----------------------------------------------------------------------
526
+ if (bearerToken && config.jwt?.enabled) {
527
+ const result = await verifyJWT(bearerToken, config);
528
+ if ('error' in result) {
529
+ recordAuthFailure(clientIp);
530
+ (0, errors_1.sendError)(res, 401, errors_1.ErrorCode.AUTH_INVALID_KEY, `JWT verification failed: ${result.error}`, {
531
+ hint: 'Check that the JWT is properly signed and not expired',
532
+ });
533
+ return;
534
+ }
535
+ // Auth success: clear brute-force entry
536
+ clearAuthFailures(clientIp);
537
+ const payload = result.payload;
538
+ const workspaceClaim = config.jwt.workspace_claim || 'workspace_id';
539
+ const rolesClaim = config.jwt.roles_claim || 'roles';
540
+ const actorClaim = config.jwt.actor_claim || 'sub';
541
+ const workspaceId = payload[workspaceClaim] || 'ws_default';
542
+ const roles = Array.isArray(payload[rolesClaim]) ? payload[rolesClaim] : [];
543
+ const actorId = payload[actorClaim] || 'unknown';
544
+ const permissions = resolvePermissions(roles, config.rbac);
545
+ const authCtx = {
546
+ workspace_id: workspaceId,
547
+ actor_id: actorId,
548
+ roles,
549
+ permissions,
550
+ auth_method: 'jwt',
551
+ };
552
+ req.auth = authCtx;
553
+ // Backward compat
554
+ req.workspace_id = workspaceId;
555
+ return next();
556
+ }
557
+ // -----------------------------------------------------------------------
558
+ // No valid auth found
559
+ // -----------------------------------------------------------------------
560
+ recordAuthFailure(clientIp);
561
+ (0, errors_1.sendError)(res, 403, errors_1.ErrorCode.AUTH_INVALID_KEY, 'Invalid API key.', {
562
+ hint: 'Check that the API key is correct and has not been revoked',
563
+ });
564
+ return;
565
+ };
566
+ }
567
+ /**
568
+ * Parse proxy auth from an HTTP request's Proxy-Authorization header.
569
+ * Format: `Proxy-Authorization: Basic base64(workspace_id:api_key)`
570
+ *
571
+ * Falls back to sidecar defaults (env vars) if no header is present.
572
+ * Also checks X-Palaryn-Workspace and X-Palaryn-Actor headers as overrides.
573
+ */
574
+ function parseProxyAuth(headers, proxyConfig, authConfig) {
575
+ const proxyAuthHeader = headers['proxy-authorization'];
576
+ const workspaceHeader = headers['x-palaryn-workspace'];
577
+ const actorHeader = headers['x-palaryn-actor'];
578
+ // Try Proxy-Authorization: Basic <base64>
579
+ if (proxyAuthHeader) {
580
+ const match = proxyAuthHeader.match(/^Basic\s+(.+)$/i);
581
+ if (!match) {
582
+ return { authenticated: false, error: 'Invalid Proxy-Authorization format. Expected: Basic <base64>' };
583
+ }
584
+ const decoded = Buffer.from(match[1], 'base64').toString('utf-8');
585
+ const colonIndex = decoded.indexOf(':');
586
+ if (colonIndex === -1) {
587
+ return { authenticated: false, error: 'Invalid Proxy-Authorization credentials. Expected: workspace_id:api_key' };
588
+ }
589
+ const workspaceId = decoded.slice(0, colonIndex);
590
+ const apiKey = decoded.slice(colonIndex + 1);
591
+ if (!workspaceId || !apiKey) {
592
+ return { authenticated: false, error: 'Empty workspace_id or api_key in Proxy-Authorization' };
593
+ }
594
+ // Validate API key against config (hash-based lookup to prevent timing attacks)
595
+ if (authConfig.enabled) {
596
+ const proxyKeyHashMap = getCachedKeyHashMap(authConfig.api_keys);
597
+ const matchedKey = lookupApiKey(apiKey, authConfig.api_keys, proxyKeyHashMap);
598
+ const keyConfig = matchedKey ? authConfig.api_keys[matchedKey] : undefined;
599
+ if (!keyConfig) {
600
+ return { authenticated: false, error: 'Invalid API key in Proxy-Authorization' };
601
+ }
602
+ if (keyConfig.revoked) {
603
+ return { authenticated: false, error: 'API key has been revoked' };
604
+ }
605
+ if (keyConfig.expires_at) {
606
+ const expiresAt = new Date(keyConfig.expires_at);
607
+ if (expiresAt.getTime() <= Date.now()) {
608
+ return { authenticated: false, error: 'API key has expired' };
609
+ }
610
+ }
611
+ keyConfig.last_used_at = new Date().toISOString();
612
+ }
613
+ return {
614
+ authenticated: true,
615
+ workspace_id: workspaceId,
616
+ api_key: apiKey,
617
+ actor_id: actorHeader || `proxy:${workspaceId}`,
618
+ };
619
+ }
620
+ // Fall back to sidecar defaults from config/env vars
621
+ if (proxyConfig.default_workspace_id) {
622
+ return {
623
+ authenticated: true,
624
+ workspace_id: workspaceHeader || proxyConfig.default_workspace_id,
625
+ actor_id: actorHeader || proxyConfig.default_actor_id || 'proxy:sidecar',
626
+ };
627
+ }
628
+ // Header-only auth (X-Palaryn-Workspace without Proxy-Authorization).
629
+ // Only allowed when auth is not required (permissive/dev mode).
630
+ // When require_auth is true, headers alone are not sufficient — they can be
631
+ // spoofed by any client. Require Proxy-Authorization or sidecar defaults.
632
+ if (workspaceHeader && !proxyConfig.require_auth) {
633
+ logger_1.logger.warn('Unauthenticated request using header-provided identity — headers can be spoofed, enable require_auth in production', { component: 'proxy-auth', workspace: workspaceHeader, actor: actorHeader || 'default' });
634
+ return {
635
+ authenticated: true,
636
+ workspace_id: workspaceHeader,
637
+ actor_id: actorHeader || `proxy:${workspaceHeader}`,
638
+ };
639
+ }
640
+ // If auth is not required (permissive mode), use defaults
641
+ if (!proxyConfig.require_auth) {
642
+ logger_1.logger.warn('Unauthenticated proxy request using default identity (ws_default/proxy:anonymous) — enable require_auth in production', { component: 'proxy-auth' });
643
+ return {
644
+ authenticated: true,
645
+ workspace_id: 'ws_default',
646
+ actor_id: 'proxy:anonymous',
647
+ };
648
+ }
649
+ return {
650
+ authenticated: false,
651
+ error: 'Proxy-Authorization required. Use Basic auth with workspace_id:api_key or set PALARYN_WORKSPACE_ID env var for sidecar mode',
652
+ };
653
+ }
654
+ // ---------------------------------------------------------------------------
655
+ // RBAC middleware factory
656
+ // ---------------------------------------------------------------------------
657
+ function createRBACMiddleware(config, requiredPermission) {
658
+ return (req, res, next) => {
659
+ // Even with RBAC disabled, admin endpoints require the key to have an admin role
660
+ if (!config.rbac?.enabled) {
661
+ if (requiredPermission === 'admin:full') {
662
+ const authCtx = req.auth;
663
+ // Allow if auth is disabled (no keys configured) or if the key has admin role
664
+ if (authCtx && authCtx.auth_method !== 'none') {
665
+ const keyRoles = authCtx.roles || [];
666
+ const hasAdmin = keyRoles.includes('admin');
667
+ if (!hasAdmin) {
668
+ // Check if the key has explicit admin:full permission via configured roles
669
+ const rbacForResolve = config.rbac?.roles
670
+ ? { ...config.rbac, enabled: true }
671
+ : { enabled: true, roles: { admin: { description: 'Admin', permissions: ['admin:full'] } }, default_role: 'agent' };
672
+ const keyPerms = resolvePermissions(keyRoles, rbacForResolve);
673
+ if (!hasPermission(keyPerms, 'admin:full')) {
674
+ (0, errors_1.sendError)(res, 403, errors_1.ErrorCode.AUTH_INSUFFICIENT_PERMS, 'Admin access required', {
675
+ hint: 'Use an API key with the admin role to access this endpoint',
676
+ });
677
+ return;
678
+ }
679
+ }
680
+ }
681
+ }
682
+ return next();
683
+ }
684
+ const authCtx = req.auth;
685
+ if (!authCtx) {
686
+ (0, errors_1.sendError)(res, 401, errors_1.ErrorCode.AUTH_REQUIRED, 'Authentication required', {
687
+ hint: 'Provide X-API-Key header or Authorization: Bearer <token>',
688
+ });
689
+ return;
690
+ }
691
+ // Auth method 'none' (auth disabled) - allow through
692
+ if (authCtx.auth_method === 'none') {
693
+ return next();
694
+ }
695
+ // If user has no roles and a default_role is configured, apply it
696
+ let permissions = authCtx.permissions;
697
+ if (authCtx.roles.length === 0 && config.rbac.default_role) {
698
+ // Prevent escalation: default_role must not be admin or operator
699
+ let effectiveDefaultRole = config.rbac.default_role;
700
+ if (effectiveDefaultRole === 'admin' || effectiveDefaultRole === 'operator') {
701
+ logger_1.logger.warn(`default_role '${effectiveDefaultRole}' is a privileged role — falling back to 'readonly'`, { component: 'auth' });
702
+ effectiveDefaultRole = 'readonly';
703
+ }
704
+ const defaultPerms = resolvePermissions([effectiveDefaultRole], config.rbac);
705
+ permissions = defaultPerms;
706
+ // Also update the auth context with the default role's permissions
707
+ authCtx.roles = [effectiveDefaultRole];
708
+ authCtx.permissions = defaultPerms;
709
+ }
710
+ if (!hasPermission(permissions, requiredPermission)) {
711
+ (0, errors_1.sendError)(res, 403, errors_1.ErrorCode.AUTH_INSUFFICIENT_PERMS, `Insufficient permissions. Required: ${requiredPermission}`, {
712
+ details: { required_permission: requiredPermission, roles: authCtx.roles },
713
+ hint: 'Assign a role with the required permission or use an admin key',
714
+ });
715
+ return;
716
+ }
717
+ return next();
718
+ };
719
+ }
720
+ //# sourceMappingURL=auth.js.map