diff --git a/src/crypto/index.js b/src/crypto/index.js index 11b6ff07a..36a8c86d5 100644 --- a/src/crypto/index.js +++ b/src/crypto/index.js @@ -65,6 +65,32 @@ export function isCryptoAvailable() { return Boolean(global.Olm); } +/* subscribes to timeline events for SAS verification */ +function listenForEvents(client, roomId, listener) { + let isEncrypted = false; + if (roomId) { + isEncrypted = client.isRoomEncrypted(roomId); + } + + if (isEncrypted) { + client.on("Event.decrypted", listener); + } else { + client.on("event", listener); + } + let subscribed = true; + return function() { + if (subscribed) { + if (isEncrypted) { + client.off("Event.decrypted", listener); + } else { + client.off("event", listener); + } + subscribed = false; + } + return null; + }; +} + const MIN_FORCE_SESSION_INTERVAL_MS = 60 * 60 * 1000; const KEY_BACKUP_KEYS_PER_REQUEST = 200; @@ -826,7 +852,9 @@ Crypto.prototype.requestVerificationDM = async function(userId, roomId, methods) ); // this handler gets removed when the verification finishes // (see the verify method of crypto/verification/Base.js) - this._baseApis.on("event", verifier.handler); + const subscription = + listenForEvents(this._baseApis, roomId, verifier.handler); + verifier.setEventsSubscription(subscription); resolve(verifier); break; } @@ -836,14 +864,19 @@ Crypto.prototype.requestVerificationDM = async function(userId, roomId, methods) } } }; - this._baseApis.on("event", listener); + let initialResponseSubscription = + listenForEvents(this._baseApis, roomId, listener); const resolve = (...args) => { - this._baseApis.off("event", listener); + if (initialResponseSubscription) { + initialResponseSubscription = initialResponseSubscription(); + } _resolve(...args); }; const reject = (...args) => { - this._baseApis.off("event", listener); + if (initialResponseSubscription) { + initialResponseSubscription = initialResponseSubscription(); + } _reject(...args); }; }); @@ -878,7 +911,9 @@ Crypto.prototype.acceptVerificationDM = function(event, Method) { verifier.handler = verificationEventHandler( verifier, event.getSender(), event.getRoomId(), event.getId(), ); - this._baseApis.on("event", verifier.handler); + const subscription = listenForEvents( + this._baseApis, event.getRoomId(), verifier.handler); + verifier.setEventsSubscription(subscription); return verifier; }; diff --git a/src/crypto/verification/Base.js b/src/crypto/verification/Base.js index fa67c72a0..d9404ba63 100644 --- a/src/crypto/verification/Base.js +++ b/src/crypto/verification/Base.js @@ -74,6 +74,7 @@ export default class VerificationBase extends EventEmitter { this._done = false; this._promise = null; this._transactionTimeoutTimer = null; + this._eventsSubscription = null; // At this point, the verification request was received so start the timeout timer. this._resetTimer(); @@ -222,6 +223,10 @@ export default class VerificationBase extends EventEmitter { // but no reject function. If cancel is called again, we'd error. if (this._reject) this._reject(e); } else { + // unsubscribe from events, this happens in _reject usually but we don't have one here + if (this._eventsSubscription) { + this._eventsSubscription = this._eventsSubscription(); + } // FIXME: this causes an "Uncaught promise" console message // if nothing ends up chaining this promise. this._promise = Promise.reject(e); @@ -246,7 +251,10 @@ export default class VerificationBase extends EventEmitter { this._done = true; this._endTimer(); if (this.handler) { - this._baseApis.off("event", this.handler); + // these listeners are attached in Crypto.acceptVerificationDM + if (this._eventsSubscription) { + this._eventsSubscription = this._eventsSubscription(); + } } resolve(...args); }; @@ -254,7 +262,10 @@ export default class VerificationBase extends EventEmitter { this._done = true; this._endTimer(); if (this.handler) { - this._baseApis.off("event", this.handler); + // these listeners are attached in Crypto.acceptVerificationDM + if (this._eventsSubscription) { + this._eventsSubscription = this._eventsSubscription(); + } } reject(...args); }; @@ -295,4 +306,8 @@ export default class VerificationBase extends EventEmitter { await this._baseApis.setDeviceVerified(userId, deviceId); } } + + setEventsSubscription(subscription) { + this._eventsSubscription = subscription; + } }