also retry decryption for backfilled entries

as their event ids won't be stored along the missing key (we only store
synced items so we don't fill up the missing event ids in the store
with undecryptable backfilled event ids)
This commit is contained in:
Bruno Windels 2021-03-15 14:33:14 +01:00
parent 86dfbbb0c9
commit 96f060c0a9
2 changed files with 21 additions and 10 deletions

View file

@ -210,11 +210,12 @@ export class RoomEncryption {
} }
let roomKey = this._megolmDecryption.roomKeyFromBackup(this._room.id, sessionId, session); let roomKey = this._megolmDecryption.roomKeyFromBackup(this._room.id, sessionId, session);
if (roomKey) { if (roomKey) {
let keyIsBestOne = false;
let retryEventIds; let retryEventIds;
try { try {
const txn = await this._storage.readWriteTxn([this._storage.storeNames.inboundGroupSessions]); const txn = await this._storage.readWriteTxn([this._storage.storeNames.inboundGroupSessions]);
try { try {
const keyIsBestOne = await this._megolmDecryption.writeRoomKey(roomKey, txn); keyIsBestOne = await this._megolmDecryption.writeRoomKey(roomKey, txn);
if (keyIsBestOne) { if (keyIsBestOne) {
retryEventIds = roomKey.eventIds; retryEventIds = roomKey.eventIds;
} }
@ -228,8 +229,8 @@ export class RoomEncryption {
// this is just clearing the internal sessionInfo // this is just clearing the internal sessionInfo
roomKey.dispose(); roomKey.dispose();
} }
if (retryEventIds?.length) { if (keyIsBestOne) {
await this._room.retryDecryption(retryEventIds); await this._room.retryDecryption(roomKey, retryEventIds || []);
} }
} }
} else if (session?.algorithm) { } else if (session?.algorithm) {

View file

@ -66,13 +66,22 @@ export class Room extends EventEmitter {
return retryEntries; return retryEntries;
} }
_getAdditionalTimelineRetryEntries(otherRetryEntries, roomKeys) {
let retryTimelineEntries = this._roomEncryption.filterUndecryptedEventEntriesForKeys(this._timeline.remoteEntries, roomKeys);
// filter out any entries already in retryEntries so we don't decrypt them twice
const existingIds = otherRetryEntries.reduce((ids, e) => {ids.add(e.id); return ids;}, new Set());
retryTimelineEntries = retryTimelineEntries.filter(e => !existingIds.has(e.id));
return retryTimelineEntries;
}
/** /**
* Used for retrying decryption from other sources than sync, like key backup. * Used for retrying decryption from other sources than sync, like key backup.
* @internal * @internal
* @param {Array<string>} eventIds * @param {RoomKey} roomKey
* @param {Array<string>} eventIds any event ids that should be retried. There might be more in the timeline though for this key.
* @return {Promise} * @return {Promise}
*/ */
async retryDecryption(eventIds) { async retryDecryption(roomKey, eventIds) {
if (!this._roomEncryption) { if (!this._roomEncryption) {
return; return;
} }
@ -80,7 +89,11 @@ export class Room extends EventEmitter {
this._storage.storeNames.timelineEvents, this._storage.storeNames.timelineEvents,
this._storage.storeNames.inboundGroupSessions, this._storage.storeNames.inboundGroupSessions,
]); ]);
const retryEntries = await this._eventIdsToEntries(eventIds, txn); let retryEntries = await this._eventIdsToEntries(eventIds, txn);
if (this._timeline) {
const retryTimelineEntries = this._getAdditionalTimelineRetryEntries(retryEntries, [roomKey]);
retryEntries = retryEntries.concat(retryTimelineEntries);
}
if (retryEntries.length) { if (retryEntries.length) {
const decryptRequest = this._decryptEntries(DecryptionSource.Retry, retryEntries, txn); const decryptRequest = this._decryptEntries(DecryptionSource.Retry, retryEntries, txn);
// this will close txn while awaiting decryption // this will close txn while awaiting decryption
@ -166,10 +179,7 @@ export class Room extends EventEmitter {
// We want to decrypt all events we can though if the user is looking // We want to decrypt all events we can though if the user is looking
// at them when the timeline is open // at them when the timeline is open
if (this._timeline) { if (this._timeline) {
let retryTimelineEntries = this._roomEncryption.filterUndecryptedEventEntriesForKeys(this._timeline.remoteEntries, newKeys); const retryTimelineEntries = this._getAdditionalTimelineRetryEntries(retryEntries, 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 // make copies so we don't modify the original entry in writeSync, before the afterSync stage
const retryTimelineEntriesCopies = retryTimelineEntries.map(e => e.clone()); const retryTimelineEntriesCopies = retryTimelineEntries.map(e => e.clone());
// add to other retry entries // add to other retry entries