From ff05041a5a240410460ce3176fd07351679dccb6 Mon Sep 17 00:00:00 2001 From: Zoe Date: Wed, 15 Jan 2020 13:57:29 +0000 Subject: [PATCH] Update room shield icons to represent encrypted but unverified chats in less alarmed tones --- src/components/structures/RoomView.js | 58 ++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 10 deletions(-) diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index a717f485f0..3adcd22d87 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -172,6 +172,7 @@ module.exports = createReactClass({ MatrixClientPeg.get().on("accountData", this.onAccountData); MatrixClientPeg.get().on("crypto.keyBackupStatus", this.onKeyBackupStatus); MatrixClientPeg.get().on("deviceVerificationChanged", this.onDeviceVerificationChanged); + MatrixClientPeg.get().on("userTrustStatusChanged", this.onUserVerificationChanged); // Start listening for RoomViewStore updates this._roomStoreToken = RoomViewStore.addListener(this._onRoomViewStoreUpdate); this._onRoomViewStoreUpdate(true); @@ -491,6 +492,7 @@ module.exports = createReactClass({ MatrixClientPeg.get().removeListener("accountData", this.onAccountData); MatrixClientPeg.get().removeListener("crypto.keyBackupStatus", this.onKeyBackupStatus); MatrixClientPeg.get().removeListener("deviceVerificationChanged", this.onDeviceVerificationChanged); + MatrixClientPeg.get().removeListener("userTrustStatusChanged", this.onUserVerificationChanged); } window.removeEventListener('beforeunload', this.onPageUnload); @@ -761,6 +763,14 @@ module.exports = createReactClass({ this._updateE2EStatus(room); }, + onUserVerificationChanged: function(userId, _trustStatus) { + const room = this.state.room; + if (!room.currentState.getMember(userId)) { + return; + } + this._updateE2EStatus(room); + }, + _updateE2EStatus: async function(room) { const cli = MatrixClientPeg.get(); if (!cli.isRoomEncrypted(room.roomId)) { @@ -784,29 +794,57 @@ module.exports = createReactClass({ return; } const e2eMembers = await room.getEncryptionTargetMembers(); + + /* + Ensure we trust our own signing key, ie, nobody's used our credentials to + replace it and sign all our devices + */ + if (!cli.checkUserTrust(cli.getUserId())) { + this.setState({ + e2eStatus: "warning", + }); + debuglog("e2e status set to warning due to not trusting our own signing key"); + return; + } + + /* + Gather verification state of every user in the room. + If _any_ user is verified then _every_ user must be verified, or we'll bail. + Note we don't count our own user so that the all/any check behaves properly. + */ + const verificationState = e2eMembers.map(({userId}) => userId) + .filter((userId) => userId !== cli.getUserId()) + .map((userId) => cli.checkUserTrust(userId).isCrossSigningVerified()); + if (verificationState.includes(true) && verificationState.includes(false)) { + this.setState({ + e2eStatus: "warning", + }); + debuglog("e2e status set to warning as some, but not all, users are verified"); + return; + } + + /* + Whether we verify or not, a user having an untrusted device requires warnings. + Check every user's devices, including ourselves. + */ for (const member of e2eMembers) { const { userId } = member; - const userVerified = cli.checkUserTrust(userId).isCrossSigningVerified(); - if (!userVerified) { - this.setState({ - e2eStatus: "warning", - }); - return; - } const devices = await cli.getStoredDevicesForUser(userId); - const allDevicesVerified = devices.every(device => { - const { deviceId } = device; + const allDevicesVerified = devices.every(({deviceId}) => { return cli.checkDeviceTrust(userId, deviceId).isCrossSigningVerified(); }); if (!allDevicesVerified) { this.setState({ e2eStatus: "warning", }); + debuglog("e2e status set to warning as not all users trust all of their devices." + + " Aborted on user", userId); return; } } + this.setState({ - e2eStatus: "verified", + e2eStatus: verificationState.includes(true) ? "verified" : "normal", }); },