diff --git a/res/css/views/rooms/_E2EIcon.scss b/res/css/views/rooms/_E2EIcon.scss
index cb99aa63f18..584ea174336 100644
--- a/res/css/views/rooms/_E2EIcon.scss
+++ b/res/css/views/rooms/_E2EIcon.scss
@@ -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;
@@ -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');
+}
diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js
index 8105805ab04..82a682f9ab2 100644
--- a/src/components/structures/MatrixChat.js
+++ b/src/components/structures/MatrixChat.js
@@ -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
diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js
index d78c9923c25..8c05acf60a6 100644
--- a/src/components/structures/RoomView.js
+++ b/src/components/structures/RoomView.js
@@ -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.
@@ -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",
});
},
diff --git a/src/components/views/dialogs/KeyShareDialog.js b/src/components/views/dialogs/KeyShareDialog.js
index 01e3479bb1c..ba8918e79c5 100644
--- a/src/components/views/dialogs/KeyShareDialog.js
+++ b/src/components/views/dialogs/KeyShareDialog.js
@@ -99,7 +99,7 @@ export default createReactClass({
this.props.onFinished(true);
}
},
- });
+ }, null, /* priority = */ false, /* static = */ true);
},
_onShareClicked: function() {
diff --git a/src/components/views/elements/DeviceVerifyButtons.js b/src/components/views/elements/DeviceVerifyButtons.js
index 15678b7d7af..bb08f8b2349 100644
--- a/src/components/views/elements/DeviceVerifyButtons.js
+++ b/src/components/views/elements/DeviceVerifyButtons.js
@@ -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() {
diff --git a/src/components/views/messages/MKeyVerificationRequest.js b/src/components/views/messages/MKeyVerificationRequest.js
index b2a1724fc66..4faa1b20aaa 100644
--- a/src/components/views/messages/MKeyVerificationRequest.js
+++ b/src/components/views/messages/MKeyVerificationRequest.js
@@ -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 = () => {
diff --git a/src/components/views/right_panel/UserInfo.js b/src/components/views/right_panel/UserInfo.js
index af8b4616f86..90bb3f3dcbb 100644
--- a/src/components/views/right_panel/UserInfo.js
+++ b/src/components/views/right_panel/UserInfo.js
@@ -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) {
@@ -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}) {
@@ -1264,7 +1275,8 @@ const UserInfo = withLegacyMatrixClient(({matrixClient: cli, user, groupId, room
let e2eIcon;
if (isRoomEncrypted && devices) {
- e2eIcon = ;
+ const e2eStatus = _getE2EStatus(cli, user.userId, devices);
+ e2eIcon = ;
}
return (
diff --git a/src/components/views/rooms/E2EIcon.js b/src/components/views/rooms/E2EIcon.js
index d6baa30c8ea..545d1fd7edf 100644
--- a/src/components/views/rooms/E2EIcon.js
+++ b/src/components/views/rooms/E2EIcon.js
@@ -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;
diff --git a/src/components/views/toasts/VerificationRequestToast.js b/src/components/views/toasts/VerificationRequestToast.js
index 89af91c41f2..7e043f4d833 100644
--- a/src/components/views/toasts/VerificationRequestToast.js
+++ b/src/components/views/toasts/VerificationRequestToast.js
@@ -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() {
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index 80604e90907..f801c3a5c59 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -857,9 +857,14 @@
" (unsupported)": " (unsupported)",
"Join as voice or video.": "Join as voice or video.",
"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",