From f3df8bc709b1f662ad45304899cf61cd9a68a2b2 Mon Sep 17 00:00:00 2001 From: Valere Date: Mon, 12 Jan 2026 17:28:18 +0100 Subject: [PATCH] review: Use is_widget directly instead of using the packageType --- config/config.devenv.json | 3 +- src/config/ConfigOptions.ts | 4 --- src/room/RoomPage.tsx | 4 +-- src/state/initialMuteState.test.ts | 55 +++++++----------------------- src/state/initialMuteState.ts | 19 +++-------- 5 files changed, 20 insertions(+), 65 deletions(-) diff --git a/config/config.devenv.json b/config/config.devenv.json index f99c4bbd..df0ff4c1 100644 --- a/config/config.devenv.json +++ b/config/config.devenv.json @@ -15,6 +15,5 @@ "delayed_leave_event_delay_ms": 18000, "delayed_leave_event_restart_ms": 4000, "network_error_retry_ms": 100 - }, - "trust_localhost_for_mute_state": true + } } diff --git a/src/config/ConfigOptions.ts b/src/config/ConfigOptions.ts index a0d18b4a..4da633ca 100644 --- a/src/config/ConfigOptions.ts +++ b/src/config/ConfigOptions.ts @@ -165,9 +165,6 @@ export interface ResolvedConfigOptions extends ConfigOptions { }; ssla: string; app_prompt: boolean; - // For privacy reasons when lobby is skipped we do not unmute by default on full builds - // but for development builds we want to unmute by default to speed up testing. - trust_localhost_for_mute_state: boolean; } export const DEFAULT_CONFIG: ResolvedConfigOptions = { @@ -182,5 +179,4 @@ export const DEFAULT_CONFIG: ResolvedConfigOptions = { }, ssla: "https://static.element.io/legal/element-software-and-services-license-agreement-uk-1.pdf", app_prompt: true, - trust_localhost_for_mute_state: false, }; diff --git a/src/room/RoomPage.tsx b/src/room/RoomPage.tsx index 28523b44..2aee4d53 100644 --- a/src/room/RoomPage.tsx +++ b/src/room/RoomPage.tsx @@ -79,9 +79,7 @@ export const RoomPage: FC = () => { calculateInitialMuteState( urlParams.skipLobby, urlParams.callIntent, - import.meta.env.VITE_PACKAGE, - window.location.hostname, - Config.get().trust_localhost_for_mute_state, + widget !== null, ), ), ); diff --git a/src/state/initialMuteState.test.ts b/src/state/initialMuteState.test.ts index 58877ba7..abbb52cd 100644 --- a/src/state/initialMuteState.test.ts +++ b/src/state/initialMuteState.test.ts @@ -12,21 +12,21 @@ import { calculateInitialMuteState } from "./initialMuteState"; test.each<{ callIntent: RTCCallIntent; - packageType: "full" | "embedded"; + isWidgetMode: boolean; }>([ - { callIntent: "audio", packageType: "full" }, - { callIntent: "audio", packageType: "embedded" }, - { callIntent: "video", packageType: "full" }, - { callIntent: "video", packageType: "embedded" }, - { callIntent: "unknown", packageType: "full" }, - { callIntent: "unknown", packageType: "embedded" }, + { callIntent: "audio", isWidgetMode: false }, + { callIntent: "audio", isWidgetMode: true }, + { callIntent: "video", isWidgetMode: false }, + { callIntent: "video", isWidgetMode: true }, + { callIntent: "unknown", isWidgetMode: false }, + { callIntent: "unknown", isWidgetMode: true }, ])( "Should allow to unmute on start if not skipping lobby (callIntent: $callIntent, packageType: $packageType)", - ({ callIntent, packageType }) => { + ({ callIntent, isWidgetMode }) => { const { audioEnabled, videoEnabled } = calculateInitialMuteState( false, callIntent, - packageType, + isWidgetMode, ); expect(audioEnabled).toBe(true); expect(videoEnabled).toBe(callIntent !== "audio"); @@ -40,12 +40,12 @@ test.each<{ { callIntent: "video" }, { callIntent: "unknown" }, ])( - "Should always mute on start if skipping lobby on non embedded build (callIntent: $callIntent)", + "Should always mute on start if skipping lobby on non widget mode (callIntent: $callIntent)", ({ callIntent }) => { const { audioEnabled, videoEnabled } = calculateInitialMuteState( true, callIntent, - "full", + false, ); expect(audioEnabled).toBe(false); expect(videoEnabled).toBe(false); @@ -59,43 +59,14 @@ test.each<{ { callIntent: "video" }, { callIntent: "unknown" }, ])( - "Can start unmuted if skipping lobby on embedded build (callIntent: $callIntent)", + "Can start unmuted if skipping lobby on widget mode (callIntent: $callIntent)", ({ callIntent }) => { const { audioEnabled, videoEnabled } = calculateInitialMuteState( true, callIntent, - "embedded", + true, ); expect(audioEnabled).toBe(true); expect(videoEnabled).toBe(callIntent !== "audio"); }, ); - -test.each<{ - isDevBuild: boolean; - currentHost: string; - expectedEnabled: boolean; -}>([ - { isDevBuild: true, currentHost: "localhost", expectedEnabled: true }, - { isDevBuild: false, currentHost: "localhost", expectedEnabled: false }, - { isDevBuild: true, currentHost: "call.example.com", expectedEnabled: false }, - { - isDevBuild: false, - currentHost: "call.example.com", - expectedEnabled: false, - }, -])( - "Should trust localhost domain when in dev mode isDevBuild($isDevBuild) host($currentHost)", - ({ isDevBuild, currentHost, expectedEnabled }) => { - const { audioEnabled, videoEnabled } = calculateInitialMuteState( - true, - "video", - "full", - currentHost, - isDevBuild, - ); - - expect(audioEnabled).toBe(expectedEnabled); - expect(videoEnabled).toBe(expectedEnabled); - }, -); diff --git a/src/state/initialMuteState.ts b/src/state/initialMuteState.ts index d4c4bca1..4d27cdda 100644 --- a/src/state/initialMuteState.ts +++ b/src/state/initialMuteState.ts @@ -17,24 +17,15 @@ import { type RTCCallIntent } from "matrix-js-sdk/lib/matrixrtc"; export function calculateInitialMuteState( skipLobby: boolean, callIntent: RTCCallIntent | undefined, - packageType: "full" | "embedded", - hostname: string | undefined = undefined, - trustLocalhost: boolean = false, + isWidgetMode: boolean, ): { audioEnabled: boolean; videoEnabled: boolean } { - logger.debug( - `calculateInitialMuteState: skipLobby=${skipLobby}, callIntent=${callIntent}, hostname=${hostname}, trustLocalhost=${trustLocalhost}`, + `calculateInitialMuteState: skipLobby=${skipLobby}, callIntent=${callIntent} isWidgetMode=${isWidgetMode}`, ); - const isTrustedHost = - packageType == "embedded" || - // Trust local hosts in dev mode to make local testing easier - (hostname == "localhost" && trustLocalhost); - - if (skipLobby && !isTrustedHost) { - // If host not trusted and lobby skipped, default to muted to protect user privacy. - // This prevents users from inadvertently joining with active audio/video - // when browser permissions were previously granted in a different context. + if (skipLobby && !isWidgetMode) { + // If not in widget mode and lobby is skipped, default to muted to protect user privacy. + // In the SPA context we don't want to unmute users without giving them a chance to adjust their settings first. return { audioEnabled: false, videoEnabled: false,