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
pull/1/head
Frederic Jacobs 10 years ago
parent 1ede61f272
commit 9872bed428

@ -49,17 +49,12 @@ static NSString* const kCallSegue = @"2.0_6.0_Call_Segue";
- (void)performUpdateCheck{ - (void)performUpdateCheck{
NSString *previousVersion = Environment.preferences.lastRanVersion; NSString *previousVersion = Environment.preferences.lastRanVersion;
NSString *currentVersion = [Environment.preferences setAndGetCurrentVersion]; NSString *currentVersion = [Environment.preferences setAndGetCurrentVersion];
// TODO: remove
if (!previousVersion) { if (!previousVersion) {
DDLogError(@"No previous version found. Possibly first launch since install."); 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]; [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)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
BOOL loggingIsEnabled;
[self setupAppearance]; [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")) { if (getenv("runningTests_dontStartApp")) {
return YES; 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; loggingIsEnabled = TRUE;
[DebugLogger.sharedInstance enableTTYLogging]; [DebugLogger.sharedInstance enableTTYLogging];
@ -97,19 +105,16 @@ static NSString* const kCallSegue = @"2.0_6.0_Call_Segue";
[DebugLogger.sharedInstance enableFileLogging]; [DebugLogger.sharedInstance enableFileLogging];
} }
self.notificationTracker = [NotificationTracker notificationTracker]; UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Storyboard" bundle:[NSBundle mainBundle]];
UIViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:@"UserInitialViewController"];
CategorizingLogger* logger = [CategorizingLogger categorizingLogger]; self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[logger addLoggingCallback:^(NSString *category, id details, NSUInteger index) {}]; self.window.rootViewController = viewController;
[Environment setCurrent:[Release releaseEnvironmentWithLogging:logger]];
[Environment.getCurrent.phoneDirectoryManager startUntilCancelled:nil];
[Environment.getCurrent.contactsManager doAfterEnvironmentInitSetup];
[[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 [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 //Accept push notification when app is not open
NSDictionary *remoteNotif = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]; NSDictionary *remoteNotif = launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey];
if (remoteNotif) { if (remoteNotif) {
@ -117,14 +122,6 @@ static NSString* const kCallSegue = @"2.0_6.0_Call_Segue";
[self application:application didReceiveRemoteNotification:remoteNotif ]; [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]; [self prepareScreenshotProtection];
[Environment.phoneManager.currentCallObservable watchLatestValue:^(CallState* latestCall) { [Environment.phoneManager.currentCallObservable watchLatestValue:^(CallState* latestCall) {

@ -22,6 +22,8 @@ MacrosSingletonInterface
- (void)wipeLogs; - (void)wipeLogs;
- (NSString*)logsDirectory;
@property (nonatomic) DDFileLogger *fileLogger; @property (nonatomic) DDFileLogger *fileLogger;
@end @end

@ -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. #pragma mark Logging - Production logging wants us to write some logs to a file in case we need it for debugging.
#import <CocoaLumberjack/DDTTYLogger.h> #import <CocoaLumberjack/DDTTYLogger.h>
#import <CocoaLumberjack/DDFileLogger.h>
@interface DebugLogger () @interface DebugLogger ()
@ -21,7 +22,7 @@
MacrosSingletonImplemention MacrosSingletonImplemention
- (void)enableFileLogging{ - (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.rollingFrequency = 60 * 60 * 24; // 24 hour rolling.
self.fileLogger.logFileManager.maximumNumberOfLogFiles = 3; // Keep three days of logs. self.fileLogger.logFileManager.maximumNumberOfLogFiles = 3; // Keep three days of logs.
[DDLog addLogger:self.fileLogger]; [DDLog addLogger:self.fileLogger];
@ -38,17 +39,15 @@ MacrosSingletonImplemention
- (void)wipeLogs{ - (void)wipeLogs{
BOOL reenableLogging = (self.fileLogger?YES:NO); BOOL reenableLogging = (self.fileLogger?YES:NO);
NSError *error;
NSArray *logsPath = self.fileLogger.logFileManager.unsortedLogFilePaths;
if (reenableLogging) { if (reenableLogging) {
[self disableFileLogging]; [self disableFileLogging];
} }
NSError *error; for (NSUInteger i = 0; i < logsPath.count; i++) {
NSString *logPath = [NSHomeDirectory() stringByAppendingString:@"/Library/Caches/Logs/"]; [[NSFileManager defaultManager] removeItemAtPath:[logsPath objectAtIndex:i] error:&error];
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];
} }
if (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 @end

@ -11,6 +11,7 @@
#import "PhoneNumberDirectoryFilterManager.h" #import "PhoneNumberDirectoryFilterManager.h"
#import "SignalKeyingStorage.h" #import "SignalKeyingStorage.h"
#import "SignalsViewController.h" #import "SignalsViewController.h"
#import "TSStorageManager.h"
#define isRegisteredUserDefaultString @"isRegistered" #define isRegisteredUserDefaultString @"isRegistered"
@ -201,12 +202,9 @@ phoneDirectoryManager;
} }
+ (void)resetAppData{ + (void)resetAppData{
[SignalKeyingStorage wipeKeychain]; [[TSStorageManager sharedManager] wipeSignalStorage];
[Environment.preferences clear]; [Environment.preferences clear];
if (self.preferences.loggingIsEnabled) {
[DebugLogger.sharedInstance wipeLogs]; [DebugLogger.sharedInstance wipeLogs];
} }
[self.preferences setAndGetCurrentVersion];
}
@end @end

@ -24,8 +24,6 @@
+(void)generateSignaling; +(void)generateSignaling;
+(void)generateServerAuthPassword; +(void)generateServerAuthPassword;
+(void)wipeKeychain;
#pragma mark Registered Phone Number #pragma mark Registered Phone Number
+(PhoneNumber*)localNumber; +(PhoneNumber*)localNumber;

@ -31,10 +31,6 @@
[self storeData:[CryptoTools generateSecureRandomData:ZID_LENGTH] forKey:ZID_KEY]; [self storeData:[CryptoTools generateSecureRandomData:ZID_LENGTH] forKey:ZID_KEY];
} }
+(void)wipeKeychain{
[TSStorageManager.sharedManager purgeCollection:SignalKeyingCollection];
}
+(int64_t) getAndIncrementOneTimeCounter { +(int64_t) getAndIncrementOneTimeCounter {
__block int64_t oldCounter; __block int64_t oldCounter;
oldCounter = [[self stringForKey:PASSWORD_COUNTER_KEY] longLongValue]; oldCounter = [[self stringForKey:PASSWORD_COUNTER_KEY] longLongValue];
@ -117,8 +113,4 @@
[TSStorageManager.sharedManager setObject:string forKey:key inCollection:SignalKeyingCollection]; [TSStorageManager.sharedManager setObject:string forKey:key inCollection:SignalKeyingCollection];
} }
@end @end

@ -12,8 +12,6 @@
@interface VersionMigrations : NSObject @interface VersionMigrations : NSObject
+ (void)migrateFrom1Dot0Dot2ToGreater;
+ (void)migrateFrom1Dot0Dot2ToVersion2Dot0; + (void)migrateFrom1Dot0Dot2ToVersion2Dot0;
+ (void)migrateFrom2Dot0BetaTo2Dot0Dot10;
@end @end

@ -28,82 +28,58 @@
@implementation VersionMigrations @implementation VersionMigrations
+ (void)migrateFrom1Dot0Dot2ToVersion2Dot0 { + (void)migrateFrom1Dot0Dot2ToVersion2Dot0 {
if (!([self wasRedPhoneRegistered] || [Environment.preferences getIsMigratingToVersion2Dot0])) {
return;
}
[Environment.preferences setIsMigratingToVersion2Dot0:YES]; [Environment.preferences setIsMigratingToVersion2Dot0:YES];
[self migrateFrom1Dot0Dot2ToGreater];
[self migrateRecentCallsToVersion2Dot0]; [self migrateRecentCallsToVersion2Dot0];
[self migrateKeyingStorageToVersion2Dot0]; [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) { [PushManager.sharedManager registrationAndRedPhoneTokenRequestWithSuccess:^(NSData *pushToken, NSString *signupToken) {
[TSAccountManager registerWithRedPhoneToken:signupToken pushToken:pushToken success:^{ [TSAccountManager registerWithRedPhoneToken:signupToken pushToken:pushToken success:^{
[Environment.preferences setIsMigratingToVersion2Dot0:NO]; [Environment.preferences setIsMigratingToVersion2Dot0:NO];
Environment *env = [Environment getCurrent]; Environment *env = [Environment getCurrent];
PhoneNumberDirectoryFilterManager *manager = [env phoneDirectoryManager]; PhoneNumberDirectoryFilterManager *manager = [env phoneDirectoryManager];
[manager forceUpdate]; [manager forceUpdate];
[waitingController dismissViewControllerAnimated:YES completion:nil];
} failure:^(NSError *error) { } failure:^(NSError *error) {
// TODO: should we have a UI response here? [self refreshLock:waitingController];
DDLogError(@"Couldn't register with TextSecure server: %@", error.debugDescription);
}]; }];
} failure:^{ } failure:^(NSError *error) {
// TODO: should we have a UI response here? [self refreshLock:waitingController];
DDLogError(@"Couldn't register with RedPhone server.");
}]; }];
} }
+ (void)migrateFrom2Dot0BetaTo2Dot0Dot10 { + (void)refreshLock:(UIAlertController*)waitingController {
[[TSStorageManager sharedManager] deleteThreadsAndMessages]; [waitingController dismissViewControllerAnimated:NO completion:^{
} UIAlertController *retryController = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"REGISTER_TEXTSECURE_COMPONENT", nil)
message:NSLocalizedString(@"REGISTER_TEXTSECURE_FAILED", nil)
+ (void)migrateFrom1Dot0Dot2ToGreater { preferredStyle:UIAlertControllerStyleAlert];
// 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; [retryController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"REGISTER_FAILED_TRY_AGAIN", nil)
NSPropertyListFormat format; style:UIAlertActionStyleDefault
NSDictionary *dict = [NSPropertyListSerialization propertyListWithData:plistData options:NSPropertyListImmutable format:&format error:&error]; handler:^(UIAlertAction *action) {
[self migrateFrom1Dot0Dot2ToVersion2Dot0];
}]];
[[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:retryController animated:YES completion:nil];
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];
}
[defaults synchronize];
[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;
} }
#pragma mark helper methods #pragma mark helper methods
+ (void) migrateRecentCallsToVersion2Dot0 { + (void) migrateRecentCallsToVersion2Dot0 {
NSUserDefaults *defaults = NSUserDefaults.standardUserDefaults; NSUserDefaults *defaults = NSUserDefaults.standardUserDefaults;
NSData *encodedData = [defaults objectForKey:RECENT_CALLS_DEFAULT_KEY]; NSData *encodedData = [defaults objectForKey:RECENT_CALLS_DEFAULT_KEY];
id data = [NSKeyedUnarchiver unarchiveObjectWithData:encodedData]; id data = [NSKeyedUnarchiver unarchiveObjectWithData:encodedData];
@ -116,16 +92,28 @@
for (RecentCall* recentCall in allRecents) { for (RecentCall* recentCall in allRecents) {
[Environment.getCurrent.recentCallManager addRecentCall:recentCall]; [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{ + (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 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) { if([UICKeyChainStore stringForKey:LOCAL_NUMBER_KEY]!=nil) {

@ -18,6 +18,8 @@
#define Signal_Message_View_Identifier @"Signal_Message_Read" #define Signal_Message_View_Identifier @"Signal_Message_Read"
#define Signal_Message_MarkAsRead_Identifier @"Signal_Message_MarkAsRead" #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. * 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 * @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. * 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 * @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. * The pushNotification and userNotificationFutureSource are accessed by the App Delegate after requested permissions.
*/ */
-(TOCFuture*)registerPushNotificationFuture; -(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 *pushNotificationFutureSource;
@property TOCFutureSource *userNotificationFutureSource; @property TOCFutureSource *userNotificationFutureSource;

@ -11,12 +11,14 @@
#import "RPServerRequestsManager.h" #import "RPServerRequestsManager.h"
#import "TSAccountManager.h" #import "TSAccountManager.h"
#define pushManagerDomain @"org.whispersystems.pushmanager"
@interface PushManager () @interface PushManager ()
@property TOCFutureSource *registerWithServerFutureSource; @property TOCFutureSource *registerWithServerFutureSource;
@property UIAlertView *missingPermissionsAlertView; @property UIAlertView *missingPermissionsAlertView;
@end @end
@implementation PushManager @implementation PushManager
@ -45,14 +47,14 @@
- (void)verifyPushPermissions{ - (void)verifyPushPermissions{
if (self.isMissingMandatoryNotificationTypes || self.needToRegisterForRemoteNotifications){ if (self.isMissingMandatoryNotificationTypes || self.needToRegisterForRemoteNotifications){
[self registrationWithSuccess:^{ [self registrationWithSuccess:^{
DDLogError(@"Re-enabled push succesfully"); DDLogInfo(@"Re-enabled push succesfully");
} failure:^{ } failure:^(NSError *error) {
DDLogError(@"Failed to re-enable push."); DDLogError(@"Failed to re-register for push");
}]; }];
} }
} }
- (void)registrationWithSuccess:(void (^)())success failure:(void (^)())failure{ - (void)registrationWithSuccess:(void (^)())success failure:(failedPushRegistrationBlock)failure{
if (!self.wantRemoteNotifications) { if (!self.wantRemoteNotifications) {
success(); success();
@ -60,9 +62,9 @@
} }
[self registrationForPushWithSuccess:^(NSData* pushToken){ [self registrationForPushWithSuccess:^(NSData* pushToken){
[self registrationForUserNotificationWithSuccess:success failure:^{ [self registrationForUserNotificationWithSuccess:success failure:^(NSError *error) {
[self.missingPermissionsAlertView show]; [self.missingPermissionsAlertView show];
failure(); failure([NSError errorWithDomain:pushManagerDomain code:400 userInfo:@{}]);
}]; }];
} failure:failure]; } failure:failure];
} }
@ -82,7 +84,7 @@
[self.registerWithServerFutureSource trySetResult:@YES]; [self.registerWithServerFutureSource trySetResult:@YES];
} else{ } else{
DDLogError(@"The server returned %@ instead of a 200 status code", task.response); 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{ } else{
[self.registerWithServerFutureSource trySetFailure:task.response]; [self.registerWithServerFutureSource trySetFailure:task.response];
@ -104,21 +106,12 @@
return self.pushNotificationFutureSource.future; return self.pushNotificationFutureSource.future;
} }
-(TOCFuture*)registerForUserNotificationsFuture{ - (void)registrationForPushWithSuccess:(void (^)(NSData* pushToken))success failure:(failedPushRegistrationBlock)failure{
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{
TOCFuture *requestPushTokenFuture = [self registerPushNotificationFuture]; TOCFuture *requestPushTokenFuture = [self registerPushNotificationFuture];
[requestPushTokenFuture catchDo:^(id failureObj) { [requestPushTokenFuture catchDo:^(id failureObj) {
failure();
[self.missingPermissionsAlertView show]; [self.missingPermissionsAlertView show];
failure(failureObj);
DDLogError(@"This should not happen on iOS8. No push token was provided"); DDLogError(@"This should not happen on iOS8. No push token was provided");
}]; }];
@ -126,13 +119,7 @@
TOCFuture *registerPushTokenFuture = [self registerForPushFutureWithToken:pushToken]; TOCFuture *registerPushTokenFuture = [self registerForPushFutureWithToken:pushToken];
[registerPushTokenFuture catchDo:^(id failureObj) { [registerPushTokenFuture catchDo:^(id failureObj) {
UIAlertView *failureToRegisterWithServerAlert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"REGISTRATION_ERROR", @"") failure(failureObj);
message:NSLocalizedString(@"REGISTRATION_BODY", nil)
delegate:nil
cancelButtonTitle:NSLocalizedString(@"OK", nil)
otherButtonTitles:nil, nil];
[failureToRegisterWithServerAlert show];
failure();
}]; }];
[registerPushTokenFuture thenDo:^(id value) { [registerPushTokenFuture thenDo:^(id value) {
@ -142,7 +129,7 @@
} }
- (void)registrationAndRedPhoneTokenRequestWithSuccess:(void (^)(NSData* pushToken, NSString* signupToken))success failure:(void (^)())failure{ - (void)registrationAndRedPhoneTokenRequestWithSuccess:(void (^)(NSData* pushToken, NSString* signupToken))success failure:(failedPushRegistrationBlock)failure{
[self registrationForPushWithSuccess:^(NSData *pushToken) { [self registrationForPushWithSuccess:^(NSData *pushToken) {
[RPServerRequestsManager.sharedInstance performRequest:[RPAPICall requestTextSecureVerificationCode] success:^(NSURLSessionDataTask *task, id responseObject) { [RPServerRequestsManager.sharedInstance performRequest:[RPAPICall requestTextSecureVerificationCode] success:^(NSURLSessionDataTask *task, id responseObject) {
NSError *error; NSError *error;
@ -151,31 +138,34 @@
NSString* tsToken = [dictionary objectForKey:@"token"]; NSString* tsToken = [dictionary objectForKey:@"token"];
if (!tsToken || !pushToken || error) { if (!tsToken || !pushToken || error) {
failure(); failure(error);
return; return;
} }
success(pushToken, tsToken); success(pushToken, tsToken);
} failure:^(NSURLSessionDataTask *task, NSError *error) { } 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{ - (void)registrationForUserNotificationWithSuccess:(void (^)())success failure:(void (^)())failure{
TOCFuture *registrerUserNotificationFuture = [self registerForUserNotificationsFuture]; TOCFuture *registrerUserNotificationFuture = [self registerForUserNotificationsFuture];
[registrerUserNotificationFuture catchDo:^(id failureObj) { [registrerUserNotificationFuture catchDo:^(id failureObj) {
[self.missingPermissionsAlertView show];
failure(); failure();
}]; }];
[registrerUserNotificationFuture thenDo:^(id types) { [registrerUserNotificationFuture thenDo:^(id types) {
if (self.isMissingMandatoryNotificationTypes) { if (self.isMissingMandatoryNotificationTypes) {
[self.missingPermissionsAlertView show];
failure(); failure();
} else{ } else{
success(); success();
@ -198,51 +188,6 @@
return YES; 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 { -(BOOL)isMissingMandatoryNotificationTypes {
int mandatoryTypes = self.mandatoryNotificationTypes; int mandatoryTypes = self.mandatoryNotificationTypes;

@ -16,6 +16,7 @@
#import "SecurityUtils.h" #import "SecurityUtils.h"
#import "TSNetworkManager.h" #import "TSNetworkManager.h"
#import "TSAccountManager.h" #import "TSAccountManager.h"
#import "TSSocketManager.h"
#import "TSStorageManager+keyingMaterial.h" #import "TSStorageManager+keyingMaterial.h"
#import "TSPreKeyManager.h" #import "TSPreKeyManager.h"
#import "TSRegisterForPushRequest.h" #import "TSRegisterForPushRequest.h"
@ -120,6 +121,7 @@
[self registerForPushNotifications:pushToken success:^{ [self registerForPushNotifications:pushToken success:^{
[self registerPreKeys:^{ [self registerPreKeys:^{
successBlock(); successBlock();
[TSSocketManager becomeActive];
} failure:failureBlock]; } failure:failureBlock];
} failure:^(NSError *error) { } failure:^(NSError *error) {
failureBlock([self errorForRegistrationFailure:kTSRegistrationFailureNetwork HTTPStatusCode:0]); failureBlock([self errorForRegistrationFailure:kTSRegistrationFailureNetwork HTTPStatusCode:0]);

@ -46,12 +46,10 @@
return [[self class] groupIdFromThreadId:self.uniqueId]; return [[self class] groupIdFromThreadId:self.uniqueId];
} }
- (NSString*)name{ - (NSString*)name{
return self.groupModel.groupName; return self.groupModel.groupName;
} }
+ (NSString*)threadIdFromGroupId:(NSData*)groupId{ + (NSString*)threadIdFromGroupId:(NSData*)groupId{
return [TSGroupThreadPrefix stringByAppendingString:[groupId base64EncodedString]]; return [TSGroupThreadPrefix stringByAppendingString:[groupId base64EncodedString]];
} }
@ -60,8 +58,6 @@
return [NSData dataFromBase64String:[threadId substringWithRange:NSMakeRange(1, threadId.length-1)]]; return [NSData dataFromBase64String:[threadId substringWithRange:NSMakeRange(1, threadId.length-1)]];
} }
- (NSArray *)recipientsWithTransaction:(YapDatabaseReadTransaction*)transaction{ - (NSArray *)recipientsWithTransaction:(YapDatabaseReadTransaction*)transaction{
NSMutableArray *recipients = [[NSMutableArray alloc] init]; NSMutableArray *recipients = [[NSMutableArray alloc] init];
@ -75,5 +71,4 @@
return recipients; return recipients;
} }
@end @end

@ -24,8 +24,6 @@
return self; return self;
} }
+ (NSString *)collection{ + (NSString *)collection{
return @"TSAttachements"; return @"TSAttachements";
} }

@ -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 @end

@ -22,10 +22,13 @@ extern NSString *const TSUIDatabaseConnectionDidUpdateNotification;
+ (instancetype)sharedManager; + (instancetype)sharedManager;
- (void)setupDatabase; - (void)setupDatabase;
- (void)deleteThreadsAndMessages; - (void)deleteThreadsAndMessages;
- (void)wipeSignalStorage;
- (YapDatabase*)database; - (YapDatabase*)database;
- (YapDatabaseConnection*)newDatabaseConnection; - (YapDatabaseConnection*)newDatabaseConnection;
- (void)setObject:(id)object forKey:(NSString*)key inCollection:(NSString*)collection; - (void)setObject:(id)object forKey:(NSString*)key inCollection:(NSString*)collection;
- (void)removeObjectForKey:(NSString*)string inCollection:(NSString *)collection; - (void)removeObjectForKey:(NSString*)string inCollection:(NSString *)collection;
@ -44,5 +47,4 @@ extern NSString *const TSUIDatabaseConnectionDidUpdateNotification;
@property (nonatomic, readonly) YapDatabaseConnection *dbConnection; @property (nonatomic, readonly) YapDatabaseConnection *dbConnection;
- (void)wipe;
@end @end

@ -81,11 +81,10 @@ static NSString * keychainDBPassAccount = @"TSDatabasePass";
} }
- (void)protectSignalFiles{ - (void)protectSignalFiles{
[self protectFolderAtPath:[TSAttachmentStream attachmentsFolder]]; [self protectFolderAtPath:[TSAttachmentStream attachmentsFolder]];
[self protectFolderAtPath:[self dbPath]]; [self protectFolderAtPath:[self dbPath]];
[self protectFolderAtPath:[NSHomeDirectory() stringByAppendingString:@"/Library/Caches/Logs/"]]; [self protectFolderAtPath:[[DebugLogger sharedInstance] logsDirectory]];
} }
- (void)protectFolderAtPath:(NSString*)path { - (void)protectFolderAtPath:(NSString*)path {
@ -98,7 +97,7 @@ static NSString * keychainDBPassAccount = @"TSDatabasePass";
if (error || !success) { if (error || !success) {
DDLogError(@"Error while removing files from backup: %@", error.description); 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; return;
} }
} }
@ -250,16 +249,21 @@ static NSString * keychainDBPassAccount = @"TSDatabasePass";
[TSAttachmentStream deleteAttachments]; [TSAttachmentStream deleteAttachments];
} }
- (void)wipe{ - (void)wipeSignalStorage{
self.database = nil; self.database = nil;
NSError *error; NSError *error;
[SSKeychain deletePasswordForService:keychainService account:keychainDBPassAccount];
[[NSFileManager defaultManager] removeItemAtPath:[self dbPath] error:&error]; [[NSFileManager defaultManager] removeItemAtPath:[self dbPath] error:&error];
if (error) { if (error) {
DDLogError(@"Failed to delete database: %@", error.description); DDLogError(@"Failed to delete database: %@", error.description);
} }
[self setupDatabase]; [TSAttachmentStream deleteAttachments];
[[self init] setupDatabase];
} }
@end @end

@ -92,8 +92,8 @@ static NSDictionary *supportedImageExtensionTypesToMIMETypes;
@"jpeg":@"image/jpeg", @"jpeg":@"image/jpeg",
@"jpg":@"image/jpeg", @"jpg":@"image/jpeg",
@"gif":@"image/gif", @"gif":@"image/gif",
@".tif":@"image/tiff", @"tif":@"image/tiff",
@".tiff":@"image/tiff" @"tiff":@"image/tiff"
}; };
} }
@ -175,13 +175,15 @@ static NSDictionary *supportedImageExtensionTypesToMIMETypes;
if ([self isVideo:contentType]){ if ([self isVideo:contentType]){
return [MIMETypeUtil filePathForVideo:uniqueId ofMIMEType:contentType inFolder:folder]; return [MIMETypeUtil filePathForVideo:uniqueId ofMIMEType:contentType inFolder:folder];
} }
else if([self isAudio:contentType]) { else if([self isAudio:contentType]) {
return [MIMETypeUtil filePathForAudio:uniqueId ofMIMEType:contentType inFolder:folder]; return [MIMETypeUtil filePathForAudio:uniqueId ofMIMEType:contentType inFolder:folder];
} }
else { else if([self isImage:contentType]){
return [MIMETypeUtil filePathForImage:uniqueId ofMIMEType:contentType inFolder:folder]; 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 { +(NSURL*) simLinkCorrectExtensionOfFile:(NSURL*)mediaURL ofMIMEType:(NSString*)contentType {
@ -204,7 +206,7 @@ static NSDictionary *supportedImageExtensionTypesToMIMETypes;
} }
+ (NSString*)filePathForImage:(NSString*)uniqueId ofMIMEType:(NSString*)contentType inFolder:(NSString*)folder{ + (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{ + (NSString*)filePathForVideo:(NSString*)uniqueId ofMIMEType:(NSString*)contentType inFolder:(NSString*)folder{

@ -103,8 +103,8 @@
-(void)didToggleSwitch:(UISwitch*)sender -(void)didToggleSwitch:(UISwitch*)sender
{ {
if (!sender.isOn) { if (!sender.isOn) {
[DebugLogger.sharedInstance disableFileLogging];
[DebugLogger.sharedInstance wipeLogs]; [DebugLogger.sharedInstance wipeLogs];
[DebugLogger.sharedInstance disableFileLogging];
} else { } else {
[DebugLogger.sharedInstance enableFileLogging]; [DebugLogger.sharedInstance enableFileLogging];
} }

@ -64,21 +64,17 @@
- (void)registerWithSuccess:(void(^)())success failure:(void(^)(NSError *))failure{ - (void)registerWithSuccess:(void(^)())success failure:(void(^)(NSError *))failure{
//TODO: Refactor this to use futures? Better error handling needed. Good enough for PoC
[_submitCodeSpinner startAnimating]; [_submitCodeSpinner startAnimating];
[[RPServerRequestsManager sharedInstance] performRequest:[RPAPICall verifyVerificationCode:_challengeTextField.text] success:^(NSURLSessionDataTask *task, id responseObject) { [[RPServerRequestsManager sharedInstance] performRequest:[RPAPICall verifyVerificationCode:_challengeTextField.text] success:^(NSURLSessionDataTask *task, id responseObject) {
[PushManager.sharedManager registrationAndRedPhoneTokenRequestWithSuccess:^(NSData *pushToken, NSString *signupToken) { [PushManager.sharedManager registrationAndRedPhoneTokenRequestWithSuccess:^(NSData *pushToken, NSString *signupToken) {
[TSAccountManager registerWithRedPhoneToken:signupToken pushToken:pushToken success:^{ [TSAccountManager registerWithRedPhoneToken:signupToken pushToken:pushToken success:^{
success(); success();
} failure:^(NSError *error) { } failure:^(NSError *error) {
failure(error); failure(error);
}]; }];
} failure:^{ } failure:^(NSError *error) {
// PushManager shows its own error alerts, so we don't want to show a second one failure(error);
failure(nil);
[_submitCodeSpinner stopAnimating]; [_submitCodeSpinner stopAnimating];
}]; }];
} failure:^(NSURLSessionDataTask *task, NSError *error) { } failure:^(NSURLSessionDataTask *task, NSError *error) {

@ -195,12 +195,12 @@ typedef enum {
[TSAccountManager unregisterTextSecureWithSuccess:^{ [TSAccountManager unregisterTextSecureWithSuccess:^{
[PushManager.sharedManager registrationForPushWithSuccess:^(NSData* pushToken){ [PushManager.sharedManager registrationForPushWithSuccess:^(NSData* pushToken){
[[RPServerRequestsManager sharedInstance]performRequest:[RPAPICall unregisterWithPushToken:pushToken] success:^(NSURLSessionDataTask *task, id responseObject) { [[RPServerRequestsManager sharedInstance]performRequest:[RPAPICall unregisterWithPushToken:pushToken] success:^(NSURLSessionDataTask *task, id responseObject) {
[[TSStorageManager sharedManager] wipe]; [Environment resetAppData];
exit(0); exit(0);
} failure:^(NSURLSessionDataTask *task, NSError *error) { } failure:^(NSURLSessionDataTask *task, NSError *error) {
SignalAlertView(NSLocalizedString(@"UNREGISTER_REDPHONE_FAIL", @""), @""); SignalAlertView(NSLocalizedString(@"UNREGISTER_REDPHONE_FAIL", @""), @"");
}]; }];
} failure:^{ } failure:^(NSError *error) {
SignalAlertView(NSLocalizedString(@"UNREGISTER_REDPHONE_FAIL", @""), @""); SignalAlertView(NSLocalizedString(@"UNREGISTER_REDPHONE_FAIL", @""), @"");
}]; }];
} failure:^(NSError *error) { } failure:^(NSError *error) {

@ -12,7 +12,7 @@
#import "TSAttachmentAdapter.h" #import "TSAttachmentAdapter.h"
@interface TSGroupModel : TSYapDatabaseObject <YapDatabaseRelationshipNode> @interface TSGroupModel : TSYapDatabaseObject
@property (nonatomic, strong) NSMutableArray *groupMemberIds; @property (nonatomic, strong) NSMutableArray *groupMemberIds;
@property (nonatomic, strong) UIImage *groupImage; @property (nonatomic, strong) UIImage *groupImage;

@ -87,17 +87,4 @@ NSString * const TSAttachementGroupAvatarFileRelationshipEdge = @"TSAttachementG
return updatedGroupInfoString; 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 @end

@ -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."; "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"; "RECENT_NAV_BAR_TITLE" = "Call Log";
"REGISTER_BUTTON_TITLE" = "REGISTER"; "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_MESSAGE" = "Please enter a valid country code";
"REGISTER_CC_ERR_ALERT_VIEW_TITLE" = "Country Code Error"; "REGISTER_CC_ERR_ALERT_VIEW_TITLE" = "Country Code Error";
"REGISTER_CHALLENGE_ALERT_VIEW_TITLE" = "Incorrect code"; "REGISTER_CHALLENGE_ALERT_VIEW_TITLE" = "Incorrect code";

Loading…
Cancel
Save