mirror of
https://github.com/MacPass/MacPass.git
synced 2025-12-13 21:42:32 +00:00
Plugin display is now more verbose
The plugin settings now displays more information about a failed plugin instead of just not displaying anything at all.
This commit is contained in:
@@ -644,6 +644,7 @@
|
||||
4C8B36A917A6ED4B005E1FF1 /* MPOutlineContextMenuDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPOutlineContextMenuDelegate.h; sourceTree = "<group>"; };
|
||||
4C8B36AA17A6ED4B005E1FF1 /* MPOutlineContextMenuDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPOutlineContextMenuDelegate.m; sourceTree = "<group>"; };
|
||||
4C8DEAA11C314D2C00D24C32 /* MPTestAutotypeDelay.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPTestAutotypeDelay.m; sourceTree = "<group>"; };
|
||||
4C8FB9FA1FC2D0EF003691AA /* MPPlugin_Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPPlugin_Private.h; sourceTree = "<group>"; };
|
||||
4C93C5701FBDFEF700F36855 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/AutotypeCandidateSelectionView.strings; sourceTree = "<group>"; };
|
||||
4C93C5711FBDFEF900F36855 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/AutotypeBuilderView.strings; sourceTree = "<group>"; };
|
||||
4C978E0C19AE54AB003067DF /* MPFlagsHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPFlagsHelper.m; sourceTree = "<group>"; };
|
||||
@@ -1541,6 +1542,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4CD034A41BFE113B003C002C /* MPPlugin.h */,
|
||||
4C8FB9FA1FC2D0EF003691AA /* MPPlugin_Private.h */,
|
||||
4CD034A51BFE113B003C002C /* MPPlugin.m */,
|
||||
4CD034A81BFE113B003C002C /* MPPluginHost.h */,
|
||||
4CD034A91BFE113B003C002C /* MPPluginHost.m */,
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="MPPluginSettingsController">
|
||||
<connections>
|
||||
<outlet property="addRemovePluginsControl" destination="B9Q-hq-K4N" id="Oqj-Ko-8UR"/>
|
||||
<outlet property="fallbackDescriptionTextField" destination="qPL-FR-ky7" id="xCb-ED-NIX"/>
|
||||
<outlet property="fallbackSettingsView" destination="wIk-iw-Tcz" id="dHl-zW-0aI"/>
|
||||
<outlet property="loadInsecurePlugsinCheckButton" destination="CqP-oK-S8k" id="YET-o6-7Cc"/>
|
||||
<outlet property="pluginTableView" destination="Ocu-C0-03d" id="jbH-qr-bVT"/>
|
||||
<outlet property="settingsView" destination="tD5-Na-7XI" id="Pa0-Tt-20U"/>
|
||||
@@ -26,6 +28,33 @@
|
||||
<view key="contentView" id="tD5-Na-7XI">
|
||||
<rect key="frame" x="1" y="1" width="326" height="349"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<customView translatesAutoresizingMaskIntoConstraints="NO" id="wIk-iw-Tcz">
|
||||
<rect key="frame" x="20" y="20" width="286" height="309"/>
|
||||
<subviews>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="qPL-FR-ky7">
|
||||
<rect key="frame" x="18" y="272" width="122" height="17"/>
|
||||
<textFieldCell key="cell" controlSize="mini" sendsActionOnEndEditing="YES" title="Plugin Settings Info" id="OOr-SW-jZb">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="qPL-FR-ky7" firstAttribute="top" secondItem="wIk-iw-Tcz" secondAttribute="top" constant="20" symbolic="YES" id="BAH-sF-W03"/>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="qPL-FR-ky7" secondAttribute="trailing" constant="20" symbolic="YES" id="HKa-7h-OiN"/>
|
||||
<constraint firstItem="qPL-FR-ky7" firstAttribute="leading" secondItem="wIk-iw-Tcz" secondAttribute="leading" constant="20" symbolic="YES" id="UTY-Lu-pvl"/>
|
||||
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="qPL-FR-ky7" secondAttribute="bottom" constant="20" symbolic="YES" id="wpb-76-pxa"/>
|
||||
</constraints>
|
||||
</customView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="wIk-iw-Tcz" firstAttribute="top" secondItem="tD5-Na-7XI" secondAttribute="top" constant="20" symbolic="YES" id="JEm-yQ-dbO"/>
|
||||
<constraint firstAttribute="trailing" secondItem="wIk-iw-Tcz" secondAttribute="trailing" constant="20" symbolic="YES" id="Zfc-6L-EPa"/>
|
||||
<constraint firstAttribute="bottom" secondItem="wIk-iw-Tcz" secondAttribute="bottom" constant="20" symbolic="YES" id="mGC-Qx-83s"/>
|
||||
<constraint firstItem="wIk-iw-Tcz" firstAttribute="leading" secondItem="tD5-Na-7XI" secondAttribute="leading" constant="20" symbolic="YES" id="phc-Nv-2hD"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</box>
|
||||
<button translatesAutoresizingMaskIntoConstraints="NO" id="CqP-oK-S8k">
|
||||
@@ -115,8 +144,8 @@
|
||||
<constraint firstAttribute="width" constant="150" id="ZpW-Bc-fSx"/>
|
||||
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="150" id="eXb-yq-O8y"/>
|
||||
</constraints>
|
||||
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="UK5-gt-5o5">
|
||||
<rect key="frame" x="1" y="133" width="148" height="16"/>
|
||||
<scroller key="horizontalScroller" verticalHuggingPriority="750" horizontal="YES" id="UK5-gt-5o5">
|
||||
<rect key="frame" x="1" y="328" width="148" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</scroller>
|
||||
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="oqL-7I-4H1">
|
||||
@@ -169,7 +198,7 @@
|
||||
<constraint firstItem="vBs-Ga-aq0" firstAttribute="leading" secondItem="fCk-fL-jU8" secondAttribute="trailing" constant="8" id="xNu-Sj-xQO"/>
|
||||
<constraint firstItem="aoG-FD-ds8" firstAttribute="top" secondItem="CqP-oK-S8k" secondAttribute="bottom" constant="8" symbolic="YES" id="zSW-h3-BrT"/>
|
||||
</constraints>
|
||||
<point key="canvasLocation" x="96" y="-112"/>
|
||||
<point key="canvasLocation" x="-344" y="-85"/>
|
||||
</customView>
|
||||
</objects>
|
||||
<resources>
|
||||
|
||||
@@ -33,6 +33,7 @@ FOUNDATION_EXPORT NSString *const kMPPluginFileExtension;
|
||||
@property (copy, readonly) NSString *identifier;
|
||||
@property (copy, readonly) NSString *name;
|
||||
@property (copy, readonly) NSString *version;
|
||||
@property (nonatomic, strong, readonly) NSBundle *bundle;
|
||||
|
||||
- (instancetype)initWithPluginHost:(MPPluginHost *)host NS_DESIGNATED_INITIALIZER;
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
//
|
||||
|
||||
#import "MPPlugin.h"
|
||||
#import "MPPlugin_Private.h"
|
||||
#import "MPPluginHost.h"
|
||||
#import "MPSettingsHelper.h"
|
||||
|
||||
@@ -28,15 +29,35 @@ NSString *const kMPPluginFileExtension = @"mpplugin";
|
||||
|
||||
@implementation MPPlugin
|
||||
|
||||
@synthesize bundle = _bundle;
|
||||
|
||||
- (instancetype)initWithPluginHost:(MPPluginHost *)host {
|
||||
self = [super init];
|
||||
if(self) {
|
||||
_enabled = YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSBundle *)bundle {
|
||||
if(_enabled) {
|
||||
return [NSBundle bundleForClass:self.class];
|
||||
}
|
||||
else {
|
||||
return _bundle;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setBundle:(NSBundle *)bundle {
|
||||
self.enabled = NO;
|
||||
if(_bundle != bundle) {
|
||||
_bundle = bundle;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)identifier {
|
||||
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
|
||||
if(bundle && bundle.bundleIdentifier) {
|
||||
return bundle.bundleIdentifier;
|
||||
if(self.bundle.bundleIdentifier) {
|
||||
return self.bundle.bundleIdentifier;
|
||||
}
|
||||
return [NSString stringWithFormat:@"unknown.bundle.identifier"];
|
||||
}
|
||||
@@ -47,10 +68,9 @@ NSString *const kMPPluginFileExtension = @"mpplugin";
|
||||
}
|
||||
|
||||
- (NSString *)version {
|
||||
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
|
||||
if(bundle) {
|
||||
NSString *humanVersion = bundle.infoDictionary[@"CFBundleShortVersionString"];
|
||||
NSString *version = bundle.infoDictionary[(NSString *)kCFBundleVersionKey];
|
||||
if(self.bundle) {
|
||||
NSString *humanVersion = self.bundle.infoDictionary[@"CFBundleShortVersionString"];
|
||||
NSString *version = self.bundle.infoDictionary[(NSString *)kCFBundleVersionKey];
|
||||
if(humanVersion && version) {
|
||||
return [NSString stringWithFormat:@"%@ (%@)", humanVersion, version];
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ FOUNDATION_EXPORT NSString *const MPPluginHostPluginBundleIdentifiyerKey;
|
||||
|
||||
@interface MPPluginHost : NSObject
|
||||
|
||||
/* List of all plugins known to the plugin manager. Disabled plugins are also present! */
|
||||
@property (readonly, copy) NSArray <MPPlugin __kindof*> *plugins;
|
||||
@property (nonatomic, readonly) BOOL loadUnsecurePlugins;
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#import "MPPluginHost.h"
|
||||
|
||||
#import "MPPlugin.h"
|
||||
#import "MPPlugin_Private.h"
|
||||
#import "NSApplication+MPAdditions.h"
|
||||
#import "MPSettingsHelper.h"
|
||||
|
||||
@@ -88,7 +89,7 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
|
||||
}
|
||||
|
||||
- (BOOL)installPluginAtURL:(NSURL *)url error:(NSError *__autoreleasing *)error {
|
||||
if(![self _validURL:url]) {
|
||||
if(![self _isValidPluginURL:url]) {
|
||||
if(error) {
|
||||
*error = [NSError errorWithCode:MPErrorInvalidPlugin description:NSLocalizedString(@"ERROR_INVALID_PLUGIN", @"Error description given when adding an invalid plugin")];
|
||||
}
|
||||
@@ -104,8 +105,7 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
|
||||
}
|
||||
|
||||
- (BOOL)uninstallPlugin:(MPPlugin *)plugin error:(NSError *__autoreleasing *)error {
|
||||
NSBundle *pluginBundle = [NSBundle bundleForClass:plugin.class];
|
||||
return [NSFileManager.defaultManager trashItemAtURL:pluginBundle.bundleURL resultingItemURL:nil error:error];
|
||||
return [NSFileManager.defaultManager trashItemAtURL:plugin.bundle.bundleURL resultingItemURL:nil error:error];
|
||||
}
|
||||
|
||||
- (void)disablePlugin:(MPPlugin *)plugin {
|
||||
@@ -120,17 +120,18 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
|
||||
- (void)_loadPlugins {
|
||||
NSURL *appSupportDir = [NSApp applicationSupportDirectoryURL:YES];
|
||||
NSError *error;
|
||||
NSLog(@"Looking for external plugins at %@.", appSupportDir.path);
|
||||
NSArray *externalPluginsURLs = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:appSupportDir
|
||||
includingPropertiesForKeys:@[]
|
||||
options:NSDirectoryEnumerationSkipsHiddenFiles
|
||||
error:&error];
|
||||
|
||||
NSLog(@"Looking for internal plugins");
|
||||
NSArray *internalPluginsURLs = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:[NSBundle mainBundle].builtInPlugInsURL
|
||||
includingPropertiesForKeys:@[]
|
||||
options:NSDirectoryEnumerationSkipsHiddenFiles
|
||||
error:&error];
|
||||
|
||||
|
||||
if(!externalPluginsURLs) {
|
||||
// No external plugins
|
||||
NSLog(@"No external plugins found!");
|
||||
@@ -142,29 +143,31 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
|
||||
NSArray *pluginURLs = [externalPluginsURLs arrayByAddingObjectsFromArray:internalPluginsURLs];
|
||||
|
||||
for(NSURL *pluginURL in pluginURLs) {
|
||||
|
||||
if(![self _validURL:pluginURL]) {
|
||||
if(![self _isValidPluginURL:pluginURL]) {
|
||||
NSLog(@"Skipping %@. No valid plugin file.", pluginURL.path);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(![self _validSignature:pluginURL]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
NSBundle *pluginBundle = [NSBundle bundleWithURL:pluginURL];
|
||||
if(!pluginBundle) {
|
||||
NSLog(@"Could not create bundle %@", pluginURL.path);
|
||||
NSLog(@"Could not access plugin bundle %@", pluginURL.path);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(pluginBundle.bundleIdentifier) {
|
||||
|
||||
if(![self _isSignedPluginURL:pluginURL]) {
|
||||
if(self.loadUnsecurePlugins) {
|
||||
NSLog(@"Loading unsecure Plugin at %@.", pluginURL.path);
|
||||
}
|
||||
else {
|
||||
[self _addPluginForBundle:pluginBundle error:NSLocalizedString(@"PLUGIN_ERROR_UNSECURE_PLUGIN", "Error for a plugin that was not signed properly")];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NSError *error;
|
||||
if(![pluginBundle preflightAndReturnError:&error]) {
|
||||
NSLog(@"Preflight Error %@ %@", error.localizedDescription, error.localizedFailureReason );
|
||||
[self _addPluginForBundle:pluginBundle error:error.localizedDescription];
|
||||
continue;
|
||||
};
|
||||
|
||||
@@ -175,11 +178,13 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
|
||||
|
||||
if(![pluginBundle loadAndReturnError:&error]) {
|
||||
NSLog(@"Bundle Loading Error %@ %@", error.localizedDescription, error.localizedFailureReason);
|
||||
[self _addPluginForBundle:pluginBundle error:error.localizedDescription];
|
||||
continue;
|
||||
}
|
||||
|
||||
if(![self _validateClass:pluginBundle.principalClass]) {
|
||||
if(![self _isValidPluginClass:pluginBundle.principalClass]) {
|
||||
NSLog(@"Wrong principal Class.");
|
||||
[self _addPluginForBundle:pluginBundle error:NSLocalizedString(@"PLUGIN_ERROR_WRONG_PRINCIPAL_CLASS", "Plugin specifies the wrong principla class!".)];
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -207,10 +212,19 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
|
||||
}
|
||||
else {
|
||||
NSLog(@"Unable to create instance of plugin class %@", pluginBundle.principalClass);
|
||||
[self _addPluginForBundle:pluginBundle error:NSLocalizedString(@"PLUGIN_ERROR_INTILIZATION_FAILED", "The plugin could not be initalized".)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_addPluginForBundle:(NSBundle *)bundle error:(NSString *)errorMessage {
|
||||
MPPlugin *plugin = [[MPPlugin alloc] initWithPluginHost:self];
|
||||
plugin.bundle = bundle;
|
||||
plugin.enabled = NO;
|
||||
plugin.errorMessage = errorMessage;
|
||||
[self.mutablePlugins addObject:plugin];
|
||||
}
|
||||
|
||||
- (BOOL)_validateUniqueBundle:(NSBundle *)bundle {
|
||||
for(MPPlugin *plugin in self.mutablePlugins) {
|
||||
NSBundle *pluginBundle = [NSBundle bundleForClass:plugin.class];
|
||||
@@ -221,24 +235,20 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)_validURL:(NSURL *)url {
|
||||
- (BOOL)_isValidPluginURL:(NSURL *)url {
|
||||
return (NSOrderedSame == [url.pathExtension compare:kMPPluginFileExtension options:NSCaseInsensitiveSearch]);
|
||||
}
|
||||
|
||||
- (BOOL)_validateClass:(Class)class {
|
||||
- (BOOL)_isValidPluginClass:(Class)class {
|
||||
return [class isSubclassOfClass:[MPPlugin class]];
|
||||
}
|
||||
|
||||
/* Code by Jedda Wignall<jedda@jedda.me> http://jedda.me/2012/03/verifying-plugin-bundles-using-code-signing/ */
|
||||
- (BOOL)_validSignature:(NSURL *)url {
|
||||
- (BOOL)_isSignedPluginURL:(NSURL *)url {
|
||||
if(!url.path) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
if(self.loadUnsecurePlugins) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
NSTask * task = [[NSTask alloc] init];
|
||||
NSPipe * pipe = [NSPipe pipe];
|
||||
NSArray* args = @[ @"--verify",
|
||||
@@ -258,16 +268,16 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
|
||||
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
|
||||
NSLog(@"Plugin %@ modified", 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
|
||||
NSLog(@"Plugin %@ not signed by correct CA", 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
|
||||
NSLog(@"Plugin %@ not signed at all.", pluginPath); // log a real error here
|
||||
}
|
||||
else {
|
||||
NSLog(@"Unkown CodeSign Error!");
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#import "MPPluginTabelCellView.h"
|
||||
#import "MPPluginHost.h"
|
||||
#import "MPPlugin.h"
|
||||
#import "MPPlugin_Private.h"
|
||||
|
||||
#import "MPConstants.h"
|
||||
#import "MPSettingsHelper.h"
|
||||
@@ -41,6 +42,8 @@ typedef NS_ENUM(NSUInteger, MPPluginSegmentType) {
|
||||
|
||||
@property (weak) IBOutlet NSTableView *pluginTableView;
|
||||
@property (weak) IBOutlet NSView *settingsView;
|
||||
@property (strong) IBOutlet NSView *fallbackSettingsView;
|
||||
@property (weak) IBOutlet NSTextField *fallbackDescriptionTextField;
|
||||
@property (weak) IBOutlet NSButton *loadInsecurePlugsinCheckButton;
|
||||
@property (weak) IBOutlet NSSegmentedControl *addRemovePluginsControl;
|
||||
|
||||
@@ -68,7 +71,7 @@ typedef NS_ENUM(NSUInteger, MPPluginSegmentType) {
|
||||
self.pluginTableView.delegate = self;
|
||||
self.pluginTableView.dataSource = self;
|
||||
[self.addRemovePluginsControl setEnabled:NO forSegment:MPRemovePluginSegment];
|
||||
|
||||
[self.fallbackSettingsView removeFromSuperview];
|
||||
[self.loadInsecurePlugsinCheckButton bind:NSValueBinding
|
||||
toObject:[NSUserDefaultsController sharedUserDefaultsController]
|
||||
withKeyPath:[MPSettingsHelper defaultControllerPathForKey:kMPSettingsKeyLoadUnsecurePlugins]
|
||||
@@ -77,7 +80,6 @@ typedef NS_ENUM(NSUInteger, MPPluginSegmentType) {
|
||||
}
|
||||
|
||||
# pragma mark - TableView
|
||||
|
||||
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
|
||||
return [MPPluginHost sharedHost].plugins.count;
|
||||
}
|
||||
@@ -85,7 +87,14 @@ typedef NS_ENUM(NSUInteger, MPPluginSegmentType) {
|
||||
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
|
||||
MPPlugin *plugin = [self pluginForRow:row];
|
||||
MPPluginTabelCellView *view = [tableView makeViewWithIdentifier:tableColumn.identifier owner:nil];
|
||||
view.textField.stringValue = [NSString stringWithFormat:@"%@", plugin.name];
|
||||
if(plugin.enabled) {
|
||||
view.textField.stringValue = plugin.name;
|
||||
}
|
||||
else {
|
||||
view.textField.stringValue = (plugin.errorMessage.length > 0
|
||||
? [NSString stringWithFormat:NSLocalizedString(@"PLUGIN_NAME_ERROR_%@", "Name for unloaded plugin with errors"), plugin.name]
|
||||
: [NSString stringWithFormat:NSLocalizedString(@"PLUGIN_NAME_DISABLED_%@", "name for disabled unloaded plugin"), plugin.name]);
|
||||
}
|
||||
view.addionalTextField.stringValue = [NSString stringWithFormat:NSLocalizedString(@"PLUGIN_VERSION_%@", "Plugin version. Include a %@ placeholder for version string"), plugin.version];
|
||||
return view;
|
||||
}
|
||||
@@ -93,14 +102,29 @@ typedef NS_ENUM(NSUInteger, MPPluginSegmentType) {
|
||||
- (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<MPPluginSettings>)plugin).settingsViewController;
|
||||
[self.settingsView addSubview:viewController.view];
|
||||
NSDictionary *dict = @{ @"view" : viewController.view,
|
||||
if(plugin.enabled) {
|
||||
if([plugin conformsToProtocol:@protocol(MPPluginSettings)]) {
|
||||
NSAssert([plugin respondsToSelector:@selector(settingsViewController)], @"Required getter for settings on plugins");
|
||||
NSViewController *viewController = ((id<MPPluginSettings>)plugin).settingsViewController;
|
||||
[self.settingsView addSubview:viewController.view];
|
||||
NSDictionary *dict = @{ @"view" : viewController.view,
|
||||
@"table" : self.pluginTableView.enclosingScrollView };
|
||||
[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]];
|
||||
}
|
||||
}
|
||||
else if(nil != plugin) {
|
||||
[self.settingsView addSubview:self.fallbackSettingsView];
|
||||
NSDictionary *dict = @{ @"view" : self.fallbackSettingsView,
|
||||
@"table" : self.pluginTableView.enclosingScrollView };
|
||||
[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]];
|
||||
if(plugin.errorMessage.length > 0) {
|
||||
self.fallbackDescriptionTextField.stringValue = plugin.errorMessage;
|
||||
}
|
||||
else {
|
||||
self.fallbackDescriptionTextField.stringValue = NSLocalizedString(@"PLUGIN_SETTINGS_GENERIC_ERROR_MESSAGE", "Generic message displayed if no details are know why a plugin was not loaded.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,7 +212,7 @@ typedef NS_ENUM(NSUInteger, MPPluginSegmentType) {
|
||||
if(NSModalResponseOK) {
|
||||
if(openPanel.URLs.count == 1) {
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
[self _addPlugin:openPanel.URLs.firstObject];
|
||||
[self _addPlugin:openPanel.URLs.firstObject];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
17
MacPass/MPPlugin_Private.h
Normal file
17
MacPass/MPPlugin_Private.h
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// MPPlugin+Private.h
|
||||
// MacPass
|
||||
//
|
||||
// Created by Michael Starke on 20.11.17.
|
||||
// Copyright © 2017 HicknHack Software GmbH. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MPPlugin.h"
|
||||
|
||||
@interface MPPlugin ()
|
||||
|
||||
@property (nonatomic, strong) NSBundle *bundle;
|
||||
@property (copy) NSString *errorMessage;
|
||||
@property BOOL enabled;
|
||||
|
||||
@end
|
||||
@@ -416,9 +416,27 @@
|
||||
/* Menu item to perform autotype with the selected entry */
|
||||
"PERFORM_AUTOTYPE_FOR_ENTRY" = "Auto-Type ausführen";
|
||||
|
||||
/* The plugin could not be initalized */
|
||||
"PLUGIN_ERROR_INTILIZATION_FAILED" = "Das Plugin konnten nicht korrekt initialisiert werden";
|
||||
|
||||
/* Error for a plugin that was not signed properly */
|
||||
"PLUGIN_ERROR_UNSECURE_PLUGIN" = "Das Plugin ist nicht korrekt signiert";
|
||||
|
||||
/* Plugin specifies the wrong principla class! */
|
||||
"PLUGIN_ERROR_WRONG_PRINCIPAL_CLASS" = "Die Hauptklasse des Plugins stimmt nicht mit der erwarteten überein";
|
||||
|
||||
/* name for disabled unloaded plugin */
|
||||
"PLUGIN_NAME_DISABLED_%@" = "🚫 %@";
|
||||
|
||||
/* Name for unloaded plugin with errors */
|
||||
"PLUGIN_NAME_ERROR_%@" = "⚠️ %@";
|
||||
|
||||
/* Label for plugin settings tab */
|
||||
"PLUGIN_SETTINGS" = "Plugins";
|
||||
|
||||
/* Generic message displayed if no details are know why a plugin was not loaded. */
|
||||
"PLUGIN_SETTINGS_GENERIC_ERROR_MESSAGE" = "Das Plugin konnte nicht geladen werden.";
|
||||
|
||||
/* Plugin version. Include a %@ placeholder for version string */
|
||||
"PLUGIN_VERSION_%@" = "Version: %@";
|
||||
|
||||
|
||||
@@ -34,12 +34,12 @@
|
||||
/* Alert informative text to ask the user if he really want to uninstall the plugin */
|
||||
"ALERT_INFORMATIVE_TEXT_REALLY_UNINSTALL_PLUGIN" = "The Plugin will be moved to the Trash.";
|
||||
|
||||
/* Alert message text when a plugin was successfully installed */
|
||||
"ALERT_MESSAGE_TEXT_PLUGIN_INSTALLED_SUGGEST_RESTART" = "Sucessfully installed Plugin!";
|
||||
|
||||
/* Alert message text when a plugin was successfully uninstalled. Include %@ placeholder for plugin name */
|
||||
"ALERT_MESSAGE_TEXT_PLUGIN_%@_UNINSTALLED_SUGGEST_RESTART" = "Plugin %@ uninstalled!";
|
||||
|
||||
/* Alert message text when a plugin was successfully installed */
|
||||
"ALERT_MESSAGE_TEXT_PLUGIN_INSTALLED_SUGGEST_RESTART" = "Sucessfully installed Plugin!";
|
||||
|
||||
/* Alert message text to ask the user if he really want to uninstall the plugin. Include %@ placeholder for plugin name */
|
||||
"ALERT_MESSAGE_TEXT_REALLY_UNINSTALL_PLUGIN_%@" = "Should the Plugin %@ really be uninstalled?";
|
||||
|
||||
@@ -416,9 +416,27 @@
|
||||
/* Menu item to perform autotype with the selected entry */
|
||||
"PERFORM_AUTOTYPE_FOR_ENTRY" = "Perform Autotype";
|
||||
|
||||
/* The plugin could not be initalized */
|
||||
"PLUGIN_ERROR_INTILIZATION_FAILED" = "Plugin could not be initalized";
|
||||
|
||||
/* Error for a plugin that was not signed properly */
|
||||
"PLUGIN_ERROR_UNSECURE_PLUGIN" = "Plugin is not properly signed";
|
||||
|
||||
/* Plugin specifies the wrong principla class! */
|
||||
"PLUGIN_ERROR_WRONG_PRINCIPAL_CLASS" = "Plugin principal class is wrong";
|
||||
|
||||
/* name for disabled unloaded plugin */
|
||||
"PLUGIN_NAME_DISABLED_%@" = "🚫 %@";
|
||||
|
||||
/* Name for unloaded plugin with errors */
|
||||
"PLUGIN_NAME_ERROR_%@" = "⚠️ %@";
|
||||
|
||||
/* Label for plugin settings tab */
|
||||
"PLUGIN_SETTINGS" = "Plugins";
|
||||
|
||||
/* Generic message displayed if no details are know why a plugin was not loaded. */
|
||||
"PLUGIN_SETTINGS_GENERIC_ERROR_MESSAGE" = "Plugin could not be loaded.";
|
||||
|
||||
/* Plugin version. Include a %@ placeholder for version string */
|
||||
"PLUGIN_VERSION_%@" = "Version: %@";
|
||||
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
/* Class = "NSButtonCell"; title = "Load unsecure Plugins"; ObjectID = "C4B-6z-ZqX"; */
|
||||
"C4B-6z-ZqX.title" = "Load unsecure Plugins";
|
||||
|
||||
/* Class = "NSTextFieldCell"; title = "Plugin Settings Info"; ObjectID = "OOr-SW-jZb"; */
|
||||
"OOr-SW-jZb.title" = "Plugin Settings Info";
|
||||
|
||||
/* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "STt-PQ-Szr"; */
|
||||
"STt-PQ-Szr.title" = "Text Cell";
|
||||
|
||||
@@ -16,3 +19,6 @@
|
||||
/* Class = "NSBox"; title = "Box"; ObjectID = "vBs-Ga-aq0"; */
|
||||
"vBs-Ga-aq0.title" = "Box";
|
||||
|
||||
/* Class = "NSTextFieldCell"; title = "Label"; ObjectID = "yuK-qH-jxx"; */
|
||||
"yuK-qH-jxx.title" = "Label";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user