Merge branch 'friend-request-refactor' of github.com:loki-project/loki-messenger-ios into friend-request-refactor

pull/175/head
nielsandriesse 5 years ago
commit 845de99561

@ -173,10 +173,7 @@ public final class SyncMessagesProtocol : NSObject {
switch friendRequestStatus { switch friendRequestStatus {
case .none, .requestExpired: case .none, .requestExpired:
let messageSender = SSKEnvironment.shared.messageSender let messageSender = SSKEnvironment.shared.messageSender
// TODO: Does the function below need to handle multi device?? // We need to send the FR message to all of the users device as the contact sync message excludes slave devices
// We need to send a FR message here directly to the user. Multi device doesn't come into play.
// TODO: Say A1 has a conversation with B1 and B2. A2 is now linked to A1. We'd want A2 to establish
// sessions with both B1 and B2, right?
let autoGeneratedFRMessage = MultiDeviceProtocol.getAutoGeneratedMultiDeviceFRMessage(for: hexEncodedPublicKey, in: transaction) let autoGeneratedFRMessage = MultiDeviceProtocol.getAutoGeneratedMultiDeviceFRMessage(for: hexEncodedPublicKey, in: transaction)
thread.isForceHidden = true thread.isForceHidden = true
thread.save(with: transaction) thread.save(with: transaction)

@ -213,7 +213,7 @@ public class LokiP2PAPI : NSObject {
var friendThreadIDs: [String] = [] var friendThreadIDs: [String] = []
storage.dbReadConnection.read { transaction in storage.dbReadConnection.read { transaction in
TSContactThread.enumerateCollectionObjects(with: transaction) { object, _ in TSContactThread.enumerateCollectionObjects(with: transaction) { object, _ in
guard let thread = object as? TSContactThread, let uniqueID = thread.uniqueId, thread.contactIdentifier() == ourHexEncodedPubKey else { return } guard let thread = object as? TSContactThread, let uniqueID = thread.uniqueId, thread.contactIdentifier() != ourHexEncodedPubKey else { return }
let status = storage.getFriendRequestStatus(for: thread.contactIdentifier(), transaction: transaction) let status = storage.getFriendRequestStatus(for: thread.contactIdentifier(), transaction: transaction)
guard status == .friends else { return } guard status == .friends else { return }
friendThreadIDs.append(uniqueID) friendThreadIDs.append(uniqueID)

@ -221,12 +221,12 @@ void AssertIsOnSendingQueue()
} }
[self.messageSender sendMessageToService:self.message [self.messageSender sendMessageToService:self.message
success:^{ success:^{
[self reportSuccess]; [self reportSuccess];
} }
failure:^(NSError *error) { failure:^(NSError *error) {
[self reportError:error]; [self reportError:error];
}]; }];
} }
- (void)didSucceed - (void)didSucceed
@ -382,16 +382,16 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
// unorthodox. // unorthodox.
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[allAttachmentIds [allAttachmentIds
addObjectsFromArray:[OutgoingMessagePreparer prepareMessageForSending:message transaction:transaction]]; addObjectsFromArray:[OutgoingMessagePreparer prepareMessageForSending:message transaction:transaction]];
}]; }];
NSOperationQueue *sendingQueue = [self sendingQueueForMessage:message]; NSOperationQueue *sendingQueue = [self sendingQueueForMessage:message];
OWSSendMessageOperation *sendMessageOperation = OWSSendMessageOperation *sendMessageOperation =
[[OWSSendMessageOperation alloc] initWithMessage:message [[OWSSendMessageOperation alloc] initWithMessage:message
messageSender:self messageSender:self
dbConnection:self.dbConnection dbConnection:self.dbConnection
success:successHandler success:successHandler
failure:failureHandler]; failure:failureHandler];
for (NSString *attachmentId in allAttachmentIds) { for (NSString *attachmentId in allAttachmentIds) {
OWSUploadOperation *uploadAttachmentOperation = [[OWSUploadOperation alloc] initWithAttachmentId:attachmentId threadID:message.thread.uniqueId dbConnection:self.dbConnection]; OWSUploadOperation *uploadAttachmentOperation = [[OWSUploadOperation alloc] initWithAttachmentId:attachmentId threadID:message.thread.uniqueId dbConnection:self.dbConnection];
@ -466,12 +466,12 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
[OutgoingMessagePreparer prepareAttachments:attachmentInfos [OutgoingMessagePreparer prepareAttachments:attachmentInfos
inMessage:message inMessage:message
completionHandler:^(NSError *_Nullable error) { completionHandler:^(NSError *_Nullable error) {
if (error) { if (error) {
failure(error); failure(error);
return; return;
} }
[self sendMessage:message success:success failure:failure]; [self sendMessage:message success:success failure:failure];
}]; }];
} }
- (void)sendMessageToService:(TSOutgoingMessage *)message - (void)sendMessageToService:(TSOutgoingMessage *)message
@ -479,16 +479,16 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
failure:(RetryableFailureHandler)failure failure:(RetryableFailureHandler)failure
{ {
[self.udManager [self.udManager
ensureSenderCertificateWithSuccess:^(SMKSenderCertificate *senderCertificate) { ensureSenderCertificateWithSuccess:^(SMKSenderCertificate *senderCertificate) {
dispatch_async([OWSDispatch sendingQueue], ^{ dispatch_async([OWSDispatch sendingQueue], ^{
[self sendMessageToService:message senderCertificate:senderCertificate success:success failure:failure]; [self sendMessageToService:message senderCertificate:senderCertificate success:success failure:failure];
}); });
} }
failure:^(NSError *error) { failure:^(NSError *error) {
dispatch_async([OWSDispatch sendingQueue], ^{ dispatch_async([OWSDispatch sendingQueue], ^{
[self sendMessageToService:message senderCertificate:nil success:success failure:failure]; [self sendMessageToService:message senderCertificate:nil success:success failure:failure];
}); });
}]; }];
} }
- (nullable NSArray<NSString *> *)unsentRecipientsForMessage:(TSOutgoingMessage *)message - (nullable NSArray<NSString *> *)unsentRecipientsForMessage:(TSOutgoingMessage *)message
@ -547,7 +547,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
for (NSString *recipientId in recipientIds) { for (NSString *recipientId in recipientIds) {
SignalRecipient *recipient = SignalRecipient *recipient =
[SignalRecipient getOrBuildUnsavedRecipientForRecipientId:recipientId transaction:transaction]; [SignalRecipient getOrBuildUnsavedRecipientForRecipientId:recipientId transaction:transaction];
[recipients addObject:recipient]; [recipients addObject:recipient];
} }
}]; }];
@ -576,21 +576,21 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
} }
OWSMessageSend *messageSend = [[OWSMessageSend alloc] initWithMessage:message OWSMessageSend *messageSend = [[OWSMessageSend alloc] initWithMessage:message
thread:thread thread:thread
recipient:recipient recipient:recipient
senderCertificate:senderCertificate senderCertificate:senderCertificate
udAccess:theirUDAccess udAccess:theirUDAccess
localNumber:self.tsAccountManager.localNumber localNumber:self.tsAccountManager.localNumber
success:^{ success:^{
// The value doesn't matter, we just need any non-NSError value. // The value doesn't matter, we just need any non-NSError value.
resolve(@(1)); resolve(@(1));
}
failure:^(NSError *error) {
@synchronized(sendErrors) {
[sendErrors addObject:error];
} }
resolve(error); failure:^(NSError *error) {
}]; @synchronized(sendErrors) {
[sendErrors addObject:error];
}
resolve(error);
}];
if ([LKMultiDeviceProtocol isMultiDeviceRequiredForMessage:message]) { // Avoid the write transaction if possible if ([LKMultiDeviceProtocol isMultiDeviceRequiredForMessage:message]) { // Avoid the write transaction if possible
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
@ -623,34 +623,34 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
void (^successHandler)(void) = ^() { void (^successHandler)(void) = ^() {
dispatch_async([OWSDispatch sendingQueue], ^{ dispatch_async([OWSDispatch sendingQueue], ^{
[self handleMessageSentLocally:message [self handleMessageSentLocally:message
success:^{ success:^{
successHandlerParam(); successHandlerParam();
} }
failure:^(NSError *error) { failure:^(NSError *error) {
OWSLogError(@"Error sending sync message for message: %@ timestamp: %llu.", OWSLogError(@"Error sending sync message for message: %@ timestamp: %llu.",
message.class, message.class,
message.timestamp); message.timestamp);
failureHandlerParam(error); failureHandlerParam(error);
}]; }];
}); });
}; };
void (^failureHandler)(NSError *) = ^(NSError *error) { void (^failureHandler)(NSError *) = ^(NSError *error) {
if (message.wasSentToAnyRecipient) { if (message.wasSentToAnyRecipient) {
dispatch_async([OWSDispatch sendingQueue], ^{ dispatch_async([OWSDispatch sendingQueue], ^{
[self handleMessageSentLocally:message [self handleMessageSentLocally:message
success:^{ success:^{
failureHandlerParam(error); failureHandlerParam(error);
} }
failure:^(NSError *syncError) { failure:^(NSError *syncError) {
OWSLogError(@"Error sending sync message for message: %@ timestamp: %llu, %@.", OWSLogError(@"Error sending sync message for message: %@ timestamp: %llu, %@.",
message.class, message.class,
message.timestamp, message.timestamp,
syncError); syncError);
// Discard the sync message error in favor of the original error // Discard the sync message error in favor of the original error
failureHandlerParam(error); failureHandlerParam(error);
}]; }];
}); });
return; return;
} }
@ -665,7 +665,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
// This thread has been deleted since the message was enqueued. // This thread has been deleted since the message was enqueued.
NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeMessageSendNoValidRecipients, NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeMessageSendNoValidRecipients,
NSLocalizedString(@"ERROR_DESCRIPTION_NO_VALID_RECIPIENTS", @"Error indicating that an outgoing message had no valid recipients.")); NSLocalizedString(@"ERROR_DESCRIPTION_NO_VALID_RECIPIENTS", @"Error indicating that an outgoing message had no valid recipients."));
[error setIsRetryable:NO]; [error setIsRetryable:NO];
return failureHandler(error); return failureHandler(error);
} }
@ -686,7 +686,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
NSArray<NSString *> *_Nullable recipientIds = [self unsentRecipientsForMessage:message thread:thread error:&error]; NSArray<NSString *> *_Nullable recipientIds = [self unsentRecipientsForMessage:message thread:thread error:&error];
if (error || !recipientIds) { if (error || !recipientIds) {
error = SSKEnsureError( error = SSKEnsureError(
error, OWSErrorCodeMessageSendNoValidRecipients, @"Could not build recipients list for message."); error, OWSErrorCodeMessageSendNoValidRecipients, @"Could not build recipients list for message.");
[error setIsRetryable:NO]; [error setIsRetryable:NO];
return failureHandler(error); return failureHandler(error);
} }
@ -723,9 +723,9 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
thread:thread thread:thread
senderCertificate:senderCertificate senderCertificate:senderCertificate
sendErrors:sendErrors] sendErrors:sendErrors]
.then(^(id value) { .then(^(id value) {
successHandler(); successHandler();
}); });
sendPromise.catch(^(id failure) { sendPromise.catch(^(id failure) {
NSError *firstRetryableError = nil; NSError *firstRetryableError = nil;
@ -773,7 +773,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
// not be sent to any recipient. // not be sent to any recipient.
if (message.sentRecipientsCount == 0) { if (message.sentRecipientsCount == 0) {
NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeMessageSendNoValidRecipients, NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeMessageSendNoValidRecipients,
NSLocalizedString(@"ERROR_DESCRIPTION_NO_VALID_RECIPIENTS", @"Error indicating that an outgoing message had no valid recipients.")); NSLocalizedString(@"ERROR_DESCRIPTION_NO_VALID_RECIPIENTS", @"Error indicating that an outgoing message had no valid recipients."));
[error setIsRetryable:NO]; [error setIsRetryable:NO];
failureHandler(error); failureHandler(error);
} else { } else {
@ -802,7 +802,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
[SignalRecipient markRecipientAsUnregistered:recipient.recipientId transaction:transaction]; [SignalRecipient markRecipientAsUnregistered:recipient.recipientId transaction:transaction];
[[TSInfoMessage userNotRegisteredMessageInThread:thread recipientId:recipient.recipientId] [[TSInfoMessage userNotRegisteredMessageInThread:thread recipientId:recipient.recipientId]
saveWithTransaction:transaction]; saveWithTransaction:transaction];
// TODO: Should we deleteAllSessionsForContact here? // TODO: Should we deleteAllSessionsForContact here?
// If so, we'll need to avoid doing a prekey fetch every // If so, we'll need to avoid doing a prekey fetch every
@ -829,7 +829,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
// we silently discard these message if there is no pre-existing session // we silently discard these message if there is no pre-existing session
// for the recipient. // for the recipient.
NSError *error = OWSErrorWithCodeDescription( NSError *error = OWSErrorWithCodeDescription(
OWSErrorCodeNoSessionForTransientMessage, @"No session for transient message."); OWSErrorCodeNoSessionForTransientMessage, @"No session for transient message.");
[error setIsRetryable:NO]; [error setIsRetryable:NO];
[error setIsFatal:YES]; [error setIsFatal:YES];
*errorHandle = error; *errorHandle = error;
@ -842,12 +842,12 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
OWSProdInfo([OWSAnalyticsEvents messageSendErrorFailedDueToUntrustedKey]); OWSProdInfo([OWSAnalyticsEvents messageSendErrorFailedDueToUntrustedKey]);
NSString *localizedErrorDescriptionFormat NSString *localizedErrorDescriptionFormat
= NSLocalizedString(@"FAILED_SENDING_BECAUSE_UNTRUSTED_IDENTITY_KEY", = NSLocalizedString(@"FAILED_SENDING_BECAUSE_UNTRUSTED_IDENTITY_KEY",
@"action sheet header when re-sending message which failed because of untrusted identity keys"); @"action sheet header when re-sending message which failed because of untrusted identity keys");
NSString *localizedErrorDescription = NSString *localizedErrorDescription =
[NSString stringWithFormat:localizedErrorDescriptionFormat, [NSString stringWithFormat:localizedErrorDescriptionFormat,
[self.contactsManager displayNameForPhoneIdentifier:recipient.recipientId]]; [self.contactsManager displayNameForPhoneIdentifier:recipient.recipientId]];
NSError *error = OWSErrorMakeUntrustedIdentityError(localizedErrorDescription, recipient.recipientId); NSError *error = OWSErrorMakeUntrustedIdentityError(localizedErrorDescription, recipient.recipientId);
// Key will continue to be unaccepted, so no need to retry. It'll only cause us to hit the Pre-Key request // Key will continue to be unaccepted, so no need to retry. It'll only cause us to hit the Pre-Key request
@ -889,8 +889,8 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
if ([exception.name isEqualToString:OWSMessageSenderRateLimitedException]) { if ([exception.name isEqualToString:OWSMessageSenderRateLimitedException]) {
NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeSignalServiceRateLimited, NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeSignalServiceRateLimited,
NSLocalizedString(@"FAILED_SENDING_BECAUSE_RATE_LIMIT", NSLocalizedString(@"FAILED_SENDING_BECAUSE_RATE_LIMIT",
@"action sheet header when re-sending message which failed because of too many attempts")); @"action sheet header when re-sending message which failed because of too many attempts"));
// We're already rate-limited. No need to exacerbate the problem. // We're already rate-limited. No need to exacerbate the problem.
[error setIsRetryable:NO]; [error setIsRetryable:NO];
// Avoid exacerbating the rate limiting. // Avoid exacerbating the rate limiting.
@ -918,9 +918,9 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
SignalRecipient *recipient = messageSend.recipient; SignalRecipient *recipient = messageSend.recipient;
OWSLogInfo(@"Attempting to send message: %@, timestamp: %llu, recipient: %@.", OWSLogInfo(@"Attempting to send message: %@, timestamp: %llu, recipient: %@.",
message.class, message.class,
message.timestamp, message.timestamp,
recipient.uniqueId); recipient.uniqueId);
AssertIsOnSendingQueue(); AssertIsOnSendingQueue();
if ([TSPreKeyManager isAppLockedDueToPreKeyUpdateFailures]) { if ([TSPreKeyManager isAppLockedDueToPreKeyUpdateFailures]) {
@ -932,16 +932,16 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
// Only try to update the signed prekey; updating it is sufficient to // Only try to update the signed prekey; updating it is sufficient to
// re-enable message sending. // re-enable message sending.
[TSPreKeyManager [TSPreKeyManager
rotateSignedPreKeyWithSuccess:^{ rotateSignedPreKeyWithSuccess:^{
OWSLogInfo(@"New pre keys registered with server."); OWSLogInfo(@"New pre keys registered with server.");
NSError *error = OWSErrorMakeMessageSendDisabledDueToPreKeyUpdateFailuresError(); NSError *error = OWSErrorMakeMessageSendDisabledDueToPreKeyUpdateFailuresError();
[error setIsRetryable:YES]; [error setIsRetryable:YES];
return messageSend.failure(error); return messageSend.failure(error);
} }
failure:^(NSError *error) { failure:^(NSError *error) {
OWSLogWarn(@"Failed to update pre keys with the server due to error: %@.", error); OWSLogWarn(@"Failed to update pre keys with the server due to error: %@.", error);
return messageSend.failure(error); return messageSend.failure(error);
}]; }];
} }
if (messageSend.remainingAttempts <= 0) { if (messageSend.remainingAttempts <= 0) {
@ -977,79 +977,79 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
} }
/* /*
if (messageSend.isLocalNumber) { if (messageSend.isLocalNumber) {
OWSAssertDebug([message isKindOfClass:[OWSOutgoingSyncMessage class]]); OWSAssertDebug([message isKindOfClass:[OWSOutgoingSyncMessage class]]);
// Messages sent to the "local number" should be sync messages. // Messages sent to the "local number" should be sync messages.
// //
// We can skip sending sync messages if we know that we have no linked // We can skip sending sync messages if we know that we have no linked
// devices. However, we need to be sure to handle the case where the // devices. However, we need to be sure to handle the case where the
// linked device list has just changed. // linked device list has just changed.
// //
// The linked device list is reflected in two separate pieces of state: // The linked device list is reflected in two separate pieces of state:
// //
// * OWSDevice's state is updated when you link or unlink a device. // * OWSDevice's state is updated when you link or unlink a device.
// * SignalRecipient's state is updated by 409 "Mismatched devices" // * SignalRecipient's state is updated by 409 "Mismatched devices"
// responses from the service. // responses from the service.
// //
// If _both_ of these pieces of state agree that there are no linked // If _both_ of these pieces of state agree that there are no linked
// devices, then can safely skip sending sync message. // devices, then can safely skip sending sync message.
// //
// NOTE: Sync messages sent via UD include the local device. // NOTE: Sync messages sent via UD include the local device.
BOOL mayHaveLinkedDevices = [OWSDeviceManager.sharedManager mayHaveLinkedDevices:self.dbConnection]; BOOL mayHaveLinkedDevices = [OWSDeviceManager.sharedManager mayHaveLinkedDevices:self.dbConnection];
BOOL hasDeviceMessages = NO; BOOL hasDeviceMessages = NO;
for (NSDictionary<NSString *, id> *deviceMessage in deviceMessages) { for (NSDictionary<NSString *, id> *deviceMessage in deviceMessages) {
NSString *_Nullable destination = deviceMessage[@"destination"]; NSString *_Nullable destination = deviceMessage[@"destination"];
if (!destination) { if (!destination) {
OWSFailDebug(@"Sync device message missing destination: %@", deviceMessage); OWSFailDebug(@"Sync device message missing destination: %@", deviceMessage);
continue; continue;
} }
if (![destination isEqualToString:messageSend.localNumber]) { if (![destination isEqualToString:messageSend.localNumber]) {
OWSFailDebug(@"Sync device message has invalid destination: %@", deviceMessage); OWSFailDebug(@"Sync device message has invalid destination: %@", deviceMessage);
continue; continue;
} }
NSNumber *_Nullable destinationDeviceId = deviceMessage[@"destinationDeviceId"]; NSNumber *_Nullable destinationDeviceId = deviceMessage[@"destinationDeviceId"];
if (!destinationDeviceId) { if (!destinationDeviceId) {
OWSFailDebug(@"Sync device message missing destination device id: %@", deviceMessage); OWSFailDebug(@"Sync device message missing destination device id: %@", deviceMessage);
continue; continue;
} }
if (destinationDeviceId.intValue != OWSDevicePrimaryDeviceId) { if (destinationDeviceId.intValue != OWSDevicePrimaryDeviceId) {
hasDeviceMessages = YES; hasDeviceMessages = YES;
break; break;
} }
} }
OWSLogInfo(@"mayHaveLinkedDevices: %d, hasDeviceMessages: %d", mayHaveLinkedDevices, hasDeviceMessages); OWSLogInfo(@"mayHaveLinkedDevices: %d, hasDeviceMessages: %d", mayHaveLinkedDevices, hasDeviceMessages);
if (!mayHaveLinkedDevices && !hasDeviceMessages) { if (!mayHaveLinkedDevices && !hasDeviceMessages) {
OWSLogInfo(@"Ignoring sync message without secondary devices: %@", [message class]); OWSLogInfo(@"Ignoring sync message without secondary devices: %@", [message class]);
OWSAssertDebug([message isKindOfClass:[OWSOutgoingSyncMessage class]]); OWSAssertDebug([message isKindOfClass:[OWSOutgoingSyncMessage class]]);
dispatch_async([OWSDispatch sendingQueue], ^{ dispatch_async([OWSDispatch sendingQueue], ^{
// This emulates the completion logic of an actual successful send (see below). // This emulates the completion logic of an actual successful send (see below).
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[message updateWithSkippedRecipient:messageSend.localNumber transaction:transaction]; [message updateWithSkippedRecipient:messageSend.localNumber transaction:transaction];
}]; }];
messageSend.success(); messageSend.success();
}); });
return; return;
} else if (mayHaveLinkedDevices && !hasDeviceMessages) { } else if (mayHaveLinkedDevices && !hasDeviceMessages) {
// We may have just linked a new secondary device which is not yet reflected in // We may have just linked a new secondary device which is not yet reflected in
// the SignalRecipient that corresponds to ourself. Proceed. Client should learn // the SignalRecipient that corresponds to ourself. Proceed. Client should learn
// of new secondary devices via 409 "Mismatched devices" response. // of new secondary devices via 409 "Mismatched devices" response.
OWSLogWarn(@"account has secondary devices, but sync message has no device messages"); OWSLogWarn(@"account has secondary devices, but sync message has no device messages");
} else if (!mayHaveLinkedDevices && hasDeviceMessages) { } else if (!mayHaveLinkedDevices && hasDeviceMessages) {
OWSFailDebug(@"sync message has device messages for unknown secondary devices."); OWSFailDebug(@"sync message has device messages for unknown secondary devices.");
} }
} else { } else {
// This can happen for users who have unregistered. // This can happen for users who have unregistered.
// We still want to try sending to them in case they have re-registered. // We still want to try sending to them in case they have re-registered.
if (deviceMessages.count < 1) { if (deviceMessages.count < 1) {
OWSLogWarn(@"Message send attempt with no device messages."); OWSLogWarn(@"Message send attempt with no device messages.");
} }
} }
*/ */
for (NSDictionary *deviceMessage in deviceMessages) { for (NSDictionary *deviceMessage in deviceMessages) {
@ -1127,7 +1127,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
} }
NSString *body = (message.body != nil && message.body.length > 0) ? message.body : [NSString stringWithFormat:@"%@", @(message.timestamp)]; // Workaround for the fact that the back-end doesn't accept messages without a body NSString *body = (message.body != nil && message.body.length > 0) ? message.body : [NSString stringWithFormat:@"%@", @(message.timestamp)]; // Workaround for the fact that the back-end doesn't accept messages without a body
LKGroupMessage *groupMessage = [[LKGroupMessage alloc] initWithHexEncodedPublicKey:userHexEncodedPublicKey displayName:displayName body:body type:LKPublicChatAPI.publicChatMessageType LKGroupMessage *groupMessage = [[LKGroupMessage alloc] initWithHexEncodedPublicKey:userHexEncodedPublicKey displayName:displayName body:body type:LKPublicChatAPI.publicChatMessageType
timestamp:message.timestamp quotedMessageTimestamp:quoteID quoteeHexEncodedPublicKey:quoteeHexEncodedPublicKey quotedMessageBody:quote.body quotedMessageServerID:quotedMessageServerID signatureData:nil signatureVersion:0]; timestamp:message.timestamp quotedMessageTimestamp:quoteID quoteeHexEncodedPublicKey:quoteeHexEncodedPublicKey quotedMessageBody:quote.body quotedMessageServerID:quotedMessageServerID signatureData:nil signatureVersion:0];
OWSLinkPreview *linkPreview = message.linkPreview; OWSLinkPreview *linkPreview = message.linkPreview;
if (linkPreview != nil) { if (linkPreview != nil) {
TSAttachmentStream *attachment = [TSAttachmentStream fetchObjectWithUniqueID:linkPreview.imageAttachmentId]; TSAttachmentStream *attachment = [TSAttachmentStream fetchObjectWithUniqueID:linkPreview.imageAttachmentId];
@ -1144,14 +1144,14 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
} }
message.actualSenderHexEncodedPublicKey = userHexEncodedPublicKey; message.actualSenderHexEncodedPublicKey = userHexEncodedPublicKey;
[[LKPublicChatAPI sendMessage:groupMessage toGroup:publicChat.channel onServer:publicChat.server] [[LKPublicChatAPI sendMessage:groupMessage toGroup:publicChat.channel onServer:publicChat.server]
.thenOn(OWSDispatch.sendingQueue, ^(LKGroupMessage *groupMessage) { .thenOn(OWSDispatch.sendingQueue, ^(LKGroupMessage *groupMessage) {
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[message saveOpenGroupServerMessageID:groupMessage.serverID in:transaction]; [message saveOpenGroupServerMessageID:groupMessage.serverID in:transaction];
[self.primaryStorage setIDForMessageWithServerID:groupMessage.serverID to:message.uniqueId in:transaction]; [self.primaryStorage setIDForMessageWithServerID:groupMessage.serverID to:message.uniqueId in:transaction];
}]; }];
[self messageSendDidSucceed:messageSend deviceMessages:deviceMessages wasSentByUD:messageSend.isUDSend wasSentByWebsocket:false]; [self messageSendDidSucceed:messageSend deviceMessages:deviceMessages wasSentByUD:messageSend.isUDSend wasSentByWebsocket:false];
}) })
.catchOn(OWSDispatch.sendingQueue, ^(NSError *error) { .catchOn(OWSDispatch.sendingQueue, ^(NSError *error) {
failedMessageSend(error); failedMessageSend(error);
}) retainUntilComplete]; }) retainUntilComplete];
} else { } else {
@ -1216,11 +1216,10 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
__block NSUInteger errorCount = 0; __block NSUInteger errorCount = 0;
for (AnyPromise *promise in promises) { for (AnyPromise *promise in promises) {
[promise [promise
.thenOn(OWSDispatch.sendingQueue, ^(id result) { .thenOn(OWSDispatch.sendingQueue, ^(id result) {
if (isSuccess) { return; } // Succeed as soon as the first promise succeeds if (isSuccess) { return; } // Succeed as soon as the first promise succeeds
[NSNotificationCenter.defaultCenter postNotificationName:NSNotification.messageSent object:[[NSNumber alloc] initWithUnsignedLongLong:signalMessage.timestamp]]; [NSNotificationCenter.defaultCenter postNotificationName:NSNotification.messageSent object:[[NSNumber alloc] initWithUnsignedLongLong:signalMessage.timestamp]];
isSuccess = YES; isSuccess = YES;
if (signalMessage.isFriendRequest) { if (signalMessage.isFriendRequest) {
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
if (!message.skipSave) { if (!message.skipSave) {
@ -1239,7 +1238,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
// Invoke the completion handler // Invoke the completion handler
[self messageSendDidSucceed:messageSend deviceMessages:deviceMessages wasSentByUD:messageSend.isUDSend wasSentByWebsocket:false]; [self messageSendDidSucceed:messageSend deviceMessages:deviceMessages wasSentByUD:messageSend.isUDSend wasSentByWebsocket:false];
}) })
.catchOn(OWSDispatch.sendingQueue, ^(NSError *error) { .catchOn(OWSDispatch.sendingQueue, ^(NSError *error) {
errorCount += 1; errorCount += 1;
if (errorCount != promiseCount) { return; } // Only error out if all promises failed if (errorCount != promiseCount) { return; } // Only error out if all promises failed
[NSNotificationCenter.defaultCenter postNotificationName:NSNotification.messageFailed object:[[NSNumber alloc] initWithUnsignedLongLong:signalMessage.timestamp]]; [NSNotificationCenter.defaultCenter postNotificationName:NSNotification.messageFailed object:[[NSNumber alloc] initWithUnsignedLongLong:signalMessage.timestamp]];
@ -1247,7 +1246,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
}) retainUntilComplete]; }) retainUntilComplete];
} }
}) })
.catchOn(OWSDispatch.sendingQueue, ^(NSError *error) { .catchOn(OWSDispatch.sendingQueue, ^(NSError *error) {
handleError(error); handleError(error);
}) retainUntilComplete]; }) retainUntilComplete];
} }
@ -1308,9 +1307,9 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
SignalRecipient *recipient = messageSend.recipient; SignalRecipient *recipient = messageSend.recipient;
OWSLogInfo(@"failed to send message: %@, timestamp: %llu, to recipient: %@", OWSLogInfo(@"failed to send message: %@, timestamp: %llu, to recipient: %@",
message.class, message.class,
message.timestamp, message.timestamp,
recipient.uniqueId); recipient.uniqueId);
void (^retrySend)(void) = ^void() { void (^retrySend)(void) = ^void() {
if (messageSend.remainingAttempts <= 0) { if (messageSend.remainingAttempts <= 0) {
@ -1359,8 +1358,8 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
OWSLogWarn(@"Unable to send due to invalid credentials. Did the user's client get de-authed by " OWSLogWarn(@"Unable to send due to invalid credentials. Did the user's client get de-authed by "
@"registering elsewhere?"); @"registering elsewhere?");
NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeSignalServiceFailure, NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeSignalServiceFailure,
NSLocalizedString( NSLocalizedString(
@"ERROR_DESCRIPTION_SENDING_UNAUTHORIZED", @"Error message when attempting to send message")); @"ERROR_DESCRIPTION_SENDING_UNAUTHORIZED", @"Error message when attempting to send message"));
// No need to retry if we've been de-authed. // No need to retry if we've been de-authed.
[error setIsRetryable:NO]; [error setIsRetryable:NO];
return messageSend.failure(error); return messageSend.failure(error);
@ -1450,28 +1449,28 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
} }
[self.dbConnection [self.dbConnection
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
if (extraDevices.count < 1 && missingDevices.count < 1) { if (extraDevices.count < 1 && missingDevices.count < 1) {
OWSProdFail([OWSAnalyticsEvents messageSenderErrorNoMissingOrExtraDevices]); OWSProdFail([OWSAnalyticsEvents messageSenderErrorNoMissingOrExtraDevices]);
} }
[recipient updateRegisteredRecipientWithDevicesToAdd:missingDevices [recipient updateRegisteredRecipientWithDevicesToAdd:missingDevices
devicesToRemove:extraDevices devicesToRemove:extraDevices
transaction:transaction]; transaction:transaction];
if (extraDevices && extraDevices.count > 0) { if (extraDevices && extraDevices.count > 0) {
OWSLogInfo(@"Deleting sessions for extra devices: %@", extraDevices); OWSLogInfo(@"Deleting sessions for extra devices: %@", extraDevices);
for (NSNumber *extraDeviceId in extraDevices) { for (NSNumber *extraDeviceId in extraDevices) {
[self.primaryStorage deleteSessionForContact:recipient.uniqueId [self.primaryStorage deleteSessionForContact:recipient.uniqueId
deviceId:extraDeviceId.intValue deviceId:extraDeviceId.intValue
protocolContext:transaction]; protocolContext:transaction];
}
} }
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
completionHandler(); completionHandler();
}); });
}]; }];
} }
- (void)handleMessageSentLocally:(TSOutgoingMessage *)message - (void)handleMessageSentLocally:(TSOutgoingMessage *)message
@ -1510,16 +1509,16 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
BOOL isRecipientUpdate = message.hasSyncedTranscript; BOOL isRecipientUpdate = message.hasSyncedTranscript;
[self [self
sendSyncTranscriptForMessage:message sendSyncTranscriptForMessage:message
isRecipientUpdate:isRecipientUpdate isRecipientUpdate:isRecipientUpdate
success:^{ success:^{
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[message updateWithHasSyncedTranscript:YES transaction:transaction]; [message updateWithHasSyncedTranscript:YES transaction:transaction];
}]; }];
success(); success();
} }
failure:failure]; failure:failure];
} }
- (void)sendSyncTranscriptForMessage:(TSOutgoingMessage *)message - (void)sendSyncTranscriptForMessage:(TSOutgoingMessage *)message
@ -1528,7 +1527,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
failure:(RetryableFailureHandler)failure failure:(RetryableFailureHandler)failure
{ {
OWSOutgoingSentMessageTranscript *sentMessageTranscript = OWSOutgoingSentMessageTranscript *sentMessageTranscript =
[[OWSOutgoingSentMessageTranscript alloc] initWithOutgoingMessage:message isRecipientUpdate:isRecipientUpdate]; [[OWSOutgoingSentMessageTranscript alloc] initWithOutgoingMessage:message isRecipientUpdate:isRecipientUpdate];
NSString *recipientId = self.tsAccountManager.localNumber; NSString *recipientId = self.tsAccountManager.localNumber;
__block SignalRecipient *recipient; __block SignalRecipient *recipient;
@ -1543,21 +1542,21 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
} }
OWSMessageSend *messageSend = [[OWSMessageSend alloc] initWithMessage:sentMessageTranscript OWSMessageSend *messageSend = [[OWSMessageSend alloc] initWithMessage:sentMessageTranscript
thread:message.thread thread:message.thread
recipient:recipient recipient:recipient
senderCertificate:senderCertificate senderCertificate:senderCertificate
udAccess:recipientUDAccess udAccess:recipientUDAccess
localNumber:self.tsAccountManager.localNumber localNumber:self.tsAccountManager.localNumber
success:^{ success:^{
OWSLogInfo(@"Successfully sent sync transcript."); OWSLogInfo(@"Successfully sent sync transcript.");
success(); success();
} }
failure:^(NSError *error) { failure:^(NSError *error) {
OWSLogInfo(@"Failed to send sync transcript: %@ (isRetryable: %d)", error, [error isRetryable]); OWSLogInfo(@"Failed to send sync transcript: %@ (isRetryable: %d)", error, [error isRetryable]);
failure(error); failure(error);
}]; }];
if ([LKMultiDeviceProtocol isMultiDeviceRequiredForMessage:message]) { // Avoid the write transaction if possible if ([LKMultiDeviceProtocol isMultiDeviceRequiredForMessage:message]) { // Avoid the write transaction if possible
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
[self.primaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [self.primaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
@ -1585,10 +1584,10 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
OWSLogDebug(@"Built message: %@ plainTextData.length: %lu", [messageSend.message class], (unsigned long)plainText.length); OWSLogDebug(@"Built message: %@ plainTextData.length: %lu", [messageSend.message class], (unsigned long)plainText.length);
OWSLogVerbose(@"Building device messages for: %@ %@ (isLocalNumber: %d, isUDSend: %d).", OWSLogVerbose(@"Building device messages for: %@ %@ (isLocalNumber: %d, isUDSend: %d).",
recipient.recipientId, recipient.recipientId,
recipient.devices, recipient.devices,
messageSend.isLocalNumber, messageSend.isLocalNumber,
messageSend.isUDSend); messageSend.isUDSend);
// Loki: Multi device is handled elsewhere so just send to the provided recipient ID here // Loki: Multi device is handled elsewhere so just send to the provided recipient ID here
NSArray<NSString *> *recipientIDs = @[ recipient.recipientId ]; NSArray<NSString *> *recipientIDs = @[ recipient.recipientId ];
@ -1605,16 +1604,16 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
__block NSDictionary *_Nullable messageDict; __block NSDictionary *_Nullable messageDict;
__block NSException *encryptionException; __block NSException *encryptionException;
[self.dbConnection [self.dbConnection
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
@try { @try {
messageDict = [self throws_encryptedMessageForMessageSend:messageSend messageDict = [self throws_encryptedMessageForMessageSend:messageSend
recipientID:recipientID recipientID:recipientID
plainText:plainText plainText:plainText
transaction:transaction]; transaction:transaction];
} @catch (NSException *exception) { } @catch (NSException *exception) {
encryptionException = exception; encryptionException = exception;
} }
}]; }];
if (encryptionException) { if (encryptionException) {
OWSLogInfo(@"Exception during encryption: %@.", encryptionException); OWSLogInfo(@"Exception during encryption: %@.", encryptionException);
@ -1669,35 +1668,35 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
/** Loki: Original code /** Loki: Original code
* ================ * ================
__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;
[self makePrekeyRequestForMessageSend:messageSend [self makePrekeyRequestForMessageSend:messageSend
deviceId:deviceId deviceId:deviceId
success:^(PreKeyBundle *_Nullable responseBundle) { success:^(PreKeyBundle *_Nullable responseBundle) {
bundle = responseBundle; bundle = responseBundle;
dispatch_semaphore_signal(sema); dispatch_semaphore_signal(sema);
} }
failure:^(NSUInteger statusCode) { failure:^(NSUInteger statusCode) {
if (statusCode == 404) { if (statusCode == 404) {
// Can't throw exception from within callback as it's probabably a different thread. // Can't throw exception from within callback as it's probabably a different thread.
exception = [NSException exceptionWithName:OWSMessageSenderInvalidDeviceException exception = [NSException exceptionWithName:OWSMessageSenderInvalidDeviceException
reason:@"Device not registered" reason:@"Device not registered"
userInfo:nil]; userInfo:nil];
} else if (statusCode == 413) { } else if (statusCode == 413) {
// Can't throw exception from within callback as it's probabably a different thread. // Can't throw exception from within callback as it's probabably a different thread.
exception = [NSException exceptionWithName:OWSMessageSenderRateLimitedException exception = [NSException exceptionWithName:OWSMessageSenderRateLimitedException
reason:@"Too many prekey requests" reason:@"Too many prekey requests"
userInfo:nil]; userInfo:nil];
} }
dispatch_semaphore_signal(sema); dispatch_semaphore_signal(sema);
}]; }];
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
if (exception) { if (exception) {
@throw exception; @throw exception;
} }
* ================ * ================
*/ */
if (!bundle) { if (!bundle) {
NSString *missingPrekeyBundleException = @"missingPrekeyBundleException"; NSString *missingPrekeyBundleException = @"missingPrekeyBundleException";
@ -1722,8 +1721,8 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
if (exception) { if (exception) {
if ([exception.name isEqualToString:UntrustedIdentityKeyException]) { if ([exception.name isEqualToString:UntrustedIdentityKeyException]) {
OWSRaiseExceptionWithUserInfo(UntrustedIdentityKeyException, OWSRaiseExceptionWithUserInfo(UntrustedIdentityKeyException,
(@{ TSInvalidPreKeyBundleKey : bundle, TSInvalidRecipientKey : recipientID }), (@{ TSInvalidPreKeyBundleKey : bundle, TSInvalidRecipientKey : recipientID }),
@""); @"");
} }
@throw exception; @throw exception;
} }
@ -1742,50 +1741,50 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
OWSAssertDebug(recipientId.length > 0); OWSAssertDebug(recipientId.length > 0);
OWSRequestMaker *requestMaker = [[OWSRequestMaker alloc] initWithLabel:@"Prekey Fetch" OWSRequestMaker *requestMaker = [[OWSRequestMaker alloc] initWithLabel:@"Prekey Fetch"
requestFactoryBlock:^(SMKUDAccessKey *_Nullable udAccessKey) { requestFactoryBlock:^(SMKUDAccessKey *_Nullable udAccessKey) {
return [OWSRequestFactory recipientPrekeyRequestWithRecipient:recipientId return [OWSRequestFactory recipientPrekeyRequestWithRecipient:recipientId
deviceId:[deviceId stringValue] deviceId:[deviceId stringValue]
udAccessKey:udAccessKey]; udAccessKey:udAccessKey];
}
udAuthFailureBlock:^{
// Note the UD auth failure so subsequent retries
// to this recipient also use basic auth.
[messageSend setHasUDAuthFailed];
}
websocketFailureBlock:^{
// Note the websocket failure so subsequent retries
// to this recipient also use REST.
messageSend.hasWebsocketSendFailed = YES;
}
recipientId:recipientId
udAccess:messageSend.udAccess
canFailoverUDAuth:YES];
[[requestMaker makeRequestObjc]
.then(^(OWSRequestMakerResult *result) {
// We _do not_ want to dispatch to the sendingQueue here; we're
// using a semaphore on the sendingQueue to block on this request.
const id responseObject = result.responseObject;
PreKeyBundle *_Nullable bundle =
[PreKeyBundle preKeyBundleFromDictionary:responseObject forDeviceNumber:deviceId];
success(bundle);
})
.catch(^(NSError *error) {
// We _do not_ want to dispatch to the sendingQueue here; we're
// using a semaphore on the sendingQueue to block on this request.
NSUInteger statusCode = 0;
if ([error.domain isEqualToString:TSNetworkManagerErrorDomain]) {
statusCode = error.code;
} else {
OWSFailDebug(@"Unexpected error: %@", error);
} }
udAuthFailureBlock:^{
// Note the UD auth failure so subsequent retries
// to this recipient also use basic auth.
[messageSend setHasUDAuthFailed];
}
websocketFailureBlock:^{
// Note the websocket failure so subsequent retries
// to this recipient also use REST.
messageSend.hasWebsocketSendFailed = YES;
}
recipientId:recipientId
udAccess:messageSend.udAccess
canFailoverUDAuth:YES];
[[requestMaker makeRequestObjc]
.then(^(OWSRequestMakerResult *result) {
// We _do not_ want to dispatch to the sendingQueue here; we're
// using a semaphore on the sendingQueue to block on this request.
const id responseObject = result.responseObject;
PreKeyBundle *_Nullable bundle =
[PreKeyBundle preKeyBundleFromDictionary:responseObject forDeviceNumber:deviceId];
success(bundle);
})
.catch(^(NSError *error) {
// We _do not_ want to dispatch to the sendingQueue here; we're
// using a semaphore on the sendingQueue to block on this request.
NSUInteger statusCode = 0;
if ([error.domain isEqualToString:TSNetworkManagerErrorDomain]) {
statusCode = error.code;
} else {
OWSFailDebug(@"Unexpected error: %@", error);
}
failure(statusCode); failure(statusCode);
}) retainUntilComplete]; }) retainUntilComplete];
} }
- (nullable NSDictionary *)throws_encryptedFriendRequestOrDeviceLinkMessageForMessageSend:(OWSMessageSend *)messageSend - (nullable NSDictionary *)throws_encryptedFriendRequestOrDeviceLinkMessageForMessageSend:(OWSMessageSend *)messageSend
deviceId:(NSNumber *)deviceId deviceId:(NSNumber *)deviceId
plainText:(NSData *)plainText plainText:(NSData *)plainText
{ {
OWSAssertDebug(messageSend); OWSAssertDebug(messageSend);
OWSAssertDebug(deviceId); OWSAssertDebug(deviceId);
@ -1845,14 +1844,14 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
if ([LKSessionManagementProtocol isSessionRequiredForMessage:messageSend.message] && ![storage containsSession:recipientID deviceId:@(OWSDevicePrimaryDeviceId).intValue protocolContext:transaction]) { if ([LKSessionManagementProtocol isSessionRequiredForMessage:messageSend.message] && ![storage containsSession:recipientID deviceId:@(OWSDevicePrimaryDeviceId).intValue protocolContext:transaction]) {
NSString *missingSessionException = @"missingSessionException"; NSString *missingSessionException = @"missingSessionException";
OWSRaiseException(missingSessionException, OWSRaiseException(missingSessionException,
@"Unexpectedly missing session for recipient: %@, device: %@.", @"Unexpectedly missing session for recipient: %@, device: %@.",
recipientID, recipientID,
@(OWSDevicePrimaryDeviceId)); @(OWSDevicePrimaryDeviceId));
} }
BOOL isFriendRequest = [messageSend.message isKindOfClass:LKFriendRequestMessage.class]; BOOL isFriendRequest = [messageSend.message isKindOfClass:LKFriendRequestMessage.class];
BOOL isDeviceLinkMessage = [messageSend.message isKindOfClass:LKDeviceLinkMessage.class] BOOL isDeviceLinkMessage = [messageSend.message isKindOfClass:LKDeviceLinkMessage.class]
&& ((LKDeviceLinkMessage *)messageSend.message).kind == LKDeviceLinkMessageKindRequest; && ((LKDeviceLinkMessage *)messageSend.message).kind == LKDeviceLinkMessageKindRequest;
SessionCipher *cipher = [[SessionCipher alloc] initWithSessionStore:storage SessionCipher *cipher = [[SessionCipher alloc] initWithSessionStore:storage
preKeyStore:storage preKeyStore:storage
@ -1866,11 +1865,11 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
if (messageSend.isUDSend) { if (messageSend.isUDSend) {
NSError *error; NSError *error;
SMKSecretSessionCipher *_Nullable secretCipher = SMKSecretSessionCipher *_Nullable secretCipher =
[[SMKSecretSessionCipher alloc] initWithSessionStore:self.primaryStorage [[SMKSecretSessionCipher alloc] initWithSessionStore:self.primaryStorage
preKeyStore:self.primaryStorage preKeyStore:self.primaryStorage
signedPreKeyStore:self.primaryStorage signedPreKeyStore:self.primaryStorage
identityStore:self.identityManager identityStore:self.identityManager
error:&error]; error:&error];
if (error || !secretCipher) { if (error || !secretCipher) {
OWSRaiseException(@"SecretSessionCipherFailure", @"Can't create secret session cipher."); OWSRaiseException(@"SecretSessionCipherFailure", @"Can't create secret session cipher.");
} }
@ -1892,7 +1891,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
} else { } else {
// This may throw an exception // This may throw an exception
id<CipherMessage> encryptedMessage = id<CipherMessage> encryptedMessage =
[cipher throws_encryptMessage:[plainText paddedMessageBody] protocolContext:transaction]; [cipher throws_encryptMessage:[plainText paddedMessageBody] protocolContext:transaction];
serializedMessage = encryptedMessage.serialized; serializedMessage = encryptedMessage.serialized;
messageType = [self messageTypeForCipherMessage:encryptedMessage]; messageType = [self messageTypeForCipherMessage:encryptedMessage];
} }
@ -1903,16 +1902,16 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
LKAddressMessage *addressMessage = [message as:[LKAddressMessage class]]; LKAddressMessage *addressMessage = [message as:[LKAddressMessage class]];
BOOL isPing = addressMessage != nil && addressMessage.isPing; BOOL isPing = addressMessage != nil && addressMessage.isPing;
OWSMessageServiceParams *messageParams = OWSMessageServiceParams *messageParams =
[[OWSMessageServiceParams alloc] initWithType:messageType [[OWSMessageServiceParams alloc] initWithType:messageType
recipientId:recipientID recipientId:recipientID
device:@(OWSDevicePrimaryDeviceId).intValue device:@(OWSDevicePrimaryDeviceId).intValue
content:serializedMessage content:serializedMessage
isSilent:isSilent isSilent:isSilent
isOnline:isOnline isOnline:isOnline
registrationId:[cipher throws_remoteRegistrationId:transaction] registrationId:[cipher throws_remoteRegistrationId:transaction]
ttl:message.ttl ttl:message.ttl
isPing:isPing isPing:isPing
isFriendRequest:isFriendRequest || isDeviceLinkMessage]; isFriendRequest:isFriendRequest || isDeviceLinkMessage];
NSError *error; NSError *error;
NSDictionary *jsonDict = [MTLJSONAdapter JSONDictionaryFromModel:messageParams error:&error]; NSDictionary *jsonDict = [MTLJSONAdapter JSONDictionaryFromModel:messageParams error:&error];
@ -2014,7 +2013,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
// suggests this could change. The logic is intended to work with multiple, but // suggests this could change. The logic is intended to work with multiple, but
// if we ever actually want to send multiple, we should do more testing. // if we ever actually want to send multiple, we should do more testing.
NSArray<TSAttachmentStream *> *quotedThumbnailAttachments = NSArray<TSAttachmentStream *> *quotedThumbnailAttachments =
[message.quotedMessage createThumbnailAttachmentsIfNecessaryWithTransaction:transaction]; [message.quotedMessage createThumbnailAttachmentsIfNecessaryWithTransaction:transaction];
for (TSAttachmentStream *attachment in quotedThumbnailAttachments) { for (TSAttachmentStream *attachment in quotedThumbnailAttachments) {
[attachmentIds addObject:attachment.uniqueId]; [attachmentIds addObject:attachment.uniqueId];
} }
@ -2031,7 +2030,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
if (message.linkPreview.imageAttachmentId != nil) { if (message.linkPreview.imageAttachmentId != nil) {
TSAttachment *attachment = TSAttachment *attachment =
[TSAttachment fetchObjectWithUniqueID:message.linkPreview.imageAttachmentId transaction:transaction]; [TSAttachment fetchObjectWithUniqueID:message.linkPreview.imageAttachmentId transaction:transaction];
if ([attachment isKindOfClass:[TSAttachmentStream class]]) { if ([attachment isKindOfClass:[TSAttachmentStream class]]) {
[attachmentIds addObject:attachment.uniqueId]; [attachmentIds addObject:attachment.uniqueId];
} else { } else {
@ -2058,11 +2057,11 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
NSMutableArray<TSAttachmentStream *> *attachmentStreams = [NSMutableArray new]; NSMutableArray<TSAttachmentStream *> *attachmentStreams = [NSMutableArray new];
for (OWSOutgoingAttachmentInfo *attachmentInfo in attachmentInfos) { for (OWSOutgoingAttachmentInfo *attachmentInfo in attachmentInfos) {
TSAttachmentStream *attachmentStream = TSAttachmentStream *attachmentStream =
[[TSAttachmentStream alloc] initWithContentType:attachmentInfo.contentType [[TSAttachmentStream alloc] initWithContentType:attachmentInfo.contentType
byteCount:(UInt32)attachmentInfo.dataSource.dataLength byteCount:(UInt32)attachmentInfo.dataSource.dataLength
sourceFilename:attachmentInfo.sourceFilename sourceFilename:attachmentInfo.sourceFilename
caption:attachmentInfo.caption caption:attachmentInfo.caption
albumMessageId:attachmentInfo.albumMessageId]; albumMessageId:attachmentInfo.albumMessageId];
if (outgoingMessage.isVoiceMessage) { if (outgoingMessage.isVoiceMessage) {
attachmentStream.attachmentType = TSAttachmentTypeVoiceMessage; attachmentStream.attachmentType = TSAttachmentTypeVoiceMessage;

Loading…
Cancel
Save