Add protocol context to protocol kit.

pull/1/head
Matthew Chen 7 years ago
parent 7358f3053f
commit 074046b98e

@ -41,7 +41,7 @@ NS_ASSUME_NONNULL_BEGIN
OWSIdentityManager *identityManager = [OWSIdentityManager sharedManager]; OWSIdentityManager *identityManager = [OWSIdentityManager sharedManager];
NSString *recipientId = [thread contactIdentifier]; NSString *recipientId = [thread contactIdentifier];
NSData *currentKey = [identityManager identityKeyForRecipientId:recipientId]; NSData *currentKey = [identityManager identityKeyForRecipientIdWOT:recipientId];
NSMutableData *flippedKey = [NSMutableData new]; NSMutableData *flippedKey = [NSMutableData new];
const char *currentKeyBytes = currentKey.bytes; const char *currentKeyBytes = currentKey.bytes;
for (NSUInteger i = 0; i < currentKey.length; i++) { for (NSUInteger i = 0; i < currentKey.length; i++) {

@ -1,5 +1,5 @@
// //
// Copyright (c) 2017 Open Whisper Systems. All rights reserved. // Copyright (c) 2018 Open Whisper Systems. All rights reserved.
// //
#import "ShowGroupMembersViewController.h" #import "ShowGroupMembersViewController.h"
@ -246,7 +246,7 @@ NS_ASSUME_NONNULL_BEGIN
for (NSString *recipientId in recipientIds) { for (NSString *recipientId in recipientIds) {
OWSVerificationState verificationState = [identityManger verificationStateForRecipientId:recipientId]; OWSVerificationState verificationState = [identityManger verificationStateForRecipientId:recipientId];
if (verificationState == OWSVerificationStateNoLongerVerified) { if (verificationState == OWSVerificationStateNoLongerVerified) {
NSData *identityKey = [identityManger identityKeyForRecipientId:recipientId]; NSData *identityKey = [identityManger identityKeyForRecipientIdWOT:recipientId];
if (identityKey.length < 1) { if (identityKey.length < 1) {
OWSFail(@"Missing identity key for: %@", recipientId); OWSFail(@"Missing identity key for: %@", recipientId);
continue; continue;

@ -404,7 +404,7 @@ typedef void (^SendMessageBlock)(SendCompletionBlock completion);
} }
case OWSVerificationStateNoLongerVerified: { case OWSVerificationStateNoLongerVerified: {
DDLogInfo(@"%@ marked recipient: %@ as default verification status.", self.logTag, recipientId); DDLogInfo(@"%@ marked recipient: %@ as default verification status.", self.logTag, recipientId);
NSData *identityKey = [[OWSIdentityManager sharedManager] identityKeyForRecipientId:recipientId]; NSData *identityKey = [[OWSIdentityManager sharedManager] identityKeyForRecipientIdWOT:recipientId];
OWSAssert(identityKey); OWSAssert(identityKey);
[[OWSIdentityManager sharedManager] setVerificationState:OWSVerificationStateDefault [[OWSIdentityManager sharedManager] setVerificationState:OWSVerificationStateDefault
identityKey:identityKey identityKey:identityKey

@ -106,9 +106,7 @@ NSString *const TSAccountManager_ServerSignalingKey = @"TSStorageServerSignaling
[transaction removeAllObjectsInCollection:TSAccountManager_UserAccountCollection]; [transaction removeAllObjectsInCollection:TSAccountManager_UserAccountCollection];
}]; }];
} }
dispatch_async([OWSDispatch sessionStoreQueue], ^{ [[TSStorageManager sharedManager] resetSessionStore];
[[TSStorageManager sharedManager] resetSessionStore];
});
} }
+ (BOOL)isRegistered + (BOOL)isRegistered
@ -201,9 +199,11 @@ NSString *const TSAccountManager_ServerSignalingKey = @"TSStorageServerSignaling
- (uint32_t)getOrGenerateRegistrationId - (uint32_t)getOrGenerateRegistrationId
{ {
__block uint32_t result;
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
[self getOrGenerateRegistrationId:transaction]; result = [self getOrGenerateRegistrationId:transaction];
}]; }];
return result;
} }
- (uint32_t)getOrGenerateRegistrationId:(YapDatabaseReadWriteTransaction *)transaction - (uint32_t)getOrGenerateRegistrationId:(YapDatabaseReadWriteTransaction *)transaction

