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

Verify users when cross-signing enabled #3728

Merged
merged 2 commits into from
Dec 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions res/css/views/rooms/_E2EIcon.scss
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ limitations under the License.
display: block;
}

.mx_E2EIcon_verified::after, .mx_E2EIcon_warning::after {
.mx_E2EIcon_warning::after,
.mx_E2EIcon_normal::after,
.mx_E2EIcon_verified::after {
content: "";
display: block;
position: absolute;
Expand All @@ -34,10 +36,14 @@ limitations under the License.
background-size: contain;
}

.mx_E2EIcon_verified::after {
background-image: url('$(res)/img/e2e/verified.svg');
}

.mx_E2EIcon_warning::after {
background-image: url('$(res)/img/e2e/warning.svg');
}

.mx_E2EIcon_normal::after {
background-image: url('$(res)/img/e2e/normal.svg');
}

.mx_E2EIcon_verified::after {
background-image: url('$(res)/img/e2e/verified.svg');
}
2 changes: 1 addition & 1 deletion src/components/structures/MatrixChat.js
Original file line number Diff line number Diff line change
Expand Up @@ -1492,7 +1492,7 @@ export default createReactClass({
const IncomingSasDialog = sdk.getComponent("views.dialogs.IncomingSasDialog");
Modal.createTrackedDialog('Incoming Verification', '', IncomingSasDialog, {
verifier,
});
}, null, /* priority = */ false, /* static = */ true);
});
}
// Fire the tinter right on startup to ensure the default theme is applied
Expand Down
41 changes: 35 additions & 6 deletions src/components/structures/RoomView.js
Original file line number Diff line number Diff line change
Expand Up @@ -792,11 +792,12 @@ module.exports = createReactClass({
this._updateE2EStatus(room);
},

_updateE2EStatus: function(room) {
if (!MatrixClientPeg.get().isRoomEncrypted(room.roomId)) {
_updateE2EStatus: async function(room) {
const cli = MatrixClientPeg.get();
if (!cli.isRoomEncrypted(room.roomId)) {
return;
}
if (!MatrixClientPeg.get().isCryptoEnabled()) {
if (!cli.isCryptoEnabled()) {
// If crypto is not currently enabled, we aren't tracking devices at all,
// so we don't know what the answer is. Let's error on the safe side and show
// a warning for this case.
Expand All @@ -805,10 +806,38 @@ module.exports = createReactClass({
});
return;
}
room.hasUnverifiedDevices().then((hasUnverifiedDevices) => {
this.setState({
e2eStatus: hasUnverifiedDevices ? "warning" : "verified",
if (!SettingsStore.isFeatureEnabled("feature_cross_signing")) {
room.hasUnverifiedDevices().then((hasUnverifiedDevices) => {
this.setState({
e2eStatus: hasUnverifiedDevices ? "warning" : "verified",
});
});
return;
}
const e2eMembers = await room.getEncryptionTargetMembers();
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;
return cli.checkDeviceTrust(userId, deviceId).isCrossSigningVerified();
});
if (!allDevicesVerified) {
this.setState({
e2eStatus: "warning",
});
return;
}
}
this.setState({
e2eStatus: "verified",
});
},

Expand Down
2 changes: 1 addition & 1 deletion src/components/views/dialogs/KeyShareDialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export default createReactClass({
this.props.onFinished(true);
}
},
});
}, null, /* priority = */ false, /* static = */ true);
},

_onShareClicked: function() {
Expand Down
2 changes: 1 addition & 1 deletion src/components/views/elements/DeviceVerifyButtons.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export default createReactClass({
Modal.createTrackedDialog('Device Verify Dialog', '', DeviceVerifyDialog, {
userId: this.props.userId,
device: this.state.device,
});
}, null, /* priority = */ false, /* static = */ true);
},

onUnverifyClick: function() {
Expand Down
2 changes: 1 addition & 1 deletion src/components/views/messages/MKeyVerificationRequest.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export default class MKeyVerificationRequest extends React.Component {
const verifier = MatrixClientPeg.get().acceptVerificationDM(this.props.mxEvent, verificationMethods.SAS);
Modal.createTrackedDialog('Incoming Verification', '', IncomingSasDialog, {
verifier,
});
}, null, /* priority = */ false, /* static = */ true);
};

_onRejectClicked = () => {
Expand Down
22 changes: 17 additions & 5 deletions src/components/views/right_panel/UserInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,20 @@ const _disambiguateDevices = (devices) => {
}
};

const _getE2EStatus = (devices) => {
const hasUnverifiedDevice = devices.some((device) => device.isUnverified());
return hasUnverifiedDevice ? "warning" : "verified";
const _getE2EStatus = (cli, userId, devices) => {
if (!SettingsStore.isFeatureEnabled("feature_cross_signing")) {
const hasUnverifiedDevice = devices.some((device) => device.isUnverified());
return hasUnverifiedDevice ? "warning" : "verified";
}
const userVerified = cli.checkUserTrust(userId).isCrossSigningVerified();
const allDevicesVerified = devices.every(device => {
const { deviceId } = device;
return cli.checkDeviceTrust(userId, deviceId).isCrossSigningVerified();
});
if (allDevicesVerified) {
return userVerified ? "verified" : "normal";
}
return "warning";
};

async function unverifyUser(matrixClient, userId) {
Expand Down Expand Up @@ -114,7 +125,7 @@ function verifyDevice(userId, device) {
Modal.createTrackedDialog('Device Verify Dialog', '', DeviceVerifyDialog, {
userId: userId,
device: device,
});
}, null, /* priority = */ false, /* static = */ true);
}

