@ai-ecoverse/slicc-kernel 1.170.4 → 1.172.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/README.md +24 -8
- package/dist/driver-worker.js +35 -11
- package/dist/driver-worker.js.map +3 -3
- package/dist/index.js +263 -53
- package/dist/index.js.map +4 -4
- package/dist/kernel-worker.js +779 -438
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-driver-worker.js +39 -15
- package/dist/node-driver-worker.js.map +3 -3
- package/dist/node-process-worker.cjs +1 -1
- package/dist/node-process-worker.js +1 -1
- package/dist/node.js +798 -488
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +1 -1
- package/dist/testing.js +498 -3
- package/dist/testing.js.map +4 -4
- package/dist/types/fs/attest.d.ts +12 -2
- package/dist/types/index.d.ts +13 -5
- package/dist/types/kernel/net/http-syscalls.d.ts +3 -1
- package/dist/types/kernel/net/loopback-transport.d.ts +1 -1
- package/dist/types/kernel/net/placeholder-floor.d.ts +9 -3
- package/dist/types/kernel/net/remote-transport.d.ts +8 -2
- package/dist/types/kernel/net/sealed-fetch.d.ts +27 -0
- package/dist/types/kernel/net/transport.d.ts +6 -1
- package/dist/types/kernel/socket.d.ts +4 -1
- package/dist/types/launcher.d.ts +12 -2
- package/dist/types/node/follow.d.ts +4 -0
- package/dist/types/node.d.ts +13 -4
- package/dist/types/sealed-relay.d.ts +12 -2
- package/dist/types/serve.d.ts +8 -1
- package/dist/types/testing.d.ts +3 -0
- package/dist/types/transport.d.ts +4 -3
- package/package.json +1 -1
package/dist/node.js
CHANGED
|
@@ -2362,9 +2362,9 @@ var KernelSocket = class _KernelSocket {
|
|
|
2362
2362
|
case SO_TYPE:
|
|
2363
2363
|
return SOCK_STREAM;
|
|
2364
2364
|
case SO_ERROR: {
|
|
2365
|
-
const
|
|
2365
|
+
const failed5 = this.failed;
|
|
2366
2366
|
this.failed = void 0;
|
|
2367
|
-
return
|
|
2367
|
+
return failed5 ? wasiErrno(failed5) : 0;
|
|
2368
2368
|
}
|
|
2369
2369
|
case SO_ACCEPTCONN:
|
|
2370
2370
|
return this.state === "listening" ? 1 : 0;
|
|
@@ -2444,6 +2444,7 @@ var LoopbackNet = class {
|
|
|
2444
2444
|
internal = /* @__PURE__ */ new Set();
|
|
2445
2445
|
reserved = /* @__PURE__ */ new Set();
|
|
2446
2446
|
facades = /* @__PURE__ */ new Map();
|
|
2447
|
+
proxyStamped;
|
|
2447
2448
|
nextEphemeral = EPHEMERAL_FIRST;
|
|
2448
2449
|
route;
|
|
2449
2450
|
origins;
|
|
@@ -2518,9 +2519,15 @@ var LoopbackNet = class {
|
|
|
2518
2519
|
this.kernelOnly(port, true);
|
|
2519
2520
|
this.facades.set(port, name2);
|
|
2520
2521
|
}
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2522
|
+
stampProxy(port) {
|
|
2523
|
+
this.proxyStamped = port;
|
|
2524
|
+
}
|
|
2525
|
+
get originsStamped() {
|
|
2526
|
+
return this.proxyStamped !== void 0;
|
|
2527
|
+
}
|
|
2528
|
+
stampsPeers(addr) {
|
|
2529
|
+
if (addr.family !== "inet" || !isLoopback(canonicalHost(addr.host))) return false;
|
|
2530
|
+
return this.facades.has(addr.port) || this.proxyStamped === addr.port;
|
|
2524
2531
|
}
|
|
2525
2532
|
activate(addr, start2) {
|
|
2526
2533
|
this.activators.set(keyOf(addr), start2);
|
|
@@ -3695,7 +3702,7 @@ function satisfies(version, range2) {
|
|
|
3695
3702
|
}
|
|
3696
3703
|
|
|
3697
3704
|
// src/version.ts
|
|
3698
|
-
var KERNEL_VERSION = true ? "1.
|
|
3705
|
+
var KERNEL_VERSION = true ? "1.172.0" : "0.0.0-dev";
|
|
3699
3706
|
var OS_RELEASE = "6.0.0-slicc";
|
|
3700
3707
|
function procVersion() {
|
|
3701
3708
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -3987,10 +3994,10 @@ async function tierPackages(fs, physical, roots, bins, kernel, global) {
|
|
|
3987
3994
|
const own = commandsOf(pkg, manifest);
|
|
3988
3995
|
const named = new Set(own.map((command) => command.name));
|
|
3989
3996
|
const extra = bins ? await binCommandsOf(physical, pkg, manifest, named) : [];
|
|
3990
|
-
const
|
|
3997
|
+
const refused4 = engineRefusal(manifest, kernel);
|
|
3991
3998
|
const name2 = pkg.slice(root.length + 1);
|
|
3992
3999
|
const dependency = direct?.has(name2) === false;
|
|
3993
|
-
const marks = { ...
|
|
4000
|
+
const marks = { ...refused4 ? { refused: refused4 } : {}, ...dependency ? { dependency } : {} };
|
|
3994
4001
|
out.push({
|
|
3995
4002
|
name: name2,
|
|
3996
4003
|
pkg,
|
|
@@ -4022,7 +4029,7 @@ function winners(tier) {
|
|
|
4022
4029
|
}
|
|
4023
4030
|
return out;
|
|
4024
4031
|
}
|
|
4025
|
-
async function scanCommands(fs, modules, binsFrom = Number.POSITIVE_INFINITY, kernel = KERNEL_VERSION,
|
|
4032
|
+
async function scanCommands(fs, modules, binsFrom = Number.POSITIVE_INFINITY, kernel = KERNEL_VERSION, refused4, global = /* @__PURE__ */ new Set()) {
|
|
4026
4033
|
const found = /* @__PURE__ */ new Map();
|
|
4027
4034
|
const physical = physicalResolver(fs);
|
|
4028
4035
|
const tiers = (typeof modules === "string" ? [modules] : modules).map(
|
|
@@ -4036,7 +4043,7 @@ async function scanCommands(fs, modules, binsFrom = Number.POSITIVE_INFINITY, ke
|
|
|
4036
4043
|
const dependencies = [];
|
|
4037
4044
|
for (const [index, roots] of tiers.entries()) {
|
|
4038
4045
|
const tier = await tierPackages(fs, physical, roots, index >= binsFrom, kernel, global);
|
|
4039
|
-
if (
|
|
4046
|
+
if (refused4) refused4.push(...tier.flatMap((entry) => entry.commands.filter((c) => c.refused)));
|
|
4040
4047
|
await take(tier.filter((entry) => !entry.dependency));
|
|
4041
4048
|
dependencies.push(tier.filter((entry) => entry.dependency));
|
|
4042
4049
|
}
|
|
@@ -4352,32 +4359,32 @@ function nextFire(schedule, after, utc = false) {
|
|
|
4352
4359
|
}
|
|
4353
4360
|
return null;
|
|
4354
4361
|
}
|
|
4355
|
-
function missedFires(schedule, from,
|
|
4362
|
+
function missedFires(schedule, from, until2, utc = false, cap = MISSED_CAP) {
|
|
4356
4363
|
let count2 = 0;
|
|
4357
4364
|
let last = null;
|
|
4358
4365
|
let at = from;
|
|
4359
4366
|
while (count2 < cap) {
|
|
4360
4367
|
at = nextFire(schedule, at, utc);
|
|
4361
|
-
if (at === null || at >
|
|
4368
|
+
if (at === null || at > until2) return { count: count2, last, more: false };
|
|
4362
4369
|
last = at;
|
|
4363
4370
|
count2++;
|
|
4364
4371
|
}
|
|
4365
4372
|
const next3 = nextFire(schedule, last, utc);
|
|
4366
|
-
if (next3 === null || next3 >
|
|
4367
|
-
return { count: count2, last: latestFire(schedule, last,
|
|
4373
|
+
if (next3 === null || next3 > until2) return { count: count2, last, more: false };
|
|
4374
|
+
return { count: count2, last: latestFire(schedule, last, until2, utc), more: true };
|
|
4368
4375
|
}
|
|
4369
|
-
function latestFire(schedule, from,
|
|
4376
|
+
function latestFire(schedule, from, until2, utc = false) {
|
|
4370
4377
|
let found = from;
|
|
4371
4378
|
for (let span = 6e4; ; span *= 2) {
|
|
4372
|
-
const start2 = Math.max(from,
|
|
4379
|
+
const start2 = Math.max(from, until2 - span);
|
|
4373
4380
|
const first = nextFire(schedule, start2, utc);
|
|
4374
|
-
if (first !== null && first <=
|
|
4381
|
+
if (first !== null && first <= until2) {
|
|
4375
4382
|
found = first;
|
|
4376
4383
|
break;
|
|
4377
4384
|
}
|
|
4378
4385
|
if (start2 === from) return from;
|
|
4379
4386
|
}
|
|
4380
|
-
for (let at = nextFire(schedule, found, utc); at !== null && at <=
|
|
4387
|
+
for (let at = nextFire(schedule, found, utc); at !== null && at <= until2; ) {
|
|
4381
4388
|
found = at;
|
|
4382
4389
|
at = nextFire(schedule, at, utc);
|
|
4383
4390
|
}
|
|
@@ -5102,12 +5109,12 @@ var UnlinkedKeeper = class {
|
|
|
5102
5109
|
return this.locks;
|
|
5103
5110
|
}
|
|
5104
5111
|
async undoing(op, peers, sends, heard, shared2 = []) {
|
|
5105
|
-
let
|
|
5112
|
+
let failed5;
|
|
5106
5113
|
let out;
|
|
5107
5114
|
try {
|
|
5108
5115
|
out = await op();
|
|
5109
5116
|
} catch (err) {
|
|
5110
|
-
|
|
5117
|
+
failed5 = err ?? new Error("failed");
|
|
5111
5118
|
await this.rollBackAsides(sends, shared2);
|
|
5112
5119
|
}
|
|
5113
5120
|
const hiddenShared = new Set(shared2.map((one) => one.hidden));
|
|
@@ -5128,7 +5135,7 @@ var UnlinkedKeeper = class {
|
|
|
5128
5135
|
const done4 = () => one.release().then(() => this.dropIfLast(one.hidden));
|
|
5129
5136
|
void Promise.all(waits.map(({ told }) => told)).then(done4, done4);
|
|
5130
5137
|
}
|
|
5131
|
-
if (
|
|
5138
|
+
if (failed5 !== void 0) throw failed5;
|
|
5132
5139
|
return out;
|
|
5133
5140
|
}
|
|
5134
5141
|
async rollBackAsides(sends, shared2) {
|
|
@@ -5275,7 +5282,7 @@ var UnlinkedKeeper = class {
|
|
|
5275
5282
|
// src/cron/clock.ts
|
|
5276
5283
|
var systemCronClock = {
|
|
5277
5284
|
now: () => Date.now(),
|
|
5278
|
-
sleep(
|
|
5285
|
+
sleep(until2, signal) {
|
|
5279
5286
|
if (signal.aborted) return Promise.resolve();
|
|
5280
5287
|
return new Promise((resolve2) => {
|
|
5281
5288
|
const done4 = () => {
|
|
@@ -5283,7 +5290,7 @@ var systemCronClock = {
|
|
|
5283
5290
|
signal.removeEventListener("abort", done4);
|
|
5284
5291
|
resolve2();
|
|
5285
5292
|
};
|
|
5286
|
-
const timer = setTimeout(done4, Math.max(0,
|
|
5293
|
+
const timer = setTimeout(done4, Math.max(0, until2 - Date.now()));
|
|
5287
5294
|
timer.unref?.();
|
|
5288
5295
|
signal.addEventListener("abort", done4, { once: true });
|
|
5289
5296
|
});
|
|
@@ -5387,15 +5394,15 @@ var CronService = class {
|
|
|
5387
5394
|
async pass() {
|
|
5388
5395
|
if (this.wake.signal.aborted) this.wake = new AbortController();
|
|
5389
5396
|
const wake = this.wake;
|
|
5390
|
-
let
|
|
5397
|
+
let until2;
|
|
5391
5398
|
try {
|
|
5392
|
-
|
|
5399
|
+
until2 = await this.tick();
|
|
5393
5400
|
} catch (err) {
|
|
5394
5401
|
await this.error(`cron: ${messageOf(err)}`);
|
|
5395
|
-
|
|
5402
|
+
until2 = this.clock.now() + WAKE_MS;
|
|
5396
5403
|
}
|
|
5397
5404
|
if (this.stopping.signal.aborted) return;
|
|
5398
|
-
await this.clock.sleep(
|
|
5405
|
+
await this.clock.sleep(until2, wake.signal);
|
|
5399
5406
|
}
|
|
5400
5407
|
async provision() {
|
|
5401
5408
|
const { fs, owners } = this.host;
|
|
@@ -5612,14 +5619,17 @@ var PLACEHOLDER_REFUSED = "refused: this request has a sealed placeholder in its
|
|
|
5612
5619
|
var PlaceholderRefused = class extends Error {
|
|
5613
5620
|
status = 403;
|
|
5614
5621
|
code = "EACCES";
|
|
5615
|
-
constructor() {
|
|
5616
|
-
super(
|
|
5622
|
+
constructor(reason = PLACEHOLDER_REFUSED) {
|
|
5623
|
+
super(reason);
|
|
5617
5624
|
}
|
|
5618
5625
|
};
|
|
5619
|
-
function
|
|
5626
|
+
function holds2(text, known) {
|
|
5627
|
+
return PLACEHOLDER.test(text) || known.some((placeholder) => text.includes(placeholder));
|
|
5628
|
+
}
|
|
5629
|
+
function carries(text, known) {
|
|
5620
5630
|
let layer = text;
|
|
5621
5631
|
for (let i = 0; i < PERCENT_LAYERS; i++) {
|
|
5622
|
-
if (
|
|
5632
|
+
if (holds2(layer, known)) return true;
|
|
5623
5633
|
const next3 = layer.replace(
|
|
5624
5634
|
ESCAPE,
|
|
5625
5635
|
(_, hex4) => String.fromCharCode(Number.parseInt(hex4, 16))
|
|
@@ -5627,35 +5637,36 @@ function carries(text) {
|
|
|
5627
5637
|
if (next3 === layer) return false;
|
|
5628
5638
|
layer = next3;
|
|
5629
5639
|
}
|
|
5630
|
-
return
|
|
5640
|
+
return holds2(layer, known);
|
|
5631
5641
|
}
|
|
5632
|
-
function basicCarries(value2) {
|
|
5642
|
+
function basicCarries(value2, known) {
|
|
5633
5643
|
const credential = BASIC.exec(value2)?.[1];
|
|
5634
5644
|
if (credential === void 0) return false;
|
|
5635
5645
|
const letters = credential.replace(/[^A-Za-z0-9+/_-]/g, "").replaceAll("-", "+").replaceAll("_", "/");
|
|
5636
5646
|
for (let shift = 0; shift < BASE64_GROUP; shift++) {
|
|
5637
5647
|
const part = letters.slice(shift);
|
|
5638
5648
|
const whole = part.length % BASE64_GROUP === 1 ? part.slice(0, -1) : part;
|
|
5639
|
-
if (carries(atob(whole))) return true;
|
|
5649
|
+
if (carries(atob(whole), known)) return true;
|
|
5640
5650
|
}
|
|
5641
5651
|
return false;
|
|
5642
5652
|
}
|
|
5643
|
-
function headersCarry(headers) {
|
|
5653
|
+
function headersCarry(headers, known) {
|
|
5644
5654
|
return headers.some(
|
|
5645
|
-
([name2, value2]) => carries(name2.toLowerCase()) || carries(value2) || basicCarries(value2)
|
|
5655
|
+
([name2, value2]) => carries(name2, known) || carries(name2.toLowerCase(), known) || carries(value2, known) || basicCarries(value2, known)
|
|
5646
5656
|
);
|
|
5647
5657
|
}
|
|
5648
|
-
function urlCarries(url) {
|
|
5649
|
-
return carries(url) || URL.canParse(url) && carries(new URL(url).href);
|
|
5658
|
+
function urlCarries(url, known) {
|
|
5659
|
+
return carries(url, known) || URL.canParse(url) && carries(new URL(url).href, known);
|
|
5650
5660
|
}
|
|
5651
|
-
function
|
|
5652
|
-
|
|
5661
|
+
function detected(request, known) {
|
|
5662
|
+
return urlCarries(request.url, known) || headersCarry(request.headers, known);
|
|
5653
5663
|
}
|
|
5654
|
-
function refuseSocket(request) {
|
|
5655
|
-
|
|
5656
|
-
|
|
5664
|
+
function refuseSocket(request, known) {
|
|
5665
|
+
if (detected(request, known) || request.protocols.some((p) => carries(p, known))) {
|
|
5666
|
+
throw new PlaceholderRefused();
|
|
5667
|
+
}
|
|
5657
5668
|
}
|
|
5658
|
-
function placeholderFloor(inner) {
|
|
5669
|
+
function placeholderFloor(inner, { known = () => [], fill: fill2 } = {}) {
|
|
5659
5670
|
const open = inner.websocket?.bind(inner);
|
|
5660
5671
|
return {
|
|
5661
5672
|
get traits() {
|
|
@@ -5663,13 +5674,14 @@ function placeholderFloor(inner) {
|
|
|
5663
5674
|
},
|
|
5664
5675
|
...open ? {
|
|
5665
5676
|
websocket: async (request) => {
|
|
5666
|
-
refuseSocket(request);
|
|
5677
|
+
refuseSocket(request, known());
|
|
5667
5678
|
return open(request);
|
|
5668
5679
|
}
|
|
5669
5680
|
} : {},
|
|
5670
|
-
async fetch(request, owner) {
|
|
5671
|
-
|
|
5672
|
-
|
|
5681
|
+
async fetch(request, owner, stamp) {
|
|
5682
|
+
if (!detected(request, known())) return inner.fetch(request, owner, stamp);
|
|
5683
|
+
if (!fill2 || !stamp) throw new PlaceholderRefused();
|
|
5684
|
+
return fill2(request, stamp);
|
|
5673
5685
|
}
|
|
5674
5686
|
};
|
|
5675
5687
|
}
|
|
@@ -5910,14 +5922,14 @@ function tunnelTarget(req) {
|
|
|
5910
5922
|
}
|
|
5911
5923
|
return { host, port };
|
|
5912
5924
|
}
|
|
5913
|
-
async function watchHangup(conn, abort,
|
|
5914
|
-
while (!
|
|
5925
|
+
async function watchHangup(conn, abort, until2) {
|
|
5926
|
+
while (!until2.aborted && !abort.signal.aborted) {
|
|
5915
5927
|
if (conn.poll().hangup) {
|
|
5916
5928
|
abort.abort(new KernelError("EPIPE"));
|
|
5917
5929
|
return;
|
|
5918
5930
|
}
|
|
5919
5931
|
try {
|
|
5920
|
-
await conn.changed(
|
|
5932
|
+
await conn.changed(until2);
|
|
5921
5933
|
} catch {
|
|
5922
5934
|
return;
|
|
5923
5935
|
}
|
|
@@ -6108,7 +6120,7 @@ var RealmProxy = class {
|
|
|
6108
6120
|
const waiting = new AbortController();
|
|
6109
6121
|
void watchHangup(ctx.socket, abort, waiting.signal);
|
|
6110
6122
|
try {
|
|
6111
|
-
response = await this.upstream(req, url, body, abort.signal, ctx.socket
|
|
6123
|
+
response = await this.upstream(req, url, body, abort.signal, ctx.socket);
|
|
6112
6124
|
} finally {
|
|
6113
6125
|
waiting.abort();
|
|
6114
6126
|
}
|
|
@@ -6135,7 +6147,7 @@ var RealmProxy = class {
|
|
|
6135
6147
|
await conn.write(latin1Bytes("HTTP/1.1 100 Continue\r\n\r\n"), this.stop.signal);
|
|
6136
6148
|
}
|
|
6137
6149
|
}
|
|
6138
|
-
async upstream(req, url, body, signal,
|
|
6150
|
+
async upstream(req, url, body, signal, socket) {
|
|
6139
6151
|
const sent = BODILESS_METHODS.has(req.method) ? void 0 : body;
|
|
6140
6152
|
try {
|
|
6141
6153
|
const fetching = this.options.transport.fetch(
|
|
@@ -6146,7 +6158,8 @@ var RealmProxy = class {
|
|
|
6146
6158
|
...sent instanceof Uint8Array ? { body: sent } : sent ? { bodyStream: sent } : {},
|
|
6147
6159
|
signal
|
|
6148
6160
|
},
|
|
6149
|
-
|
|
6161
|
+
socket.peerCred?.pid,
|
|
6162
|
+
socket.peerStamp
|
|
6150
6163
|
);
|
|
6151
6164
|
return await untilAborted(fetching, signal);
|
|
6152
6165
|
} catch (e) {
|
|
@@ -6190,8 +6203,8 @@ var RealmProxy = class {
|
|
|
6190
6203
|
}
|
|
6191
6204
|
async connect(conn, incoming, req, idle2) {
|
|
6192
6205
|
const target = tunnelTarget(req);
|
|
6193
|
-
const
|
|
6194
|
-
if (
|
|
6206
|
+
const refused4 = target.port === 443 ? await this.tunnelReady(target) : void 0;
|
|
6207
|
+
if (refused4) throw refused4;
|
|
6195
6208
|
await conn.write(latin1Bytes("HTTP/1.1 200 Connection Established\r\n\r\n"), this.stop.signal);
|
|
6196
6209
|
try {
|
|
6197
6210
|
const first = await incoming.peek(this.stop.signal);
|
|
@@ -6463,7 +6476,7 @@ async function relay(socket, conn) {
|
|
|
6463
6476
|
// src/fs/attest.ts
|
|
6464
6477
|
var ATTEST_MAX = 1024 * 1024;
|
|
6465
6478
|
var UNOWNED = 1e3;
|
|
6466
|
-
function
|
|
6479
|
+
function refuse(code, path, why) {
|
|
6467
6480
|
throw Object.assign(new Error(`attest ${path}: ${why}`), { code });
|
|
6468
6481
|
}
|
|
6469
6482
|
function chainOf(path) {
|
|
@@ -6505,39 +6518,49 @@ async function trustedParents(fs, path, o) {
|
|
|
6505
6518
|
const parents = [];
|
|
6506
6519
|
for (const dir of chainOf(path).slice(0, -1)) {
|
|
6507
6520
|
const st = await fs.lstat(dir);
|
|
6508
|
-
if (st.isSymbolicLink)
|
|
6509
|
-
if (!st.isDirectory)
|
|
6521
|
+
if (st.isSymbolicLink) refuse("EACCES", path, `${dir} is a symlink`);
|
|
6522
|
+
if (!st.isDirectory) refuse("ENOTDIR", path, `${dir} is not a directory`);
|
|
6510
6523
|
const perm = owned(dir, st);
|
|
6511
6524
|
if (o.users !== "off" && (perm.uid !== 0 || (perm.mode & 18) !== 0)) {
|
|
6512
|
-
|
|
6525
|
+
refuse("EACCES", path, `${dir} is not root-owned or is writable by group or others`);
|
|
6513
6526
|
}
|
|
6514
6527
|
parents.push(perm);
|
|
6515
6528
|
}
|
|
6516
6529
|
return parents;
|
|
6517
6530
|
}
|
|
6531
|
+
function missing(e) {
|
|
6532
|
+
return e?.code === "ENOENT";
|
|
6533
|
+
}
|
|
6518
6534
|
async function attest(fs, asked, o) {
|
|
6535
|
+
if (o.absent !== void 0 && o.absent !== "allow") {
|
|
6536
|
+
refuse("EINVAL", String(asked), "absent takes only allow");
|
|
6537
|
+
}
|
|
6519
6538
|
if (typeof asked !== "string" || !asked.startsWith("/")) {
|
|
6520
|
-
|
|
6539
|
+
refuse("EINVAL", String(asked), "not an absolute path");
|
|
6521
6540
|
}
|
|
6522
6541
|
const path = normalizePath(asked);
|
|
6523
6542
|
const mount = o.mounts.find((target) => {
|
|
6524
6543
|
const at = normalizePath(target);
|
|
6525
6544
|
return at === "/" || under(path, at);
|
|
6526
6545
|
});
|
|
6527
|
-
if (mount !== void 0)
|
|
6546
|
+
if (mount !== void 0) refuse("EACCES", path, `under the mount ${mount}`);
|
|
6528
6547
|
const parents = await trustedParents(fs, path, o);
|
|
6529
6548
|
for (let tries = 0; ; tries++) {
|
|
6530
|
-
const before = await fs.lstat(path)
|
|
6531
|
-
|
|
6549
|
+
const before = await fs.lstat(path).catch((e) => {
|
|
6550
|
+
if (o.absent === "allow" && missing(e)) return void 0;
|
|
6551
|
+
throw e;
|
|
6552
|
+
});
|
|
6553
|
+
if (!before) return { path, absent: true, users: o.users, onRootFs: true, parents };
|
|
6554
|
+
if (before.isSymbolicLink) refuse("EACCES", path, "is a symlink");
|
|
6532
6555
|
if (!before.isFile)
|
|
6533
|
-
|
|
6534
|
-
if (before.size > ATTEST_MAX)
|
|
6556
|
+
refuse(before.isDirectory ? "EISDIR" : "EINVAL", path, "is not a regular file");
|
|
6557
|
+
if (before.size > ATTEST_MAX) refuse("EFBIG", path, `is over ${ATTEST_MAX} bytes`);
|
|
6535
6558
|
const bytes = (await fs.readFileBuffer(path)).slice();
|
|
6536
6559
|
const after = await fs.lstat(path);
|
|
6537
6560
|
if (unchanged(before, after, bytes)) {
|
|
6538
6561
|
return attested(path, after, bytes, await sha256(bytes), o, parents);
|
|
6539
6562
|
}
|
|
6540
|
-
if (tries >= 1)
|
|
6563
|
+
if (tries >= 1) refuse("EAGAIN", path, "changed while it was read");
|
|
6541
6564
|
}
|
|
6542
6565
|
}
|
|
6543
6566
|
var WATCH_DEBOUNCE_MS = 50;
|
|
@@ -6708,7 +6731,7 @@ var S_IFREG = 32768;
|
|
|
6708
6731
|
var COMMAND = /^\/(?:usr\/)?bin\/([^/]+)$/;
|
|
6709
6732
|
var MAX_LINKS3 = 40;
|
|
6710
6733
|
var BIN_ENTRY = /\/bin\/[^/]+$/;
|
|
6711
|
-
function
|
|
6734
|
+
function missing2(err) {
|
|
6712
6735
|
return err?.code === "ENOENT";
|
|
6713
6736
|
}
|
|
6714
6737
|
function synthetic(directory, path) {
|
|
@@ -6812,7 +6835,7 @@ function withCommandDirs(fs, names2, userDir = async () => void 0, owners = fals
|
|
|
6812
6835
|
}
|
|
6813
6836
|
async function entryTarget(path) {
|
|
6814
6837
|
if (!BIN_ENTRY.test(path) || !(await virtual(path))?.isFile) return void 0;
|
|
6815
|
-
if (!await fs.lstat(path).then(() => false,
|
|
6838
|
+
if (!await fs.lstat(path).then(() => false, missing2)) return void 0;
|
|
6816
6839
|
const target = await targetOf2(path);
|
|
6817
6840
|
return target?.path === path ? void 0 : target;
|
|
6818
6841
|
}
|
|
@@ -6824,11 +6847,11 @@ function withCommandDirs(fs, names2, userDir = async () => void 0, owners = fals
|
|
|
6824
6847
|
return target?.path;
|
|
6825
6848
|
}
|
|
6826
6849
|
const absent2 = (err) => {
|
|
6827
|
-
if (
|
|
6850
|
+
if (missing2(err)) return EMPTY2;
|
|
6828
6851
|
throw err;
|
|
6829
6852
|
};
|
|
6830
6853
|
async function content(path, err) {
|
|
6831
|
-
if (!
|
|
6854
|
+
if (!missing2(err) || !(await linked2(path))?.isFile) throw err;
|
|
6832
6855
|
const target = await redirected2(path);
|
|
6833
6856
|
return target === void 0 ? EMPTY2 : fs.readFileBuffer(target).catch(absent2);
|
|
6834
6857
|
}
|
|
@@ -6837,7 +6860,7 @@ function withCommandDirs(fs, names2, userDir = async () => void 0, owners = fals
|
|
|
6837
6860
|
try {
|
|
6838
6861
|
return await real(path);
|
|
6839
6862
|
} catch (err) {
|
|
6840
|
-
const found =
|
|
6863
|
+
const found = missing2(err) ? await linked2(path) : void 0;
|
|
6841
6864
|
if (found) return found;
|
|
6842
6865
|
throw err;
|
|
6843
6866
|
}
|
|
@@ -6862,7 +6885,7 @@ function withCommandDirs(fs, names2, userDir = async () => void 0, owners = fals
|
|
|
6862
6885
|
const extra = await children3(path);
|
|
6863
6886
|
if (!extra) return fs.readdir(path);
|
|
6864
6887
|
const real = await fs.readdir(path).catch((err) => {
|
|
6865
|
-
if (
|
|
6888
|
+
if (missing2(err)) return [];
|
|
6866
6889
|
throw err;
|
|
6867
6890
|
});
|
|
6868
6891
|
return [.../* @__PURE__ */ new Set([...real, ...extra])].sort();
|
|
@@ -6871,7 +6894,7 @@ function withCommandDirs(fs, names2, userDir = async () => void 0, owners = fals
|
|
|
6871
6894
|
const extra = await children3(path);
|
|
6872
6895
|
if (!extra) return fs.readdirStat(path);
|
|
6873
6896
|
const real = await fs.readdirStat(path).catch((err) => {
|
|
6874
|
-
if (
|
|
6897
|
+
if (missing2(err)) return [];
|
|
6875
6898
|
throw err;
|
|
6876
6899
|
});
|
|
6877
6900
|
const seen = new Set(real.map(([name2]) => name2));
|
|
@@ -6905,7 +6928,7 @@ function withCommandDirs(fs, names2, userDir = async () => void 0, owners = fals
|
|
|
6905
6928
|
...ranged2 ? {
|
|
6906
6929
|
...ranged2,
|
|
6907
6930
|
pread: (path, offset, length2, version) => ranged2.pread(path, offset, length2, version).catch(async (err) => {
|
|
6908
|
-
const target =
|
|
6931
|
+
const target = missing2(err) ? await redirected2(path) : void 0;
|
|
6909
6932
|
if (target === void 0) throw err;
|
|
6910
6933
|
return ranged2.pread(target, offset, length2).catch(absent2);
|
|
6911
6934
|
})
|
|
@@ -6936,7 +6959,7 @@ var S_IFREG2 = 32768;
|
|
|
6936
6959
|
var MAX_HOPS2 = 40;
|
|
6937
6960
|
var parentOf3 = (path) => path.slice(0, path.lastIndexOf("/")) || "/";
|
|
6938
6961
|
var baseOf = (path) => path.slice(path.lastIndexOf("/") + 1);
|
|
6939
|
-
function
|
|
6962
|
+
function missing3(err) {
|
|
6940
6963
|
return err?.code === "ENOENT";
|
|
6941
6964
|
}
|
|
6942
6965
|
function statOf(path, bytes) {
|
|
@@ -6989,11 +7012,11 @@ function withEtcFiles(fs, files) {
|
|
|
6989
7012
|
const text = files.get(path)?.();
|
|
6990
7013
|
return text === void 0 ? void 0 : new TextEncoder().encode(text);
|
|
6991
7014
|
};
|
|
6992
|
-
const absent2 = (path) => fs.lstat(path).then(() => false,
|
|
7015
|
+
const absent2 = (path) => fs.lstat(path).then(() => false, missing3);
|
|
6993
7016
|
const follow2 = linkFollower(fs, files);
|
|
6994
7017
|
const listedAbsent = async (path) => files.has(path) && await absent2(path) ? bytesOf5(path) : void 0;
|
|
6995
7018
|
const fallback = (path, make) => async (err) => {
|
|
6996
|
-
const at =
|
|
7019
|
+
const at = missing3(err) ? await follow2(path) : void 0;
|
|
6997
7020
|
const bytes = at === void 0 ? void 0 : await listedAbsent(at);
|
|
6998
7021
|
if (bytes === void 0 || at === void 0) throw err;
|
|
6999
7022
|
return make(bytes, at);
|
|
@@ -7203,7 +7226,7 @@ var MAX_LINKS4 = 40;
|
|
|
7203
7226
|
function partsOf(path) {
|
|
7204
7227
|
return path.split("/").filter((p) => p !== "" && p !== ".");
|
|
7205
7228
|
}
|
|
7206
|
-
function
|
|
7229
|
+
function missing4(err) {
|
|
7207
7230
|
const code = err?.code;
|
|
7208
7231
|
return code === "ENOENT" || code === "ENOTDIR";
|
|
7209
7232
|
}
|
|
@@ -7222,7 +7245,7 @@ async function resolved(fs, path, follow2, hops = []) {
|
|
|
7222
7245
|
}
|
|
7223
7246
|
const at = `/${[...done4, part].join("/")}`;
|
|
7224
7247
|
const st = await fs.lstat(at).catch((err) => {
|
|
7225
|
-
if (
|
|
7248
|
+
if (missing4(err)) return void 0;
|
|
7226
7249
|
throw err;
|
|
7227
7250
|
});
|
|
7228
7251
|
if (!st) {
|
|
@@ -9366,8 +9389,8 @@ var DriverConnection = class _DriverConnection {
|
|
|
9366
9389
|
} finally {
|
|
9367
9390
|
clearTimeout(timer);
|
|
9368
9391
|
}
|
|
9369
|
-
const
|
|
9370
|
-
if (
|
|
9392
|
+
const refused4 = driverVersionError(hello.protocol);
|
|
9393
|
+
if (refused4) throw errnoError("EPROTO", refused4);
|
|
9371
9394
|
if (hello.error) throw errnoError(hello.errno ?? "EIO", hello.error);
|
|
9372
9395
|
return new _DriverConnection(port, hello.capabilities ?? {}, waiting, timeoutMs, options);
|
|
9373
9396
|
}
|
|
@@ -9451,29 +9474,29 @@ var HeldSet = class extends Set {
|
|
|
9451
9474
|
this.idle = idle2;
|
|
9452
9475
|
this.moved = moved2;
|
|
9453
9476
|
}
|
|
9454
|
-
add(
|
|
9455
|
-
|
|
9456
|
-
|
|
9457
|
-
return super.add(
|
|
9477
|
+
add(holds3) {
|
|
9478
|
+
holds3.onIdle = this.idle;
|
|
9479
|
+
holds3.onMoved = this.moved;
|
|
9480
|
+
return super.add(holds3);
|
|
9458
9481
|
}
|
|
9459
9482
|
doubt(paths, over) {
|
|
9460
|
-
for (const
|
|
9461
|
-
for (const path of paths)
|
|
9462
|
-
if (over !== void 0)
|
|
9483
|
+
for (const holds3 of this) {
|
|
9484
|
+
for (const path of paths) holds3.doubt(path, true);
|
|
9485
|
+
if (over !== void 0) holds3.doubt(over);
|
|
9463
9486
|
}
|
|
9464
9487
|
}
|
|
9465
9488
|
async bindIds(id2) {
|
|
9466
|
-
for (const
|
|
9489
|
+
for (const holds3 of [...this]) await holds3.bindIds(id2);
|
|
9467
9490
|
}
|
|
9468
9491
|
heldIds() {
|
|
9469
9492
|
const out = /* @__PURE__ */ new Map();
|
|
9470
|
-
for (const
|
|
9493
|
+
for (const holds3 of this) for (const [path, fid] of holds3.heldIds()) out.set(path, fid);
|
|
9471
9494
|
return [...out];
|
|
9472
9495
|
}
|
|
9473
|
-
delete(
|
|
9474
|
-
const removed = super.delete(
|
|
9475
|
-
for (const path of /* @__PURE__ */ new Set([...
|
|
9476
|
-
|
|
9496
|
+
delete(holds3) {
|
|
9497
|
+
const removed = super.delete(holds3);
|
|
9498
|
+
for (const path of /* @__PURE__ */ new Set([...holds3.keys(), ...holds3.opens.keys()])) this.idle(path);
|
|
9499
|
+
holds3.releaseAll();
|
|
9477
9500
|
return removed;
|
|
9478
9501
|
}
|
|
9479
9502
|
};
|
|
@@ -11391,8 +11414,8 @@ async function guarded(entry, path, req) {
|
|
|
11391
11414
|
return { paths };
|
|
11392
11415
|
} catch (err) {
|
|
11393
11416
|
const refusal3 = err.code === "EACCES";
|
|
11394
|
-
const
|
|
11395
|
-
return { refused:
|
|
11417
|
+
const refused4 = req.op === "exists" && refusal3 ? json2(false) : toErrno(err);
|
|
11418
|
+
return { refused: refused4 };
|
|
11396
11419
|
}
|
|
11397
11420
|
}
|
|
11398
11421
|
async function copyOp(entry, path, req) {
|
|
@@ -11588,13 +11611,13 @@ async function created(entry, req) {
|
|
|
11588
11611
|
return seen === void 0 ? looked : json2({ ...looked.json, seen });
|
|
11589
11612
|
}
|
|
11590
11613
|
var DENIED = /* @__PURE__ */ new Set(["EACCES", "EPERM"]);
|
|
11591
|
-
async function rmPermitted(entry, path, req,
|
|
11614
|
+
async function rmPermitted(entry, path, req, refused4) {
|
|
11592
11615
|
const st = await entry.fs.lstat(path).catch(() => void 0);
|
|
11593
|
-
if (!st?.isDirectory) return
|
|
11616
|
+
if (!st?.isDirectory) return refused4;
|
|
11594
11617
|
const unlisted = await guarded(entry, path, { ...req, op: "readdir" });
|
|
11595
11618
|
if ("refused" in unlisted) return unlisted.refused;
|
|
11596
11619
|
const names2 = await entry.fs.readdir(path).catch(() => void 0);
|
|
11597
|
-
if (!names2) return
|
|
11620
|
+
if (!names2) return refused4;
|
|
11598
11621
|
let first;
|
|
11599
11622
|
for (const name2 of names2) {
|
|
11600
11623
|
const child = await dispatchOne(entry, {
|
|
@@ -11645,14 +11668,14 @@ async function newDevName(entry, path, req) {
|
|
|
11645
11668
|
const named = NAMING.has(req.op);
|
|
11646
11669
|
if (!named && !CREATIONS.has(req.op)) return void 0;
|
|
11647
11670
|
const target = named ? entry.fs.resolvePath(entry.cwd, req.arg2 ?? "") : path;
|
|
11648
|
-
const
|
|
11649
|
-
if (!
|
|
11671
|
+
const refused4 = devCreation(target, entry.cred?.());
|
|
11672
|
+
if (!refused4) return void 0;
|
|
11650
11673
|
const there = await entry.fs.lstat(target).then(
|
|
11651
11674
|
() => true,
|
|
11652
11675
|
() => false
|
|
11653
11676
|
);
|
|
11654
11677
|
if (there) return void 0;
|
|
11655
|
-
return { ok: false, errno:
|
|
11678
|
+
return { ok: false, errno: refused4, message: `${target}: no new names in /dev or /proc` };
|
|
11656
11679
|
}
|
|
11657
11680
|
var MISS_OPS = /* @__PURE__ */ new Set(["stat", "lstat"]);
|
|
11658
11681
|
async function linkFree(fs, path) {
|
|
@@ -12364,9 +12387,9 @@ var SYS_TREE = {
|
|
|
12364
12387
|
`,
|
|
12365
12388
|
slicc_file_ids: (listing) => `${listing.fileIds ?? 0}
|
|
12366
12389
|
`,
|
|
12367
|
-
slicc_peer_holds: ({ holds:
|
|
12390
|
+
slicc_peer_holds: ({ holds: holds3 }) => `${holds3?.mine ?? 0} ${holds3?.peers ?? 0} ${holds3?.sent ?? 0}
|
|
12368
12391
|
`,
|
|
12369
|
-
slicc_peer_held: ({ holds:
|
|
12392
|
+
slicc_peer_held: ({ holds: holds3 }) => (holds3?.held ?? []).map((path) => `${path}
|
|
12370
12393
|
`).join(""),
|
|
12371
12394
|
slicc_rename_acks: (listing) => {
|
|
12372
12395
|
const samples = [...listing.renameAcks?.ackMs ?? []].sort((a, b) => a - b);
|
|
@@ -13107,11 +13130,11 @@ var EpollFile = class _EpollFile {
|
|
|
13107
13130
|
const round = new AbortController();
|
|
13108
13131
|
const stop = () => round.abort();
|
|
13109
13132
|
signal.addEventListener("abort", stop, { once: true });
|
|
13110
|
-
let
|
|
13133
|
+
let failed5 = false;
|
|
13111
13134
|
try {
|
|
13112
13135
|
await file.changed(round.signal);
|
|
13113
13136
|
} catch {
|
|
13114
|
-
|
|
13137
|
+
failed5 = true;
|
|
13115
13138
|
} finally {
|
|
13116
13139
|
round.abort();
|
|
13117
13140
|
signal.removeEventListener("abort", stop);
|
|
@@ -13119,7 +13142,7 @@ var EpollFile = class _EpollFile {
|
|
|
13119
13142
|
if (signal.aborted) return;
|
|
13120
13143
|
reg.gen++;
|
|
13121
13144
|
this.changes.wake();
|
|
13122
|
-
if (
|
|
13145
|
+
if (failed5) await pause(RETRY_MS, signal);
|
|
13123
13146
|
}
|
|
13124
13147
|
}
|
|
13125
13148
|
};
|
|
@@ -13755,8 +13778,8 @@ var KernelLoopback = class {
|
|
|
13755
13778
|
);
|
|
13756
13779
|
} catch (err) {
|
|
13757
13780
|
socket.close();
|
|
13758
|
-
const
|
|
13759
|
-
throw
|
|
13781
|
+
const refused4 = err instanceof KernelError && err.code === "ECONNREFUSED";
|
|
13782
|
+
throw refused4 ? errno2("ECONNREFUSED", `nothing listens on the kernel's port ${port}`) : err;
|
|
13760
13783
|
}
|
|
13761
13784
|
signal.addEventListener("abort", () => socket.close(), { once: true });
|
|
13762
13785
|
return socket;
|
|
@@ -14100,11 +14123,11 @@ function ipv6(host) {
|
|
|
14100
14123
|
const back = halves.length === 2 ? groups(halves[1]) : [];
|
|
14101
14124
|
if (![...head, ...back].every((g) => /^[0-9A-Fa-f]{1,4}$/.test(g))) return void 0;
|
|
14102
14125
|
const words2 = [...head, ...back].map((g) => Number.parseInt(g, 16));
|
|
14103
|
-
const
|
|
14104
|
-
if (halves.length === 2 ?
|
|
14126
|
+
const missing6 = 8 - words2.length - tail2.length;
|
|
14127
|
+
if (halves.length === 2 ? missing6 < 1 : missing6 !== 0) return void 0;
|
|
14105
14128
|
const all = [
|
|
14106
14129
|
...head.map((g) => Number.parseInt(g, 16)),
|
|
14107
|
-
...new Array(halves.length === 2 ?
|
|
14130
|
+
...new Array(halves.length === 2 ? missing6 : 0).fill(0),
|
|
14108
14131
|
...back.map((g) => Number.parseInt(g, 16)),
|
|
14109
14132
|
...tail2
|
|
14110
14133
|
];
|
|
@@ -15101,10 +15124,12 @@ var HttpHandles = class {
|
|
|
15101
15124
|
ws;
|
|
15102
15125
|
owner;
|
|
15103
15126
|
local;
|
|
15104
|
-
|
|
15127
|
+
stamp;
|
|
15128
|
+
constructor(transport, owner, local2, stamp) {
|
|
15105
15129
|
this.transport = transport;
|
|
15106
15130
|
this.owner = owner;
|
|
15107
15131
|
this.local = local2;
|
|
15132
|
+
this.stamp = stamp;
|
|
15108
15133
|
this.ws = new WsHandles(transport, () => ++this.nextHandle, local2);
|
|
15109
15134
|
}
|
|
15110
15135
|
syscall(req) {
|
|
@@ -15180,7 +15205,7 @@ var HttpHandles = class {
|
|
|
15180
15205
|
...entry.upload ? { bodyStream: entry.upload } : req.body ? { body: req.body } : {},
|
|
15181
15206
|
signal: entry.abort.signal
|
|
15182
15207
|
};
|
|
15183
|
-
const response = port === void 0 ? await this.transport.fetch(request, this.owner) : await this.local.fetch(request, port);
|
|
15208
|
+
const response = port === void 0 ? await this.transport.fetch(request, this.owner, await this.stamp?.()) : await this.local.fetch(request, port);
|
|
15184
15209
|
entry.body = response.body[Symbol.asyncIterator]();
|
|
15185
15210
|
entry.cancel = () => response.cancel();
|
|
15186
15211
|
if (!this.open.has(handle)) await entry.cancel().catch(() => void 0);
|
|
@@ -15202,8 +15227,8 @@ var HttpHandles = class {
|
|
|
15202
15227
|
if (text === NO_TRANSPORT || typeof status !== "number" || status === 502) {
|
|
15203
15228
|
const code = codeOf2(e);
|
|
15204
15229
|
const errno3 = text === NO_TRANSPORT ? "ENETUNREACH" : code !== "EIO" ? code : "ECONNREFUSED";
|
|
15205
|
-
const
|
|
15206
|
-
return { ok: false, errno: errno3, message: text, ...
|
|
15230
|
+
const failed5 = e.detail === "transport";
|
|
15231
|
+
return { ok: false, errno: errno3, message: text, ...failed5 ? { detail: "transport" } : {} };
|
|
15207
15232
|
}
|
|
15208
15233
|
entry.body = once(new TextEncoder().encode(text))[Symbol.asyncIterator]();
|
|
15209
15234
|
return this.headOf(handle, req.url, {
|
|
@@ -16998,7 +17023,7 @@ function pass(c, input, final) {
|
|
|
16998
17023
|
const partials = [];
|
|
16999
17024
|
scanMain(c, input, best, partials);
|
|
17000
17025
|
scanWrapped(c, input, best, partials);
|
|
17001
|
-
const
|
|
17026
|
+
const holds3 = final ? [] : [...new Set(partials)].sort((a, b) => a - b);
|
|
17002
17027
|
const starts = [...best.keys()].sort((a, b) => a - b);
|
|
17003
17028
|
const parts2 = [];
|
|
17004
17029
|
const hits = /* @__PURE__ */ new Map();
|
|
@@ -17008,8 +17033,8 @@ function pass(c, input, final) {
|
|
|
17008
17033
|
let h = 0;
|
|
17009
17034
|
for (; ; ) {
|
|
17010
17035
|
while (s < starts.length && starts[s] < pos) s++;
|
|
17011
|
-
while (h <
|
|
17012
|
-
const hold = h <
|
|
17036
|
+
while (h < holds3.length && holds3[h] < pos) h++;
|
|
17037
|
+
const hold = h < holds3.length ? holds3[h] : Infinity;
|
|
17013
17038
|
const next3 = s < starts.length ? starts[s] : Infinity;
|
|
17014
17039
|
if (hold <= next3) {
|
|
17015
17040
|
cut = Math.min(hold, input.length);
|
|
@@ -17111,23 +17136,23 @@ function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
|
|
|
17111
17136
|
let pending = 0;
|
|
17112
17137
|
let busy = false;
|
|
17113
17138
|
let timer;
|
|
17114
|
-
let
|
|
17139
|
+
let failed5;
|
|
17115
17140
|
const waiters = /* @__PURE__ */ new Set();
|
|
17116
17141
|
const quiet3 = () => !busy && pending === 0;
|
|
17117
17142
|
const wake = () => {
|
|
17118
17143
|
for (const waiter of [...waiters]) waiter();
|
|
17119
17144
|
};
|
|
17120
17145
|
const raise = () => {
|
|
17121
|
-
if (
|
|
17122
|
-
const err =
|
|
17123
|
-
|
|
17146
|
+
if (failed5 === void 0) return;
|
|
17147
|
+
const err = failed5;
|
|
17148
|
+
failed5 = void 0;
|
|
17124
17149
|
throw err;
|
|
17125
17150
|
};
|
|
17126
17151
|
const later = (bytes) => {
|
|
17127
17152
|
if (bytes.length === 0) return;
|
|
17128
17153
|
pending += 1;
|
|
17129
17154
|
tail2 = tail2.then(() => writeAll2(file, bytes)).catch((err) => {
|
|
17130
|
-
if (
|
|
17155
|
+
if (failed5 === void 0) failed5 = err;
|
|
17131
17156
|
}).finally(() => {
|
|
17132
17157
|
pending -= 1;
|
|
17133
17158
|
if (quiet3()) wake();
|
|
@@ -20202,7 +20227,7 @@ async function connect(req, proc) {
|
|
|
20202
20227
|
}
|
|
20203
20228
|
const path = filePath(req.addr);
|
|
20204
20229
|
const name2 = path !== void 0 ? await proc.names?.find(path) : void 0;
|
|
20205
|
-
const stamp = proc.net.
|
|
20230
|
+
const stamp = proc.net.stampsPeers(req.addr) && await proc.stamp?.();
|
|
20206
20231
|
const dialing = target.connect(req.addr, true, proc.cred?.(), stamp || void 0, true, name2);
|
|
20207
20232
|
if (req.nonblock) {
|
|
20208
20233
|
dialing?.catch(() => void 0);
|
|
@@ -20324,7 +20349,7 @@ async function secureConnect(req, proc) {
|
|
|
20324
20349
|
delete req.clientCert;
|
|
20325
20350
|
throw new KernelError("ENOTSUP");
|
|
20326
20351
|
}
|
|
20327
|
-
return { ...tlsOverTransport(req, proc), path: "transport", substitutes: true };
|
|
20352
|
+
return { ...await tlsOverTransport(req, proc), path: "transport", substitutes: true };
|
|
20328
20353
|
}
|
|
20329
20354
|
const socket = proc.net.socket("inet");
|
|
20330
20355
|
const fd = proc.fds.install(new OpenFile(socket), 3);
|
|
@@ -20343,7 +20368,7 @@ async function uplinked(proc, host) {
|
|
|
20343
20368
|
return false;
|
|
20344
20369
|
}
|
|
20345
20370
|
}
|
|
20346
|
-
function tlsOverTransport(req, proc) {
|
|
20371
|
+
async function tlsOverTransport(req, proc) {
|
|
20347
20372
|
if (req.ca) throw new KernelError("ENOTSUP");
|
|
20348
20373
|
if (req.alpn && req.alpn.length > 0 && !req.alpn.includes("http/1.1")) {
|
|
20349
20374
|
throw new KernelError("EPROTONOSUPPORT");
|
|
@@ -20356,7 +20381,9 @@ function tlsOverTransport(req, proc) {
|
|
|
20356
20381
|
if (isLoopbackHost(servername) || isLoopbackHost(req.host)) throw new KernelError("ENOTSUP");
|
|
20357
20382
|
const host = servername.includes(":") && !servername.startsWith("[") ? `[${servername}]` : servername;
|
|
20358
20383
|
const origin = req.port === 443 ? `https://${host}` : `https://${host}:${req.port}`;
|
|
20384
|
+
const stamp = proc.net.originsStamped ? await proc.stamp?.() : void 0;
|
|
20359
20385
|
const [mine, theirs] = KernelSocket.pair(proc.net, "inet", proc.cred?.());
|
|
20386
|
+
theirs.peerStamp = stamp;
|
|
20360
20387
|
mine.peer = { family: "inet", host: req.host, port: req.port };
|
|
20361
20388
|
try {
|
|
20362
20389
|
proc.net.serveOrigin(theirs, origin);
|
|
@@ -23515,13 +23542,13 @@ function inherited(opts) {
|
|
|
23515
23542
|
...opts.cred ? { cred: opts.cred } : {}
|
|
23516
23543
|
};
|
|
23517
23544
|
}
|
|
23518
|
-
function heldBy(process2,
|
|
23519
|
-
process2.keptPath = (path) =>
|
|
23520
|
-
process2.keptHandle = (handle) =>
|
|
23521
|
-
process2.holdsHandle = (handle) =>
|
|
23545
|
+
function heldBy(process2, holds3, replacements) {
|
|
23546
|
+
process2.keptPath = (path) => holds3.keptAt(path)?.hidden;
|
|
23547
|
+
process2.keptHandle = (handle) => holds3.keptFor(handle)?.hidden;
|
|
23548
|
+
process2.holdsHandle = (handle) => holds3.holdsHandle(handle);
|
|
23522
23549
|
if (replacements) process2.replacements = replacements;
|
|
23523
23550
|
}
|
|
23524
|
-
function holdingToken(opts,
|
|
23551
|
+
function holdingToken(opts, holds3, caller) {
|
|
23525
23552
|
return mintSyncFsToken({
|
|
23526
23553
|
...opts.owners ? caller : { umask: caller.umask },
|
|
23527
23554
|
...opts.dac ? { dac: opts.dac, pid: opts.pid, created: caller.created } : {},
|
|
@@ -23538,16 +23565,16 @@ function holdingToken(opts, holds2, caller) {
|
|
|
23538
23565
|
...opts.fileId ? { fileId: opts.fileId } : {},
|
|
23539
23566
|
...opts.announceHold ? { announceHold: opts.announceHold } : {},
|
|
23540
23567
|
...opts.renameSeq ? { renameSeq: opts.renameSeq } : {},
|
|
23541
|
-
hold: (path, on, open, real, handle, ino, fid) =>
|
|
23542
|
-
boundIno:
|
|
23543
|
-
trust:
|
|
23544
|
-
keptFor: (handle) =>
|
|
23545
|
-
heldAt: (handle) =>
|
|
23546
|
-
unlinked: (path) =>
|
|
23547
|
-
gate: (path, op) => opts.unlinkGate &&
|
|
23548
|
-
own: (path, op) =>
|
|
23549
|
-
revoked: (path) =>
|
|
23550
|
-
renamed: (from, to) =>
|
|
23568
|
+
hold: (path, on, open, real, handle, ino, fid) => holds3.hold(path, on, open, real, handle, ino, fid),
|
|
23569
|
+
boundIno: holds3.boundIno.bind(holds3),
|
|
23570
|
+
trust: holds3.trust.bind(holds3),
|
|
23571
|
+
keptFor: (handle) => holds3.keptFor(handle),
|
|
23572
|
+
heldAt: (handle) => holds3.pathOf(handle),
|
|
23573
|
+
unlinked: (path) => holds3.keptAt(path),
|
|
23574
|
+
gate: (path, op) => opts.unlinkGate && holds3.holding(path) ? opts.unlinkGate.run(holds3.keyOf(path), op) : op(),
|
|
23575
|
+
own: (path, op) => holds3.own(path, op),
|
|
23576
|
+
revoked: (path) => holds3.isRevoked(path),
|
|
23577
|
+
renamed: (from, to) => holds3.renamed(from, to)
|
|
23551
23578
|
});
|
|
23552
23579
|
}
|
|
23553
23580
|
function linksOf(opts) {
|
|
@@ -23704,15 +23731,15 @@ function spawnWasmProcess(opts) {
|
|
|
23704
23731
|
)
|
|
23705
23732
|
);
|
|
23706
23733
|
publishStops(process2, header5);
|
|
23707
|
-
const
|
|
23708
|
-
opts.held?.add(
|
|
23709
|
-
const token = holdingToken(opts,
|
|
23734
|
+
const holds3 = new HeldPaths();
|
|
23735
|
+
opts.held?.add(holds3);
|
|
23736
|
+
const token = holdingToken(opts, holds3, {
|
|
23710
23737
|
cred: () => process2.cred,
|
|
23711
23738
|
umask: () => process2.umask,
|
|
23712
23739
|
created: created4,
|
|
23713
|
-
holdsKept: async (path) => path.includes(`/${UNLINKED_DIR}/`) && (
|
|
23740
|
+
holdsKept: async (path) => path.includes(`/${UNLINKED_DIR}/`) && (holds3.keeps(path) || await process2.holds(path))
|
|
23714
23741
|
});
|
|
23715
|
-
heldBy(process2,
|
|
23742
|
+
heldBy(process2, holds3, opts.replacements);
|
|
23716
23743
|
const worker = opts.createWorker();
|
|
23717
23744
|
const dying = new Dying();
|
|
23718
23745
|
const dispatch2 = (req, block) => dying.serve(
|
|
@@ -23744,7 +23771,7 @@ function spawnWasmProcess(opts) {
|
|
|
23744
23771
|
responder.dispose();
|
|
23745
23772
|
lane?.dispose();
|
|
23746
23773
|
revokeSyncFsToken(token);
|
|
23747
|
-
opts.held?.delete(
|
|
23774
|
+
opts.held?.delete(holds3);
|
|
23748
23775
|
worker.terminate();
|
|
23749
23776
|
settleExit(process2.exit(), settle, code);
|
|
23750
23777
|
};
|
|
@@ -24310,10 +24337,10 @@ var RemoteWatch = class {
|
|
|
24310
24337
|
});
|
|
24311
24338
|
}
|
|
24312
24339
|
}
|
|
24313
|
-
heldBy({ tab, holds:
|
|
24340
|
+
heldBy({ tab, holds: holds3, seq: seq2 }) {
|
|
24314
24341
|
const from = tab;
|
|
24315
|
-
const { add, drop } =
|
|
24316
|
-
if (
|
|
24342
|
+
const { add, drop } = holds3;
|
|
24343
|
+
if (holds3?.instance !== void 0) this.instances.set(from, holds3.instance);
|
|
24317
24344
|
const held = this.peerHolds.get(from) ?? /* @__PURE__ */ new Map();
|
|
24318
24345
|
for (const path of drop) held.delete(path);
|
|
24319
24346
|
for (const [path, fid] of add) held.set(path, fid);
|
|
@@ -25258,6 +25285,236 @@ function enableDnsStub(net, stub) {
|
|
|
25258
25285
|
});
|
|
25259
25286
|
}
|
|
25260
25287
|
|
|
25288
|
+
// src/kernel/net/remote-transport.ts
|
|
25289
|
+
var TransportError = class extends Error {
|
|
25290
|
+
status;
|
|
25291
|
+
code;
|
|
25292
|
+
detail;
|
|
25293
|
+
constructor(message3, status, code, detail) {
|
|
25294
|
+
super(message3);
|
|
25295
|
+
this.status = status;
|
|
25296
|
+
this.code = code;
|
|
25297
|
+
this.detail = detail === "transport" ? detail : void 0;
|
|
25298
|
+
}
|
|
25299
|
+
};
|
|
25300
|
+
function unfollowed2(redirect) {
|
|
25301
|
+
return redirect !== void 0 && redirect !== "follow";
|
|
25302
|
+
}
|
|
25303
|
+
function honors(traits, redirect) {
|
|
25304
|
+
if (traits.redirectPolicy === true) return true;
|
|
25305
|
+
const hops = traits.redirectHops;
|
|
25306
|
+
const raw2 = traits.manualRedirects === true && (hops === void 0 || hops === false);
|
|
25307
|
+
return redirect === "manual" && raw2;
|
|
25308
|
+
}
|
|
25309
|
+
function refused3(message3) {
|
|
25310
|
+
return new TransportError(message3, 502, void 0, "transport");
|
|
25311
|
+
}
|
|
25312
|
+
var RemoteTransport = class {
|
|
25313
|
+
traits;
|
|
25314
|
+
port;
|
|
25315
|
+
waiting = /* @__PURE__ */ new Map();
|
|
25316
|
+
nextId = 0;
|
|
25317
|
+
sockets = /* @__PURE__ */ new Map();
|
|
25318
|
+
uploads = /* @__PURE__ */ new Map();
|
|
25319
|
+
failure;
|
|
25320
|
+
constructor(port, traits) {
|
|
25321
|
+
this.port = port;
|
|
25322
|
+
this.traits = traits;
|
|
25323
|
+
}
|
|
25324
|
+
receive(reply) {
|
|
25325
|
+
if (reply.net === "body-pull") {
|
|
25326
|
+
void this.pull(reply.nid);
|
|
25327
|
+
return;
|
|
25328
|
+
}
|
|
25329
|
+
const socket = this.sockets.get(reply.nid);
|
|
25330
|
+
if (socket && this.toSocket(reply, socket)) return;
|
|
25331
|
+
const waiter = this.waiting.get(reply.nid);
|
|
25332
|
+
if (!waiter) return;
|
|
25333
|
+
this.waiting.delete(reply.nid);
|
|
25334
|
+
if (reply.net === "error") {
|
|
25335
|
+
waiter.reject(new TransportError(reply.message, reply.status, reply.code, reply.detail));
|
|
25336
|
+
} else waiter.resolve(reply);
|
|
25337
|
+
}
|
|
25338
|
+
toSocket(reply, socket) {
|
|
25339
|
+
if (reply.net === "ws-message") socket.queue.push(reply.data);
|
|
25340
|
+
else if (reply.net === "ws-acked") socket.acked(reply.n);
|
|
25341
|
+
else if (reply.net === "ws-closed") {
|
|
25342
|
+
this.sockets.delete(reply.nid);
|
|
25343
|
+
socket.queue.end({ code: reply.code, reason: reply.reason });
|
|
25344
|
+
} else return false;
|
|
25345
|
+
return true;
|
|
25346
|
+
}
|
|
25347
|
+
async pull(nid) {
|
|
25348
|
+
const upload = this.uploads.get(nid);
|
|
25349
|
+
if (!upload) {
|
|
25350
|
+
this.port.postMessage({ net: "body-error", nid, message: "the request body is gone" });
|
|
25351
|
+
return;
|
|
25352
|
+
}
|
|
25353
|
+
try {
|
|
25354
|
+
const next3 = await upload.next();
|
|
25355
|
+
if (next3.done) {
|
|
25356
|
+
this.uploads.delete(nid);
|
|
25357
|
+
this.port.postMessage({ net: "body-end", nid });
|
|
25358
|
+
} else this.port.postMessage({ net: "body-chunk", nid, bytes: next3.value });
|
|
25359
|
+
} catch (e) {
|
|
25360
|
+
this.uploads.delete(nid);
|
|
25361
|
+
this.port.postMessage({
|
|
25362
|
+
net: "body-error",
|
|
25363
|
+
nid,
|
|
25364
|
+
message: e instanceof Error ? e.message : String(e)
|
|
25365
|
+
});
|
|
25366
|
+
}
|
|
25367
|
+
}
|
|
25368
|
+
dropUpload(nid) {
|
|
25369
|
+
const upload = this.uploads.get(nid);
|
|
25370
|
+
this.uploads.delete(nid);
|
|
25371
|
+
void upload?.return?.().catch(() => void 0);
|
|
25372
|
+
}
|
|
25373
|
+
fail(error) {
|
|
25374
|
+
this.failure = error;
|
|
25375
|
+
for (const nid of [...this.uploads.keys()]) this.dropUpload(nid);
|
|
25376
|
+
for (const waiter of this.waiting.values()) waiter.reject(error);
|
|
25377
|
+
this.waiting.clear();
|
|
25378
|
+
for (const socket of this.sockets.values())
|
|
25379
|
+
socket.queue.end({ code: 1011, reason: error.message });
|
|
25380
|
+
this.sockets.clear();
|
|
25381
|
+
}
|
|
25382
|
+
ask(call) {
|
|
25383
|
+
if (this.failure) return Promise.reject(this.failure);
|
|
25384
|
+
return new Promise((resolve2, reject) => {
|
|
25385
|
+
this.waiting.set(call.nid, { resolve: resolve2, reject });
|
|
25386
|
+
this.port.postMessage(call);
|
|
25387
|
+
});
|
|
25388
|
+
}
|
|
25389
|
+
cancel(nid) {
|
|
25390
|
+
const waiter = this.waiting.get(nid);
|
|
25391
|
+
this.waiting.delete(nid);
|
|
25392
|
+
waiter?.reject(new TransportError("the request was cancelled"));
|
|
25393
|
+
this.port.postMessage({ net: "cancel", nid });
|
|
25394
|
+
}
|
|
25395
|
+
async fetch(request, owner, stamp) {
|
|
25396
|
+
const nid = ++this.nextId;
|
|
25397
|
+
const { signal, redirect } = request;
|
|
25398
|
+
signal.throwIfAborted();
|
|
25399
|
+
if (unfollowed2(redirect) && !honors(this.traits, redirect)) {
|
|
25400
|
+
throw refused3(`this transport cannot honor redirect: ${redirect}`);
|
|
25401
|
+
}
|
|
25402
|
+
let finished = false;
|
|
25403
|
+
const abort = () => {
|
|
25404
|
+
finished = true;
|
|
25405
|
+
this.dropUpload(nid);
|
|
25406
|
+
this.cancel(nid);
|
|
25407
|
+
};
|
|
25408
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
25409
|
+
const finish = () => {
|
|
25410
|
+
this.dropUpload(nid);
|
|
25411
|
+
if (finished) return;
|
|
25412
|
+
finished = true;
|
|
25413
|
+
signal.removeEventListener("abort", abort);
|
|
25414
|
+
};
|
|
25415
|
+
if (request.bodyStream) this.uploads.set(nid, request.bodyStream[Symbol.asyncIterator]());
|
|
25416
|
+
let head;
|
|
25417
|
+
try {
|
|
25418
|
+
head = await this.ask({
|
|
25419
|
+
net: "fetch",
|
|
25420
|
+
nid,
|
|
25421
|
+
url: request.url,
|
|
25422
|
+
method: request.method,
|
|
25423
|
+
headers: request.headers,
|
|
25424
|
+
...request.bodyStream ? { streamed: true } : request.body ? { body: request.body } : {},
|
|
25425
|
+
...redirect !== void 0 ? { redirect } : {},
|
|
25426
|
+
...owner !== void 0 ? { owner } : {},
|
|
25427
|
+
...stamp ? { stamp } : {}
|
|
25428
|
+
});
|
|
25429
|
+
} catch (e) {
|
|
25430
|
+
finish();
|
|
25431
|
+
throw e;
|
|
25432
|
+
}
|
|
25433
|
+
const { status, statusText, headers, url, redirected: redirected2, redirects, opaqueRedirect } = head;
|
|
25434
|
+
const read = async () => {
|
|
25435
|
+
if (finished) return void 0;
|
|
25436
|
+
const reply = await this.ask({ net: "read", nid }).catch((e) => {
|
|
25437
|
+
finish();
|
|
25438
|
+
throw e;
|
|
25439
|
+
});
|
|
25440
|
+
if (reply.net === "chunk") return reply.bytes;
|
|
25441
|
+
finish();
|
|
25442
|
+
return void 0;
|
|
25443
|
+
};
|
|
25444
|
+
const cancel = async () => {
|
|
25445
|
+
if (finished) return;
|
|
25446
|
+
finish();
|
|
25447
|
+
this.cancel(nid);
|
|
25448
|
+
};
|
|
25449
|
+
if (unfollowed2(redirect) && (redirected2 || redirects?.length)) {
|
|
25450
|
+
await cancel();
|
|
25451
|
+
throw refused3(`this transport followed a redirect despite redirect: ${redirect}`);
|
|
25452
|
+
}
|
|
25453
|
+
return {
|
|
25454
|
+
...url !== void 0 ? { url } : {},
|
|
25455
|
+
...redirected2 !== void 0 ? { redirected: redirected2 } : {},
|
|
25456
|
+
...redirects ? { redirects } : {},
|
|
25457
|
+
...opaqueRedirect ? { opaqueRedirect } : {},
|
|
25458
|
+
status,
|
|
25459
|
+
statusText,
|
|
25460
|
+
headers,
|
|
25461
|
+
cancel,
|
|
25462
|
+
body: {
|
|
25463
|
+
[Symbol.asyncIterator]: () => ({
|
|
25464
|
+
next: async () => {
|
|
25465
|
+
const bytes = await read();
|
|
25466
|
+
return bytes ? { value: bytes, done: false } : { value: void 0, done: true };
|
|
25467
|
+
},
|
|
25468
|
+
return: async () => {
|
|
25469
|
+
await cancel();
|
|
25470
|
+
return { value: void 0, done: true };
|
|
25471
|
+
}
|
|
25472
|
+
})
|
|
25473
|
+
}
|
|
25474
|
+
};
|
|
25475
|
+
}
|
|
25476
|
+
async websocket(request) {
|
|
25477
|
+
const nid = ++this.nextId;
|
|
25478
|
+
const { signal } = request;
|
|
25479
|
+
signal.throwIfAborted();
|
|
25480
|
+
const abort = () => this.cancel(nid);
|
|
25481
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
25482
|
+
let opened2;
|
|
25483
|
+
try {
|
|
25484
|
+
opened2 = await this.ask({
|
|
25485
|
+
net: "ws-open",
|
|
25486
|
+
nid,
|
|
25487
|
+
url: request.url,
|
|
25488
|
+
protocols: request.protocols,
|
|
25489
|
+
headers: request.headers
|
|
25490
|
+
});
|
|
25491
|
+
} finally {
|
|
25492
|
+
signal.removeEventListener("abort", abort);
|
|
25493
|
+
}
|
|
25494
|
+
const close = (code, reason) => this.port.postMessage({ net: "ws-close", nid, code, reason });
|
|
25495
|
+
const queue = new MessageQueue(
|
|
25496
|
+
() => close(1e3, "a message is too big"),
|
|
25497
|
+
Number.POSITIVE_INFINITY,
|
|
25498
|
+
(n) => this.port.postMessage({ net: "ws-consumed", nid, n })
|
|
25499
|
+
);
|
|
25500
|
+
let unacked = 0;
|
|
25501
|
+
this.sockets.set(nid, { queue, acked: (n) => void (unacked -= n) });
|
|
25502
|
+
return {
|
|
25503
|
+
protocol: opened2.protocol,
|
|
25504
|
+
get buffered() {
|
|
25505
|
+
return unacked;
|
|
25506
|
+
},
|
|
25507
|
+
send: (data) => {
|
|
25508
|
+
unacked += payloadSize(data);
|
|
25509
|
+
this.port.postMessage({ net: "ws-send", nid, data });
|
|
25510
|
+
},
|
|
25511
|
+
messages: queue,
|
|
25512
|
+
close,
|
|
25513
|
+
closed: queue.closed
|
|
25514
|
+
};
|
|
25515
|
+
}
|
|
25516
|
+
};
|
|
25517
|
+
|
|
25261
25518
|
// src/kernel/net/redirect-hops.ts
|
|
25262
25519
|
var HELD_MS = 3e4;
|
|
25263
25520
|
var HELD_MAX2 = 64;
|
|
@@ -25333,7 +25590,9 @@ function replayingHops(inner, heldMs = HELD_MS) {
|
|
|
25333
25590
|
return { ...inner.traits, manualRedirects: true };
|
|
25334
25591
|
},
|
|
25335
25592
|
...inner.websocket ? { websocket: inner.websocket.bind(inner) } : {},
|
|
25336
|
-
async fetch(request,
|
|
25593
|
+
async fetch(request, ...rest2) {
|
|
25594
|
+
if (unfollowed2(request.redirect)) return inner.fetch(request, ...rest2);
|
|
25595
|
+
const [caller] = rest2;
|
|
25337
25596
|
const owner = caller ?? KERNEL;
|
|
25338
25597
|
const key = keyOf3(owner, request.method, request.url);
|
|
25339
25598
|
const waiting = held.get(key);
|
|
@@ -25343,7 +25602,7 @@ function replayingHops(inner, heldMs = HELD_MS) {
|
|
|
25343
25602
|
return replay(waiting);
|
|
25344
25603
|
}
|
|
25345
25604
|
if (waiting) drop(key);
|
|
25346
|
-
const response = await inner.fetch(request,
|
|
25605
|
+
const response = await inner.fetch(request, ...rest2);
|
|
25347
25606
|
if (!response.redirects?.length) return response;
|
|
25348
25607
|
return replay({
|
|
25349
25608
|
owner,
|
|
@@ -25356,6 +25615,173 @@ function replayingHops(inner, heldMs = HELD_MS) {
|
|
|
25356
25615
|
};
|
|
25357
25616
|
}
|
|
25358
25617
|
|
|
25618
|
+
// src/body-idle.ts
|
|
25619
|
+
var BODY_IDLE_MS = 5 * 60 * 1e3;
|
|
25620
|
+
function idleFailure(ms) {
|
|
25621
|
+
return Object.assign(new Error(`the response body sent no data for ${ms} ms`), {
|
|
25622
|
+
code: "ETIMEDOUT"
|
|
25623
|
+
});
|
|
25624
|
+
}
|
|
25625
|
+
async function readWithin(reader, ms) {
|
|
25626
|
+
if (!(ms > 0 && ms < Number.POSITIVE_INFINITY)) return reader.read();
|
|
25627
|
+
let timer;
|
|
25628
|
+
const idle2 = new Promise((_, reject) => {
|
|
25629
|
+
timer = setTimeout(() => reject(idleFailure(ms)), ms);
|
|
25630
|
+
});
|
|
25631
|
+
try {
|
|
25632
|
+
return await Promise.race([reader.read(), idle2]);
|
|
25633
|
+
} finally {
|
|
25634
|
+
clearTimeout(timer);
|
|
25635
|
+
}
|
|
25636
|
+
}
|
|
25637
|
+
|
|
25638
|
+
// src/kernel/net/sealed-fetch.ts
|
|
25639
|
+
var SEALED_FETCH_VERSION = 1;
|
|
25640
|
+
var UNSAFE_FIELD = /[\r\n\0]/;
|
|
25641
|
+
function sealedHooks(option) {
|
|
25642
|
+
if (!option) return {};
|
|
25643
|
+
if (typeof option === "function") return { request: option };
|
|
25644
|
+
const { request, fetch: fetch2 } = option;
|
|
25645
|
+
if (typeof request !== "function" || fetch2 !== void 0 && typeof fetch2 !== "function") {
|
|
25646
|
+
throw new TypeError("sealed takes a function or { request, fetch? }");
|
|
25647
|
+
}
|
|
25648
|
+
return { request, ...fetch2 ? { fetch: fetch2 } : {} };
|
|
25649
|
+
}
|
|
25650
|
+
function headerList(headers) {
|
|
25651
|
+
return Array.isArray(headers) && headers.every(
|
|
25652
|
+
(field4) => Array.isArray(field4) && field4.length === 2 && field4.every((text) => typeof text === "string" && !UNSAFE_FIELD.test(text))
|
|
25653
|
+
);
|
|
25654
|
+
}
|
|
25655
|
+
function sealedReplyValid(reply) {
|
|
25656
|
+
if (typeof reply !== "object" || reply === null) return false;
|
|
25657
|
+
const { redirects, redirected: redirected2, status, statusText, headers, url, body, cancel } = reply;
|
|
25658
|
+
return redirects === void 0 && redirected2 !== true && Number.isInteger(status) && status >= 100 && status <= 599 && typeof statusText === "string" && !UNSAFE_FIELD.test(statusText) && headerList(headers) && (url === void 0 || typeof url === "string") && typeof body?.[Symbol.asyncIterator] === "function" && typeof cancel === "function";
|
|
25659
|
+
}
|
|
25660
|
+
function dropSealedReply(reply) {
|
|
25661
|
+
const { cancel } = reply ?? {};
|
|
25662
|
+
if (typeof cancel !== "function") return;
|
|
25663
|
+
void Promise.resolve().then(() => cancel.call(reply)).catch(() => void 0);
|
|
25664
|
+
}
|
|
25665
|
+
function failed2(reason) {
|
|
25666
|
+
const text = reason instanceof Error ? reason.message : String(reason);
|
|
25667
|
+
return new PlaceholderRefused(
|
|
25668
|
+
`refused: the request with a sealed placeholder was not completed: ${text}`
|
|
25669
|
+
);
|
|
25670
|
+
}
|
|
25671
|
+
var Stall = class {
|
|
25672
|
+
idle = new AbortController();
|
|
25673
|
+
ms;
|
|
25674
|
+
timer;
|
|
25675
|
+
signal;
|
|
25676
|
+
constructor(signals, ms) {
|
|
25677
|
+
this.ms = ms;
|
|
25678
|
+
this.signal = AbortSignal.any([...signals, this.idle.signal]);
|
|
25679
|
+
}
|
|
25680
|
+
arm() {
|
|
25681
|
+
clearTimeout(this.timer);
|
|
25682
|
+
this.timer = setTimeout(() => this.idle.abort("timeout"), this.ms);
|
|
25683
|
+
this.timer.unref?.();
|
|
25684
|
+
}
|
|
25685
|
+
touch() {
|
|
25686
|
+
if (this.timer !== void 0) this.arm();
|
|
25687
|
+
}
|
|
25688
|
+
rest() {
|
|
25689
|
+
clearTimeout(this.timer);
|
|
25690
|
+
this.timer = void 0;
|
|
25691
|
+
}
|
|
25692
|
+
};
|
|
25693
|
+
async function until(work, signal) {
|
|
25694
|
+
const stopped = Promise.withResolvers();
|
|
25695
|
+
const stop = () => stopped.reject(signal.reason);
|
|
25696
|
+
if (signal.aborted) stop();
|
|
25697
|
+
else signal.addEventListener("abort", stop, { once: true });
|
|
25698
|
+
try {
|
|
25699
|
+
return await Promise.race([work, stopped.promise]);
|
|
25700
|
+
} finally {
|
|
25701
|
+
signal.removeEventListener("abort", stop);
|
|
25702
|
+
}
|
|
25703
|
+
}
|
|
25704
|
+
async function* ticking(stream2, stall) {
|
|
25705
|
+
for await (const chunk2 of stream2) {
|
|
25706
|
+
stall.touch();
|
|
25707
|
+
yield chunk2;
|
|
25708
|
+
}
|
|
25709
|
+
}
|
|
25710
|
+
function sealedRequest(request, stamp, stall) {
|
|
25711
|
+
const { method, url, headers, body, bodyStream: bodyStream2 } = request;
|
|
25712
|
+
return {
|
|
25713
|
+
v: 1,
|
|
25714
|
+
caller: structuredClone(stamp),
|
|
25715
|
+
method,
|
|
25716
|
+
url,
|
|
25717
|
+
headers: headers.map(([name2, value2]) => [name2, value2]),
|
|
25718
|
+
redirect: "manual",
|
|
25719
|
+
...bodyStream2 ? { bodyStream: ticking(bodyStream2, stall) } : body ? { body } : {}
|
|
25720
|
+
};
|
|
25721
|
+
}
|
|
25722
|
+
function guarded2(reply, stall) {
|
|
25723
|
+
let finished = false;
|
|
25724
|
+
const cancel = async () => {
|
|
25725
|
+
stall.signal.removeEventListener("abort", dropped2);
|
|
25726
|
+
stall.rest();
|
|
25727
|
+
if (finished) return;
|
|
25728
|
+
finished = true;
|
|
25729
|
+
await reply.cancel().catch(() => void 0);
|
|
25730
|
+
};
|
|
25731
|
+
const dropped2 = () => void cancel();
|
|
25732
|
+
stall.signal.addEventListener("abort", dropped2, { once: true });
|
|
25733
|
+
const source = reply.body[Symbol.asyncIterator]();
|
|
25734
|
+
const body = (async function* () {
|
|
25735
|
+
try {
|
|
25736
|
+
for (; ; ) {
|
|
25737
|
+
stall.arm();
|
|
25738
|
+
const next3 = await until(source.next(), stall.signal);
|
|
25739
|
+
stall.rest();
|
|
25740
|
+
if (next3.done) {
|
|
25741
|
+
finished = true;
|
|
25742
|
+
return;
|
|
25743
|
+
}
|
|
25744
|
+
if (!(next3.value instanceof Uint8Array)) throw failed2("a body chunk is not bytes");
|
|
25745
|
+
if (next3.value.byteLength > 0) yield next3.value;
|
|
25746
|
+
}
|
|
25747
|
+
} finally {
|
|
25748
|
+
await cancel();
|
|
25749
|
+
}
|
|
25750
|
+
})();
|
|
25751
|
+
return {
|
|
25752
|
+
...reply.url !== void 0 ? { url: reply.url } : {},
|
|
25753
|
+
status: reply.status,
|
|
25754
|
+
statusText: reply.statusText,
|
|
25755
|
+
headers: reply.headers,
|
|
25756
|
+
body,
|
|
25757
|
+
cancel
|
|
25758
|
+
};
|
|
25759
|
+
}
|
|
25760
|
+
function sealedFetcher(hook, stop, idleMs = BODY_IDLE_MS) {
|
|
25761
|
+
return async (request, stamp) => {
|
|
25762
|
+
const stall = new Stall([request.signal, stop], idleMs);
|
|
25763
|
+
const { signal } = stall;
|
|
25764
|
+
if (signal.aborted) throw failed2(signal.reason);
|
|
25765
|
+
stall.arm();
|
|
25766
|
+
const asked = Promise.resolve().then(() => {
|
|
25767
|
+
signal.throwIfAborted();
|
|
25768
|
+
return hook(sealedRequest(request, stamp, stall), { signal });
|
|
25769
|
+
});
|
|
25770
|
+
let reply;
|
|
25771
|
+
try {
|
|
25772
|
+
reply = await until(asked, signal);
|
|
25773
|
+
} catch (e) {
|
|
25774
|
+
void asked.then(dropSealedReply, () => void 0);
|
|
25775
|
+
throw failed2(e);
|
|
25776
|
+
} finally {
|
|
25777
|
+
stall.rest();
|
|
25778
|
+
}
|
|
25779
|
+
if (sealedReplyValid(reply)) return guarded2(reply, stall);
|
|
25780
|
+
dropSealedReply(reply);
|
|
25781
|
+
throw failed2("the reply is not a scrubbed response");
|
|
25782
|
+
};
|
|
25783
|
+
}
|
|
25784
|
+
|
|
25359
25785
|
// src/kernel/package-swaps.ts
|
|
25360
25786
|
var SWAP_GAP_MS = 2e3;
|
|
25361
25787
|
var STAGES = ["_tmp_", "_pacquet-stage_"];
|
|
@@ -25528,11 +25954,11 @@ var PackageLocks = class {
|
|
|
25528
25954
|
if (!locks) return Promise.resolve(() => {
|
|
25529
25955
|
});
|
|
25530
25956
|
const { promise: held, resolve: release } = Promise.withResolvers();
|
|
25531
|
-
return new Promise((granted2,
|
|
25957
|
+
return new Promise((granted2, failed5) => {
|
|
25532
25958
|
locks.request(replacingLock(this.metadata, root), { mode: "exclusive" }, () => {
|
|
25533
25959
|
granted2(() => release());
|
|
25534
25960
|
return held;
|
|
25535
|
-
}).catch(
|
|
25961
|
+
}).catch(failed5);
|
|
25536
25962
|
});
|
|
25537
25963
|
}
|
|
25538
25964
|
};
|
|
@@ -25782,9 +26208,9 @@ function serveFilesystem(port, handlers, capabilities = {}, options = {}) {
|
|
|
25782
26208
|
let open = false;
|
|
25783
26209
|
const reply = (message3, transfer = []) => port.postMessage(message3, transfer);
|
|
25784
26210
|
async function hello(message3) {
|
|
25785
|
-
const
|
|
25786
|
-
if (
|
|
25787
|
-
reply({ hello: { protocol: DRIVER_PROTOCOL, error:
|
|
26211
|
+
const refused4 = driverVersionError(message3.protocol);
|
|
26212
|
+
if (refused4) {
|
|
26213
|
+
reply({ hello: { protocol: DRIVER_PROTOCOL, error: refused4, errno: "EPROTO" } });
|
|
25788
26214
|
return;
|
|
25789
26215
|
}
|
|
25790
26216
|
try {
|
|
@@ -25916,11 +26342,11 @@ var META_OPS = ["get", "update", "move", "remove", "links", "under", "all"];
|
|
|
25916
26342
|
var FILE_ID_TRIES = 3;
|
|
25917
26343
|
function sidecar(meta) {
|
|
25918
26344
|
const pathOf = ([first]) => [first, "/"].flat().find((p) => typeof p === "string");
|
|
25919
|
-
const
|
|
26345
|
+
const guarded4 = (op) => (...args) => meta[op].apply(meta, args).catch((err) => {
|
|
25920
26346
|
throw translate(err, pathOf(args), "sidecar", false);
|
|
25921
26347
|
});
|
|
25922
26348
|
const names2 = meta.fresh ? [...META_OPS, "fresh"] : META_OPS;
|
|
25923
|
-
const ops = Object.fromEntries(names2.map((op) => [op,
|
|
26349
|
+
const ops = Object.fromEntries(names2.map((op) => [op, guarded4(op)]));
|
|
25924
26350
|
const { updateMany } = meta;
|
|
25925
26351
|
ops.updateMany = updateMany ? (changes) => updateMany.call(meta, changes).catch((err) => {
|
|
25926
26352
|
throw translate(err, changes[0]?.path ?? "/", "sidecar", false);
|
|
@@ -25944,7 +26370,7 @@ function occupied(entry) {
|
|
|
25944
26370
|
function vacatedAt(path) {
|
|
25945
26371
|
return { path, ino: inodeOf(`${path}\0${crypto.randomUUID()}`), vacated: true };
|
|
25946
26372
|
}
|
|
25947
|
-
function
|
|
26373
|
+
function missing5(err) {
|
|
25948
26374
|
const code = err?.code;
|
|
25949
26375
|
return code === "ENOENT" || code === "ENOTDIR";
|
|
25950
26376
|
}
|
|
@@ -26187,7 +26613,7 @@ var OpfsFs = class {
|
|
|
26187
26613
|
if (there) return (await this.meta.get([found.path]))[0]?.fid ?? fid;
|
|
26188
26614
|
const gone = await this.locate(found.path, true).then(
|
|
26189
26615
|
() => false,
|
|
26190
|
-
(err) =>
|
|
26616
|
+
(err) => missing5(err)
|
|
26191
26617
|
);
|
|
26192
26618
|
if (gone) {
|
|
26193
26619
|
await this.meta.update(found.path, (now) => {
|
|
@@ -26630,7 +27056,7 @@ var OpfsFs = class {
|
|
|
26630
27056
|
try {
|
|
26631
27057
|
return await op();
|
|
26632
27058
|
} catch (err) {
|
|
26633
|
-
if (attempt >= REPLACED_ATTEMPTS || !
|
|
27059
|
+
if (attempt >= REPLACED_ATTEMPTS || !missing5(err)) throw err;
|
|
26634
27060
|
await this.replacing;
|
|
26635
27061
|
if (this.replacements === seen) throw err;
|
|
26636
27062
|
}
|
|
@@ -26642,7 +27068,7 @@ var OpfsFs = class {
|
|
|
26642
27068
|
try {
|
|
26643
27069
|
return { path: current, handle: await this.handle(current) };
|
|
26644
27070
|
} catch (err) {
|
|
26645
|
-
if (!
|
|
27071
|
+
if (!missing5(err)) throw err;
|
|
26646
27072
|
const link2 = await this.linkAlong(current);
|
|
26647
27073
|
if (!link2) throw err;
|
|
26648
27074
|
if (link2.path === current && !follow2) return { path: current, link: link2 };
|
|
@@ -26878,7 +27304,7 @@ var OpfsFs = class {
|
|
|
26878
27304
|
return this.locate(path, true).then(
|
|
26879
27305
|
() => true,
|
|
26880
27306
|
(err) => {
|
|
26881
|
-
if (
|
|
27307
|
+
if (missing5(err)) return false;
|
|
26882
27308
|
throw err;
|
|
26883
27309
|
}
|
|
26884
27310
|
);
|
|
@@ -27175,7 +27601,7 @@ var OpfsFs = class {
|
|
|
27175
27601
|
try {
|
|
27176
27602
|
return [(await this.locate(path, true)).path, true];
|
|
27177
27603
|
} catch (err) {
|
|
27178
|
-
if (!
|
|
27604
|
+
if (!missing5(err)) throw err;
|
|
27179
27605
|
}
|
|
27180
27606
|
const [entry] = await this.meta.get([path]);
|
|
27181
27607
|
const wanted = entry?.link === void 0 ? path : resolvePath(parentOf9(path), entry.link);
|
|
@@ -27267,7 +27693,7 @@ var OpfsFs = class {
|
|
|
27267
27693
|
try {
|
|
27268
27694
|
found = await this.exactly(() => this.locate(path, true));
|
|
27269
27695
|
} catch (err) {
|
|
27270
|
-
if (!
|
|
27696
|
+
if (!missing5(err)) throw err;
|
|
27271
27697
|
}
|
|
27272
27698
|
if (found) {
|
|
27273
27699
|
const directory = found.handle?.kind === "directory";
|
|
@@ -27403,7 +27829,7 @@ var OpfsFs = class {
|
|
|
27403
27829
|
const taken = await this.exactly(() => this.lstat(to)).then(
|
|
27404
27830
|
() => true,
|
|
27405
27831
|
(err) => {
|
|
27406
|
-
if (
|
|
27832
|
+
if (missing5(err)) return false;
|
|
27407
27833
|
throw err;
|
|
27408
27834
|
}
|
|
27409
27835
|
);
|
|
@@ -27435,7 +27861,7 @@ var OpfsFs = class {
|
|
|
27435
27861
|
const sourceStat = await this.describe(source);
|
|
27436
27862
|
if (sourceStat.isDirectory && within9(destination, source.path)) throw fsError("EINVAL", to);
|
|
27437
27863
|
const target = await this.exactly(() => this.locate(destination, false)).catch((err) => {
|
|
27438
|
-
if (
|
|
27864
|
+
if (missing5(err)) return null;
|
|
27439
27865
|
throw err;
|
|
27440
27866
|
});
|
|
27441
27867
|
const targetStat = target && await this.describe(target);
|
|
@@ -28026,12 +28452,12 @@ var OpfsFs = class {
|
|
|
28026
28452
|
if (!move) return false;
|
|
28027
28453
|
for (let attempt = 0; ; attempt++) {
|
|
28028
28454
|
this.others++;
|
|
28029
|
-
const
|
|
28455
|
+
const failed5 = await move.call(handle, dir, name2).then(
|
|
28030
28456
|
() => void 0,
|
|
28031
28457
|
(err) => ({ err })
|
|
28032
28458
|
);
|
|
28033
|
-
if (!
|
|
28034
|
-
const error =
|
|
28459
|
+
if (!failed5) return true;
|
|
28460
|
+
const error = failed5.err?.name;
|
|
28035
28461
|
if (handle.kind !== "file" || !LOCKED.has(error)) return false;
|
|
28036
28462
|
const delay2 = SYNC_BACKOFF_MS[attempt];
|
|
28037
28463
|
if (delay2 === void 0) throw fsError("EBUSY", name2);
|
|
@@ -28072,7 +28498,7 @@ var OpfsFs = class {
|
|
|
28072
28498
|
this.refuse(at);
|
|
28073
28499
|
if (await this.exactly(() => this.locate(at, false)).then(
|
|
28074
28500
|
() => true,
|
|
28075
|
-
(err) => !
|
|
28501
|
+
(err) => !missing5(err)
|
|
28076
28502
|
)) {
|
|
28077
28503
|
throw fsError("EEXIST", path);
|
|
28078
28504
|
}
|
|
@@ -28594,22 +29020,22 @@ async function mountFstab(lines2, mount, signal, retries = FSTAB_RETRIES, discar
|
|
|
28594
29020
|
);
|
|
28595
29021
|
}
|
|
28596
29022
|
async function mountLine({ line, spec, invalid }, mount, signal, retries, discard) {
|
|
28597
|
-
let
|
|
29023
|
+
let failed5 = invalid;
|
|
28598
29024
|
for (let attempt = 0; !invalid && attempt <= retries.length && !signal.aborted; attempt++) {
|
|
28599
29025
|
try {
|
|
28600
29026
|
const entry = await mount(spec);
|
|
28601
29027
|
if (!signal.aborted) return { line, target: spec.target, entry };
|
|
28602
29028
|
discard(entry);
|
|
28603
|
-
|
|
29029
|
+
failed5 = Object.assign(new Error("the kernel stopped"), { code: "ECANCELED" });
|
|
28604
29030
|
break;
|
|
28605
29031
|
} catch (err) {
|
|
28606
|
-
|
|
29032
|
+
failed5 = err;
|
|
28607
29033
|
if (FINAL.has(codeOf6(err)) || attempt === retries.length) break;
|
|
28608
29034
|
await wait(retries[attempt], signal);
|
|
28609
29035
|
}
|
|
28610
29036
|
}
|
|
28611
|
-
const code = codeOf6(
|
|
28612
|
-
return { line, target: spec.target, code, error: String(
|
|
29037
|
+
const code = codeOf6(failed5);
|
|
29038
|
+
return { line, target: spec.target, code, error: String(failed5?.message ?? code) };
|
|
28613
29039
|
}
|
|
28614
29040
|
|
|
28615
29041
|
// src/mount/hostfs.ts
|
|
@@ -30211,7 +30637,7 @@ var RULE = new RegExp(
|
|
|
30211
30637
|
var TERM = /^[A-Za-z0-9._+-]+$/;
|
|
30212
30638
|
var PLAIN3 = /^[A-Za-z0-9_@%+=:,./-]+$/;
|
|
30213
30639
|
var USAGE = "usage: sudo [-n] [-u user] [--] command [args...]\n sudo -l";
|
|
30214
|
-
function
|
|
30640
|
+
function failed3(errno3, error) {
|
|
30215
30641
|
return { error, errno: errno3 };
|
|
30216
30642
|
}
|
|
30217
30643
|
function unescaped(double) {
|
|
@@ -30390,10 +30816,10 @@ var Sudo = class {
|
|
|
30390
30816
|
}
|
|
30391
30817
|
async untrusted(path, cwd, word) {
|
|
30392
30818
|
const files = this.o.backing ? await this.o.backing(path, cwd) : [];
|
|
30393
|
-
if (!files) return
|
|
30819
|
+
if (!files) return failed3("ENOENT", `sudo: ${word}: command not found`);
|
|
30394
30820
|
for (const file of [path, ...files]) {
|
|
30395
30821
|
if (!await this.trusted(file)) {
|
|
30396
|
-
return
|
|
30822
|
+
return failed3("EPERM", `sudo: ${file} must be root's, and writable by root only`);
|
|
30397
30823
|
}
|
|
30398
30824
|
}
|
|
30399
30825
|
return void 0;
|
|
@@ -30410,7 +30836,7 @@ var Sudo = class {
|
|
|
30410
30836
|
}
|
|
30411
30837
|
async request(caller, call, signal) {
|
|
30412
30838
|
const parsed2 = parseArgs(call.args);
|
|
30413
|
-
if (typeof parsed2 === "string") return
|
|
30839
|
+
if (typeof parsed2 === "string") return failed3("EINVAL", parsed2);
|
|
30414
30840
|
if (this.o.mode !== "enforce") {
|
|
30415
30841
|
const mode = this.o.mode;
|
|
30416
30842
|
if (parsed2.list) return { list: `sudo: users are '${mode}': commands run as the caller
|
|
@@ -30419,9 +30845,9 @@ var Sudo = class {
|
|
|
30419
30845
|
}
|
|
30420
30846
|
const { cred } = caller;
|
|
30421
30847
|
const self = await this.o.users.lookup(cred.ruid);
|
|
30422
|
-
if (!self) return
|
|
30848
|
+
if (!self) return failed3("EPERM", `sudo: uid ${cred.ruid} is not in the passwd database`);
|
|
30423
30849
|
const target = await this.lookup(parsed2.user);
|
|
30424
|
-
if (!target) return
|
|
30850
|
+
if (!target) return failed3("ENOENT", `sudo: unknown user ${parsed2.user}`);
|
|
30425
30851
|
const root = cred.euid === 0;
|
|
30426
30852
|
const rules = root ? [] : await this.policy();
|
|
30427
30853
|
const applies = await this.applies(self, cred);
|
|
@@ -30429,13 +30855,13 @@ var Sudo = class {
|
|
|
30429
30855
|
const [word = "", ...args] = parsed2.command;
|
|
30430
30856
|
const cwd = await this.canonical(call.cwd);
|
|
30431
30857
|
if (cwd === void 0 || !await this.reachable(cred, cwd)) {
|
|
30432
|
-
return
|
|
30858
|
+
return failed3(
|
|
30433
30859
|
"EACCES",
|
|
30434
30860
|
`sudo: cannot run in ${call.cwd}: it isn't a directory you can enter`
|
|
30435
30861
|
);
|
|
30436
30862
|
}
|
|
30437
30863
|
const path = await this.locate(word, cwd);
|
|
30438
|
-
if (!path) return
|
|
30864
|
+
if (!path) return failed3("ENOENT", `sudo: ${word}: command not found`);
|
|
30439
30865
|
const untrusted2 = await this.untrusted(path, cwd, word);
|
|
30440
30866
|
if (untrusted2) return untrusted2;
|
|
30441
30867
|
const argv = [path, ...args];
|
|
@@ -30446,24 +30872,24 @@ var Sudo = class {
|
|
|
30446
30872
|
if (root || matching.some((rule) => rule.nopasswd)) return grant();
|
|
30447
30873
|
const quoted = argv.map(quoteWord).join(" ");
|
|
30448
30874
|
if (matching.length === 0) {
|
|
30449
|
-
return
|
|
30875
|
+
return failed3(
|
|
30450
30876
|
"EPERM",
|
|
30451
30877
|
`sudo: ${self.name} is not allowed to run ${quoted} as ${target.name}`
|
|
30452
30878
|
);
|
|
30453
30879
|
}
|
|
30454
|
-
if (parsed2.nonInteractive) return
|
|
30455
|
-
if (this.pending.has(cred.ruid)) return
|
|
30880
|
+
if (parsed2.nonInteractive) return failed3("EPERM", "sudo: a password is required");
|
|
30881
|
+
if (this.pending.has(cred.ruid)) return failed3("EBUSY", "sudo: another request is pending");
|
|
30456
30882
|
this.pending.add(cred.ruid);
|
|
30457
30883
|
try {
|
|
30458
30884
|
const answer2 = await this.ask(caller, self, target, parsed2.command, path, cwd, signal);
|
|
30459
30885
|
if (typeof answer2 !== "string") return answer2;
|
|
30460
30886
|
if (await this.canonical(call.cwd) !== cwd || !await this.reachable(cred, cwd)) {
|
|
30461
|
-
return
|
|
30887
|
+
return failed3("EACCES", `sudo: ${call.cwd} changed while the request waited`);
|
|
30462
30888
|
}
|
|
30463
30889
|
const changed = await this.untrusted(path, cwd, word);
|
|
30464
30890
|
if (changed) return changed;
|
|
30465
30891
|
if (answer2 === "always" && !await this.remember(self, target, cwd, argv)) {
|
|
30466
|
-
return
|
|
30892
|
+
return failed3("EIO", "sudo: the rule could not be recorded");
|
|
30467
30893
|
}
|
|
30468
30894
|
return grant();
|
|
30469
30895
|
} finally {
|
|
@@ -30480,7 +30906,7 @@ var Sudo = class {
|
|
|
30480
30906
|
};
|
|
30481
30907
|
}
|
|
30482
30908
|
if (rules.length === 0) {
|
|
30483
|
-
return
|
|
30909
|
+
return failed3("EPERM", `User ${self.name} is not allowed to run sudo on ${host}.`);
|
|
30484
30910
|
}
|
|
30485
30911
|
const lines2 = rules.map(described).join("\n");
|
|
30486
30912
|
return { list: `User ${self.name} may run the following commands on ${host}:
|
|
@@ -30489,7 +30915,7 @@ ${lines2}
|
|
|
30489
30915
|
}
|
|
30490
30916
|
async ask(caller, self, target, argv, path, cwd, requester) {
|
|
30491
30917
|
const { approve } = this.o;
|
|
30492
|
-
if (!approve || requester.aborted) return
|
|
30918
|
+
if (!approve || requester.aborted) return failed3("EACCES", "sudo: approval denied");
|
|
30493
30919
|
const createdAt = Date.now();
|
|
30494
30920
|
const timeout = this.o.timeoutMs ?? SUDO_TIMEOUT_MS;
|
|
30495
30921
|
const req = {
|
|
@@ -30519,9 +30945,9 @@ ${lines2}
|
|
|
30519
30945
|
const answered = Promise.resolve().then(() => approve(req, { signal: control.signal })).catch(() => "deny");
|
|
30520
30946
|
const answer2 = await Promise.race([answered, aborted3]);
|
|
30521
30947
|
if (answer2 === "aborted" || control.signal.aborted) {
|
|
30522
|
-
return control.signal.reason === "expired" ?
|
|
30948
|
+
return control.signal.reason === "expired" ? failed3("ETIMEDOUT", "sudo: the request expired") : failed3("EINTR", "sudo: the request was withdrawn");
|
|
30523
30949
|
}
|
|
30524
|
-
return answer2 === "once" || answer2 === "always" ? answer2 :
|
|
30950
|
+
return answer2 === "once" || answer2 === "always" ? answer2 : failed3("EACCES", "sudo: approval denied");
|
|
30525
30951
|
} finally {
|
|
30526
30952
|
clearTimeout(timer);
|
|
30527
30953
|
requester.removeEventListener("abort", withdraw);
|
|
@@ -30808,13 +31234,13 @@ function interpreter(head) {
|
|
|
30808
31234
|
function expandDefaults(defaults2, env) {
|
|
30809
31235
|
const out = {};
|
|
30810
31236
|
for (const [key, value2] of Object.entries(defaults2 ?? {})) {
|
|
30811
|
-
let
|
|
31237
|
+
let missing6 = false;
|
|
30812
31238
|
const expanded = value2.replace(ENV_REFERENCE, (_, name2) => {
|
|
30813
31239
|
const set3 = Object.hasOwn(env, name2) ? env[name2] : void 0;
|
|
30814
|
-
if (set3 === void 0)
|
|
31240
|
+
if (set3 === void 0) missing6 = true;
|
|
30815
31241
|
return set3 ?? "";
|
|
30816
31242
|
});
|
|
30817
|
-
if (!
|
|
31243
|
+
if (!missing6) out[key] = expanded;
|
|
30818
31244
|
}
|
|
30819
31245
|
return out;
|
|
30820
31246
|
}
|
|
@@ -30989,6 +31415,9 @@ var Launcher = class {
|
|
|
30989
31415
|
usersMode;
|
|
30990
31416
|
dac;
|
|
30991
31417
|
sealed;
|
|
31418
|
+
fill;
|
|
31419
|
+
fills = new AbortController();
|
|
31420
|
+
placeholders = [];
|
|
30992
31421
|
scrubs = /* @__PURE__ */ new Map();
|
|
30993
31422
|
clipboard;
|
|
30994
31423
|
embedder;
|
|
@@ -31070,7 +31499,7 @@ var Launcher = class {
|
|
|
31070
31499
|
...options.env
|
|
31071
31500
|
};
|
|
31072
31501
|
this.ca = kernelCa(options.caStore ?? memoryCaStore());
|
|
31073
|
-
this.transport =
|
|
31502
|
+
this.transport = this.floored(options);
|
|
31074
31503
|
this.announcedTraits = JSON.stringify(this.transport.traits);
|
|
31075
31504
|
this.uplink = options.uplink;
|
|
31076
31505
|
this.routes = new Routes(options.uplink?.traits.ipv6 === true);
|
|
@@ -31225,16 +31654,16 @@ var Launcher = class {
|
|
|
31225
31654
|
if (!found) {
|
|
31226
31655
|
found = this.swaps.settled().then(() => this.trustedAppended()).then(async (appended2) => {
|
|
31227
31656
|
const tiers = await this.tiers(scope, appended2);
|
|
31228
|
-
const
|
|
31657
|
+
const refused4 = [];
|
|
31229
31658
|
const commands = await scanCommands(
|
|
31230
31659
|
this.scanned,
|
|
31231
31660
|
tiers,
|
|
31232
31661
|
tiers.length - appended2.length,
|
|
31233
31662
|
void 0,
|
|
31234
|
-
|
|
31663
|
+
refused4,
|
|
31235
31664
|
await this.globalRoots(scope)
|
|
31236
31665
|
);
|
|
31237
|
-
this.refusedOf.set(commands,
|
|
31666
|
+
this.refusedOf.set(commands, refused4.map(refusing));
|
|
31238
31667
|
return commands;
|
|
31239
31668
|
}).then(
|
|
31240
31669
|
(commands) => this.refusals(commands).set(SUDO_COMMAND.name, SUDO_COMMAND).set(CRONTAB_COMMAND.name, CRONTAB_COMMAND)
|
|
@@ -31440,14 +31869,14 @@ var Launcher = class {
|
|
|
31440
31869
|
return await this.commandAt(path, scope) ?? await this.refusedAt(path, name2, scope);
|
|
31441
31870
|
}
|
|
31442
31871
|
async refusedAt(path, name2, scope) {
|
|
31443
|
-
const
|
|
31444
|
-
if (
|
|
31872
|
+
const refused4 = this.refusedOf.get(await this.commands(scope)) ?? [];
|
|
31873
|
+
if (refused4.length === 0) return void 0;
|
|
31445
31874
|
const st = await this.base.stat(path).catch(() => void 0);
|
|
31446
31875
|
if (!st?.isFile) return void 0;
|
|
31447
31876
|
const real = await physicalPathAsync(this.base, path).catch(() => path);
|
|
31448
31877
|
const same2 = async (own) => own === path || await physicalPathAsync(this.base, own).catch(() => own) === real;
|
|
31449
31878
|
const owners = [];
|
|
31450
|
-
for (const c of
|
|
31879
|
+
for (const c of refused4) {
|
|
31451
31880
|
const origin = c.origin;
|
|
31452
31881
|
for (const own of [origin.glue, origin.wasm, ...origin.variants ?? []]) {
|
|
31453
31882
|
if (!await same2(own)) continue;
|
|
@@ -31457,11 +31886,11 @@ var Launcher = class {
|
|
|
31457
31886
|
}
|
|
31458
31887
|
const stem = name2.replace(/\.wasm$/, "");
|
|
31459
31888
|
const named = owners.find((c) => c.name === name2) ?? owners.find((c) => c.name === stem);
|
|
31460
|
-
return named ?? owners[0] ?? await this.refusedCopy(real, name2,
|
|
31889
|
+
return named ?? owners[0] ?? await this.refusedCopy(real, name2, refused4);
|
|
31461
31890
|
}
|
|
31462
|
-
async refusedCopy(real, name2,
|
|
31891
|
+
async refusedCopy(real, name2, refused4) {
|
|
31463
31892
|
const dir = real.slice(0, real.lastIndexOf("/"));
|
|
31464
|
-
for (const c of
|
|
31893
|
+
for (const c of refused4) {
|
|
31465
31894
|
const origin = c.origin;
|
|
31466
31895
|
if (origin.abi !== "emscripten" || origin.script || c.name !== name2) continue;
|
|
31467
31896
|
const own = await physicalPathAsync(this.base, origin.glue).catch(() => origin.glue);
|
|
@@ -31669,12 +32098,12 @@ var Launcher = class {
|
|
|
31669
32098
|
return void 0;
|
|
31670
32099
|
}
|
|
31671
32100
|
async planOne(req, { ppid, cred, scope }, catalogOnly = false) {
|
|
31672
|
-
const
|
|
32101
|
+
const refused4 = (err) => {
|
|
31673
32102
|
throw codeOf8(err) === "EACCES" ? new SpawnError("EACCES") : err;
|
|
31674
32103
|
};
|
|
31675
|
-
const file = await this.execFile(req.file, req.cwd, this.execGuard(cred, ppid)).catch(
|
|
32104
|
+
const file = await this.execFile(req.file, req.cwd, this.execGuard(cred, ppid)).catch(refused4);
|
|
31676
32105
|
const planned = await this.plan(file, req.argv, req.cwd, scope, req.argv0, catalogOnly);
|
|
31677
|
-
await this.mayExec(cred, { ...req, file, pid: ppid }, planned).catch(
|
|
32106
|
+
await this.mayExec(cred, { ...req, file, pid: ppid }, planned).catch(refused4);
|
|
31678
32107
|
if (planned) return planned;
|
|
31679
32108
|
throw new SpawnError(catalogOnly ? "ENOENT" : await this.unrunnable(file, req.cwd, scope));
|
|
31680
32109
|
}
|
|
@@ -32132,6 +32561,19 @@ var Launcher = class {
|
|
|
32132
32561
|
groupSession(pgid) {
|
|
32133
32562
|
return this.jobs.sessionOf(pgid);
|
|
32134
32563
|
}
|
|
32564
|
+
floored(options) {
|
|
32565
|
+
const { sealedFetch } = options;
|
|
32566
|
+
this.fill = sealedFetch && this.usersMode === "enforce" ? sealedFetcher(sealedFetch, this.fills.signal) : void 0;
|
|
32567
|
+
if (this.fill) this.net.stampProxy(REALM_PROXY_PORT);
|
|
32568
|
+
return placeholderFloor(replayingHops(options.transport ?? missingTransport()), {
|
|
32569
|
+
known: () => this.placeholders,
|
|
32570
|
+
...this.fill ? { fill: this.fill } : {}
|
|
32571
|
+
});
|
|
32572
|
+
}
|
|
32573
|
+
httpFor(pid) {
|
|
32574
|
+
const stamp = this.fill ? () => this.liveStamp(pid) : void 0;
|
|
32575
|
+
return new HttpHandles(this.transport, pid, this.loopbackFor(pid), stamp);
|
|
32576
|
+
}
|
|
32135
32577
|
loopbackFor(pid) {
|
|
32136
32578
|
return new KernelLoopback(
|
|
32137
32579
|
this.net,
|
|
@@ -32139,7 +32581,7 @@ var Launcher = class {
|
|
|
32139
32581
|
const cred = this.credOf(pid);
|
|
32140
32582
|
return { pid, uid: cred.euid, gid: cred.egid };
|
|
32141
32583
|
},
|
|
32142
|
-
() => this.
|
|
32584
|
+
() => this.liveStamp(pid)
|
|
32143
32585
|
);
|
|
32144
32586
|
}
|
|
32145
32587
|
sourceCheck(pid, writer) {
|
|
@@ -32304,7 +32746,7 @@ var Launcher = class {
|
|
|
32304
32746
|
jobs: this.jobs,
|
|
32305
32747
|
ptys: this.ptys,
|
|
32306
32748
|
net: this.net,
|
|
32307
|
-
http:
|
|
32749
|
+
http: this.httpFor(pid),
|
|
32308
32750
|
locks: this.locks,
|
|
32309
32751
|
fifos: this.fifos,
|
|
32310
32752
|
sems: this.sems,
|
|
@@ -32619,6 +33061,19 @@ var Launcher = class {
|
|
|
32619
33061
|
connectorStamp(pid) {
|
|
32620
33062
|
return this.sealed.stamp(this.identityOf(pid), this.credOf(pid), this.tagsOf(pid));
|
|
32621
33063
|
}
|
|
33064
|
+
async liveStamp(pid) {
|
|
33065
|
+
if (!this.creds.has(pid) || this.zombies.has(pid)) return void 0;
|
|
33066
|
+
return this.connectorStamp(pid);
|
|
33067
|
+
}
|
|
33068
|
+
setPlaceholders(list) {
|
|
33069
|
+
if (!Array.isArray(list) || !list.every((p) => typeof p === "string" && p !== "")) {
|
|
33070
|
+
throw fsError("EINVAL", "setPlaceholders takes a list of non-empty strings");
|
|
33071
|
+
}
|
|
33072
|
+
this.placeholders = [...list];
|
|
33073
|
+
}
|
|
33074
|
+
endFills() {
|
|
33075
|
+
this.fills.abort("terminated");
|
|
33076
|
+
}
|
|
32622
33077
|
identityOf(pid) {
|
|
32623
33078
|
const parent = this.jobs.shownParent(pid);
|
|
32624
33079
|
const alive = parent !== void 0 && this.running(parent);
|
|
@@ -32741,7 +33196,7 @@ var Launcher = class {
|
|
|
32741
33196
|
const at = normalizePath(path);
|
|
32742
33197
|
this.unlinked.closed(at);
|
|
32743
33198
|
this.writers?.unlinked.closed(at);
|
|
32744
|
-
const holding = [...this.held].some((
|
|
33199
|
+
const holding = [...this.held].some((holds3) => holds3.holding(at)) || [...this.openFiles].some((open2) => open2.holdsAt(at));
|
|
32745
33200
|
if (!holding) void this.rootFs.announceHolds?.([], [at], false);
|
|
32746
33201
|
const open = [...this.openFiles].some((nodes) => nodes.writes(at)) || heldUnder(this.held, at);
|
|
32747
33202
|
if (!open) void this.mounts.commit(at).catch(() => void 0);
|
|
@@ -32904,8 +33359,9 @@ var Launcher = class {
|
|
|
32904
33359
|
for (const root of roots) this.integrity.forget(root);
|
|
32905
33360
|
this.resetCatalogs();
|
|
32906
33361
|
}
|
|
32907
|
-
attest(path) {
|
|
33362
|
+
attest(path, options = {}) {
|
|
32908
33363
|
return attest(this.rootFs, path, {
|
|
33364
|
+
...options,
|
|
32909
33365
|
users: this.usersMode,
|
|
32910
33366
|
mounts: this.mounts.list().map((entry) => entry.target).filter((target) => this.mounts.mounted(target) !== void 0)
|
|
32911
33367
|
});
|
|
@@ -32962,8 +33418,8 @@ var Launcher = class {
|
|
|
32962
33418
|
for (const name2 of names2 ?? []) {
|
|
32963
33419
|
const path = joinName(real, name2);
|
|
32964
33420
|
if (await this.base.hasOwner(path)) continue;
|
|
32965
|
-
const
|
|
32966
|
-
if (
|
|
33421
|
+
const failed5 = this.inUse(path) ? "busy" : await this.base.rm(path, { recursive: true, force: true }).catch(String);
|
|
33422
|
+
if (failed5 === void 0) removed++;
|
|
32967
33423
|
else left++;
|
|
32968
33424
|
}
|
|
32969
33425
|
if (removed > 0) {
|
|
@@ -33058,7 +33514,7 @@ var Launcher = class {
|
|
|
33058
33514
|
this.pnpmStale();
|
|
33059
33515
|
if (!detach) return;
|
|
33060
33516
|
for (const nodes of this.openFiles) nodes.revoke(at);
|
|
33061
|
-
for (const
|
|
33517
|
+
for (const holds3 of this.held) holds3.revoke(at);
|
|
33062
33518
|
}
|
|
33063
33519
|
unmountAll() {
|
|
33064
33520
|
this.cron.stop();
|
|
@@ -33269,9 +33725,9 @@ var Launcher = class {
|
|
|
33269
33725
|
}
|
|
33270
33726
|
boundTo(path, hidden, fids) {
|
|
33271
33727
|
const keeping = [...this.held].map(
|
|
33272
|
-
(
|
|
33273
|
-
|
|
33274
|
-
fids.flatMap((fid) => [...
|
|
33728
|
+
(holds3) => [
|
|
33729
|
+
holds3,
|
|
33730
|
+
fids.flatMap((fid) => [...holds3.boundAt(path, fid), ...holds3.boundAt(hidden, fid)])
|
|
33275
33731
|
]
|
|
33276
33732
|
).filter(([, ids]) => ids.length > 0);
|
|
33277
33733
|
const nodes = [...this.openFiles].filter(
|
|
@@ -33282,7 +33738,7 @@ var Launcher = class {
|
|
|
33282
33738
|
(open) => fids.some((fid) => open.keepBound([hidden, path], fid, file))
|
|
33283
33739
|
).length;
|
|
33284
33740
|
for (let i = kept; i < nodes.length; i++) file.release();
|
|
33285
|
-
for (const [
|
|
33741
|
+
for (const [holds3, ids] of keeping) holds3.keepBound(ids, path, file);
|
|
33286
33742
|
void this.rootFs.announceHolds?.([], [path, hidden], false);
|
|
33287
33743
|
};
|
|
33288
33744
|
return { keeping, nodes, keep: keep2 };
|
|
@@ -33442,7 +33898,7 @@ var Launcher = class {
|
|
|
33442
33898
|
}
|
|
33443
33899
|
moved(from, to, source) {
|
|
33444
33900
|
this.renameLog.add(from, to);
|
|
33445
|
-
for (const
|
|
33901
|
+
for (const holds3 of this.held) holds3.renamed(from, to);
|
|
33446
33902
|
if (source) return;
|
|
33447
33903
|
for (const nodes of this.openFiles) nodes.renamed(from, to);
|
|
33448
33904
|
this.watchers.moved(from, to);
|
|
@@ -33587,26 +34043,6 @@ function codeOf8(err) {
|
|
|
33587
34043
|
return err?.code;
|
|
33588
34044
|
}
|
|
33589
34045
|
|
|
33590
|
-
// src/body-idle.ts
|
|
33591
|
-
var BODY_IDLE_MS = 5 * 60 * 1e3;
|
|
33592
|
-
function idleFailure(ms) {
|
|
33593
|
-
return Object.assign(new Error(`the response body sent no data for ${ms} ms`), {
|
|
33594
|
-
code: "ETIMEDOUT"
|
|
33595
|
-
});
|
|
33596
|
-
}
|
|
33597
|
-
async function readWithin(reader, ms) {
|
|
33598
|
-
if (!(ms > 0 && ms < Number.POSITIVE_INFINITY)) return reader.read();
|
|
33599
|
-
let timer;
|
|
33600
|
-
const idle2 = new Promise((_, reject) => {
|
|
33601
|
-
timer = setTimeout(() => reject(idleFailure(ms)), ms);
|
|
33602
|
-
});
|
|
33603
|
-
try {
|
|
33604
|
-
return await Promise.race([reader.read(), idle2]);
|
|
33605
|
-
} finally {
|
|
33606
|
-
clearTimeout(timer);
|
|
33607
|
-
}
|
|
33608
|
-
}
|
|
33609
|
-
|
|
33610
34046
|
// src/websocket-transport.ts
|
|
33611
34047
|
var SENT_HEADERS_DROP = /* @__PURE__ */ new Set([
|
|
33612
34048
|
"host",
|
|
@@ -33756,10 +34192,11 @@ function fetchTransport(options = {}) {
|
|
|
33756
34192
|
const send2 = options.fetch ?? globalThis.fetch.bind(globalThis);
|
|
33757
34193
|
const Socket = options.webSocket === true ? globalThis.WebSocket : options.webSocket || void 0;
|
|
33758
34194
|
const headers = options.webSocketHeaders === true;
|
|
33759
|
-
const
|
|
34195
|
+
const instance = options.redirect ?? "follow";
|
|
33760
34196
|
return {
|
|
33761
34197
|
traits: {
|
|
33762
|
-
manualRedirects:
|
|
34198
|
+
manualRedirects: instance === "manual",
|
|
34199
|
+
redirectPolicy: true,
|
|
33763
34200
|
encodedBodies: false,
|
|
33764
34201
|
maxRequestBody: options.maxRequestBody ?? MAX_REQUEST_BODY,
|
|
33765
34202
|
crossOrigin: "cors",
|
|
@@ -33775,7 +34212,7 @@ function fetchTransport(options = {}) {
|
|
|
33775
34212
|
headers: joinHeaders(request.headers),
|
|
33776
34213
|
...requestBody(request),
|
|
33777
34214
|
signal: request.signal,
|
|
33778
|
-
redirect,
|
|
34215
|
+
redirect: request.redirect ?? instance,
|
|
33779
34216
|
credentials: "omit",
|
|
33780
34217
|
mode: "cors"
|
|
33781
34218
|
});
|
|
@@ -33799,6 +34236,7 @@ function fetchTransport(options = {}) {
|
|
|
33799
34236
|
const body = chunks(response.body, options.bodyIdleMs ?? BODY_IDLE_MS);
|
|
33800
34237
|
return {
|
|
33801
34238
|
...response.redirected ? { url: response.url, redirected: true } : {},
|
|
34239
|
+
...response.type === "opaqueredirect" ? { opaqueRedirect: true } : {},
|
|
33802
34240
|
status: response.status,
|
|
33803
34241
|
statusText: response.statusText,
|
|
33804
34242
|
headers: headers2,
|
|
@@ -33834,7 +34272,34 @@ function uploadsFor(peer) {
|
|
|
33834
34272
|
});
|
|
33835
34273
|
return { of, answer: (call) => pulls.get(call.nid)?.(call) };
|
|
33836
34274
|
}
|
|
33837
|
-
function
|
|
34275
|
+
function headOf(nid, response) {
|
|
34276
|
+
return {
|
|
34277
|
+
net: "head",
|
|
34278
|
+
nid,
|
|
34279
|
+
...response.url !== void 0 ? { url: response.url } : {},
|
|
34280
|
+
...response.redirected !== void 0 ? { redirected: response.redirected } : {},
|
|
34281
|
+
...response.redirects ? { redirects: response.redirects } : {},
|
|
34282
|
+
...response.opaqueRedirect ? { opaqueRedirect: true } : {},
|
|
34283
|
+
status: response.status,
|
|
34284
|
+
statusText: response.statusText,
|
|
34285
|
+
headers: response.headers
|
|
34286
|
+
};
|
|
34287
|
+
}
|
|
34288
|
+
function requestOf(call, signal, uploads) {
|
|
34289
|
+
const { url, method, headers, streamed, body, redirect, nid } = call;
|
|
34290
|
+
return {
|
|
34291
|
+
url,
|
|
34292
|
+
method,
|
|
34293
|
+
headers,
|
|
34294
|
+
...streamed ? { bodyStream: uploads.of(nid, signal) } : body ? { body } : {},
|
|
34295
|
+
...redirect !== void 0 ? { redirect } : {},
|
|
34296
|
+
signal
|
|
34297
|
+
};
|
|
34298
|
+
}
|
|
34299
|
+
function serveTransport(peer, transport, {
|
|
34300
|
+
closeWaitMs = CLOSE_WAIT_MS3,
|
|
34301
|
+
attributed = false
|
|
34302
|
+
} = {}) {
|
|
33838
34303
|
const open = /* @__PURE__ */ new Map();
|
|
33839
34304
|
const fail3 = (nid, e) => {
|
|
33840
34305
|
open.delete(nid);
|
|
@@ -33854,27 +34319,17 @@ function serveTransport(peer, transport, { closeWaitMs = CLOSE_WAIT_MS3 } = {})
|
|
|
33854
34319
|
const entry = { abort };
|
|
33855
34320
|
open.set(call.nid, entry);
|
|
33856
34321
|
try {
|
|
33857
|
-
const response = await transport.fetch(
|
|
33858
|
-
|
|
33859
|
-
|
|
33860
|
-
|
|
33861
|
-
|
|
33862
|
-
signal: abort.signal
|
|
33863
|
-
});
|
|
34322
|
+
const response = await transport.fetch(
|
|
34323
|
+
requestOf(call, abort.signal, uploads),
|
|
34324
|
+
attributed ? call.owner : void 0,
|
|
34325
|
+
attributed ? call.stamp : void 0
|
|
34326
|
+
);
|
|
33864
34327
|
if (!open.has(call.nid)) {
|
|
33865
34328
|
await response.cancel();
|
|
33866
34329
|
return;
|
|
33867
34330
|
}
|
|
33868
34331
|
open.set(call.nid, { abort, body: response.body[Symbol.asyncIterator](), response });
|
|
33869
|
-
peer.postMessage(
|
|
33870
|
-
net: "head",
|
|
33871
|
-
nid: call.nid,
|
|
33872
|
-
...response.redirected ? { url: response.url, redirected: true } : {},
|
|
33873
|
-
...response.redirects ? { redirects: response.redirects } : {},
|
|
33874
|
-
status: response.status,
|
|
33875
|
-
statusText: response.statusText,
|
|
33876
|
-
headers: response.headers
|
|
33877
|
-
});
|
|
34332
|
+
peer.postMessage(headOf(call.nid, response));
|
|
33878
34333
|
} catch (e) {
|
|
33879
34334
|
fail3(call.nid, e);
|
|
33880
34335
|
}
|
|
@@ -34374,9 +34829,9 @@ function serveClient(port, host) {
|
|
|
34374
34829
|
ended.resolve();
|
|
34375
34830
|
}
|
|
34376
34831
|
async function hello(message3) {
|
|
34377
|
-
const
|
|
34378
|
-
if (
|
|
34379
|
-
send2({ hello: { protocol: PROTOCOL, error:
|
|
34832
|
+
const refused4 = versionError(message3.protocol) ?? await hosts.requests.accept(host, message3);
|
|
34833
|
+
if (refused4) {
|
|
34834
|
+
send2({ hello: { protocol: PROTOCOL, error: refused4 } });
|
|
34380
34835
|
detach();
|
|
34381
34836
|
return;
|
|
34382
34837
|
}
|
|
@@ -34520,6 +34975,60 @@ import { AsyncLocalStorage } from "node:async_hooks";
|
|
|
34520
34975
|
import { subscribe } from "node:diagnostics_channel";
|
|
34521
34976
|
import { lookup as lookup2 } from "node:dns/promises";
|
|
34522
34977
|
import { isIP as isIP3 } from "node:net";
|
|
34978
|
+
|
|
34979
|
+
// src/node/follow.ts
|
|
34980
|
+
var MAX_REDIRECTS = 20;
|
|
34981
|
+
var REDIRECTS = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
|
|
34982
|
+
var BODY_HEADERS = /* @__PURE__ */ new Set([
|
|
34983
|
+
"content-encoding",
|
|
34984
|
+
"content-language",
|
|
34985
|
+
"content-length",
|
|
34986
|
+
"content-location",
|
|
34987
|
+
"content-type"
|
|
34988
|
+
]);
|
|
34989
|
+
var CREDENTIALS = /* @__PURE__ */ new Set(["authorization", "proxy-authorization", "cookie", "cookie2"]);
|
|
34990
|
+
function failed4(message3) {
|
|
34991
|
+
return Object.assign(new Error(message3), { status: 502, detail: "transport" });
|
|
34992
|
+
}
|
|
34993
|
+
function locationOf(headers) {
|
|
34994
|
+
return headers.find(([name2]) => name2.toLowerCase() === "location")?.[1];
|
|
34995
|
+
}
|
|
34996
|
+
function nextHop(hop, status, location) {
|
|
34997
|
+
if (!URL.canParse(location, hop.url)) throw failed4(`a bad redirect from ${hop.url}`);
|
|
34998
|
+
const next3 = new URL(location, hop.url);
|
|
34999
|
+
if (next3.protocol !== "http:" && next3.protocol !== "https:") {
|
|
35000
|
+
throw failed4(`a redirect from ${hop.url} to ${next3.protocol}`);
|
|
35001
|
+
}
|
|
35002
|
+
next3.hash = "";
|
|
35003
|
+
const toGet = (status === 301 || status === 302) && hop.method === "POST" || status === 303 && hop.method !== "GET" && hop.method !== "HEAD";
|
|
35004
|
+
if (hop.bodyStream && !toGet) throw failed4(`a ${status} redirect would resend a streamed body`);
|
|
35005
|
+
const crossOrigin = next3.origin !== new URL(hop.url).origin;
|
|
35006
|
+
const { body, bodyStream: bodyStream2, ...rest2 } = hop;
|
|
35007
|
+
return {
|
|
35008
|
+
...rest2,
|
|
35009
|
+
...body && !toGet ? { body } : {},
|
|
35010
|
+
url: next3.href,
|
|
35011
|
+
method: toGet ? "GET" : hop.method,
|
|
35012
|
+
headers: hop.headers.filter(
|
|
35013
|
+
([name2]) => !(toGet && BODY_HEADERS.has(name2.toLowerCase())) && !(crossOrigin && CREDENTIALS.has(name2.toLowerCase()))
|
|
35014
|
+
)
|
|
35015
|
+
};
|
|
35016
|
+
}
|
|
35017
|
+
async function followRedirects(send2, request) {
|
|
35018
|
+
let hop = { ...request, redirect: "manual" };
|
|
35019
|
+
for (let hops = 0; ; hops++) {
|
|
35020
|
+
const response = await send2(hop);
|
|
35021
|
+
const location = locationOf(response.headers);
|
|
35022
|
+
if (!REDIRECTS.has(response.status) || location === void 0) {
|
|
35023
|
+
return hops > 0 ? { ...response, url: hop.url, redirected: true } : response;
|
|
35024
|
+
}
|
|
35025
|
+
await response.cancel();
|
|
35026
|
+
if (hops >= MAX_REDIRECTS) throw failed4(`too many redirects from ${request.url}`);
|
|
35027
|
+
hop = nextHop(hop, response.status, location);
|
|
35028
|
+
}
|
|
35029
|
+
}
|
|
35030
|
+
|
|
35031
|
+
// src/node/loopback.ts
|
|
34523
35032
|
var DEVTOOLS_PORTS = [9222, 9223, 9224, 9225, 9226, 9227, 9228, 9229];
|
|
34524
35033
|
var METADATA_V6 = [64768, 3778, 0, 0, 0, 0, 0, 596].join(":");
|
|
34525
35034
|
var resolveHost = async (host) => (await lookup2(host, { all: true, verbatim: true })).map((a) => a.address);
|
|
@@ -34597,7 +35106,7 @@ async function checkDestination(target, policy, resolve2 = resolveHost) {
|
|
|
34597
35106
|
throw refusal2(url, address, place);
|
|
34598
35107
|
}
|
|
34599
35108
|
}
|
|
34600
|
-
function
|
|
35109
|
+
function guarded3(check, signal) {
|
|
34601
35110
|
if (!signal) return check;
|
|
34602
35111
|
signal.throwIfAborted();
|
|
34603
35112
|
let stop = () => {
|
|
@@ -34684,22 +35193,23 @@ function ensureSubscribed() {
|
|
|
34684
35193
|
function guardedLoopback(transport, policy, resolve2) {
|
|
34685
35194
|
ensureSubscribed();
|
|
34686
35195
|
const open = transport.websocket?.bind(transport);
|
|
35196
|
+
const send2 = async (request, owner, stamp) => {
|
|
35197
|
+
await guarded3(checkDestination(request.url, policy, resolve2), request.signal);
|
|
35198
|
+
const entry = { policy };
|
|
35199
|
+
try {
|
|
35200
|
+
return await loopbackStore.run(entry, () => transport.fetch(request, owner, stamp));
|
|
35201
|
+
} catch (err) {
|
|
35202
|
+
throw entry.refused ?? err;
|
|
35203
|
+
}
|
|
35204
|
+
};
|
|
34687
35205
|
return {
|
|
34688
35206
|
get traits() {
|
|
34689
35207
|
return transport.traits;
|
|
34690
35208
|
},
|
|
34691
|
-
fetch:
|
|
34692
|
-
await guarded2(checkDestination(request.url, policy, resolve2), request.signal);
|
|
34693
|
-
const entry = { policy };
|
|
34694
|
-
try {
|
|
34695
|
-
return await loopbackStore.run(entry, () => transport.fetch(request, owner));
|
|
34696
|
-
} catch (err) {
|
|
34697
|
-
throw entry.refused ?? err;
|
|
34698
|
-
}
|
|
34699
|
-
},
|
|
35209
|
+
fetch: (request, owner, stamp) => request.redirect === "follow" ? followRedirects((hop) => send2(hop, owner, stamp), request) : send2(request, owner, stamp),
|
|
34700
35210
|
...open ? {
|
|
34701
35211
|
websocket: async (request) => {
|
|
34702
|
-
await
|
|
35212
|
+
await guarded3(checkDestination(request.url, policy, resolve2), request.signal);
|
|
34703
35213
|
const entry = { policy };
|
|
34704
35214
|
try {
|
|
34705
35215
|
return await loopbackStore.run(entry, () => open(request));
|
|
@@ -35082,212 +35592,6 @@ function diagnosing(transport, check = byDefault) {
|
|
|
35082
35592
|
};
|
|
35083
35593
|
}
|
|
35084
35594
|
|
|
35085
|
-
// src/kernel/net/remote-transport.ts
|
|
35086
|
-
var TransportError = class extends Error {
|
|
35087
|
-
status;
|
|
35088
|
-
code;
|
|
35089
|
-
detail;
|
|
35090
|
-
constructor(message3, status, code, detail) {
|
|
35091
|
-
super(message3);
|
|
35092
|
-
this.status = status;
|
|
35093
|
-
this.code = code;
|
|
35094
|
-
this.detail = detail === "transport" ? detail : void 0;
|
|
35095
|
-
}
|
|
35096
|
-
};
|
|
35097
|
-
var RemoteTransport = class {
|
|
35098
|
-
traits;
|
|
35099
|
-
port;
|
|
35100
|
-
waiting = /* @__PURE__ */ new Map();
|
|
35101
|
-
nextId = 0;
|
|
35102
|
-
sockets = /* @__PURE__ */ new Map();
|
|
35103
|
-
uploads = /* @__PURE__ */ new Map();
|
|
35104
|
-
failure;
|
|
35105
|
-
constructor(port, traits) {
|
|
35106
|
-
this.port = port;
|
|
35107
|
-
this.traits = traits;
|
|
35108
|
-
}
|
|
35109
|
-
receive(reply) {
|
|
35110
|
-
if (reply.net === "body-pull") {
|
|
35111
|
-
void this.pull(reply.nid);
|
|
35112
|
-
return;
|
|
35113
|
-
}
|
|
35114
|
-
const socket = this.sockets.get(reply.nid);
|
|
35115
|
-
if (socket && this.toSocket(reply, socket)) return;
|
|
35116
|
-
const waiter = this.waiting.get(reply.nid);
|
|
35117
|
-
if (!waiter) return;
|
|
35118
|
-
this.waiting.delete(reply.nid);
|
|
35119
|
-
if (reply.net === "error") {
|
|
35120
|
-
waiter.reject(new TransportError(reply.message, reply.status, reply.code, reply.detail));
|
|
35121
|
-
} else waiter.resolve(reply);
|
|
35122
|
-
}
|
|
35123
|
-
toSocket(reply, socket) {
|
|
35124
|
-
if (reply.net === "ws-message") socket.queue.push(reply.data);
|
|
35125
|
-
else if (reply.net === "ws-acked") socket.acked(reply.n);
|
|
35126
|
-
else if (reply.net === "ws-closed") {
|
|
35127
|
-
this.sockets.delete(reply.nid);
|
|
35128
|
-
socket.queue.end({ code: reply.code, reason: reply.reason });
|
|
35129
|
-
} else return false;
|
|
35130
|
-
return true;
|
|
35131
|
-
}
|
|
35132
|
-
async pull(nid) {
|
|
35133
|
-
const upload = this.uploads.get(nid);
|
|
35134
|
-
if (!upload) {
|
|
35135
|
-
this.port.postMessage({ net: "body-error", nid, message: "the request body is gone" });
|
|
35136
|
-
return;
|
|
35137
|
-
}
|
|
35138
|
-
try {
|
|
35139
|
-
const next3 = await upload.next();
|
|
35140
|
-
if (next3.done) {
|
|
35141
|
-
this.uploads.delete(nid);
|
|
35142
|
-
this.port.postMessage({ net: "body-end", nid });
|
|
35143
|
-
} else this.port.postMessage({ net: "body-chunk", nid, bytes: next3.value });
|
|
35144
|
-
} catch (e) {
|
|
35145
|
-
this.uploads.delete(nid);
|
|
35146
|
-
this.port.postMessage({
|
|
35147
|
-
net: "body-error",
|
|
35148
|
-
nid,
|
|
35149
|
-
message: e instanceof Error ? e.message : String(e)
|
|
35150
|
-
});
|
|
35151
|
-
}
|
|
35152
|
-
}
|
|
35153
|
-
dropUpload(nid) {
|
|
35154
|
-
const upload = this.uploads.get(nid);
|
|
35155
|
-
this.uploads.delete(nid);
|
|
35156
|
-
void upload?.return?.().catch(() => void 0);
|
|
35157
|
-
}
|
|
35158
|
-
fail(error) {
|
|
35159
|
-
this.failure = error;
|
|
35160
|
-
for (const nid of [...this.uploads.keys()]) this.dropUpload(nid);
|
|
35161
|
-
for (const waiter of this.waiting.values()) waiter.reject(error);
|
|
35162
|
-
this.waiting.clear();
|
|
35163
|
-
for (const socket of this.sockets.values())
|
|
35164
|
-
socket.queue.end({ code: 1011, reason: error.message });
|
|
35165
|
-
this.sockets.clear();
|
|
35166
|
-
}
|
|
35167
|
-
ask(call) {
|
|
35168
|
-
if (this.failure) return Promise.reject(this.failure);
|
|
35169
|
-
return new Promise((resolve2, reject) => {
|
|
35170
|
-
this.waiting.set(call.nid, { resolve: resolve2, reject });
|
|
35171
|
-
this.port.postMessage(call);
|
|
35172
|
-
});
|
|
35173
|
-
}
|
|
35174
|
-
cancel(nid) {
|
|
35175
|
-
const waiter = this.waiting.get(nid);
|
|
35176
|
-
this.waiting.delete(nid);
|
|
35177
|
-
waiter?.reject(new TransportError("the request was cancelled"));
|
|
35178
|
-
this.port.postMessage({ net: "cancel", nid });
|
|
35179
|
-
}
|
|
35180
|
-
async fetch(request) {
|
|
35181
|
-
const nid = ++this.nextId;
|
|
35182
|
-
const { signal } = request;
|
|
35183
|
-
signal.throwIfAborted();
|
|
35184
|
-
let finished = false;
|
|
35185
|
-
const abort = () => {
|
|
35186
|
-
finished = true;
|
|
35187
|
-
this.dropUpload(nid);
|
|
35188
|
-
this.cancel(nid);
|
|
35189
|
-
};
|
|
35190
|
-
signal.addEventListener("abort", abort, { once: true });
|
|
35191
|
-
const finish = () => {
|
|
35192
|
-
this.dropUpload(nid);
|
|
35193
|
-
if (finished) return;
|
|
35194
|
-
finished = true;
|
|
35195
|
-
signal.removeEventListener("abort", abort);
|
|
35196
|
-
};
|
|
35197
|
-
if (request.bodyStream) this.uploads.set(nid, request.bodyStream[Symbol.asyncIterator]());
|
|
35198
|
-
let head;
|
|
35199
|
-
try {
|
|
35200
|
-
head = await this.ask({
|
|
35201
|
-
net: "fetch",
|
|
35202
|
-
nid,
|
|
35203
|
-
url: request.url,
|
|
35204
|
-
method: request.method,
|
|
35205
|
-
headers: request.headers,
|
|
35206
|
-
...request.bodyStream ? { streamed: true } : request.body ? { body: request.body } : {}
|
|
35207
|
-
});
|
|
35208
|
-
} catch (e) {
|
|
35209
|
-
finish();
|
|
35210
|
-
throw e;
|
|
35211
|
-
}
|
|
35212
|
-
const { status, statusText, headers, url, redirected: redirected2, redirects } = head;
|
|
35213
|
-
const read = async () => {
|
|
35214
|
-
if (finished) return void 0;
|
|
35215
|
-
const reply = await this.ask({ net: "read", nid }).catch((e) => {
|
|
35216
|
-
finish();
|
|
35217
|
-
throw e;
|
|
35218
|
-
});
|
|
35219
|
-
if (reply.net === "chunk") return reply.bytes;
|
|
35220
|
-
finish();
|
|
35221
|
-
return void 0;
|
|
35222
|
-
};
|
|
35223
|
-
const cancel = async () => {
|
|
35224
|
-
if (finished) return;
|
|
35225
|
-
finish();
|
|
35226
|
-
this.cancel(nid);
|
|
35227
|
-
};
|
|
35228
|
-
return {
|
|
35229
|
-
...redirected2 ? { url, redirected: redirected2 } : {},
|
|
35230
|
-
...redirects ? { redirects } : {},
|
|
35231
|
-
status,
|
|
35232
|
-
statusText,
|
|
35233
|
-
headers,
|
|
35234
|
-
cancel,
|
|
35235
|
-
body: {
|
|
35236
|
-
[Symbol.asyncIterator]: () => ({
|
|
35237
|
-
next: async () => {
|
|
35238
|
-
const bytes = await read();
|
|
35239
|
-
return bytes ? { value: bytes, done: false } : { value: void 0, done: true };
|
|
35240
|
-
},
|
|
35241
|
-
return: async () => {
|
|
35242
|
-
await cancel();
|
|
35243
|
-
return { value: void 0, done: true };
|
|
35244
|
-
}
|
|
35245
|
-
})
|
|
35246
|
-
}
|
|
35247
|
-
};
|
|
35248
|
-
}
|
|
35249
|
-
async websocket(request) {
|
|
35250
|
-
const nid = ++this.nextId;
|
|
35251
|
-
const { signal } = request;
|
|
35252
|
-
signal.throwIfAborted();
|
|
35253
|
-
const abort = () => this.cancel(nid);
|
|
35254
|
-
signal.addEventListener("abort", abort, { once: true });
|
|
35255
|
-
let opened2;
|
|
35256
|
-
try {
|
|
35257
|
-
opened2 = await this.ask({
|
|
35258
|
-
net: "ws-open",
|
|
35259
|
-
nid,
|
|
35260
|
-
url: request.url,
|
|
35261
|
-
protocols: request.protocols,
|
|
35262
|
-
headers: request.headers
|
|
35263
|
-
});
|
|
35264
|
-
} finally {
|
|
35265
|
-
signal.removeEventListener("abort", abort);
|
|
35266
|
-
}
|
|
35267
|
-
const close = (code, reason) => this.port.postMessage({ net: "ws-close", nid, code, reason });
|
|
35268
|
-
const queue = new MessageQueue(
|
|
35269
|
-
() => close(1e3, "a message is too big"),
|
|
35270
|
-
Number.POSITIVE_INFINITY,
|
|
35271
|
-
(n) => this.port.postMessage({ net: "ws-consumed", nid, n })
|
|
35272
|
-
);
|
|
35273
|
-
let unacked = 0;
|
|
35274
|
-
this.sockets.set(nid, { queue, acked: (n) => void (unacked -= n) });
|
|
35275
|
-
return {
|
|
35276
|
-
protocol: opened2.protocol,
|
|
35277
|
-
get buffered() {
|
|
35278
|
-
return unacked;
|
|
35279
|
-
},
|
|
35280
|
-
send: (data) => {
|
|
35281
|
-
unacked += payloadSize(data);
|
|
35282
|
-
this.port.postMessage({ net: "ws-send", nid, data });
|
|
35283
|
-
},
|
|
35284
|
-
messages: queue,
|
|
35285
|
-
close,
|
|
35286
|
-
closed: queue.closed
|
|
35287
|
-
};
|
|
35288
|
-
}
|
|
35289
|
-
};
|
|
35290
|
-
|
|
35291
35595
|
// src/serve.ts
|
|
35292
35596
|
function signalNumber(name2) {
|
|
35293
35597
|
const key = name2.slice(3);
|
|
@@ -35921,9 +36225,9 @@ async function greet(channel, lock, timeoutMs, requests) {
|
|
|
35921
36225
|
} finally {
|
|
35922
36226
|
clearTimeout(timer);
|
|
35923
36227
|
}
|
|
35924
|
-
const
|
|
35925
|
-
if (
|
|
35926
|
-
const error = new Error(
|
|
36228
|
+
const refused4 = hello.error ?? versionError(hello.protocol);
|
|
36229
|
+
if (refused4) {
|
|
36230
|
+
const error = new Error(refused4);
|
|
35927
36231
|
channel.end(error);
|
|
35928
36232
|
throw error;
|
|
35929
36233
|
}
|
|
@@ -36289,6 +36593,7 @@ function checkedRequests(hook) {
|
|
|
36289
36593
|
return { kinds, handle: (request) => hook.handle(request) };
|
|
36290
36594
|
}
|
|
36291
36595
|
async function createNodeKernel(options = {}) {
|
|
36596
|
+
const hooks = sealedHooks(options.sealed);
|
|
36292
36597
|
const root = options.root ?? memoryRoot();
|
|
36293
36598
|
const fs = new OpfsFs(root, void 0, void 0, { ranged: isMemoryRoot(root) });
|
|
36294
36599
|
await fs.reconcile();
|
|
@@ -36327,7 +36632,8 @@ async function createNodeKernel(options = {}) {
|
|
|
36327
36632
|
users: options.users === void 0 ? DEFAULT_USERS : options.users,
|
|
36328
36633
|
...options.onDenial ? { onDenial: options.onDenial } : {},
|
|
36329
36634
|
...options.protect ? { protect: options.protect } : {},
|
|
36330
|
-
...
|
|
36635
|
+
...hooks.request ? { sealed: hooks.request } : {},
|
|
36636
|
+
...hooks.fetch ? { sealedFetch: hooks.fetch } : {},
|
|
36331
36637
|
...options.clipboard ? { clipboard: options.clipboard } : {},
|
|
36332
36638
|
...options.requests ? { embedder: checkedRequests(options.requests) } : {},
|
|
36333
36639
|
...options.approve ? { approve: options.approve } : {},
|
|
@@ -36403,6 +36709,8 @@ async function createNodeKernel(options = {}) {
|
|
|
36403
36709
|
},
|
|
36404
36710
|
chmod: async (path, mode) => launcher.fs.chmod(path, modeOption(mode)),
|
|
36405
36711
|
integrity: { revoke: (path) => guard2(() => launcher.revokeIntegrity(path)) },
|
|
36712
|
+
sealed: { setPlaceholders: (list) => guard2(async () => launcher.setPlaceholders(list)) },
|
|
36713
|
+
attest: ((path, attestOptions) => guard2(() => launcher.attest(path, attestOptions))),
|
|
36406
36714
|
readFile: async (path) => launcher.fs.readFileBuffer(path),
|
|
36407
36715
|
mount: (spec) => guard2(() => launcher.mount(spec)),
|
|
36408
36716
|
umount: (target) => guard2(async () => launcher.umount(target)),
|
|
@@ -36435,6 +36743,7 @@ async function createNodeKernel(options = {}) {
|
|
|
36435
36743
|
for (const reject of [...pending]) reject(new Error(TERMINATED));
|
|
36436
36744
|
for (const kill of [...live]) kill();
|
|
36437
36745
|
launcher.cdp.close();
|
|
36746
|
+
launcher.endFills();
|
|
36438
36747
|
launcher.unmountAll();
|
|
36439
36748
|
dropCache(cache);
|
|
36440
36749
|
}
|
|
@@ -36444,6 +36753,7 @@ export {
|
|
|
36444
36753
|
KernelCallError,
|
|
36445
36754
|
KernelGoneError,
|
|
36446
36755
|
MAX_WARM_WORKERS,
|
|
36756
|
+
SEALED_FETCH_VERSION,
|
|
36447
36757
|
WARM_IDLE_MS,
|
|
36448
36758
|
attachKernel,
|
|
36449
36759
|
createNodeKernel,
|