@ -134,11 +134,11 @@ static const NSTimeInterval kSignedPreKeyUpdateFailureMaxFailureDuration = 10 *
RefreshPreKeysMode modeCopy = mode; RefreshPreKeysMode modeCopy = mode;
TSStorageManager *storageManager = [TSStorageManager sharedManager]; TSStorageManager *storageManager = [TSStorageManager sharedManager];
ECKeyPair *identityKeyPair = [[OWSIdentityManager sharedManager] identityKeyPair]; ECKeyPair *identityKeyPair = [[OWSIdentityManager sharedManager] identityKeyPairWithoutProtocolContext];
if (!identityKeyPair) { if (!identityKeyPair) {
[[OWSIdentityManager sharedManager] generateNewIdentityKey]; [[OWSIdentityManager sharedManager] generateNewIdentityKey];
identityKeyPair = [[OWSIdentityManager sharedManager] identityKeyPair]; identityKeyPair = [[OWSIdentityManager sharedManager] identityKeyPairWithoutProtocolContext];
// Switch modes if necessary. // Switch modes if necessary.
modeCopy = RefreshPreKeysMode_SignedAndOneTime; modeCopy = RefreshPreKeysMode_SignedAndOneTime;

@ -111,7 +111,7 @@ NS_ASSUME_NONNULL_BEGIN
- (BOOL)hasSafetyNumbers - (BOOL)hasSafetyNumbers
{ {
return !![[OWSIdentityManager sharedManager] identityKeyForRecipientId:self.contactIdentifier]; return !![[OWSIdentityManager sharedManager] identityKeyForRecipientIdWOT:self.contactIdentifier];
} }
- (NSString *)name - (NSString *)name

@ -68,9 +68,7 @@ NS_ASSUME_NONNULL_BEGIN
TSThread *thread = [transcript threadWithTransaction:transaction]; TSThread *thread = [transcript threadWithTransaction:transaction];
if (transcript.isEndSessionMessage) { if (transcript.isEndSessionMessage) {
DDLogInfo(@"%@ EndSession was sent to recipient: %@.", self.logTag, transcript.recipientId); DDLogInfo(@"%@ EndSession was sent to recipient: %@.", self.logTag, transcript.recipientId);
dispatch_async([OWSDispatch sessionStoreQueue], ^{ [self.storageManager deleteAllSessionsForContact:transcript.recipientId protocolContext:transaction];
[self.storageManager deleteAllSessionsForContact:transcript.recipientId protocolContext:protocolContext];
});
[[[TSInfoMessage alloc] initWithTimestamp:transcript.timestamp [[[TSInfoMessage alloc] initWithTimestamp:transcript.timestamp
inThread:thread inThread:thread
messageType:TSInfoMessageTypeSessionDidEnd] saveWithTransaction:transaction]; messageType:TSInfoMessageTypeSessionDidEnd] saveWithTransaction:transaction];

@ -10,6 +10,7 @@
#import "TSContactThread.h" #import "TSContactThread.h"
#import "TSDatabaseView.h" #import "TSDatabaseView.h"
#import "TSErrorMessage_privateConstructor.h" #import "TSErrorMessage_privateConstructor.h"
#import "TSStorageManager+SessionStore.h"
#import "TSStorageManager.h" #import "TSStorageManager.h"
#import <AxolotlKit/NSData+keyVersionByte.h> #import <AxolotlKit/NSData+keyVersionByte.h>
#import <AxolotlKit/PreKeyWhisperMessage.h> #import <AxolotlKit/PreKeyWhisperMessage.h>
@ -80,10 +81,11 @@ NS_ASSUME_NONNULL_BEGIN
} }
// Saving a new identity mutates the session store so it must happen on the sessionStoreQueue // Saving a new identity mutates the session store so it must happen on the sessionStoreQueue
dispatch_async([OWSDispatch sessionStoreQueue], ^{ [TSStorageManager.protocolStoreDBConnection asyncReadWriteWithBlock:^(
YapDatabaseReadWriteTransaction *transaction) {
[[OWSIdentityManager sharedManager] saveRemoteIdentity:newKey [[OWSIdentityManager sharedManager] saveRemoteIdentity:newKey
recipientId:self.envelope.source recipientId:self.envelope.source
protocolContext:protocolContext]; protocolContext:transaction];
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
// Decrypt this and any old messages for the newly accepted key // Decrypt this and any old messages for the newly accepted key
@ -99,7 +101,7 @@ NS_ASSUME_NONNULL_BEGIN
[errorMessage remove]; [errorMessage remove];
} }
}); });
}); }];
} }
- (nullable NSData *)newIdentityKey - (nullable NSData *)newIdentityKey

@ -10,6 +10,7 @@
#import "TSContactThread.h" #import "TSContactThread.h"
#import "TSErrorMessage_privateConstructor.h" #import "TSErrorMessage_privateConstructor.h"
#import "TSOutgoingMessage.h" #import "TSOutgoingMessage.h"
#import "TSStorageManager+SessionStore.h"
#import <AxolotlKit/NSData+keyVersionByte.h> #import <AxolotlKit/NSData+keyVersionByte.h>
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
@ -57,11 +58,12 @@ NSString *TSInvalidRecipientKey = @"TSInvalidRecipientKey";
return; return;
} }
dispatch_async([OWSDispatch sessionStoreQueue], ^{ [TSStorageManager.protocolStoreDBConnection
[[OWSIdentityManager sharedManager] saveRemoteIdentity:newIdentityKey asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
recipientId:self.recipientId [[OWSIdentityManager sharedManager] saveRemoteIdentity:newIdentityKey
protocolContext:protocolContext]; recipientId:self.recipientId
}); protocolContext:transaction];
}];
} }
- (nullable NSData *)newIdentityKey - (nullable NSData *)newIdentityKey

