diff --git a/fluxer_desktop/src/preload/GscordCompatibility.ts b/fluxer_desktop/src/preload/GscordCompatibility.ts new file mode 100644 index 0000000..9085d5a --- /dev/null +++ b/fluxer_desktop/src/preload/GscordCompatibility.ts @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later + +// These functions are serialized by executeInMainWorld: keep them self-contained. +export function installForceAllIceTransportPolicy(): void { + const NativeRTCPeerConnection = window.RTCPeerConnection; + + if (typeof NativeRTCPeerConnection !== 'function') { + return; + } + + const nativeSetConfiguration = NativeRTCPeerConnection.prototype.setConfiguration; + NativeRTCPeerConnection.prototype.setConfiguration = function (configuration: RTCConfiguration): void { + const next = configuration?.iceTransportPolicy === 'relay' + ? {...configuration, iceTransportPolicy: 'all' as RTCIceTransportPolicy} + : configuration; + return nativeSetConfiguration.call(this, next); + }; + + window.RTCPeerConnection = new Proxy(NativeRTCPeerConnection, { + construct(Target, args, newTarget) { + const config = args[0] as RTCConfiguration | undefined; + + if (config?.iceTransportPolicy === 'relay') { + args[0] = { + ...config, + iceTransportPolicy: 'all', + }; + } + + return Reflect.construct(Target, args, newTarget); + }, + }); + + console.info('[Fluxer Desktop] WebRTC iceTransportPolicy forced to all'); +} + +export function installDisableLiveKitOfferWithJoin(): void { + const NativeWebSocket = window.WebSocket; + const compressionDescriptor = Object.getOwnPropertyDescriptor( + window, + 'CompressionStream', + ); + + let compressionSuppressed = false; + + const suppressCompressionStream = (): void => { + if (compressionSuppressed) { + return; + } + + Object.defineProperty(window, 'CompressionStream', { + configurable: true, + writable: true, + value: undefined, + }); + + compressionSuppressed = true; + }; + + const restoreCompressionStream = (): void => { + if (!compressionSuppressed) { + return; + } + + if (compressionDescriptor) { + Object.defineProperty( + window, + 'CompressionStream', + compressionDescriptor, + ); + } else { + delete (window as typeof window & { + CompressionStream?: typeof CompressionStream; + }).CompressionStream; + } + + compressionSuppressed = false; + }; + + const isLiveKitRtcSocket = (value: string | URL): boolean => { + try { + const url = new URL(String(value), window.location.href); + return /\/rtc\/v1\/?$/.test(url.pathname); + } catch { + return false; + } + }; + + window.WebSocket = new Proxy(NativeWebSocket, { + construct(Target, args) { + const isLiveKitRtc = isLiveKitRtcSocket( + args[0] as string | URL, + ); + + if (isLiveKitRtc) { + restoreCompressionStream(); + } + + let socket: WebSocket; + + try { + socket = Reflect.construct(Target, args, Target); + } catch (error) { + if (isLiveKitRtc) { + suppressCompressionStream(); + } + throw error; + } + + if (isLiveKitRtc) { + socket.addEventListener( + 'close', + () => suppressCompressionStream(), + {once: true}, + ); + } + + return socket; + }, + }) as typeof WebSocket; + + suppressCompressionStream(); + + console.info( + '[Fluxer Desktop] LiveKit publisher offer-with-join disabled', + ); +} diff --git a/fluxer_desktop/src/preload/index.ts b/fluxer_desktop/src/preload/index.ts index 07ef677..12d4913 100644 --- a/fluxer_desktop/src/preload/index.ts +++ b/fluxer_desktop/src/preload/index.ts @@ -59,6 +59,7 @@ import type { } from '@electron/common/Types'; import {createBrowserHandoffPreloadAPI} from '@electron/preload/BrowserHandoffPreload'; import {createDesktopStoragePreloadAPI} from '@electron/preload/DesktopStoragePreload'; +import {installDisableLiveKitOfferWithJoin, installForceAllIceTransportPolicy} from '@electron/preload/GscordCompatibility'; import {createFirstContentPaintSignal} from '@electron/preload/FirstContentPaint'; import {applyLegacyRawLocalStorage} from '@electron/preload/LegacyRawStorageSeed'; import {createLocalAppPreloadAPI} from '@electron/preload/LocalAppPreload'; @@ -86,6 +87,9 @@ import type { } from '@simplewebauthn/browser'; import {contextBridge, ipcRenderer, webFrame} from 'electron'; +contextBridge.executeInMainWorld({func: installForceAllIceTransportPolicy}); +contextBridge.executeInMainWorld({func: installDisableLiveKitOfferWithJoin}); + const ACCESSIBILITY_STORE_STORAGE_KEY = 'AccessibilityStore'; const ACTIVE_ALLOW_TRANSPARENCY_RENDERER_ARG = '--fluxer-active-allow-transparency=1'; const ACTIVE_USE_NATIVE_TITLEBAR_RENDERER_ARG = '--fluxer-active-use-native-titlebar=1';