aboutsummaryrefslogtreecommitdiffstats
path: root/Source
diff options
context:
space:
mode:
Diffstat (limited to 'Source')
-rw-r--r--Source/SPNetworkPreferencePane.h5
-rw-r--r--Source/SPNetworkPreferencePane.m195
2 files changed, 199 insertions, 1 deletions
diff --git a/Source/SPNetworkPreferencePane.h b/Source/SPNetworkPreferencePane.h
index 37408c32..d980f175 100644
--- a/Source/SPNetworkPreferencePane.h
+++ b/Source/SPNetworkPreferencePane.h
@@ -37,16 +37,19 @@
*
* Network preference pane controller.
*/
-@interface SPNetworkPreferencePane : SPPreferencePane <SPPreferencePaneProtocol>
+@interface SPNetworkPreferencePane : SPPreferencePane <SPPreferencePaneProtocol, NSTableViewDataSource, NSTableViewDelegate>
{
IBOutlet NSView *sshClientPickerView;
IBOutlet NSTextField *sshClientPath;
IBOutlet NSView *hiddenFileView;
+ IBOutlet NSTableView *sslCipherView;
@private
NSAlert *_currentAlert;
NSOpenPanel *_currentFilePanel;
+ NSMutableArray *sslCiphers;
}
- (IBAction)pickSSHClientViaFileBrowser:(id)sender;
- (IBAction)pickSSHClient:(id)sender;
+- (IBAction)resetCipherList:(id)sender;
@end
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