@ -6,6 +6,7 @@ NS_ASSUME_NONNULL_BEGIN
@class OWSSignalServiceProtosEnvelope; @class OWSSignalServiceProtosEnvelope;
@class OWSStorage; @class OWSStorage;
@class YapDatabaseReadWriteTransaction;
// This class is used to write incoming (decrypted, unprocessed) // This class is used to write incoming (decrypted, unprocessed)
// messages to a durable queue and then process them in batches, // messages to a durable queue and then process them in batches,
@ -15,7 +16,10 @@ NS_ASSUME_NONNULL_BEGIN
+ (instancetype)sharedInstance; + (instancetype)sharedInstance;
+ (void)asyncRegisterDatabaseExtension:(OWSStorage *)storage; + (void)asyncRegisterDatabaseExtension:(OWSStorage *)storage;
- (void)enqueueEnvelopeData:(NSData *)envelopeData plaintextData:(NSData *_Nullable)plaintextData; - (void)enqueueEnvelopeData:(NSData *)envelopeData
plaintextData:(NSData *_Nullable)plaintextData
transaction:(YapDatabaseReadWriteTransaction *)transaction;
- (void)handleAnyUnprocessedEnvelopesAsync; - (void)handleAnyUnprocessedEnvelopesAsync;
@end @end

@ -136,14 +136,16 @@ NSString *const OWSMessageContentJobFinderExtensionGroup = @"OWSMessageContentJo
return [jobs copy]; return [jobs copy];
} }
- (void)addJobWithEnvelopeData:(NSData *)envelopeData plaintextData:(NSData *_Nullable)plaintextData - (void)addJobWithEnvelopeData:(NSData *)envelopeData
plaintextData:(NSData *_Nullable)plaintextData
transaction:(YapDatabaseReadWriteTransaction *)transaction
{ {
// We need to persist the decrypted envelope data ASAP to prevent data loss. OWSAssert(envelopeData);
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { OWSAssert(transaction);
OWSMessageContentJob *job =
[[OWSMessageContentJob alloc] initWithEnvelopeData:envelopeData plaintextData:plaintextData]; OWSMessageContentJob *job =
[job saveWithTransaction:transaction]; [[OWSMessageContentJob alloc] initWithEnvelopeData:envelopeData plaintextData:plaintextData];
}]; [job saveWithTransaction:transaction];
} }
- (void)removeJobsWithIds:(NSArray<NSString *> *)uniqueIds - (void)removeJobsWithIds:(NSArray<NSString *> *)uniqueIds
@ -293,12 +295,15 @@ NSString *const OWSMessageContentJobFinderExtensionGroup = @"OWSMessageContentJo
return queue; return queue;
} }
- (void)enqueueEnvelopeData:(NSData *)envelopeData plaintextData:(NSData *_Nullable)plaintextData - (void)enqueueEnvelopeData:(NSData *)envelopeData
plaintextData:(NSData *_Nullable)plaintextData
transaction:(YapDatabaseReadWriteTransaction *)transaction
{ {
OWSAssert(envelopeData); OWSAssert(envelopeData);
OWSAssert(transaction);
// We need to persist the decrypted envelope data ASAP to prevent data loss. // We need to persist the decrypted envelope data ASAP to prevent data loss.
[self.finder addJobWithEnvelopeData:envelopeData plaintextData:plaintextData]; [self.finder addJobWithEnvelopeData:envelopeData plaintextData:plaintextData transaction:transaction];
} }
- (void)drainQueue - (void)drainQueue
@ -459,12 +464,15 @@ NSString *const OWSMessageContentJobFinderExtensionGroup = @"OWSMessageContentJo
[self.processingQueue drainQueue]; [self.processingQueue drainQueue];
} }
- (void)enqueueEnvelopeData:(NSData *)envelopeData plaintextData:(NSData *_Nullable)plaintextData - (void)enqueueEnvelopeData:(NSData *)envelopeData
plaintextData:(NSData *_Nullable)plaintextData
transaction:(YapDatabaseReadWriteTransaction *)transaction
{ {
OWSAssert(envelopeData); OWSAssert(envelopeData);
OWSAssert(transaction);
// We need to persist the decrypted envelope data ASAP to prevent data loss. // We need to persist the decrypted envelope data ASAP to prevent data loss.
[self.processingQueue enqueueEnvelopeData:envelopeData plaintextData:plaintextData]; [self.processingQueue enqueueEnvelopeData:envelopeData plaintextData:plaintextData transaction:transaction];
[self.processingQueue drainQueue]; [self.processingQueue drainQueue];
} }

@ -30,6 +30,9 @@ extern const NSUInteger kIdentityKeyLength;
- (void)generateNewIdentityKey; - (void)generateNewIdentityKey;
// TODO: Rename to identityKeyForRecipientId.
- (nullable NSData *)identityKeyForRecipientIdWOT:(NSString *)recipientId;
- (nullable NSData *)identityKeyForRecipientId:(NSString *)recipientId protocolContext:(nullable id)protocolContext; - (nullable NSData *)identityKeyForRecipientId:(NSString *)recipientId protocolContext:(nullable id)protocolContext;
- (void)setVerificationState:(OWSVerificationState)verificationState - (void)setVerificationState:(OWSVerificationState)verificationState
@ -55,6 +58,7 @@ extern const NSUInteger kIdentityKeyLength;
#pragma mark - Debug #pragma mark - Debug
// TODO:
- (nullable ECKeyPair *)identityKeyPairWithoutProtocolContext; - (nullable ECKeyPair *)identityKeyPairWithoutProtocolContext;
#if DEBUG #if DEBUG

