From 7cd8a5a2b230ac78c12cc40bddab10dcf9fce59f Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 20 Jun 2018 18:01:37 +0100 Subject: [PATCH 01/28] allow chaining right click contextmenus Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/structures/ContextualMenu.js | 26 +++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/components/structures/ContextualMenu.js b/src/components/structures/ContextualMenu.js index 91ec312f43..e5b3bd0b71 100644 --- a/src/components/structures/ContextualMenu.js +++ b/src/components/structures/ContextualMenu.js @@ -64,7 +64,9 @@ export default class ContextualMenu extends React.Component { // The component to render as the context menu elementClass: PropTypes.element.isRequired, // on resize callback - windowResize: PropTypes.func + windowResize: PropTypes.func, + // method to close menu + closeMenu: PropTypes.func, }; constructor() { @@ -73,6 +75,7 @@ export default class ContextualMenu extends React.Component { contextMenuRect: null, }; + this.onContextMenu = this.onContextMenu.bind(this); this.collectContextMenuRect = this.collectContextMenuRect.bind(this); } @@ -85,6 +88,25 @@ export default class ContextualMenu extends React.Component { }); } + onContextMenu(e) { + if (this.props.closeMenu) { + this.props.closeMenu(); + } + e.preventDefault(); + const x = e.clientX; + const y = e.clientY; + + setImmediate(() => { + const clickEvent = document.createEvent('MouseEvents'); + clickEvent.initMouseEvent( + 'contextmenu', true, true, window, 0, + 0, 0, x, y, false, false, + false, false, 0, null, + ); + document.elementFromPoint(x, y).dispatchEvent(clickEvent); + }); + } + render() { const position = {}; let chevronFace = null; @@ -195,7 +217,7 @@ export default class ContextualMenu extends React.Component { { chevron } - { props.hasBackground &&
} + { props.hasBackground &&
}
; } From 4508da56661a4e8bd80122ee1539bfddaf228449 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 20 Jun 2018 18:03:15 +0100 Subject: [PATCH 02/28] only override contextmenu if closeMenu is provided Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/structures/ContextualMenu.js | 27 +++++++++++---------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/components/structures/ContextualMenu.js b/src/components/structures/ContextualMenu.js index e5b3bd0b71..8b88cae479 100644 --- a/src/components/structures/ContextualMenu.js +++ b/src/components/structures/ContextualMenu.js @@ -91,20 +91,21 @@ export default class ContextualMenu extends React.Component { onContextMenu(e) { if (this.props.closeMenu) { this.props.closeMenu(); - } - e.preventDefault(); - const x = e.clientX; - const y = e.clientY; - setImmediate(() => { - const clickEvent = document.createEvent('MouseEvents'); - clickEvent.initMouseEvent( - 'contextmenu', true, true, window, 0, - 0, 0, x, y, false, false, - false, false, 0, null, - ); - document.elementFromPoint(x, y).dispatchEvent(clickEvent); - }); + e.preventDefault(); + const x = e.clientX; + const y = e.clientY; + + setImmediate(() => { + const clickEvent = document.createEvent('MouseEvents'); + clickEvent.initMouseEvent( + 'contextmenu', true, true, window, 0, + 0, 0, x, y, false, false, + false, false, 0, null, + ); + document.elementFromPoint(x, y).dispatchEvent(clickEvent); + }); + } } render() { From 891070d001cd6570f6156b33d8d294704fb0995f Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 21 Jun 2018 01:16:01 +0100 Subject: [PATCH 03/28] update UrlPreview settings to be more privacy-aware in e2ee rooms Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/structures/RoomView.js | 24 +++++- .../views/room_settings/UrlPreviewSettings.js | 74 ++++++++++++------- 2 files changed, 68 insertions(+), 30 deletions(-) diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index 97e575ff4e..c465eff44b 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -618,10 +618,26 @@ module.exports = React.createClass({ } }, - _updatePreviewUrlVisibility: function(room) { - this.setState({ - showUrlPreview: SettingsStore.getValue("urlPreviewsEnabled", room.roomId), - }); + _updatePreviewUrlVisibility: function({roomId}) { + const levels = [ + SettingLevel.ROOM_DEVICE, + SettingLevel.ROOM_ACCOUNT, + ]; + let showUrlPreview; + if (MatrixClientPeg.get().isRoomEncrypted(roomId)) { + for (const level of levels) { + const value = SettingsStore.getValueAt(level, "urlPreviewsEnabled", roomId, true, true); + if (value === Boolean(value)) { // if is Boolean + showUrlPreview = value; + break; + } + } + + showUrlPreview = showUrlPreview || false; + } else { + showUrlPreview = SettingsStore.getValue("urlPreviewsEnabled", roomId); + } + this.setState({showUrlPreview}); }, onRoom: function(room) { diff --git a/src/components/views/room_settings/UrlPreviewSettings.js b/src/components/views/room_settings/UrlPreviewSettings.js index ed58d610aa..749167c0a5 100644 --- a/src/components/views/room_settings/UrlPreviewSettings.js +++ b/src/components/views/room_settings/UrlPreviewSettings.js @@ -1,6 +1,7 @@ /* Copyright 2016 OpenMarket Ltd Copyright 2017 Travis Ralston +Copyright 2018 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. @@ -15,6 +16,7 @@ See the License for the specific language governing permissions and limitations under the License. */ +import {MatrixClient} from "matrix-js-sdk"; const React = require('react'); import PropTypes from 'prop-types'; const sdk = require("../../../index"); @@ -29,6 +31,10 @@ module.exports = React.createClass({ room: PropTypes.object, }, + contextTypes: { + matrixClient: PropTypes.instanceOf(MatrixClient).isRequired, + }, + saveSettings: function() { const promises = []; if (this.refs.urlPreviewsRoom) promises.push(this.refs.urlPreviewsRoom.save()); @@ -39,36 +45,52 @@ module.exports = React.createClass({ render: function() { const SettingsFlag = sdk.getComponent("elements.SettingsFlag"); const roomId = this.props.room.roomId; + const isEncrypted = this.context.matrixClient.isRoomEncrypted(roomId); let previewsForAccount = null; - if (SettingsStore.getValueAt(SettingLevel.ACCOUNT, "urlPreviewsEnabled")) { - previewsForAccount = ( - _t("You have enabled URL previews by default.", {}, { 'a': (sub)=>{ sub } }) - ); - } else { - previewsForAccount = ( - _t("You have disabled URL previews by default.", {}, { 'a': (sub)=>{ sub } }) - ); - } - let previewsForRoom = null; - if (SettingsStore.canSetValue("urlPreviewsEnabled", roomId, "room")) { - previewsForRoom = ( - - ); - } else { - let str = _td("URL previews are enabled by default for participants in this room."); - if (!SettingsStore.getValueAt(SettingLevel.ROOM, "urlPreviewsEnabled", roomId, /*explicit=*/true)) { - str = _td("URL previews are disabled by default for participants in this room."); + + + if (!isEncrypted) { + // Only show account setting state and room state setting state in non-e2ee rooms where they apply + const accountEnabled = SettingsStore.getValueAt(SettingLevel.ACCOUNT, "urlPreviewsEnabled"); + if (accountEnabled) { + previewsForAccount = ( + _t("You have enabled URL previews by default.", {}, { + 'a': (sub)=>{ sub }, + }) + ); + } else if (accountEnabled) { + previewsForAccount = ( + _t("You have disabled URL previews by default.", {}, { + 'a': (sub)=>{ sub }, + }) + ); } - previewsForRoom = (); + + if (SettingsStore.canSetValue("urlPreviewsEnabled", roomId, "room")) { + previewsForRoom = ( + + ); + } else { + let str = _td("URL previews are enabled by default for participants in this room."); + if (!SettingsStore.getValueAt(SettingLevel.ROOM, "urlPreviewsEnabled", roomId, /*explicit=*/true)) { + str = _td("URL previews are disabled by default for participants in this room."); + } + previewsForRoom = (); + } + } else { + previewsForAccount = ( + _t("URL Previews default to off in End-to-End Encrypted rooms to protect your privacy. " + + "They are requested through your homeserver which could infer links which are otherwise encrypted") + ); } const previewsForRoomAccount = ( From a45dc837b4f7649c42cb5a8db42c3492a9496981 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 21 Jun 2018 01:16:37 +0100 Subject: [PATCH 04/28] add copyright Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/structures/RoomView.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index c465eff44b..cf7d3f61e8 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -1,6 +1,7 @@ /* Copyright 2015, 2016 OpenMarket Ltd Copyright 2017 Vector Creations Ltd +Copyright 2018 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. From ed1f801254a85f2782b080740f516a9d675c49ac Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 21 Jun 2018 01:18:21 +0100 Subject: [PATCH 05/28] add comment Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/structures/RoomView.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index cf7d3f61e8..e2de91c035 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -625,6 +625,7 @@ module.exports = React.createClass({ SettingLevel.ROOM_ACCOUNT, ]; let showUrlPreview; + // in e2ee rooms only care about room-device and room-account, so that user has to explicitly enable previews if (MatrixClientPeg.get().isRoomEncrypted(roomId)) { for (const level of levels) { const value = SettingsStore.getValueAt(level, "urlPreviewsEnabled", roomId, true, true); From ed4b82f8fc4ed8a2017f4d03998faf4eb570822d Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 21 Jun 2018 01:40:16 +0100 Subject: [PATCH 06/28] update wording and style it like text (text cursor) Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- .../views/room_settings/UrlPreviewSettings.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/components/views/room_settings/UrlPreviewSettings.js b/src/components/views/room_settings/UrlPreviewSettings.js index 749167c0a5..6d3c6317d9 100644 --- a/src/components/views/room_settings/UrlPreviewSettings.js +++ b/src/components/views/room_settings/UrlPreviewSettings.js @@ -88,8 +88,9 @@ module.exports = React.createClass({ } } else { previewsForAccount = ( - _t("URL Previews default to off in End-to-End Encrypted rooms to protect your privacy. " + - "They are requested through your homeserver which could infer links which are otherwise encrypted") + _t("In encrypted rooms, like this one, URL previews are disabled by default to ensure that your " + + "homeserver (where the previews are generated) cannot gather information about links you see in " + + "this room.") ); } @@ -105,8 +106,13 @@ module.exports = React.createClass({ return (

{ _t("URL Previews") }

- - +
+ { _t('When someone puts a URL in their message, a URL preview can be shown to give more ' + + 'information about that link such as the title, description, and an image from the website.') } +
+
+ { previewsForAccount } +
{ previewsForRoom }
From acbc84a69c3374319d33fa6551597d36d8049aa9 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 22 Jun 2018 18:44:54 +0100 Subject: [PATCH 07/28] switch to another settings key for e2e url previews to protect on change Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/structures/RoomView.js | 25 ++++--------------- .../views/room_settings/UrlPreviewSettings.js | 9 +++---- src/settings/Settings.js | 7 ++++++ 3 files changed, 16 insertions(+), 25 deletions(-) diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index e2de91c035..af994d298f 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -620,26 +620,11 @@ module.exports = React.createClass({ }, _updatePreviewUrlVisibility: function({roomId}) { - const levels = [ - SettingLevel.ROOM_DEVICE, - SettingLevel.ROOM_ACCOUNT, - ]; - let showUrlPreview; - // in e2ee rooms only care about room-device and room-account, so that user has to explicitly enable previews - if (MatrixClientPeg.get().isRoomEncrypted(roomId)) { - for (const level of levels) { - const value = SettingsStore.getValueAt(level, "urlPreviewsEnabled", roomId, true, true); - if (value === Boolean(value)) { // if is Boolean - showUrlPreview = value; - break; - } - } - - showUrlPreview = showUrlPreview || false; - } else { - showUrlPreview = SettingsStore.getValue("urlPreviewsEnabled", roomId); - } - this.setState({showUrlPreview}); + // URL Previews in E2EE rooms can be a privacy leak so use a different setting which is per-room explicit + const key = MatrixClientPeg.get().isRoomEncrypted(roomId) ? 'urlPreviewsEnabled_e2ee' : 'urlPreviewsEnabled'; + this.setState({ + showUrlPreview: SettingsStore.getValue(key, roomId), + }); }, onRoom: function(room) { diff --git a/src/components/views/room_settings/UrlPreviewSettings.js b/src/components/views/room_settings/UrlPreviewSettings.js index 6d3c6317d9..fe2a2bacf4 100644 --- a/src/components/views/room_settings/UrlPreviewSettings.js +++ b/src/components/views/room_settings/UrlPreviewSettings.js @@ -50,7 +50,6 @@ module.exports = React.createClass({ let previewsForAccount = null; let previewsForRoom = null; - if (!isEncrypted) { // Only show account setting state and room state setting state in non-e2ee rooms where they apply const accountEnabled = SettingsStore.getValueAt(SettingLevel.ACCOUNT, "urlPreviewsEnabled"); @@ -73,7 +72,7 @@ module.exports = React.createClass({