@hydra-acp/browser 0.1.26 → 0.1.28
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/README.md +49 -33
- package/dist/hydra/client.js +24 -1
- package/dist/hydra/client.js.map +1 -1
- package/dist/index.js +12 -1
- package/dist/index.js.map +1 -1
- package/dist/server/push-store.js +97 -0
- package/dist/server/push-store.js.map +1 -0
- package/dist/server/routes-push.js +33 -0
- package/dist/server/routes-push.js.map +1 -0
- package/dist/server/routes-root.js +22 -9
- package/dist/server/routes-root.js.map +1 -1
- package/dist/server/routes-sessions.js +13 -0
- package/dist/server/routes-sessions.js.map +1 -1
- package/dist/server/session-visibility.js +34 -0
- package/dist/server/session-visibility.js.map +1 -0
- package/dist/server/turn-notify-callback.js +159 -0
- package/dist/server/turn-notify-callback.js.map +1 -0
- package/dist/server/ws-bridge.js +127 -1
- package/dist/server/ws-bridge.js.map +1 -1
- package/dist/setup/conf-writer.js +86 -0
- package/dist/setup/conf-writer.js.map +1 -0
- package/dist/setup/tailscale-wizard.js +229 -0
- package/dist/setup/tailscale-wizard.js.map +1 -0
- package/dist/ui/index.html +119 -30
- package/dist/ui/sw.js +38 -11
- package/dist/util/paths.js +3 -0
- package/dist/util/paths.js.map +1 -1
- package/package.json +3 -1
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { chmodSync, existsSync, mkdirSync } from "node:fs";
|
|
3
|
+
import { userInfo } from "node:os";
|
|
4
|
+
import { createInterface } from "node:readline";
|
|
5
|
+
import { delimiter, join, resolve } from "node:path";
|
|
6
|
+
import { paths } from "../util/paths.js";
|
|
7
|
+
import { CONF_PATH, readExisting, writeConf } from "./conf-writer.js";
|
|
8
|
+
const BOLD = "\x1b[1m";
|
|
9
|
+
const GREEN = "\x1b[32m";
|
|
10
|
+
const YELLOW = "\x1b[33m";
|
|
11
|
+
const RED = "\x1b[31m";
|
|
12
|
+
const RESET = "\x1b[0m";
|
|
13
|
+
function header(num, total, title) {
|
|
14
|
+
process.stdout.write(`\n ${BOLD}[${num}/${total}] ${title}${RESET}\n\n`);
|
|
15
|
+
}
|
|
16
|
+
function ok(msg) {
|
|
17
|
+
process.stdout.write(` ${GREEN}✓${RESET} ${msg}\n`);
|
|
18
|
+
}
|
|
19
|
+
function warn(msg) {
|
|
20
|
+
process.stdout.write(` ${YELLOW}⚠${RESET} ${msg}\n`);
|
|
21
|
+
}
|
|
22
|
+
function fail(msg) {
|
|
23
|
+
process.stderr.write(` ${RED}✗ ${msg}${RESET}\n`);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
function info(msg) {
|
|
27
|
+
process.stdout.write(` ${msg}\n`);
|
|
28
|
+
}
|
|
29
|
+
function blank() {
|
|
30
|
+
process.stdout.write("\n");
|
|
31
|
+
}
|
|
32
|
+
async function confirm(label, defaultYes) {
|
|
33
|
+
const hint = defaultYes ? "[Y/n]" : "[y/N]";
|
|
34
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
35
|
+
try {
|
|
36
|
+
const reply = await new Promise((res) => {
|
|
37
|
+
rl.question(` ${label} ${hint}: `, res);
|
|
38
|
+
});
|
|
39
|
+
const trimmed = reply.trim().toLowerCase();
|
|
40
|
+
if (!trimmed)
|
|
41
|
+
return defaultYes;
|
|
42
|
+
return trimmed.startsWith("y");
|
|
43
|
+
}
|
|
44
|
+
finally {
|
|
45
|
+
rl.close();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function hasBin(name) {
|
|
49
|
+
const dirs = (process.env.PATH ?? "").split(delimiter);
|
|
50
|
+
const exts = process.platform === "win32" ? [".exe", ".cmd", ".bat", ""] : [""];
|
|
51
|
+
for (const dir of dirs) {
|
|
52
|
+
if (!dir)
|
|
53
|
+
continue;
|
|
54
|
+
for (const ext of exts) {
|
|
55
|
+
try {
|
|
56
|
+
if (existsSync(join(dir, name + ext)))
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// not present in this dir; keep looking
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
const TOTAL_STEPS = 4;
|
|
67
|
+
function step1Prereqs() {
|
|
68
|
+
header(1, TOTAL_STEPS, "Checking Tailscale");
|
|
69
|
+
if (!hasBin("tailscale")) {
|
|
70
|
+
fail("tailscale not found on PATH. Install it first: https://tailscale.com/download");
|
|
71
|
+
}
|
|
72
|
+
ok("tailscale is installed");
|
|
73
|
+
const result = spawnSync("tailscale", ["status", "--json"], { encoding: "utf8" });
|
|
74
|
+
if (result.status !== 0) {
|
|
75
|
+
fail(`tailscale status failed: ${result.stderr?.trim() || "unknown error"}. Is the daemon running?`);
|
|
76
|
+
}
|
|
77
|
+
let status;
|
|
78
|
+
try {
|
|
79
|
+
status = JSON.parse(result.stdout);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
fail("Couldn't parse `tailscale status --json` output.");
|
|
83
|
+
}
|
|
84
|
+
if (status.BackendState !== "Running") {
|
|
85
|
+
fail(`Tailscale isn't logged in (state: ${status.BackendState ?? "unknown"}). Run \`sudo tailscale up\` first, then re-run this wizard.`);
|
|
86
|
+
}
|
|
87
|
+
const dnsName = status.Self?.DNSName?.replace(/\.$/, "");
|
|
88
|
+
const tailscaleIp = status.Self?.TailscaleIPs?.[0];
|
|
89
|
+
if (!dnsName || !tailscaleIp) {
|
|
90
|
+
fail("Couldn't read this device's MagicDNS name or tailnet IP from `tailscale status`. Is MagicDNS enabled for this tailnet?");
|
|
91
|
+
}
|
|
92
|
+
ok(`Logged in as ${dnsName}`);
|
|
93
|
+
ok(`Tailnet IP: ${tailscaleIp}`);
|
|
94
|
+
return { dnsName, tailscaleIp };
|
|
95
|
+
}
|
|
96
|
+
function isPermissionError(stderr) {
|
|
97
|
+
return /access denied|permission denied|must be root|operator/i.test(stderr);
|
|
98
|
+
}
|
|
99
|
+
// Tailscale's own wording for this varies ("HTTPS is not enabled for your
|
|
100
|
+
// tailnet" from older CLI builds vs. "your Tailscale account does not
|
|
101
|
+
// support getting TLS certs" from the control plane) — match both rather
|
|
102
|
+
// than one exact string.
|
|
103
|
+
function isCertsUnavailableError(stderr) {
|
|
104
|
+
return /https is not enabled|does not support getting tls certs/i.test(stderr);
|
|
105
|
+
}
|
|
106
|
+
function failCertsUnavailable() {
|
|
107
|
+
fail("This tailnet doesn't have HTTPS certificates enabled (or your account's plan " +
|
|
108
|
+
"doesn't support them). Enable them at https://login.tailscale.com/admin/dns " +
|
|
109
|
+
"(DNS tab -> HTTPS Certificates); if it's already on, this account/plan may not " +
|
|
110
|
+
"support tailnet TLS certs at all — check https://tailscale.com/kb/1153/enabling-https.");
|
|
111
|
+
}
|
|
112
|
+
async function step2MintCert(dnsName) {
|
|
113
|
+
header(2, TOTAL_STEPS, "Minting cert");
|
|
114
|
+
const tlsDir = resolve(paths.home(), "tls");
|
|
115
|
+
mkdirSync(tlsDir, { recursive: true });
|
|
116
|
+
chmodSync(tlsDir, 0o700);
|
|
117
|
+
const certPath = resolve(tlsDir, "cert.pem");
|
|
118
|
+
const keyPath = resolve(tlsDir, "key.pem");
|
|
119
|
+
const certArgs = ["cert", "--cert-file", certPath, "--key-file", keyPath, dnsName];
|
|
120
|
+
info("Requesting cert from Tailscale (network call, can take a few seconds)...");
|
|
121
|
+
const attempt = spawnSync("tailscale", certArgs, { encoding: "utf8" });
|
|
122
|
+
if (attempt.status !== 0) {
|
|
123
|
+
const stderr = attempt.stderr?.trim() ?? "";
|
|
124
|
+
if (isCertsUnavailableError(stderr)) {
|
|
125
|
+
failCertsUnavailable();
|
|
126
|
+
}
|
|
127
|
+
if (!isPermissionError(stderr)) {
|
|
128
|
+
fail(`tailscale cert failed: ${stderr || "unknown error"}`);
|
|
129
|
+
}
|
|
130
|
+
warn("tailscale cert needs elevated access to the local tailscaled socket.");
|
|
131
|
+
info("Fix this permanently: sudo tailscale set --operator=$(whoami)");
|
|
132
|
+
info("Future tailscale commands, including re-runs of this wizard, won't need sudo after that.");
|
|
133
|
+
blank();
|
|
134
|
+
if (!(await confirm("Retry cert generation with sudo now instead?", true))) {
|
|
135
|
+
fail("Run `sudo tailscale set --operator=$(whoami)`, then re-run this wizard.");
|
|
136
|
+
}
|
|
137
|
+
// stdin stays attached to the real terminal so sudo's password prompt
|
|
138
|
+
// still works; stdout/stderr are captured so we can still recognize a
|
|
139
|
+
// certs-unavailable failure instead of just reporting a bare exit code.
|
|
140
|
+
info("Requesting cert via sudo (may prompt for your password, then a network call)...");
|
|
141
|
+
const sudoAttempt = spawnSync("sudo", ["tailscale", ...certArgs], {
|
|
142
|
+
stdio: ["inherit", "pipe", "pipe"],
|
|
143
|
+
encoding: "utf8",
|
|
144
|
+
});
|
|
145
|
+
if (sudoAttempt.status !== 0) {
|
|
146
|
+
const sudoStderr = sudoAttempt.stderr?.trim() ?? "";
|
|
147
|
+
if (sudoStderr)
|
|
148
|
+
process.stderr.write(` ${sudoStderr}\n`);
|
|
149
|
+
if (isCertsUnavailableError(sudoStderr)) {
|
|
150
|
+
failCertsUnavailable();
|
|
151
|
+
}
|
|
152
|
+
fail(`tailscale cert failed even with sudo (exit ${sudoAttempt.status ?? "?"}).`);
|
|
153
|
+
}
|
|
154
|
+
// tailscale ran as root, so it owns the files it just wrote — the browser
|
|
155
|
+
// server (running as the invoking user) needs to be able to read them.
|
|
156
|
+
const owner = userInfo().username;
|
|
157
|
+
const chownResult = spawnSync("sudo", ["chown", owner, certPath, keyPath], {
|
|
158
|
+
stdio: "inherit",
|
|
159
|
+
});
|
|
160
|
+
if (chownResult.status !== 0) {
|
|
161
|
+
warn(`Couldn't chown the cert files to ${owner}. Fix manually: sudo chown ${owner} ${certPath} ${keyPath}`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
try {
|
|
165
|
+
chmodSync(certPath, 0o600);
|
|
166
|
+
chmodSync(keyPath, 0o600);
|
|
167
|
+
}
|
|
168
|
+
catch (err) {
|
|
169
|
+
warn(`Couldn't chmod cert files (${err.message}). Check ownership if HTTPS fails to start.`);
|
|
170
|
+
}
|
|
171
|
+
ok(`Wrote ${certPath}`);
|
|
172
|
+
ok(`Wrote ${keyPath}`);
|
|
173
|
+
info("Tailscale certs are valid ~90 days. Re-run this wizard to renew before expiry.");
|
|
174
|
+
return { certPath, keyPath };
|
|
175
|
+
}
|
|
176
|
+
function step3WriteConfig(args) {
|
|
177
|
+
header(3, TOTAL_STEPS, "Writing config");
|
|
178
|
+
const { map } = readExisting(CONF_PATH);
|
|
179
|
+
const existingHosts = (map.get("BROWSER_ALLOWED_HOSTS") ?? "")
|
|
180
|
+
.split(",")
|
|
181
|
+
.map((s) => s.trim())
|
|
182
|
+
.filter((s) => s.length > 0);
|
|
183
|
+
const hosts = new Set(existingHosts);
|
|
184
|
+
hosts.add(args.dnsName);
|
|
185
|
+
const port = Number.parseInt(map.get("BROWSER_PORT") ?? "", 10) || 5514;
|
|
186
|
+
writeConf(CONF_PATH, {
|
|
187
|
+
BROWSER_TLS_CERT: args.certPath,
|
|
188
|
+
BROWSER_TLS_KEY: args.keyPath,
|
|
189
|
+
BROWSER_HOST: args.tailscaleIp,
|
|
190
|
+
BROWSER_ALLOWED_HOSTS: Array.from(hosts).join(","),
|
|
191
|
+
});
|
|
192
|
+
ok(`Wrote ${CONF_PATH} (chmod 600)`);
|
|
193
|
+
info(`BROWSER_HOST=${args.tailscaleIp} — bound to the tailnet interface only, not your LAN.`);
|
|
194
|
+
if (map.get("BROWSER_HOST") === "0.0.0.0") {
|
|
195
|
+
warn("Previously bound to 0.0.0.0 (every interface). Narrowed to the tailnet IP.");
|
|
196
|
+
}
|
|
197
|
+
return port;
|
|
198
|
+
}
|
|
199
|
+
async function step4RestartExtension() {
|
|
200
|
+
header(4, TOTAL_STEPS, "Apply");
|
|
201
|
+
if (!hasBin("hydra-acp")) {
|
|
202
|
+
info("hydra-acp not found on PATH. Restart hydra-acp-browser manually to apply.");
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
if (!(await confirm("Restart the hydra-acp-browser extension now?", true))) {
|
|
206
|
+
info("Skipped. Apply later with: hydra-acp extensions restart hydra-acp-browser");
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
const result = spawnSync("hydra-acp", ["extensions", "restart", "hydra-acp-browser"], {
|
|
210
|
+
stdio: "inherit",
|
|
211
|
+
});
|
|
212
|
+
if (result.status === 0) {
|
|
213
|
+
ok("Restarted.");
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
warn(`hydra-acp exited with code ${result.status ?? "?"}. Restart manually if needed.`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
export async function runTailscaleSetup() {
|
|
220
|
+
process.stdout.write(`\n ${BOLD}hydra-acp-browser tailscale setup${RESET}\n`);
|
|
221
|
+
const { dnsName, tailscaleIp } = step1Prereqs();
|
|
222
|
+
const { certPath, keyPath } = await step2MintCert(dnsName);
|
|
223
|
+
const port = step3WriteConfig({ dnsName, tailscaleIp, certPath, keyPath });
|
|
224
|
+
await step4RestartExtension();
|
|
225
|
+
blank();
|
|
226
|
+
ok("Setup complete.");
|
|
227
|
+
info(`Open: https://${dnsName}:${port}/`);
|
|
228
|
+
}
|
|
229
|
+
//# sourceMappingURL=tailscale-wizard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tailscale-wizard.js","sourceRoot":"","sources":["../../src/setup/tailscale-wizard.ts"],"names":[],"mappings":"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"}
|