diff --git a/chromium_src/BUILD.gn b/chromium_src/BUILD.gn index 60fb38aab58d..a9a7cee308ef 100644 --- a/chromium_src/BUILD.gn +++ b/chromium_src/BUILD.gn @@ -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", diff --git a/docs/breaking-changes.md b/docs/breaking-changes.md index 3d570fda9e77..f0556a639aa1 100644 --- a/docs/breaking-changes.md +++ b/docs/breaking-changes.md @@ -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. diff --git a/docs/tutorial/devices.md b/docs/tutorial/devices.md index ae6d21ae6bd6..37af4e01fd2d 100644 --- a/docs/tutorial/devices.md +++ b/docs/tutorial/devices.md @@ -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 diff --git a/shell/browser/serial/serial_chooser_context.cc b/shell/browser/serial/serial_chooser_context.cc index be387c644e9a..c0ae6ed24851 100644 --- a/shell/browser/serial/serial_chooser_context.cc +++ b/shell/browser/serial/serial_chooser_context.cc @@ -9,7 +9,9 @@ #include #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& ports = it->second; diff --git a/shell/browser/serial/serial_chooser_context.h b/shell/browser/serial/serial_chooser_context.h index 0dbeb15dc81f..100287e52e25 100644 --- a/shell/browser/serial/serial_chooser_context.h +++ b/shell/browser/serial/serial_chooser_context.h @@ -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 = diff --git a/shell/browser/serial/serial_chooser_controller.cc b/shell/browser/serial/serial_chooser_controller.cc index 9ab960a3b978..217f495fd02a 100644 --- a/shell/browser/serial/serial_chooser_controller.cc +++ b/shell/browser/serial/serial_chooser_controller.cc @@ -7,9 +7,12 @@ #include #include +#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_) { diff --git a/shell/browser/serial/serial_chooser_controller.h b/shell/browser/serial/serial_chooser_controller.h index e88db05bb80e..b030be80c8c0 100644 --- a/shell/browser/serial/serial_chooser_controller.h +++ b/shell/browser/serial/serial_chooser_controller.h @@ -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 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 filters_; std::vector<::device::BluetoothUUID> allowed_bluetooth_service_class_ids_; content::SerialChooser::Callback callback_; + content::WeakDocumentPtr initiator_document_; url::Origin origin_; base::WeakPtr chooser_context_; diff --git a/shell/browser/usb/usb_chooser_context.cc b/shell/browser/usb/usb_chooser_context.cc index 1273b7dbd41e..1cb603734924 100644 --- a/shell/browser/usb/usb_chooser_context.cc +++ b/shell/browser/usb/usb_chooser_context.cc @@ -8,9 +8,11 @@ #include #include +#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; diff --git a/shell/browser/usb/usb_chooser_context.h b/shell/browser/usb/usb_chooser_context.h index d62c9ad5edfb..1f1929b4168c 100644 --- a/shell/browser/usb/usb_chooser_context.h +++ b/shell/browser/usb/usb_chooser_context.h @@ -33,6 +33,8 @@ namespace electron { class ElectronBrowserContext; +const char kDisableUSBBlocklist[] = "disable-usb-blocklist"; + class UsbChooserContext : public KeyedService, public device::mojom::UsbDeviceManagerClient { public: diff --git a/shell/browser/usb/usb_chooser_controller.cc b/shell/browser/usb/usb_chooser_controller.cc index ccc8c8c2bb11..d786846a0e86 100644 --- a/shell/browser/usb/usb_chooser_controller.cc +++ b/shell/browser/usb/usb_chooser_controller.cc @@ -8,7 +8,9 @@ #include #include +#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; }