From 9c3a62bef6731523064c8e67ca17befa7fcf0285 Mon Sep 17 00:00:00 2001 From: michael starke Date: Fri, 5 Jul 2013 20:09:17 +0200 Subject: [PATCH] Added support to save and load Attachemnts on KeePass2 Databases. Support for Keepass1 DBs is still missing --- MacPass.xcodeproj/project.pbxproj | 4 + MacPass/Base.lproj/InspectorView.xib | 35 ++++++- MacPass/Kdb4Entry+KVOAdditions.h | 4 + MacPass/Kdb4Entry+KVOAdditions.m | 18 ++++ MacPass/KdbTree+MPAdditions.h | 7 +- MacPass/KdbTree+MPAdditions.m | 58 +----------- MacPass/MPDocument+Attachments.m | 135 +++++++++++++++++++++++++++ MacPass/MPDocument.h | 14 ++- MacPass/MPDocument.m | 13 --- MacPass/MPInspectorViewController.m | 54 ++++++++++- MacPass/MacPass-Info.plist | 4 +- MacPass/de.lproj/Credits.rtf | 8 +- MacPass/en.lproj/Credits.rtf | 10 +- MiniKeePassLib | 2 +- 14 files changed, 272 insertions(+), 94 deletions(-) create mode 100644 MacPass/MPDocument+Attachments.m diff --git a/MacPass.xcodeproj/project.pbxproj b/MacPass.xcodeproj/project.pbxproj index 71d9dc22..e12b056c 100644 --- a/MacPass.xcodeproj/project.pbxproj +++ b/MacPass.xcodeproj/project.pbxproj @@ -52,6 +52,7 @@ 4C2E381F16D11FF900037A9D /* 05_LanguagesTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 4C2E381C16D11FF900037A9D /* 05_LanguagesTemplate.pdf */; }; 4C2E382316D1421B00037A9D /* MPIconHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C2E382216D1421B00037A9D /* MPIconHelper.m */; }; 4C2E382616D1470200037A9D /* MPViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C2E382516D1470200037A9D /* MPViewController.m */; }; + 4C3666411787327E00B249F1 /* MPDocument+Attachments.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3666401787327E00B249F1 /* MPDocument+Attachments.m */; }; 4C36E5B4177CD4FB00152132 /* Kdb4Tree+KVOAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C36E5B3177CD4FB00152132 /* Kdb4Tree+KVOAdditions.m */; }; 4C37A6731769393300AD0A40 /* HNHTableHeaderCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C37A6721769393300AD0A40 /* HNHTableHeaderCell.m */; }; 4C37A84015B8B474005EF8EE /* MPOutlineDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C37A83F15B8B474005EF8EE /* MPOutlineDataSource.m */; }; @@ -284,6 +285,7 @@ 4C2E382216D1421B00037A9D /* MPIconHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPIconHelper.m; sourceTree = ""; }; 4C2E382416D1470200037A9D /* MPViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPViewController.h; sourceTree = ""; }; 4C2E382516D1470200037A9D /* MPViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPViewController.m; sourceTree = ""; }; + 4C3666401787327E00B249F1 /* MPDocument+Attachments.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MPDocument+Attachments.m"; sourceTree = ""; }; 4C36E5B2177CD4FB00152132 /* Kdb4Tree+KVOAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Kdb4Tree+KVOAdditions.h"; sourceTree = ""; }; 4C36E5B3177CD4FB00152132 /* Kdb4Tree+KVOAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "Kdb4Tree+KVOAdditions.m"; sourceTree = ""; }; 4C37A6711769393300AD0A40 /* HNHTableHeaderCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HNHTableHeaderCell.h; sourceTree = ""; }; @@ -851,6 +853,7 @@ 4CE5B549173AFBA700207B39 /* MPDocument.m */, 4C5EC300177B700D00DA955B /* MPRootAdapter.h */, 4C5EC301177B700D00DA955B /* MPRootAdapter.m */, + 4C3666401787327E00B249F1 /* MPDocument+Attachments.m */, ); name = Model; sourceTree = ""; @@ -1520,6 +1523,7 @@ 4CC6727C1781D0D2006DEDCF /* KdbEntry+MPAdditions.m in Sources */, 4C5FE9AE17843CE20001D5A8 /* MPSelectedAttachmentTableCellView.m in Sources */, 4CF1F0CA1786B37900CD920E /* NSData+Gzip.m in Sources */, + 4C3666411787327E00B249F1 /* MPDocument+Attachments.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/MacPass/Base.lproj/InspectorView.xib b/MacPass/Base.lproj/InspectorView.xib index cb00c684..c9daacce 100644 --- a/MacPass/Base.lproj/InspectorView.xib +++ b/MacPass/Base.lproj/InspectorView.xib @@ -137,7 +137,6 @@ {293, 30} - _NS:9 HNHGradientView @@ -634,7 +633,6 @@ 256 {{236, 1}, {16, 332}} - _NS:83 NO @@ -1269,6 +1267,14 @@ 2068 + + + addAttachment: + + + + 2244 + imageView @@ -1546,6 +1552,14 @@ 2215 + + + saveButton + + + + 2243 + @@ -4934,7 +4948,7 @@ - 2241 + 2244 @@ -5017,10 +5031,21 @@ MPInspectorViewController MPViewController + id + id id id + id + + _popUpPasswordGenerator: + id + + + addAttachment: + id + addCustomField: id @@ -5029,6 +5054,10 @@ removeCustomField: id + + saveAttachment: + id + NSTextField diff --git a/MacPass/Kdb4Entry+KVOAdditions.h b/MacPass/Kdb4Entry+KVOAdditions.h index 9afe4aa8..38e719b3 100644 --- a/MacPass/Kdb4Entry+KVOAdditions.h +++ b/MacPass/Kdb4Entry+KVOAdditions.h @@ -15,5 +15,9 @@ - (void)removeObjectFromStringFieldsAtIndex:(NSUInteger)anIndex; - (void)insertObject:(StringField *)stringfield inStringFieldsAtIndex:(NSUInteger)anIndex; +- (NSUInteger)countOfBinaries; +- (BinaryRef *)objectInBinariesAtIndex:(NSUInteger)index; +- (void)removeObjectFromBinariesAtIndex:(NSUInteger)index; +- (void)insertObject:(BinaryRef *)binary inBinariesAtIndex:(NSUInteger)index; @end diff --git a/MacPass/Kdb4Entry+KVOAdditions.m b/MacPass/Kdb4Entry+KVOAdditions.m index 0f2cc7d9..b303ff77 100644 --- a/MacPass/Kdb4Entry+KVOAdditions.m +++ b/MacPass/Kdb4Entry+KVOAdditions.m @@ -10,6 +10,7 @@ @implementation Kdb4Entry (KVOAdditions) +/* Entries */ - (NSUInteger)countOfStringFields { return [self.stringFields count]; } @@ -26,4 +27,21 @@ [self.stringFields removeObjectAtIndex:anIndex]; } +/* Binaries */ +- (NSUInteger)countOfBinaries { + return [self.binaries count]; +} + +- (BinaryRef *)objectInBinariesAtIndex:(NSUInteger)index { + return (self.binaries)[index]; +} + +- (void)insertObject:(BinaryRef *)binary inBinariesAtIndex:(NSUInteger)index { + [self.binaries insertObject:binary atIndex:index]; +} + +- (void)removeObjectFromBinariesAtIndex:(NSUInteger)index { + [self.binaries removeObjectAtIndex:index]; +} + @end diff --git a/MacPass/KdbTree+MPAdditions.h b/MacPass/KdbTree+MPAdditions.h index 8bdff8f4..42f30555 100644 --- a/MacPass/KdbTree+MPAdditions.h +++ b/MacPass/KdbTree+MPAdditions.h @@ -9,6 +9,7 @@ #import "Kdb.h" @class BinaryRef; +@class Binary; @interface KdbTree (MPAdditions) @@ -16,10 +17,4 @@ - (NSArray *)allGroups; -- (void)addAttachment:(NSURL *)location toEntry:(KdbEntry *)anEntry; -- (void)saveAttachmentFromEntry:(KdbEntry *)anEntry toLocation:(NSURL *)location; -- (void)saveAttachment:(BinaryRef *)reference toLocation:(NSURL *)location; -- (NSUInteger)nextBinaryId; - - @end diff --git a/MacPass/KdbTree+MPAdditions.m b/MacPass/KdbTree+MPAdditions.m index ea4a27ae..b9b86cb6 100644 --- a/MacPass/KdbTree+MPAdditions.m +++ b/MacPass/KdbTree+MPAdditions.m @@ -9,6 +9,7 @@ #import "KdbTree+MPAdditions.h" #import "KdbGroup+MPTreeTools.h" +#import "NSMutableData+Base64.h" #import "Kdb3Node.h" #import "Kdb4Node.h" @@ -22,61 +23,4 @@ return [self.root childEntries]; } -- (void)addAttachment:(NSURL *)location toEntry:(KdbEntry *)anEntry { - NSError *error = nil; - NSString *fileName = [NSString stringWithFormat:@"%@.%@", [location lastPathComponent], [location pathExtension]]; - if([anEntry isKindOfClass:[Kdb3Entry class]]) { - Kdb3Entry *entry = (Kdb3Entry *)anEntry; - NSData *binaryData = [NSData dataWithContentsOfURL:location options:NSDataReadingUncached error:&error]; - if(!binaryData) { - [NSApp presentError:error]; - binaryData = nil; - error = nil; - return; // failed - } - entry.binary = binaryData; - entry.binaryDesc = fileName; - } - if( [anEntry isKindOfClass:[Kdb4Entry class]]) { - Kdb4Entry *entry = (Kdb4Entry *)anEntry; - Kdb4Tree *tree = (Kdb4Tree *)self; - NSString *fileData = [NSString stringWithContentsOfURL:location usedEncoding:0 error:&error]; - if(!fileData) { - [NSApp presentError:error]; - fileData = nil; - error = nil; - return; // failed - } - Binary *binary = [[Binary alloc] init]; - binary.binaryId = [self nextBinaryId]; - binary.compressed = (tree.compressionAlgorithm == KPLCompressionGzip); - if(binary.compressed ) { - - } - binary.data = fileData; - - [tree.binaries addObject:binary]; - BinaryRef *ref = [[BinaryRef alloc] init]; - ref.key = fileName; - [entry.binaries addObject:ref]; - } -} - -- (void)saveAttachment:(BinaryRef *)reference toLocation:(NSURL *)location { - -} - -- (void)saveAttachmentFromEntry:(KdbEntry *)entry toLocation:(NSURL *)location { - -} - -- (NSUInteger)nextBinaryId { - Kdb4Tree *tree = (Kdb4Tree *)self; - NSUInteger maxKey = 0; - for(Binary *binary in tree.binaries) { - maxKey = MAX(binary.binaryId, maxKey); - } - return (maxKey + 1); -} - @end diff --git a/MacPass/MPDocument+Attachments.m b/MacPass/MPDocument+Attachments.m new file mode 100644 index 00000000..80b6c36a --- /dev/null +++ b/MacPass/MPDocument+Attachments.m @@ -0,0 +1,135 @@ +// +// MPDocument+Attachments.m +// MacPass +// +// Created by Michael Starke on 05.07.13. +// Copyright (c) 2013 HicknHack Software GmbH. All rights reserved. +// + +#import "MPDocument.h" + +#import "NSMutableData+Base64.h" +#import "NSData+Gzip.h" + +#import "Kdb3Node.h" +#import "Kdb4Node.h" +#import "Kdb4Entry+KVOAdditions.h" + +@implementation MPDocument (Attachments) + +- (void)addAttachment:(NSURL *)location toEntry:(KdbEntry *)anEntry { + NSError *error = nil; + NSString *fileName = [location lastPathComponent]; + if([anEntry isKindOfClass:[Kdb3Entry class]]) { + Kdb3Entry *entry = (Kdb3Entry *)anEntry; + NSData *binaryData = [NSData dataWithContentsOfURL:location options:NSDataReadingUncached error:&error]; + if(!binaryData) { + [NSApp presentError:error]; + binaryData = nil; + error = nil; + return; // failed + } + entry.binary = binaryData; + entry.binaryDesc = fileName; + } + if( [anEntry isKindOfClass:[Kdb4Entry class]]) { + Kdb4Entry *entry = (Kdb4Entry *)anEntry; + NSStringEncoding encoding; + NSString *fileContents = [NSString stringWithContentsOfURL:location usedEncoding:&encoding error:&error]; + if(!fileContents) { + [NSApp presentError:error]; + fileContents = nil; + error = nil; + return; // failed + } + Binary *binary = [[Binary alloc] init]; + NSUInteger nextId = [self nextBinaryId]; + if(nextId == NSNotFound) { + binary = nil; + return; // No id found. Something went wrong + } + binary.binaryId = nextId; + binary.compressed = (self.treeV4.compressionAlgorithm != KPLCompressionNone); + NSData *encodedData; + NSData *fileData = [fileContents dataUsingEncoding:encoding]; + if(binary.compressed) { + switch(self.treeV4.compressionAlgorithm) { + case KPLCompressionGzip: { + NSData *compressedData = [fileData gzipDeflate]; + encodedData = [NSMutableData mutableDataWithBase64EncodedData:compressedData]; + break; + } + default: + NSAssert(NO, @"Unsupported Compression Algorithm"); + binary = nil; + encodedData = nil; + fileData = nil; + return; + } + } + else { + encodedData = fileData; + } + binary.data = [[NSString alloc] initWithData:encodedData encoding:NSASCIIStringEncoding]; + + [self.treeV4.binaries addObject:binary]; + BinaryRef *ref = [[BinaryRef alloc] init]; + ref.key = fileName; + ref.ref = binary.binaryId; + [entry insertObject:ref inBinariesAtIndex:[entry.binaries count]]; + } +} + +- (Binary *)findBinary:(BinaryRef *)reference { + if(self.version != MPDatabaseVersion4) { + return nil; + } + NSPredicate *filterPredicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) { + Binary *binaryFile = evaluatedObject; + return (binaryFile.binaryId == reference.ref); + }]; + NSArray *filteredBinary = [self.treeV4.binaries filteredArrayUsingPredicate:filterPredicate]; + return [filteredBinary lastObject]; +} + +- (void)saveAttachment:(BinaryRef *)reference toLocation:(NSURL *)location { + Binary *binary = [self findBinary:reference]; + NSData *rawData = nil; + if(binary) { + if(binary.compressed) { + rawData = [NSMutableData mutableDataWithBase64DecodedData:[binary.data dataUsingEncoding:NSASCIIStringEncoding]]; + rawData = [rawData gzipInflate]; + } + else { + rawData = [NSMutableData mutableDataWithBase64DecodedData:[binary.data dataUsingEncoding:NSASCIIStringEncoding]]; + } + NSError *error = nil; + if( ![rawData writeToURL:location options:0 error:&error] ) { + [NSApp presentError:error]; + } + } +} + +- (void)saveAttachmentFromEntry:(KdbEntry *)anEntry toLocation:(NSURL *)location { + if([anEntry isKindOfClass:[Kdb3Entry class]]) { + Kdb3Entry *entry = (Kdb3Entry *)anEntry; + NSError *error = nil; + if(! [entry.binary writeToURL:location options:NSDataWritingWithoutOverwriting error:&error] ) { + [NSApp presentError:error]; + } + } + return; // +} + +- (NSUInteger)nextBinaryId { + if(self.version != MPDatabaseVersion4) { + return NSNotFound; + } + NSUInteger maxKey = 0; + for(Binary *binary in self.treeV4.binaries) { + maxKey = MAX(binary.binaryId, maxKey); + } + return (maxKey + 1); +} + +@end diff --git a/MacPass/MPDocument.h b/MacPass/MPDocument.h index a95422a2..44d6c7a6 100644 --- a/MacPass/MPDocument.h +++ b/MacPass/MPDocument.h @@ -57,10 +57,6 @@ APPKIT_EXTERN NSString *const MPDocumentGroupKey; */ - (KdbEntry *)findEntry:(UUID *)uuid; - (KdbGroup *)findGroup:(UUID *)uuid; -/* - Return the Binary for the given BinaryRef. nil if none was found - */ -- (Binary *)binaryForRef:(BinaryRef *)binaryRef; - (Kdb4Tree *)treeV4; - (Kdb3Tree *)treeV3; @@ -93,3 +89,13 @@ APPKIT_EXTERN NSString *const MPDocumentGroupKey; - (void)emptyTrash:(id)sender; @end + +@interface MPDocument (Attachments) + +- (void)addAttachment:(NSURL *)location toEntry:(KdbEntry *)anEntry; +- (void)saveAttachmentFromEntry:(KdbEntry *)anEntry toLocation:(NSURL *)location; +- (void)saveAttachment:(BinaryRef *)reference toLocation:(NSURL *)location; +- (NSUInteger)nextBinaryId; +- (Binary *)findBinary:(BinaryRef *)reference; + +@end \ No newline at end of file diff --git a/MacPass/MPDocument.m b/MacPass/MPDocument.m index 2b2c41c0..a9ff5e72 100644 --- a/MacPass/MPDocument.m +++ b/MacPass/MPDocument.m @@ -217,19 +217,6 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGroupKey"; return [self.root groupForUUID:uuid]; } -- (Binary *)binaryForRef:(BinaryRef *)binaryRef { - if(self.version != MPDatabaseVersion4) { - return nil; - } - NSPredicate *filterPredicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) { - Binary *binaryFile = evaluatedObject; - return (binaryFile.binaryId == binaryRef.ref); - }]; - Kdb4Tree *tree = (Kdb4Tree *)self.tree; - NSArray *filteredBinary = [tree.binaries filteredArrayUsingPredicate:filterPredicate]; - return [filteredBinary lastObject]; -} - - (Kdb3Tree *)treeV3 { switch (_version) { case MPDatabaseVersion3: diff --git a/MacPass/MPInspectorViewController.m b/MacPass/MPInspectorViewController.m index e0fff8b5..ec951529 100644 --- a/MacPass/MPInspectorViewController.m +++ b/MacPass/MPInspectorViewController.m @@ -19,6 +19,7 @@ #import "MPCustomFieldView.h" #import "MPDatabaseVersion.h" #import "MPCustomFieldTableCellView.h" +#import "MPSelectedAttachmentTableCellView.h" #import "KdbLib.h" #import "Kdb4Node.h" @@ -58,6 +59,8 @@ enum { - (IBAction)addCustomField:(id)sender; - (IBAction)removeCustomField:(id)sender; +- (IBAction)saveAttachment:(id)sender; +- (IBAction)addAttachment:(id)sender; @end @@ -91,8 +94,8 @@ enum { [_infoTabControl bind:NSSelectedIndexBinding toObject:self withKeyPath:@"activeTab" options:nil]; [_tabView bind:NSSelectedIndexBinding toObject:self withKeyPath:@"activeTab" options:nil]; - - /* Set background to clearcolor so we can draw in the scrollview */ + + /* Set background to clearcolor so we can draw in the scrollview */ [_attachmentTableView setBackgroundColor:[NSColor clearColor]]; [_attachmentTableView bind:NSContentBinding toObject:self.attachmentsController withKeyPath:@"arrangedObjects" options:nil]; [_attachmentTableView setDelegate:self]; @@ -256,7 +259,7 @@ enum { [self.infoTabControl setEnabled:enabled forSegment:MPNotesTab]; [self.infoTabControl setEnabled:enabled forSegment:MPAttachmentsTab]; - + enabled &= [self.selectedEntry isKindOfClass:[Kdb4Entry class]]; [self.infoTabControl setEnabled:enabled forSegment:MPCustomFieldsTab]; } @@ -313,6 +316,38 @@ enum { [document entry:entry removeStringField:(entry.stringFields)[index]]; } +- (IBAction)saveAttachment:(id)sender { + Kdb4Entry *entry = (Kdb4Entry *)self.selectedEntry; + BinaryRef *reference = entry.binaries[[sender tag]]; + + + NSSavePanel *savePanel = [NSSavePanel savePanel]; + [savePanel setCanCreateDirectories:YES]; + [savePanel setNameFieldStringValue:reference.key]; + + [savePanel beginSheetModalForWindow:[[self windowController] window] completionHandler:^(NSInteger result) { + if(result == NSFileHandlingPanelOKButton) { + MPDocument *document = [[self windowController] document]; + [document saveAttachment:reference toLocation:[savePanel URL]]; + } + }]; +} + +- (IBAction)addAttachment:(id)sender { + NSOpenPanel *openPanel = [NSOpenPanel openPanel]; + [openPanel setCanChooseDirectories:NO]; + [openPanel setCanChooseFiles:YES]; + [openPanel setAllowsMultipleSelection:YES]; + [openPanel beginSheetModalForWindow:[[self windowController] window] completionHandler:^(NSInteger result) { + if(result == NSFileHandlingPanelOKButton) { + MPDocument *document = [[self windowController] document]; + for (NSURL *attachmentURL in [openPanel URLs]) { + [document addAttachment:attachmentURL toEntry:self.selectedEntry]; + } + } + }]; +} + #pragma mark Notificiations - (void)_didChangeCurrentItem:(NSNotification *)notification { MPDocumentWindowController *sender = [notification object]; @@ -354,8 +389,17 @@ enum { - (NSView *)_viewForAttachmentTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row { /* Decide what view to use */ NSIndexSet *selectedIndexes = [self.attachmentTableView selectedRowIndexes]; - NSString *viewIdentifyer = [selectedIndexes containsIndex:row] ? @"SelectedCell" : @"NormalCell"; - NSTableCellView *view = [_attachmentTableView makeViewWithIdentifier:viewIdentifyer owner:_attachmentTableView]; + NSTableCellView *view; + if([selectedIndexes containsIndex:row]) { + MPSelectedAttachmentTableCellView *cellView = [_attachmentTableView makeViewWithIdentifier:@"SelectedCell" owner:_attachmentTableView]; + [cellView.saveButton setTag:row]; + [cellView.saveButton setAction:@selector(saveAttachment:)]; + [cellView.saveButton setTarget:self]; + view = cellView; + } + else { + view = [_attachmentTableView makeViewWithIdentifier:@"NormalCell" owner:_attachmentTableView]; + } /* Bind view */ if([self.selectedEntry isKindOfClass:[Kdb4Entry class]]) { Kdb4Entry *entry = (Kdb4Entry *)self.selectedEntry; diff --git a/MacPass/MacPass-Info.plist b/MacPass/MacPass-Info.plist index 51335c82..1d639afc 100644 --- a/MacPass/MacPass-Info.plist +++ b/MacPass/MacPass-Info.plist @@ -44,11 +44,11 @@ CFBundlePackageType APPL CFBundleShortVersionString - 0.2.1 + 0.3 CFBundleSignature ???? CFBundleVersion - 1923 + 1955 LSMinimumSystemVersion ${MACOSX_DEPLOYMENT_TARGET} NSHumanReadableCopyright diff --git a/MacPass/de.lproj/Credits.rtf b/MacPass/de.lproj/Credits.rtf index f3b8bd65..147d1a12 100644 --- a/MacPass/de.lproj/Credits.rtf +++ b/MacPass/de.lproj/Credits.rtf @@ -31,6 +31,7 @@ You should have received a copy of the GNU General Public License along with thi \b0 MacPass Icon von {\field{\*\fldinst{HYPERLINK "http://iiro.jappinen.me"}}{\fldrslt Iiro J\'e4ppinen}} \b \ \ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720 {\field{\*\fldinst{HYPERLINK "https://github.com/robbiehanson/KissXML"}}{\fldrslt \b0 \cf2 KissXML}} \b0 \cf3 \ @@ -49,4 +50,9 @@ Copyright \'a9 2011, Alex Rozanski. Alle Rechte vorbehalten.\ \ \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720 {\field{\*\fldinst{HYPERLINK "http://stackoverflow.com/questions/11386876/how-to-encode-and-decode-files-as-base64-in-cocoa-objective-c"}}{\fldrslt \cf3 Base64 Encoding Category}}\ -Copyright @2013, {\field{\*\fldinst{HYPERLINK "http://stackoverflow.com/users/200321/denis2342"}}{\fldrslt denis2342}}} \ No newline at end of file +Copyright @2013, {\field{\*\fldinst{HYPERLINK "http://stackoverflow.com/users/200321/denis2342"}}{\fldrslt denis2342}}\ +\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720 +{\field{\*\fldinst{HYPERLINK "http://www.cocoadev.com/index.pl?NSDataCategory"}}{\fldrslt \cf3 NSData+Gzip}}\ +Basierend auf dem Code im CocoaDev Wiki\ +} \ No newline at end of file diff --git a/MacPass/en.lproj/Credits.rtf b/MacPass/en.lproj/Credits.rtf index 3a444031..0ed44d07 100644 --- a/MacPass/en.lproj/Credits.rtf +++ b/MacPass/en.lproj/Credits.rtf @@ -36,6 +36,7 @@ You should have received a copy of the GNU General Public License along with thi \cf0 MacPass\kerning1\expnd0\expndtw3 \kerning1\expnd0\expndtw0 Icon by {\field{\*\fldinst{HYPERLINK "http://iiro.jappinen.me"}}{\fldrslt Iiro J\'e4ppinen}}\cf2 \ \ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720 {\field{\*\fldinst{HYPERLINK "https://github.com/robbiehanson/KissXML"}}{\fldrslt \cf2 KissXML}}\cf3 \ Copyright \'a9 2012 Robbie Hanson. All rights reserved.\ \ @@ -51,5 +52,10 @@ Copyright \'a9 2010 Qiang Yu. All rights reserved.\ Copyright \'a9 2011, Alex Rozanski. All rights reserved.\ \ \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720 -{\field{\*\fldinst{HYPERLINK "http://stackoverflow.com/questions/11386876/how-to-encode-and-decode-files-as-base64-in-cocoa-objective-c"}}{\fldrslt \cf3 Base64 Encoding Category}}\ -Copyright @2013, {\field{\*\fldinst{HYPERLINK "http://stackoverflow.com/users/200321/denis2342"}}{\fldrslt denis2342}}} \ No newline at end of file +{\field{\*\fldinst{HYPERLINK "http://stackoverflow.com/questions/11386876/how-to-encode-and-decode-files-as-base64-in-cocoa-objective-c"}}{\fldrslt \cf3 NSData+Base64}}\ +Copyright @2013, {\field{\*\fldinst{HYPERLINK "http://stackoverflow.com/users/200321/denis2342"}}{\fldrslt denis2342}}\ +\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720 +{\field{\*\fldinst{HYPERLINK "http://www.cocoadev.com/index.pl?NSDataCategory"}}{\fldrslt \cf3 NSData+Gzip}}\ +Extracted from code on the CocoaDev Wiki\ +} \ No newline at end of file diff --git a/MiniKeePassLib b/MiniKeePassLib index 7d7685ba..ee4352c9 160000 --- a/MiniKeePassLib +++ b/MiniKeePassLib @@ -1 +1 @@ -Subproject commit 7d7685ba38dd310e7cddada0600de8a0f60ca735 +Subproject commit ee4352c9c5ce98ac8c00feb21e0961316a711fc8