Extended plugin settings

Plugins can be installed via drag and drop
Plugins can be uninstalled via the remove button
This commit is contained in:
michael starke
2017-11-17 17:45:10 +01:00
parent c2dd64ff70
commit 07a8085705
18 changed files with 278 additions and 69 deletions

View File

@@ -247,6 +247,7 @@
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 */; };
4CF6C3021FBF39BF0055AD03 /* MPPluginTabelCellView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CF6C3011FBF39BF0055AD03 /* MPPluginTabelCellView.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 */; };
@@ -761,6 +762,8 @@
4CF29BF317879D0000851B60 /* 26_FileSaveTemplate.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = 26_FileSaveTemplate.pdf; sourceTree = "<group>"; };
4CF5BE6B1BF33E3000048505 /* NSApplication+MPAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSApplication+MPAdditions.h"; sourceTree = "<group>"; };
4CF5BE6C1BF33E3000048505 /* NSApplication+MPAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSApplication+MPAdditions.m"; sourceTree = "<group>"; };
4CF6C3001FBF39BF0055AD03 /* MPPluginTabelCellView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPPluginTabelCellView.h; sourceTree = "<group>"; };
4CF6C3011FBF39BF0055AD03 /* MPPluginTabelCellView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPPluginTabelCellView.m; sourceTree = "<group>"; };
4CF6C70F176F4533007A811D /* MPStringLengthValueTransformer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPStringLengthValueTransformer.h; sourceTree = "<group>"; };
4CF6C710176F4533007A811D /* MPStringLengthValueTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPStringLengthValueTransformer.m; sourceTree = "<group>"; };
4CF78062176E75AD0032EE71 /* MPIntegrationSettingsController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPIntegrationSettingsController.h; sourceTree = "<group>"; };
@@ -936,6 +939,8 @@
4CCEDE29179F203B008402BE /* MPOutlineView.m */,
4CE082C11F6FCD2A0034FF56 /* MPCollectionView.h */,
4CE082C21F6FCD2A0034FF56 /* MPCollectionView.m */,
4CF6C3001FBF39BF0055AD03 /* MPPluginTabelCellView.h */,
4CF6C3011FBF39BF0055AD03 /* MPPluginTabelCellView.m */,
);
name = Views;
sourceTree = "<group>";
@@ -1867,6 +1872,7 @@
4C4B728518E4B9B400A1A5D5 /* MPDockTileHelper.m in Sources */,
4C5FE9AE17843CE20001D5A8 /* MPSelectedAttachmentTableCellView.m in Sources */,
4C3666411787327E00B249F1 /* MPDocument+Attachments.m in Sources */,
4CF6C3021FBF39BF0055AD03 /* MPPluginTabelCellView.m in Sources */,
4C10412C178CDD44001B5239 /* NSDate+Humanized.m in Sources */,
4C0C59F118B17F10009C7B76 /* DDHotKeyUtilities.m in Sources */,
4CEE46DD181C301D006BF1E5 /* MPAutotypeDaemon.m in Sources */,

View File

