Pull out TSMessageDecrypter class.

// FREEBIE
pull/1/head
Matthew Chen 8 years ago
parent 46c4f4e445
commit b28c4b74b2

@ -30,10 +30,10 @@
#import <SignalServiceKit/OWSFailedAttachmentDownloadsJob.h>
#import <SignalServiceKit/OWSFailedMessagesJob.h>
#import <SignalServiceKit/OWSIncomingMessageReadObserver.h>
#import <SignalServiceKit/OWSMessageManager.h>
#import <SignalServiceKit/OWSMessageSender.h>
#import <SignalServiceKit/TSAccountManager.h>
#import <SignalServiceKit/TSDatabaseView.h>
#import <SignalServiceKit/TSMessagesManager.h>
#import <SignalServiceKit/TSPreKeyManager.h>
#import <SignalServiceKit/TSSocketManager.h>
#import <SignalServiceKit/TSStorageManager+Calling.h>

@ -6,9 +6,9 @@
#import "AttachmentUploadView.h"
#import "JSQMediaItem+OWS.h"
#import "MIMETypeUtil.h"
#import "OWSMessageManager.h"
#import "Signal-Swift.h"
#import "TSAttachmentStream.h"
#import "TSMessagesManager.h"
#import "UIColor+JSQMessages.h"
#import "UIColor+OWS.h"
#import "UIDevice+TSHardwareVersion.h"

@ -72,6 +72,7 @@
#import <SignalServiceKit/OWSGetMessagesRequest.h>
#import <SignalServiceKit/OWSGetProfileRequest.h>
#import <SignalServiceKit/OWSIdentityManager.h>
#import <SignalServiceKit/OWSMessageManager.h>
#import <SignalServiceKit/OWSMessageReceiver.h>
#import <SignalServiceKit/OWSMessageSender.h>
#import <SignalServiceKit/OWSOutgoingCallMessage.h>
@ -92,7 +93,6 @@
#import <SignalServiceKit/TSErrorMessage.h>
#import <SignalServiceKit/TSGroupThread.h>
#import <SignalServiceKit/TSInfoMessage.h>
#import <SignalServiceKit/TSMessagesManager.h>
#import <SignalServiceKit/TSNetworkManager.h>
#import <SignalServiceKit/TSPreKeyManager.h>
#import <SignalServiceKit/TSSocketManager.h>

@ -76,6 +76,7 @@
#import <SignalServiceKit/OWSBlockingManager.h>
#import <SignalServiceKit/OWSDisappearingMessagesConfiguration.h>
#import <SignalServiceKit/OWSIdentityManager.h>
#import <SignalServiceKit/OWSMessageManager.h>
#import <SignalServiceKit/OWSMessageSender.h>
#import <SignalServiceKit/OWSVerificationStateChangeMessage.h>
#import <SignalServiceKit/SignalRecipient.h>
@ -83,7 +84,6 @@
#import <SignalServiceKit/TSAccountManager.h>
#import <SignalServiceKit/TSGroupModel.h>
#import <SignalServiceKit/TSInvalidIdentityKeyReceivingErrorMessage.h>
#import <SignalServiceKit/TSMessagesManager.h>
#import <SignalServiceKit/TSNetworkManager.h>
#import <YapDatabase/YapDatabaseView.h>
@ -288,7 +288,7 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
@property (nonatomic, readonly) ContactsUpdater *contactsUpdater;
@property (nonatomic, readonly) OWSMessageSender *messageSender;
@property (nonatomic, readonly) TSStorageManager *storageManager;
@property (nonatomic, readonly) TSMessagesManager *messagesManager;
@property (nonatomic, readonly) OWSMessageManager *messagesManager;
@property (nonatomic, readonly) TSNetworkManager *networkManager;
@property (nonatomic, readonly) OutboundCallInitiator *outboundCallInitiator;
@property (nonatomic, readonly) OWSBlockingManager *blockingManager;
@ -371,7 +371,7 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
_messageSender = [Environment getCurrent].messageSender;
_outboundCallInitiator = [Environment getCurrent].outboundCallInitiator;
_storageManager = [TSStorageManager sharedManager];
_messagesManager = [TSMessagesManager sharedManager];
_messagesManager = [OWSMessageManager sharedManager];
_networkManager = [TSNetworkManager sharedManager];
_blockingManager = [OWSBlockingManager sharedManager];
_contactsViewHelper = [[ContactsViewHelper alloc] initWithDelegate:self];

@ -17,6 +17,7 @@
#import <SignalServiceKit/OWSVerificationStateChangeMessage.h>
#import <SignalServiceKit/SecurityUtils.h>
#import <SignalServiceKit/TSCall.h>
#import <SignalServiceKit/TSIncomingMessage.h>
#import <SignalServiceKit/TSInvalidIdentityKeyReceivingErrorMessage.h>
#import <SignalServiceKit/TSStorageManager+SessionStore.h>
#import <SignalServiceKit/TSThread.h>

@ -25,8 +25,8 @@
#import <PromiseKit/AnyPromise.h>
#import <SignalServiceKit/OWSBlockingManager.h>
#import <SignalServiceKit/OWSDisappearingMessagesJob.h>
#import <SignalServiceKit/OWSMessageManager.h>
#import <SignalServiceKit/OWSMessageSender.h>
#import <SignalServiceKit/TSMessagesManager.h>
#import <SignalServiceKit/TSOutgoingMessage.h>
#import <SignalServiceKit/Threading.h>
#import <YapDatabase/YapDatabaseViewChange.h>
@ -59,7 +59,7 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState };
@property (nonatomic, readonly) AccountManager *accountManager;
@property (nonatomic, readonly) OWSContactsManager *contactsManager;
@property (nonatomic, readonly) ExperienceUpgradeFinder *experienceUpgradeFinder;
@property (nonatomic, readonly) TSMessagesManager *messagesManager;
@property (nonatomic, readonly) OWSMessageManager *messagesManager;
@property (nonatomic, readonly) OWSMessageSender *messageSender;
@property (nonatomic, readonly) OWSBlockingManager *blockingManager;
@ -108,7 +108,7 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState };
{
_accountManager = [Environment getCurrent].accountManager;
_contactsManager = [Environment getCurrent].contactsManager;
_messagesManager = [TSMessagesManager sharedManager];
_messagesManager = [OWSMessageManager sharedManager];
_messageSender = [Environment getCurrent].messageSender;
_blockingManager = [OWSBlockingManager sharedManager];
_blockedPhoneNumberSet = [NSSet setWithArray:[_blockingManager blockedPhoneNumbers]];

@ -7,9 +7,9 @@
#import "Signal-Swift.h"
#import "Util.h"
#import "ViewControllerUtils.h"
#import <SignalServiceKit/OWSMessageManager.h>
#import <SignalServiceKit/TSContactThread.h>
#import <SignalServiceKit/TSGroupThread.h>
#import <SignalServiceKit/TSMessagesManager.h>
#import <SignalServiceKit/TSThread.h>
NS_ASSUME_NONNULL_BEGIN
@ -204,9 +204,9 @@ const NSUInteger kAvatarViewDiameter = 52;
}
NSAttributedString *attributedDate = [self dateAttributedString:thread.lastMessageDate];
NSUInteger unreadCount = [[TSMessagesManager sharedManager] unreadMessagesInThread:thread];
NSUInteger unreadCount = [[OWSMessageManager sharedManager] unreadMessagesInThread:thread];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(otherUsersProfileDidChange:)
name:kNSNotificationName_OtherUsersProfileDidChange

