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_device_permissions.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 |