@byollm/protocol 0.1.0-alpha.94 → 0.1.0-alpha.96
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 +1 -1
- package/dist/chunk-W7Q7DKQ6.js +226 -0
- package/dist/chunk-W7Q7DKQ6.js.map +1 -0
- package/dist/index.d.ts +3 -458
- package/dist/index.js +24 -209
- package/dist/index.js.map +1 -1
- package/dist/portable-D2mu8USa.d.ts +477 -0
- package/dist/portable.d.ts +2 -0
- package/dist/portable.js +39 -0
- package/dist/portable.js.map +1 -0
- package/package.json +5 -1
package/dist/index.js
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CONSOLE_FRAME_VERSION,
|
|
3
|
+
CONSOLE_MAX_DATA_BYTES,
|
|
4
|
+
ConsoleBye,
|
|
5
|
+
ConsoleFrame,
|
|
6
|
+
ConsoleHello,
|
|
7
|
+
ConsoleResize,
|
|
8
|
+
ConsoleStdin,
|
|
9
|
+
ConsoleStdout,
|
|
10
|
+
ENVELOPE_BODY_VERSION,
|
|
11
|
+
PublicIdentity,
|
|
12
|
+
consoleEnvelope,
|
|
13
|
+
consoleOrder,
|
|
14
|
+
decodeEnvelopeInner,
|
|
15
|
+
encodeEnvelopeInner,
|
|
16
|
+
envelopeSignedBody,
|
|
17
|
+
fromBase64Url,
|
|
18
|
+
toBase64Url
|
|
19
|
+
} from "./chunk-W7Q7DKQ6.js";
|
|
20
|
+
|
|
1
21
|
// src/wire.ts
|
|
2
22
|
import { z as z9 } from "zod";
|
|
3
23
|
|
|
@@ -11,20 +31,6 @@ import {
|
|
|
11
31
|
verify
|
|
12
32
|
} from "crypto";
|
|
13
33
|
import { z } from "zod";
|
|
14
|
-
var PublicIdentity = z.object({
|
|
15
|
-
/** Raw Ed25519 public key. The pinned one. */
|
|
16
|
-
identity: z.string().min(1),
|
|
17
|
-
/** Raw X25519 public key, for sealing to this party. */
|
|
18
|
-
encryption: z.string().min(1),
|
|
19
|
-
/**
|
|
20
|
-
* Ed25519 signature over the encryption key, by the identity key.
|
|
21
|
-
*
|
|
22
|
-
* This is what stops an upstream substituting an encryption key of its
|
|
23
|
-
* own while relaying a genuine identity: the receiver pins the identity
|
|
24
|
-
* and refuses any encryption key not signed by it.
|
|
25
|
-
*/
|
|
26
|
-
encryptionSig: z.string().min(1)
|
|
27
|
-
}).strict();
|
|
28
34
|
var StoredKeys = z.object({
|
|
29
35
|
version: z.literal(1),
|
|
30
36
|
identityPublic: z.string().min(1),
|
|
@@ -89,16 +95,16 @@ function verifyPublicIdentity(identity) {
|
|
|
89
95
|
return false;
|
|
90
96
|
}
|
|
91
97
|
}
|
|
92
|
-
function signWith(keys,
|
|
93
|
-
return sign(null,
|
|
98
|
+
function signWith(keys, data) {
|
|
99
|
+
return sign(null, data, importPrivate(keys.identityPrivate)).toString(
|
|
94
100
|
"base64url"
|
|
95
101
|
);
|
|
96
102
|
}
|
|
97
|
-
function verifyWith(identityPublic,
|
|
103
|
+
function verifyWith(identityPublic, data, signature) {
|
|
98
104
|
try {
|
|
99
105
|
return verify(
|
|
100
106
|
null,
|
|
101
|
-
|
|
107
|
+
data,
|
|
102
108
|
importPublic(identityPublic, "Ed25519"),
|
|
103
109
|
Buffer.from(signature, "base64url")
|
|
104
110
|
);
|
|
@@ -1163,85 +1169,6 @@ var ClaimedStub = JobStub.extend({
|
|
|
1163
1169
|
import { createPrivateKey as createPrivateKey2, createPublicKey as createPublicKey2 } from "crypto";
|
|
1164
1170
|
import sodium from "libsodium-wrappers";
|
|
1165
1171
|
import { z as z8 } from "zod";
|
|
1166
|
-
|
|
1167
|
-
// src/envelope-format.ts
|
|
1168
|
-
var ALPHABET2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
1169
|
-
var CHARS = ALPHABET2.split("");
|
|
1170
|
-
var VALUES = /* @__PURE__ */ (() => {
|
|
1171
|
-
const table = new Uint8Array(128).fill(255);
|
|
1172
|
-
for (let at = 0; at < ALPHABET2.length; at += 1) {
|
|
1173
|
-
table[ALPHABET2.charCodeAt(at)] = at;
|
|
1174
|
-
}
|
|
1175
|
-
return table;
|
|
1176
|
-
})();
|
|
1177
|
-
function toBase64Url(bytes) {
|
|
1178
|
-
let out = "";
|
|
1179
|
-
for (let at = 0; at < bytes.length; at += 3) {
|
|
1180
|
-
const a = bytes[at] ?? 0;
|
|
1181
|
-
const b = bytes[at + 1];
|
|
1182
|
-
const c = bytes[at + 2];
|
|
1183
|
-
const word = a << 16 | (b ?? 0) << 8 | (c ?? 0);
|
|
1184
|
-
out += CHARS[word >> 18 & 63] ?? "";
|
|
1185
|
-
out += CHARS[word >> 12 & 63] ?? "";
|
|
1186
|
-
if (b !== void 0) out += CHARS[word >> 6 & 63] ?? "";
|
|
1187
|
-
if (c !== void 0) out += CHARS[word & 63] ?? "";
|
|
1188
|
-
}
|
|
1189
|
-
return out;
|
|
1190
|
-
}
|
|
1191
|
-
function fromBase64Url(text) {
|
|
1192
|
-
const length = text.length;
|
|
1193
|
-
if (length % 4 === 1) return void 0;
|
|
1194
|
-
const bytes = new Uint8Array(Math.floor(length * 3 / 4));
|
|
1195
|
-
let written = 0;
|
|
1196
|
-
let word = 0;
|
|
1197
|
-
let bits = 0;
|
|
1198
|
-
for (let at = 0; at < length; at += 1) {
|
|
1199
|
-
const code = text.charCodeAt(at);
|
|
1200
|
-
const value = code < 128 ? VALUES[code] : 255;
|
|
1201
|
-
if (value === void 0 || value === 255) return void 0;
|
|
1202
|
-
word = word << 6 | value;
|
|
1203
|
-
bits += 6;
|
|
1204
|
-
if (bits >= 8) {
|
|
1205
|
-
bits -= 8;
|
|
1206
|
-
bytes[written] = word >> bits & 255;
|
|
1207
|
-
written += 1;
|
|
1208
|
-
}
|
|
1209
|
-
}
|
|
1210
|
-
return bytes.subarray(0, written);
|
|
1211
|
-
}
|
|
1212
|
-
var ENVELOPE_BODY_VERSION = "byollm/v1/envelope";
|
|
1213
|
-
function envelopeSignedBody(context, plaintext) {
|
|
1214
|
-
return new TextEncoder().encode(
|
|
1215
|
-
JSON.stringify({
|
|
1216
|
-
v: ENVELOPE_BODY_VERSION,
|
|
1217
|
-
jobId: context.jobId,
|
|
1218
|
-
senderKeyId: context.senderKeyId,
|
|
1219
|
-
recipientKeyId: context.recipientKeyId,
|
|
1220
|
-
deadlineAt: context.deadlineAt,
|
|
1221
|
-
direction: context.direction,
|
|
1222
|
-
plaintext
|
|
1223
|
-
})
|
|
1224
|
-
);
|
|
1225
|
-
}
|
|
1226
|
-
function encodeEnvelopeInner(body, signature) {
|
|
1227
|
-
return JSON.stringify({ body: toBase64Url(body), signature });
|
|
1228
|
-
}
|
|
1229
|
-
function decodeEnvelopeInner(text) {
|
|
1230
|
-
let parsed;
|
|
1231
|
-
try {
|
|
1232
|
-
parsed = JSON.parse(text);
|
|
1233
|
-
} catch {
|
|
1234
|
-
return void 0;
|
|
1235
|
-
}
|
|
1236
|
-
if (typeof parsed.body !== "string" || typeof parsed.signature !== "string") {
|
|
1237
|
-
return void 0;
|
|
1238
|
-
}
|
|
1239
|
-
const body = fromBase64Url(parsed.body);
|
|
1240
|
-
if (body === void 0) return void 0;
|
|
1241
|
-
return { body, signature: parsed.signature };
|
|
1242
|
-
}
|
|
1243
|
-
|
|
1244
|
-
// src/envelope.ts
|
|
1245
1172
|
var readied;
|
|
1246
1173
|
async function cryptoReady() {
|
|
1247
1174
|
readied ??= sodium.ready;
|
|
@@ -2722,118 +2649,6 @@ var MUST_IDS = Object.freeze(Object.keys(MUSTS));
|
|
|
2722
2649
|
function mustsVerifiedBy(kind) {
|
|
2723
2650
|
return MUST_IDS.filter((id) => kindsOf(MUSTS[id]).includes(kind));
|
|
2724
2651
|
}
|
|
2725
|
-
|
|
2726
|
-
// src/console.ts
|
|
2727
|
-
import { z as z12 } from "zod";
|
|
2728
|
-
var CONSOLE_FRAME_VERSION = "byollm/v1/console";
|
|
2729
|
-
var CONSOLE_MAX_DATA_BYTES = 64 * 1024;
|
|
2730
|
-
var data = z12.string().max(Math.ceil(CONSOLE_MAX_DATA_BYTES * 4 / 3) + 4).describe("base64");
|
|
2731
|
-
var cols = z12.number().int().min(1).max(1e4);
|
|
2732
|
-
var rows = z12.number().int().min(1).max(1e4);
|
|
2733
|
-
var seq = z12.number().int().positive();
|
|
2734
|
-
var ConsoleHello = z12.object({
|
|
2735
|
-
v: z12.literal(CONSOLE_FRAME_VERSION),
|
|
2736
|
-
kind: z12.literal("hello"),
|
|
2737
|
-
seq: z12.literal(1),
|
|
2738
|
-
/**
|
|
2739
|
-
* The browser's EPHEMERAL identity for this session, and the reason hello
|
|
2740
|
-
* exists as its own frame.
|
|
2741
|
-
*
|
|
2742
|
-
* A browser has no long-term key — it is a tab, not a machine — so it
|
|
2743
|
-
* generates one per session and the box seals its output to it. That key
|
|
2744
|
-
* has to reach the box without the hub being able to substitute one of its
|
|
2745
|
-
* own, which is the classic broker attack. So it travels SEALED TO THE
|
|
2746
|
-
* BOX'S PINNED IDENTITY like every other frame: the hub cannot read it and
|
|
2747
|
-
* cannot replace it, because replacing it means producing a sealed box
|
|
2748
|
-
* the box's key opens and the browser's key signed.
|
|
2749
|
-
*
|
|
2750
|
-
* The box does not pin this. It cannot — it is new every session, and
|
|
2751
|
-
* nothing authorises it cryptographically. What authorises the browser is
|
|
2752
|
-
* the hub's per-session grant (ruling item 2); what this key does is keep
|
|
2753
|
-
* the hub from READING what it authorised.
|
|
2754
|
-
*/
|
|
2755
|
-
browser: PublicIdentity,
|
|
2756
|
-
cols,
|
|
2757
|
-
rows
|
|
2758
|
-
}).strict();
|
|
2759
|
-
var ConsoleStdin = z12.object({
|
|
2760
|
-
v: z12.literal(CONSOLE_FRAME_VERSION),
|
|
2761
|
-
/** Browser→box only. A `stdin` arriving from the box is `wrong-way`. */
|
|
2762
|
-
kind: z12.literal("stdin"),
|
|
2763
|
-
seq,
|
|
2764
|
-
data
|
|
2765
|
-
}).strict();
|
|
2766
|
-
var ConsoleStdout = z12.object({
|
|
2767
|
-
v: z12.literal(CONSOLE_FRAME_VERSION),
|
|
2768
|
-
/** Box→browser only. */
|
|
2769
|
-
kind: z12.literal("stdout"),
|
|
2770
|
-
seq,
|
|
2771
|
-
data
|
|
2772
|
-
}).strict();
|
|
2773
|
-
var ConsoleResize = z12.object({
|
|
2774
|
-
v: z12.literal(CONSOLE_FRAME_VERSION),
|
|
2775
|
-
kind: z12.literal("resize"),
|
|
2776
|
-
seq,
|
|
2777
|
-
cols,
|
|
2778
|
-
rows
|
|
2779
|
-
}).strict();
|
|
2780
|
-
var ConsoleBye = z12.object({
|
|
2781
|
-
v: z12.literal(CONSOLE_FRAME_VERSION),
|
|
2782
|
-
kind: z12.literal("bye"),
|
|
2783
|
-
seq,
|
|
2784
|
-
/** Shown to the owner in the session feed, so it is a sentence. */
|
|
2785
|
-
reason: z12.string().min(1).max(200)
|
|
2786
|
-
}).strict();
|
|
2787
|
-
var ConsoleFrame = z12.discriminatedUnion("kind", [
|
|
2788
|
-
ConsoleHello,
|
|
2789
|
-
ConsoleStdin,
|
|
2790
|
-
ConsoleStdout,
|
|
2791
|
-
ConsoleResize,
|
|
2792
|
-
ConsoleBye
|
|
2793
|
-
]);
|
|
2794
|
-
function consoleEnvelope(input) {
|
|
2795
|
-
return {
|
|
2796
|
-
jobId: input.sessionId,
|
|
2797
|
-
senderKeyId: input.senderKeyId,
|
|
2798
|
-
recipientKeyId: input.recipientKeyId,
|
|
2799
|
-
deadlineAt: input.deadlineAt,
|
|
2800
|
-
direction: input.from === "browser" ? "payload" : "result"
|
|
2801
|
-
};
|
|
2802
|
-
}
|
|
2803
|
-
function consoleOrder(from) {
|
|
2804
|
-
const maySend = {
|
|
2805
|
-
// The browser drives: it opens, it types, it sets the size, it leaves.
|
|
2806
|
-
browser: ["hello", "stdin", "resize", "bye"],
|
|
2807
|
-
// The box answers, and can end a session. Nothing else.
|
|
2808
|
-
box: ["stdout", "bye"]
|
|
2809
|
-
};
|
|
2810
|
-
const allowed = maySend[from];
|
|
2811
|
-
const opensWithHello = from === "browser";
|
|
2812
|
-
let last = 0;
|
|
2813
|
-
let closed = false;
|
|
2814
|
-
return {
|
|
2815
|
-
/** The last sequence accepted. 0 before anything has been. */
|
|
2816
|
-
get seen() {
|
|
2817
|
-
return last;
|
|
2818
|
-
},
|
|
2819
|
-
accept(frame) {
|
|
2820
|
-
if (closed) return { ok: false, fault: "closed" };
|
|
2821
|
-
if (!allowed.includes(frame.kind)) {
|
|
2822
|
-
return { ok: false, fault: "wrong-way" };
|
|
2823
|
-
}
|
|
2824
|
-
const isFirst = last === 0;
|
|
2825
|
-
const wantsHello = isFirst && opensWithHello;
|
|
2826
|
-
if (wantsHello !== (frame.kind === "hello")) {
|
|
2827
|
-
return { ok: false, fault: "out-of-turn" };
|
|
2828
|
-
}
|
|
2829
|
-
if (frame.seq <= last) return { ok: false, fault: "replayed" };
|
|
2830
|
-
if (frame.seq !== last + 1) return { ok: false, fault: "gap" };
|
|
2831
|
-
last = frame.seq;
|
|
2832
|
-
if (frame.kind === "bye") closed = true;
|
|
2833
|
-
return { ok: true };
|
|
2834
|
-
}
|
|
2835
|
-
};
|
|
2836
|
-
}
|
|
2837
2652
|
export {
|
|
2838
2653
|
ABOUT,
|
|
2839
2654
|
ABOUT_SHORT,
|