From 9fc386b803bd77aac2a7ef0928924f9e0702edc8 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Wed, 6 May 2020 13:24:38 +1000 Subject: [PATCH] Fix closed group and contact syncing. --- .../Loki/Database/OWSPrimaryStorage+Loki.h | 2 +- .../Loki/Database/OWSPrimaryStorage+Loki.m | 10 +++++++ .../FriendRequestProtocol.swift | 4 ++- .../FriendRequestProtocolTests.swift | 16 +++++++++++ .../Sync Messages/SyncMessagesProtocol.swift | 28 ++++++++----------- .../src/Messages/OWSMessageSender.m | 5 ++++ 6 files changed, 46 insertions(+), 19 deletions(-) diff --git a/SignalServiceKit/src/Loki/Database/OWSPrimaryStorage+Loki.h b/SignalServiceKit/src/Loki/Database/OWSPrimaryStorage+Loki.h index 7677af1f4..155a60524 100644 --- a/SignalServiceKit/src/Loki/Database/OWSPrimaryStorage+Loki.h +++ b/SignalServiceKit/src/Loki/Database/OWSPrimaryStorage+Loki.h @@ -62,10 +62,10 @@ typedef NS_ENUM(NSInteger, LKFriendRequestStatus) { # pragma mark - Friend Requests +- (NSSet *)getAllFriendsWithTransaction:(YapDatabaseReadTransaction *)transaction NS_SWIFT_NAME(getAllFriends(using:)); - (LKFriendRequestStatus)getFriendRequestStatusForContact:(NSString *)hexEncodedPublicKey transaction:(YapDatabaseReadTransaction *)transaction NS_SWIFT_NAME(getFriendRequestStatus(for:transaction:)); - (void)setFriendRequestStatus:(LKFriendRequestStatus)friendRequestStatus forContact:(NSString *)hexEncodedPublicKey transaction:(YapDatabaseReadWriteTransaction *)transaction NS_SWIFT_NAME(setFriendRequestStatus(_:for:transaction:)); - @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Loki/Database/OWSPrimaryStorage+Loki.m b/SignalServiceKit/src/Loki/Database/OWSPrimaryStorage+Loki.m index 2abb49798..7398f76e7 100644 --- a/SignalServiceKit/src/Loki/Database/OWSPrimaryStorage+Loki.m +++ b/SignalServiceKit/src/Loki/Database/OWSPrimaryStorage+Loki.m @@ -226,6 +226,16 @@ #define LKFriendRequestCollection @"LKFriendRequestCollection" +- (NSSet *)getAllFriendsWithTransaction:(YapDatabaseReadTransaction *)transaction { + NSMutableSet *hexEncodedPublicKeys = [NSMutableSet set]; + [transaction enumerateKeysAndObjectsInCollection:LKFriendRequestCollection usingBlock:^(NSString *hexEncodedPublicKey, NSNumber *status, BOOL * _Nonnull stop) { + if ([status integerValue] == LKFriendRequestStatusFriends) { + [hexEncodedPublicKeys addObject:hexEncodedPublicKey]; + } + }]; + return hexEncodedPublicKeys; +} + - (LKFriendRequestStatus)getFriendRequestStatusForContact:(NSString *)hexEncodedPublicKey transaction:(YapDatabaseReadTransaction *)transaction { NSNumber *_Nullable status = [transaction objectForKey:hexEncodedPublicKey inCollection:LKFriendRequestCollection]; if (status == nil) { return LKFriendRequestStatusNone; } diff --git a/SignalServiceKit/src/Loki/Protocol/Friend Requests/FriendRequestProtocol.swift b/SignalServiceKit/src/Loki/Protocol/Friend Requests/FriendRequestProtocol.swift index 923711449..1819fcc04 100644 --- a/SignalServiceKit/src/Loki/Protocol/Friend Requests/FriendRequestProtocol.swift +++ b/SignalServiceKit/src/Loki/Protocol/Friend Requests/FriendRequestProtocol.swift @@ -170,6 +170,8 @@ public final class FriendRequestProtocol : NSObject { @objc(shouldUpdateFriendRequestStatusFromMessage:) public static func shouldUpdateFriendRequestStatus(from message: TSOutgoingMessage) -> Bool { // The order of these checks matters + if (message.thread.isGroupThread()) { return false } + if (message.thread.contactIdentifier() == getUserHexEncodedPublicKey()) { return false } if (message as? DeviceLinkMessage)?.kind == .request { return true } if message is SessionRequestMessage { return false } return message is FriendRequestMessage @@ -243,7 +245,7 @@ public final class FriendRequestProtocol : NSObject { // Signal cipher decryption and thus that we have a session with the other person. let friendRequestStatus = storage.getFriendRequestStatus(for: hexEncodedPublicKey, transaction: transaction); // We shouldn't be able to skip from none to friends - guard friendRequestStatus != .none else { return } + guard friendRequestStatus != .none && friendRequestStatus != .friends else { return } // Become friends storage.setFriendRequestStatus(.friends, for: hexEncodedPublicKey, transaction: transaction) // Send a contact sync message if needed diff --git a/SignalServiceKit/src/Loki/Protocol/Friend Requests/FriendRequestProtocolTests.swift b/SignalServiceKit/src/Loki/Protocol/Friend Requests/FriendRequestProtocolTests.swift index e7c066bc5..d9a980a1c 100644 --- a/SignalServiceKit/src/Loki/Protocol/Friend Requests/FriendRequestProtocolTests.swift +++ b/SignalServiceKit/src/Loki/Protocol/Friend Requests/FriendRequestProtocolTests.swift @@ -622,6 +622,7 @@ class FriendRequestProtocolTests : XCTestCase { } // MARK: - shouldUpdateFriendRequestStatus + func test_shouldUpdateFriendRequestStatusReturnsTheCorrectValue() { let thread = LokiTestUtilities.createContactThread(for: LokiTestUtilities.generateHexEncodedPublicKey()) @@ -637,4 +638,19 @@ class FriendRequestProtocolTests : XCTestCase { XCTAssertFalse(FriendRequestProtocol.shouldUpdateFriendRequestStatus(from: sessionRequest)) XCTAssertFalse(FriendRequestProtocol.shouldUpdateFriendRequestStatus(from: deviceLinkAuthorisation)) } + + func test_shouldUpdateFriendRequestStatusReturnsFalseForGroupThreads() { + let allGroupTypes: [GroupType] = [ .closedGroup, .openGroup, .rssFeed ] + for groupType in allGroupTypes { + guard let groupThread = LokiTestUtilities.createGroupThread(groupType: groupType) else { return XCTFail() } + let friendRequest = FriendRequestMessage(timestamp: 1, thread: groupThread, body: "") + XCTAssertFalse(FriendRequestProtocol.shouldUpdateFriendRequestStatus(from: friendRequest)) + } + } + + func test_shouldUpdateFriendRequestStatusReturnsFalseForCurrentDevice() { + let thread = LokiTestUtilities.createContactThread(for: LokiTestUtilities.getCurrentUserHexEncodedPublicKey()) + let friendRequest = FriendRequestMessage(timestamp: 1, thread: thread, body: "") + XCTAssertFalse(FriendRequestProtocol.shouldUpdateFriendRequestStatus(from: friendRequest)) + } } diff --git a/SignalServiceKit/src/Loki/Protocol/Sync Messages/SyncMessagesProtocol.swift b/SignalServiceKit/src/Loki/Protocol/Sync Messages/SyncMessagesProtocol.swift index d7e905e4b..30a275246 100644 --- a/SignalServiceKit/src/Loki/Protocol/Sync Messages/SyncMessagesProtocol.swift +++ b/SignalServiceKit/src/Loki/Protocol/Sync Messages/SyncMessagesProtocol.swift @@ -36,22 +36,16 @@ public final class SyncMessagesProtocol : NSObject { } public static func syncAllContacts() -> Promise { - // Collect all master devices with which a session has been established. Note that - // this is not the same as all master devices with which we're friends. - var hepks: Set = [] - TSContactThread.enumerateCollectionObjects { object, _ in - guard let thread = object as? TSContactThread else { return } - let hexEncodedPublicKey = thread.contactIdentifier() - guard thread.isContactFriend && thread.shouldThreadBeVisible && !thread.isSlaveThread else { return } - hepks.insert(hexEncodedPublicKey) + // We need to sync over all contacts whom we are friends with. + var hepks: [String] = [] + storage.dbReadConnection.read { transaction in + hepks = self.storage + .getAllFriends(using: transaction) + .filter { ECKeyPair.isValidHexEncodedPublicKey(candidate: $0) } + .map { storage.getMasterHexEncodedPublicKey(for: $0, in: transaction) ?? $0 } } - TSGroupThread.enumerateCollectionObjects { object, _ in - guard let group = object as? TSGroupThread, group.groupModel.groupType == .closedGroup, - group.shouldThreadBeVisible else { return } - hepks.formUnion(group.groupModel.groupMemberIds) - } - hepks.insert(getUserHexEncodedPublicKey()) // TODO: Are we sure about this? - let friends = hepks.map { SignalAccount(recipientId: $0) } + + let friends = Set(hepks).map { SignalAccount(recipientId: $0) } let syncManager = SSKEnvironment.shared.syncManager let promises = friends.chunked(by: 3).map { friends -> Promise in // TODO: Does this always fit? return Promise(syncManager.syncContacts(for: friends)).map { _ in } @@ -172,10 +166,10 @@ public final class SyncMessagesProtocol : NSObject { public static func handleContactSyncMessageData(_ data: Data, using transaction: YapDatabaseReadWriteTransaction) { let parser = ContactParser(data: data) let hexEncodedPublicKeys = parser.parseHexEncodedPublicKeys() - let linkedDevices = LokiDatabaseUtilities.getLinkedDeviceHexEncodedPublicKeys(for: getUserHexEncodedPublicKey(), in: transaction) + let ourHexEncodedPublicKey = getUserHexEncodedPublicKey() // Try to establish sessions for hexEncodedPublicKey in hexEncodedPublicKeys { - guard !linkedDevices.contains(hexEncodedPublicKey) else { continue } // Skip self + guard hexEncodedPublicKey != ourHexEncodedPublicKey else { continue } // Skip self // We don't update the friend request status; that's done in OWSMessageSender.sendMessage(_:) let friendRequestStatus = storage.getFriendRequestStatus(for: hexEncodedPublicKey, transaction: transaction) switch friendRequestStatus { diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index 8c7dfbd89..cb2625b6b 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -383,6 +383,11 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [allAttachmentIds addObjectsFromArray:[OutgoingMessagePreparer prepareMessageForSending:message transaction:transaction]]; + + // Loki - Optimistically update friend request status when we can + if ([LKFriendRequestProtocol shouldUpdateFriendRequestStatusFromMessage:message]) { + [LKFriendRequestProtocol setFriendRequestStatusToSendingIfNeededForHexEncodedPublicKey:message.thread.contactIdentifier transaction:transaction]; + } }]; NSOperationQueue *sendingQueue = [self sendingQueueForMessage:message];