@lamalibre/create-lamaste 4.1.0 → 4.2.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.
- package/package.json +2 -2
- package/vendor/docs/00-introduction/how-it-works.md +2 -2
- package/vendor/docs/00-introduction/quickstart.md +5 -5
- package/vendor/docs/00-introduction/what-is-lamaste.md +5 -5
- package/vendor/docs/01-concepts/certificates.md +3 -3
- package/vendor/docs/01-concepts/mtls.md +2 -2
- package/vendor/docs/01-concepts/security-model.md +1 -1
- package/vendor/docs/01-concepts/tickets.md +2 -2
- package/vendor/docs/01-concepts/tunneling.md +4 -4
- package/vendor/docs/02-guides/agent-setup.md +3 -3
- package/vendor/docs/02-guides/certificate-management.md +2 -2
- package/vendor/docs/02-guides/cloud-provisioning.md +3 -3
- package/vendor/docs/02-guides/desktop-app-setup.md +10 -10
- package/vendor/docs/02-guides/installation.md +3 -3
- package/vendor/docs/02-guides/onboarding.md +2 -2
- package/vendor/docs/02-guides/standalone-plugin-with-tickets.md +2 -2
- package/vendor/docs/03-architecture/installer-flow.md +2 -2
- package/vendor/docs/03-architecture/installer.md +4 -4
- package/vendor/docs/03-architecture/management-flow.md +1 -1
- package/vendor/docs/03-architecture/overview.md +5 -5
- package/vendor/docs/03-architecture/panel-client.md +6 -6
- package/vendor/docs/03-architecture/panel-server.md +2 -2
- package/vendor/docs/03-architecture/state-management.md +2 -2
- package/vendor/docs/03-architecture/system-overview.md +1 -1
- package/vendor/docs/04-api-reference/onboarding.md +1 -1
- package/vendor/docs/04-api-reference/registry-and-oidc.md +26 -1
- package/vendor/docs/05-operations/backup-and-restore.md +1 -1
- package/vendor/docs/05-operations/uninstalling.md +1 -1
- package/vendor/docs/05-operations/upgrades.md +5 -5
- package/vendor/docs/06-reference/config-files.md +1 -1
- package/vendor/docs/06-reference/glossary.md +3 -3
- package/vendor/docs/06-reference/installer-flags.md +13 -13
- package/vendor/docs/06-reference/ports-and-services.md +1 -1
- package/vendor/docs/06-reference/troubleshooting.md +8 -8
- package/vendor/docs/gatekeeper-design.md +8 -8
- package/vendor/docs/identity-directory-design.md +2 -2
- package/vendor/docs/package.json +1 -1
- package/vendor/docs/todo/lib-cli-desktop-refactor.md +27 -27
- package/vendor/gatekeeper/package.json +1 -1
- package/vendor/server/package.json +2 -2
- package/vendor/server/src/commands/plugins.js +123 -168
- package/vendor/server/src/panel-api.js +4 -2
- package/vendor/server-ui/dist/assets/{index-B0nWuUyL.js → index-B5Wp8lu-.js} +26 -26
- package/vendor/server-ui/dist/index.html +1 -1
- package/vendor/serverd/package.json +2 -2
- package/vendor/serverd/src/lib/migrations/state/0005_plugin_hosting.sql +3 -0
- package/vendor/serverd/src/lib/plugin-oidc.js +33 -16
- package/vendor/serverd/src/lib/plugins.js +11 -3
- package/vendor/serverd/src/routes/management/storage.js +10 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lamalibre/lamaste-server",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.2.0",
|
|
4
4
|
"description": "Server operations CLI for Lamaste",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"test": "node --test test/*.test.js"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@lamalibre/lamaste": "^4.
|
|
20
|
+
"@lamalibre/lamaste": "^4.2.0",
|
|
21
21
|
"chalk": "^5.3.0",
|
|
22
22
|
"execa": "^9.0.0"
|
|
23
23
|
},
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* lamaste-server plugins — Manage server-side plugins.
|
|
3
3
|
*
|
|
4
4
|
* Subcommands:
|
|
5
|
-
* list List installed plugins with status
|
|
5
|
+
* list List installed plugins with status and hosting
|
|
6
6
|
* install <package> Install a plugin by npm package name
|
|
7
7
|
* enable <name> Enable a plugin
|
|
8
8
|
* disable <name> Disable a plugin
|
|
@@ -11,25 +11,24 @@
|
|
|
11
11
|
* rotate-secret <name> <clientId>
|
|
12
12
|
* New secret for a confidential OIDC client (shown once)
|
|
13
13
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
14
|
+
* Every subcommand goes through the running panel (`/api/plugins/*`, admin
|
|
15
|
+
* certificate): the panel owns the plugin registry (SQLite `state.db`), runs
|
|
16
|
+
* npm as the `lamaste` account, and writes the plugins' OIDC clients to
|
|
17
|
+
* Authelia. The CLI keeps no plugin state of its own, so a plugin it installs
|
|
18
|
+
* is the plugin the panel serves. The panel must be running — a plugin that
|
|
19
|
+
* fails to load is logged and skipped by the plugin host, so the panel stays
|
|
20
|
+
* reachable to disable it.
|
|
16
21
|
*/
|
|
17
22
|
|
|
18
23
|
import chalk from 'chalk';
|
|
19
24
|
import { execa } from 'execa';
|
|
20
|
-
import {
|
|
21
|
-
readPlugins,
|
|
22
|
-
installPlugin,
|
|
23
|
-
enablePlugin,
|
|
24
|
-
disablePlugin,
|
|
25
|
-
uninstallPlugin,
|
|
26
|
-
} from '@lamalibre/lamaste/server';
|
|
27
|
-
import { STATE_DIR, PANEL_SERVICE } from '../config.js';
|
|
28
|
-
import { exec } from '../exec.js';
|
|
25
|
+
import { PANEL_SERVICE } from '../config.js';
|
|
29
26
|
import { panelRequest } from '../panel-api.js';
|
|
30
|
-
import { createLogger } from '../logger.js';
|
|
31
27
|
import { emit, emitStep, emitError, emitComplete, emitLog } from '../ndjson.js';
|
|
32
28
|
|
|
29
|
+
/** npm runs inside the panel for install and uninstall (its own limit is 120 s). */
|
|
30
|
+
const NPM_CALL_TIMEOUT_MS = 180_000;
|
|
31
|
+
|
|
33
32
|
/**
|
|
34
33
|
* @param {string[]} args Subcommand args: ['list'] | ['install', '<pkg>'] | ...
|
|
35
34
|
* @param {{ json: boolean }} options
|
|
@@ -37,12 +36,6 @@ import { emit, emitStep, emitError, emitComplete, emitLog } from '../ndjson.js';
|
|
|
37
36
|
export async function runPlugins(args, { json }) {
|
|
38
37
|
const sub = args[0];
|
|
39
38
|
|
|
40
|
-
if (MUTATING.has(sub) && process.getuid?.() === 0) {
|
|
41
|
-
await runAsLamaste(args, { json });
|
|
42
|
-
await restartPanel(json);
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
39
|
switch (sub) {
|
|
47
40
|
case 'list':
|
|
48
41
|
return listPlugins({ json });
|
|
@@ -71,7 +64,7 @@ function printPluginUsage() {
|
|
|
71
64
|
${b('Usage:')} lamaste-server plugins <subcommand>
|
|
72
65
|
|
|
73
66
|
${b('Subcommands:')}
|
|
74
|
-
${c('list')}
|
|
67
|
+
${c('list')} Installed plugins: status, hosting (server or agent)
|
|
75
68
|
${c('install <package>')} Install a plugin (e.g. @lamalibre/herd-server)
|
|
76
69
|
${c('enable <name>')} Enable a plugin
|
|
77
70
|
${c('disable <name>')} Disable a plugin
|
|
@@ -83,11 +76,13 @@ ${b('Subcommands:')}
|
|
|
83
76
|
}
|
|
84
77
|
|
|
85
78
|
/**
|
|
79
|
+
* The plugins the running panel serves, from the panel itself: its registry
|
|
80
|
+
* (SQLite `state.db`) is the one the plugin host and the OIDC sync read.
|
|
81
|
+
*
|
|
86
82
|
* @param {{ json: boolean }} options
|
|
87
83
|
*/
|
|
88
84
|
async function listPlugins({ json }) {
|
|
89
|
-
const
|
|
90
|
-
const plugins = registry.plugins;
|
|
85
|
+
const { plugins = [] } = await panelRequest('GET', '/api/plugins');
|
|
91
86
|
|
|
92
87
|
if (json) {
|
|
93
88
|
emit({ plugins });
|
|
@@ -111,63 +106,95 @@ async function listPlugins({ json }) {
|
|
|
111
106
|
|
|
112
107
|
for (const p of plugins) {
|
|
113
108
|
const status = p.status === 'enabled' ? g('enabled') : r('disabled');
|
|
114
|
-
|
|
109
|
+
const hosting = p.hosting === 'agent' ? chalk.yellow('agent-hosted') : d('server-hosted');
|
|
110
|
+
console.log(` ${c(p.name)} ${d(p.version)} ${status} ${hosting} ${d(p.packageName)}`);
|
|
115
111
|
}
|
|
116
112
|
console.log('');
|
|
117
113
|
}
|
|
118
114
|
|
|
115
|
+
/**
|
|
116
|
+
* Print the secrets of confidential OIDC clients an install or enable created.
|
|
117
|
+
* They are shown once — the panel stores only their digests.
|
|
118
|
+
*
|
|
119
|
+
* @param {Array<{ id: string, secret: string }> | undefined} clients
|
|
120
|
+
*/
|
|
121
|
+
function printCreatedSecrets(clients) {
|
|
122
|
+
if (!clients || clients.length === 0) return;
|
|
123
|
+
console.log(` ${chalk.bold('Confidential OIDC client secrets (shown once):')}`);
|
|
124
|
+
for (const c of clients) console.log(` ${chalk.cyan(c.id)} ${c.secret}`);
|
|
125
|
+
console.log('');
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Exit with a usage or panel error, as text or NDJSON.
|
|
130
|
+
*
|
|
131
|
+
* @param {string} message
|
|
132
|
+
* @param {boolean} json
|
|
133
|
+
* @param {string} [step] NDJSON step that failed
|
|
134
|
+
* @returns {never}
|
|
135
|
+
*/
|
|
136
|
+
function fail(message, json, step) {
|
|
137
|
+
if (json) {
|
|
138
|
+
if (step) emitStep(step, 'failed', message);
|
|
139
|
+
emitError(message);
|
|
140
|
+
} else {
|
|
141
|
+
console.error(`\n ${chalk.red(message)}\n`);
|
|
142
|
+
}
|
|
143
|
+
process.exit(1);
|
|
144
|
+
}
|
|
145
|
+
|
|
119
146
|
/**
|
|
120
147
|
* @param {string | undefined} packageName
|
|
121
148
|
* @param {{ json: boolean }} options
|
|
122
149
|
*/
|
|
123
150
|
async function installPluginCmd(packageName, { json }) {
|
|
124
|
-
if (!packageName)
|
|
125
|
-
const msg = 'Usage: lamaste-server plugins install <package>';
|
|
126
|
-
if (json) emitError(msg);
|
|
127
|
-
else console.error(`\n ${msg}\n`);
|
|
128
|
-
process.exit(1);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const logger = createLogger({ json });
|
|
151
|
+
if (!packageName) fail('Usage: lamaste-server plugins install <package>', json);
|
|
132
152
|
|
|
133
153
|
if (json) {
|
|
134
154
|
emitStep('install', 'running', `Installing ${packageName}`);
|
|
135
|
-
emitLog('info', `
|
|
155
|
+
emitLog('info', `The panel is fetching ${packageName} from the npm registry.`);
|
|
136
156
|
} else {
|
|
137
157
|
process.stderr.write(` Installing ${chalk.cyan(packageName)}...`);
|
|
138
158
|
}
|
|
139
159
|
|
|
160
|
+
let result;
|
|
140
161
|
try {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
if (json) {
|
|
149
|
-
emitStep('install', 'complete');
|
|
150
|
-
emitComplete({ plugin: entry });
|
|
151
|
-
} else {
|
|
152
|
-
console.log(` ${chalk.green('ok')}`);
|
|
153
|
-
console.log(` Plugin ${chalk.cyan(entry.name)} installed (${chalk.dim('disabled')})`);
|
|
154
|
-
console.log(
|
|
155
|
-
` Run ${chalk.cyan(`lamaste-server plugins enable ${entry.name}`)} to activate.`,
|
|
156
|
-
);
|
|
157
|
-
console.log('');
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
await restartPanel(json);
|
|
162
|
+
result = await panelRequest(
|
|
163
|
+
'POST',
|
|
164
|
+
'/api/plugins/install',
|
|
165
|
+
{ packageName },
|
|
166
|
+
{ timeoutMs: NPM_CALL_TIMEOUT_MS },
|
|
167
|
+
);
|
|
161
168
|
} catch (err) {
|
|
162
|
-
if (json) {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
169
|
+
if (!json) console.log(` ${chalk.red('failed')}`);
|
|
170
|
+
fail(err.message, json, 'install');
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const { plugin, oidcClients } = result;
|
|
174
|
+
if (json) {
|
|
175
|
+
emitStep('install', 'complete');
|
|
176
|
+
emitComplete({ plugin, oidcClients });
|
|
177
|
+
return;
|
|
170
178
|
}
|
|
179
|
+
const hosting = plugin.hosting === 'agent' ? ', agent-hosted' : '';
|
|
180
|
+
console.log(` ${chalk.green('ok')}`);
|
|
181
|
+
console.log(` Plugin ${chalk.cyan(plugin.name)} installed (${chalk.dim(`disabled${hosting}`)})`);
|
|
182
|
+
console.log(` Run ${chalk.cyan(`lamaste-server plugins enable ${plugin.name}`)} to activate.`);
|
|
183
|
+
console.log('');
|
|
184
|
+
printCreatedSecrets(oidcClients);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* The panel mounts a server-hosted plugin's routes at startup, so enabling or
|
|
189
|
+
* disabling one takes effect after a restart; an agent-hosted plugin has
|
|
190
|
+
* nothing mounted and its OIDC clients are already applied.
|
|
191
|
+
*
|
|
192
|
+
* @param {string} name
|
|
193
|
+
* @returns {Promise<boolean>}
|
|
194
|
+
*/
|
|
195
|
+
async function needsRestart(name) {
|
|
196
|
+
const { plugin } = await panelRequest('GET', `/api/plugins/${encodeURIComponent(name)}`);
|
|
197
|
+
return plugin.hosting !== 'agent';
|
|
171
198
|
}
|
|
172
199
|
|
|
173
200
|
/**
|
|
@@ -175,28 +202,21 @@ async function installPluginCmd(packageName, { json }) {
|
|
|
175
202
|
* @param {{ json: boolean }} options
|
|
176
203
|
*/
|
|
177
204
|
async function enablePluginCmd(name, { json }) {
|
|
178
|
-
if (!name)
|
|
179
|
-
const msg = 'Usage: lamaste-server plugins enable <name>';
|
|
180
|
-
if (json) emitError(msg);
|
|
181
|
-
else console.error(`\n ${msg}\n`);
|
|
182
|
-
process.exit(1);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
const logger = createLogger({ json });
|
|
205
|
+
if (!name) fail('Usage: lamaste-server plugins enable <name>', json);
|
|
186
206
|
|
|
207
|
+
let result;
|
|
187
208
|
try {
|
|
188
|
-
await
|
|
189
|
-
if (json) {
|
|
190
|
-
emitComplete({ name, status: 'enabled' });
|
|
191
|
-
} else {
|
|
192
|
-
console.log(`\n Plugin ${chalk.cyan(name)} ${chalk.green('enabled')}.`);
|
|
193
|
-
}
|
|
194
|
-
await restartPanel(json);
|
|
209
|
+
result = await panelRequest('POST', `/api/plugins/${encodeURIComponent(name)}/enable`);
|
|
195
210
|
} catch (err) {
|
|
196
|
-
|
|
197
|
-
else console.error(`\n ${chalk.red(err.message)}\n`);
|
|
198
|
-
process.exit(1);
|
|
211
|
+
fail(err.message, json);
|
|
199
212
|
}
|
|
213
|
+
|
|
214
|
+
if (json) emitComplete({ name, status: 'enabled', oidcClients: result.oidcClients });
|
|
215
|
+
else {
|
|
216
|
+
console.log(`\n Plugin ${chalk.cyan(name)} ${chalk.green('enabled')}.`);
|
|
217
|
+
printCreatedSecrets(result.oidcClients);
|
|
218
|
+
}
|
|
219
|
+
if (await needsRestart(name)) await restartPanel(json);
|
|
200
220
|
}
|
|
201
221
|
|
|
202
222
|
/**
|
|
@@ -204,28 +224,17 @@ async function enablePluginCmd(name, { json }) {
|
|
|
204
224
|
* @param {{ json: boolean }} options
|
|
205
225
|
*/
|
|
206
226
|
async function disablePluginCmd(name, { json }) {
|
|
207
|
-
if (!name)
|
|
208
|
-
const msg = 'Usage: lamaste-server plugins disable <name>';
|
|
209
|
-
if (json) emitError(msg);
|
|
210
|
-
else console.error(`\n ${msg}\n`);
|
|
211
|
-
process.exit(1);
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
const logger = createLogger({ json });
|
|
227
|
+
if (!name) fail('Usage: lamaste-server plugins disable <name>', json);
|
|
215
228
|
|
|
216
229
|
try {
|
|
217
|
-
await
|
|
218
|
-
if (json) {
|
|
219
|
-
emitComplete({ name, status: 'disabled' });
|
|
220
|
-
} else {
|
|
221
|
-
console.log(`\n Plugin ${chalk.cyan(name)} ${chalk.red('disabled')}.`);
|
|
222
|
-
}
|
|
223
|
-
await restartPanel(json);
|
|
230
|
+
await panelRequest('POST', `/api/plugins/${encodeURIComponent(name)}/disable`);
|
|
224
231
|
} catch (err) {
|
|
225
|
-
|
|
226
|
-
else console.error(`\n ${chalk.red(err.message)}\n`);
|
|
227
|
-
process.exit(1);
|
|
232
|
+
fail(err.message, json);
|
|
228
233
|
}
|
|
234
|
+
|
|
235
|
+
if (json) emitComplete({ name, status: 'disabled' });
|
|
236
|
+
else console.log(`\n Plugin ${chalk.cyan(name)} ${chalk.red('disabled')}.`);
|
|
237
|
+
if (await needsRestart(name)) await restartPanel(json);
|
|
229
238
|
}
|
|
230
239
|
|
|
231
240
|
/**
|
|
@@ -233,36 +242,27 @@ async function disablePluginCmd(name, { json }) {
|
|
|
233
242
|
* @param {{ json: boolean }} options
|
|
234
243
|
*/
|
|
235
244
|
async function uninstallPluginCmd(name, { json }) {
|
|
236
|
-
if (!name)
|
|
237
|
-
const msg = 'Usage: lamaste-server plugins uninstall <name>';
|
|
238
|
-
if (json) emitError(msg);
|
|
239
|
-
else console.error(`\n ${msg}\n`);
|
|
240
|
-
process.exit(1);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
const logger = createLogger({ json });
|
|
245
|
+
if (!name) fail('Usage: lamaste-server plugins uninstall <name>', json);
|
|
244
246
|
|
|
245
247
|
if (json) emitStep('uninstall', 'running', `Uninstalling ${name}`);
|
|
246
248
|
else process.stderr.write(` Uninstalling ${chalk.cyan(name)}...`);
|
|
247
249
|
|
|
248
250
|
try {
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
}
|
|
254
|
-
console.log(` ${chalk.green('ok')}`);
|
|
255
|
-
}
|
|
256
|
-
await restartPanel(json);
|
|
251
|
+
// The panel refuses an enabled plugin (409): nothing of it is mounted
|
|
252
|
+
// once it is disabled, so no restart follows.
|
|
253
|
+
await panelRequest('DELETE', `/api/plugins/${encodeURIComponent(name)}`, null, {
|
|
254
|
+
timeoutMs: NPM_CALL_TIMEOUT_MS,
|
|
255
|
+
});
|
|
257
256
|
} catch (err) {
|
|
258
|
-
if (json) {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
}
|
|
265
|
-
|
|
257
|
+
if (!json) console.log(` ${chalk.red('failed')}`);
|
|
258
|
+
fail(err.message, json, 'uninstall');
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (json) {
|
|
262
|
+
emitStep('uninstall', 'complete');
|
|
263
|
+
emitComplete({ name, removed: true });
|
|
264
|
+
} else {
|
|
265
|
+
console.log(` ${chalk.green('ok')}`);
|
|
266
266
|
}
|
|
267
267
|
}
|
|
268
268
|
|
|
@@ -339,58 +339,13 @@ async function rotateSecretCmd(name, clientId, { json }) {
|
|
|
339
339
|
console.log(` ${chalk.bold('New secret (shown once):')} ${result.secret}\n`);
|
|
340
340
|
}
|
|
341
341
|
|
|
342
|
-
const MUTATING = new Set(['install', 'enable', 'disable', 'uninstall']);
|
|
343
|
-
|
|
344
|
-
/** Set on the child run as lamaste: the root parent restarts the panel. */
|
|
345
|
-
const CHILD_ENV = 'LAMALIBRE_LAMASTE_CLI_PLUGINS_CHILD';
|
|
346
|
-
|
|
347
|
-
/**
|
|
348
|
-
* Run a plugin subcommand as the lamaste user and wait for it.
|
|
349
|
-
*
|
|
350
|
-
* Plugin state (the npm tree, plugins.json, plugin data) lives in the
|
|
351
|
-
* lamaste-owned state directory. Running npm or writing files there as root
|
|
352
|
-
* would let whatever the panel left in that directory — a `.npmrc`, a
|
|
353
|
-
* symlink — steer root. As lamaste, it can only reach what the panel could
|
|
354
|
-
* already reach. Stays usable while the panel is down (disabling a plugin
|
|
355
|
-
* that keeps it from starting).
|
|
356
|
-
*
|
|
357
|
-
* @param {string[]} args
|
|
358
|
-
* @param {{ json: boolean }} options
|
|
359
|
-
*/
|
|
360
|
-
async function runAsLamaste(args, { json }) {
|
|
361
|
-
const uid = Number.parseInt((await execa('id', ['-u', 'lamaste'])).stdout.trim(), 10);
|
|
362
|
-
const gid = Number.parseInt((await execa('id', ['-g', 'lamaste'])).stdout.trim(), 10);
|
|
363
|
-
const { exitCode } = await execa(
|
|
364
|
-
process.execPath,
|
|
365
|
-
[process.argv[1], 'plugins', ...args, ...(json ? ['--json'] : [])],
|
|
366
|
-
{
|
|
367
|
-
uid,
|
|
368
|
-
gid,
|
|
369
|
-
cwd: STATE_DIR,
|
|
370
|
-
stdio: 'inherit',
|
|
371
|
-
reject: false,
|
|
372
|
-
env: {
|
|
373
|
-
...process.env,
|
|
374
|
-
[CHILD_ENV]: '1',
|
|
375
|
-
HOME: STATE_DIR,
|
|
376
|
-
USER: 'lamaste',
|
|
377
|
-
LOGNAME: 'lamaste',
|
|
378
|
-
npm_config_cache: `${STATE_DIR}/.npm`,
|
|
379
|
-
},
|
|
380
|
-
extendEnv: false,
|
|
381
|
-
},
|
|
382
|
-
);
|
|
383
|
-
if (exitCode !== 0) process.exit(exitCode ?? 1);
|
|
384
|
-
}
|
|
385
|
-
|
|
386
342
|
/**
|
|
387
|
-
* Restart the panel
|
|
388
|
-
*
|
|
343
|
+
* Restart the panel so it mounts (or unmounts) a server-hosted plugin's
|
|
344
|
+
* routes. Needs root, like every `lamaste-server` command that reads the
|
|
345
|
+
* admin certificate.
|
|
389
346
|
* @param {boolean} json
|
|
390
347
|
*/
|
|
391
348
|
async function restartPanel(json) {
|
|
392
|
-
// The child run as lamaste cannot; its root parent does.
|
|
393
|
-
if (process.env[CHILD_ENV] === '1') return;
|
|
394
349
|
try {
|
|
395
350
|
await execa('systemctl', ['restart', PANEL_SERVICE]);
|
|
396
351
|
if (!json) {
|
|
@@ -97,9 +97,11 @@ export function parsePanelResponse(stdout, method, path) {
|
|
|
97
97
|
* @param {string} method
|
|
98
98
|
* @param {string} path e.g. '/api/tunnels'
|
|
99
99
|
* @param {Record<string, unknown> | null} [body] sent as JSON when given
|
|
100
|
+
* @param {{ timeoutMs?: number }} [options] `timeoutMs` for calls the panel
|
|
101
|
+
* needs longer to answer (a plugin install runs npm); default 30 s
|
|
100
102
|
* @returns {Promise<Record<string, unknown>>}
|
|
101
103
|
*/
|
|
102
|
-
export async function panelRequest(method, path, body = null) {
|
|
104
|
+
export async function panelRequest(method, path, body = null, { timeoutMs = 30000 } = {}) {
|
|
103
105
|
const p12Path = `${PKI_DIR}/client.p12`;
|
|
104
106
|
|
|
105
107
|
// Read p12 password from the stored file
|
|
@@ -120,7 +122,7 @@ export async function panelRequest(method, path, body = null) {
|
|
|
120
122
|
const { stdout } = await execa(
|
|
121
123
|
'curl',
|
|
122
124
|
buildPanelCurlArgs({ method, path, body, p12Path, configPath: tmpConfigPath }),
|
|
123
|
-
{ timeout:
|
|
125
|
+
{ timeout: timeoutMs },
|
|
124
126
|
);
|
|
125
127
|
|
|
126
128
|
return parsePanelResponse(stdout, method, path);
|