@ -132,6 +132,15 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
inCollection:TSStorageManagerIdentityKeyStoreCollection]; inCollection:TSStorageManagerIdentityKeyStoreCollection];
} }
- (nullable NSData *)identityKeyForRecipientIdWOT:(NSString *)recipientId
{
__block NSData *_Nullable result = nil;
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
result = [self identityKeyForRecipientId:recipientId protocolContext:transaction];
}];
return result;
}
- (nullable NSData *)identityKeyForRecipientId:(NSString *)recipientId protocolContext:(nullable id)protocolContext - (nullable NSData *)identityKeyForRecipientId:(NSString *)recipientId protocolContext:(nullable id)protocolContext
{ {
OWSAssert(recipientId.length > 0); OWSAssert(recipientId.length > 0);

@ -1,5 +1,5 @@
// //
// Copyright (c) 2017 Open Whisper Systems. All rights reserved. // Copyright (c) 2018 Open Whisper Systems. All rights reserved.
// //
#import "OWSMessageHandler.h" #import "OWSMessageHandler.h"
@ -7,8 +7,9 @@
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
@class OWSSignalServiceProtosEnvelope; @class OWSSignalServiceProtosEnvelope;
@class YapDatabaseReadWriteTransaction;
typedef void (^DecryptSuccessBlock)(NSData *_Nullable plaintextData); typedef void (^DecryptSuccessBlock)(NSData *_Nullable plaintextData, YapDatabaseReadWriteTransaction *transaction);
typedef void (^DecryptFailureBlock)(void); typedef void (^DecryptFailureBlock)(void);
@interface OWSMessageDecrypter : OWSMessageHandler @interface OWSMessageDecrypter : OWSMessageHandler

@ -1,5 +1,5 @@
// //
// Copyright (c) 2017 Open Whisper Systems. All rights reserved. // Copyright (c) 2018 Open Whisper Systems. All rights reserved.
// //
#import "OWSMessageDecrypter.h" #import "OWSMessageDecrypter.h"
@ -89,20 +89,18 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark - Decryption #pragma mark - Decryption
- (void)decryptEnvelope:(OWSSignalServiceProtosEnvelope *)envelope - (void)decryptEnvelope:(OWSSignalServiceProtosEnvelope *)envelope
successBlock:(DecryptSuccessBlock)successBlockParameter successBlock:(DecryptSuccessBlock)successBlock
failureBlock:(DecryptFailureBlock)failureBlockParameter failureBlock:(DecryptFailureBlock)failureBlockParameter
{ {
OWSAssert(envelope); OWSAssert(envelope);
OWSAssert(successBlockParameter); OWSAssert(successBlock);
OWSAssert(failureBlockParameter); OWSAssert(failureBlockParameter);
OWSAssert([TSAccountManager isRegistered]); OWSAssert([TSAccountManager isRegistered]);
// Ensure that successBlock and failureBlock are called on a worker queue. // successBlock is called synchronously so that we can avail ourselves of
DecryptSuccessBlock successBlock = ^(NSData *_Nullable plaintextData) { // the transaction.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ //
successBlockParameter(plaintextData); // Ensure that failureBlock is called on a worker queue.
});
};
DecryptFailureBlock failureBlock = ^() { DecryptFailureBlock failureBlock = ^() {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
failureBlockParameter(); failureBlockParameter();
@ -121,9 +119,9 @@ NS_ASSUME_NONNULL_BEGIN
switch (envelope.type) { switch (envelope.type) {
case OWSSignalServiceProtosEnvelopeTypeCiphertext: { case OWSSignalServiceProtosEnvelopeTypeCiphertext: {
[self decryptSecureMessage:envelope [self decryptSecureMessage:envelope
successBlock:^(NSData *_Nullable plaintextData) { successBlock:^(NSData *_Nullable plaintextData, YapDatabaseReadWriteTransaction *transaction) {
DDLogDebug(@"%@ decrypted secure message.", self.logTag); DDLogDebug(@"%@ decrypted secure message.", self.logTag);
successBlock(plaintextData); successBlock(plaintextData, transaction);
} }
failureBlock:^(NSError *_Nullable error) { failureBlock:^(NSError *_Nullable error) {
DDLogError(@"%@ decrypting secure message from address: %@ failed with error: %@", DDLogError(@"%@ decrypting secure message from address: %@ failed with error: %@",
@ -138,9 +136,9 @@ NS_ASSUME_NONNULL_BEGIN
} }
case OWSSignalServiceProtosEnvelopeTypePrekeyBundle: { case OWSSignalServiceProtosEnvelopeTypePrekeyBundle: {
[self decryptPreKeyBundle:envelope [self decryptPreKeyBundle:envelope
successBlock:^(NSData *_Nullable plaintextData) { successBlock:^(NSData *_Nullable plaintextData, YapDatabaseReadWriteTransaction *transaction) {
DDLogDebug(@"%@ decrypted pre-key whisper message", self.logTag); DDLogDebug(@"%@ decrypted pre-key whisper message", self.logTag);
successBlock(plaintextData); successBlock(plaintextData, transaction);
} }
failureBlock:^(NSError *_Nullable error) { failureBlock:^(NSError *_Nullable error) {
DDLogError(@"%@ decrypting pre-key whisper message from address: %@ failed " DDLogError(@"%@ decrypting pre-key whisper message from address: %@ failed "
@ -157,10 +155,14 @@ NS_ASSUME_NONNULL_BEGIN
// These message types don't have a payload to decrypt. // These message types don't have a payload to decrypt.
case OWSSignalServiceProtosEnvelopeTypeReceipt: case OWSSignalServiceProtosEnvelopeTypeReceipt:
case OWSSignalServiceProtosEnvelopeTypeKeyExchange: case OWSSignalServiceProtosEnvelopeTypeKeyExchange:
case OWSSignalServiceProtosEnvelopeTypeUnknown: case OWSSignalServiceProtosEnvelopeTypeUnknown: {
successBlock(nil); [TSStorageManager.protocolStoreDBConnection
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
successBlock(nil, transaction);
}];
// Return to avoid double-acknowledging. // Return to avoid double-acknowledging.
return; return;
}
default: default:
DDLogWarn(@"Received unhandled envelope type: %d", (int)envelope.type); DDLogWarn(@"Received unhandled envelope type: %d", (int)envelope.type);
break; break;
@ -234,27 +236,30 @@ NS_ASSUME_NONNULL_BEGIN
return; return;
} }
dispatch_async([OWSDispatch sessionStoreQueue], ^{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@try { [TSStorageManager.protocolStoreDBConnection readWriteWithBlock:^(
id<CipherMessage> cipherMessage = cipherMessageBlock(encryptedData); YapDatabaseReadWriteTransaction *_Nonnull transaction) {
SessionCipher *cipher = [[SessionCipher alloc] initWithSessionStore:storageManager @try {
preKeyStore:storageManager id<CipherMessage> cipherMessage = cipherMessageBlock(encryptedData);
signedPreKeyStore:storageManager SessionCipher *cipher = [[SessionCipher alloc] initWithSessionStore:storageManager
identityKeyStore:self.identityManager preKeyStore:storageManager
recipientId:recipientId signedPreKeyStore:storageManager
deviceId:deviceId]; identityKeyStore:self.identityManager
recipientId:recipientId
NSData *plaintextData = [[cipher decrypt:cipherMessage] removePadding]; deviceId:deviceId];
successBlock(plaintextData);
} @catch (NSException *exception) { NSData *plaintextData = [[cipher decrypt:cipherMessage protocolContext:transaction] removePadding];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ successBlock(plaintextData, transaction);
[self processException:exception envelope:envelope]; } @catch (NSException *exception) {
NSString *errorDescription = [NSString dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
stringWithFormat:@"Exception while decrypting %@: %@", cipherTypeName, exception.description]; [self processException:exception envelope:envelope];
NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeFailedToDecryptMessage, errorDescription); NSString *errorDescription = [NSString
failureBlock(error); stringWithFormat:@"Exception while decrypting %@: %@", cipherTypeName, exception.description];
}); NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeFailedToDecryptMessage, errorDescription);
} failureBlock(error);
});
}
}];
}); });
} }

@ -1,5 +1,5 @@
// //
// Copyright (c) 2017 Open Whisper Systems. All rights reserved. // Copyright (c) 2018 Open Whisper Systems. All rights reserved.
// //
#import "OWSMessageHandler.h" #import "OWSMessageHandler.h"
@ -20,10 +20,6 @@ NS_ASSUME_NONNULL_BEGIN
plaintextData:(NSData *_Nullable)plaintextData plaintextData:(NSData *_Nullable)plaintextData
transaction:(YapDatabaseReadWriteTransaction *)transaction; transaction:(YapDatabaseReadWriteTransaction *)transaction;
- (NSUInteger)unreadMessagesCount;
- (NSUInteger)unreadMessagesCountExcept:(TSThread *)thread;
- (NSUInteger)unreadMessagesInThread:(TSThread *)thread;
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END

@ -21,6 +21,7 @@
#import "OWSIncomingMessageFinder.h" #import "OWSIncomingMessageFinder.h"
#import "OWSIncomingSentMessageTranscript.h" #import "OWSIncomingSentMessageTranscript.h"
#import "OWSMessageSender.h" #import "OWSMessageSender.h"
#import "OWSMessageUtils.h"
#import "OWSReadReceiptManager.h" #import "OWSReadReceiptManager.h"
#import "OWSRecordTranscriptJob.h" #import "OWSRecordTranscriptJob.h"
#import "OWSSyncConfigurationMessage.h" #import "OWSSyncConfigurationMessage.h"
@ -137,7 +138,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)yapDatabaseModified:(NSNotification *)notification - (void)yapDatabaseModified:(NSNotification *)notification
{ {
if (AppReadiness.isAppReady) { if (AppReadiness.isAppReady) {
[self updateApplicationBadgeCount]; [OWSMessageUtils.sharedManager updateApplicationBadgeCount];
} }
} }
@ -1118,47 +1119,6 @@ NS_ASSUME_NONNULL_BEGIN
} }
} }
- (NSUInteger)unreadMessagesCount
{
__block NSUInteger numberOfItems;
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
numberOfItems = [[transaction ext:TSUnreadDatabaseViewExtensionName] numberOfItemsInAllGroups];
}];
return numberOfItems;
}
- (NSUInteger)unreadMessagesCountExcept:(TSThread *)thread
{
__block NSUInteger numberOfItems;
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
id databaseView = [transaction ext:TSUnreadDatabaseViewExtensionName];
OWSAssert(databaseView);
numberOfItems = ([databaseView numberOfItemsInAllGroups] - [databaseView numberOfItemsInGroup:thread.uniqueId]);
}];
return numberOfItems;
}
- (void)updateApplicationBadgeCount
{
if (!CurrentAppContext().isMainApp) {
return;
}
NSUInteger numberOfItems = [self unreadMessagesCount];
[CurrentAppContext() setMainAppBadgeNumber:numberOfItems];
}
- (NSUInteger)unreadMessagesInThread:(TSThread *)thread
{
__block NSUInteger numberOfItems;
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
numberOfItems = [[transaction ext:TSUnreadDatabaseViewExtensionName] numberOfItemsInGroup:thread.uniqueId];
}];
return numberOfItems;
}
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END

