diff --git a/Podfile.lock b/Podfile.lock index bebd66947e..d389890282 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -188,6 +188,6 @@ SPEC CHECKSUMS: YapDatabase: cd911121580ff16675f65ad742a9eb0ab4d9e266 YYImage: 1e1b62a9997399593e4b9c4ecfbbabbf1d3f3b54 -PODFILE CHECKSUM: 8e42a06de2d254e448580cfd6212545739de62d6 +PODFILE CHECKSUM: 558b99b22f87c7fb6e4a9c3084b14a384203d431 COCOAPODS: 1.3.1 diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 29fef9e46a..5ba2b140a6 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -2052,6 +2052,9 @@ LastSwiftMigration = 0800; ProvisioningStyle = Automatic; SystemCapabilities = { + com.apple.ApplicationGroups.iOS = { + enabled = 1; + }; com.apple.DataProtection = { enabled = 1; }; @@ -2061,6 +2064,9 @@ com.apple.InterAppAudio = { enabled = 0; }; + com.apple.Keychain = { + enabled = 1; + }; com.apple.Push = { enabled = 1; }; diff --git a/Signal/Signal.entitlements b/Signal/Signal.entitlements index dfec421eaa..79da5ce675 100644 --- a/Signal/Signal.entitlements +++ b/Signal/Signal.entitlements @@ -4,6 +4,8 @@ aps-environment development + com.apple.developer.default-data-protection + NSFileProtectionComplete com.apple.developer.icloud-container-identifiers iCloud.$(CFBundleIdentifier) @@ -16,5 +18,13 @@ iCloud.$(CFBundleIdentifier) + com.apple.security.application-groups + + group.org.whispersystems.signal.group + + keychain-access-groups + + $(AppIdentifierPrefix)org.whispersystems.signal + diff --git a/Signal/src/AppDelegate.m b/Signal/src/AppDelegate.m index 5f27070441..fff346c7c9 100644 --- a/Signal/src/AppDelegate.m +++ b/Signal/src/AppDelegate.m @@ -24,6 +24,8 @@ #import "VersionMigrations.h" #import "ViewControllerUtils.h" #import +#import +#import #import #import #import @@ -38,7 +40,6 @@ #import #import #import -#import @import WebRTC; @import Intents; @@ -103,6 +104,19 @@ static NSString *const kURLHostVerifyPrefix = @"verify"; DDLogWarn(@"%@ application: didFinishLaunchingWithOptions.", self.logTag); + // We need to do this _after_ we set up logging but _before_ we do + // anything else. + [self ensureIsReadyForAppExtensions]; + +#if RELEASE + // ensureIsReadyForAppExtensions may have changed the state of the logging + // preference (due to [NSUserDefaults migrateToSharedUserDefaults]), so honor + // that change if necessary. + if (loggingIsEnabled && !OWSPreferences.loggingIsEnabled) { + [DebugLogger.sharedLogger disableFileLogging]; + } +#endif + [AppVersion instance]; [self startupLogging]; @@ -176,6 +190,21 @@ static NSString *const kURLHostVerifyPrefix = @"verify"; return YES; } +- (void)ensureIsReadyForAppExtensions +{ + if ([OWSPreferences isReadyForAppExtensions]) { + return; + } + + [NSUserDefaults migrateToSharedUserDefaults]; + + [TSStorageManager migrateToSharedData]; + [OWSProfileManager migrateToSharedData]; + [TSAttachmentStream migrateToSharedData]; + + [OWSPreferences setIsReadyForAppExtensions:YES]; +} + - (void)startupLogging { DDLogInfo(@"iOS Version: %@", [UIDevice currentDevice].systemVersion); diff --git a/Signal/src/Profiles/OWSProfileManager.h b/Signal/src/Profiles/OWSProfileManager.h index 3d67415f02..331dddb230 100644 --- a/Signal/src/Profiles/OWSProfileManager.h +++ b/Signal/src/Profiles/OWSProfileManager.h @@ -29,6 +29,8 @@ extern const NSUInteger kOWSProfileManager_MaxAvatarDiameter; - (void)resetProfileStorage; ++ (void)migrateToSharedData; + #pragma mark - Local Profile // These two methods should only be called from the main thread. diff --git a/Signal/src/Profiles/OWSProfileManager.m b/Signal/src/Profiles/OWSProfileManager.m index cc07377599..8c05020f7d 100644 --- a/Signal/src/Profiles/OWSProfileManager.m +++ b/Signal/src/Profiles/OWSProfileManager.m @@ -1384,14 +1384,29 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; return image; } ++ (NSString *)legacyProfileAvatarsDirPath +{ + return [[OWSFileSystem appDocumentDirectoryPath] stringByAppendingPathComponent:@"ProfileAvatars"]; +} + ++ (NSString *)sharedDataProfileAvatarsDirPath +{ + return [[OWSFileSystem appSharedDataDirectoryPath] stringByAppendingPathComponent:@"ProfileAvatars"]; +} + ++ (void)migrateToSharedData +{ + [OWSFileSystem moveAppFilePath:self.legacyProfileAvatarsDirPath + sharedDataFilePath:self.sharedDataProfileAvatarsDirPath + exceptionName:@"ProfileManagerCouldNotMigrateProfileDirectory"]; +} + - (NSString *)profileAvatarsDirPath { static NSString *profileAvatarsDirPath = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ - NSString *documentsPath = - [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; - profileAvatarsDirPath = [documentsPath stringByAppendingPathComponent:@"ProfileAvatars"]; + profileAvatarsDirPath = OWSProfileManager.sharedDataProfileAvatarsDirPath; BOOL isDirectory; BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:profileAvatarsDirPath isDirectory:&isDirectory]; diff --git a/Signal/src/environment/OWSPreferences.h b/Signal/src/environment/OWSPreferences.h index 27a0d674cc..6a0cb1882b 100644 --- a/Signal/src/environment/OWSPreferences.h +++ b/Signal/src/environment/OWSPreferences.h @@ -27,6 +27,9 @@ extern NSString *const OWSPreferencesKeyEnableDebugLog; #pragma mark - Specific Preferences ++ (BOOL)isReadyForAppExtensions; ++ (void)setIsReadyForAppExtensions:(BOOL)value; + - (BOOL)getHasSentAMessage; - (void)setHasSentAMessage:(BOOL)enabled; diff --git a/Signal/src/environment/OWSPreferences.m b/Signal/src/environment/OWSPreferences.m index 6e7e66467f..8548715f8a 100644 --- a/Signal/src/environment/OWSPreferences.m +++ b/Signal/src/environment/OWSPreferences.m @@ -4,6 +4,7 @@ #import "OWSPreferences.h" #import "TSStorageHeaders.h" +#import NS_ASSUME_NONNULL_BEGIN @@ -22,6 +23,7 @@ NSString *const OWSPreferencesKeyCallKitPrivacyEnabled = @"CallKitPrivacyEnabled NSString *const OWSPreferencesKeyCallsHideIPAddress = @"CallsHideIPAddress"; NSString *const OWSPreferencesKeyHasDeclinedNoContactsView = @"hasDeclinedNoContactsView"; NSString *const OWSPreferencesKeyIOSUpgradeNagVersion = @"iOSUpgradeNagVersion"; +NSString *const OWSPreferencesKey_IsReadyForAppExtensions = @"isReadyForAppExtensions"; @implementation OWSPreferences @@ -40,10 +42,7 @@ NSString *const OWSPreferencesKeyIOSUpgradeNagVersion = @"iOSUpgradeNagVersion"; #pragma mark - Helpers - (void)clear { - @synchronized(self) { - NSString *appDomain = NSBundle.mainBundle.bundleIdentifier; - [NSUserDefaults.standardUserDefaults removePersistentDomainForName:appDomain]; - } + [NSUserDefaults removeAll]; } - (nullable id)tryGetValueForKey:(NSString *)key @@ -61,6 +60,23 @@ NSString *const OWSPreferencesKeyIOSUpgradeNagVersion = @"iOSUpgradeNagVersion"; #pragma mark - Specific Preferences ++ (BOOL)isReadyForAppExtensions +{ + NSNumber *preference = [NSUserDefaults.appUserDefaults objectForKey:OWSPreferencesKey_IsReadyForAppExtensions]; + + if (preference) { + return [preference boolValue]; + } else { + return NO; + } +} + ++ (void)setIsReadyForAppExtensions:(BOOL)value +{ + [NSUserDefaults.appUserDefaults setObject:@(value) forKey:OWSPreferencesKey_IsReadyForAppExtensions]; + [NSUserDefaults.appUserDefaults synchronize]; +} + - (BOOL)screenSecurityIsEnabled { NSNumber *preference = [self tryGetValueForKey:OWSPreferencesKeyScreenSecurity]; @@ -94,7 +110,7 @@ NSString *const OWSPreferencesKeyIOSUpgradeNagVersion = @"iOSUpgradeNagVersion"; + (BOOL)loggingIsEnabled { - NSNumber *preference = [NSUserDefaults.standardUserDefaults objectForKey:OWSPreferencesKeyEnableDebugLog]; + NSNumber *preference = [NSUserDefaults.appUserDefaults objectForKey:OWSPreferencesKeyEnableDebugLog]; if (preference) { return [preference boolValue]; @@ -108,8 +124,8 @@ NSString *const OWSPreferencesKeyIOSUpgradeNagVersion = @"iOSUpgradeNagVersion"; // Logging preferences are stored in UserDefaults instead of the database, so that we can (optionally) start // logging before the database is initialized. This is important because sometimes there are problems *with* the // database initialization, and without logging it would be hard to track down. - [NSUserDefaults.standardUserDefaults setObject:@(flag) forKey:OWSPreferencesKeyEnableDebugLog]; - [NSUserDefaults.standardUserDefaults synchronize]; + [NSUserDefaults.appUserDefaults setObject:@(flag) forKey:OWSPreferencesKeyEnableDebugLog]; + [NSUserDefaults.appUserDefaults synchronize]; } - (void)setHasSentAMessage:(BOOL)enabled diff --git a/Signal/src/environment/VersionMigrations.m b/Signal/src/environment/VersionMigrations.m index 5afe4810d9..ebf2caf298 100644 --- a/Signal/src/environment/VersionMigrations.m +++ b/Signal/src/environment/VersionMigrations.m @@ -8,9 +8,10 @@ #import "OWSDatabaseMigrationRunner.h" #import "PushManager.h" #import "SignalKeyingStorage.h" -#import "TSAccountManager.h" -#import "TSNetworkManager.h" #import +#import +#import +#import #define NEEDS_TO_REGISTER_PUSH_KEY @"Register For Push" #define NEEDS_TO_REGISTER_ATTRIBUTES @"Register Attributes" @@ -125,39 +126,39 @@ + (void)blockingAttributesUpdate { LIControllerBlockingOperation blockingOperation = ^BOOL(void) { - [[NSUserDefaults standardUserDefaults] setObject:@YES forKey:NEEDS_TO_REGISTER_ATTRIBUTES]; + [[NSUserDefaults appUserDefaults] setObject:@YES forKey:NEEDS_TO_REGISTER_ATTRIBUTES]; - __block dispatch_semaphore_t sema = dispatch_semaphore_create(0); + __block dispatch_semaphore_t sema = dispatch_semaphore_create(0); - __block BOOL success; + __block BOOL success; - TSUpdateAttributesRequest *request = [[TSUpdateAttributesRequest alloc] initWithManualMessageFetching:NO]; - [[TSNetworkManager sharedManager] makeRequest:request - success:^(NSURLSessionDataTask *task, id responseObject) { - success = YES; - dispatch_semaphore_signal(sema); - } - failure:^(NSURLSessionDataTask *task, NSError *error) { - if (!IsNSErrorNetworkFailure(error)) { - OWSProdError([OWSAnalyticsEvents errorUpdateAttributesRequestFailed]); - } - success = NO; - DDLogError(@"Updating attributess failed with error: %@", error.description); - dispatch_semaphore_signal(sema); - }]; + TSUpdateAttributesRequest *request = [[TSUpdateAttributesRequest alloc] initWithManualMessageFetching:NO]; + [[TSNetworkManager sharedManager] makeRequest:request + success:^(NSURLSessionDataTask *task, id responseObject) { + success = YES; + dispatch_semaphore_signal(sema); + } + failure:^(NSURLSessionDataTask *task, NSError *error) { + if (!IsNSErrorNetworkFailure(error)) { + OWSProdError([OWSAnalyticsEvents errorUpdateAttributesRequestFailed]); + } + success = NO; + DDLogError(@"Updating attributess failed with error: %@", error.description); + dispatch_semaphore_signal(sema); + }]; - dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); + dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); - return success; + return success; }; LIControllerRetryBlock retryBlock = [LockInteractionController defaultNetworkRetry]; [LockInteractionController performBlock:blockingOperation completionBlock:^{ - [[NSUserDefaults standardUserDefaults] removeObjectForKey:NEEDS_TO_REGISTER_ATTRIBUTES]; - DDLogWarn(@"Successfully updated attributes."); + [[NSUserDefaults appUserDefaults] removeObjectForKey:NEEDS_TO_REGISTER_ATTRIBUTES]; + DDLogWarn(@"Successfully updated attributes."); } retryBlock:retryBlock usesNetwork:YES]; diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.h b/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.h index ac8f9c4906..21cd8eb986 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.h +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.h @@ -57,6 +57,8 @@ NS_ASSUME_NONNULL_BEGIN - (CGFloat)audioDurationSeconds; ++ (void)migrateToSharedData; + @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m b/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m index 5c6a740037..390f6b9d0d 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachmentStream.m @@ -180,14 +180,29 @@ NS_ASSUME_NONNULL_BEGIN return [dataSource writeToPath:filePath]; } ++ (NSString *)legacyAttachmentsDirPath +{ + return [[OWSFileSystem appDocumentDirectoryPath] stringByAppendingPathComponent:@"Attachments"]; +} + ++ (NSString *)sharedDataAttachmentsDirPath +{ + return [[OWSFileSystem appSharedDataDirectoryPath] stringByAppendingPathComponent:@"Attachments"]; +} + ++ (void)migrateToSharedData +{ + [OWSFileSystem moveAppFilePath:self.legacyAttachmentsDirPath + sharedDataFilePath:self.sharedDataAttachmentsDirPath + exceptionName:@"CouldNotMigrateAttachmentsDirectory"]; +} + + (NSString *)attachmentsFolder { static NSString *attachmentsFolder = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ - NSString *documentsPath = - [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; - attachmentsFolder = [documentsPath stringByAppendingPathComponent:@"Attachments"]; + attachmentsFolder = TSAttachmentStream.sharedDataAttachmentsDirPath; BOOL isDirectory; BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:attachmentsFolder isDirectory:&isDirectory]; diff --git a/SignalServiceKit/src/Storage/TSStorageManager.h b/SignalServiceKit/src/Storage/TSStorageManager.h index b8e5f00075..38ce979888 100644 --- a/SignalServiceKit/src/Storage/TSStorageManager.h +++ b/SignalServiceKit/src/Storage/TSStorageManager.h @@ -63,9 +63,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nullable, nonatomic, readonly) YapDatabaseConnection *dbReadConnection; @property (nullable, nonatomic, readonly) YapDatabaseConnection *dbReadWriteConnection; -#pragma mark - Utilities - -- (void)protectFolderAtPath:(NSString *)path; ++ (void)migrateToSharedData; @end diff --git a/SignalServiceKit/src/Storage/TSStorageManager.m b/SignalServiceKit/src/Storage/TSStorageManager.m index fb9fe3c65e..5a2dd722c1 100644 --- a/SignalServiceKit/src/Storage/TSStorageManager.m +++ b/SignalServiceKit/src/Storage/TSStorageManager.m @@ -24,13 +24,18 @@ NS_ASSUME_NONNULL_BEGIN -NSString *const TSStorageManagerExceptionNameDatabasePasswordInaccessible = @"TSStorageManagerExceptionNameDatabasePasswordInaccessible"; -NSString *const TSStorageManagerExceptionNameDatabasePasswordInaccessibleWhileBackgrounded = - @"TSStorageManagerExceptionNameDatabasePasswordInaccessibleWhileBackgrounded"; -NSString *const TSStorageManagerExceptionNameDatabasePasswordUnwritable = @"TSStorageManagerExceptionNameDatabasePasswordUnwritable"; -NSString *const TSStorageManagerExceptionNameNoDatabase = @"TSStorageManagerExceptionNameNoDatabase"; +NSString *const TSStorageManagerExceptionName_DatabasePasswordInaccessible + = @"TSStorageManagerExceptionName_DatabasePasswordInaccessible"; +NSString *const TSStorageManagerExceptionName_DatabasePasswordInaccessibleWhileBackgrounded + = @"TSStorageManagerExceptionName_DatabasePasswordInaccessibleWhileBackgrounded"; +NSString *const TSStorageManagerExceptionName_DatabasePasswordUnwritable + = @"TSStorageManagerExceptionName_DatabasePasswordUnwritable"; +NSString *const TSStorageManagerExceptionName_NoDatabase = @"TSStorageManagerExceptionName_NoDatabase"; +NSString *const TSStorageManagerExceptionName_CouldNotMoveDatabaseFile + = @"TSStorageManagerExceptionName_CouldNotMoveDatabaseFile"; +NSString *const TSStorageManagerExceptionName_CouldNotCreateDatabaseDirectory + = @"TSStorageManagerExceptionName_CouldNotCreateDatabaseDirectory"; -static const NSString *const databaseName = @"Signal.sqlite"; static NSString *keychainService = @"TSKeyChainService"; static NSString *keychainDBPassAccount = @"TSDatabasePass"; @@ -202,10 +207,11 @@ void setDatabaseInitialized() static TSStorageManager *sharedManager = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ - sharedManager = [[self alloc] initDefault]; #if TARGET_OS_IPHONE - [sharedManager protectSignalFiles]; + [TSStorageManager protectSignalFiles]; #endif + + sharedManager = [[self alloc] initDefault]; }); return sharedManager; } @@ -231,7 +237,7 @@ void setDatabaseInitialized() // Sleep to give analytics events time to be delivered. [NSThread sleepForTimeInterval:15.0f]; - [NSException raise:TSStorageManagerExceptionNameNoDatabase format:@"Failed to initialize database."]; + [NSException raise:TSStorageManagerExceptionName_NoDatabase format:@"Failed to initialize database."]; } OWSSingletonAssert(); @@ -253,6 +259,7 @@ void setDatabaseInitialized() options.cipherKeyBlock = ^{ return databasePassword; }; + options.enableMultiProcessSupport = YES; #ifdef DEBUG _database = [[OWSDatabase alloc] initWithPath:[self dbPath] @@ -349,10 +356,16 @@ void setDatabaseInitialized() [TSDatabaseView asyncRegistrationCompletion]; } -- (void)protectSignalFiles { - [OWSFileSystem protectFolderAtPath:[self dbPath]]; - [OWSFileSystem protectFolderAtPath:[[self dbPath] stringByAppendingString:@"-shm"]]; - [OWSFileSystem protectFolderAtPath:[[self dbPath] stringByAppendingString:@"-wal"]]; ++ (void)protectSignalFiles +{ + // The old database location was in the Document directory, + // so protect the database files individually. + [OWSFileSystem protectFolderAtPath:self.legacyDatabaseFilePath]; + [OWSFileSystem protectFolderAtPath:self.legacyDatabaseFilePath_SHM]; + [OWSFileSystem protectFolderAtPath:self.legacyDatabaseFilePath_WAL]; + + // Protect the entire new database directory. + [OWSFileSystem protectFolderAtPath:self.sharedDataDatabaseDirPath]; } - (nullable YapDatabaseConnection *)newDatabaseConnection @@ -364,33 +377,99 @@ void setDatabaseInitialized() return FALSE; } -- (BOOL)dbExists { - return [[NSFileManager defaultManager] fileExistsAtPath:[self dbPath]]; ++ (NSString *)legacyDatabaseDirPath +{ + return [OWSFileSystem appDocumentDirectoryPath]; } -- (NSString *)dbPath { - NSString *databasePath; ++ (NSString *)sharedDataDatabaseDirPath +{ + NSString *databaseDirPath = [[OWSFileSystem appSharedDataDirectoryPath] stringByAppendingPathComponent:@"database"]; NSFileManager *fileManager = [NSFileManager defaultManager]; -#if TARGET_OS_IPHONE - NSURL *fileURL = [[fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; - NSString *path = [fileURL path]; - databasePath = [path stringByAppendingPathComponent:databaseName]; -#elif TARGET_OS_MAC - - NSString *bundleID = [[NSBundle mainBundle] bundleIdentifier]; - NSArray *urlPaths = [fileManager URLsForDirectory:NSApplicationSupportDirectory inDomains:NSUserDomainMask]; - - NSURL *appDirectory = [[urlPaths objectAtIndex:0] URLByAppendingPathComponent:bundleID isDirectory:YES]; - - if (![fileManager fileExistsAtPath:[appDirectory path]]) { - [fileManager createDirectoryAtURL:appDirectory withIntermediateDirectories:NO attributes:nil error:nil]; + if (![fileManager fileExistsAtPath:databaseDirPath]) { + NSError *_Nullable error; + BOOL success = [fileManager createDirectoryAtPath:databaseDirPath + withIntermediateDirectories:NO + attributes:nil + error:&error]; + if (!success || error) { + NSString *errorDescription = + [NSString stringWithFormat:@"%@ Could not create new database directory: %@, error: %@", + self.logTag, + databaseDirPath, + error]; + OWSFail(@"%@", errorDescription); + [NSException raise:TSStorageManagerExceptionName_CouldNotCreateDatabaseDirectory + format:@"%@", errorDescription]; + } } + return databaseDirPath; +} - databasePath = [appDirectory.filePathURL.absoluteString stringByAppendingPathComponent:databaseName]; -#endif ++ (NSString *)databaseFilename +{ + return @"Signal.sqlite"; +} - return databasePath; ++ (NSString *)databaseFilename_SHM +{ + return [self.databaseFilename stringByAppendingString:@"-shm"]; +} + ++ (NSString *)databaseFilename_WAL +{ + return [self.databaseFilename stringByAppendingString:@"-wal"]; +} + ++ (NSString *)legacyDatabaseFilePath +{ + return [self.legacyDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename]; +} + ++ (NSString *)legacyDatabaseFilePath_SHM +{ + return [self.legacyDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename_SHM]; +} + ++ (NSString *)legacyDatabaseFilePath_WAL +{ + return [self.legacyDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename_WAL]; +} + ++ (NSString *)sharedDataDatabaseFilePath +{ + return [self.sharedDataDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename]; +} + ++ (NSString *)sharedDataDatabaseFilePath_SHM +{ + return [self.sharedDataDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename_SHM]; +} + ++ (NSString *)sharedDataDatabaseFilePath_WAL +{ + return [self.sharedDataDatabaseDirPath stringByAppendingPathComponent:self.databaseFilename_WAL]; +} + ++ (void)migrateToSharedData +{ + [OWSFileSystem moveAppFilePath:self.legacyDatabaseFilePath + sharedDataFilePath:self.sharedDataDatabaseFilePath + exceptionName:TSStorageManagerExceptionName_CouldNotMoveDatabaseFile]; + [OWSFileSystem moveAppFilePath:self.legacyDatabaseFilePath_SHM + sharedDataFilePath:self.sharedDataDatabaseFilePath_SHM + exceptionName:TSStorageManagerExceptionName_CouldNotMoveDatabaseFile]; + [OWSFileSystem moveAppFilePath:self.legacyDatabaseFilePath_WAL + sharedDataFilePath:self.sharedDataDatabaseFilePath_WAL + exceptionName:TSStorageManagerExceptionName_CouldNotMoveDatabaseFile]; +} + +- (NSString *)dbPath +{ + DDLogVerbose(@"databasePath: %@", TSStorageManager.sharedDataDatabaseFilePath); + + return TSStorageManager.sharedDataDatabaseFilePath; } + (BOOL)isDatabasePasswordAccessible @@ -421,7 +500,7 @@ void setDatabaseInitialized() // Presumably this happened in response to a push notification. It's possible that the keychain is corrupted // but it could also just be that the user hasn't yet unlocked their device since our password is // kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly - [NSException raise:TSStorageManagerExceptionNameDatabasePasswordInaccessibleWhileBackgrounded + [NSException raise:TSStorageManagerExceptionName_DatabasePasswordInaccessibleWhileBackgrounded format:@"%@", errorDescription]; } @@ -483,7 +562,7 @@ void setDatabaseInitialized() // Sleep to give analytics events time to be delivered. [NSThread sleepForTimeInterval:15.0f]; - [NSException raise:TSStorageManagerExceptionNameDatabasePasswordUnwritable + [NSException raise:TSStorageManagerExceptionName_DatabasePasswordUnwritable format:@"Setting DB password failed with error: %@", keySetError]; } else { DDLogWarn(@"Succesfully set new DB password."); diff --git a/SignalServiceKit/src/TSConstants.h b/SignalServiceKit/src/TSConstants.h index cefd281a0d..717e2e0fc0 100644 --- a/SignalServiceKit/src/TSConstants.h +++ b/SignalServiceKit/src/TSConstants.h @@ -57,6 +57,8 @@ typedef enum { kSMSVerification, kPhoneNumberVerification } VerificationTranspor #define textSecureSetProfileNameAPIFormat @"v1/profile/name/%@" #define textSecureProfileAvatarFormAPI @"v1/profile/form/avatar" +#define SignalApplicationGroup @"group.org.whispersystems.signal.group" + #pragma mark Push RegistrationSpecific Constants typedef NS_ENUM(NSInteger, TSPushRegistrationError) { TSPushRegistrationErrorNetwork, diff --git a/SignalServiceKit/src/Util/AppVersion.m b/SignalServiceKit/src/Util/AppVersion.m index 44fc998075..2c5dd88158 100755 --- a/SignalServiceKit/src/Util/AppVersion.m +++ b/SignalServiceKit/src/Util/AppVersion.m @@ -3,6 +3,7 @@ // #import "AppVersion.h" +#import NSString *const kNSUserDefaults_FirstAppVersion = @"kNSUserDefaults_FirstAppVersion"; NSString *const kNSUserDefaults_LastAppVersion = @"kNSUserDefaults_LastVersion"; @@ -36,24 +37,22 @@ NSString *const kNSUserDefaults_LastCompletedLaunchAppVersion = @"kNSUserDefault // The version of the app when it was first launched. // nil if the app has never been launched before. - self.firstAppVersion = [[NSUserDefaults standardUserDefaults] objectForKey:kNSUserDefaults_FirstAppVersion]; + self.firstAppVersion = [[NSUserDefaults appUserDefaults] objectForKey:kNSUserDefaults_FirstAppVersion]; // The version of the app the last time it was launched. // nil if the app has never been launched before. - self.lastAppVersion = [[NSUserDefaults standardUserDefaults] objectForKey:kNSUserDefaults_LastAppVersion]; + self.lastAppVersion = [[NSUserDefaults appUserDefaults] objectForKey:kNSUserDefaults_LastAppVersion]; self.lastCompletedLaunchAppVersion = - [[NSUserDefaults standardUserDefaults] objectForKey:kNSUserDefaults_LastCompletedLaunchAppVersion]; + [[NSUserDefaults appUserDefaults] objectForKey:kNSUserDefaults_LastCompletedLaunchAppVersion]; // Ensure the value for the "first launched version". if (!self.firstAppVersion) { self.firstAppVersion = self.currentAppVersion; - [[NSUserDefaults standardUserDefaults] setObject:self.currentAppVersion - forKey:kNSUserDefaults_FirstAppVersion]; + [[NSUserDefaults appUserDefaults] setObject:self.currentAppVersion forKey:kNSUserDefaults_FirstAppVersion]; } // Update the value for the "most recently launched version". - [[NSUserDefaults standardUserDefaults] setObject:self.currentAppVersion - forKey:kNSUserDefaults_LastAppVersion]; - [[NSUserDefaults standardUserDefaults] synchronize]; + [[NSUserDefaults appUserDefaults] setObject:self.currentAppVersion forKey:kNSUserDefaults_LastAppVersion]; + [[NSUserDefaults appUserDefaults] synchronize]; DDLogInfo(@"%@ firstAppVersion: %@", self.logTag, self.firstAppVersion); DDLogInfo(@"%@ lastAppVersion: %@", self.logTag, self.lastAppVersion); @@ -68,9 +67,9 @@ NSString *const kNSUserDefaults_LastCompletedLaunchAppVersion = @"kNSUserDefault self.lastCompletedLaunchAppVersion = self.currentAppVersion; // Update the value for the "most recently launch-completed version". - [[NSUserDefaults standardUserDefaults] setObject:self.currentAppVersion - forKey:kNSUserDefaults_LastCompletedLaunchAppVersion]; - [[NSUserDefaults standardUserDefaults] synchronize]; + [[NSUserDefaults appUserDefaults] setObject:self.currentAppVersion + forKey:kNSUserDefaults_LastCompletedLaunchAppVersion]; + [[NSUserDefaults appUserDefaults] synchronize]; } - (BOOL)isFirstLaunch diff --git a/SignalServiceKit/src/Util/NSUserDefaults+OWS.h b/SignalServiceKit/src/Util/NSUserDefaults+OWS.h new file mode 100644 index 0000000000..24bbbcbc23 --- /dev/null +++ b/SignalServiceKit/src/Util/NSUserDefaults+OWS.h @@ -0,0 +1,17 @@ +// +// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// + +NS_ASSUME_NONNULL_BEGIN + +@interface NSUserDefaults (OWS) + ++ (NSUserDefaults *)appUserDefaults; + ++ (void)migrateToSharedUserDefaults; + ++ (void)removeAll; + +@end + +NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Util/NSUserDefaults+OWS.m b/SignalServiceKit/src/Util/NSUserDefaults+OWS.m new file mode 100644 index 0000000000..746630d0ea --- /dev/null +++ b/SignalServiceKit/src/Util/NSUserDefaults+OWS.m @@ -0,0 +1,46 @@ +// +// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// + +#import "NSUserDefaults+OWS.h" +#import "TSConstants.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation NSUserDefaults (OWS) + ++ (NSUserDefaults *)appUserDefaults +{ + return [[NSUserDefaults alloc] initWithSuiteName:SignalApplicationGroup]; +} + ++ (void)migrateToSharedUserDefaults +{ + NSUserDefaults *appUserDefaults = self.appUserDefaults; + + NSDictionary *dictionary = [NSUserDefaults standardUserDefaults].dictionaryRepresentation; + for (NSString *key in dictionary) { + id value = dictionary[key]; + OWSAssert(value); + [appUserDefaults setObject:value forKey:key]; + } +} + ++ (void)removeAll +{ + [NSUserDefaults.standardUserDefaults removeAll]; + [self.appUserDefaults removeAll]; +} + +- (void)removeAll +{ + NSDictionary *dictionary = self.dictionaryRepresentation; + for (NSString *key in dictionary) { + [self removeObjectForKey:key]; + } + [self synchronize]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Util/OWSFileSystem.h b/SignalServiceKit/src/Util/OWSFileSystem.h index 3eae177bb7..b9abd6a5d8 100644 --- a/SignalServiceKit/src/Util/OWSFileSystem.h +++ b/SignalServiceKit/src/Util/OWSFileSystem.h @@ -10,6 +10,14 @@ NS_ASSUME_NONNULL_BEGIN + (void)protectFolderAtPath:(NSString *)path; ++ (NSString *)appDocumentDirectoryPath; + ++ (NSString *)appSharedDataDirectoryPath; + ++ (void)moveAppFilePath:(NSString *)oldFilePath + sharedDataFilePath:(NSString *)newFilePath + exceptionName:(NSString *)exceptionName; + @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Util/OWSFileSystem.m b/SignalServiceKit/src/Util/OWSFileSystem.m index 6e69eb0e20..8746b14433 100644 --- a/SignalServiceKit/src/Util/OWSFileSystem.m +++ b/SignalServiceKit/src/Util/OWSFileSystem.m @@ -3,6 +3,7 @@ // #import "OWSFileSystem.h" +#import "TSConstants.h" NS_ASSUME_NONNULL_BEGIN @@ -28,6 +29,59 @@ NS_ASSUME_NONNULL_BEGIN } } ++ (NSString *)appDocumentDirectoryPath +{ + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSURL *documentDirectoryURL = + [[fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; + return [documentDirectoryURL path]; +} + ++ (NSString *)appSharedDataDirectoryPath +{ + NSURL *groupContainerDirectoryURL = + [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:SignalApplicationGroup]; + return [groupContainerDirectoryURL path]; +} + ++ (void)moveAppFilePath:(NSString *)oldFilePath + sharedDataFilePath:(NSString *)newFilePath + exceptionName:(NSString *)exceptionName +{ + NSFileManager *fileManager = [NSFileManager defaultManager]; + if (![fileManager fileExistsAtPath:oldFilePath]) { + return; + } + if ([fileManager fileExistsAtPath:newFilePath]) { + OWSFail(@"%@ Can't move file or directory from %@ to %@; destination already exists.", + self.logTag, + oldFilePath, + newFilePath); + return; + } + + NSDate *startDate = [NSDate new]; + + NSError *_Nullable error; + BOOL success = [fileManager moveItemAtPath:oldFilePath toPath:newFilePath error:&error]; + if (!success || error) { + NSString *errorDescription = + [NSString stringWithFormat:@"%@ Could not move file or directory from %@ to %@, error: %@", + self.logTag, + oldFilePath, + newFilePath, + error]; + OWSFail(@"%@", errorDescription); + [NSException raise:exceptionName format:@"%@", errorDescription]; + } + + DDLogInfo(@"%@ Moving file or directory from %@ to %@ in: %f", + self.logTag, + oldFilePath, + newFilePath, + fabs([startDate timeIntervalSinceNow])); +} + @end NS_ASSUME_NONNULL_END