diff --git a/SignalServiceKit/src/Messages/TSMessagesManager.h b/SignalServiceKit/src/Messages/TSMessagesManager.h index 5ac185083..b3766722a 100644 --- a/SignalServiceKit/src/Messages/TSMessagesManager.h +++ b/SignalServiceKit/src/Messages/TSMessagesManager.h @@ -34,10 +34,14 @@ typedef void (^MessageManagerCompletionBlock)(); // decryptEnvelope: can be called from any thread. // successBlock & failureBlock may be called on any thread. +// +// Exactly one of successBlock & failureBlock will be called, +// once. - (void)decryptEnvelope:(OWSSignalServiceProtosEnvelope *)envelope successBlock:(DecryptSuccessBlock)successBlock failureBlock:(DecryptFailureBlock)failureBlock; +// processEnvelope: can be called from any thread. - (void)processEnvelope:(OWSSignalServiceProtosEnvelope *)envelope plaintextData:(NSData *_Nullable)plaintextData transaction:(YapDatabaseReadWriteTransaction *)transaction; diff --git a/SignalServiceKit/src/Messages/TSMessagesManager.m b/SignalServiceKit/src/Messages/TSMessagesManager.m index a34c06dc3..ded3d074f 100644 --- a/SignalServiceKit/src/Messages/TSMessagesManager.m +++ b/SignalServiceKit/src/Messages/TSMessagesManager.m @@ -346,6 +346,7 @@ const NSUInteger kIncomingMessageBatchSize = 10; // Return to avoid double-acknowledging. return; } + // These message types don't have a payload to decrypt. case OWSSignalServiceProtosEnvelopeTypeReceipt: case OWSSignalServiceProtosEnvelopeTypeKeyExchange: case OWSSignalServiceProtosEnvelopeTypeUnknown: @@ -364,75 +365,78 @@ const NSUInteger kIncomingMessageBatchSize = 10; failureBlock(); } -- (void)decryptSecureMessage:(OWSSignalServiceProtosEnvelope *)messageEnvelope +- (void)decryptSecureMessage:(OWSSignalServiceProtosEnvelope *)envelope successBlock:(DecryptSuccessBlock)successBlock failureBlock:(void (^)(NSError *_Nullable error))failureBlock { - OWSAssert(messageEnvelope); + OWSAssert(envelope); OWSAssert(successBlock); OWSAssert(failureBlock); - TSStorageManager *storageManager = [TSStorageManager sharedManager]; - NSString *recipientId = messageEnvelope.source; - int deviceId = messageEnvelope.sourceDevice; - dispatch_async([OWSDispatch sessionStoreQueue], ^{ - // DEPRECATED - Remove after all clients have been upgraded. - NSData *encryptedData = messageEnvelope.hasContent ? messageEnvelope.content : messageEnvelope.legacyMessage; - if (!encryptedData) { + [self decryptEnvelope:envelope + messageTypeName:@"Secure Message" + missingPayloadBlock:^{ OWSProdFail([OWSAnalyticsEvents messageManagerErrorMessageEnvelopeHasNoContent]); - failureBlock(nil); - return; } - - @try { - WhisperMessage *message = [[WhisperMessage alloc] initWithData:encryptedData]; - SessionCipher *cipher = [[SessionCipher alloc] initWithSessionStore:storageManager - preKeyStore:storageManager - signedPreKeyStore:storageManager - identityKeyStore:self.identityManager - recipientId:recipientId - deviceId:deviceId]; - - NSData *plaintextData = [[cipher decrypt:message] removePadding]; - successBlock(plaintextData); - } @catch (NSException *exception) { - dispatch_async(dispatch_get_main_queue(), ^{ - [self processException:exception envelope:messageEnvelope]; - NSString *errorDescription = - [NSString stringWithFormat:@"Exception while decrypting: %@", exception.description]; - NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeFailedToDecryptMessage, errorDescription); - failureBlock(error); - }); + cipherMessageBlock:^(NSData *encryptedData) { + return [[WhisperMessage alloc] initWithData:encryptedData]; } - }); + successBlock:successBlock + failureBlock:failureBlock]; } -- (void)decryptPreKeyBundle:(OWSSignalServiceProtosEnvelope *)preKeyEnvelope +- (void)decryptPreKeyBundle:(OWSSignalServiceProtosEnvelope *)envelope successBlock:(DecryptSuccessBlock)successBlock failureBlock:(void (^)(NSError *_Nullable error))failureBlock { - OWSAssert(preKeyEnvelope); + OWSAssert(envelope); + OWSAssert(successBlock); + OWSAssert(failureBlock); + + // Check whether we need to refresh our PreKeys every time we receive a PreKeyWhisperMessage. + [TSPreKeyManager checkPreKeys]; + + [self decryptEnvelope:envelope + messageTypeName:@"PreKey Bundle" + missingPayloadBlock:^{ + OWSProdFail([OWSAnalyticsEvents messageManagerErrorPrekeyBundleEnvelopeHasNoContent]); + } + cipherMessageBlock:^(NSData *encryptedData) { + return [[PreKeyWhisperMessage alloc] initWithData:encryptedData]; + } + successBlock:successBlock + failureBlock:failureBlock]; +} + +- (void)decryptEnvelope:(OWSSignalServiceProtosEnvelope *)envelope + messageTypeName:(NSString *)messageTypeName + missingPayloadBlock:(void (^_Nonnull)())missingPayloadBlock + cipherMessageBlock:(id (^_Nonnull)(NSData *))cipherMessageBlock + successBlock:(DecryptSuccessBlock)successBlock + failureBlock:(void (^)(NSError *_Nullable error))failureBlock +{ + OWSAssert(envelope); + OWSAssert(messageTypeName.length > 0); + OWSAssert(missingPayloadBlock); + OWSAssert(cipherMessageBlock); OWSAssert(successBlock); OWSAssert(failureBlock); TSStorageManager *storageManager = [TSStorageManager sharedManager]; - NSString *recipientId = preKeyEnvelope.source; - int deviceId = preKeyEnvelope.sourceDevice; + NSString *recipientId = envelope.source; + int deviceId = envelope.sourceDevice; // DEPRECATED - Remove after all clients have been upgraded. - NSData *encryptedData = preKeyEnvelope.hasContent ? preKeyEnvelope.content : preKeyEnvelope.legacyMessage; + NSData *encryptedData = envelope.hasContent ? envelope.content : envelope.legacyMessage; if (!encryptedData) { - OWSProdFail([OWSAnalyticsEvents messageManagerErrorPrekeyBundleEnvelopeHasNoContent]); + missingPayloadBlock(); failureBlock(nil); return; } dispatch_async([OWSDispatch sessionStoreQueue], ^{ @try { - // Check whether we need to refresh our PreKeys every time we receive a PreKeyWhisperMessage. - [TSPreKeyManager checkPreKeys]; - - PreKeyWhisperMessage *message = [[PreKeyWhisperMessage alloc] initWithData:encryptedData]; + id cipherMessage = cipherMessageBlock(encryptedData); SessionCipher *cipher = [[SessionCipher alloc] initWithSessionStore:storageManager preKeyStore:storageManager signedPreKeyStore:storageManager @@ -440,13 +444,13 @@ const NSUInteger kIncomingMessageBatchSize = 10; recipientId:recipientId deviceId:deviceId]; - NSData *plaintextData = [[cipher decrypt:message] removePadding]; + NSData *plaintextData = [[cipher decrypt:cipherMessage] removePadding]; successBlock(plaintextData); } @catch (NSException *exception) { dispatch_async(dispatch_get_main_queue(), ^{ - [self processException:exception envelope:preKeyEnvelope]; - NSString *errorDescription = - [NSString stringWithFormat:@"Exception while decrypting PreKey Bundle: %@", exception.description]; + [self processException:exception envelope:envelope]; + NSString *errorDescription = [NSString + stringWithFormat:@"Exception while decrypting %@: %@", messageTypeName, exception.description]; NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeFailedToDecryptMessage, errorDescription); failureBlock(error); });