From e8ab0602e1513455733538d189358fb0e70be509 Mon Sep 17 00:00:00 2001 From: michael starke Date: Thu, 12 Nov 2015 12:43:04 +0100 Subject: [PATCH] Removed old Code. Added simple plugin system Signed-off-by: michael starke --- MacPass.xcodeproj/project.pbxproj | 22 +++-- MacPass/Base.lproj/IntegrationSettings.xib | 42 ++------ MacPass/MPAppDelegate.h | 2 +- MacPass/MPAppDelegate.m | 14 ++- MacPass/MPAutotypeDaemon.h | 3 + MacPass/MPAutotypeDaemon.m | 16 +++ MacPass/MPGenericPlugin.h | 28 ------ MacPass/MPIntegrationSettingsController.h | 4 - MacPass/MPIntegrationSettingsController.m | 4 - MacPass/MPLockDaemon.h | 3 +- MacPass/MPLockDaemon.m | 17 ++-- MacPass/MPPlugin.h | 37 +++++++ MacPass/MPPlugin.m | 108 +++++++++++++++++++++ MacPass/MPPluginManager.h | 8 ++ MacPass/MPPluginManager.m | 31 +++++- MacPass/MPPluginSettingsController.m | 59 ++++++++--- MacPass/MPServerRequestHandling.h | 30 ------ MacPass/MPSettingsHelper.h | 8 +- MacPass/MPSettingsHelper.m | 22 +++-- MacPass/MacPass-Info.plist | 19 ++++ MacPass/NSApplication+MPAdditions.h | 22 +++++ MacPass/NSApplication+MPAdditions.m | 41 ++++++++ MacPass/PluginSettings.xib | 71 ++++++++------ 23 files changed, 426 insertions(+), 185 deletions(-) delete mode 100644 MacPass/MPGenericPlugin.h create mode 100644 MacPass/MPPlugin.h create mode 100644 MacPass/MPPlugin.m delete mode 100644 MacPass/MPServerRequestHandling.h create mode 100644 MacPass/NSApplication+MPAdditions.h create mode 100644 MacPass/NSApplication+MPAdditions.m diff --git a/MacPass.xcodeproj/project.pbxproj b/MacPass.xcodeproj/project.pbxproj index 2e210357..1de00db4 100644 --- a/MacPass.xcodeproj/project.pbxproj +++ b/MacPass.xcodeproj/project.pbxproj @@ -231,6 +231,8 @@ 4CEE46DD181C301D006BF1E5 /* MPAutotypeDaemon.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CEE46DC181C301D006BF1E5 /* MPAutotypeDaemon.m */; }; 4CEED1C617D7BD0E007180F1 /* NSError+Messages.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CEED1C517D7BD0E007180F1 /* NSError+Messages.m */; }; 4CF29BF417879D0000851B60 /* 26_FileSaveTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 4CF29BF317879D0000851B60 /* 26_FileSaveTemplate.pdf */; }; + 4CF5BE6D1BF33E3000048505 /* NSApplication+MPAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CF5BE6C1BF33E3000048505 /* NSApplication+MPAdditions.m */; }; + 4CF5BEC41BF3461800048505 /* MPPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CF5BEC31BF3461800048505 /* MPPlugin.m */; }; 4CF6C711176F4533007A811D /* MPStringLengthValueTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CF6C710176F4533007A811D /* MPStringLengthValueTransformer.m */; }; 4CF78064176E75AD0032EE71 /* MPIntegrationSettingsController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CF78063176E75AD0032EE71 /* MPIntegrationSettingsController.m */; }; 4CFB18E418A17FA20097A34B /* MPUpdateSettingsController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CFB18E318A17FA20097A34B /* MPUpdateSettingsController.m */; }; @@ -413,7 +415,6 @@ 4C2E382516D1470200037A9D /* MPViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPViewController.m; sourceTree = ""; }; 4C31FEB11B57CDDB008E7CE3 /* MPPluginManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPluginManager.h; sourceTree = ""; }; 4C31FEB21B57CDDB008E7CE3 /* MPPluginManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPluginManager.m; sourceTree = ""; }; - 4C31FEBD1B57CE45008E7CE3 /* MPGenericPlugin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPGenericPlugin.h; sourceTree = ""; }; 4C32B0E51A1D4436007E12F1 /* KPKFormat+MPUTIDetection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "KPKFormat+MPUTIDetection.h"; sourceTree = ""; }; 4C32B0E61A1D4436007E12F1 /* KPKFormat+MPUTIDetection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "KPKFormat+MPUTIDetection.m"; sourceTree = ""; }; 4C3666401787327E00B249F1 /* MPDocument+Attachments.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MPDocument+Attachments.m"; sourceTree = ""; }; @@ -717,9 +718,12 @@ 4CEED1C417D7BD0E007180F1 /* NSError+Messages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSError+Messages.h"; sourceTree = ""; }; 4CEED1C517D7BD0E007180F1 /* NSError+Messages.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSError+Messages.m"; sourceTree = ""; }; 4CF29BF317879D0000851B60 /* 26_FileSaveTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = 26_FileSaveTemplate.pdf; sourceTree = ""; }; + 4CF5BE6B1BF33E3000048505 /* NSApplication+MPAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSApplication+MPAdditions.h"; sourceTree = ""; }; + 4CF5BE6C1BF33E3000048505 /* NSApplication+MPAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSApplication+MPAdditions.m"; sourceTree = ""; }; + 4CF5BEC21BF3461800048505 /* MPPlugin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPlugin.h; sourceTree = ""; }; + 4CF5BEC31BF3461800048505 /* MPPlugin.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPlugin.m; sourceTree = ""; }; 4CF6C70F176F4533007A811D /* MPStringLengthValueTransformer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPStringLengthValueTransformer.h; sourceTree = ""; }; 4CF6C710176F4533007A811D /* MPStringLengthValueTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPStringLengthValueTransformer.m; sourceTree = ""; }; - 4CF6C715176F5183007A811D /* MPServerRequestHandling.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPServerRequestHandling.h; sourceTree = ""; }; 4CF78062176E75AD0032EE71 /* MPIntegrationSettingsController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPIntegrationSettingsController.h; sourceTree = ""; }; 4CF78063176E75AD0032EE71 /* MPIntegrationSettingsController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPIntegrationSettingsController.m; sourceTree = ""; }; 4CFB18E218A17FA20097A34B /* MPUpdateSettingsController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPUpdateSettingsController.h; sourceTree = ""; }; @@ -881,6 +885,8 @@ 4C104129178CDD26001B5239 /* Categories */ = { isa = PBXGroup; children = ( + 4CF5BE6B1BF33E3000048505 /* NSApplication+MPAdditions.h */, + 4CF5BE6C1BF33E3000048505 /* NSApplication+MPAdditions.m */, 4C46B88317063A070046109A /* NSString+MPPasswordCreation.h */, 4C46B88417063A070046109A /* NSString+MPPasswordCreation.m */, 4C10412A178CDD44001B5239 /* NSDate+Humanized.h */, @@ -944,14 +950,15 @@ name = Helper; sourceTree = ""; }; - 4C31FEBC1B57CDE0008E7CE3 /* Plugins */ = { + 4C31FEBC1B57CDE0008E7CE3 /* Plugin */ = { isa = PBXGroup; children = ( 4C31FEB11B57CDDB008E7CE3 /* MPPluginManager.h */, 4C31FEB21B57CDDB008E7CE3 /* MPPluginManager.m */, - 4C31FEBD1B57CE45008E7CE3 /* MPGenericPlugin.h */, + 4CF5BEC21BF3461800048505 /* MPPlugin.h */, + 4CF5BEC31BF3461800048505 /* MPPlugin.m */, ); - name = Plugins; + name = Plugin; sourceTree = ""; }; 4C37A84115B8B47D005EF8EE /* Delegates */ = { @@ -1231,7 +1238,7 @@ 4C77E36C15B84A240093A587 /* MacPass */ = { isa = PBXGroup; children = ( - 4C31FEBC1B57CDE0008E7CE3 /* Plugins */, + 4C31FEBC1B57CDE0008E7CE3 /* Plugin */, 4C217D8E17A32BCF00609FAA /* Common */, 4C104129178CDD26001B5239 /* Categories */, 4C89F525182FB4C50069C73C /* Autotype */, @@ -1347,7 +1354,6 @@ 4CA0B30E15BCB70200654E32 /* Protocolls */ = { isa = PBXGroup; children = ( - 4CF6C715176F5183007A811D /* MPServerRequestHandling.h */, 4CA0B30D15BCB6FD00654E32 /* MPSettingsTab.h */, 4C2B0B7419F66F6400E48913 /* MPTargetNodeResolving.h */, ); @@ -1802,6 +1808,7 @@ buildActionMask = 2147483647; files = ( 4C77E37315B84A240093A587 /* main.m in Sources */, + 4CF5BEC41BF3461800048505 /* MPPlugin.m in Sources */, 4CBA2ABA17074C07006D8139 /* MPSettingsHelper.m in Sources */, 4C77E37A15B84A240093A587 /* MPAppDelegate.m in Sources */, 4C37A84015B8B474005EF8EE /* MPOutlineDataSource.m in Sources */, @@ -1847,6 +1854,7 @@ 4C3C4EA618D6FEA100153127 /* TTTJSONTransformer.m in Sources */, 4C89B71019B4B4A300DC0A6A /* MPTreeDelegate.m in Sources */, 4C88C66918D9F8D600F43852 /* MPTemporaryFileStorageCenter.m in Sources */, + 4CF5BE6D1BF33E3000048505 /* NSApplication+MPAdditions.m in Sources */, 4CE30ACC1A312B7F0063FCC6 /* MPReferenceBuilderViewController.m in Sources */, 4C6F228C19A4AA700012310C /* MPAutotypeDelay.m in Sources */, 4C3C4EA718D6FEA100153127 /* TTTStringTransformers.m in Sources */, diff --git a/MacPass/Base.lproj/IntegrationSettings.xib b/MacPass/Base.lproj/IntegrationSettings.xib index 1f88f281..4ed94a5f 100644 --- a/MacPass/Base.lproj/IntegrationSettings.xib +++ b/MacPass/Base.lproj/IntegrationSettings.xib @@ -1,8 +1,8 @@ - + - + @@ -10,7 +10,6 @@ - @@ -24,34 +23,8 @@ - + - - - - - - - - - - - - - - - - - - - @@ -221,15 +194,12 @@ - + - - - - - + + diff --git a/MacPass/MPAppDelegate.h b/MacPass/MPAppDelegate.h index 815c24bd..727173f6 100644 --- a/MacPass/MPAppDelegate.h +++ b/MacPass/MPAppDelegate.h @@ -32,6 +32,7 @@ APPKIT_EXTERN NSString *const MPDidChangeStoredKeyFilesSettings; @property (strong) IBOutlet NSWindow *welcomeWindow; @property (strong) MPAutotypeDaemon *autotypeDaemon; @property (weak) IBOutlet NSMenuItem *saveMenuItem; + @property (nonatomic, assign) BOOL isAllowedToStoreKeyFile; - (IBAction)showPreferences:(id)sender; @@ -45,7 +46,6 @@ APPKIT_EXTERN NSString *const MPDidChangeStoredKeyFilesSettings; */ - (IBAction)clearRememberdKeyFiles:(id)sender; -- (NSString *)applicationName; - (void)lockAllDocuments; @end \ No newline at end of file diff --git a/MacPass/MPAppDelegate.m b/MacPass/MPAppDelegate.m index a83a3233..71a66f3b 100644 --- a/MacPass/MPAppDelegate.m +++ b/MacPass/MPAppDelegate.m @@ -29,6 +29,7 @@ #import "MPDocumentWindowController.h" #import "MPLockDaemon.h" #import "MPPasswordCreatorViewController.h" +#import "MPPluginManager.h" #import "MPSettingsHelper.h" #import "MPSettingsWindowController.h" #import "MPStringLengthValueTransformer.h" @@ -41,7 +42,6 @@ NSString *const MPDidChangeStoredKeyFilesSettings = @"com.hicknhack.macpass.MPDi @interface MPAppDelegate () { @private - MPLockDaemon *lockDaemon; MPDockTileHelper *dockTileHelper; BOOL _shouldOpenFile; // YES if app was started to open a } @@ -153,13 +153,11 @@ NSString *const MPDidChangeStoredKeyFilesSettings = @"com.hicknhack.macpass.MPDi } - (void)applicationDidFinishLaunching:(NSNotification *)notification { - lockDaemon = [[MPLockDaemon alloc] init]; - self.autotypeDaemon = [[MPAutotypeDaemon alloc] init]; - //dockTileHelper = [[MPDockTileHelper alloc] init]; -} - -- (NSString *)applicationName { - return [[NSBundle mainBundle] infoDictionary][@"CFBundleName"]; + /* Daemon instanziieren */ + [MPLockDaemon defaultDaemon]; + [MPAutotypeDaemon defaultDaemon]; + /* Load plugins */ + [[MPPluginManager sharedManager] loadPlugins]; } #pragma mark - diff --git a/MacPass/MPAutotypeDaemon.h b/MacPass/MPAutotypeDaemon.h index ea15f58c..ce117b69 100644 --- a/MacPass/MPAutotypeDaemon.h +++ b/MacPass/MPAutotypeDaemon.h @@ -20,6 +20,9 @@ @property (weak) IBOutlet NSPopUpButton *matchSelectionButton; @property (readonly, strong) DDHotKey *registredHotKey; ++ (instancetype)defaultDaemon; +- (instancetype)init NS_UNAVAILABLE; + - (void)performAutotypeForEntry:(KPKEntry *)entry; - (IBAction)performAutotypeWithSelectedMatch:(id)sender; - (IBAction)cancelAutotypeSelection:(id)sender; diff --git a/MacPass/MPAutotypeDaemon.m b/MacPass/MPAutotypeDaemon.m index 3f1e5ea7..6983dcbb 100644 --- a/MacPass/MPAutotypeDaemon.m +++ b/MacPass/MPAutotypeDaemon.m @@ -43,7 +43,23 @@ NSString *const kMPProcessIdentifierKey = @"kMPProcessIdentifierKey"; #pragma mark - #pragma mark Lifecylce + +static MPAutotypeDaemon *_sharedInstance; + ++ (instancetype)defaultDaemon { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _sharedInstance = [[MPAutotypeDaemon alloc] _init]; + }); + return _sharedInstance; +} + - (instancetype)init { + return nil; +} + +- (instancetype)_init { + NSAssert(_sharedInstance == nil, @"Multiple initializations not allowed on singleton"); self = [super init]; if (self) { _enabled = NO; diff --git a/MacPass/MPGenericPlugin.h b/MacPass/MPGenericPlugin.h deleted file mode 100644 index 901eae69..00000000 --- a/MacPass/MPGenericPlugin.h +++ /dev/null @@ -1,28 +0,0 @@ -// -// MPGenericPlugin.h -// MacPass -// -// Created by Michael Starke on 16/07/15. -// Copyright (c) 2015 HicknHack Software GmbH. All rights reserved. -// - -#import - -@class MPPluginManager - -@protocol MPGenericPlugin - -@required -@property (readonly) NSString *name; -@property (readonly) NSString *version; -@property (readonly) NSInteger *versionNumber; - -- (instancetype)initWithPluginManager:(MPPluginManager *)manager; - -@optional -- (void)manager:(MPPluginManager *)manager willAddNode:(KPKNode *)node; -- (void)manager:(MPPluginManager *)manager didAddNode(KPKNode *)node; -- (void)manager:(MPPluginManager *)manager willRemoveNode:(KPKNode *)node; -- (void)manager:(MPPluginManager *)manager didRemoveNode:(KPKNode *)node; - -@end diff --git a/MacPass/MPIntegrationSettingsController.h b/MacPass/MPIntegrationSettingsController.h index 0167d4af..e64167e7 100644 --- a/MacPass/MPIntegrationSettingsController.h +++ b/MacPass/MPIntegrationSettingsController.h @@ -12,10 +12,6 @@ @class DDHotKeyTextField; @interface MPIntegrationSettingsController : MPViewController - -/* Keepass HTTP */ -@property (weak) IBOutlet NSButton *enableServerCheckBox; - /* Autotype */ @property (weak) IBOutlet NSButton *enableGlobalAutotypeCheckBox; @property (weak) IBOutlet DDHotKeyTextField *hotKeyTextField; diff --git a/MacPass/MPIntegrationSettingsController.m b/MacPass/MPIntegrationSettingsController.m index e2088508..895d0042 100644 --- a/MacPass/MPIntegrationSettingsController.m +++ b/MacPass/MPIntegrationSettingsController.m @@ -40,17 +40,13 @@ - (void)awakeFromNib { NSUserDefaultsController *defaultsController = [NSUserDefaultsController sharedUserDefaultsController]; - NSString *serverKeyPath = [MPSettingsHelper defaultControllerPathForKey:kMPSettingsKeyEnableHttpServer]; NSString *enableGlobalAutotypeKeyPath = [MPSettingsHelper defaultControllerPathForKey:kMPSettingsKeyEnableGlobalAutotype]; NSString *quicklookKeyPath = [MPSettingsHelper defaultControllerPathForKey:kMPSettingsKeyEnableQuicklookPreview]; - [self.enableServerCheckBox bind:NSValueBinding toObject:defaultsController withKeyPath:serverKeyPath options:nil]; - [self.enableServerCheckBox setEnabled:NO]; [self.enableGlobalAutotypeCheckBox bind:NSValueBinding toObject:defaultsController withKeyPath:enableGlobalAutotypeKeyPath options:nil]; [self.enableQuicklookCheckBox bind:NSValueBinding toObject:defaultsController withKeyPath:quicklookKeyPath options:nil]; [self.hotKeyTextField bind:NSEnabledBinding toObject:defaultsController withKeyPath:enableGlobalAutotypeKeyPath options:nil]; self.hotKeyTextField.delegate = self; - [self.matchTitleCheckBox bind:NSValueBinding toObject:defaultsController withKeyPath:[MPSettingsHelper defaultControllerPathForKey:kMPSettingsKeyAutotypeMatchTitle ] options:nil]; [self.matchURLCheckBox bind:NSValueBinding toObject:defaultsController withKeyPath:[MPSettingsHelper defaultControllerPathForKey:kMPSettingsKeyAutotypeMatchURL] options:nil]; [self.matchHostCheckBox bind:NSValueBinding toObject:defaultsController withKeyPath:[MPSettingsHelper defaultControllerPathForKey:kMPSettingsKeyAutotypeMatchHost] options:nil]; diff --git a/MacPass/MPLockDaemon.h b/MacPass/MPLockDaemon.h index 891f5d45..0b1068af 100644 --- a/MacPass/MPLockDaemon.h +++ b/MacPass/MPLockDaemon.h @@ -10,6 +10,7 @@ @interface MPLockDaemon : NSObject -+ (MPLockDaemon *)sharedInstance; ++ (instancetype)defaultDaemon; ++ (instancetype)init NS_UNAVAILABLE; @end diff --git a/MacPass/MPLockDaemon.m b/MacPass/MPLockDaemon.m index fc3a036b..8c6e3129 100644 --- a/MacPass/MPLockDaemon.m +++ b/MacPass/MPLockDaemon.m @@ -22,16 +22,22 @@ @implementation MPLockDaemon -+ (MPLockDaemon *)sharedInstance { - static id sharedInstance; +static MPLockDaemon *_sharedInstance; + ++ (instancetype)defaultDaemon { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ - sharedInstance = [[MPLockDaemon alloc] init]; + _sharedInstance = [[MPLockDaemon alloc] _init]; }); - return sharedInstance; + return _sharedInstance; } -- (id)init { +- (instancetype)init { + return nil; +} + +- (instancetype)_init { + NSAssert(_sharedInstance == nil, @"Multiple instances of MPLockDaemon not allowed!"); self = [super init]; if (self) { NSUserDefaultsController *defaultsController = [NSUserDefaultsController sharedUserDefaultsController]; @@ -47,7 +53,6 @@ /* Timer */ [NSEvent removeMonitor:self.eventHandler]; - } - (void)setLockOnSleep:(BOOL)lockOnSleep { diff --git a/MacPass/MPPlugin.h b/MacPass/MPPlugin.h new file mode 100644 index 00000000..4a29a864 --- /dev/null +++ b/MacPass/MPPlugin.h @@ -0,0 +1,37 @@ +// +// MPPlugin.h +// MacPass +// +// Created by Michael Starke on 11/11/15. +// Copyright © 2015 HicknHack Software GmbH. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@class MPPluginManager; + +FOUNDATION_EXPORT NSString *const kMPPluginFileExtension; + +@interface MPPlugin : NSObject + +@property (copy, readonly) NSString *identifier; +@property (copy, readonly) NSString *name; +@property (copy, readonly) NSString *version; + + ++ (instancetype)pluginWithBundleURL:(NSURL *)url pluginManager:(MPPluginManager *)manager; +- (instancetype)initWithPluginManager:(MPPluginManager *)manager NS_DESIGNATED_INITIALIZER; +- (instancetype)init NS_UNAVAILABLE; + +@end + +@protocol MPPluginSettings + +@required +@property (strong, readonly) NSViewController *settingsViewController; + +@end + +NS_ASSUME_NONNULL_END \ No newline at end of file diff --git a/MacPass/MPPlugin.m b/MacPass/MPPlugin.m new file mode 100644 index 00000000..de4b2712 --- /dev/null +++ b/MacPass/MPPlugin.m @@ -0,0 +1,108 @@ +// +// MPPlugin.m +// MacPass +// +// Created by Michael Starke on 11/11/15. +// Copyright © 2015 HicknHack Software GmbH. All rights reserved. +// + +#import "MPPlugin.h" +#import "MPPluginManager.h" + +NSString *const kMPPluginFileExtension = @"mpplugin"; + +@implementation MPPlugin + ++ (instancetype)pluginWithBundleURL:(NSURL *)url pluginManager:(MPPluginManager *)manager { + if(![self _validURL:url]) { + return nil; + } + NSBundle *pluginBundle = [NSBundle bundleWithURL:url]; + if(!pluginBundle) { + return nil; + } + if(![self _validateClass:pluginBundle.principalClass]) { + return nil; + } + return [[pluginBundle.principalClass alloc] initWithPluginManager:manager]; +} + +- (instancetype)initWithPluginManager:(MPPluginManager *)manager { + self = [super init]; + return self; +} + +- (NSString *)identifier { + NSBundle *bundle = [NSBundle bundleForClass:[self class]]; + if(bundle && bundle.bundleIdentifier) { + return bundle.bundleIdentifier; + } + return [NSString stringWithFormat:@"unknown.bundle.identifier"]; +} + +- (NSString *)name { + NSString *name = [self.identifier componentsSeparatedByString:@"."].lastObject; + return nil == name ? @"Unkown Plugin" : name; +} + +- (NSString *)version { + NSBundle *bundle = [NSBundle bundleForClass:[self class]]; + NSString *version; + if(bundle) { + version = bundle.infoDictionary[(NSString *)kCFBundleVersionKey]; + if(version) { + return version; + } + } + return @"unknown.version"; +} + ++ (BOOL)_validURL:(NSURL *)url { + return (NSOrderedSame == [url.pathExtension compare:kMPPluginFileExtension options:NSCaseInsensitiveSearch]); +} + ++ (BOOL)_validateClass:(Class)class { + return ([class isSubclassOfClass:[MPPlugin class]]); +} + +/* Code by Jedda Wignall http://jedda.me/2012/03/verifying-plugin-bundles-using-code-signing/ */ ++ (BOOL)_validSignature:(NSURL *)url { + if(!url.path) { + return NO; + } + NSTask * task = [[NSTask alloc] init]; + NSPipe * pipe = [NSPipe pipe]; + NSArray* args = @[ @"--verify", + /*[NSString stringWithFormat:@"-R=anchor = \"%@\"", [[NSBundle mainBundle] pathForResource:@"BlargsoftCodeCA" ofType:@"cer"]],*/ + url.path ]; + task.launchPath = @"/usr/bin/codesign"; + task.standardOutput = pipe; + task.standardError = pipe; + task.arguments = args; + [task launch]; + [task waitUntilExit]; + + if(task.terminationStatus == 0) { + return YES; + } + NSString * taskString = [[NSString alloc] initWithData:pipe.fileHandleForReading.readDataToEndOfFile encoding:NSASCIIStringEncoding]; + if ([taskString rangeOfString:@"modified"].length > 0 || [taskString rangeOfString:@"a sealed resource is missing or invalid"].length > 0) { + // The plugin has been modified or resources removed since being signed. You probably don't want to load this. + NSLog(@"Plugin modified - not loaded"); // log a real error here + } + else if ([taskString rangeOfString:@"failed to satisfy"].length > 0) { + // The plugin is missing resources since being signed. Don't load. + // throw an error + NSLog(@"Plugin not signed by correct CA - not loaded"); // log a real error here + } + else if ([taskString rangeOfString:@"not signed at all"].length > 0) { + // The plugin was not code signed at all. Don't load. + NSLog(@"Plugin not signed at all - don't load."); // log a real error here + } + else { + // Some other codesign error + } + return NO; +} + +@end diff --git a/MacPass/MPPluginManager.h b/MacPass/MPPluginManager.h index ad395ced..1e97c6d3 100644 --- a/MacPass/MPPluginManager.h +++ b/MacPass/MPPluginManager.h @@ -9,14 +9,22 @@ #import @class KPKNode; +@class MPPlugin; @interface MPPluginManager : NSObject +@property (readonly, copy) NSArray *plugins; + typedef BOOL (^NodeMatchBlock)(KPKNode *aNode); + (instancetype)sharedManager; +- (instancetype)init NS_UNAVAILABLE; + - (NSArray *)filteredEntriesUsingBlock:(NodeMatchBlock) matchBlock; - (NSArray *)filteredGroupsUsingBlock:(NodeMatchBlock) matchBlock; +- (void)loadPlugins; +- (void)installPluginAtURL:(NSURL *)url; + @end diff --git a/MacPass/MPPluginManager.m b/MacPass/MPPluginManager.m index 51f98ee6..92a08701 100644 --- a/MacPass/MPPluginManager.m +++ b/MacPass/MPPluginManager.m @@ -9,9 +9,17 @@ #import "MPPluginManager.h" #import "MPDocument.h" +#import "MPPlugin.h" +#import "NSApplication+MPAdditions.h" #import "KeePassKit/KeePassKit.h" +@interface MPPluginManager () + +@property (strong) NSMutableArray *mutablePlugins; + +@end + @implementation MPPluginManager + (instancetype)sharedManager { @@ -29,9 +37,16 @@ - (instancetype)_init { self = [super init]; + if(self) { + _mutablePlugins = [[NSMutableArray alloc] init]; + } return self; } +- (NSArray *)plugins { + return [self.mutablePlugins copy]; +} + - (NSArray *)filteredEntriesUsingBlock:(NodeMatchBlock)matchBlock { NSArray *currentDocuments = [[NSDocumentController sharedDocumentController] documents]; NSMutableArray *entries = [[NSMutableArray alloc] initWithCapacity:200]; @@ -48,8 +63,18 @@ return nil; } -- (void)_loadPlugins { - +- (void)loadPlugins { + NSURL *dir = [NSApp applicationSupportDirectoryURL:YES]; + NSError *error; + NSArray *contentURLs = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:dir includingPropertiesForKeys:@[] options:NSDirectoryEnumerationSkipsHiddenFiles error:&error]; + if(!contentURLs) { + NSLog(@"Error while trying to locate Plugins: %@", error.localizedDescription); + } + for(NSURL *pluginURL in contentURLs) { + MPPlugin *plugin = [MPPlugin pluginWithBundleURL:pluginURL pluginManager:self]; + if(plugin) { + [self.mutablePlugins addObject:plugin]; + } + } } - @end diff --git a/MacPass/MPPluginSettingsController.m b/MacPass/MPPluginSettingsController.m index 5af5fc3f..b390aba1 100644 --- a/MacPass/MPPluginSettingsController.m +++ b/MacPass/MPPluginSettingsController.m @@ -7,12 +7,15 @@ // #import "MPPluginSettingsController.h" +#import "MPPluginManager.h" +#import "MPPlugin.h" NSString *const _kMPPluginTableNameColumn = @"Name"; -NSString *const _kMPPluginTableLoadedColumn = @"Loaded"; -@interface MPPluginSettingsController () +@interface MPPluginSettingsController () + @property (weak) IBOutlet NSTableView *pluginTableView; +@property (weak) IBOutlet NSView *settingsView; @end @@ -36,26 +39,52 @@ NSString *const _kMPPluginTableLoadedColumn = @"Loaded"; - (void)didLoadView { self.pluginTableView.tableColumns[0].identifier = _kMPPluginTableNameColumn; - self.pluginTableView.tableColumns[1].identifier = _kMPPluginTableLoadedColumn; - self.pluginTableView.tableColumns[0].title = NSLocalizedString(@"PLUGIN_TABLE_NAME_HEADER", ""); - self.pluginTableView.tableColumns[1].title = NSLocalizedString(@"PLUGIN_TABLE_LOAD_HEADER", ""); - - //self.pluginTableView.delegate = self; + + self.pluginTableView.delegate = self; self.pluginTableView.dataSource = self; + } - (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView { - return 2; + return [MPPluginManager sharedManager].plugins.count; } -- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row { - if([tableColumn.identifier isEqualToString:_kMPPluginTableLoadedColumn]) { - return @YES; +- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row { + if(![tableColumn.identifier isEqualToString:_kMPPluginTableNameColumn]) { + return nil; } - else if([tableColumn.identifier isEqualToString:_kMPPluginTableNameColumn]) { - return @"DummyPlugin"; - } - return nil; + MPPlugin *plugin = [self pluginForRow:row]; + NSTableCellView *view = [tableView makeViewWithIdentifier:@"NameCell" owner:nil]; + view.textField.stringValue = plugin.name; + return view; } +- (void)showSettingsForPlugin:(MPPlugin *)plugin { + /* move old one regardless */ + [self.settingsView.subviews.firstObject removeFromSuperview]; + if([plugin conformsToProtocol:@protocol(MPPluginSettings)]) { + NSAssert([plugin respondsToSelector:@selector(settingsViewController)], @"Required getter for settings on plugins"); + NSViewController *viewController = ((id)plugin).settingsViewController; + [self.settingsView addSubview:viewController.view]; + NSDictionary *dict = @{ @"view" : viewController.view, + @"table" : self.pluginTableView.enclosingScrollView }; + [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[view]-0-|" options:0 metrics:nil views:dict]]; + [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[view]-0-|" options:0 metrics:nil views:dict]]; + } +} + +- (MPPlugin *)pluginForRow:(NSInteger)row { + NSArray *plugins = [MPPluginManager sharedManager].plugins; + if(0 > row || row >= plugins.count) { + return nil; + } + return plugins[row]; +} + +- (void)tableViewSelectionDidChange:(NSNotification *)notification { + NSTableView *table = notification.object; + [self showSettingsForPlugin:[self pluginForRow:table.selectedRow]]; +} + + @end diff --git a/MacPass/MPServerRequestHandling.h b/MacPass/MPServerRequestHandling.h deleted file mode 100644 index 31db1106..00000000 --- a/MacPass/MPServerRequestHandling.h +++ /dev/null @@ -1,30 +0,0 @@ -// -// MPServerRequestHandler.h -// MacPass -// -// Created by Michael Starke on 17.06.13. -// Copyright (c) 2013 HicknHack Software GmbH. All rights reserved. -// - -#import - -/** - * Protocol for request handling of KeePassHttp request - */ -@protocol MPServerRequestHandling - -@required -/** - * A unique identifier for the request handler - * - * @return NSString representing the identifier - */ -- (NSString *)identifier; -/** - * Formulate a response to the request passed in as Dictionary - * - * @param data An NSDictionary containing the parsed JSON request - */ -- (void)respondTo:(NSDictionary *)data; - -@end diff --git a/MacPass/MPSettingsHelper.h b/MacPass/MPSettingsHelper.h index 4ece7f62..134c1359 100644 --- a/MacPass/MPSettingsHelper.h +++ b/MacPass/MPSettingsHelper.h @@ -20,11 +20,6 @@ APPKIT_EXTERN NSString *const kMPSettingsKeyReopenLastDatabaseOnLaunch; /* URL handling */ APPKIT_EXTERN NSString *const kMPSettingsKeyBrowserBundleId; -/* Server Settings */ -APPKIT_EXTERN NSString *const kMPSettingsKeyHttpPort; -APPKIT_EXTERN NSString *const kMPSettingsKeyEnableHttpServer; -APPKIT_EXTERN NSString *const kMPSettingsKeyShowMenuItem; - /* Autolock */ APPKIT_EXTERN NSString *const kMPSettingsKeyLockOnSleep; APPKIT_EXTERN NSString *const kMPSettingsKeyIdleLockTimeOut; @@ -65,6 +60,9 @@ APPKIT_EXTERN NSString *const kMPSettingsKeyEnableQuicklookPreview; APPKIT_EXTERN NSString *const kMPSettingsKeyDoubleClickURLAction; APPKIT_EXTERN NSString *const kMPSettingsKeyDoubleClickTitleAction; +/* Plugins */ +APPKIT_EXTERN NSString *const kMPSettingsKeyLoadUnsecurePlugins; // If set to YES this will load all plugins regardless of their codesignature status + typedef NS_ENUM(NSUInteger, MPDoubleClickURLAction) { MPDoubleClickURLActionCopy, MPDoubleClickURLActionOpen, diff --git a/MacPass/MPSettingsHelper.m b/MacPass/MPSettingsHelper.m index 59422a6a..0bc3e7ca 100644 --- a/MacPass/MPSettingsHelper.m +++ b/MacPass/MPSettingsHelper.m @@ -16,9 +16,6 @@ NSString *const kMPSettingsKeyClearPasteboardOnQuit = @"ClearC NSString *const kMPSettingsKeyBrowserBundleId = @"BrowserBundleId"; NSString *const kMPSettingsKeyOpenEmptyDatabaseOnLaunch = @"OpenEmptyDatabaseOnLaunch"; NSString *const kMPSettingsKeyReopenLastDatabaseOnLaunch = @"ReopenLastDatabaseOnLaunch"; -NSString *const kMPSettingsKeyHttpPort = @"HttpPort"; -NSString *const kMPSettingsKeyEnableHttpServer = @"EnableHttpServer"; -NSString *const kMPSettingsKeyShowMenuItem = @"ShowMenuItem"; NSString *const kMPSettingsKeyLockOnSleep = @"LockOnSleep"; NSString *const kMPSettingsKeyIdleLockTimeOut = @"IdleLockTimeOut"; NSString *const kMPSettingsKeyShowInspector = @"ShowInspector"; @@ -60,12 +57,18 @@ NSString *const kMPSettingsKeyPasswordDefaultsForEntry = @"Passwo NSString *const kMPSettingsKeyDoubleClickURLAction = @"DoubleClickURLAction"; NSString *const kMPSettingsKeyDoubleClickTitleAction = @"DoubleClickTitleAction"; +NSString *const kMPSettingsKeyLoadUnsecurePlugins = @"MPLoadUnsecurePlugins"; + /* Deprecated */ NSString *const kMPDeprecatedSettingsKeyRememberKeyFilesForDatabases = @"kMPSettingsKeyRememberKeyFilesForDatabases"; NSString *const kMPDeprecatedSettingsKeyLastDatabasePath = @"MPLastDatabasePath"; NSString *const kMPDeprecatedSettingsKeyDocumentsAutotypeFixNoteWasShown = @"DocumentsAutotypeFixNoteWasShown"; NSString *const kMPDeprecatedSettingsKeyDoubleClickURLToLaunch = @"DoubleClickURLToLaunch"; NSString *const kMPDeprecatedSettingsKeyEntrySearchFilterMode = @"EntrySearchFilterMode"; +NSString *const kMPDeprecatedSettingsKeyHttpPort = @"HttpPort"; +NSString *const kMPDeprecatedSettingsKeyEnableHttpServer = @"EnableHttpServer"; +NSString *const kMPDeprecatedSettingsKeyShowMenuItem = @"ShowMenuItem"; + @implementation MPSettingsHelper @@ -94,9 +97,6 @@ NSString *const kMPDeprecatedSettingsKeyEntrySearchFilterMode = @"En kMPSettingsKeyClearPasteboardOnQuit: @YES, kMPSettingsKeyOpenEmptyDatabaseOnLaunch: @NO, kMPSettingsKeyReopenLastDatabaseOnLaunch: @YES, - kMPSettingsKeyHttpPort: @19455, - kMPSettingsKeyEnableHttpServer: @NO, - kMPSettingsKeyShowMenuItem: @YES, kMPSettingsKeyLockOnSleep: @YES, kMPSettingsKeyIdleLockTimeOut: @0, // 5 minutes kMPSettingsKeyLegacyHideNotes: @NO, @@ -121,7 +121,8 @@ NSString *const kMPDeprecatedSettingsKeyEntrySearchFilterMode = @"En kMPSettingsKeyPasswordUseCustomString: @NO, kMPSettingsKeyPasswordCustomString: @"", kMPSettingsKeyDoubleClickURLAction: @(MPDoubleClickURLActionCopy), - kMPSettingsKeyDoubleClickTitleAction: @(MPDoubleClickTitleActionInspect) + kMPSettingsKeyDoubleClickTitleAction: @(MPDoubleClickTitleActionInspect), + kMPSettingsKeyLoadUnsecurePlugins: @NO }; }); return standardDefaults; @@ -135,7 +136,12 @@ NSString *const kMPDeprecatedSettingsKeyEntrySearchFilterMode = @"En kMPDeprecatedSettingsKeyLastDatabasePath, kMPDeprecatedSettingsKeyDocumentsAutotypeFixNoteWasShown, kMPDeprecatedSettingsKeyDoubleClickURLToLaunch, - kMPDeprecatedSettingsKeyEntrySearchFilterMode]; + kMPDeprecatedSettingsKeyEntrySearchFilterMode, + /* Moved to KeePassHttp Plugin */ + kMPDeprecatedSettingsKeyHttpPort, + kMPDeprecatedSettingsKeyEnableHttpServer, + kMPDeprecatedSettingsKeyShowMenuItem + ]; }); return deprecatedSettings; } diff --git a/MacPass/MacPass-Info.plist b/MacPass/MacPass-Info.plist index 6ede688d..47ffc93a 100644 --- a/MacPass/MacPass-Info.plist +++ b/MacPass/MacPass-Info.plist @@ -124,6 +124,25 @@ + + UTTypeConformsTo + + com.apple.package + + UTTypeDescription + MacPass Plugin + UTTypeIdentifier + com.hicknhack.macpass.plugin + UTTypeTagSpecification + + public.filename-extension + + mpplugin + mpPlugin + mpPlugIn + + + diff --git a/MacPass/NSApplication+MPAdditions.h b/MacPass/NSApplication+MPAdditions.h new file mode 100644 index 00000000..f2e88508 --- /dev/null +++ b/MacPass/NSApplication+MPAdditions.h @@ -0,0 +1,22 @@ +// +// NSApplication+MPAdditions.h +// MacPass +// +// Created by Michael Starke on 10/11/15. +// Copyright © 2015 HicknHack Software GmbH. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface NSApplication (MPAdditions) + +@property (copy, readonly) NSString *applicationName; +@property (copy, readonly, nullable) NSURL *applicationSupportDirectoryURL; + +- (NSURL * _Nullable)applicationSupportDirectoryURL:(BOOL)create; + +@end + +NS_ASSUME_NONNULL_END diff --git a/MacPass/NSApplication+MPAdditions.m b/MacPass/NSApplication+MPAdditions.m new file mode 100644 index 00000000..d95a86ac --- /dev/null +++ b/MacPass/NSApplication+MPAdditions.m @@ -0,0 +1,41 @@ +// +// NSApplication+MPAdditions.m +// MacPass +// +// Created by Michael Starke on 10/11/15. +// Copyright © 2015 HicknHack Software GmbH. All rights reserved. +// + +#import "NSApplication+MPAdditions.h" + +@implementation NSApplication (MPAdditions) + +- (NSString *)applicationName { + return [[NSBundle mainBundle].infoDictionary[@"CFBundleName"] copy]; +} + +- (NSURL *)applicationSupportDirectoryURL { + return [self applicationSupportDirectoryURL:NO]; +} + +- (NSURL *)applicationSupportDirectoryURL:(BOOL)create { + NSError *error; + NSURL *url = [[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory + inDomain:NSUserDomainMask + appropriateForURL:nil + create:NO + error:&error]; + if(url) { + url = [url URLByAppendingPathComponent:self.applicationName isDirectory:YES]; + if(create) { + [[NSFileManager defaultManager] createDirectoryAtURL:url + withIntermediateDirectories:YES + attributes:nil + error:&error]; + } + return url; + } + return nil; +} + +@end diff --git a/MacPass/PluginSettings.xib b/MacPass/PluginSettings.xib index bbfdcea9..3807916a 100644 --- a/MacPass/PluginSettings.xib +++ b/MacPass/PluginSettings.xib @@ -1,36 +1,41 @@ - + - + + - + + + + + - + - + - - + + - + @@ -42,18 +47,27 @@ - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + @@ -62,7 +76,8 @@ - + + - - - - - + + + - - + + - +