diff --git a/MacPass.xcodeproj/project.pbxproj b/MacPass.xcodeproj/project.pbxproj index 781c4b21..8aa15cd9 100644 --- a/MacPass.xcodeproj/project.pbxproj +++ b/MacPass.xcodeproj/project.pbxproj @@ -72,6 +72,8 @@ 4C431BCD16E2A82800700A81 /* MPPasteBoardController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C431BCC16E2A82700700A81 /* MPPasteBoardController.m */; }; 4C431BCF16E2BAB000700A81 /* OverlayWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4C431BCE16E2BAB000700A81 /* OverlayWindow.xib */; }; 4C4436771792BE810099E220 /* KPKFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C4436761792BE810099E220 /* KPKFormat.m */; }; + 4C4510091798C53700219998 /* StringField+Validation.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C4510081798C53700219998 /* StringField+Validation.m */; }; + 4C45100C1798C65C00219998 /* Kdb4Entry+MPAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C45100B1798C65C00219998 /* Kdb4Entry+MPAdditions.m */; }; 4C45FB1C178E09ED0010007D /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C45FB1B178E09ED0010007D /* SenTestingKit.framework */; }; 4C45FB1D178E09ED0010007D /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C77E36615B84A240093A587 /* Cocoa.framework */; }; 4C45FB23178E09ED0010007D /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4C45FB21178E09ED0010007D /* InfoPlist.strings */; }; @@ -352,6 +354,10 @@ 4C431BCE16E2BAB000700A81 /* OverlayWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = OverlayWindow.xib; sourceTree = ""; }; 4C4436751792BE810099E220 /* KPKFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KPKFormat.h; sourceTree = ""; }; 4C4436761792BE810099E220 /* KPKFormat.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KPKFormat.m; sourceTree = ""; }; + 4C4510071798C53700219998 /* StringField+Validation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "StringField+Validation.h"; sourceTree = ""; }; + 4C4510081798C53700219998 /* StringField+Validation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "StringField+Validation.m"; sourceTree = ""; }; + 4C45100A1798C65C00219998 /* Kdb4Entry+MPAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Kdb4Entry+MPAdditions.h"; sourceTree = ""; }; + 4C45100B1798C65C00219998 /* Kdb4Entry+MPAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "Kdb4Entry+MPAdditions.m"; sourceTree = ""; }; 4C45FB1A178E09ED0010007D /* MacPassTests.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MacPassTests.octest; sourceTree = BUILT_PRODUCTS_DIR; }; 4C45FB1B178E09ED0010007D /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; }; 4C45FB20178E09ED0010007D /* MacPassTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "MacPassTests-Info.plist"; sourceTree = ""; }; @@ -931,6 +937,10 @@ 4C83F4A91774B155006C5FC0 /* Kdb3Tree+NewTree.m */, 4C83F4AB1774B25F006C5FC0 /* Kdb4Tree+NewTree.h */, 4C83F4AC1774B25F006C5FC0 /* Kdb4Tree+NewTree.m */, + 4C4510071798C53700219998 /* StringField+Validation.h */, + 4C4510081798C53700219998 /* StringField+Validation.m */, + 4C45100A1798C65C00219998 /* Kdb4Entry+MPAdditions.h */, + 4C45100B1798C65C00219998 /* Kdb4Entry+MPAdditions.m */, ); name = "KeePassLib Categories"; sourceTree = ""; @@ -1820,6 +1830,8 @@ 4CC0D2D117974A5A000B4BDA /* MPAttachmentTableViewDelegate.m in Sources */, 4C67D33017981A2B00A7BDFC /* HNHTokenField.m in Sources */, 4C67D33317981ABA00A7BDFC /* HNHTokenFieldCell.m in Sources */, + 4C4510091798C53700219998 /* StringField+Validation.m in Sources */, + 4C45100C1798C65C00219998 /* Kdb4Entry+MPAdditions.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/MacPass/Kdb4Entry+MPAdditions.h b/MacPass/Kdb4Entry+MPAdditions.h new file mode 100644 index 00000000..05b9c09f --- /dev/null +++ b/MacPass/Kdb4Entry+MPAdditions.h @@ -0,0 +1,15 @@ +// +// Kdb4Entry+MPAdditions.h +// MacPass +// +// Created by Michael Starke on 19.07.13. +// Copyright (c) 2013 HicknHack Software GmbH. All rights reserved. +// + +#import "Kdb4Node.h" + +@interface Kdb4Entry (MPAdditions) + +- (NSString *)uniqueKeyForProposal:(NSString *)key; + +@end diff --git a/MacPass/Kdb4Entry+MPAdditions.m b/MacPass/Kdb4Entry+MPAdditions.m new file mode 100644 index 00000000..57bfc47e --- /dev/null +++ b/MacPass/Kdb4Entry+MPAdditions.m @@ -0,0 +1,29 @@ +// +// Kdb4Entry+MPAdditions.m +// MacPass +// +// Created by Michael Starke on 19.07.13. +// Copyright (c) 2013 HicknHack Software GmbH. All rights reserved. +// + +#import "Kdb4Entry+MPAdditions.h" + +@implementation Kdb4Entry (MPAdditions) + +- (NSString *)uniqueKeyForProposal:(NSString *)key { + /* + FIXME: Introduce some cachin behaviour. We iterate over after every single edit + */ + NSMutableSet *keys = [[NSMutableSet alloc] initWithCapacity:[self.stringFields count]]; + for(StringField *field in self.stringFields) { + [keys addObject:field.key]; + } + NSUInteger counter = 1; + NSString *base = key; + while([keys containsObject:key]) { + key = [NSString stringWithFormat:@"%@-%ld", base, counter++]; + } + return key; +} + +@end diff --git a/MacPass/MPCustomFieldTableViewDelegate.m b/MacPass/MPCustomFieldTableViewDelegate.m index f4b7eecd..89f7e231 100644 --- a/MacPass/MPCustomFieldTableViewDelegate.m +++ b/MacPass/MPCustomFieldTableViewDelegate.m @@ -24,7 +24,8 @@ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_customFieldFrameChanged:) name:NSViewFrameDidChangeNotification object:view]; if([self.viewController.selectedEntry isKindOfClass:[Kdb4Entry class]]) { StringField *stringField = entry.stringFields[row]; - [view.labelTextField bind:NSValueBinding toObject:stringField withKeyPath:MPStringFieldKeyUndoableKey options:nil]; + NSDictionary *validateOptions = @{ NSValidatesImmediatelyBindingOption: @YES }; + [view.labelTextField bind:NSValueBinding toObject:stringField withKeyPath:MPStringFieldKeyUndoableKey options:validateOptions]; [view.valueTextField bind:NSValueBinding toObject:stringField withKeyPath:MPStringFieldValueUndoableKey options:nil]; [view.removeButton setTarget:self.viewController]; [view.removeButton setAction:@selector(removeCustomField:)]; diff --git a/MacPass/MPDocument.m b/MacPass/MPDocument.m index 37b55bea..c2df2f35 100644 --- a/MacPass/MPDocument.m +++ b/MacPass/MPDocument.m @@ -19,14 +19,18 @@ #import "Kdb4Node.h" #import "Kdb4Persist.h" #import "KdbPassword.h" -#import "KdbGroup+Undo.h" + #import "KdbGroup+KVOAdditions.h" #import "Kdb4Entry+KVOAdditions.h" -#import "KdbGroup+MPTreeTools.h" -#import "KdbGroup+MPAdditions.h" + #import "KdbEntry+Undo.h" +#import "KdbGroup+Undo.h" + #import "Kdb3Tree+NewTree.h" #import "Kdb4Tree+NewTree.h" +#import "Kdb4Entry+MPAdditions.h" +#import "KdbGroup+MPTreeTools.h" +#import "KdbGroup+MPAdditions.h" #import "DataOutputStream.h" @@ -349,6 +353,7 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGroupKey"; Kdb4Entry *entryV4 = (Kdb4Entry *)entry; NSString *title = NSLocalizedString(@"DEFAULT_CUSTOM_FIELD_TITLE", @"Default Titel for new Custom-Fields"); NSString *value = NSLocalizedString(@"DEFAULT_CUSTOM_FIELD_VALUE", @"Default Value for new Custom-Fields"); + title = [entryV4 uniqueKeyForProposal:title]; StringField *newStringField = [StringField stringFieldWithKey:title andValue:value]; [self addStringField:newStringField toEntry:entryV4 atIndex:[entryV4.stringFields count]]; return newStringField; @@ -419,6 +424,7 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGroupKey"; - (void)addStringField:(StringField *)field toEntry:(Kdb4Entry *)entry atIndex:(NSUInteger)index { [[[self undoManager] prepareWithInvocationTarget:self] removeStringField:field formEntry:entry]; [[self undoManager] setActionName:NSLocalizedString(@"UNDO_ADD_STRING_FIELD", @"Add Stringfield Undo")]; + field.entry = entry; [entry insertObject:field inStringFieldsAtIndex:index]; } @@ -429,6 +435,7 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGroupKey"; } [[[self undoManager] prepareWithInvocationTarget:self] addStringField:field toEntry:entry atIndex:index]; [[self undoManager] setActionName:NSLocalizedString(@"UNDO_DELETE_STRING_FIELD", @"Delte Stringfield undo")]; + field.entry = nil; [entry removeObjectFromStringFieldsAtIndex:index]; } diff --git a/MacPass/StringField+Validation.h b/MacPass/StringField+Validation.h new file mode 100644 index 00000000..ef310f81 --- /dev/null +++ b/MacPass/StringField+Validation.h @@ -0,0 +1,13 @@ +// +// StringField+Validation.h +// MacPass +// +// Created by Michael Starke on 19.07.13. +// Copyright (c) 2013 HicknHack Software GmbH. All rights reserved. +// + +#import "Kdb4Node.h" + +@interface StringField (Validation) + +@end diff --git a/MacPass/StringField+Validation.m b/MacPass/StringField+Validation.m new file mode 100644 index 00000000..e216b9f3 --- /dev/null +++ b/MacPass/StringField+Validation.m @@ -0,0 +1,19 @@ +// +// StringField+Validation.m +// MacPass +// +// Created by Michael Starke on 19.07.13. +// Copyright (c) 2013 HicknHack Software GmbH. All rights reserved. +// + +#import "StringField+Validation.h" +#import "Kdb4Entry+MPAdditions.h" + +@implementation StringField (Validation) + +- (BOOL)validateValue:(inout __autoreleasing id *)ioValue forKey:(NSString *)inKey error:(out NSError *__autoreleasing *)outError { + *ioValue = [self.entry uniqueKeyForProposal:*ioValue]; + return YES; +} + +@end diff --git a/MiniKeePassLib b/MiniKeePassLib index def7d0c2..f23dd68c 160000 --- a/MiniKeePassLib +++ b/MiniKeePassLib @@ -1 +1 @@ -Subproject commit def7d0c27d16adf967e51692191d6b2f51da7263 +Subproject commit f23dd68cb4fe701e089042672cf7322877a8deed