@ -16,6 +16,8 @@
#import <SignalServiceKit/OWSMessageSender.h>
#import <SignalServiceKit/OWSUnknownContactBlockOfferMessage.h>
#import <SignalServiceKit/TSDatabaseView.h>
#import <SignalServiceKit/TSIncomingMessage.h>
#import <SignalServiceKit/TSInvalidIdentityKeyErrorMessage.h>
#import <SignalServiceKit/TSOutgoingMessage.h>
#import <SignalServiceKit/TSThread.h>

@ -3,11 +3,11 @@
//
#import "OWSIncomingSentMessageTranscript.h"
#import "OWSMessageManager.h"
#import "OWSSignalServiceProtos.pb.h"
#import "TSContactThread.h"
#import "TSGroupModel.h"
#import "TSGroupThread.h"
#import "TSMessagesManager.h"
#import "TSOutgoingMessage.h"
#import "TSStorageManager.h"
#import "TSThread.h"

@ -5,9 +5,9 @@
#import "TSErrorMessage.h"
#import "ContactsManagerProtocol.h"
#import "NSDate+millisecondTimeStamp.h"
#import "OWSMessageManager.h"
#import "TSContactThread.h"
#import "TSErrorMessage_privateConstructor.h"
#import "TSMessagesManager.h"
#import "TextSecureKitEnv.h"
#import <YapDatabase/YapDatabaseConnection.h>

@ -5,11 +5,11 @@
#import "TSInvalidIdentityKeyReceivingErrorMessage.h"
#import "OWSFingerprint.h"
#import "OWSIdentityManager.h"
#import "OWSMessageManager.h"
#import "OWSMessageReceiver.h"
#import "TSContactThread.h"
#import "TSDatabaseView.h"
#import "TSErrorMessage_privateConstructor.h"
#import "TSMessagesManager.h"
#import "TSStorageManager.h"
#import <AxolotlKit/NSData+keyVersionByte.h>
#import <AxolotlKit/PreKeyWhisperMessage.h>

