Browse Source

fix: WebUSB should not crash when using in-memory partitions (#42365)

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <[email protected]>
trop[bot] 10 months ago
parent
commit
bd17a98386

+ 37 - 10
shell/browser/usb/electron_usb_delegate.cc

@@ -174,6 +174,9 @@ std::unique_ptr<content::UsbChooser> ElectronUsbDelegate::RunChooser(
 bool ElectronUsbDelegate::CanRequestDevicePermission(
     content::BrowserContext* browser_context,
     const url::Origin& origin) {
+  if (!browser_context)
+    return false;
+
   base::Value::Dict details;
   details.Set("securityOrigin", origin.GetURL().spec());
   auto* permission_manager = static_cast<ElectronPermissionManager*>(
@@ -188,32 +191,46 @@ void ElectronUsbDelegate::RevokeDevicePermissionWebInitiated(
     content::BrowserContext* browser_context,
     const url::Origin& origin,
     const device::mojom::UsbDeviceInfo& device) {
-  GetChooserContext(browser_context)
-      ->RevokeDevicePermissionWebInitiated(origin, device);
+  auto* chooser_context = GetChooserContext(browser_context);
+  if (chooser_context) {
+    chooser_context->RevokeDevicePermissionWebInitiated(origin, device);
+  }
 }
 
 const device::mojom::UsbDeviceInfo* ElectronUsbDelegate::GetDeviceInfo(
     content::BrowserContext* browser_context,
     const std::string& guid) {
-  return GetChooserContext(browser_context)->GetDeviceInfo(guid);
+  auto* chooser_context = GetChooserContext(browser_context);
+  if (!chooser_context)
+    return nullptr;
+  return chooser_context->GetDeviceInfo(guid);
 }
 
 bool ElectronUsbDelegate::HasDevicePermission(
     content::BrowserContext* browser_context,
     content::RenderFrameHost* frame,
     const url::Origin& origin,
-    const device::mojom::UsbDeviceInfo& device) {
-  if (IsDevicePermissionAutoGranted(origin, device))
+    const device::mojom::UsbDeviceInfo& device_info) {
+  if (IsDevicePermissionAutoGranted(origin, device_info))
     return true;
 
+  auto* chooser_context = GetChooserContext(browser_context);
+  if (!chooser_context)
+    return false;
+
   return GetChooserContext(browser_context)
-      ->HasDevicePermission(origin, device);
+      ->HasDevicePermission(origin, device_info);
 }
 
 void ElectronUsbDelegate::GetDevices(
     content::BrowserContext* browser_context,
     blink::mojom::WebUsbService::GetDevicesCallback callback) {
-  GetChooserContext(browser_context)->GetDevices(std::move(callback));
+  auto* chooser_context = GetChooserContext(browser_context);
+  if (!chooser_context) {
+    std::move(callback).Run(std::vector<device::mojom::UsbDeviceInfoPtr>());
+    return;
+  }
+  chooser_context->GetDevices(std::move(callback));
 }
 
 void ElectronUsbDelegate::GetDevice(
@@ -222,25 +239,35 @@ void ElectronUsbDelegate::GetDevice(
     base::span<const uint8_t> blocked_interface_classes,
     mojo::PendingReceiver<device::mojom::UsbDevice> device_receiver,
     mojo::PendingRemote<device::mojom::UsbDeviceClient> device_client) {
-  GetChooserContext(browser_context)
-      ->GetDevice(guid, blocked_interface_classes, std::move(device_receiver),
-                  std::move(device_client));
+  auto* chooser_context = GetChooserContext(browser_context);
+  if (chooser_context) {
+    chooser_context->GetDevice(guid, blocked_interface_classes,
+                               std::move(device_receiver),
+                               std::move(device_client));
+  }
 }
 
 void ElectronUsbDelegate::AddObserver(content::BrowserContext* browser_context,
                                       Observer* observer) {
+  if (!browser_context)
+    return;
+
   GetContextObserver(browser_context)->AddObserver(observer);
 }
 
 void ElectronUsbDelegate::RemoveObserver(
     content::BrowserContext* browser_context,
     Observer* observer) {
+  if (!browser_context)
+    return;
+
   GetContextObserver(browser_context)->RemoveObserver(observer);
 }
 
 ElectronUsbDelegate::ContextObservation*
 ElectronUsbDelegate::GetContextObserver(
     content::BrowserContext* browser_context) {
+  CHECK(browser_context);
   if (!base::Contains(observations_, browser_context)) {
     observations_.emplace(browser_context, std::make_unique<ContextObservation>(
                                                this, browser_context));

+ 5 - 4
shell/browser/usb/electron_usb_delegate.h

@@ -56,10 +56,11 @@ class ElectronUsbDelegate : public content::UsbDelegate {
   const device::mojom::UsbDeviceInfo* GetDeviceInfo(
       content::BrowserContext* browser_context,
       const std::string& guid) override;
-  bool HasDevicePermission(content::BrowserContext* browser_context,
-                           content::RenderFrameHost* frame,
-                           const url::Origin& origin,
-                           const device::mojom::UsbDeviceInfo& device) override;
+  bool HasDevicePermission(
+      content::BrowserContext* browser_context,
+      content::RenderFrameHost* frame,
+      const url::Origin& origin,
+      const device::mojom::UsbDeviceInfo& device_info) override;
   void GetDevices(
       content::BrowserContext* browser_context,
       blink::mojom::WebUsbService::GetDevicesCallback callback) override;

+ 26 - 0
spec/chromium-spec.ts

@@ -3505,18 +3505,44 @@ describe('navigator.usb', () => {
     `, true);
   };
 
+  const getDevices: any = () => {
+    return w.webContents.executeJavaScript(`
+      navigator.usb.getDevices().then(devices => devices.map(device => device.toString())).catch(err => err.toString());
+    `, true);
+  };
+
   const notFoundError = 'NotFoundError: Failed to execute \'requestDevice\' on \'USB\': No device selected.';
 
   after(() => {
     server.close();
     closeAllWindows();
   });
+
   afterEach(() => {
     session.defaultSession.setPermissionCheckHandler(null);
     session.defaultSession.setDevicePermissionHandler(null);
     session.defaultSession.removeAllListeners('select-usb-device');
   });
 
+  it('does not crash when using in-memory partitions', async () => {
+    const sesWin = new BrowserWindow({
+      webPreferences: {
+        partition: 'test-partition'
+      }
+    });
+
+    await sesWin.loadFile(path.join(fixturesPath, 'pages', 'blank.html'));
+    server = http.createServer((req, res) => {
+      res.setHeader('Content-Type', 'text/html');
+      res.end('<body>');
+    });
+
+    serverUrl = (await listen(server)).url;
+
+    const devices = await getDevices();
+    expect(devices).to.be.an('array').that.is.empty();
+  });
+
   it('does not return a device if select-usb-device event is not defined', async () => {
     w.loadFile(path.join(fixturesPath, 'pages', 'blank.html'));
     const device = await requestDevices();