@ghostlytools/cli 1.3.2 → 1.3.4
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 -7
- package/SKILL.md +2 -1
- package/dist/assets/{api-SYPJgFRU.js → api-BCwaCbKh.js} +2 -2
- package/dist/assets/{api-aup3Amud.js → api-Bp_hWAiU.js} +100 -20
- package/dist/assets/api-Bp_hWAiU.js.map +1 -0
- package/dist/assets/{apiKit-DYkVEs6r.js → apiKit-3MLUyuhL.js} +21 -6
- package/dist/assets/apiKit-3MLUyuhL.js.map +1 -0
- package/dist/assets/{apps-DcZKu29s.js → apps-B6gqk4GD.js} +1 -1
- package/dist/assets/{apps-Rbk2HHXb.js → apps-BXw3Ui_3.js} +91 -24
- package/dist/assets/apps-BXw3Ui_3.js.map +1 -0
- package/dist/assets/{arkade-CuWlNnCz.js → arkade-CyplNY_v.js} +2 -2
- package/dist/assets/{arkade-CuWlNnCz.js.map → arkade-CyplNY_v.js.map} +1 -1
- package/dist/assets/{backup-CJWLDHuS.js → backup-BGE4BDzf.js} +6 -6
- package/dist/assets/{backup-CJWLDHuS.js.map → backup-BGE4BDzf.js.map} +1 -1
- package/dist/assets/{backup-CSMw2GHv.js → backup-Cm8ptQQA.js} +1 -1
- package/dist/assets/bark_ffi_wasm_bg-EY2uc0Bx.js.map +1 -1
- package/dist/assets/{buttons-QEnAGWoC.js → buttons-52NT4sA_.js} +4 -4
- package/dist/assets/{buttons-QEnAGWoC.js.map → buttons-52NT4sA_.js.map} +1 -1
- package/dist/assets/buttons-PCvHRlkS.js +2 -0
- package/dist/assets/{envelope-K27mzoyu.js → envelope-CsRRCrL3.js} +2 -2
- package/dist/assets/{envelope-K27mzoyu.js.map → envelope-CsRRCrL3.js.map} +1 -1
- package/dist/assets/{errors-DO5z6h_l.js → errors-B-zMxbcd.js} +6 -5
- package/dist/assets/{errors-DO5z6h_l.js.map → errors-B-zMxbcd.js.map} +1 -1
- package/dist/assets/fedimint_client_wasm_bg-BtHHlFpp.js.map +1 -1
- package/dist/assets/{ghostly_iroh_web-Dvzh3Y6E.js → ghostly_iroh_web-BsAEFIjl.js} +30 -36
- package/dist/assets/ghostly_iroh_web-BsAEFIjl.js.map +1 -0
- package/dist/assets/ghostly_iroh_web_bg.wasm +0 -0
- package/dist/assets/{groupFiles-DHTrTA4I.js → groupFiles-BurezP4Z.js} +47 -21
- package/dist/assets/{groupFiles-DHTrTA4I.js.map → groupFiles-BurezP4Z.js.map} +1 -1
- package/dist/assets/{host-C7hA-Za7.js → host-C74Sy5jT.js} +211 -42
- package/dist/assets/host-C74Sy5jT.js.map +1 -0
- package/dist/assets/{hyperdhtRelay-BVoWY2ua.js → hyperdhtRelay-D0MvfMzX.js} +2 -2
- package/dist/assets/{hyperdhtRelay-BVoWY2ua.js.map → hyperdhtRelay-D0MvfMzX.js.map} +1 -1
- package/dist/assets/{irohWeb-BJPk9bMn.js → irohWeb-DynqwRwl.js} +3 -3
- package/dist/assets/{irohWeb-BJPk9bMn.js.map → irohWeb-DynqwRwl.js.map} +1 -1
- package/dist/assets/{main-DC8cUkDx.js → main-DNzQOdNG.js} +168 -57
- package/dist/assets/main-DNzQOdNG.js.map +1 -0
- package/dist/assets/{mainline-CxbxpoU4.js → mainline-COqCHn1R.js} +2 -2
- package/dist/assets/{mainline-CxbxpoU4.js.map → mainline-COqCHn1R.js.map} +1 -1
- package/dist/assets/{networkReason-D42iNuUB.js → networkReason-WikfjkIw.js} +2 -2
- package/dist/assets/{networkReason-D42iNuUB.js.map → networkReason-WikfjkIw.js.map} +1 -1
- package/dist/assets/{nwc-Cm4sYgLv.js → nwc-ClsjYuyP.js} +3 -3
- package/dist/assets/{nwc-Cm4sYgLv.js.map → nwc-ClsjYuyP.js.map} +1 -1
- package/dist/assets/{nwcProvider-0D7vdPDd.js → nwcProvider-ksMYZra9.js} +2 -2
- package/dist/assets/{nwcProvider-0D7vdPDd.js.map → nwcProvider-ksMYZra9.js.map} +1 -1
- package/dist/assets/{profiles-BHc9pEYg.js → profiles-gPCjLOQq.js} +2 -2
- package/dist/assets/{profiles-BHc9pEYg.js.map → profiles-gPCjLOQq.js.map} +1 -1
- package/dist/assets/{registry-CVdSZW5l.js → registry-CJh9L_kF.js} +17 -32
- package/dist/assets/registry-CJh9L_kF.js.map +1 -0
- package/dist/assets/{registry-CLolR0kM.js → registry-S7SFF_JB.js} +1 -1
- package/dist/assets/{resolve-BnlEajYz.js → resolve-BJxBhU5j.js} +18 -3
- package/dist/assets/resolve-BJxBhU5j.js.map +1 -0
- package/dist/assets/{server-CJNEKxzE.js → server-C05N9q4G.js} +298 -100
- package/dist/assets/server-C05N9q4G.js.map +1 -0
- package/dist/assets/{src-yMUQvdyL.js → src-RQ6OJOUO.js} +322 -104
- package/dist/assets/src-RQ6OJOUO.js.map +1 -0
- package/dist/assets/{turnRefs-B2a8to9q.js → turnRefs-u-U75DFx.js} +2 -2
- package/dist/assets/{turnRefs-B2a8to9q.js.map → turnRefs-u-U75DFx.js.map} +1 -1
- package/dist/assets/{usdt-DesFeDiG.js → usdt-A1B3r3Mq.js} +3 -3
- package/dist/assets/{usdt-DesFeDiG.js.map → usdt-A1B3r3Mq.js.map} +1 -1
- package/dist/ghostly.mjs +1 -1
- package/package.json +1 -1
- package/dist/assets/api-aup3Amud.js.map +0 -1
- package/dist/assets/apiKit-DYkVEs6r.js.map +0 -1
- package/dist/assets/apps-Rbk2HHXb.js.map +0 -1
- package/dist/assets/buttons-CGRqZ7z0.js +0 -2
- package/dist/assets/ghostly_iroh_web-Dvzh3Y6E.js.map +0 -1
- package/dist/assets/host-C7hA-Za7.js.map +0 -1
- package/dist/assets/main-DC8cUkDx.js.map +0 -1
- package/dist/assets/registry-CVdSZW5l.js.map +0 -1
- package/dist/assets/resolve-BnlEajYz.js.map +0 -1
- package/dist/assets/server-CJNEKxzE.js.map +0 -1
- package/dist/assets/src-yMUQvdyL.js.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { xsalsa20poly1305 } from "@noble/ciphers/salsa.js";
|
|
2
2
|
import { ed25519, x25519 } from "@noble/curves/ed25519.js";
|
|
3
|
-
import { hkdf } from "@noble/hashes/hkdf.js";
|
|
4
3
|
import { sha256, sha512 } from "@noble/hashes/sha2.js";
|
|
4
|
+
import { hkdf } from "@noble/hashes/hkdf.js";
|
|
5
5
|
import { base58, base64, base64urlnopad, bech32, bech32m, createBase58check } from "@scure/base";
|
|
6
6
|
import { hmac } from "@noble/hashes/hmac.js";
|
|
7
7
|
import { hexToBytes } from "@noble/hashes/utils.js";
|
|
@@ -123,6 +123,19 @@ function fromZ32(str) {
|
|
|
123
123
|
}
|
|
124
124
|
return out;
|
|
125
125
|
}
|
|
126
|
+
/**
|
|
127
|
+
* A 32-byte key written as the one z-base-32 spelling `toZ32` produces: 52 characters that decode to 32 bytes and
|
|
128
|
+
* encode back to the same string. The last character carries four zero padding bits, so each key has exactly one
|
|
129
|
+
* spelling and keys may be compared as strings (WISP 02). Any other spelling is not a key here.
|
|
130
|
+
*/
|
|
131
|
+
function isZ32Key(value) {
|
|
132
|
+
if (typeof value !== "string" || value.length !== 52) return false;
|
|
133
|
+
try {
|
|
134
|
+
return toZ32(fromZ32(value)) === value;
|
|
135
|
+
} catch {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
126
139
|
function randomBytes(length) {
|
|
127
140
|
const bytes = new Uint8Array(length);
|
|
128
141
|
crypto.getRandomValues(bytes);
|
|
@@ -255,11 +268,26 @@ function tryDecrypt(encoded, key) {
|
|
|
255
268
|
return null;
|
|
256
269
|
}
|
|
257
270
|
}
|
|
258
|
-
|
|
259
|
-
|
|
271
|
+
/**
|
|
272
|
+
* Public keys already derived, by the SHA-256 of their seed, the most recently used last. A chat's start derives the
|
|
273
|
+
* same few seeds' keys again and again (its link, its delivery, its capability record): ~0.25 ms each in V8, ~3.4x
|
|
274
|
+
* that in JSC. The seed itself is never kept, so a seed its owner zeroes leaves nothing behind here.
|
|
275
|
+
*/
|
|
276
|
+
var publicKeys = /* @__PURE__ */ new Map();
|
|
277
|
+
function publicKeyOf(seed) {
|
|
278
|
+
const id = toBase64Url(sha256(seed));
|
|
279
|
+
let key = publicKeys.get(id);
|
|
280
|
+
if (key) publicKeys.delete(id);
|
|
281
|
+
else {
|
|
282
|
+
key = ed25519.getPublicKey(seed);
|
|
283
|
+
if (publicKeys.size >= 1024) publicKeys.delete(publicKeys.keys().next().value);
|
|
284
|
+
}
|
|
285
|
+
publicKeys.set(id, key);
|
|
286
|
+
return key.slice();
|
|
287
|
+
}
|
|
260
288
|
function identityFromSeed(seed) {
|
|
261
289
|
if (seed.length !== 32) throw new Error("Seed must be exactly 32 bytes");
|
|
262
|
-
const publicKey =
|
|
290
|
+
const publicKey = publicKeyOf(seed);
|
|
263
291
|
return {
|
|
264
292
|
seed,
|
|
265
293
|
seedB64: toBase64Url(seed),
|
|
@@ -276,7 +304,7 @@ function createIdentity() {
|
|
|
276
304
|
function publicKeyFromZ32(z32) {
|
|
277
305
|
if (z32.length !== 52) throw new Error("Invalid public key: expected 52 z-base-32 characters");
|
|
278
306
|
const bytes = fromZ32(z32);
|
|
279
|
-
if (bytes
|
|
307
|
+
if (toZ32(bytes) !== z32) throw new Error("Invalid public key: not canonical z-base-32");
|
|
280
308
|
return bytes;
|
|
281
309
|
}
|
|
282
310
|
function sign(message, seed) {
|
|
@@ -3016,7 +3044,6 @@ function readGhostly(code) {
|
|
|
3016
3044
|
};
|
|
3017
3045
|
}
|
|
3018
3046
|
var B64_KEY = /^[A-Za-z0-9_-]{43}$/;
|
|
3019
|
-
var Z32_KEY$1 = /^[ybndrfg8ejkmcpqxot1uwisza345h769]{52}$/;
|
|
3020
3047
|
function readSlashForm(code) {
|
|
3021
3048
|
const dht = code.startsWith("pair2d/");
|
|
3022
3049
|
const profile = dht || code.startsWith("pair1/") ? "paired-chat/1" : void 0;
|
|
@@ -3030,7 +3057,7 @@ function readSlashForm(code) {
|
|
|
3030
3057
|
reason: "not-ghostly"
|
|
3031
3058
|
};
|
|
3032
3059
|
const [seedB64, peerPubKeyZ32, encKeyB64] = parts;
|
|
3033
|
-
const bad = !B64_KEY.test(seedB64) ? "The seed" : !
|
|
3060
|
+
const bad = !B64_KEY.test(seedB64) ? "The seed" : !isZ32Key(peerPubKeyZ32) ? "The contact's key" : !B64_KEY.test(encKeyB64) ? "The shared key" : null;
|
|
3034
3061
|
if (bad) return {
|
|
3035
3062
|
ok: false,
|
|
3036
3063
|
reason: "damaged",
|
|
@@ -3313,7 +3340,7 @@ var ENROLL_CANCEL_REASONS = [
|
|
|
3313
3340
|
"full",
|
|
3314
3341
|
"failed"
|
|
3315
3342
|
];
|
|
3316
|
-
var KEY$
|
|
3343
|
+
var KEY$3 = /^[A-Za-z0-9_-]{43}$/;
|
|
3317
3344
|
var SIGNATURE$2 = /^[A-Za-z0-9_-]{86}$/;
|
|
3318
3345
|
var HASH$3 = /^[0-9a-f]{64}$/;
|
|
3319
3346
|
function checkKey(key, who) {
|
|
@@ -3363,7 +3390,7 @@ async function enrollHelloFrame(transcriptHash, inviterKey, joiner, about) {
|
|
|
3363
3390
|
* key's over this session's tuple. Null for anything else.
|
|
3364
3391
|
*/
|
|
3365
3392
|
function readEnrollHello(frame, transcriptHash, inviterKey, sessionKey) {
|
|
3366
|
-
if (frame.t !== "enroll-hello" || typeof frame.k !== "string" || !KEY$
|
|
3393
|
+
if (frame.t !== "enroll-hello" || typeof frame.k !== "string" || !KEY$3.test(frame.k) || typeof frame.s !== "string" || !SIGNATURE$2.test(frame.s)) return null;
|
|
3367
3394
|
if (typeof frame.name !== "string" || frame.name.length > 64 || typeof frame.app !== "string" || frame.app.length > 32) return null;
|
|
3368
3395
|
const key = fromBase64Url(frame.k);
|
|
3369
3396
|
if (key.length !== 32 || toBase64Url(key) !== toBase64Url(sessionKey)) return null;
|
|
@@ -3445,7 +3472,7 @@ function enrollGrantFrame(grant) {
|
|
|
3445
3472
|
* once and the inviter once, and a turn and `rev` an ordinary record can have. Null for anything else.
|
|
3446
3473
|
*/
|
|
3447
3474
|
function readEnrollGrant(frame, inviterKey, joinerKey) {
|
|
3448
|
-
if (frame.t !== "enroll-grant" || typeof frame.d !== "string" || !KEY$
|
|
3475
|
+
if (frame.t !== "enroll-grant" || typeof frame.d !== "string" || !KEY$3.test(frame.d) || !Array.isArray(frame.set) || frame.set.length > 4) return null;
|
|
3449
3476
|
if (!Number.isInteger(frame.turn) || frame.turn < 0 || frame.turn > TURN_MAX) return null;
|
|
3450
3477
|
if (!Number.isInteger(frame.rev) || frame.rev < 0 || frame.rev >= TURN_REV_LIMIT) return null;
|
|
3451
3478
|
const set = [];
|
|
@@ -3454,7 +3481,7 @@ function readEnrollGrant(frame, inviterKey, joinerKey) {
|
|
|
3454
3481
|
set.push(null);
|
|
3455
3482
|
continue;
|
|
3456
3483
|
}
|
|
3457
|
-
if (!Array.isArray(slot) || slot.length !== 2 || typeof slot[0] !== "string" || !KEY$
|
|
3484
|
+
if (!Array.isArray(slot) || slot.length !== 2 || typeof slot[0] !== "string" || !KEY$3.test(slot[0]) || typeof slot[1] !== "string" || slot[1].length > 64) return null;
|
|
3458
3485
|
set.push({
|
|
3459
3486
|
key: fromBase64Url(slot[0]),
|
|
3460
3487
|
name: turnName(slot[1])
|
|
@@ -3491,7 +3518,7 @@ function enrollCancelReason(frame) {
|
|
|
3491
3518
|
//#region ../core/src/setUpdate.ts
|
|
3492
3519
|
var SET_UPDATE = "set-update";
|
|
3493
3520
|
var SET_ACK = "set-ack";
|
|
3494
|
-
var KEY$
|
|
3521
|
+
var KEY$2 = /^[A-Za-z0-9_-]{43}$/;
|
|
3495
3522
|
var SIGNATURE$1 = /^[A-Za-z0-9_-]{86}$/;
|
|
3496
3523
|
/** A tombstone packet is a relay payload of 706 bytes (WISP 06 § Record); a little room above it, nothing more. */
|
|
3497
3524
|
var TOMB = /^[A-Za-z0-9_-]{100,1400}$/;
|
|
@@ -3543,7 +3570,7 @@ async function setUpdateFrame(oldAddress, update, signer) {
|
|
|
3543
3570
|
* here: that needs the old turn address (`verifySetUpdate`).
|
|
3544
3571
|
*/
|
|
3545
3572
|
function readSetUpdate(frame) {
|
|
3546
|
-
if (frame.t !== "set-update" || typeof frame.d !== "string" || !KEY$
|
|
3573
|
+
if (frame.t !== "set-update" || typeof frame.d !== "string" || !KEY$2.test(frame.d) || typeof frame.by !== "string" || !KEY$2.test(frame.by)) return null;
|
|
3547
3574
|
if (typeof frame.s !== "string" || !SIGNATURE$1.test(frame.s) || typeof frame.tomb !== "string" || !TOMB.test(frame.tomb)) return null;
|
|
3548
3575
|
if (!Array.isArray(frame.set) || frame.set.length > 4) return null;
|
|
3549
3576
|
if (frame.rec !== void 0 && (typeof frame.rec !== "string" || !TOMB.test(frame.rec))) return null;
|
|
@@ -3557,7 +3584,7 @@ function readSetUpdate(frame) {
|
|
|
3557
3584
|
signed.push(null);
|
|
3558
3585
|
continue;
|
|
3559
3586
|
}
|
|
3560
|
-
if (!Array.isArray(slot) || slot.length !== 2 || typeof slot[0] !== "string" || !KEY$
|
|
3587
|
+
if (!Array.isArray(slot) || slot.length !== 2 || typeof slot[0] !== "string" || !KEY$2.test(slot[0]) || typeof slot[1] !== "string" || slot[1].length > 64) return null;
|
|
3561
3588
|
if (utf8Encode(slot[1]).length > 16 || slot[1].includes("\0")) return null;
|
|
3562
3589
|
signed.push([slot[0], slot[1]]);
|
|
3563
3590
|
set.push({
|
|
@@ -3662,8 +3689,8 @@ var HANDOFF_CANCEL_REASONS = [
|
|
|
3662
3689
|
"password",
|
|
3663
3690
|
"stalled"
|
|
3664
3691
|
];
|
|
3665
|
-
var KEY$
|
|
3666
|
-
var DIGEST$2 = KEY$
|
|
3692
|
+
var KEY$1 = /^[A-Za-z0-9_-]{43}$/;
|
|
3693
|
+
var DIGEST$2 = KEY$1;
|
|
3667
3694
|
var SIGNATURE = /^[A-Za-z0-9_-]{86}$/;
|
|
3668
3695
|
var ID$5 = /^[A-Za-z0-9_-]{22}$/;
|
|
3669
3696
|
var B64$4 = /^[A-Za-z0-9_-]*$/;
|
|
@@ -3798,7 +3825,7 @@ function handoffHelloFrame(hello) {
|
|
|
3798
3825
|
}
|
|
3799
3826
|
function readHandoffHello(frame) {
|
|
3800
3827
|
if (frame.t !== "handoff-hello" || frame.v !== 1) return null;
|
|
3801
|
-
if (!isText$2(frame.e, KEY$
|
|
3828
|
+
if (!isText$2(frame.e, KEY$1) || fromBase64Url(frame.e).length !== 32) return null;
|
|
3802
3829
|
if (!isText$2(frame.app, VERSION_TEXT) || !isCount$1(frame.db, 1e6) || !isPins(frame.pins)) return null;
|
|
3803
3830
|
if (typeof frame.room !== "number" || !Number.isSafeInteger(frame.room) || frame.room < -1) return null;
|
|
3804
3831
|
if (typeof frame.metered !== "boolean") return null;
|
|
@@ -3864,7 +3891,7 @@ function readHandoffPake(frame) {
|
|
|
3864
3891
|
wrong: true
|
|
3865
3892
|
} : null;
|
|
3866
3893
|
if (!isText$2(frame.m, B64$4) || !frame.m.length || frame.m.length > 4096) return null;
|
|
3867
|
-
if (frame.n === 3 && !isText$2(frame.c, KEY$
|
|
3894
|
+
if (frame.n === 3 && !isText$2(frame.c, KEY$1)) return null;
|
|
3868
3895
|
return {
|
|
3869
3896
|
n: frame.n,
|
|
3870
3897
|
m: frame.m,
|
|
@@ -4656,8 +4683,12 @@ function buildSdpFromSignal(signal) {
|
|
|
4656
4683
|
function sdpHasCandidates(sdp) {
|
|
4657
4684
|
return /^a=candidate:/m.test(sdp ?? "");
|
|
4658
4685
|
}
|
|
4659
|
-
/**
|
|
4660
|
-
|
|
4686
|
+
/**
|
|
4687
|
+
* How long to keep collecting after the candidate we were waiting for showed up (a call's; a chat's data link sets its
|
|
4688
|
+
* own, the same). The host candidates are in before it, and a call's signal keeps the first reflexive one only
|
|
4689
|
+
* (`pickCallCandidates`): 400 ms held every call's offer, and its answer, back that long for nothing it carried.
|
|
4690
|
+
*/
|
|
4691
|
+
var ICE_SETTLE_MS = 150;
|
|
4661
4692
|
/** IPv4 ranges that are not reachable from the internet: this network, private, shared (CGNAT), loopback, link-local, the documentation ones, benchmarking, multicast and up. */
|
|
4662
4693
|
var NOT_GLOBAL_IPV4 = [
|
|
4663
4694
|
[0, 8],
|
|
@@ -7160,7 +7191,11 @@ function edgeParams(groupId, mySeed, myZ32, peerZ32) {
|
|
|
7160
7191
|
var GROUP_MEMBER_CAP = { max: 32 };
|
|
7161
7192
|
var MAX_GROUP_CHAIN = 1024;
|
|
7162
7193
|
var GROUP_ID = /^[A-Za-z0-9_-]{22}$/;
|
|
7163
|
-
|
|
7194
|
+
/**
|
|
7195
|
+
* A member's key, in its one canonical spelling (`isZ32Key`): a roster names members by string, so a key respelled in
|
|
7196
|
+
* its last character would be a second member for one key, and `publicKeyFromZ32` would throw on it past this check.
|
|
7197
|
+
*/
|
|
7198
|
+
var MEMBER_KEY = { test: isZ32Key };
|
|
7164
7199
|
var TAG$1 = /^[A-Za-z0-9_-]{43}$/;
|
|
7165
7200
|
var SIG$6 = /^[A-Za-z0-9_-]{86}$/;
|
|
7166
7201
|
var HASH$2 = /^[a-f0-9]{64}$/;
|
|
@@ -8861,7 +8896,15 @@ var IMAGE_LIMITS = {
|
|
|
8861
8896
|
/** Pixels on either side: the most a JPEG can say, well past what anyone sends as a picture. */
|
|
8862
8897
|
maxEdge: 65535,
|
|
8863
8898
|
/** How much of a file is read for its size: past a JPEG's EXIF, thumbnails and colour profile. */
|
|
8864
|
-
headBytes: 262144
|
|
8899
|
+
headBytes: 262144,
|
|
8900
|
+
/**
|
|
8901
|
+
* The most pixels a picture drawn in a chat may have: a 50-megapixel phone photo (8160 × 6120), about 200 MB once
|
|
8902
|
+
* decoded. A few kilobytes can say far more (a PNG of 23000 × 23000 is 64 KB and 2 GB decoded): past this a picture
|
|
8903
|
+
* is kept and saved, not drawn.
|
|
8904
|
+
*/
|
|
8905
|
+
previewPixels: 5e7,
|
|
8906
|
+
/** The longest side a picture drawn in a chat may have: a wide panorama. */
|
|
8907
|
+
previewEdge: 16384
|
|
8865
8908
|
};
|
|
8866
8909
|
/** Whether a file is a picture, by its type. */
|
|
8867
8910
|
function isImageMime(mime) {
|
|
@@ -10654,6 +10697,7 @@ var PairedFiles = class {
|
|
|
10654
10697
|
return;
|
|
10655
10698
|
}
|
|
10656
10699
|
if (active) throw new Error("Duplicate active file");
|
|
10700
|
+
if (this.events.replaced?.()) throw new Error("files/3 replaces files/2 on this session");
|
|
10657
10701
|
if (typeof frame.name !== "string" || frame.name.length > 1e3 || typeof frame.mime !== "string" || frame.mime.length > 130 || typeof frame.size !== "number" || !Number.isSafeInteger(frame.size) || frame.size < 0 || frame.size > LIMITS.maxFileBytes || typeof frame.timestamp !== "number" || !Number.isSafeInteger(frame.timestamp) || frame.timestamp <= 0 || this.incoming.size >= LIMITS.maxIncomingFilesPerPeer) throw new Error("Invalid file announcement");
|
|
10658
10702
|
const file = {
|
|
10659
10703
|
id,
|
|
@@ -10674,6 +10718,9 @@ var PairedFiles = class {
|
|
|
10674
10718
|
if (forwarded) file.forwarded = forwarded;
|
|
10675
10719
|
const stored = await this.events.onStored?.(file);
|
|
10676
10720
|
if (this.closed) return;
|
|
10721
|
+
const room = stored ? null : await this.events.room?.().catch(() => null) ?? null;
|
|
10722
|
+
if (this.closed) return;
|
|
10723
|
+
if (room !== null && file.size > room) throw new Error("No room for this file");
|
|
10677
10724
|
const sink = stored ? null : this.events.onIncoming(file);
|
|
10678
10725
|
if (!stored && (!sink || typeof sink === "string")) throw new Error(typeof sink === "string" ? sink : "File refused");
|
|
10679
10726
|
const entry = {
|
|
@@ -11811,10 +11858,10 @@ var IDENTITY_MAX_VALIDITY = 3456e4;
|
|
|
11811
11858
|
var IDENTITY_MAX_EVIDENCE = 16384;
|
|
11812
11859
|
/** Unanswered challenges a verifier keeps per conversation. */
|
|
11813
11860
|
var MAX_CHALLENGES = 8;
|
|
11861
|
+
var IDENTITY_FRAME_WINDOW_MS = 6e4;
|
|
11814
11862
|
var IDENTITY_PROVIDER_ID = /^[a-z][a-z0-9-]{0,31}$/;
|
|
11815
11863
|
/** Printable ASCII without spaces, so the statement can be built but never needs parsing. */
|
|
11816
11864
|
var IDENTITY_SUBJECT = /^[\x21-\x7e]{1,512}$/;
|
|
11817
|
-
var KEY$2 = /^[ybndrfg8ejkmcpqxot1uwisza345h769]{52}$/;
|
|
11818
11865
|
var BINDING_NONCE = /^[A-Za-z0-9_-]{22}$/;
|
|
11819
11866
|
var CHALLENGE_NONCE = /^[A-Za-z0-9_-]{43}$/;
|
|
11820
11867
|
var HEX64$2 = /^[a-f0-9]{64}$/;
|
|
@@ -11836,7 +11883,7 @@ var iso = (seconds) => (/* @__PURE__ */ new Date(seconds * 1e3)).toISOString().r
|
|
|
11836
11883
|
var isInt$2 = (v) => Number.isSafeInteger(v) && v > 0;
|
|
11837
11884
|
function isIdentityBinding(value) {
|
|
11838
11885
|
const b = value;
|
|
11839
|
-
return !!b && typeof b === "object" && !Array.isArray(b) && Object.keys(b).sort().join(",") === "expiresAt,issuedAt,key,nonce,provider,subject,v" && b.v === 1 && typeof b.provider === "string" && IDENTITY_PROVIDER_ID.test(b.provider) && typeof b.subject === "string" && IDENTITY_SUBJECT.test(b.subject) &&
|
|
11886
|
+
return !!b && typeof b === "object" && !Array.isArray(b) && Object.keys(b).sort().join(",") === "expiresAt,issuedAt,key,nonce,provider,subject,v" && b.v === 1 && typeof b.provider === "string" && IDENTITY_PROVIDER_ID.test(b.provider) && typeof b.subject === "string" && IDENTITY_SUBJECT.test(b.subject) && isZ32Key(b.key) && typeof b.nonce === "string" && BINDING_NONCE.test(b.nonce) && isInt$2(b.issuedAt) && isInt$2(b.expiresAt) && b.expiresAt > b.issuedAt && b.expiresAt - b.issuedAt <= 3456e4 && b.expiresAt < 253402300800;
|
|
11840
11887
|
}
|
|
11841
11888
|
/**
|
|
11842
11889
|
* The canonical statement, one line, so it survives every tool and clipboard (no line-ending
|
|
@@ -11896,7 +11943,7 @@ function signIdentityPresentation(seed, proofId, scope, nonce, issuedAt) {
|
|
|
11896
11943
|
return toBase64Url(sign(identityPresentationBytes(proofId, scope, nonce, issuedAt), seed));
|
|
11897
11944
|
}
|
|
11898
11945
|
function verifyIdentityPresentation(key, sig, proofId, scope, nonce, issuedAt) {
|
|
11899
|
-
if (typeof sig !== "string" || !SIG$5.test(sig) || !
|
|
11946
|
+
if (typeof sig !== "string" || !SIG$5.test(sig) || !isZ32Key(key)) return false;
|
|
11900
11947
|
return verify(fromBase64Url(sig), identityPresentationBytes(proofId, scope, nonce, issuedAt), publicKeyFromZ32(key));
|
|
11901
11948
|
}
|
|
11902
11949
|
var clean$1 = (value, max) => {
|
|
@@ -11949,6 +11996,18 @@ function receivedIdentityStatus(r, presenter, audience, now = nowSeconds()) {
|
|
|
11949
11996
|
if (Math.min(r.binding.expiresAt, r.verified.expiresAt ?? Infinity) <= now) return "expired";
|
|
11950
11997
|
return r.status === "unconfirmed" ? "unconfirmed" : "verified";
|
|
11951
11998
|
}
|
|
11999
|
+
var standing = (r, now) => r.status !== "withdrawn" && r.status !== "revoked" && Math.min(r.binding.expiresAt, r.verified.expiresAt ?? Infinity) > now;
|
|
12000
|
+
/**
|
|
12001
|
+
* `received` with room for one more proof: `replaced` (the older proof of the same identity) dropped, then the oldest ones
|
|
12002
|
+
* no longer standing; undefined when every place is still taken.
|
|
12003
|
+
*/
|
|
12004
|
+
function receivedWithRoom(received, id, replaced, now) {
|
|
12005
|
+
const kept = received.filter((r) => r.id !== id && !replaced(r));
|
|
12006
|
+
const gone = kept.filter((r) => !standing(r, now)).sort((a, b) => a.verifiedAt - b.verifiedAt);
|
|
12007
|
+
const drop = new Set(gone.slice(0, Math.max(0, kept.length - 16 + 1)));
|
|
12008
|
+
const out = kept.filter((r) => !drop.has(r));
|
|
12009
|
+
return out.length < 16 ? out : void 0;
|
|
12010
|
+
}
|
|
11952
12011
|
var shortError = (e) => clean$1(e instanceof Error ? e.message : String(e), 160) ?? "Invalid proof";
|
|
11953
12012
|
/**
|
|
11954
12013
|
* A check this side could not finish because of what its own network did: a host it refused to contact, a server
|
|
@@ -11964,6 +12023,7 @@ var IdentityCheckUnavailable = class extends Error {
|
|
|
11964
12023
|
};
|
|
11965
12024
|
/** What the contact is told when the check failed with an IdentityCheckUnavailable. */
|
|
11966
12025
|
var IDENTITY_CHECK_UNAVAILABLE = "Your contact's app could not check it. Try again later.";
|
|
12026
|
+
var TOO_MANY_RECEIVED = "Your contact keeps too many identities from you already";
|
|
11967
12027
|
var peerError = (e) => e instanceof IdentityCheckUnavailable ? IDENTITY_CHECK_UNAVAILABLE : shortError(e);
|
|
11968
12028
|
/**
|
|
11969
12029
|
* The `idp-*` exchange of one conversation. Frames (all JSON, additive, over the paired channel,
|
|
@@ -12188,31 +12248,29 @@ var IdentityExchange = class {
|
|
|
12188
12248
|
});
|
|
12189
12249
|
return;
|
|
12190
12250
|
}
|
|
12191
|
-
case "idp-withdraw":
|
|
12251
|
+
case "idp-withdraw": {
|
|
12192
12252
|
if (!id) return;
|
|
12193
|
-
|
|
12194
|
-
|
|
12195
|
-
|
|
12196
|
-
|
|
12197
|
-
|
|
12198
|
-
|
|
12199
|
-
|
|
12200
|
-
|
|
12201
|
-
|
|
12202
|
-
|
|
12203
|
-
|
|
12204
|
-
|
|
12205
|
-
|
|
12206
|
-
|
|
12207
|
-
|
|
12208
|
-
reason: "withdrawn"
|
|
12209
|
-
}) : next;
|
|
12210
|
-
});
|
|
12253
|
+
const r = this.options.storage.read().received.find((x) => x.id === id);
|
|
12254
|
+
if (r && r.status !== "withdrawn") await this.options.storage.update((l) => this.log({
|
|
12255
|
+
...l,
|
|
12256
|
+
received: l.received.map((x) => x.id === id ? {
|
|
12257
|
+
...x,
|
|
12258
|
+
status: "withdrawn"
|
|
12259
|
+
} : x)
|
|
12260
|
+
}, {
|
|
12261
|
+
type: "stopped",
|
|
12262
|
+
side: "theirs",
|
|
12263
|
+
proof: id,
|
|
12264
|
+
provider: r.binding.provider,
|
|
12265
|
+
subject: r.verified.subject,
|
|
12266
|
+
reason: "withdrawn"
|
|
12267
|
+
}));
|
|
12211
12268
|
this.send({
|
|
12212
12269
|
t: "idp-withdrawn",
|
|
12213
12270
|
id
|
|
12214
12271
|
});
|
|
12215
12272
|
return;
|
|
12273
|
+
}
|
|
12216
12274
|
case "idp-withdrawn": {
|
|
12217
12275
|
const s = id ? this.shared(id) : void 0;
|
|
12218
12276
|
if (s?.status === "withdrawal-pending") await this.setShared({
|
|
@@ -12230,25 +12288,11 @@ var IdentityExchange = class {
|
|
|
12230
12288
|
async onRequest(id, provider) {
|
|
12231
12289
|
if (!id) return;
|
|
12232
12290
|
if (typeof provider !== "string" || !this.options.providers().includes(provider)) {
|
|
12233
|
-
const error = "Your contact's app cannot verify this kind of identity yet";
|
|
12234
|
-
if (typeof provider === "string" && IDENTITY_PROVIDER_ID.test(provider)) await this.options.storage.update((l) => this.log(this.log(l, {
|
|
12235
|
-
type: "shared",
|
|
12236
|
-
side: "theirs",
|
|
12237
|
-
proof: id,
|
|
12238
|
-
provider
|
|
12239
|
-
}), {
|
|
12240
|
-
type: "result",
|
|
12241
|
-
side: "theirs",
|
|
12242
|
-
proof: id,
|
|
12243
|
-
provider,
|
|
12244
|
-
ok: false,
|
|
12245
|
-
error: "This app cannot verify this kind of identity yet"
|
|
12246
|
-
}));
|
|
12247
12291
|
this.send({
|
|
12248
12292
|
t: "idp-result",
|
|
12249
12293
|
id,
|
|
12250
12294
|
ok: false,
|
|
12251
|
-
error
|
|
12295
|
+
error: "Your contact's app cannot verify this kind of identity yet"
|
|
12252
12296
|
});
|
|
12253
12297
|
return;
|
|
12254
12298
|
}
|
|
@@ -12334,6 +12378,8 @@ var IdentityExchange = class {
|
|
|
12334
12378
|
/** The same, as this side's own timeline says it. */
|
|
12335
12379
|
let reason;
|
|
12336
12380
|
try {
|
|
12381
|
+
const mayReplace = (r) => r.binding.provider === binding.provider && (r.binding.subject === binding.subject || r.verified.subject === binding.subject);
|
|
12382
|
+
if (!receivedWithRoom(this.options.storage.read().received, id, mayReplace, now)) throw new Error(TOO_MANY_RECEIVED);
|
|
12337
12383
|
if (JSON.stringify(evidence ?? null).length > 16384) throw new Error("Evidence too large");
|
|
12338
12384
|
if (!verifyIdentityPresentation(binding.key, sig, id, scope, nonce, issuedAt)) throw new Error("The proof key did not sign this conversation's challenge");
|
|
12339
12385
|
if (binding.issuedAt > now + 300) throw new Error("The proof is dated in the future");
|
|
@@ -12349,6 +12395,12 @@ var IdentityExchange = class {
|
|
|
12349
12395
|
const challenge = challengeOf(l);
|
|
12350
12396
|
if (!challenge) throw new Error("Unknown or reused identity challenge");
|
|
12351
12397
|
const challenges = l.challenges.filter((c) => c.nonce !== nonce);
|
|
12398
|
+
const subject = verified?.subject;
|
|
12399
|
+
const received = verified && receivedWithRoom(l.received, id, (r) => r.binding.provider === binding.provider && r.verified.subject === subject, now);
|
|
12400
|
+
if (verified && !received) {
|
|
12401
|
+
verified = void 0;
|
|
12402
|
+
error = reason = TOO_MANY_RECEIVED;
|
|
12403
|
+
}
|
|
12352
12404
|
const logged = this.log(l, {
|
|
12353
12405
|
type: "result",
|
|
12354
12406
|
side: "theirs",
|
|
@@ -12359,7 +12411,7 @@ var IdentityExchange = class {
|
|
|
12359
12411
|
ok: !!verified,
|
|
12360
12412
|
...reason ? { error: reason } : {}
|
|
12361
12413
|
});
|
|
12362
|
-
if (!verified) return {
|
|
12414
|
+
if (!verified || !received) return {
|
|
12363
12415
|
...logged,
|
|
12364
12416
|
challenges
|
|
12365
12417
|
};
|
|
@@ -12375,7 +12427,6 @@ var IdentityExchange = class {
|
|
|
12375
12427
|
checkedAt: now,
|
|
12376
12428
|
status: "verified"
|
|
12377
12429
|
};
|
|
12378
|
-
const received = l.received.filter((r) => r.id !== id && !(r.binding.provider === binding.provider && r.verified.subject === verified.subject));
|
|
12379
12430
|
return {
|
|
12380
12431
|
...logged,
|
|
12381
12432
|
challenges,
|
|
@@ -12465,8 +12516,7 @@ var CapsRefusedError = class extends Error {
|
|
|
12465
12516
|
var IDENT = /^[a-z0-9][a-z0-9._-]*\/[0-9]+$/;
|
|
12466
12517
|
var HEX64$1 = /^[0-9a-f]{64}$/;
|
|
12467
12518
|
var SIG$4 = /^[A-Za-z0-9_-]{86}$/;
|
|
12468
|
-
var
|
|
12469
|
-
var KEY$1 = /^[A-Za-z0-9_-]{43}$/;
|
|
12519
|
+
var KEY = /^[A-Za-z0-9_-]{43}$/;
|
|
12470
12520
|
var hexToKey = (hex) => toBase64Url(Uint8Array.from(hex.match(/../g), (b) => parseInt(b, 16)));
|
|
12471
12521
|
var keyToHex = (key) => Array.from(fromBase64Url(key), (b) => b.toString(16).padStart(2, "0")).join("");
|
|
12472
12522
|
/**
|
|
@@ -12518,14 +12568,14 @@ function parseDescriptors(value) {
|
|
|
12518
12568
|
const out = {};
|
|
12519
12569
|
const iroh = raw["iroh/1"], hyper = raw["hyperdht/1"];
|
|
12520
12570
|
if (iroh !== void 0) {
|
|
12521
|
-
if (!iroh || typeof iroh.id !== "string" || !KEY
|
|
12571
|
+
if (!iroh || typeof iroh.id !== "string" || !KEY.test(iroh.id) || iroh.relay !== void 0 && (typeof iroh.relay !== "string" || !RELAY_URL.test(iroh.relay))) return null;
|
|
12522
12572
|
out["iroh/1"] = {
|
|
12523
12573
|
id: iroh.id,
|
|
12524
12574
|
...iroh.relay !== void 0 ? { relay: iroh.relay } : {}
|
|
12525
12575
|
};
|
|
12526
12576
|
}
|
|
12527
12577
|
if (hyper !== void 0) {
|
|
12528
|
-
if (!hyper || typeof hyper.publicKey !== "string" || !KEY
|
|
12578
|
+
if (!hyper || typeof hyper.publicKey !== "string" || !KEY.test(hyper.publicKey) || hyper.relay !== void 0 && (typeof hyper.relay !== "string" || !RELAY_URL.test(hyper.relay))) return null;
|
|
12529
12579
|
out["hyperdht/1"] = {
|
|
12530
12580
|
publicKey: hyper.publicKey,
|
|
12531
12581
|
...hyper.relay !== void 0 ? { relay: hyper.relay } : {}
|
|
@@ -12669,7 +12719,7 @@ var CapsKeys = class {
|
|
|
12669
12719
|
if (body.length < 10 || body.length > 16) throw new CapsRefusedError("format", "Malformed capability record.");
|
|
12670
12720
|
const [version, rev, issued, author, versions, transports, capabilities, extensions, rawDescriptors, name, choice] = body;
|
|
12671
12721
|
const descriptors = parseDescriptors(rawDescriptors);
|
|
12672
|
-
if (version !== 1 || !Number.isSafeInteger(rev) || rev < 0 || !Number.isSafeInteger(issued) || issued <= 0 ||
|
|
12722
|
+
if (version !== 1 || !Number.isSafeInteger(rev) || rev < 0 || !Number.isSafeInteger(issued) || issued <= 0 || !isZ32Key(author) || !list$2(versions, CAPS_LIMITS.versions, (v) => Number.isSafeInteger(v) && v > 0) || !list$2(transports, CAPS_LIMITS.transports, ident) || transports.includes("dht/1") || !list$2(capabilities, CAPS_LIMITS.capabilities, ident) || !list$2(extensions, CAPS_LIMITS.extensions, ident) || !descriptors || typeof name !== "string" || utf8Encode(name).length > CAPS_LIMITS.nameBytes || choice !== void 0 && (!ident(choice) || choice === "dht/1")) throw new CapsRefusedError("format", "Malformed capability record.");
|
|
12673
12723
|
const signer = options.pinned ?? options.expected;
|
|
12674
12724
|
if (signer && author !== signer) throw new CapsRefusedError("author", "The capability record is signed by another participation key than this contact's.");
|
|
12675
12725
|
try {
|
|
@@ -13615,13 +13665,12 @@ var SESSION_RECEIVE_PENDING = {
|
|
|
13615
13665
|
frames: 1024,
|
|
13616
13666
|
bytes: 64 * SESSION_FRAME_MAX
|
|
13617
13667
|
};
|
|
13618
|
-
var KEY = /^[ybndrfg8ejkmcpqxot1uwisza345h769]{52}$/;
|
|
13619
13668
|
var NONCE$1 = /^[A-Za-z0-9_-]{43}$/;
|
|
13620
13669
|
var SIG$2 = /^[A-Za-z0-9_-]{86}$/;
|
|
13621
13670
|
var FINGERPRINT = /^[a-f0-9]{64}$/;
|
|
13622
13671
|
var isList = (v, maximum = 8) => Array.isArray(v) && v.length > 0 && v.length <= maximum && v.every((x) => typeof x === "string" && /^[a-z0-9/-]{1,40}$/.test(x)) && new Set(v).size === v.length;
|
|
13623
13672
|
function parseOffer(v) {
|
|
13624
|
-
if (!Array.isArray(v.versions) || v.versions.length === 0 || v.versions.length > 8 || !v.versions.every((n) => Number.isSafeInteger(n) && n > 0) || new Set(v.versions).size !== v.versions.length || !isList(v.transports) || !isList(v.capabilities, 32) ||
|
|
13673
|
+
if (!Array.isArray(v.versions) || v.versions.length === 0 || v.versions.length > 8 || !v.versions.every((n) => Number.isSafeInteger(n) && n > 0) || new Set(v.versions).size !== v.versions.length || !isList(v.transports) || !isList(v.capabilities, 32) || !isZ32Key(v.key) || typeof v.nonce !== "string" || !NONCE$1.test(v.nonce)) return null;
|
|
13625
13674
|
const extensions = isList(v.extensions, 32) ? v.extensions : void 0;
|
|
13626
13675
|
return {
|
|
13627
13676
|
t: "pair-offer",
|
|
@@ -13752,7 +13801,7 @@ var PairedSession = class {
|
|
|
13752
13801
|
}
|
|
13753
13802
|
start() {
|
|
13754
13803
|
const binding = this.options.binding;
|
|
13755
|
-
if (!(binding ? (binding.transport === "hyperdht/1" ? /^[a-f0-9]{128}$/.test(binding.context) : FINGERPRINT.test(binding.context)) && binding.identities.length === 2 && binding.identities.every((k) => FINGERPRINT.test(k)) && binding.identities[0] !== binding.identities[1] : this.options.fingerprints?.length === 2 && this.options.fingerprints.every((f) => FINGERPRINT.test(f))) || !this.offer.transports.includes(this.transport) || this.options.rendezvousKeys.some((k) => !
|
|
13804
|
+
if (!(binding ? (binding.transport === "hyperdht/1" ? /^[a-f0-9]{128}$/.test(binding.context) : FINGERPRINT.test(binding.context)) && binding.identities.length === 2 && binding.identities.every((k) => FINGERPRINT.test(k)) && binding.identities[0] !== binding.identities[1] : this.options.fingerprints?.length === 2 && this.options.fingerprints.every((f) => FINGERPRINT.test(f))) || !this.offer.transports.includes(this.transport) || this.options.rendezvousKeys.some((k) => !isZ32Key(k))) return this.fail("Invalid connection binding or unavailable transport");
|
|
13756
13805
|
this.channel.onMessage = (data) => {
|
|
13757
13806
|
if (this.stopped) return;
|
|
13758
13807
|
const size = data.length;
|
|
@@ -16942,6 +16991,10 @@ var GROUP_FILE_LIMITS = {
|
|
|
16942
16991
|
serveBytesPerDay: 1073741824,
|
|
16943
16992
|
/** Transfers a holder serves at once, all groups together. */
|
|
16944
16993
|
serveAtOnce: 3,
|
|
16994
|
+
/** Bytes a served transfer gets confirmed (or the rest of its file) for it to count as moving in `wantWaitMs`. */
|
|
16995
|
+
serveMoveBytes: 16384,
|
|
16996
|
+
/** How long a served transfer keeps its place while all are taken and another member asks: past it, the place is theirs. */
|
|
16997
|
+
servePlaceMs: 3e5,
|
|
16945
16998
|
/** File announcements a member sends to one group in a minute. */
|
|
16946
16999
|
announcePerMinute: 8,
|
|
16947
17000
|
/** File announcements of one member of a group fetched by themselves in `announceWindowMs`; past it, kept for a Download. */
|
|
@@ -16978,6 +17031,11 @@ var GROUP_FILE_LIMITS = {
|
|
|
16978
17031
|
/** File sessions opening at once, and open at once, all groups together. */
|
|
16979
17032
|
sessionsOpening: 2,
|
|
16980
17033
|
sessionsOpen: 4,
|
|
17034
|
+
/**
|
|
17035
|
+
* What a transfer must bring in `wantWaitMs` (or the rest of its file, when less) to count as moving: a holder that
|
|
17036
|
+
* sends a few bytes at a time is left as one that stalls.
|
|
17037
|
+
*/
|
|
17038
|
+
wantMoveBytes: 16384,
|
|
16981
17039
|
/** The longest file name and type kept from a description. */
|
|
16982
17040
|
nameChars: 255,
|
|
16983
17041
|
mimeChars: 255
|
|
@@ -17338,7 +17396,7 @@ var VALUE = {
|
|
|
17338
17396
|
max: "(\\d[\\d.,\\u00a0\\u202f' ]*?)"
|
|
17339
17397
|
};
|
|
17340
17398
|
var escape = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
17341
|
-
Object.keys(ENGINE_ERRORS).map((code) => {
|
|
17399
|
+
var PATTERNS = Object.keys(ENGINE_ERRORS).map((code) => {
|
|
17342
17400
|
const names = [];
|
|
17343
17401
|
const source = ENGINE_ERRORS[code].split(/(\{\w+\})/).map((part) => {
|
|
17344
17402
|
const value = /^\{(\w+)\}$/.exec(part);
|
|
@@ -17352,6 +17410,18 @@ Object.keys(ENGINE_ERRORS).map((code) => {
|
|
|
17352
17410
|
pattern: new RegExp(`^${source}$`)
|
|
17353
17411
|
};
|
|
17354
17412
|
});
|
|
17413
|
+
/** The code and values of a text the engine wrote, or null for any other text (it is then shown as it is). */
|
|
17414
|
+
function parseEngineError(text) {
|
|
17415
|
+
const trimmed = text.trim();
|
|
17416
|
+
for (const { code, names, pattern } of PATTERNS) {
|
|
17417
|
+
const match = pattern.exec(trimmed);
|
|
17418
|
+
if (match) return {
|
|
17419
|
+
code,
|
|
17420
|
+
values: Object.fromEntries(names.map((name, i) => [name, match[i + 1]]))
|
|
17421
|
+
};
|
|
17422
|
+
}
|
|
17423
|
+
return null;
|
|
17424
|
+
}
|
|
17355
17425
|
//#endregion
|
|
17356
17426
|
//#region ../core/src/ghostlink.ts
|
|
17357
17427
|
/**
|
|
@@ -17708,6 +17778,24 @@ var GhostLink = class {
|
|
|
17708
17778
|
/** Edit frames the contact may send per window; the rest go unconfirmed and come again. */
|
|
17709
17779
|
editsReceived = new RateWindow(30, EDIT_RATE_WINDOW_MS);
|
|
17710
17780
|
wakeReceived = new RateWindow(6, 6e4);
|
|
17781
|
+
/**
|
|
17782
|
+
* The contact's name and picture, each saved when it changes: said once a session and when changed, so a handful a
|
|
17783
|
+
* minute each. Past that only the newest waits, read once the window has room again.
|
|
17784
|
+
*/
|
|
17785
|
+
peerSaid = {
|
|
17786
|
+
"paired-nick": {
|
|
17787
|
+
window: new RateWindow(6, 6e4),
|
|
17788
|
+
read: null,
|
|
17789
|
+
timer: null
|
|
17790
|
+
},
|
|
17791
|
+
"paired-avatar": {
|
|
17792
|
+
window: new RateWindow(6, 6e4),
|
|
17793
|
+
read: null,
|
|
17794
|
+
timer: null
|
|
17795
|
+
}
|
|
17796
|
+
};
|
|
17797
|
+
/** Identity-proof frames the contact may send per window; the rest are dropped before they are read. */
|
|
17798
|
+
identityReceived = new RateWindow(40, IDENTITY_FRAME_WINDOW_MS);
|
|
17711
17799
|
livenessTimer = null;
|
|
17712
17800
|
peerAnswersPings = false;
|
|
17713
17801
|
/** When the ping awaiting its pong went, and the round trip last measured on this session. */
|
|
@@ -19176,8 +19264,9 @@ var GhostLink = class {
|
|
|
19176
19264
|
}
|
|
19177
19265
|
/**
|
|
19178
19266
|
* Ends the idle live session on this transport and lets its listener go, for a chat in use that found every one
|
|
19179
|
-
* taken. The contact hears a goodbye
|
|
19180
|
-
*
|
|
19267
|
+
* taken. The contact hears a goodbye that says so (`yield`, `peerYielded`), rather than finding out when its pings go
|
|
19268
|
+
* unanswered, and does not watch for this app as for one that quit; the record then lists the transport undescribed,
|
|
19269
|
+
* so it stops dialling here. The chat goes on over the DHT (or WebRTC),
|
|
19181
19270
|
* and takes a listener again the same way once it is in use. False when the session may not end (see above).
|
|
19182
19271
|
*/
|
|
19183
19272
|
async yieldEndpoint(transport, idleMs) {
|
|
@@ -19189,7 +19278,10 @@ var GhostLink = class {
|
|
|
19189
19278
|
this.yielding = true;
|
|
19190
19279
|
try {
|
|
19191
19280
|
try {
|
|
19192
|
-
this.channel?.send(JSON.stringify({
|
|
19281
|
+
this.channel?.send(JSON.stringify({
|
|
19282
|
+
t: "paired-bye",
|
|
19283
|
+
yield: true
|
|
19284
|
+
}));
|
|
19193
19285
|
} catch {}
|
|
19194
19286
|
await new Promise((resolve) => setTimeout(resolve, YIELD_BYE_MS));
|
|
19195
19287
|
this.disconnect();
|
|
@@ -21148,6 +21240,8 @@ var GhostLink = class {
|
|
|
21148
21240
|
else if (paired.supports("files/2")) this.pairedFiles = new PairedFiles(channel, {
|
|
21149
21241
|
onIncoming: (file) => events.onFileIncoming?.(file) ?? null,
|
|
21150
21242
|
onStored: events.onFileStored,
|
|
21243
|
+
replaced: () => this.supportsLargeFiles,
|
|
21244
|
+
room: events.onFileRoom,
|
|
21151
21245
|
onProgress: events.onFileProgress,
|
|
21152
21246
|
onComplete: events.onFileComplete,
|
|
21153
21247
|
onFailed: events.onFileFailed
|
|
@@ -21239,7 +21333,10 @@ var GhostLink = class {
|
|
|
21239
21333
|
return;
|
|
21240
21334
|
}
|
|
21241
21335
|
if (frame?.t === "paired-bye") {
|
|
21242
|
-
if (paired.state.status === "ready")
|
|
21336
|
+
if (paired.state.status === "ready") {
|
|
21337
|
+
if (frame.yield === true) this.peerYielded(channel);
|
|
21338
|
+
else this.peerDeparted(channel);
|
|
21339
|
+
}
|
|
21243
21340
|
return;
|
|
21244
21341
|
}
|
|
21245
21342
|
if (!frame || typeof frame !== "object") return;
|
|
@@ -21318,25 +21415,15 @@ var GhostLink = class {
|
|
|
21318
21415
|
return;
|
|
21319
21416
|
}
|
|
21320
21417
|
if (typeof frame?.t === "string" && frame.t.startsWith("idp-") && this.identitySupport) {
|
|
21321
|
-
await this.options.events?.onIdentityProof?.(frame);
|
|
21418
|
+
if (this.identityReceived.take()) await this.options.events?.onIdentityProof?.(frame);
|
|
21322
21419
|
return;
|
|
21323
21420
|
}
|
|
21324
21421
|
if (typeof frame?.t === "string" && frame.t.startsWith("proof-") && this.peerProofSupport) {
|
|
21325
21422
|
await this.options.events?.onPeerProof?.(frame);
|
|
21326
21423
|
return;
|
|
21327
21424
|
}
|
|
21328
|
-
if (frame?.t === "paired-avatar") {
|
|
21329
|
-
|
|
21330
|
-
if (avatar !== void 0) this.options.events?.onPeerAvatar?.(avatar);
|
|
21331
|
-
return;
|
|
21332
|
-
}
|
|
21333
|
-
if (frame?.t === "paired-nick") {
|
|
21334
|
-
const nick = sanitizeNick(frame.n);
|
|
21335
|
-
if (typeof frame.n === "string") this.options.events?.onPeerNick?.(nick ?? null);
|
|
21336
|
-
if (nick !== this.peerNickOverride) {
|
|
21337
|
-
this.peerNickOverride = nick ?? null;
|
|
21338
|
-
this.options.events?.onPresence?.(this.presence);
|
|
21339
|
-
}
|
|
21425
|
+
if (frame?.t === "paired-avatar" || frame?.t === "paired-nick") {
|
|
21426
|
+
this.peerSays(channel, frame.t, frame);
|
|
21340
21427
|
return;
|
|
21341
21428
|
}
|
|
21342
21429
|
if (frame?.t === "paired-capabilities") {
|
|
@@ -21693,6 +21780,18 @@ var GhostLink = class {
|
|
|
21693
21780
|
this.peerLost("bye");
|
|
21694
21781
|
}
|
|
21695
21782
|
/**
|
|
21783
|
+
* The contact gave this session's listener up to another chat (`yieldEndpoint`): its app is still there, and its
|
|
21784
|
+
* record now lists the transport undescribed, so there is nothing to dial and no return to watch for. The session
|
|
21785
|
+
* ends now, and the chat reads the contact at its own pace; the contact dials once it takes a listener back. Taken
|
|
21786
|
+
* as a goodbye, it was watched as an app that quit: 89 reads of its key in the 2 minutes after a yield on the
|
|
21787
|
+
* Desktop, against 6 at the background pace (bug hunt, 2026-10-15).
|
|
21788
|
+
*/
|
|
21789
|
+
peerYielded(channel) {
|
|
21790
|
+
if (this.channel !== channel || this.stopped) return;
|
|
21791
|
+
traceLink(this.myPubKeyZ32, "peer-yielded", {});
|
|
21792
|
+
this.disconnect();
|
|
21793
|
+
}
|
|
21794
|
+
/**
|
|
21696
21795
|
* A packet of the contact's not seen before, fresh, while nothing is live, soon after a live session ended: it is back
|
|
21697
21796
|
* (its app restarted), so the wait that the attempts since built up is over, and the next dial goes now. Once per
|
|
21698
21797
|
* loss: a contact that is there but unreachable publishes often, and the wait between attempts is what spares the
|
|
@@ -21787,6 +21886,57 @@ var GhostLink = class {
|
|
|
21787
21886
|
offered.woke = true;
|
|
21788
21887
|
if (!this.dialing) setTimeout(() => this.maybeKnockEarly(offered.epoch), 0);
|
|
21789
21888
|
}
|
|
21889
|
+
/**
|
|
21890
|
+
* A name or picture the contact said, once it is one (reading it costs little; saving it is what counts): past the
|
|
21891
|
+
* window the newest waits for room on this session, so the last word still counts.
|
|
21892
|
+
*/
|
|
21893
|
+
peerSays(channel, kind, frame) {
|
|
21894
|
+
let read;
|
|
21895
|
+
if (kind === "paired-avatar") {
|
|
21896
|
+
const avatar = sanitizeAvatar(frame.a);
|
|
21897
|
+
if (avatar === void 0) return;
|
|
21898
|
+
read = () => this.options.events?.onPeerAvatar?.(avatar);
|
|
21899
|
+
} else {
|
|
21900
|
+
const nick = sanitizeNick(frame.n) ?? null, said = typeof frame.n === "string";
|
|
21901
|
+
read = () => {
|
|
21902
|
+
if (said) this.options.events?.onPeerNick?.(nick);
|
|
21903
|
+
if (nick !== this.peerNickOverride) {
|
|
21904
|
+
this.peerNickOverride = nick;
|
|
21905
|
+
this.options.events?.onPresence?.(this.presence);
|
|
21906
|
+
}
|
|
21907
|
+
};
|
|
21908
|
+
}
|
|
21909
|
+
const held = this.peerSaid[kind];
|
|
21910
|
+
if (!held.timer && held.window.take()) {
|
|
21911
|
+
read();
|
|
21912
|
+
return;
|
|
21913
|
+
}
|
|
21914
|
+
held.read = read;
|
|
21915
|
+
if (held.timer) return;
|
|
21916
|
+
const due = () => {
|
|
21917
|
+
held.timer = null;
|
|
21918
|
+
if (this.channel !== channel || !held.read) {
|
|
21919
|
+
held.read = null;
|
|
21920
|
+
return;
|
|
21921
|
+
}
|
|
21922
|
+
if (!held.window.take()) {
|
|
21923
|
+
held.timer = setTimeout(due, held.window.wait());
|
|
21924
|
+
return;
|
|
21925
|
+
}
|
|
21926
|
+
const next = held.read;
|
|
21927
|
+
held.read = null;
|
|
21928
|
+
next();
|
|
21929
|
+
};
|
|
21930
|
+
held.timer = setTimeout(due, held.window.wait());
|
|
21931
|
+
}
|
|
21932
|
+
/** What the contact said of itself and was still waiting goes with the session: the next one says it again. */
|
|
21933
|
+
dropPeerSaid() {
|
|
21934
|
+
for (const said of Object.values(this.peerSaid)) {
|
|
21935
|
+
if (said.timer) clearTimeout(said.timer);
|
|
21936
|
+
said.timer = null;
|
|
21937
|
+
said.read = null;
|
|
21938
|
+
}
|
|
21939
|
+
}
|
|
21790
21940
|
/** A ping on the session right after a wake, with `PONG_WAIT_MS` for its answer: none, and the session is dead. */
|
|
21791
21941
|
probeAfterWake(channel) {
|
|
21792
21942
|
if (!this.peerAnswersPings || this.paired?.state.status !== "ready") return;
|
|
@@ -21829,6 +21979,7 @@ var GhostLink = class {
|
|
|
21829
21979
|
this.channel = this.httpHost = this.httpClient = this.files = null;
|
|
21830
21980
|
this.peerServicesOverride = null;
|
|
21831
21981
|
this.peerNickOverride = null;
|
|
21982
|
+
this.dropPeerSaid();
|
|
21832
21983
|
this.sessionCapabilities.reset();
|
|
21833
21984
|
this.typingSender.reset();
|
|
21834
21985
|
this.typingReceiver.clear();
|
|
@@ -22455,10 +22606,14 @@ function decodeSvcbRecords(dnsPacket) {
|
|
|
22455
22606
|
}
|
|
22456
22607
|
return records;
|
|
22457
22608
|
}
|
|
22458
|
-
/**
|
|
22609
|
+
/**
|
|
22610
|
+
* The homeserver a Pubky key's packet names: the z-base-32 key its `_pubky` record points at, or undefined. The target
|
|
22611
|
+
* is read next as a key (`pubkyRecords` checks the homeserver's packet against it), so only a canonical one names a
|
|
22612
|
+
* homeserver; a respelled one is none, not a lookup that fails as "no records".
|
|
22613
|
+
*/
|
|
22459
22614
|
function pubkyHomeserverOf(dnsPacket, userZ32) {
|
|
22460
22615
|
const record = decodeSvcbRecords(dnsPacket).find((r) => r.name === `_pubky.${userZ32}` || r.name === "_pubky");
|
|
22461
|
-
return record &&
|
|
22616
|
+
return record && isZ32Key(record.target) ? record.target : void 0;
|
|
22462
22617
|
}
|
|
22463
22618
|
/**
|
|
22464
22619
|
* The homeserver's web endpoint from its own packet: of the HTTPS/SVCB records at its root, the lowest priority one
|
|
@@ -24418,7 +24573,7 @@ function shortAtprotoDid(did) {
|
|
|
24418
24573
|
}
|
|
24419
24574
|
/** The record key of a proof: its proof key (z-base-32, already a valid record key), so removal finds it. */
|
|
24420
24575
|
function atprotoProofRkey(proofKey) {
|
|
24421
|
-
if (
|
|
24576
|
+
if (!isZ32Key(proofKey)) throw new Error("Invalid proof key");
|
|
24422
24577
|
return proofKey;
|
|
24423
24578
|
}
|
|
24424
24579
|
var fragment = (id, did, name) => id === `#${name}` || id === `${did}#${name}`;
|
|
@@ -25840,6 +25995,28 @@ var fileAad = (f) => JSON.stringify([
|
|
|
25840
25995
|
f.ts
|
|
25841
25996
|
]);
|
|
25842
25997
|
var isFileBox = isSealedBox(MAX_FILE_BOX);
|
|
25998
|
+
/** The author's name (`MAX_NICK_LENGTH` characters of up to four bytes each), sealed; signed apart from `xs` (`ns`). */
|
|
25999
|
+
var MAX_NICK_BOX = Math.ceil(1088 / 3) + 4;
|
|
26000
|
+
var nickAad = (f) => JSON.stringify([
|
|
26001
|
+
"ghostly-group/1 nick",
|
|
26002
|
+
f.g,
|
|
26003
|
+
f.e,
|
|
26004
|
+
f.s,
|
|
26005
|
+
f.n,
|
|
26006
|
+
f.ts
|
|
26007
|
+
]);
|
|
26008
|
+
var nickSigned = (f, nk) => utf8Encode(JSON.stringify([
|
|
26009
|
+
"ghostly-group/1 nick",
|
|
26010
|
+
f.g,
|
|
26011
|
+
f.e,
|
|
26012
|
+
f.s,
|
|
26013
|
+
f.n,
|
|
26014
|
+
f.ts,
|
|
26015
|
+
nk.n,
|
|
26016
|
+
nk.c
|
|
26017
|
+
]));
|
|
26018
|
+
var isNickBox = isSealedBox(MAX_NICK_BOX);
|
|
26019
|
+
var isSignature = (v) => typeof v === "string" && v.length === 86 && B64$1.test(v);
|
|
25843
26020
|
var B64$1 = /^[A-Za-z0-9_-]*$/;
|
|
25844
26021
|
var secretAad$1 = (g, e, member) => JSON.stringify([
|
|
25845
26022
|
"ghostly-group/1 secret",
|
|
@@ -25979,7 +26156,7 @@ var ownKey = (f) => `${f.e}:${f.n}`;
|
|
|
25979
26156
|
/** What a frame weighs in a log, roughly: its boxes plus the fixed fields around them. */
|
|
25980
26157
|
var frameKey$1 = (f) => `${f.s}:${f.e}:${f.n}`;
|
|
25981
26158
|
/** What a kept frame counts for against `GROUP_LIMITS.relayBytes`. */
|
|
25982
|
-
var frameBytes = (f) => f.c.length + (f.m?.c.length ?? 0) + (f.r?.c.length ?? 0) + (f.sc?.c.length ?? 0) + (f.fl?.c.length ?? 0) + 400;
|
|
26159
|
+
var frameBytes = (f) => f.c.length + (f.m?.c.length ?? 0) + (f.r?.c.length ?? 0) + (f.sc?.c.length ?? 0) + (f.fl?.c.length ?? 0) + (f.nk?.c.length ?? 0) + 400;
|
|
25983
26160
|
/** Only the fields an edit frame has, as `clean` does for a message. */
|
|
25984
26161
|
var cleanEdit = (f) => ({
|
|
25985
26162
|
t: GROUP_EDIT_FRAME,
|
|
@@ -26023,7 +26200,14 @@ function clean(f) {
|
|
|
26023
26200
|
c: f.fl.c
|
|
26024
26201
|
} } : {},
|
|
26025
26202
|
...readFirstPlace(f.o, f.e) ? { o: readFirstPlace(f.o, f.e) } : {},
|
|
26026
|
-
...typeof f.xs === "string" && f.xs.length === 86 && B64$1.test(f.xs) ? { xs: f.xs } : {}
|
|
26203
|
+
...typeof f.xs === "string" && f.xs.length === 86 && B64$1.test(f.xs) ? { xs: f.xs } : {},
|
|
26204
|
+
...isNickBox(f.nk) && isSignature(f.ns) ? {
|
|
26205
|
+
nk: {
|
|
26206
|
+
n: f.nk.n,
|
|
26207
|
+
c: f.nk.c
|
|
26208
|
+
},
|
|
26209
|
+
ns: f.ns
|
|
26210
|
+
} : {}
|
|
26027
26211
|
};
|
|
26028
26212
|
}
|
|
26029
26213
|
/** Whether the member whose sync this is lacks a frame: above what it has from that sender, or one it names as missing. */
|
|
@@ -26093,6 +26277,8 @@ var GroupSession = class {
|
|
|
26093
26277
|
asked = /* @__PURE__ */ new Map();
|
|
26094
26278
|
/** The signed leave of each member I last passed on, kept for an admin that was away (`byesHeld`). In memory only. */
|
|
26095
26279
|
byesPassed = /* @__PURE__ */ new Map();
|
|
26280
|
+
/** Member → when the name I hold for it was said: its message's time, or the moment an edge said it (`heardName`). In memory only. */
|
|
26281
|
+
nickAt = /* @__PURE__ */ new Map();
|
|
26096
26282
|
queue = Promise.resolve();
|
|
26097
26283
|
/** One metadata frame that names a commit or an epoch I do not have yet: tried again when the chain moves. */
|
|
26098
26284
|
pendingMeta;
|
|
@@ -26451,7 +26637,7 @@ var GroupSession = class {
|
|
|
26451
26637
|
rewelcome(memberKey) {
|
|
26452
26638
|
return this.serialize(async () => {
|
|
26453
26639
|
this.requireAdmin();
|
|
26454
|
-
if (!rosterHas(this.roster, memberKey) || memberKey === this.myKey) throw new Error("Not a member");
|
|
26640
|
+
if (!rosterHas(this.roster, memberKey) || memberKey === this.myKey || !isZ32Key(memberKey)) throw new Error("Not a member");
|
|
26455
26641
|
const chain = this.state.chain;
|
|
26456
26642
|
let admitted = chain.length - 1;
|
|
26457
26643
|
while (admitted >= 0 && !(chain[admitted].k === "add" && chain[admitted].s === memberKey)) admitted--;
|
|
@@ -26533,7 +26719,7 @@ var GroupSession = class {
|
|
|
26533
26719
|
await this.persist();
|
|
26534
26720
|
for (const [key] of previous.m) {
|
|
26535
26721
|
if (key === this.myKey) continue;
|
|
26536
|
-
const member = rosterHas(roster, key);
|
|
26722
|
+
const member = rosterHas(roster, key) && isZ32Key(key);
|
|
26537
26723
|
this.hooks.send(key, {
|
|
26538
26724
|
t: "group-commit",
|
|
26539
26725
|
g: this.id,
|
|
@@ -26711,6 +26897,8 @@ var GroupSession = class {
|
|
|
26711
26897
|
...extra.file ? { fl: encryptText(key, fileAad(header), JSON.stringify(extra.file)) } : {},
|
|
26712
26898
|
...o ? { o } : {}
|
|
26713
26899
|
};
|
|
26900
|
+
const nick = sanitizeNick(this.hooks.nick?.());
|
|
26901
|
+
const nk = nick === void 0 ? void 0 : encryptText(key, nickAad(header), nick);
|
|
26714
26902
|
return {
|
|
26715
26903
|
t: "group-msg",
|
|
26716
26904
|
...unsigned,
|
|
@@ -26719,7 +26907,11 @@ var GroupSession = class {
|
|
|
26719
26907
|
xs: toBase64Url(sign(messageSignedWhole({
|
|
26720
26908
|
...unsigned,
|
|
26721
26909
|
...boxes
|
|
26722
|
-
}), this.identity.seed))
|
|
26910
|
+
}), this.identity.seed)),
|
|
26911
|
+
...nk ? {
|
|
26912
|
+
nk,
|
|
26913
|
+
ns: toBase64Url(sign(nickSigned(header, nk), this.identity.seed))
|
|
26914
|
+
} : {}
|
|
26723
26915
|
};
|
|
26724
26916
|
}
|
|
26725
26917
|
/** Into my bounded log, for members who missed it. */
|
|
@@ -26913,10 +27105,12 @@ var GroupSession = class {
|
|
|
26913
27105
|
setNick(key, nick) {
|
|
26914
27106
|
return this.serialize(async () => {
|
|
26915
27107
|
const clean = sanitizeNick(nick);
|
|
27108
|
+
this.nickAt.set(key, this.clock());
|
|
26916
27109
|
if ((this.state.nicks[key] ?? void 0) === clean) return;
|
|
26917
27110
|
if (clean) this.state.nicks[key] = clean;
|
|
26918
27111
|
else delete this.state.nicks[key];
|
|
26919
|
-
await this.persist();
|
|
27112
|
+
if (key === this.myKey) await this.persist();
|
|
27113
|
+
else this.persistSoon();
|
|
26920
27114
|
this.hooks.changed();
|
|
26921
27115
|
});
|
|
26922
27116
|
}
|
|
@@ -27148,6 +27342,7 @@ var GroupSession = class {
|
|
|
27148
27342
|
const key = epochKeys(secret, this.id, raw.e).message;
|
|
27149
27343
|
const text = decryptText(key, messageAad$1(raw), raw.nn, raw.c);
|
|
27150
27344
|
if (text === null) return;
|
|
27345
|
+
if (this.heardName(key, raw)) this.hooks.changed();
|
|
27151
27346
|
const firstFrame = first && {
|
|
27152
27347
|
...raw,
|
|
27153
27348
|
e: first.e,
|
|
@@ -27261,6 +27456,26 @@ var GroupSession = class {
|
|
|
27261
27456
|
return false;
|
|
27262
27457
|
}
|
|
27263
27458
|
}
|
|
27459
|
+
/**
|
|
27460
|
+
* The author's name in a message (`nk`), when the author's signature over it (`ns`) holds: any copy, handed on or
|
|
27461
|
+
* not, whole or not, since a member handing it on can only drop it. Taken only from a message newer than the one it
|
|
27462
|
+
* last came in, or than the moment an edge last said it (`setNick`), so a catch-up's older pages never bring back a
|
|
27463
|
+
* name the member changed since. Whether the name I hold changed.
|
|
27464
|
+
*/
|
|
27465
|
+
heardName(key, raw) {
|
|
27466
|
+
if (!isNickBox(raw.nk) || !isSignature(raw.ns) || raw.ts <= (this.nickAt.get(raw.s) ?? 0)) return false;
|
|
27467
|
+
try {
|
|
27468
|
+
if (!verify(fromBase64Url(raw.ns), nickSigned(raw, raw.nk), publicKeyFromZ32(raw.s))) return false;
|
|
27469
|
+
} catch {
|
|
27470
|
+
return false;
|
|
27471
|
+
}
|
|
27472
|
+
const nick = sanitizeNick(decryptText(key, nickAad(raw), raw.nk.n, raw.nk.c));
|
|
27473
|
+
if (nick === void 0) return false;
|
|
27474
|
+
this.nickAt.set(raw.s, raw.ts);
|
|
27475
|
+
if (this.state.nicks[raw.s] === nick) return false;
|
|
27476
|
+
this.state.nicks[raw.s] = nick;
|
|
27477
|
+
return true;
|
|
27478
|
+
}
|
|
27264
27479
|
openMentions(key, raw, text, everyone) {
|
|
27265
27480
|
if (!isMentionsBox(raw.m)) return [];
|
|
27266
27481
|
const plain = decryptText(key, mentionsAad(raw), raw.m.n, raw.m.c);
|
|
@@ -27452,7 +27667,7 @@ var GroupSession = class {
|
|
|
27452
27667
|
await this.replayWaiting();
|
|
27453
27668
|
}
|
|
27454
27669
|
async receiveSync(from, frame) {
|
|
27455
|
-
if (!rosterHas(this.roster, from) || !Number.isSafeInteger(frame.e) || frame.e < 0 || typeof frame.h !== "string") return;
|
|
27670
|
+
if (!rosterHas(this.roster, from) || !isZ32Key(from) || !Number.isSafeInteger(frame.e) || frame.e < 0 || typeof frame.h !== "string") return;
|
|
27456
27671
|
let answered = this.syncsAnswered.get(from);
|
|
27457
27672
|
if (!answered) this.syncsAnswered.set(from, answered = new RateWindow(GROUP_LIMITS.syncAnswers, GROUP_LIMITS.syncWindowMs, () => this.hooks.clock?.() ?? Date.now()));
|
|
27458
27673
|
if (!answered.take()) return;
|
|
@@ -28988,7 +29203,7 @@ var CommunitySession = class {
|
|
|
28988
29203
|
commit
|
|
28989
29204
|
});
|
|
28990
29205
|
if (FRESH.has(kind)) {
|
|
28991
|
-
for (const [key] of roster) if (key !== this.myKey) this.hooks.addressed(key, {
|
|
29206
|
+
for (const [key] of roster) if (key !== this.myKey && isZ32Key(key)) this.hooks.addressed(key, {
|
|
28992
29207
|
t: "group-secret",
|
|
28993
29208
|
v: 2,
|
|
28994
29209
|
g: this.id,
|
|
@@ -29035,7 +29250,7 @@ var CommunitySession = class {
|
|
|
29035
29250
|
rewelcome(memberKey) {
|
|
29036
29251
|
return this.serialize(async () => {
|
|
29037
29252
|
this.requireMember();
|
|
29038
|
-
if (!rosterHas(this.roster, memberKey) || memberKey === this.myKey) throw new Error("Not a member");
|
|
29253
|
+
if (!rosterHas(this.roster, memberKey) || memberKey === this.myKey || !isZ32Key(memberKey)) throw new Error("Not a member");
|
|
29039
29254
|
for (let i = this.state.chain.length - 1; i >= 0; i--) {
|
|
29040
29255
|
const c = this.state.chain[i];
|
|
29041
29256
|
if (c.k === "add" && c.s === memberKey) return this.welcomeFor(memberKey, communityCommitHash(c));
|
|
@@ -29101,7 +29316,10 @@ var CommunitySession = class {
|
|
|
29101
29316
|
seedB64: entry?.seedB64 ?? ""
|
|
29102
29317
|
};
|
|
29103
29318
|
await this.persist();
|
|
29104
|
-
if (entry) for (const key of this.others)
|
|
29319
|
+
if (entry) for (const key of this.others) {
|
|
29320
|
+
const frame = this.entryFrame(key);
|
|
29321
|
+
if (frame) this.hooks.addressed(key, frame);
|
|
29322
|
+
}
|
|
29105
29323
|
this.hooks.changed();
|
|
29106
29324
|
return this.state.entry.key;
|
|
29107
29325
|
});
|
|
@@ -29717,7 +29935,7 @@ var CommunitySession = class {
|
|
|
29717
29935
|
for (const { from, frame } of ready) await this.receiveMessage(from, frame);
|
|
29718
29936
|
}
|
|
29719
29937
|
async receiveSync(from, frame) {
|
|
29720
|
-
if (!this.isRecentMember(from) || !Number.isSafeInteger(frame.e) || typeof frame.h !== "string") return;
|
|
29938
|
+
if (!this.isRecentMember(from) || !isZ32Key(from) || !Number.isSafeInteger(frame.e) || typeof frame.h !== "string") return;
|
|
29721
29939
|
let answered = this.syncsAnswered.get(from);
|
|
29722
29940
|
if (!answered) this.syncsAnswered.set(from, answered = new RateWindow(COMMUNITY_LIMITS.syncAnswers, COMMUNITY_LIMITS.syncWindowMs, () => this.hooks.clock?.() ?? Date.now()));
|
|
29723
29941
|
if (!answered.take()) return;
|
|
@@ -29832,7 +30050,7 @@ var CommunitySession = class {
|
|
|
29832
30050
|
/** The current entry seed sealed to a member, when I hold it: sealed once per seed, not on every sync answer. */
|
|
29833
30051
|
entryFrame(to) {
|
|
29834
30052
|
const { key, seedB64 } = this.state.entry;
|
|
29835
|
-
if (!key || !seedB64) return null;
|
|
30053
|
+
if (!key || !seedB64 || !isZ32Key(to)) return null;
|
|
29836
30054
|
const sealed = this.sealedEntries.get(to);
|
|
29837
30055
|
if (sealed?.seedB64 === seedB64 && sealed.frame.x === key) return { ...sealed.frame };
|
|
29838
30056
|
const frame = {
|
|
@@ -31002,6 +31220,6 @@ function appStoreDecision(held, read) {
|
|
|
31002
31220
|
return read.digest === held.digest ? "same" : "equivocation";
|
|
31003
31221
|
}
|
|
31004
31222
|
//#endregion
|
|
31005
|
-
export { COMMUNITY_EDIT_FRAME as $, cardLine as $a, normalizeRelayUrl as $c, lastSharedWithMe as $i, GROUP_HAVE_FRAME as $n, parseCallSignal as $o, WakeLimiter as $r, ENROLL_GRANT as $s, didDhtFromPublicKey as $t, CommunitySession as A, readForwarded as Aa, newDeviceSetSecret as Ac, nip05RootKey as Ai, pubkyProofFile as An, rosterHas as Ao, pickHubs as Ar, handoffPakeFrame as As, verifyAtprotoRecordProof as At, knockRecords as B, validReactionNumber as Ba, firstDeviceSetSecret as Bc, dialDescriptors as Bi, findEndpoint as Bn, formatLocalTarget as Bo, TYPING_KINDS as Br, readHandoffHello as Bs, didWebDocumentUrl as Bt, sha256Paced as C, readImageMeta as Ca, ENROLL_CAPABILITY as Cc, DOMAIN_FILE_MAX_BYTES as Ci, utf8Decode as Cl, isBitcoinAddress as Cn, readCanonicalJson as Co, doorHubs as Cr, handoffContextProof as Cs, atprotoProofRkey as Ct, openGroupTyping as D, dhtEditId as Da, deviceKeyZ32 as Dc, domainWellKnownFile as Di, newPubkyProofFolder as Dn, commitHash as Do, mergeBeacon as Dr, handoffHelloFrame as Ds, parseAtprotoDidDocument as Dt, groupTypingEpoch as E, RateWindow as Ea, deviceEchoNonce as Ec, domainTxtRecord as Ei, isPubkyProofFolder as En, MEMBER_KEY as Eo, lobbyRecords as Er, handoffEphemeral as Es, normalizeAtprotoHandle as Et, KNOCK_TTL_MS as F, nextReactionNumber as Fa, TURN_SETTLE_MS as Fc, txtValue as Fi, resolveLightningDestination as Fn, DHT_POLL_INTERVALS as Fo, shouldBeHub as Fr, newHandoffId as Fs, checkDidJws as Ft, groupWakeFrame as G, BUTTON_ID as Ga, turnInstance as Gc, IdentityExchange as Gi, INVITE_TAKEN as Gn, encodeControl as Go, GROUP_PIN_FRAME as Gr, SET_ACK as Gs, normalizeDid as Gt, readKnocks as H, pairedReplyAuthor as Ha, readTurnPacket as Hc, IDENTITY_MAX_VALIDITY as Hi, parseCashuRequestPayload as Hn, webLocalFetch as Ho, TypingSender as Hr, readHandoffTurnFrame as Hs, didWebFileNames as Ht, decodeGroupEntryLink as I, queueReaction as Ia, classifyTurnRead as Ic, wellKnownUrl as Ii, decodeBolt11 as In, EXPECT_PEER_MS as Io, ChatFiles as Ir, readHandoffAck as Is, checkDidSignature as It, GROUP_LIMITS as J, PR_STATES as Ja, turnStatedVerifier as Jc, identityRevocationValue as Ji, pairedMessageFits as Jn, answersOffer as Jo, nextPinNumber as Jr, setAckFrame as Js, parseDidSignaturePaste as Jt, groupWakes as K, ITEM_STATES as Ka, turnKeys as Kc, boundVerifiedIdentity as Ki, LIVENESS_PING_MS as Kn, CALL_SIGNAL_MAX_AGE_MS as Ko, PIN_LIMITS as Kr, SET_UPDATE as Ks, parseDid as Kt, encodeGroupEntryLink as L, reactionEmoji as La, turnPutSummary as Lc, CapsExchange as Li, ENDPOINT as Ln, RELAY_POLL_INTERVALS as Lo, FILE_LIMITS as Lr, readHandoffCancel as Ls, didGhostlyServiceEntry as Lt, communityHasFrame as M, GROUP_REACTION_FRAME as Ma, webCryptoSigner as Mc, recordsFromTxt as Mi, homeserverWebEndpoint as Mn, edgeParams as Mo, readBeacon as Mr, handoffRetryAfter as Ms, DID_FILE_MAX_BYTES as Mt, decodeCommunityLink as N, REACTION_LIMITS as Na, TURN_PUT_WINDOW_MS as Nc, recordsFromWellKnown as Ni, pubkyHomeserverOf as Nn, DirectPathWatch as No, readBeaconHead as Nr, handoffStreamKey as Ns, DID_JWS_MAX_LENGTH as Nt, sealGroupTyping as O, parseLinkPreview as Oa, deviceLinkPairing as Oc, encodeDnsQuery as Oi, normalizePubkyKey as On, parseGroupCommit as Oo, mergeLobby as Or, handoffManifestFrames as Os, shortAtprotoDid as Ot, encodeCommunityLink as P, ReactionWindow as Pa, TURN_RAISE_READ_TIMEOUT_MS as Pc, recordsName as Pi, requestLnurlInvoice as Pn, AWAITING_PEER_MS as Po, readLobby as Pr, handoffVersions as Ps, DidError as Pt, frameBytes as Q, buttonLabelClash as Qa, currentRelays as Qc, revokesIdentity as Qi, GROUP_FILE_LIMITS as Qn, extractParamsFromSdp as Qo, WAKE_CALL_INTERVAL_MS as Qr, ENROLL_DONE as Qs, didDhtDocument as Qt, entryParams as R, reactionIsNewer as Ra, TURN_LAST_SEQUENCE as Rc, DHT_TEXT_CAPABILITY as Ri, cashuRequestPayload as Rn, presenceSeenAt as Ro, transferEnded as Rr, readHandoffDone as Rs, didJwsAlg as Rt, readAppBundleAsync as S, parseImageMeta as Sa, DEVICES_CAPABILITY as Sc, readManifest as Si, toZ32 as Sl, sparkInvoiceDetails as Sn, canonicalJsonBytes as So, beaconRecords as Sr, handoffContext as Ss, atprotoProofRecord as St, GroupTypingBoard as T, EDIT_RATE_WINDOW_MS as Ta, deviceEchoFrame as Tc, dnsProofName as Ti, isPubkyKey as Tn, MAX_GROUP_CHAIN as To, lobbyKeys as Tr, handoffDigest as Ts, isAtprotoDid as Tt, GROUP_WAKE_FRAME as U, readReply as Ua, signTurnPacket as Uc, IDENTITY_REVOCATION_LABEL as Ui, parseFedimintRequestPayload as Un, LIMITS as Uo, sanitizeTypingStatus as Ur, readHandoffVerified as Us, didWebFileUrl as Ut, mergeKnocks as V, wireReaction as Va, nextTurnPosition as Vc, IDENTITY_MAX_EVIDENCE as Vi, isFederationId as Vn, parseLocalTarget as Vo, TYPING_REFRESH_MS as Vr, readHandoffPake as Vs, didWebFile as Vt, GroupWakeLimiter as W, replySnippet as Wa, signTurnRelease as Wc, IdentityCheckUnavailable as Wi, GhostLink as Wn, decodeControl as Wo, typingActivity as Wr, sealHandoffPiece as Ws, didWebHost as Wt, GROUP_READ_NOTE as X, STATUS_CARD_LIMITS as Xa, DEFAULT_RELAYS as Xc, newIdentityBinding as Xi, engineError as Xn, callRtcConfig as Xo, pinNumberHolds as Xr, signTombstone as Xs, staticDidDocument as Xt, GROUP_REACTED_FRAME as Y, RUN_RESULTS as Ya, turnVerifierMark as Yc, identityStatement as Yi, pairedMessageFrame as Yn, buildSdpFromSignal as Yo, pinIsNewer as Yr, setUpdateFrame as Ys, signingKeys as Yt, GroupSession as Z, appCardId as Za, RelayTransport as Zc, receivedIdentityStatus as Zi, engineText as Zn, callSignalHeardAt as Zo, readPin as Zr, verifySetUpdate as Zs, strictBase64Url as Zt, assembleAppBundle as _, baseMime as _a, decodeInviteCode as _c, HOLD_LIMITS as _i, sanitizeAvatar as _l, validatePaymentTarget as _n, readAppRevocation as _o, mayBeHub as _r, handoffAttemptAllowed as _s, ATPROTO_DECLARED_SCOPE as _t, planAppUpdate as a, irohDescriptor as aa, enrollDoneFrame as ac, checkPushEndpoint as ai, PacketTooLargeError as al, EVM_TEST_CHAINS as an, claimedTime as ao, readGroupFileMeta as ar, HANDOFF_ACK as as, groupName as at, pacer as b, voicePeaksOf as ba, inviteOwnership as bc, isHoldUrl as bi, randomBytes as bl, SPARK_PROVIDER as bn, signAppRevocation as bo, COMMUNITY_TOPOLOGY as br, handoffBusyFrame as bs, ATPROTO_PROOF_SCOPE as bt, readAppStore as c, DHT_MESSAGE_TTL as ca, enrollProofFrame as cc, chatAppId as ci, newerPacket as cl, SEPOLIA_TEST_USDT as cn, shownTime as co, readGroupWantNo as cr, HANDOFF_HAVE as cs, SshSigError as ct, APP_BUNDLE_LIMITS as d, dhtFileId as da, verifyEnrollProof as dc, BUTTONS_CAPABILITY as di, createIdentity as dl, USDT_PUBLIC_RPC as dn, appFingerprint as do, SIGNAL_FRESH_MS as dr, HANDOFF_PAKE as ds, sameSshKey as dt, PeerProofs as ea, ENROLL_HELLO as ec, deviceWakeRequest as ei, setLinkTraceSink as el, encodeDidDhtDeactivated as en, cardUrl as eo, GROUP_WANT_FRAME as er, signalHasVideo as es, GROUP_EDIT_FRAME as et, APP_BUNDLE_MAGIC as f, formatFileSize as fa, createDeviceInvite as fc, EDIT_CAPABILITY as fi, identityFromSeed as fl, WALLET_NETWORKS as fn, appRef as fo, SIGNAL_HOLD_MS as fr, HANDOFF_PIECE_BYTES as fs, sshSignCommand as ft, appViewOf as g, VOICE_LIMITS as ga, createChatInvite as gc, HOLD_DATED_BACK_MS as gi, MAX_AVATAR_LENGTH as gl, formatPaymentAmount as gn, isAppRef as go, MESH_HUBS as gr, filePartName as gs, decodeAnyBitcoinAddress as gt, appDigest as h, PLAYABLE_AUDIO as ha, OwnInviteError as hc, HOLD_CAPABILITY as hi, verify as hl, assertWholeSats as hn, isAppKey as ho, readGroupSignal as hr, HANDOFF_VERIFIED as hs, BitcoinAddressError as ht, checkAppBeforeRun as i, automaticTransport as ia, enrollDigits as ic, wakeRequest as ii, withRequestOptions as il, ETHEREUM_USDT as in, arrivalKey as io, isGroupMessageId as ir, serviceIdFromName as is, mentionsMember as it, GROUP_READ_NOTE_COMMUNITY as j, COMMUNITY_REACTION_FRAME as ja, seedSigner as jc, normalizeDomain as ji, pubkyProofPath as jn, verifyCommitSignature as jo, rankHubs as jr, handoffReleaseFrame as js, DID_DOCUMENT_MAX_BYTES as jt, COMMUNITY_LIMITS as k, forwardedAgain as ka, devicePingFrame as kc, isPublicAddress as ki, pubkyProofCapability as kn, rosterAdmin as ko, newerHead as kr, handoffOfferFrame as ks, AtprotoProofError as kt, readAppStoreSteps as l, peekDhtMailbox as la, readEnrollGrant as lc, isAppVersion as li, openRelayPayload as ll, SEPOLIA_TEST_USDT_FAUCET as ln, APP_PREFIXES as lo, CarriedTransport as lr, HANDOFF_HELLO as ls, parseSshPublicKey as lt, APP_PERMISSIONS as m, sanitizeMime as ma, readDeviceInvite as mc, UPGRADE_CAPABILITY as mi, publicKeyFromZ32 as ml, assertTokenUnits as mn, isAppHash as mo, groupSignalFrame as mr, HANDOFF_TIMINGS as ms, verifyBitcoinMessage as mt, appStoreDecision as n, validExternalKey as na, enrollCancelFrame as nc, parseWakeFrame as ni, budgetRetryMs as nl, resolveDidDht as nn, sameButtonText as no, fetchesByItself as nr, HTTP_SERVICE_PROTO as ns, carryMentions as nt, APP_STORE_LIMITS as o, irohRelayUrl as oa, enrollGrantFrame as oc, vapidKeysMatch as oi, RELAY_PAYLOAD_MAX_BYTES as ol, ONCHAIN_PROVIDER as on, heardTime as oo, readGroupHave as or, HANDOFF_CANCEL as os, SSHSIG_MAX_ARMOR as ot, APP_ICON_PATH as p, sanitizeFileName as pa, deviceInviteJoinerParams as pc, STATUS_CARD_CAPABILITY as pi, identityFromSeedB64 as pl, arkAddressPrefix as pn, checkAppRevokeStatement as po, SIGNAL_REPLY_MS as pr, HANDOFF_REQUEST as ps, verifySshSignature as pt, parseGroupWakeFrame as q, PR_CHECKS as qa, turnName as qc, emptyIdentityLedger as qi, PAIRED_FRAME_TOO_LARGE as qn, RTC_CONFIG as qo, mayPin as qr, readSetUpdate as qs, parseDidDocument as qt, appUpdateDecision as r, TRANSPORTS as ra, enrollCancelReason as rc, relayRequest as ri, isDiscoveryBudgetError as rl, signDidDhtPacket as rn, statusCardText as ro, groupFileFallback as rr, LEGACY_SERVICES as rs, parseCommunityEdit as rt, checkAppStoreIndex as s, DHT_FILE_TOO_LARGE as sa, enrollHelloFrame as sc, APP_DATA_MAX_BYTES as si, createRelayPayload as sl, PaymentPreflightError as sn, receivedTimestamp as so, readGroupWant as sr, HANDOFF_DONE as ss, SSHSIG_NAMESPACE as st, appRevocationFor as t, emptyProofLedger as ta, ENROLL_PROOF as tc, newWakeToken as ti, traceLink as tl, encodeDidDhtPacket as tn, checkStatusCard as to, GROUP_WANT_NO_FRAME as tr, emptyLinkRecords as ts, GROUP_EDIT_TEXT_BYTES as tt, signAppStore as u, DHT_FILE_CAPABILITY as ua, readEnrollHello as uc, APPS_CAPABILITY as ui, parseRelayPayload as ul, TEST_USDT_FAUCET_AMOUNT as un, APP_STATEMENT_LIMITS as uo, GROUP_SIGNAL_FRAME as ur, HANDOFF_OFFER as us, parseSshSignature as ut, checkAppManifest as v, fileMessageText as va, encodeInviteCode as vc, HoldKeys as vi, bytesEqual as vl, walletNetworkOf as vn, readAppRevocations as vo, meshHubs as vr, handoffAttemptFailed as vs, ATPROTO_FULL_SCOPE as vt, GROUP_TYPING_FRAME as w, EDIT_BUFFER_MS as wa, HANDOFF_CAPABILITY as wc, decodeDnsResponse as wi, utf8Encode as wl, PUBKY_PROOF_MAX_BYTES as wn, GROUP_MEMBER_CAP as wo, freshHubs as wr, handoffDataFrame as ws, checkAtprotoProofRecord as wt, readAppBundle as x, parseVideoMeta as xa, ownInviteRefusal as xc, newMailbox as xi, toBase64Url as xl, sparkAddressKind as xn, canonicalJson as xo, beaconKeys as xr, handoffCancelFrame as xs, atprotoDidMethod as xt, isAppUrl as y, parseVoiceMeta as ya, inviteLink as yc, HoldRefusedError as yi, fromBase64Url as yl, SPARK_NETWORKS as yn, signAppObject as yo, pickMeshHubs as yr, handoffAttemptSucceeded as ys, ATPROTO_PROOF_COLLECTION as yt, knockIdentity as z, readReaction as za, TURN_MAX as zc, capsDescriptors as zi, fedimintRequestPayload as zn, GhostlyHttpError as zo, transferStalled as zr, readHandoffHave as zs, didSignedMessages as zt };
|
|
31223
|
+
export { COMMUNITY_EDIT_FRAME as $, buttonLabelClash as $a, currentRelays as $c, revokesIdentity as $i, GROUP_FILE_LIMITS as $n, extractParamsFromSdp as $o, WAKE_CALL_INTERVAL_MS as $r, ENROLL_DONE as $s, didDhtFromPublicKey as $t, CommunitySession as A, forwardedAgain as Aa, devicePingFrame as Ac, isPublicAddress as Ai, pubkyProofFile as An, rosterAdmin as Ao, newerHead as Ar, handoffOfferFrame as As, verifyAtprotoRecordProof as At, knockRecords as B, readReaction as Ba, TURN_MAX as Bc, capsDescriptors as Bi, findEndpoint as Bn, GhostlyHttpError as Bo, transferStalled as Br, readHandoffHave as Bs, didWebDocumentUrl as Bt, sha256Paced as C, parseImageMeta as Ca, DEVICES_CAPABILITY as Cc, readManifest as Ci, randomBytes as Cl, isBitcoinAddress as Cn, canonicalJsonBytes as Co, beaconRecords as Cr, handoffContext as Cs, atprotoProofRkey as Ct, openGroupTyping as D, RateWindow as Da, deviceEchoNonce as Dc, domainTxtRecord as Di, utf8Encode as Dl, newPubkyProofFolder as Dn, MEMBER_KEY as Do, lobbyRecords as Dr, handoffEphemeral as Ds, parseAtprotoDidDocument as Dt, groupTypingEpoch as E, EDIT_RATE_WINDOW_MS as Ea, deviceEchoFrame as Ec, dnsProofName as Ei, utf8Decode as El, isPubkyProofFolder as En, MAX_GROUP_CHAIN as Eo, lobbyKeys as Er, handoffDigest as Es, normalizeAtprotoHandle as Et, KNOCK_TTL_MS as F, ReactionWindow as Fa, TURN_RAISE_READ_TIMEOUT_MS as Fc, recordsName as Fi, resolveLightningDestination as Fn, AWAITING_PEER_MS as Fo, readLobby as Fr, handoffVersions as Fs, checkDidJws as Ft, groupWakeFrame as G, replySnippet as Ga, signTurnRelease as Gc, IdentityCheckUnavailable as Gi, INVITE_TAKEN as Gn, decodeControl as Go, typingActivity as Gr, sealHandoffPiece as Gs, normalizeDid as Gt, readKnocks as H, wireReaction as Ha, nextTurnPosition as Hc, IDENTITY_MAX_EVIDENCE as Hi, parseCashuRequestPayload as Hn, parseLocalTarget as Ho, TYPING_REFRESH_MS as Hr, readHandoffPake as Hs, didWebFileNames as Ht, decodeGroupEntryLink as I, nextReactionNumber as Ia, TURN_SETTLE_MS as Ic, txtValue as Ii, decodeBolt11 as In, DHT_POLL_INTERVALS as Io, shouldBeHub as Ir, newHandoffId as Is, checkDidSignature as It, GROUP_LIMITS as J, PR_CHECKS as Ja, turnName as Jc, emptyIdentityLedger as Ji, pairedMessageFits as Jn, RTC_CONFIG as Jo, mayPin as Jr, readSetUpdate as Js, parseDidSignaturePaste as Jt, groupWakes as K, BUTTON_ID as Ka, turnInstance as Kc, IdentityExchange as Ki, LIVENESS_PING_MS as Kn, encodeControl as Ko, GROUP_PIN_FRAME as Kr, SET_ACK as Ks, parseDid as Kt, encodeGroupEntryLink as L, queueReaction as La, classifyTurnRead as Lc, wellKnownUrl as Li, ENDPOINT as Ln, EXPECT_PEER_MS as Lo, ChatFiles as Lr, readHandoffAck as Ls, didGhostlyServiceEntry as Lt, communityHasFrame as M, COMMUNITY_REACTION_FRAME as Ma, seedSigner as Mc, normalizeDomain as Mi, homeserverWebEndpoint as Mn, verifyCommitSignature as Mo, rankHubs as Mr, handoffReleaseFrame as Ms, DID_FILE_MAX_BYTES as Mt, decodeCommunityLink as N, GROUP_REACTION_FRAME as Na, webCryptoSigner as Nc, recordsFromTxt as Ni, pubkyHomeserverOf as Nn, edgeParams as No, readBeacon as Nr, handoffRetryAfter as Ns, DID_JWS_MAX_LENGTH as Nt, sealGroupTyping as O, dhtEditId as Oa, deviceKeyZ32 as Oc, domainWellKnownFile as Oi, normalizePubkyKey as On, commitHash as Oo, mergeBeacon as Or, handoffHelloFrame as Os, shortAtprotoDid as Ot, encodeCommunityLink as P, REACTION_LIMITS as Pa, TURN_PUT_WINDOW_MS as Pc, recordsFromWellKnown as Pi, requestLnurlInvoice as Pn, DirectPathWatch as Po, readBeaconHead as Pr, handoffStreamKey as Ps, DidError as Pt, frameBytes as Q, appCardId as Qa, RelayTransport as Qc, receivedIdentityStatus as Qi, parseEngineError as Qn, callSignalHeardAt as Qo, readPin as Qr, verifySetUpdate as Qs, didDhtDocument as Qt, entryParams as R, reactionEmoji as Ra, turnPutSummary as Rc, CapsExchange as Ri, cashuRequestPayload as Rn, RELAY_POLL_INTERVALS as Ro, FILE_LIMITS as Rr, readHandoffCancel as Rs, didJwsAlg as Rt, readAppBundleAsync as S, parseVideoMeta as Sa, ownInviteRefusal as Sc, newMailbox as Si, isZ32Key as Sl, sparkInvoiceDetails as Sn, canonicalJson as So, beaconKeys as Sr, handoffCancelFrame as Ss, atprotoProofRecord as St, GroupTypingBoard as T, EDIT_BUFFER_MS as Ta, HANDOFF_CAPABILITY as Tc, decodeDnsResponse as Ti, toZ32 as Tl, isPubkyKey as Tn, GROUP_MEMBER_CAP as To, freshHubs as Tr, handoffDataFrame as Ts, isAtprotoDid as Tt, GROUP_WAKE_FRAME as U, pairedReplyAuthor as Ua, readTurnPacket as Uc, IDENTITY_MAX_VALIDITY as Ui, parseFedimintRequestPayload as Un, webLocalFetch as Uo, TypingSender as Ur, readHandoffTurnFrame as Us, didWebFileUrl as Ut, mergeKnocks as V, validReactionNumber as Va, firstDeviceSetSecret as Vc, dialDescriptors as Vi, isFederationId as Vn, formatLocalTarget as Vo, TYPING_KINDS as Vr, readHandoffHello as Vs, didWebFile as Vt, GroupWakeLimiter as W, readReply as Wa, signTurnPacket as Wc, IDENTITY_REVOCATION_LABEL as Wi, GhostLink as Wn, LIMITS as Wo, sanitizeTypingStatus as Wr, readHandoffVerified as Ws, didWebHost as Wt, GROUP_READ_NOTE as X, RUN_RESULTS as Xa, turnVerifierMark as Xc, identityStatement as Xi, engineError as Xn, buildSdpFromSignal as Xo, pinIsNewer as Xr, setUpdateFrame as Xs, staticDidDocument as Xt, GROUP_REACTED_FRAME as Y, PR_STATES as Ya, turnStatedVerifier as Yc, identityRevocationValue as Yi, pairedMessageFrame as Yn, answersOffer as Yo, nextPinNumber as Yr, setAckFrame as Ys, signingKeys as Yt, GroupSession as Z, STATUS_CARD_LIMITS as Za, DEFAULT_RELAYS as Zc, newIdentityBinding as Zi, engineText as Zn, callRtcConfig as Zo, pinNumberHolds as Zr, signTombstone as Zs, strictBase64Url as Zt, assembleAppBundle as _, VOICE_LIMITS as _a, createChatInvite as _c, HOLD_DATED_BACK_MS as _i, MAX_AVATAR_LENGTH as _l, validatePaymentTarget as _n, isAppRef as _o, MESH_HUBS as _r, filePartName as _s, ATPROTO_DECLARED_SCOPE as _t, planAppUpdate as a, automaticTransport as aa, enrollDigits as ac, wakeRequest as ai, withRequestOptions as al, EVM_TEST_CHAINS as an, arrivalKey as ao, isGroupMessageId as ar, serviceIdFromName as as, groupName as at, pacer as b, parseVoiceMeta as ba, inviteLink as bc, HoldRefusedError as bi, bytesEqual as bl, SPARK_PROVIDER as bn, signAppObject as bo, pickMeshHubs as br, handoffAttemptSucceeded as bs, ATPROTO_PROOF_SCOPE as bt, readAppStore as c, DHT_FILE_TOO_LARGE as ca, enrollHelloFrame as cc, APP_DATA_MAX_BYTES as ci, createRelayPayload as cl, SEPOLIA_TEST_USDT as cn, receivedTimestamp as co, readGroupWant as cr, HANDOFF_DONE as cs, SshSigError as ct, APP_BUNDLE_LIMITS as d, DHT_FILE_CAPABILITY as da, readEnrollHello as dc, APPS_CAPABILITY as di, parseRelayPayload as dl, USDT_PUBLIC_RPC as dn, APP_STATEMENT_LIMITS as do, GROUP_SIGNAL_FRAME as dr, HANDOFF_OFFER as ds, sameSshKey as dt, lastSharedWithMe as ea, ENROLL_GRANT as ec, WakeLimiter as ei, normalizeRelayUrl as el, encodeDidDhtDeactivated as en, cardLine as eo, GROUP_HAVE_FRAME as er, parseCallSignal as es, GROUP_EDIT_FRAME as et, APP_BUNDLE_MAGIC as f, dhtFileId as fa, verifyEnrollProof as fc, BUTTONS_CAPABILITY as fi, createIdentity as fl, WALLET_NETWORKS as fn, appFingerprint as fo, SIGNAL_FRESH_MS as fr, HANDOFF_PAKE as fs, sshSignCommand as ft, appViewOf as g, PLAYABLE_AUDIO as ga, OwnInviteError as gc, HOLD_CAPABILITY as gi, verify as gl, formatPaymentAmount as gn, isAppKey as go, readGroupSignal as gr, HANDOFF_VERIFIED as gs, decodeAnyBitcoinAddress as gt, appDigest as h, sanitizeMime as ha, readDeviceInvite as hc, UPGRADE_CAPABILITY as hi, publicKeyFromZ32 as hl, assertWholeSats as hn, isAppHash as ho, groupSignalFrame as hr, HANDOFF_TIMINGS as hs, BitcoinAddressError as ht, checkAppBeforeRun as i, TRANSPORTS as ia, enrollCancelReason as ic, relayRequest as ii, isDiscoveryBudgetError as il, ETHEREUM_USDT as in, statusCardText as io, groupFileFallback as ir, LEGACY_SERVICES as is, mentionsMember as it, GROUP_READ_NOTE_COMMUNITY as j, readForwarded as ja, newDeviceSetSecret as jc, nip05RootKey as ji, pubkyProofPath as jn, rosterHas as jo, pickHubs as jr, handoffPakeFrame as js, DID_DOCUMENT_MAX_BYTES as jt, COMMUNITY_LIMITS as k, parseLinkPreview as ka, deviceLinkPairing as kc, encodeDnsQuery as ki, pubkyProofCapability as kn, parseGroupCommit as ko, mergeLobby as kr, handoffManifestFrames as ks, AtprotoProofError as kt, readAppStoreSteps as l, DHT_MESSAGE_TTL as la, enrollProofFrame as lc, chatAppId as li, newerPacket as ll, SEPOLIA_TEST_USDT_FAUCET as ln, shownTime as lo, readGroupWantNo as lr, HANDOFF_HAVE as ls, parseSshPublicKey as lt, APP_PERMISSIONS as m, sanitizeFileName as ma, deviceInviteJoinerParams as mc, STATUS_CARD_CAPABILITY as mi, identityFromSeedB64 as ml, assertTokenUnits as mn, checkAppRevokeStatement as mo, SIGNAL_REPLY_MS as mr, HANDOFF_REQUEST as ms, verifyBitcoinMessage as mt, appStoreDecision as n, emptyProofLedger as na, ENROLL_PROOF as nc, newWakeToken as ni, traceLink as nl, resolveDidDht as nn, checkStatusCard as no, GROUP_WANT_NO_FRAME as nr, emptyLinkRecords as ns, carryMentions as nt, APP_STORE_LIMITS as o, irohDescriptor as oa, enrollDoneFrame as oc, checkPushEndpoint as oi, PacketTooLargeError as ol, ONCHAIN_PROVIDER as on, claimedTime as oo, readGroupFileMeta as or, HANDOFF_ACK as os, SSHSIG_MAX_ARMOR as ot, APP_ICON_PATH as p, formatFileSize as pa, createDeviceInvite as pc, EDIT_CAPABILITY as pi, identityFromSeed as pl, arkAddressPrefix as pn, appRef as po, SIGNAL_HOLD_MS as pr, HANDOFF_PIECE_BYTES as ps, verifySshSignature as pt, parseGroupWakeFrame as q, ITEM_STATES as qa, turnKeys as qc, boundVerifiedIdentity as qi, PAIRED_FRAME_TOO_LARGE as qn, CALL_SIGNAL_MAX_AGE_MS as qo, PIN_LIMITS as qr, SET_UPDATE as qs, parseDidDocument as qt, appUpdateDecision as r, validExternalKey as ra, enrollCancelFrame as rc, parseWakeFrame as ri, budgetRetryMs as rl, signDidDhtPacket as rn, sameButtonText as ro, fetchesByItself as rr, HTTP_SERVICE_PROTO as rs, parseCommunityEdit as rt, checkAppStoreIndex as s, irohRelayUrl as sa, enrollGrantFrame as sc, vapidKeysMatch as si, RELAY_PAYLOAD_MAX_BYTES as sl, PaymentPreflightError as sn, heardTime as so, readGroupHave as sr, HANDOFF_CANCEL as ss, SSHSIG_NAMESPACE as st, appRevocationFor as t, PeerProofs as ta, ENROLL_HELLO as tc, deviceWakeRequest as ti, setLinkTraceSink as tl, encodeDidDhtPacket as tn, cardUrl as to, GROUP_WANT_FRAME as tr, signalHasVideo as ts, GROUP_EDIT_TEXT_BYTES as tt, signAppStore as u, peekDhtMailbox as ua, readEnrollGrant as uc, isAppVersion as ui, openRelayPayload as ul, TEST_USDT_FAUCET_AMOUNT as un, APP_PREFIXES as uo, CarriedTransport as ur, HANDOFF_HELLO as us, parseSshSignature as ut, checkAppManifest as v, baseMime as va, decodeInviteCode as vc, HOLD_LIMITS as vi, sanitizeAvatar as vl, walletNetworkOf as vn, readAppRevocation as vo, mayBeHub as vr, handoffAttemptAllowed as vs, ATPROTO_FULL_SCOPE as vt, GROUP_TYPING_FRAME as w, readImageMeta as wa, ENROLL_CAPABILITY as wc, DOMAIN_FILE_MAX_BYTES as wi, toBase64Url as wl, PUBKY_PROOF_MAX_BYTES as wn, readCanonicalJson as wo, doorHubs as wr, handoffContextProof as ws, checkAtprotoProofRecord as wt, readAppBundle as x, voicePeaksOf as xa, inviteOwnership as xc, isHoldUrl as xi, fromBase64Url as xl, sparkAddressKind as xn, signAppRevocation as xo, COMMUNITY_TOPOLOGY as xr, handoffBusyFrame as xs, atprotoDidMethod as xt, isAppUrl as y, fileMessageText as ya, encodeInviteCode as yc, HoldKeys as yi, sanitizeDisplayText as yl, SPARK_NETWORKS as yn, readAppRevocations as yo, meshHubs as yr, handoffAttemptFailed as ys, ATPROTO_PROOF_COLLECTION as yt, knockIdentity as z, reactionIsNewer as za, TURN_LAST_SEQUENCE as zc, DHT_TEXT_CAPABILITY as zi, fedimintRequestPayload as zn, presenceSeenAt as zo, transferEnded as zr, readHandoffDone as zs, didSignedMessages as zt };
|
|
31006
31224
|
|
|
31007
|
-
//# sourceMappingURL=src-
|
|
31225
|
+
//# sourceMappingURL=src-RQ6OJOUO.js.map
|