diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index e5da00fb3..0fb95c169 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -76,7 +76,7 @@ 346129DA1FD5B84900532771 /* SAENotificationsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 346129D81FD5B84900532771 /* SAENotificationsManager.swift */; }; 346129DE1FD5C02A00532771 /* LockInteractionController.h in Headers */ = {isa = PBXBuildFile; fileRef = 346129DC1FD5C02900532771 /* LockInteractionController.h */; }; 346129DF1FD5C02A00532771 /* LockInteractionController.m in Sources */ = {isa = PBXBuildFile; fileRef = 346129DD1FD5C02900532771 /* LockInteractionController.m */; }; - 346129E21FD5C0BE00532771 /* VersionMigrations.h in Headers */ = {isa = PBXBuildFile; fileRef = 346129E01FD5C0BE00532771 /* VersionMigrations.h */; }; + 346129E21FD5C0BE00532771 /* VersionMigrations.h in Headers */ = {isa = PBXBuildFile; fileRef = 346129E01FD5C0BE00532771 /* VersionMigrations.h */; settings = {ATTRIBUTES = (Public, ); }; }; 346129E31FD5C0BE00532771 /* VersionMigrations.m in Sources */ = {isa = PBXBuildFile; fileRef = 346129E11FD5C0BE00532771 /* VersionMigrations.m */; }; 346129E61FD5C0C600532771 /* OWSDatabaseMigrationRunner.m in Sources */ = {isa = PBXBuildFile; fileRef = 346129E41FD5C0C600532771 /* OWSDatabaseMigrationRunner.m */; }; 346129E71FD5C0C600532771 /* OWSDatabaseMigrationRunner.h in Headers */ = {isa = PBXBuildFile; fileRef = 346129E51FD5C0C600532771 /* OWSDatabaseMigrationRunner.h */; }; diff --git a/Signal/src/AppDelegate.m b/Signal/src/AppDelegate.m index 574ac9896..518e66119 100644 --- a/Signal/src/AppDelegate.m +++ b/Signal/src/AppDelegate.m @@ -56,7 +56,6 @@ static NSString *const kURLHostVerifyPrefix = @"verify"; @interface AppDelegate () @property (nonatomic) UIWindow *screenProtectionWindow; -@property (nonatomic) OWSContactsSyncing *contactsSyncing; @property (nonatomic) BOOL hasInitialRootViewController; @end @@ -167,10 +166,7 @@ static NSString *const kURLHostVerifyPrefix = @"verify"; [self prepareScreenProtection]; - self.contactsSyncing = [[OWSContactsSyncing alloc] initWithContactsManager:[Environment current].contactsManager - identityManager:[OWSIdentityManager sharedManager] - messageSender:[Environment current].messageSender - profileManager:[OWSProfileManager sharedManager]]; + [OWSContactsSyncing sharedManager]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(databaseViewRegistrationComplete) diff --git a/Signal/test/TestUtil.h b/Signal/test/TestUtil.h index bcf80ce39..b327f0845 100644 --- a/Signal/test/TestUtil.h +++ b/Signal/test/TestUtil.h @@ -10,7 +10,5 @@ #define test(expressionExpectedToBeTrue) XCTAssert(expressionExpectedToBeTrue, @"") #define testThrows(expressionExpectedToThrow) XCTAssertThrows(expressionExpectedToThrow, @"") #define testDoesNotThrow(expressionExpectedToNotThrow) expressionExpectedToNotThrow -#define testEnv [Release unitTestEnvironment:@[]] -#define testEnvWith(options) [Release unitTestEnvironment:(@[options])] #define testChurnUntil(condition, timeout) test(_testChurnHelper(^int{ return condition; }, timeout)) #define testChurnAndConditionMustStayTrue(condition, timeout) test(!_testChurnHelper(^int{ return !(condition); }, timeout)) diff --git a/SignalMessaging/SignalMessaging.h b/SignalMessaging/SignalMessaging.h index 5c087d642..c9f025d28 100644 --- a/SignalMessaging/SignalMessaging.h +++ b/SignalMessaging/SignalMessaging.h @@ -29,3 +29,4 @@ FOUNDATION_EXPORT const unsigned char SignalMessagingVersionString[]; #import #import #import +#import diff --git a/SignalMessaging/contacts/OWSContactsSyncing.h b/SignalMessaging/contacts/OWSContactsSyncing.h index 64989f293..85cdef2ed 100644 --- a/SignalMessaging/contacts/OWSContactsSyncing.h +++ b/SignalMessaging/contacts/OWSContactsSyncing.h @@ -11,10 +11,9 @@ NS_ASSUME_NONNULL_BEGIN @interface OWSContactsSyncing : NSObject -- (instancetype)initWithContactsManager:(OWSContactsManager *)contactsManager - identityManager:(OWSIdentityManager *)identityManager - messageSender:(OWSMessageSender *)messageSender - profileManager:(OWSProfileManager *)profileManager; +- (instancetype)init NS_UNAVAILABLE; + ++ (instancetype)sharedManager; @end diff --git a/SignalMessaging/contacts/OWSContactsSyncing.m b/SignalMessaging/contacts/OWSContactsSyncing.m index 6d234d17c..140fb4669 100644 --- a/SignalMessaging/contacts/OWSContactsSyncing.m +++ b/SignalMessaging/contacts/OWSContactsSyncing.m @@ -3,6 +3,7 @@ // #import "OWSContactsSyncing.h" +#import "Environment.h" #import "OWSContactsManager.h" #import "OWSProfileManager.h" #import @@ -33,6 +34,24 @@ NSString *const kTSStorageManagerOWSContactsSyncingLastMessageKey @implementation OWSContactsSyncing ++ (instancetype)sharedManager +{ + static OWSContactsSyncing *instance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + instance = [[self alloc] initDefault]; + }); + return instance; +} + +- (instancetype)initDefault +{ + return [self initWithContactsManager:Environment.current.contactsManager + identityManager:OWSIdentityManager.sharedManager + messageSender:Environment.current.messageSender + profileManager:OWSProfileManager.sharedManager]; +} + - (instancetype)initWithContactsManager:(OWSContactsManager *)contactsManager identityManager:(OWSIdentityManager *)identityManager messageSender:(OWSMessageSender *)messageSender diff --git a/SignalMessaging/environment/Environment.m b/SignalMessaging/environment/Environment.m index cf71715c0..4bc5b050b 100644 --- a/SignalMessaging/environment/Environment.m +++ b/SignalMessaging/environment/Environment.m @@ -5,6 +5,7 @@ #import "Environment.h" #import "DebugLogger.h" #import "SignalKeyingStorage.h" +#import #import #import #import @@ -37,7 +38,7 @@ static Environment *sharedEnvironment = nil; + (void)setCurrent:(Environment *)environment { - OWSAssert(!sharedEnvironment); + OWSAssert(!sharedEnvironment || !CurrentAppContext().isMainApp); OWSAssert(environment); sharedEnvironment = environment; diff --git a/SignalMessaging/environment/Release.h b/SignalMessaging/environment/Release.h index e95d22a79..c1e68be3a 100644 --- a/SignalMessaging/environment/Release.h +++ b/SignalMessaging/environment/Release.h @@ -9,9 +9,4 @@ /// Connects to actual production infrastructure + (Environment *)releaseEnvironment; -+ (Environment *)stagingEnvironment; - -/// Fake environment with no logging -+ (Environment *)unitTestEnvironment:(NSArray *)testingAndLegacyOptions; - @end diff --git a/SignalMessaging/environment/Release.m b/SignalMessaging/environment/Release.m index f36326bc5..671130afc 100644 --- a/SignalMessaging/environment/Release.m +++ b/SignalMessaging/environment/Release.m @@ -14,56 +14,25 @@ + (Environment *)releaseEnvironment { - // Order matters here. - TSStorageManager *storageManager = [TSStorageManager sharedManager]; - TSNetworkManager *networkManager = [TSNetworkManager sharedManager]; - OWSContactsManager *contactsManager = [OWSContactsManager new]; - ContactsUpdater *contactsUpdater = [ContactsUpdater sharedUpdater]; - OWSMessageSender *messageSender = [[OWSMessageSender alloc] initWithNetworkManager:networkManager - storageManager:storageManager - contactsManager:contactsManager - contactsUpdater:contactsUpdater]; - - return [[Environment alloc] initWithContactsManager:contactsManager - contactsUpdater:contactsUpdater - networkManager:networkManager - messageSender:messageSender]; -} - -// TODELETE -+ (Environment *)stagingEnvironment -{ - // Order matters here. - TSStorageManager *storageManager = [TSStorageManager sharedManager]; - TSNetworkManager *networkManager = [TSNetworkManager sharedManager]; - OWSContactsManager *contactsManager = [OWSContactsManager new]; - ContactsUpdater *contactsUpdater = [ContactsUpdater sharedUpdater]; - OWSMessageSender *messageSender = [[OWSMessageSender alloc] initWithNetworkManager:networkManager - storageManager:storageManager - contactsManager:contactsManager - contactsUpdater:contactsUpdater]; - - return [[Environment alloc] initWithContactsManager:contactsManager - contactsUpdater:contactsUpdater - networkManager:networkManager - messageSender:messageSender]; -} - -// TODELETE -+ (Environment *)unitTestEnvironment:(NSArray *)testingAndLegacyOptions -{ - TSNetworkManager *networkManager = [TSNetworkManager sharedManager]; - OWSContactsManager *contactsManager = [OWSContactsManager new]; - ContactsUpdater *contactsUpdater = [ContactsUpdater sharedUpdater]; - OWSMessageSender *messageSender = [[OWSMessageSender alloc] initWithNetworkManager:networkManager - storageManager:[TSStorageManager sharedManager] - contactsManager:contactsManager - contactsUpdater:contactsUpdater]; - - return [[Environment alloc] initWithContactsManager:nil - contactsUpdater:contactsUpdater - networkManager:networkManager - messageSender:messageSender]; + static Environment *instance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + // Order matters here. + TSStorageManager *storageManager = [TSStorageManager sharedManager]; + TSNetworkManager *networkManager = [TSNetworkManager sharedManager]; + OWSContactsManager *contactsManager = [OWSContactsManager new]; + ContactsUpdater *contactsUpdater = [ContactsUpdater sharedUpdater]; + OWSMessageSender *messageSender = [[OWSMessageSender alloc] initWithNetworkManager:networkManager + storageManager:storageManager + contactsManager:contactsManager + contactsUpdater:contactsUpdater]; + + instance = [[Environment alloc] initWithContactsManager:contactsManager + contactsUpdater:contactsUpdater + networkManager:networkManager + messageSender:messageSender]; + }); + return instance; } @end diff --git a/SignalServiceKit/src/TextSecureKitEnv.m b/SignalServiceKit/src/TextSecureKitEnv.m index 8bda6af70..a85015892 100644 --- a/SignalServiceKit/src/TextSecureKitEnv.m +++ b/SignalServiceKit/src/TextSecureKitEnv.m @@ -3,16 +3,25 @@ // #import "TextSecureKitEnv.h" +#import "AppContext.h" NS_ASSUME_NONNULL_BEGIN -static TextSecureKitEnv *TextSecureKitEnvSharedInstance; +static TextSecureKitEnv *sharedTextSecureKitEnv; -@implementation TextSecureKitEnv +@interface TextSecureKitEnv () + +@property (nonatomic) id callMessageHandler; +@property (nonatomic) id contactsManager; +@property (nonatomic) OWSMessageSender *messageSender; +@property (nonatomic) id notificationsManager; +@property (nonatomic) id profileManager; + +@end + +#pragma mark - -@synthesize callMessageHandler = _callMessageHandler, contactsManager = _contactsManager, - messageSender = _messageSender, notificationsManager = _notificationsManager, - profileManager = _profileManager; +@implementation TextSecureKitEnv - (instancetype)initWithCallMessageHandler:(id)callMessageHandler contactsManager:(id)contactsManager @@ -25,6 +34,12 @@ static TextSecureKitEnv *TextSecureKitEnvSharedInstance; return self; } + OWSAssert(callMessageHandler); + OWSAssert(contactsManager); + OWSAssert(messageSender); + OWSAssert(notificationsManager); + OWSAssert(profileManager); + _callMessageHandler = callMessageHandler; _contactsManager = contactsManager; _messageSender = messageSender; @@ -36,48 +51,17 @@ static TextSecureKitEnv *TextSecureKitEnvSharedInstance; + (instancetype)sharedEnv { - NSAssert(TextSecureKitEnvSharedInstance, @"Trying to access shared TextSecureKitEnv before it's been set"); - return TextSecureKitEnvSharedInstance; -} - -+ (void)setSharedEnv:(TextSecureKitEnv *)env -{ - @synchronized (self) { - NSAssert(TextSecureKitEnvSharedInstance == nil, @"Trying to set shared TextSecureKitEnv which has already been set"); - TextSecureKitEnvSharedInstance = env; - } -} - -#pragma mark - getters - -- (id)callMessageHandler -{ - NSAssert(_callMessageHandler, @"Trying to access the callMessageHandler before it's set."); - return _callMessageHandler; -} - -- (id)contactsManager -{ - NSAssert(_contactsManager, @"Trying to access the contactsManager before it's set."); - return _contactsManager; -} + OWSAssert(sharedTextSecureKitEnv); -- (OWSMessageSender *)messageSender -{ - NSAssert(_messageSender, @"Trying to access the messageSender before it's set."); - return _messageSender; + return sharedTextSecureKitEnv; } -- (id)notificationsManager ++ (void)setSharedEnv:(TextSecureKitEnv *)env { - NSAssert(_notificationsManager, @"Trying to access the notificationsManager before it's set."); - return _notificationsManager; -} + OWSAssert(env); + OWSAssert(!sharedTextSecureKitEnv || !CurrentAppContext().isMainApp); -- (id)profileManager -{ - NSAssert(_profileManager, @"Trying to access the profileManager before it's set."); - return _profileManager; + sharedTextSecureKitEnv = env; } @end diff --git a/SignalServiceKit/src/Util/AppContext.m b/SignalServiceKit/src/Util/AppContext.m index c9b32ff39..f38b586da 100755 --- a/SignalServiceKit/src/Util/AppContext.m +++ b/SignalServiceKit/src/Util/AppContext.m @@ -17,7 +17,11 @@ id CurrentAppContext(void) void SetCurrentAppContext(id appContext) { - OWSCAssert(!currentAppContext); + // The main app context should only be set once. + // + // App extensions may be opened multiple times in the same process, + // so statics will persist. + OWSCAssert(!currentAppContext || !currentAppContext.isMainApp); currentAppContext = appContext; } diff --git a/SignalShareExtension/SAECallMessageHandler.swift b/SignalShareExtension/SAECallMessageHandler.swift index 64a020110..df23ca8b5 100644 --- a/SignalShareExtension/SAECallMessageHandler.swift +++ b/SignalShareExtension/SAECallMessageHandler.swift @@ -4,7 +4,8 @@ import SignalServiceKit -class SAECallMessageHandler: NSObject, OWSCallMessageHandler { +@objc +public class SAECallMessageHandler: NSObject, OWSCallMessageHandler { public func receivedOffer(_ offer: OWSSignalServiceProtosCallMessageOffer, from callerId: String) { owsFail("\(self.logTag) in \(#function).") diff --git a/SignalShareExtension/SAENotificationsManager.swift b/SignalShareExtension/SAENotificationsManager.swift index e3be12302..b060a6a33 100644 --- a/SignalShareExtension/SAENotificationsManager.swift +++ b/SignalShareExtension/SAENotificationsManager.swift @@ -4,7 +4,8 @@ import SignalServiceKit -class SAENotificationsManager: NSObject, NotificationsProtocol { +@objc +public class SAENotificationsManager: NSObject, NotificationsProtocol { public func notifyUser(for incomingMessage: TSIncomingMessage!, in thread: TSThread!, contactsManager: ContactsManagerProtocol!, transaction: YapDatabaseReadTransaction!) { owsFail("\(self.logTag) in \(#function).") diff --git a/SignalShareExtension/ShareViewController.swift b/SignalShareExtension/ShareViewController.swift index 23d4e7630..766c34740 100644 --- a/SignalShareExtension/ShareViewController.swift +++ b/SignalShareExtension/ShareViewController.swift @@ -12,8 +12,6 @@ import PromiseKit @objc public class ShareViewController: UINavigationController, SAELoadViewDelegate, SAEFailedViewDelegate { - private var contactsSyncing: OWSContactsSyncing? - private var hasInitialRootViewController = false private var isReadyForAppExtensions = false @@ -23,12 +21,13 @@ public class ShareViewController: UINavigationController, SAELoadViewDelegate, S Logger.debug("\(self.logTag()) \(#function)") // This should be the first thing we do. - SetCurrentAppContext(ShareAppExtensionContext(rootViewController:self)) + let appContext = ShareAppExtensionContext(rootViewController:self) + SetCurrentAppContext(appContext) DebugLogger.shared().enableTTYLogging() if _isDebugAssertConfiguration() { DebugLogger.shared().enableFileLogging() - } else if (OWSPreferences.isLoggingEnabled()) { + } else if OWSPreferences.isLoggingEnabled() { DebugLogger.shared().enableFileLogging() } @@ -40,7 +39,7 @@ public class ShareViewController: UINavigationController, SAELoadViewDelegate, S // We don't need to use DeviceSleepManager in the SAE. - setupEnvironment() + appContext.setupEnvironment() // TODO: // [UIUtil applySignalAppearence]; @@ -60,7 +59,7 @@ public class ShareViewController: UINavigationController, SAELoadViewDelegate, S // If we don't have TSSStorageManager, we can't consult TSAccountManager // for isRegistered, so we use OWSPreferences which is usually-accurate // copy of that state. - if (OWSPreferences.isRegistered()) { + if OWSPreferences.isRegistered() { showNotReadyView() } else { showNotRegisteredView() @@ -78,10 +77,7 @@ public class ShareViewController: UINavigationController, SAELoadViewDelegate, S // We don't need to use "screen protection" in the SAE. - contactsSyncing = OWSContactsSyncing(contactsManager:Environment.current().contactsManager, - identityManager:OWSIdentityManager.shared(), - messageSender:Environment.current().messageSender, - profileManager:OWSProfileManager.shared()) + OWSContactsSyncing.sharedManager() NotificationCenter.default.addObserver(self, selector: #selector(databaseViewRegistrationComplete), @@ -255,27 +251,6 @@ public class ShareViewController: UINavigationController, SAELoadViewDelegate, S } } - func setupEnvironment() { - let environment = Release.releaseEnvironment() - Environment.setCurrent(environment) - - // Encryption/Decryption mutates session state and must be synchronized on a serial queue. - SessionCipher.setSessionCipherDispatchQueue(OWSDispatch.sessionStoreQueue()) - - let sharedEnv = TextSecureKitEnv(callMessageHandler:SAECallMessageHandler(), - contactsManager:Environment.current().contactsManager, - messageSender:Environment.current().messageSender, - notificationsManager:SAENotificationsManager(), - profileManager:OWSProfileManager.shared()) - TextSecureKitEnv.setShared(sharedEnv) - - TSStorageManager.shared().setupDatabase(safeBlockingMigrations: { - VersionMigrations.runSafeBlockingMigrations() - }) - - Environment.current().contactsManager.startObserving() - } - // MARK: Error Views private func showNotReadyView() { diff --git a/SignalShareExtension/utils/ShareAppExtensionContext.h b/SignalShareExtension/utils/ShareAppExtensionContext.h index cd9a1a39d..9eb19c92c 100644 --- a/SignalShareExtension/utils/ShareAppExtensionContext.h +++ b/SignalShareExtension/utils/ShareAppExtensionContext.h @@ -6,12 +6,15 @@ NS_ASSUME_NONNULL_BEGIN +// This is _NOT_ a singleton and will be instantiated each time that the SAE is used. @interface ShareAppExtensionContext : NSObject - (instancetype)init NS_UNAVAILABLE; - (instancetype)initWithRootViewController:(UIViewController *)rootViewController; +- (void)setupEnvironment; + @end NS_ASSUME_NONNULL_END diff --git a/SignalShareExtension/utils/ShareAppExtensionContext.m b/SignalShareExtension/utils/ShareAppExtensionContext.m index a28a8491f..89e135b23 100644 --- a/SignalShareExtension/utils/ShareAppExtensionContext.m +++ b/SignalShareExtension/utils/ShareAppExtensionContext.m @@ -3,7 +3,15 @@ // #import "ShareAppExtensionContext.h" +#import "SignalShareExtension-Swift.h" +#import +#import +#import +#import +#import #import +#import +#import NS_ASSUME_NONNULL_BEGIN @@ -29,8 +37,6 @@ NS_ASSUME_NONNULL_BEGIN _rootViewController = rootViewController; - OWSSingletonAssert(); - return self; } @@ -118,6 +124,30 @@ NS_ASSUME_NONNULL_BEGIN OWSFail(@"%@ called %s.", self.logTag, __PRETTY_FUNCTION__); } +- (void)setupEnvironment +{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + [Environment setCurrent:[Release releaseEnvironment]]; + + // Encryption/Decryption mutates session state and must be synchronized on a serial queue. + [SessionCipher setSessionCipherDispatchQueue:[OWSDispatch sessionStoreQueue]]; + + TextSecureKitEnv *sharedEnv = + [[TextSecureKitEnv alloc] initWithCallMessageHandler:[SAECallMessageHandler new] + contactsManager:[Environment current].contactsManager + messageSender:[Environment current].messageSender + notificationsManager:[SAENotificationsManager new] + profileManager:OWSProfileManager.sharedManager]; + [TextSecureKitEnv setSharedEnv:sharedEnv]; + + [[TSStorageManager sharedManager] setupDatabaseWithSafeBlockingMigrations:^{ + [VersionMigrations runSafeBlockingMigrations]; + }]; + [[Environment current].contactsManager startObserving]; + }); +} + @end NS_ASSUME_NONNULL_END