function DeviceItem({userId, device}) {
Expand Down Expand Up @@ -1264,7 +1275,8 @@ const UserInfo = withLegacyMatrixClient(({matrixClient: cli, user, groupId, room

let e2eIcon;
if (isRoomEncrypted && devices) {
e2eIcon = <E2EIcon size={18} status={_getE2EStatus(devices)} isUser={true} />;
const e2eStatus = _getE2EStatus(cli, user.userId, devices);
e2eIcon = <E2EIcon size={18} status={e2eStatus} isUser={true} />;
}

return (
Expand Down
54 changes: 46 additions & 8 deletions src/components/views/rooms/E2EIcon.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,62 @@ limitations under the License.
import classNames from 'classnames';
import { _t } from '../../../languageHandler';
import AccessibleButton from '../elements/AccessibleButton';
import SettingsStore from '../../../settings/SettingsStore';

export default function(props) {
const { isUser } = props;
const isNormal = props.status === "normal";
const isWarning = props.status === "warning";
const isVerified = props.status === "verified";
const e2eIconClasses = classNames({
mx_E2EIcon: true,
mx_E2EIcon_warning: isWarning,
mx_E2EIcon_normal: isNormal,
mx_E2EIcon_verified: isVerified,
}, props.className);
let e2eTitle;
if (isWarning) {
e2eTitle = props.isUser ?
_t("Some devices for this user are not trusted") :
_t("Some devices in this encrypted room are not trusted");
} else if (isVerified) {
e2eTitle = props.isUser ?
_t("All devices for this user are trusted") :
_t("All devices in this encrypted room are trusted");

const crossSigning = SettingsStore.isFeatureEnabled("feature_cross_signing");
if (crossSigning && isUser) {
if (isWarning) {
e2eTitle = _t(
"This user has not verified all of their devices.",
);
} else if (isNormal) {
e2eTitle = _t(
"You have not verified this user. " +
"This user has verified all of their devices.",
);
} else if (isVerified) {
e2eTitle = _t(
"You have verified this user. " +
"This user has verified all of their devices.",
);
}
} else if (crossSigning && !isUser) {
if (isWarning) {
e2eTitle = _t(
"Some users in this encrypted room are not verified by you or " +
"they have not verified their own devices.",
);
} else if (isVerified) {
e2eTitle = _t(
"All users in this encrypted room are verified by you and " +
"they have verified their own devices.",
);
}
} else if (!crossSigning && isUser) {
if (isWarning) {
e2eTitle = _t("Some devices for this user are not trusted");
} else if (isVerified) {
e2eTitle = _t("All devices for this user are trusted");
}
} else if (!crossSigning && !isUser) {
if (isWarning) {
e2eTitle = _t("Some devices in this encrypted room are not trusted");
} else if (isVerified) {
e2eTitle = _t("All devices in this encrypted room are trusted");
}
}

let style = null;
Expand Down
4 changes: 3 additions & 1 deletion src/components/views/toasts/VerificationRequestToast.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,9 @@ export default class VerificationRequestToast extends React.PureComponent {

const verifier = this.props.request.beginKeyVerification(verificationMethods.SAS);
const IncomingSasDialog = sdk.getComponent('views.dialogs.IncomingSasDialog');
Modal.createTrackedDialog('Incoming Verification', '', IncomingSasDialog, {verifier});
Modal.createTrackedDialog('Incoming Verification', '', IncomingSasDialog, {
verifier,
}, null, /* priority = */ false, /* static = */ true);
};

render() {
Expand Down
7 changes: 6 additions & 1 deletion src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -857,9 +857,14 @@
" (unsupported)": " (unsupported)",
"Join as <voiceText>voice</voiceText> or <videoText>video</videoText>.": "Join as <voiceText>voice</voiceText> or <videoText>video</videoText>.",
"Ongoing conference call%(supportedText)s.": "Ongoing conference call%(supportedText)s.",
"This user has not verified all of their devices.": "This user has not verified all of their devices.",
"You have not verified this user. This user has verified all of their devices.": "You have not verified this user. This user has verified all of their devices.",
"You have verified this user. This user has verified all of their devices.": "You have verified this user. This user has verified all of their devices.",
"Some users in this encrypted room are not verified by you or they have not verified their own devices.": "Some users in this encrypted room are not verified by you or they have not verified their own devices.",
"All users in this encrypted room are verified by you and they have verified their own devices.": "All users in this encrypted room are verified by you and they have verified their own devices.",
"Some devices for this user are not trusted": "Some devices for this user are not trusted",
"Some devices in this encrypted room are not trusted": "Some devices in this encrypted room are not trusted",
"All devices for this user are trusted": "All devices for this user are trusted",
"Some devices in this encrypted room are not trusted": "Some devices in this encrypted room are not trusted",
"All devices in this encrypted room are trusted": "All devices in this encrypted room are trusted",
"Edit message": "Edit message",
"This event could not be displayed": "This event could not be displayed",
Expand Down