feat: add --disable-geolocation command-line flag for macOS (#45934)

* feat(macos): add --disable-geolocation-mac command-line flag

* internally deny geolocation requests if flag set

e

* wrap PermissionRequestHandler instead

* wrap custom handler and deny regardless of response

* Update docs/api/command-line-switches.md

Co-authored-by: Will Anderson <will@itsananderson.com>

* resolving conflicts during rebase

* tests added

* tests added: minor changes

* move IsGeolocationDisabledViaCommandLine inside ElectronPermissionManager as a static member

* test: inject fixturesPath via --boot-eval

* Update shell/browser/electron_permission_manager.cc

Co-authored-by: Robo <hop2deep@gmail.com>

* chore: Fixup after merge

* fixup after merge

---------

Co-authored-by: Will Anderson <will@itsananderson.com>
Co-authored-by: Robo <hop2deep@gmail.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
This commit is contained in:
Nilay Arya
2025-11-13 10:39:03 -05:00
committed by GitHub
parent b121065984
commit 32ae696ee0
6 changed files with 128 additions and 4 deletions

View File

@@ -49,6 +49,10 @@ Disables the disk cache for HTTP requests.
Disable HTTP/2 and SPDY/3.1 protocols. Disable HTTP/2 and SPDY/3.1 protocols.
### --disable-geolocation _macOS_
Disables the Geolocation API. Permission requests for geolocation will be denied internally regardless of the decision made by a handler set via `session.setPermissionRequestHandler`. This functionality is currently implemented only for macOS. Has no effect on other platforms.
### --disable-renderer-backgrounding ### --disable-renderer-backgrounding
Prevents Chromium from lowering the priority of invisible pages' renderer Prevents Chromium from lowering the priority of invisible pages' renderer

View File

@@ -886,6 +886,24 @@ void Session::SetPermissionRequestHandler(v8::Local<v8::Value> val,
blink::PermissionType permission_type, blink::PermissionType permission_type,
ElectronPermissionManager::StatusCallback callback, ElectronPermissionManager::StatusCallback callback,
const base::Value& details) { const base::Value& details) {
#if (BUILDFLAG(IS_MAC))
if (permission_type == blink::PermissionType::GEOLOCATION) {
if (ElectronPermissionManager::
IsGeolocationDisabledViaCommandLine()) {
auto original_callback = std::move(callback);
callback = base::BindOnce(
[](ElectronPermissionManager::StatusCallback callback,
content::PermissionResult /*ignored_result*/) {
// Always deny regardless of what
// content::PermissionResult is passed here
std::move(callback).Run(content::PermissionResult(
blink::mojom::PermissionStatus::DENIED,
content::PermissionStatusSource::UNSPECIFIED));
},
std::move(original_callback));
}
}
#endif
handler->Run(web_contents, permission_type, std::move(callback), handler->Run(web_contents, permission_type, std::move(callback),
details); details);
}, },

View File

