From 33f3764ec5921b20b1f23396cc61dc37fe6c7502 Mon Sep 17 00:00:00 2001 From: lockbitchat Date: Sun, 17 May 2026 23:09:45 -0400 Subject: [PATCH] fix: synchronize WebRTC privacy mode state --- src/app.jsx | 2 +- src/network/EnhancedSecureWebRTCManager.js | 18 ++++++++++------ tests/webrtc-privacy-mode.test.mjs | 24 +++++++++++++++++++++- 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/app.jsx b/src/app.jsx index e4850c4..1ad67a4 100644 --- a/src/app.jsx +++ b/src/app.jsx @@ -1752,7 +1752,7 @@ import { installDebugWindowHooks } from './utils/debugWindowHooks.js'; React.useEffect(() => { try { localStorage.setItem('securebit_relay_only_mode', String(relayOnlyMode)); } catch {} if (webrtcManagerRef.current?._config?.webrtc) { - webrtcManagerRef.current._config.webrtc.relayOnly = relayOnlyMode; + webrtcManagerRef.current._setRelayOnlyMode(relayOnlyMode); } }, [relayOnlyMode]); diff --git a/src/network/EnhancedSecureWebRTCManager.js b/src/network/EnhancedSecureWebRTCManager.js index 8de12c4..2fd9f7a 100644 --- a/src/network/EnhancedSecureWebRTCManager.js +++ b/src/network/EnhancedSecureWebRTCManager.js @@ -153,12 +153,13 @@ class EnhancedSecureWebRTCManager { useRandomHeaders: config.antiFingerprinting?.useRandomHeaders ?? false }, webrtc: { - // `privacyMode` is the explicit operator-facing setting. - // Keep `relayOnly` as a backward-compatible alias. + // `privacyMode` is canonical; `relayOnly` remains a + // backward-compatible input alias at construction time. privacyMode: config.webrtc?.privacyMode ?? (config.webrtc?.relayOnly ? 'relay-only' : 'standard'), - relayOnly: config.webrtc?.relayOnly - ?? config.webrtc?.privacyMode === 'relay-only', + relayOnly: config.webrtc?.privacyMode + ? config.webrtc.privacyMode === 'relay-only' + : config.webrtc?.relayOnly ?? false, iceServers: config.webrtc?.iceServers ?? EnhancedSecureWebRTCManager.DEFAULT_ICE_SERVERS.map(server => ({ ...server })) } @@ -7263,8 +7264,13 @@ async processMessage(data) { } _isRelayOnlyMode() { - return this._config.webrtc.privacyMode === 'relay-only' - || this._config.webrtc.relayOnly === true; + return this._config.webrtc.privacyMode === 'relay-only'; + } + + _setRelayOnlyMode(relayOnly) { + const enabled = relayOnly === true; + this._config.webrtc.privacyMode = enabled ? 'relay-only' : 'standard'; + this._config.webrtc.relayOnly = enabled; } _warnIfTurnMissing() { diff --git a/tests/webrtc-privacy-mode.test.mjs b/tests/webrtc-privacy-mode.test.mjs index 96dcd40..d29b83f 100644 --- a/tests/webrtc-privacy-mode.test.mjs +++ b/tests/webrtc-privacy-mode.test.mjs @@ -25,7 +25,8 @@ function fake(config = {}) { this.delivered.push({ message, type }); }, _hasTurnServer: EnhancedSecureWebRTCManager.prototype._hasTurnServer, - _isRelayOnlyMode: EnhancedSecureWebRTCManager.prototype._isRelayOnlyMode + _isRelayOnlyMode: EnhancedSecureWebRTCManager.prototype._isRelayOnlyMode, + _setRelayOnlyMode: EnhancedSecureWebRTCManager.prototype._setRelayOnlyMode }; } @@ -51,6 +52,27 @@ function fake(config = {}) { assert.equal(config.iceTransportPolicy, 'relay'); } +// Runtime toggles keep the canonical privacy state synchronized. +{ + const manager = fake({ privacyMode: 'standard', iceServers: [{ urls: 'turn:turn.example.test:3478' }] }); + manager._setRelayOnlyMode(true); + assert.equal(manager._config.webrtc.privacyMode, 'relay-only'); + assert.equal(manager._config.webrtc.relayOnly, true); + assert.equal(EnhancedSecureWebRTCManager.prototype._buildPeerConnectionConfig.call(manager).iceTransportPolicy, 'relay'); + + manager._setRelayOnlyMode(false); + assert.equal(manager._config.webrtc.privacyMode, 'standard'); + assert.equal(manager._config.webrtc.relayOnly, false); + assert.equal(EnhancedSecureWebRTCManager.prototype._buildPeerConnectionConfig.call(manager).iceTransportPolicy, undefined); +} + +// Canonical privacyMode wins over a stale legacy alias. +{ + const manager = fake({ privacyMode: 'standard', relayOnly: true, iceServers: [{ urls: 'turn:turn.example.test:3478' }] }); + assert.equal(manager._isRelayOnlyMode(), false); + assert.equal(EnhancedSecureWebRTCManager.prototype._buildPeerConnectionConfig.call(manager).iceTransportPolicy, undefined); +} + // Missing TURN in standard mode warns clearly and visibly. { const manager = fake();