| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "extensions/browser/api/device_permissions_manager.h" | 5 #include "extensions/browser/api/device_permissions_manager.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/memory/singleton.h" | 8 #include "base/memory/singleton.h" |
| 9 #include "base/strings/string_number_conversions.h" | 9 #include "base/strings/string_number_conversions.h" |
| 10 #include "base/strings/stringprintf.h" | 10 #include "base/strings/stringprintf.h" |
| (...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 226 result.insert(new DevicePermissionEntry(vendor_id, product_id, | 226 result.insert(new DevicePermissionEntry(vendor_id, product_id, |
| 227 serial_number, manufacturer_string, | 227 serial_number, manufacturer_string, |
| 228 product_string, last_used)); | 228 product_string, last_used)); |
| 229 } | 229 } |
| 230 return result; | 230 return result; |
| 231 } | 231 } |
| 232 | 232 |
| 233 } // namespace | 233 } // namespace |
| 234 | 234 |
| 235 DevicePermissionEntry::DevicePermissionEntry( | 235 DevicePermissionEntry::DevicePermissionEntry( |
| 236 scoped_refptr<device::UsbDevice> device, | 236 scoped_refptr<device::UsbDevice> device) |
| 237 const base::string16& serial_number, | |
| 238 const base::string16& manufacturer_string, | |
| 239 const base::string16& product_string) | |
| 240 : device_(device), | 237 : device_(device), |
| 241 vendor_id_(device->vendor_id()), | 238 vendor_id_(device->vendor_id()), |
| 242 product_id_(device->product_id()), | 239 product_id_(device->product_id()), |
| 243 serial_number_(serial_number), | 240 serial_number_(device->serial_number()), |
| 244 manufacturer_string_(manufacturer_string), | 241 manufacturer_string_(device->manufacturer_string()), |
| 245 product_string_(product_string) { | 242 product_string_(device->product_string()) { |
| 246 } | 243 } |
| 247 | 244 |
| 248 DevicePermissionEntry::DevicePermissionEntry( | 245 DevicePermissionEntry::DevicePermissionEntry( |
| 249 uint16_t vendor_id, | 246 uint16_t vendor_id, |
| 250 uint16_t product_id, | 247 uint16_t product_id, |
| 251 const base::string16& serial_number, | 248 const base::string16& serial_number, |
| 252 const base::string16& manufacturer_string, | 249 const base::string16& manufacturer_string, |
| 253 const base::string16& product_string, | 250 const base::string16& product_string, |
| 254 const base::Time& last_used) | 251 const base::Time& last_used) |
| 255 : vendor_id_(vendor_id), | 252 : vendor_id_(vendor_id), |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 334 } | 331 } |
| 335 } else { | 332 } else { |
| 336 return product_string_; | 333 return product_string_; |
| 337 } | 334 } |
| 338 } | 335 } |
| 339 | 336 |
| 340 DevicePermissions::~DevicePermissions() { | 337 DevicePermissions::~DevicePermissions() { |
| 341 } | 338 } |
| 342 | 339 |
| 343 scoped_refptr<DevicePermissionEntry> DevicePermissions::FindEntry( | 340 scoped_refptr<DevicePermissionEntry> DevicePermissions::FindEntry( |
| 344 scoped_refptr<device::UsbDevice> device, | 341 scoped_refptr<device::UsbDevice> device) const { |
| 345 const base::string16& serial_number) const { | |
| 346 const auto& ephemeral_device_entry = ephemeral_devices_.find(device); | 342 const auto& ephemeral_device_entry = ephemeral_devices_.find(device); |
| 347 if (ephemeral_device_entry != ephemeral_devices_.end()) { | 343 if (ephemeral_device_entry != ephemeral_devices_.end()) { |
| 348 return ephemeral_device_entry->second; | 344 return ephemeral_device_entry->second; |
| 349 } | 345 } |
| 350 | 346 |
| 351 if (serial_number.empty()) { | 347 if (device->serial_number().empty()) { |
| 352 return nullptr; | 348 return nullptr; |
| 353 } | 349 } |
| 354 | 350 |
| 355 for (const auto& entry : entries_) { | 351 for (const auto& entry : entries_) { |
| 356 if (!entry->IsPersistent()) { | 352 if (!entry->IsPersistent()) { |
| 357 continue; | 353 continue; |
| 358 } | 354 } |
| 359 if (entry->vendor_id() != device->vendor_id()) { | 355 if (entry->vendor_id() != device->vendor_id()) { |
| 360 continue; | 356 continue; |
| 361 } | 357 } |
| 362 if (entry->product_id() != device->product_id()) { | 358 if (entry->product_id() != device->product_id()) { |
| 363 continue; | 359 continue; |
| 364 } | 360 } |
| 365 if (entry->serial_number() != serial_number) { | 361 if (entry->serial_number() != device->serial_number()) { |
| 366 continue; | 362 continue; |
| 367 } | 363 } |
| 368 return entry; | 364 return entry; |
| 369 } | 365 } |
| 370 return nullptr; | 366 return nullptr; |
| 371 } | 367 } |
| 372 | 368 |
| 373 DevicePermissions::DevicePermissions(BrowserContext* context, | 369 DevicePermissions::DevicePermissions(BrowserContext* context, |
| 374 const std::string& extension_id) { | 370 const std::string& extension_id) { |
| 375 ExtensionPrefs* prefs = ExtensionPrefs::Get(context); | 371 ExtensionPrefs* prefs = ExtensionPrefs::Get(context); |
| 376 entries_ = GetDevicePermissionEntries(prefs, extension_id); | 372 entries_ = GetDevicePermissionEntries(prefs, extension_id); |
| 377 } | 373 } |
| 378 | 374 |
| 379 DevicePermissions::DevicePermissions(const DevicePermissions* original) | |
| 380 : entries_(original->entries_), | |
| 381 ephemeral_devices_(original->ephemeral_devices_) { | |
| 382 } | |
| 383 | |
| 384 class DevicePermissionsManager::FileThreadHelper : public UsbService::Observer { | |
| 385 public: | |
| 386 FileThreadHelper( | |
| 387 base::WeakPtr<DevicePermissionsManager> device_permissions_manager) | |
| 388 : device_permissions_manager_(device_permissions_manager), | |
| 389 observer_(this) {} | |
| 390 virtual ~FileThreadHelper() {} | |
| 391 | |
| 392 void Start() { | |
| 393 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | |
| 394 UsbService* service = device::DeviceClient::Get()->GetUsbService(); | |
| 395 if (service) { | |
| 396 observer_.Add(service); | |
| 397 } | |
| 398 } | |
| 399 | |
| 400 private: | |
| 401 void OnDeviceRemovedCleanup(scoped_refptr<UsbDevice> device) override { | |
| 402 DCHECK_CURRENTLY_ON(BrowserThread::FILE); | |
| 403 BrowserThread::PostTask( | |
| 404 BrowserThread::UI, FROM_HERE, | |
| 405 base::Bind(&DevicePermissionsManager::OnDeviceRemoved, | |
| 406 device_permissions_manager_, device)); | |
| 407 } | |
| 408 | |
| 409 base::WeakPtr<DevicePermissionsManager> device_permissions_manager_; | |
| 410 ScopedObserver<UsbService, UsbService::Observer> observer_; | |
| 411 }; | |
| 412 | |
| 413 // static | 375 // static |
| 414 DevicePermissionsManager* DevicePermissionsManager::Get( | 376 DevicePermissionsManager* DevicePermissionsManager::Get( |
| 415 BrowserContext* context) { | 377 BrowserContext* context) { |
| 416 return DevicePermissionsManagerFactory::GetForBrowserContext(context); | 378 return DevicePermissionsManagerFactory::GetForBrowserContext(context); |
| 417 } | 379 } |
| 418 | 380 |
| 419 scoped_ptr<DevicePermissions> DevicePermissionsManager::GetForExtension( | 381 DevicePermissions* DevicePermissionsManager::GetForExtension( |
| 420 const std::string& extension_id) { | 382 const std::string& extension_id) { |
| 421 DCHECK(CalledOnValidThread()); | 383 DCHECK(CalledOnValidThread()); |
| 422 return make_scoped_ptr(new DevicePermissions(GetOrInsert(extension_id))); | 384 DevicePermissions* device_permissions = Get(extension_id); |
| 385 if (!device_permissions) { |
| 386 device_permissions = new DevicePermissions(context_, extension_id); |
| 387 extension_id_to_device_permissions_[extension_id] = device_permissions; |
| 388 } |
| 389 |
| 390 return device_permissions; |
| 423 } | 391 } |
| 424 | 392 |
| 425 std::vector<base::string16> | 393 std::vector<base::string16> |
| 426 DevicePermissionsManager::GetPermissionMessageStrings( | 394 DevicePermissionsManager::GetPermissionMessageStrings( |
| 427 const std::string& extension_id) const { | 395 const std::string& extension_id) const { |
| 428 DCHECK(CalledOnValidThread()); | 396 DCHECK(CalledOnValidThread()); |
| 429 std::vector<base::string16> messages; | 397 std::vector<base::string16> messages; |
| 430 const DevicePermissions* device_permissions = Get(extension_id); | 398 const DevicePermissions* device_permissions = Get(extension_id); |
| 431 if (device_permissions) { | 399 if (device_permissions) { |
| 432 for (const scoped_refptr<DevicePermissionEntry>& entry : | 400 for (const scoped_refptr<DevicePermissionEntry>& entry : |
| 433 device_permissions->entries()) { | 401 device_permissions->entries()) { |
| 434 messages.push_back(entry->GetPermissionMessageString()); | 402 messages.push_back(entry->GetPermissionMessageString()); |
| 435 } | 403 } |
| 436 } | 404 } |
| 437 return messages; | 405 return messages; |
| 438 } | 406 } |
| 439 | 407 |
| 440 void DevicePermissionsManager::AllowUsbDevice( | 408 void DevicePermissionsManager::AllowUsbDevice( |
| 441 const std::string& extension_id, | 409 const std::string& extension_id, |
| 442 scoped_refptr<device::UsbDevice> device, | 410 scoped_refptr<device::UsbDevice> device) { |
| 443 const base::string16& product_string, | |
| 444 const base::string16& manufacturer_string, | |
| 445 const base::string16& serial_number) { | |
| 446 DCHECK(CalledOnValidThread()); | 411 DCHECK(CalledOnValidThread()); |
| 447 DevicePermissions* device_permissions = GetOrInsert(extension_id); | 412 DevicePermissions* device_permissions = GetForExtension(extension_id); |
| 448 | 413 |
| 449 scoped_refptr<DevicePermissionEntry> device_entry(new DevicePermissionEntry( | 414 scoped_refptr<DevicePermissionEntry> device_entry( |
| 450 device, serial_number, manufacturer_string, product_string)); | 415 new DevicePermissionEntry(device)); |
| 451 | 416 |
| 452 if (device_entry->IsPersistent()) { | 417 if (device_entry->IsPersistent()) { |
| 453 for (const auto& entry : device_permissions->entries()) { | 418 for (const auto& entry : device_permissions->entries()) { |
| 454 if (entry->vendor_id() != device_entry->vendor_id()) { | 419 if (entry->vendor_id() != device_entry->vendor_id()) { |
| 455 continue; | 420 continue; |
| 456 } | 421 } |
| 457 if (entry->product_id() != device_entry->product_id()) { | 422 if (entry->product_id() != device_entry->product_id()) { |
| 458 continue; | 423 continue; |
| 459 } | 424 } |
| 460 if (entry->serial_number() == device_entry->serial_number()) { | 425 if (entry->serial_number() == device_entry->serial_number()) { |
| 461 return; | 426 return; |
| 462 } | 427 } |
| 463 } | 428 } |
| 464 | 429 |
| 465 device_permissions->entries_.insert(device_entry); | 430 device_permissions->entries_.insert(device_entry); |
| 466 SaveDevicePermissionEntry(context_, extension_id, device_entry); | 431 SaveDevicePermissionEntry(context_, extension_id, device_entry); |
| 467 } else if (!ContainsKey(device_permissions->ephemeral_devices_, device)) { | 432 } else if (!ContainsKey(device_permissions->ephemeral_devices_, device)) { |
| 468 // Non-persistent devices cannot be reliably identified when they are | 433 // Non-persistent devices cannot be reliably identified when they are |
| 469 // reconnected so such devices are only remembered until disconnect. | 434 // reconnected so such devices are only remembered until disconnect. |
| 470 // Register an observer here so that this set doesn't grow undefinitely. | 435 // Register an observer here so that this set doesn't grow undefinitely. |
| 471 device_permissions->entries_.insert(device_entry); | 436 device_permissions->entries_.insert(device_entry); |
| 472 device_permissions->ephemeral_devices_[device] = device_entry; | 437 device_permissions->ephemeral_devices_[device] = device_entry; |
| 473 | 438 |
| 474 // Only start observing when an ephemeral device has been added so that | 439 // Only start observing when an ephemeral device has been added so that |
| 475 // UsbService is not automatically initialized on profile creation (which it | 440 // UsbService is not automatically initialized on profile creation (which it |
| 476 // would be if this call were in the constructor). | 441 // would be if this call were in the constructor). |
| 477 if (!helper_) { | 442 UsbService* usb_service = device::DeviceClient::Get()->GetUsbService(); |
| 478 helper_ = new FileThreadHelper(weak_factory_.GetWeakPtr()); | 443 if (!usb_service_observer_.IsObserving(usb_service)) { |
| 479 // base::Unretained is safe because any task to delete helper_ will be | 444 usb_service_observer_.Add(usb_service); |
| 480 // executed after this call. | |
| 481 BrowserThread::PostTask( | |
| 482 BrowserThread::FILE, FROM_HERE, | |
| 483 base::Bind(&FileThreadHelper::Start, base::Unretained(helper_))); | |
| 484 } | 445 } |
| 485 } | 446 } |
| 486 } | 447 } |
| 487 | 448 |
| 488 void DevicePermissionsManager::UpdateLastUsed( | 449 void DevicePermissionsManager::UpdateLastUsed( |
| 489 const std::string& extension_id, | 450 const std::string& extension_id, |
| 490 scoped_refptr<DevicePermissionEntry> entry) { | 451 scoped_refptr<DevicePermissionEntry> entry) { |
| 491 DCHECK(CalledOnValidThread()); | 452 DCHECK(CalledOnValidThread()); |
| 492 entry->set_last_used(base::Time::Now()); | 453 entry->set_last_used(base::Time::Now()); |
| 493 if (entry->IsPersistent()) { | 454 if (entry->IsPersistent()) { |
| (...skipping 24 matching lines...) Expand all Loading... |
| 518 if (device_permissions) { | 479 if (device_permissions) { |
| 519 extension_id_to_device_permissions_.erase(extension_id); | 480 extension_id_to_device_permissions_.erase(extension_id); |
| 520 delete device_permissions; | 481 delete device_permissions; |
| 521 } | 482 } |
| 522 } | 483 } |
| 523 | 484 |
| 524 DevicePermissionsManager::DevicePermissionsManager( | 485 DevicePermissionsManager::DevicePermissionsManager( |
| 525 content::BrowserContext* context) | 486 content::BrowserContext* context) |
| 526 : context_(context), | 487 : context_(context), |
| 527 process_manager_observer_(this), | 488 process_manager_observer_(this), |
| 528 helper_(nullptr), | 489 usb_service_observer_(this) { |
| 529 weak_factory_(this) { | |
| 530 process_manager_observer_.Add(ProcessManager::Get(context)); | 490 process_manager_observer_.Add(ProcessManager::Get(context)); |
| 531 } | 491 } |
| 532 | 492 |
| 533 DevicePermissionsManager::~DevicePermissionsManager() { | 493 DevicePermissionsManager::~DevicePermissionsManager() { |
| 534 for (const auto& map_entry : extension_id_to_device_permissions_) { | 494 for (const auto& map_entry : extension_id_to_device_permissions_) { |
| 535 DevicePermissions* device_permissions = map_entry.second; | 495 DevicePermissions* device_permissions = map_entry.second; |
| 536 delete device_permissions; | 496 delete device_permissions; |
| 537 } | 497 } |
| 538 if (helper_) { | |
| 539 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, helper_); | |
| 540 helper_ = nullptr; | |
| 541 } | |
| 542 } | 498 } |
| 543 | 499 |
| 544 DevicePermissions* DevicePermissionsManager::Get( | 500 DevicePermissions* DevicePermissionsManager::Get( |
| 545 const std::string& extension_id) const { | 501 const std::string& extension_id) const { |
| 546 std::map<std::string, DevicePermissions*>::const_iterator it = | 502 std::map<std::string, DevicePermissions*>::const_iterator it = |
| 547 extension_id_to_device_permissions_.find(extension_id); | 503 extension_id_to_device_permissions_.find(extension_id); |
| 548 if (it != extension_id_to_device_permissions_.end()) { | 504 if (it != extension_id_to_device_permissions_.end()) { |
| 549 return it->second; | 505 return it->second; |
| 550 } | 506 } |
| 551 | 507 |
| 552 return NULL; | 508 return NULL; |
| 553 } | 509 } |
| 554 | 510 |
| 555 DevicePermissions* DevicePermissionsManager::GetOrInsert( | |
| 556 const std::string& extension_id) { | |
| 557 DevicePermissions* device_permissions = Get(extension_id); | |
| 558 if (!device_permissions) { | |
| 559 device_permissions = new DevicePermissions(context_, extension_id); | |
| 560 extension_id_to_device_permissions_[extension_id] = device_permissions; | |
| 561 } | |
| 562 | |
| 563 return device_permissions; | |
| 564 } | |
| 565 | |
| 566 void DevicePermissionsManager::OnBackgroundHostClose( | 511 void DevicePermissionsManager::OnBackgroundHostClose( |
| 567 const std::string& extension_id) { | 512 const std::string& extension_id) { |
| 568 DCHECK(CalledOnValidThread()); | 513 DCHECK(CalledOnValidThread()); |
| 569 | 514 |
| 570 DevicePermissions* device_permissions = Get(extension_id); | 515 DevicePermissions* device_permissions = Get(extension_id); |
| 571 if (device_permissions) { | 516 if (device_permissions) { |
| 572 // When all of the app's windows are closed and the background page is | 517 // When all of the app's windows are closed and the background page is |
| 573 // suspended all ephemeral device permissions are cleared. | 518 // suspended all ephemeral device permissions are cleared. |
| 574 for (const auto& map_entry : device_permissions->ephemeral_devices_) { | 519 for (const auto& map_entry : device_permissions->ephemeral_devices_) { |
| 575 device_permissions->entries_.erase(map_entry.second); | 520 device_permissions->entries_.erase(map_entry.second); |
| 576 } | 521 } |
| 577 device_permissions->ephemeral_devices_.clear(); | 522 device_permissions->ephemeral_devices_.clear(); |
| 578 } | 523 } |
| 579 } | 524 } |
| 580 | 525 |
| 581 void DevicePermissionsManager::OnDeviceRemoved( | 526 void DevicePermissionsManager::OnDeviceRemovedCleanup( |
| 582 scoped_refptr<UsbDevice> device) { | 527 scoped_refptr<UsbDevice> device) { |
| 583 DCHECK(CalledOnValidThread()); | 528 DCHECK(CalledOnValidThread()); |
| 584 for (const auto& map_entry : extension_id_to_device_permissions_) { | 529 for (const auto& map_entry : extension_id_to_device_permissions_) { |
| 585 // An ephemeral device cannot be identified if it is reconnected and so | 530 // An ephemeral device cannot be identified if it is reconnected and so |
| 586 // permission to access it is cleared on disconnect. | 531 // permission to access it is cleared on disconnect. |
| 587 DevicePermissions* device_permissions = map_entry.second; | 532 DevicePermissions* device_permissions = map_entry.second; |
| 588 const auto& device_entry = | 533 const auto& device_entry = |
| 589 device_permissions->ephemeral_devices_.find(device); | 534 device_permissions->ephemeral_devices_.find(device); |
| 590 if (device_entry != device_permissions->ephemeral_devices_.end()) { | 535 if (device_entry != device_permissions->ephemeral_devices_.end()) { |
| 591 device_permissions->entries_.erase(device_entry->second); | 536 device_permissions->entries_.erase(device_entry->second); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 624 | 569 |
| 625 BrowserContext* DevicePermissionsManagerFactory::GetBrowserContextToUse( | 570 BrowserContext* DevicePermissionsManagerFactory::GetBrowserContextToUse( |
| 626 BrowserContext* context) const { | 571 BrowserContext* context) const { |
| 627 // Return the original (possibly off-the-record) browser context so that a | 572 // Return the original (possibly off-the-record) browser context so that a |
| 628 // separate instance of the DevicePermissionsManager is used in incognito | 573 // separate instance of the DevicePermissionsManager is used in incognito |
| 629 // mode. The parent class's implemenation returns NULL. | 574 // mode. The parent class's implemenation returns NULL. |
| 630 return context; | 575 return context; |
| 631 } | 576 } |
| 632 | 577 |
| 633 } // namespace extensions | 578 } // namespace extensions |
| OLD | NEW |