aboutsummaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
authorBibiko <bibiko@eva.mpg.de>2009-08-24 11:02:23 +0000
committerBibiko <bibiko@eva.mpg.de>2009-08-24 11:02:23 +0000
commit40880459c66165a264faa561319c996d82613fac (patch)
treea5be30704b5cfb26e9f3a3500a0869c589e0fc82 /Source
parentb02932c07c4fdbf5b8c051c5a7218c4c37cf4bf2 (diff)
downloadsequelpro-40880459c66165a264faa561319c996d82613fac.tar.gz
sequelpro-40880459c66165a264faa561319c996d82613fac.tar.bz2
sequelpro-40880459c66165a264faa561319c996d82613fac.zip
• further improvements for open/save spf files
- added encryption code routine - if encrypted ask for password • added to SPDataAdditions dataEn/DecryptedWithPassword: • tiny fixes for cascading new doc windows - never decrease win size less than minSize - large win width detection now gets rid of all connected monitors • updated credits.rtf
Diffstat (limited to 'Source')
-rw-r--r--Source/SPDataAdditions.h8
-rw-r--r--Source/SPDataAdditions.m83
-rw-r--r--Source/TableDocument.m146
3 files changed, 207 insertions, 30 deletions
diff --git a/Source/SPDataAdditions.h b/Source/SPDataAdditions.h
index fcf2640c..40bea690 100644
--- a/Source/SPDataAdditions.h
+++ b/Source/SPDataAdditions.h
@@ -26,9 +26,11 @@
@interface NSData (SPDataAdditions)
-- (NSString *) base64EncodingWithLineLength:(unsigned int)lineLength;
-- (NSString *) dataToFormattedHexString;
-- (NSString *) shortStringRepresentationUsingEncoding:(NSStringEncoding)encoding;
+- (NSString *)base64EncodingWithLineLength:(unsigned int)lineLength;
+- (NSString *)dataToFormattedHexString;
+- (NSString *)shortStringRepresentationUsingEncoding:(NSStringEncoding)encoding;
+- (NSData*)dataEncryptedWithPassword:(NSString*)password;
+- (NSData*)dataDecryptedWithPassword:(NSString*)password;
- (NSData *)compress;
- (NSData *)decompress;
diff --git a/Source/SPDataAdditions.m b/Source/SPDataAdditions.m
index edac9baa..1af06f5b 100644
--- a/Source/SPDataAdditions.m
+++ b/Source/SPDataAdditions.m
@@ -4,6 +4,11 @@
// SPDataAdditions.m
// sequel-pro
//
+// dataEncryptedWithPassword and dataDecryptedWithPassword:
+// License: FREEWARE http://aquaticmac.com/cocoa.php
+// Copyright (c) 2005, Lucas Newman
+// All rights reserved.
+//
// Created by Hans-Jörg Bibiko on June 19, 2009
//
// This program is free software; you can redistribute it and/or modify
@@ -24,6 +29,8 @@
#import "SPDataAdditions.h"
#include <zlib.h>
+#include <openssl/aes.h>
+#include <openssl/sha.h>
static char base64encodingTable[64] = {
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
@@ -101,6 +108,82 @@ static char base64encodingTable[64] = {
return base64;
}
+- (NSData*)dataEncryptedWithPassword:(NSString*)password
+{
+ // Create a random 128-bit initialization vector
+ srand(time(NULL));
+ int ivIndex;
+ unsigned char iv[16];
+ for (ivIndex = 0; ivIndex < 16; ivIndex++)
+ iv[ivIndex] = rand() & 0xff;
+
+ // Calculate the 16-byte AES block padding
+ int dataLength = [self length];
+ int paddedLength = dataLength + (32 - (dataLength % 16));
+ int totalLength = paddedLength + 16; // Data plus IV
+
+ // Allocate enough space for the IV + ciphertext
+ unsigned char *encryptedBytes = calloc(1, totalLength);
+ // The first block of the ciphertext buffer is the IV
+ memcpy(encryptedBytes, iv, 16);
+
+ unsigned char *paddedBytes = calloc(1, paddedLength);
+ memcpy(paddedBytes, [self bytes], dataLength);
+
+ // The last 32-bit chunk is the size of the plaintext, which is encrypted with the plaintext
+ int bigIntDataLength = NSSwapHostIntToBig(dataLength);
+ memcpy(paddedBytes + (paddedLength - 4), &bigIntDataLength, 4);
+
+ // Create the key from first 128-bits of the 160-bit password hash
+ unsigned char passwordDigest[20];
+ SHA1((const unsigned char *)[password UTF8String], strlen([password UTF8String]), passwordDigest);
+ AES_KEY aesKey;
+ AES_set_encrypt_key(passwordDigest, 128, &aesKey);
+
+ // AES-128-cbc encrypt the data, filling in the buffer after the IV
+ AES_cbc_encrypt(paddedBytes, encryptedBytes + 16, paddedLength, &aesKey, iv, AES_ENCRYPT);
+ free(paddedBytes);
+
+ return [NSData dataWithBytesNoCopy:encryptedBytes length:totalLength];
+}
+
+- (NSData*)dataDecryptedWithPassword:(NSString*)password
+{
+ // Create the key from the password hash
+ unsigned char passwordDigest[20];
+ SHA1((const unsigned char *)[password UTF8String], strlen([password UTF8String]), passwordDigest);
+
+ // AES-128-cbc decrypt the data
+ AES_KEY aesKey;
+ AES_set_decrypt_key(passwordDigest, 128, &aesKey);
+
+ // Total length = encrypted length + IV
+ int totalLength = [self length];
+ int encryptedLength = totalLength - 16;
+
+ // Take the IV from the first 128-bit block
+ unsigned char iv[16];
+ memcpy(iv, [self bytes], 16);
+
+ // Decrypt the data
+ unsigned char *decryptedBytes = (unsigned char*)malloc(encryptedLength);
+ AES_cbc_encrypt([self bytes] + 16, decryptedBytes, encryptedLength, &aesKey, iv, AES_DECRYPT);
+
+ // If decryption was successful, these blocks will be zeroed
+ if ( *((unsigned int*)decryptedBytes + ((encryptedLength / 4) - 4)) ||
+ *((unsigned int*)decryptedBytes + ((encryptedLength / 4) - 3)) ||
+ *((unsigned int*)decryptedBytes + ((encryptedLength / 4) - 2)) )
+ {
+ return nil;
+ }
+
+ // Get the size of the data from the last 32-bit chunk
+ int bigIntDataLength = *((unsigned int*)decryptedBytes + ((encryptedLength / 4) - 1));
+ int dataLength = NSSwapBigIntToHost(bigIntDataLength);
+
+ return [NSData dataWithBytesNoCopy:decryptedBytes length:dataLength];
+}
+
- (NSData *)decompress
{
if ([self length] == 0) return self;
diff --git a/Source/TableDocument.m b/Source/TableDocument.m
index a6b4caae..2608c47e 100644
--- a/Source/TableDocument.m
+++ b/Source/TableDocument.m
@@ -83,6 +83,7 @@
prefs = [NSUserDefaults standardUserDefaults];
queryEditorInitString = nil;
+ [saveConnectionEncryptString setStringValue:@""];
spf = nil;
@@ -114,12 +115,12 @@
screenFrame = [candidate frame];
previousFrame = [tableWindow frame];
- topLeftPoint = previousFrame.origin;
- if(topLeftPoint.x + previousFrame.size.width > screenFrame.size.width-1) {
+ if(previousFrame.origin.x - screenFrame.origin.x + previousFrame.size.width > screenFrame.size.width-1) {
previousFrame.size.width -= 50;
previousFrame.size.height -= 50;
previousFrame.origin.y += 50;
- [tableWindow setFrame:previousFrame display:YES];
+ if(previousFrame.size.width >= [tableWindow minSize].width && previousFrame.size.height >= [tableWindow minSize].height)
+ [tableWindow setFrame:previousFrame display:YES];
}
}
@@ -170,6 +171,8 @@
NSError *readError = nil;
NSString *convError = nil;
NSPropertyListFormat format;
+ NSString *encryptpw = nil;
+
NSData *pData = [[NSData dataWithContentsOfFile:path options:NSUncachedRead error:&readError] decompress];
spf = [[NSPropertyListSerialization propertyListFromData:pData
mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&convError] retain];
@@ -186,27 +189,65 @@
return;
}
+ // Init Custom Query editor with the stored queries if given
if([spf objectForKey:@"queries"])
[self initQueryEditorWithString:[spf objectForKey:@"queries"]];
- if([spf objectForKey:@"type"])
- [connectionController setType:[[spf objectForKey:@"type"] intValue]];
+ // Clean fields
+ [connectionController setName:@""];
+ [connectionController setUser:@""];
+ [connectionController setHost:@""];
+ [connectionController setPort:@""];
+ [connectionController setSshHost:@""];
+ [connectionController setSshUser:@""];
+ [connectionController setSshPort:@""];
+ [connectionController setDatabase:@""];
+ [connectionController setPassword:@""];
+ [connectionController setSshPassword:@""];
+
+ // NSLog(@"%@", spf);
+
+ // Ask for a password if SPF file passwords were encrypted
+ if([spf objectForKey:@"encrypted"] && [[spf objectForKey:@"encrypted"] intValue] == NSOnState) {
+ NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Connection file is encrypted", @"Connection file is encrypted")
+ defaultButton:@"OK"
+ alternateButton:@"Cancel"
+ otherButton:nil
+ informativeTextWithFormat:NSLocalizedString(@"Please enter the password:",@"Please enter the password")];
+
+ NSTextField *input = [[NSSecureTextField alloc] initWithFrame:NSMakeRect(0, 0, 220, 24)];
+ [input setStringValue:@""];
+ [alert setAccessoryView:input];
+ [[alert window] setInitialFirstResponder:input];
+ [[alert window] makeFirstResponder:input];
+ [input selectText:[alert window]];
+ NSInteger button = [alert runModal];
+ if (button == NSAlertDefaultReturn) {
+ encryptpw = [input stringValue];
+ [input release];
+ } else {
+ [input release];
+ return;
+ }
+ }
+
+ if([spf objectForKey:@"connectionType"]) {
+ [connectionController setType:[[spf objectForKey:@"connectionType"] intValue]];
+ [connectionController resizeTabViewToConnectionType:[connectionController type] animating:NO];
+ }
+
if([spf objectForKey:@"name"])
[connectionController setName:[spf objectForKey:@"name"]];
if([spf objectForKey:@"user"])
[connectionController setUser:[spf objectForKey:@"user"]];
if([spf objectForKey:@"host"])
[connectionController setHost:[spf objectForKey:@"host"]];
- if([spf objectForKey:@"auth"])
- [connectionController setPassword:[spf objectForKey:@"auth"]];
if([spf objectForKey:@"port"])
[connectionController setPort:[spf objectForKey:@"port"]];
if([spf objectForKey:@"sshHost"])
[connectionController setSshHost:[spf objectForKey:@"sshHost"]];
if([spf objectForKey:@"sshUser"])
[connectionController setSshUser:[spf objectForKey:@"sshUser"]];
- if([spf objectForKey:@"sshAuth"])
- [connectionController setSshPassword:[spf objectForKey:@"sshAuth"]];
if([spf objectForKey:@"sshPort"])
[connectionController setSshPort:[spf objectForKey:@"sshPort"]];
if([spf objectForKey:@"selectedDatabase"])
@@ -215,16 +256,46 @@
// If password are stored in SPF file auto-connect
// otherwise wait for password(s)
if([spf objectForKey:@"auth"]) {
- if([[spf objectForKey:@"type"] intValue] == 2) {
- if(![spf objectForKey:@"sshAuth"])
- return;
+
+ NSString *sauth;
+ if(encryptpw != nil && [spf objectForKey:@"encrypted"] && [[spf objectForKey:@"encrypted"] intValue] == NSOnState)
+ sauth = [[NSString alloc] initWithData:[[spf objectForKey:@"auth"] dataDecryptedWithPassword:encryptpw] encoding:NSUTF8StringEncoding];
+ else
+ sauth = [[NSString alloc] initWithData:[spf objectForKey:@"auth"] encoding:NSUTF8StringEncoding];
+ [connectionController setPassword:sauth];
+ [sauth release];
+
+ if([connectionController type] == SP_CONNECTION_SSHTUNNEL) {
+
+ if(![spf objectForKey:@"sshAuth"]) {
+ [connectionController setSshPassword:@""];
+ [[connectionController valueForKeyPath:@"sshSSHPasswordField"] selectText:self];
+ return;
+ }
+
+ NSString *sshauth;
+ if(encryptpw != nil && [spf objectForKey:@"encrypted"] && [[spf objectForKey:@"encrypted"] intValue] == NSOnState)
+ sshauth = [[NSString alloc] initWithData:[[spf objectForKey:@"auth"] dataDecryptedWithPassword:encryptpw] encoding:NSUTF8StringEncoding];
+ else
+ sshauth = [[NSString alloc] initWithData:[spf objectForKey:@"auth"] encoding:NSUTF8StringEncoding];
+
+ [connectionController setSshPassword:sshauth];
+ [sshauth release];
[connectionController initiateConnection:nil];
- [self performSelector:@selector(restoreSession) withObject:nil afterDelay:0.2];
} else {
+
[connectionController initiateConnection:nil];
+
}
+ } else {
+
+ [connectionController setPassword:@""];
+ [connectionController setSshPassword:@""];
+ [[connectionController valueForKeyPath:@"standardPasswordField"] selectText:self];
+
}
+ encryptpw = nil;
}
@@ -249,22 +320,13 @@
// Select table
[tablesListInstance selectTableAtIndex:[NSNumber numberWithInt:[tables indexOfObject:[spf objectForKey:@"selectedTable"]]]];
+ [[tablesListInstance valueForKeyPath:@"tablesListView"] scrollRowToVisible:[tables indexOfObject:[spf objectForKey:@"selectedTable"]]];
// Set table content details for restore
if([spf objectForKey:@"contentSortCol"])
[tableContentInstance setSortColumnNameToRestore:[spf objectForKey:@"contentSortCol"] isAscending:[[spf objectForKey:@"contentSortCol"] boolValue]];
if([spf objectForKey:@"contentLimitStartPosition"])
[tableContentInstance setLimitStartToRestore:[[spf objectForKey:@"contentLimitStartPosition"] intValue]];
- if([spf objectForKey:@"contentSelectedIndexSet"]) {
- NSMutableIndexSet *anIndexSet = [NSMutableIndexSet indexSet];
- NSArray *items = [spf objectForKey:@"contentSelectedIndexSet"];
- unsigned int i;
- for(i=0; i<[items count]; i++)
- {
- [anIndexSet addIndex:(NSUInteger)NSArrayObjectAtIndex(items, i)];
- }
- [tableContentInstance setSelectedRowIndexesToRestore:anIndexSet];
- }
if([spf objectForKey:@"contentViewport"])
[tableContentInstance setViewportToRestore:NSRectFromString([spf objectForKey:@"contentViewport"])];
if([spf objectForKey:@"contentFilter"])
@@ -296,6 +358,17 @@
}
}
+ if([spf objectForKey:@"contentSelectedIndexSet"]) {
+ NSMutableIndexSet *anIndexSet = [NSMutableIndexSet indexSet];
+ NSArray *items = [spf objectForKey:@"contentSelectedIndexSet"];
+ unsigned int i;
+ for(i=0; i<[items count]; i++)
+ {
+ [anIndexSet addIndex:(NSUInteger)NSArrayObjectAtIndex(items, i)];
+ }
+ [tableContentInstance setSelectedRowIndexesToRestore:anIndexSet];
+ }
+
// dealloc spf data
[spf release];
spf = nil;
@@ -1746,8 +1819,9 @@
// Save current session (open connection windows as SPF file)
// [panel setMessage:NSLocalizedString(@"Save Sequel Pro session", @"Save Sequel Pro session")];
[panel setAllowedFileTypes:[NSArray arrayWithObjects:@"spf", nil]];
- [saveConnectionEncryptString setDelegate:self];
+ // [saveConnectionEncryptString setDelegate:self];
[saveConnectionEncryptString setEnabled:YES];
+ [saveConnectionEncryptString selectText:self];
[saveConnectionEncryptString setStringValue:@""];
[saveConnectionEncryptString setEnabled:NO];
[saveConnectionSavePassword setState:NSOffState];
@@ -1778,9 +1852,10 @@
[saveConnectionEncrypt setEnabled:YES];
if([saveConnectionEncrypt state] == NSOnState) {
[saveConnectionEncryptString setEnabled:YES];
- [saveConnectionEncryptString selectText:nil];
+ [saveConnectionEncryptString selectText:self];
} else {
[saveConnectionEncryptString setEnabled:YES];
+ [saveConnectionEncryptString selectText:self];
[saveConnectionEncryptString setStringValue:@""];
[saveConnectionEncryptString setHidden:YES];
[saveConnectionEncryptString setHidden:NO];
@@ -1789,6 +1864,7 @@
} else {
[saveConnectionEncrypt setEnabled:NO];
[saveConnectionEncryptString setEnabled:YES];
+ [saveConnectionEncryptString selectText:self];
[saveConnectionEncryptString setStringValue:@""];
[saveConnectionEncryptString setHidden:YES];
[saveConnectionEncryptString setHidden:NO];
@@ -1824,8 +1900,13 @@
}
return;
}
+
+ // Save connection and session as SPF file
else if(contextInfo == @"saveSPFfile") {
+ [saveConnectionEncryptString abortEditing];
+ [saveConnectionEncryptString selectText:nil];
+
NSMutableDictionary *spfdata = [NSMutableDictionary dictionary];
NSIndexSet *contentSelectedIndexSet = [tableContentInstance selectedRowIndexes];
@@ -1836,14 +1917,25 @@
[spfdata setObject:[self name] forKey:@"name"];
[spfdata setObject:[self host] forKey:@"host"];
[spfdata setObject:[self user] forKey:@"user"];
- // [spfdata setObject:[connectionController password] forKey:@"auth"];
+
+ if([saveConnectionEncrypt isEnabled])
+ [spfdata setObject:[NSNumber numberWithInt:[saveConnectionEncrypt state]] forKey:@"encrypted"];
[spfdata setObject:[NSNumber numberWithInt:[connectionController type]] forKey:@"connectionType"];
if([connectionController type] == 2) {
[spfdata setObject:[connectionController sshHost] forKey:@"sshHost"];
[spfdata setObject:[connectionController sshUser] forKey:@"sshUser"];
[spfdata setObject:[connectionController sshPort] forKey:@"sshPort"];
- // [spfdata setObject:[connectionController sshPassword] forKey:@"sshAuth"];
+ }
+
+ if([saveConnectionSavePassword state] == NSOnState) {
+ if([saveConnectionEncrypt state] == NSOffState) {
+ [spfdata setObject:[[connectionController password] dataUsingEncoding:NSUTF8StringEncoding] forKey:@"auth"];
+ [spfdata setObject:[[connectionController sshPassword] dataUsingEncoding:NSUTF8StringEncoding] forKey:@"sshAuth"];
+ } else {
+ [spfdata setObject:[[[connectionController password] dataUsingEncoding:NSUTF8StringEncoding] dataEncryptedWithPassword:[saveConnectionEncryptString stringValue]] forKey:@"auth"];
+ [spfdata setObject:[[[connectionController sshPassword] dataUsingEncoding:NSUTF8StringEncoding] dataEncryptedWithPassword:[saveConnectionEncryptString stringValue]] forKey:@"sshAuth"];
+ }
}
if([connectionController port] &&[[connectionController port] length])