diff options
author | rowanbeentje <rowan@beent.je> | 2009-07-06 21:01:52 +0000 |
---|---|---|
committer | rowanbeentje <rowan@beent.je> | 2009-07-06 21:01:52 +0000 |
commit | 86b104a1da6857792c1feb7dcec0d3d654fdac5f (patch) | |
tree | 112acee41b8870a1197f6cf5591ae9f4fa6c2343 /Source | |
parent | ba53d971b598247500e93a665b4cdb0526a36a50 (diff) | |
download | sequelpro-86b104a1da6857792c1feb7dcec0d3d654fdac5f.tar.gz sequelpro-86b104a1da6857792c1feb7dcec0d3d654fdac5f.tar.bz2 sequelpro-86b104a1da6857792c1feb7dcec0d3d654fdac5f.zip |
- Improve handling of the new favorites interface in preferences, simplifying the code and fixing one or two edge cases that caused disassociation (desynch) of keychain passwords from the favorite
Diffstat (limited to 'Source')
-rw-r--r-- | Source/SPPreferenceController.h | 14 | ||||
-rw-r--r-- | Source/SPPreferenceController.m | 198 |
2 files changed, 97 insertions, 115 deletions
diff --git a/Source/SPPreferenceController.h b/Source/SPPreferenceController.h index 221508a2..f5035787 100644 --- a/Source/SPPreferenceController.h +++ b/Source/SPPreferenceController.h @@ -45,22 +45,13 @@ IBOutlet NSArrayController *favoritesController; IBOutlet NSTabView *favoritesTabView; - IBOutlet NSTextField *nameField; - IBOutlet NSTextField *standardSQLHostField; - IBOutlet NSTextField *standardUserField; IBOutlet NSSecureTextField *standardPasswordField; - IBOutlet NSTextField *standardDatabaseField; - IBOutlet NSTextField *socketUserField; IBOutlet NSSecureTextField *socketPasswordField; - IBOutlet NSTextField *socketDatabaseField; - IBOutlet NSTextField *sshSQLHostField; - IBOutlet NSTextField *sshSQLUserField; IBOutlet NSSecureTextField *sshSQLPasswordField; - IBOutlet NSTextField *sshDatabaseField; - IBOutlet NSTextField *sshHostField; - IBOutlet NSTextField *sshUserField; IBOutlet NSSecureTextField *sshPasswordField; + KeyChain *keychain; + NSDictionary *currentFavorite; IBOutlet NSTextField *editorFontName; @@ -104,5 +95,6 @@ - (void)selectFavoriteAtIndex:(unsigned int)theIndex; - (void)changeFont:(id)sender; - (IBAction)favoriteTypeDidChange:(id)sender; +- (void)updateFavoritePasswordsFromField:(NSControl *)passwordControl; @end diff --git a/Source/SPPreferenceController.m b/Source/SPPreferenceController.m index 9550e897..78d16a20 100644 --- a/Source/SPPreferenceController.m +++ b/Source/SPPreferenceController.m @@ -61,6 +61,7 @@ if (self = [super initWithWindowNibName:@"Preferences"]) { prefs = [NSUserDefaults standardUserDefaults]; [self applyRevisionChanges]; + currentFavorite = nil; } return self; @@ -597,7 +598,7 @@ [favoritesController setSelectionIndexes:[favoritesTableView selectedRowIndexes]]; } - // If no selection is present, blank the field. + // If no selection is present, blank the password fields (which can't use bindings) if ([[favoritesTableView selectedRowIndexes] count] == 0) { [standardPasswordField setStringValue:@""]; [socketPasswordField setStringValue:@""]; @@ -605,18 +606,22 @@ [sshPasswordField setStringValue:@""]; return; } + + // Keep a copy of the favorite as it currently stands + if (currentFavorite) [currentFavorite release]; + currentFavorite = [[[favoritesController selectedObjects] objectAtIndex:0] copy]; - // Otherwise retrieve and set the password. - NSString *keychainName = [keychain nameForFavoriteName:[favoritesController valueForKeyPath:@"selection.name"] id:[favoritesController valueForKeyPath:@"selection.id"]]; - NSString *keychainAccount = [keychain accountForUser:[favoritesController valueForKeyPath:@"selection.user"] host:[favoritesController valueForKeyPath:@"selection.host"] database:[favoritesController valueForKeyPath:@"selection.database"]]; + // Retrieve and set the password. + NSString *keychainName = [keychain nameForFavoriteName:[currentFavorite objectForKey:@"name"] id:[currentFavorite objectForKey:@"id"]]; + NSString *keychainAccount = [keychain accountForUser:[currentFavorite objectForKey:@"user"] host:[currentFavorite objectForKey:@"host"] database:[currentFavorite objectForKey:@"database"]]; NSString *passwordValue = [keychain getPasswordForName:keychainName account:keychainAccount]; [standardPasswordField setStringValue:passwordValue]; [socketPasswordField setStringValue:passwordValue]; [sshSQLPasswordField setStringValue:passwordValue]; // Retrieve the SSH keychain password if appropriate. - NSString *keychainSSHName = [keychain nameForSSHForFavoriteName:[favoritesController valueForKeyPath:@"selection.name"] id:[favoritesController valueForKeyPath:@"selection.id"]]; - NSString *keychainSSHAccount = [keychain accountForSSHUser:[favoritesController valueForKeyPath:@"selection.sshUser"] sshHost:[favoritesController valueForKeyPath:@"selection.sshHost"]]; + NSString *keychainSSHName = [keychain nameForSSHForFavoriteName:[currentFavorite objectForKey:@"name"] id:[currentFavorite objectForKey:@"id"]]; + NSString *keychainSSHAccount = [keychain accountForSSHUser:[currentFavorite objectForKey:@"sshUser"] sshHost:[currentFavorite objectForKey:@"sshHost"]]; [sshPasswordField setStringValue:[keychain getPasswordForName:keychainSSHName account:keychainSSHAccount]]; } @@ -709,130 +714,112 @@ // ------------------------------------------------------------------------------- - (BOOL)control:(NSControl *)control textShouldEndEditing:(NSText *)fieldEditor { - NSString *nameValue, *hostValue, *userValue, *databaseValue, *passwordValue; + + // Request a password refresh to keep keychain references in synch with favorites + [self updateFavoritePasswordsFromField:control]; + + // Proceed with editing + return YES; +} + +// ------------------------------------------------------------------------------- +// favoriteTypeDidChange: +// Update the favorite host when the type changes. +// ------------------------------------------------------------------------------- +- (IBAction)favoriteTypeDidChange:(id)sender +{ + if ([sender indexOfSelectedItem] == 1) { // Socket + [favoritesController setValue:@"localhost" forKeyPath:@"selection.host"]; + } else if ([[favoritesController valueForKeyPath:@"selection.host"] isEqualToString:@"localhost"]) { + [favoritesController setValue:@"" forKeyPath:@"selection.host"]; + } + + // Request a password refresh to keep keychain references in synch with the favorites + [self updateFavoritePasswordsFromField:nil]; +} + +// ------------------------------------------------------------------------------- +// updateFavoritePasswordsFromField: +// Check all fields used in the keychain names against the old values for that +// favorite, and update the keychain names to match if necessary. +// If an (optional) recognised password field is supplied, that field is assumed +// to have changed and is used to supply the new value. +// ------------------------------------------------------------------------------- +- (void)updateFavoritePasswordsFromField:(NSControl *)passwordControl +{ + if (!currentFavorite) return; + + NSString *passwordValue; NSString *oldKeychainName, *newKeychainName; NSString *oldKeychainAccount, *newKeychainAccount; - // Only proceed for name, host, user or database changes, for standard, socket or SSH - if (control != nameField && control != standardSQLHostField && control != standardUserField - && control != standardPasswordField && control != standardDatabaseField - && control != socketUserField && control != socketPasswordField - && control != socketDatabaseField && control != sshSQLHostField - && control != sshSQLUserField && control != sshSQLPasswordField - && control != sshDatabaseField && control != sshHostField - && control != sshUserField && control != sshPasswordField) - return YES; - - // Determine the appropriate name, host, user and database details - nameValue = [nameField stringValue]; - switch ([[favoritesController valueForKeyPath:@"selection.type"] intValue]) { - case 0: // Standard - hostValue = [standardSQLHostField stringValue]; - userValue = [standardUserField stringValue]; - databaseValue = [standardDatabaseField stringValue]; - passwordValue = [standardPasswordField stringValue]; - break; + // SQL passwords are indexed by name, host, user and database. If any of these + // have changed, or a standard password field has, alter the keychain item to match. + if (![[currentFavorite objectForKey:@"name"] isEqualToString:[favoritesController valueForKeyPath:@"selection.name"]] + || ![[currentFavorite objectForKey:@"host"] isEqualToString:[favoritesController valueForKeyPath:@"selection.host"]] + || ![[currentFavorite objectForKey:@"user"] isEqualToString:[favoritesController valueForKeyPath:@"selection.user"]] + || ![[currentFavorite objectForKey:@"database"] isEqualToString:[favoritesController valueForKeyPath:@"selection.database"]] + || passwordControl == standardPasswordField || passwordControl == socketPasswordField || passwordControl == sshSQLPasswordField) + { - case 1: // Socket - hostValue = @"localhost"; - userValue = [socketUserField stringValue]; - databaseValue = [socketDatabaseField stringValue]; + // Determine the correct password field to read the password from, defaulting to standard + if (passwordControl == socketPasswordField) { passwordValue = [socketPasswordField stringValue]; - break; - - case 2: // SSH - hostValue = [sshSQLHostField stringValue]; - userValue = [sshSQLUserField stringValue]; - databaseValue = [sshDatabaseField stringValue]; + } else if (passwordControl == sshSQLPasswordField) { passwordValue = [sshSQLPasswordField stringValue]; - break; - } - - // If account/password details have changed, update the keychain to match - if (![nameValue isEqualToString:[favoritesController valueForKeyPath:@"selection.name"]] - || ![hostValue isEqualToString:[favoritesController valueForKeyPath:@"selection.host"]] - || ![userValue isEqualToString:[favoritesController valueForKeyPath:@"selection.user"]] - || ![databaseValue isEqualToString:[favoritesController valueForKeyPath:@"selection.database"]] - || control == standardPasswordField || control == socketPasswordField || control == sshSQLPasswordField) { - - // Get the current keychain name and account strings - oldKeychainName = [keychain nameForFavoriteName:[favoritesController valueForKeyPath:@"selection.name"] id:[favoritesController valueForKeyPath:@"selection.id"]]; - oldKeychainAccount = [keychain accountForUser:[favoritesController valueForKeyPath:@"selection.user"] host:[favoritesController valueForKeyPath:@"selection.host"] database:[favoritesController valueForKeyPath:@"selection.database"]]; + } else { + passwordValue = [standardPasswordField stringValue]; + } - // Set up the new keychain name and account strings - newKeychainName = [keychain nameForFavoriteName:nameValue id:[favoritesController valueForKeyPath:@"selection.id"]]; - newKeychainAccount = [keychain accountForUser:userValue host:hostValue database:databaseValue]; + // Get the old keychain name and account strings + oldKeychainName = [keychain nameForFavoriteName:[currentFavorite objectForKey:@"name"] id:[favoritesController valueForKeyPath:@"selection.id"]]; + oldKeychainAccount = [keychain accountForUser:[currentFavorite objectForKey:@"user"] host:[currentFavorite objectForKey:@"host"] database:[currentFavorite objectForKey:@"database"]]; // Delete the old keychain item [keychain deletePasswordForName:oldKeychainName account:oldKeychainAccount]; + // Set up the new keychain name and account strings + newKeychainName = [keychain nameForFavoriteName:[favoritesController valueForKeyPath:@"selection.name"] id:[favoritesController valueForKeyPath:@"selection.id"]]; + newKeychainAccount = [keychain accountForUser:[favoritesController valueForKeyPath:@"selection.user"] host:[favoritesController valueForKeyPath:@"selection.host"] database:[favoritesController valueForKeyPath:@"selection.database"]]; + // Add the new keychain item if the password field has a value if ([passwordValue length]) [keychain addPassword:passwordValue forName:newKeychainName account:newKeychainAccount]; + + // Synch password changes + [standardPasswordField setStringValue:passwordValue]; + [socketPasswordField setStringValue:passwordValue]; + [sshSQLPasswordField setStringValue:passwordValue]; + + passwordValue = @""; } - - // Synch password changes - [standardPasswordField setStringValue:passwordValue]; - [socketPasswordField setStringValue:passwordValue]; - [sshSQLPasswordField setStringValue:passwordValue]; // If SSH account/password details have changed, update the keychain to match - if (![[nameField stringValue] isEqualToString:[favoritesController valueForKeyPath:@"selection.name"]] - || ![[sshHostField stringValue] isEqualToString:[favoritesController valueForKeyPath:@"selection.sshHost"]] - || ![[sshUserField stringValue] isEqualToString:[favoritesController valueForKeyPath:@"selection.sshUser"]] - || control == sshPasswordField) { - - // Get the current keychain name and account strings - oldKeychainName = [keychain nameForSSHForFavoriteName:[favoritesController valueForKeyPath:@"selection.name"] id:[favoritesController valueForKeyPath:@"selection.id"]]; - oldKeychainAccount = [keychain accountForSSHUser:[favoritesController valueForKeyPath:@"selection.sshUser"] sshHost:[favoritesController valueForKeyPath:@"selection.sshHost"]]; + if (![[currentFavorite objectForKey:@"name"] isEqualToString:[favoritesController valueForKeyPath:@"selection.name"]] + || ![[currentFavorite objectForKey:@"sshHost"] isEqualToString:[favoritesController valueForKeyPath:@"selection.sshHost"]] + || ![[currentFavorite objectForKey:@"sshUser"] isEqualToString:[favoritesController valueForKeyPath:@"selection.sshUser"]] + || passwordControl == sshPasswordField) { - // Set up the new keychain name and account strings - newKeychainName = [keychain nameForSSHForFavoriteName:nameValue id:[favoritesController valueForKeyPath:@"selection.id"]]; - newKeychainAccount = [keychain accountForSSHUser:[sshUserField stringValue] sshHost:[sshHostField stringValue]]; + // Get the old keychain name and account strings + oldKeychainName = [keychain nameForSSHForFavoriteName:[currentFavorite objectForKey:@"name"] id:[favoritesController valueForKeyPath:@"selection.id"]]; + oldKeychainAccount = [keychain accountForSSHUser:[currentFavorite objectForKey:@"sshUser"] sshHost:[currentFavorite objectForKey:@"sshHost"]]; // Delete the old keychain item [keychain deletePasswordForName:oldKeychainName account:oldKeychainAccount]; + // Set up the new keychain name and account strings + newKeychainName = [keychain nameForSSHForFavoriteName:[favoritesController valueForKeyPath:@"selection.name"] id:[favoritesController valueForKeyPath:@"selection.id"]]; + newKeychainAccount = [keychain accountForSSHUser:[favoritesController valueForKeyPath:@"selection.sshUser"] sshHost:[favoritesController valueForKeyPath:@"selection.sshHost"]]; + // Add the new keychain item if the password field has a value if ([[sshPasswordField stringValue] length]) [keychain addPassword:[sshPasswordField stringValue] forName:newKeychainName account:newKeychainAccount]; } - // Proceed with editing - return YES; -} - -// ------------------------------------------------------------------------------- -// favoriteTypeDidChange: -// Update the favorite host when the type changes. -// ------------------------------------------------------------------------------- -- (IBAction)favoriteTypeDidChange:(id)sender -{ - NSString *oldKeychainName, *newKeychainName; - NSString *oldKeychainAccount, *newKeychainAccount; - - // Get the current keychain name and account strings - oldKeychainName = [keychain nameForFavoriteName:[favoritesController valueForKeyPath:@"selection.name"] id:[favoritesController valueForKeyPath:@"selection.id"]]; - oldKeychainAccount = [keychain accountForUser:[favoritesController valueForKeyPath:@"selection.user"] host:[favoritesController valueForKeyPath:@"selection.host"] database:[favoritesController valueForKeyPath:@"selection.database"]]; - - // Delete the old keychain item - [keychain deletePasswordForName:oldKeychainName account:oldKeychainAccount]; - - if ([sender indexOfSelectedItem] == 1) { // Socket - [favoritesController setValue:@"localhost" forKeyPath:@"selection.host"]; - [self control:socketPasswordField textShouldEndEditing:nil]; - } else if ([[favoritesController valueForKeyPath:@"selection.host"] isEqualToString:@"localhost"]) { - [favoritesController setValue:@"" forKeyPath:@"selection.host"]; - [self control:standardPasswordField textShouldEndEditing:nil]; - } - - // Set up the new keychain name and account strings - newKeychainName = [keychain nameForFavoriteName:[favoritesController valueForKeyPath:@"selection.name"] id:[favoritesController valueForKeyPath:@"selection.id"]]; - newKeychainAccount = [keychain accountForUser:[favoritesController valueForKeyPath:@"selection.user"] host:[favoritesController valueForKeyPath:@"selection.host"] database:[favoritesController valueForKeyPath:@"selection.database"]]; - - // Add the new keychain item if the password field has a value - if ([[standardPasswordField stringValue] length]) - [keychain addPassword:[standardPasswordField stringValue] forName:newKeychainName account:newKeychainAccount]; + // Update the current favorite + if (currentFavorite) [currentFavorite release], currentFavorite = nil; + if ([[favoritesTableView selectedRowIndexes] count] > 0) + currentFavorite = [[[favoritesController selectedObjects] objectAtIndex:0] copy]; } #pragma mark - @@ -913,6 +900,7 @@ - (void)selectFavorites:(NSArray *)favorites { [favoritesController setSelectedObjects:favorites]; + [favoritesTableView scrollRowToVisible:[favoritesController selectionIndex]]; } // ------------------------------------------------------------------------------- @@ -923,6 +911,7 @@ - (void)selectFavoriteAtIndex:(unsigned int)theIndex { [favoritesController setSelectionIndex:theIndex]; + [favoritesTableView scrollRowToVisible:theIndex]; } // ------------------------------------------------------------------------------- @@ -970,7 +959,8 @@ - (void)dealloc { [keychain release], keychain = nil; - + if (currentFavorite) [currentFavorite release]; + [super dealloc]; } |