diff --git a/Podfile b/Podfile index bef8dfdd0..96143a95f 100644 --- a/Podfile +++ b/Podfile @@ -9,8 +9,9 @@ def shared_pods pod 'SQLCipher', :git => 'https://github.com/sqlcipher/sqlcipher.git', :commit => 'd5c2bec' # pod 'YapDatabase/SQLCipher', path: '../YapDatabase' pod 'YapDatabase/SQLCipher', :git => 'https://github.com/WhisperSystems/YapDatabase.git', branch: 'release/unencryptedHeaders' + pod 'AxolotlKit', path: '../SignalProtocolKit' pod 'SignalServiceKit', path: '.' - pod 'AxolotlKit', git: 'https://github.com/WhisperSystems/SignalProtocolKit.git', branch: 'mkirk/framework-friendly' + # pod 'AxolotlKit', git: 'https://github.com/WhisperSystems/SignalProtocolKit.git', branch: 'mkirk/framework-friendly' #pod 'AxolotlKit', path: '../SignalProtocolKit' pod 'HKDFKit', git: 'https://github.com/WhisperSystems/HKDFKit.git', branch: 'mkirk/framework-friendly' #pod 'HKDFKit', path: '../HKDFKit' diff --git a/Podfile.lock b/Podfile.lock index c2906f6ef..f3f119eb0 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -129,7 +129,7 @@ PODS: DEPENDENCIES: - AFNetworking - ATAppUpdater - - AxolotlKit (from `https://github.com/WhisperSystems/SignalProtocolKit.git`, branch `mkirk/framework-friendly`) + - AxolotlKit (from `../SignalProtocolKit`) - Curve25519Kit (from `https://github.com/WhisperSystems/Curve25519Kit`, branch `mkirk/framework-friendly`) - GRKOpenSSLFramework (from `https://github.com/WhisperSystems/GRKOpenSSLFramework`) - HKDFKit (from `https://github.com/WhisperSystems/HKDFKit.git`, branch `mkirk/framework-friendly`) @@ -146,8 +146,7 @@ DEPENDENCIES: EXTERNAL SOURCES: AxolotlKit: - :branch: mkirk/framework-friendly - :git: https://github.com/WhisperSystems/SignalProtocolKit.git + :path: ../SignalProtocolKit Curve25519Kit: :branch: mkirk/framework-friendly :git: https://github.com/WhisperSystems/Curve25519Kit @@ -171,9 +170,6 @@ EXTERNAL SOURCES: :git: https://github.com/WhisperSystems/YapDatabase.git CHECKOUT OPTIONS: - AxolotlKit: - :commit: 6dd55895b523e887c633bd31b9eedbfb515b8a5d - :git: https://github.com/WhisperSystems/SignalProtocolKit.git Curve25519Kit: :commit: 03a19c80aafc10a3464f0c086b1eb38239c507ac :git: https://github.com/WhisperSystems/Curve25519Kit @@ -221,6 +217,6 @@ SPEC CHECKSUMS: YapDatabase: 299a32de9d350d37a9ac5b0532609d87d5d2a5de YYImage: 1e1b62a9997399593e4b9c4ecfbbabbf1d3f3b54 -PODFILE CHECKSUM: 0d804514eb2db34b9874b653e543255d8c2f5751 +PODFILE CHECKSUM: d1c081f5e8cda394caa2bfbb157d628f33352cff COCOAPODS: 1.3.1 diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index d52c9cd19..9c0202b95 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -3152,11 +3152,7 @@ "DEBUG=1", "$(inherited)", ); - "GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = ( - "DEBUG=1", - "$(inherited)", - "SSK_BUILDING_FOR_TESTS=1", - ); + "GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = "DEBUG=1 $(inherited) SSK_BUILDING_FOR_TESTS=1"; GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; diff --git a/Signal/src/ViewControllers/DebugUI/DebugUISessionState.m b/Signal/src/ViewControllers/DebugUI/DebugUISessionState.m index 2c1058192..7ffd02f3b 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUISessionState.m +++ b/Signal/src/ViewControllers/DebugUI/DebugUISessionState.m @@ -55,7 +55,8 @@ NS_ASSUME_NONNULL_BEGIN actionBlock:^{ dispatch_async([OWSDispatch sessionStoreQueue], ^{ [[TSStorageManager sharedManager] - deleteAllSessionsForContact:thread.contactIdentifier]; + deleteAllSessionsForContact:thread.contactIdentifier + protocolContext:protocolContext]; }); }], [OWSTableItem itemWithTitle:@"Archive all sessions" diff --git a/SignalServiceKit/Utilities/precommit.py b/SignalServiceKit/Utilities/precommit.py index 73f642bb4..09f27d144 100755 --- a/SignalServiceKit/Utilities/precommit.py +++ b/SignalServiceKit/Utilities/precommit.py @@ -392,6 +392,7 @@ if __name__ == "__main__": parser = argparse.ArgumentParser(description='Precommit script.') parser.add_argument('--all', action='store_true', help='process all files in or below current dir') + parser.add_argument('--path', help='used to specify a path to process.') args = parser.parse_args() if args.all: @@ -399,6 +400,11 @@ if __name__ == "__main__": for filename in filenames: file_path = os.path.abspath(os.path.join(rootdir, filename)) process_if_appropriate(file_path) + elif args.path: + for rootdir, dirnames, filenames in os.walk(args.path): + for filename in filenames: + file_path = os.path.abspath(os.path.join(rootdir, filename)) + process_if_appropriate(file_path) else: filepaths = [] diff --git a/SignalServiceKit/src/Devices/OWSRecordTranscriptJob.m b/SignalServiceKit/src/Devices/OWSRecordTranscriptJob.m index edfe82342..18d96d43c 100644 --- a/SignalServiceKit/src/Devices/OWSRecordTranscriptJob.m +++ b/SignalServiceKit/src/Devices/OWSRecordTranscriptJob.m @@ -1,5 +1,5 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // #import "OWSRecordTranscriptJob.h" @@ -69,7 +69,7 @@ NS_ASSUME_NONNULL_BEGIN if (transcript.isEndSessionMessage) { DDLogInfo(@"%@ EndSession was sent to recipient: %@.", self.logTag, transcript.recipientId); dispatch_async([OWSDispatch sessionStoreQueue], ^{ - [self.storageManager deleteAllSessionsForContact:transcript.recipientId]; + [self.storageManager deleteAllSessionsForContact:transcript.recipientId protocolContext:protocolContext]; }); [[[TSInfoMessage alloc] initWithTimestamp:transcript.timestamp inThread:thread diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index 29c20a60f..ba1dc25ed 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -718,9 +718,7 @@ NS_ASSUME_NONNULL_BEGIN inThread:thread messageType:TSInfoMessageTypeSessionDidEnd] saveWithTransaction:transaction]; - dispatch_async([OWSDispatch sessionStoreQueue], ^{ - [self.storageManager deleteAllSessionsForContact:envelope.source]; - }); + [self.storageManager deleteAllSessionsForContact:envelope.source protocolContext:transaction]; } - (void)handleExpirationTimerUpdateMessageWithEnvelope:(OWSSignalServiceProtosEnvelope *)envelope diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index 73b1af86c..7312cac69 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -1107,7 +1107,9 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; if (extraDevices && extraDevices.count > 0) { DDLogInfo(@"%@ removing extra devices: %@", self.logTag, extraDevices); for (NSNumber *extraDeviceId in extraDevices) { - [self.storageManager deleteSessionForContact:recipient.uniqueId deviceId:extraDeviceId.intValue]; + [self.storageManager deleteSessionForContact:recipient.uniqueId + deviceId:extraDeviceId.intValue + protocolContext:protocolContext]; } [recipient removeDevices:[NSSet setWithArray:extraDevices]]; @@ -1292,7 +1294,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; OWSAssert(deviceNumber); OWSAssert(storage); - if (![storage containsSession:identifier deviceId:[deviceNumber intValue]]) { + if (![storage containsSession:identifier deviceId:[deviceNumber intValue] protocolContext:protocolContext]) { __block dispatch_semaphore_t sema = dispatch_semaphore_create(0); __block PreKeyBundle *_Nullable bundle; __block NSException *_Nullable exception; @@ -1427,7 +1429,9 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; dispatch_async([OWSDispatch sessionStoreQueue], ^{ for (NSUInteger i = 0; i < [devices count]; i++) { int deviceNumber = [devices[i] intValue]; - [[TSStorageManager sharedManager] deleteSessionForContact:identifier deviceId:deviceNumber]; + [[TSStorageManager sharedManager] deleteSessionForContact:identifier + deviceId:deviceNumber + protocolContext:protocolContext]; } completionHandler(); }); diff --git a/SignalServiceKit/src/Storage/AxolotlStore/TSStorageManager+SessionStore.h b/SignalServiceKit/src/Storage/AxolotlStore/TSStorageManager+SessionStore.h index 2e1cf67b3..a3f3ea26d 100644 --- a/SignalServiceKit/src/Storage/AxolotlStore/TSStorageManager+SessionStore.h +++ b/SignalServiceKit/src/Storage/AxolotlStore/TSStorageManager+SessionStore.h @@ -5,6 +5,8 @@ #import "TSStorageManager.h" #import +NS_ASSUME_NONNULL_BEGIN + @interface TSStorageManager (SessionStore) - (void)archiveAllSessionsForContact:(NSString *)contactIdentifier; @@ -19,3 +21,5 @@ - (void)printAllSessions; @end + +NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Storage/AxolotlStore/TSStorageManager+SessionStore.m b/SignalServiceKit/src/Storage/AxolotlStore/TSStorageManager+SessionStore.m index d90e719e8..ea353a1f4 100644 --- a/SignalServiceKit/src/Storage/AxolotlStore/TSStorageManager+SessionStore.m +++ b/SignalServiceKit/src/Storage/AxolotlStore/TSStorageManager+SessionStore.m @@ -8,18 +8,11 @@ #import #import +NS_ASSUME_NONNULL_BEGIN + NSString *const TSStorageManagerSessionStoreCollection = @"TSStorageManagerSessionStoreCollection"; NSString *const kSessionStoreDBConnectionKey = @"kSessionStoreDBConnectionKey"; -void AssertIsOnSessionStoreQueue() -{ -#ifdef DEBUG - if (@available(iOS 10.0, *)) { - dispatch_assert_queue([OWSDispatch sessionStoreQueue]); - } // else, skip assert as it's a development convenience. -#endif -} - @implementation TSStorageManager (SessionStore) /** @@ -27,36 +20,39 @@ void AssertIsOnSessionStoreQueue() * Note that it's still technically possible to access this collection from a different collection, * but that should be considered a bug. */ -+ (YapDatabaseConnection *)sessionDBConnection ++ (YapDatabaseConnection *)protocolStoreDBConnection { static dispatch_once_t onceToken; - static YapDatabaseConnection *sessionDBConnection; + static YapDatabaseConnection *protocolStoreDBConnection; dispatch_once(&onceToken, ^{ - sessionDBConnection = [TSStorageManager sharedManager].newDatabaseConnection; - sessionDBConnection.objectCacheEnabled = NO; + protocolStoreDBConnection = [TSStorageManager sharedManager].newDatabaseConnection; + protocolStoreDBConnection.objectCacheEnabled = NO; #if DEBUG - sessionDBConnection.permittedTransactions = YDB_AnySyncTransaction; + protocolStoreDBConnection.permittedTransactions = YDB_AnySyncTransaction; #endif }); - return sessionDBConnection; + return protocolStoreDBConnection; } -- (YapDatabaseConnection *)sessionDBConnection +// TODO: Audit usage of this connection. +- (YapDatabaseConnection *)protocolStoreDBConnection { - return [[self class] sessionDBConnection]; + return [[self class] protocolStoreDBConnection]; } #pragma mark - SessionStore -- (SessionRecord *)loadSession:(NSString *)contactIdentifier deviceId:(int)deviceId +- (SessionRecord *)loadSession:(NSString *)contactIdentifier deviceId:(int)deviceId protocolContext:(id)protocolContext { - AssertIsOnSessionStoreQueue(); + OWSAssert(contactIdentifier.length > 0); + OWSAssert(deviceId >= 0); + OWSAssert([protocolContext isKindOfClass:[YapDatabaseReadWriteTransaction class]]); - __block NSDictionary *dictionary; - [self.sessionDBConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - dictionary = [transaction objectForKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection]; - }]; + YapDatabaseReadWriteTransaction *transaction = protocolContext; + + NSDictionary *_Nullable dictionary = + [transaction objectForKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection]; SessionRecord *record; @@ -71,24 +67,33 @@ void AssertIsOnSessionStoreQueue() return record; } -- (NSArray *)subDevicesSessions:(NSString *)contactIdentifier +- (NSArray *)subDevicesSessions:(NSString *)contactIdentifier protocolContext:(nullable id)protocolContext { + OWSAssert(contactIdentifier.length > 0); + OWSAssert([protocolContext isKindOfClass:[YapDatabaseReadWriteTransaction class]]); + // Deprecated. We aren't currently using this anywhere, but it's "required" by the SessionStore protocol. // If we are going to start using it I'd want to re-verify it works as intended. OWSFail(@"%@ subDevicesSessions is deprecated", self.logTag); - AssertIsOnSessionStoreQueue(); - __block NSDictionary *dictionary; - [self.sessionDBConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - dictionary = [transaction objectForKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection]; - }]; + YapDatabaseReadWriteTransaction *transaction = protocolContext; + + NSDictionary *_Nullable dictionary = + [transaction objectForKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection]; return dictionary ? dictionary.allKeys : @[]; } -- (void)storeSession:(NSString *)contactIdentifier deviceId:(int)deviceId session:(SessionRecord *)session +- (void)storeSession:(NSString *)contactIdentifier + deviceId:(int)deviceId + session:(SessionRecord *)session + protocolContext:protocolContext { - AssertIsOnSessionStoreQueue(); + OWSAssert(contactIdentifier.length > 0); + OWSAssert(deviceId >= 0); + OWSAssert([protocolContext isKindOfClass:[YapDatabaseReadWriteTransaction class]]); + + YapDatabaseReadWriteTransaction *transaction = protocolContext; // We need to ensure subsequent usage of this SessionRecord does not consider this session as "fresh". Normally this // is achieved by marking things as "not fresh" at the point of deserialization - when we fetch a SessionRecord from @@ -98,68 +103,65 @@ void AssertIsOnSessionStoreQueue() // NOTE: this may no longer be necessary now that we have a non-caching session db connection. [session markAsUnFresh]; - __block NSDictionary *immutableDictionary; - [self.sessionDBConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - immutableDictionary = - [transaction objectForKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection]; - }]; - - NSMutableDictionary *dictionary = [immutableDictionary mutableCopy]; + NSDictionary *immutableDictionary = + [transaction objectForKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection]; - if (!dictionary) { - dictionary = [NSMutableDictionary dictionary]; - } + NSMutableDictionary *dictionary + = (immutableDictionary ? [immutableDictionary mutableCopy] : [NSMutableDictionary new]); [dictionary setObject:session forKey:@(deviceId)]; - [self.sessionDBConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [transaction setObject:[dictionary copy] - forKey:contactIdentifier - inCollection:TSStorageManagerSessionStoreCollection]; - }]; + [transaction setObject:[dictionary copy] + forKey:contactIdentifier + inCollection:TSStorageManagerSessionStoreCollection]; } -- (BOOL)containsSession:(NSString *)contactIdentifier deviceId:(int)deviceId +- (BOOL)containsSession:(NSString *)contactIdentifier deviceId:(int)deviceId protocolContext:(id)protocolContext { - AssertIsOnSessionStoreQueue(); + OWSAssert(contactIdentifier.length > 0); + OWSAssert(deviceId >= 0); + OWSAssert([protocolContext isKindOfClass:[YapDatabaseReadWriteTransaction class]]); - return [self loadSession:contactIdentifier deviceId:deviceId].sessionState.hasSenderChain; + return [self loadSession:contactIdentifier deviceId:deviceId protocolContext:protocolContext] + .sessionState.hasSenderChain; } -- (void)deleteSessionForContact:(NSString *)contactIdentifier deviceId:(int)deviceId +- (void)deleteSessionForContact:(NSString *)contactIdentifier + deviceId:(int)deviceId + protocolContext:(nullable id)protocolContext { - AssertIsOnSessionStoreQueue(); + OWSAssert(contactIdentifier.length > 0); + OWSAssert(deviceId >= 0); + OWSAssert([protocolContext isKindOfClass:[YapDatabaseReadWriteTransaction class]]); + + YapDatabaseReadWriteTransaction *transaction = protocolContext; + DDLogInfo( @"[TSStorageManager (SessionStore)] deleting session for contact: %@ device: %d", contactIdentifier, deviceId); - __block NSDictionary *immutableDictionary; - [self.sessionDBConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - immutableDictionary = - [transaction objectForKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection]; - }]; - NSMutableDictionary *dictionary = [immutableDictionary mutableCopy]; + NSDictionary *immutableDictionary = + [transaction objectForKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection]; - if (!dictionary) { - dictionary = [NSMutableDictionary dictionary]; - } + NSMutableDictionary *dictionary + = (immutableDictionary ? [immutableDictionary mutableCopy] : [NSMutableDictionary new]); [dictionary removeObjectForKey:@(deviceId)]; - [self.sessionDBConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [transaction setObject:[dictionary copy] - forKey:contactIdentifier - inCollection:TSStorageManagerSessionStoreCollection]; - }]; + [transaction setObject:[dictionary copy] + forKey:contactIdentifier + inCollection:TSStorageManagerSessionStoreCollection]; } -- (void)deleteAllSessionsForContact:(NSString *)contactIdentifier +- (void)deleteAllSessionsForContact:(NSString *)contactIdentifier protocolContext:(nullable id)protocolContext { - AssertIsOnSessionStoreQueue(); + OWSAssert(contactIdentifier.length > 0); + OWSAssert([protocolContext isKindOfClass:[YapDatabaseReadWriteTransaction class]]); + + YapDatabaseReadWriteTransaction *transaction = protocolContext; + DDLogInfo(@"[TSStorageManager (SessionStore)] deleting all sessions for contact:%@", contactIdentifier); - [self.sessionDBConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [transaction removeObjectForKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection]; - }]; + [transaction removeObjectForKey:contactIdentifier inCollection:TSStorageManagerSessionStoreCollection]; } - (void)archiveAllSessionsForContact:(NSString *)contactIdentifier @@ -272,3 +274,5 @@ void AssertIsOnSessionStoreQueue() #endif @end + +NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Util/OWSDispatch.h b/SignalServiceKit/src/Util/OWSDispatch.h index c9e1f7001..3d7b51b37 100644 --- a/SignalServiceKit/src/Util/OWSDispatch.h +++ b/SignalServiceKit/src/Util/OWSDispatch.h @@ -11,12 +11,6 @@ NS_ASSUME_NONNULL_BEGIN */ + (dispatch_queue_t)attachmentsQueue; -/** - * Signal protocol session state must be coordinated on a serial queue. This is sometimes used synchronously, - * so never dispatching sync *from* this queue to avoid deadlock. - */ -+ (dispatch_queue_t)sessionStoreQueue; - /** * Serial message sending queue */ diff --git a/SignalServiceKit/src/Util/OWSDispatch.m b/SignalServiceKit/src/Util/OWSDispatch.m index 0196fa61e..6278be3a2 100644 --- a/SignalServiceKit/src/Util/OWSDispatch.m +++ b/SignalServiceKit/src/Util/OWSDispatch.m @@ -18,16 +18,6 @@ NS_ASSUME_NONNULL_BEGIN return queue; } -+ (dispatch_queue_t)sessionStoreQueue -{ - static dispatch_once_t onceToken; - static dispatch_queue_t queue; - dispatch_once(&onceToken, ^{ - queue = dispatch_queue_create("org.whispersystems.signal.sessionStoreQueue", NULL); - }); - return queue; -} - + (dispatch_queue_t)sendingQueue { static dispatch_once_t onceToken;