Commit bd309847 authored by Guido Urdaneta's avatar Guido Urdaneta Committed by Commit Bot

Check system permissions for screen capture in macOS Catalina

New system-level permissions for screen capture have been introduced in macOS 10.15.
This CL adds checks for this new permission for getDisplayMedia() and
the chooseDesktopMedia() extension API. Calls fail screen capture is
requested but permission has not been given.

There is no API to check this permission, but it can be done indirectly
using other system APIs. This CL uses a heuristic proposed at
https://crbug.com/993692#c3.

Bug: 993692
Change-Id: I2b6b76f22f3aa800eb54b37c7c89c6b28536a632
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1776056Reviewed-by: default avatarRobert Sesek <rsesek@chromium.org>
Reviewed-by: default avatarMarina Ciocea <marinaciocea@chromium.org>
Commit-Queue: Guido Urdaneta <guidou@chromium.org>
Cr-Commit-Position: refs/heads/master@{#693111}
parent 8b2addc4
......@@ -74,6 +74,7 @@ Andrei Parvu <andrei.prv@gmail.com>
Andrei Parvu <parvu@adobe.com>
Andrew Boyarshin <andrew.boyarshin@gmail.com>
Andrew Brampton <me@bramp.net>
Andrew Brindamour <abrindamour@bluejeans.com>
Andrew Hung <andrhung@amazon.com>
Andrew Jorgensen <ajorgens@amazon.com>
Andrew MacPherson <andrew.macpherson@soundtrap.com>
......@@ -421,6 +422,7 @@ Jianjun Zhu <jianjun.zhu@intel.com>
Jianneng Zhong <muzuiget@gmail.com>
Jiawei Shao <jiawei.shao@intel.com>
Jie Chen <jie.a.chen@intel.com>
Jihan Chao <jihan@bluejeans.com>
Jihoon Chung <j.c@navercorp.com>
Jihoon Chung <jihoon@gmail.com>
Jihun Brent Kim <devgrapher@gmail.com>
......
......@@ -55,6 +55,10 @@
#include "ui/base/ui_base_features.h"
#endif // defined(OS_CHROMEOS)
#if defined(OS_MACOSX)
#include "chrome/browser/media/webrtc/system_media_capture_permissions_mac.h"
#endif // defined(OS_MACOSX)
using content::BrowserThread;
namespace {
......@@ -308,6 +312,16 @@ void DesktopCaptureAccessHandler::HandleRequest(
// If the device id wasn't specified then this is a screen capture request
// (i.e. chooseDesktopMedia() API wasn't used to generate device id).
if (request.requested_video_device_id.empty()) {
#if defined(OS_MACOSX)
if (system_media_permissions::CheckSystemScreenCapturePermission() !=
system_media_permissions::SystemPermission::kAllowed) {
std::move(callback).Run(
blink::MediaStreamDevices(),
blink::mojom::MediaStreamRequestResult::SYSTEM_PERMISSION_DENIED,
nullptr);
return;
}
#endif
ProcessScreenCaptureAccessRequest(web_contents, request,
std::move(callback), extension);
return;
......@@ -340,6 +354,17 @@ void DesktopCaptureAccessHandler::HandleRequest(
std::move(ui));
return;
}
#if defined(OS_MACOSX)
if (media_id.type != content::DesktopMediaID::TYPE_WEB_CONTENTS &&
system_media_permissions::CheckSystemScreenCapturePermission() !=
system_media_permissions::SystemPermission::kAllowed) {
std::move(callback).Run(
blink::MediaStreamDevices(),
blink::mojom::MediaStreamRequestResult::SYSTEM_PERMISSION_DENIED,
nullptr);
return;
}
#endif
bool loopback_audio_supported = false;
#if defined(USE_CRAS) || defined(OS_WIN)
......
......@@ -25,6 +25,10 @@
#include "content/public/browser/web_contents.h"
#include "third_party/blink/public/mojom/mediastream/media_stream.mojom-shared.h"
#if defined(OS_MACOSX)
#include "chrome/browser/media/webrtc/system_media_capture_permissions_mac.h"
#endif
// Holds pending request information so that we display one picker UI at a time
// for each content::WebContents.
struct DisplayMediaAccessHandler::PendingAccessRequest {
......@@ -198,15 +202,27 @@ void DisplayMediaAccessHandler::OnPickerDialogResults(
request_result = blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED;
} else {
request_result = blink::mojom::MediaStreamRequestResult::OK;
const auto& visible_url = url_formatter::FormatUrlForSecurityDisplay(
web_contents->GetLastCommittedURL(),
url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC);
ui = GetDevicesForDesktopCapture(
web_contents, &devices, media_id,
blink::mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE,
blink::mojom::MediaStreamType::DISPLAY_AUDIO_CAPTURE,
media_id.audio_share, false /* disable_local_echo */,
display_notification_, visible_url, visible_url);
#if defined(OS_MACOSX)
// Check screen capture permissions on Mac if necessary.
if ((media_id.type == content::DesktopMediaID::TYPE_SCREEN ||
media_id.type == content::DesktopMediaID::TYPE_WINDOW) &&
system_media_permissions::CheckSystemScreenCapturePermission() !=
system_media_permissions::SystemPermission::kAllowed) {
request_result =
blink::mojom::MediaStreamRequestResult::PERMISSION_DENIED;
}
#endif
if (request_result == blink::mojom::MediaStreamRequestResult::OK) {
const auto& visible_url = url_formatter::FormatUrlForSecurityDisplay(
web_contents->GetLastCommittedURL(),
url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC);
ui = GetDevicesForDesktopCapture(
web_contents, &devices, media_id,
blink::mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE,
blink::mojom::MediaStreamType::DISPLAY_AUDIO_CAPTURE,
media_id.audio_share, false /* disable_local_echo */,
display_notification_, visible_url, visible_url);
}
}
std::move(pending_request.callback)
......
......@@ -31,6 +31,11 @@ enum class SystemPermission {
SystemPermission CheckSystemAudioCapturePermission();
SystemPermission CheckSystemVideoCapturePermission();
// On 10.15 and above: returns the system permission.
// On 10.14 and below: returns |SystemPermission::kAllowed|, since there are no
// system screen capture permissions.
SystemPermission CheckSystemScreenCapturePermission();
// On 10.14 and above: requests system permission and returns. When requesting
// permission, the OS will show a user dialog and respond asynchronously. At the
// response, |callback| is posted with |traits|.
......
......@@ -23,6 +23,8 @@
#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "base/mac/foundation_util.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/macros.h"
#include "base/no_destructor.h"
#include "base/task/post_task.h"
......@@ -161,6 +163,27 @@ void RequestSystemMediaCapturePermission(NSString* media_type,
}
}
// Heuristic to check screen capture permission on macOS 10.15.
// See https://crbug.com/993692#c3.
bool IsScreenCaptureAllowed() {
if (@available(macOS 10.15, *)) {
base::ScopedCFTypeRef<CFArrayRef> window_list(CGWindowListCopyWindowInfo(
kCGWindowListOptionOnScreenOnly, kCGNullWindowID));
NSUInteger num_windows = CFArrayGetCount(window_list);
NSUInteger num_windows_with_name = 0;
for (NSDictionary* dict in base::mac::CFToNSCast(window_list.get())) {
if ([dict objectForKey:base::mac::CFToNSCast(kCGWindowName)]) {
num_windows_with_name++;
} else {
// No kCGWindowName detected implies no permission.
break;
}
}
return num_windows == num_windows_with_name;
}
return true;
}
} // namespace
SystemPermission CheckSystemAudioCapturePermission() {
......@@ -171,6 +194,11 @@ SystemPermission CheckSystemVideoCapturePermission() {
return CheckSystemMediaCapturePermission(AVMediaTypeVideo);
}
SystemPermission CheckSystemScreenCapturePermission() {
return IsScreenCaptureAllowed() ? SystemPermission::kAllowed
: SystemPermission::kDenied;
}
void RequestSystemAudioCapturePermisson(base::OnceClosure callback,
const base::TaskTraits& traits) {
RequestSystemMediaCapturePermission(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment