From 7ba9fcc0e5dda352b602785cc4d987e49f241ae4 Mon Sep 17 00:00:00 2001 From: Jonathan White Date: Sun, 3 Nov 2019 23:00:03 -0500 Subject: [PATCH] macOS: Check for Auto-Type permissions on use instead of at launch * Fix #3689 - link the use of Auto-Type with the permissions required to use it --- src/autotype/AutoType.cpp | 9 +++++++ src/autotype/mac/AutoTypeMac.cpp | 30 +++++++++++++++++++--- src/gui/macutils/AppKit.h | 1 + src/gui/macutils/AppKitImpl.h | 1 + src/gui/macutils/AppKitImpl.mm | 43 ++++++++++++++++++++++++-------- src/gui/macutils/MacUtils.cpp | 5 ++++ src/gui/macutils/MacUtils.h | 1 + 7 files changed, 76 insertions(+), 14 deletions(-) diff --git a/src/autotype/AutoType.cpp b/src/autotype/AutoType.cpp index a539d0a03..299299b8c 100644 --- a/src/autotype/AutoType.cpp +++ b/src/autotype/AutoType.cpp @@ -218,6 +218,15 @@ void AutoType::executeAutoTypeActions(const Entry* entry, QWidget* hideWindow, c if (hideWindow) { #if defined(Q_OS_MACOS) + // Check for accessibility permission + if (!macUtils()->enableAccessibility()) { + MessageBox::information(nullptr, + tr("Permission Required"), + tr("KeePassXC requires the Accessibility permission in order to perform entry " + "level Auto-Type. If you already granted permission, you may have to restart " + "KeePassXC.")); + return; + } macUtils()->raiseLastActiveWindow(); m_plugin->hideOwnWindow(); #else diff --git a/src/autotype/mac/AutoTypeMac.cpp b/src/autotype/mac/AutoTypeMac.cpp index 56a07acca..fadc70e1c 100644 --- a/src/autotype/mac/AutoTypeMac.cpp +++ b/src/autotype/mac/AutoTypeMac.cpp @@ -18,6 +18,7 @@ #include "AutoTypeMac.h" #include "gui/macutils/MacUtils.h" +#include "gui/MessageBox.h" #include @@ -25,6 +26,10 @@ #define MAX_WINDOW_TITLE_LENGTH 1024 #define INVALID_KEYCODE 0xFFFF +namespace { +bool accessibilityChecked = false; +} + AutoTypePlatformMac::AutoTypePlatformMac() : m_hotkeyRef(nullptr) , m_hotkeyId({ 'kpx2', HOTKEY_ID }) @@ -33,14 +38,18 @@ AutoTypePlatformMac::AutoTypePlatformMac() eventSpec.eventClass = kEventClassKeyboard; eventSpec.eventKind = kEventHotKeyPressed; + MessageBox::initializeButtonDefs(); ::InstallApplicationEventHandler(AutoTypePlatformMac::hotkeyHandler, 1, &eventSpec, this, nullptr); } -// -// Keepassx requires mac os 10.7 -// +/** + * Determine if Auto-Type is available + * + * @return always return true + */ bool AutoTypePlatformMac::isAvailable() { + // Accessibility permissions are requested upon first use, instead of on load return true; } @@ -470,6 +479,21 @@ OSStatus AutoTypePlatformMac::hotkeyHandler(EventHandlerCallRef nextHandler, Eve { Q_UNUSED(nextHandler); + // Determine if the user has given proper permissions to KeePassXC to perform Auto-Type + if (!accessibilityChecked) { + if (macUtils()->enableAccessibility() && macUtils()->enableScreenRecording()) { + accessibilityChecked = true; + } else { + // Does not have required permissions to Auto-Type, ignore the keypress + MessageBox::information(nullptr, + tr("Permission Required"), + tr("KeePassXC requires the Accessibility and Screen Recorder permission in order to perform global " + "Auto-Type. Screen Recording is necessary to use the window title to find entries. If you " + "already granted permission, you may have to restart KeePassXC.")); + return noErr; + } + } + AutoTypePlatformMac* self = static_cast(userData); EventHotKeyID hotkeyId; diff --git a/src/gui/macutils/AppKit.h b/src/gui/macutils/AppKit.h index eaccb15a5..2bff8f5b3 100644 --- a/src/gui/macutils/AppKit.h +++ b/src/gui/macutils/AppKit.h @@ -38,6 +38,7 @@ public: bool isHidden(pid_t pid); bool isDarkMode(); bool enableAccessibility(); + bool enableScreenRecording(); signals: void lockDatabases(); diff --git a/src/gui/macutils/AppKitImpl.h b/src/gui/macutils/AppKitImpl.h index 895e7cc03..326879766 100644 --- a/src/gui/macutils/AppKitImpl.h +++ b/src/gui/macutils/AppKitImpl.h @@ -37,5 +37,6 @@ - (bool) isDarkMode; - (void) userSwitchHandler:(NSNotification*) notification; - (bool) enableAccessibility; +- (bool) enableScreenRecording; @end diff --git a/src/gui/macutils/AppKitImpl.mm b/src/gui/macutils/AppKitImpl.mm index bf9068e6d..44137ee7f 100644 --- a/src/gui/macutils/AppKitImpl.mm +++ b/src/gui/macutils/AppKitImpl.mm @@ -19,6 +19,7 @@ #import "AppKitImpl.h" #import +#import #import #if __MAC_OS_X_VERSION_MAX_ALLOWED < 101200 @@ -128,21 +129,36 @@ static const NSEventMask NSEventMaskKeyDown = NSKeyDownMask; // - (bool) enableAccessibility { - // Request a 1 pixel screenshot to trigger the permissions - // required for screen reader access. These are necessary - // for Auto-Type to find the window titles in macOS 10.15+ - CGImageRef screenshot = CGWindowListCreateImage( - CGRectMake(0, 0, 1, 1), - kCGWindowListOptionOnScreenOnly, - kCGNullWindowID, - kCGWindowImageDefault); - CFRelease(screenshot); - // Request accessibility permissions for Auto-Type type on behalf of the user NSDictionary* opts = @{static_cast(kAXTrustedCheckOptionPrompt): @YES}; return AXIsProcessTrustedWithOptions(static_cast(opts)); } +// +// Check if screen recording is enabled, may show an popup asking for permissions +// +- (bool) enableScreenRecording +{ + if (@available(macOS 10.15, *)) { + // Request screen recording permission on macOS 10.15+ + // This is necessary to get the current window title + CGDisplayStreamRef stream = CGDisplayStreamCreate(CGMainDisplayID(), 1, 1, kCVPixelFormatType_32BGRA, nil, + ^(CGDisplayStreamFrameStatus status, uint64_t displayTime, + IOSurfaceRef frameSurface, CGDisplayStreamUpdateRef updateRef) { + Q_UNUSED(status); + Q_UNUSED(displayTime); + Q_UNUSED(frameSurface); + Q_UNUSED(updateRef); + }); + if (stream) { + CFRelease(stream); + } else { + return NO; + } + } + return YES; +} + @end // @@ -198,4 +214,9 @@ bool AppKit::isDarkMode() bool AppKit::enableAccessibility() { return [static_cast(self) enableAccessibility]; -} \ No newline at end of file +} + +bool AppKit::enableScreenRecording() +{ + return [static_cast(self) enableScreenRecording]; +} diff --git a/src/gui/macutils/MacUtils.cpp b/src/gui/macutils/MacUtils.cpp index 5e6aaca11..211aaa7eb 100644 --- a/src/gui/macutils/MacUtils.cpp +++ b/src/gui/macutils/MacUtils.cpp @@ -80,3 +80,8 @@ bool MacUtils::enableAccessibility() { return m_appkit->enableAccessibility(); } + +bool MacUtils::enableScreenRecording() +{ + return m_appkit->enableScreenRecording(); +} diff --git a/src/gui/macutils/MacUtils.h b/src/gui/macutils/MacUtils.h index a895623cd..3e35994b1 100644 --- a/src/gui/macutils/MacUtils.h +++ b/src/gui/macutils/MacUtils.h @@ -39,6 +39,7 @@ public: bool isHidden(); bool isDarkMode(); bool enableAccessibility(); + bool enableScreenRecording(); signals: void lockDatabases();