@ai-ecoverse/slicc-kernel 1.151.1 → 1.152.1
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 +4 -0
- package/dist/index.js.map +2 -2
- package/dist/kernel-worker.js +298 -74
- package/dist/kernel-worker.js.map +3 -3
- package/dist/meta.js.map +2 -2
- package/dist/node-process-worker.js +123 -19
- package/dist/node-process-worker.js.map +3 -3
- package/dist/node.js +298 -74
- package/dist/node.js.map +3 -3
- package/dist/process-worker.js +123 -19
- package/dist/process-worker.js.map +3 -3
- package/dist/types/fs/opfs.d.ts +4 -2
- package/dist/types/fs/types.d.ts +5 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/kernel/host.d.ts +1 -0
- package/dist/types/kernel/net/tls-client.d.ts +13 -2
- package/dist/types/kernel/net/tls-engine.d.ts +9 -2
- package/dist/types/kernel/net/tls-server.d.ts +17 -2
- package/dist/types/kernel/proc-info.d.ts +1 -0
- package/dist/types/kernel/socket-syscalls.d.ts +10 -0
- package/dist/types/kernel/socket.d.ts +1 -0
- package/dist/types/launcher.d.ts +1 -0
- package/dist/types/mount/mount-fs.d.ts +4 -1
- package/dist/types/process/js/js-net.d.ts +21 -0
- package/dist/types/process/wasi/wasi-fds.d.ts +2 -1
- package/dist/types/process/wasi/wasi-files.d.ts +3 -0
- package/dist/types/realm/sync-fs-token-registry.d.ts +3 -1
- package/package.json +1 -1
package/dist/kernel-worker.js
CHANGED
|
@@ -1569,9 +1569,10 @@ var OpfsFs = class {
|
|
|
1569
1569
|
}
|
|
1570
1570
|
async fileId(path) {
|
|
1571
1571
|
const found = await this.locate(path, true);
|
|
1572
|
-
const [entry] = await this.meta.get([found.path]);
|
|
1572
|
+
const [entry] = await (this.meta.fresh ?? this.meta.get).call(this.meta, [found.path]);
|
|
1573
1573
|
if (entry?.fid !== void 0) return entry.fid;
|
|
1574
1574
|
const fid = crypto.randomUUID();
|
|
1575
|
+
this.idWrites++;
|
|
1575
1576
|
await this.meta.update(found.path, (now) => ({
|
|
1576
1577
|
...occupied(now),
|
|
1577
1578
|
path: found.path,
|
|
@@ -1842,6 +1843,10 @@ var OpfsFs = class {
|
|
|
1842
1843
|
opfsCalls() {
|
|
1843
1844
|
return this.calls;
|
|
1844
1845
|
}
|
|
1846
|
+
idWrites = 0;
|
|
1847
|
+
fileIdWrites() {
|
|
1848
|
+
return this.idWrites;
|
|
1849
|
+
}
|
|
1845
1850
|
opfsOps() {
|
|
1846
1851
|
return this.calls + this.others;
|
|
1847
1852
|
}
|
|
@@ -2301,7 +2306,7 @@ var OpfsFs = class {
|
|
|
2301
2306
|
return new Uint8Array(await file.slice(offset, offset + length2).arrayBuffer());
|
|
2302
2307
|
});
|
|
2303
2308
|
}
|
|
2304
|
-
async pwrite(path, offset, bytes) {
|
|
2309
|
+
async pwrite(path, offset, bytes, _transfer, options) {
|
|
2305
2310
|
const at = normalizePath(path);
|
|
2306
2311
|
const movedAway = this.renamesInFlight() ? await this.writeWaits(at) : false;
|
|
2307
2312
|
this.fileWrites.set(at, (this.fileWrites.get(at) ?? 0) + 1);
|
|
@@ -2316,7 +2321,10 @@ var OpfsFs = class {
|
|
|
2316
2321
|
this.files.delete(target);
|
|
2317
2322
|
}
|
|
2318
2323
|
}
|
|
2319
|
-
const [handle] = await this.fileFor(
|
|
2324
|
+
const [handle] = await this.fileFor(
|
|
2325
|
+
path,
|
|
2326
|
+
!existed && !movedAway && options?.create !== false
|
|
2327
|
+
);
|
|
2320
2328
|
await this.writeAt(handle, target, path, offset, bytes);
|
|
2321
2329
|
} finally {
|
|
2322
2330
|
this.writeEnded(at);
|
|
@@ -4155,14 +4163,14 @@ var WsReader = class {
|
|
|
4155
4163
|
}
|
|
4156
4164
|
};
|
|
4157
4165
|
function switchingHead(accept2, protocol = "") {
|
|
4158
|
-
const
|
|
4166
|
+
const chosen3 = protocol ? `Sec-WebSocket-Protocol: ${protocol}\r
|
|
4159
4167
|
` : "";
|
|
4160
4168
|
return latin1Bytes(
|
|
4161
4169
|
`HTTP/1.1 101 Switching Protocols\r
|
|
4162
4170
|
Upgrade: websocket\r
|
|
4163
4171
|
Connection: Upgrade\r
|
|
4164
4172
|
Sec-WebSocket-Accept: ${accept2}\r
|
|
4165
|
-
${
|
|
4173
|
+
${chosen3}\r
|
|
4166
4174
|
`
|
|
4167
4175
|
);
|
|
4168
4176
|
}
|
|
@@ -6155,6 +6163,7 @@ var KernelSocket = class _KernelSocket {
|
|
|
6155
6163
|
return this.dial(addr, route2, secure2);
|
|
6156
6164
|
}
|
|
6157
6165
|
serving;
|
|
6166
|
+
pending;
|
|
6158
6167
|
served = false;
|
|
6159
6168
|
get loopbackLinked() {
|
|
6160
6169
|
return this.state === "connected" && !this.switch;
|
|
@@ -6339,6 +6348,8 @@ var KernelSocket = class _KernelSocket {
|
|
|
6339
6348
|
this.boundAt = void 0;
|
|
6340
6349
|
this.serving?.release();
|
|
6341
6350
|
this.serving = void 0;
|
|
6351
|
+
this.pending?.();
|
|
6352
|
+
this.pending = void 0;
|
|
6342
6353
|
this.changes.wake();
|
|
6343
6354
|
}
|
|
6344
6355
|
static pair(net, domain, cred) {
|
|
@@ -7915,7 +7926,7 @@ function satisfies(version, range2) {
|
|
|
7915
7926
|
}
|
|
7916
7927
|
|
|
7917
7928
|
// src/version.ts
|
|
7918
|
-
var KERNEL_VERSION = true ? "1.
|
|
7929
|
+
var KERNEL_VERSION = true ? "1.152.1" : "0.0.0-dev";
|
|
7919
7930
|
var OS_RELEASE = "6.0.0-slicc";
|
|
7920
7931
|
function procVersion() {
|
|
7921
7932
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -10696,9 +10707,9 @@ function withEtcFiles(fs, files) {
|
|
|
10696
10707
|
readFileBuffer: (path) => fs.readFileBuffer(path).catch(fallback(path, (b) => b)),
|
|
10697
10708
|
...ranged2 ? {
|
|
10698
10709
|
pread: (path, offset, length2, version) => ranged2.pread(path, offset, length2, version).catch(fallback(path, (b) => b.slice(offset, offset + length2))),
|
|
10699
|
-
pwrite: async (path, offset, bytes, transfer) => {
|
|
10710
|
+
pwrite: async (path, offset, bytes, transfer, options) => {
|
|
10700
10711
|
if (files.has(path)) await materialize(path);
|
|
10701
|
-
return ranged2.pwrite(path, offset, bytes, transfer);
|
|
10712
|
+
return ranged2.pwrite(path, offset, bytes, transfer, options);
|
|
10702
10713
|
},
|
|
10703
10714
|
truncate: async (path, size) => {
|
|
10704
10715
|
if (files.has(path)) await materialize(path);
|
|
@@ -10807,10 +10818,10 @@ var FreshModules = class {
|
|
|
10807
10818
|
};
|
|
10808
10819
|
const ranged2 = rangedOps(fs);
|
|
10809
10820
|
if (ranged2) {
|
|
10810
|
-
overrides.pwrite = async (path, at, bytes, transfer) => {
|
|
10821
|
+
overrides.pwrite = async (path, at, bytes, transfer, options) => {
|
|
10811
10822
|
const touches3 = at < MAGIC.length && this.fresh.has(normalizePath(path));
|
|
10812
10823
|
const first = at === 0 && bytes.length >= MAGIC.length ? bytes.slice(0, MAGIC.length) : void 0;
|
|
10813
|
-
await ranged2.pwrite(path, at, bytes, transfer);
|
|
10824
|
+
await ranged2.pwrite(path, at, bytes, transfer, options);
|
|
10814
10825
|
if (touches3) await decide(path, first);
|
|
10815
10826
|
};
|
|
10816
10827
|
overrides.truncate = async (path, size) => {
|
|
@@ -12088,6 +12099,9 @@ var HeldSet = class extends Set {
|
|
|
12088
12099
|
if (over !== void 0) holds2.doubt(over);
|
|
12089
12100
|
}
|
|
12090
12101
|
}
|
|
12102
|
+
async bindIds(id2) {
|
|
12103
|
+
for (const holds2 of [...this]) await holds2.bindIds(id2);
|
|
12104
|
+
}
|
|
12091
12105
|
delete(holds2) {
|
|
12092
12106
|
const removed = super.delete(holds2);
|
|
12093
12107
|
for (const path of /* @__PURE__ */ new Set([...holds2.keys(), ...holds2.opens.keys()])) this.idle(path);
|
|
@@ -12141,8 +12155,17 @@ var HeldPaths = class extends Map {
|
|
|
12141
12155
|
}
|
|
12142
12156
|
boundIno(handle) {
|
|
12143
12157
|
const doubt = this.doubted.get(handle);
|
|
12144
|
-
const
|
|
12145
|
-
return doubt === void 0 ||
|
|
12158
|
+
const bound3 = this.bound.get(handle);
|
|
12159
|
+
return doubt === void 0 || bound3 === void 0 ? void 0 : { ...bound3, doubt };
|
|
12160
|
+
}
|
|
12161
|
+
async bindIds(id2) {
|
|
12162
|
+
for (const [handle, bound3] of [...this.bound]) {
|
|
12163
|
+
const key = this.handles.get(handle);
|
|
12164
|
+
if (bound3.fid !== void 0 || key === void 0) continue;
|
|
12165
|
+
const fid = await id2(key)?.catch(() => void 0);
|
|
12166
|
+
if (fid !== void 0 && this.bound.get(handle) === bound3)
|
|
12167
|
+
this.bound.set(handle, { ...bound3, fid });
|
|
12168
|
+
}
|
|
12146
12169
|
}
|
|
12147
12170
|
trust(handle, doubt) {
|
|
12148
12171
|
if (this.doubted.get(handle) === doubt) this.doubted.delete(handle);
|
|
@@ -12183,14 +12206,15 @@ var HeldPaths = class extends Map {
|
|
|
12183
12206
|
for (const file of [...this.uses.keys()]) this.letGo(file, true);
|
|
12184
12207
|
this.keptHandles.clear();
|
|
12185
12208
|
}
|
|
12186
|
-
hold(path, on, open2 = false, real, handle, ino) {
|
|
12209
|
+
hold(path, on, open2 = false, real, handle, ino, fid) {
|
|
12187
12210
|
if (open2) {
|
|
12188
12211
|
const made2 = this.holdOpen(path, on, real, handle);
|
|
12189
12212
|
if (handle !== void 0) {
|
|
12190
12213
|
this.bound.delete(handle);
|
|
12191
12214
|
this.doubted.delete(handle);
|
|
12192
12215
|
}
|
|
12193
|
-
if (made2 !== void 0 && ino !== void 0)
|
|
12216
|
+
if (made2 !== void 0 && ino !== void 0)
|
|
12217
|
+
this.bound.set(made2, fid === void 0 ? { ino } : { ino, fid });
|
|
12194
12218
|
return made2;
|
|
12195
12219
|
}
|
|
12196
12220
|
this.holdWrite(path, on);
|
|
@@ -12926,7 +12950,7 @@ var MountFs = class _MountFs {
|
|
|
12926
12950
|
);
|
|
12927
12951
|
}
|
|
12928
12952
|
}
|
|
12929
|
-
async pwrite(path, offset, bytes, transfer = false, redirects = 0) {
|
|
12953
|
+
async pwrite(path, offset, bytes, transfer = false, options, redirects = 0) {
|
|
12930
12954
|
const real = await this.follow(path, 0, true);
|
|
12931
12955
|
const found = this.at(real);
|
|
12932
12956
|
const { pwrite } = this.base;
|
|
@@ -12934,8 +12958,8 @@ var MountFs = class _MountFs {
|
|
|
12934
12958
|
return this.based(
|
|
12935
12959
|
[real],
|
|
12936
12960
|
redirects,
|
|
12937
|
-
() => pwrite.call(this.base, real, offset, bytes),
|
|
12938
|
-
([to], n) => this.pwrite(to, offset, bytes, transfer, n)
|
|
12961
|
+
() => pwrite.call(this.base, real, offset, bytes, false, options),
|
|
12962
|
+
([to], n) => this.pwrite(to, offset, bytes, transfer, options, n)
|
|
12939
12963
|
);
|
|
12940
12964
|
}
|
|
12941
12965
|
if (!found)
|
|
@@ -12959,7 +12983,7 @@ var MountFs = class _MountFs {
|
|
|
12959
12983
|
op: "open",
|
|
12960
12984
|
path: rel2,
|
|
12961
12985
|
write: true,
|
|
12962
|
-
create:
|
|
12986
|
+
create: options?.create !== false,
|
|
12963
12987
|
truncate: false,
|
|
12964
12988
|
exclusive: false
|
|
12965
12989
|
});
|
|
@@ -13727,7 +13751,7 @@ async function run(entry, path, req) {
|
|
|
13727
13751
|
case "truncate":
|
|
13728
13752
|
return ranged(fs, path, req);
|
|
13729
13753
|
case "append":
|
|
13730
|
-
return json2(await appended(fs, path, req.body ?? new Uint8Array(0)));
|
|
13754
|
+
return json2(await appended(fs, path, req.body ?? new Uint8Array(0), req.handle));
|
|
13731
13755
|
default:
|
|
13732
13756
|
return { ok: false, errno: "EINVAL", message: `sync-fs: unknown op '${req.op}'` };
|
|
13733
13757
|
}
|
|
@@ -13871,13 +13895,17 @@ async function holdOp(entry, path, req) {
|
|
|
13871
13895
|
await entry.source?.open(path, real);
|
|
13872
13896
|
await stillThere(entry, path, req);
|
|
13873
13897
|
if (req.nofollow && !await ownEntry(entry, path, real ?? path)) continue;
|
|
13898
|
+
const fid = req.ino === void 0 ? void 0 : await idOf(entry, real ?? path);
|
|
13874
13899
|
if (!r || !r.missed(path) && !r.changedSince(path, gen) && !r.inFlight?.(path))
|
|
13875
|
-
return json2(entry.hold?.(path, on, open2, real, void 0, req.ino) ?? null);
|
|
13900
|
+
return json2(entry.hold?.(path, on, open2, real, void 0, req.ino, fid) ?? null);
|
|
13876
13901
|
}
|
|
13877
13902
|
}
|
|
13878
13903
|
entry.hold?.(path, on, open2, void 0, req.handle);
|
|
13879
13904
|
return done2;
|
|
13880
13905
|
}
|
|
13906
|
+
async function idOf(entry, path) {
|
|
13907
|
+
return await entry.fileId?.(path)?.catch(() => void 0) ?? void 0;
|
|
13908
|
+
}
|
|
13881
13909
|
async function ownEntry(entry, path, real) {
|
|
13882
13910
|
const own = await entry.fs.realpath?.(path, false).catch((err) => {
|
|
13883
13911
|
if (err.code !== "ENOENT") throw err;
|
|
@@ -13972,14 +14000,14 @@ async function createExclusive(fs, path, owner) {
|
|
|
13972
14000
|
await fs.writeFile(path, new Uint8Array(0), owner);
|
|
13973
14001
|
}
|
|
13974
14002
|
var appending = /* @__PURE__ */ new Map();
|
|
13975
|
-
async function appended(fs, path, body) {
|
|
14003
|
+
async function appended(fs, path, body, handle) {
|
|
13976
14004
|
const key = await fs.realpath?.(path, true).catch(() => void 0) ?? path;
|
|
13977
14005
|
const before = appending.get(key) ?? Promise.resolve();
|
|
13978
14006
|
const run2 = before.then(async () => {
|
|
13979
14007
|
if (fs.append) return fs.append(path, body);
|
|
13980
14008
|
const size = (await fs.stat(path)).size;
|
|
13981
14009
|
const ops = rangedOps(fs);
|
|
13982
|
-
if (ops) await ops.pwrite(path, size, body, true);
|
|
14010
|
+
if (ops) await ops.pwrite(path, size, body, true, noCreate(handle));
|
|
13983
14011
|
else {
|
|
13984
14012
|
const whole = new Uint8Array(size + body.length);
|
|
13985
14013
|
whole.set(await fs.readFileBuffer(path));
|
|
@@ -13995,6 +14023,9 @@ async function appended(fs, path, body) {
|
|
|
13995
14023
|
});
|
|
13996
14024
|
return run2;
|
|
13997
14025
|
}
|
|
14026
|
+
function noCreate(handle) {
|
|
14027
|
+
return handle === void 0 ? void 0 : { create: false };
|
|
14028
|
+
}
|
|
13998
14029
|
async function ranged(fs, path, req) {
|
|
13999
14030
|
const ops = rangedOps(fs);
|
|
14000
14031
|
if (!ops) throw syncError("ENOSYS", path);
|
|
@@ -14005,7 +14036,8 @@ async function ranged(fs, path, req) {
|
|
|
14005
14036
|
kind: "bytes",
|
|
14006
14037
|
bytes: await ops.pread(path, offset, req.length ?? 0, req.version)
|
|
14007
14038
|
};
|
|
14008
|
-
if (req.op === "pwrite")
|
|
14039
|
+
if (req.op === "pwrite")
|
|
14040
|
+
await ops.pwrite(path, offset, req.body ?? new Uint8Array(0), true, noCreate(req.handle));
|
|
14009
14041
|
else await ops.truncate(path, req.length ?? 0);
|
|
14010
14042
|
return done2;
|
|
14011
14043
|
}
|
|
@@ -14035,7 +14067,10 @@ async function bound(entry, path, handle) {
|
|
|
14035
14067
|
const bound3 = entry.boundIno?.(handle);
|
|
14036
14068
|
if (bound3 === void 0) return;
|
|
14037
14069
|
const now = await entry.fs.stat(path).catch(() => void 0);
|
|
14038
|
-
if (now
|
|
14070
|
+
if (now === void 0 && bound3.fid !== void 0 && !await entry.fs.lstat(path).catch(() => void 0))
|
|
14071
|
+
throw syncError("ENOENT", path);
|
|
14072
|
+
const same3 = bound3.fid === void 0 ? now?.ino === bound3.ino : now?.fid === bound3.fid || await idOf(entry, path) === bound3.fid;
|
|
14073
|
+
if (same3) {
|
|
14039
14074
|
entry.trust?.(handle, bound3.doubt);
|
|
14040
14075
|
return;
|
|
14041
14076
|
}
|
|
@@ -14849,6 +14884,8 @@ var SYS_TREE = {
|
|
|
14849
14884
|
slicc_rename_ack_busy: (listing) => `${listing.renameAcks?.busy ?? 0}
|
|
14850
14885
|
`,
|
|
14851
14886
|
slicc_stale_fds: (listing) => `${listing.staleFds ?? 0}
|
|
14887
|
+
`,
|
|
14888
|
+
slicc_file_ids: (listing) => `${listing.fileIds ?? 0}
|
|
14852
14889
|
`,
|
|
14853
14890
|
slicc_rename_acks: (listing) => {
|
|
14854
14891
|
const samples = [...listing.renameAcks?.ackMs ?? []].sort((a, b) => a - b);
|
|
@@ -16779,6 +16816,8 @@ var TLS_CLIENT_NO_SNI = 2;
|
|
|
16779
16816
|
var TLS_CLIENT_VERIFY_CHAIN_ONLY = 4;
|
|
16780
16817
|
var TLS_SERVER_REQUEST_CERT = 1;
|
|
16781
16818
|
var TLS_SERVER_REQUIRE_CERT = 2;
|
|
16819
|
+
var TLS_SERVER_SELECT = 4;
|
|
16820
|
+
var TLS_HANDSHAKE_SELECT = 2;
|
|
16782
16821
|
var SCRATCH = 64 * 1024;
|
|
16783
16822
|
var EOF = -1;
|
|
16784
16823
|
var TlsError = class extends Error {
|
|
@@ -16846,12 +16885,15 @@ var TlsEngine = class {
|
|
|
16846
16885
|
if (!ptr) throw this.error(this.m._tls_last_error(), "server certificate");
|
|
16847
16886
|
return new TlsLeaf(this, this.m, ptr);
|
|
16848
16887
|
}
|
|
16888
|
+
get serverSelect() {
|
|
16889
|
+
return typeof this.m._tls_server_select === "function";
|
|
16890
|
+
}
|
|
16849
16891
|
serverSession(leaf, alpn, clientCa, flags2) {
|
|
16850
16892
|
const open2 = this.m._tls_server_new;
|
|
16851
16893
|
const wire = alpnWire(alpn);
|
|
16852
16894
|
const ptr = this.withBytes(
|
|
16853
16895
|
wire,
|
|
16854
|
-
(p) => open2(leaf
|
|
16896
|
+
(p) => open2(leaf?.ptr ?? 0, wire.length > 0 ? p : 0, wire.length, clientCa?.ptr ?? 0, flags2)
|
|
16855
16897
|
);
|
|
16856
16898
|
if (!ptr) throw this.error(this.m._tls_last_error(), "tls server");
|
|
16857
16899
|
return new TlsSession(this, this.m, ptr);
|
|
@@ -17050,9 +17092,35 @@ var TlsSession = class {
|
|
|
17050
17092
|
return this.m;
|
|
17051
17093
|
}
|
|
17052
17094
|
handshake() {
|
|
17095
|
+
return this.step() === 1;
|
|
17096
|
+
}
|
|
17097
|
+
step() {
|
|
17053
17098
|
const ret = this.c._tls_handshake(this.ptr);
|
|
17054
17099
|
if (ret < 0) throw this.engine.error(ret, "tls handshake");
|
|
17055
|
-
return ret
|
|
17100
|
+
return ret;
|
|
17101
|
+
}
|
|
17102
|
+
clientAlpn() {
|
|
17103
|
+
const list = this.m._tls_client_alpn;
|
|
17104
|
+
const out = this.engine.intoScratch((p, max) => list(this.ptr, p, max));
|
|
17105
|
+
if (!(out instanceof Uint8Array)) return [];
|
|
17106
|
+
const names2 = [];
|
|
17107
|
+
for (let at = 0; at < out.length; at += 1 + out[at]) {
|
|
17108
|
+
names2.push(new TextDecoder().decode(out.subarray(at + 1, at + 1 + out[at])));
|
|
17109
|
+
}
|
|
17110
|
+
return names2;
|
|
17111
|
+
}
|
|
17112
|
+
select(leaf, alpn) {
|
|
17113
|
+
const pick = this.m._tls_server_select;
|
|
17114
|
+
const name2 = new TextEncoder().encode(alpn ?? "");
|
|
17115
|
+
const ret = this.engine.withBytes(
|
|
17116
|
+
name2,
|
|
17117
|
+
(p) => pick(this.ptr, leaf?.ptr ?? 0, name2.length > 0 ? p : 0, name2.length)
|
|
17118
|
+
);
|
|
17119
|
+
if (ret !== 0) throw this.engine.error(ret, "tls select");
|
|
17120
|
+
}
|
|
17121
|
+
refuse(alert) {
|
|
17122
|
+
const ret = this.m._tls_server_refuse(this.ptr, alert);
|
|
17123
|
+
if (ret !== 0) throw this.engine.error(ret, "tls refuse");
|
|
17056
17124
|
}
|
|
17057
17125
|
get verifyResult() {
|
|
17058
17126
|
return this.c._tls_verify_result(this.ptr);
|
|
@@ -18890,17 +18958,39 @@ function serverRefusal(err, session, first) {
|
|
|
18890
18958
|
const text = err instanceof TlsError ? err.message : String(err);
|
|
18891
18959
|
return new KernelError("EPROTO", `ERR_SSL_HANDSHAKE_FAILURE: ${text}${alertOf(session)}`);
|
|
18892
18960
|
}
|
|
18893
|
-
async function
|
|
18961
|
+
async function chosen(conn, session, select) {
|
|
18962
|
+
if (!select) throw new KernelError("EPROTO", "ERR_SSL_HANDSHAKE_FAILURE: no selection");
|
|
18963
|
+
const choice = await select({ servername: session.sni, protocols: session.clientAlpn() });
|
|
18964
|
+
if (choice.refuse === void 0) {
|
|
18965
|
+
try {
|
|
18966
|
+
session.select(choice.leaf, choice.alpn);
|
|
18967
|
+
} finally {
|
|
18968
|
+
choice.done?.();
|
|
18969
|
+
}
|
|
18970
|
+
return;
|
|
18971
|
+
}
|
|
18972
|
+
session.refuse(choice.refuse);
|
|
18973
|
+
await send(conn, session).catch(() => void 0);
|
|
18974
|
+
throw new KernelError(
|
|
18975
|
+
"EPROTO",
|
|
18976
|
+
`ERR_SSL_HANDSHAKE_FAILURE: the program refused the handshake (alert ${choice.refuse})`
|
|
18977
|
+
);
|
|
18978
|
+
}
|
|
18979
|
+
async function serverHandshake(conn, session, inbox, hooks) {
|
|
18894
18980
|
for (; ; ) {
|
|
18895
|
-
let
|
|
18981
|
+
let step2;
|
|
18896
18982
|
try {
|
|
18897
|
-
|
|
18983
|
+
step2 = session.step();
|
|
18898
18984
|
} catch (err) {
|
|
18899
18985
|
await send(conn, session).catch(() => void 0);
|
|
18900
|
-
throw serverRefusal(err, session, first());
|
|
18986
|
+
throw serverRefusal(err, session, hooks.first());
|
|
18987
|
+
}
|
|
18988
|
+
if (step2 === TLS_HANDSHAKE_SELECT) {
|
|
18989
|
+
await chosen(conn, session, hooks.select);
|
|
18990
|
+
continue;
|
|
18901
18991
|
}
|
|
18902
18992
|
await send(conn, session);
|
|
18903
|
-
if (
|
|
18993
|
+
if (step2 === 1) return;
|
|
18904
18994
|
if (!await inbox.more()) {
|
|
18905
18995
|
throw new KernelError(
|
|
18906
18996
|
"ECONNRESET",
|
|
@@ -18909,7 +18999,7 @@ async function serverHandshake(conn, session, inbox, first) {
|
|
|
18909
18999
|
}
|
|
18910
19000
|
}
|
|
18911
19001
|
}
|
|
18912
|
-
async function tlsServer(conn, session, clientCerts) {
|
|
19002
|
+
async function tlsServer(conn, session, clientCerts, select) {
|
|
18913
19003
|
let first;
|
|
18914
19004
|
const watched = {
|
|
18915
19005
|
...conn,
|
|
@@ -18921,7 +19011,7 @@ async function tlsServer(conn, session, clientCerts) {
|
|
|
18921
19011
|
};
|
|
18922
19012
|
const inbox = new Ciphertext(watched, session);
|
|
18923
19013
|
try {
|
|
18924
|
-
await serverHandshake(conn, session, inbox, () => first);
|
|
19014
|
+
await serverHandshake(conn, session, inbox, { first: () => first, select });
|
|
18925
19015
|
const chain2 = session.peerChain();
|
|
18926
19016
|
const code = clientCerts ? verifyCode(session.verifyResult) : void 0;
|
|
18927
19017
|
const protocol = session.version === 772 ? "TLSv1.3" : "TLSv1.2";
|
|
@@ -22126,10 +22216,35 @@ function storeOf(engine, ca) {
|
|
|
22126
22216
|
throw new KernelError("EINVAL", `ERR_INVALID_ARG_VALUE: ca: ${err.message}`);
|
|
22127
22217
|
}
|
|
22128
22218
|
}
|
|
22129
|
-
function
|
|
22219
|
+
function certFlags(req) {
|
|
22130
22220
|
if (!req.requestCert) return 0;
|
|
22131
22221
|
return req.rejectUnauthorized === false ? TLS_SERVER_REQUEST_CERT : TLS_SERVER_REQUIRE_CERT;
|
|
22132
22222
|
}
|
|
22223
|
+
function flagsOf(req) {
|
|
22224
|
+
if (!req.select) return certFlags(req);
|
|
22225
|
+
if (req.alpn && req.alpn.length > 0)
|
|
22226
|
+
throw new KernelError("EINVAL", "ERR_TLS_ALPN_CALLBACK_WITH_PROTOCOLS: alpn with select");
|
|
22227
|
+
return certFlags(req) | TLS_SERVER_SELECT;
|
|
22228
|
+
}
|
|
22229
|
+
async function engineOf(proc, select) {
|
|
22230
|
+
const engine = await supportOf(proc.net).engine();
|
|
22231
|
+
if (!engine.serverSessions)
|
|
22232
|
+
throw new KernelError("ENOTSUP", "the installed tls engine has no server sessions");
|
|
22233
|
+
if (select && !engine.serverSelect)
|
|
22234
|
+
throw new KernelError("ENOTSUP", "the installed tls engine has no server selection");
|
|
22235
|
+
return engine;
|
|
22236
|
+
}
|
|
22237
|
+
async function importedLeaf(proc, own, select) {
|
|
22238
|
+
const cert = certBytes(own);
|
|
22239
|
+
let engine;
|
|
22240
|
+
try {
|
|
22241
|
+
engine = await engineOf(proc, select);
|
|
22242
|
+
} catch (err) {
|
|
22243
|
+
wipe(cert);
|
|
22244
|
+
throw err;
|
|
22245
|
+
}
|
|
22246
|
+
return { engine, leaf: leafOf(engine, cert) };
|
|
22247
|
+
}
|
|
22133
22248
|
function timeoutOf(req) {
|
|
22134
22249
|
const ms = req.handshakeTimeout ?? HANDSHAKE_TIMEOUT_MS;
|
|
22135
22250
|
if (!Number.isInteger(ms) || ms <= 0)
|
|
@@ -22151,23 +22266,14 @@ function handshakeSignal(proc, ms) {
|
|
|
22151
22266
|
async function serverOf(proc, req) {
|
|
22152
22267
|
const own = req.cert;
|
|
22153
22268
|
delete req.cert;
|
|
22154
|
-
if (!own
|
|
22155
|
-
|
|
22156
|
-
|
|
22157
|
-
try {
|
|
22158
|
-
engine = await supportOf(proc.net).engine();
|
|
22159
|
-
if (!engine.serverSessions)
|
|
22160
|
-
throw new KernelError("ENOTSUP", "the installed tls engine has no server sessions");
|
|
22161
|
-
} catch (err) {
|
|
22162
|
-
wipe(cert);
|
|
22163
|
-
throw err;
|
|
22164
|
-
}
|
|
22165
|
-
const leaf = leafOf(engine, cert);
|
|
22269
|
+
if (!own && !req.select)
|
|
22270
|
+
throw new KernelError("EINVAL", "ERR_INVALID_ARG_VALUE: a server needs cert and key");
|
|
22271
|
+
const { engine, leaf } = own ? await importedLeaf(proc, own, req.select) : { engine: await engineOf(proc, true), leaf: void 0 };
|
|
22166
22272
|
let mine;
|
|
22167
22273
|
try {
|
|
22168
22274
|
mine = req.ca && req.ca.length > 0 ? storeOf(engine, req.ca) : void 0;
|
|
22169
22275
|
const flags2 = flagsOf(req);
|
|
22170
|
-
const store = mine ?? (flags2 ? await defaultStore(engine, supportOf(proc.net).roots) : void 0);
|
|
22276
|
+
const store = mine ?? (flags2 & ~TLS_SERVER_SELECT ? await defaultStore(engine, supportOf(proc.net).roots) : void 0);
|
|
22171
22277
|
return {
|
|
22172
22278
|
engine,
|
|
22173
22279
|
leaf,
|
|
@@ -22176,12 +22282,12 @@ async function serverOf(proc, req) {
|
|
|
22176
22282
|
flags: flags2,
|
|
22177
22283
|
timeoutMs: timeoutOf(req),
|
|
22178
22284
|
release() {
|
|
22179
|
-
leaf
|
|
22285
|
+
leaf?.release();
|
|
22180
22286
|
mine?.release();
|
|
22181
22287
|
}
|
|
22182
22288
|
};
|
|
22183
22289
|
} catch (err) {
|
|
22184
|
-
leaf
|
|
22290
|
+
leaf?.release();
|
|
22185
22291
|
mine?.release();
|
|
22186
22292
|
throw err;
|
|
22187
22293
|
}
|
|
@@ -22192,30 +22298,133 @@ async function listenSecure(proc, socket, req) {
|
|
|
22192
22298
|
socket.serving?.release();
|
|
22193
22299
|
socket.serving = server;
|
|
22194
22300
|
}
|
|
22301
|
+
function servedOf(info) {
|
|
22302
|
+
return {
|
|
22303
|
+
path: "kernel",
|
|
22304
|
+
protocol: info.protocol,
|
|
22305
|
+
alpnProtocol: info.alpnProtocol,
|
|
22306
|
+
servername: info.servername,
|
|
22307
|
+
authorized: info.authorized,
|
|
22308
|
+
...info.authorizationError ? { authorizationError: info.authorizationError } : {},
|
|
22309
|
+
peerCertificates: info.peerCertificates.map(encode),
|
|
22310
|
+
cipher: info.cipher
|
|
22311
|
+
};
|
|
22312
|
+
}
|
|
22313
|
+
var selections = /* @__PURE__ */ new WeakMap();
|
|
22314
|
+
function pausing(signal) {
|
|
22315
|
+
let paused;
|
|
22316
|
+
const pausedAt = new Promise((resolve2) => {
|
|
22317
|
+
paused = resolve2;
|
|
22318
|
+
});
|
|
22319
|
+
const select = (offer) => new Promise((choose, fail2) => {
|
|
22320
|
+
if (signal.aborted) fail2(signal.reason);
|
|
22321
|
+
signal.addEventListener("abort", () => fail2(signal.reason), { once: true });
|
|
22322
|
+
paused({ offer, choose, fail: fail2 });
|
|
22323
|
+
});
|
|
22324
|
+
return { pausedAt, select };
|
|
22325
|
+
}
|
|
22195
22326
|
async function serveSecure(proc, socket, req) {
|
|
22196
22327
|
const shared = req.listener?.serving;
|
|
22197
22328
|
if (req.listener && !shared) throw new KernelError("EINVAL", "the listener has no tls");
|
|
22198
22329
|
const server = shared ?? await serverOf(proc, req);
|
|
22330
|
+
const { engine, leaf, alpn, store, flags: flags2 } = server;
|
|
22331
|
+
const limit = handshakeSignal(proc, server.timeoutMs);
|
|
22332
|
+
const { pausedAt, select } = pausing(limit.signal);
|
|
22333
|
+
const certs = (flags2 & ~TLS_SERVER_SELECT) !== 0;
|
|
22334
|
+
const run2 = socket.secureLink(
|
|
22335
|
+
(raw2) => tlsServer(
|
|
22336
|
+
raw2,
|
|
22337
|
+
engine.serverSession(leaf, alpn, store, flags2),
|
|
22338
|
+
certs,
|
|
22339
|
+
flags2 & TLS_SERVER_SELECT ? select : void 0
|
|
22340
|
+
),
|
|
22341
|
+
limit.signal,
|
|
22342
|
+
(reason) => !shared && reason === timedOut
|
|
22343
|
+
).finally(() => {
|
|
22344
|
+
limit.done();
|
|
22345
|
+
selections.delete(socket);
|
|
22346
|
+
socket.pending = void 0;
|
|
22347
|
+
if (!shared) server.release();
|
|
22348
|
+
});
|
|
22349
|
+
run2.catch(() => void 0);
|
|
22350
|
+
const first = await Promise.race([run2, pausedAt.then((pause2) => ({ pause: pause2 }))]);
|
|
22351
|
+
if (!("pause" in first)) return servedOf(first);
|
|
22352
|
+
selections.set(socket, { pause: first.pause, run: run2 });
|
|
22353
|
+
socket.pending = () => first.pause.fail(new KernelError("ECONNRESET"));
|
|
22354
|
+
return { select: first.pause.offer };
|
|
22355
|
+
}
|
|
22356
|
+
var REFUSALS = /* @__PURE__ */ new Set([112, 120, 40, 49, 80]);
|
|
22357
|
+
var TlsContext = class {
|
|
22358
|
+
leaf;
|
|
22359
|
+
constructor(leaf) {
|
|
22360
|
+
this.leaf = leaf;
|
|
22361
|
+
}
|
|
22362
|
+
close() {
|
|
22363
|
+
this.leaf.release();
|
|
22364
|
+
}
|
|
22365
|
+
};
|
|
22366
|
+
var TLS_CONTEXTS_MAX = 64;
|
|
22367
|
+
async function contextSecure(proc, cert) {
|
|
22368
|
+
if (!cert) throw new KernelError("EINVAL", "ERR_INVALID_ARG_VALUE: a context needs cert and key");
|
|
22369
|
+
const held = proc.fds.numbers().filter((fd) => proc.fds.get(fd).file instanceof TlsContext);
|
|
22370
|
+
if (held.length >= TLS_CONTEXTS_MAX) {
|
|
22371
|
+
wipe(certBytes(cert));
|
|
22372
|
+
throw new KernelError("EMFILE", `at most ${TLS_CONTEXTS_MAX} tls contexts per process`);
|
|
22373
|
+
}
|
|
22374
|
+
const { leaf } = await importedLeaf(proc, cert);
|
|
22375
|
+
const file = new OpenFile(new TlsContext(leaf));
|
|
22199
22376
|
try {
|
|
22200
|
-
const
|
|
22201
|
-
|
|
22202
|
-
|
|
22203
|
-
|
|
22204
|
-
|
|
22205
|
-
|
|
22206
|
-
|
|
22207
|
-
|
|
22208
|
-
|
|
22209
|
-
|
|
22210
|
-
|
|
22211
|
-
|
|
22212
|
-
|
|
22213
|
-
|
|
22214
|
-
|
|
22215
|
-
|
|
22216
|
-
|
|
22377
|
+
const fd = proc.fds.install(file, 3);
|
|
22378
|
+
proc.fds.setCloseOnExec(fd);
|
|
22379
|
+
return fd;
|
|
22380
|
+
} catch (err) {
|
|
22381
|
+
leaf.release();
|
|
22382
|
+
throw err;
|
|
22383
|
+
}
|
|
22384
|
+
}
|
|
22385
|
+
function contextAt(fds, fd) {
|
|
22386
|
+
const open2 = fds.get(fd);
|
|
22387
|
+
const file = open2.file;
|
|
22388
|
+
if (!(file instanceof TlsContext)) throw new KernelError("EBADF", "not a tls context");
|
|
22389
|
+
const held = open2.retain();
|
|
22390
|
+
let released2 = false;
|
|
22391
|
+
return {
|
|
22392
|
+
leaf: file.leaf,
|
|
22393
|
+
done: () => {
|
|
22394
|
+
if (released2) return;
|
|
22395
|
+
released2 = true;
|
|
22396
|
+
void held.release();
|
|
22397
|
+
}
|
|
22398
|
+
};
|
|
22399
|
+
}
|
|
22400
|
+
function choiceOf(fds, pause2, req) {
|
|
22401
|
+
if (req.refuse !== void 0) {
|
|
22402
|
+
if (!REFUSALS.has(req.refuse)) throw new KernelError("EINVAL", "not a refusal alert");
|
|
22403
|
+
return { refuse: req.refuse };
|
|
22404
|
+
}
|
|
22405
|
+
if (req.alpn !== void 0 && !pause2.offer.protocols.includes(req.alpn))
|
|
22406
|
+
throw new KernelError("EINVAL", "ERR_TLS_ALPN_CALLBACK_INVALID_RESULT: not offered");
|
|
22407
|
+
return {
|
|
22408
|
+
...req.context === void 0 ? {} : contextAt(fds, req.context),
|
|
22409
|
+
...req.alpn === void 0 ? {} : { alpn: req.alpn }
|
|
22410
|
+
};
|
|
22411
|
+
}
|
|
22412
|
+
async function selectSecure(fds, socket, req) {
|
|
22413
|
+
const selecting = selections.get(socket);
|
|
22414
|
+
if (!selecting) throw new KernelError("EINVAL", "no handshake waits for a selection");
|
|
22415
|
+
selections.delete(socket);
|
|
22416
|
+
let choice;
|
|
22417
|
+
try {
|
|
22418
|
+
choice = choiceOf(fds, selecting.pause, req);
|
|
22419
|
+
} catch (err) {
|
|
22420
|
+
selecting.pause.choose({ refuse: 40 });
|
|
22421
|
+
throw err;
|
|
22422
|
+
}
|
|
22423
|
+
selecting.pause.choose(choice);
|
|
22424
|
+
try {
|
|
22425
|
+
return servedOf(await selecting.run);
|
|
22217
22426
|
} finally {
|
|
22218
|
-
|
|
22427
|
+
choice.done?.();
|
|
22219
22428
|
}
|
|
22220
22429
|
}
|
|
22221
22430
|
|
|
@@ -22383,7 +22592,9 @@ var SOCKET_OPS = [
|
|
|
22383
22592
|
"sock-tls",
|
|
22384
22593
|
"sock-tls-upgrade",
|
|
22385
22594
|
"sock-tls-serve",
|
|
22386
|
-
"sock-tls-listen"
|
|
22595
|
+
"sock-tls-listen",
|
|
22596
|
+
"sock-tls-context",
|
|
22597
|
+
"sock-tls-select"
|
|
22387
22598
|
];
|
|
22388
22599
|
function socketAt(fds, fd) {
|
|
22389
22600
|
const file = anySocketAt(fds, fd);
|
|
@@ -22464,6 +22675,12 @@ async function socketSyscall(req, proc) {
|
|
|
22464
22675
|
const listener = from === void 0 ? {} : { listener: socketAt(fds, from) };
|
|
22465
22676
|
return ok3(await serveSecure(proc, socketAt(fds, req.fd), { ...rest2, ...listener }));
|
|
22466
22677
|
}
|
|
22678
|
+
case "sock-tls-context":
|
|
22679
|
+
return ok3(await contextSecure(proc, req.cert));
|
|
22680
|
+
case "sock-tls-select": {
|
|
22681
|
+
const { fd, ...choice } = req;
|
|
22682
|
+
return ok3(await selectSecure(fds, socketAt(fds, fd), choice));
|
|
22683
|
+
}
|
|
22467
22684
|
case "sock-tls-listen":
|
|
22468
22685
|
await listenSecure(proc, socketAt(fds, req.fd), req);
|
|
22469
22686
|
return ok3({});
|
|
@@ -23336,10 +23553,10 @@ function heldIo(fs, nodes, changed) {
|
|
|
23336
23553
|
const held = await node(path);
|
|
23337
23554
|
return held ? held.byName(() => held.pread(n, at)) : ranged2.pread(path, at, n, version);
|
|
23338
23555
|
},
|
|
23339
|
-
pwrite: (path, at, bytes, transfer) => write(
|
|
23556
|
+
pwrite: (path, at, bytes, transfer, options) => write(
|
|
23340
23557
|
path,
|
|
23341
23558
|
async (held) => void await held.pwrite(bytes, at),
|
|
23342
|
-
() => ranged2.pwrite(path, at, bytes, transfer)
|
|
23559
|
+
() => ranged2.pwrite(path, at, bytes, transfer, options)
|
|
23343
23560
|
),
|
|
23344
23561
|
truncate: (path, size) => write(
|
|
23345
23562
|
path,
|
|
@@ -25624,8 +25841,9 @@ function holdingToken(opts, holds2, caller) {
|
|
|
25624
25841
|
cwd: opts.cwd,
|
|
25625
25842
|
...opts.statfs ? { statfs: opts.statfs } : {},
|
|
25626
25843
|
...opts.renames ? { renames: opts.renames } : {},
|
|
25844
|
+
...opts.fileId ? { fileId: opts.fileId } : {},
|
|
25627
25845
|
...opts.renameSeq ? { renameSeq: opts.renameSeq } : {},
|
|
25628
|
-
hold: (path, on, open2, real, handle, ino) => holds2.hold(path, on, open2, real, handle, ino),
|
|
25846
|
+
hold: (path, on, open2, real, handle, ino, fid) => holds2.hold(path, on, open2, real, handle, ino, fid),
|
|
25629
25847
|
boundIno: holds2.boundIno.bind(holds2),
|
|
25630
25848
|
trust: holds2.trust.bind(holds2),
|
|
25631
25849
|
keptFor: (handle) => holds2.keptFor(handle),
|
|
@@ -29428,7 +29646,7 @@ function targetOf(command) {
|
|
|
29428
29646
|
...command.variants ? { variants: command.variants } : {}
|
|
29429
29647
|
};
|
|
29430
29648
|
}
|
|
29431
|
-
function
|
|
29649
|
+
function chosen2(planned, env) {
|
|
29432
29650
|
const { target } = planned;
|
|
29433
29651
|
const wasm = variantFor(target.variants, env);
|
|
29434
29652
|
if (wasm === void 0) return planned;
|
|
@@ -30587,7 +30805,7 @@ var Launcher = class {
|
|
|
30587
30805
|
delete env[TICKET_ENV];
|
|
30588
30806
|
const own = env.HOSTNAME;
|
|
30589
30807
|
if (asked.target.abi === "wasi") env.HOSTNAME = this.hostname;
|
|
30590
|
-
const planned =
|
|
30808
|
+
const planned = chosen2(asked, env);
|
|
30591
30809
|
const { target, args } = planned;
|
|
30592
30810
|
let program;
|
|
30593
30811
|
let exeId;
|
|
@@ -30777,7 +30995,8 @@ var Launcher = class {
|
|
|
30777
30995
|
opfsOps: this.rootFs.opfsOps?.() ?? 0,
|
|
30778
30996
|
cwdChecks: this.cwds.checks,
|
|
30779
30997
|
renameAcks: this.rootFs.renameWaits?.(),
|
|
30780
|
-
staleFds: staleFdCount()
|
|
30998
|
+
staleFds: staleFdCount(),
|
|
30999
|
+
fileIds: this.rootFs.fileIdWrites?.() ?? 0
|
|
30781
31000
|
}),
|
|
30782
31001
|
sudo: (call, signal) => this.sudo(pid, call, signal),
|
|
30783
31002
|
crontab: (call) => this.crontab(pid, call),
|
|
@@ -30788,6 +31007,7 @@ var Launcher = class {
|
|
|
30788
31007
|
replacements: stack.unlinked,
|
|
30789
31008
|
statfs: (path) => this.mounts.statfs(path),
|
|
30790
31009
|
renames: (since, held) => this.renameLog.since(since, held),
|
|
31010
|
+
fileId: (path) => this.locks.shared?.() === true ? this.rootFileId(path) : void 0,
|
|
30791
31011
|
renameSeq: (from, to) => this.renameLog.seqOf(from, to),
|
|
30792
31012
|
mounts: () => this.mounts.list(),
|
|
30793
31013
|
mount: (call, signal) => this.processMount(pid, call, signal),
|
|
@@ -31667,12 +31887,16 @@ var Launcher = class {
|
|
|
31667
31887
|
this.writers ??= this.writerStack();
|
|
31668
31888
|
return this.writers;
|
|
31669
31889
|
}
|
|
31890
|
+
rootFileId(path) {
|
|
31891
|
+
return this.mounts.locate(path) === void 0 ? this.rootFs.fileId?.(path) : void 0;
|
|
31892
|
+
}
|
|
31670
31893
|
flushingPeers(fs) {
|
|
31671
31894
|
const peers = fs.peers?.();
|
|
31672
31895
|
if (!peers) return void 0;
|
|
31673
31896
|
peers.watch((crowded) => {
|
|
31674
31897
|
this.changes.flush();
|
|
31675
31898
|
this.changes.foreign(crowded);
|
|
31899
|
+
if (crowded) void this.held?.bindIds((path) => this.rootFileId(path));
|
|
31676
31900
|
});
|
|
31677
31901
|
return {
|
|
31678
31902
|
...peers,
|