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 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
|
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "remoting/host/mac/permission_utils.h"
#import <AVFoundation/AVFoundation.h>
#import <Cocoa/Cocoa.h>
#include "base/apple/foundation_util.h"
#include "base/apple/scoped_cftyperef.h"
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/mac/mac_util.h"
#include "base/memory/scoped_refptr.h"
#include "base/strings/sys_string_conversions.h"
#import "base/task/sequenced_task_runner.h"
#include "base/task/sequenced_task_runner.h"
#import "base/task/single_thread_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "remoting/base/string_resources.h"
#include "ui/base/cocoa/permissions_utils.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/l10n/l10n_util_mac.h"
namespace {
constexpr int kMinDialogWidthPx = 650;
// The name of the host service as it appears in the system's Accessibility
// permission dialog.
constexpr NSString* kHostServiceName = @"ChromeRemoteDesktopHost";
void ShowAccessibilityPermissionDialog() {
NSAlert* alert = [[NSAlert alloc] init];
alert.messageText =
l10n_util::GetNSStringF(IDS_ACCESSIBILITY_PERMISSION_DIALOG_TITLE,
l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
alert.informativeText = l10n_util::GetNSStringF(
IDS_ACCESSIBILITY_PERMISSION_DIALOG_BODY_TEXT,
l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
l10n_util::GetStringUTF16(
IDS_ACCESSIBILITY_PERMISSION_DIALOG_OPEN_BUTTON),
base::SysNSStringToUTF16(kHostServiceName));
[alert
addButtonWithTitle:l10n_util::GetNSString(
IDS_ACCESSIBILITY_PERMISSION_DIALOG_OPEN_BUTTON)];
[alert addButtonWithTitle:
l10n_util::GetNSString(
IDS_ACCESSIBILITY_PERMISSION_DIALOG_NOT_NOW_BUTTON)];
// Increase the alert width so the title doesn't wrap and the body text is
// less scrunched. Note that we only want to set a min-width, we don't
// want to shrink the dialog if it is already larger than our min value.
NSWindow* alert_window = alert.window;
NSRect frame = alert_window.frame;
if (frame.size.width < kMinDialogWidthPx) {
frame.size.width = kMinDialogWidthPx;
}
[alert_window setFrame:frame display:YES];
alert.alertStyle = NSAlertStyleWarning;
[alert_window makeKeyWindow];
if ([alert runModal] == NSAlertFirstButtonReturn) {
base::mac::OpenSystemSettingsPane(
base::mac::SystemSettingsPane::kPrivacySecurity_Accessibility);
}
}
void ShowScreenRecordingPermissionDialog() {
NSAlert* alert = [[NSAlert alloc] init];
alert.messageText =
l10n_util::GetNSStringF(IDS_SCREEN_RECORDING_PERMISSION_DIALOG_TITLE,
l10n_util::GetStringUTF16(IDS_PRODUCT_NAME));
alert.informativeText = l10n_util::GetNSStringF(
IDS_SCREEN_RECORDING_PERMISSION_DIALOG_BODY_TEXT,
l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
l10n_util::GetStringUTF16(
IDS_SCREEN_RECORDING_PERMISSION_DIALOG_OPEN_BUTTON),
base::SysNSStringToUTF16(kHostServiceName));
[alert addButtonWithTitle:
l10n_util::GetNSString(
IDS_SCREEN_RECORDING_PERMISSION_DIALOG_OPEN_BUTTON)];
[alert addButtonWithTitle:
l10n_util::GetNSString(
IDS_ACCESSIBILITY_PERMISSION_DIALOG_NOT_NOW_BUTTON)];
// Increase the alert width so the title doesn't wrap and the body text is
// less scrunched. Note that we only want to set a min-width, we don't
// want to shrink the dialog if it is already larger than our min value.
NSWindow* alert_window = alert.window;
NSRect frame = alert_window.frame;
if (frame.size.width < kMinDialogWidthPx) {
frame.size.width = kMinDialogWidthPx;
}
[alert_window setFrame:frame display:YES];
alert.alertStyle = NSAlertStyleWarning;
[alert_window makeKeyWindow];
if ([alert runModal] == NSAlertFirstButtonReturn) {
base::mac::OpenSystemSettingsPane(
base::mac::SystemSettingsPane::kPrivacySecurity_ScreenRecording);
}
}
} // namespace
namespace remoting::mac {
bool CanInjectInput() {
return AXIsProcessTrusted();
}
bool CanRecordScreen() {
return ui::IsScreenCaptureAllowed();
}
void RequestScreenCapturePermission() {
ui::TryPromptUserForScreenCapture();
}
// macOS requires an additional runtime permission for injecting input using
// CGEventPost (we use this in our input injector for Mac). This method will
// request that the user enable this permission for us if they are on an
// affected version and the permission has not already been approved.
void PromptUserForAccessibilityPermissionIfNeeded(
scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
if (CanInjectInput()) {
return;
}
LOG(WARNING) << "AXIsProcessTrusted returned false, requesting "
<< "permission from user to allow input injection.";
task_runner->PostTask(FROM_HERE,
base::BindOnce(&ShowAccessibilityPermissionDialog));
}
// macOS requires an additional runtime permission for capturing the screen.
// This method will request that the user enable this permission for us if they
// are on an affected version and the permission has not already been approved.
void PromptUserForScreenRecordingPermissionIfNeeded(
scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
if (CanRecordScreen()) {
return;
}
LOG(WARNING) << "CanRecordScreen returned false, requesting permission "
<< "from user to allow screen recording.";
task_runner->PostTask(FROM_HERE,
base::BindOnce(&ShowScreenRecordingPermissionDialog));
}
void PromptUserToChangeTrustStateIfNeeded(
scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
PromptUserForAccessibilityPermissionIfNeeded(task_runner);
PromptUserForScreenRecordingPermissionIfNeeded(task_runner);
}
bool CanCaptureAudio() {
AVAuthorizationStatus auth_status =
[AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio];
return auth_status == AVAuthorizationStatusAuthorized;
}
void RequestAudioCapturePermission(base::OnceCallback<void(bool)> callback) {
auto task_runner = base::SequencedTaskRunner::GetCurrentDefault();
__block auto block_callback = std::move(callback);
[AVCaptureDevice
requestAccessForMediaType:AVMediaTypeAudio
completionHandler:^(BOOL granted) {
task_runner->PostTask(
FROM_HERE,
base::BindOnce(std::move(block_callback), granted));
}];
return;
}
} // namespace remoting::mac
|