Merge branch 'charlesmchen/streamlineSignalRecipient'
This commit is contained in:
commit
3b2ae010d7
@ -127,10 +127,6 @@ public class MessageFetcherJob: NSObject {
|
||||
}
|
||||
builder.setType(type)
|
||||
|
||||
if let relay = messageDict["relay"] as? String {
|
||||
builder.setRelay(relay)
|
||||
}
|
||||
|
||||
guard let timestamp = messageDict["timestamp"] as? UInt64 else {
|
||||
Logger.error("\(self.logTag) message body didn't have timestamp")
|
||||
return nil
|
||||
|
||||
@ -74,7 +74,6 @@
|
||||
#import <SignalServiceKit/OWSPrimaryStorage.h>
|
||||
#import <SignalServiceKit/OWSReadReceiptManager.h>
|
||||
#import <SignalServiceKit/OWSVerificationStateChangeMessage.h>
|
||||
#import <SignalServiceKit/SignalRecipient.h>
|
||||
#import <SignalServiceKit/TSAccountManager.h>
|
||||
#import <SignalServiceKit/TSGroupModel.h>
|
||||
#import <SignalServiceKit/TSInvalidIdentityKeyReceivingErrorMessage.h>
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#import "DebugUIContacts.h"
|
||||
#import "OWSTableViewController.h"
|
||||
#import "Signal-Swift.h"
|
||||
#import "SignalApp.h"
|
||||
#import <Contacts/Contacts.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
@ -50,6 +51,18 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
actionBlock:^{
|
||||
[DebugUIContacts clearSignalAccountCache];
|
||||
}],
|
||||
[OWSTableItem itemWithTitle:@"Clear SignalRecipient Cache"
|
||||
actionBlock:^{
|
||||
[DebugUIContacts clearSignalRecipientCache];
|
||||
}],
|
||||
[OWSTableItem itemWithTitle:@"New Unregistered Contact Thread"
|
||||
actionBlock:^{
|
||||
[DebugUIContacts createUnregisteredContactThread];
|
||||
}],
|
||||
[OWSTableItem itemWithTitle:@"New Unregistered Group Thread"
|
||||
actionBlock:^{
|
||||
[DebugUIContacts createUnregisteredGroupThread];
|
||||
}],
|
||||
]];
|
||||
}
|
||||
|
||||
@ -1290,6 +1303,12 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
[SignalAccount removeAllObjectsInCollection];
|
||||
}
|
||||
|
||||
+ (void)clearSignalRecipientCache
|
||||
{
|
||||
DDLogWarn(@"%@ Deleting all signal recipients.", self.logTag);
|
||||
[SignalRecipient removeAllObjectsInCollection];
|
||||
}
|
||||
|
||||
+ (void)deleteAllContacts
|
||||
{
|
||||
[self deleteContactsWithFilter:^(CNContact *contact) {
|
||||
@ -1304,6 +1323,41 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
}];
|
||||
}
|
||||
|
||||
+ (NSString *)unregisteredRecipientId
|
||||
{
|
||||
// We ensure that the phone number is invalid by appending too many digits.
|
||||
NSMutableString *recipientId = [@"+1" mutableCopy];
|
||||
for (int i = 0; i < 11; i++) {
|
||||
[recipientId appendFormat:@"%d", (int)(arc4random() % 10)];
|
||||
}
|
||||
return [recipientId copy];
|
||||
}
|
||||
|
||||
+ (void)createUnregisteredContactThread
|
||||
{
|
||||
NSString *recipientId = [self unregisteredRecipientId];
|
||||
TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactId:recipientId];
|
||||
[SignalApp.sharedApp presentConversationForThread:thread];
|
||||
}
|
||||
|
||||
+ (void)createUnregisteredGroupThread
|
||||
{
|
||||
NSString *unregisteredRecipientId = [self unregisteredRecipientId];
|
||||
NSString *validRecipientId = @"+19174054216";
|
||||
|
||||
NSString *groupName = @"Partially invalid group";
|
||||
NSMutableArray<NSString *> *recipientIds = [@[
|
||||
unregisteredRecipientId,
|
||||
validRecipientId,
|
||||
[TSAccountManager localNumber],
|
||||
] mutableCopy];
|
||||
NSData *groupId = [SecurityUtils generateRandomBytes:16];
|
||||
TSGroupModel *model =
|
||||
[[TSGroupModel alloc] initWithTitle:groupName memberIds:recipientIds image:nil groupId:groupId];
|
||||
TSGroupThread *thread = [TSGroupThread getOrCreateThreadWithGroupModel:model];
|
||||
[SignalApp.sharedApp presentConversationForThread:thread];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@ -3729,7 +3729,6 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
||||
digest:nil
|
||||
byteCount:filesize
|
||||
contentType:@"audio/mp3"
|
||||
relay:@""
|
||||
sourceFilename:@"test.mp3"
|
||||
attachmentType:TSAttachmentTypeDefault];
|
||||
pointer.state = TSAttachmentPointerStateFailed;
|
||||
@ -4596,7 +4595,6 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
|
||||
digest:nil
|
||||
byteCount:filesize
|
||||
contentType:fakeAssetLoader.mimeType
|
||||
relay:@""
|
||||
sourceFilename:fakeAssetLoader.filename
|
||||
attachmentType:TSAttachmentTypeDefault];
|
||||
attachmentPointer.state = TSAttachmentPointerStateFailed;
|
||||
|
||||
@ -24,8 +24,7 @@
|
||||
ContactsUpdater *contactsUpdater = [ContactsUpdater sharedUpdater];
|
||||
OWSMessageSender *messageSender = [[OWSMessageSender alloc] initWithNetworkManager:networkManager
|
||||
primaryStorage:primaryStorage
|
||||
contactsManager:contactsManager
|
||||
contactsUpdater:contactsUpdater];
|
||||
contactsManager:contactsManager];
|
||||
|
||||
instance = [[Environment alloc] initWithContactsManager:contactsManager
|
||||
contactsUpdater:contactsUpdater
|
||||
|
||||
@ -208,8 +208,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
__block NSMutableArray *result = [NSMutableArray array];
|
||||
|
||||
for (PhoneNumber *number in [self.parsedPhoneNumbers sortedArrayUsingSelector:@selector(compare:)]) {
|
||||
SignalRecipient *signalRecipient =
|
||||
[SignalRecipient recipientWithTextSecureIdentifier:number.toE164 withTransaction:transaction];
|
||||
SignalRecipient *_Nullable signalRecipient =
|
||||
[SignalRecipient registeredRecipientForRecipientId:number.toE164 transaction:transaction];
|
||||
if (signalRecipient) {
|
||||
[result addObject:signalRecipient];
|
||||
}
|
||||
@ -223,7 +223,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
[OWSPrimaryStorage.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
for (PhoneNumber *number in self.parsedPhoneNumbers) {
|
||||
if ([SignalRecipient recipientWithTextSecureIdentifier:number.toE164 withTransaction:transaction]) {
|
||||
if ([SignalRecipient isRegisteredRecipient:number.toE164 transaction:transaction]) {
|
||||
[identifiers addObject:number.toE164];
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SignalRecipient.h"
|
||||
@ -12,8 +12,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
+ (instancetype)sharedUpdater;
|
||||
|
||||
- (nullable SignalRecipient *)synchronousLookup:(NSString *)identifier error:(NSError **)error;
|
||||
|
||||
// This asynchronously tries to verify whether or not a contact id
|
||||
// corresponds to a service account.
|
||||
//
|
||||
|
||||
@ -38,53 +38,27 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return self;
|
||||
}
|
||||
|
||||
- (nullable SignalRecipient *)synchronousLookup:(NSString *)identifier error:(NSError **)error
|
||||
{
|
||||
OWSAssert(error);
|
||||
|
||||
DDLogInfo(@"%@ %s %@", self.logTag, __PRETTY_FUNCTION__, identifier);
|
||||
|
||||
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
|
||||
|
||||
__block SignalRecipient *recipient;
|
||||
|
||||
// Assigning to a pointer parameter within the block is not preventing the referenced error from being dealloc
|
||||
// Instead, we avoid ambiguity in ownership by assigning to a local __block variable ensuring the error will be
|
||||
// retained until our error parameter can take ownership.
|
||||
__block NSError *retainedError;
|
||||
[self lookupIdentifier:identifier
|
||||
success:^(SignalRecipient *fetchedRecipient) {
|
||||
recipient = fetchedRecipient;
|
||||
dispatch_semaphore_signal(sema);
|
||||
}
|
||||
failure:^(NSError *lookupError) {
|
||||
DDLogError(
|
||||
@"%@ Could not find recipient for recipientId: %@, error: %@.", self.logTag, identifier, lookupError);
|
||||
|
||||
retainedError = lookupError;
|
||||
dispatch_semaphore_signal(sema);
|
||||
}];
|
||||
|
||||
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
|
||||
*error = retainedError;
|
||||
return recipient;
|
||||
}
|
||||
|
||||
- (void)lookupIdentifier:(NSString *)identifier
|
||||
- (void)lookupIdentifier:(NSString *)recipientId
|
||||
success:(void (^)(SignalRecipient *recipient))success
|
||||
failure:(void (^)(NSError *error))failure
|
||||
{
|
||||
OWSAssert(recipientId.length > 0);
|
||||
|
||||
// This should never happen according to nullability annotations... but IIRC it does. =/
|
||||
if (!identifier) {
|
||||
if (!recipientId) {
|
||||
OWSFail(@"%@ Cannot lookup nil identifier", self.logTag);
|
||||
failure(OWSErrorWithCodeDescription(OWSErrorCodeInvalidMethodParameters, @"Cannot lookup nil identifier"));
|
||||
return;
|
||||
}
|
||||
|
||||
[self contactIntersectionWithSet:[NSSet setWithObject:identifier]
|
||||
success:^(NSSet<NSString *> *_Nonnull matchedIds) {
|
||||
if (matchedIds.count == 1) {
|
||||
success([SignalRecipient recipientWithTextSecureIdentifier:identifier]);
|
||||
NSSet *recipiendIds = [NSSet setWithObject:recipientId];
|
||||
[self contactIntersectionWithSet:recipiendIds
|
||||
success:^(NSSet<SignalRecipient *> *recipients) {
|
||||
if (recipients.count > 0) {
|
||||
OWSAssert(recipients.count == 1);
|
||||
|
||||
SignalRecipient *recipient = recipients.allObjects.firstObject;
|
||||
success(recipient);
|
||||
} else {
|
||||
failure(OWSErrorMakeNoSuchSignalRecipientError());
|
||||
}
|
||||
@ -103,12 +77,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
}
|
||||
|
||||
[self contactIntersectionWithSet:[NSSet setWithArray:identifiers]
|
||||
success:^(NSSet<NSString *> *_Nonnull matchedIds) {
|
||||
if (matchedIds.count > 0) {
|
||||
NSMutableArray<SignalRecipient *> *recipients = [NSMutableArray new];
|
||||
for (NSString *identifier in matchedIds) {
|
||||
[recipients addObject:[SignalRecipient recipientWithTextSecureIdentifier:identifier]];
|
||||
}
|
||||
success:^(NSSet<SignalRecipient *> *recipients) {
|
||||
if (recipients.count > 0) {
|
||||
success([recipients copy]);
|
||||
} else {
|
||||
failure(OWSErrorMakeNoSuchSignalRecipientError());
|
||||
@ -117,6 +87,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
failure:failure];
|
||||
}
|
||||
|
||||
// TODO: Modify this to support delta lookups.
|
||||
- (void)updateSignalContactIntersectionWithABContacts:(NSArray<Contact *> *)abContacts
|
||||
success:(void (^)(void))success
|
||||
failure:(void (^)(NSError *error))failure
|
||||
@ -130,7 +101,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
}
|
||||
|
||||
NSMutableSet *recipientIds = [NSMutableSet set];
|
||||
[OWSPrimaryStorage.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
[OWSPrimaryStorage.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction * transaction) {
|
||||
// TODO: Don't do this.
|
||||
NSArray *allRecipientKeys = [transaction allKeysInCollection:[SignalRecipient collection]];
|
||||
[recipientIds addObjectsFromArray:allRecipientKeys];
|
||||
}];
|
||||
@ -138,78 +110,70 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
NSMutableSet<NSString *> *allContacts = [[abPhoneNumbers setByAddingObjectsFromSet:recipientIds] mutableCopy];
|
||||
|
||||
[self contactIntersectionWithSet:allContacts
|
||||
success:^(NSSet<NSString *> *matchedIds) {
|
||||
[recipientIds minusSet:matchedIds];
|
||||
|
||||
// Cleaning up unregistered identifiers
|
||||
[OWSPrimaryStorage.dbReadWriteConnection
|
||||
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
for (NSString *identifier in recipientIds) {
|
||||
SignalRecipient *recipient =
|
||||
[SignalRecipient fetchObjectWithUniqueID:identifier
|
||||
transaction:transaction];
|
||||
|
||||
[recipient removeWithTransaction:transaction];
|
||||
}
|
||||
}];
|
||||
|
||||
success:^(NSSet<SignalRecipient *> *recipients) {
|
||||
DDLogInfo(@"%@ successfully intersected contacts.", self.logTag);
|
||||
success();
|
||||
}
|
||||
failure:failure];
|
||||
}
|
||||
|
||||
- (void)contactIntersectionWithSet:(NSSet<NSString *> *)idSet
|
||||
success:(void (^)(NSSet<NSString *> *matchedIds))success
|
||||
- (void)contactIntersectionWithSet:(NSSet<NSString *> *)recipientIdsToLookup
|
||||
success:(void (^)(NSSet<SignalRecipient *> *recipients))success
|
||||
failure:(void (^)(NSError *error))failure {
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
NSMutableDictionary *phoneNumbersByHashes = [NSMutableDictionary dictionary];
|
||||
for (NSString *identifier in idSet) {
|
||||
[phoneNumbersByHashes setObject:identifier
|
||||
forKey:[Cryptography truncatedSHA1Base64EncodedWithoutPadding:identifier]];
|
||||
NSMutableDictionary<NSString *, NSString *> *phoneNumbersByHashes = [NSMutableDictionary new];
|
||||
for (NSString *recipientId in recipientIdsToLookup) {
|
||||
NSString *hash = [Cryptography truncatedSHA1Base64EncodedWithoutPadding:recipientId];
|
||||
phoneNumbersByHashes[hash] = recipientId;
|
||||
}
|
||||
NSArray *hashes = [phoneNumbersByHashes allKeys];
|
||||
|
||||
NSArray<NSString *> *hashes = [phoneNumbersByHashes allKeys];
|
||||
|
||||
TSRequest *request = [OWSRequestFactory contactsIntersectionRequestWithHashesArray:hashes];
|
||||
[[TSNetworkManager sharedManager] makeRequest:request
|
||||
success:^(NSURLSessionDataTask *tsTask, id responseDict) {
|
||||
NSMutableDictionary *attributesForIdentifier = [NSMutableDictionary dictionary];
|
||||
NSArray *contactsArray = [(NSDictionary *)responseDict objectForKey:@"contacts"];
|
||||
|
||||
// Map attributes to phone numbers
|
||||
if (contactsArray) {
|
||||
for (NSDictionary *dict in contactsArray) {
|
||||
NSString *hash = [dict objectForKey:@"token"];
|
||||
NSString *identifier = [phoneNumbersByHashes objectForKey:hash];
|
||||
|
||||
if (!identifier) {
|
||||
DDLogWarn(@"%@ An interesecting hash wasn't found in the mapping.", self.logTag);
|
||||
break;
|
||||
success:^(NSURLSessionDataTask *task, id responseDict) {
|
||||
NSMutableSet<NSString *> *registeredRecipientIds = [NSMutableSet new];
|
||||
|
||||
if ([responseDict isKindOfClass:[NSDictionary class]]) {
|
||||
NSArray<NSDictionary *> *_Nullable contactsArray = responseDict[@"contacts"];
|
||||
if ([contactsArray isKindOfClass:[NSArray class]]) {
|
||||
for (NSDictionary *contactDict in contactsArray) {
|
||||
if (![contactDict isKindOfClass:[NSDictionary class]]) {
|
||||
OWSProdLogAndFail(@"%@ invalid contact dictionary.", self.logTag);
|
||||
continue;
|
||||
}
|
||||
NSString *_Nullable hash = contactDict[@"token"];
|
||||
if (hash.length < 1) {
|
||||
OWSProdLogAndFail(@"%@ contact missing hash.", self.logTag);
|
||||
continue;
|
||||
}
|
||||
NSString *_Nullable recipientId = phoneNumbersByHashes[hash];
|
||||
if (recipientId.length < 1) {
|
||||
OWSProdLogAndFail(@"%@ An intersecting hash wasn't found in the mapping.", self.logTag);
|
||||
continue;
|
||||
}
|
||||
if (![recipientIdsToLookup containsObject:recipientId]) {
|
||||
OWSProdLogAndFail(@"%@ Intersection response included unexpected recipient.", self.logTag);
|
||||
continue;
|
||||
}
|
||||
[registeredRecipientIds addObject:recipientId];
|
||||
}
|
||||
|
||||
[attributesForIdentifier setObject:dict forKey:identifier];
|
||||
}
|
||||
}
|
||||
|
||||
// Insert or update contact attributes
|
||||
[OWSPrimaryStorage.dbReadWriteConnection
|
||||
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
for (NSString *identifier in attributesForIdentifier) {
|
||||
SignalRecipient *recipient = [SignalRecipient recipientWithTextSecureIdentifier:identifier
|
||||
withTransaction:transaction];
|
||||
if (!recipient) {
|
||||
recipient = [[SignalRecipient alloc] initWithTextSecureIdentifier:identifier relay:nil];
|
||||
}
|
||||
|
||||
NSDictionary *attributes = [attributesForIdentifier objectForKey:identifier];
|
||||
|
||||
recipient.relay = attributes[@"relay"];
|
||||
|
||||
[recipient saveWithTransaction:transaction];
|
||||
|
||||
NSMutableSet<SignalRecipient *> *recipients = [NSMutableSet new];
|
||||
[OWSPrimaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
for (NSString *recipientId in recipientIdsToLookup) {
|
||||
if ([registeredRecipientIds containsObject:recipientId]) {
|
||||
SignalRecipient *recipient =
|
||||
[SignalRecipient markRecipientAsRegisteredAndGet:recipientId transaction:transaction];
|
||||
[recipients addObject:recipient];
|
||||
} else {
|
||||
[SignalRecipient removeUnregisteredRecipient:recipientId transaction:transaction];
|
||||
}
|
||||
}];
|
||||
}
|
||||
}];
|
||||
|
||||
success([NSSet setWithArray:attributesForIdentifier.allKeys]);
|
||||
success([recipients copy]);
|
||||
}
|
||||
failure:^(NSURLSessionDataTask *task, NSError *error) {
|
||||
if (!IsNSErrorNetworkFailure(error)) {
|
||||
|
||||
@ -15,7 +15,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
// * Contacts with multiple signal accounts will correspond to
|
||||
// multiple instances of SignalAccount.
|
||||
// * For non-contacts, the contact property will be nil.
|
||||
//
|
||||
@interface SignalAccount : TSYapDatabaseObject
|
||||
|
||||
// An E164 value identifying the signal account.
|
||||
@ -42,11 +41,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
- (instancetype)initWithRecipientId:(NSString *)recipientId;
|
||||
|
||||
// In most cases this should be non-null. This should only
|
||||
// be null in the case where the SignalRecipient was
|
||||
// deleted before this property was accessed.
|
||||
- (nullable SignalRecipient *)signalRecipientWithTransaction:(YapDatabaseReadTransaction *)transaction;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@ -36,15 +36,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return self;
|
||||
}
|
||||
|
||||
- (nullable SignalRecipient *)signalRecipientWithTransaction:(YapDatabaseReadTransaction *)transaction
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
OWSAssert(transaction);
|
||||
|
||||
OWSAssert(self.recipientId.length > 0);
|
||||
return [SignalRecipient recipientWithTextSecureIdentifier:self.recipientId withTransaction:transaction];
|
||||
}
|
||||
|
||||
- (nullable NSString *)uniqueId
|
||||
{
|
||||
return _recipientId;
|
||||
|
||||
@ -6,36 +6,45 @@
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
// SignalRecipient serves two purposes:
|
||||
//
|
||||
// a) It serves as a cache of "known" Signal accounts. When the service indicates
|
||||
// that an account exists, we make sure that an instance of SignalRecipient exists
|
||||
// for that recipient id (using mark as registered).
|
||||
// When the service indicates that an account does not exist, we remove any
|
||||
// SignalRecipient.
|
||||
// b) We hang the "known device list" for known signal accounts on this entity.
|
||||
@interface SignalRecipient : TSYapDatabaseObject
|
||||
|
||||
- (instancetype)initWithTextSecureIdentifier:(NSString *)textSecureIdentifier
|
||||
relay:(nullable NSString *)relay;
|
||||
@property (nonatomic, readonly) NSOrderedSet *devices;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
+ (instancetype)selfRecipient;
|
||||
|
||||
+ (void)ensureRecipientExistsWithRecipientId:(NSString *)recipientId
|
||||
deviceId:(UInt32)deviceId
|
||||
relay:(NSString *)relay
|
||||
+ (nullable instancetype)registeredRecipientForRecipientId:(NSString *)recipientId
|
||||
transaction:(YapDatabaseReadTransaction *)transaction;
|
||||
+ (instancetype)getOrBuildUnsavedRecipientForRecipientId:(NSString *)recipientId
|
||||
transaction:(YapDatabaseReadTransaction *)transaction;
|
||||
|
||||
- (void)addDevicesToRegisteredRecipient:(NSSet *)devices
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
- (void)removeDevicesFromRegisteredRecipient:(NSSet *)devices
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
|
||||
+ (nullable instancetype)recipientWithTextSecureIdentifier:(NSString *)textSecureIdentifier;
|
||||
+ (nullable instancetype)recipientWithTextSecureIdentifier:(NSString *)textSecureIdentifier
|
||||
withTransaction:(YapDatabaseReadTransaction *)transaction;
|
||||
|
||||
@property (readonly) NSOrderedSet *devices;
|
||||
- (void)addDevices:(NSSet *)set;
|
||||
- (void)removeDevices:(NSSet *)set;
|
||||
|
||||
@property (nonatomic, nullable) NSString *relay;
|
||||
|
||||
- (BOOL)supportsVoice;
|
||||
// This property indicates support for both WebRTC audio and video calls.
|
||||
- (BOOL)supportsWebRTC;
|
||||
|
||||
- (NSString *)recipientId;
|
||||
|
||||
- (NSComparisonResult)compare:(SignalRecipient *)other;
|
||||
|
||||
+ (BOOL)isRegisteredRecipient:(NSString *)recipientId transaction:(YapDatabaseReadTransaction *)transaction;
|
||||
|
||||
+ (SignalRecipient *)markRecipientAsRegisteredAndGet:(NSString *)recipientId
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
+ (void)markRecipientAsRegistered:(NSString *)recipientId
|
||||
deviceId:(UInt32)deviceId
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
+ (void)removeUnregisteredRecipient:(NSString *)recipientId transaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
//
|
||||
|
||||
#import "SignalRecipient.h"
|
||||
#import "OWSIdentityManager.h"
|
||||
#import "TSAccountManager.h"
|
||||
#import <YapDatabase/YapDatabaseConnection.h>
|
||||
|
||||
@ -11,47 +10,28 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface SignalRecipient ()
|
||||
|
||||
@property NSOrderedSet *devices;
|
||||
@property (nonatomic) NSOrderedSet *devices;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation SignalRecipient
|
||||
|
||||
+ (NSString *)collection {
|
||||
return @"SignalRecipient";
|
||||
}
|
||||
|
||||
+ (void)ensureRecipientExistsWithRecipientId:(NSString *)recipientId
|
||||
deviceId:(UInt32)deviceId
|
||||
relay:(NSString *)relay
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
+ (instancetype)getOrBuildUnsavedRecipientForRecipientId:(NSString *)recipientId
|
||||
transaction:(YapDatabaseReadTransaction *)transaction
|
||||
{
|
||||
SignalRecipient *_Nullable existingRecipient =
|
||||
[self recipientWithTextSecureIdentifier:recipientId withTransaction:transaction];
|
||||
if (!existingRecipient) {
|
||||
DDLogDebug(
|
||||
@"%@ in %s creating recipient with deviceId: %u", self.logTag, __PRETTY_FUNCTION__, (unsigned int)deviceId);
|
||||
|
||||
SignalRecipient *newRecipient = [[self alloc] initWithTextSecureIdentifier:recipientId relay:relay];
|
||||
[newRecipient addDevices:[NSSet setWithObject:@(deviceId)]];
|
||||
[newRecipient saveWithTransaction:transaction];
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (![existingRecipient.devices containsObject:@(deviceId)]) {
|
||||
DDLogDebug(@"%@ in %s adding device %u to existing recipient.",
|
||||
self.logTag,
|
||||
__PRETTY_FUNCTION__,
|
||||
(unsigned int)deviceId);
|
||||
|
||||
[existingRecipient addDevices:[NSSet setWithObject:@(deviceId)]];
|
||||
[existingRecipient saveWithTransaction:transaction];
|
||||
OWSAssert(transaction);
|
||||
OWSAssert(recipientId.length > 0);
|
||||
|
||||
SignalRecipient *_Nullable recipient = [self registeredRecipientForRecipientId:recipientId transaction:transaction];
|
||||
if (!recipient) {
|
||||
recipient = [[self alloc] initWithTextSecureIdentifier:recipientId];
|
||||
}
|
||||
return recipient;
|
||||
}
|
||||
|
||||
- (instancetype)initWithTextSecureIdentifier:(NSString *)textSecureIdentifier
|
||||
relay:(nullable NSString *)relay
|
||||
{
|
||||
self = [super initWithUniqueId:textSecureIdentifier];
|
||||
if (!self) {
|
||||
@ -75,8 +55,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
_devices = [NSOrderedSet orderedSetWithObject:@(1)];
|
||||
}
|
||||
|
||||
_relay = [relay isEqualToString:@""] ? nil : relay;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@ -98,17 +76,23 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (nullable instancetype)recipientWithTextSecureIdentifier:(NSString *)textSecureIdentifier
|
||||
withTransaction:(YapDatabaseReadTransaction *)transaction
|
||||
|
||||
+ (nullable instancetype)registeredRecipientForRecipientId:(NSString *)recipientId
|
||||
transaction:(YapDatabaseReadTransaction *)transaction
|
||||
{
|
||||
return [self fetchObjectWithUniqueID:textSecureIdentifier transaction:transaction];
|
||||
OWSAssert(transaction);
|
||||
OWSAssert(recipientId.length > 0);
|
||||
|
||||
return [self fetchObjectWithUniqueID:recipientId transaction:transaction];
|
||||
}
|
||||
|
||||
+ (nullable instancetype)recipientWithTextSecureIdentifier:(NSString *)textSecureIdentifier
|
||||
+ (nullable instancetype)recipientForRecipientId:(NSString *)recipientId
|
||||
{
|
||||
OWSAssert(recipientId.length > 0);
|
||||
|
||||
__block SignalRecipient *recipient;
|
||||
[self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
recipient = [self recipientWithTextSecureIdentifier:textSecureIdentifier withTransaction:transaction];
|
||||
[self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
recipient = [self registeredRecipientForRecipientId:recipientId transaction:transaction];
|
||||
}];
|
||||
return recipient;
|
||||
}
|
||||
@ -116,42 +100,72 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
// TODO This method should probably live on the TSAccountManager rather than grabbing a global singleton.
|
||||
+ (instancetype)selfRecipient
|
||||
{
|
||||
SignalRecipient *myself = [self recipientWithTextSecureIdentifier:[TSAccountManager localNumber]];
|
||||
SignalRecipient *myself = [self recipientForRecipientId:[TSAccountManager localNumber]];
|
||||
if (!myself) {
|
||||
myself = [[self alloc] initWithTextSecureIdentifier:[TSAccountManager localNumber] relay:nil];
|
||||
myself = [[self alloc] initWithTextSecureIdentifier:[TSAccountManager localNumber]];
|
||||
}
|
||||
return myself;
|
||||
}
|
||||
|
||||
- (void)addDevices:(NSSet *)set
|
||||
- (void)addDevices:(NSSet *)devices
|
||||
{
|
||||
if ([self.uniqueId isEqual:[TSAccountManager localNumber]] && [set containsObject:@(1)]) {
|
||||
OWSAssert(devices.count > 0);
|
||||
|
||||
if ([self.uniqueId isEqual:[TSAccountManager localNumber]] && [devices containsObject:@(1)]) {
|
||||
OWSFail(@"%@ in %s adding self as recipient device", self.logTag, __PRETTY_FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
NSMutableOrderedSet *updatedDevices = [self.devices mutableCopy];
|
||||
[updatedDevices unionSet:set];
|
||||
|
||||
[updatedDevices unionSet:devices];
|
||||
self.devices = [updatedDevices copy];
|
||||
}
|
||||
|
||||
- (void)removeDevices:(NSSet *)set
|
||||
- (void)removeDevices:(NSSet *)devices
|
||||
{
|
||||
OWSAssert(devices.count > 0);
|
||||
|
||||
NSMutableOrderedSet *updatedDevices = [self.devices mutableCopy];
|
||||
[updatedDevices minusSet:set];
|
||||
|
||||
[updatedDevices minusSet:devices];
|
||||
self.devices = [updatedDevices copy];
|
||||
}
|
||||
|
||||
- (BOOL)supportsVoice
|
||||
- (void)addDevicesToRegisteredRecipient:(NSSet *)devices transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
return YES;
|
||||
OWSAssert(transaction);
|
||||
OWSAssert(devices.count > 0);
|
||||
|
||||
[self addDevices:devices];
|
||||
|
||||
SignalRecipient *latest =
|
||||
[SignalRecipient markRecipientAsRegisteredAndGet:self.recipientId transaction:transaction];
|
||||
|
||||
if ([devices isSubsetOfSet:latest.devices.set]) {
|
||||
return;
|
||||
}
|
||||
DDLogDebug(@"%@ adding devices: %@, to recipient: %@", self.logTag, devices, latest.recipientId);
|
||||
|
||||
[latest addDevices:devices];
|
||||
[latest saveWithTransaction_internal:transaction];
|
||||
}
|
||||
|
||||
- (BOOL)supportsWebRTC
|
||||
- (void)removeDevicesFromRegisteredRecipient:(NSSet *)devices transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
return YES;
|
||||
OWSAssert(transaction);
|
||||
OWSAssert(devices.count > 0);
|
||||
|
||||
[self removeDevices:devices];
|
||||
|
||||
SignalRecipient *latest =
|
||||
[SignalRecipient markRecipientAsRegisteredAndGet:self.recipientId transaction:transaction];
|
||||
|
||||
if (![devices isSubsetOfSet:latest.devices.set]) {
|
||||
return;
|
||||
}
|
||||
DDLogDebug(@"%@ removing devices: %@, from recipient: %@", self.logTag, devices, latest.recipientId);
|
||||
|
||||
[latest removeDevices:devices];
|
||||
[latest saveWithTransaction_internal:transaction];
|
||||
}
|
||||
|
||||
- (NSString *)recipientId
|
||||
@ -165,12 +179,80 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
}
|
||||
|
||||
- (void)saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
// We only want to mutate the persisted SignalRecipients in the database
|
||||
// using other methods of this class, e.g. markRecipientAsRegistered...
|
||||
// to create, addDevices and removeDevices to mutate. We're trying to
|
||||
// be strict about using persisted SignalRecipients as a cache to
|
||||
// reflect "last known registration status". Forcing our codebase to
|
||||
// use those methods helps ensure that we update the cache deliberately.
|
||||
OWSProdLogAndFail(@"%@ Don't call saveWithTransaction from outside this class.", self.logTag);
|
||||
|
||||
[self saveWithTransaction_internal:transaction];
|
||||
}
|
||||
|
||||
- (void)saveWithTransaction_internal:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
[super saveWithTransaction:transaction];
|
||||
|
||||
DDLogVerbose(@"%@ saved signal recipient: %@", self.logTag, self.recipientId);
|
||||
}
|
||||
|
||||
+ (BOOL)isRegisteredRecipient:(NSString *)recipientId transaction:(YapDatabaseReadTransaction *)transaction
|
||||
{
|
||||
SignalRecipient *_Nullable instance = [self registeredRecipientForRecipientId:recipientId transaction:transaction];
|
||||
return instance != nil;
|
||||
}
|
||||
|
||||
+ (SignalRecipient *)markRecipientAsRegisteredAndGet:(NSString *)recipientId
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
OWSAssert(transaction);
|
||||
OWSAssert(recipientId.length > 0);
|
||||
|
||||
SignalRecipient *_Nullable instance = [self registeredRecipientForRecipientId:recipientId transaction:transaction];
|
||||
|
||||
if (!instance) {
|
||||
DDLogDebug(@"%@ creating recipient: %@", self.logTag, recipientId);
|
||||
|
||||
instance = [[self alloc] initWithTextSecureIdentifier:recipientId];
|
||||
[instance saveWithTransaction_internal:transaction];
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
+ (void)markRecipientAsRegistered:(NSString *)recipientId
|
||||
deviceId:(UInt32)deviceId
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
OWSAssert(transaction);
|
||||
OWSAssert(recipientId.length > 0);
|
||||
|
||||
SignalRecipient *recipient = [self markRecipientAsRegisteredAndGet:recipientId transaction:transaction];
|
||||
if (![recipient.devices containsObject:@(deviceId)]) {
|
||||
DDLogDebug(@"%@ in %s adding device %u to existing recipient.",
|
||||
self.logTag,
|
||||
__PRETTY_FUNCTION__,
|
||||
(unsigned int)deviceId);
|
||||
|
||||
[recipient addDevices:[NSSet setWithObject:@(deviceId)]];
|
||||
[recipient saveWithTransaction_internal:transaction];
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)removeUnregisteredRecipient:(NSString *)recipientId transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
OWSAssert(transaction);
|
||||
OWSAssert(recipientId.length > 0);
|
||||
|
||||
SignalRecipient *_Nullable instance = [self registeredRecipientForRecipientId:recipientId transaction:transaction];
|
||||
if (!instance) {
|
||||
return;
|
||||
}
|
||||
DDLogDebug(@"%@ removing recipient: %@", self.logTag, recipientId);
|
||||
[instance removeWithTransaction:transaction];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@ -15,10 +15,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
+ (instancetype)getOrCreateThreadWithContactId:(NSString *)contactId
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
|
||||
+ (instancetype)getOrCreateThreadWithContactId:(NSString *)contactId
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
relay:(nullable NSString *)relay;
|
||||
|
||||
// Unlike getOrCreateThreadWithContactId, this will _NOT_ create a thread if one does not already exist.
|
||||
+ (nullable instancetype)getThreadWithContactId:(NSString *)contactId transaction:(YapDatabaseReadTransaction *)transaction;
|
||||
|
||||
|
||||
@ -27,35 +27,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (instancetype)getOrCreateThreadWithContactId:(NSString *)contactId
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
relay:(nullable NSString *)relay
|
||||
{
|
||||
OWSAssert(contactId.length > 0);
|
||||
|
||||
SignalRecipient *recipient =
|
||||
[SignalRecipient recipientWithTextSecureIdentifier:contactId withTransaction:transaction];
|
||||
|
||||
if (!recipient) {
|
||||
// If no recipient record exists for that contactId, create an empty record
|
||||
// for immediate use, then ask ContactsUpdater to try to update it async.
|
||||
recipient =
|
||||
[[SignalRecipient alloc] initWithTextSecureIdentifier:contactId
|
||||
relay:relay];
|
||||
[recipient saveWithTransaction:transaction];
|
||||
|
||||
// Update recipient with Server record async.
|
||||
[[ContactsUpdater sharedUpdater] lookupIdentifier:contactId
|
||||
success:^(SignalRecipient *recipient) {
|
||||
}
|
||||
failure:^(NSError *error) {
|
||||
DDLogWarn(@"Failed to lookup contact with error:%@", error);
|
||||
}];
|
||||
}
|
||||
|
||||
return [self getOrCreateThreadWithContactId:contactId transaction:transaction];
|
||||
}
|
||||
|
||||
+ (instancetype)getOrCreateThreadWithContactId:(NSString *)contactId
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction {
|
||||
OWSAssert(contactId.length > 0);
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
|
||||
#import "TSGroupThread.h"
|
||||
#import "NSData+Base64.h"
|
||||
#import "SignalRecipient.h"
|
||||
#import "TSAttachmentStream.h"
|
||||
#import <SignalServiceKit/TSAccountManager.h>
|
||||
#import <YapDatabase/YapDatabaseConnection.h>
|
||||
|
||||
@ -80,7 +80,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
OWSAttachmentsProcessor *attachmentsProcessor =
|
||||
[[OWSAttachmentsProcessor alloc] initWithAttachmentProtos:transcript.attachmentPointerProtos
|
||||
relay:transcript.relay
|
||||
networkManager:self.networkManager
|
||||
transaction:transaction];
|
||||
|
||||
|
||||
@ -30,7 +30,6 @@ extern NSString *const kAttachmentDownloadAttachmentIDKey;
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
- (instancetype)initWithAttachmentProtos:(NSArray<OWSSignalServiceProtosAttachmentPointer *> *)attachmentProtos
|
||||
relay:(nullable NSString *)relay
|
||||
networkManager:(TSNetworkManager *)networkManager
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
|
||||
@ -57,7 +57,6 @@ static const CGFloat kAttachmentDownloadProgressTheta = 0.001f;
|
||||
}
|
||||
|
||||
- (instancetype)initWithAttachmentProtos:(NSArray<OWSSignalServiceProtosAttachmentPointer *> *)attachmentProtos
|
||||
relay:(nullable NSString *)relay
|
||||
networkManager:(TSNetworkManager *)networkManager
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
@ -72,7 +71,7 @@ static const CGFloat kAttachmentDownloadProgressTheta = 0.001f;
|
||||
NSMutableArray<TSAttachmentPointer *> *attachmentPointers = [NSMutableArray new];
|
||||
|
||||
for (OWSSignalServiceProtosAttachmentPointer *attachmentProto in attachmentProtos) {
|
||||
TSAttachmentPointer *pointer = [TSAttachmentPointer attachmentPointerFromProto:attachmentProto relay:relay];
|
||||
TSAttachmentPointer *pointer = [TSAttachmentPointer attachmentPointerFromProto:attachmentProto];
|
||||
|
||||
[attachmentIds addObject:pointer.uniqueId];
|
||||
[pointer saveWithTransaction:transaction];
|
||||
@ -152,8 +151,7 @@ static const CGFloat kAttachmentDownloadProgressTheta = 0.001f;
|
||||
if (attachment.serverId < 100) {
|
||||
DDLogError(@"%@ Suspicious attachment id: %llu", self.logTag, (unsigned long long)attachment.serverId);
|
||||
}
|
||||
TSRequest *request =
|
||||
[OWSRequestFactory attachmentRequestWithAttachmentId:attachment.serverId relay:attachment.relay];
|
||||
TSRequest *request = [OWSRequestFactory attachmentRequestWithAttachmentId:attachment.serverId];
|
||||
|
||||
[self.networkManager makeRequest:request
|
||||
success:^(NSURLSessionDataTask *task, id responseObject) {
|
||||
|
||||
@ -25,14 +25,11 @@ typedef NS_ENUM(NSUInteger, TSAttachmentPointerState) {
|
||||
digest:(nullable NSData *)digest
|
||||
byteCount:(UInt32)byteCount
|
||||
contentType:(NSString *)contentType
|
||||
relay:(NSString *)relay
|
||||
sourceFilename:(nullable NSString *)sourceFilename
|
||||
attachmentType:(TSAttachmentType)attachmentType NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
+ (TSAttachmentPointer *)attachmentPointerFromProto:(OWSSignalServiceProtosAttachmentPointer *)attachmentProto
|
||||
relay:(NSString *_Nullable)relay;
|
||||
+ (TSAttachmentPointer *)attachmentPointerFromProto:(OWSSignalServiceProtosAttachmentPointer *)attachmentProto;
|
||||
|
||||
@property (nonatomic, readonly) NSString *relay;
|
||||
@property (atomic) TSAttachmentPointerState state;
|
||||
@property (nullable, atomic) NSString *mostRecentFailureLocalizedText;
|
||||
|
||||
|
||||
@ -30,7 +30,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
digest:(nullable NSData *)digest
|
||||
byteCount:(UInt32)byteCount
|
||||
contentType:(NSString *)contentType
|
||||
relay:(NSString *)relay
|
||||
sourceFilename:(nullable NSString *)sourceFilename
|
||||
attachmentType:(TSAttachmentType)attachmentType
|
||||
{
|
||||
@ -45,7 +44,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
_digest = digest;
|
||||
_state = TSAttachmentPointerStateEnqueued;
|
||||
_relay = relay;
|
||||
self.attachmentType = attachmentType;
|
||||
|
||||
return self;
|
||||
@ -53,7 +51,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
|
||||
+ (TSAttachmentPointer *)attachmentPointerFromProto:(OWSSignalServiceProtosAttachmentPointer *)attachmentProto
|
||||
relay:(NSString *_Nullable)relay
|
||||
{
|
||||
OWSAssert(attachmentProto.id != 0);
|
||||
OWSAssert(attachmentProto.key != nil);
|
||||
@ -75,7 +72,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
digest:digest
|
||||
byteCount:attachmentProto.size
|
||||
contentType:attachmentProto.contentType
|
||||
relay:relay
|
||||
sourceFilename:attachmentProto.fileName
|
||||
attachmentType:attachmentType];
|
||||
return pointer;
|
||||
|
||||
@ -19,10 +19,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@interface OWSIncomingSentMessageTranscript : NSObject
|
||||
|
||||
- (instancetype)initWithProto:(OWSSignalServiceProtosSyncMessageSent *)sentProto
|
||||
relay:(nullable NSString *)relay
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
|
||||
@property (nonatomic, readonly) NSString *relay;
|
||||
@property (nonatomic, readonly) OWSSignalServiceProtosDataMessage *dataMessage;
|
||||
@property (nonatomic, readonly) NSString *recipientId;
|
||||
@property (nonatomic, readonly) uint64_t timestamp;
|
||||
|
||||
@ -19,7 +19,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@implementation OWSIncomingSentMessageTranscript
|
||||
|
||||
- (instancetype)initWithProto:(OWSSignalServiceProtosSyncMessageSent *)sentProto
|
||||
relay:(nullable NSString *)relay
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
self = [super init];
|
||||
@ -27,7 +26,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return self;
|
||||
}
|
||||
|
||||
_relay = relay;
|
||||
_dataMessage = sentProto.message;
|
||||
_recipientId = sentProto.destination;
|
||||
_timestamp = sentProto.timestamp;
|
||||
@ -45,9 +43,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
_thread = [TSContactThread getOrCreateThreadWithContactId:_recipientId transaction:transaction];
|
||||
}
|
||||
|
||||
_quotedMessage =
|
||||
[TSQuotedMessage quotedMessageForDataMessage:_dataMessage thread:_thread relay:relay transaction:transaction];
|
||||
_contact = [OWSContacts contactForDataMessage:_dataMessage relay:relay transaction:transaction];
|
||||
_quotedMessage = [TSQuotedMessage quotedMessageForDataMessage:_dataMessage thread:_thread transaction:transaction];
|
||||
_contact = [OWSContacts contactForDataMessage:_dataMessage transaction:transaction];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@ -10,7 +10,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@class CNContact;
|
||||
@class OWSAttachmentInfo;
|
||||
@class OWSSignalServiceProtosDataMessage;
|
||||
@class OWSSignalServiceProtosDataMessage;
|
||||
@class OWSSignalServiceProtosDataMessageContact;
|
||||
@class TSAttachment;
|
||||
@class TSAttachmentStream;
|
||||
@ -177,7 +176,6 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value);
|
||||
+ (nullable OWSSignalServiceProtosDataMessageContact *)protoForContact:(OWSContact *)contact;
|
||||
|
||||
+ (nullable OWSContact *)contactForDataMessage:(OWSSignalServiceProtosDataMessage *)dataMessage
|
||||
relay:(nullable NSString *)relay
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
|
||||
@end
|
||||
|
||||
@ -893,7 +893,6 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value)
|
||||
}
|
||||
|
||||
+ (nullable OWSContact *)contactForDataMessage:(OWSSignalServiceProtosDataMessage *)dataMessage
|
||||
relay:(nullable NSString *)relay
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
OWSAssert(dataMessage);
|
||||
@ -968,8 +967,7 @@ NSString *NSStringForContactAddressType(OWSContactAddressType value)
|
||||
if (avatarInfo.hasAvatar) {
|
||||
OWSSignalServiceProtosAttachmentPointer *avatarAttachment = avatarInfo.avatar;
|
||||
|
||||
TSAttachmentPointer *attachmentPointer =
|
||||
[TSAttachmentPointer attachmentPointerFromProto:avatarAttachment relay:relay];
|
||||
TSAttachmentPointer *attachmentPointer = [TSAttachmentPointer attachmentPointerFromProto:avatarAttachment];
|
||||
[attachmentPointer saveWithTransaction:transaction];
|
||||
|
||||
contact.avatarAttachmentId = attachmentPointer.uniqueId;
|
||||
|
||||
@ -92,7 +92,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
+ (nullable instancetype)quotedMessageForDataMessage:(OWSSignalServiceProtosDataMessage *)dataMessage
|
||||
thread:(TSThread *)thread
|
||||
relay:(nullable NSString *)relay
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction;
|
||||
|
||||
@end
|
||||
|
||||
@ -105,7 +105,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
+ (TSQuotedMessage *_Nullable)quotedMessageForDataMessage:(OWSSignalServiceProtosDataMessage *)dataMessage
|
||||
thread:(TSThread *)thread
|
||||
relay:(nullable NSString *)relay
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
OWSAssert(dataMessage);
|
||||
@ -169,7 +168,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
OWSSignalServiceProtosAttachmentPointer *thumbnailAttachmentProto = quotedAttachment.thumbnail;
|
||||
TSAttachmentPointer *thumbnailPointer =
|
||||
[TSAttachmentPointer attachmentPointerFromProto:thumbnailAttachmentProto relay:relay];
|
||||
[TSAttachmentPointer attachmentPointerFromProto:thumbnailAttachmentProto];
|
||||
[thumbnailPointer saveWithTransaction:transaction];
|
||||
|
||||
attachmentInfo.thumbnailAttachmentPointerId = thumbnailPointer.uniqueId;
|
||||
|
||||
@ -8,7 +8,6 @@
|
||||
#import "OWSPrimaryStorage+SessionStore.h"
|
||||
#import "OWSPrimaryStorage.h"
|
||||
#import "PreKeyBundle+jsonDict.h"
|
||||
#import "SignalRecipient.h"
|
||||
#import "TSContactThread.h"
|
||||
#import "TSErrorMessage_privateConstructor.h"
|
||||
#import "TSOutgoingMessage.h"
|
||||
|
||||
@ -110,10 +110,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
DecryptSuccessBlock successBlock
|
||||
= ^(NSData *_Nullable plaintextData, YapDatabaseReadWriteTransaction *transaction) {
|
||||
[SignalRecipient ensureRecipientExistsWithRecipientId:envelope.source
|
||||
deviceId:envelope.sourceDevice
|
||||
relay:envelope.relay
|
||||
transaction:transaction];
|
||||
[SignalRecipient markRecipientAsRegistered:envelope.source
|
||||
deviceId:envelope.sourceDevice
|
||||
transaction:transaction];
|
||||
|
||||
successBlockParameter(plaintextData, transaction);
|
||||
};
|
||||
|
||||
@ -516,7 +516,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
OWSAssert(groupThread);
|
||||
OWSAttachmentsProcessor *attachmentsProcessor =
|
||||
[[OWSAttachmentsProcessor alloc] initWithAttachmentProtos:@[ dataMessage.group.avatar ]
|
||||
relay:envelope.relay
|
||||
networkManager:self.networkManager
|
||||
transaction:transaction];
|
||||
|
||||
@ -553,7 +552,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
OWSAttachmentsProcessor *attachmentsProcessor =
|
||||
[[OWSAttachmentsProcessor alloc] initWithAttachmentProtos:dataMessage.attachments
|
||||
relay:envelope.relay
|
||||
networkManager:self.networkManager
|
||||
transaction:transaction];
|
||||
if (!attachmentsProcessor.hasSupportedAttachments) {
|
||||
@ -605,7 +603,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
if (syncMessage.hasSent) {
|
||||
OWSIncomingSentMessageTranscript *transcript =
|
||||
[[OWSIncomingSentMessageTranscript alloc] initWithProto:syncMessage.sent
|
||||
relay:envelope.relay
|
||||
transaction:transaction];
|
||||
|
||||
OWSRecordTranscriptJob *recordJob =
|
||||
@ -916,8 +913,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
uint64_t timestamp = envelope.timestamp;
|
||||
NSString *body = dataMessage.body;
|
||||
NSData *groupId = dataMessage.hasGroup ? dataMessage.group.id : nil;
|
||||
OWSContact *_Nullable contact =
|
||||
[OWSContacts contactForDataMessage:dataMessage relay:envelope.relay transaction:transaction];
|
||||
OWSContact *_Nullable contact = [OWSContacts contactForDataMessage:dataMessage transaction:transaction];
|
||||
|
||||
if (dataMessage.group.type == OWSSignalServiceProtosGroupContextTypeRequestInfo) {
|
||||
[self handleGroupInfoRequest:envelope dataMessage:dataMessage transaction:transaction];
|
||||
@ -1016,7 +1012,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
TSQuotedMessage *_Nullable quotedMessage = [TSQuotedMessage quotedMessageForDataMessage:dataMessage
|
||||
thread:oldGroupThread
|
||||
relay:envelope.relay
|
||||
transaction:transaction];
|
||||
|
||||
DDLogDebug(@"%@ incoming message from: %@ for group: %@ with timestamp: %lu",
|
||||
@ -1060,13 +1055,11 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
self.logTag,
|
||||
envelopeAddress(envelope),
|
||||
(unsigned long)timestamp);
|
||||
TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactId:envelope.source
|
||||
transaction:transaction
|
||||
relay:envelope.relay];
|
||||
TSContactThread *thread =
|
||||
[TSContactThread getOrCreateThreadWithContactId:envelope.source transaction:transaction];
|
||||
|
||||
TSQuotedMessage *_Nullable quotedMessage = [TSQuotedMessage quotedMessageForDataMessage:dataMessage
|
||||
thread:thread
|
||||
relay:envelope.relay
|
||||
transaction:transaction];
|
||||
|
||||
TSIncomingMessage *incomingMessage =
|
||||
|
||||
@ -8,11 +8,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
extern const NSUInteger kOversizeTextMessageSizeThreshold;
|
||||
|
||||
@class ContactsUpdater;
|
||||
@class OWSBlockingManager;
|
||||
@class OWSPrimaryStorage;
|
||||
@class OWSUploadingService;
|
||||
@class SignalRecipient;
|
||||
@class TSInvalidIdentityKeySendingErrorMessage;
|
||||
@class TSNetworkManager;
|
||||
@class TSOutgoingMessage;
|
||||
@ -42,15 +40,13 @@ NS_SWIFT_NAME(MessageSender)
|
||||
|
||||
// For subclassing in tests
|
||||
OWSUploadingService *_uploadingService;
|
||||
ContactsUpdater *_contactsUpdater;
|
||||
}
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
- (instancetype)initWithNetworkManager:(TSNetworkManager *)networkManager
|
||||
primaryStorage:(OWSPrimaryStorage *)primaryStorage
|
||||
contactsManager:(id<ContactsManagerProtocol>)contactsManager
|
||||
contactsUpdater:(ContactsUpdater *)contactsUpdater;
|
||||
contactsManager:(id<ContactsManagerProtocol>)contactsManager;
|
||||
|
||||
- (void)setBlockingManager:(OWSBlockingManager *)blockingManager;
|
||||
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
|
||||
#import "OWSMessageSender.h"
|
||||
#import "AppContext.h"
|
||||
#import "ContactsUpdater.h"
|
||||
#import "NSData+keyVersionByte.h"
|
||||
#import "NSData+messagePadding.h"
|
||||
#import "NSDate+OWS.h"
|
||||
@ -78,7 +77,7 @@ void AssertIsOnSendingQueue()
|
||||
messageSender:(OWSMessageSender *)messageSender
|
||||
dbConnection:(YapDatabaseConnection *)dbConnection
|
||||
success:(void (^)(void))aSuccessHandler
|
||||
failure:(void (^)(NSError *_Nonnull error))aFailureHandler NS_DESIGNATED_INITIALIZER;
|
||||
failure:(void (^)(NSError * error))aFailureHandler NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
|
||||
@ -100,7 +99,7 @@ void AssertIsOnSendingQueue()
|
||||
@property (nonatomic, readonly) OWSMessageSender *messageSender;
|
||||
@property (nonatomic, readonly) YapDatabaseConnection *dbConnection;
|
||||
@property (nonatomic, readonly) void (^successHandler)(void);
|
||||
@property (nonatomic, readonly) void (^failureHandler)(NSError *_Nonnull error);
|
||||
@property (nonatomic, readonly) void (^failureHandler)(NSError * error);
|
||||
|
||||
@end
|
||||
|
||||
@ -112,7 +111,7 @@ void AssertIsOnSendingQueue()
|
||||
messageSender:(OWSMessageSender *)messageSender
|
||||
dbConnection:(YapDatabaseConnection *)dbConnection
|
||||
success:(void (^)(void))successHandler
|
||||
failure:(void (^)(NSError *_Nonnull error))failureHandler
|
||||
failure:(void (^)(NSError * error))failureHandler
|
||||
{
|
||||
self = [super init];
|
||||
if (!self) {
|
||||
@ -152,7 +151,7 @@ void AssertIsOnSendingQueue()
|
||||
|
||||
// Sanity check preconditions
|
||||
if (self.message.hasAttachments) {
|
||||
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction * transaction) {
|
||||
TSAttachmentStream *attachmentStream
|
||||
= (TSAttachmentStream *)[self.message attachmentWithTransaction:transaction];
|
||||
OWSAssert(attachmentStream);
|
||||
@ -216,7 +215,6 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
||||
@property (nonatomic, readonly) OWSBlockingManager *blockingManager;
|
||||
@property (nonatomic, readonly) YapDatabaseConnection *dbConnection;
|
||||
@property (nonatomic, readonly) id<ContactsManagerProtocol> contactsManager;
|
||||
@property (nonatomic, readonly) ContactsUpdater *contactsUpdater;
|
||||
@property (atomic, readonly) NSMutableDictionary<NSString *, NSOperationQueue *> *sendingQueueMap;
|
||||
|
||||
@end
|
||||
@ -226,7 +224,6 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
||||
- (instancetype)initWithNetworkManager:(TSNetworkManager *)networkManager
|
||||
primaryStorage:(OWSPrimaryStorage *)primaryStorage
|
||||
contactsManager:(id<ContactsManagerProtocol>)contactsManager
|
||||
contactsUpdater:(ContactsUpdater *)contactsUpdater
|
||||
{
|
||||
self = [super init];
|
||||
if (!self) {
|
||||
@ -236,7 +233,6 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
||||
_networkManager = networkManager;
|
||||
_primaryStorage = primaryStorage;
|
||||
_contactsManager = contactsManager;
|
||||
_contactsUpdater = contactsUpdater;
|
||||
_sendingQueueMap = [NSMutableDictionary new];
|
||||
_dbConnection = primaryStorage.newDatabaseConnection;
|
||||
|
||||
@ -451,42 +447,19 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
||||
|
||||
- (NSArray<SignalRecipient *> *)signalRecipientsForRecipientIds:(NSArray<NSString *> *)recipientIds
|
||||
message:(TSOutgoingMessage *)message
|
||||
error:(NSError **)error
|
||||
{
|
||||
OWSAssert(recipientIds);
|
||||
OWSAssert(message);
|
||||
OWSAssert(error);
|
||||
|
||||
*error = nil;
|
||||
|
||||
NSMutableArray<SignalRecipient *> *recipients = [NSMutableArray new];
|
||||
|
||||
for (NSString *recipientId in recipientIds) {
|
||||
SignalRecipient *existingRecipient = [SignalRecipient recipientWithTextSecureIdentifier:recipientId];
|
||||
|
||||
if (existingRecipient) {
|
||||
[recipients addObject:existingRecipient];
|
||||
} else {
|
||||
SignalRecipient *newRecipient = [self.contactsUpdater synchronousLookup:recipientId error:error];
|
||||
if (newRecipient) {
|
||||
[recipients addObject:newRecipient];
|
||||
} else {
|
||||
DDLogWarn(@"%@ No SignalRecipient for recipientId: %@", self.logTag, recipientId);
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
// Mark this recipient as "skipped".
|
||||
[message updateWithSkippedRecipient:recipientId transaction:transaction];
|
||||
}];
|
||||
}
|
||||
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
for (NSString *recipientId in recipientIds) {
|
||||
SignalRecipient *recipient =
|
||||
[SignalRecipient getOrBuildUnsavedRecipientForRecipientId:recipientId transaction:transaction];
|
||||
[recipients addObject:recipient];
|
||||
}
|
||||
}
|
||||
|
||||
if (recipients.count == 0 && !*error) {
|
||||
// error should be set in contactsUpater, but just in case.
|
||||
OWSProdError([OWSAnalyticsEvents messageSenderErrorCouldNotFindContacts1]);
|
||||
*error = OWSErrorMakeFailedToSendOutgoingMessageError();
|
||||
}
|
||||
|
||||
return [recipients copy];
|
||||
}];
|
||||
return recipients;
|
||||
}
|
||||
|
||||
- (void)sendMessageToService:(TSOutgoingMessage *)message
|
||||
@ -553,20 +526,9 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
||||
return;
|
||||
}
|
||||
|
||||
NSError *error;
|
||||
NSArray<SignalRecipient *> *recipients =
|
||||
[self signalRecipientsForRecipientIds:sendingRecipientIds.allObjects message:message error:&error];
|
||||
|
||||
if (recipients.count == 0) {
|
||||
if (!error) {
|
||||
OWSProdError([OWSAnalyticsEvents messageSenderErrorCouldNotFindContacts2]);
|
||||
error = OWSErrorMakeFailedToSendOutgoingMessageError();
|
||||
}
|
||||
// If no recipients were found, there's no reason to retry. It will just fail again.
|
||||
[error setIsRetryable:NO];
|
||||
failureHandler(error);
|
||||
return;
|
||||
}
|
||||
[self signalRecipientsForRecipientIds:sendingRecipientIds.allObjects message:message];
|
||||
OWSAssert(recipients.count == sendingRecipientIds.count);
|
||||
|
||||
[self groupSend:recipients message:message thread:gThread success:successHandler failure:failureHandler];
|
||||
|
||||
@ -593,26 +555,10 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
||||
return;
|
||||
}
|
||||
|
||||
SignalRecipient *recipient = [SignalRecipient recipientWithTextSecureIdentifier:recipientContactId];
|
||||
if (!recipient) {
|
||||
NSError *error;
|
||||
// possibly returns nil.
|
||||
recipient = [self.contactsUpdater synchronousLookup:recipientContactId error:&error];
|
||||
|
||||
if (error) {
|
||||
if (error.code == OWSErrorCodeNoSuchSignalRecipient) {
|
||||
DDLogWarn(@"%@ recipient contact not found", self.logTag);
|
||||
[self unregisteredRecipient:recipient message:message thread:thread];
|
||||
}
|
||||
|
||||
OWSProdError([OWSAnalyticsEvents messageSenderErrorCouldNotFindContacts3]);
|
||||
// No need to repeat trying to find a failure. Apart from repeatedly failing, it would also cause us
|
||||
// to print redundant error messages.
|
||||
[error setIsRetryable:NO];
|
||||
failureHandler(error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
NSArray<SignalRecipient *> *recipients =
|
||||
[self signalRecipientsForRecipientIds:@[recipientContactId] message:message];
|
||||
OWSAssert(recipients.count == 1);
|
||||
SignalRecipient *recipient = recipients.firstObject;
|
||||
|
||||
if (!recipient) {
|
||||
NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError();
|
||||
@ -759,15 +705,24 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
||||
message:(TSOutgoingMessage *)message
|
||||
thread:(TSThread *)thread
|
||||
{
|
||||
[self.dbConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
if (thread.isGroupThread) {
|
||||
// Mark as "skipped" group members who no longer have signal accounts.
|
||||
[message updateWithSkippedRecipient:recipient.recipientId transaction:transaction];
|
||||
}
|
||||
|
||||
[recipient removeWithTransaction:transaction];
|
||||
if (![SignalRecipient isRegisteredRecipient:recipient.recipientId transaction:transaction]) {
|
||||
return;
|
||||
}
|
||||
|
||||
[SignalRecipient removeUnregisteredRecipient:recipient.recipientId transaction:transaction];
|
||||
|
||||
[[TSInfoMessage userNotRegisteredMessageInThread:thread recipientId:recipient.recipientId]
|
||||
saveWithTransaction:transaction];
|
||||
|
||||
// TODO: Should we deleteAllSessionsForContact here?
|
||||
// If so, we'll need to avoid doing a prekey fetch every
|
||||
// time we try to send a message to an unregistered user.
|
||||
}];
|
||||
}
|
||||
|
||||
@ -779,6 +734,8 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
||||
success:(void (^)(void))successHandler
|
||||
failure:(RetryableFailureHandler)failureHandler
|
||||
{
|
||||
OWSAssert(message);
|
||||
OWSAssert(recipient);
|
||||
OWSAssert(thread || [message isKindOfClass:[OWSOutgoingSyncMessage class]]);
|
||||
|
||||
DDLogInfo(@"%@ attempting to send message: %@, timestamp: %llu, recipient: %@",
|
||||
@ -821,7 +778,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
||||
|
||||
NSArray<NSDictionary *> *deviceMessages;
|
||||
@try {
|
||||
deviceMessages = [self deviceMessages:message forRecipient:recipient];
|
||||
deviceMessages = [self deviceMessages:message recipient:recipient];
|
||||
} @catch (NSException *exception) {
|
||||
deviceMessages = @[];
|
||||
if ([exception.name isEqualToString:UntrustedIdentityKeyException]) {
|
||||
@ -943,7 +900,6 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
||||
// This emulates the completion logic of an actual successful save (see below).
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[message updateWithSkippedRecipient:localNumber transaction:transaction];
|
||||
[recipient saveWithTransaction:transaction];
|
||||
}];
|
||||
successHandler();
|
||||
});
|
||||
@ -967,6 +923,9 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
||||
// * The first (after upgrading?) time we send a sync message to our linked devices.
|
||||
// * After unlinking all linked devices.
|
||||
// * After trying and failing to link a device.
|
||||
// * The first time we send a message to a user, if they don't have their
|
||||
// default device. For example, if they have unregistered
|
||||
// their primary but still have a linked device. Or later, when they re-register.
|
||||
//
|
||||
// When we're not sure if we have linked devices, we need to try
|
||||
// to send self-sync messages even if they have no device messages
|
||||
@ -977,7 +936,6 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
||||
|
||||
TSRequest *request = [OWSRequestFactory submitMessageRequestWithRecipient:recipient.uniqueId
|
||||
messages:deviceMessages
|
||||
relay:recipient.relay
|
||||
timeStamp:message.timestamp];
|
||||
if (useWebsocketIfAvailable && TSSocketManager.canMakeRequests) {
|
||||
[TSSocketManager.sharedManager makeRequest:request
|
||||
@ -1061,8 +1019,11 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
||||
|
||||
dispatch_async([OWSDispatch sendingQueue], ^{
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[recipient saveWithTransaction:transaction];
|
||||
[message updateWithSentRecipient:recipient.uniqueId transaction:transaction];
|
||||
|
||||
// If we've just delivered a message to a user, we know they
|
||||
// have a valid Signal account.
|
||||
[SignalRecipient markRecipientAsRegisteredAndGet:recipient.recipientId transaction:transaction];
|
||||
}];
|
||||
|
||||
[self handleMessageSentLocally:message];
|
||||
@ -1112,6 +1073,25 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
||||
});
|
||||
};
|
||||
|
||||
void (^handle404)(void) = ^{
|
||||
DDLogWarn(@"%@ Unregistered recipient: %@", self.logTag, recipient.uniqueId);
|
||||
|
||||
OWSAssert(thread);
|
||||
|
||||
dispatch_async([OWSDispatch sendingQueue], ^{
|
||||
[self unregisteredRecipient:recipient message:message thread:thread];
|
||||
|
||||
NSError *error = OWSErrorMakeNoSuchSignalRecipientError();
|
||||
// No need to retry if the recipient is not registered.
|
||||
[error setIsRetryable:NO];
|
||||
// If one member of a group deletes their account,
|
||||
// the group should ignore errors when trying to send
|
||||
// messages to this ex-member.
|
||||
[error setShouldBeIgnoredForGroups:YES];
|
||||
failureHandler(error);
|
||||
});
|
||||
};
|
||||
|
||||
switch (statusCode) {
|
||||
case 401: {
|
||||
DDLogWarn(@"%@ Unable to send due to invalid credentials. Did the user's client get de-authed by "
|
||||
@ -1125,22 +1105,15 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
||||
return failureHandler(error);
|
||||
}
|
||||
case 404: {
|
||||
DDLogWarn(@"%@ Unregistered recipient: %@", self.logTag, recipient.uniqueId);
|
||||
|
||||
OWSAssert(thread);
|
||||
[self unregisteredRecipient:recipient message:message thread:thread];
|
||||
NSError *error = OWSErrorMakeNoSuchSignalRecipientError();
|
||||
// No need to retry if the recipient is not registered.
|
||||
[error setIsRetryable:NO];
|
||||
// If one member of a group deletes their account,
|
||||
// the group should ignore errors when trying to send
|
||||
// messages to this ex-member.
|
||||
[error setShouldBeIgnoredForGroups:YES];
|
||||
return failureHandler(error);
|
||||
handle404();
|
||||
return;
|
||||
}
|
||||
case 409: {
|
||||
// Mismatched devices
|
||||
DDLogWarn(@"%@ Mismatched devices for recipient: %@", self.logTag, recipient.uniqueId);
|
||||
DDLogWarn(@"%@ Mismatched devices for recipient: %@ (%zd)",
|
||||
self.logTag,
|
||||
recipient.uniqueId,
|
||||
deviceMessages.count);
|
||||
|
||||
NSError *_Nullable error = nil;
|
||||
NSDictionary *_Nullable responseJson = nil;
|
||||
@ -1153,6 +1126,13 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
||||
return failureHandler(error);
|
||||
}
|
||||
|
||||
NSNumber *_Nullable errorCode = responseJson[@"code"];
|
||||
if ([@(404) isEqual:errorCode]) {
|
||||
// Some 404s are returned as 409.
|
||||
handle404();
|
||||
return;
|
||||
}
|
||||
|
||||
[self handleMismatchedDevicesWithResponseJson:responseJson recipient:recipient completion:retrySend];
|
||||
break;
|
||||
}
|
||||
@ -1200,7 +1180,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
||||
}
|
||||
|
||||
[self.dbConnection
|
||||
asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
|
||||
asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction * transaction) {
|
||||
if (extraDevices.count < 1 && missingDevices.count < 1) {
|
||||
OWSProdFail([OWSAnalyticsEvents messageSenderErrorNoMissingOrExtraDevices]);
|
||||
}
|
||||
@ -1213,16 +1193,16 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
||||
protocolContext:transaction];
|
||||
}
|
||||
|
||||
[recipient removeDevices:[NSSet setWithArray:extraDevices]];
|
||||
[recipient removeDevicesFromRegisteredRecipient:[NSSet setWithArray:extraDevices]
|
||||
transaction:transaction];
|
||||
}
|
||||
|
||||
if (missingDevices && missingDevices.count > 0) {
|
||||
DDLogInfo(@"%@ Adding missing devices: %@", self.logTag, missingDevices);
|
||||
[recipient addDevices:[NSSet setWithArray:missingDevices]];
|
||||
[recipient addDevicesToRegisteredRecipient:[NSSet setWithArray:missingDevices]
|
||||
transaction:transaction];
|
||||
}
|
||||
|
||||
[recipient saveWithTransaction:transaction];
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
completionHandler();
|
||||
});
|
||||
@ -1270,8 +1250,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
||||
}];
|
||||
}
|
||||
|
||||
- (NSArray<NSDictionary *> *)deviceMessages:(TSOutgoingMessage *)message
|
||||
forRecipient:(SignalRecipient *)recipient
|
||||
- (NSArray<NSDictionary *> *)deviceMessages:(TSOutgoingMessage *)message recipient:(SignalRecipient *)recipient
|
||||
{
|
||||
OWSAssert(message);
|
||||
OWSAssert(recipient);
|
||||
@ -1292,7 +1271,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
||||
readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
@try {
|
||||
messageDict = [self encryptedMessageWithPlaintext:plainText
|
||||
toRecipient:recipient.uniqueId
|
||||
recipient:recipient
|
||||
deviceId:deviceNumber
|
||||
keyingStorage:self.primaryStorage
|
||||
isSilent:message.isSilent
|
||||
@ -1314,7 +1293,11 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
||||
}
|
||||
} @catch (NSException *exception) {
|
||||
if ([exception.name isEqualToString:OWSMessageSenderInvalidDeviceException]) {
|
||||
[recipient removeDevices:[NSSet setWithObject:deviceNumber]];
|
||||
[self.dbConnection
|
||||
asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction * transaction) {
|
||||
[recipient removeDevicesFromRegisteredRecipient:[NSSet setWithObject:deviceNumber]
|
||||
transaction:transaction];
|
||||
}];
|
||||
} else {
|
||||
@throw exception;
|
||||
}
|
||||
@ -1325,18 +1308,21 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
||||
}
|
||||
|
||||
- (NSDictionary *)encryptedMessageWithPlaintext:(NSData *)plainText
|
||||
toRecipient:(NSString *)identifier
|
||||
recipient:(SignalRecipient *)recipient
|
||||
deviceId:(NSNumber *)deviceNumber
|
||||
keyingStorage:(OWSPrimaryStorage *)storage
|
||||
isSilent:(BOOL)isSilent
|
||||
transaction:(YapDatabaseReadWriteTransaction *)transaction
|
||||
{
|
||||
OWSAssert(plainText);
|
||||
OWSAssert(identifier.length > 0);
|
||||
OWSAssert(recipient);
|
||||
OWSAssert(deviceNumber);
|
||||
OWSAssert(storage);
|
||||
OWSAssert(transaction);
|
||||
|
||||
NSString *identifier = recipient.recipientId;
|
||||
OWSAssert(identifier.length > 0);
|
||||
|
||||
if (![storage containsSession:identifier deviceId:[deviceNumber intValue] protocolContext:transaction]) {
|
||||
__block dispatch_semaphore_t sema = dispatch_semaphore_create(0);
|
||||
__block PreKeyBundle *_Nullable bundle;
|
||||
@ -1360,6 +1346,9 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
||||
DDLogError(@"Server replied to PreKeyBundle request with error: %@", error);
|
||||
NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response;
|
||||
if (response.statusCode == 404) {
|
||||
[recipient removeDevicesFromRegisteredRecipient:[NSSet setWithObject:deviceNumber]
|
||||
transaction:transaction];
|
||||
|
||||
// Can't throw exception from within callback as it's probabably a different thread.
|
||||
exception = [NSException exceptionWithName:OWSMessageSenderInvalidDeviceException
|
||||
reason:@"Device not registered"
|
||||
|
||||
@ -37,7 +37,7 @@ typedef NS_ENUM(NSUInteger, TSVerificationTransport) { TSVerificationTransportVo
|
||||
|
||||
+ (TSRequest *)allocAttachmentRequest;
|
||||
|
||||
+ (TSRequest *)attachmentRequestWithAttachmentId:(UInt64)attachmentId relay:(nullable NSString *)relay;
|
||||
+ (TSRequest *)attachmentRequestWithAttachmentId:(UInt64)attachmentId;
|
||||
|
||||
+ (TSRequest *)availablePreKeysCountRequest;
|
||||
|
||||
@ -60,7 +60,6 @@ typedef NS_ENUM(NSUInteger, TSVerificationTransport) { TSVerificationTransportVo
|
||||
|
||||
+ (TSRequest *)submitMessageRequestWithRecipient:(NSString *)recipientId
|
||||
messages:(NSArray *)messages
|
||||
relay:(nullable NSString *)relay
|
||||
timeStamp:(uint64_t)timeStamp;
|
||||
|
||||
+ (TSRequest *)registerSignedPrekeyRequestWithSignedPreKeyRecord:(SignedPreKeyRecord *)signedPreKey;
|
||||
|
||||
@ -101,17 +101,12 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"GET" parameters:@{}];
|
||||
}
|
||||
|
||||
+ (TSRequest *)attachmentRequestWithAttachmentId:(UInt64)attachmentId relay:(nullable NSString *)relay
|
||||
+ (TSRequest *)attachmentRequestWithAttachmentId:(UInt64)attachmentId
|
||||
{
|
||||
OWSAssert(attachmentId > 0);
|
||||
|
||||
NSString *path = [NSString stringWithFormat:@"%@/%llu", textSecureAttachmentsAPI, attachmentId];
|
||||
|
||||
// TODO: Should this be in the parameters?
|
||||
if (relay.length > 0) {
|
||||
path = [path stringByAppendingFormat:@"?relay=%@", relay];
|
||||
}
|
||||
|
||||
return [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"GET" parameters:@{}];
|
||||
}
|
||||
|
||||
@ -211,7 +206,6 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
+ (TSRequest *)submitMessageRequestWithRecipient:(NSString *)recipientId
|
||||
messages:(NSArray *)messages
|
||||
relay:(nullable NSString *)relay
|
||||
timeStamp:(uint64_t)timeStamp
|
||||
{
|
||||
// NOTE: messages may be empty; See comments in OWSDeviceManager.
|
||||
@ -219,14 +213,11 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
OWSAssert(timeStamp > 0);
|
||||
|
||||
NSString *path = [textSecureMessagesAPI stringByAppendingString:recipientId];
|
||||
NSMutableDictionary *parameters = [@{
|
||||
NSDictionary *parameters = @{
|
||||
@"messages" : messages,
|
||||
@"timestamp" : @(timeStamp),
|
||||
} mutableCopy];
|
||||
};
|
||||
|
||||
if (relay) {
|
||||
parameters[@"relay"] = relay;
|
||||
}
|
||||
return [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"PUT" parameters:parameters];
|
||||
}
|
||||
|
||||
|
||||
@ -222,6 +222,7 @@ typedef void (^failureBlock)(NSURLSessionDataTask *task, NSError *error);
|
||||
break;
|
||||
}
|
||||
case 417: {
|
||||
// TODO: Is this response code obsolete?
|
||||
DDLogWarn(@"The number is already registered on a relay. Please unregister there first: %@", request);
|
||||
failureBlock(task,
|
||||
[self errorWithHTTPCode:statusCode
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Cryptography.h"
|
||||
#import "ProfileManagerProtocol.h"
|
||||
#import "ProtoBuf+OWS.h"
|
||||
#import "SignalRecipient.h"
|
||||
#import "TSThread.h"
|
||||
#import "TextSecureKitEnv.h"
|
||||
#import "Cryptography.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user