From 4d0207f20a9473982ffab6e10e6f7e4c1a53f551 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Mon, 4 May 2020 14:05:56 +1000 Subject: [PATCH 01/10] Replace isForceHidden with computed isSlaveThread --- SignalServiceKit/src/Contacts/TSThread.h | 2 +- SignalServiceKit/src/Contacts/TSThread.m | 5 +++++ .../src/Contacts/Threads/TSGroupThread.m | 5 +++++ .../Protocol/Multi Device/MultiDeviceProtocol.swift | 13 +++++++++---- .../SessionManagementProtocol.swift | 4 ---- .../Sync Messages/SyncMessagesProtocol.swift | 11 ++--------- .../src/Storage/FullTextSearchFinder.swift | 2 +- SignalServiceKit/src/Storage/TSDatabaseView.m | 5 +++-- 8 files changed, 26 insertions(+), 21 deletions(-) diff --git a/SignalServiceKit/src/Contacts/TSThread.h b/SignalServiceKit/src/Contacts/TSThread.h index 139f3a02d..d0998d905 100644 --- a/SignalServiceKit/src/Contacts/TSThread.h +++ b/SignalServiceKit/src/Contacts/TSThread.h @@ -43,7 +43,7 @@ extern ConversationColorName const kConversationColorName_Default; @property (nonatomic) NSInteger friendRequestStatus __deprecated_msg("use OWSPrimaryStorage.getFriendRequestStatusForContact:transaction: instead"); @property (nonatomic, readonly) BOOL isContactFriend; // ======== -@property (nonatomic) BOOL isForceHidden; // FIXME: Having both this and shouldThreadBeVisible is confusing +@property (atomic, readonly) BOOL isSlaveThread; /** * Whether the object is a group thread or not. diff --git a/SignalServiceKit/src/Contacts/TSThread.m b/SignalServiceKit/src/Contacts/TSThread.m index 8a7c1f731..33571237a 100644 --- a/SignalServiceKit/src/Contacts/TSThread.m +++ b/SignalServiceKit/src/Contacts/TSThread.m @@ -773,6 +773,11 @@ ConversationColorName const kConversationColorName_Default = ConversationColorNa return [LKFriendRequestProtocol getFriendRequestUIStatusForThread:self] == LKFriendRequestUIStatusFriends; } +- (BOOL)isSlaveThread +{ + return [LKMultiDeviceProtocol isSlaveThread:self]; +} + @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Contacts/Threads/TSGroupThread.m b/SignalServiceKit/src/Contacts/Threads/TSGroupThread.m index 2a817719c..9747e84fb 100644 --- a/SignalServiceKit/src/Contacts/Threads/TSGroupThread.m +++ b/SignalServiceKit/src/Contacts/Threads/TSGroupThread.m @@ -314,6 +314,11 @@ NSString *const TSGroupThread_NotificationKey_UniqueId = @"TSGroupThread_Notific return [self.class stableColorNameForNewConversationWithString:[self threadIdFromGroupId:groupId]]; } +- (BOOL)isContactFriend +{ + return true; +} + @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocol.swift b/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocol.swift index a84b8024d..66b930464 100644 --- a/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocol.swift +++ b/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocol.swift @@ -151,10 +151,6 @@ public final class MultiDeviceProtocol : NSObject { @objc(getAutoGeneratedMultiDeviceFRMessageForHexEncodedPublicKey:in:) public static func getAutoGeneratedMultiDeviceFRMessage(for hexEncodedPublicKey: String, in transaction: YapDatabaseReadWriteTransaction) -> FriendRequestMessage { let thread = TSContactThread.getOrCreateThread(withContactId: hexEncodedPublicKey, transaction: transaction) - let masterHexEncodedPublicKey = storage.getMasterHexEncodedPublicKey(for: hexEncodedPublicKey, in: transaction) - let isSlaveDeviceThread = masterHexEncodedPublicKey != hexEncodedPublicKey - thread.isForceHidden = isSlaveDeviceThread // TODO: Could we make this computed? - thread.save(with: transaction) let result = FriendRequestMessage(outgoingMessageWithTimestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageBody: "Please accept to enable messages to be synced across devices", attachmentIds: [], expiresInSeconds: 0, expireStartedAt: 0, isVoiceMessage: false, @@ -264,6 +260,15 @@ public final class MultiDeviceProtocol : NSObject { } } } + + @objc public static func isSlaveThread(_ thread: TSThread) -> Bool { + guard let thread = thread as? TSContactThread else { return false; } + var isSlaveThread = false + Storage.read { transaction in + isSlaveThread = storage.getMasterHexEncodedPublicKey(for: thread.contactIdentifier(), in: transaction) != nil + } + return isSlaveThread + } } // MARK: - Sending (Part 2) diff --git a/SignalServiceKit/src/Loki/Protocol/Session Management/SessionManagementProtocol.swift b/SignalServiceKit/src/Loki/Protocol/Session Management/SessionManagementProtocol.swift index 4a722181d..90bd27d02 100644 --- a/SignalServiceKit/src/Loki/Protocol/Session Management/SessionManagementProtocol.swift +++ b/SignalServiceKit/src/Loki/Protocol/Session Management/SessionManagementProtocol.swift @@ -117,10 +117,6 @@ public final class SessionManagementProtocol : NSObject { public static func getSessionResetMessageSend(for hexEncodedPublicKey: String, in transaction: YapDatabaseReadWriteTransaction) -> Promise { let thread = TSContactThread.getOrCreateThread(withContactId: hexEncodedPublicKey, transaction: transaction) - let masterHexEncodedPublicKey = storage.getMasterHexEncodedPublicKey(for: hexEncodedPublicKey, in: transaction) - let isSlaveDeviceThread = masterHexEncodedPublicKey != hexEncodedPublicKey - thread.isForceHidden = isSlaveDeviceThread - thread.save(with: transaction) let message = getSessionResetMessage(for: hexEncodedPublicKey, in: transaction) let recipient = SignalRecipient.getOrBuildUnsavedRecipient(forRecipientId: hexEncodedPublicKey, transaction: transaction) let udManager = SSKEnvironment.shared.udManager diff --git a/SignalServiceKit/src/Loki/Protocol/Sync Messages/SyncMessagesProtocol.swift b/SignalServiceKit/src/Loki/Protocol/Sync Messages/SyncMessagesProtocol.swift index f86aa313b..da00355b5 100644 --- a/SignalServiceKit/src/Loki/Protocol/Sync Messages/SyncMessagesProtocol.swift +++ b/SignalServiceKit/src/Loki/Protocol/Sync Messages/SyncMessagesProtocol.swift @@ -41,7 +41,7 @@ public final class SyncMessagesProtocol : NSObject { TSContactThread.enumerateCollectionObjects { object, _ in guard let thread = object as? TSContactThread else { return } let hexEncodedPublicKey = thread.contactIdentifier() - guard thread.isContactFriend && thread.shouldThreadBeVisible && !thread.isForceHidden else { return } + guard thread.isContactFriend && thread.shouldThreadBeVisible && !thread.isSlaveThread else { return } friends.append(SignalAccount(recipientId: hexEncodedPublicKey)) } friends.append(SignalAccount(recipientId: getUserHexEncodedPublicKey())) // TODO: Are we sure about this? @@ -61,7 +61,7 @@ public final class SyncMessagesProtocol : NSObject { var groups: [TSGroupThread] = [] TSGroupThread.enumerateCollectionObjects { object, _ in guard let group = object as? TSGroupThread, group.groupModel.groupType == .closedGroup, - group.shouldThreadBeVisible, !group.isForceHidden else { return } + group.shouldThreadBeVisible else { return } groups.append(group) } let syncManager = SSKEnvironment.shared.syncManager @@ -168,30 +168,23 @@ public final class SyncMessagesProtocol : NSObject { // Try to establish sessions for hexEncodedPublicKey in hexEncodedPublicKeys { // We don't update the friend request status; that's done in OWSMessageSender.sendMessage(_:) - let thread = TSContactThread.getOrCreateThread(withContactId: hexEncodedPublicKey, transaction: transaction) let friendRequestStatus = storage.getFriendRequestStatus(for: hexEncodedPublicKey, transaction: transaction) switch friendRequestStatus { case .none, .requestExpired: let messageSender = SSKEnvironment.shared.messageSender // We need to send the FR message to all of the user's devices as the contact sync message excludes slave devices let autoGeneratedFRMessage = MultiDeviceProtocol.getAutoGeneratedMultiDeviceFRMessage(for: hexEncodedPublicKey, in: transaction) - thread.isForceHidden = true - thread.save(with: transaction) // This takes into account multi device messageSender.send(autoGeneratedFRMessage, success: { DispatchQueue.main.async { storage.dbReadWriteConnection.readWrite { transaction in autoGeneratedFRMessage.remove(with: transaction) - thread.isForceHidden = false - thread.save(with: transaction) } } }, failure: { error in DispatchQueue.main.async { storage.dbReadWriteConnection.readWrite { transaction in autoGeneratedFRMessage.remove(with: transaction) - thread.isForceHidden = false - thread.save(with: transaction) } } }) diff --git a/SignalServiceKit/src/Storage/FullTextSearchFinder.swift b/SignalServiceKit/src/Storage/FullTextSearchFinder.swift index fe6b49b83..4d1fde2f3 100644 --- a/SignalServiceKit/src/Storage/FullTextSearchFinder.swift +++ b/SignalServiceKit/src/Storage/FullTextSearchFinder.swift @@ -215,7 +215,7 @@ public class FullTextSearchFinder: NSObject { if let groupThread = object as? TSGroupThread { return self.groupThreadIndexer.index(groupThread, transaction: transaction) } else if let contactThread = object as? TSContactThread { - guard contactThread.shouldThreadBeVisible && !contactThread.isForceHidden else { + guard contactThread.shouldThreadBeVisible && !contactThread.isSlaveThread else { // If we've never sent/received a message in a TSContactThread, // then we want it to appear in the "Other Contacts" section rather // than in the "Conversations" section. diff --git a/SignalServiceKit/src/Storage/TSDatabaseView.m b/SignalServiceKit/src/Storage/TSDatabaseView.m index 04507c32b..868b06c74 100644 --- a/SignalServiceKit/src/Storage/TSDatabaseView.m +++ b/SignalServiceKit/src/Storage/TSDatabaseView.m @@ -281,14 +281,15 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup" return nil; } TSThread *thread = (TSThread *)object; + if (thread.isSlaveThread) { return nil; } - if (thread.shouldThreadBeVisible && !thread.isForceHidden) { + if (thread.shouldThreadBeVisible) { // Do nothing; we never hide threads that have ever had a message. } else { YapDatabaseViewTransaction *viewTransaction = [transaction ext:TSMessageDatabaseViewExtensionName]; OWSAssertDebug(viewTransaction); NSUInteger threadMessageCount = [viewTransaction numberOfItemsInGroup:thread.uniqueId]; - if (threadMessageCount < 1 || thread.isForceHidden) { + if (threadMessageCount < 1) { return nil; } } From da4a3c3aac1769b3712836451c4e2b24f528b8f5 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Mon, 4 May 2020 14:08:11 +1000 Subject: [PATCH 02/10] Minor fix --- SignalServiceKit/src/Contacts/TSThread.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SignalServiceKit/src/Contacts/TSThread.h b/SignalServiceKit/src/Contacts/TSThread.h index d0998d905..daf08b30e 100644 --- a/SignalServiceKit/src/Contacts/TSThread.h +++ b/SignalServiceKit/src/Contacts/TSThread.h @@ -43,7 +43,7 @@ extern ConversationColorName const kConversationColorName_Default; @property (nonatomic) NSInteger friendRequestStatus __deprecated_msg("use OWSPrimaryStorage.getFriendRequestStatusForContact:transaction: instead"); @property (nonatomic, readonly) BOOL isContactFriend; // ======== -@property (atomic, readonly) BOOL isSlaveThread; +@property (nonatomic, readonly) BOOL isSlaveThread; /** * Whether the object is a group thread or not. From 6fca0779e5e682d4997e02f1875d3b0f475abc96 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Mon, 4 May 2020 16:00:23 +1000 Subject: [PATCH 03/10] Added Test Utils. --- .../src/Contacts/Threads/TSGroupThread.m | 2 +- .../FriendRequestProtocolTests.swift | 239 ++++++++---------- .../MultiDeviceProtocolTests.swift | 1 - .../SyncMessagesProtocolTests.swift | 13 +- .../Utilities/Test/LokiTestUtilities.swift | 55 ++++ 5 files changed, 156 insertions(+), 154 deletions(-) create mode 100644 SignalServiceKit/src/Loki/Utilities/Test/LokiTestUtilities.swift diff --git a/SignalServiceKit/src/Contacts/Threads/TSGroupThread.m b/SignalServiceKit/src/Contacts/Threads/TSGroupThread.m index 9747e84fb..05c7864b3 100644 --- a/SignalServiceKit/src/Contacts/Threads/TSGroupThread.m +++ b/SignalServiceKit/src/Contacts/Threads/TSGroupThread.m @@ -316,7 +316,7 @@ NSString *const TSGroupThread_NotificationKey_UniqueId = @"TSGroupThread_Notific - (BOOL)isContactFriend { - return true; + return false; } @end diff --git a/SignalServiceKit/src/Loki/Protocol/Friend Requests/FriendRequestProtocolTests.swift b/SignalServiceKit/src/Loki/Protocol/Friend Requests/FriendRequestProtocolTests.swift index ca937acd8..9297371e0 100644 --- a/SignalServiceKit/src/Loki/Protocol/Friend Requests/FriendRequestProtocolTests.swift +++ b/SignalServiceKit/src/Loki/Protocol/Friend Requests/FriendRequestProtocolTests.swift @@ -13,17 +13,7 @@ class FriendRequestProtocolTests : XCTestCase { override func setUp() { super.setUp() - ClearCurrentAppContextForTests() - SetCurrentAppContext(TestAppContext()) - MockSSKEnvironment.activate() - - let identityManager = OWSIdentityManager.shared() - let seed = Randomness.generateRandomBytes(16)! - let keyPair = Curve25519.generateKeyPair(fromSeed: seed + seed) - let databaseConnection = identityManager.value(forKey: "dbConnection") as! YapDatabaseConnection - databaseConnection.setObject(keyPair, forKey: OWSPrimaryStorageIdentityKeyStoreIdentityKey, inCollection: OWSPrimaryStorageIdentityKeyStoreCollection) - TSAccountManager.sharedInstance().phoneNumberAwaitingVerification = keyPair.hexEncodedPublicKey - TSAccountManager.sharedInstance().didRegister() + LokiTestUtilities.setupMockEnvironment() } // MARK: - Helpers @@ -36,52 +26,21 @@ class FriendRequestProtocolTests : XCTestCase { return isFriendRequestStatus(oneOf: [ value ], for: hexEncodedPublicKey, transaction: transaction) } - func generateHexEncodedPublicKey() -> String { - return Curve25519.generateKeyPair().hexEncodedPublicKey - } - - func getDevice(for hexEncodedPublicKey: String) -> DeviceLink.Device? { - guard let signature = Data.getSecureRandomData(ofSize: 64) else { return nil } - return DeviceLink.Device(hexEncodedPublicKey: hexEncodedPublicKey, signature: signature) - } - - func createContactThread(for hexEncodedPublicKey: String) -> TSContactThread { - var result: TSContactThread! - storage.dbReadWriteConnection.readWrite { transaction in - result = TSContactThread.getOrCreateThread(withContactId: hexEncodedPublicKey, transaction: transaction) - } - return result - } - - func createGroupThread(groupType: GroupType) -> TSGroupThread? { - let hexEncodedGroupID = Randomness.generateRandomBytes(kGroupIdLength)!.toHexString() - - let groupID: Data - switch groupType { - case .closedGroup: groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(hexEncodedGroupID) - case .openGroup: groupID = LKGroupUtilities.getEncodedOpenGroupIDAsData(hexEncodedGroupID) - case .rssFeed: groupID = LKGroupUtilities.getEncodedRSSFeedIDAsData(hexEncodedGroupID) - default: return nil - } - - return TSGroupThread.getOrCreateThread(withGroupId: groupID, groupType: groupType) - } - // MARK: - shouldInputBarBeEnabled func test_shouldInputBarBeEnabledReturnsTrueOnGroupThread() { let allGroupTypes: [GroupType] = [ .closedGroup, .openGroup, .rssFeed ] for groupType in allGroupTypes { - guard let groupThread = createGroupThread(groupType: groupType) else { return XCTFail() } + guard let groupThread = LokiTestUtilities.createGroupThread(groupType: groupType) else { return XCTFail() } XCTAssertTrue(FriendRequestProtocol.shouldInputBarBeEnabled(for: groupThread)) } } func test_shouldInputBarBeEnabledReturnsTrueOnNoteToSelf() { guard let master = OWSIdentityManager.shared().identityKeyPair()?.hexEncodedPublicKey else { return XCTFail() } - let slave = generateHexEncodedPublicKey() + let slave = LokiTestUtilities.generateHexEncodedPublicKey() - guard let masterDevice = getDevice(for: master) else { return XCTFail() } - guard let slaveDevice = getDevice(for: slave) else { return XCTFail() } + guard let masterDevice = LokiTestUtilities.getDevice(for: master) else { return XCTFail() } + guard let slaveDevice = LokiTestUtilities.getDevice(for: slave) else { return XCTFail() } let deviceLink = DeviceLink(between: masterDevice, and: slaveDevice) storage.dbReadWriteConnection.readWrite { transaction in @@ -90,8 +49,8 @@ class FriendRequestProtocolTests : XCTestCase { self.storage.setFriendRequestStatus(.requestSent, for: slave, transaction: transaction) } - let masterThread = createContactThread(for: master) - let slaveThread = createContactThread(for: slave) + let masterThread = LokiTestUtilities.createContactThread(for: master) + let slaveThread = LokiTestUtilities.createContactThread(for: slave) XCTAssertTrue(FriendRequestProtocol.shouldInputBarBeEnabled(for: masterThread)) XCTAssertTrue(FriendRequestProtocol.shouldInputBarBeEnabled(for: slaveThread)) @@ -99,8 +58,8 @@ class FriendRequestProtocolTests : XCTestCase { func test_shouldInputBarBeEnabledReturnsTrueWhenStatusIsNotPending() { let statuses: [LKFriendRequestStatus] = [ .none, .requestExpired, .friends ] - let device = generateHexEncodedPublicKey() - let thread = createContactThread(for: device) + let device = LokiTestUtilities.generateHexEncodedPublicKey() + let thread = LokiTestUtilities.createContactThread(for: device) for status in statuses { storage.dbReadWriteConnection.readWrite { transaction in @@ -113,8 +72,8 @@ class FriendRequestProtocolTests : XCTestCase { func test_shouldInputBarBeEnabledReturnsFalseWhenStatusIsPending() { let statuses: [LKFriendRequestStatus] = [ .requestSending, .requestSent, .requestReceived ] - let device = generateHexEncodedPublicKey() - let thread = createContactThread(for: device) + let device = LokiTestUtilities.generateHexEncodedPublicKey() + let thread = LokiTestUtilities.createContactThread(for: device) for status in statuses { storage.dbReadWriteConnection.readWrite { transaction in @@ -126,11 +85,11 @@ class FriendRequestProtocolTests : XCTestCase { } func test_shouldInputBarBeEnabledReturnsTrueWhenFriendsWithOneLinkedDevice() { - let master = generateHexEncodedPublicKey() - let slave = generateHexEncodedPublicKey() + let master = LokiTestUtilities.generateHexEncodedPublicKey() + let slave = LokiTestUtilities.generateHexEncodedPublicKey() - guard let masterDevice = getDevice(for: master) else { return XCTFail() } - guard let slaveDevice = getDevice(for: slave) else { return XCTFail() } + guard let masterDevice = LokiTestUtilities.getDevice(for: master) else { return XCTFail() } + guard let slaveDevice = LokiTestUtilities.getDevice(for: slave) else { return XCTFail() } let deviceLink = DeviceLink(between: masterDevice, and: slaveDevice) storage.dbReadWriteConnection.readWrite { transaction in @@ -139,19 +98,19 @@ class FriendRequestProtocolTests : XCTestCase { self.storage.setFriendRequestStatus(.requestSent, for: slave, transaction: transaction) } - let masterThread = createContactThread(for: master) - let slaveThread = createContactThread(for: slave) + let masterThread = LokiTestUtilities.createContactThread(for: master) + let slaveThread = LokiTestUtilities.createContactThread(for: slave) XCTAssertTrue(FriendRequestProtocol.shouldInputBarBeEnabled(for: masterThread)) XCTAssertTrue(FriendRequestProtocol.shouldInputBarBeEnabled(for: slaveThread)) } func test_shouldInputBarBeEnabledReturnsFalseWhenOneLinkedDeviceIsPending() { - let master = generateHexEncodedPublicKey() - let slave = generateHexEncodedPublicKey() + let master = LokiTestUtilities.generateHexEncodedPublicKey() + let slave = LokiTestUtilities.generateHexEncodedPublicKey() - guard let masterDevice = getDevice(for: master) else { return XCTFail() } - guard let slaveDevice = getDevice(for: slave) else { return XCTFail() } + guard let masterDevice = LokiTestUtilities.getDevice(for: master) else { return XCTFail() } + guard let slaveDevice = LokiTestUtilities.getDevice(for: slave) else { return XCTFail() } let deviceLink = DeviceLink(between: masterDevice, and: slaveDevice) storage.dbReadWriteConnection.readWrite { transaction in @@ -159,8 +118,8 @@ class FriendRequestProtocolTests : XCTestCase { self.storage.setFriendRequestStatus(.none, for: master, transaction: transaction) } - let masterThread = createContactThread(for: master) - let slaveThread = createContactThread(for: slave) + let masterThread = LokiTestUtilities.createContactThread(for: master) + let slaveThread = LokiTestUtilities.createContactThread(for: slave) let statuses: [LKFriendRequestStatus] = [ .requestSending, .requestSent, .requestReceived ] for status in statuses { @@ -174,11 +133,11 @@ class FriendRequestProtocolTests : XCTestCase { } func test_shouldInputBarBeEnabledReturnsTrueWhenAllLinkedDevicesAreNotPendingAndNotFriends() { - let master = generateHexEncodedPublicKey() - let slave = generateHexEncodedPublicKey() + let master = LokiTestUtilities.generateHexEncodedPublicKey() + let slave = LokiTestUtilities.generateHexEncodedPublicKey() - guard let masterDevice = getDevice(for: master) else { return XCTFail() } - guard let slaveDevice = getDevice(for: slave) else { return XCTFail() } + guard let masterDevice = LokiTestUtilities.getDevice(for: master) else { return XCTFail() } + guard let slaveDevice = LokiTestUtilities.getDevice(for: slave) else { return XCTFail() } let deviceLink = DeviceLink(between: masterDevice, and: slaveDevice) storage.dbReadWriteConnection.readWrite { transaction in @@ -187,8 +146,8 @@ class FriendRequestProtocolTests : XCTestCase { self.storage.setFriendRequestStatus(.none, for: slave, transaction: transaction) } - let masterThread = createContactThread(for: master) - let slaveThread = createContactThread(for: slave) + let masterThread = LokiTestUtilities.createContactThread(for: master) + let slaveThread = LokiTestUtilities.createContactThread(for: slave) let statuses: [LKFriendRequestStatus] = [ .requestExpired, .none ] for status in statuses { @@ -202,11 +161,11 @@ class FriendRequestProtocolTests : XCTestCase { } func test_shouldInputBarEnabledShouldStillWorkIfLinkedDeviceThreadDoesNotExist() { - let master = generateHexEncodedPublicKey() - let slave = generateHexEncodedPublicKey() + let master = LokiTestUtilities.generateHexEncodedPublicKey() + let slave = LokiTestUtilities.generateHexEncodedPublicKey() - guard let masterDevice = getDevice(for: master) else { return XCTFail() } - guard let slaveDevice = getDevice(for: slave) else { return XCTFail() } + guard let masterDevice = LokiTestUtilities.getDevice(for: master) else { return XCTFail() } + guard let slaveDevice = LokiTestUtilities.getDevice(for: slave) else { return XCTFail() } let deviceLink = DeviceLink(between: masterDevice, and: slaveDevice) storage.dbReadWriteConnection.readWrite { transaction in @@ -215,7 +174,7 @@ class FriendRequestProtocolTests : XCTestCase { self.storage.setFriendRequestStatus(.friends, for: slave, transaction: transaction) } - let masterThread = createContactThread(for: master) + let masterThread = LokiTestUtilities.createContactThread(for: master) XCTAssertTrue(FriendRequestProtocol.shouldInputBarBeEnabled(for: masterThread)) } @@ -224,17 +183,17 @@ class FriendRequestProtocolTests : XCTestCase { func test_shouldAttachmentButtonBeEnabledReturnsTrueOnGroupThread() { let allGroupTypes: [GroupType] = [ .closedGroup, .openGroup, .rssFeed ] for groupType in allGroupTypes { - guard let groupThread = createGroupThread(groupType: groupType) else { return XCTFail() } + guard let groupThread = LokiTestUtilities.createGroupThread(groupType: groupType) else { return XCTFail() } XCTAssertTrue(FriendRequestProtocol.shouldAttachmentButtonBeEnabled(for: groupThread)) } } func test_shouldAttachmentButtonBeEnabledReturnsTrueOnNoteToSelf() { guard let master = OWSIdentityManager.shared().identityKeyPair()?.hexEncodedPublicKey else { return XCTFail() } - let slave = generateHexEncodedPublicKey() + let slave = LokiTestUtilities.generateHexEncodedPublicKey() - guard let masterDevice = getDevice(for: master) else { return XCTFail() } - guard let slaveDevice = getDevice(for: slave) else { return XCTFail() } + guard let masterDevice = LokiTestUtilities.getDevice(for: master) else { return XCTFail() } + guard let slaveDevice = LokiTestUtilities.getDevice(for: slave) else { return XCTFail() } let deviceLink = DeviceLink(between: masterDevice, and: slaveDevice) storage.dbReadWriteConnection.readWrite { transaction in @@ -243,16 +202,16 @@ class FriendRequestProtocolTests : XCTestCase { self.storage.setFriendRequestStatus(.requestSent, for: slave, transaction: transaction) } - let masterThread = createContactThread(for: master) - let slaveThread = createContactThread(for: slave) + let masterThread = LokiTestUtilities.createContactThread(for: master) + let slaveThread = LokiTestUtilities.createContactThread(for: slave) XCTAssertTrue(FriendRequestProtocol.shouldAttachmentButtonBeEnabled(for: masterThread)) XCTAssertTrue(FriendRequestProtocol.shouldAttachmentButtonBeEnabled(for: slaveThread)) } func test_shouldAttachmentButtonBeEnabledReturnsTrueWhenFriends() { - let device = generateHexEncodedPublicKey() - let thread = createContactThread(for: device) + let device = LokiTestUtilities.generateHexEncodedPublicKey() + let thread = LokiTestUtilities.createContactThread(for: device) storage.dbReadWriteConnection.readWrite { transaction in self.storage.setFriendRequestStatus(.friends, for: device, transaction: transaction) @@ -263,8 +222,8 @@ class FriendRequestProtocolTests : XCTestCase { func test_shouldAttachmentButtonBeEnabledReturnsFalseWhenNotFriends() { let statuses: [LKFriendRequestStatus] = [ .requestSending, .requestSent, .requestReceived, .none, .requestExpired ] - let device = generateHexEncodedPublicKey() - let thread = createContactThread(for: device) + let device = LokiTestUtilities.generateHexEncodedPublicKey() + let thread = LokiTestUtilities.createContactThread(for: device) for status in statuses { storage.dbReadWriteConnection.readWrite { transaction in @@ -276,11 +235,11 @@ class FriendRequestProtocolTests : XCTestCase { } func test_shouldAttachmentButtonBeEnabledReturnsTrueWhenFriendsWithOneLinkedDevice() { - let master = generateHexEncodedPublicKey() - let slave = generateHexEncodedPublicKey() + let master = LokiTestUtilities.generateHexEncodedPublicKey() + let slave = LokiTestUtilities.generateHexEncodedPublicKey() - guard let masterDevice = getDevice(for: master) else { return XCTFail() } - guard let slaveDevice = getDevice(for: slave) else { return XCTFail() } + guard let masterDevice = LokiTestUtilities.getDevice(for: master) else { return XCTFail() } + guard let slaveDevice = LokiTestUtilities.getDevice(for: slave) else { return XCTFail() } let deviceLink = DeviceLink(between: masterDevice, and: slaveDevice) storage.dbReadWriteConnection.readWrite { transaction in @@ -289,19 +248,19 @@ class FriendRequestProtocolTests : XCTestCase { self.storage.setFriendRequestStatus(.requestSent, for: slave, transaction: transaction) } - let masterThread = createContactThread(for: master) - let slaveThread = createContactThread(for: slave) + let masterThread = LokiTestUtilities.createContactThread(for: master) + let slaveThread = LokiTestUtilities.createContactThread(for: slave) XCTAssertTrue(FriendRequestProtocol.shouldAttachmentButtonBeEnabled(for: masterThread)) XCTAssertTrue(FriendRequestProtocol.shouldAttachmentButtonBeEnabled(for: slaveThread)) } func test_shouldAttachmentButtonBeEnabledShouldStillWorkIfLinkedDeviceThreadDoesNotExist() { - let master = generateHexEncodedPublicKey() - let slave = generateHexEncodedPublicKey() + let master = LokiTestUtilities.generateHexEncodedPublicKey() + let slave = LokiTestUtilities.generateHexEncodedPublicKey() - guard let masterDevice = getDevice(for: master) else { return XCTFail() } - guard let slaveDevice = getDevice(for: slave) else { return XCTFail() } + guard let masterDevice = LokiTestUtilities.getDevice(for: master) else { return XCTFail() } + guard let slaveDevice = LokiTestUtilities.getDevice(for: slave) else { return XCTFail() } let deviceLink = DeviceLink(between: masterDevice, and: slaveDevice) storage.dbReadWriteConnection.readWrite { transaction in @@ -310,7 +269,7 @@ class FriendRequestProtocolTests : XCTestCase { self.storage.setFriendRequestStatus(.friends, for: slave, transaction: transaction) } - let masterThread = createContactThread(for: master) + let masterThread = LokiTestUtilities.createContactThread(for: master) XCTAssertTrue(FriendRequestProtocol.shouldAttachmentButtonBeEnabled(for: masterThread)) } @@ -319,17 +278,17 @@ class FriendRequestProtocolTests : XCTestCase { func test_getFriendRequestUIStateShouldReturnNoneForGroupThreads() { let allGroupTypes: [GroupType] = [ .closedGroup, .openGroup, .rssFeed ] for groupType in allGroupTypes { - guard let groupThread = createGroupThread(groupType: groupType) else { return XCTFail() } + guard let groupThread = LokiTestUtilities.createGroupThread(groupType: groupType) else { return XCTFail() } XCTAssertTrue(FriendRequestProtocol.getFriendRequestUIStatus(for: groupThread) == .none) } } func test_getFriendRequestUIStateShouldReturnNoneOnNoteToSelf() { guard let master = OWSIdentityManager.shared().identityKeyPair()?.hexEncodedPublicKey else { return XCTFail() } - let slave = generateHexEncodedPublicKey() + let slave = LokiTestUtilities.generateHexEncodedPublicKey() - guard let masterDevice = getDevice(for: master) else { return XCTFail() } - guard let slaveDevice = getDevice(for: slave) else { return XCTFail() } + guard let masterDevice = LokiTestUtilities.getDevice(for: master) else { return XCTFail() } + guard let slaveDevice = LokiTestUtilities.getDevice(for: slave) else { return XCTFail() } let deviceLink = DeviceLink(between: masterDevice, and: slaveDevice) storage.dbReadWriteConnection.readWrite { transaction in @@ -338,16 +297,16 @@ class FriendRequestProtocolTests : XCTestCase { self.storage.setFriendRequestStatus(.friends, for: slave, transaction: transaction) } - let masterThread = createContactThread(for: master) - let slaveThread = createContactThread(for: slave) + let masterThread = LokiTestUtilities.createContactThread(for: master) + let slaveThread = LokiTestUtilities.createContactThread(for: slave) XCTAssertTrue(FriendRequestProtocol.getFriendRequestUIStatus(for: masterThread) == .none) XCTAssertTrue(FriendRequestProtocol.getFriendRequestUIStatus(for: slaveThread) == .none ) } func test_getFriendRequestUIStateShouldReturnTheCorrectStates() { - let bob = generateHexEncodedPublicKey() - let bobThread = createContactThread(for: bob) + let bob = LokiTestUtilities.generateHexEncodedPublicKey() + let bobThread = LokiTestUtilities.createContactThread(for: bob) let expectedStatuses: [LKFriendRequestStatus:FriendRequestProtocol.FriendRequestUIStatus] = [ .none: .none, @@ -368,11 +327,11 @@ class FriendRequestProtocolTests : XCTestCase { } func test_getFriendRequestUIStateShouldWorkWithMultiDevice() { - let master = generateHexEncodedPublicKey() - let slave = generateHexEncodedPublicKey() + let master = LokiTestUtilities.generateHexEncodedPublicKey() + let slave = LokiTestUtilities.generateHexEncodedPublicKey() - guard let masterDevice = getDevice(for: master) else { return XCTFail() } - guard let slaveDevice = getDevice(for: slave) else { return XCTFail() } + guard let masterDevice = LokiTestUtilities.getDevice(for: master) else { return XCTFail() } + guard let slaveDevice = LokiTestUtilities.getDevice(for: slave) else { return XCTFail() } let deviceLink = DeviceLink(between: masterDevice, and: slaveDevice) storage.dbReadWriteConnection.readWrite { transaction in @@ -380,8 +339,8 @@ class FriendRequestProtocolTests : XCTestCase { self.storage.setFriendRequestStatus(.none, for: master, transaction: transaction) } - let masterThread = createContactThread(for: master) - let slaveThread = createContactThread(for: slave) + let masterThread = LokiTestUtilities.createContactThread(for: master) + let slaveThread = LokiTestUtilities.createContactThread(for: slave) let expectedStatuses: [LKFriendRequestStatus:FriendRequestProtocol.FriendRequestUIStatus] = [ .none: .none, @@ -404,13 +363,13 @@ class FriendRequestProtocolTests : XCTestCase { func test_getFriendRequestUIStateShouldPreferFriendsOverRequestReceived() { // Case: We don't want to confuse the user by showing a friend request box when they're already friends. - let master = generateHexEncodedPublicKey() - let slave = generateHexEncodedPublicKey() + let master = LokiTestUtilities.generateHexEncodedPublicKey() + let slave = LokiTestUtilities.generateHexEncodedPublicKey() - guard let masterDevice = getDevice(for: master) else { return XCTFail() } - guard let slaveDevice = getDevice(for: slave) else { return XCTFail() } + guard let masterDevice = LokiTestUtilities.getDevice(for: master) else { return XCTFail() } + guard let slaveDevice = LokiTestUtilities.getDevice(for: slave) else { return XCTFail() } - let masterThread = createContactThread(for: master) + let masterThread = LokiTestUtilities.createContactThread(for: master) let deviceLink = DeviceLink(between: masterDevice, and: slaveDevice) storage.dbReadWriteConnection.readWrite { transaction in @@ -425,13 +384,13 @@ class FriendRequestProtocolTests : XCTestCase { func test_getFriendRequestUIStateShouldPreferReceivedOverSent() { // Case: We sent Bob a friend request and he sent one back to us through another device. // If something went wrong then we should be able to fall back to manually accepting the friend request even if we sent one. - let master = generateHexEncodedPublicKey() - let slave = generateHexEncodedPublicKey() + let master = LokiTestUtilities.generateHexEncodedPublicKey() + let slave = LokiTestUtilities.generateHexEncodedPublicKey() - guard let masterDevice = getDevice(for: master) else { return XCTFail() } - guard let slaveDevice = getDevice(for: slave) else { return XCTFail() } + guard let masterDevice = LokiTestUtilities.getDevice(for: master) else { return XCTFail() } + guard let slaveDevice = LokiTestUtilities.getDevice(for: slave) else { return XCTFail() } - let masterThread = createContactThread(for: master) + let masterThread = LokiTestUtilities.createContactThread(for: master) let deviceLink = DeviceLink(between: masterDevice, and: slaveDevice) storage.dbReadWriteConnection.readWrite { transaction in @@ -446,7 +405,7 @@ class FriendRequestProtocolTests : XCTestCase { // MARK: - acceptFriendRequest func test_acceptFriendRequestShouldSetStatusToFriendsIfWeReceivedAFriendRequest() { // Case: Bob sent us a friend request, we should become friends with him on accepting. - let bob = generateHexEncodedPublicKey() + let bob = LokiTestUtilities.generateHexEncodedPublicKey() storage.dbReadWriteConnection.readWrite { transaction in self.storage.setFriendRequestStatus(.requestReceived, for: bob, transaction: transaction) } @@ -464,7 +423,7 @@ class FriendRequestProtocolTests : XCTestCase { // Since user accepted then we should send a friend request message. let statuses: [LKFriendRequestStatus] = [ .none, .requestExpired ] for status in statuses { - let bob = generateHexEncodedPublicKey() + let bob = LokiTestUtilities.generateHexEncodedPublicKey() storage.dbReadWriteConnection.readWrite { transaction in self.storage.setFriendRequestStatus(status, for: bob, transaction: transaction) } @@ -491,7 +450,7 @@ class FriendRequestProtocolTests : XCTestCase { func test_acceptFriendRequestShouldNotDoAnythingIfRequestHasBeenSent() { // Case: We sent Bob a friend request. // We can't accept because we don't have keys to communicate with Bob. - let bob = generateHexEncodedPublicKey() + let bob = LokiTestUtilities.generateHexEncodedPublicKey() storage.dbReadWriteConnection.readWrite { transaction in self.storage.setFriendRequestStatus(.requestSent, for: bob, transaction: transaction) } @@ -506,13 +465,13 @@ class FriendRequestProtocolTests : XCTestCase { // Case: Bob sent a friend request from his slave device. // Accepting the friend request should set it to friends. // We should also send out a friend request to Bob's other devices if possible. - let master = generateHexEncodedPublicKey() - let slave = generateHexEncodedPublicKey() - let otherSlave = generateHexEncodedPublicKey() + let master = LokiTestUtilities.generateHexEncodedPublicKey() + let slave = LokiTestUtilities.generateHexEncodedPublicKey() + let otherSlave = LokiTestUtilities.generateHexEncodedPublicKey() - guard let masterDevice = getDevice(for: master) else { return XCTFail() } - guard let slaveDevice = getDevice(for: slave) else { return XCTFail() } - guard let otherSlaveDevice = getDevice(for: otherSlave) else { return XCTFail() } + guard let masterDevice = LokiTestUtilities.getDevice(for: master) else { return XCTFail() } + guard let slaveDevice = LokiTestUtilities.getDevice(for: slave) else { return XCTFail() } + guard let otherSlaveDevice = LokiTestUtilities.getDevice(for: otherSlave) else { return XCTFail() } storage.dbReadWriteConnection.readWrite { transaction in self.storage.addDeviceLink(DeviceLink(between: masterDevice, and: slaveDevice), in: transaction) @@ -537,8 +496,8 @@ class FriendRequestProtocolTests : XCTestCase { } func test_acceptFriendRequestShouldNotChangeStatusIfDevicesAreNotLinked() { - let alice = generateHexEncodedPublicKey() - let bob = generateHexEncodedPublicKey() + let alice = LokiTestUtilities.generateHexEncodedPublicKey() + let bob = LokiTestUtilities.generateHexEncodedPublicKey() storage.dbReadWriteConnection.readWrite { transaction in self.storage.setFriendRequestStatus(.requestReceived, for: alice, transaction: transaction) @@ -554,7 +513,7 @@ class FriendRequestProtocolTests : XCTestCase { // MARK: - declineFriendRequest func test_declineFriendRequestShouldChangeStatusFromReceivedToNone() { - let bob = generateHexEncodedPublicKey() + let bob = LokiTestUtilities.generateHexEncodedPublicKey() storage.dbReadWriteConnection.readWrite { transaction in self.storage.setFriendRequestStatus(.requestReceived, for: bob, transaction: transaction) @@ -568,7 +527,7 @@ class FriendRequestProtocolTests : XCTestCase { func test_declineFriendRequestShouldNotChangeStatusToNoneFromOtherStatuses() { let statuses: [LKFriendRequestStatus] = [ .none, .requestSending, .requestSent, .requestExpired, .friends ] - let bob = generateHexEncodedPublicKey() + let bob = LokiTestUtilities.generateHexEncodedPublicKey() for status in statuses { storage.dbReadWriteConnection.readWrite { transaction in @@ -589,7 +548,7 @@ class FriendRequestProtocolTests : XCTestCase { let statuses: [LKFriendRequestStatus] = [ .none, .requestSending, .requestSent, .requestReceived, .requestExpired, .friends ] for status in statuses { - let bob = generateHexEncodedPublicKey() + let bob = LokiTestUtilities.generateHexEncodedPublicKey() let bundle = storage.generatePreKeyBundle(forContact: bob) storage.dbReadWriteConnection.readWrite { transaction in self.storage.setPreKeyBundle(bundle, forContact: bob, transaction: transaction) @@ -612,13 +571,13 @@ class FriendRequestProtocolTests : XCTestCase { func test_declineFriendRequestShouldWorkWithMultipleLinkedDevices() { // Case: Bob sends 2 friend requests to Alice. // When Alice declines, it should change the statuses from requestReceived to none so friend request logic can be re-triggered. - let master = generateHexEncodedPublicKey() - let slave = generateHexEncodedPublicKey() - let otherSlave = generateHexEncodedPublicKey() + let master = LokiTestUtilities.generateHexEncodedPublicKey() + let slave = LokiTestUtilities.generateHexEncodedPublicKey() + let otherSlave = LokiTestUtilities.generateHexEncodedPublicKey() - guard let masterDevice = getDevice(for: master) else { return XCTFail() } - guard let slaveDevice = getDevice(for: slave) else { return XCTFail() } - guard let otherSlaveDevice = getDevice(for: otherSlave) else { return XCTFail() } + guard let masterDevice = LokiTestUtilities.getDevice(for: master) else { return XCTFail() } + guard let slaveDevice = LokiTestUtilities.getDevice(for: slave) else { return XCTFail() } + guard let otherSlaveDevice = LokiTestUtilities.getDevice(for: otherSlave) else { return XCTFail() } storage.dbReadWriteConnection.readWrite { transaction in self.storage.addDeviceLink(DeviceLink(between: masterDevice, and: slaveDevice), in: transaction) diff --git a/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocolTests.swift b/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocolTests.swift index 5aab343a1..1f4cb274b 100644 --- a/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocolTests.swift +++ b/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocolTests.swift @@ -4,6 +4,5 @@ import XCTest class MultiDeviceProtocolTests : XCTestCase { - // TODO: Add tests } diff --git a/SignalServiceKit/src/Loki/Protocol/Sync Messages/SyncMessagesProtocolTests.swift b/SignalServiceKit/src/Loki/Protocol/Sync Messages/SyncMessagesProtocolTests.swift index 506c96f6b..075ab8577 100644 --- a/SignalServiceKit/src/Loki/Protocol/Sync Messages/SyncMessagesProtocolTests.swift +++ b/SignalServiceKit/src/Loki/Protocol/Sync Messages/SyncMessagesProtocolTests.swift @@ -9,18 +9,7 @@ class SyncMessagesProtocolTests : XCTestCase { override func setUp() { super.setUp() - // Activate the mock environment - ClearCurrentAppContextForTests() - SetCurrentAppContext(TestAppContext()) - MockSSKEnvironment.activate() - // Register a mock user - let identityManager = OWSIdentityManager.shared() - let seed = Randomness.generateRandomBytes(16)! - let keyPair = Curve25519.generateKeyPair(fromSeed: seed + seed) - let databaseConnection = identityManager.value(forKey: "dbConnection") as! YapDatabaseConnection - databaseConnection.setObject(keyPair, forKey: OWSPrimaryStorageIdentityKeyStoreIdentityKey, inCollection: OWSPrimaryStorageIdentityKeyStoreCollection) - TSAccountManager.sharedInstance().phoneNumberAwaitingVerification = keyPair.hexEncodedPublicKey - TSAccountManager.sharedInstance().didRegister() + LokiTestUtilities.setupMockEnvironment() } func testContactSyncMessageHandling() { diff --git a/SignalServiceKit/src/Loki/Utilities/Test/LokiTestUtilities.swift b/SignalServiceKit/src/Loki/Utilities/Test/LokiTestUtilities.swift new file mode 100644 index 000000000..cb3e0d499 --- /dev/null +++ b/SignalServiceKit/src/Loki/Utilities/Test/LokiTestUtilities.swift @@ -0,0 +1,55 @@ +import Foundation +import SignalServiceKit +import Curve25519Kit + +@objc(LKTestUtilities) +class LokiTestUtilities : NSObject { + + @objc public static func setupMockEnvironment() { + ClearCurrentAppContextForTests() + SetCurrentAppContext(TestAppContext()) + MockSSKEnvironment.activate() + + let identityManager = OWSIdentityManager.shared() + let seed = Randomness.generateRandomBytes(16)! + let keyPair = Curve25519.generateKeyPair(fromSeed: seed + seed) + let databaseConnection = identityManager.value(forKey: "dbConnection") as! YapDatabaseConnection + databaseConnection.setObject(keyPair, forKey: OWSPrimaryStorageIdentityKeyStoreIdentityKey, inCollection: OWSPrimaryStorageIdentityKeyStoreCollection) + TSAccountManager.sharedInstance().phoneNumberAwaitingVerification = keyPair.hexEncodedPublicKey + TSAccountManager.sharedInstance().didRegister() + } + + @objc public static func generateKeyPair() -> ECKeyPair { + return Curve25519.generateKeyPair() + } + + @objc public static func generateHexEncodedPublicKey() -> String { + return generateKeyPair().hexEncodedPublicKey + } + + @objc(getDeviceForHexEncodedPublicKey:) + public static func getDevice(for hexEncodedPublicKey: String) -> DeviceLink.Device? { + guard let signature = Data.getSecureRandomData(ofSize: 64) else { return nil } + return DeviceLink.Device(hexEncodedPublicKey: hexEncodedPublicKey, signature: signature) + } + + @objc(createContactThreadForHexEncodedPublicKey:) + public static func createContactThread(for hexEncodedPublicKey: String) -> TSContactThread { + return TSContactThread.getOrCreateThread(contactId: hexEncodedPublicKey) + } + + @objc(createGroupThreadWithGroupType:) + public static func createGroupThread(groupType: GroupType) -> TSGroupThread? { + let hexEncodedGroupID = Randomness.generateRandomBytes(kGroupIdLength)!.toHexString() + + let groupID: Data + switch groupType { + case .closedGroup: groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(hexEncodedGroupID) + case .openGroup: groupID = LKGroupUtilities.getEncodedOpenGroupIDAsData(hexEncodedGroupID) + case .rssFeed: groupID = LKGroupUtilities.getEncodedRSSFeedIDAsData(hexEncodedGroupID) + default: return nil + } + + return TSGroupThread.getOrCreateThread(withGroupId: groupID, groupType: groupType) + } +} From 2190c98ba155e1fdece19a721283dae53546bdfd Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Mon, 4 May 2020 16:17:18 +1000 Subject: [PATCH 04/10] Fix Swift/Obj-C interop --- .../FriendRequestProtocolTests.swift | 2 +- .../Multi Device/MultiDeviceProtocol.swift | 3 ++- .../SyncMessagesProtocolTests.swift | 2 +- .../{Test => }/LokiTestUtilities.swift | 17 ++++++----------- 4 files changed, 10 insertions(+), 14 deletions(-) rename SignalServiceKit/src/Loki/Utilities/{Test => }/LokiTestUtilities.swift (84%) diff --git a/SignalServiceKit/src/Loki/Protocol/Friend Requests/FriendRequestProtocolTests.swift b/SignalServiceKit/src/Loki/Protocol/Friend Requests/FriendRequestProtocolTests.swift index 9297371e0..86b8347dd 100644 --- a/SignalServiceKit/src/Loki/Protocol/Friend Requests/FriendRequestProtocolTests.swift +++ b/SignalServiceKit/src/Loki/Protocol/Friend Requests/FriendRequestProtocolTests.swift @@ -13,7 +13,7 @@ class FriendRequestProtocolTests : XCTestCase { override func setUp() { super.setUp() - LokiTestUtilities.setupMockEnvironment() + LokiTestUtilities.setUpMockEnvironment() } // MARK: - Helpers diff --git a/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocol.swift b/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocol.swift index 66b930464..afc73a8bf 100644 --- a/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocol.swift +++ b/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocol.swift @@ -261,8 +261,9 @@ public final class MultiDeviceProtocol : NSObject { } } + // MARK: - General @objc public static func isSlaveThread(_ thread: TSThread) -> Bool { - guard let thread = thread as? TSContactThread else { return false; } + guard let thread = thread as? TSContactThread else { return false } var isSlaveThread = false Storage.read { transaction in isSlaveThread = storage.getMasterHexEncodedPublicKey(for: thread.contactIdentifier(), in: transaction) != nil diff --git a/SignalServiceKit/src/Loki/Protocol/Sync Messages/SyncMessagesProtocolTests.swift b/SignalServiceKit/src/Loki/Protocol/Sync Messages/SyncMessagesProtocolTests.swift index 075ab8577..eccb928a3 100644 --- a/SignalServiceKit/src/Loki/Protocol/Sync Messages/SyncMessagesProtocolTests.swift +++ b/SignalServiceKit/src/Loki/Protocol/Sync Messages/SyncMessagesProtocolTests.swift @@ -9,7 +9,7 @@ class SyncMessagesProtocolTests : XCTestCase { override func setUp() { super.setUp() - LokiTestUtilities.setupMockEnvironment() + LokiTestUtilities.setUpMockEnvironment() } func testContactSyncMessageHandling() { diff --git a/SignalServiceKit/src/Loki/Utilities/Test/LokiTestUtilities.swift b/SignalServiceKit/src/Loki/Utilities/LokiTestUtilities.swift similarity index 84% rename from SignalServiceKit/src/Loki/Utilities/Test/LokiTestUtilities.swift rename to SignalServiceKit/src/Loki/Utilities/LokiTestUtilities.swift index cb3e0d499..1f3187ec3 100644 --- a/SignalServiceKit/src/Loki/Utilities/Test/LokiTestUtilities.swift +++ b/SignalServiceKit/src/Loki/Utilities/LokiTestUtilities.swift @@ -2,14 +2,14 @@ import Foundation import SignalServiceKit import Curve25519Kit -@objc(LKTestUtilities) -class LokiTestUtilities : NSObject { +enum LokiTestUtilities { - @objc public static func setupMockEnvironment() { + public static func setUpMockEnvironment() { + // Activate the mock Signal environment ClearCurrentAppContextForTests() SetCurrentAppContext(TestAppContext()) MockSSKEnvironment.activate() - + // Register a mock user let identityManager = OWSIdentityManager.shared() let seed = Randomness.generateRandomBytes(16)! let keyPair = Curve25519.generateKeyPair(fromSeed: seed + seed) @@ -19,29 +19,25 @@ class LokiTestUtilities : NSObject { TSAccountManager.sharedInstance().didRegister() } - @objc public static func generateKeyPair() -> ECKeyPair { + public static func generateKeyPair() -> ECKeyPair { return Curve25519.generateKeyPair() } - @objc public static func generateHexEncodedPublicKey() -> String { + public static func generateHexEncodedPublicKey() -> String { return generateKeyPair().hexEncodedPublicKey } - @objc(getDeviceForHexEncodedPublicKey:) public static func getDevice(for hexEncodedPublicKey: String) -> DeviceLink.Device? { guard let signature = Data.getSecureRandomData(ofSize: 64) else { return nil } return DeviceLink.Device(hexEncodedPublicKey: hexEncodedPublicKey, signature: signature) } - @objc(createContactThreadForHexEncodedPublicKey:) public static func createContactThread(for hexEncodedPublicKey: String) -> TSContactThread { return TSContactThread.getOrCreateThread(contactId: hexEncodedPublicKey) } - @objc(createGroupThreadWithGroupType:) public static func createGroupThread(groupType: GroupType) -> TSGroupThread? { let hexEncodedGroupID = Randomness.generateRandomBytes(kGroupIdLength)!.toHexString() - let groupID: Data switch groupType { case .closedGroup: groupID = LKGroupUtilities.getEncodedClosedGroupIDAsData(hexEncodedGroupID) @@ -49,7 +45,6 @@ class LokiTestUtilities : NSObject { case .rssFeed: groupID = LKGroupUtilities.getEncodedRSSFeedIDAsData(hexEncodedGroupID) default: return nil } - return TSGroupThread.getOrCreateThread(withGroupId: groupID, groupType: groupType) } } From 868725f513a90eff1575a0ab10feddb282987763 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Mon, 4 May 2020 16:17:45 +1000 Subject: [PATCH 05/10] Update Pods --- Pods | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pods b/Pods index cd26ded27..04c71c59e 160000 --- a/Pods +++ b/Pods @@ -1 +1 @@ -Subproject commit cd26ded27108becc8ea6660f3d8e6b58ee2bd6c7 +Subproject commit 04c71c59e4c3b060f8ff96b072efca3a74c4980f From 5cc11b90149d15ce77d19af8b985a0bc961d0407 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 5 May 2020 09:11:43 +1000 Subject: [PATCH 06/10] Partially fix friend request UI issues --- .../Loki/Components/FriendRequestView.swift | 4 +- .../ConversationView/Cells/OWSMessageCell.m | 2 + .../ConversationViewController.m | 59 +++++++++++-------- .../ConversationView/ConversationViewModel.h | 2 + SignalMessaging/utils/ThreadUtil.m | 11 ---- SignalServiceKit/src/Contacts/TSThread.h | 4 +- SignalServiceKit/src/Contacts/TSThread.m | 17 +++--- .../src/Messages/Interactions/TSMessage.h | 1 + .../src/Messages/Interactions/TSMessage.m | 6 +- 9 files changed, 58 insertions(+), 48 deletions(-) diff --git a/Signal/src/Loki/Components/FriendRequestView.swift b/Signal/src/Loki/Components/FriendRequestView.swift index f662b1ed4..750dd886e 100644 --- a/Signal/src/Loki/Components/FriendRequestView.swift +++ b/Signal/src/Loki/Components/FriendRequestView.swift @@ -106,7 +106,7 @@ final class FriendRequestView : UIView { updateUI() } - private func updateUI() { + @objc public func updateUI() { let thread = message.thread let friendRequestStatus = FriendRequestProtocol.getFriendRequestUIStatus(for: thread) guard let contactID = thread.contactIdentifier() else { return } @@ -127,7 +127,7 @@ final class FriendRequestView : UIView { switch friendRequestStatus { case .none: format = nil // The message failed to send case .friends: format = nil - case .received: return + case .received: return // Should never occur case .sent: format = NSLocalizedString("You've sent %@ a session request", comment: "") case .expired: format = NSLocalizedString("Your session request to %@ has expired", comment: "") } diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m index b541c1771..8609fe9b8 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m @@ -225,6 +225,8 @@ NS_ASSUME_NONNULL_BEGIN [self.friendRequestView autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:self.messageBubbleView], [self.friendRequestView autoPinEdgeToSuperviewEdge:ALEdgeBottom] ]]; + } else { + [self.friendRequestView removeFromSuperview]; } if ([self updateAvatarView]) { diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index 9a83e0c9e..fce608bd0 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -518,7 +518,6 @@ typedef enum : NSUInteger { - (void)handleGroupThreadUpdatedNotification:(NSNotification *)notification { OWSAssertIsOnMainThread(); - // Check thread NSString *threadID = (NSString *)notification.object; if (![threadID isEqualToString:self.thread.uniqueId]) { return; } @@ -526,29 +525,34 @@ typedef enum : NSUInteger { [self.thread reload]; // Update UI [self hideInputIfNeeded]; - [self resetContentAndLayout]; + [self.collectionView.collectionViewLayout invalidateLayout]; + for (id item in self.viewItems) { + [item clearCachedLayoutState]; + } + [self.conversationViewModel reloadViewItems]; + [self.collectionView reloadData]; } - (void)handleUserFriendRequestStatusChangedNotification:(NSNotification *)notification { + OWSAssertIsOnMainThread(); // Friend request status doesn't apply to group threads if (self.thread.isGroupThread) { return; } NSString *hexEncodedPublicKey = (NSString *)notification.object; // Check if we should update the UI - __block BOOL needsUpdate; + __block NSSet *linkedDevices; [OWSPrimaryStorage.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - NSSet *linkedDevices = [LKDatabaseUtilities getLinkedDeviceHexEncodedPublicKeysFor:self.thread.contactIdentifier in:transaction]; - needsUpdate = [linkedDevices containsObject:hexEncodedPublicKey]; + linkedDevices = [LKDatabaseUtilities getLinkedDeviceHexEncodedPublicKeysFor:self.thread.contactIdentifier in:transaction]; }]; - if (!needsUpdate) { return; } - // Ensure the thread instance is up to date - [self.thread reload]; + if (![linkedDevices containsObject:hexEncodedPublicKey]) { return; } // Update the UI + [self updateInputBar]; + [self.collectionView.collectionViewLayout invalidateLayout]; for (id item in self.viewItems) { [item clearCachedLayoutState]; } - [self updateInputToolbar]; - [self resetContentAndLayout]; + [self.conversationViewModel reloadViewItems]; + [self.collectionView reloadData]; } - (void)handleThreadSessionRestoreDevicesChangedNotifiaction:(NSNotification *)notification @@ -665,6 +669,7 @@ typedef enum : NSUInteger { self.inputToolbar.hidden = NO; } + // Loki: In RSS feeds, don't hide the input bar entirely; just hide the text field inside. if (self.isRSSFeed) { [self.inputToolbar hideInputMethod]; } @@ -780,7 +785,7 @@ typedef enum : NSUInteger { self.inputToolbar.inputToolbarDelegate = self; self.inputToolbar.inputTextViewDelegate = self; SET_SUBVIEW_ACCESSIBILITY_IDENTIFIER(self, _inputToolbar); - [self updateInputToolbar]; + [self updateInputBar]; self.loadMoreHeader = [UILabel new]; self.loadMoreHeader.text = NSLocalizedString(@"CONVERSATION_VIEW_LOADING_MORE_MESSAGES", @"Indicates that the app is loading more messages in this conversation."); @@ -921,7 +926,7 @@ typedef enum : NSUInteger { NSTimeInterval appearenceDuration = CACurrentMediaTime() - self.viewControllerCreatedAt; OWSLogVerbose(@"First viewWillAppear took: %.2fms", appearenceDuration * 1000); } - [self updateInputToolbarLayout]; + [self updateInputBarLayout]; } - (NSArray> *)viewItems @@ -1048,7 +1053,7 @@ typedef enum : NSUInteger { - (void)updateSessionRestoreBanner { BOOL isContactThread = [self.thread isKindOfClass:[TSContactThread class]]; - BOOL shouldRemoveBanner = !isContactThread; + BOOL shouldDetachBanner = !isContactThread; if (isContactThread) { TSContactThread *thread = (TSContactThread *)self.thread; if (thread.sessionRestoreDevices.count > 0) { @@ -1068,11 +1073,10 @@ typedef enum : NSUInteger { }]; } } else { - shouldRemoveBanner = true; + shouldDetachBanner = true; } } - - if (shouldRemoveBanner && self.restoreSessionBannerView) { + if (shouldDetachBanner && self.restoreSessionBannerView != nil) { [self.restoreSessionBannerView removeFromSuperview]; self.restoreSessionBannerView = nil; } @@ -1461,7 +1465,7 @@ typedef enum : NSUInteger { // Clear the "on open" state after the view has been presented. self.actionOnOpen = ConversationViewActionNone; - [self updateInputToolbarLayout]; + [self updateInputBarLayout]; [self ensureScrollDownButton]; } @@ -1668,7 +1672,7 @@ typedef enum : NSUInteger { #pragma mark - Updating -- (void)updateInputToolbar { +- (void)updateInputBar { BOOL shouldInputBarBeEnabled = [LKFriendRequestProtocol shouldInputBarBeEnabledForThread:self.thread]; [self.inputToolbar setUserInteractionEnabled:shouldInputBarBeEnabled]; NSString *placeholderText = shouldInputBarBeEnabled ? NSLocalizedString(@"Message", "") : NSLocalizedString(@"Pending session request", ""); @@ -2890,6 +2894,15 @@ typedef enum : NSUInteger { AudioServicesPlaySystemSound(soundId); } [self.typingIndicators didSendOutgoingMessageInThread:self.thread]; + + // Loki: Lock the input bar early + if ([self.thread isKindOfClass:TSContactThread.class] && [message isKindOfClass:LKFriendRequestMessage.class]) { + NSString *recipientID = self.thread.contactIdentifier; + OWSAssertIsOnMainThread(); + [OWSPrimaryStorage.sharedManager.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + [LKFriendRequestProtocol setFriendRequestStatusToSendingIfNeededForHexEncodedPublicKey:recipientID transaction:transaction]; + }]; + } } #pragma mark UIDocumentMenuDelegate @@ -5086,7 +5099,7 @@ typedef enum : NSUInteger { } [self dismissMenuActionsIfNecessary]; - [self updateInputToolbar]; + [self updateInputBar]; if (self.isGroupConversation) { [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { @@ -5332,7 +5345,7 @@ typedef enum : NSUInteger { // new size. [strongSelf resetForSizeOrOrientationChange]; - [strongSelf updateInputToolbarLayout]; + [strongSelf updateInputBarLayout]; if (self.menuActionsViewController != nil) { [self scrollToMenuActionInteraction:NO]; @@ -5367,17 +5380,17 @@ typedef enum : NSUInteger { // Try to update the lastKnownDistanceFromBottom; the content size may have changed. [self updateLastKnownDistanceFromBottom]; } - [self updateInputToolbarLayout]; + [self updateInputBarLayout]; } - (void)viewSafeAreaInsetsDidChange { [super viewSafeAreaInsetsDidChange]; - [self updateInputToolbarLayout]; + [self updateInputBarLayout]; } -- (void)updateInputToolbarLayout +- (void)updateInputBarLayout { UIEdgeInsets safeAreaInsets = UIEdgeInsetsZero; if (@available(iOS 11, *)) { diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewModel.h b/Signal/src/ViewControllers/ConversationView/ConversationViewModel.h index 1b9c4d86a..daa28db23 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewModel.h +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewModel.h @@ -123,6 +123,8 @@ typedef NS_ENUM(NSUInteger, ConversationUpdateItemType) { - (void)appendUnsavedOutgoingTextMessage:(TSOutgoingMessage *)outgoingMessage; +- (BOOL)reloadViewItems; + @end NS_ASSUME_NONNULL_END diff --git a/SignalMessaging/utils/ThreadUtil.m b/SignalMessaging/utils/ThreadUtil.m index d9dd7e10d..a1516c539 100644 --- a/SignalMessaging/utils/ThreadUtil.m +++ b/SignalMessaging/utils/ThreadUtil.m @@ -184,17 +184,6 @@ typedef void (^BuildOutgoingMessageCompletionBlock)(TSOutgoingMessage *savedMess // If we're friends then the assumption is that we have the other user's pre key bundle. NSString *messageClassAsString = (thread.isContactFriend || thread.isGroupThread || thread.isNoteToSelf) ? @"TSOutgoingMessage" : @"LKFriendRequestMessage"; Class messageClass = NSClassFromString(messageClassAsString); - - if ([messageClassAsString isEqual:@"LKFriendRequestMessage"]) { - NSString *recipientID = thread.contactIdentifier; - if (recipientID != nil) { - dispatch_async(dispatch_get_main_queue(), ^{ - [OWSPrimaryStorage.sharedManager.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [LKFriendRequestProtocol setFriendRequestStatusToSendingIfNeededForHexEncodedPublicKey:recipientID transaction:transaction]; - }]; - }); - } - } TSOutgoingMessage *message = [[messageClass alloc] initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp] diff --git a/SignalServiceKit/src/Contacts/TSThread.h b/SignalServiceKit/src/Contacts/TSThread.h index daf08b30e..468031a0d 100644 --- a/SignalServiceKit/src/Contacts/TSThread.h +++ b/SignalServiceKit/src/Contacts/TSThread.h @@ -184,12 +184,12 @@ extern ConversationColorName const kConversationColorName_Default; #pragma mark - Loki Friend Request Handling /** - Remove any outgoing friend request message which failed to send + Remove any old outgoing friend request messages that failed to send. */ - (void)removeOldOutgoingFriendRequestMessagesIfNeededWithTransaction:(YapDatabaseReadWriteTransaction *)transaction; /** - Remove any old incoming friend request message that is still pending + Remove any old incoming friend request messages that are pending. */ - (void)removeOldIncomingFriendRequestMessagesIfNeededWithTransaction:(YapDatabaseReadWriteTransaction *)transaction; diff --git a/SignalServiceKit/src/Contacts/TSThread.m b/SignalServiceKit/src/Contacts/TSThread.m index 33571237a..3696e266a 100644 --- a/SignalServiceKit/src/Contacts/TSThread.m +++ b/SignalServiceKit/src/Contacts/TSThread.m @@ -722,12 +722,13 @@ ConversationColorName const kConversationColorName_Default = ConversationColorNa - (void)removeOldFriendRequestMessagesIfNeeded:(OWSInteractionType)interactionType withTransaction:(YapDatabaseReadWriteTransaction *)transaction { - // If we're friends with the person then we don't need to remove any friend request messages + // Friend request status doesn't apply to group threads if (self.isGroupThread) { return; } + // If we're friends with the other person then we don't need to remove any friend request messages if ([LKFriendRequestProtocol isFriendsWithAnyLinkedDeviceOfHexEncodedPublicKey:self.contactIdentifier]) { return; } NSMutableArray *idsToRemove = [NSMutableArray new]; - __block TSMessage *_Nullable messageToKeep = nil; // We want to keep this interaction and not remove it + __block TSMessage *_Nullable messageToKeep = nil; [self enumerateInteractionsWithTransaction:transaction usingBlock:^(TSInteraction *interaction, YapDatabaseReadTransaction *transaction) { if (interaction.interactionType != interactionType) { return; } @@ -754,14 +755,14 @@ ConversationColorName const kConversationColorName_Default = ConversationColorNa } }]; - for (NSString *interactionId in idsToRemove) { - // Don't delete the recent message - if (messageToKeep != nil && interactionId == messageToKeep.uniqueId) { continue; } + for (NSString *interactionID in idsToRemove) { + // Don't delete the most recent message + if (messageToKeep != nil && interactionID == messageToKeep.uniqueId) { continue; } // We need to fetch each interaction, since [TSInteraction removeWithTransaction:] does important work - TSInteraction *_Nullable interaction = [TSInteraction fetchObjectWithUniqueID:interactionId transaction:transaction]; - if (!interaction) { - OWSFailDebug(@"couldn't load thread's interaction for deletion."); + TSInteraction *_Nullable interaction = [TSInteraction fetchObjectWithUniqueID:interactionID transaction:transaction]; + if (interaction == nil) { + OWSFailDebug(@"Couldn't load interaction."); continue; } [interaction removeWithTransaction:transaction]; diff --git a/SignalServiceKit/src/Messages/Interactions/TSMessage.h b/SignalServiceKit/src/Messages/Interactions/TSMessage.h index bca04ac94..816bb67f9 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSMessage.h +++ b/SignalServiceKit/src/Messages/Interactions/TSMessage.h @@ -40,6 +40,7 @@ typedef NS_ENUM(NSInteger, LKMessageFriendRequestStatus) { @property (nonatomic, nullable) OWSLinkPreview *linkPreview; // Loki friend request handling @property (nonatomic) LKMessageFriendRequestStatus friendRequestStatus __deprecated_msg("no longer used as of version 1.1.2"); +/// Only relevant to outgoing messages. @property (nonatomic) uint64_t friendRequestExpiresAt; @property (nonatomic, readonly) BOOL isFriendRequest; @property (nonatomic, readonly) BOOL hasFriendRequestStatusMessage; diff --git a/SignalServiceKit/src/Messages/Interactions/TSMessage.m b/SignalServiceKit/src/Messages/Interactions/TSMessage.m index 272a78847..86a2a182f 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSMessage.m +++ b/SignalServiceKit/src/Messages/Interactions/TSMessage.m @@ -475,13 +475,15 @@ static const NSUInteger OWSMessageSchemaVersion = 4; - (BOOL)isFriendRequest { - return [LKFriendRequestProtocol getFriendRequestUIStatusForThread:self.thread] != LKFriendRequestUIStatusFriends; + if (self.thread.isContactFriend) { return NO; } + return [self.uniqueId isEqual:self.thread.lastInteraction.uniqueId]; } - (BOOL)hasFriendRequestStatusMessage { LKFriendRequestUIStatus friendRequestStatus = [LKFriendRequestProtocol getFriendRequestUIStatusForThread:self.thread]; - return friendRequestStatus != LKFriendRequestUIStatusNone && friendRequestStatus != LKFriendRequestUIStatusFriends; + if (friendRequestStatus == LKFriendRequestUIStatusNone || friendRequestStatus == LKFriendRequestUIStatusFriends) { return NO; }; + return [self.uniqueId isEqual:self.thread.lastInteraction.uniqueId]; } #pragma mark - Open Groups From 0890f65e61f4cdc9b435dc4e3bbc41ecb5ada028 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Tue, 5 May 2020 09:30:46 +1000 Subject: [PATCH 07/10] Added isSlaveThread tests. --- ...UpdateFriendRequestStatusStorageTest.swift | 14 +---- .../Multi Device/MultiDeviceProtocol.swift | 2 +- .../MultiDeviceProtocolTests.swift | 53 +++++++++++++++++++ 3 files changed, 56 insertions(+), 13 deletions(-) diff --git a/SignalMessaging/Loki/Migrations/LK001UpdateFriendRequestStatusStorageTest.swift b/SignalMessaging/Loki/Migrations/LK001UpdateFriendRequestStatusStorageTest.swift index efd9da286..60fb0b078 100644 --- a/SignalMessaging/Loki/Migrations/LK001UpdateFriendRequestStatusStorageTest.swift +++ b/SignalMessaging/Loki/Migrations/LK001UpdateFriendRequestStatusStorageTest.swift @@ -9,17 +9,7 @@ class LK001UpdateFriendRequestStatusStorageTest : XCTestCase { override func setUp() { super.setUp() - ClearCurrentAppContextForTests() - SetCurrentAppContext(TestAppContext()) - MockSSKEnvironment.activate() - - let identityManager = OWSIdentityManager.shared() - let seed = Randomness.generateRandomBytes(16)! - let keyPair = Curve25519.generateKeyPair(fromSeed: seed + seed) - let databaseConnection = identityManager.value(forKey: "dbConnection") as! YapDatabaseConnection - databaseConnection.setObject(keyPair, forKey: OWSPrimaryStorageIdentityKeyStoreIdentityKey, inCollection: OWSPrimaryStorageIdentityKeyStoreCollection) - TSAccountManager.sharedInstance().phoneNumberAwaitingVerification = keyPair.hexEncodedPublicKey - TSAccountManager.sharedInstance().didRegister() + LokiTestUtilities.setUpMockEnvironment() } func test_shouldMigrateFriendRequestStatusCorrectly() { @@ -54,7 +44,7 @@ class LK001UpdateFriendRequestStatusStorageTest : XCTestCase { } wait(for: [ migration ], timeout: 5) - storage.dbReadWriteConnection.readWrite { transaction in + storage.dbReadConnection.read { transaction in for (hexEncodedPublicKey, threadFriendRequestStatus) in hexEncodedPublicKeyMapping { let expectedFriendRequestStatus = friendRequestMappings[threadFriendRequestStatus]! let friendRequestStatus = self.storage.getFriendRequestStatus(for: hexEncodedPublicKey, transaction: transaction) diff --git a/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocol.swift b/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocol.swift index afc73a8bf..5a2db292f 100644 --- a/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocol.swift +++ b/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocol.swift @@ -265,7 +265,7 @@ public final class MultiDeviceProtocol : NSObject { @objc public static func isSlaveThread(_ thread: TSThread) -> Bool { guard let thread = thread as? TSContactThread else { return false } var isSlaveThread = false - Storage.read { transaction in + storage.dbReadConnection.read { transaction in isSlaveThread = storage.getMasterHexEncodedPublicKey(for: thread.contactIdentifier(), in: transaction) != nil } return isSlaveThread diff --git a/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocolTests.swift b/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocolTests.swift index 1f4cb274b..ac0dece40 100644 --- a/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocolTests.swift +++ b/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocolTests.swift @@ -4,5 +4,58 @@ import XCTest class MultiDeviceProtocolTests : XCTestCase { + private var storage: OWSPrimaryStorage { OWSPrimaryStorage.shared() } + + override func setUp() { + super.setUp() + + LokiTestUtilities.setUpMockEnvironment() + } + + // MARK: - isSlaveThread + + func test_isSlaveThreadShouldReturnFalseOnGroupThreads() { + let allGroupTypes: [GroupType] = [ .closedGroup, .openGroup, .rssFeed ] + for groupType in allGroupTypes { + guard let groupThread = LokiTestUtilities.createGroupThread(groupType: groupType) else { return XCTFail() } + XCTAssertFalse(MultiDeviceProtocol.isSlaveThread(groupThread)) + } + } + + func test_isSlaveThreadShouldReturnTheCorrectValues() { + let master = LokiTestUtilities.generateHexEncodedPublicKey() + let slave = LokiTestUtilities.generateHexEncodedPublicKey() + let other = LokiTestUtilities.generateHexEncodedPublicKey() + + guard let masterDevice = LokiTestUtilities.getDevice(for: master) else { return XCTFail() } + guard let slaveDevice = LokiTestUtilities.getDevice(for: slave) else { return XCTFail() } + let deviceLink = DeviceLink(between: masterDevice, and: slaveDevice) + storage.dbReadWriteConnection.readWrite { transaction in + self.storage.addDeviceLink(deviceLink, in: transaction) + } + + let masterThread = LokiTestUtilities.createContactThread(for: master) + let slaveThread = LokiTestUtilities.createContactThread(for: slave) + let otherThread = LokiTestUtilities.createContactThread(for: other) + + storage.dbReadWriteConnection.read { transaction in + XCTAssertNotNil(self.storage.getMasterHexEncodedPublicKey(for: slaveThread.contactIdentifier(), in: transaction)) + } + + XCTAssertFalse(MultiDeviceProtocol.isSlaveThread(masterThread)) + XCTAssertTrue(MultiDeviceProtocol.isSlaveThread(slaveThread)) + XCTAssertFalse(MultiDeviceProtocol.isSlaveThread(otherThread)) + } + + func test_isSlaveThreadShouldWorkInsideATransaction() { + let bob = LokiTestUtilities.generateHexEncodedPublicKey() + let thread = LokiTestUtilities.createContactThread(for: bob) + storage.dbReadWriteConnection.read { transaction in + XCTAssertNoThrow(MultiDeviceProtocol.isSlaveThread(thread)) + } + storage.dbReadWriteConnection.readWrite { transaction in + XCTAssertNoThrow(MultiDeviceProtocol.isSlaveThread(thread)) + } + } } From a9b3f3a6ca9c96beaa6d7c80965461d4ba331398 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 5 May 2020 09:32:20 +1000 Subject: [PATCH 08/10] Fix constraint issue --- .../src/ViewControllers/ConversationView/Cells/OWSMessageCell.m | 1 + 1 file changed, 1 insertion(+) diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m index 8609fe9b8..40cf4a619 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m @@ -227,6 +227,7 @@ NS_ASSUME_NONNULL_BEGIN ]]; } else { [self.friendRequestView removeFromSuperview]; + [self.messageBubbleViewBottomConstraint setActive:YES]; } if ([self updateAvatarView]) { From 0944725a35e97e89d3fd2b04654c88bc9383f092 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 5 May 2020 10:15:58 +1000 Subject: [PATCH 09/10] Maintain friend request view correctly --- Signal/src/Loki/Components/FriendRequestView.swift | 2 +- .../src/ViewControllers/ConversationView/Cells/OWSMessageCell.m | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Signal/src/Loki/Components/FriendRequestView.swift b/Signal/src/Loki/Components/FriendRequestView.swift index 750dd886e..1854a3c61 100644 --- a/Signal/src/Loki/Components/FriendRequestView.swift +++ b/Signal/src/Loki/Components/FriendRequestView.swift @@ -114,7 +114,7 @@ final class FriendRequestView : UIView { let format: String? switch kind { case .incoming: - buttonStackView.isHidden = friendRequestStatus != .received + buttonStackView.isHidden = (friendRequestStatus != .received) spacer2.isHidden = buttonStackView.isHidden switch friendRequestStatus { case .none: format = NSLocalizedString("You've declined %@'s session request", comment: "") diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m index 40cf4a619..1b35b058e 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSMessageCell.m @@ -227,6 +227,7 @@ NS_ASSUME_NONNULL_BEGIN ]]; } else { [self.friendRequestView removeFromSuperview]; + self.friendRequestView = nil; [self.messageBubbleViewBottomConstraint setActive:YES]; } From c545efbe72c8f2c86298c3323baa0aedc33eae62 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 5 May 2020 10:18:24 +1000 Subject: [PATCH 10/10] Minor refactoring --- .../Protocol/Multi Device/MultiDeviceProtocolTests.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocolTests.swift b/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocolTests.swift index ac0dece40..d3e714b8a 100644 --- a/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocolTests.swift +++ b/SignalServiceKit/src/Loki/Protocol/Multi Device/MultiDeviceProtocolTests.swift @@ -8,7 +8,6 @@ class MultiDeviceProtocolTests : XCTestCase { override func setUp() { super.setUp() - LokiTestUtilities.setUpMockEnvironment() } @@ -29,7 +28,9 @@ class MultiDeviceProtocolTests : XCTestCase { guard let masterDevice = LokiTestUtilities.getDevice(for: master) else { return XCTFail() } guard let slaveDevice = LokiTestUtilities.getDevice(for: slave) else { return XCTFail() } + let deviceLink = DeviceLink(between: masterDevice, and: slaveDevice) + storage.dbReadWriteConnection.readWrite { transaction in self.storage.addDeviceLink(deviceLink, in: transaction) } @@ -38,7 +39,7 @@ class MultiDeviceProtocolTests : XCTestCase { let slaveThread = LokiTestUtilities.createContactThread(for: slave) let otherThread = LokiTestUtilities.createContactThread(for: other) - storage.dbReadWriteConnection.read { transaction in + storage.dbReadConnection.read { transaction in XCTAssertNotNil(self.storage.getMasterHexEncodedPublicKey(for: slaveThread.contactIdentifier(), in: transaction)) } @@ -57,5 +58,4 @@ class MultiDeviceProtocolTests : XCTestCase { XCTAssertNoThrow(MultiDeviceProtocol.isSlaveThread(thread)) } } - }