Moved accessibilty permission checks into MPAutotypeDoctor. Added screen capture permission test.

This commit is contained in:
Michael Starke
2019-07-03 17:28:58 +02:00
parent 2e523f6018
commit b1cb776e14
9 changed files with 173 additions and 77 deletions

View File

@@ -35,6 +35,7 @@
4C17F109184E6B6C00E85625 /* 30_TerminalTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 4C17F107184E6B6C00E85625 /* 30_TerminalTemplate.pdf */; };
4C1BDF2B1E4392640012A3F0 /* MPPluginDataViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C1BDF291E4392640012A3F0 /* MPPluginDataViewController.m */; };
4C1E9885185F71A800943563 /* MPContextBarViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C1E9884185F71A800943563 /* MPContextBarViewController.m */; };
4C1ECAE322CCD30F00F46069 /* MPAutotypeDoctor.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C1ECAE222CCD30F00F46069 /* MPAutotypeDoctor.m */; };
4C1F7FA21E3A12E600D6A40E /* MPModifiedKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C1F7FA11E3A12E600D6A40E /* MPModifiedKey.m */; };
4C1FA07B18231900003A3F8C /* MPDocument+Autotype.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C1FA07A18231900003A3F8C /* MPDocument+Autotype.m */; };
4C224B4217DFCB2400FF6AEE /* MPNumericalInputFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C224B4117DFCB2400FF6AEE /* MPNumericalInputFormatter.m */; };
@@ -394,6 +395,8 @@
4C1D56382271F4BC00C3E594 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/PluginRepositoryBrowserView.strings; sourceTree = "<group>"; };
4C1E9883185F71A800943563 /* MPContextBarViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPContextBarViewController.h; sourceTree = "<group>"; };
4C1E9884185F71A800943563 /* MPContextBarViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPContextBarViewController.m; sourceTree = "<group>"; };
4C1ECAE122CCD30F00F46069 /* MPAutotypeDoctor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPAutotypeDoctor.h; sourceTree = "<group>"; };
4C1ECAE222CCD30F00F46069 /* MPAutotypeDoctor.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPAutotypeDoctor.m; sourceTree = "<group>"; };
4C1F7FA01E3A12E600D6A40E /* MPModifiedKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPModifiedKey.h; sourceTree = "<group>"; };
4C1F7FA11E3A12E600D6A40E /* MPModifiedKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPModifiedKey.m; sourceTree = "<group>"; };
4C1FA07A18231900003A3F8C /* MPDocument+Autotype.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MPDocument+Autotype.m"; sourceTree = "<group>"; };
@@ -1534,6 +1537,8 @@
4C3499FF218852160055AF45 /* MPKeyTyper.m */,
4C1F7FA01E3A12E600D6A40E /* MPModifiedKey.h */,
4C1F7FA11E3A12E600D6A40E /* MPModifiedKey.m */,
4C1ECAE122CCD30F00F46069 /* MPAutotypeDoctor.h */,
4C1ECAE222CCD30F00F46069 /* MPAutotypeDoctor.m */,
);
name = Autotype;
sourceTree = "<group>";
@@ -1990,6 +1995,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
4C1ECAE322CCD30F00F46069 /* MPAutotypeDoctor.m in Sources */,
4CD034AC1BFE113B003C002C /* MPPluginHost.m in Sources */,
4C77E37315B84A240093A587 /* main.m in Sources */,
4C0F04402147A6FA000B8568 /* MPCustomFieldTableView.m in Sources */,

View File

