diff --git a/Signal/src/Jobs/SessionResetJob.swift b/Signal/src/Jobs/SessionResetJob.swift index bb1964355..ef1494f66 100644 --- a/Signal/src/Jobs/SessionResetJob.swift +++ b/Signal/src/Jobs/SessionResetJob.swift @@ -26,7 +26,8 @@ class SessionResetJob: NSObject { func run() { Logger.info("\(TAG) Local user reset session.") - TSStorageManager.protocolStoreDBConnection().asyncReadWrite { (transaction) in + let dbConnection = TSStorageManager.shared().newDatabaseConnection() + dbConnection.asyncReadWrite { (transaction) in Logger.info("\(self.TAG) deleting sessions for recipient: \(self.recipientId)") self.storageManager.deleteAllSessions(forContact: self.recipientId, protocolContext: transaction) @@ -34,7 +35,7 @@ class SessionResetJob: NSObject { let endSessionMessage = EndSessionMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: self.thread) self.messageSender.enqueue(endSessionMessage, success: { - TSStorageManager.protocolStoreDBConnection().asyncReadWrite { (transaction) in + dbConnection.asyncReadWrite { (transaction) in // Archive the just-created session since the recipient should delete their corresponding // session upon receiving and decrypting our EndSession message. // Otherwise if we send another message before them, they wont have the session to decrypt it. @@ -46,7 +47,7 @@ class SessionResetJob: NSObject { messageType: TSInfoMessageType.typeSessionDidEnd) message.save() }, failure: {error in - TSStorageManager.protocolStoreDBConnection().asyncReadWrite { (transaction) in + dbConnection.asyncReadWrite { (transaction) in // Even though this is the error handler - which means probably the recipient didn't receive the message // there's a chance that our send did succeed and the server just timed out our repsonse or something. // Since the cost of sending a future message using a session the recipient doesn't have is so high, @@ -60,8 +61,8 @@ class SessionResetJob: NSObject { Logger.error("\(self.TAG) failed to send EndSessionMessage with error: \(error.localizedDescription)") }) } + } } - } class func run(contactThread: TSContactThread, messageSender: MessageSender, storageManager: TSStorageManager) { let job = self.init(recipientId: contactThread.contactIdentifier(), diff --git a/Signal/src/ViewControllers/DebugUI/DebugUISessionState.m b/Signal/src/ViewControllers/DebugUI/DebugUISessionState.m index 7d21310b8..d21db0e81 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUISessionState.m +++ b/Signal/src/ViewControllers/DebugUI/DebugUISessionState.m @@ -39,25 +39,19 @@ NS_ASSUME_NONNULL_BEGIN OWSIdentityManager *identityManager = [OWSIdentityManager sharedManager]; NSString *recipientId = [thread contactIdentifier]; - [TSStorageManager.protocolStoreDBConnection - readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - NSData *currentKey = [identityManager identityKeyForRecipientId:recipientId - protocolContext:transaction]; - NSMutableData *flippedKey = [NSMutableData new]; - const char *currentKeyBytes = currentKey.bytes; - for (NSUInteger i = 0; i < currentKey.length; i++) { - const char xorByte = currentKeyBytes[i] ^ 0xff; - [flippedKey appendBytes:&xorByte length:1]; - } - OWSAssert(flippedKey.length == currentKey.length); - [identityManager saveRemoteIdentity:flippedKey - recipientId:recipientId - protocolContext:transaction]; - }]; + NSData *currentKey = [identityManager identityKeyForRecipientId:recipientId]; + NSMutableData *flippedKey = [NSMutableData new]; + const char *currentKeyBytes = currentKey.bytes; + for (NSUInteger i = 0; i < currentKey.length; i++) { + const char xorByte = currentKeyBytes[i] ^ 0xff; + [flippedKey appendBytes:&xorByte length:1]; + } + OWSAssert(flippedKey.length == currentKey.length); + [identityManager saveRemoteIdentity:flippedKey recipientId:recipientId]; }], [OWSTableItem itemWithTitle:@"Delete all sessions" actionBlock:^{ - [TSStorageManager.protocolStoreDBConnection + [TSStorageManager.sharedManager.newDatabaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [[TSStorageManager sharedManager] deleteAllSessionsForContact:thread.contactIdentifier @@ -66,7 +60,7 @@ NS_ASSUME_NONNULL_BEGIN }], [OWSTableItem itemWithTitle:@"Archive all sessions" actionBlock:^{ - [TSStorageManager.protocolStoreDBConnection + [TSStorageManager.sharedManager.newDatabaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [[TSStorageManager sharedManager] archiveAllSessionsForContact:thread.contactIdentifier diff --git a/Signal/src/ViewControllers/FingerprintViewController.m b/Signal/src/ViewControllers/FingerprintViewController.m index bb0d97b14..5c2fcc8d6 100644 --- a/Signal/src/ViewControllers/FingerprintViewController.m +++ b/Signal/src/ViewControllers/FingerprintViewController.m @@ -512,7 +512,8 @@ typedef void (^CustomLayoutBlock)(void); - (void)verifyUnverifyButtonTapped:(UIGestureRecognizer *)gestureRecognizer { if (gestureRecognizer.state == UIGestureRecognizerStateRecognized) { - [TSStorageManager.protocolStoreDBConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + [TSStorageManager.sharedManager.newDatabaseConnection readWriteWithBlock:^( + YapDatabaseReadWriteTransaction *transaction) { BOOL isVerified = [[OWSIdentityManager sharedManager] verificationStateForRecipientId:self.recipientId transaction:transaction] == OWSVerificationStateVerified; diff --git a/Signal/src/ViewControllers/FingerprintViewScanController.m b/Signal/src/ViewControllers/FingerprintViewScanController.m index 4578d700f..1503fbeee 100644 --- a/Signal/src/ViewControllers/FingerprintViewScanController.m +++ b/Signal/src/ViewControllers/FingerprintViewScanController.m @@ -200,7 +200,7 @@ NS_ASSUME_NONNULL_BEGIN @"Button that marks user as verified after a successful fingerprint scan.") style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { - [TSStorageManager.protocolStoreDBConnection + [TSStorageManager.sharedManager.newDatabaseConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [OWSIdentityManager.sharedManager setVerificationState:OWSVerificationStateVerified diff --git a/Signal/src/ViewControllers/SafetyNumberConfirmationAlert.swift b/Signal/src/ViewControllers/SafetyNumberConfirmationAlert.swift index 5d5d12eef..f623c81a2 100644 --- a/Signal/src/ViewControllers/SafetyNumberConfirmationAlert.swift +++ b/Signal/src/ViewControllers/SafetyNumberConfirmationAlert.swift @@ -55,7 +55,7 @@ class SafetyNumberConfirmationAlert: NSObject { let confirmAction = UIAlertAction(title: confirmationText, style: .default) { _ in Logger.info("\(self.TAG) Confirmed identity: \(untrustedIdentity)") - TSStorageManager.protocolStoreDBConnection().asyncReadWrite { (transaction) in + self.storageManager.newDatabaseConnection().asyncReadWrite { (transaction) in OWSIdentityManager.shared().setVerificationState(.default, identityKey: untrustedIdentity.identityKey, recipientId: untrustedIdentity.recipientId, isUserInitiatedChange: true, protocolContext: transaction) DispatchQueue.main.async { completion(true) diff --git a/Signal/src/ViewControllers/ShowGroupMembersViewController.m b/Signal/src/ViewControllers/ShowGroupMembersViewController.m index 23e616614..04f024bf8 100644 --- a/Signal/src/ViewControllers/ShowGroupMembersViewController.m +++ b/Signal/src/ViewControllers/ShowGroupMembersViewController.m @@ -251,7 +251,7 @@ NS_ASSUME_NONNULL_BEGIN OWSFail(@"Missing identity key for: %@", recipientId); continue; } - [TSStorageManager.protocolStoreDBConnection + [TSStorageManager.sharedManager.newDatabaseConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [identityManger setVerificationState:OWSVerificationStateDefault identityKey:identityKey diff --git a/SignalMessaging/attachments/SharingThreadPickerViewController.m b/SignalMessaging/attachments/SharingThreadPickerViewController.m index 21e32cdf6..1efc98448 100644 --- a/SignalMessaging/attachments/SharingThreadPickerViewController.m +++ b/SignalMessaging/attachments/SharingThreadPickerViewController.m @@ -30,7 +30,7 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion); @property (nonatomic) TSThread *thread; @property (nonatomic, readonly, weak) id shareViewDelegate; @property (nonatomic, readonly) UIProgressView *progressView; -@property (nullable, atomic) TSOutgoingMessage *outgoingMessage; +@property (atomic, nullable) TSOutgoingMessage *outgoingMessage; @end @@ -385,7 +385,7 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion); DDLogDebug(@"%@ Confirming identity for recipient: %@", self.logTag, recipientId); - [TSStorageManager.protocolStoreDBConnection asyncReadWriteWithBlock:^( + [TSStorageManager.sharedManager.newDatabaseConnection asyncReadWriteWithBlock:^( YapDatabaseReadWriteTransaction *transaction) { OWSVerificationState verificationState = [[OWSIdentityManager sharedManager] verificationStateForRecipientId:recipientId transaction:transaction]; diff --git a/SignalServiceKit/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeyReceivingErrorMessage.m b/SignalServiceKit/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeyReceivingErrorMessage.m index 1f2a23eff..0bac60265 100644 --- a/SignalServiceKit/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeyReceivingErrorMessage.m +++ b/SignalServiceKit/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeyReceivingErrorMessage.m @@ -69,6 +69,8 @@ NS_ASSUME_NONNULL_BEGIN - (void)acceptNewIdentityKey { + OWSAssertIsOnMainThread(); + if (self.errorType != TSErrorMessageWrongTrustedIdentityKey) { DDLogError(@"Refusing to accept identity key for anything but a Key error."); return; @@ -80,28 +82,20 @@ NS_ASSUME_NONNULL_BEGIN return; } - // Saving a new identity mutates the session store so it must happen on the sessionStoreQueue - [TSStorageManager.protocolStoreDBConnection asyncReadWriteWithBlock:^( - YapDatabaseReadWriteTransaction *transaction) { - [[OWSIdentityManager sharedManager] saveRemoteIdentity:newKey - recipientId:self.envelope.source - protocolContext:transaction]; - - dispatch_async(dispatch_get_main_queue(), ^{ - // Decrypt this and any old messages for the newly accepted key - NSArray *messagesToDecrypt = - [self.thread receivedMessagesForInvalidKey:newKey]; - - for (TSInvalidIdentityKeyReceivingErrorMessage *errorMessage in messagesToDecrypt) { - [[OWSMessageReceiver sharedInstance] handleReceivedEnvelope:errorMessage.envelope]; - - // Here we remove the existing error message because handleReceivedEnvelope will either - // 1.) succeed and create a new successful message in the thread or... - // 2.) fail and create a new identical error message in the thread. - [errorMessage remove]; - } - }); - }]; + [[OWSIdentityManager sharedManager] saveRemoteIdentity:newKey recipientId:self.envelope.source]; + + // Decrypt this and any old messages for the newly accepted key + NSArray *messagesToDecrypt = + [self.thread receivedMessagesForInvalidKey:newKey]; + + for (TSInvalidIdentityKeyReceivingErrorMessage *errorMessage in messagesToDecrypt) { + [[OWSMessageReceiver sharedInstance] handleReceivedEnvelope:errorMessage.envelope]; + + // Here we remove the existing error message because handleReceivedEnvelope will either + // 1.) succeed and create a new successful message in the thread or... + // 2.) fail and create a new identical error message in the thread. + [errorMessage remove]; + } } - (nullable NSData *)newIdentityKey diff --git a/SignalServiceKit/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeySendingErrorMessage.m b/SignalServiceKit/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeySendingErrorMessage.m index 875b0594c..4d8f3569f 100644 --- a/SignalServiceKit/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeySendingErrorMessage.m +++ b/SignalServiceKit/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeySendingErrorMessage.m @@ -11,6 +11,7 @@ #import "TSErrorMessage_privateConstructor.h" #import "TSOutgoingMessage.h" #import "TSStorageManager+SessionStore.h" +#import "TSStorageManager.h" #import NS_ASSUME_NONNULL_BEGIN @@ -51,19 +52,13 @@ NSString *TSInvalidRecipientKey = @"TSInvalidRecipientKey"; // But there may still be some old unaccepted SN errors in the wild that need to be accepted. OWSFail(@"accepting new identity key is deprecated."); - // Saving a new identity mutates the session store so it must happen on the sessionStoreQueue NSData *_Nullable newIdentityKey = self.newIdentityKey; if (!newIdentityKey) { OWSFail(@"newIdentityKey is unexpectedly nil. Bad Prekey bundle?: %@", self.preKeyBundle); return; } - [TSStorageManager.protocolStoreDBConnection - asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [[OWSIdentityManager sharedManager] saveRemoteIdentity:newIdentityKey - recipientId:self.recipientId - protocolContext:transaction]; - }]; + [[OWSIdentityManager sharedManager] saveRemoteIdentity:newIdentityKey recipientId:self.recipientId]; } - (nullable NSData *)newIdentityKey diff --git a/SignalServiceKit/src/Messages/OWSIdentityManager.h b/SignalServiceKit/src/Messages/OWSIdentityManager.h index a3f887c4d..d79cf4c87 100644 --- a/SignalServiceKit/src/Messages/OWSIdentityManager.h +++ b/SignalServiceKit/src/Messages/OWSIdentityManager.h @@ -42,7 +42,7 @@ extern const NSUInteger kIdentityKeyLength; - (OWSVerificationState)verificationStateForRecipientId:(NSString *)recipientId; - (OWSVerificationState)verificationStateForRecipientId:(NSString *)recipientId - transaction:(YapDatabaseReadWriteTransaction *)transaction; + transaction:(YapDatabaseReadTransaction *)transaction; - (nullable OWSRecipientIdentity *)recipientIdentityForRecipientId:(NSString *)recipientId; @@ -56,6 +56,8 @@ extern const NSUInteger kIdentityKeyLength; // This method can be called from any thread. - (void)processIncomingSyncMessage:(OWSSignalServiceProtosVerified *)verified; +- (BOOL)saveRemoteIdentity:(NSData *)identityKey recipientId:(NSString *)recipientId; + #pragma mark - Debug - (nullable ECKeyPair *)identityKeyPair; diff --git a/SignalServiceKit/src/Messages/OWSIdentityManager.m b/SignalServiceKit/src/Messages/OWSIdentityManager.m index 0c7f3f1c7..11492c9ab 100644 --- a/SignalServiceKit/src/Messages/OWSIdentityManager.m +++ b/SignalServiceKit/src/Messages/OWSIdentityManager.m @@ -56,10 +56,8 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa @interface OWSIdentityManager () @property (nonatomic, readonly) TSStorageManager *storageManager; -@property (nonatomic, readonly) OWSMessageSender *messageSender; - -// TODO: Should we get rid of this property? @property (nonatomic, readonly) YapDatabaseConnection *dbConnection; +@property (nonatomic, readonly) OWSMessageSender *messageSender; @end @@ -132,7 +130,7 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa - (nullable NSData *)identityKeyForRecipientId:(NSString *)recipientId { __block NSData *_Nullable result = nil; - [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { + [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { result = [self identityKeyForRecipientId:recipientId protocolContext:transaction]; }]; return result; @@ -145,6 +143,15 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa YapDatabaseReadWriteTransaction *transaction = protocolContext; + return [self identityKeyForRecipientId:recipientId protocolContext:transaction]; +} + +- (nullable NSData *)identityKeyForRecipientId:(NSString *)recipientId + transaction:(YapDatabaseReadTransaction *)transaction +{ + OWSAssert(recipientId.length > 0); + OWSAssert(transaction); + return [OWSRecipientIdentity fetchObjectWithUniqueID:recipientId transaction:transaction].identityKey; } @@ -177,6 +184,19 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa return (int)[TSAccountManager getOrGenerateRegistrationId:transaction]; } +- (BOOL)saveRemoteIdentity:(NSData *)identityKey recipientId:(NSString *)recipientId +{ + OWSAssert(identityKey.length == kStoredIdentityKeyLength); + OWSAssert(recipientId.length > 0); + + __block BOOL result; + [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + result = [self saveRemoteIdentity:identityKey recipientId:recipientId protocolContext:transaction]; + }]; + + return result; +} + - (BOOL)saveRemoteIdentity:(NSData *)identityKey recipientId:(NSString *)recipientId protocolContext:(nullable id)protocolContext @@ -306,14 +326,14 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa { __block OWSVerificationState result; // Use a read/write transaction to block on latest. - [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { + [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) { result = [self verificationStateForRecipientId:recipientId transaction:transaction]; }]; return result; } - (OWSVerificationState)verificationStateForRecipientId:(NSString *)recipientId - transaction:(YapDatabaseReadWriteTransaction *)transaction + transaction:(YapDatabaseReadTransaction *)transaction { OWSAssert(recipientId.length > 0); OWSAssert(transaction); diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index 523b21b68..642835e3f 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -903,13 +903,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; } NSData *newIdentityKey = [newIdentityKeyWithVersion removeKeyType]; - - [self.dbConnection - readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - [[OWSIdentityManager sharedManager] saveRemoteIdentity:newIdentityKey - recipientId:recipient.recipientId - protocolContext:transaction]; - }]; + [[OWSIdentityManager sharedManager] saveRemoteIdentity:newIdentityKey recipientId:recipient.recipientId]; failureHandler(error); return; diff --git a/SignalServiceKit/src/Storage/AxolotlStore/TSStorageManager+SessionStore.h b/SignalServiceKit/src/Storage/AxolotlStore/TSStorageManager+SessionStore.h index 15815b527..f6847380e 100644 --- a/SignalServiceKit/src/Storage/AxolotlStore/TSStorageManager+SessionStore.h +++ b/SignalServiceKit/src/Storage/AxolotlStore/TSStorageManager+SessionStore.h @@ -9,8 +9,6 @@ NS_ASSUME_NONNULL_BEGIN @interface TSStorageManager (SessionStore) -+ (YapDatabaseConnection *)protocolStoreDBConnection; - - (void)archiveAllSessionsForContact:(NSString *)contactIdentifier protocolContext:(nullable id)protocolContext; #pragma mark - debug diff --git a/SignalServiceKit/src/Storage/AxolotlStore/TSStorageManager+SessionStore.m b/SignalServiceKit/src/Storage/AxolotlStore/TSStorageManager+SessionStore.m index f40711c6c..30fea09f2 100644 --- a/SignalServiceKit/src/Storage/AxolotlStore/TSStorageManager+SessionStore.m +++ b/SignalServiceKit/src/Storage/AxolotlStore/TSStorageManager+SessionStore.m @@ -20,22 +20,22 @@ NSString *const kSessionStoreDBConnectionKey = @"kSessionStoreDBConnectionKey"; * Note that it's still technically possible to access this collection from a different collection, * but that should be considered a bug. */ -+ (YapDatabaseConnection *)protocolStoreDBConnection ++ (YapDatabaseConnection *)sessionStoreDBConnection { static dispatch_once_t onceToken; - static YapDatabaseConnection *protocolStoreDBConnection; + static YapDatabaseConnection *sessionStoreDBConnection; dispatch_once(&onceToken, ^{ - protocolStoreDBConnection = [TSStorageManager sharedManager].newDatabaseConnection; - protocolStoreDBConnection.objectCacheEnabled = NO; + sessionStoreDBConnection = [TSStorageManager sharedManager].newDatabaseConnection; + sessionStoreDBConnection.objectCacheEnabled = NO; }); - return protocolStoreDBConnection; + return sessionStoreDBConnection; } // TODO: Audit usage of this connection. -- (YapDatabaseConnection *)protocolStoreDBConnection +- (YapDatabaseConnection *)sessionStoreDBConnection { - return [[self class] protocolStoreDBConnection]; + return [[self class] sessionStoreDBConnection]; } #pragma mark - SessionStore @@ -198,7 +198,7 @@ NSString *const kSessionStoreDBConnectionKey = @"kSessionStoreDBConnectionKey"; - (void)resetSessionStore { DDLogWarn(@"%@ resetting session store", self.logTag); - [self.protocolStoreDBConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { + [self.sessionStoreDBConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { [transaction removeAllObjectsInCollection:TSStorageManagerSessionStoreCollection]; }]; } @@ -206,7 +206,7 @@ NSString *const kSessionStoreDBConnectionKey = @"kSessionStoreDBConnectionKey"; - (void)printAllSessions { NSString *tag = @"[TSStorageManager (SessionStore)]"; - [self.protocolStoreDBConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) { + [self.sessionStoreDBConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) { DDLogDebug(@"%@ All Sessions:", tag); [transaction enumerateKeysAndObjectsInCollection:TSStorageManagerSessionStoreCollection @@ -255,14 +255,14 @@ NSString *const kSessionStoreDBConnectionKey = @"kSessionStoreDBConnectionKey"; - (void)snapshotSessionStore { - [self.protocolStoreDBConnection snapshotCollection:TSStorageManagerSessionStoreCollection - snapshotFilePath:self.snapshotFilePath]; + [self.sessionStoreDBConnection snapshotCollection:TSStorageManagerSessionStoreCollection + snapshotFilePath:self.snapshotFilePath]; } - (void)restoreSessionStore { - [self.protocolStoreDBConnection restoreSnapshotOfCollection:TSStorageManagerSessionStoreCollection - snapshotFilePath:self.snapshotFilePath]; + [self.sessionStoreDBConnection restoreSnapshotOfCollection:TSStorageManagerSessionStoreCollection + snapshotFilePath:self.snapshotFilePath]; } #endif