@ai-ecoverse/slicc-kernel 1.171.0 → 1.172.2
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 +25 -8
- package/dist/driver-worker.js +4 -2
- package/dist/driver-worker.js.map +2 -2
- package/dist/index.js +260 -42
- package/dist/index.js.map +4 -4
- package/dist/kernel-worker.js +602 -230
- 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 +462 -233
- 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/fs/portable.d.ts +11 -0
- package/dist/types/fs/roots.d.ts +1 -1
- 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/mount/media.d.ts +3 -1
- package/dist/types/node.d.ts +12 -4
- package/dist/types/sealed-relay.d.ts +12 -2
- package/dist/types/serve.d.ts +14 -5
- package/dist/types/testing.d.ts +3 -0
- package/dist/types/transport.d.ts +2 -1
- package/package.json +2 -2
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);
|
|
@@ -2033,11 +2033,11 @@ var OpfsFs = class {
|
|
|
2033
2033
|
}
|
|
2034
2034
|
const found = await this.locate(path, change.follow !== false);
|
|
2035
2035
|
this.refuse(found.path);
|
|
2036
|
-
const [
|
|
2037
|
-
const current = await this.ownerAt(found.path,
|
|
2036
|
+
const [stored2] = found.link ? [found.link] : await this.meta.get([found.path]);
|
|
2037
|
+
const current = await this.ownerAt(found.path, stored2);
|
|
2038
2038
|
const next3 = { uid: change.uid ?? current.uid, gid: change.gid ?? current.gid };
|
|
2039
2039
|
const handing = found.handle?.kind === "directory" && !sameOwner(next3, current);
|
|
2040
|
-
const heir = change.kind === "adopt" ? void 0 :
|
|
2040
|
+
const heir = change.kind === "adopt" ? void 0 : stored2?.heir ?? (handing ? [current.uid, current.gid] : void 0);
|
|
2041
2041
|
const ctimeMs = Date.now();
|
|
2042
2042
|
await this.meta.update(found.path, (entry) => {
|
|
2043
2043
|
const { heir: _, ...rest2 } = entry ?? found.link ?? { path: found.path };
|
|
@@ -2053,8 +2053,8 @@ var OpfsFs = class {
|
|
|
2053
2053
|
}
|
|
2054
2054
|
async movedOwner(source) {
|
|
2055
2055
|
if (!this.owners) return void 0;
|
|
2056
|
-
const [
|
|
2057
|
-
return ownOf(
|
|
2056
|
+
const [stored2] = source.link ? [source.link] : await this.meta.get([source.path]);
|
|
2057
|
+
return ownOf(stored2) ? void 0 : this.ownerAt(source.path, stored2);
|
|
2058
2058
|
}
|
|
2059
2059
|
async walk(parts2, from, start2) {
|
|
2060
2060
|
let dir = start2;
|
|
@@ -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);
|
|
@@ -3905,6 +3905,38 @@ for (const [names2, op] of [
|
|
|
3905
3905
|
}
|
|
3906
3906
|
}
|
|
3907
3907
|
|
|
3908
|
+
// src/fs/portable.ts
|
|
3909
|
+
var privateTop = () => navigator.storage.getDirectory();
|
|
3910
|
+
function clonable(handle) {
|
|
3911
|
+
const { port1, port2 } = new MessageChannel();
|
|
3912
|
+
try {
|
|
3913
|
+
port1.postMessage(handle);
|
|
3914
|
+
return true;
|
|
3915
|
+
} catch (err) {
|
|
3916
|
+
if (err?.name === "DataCloneError") return false;
|
|
3917
|
+
throw err;
|
|
3918
|
+
} finally {
|
|
3919
|
+
port1.close();
|
|
3920
|
+
port2.close();
|
|
3921
|
+
}
|
|
3922
|
+
}
|
|
3923
|
+
async function portable(handle, top = privateTop) {
|
|
3924
|
+
if (clonable(handle)) return { handle };
|
|
3925
|
+
const path = await (await top()).resolve(handle);
|
|
3926
|
+
if (path === null) {
|
|
3927
|
+
throw new Error(
|
|
3928
|
+
"this browser cannot hand a folder to a worker unless it is in the origin private file system"
|
|
3929
|
+
);
|
|
3930
|
+
}
|
|
3931
|
+
return { path };
|
|
3932
|
+
}
|
|
3933
|
+
async function directoryAt(top, path) {
|
|
3934
|
+
let dir = top;
|
|
3935
|
+
for (const name2 of path) dir = await dir.getDirectoryHandle(name2);
|
|
3936
|
+
return dir;
|
|
3937
|
+
}
|
|
3938
|
+
var samePath = (a, b) => a.length === b.length && a.every((name2, at) => name2 === b[at]);
|
|
3939
|
+
|
|
3908
3940
|
// src/fs/roots.ts
|
|
3909
3941
|
var ROOTS_DB = "slicc-kernel-roots";
|
|
3910
3942
|
var ROOTS_STORE = "roots";
|
|
@@ -3926,6 +3958,10 @@ async function same(a, b) {
|
|
|
3926
3958
|
return false;
|
|
3927
3959
|
}
|
|
3928
3960
|
}
|
|
3961
|
+
async function matches(record2, root, at) {
|
|
3962
|
+
if (record2.handle) return same(record2.handle, root);
|
|
3963
|
+
return "path" in at && record2.path !== void 0 && samePath(record2.path, at.path);
|
|
3964
|
+
}
|
|
3929
3965
|
var nameOf = (id2) => `${META_DB}:${id2}`;
|
|
3930
3966
|
function done(tx) {
|
|
3931
3967
|
return new Promise((resolve2, reject) => {
|
|
@@ -3959,18 +3995,19 @@ async function seed(factory, name2) {
|
|
|
3959
3995
|
to.close();
|
|
3960
3996
|
}
|
|
3961
3997
|
}
|
|
3962
|
-
async function rootId(factory, root, locks = globalThis.navigator?.locks) {
|
|
3998
|
+
async function rootId(factory, root, locks = globalThis.navigator?.locks, top) {
|
|
3963
3999
|
const find = async () => {
|
|
4000
|
+
const at = await portable(root, top);
|
|
3964
4001
|
const db = await open(factory);
|
|
3965
4002
|
try {
|
|
3966
4003
|
const all = await request(
|
|
3967
4004
|
db.transaction(ROOTS_STORE, "readonly").objectStore(ROOTS_STORE).getAll()
|
|
3968
4005
|
);
|
|
3969
|
-
for (const record2 of all) if (await
|
|
4006
|
+
for (const record2 of all) if (await matches(record2, root, at)) return record2.id;
|
|
3970
4007
|
const id2 = crypto.randomUUID();
|
|
3971
4008
|
if (await used(root)) await seed(factory, nameOf(id2));
|
|
3972
4009
|
const tx = db.transaction(ROOTS_STORE, "readwrite");
|
|
3973
|
-
tx.objectStore(ROOTS_STORE).put({ id: id2,
|
|
4010
|
+
tx.objectStore(ROOTS_STORE).put({ id: id2, ...at });
|
|
3974
4011
|
await done(tx);
|
|
3975
4012
|
return id2;
|
|
3976
4013
|
} finally {
|
|
@@ -6842,9 +6879,9 @@ var KernelSocket = class _KernelSocket {
|
|
|
6842
6879
|
case SO_TYPE:
|
|
6843
6880
|
return SOCK_STREAM;
|
|
6844
6881
|
case SO_ERROR: {
|
|
6845
|
-
const
|
|
6882
|
+
const failed4 = this.failed;
|
|
6846
6883
|
this.failed = void 0;
|
|
6847
|
-
return
|
|
6884
|
+
return failed4 ? wasiErrno(failed4) : 0;
|
|
6848
6885
|
}
|
|
6849
6886
|
case SO_ACCEPTCONN:
|
|
6850
6887
|
return this.state === "listening" ? 1 : 0;
|
|
@@ -6924,6 +6961,7 @@ var LoopbackNet = class {
|
|
|
6924
6961
|
internal = /* @__PURE__ */ new Set();
|
|
6925
6962
|
reserved = /* @__PURE__ */ new Set();
|
|
6926
6963
|
facades = /* @__PURE__ */ new Map();
|
|
6964
|
+
proxyStamped;
|
|
6927
6965
|
nextEphemeral = EPHEMERAL_FIRST;
|
|
6928
6966
|
route;
|
|
6929
6967
|
origins;
|
|
@@ -6998,9 +7036,15 @@ var LoopbackNet = class {
|
|
|
6998
7036
|
this.kernelOnly(port, true);
|
|
6999
7037
|
this.facades.set(port, name2);
|
|
7000
7038
|
}
|
|
7001
|
-
|
|
7002
|
-
|
|
7003
|
-
|
|
7039
|
+
stampProxy(port) {
|
|
7040
|
+
this.proxyStamped = port;
|
|
7041
|
+
}
|
|
7042
|
+
get originsStamped() {
|
|
7043
|
+
return this.proxyStamped !== void 0;
|
|
7044
|
+
}
|
|
7045
|
+
stampsPeers(addr) {
|
|
7046
|
+
if (addr.family !== "inet" || !isLoopback(canonicalHost(addr.host))) return false;
|
|
7047
|
+
return this.facades.has(addr.port) || this.proxyStamped === addr.port;
|
|
7004
7048
|
}
|
|
7005
7049
|
activate(addr, start2) {
|
|
7006
7050
|
this.activators.set(keyOf(addr), start2);
|
|
@@ -7323,7 +7367,21 @@ function headOf(nid, response) {
|
|
|
7323
7367
|
headers: response.headers
|
|
7324
7368
|
};
|
|
7325
7369
|
}
|
|
7326
|
-
function
|
|
7370
|
+
function requestOf(call, signal, uploads) {
|
|
7371
|
+
const { url, method, headers, streamed, body, redirect, nid } = call;
|
|
7372
|
+
return {
|
|
7373
|
+
url,
|
|
7374
|
+
method,
|
|
7375
|
+
headers,
|
|
7376
|
+
...streamed ? { bodyStream: uploads.of(nid, signal) } : body ? { body } : {},
|
|
7377
|
+
...redirect !== void 0 ? { redirect } : {},
|
|
7378
|
+
signal
|
|
7379
|
+
};
|
|
7380
|
+
}
|
|
7381
|
+
function serveTransport(peer, transport, {
|
|
7382
|
+
closeWaitMs = CLOSE_WAIT_MS2,
|
|
7383
|
+
attributed = false
|
|
7384
|
+
} = {}) {
|
|
7327
7385
|
const open2 = /* @__PURE__ */ new Map();
|
|
7328
7386
|
const fail2 = (nid, e) => {
|
|
7329
7387
|
open2.delete(nid);
|
|
@@ -7343,14 +7401,11 @@ function serveTransport(peer, transport, { closeWaitMs = CLOSE_WAIT_MS2 } = {})
|
|
|
7343
7401
|
const entry = { abort };
|
|
7344
7402
|
open2.set(call.nid, entry);
|
|
7345
7403
|
try {
|
|
7346
|
-
const response = await transport.fetch(
|
|
7347
|
-
|
|
7348
|
-
|
|
7349
|
-
|
|
7350
|
-
|
|
7351
|
-
...call.redirect !== void 0 ? { redirect: call.redirect } : {},
|
|
7352
|
-
signal: abort.signal
|
|
7353
|
-
});
|
|
7404
|
+
const response = await transport.fetch(
|
|
7405
|
+
requestOf(call, abort.signal, uploads),
|
|
7406
|
+
attributed ? call.owner : void 0,
|
|
7407
|
+
attributed ? call.stamp : void 0
|
|
7408
|
+
);
|
|
7354
7409
|
if (!open2.has(call.nid)) {
|
|
7355
7410
|
await response.cancel();
|
|
7356
7411
|
return;
|
|
@@ -8504,7 +8559,7 @@ function satisfies(version, range2) {
|
|
|
8504
8559
|
}
|
|
8505
8560
|
|
|
8506
8561
|
// src/version.ts
|
|
8507
|
-
var KERNEL_VERSION = true ? "1.
|
|
8562
|
+
var KERNEL_VERSION = true ? "1.172.2" : "0.0.0-dev";
|
|
8508
8563
|
var OS_RELEASE = "6.0.0-slicc";
|
|
8509
8564
|
function procVersion() {
|
|
8510
8565
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -9161,32 +9216,32 @@ function nextFire(schedule, after, utc = false) {
|
|
|
9161
9216
|
}
|
|
9162
9217
|
return null;
|
|
9163
9218
|
}
|
|
9164
|
-
function missedFires(schedule, from,
|
|
9219
|
+
function missedFires(schedule, from, until2, utc = false, cap = MISSED_CAP) {
|
|
9165
9220
|
let count2 = 0;
|
|
9166
9221
|
let last = null;
|
|
9167
9222
|
let at = from;
|
|
9168
9223
|
while (count2 < cap) {
|
|
9169
9224
|
at = nextFire(schedule, at, utc);
|
|
9170
|
-
if (at === null || at >
|
|
9225
|
+
if (at === null || at > until2) return { count: count2, last, more: false };
|
|
9171
9226
|
last = at;
|
|
9172
9227
|
count2++;
|
|
9173
9228
|
}
|
|
9174
9229
|
const next3 = nextFire(schedule, last, utc);
|
|
9175
|
-
if (next3 === null || next3 >
|
|
9176
|
-
return { count: count2, last: latestFire(schedule, last,
|
|
9230
|
+
if (next3 === null || next3 > until2) return { count: count2, last, more: false };
|
|
9231
|
+
return { count: count2, last: latestFire(schedule, last, until2, utc), more: true };
|
|
9177
9232
|
}
|
|
9178
|
-
function latestFire(schedule, from,
|
|
9233
|
+
function latestFire(schedule, from, until2, utc = false) {
|
|
9179
9234
|
let found = from;
|
|
9180
9235
|
for (let span = 6e4; ; span *= 2) {
|
|
9181
|
-
const start2 = Math.max(from,
|
|
9236
|
+
const start2 = Math.max(from, until2 - span);
|
|
9182
9237
|
const first = nextFire(schedule, start2, utc);
|
|
9183
|
-
if (first !== null && first <=
|
|
9238
|
+
if (first !== null && first <= until2) {
|
|
9184
9239
|
found = first;
|
|
9185
9240
|
break;
|
|
9186
9241
|
}
|
|
9187
9242
|
if (start2 === from) return from;
|
|
9188
9243
|
}
|
|
9189
|
-
for (let at = nextFire(schedule, found, utc); at !== null && at <=
|
|
9244
|
+
for (let at = nextFire(schedule, found, utc); at !== null && at <= until2; ) {
|
|
9190
9245
|
found = at;
|
|
9191
9246
|
at = nextFire(schedule, at, utc);
|
|
9192
9247
|
}
|
|
@@ -9552,14 +9607,14 @@ var UnlinkedKeeper = class {
|
|
|
9552
9607
|
linked = /* @__PURE__ */ new Map();
|
|
9553
9608
|
dirOwner;
|
|
9554
9609
|
peers;
|
|
9555
|
-
constructor(fs, holders,
|
|
9610
|
+
constructor(fs, holders, rootOf2, options = {}) {
|
|
9556
9611
|
this.peers = options.peers;
|
|
9557
9612
|
this.marks = options.marks ?? new PathMarks();
|
|
9558
9613
|
const { locks, owner } = options;
|
|
9559
9614
|
this.dirOwner = options.dirOwner;
|
|
9560
9615
|
this.fs = fs;
|
|
9561
9616
|
this.holders = holders;
|
|
9562
|
-
this.rootOf =
|
|
9617
|
+
this.rootOf = rootOf2;
|
|
9563
9618
|
this.locks = locks;
|
|
9564
9619
|
this.busy = options.busy ?? (() => false);
|
|
9565
9620
|
this.owner = owner;
|
|
@@ -9898,12 +9953,12 @@ var UnlinkedKeeper = class {
|
|
|
9898
9953
|
return this.locks;
|
|
9899
9954
|
}
|
|
9900
9955
|
async undoing(op, peers, sends, heard, shared2 = []) {
|
|
9901
|
-
let
|
|
9956
|
+
let failed4;
|
|
9902
9957
|
let out;
|
|
9903
9958
|
try {
|
|
9904
9959
|
out = await op();
|
|
9905
9960
|
} catch (err) {
|
|
9906
|
-
|
|
9961
|
+
failed4 = err ?? new Error("failed");
|
|
9907
9962
|
await this.rollBackAsides(sends, shared2);
|
|
9908
9963
|
}
|
|
9909
9964
|
const hiddenShared = new Set(shared2.map((one) => one.hidden));
|
|
@@ -9924,7 +9979,7 @@ var UnlinkedKeeper = class {
|
|
|
9924
9979
|
const done5 = () => one.release().then(() => this.dropIfLast(one.hidden));
|
|
9925
9980
|
void Promise.all(waits.map(({ told }) => told)).then(done5, done5);
|
|
9926
9981
|
}
|
|
9927
|
-
if (
|
|
9982
|
+
if (failed4 !== void 0) throw failed4;
|
|
9928
9983
|
return out;
|
|
9929
9984
|
}
|
|
9930
9985
|
async rollBackAsides(sends, shared2) {
|
|
@@ -10071,7 +10126,7 @@ var UnlinkedKeeper = class {
|
|
|
10071
10126
|
// src/cron/clock.ts
|
|
10072
10127
|
var systemCronClock = {
|
|
10073
10128
|
now: () => Date.now(),
|
|
10074
|
-
sleep(
|
|
10129
|
+
sleep(until2, signal) {
|
|
10075
10130
|
if (signal.aborted) return Promise.resolve();
|
|
10076
10131
|
return new Promise((resolve2) => {
|
|
10077
10132
|
const done5 = () => {
|
|
@@ -10079,7 +10134,7 @@ var systemCronClock = {
|
|
|
10079
10134
|
signal.removeEventListener("abort", done5);
|
|
10080
10135
|
resolve2();
|
|
10081
10136
|
};
|
|
10082
|
-
const timer = setTimeout(done5, Math.max(0,
|
|
10137
|
+
const timer = setTimeout(done5, Math.max(0, until2 - Date.now()));
|
|
10083
10138
|
timer.unref?.();
|
|
10084
10139
|
signal.addEventListener("abort", done5, { once: true });
|
|
10085
10140
|
});
|
|
@@ -10183,15 +10238,15 @@ var CronService = class {
|
|
|
10183
10238
|
async pass() {
|
|
10184
10239
|
if (this.wake.signal.aborted) this.wake = new AbortController();
|
|
10185
10240
|
const wake = this.wake;
|
|
10186
|
-
let
|
|
10241
|
+
let until2;
|
|
10187
10242
|
try {
|
|
10188
|
-
|
|
10243
|
+
until2 = await this.tick();
|
|
10189
10244
|
} catch (err) {
|
|
10190
10245
|
await this.error(`cron: ${messageOf(err)}`);
|
|
10191
|
-
|
|
10246
|
+
until2 = this.clock.now() + WAKE_MS;
|
|
10192
10247
|
}
|
|
10193
10248
|
if (this.stopping.signal.aborted) return;
|
|
10194
|
-
await this.clock.sleep(
|
|
10249
|
+
await this.clock.sleep(until2, wake.signal);
|
|
10195
10250
|
}
|
|
10196
10251
|
async provision() {
|
|
10197
10252
|
const { fs, owners } = this.host;
|
|
@@ -10408,14 +10463,17 @@ var PLACEHOLDER_REFUSED = "refused: this request has a sealed placeholder in its
|
|
|
10408
10463
|
var PlaceholderRefused = class extends Error {
|
|
10409
10464
|
status = 403;
|
|
10410
10465
|
code = "EACCES";
|
|
10411
|
-
constructor() {
|
|
10412
|
-
super(
|
|
10466
|
+
constructor(reason = PLACEHOLDER_REFUSED) {
|
|
10467
|
+
super(reason);
|
|
10413
10468
|
}
|
|
10414
10469
|
};
|
|
10415
|
-
function
|
|
10470
|
+
function holds2(text, known) {
|
|
10471
|
+
return PLACEHOLDER.test(text) || known.some((placeholder) => text.includes(placeholder));
|
|
10472
|
+
}
|
|
10473
|
+
function carries(text, known) {
|
|
10416
10474
|
let layer = text;
|
|
10417
10475
|
for (let i = 0; i < PERCENT_LAYERS; i++) {
|
|
10418
|
-
if (
|
|
10476
|
+
if (holds2(layer, known)) return true;
|
|
10419
10477
|
const next3 = layer.replace(
|
|
10420
10478
|
ESCAPE,
|
|
10421
10479
|
(_, hex4) => String.fromCharCode(Number.parseInt(hex4, 16))
|
|
@@ -10423,35 +10481,36 @@ function carries(text) {
|
|
|
10423
10481
|
if (next3 === layer) return false;
|
|
10424
10482
|
layer = next3;
|
|
10425
10483
|
}
|
|
10426
|
-
return
|
|
10484
|
+
return holds2(layer, known);
|
|
10427
10485
|
}
|
|
10428
|
-
function basicCarries(value2) {
|
|
10486
|
+
function basicCarries(value2, known) {
|
|
10429
10487
|
const credential = BASIC.exec(value2)?.[1];
|
|
10430
10488
|
if (credential === void 0) return false;
|
|
10431
10489
|
const letters = credential.replace(/[^A-Za-z0-9+/_-]/g, "").replaceAll("-", "+").replaceAll("_", "/");
|
|
10432
10490
|
for (let shift = 0; shift < BASE64_GROUP; shift++) {
|
|
10433
10491
|
const part = letters.slice(shift);
|
|
10434
10492
|
const whole = part.length % BASE64_GROUP === 1 ? part.slice(0, -1) : part;
|
|
10435
|
-
if (carries(atob(whole))) return true;
|
|
10493
|
+
if (carries(atob(whole), known)) return true;
|
|
10436
10494
|
}
|
|
10437
10495
|
return false;
|
|
10438
10496
|
}
|
|
10439
|
-
function headersCarry(headers) {
|
|
10497
|
+
function headersCarry(headers, known) {
|
|
10440
10498
|
return headers.some(
|
|
10441
|
-
([name2, value2]) => carries(name2.toLowerCase()) || carries(value2) || basicCarries(value2)
|
|
10499
|
+
([name2, value2]) => carries(name2, known) || carries(name2.toLowerCase(), known) || carries(value2, known) || basicCarries(value2, known)
|
|
10442
10500
|
);
|
|
10443
10501
|
}
|
|
10444
|
-
function urlCarries(url) {
|
|
10445
|
-
return carries(url) || URL.canParse(url) && carries(new URL(url).href);
|
|
10502
|
+
function urlCarries(url, known) {
|
|
10503
|
+
return carries(url, known) || URL.canParse(url) && carries(new URL(url).href, known);
|
|
10446
10504
|
}
|
|
10447
|
-
function
|
|
10448
|
-
|
|
10505
|
+
function detected(request3, known) {
|
|
10506
|
+
return urlCarries(request3.url, known) || headersCarry(request3.headers, known);
|
|
10449
10507
|
}
|
|
10450
|
-
function refuseSocket(request3) {
|
|
10451
|
-
|
|
10452
|
-
|
|
10508
|
+
function refuseSocket(request3, known) {
|
|
10509
|
+
if (detected(request3, known) || request3.protocols.some((p) => carries(p, known))) {
|
|
10510
|
+
throw new PlaceholderRefused();
|
|
10511
|
+
}
|
|
10453
10512
|
}
|
|
10454
|
-
function placeholderFloor(inner) {
|
|
10513
|
+
function placeholderFloor(inner, { known = () => [], fill: fill2 } = {}) {
|
|
10455
10514
|
const open2 = inner.websocket?.bind(inner);
|
|
10456
10515
|
return {
|
|
10457
10516
|
get traits() {
|
|
@@ -10459,13 +10518,14 @@ function placeholderFloor(inner) {
|
|
|
10459
10518
|
},
|
|
10460
10519
|
...open2 ? {
|
|
10461
10520
|
websocket: async (request3) => {
|
|
10462
|
-
refuseSocket(request3);
|
|
10521
|
+
refuseSocket(request3, known());
|
|
10463
10522
|
return open2(request3);
|
|
10464
10523
|
}
|
|
10465
10524
|
} : {},
|
|
10466
|
-
async fetch(request3, owner) {
|
|
10467
|
-
|
|
10468
|
-
|
|
10525
|
+
async fetch(request3, owner, stamp) {
|
|
10526
|
+
if (!detected(request3, known())) return inner.fetch(request3, owner, stamp);
|
|
10527
|
+
if (!fill2 || !stamp) throw new PlaceholderRefused();
|
|
10528
|
+
return fill2(request3, stamp);
|
|
10469
10529
|
}
|
|
10470
10530
|
};
|
|
10471
10531
|
}
|
|
@@ -10638,14 +10698,14 @@ function tunnelTarget(req) {
|
|
|
10638
10698
|
}
|
|
10639
10699
|
return { host, port };
|
|
10640
10700
|
}
|
|
10641
|
-
async function watchHangup(conn, abort,
|
|
10642
|
-
while (!
|
|
10701
|
+
async function watchHangup(conn, abort, until2) {
|
|
10702
|
+
while (!until2.aborted && !abort.signal.aborted) {
|
|
10643
10703
|
if (conn.poll().hangup) {
|
|
10644
10704
|
abort.abort(new KernelError("EPIPE"));
|
|
10645
10705
|
return;
|
|
10646
10706
|
}
|
|
10647
10707
|
try {
|
|
10648
|
-
await conn.changed(
|
|
10708
|
+
await conn.changed(until2);
|
|
10649
10709
|
} catch {
|
|
10650
10710
|
return;
|
|
10651
10711
|
}
|
|
@@ -10836,7 +10896,7 @@ var RealmProxy = class {
|
|
|
10836
10896
|
const waiting = new AbortController();
|
|
10837
10897
|
void watchHangup(ctx.socket, abort, waiting.signal);
|
|
10838
10898
|
try {
|
|
10839
|
-
response = await this.upstream(req, url, body, abort.signal, ctx.socket
|
|
10899
|
+
response = await this.upstream(req, url, body, abort.signal, ctx.socket);
|
|
10840
10900
|
} finally {
|
|
10841
10901
|
waiting.abort();
|
|
10842
10902
|
}
|
|
@@ -10863,7 +10923,7 @@ var RealmProxy = class {
|
|
|
10863
10923
|
await conn.write(latin1Bytes("HTTP/1.1 100 Continue\r\n\r\n"), this.stop.signal);
|
|
10864
10924
|
}
|
|
10865
10925
|
}
|
|
10866
|
-
async upstream(req, url, body, signal,
|
|
10926
|
+
async upstream(req, url, body, signal, socket) {
|
|
10867
10927
|
const sent = BODILESS_METHODS.has(req.method) ? void 0 : body;
|
|
10868
10928
|
try {
|
|
10869
10929
|
const fetching = this.options.transport.fetch(
|
|
@@ -10874,7 +10934,8 @@ var RealmProxy = class {
|
|
|
10874
10934
|
...sent instanceof Uint8Array ? { body: sent } : sent ? { bodyStream: sent } : {},
|
|
10875
10935
|
signal
|
|
10876
10936
|
},
|
|
10877
|
-
|
|
10937
|
+
socket.peerCred?.pid,
|
|
10938
|
+
socket.peerStamp
|
|
10878
10939
|
);
|
|
10879
10940
|
return await untilAborted(fetching, signal);
|
|
10880
10941
|
} catch (e) {
|
|
@@ -11191,7 +11252,7 @@ async function relay(socket, conn) {
|
|
|
11191
11252
|
// src/fs/attest.ts
|
|
11192
11253
|
var ATTEST_MAX = 1024 * 1024;
|
|
11193
11254
|
var UNOWNED = 1e3;
|
|
11194
|
-
function
|
|
11255
|
+
function refuse(code, path, why) {
|
|
11195
11256
|
throw Object.assign(new Error(`attest ${path}: ${why}`), { code });
|
|
11196
11257
|
}
|
|
11197
11258
|
function chainOf(path) {
|
|
@@ -11233,39 +11294,49 @@ async function trustedParents(fs, path, o) {
|
|
|
11233
11294
|
const parents = [];
|
|
11234
11295
|
for (const dir of chainOf(path).slice(0, -1)) {
|
|
11235
11296
|
const st = await fs.lstat(dir);
|
|
11236
|
-
if (st.isSymbolicLink)
|
|
11237
|
-
if (!st.isDirectory)
|
|
11297
|
+
if (st.isSymbolicLink) refuse("EACCES", path, `${dir} is a symlink`);
|
|
11298
|
+
if (!st.isDirectory) refuse("ENOTDIR", path, `${dir} is not a directory`);
|
|
11238
11299
|
const perm = owned(dir, st);
|
|
11239
11300
|
if (o.users !== "off" && (perm.uid !== 0 || (perm.mode & 18) !== 0)) {
|
|
11240
|
-
|
|
11301
|
+
refuse("EACCES", path, `${dir} is not root-owned or is writable by group or others`);
|
|
11241
11302
|
}
|
|
11242
11303
|
parents.push(perm);
|
|
11243
11304
|
}
|
|
11244
11305
|
return parents;
|
|
11245
11306
|
}
|
|
11307
|
+
function missing3(e) {
|
|
11308
|
+
return e?.code === "ENOENT";
|
|
11309
|
+
}
|
|
11246
11310
|
async function attest(fs, asked, o) {
|
|
11311
|
+
if (o.absent !== void 0 && o.absent !== "allow") {
|
|
11312
|
+
refuse("EINVAL", String(asked), "absent takes only allow");
|
|
11313
|
+
}
|
|
11247
11314
|
if (typeof asked !== "string" || !asked.startsWith("/")) {
|
|
11248
|
-
|
|
11315
|
+
refuse("EINVAL", String(asked), "not an absolute path");
|
|
11249
11316
|
}
|
|
11250
11317
|
const path = normalizePath(asked);
|
|
11251
11318
|
const mount = o.mounts.find((target) => {
|
|
11252
11319
|
const at = normalizePath(target);
|
|
11253
11320
|
return at === "/" || under2(path, at);
|
|
11254
11321
|
});
|
|
11255
|
-
if (mount !== void 0)
|
|
11322
|
+
if (mount !== void 0) refuse("EACCES", path, `under the mount ${mount}`);
|
|
11256
11323
|
const parents = await trustedParents(fs, path, o);
|
|
11257
11324
|
for (let tries = 0; ; tries++) {
|
|
11258
|
-
const before = await fs.lstat(path)
|
|
11259
|
-
|
|
11325
|
+
const before = await fs.lstat(path).catch((e) => {
|
|
11326
|
+
if (o.absent === "allow" && missing3(e)) return void 0;
|
|
11327
|
+
throw e;
|
|
11328
|
+
});
|
|
11329
|
+
if (!before) return { path, absent: true, users: o.users, onRootFs: true, parents };
|
|
11330
|
+
if (before.isSymbolicLink) refuse("EACCES", path, "is a symlink");
|
|
11260
11331
|
if (!before.isFile)
|
|
11261
|
-
|
|
11262
|
-
if (before.size > ATTEST_MAX)
|
|
11332
|
+
refuse(before.isDirectory ? "EISDIR" : "EINVAL", path, "is not a regular file");
|
|
11333
|
+
if (before.size > ATTEST_MAX) refuse("EFBIG", path, `is over ${ATTEST_MAX} bytes`);
|
|
11263
11334
|
const bytes = (await fs.readFileBuffer(path)).slice();
|
|
11264
11335
|
const after = await fs.lstat(path);
|
|
11265
11336
|
if (unchanged(before, after, bytes)) {
|
|
11266
11337
|
return attested(path, after, bytes, await sha2562(bytes), o, parents);
|
|
11267
11338
|
}
|
|
11268
|
-
if (tries >= 1)
|
|
11339
|
+
if (tries >= 1) refuse("EAGAIN", path, "changed while it was read");
|
|
11269
11340
|
}
|
|
11270
11341
|
}
|
|
11271
11342
|
var WATCH_DEBOUNCE_MS = 50;
|
|
@@ -11324,7 +11395,7 @@ var S_IFREG2 = 32768;
|
|
|
11324
11395
|
var COMMAND = /^\/(?:usr\/)?bin\/([^/]+)$/;
|
|
11325
11396
|
var MAX_LINKS6 = 40;
|
|
11326
11397
|
var BIN_ENTRY = /\/bin\/[^/]+$/;
|
|
11327
|
-
function
|
|
11398
|
+
function missing4(err) {
|
|
11328
11399
|
return err?.code === "ENOENT";
|
|
11329
11400
|
}
|
|
11330
11401
|
function synthetic(directory, path) {
|
|
@@ -11428,7 +11499,7 @@ function withCommandDirs(fs, names2, userDir = async () => void 0, owners = fals
|
|
|
11428
11499
|
}
|
|
11429
11500
|
async function entryTarget(path) {
|
|
11430
11501
|
if (!BIN_ENTRY.test(path) || !(await virtual(path))?.isFile) return void 0;
|
|
11431
|
-
if (!await fs.lstat(path).then(() => false,
|
|
11502
|
+
if (!await fs.lstat(path).then(() => false, missing4)) return void 0;
|
|
11432
11503
|
const target = await targetOf2(path);
|
|
11433
11504
|
return target?.path === path ? void 0 : target;
|
|
11434
11505
|
}
|
|
@@ -11440,11 +11511,11 @@ function withCommandDirs(fs, names2, userDir = async () => void 0, owners = fals
|
|
|
11440
11511
|
return target?.path;
|
|
11441
11512
|
}
|
|
11442
11513
|
const absent2 = (err) => {
|
|
11443
|
-
if (
|
|
11514
|
+
if (missing4(err)) return EMPTY2;
|
|
11444
11515
|
throw err;
|
|
11445
11516
|
};
|
|
11446
11517
|
async function content(path, err) {
|
|
11447
|
-
if (!
|
|
11518
|
+
if (!missing4(err) || !(await linked2(path))?.isFile) throw err;
|
|
11448
11519
|
const target = await redirected2(path);
|
|
11449
11520
|
return target === void 0 ? EMPTY2 : fs.readFileBuffer(target).catch(absent2);
|
|
11450
11521
|
}
|
|
@@ -11453,7 +11524,7 @@ function withCommandDirs(fs, names2, userDir = async () => void 0, owners = fals
|
|
|
11453
11524
|
try {
|
|
11454
11525
|
return await real(path);
|
|
11455
11526
|
} catch (err) {
|
|
11456
|
-
const found =
|
|
11527
|
+
const found = missing4(err) ? await linked2(path) : void 0;
|
|
11457
11528
|
if (found) return found;
|
|
11458
11529
|
throw err;
|
|
11459
11530
|
}
|
|
@@ -11478,7 +11549,7 @@ function withCommandDirs(fs, names2, userDir = async () => void 0, owners = fals
|
|
|
11478
11549
|
const extra = await children3(path);
|
|
11479
11550
|
if (!extra) return fs.readdir(path);
|
|
11480
11551
|
const real = await fs.readdir(path).catch((err) => {
|
|
11481
|
-
if (
|
|
11552
|
+
if (missing4(err)) return [];
|
|
11482
11553
|
throw err;
|
|
11483
11554
|
});
|
|
11484
11555
|
return [.../* @__PURE__ */ new Set([...real, ...extra])].sort();
|
|
@@ -11487,7 +11558,7 @@ function withCommandDirs(fs, names2, userDir = async () => void 0, owners = fals
|
|
|
11487
11558
|
const extra = await children3(path);
|
|
11488
11559
|
if (!extra) return fs.readdirStat(path);
|
|
11489
11560
|
const real = await fs.readdirStat(path).catch((err) => {
|
|
11490
|
-
if (
|
|
11561
|
+
if (missing4(err)) return [];
|
|
11491
11562
|
throw err;
|
|
11492
11563
|
});
|
|
11493
11564
|
const seen = new Set(real.map(([name2]) => name2));
|
|
@@ -11521,7 +11592,7 @@ function withCommandDirs(fs, names2, userDir = async () => void 0, owners = fals
|
|
|
11521
11592
|
...ranged2 ? {
|
|
11522
11593
|
...ranged2,
|
|
11523
11594
|
pread: (path, offset, length2, version) => ranged2.pread(path, offset, length2, version).catch(async (err) => {
|
|
11524
|
-
const target =
|
|
11595
|
+
const target = missing4(err) ? await redirected2(path) : void 0;
|
|
11525
11596
|
if (target === void 0) throw err;
|
|
11526
11597
|
return ranged2.pread(target, offset, length2).catch(absent2);
|
|
11527
11598
|
})
|
|
@@ -11552,7 +11623,7 @@ var S_IFREG3 = 32768;
|
|
|
11552
11623
|
var MAX_HOPS2 = 40;
|
|
11553
11624
|
var parentOf6 = (path) => path.slice(0, path.lastIndexOf("/")) || "/";
|
|
11554
11625
|
var baseOf2 = (path) => path.slice(path.lastIndexOf("/") + 1);
|
|
11555
|
-
function
|
|
11626
|
+
function missing5(err) {
|
|
11556
11627
|
return err?.code === "ENOENT";
|
|
11557
11628
|
}
|
|
11558
11629
|
function statOf(path, bytes) {
|
|
@@ -11605,11 +11676,11 @@ function withEtcFiles(fs, files) {
|
|
|
11605
11676
|
const text = files.get(path)?.();
|
|
11606
11677
|
return text === void 0 ? void 0 : new TextEncoder().encode(text);
|
|
11607
11678
|
};
|
|
11608
|
-
const absent2 = (path) => fs.lstat(path).then(() => false,
|
|
11679
|
+
const absent2 = (path) => fs.lstat(path).then(() => false, missing5);
|
|
11609
11680
|
const follow2 = linkFollower(fs, files);
|
|
11610
11681
|
const listedAbsent = async (path) => files.has(path) && await absent2(path) ? bytesOf2(path) : void 0;
|
|
11611
11682
|
const fallback = (path, make) => async (err) => {
|
|
11612
|
-
const at =
|
|
11683
|
+
const at = missing5(err) ? await follow2(path) : void 0;
|
|
11613
11684
|
const bytes = at === void 0 ? void 0 : await listedAbsent(at);
|
|
11614
11685
|
if (bytes === void 0 || at === void 0) throw err;
|
|
11615
11686
|
return make(bytes, at);
|
|
@@ -13509,29 +13580,29 @@ var HeldSet = class extends Set {
|
|
|
13509
13580
|
this.idle = idle2;
|
|
13510
13581
|
this.moved = moved2;
|
|
13511
13582
|
}
|
|
13512
|
-
add(
|
|
13513
|
-
|
|
13514
|
-
|
|
13515
|
-
return super.add(
|
|
13583
|
+
add(holds3) {
|
|
13584
|
+
holds3.onIdle = this.idle;
|
|
13585
|
+
holds3.onMoved = this.moved;
|
|
13586
|
+
return super.add(holds3);
|
|
13516
13587
|
}
|
|
13517
13588
|
doubt(paths, over) {
|
|
13518
|
-
for (const
|
|
13519
|
-
for (const path of paths)
|
|
13520
|
-
if (over !== void 0)
|
|
13589
|
+
for (const holds3 of this) {
|
|
13590
|
+
for (const path of paths) holds3.doubt(path, true);
|
|
13591
|
+
if (over !== void 0) holds3.doubt(over);
|
|
13521
13592
|
}
|
|
13522
13593
|
}
|
|
13523
13594
|
async bindIds(id2) {
|
|
13524
|
-
for (const
|
|
13595
|
+
for (const holds3 of [...this]) await holds3.bindIds(id2);
|
|
13525
13596
|
}
|
|
13526
13597
|
heldIds() {
|
|
13527
13598
|
const out = /* @__PURE__ */ new Map();
|
|
13528
|
-
for (const
|
|
13599
|
+
for (const holds3 of this) for (const [path, fid] of holds3.heldIds()) out.set(path, fid);
|
|
13529
13600
|
return [...out];
|
|
13530
13601
|
}
|
|
13531
|
-
delete(
|
|
13532
|
-
const removed = super.delete(
|
|
13533
|
-
for (const path of /* @__PURE__ */ new Set([...
|
|
13534
|
-
|
|
13602
|
+
delete(holds3) {
|
|
13603
|
+
const removed = super.delete(holds3);
|
|
13604
|
+
for (const path of /* @__PURE__ */ new Set([...holds3.keys(), ...holds3.opens.keys()])) this.idle(path);
|
|
13605
|
+
holds3.releaseAll();
|
|
13535
13606
|
return removed;
|
|
13536
13607
|
}
|
|
13537
13608
|
};
|
|
@@ -15232,7 +15303,7 @@ async function timesOf(entry, path, req) {
|
|
|
15232
15303
|
const st = await look.call(entry.fs, path).catch(() => void 0);
|
|
15233
15304
|
if (!st || (st.uid ?? 0) === g.cred.euid) return given;
|
|
15234
15305
|
const now = /* @__PURE__ */ new Date();
|
|
15235
|
-
const kept = (ms,
|
|
15306
|
+
const kept = (ms, stored2) => ms === stored2.getTime() ? stored2 : now;
|
|
15236
15307
|
return [kept(req.atimeMs, st.atime), kept(req.mtimeMs, st.mtime)];
|
|
15237
15308
|
}
|
|
15238
15309
|
function guardOf(entry) {
|
|
@@ -16422,9 +16493,9 @@ var SYS_TREE = {
|
|
|
16422
16493
|
`,
|
|
16423
16494
|
slicc_file_ids: (listing) => `${listing.fileIds ?? 0}
|
|
16424
16495
|
`,
|
|
16425
|
-
slicc_peer_holds: ({ holds:
|
|
16496
|
+
slicc_peer_holds: ({ holds: holds3 }) => `${holds3?.mine ?? 0} ${holds3?.peers ?? 0} ${holds3?.sent ?? 0}
|
|
16426
16497
|
`,
|
|
16427
|
-
slicc_peer_held: ({ holds:
|
|
16498
|
+
slicc_peer_held: ({ holds: holds3 }) => (holds3?.held ?? []).map((path) => `${path}
|
|
16428
16499
|
`).join(""),
|
|
16429
16500
|
slicc_rename_acks: (listing) => {
|
|
16430
16501
|
const samples = [...listing.renameAcks?.ackMs ?? []].sort((a, b) => a - b);
|
|
@@ -17165,11 +17236,11 @@ var EpollFile = class _EpollFile {
|
|
|
17165
17236
|
const round = new AbortController();
|
|
17166
17237
|
const stop = () => round.abort();
|
|
17167
17238
|
signal.addEventListener("abort", stop, { once: true });
|
|
17168
|
-
let
|
|
17239
|
+
let failed4 = false;
|
|
17169
17240
|
try {
|
|
17170
17241
|
await file.changed(round.signal);
|
|
17171
17242
|
} catch {
|
|
17172
|
-
|
|
17243
|
+
failed4 = true;
|
|
17173
17244
|
} finally {
|
|
17174
17245
|
round.abort();
|
|
17175
17246
|
signal.removeEventListener("abort", stop);
|
|
@@ -17177,7 +17248,7 @@ var EpollFile = class _EpollFile {
|
|
|
17177
17248
|
if (signal.aborted) return;
|
|
17178
17249
|
reg.gen++;
|
|
17179
17250
|
this.changes.wake();
|
|
17180
|
-
if (
|
|
17251
|
+
if (failed4) await pause(RETRY_MS, signal);
|
|
17181
17252
|
}
|
|
17182
17253
|
}
|
|
17183
17254
|
};
|
|
@@ -18158,11 +18229,11 @@ function ipv6(host) {
|
|
|
18158
18229
|
const back = halves.length === 2 ? groups(halves[1]) : [];
|
|
18159
18230
|
if (![...head, ...back].every((g) => /^[0-9A-Fa-f]{1,4}$/.test(g))) return void 0;
|
|
18160
18231
|
const words2 = [...head, ...back].map((g) => Number.parseInt(g, 16));
|
|
18161
|
-
const
|
|
18162
|
-
if (halves.length === 2 ?
|
|
18232
|
+
const missing6 = 8 - words2.length - tail2.length;
|
|
18233
|
+
if (halves.length === 2 ? missing6 < 1 : missing6 !== 0) return void 0;
|
|
18163
18234
|
const all = [
|
|
18164
18235
|
...head.map((g) => Number.parseInt(g, 16)),
|
|
18165
|
-
...new Array(halves.length === 2 ?
|
|
18236
|
+
...new Array(halves.length === 2 ? missing6 : 0).fill(0),
|
|
18166
18237
|
...back.map((g) => Number.parseInt(g, 16)),
|
|
18167
18238
|
...tail2
|
|
18168
18239
|
];
|
|
@@ -18252,19 +18323,19 @@ function indexedDbCaStore(dbName = "slicc-realm-ca") {
|
|
|
18252
18323
|
async swap(owner, expected, record2) {
|
|
18253
18324
|
const tx = (await open2()).transaction("ca", "readwrite");
|
|
18254
18325
|
const store = tx.objectStore("ca");
|
|
18255
|
-
let
|
|
18326
|
+
let stored2 = record2;
|
|
18256
18327
|
const read = store.get(owner);
|
|
18257
18328
|
read.onsuccess = () => {
|
|
18258
18329
|
const current = read.result;
|
|
18259
18330
|
const kept = winner(current, expected, record2);
|
|
18260
18331
|
if (kept === record2) store.put(record2, owner);
|
|
18261
|
-
else
|
|
18332
|
+
else stored2 = kept;
|
|
18262
18333
|
};
|
|
18263
18334
|
await new Promise((resolve2, reject) => {
|
|
18264
18335
|
tx.oncomplete = () => resolve2();
|
|
18265
18336
|
tx.onerror = () => reject(tx.error);
|
|
18266
18337
|
});
|
|
18267
|
-
return
|
|
18338
|
+
return stored2;
|
|
18268
18339
|
}
|
|
18269
18340
|
};
|
|
18270
18341
|
}
|
|
@@ -18281,10 +18352,10 @@ var RealmCa = class _RealmCa {
|
|
|
18281
18352
|
this.record = record2;
|
|
18282
18353
|
}
|
|
18283
18354
|
static async open(owner, store, now = Date.now()) {
|
|
18284
|
-
const
|
|
18285
|
-
if (
|
|
18355
|
+
const stored2 = await store.get(owner).catch(() => void 0);
|
|
18356
|
+
if (stored2 && stored2.notAfter - now > CA_RENEW_BEFORE) return new _RealmCa(stored2);
|
|
18286
18357
|
const record2 = await _RealmCa.create(owner, now);
|
|
18287
|
-
return new _RealmCa(await store.swap(owner,
|
|
18358
|
+
return new _RealmCa(await store.swap(owner, stored2, record2));
|
|
18288
18359
|
}
|
|
18289
18360
|
static async create(owner, now) {
|
|
18290
18361
|
const pair = await crypto.subtle.generateKey(ECDSA, false, ["sign", "verify"]);
|
|
@@ -19207,10 +19278,12 @@ var HttpHandles = class {
|
|
|
19207
19278
|
ws;
|
|
19208
19279
|
owner;
|
|
19209
19280
|
local;
|
|
19210
|
-
|
|
19281
|
+
stamp;
|
|
19282
|
+
constructor(transport, owner, local2, stamp) {
|
|
19211
19283
|
this.transport = transport;
|
|
19212
19284
|
this.owner = owner;
|
|
19213
19285
|
this.local = local2;
|
|
19286
|
+
this.stamp = stamp;
|
|
19214
19287
|
this.ws = new WsHandles(transport, () => ++this.nextHandle, local2);
|
|
19215
19288
|
}
|
|
19216
19289
|
syscall(req) {
|
|
@@ -19286,7 +19359,7 @@ var HttpHandles = class {
|
|
|
19286
19359
|
...entry.upload ? { bodyStream: entry.upload } : req.body ? { body: req.body } : {},
|
|
19287
19360
|
signal: entry.abort.signal
|
|
19288
19361
|
};
|
|
19289
|
-
const response = port === void 0 ? await this.transport.fetch(request3, this.owner) : await this.local.fetch(request3, port);
|
|
19362
|
+
const response = port === void 0 ? await this.transport.fetch(request3, this.owner, await this.stamp?.()) : await this.local.fetch(request3, port);
|
|
19290
19363
|
entry.body = response.body[Symbol.asyncIterator]();
|
|
19291
19364
|
entry.cancel = () => response.cancel();
|
|
19292
19365
|
if (!this.open.has(handle)) await entry.cancel().catch(() => void 0);
|
|
@@ -19308,8 +19381,8 @@ var HttpHandles = class {
|
|
|
19308
19381
|
if (text === NO_TRANSPORT || typeof status !== "number" || status === 502) {
|
|
19309
19382
|
const code = codeOf2(e);
|
|
19310
19383
|
const errno3 = text === NO_TRANSPORT ? "ENETUNREACH" : code !== "EIO" ? code : "ECONNREFUSED";
|
|
19311
|
-
const
|
|
19312
|
-
return { ok: false, errno: errno3, message: text, ...
|
|
19384
|
+
const failed4 = e.detail === "transport";
|
|
19385
|
+
return { ok: false, errno: errno3, message: text, ...failed4 ? { detail: "transport" } : {} };
|
|
19313
19386
|
}
|
|
19314
19387
|
entry.body = once(new TextEncoder().encode(text))[Symbol.asyncIterator]();
|
|
19315
19388
|
return this.headOf(handle, req.url, {
|
|
@@ -21216,7 +21289,7 @@ function pass(c, input, final) {
|
|
|
21216
21289
|
const partials = [];
|
|
21217
21290
|
scanMain(c, input, best, partials);
|
|
21218
21291
|
scanWrapped(c, input, best, partials);
|
|
21219
|
-
const
|
|
21292
|
+
const holds3 = final ? [] : [...new Set(partials)].sort((a, b) => a - b);
|
|
21220
21293
|
const starts = [...best.keys()].sort((a, b) => a - b);
|
|
21221
21294
|
const parts2 = [];
|
|
21222
21295
|
const hits = /* @__PURE__ */ new Map();
|
|
@@ -21226,8 +21299,8 @@ function pass(c, input, final) {
|
|
|
21226
21299
|
let h = 0;
|
|
21227
21300
|
for (; ; ) {
|
|
21228
21301
|
while (s < starts.length && starts[s] < pos) s++;
|
|
21229
|
-
while (h <
|
|
21230
|
-
const hold = h <
|
|
21302
|
+
while (h < holds3.length && holds3[h] < pos) h++;
|
|
21303
|
+
const hold = h < holds3.length ? holds3[h] : Infinity;
|
|
21231
21304
|
const next3 = s < starts.length ? starts[s] : Infinity;
|
|
21232
21305
|
if (hold <= next3) {
|
|
21233
21306
|
cut = Math.min(hold, input.length);
|
|
@@ -21329,23 +21402,23 @@ function scrubbed(inner, scrubber, idleMs = SCRUB_IDLE_MS) {
|
|
|
21329
21402
|
let pending = 0;
|
|
21330
21403
|
let busy = false;
|
|
21331
21404
|
let timer;
|
|
21332
|
-
let
|
|
21405
|
+
let failed4;
|
|
21333
21406
|
const waiters = /* @__PURE__ */ new Set();
|
|
21334
21407
|
const quiet2 = () => !busy && pending === 0;
|
|
21335
21408
|
const wake = () => {
|
|
21336
21409
|
for (const waiter of [...waiters]) waiter();
|
|
21337
21410
|
};
|
|
21338
21411
|
const raise = () => {
|
|
21339
|
-
if (
|
|
21340
|
-
const err =
|
|
21341
|
-
|
|
21412
|
+
if (failed4 === void 0) return;
|
|
21413
|
+
const err = failed4;
|
|
21414
|
+
failed4 = void 0;
|
|
21342
21415
|
throw err;
|
|
21343
21416
|
};
|
|
21344
21417
|
const later = (bytes) => {
|
|
21345
21418
|
if (bytes.length === 0) return;
|
|
21346
21419
|
pending += 1;
|
|
21347
21420
|
tail2 = tail2.then(() => writeAll3(file, bytes)).catch((err) => {
|
|
21348
|
-
if (
|
|
21421
|
+
if (failed4 === void 0) failed4 = err;
|
|
21349
21422
|
}).finally(() => {
|
|
21350
21423
|
pending -= 1;
|
|
21351
21424
|
if (quiet2()) wake();
|
|
@@ -22727,15 +22800,15 @@ async function scramKeys(password, x) {
|
|
|
22727
22800
|
)
|
|
22728
22801
|
);
|
|
22729
22802
|
const clientKey = await hmac(salted, encoder9.encode("Client Key"));
|
|
22730
|
-
const
|
|
22803
|
+
const stored2 = new Uint8Array(
|
|
22731
22804
|
await crypto.subtle.digest("SHA-256", clientKey)
|
|
22732
22805
|
);
|
|
22733
22806
|
const auth = encoder9.encode(`${x.clientFirstBare},${x.serverFirst},${x.clientFinalBare}`);
|
|
22734
|
-
const signature = await hmac(
|
|
22807
|
+
const signature = await hmac(stored2, auth);
|
|
22735
22808
|
const proof = clientKey.map((b, i) => b ^ signature[i]);
|
|
22736
22809
|
const serverKey = await hmac(salted, encoder9.encode("Server Key"));
|
|
22737
22810
|
const serverSignature = await hmac(serverKey, auth);
|
|
22738
|
-
for (const k of [salted, clientKey,
|
|
22811
|
+
for (const k of [salted, clientKey, stored2, signature, serverKey]) k.fill(0);
|
|
22739
22812
|
return { proof, serverSignature };
|
|
22740
22813
|
}
|
|
22741
22814
|
var SPACES = /[\u00A0\u1680\u2000-\u200B\u202F\u205F\u3000]/g;
|
|
@@ -24420,7 +24493,7 @@ async function connect(req, proc) {
|
|
|
24420
24493
|
}
|
|
24421
24494
|
const path = filePath(req.addr);
|
|
24422
24495
|
const name2 = path !== void 0 ? await proc.names?.find(path) : void 0;
|
|
24423
|
-
const stamp = proc.net.
|
|
24496
|
+
const stamp = proc.net.stampsPeers(req.addr) && await proc.stamp?.();
|
|
24424
24497
|
const dialing = target.connect(req.addr, true, proc.cred?.(), stamp || void 0, true, name2);
|
|
24425
24498
|
if (req.nonblock) {
|
|
24426
24499
|
dialing?.catch(() => void 0);
|
|
@@ -24542,7 +24615,7 @@ async function secureConnect(req, proc) {
|
|
|
24542
24615
|
delete req.clientCert;
|
|
24543
24616
|
throw new KernelError("ENOTSUP");
|
|
24544
24617
|
}
|
|
24545
|
-
return { ...tlsOverTransport(req, proc), path: "transport", substitutes: true };
|
|
24618
|
+
return { ...await tlsOverTransport(req, proc), path: "transport", substitutes: true };
|
|
24546
24619
|
}
|
|
24547
24620
|
const socket = proc.net.socket("inet");
|
|
24548
24621
|
const fd = proc.fds.install(new OpenFile(socket), 3);
|
|
@@ -24561,7 +24634,7 @@ async function uplinked(proc, host) {
|
|
|
24561
24634
|
return false;
|
|
24562
24635
|
}
|
|
24563
24636
|
}
|
|
24564
|
-
function tlsOverTransport(req, proc) {
|
|
24637
|
+
async function tlsOverTransport(req, proc) {
|
|
24565
24638
|
if (req.ca) throw new KernelError("ENOTSUP");
|
|
24566
24639
|
if (req.alpn && req.alpn.length > 0 && !req.alpn.includes("http/1.1")) {
|
|
24567
24640
|
throw new KernelError("EPROTONOSUPPORT");
|
|
@@ -24574,7 +24647,9 @@ function tlsOverTransport(req, proc) {
|
|
|
24574
24647
|
if (isLoopbackHost(servername) || isLoopbackHost(req.host)) throw new KernelError("ENOTSUP");
|
|
24575
24648
|
const host = servername.includes(":") && !servername.startsWith("[") ? `[${servername}]` : servername;
|
|
24576
24649
|
const origin = req.port === 443 ? `https://${host}` : `https://${host}:${req.port}`;
|
|
24650
|
+
const stamp = proc.net.originsStamped ? await proc.stamp?.() : void 0;
|
|
24577
24651
|
const [mine, theirs] = KernelSocket.pair(proc.net, "inet", proc.cred?.());
|
|
24652
|
+
theirs.peerStamp = stamp;
|
|
24578
24653
|
mine.peer = { family: "inet", host: req.host, port: req.port };
|
|
24579
24654
|
try {
|
|
24580
24655
|
proc.net.serveOrigin(theirs, origin);
|
|
@@ -27733,13 +27808,13 @@ function inherited(opts) {
|
|
|
27733
27808
|
...opts.cred ? { cred: opts.cred } : {}
|
|
27734
27809
|
};
|
|
27735
27810
|
}
|
|
27736
|
-
function heldBy(process,
|
|
27737
|
-
process.keptPath = (path) =>
|
|
27738
|
-
process.keptHandle = (handle) =>
|
|
27739
|
-
process.holdsHandle = (handle) =>
|
|
27811
|
+
function heldBy(process, holds3, replacements) {
|
|
27812
|
+
process.keptPath = (path) => holds3.keptAt(path)?.hidden;
|
|
27813
|
+
process.keptHandle = (handle) => holds3.keptFor(handle)?.hidden;
|
|
27814
|
+
process.holdsHandle = (handle) => holds3.holdsHandle(handle);
|
|
27740
27815
|
if (replacements) process.replacements = replacements;
|
|
27741
27816
|
}
|
|
27742
|
-
function holdingToken(opts,
|
|
27817
|
+
function holdingToken(opts, holds3, caller) {
|
|
27743
27818
|
return mintSyncFsToken({
|
|
27744
27819
|
...opts.owners ? caller : { umask: caller.umask },
|
|
27745
27820
|
...opts.dac ? { dac: opts.dac, pid: opts.pid, created: caller.created } : {},
|
|
@@ -27756,16 +27831,16 @@ function holdingToken(opts, holds2, caller) {
|
|
|
27756
27831
|
...opts.fileId ? { fileId: opts.fileId } : {},
|
|
27757
27832
|
...opts.announceHold ? { announceHold: opts.announceHold } : {},
|
|
27758
27833
|
...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) =>
|
|
27834
|
+
hold: (path, on, open2, real, handle, ino, fid) => holds3.hold(path, on, open2, real, handle, ino, fid),
|
|
27835
|
+
boundIno: holds3.boundIno.bind(holds3),
|
|
27836
|
+
trust: holds3.trust.bind(holds3),
|
|
27837
|
+
keptFor: (handle) => holds3.keptFor(handle),
|
|
27838
|
+
heldAt: (handle) => holds3.pathOf(handle),
|
|
27839
|
+
unlinked: (path) => holds3.keptAt(path),
|
|
27840
|
+
gate: (path, op) => opts.unlinkGate && holds3.holding(path) ? opts.unlinkGate.run(holds3.keyOf(path), op) : op(),
|
|
27841
|
+
own: (path, op) => holds3.own(path, op),
|
|
27842
|
+
revoked: (path) => holds3.isRevoked(path),
|
|
27843
|
+
renamed: (from, to) => holds3.renamed(from, to)
|
|
27769
27844
|
});
|
|
27770
27845
|
}
|
|
27771
27846
|
function linksOf(opts) {
|
|
@@ -27922,15 +27997,15 @@ function spawnWasmProcess(opts) {
|
|
|
27922
27997
|
)
|
|
27923
27998
|
);
|
|
27924
27999
|
publishStops(process, header4);
|
|
27925
|
-
const
|
|
27926
|
-
opts.held?.add(
|
|
27927
|
-
const token = holdingToken(opts,
|
|
28000
|
+
const holds3 = new HeldPaths();
|
|
28001
|
+
opts.held?.add(holds3);
|
|
28002
|
+
const token = holdingToken(opts, holds3, {
|
|
27928
28003
|
cred: () => process.cred,
|
|
27929
28004
|
umask: () => process.umask,
|
|
27930
28005
|
created: created4,
|
|
27931
|
-
holdsKept: async (path) => path.includes(`/${UNLINKED_DIR}/`) && (
|
|
28006
|
+
holdsKept: async (path) => path.includes(`/${UNLINKED_DIR}/`) && (holds3.keeps(path) || await process.holds(path))
|
|
27932
28007
|
});
|
|
27933
|
-
heldBy(process,
|
|
28008
|
+
heldBy(process, holds3, opts.replacements);
|
|
27934
28009
|
const worker = opts.createWorker();
|
|
27935
28010
|
const dying = new Dying();
|
|
27936
28011
|
const dispatch2 = (req, block) => dying.serve(
|
|
@@ -27962,7 +28037,7 @@ function spawnWasmProcess(opts) {
|
|
|
27962
28037
|
responder.dispose();
|
|
27963
28038
|
lane?.dispose();
|
|
27964
28039
|
revokeSyncFsToken(token);
|
|
27965
|
-
opts.held?.delete(
|
|
28040
|
+
opts.held?.delete(holds3);
|
|
27966
28041
|
worker.terminate();
|
|
27967
28042
|
settleExit(process.exit(), settle3, code);
|
|
27968
28043
|
};
|
|
@@ -29148,7 +29223,7 @@ var RemoteTransport = class {
|
|
|
29148
29223
|
waiter?.reject(new TransportError("the request was cancelled"));
|
|
29149
29224
|
this.port.postMessage({ net: "cancel", nid });
|
|
29150
29225
|
}
|
|
29151
|
-
async fetch(request3) {
|
|
29226
|
+
async fetch(request3, owner, stamp) {
|
|
29152
29227
|
const nid = ++this.nextId;
|
|
29153
29228
|
const { signal, redirect } = request3;
|
|
29154
29229
|
signal.throwIfAborted();
|
|
@@ -29178,7 +29253,9 @@ var RemoteTransport = class {
|
|
|
29178
29253
|
method: request3.method,
|
|
29179
29254
|
headers: request3.headers,
|
|
29180
29255
|
...request3.bodyStream ? { streamed: true } : request3.body ? { body: request3.body } : {},
|
|
29181
|
-
...redirect !== void 0 ? { redirect } : {}
|
|
29256
|
+
...redirect !== void 0 ? { redirect } : {},
|
|
29257
|
+
...owner !== void 0 ? { owner } : {},
|
|
29258
|
+
...stamp ? { stamp } : {}
|
|
29182
29259
|
});
|
|
29183
29260
|
} catch (e) {
|
|
29184
29261
|
finish();
|
|
@@ -29369,6 +29446,143 @@ function replayingHops(inner, heldMs = HELD_MS) {
|
|
|
29369
29446
|
};
|
|
29370
29447
|
}
|
|
29371
29448
|
|
|
29449
|
+
// src/kernel/net/sealed-fetch.ts
|
|
29450
|
+
var UNSAFE_FIELD = /[\r\n\0]/;
|
|
29451
|
+
function headerList(headers) {
|
|
29452
|
+
return Array.isArray(headers) && headers.every(
|
|
29453
|
+
(field4) => Array.isArray(field4) && field4.length === 2 && field4.every((text) => typeof text === "string" && !UNSAFE_FIELD.test(text))
|
|
29454
|
+
);
|
|
29455
|
+
}
|
|
29456
|
+
function sealedReplyValid(reply) {
|
|
29457
|
+
if (typeof reply !== "object" || reply === null) return false;
|
|
29458
|
+
const { redirects, redirected: redirected2, status, statusText, headers, url, body, cancel } = reply;
|
|
29459
|
+
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";
|
|
29460
|
+
}
|
|
29461
|
+
function dropSealedReply(reply) {
|
|
29462
|
+
const { cancel } = reply ?? {};
|
|
29463
|
+
if (typeof cancel !== "function") return;
|
|
29464
|
+
void Promise.resolve().then(() => cancel.call(reply)).catch(() => void 0);
|
|
29465
|
+
}
|
|
29466
|
+
function failed2(reason) {
|
|
29467
|
+
const text = reason instanceof Error ? reason.message : String(reason);
|
|
29468
|
+
return new PlaceholderRefused(
|
|
29469
|
+
`refused: the request with a sealed placeholder was not completed: ${text}`
|
|
29470
|
+
);
|
|
29471
|
+
}
|
|
29472
|
+
var Stall = class {
|
|
29473
|
+
idle = new AbortController();
|
|
29474
|
+
ms;
|
|
29475
|
+
timer;
|
|
29476
|
+
signal;
|
|
29477
|
+
constructor(signals, ms) {
|
|
29478
|
+
this.ms = ms;
|
|
29479
|
+
this.signal = AbortSignal.any([...signals, this.idle.signal]);
|
|
29480
|
+
}
|
|
29481
|
+
arm() {
|
|
29482
|
+
clearTimeout(this.timer);
|
|
29483
|
+
this.timer = setTimeout(() => this.idle.abort("timeout"), this.ms);
|
|
29484
|
+
this.timer.unref?.();
|
|
29485
|
+
}
|
|
29486
|
+
touch() {
|
|
29487
|
+
if (this.timer !== void 0) this.arm();
|
|
29488
|
+
}
|
|
29489
|
+
rest() {
|
|
29490
|
+
clearTimeout(this.timer);
|
|
29491
|
+
this.timer = void 0;
|
|
29492
|
+
}
|
|
29493
|
+
};
|
|
29494
|
+
async function until(work, signal) {
|
|
29495
|
+
const stopped = Promise.withResolvers();
|
|
29496
|
+
const stop = () => stopped.reject(signal.reason);
|
|
29497
|
+
if (signal.aborted) stop();
|
|
29498
|
+
else signal.addEventListener("abort", stop, { once: true });
|
|
29499
|
+
try {
|
|
29500
|
+
return await Promise.race([work, stopped.promise]);
|
|
29501
|
+
} finally {
|
|
29502
|
+
signal.removeEventListener("abort", stop);
|
|
29503
|
+
}
|
|
29504
|
+
}
|
|
29505
|
+
async function* ticking(stream, stall) {
|
|
29506
|
+
for await (const chunk2 of stream) {
|
|
29507
|
+
stall.touch();
|
|
29508
|
+
yield chunk2;
|
|
29509
|
+
}
|
|
29510
|
+
}
|
|
29511
|
+
function sealedRequest(request3, stamp, stall) {
|
|
29512
|
+
const { method, url, headers, body, bodyStream } = request3;
|
|
29513
|
+
return {
|
|
29514
|
+
v: 1,
|
|
29515
|
+
caller: structuredClone(stamp),
|
|
29516
|
+
method,
|
|
29517
|
+
url,
|
|
29518
|
+
headers: headers.map(([name2, value2]) => [name2, value2]),
|
|
29519
|
+
redirect: "manual",
|
|
29520
|
+
...bodyStream ? { bodyStream: ticking(bodyStream, stall) } : body ? { body } : {}
|
|
29521
|
+
};
|
|
29522
|
+
}
|
|
29523
|
+
function guarded2(reply, stall) {
|
|
29524
|
+
let finished = false;
|
|
29525
|
+
const cancel = async () => {
|
|
29526
|
+
stall.signal.removeEventListener("abort", dropped2);
|
|
29527
|
+
stall.rest();
|
|
29528
|
+
if (finished) return;
|
|
29529
|
+
finished = true;
|
|
29530
|
+
await reply.cancel().catch(() => void 0);
|
|
29531
|
+
};
|
|
29532
|
+
const dropped2 = () => void cancel();
|
|
29533
|
+
stall.signal.addEventListener("abort", dropped2, { once: true });
|
|
29534
|
+
const source = reply.body[Symbol.asyncIterator]();
|
|
29535
|
+
const body = (async function* () {
|
|
29536
|
+
try {
|
|
29537
|
+
for (; ; ) {
|
|
29538
|
+
stall.arm();
|
|
29539
|
+
const next3 = await until(source.next(), stall.signal);
|
|
29540
|
+
stall.rest();
|
|
29541
|
+
if (next3.done) {
|
|
29542
|
+
finished = true;
|
|
29543
|
+
return;
|
|
29544
|
+
}
|
|
29545
|
+
if (!(next3.value instanceof Uint8Array)) throw failed2("a body chunk is not bytes");
|
|
29546
|
+
if (next3.value.byteLength > 0) yield next3.value;
|
|
29547
|
+
}
|
|
29548
|
+
} finally {
|
|
29549
|
+
await cancel();
|
|
29550
|
+
}
|
|
29551
|
+
})();
|
|
29552
|
+
return {
|
|
29553
|
+
...reply.url !== void 0 ? { url: reply.url } : {},
|
|
29554
|
+
status: reply.status,
|
|
29555
|
+
statusText: reply.statusText,
|
|
29556
|
+
headers: reply.headers,
|
|
29557
|
+
body,
|
|
29558
|
+
cancel
|
|
29559
|
+
};
|
|
29560
|
+
}
|
|
29561
|
+
function sealedFetcher(hook, stop, idleMs = BODY_IDLE_MS) {
|
|
29562
|
+
return async (request3, stamp) => {
|
|
29563
|
+
const stall = new Stall([request3.signal, stop], idleMs);
|
|
29564
|
+
const { signal } = stall;
|
|
29565
|
+
if (signal.aborted) throw failed2(signal.reason);
|
|
29566
|
+
stall.arm();
|
|
29567
|
+
const asked = Promise.resolve().then(() => {
|
|
29568
|
+
signal.throwIfAborted();
|
|
29569
|
+
return hook(sealedRequest(request3, stamp, stall), { signal });
|
|
29570
|
+
});
|
|
29571
|
+
let reply;
|
|
29572
|
+
try {
|
|
29573
|
+
reply = await until(asked, signal);
|
|
29574
|
+
} catch (e) {
|
|
29575
|
+
void asked.then(dropSealedReply, () => void 0);
|
|
29576
|
+
throw failed2(e);
|
|
29577
|
+
} finally {
|
|
29578
|
+
stall.rest();
|
|
29579
|
+
}
|
|
29580
|
+
if (sealedReplyValid(reply)) return guarded2(reply, stall);
|
|
29581
|
+
dropSealedReply(reply);
|
|
29582
|
+
throw failed2("the reply is not a scrubbed response");
|
|
29583
|
+
};
|
|
29584
|
+
}
|
|
29585
|
+
|
|
29372
29586
|
// src/kernel/package-swaps.ts
|
|
29373
29587
|
var SWAP_GAP_MS = 2e3;
|
|
29374
29588
|
var STAGES = ["_tmp_", "_pacquet-stage_"];
|
|
@@ -29541,11 +29755,11 @@ var PackageLocks = class {
|
|
|
29541
29755
|
if (!locks) return Promise.resolve(() => {
|
|
29542
29756
|
});
|
|
29543
29757
|
const { promise: held, resolve: release } = Promise.withResolvers();
|
|
29544
|
-
return new Promise((granted2,
|
|
29758
|
+
return new Promise((granted2, failed4) => {
|
|
29545
29759
|
locks.request(replacingLock(this.metadata, root), { mode: "exclusive" }, () => {
|
|
29546
29760
|
granted2(() => release());
|
|
29547
29761
|
return held;
|
|
29548
|
-
}).catch(
|
|
29762
|
+
}).catch(failed4);
|
|
29549
29763
|
});
|
|
29550
29764
|
}
|
|
29551
29765
|
};
|
|
@@ -30147,22 +30361,22 @@ async function mountFstab(lines2, mount, signal, retries = FSTAB_RETRIES, discar
|
|
|
30147
30361
|
);
|
|
30148
30362
|
}
|
|
30149
30363
|
async function mountLine({ line, spec, invalid }, mount, signal, retries, discard) {
|
|
30150
|
-
let
|
|
30364
|
+
let failed4 = invalid;
|
|
30151
30365
|
for (let attempt = 0; !invalid && attempt <= retries.length && !signal.aborted; attempt++) {
|
|
30152
30366
|
try {
|
|
30153
30367
|
const entry = await mount(spec);
|
|
30154
30368
|
if (!signal.aborted) return { line, target: spec.target, entry };
|
|
30155
30369
|
discard(entry);
|
|
30156
|
-
|
|
30370
|
+
failed4 = Object.assign(new Error("the kernel stopped"), { code: "ECANCELED" });
|
|
30157
30371
|
break;
|
|
30158
30372
|
} catch (err) {
|
|
30159
|
-
|
|
30373
|
+
failed4 = err;
|
|
30160
30374
|
if (FINAL.has(codeOf6(err)) || attempt === retries.length) break;
|
|
30161
30375
|
await wait(retries[attempt], signal);
|
|
30162
30376
|
}
|
|
30163
30377
|
}
|
|
30164
|
-
const code = codeOf6(
|
|
30165
|
-
return { line, target: spec.target, code, error: String(
|
|
30378
|
+
const code = codeOf6(failed4);
|
|
30379
|
+
return { line, target: spec.target, code, error: String(failed4?.message ?? code) };
|
|
30166
30380
|
}
|
|
30167
30381
|
|
|
30168
30382
|
// src/mount/hostfs.ts
|
|
@@ -30851,18 +31065,28 @@ function settle2(request3, value2) {
|
|
|
30851
31065
|
request3.onerror = () => reject(request3.error);
|
|
30852
31066
|
});
|
|
30853
31067
|
}
|
|
30854
|
-
|
|
31068
|
+
var privateTop2 = () => navigator.storage.getDirectory();
|
|
31069
|
+
async function stored(kept, top) {
|
|
31070
|
+
const path = kept?.path;
|
|
31071
|
+
if (!Array.isArray(path)) return kept;
|
|
31072
|
+
return directoryAt(await top(), path).catch(() => void 0);
|
|
31073
|
+
}
|
|
31074
|
+
function openMedia(name2, factory, top = privateTop2) {
|
|
30855
31075
|
const request3 = factory.open(name2, 1);
|
|
30856
31076
|
request3.onupgradeneeded = () => request3.result.createObjectStore(MEDIA_STORE);
|
|
30857
31077
|
return settle2(request3, () => {
|
|
30858
31078
|
const db = request3.result;
|
|
30859
31079
|
const store = (mode) => db.transaction(MEDIA_STORE, mode).objectStore(MEDIA_STORE);
|
|
30860
31080
|
return {
|
|
30861
|
-
get: (id2) => {
|
|
31081
|
+
get: async (id2) => {
|
|
30862
31082
|
const got = store("readonly").get(id2);
|
|
30863
|
-
return settle2(got, () => got.result);
|
|
31083
|
+
return stored(await settle2(got, () => got.result), top);
|
|
30864
31084
|
},
|
|
30865
|
-
put: (id2, handle) =>
|
|
31085
|
+
put: async (id2, handle) => {
|
|
31086
|
+
const at = await portable(handle, top);
|
|
31087
|
+
const kept = "path" in at ? at : handle;
|
|
31088
|
+
await settle2(store("readwrite").put(kept, id2), () => void 0);
|
|
31089
|
+
}
|
|
30866
31090
|
};
|
|
30867
31091
|
});
|
|
30868
31092
|
}
|
|
@@ -31336,7 +31560,7 @@ var RULE = new RegExp(
|
|
|
31336
31560
|
var TERM = /^[A-Za-z0-9._+-]+$/;
|
|
31337
31561
|
var PLAIN3 = /^[A-Za-z0-9_@%+=:,./-]+$/;
|
|
31338
31562
|
var USAGE = "usage: sudo [-n] [-u user] [--] command [args...]\n sudo -l";
|
|
31339
|
-
function
|
|
31563
|
+
function failed3(errno3, error) {
|
|
31340
31564
|
return { error, errno: errno3 };
|
|
31341
31565
|
}
|
|
31342
31566
|
function unescaped(double) {
|
|
@@ -31515,10 +31739,10 @@ var Sudo = class {
|
|
|
31515
31739
|
}
|
|
31516
31740
|
async untrusted(path, cwd, word) {
|
|
31517
31741
|
const files = this.o.backing ? await this.o.backing(path, cwd) : [];
|
|
31518
|
-
if (!files) return
|
|
31742
|
+
if (!files) return failed3("ENOENT", `sudo: ${word}: command not found`);
|
|
31519
31743
|
for (const file of [path, ...files]) {
|
|
31520
31744
|
if (!await this.trusted(file)) {
|
|
31521
|
-
return
|
|
31745
|
+
return failed3("EPERM", `sudo: ${file} must be root's, and writable by root only`);
|
|
31522
31746
|
}
|
|
31523
31747
|
}
|
|
31524
31748
|
return void 0;
|
|
@@ -31535,7 +31759,7 @@ var Sudo = class {
|
|
|
31535
31759
|
}
|
|
31536
31760
|
async request(caller, call, signal) {
|
|
31537
31761
|
const parsed2 = parseArgs(call.args);
|
|
31538
|
-
if (typeof parsed2 === "string") return
|
|
31762
|
+
if (typeof parsed2 === "string") return failed3("EINVAL", parsed2);
|
|
31539
31763
|
if (this.o.mode !== "enforce") {
|
|
31540
31764
|
const mode = this.o.mode;
|
|
31541
31765
|
if (parsed2.list) return { list: `sudo: users are '${mode}': commands run as the caller
|
|
@@ -31544,9 +31768,9 @@ var Sudo = class {
|
|
|
31544
31768
|
}
|
|
31545
31769
|
const { cred } = caller;
|
|
31546
31770
|
const self = await this.o.users.lookup(cred.ruid);
|
|
31547
|
-
if (!self) return
|
|
31771
|
+
if (!self) return failed3("EPERM", `sudo: uid ${cred.ruid} is not in the passwd database`);
|
|
31548
31772
|
const target = await this.lookup(parsed2.user);
|
|
31549
|
-
if (!target) return
|
|
31773
|
+
if (!target) return failed3("ENOENT", `sudo: unknown user ${parsed2.user}`);
|
|
31550
31774
|
const root = cred.euid === 0;
|
|
31551
31775
|
const rules = root ? [] : await this.policy();
|
|
31552
31776
|
const applies = await this.applies(self, cred);
|
|
@@ -31554,13 +31778,13 @@ var Sudo = class {
|
|
|
31554
31778
|
const [word = "", ...args] = parsed2.command;
|
|
31555
31779
|
const cwd = await this.canonical(call.cwd);
|
|
31556
31780
|
if (cwd === void 0 || !await this.reachable(cred, cwd)) {
|
|
31557
|
-
return
|
|
31781
|
+
return failed3(
|
|
31558
31782
|
"EACCES",
|
|
31559
31783
|
`sudo: cannot run in ${call.cwd}: it isn't a directory you can enter`
|
|
31560
31784
|
);
|
|
31561
31785
|
}
|
|
31562
31786
|
const path = await this.locate(word, cwd);
|
|
31563
|
-
if (!path) return
|
|
31787
|
+
if (!path) return failed3("ENOENT", `sudo: ${word}: command not found`);
|
|
31564
31788
|
const untrusted2 = await this.untrusted(path, cwd, word);
|
|
31565
31789
|
if (untrusted2) return untrusted2;
|
|
31566
31790
|
const argv = [path, ...args];
|
|
@@ -31571,24 +31795,24 @@ var Sudo = class {
|
|
|
31571
31795
|
if (root || matching.some((rule) => rule.nopasswd)) return grant();
|
|
31572
31796
|
const quoted = argv.map(quoteWord).join(" ");
|
|
31573
31797
|
if (matching.length === 0) {
|
|
31574
|
-
return
|
|
31798
|
+
return failed3(
|
|
31575
31799
|
"EPERM",
|
|
31576
31800
|
`sudo: ${self.name} is not allowed to run ${quoted} as ${target.name}`
|
|
31577
31801
|
);
|
|
31578
31802
|
}
|
|
31579
|
-
if (parsed2.nonInteractive) return
|
|
31580
|
-
if (this.pending.has(cred.ruid)) return
|
|
31803
|
+
if (parsed2.nonInteractive) return failed3("EPERM", "sudo: a password is required");
|
|
31804
|
+
if (this.pending.has(cred.ruid)) return failed3("EBUSY", "sudo: another request is pending");
|
|
31581
31805
|
this.pending.add(cred.ruid);
|
|
31582
31806
|
try {
|
|
31583
31807
|
const answer2 = await this.ask(caller, self, target, parsed2.command, path, cwd, signal);
|
|
31584
31808
|
if (typeof answer2 !== "string") return answer2;
|
|
31585
31809
|
if (await this.canonical(call.cwd) !== cwd || !await this.reachable(cred, cwd)) {
|
|
31586
|
-
return
|
|
31810
|
+
return failed3("EACCES", `sudo: ${call.cwd} changed while the request waited`);
|
|
31587
31811
|
}
|
|
31588
31812
|
const changed = await this.untrusted(path, cwd, word);
|
|
31589
31813
|
if (changed) return changed;
|
|
31590
31814
|
if (answer2 === "always" && !await this.remember(self, target, cwd, argv)) {
|
|
31591
|
-
return
|
|
31815
|
+
return failed3("EIO", "sudo: the rule could not be recorded");
|
|
31592
31816
|
}
|
|
31593
31817
|
return grant();
|
|
31594
31818
|
} finally {
|
|
@@ -31605,7 +31829,7 @@ var Sudo = class {
|
|
|
31605
31829
|
};
|
|
31606
31830
|
}
|
|
31607
31831
|
if (rules.length === 0) {
|
|
31608
|
-
return
|
|
31832
|
+
return failed3("EPERM", `User ${self.name} is not allowed to run sudo on ${host}.`);
|
|
31609
31833
|
}
|
|
31610
31834
|
const lines2 = rules.map(described).join("\n");
|
|
31611
31835
|
return { list: `User ${self.name} may run the following commands on ${host}:
|
|
@@ -31614,7 +31838,7 @@ ${lines2}
|
|
|
31614
31838
|
}
|
|
31615
31839
|
async ask(caller, self, target, argv, path, cwd, requester) {
|
|
31616
31840
|
const { approve } = this.o;
|
|
31617
|
-
if (!approve || requester.aborted) return
|
|
31841
|
+
if (!approve || requester.aborted) return failed3("EACCES", "sudo: approval denied");
|
|
31618
31842
|
const createdAt = Date.now();
|
|
31619
31843
|
const timeout = this.o.timeoutMs ?? SUDO_TIMEOUT_MS;
|
|
31620
31844
|
const req = {
|
|
@@ -31644,9 +31868,9 @@ ${lines2}
|
|
|
31644
31868
|
const answered2 = Promise.resolve().then(() => approve(req, { signal: control.signal })).catch(() => "deny");
|
|
31645
31869
|
const answer2 = await Promise.race([answered2, aborted3]);
|
|
31646
31870
|
if (answer2 === "aborted" || control.signal.aborted) {
|
|
31647
|
-
return control.signal.reason === "expired" ?
|
|
31871
|
+
return control.signal.reason === "expired" ? failed3("ETIMEDOUT", "sudo: the request expired") : failed3("EINTR", "sudo: the request was withdrawn");
|
|
31648
31872
|
}
|
|
31649
|
-
return answer2 === "once" || answer2 === "always" ? answer2 :
|
|
31873
|
+
return answer2 === "once" || answer2 === "always" ? answer2 : failed3("EACCES", "sudo: approval denied");
|
|
31650
31874
|
} finally {
|
|
31651
31875
|
clearTimeout(timer);
|
|
31652
31876
|
requester.removeEventListener("abort", withdraw);
|
|
@@ -31937,13 +32161,13 @@ function interpreter(head) {
|
|
|
31937
32161
|
function expandDefaults(defaults2, env) {
|
|
31938
32162
|
const out = {};
|
|
31939
32163
|
for (const [key, value2] of Object.entries(defaults2 ?? {})) {
|
|
31940
|
-
let
|
|
32164
|
+
let missing6 = false;
|
|
31941
32165
|
const expanded = value2.replace(ENV_REFERENCE, (_, name2) => {
|
|
31942
32166
|
const set3 = Object.hasOwn(env, name2) ? env[name2] : void 0;
|
|
31943
|
-
if (set3 === void 0)
|
|
32167
|
+
if (set3 === void 0) missing6 = true;
|
|
31944
32168
|
return set3 ?? "";
|
|
31945
32169
|
});
|
|
31946
|
-
if (!
|
|
32170
|
+
if (!missing6) out[key] = expanded;
|
|
31947
32171
|
}
|
|
31948
32172
|
return out;
|
|
31949
32173
|
}
|
|
@@ -32118,6 +32342,9 @@ var Launcher = class {
|
|
|
32118
32342
|
usersMode;
|
|
32119
32343
|
dac;
|
|
32120
32344
|
sealed;
|
|
32345
|
+
fill;
|
|
32346
|
+
fills = new AbortController();
|
|
32347
|
+
placeholders = [];
|
|
32121
32348
|
scrubs = /* @__PURE__ */ new Map();
|
|
32122
32349
|
clipboard;
|
|
32123
32350
|
embedder;
|
|
@@ -32199,7 +32426,7 @@ var Launcher = class {
|
|
|
32199
32426
|
...options.env
|
|
32200
32427
|
};
|
|
32201
32428
|
this.ca = kernelCa(options.caStore ?? memoryCaStore());
|
|
32202
|
-
this.transport =
|
|
32429
|
+
this.transport = this.floored(options);
|
|
32203
32430
|
this.announcedTraits = JSON.stringify(this.transport.traits);
|
|
32204
32431
|
this.uplink = options.uplink;
|
|
32205
32432
|
this.routes = new Routes(options.uplink?.traits.ipv6 === true);
|
|
@@ -33261,6 +33488,19 @@ var Launcher = class {
|
|
|
33261
33488
|
groupSession(pgid) {
|
|
33262
33489
|
return this.jobs.sessionOf(pgid);
|
|
33263
33490
|
}
|
|
33491
|
+
floored(options) {
|
|
33492
|
+
const { sealedFetch } = options;
|
|
33493
|
+
this.fill = sealedFetch && this.usersMode === "enforce" ? sealedFetcher(sealedFetch, this.fills.signal) : void 0;
|
|
33494
|
+
if (this.fill) this.net.stampProxy(REALM_PROXY_PORT);
|
|
33495
|
+
return placeholderFloor(replayingHops(options.transport ?? missingTransport()), {
|
|
33496
|
+
known: () => this.placeholders,
|
|
33497
|
+
...this.fill ? { fill: this.fill } : {}
|
|
33498
|
+
});
|
|
33499
|
+
}
|
|
33500
|
+
httpFor(pid) {
|
|
33501
|
+
const stamp = this.fill ? () => this.liveStamp(pid) : void 0;
|
|
33502
|
+
return new HttpHandles(this.transport, pid, this.loopbackFor(pid), stamp);
|
|
33503
|
+
}
|
|
33264
33504
|
loopbackFor(pid) {
|
|
33265
33505
|
return new KernelLoopback(
|
|
33266
33506
|
this.net,
|
|
@@ -33268,7 +33508,7 @@ var Launcher = class {
|
|
|
33268
33508
|
const cred = this.credOf(pid);
|
|
33269
33509
|
return { pid, uid: cred.euid, gid: cred.egid };
|
|
33270
33510
|
},
|
|
33271
|
-
() => this.
|
|
33511
|
+
() => this.liveStamp(pid)
|
|
33272
33512
|
);
|
|
33273
33513
|
}
|
|
33274
33514
|
sourceCheck(pid, writer) {
|
|
@@ -33433,7 +33673,7 @@ var Launcher = class {
|
|
|
33433
33673
|
jobs: this.jobs,
|
|
33434
33674
|
ptys: this.ptys,
|
|
33435
33675
|
net: this.net,
|
|
33436
|
-
http:
|
|
33676
|
+
http: this.httpFor(pid),
|
|
33437
33677
|
locks: this.locks,
|
|
33438
33678
|
fifos: this.fifos,
|
|
33439
33679
|
sems: this.sems,
|
|
@@ -33598,7 +33838,7 @@ var Launcher = class {
|
|
|
33598
33838
|
}
|
|
33599
33839
|
list(viewer = ROOT) {
|
|
33600
33840
|
const members = new Map(this.jobs.list().map((member) => [member.pid, member]));
|
|
33601
|
-
const
|
|
33841
|
+
const rootOf2 = (member) => {
|
|
33602
33842
|
let root = member;
|
|
33603
33843
|
for (let up = members.get(root.execParent ?? -1); up; up = members.get(up.execParent ?? -1)) {
|
|
33604
33844
|
root = up;
|
|
@@ -33607,7 +33847,7 @@ var Launcher = class {
|
|
|
33607
33847
|
};
|
|
33608
33848
|
const shown = (pid) => {
|
|
33609
33849
|
const member = pid === void 0 ? void 0 : members.get(pid);
|
|
33610
|
-
const root = member &&
|
|
33850
|
+
const root = member && rootOf2(member).pid;
|
|
33611
33851
|
return root !== void 0 && this.running(root) ? root : INIT_PID;
|
|
33612
33852
|
};
|
|
33613
33853
|
const superseded = new Set([...members.values()].map((m) => m.execParent));
|
|
@@ -33617,7 +33857,7 @@ var Launcher = class {
|
|
|
33617
33857
|
if (member.execed && superseded.has(member.pid) || !described2) continue;
|
|
33618
33858
|
const cred = this.credOf(member.pid);
|
|
33619
33859
|
if (!maySee(viewer, cred)) continue;
|
|
33620
|
-
const root =
|
|
33860
|
+
const root = rootOf2(member);
|
|
33621
33861
|
const tags = this.tagsOf(member.pid) ?? this.tagsOf(root.pid);
|
|
33622
33862
|
listed.push({
|
|
33623
33863
|
pid: root.pid,
|
|
@@ -33748,6 +33988,19 @@ var Launcher = class {
|
|
|
33748
33988
|
connectorStamp(pid) {
|
|
33749
33989
|
return this.sealed.stamp(this.identityOf(pid), this.credOf(pid), this.tagsOf(pid));
|
|
33750
33990
|
}
|
|
33991
|
+
async liveStamp(pid) {
|
|
33992
|
+
if (!this.creds.has(pid) || this.zombies.has(pid)) return void 0;
|
|
33993
|
+
return this.connectorStamp(pid);
|
|
33994
|
+
}
|
|
33995
|
+
setPlaceholders(list) {
|
|
33996
|
+
if (!Array.isArray(list) || !list.every((p) => typeof p === "string" && p !== "")) {
|
|
33997
|
+
throw fsError("EINVAL", "setPlaceholders takes a list of non-empty strings");
|
|
33998
|
+
}
|
|
33999
|
+
this.placeholders = [...list];
|
|
34000
|
+
}
|
|
34001
|
+
endFills() {
|
|
34002
|
+
this.fills.abort("terminated");
|
|
34003
|
+
}
|
|
33751
34004
|
identityOf(pid) {
|
|
33752
34005
|
const parent = this.jobs.shownParent(pid);
|
|
33753
34006
|
const alive = parent !== void 0 && this.running(parent);
|
|
@@ -33870,7 +34123,7 @@ var Launcher = class {
|
|
|
33870
34123
|
const at = normalizePath(path);
|
|
33871
34124
|
this.unlinked.closed(at);
|
|
33872
34125
|
this.writers?.unlinked.closed(at);
|
|
33873
|
-
const holding = [...this.held].some((
|
|
34126
|
+
const holding = [...this.held].some((holds3) => holds3.holding(at)) || [...this.openFiles].some((open3) => open3.holdsAt(at));
|
|
33874
34127
|
if (!holding) void this.rootFs.announceHolds?.([], [at], false);
|
|
33875
34128
|
const open2 = [...this.openFiles].some((nodes) => nodes.writes(at)) || heldUnder(this.held, at);
|
|
33876
34129
|
if (!open2) void this.mounts.commit(at).catch(() => void 0);
|
|
@@ -34003,9 +34256,9 @@ var Launcher = class {
|
|
|
34003
34256
|
const served2 = serveFilesystem(port2, medium.handlers, FSA_CAPABILITIES);
|
|
34004
34257
|
const id2 = source.slice("fsa:".length);
|
|
34005
34258
|
this.removable.set(target, { id: id2, medium, served: served2 });
|
|
34006
|
-
const
|
|
34007
|
-
if (
|
|
34008
|
-
else ask(
|
|
34259
|
+
const stored2 = this.inserted.get(id2) ?? await this.media.get(id2);
|
|
34260
|
+
if (stored2 && await granted(stored2)) medium.insert(stored2);
|
|
34261
|
+
else ask(stored2);
|
|
34009
34262
|
return {
|
|
34010
34263
|
port: port1,
|
|
34011
34264
|
present: () => medium.present(),
|
|
@@ -34033,8 +34286,9 @@ var Launcher = class {
|
|
|
34033
34286
|
for (const root of roots) this.integrity.forget(root);
|
|
34034
34287
|
this.resetCatalogs();
|
|
34035
34288
|
}
|
|
34036
|
-
attest(path) {
|
|
34289
|
+
attest(path, options = {}) {
|
|
34037
34290
|
return attest(this.rootFs, path, {
|
|
34291
|
+
...options,
|
|
34038
34292
|
users: this.usersMode,
|
|
34039
34293
|
mounts: this.mounts.list().map((entry) => entry.target).filter((target) => this.mounts.mounted(target) !== void 0)
|
|
34040
34294
|
});
|
|
@@ -34091,8 +34345,8 @@ var Launcher = class {
|
|
|
34091
34345
|
for (const name2 of names2 ?? []) {
|
|
34092
34346
|
const path = joinName(real, name2);
|
|
34093
34347
|
if (await this.base.hasOwner(path)) continue;
|
|
34094
|
-
const
|
|
34095
|
-
if (
|
|
34348
|
+
const failed4 = this.inUse(path) ? "busy" : await this.base.rm(path, { recursive: true, force: true }).catch(String);
|
|
34349
|
+
if (failed4 === void 0) removed++;
|
|
34096
34350
|
else left++;
|
|
34097
34351
|
}
|
|
34098
34352
|
if (removed > 0) {
|
|
@@ -34187,7 +34441,7 @@ var Launcher = class {
|
|
|
34187
34441
|
this.pnpmStale();
|
|
34188
34442
|
if (!detach) return;
|
|
34189
34443
|
for (const nodes of this.openFiles) nodes.revoke(at);
|
|
34190
|
-
for (const
|
|
34444
|
+
for (const holds3 of this.held) holds3.revoke(at);
|
|
34191
34445
|
}
|
|
34192
34446
|
unmountAll() {
|
|
34193
34447
|
this.cron.stop();
|
|
@@ -34398,9 +34652,9 @@ var Launcher = class {
|
|
|
34398
34652
|
}
|
|
34399
34653
|
boundTo(path, hidden, fids) {
|
|
34400
34654
|
const keeping = [...this.held].map(
|
|
34401
|
-
(
|
|
34402
|
-
|
|
34403
|
-
fids.flatMap((fid) => [...
|
|
34655
|
+
(holds3) => [
|
|
34656
|
+
holds3,
|
|
34657
|
+
fids.flatMap((fid) => [...holds3.boundAt(path, fid), ...holds3.boundAt(hidden, fid)])
|
|
34404
34658
|
]
|
|
34405
34659
|
).filter(([, ids]) => ids.length > 0);
|
|
34406
34660
|
const nodes = [...this.openFiles].filter(
|
|
@@ -34411,7 +34665,7 @@ var Launcher = class {
|
|
|
34411
34665
|
(open2) => fids.some((fid) => open2.keepBound([hidden, path], fid, file))
|
|
34412
34666
|
).length;
|
|
34413
34667
|
for (let i = kept; i < nodes.length; i++) file.release();
|
|
34414
|
-
for (const [
|
|
34668
|
+
for (const [holds3, ids] of keeping) holds3.keepBound(ids, path, file);
|
|
34415
34669
|
void this.rootFs.announceHolds?.([], [path, hidden], false);
|
|
34416
34670
|
};
|
|
34417
34671
|
return { keeping, nodes, keep: keep2 };
|
|
@@ -34571,7 +34825,7 @@ var Launcher = class {
|
|
|
34571
34825
|
}
|
|
34572
34826
|
moved(from, to, source) {
|
|
34573
34827
|
this.renameLog.add(from, to);
|
|
34574
|
-
for (const
|
|
34828
|
+
for (const holds3 of this.held) holds3.renamed(from, to);
|
|
34575
34829
|
if (source) return;
|
|
34576
34830
|
for (const nodes of this.openFiles) nodes.renamed(from, to);
|
|
34577
34831
|
this.watchers.moved(from, to);
|
|
@@ -34784,6 +35038,98 @@ function integrityAsker(port) {
|
|
|
34784
35038
|
}
|
|
34785
35039
|
|
|
34786
35040
|
// src/sealed-relay.ts
|
|
35041
|
+
function textOf(err) {
|
|
35042
|
+
return err instanceof Error ? err.message : String(err);
|
|
35043
|
+
}
|
|
35044
|
+
function sendBytes(port, bytes) {
|
|
35045
|
+
const copy = fresh(bytes);
|
|
35046
|
+
port.postMessage({ t: "chunk", bytes: copy }, [copy.buffer]);
|
|
35047
|
+
}
|
|
35048
|
+
function askFetch(port, req, signal) {
|
|
35049
|
+
signal.throwIfAborted();
|
|
35050
|
+
const { bodyStream, ...wire } = req;
|
|
35051
|
+
const { port1: near, port2: far } = new MessageChannel();
|
|
35052
|
+
const upload = bodyStream?.[Symbol.asyncIterator]();
|
|
35053
|
+
const head = Promise.withResolvers();
|
|
35054
|
+
let reading;
|
|
35055
|
+
let ended = false;
|
|
35056
|
+
const end = (failure2) => {
|
|
35057
|
+
if (ended) return;
|
|
35058
|
+
ended = true;
|
|
35059
|
+
signal.removeEventListener("abort", abort);
|
|
35060
|
+
near.close();
|
|
35061
|
+
void upload?.return?.().catch(() => void 0);
|
|
35062
|
+
head.reject(failure2);
|
|
35063
|
+
reading?.reject(failure2);
|
|
35064
|
+
reading = void 0;
|
|
35065
|
+
};
|
|
35066
|
+
const abort = () => {
|
|
35067
|
+
near.postMessage({ t: "cancel", reason: String(signal.reason) });
|
|
35068
|
+
end(new Error(String(signal.reason)));
|
|
35069
|
+
};
|
|
35070
|
+
const pull = async () => {
|
|
35071
|
+
try {
|
|
35072
|
+
const next3 = await upload.next();
|
|
35073
|
+
if (ended) return;
|
|
35074
|
+
if (next3.done) near.postMessage({ t: "end" });
|
|
35075
|
+
else sendBytes(near, next3.value);
|
|
35076
|
+
} catch (err) {
|
|
35077
|
+
if (!ended) near.postMessage({ t: "error", message: textOf(err) });
|
|
35078
|
+
}
|
|
35079
|
+
};
|
|
35080
|
+
const respond2 = (message3) => {
|
|
35081
|
+
const { status, statusText, headers, url } = message3;
|
|
35082
|
+
const body = {
|
|
35083
|
+
[Symbol.asyncIterator]: () => ({
|
|
35084
|
+
next: () => {
|
|
35085
|
+
if (ended) return Promise.resolve({ value: void 0, done: true });
|
|
35086
|
+
reading = Promise.withResolvers();
|
|
35087
|
+
near.postMessage({ t: "read" });
|
|
35088
|
+
return reading.promise;
|
|
35089
|
+
},
|
|
35090
|
+
return: async () => {
|
|
35091
|
+
await cancel();
|
|
35092
|
+
return { value: void 0, done: true };
|
|
35093
|
+
}
|
|
35094
|
+
})
|
|
35095
|
+
};
|
|
35096
|
+
const cancel = async () => {
|
|
35097
|
+
if (ended) return;
|
|
35098
|
+
near.postMessage({ t: "cancel", reason: "cancelled" });
|
|
35099
|
+
end(new Error("the request was cancelled"));
|
|
35100
|
+
};
|
|
35101
|
+
head.resolve({
|
|
35102
|
+
...url !== void 0 ? { url } : {},
|
|
35103
|
+
status,
|
|
35104
|
+
statusText,
|
|
35105
|
+
headers,
|
|
35106
|
+
body,
|
|
35107
|
+
cancel
|
|
35108
|
+
});
|
|
35109
|
+
};
|
|
35110
|
+
near.addEventListener("message", ({ data }) => {
|
|
35111
|
+
if (data.t === "pull") void pull();
|
|
35112
|
+
else if (data.t === "stop") void upload?.return?.().catch(() => void 0);
|
|
35113
|
+
else if (data.t === "head") respond2(data);
|
|
35114
|
+
else if (data.t === "chunk") {
|
|
35115
|
+
reading?.resolve({ value: data.bytes, done: false });
|
|
35116
|
+
reading = void 0;
|
|
35117
|
+
} else if (data.t === "end") {
|
|
35118
|
+
reading?.resolve({ value: void 0, done: true });
|
|
35119
|
+
reading = void 0;
|
|
35120
|
+
end(new Error("the response ended"));
|
|
35121
|
+
} else end(new Error(data.message));
|
|
35122
|
+
});
|
|
35123
|
+
near.addEventListener("close", () => end(new Error("the sealed fetch relay closed")));
|
|
35124
|
+
near.start();
|
|
35125
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
35126
|
+
const ask = {
|
|
35127
|
+
req: { ...wire, ...upload ? { streamed: true } : {} },
|
|
35128
|
+
port: far
|
|
35129
|
+
};
|
|
35130
|
+
port.postMessage({ sealedFetch: ask }, [far]);
|
|
35131
|
+
return head.promise;
|
|
35132
|
+
}
|
|
34787
35133
|
function sealedAsker(port) {
|
|
34788
35134
|
const asks = /* @__PURE__ */ new Map();
|
|
34789
35135
|
let next3 = 0;
|
|
@@ -34807,7 +35153,7 @@ function sealedAsker(port) {
|
|
|
34807
35153
|
if (reply) waiting.resolve(reply);
|
|
34808
35154
|
else waiting.reject(new Error(error ?? "no reply"));
|
|
34809
35155
|
};
|
|
34810
|
-
return { hook, answer: answer2 };
|
|
35156
|
+
return { hook, fetch: (req, { signal }) => askFetch(port, req, signal), answer: answer2 };
|
|
34811
35157
|
}
|
|
34812
35158
|
|
|
34813
35159
|
// src/serve.ts
|
|
@@ -34825,11 +35171,24 @@ async function inOpfs(deps, root) {
|
|
|
34825
35171
|
return await opfs?.resolve(root).catch(() => null) != null;
|
|
34826
35172
|
}
|
|
34827
35173
|
async function rootNamed(deps, req, root) {
|
|
34828
|
-
if (req.metadata !== void 0 || !req.root || !deps.rootId) return req;
|
|
35174
|
+
if (req.metadata !== void 0 || !req.root && !req.rootPath || !deps.rootId) return req;
|
|
34829
35175
|
const top = await deps.storage().catch(() => void 0);
|
|
34830
35176
|
const name2 = await metadataName(top, root, deps.rootId);
|
|
34831
35177
|
return name2 === META_DB ? req : { ...req, metadata: name2 };
|
|
34832
35178
|
}
|
|
35179
|
+
async function rootOf(deps, req) {
|
|
35180
|
+
if (req.root) return req.root;
|
|
35181
|
+
const top = await deps.storage();
|
|
35182
|
+
return req.rootPath ? directoryAt(top, req.rootPath) : top;
|
|
35183
|
+
}
|
|
35184
|
+
async function insertedHandle(deps, req) {
|
|
35185
|
+
return "path" in req ? directoryAt(await deps.storage(), req.path) : req.handle;
|
|
35186
|
+
}
|
|
35187
|
+
function crossable(medium) {
|
|
35188
|
+
if (!medium.handle || clonable(medium.handle)) return medium;
|
|
35189
|
+
const { handle: _, ...rest2 } = medium;
|
|
35190
|
+
return rest2;
|
|
35191
|
+
}
|
|
34833
35192
|
function workers(deps) {
|
|
34834
35193
|
return {
|
|
34835
35194
|
createWorker: deps.createWorker,
|
|
@@ -34965,13 +35324,15 @@ function transferOf2(req, result) {
|
|
|
34965
35324
|
if (result instanceof MessagePort) return [result];
|
|
34966
35325
|
const bound3 = result?.port;
|
|
34967
35326
|
if (req.op === "connect" && bound3 instanceof MessagePort) return [bound3];
|
|
34968
|
-
if (req.op === "attest"
|
|
35327
|
+
if (req.op === "attest" && "bytes" in result) {
|
|
35328
|
+
return [result.bytes.buffer];
|
|
35329
|
+
}
|
|
34969
35330
|
return void 0;
|
|
34970
35331
|
}
|
|
34971
35332
|
function attestOps(port) {
|
|
34972
35333
|
const watches = /* @__PURE__ */ new Map();
|
|
34973
35334
|
return async (l, req) => {
|
|
34974
|
-
if (req.op === "attest") return l.attest(req.path);
|
|
35335
|
+
if (req.op === "attest") return l.attest(req.path, req.options);
|
|
34975
35336
|
if (req.op === "chmod") return l.fs.chmod(req.path, modeOption(req.mode)).then(() => true);
|
|
34976
35337
|
if (req.op === "integrity-revoke") return l.revokeIntegrity(req.path).then(() => true);
|
|
34977
35338
|
if (req.op === "unwatch-files") {
|
|
@@ -35026,7 +35387,7 @@ async function connectClient(deps, { user, tag, bind: bind2 }) {
|
|
|
35026
35387
|
});
|
|
35027
35388
|
return unbind ? { port: port2, client } : port2;
|
|
35028
35389
|
}
|
|
35029
|
-
function hostOptions(req, port, sealed, clipboard, lookup2, requests) {
|
|
35390
|
+
function hostOptions(req, port, sealed, sealedFetch, clipboard, lookup2, requests) {
|
|
35030
35391
|
return {
|
|
35031
35392
|
cron: { lock: `slicc-kernel-cron:${req.metadata ?? META_DB}` },
|
|
35032
35393
|
...req.hostname !== void 0 ? { hostname: req.hostname } : {},
|
|
@@ -35035,6 +35396,7 @@ function hostOptions(req, port, sealed, clipboard, lookup2, requests) {
|
|
|
35035
35396
|
...req.denials ? { onDenial: (denial) => port.postMessage({ denial }) } : {},
|
|
35036
35397
|
...req.protect ? { protect: hostProtect(req.protect, lookup2) } : {},
|
|
35037
35398
|
...req.sealed ? { sealed } : {},
|
|
35399
|
+
...req.sealedFetch ? { sealedFetch } : {},
|
|
35038
35400
|
...req.clipboard ? { clipboard } : {},
|
|
35039
35401
|
...req.requests ? { embedder: requests.hookFor(0, req.requests) } : {}
|
|
35040
35402
|
};
|
|
@@ -35109,7 +35471,7 @@ function serveKernel(port, deps) {
|
|
|
35109
35471
|
}
|
|
35110
35472
|
}
|
|
35111
35473
|
async function init(req) {
|
|
35112
|
-
launcher = (
|
|
35474
|
+
launcher = rootOf(deps, req).then(async (root) => {
|
|
35113
35475
|
req = await rootNamed(deps, req, root);
|
|
35114
35476
|
const name2 = req.metadata ?? META_DB;
|
|
35115
35477
|
const { meta, media } = await stores(deps, name2, req.media);
|
|
@@ -35125,11 +35487,19 @@ function serveKernel(port, deps) {
|
|
|
35125
35487
|
...req.modules ? { modules: req.modules } : {},
|
|
35126
35488
|
...req.commands ? { commands: req.commands } : {},
|
|
35127
35489
|
...req.env ? { env: req.env } : {},
|
|
35128
|
-
...hostOptions(
|
|
35490
|
+
...hostOptions(
|
|
35491
|
+
req,
|
|
35492
|
+
port,
|
|
35493
|
+
sealed.hook,
|
|
35494
|
+
sealed.fetch,
|
|
35495
|
+
clipboard.hook,
|
|
35496
|
+
integrity.lookup,
|
|
35497
|
+
requests
|
|
35498
|
+
),
|
|
35129
35499
|
...req.approve ? { approve: approvals.ask } : {},
|
|
35130
35500
|
...net,
|
|
35131
35501
|
...media ? { media } : {},
|
|
35132
|
-
onMountPending: (medium) => port.postMessage({ medium }),
|
|
35502
|
+
onMountPending: (medium) => port.postMessage({ medium: crossable(medium) }),
|
|
35133
35503
|
...req.hostfs ? { hostfs: askGrant } : {},
|
|
35134
35504
|
...pageHooks(req, port),
|
|
35135
35505
|
...mountPolicy(req.processMounts),
|
|
@@ -35145,13 +35515,15 @@ function serveKernel(port, deps) {
|
|
|
35145
35515
|
const l = await ready2();
|
|
35146
35516
|
if (req.op === "mount") return l.mount(req.spec);
|
|
35147
35517
|
if (req.op === "umount") return l.umount(req.target);
|
|
35148
|
-
if (req.op === "insert")
|
|
35518
|
+
if (req.op === "insert")
|
|
35519
|
+
return l.insert(req.target, await insertedHandle(deps, req), req.source);
|
|
35149
35520
|
return l.mounts.listed();
|
|
35150
35521
|
}
|
|
35151
35522
|
const attestOp = attestOps(port);
|
|
35152
35523
|
async function handle(req) {
|
|
35153
35524
|
if (req.op === "init") return init(req);
|
|
35154
35525
|
if (isAttestRequest(req)) return attestOp(await ready2(), req);
|
|
35526
|
+
if (req.op === "sealed-placeholders") return (await ready2()).setPlaceholders(req.list);
|
|
35155
35527
|
if (req.op === "open-terminal") return terminal(req);
|
|
35156
35528
|
if (req.op === "connect") return connect2(req.user, req.tag, req.requests);
|
|
35157
35529
|
if (isUsersRequest(req)) return usersOp(await ready2(), req);
|