@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,38 @@
1
+ /**
2
+ * Server configuration helpers.
3
+ *
4
+ * Reads panel.json and provides common paths used by all commands.
5
+ */
6
+
7
+ import { readFile } from 'node:fs/promises';
8
+
9
+ /** Default paths used on the server. */
10
+ export const CONFIG_PATH =
11
+ process.env.LAMALIBRE_LAMASTE_CONFIG || '/etc/lamalibre/lamaste/panel.json';
12
+ export const STATE_DIR = process.env.LAMALIBRE_LAMASTE_DATA_DIR || '/etc/lamalibre/lamaste';
13
+ export const PKI_DIR = process.env.LAMALIBRE_LAMASTE_PKI_DIR || '/etc/lamalibre/lamaste/pki';
14
+
15
+ /** Systemd service names. */
16
+ export const PANEL_SERVICE = 'lamalibre-lamaste-serverd';
17
+ export const GATEKEEPER_SERVICE = 'lamalibre-lamaste-gatekeeper';
18
+
19
+ /**
20
+ * Read and parse panel.json.
21
+ * @returns {Promise<Record<string, unknown>>}
22
+ */
23
+ export async function readConfig() {
24
+ const raw = await readFile(CONFIG_PATH, 'utf-8');
25
+ return JSON.parse(raw);
26
+ }
27
+
28
+ /**
29
+ * Read panel.json, returning null on error instead of throwing.
30
+ * @returns {Promise<Record<string, unknown> | null>}
31
+ */
32
+ export async function readConfigSafe() {
33
+ try {
34
+ return await readConfig();
35
+ } catch {
36
+ return null;
37
+ }
38
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Shared exec helper that wraps execa for use by core library functions.
3
+ *
4
+ * The core library (@lamalibre/lamaste/server) accepts an ExecFn dependency.
5
+ * This module provides the concrete implementation backed by execa.
6
+ */
7
+
8
+ import { execa } from 'execa';
9
+
10
+ /**
11
+ * Execute a command with array arguments via execa.
12
+ * Conforms to the ExecFn interface expected by @lamalibre/lamaste/server.
13
+ *
14
+ * @param {string} file
15
+ * @param {string[]} args
16
+ * @param {{ cwd?: string, timeout?: number, input?: string }} [options]
17
+ * @returns {Promise<{ stdout: string, stderr: string }>}
18
+ */
19
+ export async function exec(file, args, options) {
20
+ const result = await execa(file, args, {
21
+ cwd: options?.cwd,
22
+ timeout: options?.timeout,
23
+ input: options?.input,
24
+ });
25
+ return { stdout: result.stdout, stderr: result.stderr };
26
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * CLI logger that satisfies the PluginLogger / TunnelLogger / SiteLogger
3
+ * interfaces expected by @lamalibre/lamaste/server.
4
+ *
5
+ * In normal mode, logs are written to stderr with chalk formatting.
6
+ * In --json mode, logs are suppressed (output goes through ndjson.js).
7
+ */
8
+
9
+ import chalk from 'chalk';
10
+
11
+ /**
12
+ * Create a logger for CLI command use.
13
+ * @param {{ json: boolean }} options
14
+ * @returns {{ info: Function, warn: Function, error: Function }}
15
+ */
16
+ export function createLogger({ json }) {
17
+ if (json) {
18
+ return {
19
+ info() {},
20
+ warn() {},
21
+ error() {},
22
+ };
23
+ }
24
+
25
+ return {
26
+ /** @param {Record<string, unknown>} _obj @param {string} [msg] */
27
+ info(_obj, msg) {
28
+ if (msg) process.stderr.write(` ${chalk.dim(msg)}\n`);
29
+ },
30
+ /** @param {Record<string, unknown>} _obj @param {string} [msg] */
31
+ warn(_obj, msg) {
32
+ if (msg) process.stderr.write(` ${chalk.yellow('warn:')} ${msg}\n`);
33
+ },
34
+ /** @param {Record<string, unknown>} _obj @param {string} [msg] */
35
+ error(_obj, msg) {
36
+ if (msg) process.stderr.write(` ${chalk.red('error:')} ${msg}\n`);
37
+ },
38
+ };
39
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * NDJSON output helper for --json mode.
3
+ *
4
+ * When --json is enabled, all output goes through this module as
5
+ * newline-delimited JSON on stdout. This is consumed by the desktop
6
+ * app (Tauri) and automation scripts.
7
+ */
8
+
9
+ /**
10
+ * Write a single NDJSON event line to stdout.
11
+ * @param {Record<string, unknown>} event
12
+ */
13
+ export function emit(event) {
14
+ process.stdout.write(JSON.stringify(event) + '\n');
15
+ }
16
+
17
+ /**
18
+ * Emit a step progress event.
19
+ * @param {string} step
20
+ * @param {'running' | 'complete' | 'skipped' | 'failed'} status
21
+ * @param {string} [detail]
22
+ */
23
+ export function emitStep(step, status, detail) {
24
+ /** @type {Record<string, unknown>} */
25
+ const event = { event: 'step', step, status };
26
+ if (detail) event.detail = detail;
27
+ emit(event);
28
+ }
29
+
30
+ /**
31
+ * Emit an error event.
32
+ * @param {string} message
33
+ * @param {boolean} [recoverable]
34
+ */
35
+ export function emitError(message, recoverable = false) {
36
+ emit({ event: 'error', message, recoverable });
37
+ }
38
+
39
+ /**
40
+ * Emit a completion event with result data.
41
+ * @param {Record<string, unknown>} data
42
+ */
43
+ export function emitComplete(data) {
44
+ emit({ event: 'complete', ...data });
45
+ }
46
+
47
+ /**
48
+ * Emit a log event — non-step progress messages that consumers (desktop app,
49
+ * automation) can surface alongside step progress.
50
+ * @param {'debug' | 'info' | 'warn' | 'error'} level
51
+ * @param {string} message
52
+ * @param {Record<string, unknown>} [data]
53
+ */
54
+ export function emitLog(level, message, data) {
55
+ emit({ event: 'log', level, message, ...(data ? { data } : {}) });
56
+ }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Panel REST API client for localhost calls.
3
+ *
4
+ * Used by tunnel/site commands that need the full dependency stack
5
+ * (nginx, certbot, chisel) which lives in the running panel server.
6
+ * Authenticates via the admin mTLS client certificate.
7
+ */
8
+
9
+ import { readFile, writeFile, unlink } from 'node:fs/promises';
10
+ import crypto from 'node:crypto';
11
+ import { execa } from 'execa';
12
+ import { PKI_DIR } from './config.js';
13
+
14
+ const PANEL_URL = 'https://127.0.0.1:9292';
15
+
16
+ /**
17
+ * Make an authenticated API request to the local panel server.
18
+ *
19
+ * Uses curl with the admin client certificate (mTLS) and a temporary
20
+ * config file for the P12 password (never in process args).
21
+ *
22
+ * @param {string} method
23
+ * @param {string} path e.g. '/api/tunnels'
24
+ * @param {Record<string, unknown> | null} [body]
25
+ * @returns {Promise<Record<string, unknown>>}
26
+ */
27
+ export async function panelRequest(method, path, body = null) {
28
+ const p12Path = `${PKI_DIR}/client.p12`;
29
+
30
+ // Read p12 password from the stored file
31
+ let p12Password;
32
+ try {
33
+ p12Password = (await readFile(`${PKI_DIR}/.p12-password`, 'utf-8')).trim();
34
+ } catch {
35
+ throw new Error(
36
+ 'Cannot read P12 password. Ensure the server is properly installed and /etc/lamalibre/lamaste/pki/.p12-password exists.',
37
+ );
38
+ }
39
+
40
+ // Write password to a temporary config file (never in process args)
41
+ const tmpConfigPath = `/tmp/lamalibre-lamaste-curl-${crypto.randomBytes(8).toString('hex')}`;
42
+ try {
43
+ await writeFile(tmpConfigPath, `--pass "${p12Password}"\n`, { mode: 0o600 });
44
+
45
+ const curlArgs = [
46
+ '-K',
47
+ tmpConfigPath,
48
+ '--cert-type',
49
+ 'P12',
50
+ '--cert',
51
+ p12Path,
52
+ '-k', // Server uses self-signed cert on localhost
53
+ '-s', // Silent
54
+ '-S', // Show errors
55
+ '-X',
56
+ method,
57
+ '-H',
58
+ 'Content-Type: application/json',
59
+ ];
60
+
61
+ if (body) {
62
+ curlArgs.push('-d', JSON.stringify(body));
63
+ }
64
+
65
+ // Append the HTTP status on its own line so an error response is not
66
+ // mistaken for a result — the panel answers errors with a JSON body.
67
+ curlArgs.push('-w', '\n%{http_code}', `${PANEL_URL}${path}`);
68
+
69
+ const { stdout } = await execa('curl', curlArgs, { timeout: 30000 });
70
+
71
+ const split = stdout.lastIndexOf('\n');
72
+ const payload = stdout.slice(0, split).trim();
73
+ const status = Number(stdout.slice(split + 1).trim());
74
+ const parsed = payload ? JSON.parse(payload) : {};
75
+
76
+ if (!Number.isInteger(status) || status >= 400) {
77
+ const reason = [parsed.error, parsed.details].filter(Boolean).join(': ');
78
+ throw new Error(`${method} ${path} failed (HTTP ${status})${reason ? `: ${reason}` : ''}`);
79
+ }
80
+
81
+ return parsed;
82
+ } finally {
83
+ await unlink(tmpConfigPath).catch(() => {});
84
+ }
85
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Direct state file readers for server CLI.
3
+ *
4
+ * Used by list/read commands that only need to read the JSON state files.
5
+ * Mutation commands use the panel REST API instead, since mutations require
6
+ * the full dependency stack (nginx, certbot, chisel).
7
+ */
8
+
9
+ import { readFile } from 'node:fs/promises';
10
+ import path from 'node:path';
11
+ import { STATE_DIR } from './config.js';
12
+
13
+ /**
14
+ * Read and parse a JSON state file, returning a default value on ENOENT.
15
+ * @param {string} filename
16
+ * @param {unknown} defaultValue
17
+ * @returns {Promise<unknown>}
18
+ */
19
+ async function readStateFile(filename, defaultValue) {
20
+ try {
21
+ const raw = await readFile(path.join(STATE_DIR, filename), 'utf-8');
22
+ return JSON.parse(raw);
23
+ } catch (err) {
24
+ if (err.code === 'ENOENT') return defaultValue;
25
+ throw new Error(`Failed to read ${filename}: ${err.message}`);
26
+ }
27
+ }
28
+
29
+ /**
30
+ * Read the tunnels array from tunnels.json.
31
+ * @returns {Promise<Array<Record<string, unknown>>>}
32
+ */
33
+ export async function readTunnels() {
34
+ const data = await readStateFile('tunnels.json', []);
35
+ return Array.isArray(data) ? data : [];
36
+ }
37
+
38
+ /**
39
+ * Read the sites array from sites.json.
40
+ * @returns {Promise<Array<Record<string, unknown>>>}
41
+ */
42
+ export async function readSites() {
43
+ const data = await readStateFile('sites.json', []);
44
+ return Array.isArray(data) ? data : [];
45
+ }