From 9872bed4288401f7aeba79958b1c2af96b4a4f00 Mon Sep 17 00:00:00 2001 From: Frederic Jacobs Date: Fri, 20 Feb 2015 17:02:31 +0100 Subject: [PATCH] Addressing some storage related fixes. - Tested on jailbroken phone that correct files are getting encrypted - Fixes #557 - Stores image file extension - Addresses issue with deletion of debug logs - Preventing user to browse in app if not registered with TS server --- Signal/src/AppDelegate.m | 51 ++++---- Signal/src/environment/DebugLogger.h | 2 + Signal/src/environment/DebugLogger.m | 29 +++-- Signal/src/environment/Environment.m | 8 +- Signal/src/environment/SignalKeyingStorage.h | 2 - Signal/src/environment/SignalKeyingStorage.m | 8 -- Signal/src/environment/VersionMigrations.h | 2 - Signal/src/environment/VersionMigrations.m | 114 ++++++++---------- Signal/src/network/PushManager.h | 9 +- Signal/src/network/PushManager.m | 107 ++++------------ .../src/textsecure/Account/TSAccountManager.m | 2 + .../Contacts/Threads/TSGroupThread.m | 5 - Signal/src/textsecure/Messages/TSAttachment.m | 2 - Signal/src/textsecure/Messages/TSMessage.m | 9 ++ .../src/textsecure/Storage/TSStorageManager.h | 4 +- .../src/textsecure/Storage/TSStorageManager.m | 14 ++- Signal/src/util/MIMETypeUtil.m | 12 +- .../AdvancedSettingsTableViewController.m | 2 +- .../CodeVerificationViewController.m | 8 +- .../SettingsTableViewController.m | 4 +- Signal/src/view controllers/TSGroupModel.h | 2 +- Signal/src/view controllers/TSGroupModel.m | 13 -- .../translations/en.lproj/Localizable.strings | 3 + 23 files changed, 173 insertions(+), 239 deletions(-) diff --git a/Signal/src/AppDelegate.m b/Signal/src/AppDelegate.m index 357451903..20d065287 100644 --- a/Signal/src/AppDelegate.m +++ b/Signal/src/AppDelegate.m @@ -49,16 +49,11 @@ static NSString* const kCallSegue = @"2.0_6.0_Call_Segue"; - (void)performUpdateCheck{ NSString *previousVersion = Environment.preferences.lastRanVersion; NSString *currentVersion = [Environment.preferences setAndGetCurrentVersion]; - // TODO: remove + if (!previousVersion) { DDLogError(@"No previous version found. Possibly first launch since install."); - [Environment resetAppData]; // We clean previous keychain entries in case their are some entries remaining. - } - else if(([self isVersion:previousVersion atLeast:@"1.0.2" andLessThan:@"2.0"]) || [Environment.preferences getIsMigratingToVersion2Dot0] ) { + } else if(([self isVersion:previousVersion atLeast:@"1.0.2" andLessThan:@"2.0"]) || [Environment.preferences getIsMigratingToVersion2Dot0] ) { [VersionMigrations migrateFrom1Dot0Dot2ToVersion2Dot0]; - } - else if([self isVersion:previousVersion atLeast:@"2.0" andLessThan:@"2.0.10"]){ - [VersionMigrations migrateFrom2Dot0BetaTo2Dot0Dot10]; } } @@ -77,15 +72,28 @@ static NSString* const kCallSegue = @"2.0_6.0_Call_Segue"; } - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - BOOL loggingIsEnabled; + [self setupAppearance]; -#ifdef DEBUG - // Specified at Product -> Scheme -> Edit Scheme -> Test -> Arguments -> Environment to avoid things like - // the phone directory being looked up during tests. + if (getenv("runningTests_dontStartApp")) { return YES; } + self.notificationTracker = [NotificationTracker notificationTracker]; + + CategorizingLogger* logger = [CategorizingLogger categorizingLogger]; + [logger addLoggingCallback:^(NSString *category, id details, NSUInteger index) {}]; + [Environment setCurrent:[Release releaseEnvironmentWithLogging:logger]]; + [Environment.getCurrent.phoneDirectoryManager startUntilCancelled:nil]; + [Environment.getCurrent.contactsManager doAfterEnvironmentInitSetup]; + + [[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]; @@ -97,18 +105,15 @@ static NSString* const kCallSegue = @"2.0_6.0_Call_Segue"; [DebugLogger.sharedInstance enableFileLogging]; } - self.notificationTracker = [NotificationTracker notificationTracker]; + UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Storyboard" bundle:[NSBundle mainBundle]]; + UIViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:@"UserInitialViewController"]; - CategorizingLogger* logger = [CategorizingLogger categorizingLogger]; - [logger addLoggingCallback:^(NSString *category, id details, NSUInteger index) {}]; - [Environment setCurrent:[Release releaseEnvironmentWithLogging:logger]]; - [Environment.getCurrent.phoneDirectoryManager startUntilCancelled:nil]; - [Environment.getCurrent.contactsManager doAfterEnvironmentInitSetup]; + self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + self.window.rootViewController = viewController; - [[TSStorageManager sharedManager] setupDatabase]; + [self.window makeKeyAndVisible]; [self performUpdateCheck]; // this call must be made after environment has been initialized because in general upgrade may depend on environment - //Accept push notification when app is not open NSDictionary *remoteNotif = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]; @@ -117,14 +122,6 @@ static NSString* const kCallSegue = @"2.0_6.0_Call_Segue"; [self application:application didReceiveRemoteNotification:remoteNotif ]; } - UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Storyboard" bundle:[NSBundle mainBundle]]; - UIViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:@"UserInitialViewController"]; - - self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; - self.window.rootViewController = viewController; - - [self.window makeKeyAndVisible]; - [self prepareScreenshotProtection]; [Environment.phoneManager.currentCallObservable watchLatestValue:^(CallState* latestCall) { diff --git a/Signal/src/environment/DebugLogger.h b/Signal/src/environment/DebugLogger.h index e38a055d0..c0c4ab16b 100644 --- a/Signal/src/environment/DebugLogger.h +++ b/Signal/src/environment/DebugLogger.h @@ -22,6 +22,8 @@ MacrosSingletonInterface - (void)wipeLogs; +- (NSString*)logsDirectory; + @property (nonatomic) DDFileLogger *fileLogger; @end diff --git a/Signal/src/environment/DebugLogger.m b/Signal/src/environment/DebugLogger.m index 9ccd78bbb..7d828de28 100644 --- a/Signal/src/environment/DebugLogger.m +++ b/Signal/src/environment/DebugLogger.m @@ -11,6 +11,7 @@ #pragma mark Logging - Production logging wants us to write some logs to a file in case we need it for debugging. #import +#import @interface DebugLogger () @@ -21,7 +22,7 @@ MacrosSingletonImplemention - (void)enableFileLogging{ - self.fileLogger = [DDFileLogger new]; //Logging to file, because it's in the Cache folder, they are not uploaded in iTunes/iCloud backups. + self.fileLogger = [[DDFileLogger alloc] init]; //Logging to file, because it's in the Cache folder, they are not uploaded in iTunes/iCloud backups. self.fileLogger.rollingFrequency = 60 * 60 * 24; // 24 hour rolling. self.fileLogger.logFileManager.maximumNumberOfLogFiles = 3; // Keep three days of logs. [DDLog addLogger:self.fileLogger]; @@ -38,17 +39,15 @@ MacrosSingletonImplemention - (void)wipeLogs{ BOOL reenableLogging = (self.fileLogger?YES:NO); + NSError *error; + NSArray *logsPath = self.fileLogger.logFileManager.unsortedLogFilePaths; if (reenableLogging) { [self disableFileLogging]; } - NSError *error; - NSString *logPath = [NSHomeDirectory() stringByAppendingString:@"/Library/Caches/Logs/"]; - NSArray *logsFiles = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:logPath error:&error]; - - for (NSUInteger i = 0; i < logsFiles.count; i++) { - [[NSFileManager defaultManager] removeItemAtPath:[logPath stringByAppendingString:logsFiles[i]] error:&error]; + for (NSUInteger i = 0; i < logsPath.count; i++) { + [[NSFileManager defaultManager] removeItemAtPath:[logsPath objectAtIndex:i] error:&error]; } if (error) { @@ -60,4 +59,20 @@ MacrosSingletonImplemention } } +- (NSString*)logsDirectory{ + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); + NSString *baseDir = ([paths count] > 0) ? [paths objectAtIndex:0] : nil; + NSString *logsDirectory = [baseDir stringByAppendingPathComponent:@"Logs"]; + + if (![[NSFileManager defaultManager] fileExistsAtPath:logsDirectory]) { + NSError *error; + //[[NSFileManager defaultManager] createDirectoryAtPath:logsDirectory withIntermediateDirectories:YES attributes:nil error:nil]; + if (error) { + DDLogError(@"Log folder couldn't be created. %@", error.description); + } + } + + return logsDirectory; +} + @end diff --git a/Signal/src/environment/Environment.m b/Signal/src/environment/Environment.m index ac1466255..e19cc390e 100644 --- a/Signal/src/environment/Environment.m +++ b/Signal/src/environment/Environment.m @@ -11,6 +11,7 @@ #import "PhoneNumberDirectoryFilterManager.h" #import "SignalKeyingStorage.h" #import "SignalsViewController.h" +#import "TSStorageManager.h" #define isRegisteredUserDefaultString @"isRegistered" @@ -201,12 +202,9 @@ phoneDirectoryManager; } + (void)resetAppData{ - [SignalKeyingStorage wipeKeychain]; + [[TSStorageManager sharedManager] wipeSignalStorage]; [Environment.preferences clear]; - if (self.preferences.loggingIsEnabled) { - [DebugLogger.sharedInstance wipeLogs]; - } - [self.preferences setAndGetCurrentVersion]; + [DebugLogger.sharedInstance wipeLogs]; } @end diff --git a/Signal/src/environment/SignalKeyingStorage.h b/Signal/src/environment/SignalKeyingStorage.h index 932052a16..57b6a6da8 100644 --- a/Signal/src/environment/SignalKeyingStorage.h +++ b/Signal/src/environment/SignalKeyingStorage.h @@ -24,8 +24,6 @@ +(void)generateSignaling; +(void)generateServerAuthPassword; -+(void)wipeKeychain; - #pragma mark Registered Phone Number +(PhoneNumber*)localNumber; diff --git a/Signal/src/environment/SignalKeyingStorage.m b/Signal/src/environment/SignalKeyingStorage.m index 8768ac5f2..1e31537b4 100644 --- a/Signal/src/environment/SignalKeyingStorage.m +++ b/Signal/src/environment/SignalKeyingStorage.m @@ -31,10 +31,6 @@ [self storeData:[CryptoTools generateSecureRandomData:ZID_LENGTH] forKey:ZID_KEY]; } -+(void)wipeKeychain{ - [TSStorageManager.sharedManager purgeCollection:SignalKeyingCollection]; -} - +(int64_t) getAndIncrementOneTimeCounter { __block int64_t oldCounter; oldCounter = [[self stringForKey:PASSWORD_COUNTER_KEY] longLongValue]; @@ -117,8 +113,4 @@ [TSStorageManager.sharedManager setObject:string forKey:key inCollection:SignalKeyingCollection]; } - - - - @end diff --git a/Signal/src/environment/VersionMigrations.h b/Signal/src/environment/VersionMigrations.h index eac9062b3..50757ca11 100644 --- a/Signal/src/environment/VersionMigrations.h +++ b/Signal/src/environment/VersionMigrations.h @@ -12,8 +12,6 @@ @interface VersionMigrations : NSObject -+ (void)migrateFrom1Dot0Dot2ToGreater; + (void)migrateFrom1Dot0Dot2ToVersion2Dot0; -+ (void)migrateFrom2Dot0BetaTo2Dot0Dot10; @end diff --git a/Signal/src/environment/VersionMigrations.m b/Signal/src/environment/VersionMigrations.m index d67a1a0e2..1a6a692fa 100644 --- a/Signal/src/environment/VersionMigrations.m +++ b/Signal/src/environment/VersionMigrations.m @@ -28,82 +28,58 @@ @implementation VersionMigrations + (void)migrateFrom1Dot0Dot2ToVersion2Dot0 { + + if (!([self wasRedPhoneRegistered] || [Environment.preferences getIsMigratingToVersion2Dot0])) { + return; + } + [Environment.preferences setIsMigratingToVersion2Dot0:YES]; - [self migrateFrom1Dot0Dot2ToGreater]; - [self migrateRecentCallsToVersion2Dot0]; + [self migrateRecentCallsToVersion2Dot0]; [self migrateKeyingStorageToVersion2Dot0]; + + UIAlertController *waitingController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"REGISTER_TEXTSECURE_COMPONENT", nil) + message:nil + preferredStyle:UIAlertControllerStyleAlert]; + + [[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:waitingController + animated:YES + completion:nil]; + [PushManager.sharedManager registrationAndRedPhoneTokenRequestWithSuccess:^(NSData *pushToken, NSString *signupToken) { [TSAccountManager registerWithRedPhoneToken:signupToken pushToken:pushToken success:^{ [Environment.preferences setIsMigratingToVersion2Dot0:NO]; Environment *env = [Environment getCurrent]; PhoneNumberDirectoryFilterManager *manager = [env phoneDirectoryManager]; [manager forceUpdate]; + [waitingController dismissViewControllerAnimated:YES completion:nil]; } failure:^(NSError *error) { - // TODO: should we have a UI response here? + [self refreshLock:waitingController]; + DDLogError(@"Couldn't register with TextSecure server: %@", error.debugDescription); }]; - } failure:^{ - // TODO: should we have a UI response here? + } failure:^(NSError *error) { + [self refreshLock:waitingController]; + DDLogError(@"Couldn't register with RedPhone server."); }]; - - } -+ (void)migrateFrom2Dot0BetaTo2Dot0Dot10 { - [[TSStorageManager sharedManager] deleteThreadsAndMessages]; -} - -+ (void)migrateFrom1Dot0Dot2ToGreater { - - // Preferences were stored in both a preference file and a plist in the documents folder, as a temporary measure, we are going to move all the preferences to the NSUserDefaults preference store, those will be migrated to a SQLCipher-backed database - - NSString* documentsDirectory = [NSHomeDirectory() stringByAppendingPathComponent:@"/Documents/"]; - NSString *path = [NSString stringWithFormat:@"%@/%@.plist", documentsDirectory, @"RedPhone-Data"]; - - if ([NSFileManager.defaultManager fileExistsAtPath:path]) { - NSData *plistData = [NSData dataWithContentsOfFile:path]; - - NSError *error; - NSPropertyListFormat format; - NSDictionary *dict = [NSPropertyListSerialization propertyListWithData:plistData options:NSPropertyListImmutable format:&format error:&error]; - - - NSArray *entries = [dict allKeys]; - NSUserDefaults *defaults = NSUserDefaults.standardUserDefaults; - - for (NSUInteger i = 0; i < entries.count; i++) { - NSString *key = entries[i]; - [defaults setObject:dict[key] forKey:key]; - } ++ (void)refreshLock:(UIAlertController*)waitingController { + [waitingController dismissViewControllerAnimated:NO completion:^{ + UIAlertController *retryController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"REGISTER_TEXTSECURE_COMPONENT", nil) + message:NSLocalizedString(@"REGISTER_TEXTSECURE_FAILED", nil) + preferredStyle:UIAlertControllerStyleAlert]; - [defaults synchronize]; + [retryController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"REGISTER_FAILED_TRY_AGAIN", nil) + style:UIAlertActionStyleDefault + handler:^(UIAlertAction *action) { + [self migrateFrom1Dot0Dot2ToVersion2Dot0]; + }]]; - [NSFileManager.defaultManager removeItemAtPath:path error:&error]; - - if (error) { - DDLogError(@"Error while migrating data: %@", error.description); - } - - // Some users push IDs were not correctly registered, by precaution, we are going to re-register all of them - - [PushManager.sharedManager registrationWithSuccess:^{ - - } failure:^{ - DDLogError(@"Error re-registering on migration from 1.0.2"); - }]; - - [NSFileManager.defaultManager removeItemAtPath:path error:&error]; - - if (error) { - DDLogError(@"Error upgrading from 1.0.2 : %@", error.description); - } - } - - return; + [[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:retryController animated:YES completion:nil]; + }]; } #pragma mark helper methods + (void) migrateRecentCallsToVersion2Dot0 { - NSUserDefaults *defaults = NSUserDefaults.standardUserDefaults; NSData *encodedData = [defaults objectForKey:RECENT_CALLS_DEFAULT_KEY]; id data = [NSKeyedUnarchiver unarchiveObjectWithData:encodedData]; @@ -116,16 +92,28 @@ for (RecentCall* recentCall in allRecents) { [Environment.getCurrent.recentCallManager addRecentCall:recentCall]; } - // Erasing recent calls in the defaults - NSUserDefaults *localDefaults = NSUserDefaults.standardUserDefaults; - NSData *saveData = [NSKeyedArchiver archivedDataWithRootObject:[NSMutableArray array]]; - [localDefaults setObject:saveData forKey:RECENT_CALLS_DEFAULT_KEY]; - [localDefaults synchronize]; - + + NSString *appDomain = [[NSBundle mainBundle] bundleIdentifier]; + [[NSUserDefaults standardUserDefaults] removePersistentDomainForName:appDomain]; } } ++(BOOL)wasRedPhoneRegistered{ + BOOL hasPassCounter = [UICKeyChainStore stringForKey:PASSWORD_COUNTER_KEY]!=nil; + BOOL hasLocalNumber = [UICKeyChainStore stringForKey:LOCAL_NUMBER_KEY]!=nil; + BOOL hasPassKey = [UICKeyChainStore stringForKey:SAVED_PASSWORD_KEY]!=nil; + BOOL hasSignaling = [UICKeyChainStore dataForKey:SIGNALING_MAC_KEY]!=nil; + BOOL hasCipherKey = [UICKeyChainStore dataForKey:SIGNALING_CIPHER_KEY]!=nil; + BOOL hasZIDKey = [UICKeyChainStore dataForKey:ZID_KEY]!=nil; + BOOL hasSignalingExtra = [UICKeyChainStore dataForKey:SIGNALING_EXTRA_KEY]!=nil; + + BOOL registered = [[NSUserDefaults.standardUserDefaults objectForKey:@"isRegistered"] boolValue]; + + return registered &&hasPassCounter && hasLocalNumber && hasPassKey && hasSignaling + && hasCipherKey && hasCipherKey && hasZIDKey && hasSignalingExtra; +} + + (void)migrateKeyingStorageToVersion2Dot0{ // if statements ensure that if this migration is called more than once for whatever reason, the original data isn't rewritten the second time if([UICKeyChainStore stringForKey:LOCAL_NUMBER_KEY]!=nil) { diff --git a/Signal/src/network/PushManager.h b/Signal/src/network/PushManager.h index 121f2fcbd..bc42d6493 100644 --- a/Signal/src/network/PushManager.h +++ b/Signal/src/network/PushManager.h @@ -18,6 +18,8 @@ #define Signal_Message_View_Identifier @"Signal_Message_Read" #define Signal_Message_MarkAsRead_Identifier @"Signal_Message_MarkAsRead" +typedef void(^failedPushRegistrationBlock)(NSError *error); + /** * The Push Manager is responsible for registering the device for Signal push notifications. */ @@ -40,7 +42,7 @@ * @param failure Block to executre if push notification registration fails */ -- (void)registrationWithSuccess:(void (^)())success failure:(void (^)())failure; +- (void)registrationWithSuccess:(void (^)())success failure:(failedPushRegistrationBlock)failure; /** * Registers the push token with the RedPhone server, then returns the push token and a signup token to be used to register with TextSecure. @@ -49,14 +51,15 @@ * @param failure Failure completion block */ -- (void)registrationAndRedPhoneTokenRequestWithSuccess:(void (^)(NSData* pushToken, NSString* signupToken))success failure:(void (^)())failure; +- (void)registrationAndRedPhoneTokenRequestWithSuccess:(void (^)(NSData* pushToken, NSString* signupToken))success failure:(failedPushRegistrationBlock)failure; /** * The pushNotification and userNotificationFutureSource are accessed by the App Delegate after requested permissions. */ -(TOCFuture*)registerPushNotificationFuture; -- (void)registrationForPushWithSuccess:(void (^)(NSData* pushToken))success failure:(void (^)())failure; +- (void)registrationForPushWithSuccess:(void (^)(NSData* pushToken))success failure:(void(^)(NSError *))failure; + @property TOCFutureSource *pushNotificationFutureSource; @property TOCFutureSource *userNotificationFutureSource; diff --git a/Signal/src/network/PushManager.m b/Signal/src/network/PushManager.m index 2dbb92e10..51cf9c65a 100644 --- a/Signal/src/network/PushManager.m +++ b/Signal/src/network/PushManager.m @@ -11,12 +11,14 @@ #import "RPServerRequestsManager.h" #import "TSAccountManager.h" +#define pushManagerDomain @"org.whispersystems.pushmanager" + @interface PushManager () @property TOCFutureSource *registerWithServerFutureSource; - @property UIAlertView *missingPermissionsAlertView; + @end @implementation PushManager @@ -45,14 +47,14 @@ - (void)verifyPushPermissions{ if (self.isMissingMandatoryNotificationTypes || self.needToRegisterForRemoteNotifications){ [self registrationWithSuccess:^{ - DDLogError(@"Re-enabled push succesfully"); - } failure:^{ - DDLogError(@"Failed to re-enable push."); + DDLogInfo(@"Re-enabled push succesfully"); + } failure:^(NSError *error) { + DDLogError(@"Failed to re-register for push"); }]; } } -- (void)registrationWithSuccess:(void (^)())success failure:(void (^)())failure{ +- (void)registrationWithSuccess:(void (^)())success failure:(failedPushRegistrationBlock)failure{ if (!self.wantRemoteNotifications) { success(); @@ -60,9 +62,9 @@ } [self registrationForPushWithSuccess:^(NSData* pushToken){ - [self registrationForUserNotificationWithSuccess:success failure:^{ + [self registrationForUserNotificationWithSuccess:success failure:^(NSError *error) { [self.missingPermissionsAlertView show]; - failure(); + failure([NSError errorWithDomain:pushManagerDomain code:400 userInfo:@{}]); }]; } failure:failure]; } @@ -82,7 +84,7 @@ [self.registerWithServerFutureSource trySetResult:@YES]; } else{ DDLogError(@"The server returned %@ instead of a 200 status code", task.response); - [self.registerWithServerFutureSource trySetFailure:nil]; + [self.registerWithServerFutureSource trySetFailure:[NSError errorWithDomain:pushManagerDomain code:500 userInfo:nil]]; } } else{ [self.registerWithServerFutureSource trySetFailure:task.response]; @@ -104,21 +106,12 @@ return self.pushNotificationFutureSource.future; } --(TOCFuture*)registerForUserNotificationsFuture{ - self.userNotificationFutureSource = [TOCFutureSource new]; - NSSet *setOfCategories = [NSSet setWithArray:@[[self userNotificationsCallCategory], [self userNotificationsMessageCategory]]]; - UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationType)[self allNotificationTypes] - categories:setOfCategories]; - [UIApplication.sharedApplication registerUserNotificationSettings:settings]; - return self.userNotificationFutureSource.future; -} - -- (void)registrationForPushWithSuccess:(void (^)(NSData* pushToken))success failure:(void (^)())failure{ +- (void)registrationForPushWithSuccess:(void (^)(NSData* pushToken))success failure:(failedPushRegistrationBlock)failure{ TOCFuture *requestPushTokenFuture = [self registerPushNotificationFuture]; [requestPushTokenFuture catchDo:^(id failureObj) { - failure(); [self.missingPermissionsAlertView show]; + failure(failureObj); DDLogError(@"This should not happen on iOS8. No push token was provided"); }]; @@ -126,13 +119,7 @@ TOCFuture *registerPushTokenFuture = [self registerForPushFutureWithToken:pushToken]; [registerPushTokenFuture catchDo:^(id failureObj) { - UIAlertView *failureToRegisterWithServerAlert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"REGISTRATION_ERROR", @"") - message:NSLocalizedString(@"REGISTRATION_BODY", nil) - delegate:nil - cancelButtonTitle:NSLocalizedString(@"OK", nil) - otherButtonTitles:nil, nil]; - [failureToRegisterWithServerAlert show]; - failure(); + failure(failureObj); }]; [registerPushTokenFuture thenDo:^(id value) { @@ -142,8 +129,8 @@ } -- (void)registrationAndRedPhoneTokenRequestWithSuccess:(void (^)(NSData* pushToken, NSString* signupToken))success failure:(void (^)())failure{ - [self registrationForPushWithSuccess:^(NSData *pushToken) { +- (void)registrationAndRedPhoneTokenRequestWithSuccess:(void (^)(NSData* pushToken, NSString* signupToken))success failure:(failedPushRegistrationBlock)failure{ + [self registrationForPushWithSuccess:^(NSData *pushToken) { [RPServerRequestsManager.sharedInstance performRequest:[RPAPICall requestTextSecureVerificationCode] success:^(NSURLSessionDataTask *task, id responseObject) { NSError *error; @@ -151,31 +138,34 @@ NSString* tsToken = [dictionary objectForKey:@"token"]; if (!tsToken || !pushToken || error) { - failure(); + failure(error); return; } success(pushToken, tsToken); } failure:^(NSURLSessionDataTask *task, NSError *error) { - failure(); + failure(error); }]; - } failure:^{ - failure(); - }]; - + } failure:failure]; +} + +-(TOCFuture*)registerForUserNotificationsFuture{ + self.userNotificationFutureSource = [TOCFutureSource new]; + UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationType)[self allNotificationTypes] + categories:nil]; + [UIApplication.sharedApplication registerUserNotificationSettings:settings]; + return self.userNotificationFutureSource.future; } - (void)registrationForUserNotificationWithSuccess:(void (^)())success failure:(void (^)())failure{ TOCFuture *registrerUserNotificationFuture = [self registerForUserNotificationsFuture]; [registrerUserNotificationFuture catchDo:^(id failureObj) { - [self.missingPermissionsAlertView show]; failure(); }]; [registrerUserNotificationFuture thenDo:^(id types) { if (self.isMissingMandatoryNotificationTypes) { - [self.missingPermissionsAlertView show]; failure(); } else{ success(); @@ -198,51 +188,6 @@ return YES; } -- (UIUserNotificationCategory*)userNotificationsMessageCategory{ - UIMutableUserNotificationAction *action_accept = [UIMutableUserNotificationAction new]; - action_accept.identifier = Signal_Message_View_Identifier; - action_accept.title = NSLocalizedString(@"PUSH_MANAGER_VIEW", @""); - action_accept.activationMode = UIUserNotificationActivationModeForeground; - action_accept.destructive = NO; - action_accept.authenticationRequired = YES; - - UIMutableUserNotificationAction *action_decline = [UIMutableUserNotificationAction new]; - action_decline.identifier = Signal_Message_MarkAsRead_Identifier; - action_decline.title = NSLocalizedString(@"PUSH_MANAGER_MARKREAD", @""); - action_decline.activationMode = UIUserNotificationActivationModeBackground; - action_decline.destructive = NO; - action_decline.authenticationRequired = NO; - - UIMutableUserNotificationCategory *messageCategory = [UIMutableUserNotificationCategory new]; - messageCategory.identifier = Signal_Message_Category; - [messageCategory setActions:@[action_accept, action_decline] forContext:UIUserNotificationActionContextMinimal]; - [messageCategory setActions:@[action_accept, action_decline] forContext:UIUserNotificationActionContextDefault]; - - return messageCategory; -} - -- (UIUserNotificationCategory*)userNotificationsCallCategory{ - UIMutableUserNotificationAction *action_accept = [UIMutableUserNotificationAction new]; - action_accept.identifier = Signal_Call_Accept_Identifier; - action_accept.title = NSLocalizedString(@"ANSWER_CALL_BUTTON_TITLE", @""); - action_accept.activationMode = UIUserNotificationActivationModeForeground; - action_accept.destructive = NO; - action_accept.authenticationRequired = NO; - - UIMutableUserNotificationAction *action_decline = [UIMutableUserNotificationAction new]; - action_decline.identifier = Signal_Call_Decline_Identifier; - action_decline.title = NSLocalizedString(@"REJECT_CALL_BUTTON_TITLE", @""); - action_decline.activationMode = UIUserNotificationActivationModeBackground; - action_decline.destructive = NO; - action_decline.authenticationRequired = NO; - - UIMutableUserNotificationCategory *callCategory = [UIMutableUserNotificationCategory new]; - callCategory.identifier = Signal_Call_Category; - [callCategory setActions:@[action_accept, action_decline] forContext:UIUserNotificationActionContextMinimal]; - [callCategory setActions:@[action_accept, action_decline] forContext:UIUserNotificationActionContextDefault]; - - return callCategory; -} -(BOOL)isMissingMandatoryNotificationTypes { int mandatoryTypes = self.mandatoryNotificationTypes; diff --git a/Signal/src/textsecure/Account/TSAccountManager.m b/Signal/src/textsecure/Account/TSAccountManager.m index b55e55646..1f5fdc9bd 100644 --- a/Signal/src/textsecure/Account/TSAccountManager.m +++ b/Signal/src/textsecure/Account/TSAccountManager.m @@ -16,6 +16,7 @@ #import "SecurityUtils.h" #import "TSNetworkManager.h" #import "TSAccountManager.h" +#import "TSSocketManager.h" #import "TSStorageManager+keyingMaterial.h" #import "TSPreKeyManager.h" #import "TSRegisterForPushRequest.h" @@ -120,6 +121,7 @@ [self registerForPushNotifications:pushToken success:^{ [self registerPreKeys:^{ successBlock(); + [TSSocketManager becomeActive]; } failure:failureBlock]; } failure:^(NSError *error) { failureBlock([self errorForRegistrationFailure:kTSRegistrationFailureNetwork HTTPStatusCode:0]); diff --git a/Signal/src/textsecure/Contacts/Threads/TSGroupThread.m b/Signal/src/textsecure/Contacts/Threads/TSGroupThread.m index c2f7ee269..ab6a67f6a 100644 --- a/Signal/src/textsecure/Contacts/Threads/TSGroupThread.m +++ b/Signal/src/textsecure/Contacts/Threads/TSGroupThread.m @@ -46,12 +46,10 @@ return [[self class] groupIdFromThreadId:self.uniqueId]; } - - (NSString*)name{ return self.groupModel.groupName; } - + (NSString*)threadIdFromGroupId:(NSData*)groupId{ return [TSGroupThreadPrefix stringByAppendingString:[groupId base64EncodedString]]; } @@ -60,8 +58,6 @@ return [NSData dataFromBase64String:[threadId substringWithRange:NSMakeRange(1, threadId.length-1)]]; } - - - (NSArray *)recipientsWithTransaction:(YapDatabaseReadTransaction*)transaction{ NSMutableArray *recipients = [[NSMutableArray alloc] init]; @@ -75,5 +71,4 @@ return recipients; } - @end diff --git a/Signal/src/textsecure/Messages/TSAttachment.m b/Signal/src/textsecure/Messages/TSAttachment.m index 08281e0dc..b5a7bdde6 100644 --- a/Signal/src/textsecure/Messages/TSAttachment.m +++ b/Signal/src/textsecure/Messages/TSAttachment.m @@ -24,8 +24,6 @@ return self; } - - + (NSString *)collection{ return @"TSAttachements"; } diff --git a/Signal/src/textsecure/Messages/TSMessage.m b/Signal/src/textsecure/Messages/TSMessage.m index ac86d42fc..b278dedd7 100644 --- a/Signal/src/textsecure/Messages/TSMessage.m +++ b/Signal/src/textsecure/Messages/TSMessage.m @@ -68,4 +68,13 @@ NSString * const TSAttachementsRelationshipEdgeName = @"TSAttachmentEdge"; } } +- (void)removeWithTransaction:(YapDatabaseReadWriteTransaction *)transaction{ + for (NSString *attachmentId in _attachments){ + TSAttachment *attachment = [TSAttachment fetchObjectWithUniqueID:attachmentId transaction:transaction]; + [attachment removeWithTransaction:transaction]; + } + + [super removeWithTransaction:transaction]; +} + @end diff --git a/Signal/src/textsecure/Storage/TSStorageManager.h b/Signal/src/textsecure/Storage/TSStorageManager.h index a5429b8c4..306ee2736 100644 --- a/Signal/src/textsecure/Storage/TSStorageManager.h +++ b/Signal/src/textsecure/Storage/TSStorageManager.h @@ -22,10 +22,13 @@ extern NSString *const TSUIDatabaseConnectionDidUpdateNotification; + (instancetype)sharedManager; - (void)setupDatabase; - (void)deleteThreadsAndMessages; +- (void)wipeSignalStorage; - (YapDatabase*)database; - (YapDatabaseConnection*)newDatabaseConnection; + + - (void)setObject:(id)object forKey:(NSString*)key inCollection:(NSString*)collection; - (void)removeObjectForKey:(NSString*)string inCollection:(NSString *)collection; @@ -44,5 +47,4 @@ extern NSString *const TSUIDatabaseConnectionDidUpdateNotification; @property (nonatomic, readonly) YapDatabaseConnection *dbConnection; -- (void)wipe; @end diff --git a/Signal/src/textsecure/Storage/TSStorageManager.m b/Signal/src/textsecure/Storage/TSStorageManager.m index dfdb59bed..e8da4fc51 100644 --- a/Signal/src/textsecure/Storage/TSStorageManager.m +++ b/Signal/src/textsecure/Storage/TSStorageManager.m @@ -81,11 +81,10 @@ static NSString * keychainDBPassAccount = @"TSDatabasePass"; } - - (void)protectSignalFiles{ [self protectFolderAtPath:[TSAttachmentStream attachmentsFolder]]; [self protectFolderAtPath:[self dbPath]]; - [self protectFolderAtPath:[NSHomeDirectory() stringByAppendingString:@"/Library/Caches/Logs/"]]; + [self protectFolderAtPath:[[DebugLogger sharedInstance] logsDirectory]]; } - (void)protectFolderAtPath:(NSString*)path { @@ -98,7 +97,7 @@ static NSString * keychainDBPassAccount = @"TSDatabasePass"; if (error || !success) { DDLogError(@"Error while removing files from backup: %@", error.description); - SignalAlertView(NSLocalizedString(@"WARNING_STRING", @""), @"DISABLING_BACKUP_FAILED"); + SignalAlertView(NSLocalizedString(@"WARNING_STRING", @""), NSLocalizedString(@"DISABLING_BACKUP_FAILED", @"")); return; } } @@ -250,16 +249,21 @@ static NSString * keychainDBPassAccount = @"TSDatabasePass"; [TSAttachmentStream deleteAttachments]; } -- (void)wipe{ +- (void)wipeSignalStorage{ self.database = nil; NSError *error; + + [SSKeychain deletePasswordForService:keychainService account:keychainDBPassAccount]; [[NSFileManager defaultManager] removeItemAtPath:[self dbPath] error:&error]; + if (error) { DDLogError(@"Failed to delete database: %@", error.description); } - [self setupDatabase]; + [TSAttachmentStream deleteAttachments]; + + [[self init] setupDatabase]; } @end diff --git a/Signal/src/util/MIMETypeUtil.m b/Signal/src/util/MIMETypeUtil.m index 596915da4..298862fb0 100644 --- a/Signal/src/util/MIMETypeUtil.m +++ b/Signal/src/util/MIMETypeUtil.m @@ -92,8 +92,8 @@ static NSDictionary *supportedImageExtensionTypesToMIMETypes; @"jpeg":@"image/jpeg", @"jpg":@"image/jpeg", @"gif":@"image/gif", - @".tif":@"image/tiff", - @".tiff":@"image/tiff" + @"tif":@"image/tiff", + @"tiff":@"image/tiff" }; } @@ -175,13 +175,15 @@ static NSDictionary *supportedImageExtensionTypesToMIMETypes; if ([self isVideo:contentType]){ return [MIMETypeUtil filePathForVideo:uniqueId ofMIMEType:contentType inFolder:folder]; } - else if([self isAudio:contentType]) { return [MIMETypeUtil filePathForAudio:uniqueId ofMIMEType:contentType inFolder:folder]; } - else { + else if([self isImage:contentType]){ return [MIMETypeUtil filePathForImage:uniqueId ofMIMEType:contentType inFolder:folder]; } + + DDLogError(@"Got asked for path of file %@ which is unsupported", contentType); + return nil; } +(NSURL*) simLinkCorrectExtensionOfFile:(NSURL*)mediaURL ofMIMEType:(NSString*)contentType { @@ -204,7 +206,7 @@ static NSDictionary *supportedImageExtensionTypesToMIMETypes; } + (NSString*)filePathForImage:(NSString*)uniqueId ofMIMEType:(NSString*)contentType inFolder:(NSString*)folder{ - return [folder stringByAppendingFormat:@"/%@",uniqueId]; + return [[folder stringByAppendingFormat:@"/%@",uniqueId] stringByAppendingPathExtension:[self getSupportedExtensionFromImageMIMEType:contentType]]; } + (NSString*)filePathForVideo:(NSString*)uniqueId ofMIMEType:(NSString*)contentType inFolder:(NSString*)folder{ diff --git a/Signal/src/view controllers/AdvancedSettingsTableViewController.m b/Signal/src/view controllers/AdvancedSettingsTableViewController.m index e961e85c5..e2894e7bb 100644 --- a/Signal/src/view controllers/AdvancedSettingsTableViewController.m +++ b/Signal/src/view controllers/AdvancedSettingsTableViewController.m @@ -103,8 +103,8 @@ -(void)didToggleSwitch:(UISwitch*)sender { if (!sender.isOn) { - [DebugLogger.sharedInstance disableFileLogging]; [DebugLogger.sharedInstance wipeLogs]; + [DebugLogger.sharedInstance disableFileLogging]; } else { [DebugLogger.sharedInstance enableFileLogging]; } diff --git a/Signal/src/view controllers/CodeVerificationViewController.m b/Signal/src/view controllers/CodeVerificationViewController.m index 5349d14ce..2fa8fa5f7 100644 --- a/Signal/src/view controllers/CodeVerificationViewController.m +++ b/Signal/src/view controllers/CodeVerificationViewController.m @@ -64,21 +64,17 @@ - (void)registerWithSuccess:(void(^)())success failure:(void(^)(NSError *))failure{ - //TODO: Refactor this to use futures? Better error handling needed. Good enough for PoC - [_submitCodeSpinner startAnimating]; [[RPServerRequestsManager sharedInstance] performRequest:[RPAPICall verifyVerificationCode:_challengeTextField.text] success:^(NSURLSessionDataTask *task, id responseObject) { [PushManager.sharedManager registrationAndRedPhoneTokenRequestWithSuccess:^(NSData *pushToken, NSString *signupToken) { - [TSAccountManager registerWithRedPhoneToken:signupToken pushToken:pushToken success:^{ success(); } failure:^(NSError *error) { failure(error); }]; - } failure:^{ - // PushManager shows its own error alerts, so we don't want to show a second one - failure(nil); + } failure:^(NSError *error) { + failure(error); [_submitCodeSpinner stopAnimating]; }]; } failure:^(NSURLSessionDataTask *task, NSError *error) { diff --git a/Signal/src/view controllers/SettingsTableViewController.m b/Signal/src/view controllers/SettingsTableViewController.m index f96336b44..d3586c641 100644 --- a/Signal/src/view controllers/SettingsTableViewController.m +++ b/Signal/src/view controllers/SettingsTableViewController.m @@ -195,12 +195,12 @@ typedef enum { [TSAccountManager unregisterTextSecureWithSuccess:^{ [PushManager.sharedManager registrationForPushWithSuccess:^(NSData* pushToken){ [[RPServerRequestsManager sharedInstance]performRequest:[RPAPICall unregisterWithPushToken:pushToken] success:^(NSURLSessionDataTask *task, id responseObject) { - [[TSStorageManager sharedManager] wipe]; + [Environment resetAppData]; exit(0); } failure:^(NSURLSessionDataTask *task, NSError *error) { SignalAlertView(NSLocalizedString(@"UNREGISTER_REDPHONE_FAIL", @""), @""); }]; - } failure:^{ + } failure:^(NSError *error) { SignalAlertView(NSLocalizedString(@"UNREGISTER_REDPHONE_FAIL", @""), @""); }]; } failure:^(NSError *error) { diff --git a/Signal/src/view controllers/TSGroupModel.h b/Signal/src/view controllers/TSGroupModel.h index 2054ffdc9..815f7a65f 100644 --- a/Signal/src/view controllers/TSGroupModel.h +++ b/Signal/src/view controllers/TSGroupModel.h @@ -12,7 +12,7 @@ #import "TSAttachmentAdapter.h" -@interface TSGroupModel : TSYapDatabaseObject +@interface TSGroupModel : TSYapDatabaseObject @property (nonatomic, strong) NSMutableArray *groupMemberIds; @property (nonatomic, strong) UIImage *groupImage; diff --git a/Signal/src/view controllers/TSGroupModel.m b/Signal/src/view controllers/TSGroupModel.m index def8e8395..157e8f292 100644 --- a/Signal/src/view controllers/TSGroupModel.m +++ b/Signal/src/view controllers/TSGroupModel.m @@ -87,17 +87,4 @@ NSString * const TSAttachementGroupAvatarFileRelationshipEdge = @"TSAttachementG return updatedGroupInfoString; } -- (NSArray *)yapDatabaseRelationshipEdges { - if([_associatedAttachmentId length]>0){ - YapDatabaseRelationshipEdge *fileEdge = [[YapDatabaseRelationshipEdge alloc] initWithName:TSAttachementGroupAvatarFileRelationshipEdge - destinationKey:_associatedAttachmentId - collection:[TSAttachment collection] - nodeDeleteRules:YDB_DeleteDestinationIfAllSourcesDeleted]; - return @[fileEdge]; - } - else { - return nil; - } -} - @end diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index 4747425aa..d31ca037e 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -54,6 +54,9 @@ "PUSH_SETTINGS_MESSAGE" = "Signal requires push notification alerts and sounds to be enabled to work properly. Please change it in the Settings app >> Notification Center >> Signal."; "RECENT_NAV_BAR_TITLE" = "Call Log"; "REGISTER_BUTTON_TITLE" = "REGISTER"; +"REGISTER_TEXTSECURE_COMPONENT" = "Sign up for TextSecure"; +"REGISTER_TEXTSECURE_FAILED" = "We tried to sign you up for TextSecure but we couldn't reach the server. Please try again when connected."; +"REGISTER_FAILED_TRY_AGAIN" = "Try again"; "REGISTER_CC_ERR_ALERT_VIEW_MESSAGE" = "Please enter a valid country code"; "REGISTER_CC_ERR_ALERT_VIEW_TITLE" = "Country Code Error"; "REGISTER_CHALLENGE_ALERT_VIEW_TITLE" = "Incorrect code";