| // 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 "base/command_line.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/render_frame_host.h" |
| #include "device/core/device_client.h" |
| |
| 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; |
| } |
| |
| bool EnableWebUsbOnAnyOrigin() { |
| return base::CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kEnableWebUsbOnAnyOrigin); |
| } |
| |
| } // namespace |
| |
| // static |
| void WebUSBPermissionProvider::Create( |
| content::RenderFrameHost* render_frame_host, |
| mojo::InterfaceRequest<PermissionProvider> request) { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| DCHECK(render_frame_host); |
| |
| // The created object is owned by its bindings. |
| new WebUSBPermissionProvider(render_frame_host, request.Pass()); |
| } |
| |
| WebUSBPermissionProvider::~WebUSBPermissionProvider() {} |
| |
| WebUSBPermissionProvider::WebUSBPermissionProvider( |
| content::RenderFrameHost* render_frame_host, |
| mojo::InterfaceRequest<PermissionProvider> request) |
| : render_frame_host_(render_frame_host) { |
| bindings_.set_connection_error_handler(base::Bind( |
| &WebUSBPermissionProvider::OnConnectionError, base::Unretained(this))); |
| bindings_.AddBinding(this, request.Pass()); |
| } |
| |
| void WebUSBPermissionProvider::HasDevicePermission( |
| mojo::Array<device::usb::DeviceInfoPtr> requested_devices, |
| const HasDevicePermissionCallback& callback) { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| GURL origin = render_frame_host_->GetLastCommittedURL().GetOrigin(); |
| |
| 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(), origin, |
| nullptr, nullptr) && |
| EnableWebUsbOnAnyOrigin()) |
| allowed_guids.push_back(device->guid); |
| } |
| callback.Run(allowed_guids.Pass()); |
| } |
| |
| 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) { |
| bindings_.AddBinding(this, request.Pass()); |
| } |
| |
| void WebUSBPermissionProvider::OnConnectionError() { |
| if (bindings_.empty()) |
| delete this; |
| } |