From 2581d5655632ba3dbe59a20a5d8be6e8a1433717 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Thu, 7 Nov 2024 19:26:32 -0800 Subject: [PATCH 01/19] try and remove the bad dependencies --- Package.resolved | 114 ++++-------------- Package.swift | 13 +- Sources/XMTPTestHelpers/TestHelpers.swift | 1 - Sources/XMTPiOS/Client.swift | 1 - .../Codecs/RemoteAttachmentCodec.swift | 15 +-- Sources/XMTPiOS/Crypto.swift | 4 - Sources/XMTPiOS/Extensions/String.swift | 11 +- Sources/XMTPiOS/KeyUtil.swift | 17 +-- Sources/XMTPiOS/Messages/PrivateKey.swift | 1 - Sources/XMTPiOS/Messages/PublicKey.swift | 2 - Sources/XMTPiOS/SigningKey.swift | 8 -- Sources/XMTPiOS/Util.swift | 23 ---- Tests/XMTPTests/DmTests.swift | 1 - Tests/XMTPTests/GroupPermissionsTests.swift | 1 - Tests/XMTPTests/GroupTests.swift | 1 - XMTP.podspec | 26 +--- .../Account/WalletConnection.swift | 7 -- 17 files changed, 36 insertions(+), 210 deletions(-) delete mode 100644 Sources/XMTPiOS/Util.swift diff --git a/Package.resolved b/Package.resolved index 5a21bff4..c4f4f90c 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,14 +1,5 @@ { "pins" : [ - { - "identity" : "bigint", - "kind" : "remoteSourceControl", - "location" : "https://github.com/attaswift/BigInt", - "state" : { - "revision" : "793a7fac0bfc318e85994bf6900652e827aef33e", - "version" : "5.4.1" - } - }, { "identity" : "connect-swift", "kind" : "remoteSourceControl", @@ -19,12 +10,12 @@ } }, { - "identity" : "generic-json-swift", + "identity" : "cryptoswift", "kind" : "remoteSourceControl", - "location" : "https://github.com/iwill/generic-json-swift", + "location" : "https://github.com/krzyzanowskim/CryptoSwift.git", "state" : { - "revision" : "0a06575f4038b504e78ac330913d920f1630f510", - "version" : "2.0.2" + "revision" : "678d442c6f7828def400a70ae15968aef67ef52d", + "version" : "1.8.3" } }, { @@ -41,17 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/xmtp/libxmtp-swift.git", "state" : { - "revision" : "abd4f896f539e5bb090c85022177d775ad08dcb1", - "version" : "0.5.8-beta4" - } - }, - { - "identity" : "secp256k1.swift", - "kind" : "remoteSourceControl", - "location" : "https://github.com/GigaBitcoin/secp256k1.swift.git", - "state" : { - "revision" : "48fb20fce4ca3aad89180448a127d5bc16f0e44c", - "version" : "0.10.0" + "revision" : "91653cdaf999119f99189178867e32dcc53b11e8", + "version" : "0.6.0" } }, { @@ -68,8 +50,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-collections.git", "state" : { - "revision" : "3d2dc41a01f9e49d84f0a3925fb858bed64f702d", - "version" : "1.1.2" + "revision" : "671108c96644956dddcd89dd59c203dcdb36cec7", + "version" : "1.1.4" } }, { @@ -77,53 +59,26 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-docc-plugin.git", "state" : { - "revision" : "26ac5758409154cc448d7ab82389c520fa8a8247", - "version" : "1.3.0" + "revision" : "85e4bb4e1cd62cec64a4b8e769dcefdf0c5b9d64", + "version" : "1.4.3" } }, { "identity" : "swift-docc-symbolkit", "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-docc-symbolkit", + "location" : "https://github.com/swiftlang/swift-docc-symbolkit", "state" : { "revision" : "b45d1f2ed151d057b54504d653e0da5552844e34", "version" : "1.0.0" } }, - { - "identity" : "swift-http-types", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-http-types", - "state" : { - "revision" : "1ddbea1ee34354a6a2532c60f98501c35ae8edfa", - "version" : "1.2.0" - } - }, - { - "identity" : "swift-log", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-log.git", - "state" : { - "revision" : "9cb486020ebf03bfa5b5df985387a14a98744537", - "version" : "1.6.1" - } - }, { "identity" : "swift-nio", "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio.git", "state" : { - "revision" : "fc79798d5a150d61361a27ce0c51169b889e23de", - "version" : "2.68.0" - } - }, - { - "identity" : "swift-nio-extras", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-nio-extras.git", - "state" : { - "revision" : "05c36b57453d23ea63785d58a7dbc7b70ba1745e", - "version" : "1.23.0" + "revision" : "914081701062b11e3bb9e21accc379822621995e", + "version" : "2.76.1" } }, { @@ -131,8 +86,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-http2.git", "state" : { - "revision" : "a0224f3d20438635dd59c9fcc593520d80d131d0", - "version" : "1.33.0" + "revision" : "eaa71bb6ae082eee5a07407b1ad0cbd8f48f9dca", + "version" : "1.34.1" } }, { @@ -140,17 +95,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-ssl.git", "state" : { - "revision" : "2b09805797f21c380f7dc9bedaab3157c5508efb", - "version" : "2.27.0" - } - }, - { - "identity" : "swift-nio-transport-services", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-nio-transport-services.git", - "state" : { - "revision" : "38ac8221dd20674682148d6451367f89c2652980", - "version" : "1.21.0" + "revision" : "c7e95421334b1068490b5d41314a50e70bab23d1", + "version" : "2.29.0" } }, { @@ -158,8 +104,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-protobuf.git", "state" : { - "revision" : "d57a5aecf24a25b32ec4a74be2f5d0a995a47c4b", - "version" : "1.27.0" + "revision" : "ebc7251dd5b37f627c93698e4374084d98409633", + "version" : "1.28.2" } }, { @@ -167,26 +113,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-system.git", "state" : { - "revision" : "6a9e38e7bd22a3b8ba80bddf395623cf68f57807", - "version" : "1.3.1" - } - }, - { - "identity" : "web3.swift", - "kind" : "remoteSourceControl", - "location" : "https://github.com/argentlabs/web3.swift", - "state" : { - "revision" : "1e75f98a5738c470b23bbfffa9314e9f788df76b", - "version" : "1.6.1" - } - }, - { - "identity" : "websocket-kit", - "kind" : "remoteSourceControl", - "location" : "https://github.com/vapor/websocket-kit.git", - "state" : { - "revision" : "4232d34efa49f633ba61afde365d3896fc7f8740", - "version" : "2.15.0" + "revision" : "c8a44d836fe7913603e246acab7c528c2e780168", + "version" : "1.4.0" } } ], diff --git a/Package.swift b/Package.swift index 3e78edad..a7840d2b 100644 --- a/Package.swift +++ b/Package.swift @@ -7,7 +7,6 @@ let package = Package( name: "XMTPiOS", platforms: [.iOS(.v14), .macOS(.v11)], products: [ - // Products define the executables and libraries a package produces, and make them visible to other packages. .library( name: "XMTPiOS", targets: ["XMTPiOS"] @@ -18,26 +17,20 @@ let package = Package( ), ], dependencies: [ - // Dependencies declare other packages that this package depends on. - // .package(url: /* package url */, from: "1.0.0"), - .package(url: "https://github.com/GigaBitcoin/secp256k1.swift.git", exact: "0.10.0"), - .package(url: "https://github.com/argentlabs/web3.swift", from: "1.1.0"), .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: "3.0.0"), + .package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", exact: "1.8.3") ], targets: [ - // Targets are the basic building blocks of a package. A target can define a module or a test suite. - // Targets can depend on other targets in this package, and on products in packages this package depends on. .target( name: "XMTPiOS", dependencies: [ - .product(name: "secp256k1", package: "secp256k1.swift"), - "web3.swift", .product(name: "Gzip", package: "GzipSwift"), .product(name: "Connect", package: "connect-swift"), - .product(name: "LibXMTP", package: "libxmtp-swift") + .product(name: "LibXMTP", package: "libxmtp-swift"), + .product(name: "Crypto", package: "CryptoSwift") ] ), .target( diff --git a/Sources/XMTPTestHelpers/TestHelpers.swift b/Sources/XMTPTestHelpers/TestHelpers.swift index d32a1462..f5feb8f3 100644 --- a/Sources/XMTPTestHelpers/TestHelpers.swift +++ b/Sources/XMTPTestHelpers/TestHelpers.swift @@ -1,6 +1,5 @@ #if canImport(XCTest) import Combine - import CryptoKit import XCTest @testable import XMTPiOS import LibXMTP diff --git a/Sources/XMTPiOS/Client.swift b/Sources/XMTPiOS/Client.swift index 3ac2bab9..56caa5c9 100644 --- a/Sources/XMTPiOS/Client.swift +++ b/Sources/XMTPiOS/Client.swift @@ -1,6 +1,5 @@ import Foundation import LibXMTP -import web3 public typealias PreEventCallback = () async throws -> Void diff --git a/Sources/XMTPiOS/Codecs/RemoteAttachmentCodec.swift b/Sources/XMTPiOS/Codecs/RemoteAttachmentCodec.swift index 19fe5d95..3d58c2e0 100644 --- a/Sources/XMTPiOS/Codecs/RemoteAttachmentCodec.swift +++ b/Sources/XMTPiOS/Codecs/RemoteAttachmentCodec.swift @@ -1,13 +1,6 @@ -// -// RemoteAttachmentCodec.swift -// -// -// Created by Pat Nakajima on 2/19/23. -// - import CryptoKit +import CryptoSwift import Foundation -import web3 public let ContentTypeRemoteAttachment = ContentTypeID(authorityID: "xmtp.org", typeID: "remoteStaticAttachment", versionMajor: 1, versionMinor: 0) @@ -217,11 +210,7 @@ public struct RemoteAttachmentCodec: ContentCodec { throw RemoteAttachmentError.invalidParameters("missing \(name) parameter") } - guard let parameterData = parameterHex.web3.hexData else { - throw RemoteAttachmentError.invalidParameters("invalid \(name) value") - } - - return Data(parameterData) + return Data(parameterHex.hexToData) } public func shouldPush(content: RemoteAttachment) throws -> Bool { diff --git a/Sources/XMTPiOS/Crypto.swift b/Sources/XMTPiOS/Crypto.swift index 04fe4f82..05e0b87f 100644 --- a/Sources/XMTPiOS/Crypto.swift +++ b/Sources/XMTPiOS/Crypto.swift @@ -1,7 +1,3 @@ -// -// Crypto.swift -// - import CryptoKit import Foundation diff --git a/Sources/XMTPiOS/Extensions/String.swift b/Sources/XMTPiOS/Extensions/String.swift index b6fc6d21..bfa1186e 100644 --- a/Sources/XMTPiOS/Extensions/String.swift +++ b/Sources/XMTPiOS/Extensions/String.swift @@ -1,16 +1,9 @@ -// -// String.swift -// -// -// Created by Naomi Plasterer on 7/1/24. -// - import Foundation - +import CryptoSwift extension String { public var hexToData: Data { - return Data(self.web3.bytesFromHex ?? []) + return Data(hex: self) } } diff --git a/Sources/XMTPiOS/KeyUtil.swift b/Sources/XMTPiOS/KeyUtil.swift index bd7048ff..2312ea5f 100644 --- a/Sources/XMTPiOS/KeyUtil.swift +++ b/Sources/XMTPiOS/KeyUtil.swift @@ -1,12 +1,8 @@ -// -// web3.swift -// Copyright © 2022 Argent Labs Limited. All rights reserved. -// import Foundation import Logging import secp256k1 -import web3 import LibXMTP +import CryptoSwift enum KeyUtilError: Error { case invalidContext @@ -18,7 +14,6 @@ enum KeyUtilError: Error { case parseError } -// Copied from web3.swift since its version is `internal` enum KeyUtilx { static func generatePublicKey(from data: Data) throws -> Data { let vec = try LibXMTP.publicKeyFromPrivateKeyK256(privateKeyBytes: data) @@ -42,7 +37,7 @@ enum KeyUtilx { secp256k1_context_destroy(ctx) } - let msgData = hashing ? Util.keccak256(message) : message + let msgData = hashing ? message.sha3(.keccak256) : message let msg = (msgData as NSData).bytes.assumingMemoryBound(to: UInt8.self) let privateKeyPtr = (privateKey as NSData).bytes.assumingMemoryBound(to: UInt8.self) let signaturePtr = UnsafeMutablePointer.allocate(capacity: 1) @@ -64,7 +59,7 @@ enum KeyUtilx { defer { outputWithRecidPtr.deallocate() } - outputWithRecidPtr.assign(from: outputPtr, count: 64) + outputWithRecidPtr.update(from: outputPtr, count: 64) outputWithRecidPtr.advanced(by: 64).pointee = UInt8(recid) let signature = Data(bytes: outputWithRecidPtr, count: 65) @@ -72,12 +67,12 @@ enum KeyUtilx { return signature } - static func generateAddress(from publicKey: Data) -> EthereumAddress { + static func generateAddress(from publicKey: Data) -> String { let publicKeyData = publicKey.count == 64 ? publicKey : publicKey[1 ..< publicKey.count] - let hash = Util.keccak256(publicKeyData) + let hash = publicKeyData.sha3(.keccak256) let address = hash.subdata(in: 12 ..< hash.count) - return EthereumAddress("0x" + address.toHex) + return "0x" + address.toHex } static func recoverPublicKey(message: Data, signature: Data) throws -> Data { diff --git a/Sources/XMTPiOS/Messages/PrivateKey.swift b/Sources/XMTPiOS/Messages/PrivateKey.swift index 53475b0d..396041d2 100644 --- a/Sources/XMTPiOS/Messages/PrivateKey.swift +++ b/Sources/XMTPiOS/Messages/PrivateKey.swift @@ -1,4 +1,3 @@ -import CryptoKit import Foundation import LibXMTP diff --git a/Sources/XMTPiOS/Messages/PublicKey.swift b/Sources/XMTPiOS/Messages/PublicKey.swift index f83ddc7e..4a724c3f 100644 --- a/Sources/XMTPiOS/Messages/PublicKey.swift +++ b/Sources/XMTPiOS/Messages/PublicKey.swift @@ -1,7 +1,5 @@ -import CryptoKit import Foundation import LibXMTP -import web3 typealias PublicKey = Xmtp_MessageContents_PublicKey diff --git a/Sources/XMTPiOS/SigningKey.swift b/Sources/XMTPiOS/SigningKey.swift index ddfc2ec9..dd12b57e 100644 --- a/Sources/XMTPiOS/SigningKey.swift +++ b/Sources/XMTPiOS/SigningKey.swift @@ -1,12 +1,4 @@ -// -// SigningKey.swift -// -// -// Created by Pat Nakajima on 11/17/22. -// - import Foundation -import web3 import LibXMTP public enum WalletType { diff --git a/Sources/XMTPiOS/Util.swift b/Sources/XMTPiOS/Util.swift deleted file mode 100644 index d8d88dba..00000000 --- a/Sources/XMTPiOS/Util.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// Util.swift -// -// -// Created by Pat Nakajima on 11/20/22. -// - -import Foundation -import web3 - -enum Util { - static func keccak256(_ data: Data) -> Data { - return data.web3.keccak256 - } -} - -extension Array { - func chunks(_ chunkSize: Int) -> [[Element]] { - return stride(from: 0, to: self.count, by: chunkSize).map { - Array(self[$0.. Date: Thu, 14 Nov 2024 16:37:48 -0800 Subject: [PATCH 02/19] getting closer on removing the cocoapods --- Sources/XMTPiOS/Messages/PublicKey.swift | 3 +-- Sources/XMTPiOS/Messages/Signature.swift | 3 ++- Sources/XMTPiOS/Util.swift | 23 +++++++++++++++++++ .../XMTPiOSExample.xcodeproj/project.pbxproj | 17 ++++++++++++++ 4 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 Sources/XMTPiOS/Util.swift diff --git a/Sources/XMTPiOS/Messages/PublicKey.swift b/Sources/XMTPiOS/Messages/PublicKey.swift index 4a724c3f..e92f002b 100644 --- a/Sources/XMTPiOS/Messages/PublicKey.swift +++ b/Sources/XMTPiOS/Messages/PublicKey.swift @@ -9,7 +9,6 @@ enum PublicKeyError: String, Error { extension PublicKey { var walletAddress: String { - KeyUtilx.generateAddress(from: secp256K1Uncompressed.bytes) - .toChecksumAddress() + KeyUtilx.generateAddress(from: secp256K1Uncompressed.bytes).lowercased() } } diff --git a/Sources/XMTPiOS/Messages/Signature.swift b/Sources/XMTPiOS/Messages/Signature.swift index dfed671d..4af6dbf9 100644 --- a/Sources/XMTPiOS/Messages/Signature.swift +++ b/Sources/XMTPiOS/Messages/Signature.swift @@ -7,6 +7,7 @@ import Foundation import LibXMTP +import CryptoSwift /// Represents a secp256k1 compact recoverable signature. public typealias Signature = Xmtp_MessageContents_Signature @@ -42,7 +43,7 @@ extension Signature { static func ethHash(_ message: String) throws -> Data { let data = try ethPersonalMessage(message) - return Util.keccak256(data) + return data.sha3(.keccak256) } static func createIdentityText(key: Data) -> String { diff --git a/Sources/XMTPiOS/Util.swift b/Sources/XMTPiOS/Util.swift new file mode 100644 index 00000000..f72e9e18 --- /dev/null +++ b/Sources/XMTPiOS/Util.swift @@ -0,0 +1,23 @@ +// +// Util.swift +// +// +// Created by Pat Nakajima on 11/20/22. +// + +import Foundation +import CryptoSwift + +enum Util { + static func keccak256(_ data: Data) -> Data { + return data.sha3(.keccak256) + } +} + +extension Array { + func chunks(_ chunkSize: Int) -> [[Element]] { + return stride(from: 0, to: self.count, by: chunkSize).map { + Array(self[$0.. Date: Thu, 14 Nov 2024 16:51:06 -0800 Subject: [PATCH 03/19] more clean up --- Package.swift | 2 +- .../XMTPiOSExample.xcodeproj/project.pbxproj | 50 ----- .../xcshareddata/swiftpm/Package.resolved | 121 +---------- .../Account/WalletConnection.swift | 189 ------------------ .../Account/WalletConnectionMethod.swift | 55 ----- .../Views/MessageCellView.swift | 12 -- .../Views/MessageListView.swift | 19 -- 7 files changed, 3 insertions(+), 445 deletions(-) delete mode 100644 XMTPiOSExample/XMTPiOSExample/Account/WalletConnection.swift delete mode 100644 XMTPiOSExample/XMTPiOSExample/Account/WalletConnectionMethod.swift diff --git a/Package.swift b/Package.swift index a7840d2b..02623cec 100644 --- a/Package.swift +++ b/Package.swift @@ -30,7 +30,7 @@ let package = Package( .product(name: "Gzip", package: "GzipSwift"), .product(name: "Connect", package: "connect-swift"), .product(name: "LibXMTP", package: "libxmtp-swift"), - .product(name: "Crypto", package: "CryptoSwift") + .product(name: "CryptoSwift", package: "CryptoSwift") ] ), .target( diff --git a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.pbxproj b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.pbxproj index fb6acc0d..3bd16867 100644 --- a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.pbxproj +++ b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.pbxproj @@ -18,7 +18,6 @@ A6557A312941166E00CC4C7B /* MessageCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6557A302941166E00CC4C7B /* MessageCellView.swift */; }; A6557A3329411F4F00CC4C7B /* NewConversationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6557A3229411F4F00CC4C7B /* NewConversationView.swift */; }; A65F0704297B5D4E00C3C76E /* Persistence.swift in Sources */ = {isa = PBXBuildFile; fileRef = A65F0703297B5D4E00C3C76E /* Persistence.swift */; }; - A65F0707297B5E7600C3C76E /* WalletConnectSwift in Frameworks */ = {isa = PBXBuildFile; productRef = A65F0706297B5E7600C3C76E /* WalletConnectSwift */; }; A65F070A297B5E8600C3C76E /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = A65F0709297B5E8600C3C76E /* KeychainAccess */; }; A6606A1A2B5EE80000E2ED4D /* XMTPiOS in Frameworks */ = {isa = PBXBuildFile; productRef = A6606A192B5EE80000E2ED4D /* XMTPiOS */; }; A67CCEC129355B4B00131F5C /* AccountManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A67CCEC029355B4B00131F5C /* AccountManager.swift */; }; @@ -32,9 +31,6 @@ A69F33CA292DD557005A5556 /* LoggedInView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69F33C9292DD557005A5556 /* LoggedInView.swift */; }; A69F33CC292DD568005A5556 /* QRCodeSheetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69F33CB292DD568005A5556 /* QRCodeSheetView.swift */; }; A6C0F37B2AC1E321008C6AA7 /* Starscream in Frameworks */ = {isa = PBXBuildFile; productRef = A6C0F37A2AC1E321008C6AA7 /* Starscream */; }; - A6C0F37E2AC1E34F008C6AA7 /* WalletConnect in Frameworks */ = {isa = PBXBuildFile; productRef = A6C0F37D2AC1E34F008C6AA7 /* WalletConnect */; }; - A6C0F3802AC1E34F008C6AA7 /* WalletConnectModal in Frameworks */ = {isa = PBXBuildFile; productRef = A6C0F37F2AC1E34F008C6AA7 /* WalletConnectModal */; }; - A6C0F3822AC1E34F008C6AA7 /* Web3Wallet in Frameworks */ = {isa = PBXBuildFile; productRef = A6C0F3812AC1E34F008C6AA7 /* Web3Wallet */; }; A6C0F3842AC1E4B5008C6AA7 /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6C0F3832AC1E4B5008C6AA7 /* LoginView.swift */; }; A6C0F3862AC1E549008C6AA7 /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6C0F3852AC1E549008C6AA7 /* Data.swift */; }; A6D192D0293A7B97006B49F2 /* ConversationListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6D192CF293A7B97006B49F2 /* ConversationListView.swift */; }; @@ -88,13 +84,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - A65F0707297B5E7600C3C76E /* WalletConnectSwift in Frameworks */, - A6C0F3802AC1E34F008C6AA7 /* WalletConnectModal in Frameworks */, E513AEA32CE6AF2700BC31C3 /* CryptoSwift in Frameworks */, A6606A1A2B5EE80000E2ED4D /* XMTPiOS in Frameworks */, 6AEE396E29F330CD0027B657 /* secp256k1 in Frameworks */, - A6C0F37E2AC1E34F008C6AA7 /* WalletConnect in Frameworks */, - A6C0F3822AC1E34F008C6AA7 /* Web3Wallet in Frameworks */, A6C0F37B2AC1E321008C6AA7 /* Starscream in Frameworks */, A65F070A297B5E8600C3C76E /* KeychainAccess in Frameworks */, ); @@ -210,13 +202,9 @@ ); name = XMTPiOSExample; packageProductDependencies = ( - A65F0706297B5E7600C3C76E /* WalletConnectSwift */, A65F0709297B5E8600C3C76E /* KeychainAccess */, 6AEE396D29F330CD0027B657 /* secp256k1 */, A6C0F37A2AC1E321008C6AA7 /* Starscream */, - A6C0F37D2AC1E34F008C6AA7 /* WalletConnect */, - A6C0F37F2AC1E34F008C6AA7 /* WalletConnectModal */, - A6C0F3812AC1E34F008C6AA7 /* Web3Wallet */, A6606A192B5EE80000E2ED4D /* XMTPiOS */, E513AEA22CE6AF2700BC31C3 /* CryptoSwift */, ); @@ -249,11 +237,9 @@ ); mainGroup = A6281986292DC825004B9117; packageReferences = ( - A65F0705297B5E7500C3C76E /* XCRemoteSwiftPackageReference "WalletConnectSwift" */, A65F0708297B5E8600C3C76E /* XCRemoteSwiftPackageReference "KeychainAccess" */, 6AEE396C29F330CD0027B657 /* XCRemoteSwiftPackageReference "secp256k1.swift" */, A6C0F3792AC1E321008C6AA7 /* XCRemoteSwiftPackageReference "Starscream" */, - A6C0F37C2AC1E34F008C6AA7 /* XCRemoteSwiftPackageReference "WalletConnectSwiftV2" */, E513AEA12CE6AF2700BC31C3 /* XCRemoteSwiftPackageReference "CryptoSwift" */, ); productRefGroup = A6281990292DC825004B9117 /* Products */; @@ -553,14 +539,6 @@ version = 0.10.0; }; }; - A65F0705297B5E7500C3C76E /* XCRemoteSwiftPackageReference "WalletConnectSwift" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/WalletConnect/WalletConnectSwift"; - requirement = { - branch = master; - kind = branch; - }; - }; A65F0708297B5E8600C3C76E /* XCRemoteSwiftPackageReference "KeychainAccess" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/kishikawakatsumi/KeychainAccess"; @@ -577,14 +555,6 @@ version = 3.1.2; }; }; - A6C0F37C2AC1E34F008C6AA7 /* XCRemoteSwiftPackageReference "WalletConnectSwiftV2" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/WalletConnect/WalletConnectSwiftV2"; - requirement = { - kind = exactVersion; - version = 1.9.8; - }; - }; E513AEA12CE6AF2700BC31C3 /* XCRemoteSwiftPackageReference "CryptoSwift" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/krzyzanowskim/CryptoSwift.git"; @@ -601,11 +571,6 @@ package = 6AEE396C29F330CD0027B657 /* XCRemoteSwiftPackageReference "secp256k1.swift" */; productName = secp256k1; }; - A65F0706297B5E7600C3C76E /* WalletConnectSwift */ = { - isa = XCSwiftPackageProductDependency; - package = A65F0705297B5E7500C3C76E /* XCRemoteSwiftPackageReference "WalletConnectSwift" */; - productName = WalletConnectSwift; - }; A65F0709297B5E8600C3C76E /* KeychainAccess */ = { isa = XCSwiftPackageProductDependency; package = A65F0708297B5E8600C3C76E /* XCRemoteSwiftPackageReference "KeychainAccess" */; @@ -620,21 +585,6 @@ package = A6C0F3792AC1E321008C6AA7 /* XCRemoteSwiftPackageReference "Starscream" */; productName = Starscream; }; - A6C0F37D2AC1E34F008C6AA7 /* WalletConnect */ = { - isa = XCSwiftPackageProductDependency; - package = A6C0F37C2AC1E34F008C6AA7 /* XCRemoteSwiftPackageReference "WalletConnectSwiftV2" */; - productName = WalletConnect; - }; - A6C0F37F2AC1E34F008C6AA7 /* WalletConnectModal */ = { - isa = XCSwiftPackageProductDependency; - package = A6C0F37C2AC1E34F008C6AA7 /* XCRemoteSwiftPackageReference "WalletConnectSwiftV2" */; - productName = WalletConnectModal; - }; - A6C0F3812AC1E34F008C6AA7 /* Web3Wallet */ = { - isa = XCSwiftPackageProductDependency; - package = A6C0F37C2AC1E34F008C6AA7 /* XCRemoteSwiftPackageReference "WalletConnectSwiftV2" */; - productName = Web3Wallet; - }; E513AEA22CE6AF2700BC31C3 /* CryptoSwift */ = { isa = XCSwiftPackageProductDependency; package = E513AEA12CE6AF2700BC31C3 /* XCRemoteSwiftPackageReference "CryptoSwift" */; diff --git a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index b9e4d141..a156dcf3 100644 --- a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,14 +1,5 @@ { "pins" : [ - { - "identity" : "bigint", - "kind" : "remoteSourceControl", - "location" : "https://github.com/attaswift/BigInt", - "state" : { - "revision" : "0ed110f7555c34ff468e72e1686e59721f2b0da6", - "version" : "5.3.0" - } - }, { "identity" : "connect-swift", "kind" : "remoteSourceControl", @@ -23,17 +14,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/krzyzanowskim/CryptoSwift.git", "state" : { - "revision" : "039f56c5d7960f277087a0be51f5eb04ed0ec073", - "version" : "1.5.1" - } - }, - { - "identity" : "generic-json-swift", - "kind" : "remoteSourceControl", - "location" : "https://github.com/iwill/generic-json-swift", - "state" : { - "revision" : "0a06575f4038b504e78ac330913d920f1630f510", - "version" : "2.0.2" + "revision" : "678d442c6f7828def400a70ae15968aef67ef52d", + "version" : "1.8.3" } }, { @@ -63,15 +45,6 @@ "version" : "3.0.0" } }, - { - "identity" : "qrcode", - "kind" : "remoteSourceControl", - "location" : "https://github.com/WalletConnect/QRCode", - "state" : { - "revision" : "263f280d2c8144adfb0b6676109846cfc8dd552b", - "version" : "14.3.1" - } - }, { "identity" : "secp256k1.swift", "kind" : "remoteSourceControl", @@ -126,24 +99,6 @@ "version" : "1.0.0" } }, - { - "identity" : "swift-http-types", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-http-types", - "state" : { - "revision" : "99d066e29effa8845e4761dd3f2f831edfdf8925", - "version" : "1.0.0" - } - }, - { - "identity" : "swift-log", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-log.git", - "state" : { - "revision" : "532d8b529501fb73a2455b179e0bbb6d49b652ed", - "version" : "1.5.3" - } - }, { "identity" : "swift-nio", "kind" : "remoteSourceControl", @@ -153,15 +108,6 @@ "version" : "2.64.0" } }, - { - "identity" : "swift-nio-extras", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-nio-extras.git", - "state" : { - "revision" : "798c962495593a23fdea0c0c63fd55571d8dff51", - "version" : "1.20.0" - } - }, { "identity" : "swift-nio-http2", "kind" : "remoteSourceControl", @@ -180,15 +126,6 @@ "version" : "2.26.0" } }, - { - "identity" : "swift-nio-transport-services", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-nio-transport-services.git", - "state" : { - "revision" : "ebf8b9c365a6ce043bf6e6326a04b15589bd285e", - "version" : "1.20.0" - } - }, { "identity" : "swift-protobuf", "kind" : "remoteSourceControl", @@ -198,15 +135,6 @@ "version" : "1.25.2" } }, - { - "identity" : "swift-qrcode-generator", - "kind" : "remoteSourceControl", - "location" : "https://github.com/dagronf/swift-qrcode-generator", - "state" : { - "revision" : "5ca09b6a2ad190f94aa3d6ddef45b187f8c0343b", - "version" : "1.0.3" - } - }, { "identity" : "swift-system", "kind" : "remoteSourceControl", @@ -215,51 +143,6 @@ "revision" : "025bcb1165deab2e20d4eaba79967ce73013f496", "version" : "1.2.1" } - }, - { - "identity" : "swiftimagereadwrite", - "kind" : "remoteSourceControl", - "location" : "https://github.com/dagronf/SwiftImageReadWrite", - "state" : { - "revision" : "5596407d1cf61b953b8e658fa8636a471df3c509", - "version" : "1.1.6" - } - }, - { - "identity" : "walletconnectswift", - "kind" : "remoteSourceControl", - "location" : "https://github.com/WalletConnect/WalletConnectSwift", - "state" : { - "branch" : "master", - "revision" : "9e4dfba34fb35336fd5da551285d7986ff536cb8" - } - }, - { - "identity" : "walletconnectswiftv2", - "kind" : "remoteSourceControl", - "location" : "https://github.com/WalletConnect/WalletConnectSwiftV2", - "state" : { - "revision" : "addf9a3688ef5e5d9d148ecbb30ca0fd3132b908", - "version" : "1.9.8" - } - }, - { - "identity" : "web3.swift", - "kind" : "remoteSourceControl", - "location" : "https://github.com/argentlabs/web3.swift", - "state" : { - "revision" : "8ca33e700ed8de6137a0e1471017aa3b3c8de0db", - "version" : "1.6.0" - } - }, - { - "identity" : "websocket-kit", - "kind" : "remoteSourceControl", - "location" : "https://github.com/vapor/websocket-kit.git", - "state" : { - "revision" : "53fe0639a98903858d0196b699720decb42aee7b", - "version" : "2.14.0" - } } ], "version" : 2 diff --git a/XMTPiOSExample/XMTPiOSExample/Account/WalletConnection.swift b/XMTPiOSExample/XMTPiOSExample/Account/WalletConnection.swift deleted file mode 100644 index 91c1376b..00000000 --- a/XMTPiOSExample/XMTPiOSExample/Account/WalletConnection.swift +++ /dev/null @@ -1,189 +0,0 @@ -import Foundation -import UIKit -import WalletConnectSwift -import web3 -import XMTPiOS - -extension WCURL { - var asURL: URL { - // swiftlint:disable force_unwrapping - URL(string: "wc://wc?uri=\(absoluteString)")! - // swiftlint:enable force_unwrapping - } -} - -enum WalletConnectionError: String, Error { - case walletConnectURL - case noSession - case noAddress - case invalidMessage - case noSignature -} - -protocol WalletConnection { - var isConnected: Bool { get } - var walletAddress: String? { get } - func preferredConnectionMethod() throws -> WalletConnectionMethodType - func connect() async throws - func sign(_ data: Data) async throws -> Data -} - -class WCWalletConnection: WalletConnection, WalletConnectSwift.ClientDelegate { - @Published public var isConnected = false - - var walletConnectClient: WalletConnectSwift.Client! - var session: WalletConnectSwift.Session? { - didSet { - DispatchQueue.main.async { - self.isConnected = self.session != nil - } - } - } - - init() { - let peerMeta = Session.ClientMeta( - name: "xmtp-ios", - description: "XMTP", - icons: [], - // swiftlint:disable force_unwrapping - url: URL(string: "https://safe.gnosis.io")! - // swiftlint:enable force_unwrapping - ) - let dAppInfo = WalletConnectSwift.Session.DAppInfo(peerId: UUID().uuidString, peerMeta: peerMeta) - - walletConnectClient = WalletConnectSwift.Client(delegate: self, dAppInfo: dAppInfo) - } - - @MainActor func preferredConnectionMethod() throws -> WalletConnectionMethodType { - guard let url = walletConnectURL?.asURL else { - throw WalletConnectionError.walletConnectURL - } - - if UIApplication.shared.canOpenURL(url) { - return WalletRedirectConnectionMethod(redirectURI: url.absoluteString).type - } - - return WalletQRCodeConnectionMethod(redirectURI: url.absoluteString).type - } - - lazy var walletConnectURL: WCURL? = { - do { - let keybytes = try secureRandomBytes(count: 32) - - return WCURL( - topic: UUID().uuidString, - // swiftlint:disable force_unwrapping - bridgeURL: URL(string: "https://bridge.walletconnect.org")!, - // swiftlint:enable force_unwrapping - key: keybytes.reduce("") { $0 + String(format: "%02x", $1) } - ) - } catch { - return nil - } - }() - - func secureRandomBytes(count: Int) throws -> Data { - var bytes = [UInt8](repeating: 0, count: count) - - // Fill bytes with secure random data - let status = SecRandomCopyBytes( - kSecRandomDefault, - count, - &bytes - ) - - // A status of errSecSuccess indicates success - if status == errSecSuccess { - return Data(bytes) - } else { - fatalError("could not generate random bytes") - } - } - - func connect() async throws { - guard let url = walletConnectURL else { - throw WalletConnectionError.walletConnectURL - } - - try walletConnectClient.connect(to: url) - } - - func sign(_ data: Data) async throws -> Data { - guard session != nil else { - throw WalletConnectionError.noSession - } - - guard let walletAddress = walletAddress else { - throw WalletConnectionError.noAddress - } - - guard let url = walletConnectURL else { - throw WalletConnectionError.walletConnectURL - } - - guard let message = String(data: data, encoding: .utf8) else { - throw WalletConnectionError.invalidMessage - } - - return try await withCheckedThrowingContinuation { continuation in - do { - try walletConnectClient.personal_sign(url: url, message: message, account: walletAddress) { response in - if let error = response.error { - continuation.resume(throwing: error) - return - } - - do { - var resultString = try response.result(as: String.self) - - // Strip leading 0x that we get back from `personal_sign` - if resultString.hasPrefix("0x"), resultString.count == 132 { - resultString = String(resultString.dropFirst(2)) - } - - guard let resultDataBytes = resultString.web3.bytesFromHex else { - continuation.resume(throwing: WalletConnectionError.noSignature) - return - } - - var resultData = Data(resultDataBytes) - - // Ensure we have a valid recovery byte - resultData[resultData.count - 1] = 1 - resultData[resultData.count - 1] % 2 - - continuation.resume(returning: resultData) - } catch { - continuation.resume(throwing: error) - } - } - } catch { - continuation.resume(throwing: error) - } - } - } - - var walletAddress: String? { - if let address = session?.walletInfo?.accounts.first { - return EthereumAddress(address).toChecksumAddress() - } - - return nil - } - - func client(_: WalletConnectSwift.Client, didConnect _: WalletConnectSwift.WCURL) {} - - func client(_: WalletConnectSwift.Client, didFailToConnect _: WalletConnectSwift.WCURL) {} - - func client(_: WalletConnectSwift.Client, didConnect session: WalletConnectSwift.Session) { - // Future Implementation Cache session - self.session = session - } - - func client(_: WalletConnectSwift.Client, didUpdate session: WalletConnectSwift.Session) { - self.session = session - } - - func client(_: WalletConnectSwift.Client, didDisconnect _: WalletConnectSwift.Session) { - session = nil - } -} diff --git a/XMTPiOSExample/XMTPiOSExample/Account/WalletConnectionMethod.swift b/XMTPiOSExample/XMTPiOSExample/Account/WalletConnectionMethod.swift deleted file mode 100644 index 35c718ac..00000000 --- a/XMTPiOSExample/XMTPiOSExample/Account/WalletConnectionMethod.swift +++ /dev/null @@ -1,55 +0,0 @@ -// -// WalletConnectionMethod.swift -// -// -// Created by Pat Nakajima on 11/22/22. -// - -import CoreImage.CIFilterBuiltins -import UIKit -import WalletConnectSwift - -protocol WalletConnectionMethod { - var type: WalletConnectionMethodType { get } -} - -/// Describes WalletConnect flows. -public enum WalletConnectionMethodType { - case redirect(URL), qrCode(UIImage), manual(String) -} - -struct WalletRedirectConnectionMethod: WalletConnectionMethod { - var redirectURI: String - var type: WalletConnectionMethodType { - // swiftlint:disable force_unwrapping - .redirect(URL(string: redirectURI)!) - // swiftlint:enable force_unwrapping - } -} - -struct WalletQRCodeConnectionMethod: WalletConnectionMethod { - var redirectURI: String - var type: WalletConnectionMethodType { - let data = Data(redirectURI.utf8) - let context = CIContext() - let filter = CIFilter.qrCodeGenerator() - filter.setValue(data, forKey: "inputMessage") - - // swiftlint:disable force_unwrapping - let outputImage = filter.outputImage! - let scaledImage = outputImage.transformed(by: CGAffineTransform(scaleX: 3, y: 3)) - let cgImage = context.createCGImage(scaledImage, from: scaledImage.extent)! - // swiftlint:enable force_unwrapping - - let image = UIImage(cgImage: cgImage) - - return .qrCode(image) - } -} - -struct WalletManualConnectionMethod: WalletConnectionMethod { - var redirectURI: String - var type: WalletConnectionMethodType { - .manual(redirectURI) - } -} diff --git a/XMTPiOSExample/XMTPiOSExample/Views/MessageCellView.swift b/XMTPiOSExample/XMTPiOSExample/Views/MessageCellView.swift index 71105cc6..f7483ab9 100644 --- a/XMTPiOSExample/XMTPiOSExample/Views/MessageCellView.swift +++ b/XMTPiOSExample/XMTPiOSExample/Views/MessageCellView.swift @@ -7,7 +7,6 @@ import SwiftUI import XMTPiOS -import web3 struct MessageTextView: View { var myAddress: String @@ -126,14 +125,3 @@ struct MessageCellView: View { } } } - -struct MessageCellView_Previews: PreviewProvider { - static var previews: some View { - PreviewClientProvider { client in - List { - MessageCellView(myAddress: "0x00", message: DecodedMessage.preview(client: client, topic: "foo", body: "Hi, how is it going?", senderAddress: "0x00", sent: Date())) - } - .listStyle(.plain) - } - } -} diff --git a/XMTPiOSExample/XMTPiOSExample/Views/MessageListView.swift b/XMTPiOSExample/XMTPiOSExample/Views/MessageListView.swift index 087035ec..258b6c1d 100644 --- a/XMTPiOSExample/XMTPiOSExample/Views/MessageListView.swift +++ b/XMTPiOSExample/XMTPiOSExample/Views/MessageListView.swift @@ -39,22 +39,3 @@ struct MessageListView: View { } } } - -struct MessageListView_Previews: PreviewProvider { - static var previews: some View { - PreviewClientProvider { client in - // swiftlint: disable comma - MessageListView( - myAddress: "0x00", messages: [ - DecodedMessage.preview(client: client, topic: "foo", body: "Hello", senderAddress: "0x00", sent: Date().addingTimeInterval(-10)), - DecodedMessage.preview(client: client, topic: "foo",body: "Oh hi", senderAddress: "0x01", sent: Date().addingTimeInterval(-9)), - DecodedMessage.preview(client: client, topic: "foo",body: "Sup", senderAddress: "0x01", sent: Date().addingTimeInterval(-8)), - DecodedMessage.preview(client: client, topic: "foo",body: "Nice to see you", senderAddress: "0x00", sent: Date().addingTimeInterval(-7)), - DecodedMessage.preview(client: client, topic: "foo",body: "What if it's a longer message I mean really really long like should it wrap?", senderAddress: "0x01", sent: Date().addingTimeInterval(-6)), - DecodedMessage.preview(client: client, topic: "foo",body: "🧐", senderAddress: "0x00", sent: Date().addingTimeInterval(-5)), - ] - ) - // swiftlint: enable comma - } - } -} From 6eb2cc9dde49d87f98fb1e48aa055227b560d5d1 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Mon, 18 Nov 2024 09:19:18 -0800 Subject: [PATCH 04/19] update dependenecies --- Package.swift | 8 +++-- Sources/XMTPiOS/KeyUtil.swift | 1 - XMTP.podspec | 4 ++- .../XMTPiOSExample.xcodeproj/project.pbxproj | 34 +++++++++---------- 4 files changed, 25 insertions(+), 22 deletions(-) diff --git a/Package.swift b/Package.swift index f4199f1b..b46d5a38 100644 --- a/Package.swift +++ b/Package.swift @@ -17,9 +17,10 @@ let package = Package( ), ], dependencies: [ - .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/21-DOT-DEV/secp256k1.swift.git", exact: "0.18.0"), + .package(url: "https://github.com/1024jp/GzipSwift", from: "6.1.0"), + .package(url: "https://github.com/bufbuild/connect-swift", exact: "1.0.0"), + .package(url: "https://github.com/apple/swift-docc-plugin.git", from: "1.4.3"), .package(url: "https://github.com/xmtp/libxmtp-swift.git", exact: "3.0.1"), .package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", exact: "1.8.3") ], @@ -27,6 +28,7 @@ let package = Package( .target( name: "XMTPiOS", dependencies: [ + .product(name: "secp256k1", package: "secp256k1.swift"), .product(name: "Gzip", package: "GzipSwift"), .product(name: "Connect", package: "connect-swift"), .product(name: "LibXMTP", package: "libxmtp-swift"), diff --git a/Sources/XMTPiOS/KeyUtil.swift b/Sources/XMTPiOS/KeyUtil.swift index 2312ea5f..8c044e0e 100644 --- a/Sources/XMTPiOS/KeyUtil.swift +++ b/Sources/XMTPiOS/KeyUtil.swift @@ -1,5 +1,4 @@ import Foundation -import Logging import secp256k1 import LibXMTP import CryptoSwift diff --git a/XMTP.podspec b/XMTP.podspec index fc32d564..33dc54a4 100644 --- a/XMTP.podspec +++ b/XMTP.podspec @@ -20,6 +20,8 @@ Pod::Spec.new do |spec| spec.source_files = "Sources/**/*.swift" spec.frameworks = "CryptoKit", "UIKit" - spec.dependency "Connect-Swift", "= 0.12.0" + spec.dependency "GzipSwift" + spec.dependency "Connect-Swift", "= 1.0.0" spec.dependency 'LibXMTP', '= 3.0.1' spec.dependency 'CryptoSwift', '= 1.8.3' +end diff --git a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.pbxproj b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.pbxproj index 3bd16867..6d6295b7 100644 --- a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.pbxproj +++ b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.pbxproj @@ -7,7 +7,7 @@ objects = { /* Begin PBXBuildFile section */ - 6AEE396E29F330CD0027B657 /* secp256k1 in Frameworks */ = {isa = PBXBuildFile; productRef = 6AEE396D29F330CD0027B657 /* secp256k1 */; }; + E5BCC0952CEBA58F00E11814 /* secp256k1 in Frameworks */ = {isa = PBXBuildFile; productRef = E5BCC0952CEBA58F00E11814 /* secp256k1 */; }; A60FC8BF293AD054001697E3 /* MessageComposerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A60FC8BE293AD054001697E3 /* MessageComposerView.swift */; }; A60FC8C1293AD171001697E3 /* ConversationDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A60FC8C0293AD171001697E3 /* ConversationDetailView.swift */; }; A60FC8C3293AD18A001697E3 /* PreviewClientProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A60FC8C2293AD18A001697E3 /* PreviewClientProvider.swift */; }; @@ -86,7 +86,7 @@ files = ( E513AEA32CE6AF2700BC31C3 /* CryptoSwift in Frameworks */, A6606A1A2B5EE80000E2ED4D /* XMTPiOS in Frameworks */, - 6AEE396E29F330CD0027B657 /* secp256k1 in Frameworks */, + E5BCC0952CEBA58F00E11814 /* secp256k1 in Frameworks */, A6C0F37B2AC1E321008C6AA7 /* Starscream in Frameworks */, A65F070A297B5E8600C3C76E /* KeychainAccess in Frameworks */, ); @@ -203,7 +203,7 @@ name = XMTPiOSExample; packageProductDependencies = ( A65F0709297B5E8600C3C76E /* KeychainAccess */, - 6AEE396D29F330CD0027B657 /* secp256k1 */, + E5BCC0952CEBA58F00E11814 /* secp256k1 */, A6C0F37A2AC1E321008C6AA7 /* Starscream */, A6606A192B5EE80000E2ED4D /* XMTPiOS */, E513AEA22CE6AF2700BC31C3 /* CryptoSwift */, @@ -238,9 +238,9 @@ mainGroup = A6281986292DC825004B9117; packageReferences = ( A65F0708297B5E8600C3C76E /* XCRemoteSwiftPackageReference "KeychainAccess" */, - 6AEE396C29F330CD0027B657 /* XCRemoteSwiftPackageReference "secp256k1.swift" */, A6C0F3792AC1E321008C6AA7 /* XCRemoteSwiftPackageReference "Starscream" */, E513AEA12CE6AF2700BC31C3 /* XCRemoteSwiftPackageReference "CryptoSwift" */, + E5BCC0952CEBA58F00E11814 /* XCRemoteSwiftPackageReference "swift-secp256k1" */, ); productRefGroup = A6281990292DC825004B9117 /* Products */; projectDirPath = ""; @@ -531,14 +531,6 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ - 6AEE396C29F330CD0027B657 /* XCRemoteSwiftPackageReference "secp256k1.swift" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/GigaBitcoin/secp256k1.swift.git"; - requirement = { - kind = exactVersion; - version = 0.10.0; - }; - }; A65F0708297B5E8600C3C76E /* XCRemoteSwiftPackageReference "KeychainAccess" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/kishikawakatsumi/KeychainAccess"; @@ -563,14 +555,22 @@ minimumVersion = 1.8.3; }; }; + E5BCC0952CEBA58F00E11814 /* XCRemoteSwiftPackageReference "swift-secp256k1" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/21-DOT-DEV/swift-secp256k1.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 0.18.0; + }; + }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ - 6AEE396D29F330CD0027B657 /* secp256k1 */ = { - isa = XCSwiftPackageProductDependency; - package = 6AEE396C29F330CD0027B657 /* XCRemoteSwiftPackageReference "secp256k1.swift" */; - productName = secp256k1; - }; +- E5BCC0952CEBA58F00E11814 /* secp256k1 */ = { +- isa = XCSwiftPackageProductDependency; +- package = E5BCC0952CEBA58F00E11814 /* XCRemoteSwiftPackageReference "secp256k1.swift" */; +- productName = secp256k1; +- }; A65F0709297B5E8600C3C76E /* KeychainAccess */ = { isa = XCSwiftPackageProductDependency; package = A65F0708297B5E8600C3C76E /* XCRemoteSwiftPackageReference "KeychainAccess" */; From e88d7cad1f66478deb18e742faa1a70bbeb3ee1c Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Mon, 18 Nov 2024 09:48:40 -0800 Subject: [PATCH 05/19] update package resolved --- Package.resolved | 21 +++++++++++++------ Package.swift | 4 ++-- .../XMTPiOSExample.xcodeproj/project.pbxproj | 8 ------- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/Package.resolved b/Package.resolved index c4f4f90c..0d011f98 100644 --- a/Package.resolved +++ b/Package.resolved @@ -5,8 +5,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/bufbuild/connect-swift", "state" : { - "revision" : "1701d3d1b2c4c63fcccfd7094f86a88672fa5acb", - "version" : "0.12.0" + "revision" : "a8c984a1077f78e94e0884c5c11683a7f684f92c", + "version" : "1.0.0" } }, { @@ -23,8 +23,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/1024jp/GzipSwift", "state" : { - "revision" : "7a7f17761c76a932662ab77028a4329f67d645a4", - "version" : "5.2.0" + "revision" : "56bf51fdd2fe4b2cf254b2cf34aede3d7caccc6c", + "version" : "6.1.0" } }, { @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/xmtp/libxmtp-swift.git", "state" : { - "revision" : "91653cdaf999119f99189178867e32dcc53b11e8", - "version" : "0.6.0" + "revision" : "f495d4feaab40a0a6a48c1d5a99585de8107f5d2", + "version" : "3.0.1" } }, { @@ -108,6 +108,15 @@ "version" : "1.28.2" } }, + { + "identity" : "swift-secp256k1", + "kind" : "remoteSourceControl", + "location" : "https://github.com/21-DOT-DEV/swift-secp256k1", + "state" : { + "revision" : "57ce9af6db14e0114af631ace25231a9d0ccccbd", + "version" : "0.18.0" + } + }, { "identity" : "swift-system", "kind" : "remoteSourceControl", diff --git a/Package.swift b/Package.swift index b46d5a38..a0681a0f 100644 --- a/Package.swift +++ b/Package.swift @@ -17,7 +17,7 @@ let package = Package( ), ], dependencies: [ - .package(url: "https://github.com/21-DOT-DEV/secp256k1.swift.git", exact: "0.18.0"), + .package(url: "https://github.com/21-DOT-DEV/swift-secp256k1", exact: "0.18.0"), .package(url: "https://github.com/1024jp/GzipSwift", from: "6.1.0"), .package(url: "https://github.com/bufbuild/connect-swift", exact: "1.0.0"), .package(url: "https://github.com/apple/swift-docc-plugin.git", from: "1.4.3"), @@ -28,7 +28,7 @@ let package = Package( .target( name: "XMTPiOS", dependencies: [ - .product(name: "secp256k1", package: "secp256k1.swift"), + .product(name: "secp256k1", package: "swift-secp256k1"), .product(name: "Gzip", package: "GzipSwift"), .product(name: "Connect", package: "connect-swift"), .product(name: "LibXMTP", package: "libxmtp-swift"), diff --git a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.pbxproj b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.pbxproj index 6d6295b7..67a5a39e 100644 --- a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.pbxproj +++ b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.pbxproj @@ -7,7 +7,6 @@ objects = { /* Begin PBXBuildFile section */ - E5BCC0952CEBA58F00E11814 /* secp256k1 in Frameworks */ = {isa = PBXBuildFile; productRef = E5BCC0952CEBA58F00E11814 /* secp256k1 */; }; A60FC8BF293AD054001697E3 /* MessageComposerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A60FC8BE293AD054001697E3 /* MessageComposerView.swift */; }; A60FC8C1293AD171001697E3 /* ConversationDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A60FC8C0293AD171001697E3 /* ConversationDetailView.swift */; }; A60FC8C3293AD18A001697E3 /* PreviewClientProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A60FC8C2293AD18A001697E3 /* PreviewClientProvider.swift */; }; @@ -86,7 +85,6 @@ files = ( E513AEA32CE6AF2700BC31C3 /* CryptoSwift in Frameworks */, A6606A1A2B5EE80000E2ED4D /* XMTPiOS in Frameworks */, - E5BCC0952CEBA58F00E11814 /* secp256k1 in Frameworks */, A6C0F37B2AC1E321008C6AA7 /* Starscream in Frameworks */, A65F070A297B5E8600C3C76E /* KeychainAccess in Frameworks */, ); @@ -203,7 +201,6 @@ name = XMTPiOSExample; packageProductDependencies = ( A65F0709297B5E8600C3C76E /* KeychainAccess */, - E5BCC0952CEBA58F00E11814 /* secp256k1 */, A6C0F37A2AC1E321008C6AA7 /* Starscream */, A6606A192B5EE80000E2ED4D /* XMTPiOS */, E513AEA22CE6AF2700BC31C3 /* CryptoSwift */, @@ -566,11 +563,6 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ -- E5BCC0952CEBA58F00E11814 /* secp256k1 */ = { -- isa = XCSwiftPackageProductDependency; -- package = E5BCC0952CEBA58F00E11814 /* XCRemoteSwiftPackageReference "secp256k1.swift" */; -- productName = secp256k1; -- }; A65F0709297B5E8600C3C76E /* KeychainAccess */ = { isa = XCSwiftPackageProductDependency; package = A65F0708297B5E8600C3C76E /* XCRemoteSwiftPackageReference "KeychainAccess" */; From 8768fbc2a64175b7eb8f168a2a2847b08953d457 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Mon, 18 Nov 2024 09:54:59 -0800 Subject: [PATCH 06/19] remove all the old cocopods --- .github/workflows/deploy_to_cocoapods.yml | 2 +- .github/workflows/docs.yml | 2 +- .github/workflows/lint.yml | 2 +- .../xcshareddata/swiftpm/Package.resolved | 52 +++++++++---------- 4 files changed, 29 insertions(+), 29 deletions(-) diff --git a/.github/workflows/deploy_to_cocoapods.yml b/.github/workflows/deploy_to_cocoapods.yml index e7b958bf..c15103c4 100644 --- a/.github/workflows/deploy_to_cocoapods.yml +++ b/.github/workflows/deploy_to_cocoapods.yml @@ -7,7 +7,7 @@ on: jobs: build: - runs-on: macos-12 + runs-on: macos-13 steps: - uses: actions/checkout@v1 diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index e05cbaa1..75fd495b 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -32,7 +32,7 @@ jobs: environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} - runs-on: macos-12 + runs-on: macos-13 steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 0ffd8a37..c5ce5c81 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -8,7 +8,7 @@ on: jobs: build: name: Run swiftlint - runs-on: macos-12 + runs-on: macos-13 steps: - uses: maxim-lobanov/setup-xcode@v1 with: diff --git a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 74bc391c..aaf82bde 100644 --- a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -5,8 +5,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/bufbuild/connect-swift", "state" : { - "revision" : "1701d3d1b2c4c63fcccfd7094f86a88672fa5acb", - "version" : "0.12.0" + "revision" : "a8c984a1077f78e94e0884c5c11683a7f684f92c", + "version" : "1.0.0" } }, { @@ -23,8 +23,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/1024jp/GzipSwift", "state" : { - "revision" : "7a7f17761c76a932662ab77028a4329f67d645a4", - "version" : "5.2.0" + "revision" : "56bf51fdd2fe4b2cf254b2cf34aede3d7caccc6c", + "version" : "6.1.0" } }, { @@ -45,15 +45,6 @@ "version" : "3.0.1" } }, - { - "identity" : "secp256k1.swift", - "kind" : "remoteSourceControl", - "location" : "https://github.com/GigaBitcoin/secp256k1.swift.git", - "state" : { - "revision" : "48fb20fce4ca3aad89180448a127d5bc16f0e44c", - "version" : "0.10.0" - } - }, { "identity" : "starscream", "kind" : "remoteSourceControl", @@ -86,14 +77,14 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-docc-plugin.git", "state" : { - "revision" : "26ac5758409154cc448d7ab82389c520fa8a8247", - "version" : "1.3.0" + "revision" : "85e4bb4e1cd62cec64a4b8e769dcefdf0c5b9d64", + "version" : "1.4.3" } }, { "identity" : "swift-docc-symbolkit", "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-docc-symbolkit", + "location" : "https://github.com/swiftlang/swift-docc-symbolkit", "state" : { "revision" : "b45d1f2ed151d057b54504d653e0da5552844e34", "version" : "1.0.0" @@ -104,8 +95,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio.git", "state" : { - "revision" : "fc63f0cf4e55a4597407a9fc95b16a2bc44b4982", - "version" : "2.64.0" + "revision" : "914081701062b11e3bb9e21accc379822621995e", + "version" : "2.76.1" } }, { @@ -113,8 +104,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-http2.git", "state" : { - "revision" : "0904bf0feb5122b7e5c3f15db7df0eabe623dd87", - "version" : "1.30.0" + "revision" : "eaa71bb6ae082eee5a07407b1ad0cbd8f48f9dca", + "version" : "1.34.1" } }, { @@ -122,8 +113,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-nio-ssl.git", "state" : { - "revision" : "7c381eb6083542b124a6c18fae742f55001dc2b5", - "version" : "2.26.0" + "revision" : "c7e95421334b1068490b5d41314a50e70bab23d1", + "version" : "2.29.0" } }, { @@ -131,8 +122,17 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-protobuf.git", "state" : { - "revision" : "65e8f29b2d63c4e38e736b25c27b83e012159be8", - "version" : "1.25.2" + "revision" : "ebc7251dd5b37f627c93698e4374084d98409633", + "version" : "1.28.2" + } + }, + { + "identity" : "swift-secp256k1", + "kind" : "remoteSourceControl", + "location" : "https://github.com/21-DOT-DEV/swift-secp256k1.git", + "state" : { + "revision" : "57ce9af6db14e0114af631ace25231a9d0ccccbd", + "version" : "0.18.0" } }, { @@ -140,8 +140,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-system.git", "state" : { - "revision" : "025bcb1165deab2e20d4eaba79967ce73013f496", - "version" : "1.2.1" + "revision" : "c8a44d836fe7913603e246acab7c528c2e780168", + "version" : "1.4.0" } } ], From 18efc0b5c4aef69925c3e88a86960b499d041ef1 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Mon, 18 Nov 2024 10:19:22 -0800 Subject: [PATCH 07/19] try bumping the xcode version down --- .github/workflows/lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index c5ce5c81..77f34eb1 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -12,7 +12,7 @@ jobs: steps: - uses: maxim-lobanov/setup-xcode@v1 with: - xcode-version: latest-stable + xcode-version: '14' - uses: actions/checkout@v3 - run: swiftlint Sources/ XMTPiOSExample/XMTPiOSExample - run: pod lib lint --allow-warnings From 9f731ca5923f9ac8870e83c3cbd8c0d2af13b767 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Mon, 18 Nov 2024 11:17:22 -0800 Subject: [PATCH 08/19] remove the old gzip library --- Package.swift | 2 - Sources/XMTPiOS/Codecs/ContentCodec.swift | 19 ++++- .../XMTPiOS/EncodedContentCompression.swift | 85 ++++++++++--------- XMTP.podspec | 3 +- .../XMTPiOSExample.xcodeproj/project.pbxproj | 17 ++++ .../xcshareddata/swiftpm/Package.resolved | 8 +- 6 files changed, 82 insertions(+), 52 deletions(-) diff --git a/Package.swift b/Package.swift index a0681a0f..1ed8960e 100644 --- a/Package.swift +++ b/Package.swift @@ -18,7 +18,6 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/21-DOT-DEV/swift-secp256k1", exact: "0.18.0"), - .package(url: "https://github.com/1024jp/GzipSwift", from: "6.1.0"), .package(url: "https://github.com/bufbuild/connect-swift", exact: "1.0.0"), .package(url: "https://github.com/apple/swift-docc-plugin.git", from: "1.4.3"), .package(url: "https://github.com/xmtp/libxmtp-swift.git", exact: "3.0.1"), @@ -29,7 +28,6 @@ let package = Package( name: "XMTPiOS", dependencies: [ .product(name: "secp256k1", package: "swift-secp256k1"), - .product(name: "Gzip", package: "GzipSwift"), .product(name: "Connect", package: "connect-swift"), .product(name: "LibXMTP", package: "libxmtp-swift"), .product(name: "CryptoSwift", package: "CryptoSwift") diff --git a/Sources/XMTPiOS/Codecs/ContentCodec.swift b/Sources/XMTPiOS/Codecs/ContentCodec.swift index e715a191..c4d94556 100644 --- a/Sources/XMTPiOS/Codecs/ContentCodec.swift +++ b/Sources/XMTPiOS/Codecs/ContentCodec.swift @@ -40,7 +40,11 @@ extension EncodedContent { copy.compression = .gzip } - copy.content = try compression.compress(content: content) + if let compressedContent = compression.compress(content: content) { + copy.content = compressedContent + } else { + throw CodecError.invalidContent + } return copy } @@ -54,15 +58,24 @@ extension EncodedContent { switch compression { case .gzip: - copy.content = try EncodedContentCompression.gzip.decompress(content: content) + if let decompressedContent = EncodedContentCompression.gzip.decompress(content: content) { + copy.content = decompressedContent + } else { + throw CodecError.invalidContent + } case .deflate: - copy.content = try EncodedContentCompression.deflate.decompress(content: content) + if let decompressedContent = EncodedContentCompression.deflate.decompress(content: content) { + copy.content = decompressedContent + } else { + throw CodecError.invalidContent + } default: return copy } return copy } + } public protocol ContentCodec: Hashable, Equatable { diff --git a/Sources/XMTPiOS/EncodedContentCompression.swift b/Sources/XMTPiOS/EncodedContentCompression.swift index 1cb45c0c..59fe668a 100644 --- a/Sources/XMTPiOS/EncodedContentCompression.swift +++ b/Sources/XMTPiOS/EncodedContentCompression.swift @@ -1,60 +1,63 @@ -// -// EncodedContentCompression.swift -// -// -// Created by Pat Nakajima on 1/19/23. -// - +import Compression import Foundation -import Gzip -import zlib public enum EncodedContentCompression { - case deflate, gzip + case deflate + case gzip - func compress(content: Data) throws -> Data { + func compress(content: Data) -> Data? { switch self { case .deflate: - // 78 9C - Default Compression according to https://www.ietf.org/rfc/rfc1950.txt - let header = Data([0x78, 0x9C]) - - // Perform rfc1951 compression - let compressed = try (content as NSData).compressed(using: .zlib) as Data - - // Needed for rfc1950 compliance - let checksum = adler32(content) - - return header + compressed + checksum + return compressData(content, using: COMPRESSION_ZLIB) case .gzip: - return try content.gzipped() + return compressData(content, using: COMPRESSION_LZFSE) // For GZIP, switch to COMPRESSION_ZLIB if needed. } } - func decompress(content: Data) throws -> Data { + func decompress(content: Data) -> Data? { switch self { case .deflate: - // Swift uses https://www.ietf.org/rfc/rfc1951.txt while JS uses https://www.ietf.org/rfc/rfc1950.txt - // They're basically the same except the JS version has a two byte header that we can just get rid of - // and a four byte checksum at the end that seems to be ignored here. - let data = NSData(data: content[2...]) - let inflated = try data.decompressed(using: .zlib) - return inflated as Data + return decompressData(content, using: COMPRESSION_ZLIB) case .gzip: - return try content.gunzipped() + return decompressData(content, using: COMPRESSION_LZFSE) // For GZIP, switch to COMPRESSION_ZLIB if needed. } } - private func adler32(_ data: Data) -> Data { - let prime = UInt32(65521) - var s1 = UInt32(1 & 0xFFFF) - var s2 = UInt32((1 >> 16) & 0xFFFF) - data.forEach { - s1 += UInt32($0) - if s1 >= prime { s1 = s1 % prime } - s2 += s1 - if s2 >= prime { s2 = s2 % prime } + // Helper method to compress data using the Compression framework + private func compressData( + _ data: Data, using algorithm: compression_algorithm + ) -> Data? { + let destinationBuffer = UnsafeMutablePointer.allocate( + capacity: data.count) + defer { destinationBuffer.deallocate() } + + let compressedSize = data.withUnsafeBytes { sourceBuffer in + compression_encode_buffer( + destinationBuffer, data.count, + sourceBuffer.baseAddress!.assumingMemoryBound(to: UInt8.self), + data.count, nil, algorithm) } - var result = ((s2 << 16) | s1).bigEndian - return Data(bytes: &result, count: MemoryLayout.size) + + guard compressedSize > 0 else { return nil } + return Data(bytes: destinationBuffer, count: compressedSize) + } + + // Helper method to decompress data using the Compression framework + private func decompressData( + _ data: Data, using algorithm: compression_algorithm + ) -> Data? { + let destinationBuffer = UnsafeMutablePointer.allocate( + capacity: data.count * 4) // Allocate enough memory for decompressed data + defer { destinationBuffer.deallocate() } + + let decompressedSize = data.withUnsafeBytes { sourceBuffer in + compression_decode_buffer( + destinationBuffer, data.count * 4, + sourceBuffer.baseAddress!.assumingMemoryBound(to: UInt8.self), + data.count, nil, algorithm) + } + + guard decompressedSize > 0 else { return nil } + return Data(bytes: destinationBuffer, count: decompressedSize) } } diff --git a/XMTP.podspec b/XMTP.podspec index 33dc54a4..0f7c2449 100644 --- a/XMTP.podspec +++ b/XMTP.podspec @@ -12,7 +12,7 @@ Pod::Spec.new do |spec| spec.license = "MIT" spec.author = { "XMTP" => "eng@xmtp.com" } - spec.platform = :ios, '14.0', :macos, '11.0' + spec.platform = :ios, '14.0', :macos, '11.0' spec.swift_version = '5.3' @@ -20,7 +20,6 @@ Pod::Spec.new do |spec| spec.source_files = "Sources/**/*.swift" spec.frameworks = "CryptoKit", "UIKit" - spec.dependency "GzipSwift" spec.dependency "Connect-Swift", "= 1.0.0" spec.dependency 'LibXMTP', '= 3.0.1' spec.dependency 'CryptoSwift', '= 1.8.3' diff --git a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.pbxproj b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.pbxproj index 67a5a39e..1222d193 100644 --- a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.pbxproj +++ b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.pbxproj @@ -34,6 +34,7 @@ A6C0F3862AC1E549008C6AA7 /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6C0F3852AC1E549008C6AA7 /* Data.swift */; }; A6D192D0293A7B97006B49F2 /* ConversationListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6D192CF293A7B97006B49F2 /* ConversationListView.swift */; }; E513AEA32CE6AF2700BC31C3 /* CryptoSwift in Frameworks */ = {isa = PBXBuildFile; productRef = E513AEA22CE6AF2700BC31C3 /* CryptoSwift */; }; + E58362512CEBC4A6003D5D00 /* GZIP in Frameworks */ = {isa = PBXBuildFile; productRef = E58362502CEBC4A6003D5D00 /* GZIP */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -86,6 +87,7 @@ E513AEA32CE6AF2700BC31C3 /* CryptoSwift in Frameworks */, A6606A1A2B5EE80000E2ED4D /* XMTPiOS in Frameworks */, A6C0F37B2AC1E321008C6AA7 /* Starscream in Frameworks */, + E58362512CEBC4A6003D5D00 /* GZIP in Frameworks */, A65F070A297B5E8600C3C76E /* KeychainAccess in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -204,6 +206,7 @@ A6C0F37A2AC1E321008C6AA7 /* Starscream */, A6606A192B5EE80000E2ED4D /* XMTPiOS */, E513AEA22CE6AF2700BC31C3 /* CryptoSwift */, + E58362502CEBC4A6003D5D00 /* GZIP */, ); productName = XMTPiOSExample; productReference = A628198F292DC825004B9117 /* XMTPiOSExample.app */; @@ -238,6 +241,7 @@ A6C0F3792AC1E321008C6AA7 /* XCRemoteSwiftPackageReference "Starscream" */, E513AEA12CE6AF2700BC31C3 /* XCRemoteSwiftPackageReference "CryptoSwift" */, E5BCC0952CEBA58F00E11814 /* XCRemoteSwiftPackageReference "swift-secp256k1" */, + E583624F2CEBC4A6003D5D00 /* XCRemoteSwiftPackageReference "GZIP" */, ); productRefGroup = A6281990292DC825004B9117 /* Products */; projectDirPath = ""; @@ -552,6 +556,14 @@ minimumVersion = 1.8.3; }; }; + E583624F2CEBC4A6003D5D00 /* XCRemoteSwiftPackageReference "GZIP" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/nicklockwood/GZIP"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.3.2; + }; + }; E5BCC0952CEBA58F00E11814 /* XCRemoteSwiftPackageReference "swift-secp256k1" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/21-DOT-DEV/swift-secp256k1.git"; @@ -582,6 +594,11 @@ package = E513AEA12CE6AF2700BC31C3 /* XCRemoteSwiftPackageReference "CryptoSwift" */; productName = CryptoSwift; }; + E58362502CEBC4A6003D5D00 /* GZIP */ = { + isa = XCSwiftPackageProductDependency; + package = E583624F2CEBC4A6003D5D00 /* XCRemoteSwiftPackageReference "GZIP" */; + productName = GZIP; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = A6281987292DC825004B9117 /* Project object */; diff --git a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index aaf82bde..fb13ced0 100644 --- a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -19,12 +19,12 @@ } }, { - "identity" : "gzipswift", + "identity" : "gzip", "kind" : "remoteSourceControl", - "location" : "https://github.com/1024jp/GzipSwift", + "location" : "https://github.com/nicklockwood/GZIP", "state" : { - "revision" : "56bf51fdd2fe4b2cf254b2cf34aede3d7caccc6c", - "version" : "6.1.0" + "revision" : "f710a37aa978a93b815a4f64bd504dc4c3256312", + "version" : "1.3.2" } }, { From 5cecd1d2676b059185739ae1b8685e9973a90332 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Mon, 18 Nov 2024 11:25:34 -0800 Subject: [PATCH 09/19] remove force unwrap --- Sources/XMTPiOS/EncodedContentCompression.swift | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/Sources/XMTPiOS/EncodedContentCompression.swift b/Sources/XMTPiOS/EncodedContentCompression.swift index 59fe668a..0e824d20 100644 --- a/Sources/XMTPiOS/EncodedContentCompression.swift +++ b/Sources/XMTPiOS/EncodedContentCompression.swift @@ -47,14 +47,18 @@ public enum EncodedContentCompression { _ data: Data, using algorithm: compression_algorithm ) -> Data? { let destinationBuffer = UnsafeMutablePointer.allocate( - capacity: data.count * 4) // Allocate enough memory for decompressed data + capacity: data.count * 4 // Allocate enough memory for decompressed data + ) defer { destinationBuffer.deallocate() } - let decompressedSize = data.withUnsafeBytes { sourceBuffer in - compression_decode_buffer( + let decompressedSize = data.withUnsafeBytes { sourceBuffer -> Int in + guard let sourcePointer = sourceBuffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else { + return 0 // Return 0 to indicate failure + } + return compression_decode_buffer( destinationBuffer, data.count * 4, - sourceBuffer.baseAddress!.assumingMemoryBound(to: UInt8.self), - data.count, nil, algorithm) + sourcePointer, data.count, nil, algorithm + ) } guard decompressedSize > 0 else { return nil } From 9c806cdc6383788d758ac4406509f24287a79db1 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Mon, 18 Nov 2024 11:27:10 -0800 Subject: [PATCH 10/19] remove another force unwrap --- Sources/XMTPiOS/EncodedContentCompression.swift | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/Sources/XMTPiOS/EncodedContentCompression.swift b/Sources/XMTPiOS/EncodedContentCompression.swift index 0e824d20..5203ee0b 100644 --- a/Sources/XMTPiOS/EncodedContentCompression.swift +++ b/Sources/XMTPiOS/EncodedContentCompression.swift @@ -28,14 +28,18 @@ public enum EncodedContentCompression { _ data: Data, using algorithm: compression_algorithm ) -> Data? { let destinationBuffer = UnsafeMutablePointer.allocate( - capacity: data.count) + capacity: data.count + ) defer { destinationBuffer.deallocate() } - let compressedSize = data.withUnsafeBytes { sourceBuffer in - compression_encode_buffer( + let compressedSize = data.withUnsafeBytes { sourceBuffer -> Int in + guard let sourcePointer = sourceBuffer.baseAddress?.assumingMemoryBound(to: UInt8.self) else { + return 0 // Return 0 to indicate failure + } + return compression_encode_buffer( destinationBuffer, data.count, - sourceBuffer.baseAddress!.assumingMemoryBound(to: UInt8.self), - data.count, nil, algorithm) + sourcePointer, data.count, nil, algorithm + ) } guard compressedSize > 0 else { return nil } From de64769c72171e5b22078b5e29dbe025c00bb773 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Mon, 18 Nov 2024 16:01:59 -0800 Subject: [PATCH 11/19] add back sec --- Package.resolved | 25 ++++++----------- Package.swift | 4 +-- XMTP.podspec | 1 + .../XMTPiOSExample.xcodeproj/project.pbxproj | 28 ++++++------------- .../xcshareddata/swiftpm/Package.resolved | 27 ++++++------------ 5 files changed, 29 insertions(+), 56 deletions(-) diff --git a/Package.resolved b/Package.resolved index 0d011f98..005bb9de 100644 --- a/Package.resolved +++ b/Package.resolved @@ -19,21 +19,21 @@ } }, { - "identity" : "gzipswift", + "identity" : "libxmtp-swift", "kind" : "remoteSourceControl", - "location" : "https://github.com/1024jp/GzipSwift", + "location" : "https://github.com/xmtp/libxmtp-swift.git", "state" : { - "revision" : "56bf51fdd2fe4b2cf254b2cf34aede3d7caccc6c", - "version" : "6.1.0" + "revision" : "f495d4feaab40a0a6a48c1d5a99585de8107f5d2", + "version" : "3.0.1" } }, { - "identity" : "libxmtp-swift", + "identity" : "secp256k1.swift", "kind" : "remoteSourceControl", - "location" : "https://github.com/xmtp/libxmtp-swift.git", + "location" : "https://github.com/Boilertalk/secp256k1.swift.git", "state" : { - "revision" : "f495d4feaab40a0a6a48c1d5a99585de8107f5d2", - "version" : "3.0.1" + "revision" : "cd187c632fb812fd93711a9f7e644adb7e5f97f0", + "version" : "0.1.7" } }, { @@ -108,15 +108,6 @@ "version" : "1.28.2" } }, - { - "identity" : "swift-secp256k1", - "kind" : "remoteSourceControl", - "location" : "https://github.com/21-DOT-DEV/swift-secp256k1", - "state" : { - "revision" : "57ce9af6db14e0114af631ace25231a9d0ccccbd", - "version" : "0.18.0" - } - }, { "identity" : "swift-system", "kind" : "remoteSourceControl", diff --git a/Package.swift b/Package.swift index 1ed8960e..cbd00667 100644 --- a/Package.swift +++ b/Package.swift @@ -17,7 +17,7 @@ let package = Package( ), ], dependencies: [ - .package(url: "https://github.com/21-DOT-DEV/swift-secp256k1", exact: "0.18.0"), + .package(url: "https://github.com/Boilertalk/secp256k1.swift", from: "0.1.0"), .package(url: "https://github.com/bufbuild/connect-swift", exact: "1.0.0"), .package(url: "https://github.com/apple/swift-docc-plugin.git", from: "1.4.3"), .package(url: "https://github.com/xmtp/libxmtp-swift.git", exact: "3.0.1"), @@ -27,7 +27,7 @@ let package = Package( .target( name: "XMTPiOS", dependencies: [ - .product(name: "secp256k1", package: "swift-secp256k1"), + .product(name: "secp256k1", package: "secp256k1.swift"), .product(name: "Connect", package: "connect-swift"), .product(name: "LibXMTP", package: "libxmtp-swift"), .product(name: "CryptoSwift", package: "CryptoSwift") diff --git a/XMTP.podspec b/XMTP.podspec index 0f7c2449..0f45b506 100644 --- a/XMTP.podspec +++ b/XMTP.podspec @@ -20,6 +20,7 @@ Pod::Spec.new do |spec| spec.source_files = "Sources/**/*.swift" spec.frameworks = "CryptoKit", "UIKit" + spec.dependency 'secp256k1.swift' spec.dependency "Connect-Swift", "= 1.0.0" spec.dependency 'LibXMTP', '= 3.0.1' spec.dependency 'CryptoSwift', '= 1.8.3' diff --git a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.pbxproj b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.pbxproj index 1222d193..6b7d1909 100644 --- a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.pbxproj +++ b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.pbxproj @@ -34,7 +34,7 @@ A6C0F3862AC1E549008C6AA7 /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6C0F3852AC1E549008C6AA7 /* Data.swift */; }; A6D192D0293A7B97006B49F2 /* ConversationListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6D192CF293A7B97006B49F2 /* ConversationListView.swift */; }; E513AEA32CE6AF2700BC31C3 /* CryptoSwift in Frameworks */ = {isa = PBXBuildFile; productRef = E513AEA22CE6AF2700BC31C3 /* CryptoSwift */; }; - E58362512CEBC4A6003D5D00 /* GZIP in Frameworks */ = {isa = PBXBuildFile; productRef = E58362502CEBC4A6003D5D00 /* GZIP */; }; + E58362552CEC0B94003D5D00 /* secp256k1 in Frameworks */ = {isa = PBXBuildFile; productRef = E58362542CEC0B94003D5D00 /* secp256k1 */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -85,9 +85,9 @@ buildActionMask = 2147483647; files = ( E513AEA32CE6AF2700BC31C3 /* CryptoSwift in Frameworks */, + E58362552CEC0B94003D5D00 /* secp256k1 in Frameworks */, A6606A1A2B5EE80000E2ED4D /* XMTPiOS in Frameworks */, A6C0F37B2AC1E321008C6AA7 /* Starscream in Frameworks */, - E58362512CEBC4A6003D5D00 /* GZIP in Frameworks */, A65F070A297B5E8600C3C76E /* KeychainAccess in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -206,7 +206,7 @@ A6C0F37A2AC1E321008C6AA7 /* Starscream */, A6606A192B5EE80000E2ED4D /* XMTPiOS */, E513AEA22CE6AF2700BC31C3 /* CryptoSwift */, - E58362502CEBC4A6003D5D00 /* GZIP */, + E58362542CEC0B94003D5D00 /* secp256k1 */, ); productName = XMTPiOSExample; productReference = A628198F292DC825004B9117 /* XMTPiOSExample.app */; @@ -240,8 +240,7 @@ A65F0708297B5E8600C3C76E /* XCRemoteSwiftPackageReference "KeychainAccess" */, A6C0F3792AC1E321008C6AA7 /* XCRemoteSwiftPackageReference "Starscream" */, E513AEA12CE6AF2700BC31C3 /* XCRemoteSwiftPackageReference "CryptoSwift" */, - E5BCC0952CEBA58F00E11814 /* XCRemoteSwiftPackageReference "swift-secp256k1" */, - E583624F2CEBC4A6003D5D00 /* XCRemoteSwiftPackageReference "GZIP" */, + E58362532CEBFD33003D5D00 /* XCRemoteSwiftPackageReference "secp256k1" */, ); productRefGroup = A6281990292DC825004B9117 /* Products */; projectDirPath = ""; @@ -556,20 +555,12 @@ minimumVersion = 1.8.3; }; }; - E583624F2CEBC4A6003D5D00 /* XCRemoteSwiftPackageReference "GZIP" */ = { + E58362532CEBFD33003D5D00 /* XCRemoteSwiftPackageReference "secp256k1" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/nicklockwood/GZIP"; + repositoryURL = "https://github.com/Boilertalk/secp256k1.swift"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 1.3.2; - }; - }; - E5BCC0952CEBA58F00E11814 /* XCRemoteSwiftPackageReference "swift-secp256k1" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/21-DOT-DEV/swift-secp256k1.git"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 0.18.0; + minimumVersion = 0.1.7; }; }; /* End XCRemoteSwiftPackageReference section */ @@ -594,10 +585,9 @@ package = E513AEA12CE6AF2700BC31C3 /* XCRemoteSwiftPackageReference "CryptoSwift" */; productName = CryptoSwift; }; - E58362502CEBC4A6003D5D00 /* GZIP */ = { + E58362542CEC0B94003D5D00 /* secp256k1 */ = { isa = XCSwiftPackageProductDependency; - package = E583624F2CEBC4A6003D5D00 /* XCRemoteSwiftPackageReference "GZIP" */; - productName = GZIP; + productName = secp256k1; }; /* End XCSwiftPackageProductDependency section */ }; diff --git a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index fb13ced0..955fd0ec 100644 --- a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -18,15 +18,6 @@ "version" : "1.8.3" } }, - { - "identity" : "gzip", - "kind" : "remoteSourceControl", - "location" : "https://github.com/nicklockwood/GZIP", - "state" : { - "revision" : "f710a37aa978a93b815a4f64bd504dc4c3256312", - "version" : "1.3.2" - } - }, { "identity" : "keychainaccess", "kind" : "remoteSourceControl", @@ -45,6 +36,15 @@ "version" : "3.0.1" } }, + { + "identity" : "secp256k1.swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/Boilertalk/secp256k1.swift", + "state" : { + "revision" : "cd187c632fb812fd93711a9f7e644adb7e5f97f0", + "version" : "0.1.7" + } + }, { "identity" : "starscream", "kind" : "remoteSourceControl", @@ -126,15 +126,6 @@ "version" : "1.28.2" } }, - { - "identity" : "swift-secp256k1", - "kind" : "remoteSourceControl", - "location" : "https://github.com/21-DOT-DEV/swift-secp256k1.git", - "state" : { - "revision" : "57ce9af6db14e0114af631ace25231a9d0ccccbd", - "version" : "0.18.0" - } - }, { "identity" : "swift-system", "kind" : "remoteSourceControl", From 6d326a7d0524b4bffa6d68bcfcf766d6cf3fd337 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Mon, 18 Nov 2024 16:24:07 -0800 Subject: [PATCH 12/19] add target --- XMTP.podspec | 2 ++ 1 file changed, 2 insertions(+) diff --git a/XMTP.podspec b/XMTP.podspec index 0f45b506..b152df38 100644 --- a/XMTP.podspec +++ b/XMTP.podspec @@ -24,4 +24,6 @@ Pod::Spec.new do |spec| spec.dependency "Connect-Swift", "= 1.0.0" spec.dependency 'LibXMTP', '= 3.0.1' spec.dependency 'CryptoSwift', '= 1.8.3' + + spec.ios.deployment_target = '14.0' end From 0be941e3358f800ca7f9ece23297aee68a67b4b1 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Mon, 18 Nov 2024 20:16:46 -0800 Subject: [PATCH 13/19] try with another library --- Package.swift | 4 +- Sources/XMTPiOS/KeyUtil.swift | 108 ++++-------------- Tests/XMTPTests/CryptoTests.swift | 1 - XMTP.podspec | 2 +- .../XMTPiOSExample.xcodeproj/project.pbxproj | 18 ++- .../xcshareddata/swiftpm/Package.resolved | 15 ++- 6 files changed, 47 insertions(+), 101 deletions(-) diff --git a/Package.swift b/Package.swift index cbd00667..35e196f5 100644 --- a/Package.swift +++ b/Package.swift @@ -17,7 +17,7 @@ let package = Package( ), ], dependencies: [ - .package(url: "https://github.com/Boilertalk/secp256k1.swift", from: "0.1.0"), + .package(url: "https://github.com/blocto/secp256k1.swift", from: "0.7.4"), .package(url: "https://github.com/bufbuild/connect-swift", exact: "1.0.0"), .package(url: "https://github.com/apple/swift-docc-plugin.git", from: "1.4.3"), .package(url: "https://github.com/xmtp/libxmtp-swift.git", exact: "3.0.1"), @@ -27,7 +27,7 @@ let package = Package( .target( name: "XMTPiOS", dependencies: [ - .product(name: "secp256k1", package: "secp256k1.swift"), + .product(name: "secp256k1Swift", package: "secp256k1.swift"), .product(name: "Connect", package: "connect-swift"), .product(name: "LibXMTP", package: "libxmtp-swift"), .product(name: "CryptoSwift", package: "CryptoSwift") diff --git a/Sources/XMTPiOS/KeyUtil.swift b/Sources/XMTPiOS/KeyUtil.swift index 8c044e0e..054b0f44 100644 --- a/Sources/XMTPiOS/KeyUtil.swift +++ b/Sources/XMTPiOS/KeyUtil.swift @@ -1,5 +1,5 @@ import Foundation -import secp256k1 +import secp256k1Swift import LibXMTP import CryptoSwift @@ -28,42 +28,34 @@ enum KeyUtilx { } static func sign(message: Data, with privateKey: Data, hashing: Bool) throws -> Data { - guard let ctx = secp256k1_context_create(UInt32(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY)) else { - throw KeyUtilError.invalidContext - } + // Hash the message if required + let msgData = hashing ? message.sha3(.keccak256) : message - defer { - secp256k1_context_destroy(ctx) + // Ensure the private key is valid + guard privateKey.count == 32 else { + throw KeyUtilError.privateKeyInvalid } - let msgData = hashing ? message.sha3(.keccak256) : message - let msg = (msgData as NSData).bytes.assumingMemoryBound(to: UInt8.self) - let privateKeyPtr = (privateKey as NSData).bytes.assumingMemoryBound(to: UInt8.self) - let signaturePtr = UnsafeMutablePointer.allocate(capacity: 1) - defer { - signaturePtr.deallocate() - } - guard secp256k1_ecdsa_sign_recoverable(ctx, signaturePtr, msg, privateKeyPtr, nil, nil) == 1 else { - throw KeyUtilError.signatureFailure + // Create a Signing.PrivateKey instance + guard let signingKey = try? secp256k1.Signing.PrivateKey(rawRepresentation: privateKey) else { + throw KeyUtilError.privateKeyInvalid } + - let outputPtr = UnsafeMutablePointer.allocate(capacity: 64) - defer { - outputPtr.deallocate() + // Sign the message + guard let signature = try? signingKey.ecdsa.signature(for: msgData) else { + throw KeyUtilError.signatureFailure } - var recid: Int32 = 0 - secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, outputPtr, &recid, signaturePtr) - let outputWithRecidPtr = UnsafeMutablePointer.allocate(capacity: 65) - defer { - outputWithRecidPtr.deallocate() - } - outputWithRecidPtr.update(from: outputPtr, count: 64) - outputWithRecidPtr.advanced(by: 64).pointee = UInt8(recid) + // Obtain the compact signature and recovery ID + let compactSignature = try signature.compactRepresentation + let recoveryID: UInt8 = 0 - let signature = Data(bytes: outputWithRecidPtr, count: 65) + // Combine the compact signature and recovery ID + var signatureWithRecid = Data(compactSignature) + signatureWithRecid.append(recoveryID) - return signature + return signatureWithRecid } static func generateAddress(from publicKey: Data) -> String { @@ -73,64 +65,4 @@ enum KeyUtilx { let address = hash.subdata(in: 12 ..< hash.count) return "0x" + address.toHex } - - static func recoverPublicKey(message: Data, signature: Data) throws -> Data { - guard let ctx = secp256k1_context_create(UInt32(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY)) else { - throw KeyUtilError.invalidContext - } - defer { secp256k1_context_destroy(ctx) } - - // get recoverable signature - let signaturePtr = UnsafeMutablePointer.allocate(capacity: 1) - defer { signaturePtr.deallocate() } - if signature.count < 65 { - throw KeyUtilError.signatureParseFailure - } - - let serializedSignature = Data(signature[0 ..< 64]) - var v = Int32(signature[64]) - if v >= 27, v <= 30 { - v -= 27 - } else if v >= 31, v <= 34 { - v -= 31 - } else if v >= 35, v <= 38 { - v -= 35 - } - - try serializedSignature.withUnsafeBytes { - guard let baseAddress = $0.bindMemory(to: UInt8.self).baseAddress else { - throw KeyUtilError.signatureParseFailure // or a more specific error for "empty buffer" - } - if v > 3 { - throw KeyUtilError.signatureParseFailure - } - guard secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, signaturePtr, baseAddress, v) == 1 else { - throw KeyUtilError.signatureParseFailure - } - } - - let pubkey = UnsafeMutablePointer.allocate(capacity: 1) - defer { pubkey.deallocate() } - - try message.withUnsafeBytes { - guard let baseAddress = $0.bindMemory(to: UInt8.self).baseAddress else { - throw KeyUtilError.signatureFailure // Consider throwing a more specific error - } - - guard secp256k1_ecdsa_recover(ctx, pubkey, signaturePtr, baseAddress) == 1 else { - throw KeyUtilError.signatureFailure - } - } - - var size = 65 - var rv = Data(count: size) - rv.withUnsafeMutableBytes { buffer -> Void in - guard let baseAddress = buffer.bindMemory(to: UInt8.self).baseAddress else { - return // Optionally, handle the error or log this condition - } - secp256k1_ec_pubkey_serialize(ctx, baseAddress, &size, pubkey, UInt32(SECP256K1_EC_UNCOMPRESSED)) - } - - return rv - } } diff --git a/Tests/XMTPTests/CryptoTests.swift b/Tests/XMTPTests/CryptoTests.swift index c961d051..53e87720 100644 --- a/Tests/XMTPTests/CryptoTests.swift +++ b/Tests/XMTPTests/CryptoTests.swift @@ -1,5 +1,4 @@ import XCTest -import secp256k1 @testable import XMTPiOS diff --git a/XMTP.podspec b/XMTP.podspec index b152df38..3f729bc4 100644 --- a/XMTP.podspec +++ b/XMTP.podspec @@ -20,7 +20,7 @@ Pod::Spec.new do |spec| spec.source_files = "Sources/**/*.swift" spec.frameworks = "CryptoKit", "UIKit" - spec.dependency 'secp256k1.swift' + spec.dependency 'secp256k1Swift' spec.dependency "Connect-Swift", "= 1.0.0" spec.dependency 'LibXMTP', '= 3.0.1' spec.dependency 'CryptoSwift', '= 1.8.3' diff --git a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.pbxproj b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.pbxproj index 6b7d1909..04c35af4 100644 --- a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.pbxproj +++ b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.pbxproj @@ -34,7 +34,7 @@ A6C0F3862AC1E549008C6AA7 /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6C0F3852AC1E549008C6AA7 /* Data.swift */; }; A6D192D0293A7B97006B49F2 /* ConversationListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6D192CF293A7B97006B49F2 /* ConversationListView.swift */; }; E513AEA32CE6AF2700BC31C3 /* CryptoSwift in Frameworks */ = {isa = PBXBuildFile; productRef = E513AEA22CE6AF2700BC31C3 /* CryptoSwift */; }; - E58362552CEC0B94003D5D00 /* secp256k1 in Frameworks */ = {isa = PBXBuildFile; productRef = E58362542CEC0B94003D5D00 /* secp256k1 */; }; + E58362592CEC42A3003D5D00 /* secp256k1Swift in Frameworks */ = {isa = PBXBuildFile; productRef = E58362582CEC42A3003D5D00 /* secp256k1Swift */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -84,8 +84,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + E58362592CEC42A3003D5D00 /* secp256k1Swift in Frameworks */, E513AEA32CE6AF2700BC31C3 /* CryptoSwift in Frameworks */, - E58362552CEC0B94003D5D00 /* secp256k1 in Frameworks */, A6606A1A2B5EE80000E2ED4D /* XMTPiOS in Frameworks */, A6C0F37B2AC1E321008C6AA7 /* Starscream in Frameworks */, A65F070A297B5E8600C3C76E /* KeychainAccess in Frameworks */, @@ -207,6 +207,7 @@ A6606A192B5EE80000E2ED4D /* XMTPiOS */, E513AEA22CE6AF2700BC31C3 /* CryptoSwift */, E58362542CEC0B94003D5D00 /* secp256k1 */, + E58362582CEC42A3003D5D00 /* secp256k1Swift */, ); productName = XMTPiOSExample; productReference = A628198F292DC825004B9117 /* XMTPiOSExample.app */; @@ -240,7 +241,7 @@ A65F0708297B5E8600C3C76E /* XCRemoteSwiftPackageReference "KeychainAccess" */, A6C0F3792AC1E321008C6AA7 /* XCRemoteSwiftPackageReference "Starscream" */, E513AEA12CE6AF2700BC31C3 /* XCRemoteSwiftPackageReference "CryptoSwift" */, - E58362532CEBFD33003D5D00 /* XCRemoteSwiftPackageReference "secp256k1" */, + E58362572CEC42A3003D5D00 /* XCRemoteSwiftPackageReference "secp256k1" */, ); productRefGroup = A6281990292DC825004B9117 /* Products */; projectDirPath = ""; @@ -555,12 +556,12 @@ minimumVersion = 1.8.3; }; }; - E58362532CEBFD33003D5D00 /* XCRemoteSwiftPackageReference "secp256k1" */ = { + E58362572CEC42A3003D5D00 /* XCRemoteSwiftPackageReference "secp256k1" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/Boilertalk/secp256k1.swift"; + repositoryURL = "https://github.com/blocto/secp256k1.swift"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 0.1.7; + minimumVersion = 0.7.4; }; }; /* End XCRemoteSwiftPackageReference section */ @@ -589,6 +590,11 @@ isa = XCSwiftPackageProductDependency; productName = secp256k1; }; + E58362582CEC42A3003D5D00 /* secp256k1Swift */ = { + isa = XCSwiftPackageProductDependency; + package = E58362572CEC42A3003D5D00 /* XCRemoteSwiftPackageReference "secp256k1" */; + productName = secp256k1Swift; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = A6281987292DC825004B9117 /* Project object */; diff --git a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 955fd0ec..76967ae5 100644 --- a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -36,13 +36,22 @@ "version" : "3.0.1" } }, + { + "identity" : "secp256k1", + "kind" : "remoteSourceControl", + "location" : "https://github.com/portto/secp256k1.git", + "state" : { + "revision" : "6864a2560066cedede330c4b344689432a7300f7", + "version" : "0.0.5" + } + }, { "identity" : "secp256k1.swift", "kind" : "remoteSourceControl", - "location" : "https://github.com/Boilertalk/secp256k1.swift", + "location" : "https://github.com/blocto/secp256k1.swift", "state" : { - "revision" : "cd187c632fb812fd93711a9f7e644adb7e5f97f0", - "version" : "0.1.7" + "revision" : "23aa6bab1f60e513297d0d58a863418f68534e56", + "version" : "0.7.4" } }, { From 2f5aaab461adeeeaea16b092e117c8d517ec5c6e Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Tue, 19 Nov 2024 11:33:17 -0800 Subject: [PATCH 14/19] another try on signing --- Package.swift | 4 +- Sources/XMTPiOS/KeyUtil.swift | 50 +++++++++++-------- XMTP.podspec | 2 +- .../XMTPiOSExample.xcodeproj/project.pbxproj | 20 ++++---- .../xcshareddata/swiftpm/Package.resolved | 27 ++++------ 5 files changed, 51 insertions(+), 52 deletions(-) diff --git a/Package.swift b/Package.swift index 5b010e3c..1ecb5bc9 100644 --- a/Package.swift +++ b/Package.swift @@ -17,7 +17,7 @@ let package = Package( ), ], dependencies: [ - .package(url: "https://github.com/blocto/secp256k1.swift", from: "0.7.4"), + .package(url: "https://github.com/tesseract-one/CSecp256k1.swift.git", from: "0.2.0"), .package(url: "https://github.com/bufbuild/connect-swift", exact: "1.0.0"), .package(url: "https://github.com/apple/swift-docc-plugin.git", from: "1.4.3"), .package(url: "https://github.com/xmtp/libxmtp-swift.git", exact: "3.0.3"), @@ -27,7 +27,7 @@ let package = Package( .target( name: "XMTPiOS", dependencies: [ - .product(name: "secp256k1Swift", package: "secp256k1.swift"), + .product(name: "CSecp256k1", package: "CSecp256k1.swift"), .product(name: "Connect", package: "connect-swift"), .product(name: "LibXMTP", package: "libxmtp-swift"), .product(name: "CryptoSwift", package: "CryptoSwift") diff --git a/Sources/XMTPiOS/KeyUtil.swift b/Sources/XMTPiOS/KeyUtil.swift index 054b0f44..ea28ff9a 100644 --- a/Sources/XMTPiOS/KeyUtil.swift +++ b/Sources/XMTPiOS/KeyUtil.swift @@ -1,5 +1,5 @@ import Foundation -import secp256k1Swift +import CSecp256k1 import LibXMTP import CryptoSwift @@ -26,36 +26,44 @@ enum KeyUtilx { static func recoverPublicKeyKeccak256(from data: Data, message: Data) throws -> Data { return Data(try LibXMTP.recoverPublicKeyK256Keccak256(message: message, signature: data)) } - + static func sign(message: Data, with privateKey: Data, hashing: Bool) throws -> Data { - // Hash the message if required - let msgData = hashing ? message.sha3(.keccak256) : message - - // Ensure the private key is valid - guard privateKey.count == 32 else { - throw KeyUtilError.privateKeyInvalid + guard let ctx = secp256k1_context_create(UInt32(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY)) else { + throw KeyUtilError.invalidContext } - // Create a Signing.PrivateKey instance - guard let signingKey = try? secp256k1.Signing.PrivateKey(rawRepresentation: privateKey) else { - throw KeyUtilError.privateKeyInvalid + defer { + secp256k1_context_destroy(ctx) } - - // Sign the message - guard let signature = try? signingKey.ecdsa.signature(for: msgData) else { + let msgData = hashing ? Util.keccak256(message) : message + let msg = (msgData as NSData).bytes.assumingMemoryBound(to: UInt8.self) + let privateKeyPtr = (privateKey as NSData).bytes.assumingMemoryBound(to: UInt8.self) + let signaturePtr = UnsafeMutablePointer.allocate(capacity: 1) + defer { + signaturePtr.deallocate() + } + guard secp256k1_ecdsa_sign_recoverable(ctx, signaturePtr, msg, privateKeyPtr, nil, nil) == 1 else { throw KeyUtilError.signatureFailure } - // Obtain the compact signature and recovery ID - let compactSignature = try signature.compactRepresentation - let recoveryID: UInt8 = 0 + let outputPtr = UnsafeMutablePointer.allocate(capacity: 64) + defer { + outputPtr.deallocate() + } + var recid: Int32 = 0 + secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, outputPtr, &recid, signaturePtr) + + let outputWithRecidPtr = UnsafeMutablePointer.allocate(capacity: 65) + defer { + outputWithRecidPtr.deallocate() + } + outputWithRecidPtr.assign(from: outputPtr, count: 64) + outputWithRecidPtr.advanced(by: 64).pointee = UInt8(recid) - // Combine the compact signature and recovery ID - var signatureWithRecid = Data(compactSignature) - signatureWithRecid.append(recoveryID) + let signature = Data(bytes: outputWithRecidPtr, count: 65) - return signatureWithRecid + return signature } static func generateAddress(from publicKey: Data) -> String { diff --git a/XMTP.podspec b/XMTP.podspec index b3674da8..63c9919e 100644 --- a/XMTP.podspec +++ b/XMTP.podspec @@ -20,7 +20,7 @@ Pod::Spec.new do |spec| spec.source_files = "Sources/**/*.swift" spec.frameworks = "CryptoKit", "UIKit" - spec.dependency 'secp256k1Swift' + spec.dependency 'CSecp256k1', '~> 0.2' spec.dependency "Connect-Swift", "= 1.0.0" spec.dependency 'LibXMTP', '= 3.0.3' spec.dependency 'CryptoSwift', '= 1.8.3' diff --git a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.pbxproj b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.pbxproj index 04c35af4..68926c96 100644 --- a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.pbxproj +++ b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.pbxproj @@ -34,7 +34,7 @@ A6C0F3862AC1E549008C6AA7 /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6C0F3852AC1E549008C6AA7 /* Data.swift */; }; A6D192D0293A7B97006B49F2 /* ConversationListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6D192CF293A7B97006B49F2 /* ConversationListView.swift */; }; E513AEA32CE6AF2700BC31C3 /* CryptoSwift in Frameworks */ = {isa = PBXBuildFile; productRef = E513AEA22CE6AF2700BC31C3 /* CryptoSwift */; }; - E58362592CEC42A3003D5D00 /* secp256k1Swift in Frameworks */ = {isa = PBXBuildFile; productRef = E58362582CEC42A3003D5D00 /* secp256k1Swift */; }; + E583625C2CED1643003D5D00 /* CSecp256k1 in Frameworks */ = {isa = PBXBuildFile; productRef = E583625B2CED1643003D5D00 /* CSecp256k1 */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -84,9 +84,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - E58362592CEC42A3003D5D00 /* secp256k1Swift in Frameworks */, E513AEA32CE6AF2700BC31C3 /* CryptoSwift in Frameworks */, A6606A1A2B5EE80000E2ED4D /* XMTPiOS in Frameworks */, + E583625C2CED1643003D5D00 /* CSecp256k1 in Frameworks */, A6C0F37B2AC1E321008C6AA7 /* Starscream in Frameworks */, A65F070A297B5E8600C3C76E /* KeychainAccess in Frameworks */, ); @@ -207,7 +207,7 @@ A6606A192B5EE80000E2ED4D /* XMTPiOS */, E513AEA22CE6AF2700BC31C3 /* CryptoSwift */, E58362542CEC0B94003D5D00 /* secp256k1 */, - E58362582CEC42A3003D5D00 /* secp256k1Swift */, + E583625B2CED1643003D5D00 /* CSecp256k1 */, ); productName = XMTPiOSExample; productReference = A628198F292DC825004B9117 /* XMTPiOSExample.app */; @@ -241,7 +241,7 @@ A65F0708297B5E8600C3C76E /* XCRemoteSwiftPackageReference "KeychainAccess" */, A6C0F3792AC1E321008C6AA7 /* XCRemoteSwiftPackageReference "Starscream" */, E513AEA12CE6AF2700BC31C3 /* XCRemoteSwiftPackageReference "CryptoSwift" */, - E58362572CEC42A3003D5D00 /* XCRemoteSwiftPackageReference "secp256k1" */, + E583625A2CED1643003D5D00 /* XCRemoteSwiftPackageReference "CSecp256k1.swift" */, ); productRefGroup = A6281990292DC825004B9117 /* Products */; projectDirPath = ""; @@ -556,12 +556,12 @@ minimumVersion = 1.8.3; }; }; - E58362572CEC42A3003D5D00 /* XCRemoteSwiftPackageReference "secp256k1" */ = { + E583625A2CED1643003D5D00 /* XCRemoteSwiftPackageReference "CSecp256k1.swift" */ = { isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/blocto/secp256k1.swift"; + repositoryURL = "https://github.com/tesseract-one/CSecp256k1.swift.git"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 0.7.4; + minimumVersion = 0.2.0; }; }; /* End XCRemoteSwiftPackageReference section */ @@ -590,10 +590,10 @@ isa = XCSwiftPackageProductDependency; productName = secp256k1; }; - E58362582CEC42A3003D5D00 /* secp256k1Swift */ = { + E583625B2CED1643003D5D00 /* CSecp256k1 */ = { isa = XCSwiftPackageProductDependency; - package = E58362572CEC42A3003D5D00 /* XCRemoteSwiftPackageReference "secp256k1" */; - productName = secp256k1Swift; + package = E583625A2CED1643003D5D00 /* XCRemoteSwiftPackageReference "CSecp256k1.swift" */; + productName = CSecp256k1; }; /* End XCSwiftPackageProductDependency section */ }; diff --git a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 7dea0195..21d422e2 100644 --- a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -18,6 +18,15 @@ "version" : "1.8.3" } }, + { + "identity" : "csecp256k1.swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/tesseract-one/CSecp256k1.swift.git", + "state" : { + "revision" : "cfbd6f540d5084bc96a60af841121472fbe725a3", + "version" : "0.2.0" + } + }, { "identity" : "keychainaccess", "kind" : "remoteSourceControl", @@ -36,24 +45,6 @@ "version" : "3.0.3" } }, - { - "identity" : "secp256k1", - "kind" : "remoteSourceControl", - "location" : "https://github.com/portto/secp256k1.git", - "state" : { - "revision" : "6864a2560066cedede330c4b344689432a7300f7", - "version" : "0.0.5" - } - }, - { - "identity" : "secp256k1.swift", - "kind" : "remoteSourceControl", - "location" : "https://github.com/blocto/secp256k1.swift", - "state" : { - "revision" : "23aa6bab1f60e513297d0d58a863418f68534e56", - "version" : "0.7.4" - } - }, { "identity" : "starscream", "kind" : "remoteSourceControl", From 278040e65f3538a89e6a32c63d041bca9cba070d Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Tue, 19 Nov 2024 18:36:56 -0800 Subject: [PATCH 15/19] get the example app building --- .../XMTPiOSExample.xcodeproj/project.pbxproj | 28 --- .../XMTPiOSExample/Account/Account.swift | 58 ------ .../Account/AccountManager.swift | 21 -- .../XMTPiOSExample/ContentView.swift | 13 -- .../XMTPiOSExample/Views/LoginView.swift | 194 ------------------ 5 files changed, 314 deletions(-) delete mode 100644 XMTPiOSExample/XMTPiOSExample/Account/Account.swift delete mode 100644 XMTPiOSExample/XMTPiOSExample/Account/AccountManager.swift delete mode 100644 XMTPiOSExample/XMTPiOSExample/Views/LoginView.swift diff --git a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.pbxproj b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.pbxproj index 68926c96..ffb7c48b 100644 --- a/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.pbxproj +++ b/XMTPiOSExample/XMTPiOSExample.xcodeproj/project.pbxproj @@ -19,18 +19,13 @@ A65F0704297B5D4E00C3C76E /* Persistence.swift in Sources */ = {isa = PBXBuildFile; fileRef = A65F0703297B5D4E00C3C76E /* Persistence.swift */; }; A65F070A297B5E8600C3C76E /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = A65F0709297B5E8600C3C76E /* KeychainAccess */; }; A6606A1A2B5EE80000E2ED4D /* XMTPiOS in Frameworks */ = {isa = PBXBuildFile; productRef = A6606A192B5EE80000E2ED4D /* XMTPiOS */; }; - A67CCEC129355B4B00131F5C /* AccountManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A67CCEC029355B4B00131F5C /* AccountManager.swift */; }; A683860C293EA862006336FF /* MessageListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A683860B293EA862006336FF /* MessageListView.swift */; }; A685CC662B72B114008ACECE /* Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = A685CC652B72B114008ACECE /* Util.swift */; }; A685CC682B72B306008ACECE /* GroupSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A685CC672B72B306008ACECE /* GroupSettingsView.swift */; }; - A687810729679BC700042FAB /* Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = A687810629679BC700042FAB /* Account.swift */; }; - A687810C29679BFC00042FAB /* WalletConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = A687810B29679BFC00042FAB /* WalletConnection.swift */; }; - A687810E29679C0D00042FAB /* WalletConnectionMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = A687810D29679C0D00042FAB /* WalletConnectionMethod.swift */; }; A68807152B6C53E0004340BD /* GroupDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A68807142B6C53E0004340BD /* GroupDetailView.swift */; }; A69F33CA292DD557005A5556 /* LoggedInView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69F33C9292DD557005A5556 /* LoggedInView.swift */; }; A69F33CC292DD568005A5556 /* QRCodeSheetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A69F33CB292DD568005A5556 /* QRCodeSheetView.swift */; }; A6C0F37B2AC1E321008C6AA7 /* Starscream in Frameworks */ = {isa = PBXBuildFile; productRef = A6C0F37A2AC1E321008C6AA7 /* Starscream */; }; - A6C0F3842AC1E4B5008C6AA7 /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6C0F3832AC1E4B5008C6AA7 /* LoginView.swift */; }; A6C0F3862AC1E549008C6AA7 /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6C0F3852AC1E549008C6AA7 /* Data.swift */; }; A6D192D0293A7B97006B49F2 /* ConversationListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6D192CF293A7B97006B49F2 /* ConversationListView.swift */; }; E513AEA32CE6AF2700BC31C3 /* CryptoSwift in Frameworks */ = {isa = PBXBuildFile; productRef = E513AEA22CE6AF2700BC31C3 /* CryptoSwift */; }; @@ -63,17 +58,12 @@ A6557A302941166E00CC4C7B /* MessageCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageCellView.swift; sourceTree = ""; }; A6557A3229411F4F00CC4C7B /* NewConversationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewConversationView.swift; sourceTree = ""; }; A65F0703297B5D4E00C3C76E /* Persistence.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Persistence.swift; sourceTree = ""; }; - A67CCEC029355B4B00131F5C /* AccountManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountManager.swift; sourceTree = ""; }; A683860B293EA862006336FF /* MessageListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageListView.swift; sourceTree = ""; }; A685CC652B72B114008ACECE /* Util.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Util.swift; sourceTree = ""; }; A685CC672B72B306008ACECE /* GroupSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupSettingsView.swift; sourceTree = ""; }; - A687810629679BC700042FAB /* Account.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Account.swift; sourceTree = ""; }; - A687810B29679BFC00042FAB /* WalletConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletConnection.swift; sourceTree = ""; }; - A687810D29679C0D00042FAB /* WalletConnectionMethod.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletConnectionMethod.swift; sourceTree = ""; }; A68807142B6C53E0004340BD /* GroupDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupDetailView.swift; sourceTree = ""; }; A69F33C9292DD557005A5556 /* LoggedInView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoggedInView.swift; sourceTree = ""; }; A69F33CB292DD568005A5556 /* QRCodeSheetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeSheetView.swift; sourceTree = ""; }; - A6C0F3832AC1E4B5008C6AA7 /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = ""; }; A6C0F3852AC1E549008C6AA7 /* Data.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Data.swift; sourceTree = ""; }; A6D192CF293A7B97006B49F2 /* ConversationListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationListView.swift; sourceTree = ""; }; A6E774192B154D1E00F01DFF /* xmtp-ios */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = "xmtp-ios"; path = ..; sourceTree = ""; }; @@ -118,7 +108,6 @@ children = ( A6C0F3872AC1E54F008C6AA7 /* Extensions */, A65F0703297B5D4E00C3C76E /* Persistence.swift */, - A687810529679B5B00042FAB /* Account */, A69F33C8292DD54C005A5556 /* Views */, A6281992292DC825004B9117 /* XMTPiOSExampleApp.swift */, A6281994292DC825004B9117 /* ContentView.swift */, @@ -138,17 +127,6 @@ path = "Preview Content"; sourceTree = ""; }; - A687810529679B5B00042FAB /* Account */ = { - isa = PBXGroup; - children = ( - A67CCEC029355B4B00131F5C /* AccountManager.swift */, - A687810629679BC700042FAB /* Account.swift */, - A687810B29679BFC00042FAB /* WalletConnection.swift */, - A687810D29679C0D00042FAB /* WalletConnectionMethod.swift */, - ); - path = Account; - sourceTree = ""; - }; A69F33C4292DC992005A5556 /* Frameworks */ = { isa = PBXGroup; children = ( @@ -168,7 +146,6 @@ A683860B293EA862006336FF /* MessageListView.swift */, A6557A302941166E00CC4C7B /* MessageCellView.swift */, A6557A3229411F4F00CC4C7B /* NewConversationView.swift */, - A6C0F3832AC1E4B5008C6AA7 /* LoginView.swift */, A68807142B6C53E0004340BD /* GroupDetailView.swift */, A685CC672B72B306008ACECE /* GroupSettingsView.swift */, ); @@ -295,20 +272,15 @@ A68807152B6C53E0004340BD /* GroupDetailView.swift in Sources */, A6C0F3862AC1E549008C6AA7 /* Data.swift in Sources */, A65F0704297B5D4E00C3C76E /* Persistence.swift in Sources */, - A687810729679BC700042FAB /* Account.swift in Sources */, A6557A312941166E00CC4C7B /* MessageCellView.swift in Sources */, A60FC8C1293AD171001697E3 /* ConversationDetailView.swift in Sources */, A685CC682B72B306008ACECE /* GroupSettingsView.swift in Sources */, A685CC662B72B114008ACECE /* Util.swift in Sources */, A60FC8C3293AD18A001697E3 /* PreviewClientProvider.swift in Sources */, A6281995292DC825004B9117 /* ContentView.swift in Sources */, - A687810C29679BFC00042FAB /* WalletConnection.swift in Sources */, A69F33CA292DD557005A5556 /* LoggedInView.swift in Sources */, A69F33CC292DD568005A5556 /* QRCodeSheetView.swift in Sources */, - A6C0F3842AC1E4B5008C6AA7 /* LoginView.swift in Sources */, A6281993292DC825004B9117 /* XMTPiOSExampleApp.swift in Sources */, - A67CCEC129355B4B00131F5C /* AccountManager.swift in Sources */, - A687810E29679C0D00042FAB /* WalletConnectionMethod.swift in Sources */, A60FC8BF293AD054001697E3 /* MessageComposerView.swift in Sources */, A683860C293EA862006336FF /* MessageListView.swift in Sources */, A6D192D0293A7B97006B49F2 /* ConversationListView.swift in Sources */, diff --git a/XMTPiOSExample/XMTPiOSExample/Account/Account.swift b/XMTPiOSExample/XMTPiOSExample/Account/Account.swift deleted file mode 100644 index a0acfb79..00000000 --- a/XMTPiOSExample/XMTPiOSExample/Account/Account.swift +++ /dev/null @@ -1,58 +0,0 @@ -// -// Account.swift -// -// -// Created by Pat Nakajima on 11/22/22. -// -import Foundation -import XMTPiOS - -/// Wrapper around a WalletConnect V1 wallet connection. Account conforms to ``SigningKey`` so -/// you can use it to create a ``Client``. -/// -/// > Warning: The WalletConnect V1 API will be deprecated soon. -public struct Account { - var connection: WalletConnection - - public static func create() throws -> Account { - let connection = WCWalletConnection() - return try Account(connection: connection) - } - - init(connection: WalletConnection) throws { - self.connection = connection - } - - public var isConnected: Bool { - connection.isConnected - } - - public var address: String { - connection.walletAddress ?? "" - } - - public func preferredConnectionMethod() throws -> WalletConnectionMethodType { - try connection.preferredConnectionMethod() - } - - public func connect() async throws { - try await connection.connect() - } -} - -extension Account: SigningKey { - public func sign(_ data: Data) async throws -> Signature { - let signatureData = try await connection.sign(data) - - var signature = Signature() - - signature.ecdsaCompact.bytes = signatureData[0 ..< 64] - signature.ecdsaCompact.recovery = UInt32(signatureData[64]) - - return signature - } - - public func sign(message: String) async throws -> Signature { - return try await sign(Data(message.utf8)) - } -} diff --git a/XMTPiOSExample/XMTPiOSExample/Account/AccountManager.swift b/XMTPiOSExample/XMTPiOSExample/Account/AccountManager.swift deleted file mode 100644 index 9dd31539..00000000 --- a/XMTPiOSExample/XMTPiOSExample/Account/AccountManager.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// AccountManager.swift -// XMTPiOSExample -// -// Created by Pat Nakajima on 11/22/22. -// - -import Foundation -import XMTPiOS - -class AccountManager: ObservableObject { - var account: Account - - init() { - do { - account = try Account.create() - } catch { - fatalError("Account could not be created: \(error)") - } - } -} diff --git a/XMTPiOSExample/XMTPiOSExample/ContentView.swift b/XMTPiOSExample/XMTPiOSExample/ContentView.swift index 33e4de7f..d5fafb79 100644 --- a/XMTPiOSExample/XMTPiOSExample/ContentView.swift +++ b/XMTPiOSExample/XMTPiOSExample/ContentView.swift @@ -13,7 +13,6 @@ struct ContentView: View { case unknown, connecting, connected(Client), error(String) } - @StateObject var accountManager = AccountManager() @State private var status: Status = .unknown @@ -27,18 +26,6 @@ struct ContentView: View { VStack { switch status { case .unknown: - Button("Connect Wallet") { isConnectingWallet = true } - .sheet(isPresented: $isConnectingWallet) { - LoginView(onConnected: { client in - do { - self.status = .connected(client) - } catch { - print("Error setting up client: \(error)") - } - - print("Got a client: \(client)") - }) - } Button("Generate Wallet") { generateWallet() } Button("Load Saved Keys") { Task { diff --git a/XMTPiOSExample/XMTPiOSExample/Views/LoginView.swift b/XMTPiOSExample/XMTPiOSExample/Views/LoginView.swift deleted file mode 100644 index ebd27837..00000000 --- a/XMTPiOSExample/XMTPiOSExample/Views/LoginView.swift +++ /dev/null @@ -1,194 +0,0 @@ -// -// LoginView.swift -// XMTPChat -// -// Created by Pat Nakajima on 6/7/23. -// - -import SwiftUI -import Combine -import WebKit -import XMTPiOS -import WalletConnectRelay -import WalletConnectModal -import Starscream - -extension WebSocket: WebSocketConnecting { } -extension Blockchain: @unchecked Sendable { } - -struct SocketFactory: WebSocketFactory { - func create(with url: URL) -> WalletConnectRelay.WebSocketConnecting { - WebSocket(url: url) - } -} - -// WalletConnectV2's ModalSheet doesn't have any public initializers so we need -// to wrap their UIKit API -struct ModalWrapper: UIViewControllerRepresentable { - func makeUIViewController(context: Context) -> UIViewController { - let controller = UIViewController() - Task { - try? await Task.sleep(for: .seconds(0.4)) - await MainActor.run { - WalletConnectModal.present(from: controller) - } - } - return controller - } - - func updateUIViewController(_ uiViewController: UIViewController, context: Context) { - } -} - -// Conformance to XMTP iOS's SigningKey protocol -class Signer: SigningKey { - var account: WalletConnectUtils.Account - var session: WalletConnectSign.Session - - var address: String { - account.address - } - - init(session: WalletConnectSign.Session, account: WalletConnectUtils.Account) { - self.session = session - self.account = account - self.cancellable = Sign.instance.sessionResponsePublisher.sink { response in - guard case let .response(codable) = response.result else { - return - } - - // swiftlint:disable force_cast - let signatureData = Data(hexString: codable.value as! String) - // swiftlint:enable force_cast - let signature = Signature(bytes: signatureData[0..<64], recovery: Int(signatureData[64])) - - self.continuation?.resume(returning: signature) - self.continuation = nil - } - } - - var cancellable: AnyCancellable? - var continuation: CheckedContinuation? - - func sign(_ data: Data) async throws -> Signature { - let address = account.address - let topic = session.topic - let blockchain = account.blockchain - - return await withCheckedContinuation { continuation in - self.continuation = continuation - - Task { - let method = "personal_sign" - let walletAddress = address - let requestParams = AnyCodable([ - String(data: data, encoding: .utf8), - walletAddress - ]) - - let request = Request( - topic: topic, - method: method, - params: requestParams, - chainId: blockchain - ) - - try await Sign.instance.request(params: request) - } - } - } - - func sign(message: String) async throws -> Signature { - try await sign(Data(message.utf8)) - } -} - -struct LoginView: View { - var onConnected: (Client) -> Void - var publishers: [AnyCancellable] = [] - - @State private var isShowingWebview = true - // swiftlint:disable function_body_length - init( - onConnected: @escaping (Client) -> Void - ) { - self.onConnected = onConnected - - Networking.configure( - projectId: "YOUR PROJECT ID", - socketFactory: SocketFactory() - ) - - WalletConnectModal.configure( - projectId: "YOUR PROJECT ID", - metadata: .init( - name: "XMTP Chat", - description: "It's a chat app.", - url: "https://localhost:4567", - icons: [], - redirect: AppMetadata.Redirect( - native: "", - universal: nil - ) - ) - ) - - let requiredNamespaces: [String: ProposalNamespace] = [:] - let optionalNamespaces: [String: ProposalNamespace] = [ - "eip155": ProposalNamespace( - chains: [ - // swiftlint:disable force_unwrapping - Blockchain("eip155:80001")!, // Polygon Testnet - Blockchain("eip155:421613")! // Arbitrum Testnet - // swiftlint:enable force_unwrapping - ], - methods: [ - "personal_sign" - ], events: [] - ) - ] - - WalletConnectModal.set(sessionParams: .init( - requiredNamespaces: requiredNamespaces, - optionalNamespaces: optionalNamespaces, - sessionProperties: nil - )) - - Sign.instance.sessionSettlePublisher - .receive(on: DispatchQueue.main) - .sink { session in - guard let account = session.accounts.first else { return } - - Task(priority: .high) { - let signer = Signer(session: session, account: account) - let key = try secureRandomBytes(count: 32) - Persistence().saveKeys(key) - Persistence().saveAddress(signer.address) - let client = try await Client.create( - account: signer, - options: .init( - api: .init(env: .local, isSecure: false), - codecs: [GroupUpdatedCodec()], - dbEncryptionKey: key - ) - ) - - await MainActor.run { - onConnected(client) - } - } - - print("GOT AN ACCOUNT \(account)") - } - .store(in: &publishers) - } - // swiftlint:enable function_body_length - - var body: some View { - ModalWrapper() - } -} - -#Preview { - LoginView(onConnected: { _ in }) -} From 9050a6f29c16d198434bb887ad07a8aa10dbd9fa Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Tue, 19 Nov 2024 18:52:13 -0800 Subject: [PATCH 16/19] bump the proto --- .../Proto/message_contents/frames.pb.swift | 237 ++++++++++-------- 1 file changed, 128 insertions(+), 109 deletions(-) diff --git a/Sources/XMTPiOS/Proto/message_contents/frames.pb.swift b/Sources/XMTPiOS/Proto/message_contents/frames.pb.swift index 1e97f05d..0dcfda1e 100644 --- a/Sources/XMTPiOS/Proto/message_contents/frames.pb.swift +++ b/Sources/XMTPiOS/Proto/message_contents/frames.pb.swift @@ -1,5 +1,6 @@ // DO NOT EDIT. // swift-format-ignore-file +// swiftlint:disable all // // Generated by the Swift generator plugin for the protocol buffer compiler. // Source: message_contents/frames.proto @@ -24,7 +25,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// The message that will be signed by the Client and returned inside the /// `action_body` field of the FrameAction message -public struct Xmtp_MessageContents_FrameActionBody { +public struct Xmtp_MessageContents_FrameActionBody: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -37,6 +38,8 @@ public struct Xmtp_MessageContents_FrameActionBody { public var buttonIndex: Int32 = 0 /// Timestamp of the click in milliseconds since the epoch + /// + /// NOTE: This field was marked as deprecated in the .proto file. public var timestamp: UInt64 = 0 /// A unique identifier for the conversation, not tied to anything on the @@ -65,14 +68,15 @@ public struct Xmtp_MessageContents_FrameActionBody { /// The outer payload that will be sent as the `messageBytes` in the /// `trusted_data` part of the Frames message -public struct Xmtp_MessageContents_FrameAction { +public struct Xmtp_MessageContents_FrameAction: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. + /// NOTE: This field was marked as deprecated in the .proto file. public var signature: Xmtp_MessageContents_Signature { - get {return _signature ?? Xmtp_MessageContents_Signature()} - set {_signature = newValue} + get {return _signature ?? Xmtp_MessageContents_Signature()} + set {_signature = newValue} } /// Returns true if `signature` has been explicitly set. public var hasSignature: Bool {return self._signature != nil} @@ -81,9 +85,11 @@ public struct Xmtp_MessageContents_FrameAction { /// The SignedPublicKeyBundle of the signer, used to link the XMTP signature /// with a blockchain account through a chain of signatures. + /// + /// NOTE: This field was marked as deprecated in the .proto file. public var signedPublicKeyBundle: Xmtp_MessageContents_SignedPublicKeyBundle { - get {return _signedPublicKeyBundle ?? Xmtp_MessageContents_SignedPublicKeyBundle()} - set {_signedPublicKeyBundle = newValue} + get {return _signedPublicKeyBundle ?? Xmtp_MessageContents_SignedPublicKeyBundle()} + set {_signedPublicKeyBundle = newValue} } /// Returns true if `signedPublicKeyBundle` has been explicitly set. public var hasSignedPublicKeyBundle: Bool {return self._signedPublicKeyBundle != nil} @@ -94,6 +100,12 @@ public struct Xmtp_MessageContents_FrameAction { /// happen on a byte-perfect representation of the message public var actionBody: Data = Data() + /// The installation signature + public var installationSignature: Data = Data() + + /// The public installation id used to sign. + public var installationID: Data = Data() + public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} @@ -102,11 +114,6 @@ public struct Xmtp_MessageContents_FrameAction { fileprivate var _signedPublicKeyBundle: Xmtp_MessageContents_SignedPublicKeyBundle? = nil } -#if swift(>=5.5) && canImport(_Concurrency) -extension Xmtp_MessageContents_FrameActionBody: @unchecked Sendable {} -extension Xmtp_MessageContents_FrameAction: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "xmtp.message_contents" @@ -114,127 +121,139 @@ fileprivate let _protobuf_package = "xmtp.message_contents" extension Xmtp_MessageContents_FrameActionBody: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".FrameActionBody" public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .standard(proto: "frame_url"), - 2: .standard(proto: "button_index"), - 3: .same(proto: "timestamp"), - 4: .standard(proto: "opaque_conversation_identifier"), - 5: .standard(proto: "unix_timestamp"), - 6: .standard(proto: "input_text"), - 7: .same(proto: "state"), - 8: .same(proto: "address"), - 9: .standard(proto: "transaction_id"), + 1: .standard(proto: "frame_url"), + 2: .standard(proto: "button_index"), + 3: .same(proto: "timestamp"), + 4: .standard(proto: "opaque_conversation_identifier"), + 5: .standard(proto: "unix_timestamp"), + 6: .standard(proto: "input_text"), + 7: .same(proto: "state"), + 8: .same(proto: "address"), + 9: .standard(proto: "transaction_id"), ] public mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeSingularStringField(value: &self.frameURL) }() - case 2: try { try decoder.decodeSingularInt32Field(value: &self.buttonIndex) }() - case 3: try { try decoder.decodeSingularUInt64Field(value: &self.timestamp) }() - case 4: try { try decoder.decodeSingularStringField(value: &self.opaqueConversationIdentifier) }() - case 5: try { try decoder.decodeSingularUInt32Field(value: &self.unixTimestamp) }() - case 6: try { try decoder.decodeSingularStringField(value: &self.inputText) }() - case 7: try { try decoder.decodeSingularStringField(value: &self.state) }() - case 8: try { try decoder.decodeSingularStringField(value: &self.address) }() - case 9: try { try decoder.decodeSingularStringField(value: &self.transactionID) }() - default: break - } - } + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularStringField(value: &self.frameURL) }() + case 2: try { try decoder.decodeSingularInt32Field(value: &self.buttonIndex) }() + case 3: try { try decoder.decodeSingularUInt64Field(value: &self.timestamp) }() + case 4: try { try decoder.decodeSingularStringField(value: &self.opaqueConversationIdentifier) }() + case 5: try { try decoder.decodeSingularUInt32Field(value: &self.unixTimestamp) }() + case 6: try { try decoder.decodeSingularStringField(value: &self.inputText) }() + case 7: try { try decoder.decodeSingularStringField(value: &self.state) }() + case 8: try { try decoder.decodeSingularStringField(value: &self.address) }() + case 9: try { try decoder.decodeSingularStringField(value: &self.transactionID) }() + default: break + } + } } public func traverse(visitor: inout V) throws { - if !self.frameURL.isEmpty { - try visitor.visitSingularStringField(value: self.frameURL, fieldNumber: 1) - } - if self.buttonIndex != 0 { - try visitor.visitSingularInt32Field(value: self.buttonIndex, fieldNumber: 2) - } - if self.timestamp != 0 { - try visitor.visitSingularUInt64Field(value: self.timestamp, fieldNumber: 3) - } - if !self.opaqueConversationIdentifier.isEmpty { - try visitor.visitSingularStringField(value: self.opaqueConversationIdentifier, fieldNumber: 4) - } - if self.unixTimestamp != 0 { - try visitor.visitSingularUInt32Field(value: self.unixTimestamp, fieldNumber: 5) - } - if !self.inputText.isEmpty { - try visitor.visitSingularStringField(value: self.inputText, fieldNumber: 6) - } - if !self.state.isEmpty { - try visitor.visitSingularStringField(value: self.state, fieldNumber: 7) - } - if !self.address.isEmpty { - try visitor.visitSingularStringField(value: self.address, fieldNumber: 8) - } - if !self.transactionID.isEmpty { - try visitor.visitSingularStringField(value: self.transactionID, fieldNumber: 9) - } - try unknownFields.traverse(visitor: &visitor) + if !self.frameURL.isEmpty { + try visitor.visitSingularStringField(value: self.frameURL, fieldNumber: 1) + } + if self.buttonIndex != 0 { + try visitor.visitSingularInt32Field(value: self.buttonIndex, fieldNumber: 2) + } + if self.timestamp != 0 { + try visitor.visitSingularUInt64Field(value: self.timestamp, fieldNumber: 3) + } + if !self.opaqueConversationIdentifier.isEmpty { + try visitor.visitSingularStringField(value: self.opaqueConversationIdentifier, fieldNumber: 4) + } + if self.unixTimestamp != 0 { + try visitor.visitSingularUInt32Field(value: self.unixTimestamp, fieldNumber: 5) + } + if !self.inputText.isEmpty { + try visitor.visitSingularStringField(value: self.inputText, fieldNumber: 6) + } + if !self.state.isEmpty { + try visitor.visitSingularStringField(value: self.state, fieldNumber: 7) + } + if !self.address.isEmpty { + try visitor.visitSingularStringField(value: self.address, fieldNumber: 8) + } + if !self.transactionID.isEmpty { + try visitor.visitSingularStringField(value: self.transactionID, fieldNumber: 9) + } + try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Xmtp_MessageContents_FrameActionBody, rhs: Xmtp_MessageContents_FrameActionBody) -> Bool { - if lhs.frameURL != rhs.frameURL {return false} - if lhs.buttonIndex != rhs.buttonIndex {return false} - if lhs.timestamp != rhs.timestamp {return false} - if lhs.opaqueConversationIdentifier != rhs.opaqueConversationIdentifier {return false} - if lhs.unixTimestamp != rhs.unixTimestamp {return false} - if lhs.inputText != rhs.inputText {return false} - if lhs.state != rhs.state {return false} - if lhs.address != rhs.address {return false} - if lhs.transactionID != rhs.transactionID {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true + if lhs.frameURL != rhs.frameURL {return false} + if lhs.buttonIndex != rhs.buttonIndex {return false} + if lhs.timestamp != rhs.timestamp {return false} + if lhs.opaqueConversationIdentifier != rhs.opaqueConversationIdentifier {return false} + if lhs.unixTimestamp != rhs.unixTimestamp {return false} + if lhs.inputText != rhs.inputText {return false} + if lhs.state != rhs.state {return false} + if lhs.address != rhs.address {return false} + if lhs.transactionID != rhs.transactionID {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true } } extension Xmtp_MessageContents_FrameAction: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { public static let protoMessageName: String = _protobuf_package + ".FrameAction" public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ - 1: .same(proto: "signature"), - 2: .standard(proto: "signed_public_key_bundle"), - 3: .standard(proto: "action_body"), + 1: .same(proto: "signature"), + 2: .standard(proto: "signed_public_key_bundle"), + 3: .standard(proto: "action_body"), + 4: .standard(proto: "installation_signature"), + 5: .standard(proto: "installation_id"), ] public mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeSingularMessageField(value: &self._signature) }() - case 2: try { try decoder.decodeSingularMessageField(value: &self._signedPublicKeyBundle) }() - case 3: try { try decoder.decodeSingularBytesField(value: &self.actionBody) }() - default: break - } - } + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularMessageField(value: &self._signature) }() + case 2: try { try decoder.decodeSingularMessageField(value: &self._signedPublicKeyBundle) }() + case 3: try { try decoder.decodeSingularBytesField(value: &self.actionBody) }() + case 4: try { try decoder.decodeSingularBytesField(value: &self.installationSignature) }() + case 5: try { try decoder.decodeSingularBytesField(value: &self.installationID) }() + default: break + } + } } public func traverse(visitor: inout V) throws { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every if/case branch local when no optimizations - // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and - // https://github.com/apple/swift-protobuf/issues/1182 - try { if let v = self._signature { - try visitor.visitSingularMessageField(value: v, fieldNumber: 1) - } }() - try { if let v = self._signedPublicKeyBundle { - try visitor.visitSingularMessageField(value: v, fieldNumber: 2) - } }() - if !self.actionBody.isEmpty { - try visitor.visitSingularBytesField(value: self.actionBody, fieldNumber: 3) - } - try unknownFields.traverse(visitor: &visitor) + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + try { if let v = self._signature { + try visitor.visitSingularMessageField(value: v, fieldNumber: 1) + } }() + try { if let v = self._signedPublicKeyBundle { + try visitor.visitSingularMessageField(value: v, fieldNumber: 2) + } }() + if !self.actionBody.isEmpty { + try visitor.visitSingularBytesField(value: self.actionBody, fieldNumber: 3) + } + if !self.installationSignature.isEmpty { + try visitor.visitSingularBytesField(value: self.installationSignature, fieldNumber: 4) + } + if !self.installationID.isEmpty { + try visitor.visitSingularBytesField(value: self.installationID, fieldNumber: 5) + } + try unknownFields.traverse(visitor: &visitor) } public static func ==(lhs: Xmtp_MessageContents_FrameAction, rhs: Xmtp_MessageContents_FrameAction) -> Bool { - if lhs._signature != rhs._signature {return false} - if lhs._signedPublicKeyBundle != rhs._signedPublicKeyBundle {return false} - if lhs.actionBody != rhs.actionBody {return false} - if lhs.unknownFields != rhs.unknownFields {return false} - return true + if lhs._signature != rhs._signature {return false} + if lhs._signedPublicKeyBundle != rhs._signedPublicKeyBundle {return false} + if lhs.actionBody != rhs.actionBody {return false} + if lhs.installationSignature != rhs.installationSignature {return false} + if lhs.installationID != rhs.installationID {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true } } From a441bed2f21e51871b39a923cec0f61f6ba2da49 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Tue, 19 Nov 2024 18:56:25 -0800 Subject: [PATCH 17/19] bring back all the frames code --- Sources/XMTPiOS/Frames/FramesClient.swift | 108 ++++++++++++ Sources/XMTPiOS/Frames/FramesConstants.swift | 12 ++ Sources/XMTPiOS/Frames/FramesTypes.swift | 165 +++++++++++++++++++ Sources/XMTPiOS/Frames/OpenFramesProxy.swift | 38 +++++ Sources/XMTPiOS/Frames/ProxyClient.swift | 97 +++++++++++ Tests/XMTPTests/FramesTests.swift | 62 +++++++ 6 files changed, 482 insertions(+) create mode 100644 Sources/XMTPiOS/Frames/FramesClient.swift create mode 100644 Sources/XMTPiOS/Frames/FramesConstants.swift create mode 100644 Sources/XMTPiOS/Frames/FramesTypes.swift create mode 100644 Sources/XMTPiOS/Frames/OpenFramesProxy.swift create mode 100644 Sources/XMTPiOS/Frames/ProxyClient.swift create mode 100644 Tests/XMTPTests/FramesTests.swift diff --git a/Sources/XMTPiOS/Frames/FramesClient.swift b/Sources/XMTPiOS/Frames/FramesClient.swift new file mode 100644 index 00000000..f912c4fe --- /dev/null +++ b/Sources/XMTPiOS/Frames/FramesClient.swift @@ -0,0 +1,108 @@ +// +// FramesClient.swift +// +// +// Created by Alex Risch on 3/28/24. +// + +import Foundation +import LibXMTP + +public typealias FrameActionBody = Xmtp_MessageContents_FrameActionBody +public typealias FrameAction = Xmtp_MessageContents_FrameAction + +enum FramesClientError: Error { + case missingConversationTopic + case missingTarget + case readMetadataFailed(message: String, code: Int) + case postFrameFailed(message: String, code: Int) +} + +public class FramesClient { + var xmtpClient: Client + public var proxy: OpenFramesProxy + + public init(xmtpClient: Client, proxy: OpenFramesProxy? = nil) { + self.xmtpClient = xmtpClient + self.proxy = proxy ?? OpenFramesProxy() + } + + public func signFrameAction(inputs: FrameActionInputs) async throws -> FramePostPayload { + let opaqueConversationIdentifier = try self.buildOpaqueIdentifier(inputs: inputs) + let frameUrl = inputs.frameUrl + let buttonIndex = inputs.buttonIndex + let inputText = inputs.inputText ?? "" + let state = inputs.state ?? "" + let now = Date().timeIntervalSince1970 + let timestamp = now + + var toSign = FrameActionBody() + toSign.frameURL = frameUrl + toSign.buttonIndex = buttonIndex + toSign.opaqueConversationIdentifier = opaqueConversationIdentifier + toSign.timestamp = UInt64(timestamp) + toSign.inputText = inputText + toSign.unixTimestamp = UInt32(now) + toSign.state = state + + let signedAction = try await self.buildSignedFrameAction(actionBodyInputs: toSign) + + let untrustedData = FramePostUntrustedData( + url: frameUrl, timestamp: UInt64(now), buttonIndex: buttonIndex, inputText: inputText, state: state, walletAddress: self.xmtpClient.address, opaqueConversationIdentifier: opaqueConversationIdentifier, unixTimestamp: UInt32(now) + ) + + + let trustedData = FramePostTrustedData(messageBytes: signedAction.base64EncodedString()) + + let payload = FramePostPayload( + clientProtocol: "xmtp@\(PROTOCOL_VERSION)", untrustedData: untrustedData, trustedData: trustedData + ) + + return payload + } + + private func signDigest(digest: Data) async throws -> Signature { + let key = try self.xmtpClient.keys.identityKey + let privateKey = try PrivateKey(key) + let signature = try await privateKey.sign(Data(digest)) + return signature + } + + private func getPublicKeyBundle() async throws -> PublicKeyBundle { + let bundleBytes = try self.xmtpClient.publicKeyBundle; + return try PublicKeyBundle(bundleBytes); + } + + private func buildSignedFrameAction(actionBodyInputs: FrameActionBody) async throws -> Data { + + let digest = sha256(input: try actionBodyInputs.serializedData()) + let signature = try await self.signDigest(digest: digest) + + let publicKeyBundle = try await self.getPublicKeyBundle() + var frameAction = FrameAction() + frameAction.actionBody = try actionBodyInputs.serializedData() + frameAction.signature = signature + frameAction.signedPublicKeyBundle = try SignedPublicKeyBundle(publicKeyBundle) + + return try frameAction.serializedData() + } + + private func buildOpaqueIdentifier(inputs: FrameActionInputs) throws -> String { + switch inputs.conversationInputs { + case .group(let groupInputs): + let combined = groupInputs.groupId + groupInputs.groupSecret + let digest = sha256(input: combined) + return digest.base64EncodedString() + case .dm(let dmInputs): + guard let conversationTopic = dmInputs.conversationTopic else { + throw FramesClientError.missingConversationTopic + } + guard let combined = (conversationTopic.lowercased() + dmInputs.participantAccountAddresses.map { $0.lowercased() }.sorted().joined()).data(using: .utf8) else { + throw FramesClientError.missingConversationTopic + } + let digest = sha256(input: combined) + return digest.base64EncodedString() + } + } + +} diff --git a/Sources/XMTPiOS/Frames/FramesConstants.swift b/Sources/XMTPiOS/Frames/FramesConstants.swift new file mode 100644 index 00000000..192c4ab3 --- /dev/null +++ b/Sources/XMTPiOS/Frames/FramesConstants.swift @@ -0,0 +1,12 @@ +// +// File.swift +// +// +// Created by Alex Risch on 3/28/24. +// + +import Foundation + +let OPEN_FRAMES_PROXY_URL = "https://frames.xmtp.chat/" + +let PROTOCOL_VERSION = "2024-02-09" diff --git a/Sources/XMTPiOS/Frames/FramesTypes.swift b/Sources/XMTPiOS/Frames/FramesTypes.swift new file mode 100644 index 00000000..11bd29a8 --- /dev/null +++ b/Sources/XMTPiOS/Frames/FramesTypes.swift @@ -0,0 +1,165 @@ +// +// File.swift +// +// +// Created by Alex Risch on 3/28/24. +// + +import Foundation + +typealias AcceptedFrameClients = [String: String] + +enum OpenFrameButton: Codable { + case link(target: String, label: String) + case mint(target: String, label: String) + case post(target: String?, label: String) + case postRedirect(target: String?, label: String) + + enum CodingKeys: CodingKey { + case action, target, label + } + + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + let action = try container.decode(String.self, forKey: .action) + guard let target = try container.decodeIfPresent(String.self, forKey: .target) else { + throw FramesClientError.missingTarget + } + let label = try container.decode(String.self, forKey: .label) + + switch action { + case "link": + self = .link(target: target, label: label) + case "mint": + self = .mint(target: target, label: label) + case "post": + self = .post(target: target, label: label) + case "post_redirect": + self = .postRedirect(target: target, label: label) + default: + throw DecodingError.dataCorruptedError(forKey: .action, in: container, debugDescription: "Invalid action value") + } + } + + func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + switch self { + case .link(let target, let label): + try container.encode("link", forKey: .action) + try container.encode(target, forKey: .target) + try container.encode(label, forKey: .label) + case .mint(let target, let label): + try container.encode("mint", forKey: .action) + try container.encode(target, forKey: .target) + try container.encode(label, forKey: .label) + case .post(let target, let label): + try container.encode("post", forKey: .action) + try container.encode(target, forKey: .target) + try container.encode(label, forKey: .label) + case .postRedirect(let target, let label): + try container.encode("post_redirect", forKey: .action) + try container.encode(target, forKey: .target) + try container.encode(label, forKey: .label) + } + } +} + +public struct OpenFrameImage: Codable { + let content: String + let aspectRatio: AspectRatio? + let alt: String? +} + +public enum AspectRatio: String, Codable { + case ratio_1_91_1 = "1.91.1" + case ratio_1_1 = "1:1" +} + +public struct TextInput: Codable { + let content: String +} + +struct OpenFrameResult: Codable { + let acceptedClients: AcceptedFrameClients + let image: OpenFrameImage + let postUrl: String? + let textInput: TextInput? + let buttons: [String: OpenFrameButton]? + let ogImage: String + let state: String? +}; + +public struct GetMetadataResponse: Codable { + let url: String + public let extractedTags: [String: String] +} + +public struct PostRedirectResponse: Codable { + let originalUrl: String + let redirectedTo: String +}; + +public struct OpenFramesUntrustedData: Codable { + let url: String + let timestamp: Int + let buttonIndex: Int + let inputText: String? + let state: String? +} + +public typealias FramesApiRedirectResponse = PostRedirectResponse; + +public struct FramePostUntrustedData: Codable { + let url: String + let timestamp: UInt64 + let buttonIndex: Int32 + let inputText: String? + let state: String? + let walletAddress: String + let opaqueConversationIdentifier: String + let unixTimestamp: UInt32 +} + +public struct FramePostTrustedData: Codable { + let messageBytes: String +} + +public struct FramePostPayload: Codable { + let clientProtocol: String + let untrustedData: FramePostUntrustedData + let trustedData: FramePostTrustedData +} + +public struct DmActionInputs: Codable { + public let conversationTopic: String? + public let participantAccountAddresses: [String] + public init(conversationTopic: String? = nil, participantAccountAddresses: [String]) { + self.conversationTopic = conversationTopic + self.participantAccountAddresses = participantAccountAddresses + } +} + +public struct GroupActionInputs: Codable { + let groupId: Data + let groupSecret: Data +} + +public enum ConversationActionInputs: Codable { + case dm(DmActionInputs) + case group(GroupActionInputs) +} + +public struct FrameActionInputs: Codable { + let frameUrl: String + let buttonIndex: Int32 + let inputText: String? + let state: String? + let conversationInputs: ConversationActionInputs + public init(frameUrl: String, buttonIndex: Int32, inputText: String?, state: String?, conversationInputs: ConversationActionInputs) { + self.frameUrl = frameUrl + self.buttonIndex = buttonIndex + self.inputText = inputText + self.state = state + self.conversationInputs = conversationInputs + } +} diff --git a/Sources/XMTPiOS/Frames/OpenFramesProxy.swift b/Sources/XMTPiOS/Frames/OpenFramesProxy.swift new file mode 100644 index 00000000..22ea3f83 --- /dev/null +++ b/Sources/XMTPiOS/Frames/OpenFramesProxy.swift @@ -0,0 +1,38 @@ +// +// File.swift +// +// +// Created by Alex Risch on 3/28/24. +// + +import Foundation + +public class OpenFramesProxy { + let inner: ProxyClient + + init(baseUrl: String = OPEN_FRAMES_PROXY_URL) { + self.inner = ProxyClient(baseUrl: baseUrl); + } + + public func readMetadata(url: String) async throws -> GetMetadataResponse { + return try await self.inner.readMetadata(url: url); + } + + public func post(url: String, payload: FramePostPayload) async throws -> GetMetadataResponse { + return try await self.inner.post(url: url, payload: payload); + } + + public func postRedirect( + url: String, + payload: FramePostPayload + ) async throws -> FramesApiRedirectResponse { + return try await self.inner.postRedirect(url: url, payload: payload); + } + + public func mediaUrl(url: String) async throws -> String { + if url.hasPrefix("data:") { + return url + } + return self.inner.mediaUrl(url: url); + } +} diff --git a/Sources/XMTPiOS/Frames/ProxyClient.swift b/Sources/XMTPiOS/Frames/ProxyClient.swift new file mode 100644 index 00000000..332dea21 --- /dev/null +++ b/Sources/XMTPiOS/Frames/ProxyClient.swift @@ -0,0 +1,97 @@ +// +// File.swift +// +// +// Created by Alex Risch on 3/28/24. +// + +import Foundation + +struct Metadata: Codable { + let title: String + let description: String + let imageUrl: String +} + +class ProxyClient { + var baseUrl: String + + init(baseUrl: String) { + self.baseUrl = baseUrl + } + + func readMetadata(url: String) async throws -> GetMetadataResponse { + let encodedUrl = url.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "" + let fullUrl = "\(self.baseUrl)?url=\(encodedUrl)" + guard let url = URL(string: fullUrl) else { + throw URLError(.badURL) + } + + let (data, response) = try await URLSession.shared.data(from: url) + guard let httpResponse = response as? HTTPURLResponse else { + throw URLError(.badServerResponse) + } + + guard httpResponse.statusCode == 200 else { + throw FramesClientError.readMetadataFailed(message: "Failed to read metadata for \(url)", code: httpResponse.statusCode) + } + + let decoder = JSONDecoder() + let metadataResponse: GetMetadataResponse = try decoder.decode(GetMetadataResponse.self, from: data) + return metadataResponse + } + + func post(url: String, payload: Codable) async throws -> GetMetadataResponse { + let encodedUrl = url.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "" + let fullUrl = "\(self.baseUrl)?url=\(encodedUrl)" + guard let url = URL(string: fullUrl) else { + throw URLError(.badURL) + } + let encoder = JSONEncoder() + var request = URLRequest(url: url) + request.httpMethod = "POST" + request.setValue("application/json", forHTTPHeaderField: "Content-Type") + request.httpBody = try encoder.encode(payload) + + let (data, response) = try await URLSession.shared.data(for: request) + guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else { + throw URLError(.badServerResponse) + } + + let decoder = JSONDecoder() + let metadataResponse = try decoder.decode(GetMetadataResponse.self, from: data) + return metadataResponse + } + + func postRedirect(url: String, payload: Codable) async throws -> PostRedirectResponse { + let encodedUrl = url.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "" + let fullUrl = "\(self.baseUrl)redirect?url=\(encodedUrl)" + guard let url = URL(string: fullUrl) else { + throw URLError(.badURL) + } + + var request = URLRequest(url: url) + request.httpMethod = "POST" + request.setValue("application/json", forHTTPHeaderField: "Content-Type") + request.httpBody = try JSONSerialization.data(withJSONObject: payload) + + let (data, response) = try await URLSession.shared.data(for: request) + guard let httpResponse = response as? HTTPURLResponse else { + throw URLError(.badServerResponse) + } + + guard httpResponse.statusCode == 200 else { + throw FramesClientError.postFrameFailed(message: "Failed to post to frame \(url)", code: httpResponse.statusCode) + } + + let decoder = JSONDecoder() + let postRedirectResponse = try decoder.decode(PostRedirectResponse.self, from: data) + return postRedirectResponse + } + + func mediaUrl(url: String) -> String { + let encodedUrl = url.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "" + let result = "\(self.baseUrl)media?url=\(encodedUrl)" + return result + } +} diff --git a/Tests/XMTPTests/FramesTests.swift b/Tests/XMTPTests/FramesTests.swift new file mode 100644 index 00000000..99b9143b --- /dev/null +++ b/Tests/XMTPTests/FramesTests.swift @@ -0,0 +1,62 @@ +// +// FramesTests.swift +// +// +// Created by Alex Risch on 4/1/24. +// + +import Foundation +import XCTest +@testable import XMTPiOS + +final class FramesTests: XCTestCase { + func testInstantiateFramesClient() async throws { + let frameUrl = "https://fc-polls-five.vercel.app/polls/01032f47-e976-42ee-9e3d-3aac1324f4b8" + + let key = try Crypto.secureRandomBytes(count: 32) + let bo = try PrivateKey.generate() + let client = try await Client.create( + account: bo, + options: .init( + api: .init(env: .local, isSecure: false), + enableV3: true, + encryptionKey: key + ) + ) + + let framesClient = FramesClient(xmtpClient: client) + let metadata = try await framesClient.proxy.readMetadata(url: frameUrl) + let conversationTopic = "foo" + let participantAccountAddresses = ["amal", "bola"] + let dmInputs = DmActionInputs( + conversationTopic: conversationTopic, participantAccountAddresses: participantAccountAddresses) + let conversationInputs = ConversationActionInputs.dm(dmInputs) + let frameInputs = FrameActionInputs(frameUrl: frameUrl, buttonIndex: 1, inputText: nil, state: nil, conversationInputs: conversationInputs) + let signedPayload = try await framesClient.signFrameAction(inputs: frameInputs) + + guard let postUrl = metadata.extractedTags["fc:frame:post_url"] else { + throw NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "postUrl should exist"]) + } + let response = try await framesClient.proxy.post(url: postUrl, payload: signedPayload) + + guard response.extractedTags["fc:frame"] == "vNext" else { + throw NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "response should have expected extractedTags"]) + } + + guard let imageUrl = response.extractedTags["fc:frame:image"] else { + throw NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "imageUrl should exist"]) + } + + let mediaUrl = try await framesClient.proxy.mediaUrl(url: imageUrl) + + let (_, mediaResponse) = try await URLSession.shared.data(from: URL(string: mediaUrl)!) + + guard (mediaResponse as? HTTPURLResponse)?.statusCode == 200 else { + throw NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "downloadedMedia should be ok"]) + } + + guard (mediaResponse as? HTTPURLResponse)?.mimeType == "image/png" else { + throw NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "downloadedMedia should be image/png"]) + } + } +} From 4e235845316083815a0d5a264dad115d2667f550 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Wed, 20 Nov 2024 10:07:43 -0800 Subject: [PATCH 18/19] update the signer --- Sources/XMTPiOS/Frames/FramesClient.swift | 73 +++++++++++++---------- Tests/XMTPTests/FramesTests.swift | 3 +- 2 files changed, 42 insertions(+), 34 deletions(-) diff --git a/Sources/XMTPiOS/Frames/FramesClient.swift b/Sources/XMTPiOS/Frames/FramesClient.swift index f912c4fe..903ef7ad 100644 --- a/Sources/XMTPiOS/Frames/FramesClient.swift +++ b/Sources/XMTPiOS/Frames/FramesClient.swift @@ -27,8 +27,11 @@ public class FramesClient { self.proxy = proxy ?? OpenFramesProxy() } - public func signFrameAction(inputs: FrameActionInputs) async throws -> FramePostPayload { - let opaqueConversationIdentifier = try self.buildOpaqueIdentifier(inputs: inputs) + public func signFrameAction(inputs: FrameActionInputs) async throws + -> FramePostPayload + { + let opaqueConversationIdentifier = try self.buildOpaqueIdentifier( + inputs: inputs) let frameUrl = inputs.frameUrl let buttonIndex = inputs.buttonIndex let inputText = inputs.inputText ?? "" @@ -39,55 +42,55 @@ public class FramesClient { var toSign = FrameActionBody() toSign.frameURL = frameUrl toSign.buttonIndex = buttonIndex - toSign.opaqueConversationIdentifier = opaqueConversationIdentifier + toSign.opaqueConversationIdentifier = opaqueConversationIdentifier toSign.timestamp = UInt64(timestamp) toSign.inputText = inputText toSign.unixTimestamp = UInt32(now) toSign.state = state - let signedAction = try await self.buildSignedFrameAction(actionBodyInputs: toSign) + let signedAction = try await self.buildSignedFrameAction( + actionBodyInputs: toSign) let untrustedData = FramePostUntrustedData( - url: frameUrl, timestamp: UInt64(now), buttonIndex: buttonIndex, inputText: inputText, state: state, walletAddress: self.xmtpClient.address, opaqueConversationIdentifier: opaqueConversationIdentifier, unixTimestamp: UInt32(now) + url: frameUrl, timestamp: UInt64(now), buttonIndex: buttonIndex, + inputText: inputText, state: state, + walletAddress: self.xmtpClient.address, + opaqueConversationIdentifier: opaqueConversationIdentifier, + unixTimestamp: UInt32(now) ) - - let trustedData = FramePostTrustedData(messageBytes: signedAction.base64EncodedString()) + let trustedData = FramePostTrustedData( + messageBytes: signedAction.base64EncodedString()) let payload = FramePostPayload( - clientProtocol: "xmtp@\(PROTOCOL_VERSION)", untrustedData: untrustedData, trustedData: trustedData + clientProtocol: "xmtp@\(PROTOCOL_VERSION)", + untrustedData: untrustedData, trustedData: trustedData ) return payload } - - private func signDigest(digest: Data) async throws -> Signature { - let key = try self.xmtpClient.keys.identityKey - let privateKey = try PrivateKey(key) - let signature = try await privateKey.sign(Data(digest)) - return signature + + private func signDigest(message: String) async throws -> Data { + return try self.xmtpClient.signWithInstallationKey(message: message) } - - private func getPublicKeyBundle() async throws -> PublicKeyBundle { - let bundleBytes = try self.xmtpClient.publicKeyBundle; - return try PublicKeyBundle(bundleBytes); - } - - private func buildSignedFrameAction(actionBodyInputs: FrameActionBody) async throws -> Data { - - let digest = sha256(input: try actionBodyInputs.serializedData()) - let signature = try await self.signDigest(digest: digest) - - let publicKeyBundle = try await self.getPublicKeyBundle() + + private func buildSignedFrameAction(actionBodyInputs: FrameActionBody) + async throws -> Data + { + let digest = sha256(input: try actionBodyInputs.serializedData()).toHex + let signature = try await self.signDigest(message: digest) + var frameAction = FrameAction() frameAction.actionBody = try actionBodyInputs.serializedData() - frameAction.signature = signature - frameAction.signedPublicKeyBundle = try SignedPublicKeyBundle(publicKeyBundle) - + frameAction.installationSignature = signature + frameAction.installationID = self.xmtpClient.installationID.hexToData + return try frameAction.serializedData() } - - private func buildOpaqueIdentifier(inputs: FrameActionInputs) throws -> String { + + private func buildOpaqueIdentifier(inputs: FrameActionInputs) throws + -> String + { switch inputs.conversationInputs { case .group(let groupInputs): let combined = groupInputs.groupId + groupInputs.groupSecret @@ -97,7 +100,13 @@ public class FramesClient { guard let conversationTopic = dmInputs.conversationTopic else { throw FramesClientError.missingConversationTopic } - guard let combined = (conversationTopic.lowercased() + dmInputs.participantAccountAddresses.map { $0.lowercased() }.sorted().joined()).data(using: .utf8) else { + guard + let combined = + (conversationTopic.lowercased() + + dmInputs.participantAccountAddresses.map { + $0.lowercased() + }.sorted().joined()).data(using: .utf8) + else { throw FramesClientError.missingConversationTopic } let digest = sha256(input: combined) diff --git a/Tests/XMTPTests/FramesTests.swift b/Tests/XMTPTests/FramesTests.swift index 99b9143b..dcb26fb5 100644 --- a/Tests/XMTPTests/FramesTests.swift +++ b/Tests/XMTPTests/FramesTests.swift @@ -19,8 +19,7 @@ final class FramesTests: XCTestCase { account: bo, options: .init( api: .init(env: .local, isSecure: false), - enableV3: true, - encryptionKey: key + dbEncryptionKey: key ) ) From c819afcb1405add7b86cf3de0ce2a0cae28f9054 Mon Sep 17 00:00:00 2001 From: Naomi Plasterer Date: Wed, 27 Nov 2024 20:18:28 -0800 Subject: [PATCH 19/19] update the protos --- Sources/XMTPiOS/Frames/FramesClient.swift | 1 + Sources/XMTPiOS/Proto/message_contents/frames.pb.swift | 9 +++++++++ Tests/XMTPTests/FramesTests.swift | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Sources/XMTPiOS/Frames/FramesClient.swift b/Sources/XMTPiOS/Frames/FramesClient.swift index 903ef7ad..3ac719d9 100644 --- a/Sources/XMTPiOS/Frames/FramesClient.swift +++ b/Sources/XMTPiOS/Frames/FramesClient.swift @@ -84,6 +84,7 @@ public class FramesClient { frameAction.actionBody = try actionBodyInputs.serializedData() frameAction.installationSignature = signature frameAction.installationID = self.xmtpClient.installationID.hexToData + frameAction.inboxID = self.xmtpClient.inboxID return try frameAction.serializedData() } diff --git a/Sources/XMTPiOS/Proto/message_contents/frames.pb.swift b/Sources/XMTPiOS/Proto/message_contents/frames.pb.swift index 0dcfda1e..511ee371 100644 --- a/Sources/XMTPiOS/Proto/message_contents/frames.pb.swift +++ b/Sources/XMTPiOS/Proto/message_contents/frames.pb.swift @@ -106,6 +106,9 @@ public struct Xmtp_MessageContents_FrameAction: @unchecked Sendable { /// The public installation id used to sign. public var installationID: Data = Data() + /// The inbox id of the installation used to sign. + public var inboxID: String = String() + public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} @@ -206,6 +209,7 @@ extension Xmtp_MessageContents_FrameAction: SwiftProtobuf.Message, SwiftProtobuf 3: .standard(proto: "action_body"), 4: .standard(proto: "installation_signature"), 5: .standard(proto: "installation_id"), + 6: .standard(proto: "inbox_id"), ] public mutating func decodeMessage(decoder: inout D) throws { @@ -219,6 +223,7 @@ extension Xmtp_MessageContents_FrameAction: SwiftProtobuf.Message, SwiftProtobuf case 3: try { try decoder.decodeSingularBytesField(value: &self.actionBody) }() case 4: try { try decoder.decodeSingularBytesField(value: &self.installationSignature) }() case 5: try { try decoder.decodeSingularBytesField(value: &self.installationID) }() + case 6: try { try decoder.decodeSingularStringField(value: &self.inboxID) }() default: break } } @@ -244,6 +249,9 @@ extension Xmtp_MessageContents_FrameAction: SwiftProtobuf.Message, SwiftProtobuf if !self.installationID.isEmpty { try visitor.visitSingularBytesField(value: self.installationID, fieldNumber: 5) } + if !self.inboxID.isEmpty { + try visitor.visitSingularStringField(value: self.inboxID, fieldNumber: 6) + } try unknownFields.traverse(visitor: &visitor) } @@ -253,6 +261,7 @@ extension Xmtp_MessageContents_FrameAction: SwiftProtobuf.Message, SwiftProtobuf if lhs.actionBody != rhs.actionBody {return false} if lhs.installationSignature != rhs.installationSignature {return false} if lhs.installationID != rhs.installationID {return false} + if lhs.inboxID != rhs.inboxID {return false} if lhs.unknownFields != rhs.unknownFields {return false} return true } diff --git a/Tests/XMTPTests/FramesTests.swift b/Tests/XMTPTests/FramesTests.swift index dcb26fb5..b82e78d0 100644 --- a/Tests/XMTPTests/FramesTests.swift +++ b/Tests/XMTPTests/FramesTests.swift @@ -11,7 +11,7 @@ import XCTest final class FramesTests: XCTestCase { func testInstantiateFramesClient() async throws { - let frameUrl = "https://fc-polls-five.vercel.app/polls/01032f47-e976-42ee-9e3d-3aac1324f4b8" + let frameUrl = "https://fc-polls-five.vercel.app/polls/03710836-bc1d-4921-9e24-89d82015c53b" let key = try Crypto.secureRandomBytes(count: 32) let bo = try PrivateKey.generate()