@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 +8 -2
- package/dist/kernel-worker.js +300 -55
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-process-worker.js +9 -4
- package/dist/node-process-worker.js.map +3 -3
- package/dist/node.js +305 -60
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +9 -4
- package/dist/process-worker.js.map +3 -3
- package/dist/types/kernel/net/sealed-pg.d.ts +27 -4
- package/dist/types/kernel/net/sealed-scram.d.ts +20 -0
- package/dist/types/kernel/sealed-session.d.ts +16 -3
- package/dist/types/process/js/js-context.d.ts +1 -0
- package/package.json +3 -3
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.
|
|
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
|
-
-
|
|
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
|
|
package/dist/kernel-worker.js
CHANGED
|
@@ -2570,15 +2570,21 @@ var OpfsFs = class {
|
|
|
2570
2570
|
let writable2;
|
|
2571
2571
|
let handle;
|
|
2572
2572
|
try {
|
|
2573
|
-
const
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
await this.
|
|
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.
|
|
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(
|
|
14162
|
-
this.count =
|
|
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) &&
|
|
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
|
-
|
|
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
|
-
|
|
18674
|
-
|
|
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 ||
|
|
18692
|
-
this.
|
|
18693
|
-
|
|
18694
|
-
|
|
18695
|
-
|
|
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 (
|
|
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.
|
|
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
|
-
|
|
18723
|
-
|
|
18724
|
-
|
|
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
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
19115
|
-
|
|
19116
|
-
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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(
|
|
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(
|
|
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));
|