From 595864dba93d1cfe4cbc32199f0ea5e92ed1c369 Mon Sep 17 00:00:00 2001 From: Giovani Gonzalez Date: Fri, 24 Nov 2023 18:25:48 -0600 Subject: [PATCH 1/6] Adding a filter to not show conversations that contain no valid topics --- Sources/XMTP/Conversations.swift | 15 ++++++- Tests/XMTPTests/ConversationsTest.swift | 60 +++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/Sources/XMTP/Conversations.swift b/Sources/XMTP/Conversations.swift index 9b9bd3ea..b6629c43 100644 --- a/Sources/XMTP/Conversations.swift +++ b/Sources/XMTP/Conversations.swift @@ -236,7 +236,7 @@ public actor Conversations { } newConversations - .filter { $0.peerAddress != client.address } + .filter { $0.peerAddress != client.address && isValidTopic(topic: $0.topic) } .forEach { conversationsByTopic[$0.topic] = $0 } // TODO(perf): use DB to persist + sort @@ -244,6 +244,19 @@ public actor Conversations { a.createdAt < b.createdAt } } + + public func isValidTopic(topic: String) -> Bool { + let regex = "^[\\x00-\\x7F]+$" + let initialIndex = String.Index(utf16Offset: 8, in: topic) + let finalIndex = topic.lastIndex(of: "/") + if finalIndex != nil { + let unwrappedTopic = String(topic[initialIndex.. [String: Date] { let envelopes = try await client.apiClient.query( diff --git a/Tests/XMTPTests/ConversationsTest.swift b/Tests/XMTPTests/ConversationsTest.swift index c68810de..b485c035 100644 --- a/Tests/XMTPTests/ConversationsTest.swift +++ b/Tests/XMTPTests/ConversationsTest.swift @@ -78,4 +78,64 @@ class ConversationsTests: XCTestCase { await waitForExpectations(timeout: 3) } + + func testCanValidateTopicsInsideConversation() async throws { + let validId = "sdfsadf095b97a9284dcd82b2274856ccac8a21de57bebe34e7f9eeb855fb21126d3b8f" + let fixtures = await fixtures() + + // Creation of all known types of topics + let privateStore = Topic.userPrivateStoreKeyBundle(validId).description + let contact = Topic.contact(validId).description + let userIntro = Topic.userIntro(validId).description + let userInvite = Topic.userInvite(validId).description + let directMessageV1 = Topic.directMessageV1(validId, "sd").description + let directMessageV2 = Topic.directMessageV2(validId).description + let preferenceList = Topic.preferenceList(validId).description + let conversations = fixtures.bobClient.conversations + + // check if validation of topics accepts all types + Task(priority: .userInitiated) { + let resultPrivateStore = await conversations.isValidTopic(topic: privateStore) + let resultContact = await conversations.isValidTopic(topic: contact) + let resultUserIntro = await conversations.isValidTopic(topic: userIntro) + let resultUserInvite = await conversations.isValidTopic(topic: userInvite) + let resultDirectMessageV1 = await conversations.isValidTopic(topic: directMessageV1) + let resultDirectMessageV2 = await conversations.isValidTopic(topic: directMessageV2) + let resultPreferenceList = await conversations.isValidTopic(topic: preferenceList) + XCTAssertTrue( + resultPrivateStore && resultContact && resultUserIntro && resultUserInvite && + resultDirectMessageV1 && resultDirectMessageV2 && resultPreferenceList + ) + } + } + + func testCannotValidateTopicsInsideConversation() async throws { + let invalidId = "��\\u0005�!\\u000b���5\\u00001\\u0007�蛨\\u001f\\u00172��.����K9K`�" + let fixtures = await fixtures() + + // Creation of all known types of topics + let privateStore = Topic.userPrivateStoreKeyBundle(invalidId).description + let contact = Topic.contact(invalidId).description + let userIntro = Topic.userIntro(invalidId).description + let userInvite = Topic.userInvite(invalidId).description + let directMessageV1 = Topic.directMessageV1(invalidId, "sd").description + let directMessageV2 = Topic.directMessageV2(invalidId).description + let preferenceList = Topic.preferenceList(invalidId).description + let conversations = fixtures.bobClient.conversations + + // check if validation of topics declines all types + Task(priority: .userInitiated) { + let resultPrivateStore = await conversations.isValidTopic(topic: privateStore) + let resultContact = await conversations.isValidTopic(topic: contact) + let resultUserIntro = await conversations.isValidTopic(topic: userIntro) + let resultUserInvite = await conversations.isValidTopic(topic: userInvite) + let resultDirectMessageV1 = await conversations.isValidTopic(topic: directMessageV1) + let resultDirectMessageV2 = await conversations.isValidTopic(topic: directMessageV2) + let resultPreferenceList = await conversations.isValidTopic(topic: preferenceList) + XCTAssertFalse( + resultPrivateStore && resultContact && resultUserIntro && resultUserInvite && + resultDirectMessageV1 && resultDirectMessageV2 && resultPreferenceList + ) + } + } } From b1a62fb15b85bfee8b0e3221bae6c5aa6b414fff Mon Sep 17 00:00:00 2001 From: Giovani Gonzalez <78755438+giovasdistillery@users.noreply.github.com> Date: Mon, 27 Nov 2023 13:42:21 -0600 Subject: [PATCH 2/6] removing lint error for force violation issue Co-authored-by: Naomi Plasterer --- Sources/XMTP/Conversations.swift | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Sources/XMTP/Conversations.swift b/Sources/XMTP/Conversations.swift index b6629c43..1b821d09 100644 --- a/Sources/XMTP/Conversations.swift +++ b/Sources/XMTP/Conversations.swift @@ -248,9 +248,8 @@ public actor Conversations { public func isValidTopic(topic: String) -> Bool { let regex = "^[\\x00-\\x7F]+$" let initialIndex = String.Index(utf16Offset: 8, in: topic) - let finalIndex = topic.lastIndex(of: "/") - if finalIndex != nil { - let unwrappedTopic = String(topic[initialIndex.. Date: Mon, 27 Nov 2023 14:28:04 -0600 Subject: [PATCH 3/6] Update XMTP.podspec Update pod version to trigger the build --- XMTP.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/XMTP.podspec b/XMTP.podspec index edec8162..f22aee5e 100644 --- a/XMTP.podspec +++ b/XMTP.podspec @@ -16,7 +16,7 @@ Pod::Spec.new do |spec| # spec.name = "XMTP" - spec.version = "0.6.9-alpha0" + spec.version = "0.6.10-alpha0" spec.summary = "XMTP SDK Cocoapod" # This description is used to generate tags and improve search results. From 99c39b7b87e419b376bf23fdf40d3b4f99e14982 Mon Sep 17 00:00:00 2001 From: Giovani Gonzalez Date: Tue, 28 Nov 2023 12:41:23 -0600 Subject: [PATCH 4/6] Moving validation to Topic object --- Sources/XMTP/Conversations.swift | 14 +----------- Sources/XMTP/Messages/Topic.swift | 4 ++++ Tests/XMTPTests/ConversationsTest.swift | 30 ++++++++++++------------- 3 files changed, 19 insertions(+), 29 deletions(-) diff --git a/Sources/XMTP/Conversations.swift b/Sources/XMTP/Conversations.swift index 1b821d09..9998a354 100644 --- a/Sources/XMTP/Conversations.swift +++ b/Sources/XMTP/Conversations.swift @@ -236,7 +236,7 @@ public actor Conversations { } newConversations - .filter { $0.peerAddress != client.address && isValidTopic(topic: $0.topic) } + .filter { $0.peerAddress != client.address && Topic.isValidTopic(topic: $0.topic) } .forEach { conversationsByTopic[$0.topic] = $0 } // TODO(perf): use DB to persist + sort @@ -244,18 +244,6 @@ public actor Conversations { a.createdAt < b.createdAt } } - - public func isValidTopic(topic: String) -> Bool { - let regex = "^[\\x00-\\x7F]+$" - let initialIndex = String.Index(utf16Offset: 8, in: topic) - if let finalIndex = topic.lastIndex(of: "/") { - let unwrappedTopic = String(topic[initialIndex.. [String: Date] { let envelopes = try await client.apiClient.query( diff --git a/Sources/XMTP/Messages/Topic.swift b/Sources/XMTP/Messages/Topic.swift index fde788f7..724b804c 100644 --- a/Sources/XMTP/Messages/Topic.swift +++ b/Sources/XMTP/Messages/Topic.swift @@ -39,4 +39,8 @@ public enum Topic { private func wrap(_ value: String) -> String { "/xmtp/0/\(value)/proto" } + + static func isValidTopic(topic: String) -> Bool { + return topic.allSatisfy(\.isASCII) + } } diff --git a/Tests/XMTPTests/ConversationsTest.swift b/Tests/XMTPTests/ConversationsTest.swift index b485c035..be4a913b 100644 --- a/Tests/XMTPTests/ConversationsTest.swift +++ b/Tests/XMTPTests/ConversationsTest.swift @@ -91,17 +91,16 @@ class ConversationsTests: XCTestCase { let directMessageV1 = Topic.directMessageV1(validId, "sd").description let directMessageV2 = Topic.directMessageV2(validId).description let preferenceList = Topic.preferenceList(validId).description - let conversations = fixtures.bobClient.conversations // check if validation of topics accepts all types Task(priority: .userInitiated) { - let resultPrivateStore = await conversations.isValidTopic(topic: privateStore) - let resultContact = await conversations.isValidTopic(topic: contact) - let resultUserIntro = await conversations.isValidTopic(topic: userIntro) - let resultUserInvite = await conversations.isValidTopic(topic: userInvite) - let resultDirectMessageV1 = await conversations.isValidTopic(topic: directMessageV1) - let resultDirectMessageV2 = await conversations.isValidTopic(topic: directMessageV2) - let resultPreferenceList = await conversations.isValidTopic(topic: preferenceList) + let resultPrivateStore = Topic.isValidTopic(topic: privateStore) + let resultContact = Topic.isValidTopic(topic: contact) + let resultUserIntro = Topic.isValidTopic(topic: userIntro) + let resultUserInvite = Topic.isValidTopic(topic: userInvite) + let resultDirectMessageV1 = Topic.isValidTopic(topic: directMessageV1) + let resultDirectMessageV2 = Topic.isValidTopic(topic: directMessageV2) + let resultPreferenceList = Topic.isValidTopic(topic: preferenceList) XCTAssertTrue( resultPrivateStore && resultContact && resultUserIntro && resultUserInvite && resultDirectMessageV1 && resultDirectMessageV2 && resultPreferenceList @@ -121,17 +120,16 @@ class ConversationsTests: XCTestCase { let directMessageV1 = Topic.directMessageV1(invalidId, "sd").description let directMessageV2 = Topic.directMessageV2(invalidId).description let preferenceList = Topic.preferenceList(invalidId).description - let conversations = fixtures.bobClient.conversations // check if validation of topics declines all types Task(priority: .userInitiated) { - let resultPrivateStore = await conversations.isValidTopic(topic: privateStore) - let resultContact = await conversations.isValidTopic(topic: contact) - let resultUserIntro = await conversations.isValidTopic(topic: userIntro) - let resultUserInvite = await conversations.isValidTopic(topic: userInvite) - let resultDirectMessageV1 = await conversations.isValidTopic(topic: directMessageV1) - let resultDirectMessageV2 = await conversations.isValidTopic(topic: directMessageV2) - let resultPreferenceList = await conversations.isValidTopic(topic: preferenceList) + let resultPrivateStore = Topic.isValidTopic(topic: privateStore) + let resultContact = Topic.isValidTopic(topic: contact) + let resultUserIntro = Topic.isValidTopic(topic: userIntro) + let resultUserInvite = Topic.isValidTopic(topic: userInvite) + let resultDirectMessageV1 = Topic.isValidTopic(topic: directMessageV1) + let resultDirectMessageV2 = Topic.isValidTopic(topic: directMessageV2) + let resultPreferenceList = Topic.isValidTopic(topic: preferenceList) XCTAssertFalse( resultPrivateStore && resultContact && resultUserIntro && resultUserInvite && resultDirectMessageV1 && resultDirectMessageV2 && resultPreferenceList From 76f5bcfc3378698fd6c7068dd50f82e15a08f2c0 Mon Sep 17 00:00:00 2001 From: Giovani Gonzalez Date: Tue, 28 Nov 2023 12:53:08 -0600 Subject: [PATCH 5/6] Update ConversationsTest.swift Split assertions --- Tests/XMTPTests/ConversationsTest.swift | 42 +++++++++---------------- 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/Tests/XMTPTests/ConversationsTest.swift b/Tests/XMTPTests/ConversationsTest.swift index be4a913b..f87e7d8a 100644 --- a/Tests/XMTPTests/ConversationsTest.swift +++ b/Tests/XMTPTests/ConversationsTest.swift @@ -81,7 +81,6 @@ class ConversationsTests: XCTestCase { func testCanValidateTopicsInsideConversation() async throws { let validId = "sdfsadf095b97a9284dcd82b2274856ccac8a21de57bebe34e7f9eeb855fb21126d3b8f" - let fixtures = await fixtures() // Creation of all known types of topics let privateStore = Topic.userPrivateStoreKeyBundle(validId).description @@ -93,24 +92,17 @@ class ConversationsTests: XCTestCase { let preferenceList = Topic.preferenceList(validId).description // check if validation of topics accepts all types - Task(priority: .userInitiated) { - let resultPrivateStore = Topic.isValidTopic(topic: privateStore) - let resultContact = Topic.isValidTopic(topic: contact) - let resultUserIntro = Topic.isValidTopic(topic: userIntro) - let resultUserInvite = Topic.isValidTopic(topic: userInvite) - let resultDirectMessageV1 = Topic.isValidTopic(topic: directMessageV1) - let resultDirectMessageV2 = Topic.isValidTopic(topic: directMessageV2) - let resultPreferenceList = Topic.isValidTopic(topic: preferenceList) - XCTAssertTrue( - resultPrivateStore && resultContact && resultUserIntro && resultUserInvite && - resultDirectMessageV1 && resultDirectMessageV2 && resultPreferenceList - ) - } + XCTAssertTrue(Topic.isValidTopic(topic: privateStore)) + XCTAssertTrue(Topic.isValidTopic(topic: contact)) + XCTAssertTrue(Topic.isValidTopic(topic: userIntro)) + XCTAssertTrue(Topic.isValidTopic(topic: userInvite)) + XCTAssertTrue(Topic.isValidTopic(topic: directMessageV1)) + XCTAssertTrue(Topic.isValidTopic(topic: directMessageV2)) + XCTAssertTrue(Topic.isValidTopic(topic: preferenceList)) } func testCannotValidateTopicsInsideConversation() async throws { let invalidId = "��\\u0005�!\\u000b���5\\u00001\\u0007�蛨\\u001f\\u00172��.����K9K`�" - let fixtures = await fixtures() // Creation of all known types of topics let privateStore = Topic.userPrivateStoreKeyBundle(invalidId).description @@ -122,18 +114,12 @@ class ConversationsTests: XCTestCase { let preferenceList = Topic.preferenceList(invalidId).description // check if validation of topics declines all types - Task(priority: .userInitiated) { - let resultPrivateStore = Topic.isValidTopic(topic: privateStore) - let resultContact = Topic.isValidTopic(topic: contact) - let resultUserIntro = Topic.isValidTopic(topic: userIntro) - let resultUserInvite = Topic.isValidTopic(topic: userInvite) - let resultDirectMessageV1 = Topic.isValidTopic(topic: directMessageV1) - let resultDirectMessageV2 = Topic.isValidTopic(topic: directMessageV2) - let resultPreferenceList = Topic.isValidTopic(topic: preferenceList) - XCTAssertFalse( - resultPrivateStore && resultContact && resultUserIntro && resultUserInvite && - resultDirectMessageV1 && resultDirectMessageV2 && resultPreferenceList - ) - } + XCTAssertFalse(Topic.isValidTopic(topic: privateStore)) + XCTAssertFalse(Topic.isValidTopic(topic: contact)) + XCTAssertFalse(Topic.isValidTopic(topic: userIntro)) + XCTAssertFalse(Topic.isValidTopic(topic: userInvite)) + XCTAssertFalse(Topic.isValidTopic(topic: directMessageV1)) + XCTAssertFalse(Topic.isValidTopic(topic: directMessageV2)) + XCTAssertFalse(Topic.isValidTopic(topic: preferenceList)) } } From 69e4d1984f4f5aee6196b7eb9cc3bea712ba7199 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Thu, 30 Nov 2023 14:09:32 -0800 Subject: [PATCH 6/6] bump the pod spec again --- XMTP.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/XMTP.podspec b/XMTP.podspec index 8ba20f8a..2bd70cb5 100644 --- a/XMTP.podspec +++ b/XMTP.podspec @@ -16,7 +16,7 @@ Pod::Spec.new do |spec| # spec.name = "XMTP" - spec.version = "0.6.13-alpha0" + spec.version = "0.6.14-alpha0" spec.summary = "XMTP SDK Cocoapod" # This description is used to generate tags and improve search results.