@@ -26,29 +26,28 @@
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customView translatesAutoresizingMaskIntoConstraints="NO" id="1">
<rect key="frame" x="0.0" y="0.0" width="400" height="463"/>
<rect key="frame" x="0.0" y="0.0" width="400" height="421"/>
<subviews>
<box autoresizesSubviews="NO" verticalHuggingPriority="500" borderType="line" title="Autotype" translatesAutoresizingMaskIntoConstraints="NO" id="P9N-HM-wER">
<rect key="frame" x="17" y="115" width="366" height="328"/>
<rect key="frame" x="17" y="115" width="366" height="286"/>
<view key="contentView" id="faU-Ok-HJ3">
<rect key="frame" x="3" y="3" width="360" height="310"/>
<rect key="frame" x="3" y="3" width="360" height="268"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<stackView orientation="vertical" alignment="leading" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" translatesAutoresizingMaskIntoConstraints="NO" id="j52-9L-k7c">
<rect key="frame" x="16" y="17" width="328" height="283"/>
<rect key="frame" x="16" y="17" width="328" height="241"/>
<beginningViews>
<textField verticalHuggingPriority="750" fixedFrame="YES" preferredMaxLayoutWidth="328" translatesAutoresizingMaskIntoConstraints="NO" id="hMJ-Mo-xOM">
<rect key="frame" x="-2" y="227" width="332" height="56"/>
<textFieldCell key="cell" controlSize="small" id="H37-ku-aTc">
<rect key="frame" x="-2" y="227" width="150" height="14"/>
<textFieldCell key="cell" controlSize="small" title="ReportFromAutotypeDoctor" id="H37-ku-aTc">
<font key="font" metaFont="smallSystem"/>
<string key="title">Autotype is not available, because MacPass is not allowed to control your computer. To enable Autotype, go to the Security and Privacy Preferences and add MacPass to the Accessibilty group. Changes require a restart of MacPass.</string>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="jai-b6-Qv4">
<rect key="frame" x="-6" y="191" width="160" height="32"/>
<buttonCell key="cell" type="push" title="Open Preferences…" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="NP0-R3-m6n">
<rect key="frame" x="-6" y="191" width="177" height="32"/>
<buttonCell key="cell" type="push" title="Run Autotype Doctor…" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="NP0-R3-m6n">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>

View File

@@ -370,10 +370,6 @@ typedef NS_OPTIONS(NSInteger, MPAppStartupState) {
if(showWelcomeScreen) {
[self showWelcomeWindow];
}
/* run check for accessibilty after the windowserver should have presented the UI */
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[MPAutotypeDaemon.defaultDaemon checkForAccessibiltyPermissions];
});
}
@end

View File

@@ -35,13 +35,9 @@
@property (weak) IBOutlet NSPopUpButton *matchSelectionButton;
@property (readonly, strong) DDHotKey *registredHotKey;
@property (readonly, strong, class) MPAutotypeDaemon *defaultDaemon;
@property (nonatomic, readonly) BOOL autotypeSupported; // YES if the system allows for Autotype. NO if the user has denied this.
- (instancetype)init NS_UNAVAILABLE;
- (void)checkForAccessibiltyPermissions;
- (void)openAccessibiltyPreferences;
- (void)performAutotypeForEntry:(KPKEntry *)entry;
- (void)performAutotypeForEntry:(KPKEntry *)entry overrideSequence:(NSString *)sequence;
- (void)selectAutotypeCandiate:(MPAutotypeContext *)context;

View File

