// 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/usb/public/interfaces/device.mojom.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 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 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), weak_factory_(this) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK(render_frame_host_); } WebUSBPermissionProvider::~WebUSBPermissionProvider() {} base::WeakPtr WebUSBPermissionProvider::GetWeakPtr() { return weak_factory_.GetWeakPtr(); } bool WebUSBPermissionProvider::HasDevicePermission( const device::usb::DeviceInfo& device_info) const { 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); return FindOriginInDescriptorSet(device_info.webusb_allowed_origins.get(), requesting_origin, nullptr, nullptr) && chooser_context->HasDevicePermission(requesting_origin, embedding_origin, device_info); } bool WebUSBPermissionProvider::HasConfigurationPermission( uint8_t requested_configuration_value, const device::usb::DeviceInfo& device_info) const { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); return FindOriginInDescriptorSet( device_info.webusb_allowed_origins.get(), render_frame_host_->GetLastCommittedURL().GetOrigin(), &requested_configuration_value, nullptr); } bool WebUSBPermissionProvider::HasInterfacePermission( uint8_t requested_interface, uint8_t configuration_value, const device::usb::DeviceInfo& device_info) const { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); return FindOriginInDescriptorSet( device_info.webusb_allowed_origins.get(), render_frame_host_->GetLastCommittedURL().GetOrigin(), &configuration_value, &requested_interface); }