blob: 4ba868139af7abe64962af4d0c8c6327c4c2a6ee [file] [log] [blame]
// Copyright 2015 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/media_permission.h"
#include "chrome/browser/media/media_capture_devices_dispatcher.h"
#include "chrome/browser/media/media_stream_device_permission_context.h"
#include "chrome/browser/media/media_stream_device_permissions.h"
#include "chrome/browser/permissions/permission_context.h"
#include "chrome/browser/permissions/permission_context_base.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/permission_manager.h"
#include "content/public/browser/permission_type.h"
#include "content/public/common/url_constants.h"
#include "extensions/common/constants.h"
namespace {
content::PermissionType ContentSettingsTypeToPermission(
ContentSettingsType content_setting) {
if (content_setting == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC) {
return content::PermissionType::AUDIO_CAPTURE;
} else {
DCHECK_EQ(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, content_setting);
return content::PermissionType::VIDEO_CAPTURE;
}
}
} // namespace
MediaPermission::MediaPermission(ContentSettingsType content_type,
bool is_insecure_pepper_request,
const GURL& requesting_origin,
const GURL& embedding_origin,
Profile* profile)
: content_type_(content_type),
is_insecure_pepper_request_(is_insecure_pepper_request),
requesting_origin_(requesting_origin),
embedding_origin_(embedding_origin),
profile_(profile) {}
ContentSetting MediaPermission::GetPermissionStatus(
content::MediaStreamRequestResult* denial_reason) const {
// Deny the request if the security origin is empty, this happens with
// file access without |--allow-file-access-from-files| flag.
if (requesting_origin_.is_empty()) {
*denial_reason = content::MEDIA_DEVICE_INVALID_SECURITY_ORIGIN;
return CONTENT_SETTING_BLOCK;
}
// Use the Permission Context to find out if the kill switch is on. Set the
// denial reason to kill switch.
content::PermissionType permission_type =
ContentSettingsTypeToPermission(content_type_);
PermissionContextBase* permission_context =
PermissionContext::Get(profile_, permission_type);
if (!permission_context) {
*denial_reason = content::MEDIA_DEVICE_PERMISSION_DENIED;
return CONTENT_SETTING_BLOCK;
}
MediaStreamDevicePermissionContext* media_device_permission_context =
static_cast<MediaStreamDevicePermissionContext*>(permission_context);
if (media_device_permission_context->IsPermissionKillSwitchOn()) {
*denial_reason = content::MEDIA_DEVICE_KILL_SWITCH_ON;
return CONTENT_SETTING_BLOCK;
}
// Check policy and content settings.
ContentSetting result =
GetStoredContentSetting(media_device_permission_context);
if (result == CONTENT_SETTING_BLOCK)
*denial_reason = content::MEDIA_DEVICE_PERMISSION_DENIED;
return result;
}
ContentSetting MediaPermission::GetPermissionStatusWithDeviceRequired(
const std::string& device_id,
content::MediaStreamRequestResult* denial_reason) const {
// Deny the request if there is no device attached to the OS of the requested
// type.
if (!HasAvailableDevices(device_id)) {
*denial_reason = content::MEDIA_DEVICE_NO_HARDWARE;
return CONTENT_SETTING_BLOCK;
}
return GetPermissionStatus(denial_reason);
}
ContentSetting MediaPermission::GetStoredContentSetting(
MediaStreamDevicePermissionContext* media_device_permission_context) const {
if (is_insecure_pepper_request_) {
return media_device_permission_context
->GetPermissionStatusAllowingInsecureForPepper(requesting_origin_,
embedding_origin_);
} else {
return media_device_permission_context->GetPermissionStatus(
requesting_origin_, embedding_origin_);
}
}
bool MediaPermission::HasAvailableDevices(const std::string& device_id) const {
const content::MediaStreamDevices* devices = nullptr;
if (content_type_ == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC) {
devices =
&MediaCaptureDevicesDispatcher::GetInstance()->GetAudioCaptureDevices();
} else if (content_type_ == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA) {
devices =
&MediaCaptureDevicesDispatcher::GetInstance()->GetVideoCaptureDevices();
} else {
NOTREACHED();
}
// TODO(tommi): It's kind of strange to have this here since if we fail this
// test, there'll be a UI shown that indicates to the user that access to
// non-existing audio/video devices has been denied. The user won't have
// any way to change that but there will be a UI shown which indicates that
// access is blocked.
if (devices->empty())
return false;
// Note: we check device_id before dereferencing devices. If the requested
// device id is non-empty, then the corresponding device list must not be
// NULL.
if (!device_id.empty() && !devices->FindById(device_id))
return false;
return true;
}