session-ios/Signal/src/AppDelegate.m

315 lines
13 KiB
Mathematica
Raw Normal View History

2014-05-06 19:41:08 +02:00
#import "AppDelegate.h"
#import "AppStoreRating.h"
2014-05-06 19:41:08 +02:00
#import "CategorizingLogger.h"
#import "ContactsManager.h"
#import "DebugLogger.h"
2014-08-02 01:24:26 +02:00
#import "Environment.h"
#import "PreferencesUtil.h"
#import "PushManager.h"
2014-05-06 19:41:08 +02:00
#import "Release.h"
#import "TSAccountManager.h"
2015-01-28 02:13:13 +01:00
#import "TSPreKeyManager.h"
#import "TSMessagesManager.h"
#import "TSSocketManager.h"
2014-08-02 01:24:26 +02:00
#import "VersionMigrations.h"
2014-11-25 23:52:53 +01:00
#import "CodeVerificationViewController.h"
static NSString * const kStoryboardName = @"Storyboard";
static NSString * const kInitialViewControllerIdentifier = @"UserInitialViewController";
static NSString * const kURLSchemeSGNLKey = @"sgnl";
static NSString * const kURLHostVerifyPrefix = @"verify";
2014-05-06 19:41:08 +02:00
@interface AppDelegate ()
@property (nonatomic, retain) UIWindow *blankWindow;
2014-05-06 19:41:08 +02:00
@end
@implementation AppDelegate
2014-05-06 19:41:08 +02:00
#pragma mark Detect updates - perform migrations
+ (void)initialize{
[AppStoreRating setupRatingLibrary];
}
iOS 9 Support - Fixing size classes rendering bugs. - Supporting native iOS San Francisco font. - Quick Reply - Settings now slide to the left as suggested in original designed opposed to modal. - Simplification of restraints on many screens. - Full-API compatiblity with iOS 9 and iOS 8 legacy support. - Customized AddressBook Permission prompt when restrictions are enabled. If user installed Signal previously and already approved access to Contacts, don't bugg him again. - Fixes crash in migration for users who installed Signal <2.1.3 but hadn't signed up yet. - Xcode 7 / iOS 9 Travis Support - Bitcode Support is disabled until it is better understood how exactly optimizations are performed. In a first time, we will split out the crypto code into a separate binary to make it easier to optimize the non-sensitive code. Blog post with more details coming. - Partial ATS support. We are running our own Certificate Authority at Open Whisper Systems. Signal is doing certificate pinning to verify that certificates were signed by our own CA. Unfortunately Apple's App Transport Security requires to hand over chain verification to their framework with no control over the trust store. We have filed a radar to get ATS features with pinned certificates. In the meanwhile, ATS is disabled on our domain. We also followed Amazon's recommendations for our S3 domain we use to upload/download attachments. (#891) - Implement a unified `AFSecurityOWSPolicy` pinning strategy accross libraries (AFNetworking RedPhone/TextSecure & SocketRocket).
2015-09-01 19:22:08 +02:00
- (void)applicationWillEnterForeground:(UIApplication *)application {
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
}
2014-05-06 19:41:08 +02:00
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self setupAppearance];
[[PushManager sharedManager] registerPushKitNotificationFuture];
if (getenv("runningTests_dontStartApp")) {
return YES;
}
CategorizingLogger* logger = [CategorizingLogger categorizingLogger];
[logger addLoggingCallback:^(NSString *category, id details, NSUInteger index) {}];
[Environment setCurrent:[Release releaseEnvironmentWithLogging:logger]];
if ([TSAccountManager isRegistered]) {
[Environment.getCurrent.contactsManager doAfterEnvironmentInitSetup];
}
[Environment.getCurrent initCallListener];
[[TSStorageManager sharedManager] setupDatabase];
BOOL loggingIsEnabled;
#ifdef DEBUG
// Specified at Product -> Scheme -> Edit Scheme -> Test -> Arguments -> Environment to avoid things like
// the phone directory being looked up during tests.
loggingIsEnabled = TRUE;
[DebugLogger.sharedInstance enableTTYLogging];
#elif RELEASE
loggingIsEnabled = Environment.preferences.loggingIsEnabled;
#endif
[self verifyBackgroundBeforeKeysAvailableLaunch];
if (loggingIsEnabled) {
[DebugLogger.sharedInstance enableFileLogging];
}
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:kStoryboardName bundle:[NSBundle mainBundle]];
UIViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:kInitialViewControllerIdentifier];
2014-05-06 19:41:08 +02:00
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.rootViewController = viewController;
2014-08-02 01:24:26 +02:00
[self.window makeKeyAndVisible];
2015-04-25 16:59:32 +02:00
[VersionMigrations performUpdateCheck]; // this call must be made after environment has been initialized because in general upgrade may depend on environment
2015-01-31 03:50:48 +01:00
2014-05-06 19:41:08 +02:00
//Accept push notification when app is not open
NSDictionary *remoteNotif = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
2014-05-06 19:41:08 +02:00
if (remoteNotif) {
2014-07-20 00:25:22 +02:00
DDLogInfo(@"Application was launched by tapping a push notification.");
[self application:application didReceiveRemoteNotification:remoteNotif ];
2014-05-06 19:41:08 +02:00
}
2014-08-02 01:24:26 +02:00
[self prepareScreenshotProtection];
2015-01-28 02:13:13 +01:00
if ([TSAccountManager isRegistered]) {
if (application.applicationState == UIApplicationStateInactive) {
[TSSocketManager becomeActiveFromForeground];
} else if (application.applicationState == UIApplicationStateBackground) {
[TSSocketManager becomeActiveFromBackgroundExpectMessage:NO];
} else {
DDLogWarn(@"The app was launched in an unknown way");
}
2015-04-07 17:22:57 +02:00
[[PushManager sharedManager] validateUserNotificationSettings];
2015-01-28 02:13:13 +01:00
[TSPreKeyManager refreshPreKeys];
}
2015-03-21 19:33:58 +01:00
2014-05-06 19:41:08 +02:00
return YES;
}
- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken {
2014-10-06 10:05:55 +02:00
[PushManager.sharedManager.pushNotificationFutureSource trySetResult:deviceToken];
2014-05-06 19:41:08 +02:00
}
2014-05-06 19:41:08 +02:00
- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error {
#ifdef DEBUG
DDLogWarn(@"We're in debug mode, and registered a fake push identifier");
[PushManager.sharedManager.pushNotificationFutureSource trySetResult:[@"aFakePushIdentifier" dataUsingEncoding:NSUTF8StringEncoding]];
#else
2014-10-06 10:05:55 +02:00
[PushManager.sharedManager.pushNotificationFutureSource trySetFailure:error];
#endif
}
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings{
2014-10-06 10:05:55 +02:00
[PushManager.sharedManager.userNotificationFutureSource trySetResult:notificationSettings];
2014-05-06 19:41:08 +02:00
}
2014-11-25 23:52:53 +01:00
-(BOOL) application:(UIApplication*)application openURL:(NSURL*)url sourceApplication:(NSString*)sourceApplication annotation:(id)annotation {
if ([url.scheme isEqualToString:kURLSchemeSGNLKey]) {
if ([url.host hasPrefix:kURLHostVerifyPrefix] && ![TSAccountManager isRegistered]) {
id signupController = [Environment getCurrent].signUpFlowNavigationController;
if ([signupController isKindOfClass:[UINavigationController class]]) {
UINavigationController *navController = (UINavigationController*)signupController;
UIViewController *controller = [navController.childViewControllers lastObject];
if ([controller isKindOfClass:[CodeVerificationViewController class]]) {
CodeVerificationViewController *cvvc = (CodeVerificationViewController*)controller;
NSString *verificationCode = [url.path substringFromIndex:1];
cvvc.challengeTextField.text = verificationCode;
[cvvc verifyChallengeAction:nil];
} else{
DDLogWarn(@"Not the verification view controller we expected. Got %@ instead", NSStringFromClass(controller.class));
}
2014-11-25 23:52:53 +01:00
}
} else{
DDLogWarn(@"Application opened with an unknown URL action: %@", url.host);
}
} else {
DDLogWarn(@"Application opened with an unknown URL scheme: %@", url.scheme);
}
return NO;
}
-(void)applicationDidBecomeActive:(UIApplication *)application {
if ([TSAccountManager isRegistered]) {
// We're double checking that the app is active, to be sure since we can't verify in production env due to code signing.
[TSSocketManager becomeActiveFromForeground];
[[Environment getCurrent].contactsManager verifyABPermission];
}
[self removeScreenProtection];
}
- (void)applicationWillResignActive:(UIApplication *)application {
iOS 9 Support - Fixing size classes rendering bugs. - Supporting native iOS San Francisco font. - Quick Reply - Settings now slide to the left as suggested in original designed opposed to modal. - Simplification of restraints on many screens. - Full-API compatiblity with iOS 9 and iOS 8 legacy support. - Customized AddressBook Permission prompt when restrictions are enabled. If user installed Signal previously and already approved access to Contacts, don't bugg him again. - Fixes crash in migration for users who installed Signal <2.1.3 but hadn't signed up yet. - Xcode 7 / iOS 9 Travis Support - Bitcode Support is disabled until it is better understood how exactly optimizations are performed. In a first time, we will split out the crypto code into a separate binary to make it easier to optimize the non-sensitive code. Blog post with more details coming. - Partial ATS support. We are running our own Certificate Authority at Open Whisper Systems. Signal is doing certificate pinning to verify that certificates were signed by our own CA. Unfortunately Apple's App Transport Security requires to hand over chain verification to their framework with no control over the trust store. We have filed a radar to get ATS features with pinned certificates. In the meanwhile, ATS is disabled on our domain. We also followed Amazon's recommendations for our S3 domain we use to upload/download attachments. (#891) - Implement a unified `AFSecurityOWSPolicy` pinning strategy accross libraries (AFNetworking RedPhone/TextSecure & SocketRocket).
2015-09-01 19:22:08 +02:00
UIBackgroundTaskIdentifier __block bgTask = UIBackgroundTaskInvalid;
bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if ([TSAccountManager isRegistered]) {
dispatch_sync(dispatch_get_main_queue(), ^{
2015-11-03 00:26:48 +01:00
[self protectScreen];
[[[Environment getCurrent] signalsViewController] updateInboxCountLabel];
});
iOS 9 Support - Fixing size classes rendering bugs. - Supporting native iOS San Francisco font. - Quick Reply - Settings now slide to the left as suggested in original designed opposed to modal. - Simplification of restraints on many screens. - Full-API compatiblity with iOS 9 and iOS 8 legacy support. - Customized AddressBook Permission prompt when restrictions are enabled. If user installed Signal previously and already approved access to Contacts, don't bugg him again. - Fixes crash in migration for users who installed Signal <2.1.3 but hadn't signed up yet. - Xcode 7 / iOS 9 Travis Support - Bitcode Support is disabled until it is better understood how exactly optimizations are performed. In a first time, we will split out the crypto code into a separate binary to make it easier to optimize the non-sensitive code. Blog post with more details coming. - Partial ATS support. We are running our own Certificate Authority at Open Whisper Systems. Signal is doing certificate pinning to verify that certificates were signed by our own CA. Unfortunately Apple's App Transport Security requires to hand over chain verification to their framework with no control over the trust store. We have filed a radar to get ATS features with pinned certificates. In the meanwhile, ATS is disabled on our domain. We also followed Amazon's recommendations for our S3 domain we use to upload/download attachments. (#891) - Implement a unified `AFSecurityOWSPolicy` pinning strategy accross libraries (AFNetworking RedPhone/TextSecure & SocketRocket).
2015-09-01 19:22:08 +02:00
[TSSocketManager resignActivity];
}
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
});
}
2015-10-31 23:13:28 +01:00
- (void)application:(UIApplication *)application
performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem
completionHandler:(void (^)(BOOL succeeded))completionHandler {
if ([TSAccountManager isRegistered]) {
[[Environment getCurrent].signalsViewController composeNew];
} else {
UIAlertController *controller = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"REGISTER_CONTACTS_WELCOME", nil)
message:@"Someone's exited to send his first message! Register now to send your first message."
preferredStyle:UIAlertControllerStyleAlert];
completionHandler(YES);
[self.window.rootViewController presentViewController:controller animated:YES completion:^{
completionHandler(NO);
}];
}
}
2014-08-09 18:27:26 +02:00
- (void)prepareScreenshotProtection{
self.blankWindow = ({
2014-12-04 22:14:37 +01:00
UIWindow *window = [[UIWindow alloc] initWithFrame:self.window.bounds];
window.hidden = YES;
window.opaque = YES;
2014-08-09 18:27:26 +02:00
window.userInteractionEnabled = NO;
2014-12-04 22:14:37 +01:00
window.windowLevel = CGFLOAT_MAX;
// There appears to be no more reliable way to get the launchscreen image from an asset bundle
2015-03-21 19:33:58 +01:00
NSDictionary *dict = @{@"320x480" : @"LaunchImage-700",
@"320x568" : @"LaunchImage-700-568h",
@"375x667" : @"LaunchImage-800-667h",
@"414x736" : @"LaunchImage-800-Portrait-736h"};
2014-12-04 22:14:37 +01:00
NSString *key = [NSString stringWithFormat:@"%dx%d", (int)[UIScreen mainScreen].bounds.size.width, (int)[UIScreen mainScreen].bounds.size.height];
UIImage *launchImage = [UIImage imageNamed:dict[key]];
UIImageView *imgView = [[UIImageView alloc] initWithImage:launchImage];
UIViewController *vc = [[UIViewController alloc] initWithNibName:nil bundle:nil];
vc.view.frame = [[UIScreen mainScreen] bounds];
imgView.frame = [[UIScreen mainScreen] bounds];
[vc.view addSubview:imgView];
[vc.view setBackgroundColor:[UIColor ows_blackColor]];
2014-12-04 22:14:37 +01:00
window.rootViewController = vc;
2014-08-09 18:27:26 +02:00
window;
});
}
- (void)protectScreen{
2014-12-04 22:14:37 +01:00
if (Environment.preferences.screenSecurityIsEnabled){
2014-08-09 18:27:26 +02:00
self.blankWindow.hidden = NO;
}
}
- (void)removeScreenProtection{
if (Environment.preferences.screenSecurityIsEnabled) {
2014-08-09 18:27:26 +02:00
self.blankWindow.hidden = YES;
}
}
-(void)setupAppearance {
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
[[UINavigationBar appearance] setBarTintColor:[UIColor ows_materialBlueColor]];
[[UINavigationBar appearance] setTintColor:[UIColor whiteColor]];
[[UIBarButtonItem appearanceWhenContainedIn: [UISearchBar class], nil] setTintColor:[UIColor ows_materialBlueColor]];
[[UIToolbar appearance] setTintColor:[UIColor ows_materialBlueColor]];
[[UIBarButtonItem appearance] setTintColor:[UIColor whiteColor]];
NSShadow *shadow = [NSShadow new];
[shadow setShadowColor:[UIColor clearColor]];
NSDictionary *navbarTitleTextAttributes = @{
NSForegroundColorAttributeName:[UIColor whiteColor],
NSShadowAttributeName:shadow,
};
[[UISwitch appearance] setOnTintColor:[UIColor ows_materialBlueColor]];
[[UINavigationBar appearance] setTitleTextAttributes:navbarTitleTextAttributes];
}
#pragma mark Push Notifications Delegate Methods
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
[[PushManager sharedManager] application:application didReceiveRemoteNotification:userInfo];
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
[[PushManager sharedManager] application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
}
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification{
[[PushManager sharedManager] application:application didReceiveLocalNotification:notification];
}
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification completionHandler:(void (^)())completionHandler {
[[PushManager sharedManager] application:application handleActionWithIdentifier:identifier forLocalNotification:notification completionHandler:completionHandler];
}
iOS 9 Support - Fixing size classes rendering bugs. - Supporting native iOS San Francisco font. - Quick Reply - Settings now slide to the left as suggested in original designed opposed to modal. - Simplification of restraints on many screens. - Full-API compatiblity with iOS 9 and iOS 8 legacy support. - Customized AddressBook Permission prompt when restrictions are enabled. If user installed Signal previously and already approved access to Contacts, don't bugg him again. - Fixes crash in migration for users who installed Signal <2.1.3 but hadn't signed up yet. - Xcode 7 / iOS 9 Travis Support - Bitcode Support is disabled until it is better understood how exactly optimizations are performed. In a first time, we will split out the crypto code into a separate binary to make it easier to optimize the non-sensitive code. Blog post with more details coming. - Partial ATS support. We are running our own Certificate Authority at Open Whisper Systems. Signal is doing certificate pinning to verify that certificates were signed by our own CA. Unfortunately Apple's App Transport Security requires to hand over chain verification to their framework with no control over the trust store. We have filed a radar to get ATS features with pinned certificates. In the meanwhile, ATS is disabled on our domain. We also followed Amazon's recommendations for our S3 domain we use to upload/download attachments. (#891) - Implement a unified `AFSecurityOWSPolicy` pinning strategy accross libraries (AFNetworking RedPhone/TextSecure & SocketRocket).
2015-09-01 19:22:08 +02:00
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void (^)())completionHandler {
[[PushManager sharedManager] application:application handleActionWithIdentifier:identifier forLocalNotification:notification withResponseInfo:responseInfo completionHandler:completionHandler];
}
/**
* Signal requires an iPhone to be unlocked after reboot to be able to access keying material.
*/
- (void)verifyBackgroundBeforeKeysAvailableLaunch {
if ([self applicationIsActive]) {
return;
}
if (![[TSStorageManager sharedManager] databasePasswordAccessible]) {
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.alertBody = NSLocalizedString(@"PHONE_NEEDS_UNLOCK", nil);
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
exit(0);
}
}
- (BOOL)applicationIsActive {
UIApplication *app = [UIApplication sharedApplication];
if (app.applicationState == UIApplicationStateActive) {
return YES;
}
return NO;
}
2014-05-06 19:41:08 +02:00
@end