@lamalibre/create-lamaste 4.0.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 (270) hide show
  1. package/LICENSE.md +118 -0
  2. package/README.md +114 -0
  3. package/bin/create-lamaste.js +15 -0
  4. package/package.json +54 -0
  5. package/scripts/bundle-vendor.js +110 -0
  6. package/scripts/lamaste-cert-info +62 -0
  7. package/scripts/lamaste-certbot +96 -0
  8. package/scripts/lamaste-priv +693 -0
  9. package/src/index.js +646 -0
  10. package/src/lib/accounts.js +86 -0
  11. package/src/lib/binaries.js +137 -0
  12. package/src/lib/cert-help-page.js +160 -0
  13. package/src/lib/env.js +132 -0
  14. package/src/lib/http-redirect.js +38 -0
  15. package/src/lib/ownership.js +231 -0
  16. package/src/lib/relay-services.js +103 -0
  17. package/src/lib/secrets.js +19 -0
  18. package/src/lib/service-config.js +311 -0
  19. package/src/lib/summary.js +131 -0
  20. package/src/lib/wrappers.js +63 -0
  21. package/src/tasks/gatekeeper.js +233 -0
  22. package/src/tasks/harden.js +293 -0
  23. package/src/tasks/mtls.js +193 -0
  24. package/src/tasks/nginx.js +265 -0
  25. package/src/tasks/node.js +110 -0
  26. package/src/tasks/panel.js +408 -0
  27. package/src/tasks/redeploy.js +438 -0
  28. package/vendor/docs/00-introduction/how-it-works.md +447 -0
  29. package/vendor/docs/00-introduction/quickstart.md +472 -0
  30. package/vendor/docs/00-introduction/what-is-lamaste.md +112 -0
  31. package/vendor/docs/01-concepts/authentication.md +464 -0
  32. package/vendor/docs/01-concepts/authorization.md +242 -0
  33. package/vendor/docs/01-concepts/certificates.md +452 -0
  34. package/vendor/docs/01-concepts/dns-and-domains.md +343 -0
  35. package/vendor/docs/01-concepts/mtls.md +490 -0
  36. package/vendor/docs/01-concepts/nginx-reverse-proxy.md +540 -0
  37. package/vendor/docs/01-concepts/security-model.md +600 -0
  38. package/vendor/docs/01-concepts/tickets.md +414 -0
  39. package/vendor/docs/01-concepts/tunneling.md +367 -0
  40. package/vendor/docs/02-guides/agent-setup.md +194 -0
  41. package/vendor/docs/02-guides/certificate-management.md +341 -0
  42. package/vendor/docs/02-guides/cloud-provisioning.md +406 -0
  43. package/vendor/docs/02-guides/desktop-app-setup.md +226 -0
  44. package/vendor/docs/02-guides/disaster-recovery.md +464 -0
  45. package/vendor/docs/02-guides/first-tunnel.md +230 -0
  46. package/vendor/docs/02-guides/installation.md +393 -0
  47. package/vendor/docs/02-guides/managing-users.md +255 -0
  48. package/vendor/docs/02-guides/onboarding.md +244 -0
  49. package/vendor/docs/02-guides/standalone-plugin-with-tickets.md +375 -0
  50. package/vendor/docs/02-guides/static-sites.md +364 -0
  51. package/vendor/docs/03-architecture/e2e-three-vm-sequences.md +457 -0
  52. package/vendor/docs/03-architecture/installer-flow.md +151 -0
  53. package/vendor/docs/03-architecture/installer.md +445 -0
  54. package/vendor/docs/03-architecture/management-flow.md +288 -0
  55. package/vendor/docs/03-architecture/nginx-configuration.md +830 -0
  56. package/vendor/docs/03-architecture/onboarding-flow.md +164 -0
  57. package/vendor/docs/03-architecture/overview.md +541 -0
  58. package/vendor/docs/03-architecture/panel-client.md +416 -0
  59. package/vendor/docs/03-architecture/panel-server.md +695 -0
  60. package/vendor/docs/03-architecture/state-management.md +529 -0
  61. package/vendor/docs/03-architecture/system-overview.md +167 -0
  62. package/vendor/docs/04-api-reference/certificates.md +1141 -0
  63. package/vendor/docs/04-api-reference/gatekeeper.md +592 -0
  64. package/vendor/docs/04-api-reference/onboarding.md +473 -0
  65. package/vendor/docs/04-api-reference/overview.md +404 -0
  66. package/vendor/docs/04-api-reference/services.md +267 -0
  67. package/vendor/docs/04-api-reference/settings.md +343 -0
  68. package/vendor/docs/04-api-reference/sites.md +716 -0
  69. package/vendor/docs/04-api-reference/system.md +268 -0
  70. package/vendor/docs/04-api-reference/tickets.md +618 -0
  71. package/vendor/docs/04-api-reference/tunnels.md +417 -0
  72. package/vendor/docs/04-api-reference/users.md +333 -0
  73. package/vendor/docs/05-operations/backup-and-restore.md +342 -0
  74. package/vendor/docs/05-operations/monitoring.md +285 -0
  75. package/vendor/docs/05-operations/uninstalling.md +344 -0
  76. package/vendor/docs/05-operations/upgrades.md +270 -0
  77. package/vendor/docs/06-reference/config-files.md +1080 -0
  78. package/vendor/docs/06-reference/glossary.md +528 -0
  79. package/vendor/docs/06-reference/installer-flags.md +260 -0
  80. package/vendor/docs/06-reference/ports-and-services.md +244 -0
  81. package/vendor/docs/06-reference/troubleshooting.md +665 -0
  82. package/vendor/docs/_index.json +233 -0
  83. package/vendor/docs/gatekeeper-design.md +953 -0
  84. package/vendor/docs/package.json +15 -0
  85. package/vendor/docs/todo/lib-cli-desktop-refactor.md +641 -0
  86. package/vendor/gatekeeper/dist/boot.d.ts +1 -0
  87. package/vendor/gatekeeper/dist/boot.d.ts.map +1 -0
  88. package/vendor/gatekeeper/dist/boot.js +17 -0
  89. package/vendor/gatekeeper/dist/boot.js.map +1 -0
  90. package/vendor/gatekeeper/dist/cli/commands/access.d.ts +2 -0
  91. package/vendor/gatekeeper/dist/cli/commands/access.d.ts.map +1 -0
  92. package/vendor/gatekeeper/dist/cli/commands/access.js +33 -0
  93. package/vendor/gatekeeper/dist/cli/commands/access.js.map +1 -0
  94. package/vendor/gatekeeper/dist/cli/commands/grants.d.ts +2 -0
  95. package/vendor/gatekeeper/dist/cli/commands/grants.d.ts.map +1 -0
  96. package/vendor/gatekeeper/dist/cli/commands/grants.js +110 -0
  97. package/vendor/gatekeeper/dist/cli/commands/grants.js.map +1 -0
  98. package/vendor/gatekeeper/dist/cli/commands/groups.d.ts +2 -0
  99. package/vendor/gatekeeper/dist/cli/commands/groups.d.ts.map +1 -0
  100. package/vendor/gatekeeper/dist/cli/commands/groups.js +98 -0
  101. package/vendor/gatekeeper/dist/cli/commands/groups.js.map +1 -0
  102. package/vendor/gatekeeper/dist/cli/index.d.ts +3 -0
  103. package/vendor/gatekeeper/dist/cli/index.d.ts.map +1 -0
  104. package/vendor/gatekeeper/dist/cli/index.js +45 -0
  105. package/vendor/gatekeeper/dist/cli/index.js.map +1 -0
  106. package/vendor/gatekeeper/dist/index.d.ts +9 -0
  107. package/vendor/gatekeeper/dist/index.d.ts.map +1 -0
  108. package/vendor/gatekeeper/dist/index.js +13 -0
  109. package/vendor/gatekeeper/dist/index.js.map +1 -0
  110. package/vendor/gatekeeper/dist/lib/authz.d.ts +16 -0
  111. package/vendor/gatekeeper/dist/lib/authz.d.ts.map +1 -0
  112. package/vendor/gatekeeper/dist/lib/authz.js +42 -0
  113. package/vendor/gatekeeper/dist/lib/authz.js.map +1 -0
  114. package/vendor/gatekeeper/dist/lib/cache-bust.d.ts +15 -0
  115. package/vendor/gatekeeper/dist/lib/cache-bust.d.ts.map +1 -0
  116. package/vendor/gatekeeper/dist/lib/cache-bust.js +19 -0
  117. package/vendor/gatekeeper/dist/lib/cache-bust.js.map +1 -0
  118. package/vendor/gatekeeper/dist/lib/constants.d.ts +82 -0
  119. package/vendor/gatekeeper/dist/lib/constants.d.ts.map +1 -0
  120. package/vendor/gatekeeper/dist/lib/constants.js +79 -0
  121. package/vendor/gatekeeper/dist/lib/constants.js.map +1 -0
  122. package/vendor/gatekeeper/dist/lib/grants.d.ts +32 -0
  123. package/vendor/gatekeeper/dist/lib/grants.d.ts.map +1 -0
  124. package/vendor/gatekeeper/dist/lib/grants.js +314 -0
  125. package/vendor/gatekeeper/dist/lib/grants.js.map +1 -0
  126. package/vendor/gatekeeper/dist/lib/groups.d.ts +10 -0
  127. package/vendor/gatekeeper/dist/lib/groups.d.ts.map +1 -0
  128. package/vendor/gatekeeper/dist/lib/groups.js +247 -0
  129. package/vendor/gatekeeper/dist/lib/groups.js.map +1 -0
  130. package/vendor/gatekeeper/dist/lib/migration.d.ts +17 -0
  131. package/vendor/gatekeeper/dist/lib/migration.d.ts.map +1 -0
  132. package/vendor/gatekeeper/dist/lib/migration.js +79 -0
  133. package/vendor/gatekeeper/dist/lib/migration.js.map +1 -0
  134. package/vendor/gatekeeper/dist/lib/migrations/gatekeeper/0001_groups.sql +7 -0
  135. package/vendor/gatekeeper/dist/lib/migrations/gatekeeper/0002_access_grants.sql +14 -0
  136. package/vendor/gatekeeper/dist/lib/migrations/gatekeeper/0003_access_request_log.sql +9 -0
  137. package/vendor/gatekeeper/dist/lib/migrations/migrations/gatekeeper/0001_groups.sql +7 -0
  138. package/vendor/gatekeeper/dist/lib/migrations/migrations/gatekeeper/0002_access_grants.sql +14 -0
  139. package/vendor/gatekeeper/dist/lib/migrations/migrations/gatekeeper/0003_access_request_log.sql +9 -0
  140. package/vendor/gatekeeper/dist/lib/state-db.d.ts +16 -0
  141. package/vendor/gatekeeper/dist/lib/state-db.d.ts.map +1 -0
  142. package/vendor/gatekeeper/dist/lib/state-db.js +154 -0
  143. package/vendor/gatekeeper/dist/lib/state-db.js.map +1 -0
  144. package/vendor/gatekeeper/dist/lib/templates.d.ts +21 -0
  145. package/vendor/gatekeeper/dist/lib/templates.d.ts.map +1 -0
  146. package/vendor/gatekeeper/dist/lib/templates.js +151 -0
  147. package/vendor/gatekeeper/dist/lib/templates.js.map +1 -0
  148. package/vendor/gatekeeper/dist/lib/types.d.ts +178 -0
  149. package/vendor/gatekeeper/dist/lib/types.d.ts.map +1 -0
  150. package/vendor/gatekeeper/dist/lib/types.js +2 -0
  151. package/vendor/gatekeeper/dist/lib/types.js.map +1 -0
  152. package/vendor/gatekeeper/dist/server/index.d.ts +15 -0
  153. package/vendor/gatekeeper/dist/server/index.d.ts.map +1 -0
  154. package/vendor/gatekeeper/dist/server/index.js +251 -0
  155. package/vendor/gatekeeper/dist/server/index.js.map +1 -0
  156. package/vendor/gatekeeper/dist/server/routes/access-request.d.ts +7 -0
  157. package/vendor/gatekeeper/dist/server/routes/access-request.d.ts.map +1 -0
  158. package/vendor/gatekeeper/dist/server/routes/access-request.js +17 -0
  159. package/vendor/gatekeeper/dist/server/routes/access-request.js.map +1 -0
  160. package/vendor/gatekeeper/dist/server/routes/authz.d.ts +3 -0
  161. package/vendor/gatekeeper/dist/server/routes/authz.d.ts.map +1 -0
  162. package/vendor/gatekeeper/dist/server/routes/authz.js +279 -0
  163. package/vendor/gatekeeper/dist/server/routes/authz.js.map +1 -0
  164. package/vendor/gatekeeper/dist/server/routes/diagnostic.d.ts +13 -0
  165. package/vendor/gatekeeper/dist/server/routes/diagnostic.d.ts.map +1 -0
  166. package/vendor/gatekeeper/dist/server/routes/diagnostic.js +249 -0
  167. package/vendor/gatekeeper/dist/server/routes/diagnostic.js.map +1 -0
  168. package/vendor/gatekeeper/dist/server/routes/grants.d.ts +3 -0
  169. package/vendor/gatekeeper/dist/server/routes/grants.d.ts.map +1 -0
  170. package/vendor/gatekeeper/dist/server/routes/grants.js +112 -0
  171. package/vendor/gatekeeper/dist/server/routes/grants.js.map +1 -0
  172. package/vendor/gatekeeper/dist/server/routes/groups.d.ts +3 -0
  173. package/vendor/gatekeeper/dist/server/routes/groups.d.ts.map +1 -0
  174. package/vendor/gatekeeper/dist/server/routes/groups.js +139 -0
  175. package/vendor/gatekeeper/dist/server/routes/groups.js.map +1 -0
  176. package/vendor/gatekeeper/package.json +49 -0
  177. package/vendor/server/bin/lamaste-server.js +204 -0
  178. package/vendor/server/package.json +31 -0
  179. package/vendor/server/src/commands/certs.js +224 -0
  180. package/vendor/server/src/commands/chisel.js +132 -0
  181. package/vendor/server/src/commands/logs.js +49 -0
  182. package/vendor/server/src/commands/plugins.js +321 -0
  183. package/vendor/server/src/commands/reset-admin.js +478 -0
  184. package/vendor/server/src/commands/restart.js +94 -0
  185. package/vendor/server/src/commands/sites.js +257 -0
  186. package/vendor/server/src/commands/status.js +158 -0
  187. package/vendor/server/src/commands/tunnels.js +365 -0
  188. package/vendor/server/src/commands/uninstall.js +326 -0
  189. package/vendor/server/src/config.js +38 -0
  190. package/vendor/server/src/exec.js +26 -0
  191. package/vendor/server/src/logger.js +39 -0
  192. package/vendor/server/src/ndjson.js +56 -0
  193. package/vendor/server/src/panel-api.js +85 -0
  194. package/vendor/server/src/state.js +45 -0
  195. package/vendor/server-ui/dist/assets/index-B0nWuUyL.js +257 -0
  196. package/vendor/server-ui/dist/assets/index-BqWWFlTU.css +1 -0
  197. package/vendor/server-ui/dist/index.html +13 -0
  198. package/vendor/serverd/package.json +44 -0
  199. package/vendor/serverd/src/boot.js +13 -0
  200. package/vendor/serverd/src/index.js +191 -0
  201. package/vendor/serverd/src/lib/app-error.js +14 -0
  202. package/vendor/serverd/src/lib/authelia.js +85 -0
  203. package/vendor/serverd/src/lib/certbot.js +74 -0
  204. package/vendor/serverd/src/lib/chisel-args.js +6 -0
  205. package/vendor/serverd/src/lib/chisel-reconcile.js +232 -0
  206. package/vendor/serverd/src/lib/chisel-runtime.js +46 -0
  207. package/vendor/serverd/src/lib/chisel-users.js +109 -0
  208. package/vendor/serverd/src/lib/chisel.js +81 -0
  209. package/vendor/serverd/src/lib/config.js +190 -0
  210. package/vendor/serverd/src/lib/constants.js +8 -0
  211. package/vendor/serverd/src/lib/csr-signing.js +331 -0
  212. package/vendor/serverd/src/lib/enrollment.js +302 -0
  213. package/vendor/serverd/src/lib/files.js +19 -0
  214. package/vendor/serverd/src/lib/gatekeeper-client.js +135 -0
  215. package/vendor/serverd/src/lib/invite-page.js +281 -0
  216. package/vendor/serverd/src/lib/ip-utils.js +79 -0
  217. package/vendor/serverd/src/lib/migrations/state/0001_enrollment_tokens.sql +17 -0
  218. package/vendor/serverd/src/lib/migrations/state/0002_tickets.sql +70 -0
  219. package/vendor/serverd/src/lib/migrations/state/0003_plugins.sql +15 -0
  220. package/vendor/serverd/src/lib/migrations/state/0004_agents.sql +19 -0
  221. package/vendor/serverd/src/lib/mtls.js +795 -0
  222. package/vendor/serverd/src/lib/nginx.js +1090 -0
  223. package/vendor/serverd/src/lib/pki-paths.js +41 -0
  224. package/vendor/serverd/src/lib/pki-sign.js +103 -0
  225. package/vendor/serverd/src/lib/plugins.js +538 -0
  226. package/vendor/serverd/src/lib/push-install.js +390 -0
  227. package/vendor/serverd/src/lib/revocation.js +112 -0
  228. package/vendor/serverd/src/lib/services.js +131 -0
  229. package/vendor/serverd/src/lib/session.js +151 -0
  230. package/vendor/serverd/src/lib/state-db.js +130 -0
  231. package/vendor/serverd/src/lib/state.js +140 -0
  232. package/vendor/serverd/src/lib/storage.js +63 -0
  233. package/vendor/serverd/src/lib/system-stats.js +58 -0
  234. package/vendor/serverd/src/lib/tickets.js +1556 -0
  235. package/vendor/serverd/src/lib/totp.js +76 -0
  236. package/vendor/serverd/src/lib/tunnel-deps.js +41 -0
  237. package/vendor/serverd/src/lib/user-access-session.js +142 -0
  238. package/vendor/serverd/src/lib/user-access.js +52 -0
  239. package/vendor/serverd/src/middleware/errors.js +63 -0
  240. package/vendor/serverd/src/middleware/mtls.js +120 -0
  241. package/vendor/serverd/src/middleware/onboarding-guard.js +30 -0
  242. package/vendor/serverd/src/middleware/role-guard.js +58 -0
  243. package/vendor/serverd/src/middleware/twofa-session.js +65 -0
  244. package/vendor/serverd/src/middleware/user-access-session.js +52 -0
  245. package/vendor/serverd/src/routes/enrollment.js +120 -0
  246. package/vendor/serverd/src/routes/health.js +22 -0
  247. package/vendor/serverd/src/routes/invite.js +163 -0
  248. package/vendor/serverd/src/routes/management/agents.js +182 -0
  249. package/vendor/serverd/src/routes/management/certs.js +911 -0
  250. package/vendor/serverd/src/routes/management/gatekeeper-proxy.js +160 -0
  251. package/vendor/serverd/src/routes/management/identity.js +107 -0
  252. package/vendor/serverd/src/routes/management/invitations.js +166 -0
  253. package/vendor/serverd/src/routes/management/logs.js +218 -0
  254. package/vendor/serverd/src/routes/management/plugins.js +560 -0
  255. package/vendor/serverd/src/routes/management/services.js +63 -0
  256. package/vendor/serverd/src/routes/management/settings.js +325 -0
  257. package/vendor/serverd/src/routes/management/sites.js +522 -0
  258. package/vendor/serverd/src/routes/management/storage.js +192 -0
  259. package/vendor/serverd/src/routes/management/system.js +201 -0
  260. package/vendor/serverd/src/routes/management/tickets.js +457 -0
  261. package/vendor/serverd/src/routes/management/tunnels.js +709 -0
  262. package/vendor/serverd/src/routes/management/users.js +377 -0
  263. package/vendor/serverd/src/routes/management.js +36 -0
  264. package/vendor/serverd/src/routes/onboarding/dns.js +101 -0
  265. package/vendor/serverd/src/routes/onboarding/domain.js +42 -0
  266. package/vendor/serverd/src/routes/onboarding/index.js +18 -0
  267. package/vendor/serverd/src/routes/onboarding/provision.js +327 -0
  268. package/vendor/serverd/src/routes/onboarding/status.js +12 -0
  269. package/vendor/serverd/src/routes/plugin-router.js +79 -0
  270. package/vendor/serverd/src/routes/user-access.js +389 -0
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Generate pre-filled message templates for requesting access to a resource.
3
+ *
4
+ * @param username - The authenticated user's username
5
+ * @param resourceName - Human-readable resource name (e.g., FQDN or plugin name)
6
+ * @param options - Optional admin contact info and domain
7
+ * @returns Templates for email, Slack, Teams, WhatsApp, and generic
8
+ */
9
+ export function getAccessRequestTemplates(username, resourceName, options) {
10
+ const adminName = options?.adminName ?? 'Administrator';
11
+ const adminContact = options?.adminContact ?? '';
12
+ const contactLine = adminContact ? `\nAdmin contact: ${adminContact}` : '';
13
+ return {
14
+ email: {
15
+ subject: `Access request for ${resourceName}`,
16
+ body: `Hi ${adminName},\n\n` +
17
+ `I'd like to request access to ${resourceName}.\n` +
18
+ `My username is: ${username}\n\n` +
19
+ `Thank you.`,
20
+ },
21
+ slack: `Hi, could I get access to \`${resourceName}\`? My username is \`${username}\`.`,
22
+ teams: `Hi, could I get access to **${resourceName}**? My username is **${username}**.`,
23
+ whatsapp: `Hi, I need access to ${resourceName} (username: ${username}). Thanks!`,
24
+ generic: `Access request for ${resourceName}\n` + `Username: ${username}${contactLine}`,
25
+ };
26
+ }
27
+ /**
28
+ * Build an HTML page for the access-request denial page.
29
+ * Server-rendered with inline CSS, no external dependencies.
30
+ *
31
+ * @param username - The authenticated user's username
32
+ * @param resourceFqdn - The tunnel FQDN the user tried to access
33
+ * @param options - Optional admin contact info
34
+ * @returns Full HTML page string
35
+ */
36
+ export function buildAccessRequestPage(username, resourceFqdn, options) {
37
+ const templates = getAccessRequestTemplates(username, resourceFqdn, options);
38
+ const adminContact = options?.adminContact ?? '';
39
+ const adminName = options?.adminName ?? 'your administrator';
40
+ return `<!DOCTYPE html>
41
+ <html lang="en">
42
+ <head>
43
+ <meta charset="utf-8">
44
+ <meta name="viewport" content="width=device-width, initial-scale=1">
45
+ <title>Access Required — ${escapeHtml(resourceFqdn)}</title>
46
+ <style>
47
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
48
+ body {
49
+ font-family: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, monospace;
50
+ background: #09090b; color: #e4e4e7;
51
+ min-height: 100vh; display: flex; align-items: center; justify-content: center;
52
+ padding: 1rem;
53
+ }
54
+ .card {
55
+ background: #18181b; border: 1px solid #27272a; border-radius: 0.75rem;
56
+ max-width: 560px; width: 100%; padding: 2rem;
57
+ }
58
+ .icon { font-size: 2.5rem; margin-bottom: 1rem; }
59
+ h1 { font-size: 1.25rem; color: #f4f4f5; margin-bottom: 0.5rem; }
60
+ .fqdn { color: #22d3ee; }
61
+ .subtitle { color: #a1a1aa; font-size: 0.875rem; margin-bottom: 1.5rem; }
62
+ .section-label {
63
+ color: #71717a; font-size: 0.75rem; text-transform: uppercase;
64
+ letter-spacing: 0.05em; margin-bottom: 0.5rem; margin-top: 1.25rem;
65
+ }
66
+ .template-box {
67
+ background: #0f0f12; border: 1px solid #27272a; border-radius: 0.5rem;
68
+ padding: 0.75rem 1rem; margin-bottom: 0.5rem; position: relative;
69
+ font-size: 0.8125rem; line-height: 1.5; white-space: pre-wrap;
70
+ word-break: break-word; color: #d4d4d8;
71
+ }
72
+ .copy-btn {
73
+ position: absolute; top: 0.5rem; right: 0.5rem;
74
+ background: #27272a; border: 1px solid #3f3f46; border-radius: 0.375rem;
75
+ color: #a1a1aa; font-size: 0.6875rem; padding: 0.25rem 0.5rem;
76
+ cursor: pointer; font-family: inherit;
77
+ transition: background 0.15s, color 0.15s;
78
+ }
79
+ .copy-btn:hover { background: #3f3f46; color: #e4e4e7; }
80
+ .copy-btn.copied { background: #065f46; color: #6ee7b7; border-color: #065f46; }
81
+ .contact { color: #a1a1aa; font-size: 0.8125rem; margin-top: 1.5rem; }
82
+ .contact a { color: #22d3ee; text-decoration: none; }
83
+ .contact a:hover { text-decoration: underline; }
84
+ .user-badge {
85
+ display: inline-block; background: #27272a; border-radius: 0.25rem;
86
+ padding: 0.125rem 0.375rem; font-size: 0.75rem; color: #22d3ee;
87
+ }
88
+ </style>
89
+ </head>
90
+ <body>
91
+ <div class="card">
92
+ <div class="icon">&#128274;</div>
93
+ <h1>Access Required</h1>
94
+ <p class="subtitle">
95
+ You don't have access to <span class="fqdn">${escapeHtml(resourceFqdn)}</span>
96
+ </p>
97
+ <p class="subtitle">
98
+ Signed in as <span class="user-badge">${escapeHtml(username)}</span>
99
+ </p>
100
+ <p class="subtitle">
101
+ Contact ${escapeHtml(adminName)} to request access. Copy a message template below:
102
+ </p>
103
+
104
+ <div class="section-label">Email</div>
105
+ <div class="template-box" id="tpl-email">Subject: ${escapeHtml(templates.email.subject)}
106
+
107
+ ${escapeHtml(templates.email.body)}<button class="copy-btn" onclick="copyTemplate('tpl-email', this)">Copy</button></div>
108
+
109
+ <div class="section-label">Slack / Teams</div>
110
+ <div class="template-box" id="tpl-slack">${escapeHtml(templates.slack)}<button class="copy-btn" onclick="copyTemplate('tpl-slack', this)">Copy</button></div>
111
+
112
+ <div class="section-label">WhatsApp</div>
113
+ <div class="template-box" id="tpl-whatsapp">${escapeHtml(templates.whatsapp)}<button class="copy-btn" onclick="copyTemplate('tpl-whatsapp', this)">Copy</button></div>
114
+
115
+ ${adminContact ? `<p class="contact">Admin: <a href="mailto:${escapeAttr(adminContact)}">${escapeHtml(adminContact)}</a></p>` : ''}
116
+ </div>
117
+ <script>
118
+ function copyTemplate(id, btn) {
119
+ var el = document.getElementById(id);
120
+ if (!el) return;
121
+ var text = el.textContent.replace(/Copy$/, '').trim();
122
+ navigator.clipboard.writeText(text).then(function() {
123
+ btn.textContent = 'Copied';
124
+ btn.classList.add('copied');
125
+ setTimeout(function() {
126
+ btn.textContent = 'Copy';
127
+ btn.classList.remove('copied');
128
+ }, 2000);
129
+ });
130
+ }
131
+ </script>
132
+ </body>
133
+ </html>`;
134
+ }
135
+ function escapeHtml(str) {
136
+ return str
137
+ .replace(/&/g, '&amp;')
138
+ .replace(/</g, '&lt;')
139
+ .replace(/>/g, '&gt;')
140
+ .replace(/"/g, '&quot;')
141
+ .replace(/'/g, '&#039;');
142
+ }
143
+ function escapeAttr(str) {
144
+ return str
145
+ .replace(/&/g, '&amp;')
146
+ .replace(/</g, '&lt;')
147
+ .replace(/>/g, '&gt;')
148
+ .replace(/"/g, '&quot;')
149
+ .replace(/'/g, '&#039;');
150
+ }
151
+ //# sourceMappingURL=templates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/lib/templates.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,MAAM,UAAU,yBAAyB,CACvC,QAAgB,EAChB,YAAoB,EACpB,OAAyB;IAEzB,MAAM,SAAS,GAAG,OAAO,EAAE,SAAS,IAAI,eAAe,CAAC;IACxD,MAAM,YAAY,GAAG,OAAO,EAAE,YAAY,IAAI,EAAE,CAAC;IACjD,MAAM,WAAW,GAAG,YAAY,CAAC,CAAC,CAAC,oBAAoB,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAE3E,OAAO;QACL,KAAK,EAAE;YACL,OAAO,EAAE,sBAAsB,YAAY,EAAE;YAC7C,IAAI,EACF,MAAM,SAAS,OAAO;gBACtB,iCAAiC,YAAY,KAAK;gBAClD,mBAAmB,QAAQ,MAAM;gBACjC,YAAY;SACf;QACD,KAAK,EAAE,+BAA+B,YAAY,wBAAwB,QAAQ,KAAK;QACvF,KAAK,EAAE,+BAA+B,YAAY,wBAAwB,QAAQ,KAAK;QACvF,QAAQ,EAAE,wBAAwB,YAAY,eAAe,QAAQ,YAAY;QACjF,OAAO,EAAE,sBAAsB,YAAY,IAAI,GAAG,aAAa,QAAQ,GAAG,WAAW,EAAE;KACxF,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,sBAAsB,CACpC,QAAgB,EAChB,YAAoB,EACpB,OAAyB;IAEzB,MAAM,SAAS,GAAG,yBAAyB,CAAC,QAAQ,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC;IAC7E,MAAM,YAAY,GAAG,OAAO,EAAE,YAAY,IAAI,EAAE,CAAC;IACjD,MAAM,SAAS,GAAG,OAAO,EAAE,SAAS,IAAI,oBAAoB,CAAC;IAE7D,OAAO;;;;;6BAKoB,UAAU,CAAC,YAAY,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oDAkDD,UAAU,CAAC,YAAY,CAAC;;;8CAG9B,UAAU,CAAC,QAAQ,CAAC;;;gBAGlD,UAAU,CAAC,SAAS,CAAC;;;;wDAImB,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC;;EAEzF,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC;;;+CAGa,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC;;;kDAGxB,UAAU,CAAC,SAAS,CAAC,QAAQ,CAAC;;MAE1E,YAAY,CAAC,CAAC,CAAC,6CAA6C,UAAU,CAAC,YAAY,CAAC,KAAK,UAAU,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;;;;;;;;QAkB9H,CAAC;AACT,CAAC;AAED,SAAS,UAAU,CAAC,GAAW;IAC7B,OAAO,GAAG;SACP,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAC7B,CAAC;AAED,SAAS,UAAU,CAAC,GAAW;IAC7B,OAAO,GAAG;SACP,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAC7B,CAAC"}
@@ -0,0 +1,178 @@
1
+ import type { PrincipalType, AccessMode } from './constants.js';
2
+ /**
3
+ * A Lamaste access control group.
4
+ */
5
+ export interface Group {
6
+ readonly name: string;
7
+ readonly description: string;
8
+ readonly members: readonly string[];
9
+ readonly createdAt: string;
10
+ readonly createdBy: string;
11
+ }
12
+ /**
13
+ * Mutable group state (internal).
14
+ */
15
+ export interface GroupState {
16
+ name: string;
17
+ description: string;
18
+ members: string[];
19
+ createdAt: string;
20
+ createdBy: string;
21
+ }
22
+ /**
23
+ * Options for creating a group.
24
+ */
25
+ export interface CreateGroupOptions {
26
+ readonly description?: string | undefined;
27
+ readonly createdBy?: string | undefined;
28
+ }
29
+ /**
30
+ * Options for updating a group.
31
+ */
32
+ export interface UpdateGroupOptions {
33
+ readonly name?: string | undefined;
34
+ readonly description?: string | undefined;
35
+ }
36
+ /**
37
+ * Result of deleting a group.
38
+ */
39
+ export interface DeleteGroupResult {
40
+ readonly deletedGrants: number;
41
+ }
42
+ /**
43
+ * A generic access grant binding a principal to a resource.
44
+ */
45
+ export interface Grant {
46
+ readonly grantId: string;
47
+ readonly principalType: PrincipalType;
48
+ readonly principalId: string;
49
+ readonly resourceType: string;
50
+ readonly resourceId: string;
51
+ readonly context: Record<string, unknown>;
52
+ readonly used: boolean;
53
+ readonly createdAt: string;
54
+ readonly usedAt: string | null;
55
+ }
56
+ /**
57
+ * Mutable grant state (internal).
58
+ */
59
+ export interface GrantState {
60
+ grantId: string;
61
+ principalType: PrincipalType;
62
+ principalId: string;
63
+ resourceType: string;
64
+ resourceId: string;
65
+ context: Record<string, unknown>;
66
+ used: boolean;
67
+ createdAt: string;
68
+ usedAt: string | null;
69
+ }
70
+ /**
71
+ * Options for creating a grant.
72
+ */
73
+ export interface CreateGrantOptions {
74
+ readonly principalType: PrincipalType;
75
+ readonly principalId: string;
76
+ readonly resourceType: string;
77
+ readonly resourceId: string;
78
+ readonly context?: Record<string, unknown>;
79
+ }
80
+ /**
81
+ * Filter for listing grants.
82
+ */
83
+ export interface GrantFilter {
84
+ readonly principalType?: PrincipalType | undefined;
85
+ readonly principalId?: string | undefined;
86
+ readonly resourceType?: string | undefined;
87
+ readonly resourceId?: string | undefined;
88
+ readonly used?: boolean | undefined;
89
+ }
90
+ /**
91
+ * Result of an access check.
92
+ */
93
+ export interface AccessAllowed {
94
+ readonly allowed: true;
95
+ }
96
+ export interface AccessDenied {
97
+ readonly allowed: false;
98
+ readonly resource: {
99
+ readonly type: string;
100
+ readonly id: string;
101
+ };
102
+ readonly templates: AccessRequestTemplates;
103
+ }
104
+ export type AccessResult = AccessAllowed | AccessDenied;
105
+ /**
106
+ * Pre-filled message templates for access requests.
107
+ */
108
+ export interface AccessRequestTemplates {
109
+ readonly email: {
110
+ readonly subject: string;
111
+ readonly body: string;
112
+ };
113
+ readonly slack: string;
114
+ readonly teams: string;
115
+ readonly whatsapp: string;
116
+ readonly generic: string;
117
+ }
118
+ /**
119
+ * Options for generating access request templates.
120
+ */
121
+ export interface TemplateOptions {
122
+ readonly adminContact?: string | undefined;
123
+ readonly adminName?: string | undefined;
124
+ readonly domain?: string | undefined;
125
+ }
126
+ /**
127
+ * Gatekeeper service settings.
128
+ */
129
+ export interface GatekeeperSettings {
130
+ readonly adminEmail?: string | undefined;
131
+ readonly adminName?: string | undefined;
132
+ readonly slackChannel?: string | undefined;
133
+ readonly teamsChannel?: string | undefined;
134
+ readonly sessionCacheTtlMs?: number | undefined;
135
+ readonly accessLoggingEnabled?: boolean | undefined;
136
+ readonly accessLogRetentionDays?: number | undefined;
137
+ }
138
+ /**
139
+ * An entry in the access request log.
140
+ */
141
+ export interface AccessRequestEntry {
142
+ readonly timestamp: string;
143
+ readonly username: string;
144
+ readonly resourceType: string;
145
+ readonly resourceId: string;
146
+ readonly resourceFqdn: string;
147
+ }
148
+ /**
149
+ * Tunnel info used by the authz check endpoint.
150
+ */
151
+ export interface TunnelInfo {
152
+ readonly id: string;
153
+ readonly fqdn: string;
154
+ readonly accessMode: AccessMode;
155
+ readonly enabled: boolean;
156
+ }
157
+ /**
158
+ * Cached Authelia session data.
159
+ */
160
+ export interface AutheliaSession {
161
+ readonly username: string;
162
+ readonly groups: string;
163
+ readonly displayName: string;
164
+ readonly email: string;
165
+ readonly expiresAt: number;
166
+ }
167
+ /**
168
+ * Logger interface (compatible with Fastify logger).
169
+ */
170
+ export interface GatekeeperLogger {
171
+ info(msg: string): void;
172
+ info(obj: Record<string, unknown>, msg: string): void;
173
+ warn(msg: string): void;
174
+ warn(obj: Record<string, unknown>, msg: string): void;
175
+ error(msg: string): void;
176
+ error(obj: Record<string, unknown>, msg: string): void;
177
+ }
178
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/lib/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,15 @@
1
+ import '../boot.js';
2
+ import Fastify from 'fastify';
3
+ import type { TunnelInfo, GatekeeperSettings, AutheliaSession } from '../lib/types.js';
4
+ export declare function createServer(): Promise<ReturnType<typeof Fastify>>;
5
+ declare module 'fastify' {
6
+ interface FastifyInstance {
7
+ getTunnels(): TunnelInfo[];
8
+ getSettings(): GatekeeperSettings;
9
+ getSessionCache(): Map<string, AutheliaSession>;
10
+ getCacheVersion(): number;
11
+ bustCache(): void;
12
+ updateSettings(s: GatekeeperSettings): void;
13
+ }
14
+ }
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,CAAC;AAEpB,OAAO,OAAO,MAAM,SAAS,CAAC;AAc9B,OAAO,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAoHvF,wBAAsB,YAAY,IAAI,OAAO,CAAC,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC,CA6IxE;AAkCD,OAAO,QAAQ,SAAS,CAAC;IACvB,UAAU,eAAe;QACvB,UAAU,IAAI,UAAU,EAAE,CAAC;QAC3B,WAAW,IAAI,kBAAkB,CAAC;QAClC,eAAe,IAAI,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;QAChD,eAAe,IAAI,MAAM,CAAC;QAC1B,SAAS,IAAI,IAAI,CAAC;QAClB,cAAc,CAAC,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAAC;KAC7C;CACF"}
@@ -0,0 +1,251 @@
1
+ import '../boot.js';
2
+ import crypto from 'node:crypto';
3
+ import Fastify from 'fastify';
4
+ import rateLimit from '@fastify/rate-limit';
5
+ import { watch } from 'node:fs';
6
+ import { readFile } from 'node:fs/promises';
7
+ import path from 'node:path';
8
+ import { atomicWriteJSON } from '@lamalibre/lamaste';
9
+ import { DEFAULT_DATA_DIR, GROUPS_FILE, GRANTS_FILE, SETTINGS_FILE, GATEKEEPER_PORT, SESSION_CACHE_TTL_MS, } from '../lib/constants.js';
10
+ import { registerCacheInvalidator } from '../lib/cache-bust.js';
11
+ import { authzRoutes } from './routes/authz.js';
12
+ import { groupRoutes } from './routes/groups.js';
13
+ import { grantRoutes } from './routes/grants.js';
14
+ import { diagnosticRoutes } from './routes/diagnostic.js';
15
+ import { accessRequestRoutes } from './routes/access-request.js';
16
+ const dataDir = process.env.LAMALIBRE_LAMASTE_DATA_DIR ?? DEFAULT_DATA_DIR;
17
+ const tunnelsPath = path.join(dataDir, 'tunnels.json');
18
+ const settingsPath = path.join(dataDir, SETTINGS_FILE);
19
+ // ---------------------------------------------------------------------------
20
+ // In-memory caches (refreshed by file watch + TTL)
21
+ // ---------------------------------------------------------------------------
22
+ /** Tunnel info cache (refreshed on file change) */
23
+ let tunnelsCache = [];
24
+ /** Gatekeeper settings cache */
25
+ let settingsCache = {};
26
+ /** Authelia session cache: cookie hash → session data */
27
+ const sessionCache = new Map();
28
+ /** Cache version counter — incremented on cache bust */
29
+ let cacheVersion = 0;
30
+ // ---------------------------------------------------------------------------
31
+ // File loaders
32
+ // ---------------------------------------------------------------------------
33
+ async function loadTunnels() {
34
+ try {
35
+ const raw = await readFile(tunnelsPath, 'utf-8');
36
+ const parsed = JSON.parse(raw);
37
+ if (!Array.isArray(parsed))
38
+ return [];
39
+ return parsed.map((t) => ({
40
+ id: String(t.id ?? ''),
41
+ fqdn: String(t.fqdn ?? ''),
42
+ accessMode: t.accessMode ?? 'restricted',
43
+ enabled: t.enabled !== false,
44
+ }));
45
+ }
46
+ catch {
47
+ return [];
48
+ }
49
+ }
50
+ async function loadSettings() {
51
+ try {
52
+ const raw = await readFile(settingsPath, 'utf-8');
53
+ return JSON.parse(raw);
54
+ }
55
+ catch {
56
+ return {};
57
+ }
58
+ }
59
+ // ---------------------------------------------------------------------------
60
+ // File watcher with debounce
61
+ // ---------------------------------------------------------------------------
62
+ /**
63
+ * One directory watcher per parent directory, multiplexed by filename.
64
+ *
65
+ * We watch the parent directory rather than the file itself because all of our
66
+ * state files (tunnels.json, grants.json, groups.json, gatekeeper.json) are
67
+ * updated via atomic rename (temp → fsync → rename). A direct `fs.watch` on
68
+ * the file is pinned to the original inode, and the rename swaps that inode
69
+ * out — leaving the watcher silently attached to a file that no longer has a
70
+ * name. Watching the directory survives renames: we receive a `rename` event
71
+ * for the target filename each time a write lands, and re-run the reloader.
72
+ */
73
+ const dirWatchers = new Map();
74
+ function watchFile(filePath, reload, logger) {
75
+ const dir = path.dirname(filePath);
76
+ const base = path.basename(filePath);
77
+ let debounceTimer = null;
78
+ const handler = () => {
79
+ if (debounceTimer)
80
+ clearTimeout(debounceTimer);
81
+ debounceTimer = setTimeout(() => {
82
+ reload().catch(() => {
83
+ // Reload errors are non-fatal — keep using cached data
84
+ });
85
+ logger.info(`Reloaded ${base}`);
86
+ }, 200);
87
+ };
88
+ let handlers = dirWatchers.get(dir);
89
+ if (!handlers) {
90
+ handlers = new Map();
91
+ dirWatchers.set(dir, handlers);
92
+ try {
93
+ watch(dir, (_eventType, filename) => {
94
+ if (!filename)
95
+ return;
96
+ const cb = handlers.get(filename);
97
+ if (cb)
98
+ cb();
99
+ });
100
+ }
101
+ catch {
102
+ // Parent directory doesn't exist yet — watcher not set up.
103
+ dirWatchers.delete(dir);
104
+ return;
105
+ }
106
+ }
107
+ handlers.set(base, handler);
108
+ }
109
+ // ---------------------------------------------------------------------------
110
+ // Server startup
111
+ // ---------------------------------------------------------------------------
112
+ export async function createServer() {
113
+ const server = Fastify({
114
+ logger: true,
115
+ trustProxy: 1,
116
+ });
117
+ // Global rate limit. The gatekeeper binds to 127.0.0.1 and is reached
118
+ // exclusively by nginx auth_request and the panel proxy — both are
119
+ // local services. Because every caller arrives from 127.0.0.1, a
120
+ // per-IP limiter would collapse them into a single bucket and either
121
+ // be useless or punish legitimate nginx traffic. We collapse the key
122
+ // explicitly to one shared bucket and set a high ceiling; the hot
123
+ // /authz/check route then overrides this with its own ceiling that
124
+ // makes the "nginx-only" assumption explicit.
125
+ await server.register(rateLimit, {
126
+ max: 1000,
127
+ timeWindow: '1 minute',
128
+ keyGenerator: () => 'gatekeeper-internal',
129
+ });
130
+ // Load initial state
131
+ tunnelsCache = await loadTunnels();
132
+ settingsCache = await loadSettings();
133
+ // Decorate server with shared state accessors
134
+ server.decorate('getTunnels', () => tunnelsCache);
135
+ server.decorate('getSettings', () => settingsCache);
136
+ server.decorate('getSessionCache', () => sessionCache);
137
+ server.decorate('getCacheVersion', () => cacheVersion);
138
+ const bustCache = () => {
139
+ cacheVersion++;
140
+ sessionCache.clear();
141
+ };
142
+ server.decorate('bustCache', bustCache);
143
+ registerCacheInvalidator(bustCache);
144
+ server.decorate('updateSettings', (s) => {
145
+ settingsCache = s;
146
+ });
147
+ // Watch state files for changes
148
+ watchFile(tunnelsPath, async () => {
149
+ tunnelsCache = await loadTunnels();
150
+ }, server.log);
151
+ // TODO(sqlite-step-4): groups.json and access-grants.json are now
152
+ // .migrated stubs after first SQLite open. These watch registrations stay
153
+ // attached to the old paths so they never fire — every authz read goes
154
+ // through the DB and is always current, but admin grant/group changes do
155
+ // not invalidate the in-memory session cache without a daemon restart.
156
+ // Replace with a DB-modtime sentinel that the writer touches on commit
157
+ // (or polled `PRAGMA data_version`) once Step 4 (rodeo) is green.
158
+ watchFile(path.join(dataDir, GROUPS_FILE), async () => {
159
+ // Groups are read from SQLite on each call,
160
+ // but clearing session cache ensures authz re-evaluates group membership
161
+ sessionCache.clear();
162
+ }, server.log);
163
+ watchFile(path.join(dataDir, GRANTS_FILE), async () => {
164
+ // Same — clear session cache so authz picks up grant changes
165
+ sessionCache.clear();
166
+ }, server.log);
167
+ watchFile(settingsPath, async () => {
168
+ settingsCache = await loadSettings();
169
+ }, server.log);
170
+ // Load or generate API secret for localhost management auth.
171
+ // The secret is wrapped in a JSON envelope and written atomically so a
172
+ // crash during initial generation never leaves a half-written file
173
+ // (which the next start would treat as "no secret yet" and rotate, breaking
174
+ // any external client holding the previous value).
175
+ const secretPath = path.join(dataDir, 'gatekeeper-secret.json');
176
+ const legacySecretPath = path.join(dataDir, 'gatekeeper-secret');
177
+ let apiSecret;
178
+ try {
179
+ const raw = await readFile(secretPath, 'utf-8');
180
+ const parsed = JSON.parse(raw);
181
+ if (typeof parsed.secret !== 'string' || parsed.secret.length === 0) {
182
+ throw new Error('gatekeeper-secret.json is missing the "secret" field');
183
+ }
184
+ apiSecret = parsed.secret;
185
+ }
186
+ catch (err) {
187
+ if (err.code !== 'ENOENT') {
188
+ // Existing file is corrupt — refuse to rotate silently. An operator must
189
+ // resolve this so external callers do not lose their pinned secret.
190
+ throw err;
191
+ }
192
+ // First-run path: try migrating the legacy plaintext file before generating.
193
+ try {
194
+ const legacy = (await readFile(legacySecretPath, 'utf-8')).trim();
195
+ if (legacy.length > 0) {
196
+ apiSecret = legacy;
197
+ await atomicWriteJSON(secretPath, { secret: apiSecret }, { mkdirp: true });
198
+ server.log.info('Migrated legacy gatekeeper-secret file to JSON envelope');
199
+ }
200
+ else {
201
+ throw new Error('legacy gatekeeper-secret was empty');
202
+ }
203
+ }
204
+ catch {
205
+ apiSecret = crypto.randomBytes(32).toString('hex');
206
+ await atomicWriteJSON(secretPath, { secret: apiSecret }, { mkdirp: true });
207
+ server.log.info('Generated new gatekeeper API secret');
208
+ }
209
+ }
210
+ // Register routes — authz, access-request, and health are public (nginx subrequests)
211
+ await server.register(authzRoutes);
212
+ await server.register(accessRequestRoutes);
213
+ // Management /api/* routes require the shared secret
214
+ await server.register(async (scope) => {
215
+ scope.addHook('onRequest', async (request, reply) => {
216
+ const auth = request.headers['x-gatekeeper-secret'];
217
+ if (auth !== apiSecret) {
218
+ return reply.code(401).send({ error: 'Unauthorized' });
219
+ }
220
+ });
221
+ await scope.register(groupRoutes, { prefix: '/api' });
222
+ await scope.register(grantRoutes, { prefix: '/api' });
223
+ await scope.register(diagnosticRoutes, { prefix: '/api' });
224
+ });
225
+ // Health endpoint
226
+ server.get('/health', async () => ({ status: 'ok' }));
227
+ return server;
228
+ }
229
+ // ---------------------------------------------------------------------------
230
+ // Entry point
231
+ // ---------------------------------------------------------------------------
232
+ async function start() {
233
+ const server = await createServer();
234
+ await server.listen({
235
+ host: '127.0.0.1',
236
+ port: GATEKEEPER_PORT,
237
+ });
238
+ // Graceful shutdown
239
+ const shutdown = async (signal) => {
240
+ server.log.info({ signal }, 'Received signal, shutting down gracefully');
241
+ await server.close();
242
+ process.exit(0);
243
+ };
244
+ process.on('SIGTERM', () => void shutdown('SIGTERM'));
245
+ process.on('SIGINT', () => void shutdown('SIGINT'));
246
+ }
247
+ start().catch((err) => {
248
+ console.error('Failed to start gatekeeper:', err);
249
+ process.exit(1);
250
+ });
251
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { FastifyInstance } from 'fastify';
2
+ /**
3
+ * Standalone access-request page route.
4
+ * Used as a fallback when the inline 403 body approach isn't available.
5
+ */
6
+ export declare function accessRequestRoutes(fastify: FastifyInstance): Promise<void>;
7
+ //# sourceMappingURL=access-request.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"access-request.d.ts","sourceRoot":"","sources":["../../../src/server/routes/access-request.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAgC,MAAM,SAAS,CAAC;AAG7E;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAYjF"}