@ -331,11 +331,15 @@ NSString *const OWSMessageDecryptJobFinderExtensionGroup = @"OWSMessageProcessin
OWSSignalServiceProtosEnvelope *envelope = job.envelopeProto; OWSSignalServiceProtosEnvelope *envelope = job.envelopeProto;
[self.messageDecrypter decryptEnvelope:envelope [self.messageDecrypter decryptEnvelope:envelope
successBlock:^(NSData *_Nullable plaintextData) { successBlock:^(NSData *_Nullable plaintextData, YapDatabaseReadWriteTransaction *transaction) {
OWSAssert(transaction);
// We can't decrypt the same message twice, so we need to persist
// the decrypted envelope data ASAP to prevent data loss. // We persist the decrypted envelope data in the same transaction within which
[self.batchMessageProcessor enqueueEnvelopeData:job.envelopeData plaintextData:plaintextData]; // it was decrypted to prevent data loss. If the new job isn't persisted,
// the session state side effects of its decryption are also rolled back.
[self.batchMessageProcessor enqueueEnvelopeData:job.envelopeData
plaintextData:plaintextData
transaction:transaction];
dispatch_async(self.serialQueue, ^{ dispatch_async(self.serialQueue, ^{
completion(YES); completion(YES);

@ -904,9 +904,12 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
NSData *newIdentityKey = [newIdentityKeyWithVersion removeKeyType]; NSData *newIdentityKey = [newIdentityKeyWithVersion removeKeyType];
[[OWSIdentityManager sharedManager] saveRemoteIdentity:newIdentityKey [TSStorageManager.protocolStoreDBConnection
recipientId:recipient.recipientId readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
protocolContext:protocolContext]; [[OWSIdentityManager sharedManager] saveRemoteIdentity:newIdentityKey
recipientId:recipient.recipientId
protocolContext:transaction];
}];
failureHandler(error); failureHandler(error);
return; return;
@ -1101,30 +1104,34 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
} }
} }
dispatch_async([OWSDispatch sessionStoreQueue], ^{ [TSStorageManager.protocolStoreDBConnection
if (extraDevices.count < 1 && missingDevices.count < 1) { readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
OWSProdFail([OWSAnalyticsEvents messageSenderErrorNoMissingOrExtraDevices]); if (extraDevices.count < 1 && missingDevices.count < 1) {
} OWSProdFail([OWSAnalyticsEvents messageSenderErrorNoMissingOrExtraDevices]);
}
if (extraDevices && extraDevices.count > 0) { if (extraDevices && extraDevices.count > 0) {
DDLogInfo(@"%@ removing extra devices: %@", self.logTag, extraDevices); DDLogInfo(@"%@ removing extra devices: %@", self.logTag, extraDevices);
for (NSNumber *extraDeviceId in extraDevices) { for (NSNumber *extraDeviceId in extraDevices) {
[self.storageManager deleteSessionForContact:recipient.uniqueId [self.storageManager deleteSessionForContact:recipient.uniqueId
deviceId:extraDeviceId.intValue deviceId:extraDeviceId.intValue
protocolContext:protocolContext]; protocolContext:transaction];
}
[recipient removeDevices:[NSSet setWithArray:extraDevices]];
} }
[recipient removeDevices:[NSSet setWithArray:extraDevices]]; if (missingDevices && missingDevices.count > 0) {
} DDLogInfo(@"%@ Adding missing devices: %@", self.logTag, missingDevices);
[recipient addDevices:[NSSet setWithArray:missingDevices]];
}
if (missingDevices && missingDevices.count > 0) { [recipient saveWithTransaction:transaction];
DDLogInfo(@"%@ Adding missing devices: %@", self.logTag, missingDevices);
[recipient addDevices:[NSSet setWithArray:missingDevices]];
}
[recipient save]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
completionHandler(); completionHandler();
}); });
}];
} }
- (void)handleMessageSentLocally:(TSOutgoingMessage *)message - (void)handleMessageSentLocally:(TSOutgoingMessage *)message
@ -1249,19 +1256,19 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
@try { @try {
__block NSDictionary *messageDict; __block NSDictionary *messageDict;
__block NSException *encryptionException; __block NSException *encryptionException;
// Mutating session state is not thread safe, so we operate on a serial queue, shared with decryption [TSStorageManager.protocolStoreDBConnection
// operations. readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
dispatch_sync([OWSDispatch sessionStoreQueue], ^{ @try {
@try { messageDict = [self encryptedMessageWithPlaintext:plainText
messageDict = [self encryptedMessageWithPlaintext:plainText toRecipient:recipient.uniqueId
toRecipient:recipient.uniqueId deviceId:deviceNumber
deviceId:deviceNumber keyingStorage:self.storageManager
keyingStorage:self.storageManager isSilent:message.isSilent
isSilent:message.isSilent]; transaction:transaction];
} @catch (NSException *exception) { } @catch (NSException *exception) {
encryptionException = exception; encryptionException = exception;
} }
}); }];
if (encryptionException) { if (encryptionException) {
DDLogInfo(@"%@ Exception during encryption: %@", self.logTag, encryptionException); DDLogInfo(@"%@ Exception during encryption: %@", self.logTag, encryptionException);
@ -1290,13 +1297,15 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
deviceId:(NSNumber *)deviceNumber deviceId:(NSNumber *)deviceNumber
keyingStorage:(TSStorageManager *)storage keyingStorage:(TSStorageManager *)storage
isSilent:(BOOL)isSilent isSilent:(BOOL)isSilent
transaction:(YapDatabaseReadWriteTransaction *)transaction
{ {
OWSAssert(plainText); OWSAssert(plainText);
OWSAssert(identifier.length > 0); OWSAssert(identifier.length > 0);
OWSAssert(deviceNumber); OWSAssert(deviceNumber);
OWSAssert(storage); OWSAssert(storage);
OWSAssert(transaction);
if (![storage containsSession:identifier deviceId:[deviceNumber intValue] protocolContext:protocolContext]) { if (![storage containsSession:identifier deviceId:[deviceNumber intValue] protocolContext:transaction]) {
__block dispatch_semaphore_t sema = dispatch_semaphore_create(0); __block dispatch_semaphore_t sema = dispatch_semaphore_create(0);
__block PreKeyBundle *_Nullable bundle; __block PreKeyBundle *_Nullable bundle;
__block NSException *_Nullable exception; __block NSException *_Nullable exception;
@ -1341,10 +1350,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
recipientId:identifier recipientId:identifier
deviceId:[deviceNumber intValue]]; deviceId:[deviceNumber intValue]];
@try { @try {
// Mutating session state is not thread safe. [builder processPrekeyBundle:bundle protocolContext:transaction];
@synchronized(self) {
[builder processPrekeyBundle:bundle];
}
} @catch (NSException *exception) { } @catch (NSException *exception) {
if ([exception.name isEqualToString:UntrustedIdentityKeyException]) { if ([exception.name isEqualToString:UntrustedIdentityKeyException]) {
OWSRaiseExceptionWithUserInfo(UntrustedIdentityKeyException, OWSRaiseExceptionWithUserInfo(UntrustedIdentityKeyException,
@ -1363,18 +1369,20 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
recipientId:identifier recipientId:identifier
deviceId:[deviceNumber intValue]]; deviceId:[deviceNumber intValue]];
id<CipherMessage> encryptedMessage = [cipher encryptMessage:[plainText paddedMessageBody]]; id<CipherMessage> encryptedMessage =
[cipher encryptMessage:[plainText paddedMessageBody] protocolContext:transaction];
NSData *serializedMessage = encryptedMessage.serialized; NSData *serializedMessage = encryptedMessage.serialized;
TSWhisperMessageType messageType = [self messageTypeForCipherMessage:encryptedMessage]; TSWhisperMessageType messageType = [self messageTypeForCipherMessage:encryptedMessage];
OWSMessageServiceParams *messageParams = [[OWSMessageServiceParams alloc] initWithType:messageType OWSMessageServiceParams *messageParams =
recipientId:identifier [[OWSMessageServiceParams alloc] initWithType:messageType
device:[deviceNumber intValue] recipientId:identifier
content:serializedMessage device:[deviceNumber intValue]
isSilent:isSilent content:serializedMessage
registrationId:cipher.remoteRegistrationId]; isSilent:isSilent
registrationId:[cipher remoteRegistrationId:transaction]];
NSError *error; NSError *error;
NSDictionary *jsonDict = [MTLJSONAdapter JSONDictionaryFromModel:messageParams error:&error]; NSDictionary *jsonDict = [MTLJSONAdapter JSONDictionaryFromModel:messageParams error:&error];
@ -1428,15 +1436,15 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
return; return;
} }
dispatch_async([OWSDispatch sessionStoreQueue], ^{ [TSStorageManager.protocolStoreDBConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
for (NSUInteger i = 0; i < [devices count]; i++) { for (NSUInteger i = 0; i < [devices count]; i++) {
int deviceNumber = [devices[i] intValue]; int deviceNumber = [devices[i] intValue];
[[TSStorageManager sharedManager] deleteSessionForContact:identifier [[TSStorageManager sharedManager] deleteSessionForContact:identifier
deviceId:deviceNumber deviceId:deviceNumber
protocolContext:protocolContext]; protocolContext:transaction];
} }
completionHandler(); }];
}); completionHandler();
}); });
} }

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

