1// 2// KBApp.m 3// Keybase 4// 5// Created by Gabriel on 6/10/15. 6// Copyright (c) 2015 Keybase. All rights reserved. 7// 8 9#import "KBApp.h" 10 11#import "KBAppView.h" 12#import "KBPreferences.h" 13#import "KBControlPanel.h" 14#import "KBConsoleView.h" 15#import "KBWorkspace.h" 16#import "KBLogFormatter.h" 17#import "KBEnvSelectView.h" 18#import "KBUninstaller.h" 19 20#import "KBStyleGuideView.h" 21 22#import "KBPGPEncryptView.h" 23#import "KBPGPEncryptFilesView.h" 24#import "KBPGPDecryptView.h" 25#import "KBPGPDecryptFileView.h" 26#import "KBPGPSignView.h" 27#import "KBPGPSignFileView.h" 28#import "KBPGPSignFilesView.h" 29#import "KBPGPVerifyView.h" 30#import "KBPGPVerifyFileView.h" 31#import "KBWorkspace.h" 32#import "KBPGPEncryptActionView.h" 33#import "KBPGPEncrypt.h" 34 35#import <AFNetworking/AFNetworking.h> 36 37@interface KBApp () 38@property KBAppView *appView; 39@property KBPreferences *preferences; 40@property BOOL alerting; 41 42// Debug 43@property KBControlPanel *controlPanel; 44@property KBConsoleView *consoleView; 45@end 46 47@implementation KBApp 48 49+ (instancetype)app { 50 id<KBAppDelegate> delegate = [NSApp delegate]; 51 return [delegate app]; 52} 53 54+ (KBEnvironment *)environment { 55 return [self.app appView].environment; 56} 57 58- (void)open { 59 [self setup]; 60} 61 62- (void)setup { 63 _preferences = [[KBPreferences alloc] init]; 64 65 _consoleView = [[KBConsoleView alloc] init]; 66 67 _controlPanel = [[KBControlPanel alloc] init]; 68 [_controlPanel addComponents:@[_consoleView]]; 69 70 DDLogLevel logLevel = [[_preferences valueForIdentifier:@"Preferences.Log.Level"] unsignedIntegerValue]; 71 [DDLog addLogger:DDASLLogger.sharedInstance withLevel:logLevel]; 72 [DDLog addLogger:_consoleView withLevel:DDLogLevelVerbose]; 73 74 [KBAppearance setCurrentAppearance:KBAppearance.lightAppearance]; 75 76 // Network reachability is a diagnostic tool that can be used to understand why a request might have failed. 77 // It should not be used to determine whether or not to make a request. 78 [AFNetworkReachabilityManager.sharedManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) { 79 DDLogInfo(@"Reachability: %@", AFStringFromNetworkReachabilityStatus(status)); 80 }]; 81 [AFNetworkReachabilityManager.sharedManager startMonitoring]; 82 83 // Cleanup old stuff 84 //[KBUninstaller uninstall:@"keybase" completion:^(NSError *error) {}]; 85 86 // Save installed version in case a later upgrade needs this info 87 NSString *version = NSBundle.mainBundle.infoDictionary[@"CFBundleShortVersionString"]; 88 NSUserDefaults *userDefaults = [KBWorkspace userDefaults]; 89 [userDefaults setObject:version forKey:@"InstallVersion"]; 90 [userDefaults synchronize]; 91} 92 93- (void)openWithEnvironment:(KBEnvironment *)environment { 94 _appView = [[KBAppView alloc] init]; 95 [_appView openWindow]; 96 97 NSMutableArray *componentsForControlPanel = [environment.componentsForControlPanel mutableCopy]; 98// [componentsForControlPanel addObject:_appView]; 99// [componentsForControlPanel addObject:[[KBStyleGuideView alloc] init]]; 100 [_controlPanel addComponents:componentsForControlPanel]; 101 102 [_appView openWithEnvironment:environment completion:^(NSError *error) {}]; 103} 104 105- (void)openControlPanel { 106 [_controlPanel open:_appView]; 107} 108 109- (void)_test { 110 KBRTestRequest *request = [[KBRTestRequest alloc] initWithClient:self.service.client]; 111 [self.service.client registerMethod:@"keybase.1.test.testCallback" sessionId:request.sessionId requestHandler:^(NSNumber *messageId, NSString *method, NSArray *params, MPRequestCompletion completion) { 112 completion(nil, @"the reply"); 113 }]; 114 [request testWithName:@"testing" completion:^(NSError *error, KBRTest *test) { 115 // Testing 116 }]; 117} 118 119- (NSWindow *)mainWindow { 120 return _appView.window; 121} 122 123- (KBService *)service { 124 return _appView.environment.service; 125} 126 127- (NSString *)currentUsername { 128 return self.appView.userStatus.user.username; 129} 130 131- (NSString *)APIURLString:(NSString *)path { 132 return [[self appView] APIURLString:path]; 133} 134 135- (void)quitWithPrompt:(BOOL)prompt sender:(id)sender { 136 if (prompt) { 137 [KBAlert yesNoWithTitle:@"Quit" description:@"Are you sure you want to quit?" yes:@"Quit" view:_appView completion:^(BOOL yes) { 138 if (yes) [NSApplication.sharedApplication terminate:sender]; 139 }]; 140 } else { 141 [NSApplication.sharedApplication terminate:sender]; 142 } 143} 144 145- (void)closeAllWindows { 146 [_appView.window close]; 147 [_preferences close]; 148} 149 150#pragma mark Error Handling 151 152- (BOOL)setError:(NSError *)error sender:(id)sender completion:(void (^)(NSModalResponse response))completion { 153 if (!error || KBIsErrorName(error, @"CANCELED")) { 154 // Canceled, ok to ignore 155 if (completion) completion(KBErrorResponseIgnored); 156 return NO; 157 } 158 159 if (KBIsErrorName(error, @"LOGIN_REQUIRED")) { 160 [self.appView showInProgress:@"Loading"]; 161 [self.appView checkStatus]; 162 return YES; 163 } 164 165 DDLogError(@"%@", error); 166 167 if (_alerting) { 168 DDLogDebug(@"Already showing error (%@)", error); 169 if (completion) completion(KBErrorResponseIgnored); 170 return NO; 171 } 172 173 NSWindow *window = nil; 174 if ([sender isKindOfClass:NSWindow.class]) window = sender; 175 if (!window && [sender respondsToSelector:@selector(window)]) window = [sender window]; 176 177 if (!window) window = [NSApp mainWindow]; 178 if (!window) window = [NSApp keyWindow]; 179 if (!window) window = [[NSApp windows] firstObject]; 180 181 NSAssert(window, @"No window to show alert"); 182 183 _alerting = YES; 184 GHWeakSelf gself = self; 185 [[NSAlert alertWithError:error] beginSheetModalForWindow:window completionHandler:^(NSModalResponse returnCode) { 186 gself.alerting = NO; 187 if (completion) completion(returnCode); 188 }]; 189 return YES; 190} 191 192#pragma mark Menu Actions 193 194- (IBAction)encrypt:(id)sender { 195 KBPGPEncryptView *view = [[KBPGPEncryptView alloc] init]; 196 view.client = self.service.client; 197 [self.mainWindow kb_addChildWindowForView:view rect:CGRectMake(0, 0, 510, 400) position:KBWindowPositionCenter title:@"Encrypt" fixed:NO makeKey:YES]; 198} 199 200- (IBAction)encryptFile:(id)sender { 201 KBPGPEncryptFilesView *view = [[KBPGPEncryptFilesView alloc] init]; 202 view.client = self.service.client; 203 [self.mainWindow kb_addChildWindowForView:view rect:CGRectMake(0, 0, 510, 400) position:KBWindowPositionCenter title:@"Encrypt Files" fixed:NO makeKey:YES]; 204} 205 206- (IBAction)decrypt:(id)sender { 207 KBPGPDecryptView *view = [[KBPGPDecryptView alloc] init]; 208 view.client = self.service.client; 209 [self.mainWindow kb_addChildWindowForView:view rect:CGRectMake(0, 0, 510, 400) position:KBWindowPositionCenter title:@"Decrypt" fixed:NO makeKey:YES]; 210} 211 212- (IBAction)decryptFile:(id)sender { 213 KBPGPDecryptFileView *view = [[KBPGPDecryptFileView alloc] init]; 214 view.client = self.service.client; 215 [self.mainWindow kb_addChildWindowForView:view rect:CGRectMake(0, 0, 510, 400) position:KBWindowPositionCenter title:@"Decrypt Files" fixed:NO makeKey:YES]; 216} 217 218- (IBAction)sign:(id)sender { 219 KBPGPSignView *view = [[KBPGPSignView alloc] init]; 220 view.client = self.service.client; 221 [self.mainWindow kb_addChildWindowForView:view rect:CGRectMake(0, 0, 510, 400) position:KBWindowPositionCenter title:@"Sign" fixed:NO makeKey:YES]; 222} 223 224- (IBAction)signFile:(id)sender { 225 KBPGPSignFileView *view = [[KBPGPSignFileView alloc] init]; 226 view.client = self.service.client; 227 [self.mainWindow kb_addChildWindowForView:view rect:CGRectMake(0, 0, 510, 400) position:KBWindowPositionCenter title:@"Sign File" fixed:NO makeKey:YES]; 228} 229 230- (IBAction)signFiles:(id)sender { 231 KBPGPSignFilesView *view = [[KBPGPSignFilesView alloc] init]; 232 view.client = self.service.client; 233 [self.mainWindow kb_addChildWindowForView:view rect:CGRectMake(0, 0, 510, 400) position:KBWindowPositionCenter title:@"Sign Files" fixed:NO makeKey:YES]; 234} 235 236- (IBAction)verify:(id)sender { 237 KBPGPVerifyView *view = [[KBPGPVerifyView alloc] init]; 238 view.client = self.service.client; 239 [self.mainWindow kb_addChildWindowForView:view rect:CGRectMake(0, 0, 510, 400) position:KBWindowPositionCenter title:@"Verify" fixed:NO makeKey:YES]; 240} 241 242- (IBAction)verifyFile:(id)sender { 243 KBPGPVerifyFileView *view = [[KBPGPVerifyFileView alloc] init]; 244 view.client = self.service.client; 245 [self.mainWindow kb_addChildWindowForView:view rect:CGRectMake(0, 0, 510, 400) position:KBWindowPositionCenter title:@"Verify File" fixed:NO makeKey:YES]; 246} 247 248@end 249