mirror of
https://github.com/MacPass/MacPass.git
synced 2025-12-13 22:52:26 +00:00
completed simple merge workflow. Made passwordInputController better reusabel
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="9059" systemVersion="15B42" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="9059"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="12121"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="MPIconSelectViewController">
|
||||
@@ -26,31 +26,24 @@
|
||||
<collectionView focusRingType="none" id="58">
|
||||
<rect key="frame" x="0.0" y="0.0" width="380" height="280"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<animations/>
|
||||
<color key="primaryBackgroundColor" name="windowBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
<connections>
|
||||
<outlet property="itemPrototype" destination="61" id="63"/>
|
||||
</connections>
|
||||
</collectionView>
|
||||
</subviews>
|
||||
<animations/>
|
||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</clipView>
|
||||
<animations/>
|
||||
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="59">
|
||||
<rect key="frame" x="1" y="144" width="233" height="15"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<animations/>
|
||||
</scroller>
|
||||
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="60">
|
||||
<rect key="frame" x="234" y="1" width="15" height="143"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<animations/>
|
||||
</scroller>
|
||||
</scrollView>
|
||||
<button verticalHuggingPriority="750" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="101">
|
||||
<rect key="frame" x="263" y="18" width="117" height="25"/>
|
||||
<animations/>
|
||||
<buttonCell key="cell" type="roundTextured" title="Use Default Icon" bezelStyle="texturedRounded" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="102">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
@@ -61,7 +54,6 @@
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="His-4A-hcY">
|
||||
<rect key="frame" x="198" y="18" width="57" height="25"/>
|
||||
<animations/>
|
||||
<buttonCell key="cell" type="roundTextured" title="Cancel" bezelStyle="texturedRounded" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="1kM-cI-P1o">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
@@ -82,8 +74,7 @@
|
||||
<constraint firstItem="101" firstAttribute="leading" secondItem="His-4A-hcY" secondAttribute="trailing" constant="8" id="EHs-2w-CJq"/>
|
||||
<constraint firstItem="His-4A-hcY" firstAttribute="baseline" secondItem="101" secondAttribute="baseline" id="fq3-rS-gvQ"/>
|
||||
</constraints>
|
||||
<animations/>
|
||||
<point key="canvasLocation" x="370" y="95"/>
|
||||
<point key="canvasLocation" x="-26" y="-60"/>
|
||||
</customView>
|
||||
<collectionViewItem id="61">
|
||||
<connections>
|
||||
@@ -100,7 +91,6 @@
|
||||
<constraint firstAttribute="width" constant="32" id="161"/>
|
||||
<constraint firstAttribute="height" constant="32" id="162"/>
|
||||
</constraints>
|
||||
<animations/>
|
||||
<buttonCell key="cell" type="bevel" bezelStyle="regularSquare" image="NSAddTemplate" imagePosition="only" alignment="center" imageScaling="proportionallyUpOrDown" inset="2" id="115">
|
||||
<behavior key="behavior" lightByContents="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
@@ -115,7 +105,6 @@
|
||||
<constraint firstItem="114" firstAttribute="centerY" secondItem="113" secondAttribute="centerY" id="168"/>
|
||||
<constraint firstItem="114" firstAttribute="centerX" secondItem="113" secondAttribute="centerX" id="169"/>
|
||||
</constraints>
|
||||
<animations/>
|
||||
</customView>
|
||||
</objects>
|
||||
<resources>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="12121" systemVersion="16F73" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="12121"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
@@ -7,12 +7,14 @@
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="MPPasswordInputController">
|
||||
<connections>
|
||||
<outlet property="cancelButton" destination="2pb-ZG-spA" id="YrR-Yi-dnQ"/>
|
||||
<outlet property="enablePasswordCheckBox" destination="d8O-Ha-rrS" id="2AI-e9-sph"/>
|
||||
<outlet property="errorImageView" destination="262" id="294"/>
|
||||
<outlet property="errorInfoTextField" destination="268" id="67b-K9-DZd"/>
|
||||
<outlet property="keyPathControl" destination="241" id="261"/>
|
||||
<outlet property="passwordTextField" destination="338" id="495"/>
|
||||
<outlet property="togglePasswordButton" destination="408" id="493"/>
|
||||
<outlet property="unlockButton" destination="2" id="ZRr-Ui-ExP"/>
|
||||
<outlet property="view" destination="1" id="143"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
@@ -102,6 +104,19 @@ DQ
|
||||
<font key="font" metaFont="system"/>
|
||||
</buttonCell>
|
||||
</button>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="2pb-ZG-spA">
|
||||
<rect key="frame" x="236" y="64" width="82" height="32"/>
|
||||
<buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="erj-mR-UyO">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" metaFont="system"/>
|
||||
<string key="keyEquivalent" base64-UTF8="YES">
|
||||
Gw
|
||||
</string>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="_submit:" target="-2" id="aVF-1d-1Hq"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="2" secondAttribute="bottom" constant="20" symbolic="YES" id="122"/>
|
||||
@@ -125,11 +140,13 @@ DQ
|
||||
<constraint firstItem="408" firstAttribute="trailing" secondItem="486" secondAttribute="trailing" id="492"/>
|
||||
<constraint firstItem="2" firstAttribute="trailing" secondItem="486" secondAttribute="trailing" id="496"/>
|
||||
<constraint firstItem="408" firstAttribute="leading" secondItem="338" secondAttribute="trailing" constant="8" symbolic="YES" id="7qE-8F-QgB"/>
|
||||
<constraint firstItem="2pb-ZG-spA" firstAttribute="baseline" secondItem="2" secondAttribute="baseline" id="9nK-MH-Ozs"/>
|
||||
<constraint firstItem="338" firstAttribute="leading" secondItem="d8O-Ha-rrS" secondAttribute="trailing" constant="8" symbolic="YES" id="KYs-Ia-SVl"/>
|
||||
<constraint firstItem="d8O-Ha-rrS" firstAttribute="centerY" secondItem="338" secondAttribute="centerY" id="kgB-jV-OGy"/>
|
||||
<constraint firstItem="d8O-Ha-rrS" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="1" secondAttribute="leading" constant="20" symbolic="YES" id="vxq-YP-UhR"/>
|
||||
<constraint firstItem="2" firstAttribute="leading" secondItem="2pb-ZG-spA" secondAttribute="trailing" constant="12" id="ytJ-5Z-5rT"/>
|
||||
</constraints>
|
||||
<point key="canvasLocation" x="91" y="140"/>
|
||||
<point key="canvasLocation" x="-240" y="25"/>
|
||||
</customView>
|
||||
</objects>
|
||||
<resources>
|
||||
|
||||
@@ -151,7 +151,7 @@ FOUNDATION_EXPORT NSString *const MPDocumentGroupKey;
|
||||
|
||||
- (void)writeXMLToURL:(NSURL *)url;
|
||||
- (void)readXMLfromURL:(NSURL *)url;
|
||||
- (void)mergeWithContentsFromURL:(NSURL *)url;
|
||||
- (void)mergeWithContentsFromURL:(NSURL *)url key:(KPKCompositeKey *)key;
|
||||
|
||||
/* Undoable Intiialization of elements */
|
||||
- (KPKGroup *)createGroup:(KPKGroup *)parent;
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#import "MPTreeDelegate.h"
|
||||
#import "MPTargetNodeResolving.h"
|
||||
#import "MPErrorRecoveryAttempter.h"
|
||||
#import "MPPasswordInputController.h"
|
||||
|
||||
#import "KeePassKit/KeePassKit.h"
|
||||
|
||||
@@ -334,7 +335,7 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGrou
|
||||
}
|
||||
|
||||
if(strategy == MPFileChangeStrategyMerge) {
|
||||
[self mergeWithContentsFromURL:self.fileURL];
|
||||
[self mergeWithContentsFromURL:self.fileURL key:self.compositeKey];
|
||||
}
|
||||
else if(strategy == MPFileChangeStrategyUseOther) {
|
||||
[self revertToContentsOfURL:self.fileURL ofType:self.fileType error:nil];
|
||||
@@ -357,29 +358,53 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGrou
|
||||
self.encryptedData = nil;
|
||||
}
|
||||
|
||||
- (void)mergeWithContentsFromURL:(NSURL *)url {
|
||||
/* TODO read file to check what format to use */
|
||||
- (void)mergeWithContentsFromURL:(NSURL *)url key:(KPKCompositeKey *)key {
|
||||
NSError *error;
|
||||
KPKTree *otherTree = [[KPKTree alloc] initWithContentsOfUrl:url key:self.compositeKey error:&error];
|
||||
if(!otherTree) {
|
||||
if(error.code == KPKErrorPasswordAndOrKeyfileWrong) {
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
alert.alertStyle = NSAlertStyleWarning;
|
||||
alert.informativeText = NSLocalizedString(@"ALERT_MERGE_OTHER_KEY_CHANGED", @"");
|
||||
[self presentError:error];
|
||||
}
|
||||
else {
|
||||
[self presentError:error];
|
||||
}
|
||||
KPKTree *otherTree;
|
||||
|
||||
if(key) {
|
||||
otherTree = [[KPKTree alloc] initWithContentsOfUrl:url key:key error:&error];
|
||||
}
|
||||
else {
|
||||
|
||||
if(otherTree) {
|
||||
[self.tree syncronizeWithTree:otherTree options:KPKSynchronizationSynchronizeOption];
|
||||
/* the key might have changed so update ours! */
|
||||
//self.compositeKey = key;
|
||||
NSUserNotification *notification = [[NSUserNotification alloc] init];
|
||||
notification.title = NSApp.applicationName;
|
||||
notification.informativeText = NSLocalizedString(@"AUTO_MERGE_NOTIFICATION_TEXT", @"");
|
||||
notification.deliveryDate = NSDate.date;
|
||||
[NSUserNotificationCenter.defaultUserNotificationCenter scheduleNotification:notification];
|
||||
|
||||
}
|
||||
else {
|
||||
if(!key || error.code == KPKErrorPasswordAndOrKeyfileWrong) {
|
||||
NSWindow *sheet = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 100, 100)
|
||||
styleMask:NSWindowStyleMaskTitled|NSWindowStyleMaskClosable|NSWindowStyleMaskResizable
|
||||
backing:NSBackingStoreBuffered
|
||||
defer:NO];
|
||||
MPPasswordInputController *passwordInputController = [[MPPasswordInputController alloc] init];
|
||||
__weak MPDocument *welf = self;
|
||||
[passwordInputController requestPasswordWithMessage:NSLocalizedString(@"EXTERN_CHANGE_OF_MASTERKEY", @"The master key was changed by an extrenal programm!")
|
||||
cancelLabel:NSLocalizedString(@"ABORT_MERGE_KEEP_MINE", @"Button label to abort a merge on a file with changed master key!")
|
||||
completionHandler:^BOOL(NSString *password, NSURL *keyURL, BOOL didCancel, NSError *__autoreleasing *error) {
|
||||
[welf.windowForSheet endSheet:sheet returnCode:(didCancel ? NSModalResponseCancel : NSModalResponseOK)];
|
||||
if(!didCancel) {
|
||||
KPKCompositeKey *compositeKey = [[KPKCompositeKey alloc] initWithPassword:password key:keyURL];
|
||||
[welf mergeWithContentsFromURL:url key:compositeKey];
|
||||
}
|
||||
// just return yes regardless since we will display the sheet again if needed!
|
||||
return YES;
|
||||
}];
|
||||
sheet.contentViewController = passwordInputController;
|
||||
[self.windowForSheet beginSheet:sheet completionHandler:^(NSModalResponse returnCode) { /* nothing to do, rest is done in other handler! */ }];
|
||||
}
|
||||
else {
|
||||
/* unable to merge */
|
||||
NSAlert *alert = [NSAlert alertWithError:error];
|
||||
[alert beginSheetModalForWindow:self.windowForSheet completionHandler:^(NSModalResponse returnCode) {
|
||||
// do nothing;
|
||||
}];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -305,7 +305,7 @@ typedef void (^MPPasswordChangedBlock)(BOOL didChangePassword);
|
||||
//openPanel.allowedFileTypes = @[(id)kUTTypeXML];
|
||||
[openPanel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result) {
|
||||
if(result == NSFileHandlingPanelOKButton) {
|
||||
[document mergeWithContentsFromURL:openPanel.URL];
|
||||
[document mergeWithContentsFromURL:openPanel.URL key:document.compositeKey];
|
||||
}
|
||||
}];
|
||||
}
|
||||
@@ -324,7 +324,10 @@ typedef void (^MPPasswordChangedBlock)(BOOL didChangePassword);
|
||||
}
|
||||
[self _setContentViewController:self.passwordInputController];
|
||||
__weak MPDocumentWindowController *welf = self;
|
||||
[self.passwordInputController requestPasswordWithCompletionHandler:^BOOL(NSString *password, NSURL *keyURL, NSError *__autoreleasing *error) {
|
||||
[self.passwordInputController requestPasswordWithCompletionHandler:^BOOL(NSString *password, NSURL *keyURL, BOOL cancel, NSError *__autoreleasing *error) {
|
||||
if(cancel) {
|
||||
return NO;
|
||||
}
|
||||
return [((MPDocument *)welf.document) unlockWithPassword:password keyFileURL:keyURL error:error];
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -12,8 +12,10 @@
|
||||
|
||||
@interface MPPasswordInputController : MPViewController
|
||||
|
||||
typedef BOOL (^passwordInputCompletionBlock)(NSString *password, NSURL *keyURL, NSError *__autoreleasing*error);
|
||||
typedef BOOL (^passwordInputCompletionBlock)(NSString *password, NSURL *keyURL, BOOL didCancel, NSError *__autoreleasing*error);
|
||||
|
||||
- (void)requestPasswordWithCompletionHandler:(passwordInputCompletionBlock)completionHandler;
|
||||
- (void)requestPasswordWithMessage:(NSString *)message cancelLabel:(NSString *)cancelLabel completionHandler:(passwordInputCompletionBlock)completionHandler;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@@ -26,6 +26,11 @@
|
||||
@property (weak) IBOutlet NSTextField *errorInfoTextField;
|
||||
@property (weak) IBOutlet NSButton *togglePasswordButton;
|
||||
@property (weak) IBOutlet NSButton *enablePasswordCheckBox;
|
||||
@property (weak) IBOutlet NSButton *unlockButton;
|
||||
@property (weak) IBOutlet NSButton *cancelButton;
|
||||
|
||||
@property (copy) NSString *message;
|
||||
@property (copy) NSString *cancelLabel;
|
||||
|
||||
@property (assign) BOOL showPassword;
|
||||
@property (nonatomic, assign) BOOL enablePassword;
|
||||
@@ -66,11 +71,17 @@
|
||||
return self.passwordTextField;
|
||||
}
|
||||
|
||||
- (void)requestPasswordWithCompletionHandler:(passwordInputCompletionBlock)completionHandler {
|
||||
- (void)requestPasswordWithMessage:(NSString *)message cancelLabel:(NSString *)cancelLabel completionHandler:(passwordInputCompletionBlock)completionHandler {
|
||||
self.completionHandler = completionHandler;
|
||||
self.message = message;
|
||||
self.cancelLabel = cancelLabel;
|
||||
[self _reset];
|
||||
}
|
||||
|
||||
- (void)requestPasswordWithCompletionHandler:(passwordInputCompletionBlock)completionHandler {
|
||||
[self requestPasswordWithMessage:nil cancelLabel:nil completionHandler:completionHandler];
|
||||
}
|
||||
|
||||
#pragma mark Properties
|
||||
- (void)setEnablePassword:(BOOL)enablePassword {
|
||||
if(_enablePassword != enablePassword) {
|
||||
@@ -87,14 +98,24 @@
|
||||
#pragma mark -
|
||||
#pragma mark Private
|
||||
- (IBAction)_submit:(id)sender {
|
||||
if(self.completionHandler) {
|
||||
/* No password is different than an empty password */
|
||||
NSError *error = nil;
|
||||
NSString *password = self.enablePassword ? self.passwordTextField.stringValue : nil;
|
||||
if(!self.completionHandler(password, self.keyPathControl.URL, &error)) {
|
||||
[self _showError:error];
|
||||
[self.view.window shakeWindow:nil];
|
||||
}
|
||||
|
||||
if(!self.completionHandler) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* No password is different than an empty password */
|
||||
NSError *error = nil;
|
||||
NSString *password = self.enablePassword ? self.passwordTextField.stringValue : nil;
|
||||
|
||||
BOOL cancel = (sender == self.cancelButton);
|
||||
BOOL result = self.completionHandler(password, self.keyPathControl.URL, cancel, &error);
|
||||
if(cancel || result) {
|
||||
return;
|
||||
}
|
||||
[self _showError:error];
|
||||
/* do not shake if we are a sheet */
|
||||
if(!self.view.window.isSheet) {
|
||||
[self.view.window shakeWindow:nil];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,8 +133,15 @@
|
||||
self.showPassword = NO;
|
||||
self.enablePassword = YES;
|
||||
self.passwordTextField.stringValue = @"";
|
||||
self.errorInfoTextField.hidden = YES;
|
||||
self.errorImageView.hidden = YES;
|
||||
self.errorInfoTextField.hidden = (nil == self.message);
|
||||
if(self.message) {
|
||||
self.errorInfoTextField.stringValue = self.message;
|
||||
}
|
||||
self.errorImageView.hidden = (nil == self.message);;
|
||||
self.cancelButton.hidden = (nil == self.cancelLabel);
|
||||
if(self.cancelLabel) {
|
||||
self.cancelButton.stringValue = self.cancelLabel;
|
||||
}
|
||||
[self resetKeyFile:self];
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user