@vantaloom/runtime-linux-x64 0.3.10 → 0.5.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/VERSION +1 -1
- package/bin/easytier-cli +0 -0
- package/bin/easytier-core +0 -0
- package/bin/vantaloom-agent +0 -0
- package/bin/vantaloom-api +0 -0
- package/bin/vantaloom-mesh +0 -0
- package/bin/vantaloomctl +0 -0
- package/cli/package.json +1 -1
- package/cli/src/cli.mjs +461 -17
- package/manifest.json +2 -2
- package/package.json +1 -1
- package/web/404.html +1 -1
- package/web/__next.__PAGE__.txt +2 -2
- package/web/__next._full.txt +2 -2
- package/web/__next._head.txt +1 -1
- package/web/__next._index.txt +1 -1
- package/web/__next._tree.txt +1 -1
- package/web/_next/static/chunks/80b4a364458ec11d.js +52 -0
- package/web/_not-found/__next._full.txt +1 -1
- package/web/_not-found/__next._head.txt +1 -1
- package/web/_not-found/__next._index.txt +1 -1
- package/web/_not-found/__next._not-found/__PAGE__.txt +1 -1
- package/web/_not-found/__next._not-found.txt +1 -1
- package/web/_not-found/__next._tree.txt +1 -1
- package/web/_not-found.html +1 -1
- package/web/_not-found.txt +1 -1
- package/web/index.html +1 -1
- package/web/index.txt +2 -2
- package/web/_next/static/chunks/d5f21d922d1ce7bc.js +0 -52
- /package/web/_next/static/{Yzez8sn2b9GKEWWWzhZyx → 1nS86NCCueT0DPdtcRvFo}/_buildManifest.js +0 -0
- /package/web/_next/static/{Yzez8sn2b9GKEWWWzhZyx → 1nS86NCCueT0DPdtcRvFo}/_clientMiddlewareManifest.json +0 -0
- /package/web/_next/static/{Yzez8sn2b9GKEWWWzhZyx → 1nS86NCCueT0DPdtcRvFo}/_ssgManifest.js +0 -0
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
782bb79
|
package/bin/easytier-cli
ADDED
|
Binary file
|
|
Binary file
|
package/bin/vantaloom-agent
CHANGED
|
Binary file
|
package/bin/vantaloom-api
CHANGED
|
Binary file
|
|
Binary file
|
package/bin/vantaloomctl
CHANGED
|
Binary file
|
package/cli/package.json
CHANGED
package/cli/src/cli.mjs
CHANGED
|
@@ -11,10 +11,16 @@ import {
|
|
|
11
11
|
writeFileSync,
|
|
12
12
|
} from "node:fs"
|
|
13
13
|
import { cp, writeFile } from "node:fs/promises"
|
|
14
|
+
import { createHash } from "node:crypto"
|
|
14
15
|
import os from "node:os"
|
|
15
16
|
import path from "node:path"
|
|
16
17
|
import { fileURLToPath } from "node:url"
|
|
17
18
|
|
|
19
|
+
// The mesh binaries the privileged service holds open while running. On Windows
|
|
20
|
+
// a file copy can't overwrite them in place, so the lock-safe `apply` path swaps
|
|
21
|
+
// them after stopping the service.
|
|
22
|
+
const WINDOWS_MESH_BINARIES = ["easytier-core.exe", "easytier-cli.exe", "wintun.dll", "Packet.dll", "WinDivert64.sys", "vantaloom-mesh.exe"]
|
|
23
|
+
|
|
18
24
|
const cliRoot = path.resolve(fileURLToPath(import.meta.url), "..", "..")
|
|
19
25
|
const repoCandidate = path.resolve(cliRoot, "..", "..")
|
|
20
26
|
const installedConfigPath = path.join(cliRoot, "config.json")
|
|
@@ -99,6 +105,9 @@ export async function main(argv) {
|
|
|
99
105
|
case "path":
|
|
100
106
|
printPaths(options)
|
|
101
107
|
return
|
|
108
|
+
case "uninstall":
|
|
109
|
+
await uninstallRuntime(options)
|
|
110
|
+
return
|
|
102
111
|
case "help":
|
|
103
112
|
case "-h":
|
|
104
113
|
case "--help":
|
|
@@ -122,6 +131,8 @@ async function installFromSource(options) {
|
|
|
122
131
|
noStart: options.noStart,
|
|
123
132
|
sourceRoot,
|
|
124
133
|
update: options.update,
|
|
134
|
+
withMesh: options.withMesh,
|
|
135
|
+
skipMesh: options.skipMesh,
|
|
125
136
|
})
|
|
126
137
|
|
|
127
138
|
console.log(`${options.update ? "updated" : "installed"} Vantaloom: ${prefix}`)
|
|
@@ -136,6 +147,8 @@ async function installFromPackage(options) {
|
|
|
136
147
|
const version = await applyPackage(packageRoot, prefix, {
|
|
137
148
|
noStart: options.noStart,
|
|
138
149
|
update: options.update,
|
|
150
|
+
withMesh: options.withMesh,
|
|
151
|
+
skipMesh: options.skipMesh,
|
|
139
152
|
})
|
|
140
153
|
|
|
141
154
|
console.log(`${options.update ? "updated" : "installed"} Vantaloom: ${prefix}`)
|
|
@@ -189,6 +202,9 @@ async function buildRuntimePackage(sourceRoot, packageRoot, options) {
|
|
|
189
202
|
buildGo(sourceRoot, buildBin, "vantaloom-api", platform)
|
|
190
203
|
buildGo(sourceRoot, buildBin, "vantaloom-agent", platform)
|
|
191
204
|
buildGo(sourceRoot, buildBin, "vantaloomctl", platform)
|
|
205
|
+
// Privileged EasyTier sidecar (runs the mesh node as a service on Windows/macOS).
|
|
206
|
+
// Pure-Go (no CGO), so it cross-compiles cleanly for every target.
|
|
207
|
+
buildGo(sourceRoot, buildBin, "vantaloom-mesh", platform)
|
|
192
208
|
// Tray app requires CGO (systray), only buildable natively on Windows.
|
|
193
209
|
if (platform.startsWith("win32") && process.platform === "win32") {
|
|
194
210
|
try {
|
|
@@ -196,6 +212,9 @@ async function buildRuntimePackage(sourceRoot, packageRoot, options) {
|
|
|
196
212
|
} catch { /* optional: skip if systray build fails */ }
|
|
197
213
|
}
|
|
198
214
|
|
|
215
|
+
// Bundle the EasyTier mesh binaries (P2P virtual network) for the target platform.
|
|
216
|
+
await copyEasyTier(sourceRoot, buildBin, platform)
|
|
217
|
+
|
|
199
218
|
if (options.buildWeb) {
|
|
200
219
|
runPnpm(["--filter", "vantaloom-app", "build"], { cwd: sourceRoot })
|
|
201
220
|
}
|
|
@@ -207,6 +226,45 @@ async function buildRuntimePackage(sourceRoot, packageRoot, options) {
|
|
|
207
226
|
return { platform, version }
|
|
208
227
|
}
|
|
209
228
|
|
|
229
|
+
// copyEasyTier bundles the vendored EasyTier binaries (easytier-core/easytier-cli,
|
|
230
|
+
// plus wintun.dll on Windows) for the target platform into the package bin/ dir.
|
|
231
|
+
async function copyEasyTier(sourceRoot, buildBin, platform) {
|
|
232
|
+
const vendorMap = {
|
|
233
|
+
"win32-x64": "windows-x86_64",
|
|
234
|
+
"darwin-arm64": "macos-aarch64",
|
|
235
|
+
"linux-x64": "linux-x86_64",
|
|
236
|
+
}
|
|
237
|
+
const vendorName = vendorMap[platform]
|
|
238
|
+
if (!vendorName) {
|
|
239
|
+
console.warn(` warning: no EasyTier mapping for ${platform}; mesh disabled for this platform`)
|
|
240
|
+
return
|
|
241
|
+
}
|
|
242
|
+
const srcDir = path.join(sourceRoot, "vendor", "easytier", vendorName, `easytier-${vendorName}`)
|
|
243
|
+
if (!existsSync(srcDir)) {
|
|
244
|
+
console.warn(` warning: EasyTier binaries not found at ${srcDir}; run vendor download first`)
|
|
245
|
+
return
|
|
246
|
+
}
|
|
247
|
+
const isWin = platform.startsWith("win32")
|
|
248
|
+
// Packet.dll + WinDivert64.sys are REQUIRED: easytier-core.exe statically
|
|
249
|
+
// imports Packet.dll, so without it the process dies at launch with
|
|
250
|
+
// STATUS_DLL_NOT_FOUND (0xC0000135) before writing any log. wintun.dll is the
|
|
251
|
+
// TUN backend. easytier-cli.exe does not need Packet.dll (it still launches).
|
|
252
|
+
const files = isWin
|
|
253
|
+
? ["easytier-core.exe", "easytier-cli.exe", "wintun.dll", "Packet.dll", "WinDivert64.sys"]
|
|
254
|
+
: ["easytier-core", "easytier-cli"]
|
|
255
|
+
let copied = 0
|
|
256
|
+
for (const f of files) {
|
|
257
|
+
const src = path.join(srcDir, f)
|
|
258
|
+
if (!existsSync(src)) {
|
|
259
|
+
console.warn(` warning: EasyTier file missing: ${f}`)
|
|
260
|
+
continue
|
|
261
|
+
}
|
|
262
|
+
await cp(src, path.join(buildBin, f), { force: true })
|
|
263
|
+
copied++
|
|
264
|
+
}
|
|
265
|
+
console.log(` bundled EasyTier ${vendorName} (${copied} files)`)
|
|
266
|
+
}
|
|
267
|
+
|
|
210
268
|
async function applyPackage(packageRoot, prefix, options) {
|
|
211
269
|
assertRuntimePackage(packageRoot)
|
|
212
270
|
|
|
@@ -227,6 +285,14 @@ async function applyPackage(packageRoot, prefix, options) {
|
|
|
227
285
|
// don't write tray.pid, so vantaloomctl stop won't find them).
|
|
228
286
|
killTrayProcess(prefix)
|
|
229
287
|
|
|
288
|
+
// On Windows the privileged mesh service holds its binaries open, so we can't
|
|
289
|
+
// wipe or overwrite them with a plain copy. Detect that up front: if the
|
|
290
|
+
// service is running, skip those files in the bin/ copy (the elevated `apply`
|
|
291
|
+
// swaps them after stopping the service).
|
|
292
|
+
const meshLocked =
|
|
293
|
+
process.platform === "win32" &&
|
|
294
|
+
meshServiceRunning(path.join(packageRoot, "bin"), "win32")
|
|
295
|
+
|
|
230
296
|
// Copy package contents to install prefix
|
|
231
297
|
for (const name of ["bin", "web", "cli"]) {
|
|
232
298
|
const src = path.join(packageRoot, name)
|
|
@@ -235,12 +301,15 @@ async function applyPackage(packageRoot, prefix, options) {
|
|
|
235
301
|
console.error(` warning: package missing ${name}/ directory`)
|
|
236
302
|
continue
|
|
237
303
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
}
|
|
304
|
+
const copyOpts = { recursive: true, force: true, dereference: false }
|
|
305
|
+
if (name === "bin" && meshLocked) {
|
|
306
|
+
// Overwrite in place (don't wipe — that would fail on the locked files) and
|
|
307
|
+
// skip the mesh binaries the running service holds open.
|
|
308
|
+
copyOpts.filter = (s) => !WINDOWS_MESH_BINARIES.includes(path.basename(s))
|
|
309
|
+
} else {
|
|
310
|
+
removeKnownPath(dst, prefix)
|
|
311
|
+
}
|
|
312
|
+
await cp(src, dst, copyOpts)
|
|
244
313
|
}
|
|
245
314
|
|
|
246
315
|
// Ensure binaries are executable on Unix (cross-compiled from Windows they lose +x)
|
|
@@ -252,6 +321,28 @@ async function applyPackage(packageRoot, prefix, options) {
|
|
|
252
321
|
}
|
|
253
322
|
}
|
|
254
323
|
|
|
324
|
+
// Linux: grant easytier-core the TUN capability so the unprivileged runtime can
|
|
325
|
+
// bring up the mesh virtual network. This is the one privileged step of the
|
|
326
|
+
// install (a single sudo); the app itself stays unprivileged.
|
|
327
|
+
ensureLinuxMeshCapabilities(binDir)
|
|
328
|
+
|
|
329
|
+
// Windows/macOS: register (or lock-safely update) the privileged mesh service
|
|
330
|
+
// that runs easytier-core. This is the one elevation of the install on those
|
|
331
|
+
// platforms. Skipped for --no-start and gated to avoid prompting on every
|
|
332
|
+
// source rebuild (see ensureMeshService).
|
|
333
|
+
if (!options.noStart) {
|
|
334
|
+
ensureMeshService(packageRoot, prefix, {
|
|
335
|
+
sourceInstall: Boolean(options.sourceRoot),
|
|
336
|
+
withMesh: Boolean(options.withMesh),
|
|
337
|
+
skipMesh: Boolean(options.skipMesh),
|
|
338
|
+
})
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Make the runtime start at login/boot (per-user, no elevation). Idempotent.
|
|
342
|
+
if (!options.noStart && !options.skipAutostart) {
|
|
343
|
+
enableRuntimeAutostart(prefix)
|
|
344
|
+
}
|
|
345
|
+
|
|
255
346
|
// Verify vantaloomctl binary exists before trying to run it
|
|
256
347
|
const ctlBin = path.join(prefix, "bin", binaryName("vantaloomctl"))
|
|
257
348
|
if (!existsSync(ctlBin)) {
|
|
@@ -292,6 +383,340 @@ async function applyPackage(packageRoot, prefix, options) {
|
|
|
292
383
|
return version
|
|
293
384
|
}
|
|
294
385
|
|
|
386
|
+
// ensureLinuxMeshCapabilities grants easytier-core the network capabilities it
|
|
387
|
+
// needs to create a TUN device, so the unprivileged Vantaloom runtime can bring
|
|
388
|
+
// up the EasyTier mesh without running as root. Re-run on every update because
|
|
389
|
+
// replacing the binary clears file capabilities. Non-fatal: if it can't elevate
|
|
390
|
+
// or setcap is missing, mesh just falls back to the Hub relay.
|
|
391
|
+
function ensureLinuxMeshCapabilities(binDir) {
|
|
392
|
+
if (process.platform !== "linux") {
|
|
393
|
+
return
|
|
394
|
+
}
|
|
395
|
+
const core = path.join(binDir, "easytier-core")
|
|
396
|
+
if (!existsSync(core)) {
|
|
397
|
+
console.warn(" mesh: easytier-core not bundled; skipping TUN capability setup")
|
|
398
|
+
return
|
|
399
|
+
}
|
|
400
|
+
const caps = "cap_net_admin,cap_net_bind_service+ep"
|
|
401
|
+
const isRoot = typeof process.getuid === "function" && process.getuid() === 0
|
|
402
|
+
console.log(` mesh: granting TUN capability to easytier-core${isRoot ? "" : " (sudo)"} ...`)
|
|
403
|
+
const result = isRoot
|
|
404
|
+
? spawnSync("setcap", [caps, core], { stdio: "inherit" })
|
|
405
|
+
: spawnSync("sudo", ["setcap", caps, core], { stdio: "inherit" })
|
|
406
|
+
if (result.error || result.status !== 0) {
|
|
407
|
+
console.warn(
|
|
408
|
+
" mesh: could not set capabilities (P2P will fall back to the Hub relay).\n" +
|
|
409
|
+
` enable it manually with: sudo setcap ${caps} ${core}\n` +
|
|
410
|
+
" (needs the 'setcap' tool, e.g. apt install libcap2-bin)"
|
|
411
|
+
)
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// ensureMeshService registers (or lock-safely updates) the privileged EasyTier
|
|
416
|
+
// sidecar service on Windows/macOS — the one elevation of the install on those
|
|
417
|
+
// platforms. Linux uses setcap instead (see ensureLinuxMeshCapabilities).
|
|
418
|
+
//
|
|
419
|
+
// To keep the source/dev rebuild loop frictionless it only elevates when the
|
|
420
|
+
// work is actually needed (service missing, or the mesh binaries changed) and,
|
|
421
|
+
// for source installs, defers to a printed one-liner unless --with-mesh is set.
|
|
422
|
+
function ensureMeshService(packageRoot, prefix, opts) {
|
|
423
|
+
const platform = process.platform
|
|
424
|
+
if (platform !== "win32" && platform !== "darwin") return // Linux: setcap path
|
|
425
|
+
if (opts.skipMesh) return
|
|
426
|
+
|
|
427
|
+
const pkgBin = path.join(packageRoot, "bin")
|
|
428
|
+
const meshExe = path.join(pkgBin, binaryName("vantaloom-mesh"))
|
|
429
|
+
if (!existsSync(meshExe)) return // sidecar not bundled
|
|
430
|
+
|
|
431
|
+
if (!meshServiceNeedsApply(pkgBin, path.join(prefix, "bin"), platform)) {
|
|
432
|
+
return // installed binaries current and service already managing them
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if (opts.sourceInstall && !opts.withMesh) {
|
|
436
|
+
printMeshManualHint(prefix, platform)
|
|
437
|
+
return
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
if (platform === "win32") {
|
|
441
|
+
elevateWindowsMeshApply(pkgBin, prefix)
|
|
442
|
+
} else {
|
|
443
|
+
elevateDarwinMeshInstall(prefix)
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// meshServiceNeedsApply reports whether the privileged service has to be
|
|
448
|
+
// (re)applied: true if the installed mesh binaries are missing/outdated, or if
|
|
449
|
+
// the service isn't currently up.
|
|
450
|
+
function meshServiceNeedsApply(pkgBin, installBin, platform) {
|
|
451
|
+
// On Windows compare every lockable mesh file (incl. Packet.dll/WinDivert/wintun)
|
|
452
|
+
// so a missing or changed support DLL also triggers a (re)apply.
|
|
453
|
+
const names = platform === "win32"
|
|
454
|
+
? WINDOWS_MESH_BINARIES
|
|
455
|
+
: [binaryName("vantaloom-mesh"), binaryName("easytier-core")]
|
|
456
|
+
for (const name of names) {
|
|
457
|
+
const installed = path.join(installBin, name)
|
|
458
|
+
if (!existsSync(installed)) return true
|
|
459
|
+
const staged = path.join(pkgBin, name)
|
|
460
|
+
if (existsSync(staged) && fileSha(staged) !== fileSha(installed)) return true
|
|
461
|
+
}
|
|
462
|
+
return !meshServiceRunning(pkgBin, platform)
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// meshServiceRunning queries the OS service state via the (unprivileged) mesh
|
|
466
|
+
// `status` command. binDir is where to find the vantaloom-mesh binary to run.
|
|
467
|
+
function meshServiceRunning(binDir, platform) {
|
|
468
|
+
const exe = path.join(binDir, binaryName("vantaloom-mesh"))
|
|
469
|
+
if (!existsSync(exe)) return false
|
|
470
|
+
const r = spawnSync(exe, ["status"], { encoding: "utf8" })
|
|
471
|
+
if (r.error || typeof r.stdout !== "string") return false
|
|
472
|
+
const out = r.stdout.toLowerCase()
|
|
473
|
+
if (platform === "win32") return out.includes("running")
|
|
474
|
+
return r.status === 0 && !out.includes("not loaded") && !out.includes("not installed")
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
function fileSha(file) {
|
|
478
|
+
return createHash("sha256").update(readFileSync(file)).digest("hex")
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// elevateWindowsMeshApply runs the lock-safe `apply` elevated (one UAC prompt).
|
|
482
|
+
// It launches from the package copy so it can overwrite the installed binary.
|
|
483
|
+
function elevateWindowsMeshApply(pkgBin, prefix) {
|
|
484
|
+
const exe = path.join(pkgBin, "vantaloom-mesh.exe")
|
|
485
|
+
console.log(" mesh: registering privileged P2P service (UAC prompt) ...")
|
|
486
|
+
const argList = ["apply", "--pkg-bin", pkgBin, "--install-dir", prefix].map(psQuote).join(",")
|
|
487
|
+
const ps = `$ErrorActionPreference='Stop'; $p = Start-Process -FilePath ${psQuote(exe)} -ArgumentList ${argList} -Verb RunAs -Wait -PassThru; exit $p.ExitCode`
|
|
488
|
+
const r = spawnSync("powershell", ["-NoProfile", "-NonInteractive", "-Command", ps], { stdio: "inherit" })
|
|
489
|
+
if (r.error || r.status !== 0) {
|
|
490
|
+
const installed = path.join(prefix, "bin", "vantaloom-mesh.exe")
|
|
491
|
+
console.warn(" mesh: service registration was cancelled or failed; P2P falls back to the Hub relay.")
|
|
492
|
+
console.warn(` enable it later (as Administrator): "${installed}" install --install-dir "${prefix}"`)
|
|
493
|
+
} else {
|
|
494
|
+
console.log(" mesh: privileged P2P service active")
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// elevateDarwinMeshInstall registers the LaunchDaemon via sudo (one prompt). The
|
|
499
|
+
// runtime already copied the fresh binary into place; install reloads the daemon.
|
|
500
|
+
function elevateDarwinMeshInstall(prefix) {
|
|
501
|
+
const exe = path.join(prefix, "bin", "vantaloom-mesh")
|
|
502
|
+
console.log(" mesh: registering privileged P2P service (sudo) ...")
|
|
503
|
+
const r = spawnSync("sudo", [exe, "install", "--install-dir", prefix], { stdio: "inherit" })
|
|
504
|
+
if (r.error || r.status !== 0) {
|
|
505
|
+
console.warn(" mesh: LaunchDaemon registration failed; P2P falls back to the Hub relay.")
|
|
506
|
+
console.warn(` enable it later: sudo "${exe}" install --install-dir "${prefix}"`)
|
|
507
|
+
} else {
|
|
508
|
+
console.log(" mesh: privileged P2P service active")
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
function printMeshManualHint(prefix, platform) {
|
|
513
|
+
console.log(" mesh: P2P service not auto-registered for source installs.")
|
|
514
|
+
if (platform === "win32") {
|
|
515
|
+
const exe = path.join(prefix, "bin", "vantaloom-mesh.exe")
|
|
516
|
+
console.log(` enable it once (as Administrator): "${exe}" install --install-dir "${prefix}"`)
|
|
517
|
+
console.log(" or re-run install/update with --with-mesh")
|
|
518
|
+
} else {
|
|
519
|
+
const exe = path.join(prefix, "bin", "vantaloom-mesh")
|
|
520
|
+
console.log(` enable it once: sudo "${exe}" install --install-dir "${prefix}"`)
|
|
521
|
+
console.log(" or re-run install/update with --with-mesh")
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// psQuote wraps a value as a PowerShell single-quoted string literal.
|
|
526
|
+
function psQuote(value) {
|
|
527
|
+
return "'" + String(value).replace(/'/g, "''") + "'"
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// uninstallRuntime tears down a local install: stop the runtime, remove the
|
|
531
|
+
// privileged mesh service (elevated), then delete the install directory.
|
|
532
|
+
async function uninstallRuntime(options) {
|
|
533
|
+
const prefix = safeDirectory(options.prefix ?? defaultPrefix())
|
|
534
|
+
if (!existsSync(prefix)) {
|
|
535
|
+
console.log(`Vantaloom is not installed at ${prefix}`)
|
|
536
|
+
return
|
|
537
|
+
}
|
|
538
|
+
console.log(`Uninstalling Vantaloom from ${prefix} ...`)
|
|
539
|
+
|
|
540
|
+
// 1. Stop the runtime (api/agent/web/tray). Best-effort.
|
|
541
|
+
const ctlBin = path.join(prefix, "bin", binaryName("vantaloomctl"))
|
|
542
|
+
if (existsSync(ctlBin)) {
|
|
543
|
+
spawnSync(ctlBin, ["stop", "--prefix", prefix], { stdio: "inherit" })
|
|
544
|
+
}
|
|
545
|
+
killTrayProcess(prefix)
|
|
546
|
+
|
|
547
|
+
// 2. Remove the privileged mesh service (releases TUN adapter + file locks).
|
|
548
|
+
removeMeshService(prefix, options)
|
|
549
|
+
|
|
550
|
+
// 2b. Remove the login-autostart entry (lives outside the install dir).
|
|
551
|
+
disableRuntimeAutostart()
|
|
552
|
+
|
|
553
|
+
// 3. Delete the install directory.
|
|
554
|
+
try {
|
|
555
|
+
const parent = path.dirname(prefix)
|
|
556
|
+
removeKnownPath(prefix, parent)
|
|
557
|
+
console.log(`removed ${prefix}`)
|
|
558
|
+
} catch (error) {
|
|
559
|
+
console.warn(` could not remove ${prefix}: ${error.message}`)
|
|
560
|
+
console.warn(" some files may still be locked; re-run after closing Vantaloom processes.")
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
console.log("Vantaloom uninstalled.")
|
|
564
|
+
console.log("note: the install dir was left out of PATH edits; remove the bin/ entry from your shell profile if you added it.")
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
function removeMeshService(prefix, options) {
|
|
568
|
+
const platform = process.platform
|
|
569
|
+
if (platform !== "win32" && platform !== "darwin") return // Linux: nothing registered
|
|
570
|
+
const exe = path.join(prefix, "bin", binaryName("vantaloom-mesh"))
|
|
571
|
+
if (!existsSync(exe)) return
|
|
572
|
+
if (options.skipMesh) return
|
|
573
|
+
|
|
574
|
+
if (platform === "win32") {
|
|
575
|
+
if (!meshServiceRunningOrInstalled(path.join(prefix, "bin"))) return
|
|
576
|
+
console.log(" mesh: removing privileged P2P service (UAC prompt) ...")
|
|
577
|
+
const ps = `$ErrorActionPreference='Stop'; $p = Start-Process -FilePath ${psQuote(exe)} -ArgumentList 'uninstall' -Verb RunAs -Wait -PassThru; exit $p.ExitCode`
|
|
578
|
+
const r = spawnSync("powershell", ["-NoProfile", "-NonInteractive", "-Command", ps], { stdio: "inherit" })
|
|
579
|
+
if (r.error || r.status !== 0) {
|
|
580
|
+
console.warn(` mesh: could not remove service; run manually (as Administrator): "${exe}" uninstall`)
|
|
581
|
+
}
|
|
582
|
+
} else {
|
|
583
|
+
console.log(" mesh: removing privileged P2P service (sudo) ...")
|
|
584
|
+
const r = spawnSync("sudo", [exe, "uninstall"], { stdio: "inherit" })
|
|
585
|
+
if (r.error || r.status !== 0) {
|
|
586
|
+
console.warn(` mesh: could not remove service; run manually: sudo "${exe}" uninstall`)
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// meshServiceRunningOrInstalled reports whether the Windows service exists at
|
|
592
|
+
// all (running or stopped), so uninstall only prompts for elevation when there
|
|
593
|
+
// is actually something to remove.
|
|
594
|
+
function meshServiceRunningOrInstalled(binDir) {
|
|
595
|
+
const exe = path.join(binDir, "vantaloom-mesh.exe")
|
|
596
|
+
if (!existsSync(exe)) return false
|
|
597
|
+
const r = spawnSync(exe, ["status"], { encoding: "utf8" })
|
|
598
|
+
if (r.error || typeof r.stdout !== "string") return false
|
|
599
|
+
return !r.stdout.toLowerCase().includes("not installed")
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
// ── Runtime login-autostart (no elevation) ──
|
|
603
|
+
// Start the local runtime (api/agent/web/tray) at login/boot using only
|
|
604
|
+
// per-user mechanisms — no UAC/sudo. This is separate from the privileged mesh
|
|
605
|
+
// service: the mesh sidecar autostarts via the OS service manager; this brings
|
|
606
|
+
// up the unprivileged runtime that joins the mesh and serves the local API.
|
|
607
|
+
|
|
608
|
+
const AUTOSTART_LABEL = "online.timefiles.vantaloom.runtime"
|
|
609
|
+
// PowerShell HKCU: drive path. Set-ItemProperty handles values with spaces and
|
|
610
|
+
// embedded quotes cleanly (reg.exe's /d escaping is brittle), and the Run key is
|
|
611
|
+
// not blocked by Controlled Folder Access the way the Startup folder is.
|
|
612
|
+
const WINDOWS_RUN_KEY = "HKCU:\\Software\\Microsoft\\Windows\\CurrentVersion\\Run"
|
|
613
|
+
const WINDOWS_RUN_VALUE = "Vantaloom"
|
|
614
|
+
|
|
615
|
+
function enableRuntimeAutostart(prefix) {
|
|
616
|
+
try {
|
|
617
|
+
if (process.platform === "win32") {
|
|
618
|
+
// A .vbs launches the runtime with a hidden window (no console flash); the
|
|
619
|
+
// HKCU Run key runs it at login without elevation.
|
|
620
|
+
const launcher = path.join(prefix, "vantaloom.cmd")
|
|
621
|
+
const vbsPath = path.join(prefix, "autostart.vbs")
|
|
622
|
+
const vbs = `' Vantaloom runtime autostart (hidden)\r\nCreateObject("WScript.Shell").Run """${launcher}"" start", 0, False\r\n`
|
|
623
|
+
writeFileSync(vbsPath, vbs)
|
|
624
|
+
const result = spawnSync(
|
|
625
|
+
"powershell",
|
|
626
|
+
[
|
|
627
|
+
"-NoProfile",
|
|
628
|
+
"-NonInteractive",
|
|
629
|
+
"-Command",
|
|
630
|
+
`Set-ItemProperty -Path '${WINDOWS_RUN_KEY}' -Name '${WINDOWS_RUN_VALUE}' -Value 'wscript.exe "${vbsPath}"'`,
|
|
631
|
+
],
|
|
632
|
+
{ stdio: "ignore" }
|
|
633
|
+
)
|
|
634
|
+
if (result.error || result.status !== 0) {
|
|
635
|
+
console.warn(" autostart: could not register login entry (HKCU Run)")
|
|
636
|
+
} else {
|
|
637
|
+
console.log(" autostart: enabled (login Run key)")
|
|
638
|
+
}
|
|
639
|
+
return
|
|
640
|
+
}
|
|
641
|
+
if (process.platform === "darwin") {
|
|
642
|
+
const launcher = path.join(prefix, "vantaloom")
|
|
643
|
+
const dir = path.join(os.homedir(), "Library", "LaunchAgents")
|
|
644
|
+
mkdirSync(dir, { recursive: true })
|
|
645
|
+
const plistPath = path.join(dir, `${AUTOSTART_LABEL}.plist`)
|
|
646
|
+
// RunAtLoad only (no KeepAlive): `vantaloom start` spawns detached and exits.
|
|
647
|
+
const plist = `<?xml version="1.0" encoding="UTF-8"?>
|
|
648
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
649
|
+
<plist version="1.0"><dict>
|
|
650
|
+
<key>Label</key><string>${AUTOSTART_LABEL}</string>
|
|
651
|
+
<key>ProgramArguments</key><array><string>${launcher}</string><string>start</string></array>
|
|
652
|
+
<key>RunAtLoad</key><true/>
|
|
653
|
+
</dict></plist>
|
|
654
|
+
`
|
|
655
|
+
writeFileSync(plistPath, plist)
|
|
656
|
+
spawnSync("launchctl", ["unload", plistPath], { stdio: "ignore" })
|
|
657
|
+
spawnSync("launchctl", ["load", "-w", plistPath], { stdio: "ignore" })
|
|
658
|
+
console.log(" autostart: enabled (LaunchAgent)")
|
|
659
|
+
return
|
|
660
|
+
}
|
|
661
|
+
// Linux: user systemd unit + linger (no root).
|
|
662
|
+
const launcher = path.join(prefix, "vantaloom")
|
|
663
|
+
const dir = path.join(os.homedir(), ".config", "systemd", "user")
|
|
664
|
+
mkdirSync(dir, { recursive: true })
|
|
665
|
+
const unit = `[Unit]
|
|
666
|
+
Description=Vantaloom local runtime
|
|
667
|
+
After=network-online.target
|
|
668
|
+
Wants=network-online.target
|
|
669
|
+
|
|
670
|
+
[Service]
|
|
671
|
+
Type=oneshot
|
|
672
|
+
RemainAfterExit=yes
|
|
673
|
+
ExecStart=${launcher} start
|
|
674
|
+
ExecStop=${launcher} stop
|
|
675
|
+
|
|
676
|
+
[Install]
|
|
677
|
+
WantedBy=default.target
|
|
678
|
+
`
|
|
679
|
+
writeFileSync(path.join(dir, "vantaloom-runtime.service"), unit)
|
|
680
|
+
spawnSync("loginctl", ["enable-linger"], { stdio: "ignore" })
|
|
681
|
+
spawnSync("systemctl", ["--user", "daemon-reload"], { stdio: "ignore" })
|
|
682
|
+
spawnSync("systemctl", ["--user", "enable", "vantaloom-runtime.service"], { stdio: "ignore" })
|
|
683
|
+
console.log(" autostart: enabled (systemd user unit)")
|
|
684
|
+
} catch (error) {
|
|
685
|
+
console.warn(` autostart: could not enable (${error.message})`)
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
function disableRuntimeAutostart() {
|
|
690
|
+
try {
|
|
691
|
+
if (process.platform === "win32") {
|
|
692
|
+
// Remove the Run-key entry; the autostart.vbs lives in the install dir and
|
|
693
|
+
// is deleted with it.
|
|
694
|
+
spawnSync(
|
|
695
|
+
"powershell",
|
|
696
|
+
["-NoProfile", "-NonInteractive", "-Command", `Remove-ItemProperty -Path '${WINDOWS_RUN_KEY}' -Name '${WINDOWS_RUN_VALUE}' -ErrorAction SilentlyContinue`],
|
|
697
|
+
{ stdio: "ignore" }
|
|
698
|
+
)
|
|
699
|
+
return
|
|
700
|
+
}
|
|
701
|
+
if (process.platform === "darwin") {
|
|
702
|
+
const plistPath = path.join(os.homedir(), "Library", "LaunchAgents", `${AUTOSTART_LABEL}.plist`)
|
|
703
|
+
if (existsSync(plistPath)) {
|
|
704
|
+
spawnSync("launchctl", ["unload", "-w", plistPath], { stdio: "ignore" })
|
|
705
|
+
rmSync(plistPath, { force: true })
|
|
706
|
+
}
|
|
707
|
+
return
|
|
708
|
+
}
|
|
709
|
+
const unit = path.join(os.homedir(), ".config", "systemd", "user", "vantaloom-runtime.service")
|
|
710
|
+
if (existsSync(unit)) {
|
|
711
|
+
spawnSync("systemctl", ["--user", "disable", "vantaloom-runtime.service"], { stdio: "ignore" })
|
|
712
|
+
rmSync(unit, { force: true })
|
|
713
|
+
spawnSync("systemctl", ["--user", "daemon-reload"], { stdio: "ignore" })
|
|
714
|
+
}
|
|
715
|
+
} catch (error) {
|
|
716
|
+
console.warn(` autostart: could not disable (${error.message})`)
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
|
|
295
720
|
async function syncFromNpmRegistry(options, action) {
|
|
296
721
|
const prefix = safeDirectory(options.prefix ?? defaultPrefix())
|
|
297
722
|
const installedConfig = readInstalledConfig(prefix)
|
|
@@ -329,6 +754,8 @@ async function syncFromNpmRegistry(options, action) {
|
|
|
329
754
|
runtimeVersion: options.runtimeVersion ? resolved.version : "latest",
|
|
330
755
|
npmRegistry: resolved.registry,
|
|
331
756
|
update: action === "update",
|
|
757
|
+
withMesh: options.withMesh,
|
|
758
|
+
skipMesh: options.skipMesh,
|
|
332
759
|
})
|
|
333
760
|
|
|
334
761
|
console.log(`${action === "update" ? "updated" : "installed"} Vantaloom: ${prefix}`)
|
|
@@ -372,6 +799,8 @@ async function syncFromRelease(options, action) {
|
|
|
372
799
|
noStart: options.noStart,
|
|
373
800
|
sourceRoot: installedConfig.sourceRoot,
|
|
374
801
|
update: action === "update",
|
|
802
|
+
withMesh: options.withMesh,
|
|
803
|
+
skipMesh: options.skipMesh,
|
|
375
804
|
})
|
|
376
805
|
|
|
377
806
|
console.log(`${action === "update" ? "updated" : "installed"} Vantaloom: ${prefix}`)
|
|
@@ -970,6 +1399,15 @@ function parseOptions(args) {
|
|
|
970
1399
|
case "local":
|
|
971
1400
|
options.local = true
|
|
972
1401
|
break
|
|
1402
|
+
case "with-mesh":
|
|
1403
|
+
options.withMesh = true
|
|
1404
|
+
break
|
|
1405
|
+
case "skip-mesh":
|
|
1406
|
+
options.skipMesh = true
|
|
1407
|
+
break
|
|
1408
|
+
case "skip-autostart":
|
|
1409
|
+
options.skipAutostart = true
|
|
1410
|
+
break
|
|
973
1411
|
case "no-strict-ssl":
|
|
974
1412
|
options.noStrictSsl = true
|
|
975
1413
|
break
|
|
@@ -1184,17 +1622,23 @@ function printHelp() {
|
|
|
1184
1622
|
console.log(`Vantaloom CLI
|
|
1185
1623
|
|
|
1186
1624
|
Usage:
|
|
1187
|
-
vantaloom install
|
|
1188
|
-
vantaloom install
|
|
1189
|
-
vantaloom update
|
|
1190
|
-
vantaloom update
|
|
1191
|
-
vantaloom
|
|
1192
|
-
vantaloom
|
|
1193
|
-
vantaloom
|
|
1194
|
-
vantaloom
|
|
1195
|
-
vantaloom
|
|
1196
|
-
vantaloom
|
|
1197
|
-
vantaloom
|
|
1625
|
+
vantaloom install [--prefix <dir>] [--runtime-version <version>] [--npm-registry <url>] [--package <dir>] [--no-start] [--with-mesh|--skip-mesh]
|
|
1626
|
+
vantaloom install --local [--prefix <dir>] [--source <repo>] [--build-web] [--no-start] [--with-mesh]
|
|
1627
|
+
vantaloom update [--prefix <dir>] [--runtime-version <version>] [--npm-registry <url>] [--no-start] [--with-mesh|--skip-mesh]
|
|
1628
|
+
vantaloom update --local [--prefix <dir>] [--source <repo>] [--build-web] [--no-start] [--with-mesh]
|
|
1629
|
+
vantaloom uninstall [--prefix <dir>] [--skip-mesh]
|
|
1630
|
+
vantaloom package [--source <repo>] [--output <dir>] [--build-web] [--archive] [--npm-package] [--target <platform>]
|
|
1631
|
+
vantaloom start [--prefix <dir>] [--component all|api|agent|web]
|
|
1632
|
+
vantaloom stop [--prefix <dir>] [--component all|api|agent|web]
|
|
1633
|
+
vantaloom restart [--prefix <dir>] [--component all|api|agent|web]
|
|
1634
|
+
vantaloom status [--prefix <dir>]
|
|
1635
|
+
vantaloom ports [--prefix <dir>]
|
|
1636
|
+
vantaloom path [--prefix <dir>] [--source <repo>]
|
|
1198
1637
|
vantaloom platform
|
|
1638
|
+
|
|
1639
|
+
Mesh (P2P) service:
|
|
1640
|
+
Windows/macOS register a privileged EasyTier service at install (one UAC/sudo prompt).
|
|
1641
|
+
Linux grants TUN capability via setcap instead. Use --skip-mesh to opt out,
|
|
1642
|
+
or --with-mesh to force registration during a --local source install.
|
|
1199
1643
|
`)
|
|
1200
1644
|
}
|
package/manifest.json
CHANGED