fix: validate USB device selection against filtered device list (#50002)

* fix: validate USB device selection against filtered device list

Previously, UsbChooserController::OnDeviceChosen looked up the chosen
device_id via chooser_context_->GetDeviceInfo(), which searches all
known USB devices on the system rather than the filtered list shown to
the select-usb-device handler. This meant a device excluded by the
renderer's filters or exclusion_filters could still be granted
permission if the handler returned its GUID.

* bump for CI

---------

Co-authored-by: John Kleinschmidt <kleinschmidtorama@gmail.com>
This commit is contained in:
Shelley Vohr
2026-03-03 10:44:33 +01:00
committed by GitHub
parent f037673655
commit f68f3419dc
2 changed files with 18 additions and 3 deletions

View File

@@ -68,6 +68,7 @@ gin::WeakCell<api::Session>* UsbChooserController::GetSession() {
void UsbChooserController::OnDeviceAdded(
const device::mojom::UsbDeviceInfo& device_info) {
if (DisplayDevice(device_info)) {
devices_.push_back(device_info.Clone());
gin::WeakCell<api::Session>* session = GetSession();
if (session && session->Get()) {
session->Get()->Emit("usb-device-added", device_info.Clone(),
@@ -78,6 +79,9 @@ void UsbChooserController::OnDeviceAdded(
void UsbChooserController::OnDeviceRemoved(
const device::mojom::UsbDeviceInfo& device_info) {
std::erase_if(devices_, [&device_info](const auto& device) {
return device->guid == device_info.guid;
});
gin::WeakCell<api::Session>* session = GetSession();
if (session && session->Get()) {
session->Get()->Emit("usb-device-removed", device_info.Clone(),
@@ -90,9 +94,11 @@ void UsbChooserController::OnDeviceChosen(gin::Arguments* args) {
if (!args->GetNext(&device_id) || device_id.empty()) {
RunCallback(/*device_info=*/nullptr);
} else {
auto* device_info = chooser_context_->GetDeviceInfo(device_id);
if (device_info) {
RunCallback(device_info->Clone());
const auto it = std::ranges::find_if(
devices_,
[&device_id](const auto& device) { return device->guid == device_id; });
if (it != devices_.end()) {
RunCallback((*it)->Clone());
} else {
util::EmitWarning(
base::StrCat({"The device id ", device_id, " was not found."}),
@@ -127,6 +133,11 @@ void UsbChooserController::GotUsbDeviceList(
return !DisplayDevice(*device_info);
});
devices_.clear();
for (const auto& device : devices) {
devices_.push_back(device->Clone());
}
v8::Local<v8::Object> details = gin::DataObjectBuilder(isolate)
.Set("deviceList", devices)
.Set("frame", rfh)

View File

@@ -5,6 +5,7 @@
#ifndef ELECTRON_SHELL_BROWSER_USB_USB_CHOOSER_CONTROLLER_H_
#define ELECTRON_SHELL_BROWSER_USB_USB_CHOOSER_CONTROLLER_H_
#include <string>
#include <vector>
#include "base/memory/weak_ptr.h"
@@ -75,6 +76,9 @@ class UsbChooserController final : private UsbChooserContext::DeviceObserver,
base::WeakPtr<ElectronUsbDelegate> usb_delegate_;
// Filtered list of devices that passed DisplayDevice()
std::vector<device::mojom::UsbDeviceInfoPtr> devices_;
content::GlobalRenderFrameHostId render_frame_host_id_;
base::WeakPtrFactory<UsbChooserController> weak_factory_{this};