@openagt/install 0.1.0 → 0.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/dist/address.d.ts +32 -0
- package/dist/address.d.ts.map +1 -0
- package/dist/address.js +56 -0
- package/dist/address.js.map +1 -0
- package/dist/install.d.ts +12 -10
- package/dist/install.d.ts.map +1 -1
- package/dist/install.js +65 -81
- package/dist/install.js.map +1 -1
- package/dist/linux.d.ts +79 -0
- package/dist/linux.d.ts.map +1 -0
- package/dist/linux.js +289 -0
- package/dist/linux.js.map +1 -0
- package/dist/mac.d.ts +4 -25
- package/dist/mac.d.ts.map +1 -1
- package/dist/mac.js +65 -47
- package/dist/mac.js.map +1 -1
- package/dist/platform.d.ts +49 -0
- package/dist/platform.d.ts.map +1 -0
- package/dist/platform.js +2 -0
- package/dist/platform.js.map +1 -0
- package/dist/run.d.ts +12 -0
- package/dist/run.d.ts.map +1 -0
- package/dist/run.js +33 -0
- package/dist/run.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The secure address, the same on every computer: its name, the address it points at, its hosts
|
|
3
|
+
* line and its certificate. Each platform's own parts are in its module (mac.ts, linux.ts).
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* The dashboard's secure address: the website's own name, which this computer then answers
|
|
7
|
+
* itself, the dashboard with the website's copy beside it (#1919).
|
|
8
|
+
*/
|
|
9
|
+
export declare const ADDRESS = "openagent.build";
|
|
10
|
+
/**
|
|
11
|
+
* The address the name points at: one of this computer's own, the address's alone. The port rule
|
|
12
|
+
* then touches nothing else this computer sends itself on port 443 (a container a developer
|
|
13
|
+
* publishes there, say), as a rule for `127.0.0.1` would.
|
|
14
|
+
*/
|
|
15
|
+
export declare const LOOPBACK_ADDRESS = "127.0.0.42";
|
|
16
|
+
/** The end of the hosts line the install adds, which is how the uninstall finds it again. */
|
|
17
|
+
export declare const HOSTS_MARK = "# OpenAgent";
|
|
18
|
+
/** `value` as one word of a shell script, whatever it holds. */
|
|
19
|
+
export declare function quoted(value: string): string;
|
|
20
|
+
/**
|
|
21
|
+
* Shell lines that take the install's line out of the hosts file `file`, and leave the rest as it
|
|
22
|
+
* was. The file is written over, not replaced, so it keeps its owner, its permissions and a link
|
|
23
|
+
* that points at it.
|
|
24
|
+
*/
|
|
25
|
+
export declare function removeHostsLine(file: string): string;
|
|
26
|
+
/** Shell lines that point `name` at this computer in the hosts file `file`, once, however often they run. */
|
|
27
|
+
export declare function addHostsLine(file: string, name: string): string;
|
|
28
|
+
/** The certificate's openssl settings: for `name` alone, for a server, and no authority over any other. */
|
|
29
|
+
export declare function certificateConfig(name: string): string;
|
|
30
|
+
/** The longest a certificate may last for Safari and macOS: 825 days. */
|
|
31
|
+
export declare const CERTIFICATE_DAYS = 825;
|
|
32
|
+
//# sourceMappingURL=address.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"address.d.ts","sourceRoot":"","sources":["../src/address.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,eAAO,MAAM,OAAO,oBAAoB,CAAA;AACxC;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,eAAe,CAAA;AAE5C,6FAA6F;AAC7F,eAAO,MAAM,UAAU,gBAAgB,CAAA;AAEvC,gEAAgE;AAChE,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGpD;AAED,6GAA6G;AAC7G,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAO/D;AAED,2GAA2G;AAC3G,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAYtD;AAED,yEAAyE;AACzE,eAAO,MAAM,gBAAgB,MAAM,CAAA"}
|
package/dist/address.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The secure address, the same on every computer: its name, the address it points at, its hosts
|
|
3
|
+
* line and its certificate. Each platform's own parts are in its module (mac.ts, linux.ts).
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* The dashboard's secure address: the website's own name, which this computer then answers
|
|
7
|
+
* itself, the dashboard with the website's copy beside it (#1919).
|
|
8
|
+
*/
|
|
9
|
+
export const ADDRESS = 'openagent.build';
|
|
10
|
+
/**
|
|
11
|
+
* The address the name points at: one of this computer's own, the address's alone. The port rule
|
|
12
|
+
* then touches nothing else this computer sends itself on port 443 (a container a developer
|
|
13
|
+
* publishes there, say), as a rule for `127.0.0.1` would.
|
|
14
|
+
*/
|
|
15
|
+
export const LOOPBACK_ADDRESS = '127.0.0.42';
|
|
16
|
+
/** The end of the hosts line the install adds, which is how the uninstall finds it again. */
|
|
17
|
+
export const HOSTS_MARK = '# OpenAgent';
|
|
18
|
+
/** `value` as one word of a shell script, whatever it holds. */
|
|
19
|
+
export function quoted(value) {
|
|
20
|
+
return `'${value.replaceAll("'", `'\\''`)}'`;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Shell lines that take the install's line out of the hosts file `file`, and leave the rest as it
|
|
24
|
+
* was. The file is written over, not replaced, so it keeps its owner, its permissions and a link
|
|
25
|
+
* that points at it.
|
|
26
|
+
*/
|
|
27
|
+
export function removeHostsLine(file) {
|
|
28
|
+
const kept = quoted(`${file}.openagent`);
|
|
29
|
+
return `if grep -q ${quoted(` ${HOSTS_MARK}$`)} ${quoted(file)}; then sed ${quoted(`/ ${HOSTS_MARK}$/d`)} ${quoted(file)} > ${kept} && cat ${kept} > ${quoted(file)} && rm ${kept}; fi`;
|
|
30
|
+
}
|
|
31
|
+
/** Shell lines that point `name` at this computer in the hosts file `file`, once, however often they run. */
|
|
32
|
+
export function addHostsLine(file, name) {
|
|
33
|
+
return [
|
|
34
|
+
removeHostsLine(file),
|
|
35
|
+
// A file that does not end its last line would have this one joined to it.
|
|
36
|
+
`if [ -s ${quoted(file)} ] && [ -n "$(tail -c 1 ${quoted(file)})" ]; then echo >> ${quoted(file)}; fi`,
|
|
37
|
+
`printf '%s\\n' ${quoted(`${LOOPBACK_ADDRESS} ${name} ${HOSTS_MARK}`)} >> ${quoted(file)}`,
|
|
38
|
+
].join('\n');
|
|
39
|
+
}
|
|
40
|
+
/** The certificate's openssl settings: for `name` alone, for a server, and no authority over any other. */
|
|
41
|
+
export function certificateConfig(name) {
|
|
42
|
+
return `[req]
|
|
43
|
+
distinguished_name = dn
|
|
44
|
+
prompt = no
|
|
45
|
+
[dn]
|
|
46
|
+
CN = ${name}
|
|
47
|
+
[ext]
|
|
48
|
+
subjectAltName = DNS:${name}
|
|
49
|
+
basicConstraints = critical, CA:FALSE
|
|
50
|
+
keyUsage = critical, digitalSignature, keyEncipherment
|
|
51
|
+
extendedKeyUsage = serverAuth
|
|
52
|
+
`;
|
|
53
|
+
}
|
|
54
|
+
/** The longest a certificate may last for Safari and macOS: 825 days. */
|
|
55
|
+
export const CERTIFICATE_DAYS = 825;
|
|
56
|
+
//# sourceMappingURL=address.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"address.js","sourceRoot":"","sources":["../src/address.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,iBAAiB,CAAA;AACxC;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,YAAY,CAAA;AAE5C,6FAA6F;AAC7F,MAAM,CAAC,MAAM,UAAU,GAAG,aAAa,CAAA;AAEvC,gEAAgE;AAChE,MAAM,UAAU,MAAM,CAAC,KAAa;IAClC,OAAO,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,GAAG,CAAA;AAC9C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,IAAI,YAAY,CAAC,CAAA;IACxC,OAAO,cAAc,MAAM,CAAC,IAAI,UAAU,GAAG,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,cAAc,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,IAAI,WAAW,IAAI,MAAM,MAAM,CAAC,IAAI,CAAC,UAAU,IAAI,MAAM,CAAA;AACzL,CAAC;AAED,6GAA6G;AAC7G,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,IAAY;IACrD,OAAO;QACL,eAAe,CAAC,IAAI,CAAC;QACrB,2EAA2E;QAC3E,WAAW,MAAM,CAAC,IAAI,CAAC,2BAA2B,MAAM,CAAC,IAAI,CAAC,sBAAsB,MAAM,CAAC,IAAI,CAAC,MAAM;QACtG,kBAAkB,MAAM,CAAC,GAAG,gBAAgB,IAAI,IAAI,IAAI,UAAU,EAAE,CAAC,OAAO,MAAM,CAAC,IAAI,CAAC,EAAE;KAC3F,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACd,CAAC;AAED,2GAA2G;AAC3G,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO;;;;OAIF,IAAI;;uBAEY,IAAI;;;;CAI1B,CAAA;AACD,CAAC;AAED,yEAAyE;AACzE,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,CAAA"}
|
package/dist/install.d.ts
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
3
|
-
out: (line: string) => void;
|
|
4
|
-
err: (line: string) => void;
|
|
5
|
-
}
|
|
1
|
+
import type { InstallIO } from './platform.js';
|
|
2
|
+
export type { InstallIO };
|
|
6
3
|
/**
|
|
7
|
-
* `
|
|
8
|
-
*
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
* Whether `port` is free within `ms`: a dashboard told to stop closes its runs' views first, for
|
|
5
|
+
* up to ten seconds, and holds its port until it has.
|
|
6
|
+
*/
|
|
7
|
+
export declare function freed(port: number, ms: number): Promise<boolean>;
|
|
8
|
+
/**
|
|
9
|
+
* `npx @openagt/install`: the dashboard starts at login, at `https://openagent.build`. Asks for
|
|
10
|
+
* the person's password as the administrator, for the name and its port; on a Mac also macOS's
|
|
11
|
+
* own window, to trust the certificate made here. Typed again, it does the same, and asks nothing
|
|
12
|
+
* it needs no more.
|
|
11
13
|
*/
|
|
12
14
|
export declare function install(io?: InstallIO, env?: NodeJS.ProcessEnv): Promise<number>;
|
|
13
|
-
/** `npx @openagt/uninstall`: everything {@link install} put on this
|
|
15
|
+
/** `npx @openagt/uninstall`: everything {@link install} put on this computer, taken off. Each part is taken off even when another fails. */
|
|
14
16
|
export declare function uninstall(io?: InstallIO, env?: NodeJS.ProcessEnv): Promise<number>;
|
|
15
17
|
//# sourceMappingURL=install.d.ts.map
|
package/dist/install.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,SAAS,EAAY,MAAM,eAAe,CAAA;AAGxD,YAAY,EAAE,SAAS,EAAE,CAAA;AAsBzB;;;GAGG;AACH,wBAAsB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOtE;AA0DD;;;;;GAKG;AACH,wBAAsB,OAAO,CAAC,EAAE,GAAE,SAAqB,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAAC,MAAM,CAAC,CAuC9G;AAED,4IAA4I;AAC5I,wBAAsB,SAAS,CAAC,EAAE,GAAE,SAAqB,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAAC,MAAM,CAAC,CAuBhH"}
|
package/dist/install.js
CHANGED
|
@@ -1,43 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { X509Certificate } from 'node:crypto';
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
3
2
|
import { mkdir, readFile, realpath, rm, writeFile } from 'node:fs/promises';
|
|
4
3
|
import { request } from 'node:https';
|
|
5
4
|
import { createRequire } from 'node:module';
|
|
6
5
|
import { connect } from 'node:net';
|
|
7
|
-
import { homedir } from 'node:os';
|
|
8
6
|
import { dirname, join } from 'node:path';
|
|
9
7
|
import { CERTIFICATE_FILE, KEY_FILE, readSecureAddress, secureAddressDir } from '@openagt/dashboard/secure-address';
|
|
10
|
-
import { ADDRESS, CERTIFICATE_DAYS,
|
|
8
|
+
import { ADDRESS, CERTIFICATE_DAYS, LOOPBACK_ADDRESS, certificateConfig } from './address.js';
|
|
9
|
+
import { linux } from './linux.js';
|
|
10
|
+
import { mac } from './mac.js';
|
|
11
|
+
import { run } from './run.js';
|
|
11
12
|
const defaultIO = {
|
|
12
13
|
out: line => process.stdout.write(line + '\n'),
|
|
13
14
|
err: line => process.stderr.write(line + '\n'),
|
|
14
15
|
};
|
|
16
|
+
/** The kinds of computer OpenAgent installs on. */
|
|
17
|
+
const PLATFORMS = { darwin: mac, linux };
|
|
15
18
|
/** The port the dashboard's plain address is on, which the install's dashboard takes. */
|
|
16
19
|
const DASHBOARD_PORT = 4200;
|
|
17
|
-
/** Where the install keeps what it puts on this Mac, outside the secure address's own folder. */
|
|
18
|
-
function places(env) {
|
|
19
|
-
const home = env.HOME || homedir();
|
|
20
|
-
return {
|
|
21
|
-
home,
|
|
22
|
-
agent: join(home, 'Library', 'LaunchAgents', `${DASHBOARD_LABEL}.plist`),
|
|
23
|
-
logs: join(home, 'Library', 'Logs', 'OpenAgent'),
|
|
24
|
-
app: join(home, 'Library', 'Application Support', 'OpenAgent'),
|
|
25
|
-
keychain: join(home, 'Library', 'Keychains', 'login.keychain-db'),
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
/** Run a command to its end; rejects with what it said when it fails. `interactive` gives it this terminal, for a password. */
|
|
29
|
-
function run(command, args, opts = {}) {
|
|
30
|
-
if (opts.interactive) {
|
|
31
|
-
return new Promise((resolvePromise, rejectPromise) => {
|
|
32
|
-
spawn(command, args, { stdio: 'inherit' })
|
|
33
|
-
.on('error', rejectPromise)
|
|
34
|
-
.on('exit', code => (code === 0 ? resolvePromise() : rejectPromise(new Error(`${command} ended with ${code}`))));
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
return new Promise((resolvePromise, rejectPromise) => {
|
|
38
|
-
execFile(command, args, (error, _stdout, stderr) => (error ? rejectPromise(new Error(String(stderr).trim() || error.message)) : resolvePromise()));
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
20
|
/** Whether something answers on this computer's `port`. */
|
|
42
21
|
function taken(port) {
|
|
43
22
|
return new Promise(resolvePromise => {
|
|
@@ -47,9 +26,22 @@ function taken(port) {
|
|
|
47
26
|
});
|
|
48
27
|
}
|
|
49
28
|
/**
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
|
|
29
|
+
* Whether `port` is free within `ms`: a dashboard told to stop closes its runs' views first, for
|
|
30
|
+
* up to ten seconds, and holds its port until it has.
|
|
31
|
+
*/
|
|
32
|
+
export async function freed(port, ms) {
|
|
33
|
+
const until = Date.now() + ms;
|
|
34
|
+
while (await taken(port)) {
|
|
35
|
+
if (Date.now() >= until)
|
|
36
|
+
return false;
|
|
37
|
+
await new Promise(resolvePromise => setTimeout(resolvePromise, 250));
|
|
38
|
+
}
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The dashboard the computer starts at login. Run from a checkout, or from a folder of its own,
|
|
43
|
+
* it is the one this command came with. Run by `npx`, that one is in npm's cache, which npm
|
|
44
|
+
* empties when it likes: the same version is installed to a folder of OpenAgent's own.
|
|
53
45
|
*/
|
|
54
46
|
async function lastingDashboard(app, io) {
|
|
55
47
|
const manifest = await realpath(createRequire(import.meta.url).resolve('@openagt/dashboard/package.json'));
|
|
@@ -74,10 +66,6 @@ async function ensureCertificate(env) {
|
|
|
74
66
|
await rm(config);
|
|
75
67
|
return readFile(join(dir, CERTIFICATE_FILE), 'utf8');
|
|
76
68
|
}
|
|
77
|
-
/** Whether this Mac trusts the certificate for {@link ADDRESS} already, so a second install asks nothing. */
|
|
78
|
-
function trusted(certFile) {
|
|
79
|
-
return run('security', ['verify-cert', '-c', certFile, '-p', 'ssl', '-s', ADDRESS, '-q']).then(() => true, () => false);
|
|
80
|
-
}
|
|
81
69
|
/** Whether the secure address answers with the dashboard, as a browser reaches it. */
|
|
82
70
|
function answers(cert) {
|
|
83
71
|
return new Promise(resolvePromise => {
|
|
@@ -99,48 +87,50 @@ async function waitUntilAnswers(cert, ms) {
|
|
|
99
87
|
}
|
|
100
88
|
return false;
|
|
101
89
|
}
|
|
90
|
+
/** Runs `step` as the administrator, in this terminal, which asks for the password. */
|
|
91
|
+
function asAdmin(step, io) {
|
|
92
|
+
io.out(`◆ ${step.says}`);
|
|
93
|
+
return run('sudo', ['/bin/sh', '-c', step.script], { interactive: true });
|
|
94
|
+
}
|
|
102
95
|
/**
|
|
103
|
-
* `npx @openagt/install`: the dashboard starts at login, at `https://openagent.build`. Asks
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
96
|
+
* `npx @openagt/install`: the dashboard starts at login, at `https://openagent.build`. Asks for
|
|
97
|
+
* the person's password as the administrator, for the name and its port; on a Mac also macOS's
|
|
98
|
+
* own window, to trust the certificate made here. Typed again, it does the same, and asks nothing
|
|
99
|
+
* it needs no more.
|
|
107
100
|
*/
|
|
108
101
|
export async function install(io = defaultIO, env = process.env) {
|
|
109
|
-
|
|
110
|
-
|
|
102
|
+
const platform = PLATFORMS[process.platform];
|
|
103
|
+
if (!platform) {
|
|
104
|
+
io.err('For now OpenAgent installs on a Mac or on Linux only. On this computer, run `npx @openagt/dashboard`.');
|
|
111
105
|
return 1;
|
|
112
106
|
}
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
107
|
+
const unable = await platform.unable(env);
|
|
108
|
+
if (unable) {
|
|
109
|
+
io.err(unable);
|
|
110
|
+
return 1;
|
|
111
|
+
}
|
|
112
|
+
// One installed already stops first, and is waited for, so what holds the port below is someone else's.
|
|
113
|
+
const stopped = await platform.stopDashboard(env);
|
|
114
|
+
if (!(await freed(DASHBOARD_PORT, stopped ? 15_000 : 0))) {
|
|
118
115
|
io.err(`A dashboard runs on port ${DASHBOARD_PORT} already. Stop it (Ctrl+C in its terminal), then run this again.`);
|
|
119
116
|
return 1;
|
|
120
117
|
}
|
|
121
118
|
try {
|
|
122
|
-
const dashboard = await lastingDashboard(
|
|
119
|
+
const dashboard = await lastingDashboard(platform.appDir(env), io);
|
|
120
|
+
await platform.prepare(io, env);
|
|
123
121
|
const cert = await ensureCertificate(env);
|
|
124
122
|
const certFile = join(secureAddressDir(env), CERTIFICATE_FILE);
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
io.out(`◆ your password as the administrator, once: ${ADDRESS} is pointed at this Mac (/etc/hosts), and its port 443 at the dashboard (a packet filter rule).`);
|
|
130
|
-
await run('sudo', ['/bin/sh', '-c', adminInstallScript(ADDRESS)], { interactive: true });
|
|
131
|
-
await mkdir(place.logs, { recursive: true });
|
|
132
|
-
await mkdir(dirname(place.agent), { recursive: true });
|
|
133
|
-
const log = join(place.logs, 'dashboard.log');
|
|
134
|
-
const agentEnv = { PATH: env.PATH ?? '/usr/bin:/bin:/usr/sbin:/sbin', ...(env.XDG_CONFIG_HOME ? { XDG_CONFIG_HOME: env.XDG_CONFIG_HOME } : {}) };
|
|
135
|
-
await writeFile(place.agent, dashboardPlist({ node: process.execPath, dashboard, home: place.home, env: agentEnv, log }));
|
|
136
|
-
await run('launchctl', ['bootstrap', `gui/${uid}`, place.agent]);
|
|
123
|
+
await asAdmin(platform.adminInstall(certFile), io);
|
|
124
|
+
await platform.trust(certFile, io, env);
|
|
125
|
+
const vars = { PATH: env.PATH ?? '/usr/bin:/bin:/usr/sbin:/sbin', ...(env.XDG_CONFIG_HOME ? { XDG_CONFIG_HOME: env.XDG_CONFIG_HOME } : {}) };
|
|
126
|
+
const output = await platform.startDashboard({ node: process.execPath, dashboard, vars }, env);
|
|
137
127
|
if (!(await waitUntilAnswers(cert, 30_000))) {
|
|
138
|
-
io.err(`The dashboard does not answer at https://${ADDRESS} yet. What it says is in ${
|
|
128
|
+
io.err(`The dashboard does not answer at https://${ADDRESS} yet. What it says is in ${output}.`);
|
|
139
129
|
return 1;
|
|
140
130
|
}
|
|
141
131
|
io.out(`◆ OpenAgent is installed: https://${ADDRESS}`);
|
|
142
132
|
io.out(' It starts when you log in. `npx @openagt/uninstall` takes it off again.');
|
|
143
|
-
spawn(
|
|
133
|
+
spawn(platform.openCommand, [`https://${ADDRESS}`], { stdio: 'ignore', detached: true }).on('error', () => { }).unref();
|
|
144
134
|
return 0;
|
|
145
135
|
}
|
|
146
136
|
catch (err) {
|
|
@@ -148,34 +138,28 @@ export async function install(io = defaultIO, env = process.env) {
|
|
|
148
138
|
return 1;
|
|
149
139
|
}
|
|
150
140
|
}
|
|
151
|
-
/** `npx @openagt/uninstall`: everything {@link install} put on this
|
|
141
|
+
/** `npx @openagt/uninstall`: everything {@link install} put on this computer, taken off. Each part is taken off even when another fails. */
|
|
152
142
|
export async function uninstall(io = defaultIO, env = process.env) {
|
|
153
|
-
|
|
154
|
-
|
|
143
|
+
const platform = PLATFORMS[process.platform];
|
|
144
|
+
if (!platform) {
|
|
145
|
+
io.err('OpenAgent installs on a Mac or on Linux only, so there is nothing to take off here.');
|
|
155
146
|
return 1;
|
|
156
147
|
}
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
await run('launchctl', ['bootout', `gui/${uid}/${DASHBOARD_LABEL}`]).catch(() => { });
|
|
160
|
-
await rm(place.agent, { force: true });
|
|
148
|
+
const left = await platform.leftBehind(env);
|
|
149
|
+
await platform.removeDashboard(env);
|
|
161
150
|
const dir = secureAddressDir(env);
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
io.out('◆ macOS asks for your password to stop trusting the certificate.');
|
|
165
|
-
await run('security', ['remove-trusted-cert', join(dir, CERTIFICATE_FILE)]).catch(() => { });
|
|
166
|
-
const sha1 = new X509Certificate(pem).fingerprint.replaceAll(':', '');
|
|
167
|
-
await run('security', ['delete-certificate', '-Z', sha1, place.keychain]).catch(() => { });
|
|
168
|
-
}
|
|
169
|
-
io.out(`◆ your password as the administrator, once: the hosts line for ${ADDRESS} and its port rule are taken off.`);
|
|
170
|
-
const admin = await run('sudo', ['/bin/sh', '-c', adminUninstallScript()], { interactive: true }).then(() => true, () => false);
|
|
151
|
+
await platform.untrust(join(dir, CERTIFICATE_FILE), io, env);
|
|
152
|
+
const admin = await asAdmin(platform.adminUninstall(), io).then(() => true, () => false);
|
|
171
153
|
await rm(dir, { recursive: true, force: true });
|
|
172
|
-
|
|
173
|
-
|
|
154
|
+
for (const folder of platform.folders(env))
|
|
155
|
+
await rm(folder, { recursive: true, force: true });
|
|
174
156
|
if (!admin) {
|
|
175
|
-
io.err(
|
|
157
|
+
io.err('The hosts line and the port rule are still there: run this again to take them off.');
|
|
176
158
|
return 1;
|
|
177
159
|
}
|
|
178
|
-
io.out('◆ OpenAgent is off this
|
|
160
|
+
io.out('◆ OpenAgent is off this computer. Your projects and their agents’ records are left as they were.');
|
|
161
|
+
if (left)
|
|
162
|
+
io.out(` ${left}`);
|
|
179
163
|
return 0;
|
|
180
164
|
}
|
|
181
165
|
//# sourceMappingURL=install.js.map
|
package/dist/install.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install.js","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"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"}
|
package/dist/linux.d.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { Platform } from './platform.js';
|
|
2
|
+
/**
|
|
3
|
+
* What the install puts on a Linux computer. Its files and its scripts as the administrator are
|
|
4
|
+
* text, made by pure functions a test reads; {@link linux} writes and runs them.
|
|
5
|
+
*/
|
|
6
|
+
/** What starts the dashboard at login: a systemd service of the person's own. */
|
|
7
|
+
export declare const DASHBOARD_UNIT = "openagent-dashboard.service";
|
|
8
|
+
/** What sends the address's port 443 to the dashboard at every start of the computer: a systemd service, the system's. */
|
|
9
|
+
export declare const PORT_UNIT = "openagent-port.service";
|
|
10
|
+
export declare const PORT_UNIT_FILE = "/etc/systemd/system/openagent-port.service";
|
|
11
|
+
/** The nftables table the port rule is in, of its own, so taking it off touches no other rule. */
|
|
12
|
+
export declare const PORT_TABLE = "ip openagent";
|
|
13
|
+
/** The certificate's name in the browsers' certificate stores, which is how the uninstall finds it again. */
|
|
14
|
+
export declare const NSS_NICKNAME = "OpenAgent (openagent.build)";
|
|
15
|
+
/**
|
|
16
|
+
* How the browsers trust it: as a server (`P`), which Chrome asks for, and as its own authority
|
|
17
|
+
* (`C`), which Firefox asks for of a certificate that signs itself. It still signs no other: it
|
|
18
|
+
* says it is no authority (`CA:FALSE`), and may not sign certificates.
|
|
19
|
+
*/
|
|
20
|
+
export declare const NSS_TRUST = "CP,,";
|
|
21
|
+
/** The package managers the install knows, each with how it installs and removes packages. */
|
|
22
|
+
export type PackageManager = 'apt-get' | 'dnf' | 'pacman' | 'zypper';
|
|
23
|
+
/** The commands the install runs that a Linux computer may lack, and the package that has each, by package manager. */
|
|
24
|
+
export declare const TOOLS: Record<'openssl' | 'certutil' | 'nft', Record<PackageManager, string>>;
|
|
25
|
+
export type Tool = keyof typeof TOOLS;
|
|
26
|
+
/** The shell line that installs `packages` with `manager`. An `apt-get` that knows no package yet reads the list of packages first. */
|
|
27
|
+
export declare function installPackagesLine(manager: PackageManager, packages: string[]): string;
|
|
28
|
+
/** The script that installs `packages` with `manager`, and says what the package manager said only when it fails. */
|
|
29
|
+
export declare function installPackagesScript(manager: PackageManager, packages: string[]): string;
|
|
30
|
+
/**
|
|
31
|
+
* The system's own store of trusted certificates, which `curl` and other tools read, where it takes
|
|
32
|
+
* this certificate: Debian's and Ubuntu's. Fedora, Arch and openSUSE build theirs with p11-kit,
|
|
33
|
+
* which keeps out of the bundle tools read any certificate that is no authority, as this one is.
|
|
34
|
+
*/
|
|
35
|
+
export declare const SYSTEM_STORE: {
|
|
36
|
+
file: string;
|
|
37
|
+
refresh: string;
|
|
38
|
+
};
|
|
39
|
+
export type SystemStore = typeof SYSTEM_STORE;
|
|
40
|
+
/** `value` as one word of a systemd unit file; `exec` for a command line, which also reads `$`. */
|
|
41
|
+
export declare function unitWord(value: string, opts?: {
|
|
42
|
+
exec?: boolean;
|
|
43
|
+
}): string;
|
|
44
|
+
/**
|
|
45
|
+
* The person's service that runs the dashboard from login on, in their home folder. It runs with
|
|
46
|
+
* the variables of the install's terminal it needs (`vars`): a service's own `PATH` finds no `git`,
|
|
47
|
+
* `gh` or coding agent the person installed in their home, and a moved config folder holds the
|
|
48
|
+
* registry and the certificate. Started again only when it fails: a dashboard that ends well (one
|
|
49
|
+
* ran on its port already, and it handed over) stays ended.
|
|
50
|
+
*/
|
|
51
|
+
export declare function dashboardUnit(opts: {
|
|
52
|
+
node: string;
|
|
53
|
+
dashboard: string;
|
|
54
|
+
vars: {
|
|
55
|
+
[name: string]: string;
|
|
56
|
+
};
|
|
57
|
+
}): string;
|
|
58
|
+
/** The nftables commands that send the address's port 443 to the dashboard's secure port, however often they run. */
|
|
59
|
+
export declare function portRule(port?: number): string;
|
|
60
|
+
/**
|
|
61
|
+
* The system's service that loads the port rule at each start of the computer, and takes it off
|
|
62
|
+
* when stopped. It loads after the firewall's own rules, which may clear every rule first, and
|
|
63
|
+
* again whenever they are loaded again, or started after a stop.
|
|
64
|
+
*/
|
|
65
|
+
export declare function portUnit(): string;
|
|
66
|
+
/** The install's script as the administrator: the hosts line, the port rule's service, started now, and the certificate in the system's store. */
|
|
67
|
+
export declare function adminInstallScript(certFile: string, store: SystemStore | undefined, name?: string): string;
|
|
68
|
+
/** The uninstall's script as the administrator: everything {@link adminInstallScript} put there, taken off. */
|
|
69
|
+
export declare function adminUninstallScript(store: SystemStore | undefined): string;
|
|
70
|
+
/**
|
|
71
|
+
* The browsers' certificate stores in `home`: Chrome's and Chromium's, which they share, the one
|
|
72
|
+
* of Chromium installed as a snap, and one per Firefox profile, wherever Firefox was installed
|
|
73
|
+
* from. `withChrome` counts Chrome's in even before Chrome made it.
|
|
74
|
+
*/
|
|
75
|
+
export declare function certificateStores(home: string, opts: {
|
|
76
|
+
withChrome: boolean;
|
|
77
|
+
}): Promise<string[]>;
|
|
78
|
+
export declare const linux: Platform;
|
|
79
|
+
//# sourceMappingURL=linux.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linux.d.ts","sourceRoot":"","sources":["../src/linux.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAG7C;;;GAGG;AAEH,iFAAiF;AACjF,eAAO,MAAM,cAAc,gCAAgC,CAAA;AAC3D,0HAA0H;AAC1H,eAAO,MAAM,SAAS,2BAA2B,CAAA;AACjD,eAAO,MAAM,cAAc,+CAAqC,CAAA;AAChE,kGAAkG;AAClG,eAAO,MAAM,UAAU,iBAAiB,CAAA;AAExC,6GAA6G;AAC7G,eAAO,MAAM,YAAY,gCAA2B,CAAA;AACpD;;;;GAIG;AACH,eAAO,MAAM,SAAS,SAAS,CAAA;AAE/B,8FAA8F;AAC9F,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAA;AAepE,uHAAuH;AACvH,eAAO,MAAM,KAAK,EAAE,MAAM,CAAC,SAAS,GAAG,UAAU,GAAG,KAAK,EAAE,MAAM,CAAC,cAAc,EAAE,MAAM,CAAC,CAIxF,CAAA;AACD,MAAM,MAAM,IAAI,GAAG,MAAM,OAAO,KAAK,CAAA;AAErC,uIAAuI;AACvI,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAGvF;AAED,qHAAqH;AACrH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAKzF;AAED;;;;GAIG;AACH,eAAO,MAAM,YAAY;IAAK,IAAI;IAAqD,OAAO;CAA4B,CAAA;AAC1H,MAAM,MAAM,WAAW,GAAG,OAAO,YAAY,CAAA;AAM7C,mGAAmG;AACnG,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,MAAM,CAI7E;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE;QAAE,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAA;CAAE,GAAG,MAAM,CAejH;AAED,qHAAqH;AACrH,wBAAgB,QAAQ,CAAC,IAAI,GAAE,MAAoB,GAAG,MAAM,CAO3D;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,IAAI,MAAM,CAejC;AAED,kJAAkJ;AAClJ,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,SAAS,EAAE,IAAI,GAAE,MAAgB,GAAG,MAAM,CASnH;AAED,+GAA+G;AAC/G,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,WAAW,GAAG,SAAS,GAAG,MAAM,CAM3E;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;IAAE,UAAU,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CActG;AAqCD,eAAO,MAAM,KAAK,EAAE,QAkFnB,CAAA"}
|
package/dist/linux.js
ADDED
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { mkdir, readFile, readdir, rm, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { homedir, release } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { SECURE_PORT } from '@openagt/dashboard/secure-address';
|
|
6
|
+
import { ADDRESS, LOOPBACK_ADDRESS, addHostsLine, quoted, removeHostsLine } from './address.js';
|
|
7
|
+
import { installed, run, succeeds } from './run.js';
|
|
8
|
+
/**
|
|
9
|
+
* What the install puts on a Linux computer. Its files and its scripts as the administrator are
|
|
10
|
+
* text, made by pure functions a test reads; {@link linux} writes and runs them.
|
|
11
|
+
*/
|
|
12
|
+
/** What starts the dashboard at login: a systemd service of the person's own. */
|
|
13
|
+
export const DASHBOARD_UNIT = 'openagent-dashboard.service';
|
|
14
|
+
/** What sends the address's port 443 to the dashboard at every start of the computer: a systemd service, the system's. */
|
|
15
|
+
export const PORT_UNIT = 'openagent-port.service';
|
|
16
|
+
export const PORT_UNIT_FILE = `/etc/systemd/system/${PORT_UNIT}`;
|
|
17
|
+
/** The nftables table the port rule is in, of its own, so taking it off touches no other rule. */
|
|
18
|
+
export const PORT_TABLE = 'ip openagent';
|
|
19
|
+
/** The certificate's name in the browsers' certificate stores, which is how the uninstall finds it again. */
|
|
20
|
+
export const NSS_NICKNAME = `OpenAgent (${ADDRESS})`;
|
|
21
|
+
/**
|
|
22
|
+
* How the browsers trust it: as a server (`P`), which Chrome asks for, and as its own authority
|
|
23
|
+
* (`C`), which Firefox asks for of a certificate that signs itself. It still signs no other: it
|
|
24
|
+
* says it is no authority (`CA:FALSE`), and may not sign certificates.
|
|
25
|
+
*/
|
|
26
|
+
export const NSS_TRUST = 'CP,,';
|
|
27
|
+
const INSTALL_PACKAGES = {
|
|
28
|
+
'apt-get': 'DEBIAN_FRONTEND=noninteractive apt-get install -y',
|
|
29
|
+
dnf: 'dnf install -y',
|
|
30
|
+
pacman: 'pacman -S --needed --noconfirm',
|
|
31
|
+
zypper: 'zypper --non-interactive install',
|
|
32
|
+
};
|
|
33
|
+
const REMOVE_PACKAGES = {
|
|
34
|
+
'apt-get': 'apt-get remove',
|
|
35
|
+
dnf: 'dnf remove',
|
|
36
|
+
pacman: 'pacman -R',
|
|
37
|
+
zypper: 'zypper remove',
|
|
38
|
+
};
|
|
39
|
+
/** The commands the install runs that a Linux computer may lack, and the package that has each, by package manager. */
|
|
40
|
+
export const TOOLS = {
|
|
41
|
+
openssl: { 'apt-get': 'openssl', dnf: 'openssl', pacman: 'openssl', zypper: 'openssl' },
|
|
42
|
+
certutil: { 'apt-get': 'libnss3-tools', dnf: 'nss-tools', pacman: 'nss', zypper: 'mozilla-nss-tools' },
|
|
43
|
+
nft: { 'apt-get': 'nftables', dnf: 'nftables', pacman: 'nftables', zypper: 'nftables' },
|
|
44
|
+
};
|
|
45
|
+
/** The shell line that installs `packages` with `manager`. An `apt-get` that knows no package yet reads the list of packages first. */
|
|
46
|
+
export function installPackagesLine(manager, packages) {
|
|
47
|
+
const line = `${INSTALL_PACKAGES[manager]} ${packages.map(quoted).join(' ')}`;
|
|
48
|
+
return manager === 'apt-get' ? `${line} || { apt-get update && ${line}; }` : line;
|
|
49
|
+
}
|
|
50
|
+
/** The script that installs `packages` with `manager`, and says what the package manager said only when it fails. */
|
|
51
|
+
export function installPackagesScript(manager, packages) {
|
|
52
|
+
return `said=$(mktemp)
|
|
53
|
+
if ! { ${installPackagesLine(manager, packages)}; } >"$said" 2>&1; then cat "$said" >&2; rm -f "$said"; exit 1; fi
|
|
54
|
+
rm -f "$said"
|
|
55
|
+
`;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The system's own store of trusted certificates, which `curl` and other tools read, where it takes
|
|
59
|
+
* this certificate: Debian's and Ubuntu's. Fedora, Arch and openSUSE build theirs with p11-kit,
|
|
60
|
+
* which keeps out of the bundle tools read any certificate that is no authority, as this one is.
|
|
61
|
+
*/
|
|
62
|
+
export const SYSTEM_STORE = { file: `/usr/local/share/ca-certificates/${ADDRESS}.crt`, refresh: 'update-ca-certificates' };
|
|
63
|
+
function systemStore() {
|
|
64
|
+
return existsSync(SYSTEM_STORE.file.slice(0, SYSTEM_STORE.file.lastIndexOf('/'))) ? SYSTEM_STORE : undefined;
|
|
65
|
+
}
|
|
66
|
+
/** `value` as one word of a systemd unit file; `exec` for a command line, which also reads `$`. */
|
|
67
|
+
export function unitWord(value, opts = {}) {
|
|
68
|
+
let word = value.replaceAll('\\', '\\\\').replaceAll('"', '\\"').replaceAll('%', '%%');
|
|
69
|
+
if (opts.exec)
|
|
70
|
+
word = word.replaceAll('$', '$$$$');
|
|
71
|
+
return `"${word}"`;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The person's service that runs the dashboard from login on, in their home folder. It runs with
|
|
75
|
+
* the variables of the install's terminal it needs (`vars`): a service's own `PATH` finds no `git`,
|
|
76
|
+
* `gh` or coding agent the person installed in their home, and a moved config folder holds the
|
|
77
|
+
* registry and the certificate. Started again only when it fails: a dashboard that ends well (one
|
|
78
|
+
* ran on its port already, and it handed over) stays ended.
|
|
79
|
+
*/
|
|
80
|
+
export function dashboardUnit(opts) {
|
|
81
|
+
return `[Unit]
|
|
82
|
+
Description=OpenAgent dashboard, at https://${ADDRESS}
|
|
83
|
+
|
|
84
|
+
[Service]
|
|
85
|
+
ExecStart=${unitWord(opts.node, { exec: true })} ${unitWord(opts.dashboard, { exec: true })}
|
|
86
|
+
WorkingDirectory=%h
|
|
87
|
+
${Object.entries(opts.vars)
|
|
88
|
+
.map(([name, value]) => `Environment=${unitWord(`${name}=${value}`)}`)
|
|
89
|
+
.join('\n')}
|
|
90
|
+
Restart=on-failure
|
|
91
|
+
|
|
92
|
+
[Install]
|
|
93
|
+
WantedBy=default.target
|
|
94
|
+
`;
|
|
95
|
+
}
|
|
96
|
+
/** The nftables commands that send the address's port 443 to the dashboard's secure port, however often they run. */
|
|
97
|
+
export function portRule(port = SECURE_PORT) {
|
|
98
|
+
return [
|
|
99
|
+
`add table ${PORT_TABLE}`,
|
|
100
|
+
`flush table ${PORT_TABLE}`,
|
|
101
|
+
`add chain ${PORT_TABLE} output { type nat hook output priority -100 ; }`,
|
|
102
|
+
`add rule ${PORT_TABLE} output ip daddr ${LOOPBACK_ADDRESS} tcp dport 443 redirect to :${port}`,
|
|
103
|
+
].join('; ');
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* The system's service that loads the port rule at each start of the computer, and takes it off
|
|
107
|
+
* when stopped. It loads after the firewall's own rules, which may clear every rule first, and
|
|
108
|
+
* again whenever they are loaded again, or started after a stop.
|
|
109
|
+
*/
|
|
110
|
+
export function portUnit() {
|
|
111
|
+
return `[Unit]
|
|
112
|
+
Description=OpenAgent: port 443 of ${ADDRESS}, to the dashboard
|
|
113
|
+
After=nftables.service firewalld.service
|
|
114
|
+
PartOf=nftables.service
|
|
115
|
+
|
|
116
|
+
[Service]
|
|
117
|
+
Type=oneshot
|
|
118
|
+
RemainAfterExit=yes
|
|
119
|
+
ExecStart=nft ${unitWord(portRule(), { exec: true })}
|
|
120
|
+
ExecStop=nft ${unitWord(`delete table ${PORT_TABLE}`, { exec: true })}
|
|
121
|
+
|
|
122
|
+
[Install]
|
|
123
|
+
WantedBy=multi-user.target nftables.service
|
|
124
|
+
`;
|
|
125
|
+
}
|
|
126
|
+
/** The install's script as the administrator: the hosts line, the port rule's service, started now, and the certificate in the system's store. */
|
|
127
|
+
export function adminInstallScript(certFile, store, name = ADDRESS) {
|
|
128
|
+
return `set -e
|
|
129
|
+
${addHostsLine('/etc/hosts', name)}
|
|
130
|
+
printf '%s' ${quoted(portUnit())} > ${PORT_UNIT_FILE}
|
|
131
|
+
chmod 644 ${PORT_UNIT_FILE}
|
|
132
|
+
systemctl daemon-reload
|
|
133
|
+
systemctl enable ${PORT_UNIT} 2>/dev/null
|
|
134
|
+
systemctl restart ${PORT_UNIT}
|
|
135
|
+
${store ? `install -m 644 ${quoted(certFile)} ${quoted(store.file)}\n${store.refresh} >/dev/null 2>&1\n` : ''}`;
|
|
136
|
+
}
|
|
137
|
+
/** The uninstall's script as the administrator: everything {@link adminInstallScript} put there, taken off. */
|
|
138
|
+
export function adminUninstallScript(store) {
|
|
139
|
+
return `${removeHostsLine('/etc/hosts')}
|
|
140
|
+
systemctl disable --now ${PORT_UNIT} 2>/dev/null || true
|
|
141
|
+
rm -f ${PORT_UNIT_FILE}
|
|
142
|
+
systemctl daemon-reload
|
|
143
|
+
${store ? `if [ -e ${quoted(store.file)} ]; then rm -f ${quoted(store.file)}; ${store.refresh} >/dev/null 2>&1; fi\n` : ''}`;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* The browsers' certificate stores in `home`: Chrome's and Chromium's, which they share, the one
|
|
147
|
+
* of Chromium installed as a snap, and one per Firefox profile, wherever Firefox was installed
|
|
148
|
+
* from. `withChrome` counts Chrome's in even before Chrome made it.
|
|
149
|
+
*/
|
|
150
|
+
export async function certificateStores(home, opts) {
|
|
151
|
+
const chrome = join(home, '.pki', 'nssdb');
|
|
152
|
+
const firefoxes = [
|
|
153
|
+
join(home, '.mozilla', 'firefox'),
|
|
154
|
+
join(home, '.config', 'mozilla', 'firefox'),
|
|
155
|
+
join(home, 'snap', 'firefox', 'common', '.mozilla', 'firefox'),
|
|
156
|
+
join(home, '.var', 'app', 'org.mozilla.firefox', '.mozilla', 'firefox'),
|
|
157
|
+
];
|
|
158
|
+
const candidates = [chrome, join(home, 'snap', 'chromium', 'current', '.pki', 'nssdb')];
|
|
159
|
+
for (const folder of firefoxes) {
|
|
160
|
+
const profiles = await readdir(folder, { withFileTypes: true }).catch(() => []);
|
|
161
|
+
candidates.push(...profiles.filter(entry => entry.isDirectory()).map(entry => join(folder, entry.name)));
|
|
162
|
+
}
|
|
163
|
+
return candidates.filter(store => existsSync(join(store, 'cert9.db')) || (opts.withChrome && store === chrome));
|
|
164
|
+
}
|
|
165
|
+
/** Where the install keeps what it puts in the person's home. */
|
|
166
|
+
function places(env) {
|
|
167
|
+
const home = env.HOME || homedir();
|
|
168
|
+
const app = join(env.XDG_DATA_HOME || join(home, '.local', 'share'), 'openagent');
|
|
169
|
+
return {
|
|
170
|
+
home,
|
|
171
|
+
// systemd's own folder for a person's services, which it reads whatever the terminal's variables say.
|
|
172
|
+
unit: join(home, '.config', 'systemd', 'user', DASHBOARD_UNIT),
|
|
173
|
+
app,
|
|
174
|
+
/** The packages the install put on this computer, which the uninstall leaves, and names. */
|
|
175
|
+
packages: join(app, 'packages.json'),
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
/** The commands the install needs that this computer lacks. */
|
|
179
|
+
async function missingTools(env) {
|
|
180
|
+
const missing = [];
|
|
181
|
+
for (const tool of Object.keys(TOOLS))
|
|
182
|
+
if (!(await installed(tool, env.PATH)))
|
|
183
|
+
missing.push(tool);
|
|
184
|
+
return missing;
|
|
185
|
+
}
|
|
186
|
+
async function packageManager(env) {
|
|
187
|
+
for (const manager of Object.keys(INSTALL_PACKAGES))
|
|
188
|
+
if (await installed(manager, env.PATH))
|
|
189
|
+
return manager;
|
|
190
|
+
return undefined;
|
|
191
|
+
}
|
|
192
|
+
/** What the install says each missing command is for. */
|
|
193
|
+
const FOR = {
|
|
194
|
+
openssl: 'makes the certificate',
|
|
195
|
+
certutil: 'puts the certificate in the browsers',
|
|
196
|
+
nft: 'sends port 443 to the dashboard',
|
|
197
|
+
};
|
|
198
|
+
const user = (args) => ['--user', ...args];
|
|
199
|
+
export const linux = {
|
|
200
|
+
async unable(env) {
|
|
201
|
+
if (release().toLowerCase().includes('microsoft')) {
|
|
202
|
+
return 'Your browsers run on Windows, which this Linux cannot set up. Run `npx @openagt/dashboard` instead.';
|
|
203
|
+
}
|
|
204
|
+
if (!(await succeeds('systemctl', user(['show-environment'])))) {
|
|
205
|
+
return 'This computer runs no systemd for you, which starts the dashboard when you log in. Run `npx @openagt/dashboard` instead.';
|
|
206
|
+
}
|
|
207
|
+
const missing = await missingTools(env);
|
|
208
|
+
if (missing.length > 0 && !(await packageManager(env))) {
|
|
209
|
+
return `Install the commands ${missing.join(', ')} (${missing.map(tool => TOOLS[tool]['apt-get']).join(', ')} on Debian), then run this again.`;
|
|
210
|
+
}
|
|
211
|
+
return undefined;
|
|
212
|
+
},
|
|
213
|
+
async stopDashboard() {
|
|
214
|
+
if (!(await succeeds('systemctl', user(['is-active', '--quiet', DASHBOARD_UNIT]))))
|
|
215
|
+
return false;
|
|
216
|
+
await run('systemctl', user(['stop', DASHBOARD_UNIT]));
|
|
217
|
+
return true;
|
|
218
|
+
},
|
|
219
|
+
appDir: env => places(env).app,
|
|
220
|
+
async prepare(io, env) {
|
|
221
|
+
const missing = await missingTools(env);
|
|
222
|
+
const manager = await packageManager(env);
|
|
223
|
+
if (missing.length === 0 || !manager)
|
|
224
|
+
return;
|
|
225
|
+
const packages = missing.map(tool => TOOLS[tool][manager]);
|
|
226
|
+
io.out(`◆ your password as the administrator: ${packages.join(', ')} ${packages.length === 1 ? 'is' : 'are'} installed (${missing.map(tool => `${tool}, which ${FOR[tool]}`).join('; ')}).`);
|
|
227
|
+
await run('sudo', ['/bin/sh', '-c', installPackagesScript(manager, packages)], { interactive: true });
|
|
228
|
+
const place = places(env);
|
|
229
|
+
const before = await readPackages(place.packages);
|
|
230
|
+
await mkdir(place.app, { recursive: true });
|
|
231
|
+
await writeFile(place.packages, JSON.stringify({ manager, packages: [...new Set([...before.packages, ...packages])] }) + '\n');
|
|
232
|
+
},
|
|
233
|
+
adminInstall(certFile) {
|
|
234
|
+
const store = systemStore();
|
|
235
|
+
return {
|
|
236
|
+
says: `your password as the administrator: ${ADDRESS} is pointed at this computer (/etc/hosts), and its port 443 at the dashboard (an nftables rule, loaded at each start)${store ? '; the system trusts its certificate, for curl and other tools' : ''}.`,
|
|
237
|
+
script: adminInstallScript(certFile, store),
|
|
238
|
+
};
|
|
239
|
+
},
|
|
240
|
+
async trust(certFile, io, env) {
|
|
241
|
+
const stores = await certificateStores(places(env).home, { withChrome: true });
|
|
242
|
+
for (const store of stores) {
|
|
243
|
+
if (!existsSync(join(store, 'cert9.db'))) {
|
|
244
|
+
await mkdir(store, { recursive: true, mode: 0o700 });
|
|
245
|
+
await run('certutil', ['-N', '-d', `sql:${store}`, '--empty-password']);
|
|
246
|
+
}
|
|
247
|
+
// One made by an install before, for a certificate since made again, goes first.
|
|
248
|
+
await run('certutil', ['-D', '-d', `sql:${store}`, '-n', NSS_NICKNAME]).catch(() => { });
|
|
249
|
+
await run('certutil', ['-A', '-d', `sql:${store}`, '-n', NSS_NICKNAME, '-t', NSS_TRUST, '-i', certFile]);
|
|
250
|
+
}
|
|
251
|
+
io.out(`◆ Chrome and Firefox trust the certificate (${stores.length} certificate store${stores.length === 1 ? '' : 's'}). A Firefox profile made later: run this again.`);
|
|
252
|
+
},
|
|
253
|
+
async startDashboard(opts, env) {
|
|
254
|
+
const place = places(env);
|
|
255
|
+
await mkdir(join(place.unit, '..'), { recursive: true });
|
|
256
|
+
await writeFile(place.unit, dashboardUnit(opts));
|
|
257
|
+
await run('systemctl', user(['daemon-reload']));
|
|
258
|
+
await run('systemctl', user(['enable', DASHBOARD_UNIT]));
|
|
259
|
+
await run('systemctl', user(['restart', DASHBOARD_UNIT]));
|
|
260
|
+
return `\`journalctl --user -u ${DASHBOARD_UNIT}\``;
|
|
261
|
+
},
|
|
262
|
+
openCommand: 'xdg-open',
|
|
263
|
+
async removeDashboard(env) {
|
|
264
|
+
await run('systemctl', user(['disable', '--now', DASHBOARD_UNIT])).catch(() => { });
|
|
265
|
+
await rm(places(env).unit, { force: true });
|
|
266
|
+
await run('systemctl', user(['daemon-reload'])).catch(() => { });
|
|
267
|
+
},
|
|
268
|
+
async untrust(_certFile, _io, env) {
|
|
269
|
+
for (const store of await certificateStores(places(env).home, { withChrome: false })) {
|
|
270
|
+
await run('certutil', ['-D', '-d', `sql:${store}`, '-n', NSS_NICKNAME]).catch(() => { });
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
adminUninstall: () => ({
|
|
274
|
+
says: `your password as the administrator, once: the hosts line for ${ADDRESS} and its port rule are taken off${systemStore() ? ', and the system trusts its certificate no more' : ''}.`,
|
|
275
|
+
script: adminUninstallScript(systemStore()),
|
|
276
|
+
}),
|
|
277
|
+
folders: env => [places(env).app],
|
|
278
|
+
async leftBehind(env) {
|
|
279
|
+
const { manager, packages } = await readPackages(places(env).packages);
|
|
280
|
+
if (!manager || packages.length === 0)
|
|
281
|
+
return undefined;
|
|
282
|
+
return `${packages.join(', ')} ${packages.length === 1 ? 'stays' : 'stay'} installed, as other programs may use ${packages.length === 1 ? 'it' : 'them'}: \`sudo ${REMOVE_PACKAGES[manager]} ${packages.join(' ')}\` takes ${packages.length === 1 ? 'it' : 'them'} off.`;
|
|
283
|
+
},
|
|
284
|
+
};
|
|
285
|
+
async function readPackages(file) {
|
|
286
|
+
const text = await readFile(file, 'utf8').catch(() => undefined);
|
|
287
|
+
return text === undefined ? { packages: [] } : JSON.parse(text);
|
|
288
|
+
}
|
|
289
|
+
//# sourceMappingURL=linux.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linux.js","sourceRoot":"","sources":["../src/linux.ts"],"names":[],"mappings":"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"}
|
package/dist/mac.d.ts
CHANGED
|
@@ -1,18 +1,8 @@
|
|
|
1
|
+
import type { Platform } from './platform.js';
|
|
1
2
|
/**
|
|
2
|
-
* What the install puts on a Mac
|
|
3
|
-
*
|
|
3
|
+
* What the install puts on a Mac. Its files and its script as the administrator are text, made by
|
|
4
|
+
* pure functions a test reads; {@link mac} writes and runs them.
|
|
4
5
|
*/
|
|
5
|
-
/**
|
|
6
|
-
* The dashboard's secure address: the website's own name, which this computer then answers
|
|
7
|
-
* itself, the dashboard with the website's copy beside it (#1919).
|
|
8
|
-
*/
|
|
9
|
-
export declare const ADDRESS = "openagent.build";
|
|
10
|
-
/**
|
|
11
|
-
* The address the name points at: one of this computer's own, the address's alone. The port rule
|
|
12
|
-
* then touches nothing else this computer sends itself on port 443 (a container a developer
|
|
13
|
-
* publishes there, say), as a rule for `127.0.0.1` would.
|
|
14
|
-
*/
|
|
15
|
-
export declare const LOOPBACK_ADDRESS = "127.0.0.42";
|
|
16
6
|
/** What starts the dashboard at login: a launch agent of the person's own. */
|
|
17
7
|
export declare const DASHBOARD_LABEL = "build.openagent.dashboard";
|
|
18
8
|
/** What sends the address's port 443 to the dashboard at every start of the Mac: a launch daemon, the system's. */
|
|
@@ -24,8 +14,6 @@ export declare const PORT_PLIST = "/Library/LaunchDaemons/build.openagent.port.p
|
|
|
24
14
|
*/
|
|
25
15
|
export declare const PORT_ANCHOR = "com.apple/openagent";
|
|
26
16
|
export declare const PORT_RULE_FILE = "/etc/pf.anchors/build.openagent";
|
|
27
|
-
/** The end of the hosts line the install adds, which is how the uninstall finds it again. */
|
|
28
|
-
export declare const HOSTS_MARK = "# OpenAgent";
|
|
29
17
|
/** One value in a launchd property list. */
|
|
30
18
|
type PlistValue = string | boolean | PlistValue[] | {
|
|
31
19
|
[key: string]: PlistValue;
|
|
@@ -58,19 +46,10 @@ export declare function portRule(port?: number): string;
|
|
|
58
46
|
* its own until told more.
|
|
59
47
|
*/
|
|
60
48
|
export declare function portPlist(): string;
|
|
61
|
-
/** `value` as one word of a shell script, whatever it holds. */
|
|
62
|
-
export declare function quoted(value: string): string;
|
|
63
|
-
/** Shell lines that take the install's line out of the hosts file `file`, and leave the rest as it was. */
|
|
64
|
-
export declare function removeHostsLine(file: string): string;
|
|
65
|
-
/** Shell lines that point `name` at this computer in the hosts file `file`, once, however often they run. */
|
|
66
|
-
export declare function addHostsLine(file: string, name: string): string;
|
|
67
49
|
/** The install's one script as the administrator: the hosts line, and the port rule with its launch daemon, started now. */
|
|
68
50
|
export declare function adminInstallScript(name?: string): string;
|
|
69
51
|
/** The uninstall's one script as the administrator: everything {@link adminInstallScript} put there, taken off. */
|
|
70
52
|
export declare function adminUninstallScript(): string;
|
|
71
|
-
|
|
72
|
-
export declare function certificateConfig(name: string): string;
|
|
73
|
-
/** The longest a certificate may last for Safari and macOS: 825 days. */
|
|
74
|
-
export declare const CERTIFICATE_DAYS = 825;
|
|
53
|
+
export declare const mac: Platform;
|
|
75
54
|
export {};
|
|
76
55
|
//# sourceMappingURL=mac.d.ts.map
|
package/dist/mac.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mac.d.ts","sourceRoot":"","sources":["../src/mac.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mac.d.ts","sourceRoot":"","sources":["../src/mac.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAG7C;;;GAGG;AAEH,8EAA8E;AAC9E,eAAO,MAAM,eAAe,8BAA8B,CAAA;AAC1D,mHAAmH;AACnH,eAAO,MAAM,UAAU,yBAAyB,CAAA;AAChD,eAAO,MAAM,UAAU,sDAA+C,CAAA;AACtE;;;GAGG;AACH,eAAO,MAAM,WAAW,wBAAwB,CAAA;AAChD,eAAO,MAAM,cAAc,oCAAoC,CAAA;AAE/D,4CAA4C;AAC5C,KAAK,UAAU,GAAG,MAAM,GAAG,OAAO,GAAG,UAAU,EAAE,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAAA;CAAE,CAAA;AAajF,8CAA8C;AAC9C,wBAAgB,KAAK,CAAC,IAAI,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAAA;CAAE,GAAG,MAAM,CAOjE;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE;QAAE,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAW5I;AAED,iFAAiF;AACjF,wBAAgB,QAAQ,CAAC,IAAI,GAAE,MAAoB,GAAG,MAAM,CAE3D;AAED;;;;GAIG;AACH,wBAAgB,SAAS,IAAI,MAAM,CAMlC;AAKD,4HAA4H;AAC5H,wBAAgB,kBAAkB,CAAC,IAAI,GAAE,MAAgB,GAAG,MAAM,CAWjE;AAED,mHAAmH;AACnH,wBAAgB,oBAAoB,IAAI,MAAM,CAQ7C;AAgBD,eAAO,MAAM,GAAG,EAAE,QA2CjB,CAAA"}
|
package/dist/mac.js
CHANGED
|
@@ -1,19 +1,14 @@
|
|
|
1
|
+
import { X509Certificate } from 'node:crypto';
|
|
2
|
+
import { mkdir, readFile, rm, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { dirname, join } from 'node:path';
|
|
1
5
|
import { SECURE_PORT } from '@openagt/dashboard/secure-address';
|
|
6
|
+
import { ADDRESS, LOOPBACK_ADDRESS, addHostsLine, quoted, removeHostsLine } from './address.js';
|
|
7
|
+
import { run, succeeds } from './run.js';
|
|
2
8
|
/**
|
|
3
|
-
* What the install puts on a Mac
|
|
4
|
-
*
|
|
9
|
+
* What the install puts on a Mac. Its files and its script as the administrator are text, made by
|
|
10
|
+
* pure functions a test reads; {@link mac} writes and runs them.
|
|
5
11
|
*/
|
|
6
|
-
/**
|
|
7
|
-
* The dashboard's secure address: the website's own name, which this computer then answers
|
|
8
|
-
* itself, the dashboard with the website's copy beside it (#1919).
|
|
9
|
-
*/
|
|
10
|
-
export const ADDRESS = 'openagent.build';
|
|
11
|
-
/**
|
|
12
|
-
* The address the name points at: one of this computer's own, the address's alone. The port rule
|
|
13
|
-
* then touches nothing else this computer sends itself on port 443 (a container a developer
|
|
14
|
-
* publishes there, say), as a rule for `127.0.0.1` would.
|
|
15
|
-
*/
|
|
16
|
-
export const LOOPBACK_ADDRESS = '127.0.0.42';
|
|
17
12
|
/** What starts the dashboard at login: a launch agent of the person's own. */
|
|
18
13
|
export const DASHBOARD_LABEL = 'build.openagent.dashboard';
|
|
19
14
|
/** What sends the address's port 443 to the dashboard at every start of the Mac: a launch daemon, the system's. */
|
|
@@ -25,8 +20,6 @@ export const PORT_PLIST = `/Library/LaunchDaemons/${PORT_LABEL}.plist`;
|
|
|
25
20
|
*/
|
|
26
21
|
export const PORT_ANCHOR = 'com.apple/openagent';
|
|
27
22
|
export const PORT_RULE_FILE = '/etc/pf.anchors/build.openagent';
|
|
28
|
-
/** The end of the hosts line the install adds, which is how the uninstall finds it again. */
|
|
29
|
-
export const HOSTS_MARK = '# OpenAgent';
|
|
30
23
|
function escapeXml(text) {
|
|
31
24
|
return text.replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>');
|
|
32
25
|
}
|
|
@@ -83,23 +76,6 @@ export function portPlist() {
|
|
|
83
76
|
RunAtLoad: true,
|
|
84
77
|
});
|
|
85
78
|
}
|
|
86
|
-
/** `value` as one word of a shell script, whatever it holds. */
|
|
87
|
-
export function quoted(value) {
|
|
88
|
-
return `'${value.replaceAll("'", `'\\''`)}'`;
|
|
89
|
-
}
|
|
90
|
-
/** Shell lines that take the install's line out of the hosts file `file`, and leave the rest as it was. */
|
|
91
|
-
export function removeHostsLine(file) {
|
|
92
|
-
return `if grep -q ${quoted(` ${HOSTS_MARK}$`)} ${quoted(file)}; then sed -i '' ${quoted(`/ ${HOSTS_MARK}$/d`)} ${quoted(file)}; fi`;
|
|
93
|
-
}
|
|
94
|
-
/** Shell lines that point `name` at this computer in the hosts file `file`, once, however often they run. */
|
|
95
|
-
export function addHostsLine(file, name) {
|
|
96
|
-
return [
|
|
97
|
-
removeHostsLine(file),
|
|
98
|
-
// A file that does not end its last line would have this one joined to it.
|
|
99
|
-
`if [ -s ${quoted(file)} ] && [ -n "$(tail -c 1 ${quoted(file)})" ]; then echo >> ${quoted(file)}; fi`,
|
|
100
|
-
`printf '%s\\n' ${quoted(`${LOOPBACK_ADDRESS} ${name} ${HOSTS_MARK}`)} >> ${quoted(file)}`,
|
|
101
|
-
].join('\n');
|
|
102
|
-
}
|
|
103
79
|
/** Forget what the Mac remembers of names, so the hosts line counts at once. */
|
|
104
80
|
const FORGET_NAMES = 'dscacheutil -flushcache; killall -HUP mDNSResponder 2>/dev/null || true';
|
|
105
81
|
/** The install's one script as the administrator: the hosts line, and the port rule with its launch daemon, started now. */
|
|
@@ -125,20 +101,62 @@ rm -f ${PORT_RULE_FILE} ${PORT_PLIST}
|
|
|
125
101
|
${FORGET_NAMES}
|
|
126
102
|
`;
|
|
127
103
|
}
|
|
128
|
-
/**
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
keyUsage = critical, digitalSignature, keyEncipherment
|
|
139
|
-
extendedKeyUsage = serverAuth
|
|
140
|
-
`;
|
|
104
|
+
/** Where the install keeps what it puts on this Mac, outside the secure address's own folder. */
|
|
105
|
+
function places(env) {
|
|
106
|
+
const home = env.HOME || homedir();
|
|
107
|
+
return {
|
|
108
|
+
home,
|
|
109
|
+
agent: join(home, 'Library', 'LaunchAgents', `${DASHBOARD_LABEL}.plist`),
|
|
110
|
+
logs: join(home, 'Library', 'Logs', 'OpenAgent'),
|
|
111
|
+
app: join(home, 'Library', 'Application Support', 'OpenAgent'),
|
|
112
|
+
keychain: join(home, 'Library', 'Keychains', 'login.keychain-db'),
|
|
113
|
+
};
|
|
141
114
|
}
|
|
142
|
-
|
|
143
|
-
export const
|
|
115
|
+
const uid = () => process.getuid?.() ?? 0;
|
|
116
|
+
export const mac = {
|
|
117
|
+
unable: async () => undefined,
|
|
118
|
+
stopDashboard: () => succeeds('launchctl', ['bootout', `gui/${uid()}/${DASHBOARD_LABEL}`]),
|
|
119
|
+
appDir: env => places(env).app,
|
|
120
|
+
prepare: async () => { },
|
|
121
|
+
adminInstall: () => ({
|
|
122
|
+
says: `your password as the administrator, once: ${ADDRESS} is pointed at this Mac (/etc/hosts), and its port 443 at the dashboard (a packet filter rule).`,
|
|
123
|
+
script: adminInstallScript(ADDRESS),
|
|
124
|
+
}),
|
|
125
|
+
async trust(certFile, io, env) {
|
|
126
|
+
// Trusted already, by an install before: macOS asks nothing.
|
|
127
|
+
if (await succeeds('security', ['verify-cert', '-c', certFile, '-p', 'ssl', '-s', ADDRESS, '-q']))
|
|
128
|
+
return;
|
|
129
|
+
io.out(`◆ a certificate for ${ADDRESS} was made on this Mac. macOS asks for your password to trust it.`);
|
|
130
|
+
await run('security', ['add-trusted-cert', '-r', 'trustRoot', '-p', 'ssl', '-k', places(env).keychain, certFile]);
|
|
131
|
+
},
|
|
132
|
+
async startDashboard({ node, dashboard, vars }, env) {
|
|
133
|
+
const place = places(env);
|
|
134
|
+
await mkdir(place.logs, { recursive: true });
|
|
135
|
+
await mkdir(dirname(place.agent), { recursive: true });
|
|
136
|
+
const log = join(place.logs, 'dashboard.log');
|
|
137
|
+
await writeFile(place.agent, dashboardPlist({ node, dashboard, home: place.home, env: vars, log }));
|
|
138
|
+
await run('launchctl', ['bootstrap', `gui/${uid()}`, place.agent]);
|
|
139
|
+
return log;
|
|
140
|
+
},
|
|
141
|
+
openCommand: 'open',
|
|
142
|
+
async removeDashboard(env) {
|
|
143
|
+
await run('launchctl', ['bootout', `gui/${uid()}/${DASHBOARD_LABEL}`]).catch(() => { });
|
|
144
|
+
await rm(places(env).agent, { force: true });
|
|
145
|
+
},
|
|
146
|
+
async untrust(certFile, io, env) {
|
|
147
|
+
const pem = await readFile(certFile, 'utf8').catch(() => undefined);
|
|
148
|
+
if (pem === undefined)
|
|
149
|
+
return;
|
|
150
|
+
io.out('◆ macOS asks for your password to stop trusting the certificate.');
|
|
151
|
+
await run('security', ['remove-trusted-cert', certFile]).catch(() => { });
|
|
152
|
+
const sha1 = new X509Certificate(pem).fingerprint.replaceAll(':', '');
|
|
153
|
+
await run('security', ['delete-certificate', '-Z', sha1, places(env).keychain]).catch(() => { });
|
|
154
|
+
},
|
|
155
|
+
adminUninstall: () => ({
|
|
156
|
+
says: `your password as the administrator, once: the hosts line for ${ADDRESS} and its port rule are taken off.`,
|
|
157
|
+
script: adminUninstallScript(),
|
|
158
|
+
}),
|
|
159
|
+
folders: env => [places(env).app, places(env).logs],
|
|
160
|
+
leftBehind: async () => undefined,
|
|
161
|
+
};
|
|
144
162
|
//# sourceMappingURL=mac.js.map
|
package/dist/mac.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mac.js","sourceRoot":"","sources":["../src/mac.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"mac.js","sourceRoot":"","sources":["../src/mac.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/** Where the commands write. */
|
|
2
|
+
export interface InstallIO {
|
|
3
|
+
out: (line: string) => void;
|
|
4
|
+
err: (line: string) => void;
|
|
5
|
+
}
|
|
6
|
+
/** A step run as the administrator: what it is said to do before the password, and its shell script. */
|
|
7
|
+
export interface AdminStep {
|
|
8
|
+
says: string;
|
|
9
|
+
script: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* What the install does its own way on each kind of computer. {@link install} and
|
|
13
|
+
* {@link uninstall} run the same steps everywhere, each through one of these.
|
|
14
|
+
*/
|
|
15
|
+
export interface Platform {
|
|
16
|
+
/** Why OpenAgent cannot be installed on this computer, or `undefined`. Asked before anything changes. */
|
|
17
|
+
unable(env: NodeJS.ProcessEnv): Promise<string | undefined>;
|
|
18
|
+
/** The installed dashboard stopped, when it runs; whether one did. */
|
|
19
|
+
stopDashboard(env: NodeJS.ProcessEnv): Promise<boolean>;
|
|
20
|
+
/** The folder of OpenAgent's own the dashboard is installed in, when the command came by `npx`. */
|
|
21
|
+
appDir(env: NodeJS.ProcessEnv): string;
|
|
22
|
+
/** Before the certificate is made: the commands the install needs, put on this computer. */
|
|
23
|
+
prepare(io: InstallIO, env: NodeJS.ProcessEnv): Promise<void>;
|
|
24
|
+
/** The install's step as the administrator, for the certificate in `certFile`. */
|
|
25
|
+
adminInstall(certFile: string): AdminStep;
|
|
26
|
+
/** The browsers made to trust the certificate in `certFile`. */
|
|
27
|
+
trust(certFile: string, io: InstallIO, env: NodeJS.ProcessEnv): Promise<void>;
|
|
28
|
+
/** The dashboard started now and at each login, from `node` and its `dashboard` file, with `vars`; says where its output is read. */
|
|
29
|
+
startDashboard(opts: {
|
|
30
|
+
node: string;
|
|
31
|
+
dashboard: string;
|
|
32
|
+
vars: {
|
|
33
|
+
[name: string]: string;
|
|
34
|
+
};
|
|
35
|
+
}, env: NodeJS.ProcessEnv): Promise<string>;
|
|
36
|
+
/** The command that opens an address in the person's browser. */
|
|
37
|
+
openCommand: string;
|
|
38
|
+
/** The dashboard stopped, and no more started at login. */
|
|
39
|
+
removeDashboard(env: NodeJS.ProcessEnv): Promise<void>;
|
|
40
|
+
/** The browsers made to stop trusting the certificate in `certFile`. */
|
|
41
|
+
untrust(certFile: string, io: InstallIO, env: NodeJS.ProcessEnv): Promise<void>;
|
|
42
|
+
/** The uninstall's step as the administrator: everything {@link adminInstall} put there, taken off. */
|
|
43
|
+
adminUninstall(): AdminStep;
|
|
44
|
+
/** The folders the install made, beside the certificate's. */
|
|
45
|
+
folders(env: NodeJS.ProcessEnv): string[];
|
|
46
|
+
/** What the uninstall leaves on purpose, said once it is done; read before {@link folders} are removed. */
|
|
47
|
+
leftBehind(env: NodeJS.ProcessEnv): Promise<string | undefined>;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=platform.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC3B,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CAC5B;AAED,wGAAwG;AACxG,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,yGAAyG;IACzG,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;IAC3D,sEAAsE;IACtE,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IACvD,mGAAmG;IACnG,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAAA;IACtC,4FAA4F;IAC5F,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC7D,kFAAkF;IAClF,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAA;IACzC,gEAAgE;IAChE,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC7E,qIAAqI;IACrI,cAAc,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE;YAAE,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;SAAE,CAAA;KAAE,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACpI,iEAAiE;IACjE,WAAW,EAAE,MAAM,CAAA;IACnB,2DAA2D;IAC3D,eAAe,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACtD,wEAAwE;IACxE,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/E,uGAAuG;IACvG,cAAc,IAAI,SAAS,CAAA;IAC3B,8DAA8D;IAC9D,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,EAAE,CAAA;IACzC,2GAA2G;IAC3G,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;CAChE"}
|
package/dist/platform.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform.js","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":""}
|
package/dist/run.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Run a command to its end; rejects with what it said when it fails. `interactive` gives it this terminal, for a password. */
|
|
2
|
+
export declare function run(command: string, args: string[], opts?: {
|
|
3
|
+
interactive?: boolean;
|
|
4
|
+
}): Promise<void>;
|
|
5
|
+
/** Whether `command` runs to its end without failing. */
|
|
6
|
+
export declare function succeeds(command: string, args: string[]): Promise<boolean>;
|
|
7
|
+
/**
|
|
8
|
+
* Whether `command` is on this computer: in `PATH`, or in a folder of the administrator's
|
|
9
|
+
* commands, which a person's own `PATH` may leave out (`nft` is in `/usr/sbin`).
|
|
10
|
+
*/
|
|
11
|
+
export declare function installed(command: string, path: string | undefined): Promise<boolean>;
|
|
12
|
+
//# sourceMappingURL=run.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAIA,+HAA+H;AAC/H,wBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,GAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAWxG;AAED,yDAAyD;AACzD,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAK1E;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,CAM3F"}
|
package/dist/run.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { execFile, spawn } from 'node:child_process';
|
|
2
|
+
import { access, constants } from 'node:fs/promises';
|
|
3
|
+
import { delimiter, join } from 'node:path';
|
|
4
|
+
/** Run a command to its end; rejects with what it said when it fails. `interactive` gives it this terminal, for a password. */
|
|
5
|
+
export function run(command, args, opts = {}) {
|
|
6
|
+
if (opts.interactive) {
|
|
7
|
+
return new Promise((resolvePromise, rejectPromise) => {
|
|
8
|
+
spawn(command, args, { stdio: 'inherit' })
|
|
9
|
+
.on('error', rejectPromise)
|
|
10
|
+
.on('exit', code => (code === 0 ? resolvePromise() : rejectPromise(new Error(`${command} ended with ${code}`))));
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
return new Promise((resolvePromise, rejectPromise) => {
|
|
14
|
+
execFile(command, args, (error, _stdout, stderr) => (error ? rejectPromise(new Error(String(stderr).trim() || error.message)) : resolvePromise()));
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
/** Whether `command` runs to its end without failing. */
|
|
18
|
+
export function succeeds(command, args) {
|
|
19
|
+
return run(command, args).then(() => true, () => false);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Whether `command` is on this computer: in `PATH`, or in a folder of the administrator's
|
|
23
|
+
* commands, which a person's own `PATH` may leave out (`nft` is in `/usr/sbin`).
|
|
24
|
+
*/
|
|
25
|
+
export async function installed(command, path) {
|
|
26
|
+
const folders = [...(path ?? '').split(delimiter).filter(Boolean), '/usr/local/sbin', '/usr/sbin', '/sbin'];
|
|
27
|
+
for (const folder of folders) {
|
|
28
|
+
if (await access(join(folder, command), constants.X_OK).then(() => true, () => false))
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=run.js.map
|
package/dist/run.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA;AACpD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACpD,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAE3C,+HAA+H;AAC/H,MAAM,UAAU,GAAG,CAAC,OAAe,EAAE,IAAc,EAAE,IAAI,GAA8B,EAAE;IACvF,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;QACrB,OAAO,IAAI,OAAO,CAAC,CAAC,cAAc,EAAE,aAAa,EAAE,EAAE;YACnD,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;iBACvC,EAAE,CAAC,OAAO,EAAE,aAAa,CAAC;iBAC1B,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,GAAG,OAAO,eAAe,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;QACpH,CAAC,CAAC,CAAA;IACJ,CAAC;IACD,OAAO,IAAI,OAAO,CAAC,CAAC,cAAc,EAAE,aAAa,EAAE,EAAE;QACnD,QAAQ,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc,EAAE,CAAC,CAAC,CAAA;IACpJ,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,QAAQ,CAAC,OAAe,EAAE,IAAc;IACtD,OAAO,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,IAAI,CAC5B,GAAG,EAAE,CAAC,IAAI,EACV,GAAG,EAAE,CAAC,KAAK,CACZ,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAe,EAAE,IAAwB;IACvE,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,iBAAiB,EAAE,WAAW,EAAE,OAAO,CAAC,CAAA;IAC3G,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC;YAAE,OAAO,IAAI,CAAA;IACpG,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openagt/install",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Install OpenAgent on this computer: the dashboard starts when you log in, at https://openagent.build, which this computer then answers itself. `npx @openagt/uninstall` takes it all off again.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"./package.json": "./package.json"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@openagt/dashboard": "0.
|
|
32
|
+
"@openagt/dashboard": "0.56.0"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@types/node": "^20.0.0",
|