diff --git a/Signal/src/ViewControllers/AppSettings/OWSLinkDeviceViewController.m b/Signal/src/ViewControllers/AppSettings/OWSLinkDeviceViewController.m index 5312a5082..79c01657b 100644 --- a/Signal/src/ViewControllers/AppSettings/OWSLinkDeviceViewController.m +++ b/Signal/src/ViewControllers/AppSettings/OWSLinkDeviceViewController.m @@ -46,6 +46,8 @@ NS_ASSUME_NONNULL_BEGIN = NSLocalizedString(@"LINK_NEW_DEVICE_TITLE", "Navigation title when scanning QR code to add new device."); } +#pragma mark - Dependencies + - (OWSProfileManager *)profileManager { return [OWSProfileManager sharedManager]; @@ -56,6 +58,23 @@ NS_ASSUME_NONNULL_BEGIN return [OWSReadReceiptManager sharedManager]; } +- (id)udManager +{ + return SSKEnvironment.shared.udManager; +} + +- (TSAccountManager *)tsAccountManager +{ + return TSAccountManager.sharedInstance; +} + +- (TSSocketManager *)socketManager +{ + return SSKEnvironment.shared.socketManager; +} + +#pragma mark - + - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; @@ -173,6 +192,13 @@ NS_ASSUME_NONNULL_BEGIN // The service implementation of the socket connection caches the linked device state, // so all sync message sends will fail on the socket until it is cycled. [TSSocketManager.shared cycleSocket]; + + [self.udManager setUnidentifiedAccessMode:UnidentifiedAccessModeUnknown + recipientId:self.tsAccountManager.localNumber]; + + // Fetch the local profile to determine if all + // linked devices support UD. + [self.profileManager fetchLocalUsersProfile]; }); } failure:^(NSError *error) { diff --git a/SignalMessaging/profiles/OWSProfileManager.m b/SignalMessaging/profiles/OWSProfileManager.m index befff39e7..1f320c63b 100644 --- a/SignalMessaging/profiles/OWSProfileManager.m +++ b/SignalMessaging/profiles/OWSProfileManager.m @@ -525,7 +525,14 @@ typedef void (^ProfileManagerFailureBlock)(NSError *error); if (!localNumber) { return; } - [ProfileFetcherJob runWithRecipientId:localNumber ignoreThrottling:YES]; + [self fetchProfileForRecipientId:localNumber]; +} + +- (void)fetchProfileForRecipientId:(NSString *)recipientId +{ + OWSAssertIsOnMainThread(); + + [ProfileFetcherJob runWithRecipientId:recipientId ignoreThrottling:YES]; } #pragma mark - Profile Key Rotation @@ -997,8 +1004,7 @@ typedef void (^ProfileManagerFailureBlock)(NSError *error); dbConnection:self.dbConnection completion:^{ dispatch_async(dispatch_get_main_queue(), ^(void) { - [ProfileFetcherJob runWithRecipientId:recipientId - ignoreThrottling:YES]; + [self fetchProfileForRecipientId:recipientId]; }); }]; }); diff --git a/SignalServiceKit/src/Contacts/SignalRecipient.m b/SignalServiceKit/src/Contacts/SignalRecipient.m index 89a2b1ef1..4ceda6a2e 100644 --- a/SignalServiceKit/src/Contacts/SignalRecipient.m +++ b/SignalServiceKit/src/Contacts/SignalRecipient.m @@ -4,7 +4,10 @@ #import "SignalRecipient.h" #import "OWSDevice.h" +#import "ProfileManagerProtocol.h" +#import "SSKEnvironment.h" #import "TSAccountManager.h" +#import #import NS_ASSUME_NONNULL_BEGIN @@ -19,6 +22,20 @@ NS_ASSUME_NONNULL_BEGIN @implementation SignalRecipient +#pragma mark - Dependencies + +- (id)profileManager +{ + return SSKEnvironment.shared.profileManager; +} + +- (id)udManager +{ + return SSKEnvironment.shared.udManager; +} + +#pragma mark - + + (instancetype)getOrBuildUnsavedRecipientForRecipientId:(NSString *)recipientId transaction:(YapDatabaseReadTransaction *)transaction { @@ -127,6 +144,17 @@ NS_ASSUME_NONNULL_BEGIN if (devicesToRemove.count > 0) { [self removeDevicesFromRecipient:[NSSet setWithArray:devicesToRemove] transaction:transaction]; } + + // Device changes + dispatch_async(dispatch_get_main_queue(), ^{ + // Device changes can affect the UD access mode for a recipient, + // so we need to: + // + // * Mark the UD access mode as "unknown". + // * Fetch the profile for this user to update UD access mode. + [self.udManager setUnidentifiedAccessMode:UnidentifiedAccessModeUnknown recipientId:self.recipientId]; + [self.profileManager fetchProfileForRecipientId:self.recipientId]; + }); } - (void)addDevicesToRegisteredRecipient:(NSSet *)devices transaction:(YapDatabaseReadWriteTransaction *)transaction diff --git a/SignalServiceKit/src/Devices/OWSDevice.m b/SignalServiceKit/src/Devices/OWSDevice.m index 87b41d4e8..b831ad55a 100644 --- a/SignalServiceKit/src/Devices/OWSDevice.m +++ b/SignalServiceKit/src/Devices/OWSDevice.m @@ -5,11 +5,15 @@ #import "OWSDevice.h" #import "OWSError.h" #import "OWSPrimaryStorage.h" +#import "ProfileManagerProtocol.h" +#import "SSKEnvironment.h" +#import "TSAccountManager.h" #import "YapDatabaseConnection+OWS.h" #import "YapDatabaseConnection.h" #import "YapDatabaseTransaction.h" #import #import +#import NS_ASSUME_NONNULL_BEGIN @@ -112,6 +116,30 @@ NSString *const kOWSPrimaryStorage_MayHaveLinkedDevices = @"kTSStorageManager_Ma @implementation OWSDevice +#pragma mark - Dependencies + ++ (id)profileManager +{ + return SSKEnvironment.shared.profileManager; +} + ++ (id)udManager +{ + return SSKEnvironment.shared.udManager; +} + ++ (TSAccountManager *)tsAccountManager +{ + return TSAccountManager.sharedInstance; +} + +#pragma mark - + +- (void)saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction +{ + [super saveWithTransaction:transaction]; +} + + (nullable instancetype)deviceFromJSONDictionary:(NSDictionary *)deviceAttributes error:(NSError **)error { OWSDevice *device = [MTLJSONAdapter modelOfClass:[self class] fromJSONDictionary:deviceAttributes error:error]; @@ -145,16 +173,19 @@ NSString *const kOWSPrimaryStorage_MayHaveLinkedDevices = @"kTSStorageManager_Ma + (void)replaceAll:(NSArray *)currentDevices { + BOOL didChange = NO; NSMutableArray *existingDevices = [[self allObjectsInCollection] mutableCopy]; for (OWSDevice *currentDevice in currentDevices) { NSUInteger existingDeviceIndex = [existingDevices indexOfObject:currentDevice]; if (existingDeviceIndex == NSNotFound) { // New Device [currentDevice save]; + didChange = YES; } else { OWSDevice *existingDevice = existingDevices[existingDeviceIndex]; if ([existingDevice updateAttributesWithDevice:currentDevice]) { [existingDevice save]; + didChange = YES; } [existingDevices removeObjectAtIndex:existingDeviceIndex]; } @@ -163,6 +194,20 @@ NSString *const kOWSPrimaryStorage_MayHaveLinkedDevices = @"kTSStorageManager_Ma // Since we removed existing devices as we went, only stale devices remain for (OWSDevice *staleDevice in existingDevices) { [staleDevice remove]; + didChange = YES; + } + + if (didChange) { + dispatch_async(dispatch_get_main_queue(), ^{ + // Device changes can affect the UD access mode for a recipient, + // so we need to: + // + // * Mark the UD access mode as "unknown". + // * Fetch the profile for this user to update UD access mode. + [self.udManager setUnidentifiedAccessMode:UnidentifiedAccessModeUnknown + recipientId:self.tsAccountManager.localNumber]; + [self.profileManager fetchLocalUsersProfile]; + }); } } diff --git a/SignalServiceKit/src/Messages/OWSMessageSend.swift b/SignalServiceKit/src/Messages/OWSMessageSend.swift index b192f8bf9..6832f53ee 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSend.swift +++ b/SignalServiceKit/src/Messages/OWSMessageSend.swift @@ -79,9 +79,13 @@ public class OWSMessageSend: NSObject { } @objc - public func setHasUDAuthFailed() { - // We "fail over" to non-UD sends after auth errors sending via UD. + public func disableUD() { unidentifiedAccess = nil } + @objc + public func setHasUDAuthFailed() { + // We "fail over" to non-UD sends after auth errors sending via UD. + disableUD() + } } diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index 181878f02..cc55cedff 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -1016,6 +1016,11 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; OWSLogWarn(@"Sending a message with no device messages."); } + if ([message isKindOfClass:[OWSOutgoingSyncMessage class]] + && ![message isKindOfClass:[OWSOutgoingSentMessageTranscript class]]) { + [messageSend disableUD]; + } + OWSRequestMaker *requestMaker = [[OWSRequestMaker alloc] initWithRequestFactoryBlock:^(SSKUnidentifiedAccess *_Nullable unidentifiedAccess) { return [OWSRequestFactory submitMessageRequestWithRecipient:recipient.recipientId diff --git a/SignalServiceKit/src/Protocols/ProfileManagerProtocol.h b/SignalServiceKit/src/Protocols/ProfileManagerProtocol.h index 2537676f7..be08179ac 100644 --- a/SignalServiceKit/src/Protocols/ProfileManagerProtocol.h +++ b/SignalServiceKit/src/Protocols/ProfileManagerProtocol.h @@ -23,6 +23,8 @@ NS_ASSUME_NONNULL_BEGIN - (void)fetchLocalUsersProfile; +- (void)fetchProfileForRecipientId:(NSString *)recipientId; + @end NS_ASSUME_NONNULL_END