@ipul-labs/forge 1.22.0 → 1.35.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (294) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +153 -78
  3. package/dist/apple-touch-icon.png +0 -0
  4. package/dist/assets/index-CNvSOdpC.js +27 -0
  5. package/dist/assets/index-CSH1OQYQ.css +1 -0
  6. package/dist/boot-check.js +98 -0
  7. package/dist/favicon.svg +8 -0
  8. package/dist/icon-192.png +0 -0
  9. package/dist/icon-512.png +0 -0
  10. package/dist/icon.svg +12 -0
  11. package/dist/index.html +33 -0
  12. package/dist/manifest.webmanifest +18 -0
  13. package/dist/theme-init.js +11 -0
  14. package/lib/bin/cli/analyze.d.ts.map +1 -1
  15. package/lib/bin/cli/analyze.js +3 -44
  16. package/lib/bin/cli/analyze.js.map +1 -1
  17. package/lib/bin/cli/apply.d.ts.map +1 -1
  18. package/lib/bin/cli/apply.js +2 -20
  19. package/lib/bin/cli/apply.js.map +1 -1
  20. package/lib/bin/cli/cifix.d.ts.map +1 -1
  21. package/lib/bin/cli/cifix.js +4 -28
  22. package/lib/bin/cli/cifix.js.map +1 -1
  23. package/lib/bin/cli/close.d.ts.map +1 -1
  24. package/lib/bin/cli/close.js +2 -33
  25. package/lib/bin/cli/close.js.map +1 -1
  26. package/lib/bin/cli/createIssue.d.ts.map +1 -1
  27. package/lib/bin/cli/createIssue.js +3 -12
  28. package/lib/bin/cli/createIssue.js.map +1 -1
  29. package/lib/bin/cli/doctor.d.ts.map +1 -1
  30. package/lib/bin/cli/doctor.js +3 -4
  31. package/lib/bin/cli/doctor.js.map +1 -1
  32. package/lib/bin/cli/init.js +1 -10
  33. package/lib/bin/cli/init.js.map +1 -1
  34. package/lib/bin/cli/issue.d.ts.map +1 -1
  35. package/lib/bin/cli/issue.js +3 -12
  36. package/lib/bin/cli/issue.js.map +1 -1
  37. package/lib/bin/cli/issues.d.ts.map +1 -1
  38. package/lib/bin/cli/issues.js +3 -12
  39. package/lib/bin/cli/issues.js.map +1 -1
  40. package/lib/bin/cli/merge.d.ts.map +1 -1
  41. package/lib/bin/cli/merge.js +4 -20
  42. package/lib/bin/cli/merge.js.map +1 -1
  43. package/lib/bin/cli/refine.d.ts.map +1 -1
  44. package/lib/bin/cli/refine.js +2 -26
  45. package/lib/bin/cli/refine.js.map +1 -1
  46. package/lib/bin/cli/repl.d.ts.map +1 -1
  47. package/lib/bin/cli/repl.js +4 -13
  48. package/lib/bin/cli/repl.js.map +1 -1
  49. package/lib/bin/cli/repos.d.ts.map +1 -1
  50. package/lib/bin/cli/repos.js +1 -11
  51. package/lib/bin/cli/repos.js.map +1 -1
  52. package/lib/bin/cli/resetPassword.d.ts +21 -0
  53. package/lib/bin/cli/resetPassword.d.ts.map +1 -0
  54. package/lib/bin/cli/resetPassword.js +69 -0
  55. package/lib/bin/cli/resetPassword.js.map +1 -0
  56. package/lib/bin/cli/resolution.d.ts.map +1 -1
  57. package/lib/bin/cli/resolution.js +2 -19
  58. package/lib/bin/cli/resolution.js.map +1 -1
  59. package/lib/bin/cli/serverClient.d.ts +2 -0
  60. package/lib/bin/cli/serverClient.d.ts.map +1 -1
  61. package/lib/bin/cli/serverClient.js +8 -4
  62. package/lib/bin/cli/serverClient.js.map +1 -1
  63. package/lib/bin/cli/session.d.ts.map +1 -1
  64. package/lib/bin/cli/session.js.map +1 -1
  65. package/lib/bin/cli/sessionStore.d.ts +1 -1
  66. package/lib/bin/cli/sessionStore.js +2 -2
  67. package/lib/bin/cli/sessionStore.js.map +1 -1
  68. package/lib/bin/cli/ship.d.ts.map +1 -1
  69. package/lib/bin/cli/ship.js +15 -23
  70. package/lib/bin/cli/ship.js.map +1 -1
  71. package/lib/bin/cli/update.d.ts.map +1 -1
  72. package/lib/bin/cli/update.js +34 -28
  73. package/lib/bin/cli/update.js.map +1 -1
  74. package/lib/bin/cli/updatePlan.d.ts +30 -0
  75. package/lib/bin/cli/updatePlan.d.ts.map +1 -0
  76. package/lib/bin/cli/updatePlan.js +50 -0
  77. package/lib/bin/cli/updatePlan.js.map +1 -0
  78. package/lib/bin/cli/utils.d.ts +3 -0
  79. package/lib/bin/cli/utils.d.ts.map +1 -1
  80. package/lib/bin/cli/utils.js +7 -23
  81. package/lib/bin/cli/utils.js.map +1 -1
  82. package/lib/bin/cli/validate.d.ts.map +1 -1
  83. package/lib/bin/cli/validate.js +3 -25
  84. package/lib/bin/cli/validate.js.map +1 -1
  85. package/lib/bin/cli/watch.d.ts.map +1 -1
  86. package/lib/bin/cli/watch.js +3 -12
  87. package/lib/bin/cli/watch.js.map +1 -1
  88. package/lib/bin/forge-agent.js +10 -22
  89. package/lib/bin/forge-agent.js.map +1 -1
  90. package/lib/server/app.d.ts +24 -0
  91. package/lib/server/app.d.ts.map +1 -0
  92. package/lib/server/app.js +58 -0
  93. package/lib/server/app.js.map +1 -0
  94. package/lib/server/forge/analyses/analysisStore.d.ts +53 -0
  95. package/lib/server/forge/analyses/analysisStore.d.ts.map +1 -0
  96. package/lib/server/forge/analyses/analysisStore.js +77 -0
  97. package/lib/server/forge/analyses/analysisStore.js.map +1 -0
  98. package/lib/server/forge/auth/apiTokens.d.ts +34 -0
  99. package/lib/server/forge/auth/apiTokens.d.ts.map +1 -0
  100. package/lib/server/forge/auth/apiTokens.js +44 -0
  101. package/lib/server/forge/auth/apiTokens.js.map +1 -0
  102. package/lib/server/forge/auth/auditLog.d.ts +36 -0
  103. package/lib/server/forge/auth/auditLog.d.ts.map +1 -0
  104. package/lib/server/forge/auth/auditLog.js +56 -0
  105. package/lib/server/forge/auth/auditLog.js.map +1 -0
  106. package/lib/server/forge/auth/authConfig.d.ts +13 -0
  107. package/lib/server/forge/auth/authConfig.d.ts.map +1 -0
  108. package/lib/server/forge/auth/authConfig.js +37 -0
  109. package/lib/server/forge/auth/authConfig.js.map +1 -0
  110. package/lib/server/forge/auth/createAuth.d.ts +130 -0
  111. package/lib/server/forge/auth/createAuth.d.ts.map +1 -0
  112. package/lib/server/forge/auth/createAuth.js +387 -0
  113. package/lib/server/forge/auth/createAuth.js.map +1 -0
  114. package/lib/server/forge/auth/middleware.d.ts +10 -0
  115. package/lib/server/forge/auth/middleware.d.ts.map +1 -0
  116. package/lib/server/forge/auth/middleware.js +22 -0
  117. package/lib/server/forge/auth/middleware.js.map +1 -0
  118. package/lib/server/forge/auth/oidc.d.ts +38 -0
  119. package/lib/server/forge/auth/oidc.d.ts.map +1 -0
  120. package/lib/server/forge/auth/oidc.js +63 -0
  121. package/lib/server/forge/auth/oidc.js.map +1 -0
  122. package/lib/server/forge/auth/passwords.d.ts +7 -0
  123. package/lib/server/forge/auth/passwords.d.ts.map +1 -0
  124. package/lib/server/forge/auth/passwords.js +28 -0
  125. package/lib/server/forge/auth/passwords.js.map +1 -0
  126. package/lib/server/forge/auth/resetPassword.d.ts +14 -0
  127. package/lib/server/forge/auth/resetPassword.d.ts.map +1 -0
  128. package/lib/server/forge/auth/resetPassword.js +29 -0
  129. package/lib/server/forge/auth/resetPassword.js.map +1 -0
  130. package/lib/server/forge/auth/roles.d.ts +7 -0
  131. package/lib/server/forge/auth/roles.d.ts.map +1 -0
  132. package/lib/server/forge/auth/roles.js +15 -0
  133. package/lib/server/forge/auth/roles.js.map +1 -0
  134. package/lib/server/forge/auth/sessions.d.ts +27 -0
  135. package/lib/server/forge/auth/sessions.d.ts.map +1 -0
  136. package/lib/server/forge/auth/sessions.js +37 -0
  137. package/lib/server/forge/auth/sessions.js.map +1 -0
  138. package/lib/server/forge/auth/testHarness.d.ts +104 -0
  139. package/lib/server/forge/auth/testHarness.d.ts.map +1 -0
  140. package/lib/server/forge/auth/testHarness.js +53 -0
  141. package/lib/server/forge/auth/testHarness.js.map +1 -0
  142. package/lib/server/forge/auth/tokenHash.d.ts +3 -0
  143. package/lib/server/forge/auth/tokenHash.d.ts.map +1 -0
  144. package/lib/server/forge/auth/tokenHash.js +4 -0
  145. package/lib/server/forge/auth/tokenHash.js.map +1 -0
  146. package/lib/server/forge/auth/users.d.ts +51 -0
  147. package/lib/server/forge/auth/users.d.ts.map +1 -0
  148. package/lib/server/forge/auth/users.js +118 -0
  149. package/lib/server/forge/auth/users.js.map +1 -0
  150. package/lib/server/forge/core/ForgeAgent.d.ts +43 -1
  151. package/lib/server/forge/core/ForgeAgent.d.ts.map +1 -1
  152. package/lib/server/forge/core/ForgeAgent.js +209 -61
  153. package/lib/server/forge/core/ForgeAgent.js.map +1 -1
  154. package/lib/server/forge/core/agentClient.d.ts +7 -23
  155. package/lib/server/forge/core/agentClient.d.ts.map +1 -1
  156. package/lib/server/forge/core/agentClient.js +10 -25
  157. package/lib/server/forge/core/agentClient.js.map +1 -1
  158. package/lib/server/forge/core/claudeClient.d.ts +24 -1
  159. package/lib/server/forge/core/claudeClient.d.ts.map +1 -1
  160. package/lib/server/forge/core/claudeClient.js +25 -7
  161. package/lib/server/forge/core/claudeClient.js.map +1 -1
  162. package/lib/server/forge/core/configStore.d.ts +11 -1
  163. package/lib/server/forge/core/configStore.d.ts.map +1 -1
  164. package/lib/server/forge/core/configStore.js +33 -2
  165. package/lib/server/forge/core/configStore.js.map +1 -1
  166. package/lib/server/forge/core/dependencyPaths.d.ts +19 -0
  167. package/lib/server/forge/core/dependencyPaths.d.ts.map +1 -0
  168. package/lib/server/forge/core/dependencyPaths.js +32 -0
  169. package/lib/server/forge/core/dependencyPaths.js.map +1 -0
  170. package/lib/server/forge/core/evidence.d.ts +43 -0
  171. package/lib/server/forge/core/evidence.d.ts.map +1 -0
  172. package/lib/server/forge/core/evidence.js +108 -0
  173. package/lib/server/forge/core/evidence.js.map +1 -0
  174. package/lib/server/forge/core/jobs.d.ts +2 -0
  175. package/lib/server/forge/core/jobs.d.ts.map +1 -1
  176. package/lib/server/forge/core/jobs.js +8 -0
  177. package/lib/server/forge/core/jobs.js.map +1 -1
  178. package/lib/server/forge/core/localRepo.d.ts +31 -10
  179. package/lib/server/forge/core/localRepo.d.ts.map +1 -1
  180. package/lib/server/forge/core/localRepo.js +48 -82
  181. package/lib/server/forge/core/localRepo.js.map +1 -1
  182. package/lib/server/forge/core/prompts.d.ts +3 -1
  183. package/lib/server/forge/core/prompts.d.ts.map +1 -1
  184. package/lib/server/forge/core/prompts.js +14 -5
  185. package/lib/server/forge/core/prompts.js.map +1 -1
  186. package/lib/server/forge/core/providers/azuredevops.d.ts +4 -2
  187. package/lib/server/forge/core/providers/azuredevops.d.ts.map +1 -1
  188. package/lib/server/forge/core/providers/azuredevops.js +12 -2
  189. package/lib/server/forge/core/providers/azuredevops.js.map +1 -1
  190. package/lib/server/forge/core/providers/base.d.ts +29 -4
  191. package/lib/server/forge/core/providers/base.d.ts.map +1 -1
  192. package/lib/server/forge/core/providers/base.js +21 -3
  193. package/lib/server/forge/core/providers/base.js.map +1 -1
  194. package/lib/server/forge/core/providers/github.d.ts +7 -7
  195. package/lib/server/forge/core/providers/github.d.ts.map +1 -1
  196. package/lib/server/forge/core/providers/github.js +13 -4
  197. package/lib/server/forge/core/providers/github.js.map +1 -1
  198. package/lib/server/forge/core/providers/gitlab.d.ts +20 -3
  199. package/lib/server/forge/core/providers/gitlab.d.ts.map +1 -1
  200. package/lib/server/forge/core/providers/gitlab.js +65 -5
  201. package/lib/server/forge/core/providers/gitlab.js.map +1 -1
  202. package/lib/server/forge/core/providers/types.d.ts +20 -0
  203. package/lib/server/forge/core/providers/types.d.ts.map +1 -1
  204. package/lib/server/forge/core/secretBox.d.ts +17 -0
  205. package/lib/server/forge/core/secretBox.d.ts.map +1 -0
  206. package/lib/server/forge/core/secretBox.js +74 -0
  207. package/lib/server/forge/core/secretBox.js.map +1 -0
  208. package/lib/server/forge/core/types.d.ts +7 -1
  209. package/lib/server/forge/core/types.d.ts.map +1 -1
  210. package/lib/server/forge/core/validator/clone.d.ts +5 -4
  211. package/lib/server/forge/core/validator/clone.d.ts.map +1 -1
  212. package/lib/server/forge/core/validator/clone.js +6 -86
  213. package/lib/server/forge/core/validator/clone.js.map +1 -1
  214. package/lib/server/forge/core/validator/cmd.d.ts.map +1 -1
  215. package/lib/server/forge/core/validator/cmd.js +4 -1
  216. package/lib/server/forge/core/validator/cmd.js.map +1 -1
  217. package/lib/server/forge/core/validator/projectType.d.ts.map +1 -1
  218. package/lib/server/forge/core/validator/projectType.js +2 -1
  219. package/lib/server/forge/core/validator/projectType.js.map +1 -1
  220. package/lib/server/forge/core/validator/runners/node.d.ts.map +1 -1
  221. package/lib/server/forge/core/validator/runners/node.js +6 -2
  222. package/lib/server/forge/core/validator/runners/node.js.map +1 -1
  223. package/lib/server/forge/core/validator.d.ts.map +1 -1
  224. package/lib/server/forge/core/validator.js +28 -22
  225. package/lib/server/forge/core/validator.js.map +1 -1
  226. package/lib/server/forge/core/workspaces.d.ts +70 -0
  227. package/lib/server/forge/core/workspaces.d.ts.map +1 -0
  228. package/lib/server/forge/core/workspaces.js +348 -0
  229. package/lib/server/forge/core/workspaces.js.map +1 -0
  230. package/lib/server/forge/db/database.d.ts +22 -0
  231. package/lib/server/forge/db/database.d.ts.map +1 -0
  232. package/lib/server/forge/db/database.js +71 -0
  233. package/lib/server/forge/db/database.js.map +1 -0
  234. package/lib/server/forge/db/migrations.d.ts +11 -0
  235. package/lib/server/forge/db/migrations.d.ts.map +1 -0
  236. package/lib/server/forge/db/migrations.js +87 -0
  237. package/lib/server/forge/db/migrations.js.map +1 -0
  238. package/lib/server/forge/routes.d.ts.map +1 -1
  239. package/lib/server/forge/routes.js +413 -163
  240. package/lib/server/forge/routes.js.map +1 -1
  241. package/lib/server/forge/sse.d.ts +10 -0
  242. package/lib/server/forge/sse.d.ts.map +1 -0
  243. package/lib/server/forge/sse.js +22 -0
  244. package/lib/server/forge/sse.js.map +1 -0
  245. package/lib/server/spa.d.ts +12 -0
  246. package/lib/server/spa.d.ts.map +1 -0
  247. package/lib/server/spa.js +23 -0
  248. package/lib/server/spa.js.map +1 -0
  249. package/lib/server.js +9 -24
  250. package/lib/server.js.map +1 -1
  251. package/lib/shared/events.d.ts +3 -0
  252. package/lib/shared/events.d.ts.map +1 -1
  253. package/lib/shared/events.js +3 -0
  254. package/lib/shared/events.js.map +1 -1
  255. package/lib/shared/packageRoot.d.ts +11 -0
  256. package/lib/shared/packageRoot.d.ts.map +1 -0
  257. package/lib/shared/packageRoot.js +23 -0
  258. package/lib/shared/packageRoot.js.map +1 -0
  259. package/lib/shared/project.d.ts +3 -0
  260. package/lib/shared/project.d.ts.map +1 -0
  261. package/lib/shared/project.js +3 -0
  262. package/lib/shared/project.js.map +1 -0
  263. package/package.json +23 -10
  264. package/lib/bin/cli/improve.d.ts +0 -2
  265. package/lib/bin/cli/improve.d.ts.map +0 -1
  266. package/lib/bin/cli/improve.js +0 -189
  267. package/lib/bin/cli/improve.js.map +0 -1
  268. package/lib/bin/cli/stats.d.ts +0 -2
  269. package/lib/bin/cli/stats.d.ts.map +0 -1
  270. package/lib/bin/cli/stats.js +0 -78
  271. package/lib/bin/cli/stats.js.map +0 -1
  272. package/lib/server/forge/core/k8s.d.ts +0 -18
  273. package/lib/server/forge/core/k8s.d.ts.map +0 -1
  274. package/lib/server/forge/core/k8s.js +0 -49
  275. package/lib/server/forge/core/k8s.js.map +0 -1
  276. package/lib/server/forge/core/openclawClient.d.ts +0 -61
  277. package/lib/server/forge/core/openclawClient.d.ts.map +0 -1
  278. package/lib/server/forge/core/openclawClient.js +0 -111
  279. package/lib/server/forge/core/openclawClient.js.map +0 -1
  280. package/lib/server/forge/core/quotaClient.d.ts +0 -48
  281. package/lib/server/forge/core/quotaClient.d.ts.map +0 -1
  282. package/lib/server/forge/core/quotaClient.js +0 -88
  283. package/lib/server/forge/core/quotaClient.js.map +0 -1
  284. package/lib/server/forge/core/selfImprove.d.ts +0 -43
  285. package/lib/server/forge/core/selfImprove.d.ts.map +0 -1
  286. package/lib/server/forge/core/selfImprove.js +0 -372
  287. package/lib/server/forge/core/selfImprove.js.map +0 -1
  288. package/lib/server/forge/core/telemetry.d.ts +0 -100
  289. package/lib/server/forge/core/telemetry.d.ts.map +0 -1
  290. package/lib/server/forge/core/telemetry.js +0 -273
  291. package/lib/server/forge/core/telemetry.js.map +0 -1
  292. package/scripts/fix-shebang.cjs +0 -11
  293. package/scripts/inject-readme.cjs +0 -23
  294. package/scripts/local-rollout.sh +0 -134
