delay backup 10s if missing session event came from sync

This commit is contained in:
Bruno Windels 2020-09-18 13:10:41 +02:00
parent 3aead4eae2
commit da780d0aa2
2 changed files with 31 additions and 11 deletions

View file

@ -147,6 +147,7 @@ export class Session {
this.needsSessionBackup.set(true) this.needsSessionBackup.set(true)
} }
}, },
clock: this._clock
}); });
} }

View file

@ -21,8 +21,17 @@ import {makeTxnId} from "../common.js";
const ENCRYPTED_TYPE = "m.room.encrypted"; const ENCRYPTED_TYPE = "m.room.encrypted";
function encodeMissingSessionKey(senderKey, sessionId) {
return `${senderKey}|${sessionId}`;
}
function decodeMissingSessionKey(key) {
const [senderKey, sessionId] = key.split("|");
return {senderKey, sessionId};
}
export class RoomEncryption { export class RoomEncryption {
constructor({room, deviceTracker, olmEncryption, megolmEncryption, megolmDecryption, encryptionParams, storage, sessionBackup, notifyMissingMegolmSession}) { constructor({room, deviceTracker, olmEncryption, megolmEncryption, megolmDecryption, encryptionParams, storage, sessionBackup, notifyMissingMegolmSession, clock}) {
this._room = room; this._room = room;
this._deviceTracker = deviceTracker; this._deviceTracker = deviceTracker;
this._olmEncryption = olmEncryption; this._olmEncryption = olmEncryption;
@ -39,6 +48,7 @@ export class RoomEncryption {
this._storage = storage; this._storage = storage;
this._sessionBackup = sessionBackup; this._sessionBackup = sessionBackup;
this._notifyMissingMegolmSession = notifyMissingMegolmSession; this._notifyMissingMegolmSession = notifyMissingMegolmSession;
this._clock = clock;
this._disposed = false; this._disposed = false;
} }
@ -48,8 +58,8 @@ export class RoomEncryption {
} }
this._sessionBackup = sessionBackup; this._sessionBackup = sessionBackup;
for(const key of this._eventIdsByMissingSession.keys()) { for(const key of this._eventIdsByMissingSession.keys()) {
const [senderKey, sessionId] = key.split("|"); const {senderKey, sessionId} = decodeMissingSessionKey(key);
await this._requestMissingSessionFromBackup(senderKey, sessionId); await this._requestMissingSessionFromBackup(senderKey, sessionId, null);
} }
} }
@ -95,7 +105,7 @@ export class RoomEncryption {
} else if (source === DecryptionSource.Retry) { } else if (source === DecryptionSource.Retry) {
// when retrying, we could have mixed events from at the bottom of the timeline (sync) // when retrying, we could have mixed events from at the bottom of the timeline (sync)
// and somewhere else, so create a custom cache we use just for this operation. // and somewhere else, so create a custom cache we use just for this operation.
customCache = this._megolmEncryption.createSessionCache(); customCache = this._megolmDecryption.createSessionCache();
sessionCache = customCache; sessionCache = customCache;
} else { } else {
throw new Error("Unknown source: " + source); throw new Error("Unknown source: " + source);
@ -105,13 +115,13 @@ export class RoomEncryption {
if (customCache) { if (customCache) {
customCache.dispose(); customCache.dispose();
} }
return new DecryptionPreparation(preparation, errors, {isTimelineOpen}, this); return new DecryptionPreparation(preparation, errors, {isTimelineOpen, source}, this);
} }
async _processDecryptionResults(results, errors, flags, txn) { async _processDecryptionResults(results, errors, flags, txn) {
for (const error of errors.values()) { for (const error of errors.values()) {
if (error.code === "MEGOLM_NO_SESSION") { if (error.code === "MEGOLM_NO_SESSION") {
this._addMissingSessionEvent(error.event); this._addMissingSessionEvent(error.event, flags.source);
} }
} }
if (flags.isTimelineOpen) { if (flags.isTimelineOpen) {
@ -134,25 +144,34 @@ export class RoomEncryption {
} }
} }
_addMissingSessionEvent(event) { _addMissingSessionEvent(event, source) {
const senderKey = event.content?.["sender_key"]; const senderKey = event.content?.["sender_key"];
const sessionId = event.content?.["session_id"]; const sessionId = event.content?.["session_id"];
const key = `${senderKey}|${sessionId}`; const key = encodeMissingSessionKey(senderKey, sessionId);
let eventIds = this._eventIdsByMissingSession.get(key); let eventIds = this._eventIdsByMissingSession.get(key);
// new missing session // new missing session
if (!eventIds) { if (!eventIds) {
this._requestMissingSessionFromBackup(senderKey, sessionId); this._requestMissingSessionFromBackup(senderKey, sessionId, source);
eventIds = new Set(); eventIds = new Set();
this._eventIdsByMissingSession.set(key, eventIds); this._eventIdsByMissingSession.set(key, eventIds);
} }
eventIds.add(event.event_id); eventIds.add(event.event_id);
} }
async _requestMissingSessionFromBackup(senderKey, sessionId) { async _requestMissingSessionFromBackup(senderKey, sessionId, source) {
if (!this._sessionBackup) { if (!this._sessionBackup) {
this._notifyMissingMegolmSession(); this._notifyMissingMegolmSession();
return; return;
} }
// if the message came from sync, wait 10s to see if the room key arrives,
// and only after that proceed to request from backup
if (source === DecryptionSource.Sync) {
await this._clock.createTimeout(10000).elapsed();
if (this._disposed || !this._eventIdsByMissingSession.has(encodeMissingSessionKey(senderKey, sessionId))) {
return;
}
}
try { try {
const session = await this._sessionBackup.getSession(this._room.id, sessionId); const session = await this._sessionBackup.getSession(this._room.id, sessionId);
if (session?.algorithm === MEGOLM_ALGORITHM) { if (session?.algorithm === MEGOLM_ALGORITHM) {
@ -196,7 +215,7 @@ export class RoomEncryption {
// retry decryption with the new sessions // retry decryption with the new sessions
const retryEventIds = []; const retryEventIds = [];
for (const roomKey of roomKeys) { for (const roomKey of roomKeys) {
const key = `${roomKey.senderKey}|${roomKey.sessionId}`; const key = encodeMissingSessionKey(roomKey.senderKey, roomKey.sessionId);
const entriesForSession = this._eventIdsByMissingSession.get(key); const entriesForSession = this._eventIdsByMissingSession.get(key);
if (entriesForSession) { if (entriesForSession) {
this._eventIdsByMissingSession.delete(key); this._eventIdsByMissingSession.delete(key);