@ai-ecoverse/slicc-kernel 1.133.5 → 1.134.0
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 +7 -1
- package/dist/kernel-worker.js +286 -47
- package/dist/kernel-worker.js.map +4 -4
- package/dist/node-process-worker.js +1 -1
- package/dist/node.js +291 -52
- package/dist/node.js.map +4 -4
- package/dist/process-worker.js +1 -1
- 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/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;
|
package/dist/kernel-worker.js
CHANGED
|
@@ -7095,7 +7095,7 @@ function satisfies(version, range2) {
|
|
|
7095
7095
|
}
|
|
7096
7096
|
|
|
7097
7097
|
// src/version.ts
|
|
7098
|
-
var KERNEL_VERSION = true ? "1.
|
|
7098
|
+
var KERNEL_VERSION = true ? "1.134.0" : "0.0.0-dev";
|
|
7099
7099
|
var OS_RELEASE = "6.0.0-slicc";
|
|
7100
7100
|
function procVersion() {
|
|
7101
7101
|
return `Linux version ${OS_RELEASE} (slicc-kernel ${KERNEL_VERSION}) #1 SMP PREEMPT_DYNAMIC
|
|
@@ -14158,8 +14158,8 @@ var EventFd = class _EventFd {
|
|
|
14158
14158
|
count;
|
|
14159
14159
|
semaphore;
|
|
14160
14160
|
changes = new Notifier();
|
|
14161
|
-
constructor(
|
|
14162
|
-
this.count =
|
|
14161
|
+
constructor(initial2, semaphore) {
|
|
14162
|
+
this.count = initial2;
|
|
14163
14163
|
this.semaphore = semaphore;
|
|
14164
14164
|
}
|
|
14165
14165
|
async read(max, signal) {
|
|
@@ -17908,7 +17908,7 @@ var UNSAFE = /[\r\n\0]/;
|
|
|
17908
17908
|
var POSITIONS = {
|
|
17909
17909
|
http1: (position) => HEADER.test(position),
|
|
17910
17910
|
smtp: (position) => position === "auth-plain" || position === "auth-login",
|
|
17911
|
-
pg: (position) => position === "password-cleartext"
|
|
17911
|
+
pg: (position) => position === "password-cleartext" || position === "scram-sha-256"
|
|
17912
17912
|
};
|
|
17913
17913
|
function boundHost(servername) {
|
|
17914
17914
|
const lower = servername.toLowerCase();
|
|
@@ -17923,6 +17923,15 @@ function placeholdersOk(list) {
|
|
|
17923
17923
|
if (!Array.isArray(list) || list.length === 0 || list.length > SESSION_PLACEHOLDERS) return false;
|
|
17924
17924
|
return new Set(list).size === list.length && list.every((p) => typeof p === "string" && SESSION_PLACEHOLDER.test(p));
|
|
17925
17925
|
}
|
|
17926
|
+
var SCRAM_TEXT = /^[\x21-\x7e]{1,1024}$/;
|
|
17927
|
+
function scramOk(f) {
|
|
17928
|
+
if (f.position !== "scram-sha-256")
|
|
17929
|
+
return f.scram === void 0 && placeholdersOk(f.placeholders);
|
|
17930
|
+
const x = f.scram;
|
|
17931
|
+
if (f.placeholders !== void 0 || typeof x !== "object" || x === null) return false;
|
|
17932
|
+
const texts = [x.clientFirstBare, x.serverFirst, x.clientFinalBare, x.proof];
|
|
17933
|
+
return texts.every((t) => typeof t === "string" && SCRAM_TEXT.test(t));
|
|
17934
|
+
}
|
|
17926
17935
|
function hostOk(host) {
|
|
17927
17936
|
return typeof host === "string" && HOST.test(host) && boundHost(host) === host;
|
|
17928
17937
|
}
|
|
@@ -17934,7 +17943,7 @@ function sessionAskable(f, now) {
|
|
|
17934
17943
|
if (!Number.isInteger(f.port) || f.port < 1 || f.port > 65535) return false;
|
|
17935
17944
|
const age = now - f.handshakeAt;
|
|
17936
17945
|
if (!Number.isFinite(age) || age < 0 || age > SESSION_WINDOW_MS) return false;
|
|
17937
|
-
return typeof f.exit === "string" && SESSION_EXIT.test(f.exit) &&
|
|
17946
|
+
return typeof f.exit === "string" && SESSION_EXIT.test(f.exit) && scramOk(f) && headOk(f);
|
|
17938
17947
|
}
|
|
17939
17948
|
function sessionRequest(f) {
|
|
17940
17949
|
return {
|
|
@@ -17950,8 +17959,16 @@ function sessionRequest(f) {
|
|
|
17950
17959
|
verified: true,
|
|
17951
17960
|
handshakeAt: f.handshakeAt,
|
|
17952
17961
|
exit: f.exit,
|
|
17953
|
-
placeholders: [...f.placeholders],
|
|
17954
|
-
...f.head ? { head: { method: f.head.method, path: f.head.path } } : {}
|
|
17962
|
+
...f.placeholders ? { placeholders: [...f.placeholders] } : {},
|
|
17963
|
+
...f.head ? { head: { method: f.head.method, path: f.head.path } } : {},
|
|
17964
|
+
...f.scram ? {
|
|
17965
|
+
scram: {
|
|
17966
|
+
clientFirstBare: f.scram.clientFirstBare,
|
|
17967
|
+
serverFirst: f.scram.serverFirst,
|
|
17968
|
+
clientFinalBare: f.scram.clientFinalBare,
|
|
17969
|
+
proof: f.scram.proof
|
|
17970
|
+
}
|
|
17971
|
+
} : {}
|
|
17955
17972
|
};
|
|
17956
17973
|
}
|
|
17957
17974
|
function sessionValues(reply, asked) {
|
|
@@ -17959,7 +17976,9 @@ function sessionValues(reply, asked) {
|
|
|
17959
17976
|
const { error, values } = reply;
|
|
17960
17977
|
if (error !== void 0 || typeof values !== "object" || values === null) return void 0;
|
|
17961
17978
|
const out = {};
|
|
17962
|
-
|
|
17979
|
+
const keys = Object.keys(values);
|
|
17980
|
+
const wanted = asked ?? (keys.length === 1 && SESSION_PLACEHOLDER.test(keys[0]) ? keys : []);
|
|
17981
|
+
for (const ph of wanted) {
|
|
17963
17982
|
const value2 = values[ph];
|
|
17964
17983
|
if (typeof value2 === "string" && value2.length > 0 && !UNSAFE.test(value2)) out[ph] = value2;
|
|
17965
17984
|
}
|
|
@@ -18651,6 +18670,104 @@ async function substituteHead(head, ask) {
|
|
|
18651
18670
|
`, values };
|
|
18652
18671
|
}
|
|
18653
18672
|
|
|
18673
|
+
// src/kernel/net/sealed-scram.ts
|
|
18674
|
+
var encoder8 = new TextEncoder();
|
|
18675
|
+
function base64Bytes(text) {
|
|
18676
|
+
try {
|
|
18677
|
+
return Uint8Array.from(atob(text), (c) => c.charCodeAt(0));
|
|
18678
|
+
} catch {
|
|
18679
|
+
return void 0;
|
|
18680
|
+
}
|
|
18681
|
+
}
|
|
18682
|
+
function base64Of(bytes) {
|
|
18683
|
+
let bin = "";
|
|
18684
|
+
for (const b of bytes) bin += String.fromCharCode(b);
|
|
18685
|
+
return btoa(bin);
|
|
18686
|
+
}
|
|
18687
|
+
function clientFirstBare(message3) {
|
|
18688
|
+
const m = /^n,,(n=[^,]*,r=[^,]+)$/.exec(message3);
|
|
18689
|
+
return m ? m[1] : void 0;
|
|
18690
|
+
}
|
|
18691
|
+
var SERVER_FIRST = /^r=([^,]+),s=([^,]+),i=(\d{1,6})$/;
|
|
18692
|
+
var CLIENT_FINAL = /^(c=biws,r=([^,]+)),p=([^,]+)$/;
|
|
18693
|
+
var SCRAM_MAX = 1024;
|
|
18694
|
+
function exchangeOf(clientFirst, serverFirst, clientFinal) {
|
|
18695
|
+
const bare = clientFirstBare(clientFirst);
|
|
18696
|
+
const sf = SERVER_FIRST.exec(serverFirst);
|
|
18697
|
+
const fin = CLIENT_FINAL.exec(clientFinal);
|
|
18698
|
+
if (!bare || !sf || !fin || [bare, serverFirst, clientFinal].some((t) => t.length > SCRAM_MAX))
|
|
18699
|
+
return void 0;
|
|
18700
|
+
const cnonce = bare.slice(bare.indexOf(",r=") + 3);
|
|
18701
|
+
const nonce = sf[1];
|
|
18702
|
+
const salt = base64Bytes(sf[2]);
|
|
18703
|
+
const iterations = Number(sf[3]);
|
|
18704
|
+
const proof = base64Bytes(fin[3]);
|
|
18705
|
+
const ok4 = fin[2] === nonce && nonce.startsWith(cnonce) && iterations >= 1 && iterations <= 1e5 && salt !== void 0 && proof?.length === 32;
|
|
18706
|
+
if (!ok4) return void 0;
|
|
18707
|
+
return {
|
|
18708
|
+
exchange: {
|
|
18709
|
+
clientFirstBare: bare,
|
|
18710
|
+
serverFirst,
|
|
18711
|
+
clientFinalBare: fin[1],
|
|
18712
|
+
salt,
|
|
18713
|
+
iterations
|
|
18714
|
+
},
|
|
18715
|
+
proof
|
|
18716
|
+
};
|
|
18717
|
+
}
|
|
18718
|
+
async function hmac(key, data) {
|
|
18719
|
+
const k = await crypto.subtle.importKey(
|
|
18720
|
+
"raw",
|
|
18721
|
+
key,
|
|
18722
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
18723
|
+
false,
|
|
18724
|
+
["sign"]
|
|
18725
|
+
);
|
|
18726
|
+
return new Uint8Array(await crypto.subtle.sign("HMAC", k, data));
|
|
18727
|
+
}
|
|
18728
|
+
async function scramKeys(password, x) {
|
|
18729
|
+
const base = await crypto.subtle.importKey("raw", encoder8.encode(password), "PBKDF2", false, [
|
|
18730
|
+
"deriveBits"
|
|
18731
|
+
]);
|
|
18732
|
+
const salted = new Uint8Array(
|
|
18733
|
+
await crypto.subtle.deriveBits(
|
|
18734
|
+
{
|
|
18735
|
+
name: "PBKDF2",
|
|
18736
|
+
hash: "SHA-256",
|
|
18737
|
+
salt: x.salt,
|
|
18738
|
+
iterations: x.iterations
|
|
18739
|
+
},
|
|
18740
|
+
base,
|
|
18741
|
+
256
|
|
18742
|
+
)
|
|
18743
|
+
);
|
|
18744
|
+
const clientKey = await hmac(salted, encoder8.encode("Client Key"));
|
|
18745
|
+
const stored = new Uint8Array(
|
|
18746
|
+
await crypto.subtle.digest("SHA-256", clientKey)
|
|
18747
|
+
);
|
|
18748
|
+
const auth = encoder8.encode(`${x.clientFirstBare},${x.serverFirst},${x.clientFinalBare}`);
|
|
18749
|
+
const signature = await hmac(stored, auth);
|
|
18750
|
+
const proof = clientKey.map((b, i) => b ^ signature[i]);
|
|
18751
|
+
const serverKey = await hmac(salted, encoder8.encode("Server Key"));
|
|
18752
|
+
const serverSignature = await hmac(serverKey, auth);
|
|
18753
|
+
for (const k of [salted, clientKey, stored, signature, serverKey]) k.fill(0);
|
|
18754
|
+
return { proof, serverSignature };
|
|
18755
|
+
}
|
|
18756
|
+
var SPACES = /[\u00A0\u1680\u2000-\u200B\u202F\u205F\u3000]/g;
|
|
18757
|
+
var NOTHING2 = /\u00AD|\u034F|\u1806|[\u180B-\u180D]|\u200C|\u200D|\u2060|[\uFE00-\uFE0F]|\uFEFF/g;
|
|
18758
|
+
var PROHIBITED = /[\u0000-\u001F\u007F-\u009F\uE000-\uF8FF\uFFFE\uFFFF]/;
|
|
18759
|
+
function saslprep(password) {
|
|
18760
|
+
if (/^[\x20-\x7e]*$/.test(password)) return password;
|
|
18761
|
+
const mapped = password.replace(SPACES, " ").replace(NOTHING2, "").normalize("NFKC");
|
|
18762
|
+
return PROHIBITED.test(mapped) ? password : mapped;
|
|
18763
|
+
}
|
|
18764
|
+
function sameBytes(a, b) {
|
|
18765
|
+
if (a.length !== b.length) return false;
|
|
18766
|
+
let d = 0;
|
|
18767
|
+
for (let i = 0; i < a.length; i++) d |= a[i] ^ b[i];
|
|
18768
|
+
return d === 0;
|
|
18769
|
+
}
|
|
18770
|
+
|
|
18654
18771
|
// src/kernel/net/sealed-pg.ts
|
|
18655
18772
|
var PG_MESSAGE_MAX = 16 * 1024;
|
|
18656
18773
|
var PROTOCOL_3 = 196608;
|
|
@@ -18665,44 +18782,101 @@ function sniffPg(start2) {
|
|
|
18665
18782
|
const length2 = int32(bytes, 0);
|
|
18666
18783
|
return length2 >= 8 && length2 <= PG_MESSAGE_MAX && int32(bytes, 4) === PROTOCOL_3 ? "yes" : "no";
|
|
18667
18784
|
}
|
|
18785
|
+
var PLUS = "SCRAM-SHA-256-PLUS";
|
|
18786
|
+
var SASL = 10;
|
|
18787
|
+
var SASL_CONTINUE = 11;
|
|
18788
|
+
var SASL_FINAL = 12;
|
|
18789
|
+
function latin(bytes) {
|
|
18790
|
+
let out = "";
|
|
18791
|
+
for (const b of bytes) out += String.fromCharCode(b);
|
|
18792
|
+
return out;
|
|
18793
|
+
}
|
|
18668
18794
|
var PgServer = class {
|
|
18669
18795
|
buffer = new Uint8Array(0);
|
|
18670
18796
|
skip = 0;
|
|
18671
|
-
lost = false;
|
|
18672
18797
|
cleartext = false;
|
|
18673
|
-
|
|
18674
|
-
|
|
18798
|
+
sasl = false;
|
|
18799
|
+
serverFirst;
|
|
18800
|
+
expect;
|
|
18801
|
+
failed = false;
|
|
18802
|
+
lost = false;
|
|
18803
|
+
auth(message3) {
|
|
18804
|
+
const code = message3.length >= 9 ? int32(message3, 5) : -1;
|
|
18805
|
+
if (this.expect && code !== SASL_FINAL) this.failed = true;
|
|
18806
|
+
this.cleartext = message3.length === 9 && code === CLEARTEXT;
|
|
18807
|
+
if (code === SASL) return this.mechanisms(message3);
|
|
18808
|
+
else if (code === SASL_CONTINUE) this.serverFirst = latin(message3.subarray(9));
|
|
18809
|
+
else if (code === SASL_FINAL) this.final(message3);
|
|
18810
|
+
return message3;
|
|
18811
|
+
}
|
|
18812
|
+
mechanisms(message3) {
|
|
18813
|
+
this.sasl = true;
|
|
18814
|
+
const names2 = latin(message3.subarray(9)).split("\0").filter((n) => n !== "" && n !== PLUS);
|
|
18815
|
+
return frame3(82, `${latin(message3.subarray(5, 9))}${names2.map((n) => `${n}\0`).join("")}\0`);
|
|
18816
|
+
}
|
|
18817
|
+
final(message3) {
|
|
18818
|
+
const expect = this.expect;
|
|
18819
|
+
if (!expect) return;
|
|
18820
|
+
this.expect = void 0;
|
|
18821
|
+
const data = latin(message3.subarray(9));
|
|
18822
|
+
if (data !== expect.real || expect.fake.length !== expect.real.length) {
|
|
18823
|
+
this.failed = true;
|
|
18824
|
+
return;
|
|
18825
|
+
}
|
|
18826
|
+
for (let i = 0; i < expect.fake.length; i++) message3[9 + i] = expect.fake.charCodeAt(i);
|
|
18827
|
+
}
|
|
18828
|
+
lose() {
|
|
18829
|
+
this.lost = true;
|
|
18830
|
+
this.cleartext = false;
|
|
18831
|
+
this.sasl = false;
|
|
18832
|
+
if (this.expect) this.failed = true;
|
|
18833
|
+
this.expect = void 0;
|
|
18834
|
+
}
|
|
18835
|
+
filter(bytes) {
|
|
18836
|
+
if (this.lost) return bytes;
|
|
18675
18837
|
const data = new Uint8Array(this.buffer.length + bytes.length);
|
|
18676
18838
|
data.set(this.buffer);
|
|
18677
18839
|
data.set(bytes, this.buffer.length);
|
|
18840
|
+
const out = [];
|
|
18678
18841
|
let at = 0;
|
|
18679
18842
|
for (; ; ) {
|
|
18680
18843
|
const left = data.length - at;
|
|
18681
18844
|
if (this.skip > 0) {
|
|
18682
18845
|
const n = Math.min(this.skip, left);
|
|
18846
|
+
out.push(data.subarray(at, at + n));
|
|
18683
18847
|
this.skip -= n;
|
|
18684
18848
|
at += n;
|
|
18685
18849
|
if (this.skip > 0) break;
|
|
18686
18850
|
continue;
|
|
18687
18851
|
}
|
|
18688
18852
|
if (left < 5) break;
|
|
18689
|
-
const type = data[at];
|
|
18690
18853
|
const whole = 1 + int32(data, at + 1);
|
|
18691
|
-
if (whole < 5 ||
|
|
18692
|
-
this.
|
|
18693
|
-
|
|
18694
|
-
|
|
18695
|
-
|
|
18854
|
+
if (whole < 5 || data[at] === 82 && whole > PG_MESSAGE_MAX) {
|
|
18855
|
+
this.lose();
|
|
18856
|
+
out.push(data.subarray(at));
|
|
18857
|
+
at = data.length;
|
|
18858
|
+
break;
|
|
18696
18859
|
}
|
|
18697
|
-
if (
|
|
18860
|
+
if (data[at] !== 82) {
|
|
18861
|
+
if (this.expect) {
|
|
18862
|
+
this.failed = true;
|
|
18863
|
+
break;
|
|
18864
|
+
}
|
|
18698
18865
|
this.skip = whole;
|
|
18699
18866
|
continue;
|
|
18700
18867
|
}
|
|
18701
18868
|
if (left < whole) break;
|
|
18702
|
-
this.
|
|
18869
|
+
out.push(this.auth(data.slice(at, at + whole)));
|
|
18703
18870
|
at += whole;
|
|
18704
18871
|
}
|
|
18705
18872
|
this.buffer = data.slice(at);
|
|
18873
|
+
const joined4 = new Uint8Array(out.reduce((n, b) => n + b.length, 0));
|
|
18874
|
+
let to = 0;
|
|
18875
|
+
for (const b of out) {
|
|
18876
|
+
joined4.set(b, to);
|
|
18877
|
+
to += b.length;
|
|
18878
|
+
}
|
|
18879
|
+
return joined4;
|
|
18706
18880
|
}
|
|
18707
18881
|
};
|
|
18708
18882
|
function frame3(type, body) {
|
|
@@ -18719,21 +18893,76 @@ function pgLength(bytes, started) {
|
|
|
18719
18893
|
const length2 = int32(bytes, started ? 1 : 0);
|
|
18720
18894
|
return started ? 1 + length2 : length2;
|
|
18721
18895
|
}
|
|
18722
|
-
|
|
18723
|
-
|
|
18724
|
-
|
|
18725
|
-
let body = "";
|
|
18726
|
-
for (const b of message3.subarray(5)) body += String.fromCharCode(b);
|
|
18896
|
+
var MECHANISMS = /* @__PURE__ */ new Set(["SCRAM-SHA-256"]);
|
|
18897
|
+
async function cleartext(message3, asks) {
|
|
18898
|
+
const body = latin(message3.subarray(5));
|
|
18727
18899
|
if (!body.endsWith("\0") || body.indexOf("\0") !== body.length - 1)
|
|
18728
18900
|
return { bytes: message3, done: true };
|
|
18729
18901
|
const password = body.slice(0, -1);
|
|
18730
18902
|
const placeholders = placeholdersIn(password);
|
|
18731
18903
|
if (placeholders.length === 0 || placeholders.length > SESSION_PLACEHOLDERS)
|
|
18732
18904
|
return { bytes: message3, done: true };
|
|
18733
|
-
const values = usable(await
|
|
18905
|
+
const values = usable(await asks.cleartext(placeholders));
|
|
18734
18906
|
if (Object.keys(values).length === 0) return { bytes: message3, done: true };
|
|
18735
18907
|
return { bytes: frame3(112, `${replaced(password, values)}\0`), values, done: true };
|
|
18736
18908
|
}
|
|
18909
|
+
function initial(message3) {
|
|
18910
|
+
const body = latin(message3.subarray(5));
|
|
18911
|
+
const nul = body.indexOf("\0");
|
|
18912
|
+
if (nul < 0 || !MECHANISMS.has(body.slice(0, nul)) || body.length < nul + 5) return void 0;
|
|
18913
|
+
const data = message3.subarray(5 + nul + 5);
|
|
18914
|
+
return int32(message3, 5 + nul + 1) === data.length ? latin(data) : void 0;
|
|
18915
|
+
}
|
|
18916
|
+
var PgClient = class {
|
|
18917
|
+
clientFirst;
|
|
18918
|
+
server;
|
|
18919
|
+
asks;
|
|
18920
|
+
constructor(server, asks) {
|
|
18921
|
+
this.server = server;
|
|
18922
|
+
this.asks = asks;
|
|
18923
|
+
}
|
|
18924
|
+
async message(message3) {
|
|
18925
|
+
const server = this.server;
|
|
18926
|
+
if (message3[0] !== 112) return { bytes: message3, done: true };
|
|
18927
|
+
if (server.cleartext) {
|
|
18928
|
+
server.cleartext = false;
|
|
18929
|
+
return cleartext(message3, this.asks);
|
|
18930
|
+
}
|
|
18931
|
+
if (server.sasl && this.clientFirst === void 0) {
|
|
18932
|
+
this.clientFirst = initial(message3);
|
|
18933
|
+
return { bytes: message3, done: this.clientFirst === void 0 };
|
|
18934
|
+
}
|
|
18935
|
+
if (this.clientFirst !== void 0 && server.serverFirst !== void 0)
|
|
18936
|
+
return this.final(message3, this.clientFirst, server.serverFirst);
|
|
18937
|
+
return { bytes: message3, done: true };
|
|
18938
|
+
}
|
|
18939
|
+
async final(message3, first, serverFirst) {
|
|
18940
|
+
const got = exchangeOf(first, serverFirst, latin(message3.subarray(5)));
|
|
18941
|
+
if (!got) return { bytes: message3, done: true };
|
|
18942
|
+
const x = got.exchange;
|
|
18943
|
+
const values = usable(
|
|
18944
|
+
await this.asks.scram({
|
|
18945
|
+
clientFirstBare: x.clientFirstBare,
|
|
18946
|
+
serverFirst: x.serverFirst,
|
|
18947
|
+
clientFinalBare: x.clientFinalBare,
|
|
18948
|
+
proof: base64Of(got.proof)
|
|
18949
|
+
})
|
|
18950
|
+
);
|
|
18951
|
+
const [entry, ...more] = Object.entries(values);
|
|
18952
|
+
if (!entry || more.length > 0) return { bytes: message3, done: true };
|
|
18953
|
+
const [placeholder, value2] = entry;
|
|
18954
|
+
const fake = await scramKeys(placeholder, x);
|
|
18955
|
+
if (!sameBytes(fake.proof, got.proof)) return { bytes: message3, done: true };
|
|
18956
|
+
const real = await scramKeys(saslprep(value2), x);
|
|
18957
|
+
this.server.expect = {
|
|
18958
|
+
real: `v=${base64Of(real.serverSignature)}`,
|
|
18959
|
+
fake: `v=${base64Of(fake.serverSignature)}`
|
|
18960
|
+
};
|
|
18961
|
+
const bytes = frame3(112, `${x.clientFinalBare},p=${base64Of(real.proof)}`);
|
|
18962
|
+
for (const k of [real.proof, real.serverSignature, fake.proof, fake.serverSignature]) k.fill(0);
|
|
18963
|
+
return { bytes, values, done: true };
|
|
18964
|
+
}
|
|
18965
|
+
};
|
|
18737
18966
|
|
|
18738
18967
|
// src/kernel/net/sealed-smtp.ts
|
|
18739
18968
|
var SMTP_LINE_MAX = 4096;
|
|
@@ -18878,17 +19107,21 @@ var SessionWriter = class {
|
|
|
18878
19107
|
session = sessionId();
|
|
18879
19108
|
smtp;
|
|
18880
19109
|
pgStarted = false;
|
|
19110
|
+
sawPg = false;
|
|
18881
19111
|
conn;
|
|
18882
19112
|
s;
|
|
18883
|
-
|
|
19113
|
+
pgClient;
|
|
18884
19114
|
scope;
|
|
18885
19115
|
constructor(conn, s, pg, scope) {
|
|
18886
19116
|
this.conn = conn;
|
|
18887
19117
|
this.s = s;
|
|
18888
|
-
this.pg = pg;
|
|
18889
19118
|
this.scope = scope;
|
|
19119
|
+
this.pgClient = new PgClient(pg, {
|
|
19120
|
+
cleartext: (placeholders) => this.ask("pg", "password-cleartext", { placeholders }),
|
|
19121
|
+
scram: (scram) => this.ask("pg", "scram-sha-256", { scram })
|
|
19122
|
+
});
|
|
18890
19123
|
this.smtp = new SmtpClient(
|
|
18891
|
-
(position, placeholders) => this.ask("smtp", position, placeholders)
|
|
19124
|
+
(position, placeholders) => this.ask("smtp", position, { placeholders })
|
|
18892
19125
|
);
|
|
18893
19126
|
}
|
|
18894
19127
|
write(bytes) {
|
|
@@ -18899,7 +19132,7 @@ var SessionWriter = class {
|
|
|
18899
19132
|
);
|
|
18900
19133
|
return run2;
|
|
18901
19134
|
}
|
|
18902
|
-
async ask(protocol, position,
|
|
19135
|
+
async ask(protocol, position, extra) {
|
|
18903
19136
|
const s = this.s;
|
|
18904
19137
|
const values = await s.broker.sessionMaterialize({
|
|
18905
19138
|
stamp: await s.stamp(),
|
|
@@ -18911,8 +19144,7 @@ var SessionWriter = class {
|
|
|
18911
19144
|
verified: s.verified,
|
|
18912
19145
|
handshakeAt: s.handshakeAt,
|
|
18913
19146
|
exit: s.exit,
|
|
18914
|
-
|
|
18915
|
-
...head ? { head } : {}
|
|
19147
|
+
...extra
|
|
18916
19148
|
});
|
|
18917
19149
|
return values;
|
|
18918
19150
|
}
|
|
@@ -18931,6 +19163,7 @@ var SessionWriter = class {
|
|
|
18931
19163
|
this.buffer.fill(0);
|
|
18932
19164
|
this.buffer = joined4;
|
|
18933
19165
|
if (this.mode === "sniff") this.mode = modeOf(latin12(joined4.subarray(0, 8))) ?? "sniff";
|
|
19166
|
+
if (this.mode === "pg") this.sawPg = true;
|
|
18934
19167
|
if (this.mode === "pass") await this.release();
|
|
18935
19168
|
else if (this.mode === "http1") await this.http1();
|
|
18936
19169
|
else if (this.mode === "smtp") await this.lines();
|
|
@@ -18977,11 +19210,7 @@ var SessionWriter = class {
|
|
|
18977
19210
|
this.buffer = this.buffer.slice(whole);
|
|
18978
19211
|
const started = this.pgStarted;
|
|
18979
19212
|
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 };
|
|
19213
|
+
const out = started ? await this.pgClient.message(message3).catch(() => ({ bytes: message3, done: true })) : { bytes: message3, done: false };
|
|
18985
19214
|
if ("values" in out && out.values) this.remember(out.values);
|
|
18986
19215
|
try {
|
|
18987
19216
|
await writeAll4(this.conn, out.bytes);
|
|
@@ -19013,7 +19242,7 @@ var SessionWriter = class {
|
|
|
19013
19242
|
this.buffer = new Uint8Array(0);
|
|
19014
19243
|
const done5 = await substituteHead(
|
|
19015
19244
|
latin12(all.subarray(0, end)),
|
|
19016
|
-
(position, placeholders, head2) => this.ask("http1", position, placeholders, head2)
|
|
19245
|
+
(position, placeholders, head2) => this.ask("http1", position, { placeholders, head: head2 })
|
|
19017
19246
|
).catch(() => void 0);
|
|
19018
19247
|
const head = done5 ? bytesOf(done5.head) : all.subarray(0, end);
|
|
19019
19248
|
if (done5) this.remember(done5.values);
|
|
@@ -19111,9 +19340,19 @@ function sealedConn(conn, s) {
|
|
|
19111
19340
|
const observed = {
|
|
19112
19341
|
...conn,
|
|
19113
19342
|
read: async () => {
|
|
19114
|
-
|
|
19115
|
-
|
|
19116
|
-
|
|
19343
|
+
for (; ; ) {
|
|
19344
|
+
const bytes = await conn.read();
|
|
19345
|
+
if (!bytes) return bytes;
|
|
19346
|
+
const out = writer?.sawPg ? pg.filter(bytes) : bytes;
|
|
19347
|
+
if (pg.failed) {
|
|
19348
|
+
conn.close();
|
|
19349
|
+
throw new KernelError(
|
|
19350
|
+
"EPROTO",
|
|
19351
|
+
"ERR_SSL_PROTOCOL_ERROR: the pg server failed the SCRAM proof"
|
|
19352
|
+
);
|
|
19353
|
+
}
|
|
19354
|
+
if (out.length > 0) return out;
|
|
19355
|
+
}
|
|
19117
19356
|
}
|
|
19118
19357
|
};
|
|
19119
19358
|
const reader = new ScrubReader(writer ? observed : conn, scope);
|
|
@@ -24193,7 +24432,7 @@ var SEALED_OPS = /* @__PURE__ */ new Set([
|
|
|
24193
24432
|
"cancel",
|
|
24194
24433
|
"materialize"
|
|
24195
24434
|
]);
|
|
24196
|
-
var
|
|
24435
|
+
var encoder9 = new TextEncoder();
|
|
24197
24436
|
var decoder3 = new TextDecoder("utf-8", { fatal: true });
|
|
24198
24437
|
function parseSealed(bytes) {
|
|
24199
24438
|
try {
|
|
@@ -24274,7 +24513,7 @@ var SealedChannel = class {
|
|
|
24274
24513
|
await this.broker.tickets.record(req, reply, caller.pid);
|
|
24275
24514
|
if (this.inflight !== flight) return;
|
|
24276
24515
|
this.inflight = void 0;
|
|
24277
|
-
if (reply) this.reply =
|
|
24516
|
+
if (reply) this.reply = encoder9.encode(serialized(reply));
|
|
24278
24517
|
});
|
|
24279
24518
|
this.inflight = flight;
|
|
24280
24519
|
return length2;
|
|
@@ -26010,9 +26249,9 @@ function importedMemory(bytes) {
|
|
|
26010
26249
|
};
|
|
26011
26250
|
const limits = () => {
|
|
26012
26251
|
const flags2 = bytes[at++];
|
|
26013
|
-
const
|
|
26252
|
+
const initial2 = u32();
|
|
26014
26253
|
const maximum = flags2 & 1 ? u32() : void 0;
|
|
26015
|
-
return { initial, maximum, shared: (flags2 & 2) !== 0 };
|
|
26254
|
+
return { initial: initial2, maximum, shared: (flags2 & 2) !== 0 };
|
|
26016
26255
|
};
|
|
26017
26256
|
while (at < bytes.length) {
|
|
26018
26257
|
const id2 = bytes[at++];
|
|
@@ -26657,7 +26896,7 @@ var LAYOUT = [
|
|
|
26657
26896
|
var IN_TREE = /* @__PURE__ */ new Set([SUDO_PATH, CRONTAB_PATH]);
|
|
26658
26897
|
var LOAD_SAMPLE_MS = 5e3;
|
|
26659
26898
|
var LOAD_WINDOWS_MS = [6e4, 3e5, 9e5];
|
|
26660
|
-
var
|
|
26899
|
+
var encoder10 = new TextEncoder();
|
|
26661
26900
|
var USERS_MODES = ["off", "report", "enforce"];
|
|
26662
26901
|
function usersMode(mode = "off") {
|
|
26663
26902
|
if (USERS_MODES.includes(mode)) return mode;
|
|
@@ -28932,7 +29171,7 @@ var Launcher = class {
|
|
|
28932
29171
|
},
|
|
28933
29172
|
account
|
|
28934
29173
|
);
|
|
28935
|
-
const report = (message3) => options.onData(
|
|
29174
|
+
const report = (message3) => options.onData(encoder10.encode(`${message3}\r
|
|
28936
29175
|
`));
|
|
28937
29176
|
const handle = await this.launch(planned, {
|
|
28938
29177
|
env,
|
|
@@ -28970,7 +29209,7 @@ var Launcher = class {
|
|
|
28970
29209
|
};
|
|
28971
29210
|
const stdout = collect(out, options.onStdout);
|
|
28972
29211
|
const stderr = collect(err, options.onStderr);
|
|
28973
|
-
const report = (message3) => stderr(
|
|
29212
|
+
const report = (message3) => stderr(encoder10.encode(`${message3}
|
|
28974
29213
|
`));
|
|
28975
29214
|
if (!planned) {
|
|
28976
29215
|
const directory = await this.directory(file, this.fs.resolvePath(cwd, file));
|