@@ -0,0 +1,387 @@
1
+ import { randomInt, timingSafeEqual } from "node:crypto";
2
+ import express from "express";
3
+ import { API_TOKEN_PREFIX, createApiTokens } from "./apiTokens.js";
4
+ import { createAuditLog } from "./auditLog.js";
5
+ import { createOidcClient, randomToken } from "./oidc.js";
6
+ import { requireRole } from "./middleware.js";
7
+ import { isRole } from "./roles.js";
8
+ import { createSessions } from "./sessions.js";
9
+ import { createUsers } from "./users.js";
10
+ const SAFE_METHODS = new Set(["GET", "HEAD", "OPTIONS"]);
11
+ export const CSRF_HEADER = "x-forge-request";
12
+ const OIDC_STATE_TTL_MS = 10 * 60_000;
13
+ function safeEqual(a, b) {
14
+ const x = Buffer.from(a);
15
+ const y = Buffer.from(b);
16
+ return x.length === y.length && timingSafeEqual(x, y);
17
+ }
18
+ const LOOPBACK = new Set(["127.0.0.1", "::1", "::ffff:127.0.0.1"]);
19
+ const LOCAL_HOSTNAMES = new Set(["localhost", "127.0.0.1", "[::1]"]);
20
+ const FORWARDING_HEADERS = ["x-forwarded-for", "forwarded", "x-real-ip", "x-forwarded-host"];
21
+ /**
22
+ * True only for a browser on the server machine talking to Forge directly:
23
+ * loopback socket, no proxy headers (a reverse proxy on the same host would
24
+ * otherwise make every visitor look local), and a localhost Host header (so a
25
+ * DNS-rebinding page can't pose as local).
26
+ */
27
+ export function isLocalRequest(req) {
28
+ if (!LOOPBACK.has(req.socket.remoteAddress ?? ""))
29
+ return false;
30
+ if (FORWARDING_HEADERS.some((h) => req.headers[h] !== undefined))
31
+ return false;
32
+ const host = (req.headers.host ?? "").replace(/:\d+$/, "").toLowerCase();
33
+ return LOCAL_HOSTNAMES.has(host);
34
+ }
35
+ const CODE_ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
36
+ function generateSetupCode() {
37
+ const chunk = () => Array.from({ length: 4 }, () => CODE_ALPHABET[randomInt(CODE_ALPHABET.length)]).join("");
38
+ return `${chunk()}-${chunk()}-${chunk()}`;
39
+ }
40
+ function parseCookies(header) {
41
+ const out = {};
42
+ for (const part of header?.split(";") ?? []) {
43
+ const i = part.indexOf("=");
44
+ if (i > 0)
45
+ out[part.slice(0, i).trim()] = decodeURIComponent(part.slice(i + 1).trim());
46
+ }
47
+ return out;
48
+ }
49
+ /** Only same-origin relative paths; anything else (incl. `//host`) → "/". */
50
+ export function safeReturnTo(value) {
51
+ return typeof value === "string" && value.startsWith("/") && !value.startsWith("//") && !value.startsWith("/\\")
52
+ ? value
53
+ : "/";
54
+ }
55
+ const userPrincipal = (u, kind) => ({
56
+ id: u.id,
57
+ email: u.email,
58
+ name: u.name,
59
+ role: u.role,
60
+ kind,
61
+ });
62
+ const errorPage = (message) => `<!doctype html><meta charset="utf-8"><title>Sign-in failed</title><body style="font-family:system-ui;max-width:28rem;margin:15vh auto;padding:0 1rem"><h1 style="font-size:1.1rem">Sign-in failed</h1><p>${message.replace(/[<>&]/g, "")}</p><p><a href="/">Back to Forge</a></p></body>`;
63
+ export function createAuth(opts) {
64
+ const { db, clock = Date.now } = opts;
65
+ const users = createUsers({ db, clock });
66
+ const sessions = createSessions({ db, clock, idleMs: opts.sessionIdleMs, absoluteMs: opts.sessionAbsoluteMs });
67
+ const tokens = createApiTokens({ db, clock });
68
+ const audit = createAuditLog({ db, clock });
69
+ const oidc = opts.oidc ? createOidcClient(opts.oidc) : null;
70
+ let oidcRedirectUri = opts.oidc?.redirectUri ?? "";
71
+ // __Host- pins the cookie to this exact origin; it requires Secure.
72
+ const cookieName = opts.cookieSecure ? "__Host-forge_session" : "forge_session";
73
+ const setSessionCookie = (res, token) => {
74
+ const attrs = [`${cookieName}=${token}`, "Path=/", "HttpOnly", "SameSite=Lax", `Max-Age=${Math.floor(sessions.absoluteMs / 1000)}`];
75
+ if (opts.cookieSecure)
76
+ attrs.push("Secure");
77
+ res.append("Set-Cookie", attrs.join("; "));
78
+ };
79
+ const clearSessionCookie = (res) => res.append("Set-Cookie", `${cookieName}=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0${opts.cookieSecure ? "; Secure" : ""}`);
80
+ const clientMeta = (req) => ({ ip: req.ip ?? "", userAgent: String(req.headers["user-agent"] ?? "") });
81
+ const record = (req, e) => audit.record({
82
+ actorId: e.actor?.id ?? null,
83
+ actorLabel: e.actor?.email ?? e.actorLabel ?? "anonymous",
84
+ action: e.action,
85
+ outcome: e.outcome,
86
+ target: e.target ?? null,
87
+ details: e.details ?? null,
88
+ ...clientMeta(req),
89
+ });
90
+ async function startSession(req, res, user) {
91
+ const { token } = await sessions.create({ userId: user.id, ...clientMeta(req) });
92
+ setSessionCookie(res, token);
93
+ }
94
+ // ── Middleware ───────────────────────────────────────────────────────────
95
+ async function resolvePrincipal(req) {
96
+ const header = req.headers.authorization;
97
+ if (header?.startsWith("Bearer ")) {
98
+ req.authVia = "bearer";
99
+ const value = header.slice(7).trim();
100
+ if (value.startsWith(API_TOKEN_PREFIX)) {
101
+ const hit = await tokens.resolve(value);
102
+ const user = hit && (await users.findById(hit.userId));
103
+ return user && !user.disabled ? userPrincipal(user, "token") : "invalid";
104
+ }
105
+ if (opts.serviceToken && safeEqual(value, opts.serviceToken)) {
106
+ return { id: "service", email: "service-token", name: "Service token", role: "admin", kind: "service" };
107
+ }
108
+ return "invalid";
109
+ }
110
+ const sessionToken = parseCookies(req.headers.cookie)[cookieName];
111
+ if (!sessionToken)
112
+ return null;
113
+ req.authVia = "cookie";
114
+ const session = await sessions.resolve(sessionToken);
115
+ const user = session && (await users.findById(session.userId));
116
+ if (!user || user.disabled)
117
+ return null;
118
+ return userPrincipal(user, "user");
119
+ }
120
+ const authenticate = async (req, res, next) => {
121
+ try {
122
+ const principal = await resolvePrincipal(req);
123
+ if (principal === "invalid") {
124
+ res.status(401).json({ error: "Invalid or revoked token." });
125
+ return;
126
+ }
127
+ req.principal = principal ?? undefined;
128
+ next();
129
+ }
130
+ catch (err) {
131
+ next(err);
132
+ }
133
+ };
134
+ const requireUser = (req, res, next) => {
135
+ if (!req.principal) {
136
+ res.status(401).json({ error: "Sign in required." });
137
+ return;
138
+ }
139
+ next();
140
+ };
141
+ /** Cookie-authenticated writes must carry a header a cross-site form can't set. */
142
+ const csrf = (req, res, next) => {
143
+ if (req.authVia === "cookie" && !SAFE_METHODS.has(req.method) && req.headers[CSRF_HEADER] !== "1") {
144
+ res.status(403).json({ error: "Missing request header." });
145
+ return;
146
+ }
147
+ next();
148
+ };
149
+ /** Logs every state-changing API call once the response is sent. */
150
+ const auditTrail = (req, res, next) => {
151
+ if (SAFE_METHODS.has(req.method))
152
+ return next();
153
+ res.on("finish", () => {
154
+ if (res.locals.audited)
155
+ return;
156
+ const params = req.params ?? {};
157
+ const target = params.mrIid ? `!${params.mrIid}` : params.iid ? `#${params.iid}` : params.jobId ? `job ${params.jobId}` : null;
158
+ const repo = (req.body && typeof req.body.repo === "string" ? req.body.repo : null) ?? (typeof req.query.repo === "string" ? req.query.repo : null);
159
+ const outcome = res.statusCode < 400 ? "success" : res.statusCode === 401 || res.statusCode === 403 ? "denied" : "failure";
160
+ void audit
161
+ .record({
162
+ actorId: req.principal?.id ?? null,
163
+ actorLabel: req.principal?.email ?? "anonymous",
164
+ action: `${req.method} ${req.route?.path ?? req.path}`,
165
+ target,
166
+ repo,
167
+ outcome,
168
+ details: { status: res.statusCode },
169
+ ...clientMeta(req),
170
+ })
171
+ .catch((err) => console.error("[forge] audit write failed:", err));
172
+ });
173
+ next();
174
+ };
175
+ // ── /auth ────────────────────────────────────────────────────────────────
176
+ // Remote first-run setup needs proof of operating the server: FORGE_TOKEN
177
+ // when set, otherwise a one-time code printed to the server log.
178
+ const setupCode = opts.serviceToken ?? generateSetupCode();
179
+ let announced = false;
180
+ const router = express.Router();
181
+ router.use(express.json({ limit: "64kb" }));
182
+ router.get("/me", authenticate, async (req, res) => {
183
+ res.json({
184
+ user: req.principal ?? null,
185
+ needsSetup: (await users.count()) === 0,
186
+ setupRequiresToken: !isLocalRequest(req),
187
+ sso: oidc ? { name: opts.oidc?.name ?? "SSO" } : null,
188
+ });
189
+ });
190
+ router.post("/setup", async (req, res) => {
191
+ const { email, name, password, setupToken } = req.body ?? {};
192
+ if ((await users.count()) > 0)
193
+ return res.status(409).json({ error: "Forge is already set up." });
194
+ if (!isLocalRequest(req) && (typeof setupToken !== "string" || !safeEqual(setupToken.trim().toUpperCase(), setupCode.toUpperCase()))) {
195
+ return res.status(403).json({ error: "The setup code is incorrect." });
196
+ }
197
+ try {
198
+ const user = await users.create({ email, name: name ?? "", role: "admin", password });
199
+ await startSession(req, res, user);
200
+ await record(req, { action: "auth.setup", outcome: "success", actor: userPrincipal(user, "user") });
201
+ res.status(201).json({ user: userPrincipal(user, "user") });
202
+ }
203
+ catch (err) {
204
+ res.status(400).json({ error: err.message });
205
+ }
206
+ });
207
+ router.post("/login", async (req, res) => {
208
+ const { email, password } = req.body ?? {};
209
+ const result = await users.authenticate(String(email ?? ""), String(password ?? ""));
210
+ if ("reason" in result) {
211
+ await record(req, { action: "auth.login", outcome: "failure", actorLabel: String(email ?? "").toLowerCase(), details: { reason: result.reason } });
212
+ const message = result.reason === "locked"
213
+ ? "Too many failed attempts. Try again in 15 minutes."
214
+ : result.reason === "disabled"
215
+ ? "This account is disabled."
216
+ : "Invalid email or password.";
217
+ return res.status(401).json({ error: message });
218
+ }
219
+ const { user } = result;
220
+ await startSession(req, res, user);
221
+ await record(req, { action: "auth.login", outcome: "success", actor: userPrincipal(user, "user") });
222
+ res.json({ user: userPrincipal(user, "user") });
223
+ });
224
+ router.post("/logout", authenticate, csrf, async (req, res) => {
225
+ const token = parseCookies(req.headers.cookie)[cookieName];
226
+ if (token)
227
+ await sessions.revoke(token);
228
+ clearSessionCookie(res);
229
+ if (req.principal)
230
+ await record(req, { action: "auth.logout", outcome: "success", actor: req.principal });
231
+ res.json({ ok: true });
232
+ });
233
+ router.get("/tokens", authenticate, requireUser, async (req, res) => {
234
+ res.json({ tokens: await tokens.list(req.principal.id) });
235
+ });
236
+ router.post("/tokens", authenticate, requireUser, csrf, async (req, res) => {
237
+ if (req.principal.kind === "service")
238
+ return res.status(400).json({ error: "Service tokens can't mint personal tokens." });
239
+ const created = await tokens.create({ userId: req.principal.id, name: String(req.body?.name ?? "") });
240
+ await record(req, { action: "token.create", outcome: "success", actor: req.principal, target: created.record.prefix });
241
+ res.status(201).json(created);
242
+ });
243
+ router.delete("/tokens/:id", authenticate, requireUser, csrf, async (req, res) => {
244
+ const id = String(req.params.id);
245
+ const ok = await tokens.revoke({ id, userId: req.principal.id });
246
+ await record(req, { action: "token.revoke", outcome: ok ? "success" : "failure", actor: req.principal, target: id });
247
+ res.status(ok ? 200 : 404).json({ ok });
248
+ });
249
+ router.get("/oidc/start", async (req, res, next) => {
250
+ if (!oidc)
251
+ return res.status(404).json({ error: "Single sign-on is not configured." });
252
+ try {
253
+ const state = randomToken();
254
+ const nonce = randomToken();
255
+ const codeVerifier = randomToken();
256
+ await db.run("DELETE FROM oidc_states WHERE created_at < ?", [clock() - OIDC_STATE_TTL_MS]);
257
+ await db.run("INSERT INTO oidc_states (state, code_verifier, nonce, return_to, created_at) VALUES (?, ?, ?, ?, ?)", [
258
+ state,
259
+ codeVerifier,
260
+ nonce,
261
+ safeReturnTo(req.query.returnTo),
262
+ clock(),
263
+ ]);
264
+ res.redirect(302, await oidc.authorizationUrl({ state, nonce, codeVerifier, redirectUri: oidcRedirectUri }));
265
+ }
266
+ catch (err) {
267
+ next(err);
268
+ }
269
+ });
270
+ router.get("/oidc/callback", async (req, res) => {
271
+ if (!oidc || !opts.oidc)
272
+ return res.status(404).send(errorPage("Single sign-on is not configured."));
273
+ const state = String(req.query.state ?? "");
274
+ const row = await db.get("SELECT * FROM oidc_states WHERE state = ?", [state]);
275
+ await db.run("DELETE FROM oidc_states WHERE state = ?", [state]);
276
+ if (!row || clock() - row.created_at > OIDC_STATE_TTL_MS) {
277
+ return res.status(400).send(errorPage("This sign-in link expired. Start again."));
278
+ }
279
+ if (req.query.error)
280
+ return res.status(400).send(errorPage(String(req.query.error_description ?? req.query.error)));
281
+ const fail = async (status, message, label) => {
282
+ await record(req, { action: "auth.sso_login", outcome: "failure", actorLabel: label, details: { reason: message } });
283
+ res.status(status).send(errorPage(message));
284
+ };
285
+ try {
286
+ const claims = await oidc.exchange({ code: String(req.query.code ?? ""), codeVerifier: row.code_verifier, nonce: row.nonce, redirectUri: oidcRedirectUri });
287
+ const email = claims.email?.toLowerCase();
288
+ if (!email || claims.email_verified === false)
289
+ return fail(403, "Your identity provider did not supply a verified email.", email ?? "unknown");
290
+ const domain = email.split("@")[1];
291
+ if (opts.oidc.allowedDomains.length && !opts.oidc.allowedDomains.includes(domain)) {
292
+ return fail(403, "Your email domain is not allowed to sign in to this Forge workspace.", email);
293
+ }
294
+ const user = await users.upsertOidc({ subject: `${claims.iss}|${claims.sub}`, email, name: claims.name ?? "", defaultRole: opts.oidc.defaultRole });
295
+ if (user.disabled)
296
+ return fail(403, "This account is disabled.", email);
297
+ await startSession(req, res, user);
298
+ await record(req, { action: "auth.sso_login", outcome: "success", actor: userPrincipal(user, "user") });
299
+ res.redirect(302, row.return_to);
300
+ }
301
+ catch (err) {
302
+ await fail(400, err.message, "unknown");
303
+ }
304
+ });
305
+ // ── /admin ───────────────────────────────────────────────────────────────
306
+ const adminRouter = express.Router();
307
+ adminRouter.use(requireRole("admin"));
308
+ adminRouter.use((_req, res, next) => {
309
+ res.locals.audited = true; // admin routes write explicit, descriptive events
310
+ next();
311
+ });
312
+ adminRouter.get("/users", async (_req, res) => {
313
+ res.json({ users: await users.list() });
314
+ });
315
+ adminRouter.post("/users", async (req, res) => {
316
+ const { email, name, role, password } = req.body ?? {};
317
+ if (!isRole(role))
318
+ return res.status(400).json({ error: "Choose a valid role." });
319
+ try {
320
+ const user = await users.create({ email: String(email ?? ""), name: String(name ?? ""), role, password: password || undefined });
321
+ await record(req, { action: "user.create", outcome: "success", actor: req.principal, target: user.email, details: { role } });
322
+ res.status(201).json({ user });
323
+ }
324
+ catch (err) {
325
+ res.status(400).json({ error: err.message });
326
+ }
327
+ });
328
+ adminRouter.patch("/users/:id", async (req, res) => {
329
+ const target = await users.findById(String(req.params.id));
330
+ if (!target)
331
+ return res.status(404).json({ error: "User not found." });
332
+ const { role, disabled, name, password } = req.body ?? {};
333
+ if (role !== undefined && !isRole(role))
334
+ return res.status(400).json({ error: "Choose a valid role." });
335
+ const losesAdmin = target.role === "admin" && !target.disabled && ((role !== undefined && role !== "admin") || disabled === true);
336
+ if (losesAdmin && (await users.countActiveAdmins()) <= 1) {
337
+ return res.status(409).json({ error: "Forge needs at least one active admin." });
338
+ }
339
+ try {
340
+ const user = await users.update(target.id, { role, disabled, name, password });
341
+ if (disabled === true || password !== undefined) {
342
+ await sessions.revokeAllForUser(target.id);
343
+ if (disabled === true)
344
+ await tokens.revokeAllForUser(target.id);
345
+ }
346
+ const changes = Object.fromEntries(Object.entries({ role, disabled, name, password: password !== undefined ? "reset" : undefined }).filter(([, v]) => v !== undefined));
347
+ await record(req, { action: "user.update", outcome: "success", actor: req.principal, target: target.email, details: changes });
348
+ res.json({ user });
349
+ }
350
+ catch (err) {
351
+ res.status(400).json({ error: err.message });
352
+ }
353
+ });
354
+ adminRouter.get("/audit", async (req, res) => {
355
+ const n = (v) => (typeof v === "string" && v ? Number(v) : undefined);
356
+ res.json(await audit.list({
357
+ action: typeof req.query.action === "string" && req.query.action ? req.query.action : undefined,
358
+ actorId: typeof req.query.actorId === "string" && req.query.actorId ? req.query.actorId : undefined,
359
+ limit: n(req.query.limit),
360
+ before: n(req.query.before),
361
+ }));
362
+ });
363
+ return {
364
+ users,
365
+ sessions,
366
+ tokens,
367
+ audit,
368
+ router,
369
+ adminRouter,
370
+ authenticate,
371
+ requireUser,
372
+ requireRole,
373
+ csrf,
374
+ auditTrail,
375
+ /** Logs the setup code while no admin exists (only when it was generated). */
376
+ announceSetup: async () => {
377
+ if (opts.serviceToken || announced || (await users.count()) > 0)
378
+ return;
379
+ announced = true;
380
+ (opts.onSetupCode ?? ((code) => console.log(`[forge] First-run setup code (needed when not on localhost): ${code}`)))(setupCode);
381
+ },
382
+ setOidcRedirectUri: (uri) => {
383
+ oidcRedirectUri = uri;
384
+ },
385
+ };
386
+ }
387
+ //# sourceMappingURL=createAuth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createAuth.js","sourceRoot":"","sources":["../../../../server/forge/auth/createAuth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { NextFunction, Request, Response } from "express";
2
+ import { type Role } from "./roles.ts";
3
+ export type RoleGuard = ((req: Request, res: Response, next: NextFunction) => void) & {
4
+ requiredRole: Role;
5
+ };
6
+ /** Stateless: only reads `req.principal`, so routers can use it without the auth instance. */
7
+ export declare function requireRole(role: Role): RoleGuard;
8
+ /** Fail closed if a router is mounted without the auth stack in front of it. */
9
+ export declare function requirePrincipal(req: Request, res: Response, next: NextFunction): void;
10
+ //# sourceMappingURL=middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../../../server/forge/auth/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE/D,OAAO,EAAW,KAAK,IAAI,EAAE,MAAM,YAAY,CAAC;AAEhD,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC,GAAG;IAAE,YAAY,EAAE,IAAI,CAAA;CAAE,CAAC;AAE7G,8FAA8F;AAC9F,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,CAUjD;AAED,gFAAgF;AAChF,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,QAM/E"}
@@ -0,0 +1,22 @@
1
+ import { hasRole } from "./roles.js";
2
+ /** Stateless: only reads `req.principal`, so routers can use it without the auth instance. */
3
+ export function requireRole(role) {
4
+ const guard = ((req, res, next) => {
5
+ if (!req.principal || !hasRole(req.principal.role, role)) {
6
+ res.status(req.principal ? 403 : 401).json({ error: req.principal ? `Requires the ${role} role.` : "Sign in required." });
7
+ return;
8
+ }
9
+ next();
10
+ });
11
+ guard.requiredRole = role;
12
+ return guard;
13
+ }
14
+ /** Fail closed if a router is mounted without the auth stack in front of it. */
15
+ export function requirePrincipal(req, res, next) {
16
+ if (!req.principal) {
17
+ res.status(401).json({ error: "Sign in required." });
18
+ return;
19
+ }
20
+ next();
21
+ }
22
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../../../server/forge/auth/middleware.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAa,MAAM,YAAY,CAAC;AAIhD,8FAA8F;AAC9F,MAAM,UAAU,WAAW,CAAC,IAAU;IACrC,MAAM,KAAK,GAAG,CAAC,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;QAClE,IAAI,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;YAC1D,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,gBAAgB,IAAI,QAAQ,CAAC,CAAC,CAAC,mBAAmB,EAAE,CAAC,CAAC;YAC1H,OAAO;QACR,CAAC;QACD,IAAI,EAAE,CAAC;IACR,CAAC,CAAc,CAAC;IAChB,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC;IAC1B,OAAO,KAAK,CAAC;AACd,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,gBAAgB,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB;IAC/E,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;QACpB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,CAAC;QACrD,OAAO;IACR,CAAC;IACD,IAAI,EAAE,CAAC;AACR,CAAC"}
@@ -0,0 +1,38 @@
1
+ import { type JWTPayload } from "jose";
2
+ import type { Role } from "./roles.ts";
3
+ export interface OidcOptions {
4
+ issuer: string;
5
+ clientId: string;
6
+ clientSecret: string;
7
+ redirectUri: string;
8
+ defaultRole: Role;
9
+ /** Empty = any domain the IdP vouches for. */
10
+ allowedDomains: string[];
11
+ /** Button label, e.g. "Okta". */
12
+ name?: string;
13
+ scopes?: string;
14
+ }
15
+ export interface OidcClaims extends JWTPayload {
16
+ email?: string;
17
+ email_verified?: boolean;
18
+ name?: string;
19
+ nonce?: string;
20
+ }
21
+ export declare const randomToken: () => string;
22
+ export declare const pkceChallenge: (verifier: string) => string;
23
+ /** Authorization-code flow with PKCE; id_token verified against the IdP's JWKS. */
24
+ export declare function createOidcClient(opts: OidcOptions): {
25
+ authorizationUrl({ state, nonce, codeVerifier, redirectUri }: {
26
+ state: string;
27
+ nonce: string;
28
+ codeVerifier: string;
29
+ redirectUri: string;
30
+ }): Promise<string>;
31
+ exchange({ code, codeVerifier, nonce, redirectUri }: {
32
+ code: string;
33
+ codeVerifier: string;
34
+ nonce: string;
35
+ redirectUri: string;
36
+ }): Promise<OidcClaims & JWTPayload>;
37
+ };
38
+ //# sourceMappingURL=oidc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oidc.d.ts","sourceRoot":"","sources":["../../../../server/forge/auth/oidc.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiC,KAAK,UAAU,EAAE,MAAM,MAAM,CAAC;AAEtE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,MAAM,WAAW,WAAW;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,IAAI,CAAC;IAClB,8CAA8C;IAC9C,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,iCAAiC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AASD,MAAM,WAAW,UAAW,SAAQ,UAAU;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAGD,eAAO,MAAM,WAAW,cAAgC,CAAC;AACzD,eAAO,MAAM,aAAa,GAAI,UAAU,MAAM,WAA2D,CAAC;AAE1G,mFAAmF;AACnF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,WAAW;kEAgBoB;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE;yDAgBpF;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE;EAuBtI"}
@@ -0,0 +1,63 @@
1
+ import { createHash, randomBytes } from "node:crypto";
2
+ import { createRemoteJWKSet, jwtVerify } from "jose";
3
+ const b64url = (buf) => buf.toString("base64url");
4
+ export const randomToken = () => b64url(randomBytes(32));
5
+ export const pkceChallenge = (verifier) => b64url(createHash("sha256").update(verifier).digest());
6
+ /** Authorization-code flow with PKCE; id_token verified against the IdP's JWKS. */
7
+ export function createOidcClient(opts) {
8
+ let discovery = null;
9
+ let jwks = null;
10
+ const discover = () => {
11
+ discovery ??= fetch(`${opts.issuer.replace(/\/$/, "")}/.well-known/openid-configuration`).then(async (res) => {
12
+ if (!res.ok) {
13
+ discovery = null;
14
+ throw new Error(`OIDC discovery failed (${res.status}).`);
15
+ }
16
+ return (await res.json());
17
+ });
18
+ return discovery;
19
+ };
20
+ return {
21
+ async authorizationUrl({ state, nonce, codeVerifier, redirectUri }) {
22
+ const d = await discover();
23
+ const url = new URL(d.authorization_endpoint);
24
+ url.search = new URLSearchParams({
25
+ response_type: "code",
26
+ client_id: opts.clientId,
27
+ redirect_uri: redirectUri,
28
+ scope: opts.scopes ?? "openid email profile",
29
+ state,
30
+ nonce,
31
+ code_challenge: pkceChallenge(codeVerifier),
32
+ code_challenge_method: "S256",
33
+ }).toString();
34
+ return url.toString();
35
+ },
36
+ async exchange({ code, codeVerifier, nonce, redirectUri }) {
37
+ const d = await discover();
38
+ const res = await fetch(d.token_endpoint, {
39
+ method: "POST",
40
+ headers: { "content-type": "application/x-www-form-urlencoded", accept: "application/json" },
41
+ body: new URLSearchParams({
42
+ grant_type: "authorization_code",
43
+ code,
44
+ redirect_uri: redirectUri,
45
+ client_id: opts.clientId,
46
+ client_secret: opts.clientSecret,
47
+ code_verifier: codeVerifier,
48
+ }),
49
+ });
50
+ if (!res.ok)
51
+ throw new Error(`OIDC token exchange failed (${res.status}).`);
52
+ const { id_token: idToken } = (await res.json());
53
+ if (!idToken)
54
+ throw new Error("OIDC provider returned no id_token.");
55
+ jwks ??= createRemoteJWKSet(new URL(d.jwks_uri));
56
+ const { payload } = await jwtVerify(idToken, jwks, { issuer: d.issuer, audience: opts.clientId });
57
+ if (payload.nonce !== nonce)
58
+ throw new Error("OIDC nonce mismatch.");
59
+ return payload;
60
+ },
61
+ };
62
+ }
63
+ //# sourceMappingURL=oidc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oidc.js","sourceRoot":"","sources":["../../../../server/forge/auth/oidc.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export declare const PASSWORD_MIN_LENGTH = 12;
2
+ /** `scrypt$<N>$<salt b64>$<hash b64>` */
3
+ export declare function hashPassword(password: string): Promise<string>;
4
+ export declare function verifyPassword(password: string, stored: string): Promise<boolean>;
5
+ /** Returns an error message, or null when the password is acceptable. */
6
+ export declare function validatePassword(password: string): string | null;
7
+ //# sourceMappingURL=passwords.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"passwords.d.ts","sourceRoot":"","sources":["../../../../server/forge/auth/passwords.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAItC,yCAAyC;AACzC,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAIpE;AAED,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAMvF;AAED,yEAAyE;AACzE,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKhE"}
@@ -0,0 +1,28 @@
1
+ import { randomBytes, scrypt as scryptCb, timingSafeEqual } from "node:crypto";
2
+ import { promisify } from "node:util";
3
+ const scrypt = promisify(scryptCb);
4
+ export const PASSWORD_MIN_LENGTH = 12;
5
+ const PARAMS = { N: 2 ** 15, r: 8, p: 1, maxmem: 64 * 1024 * 1024 };
6
+ const KEY_LEN = 32;
7
+ /** `scrypt$<N>$<salt b64>$<hash b64>` */
8
+ export async function hashPassword(password) {
9
+ const salt = randomBytes(16);
10
+ const hash = await scrypt(password, salt, KEY_LEN, PARAMS);
11
+ return `scrypt$${PARAMS.N}$${salt.toString("base64")}$${hash.toString("base64")}`;
12
+ }
13
+ export async function verifyPassword(password, stored) {
14
+ const [scheme, n, saltB64, hashB64] = stored.split("$");
15
+ if (scheme !== "scrypt" || !n || !saltB64 || !hashB64)
16
+ return false;
17
+ const expected = Buffer.from(hashB64, "base64");
18
+ const actual = await scrypt(password, Buffer.from(saltB64, "base64"), expected.length, { ...PARAMS, N: Number(n) });
19
+ return actual.length === expected.length && timingSafeEqual(actual, expected);
20
+ }
21
+ /** Returns an error message, or null when the password is acceptable. */
22
+ export function validatePassword(password) {
23
+ if (typeof password !== "string" || password.length < PASSWORD_MIN_LENGTH) {
24
+ return `Password must be at least ${PASSWORD_MIN_LENGTH} characters.`;
25
+ }
26
+ return null;
27
+ }
28
+ //# sourceMappingURL=passwords.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"passwords.js","sourceRoot":"","sources":["../../../../server/forge/auth/passwords.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,IAAI,QAAQ,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC/E,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,CAA6E,CAAC;AAE/G,MAAM,CAAC,MAAM,mBAAmB,GAAG,EAAE,CAAC;AACtC,MAAM,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC;AACpE,MAAM,OAAO,GAAG,EAAE,CAAC;AAEnB,yCAAyC;AACzC,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAgB;IAClD,MAAM,IAAI,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC;IAC7B,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAC3D,OAAO,UAAU,MAAM,CAAC,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;AACnF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,QAAgB,EAAE,MAAc;IACpE,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACxD,IAAI,MAAM,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC;IACpE,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAChD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,EAAE,EAAE,GAAG,MAAM,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACpH,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,IAAI,eAAe,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AAC/E,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAChD,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,mBAAmB,EAAE,CAAC;QAC3E,OAAO,6BAA6B,mBAAmB,cAAc,CAAC;IACvE,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC"}