@ai-ecoverse/slicc-kernel 1.124.12 → 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.12" : "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
@@ -14824,6 +14834,8 @@ function realmCa(owner, store) {
14824
14834
 
14825
14835
  // src/kernel/net/tls-engine.ts
14826
14836
  var TLS_CLIENT_INSECURE_SKIP_VERIFY = 1;
14837
+ var TLS_CLIENT_NO_SNI = 2;
14838
+ var TLS_CLIENT_VERIFY_CHAIN_ONLY = 4;
14827
14839
  var SCRATCH = 64 * 1024;
14828
14840
  var EOF = -1;
14829
14841
  var TlsError = class extends Error {
@@ -14880,10 +14892,22 @@ var TlsEngine = class {
14880
14892
  this.m._free(ptr);
14881
14893
  }
14882
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
+ }
14883
14904
  intoScratch(fn) {
14884
14905
  const n = fn(this.scratch, SCRATCH);
14885
14906
  return n > 0 ? this.taken(n) : n;
14886
14907
  }
14908
+ get sessionControls() {
14909
+ return typeof this.m._tls_client_cert === "function";
14910
+ }
14887
14911
  get client() {
14888
14912
  return typeof this.m._tls_client_new === "function" ? this.m : void 0;
14889
14913
  }
@@ -15036,6 +15060,27 @@ var TlsSession = class {
15036
15060
  const out = this.engine.intoScratch((p, max) => this.c._tls_alpn(this.ptr, p, max));
15037
15061
  return out instanceof Uint8Array ? new TextDecoder().decode(out) : void 0;
15038
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
+ }
15039
15084
  peerChain() {
15040
15085
  const chain2 = [];
15041
15086
  const count2 = this.c._tls_peer_count(this.ptr);
@@ -16340,11 +16385,11 @@ async function runChild(req, deps) {
16340
16385
  if (pid !== 0) kill();
16341
16386
  decided.resolve();
16342
16387
  };
16343
- const controls = [];
16388
+ const controls2 = [];
16344
16389
  const capture = () => {
16345
16390
  const { promise, resolve: resolve2 } = Promise.withResolvers();
16346
16391
  const control = { shut: false, ended: resolve2, eof: promise };
16347
- controls.push(control);
16392
+ controls2.push(control);
16348
16393
  return { capture: true, max, overflow: () => stop("ENOBUFS"), control };
16349
16394
  };
16350
16395
  const decided = Promise.withResolvers();
@@ -16378,11 +16423,11 @@ async function runChild(req, deps) {
16378
16423
  let status;
16379
16424
  try {
16380
16425
  status = await reaped(deps, pid);
16381
- const open = controls.filter((c) => c.opened);
16426
+ const open = controls2.filter((c) => c.opened);
16382
16427
  await Promise.race([Promise.all(open.map((c) => c.eof)), decided.promise]);
16383
16428
  } finally {
16384
16429
  cancel?.();
16385
- for (const control of controls) control.shut = true;
16430
+ for (const control of controls2) control.shut = true;
16386
16431
  }
16387
16432
  const out = deps.children.captured(pid, 1);
16388
16433
  const err = deps.children.captured(pid, 2);
@@ -16964,6 +17009,47 @@ function encodeReceived(got) {
16964
17009
  return out;
16965
17010
  }
16966
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
+
16967
17053
  // src/kernel/net/tls-client.ts
16968
17054
  var WRITE_CHUNK = 16 * 1024;
16969
17055
  var BADCERT = [
@@ -16980,6 +17066,15 @@ function verifyCode(flags2) {
16980
17066
  if (flags2 === -1) return "UNABLE_TO_VERIFY_LEAF_SIGNATURE";
16981
17067
  return BADCERT.find(([bit]) => (flags2 & bit) !== 0)?.[1] ?? "UNABLE_TO_VERIFY_LEAF_SIGNATURE";
16982
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
+ }
16983
17078
  var Ciphertext = class {
16984
17079
  queue = [];
16985
17080
  ended = false;
@@ -17052,17 +17147,39 @@ async function handshake(conn, o, session, inbox) {
17052
17147
  }
17053
17148
  }
17054
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
+ }
17055
17161
  function infoOf(o, session) {
17056
17162
  const flags2 = session.verifyResult;
17057
17163
  const code = verifyCode(flags2);
17164
+ const protocol = session.version === 772 ? "TLSv1.3" : "TLSv1.2";
17058
17165
  return {
17059
- protocol: session.version === 772 ? "TLSv1.3" : "TLSv1.2",
17166
+ protocol,
17060
17167
  alpnProtocol: session.alpn ?? false,
17061
17168
  authorized: code === void 0,
17062
17169
  ...code ? { authorizationError: code, authorizationText: o.engine.verifyInfo(flags2).trim() } : {},
17063
- peerCertificates: session.peerChain()
17170
+ peerCertificates: session.peerChain(),
17171
+ ...controlsOf(o, session, protocol)
17064
17172
  };
17065
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
+ }
17066
17183
  function plaintext(conn, session, inbox) {
17067
17184
  let freed = false;
17068
17185
  let writeClosed = false;
@@ -17077,7 +17194,12 @@ function plaintext(conn, session, inbox) {
17077
17194
  async read() {
17078
17195
  for (; ; ) {
17079
17196
  if (freed) return null;
17080
- const got = session.read();
17197
+ let got;
17198
+ try {
17199
+ got = session.read();
17200
+ } catch (err) {
17201
+ throw alerted(err);
17202
+ }
17081
17203
  await send(conn, session);
17082
17204
  if (got instanceof Uint8Array) return got;
17083
17205
  if (got === "eof") return null;
@@ -17105,8 +17227,7 @@ function plaintext(conn, session, inbox) {
17105
17227
  };
17106
17228
  }
17107
17229
  async function tlsClient(conn, o, taken = new Uint8Array(0)) {
17108
- const flags2 = o.insecure ? TLS_CLIENT_INSECURE_SKIP_VERIFY : 0;
17109
- const session = o.engine.clientSession(o.store, o.servername, o.alpn, flags2);
17230
+ const session = o.session ?? openSession(o);
17110
17231
  const inbox = new Ciphertext(conn, session);
17111
17232
  inbox.hand(taken);
17112
17233
  try {
@@ -17119,10 +17240,10 @@ async function tlsClient(conn, o, taken = new Uint8Array(0)) {
17119
17240
  }
17120
17241
 
17121
17242
  // src/kernel/net/tls-uplink.ts
17122
- 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;
17123
17244
  var LABEL2 = /^(?!-)[A-Za-z0-9-]{1,63}(?<!-)$/;
17124
17245
  function serverName(name2) {
17125
- if (isIP(name2.replace(/^\[|\]$/g, ""))) return name2.replace(/^\[|\]$/g, "");
17246
+ if (isIP2(name2.replace(/^\[|\]$/g, ""))) return name2.replace(/^\[|\]$/g, "");
17126
17247
  const bare = name2.endsWith(".") ? name2.slice(0, -1) : name2;
17127
17248
  if (bare.length === 0 || bare.length > 253 || !bare.split(".").every((l) => LABEL2.test(l))) {
17128
17249
  throw new KernelError(
@@ -17172,9 +17293,66 @@ function sessionOf(info, servername) {
17172
17293
  authorizationText: info.authorizationText
17173
17294
  } : {},
17174
17295
  servername,
17175
- peerCertificates: info.peerCertificates.map(encode)
17296
+ peerCertificates: info.peerCertificates.map(encode),
17297
+ ...controls(info)
17176
17298
  };
17177
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
+ }
17178
17356
  async function setUp(support, req) {
17179
17357
  const engine = await support.engine();
17180
17358
  if (!engine.client)
@@ -17192,21 +17370,66 @@ async function setUp(support, req) {
17192
17370
  }
17193
17371
  return { engine, store: own, own };
17194
17372
  }
17195
- function secure(support, req, servername) {
17196
- return async (raw) => {
17197
- 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;
17198
17421
  try {
17199
- return await tlsClient(raw, {
17200
- engine,
17201
- store,
17202
- servername,
17203
- alpn: req.alpn ?? [],
17204
- insecure: req.insecure === true
17205
- });
17422
+ return await tlsClient(raw, prepared.options);
17206
17423
  } finally {
17207
- own?.release();
17424
+ prepared.own?.release();
17208
17425
  }
17209
17426
  };
17427
+ const abandon = () => {
17428
+ if (ran) return;
17429
+ prepared.options.session.free();
17430
+ prepared.own?.release();
17431
+ };
17432
+ return { make, abandon };
17210
17433
  }
17211
17434
  function supportOf(net) {
17212
17435
  const support = net.tlsClient;
@@ -17215,7 +17438,7 @@ function supportOf(net) {
17215
17438
  }
17216
17439
  async function uplinkAddress(proc, host) {
17217
17440
  const bare = host.replace(/^\[|\]$/g, "");
17218
- if (isIP(bare)) return bare;
17441
+ if (isIP2(bare)) return bare;
17219
17442
  const [first] = await proc.resolve(host, 0, () => proc.blocking());
17220
17443
  if (!first) throw new KernelError("ENOENT", `ENOTFOUND: ${host}`);
17221
17444
  return first;
@@ -17229,18 +17452,26 @@ async function connectSecure(proc, socket, host, port, req) {
17229
17452
  throw new KernelError("ENOTSUP", "TLS in the kernel needs a destination the uplink routes");
17230
17453
  const support = supportOf(proc.net);
17231
17454
  let info;
17232
- const make = secure(support, req, servername);
17233
- await socket.connectSecure({ family: "inet", host: address, port }, route, async (conn) => {
17234
- info = await conn.upgrade(make);
17235
- });
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
+ }
17236
17463
  return sessionOf(info, servername);
17237
17464
  }
17238
17465
  async function upgradeSecure(proc, socket, req) {
17239
17466
  const peer = socket.peer;
17240
17467
  const host = req.servername || (peer?.family === "inet" ? peer.host : "");
17241
17468
  const servername = serverName(host);
17242
- const info = await socket.upgradeSecure(secure(supportOf(proc.net), req, servername));
17243
- 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
+ }
17244
17475
  }
17245
17476
 
17246
17477
  // src/kernel/unix-dgram.ts
@@ -17602,17 +17833,23 @@ var NOT_HTTP_PORTS = /* @__PURE__ */ new Set([
17602
17833
  8883
17603
17834
  ]);
17604
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
+ }
17605
17839
  function wantsKernel(req) {
17606
17840
  if (req.path === "kernel") return true;
17607
17841
  if (req.path === "transport") return false;
17608
- 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);
17609
17843
  }
17610
17844
  async function secureConnect(req, proc) {
17611
17845
  if (!Number.isInteger(req.port) || req.port < 1 || req.port > 65535)
17612
17846
  throw new KernelError("EINVAL");
17613
17847
  const kernelPath = wantsKernel(req) && await uplinked(proc, req.host);
17614
17848
  if (!kernelPath) {
17615
- 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
+ }
17616
17853
  return { ...tlsOverTransport(req, proc), path: "transport", substitutes: true };
17617
17854
  }
17618
17855
  const socket = proc.net.socket("inet");
@@ -17746,13 +17983,17 @@ var VfsNode = class {
17746
17983
  const ranged2 = await this.prepare();
17747
17984
  await ranged2?.pin();
17748
17985
  }
17986
+ moving = /* @__PURE__ */ new Set();
17749
17987
  async load() {
17750
17988
  if (this.revoked) throw new KernelError("EIO");
17751
- if (!this.data) {
17989
+ while (!this.data) {
17990
+ const at = this.path;
17752
17991
  try {
17753
- this.data = await this.fs.readFileBuffer(this.path);
17992
+ this.data = await this.fs.readFileBuffer(at);
17754
17993
  } catch (err) {
17755
17994
  if (!isMissing(err)) throw err;
17995
+ while (this.moving.size > 0) await Promise.all(this.moving);
17996
+ if (this.path !== at) continue;
17756
17997
  this.data = new Uint8Array(0);
17757
17998
  this.missing = true;
17758
17999
  }
@@ -18106,6 +18347,16 @@ var VfsNodes = class {
18106
18347
  this.byPath.set(file.hidden, node);
18107
18348
  this.kept.set(node, file);
18108
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
+ }
18109
18360
  unkeep(path, file) {
18110
18361
  const node = this.byPath.get(file.hidden);
18111
18362
  if (!node) return;
@@ -21393,7 +21644,7 @@ function register(automaton, sources, ids, bytes, source) {
21393
21644
  }
21394
21645
  sources[id2].push(source);
21395
21646
  }
21396
- function prepare(secrets) {
21647
+ function prepare2(secrets) {
21397
21648
  const main = new Automaton();
21398
21649
  const wrap = new Automaton();
21399
21650
  const sources = [];
@@ -21544,7 +21795,7 @@ function merge(into, from) {
21544
21795
  }
21545
21796
  }
21546
21797
  function compile(secrets, options = {}) {
21547
- const c = prepare(secrets.map((secret) => ({ ...secret })));
21798
+ const c = prepare2(secrets.map((secret) => ({ ...secret })));
21548
21799
  const decoder4 = new TextDecoder();
21549
21800
  const idleMs = options.idleMs ?? 250;
21550
21801
  const scrubBytes = (input) => {
@@ -26549,7 +26800,7 @@ function cronLocks() {
26549
26800
  import { AsyncLocalStorage } from "node:async_hooks";
26550
26801
  import { subscribe } from "node:diagnostics_channel";
26551
26802
  import { lookup as lookup2 } from "node:dns/promises";
26552
- import { isIP as isIP2 } from "node:net";
26803
+ import { isIP as isIP3 } from "node:net";
26553
26804
  var DEVTOOLS_PORTS = [9222, 9223, 9224, 9225, 9226, 9227, 9228, 9229];
26554
26805
  var METADATA_V6 = [64768, 3778, 0, 0, 0, 0, 0, 596].join(":");
26555
26806
  var resolveHost = async (host) => (await lookup2(host, { all: true, verbatim: true })).map((a) => a.address);
@@ -26561,7 +26812,7 @@ function ipv4Place(address) {
26561
26812
  }
26562
26813
  function placeOf(address) {
26563
26814
  const plain2 = address.replace(/^\[(.*)\]$/, "$1").toLowerCase();
26564
- const kind = isIP2(plain2);
26815
+ const kind = isIP3(plain2);
26565
26816
  if (kind === 4) return ipv4Place(plain2);
26566
26817
  if (kind !== 6) return void 0;
26567
26818
  const words2 = hextets2(plain2);
@@ -26614,7 +26865,7 @@ function connectRefusal(address, port, place) {
26614
26865
  }
26615
26866
  async function addressesOf(host, resolve2) {
26616
26867
  const plain2 = host.replace(/^\[(.*)\]$/, "$1");
26617
- if (isIP2(plain2)) return [plain2];
26868
+ if (isIP3(plain2)) return [plain2];
26618
26869
  if (loopbackName2(plain2)) return ["127.0.0.1"];
26619
26870
  return resolve2(plain2).catch(() => []);
26620
26871
  }
@@ -26949,7 +27200,7 @@ function isMemoryRoot(handle) {
26949
27200
 
26950
27201
  // src/node/ws-diagnose.ts
26951
27202
  import { lookup as lookup3 } from "node:dns/promises";
26952
- import { isIP as isIP3, connect as tcp } from "node:net";
27203
+ import { isIP as isIP4, connect as tcp } from "node:net";
26953
27204
  import { connect as tls } from "node:tls";
26954
27205
  var PROBE_MS = 3e3;
26955
27206
  var PASSED = /* @__PURE__ */ new Set(["ECONNREFUSED", "EHOSTUNREACH", "ENETUNREACH", "ETIMEDOUT", "ECONNRESET"]);
@@ -26971,7 +27222,7 @@ function abortable(work, signal) {
26971
27222
  }
26972
27223
  function probe(secure2, host, port, ms, signal) {
26973
27224
  return new Promise((resolve2) => {
26974
- 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 });
26975
27226
  const stop = () => done4("ABORTED");
26976
27227
  const done4 = (code) => {
26977
27228
  clearTimeout(timer);