blob: dfbf31c43dca33f0fec6f183dace42d0de82f035 [file] [log] [blame]
Alexandre Lision745e4d62015-03-22 20:03:10 -04001/*
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -04002 * Copyright (C) 2015 Savoir-faire Linux Inc.
Alexandre Lision745e4d62015-03-22 20:03:10 -04003 * Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Additional permission under GNU GPL version 3 section 7:
20 *
21 * If you modify this program, or any covered work, by linking or
22 * combining it with the OpenSSL project's OpenSSL library (or a
23 * modified version of that library), containing parts covered by the
24 * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
25 * grants you additional permission to convey the resulting work.
26 * Corresponding Source for a non-source form of such a combination
27 * shall include the source code for the parts of OpenSSL used as well
28 * as that of the covered work.
29 */
30#import "RingWizardWC.h"
31
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -040032//Qt
33#import <QUrl>
34
35//LRC
Alexandre Lision745e4d62015-03-22 20:03:10 -040036#import <accountmodel.h>
37#import <protocolmodel.h>
38#import <QItemSelectionModel>
39#import <account.h>
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -040040#import <certificate.h>
Alexandre Lision745e4d62015-03-22 20:03:10 -040041
42#import "AppDelegate.h"
43
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -040044#define PVK_PASSWORD_TAG 0
45#define NICKNAME_TAG 1
Alexandre Lision745e4d62015-03-22 20:03:10 -040046
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -040047@interface RingWizardWC () {
48
49 __unsafe_unretained IBOutlet NSButton *goToAppButton;
50 __unsafe_unretained IBOutlet NSTextField *nickname;
51 __unsafe_unretained IBOutlet NSProgressIndicator *progressBar;
52 __unsafe_unretained IBOutlet NSTextField *indicationLabel;
53 __unsafe_unretained IBOutlet NSButton *createButton;
54 __unsafe_unretained IBOutlet NSButton *showCustomCertsButton;
55 IBOutlet NSView *securityContainer;
56
57 __unsafe_unretained IBOutlet NSSecureTextField *passwordField;
58 __unsafe_unretained IBOutlet NSView *pvkContainer;
59 __unsafe_unretained IBOutlet NSPathControl *certificatePathControl;
60 __unsafe_unretained IBOutlet NSPathControl *caListPathControl;
61 __unsafe_unretained IBOutlet NSPathControl *pvkPathControl;
62 BOOL isExpanded;
63}
64
65@property Account* accountToCreate;
Alexandre Lision745e4d62015-03-22 20:03:10 -040066@end
67
68@implementation RingWizardWC
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -040069@synthesize accountToCreate;
Alexandre Lision745e4d62015-03-22 20:03:10 -040070
71- (void)windowDidLoad {
72 [super windowDidLoad];
73
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -040074 [passwordField setTag:PVK_PASSWORD_TAG];
75 [nickname setTag:NICKNAME_TAG];
76
77 isExpanded = false;
Alexandre Lision745e4d62015-03-22 20:03:10 -040078 [self.window makeKeyAndOrderFront:nil];
79 [self.window setLevel:NSStatusWindowLevel];
80 [self.window makeMainWindow];
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -040081 if(![self checkForRingAccount]) {
82 accountToCreate = AccountModel::instance()->add("", Account::Protocol::RING);
83 } else {
84 [indicationLabel setStringValue:@"Ring is already ready to work"];
85 auto accList = AccountModel::instance()->getAccountsByProtocol(Account::Protocol::RING);
86 [self displayHash:accList[0]->username().toNSString()];
87 [showCustomCertsButton setHidden:YES];
88 }
89
90 [caListPathControl setDelegate:self];
91 [certificatePathControl setDelegate:self];
92 [pvkPathControl setDelegate:self];
Alexandre Lision745e4d62015-03-22 20:03:10 -040093}
94
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -040095- (BOOL) checkForRingAccount
Alexandre Lision745e4d62015-03-22 20:03:10 -040096{
97 for (int i = 0 ; i < AccountModel::instance()->rowCount() ; ++i) {
98 QModelIndex idx = AccountModel::instance()->index(i);
99 Account* acc = AccountModel::instance()->getAccountByModelIndex(idx);
100 if(acc->protocol() == Account::Protocol::RING) {
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -0400101 return YES;
Alexandre Lision745e4d62015-03-22 20:03:10 -0400102 }
103 }
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -0400104 return false;
Alexandre Lision745e4d62015-03-22 20:03:10 -0400105}
106
107- (void) displayHash:(NSString* ) hash
108{
109 [nickname setFrameSize:NSMakeSize(400, nickname.frame.size.height)];
110 [nickname setStringValue:hash];
111 [nickname setEditable:NO];
112 [nickname setHidden:NO];
113
114 [goToAppButton setHidden:NO];
115
116 NSSharingService* emailSharingService = [NSSharingService sharingServiceNamed:NSSharingServiceNameComposeEmail];
117
118 [createButton setTitle:@"Share by mail"];
Alexandre Lision745e4d62015-03-22 20:03:10 -0400119 [createButton setAlternateImage:emailSharingService.alternateImage];
120 [createButton setAction:@selector(shareByEmail)];
121}
122
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -0400123- (IBAction)createRingAccount:(id)sender
124{
Alexandre Lision745e4d62015-03-22 20:03:10 -0400125 [nickname setHidden:YES];
126 [progressBar setHidden:NO];
127 [createButton setEnabled:NO];
128 [indicationLabel setStringValue:@"Just a moment..."];
129
130 QModelIndex qIdx = AccountModel::instance()->protocolModel()->selectionModel()->currentIndex();
131
132 [self setCallback];
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -0400133 if (isExpanded) {
134 // retract panel
135 [self chooseOwnCertificates:nil];
136 [showCustomCertsButton setHidden:YES];
137 }
Alexandre Lision745e4d62015-03-22 20:03:10 -0400138 [self performSelector:@selector(saveAccount) withObject:nil afterDelay:1];
139
Alexandre Lision41981972015-06-04 13:27:33 -0400140 [self registerAutoStartup];
141}
142
143/**
144 * Enable launch at startup by default
145 */
146- (void) registerAutoStartup
147{
148 LSSharedFileListRef loginItemsRef = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
149 if (loginItemsRef == nil) return;
Alexandre Lision81c97212015-06-17 15:51:53 -0400150 CFURLRef appUrl = (__bridge CFURLRef)[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
Alexandre Lision41981972015-06-04 13:27:33 -0400151 LSSharedFileListItemRef itemRef = LSSharedFileListInsertItemURL(loginItemsRef, kLSSharedFileListItemLast, NULL, NULL, appUrl, NULL, NULL);
152 if (itemRef) CFRelease(itemRef);
Alexandre Lision745e4d62015-03-22 20:03:10 -0400153}
154
155- (void) saveAccount
156{
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -0400157 accountToCreate->setUpnpEnabled(YES); // Always active upnp
158 accountToCreate << Account::EditAction::SAVE;
Alexandre Lision745e4d62015-03-22 20:03:10 -0400159}
160
161- (void) setCallback
162{
163 QObject::connect(AccountModel::instance(),
164 &AccountModel::accountStateChanged,
165 [=](Account *account, const Account::RegistrationState state) {
166 NSLog(@"Account created!");
167 [progressBar setHidden:YES];
168 [createButton setEnabled:YES];
169 [indicationLabel setStringValue:@"This is your number, share it with your friends!"];
170 [self displayHash:account->username().toNSString()];
171 });
172}
173
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -0400174- (IBAction)chooseOwnCertificates:(NSButton*)sender
175{
176 if (isExpanded) {
177 [securityContainer removeFromSuperview];
178 NSRect frame = [self.window frame];
179 frame.size = CGSizeMake(securityContainer.frame.size.width, frame.size.height - securityContainer.frame.size.height);
180 frame.origin.y = frame.origin.y + securityContainer.frame.size.height;
181 [self.window setFrame:frame display:YES animate:YES];
182 isExpanded = false;
183 [sender setImage:[NSImage imageNamed:@"NSAddTemplate"]];
184 } else {
185 NSRect frame = [self.window frame];
186 frame.size = CGSizeMake(securityContainer.frame.size.width, frame.size.height + securityContainer.frame.size.height);
187 frame.origin.y = frame.origin.y - securityContainer.frame.size.height;
188 [self.window setFrame:frame display:YES animate:YES];
189
190 [securityContainer setFrameOrigin:CGPointMake(0, 50)];
191 [self.window.contentView addSubview:securityContainer];
192 isExpanded = true;
193 [sender setImage:[NSImage imageNamed:@"NSRemoveTemplate"]];
194 }
195}
196
197- (IBAction)goToApp:(id)sender
198{
Alexandre Lision745e4d62015-03-22 20:03:10 -0400199 [self.window close];
200 AppDelegate *appDelegate = (AppDelegate *)[[NSApplication sharedApplication] delegate];
201 [appDelegate showMainWindow];
202}
203
204- (void) shareByEmail
205{
Alexandre Lision745e4d62015-03-22 20:03:10 -0400206 NSMutableArray *shareItems = [[NSMutableArray alloc] initWithObjects:[nickname stringValue], nil];
207 NSSharingService* emailSharingService = [NSSharingService sharingServiceNamed:NSSharingServiceNameComposeEmail];
Alexandre Lision745e4d62015-03-22 20:03:10 -0400208 [emailSharingService performWithItems:shareItems];
209}
210
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -0400211#pragma mark - NSPathControl delegate methods
Alexandre Lision745e4d62015-03-22 20:03:10 -0400212
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -0400213- (IBAction)caListPathControlSingleClick:(id)sender
Alexandre Lision745e4d62015-03-22 20:03:10 -0400214{
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -0400215 NSURL* fileURL;
216 if ([sender isKindOfClass:[NSMenuItem class]]) {
217 fileURL = nil;
218 } else {
219 fileURL = [[sender clickedPathComponentCell] URL];
220 }
221 [self->caListPathControl setURL:fileURL];
222 accountToCreate->setTlsCaListCertificate([[fileURL path] UTF8String]);
223
224}
225
226- (IBAction)certificatePathControlSingleClick:(id)sender
227{
228 NSURL* fileURL;
229 if ([sender isKindOfClass:[NSMenuItem class]]) {
230 fileURL = nil;
231 } else {
232 fileURL = [[sender clickedPathComponentCell] URL];
233 }
234 [self->certificatePathControl setURL:fileURL];
235 accountToCreate->setTlsCertificate([[fileURL path] UTF8String]);
236
237 auto cert = accountToCreate->tlsCertificate();
238
239 if (cert) {
240 [pvkContainer setHidden:!cert->requirePrivateKey()];
241 } else {
242 [pvkContainer setHidden:YES];
243 }
244
245}
246
247- (IBAction)pvkFilePathControlSingleClick:(id)sender
248{
249 NSURL* fileURL;
250 if ([sender isKindOfClass:[NSMenuItem class]]) {
251 fileURL = nil;
252 } else {
253 fileURL = [[sender clickedPathComponentCell] URL];
254 }
255 [self->pvkPathControl setURL:fileURL];
256 accountToCreate->setTlsPrivateKey([[fileURL path] UTF8String]);
257
258 if(accountToCreate->tlsCertificate()->requirePrivateKeyPassword()) {
259 [passwordField setHidden:NO];
260 } else {
261 [passwordField setHidden:YES];
262 }
263}
264
265/*
266 Delegate method of NSPathControl to determine how the NSOpenPanel will look/behave.
267 */
268- (void)pathControl:(NSPathControl *)pathControl willDisplayOpenPanel:(NSOpenPanel *)openPanel
269{
270 NSLog(@"willDisplayOpenPanel");
271 [openPanel setAllowsMultipleSelection:NO];
272 [openPanel setCanChooseDirectories:NO];
273 [openPanel setCanChooseFiles:YES];
274 [openPanel setResolvesAliases:YES];
275
276 if(pathControl == caListPathControl) {
277 [openPanel setTitle:NSLocalizedString(@"Choose a CA list", @"Open panel title")];
278 } else if (pathControl == certificatePathControl) {
279 [openPanel setTitle:NSLocalizedString(@"Choose a certificate", @"Open panel title")];
280 } else {
281 [openPanel setTitle:NSLocalizedString(@"Choose a private key file", @"Open panel title")];
282 }
283
284 [openPanel setPrompt:NSLocalizedString(@"Choose", @"Open panel prompt for 'Choose a file'")];
285 [openPanel setDelegate:self];
286}
287
288- (void)pathControl:(NSPathControl *)pathControl willPopUpMenu:(NSMenu *)menu
289{
290 NSMenuItem *item;
291 if(pathControl == caListPathControl) {
292 item = [menu addItemWithTitle:@"Remove value" action:@selector(caListPathControlSingleClick:) keyEquivalent:@""];
293 } else if (pathControl == certificatePathControl) {
294 item = [menu addItemWithTitle:@"Remove value" action:@selector(certificatePathControlSingleClick:) keyEquivalent:@""];
295 } else {
296 item = [menu addItemWithTitle:@"Remove value" action:@selector(pvkFilePathControlSingleClick:) keyEquivalent:@""];
297 }
298 [item setTarget:self]; // or whatever target you want
299}
300
301#pragma mark - NSOpenSavePanelDelegate delegate methods
302
303- (BOOL)panel:(id)sender validateURL:(NSURL *)url error:(NSError **)outError
304{
Alexandre Lision745e4d62015-03-22 20:03:10 -0400305 return YES;
306}
307
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -0400308#pragma mark - NSTextFieldDelegate methods
309
310-(void)controlTextDidChange:(NSNotification *)notif
Alexandre Lision745e4d62015-03-22 20:03:10 -0400311{
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -0400312 NSTextField *textField = [notif object];
313 if (textField.tag == PVK_PASSWORD_TAG) {
314 accountToCreate->setTlsPassword([textField.stringValue UTF8String]);
315 return;
316 }
317
318 // else it is NICKNAME_TAG field
319 if ([textField.stringValue isEqualToString:@""]) {
320 [createButton setEnabled:NO];
321 } else {
322 [createButton setEnabled:YES];
323 }
324
325 accountToCreate->setAlias([textField.stringValue UTF8String]);
326 accountToCreate->setDisplayName([textField.stringValue UTF8String]);
Alexandre Lision745e4d62015-03-22 20:03:10 -0400327}
328
Alexandre Lisionb3f7ed62015-08-17 11:53:13 -0400329# pragma NSWindowDelegate methods
Alexandre Lision745e4d62015-03-22 20:03:10 -0400330
331- (void)windowWillClose:(NSNotification *)notification
332{
Alexandre Lision745e4d62015-03-22 20:03:10 -0400333 AppDelegate *appDelegate = (AppDelegate *)[[NSApplication sharedApplication] delegate];
334 [appDelegate showMainWindow];
335}
336
337@end