diff --git a/docs/api/web-contents.md b/docs/api/web-contents.md index 035da986f982..b83b6d6c89c9 100644 --- a/docs/api/web-contents.md +++ b/docs/api/web-contents.md @@ -2069,6 +2069,24 @@ Setting the WebRTC IP handling policy allows you to control which IPs are exposed via WebRTC. See [BrowserLeaks](https://browserleaks.com/webrtc) for more details. +#### `contents.getWebRTCUDPPortRange()` + +Returns `Object`: + +* `min` Integer - The minimum UDP port number that WebRTC should use. +* `max` Integer - The maximum UDP port number that WebRTC should use. + +By default this value is `{ min: 0, max: 0 }` , which would apply no restriction on the udp port range. + +#### `contents.setWebRTCUDPPortRange(udpPortRange)` + +* `udpPortRange` Object + * `min` Integer - The minimum UDP port number that WebRTC should use. + * `max` Integer - The maximum UDP port number that WebRTC should use. + +Setting the WebRTC UDP Port Range allows you to restrict the udp port range used by WebRTC. By default the port range is unrestricted. +**Note:** To reset to an unrestricted port range this value should be set to `{ min: 0, max: 0 }`. + #### `contents.getMediaSourceId(requestWebContents)` * `requestWebContents` WebContents - Web contents that the id will be registered to. diff --git a/shell/browser/api/electron_api_web_contents.cc b/shell/browser/api/electron_api_web_contents.cc index 8e7db50616e2..4f946d166876 100644 --- a/shell/browser/api/electron_api_web_contents.cc +++ b/shell/browser/api/electron_api_web_contents.cc @@ -2552,6 +2552,52 @@ void WebContents::SetWebRTCIPHandlingPolicy( web_contents()->SyncRendererPrefs(); } +v8::Local WebContents::GetWebRTCUDPPortRange( + v8::Isolate* isolate) const { + auto* prefs = web_contents()->GetMutableRendererPrefs(); + + gin_helper::Dictionary dict = gin::Dictionary::CreateEmpty(isolate); + dict.Set("min", static_cast(prefs->webrtc_udp_min_port)); + dict.Set("max", static_cast(prefs->webrtc_udp_max_port)); + return dict.GetHandle(); +} + +void WebContents::SetWebRTCUDPPortRange(gin::Arguments* args) { + uint32_t min = 0, max = 0; + gin_helper::Dictionary range; + + if (!args->GetNext(&range) || !range.Get("min", &min) || + !range.Get("max", &max)) { + gin_helper::ErrorThrower(args->isolate()) + .ThrowError("'min' and 'max' are both required"); + return; + } + + if ((0 == min && 0 != max) || max > UINT16_MAX) { + gin_helper::ErrorThrower(args->isolate()) + .ThrowError( + "'min' and 'max' must be in the (0, 65535] range or [0, 0]"); + return; + } + if (min > max) { + gin_helper::ErrorThrower(args->isolate()) + .ThrowError("'max' must be greater than or equal to 'min'"); + return; + } + + auto* prefs = web_contents()->GetMutableRendererPrefs(); + + if (prefs->webrtc_udp_min_port == static_cast(min) && + prefs->webrtc_udp_max_port == static_cast(max)) { + return; + } + + prefs->webrtc_udp_min_port = min; + prefs->webrtc_udp_max_port = max; + + web_contents()->SyncRendererPrefs(); +} + std::string WebContents::GetMediaSourceID( content::WebContents* request_web_contents) { auto* frame_host = web_contents()->GetPrimaryMainFrame(); @@ -4319,9 +4365,11 @@ void WebContents::FillObjectTemplate(v8::Isolate* isolate, .SetMethod("isBeingCaptured", &WebContents::IsBeingCaptured) .SetMethod("setWebRTCIPHandlingPolicy", &WebContents::SetWebRTCIPHandlingPolicy) + .SetMethod("setWebRTCUDPPortRange", &WebContents::SetWebRTCUDPPortRange) .SetMethod("getMediaSourceId", &WebContents::GetMediaSourceID) .SetMethod("getWebRTCIPHandlingPolicy", &WebContents::GetWebRTCIPHandlingPolicy) + .SetMethod("getWebRTCUDPPortRange", &WebContents::GetWebRTCUDPPortRange) .SetMethod("takeHeapSnapshot", &WebContents::TakeHeapSnapshot) .SetMethod("setImageAnimationPolicy", &WebContents::SetImageAnimationPolicy) diff --git a/shell/browser/api/electron_api_web_contents.h b/shell/browser/api/electron_api_web_contents.h index d0c65fd4b4bc..e1fc66378b3b 100644 --- a/shell/browser/api/electron_api_web_contents.h +++ b/shell/browser/api/electron_api_web_contents.h @@ -189,6 +189,8 @@ class WebContents : public ExclusiveAccessContext, int GetHistoryLength() const; const std::string GetWebRTCIPHandlingPolicy() const; void SetWebRTCIPHandlingPolicy(const std::string& webrtc_ip_handling_policy); + v8::Local GetWebRTCUDPPortRange(v8::Isolate* isolate) const; + void SetWebRTCUDPPortRange(gin::Arguments* args); std::string GetMediaSourceID(content::WebContents* request_web_contents); bool IsCrashed() const; void ForcefullyCrashRenderer(); diff --git a/spec/api-web-contents-spec.ts b/spec/api-web-contents-spec.ts index ac11521e983c..d0f560b8bcf1 100644 --- a/spec/api-web-contents-spec.ts +++ b/spec/api-web-contents-spec.ts @@ -1309,6 +1309,47 @@ describe('webContents module', () => { }); }); + describe('webrtc udp port range policy api', () => { + let w: BrowserWindow; + beforeEach(() => { + w = new BrowserWindow({ show: false }); + }); + + afterEach(closeAllWindows); + + it('check default webrtc udp port range is { min: 0, max: 0 }', () => { + const settings = w.webContents.getWebRTCUDPPortRange(); + expect(settings).to.deep.equal({ min: 0, max: 0 }); + }); + + it('can set and get webrtc udp port range policy with correct arguments', () => { + w.webContents.setWebRTCUDPPortRange({ min: 1, max: 65535 }); + const settings = w.webContents.getWebRTCUDPPortRange(); + expect(settings).to.deep.equal({ min: 1, max: 65535 }); + }); + + it('can not set webrtc udp port range policy with invalid arguments', () => { + expect(() => { + w.webContents.setWebRTCUDPPortRange({ min: 0, max: 65535 }); + }).to.throw("'min' and 'max' must be in the (0, 65535] range or [0, 0]"); + expect(() => { + w.webContents.setWebRTCUDPPortRange({ min: 1, max: 65536 }); + }).to.throw("'min' and 'max' must be in the (0, 65535] range or [0, 0]"); + expect(() => { + w.webContents.setWebRTCUDPPortRange({ min: 60000, max: 56789 }); + }).to.throw("'max' must be greater than or equal to 'min'"); + }); + + it('can reset webrtc udp port range policy to default with { min: 0, max: 0 }', () => { + w.webContents.setWebRTCUDPPortRange({ min: 1, max: 65535 }); + const settings = w.webContents.getWebRTCUDPPortRange(); + expect(settings).to.deep.equal({ min: 1, max: 65535 }); + w.webContents.setWebRTCUDPPortRange({ min: 0, max: 0 }); + const defaultSetting = w.webContents.getWebRTCUDPPortRange(); + expect(defaultSetting).to.deep.equal({ min: 0, max: 0 }); + }); + }); + describe('opener api', () => { afterEach(closeAllWindows); it('can get opener with window.open()', async () => {