|  | // 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 <stddef.h> | 
|  | #include <utility> | 
|  |  | 
|  | #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<device::usb::DeviceInfoPtr> 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<mojo::String> 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<device::usb::PermissionProvider> request) { | 
|  | DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 
|  | bindings_.AddBinding(this, std::move(request)); | 
|  | } |