From f3c49e51f2081ac6e8bb4074014149fd707a7fa2 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 3 Mar 2021 11:27:55 +0100 Subject: [PATCH] add, don't replace timeline retry entries also, filter out any that have been decrypted already --- src/matrix/e2ee/RoomEncryption.js | 14 ++++--- src/matrix/room/Room.js | 70 ++++++++++++++++++------------- 2 files changed, 48 insertions(+), 36 deletions(-) diff --git a/src/matrix/e2ee/RoomEncryption.js b/src/matrix/e2ee/RoomEncryption.js index 3cf1310d..9a6a5fc3 100644 --- a/src/matrix/e2ee/RoomEncryption.js +++ b/src/matrix/e2ee/RoomEncryption.js @@ -390,13 +390,15 @@ export class RoomEncryption { await hsApi.sendToDevice(type, payload, txnId, {log}).response(); } - filterEventEntriesForKeys(entries, keys) { + filterUndecryptedEventEntriesForKeys(entries, keys) { return entries.filter(entry => { - const {event} = entry; - if (event) { - const senderKey = event.content?.["sender_key"]; - const sessionId = event.content?.["session_id"]; - return keys.some(key => senderKey === key.senderKey && sessionId === key.sessionId); + if (entry.isEncrypted && !entry.isDecrypted) { + const {event} = entry; + if (event) { + const senderKey = event.content?.["sender_key"]; + const sessionId = event.content?.["session_id"]; + return keys.some(key => senderKey === key.senderKey && sessionId === key.sessionId); + } } return false; }); diff --git a/src/matrix/room/Room.js b/src/matrix/room/Room.js index 83dd5bf9..6f8c7530 100644 --- a/src/matrix/room/Room.js +++ b/src/matrix/room/Room.js @@ -156,6 +156,42 @@ export class Room extends EventEmitter { return request; } + async _prepareSyncDecryption(events, newKeys, roomEncryption, txn, log) { + let retryEntries; + let decryptPreparation; + // when new keys arrive, also see if any events that can now be retried to decrypt + if (newKeys) { + const entriesPerKey = await Promise.all(newKeys.map(key => this._getRetryDecryptEntriesForKey(key, txn))); + retryEntries = entriesPerKey.reduce((allEntries, entries) => allEntries.concat(entries), []); + // If we have the timeline open, see if there are more entries for the new keys + // as we only store missing session information for synced events, not backfilled. + // We want to decrypt all events we can though if the user is looking + // at them when the timeline is open + if (this._timeline) { + let retryTimelineEntries = this._roomEncryption.filterUndecryptedEventEntriesForKeys(this._timeline.remoteEntries, newKeys); + // filter out any entries already in retryEntries so we don't decrypt them twice + const existingIds = retryEntries.reduce((ids, e) => {ids.add(e.id); return ids;}, new Set()); + retryTimelineEntries = retryTimelineEntries.filter(e => !existingIds.has(e.id)); + // make copies so we don't modify the original entry in writeSync, before the afterSync stage + const retryTimelineEntriesCopies = retryTimelineEntries.map(e => e.clone()); + // add to other retry entries + retryEntries = retryEntries.concat(retryTimelineEntriesCopies); + } + if (retryEntries.length) { + log.set("retry", retryEntries.length); + events = events.concat(retryEntries.map(entry => entry.event)); + } + } + const eventsToDecrypt = events.filter(event => { + return event?.type === EVENT_ENCRYPTED_TYPE; + }); + if (eventsToDecrypt.length) { + decryptPreparation = await roomEncryption.prepareDecryptAll( + eventsToDecrypt, newKeys, DecryptionSource.Sync, txn); + } + return {retryEntries, decryptPreparation}; + } + async prepareSync(roomResponse, membership, newKeys, txn, log) { log.set("id", this.id); if (newKeys) { @@ -172,36 +208,10 @@ export class Room extends EventEmitter { let retryEntries; let decryptPreparation; if (roomEncryption) { - // also look for events in timeline here - let events = roomResponse?.timeline?.events || []; - // when new keys arrive, also see if any events that can now be retried to decrypt - if (newKeys) { - const entriesPerKey = await Promise.all(newKeys.map(key => this._getRetryDecryptEntriesForKey(key, txn))); - retryEntries = entriesPerKey.reduce((allEntries, entries) => allEntries.concat(entries), []); - // If we have the timeline open, see if there are more entries for the new keys - // as we only store missing session for synced and not backfilled events. - // We want to decrypt all events we can though if the user is looking - // at them given the timeline is open - if (this._timeline) { - let retryTimelineEntries = this._roomEncryption.filterEventEntriesForKeys(this._timeline.remoteEntries, newKeys); - // filter out any entries already in retryEntries so we don't decrypt them twice - const existingIds = new Set(retryEntries.map(e => e.id)); - retryTimelineEntries = retryTimelineEntries.filter(e => !existingIds.has(e.id)) - // make copies so we don't modify the original entry before the afterSync stage - retryEntries = retryTimelineEntries.map(e => e.clone()); - } - if (retryEntries.length) { - log.set("retry", retryEntries.length); - events = events.concat(retryEntries.map(entry => entry.event)); - } - } - const eventsToDecrypt = events.filter(event => { - return event?.type === EVENT_ENCRYPTED_TYPE; - }); - if (eventsToDecrypt.length) { - decryptPreparation = await roomEncryption.prepareDecryptAll( - eventsToDecrypt, newKeys, DecryptionSource.Sync, txn); - } + const events = roomResponse?.timeline?.events || []; + const result = await this._prepareSyncDecryption(events, newKeys, roomEncryption, txn, log); + retryEntries = result.retryEntries; + decryptPreparation = result.decryptPreparation; } return {