Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Add support for sending/receiving events from widgets
Browse files Browse the repository at this point in the history
Part of MSC2762: matrix-org/matrix-spec-proposals#2762
Requires: matrix-org/matrix-widget-api#9

This is the bare minimum required to send an event to a widget and receive events from widgets. Like the view_room action, this is controlled by a well-known permission key.

**Danger**: This allows widgets to potentially modify room state. Use the permissions with care.
  • Loading branch information
turt2live committed Nov 3, 2020
1 parent e15041b commit f5cd079
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 1 deletion.
32 changes: 32 additions & 0 deletions src/stores/widgets/StopGapWidget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ import ThemeWatcher from "../../settings/watchers/ThemeWatcher";
import {getCustomTheme} from "../../theme";
import CountlyAnalytics from "../../CountlyAnalytics";
import { ElementWidgetCapabilities } from "./ElementWidgetCapabilities";
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import ActiveRoomObserver from "../../ActiveRoomObserver";

// TODO: Destroy all of this code

Expand Down Expand Up @@ -329,6 +331,10 @@ export class StopGapWidget extends EventEmitter {
this.messaging.transport.reply(ev.detail, <IWidgetApiRequestEmptyData>{});
});

// Attach listeners for feeding events - the underlying widget classes handle permissions for us
MatrixClientPeg.get().on('event', this.onEvent);
MatrixClientPeg.get().on('Event.decrypted', this.onEventDecrypted);

if (WidgetType.JITSI.matches(this.mockWidget.type)) {
this.messaging.on("action:set_always_on_screen",
(ev: CustomEvent<IStickyActionRequest>) => {
Expand Down Expand Up @@ -422,5 +428,31 @@ export class StopGapWidget extends EventEmitter {
if (!this.started) return;
WidgetMessagingStore.instance.stopMessaging(this.mockWidget);
ActiveWidgetStore.delRoomId(this.mockWidget.id);

if (MatrixClientPeg.get()) {
MatrixClientPeg.get().off('event', this.onEvent);
MatrixClientPeg.get().off('Event.decrypted', this.onEventDecrypted);
}
}

private onEvent = (ev: MatrixEvent) => {
if (ev.isBeingDecrypted() || ev.isDecryptionFailure()) return;
if (ev.getRoomId() !== ActiveRoomObserver.activeRoomId) return;
this.feedEvent(ev);
};

private onEventDecrypted = (ev: MatrixEvent) => {
if (ev.isDecryptionFailure()) return;
if (ev.getRoomId() !== ActiveRoomObserver.activeRoomId) return;
this.feedEvent(ev);
};

private feedEvent(ev: MatrixEvent) {
if (!this.messaging) return;

const raw = ev.event;
this.messaging.feedEvent(raw).catch(e => {
console.error("Error sending event to widget: ", e);
});
}
}
26 changes: 25 additions & 1 deletion src/stores/widgets/StopGapWidgetDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@
* limitations under the License.
*/

import { Capability, WidgetDriver, WidgetType } from "matrix-widget-api";
import { Capability, ISendEventDetails, WidgetDriver, WidgetEventCapability, WidgetType } from "matrix-widget-api";
import { iterableUnion } from "../../utils/iterables";
import { MatrixClientPeg } from "../../MatrixClientPeg";
import { arrayFastClone } from "../../utils/arrays";
import { ElementWidgetCapabilities } from "./ElementWidgetCapabilities";
import ActiveRoomObserver from "../../ActiveRoomObserver";

// TODO: Purge this from the universe

Expand Down Expand Up @@ -47,7 +48,30 @@ export class StopGapWidgetDriver extends WidgetDriver {
allowedCaps.push(ElementWidgetCapabilities.CanChangeViewedRoom);
}
}
if (Array.isArray(wkPerms["event_actions"])) {
if (wkPerms["event_actions"].includes(this.forType)) {
allowedCaps.push(...WidgetEventCapability.findEventCapabilities(requested).map(c => c.raw));
}
}
}
return new Set(iterableUnion(requested, allowedCaps));
}

public async sendEvent(eventType: string, content: any, stateKey: string = null): Promise<ISendEventDetails> {
const client = MatrixClientPeg.get();
const roomId = ActiveRoomObserver.activeRoomId;

if (!client || !roomId) throw new Error("Not in a room or not attached to a client");

let r: {event_id: string} = null;
if (stateKey !== null) {
// state event
r = await client.sendStateEvent(roomId, eventType, content, stateKey);
} else {
// message event
r = await client.sendEvent(roomId, eventType, content);
}

return {roomId, eventId: r.event_id};
}
}

0 comments on commit f5cd079

Please sign in to comment.