From 4d9890e4138517db5d9d0641200f20a9d41f774a 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/src/components/views/elements/AppTile.tsx b/src/components/views/elements/AppTile.tsx index c56a23e43d..ee3dfddd2a 100644 --- a/src/components/views/elements/AppTile.tsx +++ b/src/components/views/elements/AppTile.tsx @@ -193,6 +193,9 @@ export default class AppTile extends React.Component { // This is a function to make the impact of calling SettingsStore slightly less private hasPermissionToLoad = (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 const opts: ApprovalOpts = { approved: undefined }; diff --git a/src/customisations/WidgetPermissions.ts b/src/customisations/WidgetPermissions.ts index 785ca46c2e..35efa1202f 100644 --- a/src/customisations/WidgetPermissions.ts +++ b/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/src/stores/widgets/ElementWidgetDriver.ts b/src/stores/widgets/ElementWidgetDriver.ts index e341f7627c..f266d21f1e 100644 --- a/src/stores/widgets/ElementWidgetDriver.ts +++ b/src/stores/widgets/ElementWidgetDriver.ts @@ -104,6 +104,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); @@ -573,6 +616,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(), + }); + } + const opts: ApprovalOpts = { approved: undefined }; ModuleRunner.instance.invoke(WidgetLifecycle.IdentityRequest, opts, this.forWidget); if (opts.approved) {