feat: support Web Serial & WebUSB blocklists (#46600)

This commit is contained in:
Shelley Vohr 2025-04-17 20:34:34 +02:00 committed by GitHub
parent 352a403efd
commit a29e1170b9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 106 additions and 4 deletions

View file

@ -85,6 +85,8 @@ static_library("chrome") {
"//chrome/browser/process_singleton.h",
"//chrome/browser/process_singleton_internal.cc",
"//chrome/browser/process_singleton_internal.h",
"//chrome/browser/serial/serial_blocklist.cc",
"//chrome/browser/serial/serial_blocklist.h",
"//chrome/browser/themes/browser_theme_pack.cc",
"//chrome/browser/themes/browser_theme_pack.h",
"//chrome/browser/themes/custom_theme_supplier.cc",
@ -144,6 +146,8 @@ static_library("chrome") {
"//chrome/browser/ui/views/overlay/video_overlay_window_views.h",
"//chrome/browser/ui/webui/accessibility/accessibility_ui.cc",
"//chrome/browser/ui/webui/accessibility/accessibility_ui.h",
"//chrome/browser/usb/usb_blocklist.cc",
"//chrome/browser/usb/usb_blocklist.h",
"//extensions/browser/app_window/size_constraints.cc",
"//extensions/browser/app_window/size_constraints.h",
"//ui/base/accelerators/global_accelerator_listener/global_accelerator_listener.cc",

View file

@ -14,6 +14,12 @@ This document uses the following convention to categorize breaking changes:
## Planned Breaking API Changes (37.0)
### Behavior Changed: WebUSB and WebSerial Blocklist Support
[WebUSB](https://developer.mozilla.org/en-US/docs/Web/API/WebUSB_API) and [Web Serial](https://developer.mozilla.org/en-US/docs/Web/API/Web_Serial_API) now support the [WebUSB Blocklist](https://wicg.github.io/webusb/#blocklist) and [Web Serial Blocklist](https://wicg.github.io/serial/#blocklist) used by Chromium and outlined in their respective specifications.
To disable these, users can pass `disable-usb-blocklist` and `disable-serial-blocklist` as command line flags.
### Removed: `null` value for `session` property in `ProtocolResponse`
This deprecated feature has been removed.

View file

@ -57,7 +57,7 @@ the WebHID API:
### Blocklist
By default Electron employs the same [blocklist](https://github.com/WICG/webhid/blob/main/blocklist.txt)
By default Electron employs the same [blocklist](https://wicg.github.io/webhid/#blocklist)
used by Chromium. If you wish to override this behavior, you can do so by
setting the `disable-hid-blocklist` flag:
@ -104,6 +104,16 @@ There are several additional APIs for working with the Web Serial API:
* [`ses.setPermissionCheckHandler(handler)`](../api/session.md#sessetpermissioncheckhandlerhandler)
can be used to disable serial access for specific origins.
### Blocklist
By default Electron employs the same [blocklist](https://wicg.github.io/serial/#blocklist)
used by Chromium. If you wish to override this behavior, you can do so by
setting the `disable-serial-blocklist` flag:
```js
app.commandLine.appendSwitch('disable-serial-blocklist')
```
### Example
This example demonstrates an Electron application that automatically selects
@ -145,6 +155,16 @@ Electron provides several APIs for working with the WebUSB API:
* [`ses.setUSBProtectedClassesHandler](../api/session.md#sessetusbprotectedclasseshandlerhandler)
can be used to allow usage of [protected USB classes](https://wicg.github.io/webusb/#usbinterface-interface) that are not available by default.
### Blocklist
By default Electron employs the same [blocklist](https://wicg.github.io/webusb/#blocklist)
used by Chromium. If you wish to override this behavior, you can do so by
setting the `disable-usb-blocklist` flag:
```js
app.commandLine.appendSwitch('disable-usb-blocklist')
```
### Example
This example demonstrates an Electron application that automatically selects

View file

@ -9,7 +9,9 @@
#include <utility>
#include "base/base64.h"
#include "base/command_line.h"
#include "base/values.h"
#include "chrome/browser/serial/serial_blocklist.h"
#include "content/public/browser/device_service.h"
#include "content/public/browser/web_contents.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
@ -104,6 +106,12 @@ bool SerialChooserContext::HasPortPermission(
const url::Origin& origin,
const device::mojom::SerialPortInfo& port,
content::RenderFrameHost* render_frame_host) {
bool blocklist_disabled = base::CommandLine::ForCurrentProcess()->HasSwitch(
kDisableSerialBlocklist);
if (!blocklist_disabled && SerialBlocklist::Get().IsExcluded(port)) {
return false;
}
auto it = ephemeral_ports_.find(origin);
if (it != ephemeral_ports_.end()) {
const std::set<base::UnguessableToken>& ports = it->second;

View file

@ -36,6 +36,8 @@ namespace electron {
class ElectronBrowserContext;
const char kDisableSerialBlocklist[] = "disable-serial-blocklist";
inline constexpr std::string_view kPortNameKey = "name";
inline constexpr std::string_view kTokenKey = "token";
inline constexpr std::string_view kBluetoothDevicePathKey =

View file

@ -7,9 +7,12 @@
#include <algorithm>
#include <utility>
#include "base/command_line.h"
#include "base/containers/contains.h"
#include "base/functional/bind.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/serial/serial_blocklist.h"
#include "content/public/browser/console_message.h"
#include "content/public/browser/web_contents.h"
#include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
@ -120,8 +123,7 @@ SerialChooserController::SerialChooserController(
allowed_bluetooth_service_class_ids_(
std::move(allowed_bluetooth_service_class_ids)),
callback_(std::move(callback)),
serial_delegate_(serial_delegate),
render_frame_host_id_(render_frame_host->GetGlobalId()) {
initiator_document_(render_frame_host->GetWeakDocumentPtr()) {
origin_ = web_contents_->GetPrimaryMainFrame()->GetLastCommittedOrigin();
chooser_context_ = SerialChooserContextFactory::GetForBrowserContext(
@ -210,7 +212,7 @@ void SerialChooserController::OnDeviceChosen(const std::string& port_id) {
return ptr->token.ToString() == port_id;
});
if (it != ports_.end()) {
auto* rfh = content::RenderFrameHost::FromID(render_frame_host_id_);
auto* rfh = initiator_document_.AsRenderFrameHostIfValid();
chooser_context_->GrantPortPermission(origin_, *it->get(), rfh);
RunCallback(it->Clone());
} else {
@ -246,6 +248,34 @@ void SerialChooserController::OnGetDevices(
bool SerialChooserController::DisplayDevice(
const device::mojom::SerialPortInfo& port) const {
bool blocklist_disabled = base::CommandLine::ForCurrentProcess()->HasSwitch(
kDisableSerialBlocklist);
if (!blocklist_disabled && SerialBlocklist::Get().IsExcluded(port)) {
if (port.has_vendor_id && port.has_product_id) {
AddMessageToConsole(
blink::mojom::ConsoleMessageLevel::kInfo,
base::StringPrintf(
"Skipping a port blocked by "
"the Serial blocklist: vendorId=%d, "
"productId=%d, name='%s', serial='%s'",
port.vendor_id, port.product_id,
port.display_name ? port.display_name.value().c_str() : "",
port.serial_number ? port.serial_number.value().c_str() : ""));
} else if (port.bluetooth_service_class_id) {
AddMessageToConsole(
blink::mojom::ConsoleMessageLevel::kInfo,
base::StringPrintf(
"Skipping a port blocked by "
"the Serial blocklist: bluetoothServiceClassId=%s, "
"name='%s'",
port.bluetooth_service_class_id->value().c_str(),
port.display_name ? port.display_name.value().c_str() : ""));
} else {
NOTREACHED();
}
return false;
}
if (filters_.empty()) {
return BluetoothPortIsAllowed(allowed_bluetooth_service_class_ids_, port);
}
@ -260,6 +290,15 @@ bool SerialChooserController::DisplayDevice(
return false;
}
void SerialChooserController::AddMessageToConsole(
blink::mojom::ConsoleMessageLevel level,
const std::string& message) const {
if (content::RenderFrameHost* rfh =
initiator_document_.AsRenderFrameHostIfValid()) {
rfh->AddMessageToConsole(level, message);
}
}
void SerialChooserController::RunCallback(
device::mojom::SerialPortInfoPtr port) {
if (callback_) {

View file

@ -12,9 +12,11 @@
#include "base/scoped_observation.h"
#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/serial_chooser.h"
#include "content/public/browser/weak_document_ptr.h"
#include "device/bluetooth/bluetooth_adapter.h"
#include "services/device/public/mojom/serial.mojom-forward.h"
#include "shell/browser/serial/serial_chooser_context.h"
#include "third_party/blink/public/mojom/devtools/console_message.mojom.h"
#include "third_party/blink/public/mojom/serial/serial.mojom-forward.h"
namespace content {
@ -66,6 +68,8 @@ class SerialChooserController final
void GetDevices();
void OnGetDevices(std::vector<device::mojom::SerialPortInfoPtr> ports);
bool DisplayDevice(const device::mojom::SerialPortInfo& port) const;
void AddMessageToConsole(blink::mojom::ConsoleMessageLevel level,
const std::string& message) const;
void RunCallback(device::mojom::SerialPortInfoPtr port);
void OnDeviceChosen(const std::string& port_id);
void OnGetAdapter(base::OnceClosure callback,
@ -78,6 +82,7 @@ class SerialChooserController final
std::vector<blink::mojom::SerialPortFilterPtr> filters_;
std::vector<::device::BluetoothUUID> allowed_bluetooth_service_class_ids_;
content::SerialChooser::Callback callback_;
content::WeakDocumentPtr initiator_document_;
url::Origin origin_;
base::WeakPtr<SerialChooserContext> chooser_context_;

View file

@ -8,9 +8,11 @@
#include <utility>
#include <vector>
#include "base/command_line.h"
#include "base/functional/bind.h"
#include "base/task/sequenced_task_runner.h"
#include "base/values.h"
#include "chrome/browser/usb/usb_blocklist.h"
#include "components/content_settings/core/common/content_settings.h"
#include "content/public/browser/device_service.h"
#include "services/device/public/cpp/usb/usb_ids.h"
@ -215,6 +217,12 @@ void UsbChooserContext::GrantDevicePermission(
bool UsbChooserContext::HasDevicePermission(
const url::Origin& origin,
const device::mojom::UsbDeviceInfo& device_info) {
bool blocklist_disabled =
base::CommandLine::ForCurrentProcess()->HasSwitch(kDisableUSBBlocklist);
if (!blocklist_disabled && UsbBlocklist::Get().IsExcluded(device_info)) {
return false;
}
auto it = ephemeral_devices_.find(origin);
if (it != ephemeral_devices_.end() && it->second.contains(device_info.guid)) {
return true;

View file

@ -33,6 +33,8 @@ namespace electron {
class ElectronBrowserContext;
const char kDisableUSBBlocklist[] = "disable-usb-blocklist";
class UsbChooserContext : public KeyedService,
public device::mojom::UsbDeviceManagerClient {
public:

View file

@ -8,7 +8,9 @@
#include <cstddef>
#include <utility>
#include "base/command_line.h"
#include "base/functional/bind.h"
#include "chrome/browser/usb/usb_blocklist.h"
#include "components/strings/grit/components_strings.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
@ -140,6 +142,8 @@ void UsbChooserController::GotUsbDeviceList(
bool UsbChooserController::DisplayDevice(
const device::mojom::UsbDeviceInfo& device_info) const {
bool blocklist_disabled =
base::CommandLine::ForCurrentProcess()->HasSwitch(kDisableUSBBlocklist);
if (!device::UsbDeviceFilterMatchesAny(options_->filters, device_info)) {
return false;
}
@ -151,6 +155,10 @@ bool UsbChooserController::DisplayDevice(
return false;
}
if (!blocklist_disabled && UsbBlocklist::Get().IsExcluded(device_info)) {
return false;
}
return true;
}