@ -4,9 +4,9 @@
#import "OWSBatchMessageProcessor.h"
#import "NSArray+OWS.h"
#import "OWSMessageManager.h"
#import "OWSSignalServiceProtos.pb.h"
#import "TSDatabaseView.h"
#import "TSMessagesManager.h"
#import "TSStorageManager.h"
#import "TSYapDatabaseObject.h"
#import "Threading.h"
@ -211,12 +211,12 @@ NSString *const OWSMessageContentJobFinderExtensionGroup = @"OWSBatchMessageProc
@interface OWSMessageContentQueue : NSObject
@property (nonatomic, readonly) TSMessagesManager *messagesManager;
@property (nonatomic, readonly) OWSMessageManager *messagesManager;
@property (nonatomic, readonly) YapDatabaseConnection *dbReadWriteConnection;
@property (nonatomic, readonly) OWSMessageContentJobFinder *finder;
@property (nonatomic) BOOL isDrainingQueue;
- (instancetype)initWithMessagesManager:(TSMessagesManager *)messagesManager
- (instancetype)initWithMessagesManager:(OWSMessageManager *)messagesManager
storageManager:(TSStorageManager *)storageManager
finder:(OWSMessageContentJobFinder *)finder NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@ -227,7 +227,7 @@ NSString *const OWSMessageContentJobFinderExtensionGroup = @"OWSBatchMessageProc
@implementation OWSMessageContentQueue
- (instancetype)initWithMessagesManager:(TSMessagesManager *)messagesManager
- (instancetype)initWithMessagesManager:(OWSMessageManager *)messagesManager
storageManager:(TSStorageManager *)storageManager
finder:(OWSMessageContentJobFinder *)finder
{
@ -356,7 +356,7 @@ NSString *const OWSMessageContentJobFinderExtensionGroup = @"OWSBatchMessageProc
@implementation OWSBatchMessageProcessor
- (instancetype)initWithDBConnection:(YapDatabaseConnection *)dbConnection
messagesManager:(TSMessagesManager *)messagesManager
messagesManager:(OWSMessageManager *)messagesManager
storageManager:(TSStorageManager *)storageManager
{
OWSSingletonAssert();
@ -380,7 +380,7 @@ NSString *const OWSMessageContentJobFinderExtensionGroup = @"OWSBatchMessageProc
{
// For concurrency coherency we use the same dbConnection to persist and read the unprocessed envelopes
YapDatabaseConnection *dbConnection = [[TSStorageManager sharedManager].database newConnection];
TSMessagesManager *messagesManager = [TSMessagesManager sharedManager];
OWSMessageManager *messagesManager = [OWSMessageManager sharedManager];
TSStorageManager *storageManager = [TSStorageManager sharedManager];
return [self initWithDBConnection:dbConnection messagesManager:messagesManager storageManager:storageManager];

@ -0,0 +1,30 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "OWSMessageHandler.h"
NS_ASSUME_NONNULL_BEGIN
@class OWSSignalServiceProtosEnvelope;
typedef void (^DecryptSuccessBlock)(NSData *_Nullable plaintextData);
typedef void (^DecryptFailureBlock)();
@interface OWSMessageDecrypter : OWSMessageHandler
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)sharedManager;
// 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;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,326 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "OWSMessageDecrypter.h"
#import "NSData+messagePadding.h"
#import "NotificationsProtocol.h"
#import "OWSAnalytics.h"
#import "OWSBlockingManager.h"
#import "OWSError.h"
#import "OWSIdentityManager.h"
#import "OWSSignalServiceProtos.pb.h"
#import "TSAccountManager.h"
#import "TSContactThread.h"
#import "TSErrorMessage.h"
#import "TSPreKeyManager.h"
#import "TSStorageManager+PreKeyStore.h"
#import "TSStorageManager+SessionStore.h"
#import "TSStorageManager+SignedPreKeyStore.h"
#import "TSStorageManager.h"
#import "TextSecureKitEnv.h"
#import <AxolotlKit/AxolotlExceptions.h>
#import <AxolotlKit/SessionCipher.h>
NS_ASSUME_NONNULL_BEGIN
@interface OWSMessageDecrypter ()
@property (nonatomic, readonly) TSStorageManager *storageManager;
@property (nonatomic, readonly) YapDatabaseConnection *dbConnection;
@property (nonatomic, readonly) OWSBlockingManager *blockingManager;
@property (nonatomic, readonly) OWSIdentityManager *identityManager;
@end
#pragma mark -
@implementation OWSMessageDecrypter
+ (instancetype)sharedManager
{
static OWSMessageDecrypter *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] initDefault];
});
return sharedMyManager;
}
- (instancetype)initDefault
{
TSStorageManager *storageManager = [TSStorageManager sharedManager];
OWSIdentityManager *identityManager = [OWSIdentityManager sharedManager];
OWSBlockingManager *blockingManager = [OWSBlockingManager sharedManager];
return [self initWithStorageManager:storageManager identityManager:identityManager blockingManager:blockingManager];
}
- (instancetype)initWithStorageManager:(TSStorageManager *)storageManager
identityManager:(OWSIdentityManager *)identityManager
blockingManager:(OWSBlockingManager *)blockingManager
{
self = [super init];
if (!self) {
return self;
}
_storageManager = storageManager;
_identityManager = identityManager;
_blockingManager = blockingManager;
_dbConnection = storageManager.newDatabaseConnection;
OWSSingletonAssert();
return self;
}
#pragma mark - Blocking
- (BOOL)isEnvelopeBlocked:(OWSSignalServiceProtosEnvelope *)envelope
{
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 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);
});
};
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);
if ([self isEnvelopeBlocked:envelope]) {
DDLogInfo(@"%@ ignoring blocked envelope: %@", self.tag, envelope.source);
failureBlock();
return;
}
@try {
switch (envelope.type) {
case OWSSignalServiceProtosEnvelopeTypeCiphertext: {
[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 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;
}
// These message types don't have a payload to decrypt.
case OWSSignalServiceProtosEnvelopeTypeReceipt:
case OWSSignalServiceProtosEnvelopeTypeKeyExchange:
case OWSSignalServiceProtosEnvelopeTypeUnknown:
successBlock(nil);
// Return to avoid double-acknowledging.
return;
default:
DDLogWarn(@"Received unhandled envelope type: %d", (int)envelope.type);
break;
}
} @catch (NSException *exception) {
DDLogError(@"Received an incorrectly formatted protocol buffer: %@", exception.debugDescription);
OWSProdFail([OWSAnalyticsEvents messageManagerErrorInvalidProtocolMessage]);
}
failureBlock();
}
- (void)decryptSecureMessage:(OWSSignalServiceProtosEnvelope *)envelope
successBlock:(DecryptSuccessBlock)successBlock
failureBlock:(void (^)(NSError *_Nullable error))failureBlock
{
OWSAssert(envelope);
OWSAssert(successBlock);
OWSAssert(failureBlock);
[self decryptEnvelope:envelope
cipherTypeName:@"Secure Message"
cipherMessageBlock:^(NSData *encryptedData) {
return [[WhisperMessage alloc] initWithData:encryptedData];
}
successBlock:successBlock
failureBlock:failureBlock];
}
- (void)decryptPreKeyBundle:(OWSSignalServiceProtosEnvelope *)envelope
successBlock:(DecryptSuccessBlock)successBlock
failureBlock:(void (^)(NSError *_Nullable error))failureBlock
{
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
cipherTypeName:@"PreKey Bundle"
cipherMessageBlock:^(NSData *encryptedData) {
return [[PreKeyWhisperMessage alloc] initWithData:encryptedData];
}
successBlock:successBlock
failureBlock:failureBlock];
}
- (void)decryptEnvelope:(OWSSignalServiceProtosEnvelope *)envelope
cipherTypeName:(NSString *)cipherTypeName
cipherMessageBlock:(id<CipherMessage> (^_Nonnull)(NSData *))cipherMessageBlock
successBlock:(DecryptSuccessBlock)successBlock
failureBlock:(void (^)(NSError *_Nullable error))failureBlock
{
OWSAssert(envelope);
OWSAssert(cipherTypeName.length > 0);
OWSAssert(cipherMessageBlock);
OWSAssert(successBlock);
OWSAssert(failureBlock);
TSStorageManager *storageManager = self.storageManager;
NSString *recipientId = envelope.source;
int deviceId = envelope.sourceDevice;
// DEPRECATED - Remove after all clients have been upgraded.
NSData *encryptedData = envelope.hasContent ? envelope.content : envelope.legacyMessage;
if (!encryptedData) {
OWSProdFail([OWSAnalyticsEvents messageManagerErrorMessageEnvelopeHasNoContent]);
failureBlock(nil);
return;
}
dispatch_async([OWSDispatch sessionStoreQueue], ^{
@try {
id<CipherMessage> cipherMessage = cipherMessageBlock(encryptedData);
SessionCipher *cipher = [[SessionCipher alloc] initWithSessionStore:storageManager
preKeyStore:storageManager
signedPreKeyStore:storageManager
identityKeyStore:self.identityManager
recipientId:recipientId
deviceId:deviceId];
NSData *plaintextData = [[cipher decrypt:cipherMessage] removePadding];
successBlock(plaintextData);
} @catch (NSException *exception) {
dispatch_async(dispatch_get_main_queue(), ^{
[self processException:exception envelope:envelope];
NSString *errorDescription = [NSString
stringWithFormat:@"Exception while decrypting %@: %@", cipherTypeName, exception.description];
NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeFailedToDecryptMessage, errorDescription);
failureBlock(error);
});
}
});
}
- (void)processException:(NSException *)exception envelope:(OWSSignalServiceProtosEnvelope *)envelope
{
OWSAssert([NSThread isMainThread]);
DDLogError(@"%@ Got exception: %@ of type: %@ with reason: %@",
self.tag,
exception.description,
exception.name,
exception.reason);
__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];
}
[errorMessage saveWithTransaction:transaction];
}];
if (errorMessage != nil) {
[self notifyForErrorMessage:errorMessage withEnvelope:envelope];
}
}
- (void)notifyForErrorMessage:(TSErrorMessage *)errorMessage withEnvelope:(OWSSignalServiceProtosEnvelope *)envelope
{
TSThread *contactThread = [TSContactThread getOrCreateThreadWithContactId:envelope.source];
[[TextSecureKitEnv sharedEnv].notificationsManager notifyUserForErrorMessage:errorMessage inThread:contactThread];
}
#pragma mark - Logging
+ (NSString *)tag
{
return [NSString stringWithFormat:@"[%@]", self.class];
}
- (NSString *)tag
{
return self.class.tag;
}
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,24 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
NS_ASSUME_NONNULL_BEGIN
extern const NSUInteger kIncomingMessageBatchSize;
@class OWSSignalServiceProtosContent;
@class OWSSignalServiceProtosDataMessage;
@class OWSSignalServiceProtosEnvelope;
NSString *envelopeAddress(OWSSignalServiceProtosEnvelope *envelope);
@interface OWSMessageHandler : NSObject
- (NSString *)descriptionForEnvelopeType:(OWSSignalServiceProtosEnvelope *)envelope;
- (NSString *)descriptionForEnvelope:(OWSSignalServiceProtosEnvelope *)envelope;
- (NSString *)descriptionForContent:(OWSSignalServiceProtosContent *)content;
- (NSString *)descriptionForDataMessage:(OWSSignalServiceProtosDataMessage *)dataMessage;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,163 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "OWSMessageHandler.h"
#import "OWSSignalServiceProtos.pb.h"
NS_ASSUME_NONNULL_BEGIN
// We need to use a consistent batch size throughout
// the incoming message pipeline (i.e. in the
// "decrypt" and "process" steps), or the pipeline
// doesn't flow smoothly.
//
// We want a value that is just high enough to yield
// perf benefits. The right value is probably 5-15.
const NSUInteger kIncomingMessageBatchSize = 10;
// used in log formatting
NSString *envelopeAddress(OWSSignalServiceProtosEnvelope *envelope)
{
return [NSString stringWithFormat:@"%@.%d", envelope.source, (unsigned int)envelope.sourceDevice];
}
@implementation OWSMessageHandler
- (NSString *)descriptionForEnvelopeType:(OWSSignalServiceProtosEnvelope *)envelope
{
OWSAssert(envelope != nil);
switch (envelope.type) {
case OWSSignalServiceProtosEnvelopeTypeReceipt:
return @"DeliveryReceipt";
case OWSSignalServiceProtosEnvelopeTypeUnknown:
// Shouldn't happen
OWSProdFail([OWSAnalyticsEvents messageManagerErrorEnvelopeTypeUnknown]);
return @"Unknown";
case OWSSignalServiceProtosEnvelopeTypeCiphertext:
return @"SignalEncryptedMessage";
case OWSSignalServiceProtosEnvelopeTypeKeyExchange:
// Unsupported
OWSProdFail([OWSAnalyticsEvents messageManagerErrorEnvelopeTypeKeyExchange]);
return @"KeyExchange";
case OWSSignalServiceProtosEnvelopeTypePrekeyBundle:
return @"PreKeyEncryptedMessage";
default:
// Shouldn't happen
OWSProdFail([OWSAnalyticsEvents messageManagerErrorEnvelopeTypeOther]);
return @"Other";
}
}
- (NSString *)descriptionForEnvelope:(OWSSignalServiceProtosEnvelope *)envelope
{
OWSAssert(envelope != nil);
return [NSString stringWithFormat:@"<Envelope type: %@, source: %@, timestamp: %llu content.length: %lu />",
[self descriptionForEnvelopeType:envelope],
envelopeAddress(envelope),
envelope.timestamp,
(unsigned long)envelope.content.length];
}
/**
* We don't want to just log `content.description` because we'd potentially log message bodies for dataMesssages and
* sync transcripts
*/
- (NSString *)descriptionForContent:(OWSSignalServiceProtosContent *)content
{
if (content.hasSyncMessage) {
return [NSString stringWithFormat:@"<SyncMessage: %@ />", [self descriptionForSyncMessage:content.syncMessage]];
} else if (content.hasDataMessage) {
return [NSString stringWithFormat:@"<DataMessage: %@ />", [self descriptionForDataMessage:content.dataMessage]];
} else if (content.hasCallMessage) {
return [NSString stringWithFormat:@"<CallMessage: %@ />", content.callMessage];
} else if (content.hasNullMessage) {
return [NSString stringWithFormat:@"<NullMessage: %@ />", content.nullMessage];
} else {
// Don't fire an analytics event; if we ever add a new content type, we'd generate a ton of
// analytics traffic.
OWSFail(@"Unknown content type.");
return @"UnknownContent";
}
}
/**
* We don't want to just log `dataMessage.description` because we'd potentially log message contents
*/
- (NSString *)descriptionForDataMessage:(OWSSignalServiceProtosDataMessage *)dataMessage
{
NSMutableString *description = [NSMutableString new];
if (dataMessage.hasGroup) {
[description appendString:@"(Group:YES) "];
}
if ((dataMessage.flags & OWSSignalServiceProtosDataMessageFlagsEndSession) != 0) {
[description appendString:@"EndSession"];
} else if ((dataMessage.flags & OWSSignalServiceProtosDataMessageFlagsExpirationTimerUpdate) != 0) {
[description appendString:@"ExpirationTimerUpdate"];
} else if ((dataMessage.flags & OWSSignalServiceProtosDataMessageFlagsProfileKey) != 0) {
[description appendString:@"ProfileKey"];
} else if (dataMessage.attachments.count > 0) {
[description appendString:@"MessageWithAttachment"];
} else {
[description appendString:@"Plain"];
}
return [NSString stringWithFormat:@"<%@ />", description];
}
/**
* We don't want to just log `syncMessage.description` because we'd potentially log message contents in sent transcripts
*/
- (NSString *)descriptionForSyncMessage:(OWSSignalServiceProtosSyncMessage *)syncMessage
{
NSMutableString *description = [NSMutableString new];
if (syncMessage.hasSent) {
[description appendString:@"SentTranscript"];
} else if (syncMessage.hasRequest) {
if (syncMessage.request.type == OWSSignalServiceProtosSyncMessageRequestTypeContacts) {
[description appendString:@"ContactRequest"];
} else if (syncMessage.request.type == OWSSignalServiceProtosSyncMessageRequestTypeGroups) {
[description appendString:@"GroupRequest"];
} else if (syncMessage.request.type == OWSSignalServiceProtosSyncMessageRequestTypeBlocked) {
[description appendString:@"BlockedRequest"];
} else {
// Shouldn't happen
OWSFail(@"Unknown sync message request type");
[description appendString:@"UnknownRequest"];
}
} else if (syncMessage.hasBlocked) {
[description appendString:@"Blocked"];
} else if (syncMessage.read.count > 0) {
[description appendString:@"ReadReceipt"];
} else if (syncMessage.hasVerified) {
NSString *verifiedString =
[NSString stringWithFormat:@"Verification for: %@", syncMessage.verified.destination];
[description appendString:verifiedString];
} else {
// Shouldn't happen
OWSFail(@"Unknown sync message type");
[description appendString:@"Unknown"];
}
return description;
}
#pragma mark - Logging
+ (NSString *)tag
{
return [NSString stringWithFormat:@"[%@]", self.class];
}
- (NSString *)tag
{
return self.class.tag;
}
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,29 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "OWSMessageHandler.h"
NS_ASSUME_NONNULL_BEGIN
@class OWSSignalServiceProtosEnvelope;
@class TSThread;
@class YapDatabaseReadWriteTransaction;
@interface OWSMessageManager : OWSMessageHandler
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)sharedManager;
// processEnvelope: can be called from any thread.
- (void)processEnvelope:(OWSSignalServiceProtosEnvelope *)envelope
plaintextData:(NSData *_Nullable)plaintextData
transaction:(YapDatabaseReadWriteTransaction *)transaction;
- (NSUInteger)unreadMessagesCount;
- (NSUInteger)unreadMessagesCountExcept:(TSThread *)thread;
- (NSUInteger)unreadMessagesInThread:(TSThread *)thread;
@end
NS_ASSUME_NONNULL_END

