session-ios/Signal/src/environment/VersionMigrations.m

229 lines
9.2 KiB
Mathematica
Raw Normal View History

//
2017-01-12 21:37:37 +01:00
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "VersionMigrations.h"
#import "Environment.h"
#import "LockInteractionController.h"
#import "OWSDatabaseMigrationRunner.h"
#import "PropertyListPreferences.h"
#import "PushManager.h"
#import "SignalKeyingStorage.h"
#import "TSAccountManager.h"
#import "TSNetworkManager.h"
#import <SignalServiceKit/AppVersion.h>
#import <SignalServiceKit/OWSOrphanedDataCleaner.h>
#define NEEDS_TO_REGISTER_PUSH_KEY @"Register For Push"
#define NEEDS_TO_REGISTER_ATTRIBUTES @"Register Attributes"
@interface SignalKeyingStorage (VersionMigrations)
+ (void)storeString:(NSString *)string forKey:(NSString *)key;
+ (void)storeData:(NSData *)data forKey:(NSString *)key;
@end
@implementation VersionMigrations
2015-04-25 16:59:32 +02:00
#pragma mark Utility methods
+ (void)performUpdateCheck
{
// performUpdateCheck must be invoked after Environment has been initialized because
// upgrade process may depend on Environment.
OWSAssert([Environment getCurrent]);
NSString *previousVersion = AppVersion.instance.lastAppVersion;
NSString *currentVersion = AppVersion.instance.currentAppVersion;
DDLogInfo(
@"%@ Checking migrations. currentVersion: %@, lastRanVersion: %@", self.tag, currentVersion, previousVersion);
2015-04-25 16:59:32 +02:00
if (!previousVersion) {
DDLogInfo(@"No previous version found. Probably first launch since install - nothing to migrate.");
OWSDatabaseMigrationRunner *runner =
[[OWSDatabaseMigrationRunner alloc] initWithStorageManager:[TSStorageManager sharedManager]];
[runner assumeAllExistingMigrationsRun];
2015-04-25 16:59:32 +02:00
return;
}
if ([self isVersion:previousVersion atLeast:@"1.0.2" andLessThan:@"2.0"]) {
DDLogError(@"Migrating from RedPhone no longer supported. Quitting.");
// Not translating these as so few are affected.
UIAlertController *alertController = [UIAlertController
alertControllerWithTitle:@"You must reinstall Signal"
message:
@"Sorry, your installation is too old for us to update. You'll have to start fresh."
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *quitAction = [UIAlertAction actionWithTitle:@"Quit"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *_Nonnull action) {
[DDLog flushLog];
exit(0);
}];
[alertController addAction:quitAction];
[[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:alertController
animated:YES
completion:nil];
2015-04-25 16:59:32 +02:00
}
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
if ([self isVersion:previousVersion atLeast:@"2.0.0" andLessThan:@"2.1.70"] && [TSAccountManager isRegistered]) {
2015-04-25 16:59:32 +02:00
[self clearVideoCache];
[self blockingAttributesUpdate];
}
if ([self isVersion:previousVersion atLeast:@"2.0.0" andLessThan:@"2.3.0"] && [TSAccountManager isRegistered]) {
[self clearBloomFilterCache];
}
#ifdef DEBUG
// A bug in orphan cleanup could be disastrous so let's only
// run it in DEBUG builds for a few releases.
//
// TODO: Release to production once we have analytics.
// TODO: Orphan cleanup is somewhat expensive - not least in doing a bunch
// of disk access. We might want to only run it "once per version"
// or something like that in production.
2017-07-07 17:01:24 +02:00
[OWSOrphanedDataCleaner auditAndCleanupAsync:nil];
#endif
[[[OWSDatabaseMigrationRunner alloc] initWithStorageManager:[TSStorageManager sharedManager]] runAllOutstanding];
}
+ (void)runSafeBlockingMigrations
{
[[[OWSDatabaseMigrationRunner alloc] initWithStorageManager:[TSStorageManager sharedManager]]
runSafeBlockingMigrations];
2015-04-25 16:59:32 +02:00
}
+ (BOOL)isVersion:(NSString *)thisVersionString
atLeast:(NSString *)openLowerBoundVersionString
andLessThan:(NSString *)closedUpperBoundVersionString {
return [self isVersion:thisVersionString atLeast:openLowerBoundVersionString] &&
[self isVersion:thisVersionString lessThan:closedUpperBoundVersionString];
2015-04-25 16:59:32 +02:00
}
+ (BOOL)isVersion:(NSString *)thisVersionString atLeast:(NSString *)thatVersionString {
2015-04-25 16:59:32 +02:00
return [thisVersionString compare:thatVersionString options:NSNumericSearch] != NSOrderedAscending;
}
+ (BOOL)isVersion:(NSString *)thisVersionString lessThan:(NSString *)thatVersionString {
2015-04-25 16:59:32 +02:00
return [thisVersionString compare:thatVersionString options:NSNumericSearch] == NSOrderedAscending;
}
#pragma mark Upgrading to 2.1 - Needs to register VOIP token + Removing video cache folder
2015-04-25 16:59:32 +02:00
+ (void)nonBlockingPushRegistration {
void (^failedBlock)(NSError *) = ^(NSError *error) {
DDLogError(@"Failed to register VOIP push token: %@", error.debugDescription);
};
[[PushManager sharedManager] requestPushTokenWithSuccess:^(NSString *pushToken, NSString *voipToken) {
[[TSAccountManager sharedInstance]
registerForPushNotificationsWithPushToken:pushToken
voipToken:voipToken
success:^{
DDLogWarn(@"Registered for VOIP Push.");
}
failure:failedBlock];
}
failure:failedBlock];
}
2015-04-25 16:59:32 +02:00
+ (void)clearVideoCache {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
2015-04-25 16:59:32 +02:00
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
basePath = [basePath stringByAppendingPathComponent:@"videos"];
2015-04-25 16:59:32 +02:00
NSError *error;
if ([[NSFileManager defaultManager] fileExistsAtPath:basePath]) {
2015-04-25 16:59:32 +02:00
[NSFileManager.defaultManager removeItemAtPath:basePath error:&error];
}
if (error) {
DDLogError(@"An error occured while removing the videos cache folder from old location: %@",
error.debugDescription);
}
}
#pragma mark Upgrading to 2.1.3 - Adding VOIP flag on TS Server
+ (void)blockingAttributesUpdate {
LIControllerBlockingOperation blockingOperation = ^BOOL(void) {
[[NSUserDefaults standardUserDefaults] setObject:@YES forKey:NEEDS_TO_REGISTER_ATTRIBUTES];
__block dispatch_semaphore_t sema = dispatch_semaphore_create(0);
__block BOOL success;
TSUpdateAttributesRequest *request = [[TSUpdateAttributesRequest alloc] initWithUpdatedAttributesWithVoice];
[[TSNetworkManager sharedManager] makeRequest:request
success:^(NSURLSessionDataTask *task, id responseObject) {
success = YES;
dispatch_semaphore_signal(sema);
}
failure:^(NSURLSessionDataTask *task, NSError *error) {
success = NO;
DDLogError(@"Updating attributess failed with error: %@", error.description);
dispatch_semaphore_signal(sema);
}];
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
return success;
};
LIControllerRetryBlock retryBlock = [LockInteractionController defaultNetworkRetry];
[LockInteractionController performBlock:blockingOperation
completionBlock:^{
[[NSUserDefaults standardUserDefaults] removeObjectForKey:NEEDS_TO_REGISTER_ATTRIBUTES];
DDLogWarn(@"Successfully updated attributes.");
}
retryBlock:retryBlock
usesNetwork:YES];
2015-04-25 16:59:32 +02:00
}
#pragma mark Upgrading to 2.3.0
// We removed bloom filter contact discovery. Clean up any local bloom filter data.
+ (void)clearBloomFilterCache {
NSFileManager *fm = [NSFileManager defaultManager];
NSArray *cachesDir = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *bloomFilterPath = [[cachesDir objectAtIndex:0] stringByAppendingPathComponent:@"bloomfilter"];
if ([fm fileExistsAtPath:bloomFilterPath]) {
NSError *deleteError;
if ([fm removeItemAtPath:bloomFilterPath error:&deleteError]) {
DDLogInfo(@"Successfully removed bloom filter cache.");
[[TSStorageManager sharedManager].dbReadWriteConnection
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
[transaction removeAllObjectsInCollection:@"TSRecipient"];
}];
DDLogInfo(@"Removed all TSRecipient records - will be replaced by SignalRecipients at next address sync.");
} else {
DDLogError(@"Failed to remove bloom filter cache with error: %@", deleteError.localizedDescription);
}
} else {
DDLogDebug(@"No bloom filter cache to remove.");
}
}
#pragma mark - Logging
+ (NSString *)tag
{
return [NSString stringWithFormat:@"[%@]", self.class];
}
- (NSString *)tag
{
return self.class.tag;
}
@end