aboutsummaryrefslogtreecommitdiffstats
path: root/Source/SPSSHTunnel.m
diff options
context:
space:
mode:
authorrowanbeentje <rowan@beent.je>2009-06-06 23:25:06 +0000
committerrowanbeentje <rowan@beent.je>2009-06-06 23:25:06 +0000
commitab4d3557db6d823275b688ccb7210830f029fd5c (patch)
treecf0ba9733d03868c22d81904d4486ed2de350f4c /Source/SPSSHTunnel.m
parent2f5c4b9bab18b54f2d37f4b4a05afa116cfd0c44 (diff)
downloadsequelpro-ab4d3557db6d823275b688ccb7210830f029fd5c.tar.gz
sequelpro-ab4d3557db6d823275b688ccb7210830f029fd5c.tar.bz2
sequelpro-ab4d3557db6d823275b688ccb7210830f029fd5c.zip
Further SSH tunnel improvements:
- Redesigned SSH key authentication dialog - Added ability to add SSH key passphrases to keychain (sharing details with system SSH) - SSH tunnels with keys which fail are now correctly restarted, interacting with the GUI as necessary - GUI interaction now performed on the main thread for increased stability
Diffstat (limited to 'Source/SPSSHTunnel.m')
-rw-r--r--Source/SPSSHTunnel.m58
1 files changed, 50 insertions, 8 deletions
diff --git a/Source/SPSSHTunnel.m b/Source/SPSSHTunnel.m
index d8332c14..6df20d2e 100644
--- a/Source/SPSSHTunnel.m
+++ b/Source/SPSSHTunnel.m
@@ -22,6 +22,8 @@
// More info at <http://code.google.com/p/sequel-pro/>
#import "SPSSHTunnel.h"
+#import "RegexKitLite.h"
+#import "KeyChain.h"
#import <netinet/in.h>
@@ -69,6 +71,8 @@
keychainName = nil;
keychainAccount = nil;
passwordInKeychain = NO;
+ requestedPassphrase = nil;
+ requestedResponse = NO;
task = nil;
localPort = 0;
connectionState = SPSSH_STATE_IDLE;
@@ -226,7 +230,7 @@
// [taskArguments addObject:@"-C"]; // TODO: compression?
[taskArguments addObject:@"-o ExitOnForwardFailure=yes"];
[taskArguments addObject:[NSString stringWithFormat:@"-o ConnectTimeout=%i", connectionTimeout]];
- [taskArguments addObject:@"-o NumberOfPasswordPrompts=1"];
+ [taskArguments addObject:@"-o NumberOfPasswordPrompts=3"];
if (useKeepAlive && keepAliveInterval) {
[taskArguments addObject:@"-o TCPKeepAlive=no"];
[taskArguments addObject:[NSString stringWithFormat:@"-o ServerAliveInterval=%i", (int)ceil(keepAliveInterval)]];
@@ -403,6 +407,13 @@
*/
- (BOOL) getResponseForQuestion:(NSString *)theQuestion
{
+ [self performSelectorOnMainThread:@selector(workerGetResponseForQuestion:) withObject:theQuestion waitUntilDone:YES];
+
+ return requestedResponse;
+}
+- (void) workerGetResponseForQuestion:(NSString *)theQuestion
+{
+
NSSize questionTextSize;
NSRect windowFrameRect;
@@ -410,7 +421,7 @@
[sshQuestionText setStringValue:theQuestion];
questionTextSize = [[sshQuestionText cell] cellSizeForBounds:NSMakeRect(0, 0, [sshQuestionText bounds].size.width, 500)];
windowFrameRect = [sshQuestionDialog frame];
- windowFrameRect.size.height = ((questionTextSize.height < 100)?100:questionTextSize.height) + 90;
+ windowFrameRect.size.height = ((questionTextSize.height < 100)?100:questionTextSize.height) + 70 + ([sshPasswordDialog isSheet]?0:22);
[sshQuestionDialog setFrame:windowFrameRect display:NO];
[NSApp beginSheet:sshQuestionDialog modalForWindow:parentWindow modalDelegate:self didEndSelector:nil contextInfo:nil];
int sshQueryResponseCode = [NSApp runModalForWindow:sshQuestionDialog];
@@ -421,11 +432,13 @@
// Yes
case 1:
- return YES;
+ requestedResponse = YES;
+ return;
// No
default:
- return NO;
+ requestedResponse = NO;
+ return;
}
}
@@ -437,15 +450,36 @@
{
if (![theHash isEqualToString:tunnelConnectionVerifyHash]) return nil;
+ NSString *thePassword;
+
+ [self performSelectorOnMainThread:@selector(workerGetPasswordForQuery:) withObject:theQuery waitUntilDone:YES];
+
+ if (!requestedPassphrase) return nil;
+ thePassword = [NSString stringWithString:requestedPassphrase];
+ [requestedPassphrase release], requestedPassphrase = nil;
+ return thePassword;
+}
+- (void) workerGetPasswordForQuery:(NSString *)theQuery
+{
NSSize queryTextSize;
NSRect windowFrameRect;
NSString *thePassword;
+ KeyChain *keychain;
+
+ // Work out whether a passphrase is being requested, extracting the key name
+ NSString *keyName = [theQuery stringByMatching:@"^\\s*Enter passphrase for key \\'(.*)\\':\\s*$" capture:1L];
+ if (keyName) {
+ [sshPasswordText setStringValue:[NSString stringWithFormat:@"Enter your password for the SSH key\n\"%@\"", keyName]];
+ [sshPasswordKeychainCheckbox setHidden:NO];
+ } else {
+ [sshPasswordText setStringValue:theQuery];
+ [sshPasswordKeychainCheckbox setHidden:YES];
+ }
// Request the password, sizing the window appropriately to fit the query
- [sshPasswordText setStringValue:theQuery];
queryTextSize = [[sshPasswordText cell] cellSizeForBounds:NSMakeRect(0, 0, [sshPasswordText bounds].size.width, 500)];
windowFrameRect = [sshPasswordDialog frame];
- windowFrameRect.size.height = ((queryTextSize.height < 40)?40:queryTextSize.height) + 143;
+ windowFrameRect.size.height = ((queryTextSize.height < 40)?40:queryTextSize.height) + 140 + ([sshPasswordDialog isSheet]?0:22);
[sshPasswordDialog setFrame:windowFrameRect display:NO];
[NSApp beginSheet:sshPasswordDialog modalForWindow:parentWindow modalDelegate:self didEndSelector:nil contextInfo:nil];
int sshQueryResponseCode = [NSApp runModalForWindow:sshPasswordDialog];
@@ -459,11 +493,19 @@
thePassword = [NSString stringWithString:[sshPasswordField stringValue]];
[sshPasswordField setStringValue:@""];
[[delegate undoManager] removeAllActionsWithTarget:sshPasswordField];
- return thePassword;
+ requestedPassphrase = [[NSString alloc] initWithString:thePassword];
+
+ // Add to keychain if appropriate
+ if (keyName && [sshPasswordKeychainCheckbox state] == NSOnState) {
+ keychain = [[KeyChain alloc] init];
+ [keychain addPassword:thePassword forName:@"SSH" account:keyName withLabel:[NSString stringWithFormat:@"SSH: %@", keyName]];
+ [keychain release];
+ }
+ return;
// Cancel
default:
- return nil;
+ return;
}
}