diff --git a/src/matrix/e2ee/RoomEncryption.js b/src/matrix/e2ee/RoomEncryption.js index 13b00f6f..62521a4f 100644 --- a/src/matrix/e2ee/RoomEncryption.js +++ b/src/matrix/e2ee/RoomEncryption.js @@ -93,7 +93,7 @@ export class RoomEncryption { // this happens before entries exists, as they are created by the syncwriter // but we want to be able to map it back to something in the timeline easily // when retrying decryption. - async prepareDecryptAll(events, newKeys, source, isTimelineOpen, txn) { + async prepareDecryptAll(events, newKeys, source, txn) { const errors = new Map(); const validEvents = []; for (const event of events) { @@ -126,7 +126,7 @@ export class RoomEncryption { if (customCache) { customCache.dispose(); } - return new DecryptionPreparation(preparation, errors, {isTimelineOpen, source}, this, events); + return new DecryptionPreparation(preparation, errors, source, this, events); } async _processDecryptionResults(events, results, errors, flags, txn) { @@ -139,11 +139,6 @@ export class RoomEncryption { this._missingSessionCandidates.removeEvent(event); } } - if (flags.isTimelineOpen) { - for (const result of results.values()) { - await this._verifyDecryptionResult(result, txn); - } - } } async _verifyDecryptionResult(result, txn) { @@ -424,10 +419,10 @@ export class RoomEncryption { * the decryption results before turning them */ class DecryptionPreparation { - constructor(megolmDecryptionPreparation, extraErrors, flags, roomEncryption, events) { + constructor(megolmDecryptionPreparation, extraErrors, source, roomEncryption, events) { this._megolmDecryptionPreparation = megolmDecryptionPreparation; this._extraErrors = extraErrors; - this._flags = flags; + this._source = source; this._roomEncryption = roomEncryption; this._events = events; } @@ -436,7 +431,7 @@ class DecryptionPreparation { return new DecryptionChanges( await this._megolmDecryptionPreparation.decrypt(), this._extraErrors, - this._flags, + this._source, this._roomEncryption, this._events); } @@ -447,10 +442,10 @@ class DecryptionPreparation { } class DecryptionChanges { - constructor(megolmDecryptionChanges, extraErrors, flags, roomEncryption, events) { + constructor(megolmDecryptionChanges, extraErrors, source, roomEncryption, events) { this._megolmDecryptionChanges = megolmDecryptionChanges; this._extraErrors = extraErrors; - this._flags = flags; + this._source = source; this._roomEncryption = roomEncryption; this._events = events; } @@ -458,15 +453,16 @@ class DecryptionChanges { async write(txn) { const {results, errors} = await this._megolmDecryptionChanges.write(txn); mergeMap(this._extraErrors, errors); - await this._roomEncryption._processDecryptionResults(this._events, results, errors, this._flags, txn); - return new BatchDecryptionResult(results, errors); + await this._roomEncryption._processDecryptionResults(this._events, results, errors, this._source, txn); + return new BatchDecryptionResult(results, errors, this._roomEncryption); } } class BatchDecryptionResult { - constructor(results, errors) { + constructor(results, errors, roomEncryption) { this.results = results; this.errors = errors; + this._roomEncryption = roomEncryption; } applyToEntries(entries) { @@ -482,6 +478,12 @@ class BatchDecryptionResult { } } } + + verifySenders(txn) { + return Promise.all(Array.from(this.results.values()).map(result => { + return this._roomEncryption._verifyDecryptionResult(result, txn); + })); + } } class SessionToEventIdsMap { diff --git a/src/matrix/room/Room.js b/src/matrix/room/Room.js index 5883da1a..442da4fb 100644 --- a/src/matrix/room/Room.js +++ b/src/matrix/room/Room.js @@ -147,13 +147,13 @@ export class Room extends EventEmitter { const events = entries.filter(entry => { return entry.eventType === EVENT_ENCRYPTED_TYPE; }).map(entry => entry.event); - const isTimelineOpen = this._isTimelineOpen; - r.preparation = await this._roomEncryption.prepareDecryptAll(events, null, source, isTimelineOpen, inboundSessionTxn); + r.preparation = await this._roomEncryption.prepareDecryptAll(events, null, source, inboundSessionTxn); if (r.cancelled) return; const changes = await r.preparation.decrypt(); r.preparation = null; if (r.cancelled) return; const stores = [this._storage.storeNames.groupSessionDecryptions]; + const isTimelineOpen = this._isTimelineOpen; if (isTimelineOpen) { // read to fetch devices if timeline is open stores.push(this._storage.storeNames.deviceIdentities); @@ -162,6 +162,9 @@ export class Room extends EventEmitter { let decryption; try { decryption = await changes.write(writeTxn); + if (isTimelineOpen) { + await decryption.verifySenders(writeTxn); + } } catch (err) { writeTxn.abort(); throw err; @@ -210,7 +213,7 @@ export class Room extends EventEmitter { return event?.type === EVENT_ENCRYPTED_TYPE; }); decryptPreparation = await roomEncryption.prepareDecryptAll( - eventsToDecrypt, newKeys, DecryptionSource.Sync, this._isTimelineOpen, txn); + eventsToDecrypt, newKeys, DecryptionSource.Sync, txn); } } @@ -240,6 +243,9 @@ export class Room extends EventEmitter { await log.wrap("syncWriter", log => this._syncWriter.writeSync(roomResponse, txn, log), log.level.Detail); if (decryptChanges) { const decryption = await decryptChanges.write(txn); + if (this._isTimelineOpen) { + await decryption.verifySenders(txn); + } if (retryEntries?.length) { // TODO: this will modify existing timeline entries (which we should not do in writeSync), // but it is a temporary way of reattempting decryption while timeline is open