From b485234bc633c6d9a1fb25132ad14dba34a54c97 Mon Sep 17 00:00:00 2001 From: rowanbeentje Date: Tue, 14 Apr 2009 01:00:18 +0000 Subject: - Add a unique ID to each favourite, which is also used when interacting ith the keychain. This resolves the last part of Issue #186 and associated problems (ie multiple connections via a tunnel with only the port differing - now can store different passwords). - Duplicate function in prefs now also duplicates the password - Fix a few places which created a blank keychain entry when no password was present --- Source/SPPreferenceController.m | 83 +++++++++++++++++++++++++++++++++++------ Source/TableDocument.m | 26 +++++++------ 2 files changed, 86 insertions(+), 23 deletions(-) (limited to 'Source') diff --git a/Source/SPPreferenceController.m b/Source/SPPreferenceController.m index 79589119..3838badf 100644 --- a/Source/SPPreferenceController.m +++ b/Source/SPPreferenceController.m @@ -85,6 +85,9 @@ [self _updateDefaultFavoritePopup]; } +#pragma mark - +#pragma mark Preferences upgrade routine + // ------------------------------------------------------------------------------- // applyRevisionChanges // Checks the revision number, applies any preference upgrades, and updates to @@ -182,6 +185,34 @@ [prefs removeObjectForKey:@"version"]; } + // For versions prior to r567 (0.9.5), add a timestamp-based identifier to favorites and keychain entries + if (recordedVersionNumber < 567 && [prefs objectForKey:@"favorites"]) { + int i; + NSMutableArray *favoritesArray = [prefs objectForKey:@"favorites"]; + NSMutableDictionary *favorite; + NSString *password, *keychainName, *keychainAccount; + KeyChain *upgradeKeychain = [[KeyChain alloc] init]; + + // Cycle through the favorites, generating a timestamp-derived ID for each and renaming associated keychain items. + for (i = 0; i < [favoritesArray count]; i++) { + favorite = [favoritesArray objectAtIndex:i]; + [favorite setObject:[NSNumber numberWithInt:[[NSString stringWithFormat:@"%f", [[NSDate date] timeIntervalSince1970]] hash]] forKey:@"id"]; + keychainName = [NSString stringWithFormat:@"Sequel Pro : %@", [favorite objectForKey:@"name"]]; + keychainAccount = [NSString stringWithFormat:@"%@@%@/%@", + [favorite objectForKey:@"user"], [favorite objectForKey:@"host"], [favorite objectForKey:@"database"]]; + password = [upgradeKeychain getPasswordForName:keychainName account:keychainAccount]; + [upgradeKeychain deletePasswordForName:keychainName account:keychainAccount]; + if (password && [password length]) { + keychainName = [NSString stringWithFormat:@"Sequel Pro : %@ (%i)", [favorite objectForKey:@"name"], [[favorite objectForKey:@"id"] intValue]]; + [upgradeKeychain addPassword:password forName:keychainName account:keychainAccount]; + } + [favoritesArray replaceObjectAtIndex:i withObject:[NSDictionary dictionaryWithDictionary:favorite]]; + } + [prefs setObject:[NSArray arrayWithArray:favoritesArray] forKey:@"favorites"]; + [upgradeKeychain release]; + password = nil; + } + // Update the prefs revision [prefs setObject:[NSNumber numberWithInt:currentVersionNumber] forKey:@"LastUsedVersion"]; } @@ -195,9 +226,11 @@ // ------------------------------------------------------------------------------- - (IBAction)addFavorite:(id)sender { + NSNumber *favoriteid = [NSNumber numberWithInt:[[NSString stringWithFormat:@"%f", [[NSDate date] timeIntervalSince1970]] hash]]; + // Create default favorite - NSMutableDictionary *favorite = [NSMutableDictionary dictionaryWithObjects:[NSArray arrayWithObjects:@"New Favorite", @"", @"", @"", @"", @"", nil] - forKeys:[NSArray arrayWithObjects:@"name", @"host", @"socket", @"user", @"port", @"database", nil]]; + NSMutableDictionary *favorite = [NSMutableDictionary dictionaryWithObjects:[NSArray arrayWithObjects:@"New Favorite", @"", @"", @"", @"", @"", favoriteid, nil] + forKeys:[NSArray arrayWithObjects:@"name", @"host", @"socket", @"user", @"port", @"database", @"id", nil]]; [favoritesController addObject:favorite]; @@ -217,11 +250,12 @@ NSString *user = [favoritesController valueForKeyPath:@"selection.user"]; NSString *host = [favoritesController valueForKeyPath:@"selection.host"]; NSString *database = [favoritesController valueForKeyPath:@"selection.database"]; - + int favoriteid = [[favoritesController valueForKeyPath:@"selection.id"] intValue]; + // Remove passwords from the Keychain - [keychain deletePasswordForName:[NSString stringWithFormat:@"Sequel Pro : %@", name] + [keychain deletePasswordForName:[NSString stringWithFormat:@"Sequel Pro : %@ (%i)", name, favoriteid] account:[NSString stringWithFormat:@"%@@%@/%@", user, host, database]]; - [keychain deletePasswordForName:[NSString stringWithFormat:@"Sequel Pro SSHTunnel : %@", name] + [keychain deletePasswordForName:[NSString stringWithFormat:@"Sequel Pro SSHTunnel : %@ (%i)", name, favoriteid] account:[NSString stringWithFormat:@"%@@%@/%@", user, host, database]]; // Reset last used favorite @@ -247,13 +281,31 @@ - (IBAction)duplicateFavorite:(id)sender { if ([favoritesTableView numberOfSelectedRows] == 1) { + NSString *keychainName, *keychainAccount, *password; NSMutableDictionary *favorite = [NSMutableDictionary dictionaryWithDictionary:[[favoritesController arrangedObjects] objectAtIndex:[favoritesTableView selectedRow]]]; - - // Alter the name to ensure the keychain item isn't shared and therefore overwritten when changed + NSNumber *favoriteid = [NSNumber numberWithInt:[[NSString stringWithFormat:@"%f", [[NSDate date] timeIntervalSince1970]] hash]]; + + // Select the keychain password for duplication + keychainName = [NSString stringWithFormat:@"Sequel Pro : %@ (%i)", [favorite objectForKey:@"name"], [[favorite objectForKey:@"id"] intValue]]; + keychainAccount = [NSString stringWithFormat:@"%@@%@/%@", + [favorite objectForKey:@"user"], [favorite objectForKey:@"host"], [favorite objectForKey:@"database"]]; + password = [keychain getPasswordForName:keychainName account:keychainAccount]; + + // Update the unique ID + [favorite setObject:favoriteid forKey:@"id"]; + + // Alter the name for clarity [favorite setObject:[NSString stringWithFormat:@"%@ Copy", [favorite objectForKey:@"name"]] forKey:@"name"]; - [favoritesController addObject:favorite]; + // Create a new keychain item if appropriate + if (password && [password length]) { + keychainName = [NSString stringWithFormat:@"Sequel Pro : %@ (%i)", [favorite objectForKey:@"name"], [[favorite objectForKey:@"id"] intValue]]; + [keychain addPassword:password forName:keychainName account:keychainAccount]; + } + password = nil; + [favoritesController addObject:favorite]; + [favoritesTableView reloadData]; [self _updateDefaultFavoritePopup]; } @@ -477,7 +529,14 @@ [favoritesController setSelectionIndexes:[favoritesTableView selectedRowIndexes]]; } - NSString *keychainName = [NSString stringWithFormat:@"Sequel Pro : %@", [favoritesController valueForKeyPath:@"selection.name"]]; + // If no selection is present, blank the field. + if ([[favoritesTableView selectedRowIndexes] count] == 0) { + [passwordField setStringValue:@""]; + return; + } + + // Otherwise retrieve and set the password. + NSString *keychainName = [NSString stringWithFormat:@"Sequel Pro : %@ (%i)", [favoritesController valueForKeyPath:@"selection.name"], [[favoritesController valueForKeyPath:@"selection.id"] intValue]]; NSString *keychainAccount = [NSString stringWithFormat:@"%@@%@/%@", [favoritesController valueForKeyPath:@"selection.user"], [favoritesController valueForKeyPath:@"selection.host"], @@ -570,7 +629,7 @@ return YES; // Set the current keychain name and account strings - oldKeychainName = [NSString stringWithFormat:@"Sequel Pro : %@", [favoritesController valueForKeyPath:@"selection.name"]]; + oldKeychainName = [NSString stringWithFormat:@"Sequel Pro : %@ (%i)", [favoritesController valueForKeyPath:@"selection.name"], [[favoritesController valueForKeyPath:@"selection.id"] intValue]]; oldKeychainAccount = [NSString stringWithFormat:@"%@@%@/%@", [favoritesController valueForKeyPath:@"selection.user"], [favoritesController valueForKeyPath:@"selection.host"], @@ -591,7 +650,7 @@ oldPassword = nil; // Set up the new keychain name and account strings - newKeychainName = [NSString stringWithFormat:@"Sequel Pro : %@", [nameField stringValue]]; + newKeychainName = [NSString stringWithFormat:@"Sequel Pro : %@ (%i)", [nameField stringValue], [[favoritesController valueForKeyPath:@"selection.id"] intValue]]; newKeychainAccount = [NSString stringWithFormat:@"%@@%@/%@", [userField stringValue], [hostField stringValue], @@ -601,7 +660,7 @@ [keychain deletePasswordForName:oldKeychainName account:oldKeychainAccount]; // Add the new keychain item if the password field has a value - if ([passwordField stringValue]) + if ([[passwordField stringValue] length]) [keychain addPassword:[passwordField stringValue] forName:newKeychainName account:newKeychainAccount]; // Proceed with editing diff --git a/Source/TableDocument.m b/Source/TableDocument.m index 49962fcc..1d8ac450 100644 --- a/Source/TableDocument.m +++ b/Source/TableDocument.m @@ -428,10 +428,11 @@ NSString *TableDocumentFavoritesControllerFavoritesDidChange = @"TableDocum NSString *user = [self valueForKeyPath:@"selectedFavorite.user"]; NSString *host = [self valueForKeyPath:@"selectedFavorite.host"]; NSString *database = [self valueForKeyPath:@"selectedFavorite.database"]; + int favoriteid = [[self valueForKeyPath:@"selectedFavorite.id"] intValue]; - [keyChainInstance deletePasswordForName:[NSString stringWithFormat:@"Sequel Pro : %@", name] + [keyChainInstance deletePasswordForName:[NSString stringWithFormat:@"Sequel Pro : %@ (%i)", name, favoriteid] account:[NSString stringWithFormat:@"%@@%@/%@", user, host, database]]; - [keyChainInstance deletePasswordForName:[NSString stringWithFormat:@"Sequel Pro SSHTunnel : %@", name] + [keyChainInstance deletePasswordForName:[NSString stringWithFormat:@"Sequel Pro SSHTunnel : %@ (%i)", name, favoriteid] account:[NSString stringWithFormat:@"%@@%@/%@", user, host, database]]; // Remove from favorites array controller @@ -478,7 +479,7 @@ NSString *TableDocumentFavoritesControllerFavoritesDidChange = @"TableDocum if (![self selectedFavorite]) return nil; - NSString *keychainName = [NSString stringWithFormat:@"Sequel Pro : %@", [self valueForKeyPath:@"selectedFavorite.name"]]; + NSString *keychainName = [NSString stringWithFormat:@"Sequel Pro : %@ (%i)", [self valueForKeyPath:@"selectedFavorite.name"], [[self valueForKeyPath:@"selectedFavorite.id"] intValue]]; NSString *keychainAccount = [NSString stringWithFormat:@"%@@%@/%@", [self valueForKeyPath:@"selectedFavorite.user"], [self valueForKeyPath:@"selectedFavorite.host"], @@ -505,6 +506,7 @@ NSString *TableDocumentFavoritesControllerFavoritesDidChange = @"TableDocum sshPort:(NSString *)sshPort // no-longer in use { NSString *favoriteName = [NSString stringWithFormat:@"%@@%@", user, host]; + NSNumber *favoriteid = [NSNumber numberWithInt:[[NSString stringWithFormat:@"%f", [[NSDate date] timeIntervalSince1970]] hash]]; if (![database isEqualToString:@""]) favoriteName = [NSString stringWithFormat:@"%@ %@", database, favoriteName]; @@ -517,13 +519,13 @@ NSString *TableDocumentFavoritesControllerFavoritesDidChange = @"TableDocum [self willChangeValueForKey:@"favorites"]; // write favorites and password - NSMutableDictionary *newFavorite = [NSMutableDictionary dictionaryWithObjects:[NSArray arrayWithObjects:favoriteName, host, socket, user, port, database, nil] - forKeys:[NSArray arrayWithObjects:@"name", @"host", @"socket", @"user", @"port", @"database", nil]]; + NSMutableDictionary *newFavorite = [NSMutableDictionary dictionaryWithObjects:[NSArray arrayWithObjects:favoriteName, host, socket, user, port, database, favoriteid, nil] + forKeys:[NSArray arrayWithObjects:@"name", @"host", @"socket", @"user", @"port", @"database", @"id", nil]]; [favorites addObject:newFavorite]; if (![password isEqualToString:@""]) { [keyChainInstance addPassword:password - forName:[NSString stringWithFormat:@"Sequel Pro : %@", favoriteName] + forName:[NSString stringWithFormat:@"Sequel Pro : %@ (%i)", favoriteName, [favoriteid intValue]] account:[NSString stringWithFormat:@"%@@%@/%@", user, host, database]]; } @@ -1998,13 +2000,15 @@ NSString *TableDocumentFavoritesControllerFavoritesDidChange = @"TableDocum { NSDictionary *favorite = [favorites objectAtIndex:rowIndex]; - [keyChainInstance deletePasswordForName:[NSString stringWithFormat:@"Sequel Pro : %@", favoriteNameBeingChanged] + [keyChainInstance deletePasswordForName:[NSString stringWithFormat:@"Sequel Pro : %@ (%i)", favoriteNameBeingChanged, [[favorite objectForKey:@"id"] intValue]] account:[NSString stringWithFormat:@"%@@%@/%@", [favorite objectForKey:@"user"], [favorite objectForKey:@"host"], [favorite objectForKey:@"database"]]]; - [keyChainInstance addPassword:[passwordField stringValue] - forName:[NSString stringWithFormat:@"Sequel Pro : %@", object] - account:[NSString stringWithFormat:@"%@@%@/%@", [favorite objectForKey:@"user"], [favorite objectForKey:@"host"], [favorite objectForKey:@"database"]]]; - + if ([[passwordField stringValue] length]) { + [keyChainInstance addPassword:[passwordField stringValue] + forName:[NSString stringWithFormat:@"Sequel Pro : %@ (%i)", object, [[favorite objectForKey:@"id"] intValue]] + account:[NSString stringWithFormat:@"%@@%@/%@", [favorite objectForKey:@"user"], [favorite objectForKey:@"host"], [favorite objectForKey:@"database"]]]; + } + favoriteNameBeingChanged = nil; } -- cgit v1.2.3