mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
Decouple message decryption and processing.
// FREEBIE
This commit is contained in:
parent
3abcbdf981
commit
c498e4b354
5 changed files with 257 additions and 194 deletions
|
@ -29,6 +29,7 @@
|
|||
#import <SignalServiceKit/OWSFailedAttachmentDownloadsJob.h>
|
||||
#import <SignalServiceKit/OWSFailedMessagesJob.h>
|
||||
#import <SignalServiceKit/OWSIncomingMessageReadObserver.h>
|
||||
#import <SignalServiceKit/OWSMessageDecrypter.h>
|
||||
#import <SignalServiceKit/OWSMessageSender.h>
|
||||
#import <SignalServiceKit/TSAccountManager.h>
|
||||
#import <SignalServiceKit/TSDatabaseView.h>
|
||||
|
@ -816,6 +817,7 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
|||
|
||||
// If there were any messages in our local queue which we hadn't yet processed.
|
||||
[[OWSMessageReceiver sharedInstance] handleAnyUnprocessedEnvelopesAsync];
|
||||
// [[OWSMessageDecrypter sharedInstance] handleAnyUnprocessedEnvelopesAsync];
|
||||
|
||||
[OWSProfileManager.sharedManager fetchLocalUsersProfile];
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
#pragma mark - Persisted data model
|
||||
|
||||
@class OWSSignalServiceProtosEnvelope;
|
||||
|
||||
@interface OWSMessageProcessingJob : TSYapDatabaseObject
|
||||
|
@ -27,12 +28,16 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@interface OWSMessageProcessingJob ()
|
||||
|
||||
@property (nonatomic, readonly) NSData *envelopeData;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation OWSMessageProcessingJob
|
||||
|
||||
- (instancetype)initWithEnvelope:(OWSSignalServiceProtosEnvelope *)envelope
|
||||
|
@ -70,12 +75,16 @@ NSString *const OWSMessageProcessingJobFinderExtensionGroup = @"OWSMessageProces
|
|||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@interface OWSMessageProcessingJobFinder ()
|
||||
|
||||
@property (nonatomic, readonly) YapDatabaseConnection *dbConnection;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation OWSMessageProcessingJobFinder
|
||||
|
||||
- (instancetype)initWithDBConnection:(YapDatabaseConnection *)dbConnection
|
||||
|
@ -118,7 +127,7 @@ NSString *const OWSMessageProcessingJobFinderExtensionGroup = @"OWSMessageProces
|
|||
}];
|
||||
}
|
||||
|
||||
+ (YapDatabaseView *)databaseExension
|
||||
+ (YapDatabaseView *)databaseExtension
|
||||
{
|
||||
YapDatabaseViewSorting *sorting =
|
||||
[YapDatabaseViewSorting withObjectBlock:^NSComparisonResult(YapDatabaseReadTransaction *transaction,
|
||||
|
@ -175,7 +184,7 @@ NSString *const OWSMessageProcessingJobFinderExtensionGroup = @"OWSMessageProces
|
|||
// already initialized
|
||||
return;
|
||||
}
|
||||
[database registerExtension:[self databaseExension] withName:OWSMessageProcessingJobFinderExtensionName];
|
||||
[database registerExtension:[self databaseExtension] withName:OWSMessageProcessingJobFinderExtensionName];
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -194,6 +203,8 @@ NSString *const OWSMessageProcessingJobFinderExtensionGroup = @"OWSMessageProces
|
|||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation OWSMessageProcessingQueue
|
||||
|
||||
- (instancetype)initWithMessagesManager:(TSMessagesManager *)messagesManager
|
||||
|
@ -248,17 +259,25 @@ NSString *const OWSMessageProcessingJobFinderExtensionGroup = @"OWSMessageProces
|
|||
DDLogVerbose(@"%@ completed job. %lu jobs left.",
|
||||
self.tag,
|
||||
(unsigned long)[OWSMessageProcessingJob numberOfKeysInCollection]);
|
||||
[self.finder removeJobWithId:job.uniqueId];
|
||||
[self drainQueueWorkStep];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)processJob:(OWSMessageProcessingJob *)job completion:(void (^)())completion
|
||||
{
|
||||
[self.messagesManager processEnvelope:job.envelopeProto
|
||||
completion:^{
|
||||
[self.finder removeJobWithId:job.uniqueId];
|
||||
completion();
|
||||
}];
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
[self.messagesManager decryptEnvelope:job.envelopeProto
|
||||
successBlock:^(NSData *_Nullable plaintextData) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self.messagesManager processEnvelope:job.envelopeProto plaintextData:plaintextData];
|
||||
completion();
|
||||
});
|
||||
}
|
||||
failureBlock:^{
|
||||
completion();
|
||||
}];
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark Logging
|
||||
|
@ -284,6 +303,8 @@ NSString *const OWSMessageProcessingJobFinderExtensionGroup = @"OWSMessageProces
|
|||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation OWSMessageReceiver
|
||||
|
||||
- (instancetype)initWithDBConnection:(YapDatabaseConnection *)dbConnection
|
||||
|
|
|
@ -17,6 +17,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
@protocol ContactsManagerProtocol;
|
||||
@protocol OWSCallMessageHandler;
|
||||
|
||||
typedef void (^DecryptSuccessBlock)(NSData *_Nullable plaintextData);
|
||||
typedef void (^DecryptFailureBlock)();
|
||||
typedef void (^MessageManagerCompletionBlock)();
|
||||
|
||||
@interface TSMessagesManager : NSObject
|
||||
|
@ -28,8 +30,13 @@ typedef void (^MessageManagerCompletionBlock)();
|
|||
@property (nonatomic, readonly) TSNetworkManager *networkManager;
|
||||
@property (nonatomic, readonly) ContactsUpdater *contactsUpdater;
|
||||
|
||||
- (void)processEnvelope:(OWSSignalServiceProtosEnvelope *)envelope
|
||||
completion:(nullable MessageManagerCompletionBlock)completion;
|
||||
// decryptEnvelope: can be called from any thread.
|
||||
// successBlock & failureBlock may be called on any thread.
|
||||
- (void)decryptEnvelope:(OWSSignalServiceProtosEnvelope *)envelope
|
||||
successBlock:(DecryptSuccessBlock)successBlock
|
||||
failureBlock:(DecryptFailureBlock)failureBlock;
|
||||
|
||||
- (void)processEnvelope:(OWSSignalServiceProtosEnvelope *)envelope plaintextData:(NSData *_Nullable)plaintextData;
|
||||
|
||||
- (NSUInteger)unreadMessagesCount;
|
||||
- (NSUInteger)unreadMessagesCountExcept:(TSThread *)thread;
|
||||
|
|
|
@ -260,84 +260,89 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return description;
|
||||
}
|
||||
|
||||
#pragma mark - message handling
|
||||
#pragma mark - Blocking
|
||||
|
||||
- (void)processEnvelope:(OWSSignalServiceProtosEnvelope *)envelope
|
||||
completion:(nullable MessageManagerCompletionBlock)completionHandler
|
||||
- (BOOL)isEnvelopeBlocked:(OWSSignalServiceProtosEnvelope *)envelope
|
||||
{
|
||||
OWSAssert([NSThread isMainThread]);
|
||||
OWSAssert(envelope);
|
||||
|
||||
return [_blockingManager.blockedPhoneNumbers containsObject:envelope.source];
|
||||
}
|
||||
|
||||
#pragma mark - Decryption
|
||||
|
||||
- (void)decryptEnvelope:(OWSSignalServiceProtosEnvelope *)envelope
|
||||
successBlock:(DecryptSuccessBlock)successBlockParameter
|
||||
failureBlock:(DecryptFailureBlock)failureBlockParameter
|
||||
{
|
||||
OWSAssert(envelope);
|
||||
OWSAssert(successBlockParameter);
|
||||
OWSAssert(failureBlockParameter);
|
||||
OWSAssert([TSAccountManager isRegistered]);
|
||||
|
||||
// Ensure that completionHandler is called on the main thread,
|
||||
// and handle the nil case.
|
||||
MessageManagerCompletionBlock completion = ^{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (completionHandler) {
|
||||
completionHandler();
|
||||
}
|
||||
// Ensure that successBlock and failureBlock are called on a worker queue.
|
||||
DecryptSuccessBlock successBlock = ^(NSData *_Nullable plaintextData) {
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
successBlockParameter(plaintextData);
|
||||
});
|
||||
};
|
||||
|
||||
DDLogInfo(@"%@ received envelope: %@", self.tag, [self descriptionForEnvelope:envelope]);
|
||||
DecryptFailureBlock failureBlock = ^() {
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
failureBlockParameter();
|
||||
});
|
||||
};
|
||||
DDLogInfo(@"%@ decrypting envelope: %@", self.tag, [self descriptionForEnvelope:envelope]);
|
||||
|
||||
OWSAssert(envelope.source.length > 0);
|
||||
BOOL isEnvelopeBlocked = [_blockingManager.blockedPhoneNumbers containsObject:envelope.source];
|
||||
if (isEnvelopeBlocked) {
|
||||
if ([self isEnvelopeBlocked:envelope]) {
|
||||
DDLogInfo(@"%@ ignoring blocked envelope: %@", self.tag, envelope.source);
|
||||
completion();
|
||||
failureBlock();
|
||||
return;
|
||||
}
|
||||
|
||||
@try {
|
||||
switch (envelope.type) {
|
||||
case OWSSignalServiceProtosEnvelopeTypeCiphertext: {
|
||||
[self handleSecureMessageAsync:envelope
|
||||
completion:^(NSError *_Nullable error) {
|
||||
DDLogDebug(@"%@ handled secure message.", self.tag);
|
||||
if (error) {
|
||||
DDLogError(
|
||||
@"%@ handling secure message from address: %@ failed with error: %@",
|
||||
self.tag,
|
||||
envelopeAddress(envelope),
|
||||
error);
|
||||
OWSProdError(
|
||||
[OWSAnalyticsEvents messageManagerErrorCouldNotHandleSecureMessage]);
|
||||
}
|
||||
completion();
|
||||
}];
|
||||
[self decryptSecureMessage:envelope
|
||||
successBlock:^(NSData *_Nullable plaintextData) {
|
||||
DDLogDebug(@"%@ decrypted secure message.", self.tag);
|
||||
successBlock(plaintextData);
|
||||
}
|
||||
failureBlock:^(NSError *_Nullable error) {
|
||||
DDLogError(@"%@ decrypting secure message from address: %@ failed with error: %@",
|
||||
self.tag,
|
||||
envelopeAddress(envelope),
|
||||
error);
|
||||
OWSProdError([OWSAnalyticsEvents messageManagerErrorCouldNotHandleSecureMessage]);
|
||||
failureBlock();
|
||||
}];
|
||||
// Return to avoid double-acknowledging.
|
||||
return;
|
||||
}
|
||||
case OWSSignalServiceProtosEnvelopeTypePrekeyBundle: {
|
||||
[self handlePreKeyBundleAsync:envelope
|
||||
completion:^(NSError *_Nullable error) {
|
||||
DDLogDebug(@"%@ handled pre-key whisper message", self.tag);
|
||||
if (error) {
|
||||
DDLogError(@"%@ handling pre-key whisper message from address: %@ failed "
|
||||
@"with error: %@",
|
||||
self.tag,
|
||||
envelopeAddress(envelope),
|
||||
error);
|
||||
OWSProdError(
|
||||
[OWSAnalyticsEvents messageManagerErrorCouldNotHandlePrekeyBundle]);
|
||||
}
|
||||
completion();
|
||||
}];
|
||||
[self decryptPreKeyBundle:envelope
|
||||
successBlock:^(NSData *_Nullable plaintextData) {
|
||||
DDLogDebug(@"%@ decrypted pre-key whisper message", self.tag);
|
||||
successBlock(plaintextData);
|
||||
}
|
||||
failureBlock:^(NSError *_Nullable error) {
|
||||
DDLogError(@"%@ decrypting pre-key whisper message from address: %@ failed "
|
||||
@"with error: %@",
|
||||
self.tag,
|
||||
envelopeAddress(envelope),
|
||||
error);
|
||||
OWSProdError([OWSAnalyticsEvents messageManagerErrorCouldNotHandlePrekeyBundle]);
|
||||
failureBlock();
|
||||
}];
|
||||
// Return to avoid double-acknowledging.
|
||||
return;
|
||||
}
|
||||
case OWSSignalServiceProtosEnvelopeTypeReceipt:
|
||||
[self handleDeliveryReceipt:envelope];
|
||||
break;
|
||||
|
||||
// Other messages are just dismissed for now.
|
||||
|
||||
case OWSSignalServiceProtosEnvelopeTypeKeyExchange:
|
||||
DDLogWarn(@"Received Key Exchange Message, not supported");
|
||||
break;
|
||||
case OWSSignalServiceProtosEnvelopeTypeUnknown:
|
||||
DDLogWarn(@"Received an unknown message type");
|
||||
break;
|
||||
successBlock(nil);
|
||||
// Return to avoid double-acknowledging.
|
||||
return;
|
||||
default:
|
||||
DDLogWarn(@"Received unhandled envelope type: %d", (int)envelope.type);
|
||||
break;
|
||||
|
@ -347,13 +352,140 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
OWSProdFail([OWSAnalyticsEvents messageManagerErrorInvalidProtocolMessage]);
|
||||
}
|
||||
|
||||
completion();
|
||||
failureBlock();
|
||||
}
|
||||
|
||||
- (void)decryptSecureMessage:(OWSSignalServiceProtosEnvelope *)messageEnvelope
|
||||
successBlock:(DecryptSuccessBlock)successBlock
|
||||
failureBlock:(void (^)(NSError *_Nullable error))failureBlock
|
||||
{
|
||||
OWSAssert(messageEnvelope);
|
||||
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) {
|
||||
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);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)decryptPreKeyBundle:(OWSSignalServiceProtosEnvelope *)preKeyEnvelope
|
||||
successBlock:(DecryptSuccessBlock)successBlock
|
||||
failureBlock:(void (^)(NSError *_Nullable error))failureBlock
|
||||
{
|
||||
OWSAssert(preKeyEnvelope);
|
||||
OWSAssert(successBlock);
|
||||
OWSAssert(failureBlock);
|
||||
|
||||
TSStorageManager *storageManager = [TSStorageManager sharedManager];
|
||||
NSString *recipientId = preKeyEnvelope.source;
|
||||
int deviceId = preKeyEnvelope.sourceDevice;
|
||||
|
||||
// DEPRECATED - Remove after all clients have been upgraded.
|
||||
NSData *encryptedData = preKeyEnvelope.hasContent ? preKeyEnvelope.content : preKeyEnvelope.legacyMessage;
|
||||
if (!encryptedData) {
|
||||
OWSProdFail([OWSAnalyticsEvents messageManagerErrorPrekeyBundleEnvelopeHasNoContent]);
|
||||
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];
|
||||
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:preKeyEnvelope];
|
||||
NSString *errorDescription =
|
||||
[NSString stringWithFormat:@"Exception while decrypting PreKey Bundle: %@", exception.description];
|
||||
NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeFailedToDecryptMessage, errorDescription);
|
||||
failureBlock(error);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark - message handling
|
||||
|
||||
// TODO: Add transaction parameter.
|
||||
- (void)processEnvelope:(OWSSignalServiceProtosEnvelope *)envelope plaintextData:(NSData *_Nullable)plaintextData
|
||||
{
|
||||
OWSAssert([TSAccountManager isRegistered]);
|
||||
|
||||
DDLogInfo(@"%@ received envelope: %@", self.tag, [self descriptionForEnvelope:envelope]);
|
||||
|
||||
OWSAssert(envelope.source.length > 0);
|
||||
OWSAssert(![self isEnvelopeBlocked:envelope]);
|
||||
|
||||
switch (envelope.type) {
|
||||
case OWSSignalServiceProtosEnvelopeTypeCiphertext:
|
||||
case OWSSignalServiceProtosEnvelopeTypePrekeyBundle:
|
||||
if (plaintextData) {
|
||||
[self handleEnvelope:envelope plaintextData:plaintextData];
|
||||
} else {
|
||||
OWSFail(
|
||||
@"%@ missing decrypted data for envelope: %@", self.tag, [self descriptionForEnvelope:envelope]);
|
||||
}
|
||||
break;
|
||||
case OWSSignalServiceProtosEnvelopeTypeReceipt:
|
||||
OWSAssert(!plaintextData);
|
||||
[self handleDeliveryReceipt:envelope];
|
||||
break;
|
||||
// Other messages are just dismissed for now.
|
||||
case OWSSignalServiceProtosEnvelopeTypeKeyExchange:
|
||||
DDLogWarn(@"Received Key Exchange Message, not supported");
|
||||
break;
|
||||
case OWSSignalServiceProtosEnvelopeTypeUnknown:
|
||||
DDLogWarn(@"Received an unknown message type");
|
||||
break;
|
||||
default:
|
||||
DDLogWarn(@"Received unhandled envelope type: %d", (int)envelope.type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)handleDeliveryReceipt:(OWSSignalServiceProtosEnvelope *)envelope
|
||||
{
|
||||
OWSAssert([NSThread isMainThread]);
|
||||
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
TSInteraction *interaction =
|
||||
[TSInteraction interactionForTimestamp:envelope.timestamp withTransaction:transaction];
|
||||
|
@ -364,110 +496,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
}];
|
||||
}
|
||||
|
||||
- (void)handleSecureMessageAsync:(OWSSignalServiceProtosEnvelope *)messageEnvelope
|
||||
completion:(void (^)(NSError *_Nullable error))completion
|
||||
{
|
||||
OWSAssert([NSThread isMainThread]);
|
||||
|
||||
@synchronized(self) {
|
||||
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) {
|
||||
OWSProdFail([OWSAnalyticsEvents messageManagerErrorMessageEnvelopeHasNoContent]);
|
||||
completion(nil);
|
||||
return;
|
||||
}
|
||||
|
||||
NSData *plaintextData;
|
||||
|
||||
@try {
|
||||
WhisperMessage *message = [[WhisperMessage alloc] initWithData:encryptedData];
|
||||
SessionCipher *cipher = [[SessionCipher alloc] initWithSessionStore:storageManager
|
||||
preKeyStore:storageManager
|
||||
signedPreKeyStore:storageManager
|
||||
identityKeyStore:self.identityManager
|
||||
recipientId:recipientId
|
||||
deviceId:deviceId];
|
||||
|
||||
plaintextData = [[cipher decrypt:message] removePadding];
|
||||
} @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);
|
||||
completion(error);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self handleEnvelope:messageEnvelope plaintextData:plaintextData];
|
||||
completion(nil);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
- (void)handlePreKeyBundleAsync:(OWSSignalServiceProtosEnvelope *)preKeyEnvelope
|
||||
completion:(void (^)(NSError *_Nullable error))completion
|
||||
{
|
||||
OWSAssert([NSThread isMainThread]);
|
||||
|
||||
@synchronized(self) {
|
||||
TSStorageManager *storageManager = [TSStorageManager sharedManager];
|
||||
NSString *recipientId = preKeyEnvelope.source;
|
||||
int deviceId = preKeyEnvelope.sourceDevice;
|
||||
|
||||
// DEPRECATED - Remove after all clients have been upgraded.
|
||||
NSData *encryptedData = preKeyEnvelope.hasContent ? preKeyEnvelope.content : preKeyEnvelope.legacyMessage;
|
||||
if (!encryptedData) {
|
||||
OWSProdFail([OWSAnalyticsEvents messageManagerErrorPrekeyBundleEnvelopeHasNoContent]);
|
||||
completion(nil);
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch_async([OWSDispatch sessionStoreQueue], ^{
|
||||
NSData *plaintextData;
|
||||
@try {
|
||||
// Check whether we need to refresh our PreKeys every time we receive a PreKeyWhisperMessage.
|
||||
[TSPreKeyManager checkPreKeys];
|
||||
|
||||
PreKeyWhisperMessage *message = [[PreKeyWhisperMessage alloc] initWithData:encryptedData];
|
||||
SessionCipher *cipher = [[SessionCipher alloc] initWithSessionStore:storageManager
|
||||
preKeyStore:storageManager
|
||||
signedPreKeyStore:storageManager
|
||||
identityKeyStore:self.identityManager
|
||||
recipientId:recipientId
|
||||
deviceId:deviceId];
|
||||
|
||||
plaintextData = [[cipher decrypt:message] removePadding];
|
||||
} @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];
|
||||
NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeFailedToDecryptMessage, errorDescription);
|
||||
completion(error);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self handleEnvelope:preKeyEnvelope plaintextData:plaintextData];
|
||||
completion(nil);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
- (void)handleEnvelope:(OWSSignalServiceProtosEnvelope *)envelope plaintextData:(NSData *)plaintextData
|
||||
{
|
||||
OWSAssert([NSThread isMainThread]);
|
||||
OWSAssert(envelope.hasTimestamp && envelope.timestamp > 0);
|
||||
OWSAssert(envelope.hasSource && envelope.source.length > 0);
|
||||
OWSAssert(envelope.hasSourceDevice && envelope.sourceDevice > 0);
|
||||
|
@ -1120,6 +1150,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
- (void)processException:(NSException *)exception envelope:(OWSSignalServiceProtosEnvelope *)envelope
|
||||
{
|
||||
OWSAssert([NSThread isMainThread]);
|
||||
|
||||
DDLogError(@"%@ Got exception: %@ of type: %@ with reason: %@",
|
||||
self.tag,
|
||||
exception.description,
|
||||
|
@ -1128,40 +1159,40 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
__block TSErrorMessage *errorMessage;
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
if ([exception.name isEqualToString:NoSessionException]) {
|
||||
OWSProdErrorWEnvelope([OWSAnalyticsEvents messageManagerErrorNoSession], envelope);
|
||||
errorMessage = [TSErrorMessage missingSessionWithEnvelope:envelope withTransaction:transaction];
|
||||
} else if ([exception.name isEqualToString:InvalidKeyException]) {
|
||||
OWSProdErrorWEnvelope([OWSAnalyticsEvents messageManagerErrorInvalidKey], envelope);
|
||||
errorMessage = [TSErrorMessage invalidKeyExceptionWithEnvelope:envelope withTransaction:transaction];
|
||||
} else if ([exception.name isEqualToString:InvalidKeyIdException]) {
|
||||
OWSProdErrorWEnvelope([OWSAnalyticsEvents messageManagerErrorInvalidKeyId], envelope);
|
||||
errorMessage = [TSErrorMessage invalidKeyExceptionWithEnvelope:envelope withTransaction:transaction];
|
||||
} else if ([exception.name isEqualToString:DuplicateMessageException]) {
|
||||
// Duplicate messages are dismissed
|
||||
return;
|
||||
} else if ([exception.name isEqualToString:InvalidVersionException]) {
|
||||
OWSProdErrorWEnvelope([OWSAnalyticsEvents messageManagerErrorInvalidMessageVersion], envelope);
|
||||
errorMessage = [TSErrorMessage invalidVersionWithEnvelope:envelope withTransaction:transaction];
|
||||
} else if ([exception.name isEqualToString:UntrustedIdentityKeyException]) {
|
||||
// Should no longer get here, since we now record the new identity for incoming messages.
|
||||
OWSProdErrorWEnvelope([OWSAnalyticsEvents messageManagerErrorUntrustedIdentityKeyException], envelope);
|
||||
OWSFail(@"%@ Failed to trust identity on incoming message from: %@", self.tag, envelopeAddress(envelope));
|
||||
return;
|
||||
} else {
|
||||
OWSProdErrorWEnvelope([OWSAnalyticsEvents messageManagerErrorCorruptMessage], envelope);
|
||||
errorMessage = [TSErrorMessage corruptedMessageWithEnvelope:envelope withTransaction:transaction];
|
||||
}
|
||||
if ([exception.name isEqualToString:NoSessionException]) {
|
||||
OWSProdErrorWEnvelope([OWSAnalyticsEvents messageManagerErrorNoSession], envelope);
|
||||
errorMessage = [TSErrorMessage missingSessionWithEnvelope:envelope withTransaction:transaction];
|
||||
} else if ([exception.name isEqualToString:InvalidKeyException]) {
|
||||
OWSProdErrorWEnvelope([OWSAnalyticsEvents messageManagerErrorInvalidKey], envelope);
|
||||
errorMessage = [TSErrorMessage invalidKeyExceptionWithEnvelope:envelope withTransaction:transaction];
|
||||
} else if ([exception.name isEqualToString:InvalidKeyIdException]) {
|
||||
OWSProdErrorWEnvelope([OWSAnalyticsEvents messageManagerErrorInvalidKeyId], envelope);
|
||||
errorMessage = [TSErrorMessage invalidKeyExceptionWithEnvelope:envelope withTransaction:transaction];
|
||||
} else if ([exception.name isEqualToString:DuplicateMessageException]) {
|
||||
// Duplicate messages are dismissed
|
||||
return;
|
||||
} else if ([exception.name isEqualToString:InvalidVersionException]) {
|
||||
OWSProdErrorWEnvelope([OWSAnalyticsEvents messageManagerErrorInvalidMessageVersion], envelope);
|
||||
errorMessage = [TSErrorMessage invalidVersionWithEnvelope:envelope withTransaction:transaction];
|
||||
} else if ([exception.name isEqualToString:UntrustedIdentityKeyException]) {
|
||||
// Should no longer get here, since we now record the new identity for incoming messages.
|
||||
OWSProdErrorWEnvelope([OWSAnalyticsEvents messageManagerErrorUntrustedIdentityKeyException], envelope);
|
||||
OWSFail(@"%@ Failed to trust identity on incoming message from: %@", self.tag, envelopeAddress(envelope));
|
||||
return;
|
||||
} else {
|
||||
OWSProdErrorWEnvelope([OWSAnalyticsEvents messageManagerErrorCorruptMessage], envelope);
|
||||
errorMessage = [TSErrorMessage corruptedMessageWithEnvelope:envelope withTransaction:transaction];
|
||||
}
|
||||
|
||||
[errorMessage saveWithTransaction:transaction];
|
||||
[errorMessage saveWithTransaction:transaction];
|
||||
}];
|
||||
|
||||
if (errorMessage != nil) {
|
||||
[self notififyForErrorMessage:errorMessage withEnvelope:envelope];
|
||||
[self notifyForErrorMessage:errorMessage withEnvelope:envelope];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)notififyForErrorMessage:(TSErrorMessage *)errorMessage withEnvelope:(OWSSignalServiceProtosEnvelope *)envelope
|
||||
- (void)notifyForErrorMessage:(TSErrorMessage *)errorMessage withEnvelope:(OWSSignalServiceProtosEnvelope *)envelope
|
||||
{
|
||||
TSThread *contactThread = [TSContactThread getOrCreateThreadWithContactId:envelope.source];
|
||||
[[TextSecureKitEnv sharedEnv].notificationsManager notifyUserForErrorMessage:errorMessage inThread:contactThread];
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#import "TSThread.h"
|
||||
#import <25519/Randomness.h>
|
||||
#import <SAMKeychain/SAMKeychain.h>
|
||||
#import <SignalServiceKit/OWSMessageDecrypter.h>
|
||||
#import <SignalServiceKit/OWSMessageReceiver.h>
|
||||
#import <YapDatabase/YapDatabaseRelationship.h>
|
||||
|
||||
|
@ -305,6 +306,7 @@ void setDatabaseInitialized()
|
|||
[TSDatabaseView registerUnreadDatabaseView];
|
||||
[self.database registerExtension:[TSDatabaseSecondaryIndexes registerTimeStampIndex] withName:@"idx"];
|
||||
[OWSMessageReceiver syncRegisterDatabaseExtension:self.database];
|
||||
// [OWSMessageDecrypter syncRegisterDatabaseExtension:self.database];
|
||||
|
||||
// See comments on OWSDatabaseConnection.
|
||||
//
|
||||
|
|
Loading…
Reference in a new issue