diff --git a/.eslintignore.errorfiles b/.eslintignore.errorfiles index ffc3b21181..381c7cfd70 100644 --- a/.eslintignore.errorfiles +++ b/.eslintignore.errorfiles @@ -9,7 +9,6 @@ src/components/structures/UploadBar.js src/components/views/avatars/MemberAvatar.js src/components/views/create_room/RoomAlias.js src/components/views/dialogs/SetPasswordDialog.js -src/components/views/dialogs/UnknownDeviceDialog.js src/components/views/elements/AddressSelector.js src/components/views/elements/DirectorySearchBox.js src/components/views/elements/MemberEventListSummary.js diff --git a/res/css/_components.scss b/res/css/_components.scss index 44c63b9df7..37a97d27e4 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -81,7 +81,6 @@ @import "./views/dialogs/_SlashCommandHelpDialog.scss"; @import "./views/dialogs/_TabbedIntegrationManagerDialog.scss"; @import "./views/dialogs/_TermsDialog.scss"; -@import "./views/dialogs/_UnknownDeviceDialog.scss"; @import "./views/dialogs/_UploadConfirmDialog.scss"; @import "./views/dialogs/_UserSettingsDialog.scss"; @import "./views/dialogs/_WidgetOpenIDPermissionsDialog.scss"; diff --git a/res/css/views/dialogs/_UnknownDeviceDialog.scss b/res/css/views/dialogs/_UnknownDeviceDialog.scss deleted file mode 100644 index daa6bd2352..0000000000 --- a/res/css/views/dialogs/_UnknownDeviceDialog.scss +++ /dev/null @@ -1,48 +0,0 @@ -/* -Copyright 2016 OpenMarket Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -.mx_UnknownDeviceDialog { - height: 100%; - display: flex; - flex-direction: column; -} - -.mx_UnknownDeviceDialog ul { - list-style: none; - padding: 0; -} -// userid -.mx_UnknownDeviceDialog p { - font-weight: bold; - font-size: $font-16px; -} - -.mx_UnknownDeviceDialog .mx_DeviceVerifyButtons { - flex-direction: row !important; -} - -.mx_UnknownDeviceDialog .mx_Dialog_content { - margin-bottom: 24px; - overflow-y: scroll; -} - -.mx_UnknownDeviceDialog_deviceList > li { - padding: 4px; -} - -.mx_UnknownDeviceDialog_deviceList > li > * { - padding-bottom: 0; -} diff --git a/src/CallHandler.js b/src/CallHandler.js index c95ed16eb3..e3916c25d6 100644 --- a/src/CallHandler.js +++ b/src/CallHandler.js @@ -60,7 +60,6 @@ import * as sdk from './index'; import { _t } from './languageHandler'; import Matrix from 'matrix-js-sdk'; import dis from './dispatcher/dispatcher'; -import { showUnknownDeviceDialogForCalls } from './cryptodevices'; import WidgetUtils from './utils/WidgetUtils'; import WidgetEchoStore from './stores/WidgetEchoStore'; import SettingsStore, { SettingLevel } from './settings/SettingsStore'; @@ -134,47 +133,19 @@ function _reAttemptCall(call) { function _setCallListeners(call) { call.on("error", function(err) { console.error("Call error:", err); - if (err.code === 'unknown_devices') { - const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); - - Modal.createTrackedDialog('Call Failed', '', QuestionDialog, { - title: _t('Call Failed'), - description: _t( - "There are unknown sessions in this room: "+ - "if you proceed without verifying them, it will be "+ - "possible for someone to eavesdrop on your call.", - ), - button: _t('Review Sessions'), - onFinished: function(confirmed) { - if (confirmed) { - const room = MatrixClientPeg.get().getRoom(call.roomId); - showUnknownDeviceDialogForCalls( - MatrixClientPeg.get(), - room, - () => { - _reAttemptCall(call); - }, - call.direction === 'outbound' ? _t("Call Anyway") : _t("Answer Anyway"), - call.direction === 'outbound' ? _t("Call") : _t("Answer"), - ); - } - }, - }); - } else { - if ( - MatrixClientPeg.get().getTurnServers().length === 0 && - SettingsStore.getValue("fallbackICEServerAllowed") === null - ) { - _showICEFallbackPrompt(); - return; - } - - const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); - Modal.createTrackedDialog('Call Failed', '', ErrorDialog, { - title: _t('Call Failed'), - description: err.message, - }); + if ( + MatrixClientPeg.get().getTurnServers().length === 0 && + SettingsStore.getValue("fallbackICEServerAllowed") === null + ) { + _showICEFallbackPrompt(); + return; } + + const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); + Modal.createTrackedDialog('Call Failed', '', ErrorDialog, { + title: _t('Call Failed'), + description: err.message, + }); }); call.on("hangup", function() { _setCallState(undefined, call.roomId, "ended"); diff --git a/src/components/structures/RoomStatusBar.js b/src/components/structures/RoomStatusBar.js index ae628fd06a..dd4b9759d6 100644 --- a/src/components/structures/RoomStatusBar.js +++ b/src/components/structures/RoomStatusBar.js @@ -24,7 +24,6 @@ import { _t, _td } from '../../languageHandler'; import * as sdk from '../../index'; import {MatrixClientPeg} from '../../MatrixClientPeg'; import Resend from '../../Resend'; -import * as cryptodevices from '../../cryptodevices'; import dis from '../../dispatcher/dispatcher'; import {messageForResourceLimitError, messageForSendError} from '../../utils/ErrorUtils'; @@ -126,13 +125,6 @@ export default createReactClass({ }); }, - _onSendWithoutVerifyingClick: function() { - cryptodevices.getUnknownDevicesForRoom(MatrixClientPeg.get(), this.props.room).then((devices) => { - cryptodevices.markAllDevicesKnown(MatrixClientPeg.get(), devices); - Resend.resendUnsentEvents(this.props.room); - }); - }, - _onResendAllClick: function() { Resend.resendUnsentEvents(this.props.room); dis.dispatch({action: 'focus_composer'}); @@ -143,10 +135,6 @@ export default createReactClass({ dis.dispatch({action: 'focus_composer'}); }, - _onShowDevicesClick: function() { - cryptodevices.showUnknownDeviceDialogForMessages(MatrixClientPeg.get(), this.props.room); - }, - _onRoomLocalEchoUpdated: function(event, room, oldEventId, oldStatus) { if (room.roomId !== this.props.room.roomId) return; @@ -213,82 +201,65 @@ export default createReactClass({ if (!unsentMessages.length) return null; let title; - let content; - const hasUDE = unsentMessages.some((m) => { - return m.error && m.error.name === "UnknownDeviceError"; - }); - - if (hasUDE) { - title = _t("Message not sent due to unknown sessions being present"); - content = _t( - "Show sessions, send anyway or cancel.", + let consentError = null; + let resourceLimitError = null; + for (const m of unsentMessages) { + if (m.error && m.error.errcode === 'M_CONSENT_NOT_GIVEN') { + consentError = m.error; + break; + } else if (m.error && m.error.errcode === 'M_RESOURCE_LIMIT_EXCEEDED') { + resourceLimitError = m.error; + break; + } + } + if (consentError) { + title = _t( + "You can't send any messages until you review and agree to " + + "our terms and conditions.", {}, { - 'showSessionsText': (sub) => { sub }, - 'sendAnywayText': (sub) => { sub }, - 'cancelText': (sub) => { sub }, + 'consentLink': (sub) => + + { sub } + , }, ); + } else if (resourceLimitError) { + title = messageForResourceLimitError( + resourceLimitError.data.limit_type, + resourceLimitError.data.admin_contact, { + 'monthly_active_user': _td( + "Your message wasn't sent because this homeserver has hit its Monthly Active User Limit. " + + "Please contact your service administrator to continue using the service.", + ), + '': _td( + "Your message wasn't sent because this homeserver has exceeded a resource limit. " + + "Please contact your service administrator to continue using the service.", + ), + }); + } else if ( + unsentMessages.length === 1 && + unsentMessages[0].error && + unsentMessages[0].error.data && + unsentMessages[0].error.data.error + ) { + title = messageForSendError(unsentMessages[0].error.data) || unsentMessages[0].error.data.error; } else { - let consentError = null; - let resourceLimitError = null; - for (const m of unsentMessages) { - if (m.error && m.error.errcode === 'M_CONSENT_NOT_GIVEN') { - consentError = m.error; - break; - } else if (m.error && m.error.errcode === 'M_RESOURCE_LIMIT_EXCEEDED') { - resourceLimitError = m.error; - break; - } - } - if (consentError) { - title = _t( - "You can't send any messages until you review and agree to " + - "our terms and conditions.", - {}, - { - 'consentLink': (sub) => - - { sub } - , - }, - ); - } else if (resourceLimitError) { - title = messageForResourceLimitError( - resourceLimitError.data.limit_type, - resourceLimitError.data.admin_contact, { - 'monthly_active_user': _td( - "Your message wasn't sent because this homeserver has hit its Monthly Active User Limit. " + - "Please contact your service administrator to continue using the service.", - ), - '': _td( - "Your message wasn't sent because this homeserver has exceeded a resource limit. " + - "Please contact your service administrator to continue using the service.", - ), - }); - } else if ( - unsentMessages.length === 1 && - unsentMessages[0].error && - unsentMessages[0].error.data && - unsentMessages[0].error.data.error - ) { - title = messageForSendError(unsentMessages[0].error.data) || unsentMessages[0].error.data.error; - } else { - title = _t('%(count)s of your messages have not been sent.', { count: unsentMessages.length }); - } - content = _t("%(count)s Resend all or cancel all now. " + - "You can also select individual messages to resend or cancel.", - { count: unsentMessages.length }, - { - 'resendText': (sub) => - { sub }, - 'cancelText': (sub) => - { sub }, - }, - ); + title = _t('%(count)s of your messages have not been sent.', { count: unsentMessages.length }); } + const content = _t("%(count)s Resend all or cancel all " + + "now. You can also select individual messages to resend or cancel.", + { count: unsentMessages.length }, + { + 'resendText': (sub) => + { sub }, + 'cancelText': (sub) => + { sub }, + }, + ); + return
diff --git a/src/components/views/dialogs/UnknownDeviceDialog.js b/src/components/views/dialogs/UnknownDeviceDialog.js deleted file mode 100644 index 4cad13b047..0000000000 --- a/src/components/views/dialogs/UnknownDeviceDialog.js +++ /dev/null @@ -1,187 +0,0 @@ -/* -Copyright 2017 Vector Creations Ltd -Copyright 2017 New Vector Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import React from 'react'; -import createReactClass from 'create-react-class'; -import PropTypes from 'prop-types'; -import * as sdk from '../../../index'; -import {MatrixClientPeg} from '../../../MatrixClientPeg'; -import { _t } from '../../../languageHandler'; -import SettingsStore from "../../../settings/SettingsStore"; -import { markAllDevicesKnown } from '../../../cryptodevices'; - -function UserUnknownDeviceList(props) { - const MemberDeviceInfo = sdk.getComponent('rooms.MemberDeviceInfo'); - const {userId, userDevices} = props; - - const deviceListEntries = Object.keys(userDevices).map((deviceId) => -
  • , - ); - - return ( - - ); -} - -UserUnknownDeviceList.propTypes = { - userId: PropTypes.string.isRequired, - - // map from deviceid -> deviceinfo - userDevices: PropTypes.object.isRequired, -}; - - -function UnknownDeviceList(props) { - const {devices} = props; - - const userListEntries = Object.keys(devices).map((userId) => -
  • -

    { userId }:

    - -
  • , - ); - - return ; -} - -UnknownDeviceList.propTypes = { - // map from userid -> deviceid -> deviceinfo - devices: PropTypes.object.isRequired, -}; - - -export default createReactClass({ - displayName: 'UnknownDeviceDialog', - - propTypes: { - room: PropTypes.object.isRequired, - - // map from userid -> deviceid -> deviceinfo or null if devices are not yet loaded - devices: PropTypes.object, - - onFinished: PropTypes.func.isRequired, - - // Label for the button that marks all devices known and tries the send again - sendAnywayLabel: PropTypes.string.isRequired, - - // Label for the button that to send the event if you've verified all devices - sendLabel: PropTypes.string.isRequired, - - // function to retry the request once all devices are verified / known - onSend: PropTypes.func.isRequired, - }, - - componentDidMount: function() { - MatrixClientPeg.get().on("deviceVerificationChanged", this._onDeviceVerificationChanged); - }, - - componentWillUnmount: function() { - if (MatrixClientPeg.get()) { - MatrixClientPeg.get().removeListener("deviceVerificationChanged", this._onDeviceVerificationChanged); - } - }, - - _onDeviceVerificationChanged: function(userId, deviceId, deviceInfo) { - if (this.props.devices[userId] && this.props.devices[userId][deviceId]) { - // XXX: Mutating props :/ - this.props.devices[userId][deviceId] = deviceInfo; - this.forceUpdate(); - } - }, - - _onDismissClicked: function() { - this.props.onFinished(); - }, - - _onSendAnywayClicked: function() { - markAllDevicesKnown(MatrixClientPeg.get(), this.props.devices); - - this.props.onFinished(); - this.props.onSend(); - }, - - _onSendClicked: function() { - this.props.onFinished(); - this.props.onSend(); - }, - - render: function() { - if (this.props.devices === null) { - const Spinner = sdk.getComponent("elements.Spinner"); - return ; - } - - let warning; - if (SettingsStore.getValue("blacklistUnverifiedDevices", this.props.room.roomId)) { - warning = ( -

    - { _t("You are currently blacklisting unverified sessions; to send " + - "messages to these sessions you must verify them.") } -

    - ); - } else { - warning = ( -
    -

    - { _t("We recommend you go through the verification process " + - "for each session to confirm they belong to their legitimate owner, " + - "but you can resend the message without verifying if you prefer.") } -

    -
    - ); - } - - let haveUnknownDevices = false; - Object.keys(this.props.devices).forEach((userId) => { - Object.keys(this.props.devices[userId]).map((deviceId) => { - const device = this.props.devices[userId][deviceId]; - if (device.isUnverified() && !device.isKnown()) { - haveUnknownDevices = true; - } - }); - }); - const sendButtonOnClick = haveUnknownDevices ? this._onSendAnywayClicked : this._onSendClicked; - const sendButtonLabel = haveUnknownDevices ? this.props.sendAnywayLabel : this.props.sendAnywayLabel; - - const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); - const DialogButtons = sdk.getComponent('views.elements.DialogButtons'); - return ( - -
    -

    - { _t('"%(RoomName)s" contains sessions that you haven\'t seen before.', {RoomName: this.props.room.name}) } -

    - { warning } - { _t("Unknown sessions") }: - - -
    - -
    - ); - // XXX: do we want to give the user the option to enable blacklistUnverifiedDevices for this room (or globally) at this point? - // It feels like confused users will likely turn it on and then disappear in a cloud of UISIs... - }, -}); diff --git a/src/cryptodevices.js b/src/cryptodevices.js deleted file mode 100644 index 86b97364f9..0000000000 --- a/src/cryptodevices.js +++ /dev/null @@ -1,123 +0,0 @@ -/* -Copyright 2017 New Vector Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -import Resend from './Resend'; -import * as sdk from './index'; -import dis from './dispatcher/dispatcher'; -import Modal from './Modal'; -import { _t } from './languageHandler'; - -/** - * Mark all given devices as 'known' - * - * @param {MatrixClient} matrixClient A MatrixClient - * @param {Object} devices Map from userid -> deviceid -> deviceinfo - */ -export function markAllDevicesKnown(matrixClient, devices) { - Object.keys(devices).forEach((userId) => { - Object.keys(devices[userId]).map((deviceId) => { - matrixClient.setDeviceKnown(userId, deviceId, true); - }); - }); -} - -/** - * Gets all crypto devices in a room that are marked neither known - * nor verified. - * - * @param {MatrixClient} matrixClient A MatrixClient - * @param {Room} room js-sdk room object representing the room - * @return {Promise} A promise which resolves to a map userId->deviceId->{@link - * module:crypto~DeviceInfo|DeviceInfo}. - */ -export async function getUnknownDevicesForRoom(matrixClient, room) { - const roomMembers = (await room.getEncryptionTargetMembers()).map((m) => { - return m.userId; - }); - const devices = await matrixClient.downloadKeys(roomMembers, false); - const unknownDevices = {}; - // This is all devices in this room, so find the unknown ones. - Object.keys(devices).forEach((userId) => { - Object.keys(devices[userId]).map((deviceId) => { - const device = devices[userId][deviceId]; - - if (device.isUnverified() && !device.isKnown()) { - if (unknownDevices[userId] === undefined) { - unknownDevices[userId] = {}; - } - unknownDevices[userId][deviceId] = device; - } - }); - }); - return unknownDevices; -} - -function focusComposer() { - dis.dispatch({action: 'focus_composer'}); -} - -/** - * Show the UnknownDeviceDialog for a given room. The dialog will inform the user - * that messages they sent to this room have not been sent due to unknown devices - * being present. - * - * @param {MatrixClient} matrixClient A MatrixClient - * @param {Room} room js-sdk room object representing the room - */ -export function showUnknownDeviceDialogForMessages(matrixClient, room) { - getUnknownDevicesForRoom(matrixClient, room).then((unknownDevices) => { - const onSendClicked = () => { - Resend.resendUnsentEvents(room); - }; - - const UnknownDeviceDialog = sdk.getComponent('dialogs.UnknownDeviceDialog'); - Modal.createTrackedDialog('Unknown Device Dialog', '', UnknownDeviceDialog, { - room: room, - devices: unknownDevices, - sendAnywayLabel: _t("Send anyway"), - sendLabel: _t("Send"), - onSend: onSendClicked, - onFinished: focusComposer, - }, 'mx_Dialog_unknownDevice'); - }); -} - -/** - * Show the UnknownDeviceDialog for a given room. The dialog will inform the user - * that a call they tried to place or answer in the room couldn't be placed or - * answered due to unknown devices being present. - * - * @param {MatrixClient} matrixClient A MatrixClient - * @param {Room} room js-sdk room object representing the room - * @param {func} sendAnyway Function called when the 'call anyway' or 'call' - * button is pressed. This should attempt to place or answer the call again. - * @param {string} sendAnywayLabel Label for the button displayed to retry the call - * when unknown devices are still present (eg. "Call Anyway") - * @param {string} sendLabel Label for the button displayed to retry the call - * after all devices have been verified (eg. "Call") - */ -export function showUnknownDeviceDialogForCalls(matrixClient, room, sendAnyway, sendAnywayLabel, sendLabel) { - getUnknownDevicesForRoom(matrixClient, room).then((unknownDevices) => { - const UnknownDeviceDialog = sdk.getComponent('dialogs.UnknownDeviceDialog'); - Modal.createTrackedDialog('Unknown Device Dialog', '', UnknownDeviceDialog, { - room: room, - devices: unknownDevices, - sendAnywayLabel: sendAnywayLabel, - sendLabel: sendLabel, - onSend: sendAnyway, - }, 'mx_Dialog_unknownDevice'); - }); -}