Fire an error if a pref used in the UI is missing once all prefs are fetched.
[chromium-blink-merge.git] / chrome / browser / media / protected_media_identifier_permission_context.cc
blobabdd046d8171acd1eeae76c03a69521fd1cde434
1 // Copyright 2013 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.
5 #include "chrome/browser/media/protected_media_identifier_permission_context.h"
7 #include "base/prefs/pref_service.h"
8 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
9 #include "chrome/browser/profiles/profile.h"
10 #include "chrome/common/pref_names.h"
11 #include "components/content_settings/core/common/permission_request_id.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "content/public/browser/user_metrics.h"
14 #include "content/public/browser/web_contents.h"
16 #if defined(OS_CHROMEOS)
17 #include <utility>
19 #include "chrome/browser/chromeos/attestation/platform_verification_dialog.h"
20 #include "chrome/browser/chromeos/settings/cros_settings.h"
21 #include "chromeos/settings/cros_settings_names.h"
22 #include "components/pref_registry/pref_registry_syncable.h"
23 #include "components/user_prefs/user_prefs.h"
24 #include "ui/views/widget/widget.h"
25 #elif defined(OS_ANDROID)
26 #include "base/command_line.h"
27 #include "media/base/media_switches.h"
28 #else
29 #error This file currently only supports Chrome OS and Android.
30 #endif
32 ProtectedMediaIdentifierPermissionContext::
33 ProtectedMediaIdentifierPermissionContext(Profile* profile)
34 : PermissionContextBase(profile,
35 CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER)
36 #if defined(OS_CHROMEOS)
38 weak_factory_(this)
39 #endif
43 ProtectedMediaIdentifierPermissionContext::
44 ~ProtectedMediaIdentifierPermissionContext() {
47 #if defined(OS_CHROMEOS)
48 using chromeos::attestation::PlatformVerificationDialog;
50 // static
51 void ProtectedMediaIdentifierPermissionContext::RegisterProfilePrefs(
52 user_prefs::PrefRegistrySyncable* prefs) {
53 prefs->RegisterBooleanPref(prefs::kRAConsentGranted,
54 false, // Default value.
55 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
57 #endif
59 void ProtectedMediaIdentifierPermissionContext::RequestPermission(
60 content::WebContents* web_contents,
61 const PermissionRequestID& id,
62 const GURL& requesting_origin,
63 bool user_gesture,
64 const BrowserPermissionCallback& callback) {
65 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
67 GURL embedding_origin = web_contents->GetLastCommittedURL().GetOrigin();
69 DVLOG(1) << __FUNCTION__ << ": (" << requesting_origin.spec() << ", "
70 << embedding_origin.spec() << ")";
72 ContentSetting content_setting =
73 GetPermissionStatus(requesting_origin, embedding_origin);
75 if (content_setting == CONTENT_SETTING_ALLOW ||
76 content_setting == CONTENT_SETTING_BLOCK) {
77 NotifyPermissionSet(id, requesting_origin, embedding_origin, callback,
78 false /* persist */, content_setting);
79 return;
82 DCHECK_EQ(CONTENT_SETTING_ASK, content_setting);
84 #if defined(OS_CHROMEOS)
85 // Since the dialog is modal, we only support one prompt per |web_contents|.
86 // Reject the new one if there is already one pending. See
87 // http://crbug.com/447005
88 if (pending_requests_.count(web_contents)) {
89 callback.Run(CONTENT_SETTING_ASK);
90 return;
93 // On ChromeOS, we don't use PermissionContextBase::RequestPermission() which
94 // uses the standard permission infobar/bubble UI. See http://crbug.com/454847
95 // Instead, we show the existing platform verification UI.
96 // TODO(xhwang): Remove when http://crbug.com/454847 is fixed.
97 views::Widget* widget = PlatformVerificationDialog::ShowDialog(
98 web_contents, requesting_origin,
99 base::Bind(&ProtectedMediaIdentifierPermissionContext::
100 OnPlatformVerificationConsentResponse,
101 weak_factory_.GetWeakPtr(), web_contents, id,
102 requesting_origin, embedding_origin, callback));
103 pending_requests_.insert(
104 std::make_pair(web_contents, std::make_pair(widget, id)));
105 #else
106 DCHECK(!base::CommandLine::ForCurrentProcess()->HasSwitch(
107 switches::kDisableInfobarForProtectedMediaIdentifier));
108 PermissionContextBase::RequestPermission(web_contents, id, requesting_origin,
109 user_gesture, callback);
110 #endif
113 ContentSetting ProtectedMediaIdentifierPermissionContext::GetPermissionStatus(
114 const GURL& requesting_origin,
115 const GURL& embedding_origin) const {
116 DVLOG(1) << __FUNCTION__ << ": (" << requesting_origin.spec() << ", "
117 << embedding_origin.spec() << ")";
119 if (!requesting_origin.is_valid() || !embedding_origin.is_valid() ||
120 !IsProtectedMediaIdentifierEnabled()) {
121 return CONTENT_SETTING_BLOCK;
124 ContentSetting content_setting = PermissionContextBase::GetPermissionStatus(
125 requesting_origin, embedding_origin);
126 DCHECK(content_setting == CONTENT_SETTING_ALLOW ||
127 content_setting == CONTENT_SETTING_BLOCK ||
128 content_setting == CONTENT_SETTING_ASK);
130 #if defined(OS_CHROMEOS)
131 // Check kRAConsentGranted here because it's possible that user dismissed
132 // the dialog triggered by RequestPermission() and the content setting is
133 // set to "allow" by server sync. In this case, we should still "ask".
134 if (content_setting == CONTENT_SETTING_ALLOW &&
135 !profile()->GetPrefs()->GetBoolean(prefs::kRAConsentGranted)) {
136 content_setting = CONTENT_SETTING_ASK;
138 #elif defined(OS_ANDROID)
139 // When kDisableInfobarForProtectedMediaIdentifier is enabled, do not "ask"
140 // the user and always "allow".
141 if (content_setting == CONTENT_SETTING_ASK &&
142 base::CommandLine::ForCurrentProcess()->HasSwitch(
143 switches::kDisableInfobarForProtectedMediaIdentifier)) {
144 content_setting = CONTENT_SETTING_ALLOW;
146 #endif
148 return content_setting;
151 void ProtectedMediaIdentifierPermissionContext::CancelPermissionRequest(
152 content::WebContents* web_contents,
153 const PermissionRequestID& id) {
154 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
156 #if defined(OS_CHROMEOS)
157 PendingRequestMap::iterator request = pending_requests_.find(web_contents);
158 if (request == pending_requests_.end() || !request->second.second.Equals(id))
159 return;
161 // Close the |widget_|. OnPlatformVerificationConsentResponse() will be fired
162 // during this process, but since |web_contents| is removed from
163 // |pending_requests_|, the callback will simply be dropped.
164 views::Widget* widget = request->second.first;
165 pending_requests_.erase(request);
166 widget->Close();
167 #else
168 PermissionContextBase::CancelPermissionRequest(web_contents, id);
169 #endif
172 void ProtectedMediaIdentifierPermissionContext::UpdateTabContext(
173 const PermissionRequestID& id,
174 const GURL& requesting_frame,
175 bool allowed) {
176 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
178 // WebContents may have gone away.
179 TabSpecificContentSettings* content_settings =
180 TabSpecificContentSettings::Get(id.render_process_id(),
181 id.render_view_id());
182 if (content_settings) {
183 content_settings->OnProtectedMediaIdentifierPermissionSet(
184 requesting_frame.GetOrigin(), allowed);
188 // TODO(xhwang): We should consolidate the "protected content" related pref
189 // across platforms.
190 bool ProtectedMediaIdentifierPermissionContext::
191 IsProtectedMediaIdentifierEnabled() const {
192 #if defined(OS_ANDROID)
193 if (!profile()->GetPrefs()->GetBoolean(
194 prefs::kProtectedMediaIdentifierEnabled)) {
195 DVLOG(1) << "Protected media identifier disabled by a user master switch.";
196 return false;
198 #elif defined(OS_CHROMEOS)
199 // Platform verification is not allowed in incognito or guest mode.
200 if (profile()->IsOffTheRecord() || profile()->IsGuestSession()) {
201 DVLOG(1) << "Protected media identifier disabled in incognito or guest "
202 "mode.";
203 return false;
206 // This could be disabled by the device policy or by user's master switch.
207 bool enabled_for_device = false;
208 if (!chromeos::CrosSettings::Get()->GetBoolean(
209 chromeos::kAttestationForContentProtectionEnabled,
210 &enabled_for_device) ||
211 !enabled_for_device ||
212 !profile()->GetPrefs()->GetBoolean(prefs::kEnableDRM)) {
213 DVLOG(1) << "Protected media identifier disabled by the user or by device "
214 "policy.";
215 return false;
217 #endif
219 return true;
222 #if defined(OS_CHROMEOS)
223 static void RecordRAConsentGranted(content::WebContents* web_contents) {
224 PrefService* pref_service =
225 user_prefs::UserPrefs::Get(web_contents->GetBrowserContext());
226 if (!pref_service) {
227 LOG(ERROR) << "Failed to get user prefs.";
228 return;
230 pref_service->SetBoolean(prefs::kRAConsentGranted, true);
233 void ProtectedMediaIdentifierPermissionContext::
234 OnPlatformVerificationConsentResponse(
235 content::WebContents* web_contents,
236 const PermissionRequestID& id,
237 const GURL& requesting_origin,
238 const GURL& embedding_origin,
239 const BrowserPermissionCallback& callback,
240 PlatformVerificationDialog::ConsentResponse response) {
241 // The request may have been canceled. Drop the callback in that case.
242 PendingRequestMap::iterator request = pending_requests_.find(web_contents);
243 if (request == pending_requests_.end())
244 return;
246 DCHECK(request->second.second.Equals(id));
247 pending_requests_.erase(request);
249 ContentSetting content_setting = CONTENT_SETTING_ASK;
250 bool persist = false; // Whether the ContentSetting should be saved.
251 switch (response) {
252 case PlatformVerificationDialog::CONSENT_RESPONSE_NONE:
253 content_setting = CONTENT_SETTING_ASK;
254 persist = false;
255 break;
256 case PlatformVerificationDialog::CONSENT_RESPONSE_ALLOW:
257 VLOG(1) << "Platform verification accepted by user.";
258 content::RecordAction(
259 base::UserMetricsAction("PlatformVerificationAccepted"));
260 RecordRAConsentGranted(web_contents);
261 content_setting = CONTENT_SETTING_ALLOW;
262 persist = true;
263 break;
264 case PlatformVerificationDialog::CONSENT_RESPONSE_DENY:
265 VLOG(1) << "Platform verification denied by user.";
266 content::RecordAction(
267 base::UserMetricsAction("PlatformVerificationRejected"));
268 content_setting = CONTENT_SETTING_BLOCK;
269 persist = true;
270 break;
273 NotifyPermissionSet(
274 id, requesting_origin, embedding_origin, callback,
275 persist, content_setting);
277 #endif