@ai-ecoverse/slicc-kernel 1.171.0 → 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 +22 -7
- package/dist/driver-worker.js +4 -2
- package/dist/driver-worker.js.map +2 -2
- package/dist/index.js +216 -36
- package/dist/index.js.map +4 -4
- package/dist/kernel-worker.js +507 -196
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-driver-worker.js +4 -2
- package/dist/node-driver-worker.js.map +2 -2
- package/dist/node-process-worker.cjs +1 -1
- package/dist/node-process-worker.js +1 -1
- package/dist/node.js +455 -232
- 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 +12 -4
- 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 +4 -1
- package/dist/types/kernel/net/sealed-fetch.d.ts +27 -0
- package/dist/types/kernel/net/transport.d.ts +2 -1
- package/dist/types/kernel/socket.d.ts +4 -1
- package/dist/types/launcher.d.ts +12 -2
- package/dist/types/node.d.ts +12 -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 +2 -1
- package/package.json +1 -1
package/dist/kernel-worker.js
CHANGED
|
@@ -182,13 +182,13 @@ var IndexedDbMeta = class {
|
|
|
182
182
|
return [transaction, transaction.objectStore(META_STORE)];
|
|
183
183
|
}
|
|
184
184
|
async get(paths) {
|
|
185
|
-
const
|
|
186
|
-
if (
|
|
185
|
+
const missing6 = paths.filter((path) => !this.cache.has(path));
|
|
186
|
+
if (missing6.length > 0) {
|
|
187
187
|
this.settleRemoves();
|
|
188
188
|
const generation = this.generation;
|
|
189
189
|
const [transaction, store] = this.transaction("readonly");
|
|
190
190
|
const found = /* @__PURE__ */ new Map();
|
|
191
|
-
for (const path of
|
|
191
|
+
for (const path of missing6) {
|
|
192
192
|
const request3 = store.get(path);
|
|
193
193
|
request3.onsuccess = () => void found.set(path, request3.result ?? null);
|
|
194
194
|
}
|
|
@@ -1237,10 +1237,10 @@ var RemoteWatch = class {
|
|
|
1237
1237
|
});
|
|
1238
1238
|
}
|
|
1239
1239
|
}
|
|
1240
|
-
heldBy({ tab, holds:
|
|
1240
|
+
heldBy({ tab, holds: holds3, seq: seq2 }) {
|
|
1241
1241
|
const from = tab;
|
|
1242
|
-
const { add, drop } =
|
|
1243
|
-
if (
|
|
1242
|
+
const { add, drop } = holds3;
|
|
1243
|
+
if (holds3?.instance !== void 0) this.instances.set(from, holds3.instance);
|
|
1244
1244
|
const held = this.peerHolds.get(from) ?? /* @__PURE__ */ new Map();
|
|
1245
1245
|
for (const path of drop) held.delete(path);
|
|
1246
1246
|
for (const [path, fid] of add) held.set(path, fid);
|
|
@@ -1524,11 +1524,11 @@ var META_OPS = ["get", "update", "move", "remove", "links", "under", "all"];
|
|
|
1524
1524
|
var FILE_ID_TRIES = 3;
|
|
1525
1525
|
function sidecar(meta) {
|
|
1526
1526
|
const pathOf = ([first]) => [first, "/"].flat().find((p) => typeof p === "string");
|
|
1527
|
-
const
|
|
1527
|
+
const guarded3 = (op) => (...args) => meta[op].apply(meta, args).catch((err) => {
|
|
1528
1528
|
throw translate(err, pathOf(args), "sidecar", false);
|
|
1529
1529
|
});
|
|
1530
1530
|
const names2 = meta.fresh ? [...META_OPS, "fresh"] : META_OPS;
|
|
1531
|
-
const ops = Object.fromEntries(names2.map((op) => [op,
|
|
1531
|
+
const ops = Object.fromEntries(names2.map((op) => [op, guarded3(op)]));
|
|
1532
1532
|
const { updateMany } = meta;
|
|
1533
1533
|
ops.updateMany = updateMany ? (changes) => updateMany.call(meta, changes).catch((err) => {
|
|
1534
1534
|
throw translate(err, changes[0]?.path ?? "/", "sidecar", false);
|
|
@@ -3638,12 +3638,12 @@ var OpfsFs = class {
|
|
|
3638
3638
|
if (!move) return false;
|
|
3639
3639
|
for (let attempt = 0; ; attempt++) {
|
|
3640
3640
|
this.others++;
|
|
3641
|
-
const
|
|
3641
|
+
const failed4 = await move.call(handle, dir, name2).then(
|
|
3642
3642
|
() => void 0,
|
|
3643
3643
|
(err) => ({ err })
|
|
3644
3644
|
);
|
|
3645
|
-
if (!
|
|
3646
|
-
const error =
|
|
3645
|
+
if (!failed4) return true;
|
|
3646
|
+
const error = failed4.err?.name;
|
|
3647
3647
|
if (handle.kind !== "file" || !LOCKED.has(error)) return false;
|
|
3648
3648
|
const delay2 = SYNC_BACKOFF_MS[attempt];
|
|
3649
3649
|
if (delay2 === void 0) throw fsError("EBUSY", name2);
|
|
@@ -6842,9 +6842,9 @@ var KernelSocket = class _KernelSocket {
|
|
|
6842
6842
|
case SO_TYPE:
|
|
6843
6843
|
return SOCK_STREAM;
|
|
6844
6844
|
case SO_ERROR: {
|
|
6845
|
-
const
|
|
6845
|
+
const failed4 = this.failed;
|
|
6846
6846
|
this.failed = void 0;
|
|
6847
|
-
return
|
|
6847
|
+
return failed4 ? wasiErrno(failed4) : 0;
|
|
6848
6848
|
}
|
|
6849
6849
|
case SO_ACCEPTCONN:
|
|
6850
6850
|
return this.state === "listening" ? 1 : 0;
|
|
@@ -6924,6 +6924,7 @@ var LoopbackNet = class {
|
|
|
6924
6924
|
internal = /* @__PURE__ */ new Set();
|
|
6925
6925
|
reserved = /* @__PURE__ */ new Set();
|
|
6926
6926
|
facades = /* @__PURE__ */ new Map();
|
|
6927
|
+
proxyStamped;
|
|
6927
6928
|
nextEphemeral = EPHEMERAL_FIRST;
|
|
6928
6929
|
route;
|
|
6929
6930
|
origins;
|
|
@@ -6998,9 +6999,15 @@ var LoopbackNet = class {
|
|
|
6998
6999
|
this.kernelOnly(port, true);
|
|
6999
7000
|
this.facades.set(port, name2);
|
|
7000
7001
|
}
|
|
7001
|
-
|
|
7002
|
-
|
|
7003
|
-
|
|
7002
|
+
stampProxy(port) {
|
|
7003
|
+
this.proxyStamped = port;
|
|
7004
|
+
}
|
|
7005
|
+
get originsStamped() {
|
|
7006
|
+
return this.proxyStamped !== void 0;
|
|
7007
|
+
}
|
|
7008
|
+
stampsPeers(addr) {
|
|
7009
|
+
if (addr.family !== "inet" || !isLoopback(canonicalHost(addr.host))) return false;
|
|
7010
|
+
return this.facades.has(addr.port) || this.proxyStamped === addr.port;
|
|
7004
7011
|
}
|
|
7005
7012
|
activate(addr, start2) {
|
|
7006
7013
|
this.activators.set(keyOf(addr), start2);
|
|
@@ -7323,7 +7330,21 @@ function headOf(nid, response) {
|
|
|
7323
7330
|
headers: response.headers
|
|
7324
7331
|
};
|
|
7325
7332
|
}
|
|
7326
|
-
function
|
|
7333
|
+
function requestOf(call, signal, uploads) {
|
|
7334
|
+
const { url, method, headers, streamed, body, redirect, nid } = call;
|
|
7335
|
+
return {
|
|
7336
|
+
url,
|
|
7337
|
+
method,
|
|
7338
|
+
headers,
|
|
7339
|
+
...streamed ? { bodyStream: uploads.of(nid, signal) } : body ? { body } : {},
|
|
7340
|
+
...redirect !== void 0 ? { redirect } : {},
|
|
7341
|
+
signal
|
|
7342
|
+
};
|
|
7343
|
+
}
|
|
7344
|
+
function serveTransport(peer, transport, {
|
|
7345
|
+
closeWaitMs = CLOSE_WAIT_MS2,
|
|
7346
|
+
attributed = false
|
|
7347
|
+
} = {}) {
|
|
7327
7348
|
const open2 = /* @__PURE__ */ new Map();
|
|
7328
7349
|
const fail2 = (nid, e) => {
|
|
7329
7350
|
open2.delete(nid);
|
|
@@ -7343,14 +7364,11 @@ function serveTransport(peer, transport, { closeWaitMs = CLOSE_WAIT_MS2 } = {})
|
|
|
7343
7364
|
const entry = { abort };
|
|
7344
7365
|
open2.set(call.nid, entry);
|
|
7345
7366
|
try {
|
|
7346
|
-
const response = await transport.fetch(
|
|
7347
|
-
|
|
7348
|
-
|
|
7349
|
-
|
|
7350
|
-
|
|
7351
|
-
...call.redirect !== void 0 ? { redirect: call.redirect } : {},
|
|
7352
|
-
signal: abort.signal
|
|
7353
|
-
});
|
|
7367
|
+
const response = await transport.fetch(
|
|
7368
|
+
requestOf(call, abort.signal, uploads),
|
|
7369
|
+
attributed ? call.owner : void 0,
|
|
7370
|
+
attributed ? call.stamp : void 0
|
|
7371
|
+
);
|
|
7354
7372
|
if (!open2.has(call.nid)) {
|
|
7355
7373
|
await response.cancel();
|
|
7356
7374
|
return;
|
|
@@ -8504,7 +8522,7 @@ function satisfies(version, range2) {
|
|
|
8504
8522
|
}
|
|
8505
8523
|
|
|
8506
8524
|
// src/version.ts
|
|
8507
|
-
var KERNEL_VERSION = true ? "1.
|
|
8525
|
+
var KERNEL_VERSION = true ? "1.172.0" : "0.0.0-dev";
|
|
8508
8526
|
var OS_RELEASE = "6.0.0-slicc";
|
|
8509
8527
|
function procVersion() {
|
|
8510
8528
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -9161,32 +9179,32 @@ function nextFire(schedule, after, utc = false) {
|
|
|
9161
9179
|
}
|
|
9162
9180
|
return null;
|
|
9163
9181
|
}
|
|
9164
|
-
function missedFires(schedule, from,
|
|
9182
|
+
function missedFires(schedule, from, until2, utc = false, cap = MISSED_CAP) {
|
|
9165
9183
|
let count2 = 0;
|
|
9166
9184
|
let last = null;
|
|
9167
9185
|
let at = from;
|
|
9168
9186
|
while (count2 < cap) {
|
|
9169
9187
|
at = nextFire(schedule, at, utc);
|
|
9170
|
-
if (at === null || at >
|
|
9188
|
+
if (at === null || at > until2) return { count: count2, last, more: false };
|
|
9171
9189
|
last = at;
|
|
9172
9190
|
count2++;
|
|
9173
9191
|
}
|
|
9174
9192
|
const next3 = nextFire(schedule, last, utc);
|
|
9175
|
-
if (next3 === null || next3 >
|
|
9176
|
-
return { count: count2, last: latestFire(schedule, last,
|
|
9193
|
+
if (next3 === null || next3 > until2) return { count: count2, last, more: false };
|
|
9194
|
+
return { count: count2, last: latestFire(schedule, last, until2, utc), more: true };
|
|
9177
9195
|
}
|
|
9178
|
-
function latestFire(schedule, from,
|
|
9196
|
+
function latestFire(schedule, from, until2, utc = false) {
|
|
9179
9197
|
let found = from;
|
|
9180
9198
|
for (let span = 6e4; ; span *= 2) {
|
|
9181
|
-
const start2 = Math.max(from,
|
|
9199
|
+
const start2 = Math.max(from, until2 - span);
|
|
9182
9200
|
const first = nextFire(schedule, start2, utc);
|
|
9183
|
-
if (first !== null && first <=
|
|
9201
|
+
if (first !== null && first <= until2) {
|
|
9184
9202
|
found = first;
|
|
9185
9203
|
break;
|
|
9186
9204
|
}
|
|
9187
9205
|
if (start2 === from) return from;
|
|
9188
9206
|
}
|
|
9189
|
-
for (let at = nextFire(schedule, found, utc); at !== null && at <=
|
|
9207
|
+
for (let at = nextFire(schedule, found, utc); at !== null && at <= until2; ) {
|
|
9190
9208
|
found = at;
|
|
9191
9209
|
at = nextFire(schedule, at, utc);
|
|
9192
9210
|
}
|
|
@@ -9898,12 +9916,12 @@ var UnlinkedKeeper = class {
|
|
|
9898
9916
|
return this.locks;
|
|
9899
9917
|
}
|
|
9900
9918
|
async undoing(op, peers, sends, heard, shared2 = []) {
|
|
9901
|
-
let
|
|
9919
|
+
let failed4;
|
|
9902
9920
|
let out;
|
|
9903
9921
|
try {
|
|
9904
9922
|
out = await op();
|
|
9905
9923
|
} catch (err) {
|
|
9906
|
-
|
|
9924
|
+
failed4 = err ?? new Error("failed");
|
|
9907
9925
|
await this.rollBackAsides(sends, shared2);
|
|
9908
9926
|
}
|
|
9909
9927
|
const hiddenShared = new Set(shared2.map((one) => one.hidden));
|
|
@@ -9924,7 +9942,7 @@ var UnlinkedKeeper = class {
|
|
|
9924
9942
|
const done5 = () => one.release().then(() => this.dropIfLast(one.hidden));
|
|
9925
9943
|
void Promise.all(waits.map(({ told }) => told)).then(done5, done5);
|
|
9926
9944
|
}
|
|
9927
|
-
if (
|
|
9945
|
+
if (failed4 !== void 0) throw failed4;
|
|
9928
9946
|
return out;
|
|
9929
9947
|
}
|
|
9930
9948
|
async rollBackAsides(sends, shared2) {
|
|
@@ -10071,7 +10089,7 @@ var UnlinkedKeeper = class {
|
|
|
10071
10089
|
// src/cron/clock.ts
|
|
10072
10090
|
var systemCronClock = {
|
|
10073
10091
|
now: () => Date.now(),
|
|
10074
|
-
sleep(
|
|
10092
|
+
sleep(until2, signal) {
|
|
10075
10093
|
if (signal.aborted) return Promise.resolve();
|
|
10076
10094
|
return new Promise((resolve2) => {
|
|
10077
10095
|
const done5 = () => {
|
|
@@ -10079,7 +10097,7 @@ var systemCronClock = {
|
|
|
10079
10097
|
signal.removeEventListener("abort", done5);
|
|
10080
10098
|
resolve2();
|
|
10081
10099
|
};
|
|
10082
|
-
const timer = setTimeout(done5, Math.max(0,
|
|
10100
|
+
const timer = setTimeout(done5, Math.max(0, until2 - Date.now()));
|
|
10083
10101
|
timer.unref?.();
|
|
10084
10102
|
signal.addEventListener("abort", done5, { once: true });
|
|
10085
10103
|
});
|
|
@@ -10183,15 +10201,15 @@ var CronService = class {
|
|
|
10183
10201
|
async pass() {
|
|
10184
10202
|
if (this.wake.signal.aborted) this.wake = new AbortController();
|
|
10185
10203
|
const wake = this.wake;
|
|
10186
|
-
let
|
|
10204
|
+
let until2;
|
|
10187
10205
|
try {
|
|
10188
|
-
|
|
10206
|
+
until2 = await this.tick();
|
|
10189
10207
|
} catch (err) {
|
|
10190
10208
|
await this.error(`cron: ${messageOf(err)}`);
|
|
10191
|
-
|
|
10209
|
+
until2 = this.clock.now() + WAKE_MS;
|
|
10192
10210
|
}
|
|
10193
10211
|
if (this.stopping.signal.aborted) return;
|
|
10194
|
-
await this.clock.sleep(
|
|
10212
|
+
await this.clock.sleep(until2, wake.signal);
|
|
10195
10213
|
}
|
|
10196
10214
|
async provision() {
|
|
10197
10215
|
const { fs, owners } = this.host;
|
|
@@ -10408,14 +10426,17 @@ var PLACEHOLDER_REFUSED = "refused: this request has a sealed placeholder in its
|
|
|
10408
10426
|
var PlaceholderRefused = class extends Error {
|
|
10409
10427
|
status = 403;
|
|
10410
10428
|
code = "EACCES";
|
|
10411
|
-
constructor() {
|
|
10412
|
-
super(
|
|
10429
|
+
constructor(reason = PLACEHOLDER_REFUSED) {
|
|
10430
|
+
super(reason);
|
|
10413
10431
|
}
|
|
10414
10432
|
};
|
|
10415
|
-
function
|
|
10433
|
+
function holds2(text, known) {
|
|
10434
|
+
return PLACEHOLDER.test(text) || known.some((placeholder) => text.includes(placeholder));
|
|
10435
|
+
}
|
|
10436
|
+
function carries(text, known) {
|
|
10416
10437
|
let layer = text;
|
|
10417
10438
|
for (let i = 0; i < PERCENT_LAYERS; i++) {
|
|
10418
|
-
if (
|
|
10439
|
+
if (holds2(layer, known)) return true;
|
|
10419
10440
|
const next3 = layer.replace(
|
|
10420
10441
|
ESCAPE,
|
|
10421
10442
|
(_, hex4) => String.fromCharCode(Number.parseInt(hex4, 16))
|
|
@@ -10423,35 +10444,36 @@ function carries(text) {
|
|
|
10423
10444
|
if (next3 === layer) return false;
|
|
10424
10445
|
layer = next3;
|
|
10425
10446
|
}
|
|
10426
|
-
return
|
|
10447
|
+
return holds2(layer, known);
|
|
10427
10448
|
}
|
|
10428
|
-
function basicCarries(value2) {
|
|
10449
|
+
function basicCarries(value2, known) {
|
|
10429
10450
|
const credential = BASIC.exec(value2)?.[1];
|
|
10430
10451
|
if (credential === void 0) return false;
|
|
10431
10452
|
const letters = credential.replace(/[^A-Za-z0-9+/_-]/g, "").replaceAll("-", "+").replaceAll("_", "/");
|
|
10432
10453
|
for (let shift = 0; shift < BASE64_GROUP; shift++) {
|
|
10433
10454
|
const part = letters.slice(shift);
|
|
10434
10455
|
const whole = part.length % BASE64_GROUP === 1 ? part.slice(0, -1) : part;
|
|
10435
|
-
if (carries(atob(whole))) return true;
|
|
10456
|
+
if (carries(atob(whole), known)) return true;
|
|
10436
10457
|
}
|
|
10437
10458
|
return false;
|
|
10438
10459
|
}
|
|
10439
|
-
function headersCarry(headers) {
|
|
10460
|
+
function headersCarry(headers, known) {
|
|
10440
10461
|
return headers.some(
|
|
10441
|
-
([name2, value2]) => carries(name2.toLowerCase()) || carries(value2) || basicCarries(value2)
|
|
10462
|
+
([name2, value2]) => carries(name2, known) || carries(name2.toLowerCase(), known) || carries(value2, known) || basicCarries(value2, known)
|
|
10442
10463
|
);
|
|
10443
10464
|
}
|
|
10444
|
-
function urlCarries(url) {
|
|
10445
|
-
return carries(url) || URL.canParse(url) && carries(new URL(url).href);
|
|
10465
|
+
function urlCarries(url, known) {
|
|
10466
|
+
return carries(url, known) || URL.canParse(url) && carries(new URL(url).href, known);
|
|
10446
10467
|
}
|
|
10447
|
-
function
|
|
10448
|
-
|
|
10468
|
+
function detected(request3, known) {
|
|
10469
|
+
return urlCarries(request3.url, known) || headersCarry(request3.headers, known);
|
|
10449
10470
|
}
|
|
10450
|
-
function refuseSocket(request3) {
|
|
10451
|
-
|
|
10452
|
-
|
|
10471
|
+
function refuseSocket(request3, known) {
|
|
10472
|
+
if (detected(request3, known) || request3.protocols.some((p) => carries(p, known))) {
|
|
10473
|
+
throw new PlaceholderRefused();
|
|
10474
|
+
}
|
|
10453
10475
|
}
|
|
10454
|
-
function placeholderFloor(inner) {
|
|
10476
|
+
function placeholderFloor(inner, { known = () => [], fill: fill2 } = {}) {
|
|
10455
10477
|
const open2 = inner.websocket?.bind(inner);
|
|
10456
10478
|
return {
|
|
10457
10479
|
get traits() {
|
|
@@ -10459,13 +10481,14 @@ function placeholderFloor(inner) {
|
|
|
10459
10481
|
},
|
|
10460
10482
|
...open2 ? {
|
|
10461
10483
|
websocket: async (request3) => {
|
|
10462
|
-
refuseSocket(request3);
|
|
10484
|
+
refuseSocket(request3, known());
|
|
10463
10485
|
return open2(request3);
|
|
10464
10486
|
}
|
|
10465
10487
|
} : {},
|
|
10466
|
-
async fetch(request3, owner) {
|
|
10467
|
-
|
|
10468
|
-
|
|
10488
|
+
async fetch(request3, owner, stamp) {
|
|
10489
|
+
if (!detected(request3, known())) return inner.fetch(request3, owner, stamp);
|
|
10490
|
+
if (!fill2 || !stamp) throw new PlaceholderRefused();
|
|
10491
|
+
return fill2(request3, stamp);
|
|
10469
10492
|
}
|
|
10470
10493
|
};
|
|
10471
10494
|
}
|
|
@@ -10638,14 +10661,14 @@ function tunnelTarget(req) {
|
|
|
10638
10661
|
}
|
|
10639
10662
|
return { host, port };
|
|
10640
10663
|
}
|
|
10641
|
-
async function watchHangup(conn, abort,
|
|
10642
|
-
while (!
|
|
10664
|
+
async function watchHangup(conn, abort, until2) {
|
|
10665
|
+
while (!until2.aborted && !abort.signal.aborted) {
|
|
10643
10666
|
if (conn.poll().hangup) {
|
|
10644
10667
|
abort.abort(new KernelError("EPIPE"));
|
|
10645
10668
|
return;
|
|
10646
10669
|
}
|
|
10647
10670
|
try {
|
|
10648
|
-
await conn.changed(
|
|
10671
|
+
await conn.changed(until2);
|
|
10649
10672
|
} catch {
|
|
10650
10673
|
return;
|
|
10651
10674
|
}
|
|
@@ -10836,7 +10859,7 @@ var RealmProxy = class {
|
|
|
10836
10859
|
const waiting = new AbortController();
|
|
10837
10860
|
void watchHangup(ctx.socket, abort, waiting.signal);
|
|
10838
10861
|
try {
|
|
10839
|
-
response = await this.upstream(req, url, body, abort.signal, ctx.socket
|
|
10862
|
+
response = await this.upstream(req, url, body, abort.signal, ctx.socket);
|
|
10840
10863
|
} finally {
|
|
10841
10864
|
waiting.abort();
|
|
10842
10865
|
}
|
|
@@ -10863,7 +10886,7 @@ var RealmProxy = class {
|
|
|
10863
10886
|
await conn.write(latin1Bytes("HTTP/1.1 100 Continue\r\n\r\n"), this.stop.signal);
|
|
10864
10887
|
}
|
|
10865
10888
|
}
|
|
10866
|
-
async upstream(req, url, body, signal,
|
|
10889
|
+
async upstream(req, url, body, signal, socket) {
|
|
10867
10890
|
const sent = BODILESS_METHODS.has(req.method) ? void 0 : body;
|
|
10868
10891
|
try {
|
|
10869
10892
|
const fetching = this.options.transport.fetch(
|
|
@@ -10874,7 +10897,8 @@ var RealmProxy = class {
|
|
|
10874
10897
|
...sent instanceof Uint8Array ? { body: sent } : sent ? { bodyStream: sent } : {},
|
|
10875
10898
|
signal
|
|
10876
10899
|
},
|
|
10877
|
-
|
|
10900
|
+
socket.peerCred?.pid,
|
|
10901
|
+
socket.peerStamp
|
|
10878
10902
|
);
|
|
10879
10903
|
return await untilAborted(fetching, signal);
|
|
10880
10904
|
} catch (e) {
|
|
@@ -11191,7 +11215,7 @@ async function relay(socket, conn) {
|
|
|
11191
11215
|
// src/fs/attest.ts
|
|
11192
11216
|
var ATTEST_MAX = 1024 * 1024;
|
|
11193
11217
|
var UNOWNED = 1e3;
|
|
11194
|
-
function
|
|
11218
|
+
function refuse(code, path, why) {
|
|
11195
11219
|
throw Object.assign(new Error(`attest ${path}: ${why}`), { code });
|
|
11196
11220
|
}
|
|
11197
11221
|
function chainOf(path) {
|
|
@@ -11233,39 +11257,49 @@ async function trustedParents(fs, path, o) {
|
|
|
11233
11257
|
const parents = [];
|
|
11234
11258
|
for (const dir of chainOf(path).slice(0, -1)) {
|
|
11235
11259
|
const st = await fs.lstat(dir);
|
|
11236
|
-
if (st.isSymbolicLink)
|
|
11237
|
-
if (!st.isDirectory)
|
|
11260
|
+
if (st.isSymbolicLink) refuse("EACCES", path, `${dir} is a symlink`);
|
|
11261
|
+
if (!st.isDirectory) refuse("ENOTDIR", path, `${dir} is not a directory`);
|
|
11238
11262
|
const perm = owned(dir, st);
|
|
11239
11263
|
if (o.users !== "off" && (perm.uid !== 0 || (perm.mode & 18) !== 0)) {
|
|
11240
|
-
|
|
11264
|
+
refuse("EACCES", path, `${dir} is not root-owned or is writable by group or others`);
|
|
11241
11265
|
}
|
|
11242
11266
|
parents.push(perm);
|
|
11243
11267
|
}
|
|
11244
11268
|
return parents;
|
|
11245
11269
|
}
|
|
11270
|
+
function missing3(e) {
|
|
11271
|
+
return e?.code === "ENOENT";
|
|
11272
|
+
}
|
|
11246
11273
|
async function attest(fs, asked, o) {
|
|
11274
|
+
if (o.absent !== void 0 && o.absent !== "allow") {
|
|
11275
|
+
refuse("EINVAL", String(asked), "absent takes only allow");
|
|
11276
|
+
}
|
|
11247
11277
|
if (typeof asked !== "string" || !asked.startsWith("/")) {
|
|
11248
|
-
|
|
11278
|
+
refuse("EINVAL", String(asked), "not an absolute path");
|
|
11249
11279
|
}
|
|
11250
11280
|
const path = normalizePath(asked);
|
|
11251
11281
|
const mount = o.mounts.find((target) => {
|
|
11252
11282
|
const at = normalizePath(target);
|
|
11253
11283
|
return at === "/" || under2(path, at);
|
|
11254
11284
|
});
|
|
11255
|
-
if (mount !== void 0)
|
|
11285
|
+
if (mount !== void 0) refuse("EACCES", path, `under the mount ${mount}`);
|
|
11256
11286
|
const parents = await trustedParents(fs, path, o);
|
|
11257
11287
|
for (let tries = 0; ; tries++) {
|
|
11258
|
-
const before = await fs.lstat(path)
|
|
11259
|
-
|
|
11288
|
+
const before = await fs.lstat(path).catch((e) => {
|
|
11289
|
+
if (o.absent === "allow" && missing3(e)) return void 0;
|
|
11290
|
+
throw e;
|
|
11291
|
+
});
|
|
11292
|
+
if (!before) return { path, absent: true, users: o.users, onRootFs: true, parents };
|
|
11293
|
+
if (before.isSymbolicLink) refuse("EACCES", path, "is a symlink");
|
|
11260
11294
|
if (!before.isFile)
|
|
11261
|
-
|
|
11262
|
-
if (before.size > ATTEST_MAX)
|
|
11295
|
+
refuse(before.isDirectory ? "EISDIR" : "EINVAL", path, "is not a regular file");
|
|
11296
|
+
if (before.size > ATTEST_MAX) refuse("EFBIG", path, `is over ${ATTEST_MAX} bytes`);
|
|
11263
11297
|
const bytes = (await fs.readFileBuffer(path)).slice();
|
|
11264
11298
|
const after = await fs.lstat(path);
|
|
11265
11299
|
if (unchanged(before, after, bytes)) {
|
|
11266
11300
|
return attested(path, after, bytes, await sha2562(bytes), o, parents);
|
|
11267
11301
|
}
|
|
11268
|
-
if (tries >= 1)
|
|
11302
|
+
if (tries >= 1) refuse("EAGAIN", path, "changed while it was read");
|
|
11269
11303
|
}
|
|
11270
11304
|
}
|
|
11271
11305
|
var WATCH_DEBOUNCE_MS = 50;
|
|
@@ -11324,7 +11358,7 @@ var S_IFREG2 = 32768;
|
|
|
11324
11358
|
var COMMAND = /^\/(?:usr\/)?bin\/([^/]+)$/;
|
|
11325
11359
|
var MAX_LINKS6 = 40;
|
|
11326
11360
|
var BIN_ENTRY = /\/bin\/[^/]+$/;
|
|
11327
|
-
function
|
|
11361
|
+
function missing4(err) {
|
|
11328
11362
|
return err?.code === "ENOENT";
|
|
11329
11363
|
}
|
|
11330
11364
|
function synthetic(directory, path) {
|
|
@@ -11428,7 +11462,7 @@ function withCommandDirs(fs, names2, userDir = async () => void 0, owners = fals
|
|
|
11428
11462
|
}
|
|
11429
11463
|
async function entryTarget(path) {
|
|
11430
11464
|
if (!BIN_ENTRY.test(path) || !(await virtual(path))?.isFile) return void 0;
|
|
11431
|
-
if (!await fs.lstat(path).then(() => false,
|
|
11465
|
+
if (!await fs.lstat(path).then(() => false, missing4)) return void 0;
|
|
11432
11466
|
const target = await targetOf2(path);
|
|
11433
11467
|
return target?.path === path ? void 0 : target;
|
|
11434
11468
|
}
|
|
@@ -11440,11 +11474,11 @@ function withCommandDirs(fs, names2, userDir = async () => void 0, owners = fals
|
|
|
11440
11474
|
return target?.path;
|
|
11441
11475
|
}
|
|
11442
11476
|
const absent2 = (err) => {
|
|
11443
|
-
if (
|
|
11477
|
+
if (missing4(err)) return EMPTY2;
|
|
11444
11478
|
throw err;
|
|
11445
11479
|
};
|
|
11446
11480
|
async function content(path, err) {
|
|
11447
|
-
if (!
|
|
11481
|
+
if (!missing4(err) || !(await linked2(path))?.isFile) throw err;
|
|
11448
11482
|
const target = await redirected2(path);
|
|
11449
11483
|
return target === void 0 ? EMPTY2 : fs.readFileBuffer(target).catch(absent2);
|
|
11450
11484
|
}
|
|
@@ -11453,7 +11487,7 @@ function withCommandDirs(fs, names2, userDir = async () => void 0, owners = fals
|
|
|
11453
11487
|
try {
|
|
11454
11488
|
return await real(path);
|
|
11455
11489
|
} catch (err) {
|
|
11456
|
-
const found =
|
|
11490
|
+
const found = missing4(err) ? await linked2(path) : void 0;
|
|
11457
11491
|
if (found) return found;
|
|
11458
11492
|
throw err;
|
|
11459
11493
|
}
|
|
@@ -11478,7 +11512,7 @@ function withCommandDirs(fs, names2, userDir = async () => void 0, owners = fals
|
|
|
11478
11512
|
const extra = await children3(path);
|
|
11479
11513
|
if (!extra) return fs.readdir(path);
|
|
11480
11514
|
const real = await fs.readdir(path).catch((err) => {
|
|
11481
|
-
if (
|
|
11515
|
+
if (missing4(err)) return [];
|
|
11482
11516
|
throw err;
|
|
11483
11517
|
});
|
|
11484
11518
|
return [.../* @__PURE__ */ new Set([...real, ...extra])].sort();
|
|
@@ -11487,7 +11521,7 @@ function withCommandDirs(fs, names2, userDir = async () => void 0, owners = fals
|
|
|
11487
11521
|
const extra = await children3(path);
|
|
11488
11522
|
if (!extra) return fs.readdirStat(path);
|
|
11489
11523
|
const real = await fs.readdirStat(path).catch((err) => {
|
|
11490
|
-
if (
|
|
11524
|
+
if (missing4(err)) return [];
|
|
11491
11525
|
throw err;
|
|
11492
11526
|
});
|
|
11493
11527
|
const seen = new Set(real.map(([name2]) => name2));
|
|
@@ -11521,7 +11555,7 @@ function withCommandDirs(fs, names2, userDir = async () => void 0, owners = fals
|
|
|
11521
11555
|
...ranged2 ? {
|
|
11522
11556
|
...ranged2,
|
|
11523
11557
|
pread: (path, offset, length2, version) => ranged2.pread(path, offset, length2, version).catch(async (err) => {
|
|
11524
|
-
const target =
|
|
11558
|
+
const target = missing4(err) ? await redirected2(path) : void 0;
|
|
11525
11559
|
if (target === void 0) throw err;
|
|
11526
11560
|
return ranged2.pread(target, offset, length2).catch(absent2);
|
|
11527
11561
|
})
|
|
@@ -11552,7 +11586,7 @@ var S_IFREG3 = 32768;
|
|
|
11552
11586
|
var MAX_HOPS2 = 40;
|
|
11553
11587
|
var parentOf6 = (path) => path.slice(0, path.lastIndexOf("/")) || "/";
|
|
11554
11588
|
var baseOf2 = (path) => path.slice(path.lastIndexOf("/") + 1);
|
|
11555
|
-
function
|
|
11589
|
+
function missing5(err) {
|
|
11556
11590
|
return err?.code === "ENOENT";
|
|
11557
11591
|
}
|
|
11558
11592
|
function statOf(path, bytes) {
|
|
@@ -11605,11 +11639,11 @@ function withEtcFiles(fs, files) {
|
|
|
11605
11639
|
const text = files.get(path)?.();
|
|
11606
11640
|
return text === void 0 ? void 0 : new TextEncoder().encode(text);
|
|
11607
11641
|
};
|
|
11608
|
-
const absent2 = (path) => fs.lstat(path).then(() => false,
|
|
11642
|
+
const absent2 = (path) => fs.lstat(path).then(() => false, missing5);
|
|
11609
11643
|
const follow2 = linkFollower(fs, files);
|
|
11610
11644
|
const listedAbsent = async (path) => files.has(path) && await absent2(path) ? bytesOf2(path) : void 0;
|
|
11611
11645
|
const fallback = (path, make) => async (err) => {
|
|
11612
|
-
const at =
|
|
11646
|
+
const at = missing5(err) ? await follow2(path) : void 0;
|
|
11613
11647
|
const bytes = at === void 0 ? void 0 : await listedAbsent(at);
|
|
11614
11648
|
if (bytes === void 0 || at === void 0) throw err;
|
|
11615
11649
|
return make(bytes, at);
|
|
@@ -13509,29 +13543,29 @@ var HeldSet = class extends Set {
|
|
|
13509
13543
|
this.idle = idle2;
|
|
13510
13544
|
this.moved = moved2;
|
|
13511
13545
|
}
|
|
13512
|
-
add(
|
|
13513
|
-
|
|
13514
|
-
|
|
13515
|
-
return super.add(
|
|
13546
|
+
add(holds3) {
|
|
13547
|
+
holds3.onIdle = this.idle;
|
|
13548
|
+
holds3.onMoved = this.moved;
|
|
13549
|
+
return super.add(holds3);
|
|
13516
13550
|
}
|
|
13517
13551
|
doubt(paths, over) {
|
|
13518
|
-
for (const
|
|
13519
|
-
for (const path of paths)
|
|
13520
|
-
if (over !== void 0)
|
|
13552
|
+
for (const holds3 of this) {
|
|
13553
|
+
for (const path of paths) holds3.doubt(path, true);
|
|
13554
|
+
if (over !== void 0) holds3.doubt(over);
|
|
13521
13555
|
}
|
|
13522
13556
|
}
|
|
13523
13557
|
async bindIds(id2) {
|
|
13524
|
-
for (const
|
|
13558
|
+
for (const holds3 of [...this]) await holds3.bindIds(id2);
|
|
13525
13559
|
}
|
|
13526
13560
|
heldIds() {
|
|
13527
13561
|
const out = /* @__PURE__ */ new Map();
|
|
13528
|
-
for (const
|
|
13562
|
+
for (const holds3 of this) for (const [path, fid] of holds3.heldIds()) out.set(path, fid);
|
|
13529
13563
|
return [...out];
|
|
13530
13564
|
}
|
|
13531
|
-
delete(
|
|
13532
|
-
const removed = super.delete(
|
|
13533
|
-
for (const path of /* @__PURE__ */ new Set([...
|
|
13534
|
-
|
|
13565
|
+
delete(holds3) {
|
|
13566
|
+
const removed = super.delete(holds3);
|
|
13567
|
+
for (const path of /* @__PURE__ */ new Set([...holds3.keys(), ...holds3.opens.keys()])) this.idle(path);
|
|
13568
|
+
holds3.releaseAll();
|
|
13535
13569
|
return removed;
|
|
13536
13570
|
}
|
|
13537
13571
|
};
|
|
@@ -16422,9 +16456,9 @@ var SYS_TREE = {
|
|
|
16422
16456
|
`,
|
|
16423
16457
|
slicc_file_ids: (listing) => `${listing.fileIds ?? 0}
|
|
16424
16458
|
`,
|
|
16425
|
-
slicc_peer_holds: ({ holds:
|
|
16459
|
+
slicc_peer_holds: ({ holds: holds3 }) => `${holds3?.mine ?? 0} ${holds3?.peers ?? 0} ${holds3?.sent ?? 0}
|
|
16426
16460
|
`,
|
|
16427
|
-
slicc_peer_held: ({ holds:
|
|
16461
|
+
slicc_peer_held: ({ holds: holds3 }) => (holds3?.held ?? []).map((path) => `${path}
|
|
16428
16462
|
`).join(""),
|
|
16429
16463
|
slicc_rename_acks: (listing) => {
|
|
16430
16464
|
const samples = [...listing.renameAcks?.ackMs ?? []].sort((a, b) => a - b);
|
|
@@ -17165,11 +17199,11 @@ var EpollFile = class _EpollFile {
|
|
|
17165
17199
|
const round = new AbortController();
|
|
17166
17200
|
const stop = () => round.abort();
|
|
17167
17201
|
signal.addEventListener("abort", stop, { once: true });
|
|
17168
|
-
let
|
|
17202
|
+
let failed4 = false;
|
|
17169
17203
|
try {
|
|
17170
17204
|
await file.changed(round.signal);
|
|
17171
17205
|
} catch {
|
|
17172
|
-
|
|
17206
|
+
failed4 = true;
|
|
17173
17207
|
} finally {
|
|
17174
17208
|
round.abort();
|
|
17175
17209
|
signal.removeEventListener("abort", stop);
|
|
@@ -17177,7 +17211,7 @@ var EpollFile = class _EpollFile {
|
|
|
17177
17211
|
if (signal.aborted) return;
|
|
17178
17212
|
reg.gen++;
|
|
17179
17213
|
this.changes.wake();
|
|
17180
|
-
if (
|
|
17214
|
+
if (failed4) await pause(RETRY_MS, signal);
|
|
17181
17215
|
}
|
|
17182
17216
|
}
|
|
17183
17217
|
};
|
|
@@ -18158,11 +18192,11 @@ function ipv6(host) {
|
|
|
18158
18192
|
const back = halves.length === 2 ? groups(halves[1]) : [];
|
|
18159
18193
|
if (![...head, ...back].every((g) => /^[0-9A-Fa-f]{1,4}$/.test(g))) return void 0;
|
|
18160
18194
|
const words2 = [...head, ...back].map((g) => Number.parseInt(g, 16));
|
|
18161
|
-
const
|
|
18162
|
-
if (halves.length === 2 ?
|
|
18195
|
+
const missing6 = 8 - words2.length - tail2.length;
|
|
18196
|
+
if (halves.length === 2 ? missing6 < 1 : missing6 !== 0) return void 0;
|
|
18163
18197
|
const all = [
|
|
18164
18198
|
...head.map((g) => Number.parseInt(g, 16)),
|
|
18165
|
-
...new Array(halves.length === 2 ?
|
|
18199
|
+
...new Array(halves.length === 2 ? missing6 : 0).fill(0),
|
|
18166
18200
|
...back.map((g) => Number.parseInt(g, 16)),
|
|
18167
18201
|
...tail2
|
|
18168
18202
|
];
|
|
@@ -19207,10 +19241,12 @@ var HttpHandles = class {
|
|
|
19207
19241
|
ws;
|
|
19208
19242
|
owner;
|
|
19209
19243
|
local;
|
|
19210
|
-
|
|
19244
|
+
stamp;
|
|
19245
|
+
constructor(transport, owner, local2, stamp) {
|
|
19211
19246
|
this.transport = transport;
|
|
19212
19247
|
this.owner = owner;
|
|
19213
19248
|
this.local = local2;
|
|
19249
|
+
this.stamp = stamp;
|
|
19214
19250
|
this.ws = new WsHandles(transport, () => ++this.nextHandle, local2);
|
|
19215
19251
|
}
|
|
19216
19252
|
syscall(req) {
|
|
@@ -19286,7 +19322,7 @@ var HttpHandles = class {
|
|
|
19286
19322
|
...entry.upload ? { bodyStream: entry.upload } : req.body ? { body: req.body } : {},
|
|
19287
19323
|
signal: entry.abort.signal
|
|
19288
19324
|
};
|
|
19289
|
-
const response = port === void 0 ? await this.transport.fetch(request3, this.owner) : await this.local.fetch(request3, port);
|
|
19325
|
+
const response = port === void 0 ? await this.transport.fetch(request3, this.owner, await this.stamp?.()) : await this.local.fetch(request3, port);
|
|
19290
19326
|
entry.body = response.body[Symbol.asyncIterator]();
|
|
19291
19327
|
entry.cancel = () => response.cancel();
|
|
19292
19328
|
if (!this.open.has(handle)) await entry.cancel().catch(() => void 0);
|
|
@@ -19308,8 +19344,8 @@ var HttpHandles = class {
|
|
|
19308
19344
|
if (text === NO_TRANSPORT || typeof status !== "number" || status === 502) {
|
|
19309
19345
|
const code = codeOf2(e);
|
|
19310
19346
|
const errno3 = text === NO_TRANSPORT ? "ENETUNREACH" : code !== "EIO" ? code : "ECONNREFUSED";
|
|
19311
|
-
const
|
|
19312
|
-
return { ok: false, errno: errno3, message: text, ...
|
|
19347
|
+
const failed4 = e.detail === "transport";
|
|
19348
|
+
return { ok: false, errno: errno3, message: text, ...failed4 ? { detail: "transport" } : {} };
|
|
19313
19349
|
}
|
|
19314
19350
|
entry.body = once(new TextEncoder().encode(text))[Symbol.asyncIterator]();
|
|
19315
19351
|
return this.headOf(handle, req.url, {
|
|
@@ -21216,7 +21252,7 @@ function pass(c, input, final) {
|
|
|
21216
21252
|
const partials = [];
|
|
21217
21253
|
scanMain(c, input, best, partials);
|
|
21218
21254
|
scanWrapped(c, input, best, partials);
|
|
21219
|
-
const
|
|
21255
|
+
const holds3 = final ? [] : [...new Set(partials)].sort((a, b) => a - b);
|
|
21220
21256
|
const starts = [...best.keys()].sort((a, b) => a - b);
|
|
21221
21257
|
const parts2 = [];
|
|
21222
21258
|
const hits = /* @__PURE__ */ new Map();
|
|
@@ -21226,8 +21262,8 @@ function pass(c, input, final) {
|
|
|
21226
21262
|
let h = 0;
|
|
21227
21263
|
for (; ; ) {
|
|
21228
21264
|
while (s < starts.length && starts[s] < pos) s++;
|
|
21229
|
-
while (h <
|
|
21230
|
-
const hold = h <
|
|
21265
|
+
while (h < holds3.length && holds3[h] < pos) h++;
|
|
21266
|
+
const hold = h < holds3.length ? holds3[h] : Infinity;
|
|
21231
21267
|
const next3 = s < starts.length ? starts[s] : Infinity;
|
|
21232
21268
|
if (hold <= next3) {
|
|
21233
21269
|
cut = Math.min(hold, input.length);
|
|
@@ -21329,23 +21365,23 @@ function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
|
|
|
21329
21365
|
let pending = 0;
|
|
21330
21366
|
let busy = false;
|
|
21331
21367
|
let timer;
|
|
21332
|
-
let
|
|
21368
|
+
let failed4;
|
|
21333
21369
|
const waiters = /* @__PURE__ */ new Set();
|
|
21334
21370
|
const quiet2 = () => !busy && pending === 0;
|
|
21335
21371
|
const wake = () => {
|
|
21336
21372
|
for (const waiter of [...waiters]) waiter();
|
|
21337
21373
|
};
|
|
21338
21374
|
const raise = () => {
|
|
21339
|
-
if (
|
|
21340
|
-
const err =
|
|
21341
|
-
|
|
21375
|
+
if (failed4 === void 0) return;
|
|
21376
|
+
const err = failed4;
|
|
21377
|
+
failed4 = void 0;
|
|
21342
21378
|
throw err;
|
|
21343
21379
|
};
|
|
21344
21380
|
const later = (bytes) => {
|
|
21345
21381
|
if (bytes.length === 0) return;
|
|
21346
21382
|
pending += 1;
|
|
21347
21383
|
tail2 = tail2.then(() => writeAll3(file, bytes)).catch((err) => {
|
|
21348
|
-
if (
|
|
21384
|
+
if (failed4 === void 0) failed4 = err;
|
|
21349
21385
|
}).finally(() => {
|
|
21350
21386
|
pending -= 1;
|
|
21351
21387
|
if (quiet2()) wake();
|
|
@@ -24420,7 +24456,7 @@ async function connect(req, proc) {
|
|
|
24420
24456
|
}
|
|
24421
24457
|
const path = filePath(req.addr);
|
|
24422
24458
|
const name2 = path !== void 0 ? await proc.names?.find(path) : void 0;
|
|
24423
|
-
const stamp = proc.net.
|
|
24459
|
+
const stamp = proc.net.stampsPeers(req.addr) && await proc.stamp?.();
|
|
24424
24460
|
const dialing = target.connect(req.addr, true, proc.cred?.(), stamp || void 0, true, name2);
|
|
24425
24461
|
if (req.nonblock) {
|
|
24426
24462
|
dialing?.catch(() => void 0);
|
|
@@ -24542,7 +24578,7 @@ async function secureConnect(req, proc) {
|
|
|
24542
24578
|
delete req.clientCert;
|
|
24543
24579
|
throw new KernelError("ENOTSUP");
|
|
24544
24580
|
}
|
|
24545
|
-
return { ...tlsOverTransport(req, proc), path: "transport", substitutes: true };
|
|
24581
|
+
return { ...await tlsOverTransport(req, proc), path: "transport", substitutes: true };
|
|
24546
24582
|
}
|
|
24547
24583
|
const socket = proc.net.socket("inet");
|
|
24548
24584
|
const fd = proc.fds.install(new OpenFile(socket), 3);
|
|
@@ -24561,7 +24597,7 @@ async function uplinked(proc, host) {
|
|
|
24561
24597
|
return false;
|
|
24562
24598
|
}
|
|
24563
24599
|
}
|
|
24564
|
-
function tlsOverTransport(req, proc) {
|
|
24600
|
+
async function tlsOverTransport(req, proc) {
|
|
24565
24601
|
if (req.ca) throw new KernelError("ENOTSUP");
|
|
24566
24602
|
if (req.alpn && req.alpn.length > 0 && !req.alpn.includes("http/1.1")) {
|
|
24567
24603
|
throw new KernelError("EPROTONOSUPPORT");
|
|
@@ -24574,7 +24610,9 @@ function tlsOverTransport(req, proc) {
|
|
|
24574
24610
|
if (isLoopbackHost(servername) || isLoopbackHost(req.host)) throw new KernelError("ENOTSUP");
|
|
24575
24611
|
const host = servername.includes(":") && !servername.startsWith("[") ? `[${servername}]` : servername;
|
|
24576
24612
|
const origin = req.port === 443 ? `https://${host}` : `https://${host}:${req.port}`;
|
|
24613
|
+
const stamp = proc.net.originsStamped ? await proc.stamp?.() : void 0;
|
|
24577
24614
|
const [mine, theirs] = KernelSocket.pair(proc.net, "inet", proc.cred?.());
|
|
24615
|
+
theirs.peerStamp = stamp;
|
|
24578
24616
|
mine.peer = { family: "inet", host: req.host, port: req.port };
|
|
24579
24617
|
try {
|
|
24580
24618
|
proc.net.serveOrigin(theirs, origin);
|
|
@@ -27733,13 +27771,13 @@ function inherited(opts) {
|
|
|
27733
27771
|
...opts.cred ? { cred: opts.cred } : {}
|
|
27734
27772
|
};
|
|
27735
27773
|
}
|
|
27736
|
-
function heldBy(process,
|
|
27737
|
-
process.keptPath = (path) =>
|
|
27738
|
-
process.keptHandle = (handle) =>
|
|
27739
|
-
process.holdsHandle = (handle) =>
|
|
27774
|
+
function heldBy(process, holds3, replacements) {
|
|
27775
|
+
process.keptPath = (path) => holds3.keptAt(path)?.hidden;
|
|
27776
|
+
process.keptHandle = (handle) => holds3.keptFor(handle)?.hidden;
|
|
27777
|
+
process.holdsHandle = (handle) => holds3.holdsHandle(handle);
|
|
27740
27778
|
if (replacements) process.replacements = replacements;
|
|
27741
27779
|
}
|
|
27742
|
-
function holdingToken(opts,
|
|
27780
|
+
function holdingToken(opts, holds3, caller) {
|
|
27743
27781
|
return mintSyncFsToken({
|
|
27744
27782
|
...opts.owners ? caller : { umask: caller.umask },
|
|
27745
27783
|
...opts.dac ? { dac: opts.dac, pid: opts.pid, created: caller.created } : {},
|
|
@@ -27756,16 +27794,16 @@ function holdingToken(opts, holds2, caller) {
|
|
|
27756
27794
|
...opts.fileId ? { fileId: opts.fileId } : {},
|
|
27757
27795
|
...opts.announceHold ? { announceHold: opts.announceHold } : {},
|
|
27758
27796
|
...opts.renameSeq ? { renameSeq: opts.renameSeq } : {},
|
|
27759
|
-
hold: (path, on, open2, real, handle, ino, fid) =>
|
|
27760
|
-
boundIno:
|
|
27761
|
-
trust:
|
|
27762
|
-
keptFor: (handle) =>
|
|
27763
|
-
heldAt: (handle) =>
|
|
27764
|
-
unlinked: (path) =>
|
|
27765
|
-
gate: (path, op) => opts.unlinkGate &&
|
|
27766
|
-
own: (path, op) =>
|
|
27767
|
-
revoked: (path) =>
|
|
27768
|
-
renamed: (from, to) =>
|
|
27797
|
+
hold: (path, on, open2, real, handle, ino, fid) => holds3.hold(path, on, open2, real, handle, ino, fid),
|
|
27798
|
+
boundIno: holds3.boundIno.bind(holds3),
|
|
27799
|
+
trust: holds3.trust.bind(holds3),
|
|
27800
|
+
keptFor: (handle) => holds3.keptFor(handle),
|
|
27801
|
+
heldAt: (handle) => holds3.pathOf(handle),
|
|
27802
|
+
unlinked: (path) => holds3.keptAt(path),
|
|
27803
|
+
gate: (path, op) => opts.unlinkGate && holds3.holding(path) ? opts.unlinkGate.run(holds3.keyOf(path), op) : op(),
|
|
27804
|
+
own: (path, op) => holds3.own(path, op),
|
|
27805
|
+
revoked: (path) => holds3.isRevoked(path),
|
|
27806
|
+
renamed: (from, to) => holds3.renamed(from, to)
|
|
27769
27807
|
});
|
|
27770
27808
|
}
|
|
27771
27809
|
function linksOf(opts) {
|
|
@@ -27922,15 +27960,15 @@ function spawnWasmProcess(opts) {
|
|
|
27922
27960
|
)
|
|
27923
27961
|
);
|
|
27924
27962
|
publishStops(process, header4);
|
|
27925
|
-
const
|
|
27926
|
-
opts.held?.add(
|
|
27927
|
-
const token = holdingToken(opts,
|
|
27963
|
+
const holds3 = new HeldPaths();
|
|
27964
|
+
opts.held?.add(holds3);
|
|
27965
|
+
const token = holdingToken(opts, holds3, {
|
|
27928
27966
|
cred: () => process.cred,
|
|
27929
27967
|
umask: () => process.umask,
|
|
27930
27968
|
created: created4,
|
|
27931
|
-
holdsKept: async (path) => path.includes(`/${UNLINKED_DIR}/`) && (
|
|
27969
|
+
holdsKept: async (path) => path.includes(`/${UNLINKED_DIR}/`) && (holds3.keeps(path) || await process.holds(path))
|
|
27932
27970
|
});
|
|
27933
|
-
heldBy(process,
|
|
27971
|
+
heldBy(process, holds3, opts.replacements);
|
|
27934
27972
|
const worker = opts.createWorker();
|
|
27935
27973
|
const dying = new Dying();
|
|
27936
27974
|
const dispatch2 = (req, block) => dying.serve(
|
|
@@ -27962,7 +28000,7 @@ function spawnWasmProcess(opts) {
|
|
|
27962
28000
|
responder.dispose();
|
|
27963
28001
|
lane?.dispose();
|
|
27964
28002
|
revokeSyncFsToken(token);
|
|
27965
|
-
opts.held?.delete(
|
|
28003
|
+
opts.held?.delete(holds3);
|
|
27966
28004
|
worker.terminate();
|
|
27967
28005
|
settleExit(process.exit(), settle3, code);
|
|
27968
28006
|
};
|
|
@@ -29148,7 +29186,7 @@ var RemoteTransport = class {
|
|
|
29148
29186
|
waiter?.reject(new TransportError("the request was cancelled"));
|
|
29149
29187
|
this.port.postMessage({ net: "cancel", nid });
|
|
29150
29188
|
}
|
|
29151
|
-
async fetch(request3) {
|
|
29189
|
+
async fetch(request3, owner, stamp) {
|
|
29152
29190
|
const nid = ++this.nextId;
|
|
29153
29191
|
const { signal, redirect } = request3;
|
|
29154
29192
|
signal.throwIfAborted();
|
|
@@ -29178,7 +29216,9 @@ var RemoteTransport = class {
|
|
|
29178
29216
|
method: request3.method,
|
|
29179
29217
|
headers: request3.headers,
|
|
29180
29218
|
...request3.bodyStream ? { streamed: true } : request3.body ? { body: request3.body } : {},
|
|
29181
|
-
...redirect !== void 0 ? { redirect } : {}
|
|
29219
|
+
...redirect !== void 0 ? { redirect } : {},
|
|
29220
|
+
...owner !== void 0 ? { owner } : {},
|
|
29221
|
+
...stamp ? { stamp } : {}
|
|
29182
29222
|
});
|
|
29183
29223
|
} catch (e) {
|
|
29184
29224
|
finish();
|
|
@@ -29369,6 +29409,143 @@ function replayingHops(inner, heldMs = HELD_MS) {
|
|
|
29369
29409
|
};
|
|
29370
29410
|
}
|
|
29371
29411
|
|
|
29412
|
+
// src/kernel/net/sealed-fetch.ts
|
|
29413
|
+
var UNSAFE_FIELD = /[\r\n\0]/;
|
|
29414
|
+
function headerList(headers) {
|
|
29415
|
+
return Array.isArray(headers) && headers.every(
|
|
29416
|
+
(field4) => Array.isArray(field4) && field4.length === 2 && field4.every((text) => typeof text === "string" && !UNSAFE_FIELD.test(text))
|
|
29417
|
+
);
|
|
29418
|
+
}
|
|
29419
|
+
function sealedReplyValid(reply) {
|
|
29420
|
+
if (typeof reply !== "object" || reply === null) return false;
|
|
29421
|
+
const { redirects, redirected: redirected2, status, statusText, headers, url, body, cancel } = reply;
|
|
29422
|
+
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";
|
|
29423
|
+
}
|
|
29424
|
+
function dropSealedReply(reply) {
|
|
29425
|
+
const { cancel } = reply ?? {};
|
|
29426
|
+
if (typeof cancel !== "function") return;
|
|
29427
|
+
void Promise.resolve().then(() => cancel.call(reply)).catch(() => void 0);
|
|
29428
|
+
}
|
|
29429
|
+
function failed2(reason) {
|
|
29430
|
+
const text = reason instanceof Error ? reason.message : String(reason);
|
|
29431
|
+
return new PlaceholderRefused(
|
|
29432
|
+
`refused: the request with a sealed placeholder was not completed: ${text}`
|
|
29433
|
+
);
|
|
29434
|
+
}
|
|
29435
|
+
var Stall = class {
|
|
29436
|
+
idle = new AbortController();
|
|
29437
|
+
ms;
|
|
29438
|
+
timer;
|
|
29439
|
+
signal;
|
|
29440
|
+
constructor(signals, ms) {
|
|
29441
|
+
this.ms = ms;
|
|
29442
|
+
this.signal = AbortSignal.any([...signals, this.idle.signal]);
|
|
29443
|
+
}
|
|
29444
|
+
arm() {
|
|
29445
|
+
clearTimeout(this.timer);
|
|
29446
|
+
this.timer = setTimeout(() => this.idle.abort("timeout"), this.ms);
|
|
29447
|
+
this.timer.unref?.();
|
|
29448
|
+
}
|
|
29449
|
+
touch() {
|
|
29450
|
+
if (this.timer !== void 0) this.arm();
|
|
29451
|
+
}
|
|
29452
|
+
rest() {
|
|
29453
|
+
clearTimeout(this.timer);
|
|
29454
|
+
this.timer = void 0;
|
|
29455
|
+
}
|
|
29456
|
+
};
|
|
29457
|
+
async function until(work, signal) {
|
|
29458
|
+
const stopped = Promise.withResolvers();
|
|
29459
|
+
const stop = () => stopped.reject(signal.reason);
|
|
29460
|
+
if (signal.aborted) stop();
|
|
29461
|
+
else signal.addEventListener("abort", stop, { once: true });
|
|
29462
|
+
try {
|
|
29463
|
+
return await Promise.race([work, stopped.promise]);
|
|
29464
|
+
} finally {
|
|
29465
|
+
signal.removeEventListener("abort", stop);
|
|
29466
|
+
}
|
|
29467
|
+
}
|
|
29468
|
+
async function* ticking(stream, stall) {
|
|
29469
|
+
for await (const chunk2 of stream) {
|
|
29470
|
+
stall.touch();
|
|
29471
|
+
yield chunk2;
|
|
29472
|
+
}
|
|
29473
|
+
}
|
|
29474
|
+
function sealedRequest(request3, stamp, stall) {
|
|
29475
|
+
const { method, url, headers, body, bodyStream } = request3;
|
|
29476
|
+
return {
|
|
29477
|
+
v: 1,
|
|
29478
|
+
caller: structuredClone(stamp),
|
|
29479
|
+
method,
|
|
29480
|
+
url,
|
|
29481
|
+
headers: headers.map(([name2, value2]) => [name2, value2]),
|
|
29482
|
+
redirect: "manual",
|
|
29483
|
+
...bodyStream ? { bodyStream: ticking(bodyStream, stall) } : body ? { body } : {}
|
|
29484
|
+
};
|
|
29485
|
+
}
|
|
29486
|
+
function guarded2(reply, stall) {
|
|
29487
|
+
let finished = false;
|
|
29488
|
+
const cancel = async () => {
|
|
29489
|
+
stall.signal.removeEventListener("abort", dropped2);
|
|
29490
|
+
stall.rest();
|
|
29491
|
+
if (finished) return;
|
|
29492
|
+
finished = true;
|
|
29493
|
+
await reply.cancel().catch(() => void 0);
|
|
29494
|
+
};
|
|
29495
|
+
const dropped2 = () => void cancel();
|
|
29496
|
+
stall.signal.addEventListener("abort", dropped2, { once: true });
|
|
29497
|
+
const source = reply.body[Symbol.asyncIterator]();
|
|
29498
|
+
const body = (async function* () {
|
|
29499
|
+
try {
|
|
29500
|
+
for (; ; ) {
|
|
29501
|
+
stall.arm();
|
|
29502
|
+
const next3 = await until(source.next(), stall.signal);
|
|
29503
|
+
stall.rest();
|
|
29504
|
+
if (next3.done) {
|
|
29505
|
+
finished = true;
|
|
29506
|
+
return;
|
|
29507
|
+
}
|
|
29508
|
+
if (!(next3.value instanceof Uint8Array)) throw failed2("a body chunk is not bytes");
|
|
29509
|
+
if (next3.value.byteLength > 0) yield next3.value;
|
|
29510
|
+
}
|
|
29511
|
+
} finally {
|
|
29512
|
+
await cancel();
|
|
29513
|
+
}
|
|
29514
|
+
})();
|
|
29515
|
+
return {
|
|
29516
|
+
...reply.url !== void 0 ? { url: reply.url } : {},
|
|
29517
|
+
status: reply.status,
|
|
29518
|
+
statusText: reply.statusText,
|
|
29519
|
+
headers: reply.headers,
|
|
29520
|
+
body,
|
|
29521
|
+
cancel
|
|
29522
|
+
};
|
|
29523
|
+
}
|
|
29524
|
+
function sealedFetcher(hook, stop, idleMs = BODY_IDLE_MS) {
|
|
29525
|
+
return async (request3, stamp) => {
|
|
29526
|
+
const stall = new Stall([request3.signal, stop], idleMs);
|
|
29527
|
+
const { signal } = stall;
|
|
29528
|
+
if (signal.aborted) throw failed2(signal.reason);
|
|
29529
|
+
stall.arm();
|
|
29530
|
+
const asked = Promise.resolve().then(() => {
|
|
29531
|
+
signal.throwIfAborted();
|
|
29532
|
+
return hook(sealedRequest(request3, stamp, stall), { signal });
|
|
29533
|
+
});
|
|
29534
|
+
let reply;
|
|
29535
|
+
try {
|
|
29536
|
+
reply = await until(asked, signal);
|
|
29537
|
+
} catch (e) {
|
|
29538
|
+
void asked.then(dropSealedReply, () => void 0);
|
|
29539
|
+
throw failed2(e);
|
|
29540
|
+
} finally {
|
|
29541
|
+
stall.rest();
|
|
29542
|
+
}
|
|
29543
|
+
if (sealedReplyValid(reply)) return guarded2(reply, stall);
|
|
29544
|
+
dropSealedReply(reply);
|
|
29545
|
+
throw failed2("the reply is not a scrubbed response");
|
|
29546
|
+
};
|
|
29547
|
+
}
|
|
29548
|
+
|
|
29372
29549
|
// src/kernel/package-swaps.ts
|
|
29373
29550
|
var SWAP_GAP_MS = 2e3;
|
|
29374
29551
|
var STAGES = ["_tmp_", "_pacquet-stage_"];
|
|
@@ -29541,11 +29718,11 @@ var PackageLocks = class {
|
|
|
29541
29718
|
if (!locks) return Promise.resolve(() => {
|
|
29542
29719
|
});
|
|
29543
29720
|
const { promise: held, resolve: release } = Promise.withResolvers();
|
|
29544
|
-
return new Promise((granted2,
|
|
29721
|
+
return new Promise((granted2, failed4) => {
|
|
29545
29722
|
locks.request(replacingLock(this.metadata, root), { mode: "exclusive" }, () => {
|
|
29546
29723
|
granted2(() => release());
|
|
29547
29724
|
return held;
|
|
29548
|
-
}).catch(
|
|
29725
|
+
}).catch(failed4);
|
|
29549
29726
|
});
|
|
29550
29727
|
}
|
|
29551
29728
|
};
|
|
@@ -30147,22 +30324,22 @@ async function mountFstab(lines2, mount, signal, retries = FSTAB_RETRIES, discar
|
|
|
30147
30324
|
);
|
|
30148
30325
|
}
|
|
30149
30326
|
async function mountLine({ line, spec, invalid }, mount, signal, retries, discard) {
|
|
30150
|
-
let
|
|
30327
|
+
let failed4 = invalid;
|
|
30151
30328
|
for (let attempt = 0; !invalid && attempt <= retries.length && !signal.aborted; attempt++) {
|
|
30152
30329
|
try {
|
|
30153
30330
|
const entry = await mount(spec);
|
|
30154
30331
|
if (!signal.aborted) return { line, target: spec.target, entry };
|
|
30155
30332
|
discard(entry);
|
|
30156
|
-
|
|
30333
|
+
failed4 = Object.assign(new Error("the kernel stopped"), { code: "ECANCELED" });
|
|
30157
30334
|
break;
|
|
30158
30335
|
} catch (err) {
|
|
30159
|
-
|
|
30336
|
+
failed4 = err;
|
|
30160
30337
|
if (FINAL.has(codeOf6(err)) || attempt === retries.length) break;
|
|
30161
30338
|
await wait(retries[attempt], signal);
|
|
30162
30339
|
}
|
|
30163
30340
|
}
|
|
30164
|
-
const code = codeOf6(
|
|
30165
|
-
return { line, target: spec.target, code, error: String(
|
|
30341
|
+
const code = codeOf6(failed4);
|
|
30342
|
+
return { line, target: spec.target, code, error: String(failed4?.message ?? code) };
|
|
30166
30343
|
}
|
|
30167
30344
|
|
|
30168
30345
|
// src/mount/hostfs.ts
|
|
@@ -31336,7 +31513,7 @@ var RULE = new RegExp(
|
|
|
31336
31513
|
var TERM = /^[A-Za-z0-9._+-]+$/;
|
|
31337
31514
|
var PLAIN3 = /^[A-Za-z0-9_@%+=:,./-]+$/;
|
|
31338
31515
|
var USAGE = "usage: sudo [-n] [-u user] [--] command [args...]\n sudo -l";
|
|
31339
|
-
function
|
|
31516
|
+
function failed3(errno3, error) {
|
|
31340
31517
|
return { error, errno: errno3 };
|
|
31341
31518
|
}
|
|
31342
31519
|
function unescaped(double) {
|
|
@@ -31515,10 +31692,10 @@ var Sudo = class {
|
|
|
31515
31692
|
}
|
|
31516
31693
|
async untrusted(path, cwd, word) {
|
|
31517
31694
|
const files = this.o.backing ? await this.o.backing(path, cwd) : [];
|
|
31518
|
-
if (!files) return
|
|
31695
|
+
if (!files) return failed3("ENOENT", `sudo: ${word}: command not found`);
|
|
31519
31696
|
for (const file of [path, ...files]) {
|
|
31520
31697
|
if (!await this.trusted(file)) {
|
|
31521
|
-
return
|
|
31698
|
+
return failed3("EPERM", `sudo: ${file} must be root's, and writable by root only`);
|
|
31522
31699
|
}
|
|
31523
31700
|
}
|
|
31524
31701
|
return void 0;
|
|
@@ -31535,7 +31712,7 @@ var Sudo = class {
|
|
|
31535
31712
|
}
|
|
31536
31713
|
async request(caller, call, signal) {
|
|
31537
31714
|
const parsed2 = parseArgs(call.args);
|
|
31538
|
-
if (typeof parsed2 === "string") return
|
|
31715
|
+
if (typeof parsed2 === "string") return failed3("EINVAL", parsed2);
|
|
31539
31716
|
if (this.o.mode !== "enforce") {
|
|
31540
31717
|
const mode = this.o.mode;
|
|
31541
31718
|
if (parsed2.list) return { list: `sudo: users are '${mode}': commands run as the caller
|
|
@@ -31544,9 +31721,9 @@ var Sudo = class {
|
|
|
31544
31721
|
}
|
|
31545
31722
|
const { cred } = caller;
|
|
31546
31723
|
const self = await this.o.users.lookup(cred.ruid);
|
|
31547
|
-
if (!self) return
|
|
31724
|
+
if (!self) return failed3("EPERM", `sudo: uid ${cred.ruid} is not in the passwd database`);
|
|
31548
31725
|
const target = await this.lookup(parsed2.user);
|
|
31549
|
-
if (!target) return
|
|
31726
|
+
if (!target) return failed3("ENOENT", `sudo: unknown user ${parsed2.user}`);
|
|
31550
31727
|
const root = cred.euid === 0;
|
|
31551
31728
|
const rules = root ? [] : await this.policy();
|
|
31552
31729
|
const applies = await this.applies(self, cred);
|
|
@@ -31554,13 +31731,13 @@ var Sudo = class {
|
|
|
31554
31731
|
const [word = "", ...args] = parsed2.command;
|
|
31555
31732
|
const cwd = await this.canonical(call.cwd);
|
|
31556
31733
|
if (cwd === void 0 || !await this.reachable(cred, cwd)) {
|
|
31557
|
-
return
|
|
31734
|
+
return failed3(
|
|
31558
31735
|
"EACCES",
|
|
31559
31736
|
`sudo: cannot run in ${call.cwd}: it isn't a directory you can enter`
|
|
31560
31737
|
);
|
|
31561
31738
|
}
|
|
31562
31739
|
const path = await this.locate(word, cwd);
|
|
31563
|
-
if (!path) return
|
|
31740
|
+
if (!path) return failed3("ENOENT", `sudo: ${word}: command not found`);
|
|
31564
31741
|
const untrusted2 = await this.untrusted(path, cwd, word);
|
|
31565
31742
|
if (untrusted2) return untrusted2;
|
|
31566
31743
|
const argv = [path, ...args];
|
|
@@ -31571,24 +31748,24 @@ var Sudo = class {
|
|
|
31571
31748
|
if (root || matching.some((rule) => rule.nopasswd)) return grant();
|
|
31572
31749
|
const quoted = argv.map(quoteWord).join(" ");
|
|
31573
31750
|
if (matching.length === 0) {
|
|
31574
|
-
return
|
|
31751
|
+
return failed3(
|
|
31575
31752
|
"EPERM",
|
|
31576
31753
|
`sudo: ${self.name} is not allowed to run ${quoted} as ${target.name}`
|
|
31577
31754
|
);
|
|
31578
31755
|
}
|
|
31579
|
-
if (parsed2.nonInteractive) return
|
|
31580
|
-
if (this.pending.has(cred.ruid)) return
|
|
31756
|
+
if (parsed2.nonInteractive) return failed3("EPERM", "sudo: a password is required");
|
|
31757
|
+
if (this.pending.has(cred.ruid)) return failed3("EBUSY", "sudo: another request is pending");
|
|
31581
31758
|
this.pending.add(cred.ruid);
|
|
31582
31759
|
try {
|
|
31583
31760
|
const answer2 = await this.ask(caller, self, target, parsed2.command, path, cwd, signal);
|
|
31584
31761
|
if (typeof answer2 !== "string") return answer2;
|
|
31585
31762
|
if (await this.canonical(call.cwd) !== cwd || !await this.reachable(cred, cwd)) {
|
|
31586
|
-
return
|
|
31763
|
+
return failed3("EACCES", `sudo: ${call.cwd} changed while the request waited`);
|
|
31587
31764
|
}
|
|
31588
31765
|
const changed = await this.untrusted(path, cwd, word);
|
|
31589
31766
|
if (changed) return changed;
|
|
31590
31767
|
if (answer2 === "always" && !await this.remember(self, target, cwd, argv)) {
|
|
31591
|
-
return
|
|
31768
|
+
return failed3("EIO", "sudo: the rule could not be recorded");
|
|
31592
31769
|
}
|
|
31593
31770
|
return grant();
|
|
31594
31771
|
} finally {
|
|
@@ -31605,7 +31782,7 @@ var Sudo = class {
|
|
|
31605
31782
|
};
|
|
31606
31783
|
}
|
|
31607
31784
|
if (rules.length === 0) {
|
|
31608
|
-
return
|
|
31785
|
+
return failed3("EPERM", `User ${self.name} is not allowed to run sudo on ${host}.`);
|
|
31609
31786
|
}
|
|
31610
31787
|
const lines2 = rules.map(described).join("\n");
|
|
31611
31788
|
return { list: `User ${self.name} may run the following commands on ${host}:
|
|
@@ -31614,7 +31791,7 @@ ${lines2}
|
|
|
31614
31791
|
}
|
|
31615
31792
|
async ask(caller, self, target, argv, path, cwd, requester) {
|
|
31616
31793
|
const { approve } = this.o;
|
|
31617
|
-
if (!approve || requester.aborted) return
|
|
31794
|
+
if (!approve || requester.aborted) return failed3("EACCES", "sudo: approval denied");
|
|
31618
31795
|
const createdAt = Date.now();
|
|
31619
31796
|
const timeout = this.o.timeoutMs ?? SUDO_TIMEOUT_MS;
|
|
31620
31797
|
const req = {
|
|
@@ -31644,9 +31821,9 @@ ${lines2}
|
|
|
31644
31821
|
const answered2 = Promise.resolve().then(() => approve(req, { signal: control.signal })).catch(() => "deny");
|
|
31645
31822
|
const answer2 = await Promise.race([answered2, aborted3]);
|
|
31646
31823
|
if (answer2 === "aborted" || control.signal.aborted) {
|
|
31647
|
-
return control.signal.reason === "expired" ?
|
|
31824
|
+
return control.signal.reason === "expired" ? failed3("ETIMEDOUT", "sudo: the request expired") : failed3("EINTR", "sudo: the request was withdrawn");
|
|
31648
31825
|
}
|
|
31649
|
-
return answer2 === "once" || answer2 === "always" ? answer2 :
|
|
31826
|
+
return answer2 === "once" || answer2 === "always" ? answer2 : failed3("EACCES", "sudo: approval denied");
|
|
31650
31827
|
} finally {
|
|
31651
31828
|
clearTimeout(timer);
|
|
31652
31829
|
requester.removeEventListener("abort", withdraw);
|
|
@@ -31937,13 +32114,13 @@ function interpreter(head) {
|
|
|
31937
32114
|
function expandDefaults(defaults2, env) {
|
|
31938
32115
|
const out = {};
|
|
31939
32116
|
for (const [key, value2] of Object.entries(defaults2 ?? {})) {
|
|
31940
|
-
let
|
|
32117
|
+
let missing6 = false;
|
|
31941
32118
|
const expanded = value2.replace(ENV_REFERENCE, (_, name2) => {
|
|
31942
32119
|
const set3 = Object.hasOwn(env, name2) ? env[name2] : void 0;
|
|
31943
|
-
if (set3 === void 0)
|
|
32120
|
+
if (set3 === void 0) missing6 = true;
|
|
31944
32121
|
return set3 ?? "";
|
|
31945
32122
|
});
|
|
31946
|
-
if (!
|
|
32123
|
+
if (!missing6) out[key] = expanded;
|
|
31947
32124
|
}
|
|
31948
32125
|
return out;
|
|
31949
32126
|
}
|
|
@@ -32118,6 +32295,9 @@ var Launcher = class {
|
|
|
32118
32295
|
usersMode;
|
|
32119
32296
|
dac;
|
|
32120
32297
|
sealed;
|
|
32298
|
+
fill;
|
|
32299
|
+
fills = new AbortController();
|
|
32300
|
+
placeholders = [];
|
|
32121
32301
|
scrubs = /* @__PURE__ */ new Map();
|
|
32122
32302
|
clipboard;
|
|
32123
32303
|
embedder;
|
|
@@ -32199,7 +32379,7 @@ var Launcher = class {
|
|
|
32199
32379
|
...options.env
|
|
32200
32380
|
};
|
|
32201
32381
|
this.ca = kernelCa(options.caStore ?? memoryCaStore());
|
|
32202
|
-
this.transport =
|
|
32382
|
+
this.transport = this.floored(options);
|
|
32203
32383
|
this.announcedTraits = JSON.stringify(this.transport.traits);
|
|
32204
32384
|
this.uplink = options.uplink;
|
|
32205
32385
|
this.routes = new Routes(options.uplink?.traits.ipv6 === true);
|
|
@@ -33261,6 +33441,19 @@ var Launcher = class {
|
|
|
33261
33441
|
groupSession(pgid) {
|
|
33262
33442
|
return this.jobs.sessionOf(pgid);
|
|
33263
33443
|
}
|
|
33444
|
+
floored(options) {
|
|
33445
|
+
const { sealedFetch } = options;
|
|
33446
|
+
this.fill = sealedFetch && this.usersMode === "enforce" ? sealedFetcher(sealedFetch, this.fills.signal) : void 0;
|
|
33447
|
+
if (this.fill) this.net.stampProxy(REALM_PROXY_PORT);
|
|
33448
|
+
return placeholderFloor(replayingHops(options.transport ?? missingTransport()), {
|
|
33449
|
+
known: () => this.placeholders,
|
|
33450
|
+
...this.fill ? { fill: this.fill } : {}
|
|
33451
|
+
});
|
|
33452
|
+
}
|
|
33453
|
+
httpFor(pid) {
|
|
33454
|
+
const stamp = this.fill ? () => this.liveStamp(pid) : void 0;
|
|
33455
|
+
return new HttpHandles(this.transport, pid, this.loopbackFor(pid), stamp);
|
|
33456
|
+
}
|
|
33264
33457
|
loopbackFor(pid) {
|
|
33265
33458
|
return new KernelLoopback(
|
|
33266
33459
|
this.net,
|
|
@@ -33268,7 +33461,7 @@ var Launcher = class {
|
|
|
33268
33461
|
const cred = this.credOf(pid);
|
|
33269
33462
|
return { pid, uid: cred.euid, gid: cred.egid };
|
|
33270
33463
|
},
|
|
33271
|
-
() => this.
|
|
33464
|
+
() => this.liveStamp(pid)
|
|
33272
33465
|
);
|
|
33273
33466
|
}
|
|
33274
33467
|
sourceCheck(pid, writer) {
|
|
@@ -33433,7 +33626,7 @@ var Launcher = class {
|
|
|
33433
33626
|
jobs: this.jobs,
|
|
33434
33627
|
ptys: this.ptys,
|
|
33435
33628
|
net: this.net,
|
|
33436
|
-
http:
|
|
33629
|
+
http: this.httpFor(pid),
|
|
33437
33630
|
locks: this.locks,
|
|
33438
33631
|
fifos: this.fifos,
|
|
33439
33632
|
sems: this.sems,
|
|
@@ -33748,6 +33941,19 @@ var Launcher = class {
|
|
|
33748
33941
|
connectorStamp(pid) {
|
|
33749
33942
|
return this.sealed.stamp(this.identityOf(pid), this.credOf(pid), this.tagsOf(pid));
|
|
33750
33943
|
}
|
|
33944
|
+
async liveStamp(pid) {
|
|
33945
|
+
if (!this.creds.has(pid) || this.zombies.has(pid)) return void 0;
|
|
33946
|
+
return this.connectorStamp(pid);
|
|
33947
|
+
}
|
|
33948
|
+
setPlaceholders(list) {
|
|
33949
|
+
if (!Array.isArray(list) || !list.every((p) => typeof p === "string" && p !== "")) {
|
|
33950
|
+
throw fsError("EINVAL", "setPlaceholders takes a list of non-empty strings");
|
|
33951
|
+
}
|
|
33952
|
+
this.placeholders = [...list];
|
|
33953
|
+
}
|
|
33954
|
+
endFills() {
|
|
33955
|
+
this.fills.abort("terminated");
|
|
33956
|
+
}
|
|
33751
33957
|
identityOf(pid) {
|
|
33752
33958
|
const parent = this.jobs.shownParent(pid);
|
|
33753
33959
|
const alive = parent !== void 0 && this.running(parent);
|
|
@@ -33870,7 +34076,7 @@ var Launcher = class {
|
|
|
33870
34076
|
const at = normalizePath(path);
|
|
33871
34077
|
this.unlinked.closed(at);
|
|
33872
34078
|
this.writers?.unlinked.closed(at);
|
|
33873
|
-
const holding = [...this.held].some((
|
|
34079
|
+
const holding = [...this.held].some((holds3) => holds3.holding(at)) || [...this.openFiles].some((open3) => open3.holdsAt(at));
|
|
33874
34080
|
if (!holding) void this.rootFs.announceHolds?.([], [at], false);
|
|
33875
34081
|
const open2 = [...this.openFiles].some((nodes) => nodes.writes(at)) || heldUnder(this.held, at);
|
|
33876
34082
|
if (!open2) void this.mounts.commit(at).catch(() => void 0);
|
|
@@ -34033,8 +34239,9 @@ var Launcher = class {
|
|
|
34033
34239
|
for (const root of roots) this.integrity.forget(root);
|
|
34034
34240
|
this.resetCatalogs();
|
|
34035
34241
|
}
|
|
34036
|
-
attest(path) {
|
|
34242
|
+
attest(path, options = {}) {
|
|
34037
34243
|
return attest(this.rootFs, path, {
|
|
34244
|
+
...options,
|
|
34038
34245
|
users: this.usersMode,
|
|
34039
34246
|
mounts: this.mounts.list().map((entry) => entry.target).filter((target) => this.mounts.mounted(target) !== void 0)
|
|
34040
34247
|
});
|
|
@@ -34091,8 +34298,8 @@ var Launcher = class {
|
|
|
34091
34298
|
for (const name2 of names2 ?? []) {
|
|
34092
34299
|
const path = joinName(real, name2);
|
|
34093
34300
|
if (await this.base.hasOwner(path)) continue;
|
|
34094
|
-
const
|
|
34095
|
-
if (
|
|
34301
|
+
const failed4 = this.inUse(path) ? "busy" : await this.base.rm(path, { recursive: true, force: true }).catch(String);
|
|
34302
|
+
if (failed4 === void 0) removed++;
|
|
34096
34303
|
else left++;
|
|
34097
34304
|
}
|
|
34098
34305
|
if (removed > 0) {
|
|
@@ -34187,7 +34394,7 @@ var Launcher = class {
|
|
|
34187
34394
|
this.pnpmStale();
|
|
34188
34395
|
if (!detach) return;
|
|
34189
34396
|
for (const nodes of this.openFiles) nodes.revoke(at);
|
|
34190
|
-
for (const
|
|
34397
|
+
for (const holds3 of this.held) holds3.revoke(at);
|
|
34191
34398
|
}
|
|
34192
34399
|
unmountAll() {
|
|
34193
34400
|
this.cron.stop();
|
|
@@ -34398,9 +34605,9 @@ var Launcher = class {
|
|
|
34398
34605
|
}
|
|
34399
34606
|
boundTo(path, hidden, fids) {
|
|
34400
34607
|
const keeping = [...this.held].map(
|
|
34401
|
-
(
|
|
34402
|
-
|
|
34403
|
-
fids.flatMap((fid) => [...
|
|
34608
|
+
(holds3) => [
|
|
34609
|
+
holds3,
|
|
34610
|
+
fids.flatMap((fid) => [...holds3.boundAt(path, fid), ...holds3.boundAt(hidden, fid)])
|
|
34404
34611
|
]
|
|
34405
34612
|
).filter(([, ids]) => ids.length > 0);
|
|
34406
34613
|
const nodes = [...this.openFiles].filter(
|
|
@@ -34411,7 +34618,7 @@ var Launcher = class {
|
|
|
34411
34618
|
(open2) => fids.some((fid) => open2.keepBound([hidden, path], fid, file))
|
|
34412
34619
|
).length;
|
|
34413
34620
|
for (let i = kept; i < nodes.length; i++) file.release();
|
|
34414
|
-
for (const [
|
|
34621
|
+
for (const [holds3, ids] of keeping) holds3.keepBound(ids, path, file);
|
|
34415
34622
|
void this.rootFs.announceHolds?.([], [path, hidden], false);
|
|
34416
34623
|
};
|
|
34417
34624
|
return { keeping, nodes, keep: keep2 };
|
|
@@ -34571,7 +34778,7 @@ var Launcher = class {
|
|
|
34571
34778
|
}
|
|
34572
34779
|
moved(from, to, source) {
|
|
34573
34780
|
this.renameLog.add(from, to);
|
|
34574
|
-
for (const
|
|
34781
|
+
for (const holds3 of this.held) holds3.renamed(from, to);
|
|
34575
34782
|
if (source) return;
|
|
34576
34783
|
for (const nodes of this.openFiles) nodes.renamed(from, to);
|
|
34577
34784
|
this.watchers.moved(from, to);
|
|
@@ -34784,6 +34991,98 @@ function integrityAsker(port) {
|
|
|
34784
34991
|
}
|
|
34785
34992
|
|
|
34786
34993
|
// src/sealed-relay.ts
|
|
34994
|
+
function textOf(err) {
|
|
34995
|
+
return err instanceof Error ? err.message : String(err);
|
|
34996
|
+
}
|
|
34997
|
+
function sendBytes(port, bytes) {
|
|
34998
|
+
const copy = fresh(bytes);
|
|
34999
|
+
port.postMessage({ t: "chunk", bytes: copy }, [copy.buffer]);
|
|
35000
|
+
}
|
|
35001
|
+
function askFetch(port, req, signal) {
|
|
35002
|
+
signal.throwIfAborted();
|
|
35003
|
+
const { bodyStream, ...wire } = req;
|
|
35004
|
+
const { port1: near, port2: far } = new MessageChannel();
|
|
35005
|
+
const upload = bodyStream?.[Symbol.asyncIterator]();
|
|
35006
|
+
const head = Promise.withResolvers();
|
|
35007
|
+
let reading;
|
|
35008
|
+
let ended = false;
|
|
35009
|
+
const end = (failure2) => {
|
|
35010
|
+
if (ended) return;
|
|
35011
|
+
ended = true;
|
|
35012
|
+
signal.removeEventListener("abort", abort);
|
|
35013
|
+
near.close();
|
|
35014
|
+
void upload?.return?.().catch(() => void 0);
|
|
35015
|
+
head.reject(failure2);
|
|
35016
|
+
reading?.reject(failure2);
|
|
35017
|
+
reading = void 0;
|
|
35018
|
+
};
|
|
35019
|
+
const abort = () => {
|
|
35020
|
+
near.postMessage({ t: "cancel", reason: String(signal.reason) });
|
|
35021
|
+
end(new Error(String(signal.reason)));
|
|
35022
|
+
};
|
|
35023
|
+
const pull = async () => {
|
|
35024
|
+
try {
|
|
35025
|
+
const next3 = await upload.next();
|
|
35026
|
+
if (ended) return;
|
|
35027
|
+
if (next3.done) near.postMessage({ t: "end" });
|
|
35028
|
+
else sendBytes(near, next3.value);
|
|
35029
|
+
} catch (err) {
|
|
35030
|
+
if (!ended) near.postMessage({ t: "error", message: textOf(err) });
|
|
35031
|
+
}
|
|
35032
|
+
};
|
|
35033
|
+
const respond2 = (message3) => {
|
|
35034
|
+
const { status, statusText, headers, url } = message3;
|
|
35035
|
+
const body = {
|
|
35036
|
+
[Symbol.asyncIterator]: () => ({
|
|
35037
|
+
next: () => {
|
|
35038
|
+
if (ended) return Promise.resolve({ value: void 0, done: true });
|
|
35039
|
+
reading = Promise.withResolvers();
|
|
35040
|
+
near.postMessage({ t: "read" });
|
|
35041
|
+
return reading.promise;
|
|
35042
|
+
},
|
|
35043
|
+
return: async () => {
|
|
35044
|
+
await cancel();
|
|
35045
|
+
return { value: void 0, done: true };
|
|
35046
|
+
}
|
|
35047
|
+
})
|
|
35048
|
+
};
|
|
35049
|
+
const cancel = async () => {
|
|
35050
|
+
if (ended) return;
|
|
35051
|
+
near.postMessage({ t: "cancel", reason: "cancelled" });
|
|
35052
|
+
end(new Error("the request was cancelled"));
|
|
35053
|
+
};
|
|
35054
|
+
head.resolve({
|
|
35055
|
+
...url !== void 0 ? { url } : {},
|
|
35056
|
+
status,
|
|
35057
|
+
statusText,
|
|
35058
|
+
headers,
|
|
35059
|
+
body,
|
|
35060
|
+
cancel
|
|
35061
|
+
});
|
|
35062
|
+
};
|
|
35063
|
+
near.addEventListener("message", ({ data }) => {
|
|
35064
|
+
if (data.t === "pull") void pull();
|
|
35065
|
+
else if (data.t === "stop") void upload?.return?.().catch(() => void 0);
|
|
35066
|
+
else if (data.t === "head") respond2(data);
|
|
35067
|
+
else if (data.t === "chunk") {
|
|
35068
|
+
reading?.resolve({ value: data.bytes, done: false });
|
|
35069
|
+
reading = void 0;
|
|
35070
|
+
} else if (data.t === "end") {
|
|
35071
|
+
reading?.resolve({ value: void 0, done: true });
|
|
35072
|
+
reading = void 0;
|
|
35073
|
+
end(new Error("the response ended"));
|
|
35074
|
+
} else end(new Error(data.message));
|
|
35075
|
+
});
|
|
35076
|
+
near.addEventListener("close", () => end(new Error("the sealed fetch relay closed")));
|
|
35077
|
+
near.start();
|
|
35078
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
35079
|
+
const ask = {
|
|
35080
|
+
req: { ...wire, ...upload ? { streamed: true } : {} },
|
|
35081
|
+
port: far
|
|
35082
|
+
};
|
|
35083
|
+
port.postMessage({ sealedFetch: ask }, [far]);
|
|
35084
|
+
return head.promise;
|
|
35085
|
+
}
|
|
34787
35086
|
function sealedAsker(port) {
|
|
34788
35087
|
const asks = /* @__PURE__ */ new Map();
|
|
34789
35088
|
let next3 = 0;
|
|
@@ -34807,7 +35106,7 @@ function sealedAsker(port) {
|
|
|
34807
35106
|
if (reply) waiting.resolve(reply);
|
|
34808
35107
|
else waiting.reject(new Error(error ?? "no reply"));
|
|
34809
35108
|
};
|
|
34810
|
-
return { hook, answer: answer2 };
|
|
35109
|
+
return { hook, fetch: (req, { signal }) => askFetch(port, req, signal), answer: answer2 };
|
|
34811
35110
|
}
|
|
34812
35111
|
|
|
34813
35112
|
// src/serve.ts
|
|
@@ -34965,13 +35264,15 @@ function transferOf2(req, result) {
|
|
|
34965
35264
|
if (result instanceof MessagePort) return [result];
|
|
34966
35265
|
const bound3 = result?.port;
|
|
34967
35266
|
if (req.op === "connect" && bound3 instanceof MessagePort) return [bound3];
|
|
34968
|
-
if (req.op === "attest"
|
|
35267
|
+
if (req.op === "attest" && "bytes" in result) {
|
|
35268
|
+
return [result.bytes.buffer];
|
|
35269
|
+
}
|
|
34969
35270
|
return void 0;
|
|
34970
35271
|
}
|
|
34971
35272
|
function attestOps(port) {
|
|
34972
35273
|
const watches = /* @__PURE__ */ new Map();
|
|
34973
35274
|
return async (l, req) => {
|
|
34974
|
-
if (req.op === "attest") return l.attest(req.path);
|
|
35275
|
+
if (req.op === "attest") return l.attest(req.path, req.options);
|
|
34975
35276
|
if (req.op === "chmod") return l.fs.chmod(req.path, modeOption(req.mode)).then(() => true);
|
|
34976
35277
|
if (req.op === "integrity-revoke") return l.revokeIntegrity(req.path).then(() => true);
|
|
34977
35278
|
if (req.op === "unwatch-files") {
|
|
@@ -35026,7 +35327,7 @@ async function connectClient(deps, { user, tag, bind: bind2 }) {
|
|
|
35026
35327
|
});
|
|
35027
35328
|
return unbind ? { port: port2, client } : port2;
|
|
35028
35329
|
}
|
|
35029
|
-
function hostOptions(req, port, sealed, clipboard, lookup2, requests) {
|
|
35330
|
+
function hostOptions(req, port, sealed, sealedFetch, clipboard, lookup2, requests) {
|
|
35030
35331
|
return {
|
|
35031
35332
|
cron: { lock: `slicc-kernel-cron:${req.metadata ?? META_DB}` },
|
|
35032
35333
|
...req.hostname !== void 0 ? { hostname: req.hostname } : {},
|
|
@@ -35035,6 +35336,7 @@ function hostOptions(req, port, sealed, clipboard, lookup2, requests) {
|
|
|
35035
35336
|
...req.denials ? { onDenial: (denial) => port.postMessage({ denial }) } : {},
|
|
35036
35337
|
...req.protect ? { protect: hostProtect(req.protect, lookup2) } : {},
|
|
35037
35338
|
...req.sealed ? { sealed } : {},
|
|
35339
|
+
...req.sealedFetch ? { sealedFetch } : {},
|
|
35038
35340
|
...req.clipboard ? { clipboard } : {},
|
|
35039
35341
|
...req.requests ? { embedder: requests.hookFor(0, req.requests) } : {}
|
|
35040
35342
|
};
|
|
@@ -35125,7 +35427,15 @@ function serveKernel(port, deps) {
|
|
|
35125
35427
|
...req.modules ? { modules: req.modules } : {},
|
|
35126
35428
|
...req.commands ? { commands: req.commands } : {},
|
|
35127
35429
|
...req.env ? { env: req.env } : {},
|
|
35128
|
-
...hostOptions(
|
|
35430
|
+
...hostOptions(
|
|
35431
|
+
req,
|
|
35432
|
+
port,
|
|
35433
|
+
sealed.hook,
|
|
35434
|
+
sealed.fetch,
|
|
35435
|
+
clipboard.hook,
|
|
35436
|
+
integrity.lookup,
|
|
35437
|
+
requests
|
|
35438
|
+
),
|
|
35129
35439
|
...req.approve ? { approve: approvals.ask } : {},
|
|
35130
35440
|
...net,
|
|
35131
35441
|
...media ? { media } : {},
|
|
@@ -35152,6 +35462,7 @@ function serveKernel(port, deps) {
|
|
|
35152
35462
|
async function handle(req) {
|
|
35153
35463
|
if (req.op === "init") return init(req);
|
|
35154
35464
|
if (isAttestRequest(req)) return attestOp(await ready2(), req);
|
|
35465
|
+
if (req.op === "sealed-placeholders") return (await ready2()).setPlaceholders(req.list);
|
|
35155
35466
|
if (req.op === "open-terminal") return terminal(req);
|
|
35156
35467
|
if (req.op === "connect") return connect2(req.user, req.tag, req.requests);
|
|
35157
35468
|
if (isUsersRequest(req)) return usersOp(await ready2(), req);
|