From d14f764b500742c741c3ac5a58474a94d331f2d5 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Fri, 13 Jul 2018 14:03:28 -0400 Subject: [PATCH 01/14] Streamline SignalRecipient. --- Signal/src/Jobs/MessageFetcherJob.swift | 4 - .../ConversationViewController.m | 1 - .../ViewControllers/DebugUI/DebugUIMessages.m | 2 - SignalMessaging/environment/Release.m | 3 +- .../src/Contacts/ContactsUpdater.h | 4 +- .../src/Contacts/ContactsUpdater.m | 58 ++----------- SignalServiceKit/src/Contacts/SignalAccount.h | 1 - .../src/Contacts/SignalRecipient.h | 24 +++--- .../src/Contacts/SignalRecipient.m | 44 +++++----- .../src/Contacts/Threads/TSContactThread.h | 4 - .../src/Contacts/Threads/TSContactThread.m | 32 +------- .../src/Contacts/Threads/TSGroupThread.m | 1 - .../src/Devices/OWSRecordTranscriptJob.m | 1 - .../Attachments/OWSAttachmentsProcessor.h | 1 - .../Attachments/OWSAttachmentsProcessor.m | 6 +- .../Attachments/TSAttachmentPointer.h | 5 +- .../Attachments/TSAttachmentPointer.m | 4 - .../OWSIncomingSentMessageTranscript.h | 2 - .../OWSIncomingSentMessageTranscript.m | 7 +- .../src/Messages/Interactions/OWSContact.h | 2 - .../src/Messages/Interactions/OWSContact.m | 4 +- .../Messages/Interactions/TSQuotedMessage.h | 1 - .../Messages/Interactions/TSQuotedMessage.m | 3 +- .../TSInvalidIdentityKeySendingErrorMessage.m | 1 - .../src/Messages/OWSMessageDecrypter.m | 1 - .../src/Messages/OWSMessageManager.m | 13 +-- .../src/Messages/OWSMessageSender.h | 6 +- .../src/Messages/OWSMessageSender.m | 82 ++++--------------- .../Network/API/Requests/OWSRequestFactory.h | 3 +- .../Network/API/Requests/OWSRequestFactory.m | 15 +--- .../src/Network/API/TSNetworkManager.m | 1 + SignalServiceKit/src/Protocols/ProtoBuf+OWS.m | 5 +- 32 files changed, 85 insertions(+), 256 deletions(-) diff --git a/Signal/src/Jobs/MessageFetcherJob.swift b/Signal/src/Jobs/MessageFetcherJob.swift index 52ae389d34..37c68eba0b 100644 --- a/Signal/src/Jobs/MessageFetcherJob.swift +++ b/Signal/src/Jobs/MessageFetcherJob.swift @@ -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 diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index 8a1f71ab02..c3e8f4eda8 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -74,7 +74,6 @@ #import #import #import -#import #import #import #import diff --git a/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m b/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m index 9a1ded4422..2241d9d2d8 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m +++ b/Signal/src/ViewControllers/DebugUI/DebugUIMessages.m @@ -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; diff --git a/SignalMessaging/environment/Release.m b/SignalMessaging/environment/Release.m index 210408b6bb..0824d04284 100644 --- a/SignalMessaging/environment/Release.m +++ b/SignalMessaging/environment/Release.m @@ -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 diff --git a/SignalServiceKit/src/Contacts/ContactsUpdater.h b/SignalServiceKit/src/Contacts/ContactsUpdater.h index 8ede7a4940..a686db1789 100644 --- a/SignalServiceKit/src/Contacts/ContactsUpdater.h +++ b/SignalServiceKit/src/Contacts/ContactsUpdater.h @@ -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. // diff --git a/SignalServiceKit/src/Contacts/ContactsUpdater.m b/SignalServiceKit/src/Contacts/ContactsUpdater.m index 8d972f7c02..6c0e9cc637 100644 --- a/SignalServiceKit/src/Contacts/ContactsUpdater.m +++ b/SignalServiceKit/src/Contacts/ContactsUpdater.m @@ -38,38 +38,6 @@ 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 success:(void (^)(SignalRecipient *recipient))success failure:(void (^)(NSError *error))failure @@ -173,7 +141,7 @@ NS_ASSUME_NONNULL_BEGIN TSRequest *request = [OWSRequestFactory contactsIntersectionRequestWithHashesArray:hashes]; [[TSNetworkManager sharedManager] makeRequest:request success:^(NSURLSessionDataTask *tsTask, id responseDict) { - NSMutableDictionary *attributesForIdentifier = [NSMutableDictionary dictionary]; + NSMutableSet *identifiers = [NSMutableSet new]; NSArray *contactsArray = [(NSDictionary *)responseDict objectForKey:@"contacts"]; // Map attributes to phone numbers @@ -182,34 +150,26 @@ NS_ASSUME_NONNULL_BEGIN NSString *hash = [dict objectForKey:@"token"]; NSString *identifier = [phoneNumbersByHashes objectForKey:hash]; - if (!identifier) { + if (identifier.length < 1) { DDLogWarn(@"%@ An interesecting hash wasn't found in the mapping.", self.logTag); - break; + continue; } - [attributesForIdentifier setObject:dict forKey:identifier]; + [identifiers addObject:identifier]; } } // Insert or update contact attributes + // + // TODO: Do we need to _eagerly_ ensure a SignalRecipient instance exists? [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]; + for (NSString *identifier in identifiers) { + [SignalRecipient ensureRecipientExistsWithRecipientId:identifier transaction:transaction]; } }]; - success([NSSet setWithArray:attributesForIdentifier.allKeys]); + success([identifiers copy]); } failure:^(NSURLSessionDataTask *task, NSError *error) { if (!IsNSErrorNetworkFailure(error)) { diff --git a/SignalServiceKit/src/Contacts/SignalAccount.h b/SignalServiceKit/src/Contacts/SignalAccount.h index 7f61c7b30a..e2345c5158 100644 --- a/SignalServiceKit/src/Contacts/SignalAccount.h +++ b/SignalServiceKit/src/Contacts/SignalAccount.h @@ -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. diff --git a/SignalServiceKit/src/Contacts/SignalRecipient.h b/SignalServiceKit/src/Contacts/SignalRecipient.h index d9e6aa9a21..8e9896b7e6 100644 --- a/SignalServiceKit/src/Contacts/SignalRecipient.h +++ b/SignalServiceKit/src/Contacts/SignalRecipient.h @@ -6,32 +6,36 @@ NS_ASSUME_NONNULL_BEGIN +// This class serves two purposes: +// +// * We only _persist_ SignalRecipient instances when we know +// that it corresponds to an account on the Signal service. +// So SignalRecipient serves as a defacto cache of "known +// Signal users." +// * We hang the "known device list" for signal accounts on +// this entity. @interface SignalRecipient : TSYapDatabaseObject -- (instancetype)initWithTextSecureIdentifier:(NSString *)textSecureIdentifier - relay:(nullable NSString *)relay; +@property (readonly) NSOrderedSet *devices; + +- (instancetype)init NS_UNAVAILABLE; + (instancetype)selfRecipient; ++ (SignalRecipient *)ensureRecipientExistsWithRecipientId:(NSString *)recipientId + transaction:(YapDatabaseReadWriteTransaction *)transaction; + + (void)ensureRecipientExistsWithRecipientId:(NSString *)recipientId deviceId:(UInt32)deviceId - relay:(NSString *)relay 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; diff --git a/SignalServiceKit/src/Contacts/SignalRecipient.m b/SignalServiceKit/src/Contacts/SignalRecipient.m index 55d8003f2b..351e74f9e0 100644 --- a/SignalServiceKit/src/Contacts/SignalRecipient.m +++ b/SignalServiceKit/src/Contacts/SignalRecipient.m @@ -3,7 +3,6 @@ // #import "SignalRecipient.h" -#import "OWSIdentityManager.h" #import "TSAccountManager.h" #import @@ -15,24 +14,44 @@ NS_ASSUME_NONNULL_BEGIN @end +#pragma mark - + @implementation SignalRecipient + (NSString *)collection { return @"SignalRecipient"; } ++ (SignalRecipient *)ensureRecipientExistsWithRecipientId:(NSString *)recipientId + transaction:(YapDatabaseReadWriteTransaction *)transaction +{ + SignalRecipient *_Nullable recipient = + [self recipientWithTextSecureIdentifier:recipientId withTransaction:transaction]; + if (recipient) { + return recipient; + } + + DDLogDebug(@"%@ creating recipient: %@", self.logTag, recipientId); + + recipient = [[self alloc] initWithTextSecureIdentifier:recipientId]; + [recipient saveWithTransaction:transaction]; + return recipient; +} + + (void)ensureRecipientExistsWithRecipientId:(NSString *)recipientId deviceId:(UInt32)deviceId - relay:(NSString *)relay transaction:(YapDatabaseReadWriteTransaction *)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); + DDLogDebug(@"%@ in %s creating recipient: %@, with deviceId: %u", + self.logTag, + __PRETTY_FUNCTION__, + recipientId, + (unsigned int)deviceId); - SignalRecipient *newRecipient = [[self alloc] initWithTextSecureIdentifier:recipientId relay:relay]; + SignalRecipient *newRecipient = [[self alloc] initWithTextSecureIdentifier:recipientId]; [newRecipient addDevices:[NSSet setWithObject:@(deviceId)]]; [newRecipient saveWithTransaction:transaction]; @@ -51,7 +70,6 @@ NS_ASSUME_NONNULL_BEGIN } - (instancetype)initWithTextSecureIdentifier:(NSString *)textSecureIdentifier - relay:(nullable NSString *)relay { self = [super initWithUniqueId:textSecureIdentifier]; if (!self) { @@ -75,8 +93,6 @@ NS_ASSUME_NONNULL_BEGIN _devices = [NSOrderedSet orderedSetWithObject:@(1)]; } - _relay = [relay isEqualToString:@""] ? nil : relay; - return self; } @@ -118,7 +134,7 @@ NS_ASSUME_NONNULL_BEGIN { SignalRecipient *myself = [self recipientWithTextSecureIdentifier:[TSAccountManager localNumber]]; if (!myself) { - myself = [[self alloc] initWithTextSecureIdentifier:[TSAccountManager localNumber] relay:nil]; + myself = [[self alloc] initWithTextSecureIdentifier:[TSAccountManager localNumber]]; } return myself; } @@ -144,16 +160,6 @@ NS_ASSUME_NONNULL_BEGIN self.devices = [updatedDevices copy]; } -- (BOOL)supportsVoice -{ - return YES; -} - -- (BOOL)supportsWebRTC -{ - return YES; -} - - (NSString *)recipientId { return self.uniqueId; diff --git a/SignalServiceKit/src/Contacts/Threads/TSContactThread.h b/SignalServiceKit/src/Contacts/Threads/TSContactThread.h index 0c28b19b23..c0ac5c256e 100644 --- a/SignalServiceKit/src/Contacts/Threads/TSContactThread.h +++ b/SignalServiceKit/src/Contacts/Threads/TSContactThread.h @@ -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; diff --git a/SignalServiceKit/src/Contacts/Threads/TSContactThread.m b/SignalServiceKit/src/Contacts/Threads/TSContactThread.m index 1fbf3dc362..d6bd281a62 100644 --- a/SignalServiceKit/src/Contacts/Threads/TSContactThread.m +++ b/SignalServiceKit/src/Contacts/Threads/TSContactThread.m @@ -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); @@ -68,6 +39,9 @@ NS_ASSUME_NONNULL_BEGIN [thread saveWithTransaction:transaction]; } + // TODO: Do we need to _eagerly_ ensure a SignalRecipient instance exists? + [SignalRecipient ensureRecipientExistsWithRecipientId:contactId transaction:transaction]; + return thread; } diff --git a/SignalServiceKit/src/Contacts/Threads/TSGroupThread.m b/SignalServiceKit/src/Contacts/Threads/TSGroupThread.m index be7f092001..13341b9cd9 100644 --- a/SignalServiceKit/src/Contacts/Threads/TSGroupThread.m +++ b/SignalServiceKit/src/Contacts/Threads/TSGroupThread.m @@ -4,7 +4,6 @@ #import "TSGroupThread.h" #import "NSData+Base64.h" -#import "SignalRecipient.h" #import "TSAttachmentStream.h" #import #import diff --git a/SignalServiceKit/src/Devices/OWSRecordTranscriptJob.m b/SignalServiceKit/src/Devices/OWSRecordTranscriptJob.m index 64f20b1b45..4dc206bacc 100644 --- a/SignalServiceKit/src/Devices/OWSRecordTranscriptJob.m +++ b/SignalServiceKit/src/Devices/OWSRecordTranscriptJob.m @@ -80,7 +80,6 @@ NS_ASSUME_NONNULL_BEGIN OWSAttachmentsProcessor *attachmentsProcessor = [[OWSAttachmentsProcessor alloc] initWithAttachmentProtos:transcript.attachmentPointerProtos - relay:transcript.relay networkManager:self.networkManager transaction:transaction]; diff --git a/SignalServiceKit/src/Messages/Attachments/OWSAttachmentsProcessor.h b/SignalServiceKit/src/Messages/Attachments/OWSAttachmentsProcessor.h index b1a8b19c55..361aa96760 100644 --- a/SignalServiceKit/src/Messages/Attachments/OWSAttachmentsProcessor.h +++ b/SignalServiceKit/src/Messages/Attachments/OWSAttachmentsProcessor.h @@ -30,7 +30,6 @@ extern NSString *const kAttachmentDownloadAttachmentIDKey; - (instancetype)init NS_UNAVAILABLE; - (instancetype)initWithAttachmentProtos:(NSArray *)attachmentProtos - relay:(nullable NSString *)relay networkManager:(TSNetworkManager *)networkManager transaction:(YapDatabaseReadWriteTransaction *)transaction NS_DESIGNATED_INITIALIZER; diff --git a/SignalServiceKit/src/Messages/Attachments/OWSAttachmentsProcessor.m b/SignalServiceKit/src/Messages/Attachments/OWSAttachmentsProcessor.m index 0e1132786a..980fc56359 100644 --- a/SignalServiceKit/src/Messages/Attachments/OWSAttachmentsProcessor.m +++ b/SignalServiceKit/src/Messages/Attachments/OWSAttachmentsProcessor.m @@ -57,7 +57,6 @@ static const CGFloat kAttachmentDownloadProgressTheta = 0.001f; } - (instancetype)initWithAttachmentProtos:(NSArray *)attachmentProtos - relay:(nullable NSString *)relay networkManager:(TSNetworkManager *)networkManager transaction:(YapDatabaseReadWriteTransaction *)transaction { @@ -72,7 +71,7 @@ static const CGFloat kAttachmentDownloadProgressTheta = 0.001f; NSMutableArray *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) { diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.h b/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.h index ddd96cad7f..9920d68134 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.h +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.h @@ -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; diff --git a/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.m b/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.m index b1fbcead20..00a61c68db 100644 --- a/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.m +++ b/SignalServiceKit/src/Messages/Attachments/TSAttachmentPointer.m @@ -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; diff --git a/SignalServiceKit/src/Messages/DeviceSyncing/OWSIncomingSentMessageTranscript.h b/SignalServiceKit/src/Messages/DeviceSyncing/OWSIncomingSentMessageTranscript.h index 93e3b43175..a6b9d3737f 100644 --- a/SignalServiceKit/src/Messages/DeviceSyncing/OWSIncomingSentMessageTranscript.h +++ b/SignalServiceKit/src/Messages/DeviceSyncing/OWSIncomingSentMessageTranscript.h @@ -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; diff --git a/SignalServiceKit/src/Messages/DeviceSyncing/OWSIncomingSentMessageTranscript.m b/SignalServiceKit/src/Messages/DeviceSyncing/OWSIncomingSentMessageTranscript.m index 01490fc492..333fd0dad3 100644 --- a/SignalServiceKit/src/Messages/DeviceSyncing/OWSIncomingSentMessageTranscript.m +++ b/SignalServiceKit/src/Messages/DeviceSyncing/OWSIncomingSentMessageTranscript.m @@ -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; } diff --git a/SignalServiceKit/src/Messages/Interactions/OWSContact.h b/SignalServiceKit/src/Messages/Interactions/OWSContact.h index 7dfc2ed869..254436f39e 100644 --- a/SignalServiceKit/src/Messages/Interactions/OWSContact.h +++ b/SignalServiceKit/src/Messages/Interactions/OWSContact.h @@ -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 diff --git a/SignalServiceKit/src/Messages/Interactions/OWSContact.m b/SignalServiceKit/src/Messages/Interactions/OWSContact.m index a05c514b8a..b105602f1c 100644 --- a/SignalServiceKit/src/Messages/Interactions/OWSContact.m +++ b/SignalServiceKit/src/Messages/Interactions/OWSContact.m @@ -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; diff --git a/SignalServiceKit/src/Messages/Interactions/TSQuotedMessage.h b/SignalServiceKit/src/Messages/Interactions/TSQuotedMessage.h index 202f8f1ec5..49d973fecb 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSQuotedMessage.h +++ b/SignalServiceKit/src/Messages/Interactions/TSQuotedMessage.h @@ -92,7 +92,6 @@ NS_ASSUME_NONNULL_BEGIN + (nullable instancetype)quotedMessageForDataMessage:(OWSSignalServiceProtosDataMessage *)dataMessage thread:(TSThread *)thread - relay:(nullable NSString *)relay transaction:(YapDatabaseReadWriteTransaction *)transaction; @end diff --git a/SignalServiceKit/src/Messages/Interactions/TSQuotedMessage.m b/SignalServiceKit/src/Messages/Interactions/TSQuotedMessage.m index a846b5e6a6..4dc7881e0f 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSQuotedMessage.m +++ b/SignalServiceKit/src/Messages/Interactions/TSQuotedMessage.m @@ -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; diff --git a/SignalServiceKit/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeySendingErrorMessage.m b/SignalServiceKit/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeySendingErrorMessage.m index c1cdd29838..4dd0a17649 100644 --- a/SignalServiceKit/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeySendingErrorMessage.m +++ b/SignalServiceKit/src/Messages/InvalidKeyMessages/TSInvalidIdentityKeySendingErrorMessage.m @@ -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" diff --git a/SignalServiceKit/src/Messages/OWSMessageDecrypter.m b/SignalServiceKit/src/Messages/OWSMessageDecrypter.m index 001b3aa4c2..fca8303ea2 100644 --- a/SignalServiceKit/src/Messages/OWSMessageDecrypter.m +++ b/SignalServiceKit/src/Messages/OWSMessageDecrypter.m @@ -112,7 +112,6 @@ NS_ASSUME_NONNULL_BEGIN = ^(NSData *_Nullable plaintextData, YapDatabaseReadWriteTransaction *transaction) { [SignalRecipient ensureRecipientExistsWithRecipientId:envelope.source deviceId:envelope.sourceDevice - relay:envelope.relay transaction:transaction]; successBlockParameter(plaintextData, transaction); diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index 74f49f4202..47989a9cdb 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -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 = diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.h b/SignalServiceKit/src/Messages/OWSMessageSender.h index 6b65f8f9bb..95c4889693 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.h +++ b/SignalServiceKit/src/Messages/OWSMessageSender.h @@ -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)contactsManager - contactsUpdater:(ContactsUpdater *)contactsUpdater; + contactsManager:(id)contactsManager; - (void)setBlockingManager:(OWSBlockingManager *)blockingManager; diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index 4b8c465807..ea2f506e44 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -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" @@ -216,7 +215,6 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; @property (nonatomic, readonly) OWSBlockingManager *blockingManager; @property (nonatomic, readonly) YapDatabaseConnection *dbConnection; @property (nonatomic, readonly) id contactsManager; -@property (nonatomic, readonly) ContactsUpdater *contactsUpdater; @property (atomic, readonly) NSMutableDictionary *sendingQueueMap; @end @@ -226,7 +224,6 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; - (instancetype)initWithNetworkManager:(TSNetworkManager *)networkManager primaryStorage:(OWSPrimaryStorage *)primaryStorage contactsManager:(id)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 *)signalRecipientsForRecipientIds:(NSArray *)recipientIds message:(TSOutgoingMessage *)message - error:(NSError **)error { OWSAssert(recipientIds); OWSAssert(message); - OWSAssert(error); - - *error = nil; NSMutableArray *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 readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + for (NSString *recipientId in recipientIds) { + SignalRecipient *recipient = + [SignalRecipient ensureRecipientExistsWithRecipientId: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 *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,11 @@ 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; - } - } + __block SignalRecipient *recipient; + [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + recipient = + [SignalRecipient ensureRecipientExistsWithRecipientId:recipientContactId transaction:transaction]; + }]; if (!recipient) { NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError(); @@ -977,7 +924,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 diff --git a/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.h b/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.h index d73be79c10..9ea9864c1c 100644 --- a/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.h +++ b/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.h @@ -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; diff --git a/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m b/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m index 1b38b7ea5c..334252fc0e 100644 --- a/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m +++ b/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m @@ -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]; } diff --git a/SignalServiceKit/src/Network/API/TSNetworkManager.m b/SignalServiceKit/src/Network/API/TSNetworkManager.m index d0414d70f0..9ac53d739f 100644 --- a/SignalServiceKit/src/Network/API/TSNetworkManager.m +++ b/SignalServiceKit/src/Network/API/TSNetworkManager.m @@ -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 diff --git a/SignalServiceKit/src/Protocols/ProtoBuf+OWS.m b/SignalServiceKit/src/Protocols/ProtoBuf+OWS.m index 00e207d9c0..ae6c0bdb84 100644 --- a/SignalServiceKit/src/Protocols/ProtoBuf+OWS.m +++ b/SignalServiceKit/src/Protocols/ProtoBuf+OWS.m @@ -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 From ebe87348a25606788731855236be9119ecc0fce2 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Fri, 13 Jul 2018 14:42:11 -0400 Subject: [PATCH 02/14] Streamline SignalRecipient. --- .../ViewControllers/DebugUI/DebugUIContacts.m | 54 +++++++++++++++++++ .../src/Messages/OWSMessageSender.m | 5 +- 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/Signal/src/ViewControllers/DebugUI/DebugUIContacts.m b/Signal/src/ViewControllers/DebugUI/DebugUIContacts.m index a77549a582..dbf72c28af 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUIContacts.m +++ b/Signal/src/ViewControllers/DebugUI/DebugUIContacts.m @@ -5,6 +5,7 @@ #import "DebugUIContacts.h" #import "OWSTableViewController.h" #import "Signal-Swift.h" +#import "SignalApp.h" #import 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 Invalid Contact Thread" + actionBlock:^{ + [DebugUIContacts createInvalidContactThread]; + }], + [OWSTableItem itemWithTitle:@"New Invalid Group Thread" + actionBlock:^{ + [DebugUIContacts createInvalidGroupThread]; + }], ]]; } @@ -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 *)invalidRecipientId +{ + // 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)createInvalidContactThread +{ + NSString *recipientId = [self invalidRecipientId]; + TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactId:recipientId]; + [SignalApp.sharedApp presentConversationForThread:thread]; +} + ++ (void)createInvalidGroupThread +{ + NSString *invalidRecipientId = [self invalidRecipientId]; + NSString *validRecipientId = @"+19174054216"; + + NSString *groupName = @"Partially invalid group"; + NSMutableArray *recipientIds = [@[ + invalidRecipientId, + 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 diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index ea2f506e44..cf183a70b2 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -904,8 +904,6 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; } else if (!mayHaveLinkedDevices && hasDeviceMessages) { OWSFail(@"%@ sync message has device messages for unknown secondary devices.", self.logTag); } - } else { - OWSAssert(deviceMessages.count > 0); } if (deviceMessages.count == 0) { @@ -914,6 +912,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 (device id = 0). 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 From 9618fc16c517d6c8e492531ac73cee93ed18a816 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Fri, 13 Jul 2018 15:23:08 -0400 Subject: [PATCH 03/14] Streamline SignalRecipient. --- .../src/Contacts/ContactsUpdater.m | 33 ++++++++++--------- SignalServiceKit/src/Contacts/SignalAccount.h | 5 --- SignalServiceKit/src/Contacts/SignalAccount.m | 9 ----- .../src/Contacts/SignalRecipient.h | 15 ++++----- .../src/Contacts/SignalRecipient.m | 19 +++++++++++ .../src/Messages/OWSMessageSender.m | 13 +++++++- 6 files changed, 56 insertions(+), 38 deletions(-) diff --git a/SignalServiceKit/src/Contacts/ContactsUpdater.m b/SignalServiceKit/src/Contacts/ContactsUpdater.m index 6c0e9cc637..60b6325d60 100644 --- a/SignalServiceKit/src/Contacts/ContactsUpdater.m +++ b/SignalServiceKit/src/Contacts/ContactsUpdater.m @@ -38,6 +38,16 @@ NS_ASSUME_NONNULL_BEGIN return self; } +- (SignalRecipient *)signalRecipientForRegisteredRecipientId:(NSString *)recipientId +{ + __block SignalRecipient *recipient; + [OWSPrimaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + recipient = + [SignalRecipient ensureRecipientExistsWithRegisteredRecipientId:recipientId transaction:transaction]; + }]; + return recipient; +} + - (void)lookupIdentifier:(NSString *)identifier success:(void (^)(SignalRecipient *recipient))success failure:(void (^)(NSError *error))failure @@ -52,7 +62,7 @@ NS_ASSUME_NONNULL_BEGIN [self contactIntersectionWithSet:[NSSet setWithObject:identifier] success:^(NSSet *_Nonnull matchedIds) { if (matchedIds.count == 1) { - success([SignalRecipient recipientWithTextSecureIdentifier:identifier]); + success([self signalRecipientForRegisteredRecipientId:identifier]); } else { failure(OWSErrorMakeNoSuchSignalRecipientError()); } @@ -75,7 +85,8 @@ NS_ASSUME_NONNULL_BEGIN if (matchedIds.count > 0) { NSMutableArray *recipients = [NSMutableArray new]; for (NSString *identifier in matchedIds) { - [recipients addObject:[SignalRecipient recipientWithTextSecureIdentifier:identifier]]; + [recipients + addObject:[self signalRecipientForRegisteredRecipientId:identifier]]; } success([recipients copy]); } else { @@ -109,18 +120,9 @@ NS_ASSUME_NONNULL_BEGIN success:^(NSSet *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]; - } - }]; - + // TODO: + // + // Update cache of registered identifiers. DDLogInfo(@"%@ successfully intersected contacts.", self.logTag); success(); } @@ -165,7 +167,8 @@ NS_ASSUME_NONNULL_BEGIN [OWSPrimaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { for (NSString *identifier in identifiers) { - [SignalRecipient ensureRecipientExistsWithRecipientId:identifier transaction:transaction]; + [SignalRecipient ensureRecipientExistsWithRegisteredRecipientId:identifier + transaction:transaction]; } }]; diff --git a/SignalServiceKit/src/Contacts/SignalAccount.h b/SignalServiceKit/src/Contacts/SignalAccount.h index e2345c5158..5b416f9a41 100644 --- a/SignalServiceKit/src/Contacts/SignalAccount.h +++ b/SignalServiceKit/src/Contacts/SignalAccount.h @@ -41,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 diff --git a/SignalServiceKit/src/Contacts/SignalAccount.m b/SignalServiceKit/src/Contacts/SignalAccount.m index 158992de1e..523947479d 100644 --- a/SignalServiceKit/src/Contacts/SignalAccount.m +++ b/SignalServiceKit/src/Contacts/SignalAccount.m @@ -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; diff --git a/SignalServiceKit/src/Contacts/SignalRecipient.h b/SignalServiceKit/src/Contacts/SignalRecipient.h index 8e9896b7e6..6f1d993d5a 100644 --- a/SignalServiceKit/src/Contacts/SignalRecipient.h +++ b/SignalServiceKit/src/Contacts/SignalRecipient.h @@ -6,22 +6,20 @@ NS_ASSUME_NONNULL_BEGIN -// This class serves two purposes: -// -// * We only _persist_ SignalRecipient instances when we know -// that it corresponds to an account on the Signal service. -// So SignalRecipient serves as a defacto cache of "known -// Signal users." -// * We hang the "known device list" for signal accounts on -// this entity. +// We hang the "known device list" for signal accounts on this entity. @interface SignalRecipient : TSYapDatabaseObject @property (readonly) NSOrderedSet *devices; +@property (nonatomic) BOOL mayBeUnregistered; + - (instancetype)init NS_UNAVAILABLE; + (instancetype)selfRecipient; ++ (SignalRecipient *)ensureRecipientExistsWithRegisteredRecipientId:(NSString *)recipientId + transaction:(YapDatabaseReadWriteTransaction *)transaction; + + (SignalRecipient *)ensureRecipientExistsWithRecipientId:(NSString *)recipientId transaction:(YapDatabaseReadWriteTransaction *)transaction; @@ -29,6 +27,7 @@ NS_ASSUME_NONNULL_BEGIN deviceId:(UInt32)deviceId transaction:(YapDatabaseReadWriteTransaction *)transaction; +// TODO: Replace with cache of known signal account ids. + (nullable instancetype)recipientWithTextSecureIdentifier:(NSString *)textSecureIdentifier; + (nullable instancetype)recipientWithTextSecureIdentifier:(NSString *)textSecureIdentifier withTransaction:(YapDatabaseReadTransaction *)transaction; diff --git a/SignalServiceKit/src/Contacts/SignalRecipient.m b/SignalServiceKit/src/Contacts/SignalRecipient.m index 351e74f9e0..6f11a01400 100644 --- a/SignalServiceKit/src/Contacts/SignalRecipient.m +++ b/SignalServiceKit/src/Contacts/SignalRecipient.m @@ -22,6 +22,25 @@ NS_ASSUME_NONNULL_BEGIN return @"SignalRecipient"; } +- (void)removeWithTransaction:(YapDatabaseReadWriteTransaction *)transaction +{ + OWSFail(@"%@ We should no longer remove SignalRecipients.", self.logTag); + + [super removeWithTransaction:transaction]; +} + ++ (SignalRecipient *)ensureRecipientExistsWithRegisteredRecipientId:(NSString *)recipientId + transaction:(YapDatabaseReadWriteTransaction *)transaction +{ + SignalRecipient *recipient = + [self ensureRecipientExistsWithRegisteredRecipientId:recipient transaction:transaction]; + if (recipient.mayBeUnregistered) { + recipient.mayBeUnregistered = NO; + [recipient saveWithTransaction:transaction]; + } + return recipient; +} + + (SignalRecipient *)ensureRecipientExistsWithRecipientId:(NSString *)recipientId transaction:(YapDatabaseReadWriteTransaction *)transaction { diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index cf183a70b2..a0e80f1a63 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -712,7 +712,12 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; [message updateWithSkippedRecipient:recipient.recipientId transaction:transaction]; } - [recipient removeWithTransaction:transaction]; + if (recipient.mayBeUnregistered) { + return; + } + recipient.mayBeUnregistered = YES; + [recipient saveWithTransaction:transaction]; + [[TSInfoMessage userNotRegisteredMessageInThread:thread recipientId:recipient.recipientId] saveWithTransaction:transaction]; }]; @@ -1010,6 +1015,11 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [recipient saveWithTransaction:transaction]; [message updateWithSentRecipient:recipient.uniqueId transaction:transaction]; + + if (recipient.mayBeUnregistered) { + recipient.mayBeUnregistered = NO; + [recipient saveWithTransaction:transaction]; + } }]; [self handleMessageSentLocally:message]; @@ -1075,6 +1085,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; 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. From 10b21d10e45541b0992cf7a4fd32edcd512ca4e3 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Fri, 13 Jul 2018 16:19:46 -0400 Subject: [PATCH 04/14] Streamline SignalRecipient. --- SignalServiceKit/src/Contacts/SignalRecipient.m | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/SignalServiceKit/src/Contacts/SignalRecipient.m b/SignalServiceKit/src/Contacts/SignalRecipient.m index 6f11a01400..062b19ab90 100644 --- a/SignalServiceKit/src/Contacts/SignalRecipient.m +++ b/SignalServiceKit/src/Contacts/SignalRecipient.m @@ -32,8 +32,7 @@ NS_ASSUME_NONNULL_BEGIN + (SignalRecipient *)ensureRecipientExistsWithRegisteredRecipientId:(NSString *)recipientId transaction:(YapDatabaseReadWriteTransaction *)transaction { - SignalRecipient *recipient = - [self ensureRecipientExistsWithRegisteredRecipientId:recipient transaction:transaction]; + SignalRecipient *recipient = [self ensureRecipientExistsWithRecipientId:recipientId transaction:transaction]; if (recipient.mayBeUnregistered) { recipient.mayBeUnregistered = NO; [recipient saveWithTransaction:transaction]; From ef3933bfaa7641e5b1013557749ea01f51fcabd2 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Mon, 16 Jul 2018 11:25:10 -0400 Subject: [PATCH 05/14] Streamline SignalRecipient. --- SignalServiceKit/src/Contacts/Contact.m | 6 +- .../src/Contacts/SignalRecipient.h | 18 ++- .../src/Contacts/SignalRecipient.m | 105 ++++++++++++++++-- .../src/Messages/OWSMessageSender.m | 13 +-- 4 files changed, 114 insertions(+), 28 deletions(-) diff --git a/SignalServiceKit/src/Contacts/Contact.m b/SignalServiceKit/src/Contacts/Contact.m index c088eda732..0d362cc22e 100644 --- a/SignalServiceKit/src/Contacts/Contact.m +++ b/SignalServiceKit/src/Contacts/Contact.m @@ -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 isRegisteredSignalAccount:number.toE164 transaction:transaction]) { [identifiers addObject:number.toE164]; } } diff --git a/SignalServiceKit/src/Contacts/SignalRecipient.h b/SignalServiceKit/src/Contacts/SignalRecipient.h index 6f1d993d5a..14611f8181 100644 --- a/SignalServiceKit/src/Contacts/SignalRecipient.h +++ b/SignalServiceKit/src/Contacts/SignalRecipient.h @@ -9,9 +9,7 @@ NS_ASSUME_NONNULL_BEGIN // We hang the "known device list" for signal accounts on this entity. @interface SignalRecipient : TSYapDatabaseObject -@property (readonly) NSOrderedSet *devices; - -@property (nonatomic) BOOL mayBeUnregistered; +@property (nonatomic, readonly) NSOrderedSet *devices; - (instancetype)init NS_UNAVAILABLE; @@ -28,9 +26,9 @@ NS_ASSUME_NONNULL_BEGIN transaction:(YapDatabaseReadWriteTransaction *)transaction; // TODO: Replace with cache of known signal account ids. -+ (nullable instancetype)recipientWithTextSecureIdentifier:(NSString *)textSecureIdentifier; -+ (nullable instancetype)recipientWithTextSecureIdentifier:(NSString *)textSecureIdentifier - withTransaction:(YapDatabaseReadTransaction *)transaction; +// TODO: Remove? ++ (nullable instancetype)registeredRecipientForRecipientId:(NSString *)recipientId + transaction:(YapDatabaseReadTransaction *)transaction; - (void)addDevices:(NSSet *)set; - (void)removeDevices:(NSSet *)set; @@ -39,6 +37,14 @@ NS_ASSUME_NONNULL_BEGIN - (NSComparisonResult)compare:(SignalRecipient *)other; +// TODO: Replace with cache of known signal account ids. ++ (BOOL)isRegisteredSignalAccount:(NSString *)recipientId transaction:(YapDatabaseReadTransaction *)transaction; + ++ (void)markAccountAsRegistered:(NSString *)recipientId transaction:(YapDatabaseReadWriteTransaction *)transaction; ++ (void)markAccountAsNotRegistered:(NSString *)recipientId transaction:(YapDatabaseReadWriteTransaction *)transaction; + +- (void)markAccountAsNotRegisteredWithTransaction:(YapDatabaseReadWriteTransaction *)transaction; + @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Contacts/SignalRecipient.m b/SignalServiceKit/src/Contacts/SignalRecipient.m index 062b19ab90..cb614f4e83 100644 --- a/SignalServiceKit/src/Contacts/SignalRecipient.m +++ b/SignalServiceKit/src/Contacts/SignalRecipient.m @@ -10,7 +10,9 @@ NS_ASSUME_NONNULL_BEGIN @interface SignalRecipient () -@property NSOrderedSet *devices; +@property (nonatomic) BOOL mayBeUnregistered; + +@property (nonatomic) NSOrderedSet *devices; @end @@ -43,8 +45,7 @@ NS_ASSUME_NONNULL_BEGIN + (SignalRecipient *)ensureRecipientExistsWithRecipientId:(NSString *)recipientId transaction:(YapDatabaseReadWriteTransaction *)transaction { - SignalRecipient *_Nullable recipient = - [self recipientWithTextSecureIdentifier:recipientId withTransaction:transaction]; + SignalRecipient *_Nullable recipient = [self recipientForRecipientId:recipientId transaction:transaction]; if (recipient) { return recipient; } @@ -60,8 +61,7 @@ NS_ASSUME_NONNULL_BEGIN deviceId:(UInt32)deviceId transaction:(YapDatabaseReadWriteTransaction *)transaction { - SignalRecipient *_Nullable existingRecipient = - [self recipientWithTextSecureIdentifier:recipientId withTransaction:transaction]; + SignalRecipient *_Nullable existingRecipient = [self recipientForRecipientId:recipientId transaction:transaction]; if (!existingRecipient) { DDLogDebug(@"%@ in %s creating recipient: %@, with deviceId: %u", self.logTag, @@ -132,17 +132,37 @@ 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); + + SignalRecipient *_Nullable instance = [self recipientForRecipientId:recipientId transaction:transaction]; + if (instance && !instance.mayBeUnregistered) { + return instance; + } else { + return nil; + } } -+ (nullable instancetype)recipientWithTextSecureIdentifier:(NSString *)textSecureIdentifier ++ (nullable instancetype)recipientForRecipientId:(NSString *)recipientId + transaction:(YapDatabaseReadTransaction *)transaction { + OWSAssert(transaction); + OWSAssert(recipientId.length > 0); + + return [self fetchObjectWithUniqueID:recipientId transaction:transaction]; +} + ++ (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 recipientForRecipientId:recipientId transaction:transaction]; }]; return recipient; } @@ -150,7 +170,7 @@ 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]]; } @@ -195,6 +215,67 @@ NS_ASSUME_NONNULL_BEGIN DDLogVerbose(@"%@ saved signal recipient: %@", self.logTag, self.recipientId); } ++ (BOOL)isRegisteredSignalAccount:(NSString *)recipientId +{ + __block BOOL result; + [self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { + result = [self isRegisteredSignalAccount:recipientId transaction:transaction]; + }]; + return result; +} + ++ (BOOL)isRegisteredSignalAccount:(NSString *)recipientId transaction:(YapDatabaseReadTransaction *)transaction +{ + SignalRecipient *_Nullable instance = [self recipientForRecipientId:recipientId transaction:transaction]; + return (instance && !instance.mayBeUnregistered); +} + ++ (void)markAccountAsRegistered:(NSString *)recipientId transaction:(YapDatabaseReadWriteTransaction *)transaction +{ + OWSAssert(transaction); + OWSAssert(recipientId.length > 0); + + SignalRecipient *_Nullable instance = [self recipientForRecipientId:recipientId transaction:transaction]; + + if (!instance) { + DDLogDebug(@"%@ creating recipient: %@", self.logTag, recipientId); + + instance = [[self alloc] initWithTextSecureIdentifier:recipientId]; + [instance saveWithTransaction:transaction]; + return; + } + if (!instance.mayBeUnregistered) { + return; + } + instance.mayBeUnregistered = NO; + [instance saveWithTransaction:transaction]; +} + ++ (void)markAccountAsNotRegistered:(NSString *)recipientId transaction:(YapDatabaseReadWriteTransaction *)transaction +{ + OWSAssert(transaction); + OWSAssert(recipientId.length > 0); + + SignalRecipient *_Nullable instance = [self recipientForRecipientId:recipientId transaction:transaction]; + if (!instance) { + return; + } + if (instance.mayBeUnregistered) { + return; + } + instance.mayBeUnregistered = YES; + [instance saveWithTransaction:transaction]; +} + +- (void)markAccountAsNotRegisteredWithTransaction:(YapDatabaseReadWriteTransaction *)transaction +{ + OWSAssert(transaction); + + self.mayBeUnregistered = YES; + + [SignalRecipient markAccountAsNotRegistered:self.recipientId transaction:transaction]; +} + @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index a0e80f1a63..a06b73cd27 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -712,11 +712,11 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; [message updateWithSkippedRecipient:recipient.recipientId transaction:transaction]; } - if (recipient.mayBeUnregistered) { + if (![SignalRecipient isRegisteredSignalAccount:recipient.recipientId transaction:transaction]) { return; } - recipient.mayBeUnregistered = YES; - [recipient saveWithTransaction:transaction]; + + [recipient markAccountAsNotRegisteredWithTransaction:transaction]; [[TSInfoMessage userNotRegisteredMessageInThread:thread recipientId:recipient.recipientId] saveWithTransaction:transaction]; @@ -1016,10 +1016,9 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; [recipient saveWithTransaction:transaction]; [message updateWithSentRecipient:recipient.uniqueId transaction:transaction]; - if (recipient.mayBeUnregistered) { - recipient.mayBeUnregistered = NO; - [recipient saveWithTransaction:transaction]; - } + // If we've just delivered a message to a user, we know they + // have a valid Signal account. + [SignalRecipient markAccountAsRegistered:recipient.recipientId transaction:transaction]; }]; [self handleMessageSentLocally:message]; From 05a4222b2d0ac4779b33bfda155ca30ba11b0a11 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Mon, 16 Jul 2018 12:30:07 -0400 Subject: [PATCH 06/14] Streamline SignalRecipient. --- .../src/Contacts/ContactsUpdater.m | 129 +++++++++--------- .../src/Contacts/SignalRecipient.h | 13 +- .../src/Contacts/SignalRecipient.m | 78 ++++------- .../src/Messages/OWSMessageDecrypter.m | 2 +- .../src/Messages/OWSMessageSender.m | 3 +- 5 files changed, 101 insertions(+), 124 deletions(-) diff --git a/SignalServiceKit/src/Contacts/ContactsUpdater.m b/SignalServiceKit/src/Contacts/ContactsUpdater.m index 60b6325d60..7adb95f208 100644 --- a/SignalServiceKit/src/Contacts/ContactsUpdater.m +++ b/SignalServiceKit/src/Contacts/ContactsUpdater.m @@ -38,31 +38,27 @@ NS_ASSUME_NONNULL_BEGIN return self; } -- (SignalRecipient *)signalRecipientForRegisteredRecipientId:(NSString *)recipientId -{ - __block SignalRecipient *recipient; - [OWSPrimaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - recipient = - [SignalRecipient ensureRecipientExistsWithRegisteredRecipientId:recipientId transaction:transaction]; - }]; - 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 *_Nonnull matchedIds) { - if (matchedIds.count == 1) { - success([self signalRecipientForRegisteredRecipientId:identifier]); + NSSet *recipiendIds = [NSSet setWithObject:recipientId]; + [self contactIntersectionWithSet:recipiendIds + success:^(NSSet *recipients) { + if (recipients.count > 0) { + OWSAssert(recipients.count == 1); + + SignalRecipient *recipient = recipients.allObjects.firstObject; + success(recipient); } else { failure(OWSErrorMakeNoSuchSignalRecipientError()); } @@ -81,13 +77,8 @@ NS_ASSUME_NONNULL_BEGIN } [self contactIntersectionWithSet:[NSSet setWithArray:identifiers] - success:^(NSSet *_Nonnull matchedIds) { - if (matchedIds.count > 0) { - NSMutableArray *recipients = [NSMutableArray new]; - for (NSString *identifier in matchedIds) { - [recipients - addObject:[self signalRecipientForRegisteredRecipientId:identifier]]; - } + success:^(NSSet *recipients) { + if (recipients.count > 0) { success([recipients copy]); } else { failure(OWSErrorMakeNoSuchSignalRecipientError()); @@ -96,6 +87,7 @@ NS_ASSUME_NONNULL_BEGIN failure:failure]; } +// TODO: Modify this to support delta lookups. - (void)updateSignalContactIntersectionWithABContacts:(NSArray *)abContacts success:(void (^)(void))success failure:(void (^)(NSError *error))failure @@ -109,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]; }]; @@ -117,62 +110,70 @@ NS_ASSUME_NONNULL_BEGIN NSMutableSet *allContacts = [[abPhoneNumbers setByAddingObjectsFromSet:recipientIds] mutableCopy]; [self contactIntersectionWithSet:allContacts - success:^(NSSet *matchedIds) { - [recipientIds minusSet:matchedIds]; - - // TODO: - // - // Update cache of registered identifiers. + success:^(NSSet *recipients) { DDLogInfo(@"%@ successfully intersected contacts.", self.logTag); success(); } failure:failure]; } -- (void)contactIntersectionWithSet:(NSSet *)idSet - success:(void (^)(NSSet *matchedIds))success +- (void)contactIntersectionWithSet:(NSSet *)recipientIdsToLookup + success:(void (^)(NSSet *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 *phoneNumbersByHashes = [NSMutableDictionary new]; + for (NSString *recipientId in recipientIdsToLookup) { + NSString *hash = [Cryptography truncatedSHA1Base64EncodedWithoutPadding:recipientId]; + phoneNumbersByHashes[hash] = recipientId; } - NSArray *hashes = [phoneNumbersByHashes allKeys]; - + NSArray *hashes = [phoneNumbersByHashes allKeys]; + TSRequest *request = [OWSRequestFactory contactsIntersectionRequestWithHashesArray:hashes]; [[TSNetworkManager sharedManager] makeRequest:request - success:^(NSURLSessionDataTask *tsTask, id responseDict) { - NSMutableSet *identifiers = [NSMutableSet new]; - 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.length < 1) { - DDLogWarn(@"%@ An interesecting hash wasn't found in the mapping.", self.logTag); - continue; + success:^(NSURLSessionDataTask *task, id responseDict) { + NSMutableSet *registeredRecipientIds = [NSMutableSet new]; + + if ([responseDict isKindOfClass:[NSDictionary class]]) { + NSArray *_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]; } - - [identifiers addObject:identifier]; } } - - // Insert or update contact attributes - // - // TODO: Do we need to _eagerly_ ensure a SignalRecipient instance exists? - [OWSPrimaryStorage.dbReadWriteConnection - readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - for (NSString *identifier in identifiers) { - [SignalRecipient ensureRecipientExistsWithRegisteredRecipientId:identifier - transaction:transaction]; + + NSMutableSet *recipients = [NSMutableSet new]; + [OWSPrimaryStorage.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + for (NSString *recipientId in recipientIdsToLookup) { + if ([registeredRecipientIds containsObject:recipientId]) { + SignalRecipient *recipient = + [SignalRecipient markAccountAsRegistered:recipientId transaction:transaction]; + [recipients addObject:recipient]; + } else { + [SignalRecipient markAccountAsNotRegistered:recipientId transaction:transaction]; } - }]; + } + }]; - success([identifiers copy]); + success([recipients copy]); } failure:^(NSURLSessionDataTask *task, NSError *error) { if (!IsNSErrorNetworkFailure(error)) { diff --git a/SignalServiceKit/src/Contacts/SignalRecipient.h b/SignalServiceKit/src/Contacts/SignalRecipient.h index 14611f8181..a68b70394b 100644 --- a/SignalServiceKit/src/Contacts/SignalRecipient.h +++ b/SignalServiceKit/src/Contacts/SignalRecipient.h @@ -21,12 +21,6 @@ NS_ASSUME_NONNULL_BEGIN + (SignalRecipient *)ensureRecipientExistsWithRecipientId:(NSString *)recipientId transaction:(YapDatabaseReadWriteTransaction *)transaction; -+ (void)ensureRecipientExistsWithRecipientId:(NSString *)recipientId - deviceId:(UInt32)deviceId - transaction:(YapDatabaseReadWriteTransaction *)transaction; - -// TODO: Replace with cache of known signal account ids. -// TODO: Remove? + (nullable instancetype)registeredRecipientForRecipientId:(NSString *)recipientId transaction:(YapDatabaseReadTransaction *)transaction; @@ -40,11 +34,12 @@ NS_ASSUME_NONNULL_BEGIN // TODO: Replace with cache of known signal account ids. + (BOOL)isRegisteredSignalAccount:(NSString *)recipientId transaction:(YapDatabaseReadTransaction *)transaction; -+ (void)markAccountAsRegistered:(NSString *)recipientId transaction:(YapDatabaseReadWriteTransaction *)transaction; ++ (SignalRecipient *)markAccountAsRegistered:(NSString *)recipientId transaction:(YapDatabaseReadWriteTransaction *)transaction; ++ (void)markAccountAsRegistered:(NSString *)recipientId + deviceId:(UInt32)deviceId + transaction:(YapDatabaseReadWriteTransaction *)transaction; + (void)markAccountAsNotRegistered:(NSString *)recipientId transaction:(YapDatabaseReadWriteTransaction *)transaction; -- (void)markAccountAsNotRegisteredWithTransaction:(YapDatabaseReadWriteTransaction *)transaction; - @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Contacts/SignalRecipient.m b/SignalServiceKit/src/Contacts/SignalRecipient.m index cb614f4e83..c6e5961022 100644 --- a/SignalServiceKit/src/Contacts/SignalRecipient.m +++ b/SignalServiceKit/src/Contacts/SignalRecipient.m @@ -57,36 +57,6 @@ NS_ASSUME_NONNULL_BEGIN return recipient; } -+ (void)ensureRecipientExistsWithRecipientId:(NSString *)recipientId - deviceId:(UInt32)deviceId - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - SignalRecipient *_Nullable existingRecipient = [self recipientForRecipientId:recipientId transaction:transaction]; - if (!existingRecipient) { - DDLogDebug(@"%@ in %s creating recipient: %@, with deviceId: %u", - self.logTag, - __PRETTY_FUNCTION__, - recipientId, - (unsigned int)deviceId); - - SignalRecipient *newRecipient = [[self alloc] initWithTextSecureIdentifier:recipientId]; - [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]; - } -} - - (instancetype)initWithTextSecureIdentifier:(NSString *)textSecureIdentifier { self = [super initWithUniqueId:textSecureIdentifier]; @@ -184,17 +154,19 @@ NS_ASSUME_NONNULL_BEGIN return; } - NSMutableOrderedSet *updatedDevices = [self.devices mutableCopy]; + NSMutableOrderedSet *updatedDevices = (self.devices + ? [self.devices mutableCopy] + : [NSMutableOrderedSet new]); [updatedDevices unionSet:set]; - self.devices = [updatedDevices copy]; } - (void)removeDevices:(NSSet *)set { - NSMutableOrderedSet *updatedDevices = [self.devices mutableCopy]; + NSMutableOrderedSet *updatedDevices = (self.devices + ? [self.devices mutableCopy] + : [NSMutableOrderedSet new]); [updatedDevices minusSet:set]; - self.devices = [updatedDevices copy]; } @@ -230,7 +202,7 @@ NS_ASSUME_NONNULL_BEGIN return (instance && !instance.mayBeUnregistered); } -+ (void)markAccountAsRegistered:(NSString *)recipientId transaction:(YapDatabaseReadWriteTransaction *)transaction ++ (SignalRecipient *)markAccountAsRegistered:(NSString *)recipientId transaction:(YapDatabaseReadWriteTransaction *)transaction { OWSAssert(transaction); OWSAssert(recipientId.length > 0); @@ -242,13 +214,30 @@ NS_ASSUME_NONNULL_BEGIN instance = [[self alloc] initWithTextSecureIdentifier:recipientId]; [instance saveWithTransaction:transaction]; - return; + } else if (instance.mayBeUnregistered) { + instance.mayBeUnregistered = NO; + [instance saveWithTransaction:transaction]; } - if (!instance.mayBeUnregistered) { - return; + return instance; +} + ++ (void)markAccountAsRegistered:(NSString *)recipientId + deviceId:(UInt32)deviceId + transaction:(YapDatabaseReadWriteTransaction *)transaction +{ + OWSAssert(transaction); + OWSAssert(recipientId.length > 0); + + SignalRecipient *recipient = [self markAccountAsRegistered: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:transaction]; } - instance.mayBeUnregistered = NO; - [instance saveWithTransaction:transaction]; } + (void)markAccountAsNotRegistered:(NSString *)recipientId transaction:(YapDatabaseReadWriteTransaction *)transaction @@ -267,15 +256,6 @@ NS_ASSUME_NONNULL_BEGIN [instance saveWithTransaction:transaction]; } -- (void)markAccountAsNotRegisteredWithTransaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSAssert(transaction); - - self.mayBeUnregistered = YES; - - [SignalRecipient markAccountAsNotRegistered:self.recipientId transaction:transaction]; -} - @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Messages/OWSMessageDecrypter.m b/SignalServiceKit/src/Messages/OWSMessageDecrypter.m index fca8303ea2..ab4dafab67 100644 --- a/SignalServiceKit/src/Messages/OWSMessageDecrypter.m +++ b/SignalServiceKit/src/Messages/OWSMessageDecrypter.m @@ -110,7 +110,7 @@ NS_ASSUME_NONNULL_BEGIN DecryptSuccessBlock successBlock = ^(NSData *_Nullable plaintextData, YapDatabaseReadWriteTransaction *transaction) { - [SignalRecipient ensureRecipientExistsWithRecipientId:envelope.source + [SignalRecipient markAccountAsRegistered:envelope.source deviceId:envelope.sourceDevice transaction:transaction]; diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index a06b73cd27..147e35bd58 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -716,7 +716,8 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; return; } - [recipient markAccountAsNotRegisteredWithTransaction:transaction]; + [SignalRecipient markAccountAsNotRegistered:recipient.recipientId + transaction:transaction]; [[TSInfoMessage userNotRegisteredMessageInThread:thread recipientId:recipient.recipientId] saveWithTransaction:transaction]; From b6489c694842ebffd5b565279fdde66d32d627cd Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Mon, 16 Jul 2018 12:39:24 -0400 Subject: [PATCH 07/14] Streamline SignalRecipient. --- .../src/Contacts/SignalRecipient.h | 8 ++--- .../src/Contacts/SignalRecipient.m | 29 +++++-------------- .../src/Contacts/Threads/TSContactThread.m | 3 -- .../src/Messages/OWSMessageSender.m | 13 ++++----- 4 files changed, 16 insertions(+), 37 deletions(-) diff --git a/SignalServiceKit/src/Contacts/SignalRecipient.h b/SignalServiceKit/src/Contacts/SignalRecipient.h index a68b70394b..3d4763db0f 100644 --- a/SignalServiceKit/src/Contacts/SignalRecipient.h +++ b/SignalServiceKit/src/Contacts/SignalRecipient.h @@ -15,14 +15,10 @@ NS_ASSUME_NONNULL_BEGIN + (instancetype)selfRecipient; -+ (SignalRecipient *)ensureRecipientExistsWithRegisteredRecipientId:(NSString *)recipientId - transaction:(YapDatabaseReadWriteTransaction *)transaction; - -+ (SignalRecipient *)ensureRecipientExistsWithRecipientId:(NSString *)recipientId - transaction:(YapDatabaseReadWriteTransaction *)transaction; - + (nullable instancetype)registeredRecipientForRecipientId:(NSString *)recipientId transaction:(YapDatabaseReadTransaction *)transaction; ++ (instancetype)getOrCreatedUnsavedRecipientForRecipientId:(NSString *)recipientId + transaction:(YapDatabaseReadTransaction *)transaction; - (void)addDevices:(NSSet *)set; - (void)removeDevices:(NSSet *)set; diff --git a/SignalServiceKit/src/Contacts/SignalRecipient.m b/SignalServiceKit/src/Contacts/SignalRecipient.m index c6e5961022..a5a30d510d 100644 --- a/SignalServiceKit/src/Contacts/SignalRecipient.m +++ b/SignalServiceKit/src/Contacts/SignalRecipient.m @@ -31,32 +31,19 @@ NS_ASSUME_NONNULL_BEGIN [super removeWithTransaction:transaction]; } -+ (SignalRecipient *)ensureRecipientExistsWithRegisteredRecipientId:(NSString *)recipientId - transaction:(YapDatabaseReadWriteTransaction *)transaction ++ (instancetype)getOrCreatedUnsavedRecipientForRecipientId:(NSString *)recipientId + transaction:(YapDatabaseReadTransaction *)transaction { - SignalRecipient *recipient = [self ensureRecipientExistsWithRecipientId:recipientId transaction:transaction]; - if (recipient.mayBeUnregistered) { - recipient.mayBeUnregistered = NO; - [recipient 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; } -+ (SignalRecipient *)ensureRecipientExistsWithRecipientId:(NSString *)recipientId - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - SignalRecipient *_Nullable recipient = [self recipientForRecipientId:recipientId transaction:transaction]; - if (recipient) { - return recipient; - } - - DDLogDebug(@"%@ creating recipient: %@", self.logTag, recipientId); - - recipient = [[self alloc] initWithTextSecureIdentifier:recipientId]; - [recipient saveWithTransaction:transaction]; - return recipient; -} - - (instancetype)initWithTextSecureIdentifier:(NSString *)textSecureIdentifier { self = [super initWithUniqueId:textSecureIdentifier]; diff --git a/SignalServiceKit/src/Contacts/Threads/TSContactThread.m b/SignalServiceKit/src/Contacts/Threads/TSContactThread.m index d6bd281a62..53464dee5b 100644 --- a/SignalServiceKit/src/Contacts/Threads/TSContactThread.m +++ b/SignalServiceKit/src/Contacts/Threads/TSContactThread.m @@ -39,9 +39,6 @@ NS_ASSUME_NONNULL_BEGIN [thread saveWithTransaction:transaction]; } - // TODO: Do we need to _eagerly_ ensure a SignalRecipient instance exists? - [SignalRecipient ensureRecipientExistsWithRecipientId:contactId transaction:transaction]; - return thread; } diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index 147e35bd58..0ea500c23d 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -454,8 +454,8 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; NSMutableArray *recipients = [NSMutableArray new]; [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { for (NSString *recipientId in recipientIds) { - SignalRecipient *recipient = - [SignalRecipient ensureRecipientExistsWithRecipientId:recipientId transaction:transaction]; + SignalRecipient *recipient = [SignalRecipient getOrCreatedUnsavedRecipientForRecipientId:recipientId + transaction:transaction]; [recipients addObject:recipient]; } }]; @@ -555,11 +555,10 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; return; } - __block SignalRecipient *recipient; - [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - recipient = - [SignalRecipient ensureRecipientExistsWithRecipientId:recipientContactId transaction:transaction]; - }]; + NSArray *recipients = + [self signalRecipientsForRecipientIds:@[recipientContactId] message:message]; + OWSAssert(recipients.count == 1); + SignalRecipient *recipient = recipients.firstObject; if (!recipient) { NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError(); From 77884913d847b6365b0c8903e27ae634db5bb0f4 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Mon, 16 Jul 2018 13:11:00 -0400 Subject: [PATCH 08/14] Streamline SignalRecipient. --- .../src/Contacts/SignalRecipient.h | 16 +++-- .../src/Contacts/SignalRecipient.m | 67 ++++++++++--------- .../src/Messages/OWSMessageSender.m | 24 ++++--- 3 files changed, 62 insertions(+), 45 deletions(-) diff --git a/SignalServiceKit/src/Contacts/SignalRecipient.h b/SignalServiceKit/src/Contacts/SignalRecipient.h index 3d4763db0f..46481f14c0 100644 --- a/SignalServiceKit/src/Contacts/SignalRecipient.h +++ b/SignalServiceKit/src/Contacts/SignalRecipient.h @@ -6,7 +6,14 @@ NS_ASSUME_NONNULL_BEGIN -// We hang the "known device list" for signal accounts on this entity. +// 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 @property (nonatomic, readonly) NSOrderedSet *devices; @@ -20,14 +27,15 @@ NS_ASSUME_NONNULL_BEGIN + (instancetype)getOrCreatedUnsavedRecipientForRecipientId:(NSString *)recipientId transaction:(YapDatabaseReadTransaction *)transaction; -- (void)addDevices:(NSSet *)set; -- (void)removeDevices:(NSSet *)set; +- (void)addDevicesToRegisteredRecipient:(NSSet *)devices + transaction:(YapDatabaseReadWriteTransaction *)transaction; +- (void)removeDevicesFromRegisteredRecipient:(NSSet *)devices + transaction:(YapDatabaseReadWriteTransaction *)transaction; - (NSString *)recipientId; - (NSComparisonResult)compare:(SignalRecipient *)other; -// TODO: Replace with cache of known signal account ids. + (BOOL)isRegisteredSignalAccount:(NSString *)recipientId transaction:(YapDatabaseReadTransaction *)transaction; + (SignalRecipient *)markAccountAsRegistered:(NSString *)recipientId transaction:(YapDatabaseReadWriteTransaction *)transaction; diff --git a/SignalServiceKit/src/Contacts/SignalRecipient.m b/SignalServiceKit/src/Contacts/SignalRecipient.m index a5a30d510d..27fd1577cc 100644 --- a/SignalServiceKit/src/Contacts/SignalRecipient.m +++ b/SignalServiceKit/src/Contacts/SignalRecipient.m @@ -10,8 +10,6 @@ NS_ASSUME_NONNULL_BEGIN @interface SignalRecipient () -@property (nonatomic) BOOL mayBeUnregistered; - @property (nonatomic) NSOrderedSet *devices; @end @@ -96,12 +94,7 @@ NS_ASSUME_NONNULL_BEGIN OWSAssert(transaction); OWSAssert(recipientId.length > 0); - SignalRecipient *_Nullable instance = [self recipientForRecipientId:recipientId transaction:transaction]; - if (instance && !instance.mayBeUnregistered) { - return instance; - } else { - return nil; - } + return [self recipientForRecipientId:recipientId transaction:transaction]; } + (nullable instancetype)recipientForRecipientId:(NSString *)recipientId @@ -134,9 +127,11 @@ NS_ASSUME_NONNULL_BEGIN 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; } @@ -144,19 +139,45 @@ NS_ASSUME_NONNULL_BEGIN NSMutableOrderedSet *updatedDevices = (self.devices ? [self.devices mutableCopy] : [NSMutableOrderedSet new]); - [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 ? [self.devices mutableCopy] : [NSMutableOrderedSet new]); - [updatedDevices minusSet:set]; + [updatedDevices minusSet:devices]; self.devices = [updatedDevices copy]; } +- (void)addDevicesToRegisteredRecipient:(NSSet *)devices transaction:(YapDatabaseReadWriteTransaction *)transaction +{ + OWSAssert(transaction); + OWSAssert(devices.count > 0); + + [self addDevices:devices]; + + SignalRecipient *latest = [SignalRecipient markAccountAsRegistered:self.recipientId transaction:transaction]; + [latest addDevices:devices]; + [latest saveWithTransaction:transaction]; +} + +- (void)removeDevicesFromRegisteredRecipient:(NSSet *)devices transaction:(YapDatabaseReadWriteTransaction *)transaction +{ + OWSAssert(transaction); + OWSAssert(devices.count > 0); + + [self removeDevices:devices]; + + SignalRecipient *latest = [SignalRecipient markAccountAsRegistered:self.recipientId transaction:transaction]; + [latest removeDevices:devices]; + [latest saveWithTransaction:transaction]; +} + - (NSString *)recipientId { return self.uniqueId; @@ -174,19 +195,10 @@ NS_ASSUME_NONNULL_BEGIN DDLogVerbose(@"%@ saved signal recipient: %@", self.logTag, self.recipientId); } -+ (BOOL)isRegisteredSignalAccount:(NSString *)recipientId -{ - __block BOOL result; - [self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - result = [self isRegisteredSignalAccount:recipientId transaction:transaction]; - }]; - return result; -} - + (BOOL)isRegisteredSignalAccount:(NSString *)recipientId transaction:(YapDatabaseReadTransaction *)transaction { SignalRecipient *_Nullable instance = [self recipientForRecipientId:recipientId transaction:transaction]; - return (instance && !instance.mayBeUnregistered); + return instance != nil; } + (SignalRecipient *)markAccountAsRegistered:(NSString *)recipientId transaction:(YapDatabaseReadWriteTransaction *)transaction @@ -201,9 +213,6 @@ NS_ASSUME_NONNULL_BEGIN instance = [[self alloc] initWithTextSecureIdentifier:recipientId]; [instance saveWithTransaction:transaction]; - } else if (instance.mayBeUnregistered) { - instance.mayBeUnregistered = NO; - [instance saveWithTransaction:transaction]; } return instance; } @@ -236,11 +245,7 @@ NS_ASSUME_NONNULL_BEGIN if (!instance) { return; } - if (instance.mayBeUnregistered) { - return; - } - instance.mayBeUnregistered = YES; - [instance saveWithTransaction:transaction]; + [instance removeWithTransaction:transaction]; } @end diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index 0ea500c23d..89dd4a9fef 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -77,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 @@ -99,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 @@ -111,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) { @@ -151,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); @@ -1157,7 +1157,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; } [self.dbConnection - asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { + asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction * transaction) { if (extraDevices.count < 1 && missingDevices.count < 1) { OWSProdFail([OWSAnalyticsEvents messageSenderErrorNoMissingOrExtraDevices]); } @@ -1170,16 +1170,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(); }); @@ -1271,7 +1271,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; } From c830f880aa40949d6f3b38191f98ac2b646af4e2 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Mon, 16 Jul 2018 14:09:50 -0400 Subject: [PATCH 09/14] Streamline SignalRecipient. --- SignalServiceKit/src/Contacts/SignalRecipient.m | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/SignalServiceKit/src/Contacts/SignalRecipient.m b/SignalServiceKit/src/Contacts/SignalRecipient.m index 27fd1577cc..86c5c7f8df 100644 --- a/SignalServiceKit/src/Contacts/SignalRecipient.m +++ b/SignalServiceKit/src/Contacts/SignalRecipient.m @@ -18,17 +18,6 @@ NS_ASSUME_NONNULL_BEGIN @implementation SignalRecipient -+ (NSString *)collection { - return @"SignalRecipient"; -} - -- (void)removeWithTransaction:(YapDatabaseReadWriteTransaction *)transaction -{ - OWSFail(@"%@ We should no longer remove SignalRecipients.", self.logTag); - - [super removeWithTransaction:transaction]; -} - + (instancetype)getOrCreatedUnsavedRecipientForRecipientId:(NSString *)recipientId transaction:(YapDatabaseReadTransaction *)transaction { From ace07ac62a9ef3de467c5e868810616aaeaf1911 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Mon, 16 Jul 2018 16:34:37 -0400 Subject: [PATCH 10/14] Respond to CR. --- .../ViewControllers/DebugUI/DebugUIContacts.m | 8 ++--- .../src/Contacts/SignalRecipient.h | 4 +-- .../src/Contacts/SignalRecipient.m | 29 ++++++++++--------- .../src/Messages/OWSMessageSender.m | 6 ++-- 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/Signal/src/ViewControllers/DebugUI/DebugUIContacts.m b/Signal/src/ViewControllers/DebugUI/DebugUIContacts.m index dbf72c28af..88f7a9725d 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUIContacts.m +++ b/Signal/src/ViewControllers/DebugUI/DebugUIContacts.m @@ -1323,7 +1323,7 @@ NS_ASSUME_NONNULL_BEGIN }]; } -+ (NSString *)invalidRecipientId ++ (NSString *)unregisteredRecipientId { // We ensure that the phone number is invalid by appending too many digits. NSMutableString *recipientId = [@"+1" mutableCopy]; @@ -1335,19 +1335,19 @@ NS_ASSUME_NONNULL_BEGIN + (void)createInvalidContactThread { - NSString *recipientId = [self invalidRecipientId]; + NSString *recipientId = [self unregisteredRecipientId]; TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactId:recipientId]; [SignalApp.sharedApp presentConversationForThread:thread]; } + (void)createInvalidGroupThread { - NSString *invalidRecipientId = [self invalidRecipientId]; + NSString *unregisteredRecipientId = [self unregisteredRecipientId]; NSString *validRecipientId = @"+19174054216"; NSString *groupName = @"Partially invalid group"; NSMutableArray *recipientIds = [@[ - invalidRecipientId, + unregisteredRecipientId, validRecipientId, [TSAccountManager localNumber], ] mutableCopy]; diff --git a/SignalServiceKit/src/Contacts/SignalRecipient.h b/SignalServiceKit/src/Contacts/SignalRecipient.h index 46481f14c0..8f5438d44a 100644 --- a/SignalServiceKit/src/Contacts/SignalRecipient.h +++ b/SignalServiceKit/src/Contacts/SignalRecipient.h @@ -24,8 +24,8 @@ NS_ASSUME_NONNULL_BEGIN + (nullable instancetype)registeredRecipientForRecipientId:(NSString *)recipientId transaction:(YapDatabaseReadTransaction *)transaction; -+ (instancetype)getOrCreatedUnsavedRecipientForRecipientId:(NSString *)recipientId - transaction:(YapDatabaseReadTransaction *)transaction; ++ (instancetype)getOrBuildUnsavedRecipientForRecipientId:(NSString *)recipientId + transaction:(YapDatabaseReadTransaction *)transaction; - (void)addDevicesToRegisteredRecipient:(NSSet *)devices transaction:(YapDatabaseReadWriteTransaction *)transaction; diff --git a/SignalServiceKit/src/Contacts/SignalRecipient.m b/SignalServiceKit/src/Contacts/SignalRecipient.m index 86c5c7f8df..ad7e39cc5f 100644 --- a/SignalServiceKit/src/Contacts/SignalRecipient.m +++ b/SignalServiceKit/src/Contacts/SignalRecipient.m @@ -18,8 +18,8 @@ NS_ASSUME_NONNULL_BEGIN @implementation SignalRecipient -+ (instancetype)getOrCreatedUnsavedRecipientForRecipientId:(NSString *)recipientId - transaction:(YapDatabaseReadTransaction *)transaction ++ (instancetype)getOrBuildUnsavedRecipientForRecipientId:(NSString *)recipientId + transaction:(YapDatabaseReadTransaction *)transaction { OWSAssert(transaction); OWSAssert(recipientId.length > 0); @@ -125,9 +125,7 @@ NS_ASSUME_NONNULL_BEGIN return; } - NSMutableOrderedSet *updatedDevices = (self.devices - ? [self.devices mutableCopy] - : [NSMutableOrderedSet new]); + NSMutableOrderedSet *updatedDevices = [self.devices mutableCopy]; [updatedDevices unionSet:devices]; self.devices = [updatedDevices copy]; } @@ -135,10 +133,8 @@ NS_ASSUME_NONNULL_BEGIN - (void)removeDevices:(NSSet *)devices { OWSAssert(devices.count > 0); - - NSMutableOrderedSet *updatedDevices = (self.devices - ? [self.devices mutableCopy] - : [NSMutableOrderedSet new]); + + NSMutableOrderedSet *updatedDevices = [self.devices mutableCopy]; [updatedDevices minusSet:devices]; self.devices = [updatedDevices copy]; } @@ -152,7 +148,7 @@ NS_ASSUME_NONNULL_BEGIN SignalRecipient *latest = [SignalRecipient markAccountAsRegistered:self.recipientId transaction:transaction]; [latest addDevices:devices]; - [latest saveWithTransaction:transaction]; + [latest saveWithTransaction_internal:transaction]; } - (void)removeDevicesFromRegisteredRecipient:(NSSet *)devices transaction:(YapDatabaseReadWriteTransaction *)transaction @@ -164,7 +160,7 @@ NS_ASSUME_NONNULL_BEGIN SignalRecipient *latest = [SignalRecipient markAccountAsRegistered:self.recipientId transaction:transaction]; [latest removeDevices:devices]; - [latest saveWithTransaction:transaction]; + [latest saveWithTransaction_internal:transaction]; } - (NSString *)recipientId @@ -178,6 +174,13 @@ NS_ASSUME_NONNULL_BEGIN } - (void)saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction +{ + OWSProdLogAndFail(@"%@ Don't call saveWithTransaction from outside this class.", self.logTag); + + [self saveWithTransaction_internal:transaction]; +} + +- (void)saveWithTransaction_internal:(YapDatabaseReadWriteTransaction *)transaction { [super saveWithTransaction:transaction]; @@ -201,7 +204,7 @@ NS_ASSUME_NONNULL_BEGIN DDLogDebug(@"%@ creating recipient: %@", self.logTag, recipientId); instance = [[self alloc] initWithTextSecureIdentifier:recipientId]; - [instance saveWithTransaction:transaction]; + [instance saveWithTransaction_internal:transaction]; } return instance; } @@ -221,7 +224,7 @@ NS_ASSUME_NONNULL_BEGIN (unsigned int)deviceId); [recipient addDevices:[NSSet setWithObject:@(deviceId)]]; - [recipient saveWithTransaction:transaction]; + [recipient saveWithTransaction_internal:transaction]; } } diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index 89dd4a9fef..c8960db373 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -454,8 +454,8 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; NSMutableArray *recipients = [NSMutableArray new]; [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { for (NSString *recipientId in recipientIds) { - SignalRecipient *recipient = [SignalRecipient getOrCreatedUnsavedRecipientForRecipientId:recipientId - transaction:transaction]; + SignalRecipient *recipient = + [SignalRecipient getOrBuildUnsavedRecipientForRecipientId:recipientId transaction:transaction]; [recipients addObject:recipient]; } }]; @@ -895,7 +895,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(); }); @@ -1013,7 +1012,6 @@ 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 From cc91cb3dbf6e4f25e499ad529337bccbad734b1f Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Tue, 17 Jul 2018 10:09:01 -0400 Subject: [PATCH 11/14] Respond to CR. --- SignalServiceKit/src/Contacts/Contact.m | 2 +- .../src/Contacts/ContactsUpdater.m | 4 +- .../src/Contacts/SignalRecipient.h | 13 +-- .../src/Contacts/SignalRecipient.m | 34 ++++++-- .../src/Messages/OWSMessageDecrypter.m | 6 +- .../src/Messages/OWSMessageSender.m | 82 +++++++++++++------ 6 files changed, 94 insertions(+), 47 deletions(-) diff --git a/SignalServiceKit/src/Contacts/Contact.m b/SignalServiceKit/src/Contacts/Contact.m index 0d362cc22e..8bc4004bf4 100644 --- a/SignalServiceKit/src/Contacts/Contact.m +++ b/SignalServiceKit/src/Contacts/Contact.m @@ -223,7 +223,7 @@ NS_ASSUME_NONNULL_BEGIN [OWSPrimaryStorage.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { for (PhoneNumber *number in self.parsedPhoneNumbers) { - if ([SignalRecipient isRegisteredSignalAccount:number.toE164 transaction:transaction]) { + if ([SignalRecipient isRegisteredRecipient:number.toE164 transaction:transaction]) { [identifiers addObject:number.toE164]; } } diff --git a/SignalServiceKit/src/Contacts/ContactsUpdater.m b/SignalServiceKit/src/Contacts/ContactsUpdater.m index 7adb95f208..cdd8836511 100644 --- a/SignalServiceKit/src/Contacts/ContactsUpdater.m +++ b/SignalServiceKit/src/Contacts/ContactsUpdater.m @@ -165,10 +165,10 @@ NS_ASSUME_NONNULL_BEGIN for (NSString *recipientId in recipientIdsToLookup) { if ([registeredRecipientIds containsObject:recipientId]) { SignalRecipient *recipient = - [SignalRecipient markAccountAsRegistered:recipientId transaction:transaction]; + [SignalRecipient markRecipientAsRegisteredAndGet:recipientId transaction:transaction]; [recipients addObject:recipient]; } else { - [SignalRecipient markAccountAsNotRegistered:recipientId transaction:transaction]; + [SignalRecipient removeUnregisteredRecipient:recipientId transaction:transaction]; } } }]; diff --git a/SignalServiceKit/src/Contacts/SignalRecipient.h b/SignalServiceKit/src/Contacts/SignalRecipient.h index 8f5438d44a..e1ef16f7b0 100644 --- a/SignalServiceKit/src/Contacts/SignalRecipient.h +++ b/SignalServiceKit/src/Contacts/SignalRecipient.h @@ -36,13 +36,14 @@ NS_ASSUME_NONNULL_BEGIN - (NSComparisonResult)compare:(SignalRecipient *)other; -+ (BOOL)isRegisteredSignalAccount:(NSString *)recipientId transaction:(YapDatabaseReadTransaction *)transaction; ++ (BOOL)isRegisteredRecipient:(NSString *)recipientId transaction:(YapDatabaseReadTransaction *)transaction; -+ (SignalRecipient *)markAccountAsRegistered:(NSString *)recipientId transaction:(YapDatabaseReadWriteTransaction *)transaction; -+ (void)markAccountAsRegistered:(NSString *)recipientId - deviceId:(UInt32)deviceId - transaction:(YapDatabaseReadWriteTransaction *)transaction; -+ (void)markAccountAsNotRegistered:(NSString *)recipientId transaction:(YapDatabaseReadWriteTransaction *)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 diff --git a/SignalServiceKit/src/Contacts/SignalRecipient.m b/SignalServiceKit/src/Contacts/SignalRecipient.m index ad7e39cc5f..93d40bbf1b 100644 --- a/SignalServiceKit/src/Contacts/SignalRecipient.m +++ b/SignalServiceKit/src/Contacts/SignalRecipient.m @@ -146,7 +146,14 @@ NS_ASSUME_NONNULL_BEGIN [self addDevices:devices]; - SignalRecipient *latest = [SignalRecipient markAccountAsRegistered:self.recipientId transaction:transaction]; + 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]; } @@ -158,7 +165,14 @@ NS_ASSUME_NONNULL_BEGIN [self removeDevices:devices]; - SignalRecipient *latest = [SignalRecipient markAccountAsRegistered:self.recipientId transaction:transaction]; + 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]; } @@ -187,13 +201,14 @@ NS_ASSUME_NONNULL_BEGIN DDLogVerbose(@"%@ saved signal recipient: %@", self.logTag, self.recipientId); } -+ (BOOL)isRegisteredSignalAccount:(NSString *)recipientId transaction:(YapDatabaseReadTransaction *)transaction ++ (BOOL)isRegisteredRecipient:(NSString *)recipientId transaction:(YapDatabaseReadTransaction *)transaction { SignalRecipient *_Nullable instance = [self recipientForRecipientId:recipientId transaction:transaction]; return instance != nil; } -+ (SignalRecipient *)markAccountAsRegistered:(NSString *)recipientId transaction:(YapDatabaseReadWriteTransaction *)transaction ++ (SignalRecipient *)markRecipientAsRegisteredAndGet:(NSString *)recipientId + transaction:(YapDatabaseReadWriteTransaction *)transaction { OWSAssert(transaction); OWSAssert(recipientId.length > 0); @@ -209,14 +224,14 @@ NS_ASSUME_NONNULL_BEGIN return instance; } -+ (void)markAccountAsRegistered:(NSString *)recipientId - deviceId:(UInt32)deviceId - transaction:(YapDatabaseReadWriteTransaction *)transaction ++ (void)markRecipientAsRegistered:(NSString *)recipientId + deviceId:(UInt32)deviceId + transaction:(YapDatabaseReadWriteTransaction *)transaction { OWSAssert(transaction); OWSAssert(recipientId.length > 0); - SignalRecipient *recipient = [self markAccountAsRegistered:recipientId transaction:transaction]; + SignalRecipient *recipient = [self markRecipientAsRegisteredAndGet:recipientId transaction:transaction]; if (![recipient.devices containsObject:@(deviceId)]) { DDLogDebug(@"%@ in %s adding device %u to existing recipient.", self.logTag, @@ -228,7 +243,7 @@ NS_ASSUME_NONNULL_BEGIN } } -+ (void)markAccountAsNotRegistered:(NSString *)recipientId transaction:(YapDatabaseReadWriteTransaction *)transaction ++ (void)removeUnregisteredRecipient:(NSString *)recipientId transaction:(YapDatabaseReadWriteTransaction *)transaction { OWSAssert(transaction); OWSAssert(recipientId.length > 0); @@ -237,6 +252,7 @@ NS_ASSUME_NONNULL_BEGIN if (!instance) { return; } + DDLogDebug(@"%@ removing recipient: %@", self.logTag, recipientId); [instance removeWithTransaction:transaction]; } diff --git a/SignalServiceKit/src/Messages/OWSMessageDecrypter.m b/SignalServiceKit/src/Messages/OWSMessageDecrypter.m index ab4dafab67..78698d0562 100644 --- a/SignalServiceKit/src/Messages/OWSMessageDecrypter.m +++ b/SignalServiceKit/src/Messages/OWSMessageDecrypter.m @@ -110,9 +110,9 @@ NS_ASSUME_NONNULL_BEGIN DecryptSuccessBlock successBlock = ^(NSData *_Nullable plaintextData, YapDatabaseReadWriteTransaction *transaction) { - [SignalRecipient markAccountAsRegistered:envelope.source - deviceId:envelope.sourceDevice - transaction:transaction]; + [SignalRecipient markRecipientAsRegistered:envelope.source + deviceId:envelope.sourceDevice + transaction:transaction]; successBlockParameter(plaintextData, transaction); }; diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index c8960db373..b161f376dc 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -452,7 +452,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; OWSAssert(message); NSMutableArray *recipients = [NSMutableArray new]; - [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { for (NSString *recipientId in recipientIds) { SignalRecipient *recipient = [SignalRecipient getOrBuildUnsavedRecipientForRecipientId:recipientId transaction:transaction]; @@ -705,21 +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]; } - if (![SignalRecipient isRegisteredSignalAccount:recipient.recipientId transaction:transaction]) { + if (![SignalRecipient isRegisteredRecipient:recipient.recipientId transaction:transaction]) { return; } - [SignalRecipient markAccountAsNotRegistered:recipient.recipientId - transaction:transaction]; + [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. }]; } @@ -731,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: %@", @@ -773,7 +778,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; NSArray *deviceMessages; @try { - deviceMessages = [self deviceMessages:message forRecipient:recipient]; + deviceMessages = [self deviceMessages:message recipient:recipient]; } @catch (NSException *exception) { deviceMessages = @[]; if ([exception.name isEqualToString:UntrustedIdentityKeyException]) { @@ -908,6 +913,8 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; } else if (!mayHaveLinkedDevices && hasDeviceMessages) { OWSFail(@"%@ sync message has device messages for unknown secondary devices.", self.logTag); } + } else { + OWSAssert(deviceMessages.count > 0); } if (deviceMessages.count == 0) { @@ -1016,7 +1023,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; // If we've just delivered a message to a user, we know they // have a valid Signal account. - [SignalRecipient markAccountAsRegistered:recipient.recipientId transaction:transaction]; + [SignalRecipient markRecipientAsRegisteredAndGet:recipient.recipientId transaction:transaction]; }]; [self handleMessageSentLocally:message]; @@ -1066,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 " @@ -1079,23 +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; @@ -1108,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; } @@ -1225,8 +1250,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; }]; } -- (NSArray *)deviceMessages:(TSOutgoingMessage *)message - forRecipient:(SignalRecipient *)recipient +- (NSArray *)deviceMessages:(TSOutgoingMessage *)message recipient:(SignalRecipient *)recipient { OWSAssert(message); OWSAssert(recipient); @@ -1247,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 @@ -1284,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; @@ -1319,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" From 094cf3691d3ef9a97abb047a5e12de59587eec96 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Tue, 17 Jul 2018 10:37:26 -0400 Subject: [PATCH 12/14] Respond to CR. --- SignalServiceKit/src/Messages/OWSMessageSender.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index b161f376dc..0189774682 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -924,7 +924,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; // * 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 (device id = 0). For example, if they have unregistered + // 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 From 7f33236d6ca068001a9ac5ca657f2d42d33d4eb1 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Tue, 17 Jul 2018 16:58:00 -0400 Subject: [PATCH 13/14] Respond to CR. --- Signal/src/ViewControllers/DebugUI/DebugUIContacts.m | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Signal/src/ViewControllers/DebugUI/DebugUIContacts.m b/Signal/src/ViewControllers/DebugUI/DebugUIContacts.m index 88f7a9725d..21344687aa 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUIContacts.m +++ b/Signal/src/ViewControllers/DebugUI/DebugUIContacts.m @@ -55,13 +55,13 @@ NS_ASSUME_NONNULL_BEGIN actionBlock:^{ [DebugUIContacts clearSignalRecipientCache]; }], - [OWSTableItem itemWithTitle:@"New Invalid Contact Thread" + [OWSTableItem itemWithTitle:@"New Unregistered Contact Thread" actionBlock:^{ - [DebugUIContacts createInvalidContactThread]; + [DebugUIContacts createUnregisteredContactThread]; }], - [OWSTableItem itemWithTitle:@"New Invalid Group Thread" + [OWSTableItem itemWithTitle:@"New Unregistered Group Thread" actionBlock:^{ - [DebugUIContacts createInvalidGroupThread]; + [DebugUIContacts createUnregisteredGroupThread]; }], ]]; } @@ -1333,14 +1333,14 @@ NS_ASSUME_NONNULL_BEGIN return [recipientId copy]; } -+ (void)createInvalidContactThread ++ (void)createUnregisteredContactThread { NSString *recipientId = [self unregisteredRecipientId]; TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactId:recipientId]; [SignalApp.sharedApp presentConversationForThread:thread]; } -+ (void)createInvalidGroupThread ++ (void)createUnregisteredGroupThread { NSString *unregisteredRecipientId = [self unregisteredRecipientId]; NSString *validRecipientId = @"+19174054216"; From 899e96f70ff600f1ebe5e13ea8c7f0ae5e36b9ec Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Wed, 18 Jul 2018 14:25:30 -0400 Subject: [PATCH 14/14] Respond to CR. --- .../src/Contacts/SignalRecipient.m | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/SignalServiceKit/src/Contacts/SignalRecipient.m b/SignalServiceKit/src/Contacts/SignalRecipient.m index 93d40bbf1b..2790e59ab4 100644 --- a/SignalServiceKit/src/Contacts/SignalRecipient.m +++ b/SignalServiceKit/src/Contacts/SignalRecipient.m @@ -83,15 +83,6 @@ NS_ASSUME_NONNULL_BEGIN OWSAssert(transaction); OWSAssert(recipientId.length > 0); - return [self recipientForRecipientId:recipientId transaction:transaction]; -} - -+ (nullable instancetype)recipientForRecipientId:(NSString *)recipientId - transaction:(YapDatabaseReadTransaction *)transaction -{ - OWSAssert(transaction); - OWSAssert(recipientId.length > 0); - return [self fetchObjectWithUniqueID:recipientId transaction:transaction]; } @@ -101,7 +92,7 @@ NS_ASSUME_NONNULL_BEGIN __block SignalRecipient *recipient; [self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - recipient = [self recipientForRecipientId:recipientId transaction:transaction]; + recipient = [self registeredRecipientForRecipientId:recipientId transaction:transaction]; }]; return recipient; } @@ -189,6 +180,12 @@ 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]; @@ -203,7 +200,7 @@ NS_ASSUME_NONNULL_BEGIN + (BOOL)isRegisteredRecipient:(NSString *)recipientId transaction:(YapDatabaseReadTransaction *)transaction { - SignalRecipient *_Nullable instance = [self recipientForRecipientId:recipientId transaction:transaction]; + SignalRecipient *_Nullable instance = [self registeredRecipientForRecipientId:recipientId transaction:transaction]; return instance != nil; } @@ -213,7 +210,7 @@ NS_ASSUME_NONNULL_BEGIN OWSAssert(transaction); OWSAssert(recipientId.length > 0); - SignalRecipient *_Nullable instance = [self recipientForRecipientId:recipientId transaction:transaction]; + SignalRecipient *_Nullable instance = [self registeredRecipientForRecipientId:recipientId transaction:transaction]; if (!instance) { DDLogDebug(@"%@ creating recipient: %@", self.logTag, recipientId); @@ -248,7 +245,7 @@ NS_ASSUME_NONNULL_BEGIN OWSAssert(transaction); OWSAssert(recipientId.length > 0); - SignalRecipient *_Nullable instance = [self recipientForRecipientId:recipientId transaction:transaction]; + SignalRecipient *_Nullable instance = [self registeredRecipientForRecipientId:recipientId transaction:transaction]; if (!instance) { return; }