@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,257 @@
1
+ /**
2
+ * lamaste-server sites — Manage static sites.
3
+ *
4
+ * Subcommands:
5
+ * list List managed sites
6
+ * create --name <n> [--type <t>] Create a site
7
+ * delete <id> Delete a site by ID
8
+ * aliases <id> --set <a,b|""> Replace a custom site's redirect aliases
9
+ *
10
+ * List reads directly from the state file.
11
+ * Create/delete use the panel REST API (which has the full
12
+ * nginx/certbot/directory dependency stack).
13
+ */
14
+
15
+ import chalk from 'chalk';
16
+ import { readSites } from '../state.js';
17
+ import { panelRequest } from '../panel-api.js';
18
+ import { emit, emitError, emitComplete } from '../ndjson.js';
19
+
20
+ /**
21
+ * @param {string[]} args
22
+ * @param {{ json: boolean }} options
23
+ */
24
+ export async function runSites(args, { json }) {
25
+ const sub = args[0];
26
+
27
+ switch (sub) {
28
+ case 'list':
29
+ return listSites({ json });
30
+ case 'create':
31
+ return createSite(args.slice(1), { json });
32
+ case 'delete':
33
+ return deleteSite(args[1], { json });
34
+ case 'aliases':
35
+ return setAliases(args.slice(1), { json });
36
+ default:
37
+ printSiteUsage();
38
+ process.exit(sub ? 1 : 0);
39
+ }
40
+ }
41
+
42
+ function printSiteUsage() {
43
+ const b = chalk.bold;
44
+ const c = chalk.cyan;
45
+ console.log(`
46
+ ${b('Usage:')} lamaste-server sites <subcommand>
47
+
48
+ ${b('Subcommands:')}
49
+ ${c('list')} List managed sites
50
+ ${c('create')} --name <n> [options] Create a site
51
+ ${c('delete')} <id> Delete a site by ID
52
+ ${c('aliases')} <id> --set <a,b> Replace redirect aliases (--set "" clears)
53
+
54
+ ${b('Create options:')}
55
+ --name <name> Site name (required)
56
+ --type <type> Site type: managed (default) or custom
57
+ --custom-domain <d> Custom domain (required if type is custom)
58
+ --aliases <a,b> Hostnames that redirect to the custom domain (e.g. www.<domain>)
59
+ --spa Enable SPA mode (single-page application routing)
60
+ --authelia Enable Authelia protection
61
+ `);
62
+ }
63
+
64
+ /**
65
+ * @param {{ json: boolean }} options
66
+ */
67
+ async function listSites({ json }) {
68
+ const sites = await readSites();
69
+
70
+ if (json) {
71
+ emit({ sites });
72
+ return;
73
+ }
74
+
75
+ if (sites.length === 0) {
76
+ console.log('\n No sites configured.\n');
77
+ return;
78
+ }
79
+
80
+ const b = chalk.bold;
81
+ const c = chalk.cyan;
82
+ const g = chalk.green;
83
+ const y = chalk.yellow;
84
+ const d = chalk.dim;
85
+
86
+ console.log('');
87
+ console.log(b(' Static Sites'));
88
+ console.log(d(' ' + '\u2500'.repeat(50)));
89
+
90
+ for (const s of sites) {
91
+ const dnsStatus = s.dnsVerified ? g('verified') : y('pending DNS');
92
+ const certStatus = s.certIssued ? g('cert issued') : y('no cert');
93
+ const spaTag = s.spaMode ? d('[SPA]') : '';
94
+ const authTag = s.autheliaProtected ? d('[protected]') : '';
95
+
96
+ console.log(
97
+ ` ${c(s.name)} ${d(s.fqdn)} ${s.type} ${dnsStatus} ${certStatus} ${spaTag} ${authTag}`.trimEnd(),
98
+ );
99
+ console.log(` ${d(`id: ${s.id}`)}`);
100
+ }
101
+ console.log('');
102
+ }
103
+
104
+ /**
105
+ * @param {string[]} args
106
+ * @param {{ json: boolean }} options
107
+ */
108
+ async function createSite(args, { json }) {
109
+ const name = getArg(args, 'name');
110
+ const type = getArg(args, 'type') || 'managed';
111
+ const customDomain = getArg(args, 'custom-domain') || undefined;
112
+ const aliasArg = getArg(args, 'aliases');
113
+ const spaMode = args.includes('--spa');
114
+ const autheliaProtected = args.includes('--authelia');
115
+
116
+ if (!name) {
117
+ const msg = 'Error: --name is required';
118
+ if (json) emitError(msg);
119
+ else console.error(`\n ${msg}\n`);
120
+ process.exit(1);
121
+ }
122
+
123
+ if (type !== 'managed' && type !== 'custom') {
124
+ const msg = 'Error: --type must be managed or custom';
125
+ if (json) emitError(msg);
126
+ else console.error(`\n ${msg}\n`);
127
+ process.exit(1);
128
+ }
129
+
130
+ if (type === 'custom' && !customDomain) {
131
+ const msg = 'Error: --custom-domain is required for custom type sites';
132
+ if (json) emitError(msg);
133
+ else console.error(`\n ${msg}\n`);
134
+ process.exit(1);
135
+ }
136
+
137
+ /** @type {Record<string, unknown>} */
138
+ const body = { name, type, spaMode, autheliaProtected };
139
+ if (customDomain) body.customDomain = customDomain;
140
+ if (aliasArg) body.aliases = splitAliases(aliasArg);
141
+
142
+ if (!json) process.stderr.write(` Creating site ${chalk.cyan(name)}...`);
143
+
144
+ try {
145
+ const result = await panelRequest('POST', '/api/sites', body);
146
+
147
+ if (json) {
148
+ emitComplete({ site: result.site || result });
149
+ } else {
150
+ console.log(` ${chalk.green('ok')}`);
151
+ const site = result.site || result;
152
+ console.log(` FQDN: ${chalk.cyan(String(site.fqdn || name))}`);
153
+ console.log(` ID: ${chalk.dim(String(site.id || 'unknown'))}`);
154
+ if (result.message) {
155
+ console.log(` ${chalk.dim(String(result.message))}`);
156
+ }
157
+ console.log('');
158
+ }
159
+ } catch (err) {
160
+ if (json) emitError(err.message);
161
+ else {
162
+ console.log(` ${chalk.red('failed')}`);
163
+ console.error(` ${chalk.red(err.message)}\n`);
164
+ }
165
+ process.exit(1);
166
+ }
167
+ }
168
+
169
+ /**
170
+ * @param {string | undefined} id
171
+ * @param {{ json: boolean }} options
172
+ */
173
+ async function deleteSite(id, { json }) {
174
+ if (!id) {
175
+ const msg = 'Usage: lamaste-server sites delete <id>';
176
+ if (json) emitError(msg);
177
+ else console.error(`\n ${msg}\n`);
178
+ process.exit(1);
179
+ }
180
+
181
+ if (!json) process.stderr.write(` Deleting site ${chalk.dim(id)}...`);
182
+
183
+ try {
184
+ await panelRequest('DELETE', `/api/sites/${id}`);
185
+ if (json) {
186
+ emitComplete({ id, deleted: true });
187
+ } else {
188
+ console.log(` ${chalk.green('ok')}\n`);
189
+ }
190
+ } catch (err) {
191
+ if (json) emitError(err.message);
192
+ else {
193
+ console.log(` ${chalk.red('failed')}`);
194
+ console.error(` ${chalk.red(err.message)}\n`);
195
+ }
196
+ process.exit(1);
197
+ }
198
+ }
199
+
200
+ /**
201
+ * @param {string[]} args
202
+ * @param {string} name
203
+ * @returns {string | null}
204
+ */
205
+ function getArg(args, name) {
206
+ const idx = args.indexOf(`--${name}`);
207
+ if (idx === -1 || idx + 1 >= args.length) return null;
208
+ return args[idx + 1];
209
+ }
210
+
211
+ /**
212
+ * @param {string} value
213
+ * @returns {string[]}
214
+ */
215
+ function splitAliases(value) {
216
+ return value
217
+ .split(',')
218
+ .map((a) => a.trim().toLowerCase())
219
+ .filter(Boolean);
220
+ }
221
+
222
+ /**
223
+ * @param {string[]} args
224
+ * @param {{ json: boolean }} options
225
+ */
226
+ async function setAliases(args, { json }) {
227
+ const id = args[0];
228
+ const setIdx = args.indexOf('--set');
229
+ if (!id || setIdx === -1 || setIdx + 1 >= args.length) {
230
+ const msg = 'Usage: lamaste-server sites aliases <id> --set <a,b> (--set "" clears)';
231
+ if (json) emitError(msg);
232
+ else console.error(`\n ${msg}\n`);
233
+ process.exit(1);
234
+ }
235
+ const aliases = splitAliases(args[setIdx + 1]);
236
+
237
+ if (!json) process.stderr.write(` Updating aliases for ${chalk.dim(id)}...`);
238
+
239
+ try {
240
+ const result = await panelRequest('PATCH', `/api/sites/${id}`, { aliases });
241
+ if (json) {
242
+ emitComplete({ site: result.site, ...(result.warning ? { warning: result.warning } : {}) });
243
+ } else {
244
+ console.log(` ${chalk.green('ok')}`);
245
+ const list = result.site?.aliases ?? [];
246
+ console.log(` Aliases: ${list.length > 0 ? list.join(', ') : chalk.dim('none')}\n`);
247
+ if (result.warning) console.log(` ${chalk.yellow(result.warning)}\n`);
248
+ }
249
+ } catch (err) {
250
+ if (json) emitError(err.message);
251
+ else {
252
+ console.log(` ${chalk.red('failed')}`);
253
+ console.error(` ${chalk.red(err.message)}\n`);
254
+ }
255
+ process.exit(1);
256
+ }
257
+ }
@@ -0,0 +1,158 @@
1
+ /**
2
+ * lamaste-server status — Server health, uptime, resource usage.
3
+ *
4
+ * Reads systemctl status, panel.json config, and cert expiry info.
5
+ */
6
+
7
+ import chalk from 'chalk';
8
+ import { execa } from 'execa';
9
+ import { readConfigSafe, PANEL_SERVICE, GATEKEEPER_SERVICE, PKI_DIR } from '../config.js';
10
+ import { getMtlsCerts } from '@lamalibre/lamaste/server';
11
+ import { exec } from '../exec.js';
12
+ import { emit } from '../ndjson.js';
13
+
14
+ /**
15
+ * @param {{ json: boolean }} options
16
+ */
17
+ export async function runStatus({ json }) {
18
+ const config = await readConfigSafe();
19
+ const domain = config?.domain ?? null;
20
+
21
+ // Collect service statuses
22
+ const panelStatus = await getServiceStatus(PANEL_SERVICE);
23
+ const gatekeeperStatus = await getServiceStatus(GATEKEEPER_SERVICE);
24
+ const nginxStatus = await getServiceStatus('nginx');
25
+ const autheliaStatus = await getServiceStatus('authelia');
26
+
27
+ // Collect cert info
28
+ let certs = [];
29
+ try {
30
+ certs = await getMtlsCerts(PKI_DIR, exec);
31
+ } catch {
32
+ // PKI dir may not be readable
33
+ }
34
+
35
+ // Collect system info
36
+ const uptime = await getUptime();
37
+ const memory = await getMemoryUsage();
38
+
39
+ if (json) {
40
+ emit({
41
+ domain,
42
+ services: {
43
+ panel: panelStatus,
44
+ gatekeeper: gatekeeperStatus,
45
+ nginx: nginxStatus,
46
+ authelia: autheliaStatus,
47
+ },
48
+ certificates: certs,
49
+ uptime,
50
+ memory,
51
+ });
52
+ return;
53
+ }
54
+
55
+ const b = chalk.bold;
56
+ const c = chalk.cyan;
57
+ const g = chalk.green;
58
+ const r = chalk.red;
59
+ const d = chalk.dim;
60
+ const y = chalk.yellow;
61
+
62
+ console.log('');
63
+ console.log(b(' Lamaste Server Status'));
64
+ console.log(d(' ' + '\u2500'.repeat(40)));
65
+
66
+ if (domain) {
67
+ console.log(` ${b('Domain:')} ${c(String(domain))}`);
68
+ }
69
+
70
+ if (uptime) {
71
+ console.log(` ${b('Uptime:')} ${d(uptime)}`);
72
+ }
73
+ if (memory) {
74
+ console.log(` ${b('Memory:')} ${d(memory)}`);
75
+ }
76
+
77
+ console.log('');
78
+ console.log(b(' Services'));
79
+ console.log(d(' ' + '\u2500'.repeat(40)));
80
+
81
+ printService('Panel', panelStatus, { b, g, r });
82
+ printService('Gatekeeper', gatekeeperStatus, { b, g, r });
83
+ printService('Nginx', nginxStatus, { b, g, r });
84
+ printService('Authelia', autheliaStatus, { b, g, r });
85
+
86
+ if (certs.length > 0) {
87
+ console.log('');
88
+ console.log(b(' Certificates'));
89
+ console.log(d(' ' + '\u2500'.repeat(40)));
90
+
91
+ for (const cert of certs) {
92
+ const label = cert.type === 'mtls-ca' ? 'CA' : 'Client';
93
+ const status = cert.expiringSoon ? y('expiring soon') : g('valid');
94
+ console.log(
95
+ ` ${b(label + ':')} ${status} ${d(`(expires in ${cert.daysUntilExpiry} days)`)}`,
96
+ );
97
+ }
98
+ }
99
+
100
+ console.log('');
101
+ }
102
+
103
+ /**
104
+ * @param {string} name
105
+ * @param {{ active: boolean, status: string }} info
106
+ * @param {Record<string, Function>} colors
107
+ */
108
+ function printService(name, info, { b, g, r }) {
109
+ const pad = name.length < 12 ? ' '.repeat(12 - name.length) : ' ';
110
+ const statusText = info.active ? g('active') : r(info.status || 'inactive');
111
+ console.log(` ${b(name + ':')}${pad}${statusText}`);
112
+ }
113
+
114
+ /**
115
+ * Get systemd service status.
116
+ * @param {string} service
117
+ * @returns {Promise<{ active: boolean, status: string }>}
118
+ */
119
+ async function getServiceStatus(service) {
120
+ try {
121
+ const { stdout } = await execa('systemctl', ['is-active', service]);
122
+ const status = stdout.trim();
123
+ return { active: status === 'active', status };
124
+ } catch (err) {
125
+ const status = err?.stdout?.trim() || 'inactive';
126
+ return { active: false, status };
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Get system uptime as a human-readable string.
132
+ * @returns {Promise<string | null>}
133
+ */
134
+ async function getUptime() {
135
+ try {
136
+ const { stdout } = await execa('uptime', ['-p']);
137
+ return stdout.trim();
138
+ } catch {
139
+ return null;
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Get memory usage summary.
145
+ * @returns {Promise<string | null>}
146
+ */
147
+ async function getMemoryUsage() {
148
+ try {
149
+ const { stdout } = await execa('free', ['-h', '--si']);
150
+ const lines = stdout.trim().split('\n');
151
+ const memLine = lines.find((l) => l.startsWith('Mem:'));
152
+ if (!memLine) return null;
153
+ const parts = memLine.split(/\s+/);
154
+ return `${parts[2]} used / ${parts[1]} total`;
155
+ } catch {
156
+ return null;
157
+ }
158
+ }