From 526d5e33b982f401ad649f7dbab37fc207089d3e Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Sat, 26 Aug 2017 17:45:05 -0400 Subject: [PATCH] Sync profile key to sibling devices when updating contact // FREEBIE --- Signal.xcodeproj/project.pbxproj | 6 ++ .../src/MultiDeviceProfileKeyUpdateJob.swift | 55 +++++++++++++++++++ Signal/src/Profiles/OWSProfileManager.m | 11 ++++ Signal/src/Signal-Bridging-Header.h | 2 + Signal/src/util/OWSContactsSyncing.m | 7 ++- .../DeviceSyncing/OWSSyncContactsMessage.h | 8 +-- .../DeviceSyncing/OWSSyncContactsMessage.m | 15 ++--- .../src/Messages/TSMessagesManager.m | 8 +-- 8 files changed, 94 insertions(+), 18 deletions(-) create mode 100644 Signal/src/MultiDeviceProfileKeyUpdateJob.swift diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index e2cfc63c1..e694be133 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -115,6 +115,8 @@ 4509E79A1DD653700025A59F /* WebRTC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4509E7991DD653700025A59F /* WebRTC.framework */; }; 450DF2051E0D74AC003D14BE /* Platform.swift in Sources */ = {isa = PBXBuildFile; fileRef = 450DF2041E0D74AC003D14BE /* Platform.swift */; }; 450DF2091E0DD2C6003D14BE /* UserNotificationsAdaptee.swift in Sources */ = {isa = PBXBuildFile; fileRef = 450DF2081E0DD2C6003D14BE /* UserNotificationsAdaptee.swift */; }; + 451686AB1F520CDA00AC3D4B /* MultiDeviceProfileKeyUpdateJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 451686AA1F520CDA00AC3D4B /* MultiDeviceProfileKeyUpdateJob.swift */; }; + 451686AC1F520CDA00AC3D4B /* MultiDeviceProfileKeyUpdateJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 451686AA1F520CDA00AC3D4B /* MultiDeviceProfileKeyUpdateJob.swift */; }; 4516E3FF1DD2193B00DC4206 /* OWS101ExistingUsersBlockOnIdentityChange.m in Sources */ = {isa = PBXBuildFile; fileRef = 4516E3FE1DD2193B00DC4206 /* OWS101ExistingUsersBlockOnIdentityChange.m */; }; 4517642A1DE939FD00EDB8B9 /* ContactCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 451764281DE939FD00EDB8B9 /* ContactCell.xib */; }; 4517642B1DE939FD00EDB8B9 /* ContactCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 451764291DE939FD00EDB8B9 /* ContactCell.swift */; }; @@ -578,6 +580,7 @@ 4509E7991DD653700025A59F /* WebRTC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebRTC.framework; path = Carthage/Build/iOS/WebRTC.framework; sourceTree = ""; }; 450DF2041E0D74AC003D14BE /* Platform.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Platform.swift; sourceTree = ""; }; 450DF2081E0DD2C6003D14BE /* UserNotificationsAdaptee.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; name = UserNotificationsAdaptee.swift; path = UserInterface/Notifications/UserNotificationsAdaptee.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; + 451686AA1F520CDA00AC3D4B /* MultiDeviceProfileKeyUpdateJob.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultiDeviceProfileKeyUpdateJob.swift; sourceTree = ""; }; 4516E3FD1DD2193B00DC4206 /* OWS101ExistingUsersBlockOnIdentityChange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWS101ExistingUsersBlockOnIdentityChange.h; path = Migrations/OWS101ExistingUsersBlockOnIdentityChange.h; sourceTree = ""; }; 4516E3FE1DD2193B00DC4206 /* OWS101ExistingUsersBlockOnIdentityChange.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWS101ExistingUsersBlockOnIdentityChange.m; path = Migrations/OWS101ExistingUsersBlockOnIdentityChange.m; sourceTree = ""; }; 451764281DE939FD00EDB8B9 /* ContactCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ContactCell.xib; sourceTree = ""; }; @@ -1276,6 +1279,7 @@ 45D231761DC7E8F10034FA89 /* SessionResetJob.swift */, 452ECA4C1E087E7200E2F016 /* MessageFetcherJob.swift */, 4585C4651ED5DF7A00896AEA /* ProfileFetcherJob.swift */, + 451686AA1F520CDA00AC3D4B /* MultiDeviceProfileKeyUpdateJob.swift */, ); name = Jobs; sourceTree = ""; @@ -2247,6 +2251,7 @@ 34CE88E71F2FB9A10098030F /* ProfileViewController.m in Sources */, 348F2EAE1F0D21BC00D4ECE0 /* DeviceSleepManager.swift in Sources */, 34E3EF101EFC2684007F6822 /* DebugUIPage.m in Sources */, + 451686AB1F520CDA00AC3D4B /* MultiDeviceProfileKeyUpdateJob.swift in Sources */, 76EB058A18170B33006006FC /* Release.m in Sources */, 45D231771DC7E8F10034FA89 /* SessionResetJob.swift in Sources */, 4563ADF11F22BD7100DEB8C7 /* OWS106EnsureProfileComplete.swift in Sources */, @@ -2462,6 +2467,7 @@ B660F6E01C29868000687D6E /* UtilTest.m in Sources */, 45F3AEB71DFDE7900080CE33 /* AvatarImageView.swift in Sources */, B660F6DA1C29868000687D6E /* ExceptionsTest.m in Sources */, + 451686AC1F520CDA00AC3D4B /* MultiDeviceProfileKeyUpdateJob.swift in Sources */, 45C9DEB91DF4E35A0065CA84 /* WebRTCCallMessageHandler.swift in Sources */, B660F6DB1C29868000687D6E /* FunctionalUtilTest.m in Sources */, 45E7A6A81E71CA7E00D44FB5 /* DisplayableTextFilterTest.swift in Sources */, diff --git a/Signal/src/MultiDeviceProfileKeyUpdateJob.swift b/Signal/src/MultiDeviceProfileKeyUpdateJob.swift new file mode 100644 index 000000000..8023b304f --- /dev/null +++ b/Signal/src/MultiDeviceProfileKeyUpdateJob.swift @@ -0,0 +1,55 @@ +// +// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// + +import Foundation +import PromiseKit + +@objc class MultiDeviceProfileKeyUpdateJob: NSObject { + + let TAG = "[MultiDeviceProfileKeyUpdateJob]" + + let profileKey: OWSAES256Key + let identityManager: OWSIdentityManager + let messageSender: MessageSender + let profileManager: OWSProfileManager + + required init(profileKey: OWSAES256Key, identityManager: OWSIdentityManager, messageSender: MessageSender, profileManager: OWSProfileManager) { + self.profileKey = profileKey + + self.identityManager = identityManager + self.messageSender = messageSender + self.profileManager = profileManager + } + + class func run(profileKey: OWSAES256Key, identityManager: OWSIdentityManager, messageSender: MessageSender, profileManager: OWSProfileManager) { + return self.init(profileKey: profileKey, identityManager: identityManager, messageSender: messageSender, profileManager: profileManager).run() + } + + func run(retryDelay: TimeInterval = 1) { + guard let localNumber = TSAccountManager.localNumber() else { + owsFail("\(self.TAG) localNumber was unexpectedly nil") + return + } + + let localSignalAccount = SignalAccount(recipientId: localNumber) + localSignalAccount.contact = Contact() + let syncContactsMessage = OWSSyncContactsMessage(signalAccounts: [localSignalAccount], + identityManager: self.identityManager, + profileManager: self.profileManager) + + self.messageSender.sendTemporaryAttachmentData(syncContactsMessage.buildPlainTextAttachmentData(), + contentType: OWSMimeTypeApplicationOctetStream, + in: syncContactsMessage, + success: { + Logger.info("\(self.TAG) Successfully synced profile key") + + }, + failure: { error in + Logger.error("\(self.TAG) in \(#function) failed with error: \(error) retrying in \(retryDelay)s.") + after(seconds: retryDelay).then { + self.run(retryDelay: retryDelay * 2) + }.retainUntilComplete() + }) + } +} diff --git a/Signal/src/Profiles/OWSProfileManager.m b/Signal/src/Profiles/OWSProfileManager.m index 0a4fc99d5..209b5415c 100644 --- a/Signal/src/Profiles/OWSProfileManager.m +++ b/Signal/src/Profiles/OWSProfileManager.m @@ -105,6 +105,7 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; @property (nonatomic, readonly) OWSMessageSender *messageSender; @property (nonatomic, readonly) YapDatabaseConnection *dbConnection; @property (nonatomic, readonly) TSNetworkManager *networkManager; +@property (nonatomic, readonly) OWSIdentityManager *identityManager; // This property can be accessed on any thread, while synchronized on self. @property (nonatomic, readonly) UserProfile *localUserProfile; @@ -199,6 +200,11 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; return [OWSSignalService sharedInstance].CDNSessionManager; } +- (OWSIdentityManager *)identityManager +{ + return [OWSIdentityManager sharedManager]; +} + #pragma mark - User Profile Accessor // This method can be safely called from any thread. @@ -236,6 +242,11 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; dispatch_async(dispatch_get_main_queue(), ^{ if (isLocalUserProfile) { + [MultiDeviceProfileKeyUpdateJob runWithProfileKey:userProfile.profileKey + identityManager:self.identityManager + messageSender:self.messageSender + profileManager:self]; + [[NSNotificationCenter defaultCenter] postNotificationName:kNSNotificationName_LocalProfileDidChange object:nil userInfo:nil]; diff --git a/Signal/src/Signal-Bridging-Header.h b/Signal/src/Signal-Bridging-Header.h index 60c3a7b63..d155318f0 100644 --- a/Signal/src/Signal-Bridging-Header.h +++ b/Signal/src/Signal-Bridging-Header.h @@ -60,6 +60,7 @@ #import #import #import +#import #import #import #import @@ -71,6 +72,7 @@ #import #import #import +#import #import #import #import diff --git a/Signal/src/util/OWSContactsSyncing.m b/Signal/src/util/OWSContactsSyncing.m index d4f4ad301..35ebf7b03 100644 --- a/Signal/src/util/OWSContactsSyncing.m +++ b/Signal/src/util/OWSContactsSyncing.m @@ -94,9 +94,10 @@ NSString *const kTSStorageManagerOWSContactsSyncingLastMessageKey = return; } - OWSSyncContactsMessage *syncContactsMessage = [[OWSSyncContactsMessage alloc] initWithContactsManager:self.contactsManager - identityManager:self.identityManager - profileManager:self.profileManager]; + OWSSyncContactsMessage *syncContactsMessage = + [[OWSSyncContactsMessage alloc] initWithSignalAccounts:self.contactsManager.signalAccounts + identityManager:self.identityManager + profileManager:self.profileManager]; NSData *messageData = [syncContactsMessage buildPlainTextAttachmentData]; diff --git a/SignalServiceKit/src/Messages/DeviceSyncing/OWSSyncContactsMessage.h b/SignalServiceKit/src/Messages/DeviceSyncing/OWSSyncContactsMessage.h index d948751e1..3cd3a1ad1 100644 --- a/SignalServiceKit/src/Messages/DeviceSyncing/OWSSyncContactsMessage.h +++ b/SignalServiceKit/src/Messages/DeviceSyncing/OWSSyncContactsMessage.h @@ -6,15 +6,15 @@ NS_ASSUME_NONNULL_BEGIN -@protocol ContactsManagerProtocol; @protocol ProfileManagerProtocol; +@class SignalAccount; @class OWSIdentityManager; @interface OWSSyncContactsMessage : OWSOutgoingSyncMessage -- (instancetype)initWithContactsManager:(id)contactsManager - identityManager:(OWSIdentityManager *)identityManager - profileManager:(id)profileManager; +- (instancetype)initWithSignalAccounts:(NSArray *)signalAccounts + identityManager:(OWSIdentityManager *)identityManager + profileManager:(id)profileManager; - (NSData *)buildPlainTextAttachmentData; diff --git a/SignalServiceKit/src/Messages/DeviceSyncing/OWSSyncContactsMessage.m b/SignalServiceKit/src/Messages/DeviceSyncing/OWSSyncContactsMessage.m index df43c163c..0dd4172b8 100644 --- a/SignalServiceKit/src/Messages/DeviceSyncing/OWSSyncContactsMessage.m +++ b/SignalServiceKit/src/Messages/DeviceSyncing/OWSSyncContactsMessage.m @@ -18,7 +18,7 @@ NS_ASSUME_NONNULL_BEGIN @interface OWSSyncContactsMessage () -@property (nonatomic, readonly) id contactsManager; +@property (nonatomic, readonly) NSArray *signalAccounts; @property (nonatomic, readonly) OWSIdentityManager *identityManager; @property (nonatomic, readonly) id profileManager; @@ -26,16 +26,16 @@ NS_ASSUME_NONNULL_BEGIN @implementation OWSSyncContactsMessage -- (instancetype)initWithContactsManager:(id)contactsManager - identityManager:(OWSIdentityManager *)identityManager - profileManager:(id)profileManager +- (instancetype)initWithSignalAccounts:(NSArray *)signalAccounts + identityManager:(OWSIdentityManager *)identityManager + profileManager:(id)profileManager { self = [super initWithTimestamp:[NSDate ows_millisecondTimeStamp]]; if (!self) { return self; } - _contactsManager = contactsManager; + _signalAccounts = signalAccounts; _identityManager = identityManager; _profileManager = profileManager; @@ -73,8 +73,9 @@ NS_ASSUME_NONNULL_BEGIN [dataOutputStream open]; OWSContactsOutputStream *contactsOutputStream = [OWSContactsOutputStream streamWithOutputStream:dataOutputStream]; - for (SignalAccount *signalAccount in self.contactsManager.signalAccounts) { - OWSRecipientIdentity *recipientIdentity = [self.identityManager recipientIdentityForRecipientId:signalAccount.recipientId]; + for (SignalAccount *signalAccount in self.signalAccounts) { + OWSRecipientIdentity *_Nullable recipientIdentity = + [self.identityManager recipientIdentityForRecipientId:signalAccount.recipientId]; NSData *_Nullable profileKeyData = [self.profileManager profileKeyDataForRecipientId:signalAccount.recipientId]; [contactsOutputStream writeSignalAccount:signalAccount diff --git a/SignalServiceKit/src/Messages/TSMessagesManager.m b/SignalServiceKit/src/Messages/TSMessagesManager.m index a36a34b07..9d493671f 100644 --- a/SignalServiceKit/src/Messages/TSMessagesManager.m +++ b/SignalServiceKit/src/Messages/TSMessagesManager.m @@ -731,10 +731,10 @@ NS_ASSUME_NONNULL_BEGIN } else if (syncMessage.hasRequest) { if (syncMessage.request.type == OWSSignalServiceProtosSyncMessageRequestTypeContacts) { OWSSyncContactsMessage *syncContactsMessage = - [[OWSSyncContactsMessage alloc] initWithContactsManager:self.contactsManager - identityManager:self.identityManager - profileManager:self.profileManager]; - + [[OWSSyncContactsMessage alloc] initWithSignalAccounts:self.contactsManager.signalAccounts + identityManager:self.identityManager + profileManager:self.profileManager]; + [self.messageSender sendTemporaryAttachmentData:[syncContactsMessage buildPlainTextAttachmentData] contentType:OWSMimeTypeApplicationOctetStream inMessage:syncContactsMessage