diff --git a/src/DeviceListener.js b/src/DeviceListener.js index 41f249b335..a7b259e179 100644 --- a/src/DeviceListener.js +++ b/src/DeviceListener.js @@ -20,12 +20,9 @@ import * as sdk from './index'; import { _t } from './languageHandler'; import ToastStore from './stores/ToastStore'; -function toastKey(deviceId) { - return 'unverified_session_' + deviceId; -} - const KEY_BACKUP_POLL_INTERVAL = 5 * 60 * 1000; const THIS_DEVICE_TOAST_KEY = 'setupencryption'; +const OTHER_DEVICES_TOAST_KEY = 'reviewsessions'; export default class DeviceListener { static sharedInstance() { @@ -34,8 +31,6 @@ export default class DeviceListener { } constructor() { - // set of device IDs we're currently showing toasts for - this._activeNagToasts = new Set(); // device IDs for which the user has dismissed the verify toast ('Later') this._dismissed = new Set(); // has the user dismissed any of the various nag toasts to setup encryption on this device? @@ -71,8 +66,11 @@ export default class DeviceListener { this._keyBackupFetchedAt = null; } - dismissVerification(deviceId) { - this._dismissed.add(deviceId); + async dismissVerifications() { + const cli = MatrixClientPeg.get(); + const devices = await cli.getStoredDevicesForUser(cli.getUserId()); + this._dismissed = new Set(devices.filter(d => d.deviceId !== cli.deviceId).map(d => d.deviceId)); + this._recheck(); } @@ -202,33 +200,28 @@ export default class DeviceListener { // as long as cross-signing isn't ready, // you can't see or dismiss any device toasts if (crossSigningReady) { - const newActiveToasts = new Set(); + const unverifiedDeviceIds = new Set(); const devices = await cli.getStoredDevicesForUser(cli.getUserId()); for (const device of devices) { if (device.deviceId == cli.deviceId) continue; const deviceTrust = await cli.checkDeviceTrust(cli.getUserId(), device.deviceId); - if (deviceTrust.isCrossSigningVerified() || this._dismissed.has(device.deviceId)) { - ToastStore.sharedInstance().dismissToast(toastKey(device.deviceId)); - } else { - this._activeNagToasts.add(device.deviceId); - ToastStore.sharedInstance().addOrReplaceToast({ - key: toastKey(device.deviceId), - title: _t("Unverified login. Was this you?"), - icon: "verification_warning", - props: { device }, - component: sdk.getComponent("toasts.UnverifiedSessionToast"), - }); - newActiveToasts.add(device.deviceId); + if (!deviceTrust.isCrossSigningVerified() && !this._dismissed.has(device.deviceId)) { + unverifiedDeviceIds.add(device.deviceId); } } - // clear any other outstanding toasts (eg. logged out devices) - for (const deviceId of this._activeNagToasts) { - if (!newActiveToasts.has(deviceId)) ToastStore.sharedInstance().dismissToast(toastKey(deviceId)); + if (unverifiedDeviceIds.size > 0) { + ToastStore.sharedInstance().addOrReplaceToast({ + key: OTHER_DEVICES_TOAST_KEY, + title: _t("Review where you’re logged in"), + icon: "verification_warning", + component: sdk.getComponent("toasts.UnverifiedSessionToast"), + }); + } else { + ToastStore.sharedInstance().dismissToast(OTHER_DEVICES_TOAST_KEY); } - this._activeNagToasts = newActiveToasts; } } } diff --git a/src/components/views/toasts/UnverifiedSessionToast.js b/src/components/views/toasts/UnverifiedSessionToast.js index cb0cadcdc8..587a54164d 100644 --- a/src/components/views/toasts/UnverifiedSessionToast.js +++ b/src/components/views/toasts/UnverifiedSessionToast.js @@ -18,6 +18,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { _t } from '../../../languageHandler'; import Modal from "../../../Modal"; +import dis from "../../../dispatcher"; import { MatrixClientPeg } from '../../../MatrixClientPeg'; import DeviceListener from '../../../DeviceListener'; import NewSessionReviewDialog from '../dialogs/NewSessionReviewDialog'; @@ -26,29 +27,17 @@ import { replaceableComponent } from '../../../utils/replaceableComponent'; @replaceableComponent("views.toasts.UnverifiedSessionToast") export default class UnverifiedSessionToast extends React.PureComponent { - static propTypes = { - toastKey: PropTypes.string.isRequired, - device: PropTypes.object.isRequired, - }; - _onLaterClick = () => { - const { device } = this.props; - DeviceListener.sharedInstance().dismissVerification(device.deviceId); + DeviceListener.sharedInstance().dismissVerifications(); }; _onReviewClick = async () => { - const { device } = this.props; + DeviceListener.sharedInstance().dismissVerifications(); - Modal.createTrackedDialog('New Session Review', 'Starting dialog', NewSessionReviewDialog, { + dis.dispatch({ + action: 'view_user_info', userId: MatrixClientPeg.get().getUserId(), - device, - onFinished: (r) => { - if (!r) { - /* This'll come back false if the user clicks "this wasn't me" and saw a warning dialog */ - this._onLaterClick(); - } - }, - }, null, /* priority = */ false, /* static = */ true); + }); }; render() { @@ -56,11 +45,7 @@ export default class UnverifiedSessionToast extends React.PureComponent { return (