| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "chrome/browser/media/media_stream_devices_controller.h" | 5 #include "chrome/browser/media/media_stream_devices_controller.h" |
| 6 | 6 |
| 7 #include "base/command_line.h" | |
| 8 #include "base/metrics/histogram.h" | 7 #include "base/metrics/histogram.h" |
| 9 #include "base/prefs/pref_service.h" | |
| 10 #include "base/prefs/scoped_user_pref_update.h" | 8 #include "base/prefs/scoped_user_pref_update.h" |
| 11 #include "base/strings/utf_string_conversions.h" | 9 #include "base/strings/utf_string_conversions.h" |
| 12 #include "base/values.h" | 10 #include "base/values.h" |
| 13 #include "chrome/browser/content_settings/content_settings_provider.h" | 11 #include "chrome/browser/content_settings/content_settings_provider.h" |
| 14 #include "chrome/browser/content_settings/host_content_settings_map.h" | 12 #include "chrome/browser/content_settings/host_content_settings_map.h" |
| 15 #include "chrome/browser/content_settings/tab_specific_content_settings.h" | 13 #include "chrome/browser/content_settings/tab_specific_content_settings.h" |
| 16 #include "chrome/browser/media/media_capture_devices_dispatcher.h" | 14 #include "chrome/browser/media/media_capture_devices_dispatcher.h" |
| 17 #include "chrome/browser/media/media_stream_capture_indicator.h" | 15 #include "chrome/browser/media/media_stream_capture_indicator.h" |
| 16 #include "chrome/browser/media/media_stream_devices_util.h" |
| 18 #include "chrome/browser/profiles/profile.h" | 17 #include "chrome/browser/profiles/profile.h" |
| 19 #include "chrome/browser/ui/browser.h" | 18 #include "chrome/browser/ui/browser.h" |
| 20 #include "chrome/common/chrome_switches.h" | 19 #include "chrome/common/chrome_switches.h" |
| 21 #include "chrome/common/content_settings.h" | 20 #include "chrome/common/content_settings.h" |
| 22 #include "chrome/common/content_settings_pattern.h" | 21 #include "chrome/common/content_settings_pattern.h" |
| 23 #include "chrome/common/pref_names.h" | 22 #include "chrome/common/pref_names.h" |
| 24 #include "chrome/grit/generated_resources.h" | 23 #include "chrome/grit/generated_resources.h" |
| 25 #include "components/pref_registry/pref_registry_syncable.h" | 24 #include "components/pref_registry/pref_registry_syncable.h" |
| 26 #include "content/public/browser/browser_thread.h" | 25 #include "content/public/browser/browser_thread.h" |
| 27 #include "content/public/browser/render_widget_host_view.h" | 26 #include "content/public/browser/render_widget_host_view.h" |
| 28 #include "content/public/common/media_stream_request.h" | 27 #include "content/public/common/media_stream_request.h" |
| 29 #include "extensions/common/constants.h" | 28 #include "extensions/common/constants.h" |
| 30 #include "grit/theme_resources.h" | 29 #include "grit/theme_resources.h" |
| 31 #include "ui/base/l10n/l10n_util.h" | 30 #include "ui/base/l10n/l10n_util.h" |
| 32 | 31 |
| 33 #if defined(OS_CHROMEOS) | |
| 34 #include "components/user_manager/user_manager.h" | |
| 35 #endif | |
| 36 | |
| 37 using content::BrowserThread; | 32 using content::BrowserThread; |
| 38 | 33 |
| 39 namespace { | 34 namespace { |
| 40 | 35 |
| 41 bool HasAvailableDevicesForRequest(const content::MediaStreamRequest& request) { | 36 bool HasAvailableDevicesForRequest(const content::MediaStreamRequest& request) { |
| 42 const content::MediaStreamDevices* audio_devices = | 37 const content::MediaStreamDevices* audio_devices = |
| 43 request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE ? | 38 request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE ? |
| 44 &MediaCaptureDevicesDispatcher::GetInstance() | 39 &MediaCaptureDevicesDispatcher::GetInstance() |
| 45 ->GetAudioCaptureDevices() : | 40 ->GetAudioCaptureDevices() : |
| 46 NULL; | 41 NULL; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 74 } | 69 } |
| 75 | 70 |
| 76 if (!request.requested_video_device_id.empty() && | 71 if (!request.requested_video_device_id.empty() && |
| 77 !video_devices->FindById(request.requested_video_device_id)) { | 72 !video_devices->FindById(request.requested_video_device_id)) { |
| 78 return false; | 73 return false; |
| 79 } | 74 } |
| 80 | 75 |
| 81 return true; | 76 return true; |
| 82 } | 77 } |
| 83 | 78 |
| 84 bool IsInKioskMode() { | |
| 85 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kKioskMode)) | |
| 86 return true; | |
| 87 | |
| 88 #if defined(OS_CHROMEOS) | |
| 89 const user_manager::UserManager* user_manager = | |
| 90 user_manager::UserManager::Get(); | |
| 91 return user_manager && user_manager->IsLoggedInAsKioskApp(); | |
| 92 #else | |
| 93 return false; | |
| 94 #endif | |
| 95 } | |
| 96 | |
| 97 enum DevicePermissionActions { | 79 enum DevicePermissionActions { |
| 98 kAllowHttps = 0, | 80 kAllowHttps = 0, |
| 99 kAllowHttp, | 81 kAllowHttp, |
| 100 kDeny, | 82 kDeny, |
| 101 kCancel, | 83 kCancel, |
| 102 kPermissionActionsMax // Must always be last! | 84 kPermissionActionsMax // Must always be last! |
| 103 }; | 85 }; |
| 104 | 86 |
| 105 } // namespace | 87 } // namespace |
| 106 | 88 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 127 // For MEDIA_OPEN_DEVICE requests (Pepper) we always request both webcam | 109 // For MEDIA_OPEN_DEVICE requests (Pepper) we always request both webcam |
| 128 // and microphone to avoid popping two infobars. | 110 // and microphone to avoid popping two infobars. |
| 129 // We start with setting the requested media type to allowed or blocked | 111 // We start with setting the requested media type to allowed or blocked |
| 130 // depending on the policy. If not blocked by policy it may be blocked later | 112 // depending on the policy. If not blocked by policy it may be blocked later |
| 131 // in the two remaining filtering steps (by user setting or by user when | 113 // in the two remaining filtering steps (by user setting or by user when |
| 132 // clicking the infobar). | 114 // clicking the infobar). |
| 133 // TODO(grunell): It's not the nicest solution to let the MEDIA_OPEN_DEVICE | 115 // TODO(grunell): It's not the nicest solution to let the MEDIA_OPEN_DEVICE |
| 134 // case take a ride on the MEDIA_DEVICE_*_CAPTURE permission. Should be fixed. | 116 // case take a ride on the MEDIA_DEVICE_*_CAPTURE permission. Should be fixed. |
| 135 if (request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE || | 117 if (request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE || |
| 136 request.request_type == content::MEDIA_OPEN_DEVICE) { | 118 request.request_type == content::MEDIA_OPEN_DEVICE) { |
| 137 if (GetDevicePolicy(prefs::kAudioCaptureAllowed, | 119 if (GetDevicePolicy(profile_, |
| 120 request_.security_origin, |
| 121 prefs::kAudioCaptureAllowed, |
| 138 prefs::kAudioCaptureAllowedUrls) == ALWAYS_DENY) { | 122 prefs::kAudioCaptureAllowedUrls) == ALWAYS_DENY) { |
| 139 request_permissions_.insert(std::make_pair( | 123 request_permissions_.insert(std::make_pair( |
| 140 content::MEDIA_DEVICE_AUDIO_CAPTURE, | 124 content::MEDIA_DEVICE_AUDIO_CAPTURE, |
| 141 MediaStreamTypeSettings(MEDIA_BLOCKED_BY_POLICY, | 125 MediaStreamTypeSettings(MEDIA_BLOCKED_BY_POLICY, |
| 142 request.requested_audio_device_id))); | 126 request.requested_audio_device_id))); |
| 143 } else { | 127 } else { |
| 144 request_permissions_.insert(std::make_pair( | 128 request_permissions_.insert(std::make_pair( |
| 145 content::MEDIA_DEVICE_AUDIO_CAPTURE, | 129 content::MEDIA_DEVICE_AUDIO_CAPTURE, |
| 146 MediaStreamTypeSettings(MEDIA_ALLOWED, | 130 MediaStreamTypeSettings(MEDIA_ALLOWED, |
| 147 request.requested_audio_device_id))); | 131 request.requested_audio_device_id))); |
| 148 } | 132 } |
| 149 } | 133 } |
| 150 if (request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE || | 134 if (request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE || |
| 151 request.request_type == content::MEDIA_OPEN_DEVICE) { | 135 request.request_type == content::MEDIA_OPEN_DEVICE) { |
| 152 if (GetDevicePolicy(prefs::kVideoCaptureAllowed, | 136 if (GetDevicePolicy(profile_, |
| 137 request_.security_origin, |
| 138 prefs::kVideoCaptureAllowed, |
| 153 prefs::kVideoCaptureAllowedUrls) == ALWAYS_DENY) { | 139 prefs::kVideoCaptureAllowedUrls) == ALWAYS_DENY) { |
| 154 request_permissions_.insert(std::make_pair( | 140 request_permissions_.insert(std::make_pair( |
| 155 content::MEDIA_DEVICE_VIDEO_CAPTURE, | 141 content::MEDIA_DEVICE_VIDEO_CAPTURE, |
| 156 MediaStreamTypeSettings(MEDIA_BLOCKED_BY_POLICY, | 142 MediaStreamTypeSettings(MEDIA_BLOCKED_BY_POLICY, |
| 157 request.requested_video_device_id))); | 143 request.requested_video_device_id))); |
| 158 } else { | 144 } else { |
| 159 request_permissions_.insert(std::make_pair( | 145 request_permissions_.insert(std::make_pair( |
| 160 content::MEDIA_DEVICE_VIDEO_CAPTURE, | 146 content::MEDIA_DEVICE_VIDEO_CAPTURE, |
| 161 MediaStreamTypeSettings(MEDIA_ALLOWED, | 147 MediaStreamTypeSettings(MEDIA_ALLOWED, |
| 162 request.requested_video_device_id))); | 148 request.requested_video_device_id))); |
| (...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 449 void MediaStreamDevicesController::Cancelled() { | 435 void MediaStreamDevicesController::Cancelled() { |
| 450 UMA_HISTOGRAM_ENUMERATION("Media.DevicePermissionActions", | 436 UMA_HISTOGRAM_ENUMERATION("Media.DevicePermissionActions", |
| 451 kCancel, kPermissionActionsMax); | 437 kCancel, kPermissionActionsMax); |
| 452 Deny(false, content::MEDIA_DEVICE_PERMISSION_DISMISSED); | 438 Deny(false, content::MEDIA_DEVICE_PERMISSION_DISMISSED); |
| 453 } | 439 } |
| 454 | 440 |
| 455 void MediaStreamDevicesController::RequestFinished() { | 441 void MediaStreamDevicesController::RequestFinished() { |
| 456 delete this; | 442 delete this; |
| 457 } | 443 } |
| 458 | 444 |
| 459 MediaStreamDevicesController::DevicePolicy | |
| 460 MediaStreamDevicesController::GetDevicePolicy( | |
| 461 const char* policy_name, | |
| 462 const char* whitelist_policy_name) const { | |
| 463 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 464 | |
| 465 // If the security origin policy matches a value in the whitelist, allow it. | |
| 466 // Otherwise, check the |policy_name| master switch for the default behavior. | |
| 467 | |
| 468 PrefService* prefs = profile_->GetPrefs(); | |
| 469 | |
| 470 // TODO(tommi): Remove the kiosk mode check when the whitelist below | |
| 471 // is visible in the media exceptions UI. | |
| 472 // See discussion here: https://codereview.chromium.org/15738004/ | |
| 473 if (IsInKioskMode()) { | |
| 474 const base::ListValue* list = prefs->GetList(whitelist_policy_name); | |
| 475 std::string value; | |
| 476 for (size_t i = 0; i < list->GetSize(); ++i) { | |
| 477 if (list->GetString(i, &value)) { | |
| 478 ContentSettingsPattern pattern = | |
| 479 ContentSettingsPattern::FromString(value); | |
| 480 if (pattern == ContentSettingsPattern::Wildcard()) { | |
| 481 DLOG(WARNING) << "Ignoring wildcard URL pattern: " << value; | |
| 482 continue; | |
| 483 } | |
| 484 DLOG_IF(ERROR, !pattern.IsValid()) << "Invalid URL pattern: " << value; | |
| 485 if (pattern.IsValid() && pattern.Matches(request_.security_origin)) | |
| 486 return ALWAYS_ALLOW; | |
| 487 } | |
| 488 } | |
| 489 } | |
| 490 | |
| 491 // If a match was not found, check if audio capture is otherwise disallowed | |
| 492 // or if the user should be prompted. Setting the policy value to "true" | |
| 493 // is equal to not setting it at all, so from hereon out, we will return | |
| 494 // either POLICY_NOT_SET (prompt) or ALWAYS_DENY (no prompt, no access). | |
| 495 if (!prefs->GetBoolean(policy_name)) | |
| 496 return ALWAYS_DENY; | |
| 497 | |
| 498 return POLICY_NOT_SET; | |
| 499 } | |
| 500 | |
| 501 bool MediaStreamDevicesController::IsRequestAllowedByDefault() const { | 445 bool MediaStreamDevicesController::IsRequestAllowedByDefault() const { |
| 502 // The request from internal objects like chrome://URLs is always allowed. | 446 // The request from internal objects like chrome://URLs is always allowed. |
| 503 if (ShouldAlwaysAllowOrigin()) | 447 if (CheckAllowAllMediaStreamContentForOrigin(profile_, |
| 448 request_.security_origin)) { |
| 504 return true; | 449 return true; |
| 450 } |
| 505 | 451 |
| 506 struct { | 452 struct { |
| 507 bool has_capability; | 453 bool has_capability; |
| 508 const char* policy_name; | 454 const char* policy_name; |
| 509 const char* list_policy_name; | 455 const char* list_policy_name; |
| 510 ContentSettingsType settings_type; | 456 ContentSettingsType settings_type; |
| 511 } device_checks[] = { | 457 } device_checks[] = { |
| 512 { IsDeviceAudioCaptureRequestedAndAllowed(), prefs::kAudioCaptureAllowed, | 458 { IsDeviceAudioCaptureRequestedAndAllowed(), prefs::kAudioCaptureAllowed, |
| 513 prefs::kAudioCaptureAllowedUrls, CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC }, | 459 prefs::kAudioCaptureAllowedUrls, CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC }, |
| 514 { IsDeviceVideoCaptureRequestedAndAllowed(), prefs::kVideoCaptureAllowed, | 460 { IsDeviceVideoCaptureRequestedAndAllowed(), prefs::kVideoCaptureAllowed, |
| 515 prefs::kVideoCaptureAllowedUrls, | 461 prefs::kVideoCaptureAllowedUrls, |
| 516 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA }, | 462 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA }, |
| 517 }; | 463 }; |
| 518 | 464 |
| 519 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(device_checks); ++i) { | 465 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(device_checks); ++i) { |
| 520 if (!device_checks[i].has_capability) | 466 if (!device_checks[i].has_capability) |
| 521 continue; | 467 continue; |
| 522 | 468 |
| 523 DevicePolicy policy = GetDevicePolicy(device_checks[i].policy_name, | 469 MediaStreamDevicePolicy policy = |
| 524 device_checks[i].list_policy_name); | 470 GetDevicePolicy(profile_, |
| 471 request_.security_origin, |
| 472 device_checks[i].policy_name, |
| 473 device_checks[i].list_policy_name); |
| 525 | 474 |
| 526 if (policy == ALWAYS_DENY) | 475 if (policy == ALWAYS_DENY) |
| 527 return false; | 476 return false; |
| 528 | 477 |
| 529 if (policy == POLICY_NOT_SET) { | 478 if (policy == POLICY_NOT_SET) { |
| 530 // Only load content settings from secure origins unless it is a | 479 // Only load content settings from secure origins unless it is a |
| 531 // content::MEDIA_OPEN_DEVICE (Pepper) request. | 480 // content::MEDIA_OPEN_DEVICE (Pepper) request. |
| 532 if (!IsSchemeSecure() && | 481 if (!IsSchemeSecure() && |
| 533 request_.request_type != content::MEDIA_OPEN_DEVICE) { | 482 request_.request_type != content::MEDIA_OPEN_DEVICE) { |
| 534 return false; | 483 return false; |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 588 profile_->GetHostContentSettingsMap()->GetDefaultContentSetting( | 537 profile_->GetHostContentSettingsMap()->GetDefaultContentSetting( |
| 589 CONTENT_SETTINGS_TYPE_MEDIASTREAM, NULL); | 538 CONTENT_SETTINGS_TYPE_MEDIASTREAM, NULL); |
| 590 return (current_setting == CONTENT_SETTING_BLOCK); | 539 return (current_setting == CONTENT_SETTING_BLOCK); |
| 591 } | 540 } |
| 592 | 541 |
| 593 bool MediaStreamDevicesController::IsSchemeSecure() const { | 542 bool MediaStreamDevicesController::IsSchemeSecure() const { |
| 594 return request_.security_origin.SchemeIsSecure() || | 543 return request_.security_origin.SchemeIsSecure() || |
| 595 request_.security_origin.SchemeIs(extensions::kExtensionScheme); | 544 request_.security_origin.SchemeIs(extensions::kExtensionScheme); |
| 596 } | 545 } |
| 597 | 546 |
| 598 bool MediaStreamDevicesController::ShouldAlwaysAllowOrigin() const { | |
| 599 // TODO(markusheintz): Replace CONTENT_SETTINGS_TYPE_MEDIA_STREAM with the | |
| 600 // appropriate new CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC and | |
| 601 // CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA. | |
| 602 return profile_->GetHostContentSettingsMap()->ShouldAllowAllContent( | |
| 603 request_.security_origin, request_.security_origin, | |
| 604 CONTENT_SETTINGS_TYPE_MEDIASTREAM); | |
| 605 } | |
| 606 | |
| 607 void MediaStreamDevicesController::SetPermission(bool allowed) const { | 547 void MediaStreamDevicesController::SetPermission(bool allowed) const { |
| 608 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 548 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 609 ContentSettingsPattern primary_pattern = | 549 ContentSettingsPattern primary_pattern = |
| 610 ContentSettingsPattern::FromURLNoWildcard(request_.security_origin); | 550 ContentSettingsPattern::FromURLNoWildcard(request_.security_origin); |
| 611 // Check the pattern is valid or not. When the request is from a file access, | 551 // Check the pattern is valid or not. When the request is from a file access, |
| 612 // no exception will be made. | 552 // no exception will be made. |
| 613 if (!primary_pattern.IsValid()) | 553 if (!primary_pattern.IsValid()) |
| 614 return; | 554 return; |
| 615 | 555 |
| 616 ContentSetting content_setting = allowed ? | 556 ContentSetting content_setting = allowed ? |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 677 } | 617 } |
| 678 | 618 |
| 679 bool MediaStreamDevicesController::IsCaptureDeviceRequestAllowed() const { | 619 bool MediaStreamDevicesController::IsCaptureDeviceRequestAllowed() const { |
| 680 #if defined(OS_ANDROID) | 620 #if defined(OS_ANDROID) |
| 681 // Don't approve device requests if the tab was hidden. | 621 // Don't approve device requests if the tab was hidden. |
| 682 // TODO(qinmin): Add a test for this. http://crbug.com/396869. | 622 // TODO(qinmin): Add a test for this. http://crbug.com/396869. |
| 683 return web_contents_->GetRenderWidgetHostView()->IsShowing(); | 623 return web_contents_->GetRenderWidgetHostView()->IsShowing(); |
| 684 #endif | 624 #endif |
| 685 return true; | 625 return true; |
| 686 } | 626 } |
| OLD | NEW |