File diff suppressed because it is too large Load Diff

@ -1,5 +1,5 @@
// //
// Copyright (c) 2017 Open Whisper Systems. All rights reserved. // Copyright (c) 2018 Open Whisper Systems. All rights reserved.
// //
#import "OWSFingerprintBuilder.h" #import "OWSFingerprintBuilder.h"
@ -36,7 +36,8 @@ NS_ASSUME_NONNULL_BEGIN
- (nullable OWSFingerprint *)fingerprintWithTheirSignalId:(NSString *)theirSignalId - (nullable OWSFingerprint *)fingerprintWithTheirSignalId:(NSString *)theirSignalId
{ {
NSData *_Nullable theirIdentityKey = [[OWSIdentityManager sharedManager] identityKeyForRecipientId:theirSignalId]; NSData *_Nullable theirIdentityKey =
[[OWSIdentityManager sharedManager] identityKeyForRecipientIdWOT:theirSignalId];
if (theirIdentityKey == nil) { if (theirIdentityKey == nil) {
OWSFail(@"%@ Missing their identity key", self.logTag); OWSFail(@"%@ Missing their identity key", self.logTag);
@ -51,7 +52,7 @@ NS_ASSUME_NONNULL_BEGIN
NSString *theirName = [self.contactsManager displayNameForPhoneIdentifier:theirSignalId]; NSString *theirName = [self.contactsManager displayNameForPhoneIdentifier:theirSignalId];
NSString *mySignalId = [self.accountManager localNumber]; NSString *mySignalId = [self.accountManager localNumber];
NSData *myIdentityKey = [[OWSIdentityManager sharedManager] identityKeyPair].publicKey; NSData *myIdentityKey = [[OWSIdentityManager sharedManager] identityKeyPairWithoutProtocolContext].publicKey;
return [OWSFingerprint fingerprintWithMyStableId:mySignalId return [OWSFingerprint fingerprintWithMyStableId:mySignalId
myIdentityKey:myIdentityKey myIdentityKey:myIdentityKey

@ -43,7 +43,9 @@ NSString *const kSessionStoreDBConnectionKey = @"kSessionStoreDBConnectionKey";
#pragma mark - SessionStore #pragma mark - SessionStore
- (SessionRecord *)loadSession:(NSString *)contactIdentifier deviceId:(int)deviceId protocolContext:(id)protocolContext - (SessionRecord *)loadSession:(NSString *)contactIdentifier
deviceId:(int)deviceId
protocolContext:(nullable id)protocolContext
{ {
OWSAssert(contactIdentifier.length > 0); OWSAssert(contactIdentifier.length > 0);
OWSAssert(deviceId >= 0); OWSAssert(deviceId >= 0);
@ -116,7 +118,9 @@ NSString *const kSessionStoreDBConnectionKey = @"kSessionStoreDBConnectionKey";
inCollection:TSStorageManagerSessionStoreCollection]; inCollection:TSStorageManagerSessionStoreCollection];
} }
- (BOOL)containsSession:(NSString *)contactIdentifier deviceId:(int)deviceId protocolContext:(id)protocolContext - (BOOL)containsSession:(NSString *)contactIdentifier
deviceId:(int)deviceId
protocolContext:(nullable id)protocolContext
{ {
OWSAssert(contactIdentifier.length > 0); OWSAssert(contactIdentifier.length > 0);
OWSAssert(deviceId >= 0); OWSAssert(deviceId >= 0);

@ -27,7 +27,7 @@ NSString *const TSStorageManagerKeyPrekeyCurrentSignedPrekeyId = @"currentSigned
// Signed prekey ids must be > 0. // Signed prekey ids must be > 0.
int preKeyId = 1 + arc4random_uniform(INT32_MAX - 1); int preKeyId = 1 + arc4random_uniform(INT32_MAX - 1);
ECKeyPair *_Nullable identityKeyPair = [[OWSIdentityManager sharedManager] identityKeyPair]; ECKeyPair *_Nullable identityKeyPair = [[OWSIdentityManager sharedManager] identityKeyPairWithoutProtocolContext];
return [[SignedPreKeyRecord alloc] return [[SignedPreKeyRecord alloc]
initWithId:preKeyId initWithId:preKeyId
keyPair:keyPair keyPair:keyPair

Loading…
Cancel
Save