electron/shell/browser/electron_permission_manager.cc
electron-roller[bot] dd03cceda0
chore: bump chromium to 137.0.7128.1 (main) (#46482)
* chore: bump chromium in DEPS to 137.0.7107.0

* chore: bump chromium in DEPS to 137.0.7109.0

* chore: bump chromium in DEPS to 137.0.7111.0

* chore: bump chromium in DEPS to 137.0.7113.0

* 6384240: Remove double-declaration for accessibility on macOS | 6384240

* 6422872: Remove unused includes in isolation_info_mojom_traits.h | 6422872

* chore: update patches

* 6400733: Avoid ipc_message_macros.h usage in some foo_param_traits_macros.h files | 6400733

* chore: update patches

* 6423410: Enable unsafe buffer warnings for chromium, try #3. | 6423410

* chore: iwyu

* refactor: prefer value initialization over memset()

From the looks up upstream commits in base/, it looks like memset()
could trigger `-Wunsafe-buffer-usage` warnings soon?

Value initialization is more C++ish and less error-prone anyway,
due to memset()'s easily swappable parameters.

* refactor: NotifyIcon::InitIconData() returns a NOTIFYICONDATA

This follows F.20 in the C++ Core Guidelines and also removes the need
for memset()

* 6423410: Enable unsafe buffer warnings for chromium, try #3. | 6423410

remove all uses of:

- strcmp()

* fixup!  6423410: Enable unsafe buffer warnings for chromium, try #3. | 6423410

* 6433203: Add a PassKey to RegisterDeleteDelegateCallback(). | 6433203

* chore: bump chromium in DEPS to 137.0.7115.0

* 6387077: [PermissionOptions] Generalize PermissionRequestDescription | 6387077

* chore: update patches

* 6387077: [PermissionOptions] Generalize PermissionRequestDescription | 6387077

* fix: add pragma for MacSDK unsafe buffers | 6423410: Enable unsafe buffer warnings for chromium, try #3. | 6423410

* chore: bump chromium in DEPS to 137.0.7117.0

* chore: update patches

* chore: update filesnames.libcxx.gni

* 6431756: Replace SetOwnedByWidget() bool arg with a PassKey. | 6431756

* 6387077: [PermissionOptions] Generalize PermissionRequestDescription | 6387077

* 6428345: Remove ExtensionService usage from ChromeExtensionRegistrarDelegate | 6428345

* 6384315: Migrate extensions_enabled from ExtensionService to Registrar | 6384315

* 6428749: [extensions] Refactor ExtensionService for AddNewAndUpdateExtension. | 6428749

* chore: bump chromium in DEPS to 137.0.7119.0

* 6440290: corner-shape: support inset shadow | 6440290

* 6429230: FSA: Move blocked paths to the PermissionContext class | 6429230

* chore: update patches

* chore: bump chromium in DEPS to 137.0.7121.0

* chore: update patches

* fix: partially revert 6443473: Remove ItemDelete from the Mac version of AppleKeychain | 6443473

* fix: update filenames.libcxx.gni

* chore: bump chromium in DEPS to 137.0.7123.0

* chore: update patches

* chore: "grandfather in" electron views too

Lock further access to View::set_owned_by_client() | 6448510

* chore: update feat_corner_smoothing_css_rule_and_blink_painting.patch

corner-shape: support inset shadow | 6440290

* refactor: grandfather in AutofillPopupView as a subclass of WidgetDelegateView

Add a PassKey for std::make_unique<WidgetDelegateView>() | 6442265

* Provide dbus appmenu information on Wayland | 6405535

* [extensions] Move OnExtensionInstalled out of ExtensionService. | 6443325

* refactor: grandfather in NativeWindowViews for delete callbacks

6433203: Add a PassKey to RegisterDeleteDelegateCallback(). | 6433203

* chore: merge the four "grandfather" patches into one

* [A11yPerformance] Remove IsAccessibilityAllowed() | 6404386: [A11yPerformance] Remove IsAccessibilityAllowed() | 6404386

NB: the changes here are copied from the upstream changes in
chrome/browser/ui/webui/accessibility/accessibility_ui.cc

* 6420753: [PermissionOptions] Use PermissionDescriptorPtr in PermissionController | 6420753

* 6429573: [accessibility] Move mode change out of AccessibilityNotificationWaiter | 6429573

* chore: e patches all

* 6419936: [win] Change ScreenWin public static methods to virtual | 6419936

* 6423410: Enable unsafe buffer warnings for chromium, try #3. | 6423410

remove all uses of:

- fprintf()
- fputs()
- snprintf()
- vsnprintf()

* fix: size conversion FTBFS on Win

* 6423410: Enable unsafe buffer warnings for chromium, try #3. | 6423410

remove all uses of:

- wcscpy_s()

* 6423410: Enable unsafe buffer warnings for chromium, try #3. | 6423410

remove all uses of:

- wcsncpy_s()

* chore: update mas_avoid_private_macos_api_usage.patch.patch

6394283: Remove double-declaration for accessibility on iOS | 6394283

Lots of context shear in this commit but the only interesting part is:

-+  return nullptr;
++  return {};

Which is needed because the return type is sometimes not a pointer.

* chore: e patches all

* chore: disable -Wmacro-redefined warning in electron_main_win.cc

* chore: bump chromium in DEPS to 137.0.7123.5

* refactor: patch electron PermissionTypes into blink

6387077: [PermissionOptions] Generalize PermissionRequestDescription | 6387077

* chore: e patches all

* chore: remove the box_painter_base.cc part of feat_corner_smoothing_css_rule_and_blink_painting.patch

as per code review @ https://github.com/electron/electron/pull/46482#pullrequestreview-2777338370

* test: enable window-smaller-than-64x64 test on Linux

* chore: bump chromium in DEPS to 137.0.7124.1

* chore: bump chromium in DEPS to 137.0.7125.1

* chore: bump chromium in DEPS to 137.0.7127.3

* 6459201: [Extensions] Remove ExtensionSystem::FinishDelayedInstallationIfReady() | 6459201

* 6454796: [Extensions] Move (most) registrar delayed install logic to //extensions | 6454796

* chore: bump chromium in DEPS to 137.0.7128.1

* chore: e patches all

* chore: node ./script/gen-libc++-filenames.js

* [views] Gate DesktopWindowTreeHostWin::window_enlargement_ behind flag

Refs 6428649

* feat: allow opt-out animated_content_sampler.

Refs 6438681

* Trigger CI

---------

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: Keeley Hammond <khammond@slack-corp.com>
Co-authored-by: Charles Kerr <charles@charleskerr.com>
Co-authored-by: Keeley Hammond <vertedinde@electronjs.org>
Co-authored-by: deepak1556 <hop2deep@gmail.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2025-04-22 15:53:29 -04:00

432 lines
16 KiB
C++

// Copyright (c) 2016 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "shell/browser/electron_permission_manager.h"
#include <memory>
#include <utility>
#include <vector>
#include "base/containers/to_vector.h"
#include "base/values.h"
#include "content/browser/permissions/permission_util.h" // nogncheck
#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/permission_controller.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "gin/data_object_builder.h"
#include "shell/browser/api/electron_api_web_contents.h"
#include "shell/browser/electron_browser_context.h"
#include "shell/browser/electron_browser_main_parts.h"
#include "shell/browser/web_contents_permission_helper.h"
#include "shell/browser/web_contents_preferences.h"
#include "shell/common/gin_converters/content_converter.h"
#include "shell/common/gin_converters/frame_converter.h"
#include "shell/common/gin_converters/usb_protected_classes_converter.h"
#include "shell/common/gin_converters/value_converter.h"
#include "shell/common/gin_helper/dictionary.h"
#include "shell/common/gin_helper/event_emitter_caller.h"
#include "third_party/blink/public/common/permissions/permission_utils.h"
namespace electron {
namespace {
bool WebContentsDestroyed(content::RenderFrameHost* rfh) {
content::WebContents* web_contents =
content::WebContents::FromRenderFrameHost(rfh);
if (!web_contents)
return true;
return web_contents->IsBeingDestroyed();
}
void PermissionRequestResponseCallbackWrapper(
ElectronPermissionManager::StatusCallback callback,
const std::vector<blink::mojom::PermissionStatus>& vector) {
std::move(callback).Run(vector[0]);
}
} // namespace
class ElectronPermissionManager::PendingRequest {
public:
PendingRequest(content::RenderFrameHost* render_frame_host,
std::vector<blink::mojom::PermissionDescriptorPtr> permissions,
StatusesCallback callback)
: render_frame_host_id_(render_frame_host->GetGlobalId()),
callback_(std::move(callback)),
permissions_(std::move(permissions)),
results_(permissions_.size(), blink::mojom::PermissionStatus::DENIED),
remaining_results_(permissions_.size()) {}
void SetPermissionStatus(int permission_id,
blink::mojom::PermissionStatus status) {
DCHECK(!IsComplete());
if (status == blink::mojom::PermissionStatus::GRANTED) {
const auto permission = blink::PermissionDescriptorToPermissionType(
permissions_[permission_id]);
if (permission == blink::PermissionType::MIDI_SYSEX) {
content::ChildProcessSecurityPolicy::GetInstance()
->GrantSendMidiSysExMessage(render_frame_host_id_.child_id);
} else if (permission == blink::PermissionType::GEOLOCATION) {
ElectronBrowserMainParts::Get()
->GetGeolocationControl()
->UserDidOptIntoLocationServices();
}
}
results_[permission_id] = status;
--remaining_results_;
}
content::RenderFrameHost* GetRenderFrameHost() {
return content::RenderFrameHost::FromID(render_frame_host_id_);
}
[[nodiscard]] bool IsComplete() const { return remaining_results_ == 0; }
void RunCallback() {
if (!callback_.is_null()) {
std::move(callback_).Run(results_);
}
}
private:
content::GlobalRenderFrameHostId render_frame_host_id_;
StatusesCallback callback_;
std::vector<blink::mojom::PermissionDescriptorPtr> permissions_;
std::vector<blink::mojom::PermissionStatus> results_;
size_t remaining_results_;
};
ElectronPermissionManager::ElectronPermissionManager() = default;
ElectronPermissionManager::~ElectronPermissionManager() = default;
void ElectronPermissionManager::SetPermissionRequestHandler(
const RequestHandler& handler) {
if (handler.is_null() && !pending_requests_.IsEmpty()) {
for (PendingRequestsMap::iterator iter(&pending_requests_); !iter.IsAtEnd();
iter.Advance()) {
auto* request = iter.GetCurrentValue();
if (!WebContentsDestroyed(request->GetRenderFrameHost()))
request->RunCallback();
}
pending_requests_.Clear();
}
request_handler_ = handler;
}
void ElectronPermissionManager::SetPermissionCheckHandler(
const CheckHandler& handler) {
check_handler_ = handler;
}
void ElectronPermissionManager::SetDevicePermissionHandler(
const DeviceCheckHandler& handler) {
device_permission_handler_ = handler;
}
void ElectronPermissionManager::SetProtectedUSBHandler(
const ProtectedUSBHandler& handler) {
protected_usb_handler_ = handler;
}
void ElectronPermissionManager::SetBluetoothPairingHandler(
const BluetoothPairingHandler& handler) {
bluetooth_pairing_handler_ = handler;
}
void ElectronPermissionManager::RequestPermissionWithDetails(
blink::mojom::PermissionDescriptorPtr permission,
content::RenderFrameHost* render_frame_host,
const GURL& requesting_origin,
bool user_gesture,
base::Value::Dict details,
StatusCallback response_callback) {
if (render_frame_host->IsNestedWithinFencedFrame()) {
std::move(response_callback).Run(blink::mojom::PermissionStatus::DENIED);
return;
}
RequestPermissionsWithDetails(
render_frame_host,
content::PermissionRequestDescription(std::move(permission), user_gesture,
requesting_origin),
std::move(details),
base::BindOnce(PermissionRequestResponseCallbackWrapper,
std::move(response_callback)));
}
void ElectronPermissionManager::RequestPermissions(
content::RenderFrameHost* render_frame_host,
const content::PermissionRequestDescription& request_description,
StatusesCallback callback) {
if (render_frame_host->IsNestedWithinFencedFrame()) {
std::move(callback).Run(std::vector<blink::mojom::PermissionStatus>(
request_description.permissions.size(),
blink::mojom::PermissionStatus::DENIED));
return;
}
RequestPermissionsWithDetails(render_frame_host, request_description, {},
std::move(callback));
}
void ElectronPermissionManager::RequestPermissionsWithDetails(
content::RenderFrameHost* render_frame_host,
const content::PermissionRequestDescription& request_description,
base::Value::Dict details,
StatusesCallback response_callback) {
if (request_description.permissions.empty()) {
std::move(response_callback).Run({});
return;
}
auto permissions = base::ToVector(request_description.permissions,
[](const auto& permission_descriptor) {
return permission_descriptor.Clone();
});
if (request_handler_.is_null()) {
std::vector<blink::mojom::PermissionStatus> statuses;
for (const auto& permission : permissions) {
const auto permission_type =
blink::PermissionDescriptorToPermissionType(permission);
if (permission_type == blink::PermissionType::MIDI_SYSEX) {
content::ChildProcessSecurityPolicy::GetInstance()
->GrantSendMidiSysExMessage(
render_frame_host->GetProcess()->GetDeprecatedID());
} else if (permission_type == blink::PermissionType::GEOLOCATION) {
ElectronBrowserMainParts::Get()
->GetGeolocationControl()
->UserDidOptIntoLocationServices();
}
statuses.push_back(blink::mojom::PermissionStatus::GRANTED);
}
std::move(response_callback).Run(statuses);
return;
}
auto* web_contents =
content::WebContents::FromRenderFrameHost(render_frame_host);
int request_id = pending_requests_.Add(std::make_unique<PendingRequest>(
render_frame_host, std::move(permissions), std::move(response_callback)));
details.Set("requestingUrl", render_frame_host->GetLastCommittedURL().spec());
details.Set("isMainFrame", render_frame_host->GetParent() == nullptr);
base::Value dict_value(std::move(details));
for (size_t i = 0; i < request_description.permissions.size(); ++i) {
const auto permission = blink::PermissionDescriptorToPermissionType(
request_description.permissions[i]);
const auto callback =
base::BindRepeating(&ElectronPermissionManager::OnPermissionResponse,
base::Unretained(this), request_id, i);
request_handler_.Run(web_contents, permission, callback, dict_value);
}
}
void ElectronPermissionManager::OnPermissionResponse(
int request_id,
int permission_id,
blink::mojom::PermissionStatus status) {
auto* pending_request = pending_requests_.Lookup(request_id);
if (!pending_request)
return;
pending_request->SetPermissionStatus(permission_id, status);
if (pending_request->IsComplete()) {
pending_request->RunCallback();
pending_requests_.Remove(request_id);
}
}
void ElectronPermissionManager::ResetPermission(
blink::PermissionType permission,
const GURL& requesting_origin,
const GURL& embedding_origin) {}
void ElectronPermissionManager::RequestPermissionsFromCurrentDocument(
content::RenderFrameHost* render_frame_host,
const content::PermissionRequestDescription& request_description,
base::OnceCallback<void(const std::vector<blink::mojom::PermissionStatus>&)>
callback) {
if (render_frame_host->IsNestedWithinFencedFrame()) {
std::move(callback).Run(std::vector<blink::mojom::PermissionStatus>(
request_description.permissions.size(),
blink::mojom::PermissionStatus::DENIED));
return;
}
RequestPermissionsWithDetails(render_frame_host, request_description, {},
std::move(callback));
}
blink::mojom::PermissionStatus ElectronPermissionManager::GetPermissionStatus(
blink::PermissionType permission,
const GURL& requesting_origin,
const GURL& embedding_origin) {
base::Value::Dict details;
details.Set("embeddingOrigin", embedding_origin.spec());
bool granted = CheckPermissionWithDetails(permission, {}, requesting_origin,
std::move(details));
return granted ? blink::mojom::PermissionStatus::GRANTED
: blink::mojom::PermissionStatus::DENIED;
}
content::PermissionResult
ElectronPermissionManager::GetPermissionResultForOriginWithoutContext(
blink::PermissionType permission,
const url::Origin& requesting_origin,
const url::Origin& embedding_origin) {
blink::mojom::PermissionStatus status = GetPermissionStatus(
permission, requesting_origin.GetURL(), embedding_origin.GetURL());
return {status, content::PermissionStatusSource::UNSPECIFIED};
}
void ElectronPermissionManager::CheckBluetoothDevicePair(
gin_helper::Dictionary details,
PairCallback pair_callback) const {
if (bluetooth_pairing_handler_.is_null()) {
base::Value::Dict response;
response.Set("confirmed", false);
std::move(pair_callback).Run(std::move(response));
} else {
bluetooth_pairing_handler_.Run(details, std::move(pair_callback));
}
}
bool ElectronPermissionManager::CheckPermissionWithDetails(
blink::PermissionType permission,
content::RenderFrameHost* render_frame_host,
const GURL& requesting_origin,
base::Value::Dict details) const {
if (check_handler_.is_null()) {
if (permission == blink::PermissionType::DEPRECATED_SYNC_CLIPBOARD_READ) {
return false;
} else {
return true;
}
}
auto* web_contents =
render_frame_host
? content::WebContents::FromRenderFrameHost(render_frame_host)
: nullptr;
if (render_frame_host) {
details.Set("requestingUrl",
render_frame_host->GetLastCommittedURL().spec());
}
details.Set("isMainFrame",
render_frame_host && render_frame_host->GetParent() == nullptr);
switch (permission) {
case blink::PermissionType::AUDIO_CAPTURE:
details.Set("mediaType", "audio");
break;
case blink::PermissionType::VIDEO_CAPTURE:
details.Set("mediaType", "video");
break;
default:
break;
}
return check_handler_.Run(web_contents, permission, requesting_origin,
base::Value(std::move(details)));
}
bool ElectronPermissionManager::CheckDevicePermission(
blink::PermissionType permission,
const url::Origin& origin,
const base::Value& device,
ElectronBrowserContext* browser_context) const {
if (device_permission_handler_.is_null())
return browser_context->CheckDevicePermission(origin, device, permission);
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
v8::HandleScope scope(isolate);
v8::Local<v8::Object> details = gin::DataObjectBuilder(isolate)
.Set("deviceType", permission)
.Set("origin", origin.Serialize())
.Set("device", device.Clone())
.Build();
return device_permission_handler_.Run(details);
}
void ElectronPermissionManager::GrantDevicePermission(
blink::PermissionType permission,
const url::Origin& origin,
const base::Value& device,
ElectronBrowserContext* browser_context) const {
if (device_permission_handler_.is_null()) {
browser_context->GrantDevicePermission(origin, device, permission);
}
}
void ElectronPermissionManager::RevokeDevicePermission(
blink::PermissionType permission,
const url::Origin& origin,
const base::Value& device,
ElectronBrowserContext* browser_context) const {
browser_context->RevokeDevicePermission(origin, device, permission);
}
ElectronPermissionManager::USBProtectedClasses
ElectronPermissionManager::CheckProtectedUSBClasses(
const USBProtectedClasses& classes) const {
if (protected_usb_handler_.is_null())
return classes;
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
v8::HandleScope scope(isolate);
v8::Local<v8::Object> details =
gin::DataObjectBuilder(isolate).Set("protectedClasses", classes).Build();
return protected_usb_handler_.Run(details);
}
blink::mojom::PermissionStatus
ElectronPermissionManager::GetPermissionStatusForCurrentDocument(
blink::PermissionType permission,
content::RenderFrameHost* render_frame_host,
bool /*should_include_device_status*/) {
if (render_frame_host->IsNestedWithinFencedFrame())
return blink::mojom::PermissionStatus::DENIED;
base::Value::Dict details;
details.Set("embeddingOrigin",
content::PermissionUtil::GetLastCommittedOriginAsURL(
render_frame_host->GetMainFrame())
.spec());
bool granted = CheckPermissionWithDetails(
permission, render_frame_host,
render_frame_host->GetLastCommittedOrigin().GetURL(), std::move(details));
return granted ? blink::mojom::PermissionStatus::GRANTED
: blink::mojom::PermissionStatus::DENIED;
}
blink::mojom::PermissionStatus
ElectronPermissionManager::GetPermissionStatusForWorker(
blink::PermissionType permission,
content::RenderProcessHost* render_process_host,
const GURL& worker_origin) {
return GetPermissionStatus(permission, worker_origin, worker_origin);
}
blink::mojom::PermissionStatus
ElectronPermissionManager::GetPermissionStatusForEmbeddedRequester(
blink::PermissionType permission,
content::RenderFrameHost* render_frame_host,
const url::Origin& overridden_origin) {
if (render_frame_host->IsNestedWithinFencedFrame())
return blink::mojom::PermissionStatus::DENIED;
return GetPermissionStatus(
permission, overridden_origin.GetURL(),
render_frame_host->GetLastCommittedOrigin().GetURL());
}
} // namespace electron