|
|
|
@ -4,6 +4,7 @@
|
|
|
|
|
|
|
|
|
|
#import "OWSMessageSender.h"
|
|
|
|
|
#import "ContactsUpdater.h"
|
|
|
|
|
#import "NSData+keyVersionByte.h"
|
|
|
|
|
#import "NSData+messagePadding.h"
|
|
|
|
|
#import "OWSBlockingManager.h"
|
|
|
|
|
#import "OWSDevice.h"
|
|
|
|
@ -540,34 +541,6 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)resendMessageFromKeyError:(TSInvalidIdentityKeySendingErrorMessage *)errorMessage
|
|
|
|
|
success:(void (^)())successHandler
|
|
|
|
|
failure:(void (^)(NSError *error))failureHandler
|
|
|
|
|
{
|
|
|
|
|
AssertIsOnMainThread();
|
|
|
|
|
OWSAssert(errorMessage);
|
|
|
|
|
|
|
|
|
|
NSString *failedMessageId = errorMessage.messageId;
|
|
|
|
|
|
|
|
|
|
// Here we remove the existing error message because sending a new message will either
|
|
|
|
|
// 1.) succeed and create a new successful message in the thread or...
|
|
|
|
|
// 2.) fail and create a new identical error message in the thread.
|
|
|
|
|
[errorMessage remove];
|
|
|
|
|
|
|
|
|
|
// The failedMessageId might be nil for transient, unsaved outgoing messages.
|
|
|
|
|
// See [TSOutgoingMessage saveWithTransaction:] for details of which messages
|
|
|
|
|
// we do not save.
|
|
|
|
|
|
|
|
|
|
if (!failedMessageId) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TSOutgoingMessage *message = [TSOutgoingMessage fetchObjectWithUniqueID:failedMessageId];
|
|
|
|
|
OWSAssert(message);
|
|
|
|
|
|
|
|
|
|
return [self sendMessage:message success:successHandler failure:failureHandler];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSArray<SignalRecipient *> *)getRecipients:(NSArray<NSString *> *)identifiers error:(NSError **)error
|
|
|
|
|
{
|
|
|
|
|
NSMutableArray<SignalRecipient *> *recipients = [NSMutableArray new];
|
|
|
|
@ -885,20 +858,47 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
|
|
|
|
} @catch (NSException *exception) {
|
|
|
|
|
deviceMessages = @[];
|
|
|
|
|
if ([exception.name isEqualToString:UntrustedIdentityKeyException]) {
|
|
|
|
|
[[TSInvalidIdentityKeySendingErrorMessage
|
|
|
|
|
untrustedKeyWithOutgoingMessage:message
|
|
|
|
|
inThread:thread
|
|
|
|
|
forRecipient:exception.userInfo[TSInvalidRecipientKey]
|
|
|
|
|
preKeyBundle:exception.userInfo[TSInvalidPreKeyBundleKey]] save];
|
|
|
|
|
// This *can* happen under normal usage, but it should happen relatively rarely.
|
|
|
|
|
// We expect it to happen whenever Bob reinstalls, and Alice messages Bob before
|
|
|
|
|
// she can pull down his latest identity.
|
|
|
|
|
// If it's happening a lot, we should rethink our profile fetching strategy.
|
|
|
|
|
OWSAnalyticsInfo(@"Message send failed due to untrusted key.");
|
|
|
|
|
|
|
|
|
|
NSError *error = OWSErrorWithCodeDescription(OWSErrorCodeUntrustedIdentityKey,
|
|
|
|
|
NSLocalizedString(@"FAILED_SENDING_BECAUSE_UNTRUSTED_IDENTITY_KEY",
|
|
|
|
|
@"action sheet header when re-sending message which failed because of untrusted identity keys"));
|
|
|
|
|
|
|
|
|
|
// Key will continue to be unaccepted, so no need to retry. It'll only cause us to hit the Pre-Key request
|
|
|
|
|
// rate limit
|
|
|
|
|
[error setIsRetryable:NO];
|
|
|
|
|
// Avoid the "Too many failures with this contact" error rate limiting.
|
|
|
|
|
[error setIsFatal:YES];
|
|
|
|
|
return failureHandler(error);
|
|
|
|
|
|
|
|
|
|
PreKeyBundle *newKeyBundle = exception.userInfo[TSInvalidPreKeyBundleKey];
|
|
|
|
|
if (![newKeyBundle isKindOfClass:[PreKeyBundle class]]) {
|
|
|
|
|
OWSFail(@"%@ unexpected TSInvalidPreKeyBundleKey: %@", self.tag, newKeyBundle);
|
|
|
|
|
failureHandler(error);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NSData *newIdentityKeyWithVersion = newKeyBundle.identityKey;
|
|
|
|
|
if (![newIdentityKeyWithVersion isKindOfClass:[NSData class]]) {
|
|
|
|
|
OWSFail(@"%@ unexpected TSInvalidRecipientKey: %@", self.tag, newIdentityKeyWithVersion);
|
|
|
|
|
failureHandler(error);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NSData *newIdentityKey = [newIdentityKeyWithVersion removeKeyType];
|
|
|
|
|
if (newIdentityKey.length != kIdentityKeyLength) {
|
|
|
|
|
OWSFail(@"%@ unexpected key length: %lu", self.tag, (unsigned long)newIdentityKey.length);
|
|
|
|
|
failureHandler(error);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[[OWSIdentityManager sharedManager] saveRemoteIdentity:newIdentityKey recipientId:recipient.recipientId];
|
|
|
|
|
|
|
|
|
|
failureHandler(error);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ([exception.name isEqualToString:OWSMessageSenderRateLimitedException]) {
|
|
|
|
@ -1313,6 +1313,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Called when the server indicates that the devices no longer exist - e.g. when the remote recipient has reinstalled.
|
|
|
|
|
- (void)handleStaleDevicesWithResponse:(NSData *)responseData
|
|
|
|
|
recipientId:(NSString *)identifier
|
|
|
|
|
completion:(void (^)())completionHandler
|
|
|
|
|