From b60e5f40ab89dd3ff62069200223ea7ac64ac25d Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Wed, 13 Jan 2021 12:54:36 +0000 Subject: [PATCH 01/13] Prepare changelog for v9.5.0-rc.1 --- CHANGELOG.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01b3978cc..f53e8c85c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,32 @@ +Changes in [9.5.0-rc.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v9.5.0-rc.1) (2021-01-13) +========================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v9.4.1...v9.5.0-rc.1) + + * Don't log if no WebRTC + [\#1574](https://github.com/matrix-org/matrix-js-sdk/pull/1574) + * Add _unstable_getSharedRooms + [\#1417](https://github.com/matrix-org/matrix-js-sdk/pull/1417) + * Bump node-notifier from 8.0.0 to 8.0.1 + [\#1568](https://github.com/matrix-org/matrix-js-sdk/pull/1568) + * Ignore party ID if opponent is v0 + [\#1567](https://github.com/matrix-org/matrix-js-sdk/pull/1567) + * Basic call transfer initiation support + [\#1566](https://github.com/matrix-org/matrix-js-sdk/pull/1566) + * Room version 6 is now a thing + [\#1572](https://github.com/matrix-org/matrix-js-sdk/pull/1572) + * Store keys with same index but better trust level + [\#1571](https://github.com/matrix-org/matrix-js-sdk/pull/1571) + * Use TypeScript source for development, swap to build during release + [\#1561](https://github.com/matrix-org/matrix-js-sdk/pull/1561) + * Revert "Ignore party ID if opponent is v0" + [\#1565](https://github.com/matrix-org/matrix-js-sdk/pull/1565) + * Basic call transfer initiation support + [\#1558](https://github.com/matrix-org/matrix-js-sdk/pull/1558) + * Ignore party ID if opponent is v0 + [\#1559](https://github.com/matrix-org/matrix-js-sdk/pull/1559) + * Honour a call reject event from another of our own devices + [\#1562](https://github.com/matrix-org/matrix-js-sdk/pull/1562) + Changes in [9.4.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v9.4.1) (2020-12-21) ================================================================================================ [Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v9.4.0...v9.4.1) From 50ee489079930fe3e091a929ea6c61b5fd0b28dd Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Wed, 13 Jan 2021 12:54:37 +0000 Subject: [PATCH 02/13] v9.5.0-rc.1 --- package.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 62f2bba62..96c7993e5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-js-sdk", - "version": "9.4.1", + "version": "9.5.0-rc.1", "description": "Matrix Client-Server SDK for Javascript", "scripts": { "prepublishOnly": "yarn build", @@ -27,7 +27,7 @@ "keywords": [ "matrix-org" ], - "main": "./src/index.ts", + "main": "./lib/index.js", "browser": "./lib/browser-index.js", "matrix_src_main": "./src/index.ts", "matrix_src_browser": "./src/browser-index.js", @@ -95,5 +95,6 @@ }, "jest": { "testEnvironment": "node" - } + }, + "typings": "./lib/index.d.ts" } From 159b98132dd2f09b6fdb625ffab9ac447f8a952b Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Thu, 14 Jan 2021 17:49:15 +0000 Subject: [PATCH 03/13] Stop retrying TURN access when forbidden If we're not allowed to have TURN access, there's no reason to ask in a loop. --- src/client.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/client.js b/src/client.js index acf33e64c..5395cc14d 100644 --- a/src/client.js +++ b/src/client.js @@ -5425,6 +5425,11 @@ function checkTurnServers(client) { } }, function(err) { logger.error("Failed to get TURN URIs"); + // If we get a 403, there's no point in looping forever. + if (err.httpStatus === 403) { + logger.info("TURN access unavailable for this account"); + return; + } client._checkTurnServersTimeoutID = setTimeout(function() { checkTurnServers(client); }, 60000); From 458384d65887a6c2e02c82258c8d720dd11dd88a Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Thu, 14 Jan 2021 19:55:02 -0500 Subject: [PATCH 04/13] queue keys for backup even if backup isn't enabled yet We may not have managed to set up the backup yet when we get keys. So we should unconditionally queue up the keys for backup, so that when the backup is set up, they will be sent instead of dropped. --- src/crypto/algorithms/megolm.js | 36 +++++++++++---------------------- src/crypto/index.js | 14 ++++++------- 2 files changed, 19 insertions(+), 31 deletions(-) diff --git a/src/crypto/algorithms/megolm.js b/src/crypto/algorithms/megolm.js index 006a11010..f8ce23a3f 100644 --- a/src/crypto/algorithms/megolm.js +++ b/src/crypto/algorithms/megolm.js @@ -369,17 +369,11 @@ MegolmEncryption.prototype._prepareNewSession = async function() { key.key, {ed25519: this._olmDevice.deviceEd25519Key}, ); - if (this._crypto.backupInfo) { - // don't wait for it to complete - this._crypto.backupGroupSession( - this._roomId, this._olmDevice.deviceCurve25519Key, [], - sessionId, key.key, - ).catch((e) => { - // This throws if the upload failed, but this is fine - // since it will have written it to the db and will retry. - logger.log("Failed to back up megolm session", e); - }); - } + // don't wait for it to complete + this._crypto.backupGroupSession( + this._roomId, this._olmDevice.deviceCurve25519Key, [], + sessionId, key.key, + ); return new OutboundSessionInfo(sessionId); }; @@ -1347,18 +1341,12 @@ MegolmDecryption.prototype.onRoomKeyEvent = function(event) { } }); }).then(() => { - if (this._crypto.backupInfo) { - // don't wait for the keys to be backed up for the server - this._crypto.backupGroupSession( - content.room_id, senderKey, forwardingKeyChain, - content.session_id, content.session_key, keysClaimed, - exportFormat, - ).catch((e) => { - // This throws if the upload failed, but this is fine - // since it will have written it to the db and will retry. - logger.log("Failed to back up megolm session", e); - }); - } + // don't wait for the keys to be backed up for the server + this._crypto.backupGroupSession( + content.room_id, senderKey, forwardingKeyChain, + content.session_id, content.session_key, keysClaimed, + exportFormat, + ); }).catch((e) => { logger.error(`Error handling m.room_key_event: ${e}`); }); @@ -1564,7 +1552,7 @@ MegolmDecryption.prototype.importRoomKey = function(session, opts = {}) { true, opts.untrusted ? { untrusted: opts.untrusted } : {}, ).then(() => { - if (this._crypto.backupInfo && opts.source !== "backup") { + if (opts.source !== "backup") { // don't wait for it to complete this._crypto.backupGroupSession( session.room_id, diff --git a/src/crypto/index.js b/src/crypto/index.js index 332ff7019..9b4a5bd6e 100644 --- a/src/crypto/index.js +++ b/src/crypto/index.js @@ -2884,18 +2884,18 @@ Crypto.prototype.backupGroupSession = async function( sessionId, sessionKey, keysClaimed, exportFormat, ) { - if (!this.backupInfo) { - throw new Error("Key backups are not enabled"); - } - await this._cryptoStore.markSessionsNeedingBackup([{ senderKey: senderKey, sessionId: sessionId, }]); - // don't wait for this to complete: it will delay so - // happens in the background - this.scheduleKeyBackupSend(); + if (this.backupInfo) { + // don't wait for this to complete: it will delay so + // happens in the background + this.scheduleKeyBackupSend(); + } + // if this.backupInfo is not set, then the keys will be backed up when + // client.enableKeyBackup is called }; /** From f6e8048d9e2ffe1942a4c41b3ba20a2dfbcff0b0 Mon Sep 17 00:00:00 2001 From: tzyl Date: Mon, 18 Jan 2021 10:17:46 +0000 Subject: [PATCH 05/13] Expose getPresence endpoint --- spec/unit/matrix-client.spec.js | 15 +++++++++++++++ src/client.js | 13 +++++++++++++ 2 files changed, 28 insertions(+) diff --git a/spec/unit/matrix-client.spec.js b/spec/unit/matrix-client.spec.js index fc4a4dc56..3811c5b56 100644 --- a/spec/unit/matrix-client.spec.js +++ b/spec/unit/matrix-client.spec.js @@ -521,4 +521,19 @@ describe("MatrixClient", function() { xit("should be able to peek into a room using peekInRoom", function(done) { }); }); + + describe("getPresence", function() { + it("should send a presence HTTP GET", function() { + httpLookups = [{ + method: "GET", + path: `/presence/${encodeURIComponent(userId)}/status`, + data: { + "presence": "unavailable", + "last_active_ago": 420845, + }, + }]; + client.getPresence(userId); + expect(httpLookups.length).toEqual(0); + }); + }); }); diff --git a/src/client.js b/src/client.js index 5395cc14d..343b3f2b3 100644 --- a/src/client.js +++ b/src/client.js @@ -3841,6 +3841,19 @@ MatrixClient.prototype.setPresence = function(opts, callback) { ); }; +/** + * @param {string} userId The user to get presence for + * @param {module:client.callback} callback Optional. + * @return {Promise} Resolves: The presence state for this user. + * @return {module:http-api.MatrixError} Rejects: with an error response. + */ +MatrixClient.prototype.getPresence = function(userId, callback) { + const path = utils.encodeUri("/presence/$userId/status", { + $userId: userId, + }); + + return this._http.authedRequest(callback, "GET", path, undefined, undefined); +}; /** * Retrieve older messages from the given room and put them in the timeline. From 59043781705fd45964449c8f58f2706e3297afdb Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Mon, 18 Jan 2021 15:03:59 +0000 Subject: [PATCH 06/13] Prepare changelog for v9.5.0 --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f53e8c85c..10568af89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +Changes in [9.5.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v9.5.0) (2021-01-18) +================================================================================================ +[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v9.5.0-rc.1...v9.5.0) + + * No changes since rc.1 + Changes in [9.5.0-rc.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v9.5.0-rc.1) (2021-01-13) ========================================================================================================== [Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v9.4.1...v9.5.0-rc.1) From 45f3a2f909a40a5ba0cfc503b33e58ee750caae4 Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Mon, 18 Jan 2021 15:04:00 +0000 Subject: [PATCH 07/13] v9.5.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 96c7993e5..f0bdafd68 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-js-sdk", - "version": "9.5.0-rc.1", + "version": "9.5.0", "description": "Matrix Client-Server SDK for Javascript", "scripts": { "prepublishOnly": "yarn build", From 214a9df3823e602400b24d9a81cfc7b7df0a863b Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Mon, 18 Jan 2021 15:06:36 +0000 Subject: [PATCH 08/13] Resetting package fields for development --- package.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index f0bdafd68..96871616b 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "keywords": [ "matrix-org" ], - "main": "./lib/index.js", + "main": "./src/index.ts", "browser": "./lib/browser-index.js", "matrix_src_main": "./src/index.ts", "matrix_src_browser": "./src/browser-index.js", @@ -95,6 +95,5 @@ }, "jest": { "testEnvironment": "node" - }, - "typings": "./lib/index.d.ts" + } } From d23bbaeb065404bbfde373a5763b1d09e48c45a0 Mon Sep 17 00:00:00 2001 From: David Baker Date: Tue, 19 Jan 2021 12:25:36 +0000 Subject: [PATCH 09/13] Fix extra negotiate message in Firefox Hopefully explained by the comments: Firefox sees that it's been put on hold and tries to negotiate itself off hold again. Fixes https://github.com/vector-im/element-web/issues/16190 --- src/webrtc/call.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/webrtc/call.ts b/src/webrtc/call.ts index c69ab2e4c..8cbfa582e 100644 --- a/src/webrtc/call.ts +++ b/src/webrtc/call.ts @@ -1069,8 +1069,21 @@ export class MatrixCall extends EventEmitter { await this.peerConn.setRemoteDescription(description); if (description.type === 'offer') { + // First we sent the direction of the tranciever to what we'd like it to be, + // irresepective of whether the other side has us on hold - so just whether we + // want the call to be on hold or not. This is necessary because in a few lines, + // we'll adjust the direction and unless we do this too, we'll never come off hold. + for (const tranceiver of this.peerConn.getTransceivers()) { + tranceiver.direction = this.isRemoteOnHold() ? 'inactive' : 'sendrecv'; + } const localDescription = await this.peerConn.createAnswer(); await this.peerConn.setLocalDescription(localDescription); + // Now we've got our answer, set the direction to the outcome of the negotiation. + // We need to do this otherwise Firefox will notice that the direction is not the + // currentDirection and try to negotiate itself off hold again. + for (const tranceiver of this.peerConn.getTransceivers()) { + tranceiver.direction = tranceiver.currentDirection; + } this.sendVoipEvent(EventType.CallNegotiate, { description: this.peerConn.localDescription, From 9f275d57a9c11d40e10d9601cbd0ee1290da79c0 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Tue, 19 Jan 2021 15:28:28 +0000 Subject: [PATCH 10/13] Add debug logs to encryption prep This extra debug logs may help isolate the cause of https://github.com/vector-im/element-web/issues/16194. These changes also fix a related (but most likely different) failure mode: if a failure occurred in the `encryptionPreparation` async task, we would skip trying to prepare in all future attempts for that room. This change ensures prep failures are logged and we resume prep attempts on the next call from the application. --- src/crypto/algorithms/megolm.js | 48 ++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/src/crypto/algorithms/megolm.js b/src/crypto/algorithms/megolm.js index f8ce23a3f..d295c054a 100644 --- a/src/crypto/algorithms/megolm.js +++ b/src/crypto/algorithms/megolm.js @@ -264,11 +264,14 @@ MegolmEncryption.prototype._ensureOutboundSession = async function( await Promise.all([ (async () => { // share keys with devices that we already have a session for + logger.debug(`Sharing keys with existing Olm sessions in ${this._roomId}`); await this._shareKeyWithOlmSessions( session, key, payload, olmSessions, ); + logger.debug(`Shared keys with existing Olm sessions in ${this._roomId}`); })(), (async () => { + logger.debug(`Sharing keys with new Olm sessions in ${this._roomId}`); const errorDevices = []; // meanwhile, establish olm sessions for devices that we don't @@ -319,8 +322,10 @@ MegolmEncryption.prototype._ensureOutboundSession = async function( } else { await this._notifyFailedOlmDevices(session, key, errorDevices); } + logger.debug(`Shared keys with new Olm sessions in ${this._roomId}`); })(), (async () => { + logger.debug(`Notifying blocked devices in ${this._roomId}`); // also, notify blocked devices that they're blocked const blockedMap = {}; for (const [userId, userBlockedDevices] of Object.entries(blocked)) { @@ -336,6 +341,7 @@ MegolmEncryption.prototype._ensureOutboundSession = async function( } await this._notifyBlockedDevices(session, blockedMap); + logger.debug(`Notified blocked devices in ${this._roomId}`); })(), ]); }; @@ -348,6 +354,11 @@ MegolmEncryption.prototype._ensureOutboundSession = async function( // first wait for the previous share to complete const prom = this._setupPromise.then(prepareSession); + // Ensure any failures are logged for debugging + prom.catch(e => { + logger.error(`Failed to ensure outbound session in ${this._roomId}`, e); + }); + // _setupPromise resolves to `session` whether or not the share succeeds this._setupPromise = prom.then(returnSession, returnSession); @@ -840,24 +851,41 @@ MegolmEncryption.prototype.prepareToEncrypt = function(room) { // We're already preparing something, so don't do anything else. // FIXME: check if we need to restart // (https://github.com/matrix-org/matrix-js-sdk/issues/1255) + const elapsedTime = Date.now() - this.encryptionPreparationMetadata.startTime + logger.debug( + `Already started preparing to encrypt for ${this._roomId} ` + + `${elapsedTime} ms ago, skipping`, + ); return; } logger.debug(`Preparing to encrypt events for ${this._roomId}`); + this.encryptionPreparationMetadata = { + startTime: Date.now(), + }; this.encryptionPreparation = (async () => { - const [devicesInRoom, blocked] = await this._getDevicesInRoom(room); + try { + logger.debug(`Getting devices in ${this._roomId}`); + const [devicesInRoom, blocked] = await this._getDevicesInRoom(room); - if (this._crypto.getGlobalErrorOnUnknownDevices()) { - // Drop unknown devices for now. When the message gets sent, we'll - // throw an error, but we'll still be prepared to send to the known - // devices. - this._removeUnknownDevices(devicesInRoom); + if (this._crypto.getGlobalErrorOnUnknownDevices()) { + // Drop unknown devices for now. When the message gets sent, we'll + // throw an error, but we'll still be prepared to send to the known + // devices. + this._removeUnknownDevices(devicesInRoom); + } + + logger.debug(`Ensuring outbound session in ${this._roomId}`); + await this._ensureOutboundSession(devicesInRoom, blocked, true); + + logger.debug(`Ready to encrypt events for ${this._roomId}`); + } catch (e) { + logger.error(`Failed to prepare to encrypt events for ${this._roomId}`, e); + } finally { + delete this.encryptionPreparationMetadata; + delete this.encryptionPreparation; } - - await this._ensureOutboundSession(devicesInRoom, blocked, true); - - delete this.encryptionPreparation; })(); }; From 4a073a7ba526c3cdbb9bda95f6ff4e50f63ed045 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Tue, 19 Jan 2021 15:36:08 +0000 Subject: [PATCH 11/13] Fix lint --- src/crypto/algorithms/megolm.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crypto/algorithms/megolm.js b/src/crypto/algorithms/megolm.js index d295c054a..d2e4e86fb 100644 --- a/src/crypto/algorithms/megolm.js +++ b/src/crypto/algorithms/megolm.js @@ -851,7 +851,7 @@ MegolmEncryption.prototype.prepareToEncrypt = function(room) { // We're already preparing something, so don't do anything else. // FIXME: check if we need to restart // (https://github.com/matrix-org/matrix-js-sdk/issues/1255) - const elapsedTime = Date.now() - this.encryptionPreparationMetadata.startTime + const elapsedTime = Date.now() - this.encryptionPreparationMetadata.startTime; logger.debug( `Already started preparing to encrypt for ${this._roomId} ` + `${elapsedTime} ms ago, skipping`, From c289effba02ec7dc355d91a179c8d15cb3855588 Mon Sep 17 00:00:00 2001 From: David Baker Date: Tue, 19 Jan 2021 18:11:41 +0000 Subject: [PATCH 12/13] Log the call ID when logging that we've received VoIP events Should make the logs a bit clearer --- src/webrtc/call.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/webrtc/call.ts b/src/webrtc/call.ts index 70f6c241b..b4ab781bc 100644 --- a/src/webrtc/call.ts +++ b/src/webrtc/call.ts @@ -1360,7 +1360,7 @@ export class MatrixCall extends EventEmitter { } onHangupReceived = (msg) => { - logger.debug("Hangup received"); + logger.debug("Hangup received for call ID " + + this.callId); // party ID must match (our chosen partner hanging up the call) or be undefined (we haven't chosen // a partner yet but we're treating the hangup as a reject as per VoIP v0) @@ -1373,7 +1373,7 @@ export class MatrixCall extends EventEmitter { }; onRejectReceived = (msg) => { - logger.debug("Reject received"); + logger.debug("Reject received for call ID " + this.callId); // No need to check party_id for reject because if we'd received either // an answer or reject, we wouldn't be in state InviteSent @@ -1395,7 +1395,7 @@ export class MatrixCall extends EventEmitter { }; onAnsweredElsewhere = (msg) => { - logger.debug("Answered elsewhere"); + logger.debug("Call ID " + this.callId + " answered elsewhere"); this.terminate(CallParty.Remote, CallErrorCode.AnsweredElsewhere, true); }; From 4820cf8cac87824e9ed0bca773433a2c107ee81f Mon Sep 17 00:00:00 2001 From: David Baker Date: Tue, 19 Jan 2021 19:28:08 +0000 Subject: [PATCH 13/13] Log call ID here too --- src/webrtc/call.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/webrtc/call.ts b/src/webrtc/call.ts index b4ab781bc..5cc1c5c45 100644 --- a/src/webrtc/call.ts +++ b/src/webrtc/call.ts @@ -1242,7 +1242,7 @@ export class MatrixCall extends EventEmitter { return; // because ICE can still complete as we're ending the call } logger.debug( - "ICE connection state changed to: " + this.peerConn.iceConnectionState, + "Call ID " + this.callId + ": ICE connection state changed to: " + this.peerConn.iceConnectionState, ); // ideally we'd consider the call to be connected when we get media but // chrome doesn't implement any of the 'onstarted' events yet