Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / extensions / browser / api / device_permissions_prompt.cc
bloba72ebd3c69c539f51021936b082cba4fab16e730
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"
7 #include "base/bind.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 {
39 namespace {
41 void NoopHidCallback(const std::vector<scoped_refptr<device::HidDeviceInfo>>&) {
44 void NoopUsbCallback(const std::vector<scoped_refptr<device::UsbDevice>>&) {}
46 class UsbDeviceInfo : public DevicePermissionsPrompt::Prompt::DeviceInfo {
47 public:
48 UsbDeviceInfo(scoped_refptr<UsbDevice> device) : device_(device) {
49 name_ = DevicePermissionsManager::GetPermissionMessage(
50 device->vendor_id(), device->product_id(),
51 device->manufacturer_string(), device->product_string(),
52 base::string16(), // Serial number is displayed separately.
53 true);
54 serial_number_ = device->serial_number();
57 ~UsbDeviceInfo() override {}
59 const scoped_refptr<UsbDevice>& device() const { return device_; }
61 private:
62 // TODO(reillyg): Convert this to a weak reference when UsbDevice has a
63 // connected flag.
64 scoped_refptr<UsbDevice> device_;
67 class UsbDevicePermissionsPrompt : public DevicePermissionsPrompt::Prompt,
68 public device::UsbService::Observer {
69 public:
70 UsbDevicePermissionsPrompt(
71 const Extension* extension,
72 content::BrowserContext* context,
73 bool multiple,
74 const std::vector<UsbDeviceFilter>& filters,
75 const DevicePermissionsPrompt::UsbDevicesCallback& callback)
76 : Prompt(extension, context, multiple),
77 filters_(filters),
78 callback_(callback),
79 service_observer_(this) {}
81 private:
82 ~UsbDevicePermissionsPrompt() override {}
84 // DevicePermissionsPrompt::Prompt implementation:
85 void SetObserver(
86 DevicePermissionsPrompt::Prompt::Observer* observer) override {
87 DevicePermissionsPrompt::Prompt::SetObserver(observer);
89 if (observer) {
90 UsbService* service = device::DeviceClient::Get()->GetUsbService();
91 if (service && !service_observer_.IsObserving(service)) {
92 service->GetDevices(
93 base::Bind(&UsbDevicePermissionsPrompt::OnDevicesEnumerated, this));
94 service_observer_.Add(service);
99 base::string16 GetHeading() const override {
100 return l10n_util::GetSingleOrMultipleStringUTF16(
101 IDS_USB_DEVICE_PERMISSIONS_PROMPT_TITLE, multiple());
104 void Dismissed() override {
105 DevicePermissionsManager* permissions_manager =
106 DevicePermissionsManager::Get(browser_context());
107 std::vector<scoped_refptr<UsbDevice>> devices;
108 for (const DeviceInfo* device : devices_) {
109 if (device->granted()) {
110 const UsbDeviceInfo* usb_device =
111 static_cast<const UsbDeviceInfo*>(device);
112 devices.push_back(usb_device->device());
113 if (permissions_manager) {
114 permissions_manager->AllowUsbDevice(extension()->id(),
115 usb_device->device());
119 DCHECK(multiple() || devices.size() <= 1);
120 callback_.Run(devices);
121 callback_.Reset();
124 // device::UsbService::Observer implementation:
125 void OnDeviceAdded(scoped_refptr<UsbDevice> device) override {
126 if (!(filters_.empty() || UsbDeviceFilter::MatchesAny(device, filters_))) {
127 return;
130 scoped_ptr<DeviceInfo> device_info(new UsbDeviceInfo(device));
131 device->CheckUsbAccess(
132 base::Bind(&UsbDevicePermissionsPrompt::AddCheckedDevice, this,
133 base::Passed(&device_info)));
136 void OnDeviceRemoved(scoped_refptr<UsbDevice> device) override {
137 for (auto it = devices_.begin(); it != devices_.end(); ++it) {
138 const UsbDeviceInfo* entry = static_cast<const UsbDeviceInfo*>(*it);
139 if (entry->device() == device) {
140 devices_.erase(it);
141 if (observer()) {
142 observer()->OnDevicesChanged();
144 return;
149 void OnDevicesEnumerated(
150 const std::vector<scoped_refptr<UsbDevice>>& devices) {
151 for (const auto& device : devices) {
152 OnDeviceAdded(device);
156 std::vector<UsbDeviceFilter> filters_;
157 DevicePermissionsPrompt::UsbDevicesCallback callback_;
158 ScopedObserver<UsbService, UsbService::Observer> service_observer_;
161 class HidDeviceInfo : public DevicePermissionsPrompt::Prompt::DeviceInfo {
162 public:
163 HidDeviceInfo(scoped_refptr<device::HidDeviceInfo> device) : device_(device) {
164 name_ = DevicePermissionsManager::GetPermissionMessage(
165 device->vendor_id(), device->product_id(),
166 base::string16(), // HID devices include manufacturer in product name.
167 base::UTF8ToUTF16(device->product_name()),
168 base::string16(), // Serial number is displayed separately.
169 false);
170 serial_number_ = base::UTF8ToUTF16(device->serial_number());
173 ~HidDeviceInfo() override {}
175 const scoped_refptr<device::HidDeviceInfo>& device() const { return device_; }
177 private:
178 scoped_refptr<device::HidDeviceInfo> device_;
181 class HidDevicePermissionsPrompt : public DevicePermissionsPrompt::Prompt,
182 public device::HidService::Observer {
183 public:
184 HidDevicePermissionsPrompt(
185 const Extension* extension,
186 content::BrowserContext* context,
187 bool multiple,
188 const std::vector<HidDeviceFilter>& filters,
189 const DevicePermissionsPrompt::HidDevicesCallback& callback)
190 : Prompt(extension, context, multiple),
191 filters_(filters),
192 callback_(callback),
193 service_observer_(this) {}
195 private:
196 ~HidDevicePermissionsPrompt() override {}
198 // DevicePermissionsPrompt::Prompt implementation:
199 void SetObserver(
200 DevicePermissionsPrompt::Prompt::Observer* observer) override {
201 DevicePermissionsPrompt::Prompt::SetObserver(observer);
203 if (observer) {
204 HidService* service = device::DeviceClient::Get()->GetHidService();
205 if (service && !service_observer_.IsObserving(service)) {
206 service->GetDevices(
207 base::Bind(&HidDevicePermissionsPrompt::OnDevicesEnumerated, this));
208 service_observer_.Add(service);
213 base::string16 GetHeading() const override {
214 return l10n_util::GetSingleOrMultipleStringUTF16(
215 IDS_HID_DEVICE_PERMISSIONS_PROMPT_TITLE, multiple());
218 void Dismissed() override {
219 DevicePermissionsManager* permissions_manager =
220 DevicePermissionsManager::Get(browser_context());
221 std::vector<scoped_refptr<device::HidDeviceInfo>> devices;
222 for (const DeviceInfo* device : devices_) {
223 if (device->granted()) {
224 const HidDeviceInfo* hid_device =
225 static_cast<const HidDeviceInfo*>(device);
226 devices.push_back(hid_device->device());
227 if (permissions_manager) {
228 permissions_manager->AllowHidDevice(extension()->id(),
229 hid_device->device());
233 DCHECK(multiple() || devices.size() <= 1);
234 callback_.Run(devices);
235 callback_.Reset();
238 // device::HidService::Observer implementation:
239 void OnDeviceAdded(scoped_refptr<device::HidDeviceInfo> device) override {
240 if (HasUnprotectedCollections(device) &&
241 (filters_.empty() || HidDeviceFilter::MatchesAny(device, filters_))) {
242 scoped_ptr<DeviceInfo> device_info(new HidDeviceInfo(device));
243 #if defined(OS_CHROMEOS)
244 chromeos::PermissionBrokerClient* client =
245 chromeos::DBusThreadManager::Get()->GetPermissionBrokerClient();
246 DCHECK(client) << "Could not get permission broker client.";
247 device::HidDeviceInfoLinux* linux_device_info =
248 static_cast<device::HidDeviceInfoLinux*>(device.get());
249 client->CheckPathAccess(
250 linux_device_info->device_node(),
251 base::Bind(&HidDevicePermissionsPrompt::AddCheckedDevice, this,
252 base::Passed(&device_info)));
253 #else
254 AddCheckedDevice(device_info.Pass(), true);
255 #endif // defined(OS_CHROMEOS)
259 void OnDeviceRemoved(scoped_refptr<device::HidDeviceInfo> device) override {
260 for (auto it = devices_.begin(); it != devices_.end(); ++it) {
261 const HidDeviceInfo* entry = static_cast<const HidDeviceInfo*>(*it);
262 if (entry->device() == device) {
263 devices_.erase(it);
264 if (observer()) {
265 observer()->OnDevicesChanged();
267 return;
272 void OnDevicesEnumerated(
273 const std::vector<scoped_refptr<device::HidDeviceInfo>>& devices) {
274 for (const auto& device : devices) {
275 OnDeviceAdded(device);
279 bool HasUnprotectedCollections(scoped_refptr<device::HidDeviceInfo> device) {
280 for (const auto& collection : device->collections()) {
281 if (!collection.usage.IsProtected()) {
282 return true;
285 return false;
288 std::vector<HidDeviceFilter> filters_;
289 DevicePermissionsPrompt::HidDevicesCallback callback_;
290 ScopedObserver<HidService, HidService::Observer> service_observer_;
293 } // namespace
295 DevicePermissionsPrompt::Prompt::DeviceInfo::DeviceInfo() {
298 DevicePermissionsPrompt::Prompt::DeviceInfo::~DeviceInfo() {
301 DevicePermissionsPrompt::Prompt::Observer::~Observer() {
304 DevicePermissionsPrompt::Prompt::Prompt(const Extension* extension,
305 content::BrowserContext* context,
306 bool multiple)
307 : extension_(extension), browser_context_(context), multiple_(multiple) {
310 void DevicePermissionsPrompt::Prompt::SetObserver(Observer* observer) {
311 observer_ = observer;
314 base::string16 DevicePermissionsPrompt::Prompt::GetPromptMessage() const {
315 return base::i18n::MessageFormatter::FormatWithNumberedArgs(
316 l10n_util::GetStringUTF16(IDS_DEVICE_PERMISSIONS_PROMPT),
317 multiple_ ? "multiple" : "single", extension_->name());
320 base::string16 DevicePermissionsPrompt::Prompt::GetDeviceName(
321 size_t index) const {
322 DCHECK_LT(index, devices_.size());
323 return devices_[index]->name();
326 base::string16 DevicePermissionsPrompt::Prompt::GetDeviceSerialNumber(
327 size_t index) const {
328 DCHECK_LT(index, devices_.size());
329 return devices_[index]->serial_number();
332 void DevicePermissionsPrompt::Prompt::GrantDevicePermission(size_t index) {
333 DCHECK_LT(index, devices_.size());
334 devices_[index]->set_granted();
337 DevicePermissionsPrompt::Prompt::~Prompt() {
340 void DevicePermissionsPrompt::Prompt::AddCheckedDevice(
341 scoped_ptr<DeviceInfo> device,
342 bool allowed) {
343 if (allowed) {
344 devices_.push_back(device.Pass());
345 if (observer_) {
346 observer_->OnDevicesChanged();
351 DevicePermissionsPrompt::DevicePermissionsPrompt(
352 content::WebContents* web_contents)
353 : web_contents_(web_contents) {
356 DevicePermissionsPrompt::~DevicePermissionsPrompt() {
359 void DevicePermissionsPrompt::AskForUsbDevices(
360 const Extension* extension,
361 content::BrowserContext* context,
362 bool multiple,
363 const std::vector<UsbDeviceFilter>& filters,
364 const UsbDevicesCallback& callback) {
365 prompt_ = new UsbDevicePermissionsPrompt(extension, context, multiple,
366 filters, callback);
367 ShowDialog();
370 void DevicePermissionsPrompt::AskForHidDevices(
371 const Extension* extension,
372 content::BrowserContext* context,
373 bool multiple,
374 const std::vector<HidDeviceFilter>& filters,
375 const HidDevicesCallback& callback) {
376 prompt_ = new HidDevicePermissionsPrompt(extension, context, multiple,
377 filters, callback);
378 ShowDialog();
381 // static
382 scoped_refptr<DevicePermissionsPrompt::Prompt>
383 DevicePermissionsPrompt::CreateHidPromptForTest(const Extension* extension,
384 bool multiple) {
385 return make_scoped_refptr(new HidDevicePermissionsPrompt(
386 extension, nullptr, multiple, std::vector<HidDeviceFilter>(),
387 base::Bind(&NoopHidCallback)));
390 // static
391 scoped_refptr<DevicePermissionsPrompt::Prompt>
392 DevicePermissionsPrompt::CreateUsbPromptForTest(const Extension* extension,
393 bool multiple) {
394 return make_scoped_refptr(new UsbDevicePermissionsPrompt(
395 extension, nullptr, multiple, std::vector<UsbDeviceFilter>(),
396 base::Bind(&NoopUsbCallback)));
399 } // namespace extensions