diff --git a/src/matrix/room/Room.js b/src/matrix/room/Room.js index a5781de0..e8fda52e 100644 --- a/src/matrix/room/Room.js +++ b/src/matrix/room/Room.js @@ -176,8 +176,20 @@ export class Room extends EventEmitter { let events = roomResponse?.timeline?.events || []; // when new keys arrive, also see if any events that can now be retried to decrypt if (newKeys) { - const nestedEntries = await Promise.all(newKeys.map(key => this._getRetryDecryptEntriesForKey(key, txn))); - retryEntries = nestedEntries.reduce((allEntries, entries) => allEntries.concat(entries), []); + 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)); diff --git a/src/matrix/room/timeline/entries/EventEntry.js b/src/matrix/room/timeline/entries/EventEntry.js index 410c3d63..88a0aa5e 100644 --- a/src/matrix/room/timeline/entries/EventEntry.js +++ b/src/matrix/room/timeline/entries/EventEntry.js @@ -25,6 +25,13 @@ export class EventEntry extends BaseEntry { this._decryptionResult = null; } + clone() { + const clone = new EventEntry(this._eventEntry, this._fragmentIdComparer); + clone._decryptionResult = this._decryptionResult; + clone._decryptionError = this._decryptionError; + return clone; + } + get event() { return this._eventEntry.event; }