From 6bac1836069d4ee8510b750966ac04c35da34994 Mon Sep 17 00:00:00 2001 From: michael starke Date: Thu, 12 Nov 2015 18:59:54 +0100 Subject: [PATCH] Extenden Plugin system Plugin Settings now properly display plugins Plugins are loaded/unloaded based on security settings Signed-off-by: michael starke --- MacPass.xcodeproj/project.pbxproj | 16 ++- MacPass/Base.lproj/GeneralSettings.xib | 5 +- MacPass/{ => Base.lproj}/PluginSettings.xib | 74 ++++++++--- MacPass/Base.lproj/UpdateSettings.xib | 4 +- MacPass/Base.lproj/WorkflowSettings.xib | 4 +- MacPass/MPAppDelegate.m | 4 +- MacPass/MPPlugin.h | 2 - MacPass/MPPlugin.m | 62 +-------- MacPass/MPPluginManager.h | 11 +- MacPass/MPPluginManager.m | 135 +++++++++++++++++++- MacPass/MPPluginSettingsController.m | 49 ++++++- 11 files changed, 262 insertions(+), 104 deletions(-) rename MacPass/{ => Base.lproj}/PluginSettings.xib (60%) diff --git a/MacPass.xcodeproj/project.pbxproj b/MacPass.xcodeproj/project.pbxproj index 1de00db4..1c3b2621 100644 --- a/MacPass.xcodeproj/project.pbxproj +++ b/MacPass.xcodeproj/project.pbxproj @@ -16,6 +16,7 @@ 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 */; }; + 4C0DBEF51BF508DE00F9B287 /* PluginSettings.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C0DBEF71BF508DE00F9B287 /* PluginSettings.xib */; }; 4C0DD6C618B2A44700FCB193 /* AutotypeCandidateSelectionWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C0DD6C518B2A44700FCB193 /* AutotypeCandidateSelectionWindow.xib */; }; 4C0F647817B6B65E00D9522A /* MPSheetWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C0F647717B6B65E00D9522A /* MPSheetWindowController.m */; }; 4C0F647B17B6BC9C00D9522A /* MPSavePanelAccessoryViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C0F647A17B6BC9C00D9522A /* MPSavePanelAccessoryViewController.m */; }; @@ -31,7 +32,6 @@ 4C1FA07B18231900003A3F8C /* MPDocument+Autotype.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C1FA07A18231900003A3F8C /* MPDocument+Autotype.m */; }; 4C224B4217DFCB2400FF6AEE /* MPNumericalInputFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C224B4117DFCB2400FF6AEE /* MPNumericalInputFormatter.m */; }; 4C25703F1BF11C2300D39416 /* MPPluginSettingsController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C25703D1BF11C2300D39416 /* MPPluginSettingsController.m */; }; - 4C2570401BF11C2300D39416 /* PluginSettings.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C25703E1BF11C2300D39416 /* PluginSettings.xib */; }; 4C25D58716CF0FAA00F6806C /* EntryView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C25D58616CF0FAA00F6806C /* EntryView.xib */; }; 4C26C33F18D8C92100CF1A1C /* MPTemporaryFileStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C26C33E18D8C92100CF1A1C /* MPTemporaryFileStorage.m */; }; 4C26C34B18D8D5A300CF1A1C /* MPPreviewViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C26C34918D8D5A300CF1A1C /* MPPreviewViewController.m */; }; @@ -373,6 +373,7 @@ 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; }; + 4C0DBEF61BF508DE00F9B287 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/PluginSettings.xib; sourceTree = ""; }; 4C0DD6C518B2A44700FCB193 /* AutotypeCandidateSelectionWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = AutotypeCandidateSelectionWindow.xib; sourceTree = ""; }; 4C0F647617B6B65E00D9522A /* MPSheetWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPSheetWindowController.h; sourceTree = ""; }; 4C0F647717B6B65E00D9522A /* MPSheetWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPSheetWindowController.m; sourceTree = ""; }; @@ -397,7 +398,6 @@ 4C224B4117DFCB2400FF6AEE /* MPNumericalInputFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPNumericalInputFormatter.m; sourceTree = ""; }; 4C25703C1BF11C2300D39416 /* MPPluginSettingsController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPPluginSettingsController.h; sourceTree = ""; }; 4C25703D1BF11C2300D39416 /* MPPluginSettingsController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPluginSettingsController.m; sourceTree = ""; }; - 4C25703E1BF11C2300D39416 /* PluginSettings.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PluginSettings.xib; sourceTree = ""; }; 4C25D58616CF0FAA00F6806C /* EntryView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = EntryView.xib; sourceTree = ""; }; 4C26C33D18D8C92100CF1A1C /* MPTemporaryFileStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPTemporaryFileStorage.h; sourceTree = ""; }; 4C26C33E18D8C92100CF1A1C /* MPTemporaryFileStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPTemporaryFileStorage.m; sourceTree = ""; }; @@ -1466,7 +1466,7 @@ 6021FE5818E1429500C3BC51 /* IntegrationSettings.xib */, 6021FE6318E15D9100C3BC51 /* WorkflowSettings.xib */, 6021FE6E18E15E6D00C3BC51 /* UpdateSettings.xib */, - 4C25703E1BF11C2300D39416 /* PluginSettings.xib */, + 4C0DBEF71BF508DE00F9B287 /* PluginSettings.xib */, ); name = Settings; sourceTree = ""; @@ -1768,7 +1768,7 @@ 4C7ABA4E17BAEC7000FF5799 /* addEntryTemplate.pdf in Resources */, 4C53A7A51864C39D000DFF0D /* KPKLocalizable.strings in Resources */, 4C3826761AD04C24007D7D67 /* harddiskTemplate.pdf in Resources */, - 4C2570401BF11C2300D39416 /* PluginSettings.xib in Resources */, + 4C0DBEF51BF508DE00F9B287 /* PluginSettings.xib in Resources */, 4C7F8B681A10B68400CCB83D /* WelcomeWindow.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1942,6 +1942,14 @@ /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ + 4C0DBEF71BF508DE00F9B287 /* PluginSettings.xib */ = { + isa = PBXVariantGroup; + children = ( + 4C0DBEF61BF508DE00F9B287 /* Base */, + ); + name = PluginSettings.xib; + sourceTree = ""; + }; 4C45FB21178E09ED0010007D /* InfoPlist.strings */ = { isa = PBXVariantGroup; children = ( diff --git a/MacPass/Base.lproj/GeneralSettings.xib b/MacPass/Base.lproj/GeneralSettings.xib index 8a083e67..eb480138 100644 --- a/MacPass/Base.lproj/GeneralSettings.xib +++ b/MacPass/Base.lproj/GeneralSettings.xib @@ -1,8 +1,8 @@ - + - + @@ -218,6 +218,7 @@ + diff --git a/MacPass/PluginSettings.xib b/MacPass/Base.lproj/PluginSettings.xib similarity index 60% rename from MacPass/PluginSettings.xib rename to MacPass/Base.lproj/PluginSettings.xib index 3807916a..52dc9c07 100644 --- a/MacPass/PluginSettings.xib +++ b/MacPass/Base.lproj/PluginSettings.xib @@ -3,32 +3,58 @@ + + - + - + - - + + + + + + + - + + + + + + + + + + + + + - + - + - + @@ -52,8 +78,8 @@ - - + + @@ -62,6 +88,11 @@ + + + + + @@ -77,7 +108,7 @@ - + - - - - - - - + + + + + + + + + + + + - + diff --git a/MacPass/Base.lproj/UpdateSettings.xib b/MacPass/Base.lproj/UpdateSettings.xib index f1c73b4e..6c644edd 100644 --- a/MacPass/Base.lproj/UpdateSettings.xib +++ b/MacPass/Base.lproj/UpdateSettings.xib @@ -1,8 +1,8 @@ - + - + diff --git a/MacPass/Base.lproj/WorkflowSettings.xib b/MacPass/Base.lproj/WorkflowSettings.xib index 8d966f55..dbf4d44e 100644 --- a/MacPass/Base.lproj/WorkflowSettings.xib +++ b/MacPass/Base.lproj/WorkflowSettings.xib @@ -1,8 +1,8 @@ - + - + diff --git a/MacPass/MPAppDelegate.m b/MacPass/MPAppDelegate.m index 71a66f3b..f0f6bc40 100644 --- a/MacPass/MPAppDelegate.m +++ b/MacPass/MPAppDelegate.m @@ -156,8 +156,8 @@ NSString *const MPDidChangeStoredKeyFilesSettings = @"com.hicknhack.macpass.MPDi /* Daemon instanziieren */ [MPLockDaemon defaultDaemon]; [MPAutotypeDaemon defaultDaemon]; - /* Load plugins */ - [[MPPluginManager sharedManager] loadPlugins]; + /* Create Plugin Manager */ + [MPPluginManager sharedManager]; } #pragma mark - diff --git a/MacPass/MPPlugin.h b/MacPass/MPPlugin.h index 4a29a864..e9eb0471 100644 --- a/MacPass/MPPlugin.h +++ b/MacPass/MPPlugin.h @@ -20,8 +20,6 @@ FOUNDATION_EXPORT NSString *const kMPPluginFileExtension; @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; diff --git a/MacPass/MPPlugin.m b/MacPass/MPPlugin.m index de4b2712..949c8719 100644 --- a/MacPass/MPPlugin.m +++ b/MacPass/MPPlugin.m @@ -8,25 +8,12 @@ #import "MPPlugin.h" #import "MPPluginManager.h" +#import "MPSettingsHelper.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; @@ -57,52 +44,5 @@ NSString *const kMPPluginFileExtension = @"mpplugin"; 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 1e97c6d3..6a2649b0 100644 --- a/MacPass/MPPluginManager.h +++ b/MacPass/MPPluginManager.h @@ -8,12 +8,20 @@ #import +FOUNDATION_EXPORT NSString *const MPPluginManagerWillLoadPlugin; +FOUNDATION_EXPORT NSString *const MPPluginManagerDidLoadPlugin; +FOUNDATION_EXPORT NSString *const MPPluginManagerWillUnloadPlugin; +FOUNDATION_EXPORT NSString *const MPPluginManagerDidUnloadPlugin; + +FOUNDATION_EXPORT NSString *const MPPluginManagerPluginBundleIdentifiyerKey; + @class KPKNode; @class MPPlugin; @interface MPPluginManager : NSObject @property (readonly, copy) NSArray *plugins; +@property (nonatomic, readonly) BOOL loadUnsecurePlugins; typedef BOOL (^NodeMatchBlock)(KPKNode *aNode); @@ -24,7 +32,4 @@ typedef BOOL (^NodeMatchBlock)(KPKNode *aNode); - (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 92a08701..6aa6d1fc 100644 --- a/MacPass/MPPluginManager.m +++ b/MacPass/MPPluginManager.m @@ -11,17 +11,32 @@ #import "MPDocument.h" #import "MPPlugin.h" #import "NSApplication+MPAdditions.h" +#import "MPSettingsHelper.h" #import "KeePassKit/KeePassKit.h" + +NSString *const MPPluginManagerWillLoadPlugin = @"com.hicknhack.macpass.MPPluginManagerWillLoadPlugin"; +NSString *const MPPluginManagerDidLoadPlugin = @"comt.hicknhack.macpass.MPPluginManagerDidLoadPlugin"; +NSString *const MPPluginManagerWillUnloadPlugin = @"com.hicknhack.macpass.MPPluginManagerWillUnloadPlugin"; +NSString *const MPPluginManagerDidUnloadPlugin = @"com.hicknhack.macpass.MPPluginManagerDidUnloadPlugin"; + +NSString *const MPPluginManagerPluginBundleIdentifiyerKey = @"MPPluginManagerPluginBundleIdentifiyerKey"; + + @interface MPPluginManager () @property (strong) NSMutableArray *mutablePlugins; +@property (nonatomic) BOOL loadUnsecurePlugins; @end @implementation MPPluginManager ++ (NSSet *)keyPathsForValuesAffectingPlugins { + return [NSSet setWithObject:NSStringFromSelector(@selector(mutablePlugins))]; +} + + (instancetype)sharedManager { static MPPluginManager *instance; static dispatch_once_t onceToken; @@ -39,10 +54,24 @@ self = [super init]; if(self) { _mutablePlugins = [[NSMutableArray alloc] init]; + _loadUnsecurePlugins = [[NSUserDefaults standardUserDefaults] boolForKey:kMPSettingsKeyLoadUnsecurePlugins]; + [self _loadPlugins]; + + [self bind:NSStringFromSelector(@selector(loadUnsecurePlugins)) + toObject:[NSUserDefaultsController sharedUserDefaultsController] + withKeyPath:[MPSettingsHelper defaultControllerPathForKey:kMPSettingsKeyLoadUnsecurePlugins] + options:nil]; } return self; } +- (void)setLoadUnsecurePlugins:(BOOL)loadUnsecurePlugins { + if(_loadUnsecurePlugins != loadUnsecurePlugins) { + _loadUnsecurePlugins = loadUnsecurePlugins; + [self _loadPlugins]; + } +} + - (NSArray *)plugins { return [self.mutablePlugins copy]; } @@ -60,21 +89,121 @@ } - (NSArray *)filteredGroupsUsingBlock:(NodeMatchBlock)matchBlock { + NSAssert(NO, @"Not implemented"); return nil; } -- (void)loadPlugins { +- (void)_unloadPlugins { + /* TODO Notofications for UI */ + NSMutableArray *bundles = [[NSMutableArray alloc] initWithCapacity:self.mutablePlugins.count]; + for(MPPlugin *plugin in self.mutablePlugins) { + NSBundle *pluginBundle = [NSBundle bundleForClass:plugin.class]; + if(pluginBundle) { + [bundles addObject:pluginBundle]; + [[NSNotificationCenter defaultCenter] postNotificationName:MPPluginManagerWillUnloadPlugin object:self userInfo:@{ MPPluginManagerPluginBundleIdentifiyerKey : plugin.identifier}]; + } + } + [self.mutablePlugins removeAllObjects]; + for(NSBundle *bundle in bundles) { + [bundle unload]; + NSString *identifiery = bundle.bundleIdentifier ? bundle.bundleIdentifier : @"unknown"; + [[NSNotificationCenter defaultCenter] postNotificationName:MPPluginManagerDidUnloadPlugin object:self userInfo:@{ MPPluginManagerPluginBundleIdentifiyerKey : identifiery }]; + } +} + +- (void)_loadPlugins { + /* unload all plugins just to be sure */ + [self _unloadPlugins]; NSURL *dir = [NSApp applicationSupportDirectoryURL:YES]; NSError *error; - NSArray *contentURLs = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:dir includingPropertiesForKeys:@[] options:NSDirectoryEnumerationSkipsHiddenFiles error:&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(![self _validURL:pluginURL]) { + continue; + } + + if(![self _validSignature:pluginURL]) { + continue; + } + + NSBundle *pluginBundle = [NSBundle bundleWithURL:pluginURL]; + if(!pluginBundle) { + continue; + } + + if(![self _validateClass:pluginBundle.principalClass]) { + continue; + } + MPPlugin *plugin = [[pluginBundle.principalClass alloc] initWithPluginManager:self]; if(plugin) { + [[NSNotificationCenter defaultCenter] postNotificationName:MPPluginManagerWillLoadPlugin object:self userInfo:@{ MPPluginManagerPluginBundleIdentifiyerKey : plugin.identifier }]; [self.mutablePlugins addObject:plugin]; + [[NSNotificationCenter defaultCenter] postNotificationName:MPPluginManagerDidLoadPlugin object:self userInfo:@{ MPPluginManagerPluginBundleIdentifiyerKey : plugin.identifier }]; } } } + +- (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; + } + + if(self.loadUnsecurePlugins) { + return YES; + } + + 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 *pluginPath = url.path ? url.path : @""; + 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", pluginPath); // 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", pluginPath); // 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.", pluginPath); // log a real error here + } + else { + NSLog(@"Unkown CodeSign Error!"); + } + + return NO; +} + + @end diff --git a/MacPass/MPPluginSettingsController.m b/MacPass/MPPluginSettingsController.m index b390aba1..766fa79c 100644 --- a/MacPass/MPPluginSettingsController.m +++ b/MacPass/MPPluginSettingsController.m @@ -10,17 +10,47 @@ #import "MPPluginManager.h" #import "MPPlugin.h" +#import "MPSettingsHelper.h" + NSString *const _kMPPluginTableNameColumn = @"Name"; @interface MPPluginSettingsController () @property (weak) IBOutlet NSTableView *pluginTableView; @property (weak) IBOutlet NSView *settingsView; +@property (weak) IBOutlet NSButton *loadInsecurePlugsinCheckButton; @end @implementation MPPluginSettingsController +- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if(self) { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(_didChangePlugins:) + name:MPPluginManagerWillLoadPlugin + object:[MPPluginManager sharedManager]]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(_didChangePlugins:) + name:MPPluginManagerDidLoadPlugin + object:[MPPluginManager sharedManager]]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(_didChangePlugins:) + name:MPPluginManagerWillUnloadPlugin + object:[MPPluginManager sharedManager]]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(_didChangePlugins:) + name:MPPluginManagerDidUnloadPlugin + object:[MPPluginManager sharedManager]]; + } + return self; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + - (NSString *)nibName { return @"PluginSettings"; } @@ -39,10 +69,15 @@ NSString *const _kMPPluginTableNameColumn = @"Name"; - (void)didLoadView { self.pluginTableView.tableColumns[0].identifier = _kMPPluginTableNameColumn; - + self.pluginTableView.delegate = self; self.pluginTableView.dataSource = self; - + + [self.loadInsecurePlugsinCheckButton bind:NSValueBinding + toObject:[NSUserDefaultsController sharedUserDefaultsController] + withKeyPath:[MPSettingsHelper defaultControllerPathForKey:kMPSettingsKeyLoadUnsecurePlugins] + options:nil]; + } - (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView { @@ -68,8 +103,8 @@ NSString *const _kMPPluginTableNameColumn = @"Name"; [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]]; + [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[view]-|" options:0 metrics:nil views:dict]]; + [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[view]-|" options:0 metrics:nil views:dict]]; } } @@ -87,4 +122,10 @@ NSString *const _kMPPluginTableNameColumn = @"Name"; } +- (void)_didChangePlugins:(NSNotification *)notification { + /* better way? */ + [self.pluginTableView deselectAll:self]; + [self.pluginTableView reloadData]; +} + @end