Merge pull request #3630 from matrix-org/travis/widget-permission
Wire up the widget permission prompt to the cross-platform setting
This commit is contained in:
commit
1c1b8cf6b9
4 changed files with 44 additions and 21 deletions
|
@ -34,7 +34,7 @@ import dis from '../../../dispatcher';
|
||||||
import ActiveWidgetStore from '../../../stores/ActiveWidgetStore';
|
import ActiveWidgetStore from '../../../stores/ActiveWidgetStore';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import {IntegrationManagers} from "../../../integrations/IntegrationManagers";
|
import {IntegrationManagers} from "../../../integrations/IntegrationManagers";
|
||||||
import SettingsStore from "../../../settings/SettingsStore";
|
import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore";
|
||||||
|
|
||||||
const ALLOWED_APP_URL_SCHEMES = ['https:', 'http:'];
|
const ALLOWED_APP_URL_SCHEMES = ['https:', 'http:'];
|
||||||
const ENABLE_REACT_PERF = false;
|
const ENABLE_REACT_PERF = false;
|
||||||
|
@ -69,8 +69,11 @@ export default class AppTile extends React.Component {
|
||||||
* @return {Object} Updated component state to be set with setState
|
* @return {Object} Updated component state to be set with setState
|
||||||
*/
|
*/
|
||||||
_getNewState(newProps) {
|
_getNewState(newProps) {
|
||||||
const widgetPermissionId = [newProps.room.roomId, encodeURIComponent(newProps.url)].join('_');
|
// This is a function to make the impact of calling SettingsStore slightly less
|
||||||
const hasPermissionToLoad = localStorage.getItem(widgetPermissionId);
|
const hasPermissionToLoad = () => {
|
||||||
|
const currentlyAllowedWidgets = SettingsStore.getValue("allowedWidgets", newProps.room.roomId);
|
||||||
|
return !!currentlyAllowedWidgets[newProps.eventId];
|
||||||
|
};
|
||||||
|
|
||||||
const PersistedElement = sdk.getComponent("elements.PersistedElement");
|
const PersistedElement = sdk.getComponent("elements.PersistedElement");
|
||||||
return {
|
return {
|
||||||
|
@ -78,10 +81,9 @@ export default class AppTile extends React.Component {
|
||||||
// True while the iframe content is loading
|
// True while the iframe content is loading
|
||||||
loading: this.props.waitForIframeLoad && !PersistedElement.isMounted(this._persistKey),
|
loading: this.props.waitForIframeLoad && !PersistedElement.isMounted(this._persistKey),
|
||||||
widgetUrl: this._addWurlParams(newProps.url),
|
widgetUrl: this._addWurlParams(newProps.url),
|
||||||
widgetPermissionId: widgetPermissionId,
|
|
||||||
// Assume that widget has permission to load if we are the user who
|
// Assume that widget has permission to load if we are the user who
|
||||||
// added it to the room, or if explicitly granted by the user
|
// added it to the room, or if explicitly granted by the user
|
||||||
hasPermissionToLoad: hasPermissionToLoad === 'true' || newProps.userId === newProps.creatorUserId,
|
hasPermissionToLoad: newProps.userId === newProps.creatorUserId || hasPermissionToLoad(),
|
||||||
error: null,
|
error: null,
|
||||||
deleting: false,
|
deleting: false,
|
||||||
widgetPageTitle: newProps.widgetPageTitle,
|
widgetPageTitle: newProps.widgetPageTitle,
|
||||||
|
@ -446,24 +448,38 @@ export default class AppTile extends React.Component {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO -- Store permission in account data so that it is persisted across multiple devices */
|
|
||||||
_grantWidgetPermission() {
|
_grantWidgetPermission() {
|
||||||
console.warn('Granting permission to load widget - ', this.state.widgetUrl);
|
const roomId = this.props.room.roomId;
|
||||||
localStorage.setItem(this.state.widgetPermissionId, true);
|
console.info("Granting permission for widget to load: " + this.props.eventId);
|
||||||
|
const current = SettingsStore.getValue("allowedWidgets", roomId);
|
||||||
|
current[this.props.eventId] = true;
|
||||||
|
SettingsStore.setValue("allowedWidgets", roomId, SettingLevel.ROOM_ACCOUNT, current).then(() => {
|
||||||
this.setState({hasPermissionToLoad: true});
|
this.setState({hasPermissionToLoad: true});
|
||||||
// Now that we have permission, fetch the IM token
|
|
||||||
|
// Fetch a token for the integration manager, now that we're allowed to
|
||||||
this.setScalarToken();
|
this.setScalarToken();
|
||||||
|
}).catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
// We don't really need to do anything about this - the user will just hit the button again.
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_revokeWidgetPermission() {
|
_revokeWidgetPermission() {
|
||||||
console.warn('Revoking permission to load widget - ', this.state.widgetUrl);
|
const roomId = this.props.room.roomId;
|
||||||
localStorage.removeItem(this.state.widgetPermissionId);
|
console.info("Revoking permission for widget to load: " + this.props.eventId);
|
||||||
|
const current = SettingsStore.getValue("allowedWidgets", roomId);
|
||||||
|
current[this.props.eventId] = false;
|
||||||
|
SettingsStore.setValue("allowedWidgets", roomId, SettingLevel.ROOM_ACCOUNT, current).then(() => {
|
||||||
this.setState({hasPermissionToLoad: false});
|
this.setState({hasPermissionToLoad: false});
|
||||||
|
|
||||||
// Force the widget to be non-persistent
|
// Force the widget to be non-persistent (able to be deleted/forgotten)
|
||||||
ActiveWidgetStore.destroyPersistentWidget(this.props.id);
|
ActiveWidgetStore.destroyPersistentWidget(this.props.id);
|
||||||
const PersistedElement = sdk.getComponent("elements.PersistedElement");
|
const PersistedElement = sdk.getComponent("elements.PersistedElement");
|
||||||
PersistedElement.destroyElement(this._persistKey);
|
PersistedElement.destroyElement(this._persistKey);
|
||||||
|
}).catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
// We don't really need to do anything about this - the user will just hit the button again.
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
formatAppTileName() {
|
formatAppTileName() {
|
||||||
|
@ -720,6 +736,7 @@ AppTile.displayName ='AppTile';
|
||||||
|
|
||||||
AppTile.propTypes = {
|
AppTile.propTypes = {
|
||||||
id: PropTypes.string.isRequired,
|
id: PropTypes.string.isRequired,
|
||||||
|
eventId: PropTypes.string, // required for room widgets
|
||||||
url: PropTypes.string.isRequired,
|
url: PropTypes.string.isRequired,
|
||||||
name: PropTypes.string.isRequired,
|
name: PropTypes.string.isRequired,
|
||||||
room: PropTypes.object.isRequired,
|
room: PropTypes.object.isRequired,
|
||||||
|
|
|
@ -67,13 +67,15 @@ module.exports = createReactClass({
|
||||||
return ev.getStateKey() === ActiveWidgetStore.getPersistentWidgetId();
|
return ev.getStateKey() === ActiveWidgetStore.getPersistentWidgetId();
|
||||||
});
|
});
|
||||||
const app = WidgetUtils.makeAppConfig(
|
const app = WidgetUtils.makeAppConfig(
|
||||||
appEvent.getStateKey(), appEvent.getContent(), appEvent.getSender(), persistentWidgetInRoomId,
|
appEvent.getStateKey(), appEvent.getContent(), appEvent.getSender(),
|
||||||
|
persistentWidgetInRoomId, appEvent.getId(),
|
||||||
);
|
);
|
||||||
const capWhitelist = WidgetUtils.getCapWhitelistForAppTypeInRoomId(app.type, persistentWidgetInRoomId);
|
const capWhitelist = WidgetUtils.getCapWhitelistForAppTypeInRoomId(app.type, persistentWidgetInRoomId);
|
||||||
const AppTile = sdk.getComponent('elements.AppTile');
|
const AppTile = sdk.getComponent('elements.AppTile');
|
||||||
return <AppTile
|
return <AppTile
|
||||||
key={app.id}
|
key={app.id}
|
||||||
id={app.id}
|
id={app.id}
|
||||||
|
eventId={app.eventId}
|
||||||
url={app.url}
|
url={app.url}
|
||||||
name={app.name}
|
name={app.name}
|
||||||
type={app.type}
|
type={app.type}
|
||||||
|
|
|
@ -107,7 +107,9 @@ module.exports = createReactClass({
|
||||||
this.props.room.roomId, WidgetUtils.getRoomWidgets(this.props.room),
|
this.props.room.roomId, WidgetUtils.getRoomWidgets(this.props.room),
|
||||||
);
|
);
|
||||||
return widgets.map((ev) => {
|
return widgets.map((ev) => {
|
||||||
return WidgetUtils.makeAppConfig(ev.getStateKey(), ev.getContent(), ev.getSender());
|
return WidgetUtils.makeAppConfig(
|
||||||
|
ev.getStateKey(), ev.getContent(), ev.getSender(), ev.getRoomId(), ev.getId(),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -159,6 +161,7 @@ module.exports = createReactClass({
|
||||||
return (<AppTile
|
return (<AppTile
|
||||||
key={app.id}
|
key={app.id}
|
||||||
id={app.id}
|
id={app.id}
|
||||||
|
eventId={app.eventId}
|
||||||
url={app.url}
|
url={app.url}
|
||||||
name={app.name}
|
name={app.name}
|
||||||
type={app.type}
|
type={app.type}
|
||||||
|
|
|
@ -400,7 +400,7 @@ export default class WidgetUtils {
|
||||||
return client.setAccountData('m.widgets', userWidgets);
|
return client.setAccountData('m.widgets', userWidgets);
|
||||||
}
|
}
|
||||||
|
|
||||||
static makeAppConfig(appId, app, senderUserId, roomId) {
|
static makeAppConfig(appId, app, senderUserId, roomId, eventId) {
|
||||||
const myUserId = MatrixClientPeg.get().credentials.userId;
|
const myUserId = MatrixClientPeg.get().credentials.userId;
|
||||||
const user = MatrixClientPeg.get().getUser(myUserId);
|
const user = MatrixClientPeg.get().getUser(myUserId);
|
||||||
const params = {
|
const params = {
|
||||||
|
@ -419,6 +419,7 @@ export default class WidgetUtils {
|
||||||
app.creatorUserId = senderUserId;
|
app.creatorUserId = senderUserId;
|
||||||
|
|
||||||
app.id = appId;
|
app.id = appId;
|
||||||
|
app.eventId = eventId;
|
||||||
app.name = app.name || app.type;
|
app.name = app.name || app.type;
|
||||||
|
|
||||||
if (app.data) {
|
if (app.data) {
|
||||||
|
|
Loading…
Reference in a new issue