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/i18n/message_formatter.h"
9 #include "base/scoped_observer.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "device/core/device_client.h"
13 #include "device/hid/hid_device_filter.h"
14 #include "device/hid/hid_device_info.h"
15 #include "device/hid/hid_service.h"
16 #include "device/usb/usb_device.h"
17 #include "device/usb/usb_device_filter.h"
18 #include "device/usb/usb_ids.h"
19 #include "device/usb/usb_service.h"
20 #include "extensions/browser/api/device_permissions_manager.h"
21 #include "extensions/common/extension.h"
22 #include "extensions/strings/grit/extensions_strings.h"
23 #include "ui/base/l10n/l10n_util.h"
25 #if defined(OS_CHROMEOS)
26 #include "chromeos/dbus/dbus_thread_manager.h"
27 #include "chromeos/dbus/permission_broker_client.h"
28 #include "device/hid/hid_device_info_linux.h"
29 #endif // defined(OS_CHROMEOS)
31 using device::HidDeviceFilter
;
32 using device::HidService
;
33 using device::UsbDevice
;
34 using device::UsbDeviceFilter
;
35 using device::UsbService
;
37 namespace extensions
{
41 class UsbDeviceInfo
: public DevicePermissionsPrompt::Prompt::DeviceInfo
{
43 UsbDeviceInfo(scoped_refptr
<UsbDevice
> device
) : device_(device
) {
44 name_
= DevicePermissionsManager::GetPermissionMessage(
45 device
->vendor_id(), device
->product_id(),
46 device
->manufacturer_string(), device
->product_string(),
47 base::string16(), // Serial number is displayed separately.
49 serial_number_
= device
->serial_number();
52 ~UsbDeviceInfo() override
{}
54 const scoped_refptr
<UsbDevice
>& device() const { return device_
; }
57 // TODO(reillyg): Convert this to a weak reference when UsbDevice has a
59 scoped_refptr
<UsbDevice
> device_
;
62 class UsbDevicePermissionsPrompt
: public DevicePermissionsPrompt::Prompt
,
63 public device::UsbService::Observer
{
65 UsbDevicePermissionsPrompt(
66 const Extension
* extension
,
67 content::BrowserContext
* context
,
69 const std::vector
<UsbDeviceFilter
>& filters
,
70 const DevicePermissionsPrompt::UsbDevicesCallback
& callback
)
71 : Prompt(extension
, context
, multiple
),
74 service_observer_(this) {}
77 ~UsbDevicePermissionsPrompt() override
{}
79 // DevicePermissionsPrompt::Prompt implementation:
81 DevicePermissionsPrompt::Prompt::Observer
* observer
) override
{
82 DevicePermissionsPrompt::Prompt::SetObserver(observer
);
85 UsbService
* service
= device::DeviceClient::Get()->GetUsbService();
86 if (service
&& !service_observer_
.IsObserving(service
)) {
88 base::Bind(&UsbDevicePermissionsPrompt::OnDevicesEnumerated
, this));
89 service_observer_
.Add(service
);
94 base::string16
GetHeading() const override
{
95 return l10n_util::GetSingleOrMultipleStringUTF16(
96 IDS_USB_DEVICE_PERMISSIONS_PROMPT_TITLE
, multiple());
99 void Dismissed() override
{
100 DevicePermissionsManager
* permissions_manager
=
101 DevicePermissionsManager::Get(browser_context());
102 std::vector
<scoped_refptr
<UsbDevice
>> devices
;
103 for (const DeviceInfo
* device
: devices_
) {
104 if (device
->granted()) {
105 const UsbDeviceInfo
* usb_device
=
106 static_cast<const UsbDeviceInfo
*>(device
);
107 devices
.push_back(usb_device
->device());
108 if (permissions_manager
) {
109 permissions_manager
->AllowUsbDevice(extension()->id(),
110 usb_device
->device());
114 DCHECK(multiple() || devices
.size() <= 1);
115 callback_
.Run(devices
);
119 // device::UsbService::Observer implementation:
120 void OnDeviceAdded(scoped_refptr
<UsbDevice
> device
) override
{
121 if (!(filters_
.empty() || UsbDeviceFilter::MatchesAny(device
, filters_
))) {
125 scoped_ptr
<DeviceInfo
> device_info(new UsbDeviceInfo(device
));
126 device
->CheckUsbAccess(
127 base::Bind(&UsbDevicePermissionsPrompt::AddCheckedDevice
, this,
128 base::Passed(&device_info
)));
131 void OnDeviceRemoved(scoped_refptr
<UsbDevice
> device
) override
{
132 for (auto it
= devices_
.begin(); it
!= devices_
.end(); ++it
) {
133 const UsbDeviceInfo
* entry
= static_cast<const UsbDeviceInfo
*>(*it
);
134 if (entry
->device() == device
) {
137 observer()->OnDevicesChanged();
144 void OnDevicesEnumerated(
145 const std::vector
<scoped_refptr
<UsbDevice
>>& devices
) {
146 for (const auto& device
: devices
) {
147 OnDeviceAdded(device
);
151 std::vector
<UsbDeviceFilter
> filters_
;
152 DevicePermissionsPrompt::UsbDevicesCallback callback_
;
153 ScopedObserver
<UsbService
, UsbService::Observer
> service_observer_
;
156 class HidDeviceInfo
: public DevicePermissionsPrompt::Prompt::DeviceInfo
{
158 HidDeviceInfo(scoped_refptr
<device::HidDeviceInfo
> device
) : device_(device
) {
159 name_
= DevicePermissionsManager::GetPermissionMessage(
160 device
->vendor_id(), device
->product_id(),
161 base::string16(), // HID devices include manufacturer in product name.
162 base::UTF8ToUTF16(device
->product_name()),
163 base::string16(), // Serial number is displayed separately.
165 serial_number_
= base::UTF8ToUTF16(device
->serial_number());
168 ~HidDeviceInfo() override
{}
170 const scoped_refptr
<device::HidDeviceInfo
>& device() const { return device_
; }
173 scoped_refptr
<device::HidDeviceInfo
> device_
;
176 class HidDevicePermissionsPrompt
: public DevicePermissionsPrompt::Prompt
,
177 public device::HidService::Observer
{
179 HidDevicePermissionsPrompt(
180 const Extension
* extension
,
181 content::BrowserContext
* context
,
183 const std::vector
<HidDeviceFilter
>& filters
,
184 const DevicePermissionsPrompt::HidDevicesCallback
& callback
)
185 : Prompt(extension
, context
, multiple
),
188 service_observer_(this) {}
191 ~HidDevicePermissionsPrompt() override
{}
193 // DevicePermissionsPrompt::Prompt implementation:
195 DevicePermissionsPrompt::Prompt::Observer
* observer
) override
{
196 DevicePermissionsPrompt::Prompt::SetObserver(observer
);
199 HidService
* service
= device::DeviceClient::Get()->GetHidService();
200 if (service
&& !service_observer_
.IsObserving(service
)) {
202 base::Bind(&HidDevicePermissionsPrompt::OnDevicesEnumerated
, this));
203 service_observer_
.Add(service
);
208 base::string16
GetHeading() const override
{
209 return l10n_util::GetSingleOrMultipleStringUTF16(
210 IDS_HID_DEVICE_PERMISSIONS_PROMPT_TITLE
, multiple());
213 void Dismissed() override
{
214 DevicePermissionsManager
* permissions_manager
=
215 DevicePermissionsManager::Get(browser_context());
216 std::vector
<scoped_refptr
<device::HidDeviceInfo
>> devices
;
217 for (const DeviceInfo
* device
: devices_
) {
218 if (device
->granted()) {
219 const HidDeviceInfo
* hid_device
=
220 static_cast<const HidDeviceInfo
*>(device
);
221 devices
.push_back(hid_device
->device());
222 if (permissions_manager
) {
223 permissions_manager
->AllowHidDevice(extension()->id(),
224 hid_device
->device());
228 DCHECK(multiple() || devices
.size() <= 1);
229 callback_
.Run(devices
);
233 // device::HidService::Observer implementation:
234 void OnDeviceAdded(scoped_refptr
<device::HidDeviceInfo
> device
) override
{
235 if (HasUnprotectedCollections(device
) &&
236 (filters_
.empty() || HidDeviceFilter::MatchesAny(device
, filters_
))) {
237 scoped_ptr
<DeviceInfo
> device_info(new HidDeviceInfo(device
));
238 #if defined(OS_CHROMEOS)
239 chromeos::PermissionBrokerClient
* client
=
240 chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient();
241 DCHECK(client
) << "Could not get permission broker client.";
242 device::HidDeviceInfoLinux
* linux_device_info
=
243 static_cast<device::HidDeviceInfoLinux
*>(device
.get());
244 client
->CheckPathAccess(
245 linux_device_info
->device_node(),
246 base::Bind(&HidDevicePermissionsPrompt::AddCheckedDevice
, this,
247 base::Passed(&device_info
)));
249 AddCheckedDevice(device_info
.Pass(), true);
250 #endif // defined(OS_CHROMEOS)
254 void OnDeviceRemoved(scoped_refptr
<device::HidDeviceInfo
> device
) override
{
255 for (auto it
= devices_
.begin(); it
!= devices_
.end(); ++it
) {
256 const HidDeviceInfo
* entry
= static_cast<const HidDeviceInfo
*>(*it
);
257 if (entry
->device() == device
) {
260 observer()->OnDevicesChanged();
267 void OnDevicesEnumerated(
268 const std::vector
<scoped_refptr
<device::HidDeviceInfo
>>& devices
) {
269 for (const auto& device
: devices
) {
270 OnDeviceAdded(device
);
274 bool HasUnprotectedCollections(scoped_refptr
<device::HidDeviceInfo
> device
) {
275 for (const auto& collection
: device
->collections()) {
276 if (!collection
.usage
.IsProtected()) {
283 std::vector
<HidDeviceFilter
> filters_
;
284 DevicePermissionsPrompt::HidDevicesCallback callback_
;
285 ScopedObserver
<HidService
, HidService::Observer
> service_observer_
;
290 DevicePermissionsPrompt::Prompt::DeviceInfo::DeviceInfo() {
293 DevicePermissionsPrompt::Prompt::DeviceInfo::~DeviceInfo() {
296 DevicePermissionsPrompt::Prompt::Observer::~Observer() {
299 DevicePermissionsPrompt::Prompt::Prompt(const Extension
* extension
,
300 content::BrowserContext
* context
,
302 : extension_(extension
), browser_context_(context
), multiple_(multiple
) {
305 void DevicePermissionsPrompt::Prompt::SetObserver(Observer
* observer
) {
306 observer_
= observer
;
309 base::string16
DevicePermissionsPrompt::Prompt::GetPromptMessage() const {
310 return base::i18n::MessageFormatter::FormatWithNumberedArgs(
311 l10n_util::GetStringUTF16(IDS_DEVICE_PERMISSIONS_PROMPT
),
312 multiple_
? "multiple" : "single", extension_
->name());
315 base::string16
DevicePermissionsPrompt::Prompt::GetDeviceName(
316 size_t index
) const {
317 DCHECK_LT(index
, devices_
.size());
318 return devices_
[index
]->name();
321 base::string16
DevicePermissionsPrompt::Prompt::GetDeviceSerialNumber(
322 size_t index
) const {
323 DCHECK_LT(index
, devices_
.size());
324 return devices_
[index
]->serial_number();
327 void DevicePermissionsPrompt::Prompt::GrantDevicePermission(size_t index
) {
328 DCHECK_LT(index
, devices_
.size());
329 devices_
[index
]->set_granted();
332 DevicePermissionsPrompt::Prompt::~Prompt() {
335 void DevicePermissionsPrompt::Prompt::AddCheckedDevice(
336 scoped_ptr
<DeviceInfo
> device
,
339 devices_
.push_back(device
.Pass());
341 observer_
->OnDevicesChanged();
346 DevicePermissionsPrompt::DevicePermissionsPrompt(
347 content::WebContents
* web_contents
)
348 : web_contents_(web_contents
) {
351 DevicePermissionsPrompt::~DevicePermissionsPrompt() {
354 void DevicePermissionsPrompt::AskForUsbDevices(
355 const Extension
* extension
,
356 content::BrowserContext
* context
,
358 const std::vector
<UsbDeviceFilter
>& filters
,
359 const UsbDevicesCallback
& callback
) {
360 prompt_
= new UsbDevicePermissionsPrompt(extension
, context
, multiple
,
365 void DevicePermissionsPrompt::AskForHidDevices(
366 const Extension
* extension
,
367 content::BrowserContext
* context
,
369 const std::vector
<HidDeviceFilter
>& filters
,
370 const HidDevicesCallback
& callback
) {
371 prompt_
= new HidDevicePermissionsPrompt(extension
, context
, multiple
,
376 } // namespace extensions