mirror of
https://github.com/electron/electron.git
synced 2026-04-10 03:01:51 -04:00
* fix: use requesting frame origin instead of top-level URL for permissions `WebContentsPermissionHelper::RequestPermission` passes `web_contents_->GetLastCommittedURL()` as the origin to the permission manager instead of the actual requesting frame's origin. This enables origin confusion when granting permissions to embedded third-party iframes, since app permission handlers see the top-level origin instead of the iframe's. The same pattern exists in the HID, USB, and Serial device choosers, where grants are keyed to the primary main frame's origin rather than the requesting frame's. Fix this by using `requesting_frame->GetLastCommittedOrigin()` in all affected code paths, renaming `details.requestingUrl` to `details.requestingOrigin`, and populating it with the serialized origin only. Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com> * chore: keep requestingUrl name in permission handler details The previous commit changed the details.requestingUrl field to details.requestingOrigin in permission request/check handlers. That field was already populated from the requesting frame's RFH, so the rename was unnecessary and would break apps that read the existing property. Revert to requestingUrl to preserve the existing API shape. The functional changes to use the requesting frame in WebContentsPermissionHelper and the HID/USB/Serial choosers remain. Co-authored-by: Samuel Attard <sattard@anthropic.com> --------- Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com> Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com> Co-authored-by: Samuel Attard <sattard@anthropic.com>
147 lines
5.4 KiB
C++
147 lines
5.4 KiB
C++
// Copyright (c) 2020 Microsoft, Inc.
|
|
// Use of this source code is governed by the MIT license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "shell/browser/serial/electron_serial_delegate.h"
|
|
|
|
#include <utility>
|
|
|
|
#include "base/feature_list.h"
|
|
#include "content/public/browser/web_contents.h"
|
|
#include "shell/browser/api/electron_api_web_contents.h"
|
|
#include "shell/browser/serial/serial_chooser_context.h"
|
|
#include "shell/browser/serial/serial_chooser_context_factory.h"
|
|
#include "shell/browser/serial/serial_chooser_controller.h"
|
|
#include "shell/browser/web_contents_permission_helper.h"
|
|
|
|
namespace electron {
|
|
|
|
SerialChooserContext* GetChooserContext(content::RenderFrameHost* frame) {
|
|
auto* web_contents = content::WebContents::FromRenderFrameHost(frame);
|
|
auto* browser_context = web_contents->GetBrowserContext();
|
|
return SerialChooserContextFactory::GetForBrowserContext(browser_context);
|
|
}
|
|
|
|
ElectronSerialDelegate::ElectronSerialDelegate() = default;
|
|
|
|
ElectronSerialDelegate::~ElectronSerialDelegate() = default;
|
|
|
|
std::unique_ptr<content::SerialChooser> ElectronSerialDelegate::RunChooser(
|
|
content::RenderFrameHost* frame,
|
|
std::vector<blink::mojom::SerialPortFilterPtr> filters,
|
|
std::vector<device::BluetoothUUID> allowed_bluetooth_service_class_ids,
|
|
content::SerialChooser::Callback callback) {
|
|
SerialChooserController* controller = ControllerForFrame(frame);
|
|
if (controller) {
|
|
DeleteControllerForFrame(frame);
|
|
}
|
|
AddControllerForFrame(frame, std::move(filters),
|
|
std::move(allowed_bluetooth_service_class_ids),
|
|
std::move(callback));
|
|
|
|
// Return a nullptr because the return value isn't used for anything, eg
|
|
// there is no mechanism to cancel navigator.serial.requestPort(). The return
|
|
// value is simply used in Chromium to cleanup the chooser UI once the serial
|
|
// service is destroyed.
|
|
return nullptr;
|
|
}
|
|
|
|
bool ElectronSerialDelegate::CanRequestPortPermission(
|
|
content::RenderFrameHost* frame) {
|
|
auto* web_contents = content::WebContents::FromRenderFrameHost(frame);
|
|
auto* permission_helper =
|
|
WebContentsPermissionHelper::FromWebContents(web_contents);
|
|
return permission_helper->CheckSerialAccessPermission(
|
|
frame->GetLastCommittedOrigin());
|
|
}
|
|
|
|
bool ElectronSerialDelegate::HasPortPermission(
|
|
content::RenderFrameHost* frame,
|
|
const device::mojom::SerialPortInfo& port) {
|
|
return GetChooserContext(frame)->HasPortPermission(
|
|
frame->GetLastCommittedOrigin(), port, frame);
|
|
}
|
|
|
|
void ElectronSerialDelegate::RevokePortPermissionWebInitiated(
|
|
content::RenderFrameHost* frame,
|
|
const base::UnguessableToken& token) {
|
|
return GetChooserContext(frame)->RevokePortPermissionWebInitiated(
|
|
frame->GetLastCommittedOrigin(), token, frame);
|
|
}
|
|
|
|
const device::mojom::SerialPortInfo* ElectronSerialDelegate::GetPortInfo(
|
|
content::RenderFrameHost* frame,
|
|
const base::UnguessableToken& token) {
|
|
return GetChooserContext(frame)->GetPortInfo(token);
|
|
}
|
|
|
|
device::mojom::SerialPortManager* ElectronSerialDelegate::GetPortManager(
|
|
content::RenderFrameHost* frame) {
|
|
return GetChooserContext(frame)->GetPortManager();
|
|
}
|
|
|
|
void ElectronSerialDelegate::AddObserver(
|
|
content::RenderFrameHost* frame,
|
|
content::SerialDelegate::Observer* observer) {
|
|
observer_list_.AddObserver(observer);
|
|
auto* chooser_context = GetChooserContext(frame);
|
|
if (!port_observation_.IsObserving())
|
|
port_observation_.Observe(chooser_context);
|
|
}
|
|
|
|
void ElectronSerialDelegate::RemoveObserver(
|
|
content::RenderFrameHost* frame,
|
|
content::SerialDelegate::Observer* observer) {
|
|
observer_list_.RemoveObserver(observer);
|
|
}
|
|
|
|
SerialChooserController* ElectronSerialDelegate::ControllerForFrame(
|
|
content::RenderFrameHost* render_frame_host) {
|
|
auto mapping = controller_map_.find(render_frame_host);
|
|
return mapping == controller_map_.end() ? nullptr : mapping->second.get();
|
|
}
|
|
|
|
SerialChooserController* ElectronSerialDelegate::AddControllerForFrame(
|
|
content::RenderFrameHost* render_frame_host,
|
|
std::vector<blink::mojom::SerialPortFilterPtr> filters,
|
|
std::vector<device::BluetoothUUID> allowed_bluetooth_service_class_ids,
|
|
content::SerialChooser::Callback callback) {
|
|
auto* web_contents =
|
|
content::WebContents::FromRenderFrameHost(render_frame_host);
|
|
auto controller = std::make_unique<SerialChooserController>(
|
|
render_frame_host, std::move(filters),
|
|
std::move(allowed_bluetooth_service_class_ids), std::move(callback),
|
|
web_contents, weak_factory_.GetWeakPtr());
|
|
controller_map_.try_emplace(render_frame_host, std::move(controller));
|
|
return ControllerForFrame(render_frame_host);
|
|
}
|
|
|
|
void ElectronSerialDelegate::DeleteControllerForFrame(
|
|
content::RenderFrameHost* render_frame_host) {
|
|
controller_map_.erase(render_frame_host);
|
|
}
|
|
|
|
// SerialChooserContext::PortObserver:
|
|
void ElectronSerialDelegate::OnPortAdded(
|
|
const device::mojom::SerialPortInfo& port) {
|
|
observer_list_.Notify(&content::SerialDelegate::Observer::OnPortAdded, port);
|
|
}
|
|
|
|
void ElectronSerialDelegate::OnPortRemoved(
|
|
const device::mojom::SerialPortInfo& port) {
|
|
observer_list_.Notify(&content::SerialDelegate::Observer::OnPortRemoved,
|
|
port);
|
|
}
|
|
|
|
void ElectronSerialDelegate::OnPortManagerConnectionError() {
|
|
port_observation_.Reset();
|
|
observer_list_.Notify(
|
|
&content::SerialDelegate::Observer::OnPortManagerConnectionError);
|
|
}
|
|
|
|
void ElectronSerialDelegate::OnSerialChooserContextShutdown() {
|
|
port_observation_.Reset();
|
|
}
|
|
|
|
} // namespace electron
|