@ -2,13 +2,10 @@
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "TSMessagesManager.h"
#import "OWSMessageManager.h"
#import "ContactsManagerProtocol.h"
#import "ContactsUpdater.h"
#import "Cryptography.h"
#import "DataSource.h"
#import "MimeTypeUtil.h"
#import "NSData+messagePadding.h"
#import "NSDate+millisecondTimeStamp.h"
#import "NotificationsProtocol.h"
#import "OWSAttachmentsProcessor.h"
@ -17,7 +14,7 @@
#import "OWSDisappearingConfigurationUpdateInfoMessage.h"
#import "OWSDisappearingMessagesConfiguration.h"
#import "OWSDisappearingMessagesJob.h"
#import "OWSError.h"
#import "OWSIdentityManager.h"
#import "OWSIncomingMessageFinder.h"
#import "OWSIncomingSentMessageTranscript.h"
#import "OWSMessageSender.h"
@ -28,33 +25,21 @@
#import "OWSSyncGroupsRequestMessage.h"
#import "ProfileManagerProtocol.h"
#import "TSAccountManager.h"
#import "TSAttachmentStream.h"
#import "TSCall.h"
#import "TSContactThread.h"
#import "TSDatabaseView.h"
#import "TSGroupModel.h"
#import "TSGroupThread.h"
#import "TSIncomingMessage.h"
#import "TSInfoMessage.h"
#import "TSInvalidIdentityKeyReceivingErrorMessage.h"
#import "TSNetworkManager.h"
#import "TSPreKeyManager.h"
#import "TSStorageHeaders.h"
#import "TSOutgoingMessage.h"
#import "TSStorageManager+SessionStore.h"
#import "TSStorageManager.h"
#import "TextSecureKitEnv.h"
#import <AxolotlKit/AxolotlExceptions.h>
#import <AxolotlKit/SessionCipher.h>
NS_ASSUME_NONNULL_BEGIN
// We need to use a consistent batch size throughout
// the incoming message pipeline (i.e. in the
// "decrypt" and "process" steps), or the pipeline
// doesn't flow smoothly.
//
// We want a value that is just high enough to yield
// perf benefits. The right value is probably 5-15.
const NSUInteger kIncomingMessageBatchSize = 10;
@interface TSMessagesManager ()
@interface OWSMessageManager ()
@property (nonatomic, readonly) id<OWSCallMessageHandler> callMessageHandler;
@property (nonatomic, readonly) id<ContactsManagerProtocol> contactsManager;
@ -63,15 +48,18 @@ const NSUInteger kIncomingMessageBatchSize = 10;
@property (nonatomic, readonly) OWSIncomingMessageFinder *incomingMessageFinder;
@property (nonatomic, readonly) OWSBlockingManager *blockingManager;
@property (nonatomic, readonly) OWSIdentityManager *identityManager;
@property (nonatomic, readonly) TSNetworkManager *networkManager;
@property (nonatomic, readonly) YapDatabaseConnection *dbConnection;
@end
#pragma mark -
@implementation TSMessagesManager
@implementation OWSMessageManager
+ (instancetype)sharedManager {
static TSMessagesManager *sharedMyManager = nil;
+ (instancetype)sharedManager
{
static OWSMessageManager *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] initDefault];
@ -85,16 +73,14 @@ const NSUInteger kIncomingMessageBatchSize = 10;
TSStorageManager *storageManager = [TSStorageManager sharedManager];
id<ContactsManagerProtocol> contactsManager = [TextSecureKitEnv sharedEnv].contactsManager;
id<OWSCallMessageHandler> callMessageHandler = [TextSecureKitEnv sharedEnv].callMessageHandler;
ContactsUpdater *contactsUpdater = [ContactsUpdater sharedUpdater];
OWSIdentityManager *identityManager = [OWSIdentityManager sharedManager];
OWSMessageSender *messageSender = [TextSecureKitEnv sharedEnv].messageSender;
return [self initWithNetworkManager:networkManager
storageManager:storageManager
callMessageHandler:callMessageHandler
contactsManager:contactsManager
contactsUpdater:contactsUpdater
identityManager:identityManager
messageSender:messageSender];
}
@ -103,7 +89,6 @@ const NSUInteger kIncomingMessageBatchSize = 10;
storageManager:(TSStorageManager *)storageManager
callMessageHandler:(id<OWSCallMessageHandler>)callMessageHandler
contactsManager:(id<ContactsManagerProtocol>)contactsManager
contactsUpdater:(ContactsUpdater *)contactsUpdater
identityManager:(OWSIdentityManager *)identityManager
messageSender:(OWSMessageSender *)messageSender
{
@ -117,7 +102,6 @@ const NSUInteger kIncomingMessageBatchSize = 10;
_networkManager = networkManager;
_callMessageHandler = callMessageHandler;
_contactsManager = contactsManager;
_contactsUpdater = contactsUpdater;
_identityManager = identityManager;
_messageSender = messageSender;
@ -145,130 +129,6 @@ const NSUInteger kIncomingMessageBatchSize = 10;
[self updateApplicationBadgeCount];
}
#pragma mark - Debugging
- (NSString *)descriptionForEnvelopeType:(OWSSignalServiceProtosEnvelope *)envelope
{
OWSAssert(envelope != nil);
switch (envelope.type) {
case OWSSignalServiceProtosEnvelopeTypeReceipt:
return @"DeliveryReceipt";
case OWSSignalServiceProtosEnvelopeTypeUnknown:
// Shouldn't happen
OWSProdFail([OWSAnalyticsEvents messageManagerErrorEnvelopeTypeUnknown]);
return @"Unknown";
case OWSSignalServiceProtosEnvelopeTypeCiphertext:
return @"SignalEncryptedMessage";
case OWSSignalServiceProtosEnvelopeTypeKeyExchange:
// Unsupported
OWSProdFail([OWSAnalyticsEvents messageManagerErrorEnvelopeTypeKeyExchange]);
return @"KeyExchange";
case OWSSignalServiceProtosEnvelopeTypePrekeyBundle:
return @"PreKeyEncryptedMessage";
default:
// Shouldn't happen
OWSProdFail([OWSAnalyticsEvents messageManagerErrorEnvelopeTypeOther]);
return @"Other";
}
}
- (NSString *)descriptionForEnvelope:(OWSSignalServiceProtosEnvelope *)envelope
{
OWSAssert(envelope != nil);
return [NSString stringWithFormat:@"<Envelope type: %@, source: %@, timestamp: %llu content.length: %lu />",
[self descriptionForEnvelopeType:envelope],
envelopeAddress(envelope),
envelope.timestamp,
(unsigned long)envelope.content.length];
}
/**
* We don't want to just log `content.description` because we'd potentially log message bodies for dataMesssages and
* sync transcripts
*/
- (NSString *)descriptionForContent:(OWSSignalServiceProtosContent *)content
{
if (content.hasSyncMessage) {
return [NSString stringWithFormat:@"<SyncMessage: %@ />", [self descriptionForSyncMessage:content.syncMessage]];
} else if (content.hasDataMessage) {
return [NSString stringWithFormat:@"<DataMessage: %@ />", [self descriptionForDataMessage:content.dataMessage]];
} else if (content.hasCallMessage) {
return [NSString stringWithFormat:@"<CallMessage: %@ />", content.callMessage];
} else if (content.hasNullMessage) {
return [NSString stringWithFormat:@"<NullMessage: %@ />", content.nullMessage];
} else {
// Don't fire an analytics event; if we ever add a new content type, we'd generate a ton of
// analytics traffic.
OWSFail(@"Unknown content type.");
return @"UnknownContent";
}
}
/**
* We don't want to just log `dataMessage.description` because we'd potentially log message contents
*/
- (NSString *)descriptionForDataMessage:(OWSSignalServiceProtosDataMessage *)dataMessage
{
NSMutableString *description = [NSMutableString new];
if (dataMessage.hasGroup) {
[description appendString:@"(Group:YES) "];
}
if ((dataMessage.flags & OWSSignalServiceProtosDataMessageFlagsEndSession) != 0) {
[description appendString:@"EndSession"];
} else if ((dataMessage.flags & OWSSignalServiceProtosDataMessageFlagsExpirationTimerUpdate) != 0) {
[description appendString:@"ExpirationTimerUpdate"];
} else if ((dataMessage.flags & OWSSignalServiceProtosDataMessageFlagsProfileKey) != 0) {
[description appendString:@"ProfileKey"];
} else if (dataMessage.attachments.count > 0) {
[description appendString:@"MessageWithAttachment"];
} else {
[description appendString:@"Plain"];
}
return [NSString stringWithFormat:@"<%@ />", description];
}
/**
* We don't want to just log `syncMessage.description` because we'd potentially log message contents in sent transcripts
*/
- (NSString *)descriptionForSyncMessage:(OWSSignalServiceProtosSyncMessage *)syncMessage
{
NSMutableString *description = [NSMutableString new];
if (syncMessage.hasSent) {
[description appendString:@"SentTranscript"];
} else if (syncMessage.hasRequest) {
if (syncMessage.request.type == OWSSignalServiceProtosSyncMessageRequestTypeContacts) {
[description appendString:@"ContactRequest"];
} else if (syncMessage.request.type == OWSSignalServiceProtosSyncMessageRequestTypeGroups) {
[description appendString:@"GroupRequest"];
} else if (syncMessage.request.type == OWSSignalServiceProtosSyncMessageRequestTypeBlocked) {
[description appendString:@"BlockedRequest"];
} else {
// Shouldn't happen
OWSFail(@"Unknown sync message request type");
[description appendString:@"UnknownRequest"];
}
} else if (syncMessage.hasBlocked) {
[description appendString:@"Blocked"];
} else if (syncMessage.read.count > 0) {
[description appendString:@"ReadReceipt"];
} else if (syncMessage.hasVerified) {
NSString *verifiedString =
[NSString stringWithFormat:@"Verification for: %@", syncMessage.verified.destination];
[description appendString:verifiedString];
} else {
// Shouldn't happen
OWSFail(@"Unknown sync message type");
[description appendString:@"Unknown"];
}
return description;
}
#pragma mark - Blocking
- (BOOL)isEnvelopeBlocked:(OWSSignalServiceProtosEnvelope *)envelope
@ -278,178 +138,6 @@ const NSUInteger kIncomingMessageBatchSize = 10;
return [_blockingManager isRecipientIdBlocked: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 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);
});
};
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);
if ([self isEnvelopeBlocked:envelope]) {
DDLogInfo(@"%@ ignoring blocked envelope: %@", self.tag, envelope.source);
failureBlock();
return;
}
@try {
switch (envelope.type) {
case OWSSignalServiceProtosEnvelopeTypeCiphertext: {
[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 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;
}
// These message types don't have a payload to decrypt.
case OWSSignalServiceProtosEnvelopeTypeReceipt:
case OWSSignalServiceProtosEnvelopeTypeKeyExchange:
case OWSSignalServiceProtosEnvelopeTypeUnknown:
successBlock(nil);
// Return to avoid double-acknowledging.
return;
default:
DDLogWarn(@"Received unhandled envelope type: %d", (int)envelope.type);
break;
}
} @catch (NSException *exception) {
DDLogError(@"Received an incorrectly formatted protocol buffer: %@", exception.debugDescription);
OWSProdFail([OWSAnalyticsEvents messageManagerErrorInvalidProtocolMessage]);
}
failureBlock();
}
- (void)decryptSecureMessage:(OWSSignalServiceProtosEnvelope *)envelope
successBlock:(DecryptSuccessBlock)successBlock
failureBlock:(void (^)(NSError *_Nullable error))failureBlock
{
OWSAssert(envelope);
OWSAssert(successBlock);
OWSAssert(failureBlock);
[self decryptEnvelope:envelope
messageTypeName:@"Secure Message"
cipherMessageBlock:^(NSData *encryptedData) {
return [[WhisperMessage alloc] initWithData:encryptedData];
}
successBlock:successBlock
failureBlock:failureBlock];
}
- (void)decryptPreKeyBundle:(OWSSignalServiceProtosEnvelope *)envelope
successBlock:(DecryptSuccessBlock)successBlock
failureBlock:(void (^)(NSError *_Nullable error))failureBlock
{
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"
cipherMessageBlock:^(NSData *encryptedData) {
return [[PreKeyWhisperMessage alloc] initWithData:encryptedData];
}
successBlock:successBlock
failureBlock:failureBlock];
}
- (void)decryptEnvelope:(OWSSignalServiceProtosEnvelope *)envelope
messageTypeName:(NSString *)messageTypeName
cipherMessageBlock:(id<CipherMessage> (^_Nonnull)(NSData *))cipherMessageBlock
successBlock:(DecryptSuccessBlock)successBlock
failureBlock:(void (^)(NSError *_Nullable error))failureBlock
{
OWSAssert(envelope);
OWSAssert(messageTypeName.length > 0);
OWSAssert(cipherMessageBlock);
OWSAssert(successBlock);
OWSAssert(failureBlock);
TSStorageManager *storageManager = self.storageManager;
NSString *recipientId = envelope.source;
int deviceId = envelope.sourceDevice;
// DEPRECATED - Remove after all clients have been upgraded.
NSData *encryptedData = envelope.hasContent ? envelope.content : envelope.legacyMessage;
if (!encryptedData) {
OWSProdFail([OWSAnalyticsEvents messageManagerErrorMessageEnvelopeHasNoContent]);
failureBlock(nil);
return;
}
dispatch_async([OWSDispatch sessionStoreQueue], ^{
@try {
id<CipherMessage> cipherMessage = cipherMessageBlock(encryptedData);
SessionCipher *cipher = [[SessionCipher alloc] initWithSessionStore:storageManager
preKeyStore:storageManager
signedPreKeyStore:storageManager
identityKeyStore:self.identityManager
recipientId:recipientId
deviceId:deviceId];
NSData *plaintextData = [[cipher decrypt:cipherMessage] removePadding];
successBlock(plaintextData);
} @catch (NSException *exception) {
dispatch_async(dispatch_get_main_queue(), ^{
[self processException:exception envelope:envelope];
NSString *errorDescription = [NSString
stringWithFormat:@"Exception while decrypting %@: %@", messageTypeName, exception.description];
NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeFailedToDecryptMessage, errorDescription);
failureBlock(error);
});
}
});
}
#pragma mark - message handling
- (void)processEnvelope:(OWSSignalServiceProtosEnvelope *)envelope
@ -1205,69 +893,11 @@ const NSUInteger kIncomingMessageBatchSize = 10;
return incomingMessage;
}
- (void)processException:(NSException *)exception envelope:(OWSSignalServiceProtosEnvelope *)envelope
{
OWSAssert([NSThread isMainThread]);
DDLogError(@"%@ Got exception: %@ of type: %@ with reason: %@",
self.tag,
exception.description,
exception.name,
exception.reason);
__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];
}
[errorMessage saveWithTransaction:transaction];
}];
if (errorMessage != nil) {
[self notifyForErrorMessage:errorMessage withEnvelope:envelope];
}
}
- (void)notifyForErrorMessage:(TSErrorMessage *)errorMessage withEnvelope:(OWSSignalServiceProtosEnvelope *)envelope
{
TSThread *contactThread = [TSContactThread getOrCreateThreadWithContactId:envelope.source];
[[TextSecureKitEnv sharedEnv].notificationsManager notifyUserForErrorMessage:errorMessage inThread:contactThread];
}
#pragma mark - helpers
// used in log formatting
NSString *envelopeAddress(OWSSignalServiceProtosEnvelope *envelope)
{
return [NSString stringWithFormat:@"%@.%d", envelope.source, (unsigned int)envelope.sourceDevice];
}
- (BOOL)isDataMessageGroupAvatarUpdate:(OWSSignalServiceProtosDataMessage *)dataMessage
{
return dataMessage.hasGroup
&& dataMessage.group.type == OWSSignalServiceProtosGroupContextTypeUpdate
return dataMessage.hasGroup && dataMessage.group.type == OWSSignalServiceProtosGroupContextTypeUpdate
&& dataMessage.group.hasAvatar;
}
@ -1290,16 +920,18 @@ NSString *envelopeAddress(OWSSignalServiceProtosEnvelope *envelope)
}
}
- (NSUInteger)unreadMessagesCount {
- (NSUInteger)unreadMessagesCount
{
__block NSUInteger numberOfItems;
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
numberOfItems = [[transaction ext:TSUnreadDatabaseViewExtensionName] numberOfItemsInAllGroups];
numberOfItems = [[transaction ext:TSUnreadDatabaseViewExtensionName] numberOfItemsInAllGroups];
}];
return numberOfItems;
}
- (NSUInteger)unreadMessagesCountExcept:(TSThread *)thread {
- (NSUInteger)unreadMessagesCountExcept:(TSThread *)thread
{
__block NSUInteger numberOfItems;
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
id databaseView = [transaction ext:TSUnreadDatabaseViewExtensionName];
@ -1316,10 +948,11 @@ NSString *envelopeAddress(OWSSignalServiceProtosEnvelope *envelope)
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:numberOfItems];
}
- (NSUInteger)unreadMessagesInThread:(TSThread *)thread {
- (NSUInteger)unreadMessagesInThread:(TSThread *)thread
{
__block NSUInteger numberOfItems;
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
numberOfItems = [[transaction ext:TSUnreadDatabaseViewExtensionName] numberOfItemsInGroup:thread.uniqueId];
numberOfItems = [[transaction ext:TSUnreadDatabaseViewExtensionName] numberOfItemsInGroup:thread.uniqueId];
}];
return numberOfItems;
}

