aboutsummaryrefslogtreecommitdiffstats
path: root/Source/TableDocument.m
diff options
context:
space:
mode:
authorrowanbeentje <rowan@beent.je>2009-06-04 01:44:16 +0000
committerrowanbeentje <rowan@beent.je>2009-06-04 01:44:16 +0000
commit31123c9ff149908120a5bca94e76f5023c0b7e1e (patch)
treef76933e4c19d63cd17f160919731fbb5c9162b75 /Source/TableDocument.m
parentfc748400d92a0b7874a19eba3fa573cdf1415ee5 (diff)
downloadsequelpro-31123c9ff149908120a5bca94e76f5023c0b7e1e.tar.gz
sequelpro-31123c9ff149908120a5bca94e76f5023c0b7e1e.tar.bz2
sequelpro-31123c9ff149908120a5bca94e76f5023c0b7e1e.zip
Further SSH tunnel improvements, password handling improvements, and minor bugfixes:
- SSH tunnels can now correctly show dialogs for ssh queries, eg host key mismatches - SSH tunnels are now correctly closed by the document for connection failures - Keychain password item name and account generation has been moved to within the keychain class, to centralise generation for consistency - Keychain item names and accounts now correctly deal with nil values, allowing more keychain items to be read - "Add to favorites" button and menu item now correctly store passwords and SSH tunnel settings - Duplicating favorites in preferences now selects the newly created favorite instead of deselecting everything - Fixes an occasional crasher sometimes encountered in keychain usage
Diffstat (limited to 'Source/TableDocument.m')
-rw-r--r--Source/TableDocument.m118
1 files changed, 73 insertions, 45 deletions
diff --git a/Source/TableDocument.m b/Source/TableDocument.m
index 5ed89519..d0b04d5e 100644
--- a/Source/TableDocument.m
+++ b/Source/TableDocument.m
@@ -73,6 +73,7 @@ NSString *TableDocumentFavoritesControllerSelectionIndexDidChange = @"TableDocum
connectionSSHKeychainItemName = nil;
connectionSSHKeychainItemAccount = nil;
selectedDatabase = nil;
+ sshTunnel = nil;
printWebView = [[WebView alloc] init];
[printWebView setFrameLoadDelegate:self];
@@ -277,8 +278,8 @@ NSString *TableDocumentFavoritesControllerSelectionIndexDidChange = @"TableDocum
[self failConnectionWithErrorMessage:NSLocalizedString(@"Insufficient details provided to establish a connection. Please provide at least a host or socket.", @"insufficient details informative message")];
return;
}
- if ([sshCheckbox state] == NSOnState && (![[sshHostField stringValue] length] || ![[sshUserField stringValue] length])) {
- [self failConnectionWithErrorMessage:NSLocalizedString(@"Please enter the hostname and username for the SSH Tunnel, or disable the SSH Tunnel.", @"message of panel when ssh details are incomplete")];
+ if ([sshCheckbox state] == NSOnState && ![[sshHostField stringValue] length]) {
+ [self failConnectionWithErrorMessage:NSLocalizedString(@"Please enter the hostname for the SSH Tunnel, or disable the SSH Tunnel.", @"message of panel when ssh details are incomplete")];
return;
}
@@ -292,7 +293,7 @@ NSString *TableDocumentFavoritesControllerSelectionIndexDidChange = @"TableDocum
// for increased security.
if (connectionKeychainItemName) {
if ([[keyChainInstance getPasswordForName:connectionKeychainItemName account:connectionKeychainItemAccount] isEqualToString:[passwordField stringValue]]) {
- [passwordField setStringValue:@""];
+ [passwordField setStringValue:[[NSString string] stringByPaddingToLength:[[passwordField stringValue] length] withString:@"sp" startingAtIndex:0]];
[[self undoManager] removeAllActionsWithTarget:passwordField];
} else {
[connectionKeychainItemName release], connectionKeychainItemName = nil;
@@ -301,7 +302,7 @@ NSString *TableDocumentFavoritesControllerSelectionIndexDidChange = @"TableDocum
}
if (connectionSSHKeychainItemName) {
if ([[keyChainInstance getPasswordForName:connectionSSHKeychainItemName account:connectionSSHKeychainItemAccount] isEqualToString:[sshPasswordField stringValue]]) {
- [sshPasswordField setStringValue:@""];
+ [sshPasswordField setStringValue:[[NSString string] stringByPaddingToLength:[[sshPasswordField stringValue] length] withString:@"sp" startingAtIndex:0]];
[[self undoManager] removeAllActionsWithTarget:sshPasswordField];
} else {
[connectionSSHKeychainItemName release], connectionSSHKeychainItemName = nil;
@@ -316,7 +317,7 @@ NSString *TableDocumentFavoritesControllerSelectionIndexDidChange = @"TableDocum
}
// ...or start the MySQL connection process directly
- [self initiateMySQLConnection:nil];
+ [self initiateMySQLConnection];
}
/*
@@ -326,26 +327,26 @@ NSString *TableDocumentFavoritesControllerSelectionIndexDidChange = @"TableDocum
*/
- (void)initiateSSHTunnelConnection
{
- SPSSHTunnel *theTunnel;
[connectProgressStatusText setStringValue:NSLocalizedString(@"SSH connecting...", @"SSH connecting very short status message")];
[connectProgressStatusText display];
// Set up the tunnel details
- theTunnel = [[SPSSHTunnel alloc] initToHost:[sshHostField stringValue] port:([[sshPortField stringValue] length]?[sshPortField intValue]:22) login:[sshUserField stringValue] tunnellingToPort:([[portField stringValue] length]?[portField intValue]:3306) onHost:[hostField stringValue]];
+ sshTunnel = [[SPSSHTunnel alloc] initToHost:[sshHostField stringValue] port:([[sshPortField stringValue] length]?[sshPortField intValue]:22) login:[sshUserField stringValue] tunnellingToPort:([[portField stringValue] length]?[portField intValue]:3306) onHost:[hostField stringValue]];
+ [sshTunnel setParentWindow:tableWindow];
// Add keychain or plaintext password as appropriate - note the checks in initiateConnection.
if (connectionSSHKeychainItemName) {
- [theTunnel setPasswordKeychainName:connectionSSHKeychainItemName account:connectionSSHKeychainItemAccount];
+ [sshTunnel setPasswordKeychainName:connectionSSHKeychainItemName account:connectionSSHKeychainItemAccount];
} else {
- [theTunnel setPassword:[sshPasswordField stringValue]];
+ [sshTunnel setPassword:[sshPasswordField stringValue]];
}
// Set the callback function on the tunnel
- [theTunnel setConnectionStateChangeSelector:@selector(sshTunnelCallback:) delegate:self];
+ [sshTunnel setConnectionStateChangeSelector:@selector(sshTunnelCallback:) delegate:self];
// Ask the tunnel to connect. This will call the callback below on success or failure, passing
// itself as an argument - retain count should be one at this point.
- [theTunnel connect];
+ [sshTunnel connect];
}
/*
@@ -360,19 +361,19 @@ NSString *TableDocumentFavoritesControllerSelectionIndexDidChange = @"TableDocum
if (newState == SPSSH_STATE_IDLE) {
[self failConnectionWithErrorMessage:[theTunnel lastError]];
} else if (newState == SPSSH_STATE_CONNECTED) {
- [self initiateMySQLConnection:theTunnel];
+ [self initiateMySQLConnection];
}
}
/*
* Set up the MySQL connection, either through a successful tunnel or directly.
*/
-- (void)initiateMySQLConnection:(SPSSHTunnel *)theTunnel
+- (void)initiateMySQLConnection
{
CMMCPResult *theResult;
id version;
- if (theTunnel)
+ if (sshTunnel)
[connectProgressStatusText setStringValue:NSLocalizedString(@"MySQL connecting...", @"MySQL connecting very short status message")];
else
[connectProgressStatusText setStringValue:NSLocalizedString(@"Connecting...", @"Generic connecting very short status message")];
@@ -388,12 +389,12 @@ NSString *TableDocumentFavoritesControllerSelectionIndexDidChange = @"TableDocum
// Otherwise, initialise to host, using tunnel if appropriate
} else {
- if (theTunnel) {
+ if (sshTunnel) {
mySQLConnection = [[CMMCPConnection alloc] initToHost:@"127.0.0.1"
withLogin:[userField stringValue]
- usingPort:[theTunnel localPort]];
- [mySQLConnection setSSHTunnel:theTunnel];
- [theTunnel release];
+ usingPort:[sshTunnel localPort]];
+ [mySQLConnection setSSHTunnel:sshTunnel];
+ [sshTunnel release], sshTunnel = nil;
} else {
mySQLConnection = [[CMMCPConnection alloc] initToHost:[hostField stringValue]
withLogin:[userField stringValue]
@@ -414,7 +415,6 @@ NSString *TableDocumentFavoritesControllerSelectionIndexDidChange = @"TableDocum
if (![mySQLConnection isConnected]) {
[self failConnectionWithErrorMessage:[NSString stringWithFormat:NSLocalizedString(@"Unable to connect to host %@, or the request timed out.\n\nBe sure that the address is correct and that you have the necessary privileges, or try increasing the connection timeout (currently %i seconds).\n\nMySQL said: %@", @"message of panel when connection to host failed"), [hostField stringValue], [[prefs objectForKey:@"ConnectionTimeoutValue"] intValue], [mySQLConnection getLastErrorMessage]]];
- if (theTunnel) [theTunnel disconnect];
return;
}
if (![[databaseField stringValue] isEqualToString:@""]) {
@@ -423,7 +423,6 @@ NSString *TableDocumentFavoritesControllerSelectionIndexDidChange = @"TableDocum
selectedDatabase = [[databaseField stringValue] retain];
} else {
[self failConnectionWithErrorMessage:[NSString stringWithFormat:NSLocalizedString(@"Connected to host, but unable to connect to database %@.\n\nBe sure that the database exists and that you have the necessary privileges.\n\nMySQL said: %@", @"message of panel when connection to db failed"), [databaseField stringValue], [mySQLConnection getLastErrorMessage]]];
- if (theTunnel) [theTunnel disconnect];
return;
}
}
@@ -500,6 +499,9 @@ NSString *TableDocumentFavoritesControllerSelectionIndexDidChange = @"TableDocum
// Stop the modal sheet
[connectSheet orderOut:nil];
[NSApp endSheet:connectSheet];
+
+ // Release as appropriate
+ if (sshTunnel) [sshTunnel disconnect], [sshTunnel release], sshTunnel = nil;
// Display the connection error message
NSBeginAlertSheet(NSLocalizedString(@"Connection failed!", @"connection failed title"), NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, @selector(sheetDidEnd:returnCode:contextInfo:), @"connect", theErrorMessage);
@@ -548,11 +550,8 @@ NSString *TableDocumentFavoritesControllerSelectionIndexDidChange = @"TableDocum
// Check whether the password exists in the keychain, and if so add it; also record the
// keychain details so we can pass around only those details if the password doesn't change
- connectionKeychainItemName = [[NSString stringWithFormat:@"Sequel Pro : %@ (%i)", [self valueForKeyPath:@"selectedFavorite.name"], [[self valueForKeyPath:@"selectedFavorite.id"] intValue]] retain];
- connectionKeychainItemAccount = [[NSString stringWithFormat:@"%@@%@/%@",
- [self valueForKeyPath:@"selectedFavorite.user"],
- [self valueForKeyPath:@"selectedFavorite.host"],
- [self valueForKeyPath:@"selectedFavorite.database"]] retain];
+ connectionKeychainItemName = [[keyChainInstance nameForFavoriteName:[self valueForKeyPath:@"selectedFavorite.name"] id:[self valueForKeyPath:@"selectedFavorite.id"]] retain];
+ connectionKeychainItemAccount = [[keyChainInstance accountForUser:[self valueForKeyPath:@"selectedFavorite.user"] host:[self valueForKeyPath:@"selectedFavorite.host"] database:[self valueForKeyPath:@"selectedFavorite.database"]] retain];
if ([keyChainInstance passwordExistsForName:connectionKeychainItemName account:connectionKeychainItemAccount]) {
[passwordField setStringValue:[keyChainInstance getPasswordForName:connectionKeychainItemName account:connectionKeychainItemAccount]];
} else {
@@ -562,10 +561,8 @@ NSString *TableDocumentFavoritesControllerSelectionIndexDidChange = @"TableDocum
}
// And the same for the SSH password
- connectionSSHKeychainItemName = [[NSString stringWithFormat:@"Sequel Pro SSHTunnel : %@ (%i)", [self valueForKeyPath:@"selectedFavorite.name"], [[self valueForKeyPath:@"selectedFavorite.id"] intValue]] retain];
- connectionSSHKeychainItemAccount = [[NSString stringWithFormat:@"%@@%@",
- [self valueForKeyPath:@"selectedFavorite.sshUser"],
- [self valueForKeyPath:@"selectedFavorite.sshHost"]] retain];
+ connectionSSHKeychainItemName = [[NSString alloc] initWithString:[keyChainInstance nameForSSHForFavoriteName:[self valueForKeyPath:@"selectedFavorite.name"] id:[self valueForKeyPath:@"selectedFavorite.id"]]];
+ connectionSSHKeychainItemAccount = [[NSString alloc] initWithString:[keyChainInstance accountForSSHUser:[self valueForKeyPath:@"selectedFavorite.sshUser"] sshHost:[self valueForKeyPath:@"selectedFavorite.sshHost"]]];
if ([keyChainInstance passwordExistsForName:connectionSSHKeychainItemName account:connectionSSHKeychainItemAccount]) {
[sshPasswordField setStringValue:[keyChainInstance getPasswordForName:connectionSSHKeychainItemName account:connectionSSHKeychainItemAccount]];
} else {
@@ -619,7 +616,7 @@ NSString *TableDocumentFavoritesControllerSelectionIndexDidChange = @"TableDocum
- (void)connectSheetAddToFavorites:(id)sender
{
- [self addToFavoritesName:[nameField stringValue] host:[hostField stringValue] socket:[socketField stringValue] user:[userField stringValue] password:[passwordField stringValue] port:[portField stringValue] database:[databaseField stringValue] useSSH:false sshHost:@"" sshUser:@"" sshPassword:@"" sshPort:@""];
+ [self addToFavoritesName:[nameField stringValue] host:[hostField stringValue] socket:[socketField stringValue] user:[userField stringValue] password:[passwordField stringValue] port:[portField stringValue] database:[databaseField stringValue] useSSH:([sshCheckbox state] == NSOnState) sshHost:[sshHostField stringValue] sshUser:[sshUserField stringValue] sshPassword:[sshPasswordField stringValue] sshPort:[sshPortField stringValue]];
}
/**
@@ -628,31 +625,50 @@ NSString *TableDocumentFavoritesControllerSelectionIndexDidChange = @"TableDocum
- (void)addToFavoritesName:(NSString *)name host:(NSString *)host socket:(NSString *)socket
user:(NSString *)user password:(NSString *)password
port:(NSString *)port database:(NSString *)database
- useSSH:(BOOL)useSSH // no-longer in use
- sshHost:(NSString *)sshHost // no-longer in use
- sshUser:(NSString *)sshUser // no-longer in use
- sshPassword:(NSString *)sshPassword // no-longer in use
- sshPort:(NSString *)sshPort // no-longer in use
+ useSSH:(BOOL)useSSH
+ sshHost:(NSString *)sshHost sshUser:(NSString *)sshUser
+ sshPassword:(NSString *)sshPassword sshPort:(NSString *)sshPort
{
NSString *favoriteName = [name length]?name:[NSString stringWithFormat:@"%@@%@", user, host];
NSNumber *favoriteid = [NSNumber numberWithInt:[[NSString stringWithFormat:@"%f", [[NSDate date] timeIntervalSince1970]] hash]];
if (![name length] && ![database isEqualToString:@""])
favoriteName = [NSString stringWithFormat:@"%@ %@", database, favoriteName];
- // test if host and socket are not nil
+ // Ensure that host and socket are not nil
if ([host isEqualToString:@""] && [socket isEqualToString:@""]) {
NSRunAlertPanel(NSLocalizedString(@"Insufficient connection details", @"insufficient details message"), NSLocalizedString(@"Insufficient details provided to establish a connection. Please provide at least a host or socket.", @"insufficient details informative message"), NSLocalizedString(@"OK", @"OK button"), nil, nil);
-
return;
}
- // write favorites and password
- 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]];
+ // If SSH is enabled, ensure that the SSH host is not nil
+ if ([sshCheckbox state] == NSOnState && ![[sshHostField stringValue] length]) {
+ NSRunAlertPanel(NSLocalizedString(@"Insufficient connection details", @"insufficient details message"), NSLocalizedString(@"Please enter the hostname for the SSH Tunnel, or disable the SSH Tunnel.", @"message of panel when ssh details are incomplete"), NSLocalizedString(@"OK", @"OK button"), nil, nil);
+ return;
+ }
+
+ // Write favorites and password(s)
+ NSDictionary *newFavorite = [NSDictionary dictionaryWithObjectsAndKeys:
+ favoriteName, @"name",
+ host, @"host",
+ socket, @"socket",
+ user, @"user",
+ port, @"port",
+ database, @"database",
+ [NSNumber numberWithBool:useSSH], @"useSSH",
+ sshHost, @"sshHost",
+ sshUser, @"sshUser",
+ sshPort, @"sshPort",
+ favoriteid, @"id",
+ nil];
if (![password isEqualToString:@""]) {
[keyChainInstance addPassword:password
- forName:[NSString stringWithFormat:@"Sequel Pro : %@ (%i)", favoriteName, [favoriteid intValue]]
- account:[NSString stringWithFormat:@"%@@%@/%@", user, host, database]];
+ forName:[keyChainInstance nameForFavoriteName:favoriteName id:[NSString stringWithFormat:@"%i", [favoriteid intValue]]]
+ account:[keyChainInstance accountForUser:user host:host database:database]];
+ }
+ if (![sshPassword isEqualToString:@""]) {
+ [keyChainInstance addPassword:password
+ forName:[keyChainInstance nameForSSHForFavoriteName:favoriteName id:[NSString stringWithFormat:@"%i", [favoriteid intValue]]]
+ account:[keyChainInstance accountForSSHUser:sshUser sshHost:sshHost]];
}
[favoritesController addObject:newFavorite];
@@ -1568,7 +1584,7 @@ NSString *TableDocumentFavoritesControllerSelectionIndexDidChange = @"TableDocum
- (void)closeConnection
{
[mySQLConnection disconnect];
-
+
// Disconnected Growl notification
[[SPGrowlController sharedGrowlController] notifyWithTitle:@"Disconnected"
description:[NSString stringWithFormat:NSLocalizedString(@"Disconnected from %@",@"description for disconnected growl notification"), [tableWindow title]]
@@ -1858,8 +1874,19 @@ NSString *TableDocumentFavoritesControllerSelectionIndexDidChange = @"TableDocum
return;
}
- // Add current connection to favorites using the same method as used on the connection sheet to provide consistency.
- [self connectSheetAddToFavorites:self];
+ // Add current connection to favorites
+ NSString *password, *sshPassword;
+ if (connectionKeychainItemName) {
+ password = [keyChainInstance getPasswordForName:connectionKeychainItemName account:connectionKeychainItemAccount];
+ } else {
+ password = [passwordField stringValue];
+ }
+ if (connectionSSHKeychainItemName) {
+ sshPassword = [keyChainInstance getPasswordForName:connectionSSHKeychainItemName account:connectionSSHKeychainItemAccount];
+ } else {
+ sshPassword = [sshPasswordField stringValue];
+ }
+ [self addToFavoritesName:[nameField stringValue] host:[hostField stringValue] socket:[socketField stringValue] user:[userField stringValue] password:password port:[portField stringValue] database:[databaseField stringValue] useSSH:([sshCheckbox state] == NSOnState) sshHost:[sshHostField stringValue] sshUser:[sshUserField stringValue] sshPassword:sshPassword sshPort:[sshPortField stringValue]];
}
/**
@@ -2151,6 +2178,7 @@ NSString *TableDocumentFavoritesControllerSelectionIndexDidChange = @"TableDocum
- (void)windowWillClose:(NSNotification *)aNotification
{
if ([mySQLConnection isConnected]) [self closeConnection];
+ if (sshTunnel) [sshTunnel disconnect], [sshTunnel release], sshTunnel = nil;
if ([[[SPQueryConsole sharedQueryConsole] window] isVisible]) [self toggleConsole:self];
[[customQueryInstance helpWebViewWindow] release];
[createTableSyntaxWindow release];