Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(9)

Unified Diff: extensions/browser/api/device_permissions_manager.cc

Issue 606503002: Rewrite apps::SavedDevicesService as extensions::DevicePermissionsManager. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Use C++11 for each loops and auto. Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: extensions/browser/api/device_permissions_manager.cc
diff --git a/extensions/browser/api/device_permissions_manager.cc b/extensions/browser/api/device_permissions_manager.cc
new file mode 100644
index 0000000000000000000000000000000000000000..a005adbbc4b18c57d7c8dfa7217711242113b6d9
--- /dev/null
+++ b/extensions/browser/api/device_permissions_manager.cc
@@ -0,0 +1,384 @@
+// Copyright 2014 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 "extensions/browser/api/device_permissions_manager.h"
+
+#include "base/memory/singleton.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "content/public/browser/notification_service.h"
+#include "device/usb/usb_ids.h"
+#include "extensions/browser/extension_host.h"
+#include "extensions/browser/extension_prefs.h"
+#include "extensions/browser/notification_types.h"
+#include "extensions/strings/grit/extensions_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace extensions {
+
+using content::BrowserContext;
+using device::UsbDevice;
+using extensions::APIPermission;
+using extensions::Extension;
+using extensions::ExtensionHost;
+using extensions::ExtensionPrefs;
+
+namespace {
+
+// Preference keys
+
+// The device that the app has permission to access.
+const char kDevices[] = "devices";
+
+// The type of device saved.
+const char kDeviceType[] = "type";
+
+// Type identifier for USB devices.
+const char kDeviceTypeUsb[] = "usb";
+
+// The vendor ID of the device that the app had permission to access.
+const char kDeviceVendorId[] = "vendor_id";
+
+// The product ID of the device that the app had permission to access.
+const char kDeviceProductId[] = "product_id";
+
+// The serial number of the device that the app has permission to access.
+const char kDeviceSerialNumber[] = "serial_number";
+
+// Persists a DevicePermissionEntry in ExtensionPrefs.
+void SaveDevicePermissionEntry(BrowserContext* context,
+ const std::string& extension_id,
+ const DevicePermissionEntry& device) {
+ ExtensionPrefs* prefs = ExtensionPrefs::Get(context);
+ ExtensionPrefs::ScopedListUpdate update(prefs, extension_id, kDevices);
+ base::ListValue* devices = update.Get();
+ if (!devices) {
+ devices = update.Create();
+ }
+
+ base::Value* device_entry = device.ToValue();
+ DCHECK(devices->Find(*device_entry) == devices->end());
+ devices->Append(device_entry);
+}
+
+// Clears all DevicePermissionEntries for the app from ExtensionPrefs.
+void ClearDevicePermissionEntries(ExtensionPrefs* prefs,
+ const std::string& extension_id) {
+ prefs->UpdateExtensionPref(extension_id, kDevices, NULL);
+}
+
+// Returns all DevicePermissionEntries for the app.
+std::vector<DevicePermissionEntry> GetDevicePermissionEntries(
+ ExtensionPrefs* prefs,
+ const std::string& extension_id) {
+ std::vector<DevicePermissionEntry> result;
+ const base::ListValue* devices = NULL;
+ if (!prefs->ReadPrefAsList(extension_id, kDevices, &devices)) {
+ return result;
+ }
+
+ for (base::ListValue::const_iterator it = devices->begin();
+ it != devices->end();
+ ++it) {
+ const base::DictionaryValue* device_entry = NULL;
+ if (!(*it)->GetAsDictionary(&device_entry)) {
+ continue;
+ }
+ int vendor_id;
+ if (!device_entry->GetIntegerWithoutPathExpansion(kDeviceVendorId,
+ &vendor_id) ||
+ vendor_id < 0 || vendor_id > UINT16_MAX) {
+ continue;
+ }
+ int product_id;
+ if (!device_entry->GetIntegerWithoutPathExpansion(kDeviceProductId,
+ &product_id) ||
+ product_id < 0 || product_id > UINT16_MAX) {
+ continue;
+ }
+ base::string16 serial_number;
+ if (!device_entry->GetStringWithoutPathExpansion(kDeviceSerialNumber,
+ &serial_number)) {
+ continue;
+ }
+
+ result.push_back(
+ DevicePermissionEntry(vendor_id, product_id, serial_number));
+ }
+ return result;
+}
+}
+
+DevicePermissionEntry::DevicePermissionEntry(
+ uint16_t vendor_id,
+ uint16_t product_id,
+ const base::string16& serial_number)
+ : vendor_id(vendor_id),
+ product_id(product_id),
+ serial_number(serial_number) {
+}
+
+base::Value* DevicePermissionEntry::ToValue() const {
+ base::DictionaryValue* device_entry_dict = new base::DictionaryValue();
+ device_entry_dict->SetStringWithoutPathExpansion(kDeviceType, kDeviceTypeUsb);
+ device_entry_dict->SetIntegerWithoutPathExpansion(kDeviceVendorId, vendor_id);
+ device_entry_dict->SetIntegerWithoutPathExpansion(kDeviceProductId,
+ product_id);
+ device_entry_dict->SetStringWithoutPathExpansion(kDeviceSerialNumber,
+ serial_number);
+ return device_entry_dict;
+}
+
+DevicePermissions::~DevicePermissions() {
+}
+
+bool DevicePermissions::CheckUsbDevice(
+ scoped_refptr<device::UsbDevice> device) const {
+ if (ephemeral_devices_.find(device) != ephemeral_devices_.end()) {
+ return true;
+ }
+
+ bool have_serial_number = false;
+ base::string16 serial_number;
+ for (const auto& entry : permission_entries_) {
+ if (entry.vendor_id != device->vendor_id()) {
+ continue;
+ }
+ if (entry.product_id != device->product_id()) {
+ continue;
+ }
+ if (!have_serial_number) {
+ if (!device->GetSerialNumber(&serial_number)) {
+ break;
+ }
+ have_serial_number = true;
+ }
+ if (entry.serial_number != serial_number) {
+ continue;
+ }
+ return true;
+ }
+ return false;
+}
+
+DevicePermissions::DevicePermissions(BrowserContext* context,
+ const std::string& extension_id) {
+ ExtensionPrefs* prefs = ExtensionPrefs::Get(context);
+ permission_entries_ = GetDevicePermissionEntries(prefs, extension_id);
+}
+
+DevicePermissions::DevicePermissions(
+ const std::vector<DevicePermissionEntry>& permission_entries,
+ const std::set<scoped_refptr<device::UsbDevice>>& ephemeral_devices)
+ : permission_entries_(permission_entries),
+ ephemeral_devices_(ephemeral_devices) {
+}
+
+std::vector<DevicePermissionEntry>& DevicePermissions::permission_entries() {
+ return permission_entries_;
+}
+
+std::set<scoped_refptr<device::UsbDevice>>&
+DevicePermissions::ephemeral_devices() {
+ return ephemeral_devices_;
+}
+
+// static
+DevicePermissionsManager* DevicePermissionsManager::Get(
+ BrowserContext* context) {
+ return DevicePermissionsManagerFactory::GetForBrowserContext(context);
+}
+
+scoped_ptr<DevicePermissions> DevicePermissionsManager::GetForExtension(
+ const std::string& extension_id) {
+ DCHECK(CalledOnValidThread());
+
+ DevicePermissions* device_permissions = GetOrInsert(extension_id);
+ return make_scoped_ptr(
+ new DevicePermissions(device_permissions->permission_entries(),
+ device_permissions->ephemeral_devices()));
+}
+
+std::vector<base::string16>
+DevicePermissionsManager::GetPermissionMessageStrings(
+ const std::string& extension_id) {
+ DCHECK(CalledOnValidThread());
+
+ std::vector<base::string16> messages;
+ DevicePermissions* device_permissions = Get(extension_id);
+ if (!device_permissions) {
+ return messages;
+ }
+
+ for (const auto& entry : device_permissions->permission_entries()) {
+ const char* vendorName = device::UsbIds::GetVendorName(entry.vendor_id);
+ const char* productName =
+ device::UsbIds::GetProductName(entry.vendor_id, entry.product_id);
+ if (vendorName) {
+ if (productName) {
+ messages.push_back(l10n_util::GetStringFUTF16(
+ IDS_EXTENSION_PROMPT_WARNING_USB_DEVICE_SERIAL,
+ base::UTF8ToUTF16(vendorName),
+ base::UTF8ToUTF16(productName),
+ entry.serial_number));
+ } else {
+ messages.push_back(l10n_util::GetStringFUTF16(
+ IDS_EXTENSION_PROMPT_WARNING_USB_DEVICE_PID_SERIAL,
+ base::UTF8ToUTF16(vendorName),
+ base::ASCIIToUTF16(base::StringPrintf("0x%04X", entry.product_id)),
+ entry.serial_number));
+ }
+ } else {
+ messages.push_back(l10n_util::GetStringFUTF16(
+ IDS_EXTENSION_PROMPT_WARNING_USB_DEVICE_VID_PID_SERIAL,
+ base::ASCIIToUTF16(base::StringPrintf("0x%04X", entry.vendor_id)),
+ base::ASCIIToUTF16(base::StringPrintf("0x%04X", entry.product_id)),
+ entry.serial_number));
+ }
+ }
+ return messages;
+}
+
+void DevicePermissionsManager::AllowUsbDevice(
+ const std::string& extension_id,
+ scoped_refptr<device::UsbDevice> device,
+ const base::string16& serial_number) {
+ DCHECK(CalledOnValidThread());
+ DevicePermissions* device_permissions = GetOrInsert(extension_id);
+
+ if (!serial_number.empty()) {
+ for (const auto& entry : device_permissions->permission_entries()) {
+ if (entry.vendor_id != device->vendor_id()) {
+ continue;
+ }
+ if (entry.product_id != device->product_id()) {
+ continue;
+ }
+ if (entry.serial_number == serial_number) {
+ return;
+ }
+ }
+
+ DevicePermissionEntry device_entry = DevicePermissionEntry(
+ device->vendor_id(), device->product_id(), serial_number);
+ device_permissions->permission_entries().push_back(device_entry);
+ SaveDevicePermissionEntry(context_, extension_id, device_entry);
+ } else {
+ // Without a serial number a device cannot be reliably identified when it
+ // is reconnected so such devices are only remembered until disconnect.
+ // Register an observer here so that this set doesn't grow undefinitely.
+ device_permissions->ephemeral_devices().insert(device);
+ device->AddObserver(this);
+ }
+}
+
+void DevicePermissionsManager::Clear(const std::string& extension_id) {
+ DCHECK(CalledOnValidThread());
+
+ ClearDevicePermissionEntries(ExtensionPrefs::Get(context_), extension_id);
+ std::map<std::string, DevicePermissions*>::iterator it =
+ extension_id_to_device_permissions_.find(extension_id);
+ if (it != extension_id_to_device_permissions_.end()) {
+ delete it->second;
+ extension_id_to_device_permissions_.erase(it);
+ }
+}
+
+DevicePermissionsManager::DevicePermissionsManager(
+ content::BrowserContext* context)
+ : context_(context) {
+ registrar_.Add(this,
+ extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED,
+ content::NotificationService::AllSources());
+}
+
+DevicePermissionsManager::~DevicePermissionsManager() {
+ for (const auto& map_entry : extension_id_to_device_permissions_) {
+ delete map_entry.second;
+ }
+}
+
+DevicePermissions* DevicePermissionsManager::Get(
+ const std::string& extension_id) const {
+ std::map<std::string, DevicePermissions*>::const_iterator it =
+ extension_id_to_device_permissions_.find(extension_id);
+ if (it != extension_id_to_device_permissions_.end()) {
+ return it->second;
+ }
+
+ return NULL;
+}
+
+DevicePermissions* DevicePermissionsManager::GetOrInsert(
+ const std::string& extension_id) {
+ DevicePermissions* device_permissions = Get(extension_id);
+ if (!device_permissions) {
+ device_permissions = new DevicePermissions(context_, extension_id);
+ extension_id_to_device_permissions_[extension_id] = device_permissions;
+ }
+
+ return device_permissions;
+}
+
+void DevicePermissionsManager::Observe(
+ int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+ DCHECK(CalledOnValidThread());
+ DCHECK_EQ(extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED, type);
+
+ ExtensionHost* host = content::Details<ExtensionHost>(details).ptr();
+ DevicePermissions* device_permissions = Get(host->extension_id());
+ if (device_permissions) {
+ // When the extension is unloaded all ephemeral device permissions are
+ // cleared.
+ for (std::set<scoped_refptr<UsbDevice>>::iterator it =
+ device_permissions->ephemeral_devices().begin();
+ it != device_permissions->ephemeral_devices().end();
+ ++it) {
+ (*it)->RemoveObserver(this);
+ }
+ device_permissions->ephemeral_devices().clear();
+ }
+}
+
+void DevicePermissionsManager::OnDisconnect(scoped_refptr<UsbDevice> device) {
+ for (const auto& map_entry : extension_id_to_device_permissions_) {
+ // An ephemeral device cannot be identified if it is reconnected and so
+ // permission to access it is cleared on disconnect.
+ map_entry.second->ephemeral_devices().erase(device);
+ device->RemoveObserver(this);
+ }
+}
+
+// static
+DevicePermissionsManager* DevicePermissionsManagerFactory::GetForBrowserContext(
+ content::BrowserContext* context) {
+ return static_cast<DevicePermissionsManager*>(
+ GetInstance()->GetServiceForBrowserContext(context, true));
+}
+
+// static
+DevicePermissionsManagerFactory*
+DevicePermissionsManagerFactory::GetInstance() {
+ return Singleton<DevicePermissionsManagerFactory>::get();
+}
+
+DevicePermissionsManagerFactory::DevicePermissionsManagerFactory()
+ : BrowserContextKeyedServiceFactory(
+ "DevicePermissionsManager",
+ BrowserContextDependencyManager::GetInstance()) {
+}
+
+DevicePermissionsManagerFactory::~DevicePermissionsManagerFactory() {
+}
+
+KeyedService* DevicePermissionsManagerFactory::BuildServiceInstanceFor(
+ content::BrowserContext* context) const {
+ return new DevicePermissionsManager(context);
+}
+
+} // namespace extensions

Powered by Google App Engine
This is Rietveld 408576698