@@ -31,6 +31,7 @@
#import "MPSettingsHelper.h"
#import "MPAutotypeCandidateSelectionViewController.h"
#import "MPUserNotificationCenterDelegate.h"
#import "MPAutotypeDoctor.h"
#import "MPPluginHost.h"
#import "MPPlugin.h"
@@ -57,12 +58,11 @@ NSString *const kMPProcessIdentifierKey = @"kMPProcessIdentifierKey";
@property (strong) NSRunningApplication *previousApplication; // The application that was active before we got invoked
@property (assign) NSTimeInterval userActionRequested;
@property (strong) id applicationActivationObserver;
@property BOOL shouldRunAutotypeDoctor;
@end
@implementation MPAutotypeDaemon
@dynamic autotypeSupported;
#pragma mark -
#pragma mark Lifecylce
@@ -87,6 +87,8 @@ static MPAutotypeDaemon *_sharedInstance;
_enabled = NO;
_targetPID = -1;
_userActionRequested = NSDate.distantPast.timeIntervalSinceReferenceDate;
_shouldRunAutotypeDoctor = NO;
BOOL test = MPAutotypeDoctor.defaultDoctor.hasScreenRecordingPermissions;
[self bind:NSStringFromSelector(@selector(enabled))
toObject:NSUserDefaultsController.sharedUserDefaultsController
withKeyPath:[MPSettingsHelper defaultControllerPathForKey:kMPSettingsKeyEnableGlobalAutotype]
@@ -117,13 +119,6 @@ static MPAutotypeDaemon *_sharedInstance;
#pragma mark -
#pragma mark Properties
- (BOOL)autotypeSupported {
if(@available(macOS 10.14, *)) {
return AXIsProcessTrusted();
}
/* macOS 10.13 and lower allows us to send key events regardless of accessibilty trust */
return YES;
}
- (void)setEnabled:(BOOL)enabled {
if(_enabled != enabled) {
@@ -142,52 +137,6 @@ static MPAutotypeDaemon *_sharedInstance;
}
}
- (void)checkForAccessibiltyPermissions {
if(!self.enabled) {
return;
}
if(NSApplication.sharedApplication.isRunningTests) {
return; // Do not display pop-up when running tests
}
BOOL hideAlert = NO;
if(nil != [NSUserDefaults.standardUserDefaults objectForKey:kMPSettingsKeyAutotypeHideAccessibiltyWarning]) {
hideAlert = [NSUserDefaults.standardUserDefaults boolForKey:kMPSettingsKeyAutotypeHideAccessibiltyWarning];
}
if(hideAlert || self.autotypeSupported) {
return;
}
else {
NSAlert *alert = [[NSAlert alloc] init];
alert.alertStyle = NSWarningAlertStyle;
alert.messageText = NSLocalizedString(@"ALERT_AUTOTYPE_MISSING_ACCESSIBILTY_PERMISSIONS_MESSAGE_TEXT", @"Alert message displayed when Autotype performs self check and lacks accessibilty permissions");
alert.informativeText = NSLocalizedString(@"ALERT_AUTOTYPE_MISSING_ACCESSIBILTY_PERMISSIONS_INFORMATIVE_TEXT", @"Alert informative text displayed when Autotype performs self check and lacks accessibilty permissions");
alert.showsSuppressionButton = YES;
[alert addButtonWithTitle:NSLocalizedString(@"ALERT_AUTOTYPE_MISSING_ACCESSIBILTY_PERMISSIONS_BUTTON_OK", @"Button in dialog to leave autotype disabled and continiue!")];
[alert addButtonWithTitle:NSLocalizedString(@"ALERT_AUTOTYPE_MISSING_ACCESSIBILTY_PERMISSIONS_BUTTON_OPEN_PREFERENCES", @"Button in dialog to open accessibilty preferences pane!")];
NSModalResponse returnCode = [alert runModal];
BOOL suppressWarning = (alert.suppressionButton.state == NSOnState);
[NSUserDefaults.standardUserDefaults setBool:suppressWarning forKey:kMPSettingsKeyAutotypeHideAccessibiltyWarning];
switch(returnCode) {
case NSAlertFirstButtonReturn: {
/* ok, ignore */
break;
}
case NSAlertSecondButtonReturn:
/* open prefs */
[self openAccessibiltyPreferences];
break;
default:
break;
}
}
}
- (void)openAccessibiltyPreferences {
[NSWorkspace.sharedWorkspace openURL:[NSURL URLWithString:@"x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility"]];
}
#pragma mark -
#pragma mark Autotype Invocation
- (void)performAutotypeForEntry:(KPKEntry *)entry {
@@ -225,6 +174,10 @@ static MPAutotypeDaemon *_sharedInstance;
#pragma mark Autotype Execution
- (void)_performAutotypeForEntry:(KPKEntry *)entryOrNil {
if(self.shouldRunAutotypeDoctor) {
[MPAutotypeDoctor.defaultDoctor showPermissionCheckReport];
}
/*if(!self.autotypeSupported) {
NSUserNotification *notification = [[NSUserNotification alloc] init];
notification.title = NSApp.applicationName;

View File

@@ -0,0 +1,31 @@
//
// MPAutotypeDoctor.h
// MacPass
//
// Created by Michael Starke on 03.07.19.
// Copyright © 2019 HicknHack Software GmbH. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
typedef NS_OPTIONS(NSUInteger, MPAutotypeIssue) {
MPAutotypeIssueNoAccessibiltyPermission,
MPAutotypeIssueNoScreenRecordingPermission
};
@interface MPAutotypeDoctor : NSObject
@property (class, readonly, strong) MPAutotypeDoctor *defaultDoctor;
@property (nonatomic, readonly) BOOL hasAccessibiltyPermissions; // 10.14 requires accessibilty access to send key strokes to other applications
@property (nonatomic, readonly) BOOL hasScreenRecordingPermissions; // 10.15 requires screen recording permissions to get window names from other processes
@property (nonatomic, readonly, copy) NSString *localizedErrorDescription; // If any issues are present, this property holds alocalized error description
- (BOOL)checkPermissionsWithoutUserFeedback;
- (void)showPermissionCheckReport;
@end
NS_ASSUME_NONNULL_END

114
MacPass/MPAutotypeDoctor.m Normal file
View File

@@ -0,0 +1,114 @@
//
// MPAutotypeDoctor.m
// MacPass
//
// Created by Michael Starke on 03.07.19.
// Copyright © 2019 HicknHack Software GmbH. All rights reserved.
//
#import "MPAutotypeDoctor.h"
#import "MPSettingsHelper.h"
#import "NSApplication+MPAdditions.h"
@interface MPAutotypeDoctor ()
@end
@implementation MPAutotypeDoctor
+ (MPAutotypeDoctor *)defaultDoctor {
static MPAutotypeDoctor *instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instance = [[MPAutotypeDoctor alloc] init];
});
return instance;
}
- (BOOL)hasScreenRecordingPermissions {
/* macos 10.14 and lower do not require screen recording permission to get window titles */
if(@available(macos 10.15, *)) {
/*
To minimize the intrusion just make a 1px image of the upper left corner
This way there is no possibilty to access any private data
*/
CGImageRef screenshot = CGWindowListCreateImage(
CGRectMake(0, 0, 1, 1),
kCGWindowListOptionOnScreenOnly,
kCGNullWindowID,
kCGWindowImageDefault);
if(!screenshot) {
return NO;
}
}
return YES;
}
- (BOOL)hasAccessibiltyPermissions {
if(@available(macOS 10.14, *)) {
return AXIsProcessTrusted();
}
/* macOS 10.13 and lower allows us to send key events regardless of accessibilty trust */
return YES;
}
- (NSString *)localizedErrorDescription {
return @"TODO";
}
- (void)showPermissionCheckReport {
// TODO
}
- (BOOL)checkPermissionsWithoutUserFeedback {
// TODO
return YES;
}
- (void)checkForAccessibiltyPermissions {
if(NSApplication.sharedApplication.isRunningTests) {
return; // Do not display pop-up when running tests
}
BOOL hideAlert = NO;
if(nil != [NSUserDefaults.standardUserDefaults objectForKey:kMPSettingsKeyAutotypeHideAccessibiltyWarning]) {
hideAlert = [NSUserDefaults.standardUserDefaults boolForKey:kMPSettingsKeyAutotypeHideAccessibiltyWarning];
}
if(hideAlert || self.hasAccessibiltyPermissions) {
return;
}
else {
NSAlert *alert = [[NSAlert alloc] init];
alert.alertStyle = NSWarningAlertStyle;
alert.messageText = NSLocalizedString(@"ALERT_AUTOTYPE_MISSING_ACCESSIBILTY_PERMISSIONS_MESSAGE_TEXT", @"Alert message displayed when Autotype performs self check and lacks accessibilty permissions");
alert.informativeText = NSLocalizedString(@"ALERT_AUTOTYPE_MISSING_ACCESSIBILTY_PERMISSIONS_INFORMATIVE_TEXT", @"Alert informative text displayed when Autotype performs self check and lacks accessibilty permissions");
alert.showsSuppressionButton = YES;
[alert addButtonWithTitle:NSLocalizedString(@"ALERT_AUTOTYPE_MISSING_ACCESSIBILTY_PERMISSIONS_BUTTON_OK", @"Button in dialog to leave autotype disabled and continiue!")];
[alert addButtonWithTitle:NSLocalizedString(@"ALERT_AUTOTYPE_MISSING_ACCESSIBILTY_PERMISSIONS_BUTTON_OPEN_PREFERENCES", @"Button in dialog to open accessibilty preferences pane!")];
NSModalResponse returnCode = [alert runModal];
BOOL suppressWarning = (alert.suppressionButton.state == NSOnState);
[NSUserDefaults.standardUserDefaults setBool:suppressWarning forKey:kMPSettingsKeyAutotypeHideAccessibiltyWarning];
switch(returnCode) {
case NSAlertFirstButtonReturn: {
/* ok, ignore */
break;
}
case NSAlertSecondButtonReturn:
/* open prefs */
[self openAccessibiltyPreferences];
break;
default:
break;
}
}
}
- (void)openAccessibiltyPreferences {
[NSWorkspace.sharedWorkspace openURL:[NSURL URLWithString:@"x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility"]];
}
- (void)checkForWindowTitlePermissions {
}
@end

View File

@@ -23,7 +23,7 @@
#import "MPIntegrationPreferencesController.h"
#import "MPSettingsHelper.h"
#import "MPIconHelper.h"
#import "MPAutotypeDaemon.h"
#import "MPAutotypeDoctor.h"
#import "DDHotKeyCenter.h"
#import "DDHotKey+MacPassAdditions.h"
@@ -105,7 +105,8 @@
}
- (void)_updateAccessabilityWarning {
BOOL hasAutotypeSupport = MPAutotypeDaemon.defaultDaemon.autotypeSupported;
BOOL hasAutotypeSupport = MPAutotypeDoctor.defaultDoctor.hasAccessibiltyPermissions;
if(hasAutotypeSupport) {
[self.autotypeStackView setVisibilityPriority:NSStackViewVisibilityPriorityNotVisible forView:self.autotypeWarningTextField];
@@ -118,6 +119,6 @@
}
- (void)openAccessibiltyPreferences:(id)sender {
[MPAutotypeDaemon.defaultDaemon openAccessibiltyPreferences];
[MPAutotypeDoctor.defaultDoctor showPermissionCheckReport];
}
@end

View File

@@ -22,7 +22,7 @@
#import "MPUserNotificationCenterDelegate.h"
#import "MPDocumentController.h"
#import "MPAutotypeDaemon.h"
#import "MPAutotypeDoctor.h"
NSString *const MPUserNotificationTypeKey = @"MPUserNotificationTypeKey";
NSString *const MPUserNotificationTypeAutotypeFeedback = @"MPUserNotificationTypeAutotypeFeedback";
@@ -46,7 +46,7 @@ NSString *const MPUserNotificationTypeShowAccessibiltyPreferences = @"MPUserNoti
[((MPDocumentController*)NSDocumentController.sharedDocumentController) reopenLastDocument];
}
else if([notificationType isEqualToString:MPUserNotificationTypeShowAccessibiltyPreferences]) {
[MPAutotypeDaemon.defaultDaemon openAccessibiltyPreferences];
[MPAutotypeDoctor.defaultDoctor showPermissionCheckReport];
}
}