Use the WidgetDriver to run OIDC requests

Fixes https://github.com/vector-im/element-web/issues/15775
This commit is contained in:
Travis Ralston 2020-11-23 14:10:14 -07:00
parent 2144932bbc
commit 28c78509a1
2 changed files with 42 additions and 57 deletions

View file

@ -17,8 +17,6 @@
import { Room } from "matrix-js-sdk/src/models/room"; import { Room } from "matrix-js-sdk/src/models/room";
import { import {
ClientWidgetApi, ClientWidgetApi,
IGetOpenIDActionRequest,
IGetOpenIDActionResponseData,
IStickerActionRequest, IStickerActionRequest,
IStickyActionRequest, IStickyActionRequest,
ITemplateParams, ITemplateParams,
@ -27,10 +25,8 @@ import {
IWidgetApiRequestEmptyData, IWidgetApiRequestEmptyData,
IWidgetData, IWidgetData,
MatrixCapabilities, MatrixCapabilities,
OpenIDRequestState,
runTemplate, runTemplate,
Widget, Widget,
WidgetApiToWidgetAction,
WidgetApiFromWidgetAction, WidgetApiFromWidgetAction,
IModalWidgetOpenRequest, IModalWidgetOpenRequest,
IWidgetApiErrorResponseData, IWidgetApiErrorResponseData,
@ -50,8 +46,6 @@ import ActiveWidgetStore from "../ActiveWidgetStore";
import { objectShallowClone } from "../../utils/objects"; import { objectShallowClone } from "../../utils/objects";
import defaultDispatcher from "../../dispatcher/dispatcher"; import defaultDispatcher from "../../dispatcher/dispatcher";
import { ElementWidgetActions, IViewRoomApiRequest } from "./ElementWidgetActions"; import { ElementWidgetActions, IViewRoomApiRequest } from "./ElementWidgetActions";
import Modal from "../../Modal";
import WidgetOpenIDPermissionsDialog from "../../components/views/dialogs/WidgetOpenIDPermissionsDialog";
import {ModalWidgetStore} from "../ModalWidgetStore"; import {ModalWidgetStore} from "../ModalWidgetStore";
import ThemeWatcher from "../../settings/watchers/ThemeWatcher"; import ThemeWatcher from "../../settings/watchers/ThemeWatcher";
import {getCustomTheme} from "../../theme"; import {getCustomTheme} from "../../theme";
@ -235,55 +229,6 @@ export class StopGapWidget extends EventEmitter {
return this.messaging.widget.id; return this.messaging.widget.id;
} }
private onOpenIdReq = async (ev: CustomEvent<IGetOpenIDActionRequest>) => {
ev.preventDefault();
const rawUrl = this.appTileProps.app.url;
const widgetSecurityKey = WidgetUtils.getWidgetSecurityKey(this.widgetId, rawUrl, this.appTileProps.userWidget);
const settings = SettingsStore.getValue("widgetOpenIDPermissions");
if (settings.deny && settings.deny.includes(widgetSecurityKey)) {
this.messaging.transport.reply(ev.detail, <IGetOpenIDActionResponseData>{
state: OpenIDRequestState.Blocked,
});
return;
}
if (settings.allow && settings.allow.includes(widgetSecurityKey)) {
const credentials = await MatrixClientPeg.get().getOpenIdToken();
this.messaging.transport.reply(ev.detail, <IGetOpenIDActionResponseData>{
state: OpenIDRequestState.Allowed,
...credentials,
});
return;
}
// Confirm that we received the request
this.messaging.transport.reply(ev.detail, <IGetOpenIDActionResponseData>{
state: OpenIDRequestState.PendingUserConfirmation,
});
// Actually ask for permission to send the user's data
Modal.createTrackedDialog("OpenID widget permissions", '', WidgetOpenIDPermissionsDialog, {
widgetUrl: rawUrl,
widgetId: this.widgetId,
isUserWidget: this.appTileProps.userWidget,
onFinished: async (confirm) => {
const responseBody: IGetOpenIDActionResponseData = {
state: confirm ? OpenIDRequestState.Allowed : OpenIDRequestState.Blocked,
original_request_id: ev.detail.requestId, // eslint-disable-line camelcase
};
if (confirm) {
const credentials = await MatrixClientPeg.get().getOpenIdToken();
Object.assign(responseBody, credentials);
}
this.messaging.transport.send(WidgetApiToWidgetAction.OpenIDCredentials, responseBody).catch(error => {
console.error("Failed to send OpenID credentials: ", error);
});
},
});
};
private onOpenModal = async (ev: CustomEvent<IModalWidgetOpenRequest>) => { private onOpenModal = async (ev: CustomEvent<IModalWidgetOpenRequest>) => {
ev.preventDefault(); ev.preventDefault();
if (ModalWidgetStore.instance.canOpenModalWidget()) { if (ModalWidgetStore.instance.canOpenModalWidget()) {
@ -305,7 +250,6 @@ export class StopGapWidget extends EventEmitter {
this.messaging = new ClientWidgetApi(this.mockWidget, iframe, driver); this.messaging = new ClientWidgetApi(this.mockWidget, iframe, driver);
this.messaging.on("preparing", () => this.emit("preparing")); this.messaging.on("preparing", () => this.emit("preparing"));
this.messaging.on("ready", () => this.emit("ready")); this.messaging.on("ready", () => this.emit("ready"));
this.messaging.on(`action:${WidgetApiFromWidgetAction.GetOpenIDCredentials}`, this.onOpenIdReq);
this.messaging.on(`action:${WidgetApiFromWidgetAction.OpenModalWidget}`, this.onOpenModal); this.messaging.on(`action:${WidgetApiFromWidgetAction.OpenModalWidget}`, this.onOpenModal);
WidgetMessagingStore.instance.storeMessaging(this.mockWidget, this.messaging); WidgetMessagingStore.instance.storeMessaging(this.mockWidget, this.messaging);

View file

@ -16,8 +16,12 @@
import { import {
Capability, Capability,
IOpenIDCredentials,
IOpenIDUpdate,
ISendEventDetails, ISendEventDetails,
MatrixCapabilities, MatrixCapabilities,
OpenIDRequestState,
SimpleObservable,
Widget, Widget,
WidgetDriver, WidgetDriver,
WidgetKind, WidgetKind,
@ -26,6 +30,9 @@ import { iterableDiff, iterableUnion } from "../../utils/iterables";
import { MatrixClientPeg } from "../../MatrixClientPeg"; import { MatrixClientPeg } from "../../MatrixClientPeg";
import ActiveRoomObserver from "../../ActiveRoomObserver"; import ActiveRoomObserver from "../../ActiveRoomObserver";
import Modal from "../../Modal"; import Modal from "../../Modal";
import WidgetUtils from "../../utils/WidgetUtils";
import SettingsStore from "../../settings/SettingsStore";
import WidgetOpenIDPermissionsDialog from "../../components/views/dialogs/WidgetOpenIDPermissionsDialog";
import WidgetCapabilitiesPromptDialog, { import WidgetCapabilitiesPromptDialog, {
getRememberedCapabilitiesForWidget, getRememberedCapabilitiesForWidget,
} from "../../components/views/dialogs/WidgetCapabilitiesPromptDialog"; } from "../../components/views/dialogs/WidgetCapabilitiesPromptDialog";
@ -79,7 +86,7 @@ export class StopGapWidgetDriver extends WidgetDriver {
if (!client || !roomId) throw new Error("Not in a room or not attached to a client"); if (!client || !roomId) throw new Error("Not in a room or not attached to a client");
let r: {event_id: string} = null; // eslint-disable-line camelcase let r: { event_id: string } = null; // eslint-disable-line camelcase
if (stateKey !== null) { if (stateKey !== null) {
// state event // state event
r = await client.sendStateEvent(roomId, eventType, content, stateKey); r = await client.sendStateEvent(roomId, eventType, content, stateKey);
@ -90,4 +97,38 @@ export class StopGapWidgetDriver extends WidgetDriver {
return {roomId, eventId: r.event_id}; return {roomId, eventId: r.event_id};
} }
public async askOpenID(observer: SimpleObservable<IOpenIDUpdate>) {
const isUserWidget = this.forWidgetKind !== WidgetKind.Room; // modal and account widgets are "user" widgets
const rawUrl = this.forWidget.templateUrl;
const widgetSecurityKey = WidgetUtils.getWidgetSecurityKey(this.forWidget.id, rawUrl, isUserWidget);
const getToken = (): Promise<IOpenIDCredentials> => {
return MatrixClientPeg.get().getOpenIdToken();
};
const settings = SettingsStore.getValue("widgetOpenIDPermissions");
if (settings?.deny?.includes(widgetSecurityKey)) {
return observer.update({state: OpenIDRequestState.Blocked});
}
if (settings?.allow?.includes(widgetSecurityKey)) {
return observer.update({state: OpenIDRequestState.Allowed, token: await getToken()});
}
observer.update({state: OpenIDRequestState.PendingUserConfirmation});
Modal.createTrackedDialog("OpenID widget permissions", '', WidgetOpenIDPermissionsDialog, {
widgetUrl: rawUrl,
widgetId: this.forWidget.id,
isUserWidget: isUserWidget,
onFinished: async (confirm) => {
if (!confirm) {
return observer.update({state: OpenIDRequestState.Blocked});
}
return observer.update({state: OpenIDRequestState.Allowed, token: await getToken()});
},
});
}
} }