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

Side by Side 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: Added comments. Created 6 years, 2 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 unified diff | Download patch
« no previous file with comments | « extensions/browser/api/device_permissions_manager.h ('k') | extensions/browser/api/usb/DEPS » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.
4
5 #include "extensions/browser/api/device_permissions_manager.h"
6
7 #include "base/memory/singleton.h"
8 #include "base/strings/stringprintf.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "base/values.h"
11 #include "components/keyed_service/content/browser_context_dependency_manager.h"
12 #include "content/public/browser/notification_service.h"
13 #include "device/usb/usb_ids.h"
14 #include "extensions/browser/extension_host.h"
15 #include "extensions/browser/extension_prefs.h"
16 #include "extensions/browser/notification_types.h"
17 #include "extensions/strings/grit/extensions_strings.h"
18 #include "ui/base/l10n/l10n_util.h"
19
20 namespace extensions {
21
22 using content::BrowserContext;
23 using device::UsbDevice;
24 using extensions::APIPermission;
25 using extensions::Extension;
26 using extensions::ExtensionHost;
27 using extensions::ExtensionPrefs;
28
29 namespace {
30
31 // Preference keys
32
33 // The device that the app has permission to access.
34 const char kDevices[] = "devices";
35
36 // The type of device saved.
37 const char kDeviceType[] = "type";
38
39 // Type identifier for USB devices.
40 const char kDeviceTypeUsb[] = "usb";
41
42 // The vendor ID of the device that the app had permission to access.
43 const char kDeviceVendorId[] = "vendor_id";
44
45 // The product ID of the device that the app had permission to access.
46 const char kDeviceProductId[] = "product_id";
47
48 // The serial number of the device that the app has permission to access.
49 const char kDeviceSerialNumber[] = "serial_number";
50
51 // Persists a DevicePermissionEntry in ExtensionPrefs.
52 void SaveDevicePermissionEntry(BrowserContext* context,
53 const std::string& extension_id,
54 const DevicePermissionEntry& device) {
55 ExtensionPrefs* prefs = ExtensionPrefs::Get(context);
56 ExtensionPrefs::ScopedListUpdate update(prefs, extension_id, kDevices);
57 base::ListValue* devices = update.Get();
58 if (!devices) {
59 devices = update.Create();
60 }
61
62 base::Value* device_entry = device.ToValue();
63 DCHECK(devices->Find(*device_entry) == devices->end());
64 devices->Append(device_entry);
65 }
66
67 // Clears all DevicePermissionEntries for the app from ExtensionPrefs.
68 void ClearDevicePermissionEntries(ExtensionPrefs* prefs,
69 const std::string& extension_id) {
70 prefs->UpdateExtensionPref(extension_id, kDevices, NULL);
71 }
72
73 // Returns all DevicePermissionEntries for the app.
74 std::vector<DevicePermissionEntry> GetDevicePermissionEntries(
75 ExtensionPrefs* prefs,
76 const std::string& extension_id) {
77 std::vector<DevicePermissionEntry> result;
78 const base::ListValue* devices = NULL;
79 if (!prefs->ReadPrefAsList(extension_id, kDevices, &devices)) {
80 return result;
81 }
82
83 for (base::ListValue::const_iterator it = devices->begin();
84 it != devices->end();
85 ++it) {
86 const base::DictionaryValue* device_entry = NULL;
87 if (!(*it)->GetAsDictionary(&device_entry)) {
88 continue;
89 }
90 int vendor_id;
91 if (!device_entry->GetIntegerWithoutPathExpansion(kDeviceVendorId,
92 &vendor_id) ||
93 vendor_id < 0 || vendor_id > UINT16_MAX) {
94 continue;
95 }
96 int product_id;
97 if (!device_entry->GetIntegerWithoutPathExpansion(kDeviceProductId,
98 &product_id) ||
99 product_id < 0 || product_id > UINT16_MAX) {
100 continue;
101 }
102 base::string16 serial_number;
103 if (!device_entry->GetStringWithoutPathExpansion(kDeviceSerialNumber,
104 &serial_number)) {
105 continue;
106 }
107
108 result.push_back(
109 DevicePermissionEntry(vendor_id, product_id, serial_number));
110 }
111 return result;
112 }
113 }
114
115 DevicePermissionEntry::DevicePermissionEntry(
116 uint16_t vendor_id,
117 uint16_t product_id,
118 const base::string16& serial_number)
119 : vendor_id(vendor_id),
120 product_id(product_id),
121 serial_number(serial_number) {
122 }
123
124 base::Value* DevicePermissionEntry::ToValue() const {
125 base::DictionaryValue* device_entry_dict = new base::DictionaryValue();
126 device_entry_dict->SetStringWithoutPathExpansion(kDeviceType, kDeviceTypeUsb);
127 device_entry_dict->SetIntegerWithoutPathExpansion(kDeviceVendorId, vendor_id);
128 device_entry_dict->SetIntegerWithoutPathExpansion(kDeviceProductId,
129 product_id);
130 device_entry_dict->SetStringWithoutPathExpansion(kDeviceSerialNumber,
131 serial_number);
132 return device_entry_dict;
133 }
134
135 DevicePermissions::~DevicePermissions() {
136 }
137
138 bool DevicePermissions::CheckUsbDevice(
139 scoped_refptr<device::UsbDevice> device) const {
140 if (ephemeral_devices_.find(device) != ephemeral_devices_.end()) {
141 return true;
142 }
143
144 bool have_serial_number = false;
145 base::string16 serial_number;
146 for (const auto& entry : permission_entries_) {
147 if (entry.vendor_id != device->vendor_id()) {
148 continue;
149 }
150 if (entry.product_id != device->product_id()) {
151 continue;
152 }
153 if (!have_serial_number) {
154 if (!device->GetSerialNumber(&serial_number)) {
155 break;
156 }
157 have_serial_number = true;
158 }
159 if (entry.serial_number != serial_number) {
160 continue;
161 }
162 return true;
163 }
164 return false;
165 }
166
167 DevicePermissions::DevicePermissions(BrowserContext* context,
168 const std::string& extension_id) {
169 ExtensionPrefs* prefs = ExtensionPrefs::Get(context);
170 permission_entries_ = GetDevicePermissionEntries(prefs, extension_id);
171 }
172
173 DevicePermissions::DevicePermissions(
174 const std::vector<DevicePermissionEntry>& permission_entries,
175 const std::set<scoped_refptr<device::UsbDevice>>& ephemeral_devices)
176 : permission_entries_(permission_entries),
177 ephemeral_devices_(ephemeral_devices) {
178 }
179
180 std::vector<DevicePermissionEntry>& DevicePermissions::permission_entries() {
181 return permission_entries_;
182 }
183
184 std::set<scoped_refptr<device::UsbDevice>>&
185 DevicePermissions::ephemeral_devices() {
186 return ephemeral_devices_;
187 }
188
189 // static
190 DevicePermissionsManager* DevicePermissionsManager::Get(
191 BrowserContext* context) {
192 return DevicePermissionsManagerFactory::GetForBrowserContext(context);
193 }
194
195 scoped_ptr<DevicePermissions> DevicePermissionsManager::GetForExtension(
196 const std::string& extension_id) {
197 DCHECK(CalledOnValidThread());
198
199 DevicePermissions* device_permissions = GetOrInsert(extension_id);
200 return make_scoped_ptr(
201 new DevicePermissions(device_permissions->permission_entries(),
202 device_permissions->ephemeral_devices()));
203 }
204
205 std::vector<base::string16>
206 DevicePermissionsManager::GetPermissionMessageStrings(
207 const std::string& extension_id) {
208 DCHECK(CalledOnValidThread());
209
210 std::vector<base::string16> messages;
211 DevicePermissions* device_permissions = Get(extension_id);
212 if (!device_permissions) {
213 return messages;
214 }
215
216 for (const auto& entry : device_permissions->permission_entries()) {
217 const char* vendorName = device::UsbIds::GetVendorName(entry.vendor_id);
218 const char* productName =
219 device::UsbIds::GetProductName(entry.vendor_id, entry.product_id);
220 if (vendorName) {
221 if (productName) {
222 messages.push_back(l10n_util::GetStringFUTF16(
223 IDS_EXTENSION_PROMPT_WARNING_USB_DEVICE_SERIAL,
224 base::UTF8ToUTF16(vendorName),
225 base::UTF8ToUTF16(productName),
226 entry.serial_number));
227 } else {
228 messages.push_back(l10n_util::GetStringFUTF16(
229 IDS_EXTENSION_PROMPT_WARNING_USB_DEVICE_PID_SERIAL,
230 base::UTF8ToUTF16(vendorName),
231 base::ASCIIToUTF16(base::StringPrintf("0x%04X", entry.product_id)),
232 entry.serial_number));
233 }
234 } else {
235 messages.push_back(l10n_util::GetStringFUTF16(
236 IDS_EXTENSION_PROMPT_WARNING_USB_DEVICE_VID_PID_SERIAL,
237 base::ASCIIToUTF16(base::StringPrintf("0x%04X", entry.vendor_id)),
238 base::ASCIIToUTF16(base::StringPrintf("0x%04X", entry.product_id)),
239 entry.serial_number));
240 }
241 }
242 return messages;
243 }
244
245 void DevicePermissionsManager::AllowUsbDevice(
246 const std::string& extension_id,
247 scoped_refptr<device::UsbDevice> device,
248 const base::string16& serial_number) {
249 DCHECK(CalledOnValidThread());
250 DevicePermissions* device_permissions = GetOrInsert(extension_id);
251
252 if (!serial_number.empty()) {
253 for (const auto& entry : device_permissions->permission_entries()) {
254 if (entry.vendor_id != device->vendor_id()) {
255 continue;
256 }
257 if (entry.product_id != device->product_id()) {
258 continue;
259 }
260 if (entry.serial_number == serial_number) {
261 return;
262 }
263 }
264
265 DevicePermissionEntry device_entry = DevicePermissionEntry(
266 device->vendor_id(), device->product_id(), serial_number);
267 device_permissions->permission_entries().push_back(device_entry);
268 SaveDevicePermissionEntry(context_, extension_id, device_entry);
269 } else {
270 // Without a serial number a device cannot be reliably identified when it
271 // is reconnected so such devices are only remembered until disconnect.
272 // Register an observer here so that this set doesn't grow undefinitely.
273 device_permissions->ephemeral_devices().insert(device);
274 device->AddObserver(this);
275 }
276 }
277
278 void DevicePermissionsManager::Clear(const std::string& extension_id) {
279 DCHECK(CalledOnValidThread());
280
281 ClearDevicePermissionEntries(ExtensionPrefs::Get(context_), extension_id);
282 std::map<std::string, DevicePermissions*>::iterator it =
283 extension_id_to_device_permissions_.find(extension_id);
284 if (it != extension_id_to_device_permissions_.end()) {
285 delete it->second;
286 extension_id_to_device_permissions_.erase(it);
287 }
288 }
289
290 DevicePermissionsManager::DevicePermissionsManager(
291 content::BrowserContext* context)
292 : context_(context) {
293 registrar_.Add(this,
294 extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED,
295 content::NotificationService::AllSources());
296 }
297
298 DevicePermissionsManager::~DevicePermissionsManager() {
299 for (const auto& map_entry : extension_id_to_device_permissions_) {
300 delete map_entry.second;
301 }
302 }
303
304 DevicePermissions* DevicePermissionsManager::Get(
305 const std::string& extension_id) const {
306 std::map<std::string, DevicePermissions*>::const_iterator it =
307 extension_id_to_device_permissions_.find(extension_id);
308 if (it != extension_id_to_device_permissions_.end()) {
309 return it->second;
310 }
311
312 return NULL;
313 }
314
315 DevicePermissions* DevicePermissionsManager::GetOrInsert(
316 const std::string& extension_id) {
317 DevicePermissions* device_permissions = Get(extension_id);
318 if (!device_permissions) {
319 device_permissions = new DevicePermissions(context_, extension_id);
320 extension_id_to_device_permissions_[extension_id] = device_permissions;
321 }
322
323 return device_permissions;
324 }
325
326 void DevicePermissionsManager::Observe(
327 int type,
328 const content::NotificationSource& source,
329 const content::NotificationDetails& details) {
330 DCHECK(CalledOnValidThread());
331 DCHECK_EQ(extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED, type);
332
333 ExtensionHost* host = content::Details<ExtensionHost>(details).ptr();
334 DevicePermissions* device_permissions = Get(host->extension_id());
335 if (device_permissions) {
336 // When the extension is unloaded all ephemeral device permissions are
337 // cleared.
338 for (std::set<scoped_refptr<UsbDevice>>::iterator it =
339 device_permissions->ephemeral_devices().begin();
340 it != device_permissions->ephemeral_devices().end();
341 ++it) {
342 (*it)->RemoveObserver(this);
343 }
344 device_permissions->ephemeral_devices().clear();
345 }
346 }
347
348 void DevicePermissionsManager::OnDisconnect(scoped_refptr<UsbDevice> device) {
349 for (const auto& map_entry : extension_id_to_device_permissions_) {
350 // An ephemeral device cannot be identified if it is reconnected and so
351 // permission to access it is cleared on disconnect.
352 map_entry.second->ephemeral_devices().erase(device);
353 device->RemoveObserver(this);
354 }
355 }
356
357 // static
358 DevicePermissionsManager* DevicePermissionsManagerFactory::GetForBrowserContext(
359 content::BrowserContext* context) {
360 return static_cast<DevicePermissionsManager*>(
361 GetInstance()->GetServiceForBrowserContext(context, true));
362 }
363
364 // static
365 DevicePermissionsManagerFactory*
366 DevicePermissionsManagerFactory::GetInstance() {
367 return Singleton<DevicePermissionsManagerFactory>::get();
368 }
369
370 DevicePermissionsManagerFactory::DevicePermissionsManagerFactory()
371 : BrowserContextKeyedServiceFactory(
372 "DevicePermissionsManager",
373 BrowserContextDependencyManager::GetInstance()) {
374 }
375
376 DevicePermissionsManagerFactory::~DevicePermissionsManagerFactory() {
377 }
378
379 KeyedService* DevicePermissionsManagerFactory::BuildServiceInstanceFor(
380 content::BrowserContext* context) const {
381 return new DevicePermissionsManager(context);
382 }
383
384 } // namespace extensions
OLDNEW
« no previous file with comments | « extensions/browser/api/device_permissions_manager.h ('k') | extensions/browser/api/usb/DEPS » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698