@agentvault/agentvault 0.9.0 → 0.9.2
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/channel.d.ts.map +1 -1
- package/dist/cli.js +200 -16
- package/dist/cli.js.map +3 -3
- package/dist/index.js +200 -16
- package/dist/index.js.map +3 -3
- package/dist/openclaw-entry.d.ts.map +1 -1
- package/dist/openclaw-entry.js +16 -8
- package/dist/openclaw-entry.js.map +2 -2
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -45421,9 +45421,18 @@ var SecureChannel = class _SecureChannel extends EventEmitter {
|
|
|
45421
45421
|
scanStatus = scanResult.status;
|
|
45422
45422
|
}
|
|
45423
45423
|
this._appendHistory("agent", plaintext, topicId);
|
|
45424
|
+
const roomConvIds = /* @__PURE__ */ new Set();
|
|
45425
|
+
if (this._persisted?.rooms) {
|
|
45426
|
+
for (const room of Object.values(this._persisted.rooms)) {
|
|
45427
|
+
for (const cid of room.conversationIds) {
|
|
45428
|
+
roomConvIds.add(cid);
|
|
45429
|
+
}
|
|
45430
|
+
}
|
|
45431
|
+
}
|
|
45424
45432
|
const messageGroupId = randomUUID();
|
|
45425
45433
|
for (const [convId, session] of this._sessions) {
|
|
45426
45434
|
if (!session.activated) continue;
|
|
45435
|
+
if (roomConvIds.has(convId)) continue;
|
|
45427
45436
|
const encrypted = session.ratchet.encrypt(plaintext);
|
|
45428
45437
|
const transport = encryptedMessageToTransport(encrypted);
|
|
45429
45438
|
const msg = {
|
|
@@ -45569,6 +45578,10 @@ var SecureChannel = class _SecureChannel extends EventEmitter {
|
|
|
45569
45578
|
if (conv.participantA !== myDeviceId && conv.participantB !== myDeviceId) {
|
|
45570
45579
|
continue;
|
|
45571
45580
|
}
|
|
45581
|
+
if (this._sessions.has(conv.id)) {
|
|
45582
|
+
conversationIds.push(conv.id);
|
|
45583
|
+
continue;
|
|
45584
|
+
}
|
|
45572
45585
|
const otherDeviceId = conv.participantA === myDeviceId ? conv.participantB : conv.participantA;
|
|
45573
45586
|
const otherMember = roomData.members.find((m2) => m2.deviceId === otherDeviceId);
|
|
45574
45587
|
if (!otherMember?.identityPublicKey) {
|
|
@@ -45578,13 +45591,12 @@ var SecureChannel = class _SecureChannel extends EventEmitter {
|
|
|
45578
45591
|
continue;
|
|
45579
45592
|
}
|
|
45580
45593
|
const isInitiator = myDeviceId < otherDeviceId;
|
|
45594
|
+
const theirEphKey = otherMember.ephemeralPublicKey ?? otherMember.identityPublicKey;
|
|
45581
45595
|
const sharedSecret = performX3DH({
|
|
45582
45596
|
myIdentityPrivate: hexToBytes(identity.privateKey),
|
|
45583
45597
|
myEphemeralPrivate: hexToBytes(ephemeral.privateKey),
|
|
45584
45598
|
theirIdentityPublic: hexToBytes(otherMember.identityPublicKey),
|
|
45585
|
-
theirEphemeralPublic: hexToBytes(
|
|
45586
|
-
otherMember.ephemeralPublicKey ?? otherMember.identityPublicKey
|
|
45587
|
-
),
|
|
45599
|
+
theirEphemeralPublic: hexToBytes(theirEphKey),
|
|
45588
45600
|
isInitiator
|
|
45589
45601
|
});
|
|
45590
45602
|
const ratchet = isInitiator ? DoubleRatchet.initSender(sharedSecret, {
|
|
@@ -45656,9 +45668,11 @@ var SecureChannel = class _SecureChannel extends EventEmitter {
|
|
|
45656
45668
|
this._ws.send(
|
|
45657
45669
|
JSON.stringify({
|
|
45658
45670
|
event: "room_message",
|
|
45659
|
-
|
|
45660
|
-
|
|
45661
|
-
|
|
45671
|
+
data: {
|
|
45672
|
+
room_id: roomId,
|
|
45673
|
+
recipients,
|
|
45674
|
+
message_type: messageType
|
|
45675
|
+
}
|
|
45662
45676
|
})
|
|
45663
45677
|
);
|
|
45664
45678
|
} else {
|
|
@@ -46084,6 +46098,23 @@ var SecureChannel = class _SecureChannel extends EventEmitter {
|
|
|
46084
46098
|
if (this._persisted.hubAddress) {
|
|
46085
46099
|
payload2.hub_address = this._persisted.hubAddress;
|
|
46086
46100
|
}
|
|
46101
|
+
if (channelEntry.observerSession?.ratchetState) {
|
|
46102
|
+
try {
|
|
46103
|
+
const obsRatchet = DoubleRatchet.deserialize(channelEntry.observerSession.ratchetState);
|
|
46104
|
+
const obsEncrypted = obsRatchet.encrypt(text);
|
|
46105
|
+
const obsHeaderObj = {
|
|
46106
|
+
dhPublicKey: bytesToHex(obsEncrypted.header.dhPublicKey),
|
|
46107
|
+
previousChainLength: obsEncrypted.header.previousChainLength,
|
|
46108
|
+
messageNumber: obsEncrypted.header.messageNumber
|
|
46109
|
+
};
|
|
46110
|
+
payload2.observer_header_blob = Buffer.from(JSON.stringify(obsHeaderObj)).toString("hex");
|
|
46111
|
+
payload2.observer_ciphertext = bytesToHex(obsEncrypted.ciphertext);
|
|
46112
|
+
payload2.observer_nonce = bytesToHex(obsEncrypted.nonce);
|
|
46113
|
+
channelEntry.observerSession.ratchetState = obsRatchet.serialize();
|
|
46114
|
+
} catch (obsErr) {
|
|
46115
|
+
console.error("[SecureChannel] Observer encryption failed (sending without observer copy):", obsErr);
|
|
46116
|
+
}
|
|
46117
|
+
}
|
|
46087
46118
|
channelEntry.session.ratchetState = ratchet.serialize();
|
|
46088
46119
|
await this._persistState();
|
|
46089
46120
|
this._ws.send(
|
|
@@ -46380,13 +46411,20 @@ var SecureChannel = class _SecureChannel extends EventEmitter {
|
|
|
46380
46411
|
return;
|
|
46381
46412
|
}
|
|
46382
46413
|
if (data.event === "message") {
|
|
46383
|
-
|
|
46414
|
+
try {
|
|
46415
|
+
await this._handleIncomingMessage(data.data);
|
|
46416
|
+
} catch (msgErr) {
|
|
46417
|
+
console.error(
|
|
46418
|
+
`[SecureChannel] Message handler failed for conv ${data.data?.conversation_id?.slice(0, 8) ?? "?"}...:`,
|
|
46419
|
+
msgErr
|
|
46420
|
+
);
|
|
46421
|
+
}
|
|
46384
46422
|
}
|
|
46385
46423
|
if (data.event === "room_joined") {
|
|
46386
46424
|
const d2 = data.data;
|
|
46387
46425
|
this.joinRoom({
|
|
46388
46426
|
roomId: d2.room_id,
|
|
46389
|
-
name: d2.name,
|
|
46427
|
+
name: d2.room_name ?? d2.name ?? "Room",
|
|
46390
46428
|
members: (d2.members || []).map((m2) => ({
|
|
46391
46429
|
deviceId: m2.device_id,
|
|
46392
46430
|
entityType: m2.entity_type,
|
|
@@ -46402,7 +46440,14 @@ var SecureChannel = class _SecureChannel extends EventEmitter {
|
|
|
46402
46440
|
}).catch((err) => this.emit("error", err));
|
|
46403
46441
|
}
|
|
46404
46442
|
if (data.event === "room_message") {
|
|
46405
|
-
|
|
46443
|
+
try {
|
|
46444
|
+
await this._handleRoomMessage(data.data);
|
|
46445
|
+
} catch (rmErr) {
|
|
46446
|
+
console.error(
|
|
46447
|
+
`[SecureChannel] Room message handler failed:`,
|
|
46448
|
+
rmErr
|
|
46449
|
+
);
|
|
46450
|
+
}
|
|
46406
46451
|
}
|
|
46407
46452
|
if (data.event === "room_participant_added") {
|
|
46408
46453
|
const p2 = data.data;
|
|
@@ -46539,6 +46584,74 @@ var SecureChannel = class _SecureChannel extends EventEmitter {
|
|
|
46539
46584
|
}
|
|
46540
46585
|
this.emit("a2a_channel_activated", actData);
|
|
46541
46586
|
}
|
|
46587
|
+
if (data.event === "a2a_observer_enabled") {
|
|
46588
|
+
const obsData = data.data || data;
|
|
46589
|
+
const obsChannelId = obsData.channel_id;
|
|
46590
|
+
const obsChannelEntry = this._persisted?.a2aChannels?.[obsChannelId];
|
|
46591
|
+
if (obsChannelEntry && this._persisted && this._ws) {
|
|
46592
|
+
try {
|
|
46593
|
+
const obsEphemeral = await generateEphemeralKeypair();
|
|
46594
|
+
const obsEphPubHex = bytesToHex(obsEphemeral.publicKey);
|
|
46595
|
+
const obsEphPrivHex = bytesToHex(obsEphemeral.privateKey);
|
|
46596
|
+
obsChannelEntry.pendingObserverEphemeralPrivateKey = obsEphPrivHex;
|
|
46597
|
+
await this._persistState();
|
|
46598
|
+
this._ws.send(
|
|
46599
|
+
JSON.stringify({
|
|
46600
|
+
event: "a2a_observer_key_submit",
|
|
46601
|
+
data: {
|
|
46602
|
+
channel_id: obsChannelId,
|
|
46603
|
+
ephemeral_key: obsEphPubHex,
|
|
46604
|
+
side: obsChannelEntry.role || "initiator"
|
|
46605
|
+
}
|
|
46606
|
+
})
|
|
46607
|
+
);
|
|
46608
|
+
console.log(
|
|
46609
|
+
`[SecureChannel] Observer key submitted for channel ${obsChannelId.slice(0, 8)}... (side=${obsChannelEntry.role})`
|
|
46610
|
+
);
|
|
46611
|
+
} catch (err) {
|
|
46612
|
+
console.error("[SecureChannel] Observer key submission failed:", err);
|
|
46613
|
+
}
|
|
46614
|
+
}
|
|
46615
|
+
}
|
|
46616
|
+
if (data.event === "a2a_observer_key_accepted") {
|
|
46617
|
+
const obsAccData = data.data || data;
|
|
46618
|
+
const obsAccChannelId = obsAccData.channel_id;
|
|
46619
|
+
const observerIdentityHex = obsAccData.observer_identity_key;
|
|
46620
|
+
const obsAccSide = obsAccData.side;
|
|
46621
|
+
const obsAccEntry = this._persisted?.a2aChannels?.[obsAccChannelId];
|
|
46622
|
+
if (obsAccEntry && obsAccEntry.pendingObserverEphemeralPrivateKey && this._persisted) {
|
|
46623
|
+
try {
|
|
46624
|
+
const myIdentityPrivate = hexToBytes(this._persisted.identityKeypair.privateKey);
|
|
46625
|
+
const myIdentityPublic = hexToBytes(this._persisted.identityKeypair.publicKey);
|
|
46626
|
+
const myObsEphemeralPrivate = hexToBytes(obsAccEntry.pendingObserverEphemeralPrivateKey);
|
|
46627
|
+
const ownerIdentityPublic = hexToBytes(observerIdentityHex);
|
|
46628
|
+
const obsSharedSecret = performX3DH({
|
|
46629
|
+
myIdentityPrivate,
|
|
46630
|
+
myEphemeralPrivate: myObsEphemeralPrivate,
|
|
46631
|
+
theirIdentityPublic: ownerIdentityPublic,
|
|
46632
|
+
theirEphemeralPublic: ownerIdentityPublic,
|
|
46633
|
+
// owner uses identity as ephemeral
|
|
46634
|
+
isInitiator: true
|
|
46635
|
+
});
|
|
46636
|
+
const identityKp = {
|
|
46637
|
+
publicKey: myIdentityPublic,
|
|
46638
|
+
privateKey: myIdentityPrivate,
|
|
46639
|
+
keyType: "ed25519"
|
|
46640
|
+
};
|
|
46641
|
+
const obsRatchet = DoubleRatchet.initSender(obsSharedSecret, identityKp);
|
|
46642
|
+
obsAccEntry.observerSession = {
|
|
46643
|
+
ratchetState: obsRatchet.serialize()
|
|
46644
|
+
};
|
|
46645
|
+
delete obsAccEntry.pendingObserverEphemeralPrivateKey;
|
|
46646
|
+
await this._persistState();
|
|
46647
|
+
console.log(
|
|
46648
|
+
`[SecureChannel] Observer ratchet initialized for channel ${obsAccChannelId.slice(0, 8)}... (side=${obsAccSide})`
|
|
46649
|
+
);
|
|
46650
|
+
} catch (err) {
|
|
46651
|
+
console.error("[SecureChannel] Observer ratchet init failed:", err);
|
|
46652
|
+
}
|
|
46653
|
+
}
|
|
46654
|
+
}
|
|
46542
46655
|
if (data.event === "a2a_channel_rejected") {
|
|
46543
46656
|
this.emit("a2a_channel_rejected", data.data || data);
|
|
46544
46657
|
}
|
|
@@ -47009,7 +47122,73 @@ ${messageText}`;
|
|
|
47009
47122
|
header_blob: msgData.header_blob,
|
|
47010
47123
|
ciphertext: msgData.ciphertext
|
|
47011
47124
|
});
|
|
47012
|
-
|
|
47125
|
+
let plaintext;
|
|
47126
|
+
try {
|
|
47127
|
+
plaintext = session.ratchet.decrypt(encrypted);
|
|
47128
|
+
} catch (decryptErr) {
|
|
47129
|
+
console.warn(
|
|
47130
|
+
`[SecureChannel] Room decrypt failed for conv ${convId.slice(0, 8)}...: ${String(decryptErr)}, re-initializing ratchet`
|
|
47131
|
+
);
|
|
47132
|
+
try {
|
|
47133
|
+
const roomEntry = this._persisted?.rooms ? Object.values(this._persisted.rooms).find(
|
|
47134
|
+
(r2) => r2.conversationIds.includes(convId)
|
|
47135
|
+
) : null;
|
|
47136
|
+
if (!roomEntry) throw new Error("Room not found for conversation");
|
|
47137
|
+
const otherMember = roomEntry.members.find(
|
|
47138
|
+
(m2) => m2.deviceId === msgData.sender_device_id
|
|
47139
|
+
);
|
|
47140
|
+
if (!otherMember?.identityPublicKey) throw new Error("No key for sender");
|
|
47141
|
+
const isInitiator = this._deviceId < msgData.sender_device_id;
|
|
47142
|
+
const identity = this._persisted.identityKeypair;
|
|
47143
|
+
const ephemeral = this._persisted.ephemeralKeypair;
|
|
47144
|
+
const sharedSecret = performX3DH({
|
|
47145
|
+
myIdentityPrivate: hexToBytes(identity.privateKey),
|
|
47146
|
+
myEphemeralPrivate: hexToBytes(ephemeral.privateKey),
|
|
47147
|
+
theirIdentityPublic: hexToBytes(otherMember.identityPublicKey),
|
|
47148
|
+
theirEphemeralPublic: hexToBytes(
|
|
47149
|
+
otherMember.ephemeralPublicKey ?? otherMember.identityPublicKey
|
|
47150
|
+
),
|
|
47151
|
+
isInitiator
|
|
47152
|
+
});
|
|
47153
|
+
const newRatchet = isInitiator ? DoubleRatchet.initSender(sharedSecret, {
|
|
47154
|
+
publicKey: hexToBytes(identity.publicKey),
|
|
47155
|
+
privateKey: hexToBytes(identity.privateKey),
|
|
47156
|
+
keyType: "ed25519"
|
|
47157
|
+
}) : DoubleRatchet.initReceiver(sharedSecret, {
|
|
47158
|
+
publicKey: hexToBytes(identity.publicKey),
|
|
47159
|
+
privateKey: hexToBytes(identity.privateKey),
|
|
47160
|
+
keyType: "ed25519"
|
|
47161
|
+
});
|
|
47162
|
+
session.ratchet = newRatchet;
|
|
47163
|
+
session.activated = false;
|
|
47164
|
+
this._persisted.sessions[convId] = {
|
|
47165
|
+
ownerDeviceId: session.ownerDeviceId,
|
|
47166
|
+
ratchetState: newRatchet.serialize(),
|
|
47167
|
+
activated: false
|
|
47168
|
+
};
|
|
47169
|
+
await this._persistState();
|
|
47170
|
+
console.log(
|
|
47171
|
+
`[SecureChannel] Room ratchet re-initialized for conv ${convId.slice(0, 8)}...`
|
|
47172
|
+
);
|
|
47173
|
+
plaintext = session.ratchet.decrypt(encrypted);
|
|
47174
|
+
} catch (reinitErr) {
|
|
47175
|
+
console.error(
|
|
47176
|
+
`[SecureChannel] Room ratchet re-init failed for conv ${convId.slice(0, 8)}...:`,
|
|
47177
|
+
reinitErr
|
|
47178
|
+
);
|
|
47179
|
+
return;
|
|
47180
|
+
}
|
|
47181
|
+
}
|
|
47182
|
+
let messageText;
|
|
47183
|
+
let messageType;
|
|
47184
|
+
try {
|
|
47185
|
+
const parsed = JSON.parse(plaintext);
|
|
47186
|
+
messageType = parsed.type || "message";
|
|
47187
|
+
messageText = parsed.text || plaintext;
|
|
47188
|
+
} catch {
|
|
47189
|
+
messageType = "message";
|
|
47190
|
+
messageText = plaintext;
|
|
47191
|
+
}
|
|
47013
47192
|
if (!session.activated) {
|
|
47014
47193
|
session.activated = true;
|
|
47015
47194
|
console.log(
|
|
@@ -47024,16 +47203,17 @@ ${messageText}`;
|
|
|
47024
47203
|
messageId: msgData.message_id ?? "",
|
|
47025
47204
|
conversationId: convId,
|
|
47026
47205
|
timestamp: msgData.created_at ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
47027
|
-
messageType
|
|
47206
|
+
messageType,
|
|
47207
|
+
roomId: msgData.room_id
|
|
47028
47208
|
};
|
|
47029
47209
|
this.emit("room_message", {
|
|
47030
47210
|
roomId: msgData.room_id,
|
|
47031
47211
|
senderDeviceId: msgData.sender_device_id,
|
|
47032
|
-
plaintext,
|
|
47033
|
-
messageType
|
|
47212
|
+
plaintext: messageText,
|
|
47213
|
+
messageType,
|
|
47034
47214
|
timestamp: msgData.created_at ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
47035
47215
|
});
|
|
47036
|
-
this.config.onMessage?.(
|
|
47216
|
+
this.config.onMessage?.(messageText, metadata);
|
|
47037
47217
|
}
|
|
47038
47218
|
/**
|
|
47039
47219
|
* Find the pairwise conversation ID for a given sender in a room.
|
|
@@ -47121,8 +47301,12 @@ ${messageText}`;
|
|
|
47121
47301
|
since = msg.created_at;
|
|
47122
47302
|
totalProcessed++;
|
|
47123
47303
|
} catch (err) {
|
|
47124
|
-
|
|
47125
|
-
|
|
47304
|
+
console.warn(
|
|
47305
|
+
`[SecureChannel] Sync decrypt failed for msg ${msg.id.slice(0, 8)}... in conv ${msg.conversation_id.slice(0, 8)}...: ${String(err)}`
|
|
47306
|
+
);
|
|
47307
|
+
this._persisted.lastMessageTimestamp = msg.created_at;
|
|
47308
|
+
since = msg.created_at;
|
|
47309
|
+
continue;
|
|
47126
47310
|
}
|
|
47127
47311
|
}
|
|
47128
47312
|
await this._persistState();
|