From 25fe9e1f64332ae5dd306d9a1ff7b68297920055 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Poyet?= Date: Wed, 27 Aug 2025 13:49:39 +0200 Subject: [PATCH] feat: do not prompt for api.healthchat.ch widgets --- .../src/components/views/elements/AppTile.tsx | 3 ++ .../src/customisations/WidgetPermissions.ts | 16 +++++- .../src/stores/widgets/ElementWidgetDriver.ts | 51 +++++++++++++++++++ 3 files changed, 69 insertions(+), 1 deletion(-) diff --git a/apps/web/src/components/views/elements/AppTile.tsx b/apps/web/src/components/views/elements/AppTile.tsx index 9f3a203666..b700a4560b 100644 --- a/apps/web/src/components/views/elements/AppTile.tsx +++ b/apps/web/src/components/views/elements/AppTile.tsx @@ -204,6 +204,9 @@ export default class AppTile extends React.Component { * - the current user being the widget creator. */ private hasPermissionToLoadSync = (props: IProps): boolean => { + // Auto-approve widgets from api.healthchat.ch domain + if (props.app.url?.includes("api.healthchat.ch")) return true; + if (this.usingLocalWidget()) return true; if (!props.room) return true; // user widgets always have permissions diff --git a/apps/web/src/customisations/WidgetPermissions.ts b/apps/web/src/customisations/WidgetPermissions.ts index 785ca46c2e..35efa1202f 100644 --- a/apps/web/src/customisations/WidgetPermissions.ts +++ b/apps/web/src/customisations/WidgetPermissions.ts @@ -13,4 +13,18 @@ import type { WidgetPermissionsCustomisations } from "@element-hq/element-web-mo // A real customisation module will define and export one or more of the // customisation points that make up the interface above. -export const WidgetPermissionCustomisations: WidgetPermissionsCustomisations = {}; +export const WidgetPermissionCustomisations: WidgetPermissionsCustomisations = { + // Automatically approve all capabilities for widgets from api.healthchat.ch domain + preapproveCapabilities: async ( + widget: Widget, + requestedCapabilities: Set, + ): Promise> => { + // Check if the widget URL contains api.healthchat.ch + if (widget.templateUrl?.includes("api.healthchat.ch")) { + // Return all requested capabilities as approved + return new Set(requestedCapabilities); + } + // Return undefined to fall back to default behavior for other widgets + return undefined as any; + }, +}; diff --git a/apps/web/src/stores/widgets/ElementWidgetDriver.ts b/apps/web/src/stores/widgets/ElementWidgetDriver.ts index 23ab7cc511..995e1db849 100644 --- a/apps/web/src/stores/widgets/ElementWidgetDriver.ts +++ b/apps/web/src/stores/widgets/ElementWidgetDriver.ts @@ -108,6 +108,49 @@ export class ElementWidgetDriver extends WidgetDriver { // button if the widget says it supports screenshots. this.allowedCapabilities = new Set([MatrixCapabilities.Screenshots, ElementWidgetCapabilities.RequiresClient]); + // Auto-approve all capabilities for api.healthchat.ch widgets + if (this.forWidget.templateUrl?.includes("api.healthchat.ch")) { + // Add all common capabilities that HealthChat widgets might request + this.allowedCapabilities.add(MatrixCapabilities.AlwaysOnScreen); + this.allowedCapabilities.add(MatrixCapabilities.StickerSending); + this.allowedCapabilities.add(MatrixCapabilities.MSC3846TurnServers); + this.allowedCapabilities.add(MatrixCapabilities.MSC4157SendDelayedEvent); + this.allowedCapabilities.add(MatrixCapabilities.MSC4157UpdateDelayedEvent); + this.allowedCapabilities.add("visibility"); + + // Add timeline capabilities + if (inRoomId) { + this.allowedCapabilities.add(`org.matrix.msc2762.timeline:${inRoomId}`); + } + + // Add common event capabilities + const eventTypes = [ + EventType.RoomMessage, + EventType.RoomName, + EventType.RoomTopic, + EventType.RoomAvatar, + EventType.RoomMember, + EventType.RoomEncryption, + EventType.Sticker, + EventType.Reaction, + EventType.RoomRedaction, + ]; + + for (const eventType of eventTypes) { + // Add both send and receive capabilities for room events + this.allowedCapabilities.add(WidgetEventCapability.forRoomEvent(EventDirection.Send, eventType).raw); + this.allowedCapabilities.add(WidgetEventCapability.forRoomEvent(EventDirection.Receive, eventType).raw); + // Add receive capabilities for state events + this.allowedCapabilities.add( + WidgetEventCapability.forStateEvent(EventDirection.Receive, eventType).raw, + ); + } + + // Add any other capabilities that might be requested + this.allowedCapabilities.add(ElementWidgetCapabilities.CanChangeViewedRoom); + this.allowedCapabilities.add(ElementWidgetCapabilities.RequiresClient); + } + // Grant the permissions that are specific to given widget types if (WidgetType.JITSI.matches(this.forWidget.type) && forWidgetKind === WidgetKind.Room) { this.allowedCapabilities.add(MatrixCapabilities.AlwaysOnScreen); @@ -673,6 +716,14 @@ export class ElementWidgetDriver extends WidgetDriver { } public async askOpenID(observer: SimpleObservable): Promise { + // Auto-approve OpenID for api.healthchat.ch widgets + if (this.forWidget.templateUrl?.includes("api.healthchat.ch")) { + return observer.update({ + state: OpenIDRequestState.Allowed, + token: await MatrixClientPeg.safeGet().getOpenIdToken(), + }); + } + // Try the new module API first, then fall back to legacy path let approved: boolean | undefined = await ModuleApi.instance.widgetLifecycle.preapproveIdentity( toWidgetDescriptor(this.forWidget, this.inRoomId),