From edf43583880838f0ef689dde148f42a88c133772 Mon Sep 17 00:00:00 2001 From: michael starke Date: Wed, 26 Mar 2014 22:29:45 +0100 Subject: [PATCH] Fixed isse with auto type skipping paste commands Started implementing AutotypeFixDialog for 0.4.0 and 0.4.1 fix Autotype candidate selection is shorter using subitems instead of single line --- MacPass.xcodeproj/project.pbxproj | 10 ++ MacPass/AutotypeCandidateSelectionWindow.xib | 14 +- MacPass/Base.lproj/MainMenu.xib | 6 + MacPass/FixAutotypeWindow.xib | 139 +++++++++++++++++++ MacPass/MPAppDelegate.h | 1 + MacPass/MPAppDelegate.m | 10 ++ MacPass/MPAutotypeCommand.h | 15 +- MacPass/MPAutotypeCommand.m | 12 +- MacPass/MPAutotypeDaemon.h | 4 +- MacPass/MPAutotypeDaemon.m | 31 +++-- MacPass/MPFixAutotypeWindowController.h | 15 ++ MacPass/MPFixAutotypeWindowController.m | 139 +++++++++++++++++++ 12 files changed, 375 insertions(+), 21 deletions(-) create mode 100644 MacPass/FixAutotypeWindow.xib create mode 100644 MacPass/MPFixAutotypeWindowController.h create mode 100644 MacPass/MPFixAutotypeWindowController.m diff --git a/MacPass.xcodeproj/project.pbxproj b/MacPass.xcodeproj/project.pbxproj index 9cb97e6a..0bf84533 100644 --- a/MacPass.xcodeproj/project.pbxproj +++ b/MacPass.xcodeproj/project.pbxproj @@ -16,6 +16,8 @@ 4C0728BD17B5B7F7005A7DD9 /* MPPasswordEditWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C0728BC17B5B7F7005A7DD9 /* MPPasswordEditWindowController.m */; }; 4C0728BF17B68ED0005A7DD9 /* SavePanelAccessoryView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C0728BE17B68ED0005A7DD9 /* SavePanelAccessoryView.xib */; }; 4C08C3AE17B3022400BBBC95 /* KPKLegacyHeaderWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C08C3AD17B3022400BBBC95 /* KPKLegacyHeaderWriter.m */; }; + 4C0B038C18E36DA400B9F9C9 /* MPFixAutotypeWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C0B038A18E36DA400B9F9C9 /* MPFixAutotypeWindowController.m */; }; + 4C0B038D18E36DA400B9F9C9 /* FixAutotypeWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C0B038B18E36DA400B9F9C9 /* FixAutotypeWindow.xib */; }; 4C0C59F118B17F10009C7B76 /* DDHotKeyUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C0C59EF18B17F10009C7B76 /* DDHotKeyUtilities.m */; }; 4C0DD6C618B2A44700FCB193 /* AutotypeCandidateSelectionWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C0DD6C518B2A44700FCB193 /* AutotypeCandidateSelectionWindow.xib */; }; 4C0F647817B6B65E00D9522A /* MPSheetWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C0F647717B6B65E00D9522A /* MPSheetWindowController.m */; }; @@ -377,6 +379,9 @@ 4C08C3AC17B3022400BBBC95 /* KPKLegacyHeaderWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KPKLegacyHeaderWriter.h; sourceTree = ""; }; 4C08C3AD17B3022400BBBC95 /* KPKLegacyHeaderWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KPKLegacyHeaderWriter.m; sourceTree = ""; }; 4C08C3AF17B3036500BBBC95 /* KPKLegacyFormat.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = KPKLegacyFormat.h; path = Format/KPKLegacyFormat.h; sourceTree = ""; }; + 4C0B038918E36DA400B9F9C9 /* MPFixAutotypeWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPFixAutotypeWindowController.h; sourceTree = ""; }; + 4C0B038A18E36DA400B9F9C9 /* MPFixAutotypeWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPFixAutotypeWindowController.m; sourceTree = ""; }; + 4C0B038B18E36DA400B9F9C9 /* FixAutotypeWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = FixAutotypeWindow.xib; sourceTree = ""; }; 4C0C59EF18B17F10009C7B76 /* DDHotKeyUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DDHotKeyUtilities.m; path = DDHotKey/DDHotKeyUtilities.m; sourceTree = ""; }; 4C0C59F018B17F10009C7B76 /* DDHotKeyUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = DDHotKeyUtilities.h; path = DDHotKey/DDHotKeyUtilities.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 4C0DD6C518B2A44700FCB193 /* AutotypeCandidateSelectionWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AutotypeCandidateSelectionWindow.xib; sourceTree = ""; }; @@ -1879,6 +1884,8 @@ 4CD5D704177A5F3300100649 /* MPDatabaseSettingsWindowController.m */, 4C0728BB17B5B7F7005A7DD9 /* MPPasswordEditWindowController.h */, 4C0728BC17B5B7F7005A7DD9 /* MPPasswordEditWindowController.m */, + 4C0B038918E36DA400B9F9C9 /* MPFixAutotypeWindowController.h */, + 4C0B038A18E36DA400B9F9C9 /* MPFixAutotypeWindowController.m */, ); name = "Window Controller"; sourceTree = ""; @@ -1895,6 +1902,7 @@ 4CE8247216E2E99F00573141 /* Windows */ = { isa = PBXGroup; children = ( + 4C0B038B18E36DA400B9F9C9 /* FixAutotypeWindow.xib */, 4CA0B2EC15BCADAC00654E32 /* SettingsWindow.xib */, 4CD884B615BD47080042BBF8 /* DocumentWindow.xib */, 4C431BCE16E2BAB000700A81 /* OverlayWindow.xib */, @@ -2153,6 +2161,7 @@ 4C7ABA4917BAEC6700FF5799 /* 16_BrowserTemplate.pdf in Resources */, 4C7ABA4A17BAEC6700FF5799 /* 17_CDRomTemplate.pdf in Resources */, 4C7ABA4B17BAEC6700FF5799 /* 19_EmailTemplate.pdf in Resources */, + 4C0B038D18E36DA400B9F9C9 /* FixAutotypeWindow.xib in Resources */, 4C0DD6C618B2A44700FCB193 /* AutotypeCandidateSelectionWindow.xib in Resources */, 4C7ABA4C17BAEC6700FF5799 /* 20_MiscTemplate.pdf in Resources */, 4C7ABA4E17BAEC7000FF5799 /* addEntryTemplate.pdf in Resources */, @@ -2282,6 +2291,7 @@ 4C245B7E176E1E3D0086100E /* MultipartMessageHeader.m in Sources */, 4C245B7F176E1E3D0086100E /* MultipartMessageHeaderField.m in Sources */, 4C245B80176E1E3D0086100E /* HTTPAsyncFileResponse.m in Sources */, + 4C0B038C18E36DA400B9F9C9 /* MPFixAutotypeWindowController.m in Sources */, 4C245B81176E1E3D0086100E /* HTTPDataResponse.m in Sources */, 4C245B82176E1E3D0086100E /* HTTPDynamicFileResponse.m in Sources */, 4C245B83176E1E3D0086100E /* HTTPErrorResponse.m in Sources */, diff --git a/MacPass/AutotypeCandidateSelectionWindow.xib b/MacPass/AutotypeCandidateSelectionWindow.xib index a680b3e1..0f12e8aa 100644 --- a/MacPass/AutotypeCandidateSelectionWindow.xib +++ b/MacPass/AutotypeCandidateSelectionWindow.xib @@ -1,20 +1,19 @@ - + - + - - + @@ -33,7 +32,7 @@ Gw - + @@ -95,4 +97,4 @@ Gw - \ No newline at end of file + diff --git a/MacPass/Base.lproj/MainMenu.xib b/MacPass/Base.lproj/MainMenu.xib index 147b1d34..9c1a275f 100644 --- a/MacPass/Base.lproj/MainMenu.xib +++ b/MacPass/Base.lproj/MainMenu.xib @@ -112,6 +112,12 @@ + + + + + + diff --git a/MacPass/FixAutotypeWindow.xib b/MacPass/FixAutotypeWindow.xib new file mode 100644 index 00000000..d5ae8244 --- /dev/null +++ b/MacPass/FixAutotypeWindow.xib @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MacPass/MPAppDelegate.h b/MacPass/MPAppDelegate.h index 4a90b065..1bc4d8ea 100644 --- a/MacPass/MPAppDelegate.h +++ b/MacPass/MPAppDelegate.h @@ -35,6 +35,7 @@ FOUNDATION_EXTERN NSString *const MPDidChangeStoredKeyFilesSettings; - (IBAction)showPasswordCreator:(id)sender; - (IBAction)createNewDatabase:(id)sender; - (IBAction)openDatabase:(id)sender; +- (IBAction)fixAutotype:(id)sender; /** * Clears the stored key files for any documents. * @param sender sender of this action diff --git a/MacPass/MPAppDelegate.m b/MacPass/MPAppDelegate.m index 2c335159..84ac39ce 100644 --- a/MacPass/MPAppDelegate.m +++ b/MacPass/MPAppDelegate.m @@ -31,6 +31,7 @@ #import "MPLockDaemon.h" #import "MPAutotypeDaemon.h" #import "MPDocumentWindowController.h" +#import "MPFixAutotypeWindowController.h" #import "MPTemporaryFileStorageCenter.h" @@ -50,6 +51,7 @@ NSString *const MPDidChangeStoredKeyFilesSettings = @"com.hicknhack.macpass.MPDi @property (strong, nonatomic) MPSettingsWindowController *settingsController; @property (strong, nonatomic) MPPasswordCreatorViewController *passwordCreatorController; +@property (strong) MPFixAutotypeWindowController *fixAutotypeWindowController; @end @@ -219,6 +221,14 @@ NSString *const MPDidChangeStoredKeyFilesSettings = @"com.hicknhack.macpass.MPDi [[NSUserDefaults standardUserDefaults] removeObjectForKey:kMPSettingsKeyRememeberdKeysForDatabases]; } +- (void)fixAutotype:(id)sender { + if(!self.fixAutotypeWindowController) { + self.fixAutotypeWindowController = [[MPFixAutotypeWindowController alloc] init]; + } + [self.fixAutotypeWindowController reset]; + [[self.fixAutotypeWindowController window] makeKeyAndOrderFront:sender]; +} + #pragma mark - #pragma mark Private Helper - (void)_applicationDidFinishRestoringWindows:(NSNotification *)notification { diff --git a/MacPass/MPAutotypeCommand.h b/MacPass/MPAutotypeCommand.h index 9e8a24c2..bee0052f 100644 --- a/MacPass/MPAutotypeCommand.h +++ b/MacPass/MPAutotypeCommand.h @@ -13,14 +13,23 @@ /** * The Autotype command reperesent a capsualted Action that was determined by interpreting * Autotype field for a given entry. This is a class cluster and schould be considered the sole - * enty point for creating AutotypeCommands. + * enty point for creating AutotypeCommands. You should never need to build a command on your own. */ @interface MPAutotypeCommand : NSObject @property (readonly, strong) MPAutotypeContext *context; - +/** + * Creates a command sequence for the given context. The context's keystroke sequence is + * is evaluated (Placholders filled, references resolved) and the commands are created in the + * order of their execution + * + * @param context the context to create the comamnds from. + * + * @return NSArray of MPAutotypeCommand + */ + (NSArray *)commandsForContext:(MPAutotypeContext *)context; + /** * Sends a KeyPress Event with the supplied modifier flags and Keycode * Any existing modifiers will be disabled for this event. If the user @@ -37,7 +46,7 @@ - (void)sendPasteKeyCode; /** - * Exectues the Autotype Command. This will be called by the autotype daemon. + * Exectues the Autotype Command. */ - (void)execute; diff --git a/MacPass/MPAutotypeCommand.m b/MacPass/MPAutotypeCommand.m index 34a0d19d..3bb2c8b9 100644 --- a/MacPass/MPAutotypeCommand.m +++ b/MacPass/MPAutotypeCommand.m @@ -124,8 +124,7 @@ } NSRange pasteRange = NSMakeRange(lastLocation, commandRange.location - lastLocation); if(pasteRange.length > 0) { - NSString *pasteValue = [context.evaluatedCommand substringWithRange:NSMakeRange(lastLocation, commandRange.location - lastLocation)]; - // Determin if it's amodifier key, and collect them! + NSString *pasteValue = [context.evaluatedCommand substringWithRange:pasteRange]; [self appendPasteCommandForContent:pasteValue toCommands:commands]; } } @@ -138,6 +137,15 @@ } lastLocation = commandRange.location + commandRange.length; } + /* Collect any part that isn't a command or if onyl paste is used */ + if(lastLocation < [context.evaluatedCommand length]) { + NSRange pasteRange = NSMakeRange(lastLocation, [context.evaluatedCommand length] - lastLocation); + if(pasteRange.length > 0) { + NSString *pasteValue = [context.evaluatedCommand substringWithRange:pasteRange]; + [self appendPasteCommandForContent:pasteValue toCommands:commands]; + } + + } return commands; } diff --git a/MacPass/MPAutotypeDaemon.h b/MacPass/MPAutotypeDaemon.h index 9dd7633d..8db6ed04 100644 --- a/MacPass/MPAutotypeDaemon.h +++ b/MacPass/MPAutotypeDaemon.h @@ -17,8 +17,8 @@ @property (strong) IBOutlet NSWindow *matchSelectionWindow; @property (weak) IBOutlet NSPopUpButton *matchSelectionButton; -@property (weak) IBOutlet NSButton *performAutotypeButton; -- (void)exectureAutotypeForEntry:(KPKEntry *)entry withWindowTitle:(NSString *)title; +- (IBAction)executeAutotypeWithSelectedMatch:(id)sender; +- (IBAction)cancelAutotypeSelection:(id)sender; @end diff --git a/MacPass/MPAutotypeDaemon.m b/MacPass/MPAutotypeDaemon.m index 376fad4f..fb737982 100644 --- a/MacPass/MPAutotypeDaemon.m +++ b/MacPass/MPAutotypeDaemon.m @@ -66,7 +66,18 @@ NSString *const kMPApplciationNameKey = @"applicationName"; [self _performAutotypeForContext:context]; } +- (void)cancelAutotypeSelection:(id)sender { + [self.matchSelectionWindow orderOut:sender]; + if(self.lastFrontMostApplication) { + [MPAutotypeDaemon _orderApplicationToFront:self.lastFrontMostApplication]; + } +} + - (void)_didPressHotKey { + + /* Reset the applciation on every keypress */ + self.lastFrontMostApplication = nil; + NSArray *documents = [NSApp orderedDocuments]; MPDocument *currentDocument = nil; for(MPDocument *openDocument in documents) { @@ -105,11 +116,11 @@ NSString *const kMPApplciationNameKey = @"applicationName"; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSArray *commands = [MPAutotypeCommand commandsForContext:context]; [MPAutotypeDaemon _orderApplicationToFront:self.lastFrontMostApplication]; - usleep(1000*1000); BOOL lastCommandWasPaste = NO; for(MPAutotypeCommand *command in commands) { if(lastCommandWasPaste) { - usleep(500*1000); + NSLog(@"Sleeping for pasting!"); + usleep(1000*1000); } [command execute]; lastCommandWasPaste = [command isKindOfClass:[MPAutotypePaste class]]; @@ -153,22 +164,26 @@ NSString *const kMPApplciationNameKey = @"applicationName"; - (void)_presentSelectionWindow:(NSArray *)candidates { if(!self.matchSelectionWindow) { [[NSBundle mainBundle] loadNibNamed:@"AutotypeCandidateSelectionWindow" owner:self topLevelObjects:nil]; - [self.performAutotypeButton setTarget:self]; - [self.performAutotypeButton setAction:@selector(executeAutotypeWithSelectedMatch:)]; [self.matchSelectionWindow setLevel:NSFloatingWindowLevel]; } NSMenu *associationMenu = [[NSMenu alloc] init]; [associationMenu addItemWithTitle:NSLocalizedString(@"SELECT_AUTOTYPE_CANDIDATE", "") action:NULL keyEquivalent:@""]; [associationMenu addItem:[NSMenuItem separatorItem]]; [associationMenu setAutoenablesItems:NO]; - NSString *entryMask = NSLocalizedString(@"TITLE_%@_USERNAME_%@_PASSWORD_%@_AUTOTYPE_SEQUENCE_%@", "Mask to create autotype entries for selection by the user. %1 Title %2 Username %3 Password %4 Sequence"); for(MPAutotypeContext *context in candidates) { - NSString *title = [[NSString alloc] initWithFormat:entryMask, context.entry.title, context.entry.username, context.entry.password, context.command]; - NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:title action:0 keyEquivalent:@""]; + NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:context.entry.title action:0 keyEquivalent:@""]; [item setRepresentedObject:context]; [associationMenu addItem:item]; + NSArray *attributes = @[ context.entry.username, context.command ]; + for(NSString *value in attributes) { + NSMenuItem *valueItem = [[NSMenuItem alloc] initWithTitle:value action:NULL keyEquivalent:@""]; + [valueItem setIndentationLevel:1]; + [valueItem setEnabled:NO]; + [associationMenu addItem:valueItem]; + } } [self.matchSelectionButton setMenu:associationMenu]; + [NSApp activateIgnoringOtherApps:YES]; [self.matchSelectionWindow makeKeyAndOrderFront:self]; /* Setup Items in Popup */ } @@ -179,7 +194,7 @@ NSString *const kMPApplciationNameKey = @"applicationName"; NSAppleScript *script = [[NSAppleScript alloc] initWithSource:appleScript]; NSDictionary *error; NSAppleEventDescriptor *descriptor = [script executeAndReturnError:&error]; - if(descriptor) { + if(!descriptor) { NSLog(@"Error trying to execure %@: %@", script, error); } } diff --git a/MacPass/MPFixAutotypeWindowController.h b/MacPass/MPFixAutotypeWindowController.h new file mode 100644 index 00000000..dbf285f9 --- /dev/null +++ b/MacPass/MPFixAutotypeWindowController.h @@ -0,0 +1,15 @@ +// +// MPFixAutotypeWindowController.h +// MacPass +// +// Created by Michael Starke on 26/03/14. +// Copyright (c) 2014 HicknHack Software GmbH. All rights reserved. +// + +#import + +@interface MPFixAutotypeWindowController : NSWindowController + +- (void)reset; + +@end diff --git a/MacPass/MPFixAutotypeWindowController.m b/MacPass/MPFixAutotypeWindowController.m new file mode 100644 index 00000000..e83ed264 --- /dev/null +++ b/MacPass/MPFixAutotypeWindowController.m @@ -0,0 +1,139 @@ +// +// MPFixAutotypeWindowController.m +// MacPass +// +// Created by Michael Starke on 26/03/14. +// Copyright (c) 2014 HicknHack Software GmbH. All rights reserved. +// + +#import "MPFixAutotypeWindowController.h" +#import "MPDocument.h" +#import "KPKNode.h" +#import "KPKEntry.h" +#import "KPKGroup.h" +#import "KPKAutotype.h" + +@interface KPKGroup (Breadcrumb) + +- (NSString *)breadcrumb; + +@end + +@implementation KPKGroup (Breadcrumb) + +- (NSString *)breadcrumb { + if(self.parent) { + return [[self.parent breadcrumb] stringByAppendingFormat:@" > %@", self.name]; + } + return self.name; +} + +@end + +@interface MPFixAutotypeWindowController () { + NSMutableArray *_elements; +} + +@property (weak) NSTableView *tableView; + +@end + +@implementation MPFixAutotypeWindowController + +- (instancetype)init { + self = [super initWithWindowNibName:@"FixAutotypeWindow"]; + return self; +} + +- (instancetype)initWithWindow:(NSWindow *)window { + self = [super initWithWindow:window]; + if (self) { + } + return self; +} + +- (void)windowDidLoad { + [super windowDidLoad]; +} + +- (void)reset { + _elements = nil; + [self.tableView reloadData]; +} + +#pragma mark - +#pragma mark NSTableViewDataSource + +- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView { + + self.tableView = tableView; + + return [[self entriesAndGroups] count]; +} + +- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row { + + self.tableView = tableView; + id node = [self entriesAndGroups][row]; + if([[tableColumn identifier] isEqualToString:@"TitleCell"]) { + if( [node respondsToSelector:@selector(title)]) { + return [node title]; + } + return [node breadcrumb]; + } + else if ([[tableColumn identifier] isEqualToString:@"AutotypeCell"]) { + if([node respondsToSelector:@selector(defaultAutoTypeSequence)]) { + return [node defaultAutoTypeSequence]; + } + return [[node autotype] defaultKeystrokeSequence]; + } + else if([[tableColumn identifier] isEqualToString:@"IsDefaultCell"]) { + BOOL isDefault = NO; + if([node respondsToSelector:@selector(hasDefaultAutotypeSequence)]) { + isDefault = [node hasDefaultAutotypeSequence]; + } + else { + isDefault = [[node autotype] hasDefaultKeystrokeSequence]; + } + return isDefault ? @"Yes" : @"No"; + } + return nil; +} + +#pragma mark - +#pragma mark NSTableViewDelegate + +- (BOOL)tableView:(NSTableView *)tableView isGroupRow:(NSInteger)row { + id item = [self entriesAndGroups][row]; + return [item isKindOfClass:[KPKGroup class]]; +} + +#pragma mark - +#pragma mark Data accessors + +- (NSArray *)entriesAndGroups { + if(nil == _elements) { + NSArray *documents = [[NSDocumentController sharedDocumentController] documents]; + _elements = [[NSMutableArray alloc] init]; + for(MPDocument *document in documents) { + if(!document.root) { + continue; + } + KPKGroup *group = document.root; + [self flattenGroup:group toArray:_elements]; + } + } + return _elements; +} + + +- (void)flattenGroup:(KPKGroup *)group toArray:(NSMutableArray *)array { + [array addObject:group]; + [array addObjectsFromArray:group.entries]; + for(KPKGroup *childGroup in group.groups) { + [self flattenGroup:childGroup toArray:array]; + } +} + + +@end