@@ -44,13 +44,13 @@
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<scrollView autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fCk-fL-jU8">
<scrollView autohidesScrollers="YES" horizontalLineScroll="37" horizontalPageScroll="10" verticalLineScroll="37" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fCk-fL-jU8">
<rect key="frame" x="20" y="50" width="150" height="345"/>
<clipView key="contentView" id="lTL-Q2-k45">
<rect key="frame" x="1" y="1" width="148" height="343"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnReordering="NO" columnSelection="YES" columnResizing="NO" multipleSelection="NO" autosaveColumns="NO" rowSizeStyle="automatic" viewBased="YES" id="Ocu-C0-03d">
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnReordering="NO" columnSelection="YES" columnResizing="NO" multipleSelection="NO" autosaveColumns="NO" rowHeight="35" rowSizeStyle="automatic" viewBased="YES" id="Ocu-C0-03d">
<rect key="frame" x="0.0" y="0.0" width="148" height="343"/>
<autoresizingMask key="autoresizingMask"/>
<size key="intercellSpacing" width="3" height="2"/>
@@ -70,21 +70,38 @@
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView id="vVt-P3-yLp">
<rect key="frame" x="1" y="1" width="145" height="17"/>
<tableCellView id="vVt-P3-yLp" customClass="MPPluginTabelCellView">
<rect key="frame" x="1" y="1" width="145" height="35"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="q1P-PD-0LW">
<rect key="frame" x="0.0" y="0.0" width="100" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="q1P-PD-0LW">
<rect key="frame" x="0.0" y="18" width="127" height="17"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="fug-79-n9g">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="fQy-Sz-4VA">
<rect key="frame" x="0.0" y="2" width="145" height="14"/>
<textFieldCell key="cell" controlSize="small" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Label" id="yuK-qH-jxx">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="disabledControlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<constraints>
<constraint firstAttribute="bottom" secondItem="fQy-Sz-4VA" secondAttribute="bottom" constant="2" id="Flm-uU-Rzj"/>
<constraint firstAttribute="trailing" secondItem="fQy-Sz-4VA" secondAttribute="trailing" constant="2" id="Iy0-iV-Mbx"/>
<constraint firstItem="fQy-Sz-4VA" firstAttribute="top" secondItem="q1P-PD-0LW" secondAttribute="bottom" constant="2" id="RZb-58-Zwr"/>
<constraint firstItem="q1P-PD-0LW" firstAttribute="leading" secondItem="vVt-P3-yLp" secondAttribute="leading" constant="2" id="bTc-2c-BYB"/>
<constraint firstAttribute="trailing" secondItem="q1P-PD-0LW" secondAttribute="trailing" constant="20" symbolic="YES" id="gSi-vN-xzX"/>
<constraint firstItem="q1P-PD-0LW" firstAttribute="top" secondItem="vVt-P3-yLp" secondAttribute="top" id="tTs-2E-33f"/>
<constraint firstItem="fQy-Sz-4VA" firstAttribute="leading" secondItem="vVt-P3-yLp" secondAttribute="leading" constant="2" id="zLP-Ci-nUM"/>
</constraints>
<connections>
<outlet property="addionalTextField" destination="fQy-Sz-4VA" id="nr7-5w-TEg"/>
<outlet property="textField" destination="q1P-PD-0LW" id="yB7-Uf-IIx"/>
</connections>
</tableCellView>
@@ -152,7 +169,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="-214" y="11"/>
<point key="canvasLocation" x="-231" y="-58.5"/>
</customView>
</objects>
<resources>

View File

