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)
}
},
clock: this._clock
});
}

View file

@ -21,8 +21,17 @@ import {makeTxnId} from "../common.js";
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 {
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._deviceTracker = deviceTracker;
this._olmEncryption = olmEncryption;
@ -39,6 +48,7 @@ export class RoomEncryption {
this._storage = storage;
this._sessionBackup = sessionBackup;
this._notifyMissingMegolmSession = notifyMissingMegolmSession;
this._clock = clock;
this._disposed = false;
}
@ -48,8 +58,8 @@ export class RoomEncryption {
}
this._sessionBackup = sessionBackup;
for(const key of this._eventIdsByMissingSession.keys()) {
const [senderKey, sessionId] = key.split("|");
await this._requestMissingSessionFromBackup(senderKey, sessionId);
const {senderKey, sessionId} = decodeMissingSessionKey(key);
await this._requestMissingSessionFromBackup(senderKey, sessionId, null);
}
}
@ -95,7 +105,7 @@ export class RoomEncryption {
} else if (source === DecryptionSource.Retry) {
// 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.
customCache = this._megolmEncryption.createSessionCache();
customCache = this._megolmDecryption.createSessionCache();
sessionCache = customCache;
} else {
throw new Error("Unknown source: " + source);
@ -105,13 +115,13 @@ export class RoomEncryption {
if (customCache) {
customCache.dispose();
}
return new DecryptionPreparation(preparation, errors, {isTimelineOpen}, this);
return new DecryptionPreparation(preparation, errors, {isTimelineOpen, source}, this);
}
async _processDecryptionResults(results, errors, flags, txn) {
for (const error of errors.values()) {
if (error.code === "MEGOLM_NO_SESSION") {
this._addMissingSessionEvent(error.event);
this._addMissingSessionEvent(error.event, flags.source);
}
}
if (flags.isTimelineOpen) {
@ -134,25 +144,34 @@ export class RoomEncryption {
}
}
_addMissingSessionEvent(event) {
_addMissingSessionEvent(event, source) {
const senderKey = event.content?.["sender_key"];
const sessionId = event.content?.["session_id"];
const key = `${senderKey}|${sessionId}`;
const key = encodeMissingSessionKey(senderKey, sessionId);
let eventIds = this._eventIdsByMissingSession.get(key);
// new missing session
if (!eventIds) {
this._requestMissingSessionFromBackup(senderKey, sessionId);
this._requestMissingSessionFromBackup(senderKey, sessionId, source);
eventIds = new Set();
this._eventIdsByMissingSession.set(key, eventIds);
}
eventIds.add(event.event_id);
}
async _requestMissingSessionFromBackup(senderKey, sessionId) {
async _requestMissingSessionFromBackup(senderKey, sessionId, source) {
if (!this._sessionBackup) {
this._notifyMissingMegolmSession();
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 {
const session = await this._sessionBackup.getSession(this._room.id, sessionId);
if (session?.algorithm === MEGOLM_ALGORITHM) {
@ -196,7 +215,7 @@ export class RoomEncryption {
// retry decryption with the new sessions
const retryEventIds = [];
for (const roomKey of roomKeys) {
const key = `${roomKey.senderKey}|${roomKey.sessionId}`;
const key = encodeMissingSessionKey(roomKey.senderKey, roomKey.sessionId);
const entriesForSession = this._eventIdsByMissingSession.get(key);
if (entriesForSession) {
this._eventIdsByMissingSession.delete(key);