From 2e15e8f9b458c01612d60eeaa73fdd0a5308b9b5 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Sat, 21 Jan 2017 05:13:36 +0000 Subject: [PATCH 1/8] very barebones support for warning users when rooms contain unknown devices --- src/Resend.js | 13 +++- src/component-index.js | 2 + .../views/dialogs/UnknownDeviceDialog.js | 73 +++++++++++++++++++ .../views/rooms/MessageComposerInput.js | 10 ++- .../views/rooms/MessageComposerInputOld.js | 11 ++- .../views/rooms/SimpleRoomHeader.js | 2 +- 6 files changed, 104 insertions(+), 7 deletions(-) create mode 100644 src/components/views/dialogs/UnknownDeviceDialog.js diff --git a/src/Resend.js b/src/Resend.js index ecf504e780..e67c812b7c 100644 --- a/src/Resend.js +++ b/src/Resend.js @@ -16,17 +16,26 @@ limitations under the License. var MatrixClientPeg = require('./MatrixClientPeg'); var dis = require('./dispatcher'); +var sdk = require('./index'); +var Modal = require('./Modal'); module.exports = { resend: function(event) { MatrixClientPeg.get().resendEvent( event, MatrixClientPeg.get().getRoom(event.getRoomId()) - ).done(function() { + ).done(function(res) { dis.dispatch({ action: 'message_sent', event: event }); - }, function() { + }, function(err) { + if (err.name === "UnknownDeviceError") { + var UnknownDeviceDialog = sdk.getComponent("dialogs.UnknownDeviceDialog"); + Modal.createDialog(UnknownDeviceDialog, { + devices: err.devices + }); + } + dis.dispatch({ action: 'message_send_failed', event: event diff --git a/src/component-index.js b/src/component-index.js index e83de8739d..dcf96a6e56 100644 --- a/src/component-index.js +++ b/src/component-index.js @@ -89,6 +89,8 @@ import views$dialogs$SetDisplayNameDialog from './components/views/dialogs/SetDi views$dialogs$SetDisplayNameDialog && (module.exports.components['views.dialogs.SetDisplayNameDialog'] = views$dialogs$SetDisplayNameDialog); import views$dialogs$TextInputDialog from './components/views/dialogs/TextInputDialog'; views$dialogs$TextInputDialog && (module.exports.components['views.dialogs.TextInputDialog'] = views$dialogs$TextInputDialog); +import views$dialogs$UnknownDeviceDialog from './components/views/dialogs/UnknownDeviceDialog'; +views$dialogs$UnknownDeviceDialog && (module.exports.components['views.dialogs.UnknownDeviceDialog'] = views$dialogs$UnknownDeviceDialog); import views$elements$AddressSelector from './components/views/elements/AddressSelector'; views$elements$AddressSelector && (module.exports.components['views.elements.AddressSelector'] = views$elements$AddressSelector); import views$elements$AddressTile from './components/views/elements/AddressTile'; diff --git a/src/components/views/dialogs/UnknownDeviceDialog.js b/src/components/views/dialogs/UnknownDeviceDialog.js new file mode 100644 index 0000000000..aad310c855 --- /dev/null +++ b/src/components/views/dialogs/UnknownDeviceDialog.js @@ -0,0 +1,73 @@ +/* +Copyright 2015, 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. +*/ + +var React = require("react"); +var sdk = require('../../../index'); +var MatrixClientPeg = require("../../../MatrixClientPeg"); + +module.exports = React.createClass({ + displayName: 'UnknownEventDialog', + + propTypes: { + devices: React.PropTypes.object.isRequired, + onFinished: React.PropTypes.func.isRequired, + }, + + onKeyDown: function(e) { + if (e.keyCode === 27) { // escape + e.stopPropagation(); + e.preventDefault(); + this.props.onFinished(false); + } + }, + + render: function() { + return ( +
+
+ Room contains unknown devices +
+
+

This room contains unknown devices which have not been verified.

+

We strongly recommend you verify them before continuing.

+

Unknown devices: +

    { + Object.keys(this.props.devices).map(userId=>{ + return
  • +

    { userId }:

    +
      + { + Object.keys(this.props.devices[userId]).map(deviceId=>{ + return
    • + { deviceId } ( { this.props.devices[userId][deviceId].getDisplayName() } ) +
    • + }) + } +
    +
  • + }) + }
+

+
+
+ +
+
+ ); + } +}); diff --git a/src/components/views/rooms/MessageComposerInput.js b/src/components/views/rooms/MessageComposerInput.js index bf936a2c13..4a6e36b854 100644 --- a/src/components/views/rooms/MessageComposerInput.js +++ b/src/components/views/rooms/MessageComposerInput.js @@ -553,11 +553,17 @@ export default class MessageComposerInput extends React.Component { sendMessagePromise = sendTextFn.call(this.client, this.props.room.roomId, contentText); } - sendMessagePromise.then(() => { + sendMessagePromise.then((res) => { dis.dispatch({ action: 'message_sent', }); - }, () => { + }, (err) => { + if (err.name === "UnknownDeviceError") { + var UnknownDeviceDialog = sdk.getComponent("dialogs.UnknownDeviceDialog"); + Modal.createDialog(UnknownDeviceDialog, { + devices: err.devices + }); + } dis.dispatch({ action: 'message_send_failed', }); diff --git a/src/components/views/rooms/MessageComposerInputOld.js b/src/components/views/rooms/MessageComposerInputOld.js index c5d5f083c1..a5b1f6b786 100644 --- a/src/components/views/rooms/MessageComposerInputOld.js +++ b/src/components/views/rooms/MessageComposerInputOld.js @@ -337,11 +337,18 @@ module.exports = React.createClass({ MatrixClientPeg.get().sendTextMessage(this.props.room.roomId, contentText); } - sendMessagePromise.done(function() { + sendMessagePromise.done(function(res) { dis.dispatch({ action: 'message_sent' }); - }, function() { + }, function(err) { + if (err.name === "UnknownDeviceError") { + var UnknownDeviceDialog = sdk.getComponent("dialogs.UnknownDeviceDialog"); + Modal.createDialog(UnknownDeviceDialog, { + devices: err.devices + }); + } + dis.dispatch({ action: 'message_send_failed' }); diff --git a/src/components/views/rooms/SimpleRoomHeader.js b/src/components/views/rooms/SimpleRoomHeader.js index 4c63be5b99..c6d09f49ee 100644 --- a/src/components/views/rooms/SimpleRoomHeader.js +++ b/src/components/views/rooms/SimpleRoomHeader.js @@ -44,7 +44,7 @@ module.exports = React.createClass({ var cancelButton; if (this.props.onCancelClick) { - cancelButton =
Cancel
; + cancelButton =
Cancel
; } var showRhsButton; From 21f3aeac8e30ebb3e84244acbe0dad56b1c84a5d Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Wed, 25 Jan 2017 16:40:27 +0000 Subject: [PATCH 2/8] Revert accidental change This was an unrelated change which is being done on another branch anyway --- src/components/views/rooms/SimpleRoomHeader.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/rooms/SimpleRoomHeader.js b/src/components/views/rooms/SimpleRoomHeader.js index c6d09f49ee..4c63be5b99 100644 --- a/src/components/views/rooms/SimpleRoomHeader.js +++ b/src/components/views/rooms/SimpleRoomHeader.js @@ -44,7 +44,7 @@ module.exports = React.createClass({ var cancelButton; if (this.props.onCancelClick) { - cancelButton =
Cancel
; + cancelButton =
Cancel
; } var showRhsButton; From 5da6ca8fc10dcb5dec74e7943060e1ff051e500d Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Wed, 25 Jan 2017 18:25:40 +0000 Subject: [PATCH 3/8] Refactor UnknownDeviceDialog hopefully make this a bit more readable, and use our new BaseDialog. --- .../views/dialogs/UnknownDeviceDialog.js | 93 +++++++++++-------- 1 file changed, 55 insertions(+), 38 deletions(-) diff --git a/src/components/views/dialogs/UnknownDeviceDialog.js b/src/components/views/dialogs/UnknownDeviceDialog.js index aad310c855..bb50da71a5 100644 --- a/src/components/views/dialogs/UnknownDeviceDialog.js +++ b/src/components/views/dialogs/UnknownDeviceDialog.js @@ -14,60 +14,77 @@ See the License for the specific language governing permissions and limitations under the License. */ -var React = require("react"); -var sdk = require('../../../index'); -var MatrixClientPeg = require("../../../MatrixClientPeg"); +import React from 'react'; +import sdk from '../../../index'; -module.exports = React.createClass({ +function UserUnknownDeviceList(props) { + const {userDevices} = props; + + const deviceListEntries = Object.keys(userDevices).map((deviceId) => +
  • + { deviceId } ( { userDevices[deviceId].getDisplayName() } ) +
  • , + ); + + return
      {deviceListEntries}
    ; +} + +UserUnknownDeviceList.propTypes = { + // map from deviceid -> deviceinfo + userDevices: React.PropTypes.object.isRequired, +}; + + +function UnknownDeviceList(props) { + const {devices} = props; + + const userListEntries = Object.keys(devices).map((userId) => +
  • +

    { userId }:

    + +
  • , + ); + + return
      {userListEntries}
    ; +} + +UnknownDeviceList.propTypes = { + // map from userid -> deviceid -> deviceinfo + devices: React.PropTypes.object.isRequired, +}; + + +export default React.createClass({ displayName: 'UnknownEventDialog', propTypes: { + // map from userid -> deviceid -> deviceinfo devices: React.PropTypes.object.isRequired, onFinished: React.PropTypes.func.isRequired, }, - onKeyDown: function(e) { - if (e.keyCode === 27) { // escape - e.stopPropagation(); - e.preventDefault(); - this.props.onFinished(false); - } - }, - render: function() { + const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); return ( -
    -
    - Room contains unknown devices -
    +
    -

    This room contains unknown devices which have not been verified.

    +

    This room contains unknown devices which have not been + verified.

    +

    We strongly recommend you verify them before continuing.

    -

    Unknown devices: -

      { - Object.keys(this.props.devices).map(userId=>{ - return
    • -

      { userId }:

      -
        - { - Object.keys(this.props.devices[userId]).map(deviceId=>{ - return
      • - { deviceId } ( { this.props.devices[userId][deviceId].getDisplayName() } ) -
      • - }) - } -
      -
    • - }) - }
    -

    +

    Unknown devices:

    +
    -
    -
    + ); - } + }, }); From 70190be65cfab451b998bc4b7f7730f0c15fd7f7 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Wed, 25 Jan 2017 19:06:15 +0000 Subject: [PATCH 4/8] Factor out common onSendMessageFailed --- .../views/rooms/MessageComposerInput.js | 15 +++-------- .../views/rooms/MessageComposerInputOld.js | 26 ++++++++++--------- 2 files changed, 17 insertions(+), 24 deletions(-) diff --git a/src/components/views/rooms/MessageComposerInput.js b/src/components/views/rooms/MessageComposerInput.js index 4a6e36b854..80e41555a2 100644 --- a/src/components/views/rooms/MessageComposerInput.js +++ b/src/components/views/rooms/MessageComposerInput.js @@ -40,6 +40,7 @@ import * as HtmlUtils from '../../../HtmlUtils'; import Autocomplete from './Autocomplete'; import {Completion} from "../../../autocomplete/Autocompleter"; import Markdown from '../../../Markdown'; +import {onSendMessageFailed} from './MessageComposerInputOld'; const TYPING_USER_TIMEOUT = 10000, TYPING_SERVER_TIMEOUT = 30000; @@ -553,21 +554,11 @@ export default class MessageComposerInput extends React.Component { sendMessagePromise = sendTextFn.call(this.client, this.props.room.roomId, contentText); } - sendMessagePromise.then((res) => { + sendMessagePromise.done((res) => { dis.dispatch({ action: 'message_sent', }); - }, (err) => { - if (err.name === "UnknownDeviceError") { - var UnknownDeviceDialog = sdk.getComponent("dialogs.UnknownDeviceDialog"); - Modal.createDialog(UnknownDeviceDialog, { - devices: err.devices - }); - } - dis.dispatch({ - action: 'message_send_failed', - }); - }); + }, onSendMessageFailed); this.setState({ editorState: this.createEditorState(), diff --git a/src/components/views/rooms/MessageComposerInputOld.js b/src/components/views/rooms/MessageComposerInputOld.js index a5b1f6b786..d81f89a3c3 100644 --- a/src/components/views/rooms/MessageComposerInputOld.js +++ b/src/components/views/rooms/MessageComposerInputOld.js @@ -29,10 +29,22 @@ var TYPING_USER_TIMEOUT = 10000; var TYPING_SERVER_TIMEOUT = 30000; var MARKDOWN_ENABLED = true; +export function onSendMessageFailed(err) { + if (err.name === "UnknownDeviceError") { + const UnknownDeviceDialog = sdk.getComponent("dialogs.UnknownDeviceDialog"); + Modal.createDialog(UnknownDeviceDialog, { + devices: err.devices, + }); + } + dis.dispatch({ + action: 'message_send_failed', + }); +} + /* * The textInput part of the MessageComposer */ -module.exports = React.createClass({ +export default React.createClass({ displayName: 'MessageComposerInput', statics: { @@ -341,18 +353,8 @@ module.exports = React.createClass({ dis.dispatch({ action: 'message_sent' }); - }, function(err) { - if (err.name === "UnknownDeviceError") { - var UnknownDeviceDialog = sdk.getComponent("dialogs.UnknownDeviceDialog"); - Modal.createDialog(UnknownDeviceDialog, { - devices: err.devices - }); - } + }, onSendMessageFailed); - dis.dispatch({ - action: 'message_send_failed' - }); - }); this.refs.textarea.value = ''; this.resizeInput(); ev.preventDefault(); From ebf6ba89940362ae565f49507c178ebd62cd4f4b Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Wed, 25 Jan 2017 23:52:48 +0100 Subject: [PATCH 5/8] explicitly set device known-ness --- src/components/views/dialogs/UnknownDeviceDialog.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/components/views/dialogs/UnknownDeviceDialog.js b/src/components/views/dialogs/UnknownDeviceDialog.js index aad310c855..b771534852 100644 --- a/src/components/views/dialogs/UnknownDeviceDialog.js +++ b/src/components/views/dialogs/UnknownDeviceDialog.js @@ -26,6 +26,16 @@ module.exports = React.createClass({ onFinished: React.PropTypes.func.isRequired, }, + componentDidMount: function() { + // Given we've now shown the user the unknown device, it is no longer + // unknown to them. Therefore mark it as 'known'. + Object.keys(this.props.devices).forEach(userId=>{ + Object.keys(this.props.devices[userId]).map(deviceId=>{ + MatrixClientPeg.get().setDeviceKnown(userId, deviceId, true); + }) + }); + }, + onKeyDown: function(e) { if (e.keyCode === 27) { // escape e.stopPropagation(); From 2c7b3d9a02b35ad3a0ed6d40ac724552a7fdda78 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Thu, 26 Jan 2017 14:55:58 +0000 Subject: [PATCH 6/8] UnknownDeviceDialog: Reword the warning --- src/components/views/dialogs/UnknownDeviceDialog.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/components/views/dialogs/UnknownDeviceDialog.js b/src/components/views/dialogs/UnknownDeviceDialog.js index de69fd1c9d..aa64e9ed99 100644 --- a/src/components/views/dialogs/UnknownDeviceDialog.js +++ b/src/components/views/dialogs/UnknownDeviceDialog.js @@ -82,10 +82,16 @@ export default React.createClass({ title='Room contains unknown devices' >
    -

    This room contains unknown devices which have not been +

    This room contains devices which have not been verified.

    - -

    We strongly recommend you verify them before continuing.

    +

    + This means there is no guarantee that the devices belong + to a valid user of the room. +

    + We recommend you go through the verification process + for each device before continuing, but you can resend + the message without verifying if you prefer. +

    Unknown devices:

    From 5e5b7f89f4ee41616e08fb7ae4abd50297ceb5fc Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Thu, 2 Feb 2017 00:25:49 +0000 Subject: [PATCH 7/8] support scrollable content for UnknownDeviceDialog --- src/Modal.js | 2 +- src/Resend.js | 2 +- src/components/views/dialogs/UnknownDeviceDialog.js | 7 ++++--- src/components/views/rooms/MessageComposerInputOld.js | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Modal.js b/src/Modal.js index 89e8b1361c..b6cc46ed45 100644 --- a/src/Modal.js +++ b/src/Modal.js @@ -177,7 +177,7 @@ class ModalManager { var modal = this._modals[0]; var dialog = ( -
    +
    {modal.elem}
    diff --git a/src/Resend.js b/src/Resend.js index e67c812b7c..59a8bd4192 100644 --- a/src/Resend.js +++ b/src/Resend.js @@ -33,7 +33,7 @@ module.exports = { var UnknownDeviceDialog = sdk.getComponent("dialogs.UnknownDeviceDialog"); Modal.createDialog(UnknownDeviceDialog, { devices: err.devices - }); + }, "mx_Dialog_unknownDevice"); } dis.dispatch({ diff --git a/src/components/views/dialogs/UnknownDeviceDialog.js b/src/components/views/dialogs/UnknownDeviceDialog.js index aa64e9ed99..11d0479f15 100644 --- a/src/components/views/dialogs/UnknownDeviceDialog.js +++ b/src/components/views/dialogs/UnknownDeviceDialog.js @@ -17,6 +17,7 @@ limitations under the License. import React from 'react'; import sdk from '../../../index'; import MatrixClientPeg from '../../../MatrixClientPeg'; +import GeminiScrollbar from 'react-gemini-scrollbar'; function UserUnknownDeviceList(props) { const {userDevices} = props; @@ -81,12 +82,12 @@ export default React.createClass({ onFinished={this.props.onFinished} title='Room contains unknown devices' > -
    +

    This room contains devices which have not been verified.

    This means there is no guarantee that the devices belong - to a valid user of the room. + to a rightful user of the room.

    We recommend you go through the verification process for each device before continuing, but you can resend @@ -94,7 +95,7 @@ export default React.createClass({

    Unknown devices:

    -
    +