@antzsoft/chat-core 1.2.4 → 1.2.5
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/dist/{chunk-6NMA64BX.js → chunk-ZNA6B2R5.js} +235 -62
- package/dist/chunk-ZNA6B2R5.js.map +1 -0
- package/dist/index.cjs +223 -136
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +32 -3
- package/dist/index.d.ts +32 -3
- package/dist/index.js +58 -137
- package/dist/index.js.map +1 -1
- package/dist/internal.cjs.map +1 -1
- package/dist/internal.d.cts +1 -1
- package/dist/internal.d.ts +1 -1
- package/dist/internal.js +1 -1
- package/dist/{storage-Bp6fk9aM.d.cts → storage-CctLCOnZ.d.cts} +1 -1
- package/dist/{storage-Bp6fk9aM.d.ts → storage-CctLCOnZ.d.ts} +1 -1
- package/package.json +1 -1
- package/dist/chunk-6NMA64BX.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -105,18 +105,27 @@ __export(src_exports, {
|
|
|
105
105
|
connectSocket: () => connectSocket,
|
|
106
106
|
conversationsApi: () => conversationsApi,
|
|
107
107
|
createAuthStore: () => createAuthStore,
|
|
108
|
+
createRestTransitSession: () => createRestTransitSession,
|
|
109
|
+
decryptPayload: () => decryptPayload,
|
|
108
110
|
devicesApi: () => devicesApi,
|
|
109
111
|
disconnectSocket: () => disconnectSocket,
|
|
112
|
+
encryptPayload: () => encryptPayload,
|
|
113
|
+
fetchServerKeys: () => fetchServerKeys,
|
|
114
|
+
generateEphemeralKey: () => generateEphemeralKey,
|
|
110
115
|
getApiClient: () => getApiClient,
|
|
111
116
|
getAuthStore: () => getAuthStore,
|
|
112
117
|
getCompressionStrategy: () => getCompressionStrategy,
|
|
118
|
+
getSessionId: () => getSessionId,
|
|
119
|
+
getSessionKey: () => getSessionKey,
|
|
113
120
|
getSocket: () => getSocket,
|
|
114
121
|
getSocketStatus: () => getSocketStatus,
|
|
115
122
|
initApiClient: () => initApiClient,
|
|
116
123
|
initAuthStore: () => initAuthStore,
|
|
124
|
+
isTransitEnvelope: () => isTransitEnvelope,
|
|
117
125
|
messagesApi: () => messagesApi,
|
|
118
126
|
normalizeConversation: () => normalizeConversation,
|
|
119
127
|
onSocketStatus: () => onSocketStatus,
|
|
128
|
+
performHandshake: () => performHandshake,
|
|
120
129
|
reconnectSocket: () => reconnectSocket,
|
|
121
130
|
refreshSocketAuth: () => refreshSocketAuth,
|
|
122
131
|
resetAuthStore: () => resetAuthStore,
|
|
@@ -391,6 +400,9 @@ function setTransitSession(session) {
|
|
|
391
400
|
s.readyResolve?.();
|
|
392
401
|
s.readyResolve = null;
|
|
393
402
|
}
|
|
403
|
+
function getTransitSession() {
|
|
404
|
+
return getState().session;
|
|
405
|
+
}
|
|
394
406
|
function clearTransitSession() {
|
|
395
407
|
const s = getState();
|
|
396
408
|
s.session = null;
|
|
@@ -407,10 +419,156 @@ function getSessionId() {
|
|
|
407
419
|
return getState().session?.sessionId ?? null;
|
|
408
420
|
}
|
|
409
421
|
|
|
422
|
+
// src/crypto/detect.ts
|
|
423
|
+
var _cached = null;
|
|
424
|
+
async function detectTransitAlgo() {
|
|
425
|
+
if (_cached) return _cached;
|
|
426
|
+
try {
|
|
427
|
+
await globalThis.crypto.subtle.generateKey(
|
|
428
|
+
{ name: "X25519" },
|
|
429
|
+
false,
|
|
430
|
+
["deriveKey"]
|
|
431
|
+
);
|
|
432
|
+
_cached = "x25519";
|
|
433
|
+
} catch {
|
|
434
|
+
_cached = "p256";
|
|
435
|
+
}
|
|
436
|
+
return _cached;
|
|
437
|
+
}
|
|
438
|
+
function resetAlgoCache() {
|
|
439
|
+
_cached = null;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// src/crypto/handshake.ts
|
|
443
|
+
function hasWebCrypto2() {
|
|
444
|
+
return typeof globalThis.crypto?.subtle !== "undefined";
|
|
445
|
+
}
|
|
446
|
+
async function fetchServerKeys(apiUrl) {
|
|
447
|
+
const res = await fetch(`${apiUrl}/crypto/pubkey`);
|
|
448
|
+
if (!res.ok) throw new Error(`[AntzChat] Failed to fetch server public key: ${res.status}`);
|
|
449
|
+
const body = await res.json();
|
|
450
|
+
return body?.data ?? body;
|
|
451
|
+
}
|
|
452
|
+
async function generateEphemeralKey(algo, serverKeys) {
|
|
453
|
+
if (hasWebCrypto2()) {
|
|
454
|
+
return generateWebCryptoEphemeralKey(algo, serverKeys);
|
|
455
|
+
}
|
|
456
|
+
return generateNobleEphemeralKey(serverKeys);
|
|
457
|
+
}
|
|
458
|
+
async function createRestTransitSession(apiUrl) {
|
|
459
|
+
try {
|
|
460
|
+
const serverKeys = await fetchServerKeys(apiUrl);
|
|
461
|
+
if (!serverKeys.enabled) return null;
|
|
462
|
+
const algo = hasWebCrypto2() ? await detectTransitAlgo() : "x25519";
|
|
463
|
+
const { ephemeralPubB64, deriveSessionKey } = await generateEphemeralKey(algo, serverKeys);
|
|
464
|
+
const res = await fetch(`${apiUrl}/crypto/session`, {
|
|
465
|
+
method: "POST",
|
|
466
|
+
headers: { "Content-Type": "application/json" },
|
|
467
|
+
body: JSON.stringify({ ephemeralPub: ephemeralPubB64, algo })
|
|
468
|
+
});
|
|
469
|
+
if (!res.ok) return null;
|
|
470
|
+
const body = await res.json();
|
|
471
|
+
const sessionId = (body?.data ?? body)?.sessionId ?? body?.sessionId;
|
|
472
|
+
if (!sessionId) return null;
|
|
473
|
+
const sessionKey = await deriveSessionKey(sessionId);
|
|
474
|
+
return { sessionId, sessionKey };
|
|
475
|
+
} catch {
|
|
476
|
+
return null;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
async function performHandshake(algo, serverKeys, socketHandshakeAuth) {
|
|
480
|
+
const { ephemeralPubB64, deriveSessionKey } = await generateEphemeralKey(algo, serverKeys);
|
|
481
|
+
socketHandshakeAuth["transitEphemeralPub"] = ephemeralPubB64;
|
|
482
|
+
socketHandshakeAuth["transitAlgo"] = algo;
|
|
483
|
+
return deriveSessionKey;
|
|
484
|
+
}
|
|
485
|
+
async function generateWebCryptoEphemeralKey(algo, serverKeys) {
|
|
486
|
+
const ephemeral = await globalThis.crypto.subtle.generateKey(
|
|
487
|
+
algo === "x25519" ? { name: "X25519" } : { name: "ECDH", namedCurve: "P-256" },
|
|
488
|
+
false,
|
|
489
|
+
["deriveBits"]
|
|
490
|
+
);
|
|
491
|
+
const pubRaw = await globalThis.crypto.subtle.exportKey("raw", ephemeral.publicKey);
|
|
492
|
+
const ephemeralPriv = ephemeral.privateKey;
|
|
493
|
+
return {
|
|
494
|
+
ephemeralPubB64: bufToB642(pubRaw),
|
|
495
|
+
deriveSessionKey: (sessionId) => deriveWebCryptoSessionKey(ephemeralPriv, algo, serverKeys, sessionId)
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
async function deriveWebCryptoSessionKey(ephemeralPriv, algo, serverKeys, sessionId) {
|
|
499
|
+
const serverPubRaw = b64ToBuf2(algo === "x25519" ? serverKeys.x25519 : serverKeys.p256);
|
|
500
|
+
const keyAlgoParams = algo === "x25519" ? { name: "X25519" } : { name: "ECDH", namedCurve: "P-256" };
|
|
501
|
+
const serverPubKey = await globalThis.crypto.subtle.importKey("raw", serverPubRaw, keyAlgoParams, false, []);
|
|
502
|
+
const sharedBits = await globalThis.crypto.subtle.deriveBits(
|
|
503
|
+
{ name: algo === "x25519" ? "X25519" : "ECDH", public: serverPubKey },
|
|
504
|
+
ephemeralPriv,
|
|
505
|
+
256
|
|
506
|
+
);
|
|
507
|
+
const hkdfKey = await globalThis.crypto.subtle.importKey("raw", sharedBits, "HKDF", false, ["deriveKey"]);
|
|
508
|
+
const salt = new TextEncoder().encode(sessionId);
|
|
509
|
+
const info = new TextEncoder().encode("antz-transit-v1");
|
|
510
|
+
return globalThis.crypto.subtle.deriveKey(
|
|
511
|
+
{ name: "HKDF", hash: "SHA-256", salt, info },
|
|
512
|
+
hkdfKey,
|
|
513
|
+
{ name: "AES-GCM", length: 256 },
|
|
514
|
+
false,
|
|
515
|
+
["encrypt", "decrypt"]
|
|
516
|
+
);
|
|
517
|
+
}
|
|
518
|
+
async function generateNobleEphemeralKey(serverKeys) {
|
|
519
|
+
const { x25519 } = await import("@noble/curves/ed25519");
|
|
520
|
+
const { hkdf } = await import("@noble/hashes/hkdf");
|
|
521
|
+
const { sha256 } = await import("@noble/hashes/sha256");
|
|
522
|
+
const { randomBytes } = await import("@noble/hashes/utils");
|
|
523
|
+
const ephemeralPriv = randomBytes(32);
|
|
524
|
+
const ephemeralPub = x25519.getPublicKey(ephemeralPriv);
|
|
525
|
+
const serverPubBytes = base64ToUint82(serverKeys.x25519);
|
|
526
|
+
return {
|
|
527
|
+
ephemeralPubB64: uint8ToBase64(ephemeralPub),
|
|
528
|
+
deriveSessionKey: (sessionId) => {
|
|
529
|
+
const sharedSecret = x25519.getSharedSecret(ephemeralPriv, serverPubBytes);
|
|
530
|
+
const salt = new TextEncoder().encode(sessionId);
|
|
531
|
+
const info = new TextEncoder().encode("antz-transit-v1");
|
|
532
|
+
return Promise.resolve(hkdf(sha256, sharedSecret, salt, info, 32));
|
|
533
|
+
}
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
function bufToB642(buf) {
|
|
537
|
+
const bytes = new Uint8Array(buf);
|
|
538
|
+
let str = "";
|
|
539
|
+
bytes.forEach((b) => {
|
|
540
|
+
str += String.fromCharCode(b);
|
|
541
|
+
});
|
|
542
|
+
return btoa(str);
|
|
543
|
+
}
|
|
544
|
+
function b64ToBuf2(b64) {
|
|
545
|
+
const bin = atob(b64);
|
|
546
|
+
const buf = new Uint8Array(bin.length);
|
|
547
|
+
for (let i = 0; i < bin.length; i++) buf[i] = bin.charCodeAt(i);
|
|
548
|
+
return buf.buffer;
|
|
549
|
+
}
|
|
550
|
+
function uint8ToBase64(bytes) {
|
|
551
|
+
let str = "";
|
|
552
|
+
bytes.forEach((b) => {
|
|
553
|
+
str += String.fromCharCode(b);
|
|
554
|
+
});
|
|
555
|
+
return btoa(str);
|
|
556
|
+
}
|
|
557
|
+
function base64ToUint82(b64) {
|
|
558
|
+
const bin = atob(b64);
|
|
559
|
+
const buf = new Uint8Array(bin.length);
|
|
560
|
+
for (let i = 0; i < bin.length; i++) buf[i] = bin.charCodeAt(i);
|
|
561
|
+
return buf;
|
|
562
|
+
}
|
|
563
|
+
|
|
410
564
|
// src/api/client.ts
|
|
411
565
|
var _tokenStore = null;
|
|
412
566
|
var _config = null;
|
|
413
567
|
var _avatarSent = false;
|
|
568
|
+
var _transitHandshakePromise = null;
|
|
569
|
+
function getTransitHandshakePromise() {
|
|
570
|
+
return _transitHandshakePromise;
|
|
571
|
+
}
|
|
414
572
|
function initApiClient(config, tokenStore) {
|
|
415
573
|
_config = config;
|
|
416
574
|
_tokenStore = tokenStore;
|
|
@@ -420,6 +578,23 @@ function initApiClient(config, tokenStore) {
|
|
|
420
578
|
headers: { "Content-Type": "application/json" }
|
|
421
579
|
});
|
|
422
580
|
configureTransit(config.transitEncryption);
|
|
581
|
+
if (config.transitEncryption && !getTransitSession() && !_transitHandshakePromise) {
|
|
582
|
+
_transitHandshakePromise = (async () => {
|
|
583
|
+
try {
|
|
584
|
+
const session = await createRestTransitSession(config.apiUrl);
|
|
585
|
+
if (session && !getTransitSession()) {
|
|
586
|
+
const algo = typeof globalThis.crypto?.subtle !== "undefined" ? await detectTransitAlgo() : "x25519";
|
|
587
|
+
setTransitSession({ sessionKey: session.sessionKey, algo, sessionId: session.sessionId, enabled: true });
|
|
588
|
+
} else if (!session) {
|
|
589
|
+
configureTransit(false);
|
|
590
|
+
}
|
|
591
|
+
} catch {
|
|
592
|
+
configureTransit(false);
|
|
593
|
+
} finally {
|
|
594
|
+
_transitHandshakePromise = null;
|
|
595
|
+
}
|
|
596
|
+
})();
|
|
597
|
+
}
|
|
423
598
|
client.interceptors.request.use(async (req) => {
|
|
424
599
|
const token = _tokenStore?.getAccessToken();
|
|
425
600
|
if (token) req.headers["Authorization"] = `Bearer ${token}`;
|
|
@@ -827,7 +1002,8 @@ function normalizeLastMessage(lastMsg) {
|
|
|
827
1002
|
isEdited: false,
|
|
828
1003
|
sentAt: lastMsg.sentAt ?? "",
|
|
829
1004
|
createdAt: lastMsg.sentAt ?? "",
|
|
830
|
-
...lastMsg.senderName && { senderName: lastMsg.senderName }
|
|
1005
|
+
...lastMsg.senderName && { senderName: lastMsg.senderName },
|
|
1006
|
+
...lastMsg.attachmentType && { attachmentType: lastMsg.attachmentType }
|
|
831
1007
|
};
|
|
832
1008
|
}
|
|
833
1009
|
function normalizeConversation(conv) {
|
|
@@ -1191,122 +1367,6 @@ var usersApi = {
|
|
|
1191
1367
|
|
|
1192
1368
|
// src/socket/socket.ts
|
|
1193
1369
|
var import_socket = require("socket.io-client");
|
|
1194
|
-
|
|
1195
|
-
// src/crypto/detect.ts
|
|
1196
|
-
var _cached = null;
|
|
1197
|
-
async function detectTransitAlgo() {
|
|
1198
|
-
if (_cached) return _cached;
|
|
1199
|
-
try {
|
|
1200
|
-
await globalThis.crypto.subtle.generateKey(
|
|
1201
|
-
{ name: "X25519" },
|
|
1202
|
-
false,
|
|
1203
|
-
["deriveKey"]
|
|
1204
|
-
);
|
|
1205
|
-
_cached = "x25519";
|
|
1206
|
-
} catch {
|
|
1207
|
-
_cached = "p256";
|
|
1208
|
-
}
|
|
1209
|
-
return _cached;
|
|
1210
|
-
}
|
|
1211
|
-
function resetAlgoCache() {
|
|
1212
|
-
_cached = null;
|
|
1213
|
-
}
|
|
1214
|
-
|
|
1215
|
-
// src/crypto/handshake.ts
|
|
1216
|
-
function hasWebCrypto2() {
|
|
1217
|
-
return typeof globalThis.crypto?.subtle !== "undefined";
|
|
1218
|
-
}
|
|
1219
|
-
async function fetchServerKeys(apiUrl) {
|
|
1220
|
-
const res = await fetch(`${apiUrl}/crypto/pubkey`);
|
|
1221
|
-
if (!res.ok) throw new Error(`[AntzChat] Failed to fetch server public key: ${res.status}`);
|
|
1222
|
-
const body = await res.json();
|
|
1223
|
-
return body?.data ?? body;
|
|
1224
|
-
}
|
|
1225
|
-
async function performHandshake(algo, serverKeys, socketHandshakeAuth) {
|
|
1226
|
-
if (hasWebCrypto2()) {
|
|
1227
|
-
return performWebCryptoHandshake(algo, serverKeys, socketHandshakeAuth);
|
|
1228
|
-
}
|
|
1229
|
-
return performNobleHandshake(serverKeys, socketHandshakeAuth);
|
|
1230
|
-
}
|
|
1231
|
-
async function performWebCryptoHandshake(algo, serverKeys, socketHandshakeAuth) {
|
|
1232
|
-
const ephemeral = await globalThis.crypto.subtle.generateKey(
|
|
1233
|
-
algo === "x25519" ? { name: "X25519" } : { name: "ECDH", namedCurve: "P-256" },
|
|
1234
|
-
false,
|
|
1235
|
-
["deriveBits"]
|
|
1236
|
-
);
|
|
1237
|
-
const pubRaw = await globalThis.crypto.subtle.exportKey("raw", ephemeral.publicKey);
|
|
1238
|
-
socketHandshakeAuth["transitEphemeralPub"] = bufToB642(pubRaw);
|
|
1239
|
-
socketHandshakeAuth["transitAlgo"] = algo;
|
|
1240
|
-
const ephemeralPriv = ephemeral.privateKey;
|
|
1241
|
-
return (sessionId) => deriveWebCryptoSessionKey(ephemeralPriv, algo, serverKeys, sessionId);
|
|
1242
|
-
}
|
|
1243
|
-
async function deriveWebCryptoSessionKey(ephemeralPriv, algo, serverKeys, sessionId) {
|
|
1244
|
-
const serverPubRaw = b64ToBuf2(algo === "x25519" ? serverKeys.x25519 : serverKeys.p256);
|
|
1245
|
-
const keyAlgoParams = algo === "x25519" ? { name: "X25519" } : { name: "ECDH", namedCurve: "P-256" };
|
|
1246
|
-
const serverPubKey = await globalThis.crypto.subtle.importKey("raw", serverPubRaw, keyAlgoParams, false, []);
|
|
1247
|
-
const sharedBits = await globalThis.crypto.subtle.deriveBits(
|
|
1248
|
-
{ name: algo === "x25519" ? "X25519" : "ECDH", public: serverPubKey },
|
|
1249
|
-
ephemeralPriv,
|
|
1250
|
-
256
|
|
1251
|
-
);
|
|
1252
|
-
const hkdfKey = await globalThis.crypto.subtle.importKey("raw", sharedBits, "HKDF", false, ["deriveKey"]);
|
|
1253
|
-
const salt = new TextEncoder().encode(sessionId);
|
|
1254
|
-
const info = new TextEncoder().encode("antz-transit-v1");
|
|
1255
|
-
return globalThis.crypto.subtle.deriveKey(
|
|
1256
|
-
{ name: "HKDF", hash: "SHA-256", salt, info },
|
|
1257
|
-
hkdfKey,
|
|
1258
|
-
{ name: "AES-GCM", length: 256 },
|
|
1259
|
-
false,
|
|
1260
|
-
["encrypt", "decrypt"]
|
|
1261
|
-
);
|
|
1262
|
-
}
|
|
1263
|
-
async function performNobleHandshake(serverKeys, socketHandshakeAuth) {
|
|
1264
|
-
const { x25519 } = await import("@noble/curves/ed25519");
|
|
1265
|
-
const { hkdf } = await import("@noble/hashes/hkdf");
|
|
1266
|
-
const { sha256 } = await import("@noble/hashes/sha256");
|
|
1267
|
-
const { randomBytes } = await import("@noble/hashes/utils");
|
|
1268
|
-
const ephemeralPriv = randomBytes(32);
|
|
1269
|
-
const ephemeralPub = x25519.getPublicKey(ephemeralPriv);
|
|
1270
|
-
const serverPubBytes = base64ToUint82(serverKeys.x25519);
|
|
1271
|
-
socketHandshakeAuth["transitEphemeralPub"] = uint8ToBase64(ephemeralPub);
|
|
1272
|
-
socketHandshakeAuth["transitAlgo"] = "x25519";
|
|
1273
|
-
return (sessionId) => {
|
|
1274
|
-
const sharedSecret = x25519.getSharedSecret(ephemeralPriv, serverPubBytes);
|
|
1275
|
-
const salt = new TextEncoder().encode(sessionId);
|
|
1276
|
-
const info = new TextEncoder().encode("antz-transit-v1");
|
|
1277
|
-
const sessionKey = hkdf(sha256, sharedSecret, salt, info, 32);
|
|
1278
|
-
return Promise.resolve(sessionKey);
|
|
1279
|
-
};
|
|
1280
|
-
}
|
|
1281
|
-
function bufToB642(buf) {
|
|
1282
|
-
const bytes = new Uint8Array(buf);
|
|
1283
|
-
let str = "";
|
|
1284
|
-
bytes.forEach((b) => {
|
|
1285
|
-
str += String.fromCharCode(b);
|
|
1286
|
-
});
|
|
1287
|
-
return btoa(str);
|
|
1288
|
-
}
|
|
1289
|
-
function b64ToBuf2(b64) {
|
|
1290
|
-
const bin = atob(b64);
|
|
1291
|
-
const buf = new Uint8Array(bin.length);
|
|
1292
|
-
for (let i = 0; i < bin.length; i++) buf[i] = bin.charCodeAt(i);
|
|
1293
|
-
return buf.buffer;
|
|
1294
|
-
}
|
|
1295
|
-
function uint8ToBase64(bytes) {
|
|
1296
|
-
let str = "";
|
|
1297
|
-
bytes.forEach((b) => {
|
|
1298
|
-
str += String.fromCharCode(b);
|
|
1299
|
-
});
|
|
1300
|
-
return btoa(str);
|
|
1301
|
-
}
|
|
1302
|
-
function base64ToUint82(b64) {
|
|
1303
|
-
const bin = atob(b64);
|
|
1304
|
-
const buf = new Uint8Array(bin.length);
|
|
1305
|
-
for (let i = 0; i < bin.length; i++) buf[i] = bin.charCodeAt(i);
|
|
1306
|
-
return buf;
|
|
1307
|
-
}
|
|
1308
|
-
|
|
1309
|
-
// src/socket/socket.ts
|
|
1310
1370
|
var _socket = null;
|
|
1311
1371
|
var _socketProxy = null;
|
|
1312
1372
|
var _connectingPromise = null;
|
|
@@ -1403,17 +1463,35 @@ async function _doConnect(config, getToken) {
|
|
|
1403
1463
|
};
|
|
1404
1464
|
let boundDeriveSessionKey = null;
|
|
1405
1465
|
if (config.transitEncryption) {
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1466
|
+
const inFlight = getTransitHandshakePromise();
|
|
1467
|
+
if (inFlight) await inFlight;
|
|
1468
|
+
const existingSession = getTransitSession();
|
|
1469
|
+
let httpsSession = null;
|
|
1470
|
+
if (existingSession?.enabled && existingSession.sessionId) {
|
|
1471
|
+
httpsSession = { sessionId: existingSession.sessionId, sessionKey: existingSession.sessionKey };
|
|
1472
|
+
} else {
|
|
1473
|
+
httpsSession = await createRestTransitSession(config.apiUrl);
|
|
1474
|
+
if (httpsSession) {
|
|
1475
|
+
const algo = globalThis.crypto?.subtle ? await detectTransitAlgo() : "x25519";
|
|
1476
|
+
setTransitSession({ sessionKey: httpsSession.sessionKey, algo, sessionId: httpsSession.sessionId, enabled: true });
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
if (httpsSession) {
|
|
1480
|
+
socketHandshakeAuth["transitSessionId"] = httpsSession.sessionId;
|
|
1481
|
+
boundDeriveSessionKey = null;
|
|
1482
|
+
} else {
|
|
1483
|
+
try {
|
|
1484
|
+
const serverKeys = await fetchServerKeys(config.apiUrl);
|
|
1485
|
+
if (!serverKeys.enabled) {
|
|
1486
|
+
throw new Error(
|
|
1487
|
+
"[AntzChat] Transit encryption mismatch: SDK has transitEncryption=true but server has TRANSIT_ENCRYPTION_ENABLED=false. Align the config on both sides."
|
|
1488
|
+
);
|
|
1489
|
+
}
|
|
1490
|
+
const algo = globalThis.crypto?.subtle ? await detectTransitAlgo() : "x25519";
|
|
1491
|
+
boundDeriveSessionKey = await performHandshake(algo, serverKeys, socketHandshakeAuth);
|
|
1492
|
+
} catch (err) {
|
|
1493
|
+
throw err;
|
|
1412
1494
|
}
|
|
1413
|
-
const algo = globalThis.crypto?.subtle ? await detectTransitAlgo() : "x25519";
|
|
1414
|
-
boundDeriveSessionKey = await performHandshake(algo, serverKeys, socketHandshakeAuth);
|
|
1415
|
-
} catch (err) {
|
|
1416
|
-
throw err;
|
|
1417
1495
|
}
|
|
1418
1496
|
} else {
|
|
1419
1497
|
try {
|
|
@@ -1571,11 +1649,7 @@ async function drainSendQueue(conversationId) {
|
|
|
1571
1649
|
entry.reject(new Error("[AntzChat] Message dropped: queued too long"));
|
|
1572
1650
|
continue;
|
|
1573
1651
|
}
|
|
1574
|
-
|
|
1575
|
-
entry.resolve(await entry.run());
|
|
1576
|
-
} catch (e) {
|
|
1577
|
-
entry.reject(e);
|
|
1578
|
-
}
|
|
1652
|
+
entry.run().then(entry.resolve).catch(entry.reject);
|
|
1579
1653
|
}
|
|
1580
1654
|
sendQueues.delete(conversationId);
|
|
1581
1655
|
sendQueueRunning.delete(conversationId);
|
|
@@ -1619,11 +1693,13 @@ async function withAck(event, payload) {
|
|
|
1619
1693
|
}
|
|
1620
1694
|
if (!socket) return Promise.reject(new Error(`[AntzChat] Socket not connected (event: ${event})`));
|
|
1621
1695
|
return new Promise((resolve, reject) => {
|
|
1622
|
-
|
|
1696
|
+
let timer;
|
|
1623
1697
|
secureEmit(socket, event, payload, (response) => {
|
|
1624
1698
|
clearTimeout(timer);
|
|
1625
1699
|
resolve(response);
|
|
1626
|
-
})
|
|
1700
|
+
}).then(() => {
|
|
1701
|
+
timer = setTimeout(() => reject(new Error(`Socket ack timeout: ${event}`)), ACK_TIMEOUT);
|
|
1702
|
+
}).catch(reject);
|
|
1627
1703
|
});
|
|
1628
1704
|
}
|
|
1629
1705
|
function fireAndForget(event, payload) {
|
|
@@ -1673,7 +1749,7 @@ var socketEmit = {
|
|
|
1673
1749
|
const socket = tryGetSocket();
|
|
1674
1750
|
if (!socket) return Promise.resolve([]);
|
|
1675
1751
|
return new Promise((resolve, reject) => {
|
|
1676
|
-
|
|
1752
|
+
let timer;
|
|
1677
1753
|
secureEmit(socket, "get_online_users", { userIds }, (response) => {
|
|
1678
1754
|
clearTimeout(timer);
|
|
1679
1755
|
if (response && typeof response === "object" && "onlineStatus" in response) {
|
|
@@ -1684,7 +1760,9 @@ var socketEmit = {
|
|
|
1684
1760
|
} else {
|
|
1685
1761
|
resolve([]);
|
|
1686
1762
|
}
|
|
1687
|
-
})
|
|
1763
|
+
}).then(() => {
|
|
1764
|
+
timer = setTimeout(() => reject(new Error("get_online_users timeout")), ACK_TIMEOUT);
|
|
1765
|
+
}).catch(reject);
|
|
1688
1766
|
});
|
|
1689
1767
|
},
|
|
1690
1768
|
getTypingUsers(conversationId) {
|
|
@@ -1752,18 +1830,27 @@ var AntzChatClient = class {
|
|
|
1752
1830
|
connectSocket,
|
|
1753
1831
|
conversationsApi,
|
|
1754
1832
|
createAuthStore,
|
|
1833
|
+
createRestTransitSession,
|
|
1834
|
+
decryptPayload,
|
|
1755
1835
|
devicesApi,
|
|
1756
1836
|
disconnectSocket,
|
|
1837
|
+
encryptPayload,
|
|
1838
|
+
fetchServerKeys,
|
|
1839
|
+
generateEphemeralKey,
|
|
1757
1840
|
getApiClient,
|
|
1758
1841
|
getAuthStore,
|
|
1759
1842
|
getCompressionStrategy,
|
|
1843
|
+
getSessionId,
|
|
1844
|
+
getSessionKey,
|
|
1760
1845
|
getSocket,
|
|
1761
1846
|
getSocketStatus,
|
|
1762
1847
|
initApiClient,
|
|
1763
1848
|
initAuthStore,
|
|
1849
|
+
isTransitEnvelope,
|
|
1764
1850
|
messagesApi,
|
|
1765
1851
|
normalizeConversation,
|
|
1766
1852
|
onSocketStatus,
|
|
1853
|
+
performHandshake,
|
|
1767
1854
|
reconnectSocket,
|
|
1768
1855
|
refreshSocketAuth,
|
|
1769
1856
|
resetAuthStore,
|