@agentvault/secure-channel 0.2.0 → 0.4.0
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 +9 -0
- package/dist/channel.d.ts.map +1 -1
- package/dist/cli.js +153 -42
- package/dist/cli.js.map +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +154 -43
- package/dist/index.js.map +2 -2
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/channel.d.ts
CHANGED
|
@@ -25,6 +25,10 @@ export declare class SecureChannel extends EventEmitter {
|
|
|
25
25
|
/** Returns the number of active sessions. */
|
|
26
26
|
get sessionCount(): number;
|
|
27
27
|
start(): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Append a message to persistent history for cross-device replay.
|
|
30
|
+
*/
|
|
31
|
+
private _appendHistory;
|
|
28
32
|
/**
|
|
29
33
|
* Encrypt and send a message to ALL owner devices (fanout).
|
|
30
34
|
* Each session gets the same plaintext encrypted independently.
|
|
@@ -46,6 +50,11 @@ export declare class SecureChannel extends EventEmitter {
|
|
|
46
50
|
* This allows all owner devices to see messages from any single device.
|
|
47
51
|
*/
|
|
48
52
|
private _relaySyncToSiblings;
|
|
53
|
+
/**
|
|
54
|
+
* Send stored message history to a newly-activated session.
|
|
55
|
+
* Batches all history into a single encrypted message.
|
|
56
|
+
*/
|
|
57
|
+
private _replayHistoryToSession;
|
|
49
58
|
/**
|
|
50
59
|
* Handle a device_linked event: a new owner device has joined.
|
|
51
60
|
* Fetches the new device's public keys, performs X3DH, and initializes
|
package/dist/channel.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAa3C,OAAO,KAAK,EACV,mBAAmB,EACnB,YAAY,
|
|
1
|
+
{"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAa3C,OAAO,KAAK,EACV,mBAAmB,EACnB,YAAY,EAKb,MAAM,YAAY,CAAC;AAiDpB,qBAAa,aAAc,SAAQ,YAAY;IAiBjC,OAAO,CAAC,MAAM;IAhB1B,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,sBAAsB,CAAc;IAC5C,OAAO,CAAC,UAAU,CAAuB;IACzC,OAAO,CAAC,SAAS,CAGH;IACd,OAAO,CAAC,GAAG,CAA0B;IACrC,OAAO,CAAC,UAAU,CAA8C;IAChE,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,eAAe,CAA8C;IACrE,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,UAAU,CAA+B;gBAE7B,MAAM,EAAE,mBAAmB;IAI/C,IAAI,KAAK,IAAI,YAAY,CAExB;IAED,IAAI,QAAQ,IAAI,MAAM,GAAG,IAAI,CAE5B;IAED,IAAI,WAAW,IAAI,MAAM,GAAG,IAAI,CAE/B;IAED,iEAAiE;IACjE,IAAI,cAAc,IAAI,MAAM,GAAG,IAAI,CAElC;IAED,2CAA2C;IAC3C,IAAI,eAAe,IAAI,MAAM,EAAE,CAE9B;IAED,6CAA6C;IAC7C,IAAI,YAAY,IAAI,MAAM,CAEzB;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAsC5B;;OAEG;IACH,OAAO,CAAC,cAAc;IAmBtB;;;OAGG;IACG,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAsCtC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAoBb,OAAO;IAgDrB,OAAO,CAAC,KAAK;YAgCC,SAAS;IA2HvB,OAAO,CAAC,QAAQ;IA4DhB;;;;OAIG;YACW,sBAAsB;IAoFpC;;;OAGG;YACW,oBAAoB;IAmClC;;;OAGG;YACW,uBAAuB;IAkCrC;;;;OAIG;YACW,mBAAmB;IAkEjC;;;OAGG;YACW,mBAAmB;IAwFjC,OAAO,CAAC,kBAAkB;IAgB1B,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,YAAY;IAKpB;;;OAGG;YACW,aAAa;CAc5B"}
|
package/dist/cli.js
CHANGED
|
@@ -45054,7 +45054,8 @@ function migratePersistedState(raw) {
|
|
|
45054
45054
|
identityKeypair: legacy.identityKeypair,
|
|
45055
45055
|
ephemeralKeypair: legacy.ephemeralKeypair,
|
|
45056
45056
|
fingerprint: legacy.fingerprint,
|
|
45057
|
-
lastMessageTimestamp: legacy.lastMessageTimestamp
|
|
45057
|
+
lastMessageTimestamp: legacy.lastMessageTimestamp,
|
|
45058
|
+
messageHistory: []
|
|
45058
45059
|
};
|
|
45059
45060
|
}
|
|
45060
45061
|
var SecureChannel = class extends EventEmitter {
|
|
@@ -45101,6 +45102,9 @@ var SecureChannel = class extends EventEmitter {
|
|
|
45101
45102
|
const raw = await loadState(this.config.dataDir);
|
|
45102
45103
|
if (raw) {
|
|
45103
45104
|
this._persisted = migratePersistedState(raw);
|
|
45105
|
+
if (!this._persisted.messageHistory) {
|
|
45106
|
+
this._persisted.messageHistory = [];
|
|
45107
|
+
}
|
|
45104
45108
|
this._deviceId = this._persisted.deviceId;
|
|
45105
45109
|
this._deviceJwt = this._persisted.deviceJwt;
|
|
45106
45110
|
this._primaryConversationId = this._persisted.primaryConversationId;
|
|
@@ -45112,7 +45116,8 @@ var SecureChannel = class extends EventEmitter {
|
|
|
45112
45116
|
const ratchet = DoubleRatchet.deserialize(sessionData.ratchetState);
|
|
45113
45117
|
this._sessions.set(convId, {
|
|
45114
45118
|
ownerDeviceId: sessionData.ownerDeviceId,
|
|
45115
|
-
ratchet
|
|
45119
|
+
ratchet,
|
|
45120
|
+
activated: sessionData.activated ?? false
|
|
45116
45121
|
});
|
|
45117
45122
|
}
|
|
45118
45123
|
}
|
|
@@ -45121,6 +45126,24 @@ var SecureChannel = class extends EventEmitter {
|
|
|
45121
45126
|
}
|
|
45122
45127
|
await this._enroll();
|
|
45123
45128
|
}
|
|
45129
|
+
/**
|
|
45130
|
+
* Append a message to persistent history for cross-device replay.
|
|
45131
|
+
*/
|
|
45132
|
+
_appendHistory(sender, text) {
|
|
45133
|
+
if (!this._persisted) return;
|
|
45134
|
+
if (!this._persisted.messageHistory) {
|
|
45135
|
+
this._persisted.messageHistory = [];
|
|
45136
|
+
}
|
|
45137
|
+
const maxSize = this.config.maxHistorySize ?? 500;
|
|
45138
|
+
this._persisted.messageHistory.push({
|
|
45139
|
+
sender,
|
|
45140
|
+
text,
|
|
45141
|
+
ts: (/* @__PURE__ */ new Date()).toISOString()
|
|
45142
|
+
});
|
|
45143
|
+
if (this._persisted.messageHistory.length > maxSize) {
|
|
45144
|
+
this._persisted.messageHistory = this._persisted.messageHistory.slice(-maxSize);
|
|
45145
|
+
}
|
|
45146
|
+
}
|
|
45124
45147
|
/**
|
|
45125
45148
|
* Encrypt and send a message to ALL owner devices (fanout).
|
|
45126
45149
|
* Each session gets the same plaintext encrypted independently.
|
|
@@ -45129,8 +45152,12 @@ var SecureChannel = class extends EventEmitter {
|
|
|
45129
45152
|
if (this._state !== "ready" || this._sessions.size === 0 || !this._ws) {
|
|
45130
45153
|
throw new Error("Channel is not ready");
|
|
45131
45154
|
}
|
|
45155
|
+
this._appendHistory("agent", plaintext);
|
|
45132
45156
|
const messageGroupId = randomUUID();
|
|
45133
45157
|
for (const [convId, session] of this._sessions) {
|
|
45158
|
+
if (!session.activated) {
|
|
45159
|
+
continue;
|
|
45160
|
+
}
|
|
45134
45161
|
const encrypted = session.ratchet.encrypt(plaintext);
|
|
45135
45162
|
const transport = encryptedMessageToTransport(encrypted);
|
|
45136
45163
|
this._ws.send(
|
|
@@ -45201,7 +45228,8 @@ var SecureChannel = class extends EventEmitter {
|
|
|
45201
45228
|
publicKey: bytesToHex(ephemeral.publicKey),
|
|
45202
45229
|
privateKey: bytesToHex(ephemeral.privateKey)
|
|
45203
45230
|
},
|
|
45204
|
-
fingerprint: result.fingerprint
|
|
45231
|
+
fingerprint: result.fingerprint,
|
|
45232
|
+
messageHistory: []
|
|
45205
45233
|
};
|
|
45206
45234
|
this._poll();
|
|
45207
45235
|
} catch (err) {
|
|
@@ -45252,36 +45280,73 @@ var SecureChannel = class extends EventEmitter {
|
|
|
45252
45280
|
this._deviceJwt = result.device_jwt;
|
|
45253
45281
|
const identity = this._persisted.identityKeypair;
|
|
45254
45282
|
const ephemeral = this._persisted.ephemeralKeypair;
|
|
45255
|
-
const
|
|
45256
|
-
|
|
45257
|
-
|
|
45258
|
-
|
|
45259
|
-
|
|
45260
|
-
|
|
45261
|
-
|
|
45262
|
-
|
|
45263
|
-
|
|
45264
|
-
|
|
45265
|
-
|
|
45266
|
-
|
|
45267
|
-
|
|
45268
|
-
|
|
45269
|
-
|
|
45270
|
-
|
|
45271
|
-
|
|
45272
|
-
|
|
45283
|
+
const sessions = {};
|
|
45284
|
+
for (const conv of conversations) {
|
|
45285
|
+
const ownerIdentityKey = conv.owner_identity_public_key || result.owner_identity_public_key;
|
|
45286
|
+
const ownerEphemeralKey = conv.owner_ephemeral_public_key || result.owner_ephemeral_public_key || ownerIdentityKey;
|
|
45287
|
+
const sharedSecret = performX3DH({
|
|
45288
|
+
myIdentityPrivate: hexToBytes(identity.privateKey),
|
|
45289
|
+
myEphemeralPrivate: hexToBytes(ephemeral.privateKey),
|
|
45290
|
+
theirIdentityPublic: hexToBytes(ownerIdentityKey),
|
|
45291
|
+
theirEphemeralPublic: hexToBytes(ownerEphemeralKey),
|
|
45292
|
+
isInitiator: false
|
|
45293
|
+
});
|
|
45294
|
+
const ratchet = DoubleRatchet.initReceiver(sharedSecret, {
|
|
45295
|
+
publicKey: hexToBytes(identity.publicKey),
|
|
45296
|
+
privateKey: hexToBytes(identity.privateKey),
|
|
45297
|
+
keyType: "ed25519"
|
|
45298
|
+
});
|
|
45299
|
+
this._sessions.set(conv.conversation_id, {
|
|
45300
|
+
ownerDeviceId: conv.owner_device_id,
|
|
45301
|
+
ratchet,
|
|
45302
|
+
activated: false
|
|
45303
|
+
// Wait for owner's first message before sending to this session
|
|
45304
|
+
});
|
|
45305
|
+
sessions[conv.conversation_id] = {
|
|
45306
|
+
ownerDeviceId: conv.owner_device_id,
|
|
45307
|
+
ratchetState: ratchet.serialize()
|
|
45308
|
+
};
|
|
45309
|
+
console.log(
|
|
45310
|
+
`[SecureChannel] Session initialized for conv ${conv.conversation_id.slice(0, 8)}... (owner ${conv.owner_device_id.slice(0, 8)}..., primary=${conv.is_primary})`
|
|
45311
|
+
);
|
|
45312
|
+
}
|
|
45273
45313
|
this._persisted = {
|
|
45274
45314
|
...this._persisted,
|
|
45275
45315
|
deviceJwt: result.device_jwt,
|
|
45276
45316
|
primaryConversationId: primary.conversation_id,
|
|
45277
|
-
sessions
|
|
45278
|
-
|
|
45279
|
-
ownerDeviceId: primary.owner_device_id,
|
|
45280
|
-
ratchetState: ratchet.serialize()
|
|
45281
|
-
}
|
|
45282
|
-
}
|
|
45317
|
+
sessions,
|
|
45318
|
+
messageHistory: this._persisted.messageHistory ?? []
|
|
45283
45319
|
};
|
|
45284
45320
|
await saveState(this.config.dataDir, this._persisted);
|
|
45321
|
+
if (this.config.webhookUrl) {
|
|
45322
|
+
try {
|
|
45323
|
+
const webhookResp = await fetch(
|
|
45324
|
+
`${this.config.apiUrl}/api/v1/devices/self/webhook`,
|
|
45325
|
+
{
|
|
45326
|
+
method: "PATCH",
|
|
45327
|
+
headers: {
|
|
45328
|
+
"Content-Type": "application/json",
|
|
45329
|
+
Authorization: `Bearer ${this._deviceJwt}`
|
|
45330
|
+
},
|
|
45331
|
+
body: JSON.stringify({ webhook_url: this.config.webhookUrl })
|
|
45332
|
+
}
|
|
45333
|
+
);
|
|
45334
|
+
if (webhookResp.ok) {
|
|
45335
|
+
const webhookData = await webhookResp.json();
|
|
45336
|
+
console.log(
|
|
45337
|
+
`[SecureChannel] Webhook registered: ${this.config.webhookUrl} (secret: ${webhookData.webhook_secret?.slice(0, 8)}...)`
|
|
45338
|
+
);
|
|
45339
|
+
this.emit("webhook_registered", {
|
|
45340
|
+
url: this.config.webhookUrl,
|
|
45341
|
+
secret: webhookData.webhook_secret
|
|
45342
|
+
});
|
|
45343
|
+
} else {
|
|
45344
|
+
console.warn(`[SecureChannel] Webhook registration failed: ${webhookResp.status}`);
|
|
45345
|
+
}
|
|
45346
|
+
} catch (err) {
|
|
45347
|
+
console.warn(`[SecureChannel] Webhook registration error: ${err}`);
|
|
45348
|
+
}
|
|
45349
|
+
}
|
|
45285
45350
|
this._connect();
|
|
45286
45351
|
} catch (err) {
|
|
45287
45352
|
this._handleError(err);
|
|
@@ -45352,6 +45417,10 @@ var SecureChannel = class extends EventEmitter {
|
|
|
45352
45417
|
ciphertext: msgData.ciphertext
|
|
45353
45418
|
});
|
|
45354
45419
|
const plaintext = session.ratchet.decrypt(encrypted);
|
|
45420
|
+
if (!session.activated) {
|
|
45421
|
+
session.activated = true;
|
|
45422
|
+
console.log(`[SecureChannel] Session ${convId.slice(0, 8)}... activated by first owner message`);
|
|
45423
|
+
}
|
|
45355
45424
|
let messageText;
|
|
45356
45425
|
let messageType;
|
|
45357
45426
|
try {
|
|
@@ -45362,7 +45431,14 @@ var SecureChannel = class extends EventEmitter {
|
|
|
45362
45431
|
messageType = "message";
|
|
45363
45432
|
messageText = plaintext;
|
|
45364
45433
|
}
|
|
45434
|
+
if (messageType === "session_init") {
|
|
45435
|
+
console.log(`[SecureChannel] session_init received for ${convId.slice(0, 8)}..., replaying history`);
|
|
45436
|
+
await this._replayHistoryToSession(convId);
|
|
45437
|
+
await this._persistState();
|
|
45438
|
+
return;
|
|
45439
|
+
}
|
|
45365
45440
|
if (messageType === "message") {
|
|
45441
|
+
this._appendHistory("owner", messageText);
|
|
45366
45442
|
const metadata = {
|
|
45367
45443
|
messageId: msgData.message_id,
|
|
45368
45444
|
conversationId: convId,
|
|
@@ -45391,6 +45467,7 @@ var SecureChannel = class extends EventEmitter {
|
|
|
45391
45467
|
});
|
|
45392
45468
|
for (const [siblingConvId, siblingSession] of this._sessions) {
|
|
45393
45469
|
if (siblingConvId === sourceConvId) continue;
|
|
45470
|
+
if (!siblingSession.activated) continue;
|
|
45394
45471
|
const syncEncrypted = siblingSession.ratchet.encrypt(syncPayload);
|
|
45395
45472
|
const syncTransport = encryptedMessageToTransport(syncEncrypted);
|
|
45396
45473
|
this._ws.send(
|
|
@@ -45405,6 +45482,38 @@ var SecureChannel = class extends EventEmitter {
|
|
|
45405
45482
|
);
|
|
45406
45483
|
}
|
|
45407
45484
|
}
|
|
45485
|
+
/**
|
|
45486
|
+
* Send stored message history to a newly-activated session.
|
|
45487
|
+
* Batches all history into a single encrypted message.
|
|
45488
|
+
*/
|
|
45489
|
+
async _replayHistoryToSession(convId) {
|
|
45490
|
+
const session = this._sessions.get(convId);
|
|
45491
|
+
if (!session || !session.activated || !this._ws) return;
|
|
45492
|
+
const history = this._persisted?.messageHistory ?? [];
|
|
45493
|
+
if (history.length === 0) {
|
|
45494
|
+
console.log(`[SecureChannel] No history to replay for ${convId.slice(0, 8)}...`);
|
|
45495
|
+
return;
|
|
45496
|
+
}
|
|
45497
|
+
console.log(
|
|
45498
|
+
`[SecureChannel] Replaying ${history.length} messages to session ${convId.slice(0, 8)}...`
|
|
45499
|
+
);
|
|
45500
|
+
const replayPayload = JSON.stringify({
|
|
45501
|
+
type: "history_replay",
|
|
45502
|
+
messages: history
|
|
45503
|
+
});
|
|
45504
|
+
const encrypted = session.ratchet.encrypt(replayPayload);
|
|
45505
|
+
const transport = encryptedMessageToTransport(encrypted);
|
|
45506
|
+
this._ws.send(
|
|
45507
|
+
JSON.stringify({
|
|
45508
|
+
event: "message",
|
|
45509
|
+
data: {
|
|
45510
|
+
conversation_id: convId,
|
|
45511
|
+
header_blob: transport.header_blob,
|
|
45512
|
+
ciphertext: transport.ciphertext
|
|
45513
|
+
}
|
|
45514
|
+
})
|
|
45515
|
+
);
|
|
45516
|
+
}
|
|
45408
45517
|
/**
|
|
45409
45518
|
* Handle a device_linked event: a new owner device has joined.
|
|
45410
45519
|
* Fetches the new device's public keys, performs X3DH, and initializes
|
|
@@ -45415,27 +45524,20 @@ var SecureChannel = class extends EventEmitter {
|
|
|
45415
45524
|
`[SecureChannel] New owner device linked: ${event.owner_device_id.slice(0, 8)}...`
|
|
45416
45525
|
);
|
|
45417
45526
|
try {
|
|
45418
|
-
|
|
45419
|
-
`${this.config.apiUrl}/api/v1/conversations/${event.conversation_id}/keys`,
|
|
45420
|
-
{
|
|
45421
|
-
headers: { Authorization: `Bearer ${this._deviceJwt}` }
|
|
45422
|
-
}
|
|
45423
|
-
);
|
|
45424
|
-
if (!keysRes.ok) {
|
|
45527
|
+
if (!event.owner_identity_public_key) {
|
|
45425
45528
|
console.error(
|
|
45426
|
-
`[SecureChannel]
|
|
45529
|
+
`[SecureChannel] device_linked event missing owner keys for conv ${event.conversation_id.slice(0, 8)}...`
|
|
45427
45530
|
);
|
|
45428
45531
|
return;
|
|
45429
45532
|
}
|
|
45430
|
-
const keys = await keysRes.json();
|
|
45431
45533
|
const identity = this._persisted.identityKeypair;
|
|
45432
45534
|
const ephemeral = this._persisted.ephemeralKeypair;
|
|
45433
45535
|
const sharedSecret = performX3DH({
|
|
45434
45536
|
myIdentityPrivate: hexToBytes(identity.privateKey),
|
|
45435
45537
|
myEphemeralPrivate: hexToBytes(ephemeral.privateKey),
|
|
45436
|
-
theirIdentityPublic: hexToBytes(
|
|
45538
|
+
theirIdentityPublic: hexToBytes(event.owner_identity_public_key),
|
|
45437
45539
|
theirEphemeralPublic: hexToBytes(
|
|
45438
|
-
|
|
45540
|
+
event.owner_ephemeral_public_key ?? event.owner_identity_public_key
|
|
45439
45541
|
),
|
|
45440
45542
|
isInitiator: false
|
|
45441
45543
|
});
|
|
@@ -45446,15 +45548,18 @@ var SecureChannel = class extends EventEmitter {
|
|
|
45446
45548
|
});
|
|
45447
45549
|
this._sessions.set(event.conversation_id, {
|
|
45448
45550
|
ownerDeviceId: event.owner_device_id,
|
|
45449
|
-
ratchet
|
|
45551
|
+
ratchet,
|
|
45552
|
+
activated: false
|
|
45553
|
+
// Wait for owner's first message
|
|
45450
45554
|
});
|
|
45451
45555
|
this._persisted.sessions[event.conversation_id] = {
|
|
45452
45556
|
ownerDeviceId: event.owner_device_id,
|
|
45453
|
-
ratchetState: ratchet.serialize()
|
|
45557
|
+
ratchetState: ratchet.serialize(),
|
|
45558
|
+
activated: false
|
|
45454
45559
|
};
|
|
45455
45560
|
await this._persistState();
|
|
45456
45561
|
console.log(
|
|
45457
|
-
`[SecureChannel] Session initialized for device ${event.owner_device_id.slice(0, 8)}
|
|
45562
|
+
`[SecureChannel] Session initialized for device ${event.owner_device_id.slice(0, 8)}... (conv ${event.conversation_id.slice(0, 8)}...)`
|
|
45458
45563
|
);
|
|
45459
45564
|
} catch (err) {
|
|
45460
45565
|
console.error(
|
|
@@ -45493,6 +45598,10 @@ var SecureChannel = class extends EventEmitter {
|
|
|
45493
45598
|
ciphertext: msg.ciphertext
|
|
45494
45599
|
});
|
|
45495
45600
|
const plaintext = session.ratchet.decrypt(encrypted);
|
|
45601
|
+
if (!session.activated) {
|
|
45602
|
+
session.activated = true;
|
|
45603
|
+
console.log(`[SecureChannel] Session ${msg.conversation_id.slice(0, 8)}... activated during sync`);
|
|
45604
|
+
}
|
|
45496
45605
|
let messageText;
|
|
45497
45606
|
let messageType;
|
|
45498
45607
|
try {
|
|
@@ -45504,6 +45613,7 @@ var SecureChannel = class extends EventEmitter {
|
|
|
45504
45613
|
messageText = plaintext;
|
|
45505
45614
|
}
|
|
45506
45615
|
if (messageType === "message") {
|
|
45616
|
+
this._appendHistory("owner", messageText);
|
|
45507
45617
|
const metadata = {
|
|
45508
45618
|
messageId: msg.id,
|
|
45509
45619
|
conversationId: msg.conversation_id,
|
|
@@ -45554,7 +45664,8 @@ var SecureChannel = class extends EventEmitter {
|
|
|
45554
45664
|
for (const [convId, session] of this._sessions) {
|
|
45555
45665
|
this._persisted.sessions[convId] = {
|
|
45556
45666
|
ownerDeviceId: session.ownerDeviceId,
|
|
45557
|
-
ratchetState: session.ratchet.serialize()
|
|
45667
|
+
ratchetState: session.ratchet.serialize(),
|
|
45668
|
+
activated: session.activated
|
|
45558
45669
|
};
|
|
45559
45670
|
}
|
|
45560
45671
|
await saveState(this.config.dataDir, this._persisted);
|