@agentvault/agentvault 0.19.57 → 0.19.59
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/_cp.d.ts +10 -0
- package/dist/_cp.d.ts.map +1 -0
- package/dist/account-config.d.ts +20 -0
- package/dist/account-config.d.ts.map +1 -0
- package/dist/channel.d.ts +389 -0
- package/dist/channel.d.ts.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +47 -416
- package/dist/cli.js.map +2 -2
- package/dist/create-agent.d.ts +28 -0
- package/dist/create-agent.d.ts.map +1 -0
- package/dist/credential-store.d.ts +62 -0
- package/dist/credential-store.d.ts.map +1 -0
- package/dist/crypto-helpers.d.ts +2 -0
- package/dist/crypto-helpers.d.ts.map +1 -0
- package/dist/doctor.d.ts +41 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/fetch-interceptor.d.ts +32 -0
- package/dist/fetch-interceptor.d.ts.map +1 -0
- package/dist/gateway-send.d.ts +98 -0
- package/dist/gateway-send.d.ts.map +1 -0
- package/dist/http-handlers.d.ts +53 -0
- package/dist/http-handlers.d.ts.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +47 -416
- package/dist/index.js.map +2 -2
- package/dist/mcp-handlers.d.ts +26 -0
- package/dist/mcp-handlers.d.ts.map +1 -0
- package/dist/mcp-proxy-helpers.d.ts +9 -0
- package/dist/mcp-proxy-helpers.d.ts.map +1 -0
- package/dist/mcp-server.d.ts +91 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mls-state.d.ts +16 -0
- package/dist/mls-state.d.ts.map +1 -0
- package/dist/openclaw-compat.d.ts +33 -0
- package/dist/openclaw-compat.d.ts.map +1 -0
- package/dist/openclaw-entry.d.ts +32 -0
- package/dist/openclaw-entry.d.ts.map +1 -0
- package/dist/openclaw-plugin.d.ts +102 -0
- package/dist/openclaw-plugin.d.ts.map +1 -0
- package/dist/openclaw-types.d.ts +186 -0
- package/dist/openclaw-types.d.ts.map +1 -0
- package/dist/policy-enforcer.d.ts +78 -0
- package/dist/policy-enforcer.d.ts.map +1 -0
- package/dist/setup.d.ts +27 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/skill-invoker.d.ts +30 -0
- package/dist/skill-invoker.d.ts.map +1 -0
- package/dist/skill-manifest.d.ts +30 -0
- package/dist/skill-manifest.d.ts.map +1 -0
- package/dist/skill-telemetry.d.ts +36 -0
- package/dist/skill-telemetry.d.ts.map +1 -0
- package/dist/skills-publish.d.ts +8 -0
- package/dist/skills-publish.d.ts.map +1 -0
- package/dist/state.d.ts +32 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/transport.d.ts +24 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/types.d.ts +421 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/workspace-handlers.d.ts +62 -0
- package/dist/workspace-handlers.d.ts.map +1 -0
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -62647,6 +62647,24 @@ var init_channel = __esm({
|
|
|
62647
62647
|
if (this._persisted.seenA2AMessageIds) {
|
|
62648
62648
|
this._a2aSeenMessageIds = new Set(this._persisted.seenA2AMessageIds.slice(-_SecureChannel.A2A_SEEN_MAX));
|
|
62649
62649
|
}
|
|
62650
|
+
if (this._persisted?.rooms) {
|
|
62651
|
+
const roomConvIds = /* @__PURE__ */ new Set();
|
|
62652
|
+
for (const room of Object.values(this._persisted.rooms)) {
|
|
62653
|
+
for (const cid of room.conversationIds || []) {
|
|
62654
|
+
roomConvIds.add(cid);
|
|
62655
|
+
}
|
|
62656
|
+
}
|
|
62657
|
+
let cleanedCount = 0;
|
|
62658
|
+
for (const cid of roomConvIds) {
|
|
62659
|
+
if (this._persisted.sessions[cid]) {
|
|
62660
|
+
delete this._persisted.sessions[cid];
|
|
62661
|
+
cleanedCount++;
|
|
62662
|
+
}
|
|
62663
|
+
}
|
|
62664
|
+
if (cleanedCount > 0) {
|
|
62665
|
+
console.log(`[SecureChannel] Cleaned ${cleanedCount} stale DR room sessions`);
|
|
62666
|
+
}
|
|
62667
|
+
}
|
|
62650
62668
|
for (const [convId, sessionData] of Object.entries(
|
|
62651
62669
|
this._persisted.sessions
|
|
62652
62670
|
)) {
|
|
@@ -63019,98 +63037,34 @@ var init_channel = __esm({
|
|
|
63019
63037
|
}
|
|
63020
63038
|
// --- Multi-agent room methods ---
|
|
63021
63039
|
/**
|
|
63022
|
-
* Join a room by
|
|
63023
|
-
*
|
|
63040
|
+
* Join a room by collecting pairwise conversation IDs involving this device.
|
|
63041
|
+
* Encryption is handled by MLS group operations, not per-member DR sessions.
|
|
63024
63042
|
*/
|
|
63025
63043
|
async joinRoom(roomData) {
|
|
63026
63044
|
if (!this._persisted) {
|
|
63027
63045
|
throw new Error("Channel not initialized");
|
|
63028
63046
|
}
|
|
63029
63047
|
await libsodium_wrappers_default.ready;
|
|
63030
|
-
if (roomData.forceRekey) {
|
|
63031
|
-
let cleared = 0;
|
|
63032
|
-
const existingRoom = this._persisted.rooms?.[roomData.roomId];
|
|
63033
|
-
if (existingRoom) {
|
|
63034
|
-
for (const convId of existingRoom.conversationIds) {
|
|
63035
|
-
if (this._sessions.has(convId)) {
|
|
63036
|
-
this._sessions.delete(convId);
|
|
63037
|
-
cleared++;
|
|
63038
|
-
}
|
|
63039
|
-
delete this._persisted.sessions[convId];
|
|
63040
|
-
}
|
|
63041
|
-
}
|
|
63042
|
-
if (this._persisted) {
|
|
63043
|
-
this._persisted.lastMessageTimestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
63044
|
-
}
|
|
63045
|
-
console.log(
|
|
63046
|
-
`[SecureChannel] Force rekey: cleared ${cleared} sessions for room ${roomData.roomId.slice(0, 8)}...`
|
|
63047
|
-
);
|
|
63048
|
-
}
|
|
63049
|
-
const identity = this._persisted.identityKeypair;
|
|
63050
|
-
const ephemeral = this._persisted.ephemeralKeypair;
|
|
63051
63048
|
const myDeviceId = this._deviceId;
|
|
63052
63049
|
const conversationIds = [];
|
|
63053
63050
|
for (const conv of roomData.conversations) {
|
|
63054
63051
|
if (conv.participantA !== myDeviceId && conv.participantB !== myDeviceId) {
|
|
63055
63052
|
continue;
|
|
63056
63053
|
}
|
|
63057
|
-
if (this._sessions.has(conv.id)) {
|
|
63058
|
-
conversationIds.push(conv.id);
|
|
63059
|
-
continue;
|
|
63060
|
-
}
|
|
63061
|
-
const otherDeviceId = conv.participantA === myDeviceId ? conv.participantB : conv.participantA;
|
|
63062
|
-
const otherMember = roomData.members.find((m2) => m2.deviceId === otherDeviceId);
|
|
63063
|
-
if (!otherMember?.identityPublicKey) {
|
|
63064
|
-
console.warn(
|
|
63065
|
-
`[SecureChannel] No public key for member ${otherDeviceId.slice(0, 8)}..., skipping`
|
|
63066
|
-
);
|
|
63067
|
-
continue;
|
|
63068
|
-
}
|
|
63069
|
-
const isInitiator = myDeviceId < otherDeviceId;
|
|
63070
|
-
const theirEphKey = otherMember.ephemeralPublicKey ?? otherMember.identityPublicKey;
|
|
63071
|
-
const sharedSecret = performX3DH({
|
|
63072
|
-
myIdentityPrivate: hexToBytes(identity.privateKey),
|
|
63073
|
-
myEphemeralPrivate: hexToBytes(ephemeral.privateKey),
|
|
63074
|
-
theirIdentityPublic: hexToBytes(otherMember.identityPublicKey),
|
|
63075
|
-
theirEphemeralPublic: hexToBytes(theirEphKey),
|
|
63076
|
-
isInitiator
|
|
63077
|
-
});
|
|
63078
|
-
const peerIdentityPub = hexToBytes(otherMember.identityPublicKey);
|
|
63079
|
-
const ratchet = isInitiator ? DoubleRatchet.initSender(sharedSecret, {
|
|
63080
|
-
publicKey: hexToBytes(identity.publicKey),
|
|
63081
|
-
privateKey: hexToBytes(identity.privateKey),
|
|
63082
|
-
keyType: "ed25519"
|
|
63083
|
-
}, peerIdentityPub) : DoubleRatchet.initReceiver(sharedSecret, {
|
|
63084
|
-
publicKey: hexToBytes(identity.publicKey),
|
|
63085
|
-
privateKey: hexToBytes(identity.privateKey),
|
|
63086
|
-
keyType: "ed25519"
|
|
63087
|
-
}, peerIdentityPub);
|
|
63088
|
-
this._sessions.set(conv.id, {
|
|
63089
|
-
ownerDeviceId: otherDeviceId,
|
|
63090
|
-
ratchet,
|
|
63091
|
-
activated: isInitiator,
|
|
63092
|
-
// initiator can send immediately
|
|
63093
|
-
epoch: 1
|
|
63094
|
-
});
|
|
63095
|
-
this._persisted.sessions[conv.id] = {
|
|
63096
|
-
ownerDeviceId: otherDeviceId,
|
|
63097
|
-
ratchetState: ratchet.serialize(),
|
|
63098
|
-
activated: isInitiator,
|
|
63099
|
-
epoch: 1
|
|
63100
|
-
};
|
|
63101
63054
|
conversationIds.push(conv.id);
|
|
63102
|
-
console.log(
|
|
63103
|
-
`[SecureChannel] Room session initialized: conv ${conv.id.slice(0, 8)}... with ${otherDeviceId.slice(0, 8)}... (initiator=${isInitiator})`
|
|
63104
|
-
);
|
|
63105
63055
|
}
|
|
63106
63056
|
if (!this._persisted.rooms) {
|
|
63107
63057
|
this._persisted.rooms = {};
|
|
63108
63058
|
}
|
|
63059
|
+
const existingMlsGroupId = this._persisted.rooms[roomData.roomId]?.mlsGroupId;
|
|
63060
|
+
const existingMlsTs = this._persisted.rooms[roomData.roomId]?.lastMlsMessageTs;
|
|
63109
63061
|
this._persisted.rooms[roomData.roomId] = {
|
|
63110
63062
|
roomId: roomData.roomId,
|
|
63111
63063
|
name: roomData.name,
|
|
63112
63064
|
conversationIds,
|
|
63113
|
-
members: roomData.members
|
|
63065
|
+
members: roomData.members,
|
|
63066
|
+
...existingMlsGroupId && { mlsGroupId: existingMlsGroupId },
|
|
63067
|
+
...existingMlsTs && { lastMlsMessageTs: existingMlsTs }
|
|
63114
63068
|
};
|
|
63115
63069
|
const mlsRoom = this._persisted.rooms[roomData.roomId];
|
|
63116
63070
|
if (mlsRoom.mlsGroupId && !roomData.forceRekey) {
|
|
@@ -63193,68 +63147,15 @@ var init_channel = __esm({
|
|
|
63193
63147
|
}
|
|
63194
63148
|
return;
|
|
63195
63149
|
} catch (mlsErr) {
|
|
63196
|
-
|
|
63197
|
-
|
|
63198
|
-
|
|
63199
|
-
}
|
|
63200
|
-
const recipients = [];
|
|
63201
|
-
for (const convId of room.conversationIds) {
|
|
63202
|
-
const session = this._sessions.get(convId);
|
|
63203
|
-
if (!session) {
|
|
63204
|
-
console.warn(`[SecureChannel] No session for room conv ${convId.slice(0, 8)}..., skipping`);
|
|
63205
|
-
continue;
|
|
63206
|
-
}
|
|
63207
|
-
const encrypted = session.ratchet.encrypt(plaintext);
|
|
63208
|
-
const transport = encryptedMessageToTransport(encrypted);
|
|
63209
|
-
recipients.push({
|
|
63210
|
-
device_id: session.ownerDeviceId,
|
|
63211
|
-
header_blob: transport.header_blob,
|
|
63212
|
-
ciphertext: transport.ciphertext
|
|
63213
|
-
});
|
|
63214
|
-
}
|
|
63215
|
-
if (recipients.length === 0) {
|
|
63216
|
-
throw new Error("No active sessions in room");
|
|
63217
|
-
}
|
|
63218
|
-
await this._persistState();
|
|
63219
|
-
if (this._state === "ready" && this._ws) {
|
|
63220
|
-
this._ws.send(
|
|
63221
|
-
JSON.stringify({
|
|
63222
|
-
event: "room_message",
|
|
63223
|
-
data: {
|
|
63224
|
-
room_id: roomId,
|
|
63225
|
-
recipients,
|
|
63226
|
-
message_type: messageType,
|
|
63227
|
-
priority: opts?.priority ?? "normal",
|
|
63228
|
-
metadata: opts?.metadata
|
|
63229
|
-
}
|
|
63230
|
-
})
|
|
63231
|
-
);
|
|
63232
|
-
} else {
|
|
63233
|
-
try {
|
|
63234
|
-
const res = await fetch(
|
|
63235
|
-
`${this.config.apiUrl}/api/v1/rooms/${roomId}/messages`,
|
|
63236
|
-
{
|
|
63237
|
-
method: "POST",
|
|
63238
|
-
headers: {
|
|
63239
|
-
"Content-Type": "application/json",
|
|
63240
|
-
Authorization: `Bearer ${this._deviceJwt}`
|
|
63241
|
-
},
|
|
63242
|
-
body: JSON.stringify({
|
|
63243
|
-
recipients,
|
|
63244
|
-
message_type: messageType,
|
|
63245
|
-
priority: opts?.priority ?? "normal",
|
|
63246
|
-
metadata: opts?.metadata
|
|
63247
|
-
})
|
|
63248
|
-
}
|
|
63249
|
-
);
|
|
63250
|
-
if (!res.ok) {
|
|
63251
|
-
const detail = await res.text();
|
|
63252
|
-
throw new Error(`Room message failed (${res.status}): ${detail}`);
|
|
63150
|
+
throw new Error(
|
|
63151
|
+
`MLS encrypt failed for room ${roomId.slice(0, 8)}... \u2014 MLS group must be initialized before sending. Error: ${mlsErr}`
|
|
63152
|
+
);
|
|
63253
63153
|
}
|
|
63254
|
-
} catch (err) {
|
|
63255
|
-
throw new Error(`Failed to send room message: ${err}`);
|
|
63256
63154
|
}
|
|
63257
63155
|
}
|
|
63156
|
+
throw new Error(
|
|
63157
|
+
`Room ${roomId.slice(0, 8)}... has no initialized MLS group. MLS initialization must complete before messages can be sent.`
|
|
63158
|
+
);
|
|
63258
63159
|
}
|
|
63259
63160
|
/**
|
|
63260
63161
|
* Leave a room: remove sessions and persisted room state.
|
|
@@ -65414,250 +65315,8 @@ ${messageText}`;
|
|
|
65414
65315
|
this.emit("error", err);
|
|
65415
65316
|
}
|
|
65416
65317
|
}
|
|
65417
|
-
|
|
65418
|
-
|
|
65419
|
-
* Shared by all room ratchet failure paths to avoid code duplication.
|
|
65420
|
-
*/
|
|
65421
|
-
_sendRoomResyncIfCooled(convId, reason, session) {
|
|
65422
|
-
const RESYNC_COOLDOWN_MS = 5 * 60 * 1e3;
|
|
65423
|
-
const lastResync = this._lastResyncRequest.get(convId) ?? 0;
|
|
65424
|
-
if (Date.now() - lastResync > RESYNC_COOLDOWN_MS && this._ws && this._persisted) {
|
|
65425
|
-
this._lastResyncRequest.set(convId, Date.now());
|
|
65426
|
-
this._ws.send(
|
|
65427
|
-
JSON.stringify({
|
|
65428
|
-
event: "resync_request",
|
|
65429
|
-
data: {
|
|
65430
|
-
conversation_id: convId,
|
|
65431
|
-
reason,
|
|
65432
|
-
identity_public_key: this._persisted.identityKeypair.publicKey,
|
|
65433
|
-
ephemeral_public_key: this._persisted.ephemeralKeypair.publicKey,
|
|
65434
|
-
epoch: session?.epoch
|
|
65435
|
-
}
|
|
65436
|
-
})
|
|
65437
|
-
);
|
|
65438
|
-
console.log(
|
|
65439
|
-
`[SecureChannel] Room resync requested for conv ${convId.slice(0, 8)} (${reason})`
|
|
65440
|
-
);
|
|
65441
|
-
}
|
|
65442
|
-
}
|
|
65443
|
-
/**
|
|
65444
|
-
* Handle an incoming room message (pairwise path — used by sync replay and pairwise room fallback).
|
|
65445
|
-
* Finds the pairwise conversation for the sender, decrypts, and emits a room_message event.
|
|
65446
|
-
*/
|
|
65447
|
-
async _handleRoomMessage(msgData) {
|
|
65448
|
-
if (msgData.sender_device_id === this._deviceId) return;
|
|
65449
|
-
this._lastInboundRoomId = msgData.room_id;
|
|
65450
|
-
const convId = msgData.conversation_id ?? this._findConversationForSender(msgData.sender_device_id, msgData.room_id);
|
|
65451
|
-
if (!convId) {
|
|
65452
|
-
console.warn(
|
|
65453
|
-
`[SecureChannel] No conversation found for sender ${msgData.sender_device_id.slice(0, 8)}... in room ${msgData.room_id}`
|
|
65454
|
-
);
|
|
65455
|
-
return;
|
|
65456
|
-
}
|
|
65457
|
-
let session = this._sessions.get(convId);
|
|
65458
|
-
if (!session) {
|
|
65459
|
-
console.warn(
|
|
65460
|
-
`[SecureChannel] No session for room conv ${convId.slice(0, 8)}..., fetching room data`
|
|
65461
|
-
);
|
|
65462
|
-
try {
|
|
65463
|
-
const roomRes = await fetch(
|
|
65464
|
-
`${this.config.apiUrl}/api/v1/rooms/${msgData.room_id}`,
|
|
65465
|
-
{
|
|
65466
|
-
headers: {
|
|
65467
|
-
Authorization: `Bearer ${this._persisted.deviceJwt}`
|
|
65468
|
-
}
|
|
65469
|
-
}
|
|
65470
|
-
);
|
|
65471
|
-
if (roomRes.ok) {
|
|
65472
|
-
const roomData = await roomRes.json();
|
|
65473
|
-
await this.joinRoom({
|
|
65474
|
-
roomId: roomData.id,
|
|
65475
|
-
name: roomData.name,
|
|
65476
|
-
members: (roomData.members || []).map((m2) => ({
|
|
65477
|
-
deviceId: m2.device_id,
|
|
65478
|
-
entityType: m2.entity_type,
|
|
65479
|
-
displayName: m2.display_name,
|
|
65480
|
-
identityPublicKey: m2.identity_public_key,
|
|
65481
|
-
ephemeralPublicKey: m2.ephemeral_public_key
|
|
65482
|
-
})),
|
|
65483
|
-
conversations: (roomData.conversations || []).map((c2) => ({
|
|
65484
|
-
id: c2.id,
|
|
65485
|
-
participantA: c2.participant_a,
|
|
65486
|
-
participantB: c2.participant_b
|
|
65487
|
-
}))
|
|
65488
|
-
});
|
|
65489
|
-
session = this._sessions.get(convId);
|
|
65490
|
-
}
|
|
65491
|
-
} catch (fetchErr) {
|
|
65492
|
-
console.error(
|
|
65493
|
-
`[SecureChannel] Failed to fetch room data for ${msgData.room_id}:`,
|
|
65494
|
-
fetchErr
|
|
65495
|
-
);
|
|
65496
|
-
}
|
|
65497
|
-
if (!session) {
|
|
65498
|
-
console.warn(
|
|
65499
|
-
`[SecureChannel] Still no session for room conv ${convId.slice(0, 8)}... after refresh, skipping`
|
|
65500
|
-
);
|
|
65501
|
-
return;
|
|
65502
|
-
}
|
|
65503
|
-
}
|
|
65504
|
-
const encrypted = transportToEncryptedMessage({
|
|
65505
|
-
header_blob: msgData.header_blob,
|
|
65506
|
-
ciphertext: msgData.ciphertext
|
|
65507
|
-
});
|
|
65508
|
-
let plaintext;
|
|
65509
|
-
const ratchetSnapshot = session.ratchet.serialize();
|
|
65510
|
-
try {
|
|
65511
|
-
plaintext = session.ratchet.decrypt(encrypted);
|
|
65512
|
-
} catch (decryptErr) {
|
|
65513
|
-
try {
|
|
65514
|
-
session.ratchet = DoubleRatchet.deserialize(ratchetSnapshot);
|
|
65515
|
-
} catch {
|
|
65516
|
-
}
|
|
65517
|
-
console.warn(
|
|
65518
|
-
`[SecureChannel] Room decrypt failed for conv ${convId.slice(0, 8)}...: ${String(decryptErr)}, re-initializing ratchet`
|
|
65519
|
-
);
|
|
65520
|
-
try {
|
|
65521
|
-
const roomEntry = this._persisted?.rooms ? Object.values(this._persisted.rooms).find(
|
|
65522
|
-
(r2) => r2.conversationIds.includes(convId)
|
|
65523
|
-
) : null;
|
|
65524
|
-
if (!roomEntry) throw new Error("Room not found for conversation");
|
|
65525
|
-
const otherMember = roomEntry.members.find(
|
|
65526
|
-
(m2) => m2.deviceId === msgData.sender_device_id
|
|
65527
|
-
);
|
|
65528
|
-
if (!otherMember?.identityPublicKey) throw new Error("No key for sender");
|
|
65529
|
-
const isInitiator = this._deviceId < msgData.sender_device_id;
|
|
65530
|
-
const identity = this._persisted.identityKeypair;
|
|
65531
|
-
const ephemeral = this._persisted.ephemeralKeypair;
|
|
65532
|
-
const sharedSecret = performX3DH({
|
|
65533
|
-
myIdentityPrivate: hexToBytes(identity.privateKey),
|
|
65534
|
-
myEphemeralPrivate: hexToBytes(ephemeral.privateKey),
|
|
65535
|
-
theirIdentityPublic: hexToBytes(otherMember.identityPublicKey),
|
|
65536
|
-
theirEphemeralPublic: hexToBytes(
|
|
65537
|
-
otherMember.ephemeralPublicKey ?? otherMember.identityPublicKey
|
|
65538
|
-
),
|
|
65539
|
-
isInitiator
|
|
65540
|
-
});
|
|
65541
|
-
const peerIdPub = hexToBytes(otherMember.identityPublicKey);
|
|
65542
|
-
const newRatchet = isInitiator ? DoubleRatchet.initSender(sharedSecret, {
|
|
65543
|
-
publicKey: hexToBytes(identity.publicKey),
|
|
65544
|
-
privateKey: hexToBytes(identity.privateKey),
|
|
65545
|
-
keyType: "ed25519"
|
|
65546
|
-
}, peerIdPub) : DoubleRatchet.initReceiver(sharedSecret, {
|
|
65547
|
-
publicKey: hexToBytes(identity.publicKey),
|
|
65548
|
-
privateKey: hexToBytes(identity.privateKey),
|
|
65549
|
-
keyType: "ed25519"
|
|
65550
|
-
}, peerIdPub);
|
|
65551
|
-
session.ratchet = newRatchet;
|
|
65552
|
-
session.activated = false;
|
|
65553
|
-
this._persisted.sessions[convId] = {
|
|
65554
|
-
ownerDeviceId: session.ownerDeviceId,
|
|
65555
|
-
ratchetState: newRatchet.serialize(),
|
|
65556
|
-
activated: false
|
|
65557
|
-
};
|
|
65558
|
-
await this._persistState();
|
|
65559
|
-
console.log(
|
|
65560
|
-
`[SecureChannel] Room ratchet re-initialized for conv ${convId.slice(0, 8)}...`
|
|
65561
|
-
);
|
|
65562
|
-
const incomingMsgNum = encrypted.header.messageNumber;
|
|
65563
|
-
if (incomingMsgNum <= 5) {
|
|
65564
|
-
try {
|
|
65565
|
-
plaintext = session.ratchet.decrypt(encrypted);
|
|
65566
|
-
session.activated = true;
|
|
65567
|
-
if (this._persisted.sessions[convId]) {
|
|
65568
|
-
this._persisted.sessions[convId].activated = true;
|
|
65569
|
-
}
|
|
65570
|
-
await this._persistState();
|
|
65571
|
-
console.log(
|
|
65572
|
-
`[SecureChannel] Room session ${convId.slice(0, 8)}... re-activated after ratchet re-init`
|
|
65573
|
-
);
|
|
65574
|
-
} catch (retryErr) {
|
|
65575
|
-
console.warn(
|
|
65576
|
-
`[SecureChannel] Room re-init retry failed for conv ${convId.slice(0, 8)} (msgNum=${incomingMsgNum}):`,
|
|
65577
|
-
retryErr
|
|
65578
|
-
);
|
|
65579
|
-
this._sendRoomResyncIfCooled(convId, "room_reinit_retry_failed", session);
|
|
65580
|
-
return;
|
|
65581
|
-
}
|
|
65582
|
-
} else {
|
|
65583
|
-
console.log(
|
|
65584
|
-
`[SecureChannel] Room re-init: skipping message with msgNum=${incomingMsgNum} for conv ${convId.slice(0, 8)} (too far ahead for fresh ratchet)`
|
|
65585
|
-
);
|
|
65586
|
-
this._sendRoomResyncIfCooled(convId, "room_message_skip");
|
|
65587
|
-
return;
|
|
65588
|
-
}
|
|
65589
|
-
} catch (reinitErr) {
|
|
65590
|
-
console.error(
|
|
65591
|
-
`[SecureChannel] Room ratchet re-init failed for conv ${convId.slice(0, 8)}...:`,
|
|
65592
|
-
reinitErr
|
|
65593
|
-
);
|
|
65594
|
-
this._sendRoomResyncIfCooled(convId, "room_reinit_failed");
|
|
65595
|
-
return;
|
|
65596
|
-
}
|
|
65597
|
-
}
|
|
65598
|
-
let messageText;
|
|
65599
|
-
let messageType;
|
|
65600
|
-
try {
|
|
65601
|
-
const parsed = JSON.parse(plaintext);
|
|
65602
|
-
messageType = parsed.type || "message";
|
|
65603
|
-
messageText = parsed.text || plaintext;
|
|
65604
|
-
} catch {
|
|
65605
|
-
messageType = "message";
|
|
65606
|
-
messageText = plaintext;
|
|
65607
|
-
}
|
|
65608
|
-
if (CREDENTIAL_MESSAGE_TYPES.has(messageType)) {
|
|
65609
|
-
this._handleCredentialMessage(msgData.room_id, messageType, messageText, msgData.message_id);
|
|
65610
|
-
if (msgData.created_at && this._persisted) {
|
|
65611
|
-
this._persisted.lastMessageTimestamp = msgData.created_at;
|
|
65612
|
-
}
|
|
65613
|
-
await this._persistState();
|
|
65614
|
-
return;
|
|
65615
|
-
}
|
|
65616
|
-
if (!ROOM_AGENT_TYPES.has(messageType)) {
|
|
65617
|
-
return;
|
|
65618
|
-
}
|
|
65619
|
-
if (!session.activated) {
|
|
65620
|
-
session.activated = true;
|
|
65621
|
-
console.log(
|
|
65622
|
-
`[SecureChannel] Room session ${convId.slice(0, 8)}... activated by first message`
|
|
65623
|
-
);
|
|
65624
|
-
}
|
|
65625
|
-
if (msgData.message_id) {
|
|
65626
|
-
this._sendAck(msgData.message_id);
|
|
65627
|
-
}
|
|
65628
|
-
if (msgData.created_at && this._persisted) {
|
|
65629
|
-
this._persisted.lastMessageTimestamp = msgData.created_at;
|
|
65630
|
-
}
|
|
65631
|
-
await this._persistState();
|
|
65632
|
-
const legacyRoomMembers = this._persisted?.rooms?.[msgData.room_id]?.members ?? [];
|
|
65633
|
-
const legacySenderMember = legacyRoomMembers.find((m2) => m2.deviceId === msgData.sender_device_id);
|
|
65634
|
-
const legacySenderIsAgent = legacySenderMember?.entityType === "agent";
|
|
65635
|
-
const legacySenderLabel = legacySenderMember?.displayName || "someone";
|
|
65636
|
-
const metadata = {
|
|
65637
|
-
messageId: msgData.message_id ?? "",
|
|
65638
|
-
conversationId: convId,
|
|
65639
|
-
timestamp: msgData.created_at ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
65640
|
-
messageType,
|
|
65641
|
-
roomId: msgData.room_id,
|
|
65642
|
-
senderDeviceId: msgData.sender_device_id,
|
|
65643
|
-
senderIsAgent: legacySenderIsAgent,
|
|
65644
|
-
senderName: legacySenderLabel,
|
|
65645
|
-
roomName: this._persisted?.rooms?.[msgData.room_id]?.name
|
|
65646
|
-
};
|
|
65647
|
-
this._appendHistory("owner", messageText, `room:${msgData.room_id}`);
|
|
65648
|
-
this.emit("room_message", {
|
|
65649
|
-
roomId: msgData.room_id,
|
|
65650
|
-
senderDeviceId: msgData.sender_device_id,
|
|
65651
|
-
senderName: legacySenderLabel,
|
|
65652
|
-
plaintext: messageText,
|
|
65653
|
-
messageType,
|
|
65654
|
-
timestamp: msgData.created_at ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
65655
|
-
});
|
|
65656
|
-
const legacyContextualMessage = legacySenderIsAgent ? messageText : `[${legacySenderLabel}]: ${messageText}`;
|
|
65657
|
-
Promise.resolve(this.config.onMessage?.(legacyContextualMessage, metadata)).catch((err) => {
|
|
65658
|
-
console.error("[SecureChannel] onMessage callback error:", err);
|
|
65659
|
-
});
|
|
65660
|
-
}
|
|
65318
|
+
// _sendRoomResyncIfCooled removed — rooms are MLS-only now
|
|
65319
|
+
// _handleRoomMessage removed — rooms are MLS-only now
|
|
65661
65320
|
/**
|
|
65662
65321
|
* Handle credential protocol messages (grant, revoke, request).
|
|
65663
65322
|
* These are intercepted before reaching the agent's onMessage callback.
|
|
@@ -65746,20 +65405,7 @@ ${messageText}`;
|
|
|
65746
65405
|
purgeRoomCredentials(roomId) {
|
|
65747
65406
|
this._credentialStore.purgeForRoom(roomId);
|
|
65748
65407
|
}
|
|
65749
|
-
|
|
65750
|
-
* Find the pairwise conversation ID for a given sender in a room.
|
|
65751
|
-
*/
|
|
65752
|
-
_findConversationForSender(senderDeviceId, roomId) {
|
|
65753
|
-
const room = this._persisted?.rooms?.[roomId];
|
|
65754
|
-
if (!room) return null;
|
|
65755
|
-
for (const convId of room.conversationIds) {
|
|
65756
|
-
const session = this._sessions.get(convId);
|
|
65757
|
-
if (session && session.ownerDeviceId === senderDeviceId) {
|
|
65758
|
-
return convId;
|
|
65759
|
-
}
|
|
65760
|
-
}
|
|
65761
|
-
return null;
|
|
65762
|
-
}
|
|
65408
|
+
// _findConversationForSender removed — rooms are MLS-only now
|
|
65763
65409
|
// ---------------------------------------------------------------------------
|
|
65764
65410
|
// MLS room message handlers
|
|
65765
65411
|
// ---------------------------------------------------------------------------
|
|
@@ -65783,11 +65429,12 @@ ${messageText}`;
|
|
|
65783
65429
|
return;
|
|
65784
65430
|
}
|
|
65785
65431
|
}
|
|
65786
|
-
|
|
65787
|
-
|
|
65788
|
-
|
|
65432
|
+
const resolvedRoomId = roomId;
|
|
65433
|
+
this._lastInboundRoomId = resolvedRoomId;
|
|
65434
|
+
const mlsGroup = this._mlsGroups.get(resolvedRoomId);
|
|
65435
|
+
console.log(`[SecureChannel] MLS decrypt attempt room=${resolvedRoomId.slice(0, 8)} group=${groupId?.slice(0, 8)} loaded=${!!mlsGroup} init=${mlsGroup?.isInitialized} mlsGroupsKeys=[${Array.from(this._mlsGroups.keys()).join(",")}]`);
|
|
65789
65436
|
if (!mlsGroup?.isInitialized) {
|
|
65790
|
-
console.warn(`[SecureChannel] MLS group not loaded for room ${
|
|
65437
|
+
console.warn(`[SecureChannel] MLS group not loaded for room ${resolvedRoomId.slice(0, 8)}`);
|
|
65791
65438
|
return;
|
|
65792
65439
|
}
|
|
65793
65440
|
try {
|
|
@@ -65809,7 +65456,7 @@ ${messageText}`;
|
|
|
65809
65456
|
messageText = rawPlaintext;
|
|
65810
65457
|
}
|
|
65811
65458
|
if (CREDENTIAL_MESSAGE_TYPES.has(messageType)) {
|
|
65812
|
-
this._handleCredentialMessage(
|
|
65459
|
+
this._handleCredentialMessage(resolvedRoomId, messageType, messageText, data.message_id);
|
|
65813
65460
|
if (data.created_at && this._persisted) {
|
|
65814
65461
|
this._persisted.lastMessageTimestamp = data.created_at;
|
|
65815
65462
|
}
|
|
@@ -65824,13 +65471,13 @@ ${messageText}`;
|
|
|
65824
65471
|
}
|
|
65825
65472
|
if (data.created_at && this._persisted) {
|
|
65826
65473
|
this._persisted.lastMessageTimestamp = data.created_at;
|
|
65827
|
-
const roomState = this._persisted.rooms?.[
|
|
65474
|
+
const roomState = this._persisted.rooms?.[resolvedRoomId];
|
|
65828
65475
|
if (roomState) {
|
|
65829
65476
|
roomState.lastMlsMessageTs = data.created_at;
|
|
65830
65477
|
}
|
|
65831
65478
|
}
|
|
65832
65479
|
await this._persistState();
|
|
65833
|
-
const roomMembers = this._persisted?.rooms?.[
|
|
65480
|
+
const roomMembers = this._persisted?.rooms?.[resolvedRoomId]?.members ?? [];
|
|
65834
65481
|
const senderMember = roomMembers.find((m2) => m2.deviceId === senderDeviceId);
|
|
65835
65482
|
const senderIsAgent = senderMember?.entityType === "agent";
|
|
65836
65483
|
const metadata = {
|
|
@@ -65838,16 +65485,16 @@ ${messageText}`;
|
|
|
65838
65485
|
conversationId: "",
|
|
65839
65486
|
timestamp: data.created_at ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
65840
65487
|
messageType,
|
|
65841
|
-
roomId,
|
|
65488
|
+
roomId: resolvedRoomId,
|
|
65842
65489
|
senderDeviceId,
|
|
65843
65490
|
senderIsAgent,
|
|
65844
65491
|
senderName: senderMember?.displayName || "unknown",
|
|
65845
|
-
roomName: this._persisted?.rooms?.[
|
|
65492
|
+
roomName: this._persisted?.rooms?.[resolvedRoomId]?.name
|
|
65846
65493
|
};
|
|
65847
65494
|
const senderLabel = senderMember?.displayName || "someone";
|
|
65848
|
-
this._appendHistory("owner", messageText, `room:${
|
|
65495
|
+
this._appendHistory("owner", messageText, `room:${resolvedRoomId}`);
|
|
65849
65496
|
this.emit("room_message", {
|
|
65850
|
-
roomId,
|
|
65497
|
+
roomId: resolvedRoomId,
|
|
65851
65498
|
senderDeviceId,
|
|
65852
65499
|
senderName: senderLabel,
|
|
65853
65500
|
plaintext: messageText,
|
|
@@ -65859,7 +65506,7 @@ ${messageText}`;
|
|
|
65859
65506
|
console.error("[SecureChannel] onMessage callback error (MLS):", err);
|
|
65860
65507
|
});
|
|
65861
65508
|
} catch (err) {
|
|
65862
|
-
console.error(`[SecureChannel] MLS room decrypt failed for ${
|
|
65509
|
+
console.error(`[SecureChannel] MLS room decrypt failed for ${resolvedRoomId.slice(0, 8)}:`, err);
|
|
65863
65510
|
}
|
|
65864
65511
|
}
|
|
65865
65512
|
async _handleMlsCommit(data) {
|
|
@@ -66186,22 +65833,6 @@ ${messageText}`;
|
|
|
66186
65833
|
}
|
|
66187
65834
|
}
|
|
66188
65835
|
if (roomId) {
|
|
66189
|
-
try {
|
|
66190
|
-
await this._handleRoomMessage({
|
|
66191
|
-
room_id: roomId,
|
|
66192
|
-
sender_device_id: msg.sender_device_id,
|
|
66193
|
-
conversation_id: msg.conversation_id,
|
|
66194
|
-
header_blob: msg.header_blob,
|
|
66195
|
-
ciphertext: msg.ciphertext,
|
|
66196
|
-
message_id: msg.id,
|
|
66197
|
-
created_at: msg.created_at
|
|
66198
|
-
});
|
|
66199
|
-
} catch (roomErr) {
|
|
66200
|
-
console.warn(
|
|
66201
|
-
`[SecureChannel] Sync room message failed for ${msg.conversation_id.slice(0, 8)}...:`,
|
|
66202
|
-
roomErr
|
|
66203
|
-
);
|
|
66204
|
-
}
|
|
66205
65836
|
this._persisted.lastMessageTimestamp = msg.created_at;
|
|
66206
65837
|
since = msg.created_at;
|
|
66207
65838
|
continue;
|