Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Room header & message box shields now reflect cross-signing state #3850

Merged
merged 7 commits into from
Jan 17, 2020
58 changes: 48 additions & 10 deletions src/components/structures/RoomView.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ export default 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);
Expand Down Expand Up @@ -492,6 +493,7 @@ export default 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);
Expand Down Expand Up @@ -762,6 +764,14 @@ export default 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)) {
Expand All @@ -785,29 +795,57 @@ export default 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;
}
foldleft marked this conversation as resolved.
Show resolved Hide resolved

/*
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",
foldleft marked this conversation as resolved.
Show resolved Hide resolved
});
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.
foldleft marked this conversation as resolved.
Show resolved Hide resolved
*/
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();
foldleft marked this conversation as resolved.
Show resolved Hide resolved
});
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",
});
},

Expand Down