@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.
@@ -4655,8 +4655,8 @@ function uplinkLink(conn, onReset) {
4655
4655
  open = false;
4656
4656
  conn.close();
4657
4657
  };
4658
- void inbound(conn, rx).catch(() => {
4659
- onReset();
4658
+ void inbound(conn, rx).catch((err) => {
4659
+ onReset(err);
4660
4660
  close();
4661
4661
  tx.closeRead();
4662
4662
  }).finally(() => rx.closeWrite());
@@ -4747,7 +4747,7 @@ var KernelSocket = class _KernelSocket {
4747
4747
  state = "open";
4748
4748
  dialing;
4749
4749
  failed;
4750
- reset = false;
4750
+ reset;
4751
4751
  local;
4752
4752
  peer;
4753
4753
  peerCred;
@@ -4786,19 +4786,20 @@ var KernelSocket = class _KernelSocket {
4786
4786
  const { rx } = this.connection();
4787
4787
  if (this.readShut || max <= 0) return new Uint8Array(0);
4788
4788
  const bytes = await pipeCall(() => rx.read(max, signal));
4789
- if (bytes.length === 0 && this.reset) throw new KernelError("ECONNRESET");
4789
+ if (bytes.length === 0 && this.reset) throw this.reset;
4790
4790
  return bytes;
4791
4791
  }
4792
4792
  async peek(max, signal) {
4793
4793
  const { rx } = this.connection();
4794
4794
  if (this.readShut || max <= 0) return new Uint8Array(0);
4795
4795
  const bytes = await pipeCall(() => rx.peek(max, signal));
4796
- if (bytes.length === 0 && this.reset) throw new KernelError("ECONNRESET");
4796
+ if (bytes.length === 0 && this.reset) throw this.reset;
4797
4797
  return bytes;
4798
4798
  }
4799
4799
  async write(bytes, signal) {
4800
4800
  const { tx } = this.connection();
4801
4801
  if (this.writeShut) throw new KernelError("EPIPE");
4802
+ if (this.reset?.code === "EPROTO") throw this.reset;
4802
4803
  return pipeCall(() => tx.write(bytes, signal));
4803
4804
  }
4804
4805
  poll() {
@@ -4983,8 +4984,8 @@ var KernelSocket = class _KernelSocket {
4983
4984
  this.dialing = void 0;
4984
4985
  this.switch = conn;
4985
4986
  this.attach(
4986
- uplinkLink(conn, () => {
4987
- this.reset = true;
4987
+ uplinkLink(conn, (err) => {
4988
+ this.reset = err instanceof KernelError && err.code === "EPROTO" ? err : new KernelError("ECONNRESET");
4988
4989
  this.changes.wake();
4989
4990
  })
4990
4991
  );
@@ -6625,7 +6626,7 @@ function satisfies(version, range2) {
6625
6626
  }
6626
6627
 
6627
6628
  // src/version.ts
6628
- var KERNEL_VERSION = true ? "1.124.11" : "0.0.0-dev";
6629
+ var KERNEL_VERSION = true ? "1.124.13" : "0.0.0-dev";
6629
6630
  var OS_RELEASE = "6.0.0-slicc";
6630
6631
  function procVersion() {
6631
6632
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -7682,16 +7683,24 @@ var UnlinkedKeeper = class {
7682
7683
  gated();
7683
7684
  const held = /* @__PURE__ */ new Map();
7684
7685
  const hidden = /* @__PURE__ */ new Map();
7685
- for (; ; ) {
7686
- await take();
7687
- const now = this.heldWithin(target);
7688
- const next3 = paths.filter((path) => now.has(path) && !held.has(path));
7689
- if (next3.length === 0) break;
7690
- for (const path of next3) {
7691
- held.set(path, now.get(path));
7692
- const at = await this.hide(path);
7693
- if (at !== void 0) hidden.set(path, at);
7686
+ const moved2 = [];
7687
+ try {
7688
+ for (; ; ) {
7689
+ await take();
7690
+ const now = this.heldWithin(target);
7691
+ const next3 = paths.filter((path) => now.has(path) && !held.has(path));
7692
+ if (next3.length === 0) break;
7693
+ for (const path of next3) {
7694
+ const holders = now.get(path);
7695
+ held.set(path, holders);
7696
+ for (const holder of holders) moved2.push(holder.moving?.(path) ?? (() => void 0));
7697
+ const at = await this.hide(path);
7698
+ if (at !== void 0) hidden.set(path, at);
7699
+ }
7694
7700
  }
7701
+ } catch (err) {
7702
+ for (const settle3 of moved2) settle3();
7703
+ throw err;
7695
7704
  }
7696
7705
  sealed();
7697
7706
  const done4 = () => {
@@ -7704,6 +7713,7 @@ var UnlinkedKeeper = class {
7704
7713
  files.set(path, file);
7705
7714
  for (const holder of holders) holder.keep(path, file);
7706
7715
  }
7716
+ for (const settle3 of moved2) settle3();
7707
7717
  return {
7708
7718
  moved: new Set(hidden.keys()),
7709
7719
  commit: () => {
@@ -12394,6 +12404,10 @@ function attachSyncSabResponder(port, sab, token, opts) {
12394
12404
  Atomics.add(header3, SAB_I_PUB, 1);
12395
12405
  Atomics.notify(header3, SAB_I_PUB);
12396
12406
  if (offset + chunk2 >= entry.payload.byteLength) drop(id2);
12407
+ else if (entry.timer) {
12408
+ clearTimeout(entry.timer);
12409
+ entry.timer = setTimeout(() => drop(id2), PENDING_TTL_MS);
12410
+ }
12397
12411
  }
12398
12412
  function settle3(id2, result) {
12399
12413
  if (disposed) return;
@@ -14769,6 +14783,8 @@ function realmCa(owner, store) {
14769
14783
 
14770
14784
  // src/kernel/net/tls-engine.ts
14771
14785
  var TLS_CLIENT_INSECURE_SKIP_VERIFY = 1;
14786
+ var TLS_CLIENT_NO_SNI = 2;
14787
+ var TLS_CLIENT_VERIFY_CHAIN_ONLY = 4;
14772
14788
  var SCRATCH = 64 * 1024;
14773
14789
  var EOF = -1;
14774
14790
  var TlsError = class extends Error {
@@ -14825,10 +14841,22 @@ var TlsEngine = class {
14825
14841
  this.m._free(ptr);
14826
14842
  }
14827
14843
  }
14844
+ withSecret(bytes, fn) {
14845
+ const ptr = this.put(bytes);
14846
+ try {
14847
+ return fn(ptr);
14848
+ } finally {
14849
+ this.m.HEAPU8.fill(0, ptr, ptr + bytes.length + 1);
14850
+ this.m._free(ptr);
14851
+ }
14852
+ }
14828
14853
  intoScratch(fn) {
14829
14854
  const n = fn(this.scratch, SCRATCH);
14830
14855
  return n > 0 ? this.taken(n) : n;
14831
14856
  }
14857
+ get sessionControls() {
14858
+ return typeof this.m._tls_client_cert === "function";
14859
+ }
14832
14860
  get client() {
14833
14861
  return typeof this.m._tls_client_new === "function" ? this.m : void 0;
14834
14862
  }
@@ -14981,6 +15009,27 @@ var TlsSession = class {
14981
15009
  const out = this.engine.intoScratch((p, max) => this.c._tls_alpn(this.ptr, p, max));
14982
15010
  return out instanceof Uint8Array ? new TextDecoder().decode(out) : void 0;
14983
15011
  }
15012
+ ownCert(chain2, key, pass2) {
15013
+ const set3 = this.m._tls_client_cert;
15014
+ const keyLen = key[0] === 45 ? key.length + 1 : key.length;
15015
+ const ret = this.engine.withBytes(
15016
+ chain2,
15017
+ (c) => this.engine.withSecret(
15018
+ key,
15019
+ (k) => this.engine.withSecret(
15020
+ pass2,
15021
+ (p) => set3(this.ptr, c, chain2.length, k, keyLen, pass2.length > 0 ? p : 0, pass2.length)
15022
+ )
15023
+ )
15024
+ );
15025
+ if (ret !== 0) throw this.engine.error(ret, "client certificate");
15026
+ }
15027
+ get ciphersuite() {
15028
+ return this.m._tls_ciphersuite(this.ptr);
15029
+ }
15030
+ get nameMismatch() {
15031
+ return this.m._tls_name_mismatch(this.ptr) === 1;
15032
+ }
14984
15033
  peerChain() {
14985
15034
  const chain2 = [];
14986
15035
  const count2 = this.c._tls_peer_count(this.ptr);
@@ -16399,11 +16448,11 @@ async function runChild(req, deps) {
16399
16448
  if (pid !== 0) kill();
16400
16449
  decided.resolve();
16401
16450
  };
16402
- const controls = [];
16451
+ const controls2 = [];
16403
16452
  const capture = () => {
16404
16453
  const { promise, resolve: resolve2 } = Promise.withResolvers();
16405
16454
  const control = { shut: false, ended: resolve2, eof: promise };
16406
- controls.push(control);
16455
+ controls2.push(control);
16407
16456
  return { capture: true, max, overflow: () => stop("ENOBUFS"), control };
16408
16457
  };
16409
16458
  const decided = Promise.withResolvers();
@@ -16437,11 +16486,11 @@ async function runChild(req, deps) {
16437
16486
  let status;
16438
16487
  try {
16439
16488
  status = await reaped(deps, pid);
16440
- const open = controls.filter((c) => c.opened);
16489
+ const open = controls2.filter((c) => c.opened);
16441
16490
  await Promise.race([Promise.all(open.map((c) => c.eof)), decided.promise]);
16442
16491
  } finally {
16443
16492
  cancel?.();
16444
- for (const control of controls) control.shut = true;
16493
+ for (const control of controls2) control.shut = true;
16445
16494
  }
16446
16495
  const out = deps.children.captured(pid, 1);
16447
16496
  const err = deps.children.captured(pid, 2);
@@ -17023,6 +17072,47 @@ function encodeReceived(got) {
17023
17072
  return out;
17024
17073
  }
17025
17074
 
17075
+ // src/kernel/net/tls-ciphers.ts
17076
+ var SUITES = [
17077
+ [4865, "TLS_AES_128_GCM_SHA256", "TLS_AES_128_GCM_SHA256", "TLSv1.3"],
17078
+ [4866, "TLS_AES_256_GCM_SHA384", "TLS_AES_256_GCM_SHA384", "TLSv1.3"],
17079
+ [4867, "TLS_CHACHA20_POLY1305_SHA256", "TLS_CHACHA20_POLY1305_SHA256", "TLSv1.3"],
17080
+ [4868, "TLS_AES_128_CCM_SHA256", "TLS_AES_128_CCM_SHA256", "TLSv1.3"],
17081
+ [4869, "TLS_AES_128_CCM_8_SHA256", "TLS_AES_128_CCM_8_SHA256", "TLSv1.3"],
17082
+ [49195, "ECDHE-ECDSA-AES128-GCM-SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLSv1.2"],
17083
+ [49196, "ECDHE-ECDSA-AES256-GCM-SHA384", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLSv1.2"],
17084
+ [49199, "ECDHE-RSA-AES128-GCM-SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLSv1.2"],
17085
+ [49200, "ECDHE-RSA-AES256-GCM-SHA384", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLSv1.2"],
17086
+ [52392, "ECDHE-RSA-CHACHA20-POLY1305", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "TLSv1.2"],
17087
+ [
17088
+ 52393,
17089
+ "ECDHE-ECDSA-CHACHA20-POLY1305",
17090
+ "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
17091
+ "TLSv1.2"
17092
+ ],
17093
+ [49187, "ECDHE-ECDSA-AES128-SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "TLSv1.2"],
17094
+ [49188, "ECDHE-ECDSA-AES256-SHA384", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "TLSv1.2"],
17095
+ [49191, "ECDHE-RSA-AES128-SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "TLSv1.2"],
17096
+ [49192, "ECDHE-RSA-AES256-SHA384", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", "TLSv1.2"],
17097
+ [49161, "ECDHE-ECDSA-AES128-SHA", "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "TLSv1.0"],
17098
+ [49162, "ECDHE-ECDSA-AES256-SHA", "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "TLSv1.0"],
17099
+ [49171, "ECDHE-RSA-AES128-SHA", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "TLSv1.0"],
17100
+ [49172, "ECDHE-RSA-AES256-SHA", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "TLSv1.0"],
17101
+ [156, "AES128-GCM-SHA256", "TLS_RSA_WITH_AES_128_GCM_SHA256", "TLSv1.2"],
17102
+ [157, "AES256-GCM-SHA384", "TLS_RSA_WITH_AES_256_GCM_SHA384", "TLSv1.2"],
17103
+ [158, "DHE-RSA-AES128-GCM-SHA256", "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "TLSv1.2"],
17104
+ [159, "DHE-RSA-AES256-GCM-SHA384", "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "TLSv1.2"]
17105
+ ];
17106
+ function cipherOf(id2, protocol) {
17107
+ const known = SUITES.find(([n]) => n === id2);
17108
+ const hex3 = `0x${id2.toString(16).padStart(4, "0").toUpperCase()}`;
17109
+ return {
17110
+ name: known?.[1] ?? hex3,
17111
+ standardName: known?.[2] ?? hex3,
17112
+ version: known?.[3] ?? protocol
17113
+ };
17114
+ }
17115
+
17026
17116
  // src/kernel/net/tls-client.ts
17027
17117
  var WRITE_CHUNK = 16 * 1024;
17028
17118
  var BADCERT = [
@@ -17039,6 +17129,15 @@ function verifyCode(flags2) {
17039
17129
  if (flags2 === -1) return "UNABLE_TO_VERIFY_LEAF_SIGNATURE";
17040
17130
  return BADCERT.find(([bit]) => (flags2 & bit) !== 0)?.[1] ?? "UNABLE_TO_VERIFY_LEAF_SIGNATURE";
17041
17131
  }
17132
+ function isIP(name2) {
17133
+ return ipv4Bytes(name2) !== void 0 || name2.includes(":") && ipv6Groups(name2) !== void 0;
17134
+ }
17135
+ function clientFlags(o) {
17136
+ 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);
17137
+ }
17138
+ function openSession(o) {
17139
+ return o.engine.clientSession(o.store, o.servername, o.alpn, clientFlags(o));
17140
+ }
17042
17141
  var Ciphertext = class {
17043
17142
  queue = [];
17044
17143
  ended = false;
@@ -17111,17 +17210,39 @@ async function handshake(conn, o, session, inbox) {
17111
17210
  }
17112
17211
  }
17113
17212
  }
17213
+ function controlsOf(o, session, protocol) {
17214
+ if (!o.engine.sessionControls) return {};
17215
+ const checked = o.checkHostname !== false && !o.insecure;
17216
+ return {
17217
+ cipher: cipherOf(session.ciphersuite, protocol),
17218
+ clientCertificate: o.clientCertificate === true,
17219
+ sni: o.sni !== false && !isIP(o.servername),
17220
+ hostnameChecked: checked,
17221
+ ...o.insecure ? {} : { hostnameMatches: checked || !session.nameMismatch }
17222
+ };
17223
+ }
17114
17224
  function infoOf(o, session) {
17115
17225
  const flags2 = session.verifyResult;
17116
17226
  const code = verifyCode(flags2);
17227
+ const protocol = session.version === 772 ? "TLSv1.3" : "TLSv1.2";
17117
17228
  return {
17118
- protocol: session.version === 772 ? "TLSv1.3" : "TLSv1.2",
17229
+ protocol,
17119
17230
  alpnProtocol: session.alpn ?? false,
17120
17231
  authorized: code === void 0,
17121
17232
  ...code ? { authorizationError: code, authorizationText: o.engine.verifyInfo(flags2).trim() } : {},
17122
- peerCertificates: session.peerChain()
17233
+ peerCertificates: session.peerChain(),
17234
+ ...controlsOf(o, session, protocol)
17123
17235
  };
17124
17236
  }
17237
+ var FATAL_ALERT = -30592;
17238
+ function alerted(err) {
17239
+ if (err.code === FATAL_ALERT)
17240
+ return new KernelError(
17241
+ "EPROTO",
17242
+ `ERR_SSL_FATAL_ALERT: the server ended the session: ${err.message}`
17243
+ );
17244
+ return new KernelError("EPROTO", `ERR_SSL_PROTOCOL_ERROR: ${err.message}`);
17245
+ }
17125
17246
  function plaintext(conn, session, inbox) {
17126
17247
  let freed = false;
17127
17248
  let writeClosed = false;
@@ -17136,7 +17257,12 @@ function plaintext(conn, session, inbox) {
17136
17257
  async read() {
17137
17258
  for (; ; ) {
17138
17259
  if (freed) return null;
17139
- const got = session.read();
17260
+ let got;
17261
+ try {
17262
+ got = session.read();
17263
+ } catch (err) {
17264
+ throw alerted(err);
17265
+ }
17140
17266
  await send(conn, session);
17141
17267
  if (got instanceof Uint8Array) return got;
17142
17268
  if (got === "eof") return null;
@@ -17164,8 +17290,7 @@ function plaintext(conn, session, inbox) {
17164
17290
  };
17165
17291
  }
17166
17292
  async function tlsClient(conn, o, taken = new Uint8Array(0)) {
17167
- const flags2 = o.insecure ? TLS_CLIENT_INSECURE_SKIP_VERIFY : 0;
17168
- const session = o.engine.clientSession(o.store, o.servername, o.alpn, flags2);
17293
+ const session = o.session ?? openSession(o);
17169
17294
  const inbox = new Ciphertext(conn, session);
17170
17295
  inbox.hand(taken);
17171
17296
  try {
@@ -17178,10 +17303,10 @@ async function tlsClient(conn, o, taken = new Uint8Array(0)) {
17178
17303
  }
17179
17304
 
17180
17305
  // src/kernel/net/tls-uplink.ts
17181
- var isIP = (text) => ipv4Bytes(text) !== void 0 || text.includes(":") && ipv6Groups(text) !== void 0;
17306
+ var isIP2 = (text) => ipv4Bytes(text) !== void 0 || text.includes(":") && ipv6Groups(text) !== void 0;
17182
17307
  var LABEL2 = /^(?!-)[A-Za-z0-9-]{1,63}(?<!-)$/;
17183
17308
  function serverName(name2) {
17184
- if (isIP(name2.replace(/^\[|\]$/g, ""))) return name2.replace(/^\[|\]$/g, "");
17309
+ if (isIP2(name2.replace(/^\[|\]$/g, ""))) return name2.replace(/^\[|\]$/g, "");
17185
17310
  const bare = name2.endsWith(".") ? name2.slice(0, -1) : name2;
17186
17311
  if (bare.length === 0 || bare.length > 253 || !bare.split(".").every((l) => LABEL2.test(l))) {
17187
17312
  throw new KernelError(
@@ -17231,9 +17356,66 @@ function sessionOf(info, servername) {
17231
17356
  authorizationText: info.authorizationText
17232
17357
  } : {},
17233
17358
  servername,
17234
- peerCertificates: info.peerCertificates.map(encode)
17359
+ peerCertificates: info.peerCertificates.map(encode),
17360
+ ...controls(info)
17235
17361
  };
17236
17362
  }
17363
+ function controls(info) {
17364
+ if (!info.cipher) return {};
17365
+ return {
17366
+ cipher: info.cipher,
17367
+ clientCertificate: info.clientCertificate === true,
17368
+ sni: info.sni !== false,
17369
+ hostnameChecked: info.hostnameChecked === true,
17370
+ ...info.hostnameMatches === void 0 ? {} : { hostnameMatches: info.hostnameMatches }
17371
+ };
17372
+ }
17373
+ var KEY_ERRORS = [
17374
+ [-3, "ERR_OSSL_X509_KEY_VALUES_MISMATCH"],
17375
+ [-15232, "ERR_OSSL_BAD_DECRYPT"],
17376
+ [-15360, "ERR_OSSL_CRYPTO_INTERRUPTED_OR_CANCELLED"]
17377
+ ];
17378
+ function keyRefused(err) {
17379
+ const code = err instanceof TlsError ? err.code : 0;
17380
+ const name2 = KEY_ERRORS.find(([n]) => n === code)?.[1] ?? "ERR_OSSL_UNSUPPORTED";
17381
+ const text = code === -3 ? "the key does not match the certificate" : err.message;
17382
+ return new KernelError("EPROTO", `${name2}: ${text}`);
17383
+ }
17384
+ function takeCert(req) {
17385
+ const cert = req.clientCert;
17386
+ if (!cert) return void 0;
17387
+ delete req.clientCert;
17388
+ if (!Array.isArray(cert.chain) || cert.chain.length === 0 || typeof cert.key !== "string")
17389
+ throw new KernelError("EINVAL", "ERR_INVALID_ARG_VALUE: cert and key go together");
17390
+ let ders;
17391
+ let key;
17392
+ try {
17393
+ ders = cert.chain.map(base64Der);
17394
+ key = base64Der(cert.key);
17395
+ } catch {
17396
+ throw new KernelError("EINVAL", "ERR_INVALID_ARG_VALUE: cert or key is not base64");
17397
+ }
17398
+ const chain2 = new Uint8Array(ders.reduce((n, d) => n + d.length, 0));
17399
+ let at = 0;
17400
+ for (const der of ders) {
17401
+ chain2.set(der, at);
17402
+ at += der.length;
17403
+ }
17404
+ const pass2 = new TextEncoder().encode(cert.passphrase ?? "");
17405
+ return { chain: chain2, key, pass: pass2 };
17406
+ }
17407
+ function withCert(session, cert) {
17408
+ if (!cert) return;
17409
+ try {
17410
+ session.ownCert(cert.chain, cert.key, cert.pass);
17411
+ } catch (err) {
17412
+ throw keyRefused(err);
17413
+ }
17414
+ }
17415
+ function wipe(cert) {
17416
+ cert?.key.fill(0);
17417
+ cert?.pass.fill(0);
17418
+ }
17237
17419
  async function setUp(support, req) {
17238
17420
  const engine = await support.engine();
17239
17421
  if (!engine.client)
@@ -17251,21 +17433,66 @@ async function setUp(support, req) {
17251
17433
  }
17252
17434
  return { engine, store: own, own };
17253
17435
  }
17254
- function secure(support, req, servername) {
17255
- return async (raw) => {
17256
- const { engine, store, own } = await setUp(support, req);
17436
+ async function prepare(support, req, servername) {
17437
+ const cert = takeCert(req);
17438
+ try {
17439
+ return await prepareWith(support, req, servername, cert);
17440
+ } catch (err) {
17441
+ if (err instanceof KernelError) throw err;
17442
+ throw new KernelError("ENOTSUP", err instanceof Error ? err.message : String(err));
17443
+ } finally {
17444
+ wipe(cert);
17445
+ }
17446
+ }
17447
+ async function prepareWith(support, req, servername, cert) {
17448
+ if (req.checkHostname === false && req.insecure === true) {
17449
+ throw new KernelError(
17450
+ "EINVAL",
17451
+ "ERR_INVALID_ARG_VALUE: checkHostname: false needs rejectUnauthorized"
17452
+ );
17453
+ }
17454
+ const { engine, store, own } = await setUp(support, req);
17455
+ const options = {
17456
+ engine,
17457
+ store,
17458
+ servername,
17459
+ alpn: req.alpn ?? [],
17460
+ insecure: req.insecure === true,
17461
+ ...req.sni === false ? { sni: false } : {},
17462
+ ...req.checkHostname === false ? { checkHostname: false } : {},
17463
+ clientCertificate: cert !== void 0
17464
+ };
17465
+ let session;
17466
+ try {
17467
+ const controls2 = req.sni === false || req.checkHostname === false || cert !== void 0;
17468
+ if (controls2 && !engine.sessionControls) {
17469
+ throw new KernelError("ENOTSUP", "the installed tls engine has no client certificates");
17470
+ }
17471
+ session = openSession(options);
17472
+ withCert(session, cert);
17473
+ return { options: { ...options, session }, own };
17474
+ } catch (err) {
17475
+ session?.free();
17476
+ own?.release();
17477
+ throw err;
17478
+ }
17479
+ }
17480
+ function secure(prepared) {
17481
+ let ran = false;
17482
+ const make = async (raw) => {
17483
+ ran = true;
17257
17484
  try {
17258
- return await tlsClient(raw, {
17259
- engine,
17260
- store,
17261
- servername,
17262
- alpn: req.alpn ?? [],
17263
- insecure: req.insecure === true
17264
- });
17485
+ return await tlsClient(raw, prepared.options);
17265
17486
  } finally {
17266
- own?.release();
17487
+ prepared.own?.release();
17267
17488
  }
17268
17489
  };
17490
+ const abandon = () => {
17491
+ if (ran) return;
17492
+ prepared.options.session.free();
17493
+ prepared.own?.release();
17494
+ };
17495
+ return { make, abandon };
17269
17496
  }
17270
17497
  function supportOf(net) {
17271
17498
  const support = net.tlsClient;
@@ -17274,7 +17501,7 @@ function supportOf(net) {
17274
17501
  }
17275
17502
  async function uplinkAddress(proc, host) {
17276
17503
  const bare = host.replace(/^\[|\]$/g, "");
17277
- if (isIP(bare)) return bare;
17504
+ if (isIP2(bare)) return bare;
17278
17505
  const [first] = await proc.resolve(host, 0, () => proc.blocking());
17279
17506
  if (!first) throw new KernelError("ENOENT", `ENOTFOUND: ${host}`);
17280
17507
  return first;
@@ -17288,18 +17515,26 @@ async function connectSecure(proc, socket, host, port, req) {
17288
17515
  throw new KernelError("ENOTSUP", "TLS in the kernel needs a destination the uplink routes");
17289
17516
  const support = supportOf(proc.net);
17290
17517
  let info;
17291
- const make = secure(support, req, servername);
17292
- await socket.connectSecure({ family: "inet", host: address, port }, route, async (conn) => {
17293
- info = await conn.upgrade(make);
17294
- });
17518
+ const { make, abandon } = secure(await prepare(support, req, servername));
17519
+ try {
17520
+ await socket.connectSecure({ family: "inet", host: address, port }, route, async (conn) => {
17521
+ info = await conn.upgrade(make);
17522
+ });
17523
+ } finally {
17524
+ abandon();
17525
+ }
17295
17526
  return sessionOf(info, servername);
17296
17527
  }
17297
17528
  async function upgradeSecure(proc, socket, req) {
17298
17529
  const peer = socket.peer;
17299
17530
  const host = req.servername || (peer?.family === "inet" ? peer.host : "");
17300
17531
  const servername = serverName(host);
17301
- const info = await socket.upgradeSecure(secure(supportOf(proc.net), req, servername));
17302
- return sessionOf(info, servername);
17532
+ const { make, abandon } = secure(await prepare(supportOf(proc.net), req, servername));
17533
+ try {
17534
+ return sessionOf(await socket.upgradeSecure(make), servername);
17535
+ } finally {
17536
+ abandon();
17537
+ }
17303
17538
  }
17304
17539
 
17305
17540
  // src/kernel/unix-dgram.ts
@@ -17661,17 +17896,23 @@ var NOT_HTTP_PORTS = /* @__PURE__ */ new Set([
17661
17896
  8883
17662
17897
  ]);
17663
17898
  var HOST_NAME = /^[A-Za-z0-9.-]+$|^\[?[0-9A-Fa-f:.]+\]?$/;
17899
+ function sessionControls(req) {
17900
+ return req.sni === false || req.checkHostname === false || req.clientCert !== void 0;
17901
+ }
17664
17902
  function wantsKernel(req) {
17665
17903
  if (req.path === "kernel") return true;
17666
17904
  if (req.path === "transport") return false;
17667
- 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);
17905
+ 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);
17668
17906
  }
17669
17907
  async function secureConnect(req, proc) {
17670
17908
  if (!Number.isInteger(req.port) || req.port < 1 || req.port > 65535)
17671
17909
  throw new KernelError("EINVAL");
17672
17910
  const kernelPath = wantsKernel(req) && await uplinked(proc, req.host);
17673
17911
  if (!kernelPath) {
17674
- if (req.path === "kernel" || Array.isArray(req.ca)) throw new KernelError("ENOTSUP");
17912
+ if (req.path === "kernel" || Array.isArray(req.ca) || sessionControls(req)) {
17913
+ delete req.clientCert;
17914
+ throw new KernelError("ENOTSUP");
17915
+ }
17675
17916
  return { ...tlsOverTransport(req, proc), path: "transport", substitutes: true };
17676
17917
  }
17677
17918
  const socket = proc.net.socket("inet");
@@ -17805,13 +18046,17 @@ var VfsNode = class {
17805
18046
  const ranged2 = await this.prepare();
17806
18047
  await ranged2?.pin();
17807
18048
  }
18049
+ moving = /* @__PURE__ */ new Set();
17808
18050
  async load() {
17809
18051
  if (this.revoked) throw new KernelError("EIO");
17810
- if (!this.data) {
18052
+ while (!this.data) {
18053
+ const at = this.path;
17811
18054
  try {
17812
- this.data = await this.fs.readFileBuffer(this.path);
18055
+ this.data = await this.fs.readFileBuffer(at);
17813
18056
  } catch (err) {
17814
18057
  if (!isMissing(err)) throw err;
18058
+ while (this.moving.size > 0) await Promise.all(this.moving);
18059
+ if (this.path !== at) continue;
17815
18060
  this.data = new Uint8Array(0);
17816
18061
  this.missing = true;
17817
18062
  }
@@ -18165,6 +18410,16 @@ var VfsNodes = class {
18165
18410
  this.byPath.set(file.hidden, node);
18166
18411
  this.kept.set(node, file);
18167
18412
  }
18413
+ moving(path) {
18414
+ const node = this.byPath.get(path);
18415
+ if (!node) return () => void 0;
18416
+ const { promise, resolve: resolve2 } = Promise.withResolvers();
18417
+ node.moving.add(promise);
18418
+ return () => {
18419
+ node.moving.delete(promise);
18420
+ resolve2();
18421
+ };
18422
+ }
18168
18423
  unkeep(path, file) {
18169
18424
  const node = this.byPath.get(file.hidden);
18170
18425
  if (!node) return;
@@ -21452,7 +21707,7 @@ function register(automaton, sources, ids, bytes, source) {
21452
21707
  }
21453
21708
  sources[id2].push(source);
21454
21709
  }
21455
- function prepare(secrets) {
21710
+ function prepare2(secrets) {
21456
21711
  const main = new Automaton();
21457
21712
  const wrap = new Automaton();
21458
21713
  const sources = [];
@@ -21603,7 +21858,7 @@ function merge(into, from) {
21603
21858
  }
21604
21859
  }
21605
21860
  function compile(secrets, options = {}) {
21606
- const c = prepare(secrets.map((secret) => ({ ...secret })));
21861
+ const c = prepare2(secrets.map((secret) => ({ ...secret })));
21607
21862
  const decoder4 = new TextDecoder();
21608
21863
  const idleMs = options.idleMs ?? 250;
21609
21864
  const scrubBytes = (input) => {