aboutsummaryrefslogtreecommitdiffstats
path: root/Source/SPNetworkPreferencePane.m
diff options
context:
space:
mode:
authorMax <post@wickenrode.com>2015-03-21 03:05:33 +0100
committerMax <post@wickenrode.com>2015-03-21 03:05:33 +0100
commitea39be538d4726b583e67748d6e3e7ffb0ce9026 (patch)
tree186b98ae442bf547b4d7f84fc893bd80da6d0ce5 /Source/SPNetworkPreferencePane.m
parent1b6248d6a256ad774d092151227fdd5f40247c02 (diff)
downloadsequelpro-ea39be538d4726b583e67748d6e3e7ffb0ce9026.tar.gz
sequelpro-ea39be538d4726b583e67748d6e3e7ffb0ce9026.tar.bz2
sequelpro-ea39be538d4726b583e67748d6e3e7ffb0ce9026.zip
Add UI for custom SSL cipher lists
See Preferences > Network. Note: If you play around with that too much and libmysql can no longer connect, don't hope for a meaningful error. It will rather be something like "protocol version mismatch".
Diffstat (limited to 'Source/SPNetworkPreferencePane.m')
-rw-r--r--Source/SPNetworkPreferencePane.m195
1 files changed, 195 insertions, 0 deletions
diff --git a/Source/SPNetworkPreferencePane.m b/Source/SPNetworkPreferencePane.m
index 376ba39f..4f13c433 100644
--- a/Source/SPNetworkPreferencePane.m
+++ b/Source/SPNetworkPreferencePane.m
@@ -30,12 +30,33 @@
#import "SPNetworkPreferencePane.h"
+static NSString *SPSSLCipherListMarkerItem = @"--";
+static NSString *SPSSLCipherPboardTypeName = @"SSLCipherPboardType";
+
@interface SPNetworkPreferencePane (Private)
- (void)updateHiddenFiles;
+- (void)loadSSLCiphers;
+- (void)storeSSLCiphers;
++ (NSArray *)defaultSSLCipherList;
@end
@implementation SPNetworkPreferencePane
+- (instancetype)init
+{
+ self = [super init];
+ if (self) {
+ sslCiphers = [[NSMutableArray alloc] init];
+ }
+ return self;
+}
+
+- (void)dealloc
+{
+ SPClear(sslCiphers);
+ [super dealloc];
+}
+
#pragma mark -
#pragma mark Preference pane protocol methods
@@ -69,6 +90,16 @@
return NO;
}
+- (void)preferencePaneWillBeShown
+{
+ [self loadSSLCiphers];
+ if(![[sslCipherView registeredDraggedTypes] containsObject:SPSSLCipherPboardTypeName])
+ [sslCipherView registerForDraggedTypes:@[SPSSLCipherPboardTypeName]];
+}
+
+#pragma mark -
+#pragma mark Custom SSH client methods
+
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if([SPHiddenKeyFileVisibilityKey isEqualTo:keyPath]) {
@@ -131,4 +162,168 @@
SPClear(_currentAlert);
}
+#pragma mark -
+#pragma mark SSL cipher list methods
+
+- (void)loadSSLCiphers
+{
+ NSArray *supportedCiphers = [SPNetworkPreferencePane defaultSSLCipherList];
+ [sslCiphers removeAllObjects];
+
+ NSString *userCipherString = [prefs stringForKey:SPSSLCipherListKey];
+ if(userCipherString) {
+ //expand user list
+ NSArray *userCipherList = [userCipherString componentsSeparatedByString:@":"];
+
+ //compare the users list to the valid list and only copy over valid items
+ for (NSString *userCipher in userCipherList) {
+ if (![supportedCiphers containsObject:userCipher] || [sslCiphers containsObject:userCipher]) {
+ SPLog(@"Unknown ssl cipher in users' list: %@",userCipher);
+ continue;
+ }
+ [sslCiphers addObject:userCipher];
+ }
+
+ //now we do the reverse and add valid ciphers that are not yet in the users list.
+ //We'll just assume the ones not in the users' list are newer and therefore better and add
+ //them at the top
+ NSUInteger shift = 0;
+ for (NSString *validCipher in supportedCiphers) {
+ if(![sslCiphers containsObject:validCipher]) {
+ [sslCiphers insertObject:validCipher atIndex:shift++];
+ }
+ }
+ }
+ else {
+ //no user prefs configured, so we'll just go with the defaults
+ [sslCiphers addObjectsFromArray:supportedCiphers];
+ }
+
+ //reload UI
+ [sslCipherView deselectAll:nil];
+ [sslCipherView reloadData];
+}
+
+- (void)storeSSLCiphers
+{
+ NSString *flattedList = [sslCiphers componentsJoinedByString:@":"];
+ [prefs setObject:flattedList forKey:SPSSLCipherListKey];
+}
+
+- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
+{
+ return [sslCiphers count];
+}
+
+- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
+{
+ NSString *value = [sslCiphers objectAtIndex:rowIndex];
+ if ([value isEqualTo:SPSSLCipherListMarkerItem]) {
+ return NSLocalizedString(@"Disabled Cipher Suites", @"Preferences : Network : SSL Chiper suites : List seperator");
+ }
+ return value;
+}
+
+- (BOOL)tableView:(NSTableView *)tableView isGroupRow:(NSInteger)row
+{
+ return ([[sslCiphers objectAtIndex:row] isEqualTo:SPSSLCipherListMarkerItem]);
+}
+
+- (BOOL)tableView:(NSTableView *)tableView shouldSelectRow:(NSInteger)row
+{
+ return ![self tableView:tableView isGroupRow:row];
+}
+
+- (BOOL)tableView:(NSTableView *)aTableView acceptDrop:(id <NSDraggingInfo>)info row:(NSInteger)row dropOperation:(NSTableViewDropOperation)operation
+{
+ if(row < 0) return NO; //why is that even a signed int when all "indexes" are unsigned!?
+
+ NSPasteboard *pboard = [info draggingPasteboard];
+ NSArray *draggedItems = [NSKeyedUnarchiver unarchiveObjectWithData:[pboard dataForType:SPSSLCipherPboardTypeName]];
+
+ NSUInteger nextInsert = row;
+ for (NSString *item in draggedItems) {
+ NSUInteger oldPos = [sslCiphers indexOfObject:item];
+ [sslCiphers removeObjectAtIndex:oldPos];
+
+ if(oldPos < (NSUInteger)row) {
+ // readjust position because we removed an object further up in the list, shifting all following indexes down by 1
+ nextInsert--;
+ }
+
+ [sslCiphers insertObject:item atIndex:nextInsert++];
+ }
+
+ NSMutableIndexSet *newSelection = [NSMutableIndexSet indexSet];
+ for (NSString *item in draggedItems) {
+ [newSelection addIndex:[sslCiphers indexOfObject:item]];
+ }
+
+ [self storeSSLCiphers];
+ [sslCipherView selectRowIndexes:newSelection byExtendingSelection:NO];
+
+ return YES;
+}
+
+- (NSDragOperation)tableView:(NSTableView *)aTableView validateDrop:(id <NSDraggingInfo>)info proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)operation
+{
+ //cannot drop something on another item in the list, only between them
+ return (operation == NSTableViewDropOn)? NSDragOperationNone : NSDragOperationMove;
+}
+
+- (BOOL)tableView:(NSTableView *)aTableView writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard *)pboard
+{
+ //the marker cannot be actively reordered
+ if ([rowIndexes containsIndex:[sslCiphers indexOfObject:SPSSLCipherListMarkerItem]])
+ return NO;
+
+ //put the names of the items on the pasteboard. easier to work with than indexes...
+ NSMutableArray *items = [NSMutableArray arrayWithCapacity:[rowIndexes count]];
+ [rowIndexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
+ [items addObject:[sslCiphers objectAtIndex:idx]];
+ }];
+
+ NSData *arch = [NSKeyedArchiver archivedDataWithRootObject:items];
+ [pboard declareTypes:@[SPSSLCipherPboardTypeName] owner:self];
+ [pboard setData:arch forType:SPSSLCipherPboardTypeName];
+ return YES;
+}
+
+- (IBAction)resetCipherList:(id)sender
+{
+ //remove the user pref and reset the GUI
+ [prefs removeObjectForKey:SPSSLCipherListKey];
+ [self loadSSLCiphers];
+}
+
++ (NSArray *)defaultSSLCipherList
+{
+ //this is the default list as hardcoded in SPMySQLConnection.m
+ //Sadly there is no way to make MySQL give us the list of runtime-supported ciphers.
+ return @[@"DHE-RSA-AES256-SHA",
+ @"AES256-SHA",
+ @"DHE-RSA-AES128-SHA",
+ @"AES128-SHA",
+ @"AES256-RMD",
+ @"AES128-RMD",
+ @"DES-CBC3-RMD",
+ @"DHE-RSA-AES256-RMD",
+ @"DHE-RSA-AES128-RMD",
+ @"DHE-RSA-DES-CBC3-RMD",
+ @"RC4-SHA",
+ @"RC4-MD5",
+ @"DES-CBC3-SHA",
+ @"DES-CBC-SHA",
+ @"EDH-RSA-DES-CBC3-SHA",
+ @"EDH-RSA-DES-CBC-SHA",
+ SPSSLCipherListMarkerItem, //marker. disabled items below here
+ @"EDH-DSS-DES-CBC-SHA",
+ @"EDH-DSS-DES-CBC3-SHA",
+ @"DHE-DSS-AES128-SHA",
+ @"DHE-DSS-AES256-SHA",
+ @"DHE-DSS-DES-CBC3-RMD",
+ @"DHE-DSS-AES128-RMD",
+ @"DHE-DSS-AES256-RMD"];
+}
+
@end