tesseract-agent 0.9.20 → 0.9.22
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-bundle/cli.js +611 -272
- package/package.json +1 -1
package/dist-bundle/cli.js
CHANGED
|
@@ -63238,7 +63238,7 @@ var mesh_ca_exports = {};
|
|
|
63238
63238
|
__export(mesh_ca_exports, {
|
|
63239
63239
|
netCaCommand: () => netCaCommand
|
|
63240
63240
|
});
|
|
63241
|
-
import { chmodSync as chmodSync7, existsSync as existsSync35, mkdirSync as mkdirSync31, readFileSync as
|
|
63241
|
+
import { chmodSync as chmodSync7, existsSync as existsSync35, mkdirSync as mkdirSync31, readFileSync as readFileSync34, writeFileSync as writeFileSync31 } from "node:fs";
|
|
63242
63242
|
import { join as join62, resolve as resolve11 } from "node:path";
|
|
63243
63243
|
import { createInterface } from "node:readline";
|
|
63244
63244
|
function die(msg) {
|
|
@@ -63270,7 +63270,7 @@ async function readPassphrase(prompt) {
|
|
|
63270
63270
|
}
|
|
63271
63271
|
}
|
|
63272
63272
|
function writeSecretFile(p, bytes2) {
|
|
63273
|
-
|
|
63273
|
+
writeFileSync31(p, bytes2, { mode: 384 });
|
|
63274
63274
|
try {
|
|
63275
63275
|
chmodSync7(p, 384);
|
|
63276
63276
|
} catch {
|
|
@@ -63289,9 +63289,9 @@ async function openCa(dir2) {
|
|
|
63289
63289
|
if (!existsSync35(gPath) || !existsSync35(sPath)) {
|
|
63290
63290
|
die(`No mesh CA in ${dir2}. Run: tesseract-agent net init --org NAME --ca-dir ${dir2}`);
|
|
63291
63291
|
}
|
|
63292
|
-
const genesisBytes = new Uint8Array(
|
|
63292
|
+
const genesisBytes = new Uint8Array(readFileSync34(gPath));
|
|
63293
63293
|
const genesis = decodeGenesis(genesisBytes);
|
|
63294
|
-
const sealed = decodeRecoveryBundle(new Uint8Array(
|
|
63294
|
+
const sealed = decodeRecoveryBundle(new Uint8Array(readFileSync34(sPath)));
|
|
63295
63295
|
const pass = await readPassphrase("CA passphrase: ");
|
|
63296
63296
|
let seed;
|
|
63297
63297
|
try {
|
|
@@ -63329,7 +63329,7 @@ async function netCaCommand(rest, flags) {
|
|
|
63329
63329
|
const genesisBytes = encodeGenesis(genesis);
|
|
63330
63330
|
const fp = await genesisFingerprint(genesis);
|
|
63331
63331
|
ensureDir(caDir);
|
|
63332
|
-
|
|
63332
|
+
writeFileSync31(join62(caDir, "genesis.bin"), genesisBytes);
|
|
63333
63333
|
writeSecretFile(join62(caDir, "ca.sealed"), encodeRecoveryBundle(await sealCaKey(seed, pass, `${org} mesh CA`)));
|
|
63334
63334
|
writeSecretFile(join62(caDir, "disablement.secret"), hex3(disable.secret));
|
|
63335
63335
|
console.log(`
|
|
@@ -63399,8 +63399,8 @@ Next, issue an identity for a machine (pick a free address in ${formatPrefix(gen
|
|
|
63399
63399
|
[{ keyIndex: 0, privateKey: ca.privateKey }]
|
|
63400
63400
|
);
|
|
63401
63401
|
ensureDir(outDir);
|
|
63402
|
-
|
|
63403
|
-
|
|
63402
|
+
writeFileSync31(join62(outDir, "genesis.bin"), genesisBytes);
|
|
63403
|
+
writeFileSync31(join62(outDir, "node.cert"), encodeCert(cert));
|
|
63404
63404
|
writeSecretFile(join62(outDir, "node.key"), await exportStaticPrivate(nodeKey));
|
|
63405
63405
|
console.log(`Minted "${name}" at ${ip4}.`);
|
|
63406
63406
|
console.log(` ${outDir}`);
|
|
@@ -63443,7 +63443,7 @@ Next, issue an identity for a machine (pick a free address in ${formatPrefix(gen
|
|
|
63443
63443
|
};
|
|
63444
63444
|
const signed = await signBundle(bundle, [{ keyIndex: 0, privateKey: ca.privateKey }]);
|
|
63445
63445
|
const out = resolve11(typeof flags.out === "string" ? flags.out : join62(caDir, "bundle.bin"));
|
|
63446
|
-
|
|
63446
|
+
writeFileSync31(out, encodeSignedBundle(signed));
|
|
63447
63447
|
console.log(`Signed policy bundle (epoch ${epoch2}) \u2192 ${out}`);
|
|
63448
63448
|
console.log("Every node must receive it; the relay distributes it, or copy it to");
|
|
63449
63449
|
console.log(`each node's mesh directory as bundle.bin.`);
|
|
@@ -63465,9 +63465,9 @@ var init_mesh_ca = __esm({
|
|
|
63465
63465
|
|
|
63466
63466
|
// src/cli.ts
|
|
63467
63467
|
init_base_paths();
|
|
63468
|
-
import { existsSync as existsSync36, mkdtempSync as mkdtempSync2, readFileSync as
|
|
63468
|
+
import { existsSync as existsSync36, mkdtempSync as mkdtempSync2, readFileSync as readFileSync36, rmSync as rmSync10 } from "node:fs";
|
|
63469
63469
|
import { createHash as createHash8 } from "node:crypto";
|
|
63470
|
-
import { execFileSync as execFileSync5, spawn as
|
|
63470
|
+
import { execFileSync as execFileSync5, spawn as spawn13 } from "node:child_process";
|
|
63471
63471
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
63472
63472
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
63473
63473
|
import { dirname as dirname27, join as join63, resolve as resolve13 } from "node:path";
|
|
@@ -67085,6 +67085,7 @@ import { join as join20 } from "node:path";
|
|
|
67085
67085
|
// ../../packages/host-core/dist/gui/daemon-gui.js
|
|
67086
67086
|
import { join as join19, dirname as dirname8 } from "node:path";
|
|
67087
67087
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
67088
|
+
import { spawn as spawn6, spawnSync } from "node:child_process";
|
|
67088
67089
|
import { existsSync as existsSync9 } from "node:fs";
|
|
67089
67090
|
var el = null;
|
|
67090
67091
|
var guiReady = false;
|
|
@@ -67256,6 +67257,9 @@ function electronModule() {
|
|
|
67256
67257
|
function daemonGuiTrayActive() {
|
|
67257
67258
|
return guiReady && tray !== null;
|
|
67258
67259
|
}
|
|
67260
|
+
function daemonGuiReady() {
|
|
67261
|
+
return guiReady;
|
|
67262
|
+
}
|
|
67259
67263
|
var uiDirOverride = null;
|
|
67260
67264
|
var resolvedUiDir;
|
|
67261
67265
|
function daemonUiDir() {
|
|
@@ -67301,14 +67305,48 @@ Set CCB_DAEMON_UI_DIR to the directory containing preload.cjs, or rebuild the da
|
|
|
67301
67305
|
function daemonPreloadPath() {
|
|
67302
67306
|
return join19(daemonUiDir(), "preload.cjs");
|
|
67303
67307
|
}
|
|
67308
|
+
function devAppPath() {
|
|
67309
|
+
const env = process.env.CCB_APP_DIR;
|
|
67310
|
+
if (env)
|
|
67311
|
+
return env;
|
|
67312
|
+
const daemonEntry = process.argv[1];
|
|
67313
|
+
if (daemonEntry) {
|
|
67314
|
+
const cand = join19(dirname8(daemonEntry), "..", "..", "desktop");
|
|
67315
|
+
if (existsSync9(join19(cand, "package.json")))
|
|
67316
|
+
return cand;
|
|
67317
|
+
}
|
|
67318
|
+
return null;
|
|
67319
|
+
}
|
|
67320
|
+
async function reExecMainApp(url2) {
|
|
67321
|
+
try {
|
|
67322
|
+
const env = { ...process.env };
|
|
67323
|
+
delete env.CCB_DAEMON_GUI;
|
|
67324
|
+
delete env.CCB_FORCE_DAEMON_GUI;
|
|
67325
|
+
delete env.ELECTRON_RUN_AS_NODE;
|
|
67326
|
+
const appPath = el?.app?.isPackaged === false ? devAppPath() : null;
|
|
67327
|
+
const args = appPath ? [appPath, url2] : [url2];
|
|
67328
|
+
log2(`openMainApp: re-exec ${process.execPath} ${args.join(" ")}`);
|
|
67329
|
+
const child = spawn6(process.execPath, args, { detached: true, stdio: "ignore", env });
|
|
67330
|
+
child.on("error", (e) => log2("openMainApp: spawn failed:", e instanceof Error ? e.message : String(e)));
|
|
67331
|
+
child.unref();
|
|
67332
|
+
} catch (e) {
|
|
67333
|
+
log2("openMainApp failed:", e instanceof Error ? e.message : String(e));
|
|
67334
|
+
}
|
|
67335
|
+
}
|
|
67336
|
+
async function openMainApp(sessionId) {
|
|
67337
|
+
return reExecMainApp(sessionId ? `tesseract://resume/${encodeURIComponent(sessionId)}` : "tesseract://open");
|
|
67338
|
+
}
|
|
67339
|
+
async function openMainAppSettings() {
|
|
67340
|
+
return reExecMainApp("tesseract://settings");
|
|
67341
|
+
}
|
|
67304
67342
|
|
|
67305
67343
|
// ../../packages/host-core/dist/os-control-runner.js
|
|
67306
|
-
import { spawn as
|
|
67344
|
+
import { spawn as spawn7 } from "node:child_process";
|
|
67307
67345
|
var IS_MAC = process.platform === "darwin";
|
|
67308
67346
|
var log3 = (...a) => console.log("[os-control]", ...a);
|
|
67309
67347
|
function capture(command, args, opts = {}) {
|
|
67310
67348
|
return new Promise((resolve14) => {
|
|
67311
|
-
const child =
|
|
67349
|
+
const child = spawn7(command, args, { cwd: opts.cwd, windowsHide: true });
|
|
67312
67350
|
const max = opts.maxBuffer ?? 4 * 1024 * 1024;
|
|
67313
67351
|
let out = "";
|
|
67314
67352
|
let err2 = "";
|
|
@@ -67667,10 +67705,11 @@ function askRdeskConsent(opts) {
|
|
|
67667
67705
|
win3.setAlwaysOnTop(true, "screen-saver");
|
|
67668
67706
|
win3.setVisibleOnAllWorkspaces(true, { visibleOnFullScreen: true });
|
|
67669
67707
|
const reqId = randomUUID9();
|
|
67670
|
-
const who = opts.viewerName ?
|
|
67708
|
+
const who = opts.viewerName ? `Someone calling themselves \u201C${opts.viewerName}\u201D` : "Someone";
|
|
67671
67709
|
void win3.loadFile(uiPath("consent.html")).then(() => {
|
|
67672
67710
|
try {
|
|
67673
|
-
|
|
67711
|
+
const how = opts.grant === "password" ? " They used this machine\u2019s unattended password." : "";
|
|
67712
|
+
win3.webContents.send("consent:show", { reqId, title: "Allow remote desktop access?", body: `${who} wants to view and control this computer.${how}` });
|
|
67674
67713
|
win3.show();
|
|
67675
67714
|
win3.focus();
|
|
67676
67715
|
el2.app.focus?.({ steal: true });
|
|
@@ -71682,14 +71721,14 @@ import { randomUUID as randomUUID14 } from "node:crypto";
|
|
|
71682
71721
|
|
|
71683
71722
|
// ../../packages/host-core/dist/video-edit.js
|
|
71684
71723
|
init_base_paths();
|
|
71685
|
-
import { spawn as
|
|
71724
|
+
import { spawn as spawn8 } from "node:child_process";
|
|
71686
71725
|
import { mkdirSync as mkdirSync11, readFileSync as readFileSync16, rmSync as rmSync4, writeFileSync as writeFileSync12 } from "node:fs";
|
|
71687
71726
|
import { join as join25, isAbsolute as isAbsolute4 } from "node:path";
|
|
71688
71727
|
import { randomUUID as randomUUID13 } from "node:crypto";
|
|
71689
71728
|
|
|
71690
71729
|
// ../../packages/host-core/dist/ffmpeg.js
|
|
71691
71730
|
import { existsSync as existsSync11 } from "node:fs";
|
|
71692
|
-
import { spawnSync } from "node:child_process";
|
|
71731
|
+
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
71693
71732
|
import { sep as sep4 } from "node:path";
|
|
71694
71733
|
import { createRequire as createRequire3 } from "node:module";
|
|
71695
71734
|
var require_ = createRequire3(import.meta.url);
|
|
@@ -71708,7 +71747,7 @@ function fromPackage(name) {
|
|
|
71708
71747
|
}
|
|
71709
71748
|
function fromPath(cmd) {
|
|
71710
71749
|
try {
|
|
71711
|
-
const r =
|
|
71750
|
+
const r = spawnSync2(cmd, ["-version"], { stdio: "ignore", timeout: 5e3 });
|
|
71712
71751
|
return r.status === 0 ? cmd : null;
|
|
71713
71752
|
} catch {
|
|
71714
71753
|
return null;
|
|
@@ -71790,7 +71829,7 @@ function run(bin, args, opts) {
|
|
|
71790
71829
|
let timedOut = false;
|
|
71791
71830
|
let child;
|
|
71792
71831
|
try {
|
|
71793
|
-
child =
|
|
71832
|
+
child = spawn8(bin, args, { cwd: opts?.cwd ?? mediaSpawnCwd(), stdio: ["ignore", "pipe", "pipe"] });
|
|
71794
71833
|
} catch (e) {
|
|
71795
71834
|
reject(e instanceof Error ? e : new Error(String(e)));
|
|
71796
71835
|
return;
|
|
@@ -71869,7 +71908,7 @@ async function renderEdl(edl, opts) {
|
|
|
71869
71908
|
const { args, expectedDurationSec } = compileEdl(edl, { outPath, assFile, encoder, assetInfo });
|
|
71870
71909
|
const watchdogMs = Math.min(45 * 6e4, Math.max(LONG_TIMEOUT_MS, Math.round((expectedDurationSec ?? 0) * 4e3)));
|
|
71871
71910
|
await new Promise((resolve14, reject) => {
|
|
71872
|
-
const child =
|
|
71911
|
+
const child = spawn8(resolveFfmpeg(), ["-y", "-hide_banner", "-nostats", "-progress", "pipe:1", ...args], { cwd: mediaSpawnCwd(), stdio: ["ignore", "pipe", "pipe"] });
|
|
71873
71912
|
let stderrTail = "";
|
|
71874
71913
|
let stdoutBuf = "";
|
|
71875
71914
|
let timedOut = false;
|
|
@@ -71953,7 +71992,7 @@ async function enhanceVideo(path6, spec, opts) {
|
|
|
71953
71992
|
const watchdogMs = Math.min(45 * 6e4, Math.max(LONG_TIMEOUT_MS, Math.round(expected * 8e3)));
|
|
71954
71993
|
const summary = chain2.steps.join(" \xB7 ");
|
|
71955
71994
|
await new Promise((resolve14, reject) => {
|
|
71956
|
-
const child =
|
|
71995
|
+
const child = spawn8(resolveFfmpeg(), ["-y", "-hide_banner", "-nostats", "-progress", "pipe:1", ...args], { cwd: mediaSpawnCwd(), stdio: ["ignore", "pipe", "pipe"] });
|
|
71957
71996
|
let stderrTail = "";
|
|
71958
71997
|
let stdoutBuf = "";
|
|
71959
71998
|
let timedOut = false;
|
|
@@ -72117,7 +72156,7 @@ function readChunkBase64(path6) {
|
|
|
72117
72156
|
|
|
72118
72157
|
// ../../packages/host-core/dist/video-upscale.js
|
|
72119
72158
|
init_base_paths();
|
|
72120
|
-
import { spawn as
|
|
72159
|
+
import { spawn as spawn9 } from "node:child_process";
|
|
72121
72160
|
import { existsSync as existsSync12, mkdirSync as mkdirSync12, readFileSync as readFileSync17, readdirSync as readdirSync5 } from "node:fs";
|
|
72122
72161
|
import { join as join26, dirname as dirname11 } from "node:path";
|
|
72123
72162
|
var upscaleCwd;
|
|
@@ -72145,7 +72184,7 @@ function resolveRealesrgan() {
|
|
|
72145
72184
|
}
|
|
72146
72185
|
function fromPath2(cmd) {
|
|
72147
72186
|
try {
|
|
72148
|
-
const r =
|
|
72187
|
+
const r = spawn9(cmd, ["-h"], { stdio: "ignore" });
|
|
72149
72188
|
r.on("error", () => {
|
|
72150
72189
|
});
|
|
72151
72190
|
r.kill();
|
|
@@ -72190,7 +72229,7 @@ async function realesrganGpuWorks() {
|
|
|
72190
72229
|
return false;
|
|
72191
72230
|
}
|
|
72192
72231
|
await new Promise((resolve14, reject) => {
|
|
72193
|
-
const c =
|
|
72232
|
+
const c = spawn9(re.bin, ["-i", inP, "-o", outP, "-n", model, "-s", "2", "-m", re.models, "-g", "0"], { cwd: upscaleSpawnCwd(), stdio: "ignore" });
|
|
72194
72233
|
const t = setTimeout(() => {
|
|
72195
72234
|
c.kill("SIGKILL");
|
|
72196
72235
|
reject(new Error("probe timeout"));
|
|
@@ -72289,7 +72328,7 @@ async function realesrganUpscale(path6, opts) {
|
|
|
72289
72328
|
if (!nFrames)
|
|
72290
72329
|
throw new Error("No frames extracted.");
|
|
72291
72330
|
await new Promise((resolve14, reject) => {
|
|
72292
|
-
const child =
|
|
72331
|
+
const child = spawn9(re.bin, ["-i", fin, "-o", fup, "-n", model, "-s", String(scale), "-m", re.models, "-f", "png", "-g", "0"], { cwd: upscaleSpawnCwd(), stdio: ["ignore", "pipe", "pipe"] });
|
|
72293
72332
|
let tail3 = "";
|
|
72294
72333
|
const timer = setTimeout(() => child.kill("SIGKILL"), 45 * 6e4);
|
|
72295
72334
|
child.stderr.on("data", (d) => {
|
|
@@ -72368,8 +72407,8 @@ async function falTopazEnhance(path6, spec, opts) {
|
|
|
72368
72407
|
const dir2 = opts.outDir ?? workDir();
|
|
72369
72408
|
mkdirSync12(dir2, { recursive: true });
|
|
72370
72409
|
const outPath = join26(dir2, "enhanced.mp4");
|
|
72371
|
-
const { writeFileSync:
|
|
72372
|
-
|
|
72410
|
+
const { writeFileSync: writeFileSync32 } = await import("node:fs");
|
|
72411
|
+
writeFileSync32(outPath, Buffer.from(await dl.arrayBuffer()));
|
|
72373
72412
|
const out = await probeMedia(outPath).catch(() => null);
|
|
72374
72413
|
opts.onProgress?.(100, "Enhance complete");
|
|
72375
72414
|
return { path: outPath, mime: MIME, width: out?.width ?? null, height: out?.height ?? null, durationSec: out?.durationSec ?? p.durationSec, summary: `fal Topaz ${spec.model ?? "Proteus"} \xD7${spec.upscaleFactor ?? 2}` };
|
|
@@ -74223,12 +74262,12 @@ async function dirStats(root, opts) {
|
|
|
74223
74262
|
}
|
|
74224
74263
|
async function codeStats(root) {
|
|
74225
74264
|
const start3 = Date.now();
|
|
74226
|
-
const MAX_FILES = 25e3,
|
|
74265
|
+
const MAX_FILES = 25e3, MAX_BYTES2 = 256 * 1024 * 1024, TIME_MS = 12e3;
|
|
74227
74266
|
const byLang = /* @__PURE__ */ new Map();
|
|
74228
74267
|
let totalFiles = 0, totalLines = 0, bytes2 = 0, truncated = false;
|
|
74229
74268
|
const stack = [root];
|
|
74230
74269
|
while (stack.length) {
|
|
74231
|
-
if (totalFiles >= MAX_FILES || bytes2 >=
|
|
74270
|
+
if (totalFiles >= MAX_FILES || bytes2 >= MAX_BYTES2 || Date.now() - start3 > TIME_MS) {
|
|
74232
74271
|
truncated = true;
|
|
74233
74272
|
break;
|
|
74234
74273
|
}
|
|
@@ -74240,7 +74279,7 @@ async function codeStats(root) {
|
|
|
74240
74279
|
continue;
|
|
74241
74280
|
}
|
|
74242
74281
|
for (const e of ents) {
|
|
74243
|
-
if (totalFiles >= MAX_FILES || bytes2 >=
|
|
74282
|
+
if (totalFiles >= MAX_FILES || bytes2 >= MAX_BYTES2 || Date.now() - start3 > TIME_MS) {
|
|
74244
74283
|
truncated = true;
|
|
74245
74284
|
break;
|
|
74246
74285
|
}
|
|
@@ -78509,8 +78548,8 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
78509
78548
|
}
|
|
78510
78549
|
return this._userIgnored(path6, stats);
|
|
78511
78550
|
}
|
|
78512
|
-
_isntIgnored(path6,
|
|
78513
|
-
return !this._isIgnored(path6,
|
|
78551
|
+
_isntIgnored(path6, stat8) {
|
|
78552
|
+
return !this._isIgnored(path6, stat8);
|
|
78514
78553
|
}
|
|
78515
78554
|
/**
|
|
78516
78555
|
* Provides a set of common helpers and properties relating to symlink handling.
|
|
@@ -80079,18 +80118,40 @@ function assertServerSelection() {
|
|
|
80079
80118
|
send2("host", { type: "host:select", hostId: serverSelected ? SERVER_HOST_ID : ownHostId() });
|
|
80080
80119
|
}
|
|
80081
80120
|
var iceWaiters = [];
|
|
80121
|
+
var lastIce = null;
|
|
80122
|
+
var ICE_CACHE_MAX_AGE_MS = 5 * 6e4;
|
|
80123
|
+
var iceReqSeq = 0;
|
|
80124
|
+
function rememberIce(servers) {
|
|
80125
|
+
lastIce = { servers, at: Date.now() };
|
|
80126
|
+
}
|
|
80082
80127
|
function fetchIceServers() {
|
|
80083
|
-
|
|
80084
|
-
|
|
80085
|
-
|
|
80128
|
+
const ask2 = () => new Promise((resolve14) => {
|
|
80129
|
+
const id = `ice-${++iceReqSeq}`;
|
|
80130
|
+
const waiter = (servers) => resolve14(servers);
|
|
80131
|
+
iceWaiters.push(waiter);
|
|
80132
|
+
send2("signal", { type: "signal:get-ice" }, { browserId: id });
|
|
80086
80133
|
setTimeout(() => {
|
|
80087
|
-
const i = iceWaiters.indexOf(
|
|
80134
|
+
const i = iceWaiters.indexOf(waiter);
|
|
80088
80135
|
if (i >= 0) {
|
|
80089
80136
|
iceWaiters.splice(i, 1);
|
|
80090
|
-
resolve14(
|
|
80137
|
+
resolve14(null);
|
|
80091
80138
|
}
|
|
80092
80139
|
}, 2500);
|
|
80093
80140
|
});
|
|
80141
|
+
return (async () => {
|
|
80142
|
+
const first = await ask2();
|
|
80143
|
+
if (first)
|
|
80144
|
+
return first;
|
|
80145
|
+
const second = await ask2();
|
|
80146
|
+
if (second)
|
|
80147
|
+
return second;
|
|
80148
|
+
if (lastIce && Date.now() - lastIce.at < ICE_CACHE_MAX_AGE_MS) {
|
|
80149
|
+
console.log("[control-link] ice: relay did not answer get-ice; reusing the last minted list (TURN still available)");
|
|
80150
|
+
return lastIce.servers;
|
|
80151
|
+
}
|
|
80152
|
+
console.log("[control-link] ice: relay did not answer get-ice; falling back to public STUN \u2014 NO TURN, a session that needs a relay will fail");
|
|
80153
|
+
return DEFAULT_ICE_SERVERS;
|
|
80154
|
+
})();
|
|
80094
80155
|
}
|
|
80095
80156
|
function relayBrowser(payload, clientId) {
|
|
80096
80157
|
send2("browser", payload, { clientId });
|
|
@@ -80803,7 +80864,8 @@ function registerAsHost() {
|
|
|
80803
80864
|
const kind = process.env.CCB_HOST_KIND === "cloud" ? "cloud" : void 0;
|
|
80804
80865
|
const name = kind === "cloud" ? "Cloud agent" : hostname3();
|
|
80805
80866
|
const caps = hostSessions ? ["agent", "fs", "term", "e2e"] : ["agent", "fs", "term"];
|
|
80806
|
-
|
|
80867
|
+
if (hooks?.onRdesk)
|
|
80868
|
+
caps.push("rdesk");
|
|
80807
80869
|
caps.push("xfer");
|
|
80808
80870
|
const upAdvert = upscaleAdvert();
|
|
80809
80871
|
if (upAdvert.gpu)
|
|
@@ -80888,6 +80950,10 @@ function connect() {
|
|
|
80888
80950
|
hooks?.onDrop?.(env.payload);
|
|
80889
80951
|
return;
|
|
80890
80952
|
}
|
|
80953
|
+
if (channel === "rdesk-req") {
|
|
80954
|
+
hooks?.onRdeskRequest?.(env.payload);
|
|
80955
|
+
return;
|
|
80956
|
+
}
|
|
80891
80957
|
if (channel === "p2p") {
|
|
80892
80958
|
const m = env.payload;
|
|
80893
80959
|
for (const cb of [...p2pSubscribers])
|
|
@@ -81042,6 +81108,7 @@ function connect() {
|
|
|
81042
81108
|
if (channel === "signal") {
|
|
81043
81109
|
const p = env.payload;
|
|
81044
81110
|
if (p?.type === "signal:ready" && Array.isArray(p.iceServers)) {
|
|
81111
|
+
rememberIce(p.iceServers);
|
|
81045
81112
|
const waiters = iceWaiters;
|
|
81046
81113
|
iceWaiters = [];
|
|
81047
81114
|
for (const r of waiters)
|
|
@@ -81265,9 +81332,17 @@ async function createRemoteDesktopEngine(kind, ctx2) {
|
|
|
81265
81332
|
function grantOf(msg) {
|
|
81266
81333
|
return msg.auth.kind;
|
|
81267
81334
|
}
|
|
81335
|
+
var PW_FREE_ATTEMPTS = 3;
|
|
81336
|
+
var PW_BACKOFF_BASE_MS = 2e3;
|
|
81337
|
+
var PW_BACKOFF_MAX_MS = 15 * 6e4;
|
|
81338
|
+
var PW_FAILURE_DECAY_MS = 30 * 6e4;
|
|
81268
81339
|
var RdeskSessionManager = class {
|
|
81269
81340
|
sessions = /* @__PURE__ */ new Map();
|
|
81270
81341
|
deps;
|
|
81342
|
+
/** Consecutive failed password attempts, and the time the lockout expires. */
|
|
81343
|
+
pwFailures = 0;
|
|
81344
|
+
pwLockedUntil = 0;
|
|
81345
|
+
pwLastFailureAt = 0;
|
|
81271
81346
|
constructor(deps) {
|
|
81272
81347
|
this.deps = deps;
|
|
81273
81348
|
}
|
|
@@ -81282,7 +81357,14 @@ var RdeskSessionManager = class {
|
|
|
81282
81357
|
this.deps.log?.(`[rdesk] ${msg}`);
|
|
81283
81358
|
}
|
|
81284
81359
|
now() {
|
|
81285
|
-
return Date.now();
|
|
81360
|
+
return this.deps.now?.() ?? Date.now();
|
|
81361
|
+
}
|
|
81362
|
+
/** How long the password gate stays shut after repeated failures (exponential, capped). */
|
|
81363
|
+
pwBackoffMs() {
|
|
81364
|
+
const over = this.pwFailures - PW_FREE_ATTEMPTS;
|
|
81365
|
+
if (over <= 0)
|
|
81366
|
+
return 0;
|
|
81367
|
+
return Math.min(PW_BACKOFF_BASE_MS * 2 ** (over - 1), PW_BACKOFF_MAX_MS);
|
|
81286
81368
|
}
|
|
81287
81369
|
audit(e) {
|
|
81288
81370
|
this.deps.audit?.({ at: this.now(), ...e });
|
|
@@ -81303,7 +81385,9 @@ var RdeskSessionManager = class {
|
|
|
81303
81385
|
}
|
|
81304
81386
|
/** Handle a viewer's `rdesk:connect`. Runs the grant→consent policy, then builds +
|
|
81305
81387
|
* starts the engine and replies `rdesk:accepted`, or replies `rdesk:denied`. */
|
|
81306
|
-
async onConnect(sessionId,
|
|
81388
|
+
async onConnect(sessionId, viewerIn, msg) {
|
|
81389
|
+
const declared = typeof msg.viewerName === "string" ? msg.viewerName.trim().slice(0, 60) : "";
|
|
81390
|
+
const viewer = viewerIn.name || !declared ? viewerIn : { ...viewerIn, name: declared };
|
|
81307
81391
|
const grant0 = grantOf(msg);
|
|
81308
81392
|
this.audit({ event: "connect", sessionId, viewerUserId: viewer.userId, viewerName: viewer.name, grant: grant0 });
|
|
81309
81393
|
const deny = (reason) => {
|
|
@@ -81315,24 +81399,48 @@ var RdeskSessionManager = class {
|
|
|
81315
81399
|
return deny("entitlement");
|
|
81316
81400
|
if (this.sessions.has(sessionId))
|
|
81317
81401
|
return deny("busy");
|
|
81402
|
+
const maxSessions = this.deps.maxSessions ?? 3;
|
|
81403
|
+
if (maxSessions > 0 && this.sessions.size >= maxSessions) {
|
|
81404
|
+
this.log(`connect refused sessionId=${sessionId} \u2014 at the ${maxSessions}-session limit`);
|
|
81405
|
+
return deny("busy");
|
|
81406
|
+
}
|
|
81318
81407
|
const grant = grantOf(msg);
|
|
81319
81408
|
if (grant === "password") {
|
|
81409
|
+
if (this.now() < this.pwLockedUntil) {
|
|
81410
|
+
this.log(`password attempt refused \u2014 locked for ${Math.ceil((this.pwLockedUntil - this.now()) / 1e3)}s`);
|
|
81411
|
+
this.audit({ event: "deny", sessionId, grant, detail: "password-locked" });
|
|
81412
|
+
return deny("password");
|
|
81413
|
+
}
|
|
81414
|
+
if (this.pwLastFailureAt && this.now() - this.pwLastFailureAt > PW_FAILURE_DECAY_MS) {
|
|
81415
|
+
this.pwFailures = 0;
|
|
81416
|
+
this.pwLockedUntil = 0;
|
|
81417
|
+
}
|
|
81320
81418
|
const pw = msg.auth.kind === "password" ? msg.auth.password : "";
|
|
81321
81419
|
const ok = await this.deps.checkPassword(pw);
|
|
81322
|
-
if (!ok)
|
|
81420
|
+
if (!ok) {
|
|
81421
|
+
this.pwFailures += 1;
|
|
81422
|
+
this.pwLastFailureAt = this.now();
|
|
81423
|
+
const backoff = this.pwBackoffMs();
|
|
81424
|
+
if (backoff > 0) {
|
|
81425
|
+
this.pwLockedUntil = this.now() + backoff;
|
|
81426
|
+
this.log(`password failed ${this.pwFailures}\xD7 \u2014 locking the password gate for ${Math.round(backoff / 1e3)}s`);
|
|
81427
|
+
}
|
|
81323
81428
|
return deny("password");
|
|
81429
|
+
}
|
|
81430
|
+
this.pwFailures = 0;
|
|
81431
|
+
this.pwLockedUntil = 0;
|
|
81432
|
+
this.pwLastFailureAt = 0;
|
|
81324
81433
|
} else if (grant === "code") {
|
|
81325
81434
|
const allowed = await this.deps.consent({ sessionId, viewerName: viewer.name, grant });
|
|
81326
81435
|
if (!allowed)
|
|
81327
81436
|
return deny("consent");
|
|
81328
81437
|
}
|
|
81329
|
-
const
|
|
81330
|
-
const accessLevel =
|
|
81438
|
+
const da = this.deps.defaultAccess;
|
|
81439
|
+
const accessLevel = (typeof da === "function" ? da() : da) ?? "view";
|
|
81331
81440
|
const engineKind = msg.engine ?? "tesseract";
|
|
81332
81441
|
const ctx2 = {
|
|
81333
81442
|
sessionId,
|
|
81334
81443
|
accessLevel,
|
|
81335
|
-
forceRelay,
|
|
81336
81444
|
sendSignal: (m) => this.deps.sendSignal(sessionId, viewer.clientId, m),
|
|
81337
81445
|
sendControl: (m) => this.deps.sendControl(sessionId, viewer.clientId, m),
|
|
81338
81446
|
sendData: (_m) => {
|
|
@@ -81342,7 +81450,8 @@ var RdeskSessionManager = class {
|
|
|
81342
81450
|
let engine;
|
|
81343
81451
|
try {
|
|
81344
81452
|
engine = await this.deps.createEngine(engineKind, ctx2);
|
|
81345
|
-
|
|
81453
|
+
const dq = this.deps.defaultQuality;
|
|
81454
|
+
await engine.start({ monitorId: void 0, quality: (typeof dq === "function" ? dq() : dq) ?? "auto" });
|
|
81346
81455
|
} catch (e) {
|
|
81347
81456
|
this.log(`engine start failed sessionId=${sessionId}: ${e instanceof Error ? e.message : String(e)}`);
|
|
81348
81457
|
return deny("offline");
|
|
@@ -81351,9 +81460,9 @@ var RdeskSessionManager = class {
|
|
|
81351
81460
|
const sources = await engine.listSources?.().catch(() => []) ?? [];
|
|
81352
81461
|
const activeMonitor = monitors.find((m) => m.primary)?.id ?? monitors[0]?.id ?? "";
|
|
81353
81462
|
const activeSource = sources.find((s) => s.kind === "screen" && s.primary)?.id ?? sources[0]?.id ?? "";
|
|
81354
|
-
const session = { sessionId, viewer, grant, accessLevel,
|
|
81463
|
+
const session = { sessionId, viewer, grant, accessLevel, engine, startedAt: this.now() };
|
|
81355
81464
|
this.sessions.set(sessionId, session);
|
|
81356
|
-
this.log(`accepted sessionId=${sessionId} grant=${grant} engine=${engine.id} access=${accessLevel}
|
|
81465
|
+
this.log(`accepted sessionId=${sessionId} grant=${grant} engine=${engine.id} access=${accessLevel}`);
|
|
81357
81466
|
this.audit({ event: "accept", sessionId, viewerUserId: viewer.userId, viewerName: viewer.name, grant, detail: `engine=${engine.id}` });
|
|
81358
81467
|
this.deps.sendControl(sessionId, viewer.clientId, {
|
|
81359
81468
|
type: "rdesk:accepted",
|
|
@@ -81363,8 +81472,7 @@ var RdeskSessionManager = class {
|
|
|
81363
81472
|
activeMonitor,
|
|
81364
81473
|
sources,
|
|
81365
81474
|
activeSource,
|
|
81366
|
-
caps: engine.capabilities()
|
|
81367
|
-
forceRelay
|
|
81475
|
+
caps: engine.capabilities()
|
|
81368
81476
|
});
|
|
81369
81477
|
this.changed();
|
|
81370
81478
|
}
|
|
@@ -81387,12 +81495,20 @@ var RdeskSessionManager = class {
|
|
|
81387
81495
|
this.changed();
|
|
81388
81496
|
}
|
|
81389
81497
|
/** A viewer asks for control (view→control). Own-fleet auto-grants; cross-account
|
|
81390
|
-
* runs the consent prompt. Denial simply leaves the session view-only.
|
|
81498
|
+
* runs the consent prompt. Denial simply leaves the session view-only.
|
|
81499
|
+
*
|
|
81500
|
+
* The decision keys off `grant` ALONE. It used to also accept `viewer.sameAccount`, but
|
|
81501
|
+
* that flag was hardcoded `true` at every production call site (the relay hook has no
|
|
81502
|
+
* userId to derive it from), so this test always passed and ANY cross-account viewer —
|
|
81503
|
+
* including an unattended password one — could silently escalate view→control with no
|
|
81504
|
+
* prompt, and could instantly undo a host that demoted them back to view. `grant` is
|
|
81505
|
+
* resolved in onConnect, stored per session and immutable, and `registry` IS same-account
|
|
81506
|
+
* by construction (the relay only exposes own-account hosts in host:list). */
|
|
81391
81507
|
async requestControl(sessionId) {
|
|
81392
81508
|
const s = this.sessions.get(sessionId);
|
|
81393
81509
|
if (!s || s.accessLevel === "control")
|
|
81394
81510
|
return;
|
|
81395
|
-
let allow = s.grant === "registry"
|
|
81511
|
+
let allow = s.grant === "registry";
|
|
81396
81512
|
if (!allow)
|
|
81397
81513
|
allow = await this.deps.consent({ sessionId, viewerName: s.viewer.name, grant: s.grant });
|
|
81398
81514
|
if (allow)
|
|
@@ -81469,6 +81585,7 @@ var RdeskSessionManager = class {
|
|
|
81469
81585
|
}
|
|
81470
81586
|
if (msg.type === "rdesk:av") {
|
|
81471
81587
|
const s = this.sessions.get(sessionId);
|
|
81588
|
+
s?.engine.setAv?.(msg.on);
|
|
81472
81589
|
this.deps.onCall?.({ sessionId, on: msg.on, viewerName: s?.viewer.name });
|
|
81473
81590
|
this.audit({ event: "call", sessionId, detail: msg.on ? "viewer joined call" : "viewer left call" });
|
|
81474
81591
|
return;
|
|
@@ -81537,6 +81654,7 @@ function ensureIpc() {
|
|
|
81537
81654
|
}));
|
|
81538
81655
|
el2.ipcMain.on("rdesk:pub:ready", (_e, p) => route2(p, (w) => w.handlers.onReady()));
|
|
81539
81656
|
el2.ipcMain.on("rdesk:pub:error", (_e, p) => route2(p, (w, x) => w.handlers.onError(String(x.error ?? "publisher error"))));
|
|
81657
|
+
el2.ipcMain.on("rdesk:pub:path", (_e, p) => route2(p, (w, x) => w.handlers.onPath?.(String(x.path ?? "unknown"), { localType: x.localType ?? null, remoteType: x.remoteType ?? null })));
|
|
81540
81658
|
el2.ipcMain.on("rdesk:pub:stopped", (_e, p) => route2(p, (w) => w.onStoppedAck()));
|
|
81541
81659
|
}
|
|
81542
81660
|
async function listPublisherMonitors() {
|
|
@@ -81639,7 +81757,6 @@ var PublisherWindow = class {
|
|
|
81639
81757
|
sessionId: this.sessionId,
|
|
81640
81758
|
sourceId,
|
|
81641
81759
|
iceServers: opts.iceServers,
|
|
81642
|
-
forceRelay: opts.forceRelay,
|
|
81643
81760
|
quality: opts.quality ?? "auto",
|
|
81644
81761
|
systemAudio: opts.systemAudio ?? false,
|
|
81645
81762
|
maxWidth: opts.maxWidth,
|
|
@@ -81654,6 +81771,10 @@ var PublisherWindow = class {
|
|
|
81654
81771
|
/** Create the hidden window in CANVAS mode: no local capture — the RDP/VNC engine
|
|
81655
81772
|
* pushes framebuffer rects via {@link pushFrame}, which are painted to a canvas that
|
|
81656
81773
|
* is captureStream()'d into the same WebRTC PeerConnection. Reuses the whole pipeline. */
|
|
81774
|
+
/** Turn two-way voice on/off on THIS peer connection (the publisher re-offers). */
|
|
81775
|
+
setAv(on) {
|
|
81776
|
+
this.win?.webContents.send("rdesk:pub:av", { sessionId: this.sessionId, on });
|
|
81777
|
+
}
|
|
81657
81778
|
async startCanvas(opts) {
|
|
81658
81779
|
const el2 = electronModule();
|
|
81659
81780
|
if (!el2?.BrowserWindow)
|
|
@@ -81681,7 +81802,6 @@ var PublisherWindow = class {
|
|
|
81681
81802
|
sessionId: this.sessionId,
|
|
81682
81803
|
mode: "canvas",
|
|
81683
81804
|
iceServers: opts.iceServers,
|
|
81684
|
-
forceRelay: opts.forceRelay,
|
|
81685
81805
|
quality: opts.quality ?? "auto",
|
|
81686
81806
|
width: opts.width,
|
|
81687
81807
|
height: opts.height,
|
|
@@ -81719,7 +81839,6 @@ var PublisherWindow = class {
|
|
|
81719
81839
|
sessionId: this.sessionId,
|
|
81720
81840
|
sourceId,
|
|
81721
81841
|
iceServers: opts.iceServers,
|
|
81722
|
-
forceRelay: opts.forceRelay,
|
|
81723
81842
|
quality: opts.quality ?? "auto",
|
|
81724
81843
|
systemAudio: opts.systemAudio ?? false,
|
|
81725
81844
|
maxWidth: opts.maxWidth,
|
|
@@ -81931,21 +82050,32 @@ var TesseractEngine = class {
|
|
|
81931
82050
|
this.deps = deps;
|
|
81932
82051
|
this.access = ctx2.accessLevel;
|
|
81933
82052
|
}
|
|
82053
|
+
/**
|
|
82054
|
+
* What this session can ACTUALLY do, derived at runtime.
|
|
82055
|
+
*
|
|
82056
|
+
* This used to be a hardcoded constant returned identically on every platform, so a
|
|
82057
|
+
* viewer was told `input: true` by a Wayland host that cannot inject a keystroke, and
|
|
82058
|
+
* offered a system-audio toggle on macOS where the capture is known to be silent. A
|
|
82059
|
+
* capability flag that doesn't track reality is worse than no flag: the viewer renders
|
|
82060
|
+
* a control that quietly does nothing.
|
|
82061
|
+
*/
|
|
81934
82062
|
capabilities() {
|
|
81935
82063
|
return {
|
|
81936
|
-
input:
|
|
82064
|
+
// False until an input runner was actually obtained (see start()): on Wayland
|
|
82065
|
+
// without the portal, control is impossible and the session is view-only.
|
|
82066
|
+
input: !!this.injector,
|
|
81937
82067
|
clipboard: true,
|
|
81938
|
-
|
|
81939
|
-
//
|
|
82068
|
+
// No drag/drop or upload surface exists inside an rdesk session today. It was
|
|
82069
|
+
// advertised as if it did; nothing in either viewer ever read it.
|
|
82070
|
+
fileTransfer: false,
|
|
81940
82071
|
multiMonitor: true,
|
|
81941
82072
|
windowCapture: true,
|
|
81942
82073
|
// share a single window/app (privacy)
|
|
82074
|
+
// Voice now rides this session's own peer connection (setAv).
|
|
81943
82075
|
bidiAudioVideo: true,
|
|
81944
|
-
//
|
|
81945
|
-
//
|
|
81946
|
-
|
|
81947
|
-
// ScreenCaptureKit audio addon lands). Advertised so the viewer shows the toggle.
|
|
81948
|
-
systemAudio: true
|
|
82076
|
+
// Windows/Linux capture desktop audio natively; macOS needs a loopback we don't
|
|
82077
|
+
// ship, so claiming it there just produces a toggle that yields silence.
|
|
82078
|
+
systemAudio: process.platform !== "darwin"
|
|
81949
82079
|
};
|
|
81950
82080
|
}
|
|
81951
82081
|
listMonitors() {
|
|
@@ -81955,7 +82085,7 @@ var TesseractEngine = class {
|
|
|
81955
82085
|
return listPublisherSources();
|
|
81956
82086
|
}
|
|
81957
82087
|
startOpts(iceServers) {
|
|
81958
|
-
return { iceServers,
|
|
82088
|
+
return { iceServers, quality: this.quality, systemAudio: this.systemAudio };
|
|
81959
82089
|
}
|
|
81960
82090
|
async setSource(sourceId) {
|
|
81961
82091
|
this.sourceId = sourceId;
|
|
@@ -82008,12 +82138,14 @@ var TesseractEngine = class {
|
|
|
82008
82138
|
}
|
|
82009
82139
|
},
|
|
82010
82140
|
onReady: () => this.ctx.log("publisher connected"),
|
|
82011
|
-
onError: (err2) => this.ctx.log(`publisher error: ${err2}`)
|
|
82141
|
+
onError: (err2) => this.ctx.log(`publisher error: ${err2}`),
|
|
82142
|
+
// Media is direct-first; log which path actually won so a regression to relay
|
|
82143
|
+
// (which costs real bandwidth) is visible instead of silent. Types only, no IPs.
|
|
82144
|
+
onPath: (path6, d) => this.ctx.log(`media path=${path6} (local=${d.localType ?? "?"} remote=${d.remoteType ?? "?"})`)
|
|
82012
82145
|
});
|
|
82013
82146
|
this.pub = pub;
|
|
82014
82147
|
await pub.start({
|
|
82015
82148
|
iceServers,
|
|
82016
|
-
forceRelay: this.ctx.forceRelay,
|
|
82017
82149
|
monitorId: this.monitorId,
|
|
82018
82150
|
quality: this.quality,
|
|
82019
82151
|
systemAudio: this.systemAudio
|
|
@@ -82043,6 +82175,9 @@ var TesseractEngine = class {
|
|
|
82043
82175
|
const iceServers = await this.deps.getIceServers().catch(() => []);
|
|
82044
82176
|
await this.pub?.setMonitor(monitorId, this.startOpts(iceServers));
|
|
82045
82177
|
}
|
|
82178
|
+
setAv(on) {
|
|
82179
|
+
this.pub?.setAv(on);
|
|
82180
|
+
}
|
|
82046
82181
|
setQuality(preset) {
|
|
82047
82182
|
this.quality = preset;
|
|
82048
82183
|
this.pub?.setQuality(preset);
|
|
@@ -82064,13 +82199,156 @@ function registerTesseractEngine(deps) {
|
|
|
82064
82199
|
}
|
|
82065
82200
|
|
|
82066
82201
|
// ../../packages/host-core/dist/local-server.js
|
|
82067
|
-
import { timingSafeEqual as
|
|
82202
|
+
import { timingSafeEqual as timingSafeEqual5 } from "node:crypto";
|
|
82203
|
+
|
|
82204
|
+
// ../../packages/host-core/dist/rdesk/server-prefs.js
|
|
82205
|
+
import { readFileSync as readFileSync25, writeFileSync as writeFileSync17 } from "node:fs";
|
|
82206
|
+
import { join as join44 } from "node:path";
|
|
82207
|
+
function rdeskServerPrefsPath() {
|
|
82208
|
+
return join44(daemonDir2(), "rdesk-server.json");
|
|
82209
|
+
}
|
|
82210
|
+
var DEFAULTS2 = {
|
|
82211
|
+
enabled: true,
|
|
82212
|
+
defaultAccess: "control",
|
|
82213
|
+
quality: "auto",
|
|
82214
|
+
autostart: true,
|
|
82215
|
+
hideTray: false,
|
|
82216
|
+
noticeShownAt: 0
|
|
82217
|
+
};
|
|
82218
|
+
function readRdeskServerPrefs() {
|
|
82219
|
+
try {
|
|
82220
|
+
const p = JSON.parse(readFileSync25(rdeskServerPrefsPath(), "utf8"));
|
|
82221
|
+
return {
|
|
82222
|
+
// `!== false` (not `?? true`): only an explicit opt-out disables sharing, so a
|
|
82223
|
+
// partially-written or older prefs file never silently turns the machine off.
|
|
82224
|
+
enabled: p.enabled !== false,
|
|
82225
|
+
defaultAccess: p.defaultAccess === "view" ? "view" : "control",
|
|
82226
|
+
quality: p.quality ?? DEFAULTS2.quality,
|
|
82227
|
+
autostart: p.autostart ?? DEFAULTS2.autostart,
|
|
82228
|
+
hideTray: p.hideTray ?? DEFAULTS2.hideTray,
|
|
82229
|
+
noticeShownAt: typeof p.noticeShownAt === "number" ? p.noticeShownAt : 0
|
|
82230
|
+
};
|
|
82231
|
+
} catch {
|
|
82232
|
+
return { ...DEFAULTS2 };
|
|
82233
|
+
}
|
|
82234
|
+
}
|
|
82235
|
+
function writeRdeskServerPrefs(patch) {
|
|
82236
|
+
try {
|
|
82237
|
+
const next = { ...readRdeskServerPrefs(), ...patch };
|
|
82238
|
+
writeFileSync17(rdeskServerPrefsPath(), JSON.stringify(next), { mode: 384 });
|
|
82239
|
+
} catch {
|
|
82240
|
+
}
|
|
82241
|
+
}
|
|
82242
|
+
function rdeskSharingEnabled() {
|
|
82243
|
+
if (process.env.CCB_RDESK_ENABLED === "0")
|
|
82244
|
+
return false;
|
|
82245
|
+
if (process.env.CCB_RDESK_ENABLED === "1")
|
|
82246
|
+
return true;
|
|
82247
|
+
return readRdeskServerPrefs().enabled;
|
|
82248
|
+
}
|
|
82249
|
+
|
|
82250
|
+
// ../../packages/host-core/dist/rdesk/password.js
|
|
82251
|
+
import { scryptSync, randomBytes as randomBytes5, timingSafeEqual as timingSafeEqual4, randomInt } from "node:crypto";
|
|
82252
|
+
import { readFileSync as readFileSync26, writeFileSync as writeFileSync18, existsSync as existsSync21, unlinkSync as unlinkSync2 } from "node:fs";
|
|
82253
|
+
import { join as join45 } from "node:path";
|
|
82254
|
+
function pwFile() {
|
|
82255
|
+
return join45(daemonDir2(), "rdesk-password.json");
|
|
82256
|
+
}
|
|
82257
|
+
function pwPlainFile() {
|
|
82258
|
+
return join45(daemonDir2(), "rdesk-password.enc");
|
|
82259
|
+
}
|
|
82260
|
+
var PW_ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz23456789";
|
|
82261
|
+
var PW_LENGTH = 16;
|
|
82262
|
+
function generatePassword() {
|
|
82263
|
+
let out = "";
|
|
82264
|
+
for (let i = 0; i < PW_LENGTH; i++)
|
|
82265
|
+
out += PW_ALPHABET[randomInt(PW_ALPHABET.length)];
|
|
82266
|
+
return (out.match(/.{1,4}/g) ?? [out]).join("-");
|
|
82267
|
+
}
|
|
82268
|
+
function writePlain(password) {
|
|
82269
|
+
try {
|
|
82270
|
+
const safe = electronModule()?.safeStorage;
|
|
82271
|
+
if (!safe?.isEncryptionAvailable())
|
|
82272
|
+
return;
|
|
82273
|
+
writeFileSync18(pwPlainFile(), safe.encryptString(password), { mode: 384 });
|
|
82274
|
+
} catch {
|
|
82275
|
+
}
|
|
82276
|
+
}
|
|
82277
|
+
function canRevealRdeskPassword() {
|
|
82278
|
+
try {
|
|
82279
|
+
const safe = electronModule()?.safeStorage;
|
|
82280
|
+
return !!safe?.isEncryptionAvailable() && existsSync21(pwPlainFile());
|
|
82281
|
+
} catch {
|
|
82282
|
+
return false;
|
|
82283
|
+
}
|
|
82284
|
+
}
|
|
82285
|
+
function readRdeskPasswordPlain() {
|
|
82286
|
+
try {
|
|
82287
|
+
const safe = electronModule()?.safeStorage;
|
|
82288
|
+
if (!safe?.isEncryptionAvailable())
|
|
82289
|
+
return null;
|
|
82290
|
+
return safe.decryptString(readFileSync26(pwPlainFile()));
|
|
82291
|
+
} catch {
|
|
82292
|
+
return null;
|
|
82293
|
+
}
|
|
82294
|
+
}
|
|
82295
|
+
function setRdeskPassword(password) {
|
|
82296
|
+
if (!password) {
|
|
82297
|
+
try {
|
|
82298
|
+
unlinkSync2(pwFile());
|
|
82299
|
+
} catch {
|
|
82300
|
+
}
|
|
82301
|
+
try {
|
|
82302
|
+
unlinkSync2(pwPlainFile());
|
|
82303
|
+
} catch {
|
|
82304
|
+
}
|
|
82305
|
+
return;
|
|
82306
|
+
}
|
|
82307
|
+
const salt = randomBytes5(16);
|
|
82308
|
+
const hash2 = scryptSync(password, salt, 32);
|
|
82309
|
+
writeFileSync18(pwFile(), JSON.stringify({ salt: salt.toString("hex"), hash: hash2.toString("hex") }), { mode: 384 });
|
|
82310
|
+
writePlain(password);
|
|
82311
|
+
}
|
|
82312
|
+
function regenerateRdeskPassword() {
|
|
82313
|
+
const pw = generatePassword();
|
|
82314
|
+
setRdeskPassword(pw);
|
|
82315
|
+
return pw;
|
|
82316
|
+
}
|
|
82317
|
+
function ensureRdeskPassword() {
|
|
82318
|
+
if (hasRdeskPassword())
|
|
82319
|
+
return null;
|
|
82320
|
+
return regenerateRdeskPassword();
|
|
82321
|
+
}
|
|
82322
|
+
function hasRdeskPassword() {
|
|
82323
|
+
return !!process.env.CCB_RDESK_PASSWORD || existsSync21(pwFile());
|
|
82324
|
+
}
|
|
82325
|
+
function verifyRdeskPassword(password) {
|
|
82326
|
+
if (!password)
|
|
82327
|
+
return false;
|
|
82328
|
+
const override = process.env.CCB_RDESK_PASSWORD;
|
|
82329
|
+
if (override)
|
|
82330
|
+
return password.length === override.length && timingSafeEqual4(Buffer.from(password), Buffer.from(override));
|
|
82331
|
+
try {
|
|
82332
|
+
const { salt, hash: hash2 } = JSON.parse(readFileSync26(pwFile(), "utf8"));
|
|
82333
|
+
const got = scryptSync(password, Buffer.from(salt, "hex"), 32);
|
|
82334
|
+
const want = Buffer.from(hash2, "hex");
|
|
82335
|
+
return got.length === want.length && timingSafeEqual4(got, want);
|
|
82336
|
+
} catch {
|
|
82337
|
+
return false;
|
|
82338
|
+
}
|
|
82339
|
+
}
|
|
82340
|
+
|
|
82341
|
+
// ../../packages/host-core/dist/rdesk/server-auth.js
|
|
82342
|
+
var DEFAULT_API = (process.env.CCB_TESSERACT_API ?? "https://app.tesseract.dev").replace(/\/$/, "");
|
|
82343
|
+
function getMachinePublicId() {
|
|
82344
|
+
return readCredentials()?.publicId ?? null;
|
|
82345
|
+
}
|
|
82068
82346
|
|
|
82069
82347
|
// ../../packages/host-core/dist/vault/manager.js
|
|
82070
82348
|
import { createHash as createHash7 } from "node:crypto";
|
|
82071
82349
|
|
|
82072
82350
|
// ../../packages/host-core/dist/vault/passkey.js
|
|
82073
|
-
import { createHash as createHash6, createPrivateKey, createSign, sign as rawSign, generateKeyPairSync, randomBytes as
|
|
82351
|
+
import { createHash as createHash6, createPrivateKey, createSign, sign as rawSign, generateKeyPairSync, randomBytes as randomBytes6 } from "node:crypto";
|
|
82074
82352
|
function buildAuthenticatorData(rpId, signCount) {
|
|
82075
82353
|
const rpIdHash = createHash6("sha256").update(rpId).digest();
|
|
82076
82354
|
const counter = Buffer.alloc(4);
|
|
@@ -82126,7 +82404,7 @@ function createPasskeyRegistration(rpId) {
|
|
|
82126
82404
|
const pkcs8 = privateKey.export({ type: "pkcs8", format: "der" });
|
|
82127
82405
|
const jwk = publicKey.export({ format: "jwk" });
|
|
82128
82406
|
const cose = coseEs256(Buffer.from(jwk.x, "base64url"), Buffer.from(jwk.y, "base64url"));
|
|
82129
|
-
const credentialId =
|
|
82407
|
+
const credentialId = randomBytes6(32);
|
|
82130
82408
|
const rpIdHash = createHash6("sha256").update(rpId).digest();
|
|
82131
82409
|
const flags = Buffer.from([69]);
|
|
82132
82410
|
const signCount = Buffer.alloc(4);
|
|
@@ -82151,7 +82429,7 @@ function createPasskeyRegistration(rpId) {
|
|
|
82151
82429
|
|
|
82152
82430
|
// ../../packages/host-core/dist/vault/manager.js
|
|
82153
82431
|
init_base_paths();
|
|
82154
|
-
import { mkdirSync as mkdirSync21, readFileSync as
|
|
82432
|
+
import { mkdirSync as mkdirSync21, readFileSync as readFileSync29, writeFileSync as writeFileSync21 } from "node:fs";
|
|
82155
82433
|
import { dirname as dirname20 } from "node:path";
|
|
82156
82434
|
|
|
82157
82435
|
// ../../packages/vault-core/dist/crypto.js
|
|
@@ -82322,7 +82600,7 @@ function tombstone(id, updatedAt) {
|
|
|
82322
82600
|
// ../../packages/vault-core/dist/authenticator.js
|
|
82323
82601
|
var subtle2 = globalThis.crypto.subtle;
|
|
82324
82602
|
var bs2 = (b) => b;
|
|
82325
|
-
var
|
|
82603
|
+
var DEFAULTS3 = { algorithm: "SHA1", digits: 6, period: 30, counter: 0 };
|
|
82326
82604
|
async function hmac(algorithm, keyBytes, msg) {
|
|
82327
82605
|
const hash2 = algorithm === "SHA512" ? "SHA-512" : algorithm === "SHA256" ? "SHA-256" : "SHA-1";
|
|
82328
82606
|
const key2 = await subtle2.importKey("raw", bs2(keyBytes), { name: "HMAC", hash: hash2 }, false, ["sign"]);
|
|
@@ -82354,7 +82632,7 @@ async function generateTotp(params, atMs = Date.now()) {
|
|
|
82354
82632
|
return { code, secondsRemaining: period - seconds % period, period };
|
|
82355
82633
|
}
|
|
82356
82634
|
async function generateFromUri(uriOrSecret, atMs = Date.now()) {
|
|
82357
|
-
const params = uriOrSecret.startsWith("otpauth://") ? parseOtpauthUri(uriOrSecret) : { ...
|
|
82635
|
+
const params = uriOrSecret.startsWith("otpauth://") ? parseOtpauthUri(uriOrSecret) : { ...DEFAULTS3, type: "totp", secret: uriOrSecret.replace(/\s+/g, "").toUpperCase() };
|
|
82358
82636
|
return generateTotp(params, atMs);
|
|
82359
82637
|
}
|
|
82360
82638
|
function parseOtpauthUri(uri) {
|
|
@@ -82400,7 +82678,7 @@ var SETS = {
|
|
|
82400
82678
|
symbol: "!@#$%^&*()-_=+[]{};:,.<>?"
|
|
82401
82679
|
};
|
|
82402
82680
|
var AMBIGUOUS = new Set("O0Il1");
|
|
82403
|
-
function
|
|
82681
|
+
function randomInt2(maxExclusive) {
|
|
82404
82682
|
const limit = Math.floor(256 / maxExclusive) * maxExclusive;
|
|
82405
82683
|
let x;
|
|
82406
82684
|
do {
|
|
@@ -82409,9 +82687,9 @@ function randomInt(maxExclusive) {
|
|
|
82409
82687
|
return x % maxExclusive;
|
|
82410
82688
|
}
|
|
82411
82689
|
function pick2(pool) {
|
|
82412
|
-
return pool[
|
|
82690
|
+
return pool[randomInt2(pool.length)];
|
|
82413
82691
|
}
|
|
82414
|
-
function
|
|
82692
|
+
function generatePassword2(opts = {}) {
|
|
82415
82693
|
const o = {
|
|
82416
82694
|
length: 20,
|
|
82417
82695
|
uppercase: true,
|
|
@@ -82452,7 +82730,7 @@ function generatePassword(opts = {}) {
|
|
|
82452
82730
|
}
|
|
82453
82731
|
function shuffle(arr) {
|
|
82454
82732
|
for (let i = arr.length - 1; i > 0; i--) {
|
|
82455
|
-
const j =
|
|
82733
|
+
const j = randomInt2(i + 1);
|
|
82456
82734
|
[arr[i], arr[j]] = [arr[j], arr[i]];
|
|
82457
82735
|
}
|
|
82458
82736
|
return arr;
|
|
@@ -83173,7 +83451,7 @@ function makeDaemonVaultApi(getOrigin, getToken2) {
|
|
|
83173
83451
|
|
|
83174
83452
|
// ../../packages/host-core/dist/vault/persistence.js
|
|
83175
83453
|
init_base_paths();
|
|
83176
|
-
import { existsSync as
|
|
83454
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync19, readFileSync as readFileSync27, writeFileSync as writeFileSync19, unlinkSync as unlinkSync3 } from "node:fs";
|
|
83177
83455
|
import { dirname as dirname19 } from "node:path";
|
|
83178
83456
|
function vaultStoreFile() {
|
|
83179
83457
|
return homePath(".tesseract", "vault", "vault.json");
|
|
@@ -83185,9 +83463,9 @@ function makeVaultPersistence(file2 = vaultStoreFile, deviceKeyFile = vaultDevic
|
|
|
83185
83463
|
return {
|
|
83186
83464
|
load() {
|
|
83187
83465
|
try {
|
|
83188
|
-
if (!
|
|
83466
|
+
if (!existsSync22(file2()))
|
|
83189
83467
|
return null;
|
|
83190
|
-
const parsed = JSON.parse(
|
|
83468
|
+
const parsed = JSON.parse(readFileSync27(file2(), "utf8"));
|
|
83191
83469
|
if (!parsed || typeof parsed !== "object")
|
|
83192
83470
|
return null;
|
|
83193
83471
|
return { meta: parsed.meta ?? null, items: Array.isArray(parsed.items) ? parsed.items : [] };
|
|
@@ -83198,13 +83476,13 @@ function makeVaultPersistence(file2 = vaultStoreFile, deviceKeyFile = vaultDevic
|
|
|
83198
83476
|
save(state2) {
|
|
83199
83477
|
try {
|
|
83200
83478
|
mkdirSync19(dirname19(file2()), { recursive: true, mode: 448 });
|
|
83201
|
-
|
|
83479
|
+
writeFileSync19(file2(), JSON.stringify(state2), { mode: 384 });
|
|
83202
83480
|
} catch {
|
|
83203
83481
|
}
|
|
83204
83482
|
},
|
|
83205
83483
|
loadDeviceKey() {
|
|
83206
83484
|
try {
|
|
83207
|
-
return
|
|
83485
|
+
return existsSync22(deviceKeyFile()) ? readFileSync27(deviceKeyFile(), "utf8").trim() || null : null;
|
|
83208
83486
|
} catch {
|
|
83209
83487
|
return null;
|
|
83210
83488
|
}
|
|
@@ -83212,14 +83490,14 @@ function makeVaultPersistence(file2 = vaultStoreFile, deviceKeyFile = vaultDevic
|
|
|
83212
83490
|
saveDeviceKey(base64Key) {
|
|
83213
83491
|
try {
|
|
83214
83492
|
mkdirSync19(dirname19(deviceKeyFile()), { recursive: true, mode: 448 });
|
|
83215
|
-
|
|
83493
|
+
writeFileSync19(deviceKeyFile(), base64Key, { mode: 384 });
|
|
83216
83494
|
} catch {
|
|
83217
83495
|
}
|
|
83218
83496
|
},
|
|
83219
83497
|
clearDeviceKey() {
|
|
83220
83498
|
try {
|
|
83221
|
-
if (
|
|
83222
|
-
|
|
83499
|
+
if (existsSync22(deviceKeyFile()))
|
|
83500
|
+
unlinkSync3(deviceKeyFile());
|
|
83223
83501
|
} catch {
|
|
83224
83502
|
}
|
|
83225
83503
|
}
|
|
@@ -83228,8 +83506,8 @@ function makeVaultPersistence(file2 = vaultStoreFile, deviceKeyFile = vaultDevic
|
|
|
83228
83506
|
|
|
83229
83507
|
// ../../packages/host-core/dist/vault/biometric.js
|
|
83230
83508
|
init_base_paths();
|
|
83231
|
-
import { existsSync as
|
|
83232
|
-
import { join as
|
|
83509
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync20, readFileSync as readFileSync28, rmSync as rmSync6, writeFileSync as writeFileSync20 } from "node:fs";
|
|
83510
|
+
import { join as join46 } from "node:path";
|
|
83233
83511
|
async function electronBio() {
|
|
83234
83512
|
if (!electronModule())
|
|
83235
83513
|
return null;
|
|
@@ -83250,7 +83528,7 @@ function bioDir() {
|
|
|
83250
83528
|
return d;
|
|
83251
83529
|
}
|
|
83252
83530
|
function bioFile(id) {
|
|
83253
|
-
return
|
|
83531
|
+
return join46(bioDir(), `${String(id).replace(/[^a-zA-Z0-9_-]/g, "").slice(0, 64)}.enc`);
|
|
83254
83532
|
}
|
|
83255
83533
|
async function biometricAvailable() {
|
|
83256
83534
|
if (process.platform !== "darwin")
|
|
@@ -83265,24 +83543,24 @@ async function biometricAvailable() {
|
|
|
83265
83543
|
}
|
|
83266
83544
|
}
|
|
83267
83545
|
function biometricEnrolled(id) {
|
|
83268
|
-
return
|
|
83546
|
+
return existsSync23(bioFile(id));
|
|
83269
83547
|
}
|
|
83270
83548
|
async function biometricEnroll(id, base64Key) {
|
|
83271
83549
|
const bio = await electronBio();
|
|
83272
83550
|
if (!bio)
|
|
83273
83551
|
throw new Error("Touch ID is not available on this device.");
|
|
83274
83552
|
await bio.systemPreferences.promptTouchID("enable Touch ID for your vault");
|
|
83275
|
-
|
|
83553
|
+
writeFileSync20(bioFile(id), bio.safeStorage.encryptString(base64Key), { mode: 384 });
|
|
83276
83554
|
}
|
|
83277
83555
|
async function biometricUnlock(id) {
|
|
83278
83556
|
const f = bioFile(id);
|
|
83279
|
-
if (!
|
|
83557
|
+
if (!existsSync23(f))
|
|
83280
83558
|
throw new Error("Touch ID is not set up for this vault.");
|
|
83281
83559
|
const bio = await electronBio();
|
|
83282
83560
|
if (!bio)
|
|
83283
83561
|
throw new Error("Touch ID is not available on this device.");
|
|
83284
83562
|
await bio.systemPreferences.promptTouchID("unlock your vault");
|
|
83285
|
-
return bio.safeStorage.decryptString(
|
|
83563
|
+
return bio.safeStorage.decryptString(readFileSync28(f));
|
|
83286
83564
|
}
|
|
83287
83565
|
function biometricDisable(id) {
|
|
83288
83566
|
try {
|
|
@@ -83312,7 +83590,7 @@ var VaultManager = class {
|
|
|
83312
83590
|
// ── auto-lock ────────────────────────────────────────────────────────────────────
|
|
83313
83591
|
loadAutoLock() {
|
|
83314
83592
|
try {
|
|
83315
|
-
const raw = JSON.parse(
|
|
83593
|
+
const raw = JSON.parse(readFileSync29(settingsFile(), "utf8"));
|
|
83316
83594
|
return Number.isFinite(raw.autoLockMinutes) ? Math.max(0, raw.autoLockMinutes) : 0;
|
|
83317
83595
|
} catch {
|
|
83318
83596
|
return 0;
|
|
@@ -83321,7 +83599,7 @@ var VaultManager = class {
|
|
|
83321
83599
|
saveAutoLock() {
|
|
83322
83600
|
try {
|
|
83323
83601
|
mkdirSync21(dirname20(settingsFile()), { recursive: true, mode: 448 });
|
|
83324
|
-
|
|
83602
|
+
writeFileSync21(settingsFile(), JSON.stringify({ autoLockMinutes: this.autoLockMinutes }), { mode: 384 });
|
|
83325
83603
|
} catch {
|
|
83326
83604
|
}
|
|
83327
83605
|
}
|
|
@@ -83600,7 +83878,7 @@ var VaultManager = class {
|
|
|
83600
83878
|
}
|
|
83601
83879
|
// ── misc ─────────────────────────────────────────────────────────────────────────
|
|
83602
83880
|
generatePassword(opts) {
|
|
83603
|
-
return
|
|
83881
|
+
return generatePassword2(opts);
|
|
83604
83882
|
}
|
|
83605
83883
|
async syncNow() {
|
|
83606
83884
|
await this.sync.ensureSynced();
|
|
@@ -83628,7 +83906,7 @@ function tokenMatches(got, want) {
|
|
|
83628
83906
|
return false;
|
|
83629
83907
|
const a = Buffer.from(got);
|
|
83630
83908
|
const b = Buffer.from(want);
|
|
83631
|
-
return a.length === b.length &&
|
|
83909
|
+
return a.length === b.length && timingSafeEqual5(a, b);
|
|
83632
83910
|
}
|
|
83633
83911
|
function originAllowed(origin) {
|
|
83634
83912
|
if (!origin)
|
|
@@ -83715,6 +83993,8 @@ async function startLocalServer(opts) {
|
|
|
83715
83993
|
void handleVault(env.payload);
|
|
83716
83994
|
else if (env.channel === "term")
|
|
83717
83995
|
void handleTerm(env.payload);
|
|
83996
|
+
else if (env.channel === "rdeskadmin")
|
|
83997
|
+
void handleRdeskAdmin(env.payload);
|
|
83718
83998
|
else if (env.channel === "voice")
|
|
83719
83999
|
void handleVoice(env.payload);
|
|
83720
84000
|
else if (env.channel === "present") {
|
|
@@ -83733,7 +84013,7 @@ async function startLocalServer(opts) {
|
|
|
83733
84013
|
const rd = opts.getRdesk?.();
|
|
83734
84014
|
if (rd && env.sessionId) {
|
|
83735
84015
|
rdeskSessions.add(env.sessionId);
|
|
83736
|
-
void rd.onClientMessage(env.sessionId, { clientId: loopbackOrigin,
|
|
84016
|
+
void rd.onClientMessage(env.sessionId, { clientId: loopbackOrigin, name: "This device" }, env.payload);
|
|
83737
84017
|
}
|
|
83738
84018
|
} else if (env.channel === "signal") {
|
|
83739
84019
|
const rd = opts.getRdesk?.();
|
|
@@ -83775,6 +84055,39 @@ async function startLocalServer(opts) {
|
|
|
83775
84055
|
});
|
|
83776
84056
|
ws.on("error", () => {
|
|
83777
84057
|
});
|
|
84058
|
+
async function handleRdeskAdmin(msg) {
|
|
84059
|
+
const reply3 = (payload) => send3("rdeskadmin", { requestId: msg.requestId, ...payload });
|
|
84060
|
+
const state2 = () => ({
|
|
84061
|
+
prefs: readRdeskServerPrefs(),
|
|
84062
|
+
machineId: getMachinePublicId(),
|
|
84063
|
+
hasPassword: hasRdeskPassword(),
|
|
84064
|
+
canReveal: canRevealRdeskPassword(),
|
|
84065
|
+
sessions: opts.getRdeskSessions?.() ?? []
|
|
84066
|
+
});
|
|
84067
|
+
switch (msg.type) {
|
|
84068
|
+
case "rdesk:state":
|
|
84069
|
+
reply3({ type: "rdesk:state", ...state2() });
|
|
84070
|
+
break;
|
|
84071
|
+
case "rdesk:set":
|
|
84072
|
+
if (msg.patch)
|
|
84073
|
+
writeRdeskServerPrefs(msg.patch);
|
|
84074
|
+
reply3({ type: "rdesk:state", ...state2() });
|
|
84075
|
+
break;
|
|
84076
|
+
case "rdesk:reveal-password":
|
|
84077
|
+
reply3({ type: "rdesk:password", password: readRdeskPasswordPlain() });
|
|
84078
|
+
break;
|
|
84079
|
+
case "rdesk:regenerate-password":
|
|
84080
|
+
reply3({ type: "rdesk:state", password: regenerateRdeskPassword(), ...state2() });
|
|
84081
|
+
break;
|
|
84082
|
+
case "rdesk:disconnect":
|
|
84083
|
+
if (msg.sessionId)
|
|
84084
|
+
await opts.getRdesk?.()?.disconnect(msg.sessionId, "host");
|
|
84085
|
+
reply3({ type: "rdesk:state", ...state2() });
|
|
84086
|
+
break;
|
|
84087
|
+
default:
|
|
84088
|
+
reply3({ type: "rdesk:error", error: `unknown rdeskadmin message: ${String(msg.type)}` });
|
|
84089
|
+
}
|
|
84090
|
+
}
|
|
83778
84091
|
async function handleAgent(msg) {
|
|
83779
84092
|
const b = await getSharedBackend();
|
|
83780
84093
|
switch (msg.type) {
|
|
@@ -84149,24 +84462,24 @@ async function startLocalServer(opts) {
|
|
|
84149
84462
|
|
|
84150
84463
|
// ../../packages/host-core/dist/daemon-runtime.js
|
|
84151
84464
|
init_base_paths();
|
|
84152
|
-
import { readFileSync as
|
|
84465
|
+
import { readFileSync as readFileSync32, writeFileSync as writeFileSync27, existsSync as existsSync29, mkdirSync as mkdirSync27, unlinkSync as unlinkSync4, chmodSync as chmodSync6 } from "node:fs";
|
|
84153
84466
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
84154
84467
|
import { join as join55 } from "node:path";
|
|
84155
84468
|
import { randomBytes as randomBytes8 } from "node:crypto";
|
|
84156
84469
|
import { hostname as hostname4 } from "node:os";
|
|
84157
84470
|
|
|
84158
84471
|
// ../../packages/host-core/dist/device-identity.js
|
|
84159
|
-
import { join as
|
|
84160
|
-
import { readFileSync as
|
|
84472
|
+
import { join as join47 } from "node:path";
|
|
84473
|
+
import { readFileSync as readFileSync30, writeFileSync as writeFileSync22, existsSync as existsSync24, mkdirSync as mkdirSync22, renameSync as renameSync8, chmodSync as chmodSync3 } from "node:fs";
|
|
84161
84474
|
var cached2 = null;
|
|
84162
84475
|
function identityPath() {
|
|
84163
|
-
return
|
|
84476
|
+
return join47(daemonDir2(), "identity.json");
|
|
84164
84477
|
}
|
|
84165
84478
|
async function loadOrCreateDeviceIdentity() {
|
|
84166
84479
|
if (cached2)
|
|
84167
84480
|
return cached2;
|
|
84168
84481
|
try {
|
|
84169
|
-
const stored = JSON.parse(
|
|
84482
|
+
const stored = JSON.parse(readFileSync30(identityPath(), "utf-8"));
|
|
84170
84483
|
if (stored?.privateJwk) {
|
|
84171
84484
|
cached2 = await importIdentity(stored.privateJwk);
|
|
84172
84485
|
return cached2;
|
|
@@ -84176,10 +84489,10 @@ async function loadOrCreateDeviceIdentity() {
|
|
|
84176
84489
|
const kp = await generateIdentityKeyPair(true);
|
|
84177
84490
|
const { privateJwk, publicRaw } = await exportIdentity(kp);
|
|
84178
84491
|
const dir2 = daemonDir2();
|
|
84179
|
-
if (!
|
|
84492
|
+
if (!existsSync24(dir2))
|
|
84180
84493
|
mkdirSync22(dir2, { recursive: true, mode: 448 });
|
|
84181
84494
|
const tmp = `${identityPath()}.tmp`;
|
|
84182
|
-
|
|
84495
|
+
writeFileSync22(tmp, JSON.stringify({ privateJwk, publicRaw, alg: "P256-ECDSA" }, null, 2), { mode: 384 });
|
|
84183
84496
|
renameSync8(tmp, identityPath());
|
|
84184
84497
|
try {
|
|
84185
84498
|
chmodSync3(identityPath(), 384);
|
|
@@ -84190,7 +84503,7 @@ async function loadOrCreateDeviceIdentity() {
|
|
|
84190
84503
|
}
|
|
84191
84504
|
var sealingCached = null;
|
|
84192
84505
|
function sealingPath() {
|
|
84193
|
-
return
|
|
84506
|
+
return join47(daemonDir2(), "sealing.json");
|
|
84194
84507
|
}
|
|
84195
84508
|
var EC_DH = { name: "ECDH", namedCurve: "P-256" };
|
|
84196
84509
|
async function loadOrCreateSealingKey() {
|
|
@@ -84198,7 +84511,7 @@ async function loadOrCreateSealingKey() {
|
|
|
84198
84511
|
return sealingCached;
|
|
84199
84512
|
const { subtle: subtle5 } = globalThis.crypto;
|
|
84200
84513
|
try {
|
|
84201
|
-
const stored = JSON.parse(
|
|
84514
|
+
const stored = JSON.parse(readFileSync30(sealingPath(), "utf-8"));
|
|
84202
84515
|
if (stored?.privateJwk && stored.publicRaw) {
|
|
84203
84516
|
const privateKey = await subtle5.importKey("jwk", stored.privateJwk, EC_DH, true, ["deriveBits"]);
|
|
84204
84517
|
sealingCached = { privateKey, publicRaw: unb64u(stored.publicRaw) };
|
|
@@ -84210,10 +84523,10 @@ async function loadOrCreateSealingKey() {
|
|
|
84210
84523
|
const publicRaw = new Uint8Array(await subtle5.exportKey("raw", kp.publicKey));
|
|
84211
84524
|
const privateJwk = await subtle5.exportKey("jwk", kp.privateKey);
|
|
84212
84525
|
const dir2 = daemonDir2();
|
|
84213
|
-
if (!
|
|
84526
|
+
if (!existsSync24(dir2))
|
|
84214
84527
|
mkdirSync22(dir2, { recursive: true, mode: 448 });
|
|
84215
84528
|
const tmp = `${sealingPath()}.tmp`;
|
|
84216
|
-
|
|
84529
|
+
writeFileSync22(tmp, JSON.stringify({ privateJwk, publicRaw: b64u(publicRaw), alg: "P256-ECDH" }, null, 2), { mode: 384 });
|
|
84217
84530
|
renameSync8(tmp, sealingPath());
|
|
84218
84531
|
try {
|
|
84219
84532
|
chmodSync3(sealingPath(), 384);
|
|
@@ -84276,10 +84589,10 @@ import { createSocket as createSocket2 } from "node:dgram";
|
|
|
84276
84589
|
import { createRequire as createRequire4 } from "node:module";
|
|
84277
84590
|
|
|
84278
84591
|
// ../../packages/host-core/dist/mesh/config.js
|
|
84279
|
-
import { chmodSync as chmodSync4, existsSync as
|
|
84280
|
-
import { join as
|
|
84592
|
+
import { chmodSync as chmodSync4, existsSync as existsSync25, mkdirSync as mkdirSync23, readFileSync as readFileSync31, rmSync as rmSync7, writeFileSync as writeFileSync23 } from "node:fs";
|
|
84593
|
+
import { join as join48 } from "node:path";
|
|
84281
84594
|
function meshDir() {
|
|
84282
|
-
return
|
|
84595
|
+
return join48(daemonDir2(), "mesh");
|
|
84283
84596
|
}
|
|
84284
84597
|
var FILES = {
|
|
84285
84598
|
genesis: "genesis.bin",
|
|
@@ -84288,9 +84601,9 @@ var FILES = {
|
|
|
84288
84601
|
bundle: "bundle.bin"
|
|
84289
84602
|
};
|
|
84290
84603
|
function readIfPresent(name) {
|
|
84291
|
-
const p =
|
|
84604
|
+
const p = join48(meshDir(), name);
|
|
84292
84605
|
try {
|
|
84293
|
-
return
|
|
84606
|
+
return existsSync25(p) ? new Uint8Array(readFileSync31(p)) : void 0;
|
|
84294
84607
|
} catch {
|
|
84295
84608
|
return void 0;
|
|
84296
84609
|
}
|
|
@@ -84307,8 +84620,8 @@ function loadMeshIdentity() {
|
|
|
84307
84620
|
return { genesis, cert, staticPrivate, ...bundle ? { bundle } : {} };
|
|
84308
84621
|
}
|
|
84309
84622
|
function writeSecret(name, bytes2) {
|
|
84310
|
-
const p =
|
|
84311
|
-
|
|
84623
|
+
const p = join48(meshDir(), name);
|
|
84624
|
+
writeFileSync23(p, bytes2, { mode: 384 });
|
|
84312
84625
|
try {
|
|
84313
84626
|
chmodSync4(p, 384);
|
|
84314
84627
|
} catch {
|
|
@@ -84320,21 +84633,21 @@ function saveMeshIdentity(id) {
|
|
|
84320
84633
|
chmodSync4(meshDir(), 448);
|
|
84321
84634
|
} catch {
|
|
84322
84635
|
}
|
|
84323
|
-
|
|
84324
|
-
|
|
84636
|
+
writeFileSync23(join48(meshDir(), FILES.genesis), id.genesis);
|
|
84637
|
+
writeFileSync23(join48(meshDir(), FILES.cert), id.cert);
|
|
84325
84638
|
writeSecret(FILES.key, id.staticPrivate);
|
|
84326
84639
|
if (id.bundle)
|
|
84327
|
-
|
|
84640
|
+
writeFileSync23(join48(meshDir(), FILES.bundle), id.bundle);
|
|
84328
84641
|
}
|
|
84329
84642
|
var STATUS_REFRESH_MS = 5e3;
|
|
84330
84643
|
var STATUS_STALE_MS = 2e4;
|
|
84331
84644
|
function statusPath() {
|
|
84332
|
-
return
|
|
84645
|
+
return join48(meshDir(), "status.json");
|
|
84333
84646
|
}
|
|
84334
84647
|
function writeStatus(status2) {
|
|
84335
84648
|
try {
|
|
84336
84649
|
mkdirSync23(meshDir(), { recursive: true, mode: 448 });
|
|
84337
|
-
|
|
84650
|
+
writeFileSync23(statusPath(), JSON.stringify({ ...status2, at: Date.now() }, null, 2));
|
|
84338
84651
|
} catch {
|
|
84339
84652
|
}
|
|
84340
84653
|
}
|
|
@@ -84346,7 +84659,7 @@ function clearStatus() {
|
|
|
84346
84659
|
}
|
|
84347
84660
|
function readStatus() {
|
|
84348
84661
|
try {
|
|
84349
|
-
const raw = JSON.parse(
|
|
84662
|
+
const raw = JSON.parse(readFileSync31(statusPath(), "utf8"));
|
|
84350
84663
|
if (typeof raw.at !== "number")
|
|
84351
84664
|
return null;
|
|
84352
84665
|
return { ...raw, at: raw.at, stale: Date.now() - raw.at > STATUS_STALE_MS };
|
|
@@ -84357,7 +84670,7 @@ function readStatus() {
|
|
|
84357
84670
|
function cacheBundle(bundle) {
|
|
84358
84671
|
try {
|
|
84359
84672
|
mkdirSync23(meshDir(), { recursive: true, mode: 448 });
|
|
84360
|
-
|
|
84673
|
+
writeFileSync23(join48(meshDir(), FILES.bundle), bundle);
|
|
84361
84674
|
} catch {
|
|
84362
84675
|
}
|
|
84363
84676
|
}
|
|
@@ -84970,7 +85283,7 @@ import { basename as basename11 } from "node:path";
|
|
|
84970
85283
|
// ../../packages/host-core/dist/drops/paths.js
|
|
84971
85284
|
init_base_paths();
|
|
84972
85285
|
import { mkdir as mkdir11 } from "node:fs/promises";
|
|
84973
|
-
import { join as
|
|
85286
|
+
import { join as join49 } from "node:path";
|
|
84974
85287
|
|
|
84975
85288
|
// ../../packages/host-core/dist/drops/names.js
|
|
84976
85289
|
var WINDOWS_RESERVED = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])$/i;
|
|
@@ -85059,7 +85372,7 @@ function basenameOf(p) {
|
|
|
85059
85372
|
function resolveDropsRoot() {
|
|
85060
85373
|
const root = resolveHostRoot();
|
|
85061
85374
|
const preferred = dropsDir();
|
|
85062
|
-
return isInsideRoot(preferred, root) ? preferred :
|
|
85375
|
+
return isInsideRoot(preferred, root) ? preferred : join49(root, "Drops");
|
|
85063
85376
|
}
|
|
85064
85377
|
async function ensureDropsRoot() {
|
|
85065
85378
|
const dir2 = resolveDropsRoot();
|
|
@@ -85075,7 +85388,7 @@ async function ensureDropDir(opts) {
|
|
|
85075
85388
|
parts.push(sanitizeDropName(opts.sender, "Unknown sender"));
|
|
85076
85389
|
if (!opts.singleItem && opts.label)
|
|
85077
85390
|
parts.push(sanitizeDropName(opts.label, "Files"));
|
|
85078
|
-
const dir2 =
|
|
85391
|
+
const dir2 = join49(...parts);
|
|
85079
85392
|
await mkdir11(dir2, { recursive: true });
|
|
85080
85393
|
return dir2;
|
|
85081
85394
|
}
|
|
@@ -85218,7 +85531,7 @@ function createDropHandler(deps) {
|
|
|
85218
85531
|
// ../../packages/host-core/dist/drops/blob-fetch.js
|
|
85219
85532
|
import { createWriteStream as createWriteStream2 } from "node:fs";
|
|
85220
85533
|
import { mkdir as mkdir12, rm as rm4, chmod as chmod3 } from "node:fs/promises";
|
|
85221
|
-
import { dirname as dirname22, join as
|
|
85534
|
+
import { dirname as dirname22, join as join50 } from "node:path";
|
|
85222
85535
|
import { Readable as Readable2 } from "node:stream";
|
|
85223
85536
|
import { pipeline } from "node:stream/promises";
|
|
85224
85537
|
|
|
@@ -85390,7 +85703,7 @@ async function fetchBlobDrop(opts) {
|
|
|
85390
85703
|
log7(`drop ${opts.dropId}: refusing directory "${item.rel}"`);
|
|
85391
85704
|
continue;
|
|
85392
85705
|
}
|
|
85393
|
-
const abs =
|
|
85706
|
+
const abs = join50(opts.destDir, rel);
|
|
85394
85707
|
if (!isInsideRoot(abs, opts.destDir)) {
|
|
85395
85708
|
log7(`drop ${opts.dropId}: refusing directory outside the destination`);
|
|
85396
85709
|
continue;
|
|
@@ -85411,7 +85724,7 @@ async function fetchBlobDrop(opts) {
|
|
|
85411
85724
|
log7(`drop ${opts.dropId}: refusing "${item.rel}"`);
|
|
85412
85725
|
continue;
|
|
85413
85726
|
}
|
|
85414
|
-
let abs =
|
|
85727
|
+
let abs = join50(opts.destDir, rel);
|
|
85415
85728
|
if (!isInsideRoot(abs, opts.destDir)) {
|
|
85416
85729
|
log7(`drop ${opts.dropId}: refusing a path outside the destination`);
|
|
85417
85730
|
continue;
|
|
@@ -85654,7 +85967,7 @@ var VncEngine = class {
|
|
|
85654
85967
|
const c = client;
|
|
85655
85968
|
this.fbw = c.width ?? 1280;
|
|
85656
85969
|
this.fbh = c.height ?? 800;
|
|
85657
|
-
void this.pub?.startCanvas({ iceServers: [],
|
|
85970
|
+
void this.pub?.startCanvas({ iceServers: [], quality: "auto", width: this.fbw, height: this.fbh, maxFps: 30 });
|
|
85658
85971
|
client.requestUpdate?.(false, 0, 0, this.fbw, this.fbh);
|
|
85659
85972
|
});
|
|
85660
85973
|
client.on("rect", (rect) => {
|
|
@@ -85756,38 +86069,47 @@ function registerRdpEngine() {
|
|
|
85756
86069
|
}
|
|
85757
86070
|
|
|
85758
86071
|
// ../../packages/host-core/dist/rdesk/audit.js
|
|
85759
|
-
import {
|
|
85760
|
-
import { join as
|
|
86072
|
+
import { appendFile, stat as stat7, rename as rename3 } from "node:fs/promises";
|
|
86073
|
+
import { join as join51 } from "node:path";
|
|
86074
|
+
var MAX_BYTES = 2 * 1024 * 1024;
|
|
85761
86075
|
function rdeskAuditPath() {
|
|
85762
|
-
return
|
|
86076
|
+
return join51(daemonDir2(), "rdesk-audit.jsonl");
|
|
85763
86077
|
}
|
|
85764
|
-
|
|
86078
|
+
var queue = [];
|
|
86079
|
+
var draining = false;
|
|
86080
|
+
async function rotateIfNeeded(path6) {
|
|
85765
86081
|
try {
|
|
85766
|
-
|
|
86082
|
+
const st = await stat7(path6);
|
|
86083
|
+
if (st.size < MAX_BYTES)
|
|
86084
|
+
return;
|
|
86085
|
+
await rename3(path6, `${path6}.1`);
|
|
85767
86086
|
} catch {
|
|
85768
86087
|
}
|
|
85769
86088
|
}
|
|
85770
|
-
|
|
85771
|
-
|
|
85772
|
-
|
|
85773
|
-
|
|
85774
|
-
|
|
85775
|
-
|
|
85776
|
-
|
|
86089
|
+
async function drain() {
|
|
86090
|
+
if (draining)
|
|
86091
|
+
return;
|
|
86092
|
+
draining = true;
|
|
86093
|
+
try {
|
|
86094
|
+
while (queue.length) {
|
|
86095
|
+
const batch = queue.join("");
|
|
86096
|
+
queue = [];
|
|
86097
|
+
const path6 = rdeskAuditPath();
|
|
86098
|
+
await rotateIfNeeded(path6);
|
|
86099
|
+
await appendFile(path6, batch, { mode: 384 });
|
|
86100
|
+
}
|
|
86101
|
+
} catch {
|
|
86102
|
+
} finally {
|
|
86103
|
+
draining = false;
|
|
86104
|
+
if (queue.length)
|
|
86105
|
+
void drain();
|
|
86106
|
+
}
|
|
85777
86107
|
}
|
|
85778
|
-
function
|
|
85779
|
-
if (!password)
|
|
85780
|
-
return false;
|
|
85781
|
-
const override = process.env.CCB_RDESK_PASSWORD;
|
|
85782
|
-
if (override)
|
|
85783
|
-
return password.length === override.length && timingSafeEqual5(Buffer.from(password), Buffer.from(override));
|
|
86108
|
+
function appendRdeskAudit(e) {
|
|
85784
86109
|
try {
|
|
85785
|
-
|
|
85786
|
-
|
|
85787
|
-
const want = Buffer.from(hash2, "hex");
|
|
85788
|
-
return got.length === want.length && timingSafeEqual5(got, want);
|
|
86110
|
+
queue.push(JSON.stringify(e) + "\n");
|
|
86111
|
+
void drain();
|
|
85789
86112
|
} catch {
|
|
85790
|
-
return false;
|
|
85791
86113
|
}
|
|
85792
86114
|
}
|
|
85793
86115
|
|
|
@@ -85923,9 +86245,9 @@ function bindBridge(i, log9) {
|
|
|
85923
86245
|
|
|
85924
86246
|
// ../../packages/host-core/dist/vault/autofill-bridge.js
|
|
85925
86247
|
import { randomBytes as randomBytes7 } from "node:crypto";
|
|
85926
|
-
import { existsSync as existsSync26, mkdirSync as mkdirSync24, writeFileSync as
|
|
86248
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync24, writeFileSync as writeFileSync24, rmSync as rmSync8 } from "node:fs";
|
|
85927
86249
|
import { homedir as homedir6 } from "node:os";
|
|
85928
|
-
import { join as
|
|
86250
|
+
import { join as join52 } from "node:path";
|
|
85929
86251
|
|
|
85930
86252
|
// ../../packages/host-core/dist/vault/peer-verify.js
|
|
85931
86253
|
import { execFile as execFile6 } from "node:child_process";
|
|
@@ -85987,10 +86309,10 @@ async function isTrustedAutofillPeer(remotePort) {
|
|
|
85987
86309
|
var APPEX_BUNDLE_ID = "dev.tesseract.AutoFill";
|
|
85988
86310
|
var BRIDGE_PORTS2 = [17872, 17873, 17874, 17875];
|
|
85989
86311
|
function appexContainerData() {
|
|
85990
|
-
return
|
|
86312
|
+
return join52(homedir6(), "Library", "Containers", APPEX_BUNDLE_ID, "Data");
|
|
85991
86313
|
}
|
|
85992
86314
|
function bridgeInfoPath() {
|
|
85993
|
-
return
|
|
86315
|
+
return join52(appexContainerData(), "Library", "Application Support", "tesseract-autofill-bridge.json");
|
|
85994
86316
|
}
|
|
85995
86317
|
var infoLoggedOnce = false;
|
|
85996
86318
|
function writeBridgeInfo(port, token3, log9) {
|
|
@@ -86005,9 +86327,9 @@ function writeBridgeInfo(port, token3, log9) {
|
|
|
86005
86327
|
}
|
|
86006
86328
|
return;
|
|
86007
86329
|
}
|
|
86008
|
-
const dir2 =
|
|
86330
|
+
const dir2 = join52(containerData, "Library", "Application Support");
|
|
86009
86331
|
mkdirSync24(dir2, { recursive: true });
|
|
86010
|
-
|
|
86332
|
+
writeFileSync24(bridgeInfoPath(), JSON.stringify({ port, token: token3, pid: process.pid, ts: Date.now() }), { mode: 384 });
|
|
86011
86333
|
if (!infoLoggedOnce) {
|
|
86012
86334
|
infoLoggedOnce = true;
|
|
86013
86335
|
log9("autofill bridge-info WROTE", port, "\u2192", dir2);
|
|
@@ -86163,7 +86485,7 @@ function startAutofillBridge(log9 = () => {
|
|
|
86163
86485
|
}
|
|
86164
86486
|
|
|
86165
86487
|
// ../../packages/host-core/dist/power-node.js
|
|
86166
|
-
import { spawn as
|
|
86488
|
+
import { spawn as spawn10 } from "node:child_process";
|
|
86167
86489
|
import { platform } from "node:os";
|
|
86168
86490
|
function createNodePowerController() {
|
|
86169
86491
|
const active = /* @__PURE__ */ new Set();
|
|
@@ -86171,9 +86493,9 @@ function createNodePowerController() {
|
|
|
86171
86493
|
function spawnInhibitor() {
|
|
86172
86494
|
try {
|
|
86173
86495
|
if (platform() === "darwin")
|
|
86174
|
-
return
|
|
86496
|
+
return spawn10("caffeinate", ["-i"], { stdio: "ignore" });
|
|
86175
86497
|
if (platform() === "linux") {
|
|
86176
|
-
return
|
|
86498
|
+
return spawn10("systemd-inhibit", ["--what=sleep", "--why=tesseract agent running", "--mode=block", "sleep", "infinity"], { stdio: "ignore" });
|
|
86177
86499
|
}
|
|
86178
86500
|
} catch {
|
|
86179
86501
|
}
|
|
@@ -86221,9 +86543,9 @@ function createNodePowerController() {
|
|
|
86221
86543
|
|
|
86222
86544
|
// ../../packages/host-core/dist/native-host.js
|
|
86223
86545
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
86224
|
-
import { chmodSync as chmodSync5, existsSync as existsSync27, mkdirSync as mkdirSync25, writeFileSync as
|
|
86546
|
+
import { chmodSync as chmodSync5, existsSync as existsSync27, mkdirSync as mkdirSync25, writeFileSync as writeFileSync25 } from "node:fs";
|
|
86225
86547
|
import { homedir as homedir7, platform as platform2 } from "node:os";
|
|
86226
|
-
import { dirname as dirname23, join as
|
|
86548
|
+
import { dirname as dirname23, join as join53, resolve as resolve10 } from "node:path";
|
|
86227
86549
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
86228
86550
|
var HOST_NAME = "com.tesseract.companion";
|
|
86229
86551
|
var EXTENSION_IDS = ["icpnghhpcmaonjckkpilpajblfehpplo", "giolfpookdhjfafcchaflhmigghaeffn"];
|
|
@@ -86232,18 +86554,18 @@ function browserProfileDirs() {
|
|
|
86232
86554
|
const home = homedir7();
|
|
86233
86555
|
const p = platform2();
|
|
86234
86556
|
if (p === "darwin") {
|
|
86235
|
-
const base =
|
|
86236
|
-
return ["Google/Chrome", "Google/Chrome Beta", "Google/Chrome Dev", "Google/Chrome Canary", "Chromium", "Microsoft Edge", "BraveSoftware/Brave-Browser", "Vivaldi", "Arc"].map((b) =>
|
|
86557
|
+
const base = join53(home, "Library/Application Support");
|
|
86558
|
+
return ["Google/Chrome", "Google/Chrome Beta", "Google/Chrome Dev", "Google/Chrome Canary", "Chromium", "Microsoft Edge", "BraveSoftware/Brave-Browser", "Vivaldi", "Arc"].map((b) => join53(base, b));
|
|
86237
86559
|
}
|
|
86238
86560
|
if (p === "win32")
|
|
86239
86561
|
return [];
|
|
86240
|
-
const cfg2 =
|
|
86241
|
-
return ["google-chrome", "google-chrome-beta", "chromium", "microsoft-edge", "BraveSoftware/Brave-Browser", "vivaldi"].map((b) =>
|
|
86562
|
+
const cfg2 = join53(home, ".config");
|
|
86563
|
+
return ["google-chrome", "google-chrome-beta", "chromium", "microsoft-edge", "BraveSoftware/Brave-Browser", "vivaldi"].map((b) => join53(cfg2, b));
|
|
86242
86564
|
}
|
|
86243
86565
|
function resolveBridge(log9) {
|
|
86244
86566
|
const candidates = [
|
|
86245
86567
|
process.env.CCB_COMPANION_HOST_JS,
|
|
86246
|
-
process.resourcesPath ?
|
|
86568
|
+
process.resourcesPath ? join53(process.resourcesPath, "companion-host", BRIDGE_BASENAME) : void 0
|
|
86247
86569
|
];
|
|
86248
86570
|
try {
|
|
86249
86571
|
const here = dirname23(fileURLToPath3(import.meta.url));
|
|
@@ -86259,14 +86581,14 @@ function resolveBridge(log9) {
|
|
|
86259
86581
|
}
|
|
86260
86582
|
function writeLauncher(daemonDir3, bridge, runtime) {
|
|
86261
86583
|
const isWin = platform2() === "win32";
|
|
86262
|
-
const launcher =
|
|
86584
|
+
const launcher = join53(daemonDir3, isWin ? "companion-host.cmd" : "companion-host.sh");
|
|
86263
86585
|
if (isWin) {
|
|
86264
|
-
|
|
86586
|
+
writeFileSync25(launcher, `@echo off\r
|
|
86265
86587
|
set ELECTRON_RUN_AS_NODE=1\r
|
|
86266
86588
|
"${runtime}" "${bridge}" %*\r
|
|
86267
86589
|
`);
|
|
86268
86590
|
} else {
|
|
86269
|
-
|
|
86591
|
+
writeFileSync25(launcher, `#!/bin/sh
|
|
86270
86592
|
# Tesseract Companion native-messaging launcher (auto-written by the daemon).
|
|
86271
86593
|
ELECTRON_RUN_AS_NODE=1 exec "${runtime}" "${bridge}" "$@"
|
|
86272
86594
|
`);
|
|
@@ -86297,9 +86619,9 @@ function registerNativeHost(opts) {
|
|
|
86297
86619
|
if (!existsSync27(profile))
|
|
86298
86620
|
continue;
|
|
86299
86621
|
try {
|
|
86300
|
-
const dir2 =
|
|
86622
|
+
const dir2 = join53(profile, "NativeMessagingHosts");
|
|
86301
86623
|
mkdirSync25(dir2, { recursive: true });
|
|
86302
|
-
|
|
86624
|
+
writeFileSync25(join53(dir2, `${HOST_NAME}.json`), manifestJson);
|
|
86303
86625
|
wrote++;
|
|
86304
86626
|
} catch {
|
|
86305
86627
|
}
|
|
@@ -86311,8 +86633,8 @@ function registerNativeHost(opts) {
|
|
|
86311
86633
|
}
|
|
86312
86634
|
function registerWindows(daemonDir3, manifestJson, log9) {
|
|
86313
86635
|
try {
|
|
86314
|
-
const manifestPath =
|
|
86315
|
-
|
|
86636
|
+
const manifestPath = join53(daemonDir3, `${HOST_NAME}.json`);
|
|
86637
|
+
writeFileSync25(manifestPath, manifestJson);
|
|
86316
86638
|
for (const root of ["Software\\Google\\Chrome", "Software\\Microsoft\\Edge", "Software\\BraveSoftware\\Brave-Browser"]) {
|
|
86317
86639
|
try {
|
|
86318
86640
|
execFileSync3("reg", ["add", `HKCU\\${root}\\NativeMessagingHosts\\${HOST_NAME}`, "/ve", "/t", "REG_SZ", "/d", manifestPath, "/f"], { stdio: "ignore" });
|
|
@@ -86326,10 +86648,10 @@ function registerWindows(daemonDir3, manifestJson, log9) {
|
|
|
86326
86648
|
}
|
|
86327
86649
|
|
|
86328
86650
|
// ../../packages/host-core/dist/activity/activity-tracker.js
|
|
86329
|
-
import { promises as fsp, writeFileSync as
|
|
86330
|
-
import { join as
|
|
86651
|
+
import { promises as fsp, writeFileSync as writeFileSync26, mkdirSync as mkdirSync26, existsSync as existsSync28 } from "node:fs";
|
|
86652
|
+
import { join as join54 } from "node:path";
|
|
86331
86653
|
function activityProfilePath() {
|
|
86332
|
-
return
|
|
86654
|
+
return join54(daemonDir2(), "activity-profile.json");
|
|
86333
86655
|
}
|
|
86334
86656
|
var MAX_APPS = 300;
|
|
86335
86657
|
var MAX_AGE_DAYS = 120;
|
|
@@ -86441,7 +86763,7 @@ function createActivityTracker(opts = {}) {
|
|
|
86441
86763
|
pruneProfile(profile);
|
|
86442
86764
|
profile.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
86443
86765
|
mkdirSync26(daemonDir2(), { recursive: true, mode: 448 });
|
|
86444
|
-
|
|
86766
|
+
writeFileSync26(activityProfilePath(), JSON.stringify(profile), { mode: 384 });
|
|
86445
86767
|
dirty = 0;
|
|
86446
86768
|
}
|
|
86447
86769
|
} catch (e) {
|
|
@@ -86455,9 +86777,6 @@ function createActivityTracker(opts = {}) {
|
|
|
86455
86777
|
};
|
|
86456
86778
|
}
|
|
86457
86779
|
|
|
86458
|
-
// ../../packages/host-core/dist/rdesk/server-auth.js
|
|
86459
|
-
var DEFAULT_API = (process.env.CCB_TESSERACT_API ?? "https://app.tesseract.dev").replace(/\/$/, "");
|
|
86460
|
-
|
|
86461
86780
|
// ../../packages/host-core/dist/gui/rdesk-client-window.js
|
|
86462
86781
|
var win = null;
|
|
86463
86782
|
function getRdeskClientWebContents() {
|
|
@@ -86475,46 +86794,7 @@ function getRdeskClientWebContents() {
|
|
|
86475
86794
|
}
|
|
86476
86795
|
|
|
86477
86796
|
// ../../packages/host-core/dist/gui/rdesk-call-window.js
|
|
86478
|
-
import { join as join54 } from "node:path";
|
|
86479
86797
|
var win2 = null;
|
|
86480
|
-
function showRdeskCallWindow(opts) {
|
|
86481
|
-
const el2 = electronModule();
|
|
86482
|
-
if (!el2?.BrowserWindow)
|
|
86483
|
-
return;
|
|
86484
|
-
if (win2 && !win2.isDestroyed()) {
|
|
86485
|
-
try {
|
|
86486
|
-
win2.focus();
|
|
86487
|
-
} catch {
|
|
86488
|
-
}
|
|
86489
|
-
return;
|
|
86490
|
-
}
|
|
86491
|
-
const w = new el2.BrowserWindow({
|
|
86492
|
-
width: 380,
|
|
86493
|
-
height: 320,
|
|
86494
|
-
resizable: true,
|
|
86495
|
-
minimizable: true,
|
|
86496
|
-
fullscreenable: false,
|
|
86497
|
-
alwaysOnTop: true,
|
|
86498
|
-
skipTaskbar: false,
|
|
86499
|
-
title: "Remote desktop \u2014 call",
|
|
86500
|
-
backgroundColor: "#15151a",
|
|
86501
|
-
webPreferences: { contextIsolation: true, sandbox: false }
|
|
86502
|
-
});
|
|
86503
|
-
try {
|
|
86504
|
-
w.setAlwaysOnTop(true, "floating");
|
|
86505
|
-
} catch {
|
|
86506
|
-
}
|
|
86507
|
-
w.on("closed", () => {
|
|
86508
|
-
win2 = null;
|
|
86509
|
-
try {
|
|
86510
|
-
opts.onClosed?.();
|
|
86511
|
-
} catch {
|
|
86512
|
-
}
|
|
86513
|
-
});
|
|
86514
|
-
const loadFile = w.loadFile;
|
|
86515
|
-
void loadFile(join54(daemonUiDir(), "rdesk-call.html"), { query: { url: opts.url, token: opts.token, room: opts.room } }).catch((e) => console.error("[rdesk-call] loadFile FAILED", e?.message ?? e));
|
|
86516
|
-
win2 = w;
|
|
86517
|
-
}
|
|
86518
86798
|
function closeRdeskCallWindow() {
|
|
86519
86799
|
const w = win2;
|
|
86520
86800
|
win2 = null;
|
|
@@ -86575,11 +86855,11 @@ async function runDaemon(opts = {}) {
|
|
|
86575
86855
|
}
|
|
86576
86856
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
86577
86857
|
try {
|
|
86578
|
-
|
|
86858
|
+
writeFileSync27(f, String(process.pid), { flag: "wx" });
|
|
86579
86859
|
return true;
|
|
86580
86860
|
} catch {
|
|
86581
86861
|
try {
|
|
86582
|
-
const prev = Number(
|
|
86862
|
+
const prev = Number(readFileSync32(f, "utf-8").trim());
|
|
86583
86863
|
if (!prev)
|
|
86584
86864
|
return false;
|
|
86585
86865
|
if (prev !== process.pid && isAlive2(prev))
|
|
@@ -86595,7 +86875,7 @@ async function runDaemon(opts = {}) {
|
|
|
86595
86875
|
function releaseLock() {
|
|
86596
86876
|
try {
|
|
86597
86877
|
const f = pidfile();
|
|
86598
|
-
if (existsSync29(f) && Number(
|
|
86878
|
+
if (existsSync29(f) && Number(readFileSync32(f, "utf-8").trim()) === process.pid)
|
|
86599
86879
|
unlinkSync4(f);
|
|
86600
86880
|
} catch {
|
|
86601
86881
|
}
|
|
@@ -86640,11 +86920,11 @@ async function runDaemon(opts = {}) {
|
|
|
86640
86920
|
let lockPid = 0, statusPid = 0;
|
|
86641
86921
|
const otherPids = [];
|
|
86642
86922
|
try {
|
|
86643
|
-
lockPid = Number(
|
|
86923
|
+
lockPid = Number(readFileSync32(pidfile(), "utf-8").trim());
|
|
86644
86924
|
} catch {
|
|
86645
86925
|
}
|
|
86646
86926
|
try {
|
|
86647
|
-
statusPid = Number(JSON.parse(
|
|
86927
|
+
statusPid = Number(JSON.parse(readFileSync32(statusFile(), "utf-8")).pid ?? 0);
|
|
86648
86928
|
} catch {
|
|
86649
86929
|
}
|
|
86650
86930
|
for (const p of otherDaemonPids())
|
|
@@ -86661,7 +86941,7 @@ async function runDaemon(opts = {}) {
|
|
|
86661
86941
|
}
|
|
86662
86942
|
function writeStatus2(s) {
|
|
86663
86943
|
try {
|
|
86664
|
-
|
|
86944
|
+
writeFileSync27(statusFile(), JSON.stringify({ pid: process.pid, version: VERSION2, execPath: process.execPath, updatedAt: (/* @__PURE__ */ new Date()).toISOString(), gui: daemonGuiTrayActive(), ...localInfo ?? {}, ...s }));
|
|
86665
86945
|
chmodSync6(statusFile(), 384);
|
|
86666
86946
|
} catch {
|
|
86667
86947
|
}
|
|
@@ -86675,7 +86955,7 @@ async function runDaemon(opts = {}) {
|
|
|
86675
86955
|
}
|
|
86676
86956
|
if (!acquireLock2()) {
|
|
86677
86957
|
try {
|
|
86678
|
-
|
|
86958
|
+
writeFileSync27(pidfile(), String(process.pid));
|
|
86679
86959
|
} catch {
|
|
86680
86960
|
}
|
|
86681
86961
|
}
|
|
@@ -86845,7 +87125,7 @@ async function runDaemon(opts = {}) {
|
|
|
86845
87125
|
process.env.CCB_HOST_DAEMON = "1";
|
|
86846
87126
|
const localToken = randomBytes8(24).toString("hex");
|
|
86847
87127
|
try {
|
|
86848
|
-
localServer = await startLocalServer({ hostRoot: resolveHostRoot(), token: localToken, log: log9, getRdesk: () => rdeskManager, loopbackRdeskSend });
|
|
87128
|
+
localServer = await startLocalServer({ hostRoot: resolveHostRoot(), token: localToken, log: log9, getRdesk: () => rdeskManager, loopbackRdeskSend, getRdeskSessions: () => rdeskRef?.sessionInfos() ?? [] });
|
|
86849
87129
|
localInfo = { localPort: localServer.port, localToken };
|
|
86850
87130
|
} catch (e) {
|
|
86851
87131
|
log9("local listener failed to start", e.message);
|
|
@@ -86975,7 +87255,7 @@ async function runDaemon(opts = {}) {
|
|
|
86975
87255
|
let rdeskRef = null;
|
|
86976
87256
|
const rdesk = new RdeskSessionManager({
|
|
86977
87257
|
createEngine: createRemoteDesktopEngine,
|
|
86978
|
-
consent: ({ viewerName }) => askRdeskConsent({ viewerName }),
|
|
87258
|
+
consent: ({ viewerName, grant }) => askRdeskConsent({ viewerName, grant }),
|
|
86979
87259
|
// Unattended-access password (Phase 4): a scrypt hash in daemon settings, opt-in.
|
|
86980
87260
|
checkPassword: (pw) => verifyRdeskPassword(pw),
|
|
86981
87261
|
// Route to the local viewer over loopback when this session's viewer connected via
|
|
@@ -86994,8 +87274,20 @@ async function runDaemon(opts = {}) {
|
|
|
86994
87274
|
else
|
|
86995
87275
|
relayRdeskSignal(msg, { clientId }, sessionId);
|
|
86996
87276
|
},
|
|
86997
|
-
|
|
86998
|
-
|
|
87277
|
+
// Two independent conditions: the GUI/tray must be up (we need it to capture), AND the
|
|
87278
|
+
// user must not have switched sharing off. Read FRESH so the Settings toggle applies to
|
|
87279
|
+
// the next connect with no daemon restart. NOTE this is deliberately rdesk-scoped — the
|
|
87280
|
+
// `sharing`/`driving` flag in control-link gates fs/term/agent TOGETHER, so turning
|
|
87281
|
+
// screen sharing on must never be implemented there.
|
|
87282
|
+
canServe: () => daemonGuiReady() && rdeskSharingEnabled(),
|
|
87283
|
+
// Read per connect (not captured once) for the same reason.
|
|
87284
|
+
defaultAccess: () => readRdeskServerPrefs().defaultAccess,
|
|
87285
|
+
// Was persisted by the settings UI and then ignored — sessions always started at 'auto'.
|
|
87286
|
+
defaultQuality: () => readRdeskServerPrefs().quality,
|
|
87287
|
+
// Each viewer costs a capture+encode window; cap the count so a runaway or hostile
|
|
87288
|
+
// client can't spawn them until the machine falls over. Override for a genuine
|
|
87289
|
+
// multi-viewer use case (training/demo) once there's a setting for it.
|
|
87290
|
+
maxSessions: Number(process.env.CCB_RDESK_MAX_SESSIONS ?? "3") || 3,
|
|
86999
87291
|
// Phase 3 host control plane: append every lifecycle event to the audit log, and
|
|
87000
87292
|
// reflect live sessions in the tray ("Sharing this screen — N viewers" + Stop all).
|
|
87001
87293
|
audit: (e) => appendRdeskAudit(e),
|
|
@@ -87009,33 +87301,23 @@ async function runDaemon(opts = {}) {
|
|
|
87009
87301
|
// joined to the SAME LiveKit room (= the rdesk sessionId) the viewer is in, so the person at the
|
|
87010
87302
|
// host can talk. Reuses the team-chat/huddle conferencing; the daemon mints its own join token
|
|
87011
87303
|
// with the device token (identity `${sub}#host`, distinct from the viewer's).
|
|
87012
|
-
|
|
87304
|
+
// Voice now rides the session's own peer connection (session-manager → engine.setAv),
|
|
87305
|
+
// so the host no longer mints a LiveKit token or opens an SFU call window for rdesk.
|
|
87306
|
+
// `onCall` is just the local surface: tell the person at this machine that the viewer
|
|
87307
|
+
// switched voice on. LiveKit stays exactly as it is for team huddles, which are 3+ way
|
|
87308
|
+
// and genuinely need an SFU.
|
|
87309
|
+
onCall: ({ sessionId, on, viewerName }) => {
|
|
87310
|
+
log9(`[rdesk call] ${viewerName ?? "viewer"} ${on ? "started" : "ended"} voice on ${sessionId}`);
|
|
87013
87311
|
if (!on) {
|
|
87014
87312
|
closeRdeskCallWindow();
|
|
87015
87313
|
return;
|
|
87016
87314
|
}
|
|
87017
|
-
|
|
87018
|
-
|
|
87019
|
-
|
|
87020
|
-
|
|
87021
|
-
|
|
87022
|
-
|
|
87023
|
-
signal: AbortSignal.timeout(1e4)
|
|
87024
|
-
});
|
|
87025
|
-
if (!r.ok) {
|
|
87026
|
-
log9(`[rdesk call] token mint ${r.status} (conferencing configured?)`);
|
|
87027
|
-
return;
|
|
87028
|
-
}
|
|
87029
|
-
const j = await r.json().catch(() => ({}));
|
|
87030
|
-
if (!j.token || !j.url) {
|
|
87031
|
-
log9("[rdesk call] token response missing token/url");
|
|
87032
|
-
return;
|
|
87033
|
-
}
|
|
87034
|
-
showRdeskCallWindow({ url: j.url, token: j.token, room: sessionId });
|
|
87035
|
-
} catch (e) {
|
|
87036
|
-
log9("[rdesk call] token mint failed", e instanceof Error ? e.message : String(e));
|
|
87037
|
-
}
|
|
87038
|
-
})();
|
|
87315
|
+
try {
|
|
87316
|
+
const NotifCtor = electronModule()?.Notification;
|
|
87317
|
+
if (NotifCtor)
|
|
87318
|
+
new NotifCtor({ title: "Remote desktop", body: `${viewerName ?? "The viewer"} turned on voice.` }).show();
|
|
87319
|
+
} catch {
|
|
87320
|
+
}
|
|
87039
87321
|
},
|
|
87040
87322
|
// In-session chat from the viewer → surface it to the operator as a native notification.
|
|
87041
87323
|
// On macOS the notification carries an inline REPLY box (hasReply) whose text is sent
|
|
@@ -87062,6 +87344,42 @@ async function runDaemon(opts = {}) {
|
|
|
87062
87344
|
log: (m) => log9(m)
|
|
87063
87345
|
});
|
|
87064
87346
|
rdeskRef = rdesk;
|
|
87347
|
+
try {
|
|
87348
|
+
if (rdeskSharingEnabled()) {
|
|
87349
|
+
const generated = ensureRdeskPassword();
|
|
87350
|
+
const prefs = readRdeskServerPrefs();
|
|
87351
|
+
if (generated && !prefs.noticeShownAt) {
|
|
87352
|
+
const id = getMachinePublicId();
|
|
87353
|
+
log9(`rdesk: generated an unattended password; this machine is reachable as ${id ?? "(id pending)"}`);
|
|
87354
|
+
try {
|
|
87355
|
+
const NotifCtor = electronModule()?.Notification;
|
|
87356
|
+
if (NotifCtor) {
|
|
87357
|
+
const n = new NotifCtor({
|
|
87358
|
+
title: "Remote Desktop is on",
|
|
87359
|
+
body: id ? `This machine can be reached with ID ${id} and its password. Open Settings to see it or turn it off.` : "This machine can be reached remotely. Open Settings to see its ID and password, or turn it off."
|
|
87360
|
+
});
|
|
87361
|
+
n.on("click", () => {
|
|
87362
|
+
void openMainAppSettings();
|
|
87363
|
+
});
|
|
87364
|
+
n.show();
|
|
87365
|
+
}
|
|
87366
|
+
} catch {
|
|
87367
|
+
}
|
|
87368
|
+
writeRdeskServerPrefs({ noticeShownAt: Date.now() });
|
|
87369
|
+
}
|
|
87370
|
+
}
|
|
87371
|
+
} catch (e) {
|
|
87372
|
+
log9(`rdesk: password/notice setup failed: ${e instanceof Error ? e.message : e}`);
|
|
87373
|
+
}
|
|
87374
|
+
let rdeskWasEnabled = rdeskSharingEnabled();
|
|
87375
|
+
setInterval(() => {
|
|
87376
|
+
const on = rdeskSharingEnabled();
|
|
87377
|
+
if (rdeskWasEnabled && !on) {
|
|
87378
|
+
log9("rdesk: sharing turned off \u2014 disconnecting live sessions");
|
|
87379
|
+
void rdeskRef?.disconnectAll("revoked");
|
|
87380
|
+
}
|
|
87381
|
+
rdeskWasEnabled = on;
|
|
87382
|
+
}, 3e4).unref?.();
|
|
87065
87383
|
rdeskManager = rdesk;
|
|
87066
87384
|
const chatAgent = createChatAgentRunner({
|
|
87067
87385
|
apiUrl: c.apiOrigin.replace(/\/$/, ""),
|
|
@@ -87104,7 +87422,7 @@ async function runDaemon(opts = {}) {
|
|
|
87104
87422
|
// Remote-desktop host: a viewer drives an rdesk session on this machine.
|
|
87105
87423
|
onRdesk: (payload, clientId, sessionId) => {
|
|
87106
87424
|
if (rdesk && clientId)
|
|
87107
|
-
void rdesk.onClientMessage(sessionId, { clientId
|
|
87425
|
+
void rdesk.onClientMessage(sessionId, { clientId }, payload);
|
|
87108
87426
|
},
|
|
87109
87427
|
onRdeskSignal: (payload, _clientId, sessionId) => {
|
|
87110
87428
|
rdesk?.onSignal(sessionId, payload);
|
|
@@ -87112,6 +87430,27 @@ async function runDaemon(opts = {}) {
|
|
|
87112
87430
|
// Standalone CLIENT (viewer) receive-side: forward the host's rdesk control events, WebRTC
|
|
87113
87431
|
// SDP/ICE signals, and session events to the client window. No client window ⇒ no-op, so
|
|
87114
87432
|
// the daemon-as-HOST path above is unchanged.
|
|
87433
|
+
// Someone is asking to connect to this account's machines. The daemon can't run the
|
|
87434
|
+
// approval UI, but it CAN say so — otherwise, with the app closed, the request reaches an
|
|
87435
|
+
// online host that ignores it AND the push is suppressed for exactly that reason (the
|
|
87436
|
+
// fan-out only pushes when nothing is online), so nobody ever hears about it.
|
|
87437
|
+
onRdeskRequest: (m) => {
|
|
87438
|
+
if (m?.type !== "rdesk:request")
|
|
87439
|
+
return;
|
|
87440
|
+
const who = typeof m.fromName === "string" ? m.fromName : "Someone";
|
|
87441
|
+
log9(`[rdesk request] ${who} is asking to connect`);
|
|
87442
|
+
try {
|
|
87443
|
+
const NotifCtor = electronModule()?.Notification;
|
|
87444
|
+
if (!NotifCtor)
|
|
87445
|
+
return;
|
|
87446
|
+
const n = new NotifCtor({ title: "Remote desktop request", body: `${who} wants to connect to your computer. Open Tesseract to answer.` });
|
|
87447
|
+
n.on("click", () => {
|
|
87448
|
+
void openMainApp();
|
|
87449
|
+
});
|
|
87450
|
+
n.show();
|
|
87451
|
+
} catch {
|
|
87452
|
+
}
|
|
87453
|
+
},
|
|
87115
87454
|
onSessionEvent: (msg) => {
|
|
87116
87455
|
getRdeskClientWebContents()?.send("session:event", msg);
|
|
87117
87456
|
},
|
|
@@ -87185,17 +87524,17 @@ var CHUNK_BYTES = 256 * 1024;
|
|
|
87185
87524
|
import { platform as platform3 } from "node:os";
|
|
87186
87525
|
|
|
87187
87526
|
// ../../packages/host-core/dist/service/launchd.js
|
|
87188
|
-
import { writeFileSync as
|
|
87527
|
+
import { writeFileSync as writeFileSync28, existsSync as existsSync30, mkdirSync as mkdirSync28, unlinkSync as unlinkSync5 } from "node:fs";
|
|
87189
87528
|
import { dirname as dirname24, join as join56 } from "node:path";
|
|
87190
87529
|
import { homedir as homedir8, userInfo } from "node:os";
|
|
87191
87530
|
|
|
87192
87531
|
// ../../packages/host-core/dist/service/exec.js
|
|
87193
|
-
import { execFile as execFile7, spawn as
|
|
87532
|
+
import { execFile as execFile7, spawn as spawn11 } from "node:child_process";
|
|
87194
87533
|
import { promisify as promisify6 } from "node:util";
|
|
87195
87534
|
var run3 = promisify6(execFile7);
|
|
87196
87535
|
function runInherit(cmd, args) {
|
|
87197
87536
|
return new Promise((resolve14) => {
|
|
87198
|
-
const p =
|
|
87537
|
+
const p = spawn11(cmd, args, { stdio: "inherit" });
|
|
87199
87538
|
p.on("error", () => resolve14());
|
|
87200
87539
|
p.on("close", () => resolve14());
|
|
87201
87540
|
});
|
|
@@ -87261,7 +87600,7 @@ ${env}
|
|
|
87261
87600
|
mkdirSync28(workDirOf(spec), { recursive: true });
|
|
87262
87601
|
mkdirSync28(dirname24(plistPath()), { recursive: true });
|
|
87263
87602
|
mkdirSync28(dirname24(spec.logPath), { recursive: true });
|
|
87264
|
-
|
|
87603
|
+
writeFileSync28(plistPath(), buildPlist(spec));
|
|
87265
87604
|
await run3("launchctl", ["bootout", serviceTarget()]).catch(() => {
|
|
87266
87605
|
});
|
|
87267
87606
|
await run3("launchctl", ["bootstrap", domainTarget(), plistPath()]);
|
|
@@ -87311,7 +87650,7 @@ ${env}
|
|
|
87311
87650
|
}
|
|
87312
87651
|
|
|
87313
87652
|
// ../../packages/host-core/dist/service/systemd.js
|
|
87314
|
-
import { writeFileSync as
|
|
87653
|
+
import { writeFileSync as writeFileSync29, existsSync as existsSync31, mkdirSync as mkdirSync29, unlinkSync as unlinkSync6 } from "node:fs";
|
|
87315
87654
|
import { dirname as dirname25, join as join57 } from "node:path";
|
|
87316
87655
|
import { homedir as homedir9, userInfo as userInfo2 } from "node:os";
|
|
87317
87656
|
function unitVal(v) {
|
|
@@ -87354,7 +87693,7 @@ WantedBy=default.target
|
|
|
87354
87693
|
mkdirSync29(workDirOf(spec), { recursive: true });
|
|
87355
87694
|
mkdirSync29(dirname25(unitPath()), { recursive: true });
|
|
87356
87695
|
mkdirSync29(dirname25(spec.logPath), { recursive: true });
|
|
87357
|
-
|
|
87696
|
+
writeFileSync29(unitPath(), buildUnit(spec));
|
|
87358
87697
|
await run3("loginctl", ["enable-linger", userInfo2().username]).catch(() => {
|
|
87359
87698
|
});
|
|
87360
87699
|
await run3("systemctl", ["--user", "daemon-reload"]).catch(() => {
|
|
@@ -87397,7 +87736,7 @@ WantedBy=default.target
|
|
|
87397
87736
|
}
|
|
87398
87737
|
|
|
87399
87738
|
// ../../packages/host-core/dist/service/windows.js
|
|
87400
|
-
import { writeFileSync as
|
|
87739
|
+
import { writeFileSync as writeFileSync30, existsSync as existsSync32, mkdirSync as mkdirSync30, unlinkSync as unlinkSync7 } from "node:fs";
|
|
87401
87740
|
import { dirname as dirname26, join as join58 } from "node:path";
|
|
87402
87741
|
function makeWindowsTask(instanceId) {
|
|
87403
87742
|
const task = `Fineguide\\TesseractHost${instanceId ? `-${instanceId}` : ""}`;
|
|
@@ -87421,7 +87760,7 @@ start "" /b ${cmd} >> "${oneLine2(spec.logPath).replace(/"/g, "")}" 2>&1\r
|
|
|
87421
87760
|
mkdirSync30(spec.workingDirectory ?? daemonDir2(), { recursive: true });
|
|
87422
87761
|
mkdirSync30(dirname26(spec.logPath), { recursive: true });
|
|
87423
87762
|
mkdirSync30(dirname26(wrapperPath()), { recursive: true });
|
|
87424
|
-
|
|
87763
|
+
writeFileSync30(wrapperPath(), buildWrapper(spec));
|
|
87425
87764
|
await run3("schtasks", ["/Create", "/TN", task, "/SC", "ONLOGON", "/RL", "LIMITED", "/F", "/TR", `"${wrapperPath()}"`]);
|
|
87426
87765
|
await run3("schtasks", ["/Run", "/TN", task]).catch(() => {
|
|
87427
87766
|
});
|
|
@@ -87709,7 +88048,7 @@ function whoami() {
|
|
|
87709
88048
|
}
|
|
87710
88049
|
|
|
87711
88050
|
// src/self-update.ts
|
|
87712
|
-
import { spawn as
|
|
88051
|
+
import { spawn as spawn12 } from "node:child_process";
|
|
87713
88052
|
import { createPublicKey, verify as cryptoVerify } from "node:crypto";
|
|
87714
88053
|
var RESTART_EXIT_CODE = 75;
|
|
87715
88054
|
var REGISTRY_BASE = "https://registry.npmjs.org/tesseract-agent";
|
|
@@ -87784,7 +88123,7 @@ function installVersion(target) {
|
|
|
87784
88123
|
log8(`installing tesseract-agent@${target} \u2026`);
|
|
87785
88124
|
let child;
|
|
87786
88125
|
try {
|
|
87787
|
-
child =
|
|
88126
|
+
child = spawn12(npm, ["install", "-g", `tesseract-agent@${target}`], { stdio: ["ignore", "inherit", "inherit"] });
|
|
87788
88127
|
} catch (e) {
|
|
87789
88128
|
log8("npm spawn threw:", e instanceof Error ? e.message : String(e));
|
|
87790
88129
|
resolve14(false);
|
|
@@ -87849,7 +88188,7 @@ function startSelfUpdater(current) {
|
|
|
87849
88188
|
// src/service.ts
|
|
87850
88189
|
import { join as join60 } from "node:path";
|
|
87851
88190
|
import { platform as platform4 } from "node:os";
|
|
87852
|
-
import { existsSync as existsSync34, readFileSync as
|
|
88191
|
+
import { existsSync as existsSync34, readFileSync as readFileSync33 } from "node:fs";
|
|
87853
88192
|
function controller(instanceId) {
|
|
87854
88193
|
const c = getServiceController(instanceId);
|
|
87855
88194
|
if (!c) {
|
|
@@ -87877,7 +88216,7 @@ function runningDaemonInfo() {
|
|
|
87877
88216
|
const lock = join60(daemonDir2(), "daemon.lock");
|
|
87878
88217
|
try {
|
|
87879
88218
|
if (!existsSync34(lock)) return null;
|
|
87880
|
-
const pid = Number(
|
|
88219
|
+
const pid = Number(readFileSync33(lock, "utf-8").trim());
|
|
87881
88220
|
if (!pid || !isAlive(pid)) return null;
|
|
87882
88221
|
return { pid, device: readCredentials()?.deviceId };
|
|
87883
88222
|
} catch {
|
|
@@ -87911,7 +88250,7 @@ async function logs(instanceId, follow) {
|
|
|
87911
88250
|
}
|
|
87912
88251
|
|
|
87913
88252
|
// src/net.ts
|
|
87914
|
-
import { readFileSync as
|
|
88253
|
+
import { readFileSync as readFileSync35 } from "node:fs";
|
|
87915
88254
|
import { resolve as resolve12 } from "node:path";
|
|
87916
88255
|
function usage() {
|
|
87917
88256
|
console.log(`Usage:
|
|
@@ -87934,7 +88273,7 @@ function readOrDie(label, p) {
|
|
|
87934
88273
|
process.exit(1);
|
|
87935
88274
|
}
|
|
87936
88275
|
try {
|
|
87937
|
-
return new Uint8Array(
|
|
88276
|
+
return new Uint8Array(readFileSync35(resolve12(p)));
|
|
87938
88277
|
} catch (e) {
|
|
87939
88278
|
console.error(`net enroll: could not read --${label} ${p}: ${e instanceof Error ? e.message : e}`);
|
|
87940
88279
|
process.exit(1);
|
|
@@ -88037,7 +88376,7 @@ async function netCommand(rest, flags) {
|
|
|
88037
88376
|
function pkgVersion() {
|
|
88038
88377
|
try {
|
|
88039
88378
|
const p = join63(dirname27(fileURLToPath4(import.meta.url)), "..", "package.json");
|
|
88040
|
-
return JSON.parse(
|
|
88379
|
+
return JSON.parse(readFileSync36(p, "utf8")).version ?? "0.0.0";
|
|
88041
88380
|
} catch {
|
|
88042
88381
|
return "0.0.0";
|
|
88043
88382
|
}
|
|
@@ -88093,7 +88432,7 @@ async function superviseDaemon(cliEntry) {
|
|
|
88093
88432
|
let stopping3 = false;
|
|
88094
88433
|
let child = null;
|
|
88095
88434
|
const spawnWorker = () => {
|
|
88096
|
-
const c =
|
|
88435
|
+
const c = spawn13(process.execPath, [cliEntry, "__worker"], { stdio: "inherit", env: process.env });
|
|
88097
88436
|
child = c;
|
|
88098
88437
|
let settled = false;
|
|
88099
88438
|
const settle = (fn) => {
|
|
@@ -88242,7 +88581,7 @@ async function captureClaudeSubscription(flags) {
|
|
|
88242
88581
|
console.log("Open the authorization URL in any browser; paste the returned code here if Claude asks for it.");
|
|
88243
88582
|
try {
|
|
88244
88583
|
const code = await new Promise((resolveCode, reject) => {
|
|
88245
|
-
const child =
|
|
88584
|
+
const child = spawn13(binary, args, {
|
|
88246
88585
|
env: { ...process.env, CLAUDE_CONFIG_DIR: home },
|
|
88247
88586
|
stdio: "inherit"
|
|
88248
88587
|
});
|
|
@@ -88251,7 +88590,7 @@ async function captureClaudeSubscription(flags) {
|
|
|
88251
88590
|
});
|
|
88252
88591
|
if (code !== 0) throw new Error(`Claude sign-in did not complete (exit ${code}).`);
|
|
88253
88592
|
const file2 = join63(home, ".credentials.json");
|
|
88254
|
-
if (existsSync36(file2)) return
|
|
88593
|
+
if (existsSync36(file2)) return readFileSync36(file2, "utf8");
|
|
88255
88594
|
if (process.platform === "darwin") {
|
|
88256
88595
|
const value = execFileSync5("security", [
|
|
88257
88596
|
"find-generic-password",
|
|
@@ -88333,7 +88672,7 @@ async function runnerCommand(rest, flags) {
|
|
|
88333
88672
|
process.exit(1);
|
|
88334
88673
|
}
|
|
88335
88674
|
const oauthFilePath = typeof flags["oauth-file"] === "string" ? resolve13(flags["oauth-file"]) : void 0;
|
|
88336
|
-
const oauthAuthFile = oauthFilePath ?
|
|
88675
|
+
const oauthAuthFile = oauthFilePath ? readFileSync36(oauthFilePath, "utf8") : void 0;
|
|
88337
88676
|
if (oauthAuthFile) {
|
|
88338
88677
|
try {
|
|
88339
88678
|
JSON.parse(oauthAuthFile);
|