summaryrefslogtreecommitdiffstats
path: root/chrome/browser/media/media_permission.cc
blob: 4ba868139af7abe64962af4d0c8c6327c4c2a6ee (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// 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;
}