diff --git a/SignalServiceKit/src/Contacts/Contact.m b/SignalServiceKit/src/Contacts/Contact.m index c088eda73..0d362cc22 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 6f1d993d5..14611f818 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 062b19ab9..cb614f4e8 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 +{ + 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)recipientForRecipientId:(NSString *)recipientId + transaction:(YapDatabaseReadTransaction *)transaction { - return [self fetchObjectWithUniqueID:textSecureIdentifier transaction:transaction]; + OWSAssert(transaction); + OWSAssert(recipientId.length > 0); + + return [self fetchObjectWithUniqueID:recipientId transaction:transaction]; } -+ (nullable instancetype)recipientWithTextSecureIdentifier:(NSString *)textSecureIdentifier ++ (nullable instancetype)recipientForRecipientId:(NSString *)recipientId { + OWSAssert(recipientId.length > 0); + __block SignalRecipient *recipient; - [self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) { - recipient = [self recipientWithTextSecureIdentifier:textSecureIdentifier withTransaction:transaction]; + [self.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { + recipient = [self 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 a0e80f1a6..a06b73cd2 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];