windows-development-sandbox 1.13.2 → 1.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app/features/storage/storage.run.js +1 -1
- package/dist/bin/agent-sandbox.js +2 -2
- package/dist/bin/{chunk-VENWSGX2.js → chunk-BQ23GBLC.js} +411 -58
- package/dist/bin/{chunk-K4SU3MHJ.js → chunk-F7IMME5G.js} +1 -1
- package/dist/bin/{chunk-IL7BXJF2.js → chunk-LQHEUN2A.js} +1 -1
- package/dist/bin/claude-host.js +2 -2
- package/dist/bin/claude-sbx.js +2 -2
- package/dist/bin/codex-sbx.js +2 -2
- package/dist/bin/gemini-sbx.js +2 -2
- package/dist/bin/sandbox.js +2 -2
- package/dist/bin/sbx-hide.js +2 -2
- package/dist/bin/sbx-show.js +2 -2
- package/dist/cli/commands/launch/launch.js +1 -1
- package/dist/cli/commands/repair/checks/contained.js +1 -1
- package/dist/guest/daemon/sessions.d.ts +7 -0
- package/dist/guest/daemon/sessions.js +23 -2
- package/dist/guest/entries/daemon.js +1 -0
- package/dist/guest/sessions/pty-host.d.ts +10 -0
- package/dist/guest/sessions/pty-host.js +48 -3
- package/dist/host/channel/channel.js +1 -1
- package/dist/host/install/install-record.d.ts +1 -0
- package/dist/host/install/install-record.js +2 -0
- package/dist/host/sandbox/contained-deps.d.ts +2 -1
- package/dist/host/sandbox/contained-deps.js +6 -4
- package/dist/host/sharing/lifecycle.js +9 -1
- package/dist/host/storage/contained/contained-storage.js +13 -0
- package/dist/host/storage/contained/disk-port.d.ts +5 -0
- package/dist/host/storage/contained/helper-port.d.ts +72 -0
- package/dist/host/storage/contained/helper-port.js +162 -0
- package/dist/host/storage/contained/index.d.ts +1 -0
- package/dist/host/storage/contained/index.js +1 -0
- package/dist/host/web/bridge.d.ts +5 -0
- package/dist/host/web/bridge.js +11 -1
- package/dist/host/web/server.d.ts +2 -0
- package/dist/host/web/server.js +11 -1
- package/dist/runtime/agent.js +9 -0
- package/dist/runtime/daemon.js +57 -3
- package/dist/runtime/db.js +9 -0
- package/dist/runtime/main.js +195 -12
- package/dist/runtime/netproxy.js +9 -0
- package/dist/runtime/view.js +195 -12
- package/dist/selftest/channel.test.js +72 -1
- package/dist/selftest/contained.test.js +1 -37
- package/dist/selftest/hcs.test.js +5 -2
- package/dist/selftest/index.js +2 -0
- package/dist/selftest/install.test.js +11 -0
- package/dist/selftest/live-daemon.test.js +51 -1
- package/dist/selftest/live-terminal.test.js +112 -4
- package/dist/selftest/storage-helper.test.d.ts +2 -0
- package/dist/selftest/storage-helper.test.js +493 -0
- package/dist/selftest/support/vhdx.d.ts +14 -0
- package/dist/selftest/support/vhdx.js +72 -0
- package/dist/selftest/web.test.js +14 -2
- package/dist/shared/channel/run-dir.d.ts +6 -0
- package/dist/shared/channel/run-dir.js +9 -0
- package/dist/shared/pty/index.d.ts +3 -1
- package/dist/shared/pty/index.js +3 -1
- package/dist/shared/pty/key-gate.d.ts +24 -0
- package/dist/shared/pty/key-gate.js +45 -0
- package/dist/shared/pty/mouse-modes.d.ts +27 -0
- package/dist/shared/pty/mouse-modes.js +155 -0
- package/dist/shared/pty/terminal.d.ts +0 -5
- package/dist/shared/pty/terminal.js +51 -20
- package/dist/sync/watcher.js +1 -1
- package/dist/web/index.html +1 -1
- package/dist/web/{main-NBQ3LF4E.js → main-6XNBTJLT.js} +33 -33
- package/native/csharp/HcsHost/AssemblyInfo.cs +3 -3
- package/native/csharp/HostTools/AssemblyInfo.cs +3 -3
- package/native/csharp/StorageHelper/AssemblyInfo.cs +15 -0
- package/native/csharp/StorageHelper/Client.cs +297 -0
- package/native/csharp/StorageHelper/Log.cs +177 -0
- package/native/csharp/StorageHelper/MountRecords.cs +160 -0
- package/native/csharp/StorageHelper/Operations.cs +596 -0
- package/native/csharp/StorageHelper/Pins.cs +270 -0
- package/native/csharp/StorageHelper/Privileges.cs +78 -0
- package/native/csharp/StorageHelper/Program.cs +349 -0
- package/native/csharp/StorageHelper/Protocol.cs +107 -0
- package/native/csharp/StorageHelper/RateLimiter.cs +97 -0
- package/native/csharp/StorageHelper/Rules.cs +156 -0
- package/native/csharp/StorageHelper/Server.cs +656 -0
- package/native/csharp/StorageHelper/Settings.cs +297 -0
- package/native/csharp/StorageHelper/StorageService.cs +53 -0
- package/native/csharp/StorageHelper/UserSettings.cs +206 -0
- package/native/csharp/StorageHelper/Vhdx.cs +230 -0
- package/native/csharp/StorageHelper/VirtualDisk.cs +241 -0
- package/native/csharp/StorageHelper/Volumes.cs +379 -0
- package/native/csharp/StorageHelper/Watchdog.cs +128 -0
- package/native/csharp/StorageHelper/Win32.cs +250 -0
- package/native/scripts/set-storage-helper.ps1 +203 -0
- package/package.json +1 -1
- package/sandbox/csharp/PtyHost.cs +236 -1
|
@@ -20056,7 +20056,7 @@ var require_websocket = __commonJS({
|
|
|
20056
20056
|
var EventEmitter = __require("events");
|
|
20057
20057
|
var https2 = __require("https");
|
|
20058
20058
|
var http3 = __require("http");
|
|
20059
|
-
var
|
|
20059
|
+
var net8 = __require("net");
|
|
20060
20060
|
var tls = __require("tls");
|
|
20061
20061
|
var { randomBytes, createHash } = __require("crypto");
|
|
20062
20062
|
var { Duplex, Readable: Readable2 } = __require("stream");
|
|
@@ -20813,12 +20813,12 @@ var require_websocket = __commonJS({
|
|
|
20813
20813
|
}
|
|
20814
20814
|
function netConnect(options) {
|
|
20815
20815
|
options.path = options.socketPath;
|
|
20816
|
-
return
|
|
20816
|
+
return net8.connect(options);
|
|
20817
20817
|
}
|
|
20818
20818
|
function tlsConnect(options) {
|
|
20819
20819
|
options.path = void 0;
|
|
20820
20820
|
if (!options.servername && options.servername !== "") {
|
|
20821
|
-
options.servername =
|
|
20821
|
+
options.servername = net8.isIP(options.host) ? "" : options.host;
|
|
20822
20822
|
}
|
|
20823
20823
|
return tls.connect(options);
|
|
20824
20824
|
}
|
|
@@ -51219,6 +51219,14 @@ var ContainedStorage = class {
|
|
|
51219
51219
|
userSid: this.deps.userSid()
|
|
51220
51220
|
});
|
|
51221
51221
|
this.requireOk(outcome, "mount");
|
|
51222
|
+
} else {
|
|
51223
|
+
const confirmed = await this.deps.port.confirmMounted?.({
|
|
51224
|
+
paths,
|
|
51225
|
+
maxGb: this.deps.maxGb,
|
|
51226
|
+
create: false,
|
|
51227
|
+
userSid: this.deps.userSid()
|
|
51228
|
+
});
|
|
51229
|
+
if (confirmed) this.requireOk(confirmed, "mount");
|
|
51222
51230
|
}
|
|
51223
51231
|
this.assertReallyMounted();
|
|
51224
51232
|
for (const name2 of CONTAINED_FOLDERS) fs18.mkdirSync(path26.join(paths.mount, name2), { recursive: true });
|
|
@@ -51473,6 +51481,138 @@ function safeJson(text) {
|
|
|
51473
51481
|
}
|
|
51474
51482
|
}
|
|
51475
51483
|
|
|
51484
|
+
// src/host/storage/contained/helper-port.ts
|
|
51485
|
+
import net from "node:net";
|
|
51486
|
+
var HELPER_PIPE = "\\\\.\\pipe\\AgentSandboxStorage";
|
|
51487
|
+
var HELPER_PROTOCOL = 1;
|
|
51488
|
+
var MOUNT_TIMEOUT_MS2 = 10 * 6e4;
|
|
51489
|
+
var MAX_ANSWER_BYTES = 64 * 1024;
|
|
51490
|
+
var HelperRequestSchema = external_exports.object({ verb: external_exports.enum(["mount", "dismount"]), set: external_exports.string().regex(SET_NAME_RULE) }).strict();
|
|
51491
|
+
var HelperAnswerSchema = external_exports.object({
|
|
51492
|
+
protocol: external_exports.number().int(),
|
|
51493
|
+
ok: external_exports.boolean(),
|
|
51494
|
+
message: external_exports.string().max(4e3),
|
|
51495
|
+
created: external_exports.boolean(),
|
|
51496
|
+
alreadyMounted: external_exports.boolean(),
|
|
51497
|
+
fallback: external_exports.boolean(),
|
|
51498
|
+
image: external_exports.string().max(1e3),
|
|
51499
|
+
mount: external_exports.string().max(1e3),
|
|
51500
|
+
notes: external_exports.array(external_exports.string().max(1e3)).max(50)
|
|
51501
|
+
});
|
|
51502
|
+
var ABSENT_CODES = /* @__PURE__ */ new Set(["ENOENT", "EACCES", "EPERM", "ECONNREFUSED"]);
|
|
51503
|
+
var pipeConnector = (pipe2, line, timeoutMs) => new Promise((resolve) => {
|
|
51504
|
+
let text = "";
|
|
51505
|
+
let connected = false;
|
|
51506
|
+
let settled = false;
|
|
51507
|
+
const done = (result) => {
|
|
51508
|
+
if (settled) return;
|
|
51509
|
+
settled = true;
|
|
51510
|
+
clearTimeout(timer);
|
|
51511
|
+
socket.destroy();
|
|
51512
|
+
resolve(result);
|
|
51513
|
+
};
|
|
51514
|
+
const socket = net.connect(pipe2);
|
|
51515
|
+
const timer = setTimeout(
|
|
51516
|
+
() => done({ kind: "failed", reason: "the storage helper did not answer in time" }),
|
|
51517
|
+
timeoutMs
|
|
51518
|
+
);
|
|
51519
|
+
socket.setEncoding("utf8");
|
|
51520
|
+
socket.on("connect", () => {
|
|
51521
|
+
connected = true;
|
|
51522
|
+
socket.write(line + "\n");
|
|
51523
|
+
});
|
|
51524
|
+
socket.on("data", (chunk) => {
|
|
51525
|
+
text += chunk;
|
|
51526
|
+
const end = text.indexOf("\n");
|
|
51527
|
+
if (end >= 0) done({ kind: "answer", text: text.slice(0, end) });
|
|
51528
|
+
else if (text.length > MAX_ANSWER_BYTES) done({ kind: "failed", reason: "the storage helper answered too much" });
|
|
51529
|
+
});
|
|
51530
|
+
socket.on("error", (e) => {
|
|
51531
|
+
if (!connected && ABSENT_CODES.has(e.code ?? "")) done({ kind: "absent", reason: e.code ?? "no pipe" });
|
|
51532
|
+
else done({ kind: "failed", reason: e.message });
|
|
51533
|
+
});
|
|
51534
|
+
socket.on("close", () => done({ kind: "failed", reason: "the storage helper closed the connection" }));
|
|
51535
|
+
});
|
|
51536
|
+
function helperApplies(env, configOverridden) {
|
|
51537
|
+
if (configOverridden) return false;
|
|
51538
|
+
return !env.AGENT_SANDBOX_CONFIG && !env.AGENT_SANDBOX_HOME;
|
|
51539
|
+
}
|
|
51540
|
+
function samePaths(answer, paths) {
|
|
51541
|
+
const norm3 = (p) => p.replace(/\\+$/, "").toLowerCase();
|
|
51542
|
+
return norm3(answer.image) === norm3(paths.image) && norm3(answer.mount) === norm3(paths.mount);
|
|
51543
|
+
}
|
|
51544
|
+
function readAnswer(result, paths) {
|
|
51545
|
+
if (result.kind === "absent") return { use: "fallback", why: "no storage helper (" + result.reason + ")" };
|
|
51546
|
+
if (result.kind === "failed")
|
|
51547
|
+
return { use: "outcome", outcome: failed("The storage helper did not finish: " + result.reason + ".") };
|
|
51548
|
+
let raw;
|
|
51549
|
+
try {
|
|
51550
|
+
raw = JSON.parse(result.text);
|
|
51551
|
+
} catch {
|
|
51552
|
+
return { use: "fallback", why: "the storage helper gave an answer that is not JSON" };
|
|
51553
|
+
}
|
|
51554
|
+
const parsed = HelperAnswerSchema.safeParse(raw);
|
|
51555
|
+
if (!parsed.success || parsed.data.protocol !== HELPER_PROTOCOL)
|
|
51556
|
+
return { use: "fallback", why: "the storage helper speaks another version" };
|
|
51557
|
+
const answer = parsed.data;
|
|
51558
|
+
if (answer.fallback) return { use: "fallback", why: answer.message };
|
|
51559
|
+
if (answer.ok && !samePaths(answer, paths))
|
|
51560
|
+
return {
|
|
51561
|
+
use: "outcome",
|
|
51562
|
+
outcome: failed(
|
|
51563
|
+
"The storage helper used other folders (" + answer.mount + ") than this command (" + paths.mount + "): your settings differ from what it reads. Run sandbox doctor."
|
|
51564
|
+
)
|
|
51565
|
+
};
|
|
51566
|
+
return {
|
|
51567
|
+
use: "outcome",
|
|
51568
|
+
outcome: {
|
|
51569
|
+
ok: answer.ok,
|
|
51570
|
+
message: answer.message,
|
|
51571
|
+
created: answer.created,
|
|
51572
|
+
alreadyMounted: answer.alreadyMounted,
|
|
51573
|
+
notes: answer.notes
|
|
51574
|
+
}
|
|
51575
|
+
};
|
|
51576
|
+
}
|
|
51577
|
+
function failed(message) {
|
|
51578
|
+
return { ok: false, message, created: false, alreadyMounted: false, notes: [] };
|
|
51579
|
+
}
|
|
51580
|
+
var HelperDiskPort = class {
|
|
51581
|
+
constructor(fallback, applies, connect2 = pipeConnector, pipe2 = HELPER_PIPE) {
|
|
51582
|
+
this.fallback = fallback;
|
|
51583
|
+
this.applies = applies;
|
|
51584
|
+
this.connect = connect2;
|
|
51585
|
+
this.pipe = pipe2;
|
|
51586
|
+
}
|
|
51587
|
+
fallback;
|
|
51588
|
+
applies;
|
|
51589
|
+
connect;
|
|
51590
|
+
pipe;
|
|
51591
|
+
async mount(request2) {
|
|
51592
|
+
const answer = await this.ask({ verb: "mount", set: request2.paths.set }, request2.paths);
|
|
51593
|
+
return answer ?? this.fallback.mount(request2);
|
|
51594
|
+
}
|
|
51595
|
+
/** The helper checks a mount without a prompt (it is "mounted already" only for this image); null without it. */
|
|
51596
|
+
confirmMounted(request2) {
|
|
51597
|
+
return this.ask({ verb: "mount", set: request2.paths.set }, request2.paths);
|
|
51598
|
+
}
|
|
51599
|
+
async dismount(request2) {
|
|
51600
|
+
const answer = await this.ask({ verb: "dismount", set: request2.paths.set }, request2.paths);
|
|
51601
|
+
return answer ?? this.fallback.dismount(request2);
|
|
51602
|
+
}
|
|
51603
|
+
reality(paths) {
|
|
51604
|
+
return this.fallback.reality(paths);
|
|
51605
|
+
}
|
|
51606
|
+
/** The helper's outcome, or null to use the permission prompt. */
|
|
51607
|
+
async ask(request2, paths) {
|
|
51608
|
+
if (!this.applies) return null;
|
|
51609
|
+
if (this.pipe === HELPER_PIPE) refuseInSelfTest("mount or dismount a disk image");
|
|
51610
|
+
const line = JSON.stringify(HelperRequestSchema.parse(request2));
|
|
51611
|
+
const read = readAnswer(await this.connect(this.pipe, line, MOUNT_TIMEOUT_MS2), paths);
|
|
51612
|
+
return read.use === "outcome" ? read.outcome : null;
|
|
51613
|
+
}
|
|
51614
|
+
};
|
|
51615
|
+
|
|
51476
51616
|
// src/host/storage/contained/resolve.ts
|
|
51477
51617
|
import fs21 from "node:fs";
|
|
51478
51618
|
import path29 from "node:path";
|
|
@@ -52959,6 +53099,11 @@ var RunDir = class {
|
|
|
52959
53099
|
projectsDir;
|
|
52960
53100
|
/** audit.processes: programs the sandbox started, in small .jsonl files the host takes in and deletes. */
|
|
52961
53101
|
auditDir;
|
|
53102
|
+
/**
|
|
53103
|
+
* Each running session's process tree, recorded by its ptyhost (guest only: the daemon ends what a ptyhost that was
|
|
53104
|
+
* itself ended left running).
|
|
53105
|
+
*/
|
|
53106
|
+
treesDir;
|
|
52962
53107
|
/** One-shot secrets the host hands over (see secrets.ts). Next to run, not in it: shared-use users can change run. */
|
|
52963
53108
|
secretsDir;
|
|
52964
53109
|
constructor(dataDir) {
|
|
@@ -52972,6 +53117,7 @@ var RunDir = class {
|
|
|
52972
53117
|
this.sessionsDir = path41.join(this.root, "sessions");
|
|
52973
53118
|
this.projectsDir = path41.join(this.root, "projects");
|
|
52974
53119
|
this.auditDir = path41.join(this.root, "audit");
|
|
53120
|
+
this.treesDir = path41.join(this.root, "trees");
|
|
52975
53121
|
this.secretsDir = path41.join(dataDir, "secrets");
|
|
52976
53122
|
}
|
|
52977
53123
|
requestFile(id) {
|
|
@@ -52983,6 +53129,9 @@ var RunDir = class {
|
|
|
52983
53129
|
sessionFile(id) {
|
|
52984
53130
|
return path41.join(this.sessionsDir, safeId(id) + ".json");
|
|
52985
53131
|
}
|
|
53132
|
+
treeFile(id) {
|
|
53133
|
+
return path41.join(this.treesDir, safeId(id) + ".json");
|
|
53134
|
+
}
|
|
52986
53135
|
projectFile(name2) {
|
|
52987
53136
|
return path41.join(this.projectsDir, safeId(name2) + ".json");
|
|
52988
53137
|
}
|
|
@@ -53218,6 +53367,8 @@ var InstallRecordSchema = external_exports.object({
|
|
|
53218
53367
|
scope: external_exports.enum(["user", "machine"]),
|
|
53219
53368
|
groupSid: external_exports.string().nullable(),
|
|
53220
53369
|
autoUpdate: external_exports.boolean(),
|
|
53370
|
+
/** All-users installs: the storage helper service (AgentSandboxStorage) was installed. Older records have none. */
|
|
53371
|
+
storageHelper: external_exports.boolean().optional(),
|
|
53221
53372
|
installedAt: external_exports.string()
|
|
53222
53373
|
});
|
|
53223
53374
|
var InstallRecordFile = class {
|
|
@@ -53452,7 +53603,15 @@ function beginSharing(deps, start, now2 = /* @__PURE__ */ new Date()) {
|
|
|
53452
53603
|
deps.records.write({ ...start, startedAt: start.startedAt ?? now2.toISOString() });
|
|
53453
53604
|
if (!opens(deps, start.dataPath)) return;
|
|
53454
53605
|
const run3 = new RunDir(start.dataPath);
|
|
53455
|
-
for (const dir of [
|
|
53606
|
+
for (const dir of [
|
|
53607
|
+
run3.root,
|
|
53608
|
+
run3.requestsDir,
|
|
53609
|
+
run3.responsesDir,
|
|
53610
|
+
run3.sessionsDir,
|
|
53611
|
+
run3.projectsDir,
|
|
53612
|
+
run3.auditDir,
|
|
53613
|
+
run3.treesDir
|
|
53614
|
+
])
|
|
53456
53615
|
fs32.mkdirSync(dir, { recursive: true });
|
|
53457
53616
|
const plan = sharingAclPlan({
|
|
53458
53617
|
storageUserDir: storageOf(start.dataPath),
|
|
@@ -53523,13 +53682,13 @@ function machineDoctorRows(packageRoot, dataPath) {
|
|
|
53523
53682
|
}
|
|
53524
53683
|
|
|
53525
53684
|
// src/host/sandbox/contained-deps.ts
|
|
53526
|
-
function realContainedDeps(storageRoot, maxGb) {
|
|
53685
|
+
function realContainedDeps(storageRoot, maxGb, configOverridden = false) {
|
|
53527
53686
|
return {
|
|
53528
53687
|
storageRoot,
|
|
53529
53688
|
maxGb,
|
|
53530
53689
|
protect: (dir) => protectPrivateFolder(dir),
|
|
53531
53690
|
userSid: currentUserSid,
|
|
53532
|
-
port: new ScriptDiskPort(),
|
|
53691
|
+
port: new HelperDiskPort(new ScriptDiskPort(), helperApplies(process.env, configOverridden)),
|
|
53533
53692
|
sandboxRunning: isSandboxRunning
|
|
53534
53693
|
};
|
|
53535
53694
|
}
|
|
@@ -59196,7 +59355,7 @@ import fs73 from "node:fs";
|
|
|
59196
59355
|
import path95 from "node:path";
|
|
59197
59356
|
|
|
59198
59357
|
// src/shared/vpn/wireguard.ts
|
|
59199
|
-
import
|
|
59358
|
+
import net2 from "node:net";
|
|
59200
59359
|
var MAX_WIREGUARD_BYTES = 16 * 1024;
|
|
59201
59360
|
var MAX_LINES3 = 300;
|
|
59202
59361
|
var MAX_PEERS = 16;
|
|
@@ -59209,7 +59368,7 @@ var HOST2 = /^(?:\d{1,3}(?:\.\d{1,3}){3}|[A-Za-z0-9](?:[A-Za-z0-9.-]{0,251}[A-Za
|
|
|
59209
59368
|
function validCidr(text) {
|
|
59210
59369
|
const [addr, prefix, ...rest] = text.split("/");
|
|
59211
59370
|
if (rest.length > 0 || !addr) return false;
|
|
59212
|
-
const version2 =
|
|
59371
|
+
const version2 = net2.isIP(addr);
|
|
59213
59372
|
if (version2 === 0) return false;
|
|
59214
59373
|
if (prefix === void 0) return true;
|
|
59215
59374
|
if (!/^\d{1,3}$/.test(prefix)) return false;
|
|
@@ -59273,10 +59432,10 @@ function inspectWireguard(text) {
|
|
|
59273
59432
|
else if (!KEY.test(privateKey)) refuse2("PrivateKey is not a WireGuard key (44 characters of base64)");
|
|
59274
59433
|
const addresses = joined(face, "address");
|
|
59275
59434
|
if (addresses.length === 0 || !addresses.every(validCidr)) refuse2("[Interface] needs valid Address values");
|
|
59276
|
-
else if (!addresses.some((a) =>
|
|
59435
|
+
else if (!addresses.some((a) => net2.isIPv4(a.split("/")[0])))
|
|
59277
59436
|
refuse2("Address needs an IPv4 address (the kill switch works on IPv4)");
|
|
59278
59437
|
const dns = joined(face, "dns");
|
|
59279
|
-
if (!dns.every((d) =>
|
|
59438
|
+
if (!dns.every((d) => net2.isIP(d) !== 0)) refuse2("DNS may only list IP addresses");
|
|
59280
59439
|
const mtuText = one(face, "mtu");
|
|
59281
59440
|
const mtu = mtuText === void 0 ? void 0 : inRange(mtuText, 576, 1500);
|
|
59282
59441
|
if (mtuText !== void 0 && mtu === null) refuse2("MTU must be a number from 576 to 1500");
|
|
@@ -59296,7 +59455,7 @@ function inspectWireguard(text) {
|
|
|
59296
59455
|
const m = endpoint ? /^([^:[\]]+):(\d{1,5})$/.exec(endpoint) : null;
|
|
59297
59456
|
if (!m || !HOST2.test(m[1]) || inRange(m[2], 1, 65535) === null)
|
|
59298
59457
|
return refuse2(who + "Endpoint must be host:port with a name or an IPv4 address");
|
|
59299
|
-
if (/^\d+\.\d+\.\d+\.\d+$/.test(m[1]) && !
|
|
59458
|
+
if (/^\d+\.\d+\.\d+\.\d+$/.test(m[1]) && !net2.isIPv4(m[1])) return refuse2(who + "Endpoint is not a valid address");
|
|
59300
59459
|
const keepText = one(p, "persistentkeepalive");
|
|
59301
59460
|
let keepalive;
|
|
59302
59461
|
if (keepText !== void 0 && keepText.toLowerCase() !== "off") {
|
|
@@ -59892,7 +60051,7 @@ import fs80 from "node:fs";
|
|
|
59892
60051
|
import path105 from "node:path";
|
|
59893
60052
|
|
|
59894
60053
|
// src/host/network/port-forward.ts
|
|
59895
|
-
import
|
|
60054
|
+
import net5 from "node:net";
|
|
59896
60055
|
|
|
59897
60056
|
// src/shared/network/policy.ts
|
|
59898
60057
|
function relayPort(index) {
|
|
@@ -60131,14 +60290,14 @@ var SandboxChannel = class {
|
|
|
60131
60290
|
removeLink(p.root);
|
|
60132
60291
|
return;
|
|
60133
60292
|
}
|
|
60134
|
-
for (const target2 of [p.sandboxFile, p.requestsDir, p.responsesDir, p.sessionsDir, p.projectsDir]) {
|
|
60293
|
+
for (const target2 of [p.sandboxFile, p.requestsDir, p.responsesDir, p.sessionsDir, p.projectsDir, p.treesDir]) {
|
|
60135
60294
|
safeRemove(target2, this.dataPath);
|
|
60136
60295
|
}
|
|
60137
60296
|
}
|
|
60138
60297
|
};
|
|
60139
60298
|
|
|
60140
60299
|
// src/host/channel/attach.ts
|
|
60141
|
-
import
|
|
60300
|
+
import net4 from "node:net";
|
|
60142
60301
|
import os16 from "node:os";
|
|
60143
60302
|
|
|
60144
60303
|
// src/shared/pty/protocol.ts
|
|
@@ -60197,10 +60356,10 @@ var FrameReader = class {
|
|
|
60197
60356
|
};
|
|
60198
60357
|
|
|
60199
60358
|
// src/shared/pty/client.ts
|
|
60200
|
-
import
|
|
60359
|
+
import net3 from "node:net";
|
|
60201
60360
|
var connectOnce = (host, port, timeoutMs) => {
|
|
60202
60361
|
return new Promise((resolve, reject) => {
|
|
60203
|
-
const socket =
|
|
60362
|
+
const socket = net3.connect({ host, port });
|
|
60204
60363
|
const timer = setTimeout(() => {
|
|
60205
60364
|
socket.destroy();
|
|
60206
60365
|
reject(new Error("timed out connecting to " + host + ":" + port));
|
|
@@ -60485,12 +60644,175 @@ var CtrlCGuard = class {
|
|
|
60485
60644
|
}
|
|
60486
60645
|
};
|
|
60487
60646
|
|
|
60488
|
-
// src/shared/pty/
|
|
60489
|
-
var MOUSE_OFF = "\x1B[?1000l\x1B[?1002l\x1B[?1003l\x1B[?1005l\x1B[?1006l\x1B[?1015l";
|
|
60647
|
+
// src/shared/pty/key-gate.ts
|
|
60490
60648
|
function fixWindowsKeys(chunk) {
|
|
60491
60649
|
if (!chunk.includes(8) && !chunk.includes(127)) return chunk;
|
|
60492
60650
|
return Buffer.from(chunk.map((b) => b === 8 ? 127 : b === 127 ? 8 : b));
|
|
60493
60651
|
}
|
|
60652
|
+
var KeyGate = class {
|
|
60653
|
+
pending = [];
|
|
60654
|
+
decided;
|
|
60655
|
+
swap = false;
|
|
60656
|
+
/** windowsConsole: input comes from a Windows console in raw mode (its mode is decided later); else it goes as is. */
|
|
60657
|
+
constructor(windowsConsole) {
|
|
60658
|
+
this.decided = !windowsConsole;
|
|
60659
|
+
}
|
|
60660
|
+
/** The bytes to send now (empty while the mode is not known yet). */
|
|
60661
|
+
push(data) {
|
|
60662
|
+
if (!data.length) return data;
|
|
60663
|
+
if (!this.decided) {
|
|
60664
|
+
this.pending.push(data);
|
|
60665
|
+
return Buffer.alloc(0);
|
|
60666
|
+
}
|
|
60667
|
+
return this.swap ? fixWindowsKeys(data) : data;
|
|
60668
|
+
}
|
|
60669
|
+
/** The console's mode is known: what was held, ready to send. Later calls only change how new input is read. */
|
|
60670
|
+
decide(vtInput) {
|
|
60671
|
+
this.swap = !vtInput;
|
|
60672
|
+
this.decided = true;
|
|
60673
|
+
const held = Buffer.concat(this.pending);
|
|
60674
|
+
this.pending = [];
|
|
60675
|
+
return this.swap ? fixWindowsKeys(held) : held;
|
|
60676
|
+
}
|
|
60677
|
+
};
|
|
60678
|
+
|
|
60679
|
+
// src/shared/pty/mouse-modes.ts
|
|
60680
|
+
var TRACKING = [9, 1e3, 1002, 1003];
|
|
60681
|
+
var MAX_PARAMS = 64;
|
|
60682
|
+
var MOTION = 32;
|
|
60683
|
+
var NO_BUTTON = 3;
|
|
60684
|
+
var MouseModes = class {
|
|
60685
|
+
on = /* @__PURE__ */ new Set();
|
|
60686
|
+
/** 0 text, 1 after ESC, 2 after ESC[, 3 in ESC[? parameters, 4 after ESC[! */
|
|
60687
|
+
state = 0;
|
|
60688
|
+
params = "";
|
|
60689
|
+
/** Reads the program's output (after OutputFilter): the mode changes in it. */
|
|
60690
|
+
watch(output2) {
|
|
60691
|
+
for (const b of output2) {
|
|
60692
|
+
if (b === 27) {
|
|
60693
|
+
this.state = 1;
|
|
60694
|
+
continue;
|
|
60695
|
+
}
|
|
60696
|
+
if (this.state === 1) {
|
|
60697
|
+
if (b === 99) this.on.clear();
|
|
60698
|
+
this.state = b === 91 ? 2 : 0;
|
|
60699
|
+
} else if (this.state === 2) {
|
|
60700
|
+
this.state = b === 63 ? 3 : b === 33 ? 4 : 0;
|
|
60701
|
+
this.params = "";
|
|
60702
|
+
} else if (this.state === 4) {
|
|
60703
|
+
if (b === 112) this.on.clear();
|
|
60704
|
+
this.state = 0;
|
|
60705
|
+
} else if (this.state === 3) {
|
|
60706
|
+
if (b >= 48 && b <= 57 || b === 59) {
|
|
60707
|
+
this.params += String.fromCharCode(b);
|
|
60708
|
+
if (this.params.length > MAX_PARAMS) this.state = 0;
|
|
60709
|
+
} else {
|
|
60710
|
+
if (b === 104 || b === 108) this.apply(this.params, b === 104);
|
|
60711
|
+
this.state = 0;
|
|
60712
|
+
}
|
|
60713
|
+
}
|
|
60714
|
+
}
|
|
60715
|
+
}
|
|
60716
|
+
/** The program is gone (exited or restarting): its modes went with it. */
|
|
60717
|
+
reset() {
|
|
60718
|
+
this.on.clear();
|
|
60719
|
+
this.state = 0;
|
|
60720
|
+
this.params = "";
|
|
60721
|
+
}
|
|
60722
|
+
/** True while the program tracks the mouse in any way. */
|
|
60723
|
+
tracking() {
|
|
60724
|
+
return TRACKING.some((m) => this.on.has(m));
|
|
60725
|
+
}
|
|
60726
|
+
/** True while the program has a mode on (2004: bracketed paste). */
|
|
60727
|
+
has(mode) {
|
|
60728
|
+
return this.on.has(mode);
|
|
60729
|
+
}
|
|
60730
|
+
/** The mode numbers on now (for the report and tests). */
|
|
60731
|
+
modes() {
|
|
60732
|
+
return [...this.on].sort((a, b) => a - b);
|
|
60733
|
+
}
|
|
60734
|
+
/** `input` without the mouse reports the program has not asked for. Sequences must be whole (InputJoiner). */
|
|
60735
|
+
filter(input2) {
|
|
60736
|
+
if (!input2.includes(27)) return input2;
|
|
60737
|
+
const parts = [];
|
|
60738
|
+
let from = 0;
|
|
60739
|
+
let i = input2.indexOf(27);
|
|
60740
|
+
while (i !== -1) {
|
|
60741
|
+
const report = mouseReport(input2, i, this.on.has(1005), this.on.has(1015));
|
|
60742
|
+
if (report && !this.allows(report.button)) {
|
|
60743
|
+
parts.push(input2.subarray(from, i));
|
|
60744
|
+
from = i + report.length;
|
|
60745
|
+
i = input2.indexOf(27, from);
|
|
60746
|
+
} else i = input2.indexOf(27, i + 1);
|
|
60747
|
+
}
|
|
60748
|
+
if (from === 0) return input2;
|
|
60749
|
+
parts.push(input2.subarray(from));
|
|
60750
|
+
return Buffer.concat(parts);
|
|
60751
|
+
}
|
|
60752
|
+
allows(button) {
|
|
60753
|
+
if (!this.tracking()) return false;
|
|
60754
|
+
if ((button & MOTION) === 0) return true;
|
|
60755
|
+
if (this.on.has(1003)) return true;
|
|
60756
|
+
return this.on.has(1002) && (button & NO_BUTTON) !== NO_BUTTON;
|
|
60757
|
+
}
|
|
60758
|
+
apply(params, set3) {
|
|
60759
|
+
for (const p of params.split(";")) {
|
|
60760
|
+
const mode = Number(p);
|
|
60761
|
+
if (!p || !Number.isSafeInteger(mode)) continue;
|
|
60762
|
+
if (set3) this.on.add(mode);
|
|
60763
|
+
else this.on.delete(mode);
|
|
60764
|
+
}
|
|
60765
|
+
}
|
|
60766
|
+
};
|
|
60767
|
+
function mouseReport(data, at, utf8, urxvt) {
|
|
60768
|
+
if (data[at + 1] !== 91) return null;
|
|
60769
|
+
const sgr = data[at + 2] === 60;
|
|
60770
|
+
if (sgr || urxvt && data[at + 2] >= 48 && data[at + 2] <= 57) {
|
|
60771
|
+
let i = at + (sgr ? 3 : 2);
|
|
60772
|
+
let digits = "";
|
|
60773
|
+
let fields = 1;
|
|
60774
|
+
for (; i < data.length && i - at < 32; i++) {
|
|
60775
|
+
const b = data[i];
|
|
60776
|
+
if (b >= 48 && b <= 57) {
|
|
60777
|
+
if (fields === 1) digits += String.fromCharCode(b);
|
|
60778
|
+
} else if (b === 59) fields++;
|
|
60779
|
+
else break;
|
|
60780
|
+
}
|
|
60781
|
+
if (i >= data.length || fields !== 3 || !digits) return null;
|
|
60782
|
+
if (sgr ? data[i] !== 77 && data[i] !== 109 : data[i] !== 77) return null;
|
|
60783
|
+
const button = Number(digits) - (sgr ? 0 : 32);
|
|
60784
|
+
return button >= 0 ? { button, length: i - at + 1 } : null;
|
|
60785
|
+
}
|
|
60786
|
+
if (data[at + 2] === 77 && !utf8 && data.length - at >= 6) {
|
|
60787
|
+
const button = data[at + 3] - 32;
|
|
60788
|
+
return button >= 0 ? { button, length: 6 } : null;
|
|
60789
|
+
}
|
|
60790
|
+
return null;
|
|
60791
|
+
}
|
|
60792
|
+
|
|
60793
|
+
// src/shared/pty/terminal.ts
|
|
60794
|
+
var MOUSE_OFF = "\x1B[?1000l\x1B[?1002l\x1B[?1003l\x1B[?1005l\x1B[?1006l\x1B[?1015l";
|
|
60795
|
+
var SETTLE_QUIET_MS = 50;
|
|
60796
|
+
var SETTLE_MAX_MS = 300;
|
|
60797
|
+
function drainInput(stream) {
|
|
60798
|
+
return new Promise((done) => {
|
|
60799
|
+
let quiet;
|
|
60800
|
+
const end = () => {
|
|
60801
|
+
clearTimeout(quiet);
|
|
60802
|
+
clearTimeout(cap);
|
|
60803
|
+
stream.off("data", onData);
|
|
60804
|
+
done();
|
|
60805
|
+
};
|
|
60806
|
+
const onData = () => {
|
|
60807
|
+
clearTimeout(quiet);
|
|
60808
|
+
quiet = setTimeout(end, SETTLE_QUIET_MS);
|
|
60809
|
+
};
|
|
60810
|
+
const cap = setTimeout(end, SETTLE_MAX_MS);
|
|
60811
|
+
stream.on("data", onData);
|
|
60812
|
+
onData();
|
|
60813
|
+
});
|
|
60814
|
+
}
|
|
60815
|
+
var VT_WAIT_MS = 1e4;
|
|
60494
60816
|
function runTerminalClient(socket, token, options = {}) {
|
|
60495
60817
|
const stdin = process.stdin;
|
|
60496
60818
|
const stdout = process.stdout;
|
|
@@ -60498,14 +60820,16 @@ function runTerminalClient(socket, token, options = {}) {
|
|
|
60498
60820
|
const [c2, r] = stdout.isTTY ? stdout.getWindowSize() : [0, 0];
|
|
60499
60821
|
return [c2 || 120, r || 30];
|
|
60500
60822
|
};
|
|
60501
|
-
|
|
60823
|
+
const keys = new KeyGate(process.platform === "win32" && Boolean(stdin.isTTY));
|
|
60502
60824
|
return new Promise((resolve) => {
|
|
60503
60825
|
let done = false;
|
|
60504
60826
|
const reader = new FrameReader();
|
|
60505
60827
|
const filter = new OutputFilter({ clipboardWrites: options.clipboardWrites });
|
|
60506
60828
|
let sent = size();
|
|
60507
60829
|
let resizeTimer;
|
|
60508
|
-
let vtInput;
|
|
60830
|
+
let vtInput, vtTimer;
|
|
60831
|
+
const mouse = new MouseModes();
|
|
60832
|
+
let passthrough = false;
|
|
60509
60833
|
const finish = (result) => {
|
|
60510
60834
|
if (done) return;
|
|
60511
60835
|
done = true;
|
|
@@ -60516,9 +60840,13 @@ function runTerminalClient(socket, token, options = {}) {
|
|
|
60516
60840
|
clearInterval(sizeWatch);
|
|
60517
60841
|
clearTimeout(joinTimer);
|
|
60518
60842
|
clearTimeout(hintTimer);
|
|
60843
|
+
clearTimeout(vtTimer);
|
|
60519
60844
|
socket.destroy();
|
|
60520
|
-
|
|
60521
|
-
|
|
60845
|
+
const tracked = mouse.tracking();
|
|
60846
|
+
const reset = "\x1B[0m\x1B[?25h" + MOUSE_OFF + (mouse.has(2004) ? "\x1B[?2004l" : "") + "\r\n";
|
|
60847
|
+
const flushed = new Promise((written) => stdout.write(reset, () => written()));
|
|
60848
|
+
const settled = tracked ? flushed.then(() => drainInput(stdin)) : Promise.resolve();
|
|
60849
|
+
void Promise.all([settled, vtInput?.stop()]).then(() => {
|
|
60522
60850
|
if (stdin.isTTY) stdin.setRawMode(false);
|
|
60523
60851
|
stdin.pause();
|
|
60524
60852
|
resolve(result);
|
|
@@ -60526,9 +60854,10 @@ function runTerminalClient(socket, token, options = {}) {
|
|
|
60526
60854
|
};
|
|
60527
60855
|
const joiner = new InputJoiner();
|
|
60528
60856
|
let joinTimer;
|
|
60529
|
-
const
|
|
60530
|
-
if (data.length && !done) socket.write(encodeFrame(FrameType.Input,
|
|
60857
|
+
const write = (data) => {
|
|
60858
|
+
if (data.length && !done) socket.write(encodeFrame(FrameType.Input, data));
|
|
60531
60859
|
};
|
|
60860
|
+
const sendInput = (data) => write(keys.push(passthrough ? mouse.filter(data) : data));
|
|
60532
60861
|
const guard2 = options.confirmCtrlC ? new CtrlCGuard() : null;
|
|
60533
60862
|
let hintTimer;
|
|
60534
60863
|
const onInput = (chunk) => {
|
|
@@ -60550,7 +60879,6 @@ function runTerminalClient(socket, token, options = {}) {
|
|
|
60550
60879
|
sendInput(joiner.push(chunk));
|
|
60551
60880
|
if (joiner.holding()) joinTimer = setTimeout(() => sendInput(joiner.flush()), JOIN_MS);
|
|
60552
60881
|
};
|
|
60553
|
-
let passthrough = false;
|
|
60554
60882
|
const sendSize = () => {
|
|
60555
60883
|
const [c3, r2] = size();
|
|
60556
60884
|
if (c3 === sent[0] && r2 === sent[1]) return;
|
|
@@ -60580,11 +60908,14 @@ function runTerminalClient(socket, token, options = {}) {
|
|
|
60580
60908
|
for (const frame of frames) {
|
|
60581
60909
|
if (frame.type === FrameType.Output) {
|
|
60582
60910
|
const out = filter.push(frame.payload);
|
|
60911
|
+
mouse.watch(out);
|
|
60583
60912
|
guard2?.watchOutput(out.toString("latin1"));
|
|
60584
60913
|
stdout.write(out);
|
|
60585
60914
|
} else if (frame.type === FrameType.Console) passthrough = frame.payload.toString("latin1") === "conpty.dll";
|
|
60586
|
-
else if (frame.type === FrameType.Restarting)
|
|
60587
|
-
|
|
60915
|
+
else if (frame.type === FrameType.Restarting) {
|
|
60916
|
+
mouse.reset();
|
|
60917
|
+
stdout.write(MOUSE_OFF + "\x1B[2J\x1B[3J\x1B[H");
|
|
60918
|
+
} else if (frame.type === FrameType.Exit)
|
|
60588
60919
|
finish({ reason: "exit", exitCode: frame.payload.length >= 4 ? frame.payload.readInt32LE(0) : 1 });
|
|
60589
60920
|
else if (frame.type === FrameType.Error)
|
|
60590
60921
|
finish({
|
|
@@ -60600,8 +60931,10 @@ function runTerminalClient(socket, token, options = {}) {
|
|
|
60600
60931
|
socket.write(helloFrame(token, c2, r));
|
|
60601
60932
|
if (stdin.isTTY) stdin.setRawMode(true);
|
|
60602
60933
|
vtInput = enableVtInput();
|
|
60934
|
+
vtTimer = setTimeout(() => write(keys.decide(false)), VT_WAIT_MS);
|
|
60603
60935
|
void vtInput.ready.then((on) => {
|
|
60604
|
-
|
|
60936
|
+
clearTimeout(vtTimer);
|
|
60937
|
+
write(keys.decide(on));
|
|
60605
60938
|
});
|
|
60606
60939
|
stdin.on("data", onInput);
|
|
60607
60940
|
stdin.resume();
|
|
@@ -60612,7 +60945,7 @@ function runTerminalClient(socket, token, options = {}) {
|
|
|
60612
60945
|
// src/host/channel/attach.ts
|
|
60613
60946
|
var ipToInt = (ip) => ip.split(".").reduce((n, part) => n * 256 + Number(part), 0);
|
|
60614
60947
|
function isSandboxAddress(ip, interfaces = os16.networkInterfaces()) {
|
|
60615
|
-
if (!
|
|
60948
|
+
if (!net4.isIPv4(ip)) return false;
|
|
60616
60949
|
return Object.entries(interfaces).some(
|
|
60617
60950
|
([name2, list]) => /^vEthernet/i.test(name2) && !/WSL/i.test(name2) && (list ?? []).some((i) => {
|
|
60618
60951
|
if (i.family !== "IPv4" || i.internal) return false;
|
|
@@ -60691,13 +61024,13 @@ function sandboxAddress(dataPath) {
|
|
|
60691
61024
|
}
|
|
60692
61025
|
function startPortForwards(forwards, address, note = () => void 0) {
|
|
60693
61026
|
const servers = forwards.map((f, i) => {
|
|
60694
|
-
const server =
|
|
61027
|
+
const server = net5.createServer((client) => {
|
|
60695
61028
|
const ip = address();
|
|
60696
61029
|
if (!ip) {
|
|
60697
61030
|
client.destroy();
|
|
60698
61031
|
return;
|
|
60699
61032
|
}
|
|
60700
|
-
const target2 =
|
|
61033
|
+
const target2 = net5.connect(relayPort(i), ip);
|
|
60701
61034
|
client.pipe(target2).pipe(client);
|
|
60702
61035
|
target2.on("error", () => client.destroy());
|
|
60703
61036
|
client.on("error", () => target2.destroy());
|
|
@@ -61547,7 +61880,10 @@ var Watcher = class {
|
|
|
61547
61880
|
/** Contained storage of this data set (only when a mounted image is on record), else null. */
|
|
61548
61881
|
contained() {
|
|
61549
61882
|
try {
|
|
61550
|
-
const storage = new ContainedStorage(
|
|
61883
|
+
const storage = new ContainedStorage(
|
|
61884
|
+
realContainedDeps(this.storageRoot, 64, Boolean(this.resume.config)),
|
|
61885
|
+
setNameOf(this.dataPath)
|
|
61886
|
+
);
|
|
61551
61887
|
return storage.isRecorded() ? storage : null;
|
|
61552
61888
|
} catch {
|
|
61553
61889
|
return null;
|
|
@@ -64698,17 +65034,17 @@ var DataService = class {
|
|
|
64698
65034
|
}
|
|
64699
65035
|
/** Removes the planned folders. A failure on one does not stop the others. */
|
|
64700
65036
|
clean(plan) {
|
|
64701
|
-
const
|
|
65037
|
+
const failed2 = [];
|
|
64702
65038
|
for (const t of plan.present) {
|
|
64703
65039
|
try {
|
|
64704
65040
|
removeTree(t.path, t.root);
|
|
64705
65041
|
} catch (e) {
|
|
64706
|
-
|
|
65042
|
+
failed2.push(t.target + " (" + errMsg(e) + ")");
|
|
64707
65043
|
}
|
|
64708
65044
|
}
|
|
64709
65045
|
return {
|
|
64710
65046
|
freedBytes: plan.totalBytes - import_lodash22.default.sumBy(plan.present, (t) => sizeOf(t.path)),
|
|
64711
|
-
failed,
|
|
65047
|
+
failed: failed2,
|
|
64712
65048
|
touchedData: plan.present.some((t) => t.root === this.ctx.dataPath || t.target === "all")
|
|
64713
65049
|
};
|
|
64714
65050
|
}
|
|
@@ -65196,8 +65532,8 @@ function decideUpdate(input2) {
|
|
|
65196
65532
|
if (!input2.latest) return skip("no-release");
|
|
65197
65533
|
const latest = input2.latest;
|
|
65198
65534
|
if (compareVersions(latest.version, input2.current) <= 0) return skip("up-to-date");
|
|
65199
|
-
const
|
|
65200
|
-
if (
|
|
65535
|
+
const failed2 = input2.state.failed;
|
|
65536
|
+
if (failed2 && compareVersions(latest.version, failed2.version) <= 0) return skip("failed-before");
|
|
65201
65537
|
return { kind: "install", release: latest };
|
|
65202
65538
|
}
|
|
65203
65539
|
|
|
@@ -65237,13 +65573,13 @@ function updateNotice(state, current, seenKey) {
|
|
|
65237
65573
|
const off = state.autoOff;
|
|
65238
65574
|
if (off && compareVersions(off.version, current) > 0)
|
|
65239
65575
|
candidates.push({ at: off.at, notice: { key: "auto-off@" + off.at, text: autoOffText(off.version, current) } });
|
|
65240
|
-
const
|
|
65241
|
-
if (
|
|
65576
|
+
const failed2 = state.failed;
|
|
65577
|
+
if (failed2 && compareVersions(failed2.version, current) > 0 && off?.version !== failed2.version)
|
|
65242
65578
|
candidates.push({
|
|
65243
|
-
at:
|
|
65579
|
+
at: failed2.at,
|
|
65244
65580
|
notice: {
|
|
65245
|
-
key: "failed@" +
|
|
65246
|
-
text: "Update to " +
|
|
65581
|
+
key: "failed@" + failed2.at,
|
|
65582
|
+
text: "Update to " + failed2.version + " failed; still on " + current + " (sandbox update --rollback, or sandbox update for details)."
|
|
65247
65583
|
}
|
|
65248
65584
|
});
|
|
65249
65585
|
const newest = candidates.sort((a, b) => Date.parse(b.at) - Date.parse(a.at))[0];
|
|
@@ -67615,7 +67951,7 @@ async function knockOnDoor(storageRoot, owner) {
|
|
|
67615
67951
|
|
|
67616
67952
|
// src/host/remote/cert.ts
|
|
67617
67953
|
import crypto17 from "node:crypto";
|
|
67618
|
-
import
|
|
67954
|
+
import net6 from "node:net";
|
|
67619
67955
|
var CERT_DAYS = 397;
|
|
67620
67956
|
var DAY_MS4 = 864e5;
|
|
67621
67957
|
function length(n) {
|
|
@@ -67660,13 +67996,13 @@ function extension(id, critical, value) {
|
|
|
67660
67996
|
}
|
|
67661
67997
|
function altNames(addresses, dnsNames) {
|
|
67662
67998
|
const entries = [
|
|
67663
|
-
...addresses.filter((a) =>
|
|
67999
|
+
...addresses.filter((a) => net6.isIPv4(a)).map((a) => tlv(135, Buffer.from(a.split(".").map(Number)))),
|
|
67664
68000
|
...dnsNames.filter((d) => /^[A-Za-z0-9-]{1,63}$/.test(d)).map((d) => tlv(130, Buffer.from(d, "ascii")))
|
|
67665
68001
|
];
|
|
67666
68002
|
return seq(...entries);
|
|
67667
68003
|
}
|
|
67668
68004
|
function makeCertificate(r) {
|
|
67669
|
-
if (!r.addresses.length || !r.addresses.every((a) =>
|
|
68005
|
+
if (!r.addresses.length || !r.addresses.every((a) => net6.isIPv4(a)))
|
|
67670
68006
|
throw new Error("A certificate needs at least one IPv4 address.");
|
|
67671
68007
|
const now2 = r.now ?? Date.now();
|
|
67672
68008
|
const days = r.days ?? CERT_DAYS;
|
|
@@ -67716,20 +68052,20 @@ import path137 from "node:path";
|
|
|
67716
68052
|
import { spawn as spawn11 } from "node:child_process";
|
|
67717
68053
|
|
|
67718
68054
|
// src/host/remote/lan.ts
|
|
67719
|
-
import
|
|
68055
|
+
import net7 from "node:net";
|
|
67720
68056
|
import os20 from "node:os";
|
|
67721
68057
|
var toInt = (ip) => ip.split(".").reduce((n, part) => n * 256 + Number(part), 0) >>> 0;
|
|
67722
68058
|
function isPrivateIPv4(ip) {
|
|
67723
|
-
if (!
|
|
68059
|
+
if (!net7.isIPv4(ip)) return false;
|
|
67724
68060
|
const [a, b] = ip.split(".").map(Number);
|
|
67725
68061
|
return a === 10 || a === 172 && b >= 16 && b <= 31 || a === 192 && b === 168;
|
|
67726
68062
|
}
|
|
67727
68063
|
function isLoopbackIPv4(ip) {
|
|
67728
|
-
return
|
|
68064
|
+
return net7.isIPv4(ip) && ip.startsWith("127.");
|
|
67729
68065
|
}
|
|
67730
68066
|
function plainIPv4(ip) {
|
|
67731
68067
|
const value = ip ?? "";
|
|
67732
|
-
return value.startsWith("::ffff:") &&
|
|
68068
|
+
return value.startsWith("::ffff:") && net7.isIPv4(value.slice(7)) ? value.slice(7) : value;
|
|
67733
68069
|
}
|
|
67734
68070
|
function virtualAdapter(name2) {
|
|
67735
68071
|
return /^vEthernet/i.test(name2) || /Hyper-V|WSL/i.test(name2);
|
|
@@ -68090,9 +68426,11 @@ var TerminalBridge = class {
|
|
|
68090
68426
|
break;
|
|
68091
68427
|
}
|
|
68092
68428
|
case FrameType.Restarting:
|
|
68429
|
+
this.mouseOff();
|
|
68093
68430
|
this.tell({ t: "restarting" });
|
|
68094
68431
|
break;
|
|
68095
68432
|
case FrameType.Exit:
|
|
68433
|
+
this.mouseOff();
|
|
68096
68434
|
this.tell({ t: "exit", code: frame.payload.length >= 4 ? frame.payload.readInt32LE(0) : 1 });
|
|
68097
68435
|
this.finish(1e3, "exit");
|
|
68098
68436
|
return;
|
|
@@ -68106,6 +68444,13 @@ var TerminalBridge = class {
|
|
|
68106
68444
|
}
|
|
68107
68445
|
if (this.ws.bufferedAmount > MAX_BUFFERED_BYTES) this.hold();
|
|
68108
68446
|
}
|
|
68447
|
+
/**
|
|
68448
|
+
* The program's mouse tracking ends with it: the browser's terminal stops sending clicks and moves, and a drag
|
|
68449
|
+
* selects text again (an ended terminal stays on screen).
|
|
68450
|
+
*/
|
|
68451
|
+
mouseOff() {
|
|
68452
|
+
if (this.ws.readyState === this.ws.OPEN) this.ws.send(Buffer.from(MOUSE_OFF, "latin1"), { binary: true });
|
|
68453
|
+
}
|
|
68109
68454
|
/** Stops reading from the session until the browser has taken what it was sent. */
|
|
68110
68455
|
hold() {
|
|
68111
68456
|
if (this.drain || !this.socket) return;
|
|
@@ -68577,6 +68922,7 @@ var WebServer = class {
|
|
|
68577
68922
|
live;
|
|
68578
68923
|
actualPort = 0;
|
|
68579
68924
|
lastUsed = Date.now();
|
|
68925
|
+
lastCheck = Date.now();
|
|
68580
68926
|
heartbeat;
|
|
68581
68927
|
idleCheck;
|
|
68582
68928
|
get port() {
|
|
@@ -68591,7 +68937,8 @@ var WebServer = class {
|
|
|
68591
68937
|
this.heartbeat = setInterval(() => this.beat(), this.options.heartbeatMs ?? HEARTBEAT_MS);
|
|
68592
68938
|
this.heartbeat.unref();
|
|
68593
68939
|
if (this.options.idleExitMs) {
|
|
68594
|
-
this.
|
|
68940
|
+
this.lastCheck = Date.now();
|
|
68941
|
+
this.idleCheck = setInterval(() => void this.checkIdle(), this.checkEveryMs());
|
|
68595
68942
|
this.idleCheck.unref();
|
|
68596
68943
|
}
|
|
68597
68944
|
const gate = this.options.gate;
|
|
@@ -68632,6 +68979,9 @@ var WebServer = class {
|
|
|
68632
68979
|
/** No browser has used the server for a while: it ends (sooner when no sandbox runs). */
|
|
68633
68980
|
async checkIdle() {
|
|
68634
68981
|
const limit = this.options.idleExitMs ?? 0;
|
|
68982
|
+
const now2 = Date.now();
|
|
68983
|
+
if (now2 - this.lastCheck > 3 * this.checkEveryMs()) this.lastUsed = now2;
|
|
68984
|
+
this.lastCheck = now2;
|
|
68635
68985
|
if (!limit || this.tracked.size > 0) return;
|
|
68636
68986
|
const idle = Date.now() - this.lastUsed;
|
|
68637
68987
|
if (idle >= limit) return this.options.onStop?.();
|
|
@@ -68643,6 +68993,9 @@ var WebServer = class {
|
|
|
68643
68993
|
}
|
|
68644
68994
|
this.options.onStop?.();
|
|
68645
68995
|
}
|
|
68996
|
+
checkEveryMs() {
|
|
68997
|
+
return Math.min(6e4, this.quietMs());
|
|
68998
|
+
}
|
|
68646
68999
|
/** How long unused before it ends when no sandbox runs. */
|
|
68647
69000
|
quietMs() {
|
|
68648
69001
|
return Math.min(this.options.idleExitMs ?? 0, this.options.idleNoSandboxMs ?? IDLE_NO_SANDBOX_MS);
|
|
@@ -71166,7 +71519,7 @@ function requireNoSandbox() {
|
|
|
71166
71519
|
function storageFor(ctx) {
|
|
71167
71520
|
const { config: config3 } = ctx.loaded;
|
|
71168
71521
|
return new ContainedStorage(
|
|
71169
|
-
realContainedDeps(ctx.storageRoot, config3.storage.containedMaxGb),
|
|
71522
|
+
realContainedDeps(ctx.storageRoot, config3.storage.containedMaxGb, Boolean(ctx.options.config)),
|
|
71170
71523
|
config3.storage.dataName
|
|
71171
71524
|
);
|
|
71172
71525
|
}
|
|
@@ -72551,7 +72904,7 @@ import fs111 from "node:fs";
|
|
|
72551
72904
|
function storageOf2(env) {
|
|
72552
72905
|
const { config: config3 } = env.ctx.loaded;
|
|
72553
72906
|
return new ContainedStorage(
|
|
72554
|
-
realContainedDeps(env.storageRoot, config3.storage.containedMaxGb),
|
|
72907
|
+
realContainedDeps(env.storageRoot, config3.storage.containedMaxGb, Boolean(env.ctx.options.config)),
|
|
72555
72908
|
config3.storage.dataName
|
|
72556
72909
|
);
|
|
72557
72910
|
}
|
|
@@ -76578,13 +76931,13 @@ var cleanEngineRun = implement(cleanEngine, async (ctx, _input, io) => {
|
|
|
76578
76931
|
r.stopped ? "ok" : "danger"
|
|
76579
76932
|
);
|
|
76580
76933
|
const stopped = results.filter((r) => r.stopped).length;
|
|
76581
|
-
const
|
|
76582
|
-
if (
|
|
76934
|
+
const failed2 = results.length - stopped;
|
|
76935
|
+
if (failed2)
|
|
76583
76936
|
fail(
|
|
76584
|
-
plural2(
|
|
76937
|
+
plural2(failed2, "HCS system") + " could not be stopped.",
|
|
76585
76938
|
"Run it again from an administrator terminal: sandbox engine clean"
|
|
76586
76939
|
);
|
|
76587
|
-
return { available: true, stopped, failed, message: "Stopped " + plural2(stopped, "HCS system") + "." };
|
|
76940
|
+
return { available: true, stopped, failed: failed2, message: "Stopped " + plural2(stopped, "HCS system") + "." };
|
|
76588
76941
|
});
|
|
76589
76942
|
|
|
76590
76943
|
// src/app/features/vpn/vpn.def.ts
|
|
@@ -77449,7 +77802,7 @@ async function attachOpened(ctx, session) {
|
|
|
77449
77802
|
nextStep("sandbox attach " + session);
|
|
77450
77803
|
return 0;
|
|
77451
77804
|
}
|
|
77452
|
-
const { attach: attach2 } = await import("./chunk-
|
|
77805
|
+
const { attach: attach2 } = await import("./chunk-LQHEUN2A.js");
|
|
77453
77806
|
return attach2({ ...ctx, options: { ...ctx.options, positionals: [session] } });
|
|
77454
77807
|
}
|
|
77455
77808
|
function definitionHandler(def) {
|
|
@@ -77948,7 +78301,7 @@ var Launcher = class {
|
|
|
77948
78301
|
const engine = await openEngine(config3);
|
|
77949
78302
|
const provider = providerFor(
|
|
77950
78303
|
config3,
|
|
77951
|
-
config3.storage.contained === "off" ? {} : { contained: realContainedDeps(ctx.storageRoot, config3.storage.containedMaxGb) }
|
|
78304
|
+
config3.storage.contained === "off" ? {} : { contained: realContainedDeps(ctx.storageRoot, config3.storage.containedMaxGb, Boolean(ctx.options.config)) }
|
|
77952
78305
|
);
|
|
77953
78306
|
if (!generateOnly) assertCanLaunch(isSandboxRunning() ? runningOwner() : void 0);
|
|
77954
78307
|
const dataMappings = await this.prepareStorage(provider, run3);
|