@@ -11,6 +11,7 @@
#include "services/device/public/cpp/geolocation/geolocation_system_permission_manager.h" #include "services/device/public/cpp/geolocation/geolocation_system_permission_manager.h"
#include "services/device/public/cpp/geolocation/system_geolocation_source_apple.h" #include "services/device/public/cpp/geolocation/system_geolocation_source_apple.h"
#include "shell/browser/browser_process_impl.h" #include "shell/browser/browser_process_impl.h"
#include "shell/browser/electron_permission_manager.h"
#include "shell/browser/mac/electron_application.h" #include "shell/browser/mac/electron_application.h"
#include "shell/browser/mac/electron_application_delegate.h" #include "shell/browser/mac/electron_application_delegate.h"
#include "ui/base/l10n/l10n_util_mac.h" #include "ui/base/l10n/l10n_util_mac.h"
@@ -32,7 +33,13 @@ void ElectronBrowserMainParts::PreCreateMainMessageLoop() {
setObject:@"NO" setObject:@"NO"
forKey:@"NSTreatUnknownArgumentsAsOpen"]; forKey:@"NSTreatUnknownArgumentsAsOpen"];
if (!device::GeolocationSystemPermissionManager::GetInstance()) { const bool geolocationDisabled =
ElectronPermissionManager::IsGeolocationDisabledViaCommandLine();
// Check if geolocation api is NOT disabled via command line before
// CreateGeolocationSystemPermissionManager is called
if (!geolocationDisabled &&
!device::GeolocationSystemPermissionManager::GetInstance()) {
device::GeolocationSystemPermissionManager::SetInstance( device::GeolocationSystemPermissionManager::SetInstance(
device::SystemGeolocationSourceApple:: device::SystemGeolocationSourceApple::
CreateGeolocationSystemPermissionManager()); CreateGeolocationSystemPermissionManager());

View File

@@ -8,6 +8,7 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "base/command_line.h"
#include "base/containers/to_vector.h" #include "base/containers/to_vector.h"
#include "base/values.h" #include "base/values.h"
#include "content/browser/permissions/permission_util.h" // nogncheck #include "content/browser/permissions/permission_util.h" // nogncheck
@@ -146,6 +147,17 @@ void ElectronPermissionManager::SetBluetoothPairingHandler(
bluetooth_pairing_handler_ = handler; bluetooth_pairing_handler_ = handler;
} }
// static
bool ElectronPermissionManager::IsGeolocationDisabledViaCommandLine() {
// Remove platform check once flag is extended to other platforms
#if BUILDFLAG(IS_MAC)
auto* command_line = base::CommandLine::ForCurrentProcess();
return command_line->HasSwitch("disable-geolocation");
#else
return false;
#endif
}
bool ElectronPermissionManager::HasPermissionRequestHandler() const { bool ElectronPermissionManager::HasPermissionRequestHandler() const {
return !request_handler_.is_null(); return !request_handler_.is_null();
} }
@@ -220,9 +232,16 @@ void ElectronPermissionManager::RequestPermissionsWithDetails(
->GrantSendMidiSysExMessage( ->GrantSendMidiSysExMessage(
render_frame_host->GetProcess()->GetDeprecatedID()); render_frame_host->GetProcess()->GetDeprecatedID());
} else if (permission_type == blink::PermissionType::GEOLOCATION) { } else if (permission_type == blink::PermissionType::GEOLOCATION) {
ElectronBrowserMainParts::Get() if (IsGeolocationDisabledViaCommandLine()) {
->GetGeolocationControl() results.push_back(content::PermissionResult(
->UserDidOptIntoLocationServices(); blink::mojom::PermissionStatus::DENIED,
content::PermissionStatusSource::UNSPECIFIED));
continue;
} else {
ElectronBrowserMainParts::Get()
->GetGeolocationControl()
->UserDidOptIntoLocationServices();
}
} }
results.push_back(content::PermissionResult( results.push_back(content::PermissionResult(
blink::mojom::PermissionStatus::GRANTED, blink::mojom::PermissionStatus::GRANTED,
@@ -331,6 +350,10 @@ bool ElectronPermissionManager::CheckPermissionWithDetails(
content::RenderFrameHost* render_frame_host, content::RenderFrameHost* render_frame_host,
const GURL& requesting_origin, const GURL& requesting_origin,
base::Value::Dict details) const { base::Value::Dict details) const {
if (permission == blink::PermissionType::GEOLOCATION &&
IsGeolocationDisabledViaCommandLine())
return false;
if (check_handler_.is_null()) { if (check_handler_.is_null()) {
if (permission == blink::PermissionType::DEPRECATED_SYNC_CLIPBOARD_READ) { if (permission == blink::PermissionType::DEPRECATED_SYNC_CLIPBOARD_READ) {
return false; return false;
@@ -368,6 +391,10 @@ bool ElectronPermissionManager::CheckDevicePermission(
const url::Origin& origin, const url::Origin& origin,
const base::Value& device, const base::Value& device,
ElectronBrowserContext* browser_context) const { ElectronBrowserContext* browser_context) const {
if (permission == blink::PermissionType::GEOLOCATION &&
IsGeolocationDisabledViaCommandLine())
return false;
if (device_permission_handler_.is_null()) if (device_permission_handler_.is_null())
return browser_context->CheckDevicePermission(origin, device, permission); return browser_context->CheckDevicePermission(origin, device, permission);

View File

@@ -66,6 +66,8 @@ class ElectronPermissionManager : public content::PermissionControllerDelegate {
using BluetoothPairingHandler = using BluetoothPairingHandler =
base::RepeatingCallback<void(gin_helper::Dictionary, PairCallback)>; base::RepeatingCallback<void(gin_helper::Dictionary, PairCallback)>;
static bool IsGeolocationDisabledViaCommandLine();
void RequestPermissionWithDetails( void RequestPermissionWithDetails(
blink::mojom::PermissionDescriptorPtr permission, blink::mojom::PermissionDescriptorPtr permission,
content::RenderFrameHost* render_frame_host, content::RenderFrameHost* render_frame_host,

View File

@@ -898,6 +898,72 @@ describe('chromium features', () => {
expect(position).to.have.property('coords'); expect(position).to.have.property('coords');
expect(position).to.have.property('timestamp'); expect(position).to.have.property('timestamp');
}); });
ifdescribe(process.platform === 'darwin')('with --disable-geolocation', () => {
const testSwitchBehavior = (handlerAction: 'allow' | 'deny' | 'none') => async () => {
const rc = await startRemoteControlApp([
'--disable-geolocation',
`--boot-eval=fixturesPath=${JSON.stringify(fixturesPath)}`
]);
const result = await rc.remotely(async (action: typeof handlerAction) => {
const { session, BrowserWindow } = require('electron');
const path = require('node:path');
// Isolate each test's permissions to prevent permission state leaks between the test variations
const testSession = session.fromPartition(`geolocation-disable-${action}`);
if (action !== 'none') {
// Make the PermissionRequestHandler behave according to action variable passed for this test
testSession.setPermissionRequestHandler((_wc, permission, callback) => {
if (permission === 'geolocation') {
if (action === 'allow') callback(true);
else if (action === 'deny') callback(false);
else callback(false);
}
});
}
const w = new BrowserWindow({
show: false,
webPreferences: {
session: testSession,
nodeIntegration: true,
contextIsolation: false
}
});
await w.loadFile(path.join(fixturesPath, 'pages', 'blank.html'));
const permissionState = await w.webContents.executeJavaScript(`
navigator.permissions.query({ name: 'geolocation' })
.then(status => status.state)
.catch(() => 'error')
`);
const geoResult = await w.webContents.executeJavaScript(`
new Promise(resolve => {
navigator.geolocation.getCurrentPosition(
() => resolve('allowed'),
err => resolve(err.code)
);
})
`);
return { permissionState, geoResult };
}, handlerAction);
// Always expect status to be denied regardless of the decision made by a handler set via `session.setPermissionRequestHandler`
expect(result.permissionState).to.equal('denied', `Unexpected permission state for ${handlerAction} handler`);
// 1 = PERMISSION_DENIED
expect(result.geoResult).to.equal(1, `Unexpected API result for ${handlerAction} handler`);
};
it('denies geolocation when permission request handler would allow', testSwitchBehavior('allow'));
it('denies geolocation when permission request handler would deny', testSwitchBehavior('deny'));
it('denies geolocation with no permission request handler', testSwitchBehavior('none'));
});
}); });
describe('File System API,', () => { describe('File System API,', () => {