@@ -51,7 +51,7 @@
KPKEntry *entry = document.selectedEntries.count == 1 ? document.selectedEntries.lastObject : nil;
NSPasteboard *draggingPasteBoard = [info draggingPasteboard];
NSArray *arrayOfURLs = [draggingPasteBoard readObjectsForClasses:@[[NSURL class]] options:nil];
NSArray *arrayOfURLs = [draggingPasteBoard readObjectsForClasses:@[NSURL.class] options:nil];
for(NSURL *fileUrl in arrayOfURLs) {
[document addAttachment:fileUrl toEntry:entry];

View File

@@ -28,6 +28,7 @@
FOUNDATION_EXPORT NSString *const MPPasteBoardType;
FOUNDATION_EXPORT NSString *const MPKdbDocumentUTI;
FOUNDATION_EXPORT NSString *const MPKdbxDocumentUTI;
FOUNDATION_EXPORT NSString *const MPPluginUTI;
#endif

View File

@@ -22,6 +22,7 @@
#import "MPConstants.h"
NSString *const MPPasteBoardType = @"com.hicknhack.macpass.pasteboard";
NSString *const MPKdbDocumentUTI = @"com.hicknhack.macpass.kdb";
NSString *const MPKdbxDocumentUTI = @"com.hicknhack.macpass.kdbx";
NSString *const MPPasteBoardType = @"com.hicknhack.macpass.pasteboard";
NSString *const MPKdbDocumentUTI = @"com.hicknhack.macpass.kdb";
NSString *const MPKdbxDocumentUTI = @"com.hicknhack.macpass.kdbx";
NSString *const MPPluginUTI = @"com.hicknhack.macpass.plugin";

View File

@@ -556,7 +556,7 @@ typedef void (^MPPasswordChangedBlock)(BOOL didChangePassword);
alert.informativeText = NSLocalizedString(@"RECOMMEND_PASSWORD_CHANGE_ALERT_DESCRIPTION", "Informative text for the recommend password change alert");
[alert addButtonWithTitle:NSLocalizedString(@"CHANGE_PASSWORD_WITH_DOTS", "Button to show the password change dialog")];
[alert addButtonWithTitle:NSLocalizedString(@"CANCEL", "Cancel button to postpone password change")];
[alert addButtonWithTitle:NSLocalizedString(@"CHANGE_LATER", "Button to postpone the password change")];
alert.buttons[1].keyEquivalent = [NSString stringWithFormat:@"%c", 0x1b];

View File

@@ -48,8 +48,6 @@ FOUNDATION_EXPORT NSString *const kMPPluginFileExtension;
@end
@class KPKTree;
@interface MPPlugin (Deprecated)
- (instancetype)initWithPluginManager:(id)manager;

View File

@@ -48,10 +48,16 @@ NSString *const kMPPluginFileExtension = @"mpplugin";
- (NSString *)version {
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSString *version;
if(bundle) {
version = bundle.infoDictionary[(NSString *)kCFBundleVersionKey];
if(version) {
NSString *humanVersion = bundle.infoDictionary[@"CFBundleShortVersionString"];
NSString *version = bundle.infoDictionary[(NSString *)kCFBundleVersionKey];
if(humanVersion && version) {
return [NSString stringWithFormat:@"%@ (%@)", humanVersion, version];
}
else if(humanVersion) {
return humanVersion;
}
else if(version) {
return version;
}
}
@@ -71,7 +77,7 @@ NSString *const kMPPluginFileExtension = @"mpplugin";
NSLog(@"Deprecated initalizer. Use initWithPluginHost: instead!");
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnonnull"
self = [self initWithPluginHost:nil];
self = [self initWithPluginHost:manager];
#pragma cland diagnostic pop
return self;
}

View File

@@ -39,5 +39,8 @@ FOUNDATION_EXPORT NSString *const MPPluginHostPluginBundleIdentifiyerKey;
- (instancetype)init NS_UNAVAILABLE;
- (BOOL)installPluginAtURL:(NSURL *)url error:(NSError *__autoreleasing *)error;
- (BOOL)uninstallPlugin:(MPPlugin *)plugin error:(NSError *__autoreleasing *)error;
- (void)disablePlugin:(MPPlugin *)plugin;
- (void)enablePlugin:(MPPlugin *)plugin;
@end

View File

@@ -37,10 +37,10 @@ NSString *const MPPluginHostDidLoadPlugin = @"comt.hicknhack.macpass.MPPluginHos
NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBundleIdentifiyerKey";
@interface MPPluginHost () <NSFileManagerDelegate>
@interface MPPluginHost ()
@property (strong) NSMutableArray<MPPlugin __kindof *> *mutablePlugins;
@property (nonatomic) BOOL loadUnsecurePlugins;
@property (copy) NSArray<NSString *> *disabledPlugins;
@end
@@ -67,13 +67,18 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
self = [super init];
if(self) {
_mutablePlugins = [[NSMutableArray alloc] init];
_disabledPlugins = [[NSUserDefaults standardUserDefaults] arrayForKey:kMPSettingsKeyLoadUnsecurePlugins];
_loadUnsecurePlugins = [[NSUserDefaults standardUserDefaults] boolForKey:kMPSettingsKeyLoadUnsecurePlugins];
[self _loadPlugins];
[self bind:NSStringFromSelector(@selector(loadUnsecurePlugins))
toObject:[NSUserDefaultsController sharedUserDefaultsController]
toObject:NSUserDefaultsController.sharedUserDefaultsController
withKeyPath:[MPSettingsHelper defaultControllerPathForKey:kMPSettingsKeyLoadUnsecurePlugins]
options:nil];
[self bind:NSStringFromSelector(@selector(disabledPlugins))
toObject:NSUserDefaultsController.sharedUserDefaultsController
withKeyPath:[MPSettingsHelper defaultControllerPathForKey:kMPSettingsKeyDisabledPlugins]
options:nil];
}
return self;
}
@@ -95,16 +100,21 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
}
NSURL *appSupportURL = [NSApp applicationSupportDirectoryURL:YES];
NSURL *destinationURL = [appSupportURL URLByAppendingPathComponent:fileName];
NSFileManager.defaultManager.delegate = self;
return [NSFileManager.defaultManager moveItemAtURL:url toURL:destinationURL error:error];
}
#pragma mark - NSFileManagerDelegate
- (BOOL)fileManager:(NSFileManager *)fileManager shouldProceedAfterError:(NSError *)error movingItemAtURL:(NSURL *)srcURL toURL:(NSURL *)dstURL {
return NO;
- (BOOL)uninstallPlugin:(MPPlugin *)plugin error:(NSError *__autoreleasing *)error {
NSBundle *pluginBundle = [NSBundle bundleForClass:plugin.class];
return [NSFileManager.defaultManager trashItemAtURL:pluginBundle.bundleURL resultingItemURL:nil error:error];
}
- (void)disablePlugin:(MPPlugin *)plugin {
}
- (void)enablePlugin:(MPPlugin *)plugin {
}
#pragma mark - Plugin Loading
- (void)_loadPlugins {
@@ -146,6 +156,12 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
NSLog(@"Could not create bundle %@", pluginURL.path);
continue;
}
if(pluginBundle.bundleIdentifier) {
}
NSError *error;
if(![pluginBundle preflightAndReturnError:&error]) {
NSLog(@"Preflight Error %@ %@", error.localizedDescription, error.localizedFailureReason );
@@ -166,11 +182,19 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
NSLog(@"Wrong principal Class.");
continue;
}
if([pluginBundle.principalClass instancesRespondToSelector:NSSelectorFromString(@"initWithPluginManager:")]) {
NSLog(@"Plugin uses old interface. Update plugin to use initWithPluginHost: instead of initWithPluginManager:!");
}
MPPlugin *plugin = [[pluginBundle.principalClass alloc] initWithPluginHost:self];
IMP defaultImp = [MPPlugin.class instanceMethodForSelector:@selector(initWithPluginManager:)];
IMP pluginImp = [pluginBundle.principalClass instanceMethodForSelector:@selector(initWithPluginManager:)];
MPPlugin *plugin;
if(defaultImp != pluginImp) {
NSLog(@"Plugin uses old interface. Update plugin to use initWithPluginHost: instead of initWithPluginManager:!");
plugin = [[pluginBundle.principalClass alloc] initWithPluginManager:self];
}
else {
plugin = [[pluginBundle.principalClass alloc] initWithPluginHost:self];
}
if(plugin) {
NSLog(@"Loaded plugin instance %@", pluginBundle.principalClass);
[[NSNotificationCenter defaultCenter] postNotificationName:MPPluginHostWillLoadPlugin
@@ -252,5 +276,4 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
return NO;
}
@end

View File

@@ -21,9 +21,11 @@
//
#import "MPPluginSettingsController.h"
#import "MPPluginTabelCellView.h"
#import "MPPluginHost.h"
#import "MPPlugin.h"
#import "MPConstants.h"
#import "MPSettingsHelper.h"
#import "NSApplication+MPAdditions.h"
@@ -71,18 +73,20 @@ typedef NS_ENUM(NSUInteger, MPPluginSegmentType) {
toObject:[NSUserDefaultsController sharedUserDefaultsController]
withKeyPath:[MPSettingsHelper defaultControllerPathForKey:kMPSettingsKeyLoadUnsecurePlugins]
options:nil];
[self.pluginTableView registerForDraggedTypes:@[(NSString *)kUTTypeFileURL]];
}
# pragma mark - TableView
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
return [MPPluginHost sharedHost].plugins.count;
}
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
MPPlugin *plugin = [self pluginForRow:row];
NSTableCellView *view = [tableView makeViewWithIdentifier:tableColumn.identifier owner:nil];
view.textField.stringValue = plugin.name;
MPPluginTabelCellView *view = [tableView makeViewWithIdentifier:tableColumn.identifier owner:nil];
view.textField.stringValue = [NSString stringWithFormat:@"%@", plugin.name];
view.addionalTextField.stringValue = [NSString stringWithFormat:NSLocalizedString(@"PLUGIN_VERSION_%@", "Plugin version. Include a %@ placeholder for version string"), plugin.version];
return view;
}
@@ -110,11 +114,48 @@ typedef NS_ENUM(NSUInteger, MPPluginSegmentType) {
- (void)tableViewSelectionDidChange:(NSNotification *)notification {
NSTableView *table = notification.object;
if(table != self.pluginTableView) {
return; // wrong tableview
}
MPPlugin *plugin = [self pluginForRow:table.selectedRow];
//[self.addRemovePluginsControl setEnabled:(nil != plugin) forSegment:MPRemovePluginSegment];
[self.addRemovePluginsControl setEnabled:(nil != plugin) forSegment:MPRemovePluginSegment];
[self showSettingsForPlugin:plugin];
}
- (NSDragOperation)tableView:(NSTableView *)tableView validateDrop:(id <NSDraggingInfo>)info proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)dropOperation {
NSArray *arrayOfURLs = [[info draggingPasteboard] readObjectsForClasses:@[NSURL.class] options:nil];
if(arrayOfURLs.count != 1) {
return NO;
}
NSURL *pluginURL = arrayOfURLs.firstObject;
if(!pluginURL.isFileURL) {
return NO;
}
if(![pluginURL.lastPathComponent.pathExtension isEqualToString:kMPPluginFileExtension]) {
return NO;
}
[tableView setDropRow:-1 dropOperation:NSTableViewDropOn];
return YES;
}
- (BOOL)tableView:(NSTableView *)tableView acceptDrop:(nonnull id<NSDraggingInfo>)info row:(NSInteger)row dropOperation:(NSTableViewDropOperation)dropOperation {
/* dispatch installation since we do not want to wait for the result */
if(dropOperation != NSTableViewDropOn) {
return NO;
}
NSPasteboard *draggingPasteboard = [info draggingPasteboard];
NSArray *arrayOfURLs = [draggingPasteboard readObjectsForClasses:@[NSURL.class] options:nil];
if(arrayOfURLs.count != 1) {
return NO;
}
dispatch_async(dispatch_get_main_queue(), ^{
[self _addPlugin:arrayOfURLs.firstObject];
});
return YES;
}
#pragma mark - Actions
- (IBAction)browsePlugins:(id)sender {
[NSWorkspace.sharedWorkspace openURL:[NSApp applicationSupportDirectoryURL:YES]];
}
@@ -128,6 +169,7 @@ typedef NS_ENUM(NSUInteger, MPPluginSegmentType) {
[self showAddPluginPanel];
break;
case MPRemovePluginSegment:
[self showRemovePluginAlert];
break;
default:
break;
@@ -162,11 +204,49 @@ typedef NS_ENUM(NSUInteger, MPPluginSegmentType) {
NSAlert *alert = [[NSAlert alloc] init];
alert.alertStyle = NSAlertStyleInformational;
alert.messageText = NSLocalizedString(@"ALERT_MESSAGE_TEXT_PLUGIN_INSTALLED_SUGGEST_RESTART", "Alert message text when a plugin was successfully installed");
alert.informativeText = NSLocalizedString(@"ALERT_INFORMATIVE_TEXT_PLUGIN_INSTALLED_SUGGEST_RESTART", "ALert informative text when a plugin was sucessfully installed");
[alert addButtonWithTitle:NSLocalizedString(@"CANCEL", @"Cancel button in plugin installed, request restart alert")];
[alert addButtonWithTitle:NSLocalizedString(@"RESTART", @"Restart button in plugin installed, request restart alert")];
alert.informativeText = NSLocalizedString(@"ALERT_INFORMATIVE_TEXT_PLUGIN_INSTALLED_SUGGEST_RESTART", "Alert informative text when a plugin was sucessfully installed");
[alert addButtonWithTitle:NSLocalizedString(@"RESTART", @"Restart")];
[alert addButtonWithTitle:NSLocalizedString(@"KEEP_RUNNING", @"Do not restart MacPass")];
[alert beginSheetModalForWindow:self.view.window completionHandler:^(NSModalResponse returnCode) {
if(returnCode == NSAlertSecondButtonReturn) {
if(returnCode == NSAlertFirstButtonReturn) {
[NSApp relaunchAfterDelay:3];
}
}];
}
}
- (void)showRemovePluginAlert {
MPPlugin *plugin = [self pluginForRow:self.pluginTableView.selectedRow];
if(!plugin) {
return;
}
NSAlert *alert = [[NSAlert alloc] init];
alert.alertStyle = NSAlertStyleWarning;
alert.messageText = [NSString stringWithFormat:NSLocalizedString(@"ALERT_MESSAGE_TEXT_REALLY_UNINSTALL_PLUGIN_%@", "Alert message text to ask the user if he really want to uninstall the plugin. Include %@ placeholder for plugin name"), plugin.name];
alert.informativeText = NSLocalizedString(@"ALERT_INFORMATIVE_TEXT_REALLY_UNINSTALL_PLUGIN", "Alert informative text to ask the user if he really want to uninstall the plugin");
[alert addButtonWithTitle:NSLocalizedString(@"UNINSTALL", @"Uninstall plugin")];
[alert addButtonWithTitle:NSLocalizedString(@"KEEP_PLUGIN", @"Do not install the plugin")];
[alert beginSheetModalForWindow:self.view.window completionHandler:^(NSModalResponse returnCode) {
if(returnCode == NSAlertFirstButtonReturn) {
[self _removePlugin:plugin];
}
}];
}
- (void)_removePlugin:(MPPlugin *)plugin {
NSError *error;
if(![[MPPluginHost sharedHost] uninstallPlugin:plugin error:&error]) {
[NSApp presentError:error modalForWindow:self.view.window delegate:nil didPresentSelector:NULL contextInfo:NULL];
}
else {
NSAlert *alert = [[NSAlert alloc] init];
alert.alertStyle = NSAlertStyleInformational;
alert.messageText = [NSString stringWithFormat:NSLocalizedString(@"ALERT_MESSAGE_TEXT_PLUGIN_%@_UNINSTALLED_SUGGEST_RESTART", "Alert message text when a plugin was successfully uninstalled. Include %@ placeholder for plugin name"), plugin.name];
alert.informativeText = NSLocalizedString(@"ALERT_INFORMATIVE_TEXT_PLUGIN_UNINSTALLED_SUGGEST_RESTART", "Alert informative text when a plugin was sucessfully uninstalled");
[alert addButtonWithTitle:NSLocalizedString(@"RESTART", @"Restart")];
[alert addButtonWithTitle:NSLocalizedString(@"KEEP_RUNNING", @"Do not restart MacPass")];
[alert beginSheetModalForWindow:self.view.window completionHandler:^(NSModalResponse returnCode) {
if(returnCode == NSAlertFirstButtonReturn) {
[NSApp relaunchAfterDelay:3];
}
}];

View File

@@ -0,0 +1,15 @@
//
// MPPluginTabelCellView.h
// MacPass
//
// Created by Michael Starke on 17.11.17.
// Copyright © 2017 HicknHack Software GmbH. All rights reserved.
//
#import <Cocoa/Cocoa.h>
@interface MPPluginTabelCellView : NSTableCellView
@property (weak) IBOutlet NSTextField *addionalTextField;
@end

View File

@@ -0,0 +1,13 @@
//
// MPPluginTabelCellView.m
// MacPass
//
// Created by Michael Starke on 17.11.17.
// Copyright © 2017 HicknHack Software GmbH. All rights reserved.
//
#import "MPPluginTabelCellView.h"
@implementation MPPluginTabelCellView
@end

View File

@@ -79,6 +79,7 @@ APPKIT_EXTERN NSString *const kMPSettingsKeyUpdatePasswordOnTemplateEntries;
/* Plugins */
APPKIT_EXTERN NSString *const kMPSettingsKeyLoadUnsecurePlugins; // If set to YES this will load all plugins regardless of their codesignature status
APPKIT_EXTERN NSString *const kMPSettingsKeyDisabledPlugins; // NSArray of bundle identifiers of disabled plugins
typedef NS_ENUM(NSUInteger, MPFileChangeStrategy) {
MPFileChangeStrategyAsk,

View File

@@ -74,7 +74,8 @@ NSString *const kMPSettingsKeyDoubleClickURLAction = @"Double
NSString *const kMPSettingsKeyDoubleClickTitleAction = @"DoubleClickTitleAction";
NSString *const kMPSettingsKeyUpdatePasswordOnTemplateEntries = @"UpdatePasswordOnTemplateEntries";
NSString *const kMPSettingsKeyLoadUnsecurePlugins = @"MPLoadUnsecurePlugins";
NSString *const kMPSettingsKeyLoadUnsecurePlugins = @"LoadUnsecurePlugins";
NSString *const kMPSettingsKeyDisabledPlugins = @"DisabledPlugins";
/* Deprecated */
NSString *const kMPDeprecatedSettingsKeyRememberKeyFilesForDatabases = @"kMPSettingsKeyRememberKeyFilesForDatabases";
@@ -86,6 +87,7 @@ NSString *const kMPDeprecatedSettingsKeyHttpPort = @"Ht
NSString *const kMPDeprecatedSettingsKeyEnableHttpServer = @"EnableHttpServer";
NSString *const kMPDeprecatedSettingsKeyShowMenuItem = @"ShowMenuItem";
NSString *const kMPDeprecatedSettingsKeyDefaultPasswordRounds = @"KeyDefaultPasswordRounds";
NSString *const kMPDepricatedSettingsKeyLoadUnsecurePlugins = @"MPLoadUnsecurePlugins";
@implementation MPSettingsHelper
@@ -99,6 +101,7 @@ NSString *const kMPDeprecatedSettingsKeyDefaultPasswordRounds = @"Ke
[self _migrateURLDoubleClickPreferences];
[self _migrateEntrySearchFlags];
[self _migrateRememberedKeyFiles];
[self _migrateLoadUnsecurePlugins];
[self _removeDeprecatedValues];
}
@@ -143,7 +146,8 @@ NSString *const kMPDeprecatedSettingsKeyDefaultPasswordRounds = @"Ke
kMPSettingsKeyDoubleClickURLAction: @(MPDoubleClickURLActionCopy),
kMPSettingsKeyDoubleClickTitleAction: @(MPDoubleClickTitleActionInspect),
kMPSettingsKeyLoadUnsecurePlugins: @NO,
kMPSettingsKeyUpdatePasswordOnTemplateEntries: @YES
kMPSettingsKeyUpdatePasswordOnTemplateEntries: @YES,
kMPSettingsKeyDisabledPlugins: @[]
};
});
return standardDefaults;
@@ -162,7 +166,8 @@ NSString *const kMPDeprecatedSettingsKeyDefaultPasswordRounds = @"Ke
/* Moved to KeePassHttp Plugin */
kMPDeprecatedSettingsKeyHttpPort,
kMPDeprecatedSettingsKeyEnableHttpServer,
kMPDeprecatedSettingsKeyShowMenuItem
kMPDeprecatedSettingsKeyShowMenuItem,
kMPDepricatedSettingsKeyLoadUnsecurePlugins
];
});
return deprecatedSettings;
@@ -251,4 +256,16 @@ NSString *const kMPDeprecatedSettingsKeyDefaultPasswordRounds = @"Ke
}
}
+ (void)_migrateLoadUnsecurePlugins {
id value = [NSUserDefaults.standardUserDefaults objectForKey:kMPDepricatedSettingsKeyLoadUnsecurePlugins];
if(!value) {
return; // value already migrated or was set to default value
}
BOOL oldValue = [NSUserDefaults.standardUserDefaults boolForKey:kMPDepricatedSettingsKeyLoadUnsecurePlugins];
if(oldValue != [[self _standardDefaults][kMPDepricatedSettingsKeyLoadUnsecurePlugins] boolValue]) {
[NSUserDefaults.standardUserDefaults setBool:oldValue forKey:kMPSettingsKeyLoadUnsecurePlugins];
}
}
@end

