blob: 22320b1ae3763692a96448b529ff116e3196159d [file] [log] [blame]
/*
* Copyright (C) 2004-2015 Savoir-Faire Linux Inc.
* Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Additional permission under GNU GPL version 3 section 7:
*
* If you modify this program, or any covered work, by linking or
* combining it with the OpenSSL project's OpenSSL library (or a
* modified version of that library), containing parts covered by the
* terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
* grants you additional permission to convey the resulting work.
* Corresponding Source for a non-source form of such a combination
* shall include the source code for the parts of OpenSSL used as well
* as that of the covered work.
*/
#import "AccSecurityVC.h"
#import <QUrl>
#import <certificate.h>
#import <tlsmethodmodel.h>
#import <qitemselectionmodel.h>
#import <ciphermodel.h>
#import "QNSTreeController.h"
#import "CertificateWC.h"
// Tags for views
#define PVK_PASSWORD_TAG 0
#define OUTGOING_TLS_SRV_NAME 1
#define TLS_NEGOTIATION_TAG 2
#define COLUMNID_NAME @"CipherNameColumn"
#define COLUMNID_STATE @"CipherStateColumn"
@interface AccSecurityVC ()
@property Account* privateAccount;
@property NSTreeController *treeController;
@property (unsafe_unretained) IBOutlet NSOutlineView *cipherListView;
@property (unsafe_unretained) IBOutlet NSButton *useTLS;
@property (unsafe_unretained) IBOutlet NSView *tlsContainer;
@property (unsafe_unretained) IBOutlet NSSecureTextField *pvkPasswordField;
@property (unsafe_unretained) IBOutlet NSTextField *outgoingTlsServerName;
@property (unsafe_unretained) IBOutlet NSTextField *tlsNegotiationTimeout;
@property (unsafe_unretained) IBOutlet NSStepper *tlsNegotiationTimeoutStepper;
@property CertificateWC* certificateWC;
@property (unsafe_unretained) IBOutlet NSPathControl *caListPathControl;
@property (unsafe_unretained) IBOutlet NSPathControl *certificatePathControl;
@property (unsafe_unretained) IBOutlet NSPathControl *pvkPathControl;
@property (unsafe_unretained) IBOutlet NSPopUpButton *tlsMethodList;
@property (unsafe_unretained) IBOutlet NSButton *srtpRTPFallback;
@property (unsafe_unretained) IBOutlet NSButton *useSRTP;
@property (unsafe_unretained) IBOutlet NSButton *verifyCertAsClientButton;
@property (unsafe_unretained) IBOutlet NSButton *verifyCertAsServerButton;
@property (unsafe_unretained) IBOutlet NSButton *requireCertButton;
@end
@implementation AccSecurityVC
@synthesize privateAccount;
@synthesize treeController;
@synthesize cipherListView;
@synthesize certificateWC;
@synthesize tlsContainer;
@synthesize useTLS;
@synthesize useSRTP;
@synthesize srtpRTPFallback;
@synthesize pvkPasswordField;
@synthesize tlsNegotiationTimeout;
@synthesize tlsNegotiationTimeoutStepper;
@synthesize outgoingTlsServerName;
@synthesize caListPathControl;
@synthesize certificatePathControl;
@synthesize pvkPathControl;
@synthesize verifyCertAsClientButton;
@synthesize verifyCertAsServerButton;
@synthesize requireCertButton;
- (void)awakeFromNib
{
NSLog(@"INIT Security VC");
[pvkPasswordField setTag:PVK_PASSWORD_TAG];
[outgoingTlsServerName setTag:OUTGOING_TLS_SRV_NAME];
[tlsNegotiationTimeoutStepper setTag:TLS_NEGOTIATION_TAG];
[tlsNegotiationTimeout setTag:TLS_NEGOTIATION_TAG];
}
- (void)loadAccount:(Account *)account
{
privateAccount = account;
[self updateControlsWithTag:PVK_PASSWORD_TAG];
[self updateControlsWithTag:OUTGOING_TLS_SRV_NAME];
[self updateControlsWithTag:TLS_NEGOTIATION_TAG];
QModelIndex qTlsMethodIdx = privateAccount->tlsMethodModel()->selectionModel()->currentIndex();
[self.tlsMethodList removeAllItems];
[self.tlsMethodList addItemWithTitle:qTlsMethodIdx.data(Qt::DisplayRole).toString().toNSString()];
treeController = [[QNSTreeController alloc] initWithQModel:privateAccount->cipherModel()];
[treeController setAvoidsEmptySelection:NO];
[treeController setAlwaysUsesMultipleValuesMarker:YES];
[treeController setChildrenKeyPath:@"children"];
[cipherListView bind:@"content" toObject:treeController withKeyPath:@"arrangedObjects" options:nil];
[cipherListView bind:@"sortDescriptors" toObject:treeController withKeyPath:@"sortDescriptors" options:nil];
[cipherListView bind:@"selectionIndexPaths" toObject:treeController withKeyPath:@"selectionIndexPaths" options:nil];
[useTLS setState:privateAccount->isTlsEnabled()];
[tlsContainer setHidden:!privateAccount->isTlsEnabled()];
[useSRTP setState:privateAccount->isSrtpEnabled()];
[srtpRTPFallback setState:privateAccount->isSrtpRtpFallback()];
[srtpRTPFallback setEnabled:useSRTP.state];
NSArray * pathComponentArray = [self pathComponentArray];
if(privateAccount->tlsCaListCertificate() != nil) {
NSLog(@"CA ==> %@", privateAccount->tlsCaListCertificate()->path().toNSURL());
[caListPathControl setURL:privateAccount->tlsCaListCertificate()->path().toNSURL()];
} else {
[caListPathControl setURL:nil];
}
if(privateAccount->tlsCertificate() != nil) {
NSLog(@" CERT ==> %@", privateAccount->tlsCertificate()->path().toNSURL());
[certificatePathControl setURL:privateAccount->tlsCertificate()->path().toNSURL()];
} else {
[certificatePathControl setURL:nil];
}
if(privateAccount->tlsPrivateKeyCertificate() != nil) {
NSLog(@" PVK ==> %@", privateAccount->tlsPrivateKeyCertificate()->path().toNSURL());
[pvkPathControl setURL:privateAccount->tlsPrivateKeyCertificate()->path().toNSURL()];
} else {
[pvkPathControl setURL:nil];
}
[verifyCertAsServerButton setState:privateAccount->isTlsVerifyServer()];
[verifyCertAsClientButton setState:privateAccount->isTlsVerifyClient()];
[requireCertButton setState:privateAccount->isTlsRequireClientCertificate()];
}
/*
Assemble a set of custom cells to display into an array to pass to the path control.
*/
- (NSArray *)pathComponentArray
{
NSMutableArray *pathComponentArray = [[NSMutableArray alloc] init];
NSFileManager *fileManager = [[NSFileManager alloc] init];
NSURL* desktopURL = [fileManager URLForDirectory:NSDesktopDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
NSURL* documentsURL = [fileManager URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
NSURL* userURL = [fileManager URLForDirectory:NSUserDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
NSPathComponentCell *componentCell;
// Use utility method to obtain a NSPathComponentCell based on icon, title and URL.
componentCell = [self componentCellForType:kGenericFolderIcon withTitle:@"Desktop" URL:desktopURL];
[pathComponentArray addObject:componentCell];
componentCell = [self componentCellForType:kGenericFolderIcon withTitle:@"Documents" URL:documentsURL];
[pathComponentArray addObject:componentCell];
componentCell = [self componentCellForType:kUserFolderIcon withTitle:NSUserName() URL:userURL];
[pathComponentArray addObject:componentCell];
return pathComponentArray;
}
/*
This method is used by pathComponentArray to create a NSPathComponent cell based on icon, title and URL information.
Each path component needs an icon, URL and title.
*/
- (NSPathComponentCell *)componentCellForType:(OSType)withIconType withTitle:(NSString *)title URL:(NSURL *)url
{
NSPathComponentCell *componentCell = [[NSPathComponentCell alloc] init];
NSImage *iconImage = [[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(withIconType)];
[componentCell setImage:iconImage];
[componentCell setURL:url];
[componentCell setTitle:title];
return componentCell;
}
- (IBAction)chooseTlsMethod:(id)sender {
int index = [sender indexOfSelectedItem];
QModelIndex qIdx = privateAccount->tlsMethodModel()->index(index, 0);
privateAccount->tlsMethodModel()->selectionModel()->setCurrentIndex(qIdx, QItemSelectionModel::ClearAndSelect);
}
- (IBAction)toggleUseTLS:(id)sender {
privateAccount->setTlsEnabled([sender state]);
[tlsContainer setHidden:![sender state]];
}
- (IBAction)toggleUseSRTP:(id)sender {
privateAccount->setSrtpEnabled([sender state]);
[srtpRTPFallback setEnabled:[sender state]];
}
- (IBAction)toggleRTPFallback:(id)sender {
privateAccount->setSrtpRtpFallback([sender state]);
}
- (IBAction)toggleVerifyCertAsClient:(id)sender {
privateAccount->setTlsVerifyClient([sender state]);
}
- (IBAction)toggleVerifyCertServer:(id)sender {
privateAccount->setTlsVerifyServer([sender state]);
}
- (IBAction)toggleRequireCert:(id)sender {
privateAccount->setTlsRequireClientCertificate([sender state]);
}
- (IBAction)toggleCipher:(id)sender {
NSInteger row = [sender clickedRow];
NSTableColumn *col = [sender tableColumnWithIdentifier:COLUMNID_STATE];
NSButtonCell *cell = [col dataCellForRow:row];
privateAccount->cipherModel()->setData(privateAccount->cipherModel()->index(row, 0, QModelIndex()),
cell.state == NSOnState ? Qt::Unchecked : Qt::Checked, Qt::CheckStateRole);
}
- (void) updateControlsWithTag:(NSInteger) tag
{
switch (tag) {
case PVK_PASSWORD_TAG:
[pvkPasswordField setStringValue:privateAccount->tlsPassword().toNSString()];
break;
case OUTGOING_TLS_SRV_NAME:
[outgoingTlsServerName setStringValue:privateAccount->tlsServerName().toNSString()];
break;
case TLS_NEGOTIATION_TAG:
[tlsNegotiationTimeout setIntegerValue:privateAccount->tlsNegotiationTimeoutSec()];
[tlsNegotiationTimeoutStepper setIntegerValue:privateAccount->tlsNegotiationTimeoutSec()];
break;
default:
break;
}
}
#pragma mark - NSTextFieldDelegate methods
-(void)controlTextDidChange:(NSNotification *)notif
{
NSTextField *textField = [notif object];
NSRange test = [[textField currentEditor] selectedRange];
[self valueDidChange:textField];
//FIXME: saving account lose focus because in NSTreeController we remove and reinsert row so View selction change
[textField.window makeFirstResponder:textField];
[[textField currentEditor] setSelectedRange:test];
}
- (IBAction) valueDidChange: (id) sender
{
switch ([sender tag]) {
case PVK_PASSWORD_TAG:
privateAccount->setTlsPassword([[sender stringValue] UTF8String]);
break;
case OUTGOING_TLS_SRV_NAME:
privateAccount->setTlsServerName([[sender stringValue] UTF8String]);
break;
case TLS_NEGOTIATION_TAG:
privateAccount->setTlsNegotiationTimeoutSec([sender integerValue]);
break;
default:
break;
}
[self updateControlsWithTag:[sender tag]];
}
#pragma mark - NSPathControl delegate methods
- (IBAction)caListPathControlSingleClick:(id)sender {
NSURL* fileURL = [[sender clickedPathComponentCell] URL];
NSLog(@"==> %@", fileURL);
[self.caListPathControl setURL:fileURL];
privateAccount->setTlsCaListCertificate(QUrl::fromNSURL(fileURL).toString());
}
- (IBAction)certificatePathControlSingleClick:(id)sender {
// Select that chosen component of the path.
NSURL* fileURL = [[sender clickedPathComponentCell] URL];
NSLog(@"==> %@", fileURL);
[self.certificatePathControl setURL:fileURL];
privateAccount->setTlsCertificate(QUrl::fromNSURL(fileURL).toString());
}
- (IBAction)pvkFilePathControlSingleClick:(id)sender {
NSURL* fileURL = [[sender clickedPathComponentCell] URL];
NSLog(@"==> %@", fileURL);
[self.pvkPathControl setURL:fileURL];
privateAccount->setTlsPrivateKeyCertificate(QUrl::fromNSURL(fileURL).toString());
// qDebug() << "TEST" << privateAccount->tlsPrivateKeyCertificate()->hasPrivateKey();
}
- (IBAction)showCA:(id)sender
{
certificateWC = [[CertificateWC alloc] initWithWindowNibName:@"CertificateWindow"];
[certificateWC setCertificate:privateAccount->tlsCaListCertificate()];
[self.view.window beginSheet:certificateWC.window completionHandler:nil];
}
- (IBAction)showEndpointCertificate:(id)sender
{
certificateWC = [[CertificateWC alloc] initWithWindowNibName:@"CertificateWindow"];
[certificateWC setCertificate:privateAccount->tlsCertificate()];
[self.view.window beginSheet:certificateWC.window completionHandler:nil];}
/*
Delegate method of NSPathControl to determine how the NSOpenPanel will look/behave.
*/
- (void)pathControl:(NSPathControl *)pathControl willDisplayOpenPanel:(NSOpenPanel *)openPanel
{
NSLog(@"willDisplayOpenPanel");
[openPanel setAllowsMultipleSelection:NO];
[openPanel setCanChooseDirectories:NO];
[openPanel setCanChooseFiles:YES];
[openPanel setResolvesAliases:YES];
if(pathControl == self.caListPathControl) {
[openPanel setTitle:NSLocalizedString(@"Choose a CA list", @"Open panel title")];
} else if (pathControl == self.certificatePathControl) {
[openPanel setTitle:NSLocalizedString(@"Choose a certificate", @"Open panel title")];
} else {
[openPanel setTitle:NSLocalizedString(@"Choose a private key file", @"Open panel title")];
}
[openPanel setPrompt:NSLocalizedString(@"Choose", @"Open panel prompt for 'Choose a file'")];
[openPanel setDelegate:self];
}
- (void)pathControl:(NSPathControl *)pathControl willPopUpMenu:(NSMenu *)menu
{
}
#pragma mark - NSOpenSavePanelDelegate delegate methods
- (void)panel:(id)sender willExpand:(BOOL)expanding
{
//NSLog(@"willExpand");
}
- (NSString *)panel:(id)sender userEnteredFilename:(NSString *)filename confirmed:(BOOL)okFlag
{
//NSLog(@"userEnteredFilename");
}
- (void)panelSelectionDidChange:(id)sender
{
//NSLog(@"panelSelectionDidChange");
}
- (BOOL)panel:(id)sender validateURL:(NSURL *)url error:(NSError **)outError
{
NSLog(@"validateURL");
return YES;
}
#pragma mark - NSMenuDelegate methods
- (BOOL)menu:(NSMenu *)menu updateItem:(NSMenuItem *)item atIndex:(NSInteger)index shouldCancel:(BOOL)shouldCancel
{
QModelIndex qIdx;
if([menu.title isEqualToString:@"tlsmethodlist"])
{
qIdx = privateAccount->tlsMethodModel()->index(index);
[item setTitle:qIdx.data(Qt::DisplayRole).toString().toNSString()];
}
return YES;
}
- (NSInteger)numberOfItemsInMenu:(NSMenu *)menu
{
if([menu.title isEqualToString:@"tlsmethodlist"])
return privateAccount->tlsMethodModel()->rowCount();
}
#pragma mark - NSOutlineViewDelegate methods
// -------------------------------------------------------------------------------
// shouldSelectItem:item
// -------------------------------------------------------------------------------
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item;
{
return YES;
}
// -------------------------------------------------------------------------------
// dataCellForTableColumn:tableColumn:item
// -------------------------------------------------------------------------------
- (NSCell *)outlineView:(NSOutlineView *)outlineView dataCellForTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
NSCell *returnCell = [tableColumn dataCell];
return returnCell;
}
// -------------------------------------------------------------------------------
// textShouldEndEditing:fieldEditor
// -------------------------------------------------------------------------------
- (BOOL)control:(NSControl *)control textShouldEndEditing:(NSText *)fieldEditor
{
if ([[fieldEditor string] length] == 0)
{
// don't allow empty node names
return NO;
}
else
{
return YES;
}
}
// -------------------------------------------------------------------------------
// shouldEditTableColumn:tableColumn:item
//
// Decide to allow the edit of the given outline view "item".
// -------------------------------------------------------------------------------
- (BOOL)outlineView:(NSOutlineView *)outlineView shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
return NO;
}
// -------------------------------------------------------------------------------
// outlineView:willDisplayCell:forTableColumn:item
// -------------------------------------------------------------------------------
- (void)outlineView:(NSOutlineView *)olv willDisplayCell:(NSCell*)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
QModelIndex qIdx = [treeController toQIdx:((NSTreeNode*)item)];
if(!qIdx.isValid())
return;
if ([[tableColumn identifier] isEqualToString:COLUMNID_NAME])
{
cell.title = qIdx.data(Qt::DisplayRole).toString().toNSString();
}
}
// -------------------------------------------------------------------------------
// outlineViewSelectionDidChange:notification
// -------------------------------------------------------------------------------
- (void)outlineViewSelectionDidChange:(NSNotification *)notification
{
// ask the tree controller for the current selection
if([[treeController selectedNodes] count] > 0) {
}
}
@end