Merge pull request #3728 from matrix-org/jryans/verify-users

Verify users when cross-signing enabled
This commit is contained in:
David Baker 2019-12-16 10:12:46 +00:00 committed by GitHub
commit be914c7b0c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 122 additions and 30 deletions

View file

@ -22,7 +22,9 @@ limitations under the License.
display: block; display: block;
} }
.mx_E2EIcon_verified::after, .mx_E2EIcon_warning::after { .mx_E2EIcon_warning::after,
.mx_E2EIcon_normal::after,
.mx_E2EIcon_verified::after {
content: ""; content: "";
display: block; display: block;
position: absolute; position: absolute;
@ -34,10 +36,14 @@ limitations under the License.
background-size: contain; background-size: contain;
} }
.mx_E2EIcon_verified::after {
background-image: url('$(res)/img/e2e/verified.svg');
}
.mx_E2EIcon_warning::after { .mx_E2EIcon_warning::after {
background-image: url('$(res)/img/e2e/warning.svg'); 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');
}

View file

@ -1492,7 +1492,7 @@ export default createReactClass({
const IncomingSasDialog = sdk.getComponent("views.dialogs.IncomingSasDialog"); const IncomingSasDialog = sdk.getComponent("views.dialogs.IncomingSasDialog");
Modal.createTrackedDialog('Incoming Verification', '', IncomingSasDialog, { Modal.createTrackedDialog('Incoming Verification', '', IncomingSasDialog, {
verifier, verifier,
}); }, null, /* priority = */ false, /* static = */ true);
}); });
} }
// Fire the tinter right on startup to ensure the default theme is applied // Fire the tinter right on startup to ensure the default theme is applied

View file

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

View file

@ -99,7 +99,7 @@ export default createReactClass({
this.props.onFinished(true); this.props.onFinished(true);
} }
}, },
}); }, null, /* priority = */ false, /* static = */ true);
}, },
_onShareClicked: function() { _onShareClicked: function() {

View file

@ -59,7 +59,7 @@ export default createReactClass({
Modal.createTrackedDialog('Device Verify Dialog', '', DeviceVerifyDialog, { Modal.createTrackedDialog('Device Verify Dialog', '', DeviceVerifyDialog, {
userId: this.props.userId, userId: this.props.userId,
device: this.state.device, device: this.state.device,
}); }, null, /* priority = */ false, /* static = */ true);
}, },
onUnverifyClick: function() { onUnverifyClick: function() {

View file

@ -52,7 +52,7 @@ export default class MKeyVerificationRequest extends React.Component {
const verifier = MatrixClientPeg.get().acceptVerificationDM(this.props.mxEvent, verificationMethods.SAS); const verifier = MatrixClientPeg.get().acceptVerificationDM(this.props.mxEvent, verificationMethods.SAS);
Modal.createTrackedDialog('Incoming Verification', '', IncomingSasDialog, { Modal.createTrackedDialog('Incoming Verification', '', IncomingSasDialog, {
verifier, verifier,
}); }, null, /* priority = */ false, /* static = */ true);
}; };
_onRejectClicked = () => { _onRejectClicked = () => {

View file

@ -58,9 +58,20 @@ const _disambiguateDevices = (devices) => {
} }
}; };
const _getE2EStatus = (devices) => { const _getE2EStatus = (cli, userId, devices) => {
if (!SettingsStore.isFeatureEnabled("feature_cross_signing")) {
const hasUnverifiedDevice = devices.some((device) => device.isUnverified()); const hasUnverifiedDevice = devices.some((device) => device.isUnverified());
return hasUnverifiedDevice ? "warning" : "verified"; 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) { async function unverifyUser(matrixClient, userId) {
@ -114,7 +125,7 @@ function verifyDevice(userId, device) {
Modal.createTrackedDialog('Device Verify Dialog', '', DeviceVerifyDialog, { Modal.createTrackedDialog('Device Verify Dialog', '', DeviceVerifyDialog, {
userId: userId, userId: userId,
device: device, device: device,
}); }, null, /* priority = */ false, /* static = */ true);
} }
function DeviceItem({userId, device}) { function DeviceItem({userId, device}) {
@ -1264,7 +1275,8 @@ const UserInfo = withLegacyMatrixClient(({matrixClient: cli, user, groupId, room
let e2eIcon; let e2eIcon;
if (isRoomEncrypted && devices) { 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 ( return (

View file

@ -17,24 +17,62 @@ limitations under the License.
import classNames from 'classnames'; import classNames from 'classnames';
import { _t } from '../../../languageHandler'; import { _t } from '../../../languageHandler';
import AccessibleButton from '../elements/AccessibleButton'; import AccessibleButton from '../elements/AccessibleButton';
import SettingsStore from '../../../settings/SettingsStore';
export default function(props) { export default function(props) {
const { isUser } = props;
const isNormal = props.status === "normal";
const isWarning = props.status === "warning"; const isWarning = props.status === "warning";
const isVerified = props.status === "verified"; const isVerified = props.status === "verified";
const e2eIconClasses = classNames({ const e2eIconClasses = classNames({
mx_E2EIcon: true, mx_E2EIcon: true,
mx_E2EIcon_warning: isWarning, mx_E2EIcon_warning: isWarning,
mx_E2EIcon_normal: isNormal,
mx_E2EIcon_verified: isVerified, mx_E2EIcon_verified: isVerified,
}, props.className); }, props.className);
let e2eTitle; let e2eTitle;
const crossSigning = SettingsStore.isFeatureEnabled("feature_cross_signing");
if (crossSigning && isUser) {
if (isWarning) { if (isWarning) {
e2eTitle = props.isUser ? e2eTitle = _t(
_t("Some devices for this user are not trusted") : "This user has not verified all of their devices.",
_t("Some devices in this encrypted room are not trusted"); );
} else if (isNormal) {
e2eTitle = _t(
"You have not verified this user. " +
"This user has verified all of their devices.",
);
} else if (isVerified) { } else if (isVerified) {
e2eTitle = props.isUser ? e2eTitle = _t(
_t("All devices for this user are trusted") : "You have verified this user. " +
_t("All devices in this encrypted room are trusted"); "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; let style = null;

View file

@ -90,7 +90,9 @@ export default class VerificationRequestToast extends React.PureComponent {
const verifier = this.props.request.beginKeyVerification(verificationMethods.SAS); const verifier = this.props.request.beginKeyVerification(verificationMethods.SAS);
const IncomingSasDialog = sdk.getComponent('views.dialogs.IncomingSasDialog'); 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() { render() {

View file

@ -857,9 +857,14 @@
" (unsupported)": " (unsupported)", " (unsupported)": " (unsupported)",
"Join as <voiceText>voice</voiceText> or <videoText>video</videoText>.": "Join as <voiceText>voice</voiceText> or <videoText>video</videoText>.", "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.", "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 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", "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", "All devices in this encrypted room are trusted": "All devices in this encrypted room are trusted",
"Edit message": "Edit message", "Edit message": "Edit message",
"This event could not be displayed": "This event could not be displayed", "This event could not be displayed": "This event could not be displayed",