From 76f4f88fcd527ad2393f7f6cb249ad2592b250b6 Mon Sep 17 00:00:00 2001 From: Richard Lewis Date: Wed, 26 Jul 2017 11:28:43 +0100 Subject: [PATCH 01/32] App tile permissions -- broken --- .../views/elements/AppPermission.js | 43 +++++++++++++++++ src/components/views/elements/AppTile.js | 47 +++++++++++++------ 2 files changed, 76 insertions(+), 14 deletions(-) create mode 100644 src/components/views/elements/AppPermission.js diff --git a/src/components/views/elements/AppPermission.js b/src/components/views/elements/AppPermission.js new file mode 100644 index 0000000000..a6ecd7b5f7 --- /dev/null +++ b/src/components/views/elements/AppPermission.js @@ -0,0 +1,43 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { URL, URLSearchParams } from 'url'; + +export default class AppPermission extends React.Component { + constructor(props) { + super(props); + + this.state = { + curl: this.getCurl(), + }; + } + + getCurl() { + let wurl = URL.parse(this.props.url); + console.log('wurl', wurl); + if(wurl.searchParams.get('url')) { + let curl = wurl.searchParams.get('url'); + console.log('curl', curl); + } + } + + render() { + return ( +
+ Load widget with URL : {this.state.cUrl} + +
+ ); + } +} + +AppPermission.propTypes = { + url: PropTypes.string.isRequired, + onPermissionGranted: PropTypes.func.isRequired, +}; +AppPermission.defaultPropTypes = { + onPermissionGranted: function() {}, +}; diff --git a/src/components/views/elements/AppTile.js b/src/components/views/elements/AppTile.js index 9573b9fd9f..994b613b41 100644 --- a/src/components/views/elements/AppTile.js +++ b/src/components/views/elements/AppTile.js @@ -24,6 +24,7 @@ import SdkConfig from '../../../SdkConfig'; import Modal from '../../../Modal'; import { _t } from '../../../languageHandler'; import sdk from '../../../index'; +import AppPermission from './AppPermission'; const ALLOWED_APP_URL_SCHEMES = ['https:', 'http:']; const betaHelpMsg = 'This feature is currently experimental and is intended for beta testing only'; @@ -46,9 +47,12 @@ export default React.createClass({ }, getInitialState: function() { + const widgetPermissionId = [this.props.room.roomId, encodeURIComponent(this.props.url)].join('_'); return { loading: false, widgetUrl: this.props.url, + widgetPermissionId: widgetPermissionId, + hasPermissionToLoad: localStorage.getItem(widgetPermissionId), error: null, deleting: false, }; @@ -116,6 +120,11 @@ export default React.createClass({ }); }, + _grantWidgetPermission() { + console.warn('Granting permission to load widget - ', this.state.widgetUrl); + localStorage.setItem(this.state.widgetPermissionId, true); + }, + formatAppTileName: function() { let appTileName = "No name"; if(this.props.name && this.props.name.trim()) { @@ -133,30 +142,40 @@ export default React.createClass({ return
; } + // Note that there is advice saying allow-scripts shouldn't be used with allow-same-origin + // because that would allow the iframe to prgramatically remove the sandbox attribute, but + // this would only be for content hosted on the same origin as the riot client: anything + // hosted on the same origin as the client will get the same access as if you clicked + // a link to it. + const sandboxFlags = "allow-forms allow-popups allow-popups-to-escape-sandbox "+ + "allow-same-origin allow-scripts"; + const parsedWidgetUrl = url.parse(this.state.widgetUrl); + let safeWidgetUrl = ''; + if (ALLOWED_APP_URL_SCHEMES.indexOf(parsedWidgetUrl.protocol) !== -1) { + safeWidgetUrl = url.format(parsedWidgetUrl); + } + if (this.state.loading) { appTileBody = (
Loading...
); - } else { - // Note that there is advice saying allow-scripts shouldn't be used with allow-same-origin - // because that would allow the iframe to prgramatically remove the sandbox attribute, but - // this would only be for content hosted on the same origin as the riot client: anything - // hosted on the same origin as the client will get the same access as if you clicked - // a link to it. - const sandboxFlags = "allow-forms allow-popups allow-popups-to-escape-sandbox "+ - "allow-same-origin allow-scripts"; - const parsedWidgetUrl = url.parse(this.state.widgetUrl); - let safeWidgetUrl = ''; - if (ALLOWED_APP_URL_SCHEMES.indexOf(parsedWidgetUrl.protocol) !== -1) { - safeWidgetUrl = url.format(parsedWidgetUrl); - } + } else if (this.state.hasPermissionToLoad === true) { appTileBody = (
-
); + } else { + appTileBody = ( + + ); } // editing is done in scalar From 9f52c13bea3f706ba004a61b673427d2bc292156 Mon Sep 17 00:00:00 2001 From: Richard Lewis Date: Wed, 26 Jul 2017 16:47:58 +0100 Subject: [PATCH 02/32] Grant permission to load app widget. --- .../views/elements/AppPermission.js | 29 +++++++++++++------ src/components/views/elements/AppTile.js | 1 + 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/components/views/elements/AppPermission.js b/src/components/views/elements/AppPermission.js index a6ecd7b5f7..ad697e2df0 100644 --- a/src/components/views/elements/AppPermission.js +++ b/src/components/views/elements/AppPermission.js @@ -1,30 +1,41 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { URL, URLSearchParams } from 'url'; +import url from 'url'; export default class AppPermission extends React.Component { constructor(props) { super(props); + const curl = this.getCurl(); this.state = { - curl: this.getCurl(), + curl: curl, }; + console.log('curl', curl); } getCurl() { - let wurl = URL.parse(this.props.url); - console.log('wurl', wurl); - if(wurl.searchParams.get('url')) { - let curl = wurl.searchParams.get('url'); - console.log('curl', curl); + const wurl = url.parse(this.props.url); + let curl; + + const searchParams = new URLSearchParams(wurl.search); + if(searchParams && searchParams.get('url')) { + curl = searchParams.get('url'); } + curl = curl || wurl; + return curl; } render() { return ( -
- Load widget with URL : {this.state.cUrl} +
+
+ Warning +
+
+ Do you want to load widget from URL?: {this.state.curl} +
); } From f2058e0a6cb053ab6b3a5d350aef149370fde042 Mon Sep 17 00:00:00 2001 From: Richard Lewis Date: Thu, 27 Jul 2017 16:41:20 +0100 Subject: [PATCH 03/32] Add message spinner component. --- .../views/elements/MessageSpinner.js | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/components/views/elements/MessageSpinner.js diff --git a/src/components/views/elements/MessageSpinner.js b/src/components/views/elements/MessageSpinner.js new file mode 100644 index 0000000000..93995a83dc --- /dev/null +++ b/src/components/views/elements/MessageSpinner.js @@ -0,0 +1,36 @@ +/* +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. +*/ + +'use strict'; + +const React = require('react'); + +module.exports = React.createClass({ + displayName: 'MessageSpinner', + + render: function() { + const w = this.props.w || 32; + const h = this.props.h || 32; + const imgClass = this.props.imgClassName || ""; + const msg = this.props.msg || "Loading..."; + return ( +
+
{msg}
  + +
+ ); + }, +}); From 8e4f1f09899ded2d7ae0c0b4971c0cc104a88d27 Mon Sep 17 00:00:00 2001 From: Richard Lewis Date: Thu, 27 Jul 2017 16:41:52 +0100 Subject: [PATCH 04/32] Add message spinner. --- src/components/views/elements/AppTile.js | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/components/views/elements/AppTile.js b/src/components/views/elements/AppTile.js index 522db7399e..36954ff25f 100644 --- a/src/components/views/elements/AppTile.js +++ b/src/components/views/elements/AppTile.js @@ -25,6 +25,7 @@ import Modal from '../../../Modal'; import { _t } from '../../../languageHandler'; import sdk from '../../../index'; import AppPermission from './AppPermission'; +import MessageSpinner from './MessageSpinner'; const ALLOWED_APP_URL_SCHEMES = ['https:', 'http:']; const betaHelpMsg = 'This feature is currently experimental and is intended for beta testing only'; @@ -38,6 +39,7 @@ export default React.createClass({ name: React.PropTypes.string.isRequired, room: React.PropTypes.object.isRequired, type: React.PropTypes.string.isRequired, + fullWidth: React.PropTypes.bool, }, getDefaultProps: function() { @@ -48,11 +50,12 @@ export default React.createClass({ getInitialState: function() { const widgetPermissionId = [this.props.room.roomId, encodeURIComponent(this.props.url)].join('_'); + const hasPermissionToLoad = localStorage.getItem(widgetPermissionId); return { loading: false, widgetUrl: this.props.url, widgetPermissionId: widgetPermissionId, - hasPermissionToLoad: localStorage.getItem(widgetPermissionId), + hasPermissionToLoad: Boolean(hasPermissionToLoad === 'true'), error: null, deleting: false, }; @@ -123,6 +126,7 @@ export default React.createClass({ _grantWidgetPermission() { console.warn('Granting permission to load widget - ', this.state.widgetUrl); localStorage.setItem(this.state.widgetPermissionId, true); + this.setState({hasPermissionToLoad: true}); }, formatAppTileName: function() { @@ -157,9 +161,11 @@ export default React.createClass({ if (this.state.loading) { appTileBody = ( -
Loading...
+
+ +
); - } else if (this.state.hasPermissionToLoad === true) { + } else if (this.state.hasPermissionToLoad == true) { appTileBody = (