diff --git a/SignalServiceKit/src/Contacts/SignalRecipient.h b/SignalServiceKit/src/Contacts/SignalRecipient.h index 3d4763db0..46481f14c 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 a5a30d510..27fd1577c 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 0ea500c23..89dd4a9fe 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; }