blob: 3ef58c85b500a619821eab9d88b2a9166e588769 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/media/protected_media_identifier_permission_context.h"
#include "base/command_line.h"
#include "base/metrics/user_metrics.h"
#include "build/build_config.h"
#include "chrome/browser/content_settings/tab_specific_content_settings.h"
#include "chrome/browser/permissions/permission_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#if defined(OS_CHROMEOS)
#include <utility>
#include "chrome/browser/chromeos/attestation/platform_verification_dialog.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chromeos/chromeos_switches.h"
#include "chromeos/settings/cros_settings_names.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/user_prefs/user_prefs.h"
#include "ui/views/widget/widget.h"
#elif !defined(OS_ANDROID)
#error This file currently only supports Chrome OS and Android.
#endif
#if defined(OS_CHROMEOS)
using chromeos::attestation::PlatformVerificationDialog;
#endif
ProtectedMediaIdentifierPermissionContext::
ProtectedMediaIdentifierPermissionContext(Profile* profile)
: PermissionContextBase(profile,
CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER)
#if defined(OS_CHROMEOS)
,
weak_factory_(this)
#endif
{
}
ProtectedMediaIdentifierPermissionContext::
~ProtectedMediaIdentifierPermissionContext() {
}
#if defined(OS_CHROMEOS)
void ProtectedMediaIdentifierPermissionContext::DecidePermission(
content::WebContents* web_contents,
const PermissionRequestID& id,
const GURL& requesting_origin,
const GURL& embedding_origin,
bool user_gesture,
const BrowserPermissionCallback& callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// Since the dialog is modal, we only support one prompt per |web_contents|.
// Reject the new one if there is already one pending. See
// http://crbug.com/447005
if (pending_requests_.count(web_contents)) {
callback.Run(CONTENT_SETTING_ASK);
return;
}
// On ChromeOS, we don't use PermissionContextBase::RequestPermission() which
// uses the standard permission infobar/bubble UI. See http://crbug.com/454847
// Instead, we show the existing platform verification UI.
// TODO(xhwang): Remove when http://crbug.com/454847 is fixed.
views::Widget* widget = PlatformVerificationDialog::ShowDialog(
web_contents, requesting_origin,
base::Bind(&ProtectedMediaIdentifierPermissionContext::
OnPlatformVerificationConsentResponse,
weak_factory_.GetWeakPtr(), web_contents, id,
requesting_origin, embedding_origin, callback));
pending_requests_.insert(
std::make_pair(web_contents, std::make_pair(widget, id)));
}
#endif // defined(OS_CHROMEOS)
ContentSetting
ProtectedMediaIdentifierPermissionContext::GetPermissionStatusInternal(
content::RenderFrameHost* render_frame_host,
const GURL& requesting_origin,
const GURL& embedding_origin) const {
DVLOG(1) << __func__ << ": (" << requesting_origin.spec() << ", "
<< embedding_origin.spec() << ")";
if (!requesting_origin.is_valid() || !embedding_origin.is_valid() ||
!IsProtectedMediaIdentifierEnabled()) {
return CONTENT_SETTING_BLOCK;
}
ContentSetting content_setting =
PermissionContextBase::GetPermissionStatusInternal(
render_frame_host, requesting_origin, embedding_origin);
DCHECK(content_setting == CONTENT_SETTING_ALLOW ||
content_setting == CONTENT_SETTING_BLOCK ||
content_setting == CONTENT_SETTING_ASK);
return content_setting;
}
void ProtectedMediaIdentifierPermissionContext::CancelPermissionRequest(
content::WebContents* web_contents,
const PermissionRequestID& id) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
#if defined(OS_CHROMEOS)
PendingRequestMap::iterator request = pending_requests_.find(web_contents);
if (request == pending_requests_.end() || (request->second.second != id))
return;
views::Widget* widget = request->second.first;
pending_requests_.erase(request);
// If |web_contents| is being destroyed, |widget| could be invalid. No need to
// manually close it here. Otherwise, close the |widget| here.
// OnPlatformVerificationConsentResponse() will be fired during this process,
// but since |web_contents| is removed from |pending_requests_|, the callback
// will simply be dropped.
if (!web_contents->IsBeingDestroyed())
widget->Close();
#else
PermissionContextBase::CancelPermissionRequest(web_contents, id);
#endif
}
void ProtectedMediaIdentifierPermissionContext::UpdateTabContext(
const PermissionRequestID& id,
const GURL& requesting_frame,
bool allowed) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// WebContents may have gone away.
TabSpecificContentSettings* content_settings =
TabSpecificContentSettings::GetForFrame(id.render_process_id(),
id.render_frame_id());
if (content_settings) {
content_settings->OnProtectedMediaIdentifierPermissionSet(
requesting_frame.GetOrigin(), allowed);
}
}
bool ProtectedMediaIdentifierPermissionContext::IsRestrictedToSecureOrigins()
const {
// EME is not supported on insecure origins, see https://goo.gl/Ks5zf7
// Note that origins whitelisted by --unsafely-treat-insecure-origin-as-secure
// flag will be treated as "secure" so they will not be affected.
return true;
}
// TODO(xhwang): We should consolidate the "protected content" related pref
// across platforms.
bool ProtectedMediaIdentifierPermissionContext::
IsProtectedMediaIdentifierEnabled() const {
#if defined(OS_CHROMEOS)
// Platform verification is not allowed in incognito or guest mode.
if (profile()->IsOffTheRecord() || profile()->IsGuestSession()) {
DVLOG(1) << "Protected media identifier disabled in incognito or guest "
"mode.";
return false;
}
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(chromeos::switches::kSystemDevMode) &&
!command_line->HasSwitch(chromeos::switches::kAllowRAInDevMode)) {
DVLOG(1) << "Protected media identifier disabled in dev mode.";
return false;
}
// This could be disabled by the device policy or by user's master switch.
bool enabled_for_device = false;
if (!chromeos::CrosSettings::Get()->GetBoolean(
chromeos::kAttestationForContentProtectionEnabled,
&enabled_for_device) ||
!enabled_for_device ||
!profile()->GetPrefs()->GetBoolean(prefs::kEnableDRM)) {
DVLOG(1) << "Protected media identifier disabled by the user or by device "
"policy.";
return false;
}
#endif
return true;
}
#if defined(OS_CHROMEOS)
void ProtectedMediaIdentifierPermissionContext::
OnPlatformVerificationConsentResponse(
content::WebContents* web_contents,
const PermissionRequestID& id,
const GURL& requesting_origin,
const GURL& embedding_origin,
const BrowserPermissionCallback& callback,
PlatformVerificationDialog::ConsentResponse response) {
// The request may have been canceled. Drop the callback in that case.
PendingRequestMap::iterator request = pending_requests_.find(web_contents);
if (request == pending_requests_.end())
return;
DCHECK(request->second.second == id);
pending_requests_.erase(request);
ContentSetting content_setting = CONTENT_SETTING_ASK;
bool persist = false; // Whether the ContentSetting should be saved.
switch (response) {
case PlatformVerificationDialog::CONSENT_RESPONSE_NONE:
VLOG(1) << "Platform verification dismissed by user.";
content_setting = CONTENT_SETTING_ASK;
persist = false;
break;
case PlatformVerificationDialog::CONSENT_RESPONSE_ALLOW:
VLOG(1) << "Platform verification accepted by user.";
base::RecordAction(
base::UserMetricsAction("PlatformVerificationAccepted"));
content_setting = CONTENT_SETTING_ALLOW;
persist = true;
break;
case PlatformVerificationDialog::CONSENT_RESPONSE_DENY:
VLOG(1) << "Platform verification denied by user.";
base::RecordAction(
base::UserMetricsAction("PlatformVerificationRejected"));
content_setting = CONTENT_SETTING_BLOCK;
persist = true;
break;
}
NotifyPermissionSet(
id, requesting_origin, embedding_origin, callback,
persist, content_setting);
}
#endif