// Copyright 2015 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/usb/web_usb_permission_provider.h" #include #include #include "chrome/browser/profiles/profile.h" #include "chrome/browser/usb/usb_chooser_context.h" #include "chrome/browser/usb/usb_chooser_context_factory.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" #include "device/core/device_client.h" using content::WebContents; using device::usb::WebUsbDescriptorSet; using device::usb::WebUsbConfigurationSubsetPtr; using device::usb::WebUsbFunctionSubsetPtr; namespace { bool FindOriginInDescriptorSet(const WebUsbDescriptorSet* set, const GURL& origin, const uint8_t* configuration_value, const uint8_t* interface_number) { if (!set) return false; for (size_t i = 0; i < set->origins.size(); ++i) { if (origin.spec() == set->origins[i]) return true; } for (size_t i = 0; i < set->configurations.size(); ++i) { const device::usb::WebUsbConfigurationSubsetPtr& config = set->configurations[i]; if (configuration_value && *configuration_value != config->configuration_value) continue; for (size_t j = 0; i < config->origins.size(); ++j) { if (origin.spec() == config->origins[j]) return true; } for (size_t j = 0; j < config->functions.size(); ++j) { const device::usb::WebUsbFunctionSubsetPtr& function = config->functions[j]; // TODO(reillyg): Implement support for Interface Association Descriptors // so that this check will match associated interfaces. if (interface_number && *interface_number != function->first_interface) continue; for (size_t k = 0; k < function->origins.size(); ++k) { if (origin.spec() == function->origins[k]) return true; } } } return false; } } // namespace WebUSBPermissionProvider::WebUSBPermissionProvider( content::RenderFrameHost* render_frame_host) : render_frame_host_(render_frame_host) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK(render_frame_host_); } WebUSBPermissionProvider::~WebUSBPermissionProvider() {} void WebUSBPermissionProvider::HasDevicePermission( mojo::Array requested_devices, const HasDevicePermissionCallback& callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); WebContents* web_contents = WebContents::FromRenderFrameHost(render_frame_host_); GURL embedding_origin = web_contents->GetMainFrame()->GetLastCommittedURL().GetOrigin(); GURL requesting_origin = render_frame_host_->GetLastCommittedURL().GetOrigin(); Profile* profile = Profile::FromBrowserContext(web_contents->GetBrowserContext()); UsbChooserContext* chooser_context = UsbChooserContextFactory::GetForProfile(profile); mojo::Array allowed_guids(0); for (size_t i = 0; i < requested_devices.size(); ++i) { const device::usb::DeviceInfoPtr& device = requested_devices[i]; if (FindOriginInDescriptorSet(device->webusb_allowed_origins.get(), requesting_origin, nullptr, nullptr) && chooser_context->HasDevicePermission(requesting_origin, embedding_origin, device->guid)) allowed_guids.push_back(device->guid); } callback.Run(std::move(allowed_guids)); } void WebUSBPermissionProvider::HasConfigurationPermission( uint8_t requested_configuration_value, device::usb::DeviceInfoPtr device, const HasInterfacePermissionCallback& callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); callback.Run(FindOriginInDescriptorSet( device->webusb_allowed_origins.get(), render_frame_host_->GetLastCommittedURL().GetOrigin(), &requested_configuration_value, nullptr)); } void WebUSBPermissionProvider::HasInterfacePermission( uint8_t requested_interface, uint8_t configuration_value, device::usb::DeviceInfoPtr device, const HasInterfacePermissionCallback& callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); callback.Run(FindOriginInDescriptorSet( device->webusb_allowed_origins.get(), render_frame_host_->GetLastCommittedURL().GetOrigin(), &configuration_value, &requested_interface)); } void WebUSBPermissionProvider::Bind( mojo::InterfaceRequest request) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); bindings_.AddBinding(this, std::move(request)); }