@ai-ecoverse/slicc-kernel 1.124.11 → 1.124.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/node.js CHANGED
@@ -1557,8 +1557,8 @@ function uplinkLink(conn, onReset) {
1557
1557
  open = false;
1558
1558
  conn.close();
1559
1559
  };
1560
- void inbound(conn, rx).catch(() => {
1561
- onReset();
1560
+ void inbound(conn, rx).catch((err) => {
1561
+ onReset(err);
1562
1562
  close();
1563
1563
  tx.closeRead();
1564
1564
  }).finally(() => rx.closeWrite());
@@ -1649,7 +1649,7 @@ var KernelSocket = class _KernelSocket {
1649
1649
  state = "open";
1650
1650
  dialing;
1651
1651
  failed;
1652
- reset = false;
1652
+ reset;
1653
1653
  local;
1654
1654
  peer;
1655
1655
  peerCred;
@@ -1688,19 +1688,20 @@ var KernelSocket = class _KernelSocket {
1688
1688
  const { rx } = this.connection();
1689
1689
  if (this.readShut || max <= 0) return new Uint8Array(0);
1690
1690
  const bytes = await pipeCall(() => rx.read(max, signal));
1691
- if (bytes.length === 0 && this.reset) throw new KernelError("ECONNRESET");
1691
+ if (bytes.length === 0 && this.reset) throw this.reset;
1692
1692
  return bytes;
1693
1693
  }
1694
1694
  async peek(max, signal) {
1695
1695
  const { rx } = this.connection();
1696
1696
  if (this.readShut || max <= 0) return new Uint8Array(0);
1697
1697
  const bytes = await pipeCall(() => rx.peek(max, signal));
1698
- if (bytes.length === 0 && this.reset) throw new KernelError("ECONNRESET");
1698
+ if (bytes.length === 0 && this.reset) throw this.reset;
1699
1699
  return bytes;
1700
1700
  }
1701
1701
  async write(bytes, signal) {
1702
1702
  const { tx } = this.connection();
1703
1703
  if (this.writeShut) throw new KernelError("EPIPE");
1704
+ if (this.reset?.code === "EPROTO") throw this.reset;
1704
1705
  return pipeCall(() => tx.write(bytes, signal));
1705
1706
  }
1706
1707
  poll() {
@@ -1885,8 +1886,8 @@ var KernelSocket = class _KernelSocket {
1885
1886
  this.dialing = void 0;
1886
1887
  this.switch = conn;
1887
1888
  this.attach(
1888
- uplinkLink(conn, () => {
1889
- this.reset = true;
1889
+ uplinkLink(conn, (err) => {
1890
+ this.reset = err instanceof KernelError && err.code === "EPROTO" ? err : new KernelError("ECONNRESET");
1890
1891
  this.changes.wake();
1891
1892
  })
1892
1893
  );
@@ -5993,16 +5994,24 @@ var UnlinkedKeeper = class {
5993
5994
  gated();
5994
5995
  const held = /* @__PURE__ */ new Map();
5995
5996
  const hidden = /* @__PURE__ */ new Map();
5996
- for (; ; ) {
5997
- await take();
5998
- const now = this.heldWithin(target);
5999
- const next3 = paths.filter((path) => now.has(path) && !held.has(path));
6000
- if (next3.length === 0) break;
6001
- for (const path of next3) {
6002
- held.set(path, now.get(path));
6003
- const at = await this.hide(path);
6004
- if (at !== void 0) hidden.set(path, at);
5997
+ const moved2 = [];
5998
+ try {
5999
+ for (; ; ) {
6000
+ await take();
6001
+ const now = this.heldWithin(target);
6002
+ const next3 = paths.filter((path) => now.has(path) && !held.has(path));
6003
+ if (next3.length === 0) break;
6004
+ for (const path of next3) {
6005
+ const holders = now.get(path);
6006
+ held.set(path, holders);
6007
+ for (const holder of holders) moved2.push(holder.moving?.(path) ?? (() => void 0));
6008
+ const at = await this.hide(path);
6009
+ if (at !== void 0) hidden.set(path, at);
6010
+ }
6005
6011
  }
6012
+ } catch (err) {
6013
+ for (const settle of moved2) settle();
6014
+ throw err;
6006
6015
  }
6007
6016
  sealed();
6008
6017
  const done4 = () => {
@@ -6015,6 +6024,7 @@ var UnlinkedKeeper = class {
6015
6024
  files.set(path, file);
6016
6025
  for (const holder of holders) holder.keep(path, file);
6017
6026
  }
6027
+ for (const settle of moved2) settle();
6018
6028
  return {
6019
6029
  moved: new Set(hidden.keys()),
6020
6030
  commit: () => {
@@ -7070,7 +7080,7 @@ function satisfies(version, range2) {
7070
7080
  }
7071
7081
 
7072
7082
  // src/version.ts
7073
- var KERNEL_VERSION = true ? "1.124.11" : "0.0.0-dev";
7083
+ var KERNEL_VERSION = true ? "1.124.13" : "0.0.0-dev";
7074
7084
  var OS_RELEASE = "6.0.0-slicc";
7075
7085
  function procVersion() {
7076
7086
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -12489,6 +12499,10 @@ function attachSyncSabResponder(port, sab, token, opts) {
12489
12499
  Atomics.add(header4, SAB_I_PUB, 1);
12490
12500
  Atomics.notify(header4, SAB_I_PUB);
12491
12501
  if (offset + chunk2 >= entry.payload.byteLength) drop(id2);
12502
+ else if (entry.timer) {
12503
+ clearTimeout(entry.timer);
12504
+ entry.timer = setTimeout(() => drop(id2), PENDING_TTL_MS);
12505
+ }
12492
12506
  }
12493
12507
  function settle(id2, result) {
12494
12508
  if (disposed) return;
@@ -14820,6 +14834,8 @@ function realmCa(owner, store) {
14820
14834
 
14821
14835
  // src/kernel/net/tls-engine.ts
14822
14836
  var TLS_CLIENT_INSECURE_SKIP_VERIFY = 1;
14837
+ var TLS_CLIENT_NO_SNI = 2;
14838
+ var TLS_CLIENT_VERIFY_CHAIN_ONLY = 4;
14823
14839
  var SCRATCH = 64 * 1024;
14824
14840
  var EOF = -1;
14825
14841
  var TlsError = class extends Error {
@@ -14876,10 +14892,22 @@ var TlsEngine = class {
14876
14892
  this.m._free(ptr);
14877
14893
  }
14878
14894
  }
14895
+ withSecret(bytes, fn) {
14896
+ const ptr = this.put(bytes);
14897
+ try {
14898
+ return fn(ptr);
14899
+ } finally {
14900
+ this.m.HEAPU8.fill(0, ptr, ptr + bytes.length + 1);
14901
+ this.m._free(ptr);
14902
+ }
14903
+ }
14879
14904
  intoScratch(fn) {
14880
14905
  const n = fn(this.scratch, SCRATCH);
14881
14906
  return n > 0 ? this.taken(n) : n;
14882
14907
  }
14908
+ get sessionControls() {
14909
+ return typeof this.m._tls_client_cert === "function";
14910
+ }
14883
14911
  get client() {
14884
14912
  return typeof this.m._tls_client_new === "function" ? this.m : void 0;
14885
14913
  }
@@ -15032,6 +15060,27 @@ var TlsSession = class {
15032
15060
  const out = this.engine.intoScratch((p, max) => this.c._tls_alpn(this.ptr, p, max));
15033
15061
  return out instanceof Uint8Array ? new TextDecoder().decode(out) : void 0;
15034
15062
  }
15063
+ ownCert(chain2, key, pass2) {
15064
+ const set3 = this.m._tls_client_cert;
15065
+ const keyLen = key[0] === 45 ? key.length + 1 : key.length;
15066
+ const ret = this.engine.withBytes(
15067
+ chain2,
15068
+ (c) => this.engine.withSecret(
15069
+ key,
15070
+ (k) => this.engine.withSecret(
15071
+ pass2,
15072
+ (p) => set3(this.ptr, c, chain2.length, k, keyLen, pass2.length > 0 ? p : 0, pass2.length)
15073
+ )
15074
+ )
15075
+ );
15076
+ if (ret !== 0) throw this.engine.error(ret, "client certificate");
15077
+ }
15078
+ get ciphersuite() {
15079
+ return this.m._tls_ciphersuite(this.ptr);
15080
+ }
15081
+ get nameMismatch() {
15082
+ return this.m._tls_name_mismatch(this.ptr) === 1;
15083
+ }
15035
15084
  peerChain() {
15036
15085
  const chain2 = [];
15037
15086
  const count2 = this.c._tls_peer_count(this.ptr);
@@ -16336,11 +16385,11 @@ async function runChild(req, deps) {
16336
16385
  if (pid !== 0) kill();
16337
16386
  decided.resolve();
16338
16387
  };
16339
- const controls = [];
16388
+ const controls2 = [];
16340
16389
  const capture = () => {
16341
16390
  const { promise, resolve: resolve2 } = Promise.withResolvers();
16342
16391
  const control = { shut: false, ended: resolve2, eof: promise };
16343
- controls.push(control);
16392
+ controls2.push(control);
16344
16393
  return { capture: true, max, overflow: () => stop("ENOBUFS"), control };
16345
16394
  };
16346
16395
  const decided = Promise.withResolvers();
@@ -16374,11 +16423,11 @@ async function runChild(req, deps) {
16374
16423
  let status;
16375
16424
  try {
16376
16425
  status = await reaped(deps, pid);
16377
- const open = controls.filter((c) => c.opened);
16426
+ const open = controls2.filter((c) => c.opened);
16378
16427
  await Promise.race([Promise.all(open.map((c) => c.eof)), decided.promise]);
16379
16428
  } finally {
16380
16429
  cancel?.();
16381
- for (const control of controls) control.shut = true;
16430
+ for (const control of controls2) control.shut = true;
16382
16431
  }
16383
16432
  const out = deps.children.captured(pid, 1);
16384
16433
  const err = deps.children.captured(pid, 2);
@@ -16960,6 +17009,47 @@ function encodeReceived(got) {
16960
17009
  return out;
16961
17010
  }
16962
17011
 
17012
+ // src/kernel/net/tls-ciphers.ts
17013
+ var SUITES = [
17014
+ [4865, "TLS_AES_128_GCM_SHA256", "TLS_AES_128_GCM_SHA256", "TLSv1.3"],
17015
+ [4866, "TLS_AES_256_GCM_SHA384", "TLS_AES_256_GCM_SHA384", "TLSv1.3"],
17016
+ [4867, "TLS_CHACHA20_POLY1305_SHA256", "TLS_CHACHA20_POLY1305_SHA256", "TLSv1.3"],
17017
+ [4868, "TLS_AES_128_CCM_SHA256", "TLS_AES_128_CCM_SHA256", "TLSv1.3"],
17018
+ [4869, "TLS_AES_128_CCM_8_SHA256", "TLS_AES_128_CCM_8_SHA256", "TLSv1.3"],
17019
+ [49195, "ECDHE-ECDSA-AES128-GCM-SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLSv1.2"],
17020
+ [49196, "ECDHE-ECDSA-AES256-GCM-SHA384", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLSv1.2"],
17021
+ [49199, "ECDHE-RSA-AES128-GCM-SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLSv1.2"],
17022
+ [49200, "ECDHE-RSA-AES256-GCM-SHA384", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLSv1.2"],
17023
+ [52392, "ECDHE-RSA-CHACHA20-POLY1305", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLSv1.2"],
17024
+ [
17025
+ 52393,
17026
+ "ECDHE-ECDSA-CHACHA20-POLY1305",
17027
+ "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
17028
+ "TLSv1.2"
17029
+ ],
17030
+ [49187, "ECDHE-ECDSA-AES128-SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "TLSv1.2"],
17031
+ [49188, "ECDHE-ECDSA-AES256-SHA384", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "TLSv1.2"],
17032
+ [49191, "ECDHE-RSA-AES128-SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "TLSv1.2"],
17033
+ [49192, "ECDHE-RSA-AES256-SHA384", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", "TLSv1.2"],
17034
+ [49161, "ECDHE-ECDSA-AES128-SHA", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLSv1.0"],
17035
+ [49162, "ECDHE-ECDSA-AES256-SHA", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "TLSv1.0"],
17036
+ [49171, "ECDHE-RSA-AES128-SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLSv1.0"],
17037
+ [49172, "ECDHE-RSA-AES256-SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLSv1.0"],
17038
+ [156, "AES128-GCM-SHA256", "TLS_RSA_WITH_AES_128_GCM_SHA256", "TLSv1.2"],
17039
+ [157, "AES256-GCM-SHA384", "TLS_RSA_WITH_AES_256_GCM_SHA384", "TLSv1.2"],
17040
+ [158, "DHE-RSA-AES128-GCM-SHA256", "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "TLSv1.2"],
17041
+ [159, "DHE-RSA-AES256-GCM-SHA384", "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "TLSv1.2"]
17042
+ ];
17043
+ function cipherOf(id2, protocol) {
17044
+ const known = SUITES.find(([n]) => n === id2);
17045
+ const hex3 = `0x${id2.toString(16).padStart(4, "0").toUpperCase()}`;
17046
+ return {
17047
+ name: known?.[1] ?? hex3,
17048
+ standardName: known?.[2] ?? hex3,
17049
+ version: known?.[3] ?? protocol
17050
+ };
17051
+ }
17052
+
16963
17053
  // src/kernel/net/tls-client.ts
16964
17054
  var WRITE_CHUNK = 16 * 1024;
16965
17055
  var BADCERT = [
@@ -16976,6 +17066,15 @@ function verifyCode(flags2) {
16976
17066
  if (flags2 === -1) return "UNABLE_TO_VERIFY_LEAF_SIGNATURE";
16977
17067
  return BADCERT.find(([bit]) => (flags2 & bit) !== 0)?.[1] ?? "UNABLE_TO_VERIFY_LEAF_SIGNATURE";
16978
17068
  }
17069
+ function isIP(name2) {
17070
+ return ipv4Bytes(name2) !== void 0 || name2.includes(":") && ipv6Groups(name2) !== void 0;
17071
+ }
17072
+ function clientFlags(o) {
17073
+ return (o.insecure ? TLS_CLIENT_INSECURE_SKIP_VERIFY : 0) | (o.sni === false ? TLS_CLIENT_NO_SNI : 0) | (o.checkHostname === false ? TLS_CLIENT_VERIFY_CHAIN_ONLY : 0);
17074
+ }
17075
+ function openSession(o) {
17076
+ return o.engine.clientSession(o.store, o.servername, o.alpn, clientFlags(o));
17077
+ }
16979
17078
  var Ciphertext = class {
16980
17079
  queue = [];
16981
17080
  ended = false;
@@ -17048,17 +17147,39 @@ async function handshake(conn, o, session, inbox) {
17048
17147
  }
17049
17148
  }
17050
17149
  }
17150
+ function controlsOf(o, session, protocol) {
17151
+ if (!o.engine.sessionControls) return {};
17152
+ const checked = o.checkHostname !== false && !o.insecure;
17153
+ return {
17154
+ cipher: cipherOf(session.ciphersuite, protocol),
17155
+ clientCertificate: o.clientCertificate === true,
17156
+ sni: o.sni !== false && !isIP(o.servername),
17157
+ hostnameChecked: checked,
17158
+ ...o.insecure ? {} : { hostnameMatches: checked || !session.nameMismatch }
17159
+ };
17160
+ }
17051
17161
  function infoOf(o, session) {
17052
17162
  const flags2 = session.verifyResult;
17053
17163
  const code = verifyCode(flags2);
17164
+ const protocol = session.version === 772 ? "TLSv1.3" : "TLSv1.2";
17054
17165
  return {
17055
- protocol: session.version === 772 ? "TLSv1.3" : "TLSv1.2",
17166
+ protocol,
17056
17167
  alpnProtocol: session.alpn ?? false,
17057
17168
  authorized: code === void 0,
17058
17169
  ...code ? { authorizationError: code, authorizationText: o.engine.verifyInfo(flags2).trim() } : {},
17059
- peerCertificates: session.peerChain()
17170
+ peerCertificates: session.peerChain(),
17171
+ ...controlsOf(o, session, protocol)
17060
17172
  };
17061
17173
  }
17174
+ var FATAL_ALERT = -30592;
17175
+ function alerted(err) {
17176
+ if (err.code === FATAL_ALERT)
17177
+ return new KernelError(
17178
+ "EPROTO",
17179
+ `ERR_SSL_FATAL_ALERT: the server ended the session: ${err.message}`
17180
+ );
17181
+ return new KernelError("EPROTO", `ERR_SSL_PROTOCOL_ERROR: ${err.message}`);
17182
+ }
17062
17183
  function plaintext(conn, session, inbox) {
17063
17184
  let freed = false;
17064
17185
  let writeClosed = false;
@@ -17073,7 +17194,12 @@ function plaintext(conn, session, inbox) {
17073
17194
  async read() {
17074
17195
  for (; ; ) {
17075
17196
  if (freed) return null;
17076
- const got = session.read();
17197
+ let got;
17198
+ try {
17199
+ got = session.read();
17200
+ } catch (err) {
17201
+ throw alerted(err);
17202
+ }
17077
17203
  await send(conn, session);
17078
17204
  if (got instanceof Uint8Array) return got;
17079
17205
  if (got === "eof") return null;
@@ -17101,8 +17227,7 @@ function plaintext(conn, session, inbox) {
17101
17227
  };
17102
17228
  }
17103
17229
  async function tlsClient(conn, o, taken = new Uint8Array(0)) {
17104
- const flags2 = o.insecure ? TLS_CLIENT_INSECURE_SKIP_VERIFY : 0;
17105
- const session = o.engine.clientSession(o.store, o.servername, o.alpn, flags2);
17230
+ const session = o.session ?? openSession(o);
17106
17231
  const inbox = new Ciphertext(conn, session);
17107
17232
  inbox.hand(taken);
17108
17233
  try {
@@ -17115,10 +17240,10 @@ async function tlsClient(conn, o, taken = new Uint8Array(0)) {
17115
17240
  }
17116
17241
 
17117
17242
  // src/kernel/net/tls-uplink.ts
17118
- var isIP = (text) => ipv4Bytes(text) !== void 0 || text.includes(":") && ipv6Groups(text) !== void 0;
17243
+ var isIP2 = (text) => ipv4Bytes(text) !== void 0 || text.includes(":") && ipv6Groups(text) !== void 0;
17119
17244
  var LABEL2 = /^(?!-)[A-Za-z0-9-]{1,63}(?<!-)$/;
17120
17245
  function serverName(name2) {
17121
- if (isIP(name2.replace(/^\[|\]$/g, ""))) return name2.replace(/^\[|\]$/g, "");
17246
+ if (isIP2(name2.replace(/^\[|\]$/g, ""))) return name2.replace(/^\[|\]$/g, "");
17122
17247
  const bare = name2.endsWith(".") ? name2.slice(0, -1) : name2;
17123
17248
  if (bare.length === 0 || bare.length > 253 || !bare.split(".").every((l) => LABEL2.test(l))) {
17124
17249
  throw new KernelError(
@@ -17168,9 +17293,66 @@ function sessionOf(info, servername) {
17168
17293
  authorizationText: info.authorizationText
17169
17294
  } : {},
17170
17295
  servername,
17171
- peerCertificates: info.peerCertificates.map(encode)
17296
+ peerCertificates: info.peerCertificates.map(encode),
17297
+ ...controls(info)
17172
17298
  };
17173
17299
  }
17300
+ function controls(info) {
17301
+ if (!info.cipher) return {};
17302
+ return {
17303
+ cipher: info.cipher,
17304
+ clientCertificate: info.clientCertificate === true,
17305
+ sni: info.sni !== false,
17306
+ hostnameChecked: info.hostnameChecked === true,
17307
+ ...info.hostnameMatches === void 0 ? {} : { hostnameMatches: info.hostnameMatches }
17308
+ };
17309
+ }
17310
+ var KEY_ERRORS = [
17311
+ [-3, "ERR_OSSL_X509_KEY_VALUES_MISMATCH"],
17312
+ [-15232, "ERR_OSSL_BAD_DECRYPT"],
17313
+ [-15360, "ERR_OSSL_CRYPTO_INTERRUPTED_OR_CANCELLED"]
17314
+ ];
17315
+ function keyRefused(err) {
17316
+ const code = err instanceof TlsError ? err.code : 0;
17317
+ const name2 = KEY_ERRORS.find(([n]) => n === code)?.[1] ?? "ERR_OSSL_UNSUPPORTED";
17318
+ const text = code === -3 ? "the key does not match the certificate" : err.message;
17319
+ return new KernelError("EPROTO", `${name2}: ${text}`);
17320
+ }
17321
+ function takeCert(req) {
17322
+ const cert = req.clientCert;
17323
+ if (!cert) return void 0;
17324
+ delete req.clientCert;
17325
+ if (!Array.isArray(cert.chain) || cert.chain.length === 0 || typeof cert.key !== "string")
17326
+ throw new KernelError("EINVAL", "ERR_INVALID_ARG_VALUE: cert and key go together");
17327
+ let ders;
17328
+ let key;
17329
+ try {
17330
+ ders = cert.chain.map(base64Der);
17331
+ key = base64Der(cert.key);
17332
+ } catch {
17333
+ throw new KernelError("EINVAL", "ERR_INVALID_ARG_VALUE: cert or key is not base64");
17334
+ }
17335
+ const chain2 = new Uint8Array(ders.reduce((n, d) => n + d.length, 0));
17336
+ let at = 0;
17337
+ for (const der of ders) {
17338
+ chain2.set(der, at);
17339
+ at += der.length;
17340
+ }
17341
+ const pass2 = new TextEncoder().encode(cert.passphrase ?? "");
17342
+ return { chain: chain2, key, pass: pass2 };
17343
+ }
17344
+ function withCert(session, cert) {
17345
+ if (!cert) return;
17346
+ try {
17347
+ session.ownCert(cert.chain, cert.key, cert.pass);
17348
+ } catch (err) {
17349
+ throw keyRefused(err);
17350
+ }
17351
+ }
17352
+ function wipe(cert) {
17353
+ cert?.key.fill(0);
17354
+ cert?.pass.fill(0);
17355
+ }
17174
17356
  async function setUp(support, req) {
17175
17357
  const engine = await support.engine();
17176
17358
  if (!engine.client)
@@ -17188,21 +17370,66 @@ async function setUp(support, req) {
17188
17370
  }
17189
17371
  return { engine, store: own, own };
17190
17372
  }
17191
- function secure(support, req, servername) {
17192
- return async (raw) => {
17193
- const { engine, store, own } = await setUp(support, req);
17373
+ async function prepare(support, req, servername) {
17374
+ const cert = takeCert(req);
17375
+ try {
17376
+ return await prepareWith(support, req, servername, cert);
17377
+ } catch (err) {
17378
+ if (err instanceof KernelError) throw err;
17379
+ throw new KernelError("ENOTSUP", err instanceof Error ? err.message : String(err));
17380
+ } finally {
17381
+ wipe(cert);
17382
+ }
17383
+ }
17384
+ async function prepareWith(support, req, servername, cert) {
17385
+ if (req.checkHostname === false && req.insecure === true) {
17386
+ throw new KernelError(
17387
+ "EINVAL",
17388
+ "ERR_INVALID_ARG_VALUE: checkHostname: false needs rejectUnauthorized"
17389
+ );
17390
+ }
17391
+ const { engine, store, own } = await setUp(support, req);
17392
+ const options = {
17393
+ engine,
17394
+ store,
17395
+ servername,
17396
+ alpn: req.alpn ?? [],
17397
+ insecure: req.insecure === true,
17398
+ ...req.sni === false ? { sni: false } : {},
17399
+ ...req.checkHostname === false ? { checkHostname: false } : {},
17400
+ clientCertificate: cert !== void 0
17401
+ };
17402
+ let session;
17403
+ try {
17404
+ const controls2 = req.sni === false || req.checkHostname === false || cert !== void 0;
17405
+ if (controls2 && !engine.sessionControls) {
17406
+ throw new KernelError("ENOTSUP", "the installed tls engine has no client certificates");
17407
+ }
17408
+ session = openSession(options);
17409
+ withCert(session, cert);
17410
+ return { options: { ...options, session }, own };
17411
+ } catch (err) {
17412
+ session?.free();
17413
+ own?.release();
17414
+ throw err;
17415
+ }
17416
+ }
17417
+ function secure(prepared) {
17418
+ let ran = false;
17419
+ const make = async (raw) => {
17420
+ ran = true;
17194
17421
  try {
17195
- return await tlsClient(raw, {
17196
- engine,
17197
- store,
17198
- servername,
17199
- alpn: req.alpn ?? [],
17200
- insecure: req.insecure === true
17201
- });
17422
+ return await tlsClient(raw, prepared.options);
17202
17423
  } finally {
17203
- own?.release();
17424
+ prepared.own?.release();
17204
17425
  }
17205
17426
  };
17427
+ const abandon = () => {
17428
+ if (ran) return;
17429
+ prepared.options.session.free();
17430
+ prepared.own?.release();
17431
+ };
17432
+ return { make, abandon };
17206
17433
  }
17207
17434
  function supportOf(net) {
17208
17435
  const support = net.tlsClient;
@@ -17211,7 +17438,7 @@ function supportOf(net) {
17211
17438
  }
17212
17439
  async function uplinkAddress(proc, host) {
17213
17440
  const bare = host.replace(/^\[|\]$/g, "");
17214
- if (isIP(bare)) return bare;
17441
+ if (isIP2(bare)) return bare;
17215
17442
  const [first] = await proc.resolve(host, 0, () => proc.blocking());
17216
17443
  if (!first) throw new KernelError("ENOENT", `ENOTFOUND: ${host}`);
17217
17444
  return first;
@@ -17225,18 +17452,26 @@ async function connectSecure(proc, socket, host, port, req) {
17225
17452
  throw new KernelError("ENOTSUP", "TLS in the kernel needs a destination the uplink routes");
17226
17453
  const support = supportOf(proc.net);
17227
17454
  let info;
17228
- const make = secure(support, req, servername);
17229
- await socket.connectSecure({ family: "inet", host: address, port }, route, async (conn) => {
17230
- info = await conn.upgrade(make);
17231
- });
17455
+ const { make, abandon } = secure(await prepare(support, req, servername));
17456
+ try {
17457
+ await socket.connectSecure({ family: "inet", host: address, port }, route, async (conn) => {
17458
+ info = await conn.upgrade(make);
17459
+ });
17460
+ } finally {
17461
+ abandon();
17462
+ }
17232
17463
  return sessionOf(info, servername);
17233
17464
  }
17234
17465
  async function upgradeSecure(proc, socket, req) {
17235
17466
  const peer = socket.peer;
17236
17467
  const host = req.servername || (peer?.family === "inet" ? peer.host : "");
17237
17468
  const servername = serverName(host);
17238
- const info = await socket.upgradeSecure(secure(supportOf(proc.net), req, servername));
17239
- return sessionOf(info, servername);
17469
+ const { make, abandon } = secure(await prepare(supportOf(proc.net), req, servername));
17470
+ try {
17471
+ return sessionOf(await socket.upgradeSecure(make), servername);
17472
+ } finally {
17473
+ abandon();
17474
+ }
17240
17475
  }
17241
17476
 
17242
17477
  // src/kernel/unix-dgram.ts
@@ -17598,17 +17833,23 @@ var NOT_HTTP_PORTS = /* @__PURE__ */ new Set([
17598
17833
  8883
17599
17834
  ]);
17600
17835
  var HOST_NAME = /^[A-Za-z0-9.-]+$|^\[?[0-9A-Fa-f:.]+\]?$/;
17836
+ function sessionControls(req) {
17837
+ return req.sni === false || req.checkHostname === false || req.clientCert !== void 0;
17838
+ }
17601
17839
  function wantsKernel(req) {
17602
17840
  if (req.path === "kernel") return true;
17603
17841
  if (req.path === "transport") return false;
17604
- return Array.isArray(req.ca) || req.alpn !== void 0 && req.alpn.length > 0 && !req.alpn.includes("http/1.1") || NOT_HTTP_PORTS.has(req.port);
17842
+ return Array.isArray(req.ca) || sessionControls(req) || req.alpn !== void 0 && req.alpn.length > 0 && !req.alpn.includes("http/1.1") || NOT_HTTP_PORTS.has(req.port);
17605
17843
  }
17606
17844
  async function secureConnect(req, proc) {
17607
17845
  if (!Number.isInteger(req.port) || req.port < 1 || req.port > 65535)
17608
17846
  throw new KernelError("EINVAL");
17609
17847
  const kernelPath = wantsKernel(req) && await uplinked(proc, req.host);
17610
17848
  if (!kernelPath) {
17611
- if (req.path === "kernel" || Array.isArray(req.ca)) throw new KernelError("ENOTSUP");
17849
+ if (req.path === "kernel" || Array.isArray(req.ca) || sessionControls(req)) {
17850
+ delete req.clientCert;
17851
+ throw new KernelError("ENOTSUP");
17852
+ }
17612
17853
  return { ...tlsOverTransport(req, proc), path: "transport", substitutes: true };
17613
17854
  }
17614
17855
  const socket = proc.net.socket("inet");
@@ -17742,13 +17983,17 @@ var VfsNode = class {
17742
17983
  const ranged2 = await this.prepare();
17743
17984
  await ranged2?.pin();
17744
17985
  }
17986
+ moving = /* @__PURE__ */ new Set();
17745
17987
  async load() {
17746
17988
  if (this.revoked) throw new KernelError("EIO");
17747
- if (!this.data) {
17989
+ while (!this.data) {
17990
+ const at = this.path;
17748
17991
  try {
17749
- this.data = await this.fs.readFileBuffer(this.path);
17992
+ this.data = await this.fs.readFileBuffer(at);
17750
17993
  } catch (err) {
17751
17994
  if (!isMissing(err)) throw err;
17995
+ while (this.moving.size > 0) await Promise.all(this.moving);
17996
+ if (this.path !== at) continue;
17752
17997
  this.data = new Uint8Array(0);
17753
17998
  this.missing = true;
17754
17999
  }
@@ -18102,6 +18347,16 @@ var VfsNodes = class {
18102
18347
  this.byPath.set(file.hidden, node);
18103
18348
  this.kept.set(node, file);
18104
18349
  }
18350
+ moving(path) {
18351
+ const node = this.byPath.get(path);
18352
+ if (!node) return () => void 0;
18353
+ const { promise, resolve: resolve2 } = Promise.withResolvers();
18354
+ node.moving.add(promise);
18355
+ return () => {
18356
+ node.moving.delete(promise);
18357
+ resolve2();
18358
+ };
18359
+ }
18105
18360
  unkeep(path, file) {
18106
18361
  const node = this.byPath.get(file.hidden);
18107
18362
  if (!node) return;
@@ -21389,7 +21644,7 @@ function register(automaton, sources, ids, bytes, source) {
21389
21644
  }
21390
21645
  sources[id2].push(source);
21391
21646
  }
21392
- function prepare(secrets) {
21647
+ function prepare2(secrets) {
21393
21648
  const main = new Automaton();
21394
21649
  const wrap = new Automaton();
21395
21650
  const sources = [];
@@ -21540,7 +21795,7 @@ function merge(into, from) {
21540
21795
  }
21541
21796
  }
21542
21797
  function compile(secrets, options = {}) {
21543
- const c = prepare(secrets.map((secret) => ({ ...secret })));
21798
+ const c = prepare2(secrets.map((secret) => ({ ...secret })));
21544
21799
  const decoder4 = new TextDecoder();
21545
21800
  const idleMs = options.idleMs ?? 250;
21546
21801
  const scrubBytes = (input) => {
@@ -26545,7 +26800,7 @@ function cronLocks() {
26545
26800
  import { AsyncLocalStorage } from "node:async_hooks";
26546
26801
  import { subscribe } from "node:diagnostics_channel";
26547
26802
  import { lookup as lookup2 } from "node:dns/promises";
26548
- import { isIP as isIP2 } from "node:net";
26803
+ import { isIP as isIP3 } from "node:net";
26549
26804
  var DEVTOOLS_PORTS = [9222, 9223, 9224, 9225, 9226, 9227, 9228, 9229];
26550
26805
  var METADATA_V6 = [64768, 3778, 0, 0, 0, 0, 0, 596].join(":");
26551
26806
  var resolveHost = async (host) => (await lookup2(host, { all: true, verbatim: true })).map((a) => a.address);
@@ -26557,7 +26812,7 @@ function ipv4Place(address) {
26557
26812
  }
26558
26813
  function placeOf(address) {
26559
26814
  const plain2 = address.replace(/^\[(.*)\]$/, "$1").toLowerCase();
26560
- const kind = isIP2(plain2);
26815
+ const kind = isIP3(plain2);
26561
26816
  if (kind === 4) return ipv4Place(plain2);
26562
26817
  if (kind !== 6) return void 0;
26563
26818
  const words2 = hextets2(plain2);
@@ -26610,7 +26865,7 @@ function connectRefusal(address, port, place) {
26610
26865
  }
26611
26866
  async function addressesOf(host, resolve2) {
26612
26867
  const plain2 = host.replace(/^\[(.*)\]$/, "$1");
26613
- if (isIP2(plain2)) return [plain2];
26868
+ if (isIP3(plain2)) return [plain2];
26614
26869
  if (loopbackName2(plain2)) return ["127.0.0.1"];
26615
26870
  return resolve2(plain2).catch(() => []);
26616
26871
  }
@@ -26945,7 +27200,7 @@ function isMemoryRoot(handle) {
26945
27200
 
26946
27201
  // src/node/ws-diagnose.ts
26947
27202
  import { lookup as lookup3 } from "node:dns/promises";
26948
- import { isIP as isIP3, connect as tcp } from "node:net";
27203
+ import { isIP as isIP4, connect as tcp } from "node:net";
26949
27204
  import { connect as tls } from "node:tls";
26950
27205
  var PROBE_MS = 3e3;
26951
27206
  var PASSED = /* @__PURE__ */ new Set(["ECONNREFUSED", "EHOSTUNREACH", "ENETUNREACH", "ETIMEDOUT", "ECONNRESET"]);
@@ -26967,7 +27222,7 @@ function abortable(work, signal) {
26967
27222
  }
26968
27223
  function probe(secure2, host, port, ms, signal) {
26969
27224
  return new Promise((resolve2) => {
26970
- const socket = secure2 ? tls({ host, port, ...isIP3(host) ? {} : { servername: host } }) : tcp({ host, port });
27225
+ const socket = secure2 ? tls({ host, port, ...isIP4(host) ? {} : { servername: host } }) : tcp({ host, port });
26971
27226
  const stop = () => done4("ABORTED");
26972
27227
  const done4 = (code) => {
26973
27228
  clearTimeout(timer);