1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "extensions/browser/api/device_permissions_prompt.h"
8 #include "base/scoped_observer.h"
9 #include "base/strings/stringprintf.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "device/core/device_client.h"
12 #include "device/hid/hid_device_filter.h"
13 #include "device/hid/hid_device_info.h"
14 #include "device/hid/hid_service.h"
15 #include "device/usb/usb_device.h"
16 #include "device/usb/usb_device_filter.h"
17 #include "device/usb/usb_ids.h"
18 #include "device/usb/usb_service.h"
19 #include "extensions/browser/api/device_permissions_manager.h"
20 #include "extensions/common/extension.h"
21 #include "extensions/strings/grit/extensions_strings.h"
22 #include "ui/base/l10n/l10n_util.h"
24 #if defined(OS_CHROMEOS)
25 #include "chromeos/dbus/dbus_thread_manager.h"
26 #include "chromeos/dbus/permission_broker_client.h"
27 #endif // defined(OS_CHROMEOS)
29 using device::HidDeviceFilter
;
30 using device::HidService
;
31 using device::UsbDevice
;
32 using device::UsbDeviceFilter
;
33 using device::UsbService
;
35 namespace extensions
{
39 class UsbDeviceInfo
: public DevicePermissionsPrompt::Prompt::DeviceInfo
{
41 UsbDeviceInfo(scoped_refptr
<UsbDevice
> device
) : device_(device
) {
42 name_
= DevicePermissionsManager::GetPermissionMessage(
43 device
->vendor_id(), device
->product_id(),
44 device
->manufacturer_string(), device
->product_string(),
45 base::string16(), // Serial number is displayed separately.
47 serial_number_
= device
->serial_number();
50 ~UsbDeviceInfo() override
{}
52 const scoped_refptr
<UsbDevice
>& device() const { return device_
; }
55 // TODO(reillyg): Convert this to a weak reference when UsbDevice has a
57 scoped_refptr
<UsbDevice
> device_
;
60 class UsbDevicePermissionsPrompt
: public DevicePermissionsPrompt::Prompt
,
61 public device::UsbService::Observer
{
63 UsbDevicePermissionsPrompt(
64 const Extension
* extension
,
65 content::BrowserContext
* context
,
67 const std::vector
<UsbDeviceFilter
>& filters
,
68 const DevicePermissionsPrompt::UsbDevicesCallback
& callback
)
69 : Prompt(extension
, context
, multiple
),
72 service_observer_(this) {}
75 ~UsbDevicePermissionsPrompt() override
{}
77 // DevicePermissionsPrompt::Prompt implementation:
79 DevicePermissionsPrompt::Prompt::Observer
* observer
) override
{
80 DevicePermissionsPrompt::Prompt::SetObserver(observer
);
83 UsbService
* service
= device::DeviceClient::Get()->GetUsbService();
84 if (service
&& !service_observer_
.IsObserving(service
)) {
86 base::Bind(&UsbDevicePermissionsPrompt::OnDevicesEnumerated
, this));
87 service_observer_
.Add(service
);
92 base::string16
GetHeading() const override
{
93 return l10n_util::GetPluralStringFUTF16(
94 IDS_HID_DEVICE_PERMISSIONS_PROMPT_TITLE
, devices_
.size());
97 void Dismissed() override
{
98 DevicePermissionsManager
* permissions_manager
=
99 DevicePermissionsManager::Get(browser_context());
100 std::vector
<scoped_refptr
<UsbDevice
>> devices
;
101 for (const DeviceInfo
* device
: devices_
) {
102 if (device
->granted()) {
103 const UsbDeviceInfo
* usb_device
=
104 static_cast<const UsbDeviceInfo
*>(device
);
105 devices
.push_back(usb_device
->device());
106 if (permissions_manager
) {
107 permissions_manager
->AllowUsbDevice(extension()->id(),
108 usb_device
->device());
112 DCHECK(multiple() || devices
.size() <= 1);
113 callback_
.Run(devices
);
117 // device::UsbService::Observer implementation:
118 void OnDeviceAdded(scoped_refptr
<UsbDevice
> device
) override
{
119 if (!(filters_
.empty() || UsbDeviceFilter::MatchesAny(device
, filters_
))) {
123 scoped_ptr
<DeviceInfo
> device_info(new UsbDeviceInfo(device
));
124 device
->CheckUsbAccess(
125 base::Bind(&UsbDevicePermissionsPrompt::AddCheckedDevice
, this,
126 base::Passed(&device_info
)));
129 void OnDeviceRemoved(scoped_refptr
<UsbDevice
> device
) override
{
130 for (auto it
= devices_
.begin(); it
!= devices_
.end(); ++it
) {
131 const UsbDeviceInfo
* entry
= static_cast<const UsbDeviceInfo
*>(*it
);
132 if (entry
->device() == device
) {
135 observer()->OnDevicesChanged();
142 void OnDevicesEnumerated(
143 const std::vector
<scoped_refptr
<UsbDevice
>>& devices
) {
144 for (const auto& device
: devices
) {
145 OnDeviceAdded(device
);
149 std::vector
<UsbDeviceFilter
> filters_
;
150 DevicePermissionsPrompt::UsbDevicesCallback callback_
;
151 ScopedObserver
<UsbService
, UsbService::Observer
> service_observer_
;
154 class HidDeviceInfo
: public DevicePermissionsPrompt::Prompt::DeviceInfo
{
156 HidDeviceInfo(scoped_refptr
<device::HidDeviceInfo
> device
) : device_(device
) {
157 name_
= DevicePermissionsManager::GetPermissionMessage(
158 device
->vendor_id(), device
->product_id(),
159 base::string16(), // HID devices include manufacturer in product name.
160 base::UTF8ToUTF16(device
->product_name()),
161 base::string16(), // Serial number is displayed separately.
163 serial_number_
= base::UTF8ToUTF16(device
->serial_number());
166 ~HidDeviceInfo() override
{}
168 const scoped_refptr
<device::HidDeviceInfo
>& device() const { return device_
; }
171 scoped_refptr
<device::HidDeviceInfo
> device_
;
174 class HidDevicePermissionsPrompt
: public DevicePermissionsPrompt::Prompt
,
175 public device::HidService::Observer
{
177 HidDevicePermissionsPrompt(
178 const Extension
* extension
,
179 content::BrowserContext
* context
,
181 const std::vector
<HidDeviceFilter
>& filters
,
182 const DevicePermissionsPrompt::HidDevicesCallback
& callback
)
183 : Prompt(extension
, context
, multiple
),
186 service_observer_(this) {}
189 ~HidDevicePermissionsPrompt() override
{}
191 // DevicePermissionsPrompt::Prompt implementation:
193 DevicePermissionsPrompt::Prompt::Observer
* observer
) override
{
194 DevicePermissionsPrompt::Prompt::SetObserver(observer
);
197 HidService
* service
= device::DeviceClient::Get()->GetHidService();
198 if (service
&& !service_observer_
.IsObserving(service
)) {
200 base::Bind(&HidDevicePermissionsPrompt::OnDevicesEnumerated
, this));
201 service_observer_
.Add(service
);
206 base::string16
GetHeading() const override
{
207 return l10n_util::GetPluralStringFUTF16(
208 IDS_USB_DEVICE_PERMISSIONS_PROMPT_TITLE
, devices_
.size());
211 void Dismissed() override
{
212 DevicePermissionsManager
* permissions_manager
=
213 DevicePermissionsManager::Get(browser_context());
214 std::vector
<scoped_refptr
<device::HidDeviceInfo
>> devices
;
215 for (const DeviceInfo
* device
: devices_
) {
216 if (device
->granted()) {
217 const HidDeviceInfo
* hid_device
=
218 static_cast<const HidDeviceInfo
*>(device
);
219 devices
.push_back(hid_device
->device());
220 if (permissions_manager
) {
221 permissions_manager
->AllowHidDevice(extension()->id(),
222 hid_device
->device());
226 DCHECK(multiple() || devices
.size() <= 1);
227 callback_
.Run(devices
);
231 // device::HidService::Observer implementation:
232 void OnDeviceAdded(scoped_refptr
<device::HidDeviceInfo
> device
) override
{
233 if (HasUnprotectedCollections(device
) &&
234 (filters_
.empty() || HidDeviceFilter::MatchesAny(device
, filters_
))) {
235 scoped_ptr
<DeviceInfo
> device_info(new HidDeviceInfo(device
));
236 #if defined(OS_CHROMEOS)
237 chromeos::PermissionBrokerClient
* client
=
238 chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient();
239 DCHECK(client
) << "Could not get permission broker client.";
240 client
->CheckPathAccess(
242 base::Bind(&HidDevicePermissionsPrompt::AddCheckedDevice
, this,
243 base::Passed(&device_info
)));
245 AddCheckedDevice(device_info
.Pass(), true);
246 #endif // defined(OS_CHROMEOS)
250 void OnDeviceRemoved(scoped_refptr
<device::HidDeviceInfo
> device
) override
{
251 for (auto it
= devices_
.begin(); it
!= devices_
.end(); ++it
) {
252 const HidDeviceInfo
* entry
= static_cast<const HidDeviceInfo
*>(*it
);
253 if (entry
->device() == device
) {
256 observer()->OnDevicesChanged();
263 void OnDevicesEnumerated(
264 const std::vector
<scoped_refptr
<device::HidDeviceInfo
>>& devices
) {
265 for (const auto& device
: devices
) {
266 OnDeviceAdded(device
);
270 bool HasUnprotectedCollections(scoped_refptr
<device::HidDeviceInfo
> device
) {
271 for (const auto& collection
: device
->collections()) {
272 if (!collection
.usage
.IsProtected()) {
279 std::vector
<HidDeviceFilter
> filters_
;
280 DevicePermissionsPrompt::HidDevicesCallback callback_
;
281 ScopedObserver
<HidService
, HidService::Observer
> service_observer_
;
286 DevicePermissionsPrompt::Prompt::DeviceInfo::DeviceInfo() {
289 DevicePermissionsPrompt::Prompt::DeviceInfo::~DeviceInfo() {
292 DevicePermissionsPrompt::Prompt::Observer::~Observer() {
295 DevicePermissionsPrompt::Prompt::Prompt(const Extension
* extension
,
296 content::BrowserContext
* context
,
298 : extension_(extension
), browser_context_(context
), multiple_(multiple
) {
301 void DevicePermissionsPrompt::Prompt::SetObserver(Observer
* observer
) {
302 observer_
= observer
;
305 base::string16
DevicePermissionsPrompt::Prompt::GetPromptMessage() const {
306 // TODO(jungshik): Consider using the ICU syntax once bug 481734 is fixed.
307 return l10n_util::GetStringFUTF16(multiple_
308 ? IDS_DEVICE_PERMISSIONS_PROMPT_MULTIPLE
309 : IDS_DEVICE_PERMISSIONS_PROMPT_SINGLE
,
310 base::UTF8ToUTF16(extension_
->name()));
313 base::string16
DevicePermissionsPrompt::Prompt::GetDeviceName(
314 size_t index
) const {
315 DCHECK_LT(index
, devices_
.size());
316 return devices_
[index
]->name();
319 base::string16
DevicePermissionsPrompt::Prompt::GetDeviceSerialNumber(
320 size_t index
) const {
321 DCHECK_LT(index
, devices_
.size());
322 return devices_
[index
]->serial_number();
325 void DevicePermissionsPrompt::Prompt::GrantDevicePermission(size_t index
) {
326 DCHECK_LT(index
, devices_
.size());
327 devices_
[index
]->set_granted();
330 DevicePermissionsPrompt::Prompt::~Prompt() {
333 void DevicePermissionsPrompt::Prompt::AddCheckedDevice(
334 scoped_ptr
<DeviceInfo
> device
,
337 devices_
.push_back(device
.release());
339 observer_
->OnDevicesChanged();
344 DevicePermissionsPrompt::DevicePermissionsPrompt(
345 content::WebContents
* web_contents
)
346 : web_contents_(web_contents
) {
349 DevicePermissionsPrompt::~DevicePermissionsPrompt() {
352 void DevicePermissionsPrompt::AskForUsbDevices(
353 const Extension
* extension
,
354 content::BrowserContext
* context
,
356 const std::vector
<UsbDeviceFilter
>& filters
,
357 const UsbDevicesCallback
& callback
) {
358 prompt_
= new UsbDevicePermissionsPrompt(extension
, context
, multiple
,
363 void DevicePermissionsPrompt::AskForHidDevices(
364 const Extension
* extension
,
365 content::BrowserContext
* context
,
367 const std::vector
<HidDeviceFilter
>& filters
,
368 const HidDevicesCallback
& callback
) {
369 prompt_
= new HidDevicePermissionsPrompt(extension
, context
, multiple
,
374 } // namespace extensions