@ -5,9 +5,9 @@
#import "OWSMessageReceiver.h"
#import "NSArray+OWS.h"
#import "OWSBatchMessageProcessor.h"
#import "OWSMessageDecrypter.h"
#import "OWSSignalServiceProtos.pb.h"
#import "TSDatabaseView.h"
#import "TSMessagesManager.h"
#import "TSStorageManager.h"
#import "TSYapDatabaseObject.h"
#import "Threading.h"
@ -208,14 +208,14 @@ NSString *const OWSMessageDecryptJobFinderExtensionGroup = @"OWSMessageProcessin
@interface OWSMessageDecryptQueue : NSObject
@property (nonatomic, readonly) TSMessagesManager *messagesManager;
@property (nonatomic, readonly) OWSMessageDecrypter *messageDecrypter;
@property (nonatomic, readonly) OWSBatchMessageProcessor *batchMessageProcessor;
@property (nonatomic, readonly) OWSMessageDecryptJobFinder *finder;
@property (nonatomic) BOOL isDrainingQueue;
- (instancetype)initWithMessagesManager:(TSMessagesManager *)messagesManager
batchMessageProcessor:(OWSBatchMessageProcessor *)batchMessageProcessor
finder:(OWSMessageDecryptJobFinder *)finder NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithMessageDecrypter:(OWSMessageDecrypter *)messageDecrypter
batchMessageProcessor:(OWSBatchMessageProcessor *)batchMessageProcessor
finder:(OWSMessageDecryptJobFinder *)finder NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@end
@ -224,9 +224,9 @@ NSString *const OWSMessageDecryptJobFinderExtensionGroup = @"OWSMessageProcessin
@implementation OWSMessageDecryptQueue
- (instancetype)initWithMessagesManager:(TSMessagesManager *)messagesManager
batchMessageProcessor:(OWSBatchMessageProcessor *)batchMessageProcessor
finder:(OWSMessageDecryptJobFinder *)finder
- (instancetype)initWithMessageDecrypter:(OWSMessageDecrypter *)messageDecrypter
batchMessageProcessor:(OWSBatchMessageProcessor *)batchMessageProcessor
finder:(OWSMessageDecryptJobFinder *)finder
{
OWSSingletonAssert();
@ -235,7 +235,7 @@ NSString *const OWSMessageDecryptJobFinderExtensionGroup = @"OWSMessageProcessin
return self;
}
_messagesManager = messagesManager;
_messageDecrypter = messageDecrypter;
_batchMessageProcessor = batchMessageProcessor;
_finder = finder;
_isDrainingQueue = NO;
@ -337,7 +337,7 @@ NSString *const OWSMessageDecryptJobFinderExtensionGroup = @"OWSMessageProcessin
OWSAssert(unprocessedJobs.count > 0);
OWSMessageDecryptJob *job = unprocessedJobs.firstObject;
[unprocessedJobs removeObjectAtIndex:0];
[self.messagesManager decryptEnvelope:job.envelopeProto
[self.messageDecrypter decryptEnvelope:job.envelopeProto
successBlock:^(NSData *_Nullable plaintextData) {
if (plaintextData) {
plaintextDataMap[job.uniqueId] = plaintextData;
@ -384,7 +384,7 @@ NSString *const OWSMessageDecryptJobFinderExtensionGroup = @"OWSMessageProcessin
@implementation OWSMessageReceiver
- (instancetype)initWithDBConnection:(YapDatabaseConnection *)dbConnection
messagesManager:(TSMessagesManager *)messagesManager
messageDecrypter:(OWSMessageDecrypter *)messageDecrypter
batchMessageProcessor:(OWSBatchMessageProcessor *)batchMessageProcessor
{
OWSSingletonAssert();
@ -396,9 +396,9 @@ NSString *const OWSMessageDecryptJobFinderExtensionGroup = @"OWSMessageProcessin
OWSMessageDecryptJobFinder *finder = [[OWSMessageDecryptJobFinder alloc] initWithDBConnection:dbConnection];
OWSMessageDecryptQueue *processingQueue =
[[OWSMessageDecryptQueue alloc] initWithMessagesManager:messagesManager
batchMessageProcessor:batchMessageProcessor
finder:finder];
[[OWSMessageDecryptQueue alloc] initWithMessageDecrypter:messageDecrypter
batchMessageProcessor:batchMessageProcessor
finder:finder];
_processingQueue = processingQueue;
@ -409,11 +409,11 @@ NSString *const OWSMessageDecryptJobFinderExtensionGroup = @"OWSMessageProcessin
{
// For concurrency coherency we use the same dbConnection to persist and read the unprocessed envelopes
YapDatabaseConnection *dbConnection = [[TSStorageManager sharedManager].database newConnection];
TSMessagesManager *messagesManager = [TSMessagesManager sharedManager];
OWSMessageDecrypter *messageDecrypter = [OWSMessageDecrypter sharedManager];
OWSBatchMessageProcessor *batchMessageProcessor = [OWSBatchMessageProcessor sharedInstance];
return [self initWithDBConnection:dbConnection
messagesManager:messagesManager
messageDecrypter:messageDecrypter
batchMessageProcessor:batchMessageProcessor];
}

@ -1,55 +0,0 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "TSIncomingMessage.h"
#import "TSInvalidIdentityKeySendingErrorMessage.h"
#import "TSOutgoingMessage.h"
NS_ASSUME_NONNULL_BEGIN
extern const NSUInteger kIncomingMessageBatchSize;
@class TSNetworkManager;
@class TSStorageManager;
@class OWSSignalServiceProtosEnvelope;
@class OWSSignalServiceProtosDataMessage;
@class ContactsUpdater;
@class OWSMessageSender;
@protocol ContactsManagerProtocol;
@protocol OWSCallMessageHandler;
typedef void (^DecryptSuccessBlock)(NSData *_Nullable plaintextData);
typedef void (^DecryptFailureBlock)();
typedef void (^MessageManagerCompletionBlock)();
@interface TSMessagesManager : NSObject
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)sharedManager;
@property (nonatomic, readonly) YapDatabaseConnection *dbConnection;
@property (nonatomic, readonly) TSNetworkManager *networkManager;
@property (nonatomic, readonly) ContactsUpdater *contactsUpdater;
// 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;
- (NSUInteger)unreadMessagesCount;
- (NSUInteger)unreadMessagesCountExcept:(TSThread *)thread;
- (NSUInteger)unreadMessagesInThread:(TSThread *)thread;
@end
NS_ASSUME_NONNULL_END

@ -5,13 +5,14 @@
#import "TSSocketManager.h"
#import "Cryptography.h"
#import "NSTimer+OWS.h"
#import "OWSMessageManager.h"
#import "OWSMessageReceiver.h"
#import "OWSSignalService.h"
#import "OWSSignalServiceProtos.pb.h"
#import "OWSWebsocketSecurityPolicy.h"
#import "SubProtocol.pb.h"
#import "TSAccountManager.h"
#import "TSConstants.h"
#import "TSMessagesManager.h"
#import "TSStorageManager+keyingMaterial.h"
#import "Threading.h"

@ -134,8 +134,8 @@ typedef NSDictionary<NSString *, id> *_Nonnull (^OWSProdAssertParametersBlock)()
#define OWSProdCritical(__eventName) OWSProdEventWParams(OWSAnalyticsSeverityCritical, __eventName, nil)
#pragma mark - TSMessagesManager macros
// Defined here rather than in TSMessagesManager so that our analytic event extraction script
#pragma mark - OWSMessageManager macros
// Defined here rather than in OWSMessageManager so that our analytic event extraction script
// can properly detect the event names.
//
// The debug logs can be more verbose than the analytics events.

Loading…
Cancel
Save