@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.
@@ -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.12" : "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: () => {
@@ -14773,6 +14783,8 @@ function realmCa(owner, store) {
14773
14783
 
14774
14784
  // src/kernel/net/tls-engine.ts
14775
14785
  var TLS_CLIENT_INSECURE_SKIP_VERIFY = 1;
14786
+ var TLS_CLIENT_NO_SNI = 2;
14787
+ var TLS_CLIENT_VERIFY_CHAIN_ONLY = 4;
14776
14788
  var SCRATCH = 64 * 1024;
14777
14789
  var EOF = -1;
14778
14790
  var TlsError = class extends Error {
@@ -14829,10 +14841,22 @@ var TlsEngine = class {
14829
14841
  this.m._free(ptr);
14830
14842
  }
14831
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
+ }
14832
14853
  intoScratch(fn) {
14833
14854
  const n = fn(this.scratch, SCRATCH);
14834
14855
  return n > 0 ? this.taken(n) : n;
14835
14856
  }
14857
+ get sessionControls() {
14858
+ return typeof this.m._tls_client_cert === "function";
14859
+ }
14836
14860
  get client() {
14837
14861
  return typeof this.m._tls_client_new === "function" ? this.m : void 0;
14838
14862
  }
@@ -14985,6 +15009,27 @@ var TlsSession = class {
14985
15009
  const out = this.engine.intoScratch((p, max) => this.c._tls_alpn(this.ptr, p, max));
14986
15010
  return out instanceof Uint8Array ? new TextDecoder().decode(out) : void 0;
14987
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
+ }
14988
15033
  peerChain() {
14989
15034
  const chain2 = [];
14990
15035
  const count2 = this.c._tls_peer_count(this.ptr);
@@ -16403,11 +16448,11 @@ async function runChild(req, deps) {
16403
16448
  if (pid !== 0) kill();
16404
16449
  decided.resolve();
16405
16450
  };
16406
- const controls = [];
16451
+ const controls2 = [];
16407
16452
  const capture = () => {
16408
16453
  const { promise, resolve: resolve2 } = Promise.withResolvers();
16409
16454
  const control = { shut: false, ended: resolve2, eof: promise };
16410
- controls.push(control);
16455
+ controls2.push(control);
16411
16456
  return { capture: true, max, overflow: () => stop("ENOBUFS"), control };
16412
16457
  };
16413
16458
  const decided = Promise.withResolvers();
@@ -16441,11 +16486,11 @@ async function runChild(req, deps) {
16441
16486
  let status;
16442
16487
  try {
16443
16488
  status = await reaped(deps, pid);
16444
- const open = controls.filter((c) => c.opened);
16489
+ const open = controls2.filter((c) => c.opened);
16445
16490
  await Promise.race([Promise.all(open.map((c) => c.eof)), decided.promise]);
16446
16491
  } finally {
16447
16492
  cancel?.();
16448
- for (const control of controls) control.shut = true;
16493
+ for (const control of controls2) control.shut = true;
16449
16494
  }
16450
16495
  const out = deps.children.captured(pid, 1);
16451
16496
  const err = deps.children.captured(pid, 2);
@@ -17027,6 +17072,47 @@ function encodeReceived(got) {
17027
17072
  return out;
17028
17073
  }
17029
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
+
17030
17116
  // src/kernel/net/tls-client.ts
17031
17117
  var WRITE_CHUNK = 16 * 1024;
17032
17118
  var BADCERT = [
@@ -17043,6 +17129,15 @@ function verifyCode(flags2) {
17043
17129
  if (flags2 === -1) return "UNABLE_TO_VERIFY_LEAF_SIGNATURE";
17044
17130
  return BADCERT.find(([bit]) => (flags2 & bit) !== 0)?.[1] ?? "UNABLE_TO_VERIFY_LEAF_SIGNATURE";
17045
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
+ }
17046
17141
  var Ciphertext = class {
17047
17142
  queue = [];
17048
17143
  ended = false;
@@ -17115,17 +17210,39 @@ async function handshake(conn, o, session, inbox) {
17115
17210
  }
17116
17211
  }
17117
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
+ }
17118
17224
  function infoOf(o, session) {
17119
17225
  const flags2 = session.verifyResult;
17120
17226
  const code = verifyCode(flags2);
17227
+ const protocol = session.version === 772 ? "TLSv1.3" : "TLSv1.2";
17121
17228
  return {
17122
- protocol: session.version === 772 ? "TLSv1.3" : "TLSv1.2",
17229
+ protocol,
17123
17230
  alpnProtocol: session.alpn ?? false,
17124
17231
  authorized: code === void 0,
17125
17232
  ...code ? { authorizationError: code, authorizationText: o.engine.verifyInfo(flags2).trim() } : {},
17126
- peerCertificates: session.peerChain()
17233
+ peerCertificates: session.peerChain(),
17234
+ ...controlsOf(o, session, protocol)
17127
17235
  };
17128
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
+ }
17129
17246
  function plaintext(conn, session, inbox) {
17130
17247
  let freed = false;
17131
17248
  let writeClosed = false;
@@ -17140,7 +17257,12 @@ function plaintext(conn, session, inbox) {
17140
17257
  async read() {
17141
17258
  for (; ; ) {
17142
17259
  if (freed) return null;
17143
- const got = session.read();
17260
+ let got;
17261
+ try {
17262
+ got = session.read();
17263
+ } catch (err) {
17264
+ throw alerted(err);
17265
+ }
17144
17266
  await send(conn, session);
17145
17267
  if (got instanceof Uint8Array) return got;
17146
17268
  if (got === "eof") return null;
@@ -17168,8 +17290,7 @@ function plaintext(conn, session, inbox) {
17168
17290
  };
17169
17291
  }
17170
17292
  async function tlsClient(conn, o, taken = new Uint8Array(0)) {
17171
- const flags2 = o.insecure ? TLS_CLIENT_INSECURE_SKIP_VERIFY : 0;
17172
- const session = o.engine.clientSession(o.store, o.servername, o.alpn, flags2);
17293
+ const session = o.session ?? openSession(o);
17173
17294
  const inbox = new Ciphertext(conn, session);
17174
17295
  inbox.hand(taken);
17175
17296
  try {
@@ -17182,10 +17303,10 @@ async function tlsClient(conn, o, taken = new Uint8Array(0)) {
17182
17303
  }
17183
17304
 
17184
17305
  // src/kernel/net/tls-uplink.ts
17185
- 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;
17186
17307
  var LABEL2 = /^(?!-)[A-Za-z0-9-]{1,63}(?<!-)$/;
17187
17308
  function serverName(name2) {
17188
- if (isIP(name2.replace(/^\[|\]$/g, ""))) return name2.replace(/^\[|\]$/g, "");
17309
+ if (isIP2(name2.replace(/^\[|\]$/g, ""))) return name2.replace(/^\[|\]$/g, "");
17189
17310
  const bare = name2.endsWith(".") ? name2.slice(0, -1) : name2;
17190
17311
  if (bare.length === 0 || bare.length > 253 || !bare.split(".").every((l) => LABEL2.test(l))) {
17191
17312
  throw new KernelError(
@@ -17235,9 +17356,66 @@ function sessionOf(info, servername) {
17235
17356
  authorizationText: info.authorizationText
17236
17357
  } : {},
17237
17358
  servername,
17238
- peerCertificates: info.peerCertificates.map(encode)
17359
+ peerCertificates: info.peerCertificates.map(encode),
17360
+ ...controls(info)
17239
17361
  };
17240
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
+ }
17241
17419
  async function setUp(support, req) {
17242
17420
  const engine = await support.engine();
17243
17421
  if (!engine.client)
@@ -17255,21 +17433,66 @@ async function setUp(support, req) {
17255
17433
  }
17256
17434
  return { engine, store: own, own };
17257
17435
  }
17258
- function secure(support, req, servername) {
17259
- return async (raw) => {
17260
- 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;
17261
17484
  try {
17262
- return await tlsClient(raw, {
17263
- engine,
17264
- store,
17265
- servername,
17266
- alpn: req.alpn ?? [],
17267
- insecure: req.insecure === true
17268
- });
17485
+ return await tlsClient(raw, prepared.options);
17269
17486
  } finally {
17270
- own?.release();
17487
+ prepared.own?.release();
17271
17488
  }
17272
17489
  };
17490
+ const abandon = () => {
17491
+ if (ran) return;
17492
+ prepared.options.session.free();
17493
+ prepared.own?.release();
17494
+ };
17495
+ return { make, abandon };
17273
17496
  }
17274
17497
  function supportOf(net) {
17275
17498
  const support = net.tlsClient;
@@ -17278,7 +17501,7 @@ function supportOf(net) {
17278
17501
  }
17279
17502
  async function uplinkAddress(proc, host) {
17280
17503
  const bare = host.replace(/^\[|\]$/g, "");
17281
- if (isIP(bare)) return bare;
17504
+ if (isIP2(bare)) return bare;
17282
17505
  const [first] = await proc.resolve(host, 0, () => proc.blocking());
17283
17506
  if (!first) throw new KernelError("ENOENT", `ENOTFOUND: ${host}`);
17284
17507
  return first;
@@ -17292,18 +17515,26 @@ async function connectSecure(proc, socket, host, port, req) {
17292
17515
  throw new KernelError("ENOTSUP", "TLS in the kernel needs a destination the uplink routes");
17293
17516
  const support = supportOf(proc.net);
17294
17517
  let info;
17295
- const make = secure(support, req, servername);
17296
- await socket.connectSecure({ family: "inet", host: address, port }, route, async (conn) => {
17297
- info = await conn.upgrade(make);
17298
- });
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
+ }
17299
17526
  return sessionOf(info, servername);
17300
17527
  }
17301
17528
  async function upgradeSecure(proc, socket, req) {
17302
17529
  const peer = socket.peer;
17303
17530
  const host = req.servername || (peer?.family === "inet" ? peer.host : "");
17304
17531
  const servername = serverName(host);
17305
- const info = await socket.upgradeSecure(secure(supportOf(proc.net), req, servername));
17306
- 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
+ }
17307
17538
  }
17308
17539
 
17309
17540
  // src/kernel/unix-dgram.ts
@@ -17665,17 +17896,23 @@ var NOT_HTTP_PORTS = /* @__PURE__ */ new Set([
17665
17896
  8883
17666
17897
  ]);
17667
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
+ }
17668
17902
  function wantsKernel(req) {
17669
17903
  if (req.path === "kernel") return true;
17670
17904
  if (req.path === "transport") return false;
17671
- 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);
17672
17906
  }
17673
17907
  async function secureConnect(req, proc) {
17674
17908
  if (!Number.isInteger(req.port) || req.port < 1 || req.port > 65535)
17675
17909
  throw new KernelError("EINVAL");
17676
17910
  const kernelPath = wantsKernel(req) && await uplinked(proc, req.host);
17677
17911
  if (!kernelPath) {
17678
- 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
+ }
17679
17916
  return { ...tlsOverTransport(req, proc), path: "transport", substitutes: true };
17680
17917
  }
17681
17918
  const socket = proc.net.socket("inet");
@@ -17809,13 +18046,17 @@ var VfsNode = class {
17809
18046
  const ranged2 = await this.prepare();
17810
18047
  await ranged2?.pin();
17811
18048
  }
18049
+ moving = /* @__PURE__ */ new Set();
17812
18050
  async load() {
17813
18051
  if (this.revoked) throw new KernelError("EIO");
17814
- if (!this.data) {
18052
+ while (!this.data) {
18053
+ const at = this.path;
17815
18054
  try {
17816
- this.data = await this.fs.readFileBuffer(this.path);
18055
+ this.data = await this.fs.readFileBuffer(at);
17817
18056
  } catch (err) {
17818
18057
  if (!isMissing(err)) throw err;
18058
+ while (this.moving.size > 0) await Promise.all(this.moving);
18059
+ if (this.path !== at) continue;
17819
18060
  this.data = new Uint8Array(0);
17820
18061
  this.missing = true;
17821
18062
  }
@@ -18169,6 +18410,16 @@ var VfsNodes = class {
18169
18410
  this.byPath.set(file.hidden, node);
18170
18411
  this.kept.set(node, file);
18171
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
+ }
18172
18423
  unkeep(path, file) {
18173
18424
  const node = this.byPath.get(file.hidden);
18174
18425
  if (!node) return;
@@ -21456,7 +21707,7 @@ function register(automaton, sources, ids, bytes, source) {
21456
21707
  }
21457
21708
  sources[id2].push(source);
21458
21709
  }
21459
- function prepare(secrets) {
21710
+ function prepare2(secrets) {
21460
21711
  const main = new Automaton();
21461
21712
  const wrap = new Automaton();
21462
21713
  const sources = [];
@@ -21607,7 +21858,7 @@ function merge(into, from) {
21607
21858
  }
21608
21859
  }
21609
21860
  function compile(secrets, options = {}) {
21610
- const c = prepare(secrets.map((secret) => ({ ...secret })));
21861
+ const c = prepare2(secrets.map((secret) => ({ ...secret })));
21611
21862
  const decoder4 = new TextDecoder();
21612
21863
  const idleMs = options.idleMs ?? 250;
21613
21864
  const scrubBytes = (input) => {