diff --git a/Package.resolved b/Package.resolved index 1447583c..03d36b46 100644 --- a/Package.resolved +++ b/Package.resolved @@ -41,8 +41,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/xmtp/libxmtp-swift.git", "state" : { - "revision" : "6ddc5a583663560698d66a7f99852ccb093cf4a5", - "version" : "0.5.7-beta2" + "revision" : "c27b586925714a253e5e9b3875788571552f46d6", + "version" : "0.5.8-beta1" } }, { diff --git a/Package.swift b/Package.swift index 7a1c3498..047691bf 100644 --- a/Package.swift +++ b/Package.swift @@ -25,7 +25,7 @@ let package = Package( .package(url: "https://github.com/1024jp/GzipSwift", from: "5.2.0"), .package(url: "https://github.com/bufbuild/connect-swift", exact: "0.12.0"), .package(url: "https://github.com/apple/swift-docc-plugin.git", from: "1.0.0"), - .package(url: "https://github.com/xmtp/libxmtp-swift.git", exact: "0.5.7-beta3"), + .package(url: "https://github.com/xmtp/libxmtp-swift.git", exact: "0.5.8-beta3"), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. diff --git a/Sources/XMTPiOS/Client.swift b/Sources/XMTPiOS/Client.swift index 29131781..c0a9b2d7 100644 --- a/Sources/XMTPiOS/Client.swift +++ b/Sources/XMTPiOS/Client.swift @@ -553,6 +553,7 @@ public final class Client { } public func deleteLocalDatabase() throws { + try dropLocalDatabaseConnection() let fm = FileManager.default try fm.removeItem(atPath: dbPath) } @@ -640,7 +641,7 @@ public final class Client { try await signatureRequest.addEcdsaSignature(signatureBytes: signedData.rawData) } - try await client.registerIdentity(signatureRequest: signatureRequest) + try await client.applySignatureRequest(signatureRequest: signatureRequest) } catch { throw ClientError.addWalletError("Failed to sign the message: \(error.localizedDescription)") } @@ -663,4 +664,26 @@ public final class Client { return false } } + + public func revokeAllOtherInstallations(signingKey: SigningKey) async throws { + guard let client = v3Client else { + throw ClientError.noV3Client("Error: No V3 client initialized") + } + + let signatureRequest = try await client.revokeAllOtherInstallations() + do { + let signedData = try await signingKey.sign(message: signatureRequest.signatureText()) + try await signatureRequest.addEcdsaSignature(signatureBytes: signedData.rawData) + try await client.applySignatureRequest(signatureRequest: signatureRequest) + } catch { + throw ClientError.creationError("Failed to sign the message: \(error.localizedDescription)") + } + } + + public func inboxState(refreshFromNetwork: Bool) async throws -> InboxState { + guard let client = v3Client else { + throw ClientError.noV3Client("Error: No V3 client initialized") + } + return InboxState(ffiInboxState: try await client.inboxState(refreshFromNetwork: refreshFromNetwork)) + } } diff --git a/Sources/XMTPiOS/Conversations.swift b/Sources/XMTPiOS/Conversations.swift index b0c34042..4cb0d1ea 100644 --- a/Sources/XMTPiOS/Conversations.swift +++ b/Sources/XMTPiOS/Conversations.swift @@ -103,6 +103,13 @@ public actor Conversations { } try await v3Client.conversations().sync() } + + public func syncAllGroups() async throws -> UInt32 { + guard let v3Client = client.v3Client else { + return 0 + } + return try await v3Client.conversations().syncAllGroups() + } public func groups(createdAfter: Date? = nil, createdBefore: Date? = nil, limit: Int? = nil) async throws -> [Group] { guard let v3Client = client.v3Client else { diff --git a/Sources/XMTPiOS/Mls/InboxState.swift b/Sources/XMTPiOS/Mls/InboxState.swift new file mode 100644 index 00000000..f604f15c --- /dev/null +++ b/Sources/XMTPiOS/Mls/InboxState.swift @@ -0,0 +1,34 @@ +// +// InboxState.swift +// +// +// Created by Naomi Plasterer on 8/21/24. +// + +import Foundation +import LibXMTP + +public struct InboxState { + var ffiInboxState: FfiInboxState + + init(ffiInboxState: FfiInboxState) { + self.ffiInboxState = ffiInboxState + } + + public var inboxId: String { + ffiInboxState.inboxId + } + + public var addresses: [String] { + ffiInboxState.accountAddresses + } + + public var installationIds: [String] { + ffiInboxState.installationIds.map { $0.toHex } + } + + public var recoveryAddress: String { + ffiInboxState.recoveryAddress + } + +} diff --git a/Tests/XMTPTests/ClientTests.swift b/Tests/XMTPTests/ClientTests.swift index f8350972..94c1168a 100644 --- a/Tests/XMTPTests/ClientTests.swift +++ b/Tests/XMTPTests/ClientTests.swift @@ -530,5 +530,41 @@ class ClientTests: XCTestCase { self.key = key } } + + func testRevokesAllOtherInstallations() async throws { + let key = try Crypto.secureRandomBytes(count: 32) + let alix = try PrivateKey.generate() + let options = ClientOptions.init( + api: .init(env: .local, isSecure: false), + enableV3: true, + encryptionKey: key + ) + + let alixClient = try await Client.create( + account: alix, + options: options + ) + try alixClient.dropLocalDatabaseConnection() + try alixClient.deleteLocalDatabase() + + let alixClient2 = try await Client.create( + account: alix, + options: options + ) + try alixClient2.dropLocalDatabaseConnection() + try alixClient2.deleteLocalDatabase() + let alixClient3 = try await Client.create( + account: alix, + options: options + ) + + let state = try await alixClient3.inboxState(refreshFromNetwork: true) + XCTAssertEqual(state.installationIds.count, 3) + + try await alixClient3.revokeAllOtherInstallations(signingKey: alix) + + let newState = try await alixClient3.inboxState(refreshFromNetwork: true) + XCTAssertEqual(newState.installationIds.count, 1) + } } diff --git a/Tests/XMTPTests/GroupTests.swift b/Tests/XMTPTests/GroupTests.swift index 1eb3bd97..5ea5ec48 100644 --- a/Tests/XMTPTests/GroupTests.swift +++ b/Tests/XMTPTests/GroupTests.swift @@ -838,6 +838,51 @@ class GroupTests: XCTestCase { XCTAssertEqual(preparedMessageId, messages.first!.id) } + func testCanSyncManyGroupsInUnderASecond() async throws { + let fixtures = try await localFixtures() + var groups: [Group] = [] + + for _ in 0..<100 { + var group = try await fixtures.aliceClient.conversations.newGroup(with: [fixtures.bob.address]) + groups.append(group) + } + try await fixtures.bobClient.conversations.sync() + let bobGroup = try fixtures.bobClient.findGroup(groupId: groups[0].id) + try await groups[0].send(content: "hi") + let messageCount = try await bobGroup!.messages().count + XCTAssertEqual(messageCount, 0) + do { + let start = Date() + let numGroupsSynced = try await fixtures.bobClient.conversations.syncAllGroups() + let end = Date() + print(end.timeIntervalSince(start)) + XCTAssert(end.timeIntervalSince(start) < 1) + XCTAssert(numGroupsSynced == 100) + } catch { + print("Failed to list groups members: \(error)") + throw error // Rethrow the error to fail the test if group creation fails + } + + let messageCount2 = try await bobGroup!.messages().count + XCTAssertEqual(messageCount2, 1) + + for aliceConv in try await fixtures.aliceClient.conversations.list(includeGroups: true) { + guard case let .group(aliceGroup) = aliceConv else { + XCTFail("failed converting conversation to group") + return + } + try await aliceGroup.removeMembers(addresses: [fixtures.bobClient.address]) + } + + // first syncAllGroups after removal still sync groups in order to process the removal + var numGroupsSynced = try await fixtures.bobClient.conversations.syncAllGroups() + XCTAssert(numGroupsSynced == 100) + + // next syncAllGroups only will sync active groups + numGroupsSynced = try await fixtures.bobClient.conversations.syncAllGroups() + XCTAssert(numGroupsSynced == 0) + } + func testCanListManyMembersInParallelInUnderASecond() async throws { let fixtures = try await localFixtures() var groups: [Group] = [] diff --git a/XMTP.podspec b/XMTP.podspec index fd724250..a86e32d8 100644 --- a/XMTP.podspec +++ b/XMTP.podspec @@ -16,7 +16,7 @@ Pod::Spec.new do |spec| # spec.name = "XMTP" - spec.version = "0.14.6" + spec.version = "0.14.10" spec.summary = "XMTP SDK Cocoapod" # This description is used to generate tags and improve search results. @@ -44,5 +44,5 @@ Pod::Spec.new do |spec| spec.dependency "web3.swift" spec.dependency "GzipSwift" spec.dependency "Connect-Swift", "= 0.12.0" - spec.dependency 'LibXMTP', '= 0.5.7-beta3' + spec.dependency 'LibXMTP', '= 0.5.8-beta3' end diff --git a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index ff38182f..16d9eac9 100644 --- a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -59,8 +59,16 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/xmtp/libxmtp-swift.git", "state" : { +<<<<<<< HEAD "revision" : "65e9a6eed3db394c1afad7d895b89a0c1cae914b", "version" : "0.5.7-beta0" +||||||| 135991e + "revision" : "0b2d92a8da6caa2e5f16a2ea060b099278354d74", + "version" : "0.5.7-beta3" +======= + "revision" : "06e890646a32c3ae9b9ac78150a7ec4971e54c9d", + "version" : "0.5.8-beta3" +>>>>>>> 3fe600e493b3d2964d91d4a54047d9c56fd5ec46 } }, {