View File

@@ -68,7 +68,7 @@
<key>MPHelpURL</key>
<string>https://github.com/mstarke/MacPass</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2012-2016 HicknHack Software GmbH. All rights reserved.</string>
<string>Copyright © 2012-2017 HicknHack Software GmbH. All rights reserved.</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>

View File

@@ -352,6 +352,9 @@
/* Label for plugin settings tab */
"PLUGIN_SETTINGS" = "Plugins";
/* Plugin version. Include a %@ placeholder for version string */
"PLUGIN_VERSION_%@" = "Version: %@";
/* Menu item to preview the selected attached file. */
"PREVIEW" = "Vorschau";

View File

@@ -19,24 +19,30 @@
/* Button label to abort a merge on a file with changed master key! */
"ABORT_MERGE_KEEP_MINE" = "Abort Merge. Keep Mine.";
/* No comment provided by engineer. */
/* Toolbar item with action menu */
"ACTION" = "Action";
/* No comment provided by engineer. */
/* Action to add an entry via template */
"ADD_TREMPLATE_ENTRY" = "Create Template Entry";
/* ALert informative text when a plugin was sucessfully installed */
"ALERT_INFORMATIVE_TEXT_PLUGIN_INSTALLED_SUGGEST_RESTART" = "Plugins can only be loaded at start up. To activate the installed pluing, please restart MacPass.";
/* Alert informative text when a plugin was sucessfully installed */
"ALERT_INFORMATIVE_TEXT_PLUGIN_INSTALLED_SUGGEST_RESTART" = "Plugins can only be loaded at start up. To activate the installed plugin, please restart MacPass.";
/* (No Comment) */
"ALERT_KDB_UNSUPPORTED_ADD_ENTRY_INFORMATIVE" = "The KDB format does not support entries inside this group. The entry will be moved when the file is saved.";
/* Alert informative text when a plugin was sucessfully uninstalled */
"ALERT_INFORMATIVE_TEXT_PLUGIN_UNINSTALLED_SUGGEST_RESTART" = "Plugins cannot be removed while MacPass is running. Please restart MacPass to unload the plugin.";
/* (No Comment) */
"ALERT_KDB_UNSUPPORTED_ADD_ENTRY_MESSAGE" = "Adding entries not supported";
/* 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 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?";
/* Attachments column title (shows counts)
Menu item to toggle display of attachment count column in entry table */
"ATTACHMENTS" = "Attachments";
@@ -65,9 +71,7 @@
/* Sucessfully merged external changes */
"AUTO_MERGE_NOTIFICATION_TEXT" = "Auto merge successfull!";
/* Cancel
Cancel button in plugin installed, request restart alert
Cancel button to postpone password change */
/* Cancel */
"CANCEL" = "Cancel";
/* Menu item in the database outline context menu to change the database name */
@@ -76,6 +80,9 @@
/* (No Comment) */
"CHANGE_FORMAT" = "Change File Format to KDBX";
/* Button to postpone the password change */
"CHANGE_LATER" = "Change Later";
/* Button to show the password change dialog
Single button to show the password change dialog */
"CHANGE_PASSWORD_WITH_DOTS" = "Change Password…";
@@ -89,7 +96,7 @@
/* Clear Autotype Button */
"CLEAR_AUTOTYPE" = "Clear Autotype";
/* No comment provided by engineer. */
/* Menu to clear recent searches */
"CLEAR_RECENT_SEARCHES" = "Clear recent searches";
/* Field name that was copied to the pasteboard */
@@ -119,13 +126,15 @@
/* Action title for copying a group via drag and drop */
"COPY_GROUP" = "Copy Group";
/* Menu item to copy the password of an entry */
/* Menu item to copy the password of an entry
Toolbar item copy password */
"COPY_PASSWORD" = "Copy Password";
/* Menu item to copy the URL of an entry */
"COPY_URL" = "Copy URL";
/* Menu item to copy the username of an entry */
/* Menu item to copy the username of an entry
Toolbar item copy username */
"COPY_USERNAME" = "Copy Username";
/* (No Comment) */
@@ -137,7 +146,7 @@
/* Title for menu for custom search filters */
"CUSTOM_SEARCH_FILTER_MENU" = "Custom Search Filter…";
/* Default name database */
/* Default display name for KDB databases */
"DATABASE" = "Database";
/* Default Browser */
@@ -161,7 +170,8 @@
/* Menu item in the database outline context menu to delete the node from the trash
Menu item to delete an entry
Menu item to delete the selected attached file
Menu item to delete the selected custom icon */
Menu item to delete the selected custom icon
Toolbar item delete item */
"DELETE" = "Delete";
/* No comment provided by engineer. */
@@ -266,7 +276,7 @@
/* Imports a dragged URL for a new entry */
"IMPORT_URL" = "Import URL";
/* No comment provided by engineer. */
/* Toolbar item toggle inspector */
"INSPECTOR" = "Inspector";
/* Label for the integration settings tab */
@@ -284,10 +294,16 @@
/* Reopen the file! */
"KEEP_OTHER_DISCARD_MINE" = "Keep Other, Discard Mine";
/* Do not install the plugin */
"KEEP_PLUGIN" = "Keep Plugin";
/* Do not restart MacPass */
"KEEP_RUNNING" = "Keep Running";
/* last week */
"LAST_WEEK" = "Last week";
/* No comment provided by engineer. */
/* Toolbar item to Lock the database */
"LOCK" = "Lock";
/* Message in the open panel to add attachments to an entry */
@@ -312,13 +328,15 @@
/* Name for a newly created Database */
"NEW_DATABASE" = "Database";
/* Menu item to create a new entry */
/* Menu item to create a new entry
Toolbar item new entry */
"NEW_ENTRY" = "New Entry";
/* Submenu to add an entry via template */
"NEW_ENTRY_WITH_TEMPLATE_%@" = "Create Entry with Template %@";
/* Menu item to create a new group */
/* Menu item to create a new group
Toolbar item new group */
"NEW_GROUP" = "New Group";
/* Placeholder text for input fields if no entry or group is selected */
@@ -401,10 +419,13 @@
/* Label for plugin settings tab */
"PLUGIN_SETTINGS" = "Plugins";
/* Plugin version. Include a %@ placeholder for version string */
"PLUGIN_VERSION_%@" = "Version: %@";
/* Menu item to preview the selected attached file. */
"PREVIEW" = "Preview";
/* No comment provided by engineer. */
/* Recent searches menu item */
"RECENT_SEARCHES" = "Recent searches";
/* Informative text for the recommend password change alert */
@@ -413,7 +434,7 @@
/* Message text for the recommend password change alert */
"RECOMMEND_PASSWORD_CHANGE_ALERT_TITLE" = "Please change the database password!";
/* Restart button in plugin installed, request restart alert */
/* Restart */
"RESTART" = "Restart";
/* Action to restore and Entry to a previous state of it's history */
@@ -432,7 +453,7 @@
/* Save file menu item title when save will prompt for a location to save or ask for a password/key */
"SAVE_WITH_DOTS" = "Save…";
/* No comment provided by engineer. */
/* Search input in Toolbar */
"SEARCH" = "Search";
/* Search option: Find duplicate passwords */
@@ -477,7 +498,8 @@
/* (No Comment) */
"SHORT_FILE_CHANGE_STRATEGY_ASK" = "Ask";
/* Menu item to show the history of the selected entry */
/* Menu item to show the history of the selected entry
Toolbar item to toggel history display */
"SHOW_HISTORY" = "Show History";
/* Menu item to show the reference builder in a text view's context menu */
@@ -498,6 +520,9 @@
/* Move Group to Trash */
"TRASH_GROUP" = "Trash Group";
/* Uninstall plugin */
"UNINSTALL" = "Uninstall";
/* No comment provided by engineer. */
"UNKNOWN_FILE_VERSION" = "Unknown File Version";