diff --git a/MacPass/DDHotKey+MacPassAdditions.h b/MacPass/DDHotKey+MacPassAdditions.h index b7c6a02c..66c1dc2d 100644 --- a/MacPass/DDHotKey+MacPassAdditions.h +++ b/MacPass/DDHotKey+MacPassAdditions.h @@ -25,14 +25,14 @@ @interface DDHotKey (MPKeydata) @property (readonly, copy) NSData *keyData; - +@property (readonly, copy, class) NSData *defaultHotKeyData; /** Use this method to retrieve the data, since deallocation of a hotkey unregisters it, this could yield unwanted behaviour! @return data for the default hot key. */ + (NSData *)hotKeyDataWithKeyCode:(unsigned short)keyCode modifierFlags:(NSUInteger)flags; -+ (NSData *)defaultHotKeyData; + + (instancetype)defaultHotKey; + (instancetype)defaultHotKeyWithTask:(DDHotKeyTask)task; + (instancetype)hotKeyWithKeyData:(NSData *)data task:(DDHotKeyTask)task; diff --git a/MacPass/MPAutotypeDaemon.h b/MacPass/MPAutotypeDaemon.h index b6561014..762d001c 100644 --- a/MacPass/MPAutotypeDaemon.h +++ b/MacPass/MPAutotypeDaemon.h @@ -40,6 +40,7 @@ - (instancetype)init NS_UNAVAILABLE; - (void)checkForAccessibiltyPermissions; +- (void)openAccessibiltyPreferences; - (void)performAutotypeForEntry:(KPKEntry *)entry; - (void)performAutotypeForEntry:(KPKEntry *)entry overrideSequence:(NSString *)sequence; diff --git a/MacPass/MPAutotypeDaemon.m b/MacPass/MPAutotypeDaemon.m index f2857cf4..0b75c679 100644 --- a/MacPass/MPAutotypeDaemon.m +++ b/MacPass/MPAutotypeDaemon.m @@ -134,13 +134,47 @@ static MPAutotypeDaemon *_sharedInstance; } - (void)checkForAccessibiltyPermissions { - if(@available(macOS 10.14, *)) { - CFStringRef keys[] = { kAXTrustedCheckOptionPrompt }; - CFBooleanRef values[] = { kCFBooleanTrue }; - CFDictionaryRef dictRef = CFDictionaryCreate(kCFAllocatorDefault, (const void **)keys, (const void **)values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - AXIsProcessTrustedWithOptions(dictRef); - CFRelease(dictRef); + if(!self.enabled) { + return; } + 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.suppressionButton.title = NSLocalizedString(@"ALERT_AUTOTYPE_MISSING_ACCESSIBILTY_PERMISSIONS_SUPPRESS_WARNING", @"Checkbox in dialog to set the selection as default file change strategy!"); + [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!")]; + NSWindow *window = NSDocumentController.sharedDocumentController.currentDocument.windowForSheet; + [alert beginSheetModalForWindow:window completionHandler:^(NSModalResponse returnCode) { + 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 - @@ -180,7 +214,17 @@ static MPAutotypeDaemon *_sharedInstance; #pragma mark Autotype Execution - (void)_performAutotypeForEntry:(KPKEntry *)entryOrNil { - NSInteger pid = [NSProcessInfo processInfo].processIdentifier; + if(!self.autotypeSupported) { + NSUserNotification *notification = [[NSUserNotification alloc] init]; + notification.title = NSApp.applicationName; + notification.informativeText = NSLocalizedString(@"AUTOTYPE_NOTIFICATION_MACPASS_HAS_NO_ACCESSIBILTY_PERMISSIONS", "Notification: Autotype failed, MacPass has no permission to send key strokes"); + notification.actionButtonTitle = NSLocalizedString(@"OPEN_PREFERENCES", "Action button in Notification to show the Accessibilty preferences"); + notification.userInfo = @{ MPUserNotificationTypeKey: MPUserNotificationTypeShowAccessibiltyPreferences }; + notification.showsButtons = YES; + [NSUserNotificationCenter.defaultUserNotificationCenter deliverNotification:notification]; + return; + } + NSInteger pid = NSProcessInfo.processInfo.processIdentifier; if(self.targetPID == pid) { return; // We do not perform Autotype on ourselves } diff --git a/MacPass/MPIntegrationSettingsController.m b/MacPass/MPIntegrationSettingsController.m index 4fd4a099..5cbfbf3e 100644 --- a/MacPass/MPIntegrationSettingsController.m +++ b/MacPass/MPIntegrationSettingsController.m @@ -116,6 +116,7 @@ [self.autotypeStackView setVisibilityPriority:NSStackViewVisibilityPriorityMustHold forView:self.openPreferencesButton]; } + /* NSArray *controls = @[ self.enableGlobalAutotypeCheckBox, self.hotKeyTextField, self.matchTitleCheckBox, @@ -126,10 +127,10 @@ for(NSControl *control in controls) { control.enabled = hasAutotypeSupport; } + */ } - (void)openAccessibiltyPreferences:(id)sender { - [NSWorkspace.sharedWorkspace openURL:[NSURL URLWithString:@"x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility"]]; - + [MPAutotypeDaemon.defaultDaemon openAccessibiltyPreferences]; } @end diff --git a/MacPass/MPSettingsHelper.h b/MacPass/MPSettingsHelper.h index e517fb2e..6cbf4de8 100644 --- a/MacPass/MPSettingsHelper.h +++ b/MacPass/MPSettingsHelper.h @@ -50,8 +50,8 @@ APPKIT_EXTERN NSString *const kMPSettingsKeyLegacyHideUsername; APPKIT_EXTERN NSString *const kMPSettingsKeyLegacyHidePassword; APPKIT_EXTERN NSString *const kMPSettingsKeyLegacyHideNotes; APPKIT_EXTERN NSString *const kMPSettingsKeyLegacyHideURL; -/* Document/Key Location store */ +/* Document/Key Location store */ APPKIT_EXTERN NSString *const kMPSettingsKeyLastDatabasePath; // Path to the last opened Database. Workaround if users have disabled the feature in the OS APPKIT_EXTERN NSString *const kMPSettingsKeyRememeberdKeysForDatabases; // NSDictionary of all db file urls and the corresponding key file url APPKIT_EXTERN NSString *const kMPSettingsKeyRememberKeyFilesForDatabases; // YES if key files should be remembers @@ -65,6 +65,7 @@ APPKIT_EXTERN NSString *const kMPSettingsKeyAutotypeMatchTitle; // APPKIT_EXTERN NSString *const kMPSettingsKeyAutotypeMatchURL; // Autotype lookup includes entry URL APPKIT_EXTERN NSString *const kMPSettingsKeyAutotypeMatchHost; // Autotype lookup includes host part of entry URL APPKIT_EXTERN NSString *const kMPSettingsKeyAutotypeMatchTags; // Autotype lookup includes tags for entries +APPKIT_EXTERN NSString *const kMPSettingsKeyAutotypeHideAccessibiltyWarning; // Do not show an alert, when MacPass has no support for Autotype /* Search */ APPKIT_EXTERN NSString *const kMPSettingsKeyEntrySearchFilterContext; diff --git a/MacPass/MPSettingsHelper.m b/MacPass/MPSettingsHelper.m index f1f08f62..74fc61db 100644 --- a/MacPass/MPSettingsHelper.m +++ b/MacPass/MPSettingsHelper.m @@ -56,6 +56,7 @@ NSString *const kMPSettingsKeyAutotypeMatchTitle = @"Autoty NSString *const kMPSettingsKeyAutotypeMatchURL = @"AutotypeMatchURL"; NSString *const kMPSettingsKeyAutotypeMatchHost = @"AutotypeMatchHost"; NSString *const kMPSettingsKeyAutotypeMatchTags = @"AutotypeMatchTags"; +NSString *const kMPSettingsKeyAutotypeHideAccessibiltyWarning = @"AutotypeHideAccessibiltyWarning"; NSString *const kMPSettingsKeyEntrySearchFilterContext = @"EntrySearchFilterContext"; diff --git a/MacPass/MPUserNotificationCenterDelegate.h b/MacPass/MPUserNotificationCenterDelegate.h index b3506d51..0eadfd6b 100644 --- a/MacPass/MPUserNotificationCenterDelegate.h +++ b/MacPass/MPUserNotificationCenterDelegate.h @@ -25,6 +25,7 @@ FOUNDATION_EXTERN NSString *const MPUserNotificationTypeKey; FOUNDATION_EXTERN NSString *const MPUserNotificationTypeAutotypeFeedback; FOUNDATION_EXTERN NSString *const MPUserNotificationTypeAutotypeOpenDocumentRequest; +FOUNDATION_EXTERN NSString *const MPUserNotificationTypeShowAccessibiltyPreferences; @interface MPUserNotificationCenterDelegate : NSObject diff --git a/MacPass/MPUserNotificationCenterDelegate.m b/MacPass/MPUserNotificationCenterDelegate.m index bb7ba24c..307276bd 100644 --- a/MacPass/MPUserNotificationCenterDelegate.m +++ b/MacPass/MPUserNotificationCenterDelegate.m @@ -22,10 +22,12 @@ #import "MPUserNotificationCenterDelegate.h" #import "MPDocumentController.h" +#import "MPAutotypeDaemon.h" NSString *const MPUserNotificationTypeKey = @"MPUserNotificationTypeKey"; NSString *const MPUserNotificationTypeAutotypeFeedback = @"MPUserNotificationTypeAutotypeFeedback"; NSString *const MPUserNotificationTypeAutotypeOpenDocumentRequest = @"MPUserNotificationTypeAutotypeOpenDocumentRequest"; +NSString *const MPUserNotificationTypeShowAccessibiltyPreferences = @"MPUserNotificationTypeShowAccessibiltyPreferences"; @implementation MPUserNotificationCenterDelegate @@ -39,13 +41,24 @@ NSString *const MPUserNotificationTypeAutotypeOpenDocumentRequest = @"MPUserNoti - (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification { NSDictionary *userInfo = notification.userInfo; - if([userInfo[MPUserNotificationTypeKey] isEqualToString:MPUserNotificationTypeAutotypeOpenDocumentRequest]) { + NSString *notificationType = userInfo[MPUserNotificationTypeKey]; + if([notificationType isEqualToString:MPUserNotificationTypeAutotypeOpenDocumentRequest]) { [((MPDocumentController*)NSDocumentController.sharedDocumentController) reopenLastDocument]; } + else if([notificationType isEqualToString:MPUserNotificationTypeShowAccessibiltyPreferences]) { + [MPAutotypeDaemon.defaultDaemon openAccessibiltyPreferences]; + } } - (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification { - return [notification.userInfo[MPUserNotificationTypeKey] isEqualToString:MPUserNotificationTypeAutotypeFeedback]; + NSString *notificationType = notification.userInfo[MPUserNotificationTypeKey]; + if([notificationType isEqualToString:MPUserNotificationTypeAutotypeFeedback]) { + return YES; + } + if([notificationType isEqualToString:MPUserNotificationTypeShowAccessibiltyPreferences]) { + return YES; + } + return NO; } diff --git a/MacPass/en.lproj/Localizable.strings b/MacPass/en.lproj/Localizable.strings index 61ae624c..63f6c0aa 100644 --- a/MacPass/en.lproj/Localizable.strings +++ b/MacPass/en.lproj/Localizable.strings @@ -31,6 +31,21 @@ /* Action to add an entry via template */ "ADD_TREMPLATE_ENTRY" = "Create Template Entry"; +/* Button in dialog to leave autotype disabled and continiue! */ +"ALERT_AUTOTYPE_MISSING_ACCESSIBILTY_PERMISSIONS_BUTTON_OK" = "Keep Autotype disabled."; + +/* Button in dialog to open accessibilty preferences pane! */ +"ALERT_AUTOTYPE_MISSING_ACCESSIBILTY_PERMISSIONS_BUTTON_OPEN_PREFERENCES" = "Open Accessibilty Preferences…"; + +/* Alert informative text displayed when Autotype performs self check and lacks accessibilty permissions */ +"ALERT_AUTOTYPE_MISSING_ACCESSIBILTY_PERMISSIONS_INFORMATIVE_TEXT" = "The system prevents MacPass from sending key strokes to other Applications. To enable Autotype please grant MacPass Accessibilty rights in the privacy preferences."; + +/* Alert message displayed when Autotype performs self check and lacks accessibilty permissions */ +"ALERT_AUTOTYPE_MISSING_ACCESSIBILTY_PERMISSIONS_MESSAGE_TEXT" = "MacPass cannot perform Autotype"; + +/* Checkbox in dialog to set the selection as default file change strategy! */ +"ALERT_AUTOTYPE_MISSING_ACCESSIBILTY_PERMISSIONS_SUPPRESS_WARNING" = "Do not show this warning again."; + /* Alert informative text when plugins or their settings change and require a restart */ "ALERT_INFORMATIVE_TEXT_PLUGINS_CHANGED_SUGGEST_RESTART" = "Changes to plugins and global plugin settings take only effect after restart. Restart MacPass now?"; @@ -80,6 +95,9 @@ /* Disable autotype menu item */ "AUTOTYPE_NO" = "Disable Autotype"; +/* Notification: Autotype failed, MacPass has no permission to send key strokes */ +"AUTOTYPE_NOTIFICATION_MACPASS_HAS_NO_ACCESSIBILTY_PERMISSIONS" = "Autotype disabled because of missing accessibilty access."; + /* Notification: Autotype failed, no documents are open */ "AUTOTYPE_OVERLAY_NO_DOCUMENTS" = "Please open a database file to use Global Autotype!"; @@ -408,6 +426,9 @@ /* Action button in Notification to open a document */ "OPEN_DOCUMENT" = "Open Document"; +/* Action button in Notification to show the Accessibilty preferences */ +"OPEN_PREFERENCES" = "Open Accessiblity Preferences…"; + /* Menu item to open the URL with the default application */ "OPEN_URL" = "Open URL";