Wire up the widget permission prompt to the cross-platform setting
This doesn't have any backwards compatibility with anyone who has already clicked "Allow". We kinda want everyone to read the new prompt, so what better way to do it than effectively revoke all widget permissions? Part of https://github.com/vector-im/riot-web/issues/11262
This commit is contained in:
parent
fea8737632
commit
b185eed462
4 changed files with 41 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);
|
||||||
this.setState({hasPermissionToLoad: true});
|
const current = SettingsStore.getValue("allowedWidgets", roomId);
|
||||||
// Now that we have permission, fetch the IM token
|
current[this.props.eventId] = true;
|
||||||
this.setScalarToken();
|
SettingsStore.setValue("allowedWidgets", roomId, SettingLevel.ROOM_ACCOUNT, current).then(() => {
|
||||||
|
this.setState({hasPermissionToLoad: true});
|
||||||
|
|
||||||
|
// Fetch a token for the integration manager, now that we're allowed to
|
||||||
|
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);
|
||||||
this.setState({hasPermissionToLoad: false});
|
const current = SettingsStore.getValue("allowedWidgets", roomId);
|
||||||
|
current[this.props.eventId] = false;
|
||||||
|
SettingsStore.setValue("allowedWidgets", roomId, SettingLevel.ROOM_ACCOUNT, current).then(() => {
|
||||||
|
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,14 @@ 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,7 @@ 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 +159,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