diff options
author | juncai <juncai@chromium.org> | 2015-12-10 18:37:39 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-12-11 02:38:30 +0000 |
commit | a7dd94484b64397611deaf2177f28dcb83a7903b (patch) | |
tree | d0e7d05da99fe815c5f823a19e544083883870ea /chrome/browser/usb | |
parent | d454228bc08c2f2f7c6b430a5c39b571a530936c (diff) | |
download | chromium_src-a7dd94484b64397611deaf2177f28dcb83a7903b.zip chromium_src-a7dd94484b64397611deaf2177f28dcb83a7903b.tar.gz chromium_src-a7dd94484b64397611deaf2177f28dcb83a7903b.tar.bz2 |
Add chrome side webusb permission UI code
This patch added chrome side webusb permission UI code.
It displays a device chooser permission dialog box asking
permission from user so that website can access
the device.
This patch is for Linux, Windows, and ChromeOS. There will
be another patch for Mac.
BUG=492204
Review URL: https://codereview.chromium.org/1408193003
Cr-Commit-Position: refs/heads/master@{#364593}
Diffstat (limited to 'chrome/browser/usb')
-rw-r--r-- | chrome/browser/usb/DEPS | 2 | ||||
-rw-r--r-- | chrome/browser/usb/usb_chooser_bubble_delegate.cc | 152 | ||||
-rw-r--r-- | chrome/browser/usb/usb_chooser_bubble_delegate.h | 65 | ||||
-rw-r--r-- | chrome/browser/usb/usb_tab_helper.cc | 52 | ||||
-rw-r--r-- | chrome/browser/usb/usb_tab_helper.h | 23 | ||||
-rw-r--r-- | chrome/browser/usb/web_usb_permission_bubble.cc | 45 | ||||
-rw-r--r-- | chrome/browser/usb/web_usb_permission_bubble.h | 48 |
7 files changed, 376 insertions, 11 deletions
diff --git a/chrome/browser/usb/DEPS b/chrome/browser/usb/DEPS index 4e689e7..1e0f248 100644 --- a/chrome/browser/usb/DEPS +++ b/chrome/browser/usb/DEPS @@ -1,4 +1,6 @@ include_rules = [ + "+chrome/browser/ui", + "+components/bubble", "+device/core", "+device/devices_app/usb/public", "+device/usb", diff --git a/chrome/browser/usb/usb_chooser_bubble_delegate.cc b/chrome/browser/usb/usb_chooser_bubble_delegate.cc new file mode 100644 index 0000000..6815fab --- /dev/null +++ b/chrome/browser/usb/usb_chooser_bubble_delegate.cc @@ -0,0 +1,152 @@ +// 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/usb_chooser_bubble_delegate.h" + +#include "base/bind.h" +#include "base/stl_util.h" +#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/render_frame_host.h" +#include "content/public/browser/web_contents.h" +#include "device/core/device_client.h" +#include "device/devices_app/usb/type_converters.h" +#include "device/usb/usb_device.h" +#include "device/usb/usb_device_filter.h" +#include "url/gurl.h" + +namespace { + +// Check if the origin is in the description set. +bool FindOriginInDescriptorSet(const device::WebUsbDescriptorSet* set, + const GURL& origin) { + if (!set) + return false; + + if (ContainsValue(set->origins, origin)) + return true; + + for (const auto& config : set->configurations) { + if (ContainsValue(config.origins, origin)) + return true; + + for (const auto& function : config.functions) { + if (ContainsValue(function.origins, origin)) + return true; + } + } + + return false; +} + +} // namespace + +UsbChooserBubbleDelegate::UsbChooserBubbleDelegate( + Browser* browser, + mojo::Array<device::usb::DeviceFilterPtr> device_filters, + content::RenderFrameHost* render_frame_host, + const webusb::WebUsbPermissionBubble::GetPermissionCallback& callback) + : ChooserBubbleDelegate(browser), + render_frame_host_(render_frame_host), + callback_(callback), + usb_service_observer_(this), + weak_factory_(this) { + device::UsbService* usb_service = + device::DeviceClient::Get()->GetUsbService(); + if (!usb_service) + return; + + if (!usb_service_observer_.IsObserving(usb_service)) + usb_service_observer_.Add(usb_service); + + if (!device_filters.is_null()) + filters_ = device_filters.To<std::vector<device::UsbDeviceFilter>>(); + + usb_service->GetDevices(base::Bind( + &UsbChooserBubbleDelegate::GotUsbDeviceList, weak_factory_.GetWeakPtr())); +} + +UsbChooserBubbleDelegate::~UsbChooserBubbleDelegate() { + if (!callback_.is_null()) + callback_.Run(nullptr); +} + +const std::vector<base::string16>& UsbChooserBubbleDelegate::GetOptions() + const { + return devices_names_; +} + +void UsbChooserBubbleDelegate::Select(int index) { + size_t idx = static_cast<size_t>(index); + size_t num_options = devices_.size(); + DCHECK_LT(idx, num_options); + if (idx < num_options) { + content::WebContents* web_contents = + content::WebContents::FromRenderFrameHost(render_frame_host_); + GURL embedding_origin = + web_contents->GetMainFrame()->GetLastCommittedURL().GetOrigin(); + Profile* profile = + Profile::FromBrowserContext(web_contents->GetBrowserContext()); + UsbChooserContext* chooser_context = + UsbChooserContextFactory::GetForProfile(profile); + chooser_context->GrantDevicePermission( + render_frame_host_->GetLastCommittedURL().GetOrigin(), embedding_origin, + devices_[idx]->guid()); + + device::usb::DeviceInfoPtr device_info_ptr = + device::usb::DeviceInfo::From(*devices_[idx]); + callback_.Run(device_info_ptr.Pass()); + } else { + callback_.Run(nullptr); + } + callback_.reset(); // Reset |callback_| so that it is only run once. +} + +void UsbChooserBubbleDelegate::Cancel() {} + +void UsbChooserBubbleDelegate::Close() {} + +void UsbChooserBubbleDelegate::OnDeviceAdded( + scoped_refptr<device::UsbDevice> device) { + DCHECK(!ContainsValue(devices_, device)); + if (device::UsbDeviceFilter::MatchesAny(device, filters_) && + FindOriginInDescriptorSet( + device->webusb_allowed_origins(), + render_frame_host_->GetLastCommittedURL().GetOrigin())) { + devices_.push_back(device); + devices_names_.push_back(device->product_string()); + if (observer()) + observer()->OnOptionAdded(static_cast<int>(devices_names_.size()) - 1); + } +} + +void UsbChooserBubbleDelegate::OnDeviceRemoved( + scoped_refptr<device::UsbDevice> device) { + auto iter = std::find(devices_.begin(), devices_.end(), device); + if (iter != devices_.end()) { + int index = iter - devices_.begin(); + devices_.erase(iter); + devices_names_.erase(devices_names_.begin() + index); + if (observer()) + observer()->OnOptionRemoved(index); + } +} + +// Get a list of devices that can be shown in the chooser bubble UI for +// user to grant permsssion. +void UsbChooserBubbleDelegate::GotUsbDeviceList( + const std::vector<scoped_refptr<device::UsbDevice>>& devices) { + for (const auto& device : devices) { + if (device::UsbDeviceFilter::MatchesAny(device, filters_) && + FindOriginInDescriptorSet( + device->webusb_allowed_origins(), + render_frame_host_->GetLastCommittedURL().GetOrigin())) { + devices_.push_back(device); + devices_names_.push_back(device->product_string()); + } + } + if (observer()) + observer()->OnOptionsInitialized(); +} diff --git a/chrome/browser/usb/usb_chooser_bubble_delegate.h b/chrome/browser/usb/usb_chooser_bubble_delegate.h new file mode 100644 index 0000000..9d06131 --- /dev/null +++ b/chrome/browser/usb/usb_chooser_bubble_delegate.h @@ -0,0 +1,65 @@ +// 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. + +#ifndef CHROME_BROWSER_USB_USB_CHOOSER_BUBBLE_DELEGATE_H_ +#define CHROME_BROWSER_USB_USB_CHOOSER_BUBBLE_DELEGATE_H_ + +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" +#include "base/scoped_observer.h" +#include "chrome/browser/ui/website_settings/chooser_bubble_delegate.h" +#include "components/webusb/public/interfaces/webusb_permission_bubble.mojom.h" +#include "device/usb/usb_service.h" +#include "mojo/public/cpp/bindings/array.h" + +namespace content { +class RenderFrameHost; +} + +namespace device { +class UsbDevice; +class UsbDeviceFilter; +} + +class Browser; + +// UsbChooserBubbleDelegate creates a chooser bubble for WebUsb. +class UsbChooserBubbleDelegate : public ChooserBubbleDelegate, + public device::UsbService::Observer { + public: + UsbChooserBubbleDelegate( + Browser* browser, + mojo::Array<device::usb::DeviceFilterPtr> device_filters, + content::RenderFrameHost* render_frame_host, + const webusb::WebUsbPermissionBubble::GetPermissionCallback& callback); + ~UsbChooserBubbleDelegate() override; + + // ChooserBubbleDelegate: + const std::vector<base::string16>& GetOptions() const override; + void Select(int index) override; + void Cancel() override; + void Close() override; + + // device::UsbService::Observer: + void OnDeviceAdded(scoped_refptr<device::UsbDevice> device) override; + void OnDeviceRemoved(scoped_refptr<device::UsbDevice> device) override; + + void GotUsbDeviceList( + const std::vector<scoped_refptr<device::UsbDevice>>& devices); + + private: + content::RenderFrameHost* const render_frame_host_; + webusb::WebUsbPermissionBubble::GetPermissionCallback callback_; + ScopedObserver<device::UsbService, device::UsbService::Observer> + usb_service_observer_; + std::vector<device::UsbDeviceFilter> filters_; + std::vector<scoped_refptr<device::UsbDevice>> devices_; + std::vector<base::string16> devices_names_; + base::WeakPtrFactory<UsbChooserBubbleDelegate> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(UsbChooserBubbleDelegate); +}; + +#endif // CHROME_BROWSER_USB_USB_CHOOSER_BUBBLE_DELEGATE_H_ diff --git a/chrome/browser/usb/usb_tab_helper.cc b/chrome/browser/usb/usb_tab_helper.cc index 29f875a..3eafaee 100644 --- a/chrome/browser/usb/usb_tab_helper.cc +++ b/chrome/browser/usb/usb_tab_helper.cc @@ -4,6 +4,10 @@ #include "chrome/browser/usb/usb_tab_helper.h" +#include <utility> + +#include "base/memory/scoped_ptr.h" +#include "chrome/browser/usb/web_usb_permission_bubble.h" #include "chrome/browser/usb/web_usb_permission_provider.h" #include "device/devices_app/usb/device_manager_impl.h" @@ -12,6 +16,11 @@ using content::WebContents; DEFINE_WEB_CONTENTS_USER_DATA_KEY(UsbTabHelper); +struct FrameUsbServices { + scoped_ptr<WebUSBPermissionProvider> permission_provider; + scoped_ptr<ChromeWebUsbPermissionBubble> permission_bubble; +}; + // static UsbTabHelper* UsbTabHelper::GetOrCreateForWebContents( WebContents* web_contents) { @@ -36,23 +45,50 @@ void UsbTabHelper::CreateDeviceManager( request.Pass()); } +void UsbTabHelper::CreatePermissionBubble( + content::RenderFrameHost* render_frame_host, + mojo::InterfaceRequest<webusb::WebUsbPermissionBubble> request) { + GetPermissionBubble(render_frame_host, request.Pass()); +} + UsbTabHelper::UsbTabHelper(WebContents* web_contents) : content::WebContentsObserver(web_contents) {} void UsbTabHelper::RenderFrameDeleted(RenderFrameHost* render_frame_host) { - permission_provider_.erase(render_frame_host); + frame_usb_services_.erase(render_frame_host); +} + +FrameUsbServices* UsbTabHelper::GetFrameUsbService( + content::RenderFrameHost* render_frame_host) { + FrameUsbServicesMap::const_iterator it = + frame_usb_services_.find(render_frame_host); + if (it == frame_usb_services_.end()) { + scoped_ptr<FrameUsbServices> frame_usb_services(new FrameUsbServices()); + it = (frame_usb_services_.insert( + std::make_pair(render_frame_host, frame_usb_services.Pass()))) + .first; + } + return it->second.get(); } void UsbTabHelper::GetPermissionProvider( RenderFrameHost* render_frame_host, mojo::InterfaceRequest<device::usb::PermissionProvider> request) { - const auto it = permission_provider_.find(render_frame_host); - if (it == permission_provider_.end()) { - scoped_ptr<WebUSBPermissionProvider> permission_provider( + FrameUsbServices* frame_usb_services = GetFrameUsbService(render_frame_host); + if (!frame_usb_services->permission_provider) { + frame_usb_services->permission_provider.reset( new WebUSBPermissionProvider(render_frame_host)); - permission_provider->Bind(request.Pass()); - permission_provider_[render_frame_host] = permission_provider.Pass(); - } else { - it->second->Bind(request.Pass()); } + frame_usb_services->permission_provider->Bind(request.Pass()); +} + +void UsbTabHelper::GetPermissionBubble( + content::RenderFrameHost* render_frame_host, + mojo::InterfaceRequest<webusb::WebUsbPermissionBubble> request) { + FrameUsbServices* frame_usb_services = GetFrameUsbService(render_frame_host); + if (!frame_usb_services->permission_bubble) { + frame_usb_services->permission_bubble.reset( + new ChromeWebUsbPermissionBubble(render_frame_host)); + } + frame_usb_services->permission_bubble->Bind(request.Pass()); } diff --git a/chrome/browser/usb/usb_tab_helper.h b/chrome/browser/usb/usb_tab_helper.h index 003f8dd..7d4cec5 100644 --- a/chrome/browser/usb/usb_tab_helper.h +++ b/chrome/browser/usb/usb_tab_helper.h @@ -19,7 +19,14 @@ class PermissionProvider; } } -class WebUSBPermissionProvider; +namespace webusb { +class WebUsbPermissionBubble; +} + +struct FrameUsbServices; + +typedef std::map<content::RenderFrameHost*, scoped_ptr<FrameUsbServices>> + FrameUsbServicesMap; // Per-tab owner of USB services provided to render frames within that tab. class UsbTabHelper : public content::WebContentsObserver, @@ -34,6 +41,10 @@ class UsbTabHelper : public content::WebContentsObserver, content::RenderFrameHost* render_frame_host, mojo::InterfaceRequest<device::usb::DeviceManager> request); + void CreatePermissionBubble( + content::RenderFrameHost* render_frame_host, + mojo::InterfaceRequest<webusb::WebUsbPermissionBubble> request); + private: explicit UsbTabHelper(content::WebContents* web_contents); friend class content::WebContentsUserData<UsbTabHelper>; @@ -41,12 +52,18 @@ class UsbTabHelper : public content::WebContentsObserver, // content::WebContentsObserver overrides: void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override; + FrameUsbServices* GetFrameUsbService( + content::RenderFrameHost* render_frame_host); + void GetPermissionProvider( content::RenderFrameHost* render_frame_host, mojo::InterfaceRequest<device::usb::PermissionProvider> request); - std::map<content::RenderFrameHost*, scoped_ptr<WebUSBPermissionProvider>> - permission_provider_; + void GetPermissionBubble( + content::RenderFrameHost* render_frame_host, + mojo::InterfaceRequest<webusb::WebUsbPermissionBubble> request); + + FrameUsbServicesMap frame_usb_services_; DISALLOW_COPY_AND_ASSIGN(UsbTabHelper); }; diff --git a/chrome/browser/usb/web_usb_permission_bubble.cc b/chrome/browser/usb/web_usb_permission_bubble.cc new file mode 100644 index 0000000..c7ca541 --- /dev/null +++ b/chrome/browser/usb/web_usb_permission_bubble.cc @@ -0,0 +1,45 @@ +// 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_bubble.h" + +#include "chrome/browser/ui/browser_finder.h" +#include "chrome/browser/ui/chrome_bubble_manager.h" +#include "chrome/browser/usb/usb_chooser_bubble_delegate.h" +#include "components/bubble/bubble_controller.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_frame_host.h" + +ChromeWebUsbPermissionBubble::ChromeWebUsbPermissionBubble( + content::RenderFrameHost* render_frame_host) + : render_frame_host_(render_frame_host) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DCHECK(render_frame_host); +} + +ChromeWebUsbPermissionBubble::~ChromeWebUsbPermissionBubble() { + for (const auto& bubble : bubbles_) { + if (bubble) + bubble->CloseBubble(BUBBLE_CLOSE_FORCED); + } +} + +void ChromeWebUsbPermissionBubble::GetPermission( + mojo::Array<device::usb::DeviceFilterPtr> device_filters, + const GetPermissionCallback& callback) { + content::WebContents* web_contents = + content::WebContents::FromRenderFrameHost(render_frame_host_); + Browser* browser = chrome::FindBrowserWithWebContents(web_contents); + scoped_ptr<BubbleDelegate> bubble_delegate(new UsbChooserBubbleDelegate( + browser, device_filters.Pass(), render_frame_host_, callback)); + BubbleReference bubble_reference = + browser->GetBubbleManager()->ShowBubble(bubble_delegate.Pass()); + bubbles_.push_back(bubble_reference); +} + +void ChromeWebUsbPermissionBubble::Bind( + mojo::InterfaceRequest<webusb::WebUsbPermissionBubble> request) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + bindings_.AddBinding(this, request.Pass()); +} diff --git a/chrome/browser/usb/web_usb_permission_bubble.h b/chrome/browser/usb/web_usb_permission_bubble.h new file mode 100644 index 0000000..18247541 --- /dev/null +++ b/chrome/browser/usb/web_usb_permission_bubble.h @@ -0,0 +1,48 @@ +// 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. + +#ifndef CHROME_BROWSER_USB_WEB_USB_PERMISSION_BUBBLE_H_ +#define CHROME_BROWSER_USB_WEB_USB_PERMISSION_BUBBLE_H_ + +#include <vector> + +#include "base/macros.h" +#include "components/bubble/bubble_reference.h" +#include "components/webusb/public/interfaces/webusb_permission_bubble.mojom.h" +#include "mojo/common/weak_binding_set.h" +#include "mojo/public/cpp/bindings/array.h" +#include "mojo/public/cpp/bindings/interface_request.h" + +namespace content { +class RenderFrameHost; +} + +namespace device { +class UsbDevice; +} + +// Implementation of the public webusb::WebUsbPermissionBubble interface. +// This interface can be used by a webpage to request permission from user +// to access a certain device. +class ChromeWebUsbPermissionBubble : public webusb::WebUsbPermissionBubble { + public: + explicit ChromeWebUsbPermissionBubble( + content::RenderFrameHost* render_frame_host); + + ~ChromeWebUsbPermissionBubble() override; + + // webusb::WebUsbPermissionBubble: + void GetPermission(mojo::Array<device::usb::DeviceFilterPtr> device_filters, + const GetPermissionCallback& callback) override; + void Bind(mojo::InterfaceRequest<webusb::WebUsbPermissionBubble> request); + + private: + content::RenderFrameHost* const render_frame_host_; + mojo::WeakBindingSet<webusb::WebUsbPermissionBubble> bindings_; + std::vector<BubbleReference> bubbles_; + + DISALLOW_COPY_AND_ASSIGN(ChromeWebUsbPermissionBubble); +}; + +#endif // CHROME_BROWSER_USB_WEB_USB_PERMISSION_BUBBLE_H_ |