diff --git a/SignalServiceKit/src/Loki/Protocol/Meta/SessionMetaProtocol.swift b/SignalServiceKit/src/Loki/Protocol/Meta/SessionMetaProtocol.swift index f545cb2c4..f9e031296 100644 --- a/SignalServiceKit/src/Loki/Protocol/Meta/SessionMetaProtocol.swift +++ b/SignalServiceKit/src/Loki/Protocol/Meta/SessionMetaProtocol.swift @@ -94,6 +94,12 @@ public final class SessionMetaProtocol : NSObject { } // MARK: - Receiving + + @objc(isErrorMessageFromBeforeRestoration:) + public static func isErrorMessageFromBeforeRestoration(_ errorMessage: TSErrorMessage) -> Bool { + let restorationTimeInMs = UInt64(storage.getRestorationTime() * 1000) + return errorMessage.timestamp < restorationTimeInMs + } @objc(shouldSkipMessageDecryptResult:wrappedIn:) public static func shouldSkipMessageDecryptResult(_ result: OWSMessageDecryptResult, wrappedIn envelope: SSKProtoEnvelope) -> Bool { diff --git a/SignalServiceKit/src/Loki/Protocol/Session Management/SessionManagementProtocol.swift b/SignalServiceKit/src/Loki/Protocol/Session Management/SessionManagementProtocol.swift index a8c8037ec..b189ab16a 100644 --- a/SignalServiceKit/src/Loki/Protocol/Session Management/SessionManagementProtocol.swift +++ b/SignalServiceKit/src/Loki/Protocol/Session Management/SessionManagementProtocol.swift @@ -164,15 +164,21 @@ public final class SessionManagementProtocol : NSObject { // MARK: - Receiving @objc(handleDecryptionError:forPublicKey:transaction:) - public static func handleDecryptionError(_ rawValue: Int32, for publicKey: String, using transaction: YapDatabaseReadWriteTransaction) { - let type = TSErrorMessageType(rawValue: rawValue) + public static func handleDecryptionError(_ errorMessage: TSErrorMessage, for publicKey: String, using transaction: YapDatabaseReadWriteTransaction) { + let type = errorMessage.errorType let masterPublicKey = storage.getMasterHexEncodedPublicKey(for: publicKey, in: transaction) ?? publicKey let thread = TSContactThread.getOrCreateThread(withContactId: masterPublicKey, transaction: transaction) + let restorationTimeInMs = UInt64(storage.getRestorationTime() * 1000) // Show the session reset prompt upon certain errors switch type { case .noSession, .invalidMessage, .invalidKeyException: - // Store the source device's public key in case it was a secondary device - thread.addSessionRestoreDevice(publicKey, transaction: transaction) + if restorationTimeInMs > errorMessage.timestamp { + // Automatically rebuild session after restoration + sendSessionRequestIfNeeded(to: publicKey, using: transaction) + } else { + // Store the source device's public key in case it was a secondary device + thread.addSessionRestoreDevice(publicKey, transaction: transaction) + } default: break } } @@ -180,7 +186,8 @@ public final class SessionManagementProtocol : NSObject { private static func shouldProcessSessionRequest(from publicKey: String, at timestamp: UInt64) -> Bool { let sentTimestamp = Storage.getSessionRequestSentTimestamp(for: publicKey) let processedTimestamp = Storage.getSessionRequestProcessedTimestamp(for: publicKey) - return timestamp > sentTimestamp && timestamp > processedTimestamp + let restorationTimestamp = UInt64(storage.getRestorationTime() * 1000) + return timestamp > sentTimestamp && timestamp > processedTimestamp && timestamp > restorationTimestamp } @objc(handlePreKeyBundleMessageIfNeeded:wrappedIn:transaction:) diff --git a/SignalServiceKit/src/Messages/Interactions/OWSEndSessionMessage.m b/SignalServiceKit/src/Messages/Interactions/OWSEndSessionMessage.m index 4138f194b..01450736f 100644 --- a/SignalServiceKit/src/Messages/Interactions/OWSEndSessionMessage.m +++ b/SignalServiceKit/src/Messages/Interactions/OWSEndSessionMessage.m @@ -5,6 +5,7 @@ #import "OWSEndSessionMessage.h" #import "OWSPrimaryStorage+Loki.h" #import "SignalRecipient.h" +#import #import NS_ASSUME_NONNULL_BEGIN diff --git a/SignalServiceKit/src/Messages/OWSMessageDecrypter.m b/SignalServiceKit/src/Messages/OWSMessageDecrypter.m index c49dd136e..3a84b0f80 100644 --- a/SignalServiceKit/src/Messages/OWSMessageDecrypter.m +++ b/SignalServiceKit/src/Messages/OWSMessageDecrypter.m @@ -526,7 +526,7 @@ NSError *EnsureDecryptError(NSError *_Nullable error, NSString *fallbackErrorDes NSError *_Nullable underlyingError; SSKProtoEnvelope *_Nullable identifiedEnvelope; - if (![decryptError.domain isEqualToString:@"SignalMetadataKit.SecretSessionKnownSenderError"]) { + if (![decryptError.domain isEqualToString:@"SessionMetadataKit.SecretSessionKnownSenderError"]) { underlyingError = decryptError; identifiedEnvelope = envelope; } else { @@ -574,7 +574,7 @@ NSError *EnsureDecryptError(NSError *_Nullable error, NSString *fallbackErrorDes return; } - if ([underlyingError.domain isEqualToString:@"SignalMetadataKit.SMKSecretSessionCipherError"] + if ([underlyingError.domain isEqualToString:@"SessionMetadataKit.SMKSecretSessionCipherError"] && underlyingError.code == SMKSecretSessionCipherErrorSelfSentMessage) { // Self-sent messages can be safely discarded. failureBlock(underlyingError); @@ -690,9 +690,17 @@ NSError *EnsureDecryptError(NSError *_Nullable error, NSString *fallbackErrorDes OWSAssertDebug(errorMessage); if (errorMessage != nil) { - [errorMessage saveWithTransaction:transaction]; - [LKSessionManagementProtocol handleDecryptionError:errorMessage.errorType forPublicKey:envelope.source transaction:transaction]; - [self notifyUserForErrorMessage:errorMessage envelope:envelope transaction:transaction]; + [LKSessionManagementProtocol handleDecryptionError:errorMessage forPublicKey:envelope.source transaction:transaction]; + if (![LKSessionMetaProtocol isErrorMessageFromBeforeRestoration:errorMessage]) { + [errorMessage saveWithTransaction:transaction]; + [self notifyUserForErrorMessage:errorMessage envelope:envelope transaction:transaction]; + } else { + // Show the thread if it exists before restoration + NSString *masterPublicKey = [LKDatabaseUtilities getMasterHexEncodedPublicKeyFor:envelope.source in:transaction] ?: envelope.source; + TSThread *contactThread = [TSContactThread getOrCreateThreadWithContactId:masterPublicKey transaction:transaction]; + contactThread.shouldThreadBeVisible = true; + [contactThread saveWithTransaction:transaction]; + } } } error:nil]; } diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index 0eec0f8c3..a5e64e1cb 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -1450,13 +1450,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; OWSPrimaryStorage *storage = self.primaryStorage; SignalRecipient *recipient = messageSend.recipient; OWSAssertDebug(recipientID.length > 0); - - __block BOOL hasSession; - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - hasSession = [storage containsSession:recipientID deviceId:[deviceId intValue] protocolContext:transaction]; - } error:nil]; - if (hasSession) { return YES; } - + // Discard "typing indicator" messages if there is no existing session with the user. BOOL canSafelyBeDiscarded = messageSend.message.isOnline; if (canSafelyBeDiscarded) { @@ -1467,6 +1461,12 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; __block NSException *exception; if (!bundle) { + __block BOOL hasSession; + [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + hasSession = [storage containsSession:recipientID deviceId:[deviceId intValue] protocolContext:transaction]; + } error:nil]; + if (hasSession) { return YES; } + TSOutgoingMessage *message = messageSend.message; // Loki: Remove this when we have shared sender keys // ========