@ai-ecoverse/slicc-kernel 1.133.5 → 1.134.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -504,7 +504,13 @@ The module's default export (or its `main` export) is called with a context and
504
504
  - `AUTH PLAIN <blob>`, or the line after a bare `AUTH PLAIN`: the kernel decodes the blob, and asks the vault (`auth-plain`) only when the placeholders are in the **password field**. A placeholder in the user or authorization identity goes out as written. It substitutes there and re-encodes.
505
505
  - `AUTH LOGIN`: the password line (the second line, or the first after `AUTH LOGIN <user>`) is decoded, substituted (`auth-login`) and re-encoded; the user line goes out as written.
506
506
  - Every other line goes out as written. After the first `AUTH`, or once `MAIL`, `RCPT`, `DATA` or `BDAT` is seen, so is the rest of the session. A line still unfinished after 2 s, or longer than 4 KiB, is sent as written, and so is the rest.
507
- - **pg:** a session that starts with a protocol 3 `StartupMessage` (after `sslmode`'s `SSLRequest` upgrade, or with direct TLS) is followed message by message. The only position is the **`PasswordMessage` answering `AuthenticationCleartextPassword` (`R` 3)**, as the program read it from the server. The password is substituted (`password-cleartext`) and the message is framed again. Anything else goes out as written: the startup, an MD5 (`R` 5) or SCRAM (`R` 10) answer, every later message, and a frame over 16 KiB. MD5 and SCRAM need the kernel to compute the answer from the password, so they aren't supported yet. A server whose `pg_hba` asks for them gets the placeholder, and refuses.
507
+ - **pg:** a session that starts with a protocol 3 `StartupMessage` (after `sslmode`'s `SSLRequest` upgrade, or with direct TLS) is followed message by message. The only position is the **`PasswordMessage` answering `AuthenticationCleartextPassword` (`R` 3)**, as the program read it from the server. The password is substituted (`password-cleartext`) and the message is framed again. **SCRAM-SHA-256** (`R` 10, the pg 14+ default) works with an unmodified client:
508
+ - **What the server is offered:** in a session that can substitute, the kernel offers the program only `SCRAM-SHA-256`, never `-PLUS`. The program's client computes its proof from the placeholder. Dropping `-PLUS` costs nothing here: the kernel terminates and verifies the TLS itself, so channel binding would only bind to the kernel's own session. A client that **requires** channel binding (libpq's `channel_binding=require`) refuses the connection and never gets the value, so leave it at `prefer` or `disable` for sealed SCRAM.
509
+ - **The match:** the kernel sends the three SCRAM messages and that proof to the vault (`scram-sha-256`, with no placeholders), and the vault names the one bound placeholder whose proof matches.
510
+ - **The exchange:** the kernel recomputes the proof from the value and sends that instead. It checks the server's final signature against the value **before** it hands the program the signature its own placeholder-based check expects. A server whose signature doesn't verify, or that answers with an error, ends the session (`EPROTO`) without passing it on. The salted password and the derived keys are wiped after the exchange.
511
+ - **Requirements:** only the plain GS2 header (`n,,`) and the bare RFC 5802 messages; at most 100000 iterations.
512
+
513
+ Anything else goes out as written: the startup, an MD5 (`R` 5) answer, every later message, and a frame over 16 KiB. A server whose `pg_hba` asks for MD5 gets the placeholder, and refuses.
508
514
  - **What goes out:** the placeholders the vault answers with a value of at least 8 bytes go out as that value (`Basic` decoded, substituted and re-encoded). Everything else goes out as written:
509
515
  - the request line and the body;
510
516
  - other headers;
@@ -1245,7 +1251,7 @@ The tools in `tools/cert-review/`:
1245
1251
  - **FAIL:** a regression, or a failing test (by the counts, even without its rows) is **not certified**, and the group is red;
1246
1252
  - **INCOMPLETE** blocks too: no result, a result from another bios than the pinned one, a missing shard, a shard that exited without a failing test, a refused candidate, 0 tests run, or no test passed;
1247
1253
  - **not judged:** every failing test fails on `main`'s own pins too (`both`), so the canary is broken on `main`, not by this group. That passes with a note, as do `both` rows next to a pass. Either way, `pr notice` opens one issue, `downstream: bios canary failing on main (<bios sha>)`, or comments on the open one, and the next group that passes closes it. Flaky rows are advisory.
1248
- - **`downstream-override`**, next to `cert-review-approved`: a coordinator-only label that waives a downstream FAIL. It is head-bound by the same self-guard (`cert-self-guard` with `approval-label: downstream-override` and every path, dot paths included), so a push drops it. It applies only when **every** pull request in the group carries it on the head being merged: the group reads the guard's receipt and waives only when each member was checked and approved, so a pull request whose paths the guard's globs miss gets no waiver. The group's line then reads `downstream: overridden (downstream-override on the head, by the coordinator) …`, with the failure it waived. It never covers INCOMPLETE. A pull request's own certification line ends `downstream: merge group`, since its downstream verdict comes in the group.
1254
+ - **No downstream waiver.** A downstream FAIL or INCOMPLETE in the merge group is not certified; fix the regression or bios's side first (the coordinator-only `downstream-override` label was removed with the 2026-10-19 cert model). A pull request's own certification line ends `downstream: merge group`, since its downstream verdict comes in the group.
1249
1255
 
1250
1256
  Not part of the run yet: the rest of bios's setup (the `rest` shard, the upgrade boot, the sudo rows under `enforce`). More shards plug in through the canary call's `shards`.
1251
1257
 
@@ -2570,15 +2570,21 @@ var OpfsFs = class {
2570
2570
  let writable2;
2571
2571
  let handle;
2572
2572
  try {
2573
- const [made2, existed, at] = await this.fileFor(destination);
2574
- handle = made2;
2575
- target = at;
2576
- if (!existed && !created4) {
2577
- created4 = true;
2578
- await this.stampNew(target, options.owner, false);
2573
+ const kept = created4 ? this.files.get(destination) : void 0;
2574
+ if (kept) {
2575
+ if (options.owner?.fifo || options.owner?.socket) throw fsError("ENXIO", to);
2576
+ handle = kept;
2577
+ } else {
2578
+ const [made2, existed, at] = await this.fileFor(destination);
2579
+ handle = made2;
2580
+ target = at;
2581
+ if (!existed && !created4) {
2582
+ created4 = true;
2583
+ await this.stampNew(target, options.owner, false);
2584
+ }
2585
+ const [entry] = await this.meta.get([target]);
2586
+ if (entry?.fifo || entry?.socket) throw fsError("ENXIO", to);
2579
2587
  }
2580
- const [entry] = await this.meta.get([target]);
2581
- if (entry?.fifo || entry?.socket) throw fsError("ENXIO", to);
2582
2588
  this.wrote(handle);
2583
2589
  writable2 = await handle.createWritable();
2584
2590
  await writable2.write(file);
@@ -7095,7 +7101,7 @@ function satisfies(version, range2) {
7095
7101
  }
7096
7102
 
7097
7103
  // src/version.ts
7098
- var KERNEL_VERSION = true ? "1.133.5" : "0.0.0-dev";
7104
+ var KERNEL_VERSION = true ? "1.134.1" : "0.0.0-dev";
7099
7105
  var OS_RELEASE = "6.0.0-slicc";
7100
7106
  function procVersion() {
7101
7107
  return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
@@ -14158,8 +14164,8 @@ var EventFd = class _EventFd {
14158
14164
  count;
14159
14165
  semaphore;
14160
14166
  changes = new Notifier();
14161
- constructor(initial, semaphore) {
14162
- this.count = initial;
14167
+ constructor(initial2, semaphore) {
14168
+ this.count = initial2;
14163
14169
  this.semaphore = semaphore;
14164
14170
  }
14165
14171
  async read(max, signal) {
@@ -17908,7 +17914,7 @@ var UNSAFE = /[\r\n\0]/;
17908
17914
  var POSITIONS = {
17909
17915
  http1: (position) => HEADER.test(position),
17910
17916
  smtp: (position) => position === "auth-plain" || position === "auth-login",
17911
- pg: (position) => position === "password-cleartext"
17917
+ pg: (position) => position === "password-cleartext" || position === "scram-sha-256"
17912
17918
  };
17913
17919
  function boundHost(servername) {
17914
17920
  const lower = servername.toLowerCase();
@@ -17923,6 +17929,15 @@ function placeholdersOk(list) {
17923
17929
  if (!Array.isArray(list) || list.length === 0 || list.length > SESSION_PLACEHOLDERS) return false;
17924
17930
  return new Set(list).size === list.length && list.every((p) => typeof p === "string" && SESSION_PLACEHOLDER.test(p));
17925
17931
  }
17932
+ var SCRAM_TEXT = /^[\x21-\x7e]{1,1024}$/;
17933
+ function scramOk(f) {
17934
+ if (f.position !== "scram-sha-256")
17935
+ return f.scram === void 0 && placeholdersOk(f.placeholders);
17936
+ const x = f.scram;
17937
+ if (f.placeholders !== void 0 || typeof x !== "object" || x === null) return false;
17938
+ const texts = [x.clientFirstBare, x.serverFirst, x.clientFinalBare, x.proof];
17939
+ return texts.every((t) => typeof t === "string" && SCRAM_TEXT.test(t));
17940
+ }
17926
17941
  function hostOk(host) {
17927
17942
  return typeof host === "string" && HOST.test(host) && boundHost(host) === host;
17928
17943
  }
@@ -17934,7 +17949,7 @@ function sessionAskable(f, now) {
17934
17949
  if (!Number.isInteger(f.port) || f.port < 1 || f.port > 65535) return false;
17935
17950
  const age = now - f.handshakeAt;
17936
17951
  if (!Number.isFinite(age) || age < 0 || age > SESSION_WINDOW_MS) return false;
17937
- return typeof f.exit === "string" && SESSION_EXIT.test(f.exit) && placeholdersOk(f.placeholders) && headOk(f);
17952
+ return typeof f.exit === "string" && SESSION_EXIT.test(f.exit) && scramOk(f) && headOk(f);
17938
17953
  }
17939
17954
  function sessionRequest(f) {
17940
17955
  return {
@@ -17950,8 +17965,16 @@ function sessionRequest(f) {
17950
17965
  verified: true,
17951
17966
  handshakeAt: f.handshakeAt,
17952
17967
  exit: f.exit,
17953
- placeholders: [...f.placeholders],
17954
- ...f.head ? { head: { method: f.head.method, path: f.head.path } } : {}
17968
+ ...f.placeholders ? { placeholders: [...f.placeholders] } : {},
17969
+ ...f.head ? { head: { method: f.head.method, path: f.head.path } } : {},
17970
+ ...f.scram ? {
17971
+ scram: {
17972
+ clientFirstBare: f.scram.clientFirstBare,
17973
+ serverFirst: f.scram.serverFirst,
17974
+ clientFinalBare: f.scram.clientFinalBare,
17975
+ proof: f.scram.proof
17976
+ }
17977
+ } : {}
17955
17978
  };
17956
17979
  }
17957
17980
  function sessionValues(reply, asked) {
@@ -17959,7 +17982,9 @@ function sessionValues(reply, asked) {
17959
17982
  const { error, values } = reply;
17960
17983
  if (error !== void 0 || typeof values !== "object" || values === null) return void 0;
17961
17984
  const out = {};
17962
- for (const ph of asked) {
17985
+ const keys = Object.keys(values);
17986
+ const wanted = asked ?? (keys.length === 1 && SESSION_PLACEHOLDER.test(keys[0]) ? keys : []);
17987
+ for (const ph of wanted) {
17963
17988
  const value2 = values[ph];
17964
17989
  if (typeof value2 === "string" && value2.length > 0 && !UNSAFE.test(value2)) out[ph] = value2;
17965
17990
  }
@@ -18651,6 +18676,104 @@ async function substituteHead(head, ask) {
18651
18676
  `, values };
18652
18677
  }
18653
18678
 
18679
+ // src/kernel/net/sealed-scram.ts
18680
+ var encoder8 = new TextEncoder();
18681
+ function base64Bytes(text) {
18682
+ try {
18683
+ return Uint8Array.from(atob(text), (c) => c.charCodeAt(0));
18684
+ } catch {
18685
+ return void 0;
18686
+ }
18687
+ }
18688
+ function base64Of(bytes) {
18689
+ let bin = "";
18690
+ for (const b of bytes) bin += String.fromCharCode(b);
18691
+ return btoa(bin);
18692
+ }
18693
+ function clientFirstBare(message3) {
18694
+ const m = /^n,,(n=[^,]*,r=[^,]+)$/.exec(message3);
18695
+ return m ? m[1] : void 0;
18696
+ }
18697
+ var SERVER_FIRST = /^r=([^,]+),s=([^,]+),i=(\d{1,6})$/;
18698
+ var CLIENT_FINAL = /^(c=biws,r=([^,]+)),p=([^,]+)$/;
18699
+ var SCRAM_MAX = 1024;
18700
+ function exchangeOf(clientFirst, serverFirst, clientFinal) {
18701
+ const bare = clientFirstBare(clientFirst);
18702
+ const sf = SERVER_FIRST.exec(serverFirst);
18703
+ const fin = CLIENT_FINAL.exec(clientFinal);
18704
+ if (!bare || !sf || !fin || [bare, serverFirst, clientFinal].some((t) => t.length > SCRAM_MAX))
18705
+ return void 0;
18706
+ const cnonce = bare.slice(bare.indexOf(",r=") + 3);
18707
+ const nonce = sf[1];
18708
+ const salt = base64Bytes(sf[2]);
18709
+ const iterations = Number(sf[3]);
18710
+ const proof = base64Bytes(fin[3]);
18711
+ const ok4 = fin[2] === nonce && nonce.startsWith(cnonce) && iterations >= 1 && iterations <= 1e5 && salt !== void 0 && proof?.length === 32;
18712
+ if (!ok4) return void 0;
18713
+ return {
18714
+ exchange: {
18715
+ clientFirstBare: bare,
18716
+ serverFirst,
18717
+ clientFinalBare: fin[1],
18718
+ salt,
18719
+ iterations
18720
+ },
18721
+ proof
18722
+ };
18723
+ }
18724
+ async function hmac(key, data) {
18725
+ const k = await crypto.subtle.importKey(
18726
+ "raw",
18727
+ key,
18728
+ { name: "HMAC", hash: "SHA-256" },
18729
+ false,
18730
+ ["sign"]
18731
+ );
18732
+ return new Uint8Array(await crypto.subtle.sign("HMAC", k, data));
18733
+ }
18734
+ async function scramKeys(password, x) {
18735
+ const base = await crypto.subtle.importKey("raw", encoder8.encode(password), "PBKDF2", false, [
18736
+ "deriveBits"
18737
+ ]);
18738
+ const salted = new Uint8Array(
18739
+ await crypto.subtle.deriveBits(
18740
+ {
18741
+ name: "PBKDF2",
18742
+ hash: "SHA-256",
18743
+ salt: x.salt,
18744
+ iterations: x.iterations
18745
+ },
18746
+ base,
18747
+ 256
18748
+ )
18749
+ );
18750
+ const clientKey = await hmac(salted, encoder8.encode("Client Key"));
18751
+ const stored = new Uint8Array(
18752
+ await crypto.subtle.digest("SHA-256", clientKey)
18753
+ );
18754
+ const auth = encoder8.encode(`${x.clientFirstBare},${x.serverFirst},${x.clientFinalBare}`);
18755
+ const signature = await hmac(stored, auth);
18756
+ const proof = clientKey.map((b, i) => b ^ signature[i]);
18757
+ const serverKey = await hmac(salted, encoder8.encode("Server Key"));
18758
+ const serverSignature = await hmac(serverKey, auth);
18759
+ for (const k of [salted, clientKey, stored, signature, serverKey]) k.fill(0);
18760
+ return { proof, serverSignature };
18761
+ }
18762
+ var SPACES = /[\u00A0\u1680\u2000-\u200B\u202F\u205F\u3000]/g;
18763
+ var NOTHING2 = /\u00AD|\u034F|\u1806|[\u180B-\u180D]|\u200C|\u200D|\u2060|[\uFE00-\uFE0F]|\uFEFF/g;
18764
+ var PROHIBITED = /[\u0000-\u001F\u007F-\u009F\uE000-\uF8FF\uFFFE\uFFFF]/;
18765
+ function saslprep(password) {
18766
+ if (/^[\x20-\x7e]*$/.test(password)) return password;
18767
+ const mapped = password.replace(SPACES, " ").replace(NOTHING2, "").normalize("NFKC");
18768
+ return PROHIBITED.test(mapped) ? password : mapped;
18769
+ }
18770
+ function sameBytes(a, b) {
18771
+ if (a.length !== b.length) return false;
18772
+ let d = 0;
18773
+ for (let i = 0; i < a.length; i++) d |= a[i] ^ b[i];
18774
+ return d === 0;
18775
+ }
18776
+
18654
18777
  // src/kernel/net/sealed-pg.ts
18655
18778
  var PG_MESSAGE_MAX = 16 * 1024;
18656
18779
  var PROTOCOL_3 = 196608;
@@ -18665,44 +18788,101 @@ function sniffPg(start2) {
18665
18788
  const length2 = int32(bytes, 0);
18666
18789
  return length2 >= 8 && length2 <= PG_MESSAGE_MAX && int32(bytes, 4) === PROTOCOL_3 ? "yes" : "no";
18667
18790
  }
18791
+ var PLUS = "SCRAM-SHA-256-PLUS";
18792
+ var SASL = 10;
18793
+ var SASL_CONTINUE = 11;
18794
+ var SASL_FINAL = 12;
18795
+ function latin(bytes) {
18796
+ let out = "";
18797
+ for (const b of bytes) out += String.fromCharCode(b);
18798
+ return out;
18799
+ }
18668
18800
  var PgServer = class {
18669
18801
  buffer = new Uint8Array(0);
18670
18802
  skip = 0;
18671
- lost = false;
18672
18803
  cleartext = false;
18673
- feed(bytes) {
18674
- if (this.lost) return;
18804
+ sasl = false;
18805
+ serverFirst;
18806
+ expect;
18807
+ failed = false;
18808
+ lost = false;
18809
+ auth(message3) {
18810
+ const code = message3.length >= 9 ? int32(message3, 5) : -1;
18811
+ if (this.expect && code !== SASL_FINAL) this.failed = true;
18812
+ this.cleartext = message3.length === 9 && code === CLEARTEXT;
18813
+ if (code === SASL) return this.mechanisms(message3);
18814
+ else if (code === SASL_CONTINUE) this.serverFirst = latin(message3.subarray(9));
18815
+ else if (code === SASL_FINAL) this.final(message3);
18816
+ return message3;
18817
+ }
18818
+ mechanisms(message3) {
18819
+ this.sasl = true;
18820
+ const names2 = latin(message3.subarray(9)).split("\0").filter((n) => n !== "" && n !== PLUS);
18821
+ return frame3(82, `${latin(message3.subarray(5, 9))}${names2.map((n) => `${n}\0`).join("")}\0`);
18822
+ }
18823
+ final(message3) {
18824
+ const expect = this.expect;
18825
+ if (!expect) return;
18826
+ this.expect = void 0;
18827
+ const data = latin(message3.subarray(9));
18828
+ if (data !== expect.real || expect.fake.length !== expect.real.length) {
18829
+ this.failed = true;
18830
+ return;
18831
+ }
18832
+ for (let i = 0; i < expect.fake.length; i++) message3[9 + i] = expect.fake.charCodeAt(i);
18833
+ }
18834
+ lose() {
18835
+ this.lost = true;
18836
+ this.cleartext = false;
18837
+ this.sasl = false;
18838
+ if (this.expect) this.failed = true;
18839
+ this.expect = void 0;
18840
+ }
18841
+ filter(bytes) {
18842
+ if (this.lost) return bytes;
18675
18843
  const data = new Uint8Array(this.buffer.length + bytes.length);
18676
18844
  data.set(this.buffer);
18677
18845
  data.set(bytes, this.buffer.length);
18846
+ const out = [];
18678
18847
  let at = 0;
18679
18848
  for (; ; ) {
18680
18849
  const left = data.length - at;
18681
18850
  if (this.skip > 0) {
18682
18851
  const n = Math.min(this.skip, left);
18852
+ out.push(data.subarray(at, at + n));
18683
18853
  this.skip -= n;
18684
18854
  at += n;
18685
18855
  if (this.skip > 0) break;
18686
18856
  continue;
18687
18857
  }
18688
18858
  if (left < 5) break;
18689
- const type = data[at];
18690
18859
  const whole = 1 + int32(data, at + 1);
18691
- if (whole < 5 || type === 82 && whole > PG_MESSAGE_MAX) {
18692
- this.lost = true;
18693
- this.cleartext = false;
18694
- this.buffer = new Uint8Array(0);
18695
- return;
18860
+ if (whole < 5 || data[at] === 82 && whole > PG_MESSAGE_MAX) {
18861
+ this.lose();
18862
+ out.push(data.subarray(at));
18863
+ at = data.length;
18864
+ break;
18696
18865
  }
18697
- if (type !== 82) {
18866
+ if (data[at] !== 82) {
18867
+ if (this.expect) {
18868
+ this.failed = true;
18869
+ break;
18870
+ }
18698
18871
  this.skip = whole;
18699
18872
  continue;
18700
18873
  }
18701
18874
  if (left < whole) break;
18702
- this.cleartext = whole === 9 && int32(data, at + 5) === CLEARTEXT;
18875
+ out.push(this.auth(data.slice(at, at + whole)));
18703
18876
  at += whole;
18704
18877
  }
18705
18878
  this.buffer = data.slice(at);
18879
+ const joined4 = new Uint8Array(out.reduce((n, b) => n + b.length, 0));
18880
+ let to = 0;
18881
+ for (const b of out) {
18882
+ joined4.set(b, to);
18883
+ to += b.length;
18884
+ }
18885
+ return joined4;
18706
18886
  }
18707
18887
  };
18708
18888
  function frame3(type, body) {
@@ -18719,21 +18899,76 @@ function pgLength(bytes, started) {
18719
18899
  const length2 = int32(bytes, started ? 1 : 0);
18720
18900
  return started ? 1 + length2 : length2;
18721
18901
  }
18722
- async function pgPassword(message3, server, ask) {
18723
- if (message3[0] !== 112 || !server.cleartext) return { bytes: message3, done: true };
18724
- server.cleartext = false;
18725
- let body = "";
18726
- for (const b of message3.subarray(5)) body += String.fromCharCode(b);
18902
+ var MECHANISMS = /* @__PURE__ */ new Set(["SCRAM-SHA-256"]);
18903
+ async function cleartext(message3, asks) {
18904
+ const body = latin(message3.subarray(5));
18727
18905
  if (!body.endsWith("\0") || body.indexOf("\0") !== body.length - 1)
18728
18906
  return { bytes: message3, done: true };
18729
18907
  const password = body.slice(0, -1);
18730
18908
  const placeholders = placeholdersIn(password);
18731
18909
  if (placeholders.length === 0 || placeholders.length > SESSION_PLACEHOLDERS)
18732
18910
  return { bytes: message3, done: true };
18733
- const values = usable(await ask(placeholders));
18911
+ const values = usable(await asks.cleartext(placeholders));
18734
18912
  if (Object.keys(values).length === 0) return { bytes: message3, done: true };
18735
18913
  return { bytes: frame3(112, `${replaced(password, values)}\0`), values, done: true };
18736
18914
  }
18915
+ function initial(message3) {
18916
+ const body = latin(message3.subarray(5));
18917
+ const nul = body.indexOf("\0");
18918
+ if (nul < 0 || !MECHANISMS.has(body.slice(0, nul)) || body.length < nul + 5) return void 0;
18919
+ const data = message3.subarray(5 + nul + 5);
18920
+ return int32(message3, 5 + nul + 1) === data.length ? latin(data) : void 0;
18921
+ }
18922
+ var PgClient = class {
18923
+ clientFirst;
18924
+ server;
18925
+ asks;
18926
+ constructor(server, asks) {
18927
+ this.server = server;
18928
+ this.asks = asks;
18929
+ }
18930
+ async message(message3) {
18931
+ const server = this.server;
18932
+ if (message3[0] !== 112) return { bytes: message3, done: true };
18933
+ if (server.cleartext) {
18934
+ server.cleartext = false;
18935
+ return cleartext(message3, this.asks);
18936
+ }
18937
+ if (server.sasl && this.clientFirst === void 0) {
18938
+ this.clientFirst = initial(message3);
18939
+ return { bytes: message3, done: this.clientFirst === void 0 };
18940
+ }
18941
+ if (this.clientFirst !== void 0 && server.serverFirst !== void 0)
18942
+ return this.final(message3, this.clientFirst, server.serverFirst);
18943
+ return { bytes: message3, done: true };
18944
+ }
18945
+ async final(message3, first, serverFirst) {
18946
+ const got = exchangeOf(first, serverFirst, latin(message3.subarray(5)));
18947
+ if (!got) return { bytes: message3, done: true };
18948
+ const x = got.exchange;
18949
+ const values = usable(
18950
+ await this.asks.scram({
18951
+ clientFirstBare: x.clientFirstBare,
18952
+ serverFirst: x.serverFirst,
18953
+ clientFinalBare: x.clientFinalBare,
18954
+ proof: base64Of(got.proof)
18955
+ })
18956
+ );
18957
+ const [entry, ...more] = Object.entries(values);
18958
+ if (!entry || more.length > 0) return { bytes: message3, done: true };
18959
+ const [placeholder, value2] = entry;
18960
+ const fake = await scramKeys(placeholder, x);
18961
+ if (!sameBytes(fake.proof, got.proof)) return { bytes: message3, done: true };
18962
+ const real = await scramKeys(saslprep(value2), x);
18963
+ this.server.expect = {
18964
+ real: `v=${base64Of(real.serverSignature)}`,
18965
+ fake: `v=${base64Of(fake.serverSignature)}`
18966
+ };
18967
+ const bytes = frame3(112, `${x.clientFinalBare},p=${base64Of(real.proof)}`);
18968
+ for (const k of [real.proof, real.serverSignature, fake.proof, fake.serverSignature]) k.fill(0);
18969
+ return { bytes, values, done: true };
18970
+ }
18971
+ };
18737
18972
 
18738
18973
  // src/kernel/net/sealed-smtp.ts
18739
18974
  var SMTP_LINE_MAX = 4096;
@@ -18878,17 +19113,21 @@ var SessionWriter = class {
18878
19113
  session = sessionId();
18879
19114
  smtp;
18880
19115
  pgStarted = false;
19116
+ sawPg = false;
18881
19117
  conn;
18882
19118
  s;
18883
- pg;
19119
+ pgClient;
18884
19120
  scope;
18885
19121
  constructor(conn, s, pg, scope) {
18886
19122
  this.conn = conn;
18887
19123
  this.s = s;
18888
- this.pg = pg;
18889
19124
  this.scope = scope;
19125
+ this.pgClient = new PgClient(pg, {
19126
+ cleartext: (placeholders) => this.ask("pg", "password-cleartext", { placeholders }),
19127
+ scram: (scram) => this.ask("pg", "scram-sha-256", { scram })
19128
+ });
18890
19129
  this.smtp = new SmtpClient(
18891
- (position, placeholders) => this.ask("smtp", position, placeholders)
19130
+ (position, placeholders) => this.ask("smtp", position, { placeholders })
18892
19131
  );
18893
19132
  }
18894
19133
  write(bytes) {
@@ -18899,7 +19138,7 @@ var SessionWriter = class {
18899
19138
  );
18900
19139
  return run2;
18901
19140
  }
18902
- async ask(protocol, position, placeholders, head) {
19141
+ async ask(protocol, position, extra) {
18903
19142
  const s = this.s;
18904
19143
  const values = await s.broker.sessionMaterialize({
18905
19144
  stamp: await s.stamp(),
@@ -18911,8 +19150,7 @@ var SessionWriter = class {
18911
19150
  verified: s.verified,
18912
19151
  handshakeAt: s.handshakeAt,
18913
19152
  exit: s.exit,
18914
- placeholders,
18915
- ...head ? { head } : {}
19153
+ ...extra
18916
19154
  });
18917
19155
  return values;
18918
19156
  }
@@ -18931,6 +19169,7 @@ var SessionWriter = class {
18931
19169
  this.buffer.fill(0);
18932
19170
  this.buffer = joined4;
18933
19171
  if (this.mode === "sniff") this.mode = modeOf(latin12(joined4.subarray(0, 8))) ?? "sniff";
19172
+ if (this.mode === "pg") this.sawPg = true;
18934
19173
  if (this.mode === "pass") await this.release();
18935
19174
  else if (this.mode === "http1") await this.http1();
18936
19175
  else if (this.mode === "smtp") await this.lines();
@@ -18977,11 +19216,7 @@ var SessionWriter = class {
18977
19216
  this.buffer = this.buffer.slice(whole);
18978
19217
  const started = this.pgStarted;
18979
19218
  this.pgStarted = true;
18980
- const out = started ? await pgPassword(
18981
- message3,
18982
- this.pg,
18983
- (placeholders) => this.ask("pg", "password-cleartext", placeholders)
18984
- ).catch(() => ({ bytes: message3, done: true })) : { bytes: message3, done: false };
19219
+ const out = started ? await this.pgClient.message(message3).catch(() => ({ bytes: message3, done: true })) : { bytes: message3, done: false };
18985
19220
  if ("values" in out && out.values) this.remember(out.values);
18986
19221
  try {
18987
19222
  await writeAll4(this.conn, out.bytes);
@@ -19013,7 +19248,7 @@ var SessionWriter = class {
19013
19248
  this.buffer = new Uint8Array(0);
19014
19249
  const done5 = await substituteHead(
19015
19250
  latin12(all.subarray(0, end)),
19016
- (position, placeholders, head2) => this.ask("http1", position, placeholders, head2)
19251
+ (position, placeholders, head2) => this.ask("http1", position, { placeholders, head: head2 })
19017
19252
  ).catch(() => void 0);
19018
19253
  const head = done5 ? bytesOf(done5.head) : all.subarray(0, end);
19019
19254
  if (done5) this.remember(done5.values);
@@ -19111,9 +19346,19 @@ function sealedConn(conn, s) {
19111
19346
  const observed = {
19112
19347
  ...conn,
19113
19348
  read: async () => {
19114
- const bytes = await conn.read();
19115
- if (bytes) pg.feed(bytes);
19116
- return bytes;
19349
+ for (; ; ) {
19350
+ const bytes = await conn.read();
19351
+ if (!bytes) return bytes;
19352
+ const out = writer?.sawPg ? pg.filter(bytes) : bytes;
19353
+ if (pg.failed) {
19354
+ conn.close();
19355
+ throw new KernelError(
19356
+ "EPROTO",
19357
+ "ERR_SSL_PROTOCOL_ERROR: the pg server failed the SCRAM proof"
19358
+ );
19359
+ }
19360
+ if (out.length > 0) return out;
19361
+ }
19117
19362
  }
19118
19363
  };
19119
19364
  const reader = new ScrubReader(writer ? observed : conn, scope);
@@ -24193,7 +24438,7 @@ var SEALED_OPS = /* @__PURE__ */ new Set([
24193
24438
  "cancel",
24194
24439
  "materialize"
24195
24440
  ]);
24196
- var encoder8 = new TextEncoder();
24441
+ var encoder9 = new TextEncoder();
24197
24442
  var decoder3 = new TextDecoder("utf-8", { fatal: true });
24198
24443
  function parseSealed(bytes) {
24199
24444
  try {
@@ -24274,7 +24519,7 @@ var SealedChannel = class {
24274
24519
  await this.broker.tickets.record(req, reply, caller.pid);
24275
24520
  if (this.inflight !== flight) return;
24276
24521
  this.inflight = void 0;
24277
- if (reply) this.reply = encoder8.encode(serialized(reply));
24522
+ if (reply) this.reply = encoder9.encode(serialized(reply));
24278
24523
  });
24279
24524
  this.inflight = flight;
24280
24525
  return length2;
@@ -26010,9 +26255,9 @@ function importedMemory(bytes) {
26010
26255
  };
26011
26256
  const limits = () => {
26012
26257
  const flags2 = bytes[at++];
26013
- const initial = u32();
26258
+ const initial2 = u32();
26014
26259
  const maximum = flags2 & 1 ? u32() : void 0;
26015
- return { initial, maximum, shared: (flags2 & 2) !== 0 };
26260
+ return { initial: initial2, maximum, shared: (flags2 & 2) !== 0 };
26016
26261
  };
26017
26262
  while (at < bytes.length) {
26018
26263
  const id2 = bytes[at++];
@@ -26657,7 +26902,7 @@ var LAYOUT = [
26657
26902
  var IN_TREE = /* @__PURE__ */ new Set([SUDO_PATH, CRONTAB_PATH]);
26658
26903
  var LOAD_SAMPLE_MS = 5e3;
26659
26904
  var LOAD_WINDOWS_MS = [6e4, 3e5, 9e5];
26660
- var encoder9 = new TextEncoder();
26905
+ var encoder10 = new TextEncoder();
26661
26906
  var USERS_MODES = ["off", "report", "enforce"];
26662
26907
  function usersMode(mode = "off") {
26663
26908
  if (USERS_MODES.includes(mode)) return mode;
@@ -28932,7 +29177,7 @@ var Launcher = class {
28932
29177
  },
28933
29178
  account
28934
29179
  );
28935
- const report = (message3) => options.onData(encoder9.encode(`${message3}\r
29180
+ const report = (message3) => options.onData(encoder10.encode(`${message3}\r
28936
29181
  `));
28937
29182
  const handle = await this.launch(planned, {
28938
29183
  env,
@@ -28970,7 +29215,7 @@ var Launcher = class {
28970
29215
  };
28971
29216
  const stdout = collect(out, options.onStdout);
28972
29217
  const stderr = collect(err, options.onStderr);
28973
- const report = (message3) => stderr(encoder9.encode(`${message3}
29218
+ const report = (message3) => stderr(encoder10.encode(`${message3}
28974
29219
  `));
28975
29220
  if (!planned) {
28976
29221
  const directory = await this.directory(file, this.fs.resolvePath(cwd, file));