diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a47113a5..50bbcd46 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -25,8 +25,8 @@ jobs: platform: - iOS steps: - - uses: actions/checkout@v2.3.4 - - uses: mxcl/xcodebuild@v1 + - uses: actions/checkout@v4 + - uses: mxcl/xcodebuild@v3.0.0 with: platform: ${{ matrix.platform }} action: test diff --git a/.gitignore b/.gitignore index b5d2630a..41ca90cd 100644 --- a/.gitignore +++ b/.gitignore @@ -49,7 +49,6 @@ playground.xcworkspace # # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata # hence it is not needed unless you have added a package configuration file to your project -.swiftpm/ .build/ diff --git a/.periphery.yml b/.periphery.yml new file mode 100644 index 00000000..1ffd9c5f --- /dev/null +++ b/.periphery.yml @@ -0,0 +1,3 @@ +retain_public: true +targets: +- TorusUtils diff --git a/.swiftpm/TorusUtils.xctestplan b/.swiftpm/TorusUtils.xctestplan new file mode 100644 index 00000000..7a94645d --- /dev/null +++ b/.swiftpm/TorusUtils.xctestplan @@ -0,0 +1,24 @@ +{ + "configurations" : [ + { + "id" : "9F2D8848-AB66-4789-A38F-C7E010657904", + "name" : "Test Scheme Action", + "options" : { + + } + } + ], + "defaultOptions" : { + "testRepetitionMode" : "retryOnFailure" + }, + "testTargets" : [ + { + "target" : { + "containerPath" : "container:", + "identifier" : "TorusUtilsTests", + "name" : "TorusUtilsTests" + } + } + ], + "version" : 1 +} diff --git a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..919434a6 --- /dev/null +++ b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/TorusUtils.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/TorusUtils.xcscheme new file mode 100644 index 00000000..c8f8c286 --- /dev/null +++ b/.swiftpm/xcode/xcshareddata/xcschemes/TorusUtils.xcscheme @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Package.resolved b/Package.resolved index 0bf696a3..99bb4888 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,14 +1,5 @@ { "pins" : [ - { - "identity" : "anycodable", - "kind" : "remoteSourceControl", - "location" : "https://github.com/Flight-School/AnyCodable", - "state" : { - "revision" : "862808b2070cd908cb04f9aafe7de83d35f81b05", - "version" : "0.6.7" - } - }, { "identity" : "bigint", "kind" : "remoteSourceControl", @@ -32,8 +23,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/torusresearch/fetch-node-details-swift.git", "state" : { - "revision" : "f085d3d85a4f36b57cfef8f0871ac8df1dd4f6f1", - "version" : "6.0.1" + "revision" : "4bd96c33ba8d02d9e27190c5c7cedf09cfdfd656", + "version" : "6.0.3" } }, { diff --git a/Package.swift b/Package.swift index 57771d76..25e8de38 100644 --- a/Package.swift +++ b/Package.swift @@ -12,17 +12,14 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/tkey/curvelib.swift", from: "1.0.1"), - .package(url: "https://github.com/torusresearch/fetch-node-details-swift", from: "6.0.1"), - .package(url: "https://github.com/vapor/jwt-kit", from: "4.0.0"), - .package( - url: "https://github.com/Flight-School/AnyCodable", - from: "0.6.0" - ), + .package(url: "https://github.com/torusresearch/fetch-node-details-swift", from: "6.0.3"), + // NB: jwt-kit may only be a dependency in tests or it will break cocoapod support + .package(url: "https://github.com/vapor/jwt-kit.git", from: "4.0.0"), ], targets: [ .target( name: "TorusUtils", - dependencies: ["AnyCodable", + dependencies: [ .product(name: "FetchNodeDetails", package: "fetch-node-details-swift"), .product(name: "curveSecp256k1", package: "curvelib.swift"), ]), diff --git a/README.md b/README.md index b25be952..3cbecc7f 100644 --- a/README.md +++ b/README.md @@ -8,26 +8,37 @@ This utility library allows for early exits in optimistic scenarios, while handl The general approach is to evaluate predicates against a list of (potentially incomplete) results, and exit when the predicate passes. ## 🔗 Installation -You can install the SingleFactorAuth Swift using Swift Package Manager. +You can install the TorusUtils using Swift Package Manager: ``` ... dependencies: [ ... - .package(url: "https://github.com/torusresearch/torus-utils-swift", from: "8.0.1") + .package(url: "https://github.com/torusresearch/torus-utils-swift", from: "9.0.0") ], +targets: [ + .target( name: "", + dependencies: [ + .product(name: "TorusUtils", package: "torus-utils-swift") + ] + ) ], +] +... +``` + +Or CocoaPods: + +``` +... + pod 'Torus-utils', '~> 9.0.0' ... ``` ## Getting Started -Initialize the `TorusUtils` class by passing `TorusNetwork`, `enableOneKey`, and your `clientId`. `enableOneKey` if true, adds the nonce value to the key, to make it compaitible with v2 users. The package supports both legacy and sapphire networks. +Initialize the `TorusUtils` class by passing `TorusOptions` as params. Params includes `TorusNetwork`, `enableOneKey`, and your `clientId`. `enableOneKey` if true, adds the nonce value to the key, to make it compatible with v2 users. The package supports both legacy and sapphire networks. ```swift - let torus = TorusUtils( - enableOneKey: true, - network: .sapphire(.SAPPHIRE_DEVNET), - clientId: "YOUR_CLIENT_ID" - ) + let torusUtils = TorusUtils(params: TorusOptions(clientId: "YOUR_CLIENT_ID", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true)) ``` @@ -39,22 +50,17 @@ Use the `getNodeDetails` function to retrive the node details for specific `veri do { let fnd = NodeDetailManager(network: .sapphire(.SAPPHIRE_DEVNET)) - let nodeDetails = try await fnd.getNodeDetails(verifier: verifer, verifierID: veriferID) + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) - let publicAddressResponse = try await torus.getPublicAddress( - endpoints: nodeDetails.getTorusNodeEndpoints(), - torusNodePubs: nodeDetails.torusNodePub, - verifier: TORUS_TEST_VERIFIER, - verifierId: TORUS_TEST_EMAIL - ) - - print(publicAddressResponse.oAuthKeyData!.evmAddress) + let publicDetails = try await torus.getPublicAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierId: verifierID) + + print(publicDetails.oAuthKeyData!.evmAddress) } catch let error { // Handle error } ``` -Use `retriveShares` function to login a user, and get the login data such as `sessionData`, `privKey`, `evmAddress`, `metaData` for user. Along with node detals, it also takes verifier, `verifierParams`, and `idToken`(JWT token). +Use `retrieveShares` function to login a user, and get the login data such as `sessionData`, `privKey`, `evmAddress`, `metaData` for user. Along with node details, it also takes `verifier`, `verifierParams`, and `idToken`(JWT token). ```swift // verifier_id takes the value, for instance email, sub, or custom. @@ -62,16 +68,11 @@ let verifierParams = VerifierParams(verifier_id: "verifier_id_value") do { // Use nodeDetails from above step - let data = try await torus.retrieveShares( - endpoints: nodeDetails.getTorusNodeEndpoints(), - torusNodePubs: nodeDetails.getTorusNodePub(), - indexes: nodeDetails.getTorusIndexes(), - verifier: TORUS_TEST_VERIFIER, - verifierParams: verifierParams, - idToken: token - ) - - let privateKey = data.finalKeyData!.privKey + + let verifierParams = VerifierParams(verifier_id: verifierID) + + let data = try await torus.retrieveShares(endpoints: nodeDetails.getTorusNodeSSSEndpoints(), indexes: nodeDetails.getTorusIndexes(), verifier: verifier, verifierParams: verifierParams, idToken: token) + let evmAddress = data.finalKeyData!.evmAddress } catch let error { // Handle error @@ -85,4 +86,4 @@ do { - Have a look at our [Community Portal](https://community.web3auth.io/) to see if anyone has any questions or issues you might be having. Feel free to reate new topics and we'll help you out as soon as possible. - Checkout our [Troubleshooting Documentation Page](https://web3auth.io/docs/troubleshooting) to know the common issues and solutions. -- For Priority Support, please have a look at our [Pricing Page](https://web3auth.io/pricing.html) for the plan that suits your needs. \ No newline at end of file +- For Priority Support, please have a look at our [Pricing Page](https://web3auth.io/pricing.html) for the plan that suits your needs. diff --git a/Sources/TorusUtils/AbstractTorusUtils.swift b/Sources/TorusUtils/AbstractTorusUtils.swift deleted file mode 100644 index d22f90a8..00000000 --- a/Sources/TorusUtils/AbstractTorusUtils.swift +++ /dev/null @@ -1,9 +0,0 @@ -import BigInt -import FetchNodeDetails -import Foundation - -public protocol AbstractTorusUtils { - func retrieveShares(endpoints: [String], torusNodePubs: [TorusNodePubModel], indexes: [BigUInt], verifier: String, verifierParams: VerifierParams, idToken: String, extraParams: [String: Codable]) async throws -> TorusKey - - func getPublicAddress(endpoints: [String], torusNodePubs: [TorusNodePubModel], verifier: String, verifierId: String, extendedVerifierId: String?) async throws -> TorusPublicKey -} diff --git a/Sources/TorusUtils/Constants.swift b/Sources/TorusUtils/Constants.swift index e5af863f..e88aa344 100644 --- a/Sources/TorusUtils/Constants.swift +++ b/Sources/TorusUtils/Constants.swift @@ -1,13 +1,8 @@ enum JRPC_METHODS { static let GET_OR_SET_KEY = "GetPubKeyOrKeyAssign" static let COMMITMENT_REQUEST = "CommitmentRequest" - static let IMPORT_SHARE = "ImportShare" + static let IMPORT_SHARES = "ImportShares" static let GET_SHARE_OR_KEY_ASSIGN = "GetShareOrKeyAssign" - static let LEGACY_VERIFIER_LOOKUP_REQUEST = "VerifierLookupRequest" - static let LEGACY_KEY_ASSIGN = "KeyAssign" - static let LEGACY_SHARE_REQUEST = "ShareRequest" } let CURVE_N: String = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141" - -let LEGACY_METADATA_HOST = "https://metadata.tor.us" diff --git a/Sources/TorusUtils/DataModels.swift b/Sources/TorusUtils/DataModels.swift deleted file mode 100644 index 9795185f..00000000 --- a/Sources/TorusUtils/DataModels.swift +++ /dev/null @@ -1,173 +0,0 @@ -import BigInt -import Foundation - -public struct TaskGroupResponse { - public var data: Data - public var urlResponse: URLResponse - public var index: Int - - public init(data: Data, urlResponse: URLResponse, index: Int) { - self.data = data - self.urlResponse = urlResponse - self.index = index - } -} - -public enum TypeOfUser: String { - case v1 - case v2 -} - -public struct GetUserAndAddress { - public var typeOfUser: TypeOfUser - public var pubNonce: PubNonce? - public var nonceResult: String? - public var address: String - public var x: String - public var y: String - - public init(typeOfUser: TypeOfUser, address: String, x: String, y: String, pubNonce: PubNonce? = nil, nonceResult: String? = nil) { - self.typeOfUser = typeOfUser - self.address = address - self.x = x - self.y = y - self.pubNonce = pubNonce - self.nonceResult = nonceResult - } -} - -public struct GetPublicAddressResult { - public var address: String - public var typeOfUser: TypeOfUser? - public var x: String? - public var y: String? - public var metadataNonce: BigUInt? - public var pubNonce: PubNonce? - public var nodeIndexes: [Int]? - public var upgarded: Bool? - - public init(address: String, typeOfUser: TypeOfUser? = nil, x: String? = nil, y: String? = nil, metadataNonce: BigUInt? = nil, pubNonce: PubNonce? = nil, nodeIndexes: [Int]? = [], upgraded: Bool? = false) { - self.typeOfUser = typeOfUser - self.address = address - self.x = x - self.y = y - self.metadataNonce = metadataNonce - self.pubNonce = pubNonce - self.nodeIndexes = nodeIndexes - upgarded = upgraded - } -} - -public struct GetOrSetNonceResult: Codable { - public var typeOfUser: String? - public var nonce: String? - public var pubNonce: PubNonce? - public var ifps: String? - public var upgraded: Bool? - - public init(typeOfUser: String, nonce: String? = nil, pubNonce: PubNonce? = nil, ifps: String? = nil, upgraded: Bool? = false) { - self.typeOfUser = typeOfUser - self.nonce = nonce - self.pubNonce = pubNonce - self.ifps = ifps - self.upgraded = upgraded - } - - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - - typeOfUser = try container.decodeIfPresent(String.self, forKey: .typeOfUser) - nonce = try container.decodeIfPresent(String.self, forKey: .nonce) - pubNonce = try container.decodeIfPresent(PubNonce.self, forKey: .pubNonce) - ifps = try container.decodeIfPresent(String.self, forKey: .ifps) - upgraded = try container.decodeIfPresent(Bool.self, forKey: .upgraded) - } -} - -public struct PubNonce: Codable, Equatable { - public var x: String - public var y: String - - public init(x: String, y: String) { - self.x = x - self.y = y - } - - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - x = try container.decode(String.self, forKey: .x) - y = try container.decode(String.self, forKey: .y) - } -} - -public struct UserTypeAndAddress { - public var typeOfUser: String - public var nonce: BigInt? - public var x: String - public var y: String - public var address: String - - public init(typeOfUser: String, x: String, y: String, nonce: BigInt?, address: String) { - self.typeOfUser = typeOfUser - self.address = address - self.x = x - self.y = y - self.nonce = nonce - } -} - -public struct NonceMetadataParams: Codable { - public struct SetNonceData: Codable { - public var operation: String? - public var data: String? - public var timestamp: String? - - public init(operation: String? = nil, data: String? = nil, timestamp: String? = nil) { - self.operation = operation - self.data = data - self.timestamp = timestamp - } - } - - public var namespace: String? - public var pub_key_X: String - public var pub_key_Y: String - public var set_data: SetNonceData - public var signature: String - - public init(pub_key_X: String, pub_key_Y: String, setData: SetNonceData, signature: String, namespace: String? = nil) { - self.namespace = namespace - self.pub_key_X = pub_key_X - self.pub_key_Y = pub_key_Y - set_data = setData - self.signature = signature - } -} - -typealias StringifiedType = [String: Codable] - -public struct MetadataParams: Codable { - public struct SetData: Codable { - public var data: String - public var timestamp: String - - public init(data: String, timestamp: String) { - self.data = data - self.timestamp = timestamp - } - } - - public var namespace: String? - public var pub_key_X: String - public var pub_key_Y: String - public var set_data: SetData - public var signature: String - - public init(pub_key_X: String, pub_key_Y: String, setData: SetData, signature: String, namespace: String? = nil) { - self.namespace = namespace - self.pub_key_X = pub_key_X - self.pub_key_Y = pub_key_Y - set_data = setData - self.signature = signature - } -} diff --git a/Sources/TorusUtils/Extensions/Array+Extension.swift b/Sources/TorusUtils/Extensions/Array+Extension.swift index 10c61bcd..ad38dc0a 100644 --- a/Sources/TorusUtils/Extensions/Array+Extension.swift +++ b/Sources/TorusUtils/Extensions/Array+Extension.swift @@ -14,69 +14,64 @@ // extension Array { - @inlinable - init(reserveCapacity: Int) { - self = Array() - self.reserveCapacity(reserveCapacity) - } + @inlinable + init(reserveCapacity: Int) { + self = Array() + self.reserveCapacity(reserveCapacity) + } - @inlinable - var slice: ArraySlice { - self[self.startIndex ..< self.endIndex] - } - - @inlinable - subscript (safe index: Index) -> Element? { - return indices.contains(index) ? self[index] : nil - } + @inlinable + var slice: ArraySlice { + self[startIndex ..< endIndex] + } } extension Array where Element == UInt8 { - public init(hex: String) { - self.init(reserveCapacity: hex.unicodeScalars.lazy.underestimatedCount) - var buffer: UInt8? - var skip = hex.hasPrefix("0x") ? 2 : 0 - for char in hex.unicodeScalars.lazy { - guard skip == 0 else { - skip -= 1 - continue - } - guard char.value >= 48 && char.value <= 102 else { - removeAll() - return - } - let v: UInt8 - let c: UInt8 = UInt8(char.value) - switch c { - case let c where c <= 57: - v = c - 48 - case let c where c >= 65 && c <= 70: - v = c - 55 - case let c where c >= 97: - v = c - 87 - default: - removeAll() - return - } - if let b = buffer { - append(b << 4 | v) - buffer = nil - } else { - buffer = v - } - } - if let b = buffer { - append(b) + public init(hex: String) { + self.init(reserveCapacity: hex.unicodeScalars.lazy.underestimatedCount) + var buffer: UInt8? + var skip = hex.hasPrefix("0x") ? 2 : 0 + for char in hex.unicodeScalars.lazy { + guard skip == 0 else { + skip -= 1 + continue + } + guard char.value >= 48 && char.value <= 102 else { + removeAll() + return + } + let v: UInt8 + let c: UInt8 = UInt8(char.value) + switch c { + case let c where c <= 57: + v = c - 48 + case let c where c >= 65 && c <= 70: + v = c - 55 + case let c where c >= 97: + v = c - 87 + default: + removeAll() + return + } + if let b = buffer { + append(b << 4 | v) + buffer = nil + } else { + buffer = v + } + } + if let b = buffer { + append(b) + } } - } - public func toHexString() -> String { - `lazy`.reduce(into: "") { - var s = String($1, radix: 16) - if s.count == 1 { - s = "0" + s - } - $0 += s + public func toHexString() -> String { + lazy.reduce(into: "") { + var s = String($1, radix: 16) + if s.count == 1 { + s = "0" + s + } + $0 += s + } } - } } diff --git a/Sources/TorusUtils/Extensions/Data+Extension.swift b/Sources/TorusUtils/Extensions/Data+Extension.swift index 5673b055..4b44a2e3 100755 --- a/Sources/TorusUtils/Extensions/Data+Extension.swift +++ b/Sources/TorusUtils/Extensions/Data+Extension.swift @@ -1,23 +1,23 @@ import Foundation -public extension Data { +extension Data { var hexString: String { return map { String(format: "%02x", $0) }.joined() } - func addLeading0sForLength64() -> Data { + public func addLeading0sForLength64() -> Data { Data(hex: hexString.addLeading0sForLength64()) } - + init(hex: String) { - self.init(Array(hex: hex)) + self.init(Array(hex: hex)) } var bytes: Array { - Array(self) + Array(self) } func toHexString() -> String { - self.bytes.toHexString() + bytes.toHexString() } } diff --git a/Sources/TorusUtils/Extensions/OSLog+categories.swift b/Sources/TorusUtils/Extensions/OSLog+categories.swift index 795d5da7..9154afde 100644 --- a/Sources/TorusUtils/Extensions/OSLog+categories.swift +++ b/Sources/TorusUtils/Extensions/OSLog+categories.swift @@ -6,8 +6,6 @@ let subsystem = Bundle.main.bundleIdentifier ?? "com.torus.utils" public struct TorusUtilsLogger { static let inactiveLog = OSLog.disabled static let network = OSLog(subsystem: subsystem, category: "network") - static let parsing = OSLog(subsystem: subsystem, category: "parsing") - static let core = OSLog(subsystem: subsystem, category: "core") } func getTorusLogger(log: OSLog = .default, type: OSLogType = .default) -> OSLog { diff --git a/Sources/TorusUtils/Extensions/Sequence+Extension.swift b/Sources/TorusUtils/Extensions/Sequence+Extension.swift deleted file mode 100644 index 8b10b1e7..00000000 --- a/Sources/TorusUtils/Extensions/Sequence+Extension.swift +++ /dev/null @@ -1,7 +0,0 @@ -import BigInt -import Foundation - -extension Sequence where Element == UInt8 { - var data: Data { .init(self) } - var hexa: String { map { .init(format: "%02x", $0) }.joined() } -} diff --git a/Sources/TorusUtils/Extensions/String+Extension.swift b/Sources/TorusUtils/Extensions/String+Extension.swift index c058cf37..82bf77ad 100755 --- a/Sources/TorusUtils/Extensions/String+Extension.swift +++ b/Sources/TorusUtils/Extensions/String+Extension.swift @@ -1,15 +1,15 @@ import Foundation extension String { - func hasHexPrefix() -> Bool { - return hasPrefix("0x") - } - func addHexPrefix() -> String { - if !hasPrefix("0x") { - return "0x" + self + if hasPrefix("0x") { + return self } - return self + return "0x" + self + } + + func add04PrefixUnchecked() -> String { + return "04" + self } func stripHexPrefix() -> String { @@ -20,26 +20,15 @@ extension String { return self } - func has04Prefix() -> Bool { - return hasPrefix("04") - } - - func add04Prefix(targetLength: Int = 128) -> String { - if self.count == targetLength{ - return "04" + self - } - return self - } - - func strip04Prefix(targetLength: Int = 130) -> String { - if hasPrefix("04") && self.count == targetLength { + func strip04Prefix() -> String { + if hasPrefix("04") { let indexStart = index(startIndex, offsetBy: 2) return String(self[indexStart...]) } return self } - func addLeading0sForLength64() -> String { + public func addLeading0sForLength64() -> String { if count < 64 { let toAdd = String(repeating: "0", count: 64 - count) return toAdd + self @@ -48,35 +37,23 @@ extension String { } } - func customBytes() -> Array { - data(using: String.Encoding.utf8, allowLossyConversion: true)?.bytes ?? Array(utf8) - } + public func hexEncodedToString() -> String { + var finalString = "" + var chars = Array(self) - func toChecksumAddress() -> String { - let lowerCaseAddress = stripHexPrefix().lowercased() - let arr = Array(lowerCaseAddress) - let hash = keccak256Data(lowerCaseAddress.data(using: .utf8) ?? Data() ).toHexString() + if (chars.count % 2) != 0 { // odd number of characters in hex, pad with single zero. + chars.insert("0", at: 0) + } - var result = String() - for i in 0 ... lowerCaseAddress.count - 1 { - let iIndex = hash.index(hash.startIndex, offsetBy: i) - if let val = hash[iIndex].hexDigitValue , val >= 8 { - result.append(arr[i].uppercased()) - } else { - result.append(arr[i]) + for count in stride(from: 0, to: chars.count - 1, by: 2) { + let firstDigit = Int("\(chars[count])", radix: 16) ?? 0 + let lastDigit = Int("\(chars[count + 1])", radix: 16) ?? 0 + let decimal = firstDigit * 16 + lastDigit + let decimalString = String(format: "%c", decimal) as String + if !(decimalString.isEmpty) { // lossy conversion + finalString.append(Character(decimalString)) } } - return result.addHexPrefix() - } -} - -extension StringProtocol { - var hexa: [UInt8] { - var startIndex = self.startIndex - return (0 ..< count / 2).compactMap { _ in - let endIndex = index(after: startIndex) - defer { startIndex = index(after: endIndex) } - return UInt8(self[startIndex ... endIndex], radix: 16) - } + return finalString } } diff --git a/Sources/TorusUtils/Extensions/TorusUtils+extension.swift b/Sources/TorusUtils/Extensions/TorusUtils+extension.swift deleted file mode 100644 index b01e1eda..00000000 --- a/Sources/TorusUtils/Extensions/TorusUtils+extension.swift +++ /dev/null @@ -1,1335 +0,0 @@ -import Foundation -import curveSecp256k1 -import AnyCodable -import BigInt -import CryptoKit -import FetchNodeDetails -import OSLog - - - -extension TorusUtils { - - - internal func combinations(elements: ArraySlice, k: Int) -> [[T]] { - if k == 0 { - return [[]] - } - - guard let first = elements.first else { - return [] - } - - let head = [first] - let subcombos = combinations(elements: elements.dropFirst(), k: k - 1) - var ret = subcombos.map { head + $0 } - ret += combinations(elements: elements.dropFirst(), k: k) - - return ret - } - - internal func combinations(elements: [T], k: Int) -> [[T]] { - return combinations(elements: ArraySlice(elements), k: k) - } - - internal func makeUrlRequest(url: String, httpMethod: HTTPMethod = .post) throws -> URLRequest { - guard - let url = URL(string: url) - else { - throw TorusUtilError.runtime("Invalid Url \(url)") - } - var rq = URLRequest(url: url) - rq.httpMethod = httpMethod.name - rq.addValue("application/json", forHTTPHeaderField: "Content-Type") - rq.addValue("application/json", forHTTPHeaderField: "Accept") - return rq - } - - internal func thresholdSame(arr: [T], threshold: Int) -> T? { - var hashmap = [T: Int]() - for (_, value) in arr.enumerated() { - if let _ = hashmap[value] { - hashmap[value]! += 1 - } else { - hashmap[value] = 1 - } - if hashmap[value] == threshold { - return value - } - } - return nil - } - - internal func isLegacyNetwork() -> Bool { - if case .legacy = network { - return true - } - return false - } - - internal func isMigratedLegacyNetwork() -> Bool { - if case let .legacy(legacyNetwork) = network { - let legacyRoute = legacyNetwork.migration_map - if !legacyRoute.migrationCompleted { - return true - } - return false - } - return false - } - - // MARK: - metadata API - - internal func getMetadata(dictionary: [String: String]) async throws -> BigUInt { - let encoded = try JSONSerialization.data(withJSONObject: dictionary, options: [.sortedKeys]) - - var request = try makeUrlRequest(url: "\(legacyMetadataHost)/get") - request.httpBody = encoded - let val = try await urlSession.data(for: request) - let data = try JSONSerialization.jsonObject(with: val.0) as? [String: Any] ?? [:] - os_log("getMetadata: %@", log: getTorusLogger(log: TorusUtilsLogger.network, type: .info), type: .info, data) - guard - let msg: String = data["message"] as? String, - let ret = BigUInt(msg, radix: 16) - else { - throw TorusUtilError.decodingFailed("Message value not correct or nil in \(data)") - } - return ret - } - - internal func getOrSetNonce(x: String, y: String, privateKey: String? = nil, getOnly: Bool = false) async throws -> GetOrSetNonceResult { - var data: Data - let msg = getOnly ? "getNonce" : "getOrSetNonce" - if privateKey != nil { - let val = try generateParams(message: msg, privateKey: privateKey!) - let encoder = JSONEncoder() - encoder.outputFormatting = .sortedKeys - data = try encoder.encode(val) - } else { - let dict: [String: Any] = ["pub_key_X": x, "pub_key_Y": y, "set_data": ["data": msg]] - data = try JSONSerialization.data(withJSONObject: dict, options: .sortedKeys) - } - var request = try makeUrlRequest(url: "\(legacyMetadataHost)/get_or_set_nonce") - request.httpBody = data - let val = try await urlSession.data(for: request) - let decoded = try JSONDecoder().decode(GetOrSetNonceResult.self, from: val.0) - return decoded - } - - internal func generateParams(message: String, privateKey: String) throws -> MetadataParams { - let privKey = try SecretKey(hex: privateKey) - let publicKey = try privKey.toPublic().serialize(compressed: false) - - let timeStamp = String(BigUInt(serverTimeOffset + Date().timeIntervalSince1970), radix: 16) - let setData: MetadataParams.SetData = .init(data: message, timestamp: timeStamp) - let encoder = JSONEncoder() - encoder.outputFormatting = .sortedKeys - let encodedData = try encoder - .encode(setData) - - let hash = keccak256Data(encodedData).hexString - let sigData = try ECDSA.signRecoverable(key: privKey, hash: hash).serialize() - - return .init(pub_key_X: String(publicKey.suffix(128).prefix(64)), pub_key_Y: String(publicKey.suffix(64)), setData: setData, signature: Data(hex: sigData).base64EncodedString()) - } - - // MARK: - getShareOrKeyAssign - - private func getShareOrKeyAssign(endpoints: [String], nodeSigs: [CommitmentRequestResponse], verifier: String, verifierParams: VerifierParams, idToken: String, extraParams: [String: Any] = [:]) async throws -> [URLRequest] { - _ = createURLSession() - _ = Int(endpoints.count / 2) + 1 - var rpcdata: Data = Data() - - let loadedStrings = extraParams - let valueDict = ["idtoken": idToken, - "nodesignatures": nodeSigs, - "verifieridentifier": verifier, - "verifier_id": verifierParams.verifier_id, - "extended_verifier_id": verifierParams.extended_verifier_id, - ] as [String: Codable] - - let keepingCurrent = loadedStrings.merging(valueDict) { current, _ in current } - let finalItem = keepingCurrent.merging(verifierParams.additionalParams) { current, _ in current } - - let params = ["encrypted": "yes", - "use_temp": true, - "one_key_flow": true, - "item": AnyCodable([finalItem]), - ] as [String: AnyCodable] - - let dataForRequest = ["jsonrpc": "2.0", - "id": 10, - "method": AnyCodable(JRPC_METHODS.GET_SHARE_OR_KEY_ASSIGN), - "params": AnyCodable(params), - ] as [String: AnyCodable] - - // do { - let encoder = JSONEncoder() - encoder.outputFormatting = .sortedKeys - rpcdata = try encoder.encode(dataForRequest) - // } catch { - // os_log("get share or key assign - error: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .error), type: .error, error.localizedDescription) - // } - - // Create Array of URLRequest Promises - var requestArray = [URLRequest]() - - for endpoint in endpoints { - var request = try makeUrlRequest(url: endpoint, httpMethod: .post) - request.httpBody = rpcdata - requestArray.append(request) - } - - return requestArray - } - - private func reconstructKey(decryptedShares: [Int: String], thresholdPublicKey: KeyAssignment.PublicKey) throws -> String? { - // run lagrange interpolation on all subsets, faster in the optimistic scenario than berlekamp-welch due to early exit - let allCombis = combinations(elements: Array(0 ..< decryptedShares.count), k: 3) - var returnedKey: String? - - for j in 0 ..< allCombis.count { - let currentCombi = allCombis[j] - let currentCombiShares = decryptedShares.enumerated().reduce(into: [Int: String]()) { acc, current in - let (index, curr) = current - if currentCombi.contains(index) { - acc[curr.key] = curr.value - } - } - let derivedPrivateKey = try SecretKey(hex: try lagrangeInterpolation(shares: currentCombiShares, offset: 0).addLeading0sForLength64()) - - let decryptedPubKey = try derivedPrivateKey.toPublic().serialize(compressed: false) - let decryptedPubKeyX = String(decryptedPubKey.suffix(128).prefix(64)) - let decryptedPubKeyY = String(decryptedPubKey.suffix(64)) - if decryptedPubKeyX == thresholdPublicKey.X.addLeading0sForLength64() && decryptedPubKeyY == thresholdPublicKey.Y.addLeading0sForLength64() { - returnedKey = try derivedPrivateKey.serialize().addLeading0sForLength64() - break - } - } - - return returnedKey - } - - // MARK: - retrieveShare - - // TODO: add importShare functionality later - internal func retrieveShare( - legacyMetadataHost: String, - allowHost: String, - enableOneKey: Bool, - network: TorusNetwork, - clientId: String, - endpoints: [String], - verifier: String, - verifierParams: VerifierParams, - idToken: String, - extraParams: [String: Any] = [:] - ) async throws -> TorusKey { - let session = createURLSession() - let threshold = (endpoints.count / 2) + 1 - - let sessionAuthKey = SecretKey() - let serializedPublicKey = try sessionAuthKey.toPublic().serialize(compressed: false) - - // Split key in 2 parts, X and Y - let pubKeyX = String(serializedPublicKey.suffix(128).prefix(64)) - let pubKeyY = String(serializedPublicKey.suffix(64)) - - // Hash the token from OAuth login - let timestamp = String(Int(getTimestamp())) - let hashedToken = keccak256Data(idToken.data(using: .utf8) ?? Data()).toHexString() - - - let nodeSigs = try await commitmentRequest(endpoints: endpoints, verifier: verifier, pubKeyX: pubKeyX, pubKeyY: pubKeyY, timestamp: timestamp, tokenCommitment: hashedToken) - os_log("retrieveShares - data after commitment request: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .info), type: .info, nodeSigs) - var promiseArrRequest = [URLRequest]() - - // TODO: make sure we have only complete requests in promiseArrRequest? - promiseArrRequest = try await getShareOrKeyAssign(endpoints: endpoints, nodeSigs: nodeSigs, verifier: verifier, verifierParams: verifierParams, idToken: idToken, extraParams: extraParams) - - var thresholdNonceData: GetOrSetNonceResult? - var pubkeyArr = [KeyAssignment.PublicKey]() - var isNewKeyArr: [String] = [] - var completeShareRequestResponseArr = [ShareRequestResult]() - var thresholdPublicKey: KeyAssignment.PublicKey? - - try await withThrowingTaskGroup(of: Result.self, body: { group in - - for (i, rq) in promiseArrRequest.enumerated() { - group.addTask { - do { - let val = try await session.data(for: rq) - return .success(.init(data: val.0, urlResponse: val.1, index: i)) - } catch { - return .failure(error) - } - } - } - - for try await val in group { - do { - switch val { - case let .success(model): - let data = model.data - let decoded = try JSONDecoder().decode(JSONRPCresponse.self, from: data) - os_log("retrieveShare promise - reponse: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .info), type: .info, decoded.message ?? "") - - if decoded.error != nil { - os_log("retrieveShare promise - decode error: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .error), type: .error, decoded.error?.message ?? "") - throw TorusUtilError.runtime(decoded.error?.message ?? "") - } - - // Ensure that we don't add bad data to result arrays. - guard - let decodedResult = decoded.result as? ShareRequestResult - else { throw TorusUtilError.decodingFailed("ShareReqeust error decoding error : \(decoded), can't decode into shareRequestResult") } - - isNewKeyArr.append(decodedResult.isNewKey) - completeShareRequestResponseArr.append(decodedResult) - let keyObj = decodedResult.keys - if let first = keyObj.first { - let pubkey = first.publicKey - let nonceData = first.nonceData - let pubNonce = nonceData?.pubNonce?.x - - pubkeyArr.append(pubkey) - if thresholdNonceData == nil && verifierParams.extended_verifier_id == nil { - if pubNonce != "" { - thresholdNonceData = nonceData - } - } - guard let result = thresholdSame(arr: pubkeyArr, threshold: threshold) - else { - throw TorusUtilError.thresholdError - } - - thresholdPublicKey = result - - if thresholdPublicKey?.X == nil { - throw TorusUtilError.thresholdError - } - - if thresholdNonceData == nil && verifierParams.extended_verifier_id == nil && !isLegacyNetwork() { - throw TorusUtilError.metadataNonceMissing - } - return - } - case let .failure(error): - throw error - } - } catch { - os_log("retrieveShare promise - share request error: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .debug)) - } - } - - os_log("retrieveShare - invalid result from nodes, threshold number of public key results are not matching", log: getTorusLogger(log: TorusUtilsLogger.core, type: .error), type: .error) - throw TorusUtilError.thresholdError - }) - - // optimistically run lagrange interpolation once threshold number of shares have been received - // this is matched against the user public key to ensure that shares are consistent - // Note: no need of thresholdMetadataNonce for extended_verifier_id key - if completeShareRequestResponseArr.count >= threshold { - if thresholdPublicKey?.X != nil && (thresholdNonceData != nil && thresholdNonceData?.pubNonce?.x != "" || verifierParams.extended_verifier_id != nil || isLegacyNetwork()) { - // Code block to execute if all conditions are true - var shares = [String]() - var sessionTokenSigPromises = [String?]() - var sessionTokenPromises = [String?]() - var nodeIndexes = [Int]() - var sessionTokenData = [SessionToken?]() - - guard let isNewKey = thresholdSame(arr: isNewKeyArr, threshold: threshold) - else { - os_log("retrieveShare - invalid result from nodes, threshold number of is_new_key results are not matching", log: getTorusLogger(log: TorusUtilsLogger.core, type: .error), type: .error) - throw TorusUtilError.thresholdError - } - - for currentShareResponse in completeShareRequestResponseArr { - let sessionTokens = currentShareResponse.sessionTokens - let sessionTokenMetadata = currentShareResponse.sessionTokenMetadata - let sessionTokenSigs = currentShareResponse.sessionTokenSigs - let sessionTokenSigMetadata = currentShareResponse.sessionTokenSigMetadata - let keys = currentShareResponse.keys - - if sessionTokenSigs.count > 0 { - // decrypt sessionSig if enc metadata is sent - if sessionTokenSigMetadata.first?.ephemPublicKey != nil { - sessionTokenSigPromises.append(try? decryptNodeData(eciesData: sessionTokenSigMetadata[0], ciphertextHex: sessionTokenSigs[0], privKey: sessionAuthKey.serialize().addLeading0sForLength64())) - } else { - sessionTokenSigPromises.append(sessionTokenSigs[0]) - } - } else { - sessionTokenSigPromises.append(nil) - } - - if sessionTokens.count > 0 { - if sessionTokenMetadata.first?.ephemPublicKey != nil { - sessionTokenPromises.append(try? decryptNodeData(eciesData: sessionTokenMetadata[0], ciphertextHex: sessionTokens[0], privKey: sessionAuthKey.serialize().addLeading0sForLength64())) - } else { - sessionTokenPromises.append(sessionTokenSigs[0]) - } - } else { - sessionTokenPromises.append(nil) - } - - if keys.count > 0 { - let latestKey = currentShareResponse.keys[0] - nodeIndexes.append(Int(latestKey.nodeIndex)) - let data = Data(base64Encoded: latestKey.share, options: [])! - guard let ciphertextHex = String(data: data, encoding: .ascii) else { - throw TorusUtilError.decodingFailed() - } - let decryptedShare = try decryptNodeData(eciesData: latestKey.shareMetadata, ciphertextHex: ciphertextHex, privKey: sessionAuthKey.serialize().addLeading0sForLength64()) - shares.append(decryptedShare.addLeading0sForLength64()) - } else { - os_log("retrieveShare - 0 keys returned from nodes", log: getTorusLogger(log: TorusUtilsLogger.core, type: .error), type: .error) - throw TorusUtilError.thresholdError - } - } - - let validTokens = sessionTokenPromises.filter { token in - if let _ = token { - return true - } - return false - } - - if verifierParams.extended_verifier_id == nil && validTokens.count < threshold { - os_log("retrieveShare - Insufficient number of session tokens from nodes, required: %@, found: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .debug), type: .debug, threshold, validTokens.count) - throw TorusUtilError.apiRequestFailed - } - - let validSigs = sessionTokenSigPromises.filter { sig in - if let _ = sig { - return true - } - return false - } - - if verifierParams.extended_verifier_id == nil && validSigs.count < threshold { - os_log("retrieveShare - Insufficient number of session signatures from nodes, required: %@, found: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .debug), type: .debug, threshold, validSigs.count) - throw TorusUtilError.apiRequestFailed - } - - for (index, x) in sessionTokenPromises.enumerated() { - if x == nil { - sessionTokenData.append(nil) - } else { - let token = x! - let signature = sessionTokenSigPromises[index] - let nodePubX = completeShareRequestResponseArr[index].nodePubX - let nodePubY = completeShareRequestResponseArr[index].nodePubY - - sessionTokenData.append(SessionToken(token: token, signature: signature!, node_pubx: nodePubX, node_puby: nodePubY)) - } - } - - let sharesWithIndex = shares.enumerated().reduce(into: [Int: String]()) { acc, current in - let (index, curr) = current - acc[nodeIndexes[index]] = curr - } - - let returnedKey = try reconstructKey(decryptedShares: sharesWithIndex, thresholdPublicKey: thresholdPublicKey!) - if returnedKey == nil { - throw TorusUtilError.privateKeyDeriveFailed - } - - guard let oAuthKey = returnedKey else { - throw TorusUtilError.privateKeyDeriveFailed - } - - let derivedPrivateKey = try SecretKey(hex: oAuthKey) - - let oAuthPubKey = try derivedPrivateKey.toPublic().serialize(compressed: false) - let oAuthPubKeyX = String(oAuthPubKey.suffix(128).prefix(64)) - let oAuthPubKeyY = String(oAuthPubKey.suffix(64)) - - var metadataNonce = BigInt(thresholdNonceData?.nonce ?? "0", radix: 16) ?? BigInt(0) - - var pubKeyNonceResult: PubNonce? - var typeOfUser: UserType = .v1 - - var finalPubKey = oAuthPubKey - if verifierParams.extended_verifier_id != nil { - typeOfUser = .v2 - // For TSS key, no need to add pub nonce - finalPubKey = String(finalPubKey.suffix(128)) - } else if case .legacy = self.network { - if self.enableOneKey { - // get or set nonce based on isNewKey variable - let nonceResult = try await getOrSetNonce(x: oAuthPubKeyX, y: oAuthPubKeyY, privateKey: oAuthKey, getOnly: isNewKey == "false") - // BigInt( Data(hex: nonceResult.nonce ?? "0")) - metadataNonce = BigInt(nonceResult.nonce ?? "0", radix: 16)! - let usertype = nonceResult.typeOfUser - - if usertype == "v2" { - let pubNonceX = nonceResult.pubNonce?.x - let pubNonceY = nonceResult.pubNonce?.y - typeOfUser = .v2 - let pubkey2 = (pubNonceX!.addLeading0sForLength64() + pubNonceY!.addLeading0sForLength64()).add04Prefix() - let combined = try combinePublicKeys(keys: [finalPubKey, pubkey2], compressed: false) - finalPubKey = combined - pubKeyNonceResult = .init(x: pubNonceX!, y: pubNonceY!) - } else { - typeOfUser = .v1 - // for imported keys in legacy networks - metadataNonce = BigInt(try await getMetadata(dictionary: ["pub_key_X": oAuthPubKeyX, "pub_key_Y": oAuthPubKeyY])) - let privateKeyWithNonce = (BigInt(oAuthKey, radix: 16)! + BigInt(metadataNonce)).modulus(modulusValue) - finalPubKey = String(privateKeyWithNonce, radix: 16).addLeading0sForLength64() - } - } else { - typeOfUser = .v1 - // for imported keys in legacy networks - metadataNonce = BigInt(try await getMetadata(dictionary: ["pub_key_X": oAuthPubKeyX, "pub_key_Y": oAuthPubKeyY])) - let privateKeyWithNonce = (BigInt(oAuthKey, radix: 16)! + BigInt(metadataNonce)).modulus(modulusValue) - finalPubKey = String(privateKeyWithNonce, radix: 16).addLeading0sForLength64() - } - } else { - typeOfUser = .v2 - - let pubNonceX = thresholdNonceData!.pubNonce!.x - let pubNonceY = thresholdNonceData!.pubNonce!.y - let pubkey2 = (pubNonceX.addLeading0sForLength64() + pubNonceY.addLeading0sForLength64()).add04Prefix() - let combined = try combinePublicKeys(keys: [finalPubKey, pubkey2], compressed: false) - finalPubKey = combined - pubKeyNonceResult = .init(x: pubNonceX, y: pubNonceY) - } - - let oAuthKeyAddress = generateAddressFromPubKey(publicKeyX: oAuthPubKeyX, publicKeyY: oAuthPubKeyY) - - var finalPrivKey = "" - - if typeOfUser == .v1 || (typeOfUser == .v2 && metadataNonce > BigInt(0)) { - let privateKeyWithNonce = ((BigInt(oAuthKey, radix: 16) ?? BigInt(0)) + metadataNonce).modulus(modulusValue) - finalPrivKey = String(privateKeyWithNonce, radix: 16).addLeading0sForLength64() - } - - let (finalPubX, finalPubY) = try getPublicKeyPointFromPubkeyString(pubKey: finalPubKey) - // deriving address from pub key coz pubkey is always available - // but finalPrivKey won't be available for v2 user upgraded to 2/n - let finalEvmAddress = generateAddressFromPubKey(publicKeyX: finalPubX, publicKeyY: finalPubY) - - var isUpgraded: Bool? - - switch typeOfUser { - case .v1: - isUpgraded = nil - case .v2: - isUpgraded = metadataNonce == BigInt(0) - } - - return TorusKey( - finalKeyData: .init( - evmAddress: finalEvmAddress, - X: finalPubX.addLeading0sForLength64(), - Y: finalPubY.addLeading0sForLength64(), - privKey: finalPrivKey - ), - oAuthKeyData: .init( - evmAddress: oAuthKeyAddress, - X: oAuthPubKeyX, - Y: oAuthPubKeyY, - privKey: oAuthKey - ), - sessionData: .init( - sessionTokenData: sessionTokenData, - sessionAuthKey: try sessionAuthKey.serialize().addLeading0sForLength64() - ), - metadata: .init( - pubNonce: pubKeyNonceResult, - nonce: BigUInt(metadataNonce), - typeOfUser: typeOfUser, - upgraded: isUpgraded - ), - nodesData: .init(nodeIndexes: nodeIndexes) - ) - } - } - throw TorusUtilError.retrieveOrImportShareError - } - - // MARK: - commitment request - - internal func commitmentRequest(endpoints: [String], verifier: String, pubKeyX: String, pubKeyY: String, timestamp: String, tokenCommitment: String) async throws -> [CommitmentRequestResponse] { - let session = createURLSession() - - let threshold = Int(endpoints.count / 4) * 3 + 1 - let encoder = JSONEncoder() - var failedLookUpCount = 0 - let jsonRPCRequest = JSONRPCrequest( - method: JRPC_METHODS.COMMITMENT_REQUEST, - params: ["messageprefix": "mug00", - "tokencommitment": tokenCommitment, - "temppubx": pubKeyX, - "temppuby": pubKeyY, - "verifieridentifier": verifier, - "timestamp": timestamp] - ) - - guard let rpcdata = try? encoder.encode(jsonRPCRequest) - else { - throw TorusUtilError.runtime("Unable to encode request. \(jsonRPCRequest)") - } - - // Build promises array - var nodeSignatures = [CommitmentRequestResponse]() - var requestArr = [URLRequest]() - for (_, el) in endpoints.enumerated() { - var rq = try makeUrlRequest(url: el) - rq.httpBody = rpcdata - requestArr.append(rq) - } - return try await withThrowingTaskGroup(of: Result.self, body: { group in - - for (i, rq) in requestArr.enumerated() { - group.addTask { - do { - let val = try await session.data(for: rq) - return .success(.init(data: val.0, urlResponse: val.1, index: i)) - } catch { - return .failure(error) - } - } - } - - for try await val in group { - do { - try Task.checkCancellation() - switch val { - case let .success(model): - let data = model.data - let decoded = try JSONDecoder().decode(JSONRPCresponse.self, from: data) - os_log("commitmentRequest - reponse: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .info), type: .info, decoded.message ?? "") - - // TODO: this error block can't catch error - if decoded.error != nil { - os_log("commitmentRequest - error: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .error), type: .error, decoded.error?.message ?? "") - throw TorusUtilError.runtime(decoded.error?.message ?? "") - } - - // Ensure that we don't add bad data to result arrays. - guard - let response = decoded.result as? CommitmentRequestResponse - else { - throw TorusUtilError.decodingFailed("CommitmentRequestResponse could not be decoded") - } - - // Check if k+t responses are back - let val = CommitmentRequestResponse(data: response.data, nodepubx: response.nodepubx, nodepuby: response.nodepuby, signature: response.signature) - nodeSignatures.append(val) - if nodeSignatures.count >= threshold { - os_log("commitmentRequest - nodeSignatures: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .debug), type: .debug, nodeSignatures) - session.invalidateAndCancel() - return nodeSignatures - } - case let .failure(error): - os_log("commitmentRequest - error: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .error), type: .error, error.localizedDescription) - } - } catch { - failedLookUpCount += 1 - os_log("commitmentRequest - error: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .error), type: .error, error.localizedDescription) - if failedLookUpCount > endpoints.count - threshold { - os_log("commitmentRequest - error: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .error), type: .error, TorusUtilError.runtime("threshold node unavailable").localizedDescription) - session.invalidateAndCancel() - throw error - } - } - } - throw TorusUtilError.commitmentRequestFailed - }) - } - - internal func convertMetadataToNonce(params: [String: Any]?) -> BigUInt { - guard let params = params, let message = params["message"] as? String else { - return BigUInt(0) - } - return BigUInt(message, radix: 16)! - } - - internal func decryptNodeData(eciesData: EciesHex, ciphertextHex: String, privKey: String) throws -> String { - let eciesOpts = ECIES( - iv: eciesData.iv, - ephemPublicKey: eciesData.ephemPublicKey, - ciphertext: ciphertextHex, - mac: eciesData.mac - ) - - let decryptedSigBuffer = try decrypt(privateKey: privKey, opts: eciesOpts).hexString - return decryptedSigBuffer - } - - public func encryptData(privkeyHex: String, _ dataToEncrypt: String) throws -> String { - let privKey = try SecretKey(hex: privkeyHex) - let pubKey = try privKey.toPublic().serialize(compressed: false) - let encParams = try encrypt(publicKey: pubKey, msg: dataToEncrypt, opts: nil) - let data = try JSONEncoder().encode(encParams) - guard let string = String(data: data, encoding: .utf8) else { throw TorusUtilError.runtime("Invalid String from enc Params") } - return string - } - - internal func randomBytes(ofLength length: Int) throws -> [UInt8] { - var bytes = [UInt8](repeating: 0, count: length) - let status = SecRandomCopyBytes(kSecRandomDefault, length, &bytes) - if status == errSecSuccess { - return bytes - } - throw TorusUtilError.runtime("Failed to generate secure random bytes") - } - - public func encrypt(publicKey: String, msg: String, opts: Ecies? = nil) throws -> Ecies { - guard let data = msg.data(using: .utf8) else { - throw TorusUtilError.runtime("Encryption: Invalid utf8 string") - } - let curveMsg = try Encryption.encrypt(pk: PublicKey(hex: publicKey), plainText: data) - return try .init(iv: curveMsg.iv(), ephemPublicKey: curveMsg.ephemeralPublicKey().serialize(compressed: false), ciphertext: curveMsg.chipherText(), mac: curveMsg.mac()) - } - - // MARK: - decrypt shares - - internal func decryptIndividualShares(shares: [Int: RetrieveDecryptAndReconstuctResponseModel], privateKey: String) throws -> [Int: String] { - var result = [Int: String]() - - for (_, el) in shares.enumerated() { - let nodeIndex = el.key - - guard - let data = Data(base64Encoded: el.value.share), - let share = String(data: data, encoding: .utf8) - else { - throw TorusUtilError.decryptionFailed - } - - let ecies: ECIES = .init(iv: el.value.iv, ephemPublicKey: el.value.ephemPublicKey, ciphertext: share, mac: el.value.mac) - result[nodeIndex] = try decrypt(privateKey: privateKey, opts: ecies).toHexString() - - if shares.count == result.count { - return result - } - } - throw TorusUtilError.runtime("decryptIndividualShares func failed") - } - - // MARK: - Lagrange interpolation - - internal func thresholdLagrangeInterpolation(data filteredData: [Int: String], endpoints: [String], lookupPubkeyX: String, lookupPubkeyY: String) throws -> (String, String, String) { - // all possible combinations of share indexes to interpolate - let shareCombinations = combinations(elements: Array(filteredData.keys), k: Int(endpoints.count / 2) + 1) - for shareIndexSet in shareCombinations { - var sharesToInterpolate: [Int: String] = [:] - shareIndexSet.forEach { sharesToInterpolate[$0] = filteredData[$0] } - do { - let data = try lagrangeInterpolation(shares: sharesToInterpolate) - let finalPrivateKey = try SecretKey(hex: data) - let finalPublicKey = try finalPrivateKey.toPublic().serialize(compressed: false) - // Split key in 2 parts, X and Y - let pubKeyX = String(finalPublicKey.suffix(128).prefix(64)) - let pubKeyY = String(finalPublicKey.suffix(64)) - os_log("retrieveDecryptAndReconstuct: private key rebuild %@ %@ %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .debug), type: .debug, data, pubKeyX, pubKeyY) - - // Verify - if pubKeyX == lookupPubkeyX && pubKeyY == lookupPubkeyY { - return (pubKeyX, pubKeyY, data) - } else { - os_log("retrieveDecryptAndReconstuct: verification failed", log: getTorusLogger(log: TorusUtilsLogger.core, type: .error), type: .error) - } - } catch { - os_log("retrieveDecryptAndReconstuct: lagrangeInterpolation: err: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .error), type: .error, error.localizedDescription) - } - } - throw TorusUtilError.interpolationFailed - } - - internal func lagrangeInterpolation(shares: [Int: String], offset: Int = 1) throws -> String { - let CurveSecp256k1N = modulusValue - - // Convert shares to BigInt(Shares) - var shareList = [BigInt: BigInt]() - _ = shares.map { shareList[BigInt($0.key + offset)] = BigInt($0.value.addLeading0sForLength64(), radix: 16) } - - var secret = BigUInt("0") // to support BigInt 4.0 dependency on cocoapods - var sharesDecrypt = 0 - - for (i, share) in shareList { - var upper = BigInt(1) - var lower = BigInt(1) - for (j, _) in shareList { - if i != j { - let negatedJ = j * BigInt(-1) - upper = upper * negatedJ - upper = upper.modulus(CurveSecp256k1N) - - var temp = i - j - temp = temp.modulus(CurveSecp256k1N) - lower = (lower * temp).modulus(CurveSecp256k1N) - } - } - guard - let inv = lower.inverse(CurveSecp256k1N) - else { - throw TorusUtilError.decryptionFailed - } - var delta = (upper * inv).modulus(CurveSecp256k1N) - delta = (delta * share).modulus(CurveSecp256k1N) - secret = BigUInt((BigInt(secret) + delta).modulus(CurveSecp256k1N)) - sharesDecrypt += 1 - } - let secretString = String(secret.serialize().hexa.suffix(64)) - if sharesDecrypt == shareList.count { - return secretString - } else { - throw TorusUtilError.interpolationFailed - } - } - - // MARK: - getPubKeyOrKeyAssign - - internal func getPubKeyOrKeyAssign(endpoints: [String], verifier: String, verifierId: String, extendedVerifierId: String? = nil) async throws -> KeyLookupResult { - // Encode data - let encoder = JSONEncoder() - let session = createURLSession() - let threshold = (endpoints.count / 2) + 1 - var failedLookupCount = 0 - - // flag to check if node with index 1 is queried for metadata - var isNodeOneVisited = false - - let methodName = JRPC_METHODS.GET_OR_SET_KEY - - let params = GetPublicAddressOrKeyAssignParams(verifier: verifier, verifier_id: verifierId, extended_verifier_id: extendedVerifierId, one_key_flow: true, fetch_node_index: true) - - let jsonRPCRequest = JSONRPCrequest( - method: methodName, - params: params - ) - - guard let rpcdata = try? encoder.encode(jsonRPCRequest) - - else { - throw TorusUtilError.encodingFailed("\(jsonRPCRequest)") - } - - // Create Array of URLRequest Promises - - var resultArray: [KeyLookupResponse] = [] - var requestArray = [URLRequest]() - for endpoint in endpoints { - var request = try makeUrlRequest(url: endpoint) - request.httpBody = rpcdata - requestArray.append(request) - } - - var nonceResult: GetOrSetNonceResult? - var nodeIndexesArray: [Int] = [] - var keyArray: [VerifierLookupResponse?] = [] - - return try await withThrowingTaskGroup(of: Result.self, returning: KeyLookupResult.self) { group in - - for (i, rq) in requestArray.enumerated() { - group.addTask { - do { - let val = try await session.data(for: rq) - return .success(.init(data: val.0, urlResponse: val.1, index: i)) - } catch { - return .failure(error) - } - } - } - - // this is serial execution - // TODO: convert this to some function implementation as we do in web - for try await val in group { - do { - switch val { - case let .success(model): - // print( try JSONSerialization.jsonObject(with: model.data) ) - let data = model.data - let decoded = try JSONDecoder().decode(JSONRPCresponse.self, from: data) // User decoder to covert to struct - let result = decoded.result as? VerifierLookupResponse - - if let _ = decoded.error { - let error = KeyLookupError.createErrorFromString(errorString: "") - throw error - } else { - let decodedResult = result! - keyArray.append(decodedResult) - if let k = decodedResult.keys, - let key = k.first { - let model = KeyLookupResponse(pubKeyX: key.pub_key_X, pubKeyY: key.pub_key_Y, address: key.address, isNewKey: decodedResult.is_new_key) - - resultArray.append(model) - if let nonceData = key.nonce_data { - let pubNonceX = nonceData.pubNonce?.x - if pubNonceX != nil && pubNonceX != "" && nonceResult == nil { - nonceResult = key.nonce_data - } - } - } - } - let keyResult = thresholdSame(arr: resultArray, threshold: threshold) // Check if threshold is satisfied - - // proceed if we have key result and either of nonceResult, extendedVerifierId, isLegacyNetwork is - // available - if keyResult != nil && (nonceResult != nil || extendedVerifierId != nil || isLegacyNetwork()) { - if let keyResult = keyResult { - os_log("%@: fulfill: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .debug), type: .debug, methodName, keyResult.description) - session.invalidateAndCancel() - keyArray.forEach({ result in - - if result?.node_index == "1" { - isNodeOneVisited = true - } - if result != nil && result?.node_index != "0" { - nodeIndexesArray.append(Int(result!.node_index)!) - } - - }) - - return KeyLookupResult(keyResult: keyResult, nodeIndexes: nodeIndexesArray, nonceResult: nonceResult) - } - } - throw NSError(domain: "condition not meet", code: 1001) - case let .failure(error): - throw error - } - } catch { - failedLookupCount += 1 - os_log("%@: err: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .error), type: .error, methodName, error.localizedDescription) - - if (isNodeOneVisited && failedLookupCount > (endpoints.count - threshold)) || (failedLookupCount == endpoints.count) { - os_log("%@: err: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .error), type: .error, methodName, TorusUtilError.runtime("threshold nodes unavailable").localizedDescription) - session.invalidateAndCancel() - throw error - } - } - } - - throw TorusUtilError.runtime("\(methodName) func failed") - } - } - - // MARK: - keylookup - - internal func awaitKeyLookup(endpoints: [String], verifier: String, verifierId: String, timeout: Int = 0) async throws -> KeyLookupResponse { - let durationInNanoseconds = UInt64(timeout * 1000000000) - try await Task.sleep(nanoseconds: durationInNanoseconds) - return try await keyLookup(endpoints: endpoints, verifier: verifier, verifierId: verifierId) - } - - internal func awaitLegacyKeyLookup(endpoints: [String], verifier: String, verifierId: String, timeout: Int = 0) async throws -> LegacyKeyLookupResponse { - let durationInNanoseconds = UInt64(timeout * 1000000000) - try await Task.sleep(nanoseconds: durationInNanoseconds) - return try await legacyKeyLookup(endpoints: endpoints, verifier: verifier, verifierId: verifierId) - } - - internal func legacyKeyLookup(endpoints: [String], verifier: String, verifierId: String) async throws -> LegacyKeyLookupResponse { - // Enode data - let encoder = JSONEncoder() - let session = createURLSession() - let threshold = (endpoints.count / 2) + 1 - var failedLookupCount = 0 - let jsonRPCRequest = JSONRPCrequest( - method: JRPC_METHODS.LEGACY_VERIFIER_LOOKUP_REQUEST, - params: ["verifier": verifier, "verifier_id": verifierId]) - guard let rpcdata = try? encoder.encode(jsonRPCRequest) - else { - throw TorusUtilError.encodingFailed("\(jsonRPCRequest)") - } - var allowHostRequest = try makeUrlRequest(url: allowHost, httpMethod: .get) - allowHostRequest.addValue("torus-default", forHTTPHeaderField: "x-api-key") - allowHostRequest.addValue(verifier, forHTTPHeaderField: "Origin") - do { - _ = try await session.data(for: allowHostRequest) - } catch { - os_log("KeyLookup: signer allow: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .error), type: .error, error.localizedDescription) - throw error - } - - // Create Array of URLRequest Promises - - var resultArray = [LegacyKeyLookupResponse]() - var requestArray = [URLRequest]() - for endpoint in endpoints { - var request = try makeUrlRequest(url: endpoint) - request.httpBody = rpcdata - requestArray.append(request) - } - - return try await withThrowingTaskGroup(of: Result.self, body: { [unowned self] group in - for (i, rq) in requestArray.enumerated() { - group.addTask { - do { - let val = try await session.data(for: rq) - return .success(.init(data: val.0, urlResponse: val.1, index: i)) - } catch { - return .failure(error) - } - } - } - - for try await val in group { - do { - switch val { - case let .success(model): - let data = model.data - let decoded = try JSONDecoder().decode(JSONRPCresponse.self, from: data) // User decoder to covert to struct - os_log("keyLookup: API response: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .debug), type: .debug, "\(decoded)") - - let result = decoded.result - let error = decoded.error - if let _ = error { - let error = KeyLookupError.createErrorFromString(errorString: decoded.error?.data ?? "") - throw error - } else { - guard - let decodedResult = result as? [String: [[String: String]]], - let k = decodedResult["keys"], - let keys = k.first, - let pubKeyX = keys["pub_key_X"], - let pubKeyY = keys["pub_key_Y"], - let keyIndex = keys["key_index"], - let address = keys["address"] - else { - throw TorusUtilError.decodingFailed("keys not found in \(result ?? "")") - } - let model = LegacyKeyLookupResponse(pubKeyX: pubKeyX, pubKeyY: pubKeyY, keyIndex: keyIndex, address: address) - resultArray.append(model) - } - let keyResult = thresholdSame(arr: resultArray, threshold: threshold) // Check if threshold is satisfied - - if let keyResult = keyResult { - os_log("keyLookup: fulfill: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .debug), type: .debug, keyResult.description) - session.invalidateAndCancel() - return keyResult - } - case let .failure(error): - throw error - } - } catch { - failedLookupCount += 1 - os_log("keyLookup: err: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .error), type: .error, error.localizedDescription) - if failedLookupCount > (endpoints.count - threshold) { - os_log("keyLookup: err: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .error), type: .error, TorusUtilError.runtime("threshold nodes unavailable").localizedDescription) - session.invalidateAndCancel() - throw error - } - } - } - throw TorusUtilError.runtime("keyLookup func failed") - }) - } - - internal func keyLookup(endpoints: [String], verifier: String, verifierId: String) async throws -> KeyLookupResponse { - // Enode data - let encoder = JSONEncoder() - let session = createURLSession() - let threshold = (endpoints.count / 2) + 1 - var failedLookupCount = 0 - let jsonRPCRequest = JSONRPCrequest( - method: JRPC_METHODS.LEGACY_VERIFIER_LOOKUP_REQUEST, - params: ["verifier": verifier, "verifier_id": verifierId]) - guard let rpcdata = try? encoder.encode(jsonRPCRequest) - else { - throw TorusUtilError.encodingFailed("\(jsonRPCRequest)") - } - var allowHostRequest = try makeUrlRequest(url: allowHost, httpMethod: .get) - allowHostRequest.addValue("torus-default", forHTTPHeaderField: "x-api-key") - allowHostRequest.addValue(verifier, forHTTPHeaderField: "Origin") - do { - _ = try await session.data(for: allowHostRequest) - } catch { - os_log("KeyLookup: signer allow: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .error), type: .error, error.localizedDescription) - throw error - } - - // Create Array of URLRequest Promises - - var resultArray = [KeyLookupResponse]() - var requestArray = [URLRequest]() - for endpoint in endpoints { - var request = try makeUrlRequest(url: endpoint) - request.httpBody = rpcdata - requestArray.append(request) - } - - return try await withThrowingTaskGroup(of: Result.self, body: { [unowned self] group in - for (i, rq) in requestArray.enumerated() { - group.addTask { - do { - let val = try await session.data(for: rq) - return .success(.init(data: val.0, urlResponse: val.1, index: i)) - } catch { - return .failure(error) - } - } - } - - for try await val in group { - do { - switch val { - case let .success(model): - let data = model.data - let decoded = try JSONDecoder().decode(JSONRPCresponse.self, from: data) // User decoder to covert to struct - os_log("keyLookup: API response: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .debug), type: .debug, "\(decoded)") - - // result of decoded data - let result = decoded.result - let error = decoded.error - if let _ = error { - let error = KeyLookupError.createErrorFromString(errorString: decoded.error?.data ?? "") - throw error - } else { - guard - let decodedResult = result as? [String: [[String: Any]]], - - let k = decodedResult["keys"], - let keys = k.first, - let pubKeyX = keys["pub_key_X"] as? String, - let pubKeyY = keys["pub_key_Y"] as? String, - let address = keys["address"] as? String - else { - throw TorusUtilError.decodingFailed("key not found") - } - let isNewKey = keys["is_new_key"] as? Bool ?? false - let model = KeyLookupResponse(pubKeyX: pubKeyX, pubKeyY: pubKeyY, address: address, isNewKey: isNewKey) - resultArray.append(model) - } - let keyResult = thresholdSame(arr: resultArray, threshold: threshold) // Check if threshold is satisfied - - if let keyResult = keyResult { - os_log("keyLookup: fulfill: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .debug), type: .debug, keyResult.description) - session.invalidateAndCancel() - return keyResult - } - case let .failure(error): - throw error - } - } catch { - failedLookupCount += 1 - os_log("keyLookup: err: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .error), type: .error, error.localizedDescription) - if failedLookupCount > (endpoints.count - threshold) { - os_log("keyLookup: err: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .error), type: .error, TorusUtilError.runtime("threshold nodes unavailable").localizedDescription) - session.invalidateAndCancel() - throw error - } - } - } - throw TorusUtilError.runtime("keyLookup func failed") - }) - } - - // MARK: - key assignment - - internal func keyAssign(endpoints: [String], torusNodePubs: [TorusNodePubModel], verifier: String, verifierId: String, signerHost: String, network: TorusNetwork, firstPoint: Int? = nil, lastPoint: Int? = nil) async throws -> JSONRPCresponse { - var nodeNum: Int = 0 - var initialPoint: Int = 0 - os_log("KeyAssign: endpoints: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .debug), type: .debug, endpoints) - if let safeLastPoint = lastPoint { - nodeNum = safeLastPoint % endpoints.count - } else { - nodeNum = Int(floor(Double(Double(arc4random_uniform(1)) * Double(endpoints.count)))) - } - if nodeNum == firstPoint { - throw TorusUtilError.runtime("Looped through all") - } - if let safefirstPoint = firstPoint { - initialPoint = safefirstPoint - } - - let encoder = JSONEncoder() - if #available(macOS 10.13, *) { - encoder.outputFormatting = .sortedKeys - } else { - // Fallback on earlier versions - } - os_log("newEndpoints2 : %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .debug), type: .debug, endpoints) - - let SignerObject = JSONRPCrequest(method: JRPC_METHODS.LEGACY_KEY_ASSIGN, params: ["verifier": verifier, "verifier_id": verifierId]) - let rpcdata = try encoder.encode(SignerObject) - var request = try makeUrlRequest(url: signerHost) - request.addValue(torusNodePubs[nodeNum].getX().lowercased(), forHTTPHeaderField: "pubKeyX") - request.addValue(torusNodePubs[nodeNum].getY().lowercased(), forHTTPHeaderField: "pubKeyY") - switch network { - case let .legacy(network): request.addValue(network.path, forHTTPHeaderField: "network") - case let .sapphire(network): request.addValue(network.path, forHTTPHeaderField: "network") - } - - request.httpBody = rpcdata - do { - let responseFromSignerData: (Data, URLResponse) = try await urlSession.data(for: request) - let decodedSignerResponse = try JSONDecoder().decode(SignerResponse.self, from: responseFromSignerData.0) - os_log("KeyAssign: responseFromSigner: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .debug), type: .debug, "\(decodedSignerResponse)") - let keyassignRequest = KeyAssignRequest(params: ["verifier": verifier, "verifier_id": verifierId], signerResponse: decodedSignerResponse) - // Combine signer respose and request data - encoder.outputFormatting = .sortedKeys - let newData = try encoder.encode(keyassignRequest) - var request2 = try makeUrlRequest(url: endpoints[nodeNum]) - request2.httpBody = newData - let keyAssignRequestData: (Data, URLResponse) = try await urlSession.data(for: request2) - do { - let decodedData = try JSONDecoder().decode(JSONRPCresponse.self, from: keyAssignRequestData.0) // User decoder to covert to struct - - os_log("keyAssign: fullfill: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .debug), type: .debug, "\(decodedData)") - return decodedData - } catch let err { - throw TorusUtilError.decodingFailed(err.localizedDescription) - } - } catch { - os_log("KeyAssign: err: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .error), type: .error, "\(error)") - return try await keyAssign(endpoints: endpoints, torusNodePubs: torusNodePubs, verifier: verifier, verifierId: verifierId, signerHost: signerHost, network: network, firstPoint: initialPoint, lastPoint: nodeNum + 1) - } - } - - internal func generateNonceMetadataParams(message: String, privateKey: BigInt, nonce: BigInt?) throws -> NonceMetadataParams { - let privKey = try SecretKey(hex: privateKey.magnitude.serialize().hexString.addLeading0sForLength64()) - let publicKey = try privKey.toPublic().serialize(compressed: false) - - let timeStamp = String(BigUInt(serverTimeOffset + Date().timeIntervalSince1970), radix: 16) - var setData: NonceMetadataParams.SetNonceData = .init(data: message, timestamp: timeStamp) - if nonce != nil { - setData.data = String(nonce!, radix: 16).addLeading0sForLength64() - } - let encoder = JSONEncoder() - encoder.outputFormatting = .sortedKeys - let encodedData = try JSONEncoder() - .encode(setData) - let hash = keccak256Data(encodedData).hexString - let sigData = try ECDSA.signRecoverable(key: privKey, hash: hash).serialize() - - return .init(pub_key_X: String(publicKey.suffix(128).prefix(64)), pub_key_Y: String(publicKey.suffix(64)), setData: setData, signature: Data(hex: sigData).base64EncodedString()) - } - - internal func getPublicKeyPointFromPubkeyString(pubKey: String) throws -> (String, String) { - let publicKeyHashData = Data(hex: pubKey.strip04Prefix()) - if !(publicKeyHashData.count == 64) { - throw TorusUtilError.invalidKeySize - } - - let xCoordinateData = publicKeyHashData.prefix(32).toHexString() - let yCoordinateData = publicKeyHashData.suffix(32).toHexString() - - return (xCoordinateData, yCoordinateData) - } - - internal func combinePublicKeys(keys: [String], compressed: Bool) throws -> String { - let collection = PublicKeyCollection() - for item in keys { - let pk = try PublicKey(hex: item) - try collection.insert(key: pk) - } - - let added = try PublicKey.combine(collection: collection).serialize(compressed: compressed) - return added - } - - internal func formatLegacyPublicData(finalKeyResult: KeyLookupResponse, enableOneKey: Bool, isNewKey: Bool) async throws -> TorusPublicKey { - var finalPubKey: String = "" - var nonce: BigUInt = 0 - var typeOfUser: TypeOfUser = .v1 - var pubNonce: PubNonce? - var result: TorusPublicKey - var nonceResult: GetOrSetNonceResult? - let pubKeyX = finalKeyResult.pubKeyX - let pubKeyY = finalKeyResult.pubKeyY - let (oAuthX, oAuthY) = (pubKeyX.addLeading0sForLength64(), pubKeyY.addLeading0sForLength64()) - if enableOneKey { - nonceResult = try await getOrSetNonce(x: pubKeyX, y: pubKeyY, privateKey: nil, getOnly: !isNewKey) - nonce = BigUInt(nonceResult?.nonce ?? "0") ?? 0 - typeOfUser = .init(rawValue: nonceResult?.typeOfUser ?? ".v1") ?? .v1 - if typeOfUser == .v1 { - finalPubKey = (pubKeyX.addLeading0sForLength64() + pubKeyY.addLeading0sForLength64()).add04Prefix() - if nonce != BigInt(0) { - let noncePrivateKey = try SecretKey(hex: BigUInt(nonce).magnitude.serialize().addLeading0sForLength64().hexString) - let noncePublicKey = try noncePrivateKey.toPublic().serialize(compressed: false) - finalPubKey = try combinePublicKeys(keys: [finalPubKey, noncePublicKey], compressed: false) - } else { - finalPubKey = String(finalPubKey) - } - } else if typeOfUser == .v2 { - pubNonce = nonceResult?.pubNonce - if nonceResult?.upgraded ?? false { - finalPubKey = (pubKeyX.addLeading0sForLength64() + pubKeyY.addLeading0sForLength64()).add04Prefix() - } else { - guard nonceResult?.pubNonce != nil else { throw TorusUtilError.decodingFailed("No pub nonce found") } - finalPubKey = (pubKeyX.addLeading0sForLength64() + pubKeyY.addLeading0sForLength64()).add04Prefix() - let ecpubKeys = ((nonceResult?.pubNonce!.x.addLeading0sForLength64())! + (nonceResult?.pubNonce!.y.addLeading0sForLength64())!).add04Prefix() - finalPubKey = try combinePublicKeys(keys: [finalPubKey, ecpubKeys], compressed: false) - } - finalPubKey = String(finalPubKey.suffix(128)) - } else { - throw TorusUtilError.runtime("getOrSetNonce should always return typeOfUser.") - } - } else { - typeOfUser = .v1 - let localNonce = try await getMetadata(dictionary: ["pub_key_X": pubKeyX, "pub_key_Y": pubKeyY]) - nonce = localNonce - let localPubkeyX = finalKeyResult.pubKeyX - let localPubkeyY = finalKeyResult.pubKeyY - finalPubKey = (localPubkeyX.addLeading0sForLength64() + localPubkeyY.addLeading0sForLength64()).add04Prefix() - if localNonce != BigInt(0) { - let nonce2 = BigInt(localNonce) - let noncePrivateKey = try SecretKey(hex: BigUInt(nonce2).magnitude.serialize().addLeading0sForLength64().hexString) - let noncePublicKey = try noncePrivateKey.toPublic().serialize(compressed: false) - finalPubKey = try combinePublicKeys(keys: [finalPubKey, noncePublicKey], compressed: false) - } else { - finalPubKey = String(finalPubKey) - } - } - let finalX = String(finalPubKey.suffix(128).prefix(64)) - let finalY = String(finalPubKey.suffix(64)) - - let oAuthAddress = generateAddressFromPubKey(publicKeyX: oAuthX, publicKeyY: oAuthY) - let finalAddress = generateAddressFromPubKey(publicKeyX: finalX, publicKeyY: finalY) - - var usertype = "" - switch typeOfUser { - case .v1: - usertype = "v1" - case .v2: - usertype = "v2" - } - - result = TorusPublicKey( - finalKeyData: .init( - evmAddress: finalAddress, - X: finalX.addLeading0sForLength64(), - Y: finalY.addLeading0sForLength64() - ), - oAuthKeyData: .init( - evmAddress: oAuthAddress, - X: oAuthX.addLeading0sForLength64(), - Y: oAuthY.addLeading0sForLength64() - ), - metadata: .init( - pubNonce: pubNonce, - nonce: nonce, - typeOfUser: UserType(rawValue: usertype)!, - upgraded: nonceResult?.upgraded ?? false - ), - nodesData: .init(nodeIndexes: []) - ) - return result - } - - internal func tupleToArray(_ tuple: Any) -> [UInt8] { - let tupleMirror = Mirror(reflecting: tuple) - let tupleElements = tupleMirror.children.map({ $0.value as! UInt8 }) - return tupleElements - } - - public func decrypt(privateKey: String, opts: ECIES) throws -> Data { - let secret = try SecretKey(hex: privateKey) - let msg = try EncryptedMessage(cipherText: opts.ciphertext, ephemeralPublicKey: PublicKey(hex: opts.ephemPublicKey), iv: opts.iv, mac: opts.mac) - let result = try Encryption.decrypt(sk: secret, encrypted: msg) - return result - } -} - -extension Array where Element == UInt8 { - func uint8Reverse() -> Array { - var revArr = [Element]() - for arrayIndex in stride(from: count - 1, through: 0, by: -1) { - revArr.append(self[arrayIndex]) - } - return revArr - } -} diff --git a/Sources/TorusUtils/Helpers/Common.swift b/Sources/TorusUtils/Helpers/Common.swift index bcb548d4..e62140c4 100644 --- a/Sources/TorusUtils/Helpers/Common.swift +++ b/Sources/TorusUtils/Helpers/Common.swift @@ -1,17 +1,96 @@ import BigInt import Foundation +#if canImport(curveSecp256k1) + import curveSecp256k1 +#endif -import curveSecp256k1 +internal func normalizeKeysResult(result: VerifierLookupResponse) -> KeyLookupResult.KeyResult { + var finalResult = KeyLookupResult.KeyResult(is_new_key: result.is_new_key) -func keccak256Data(_ data: Data) -> Data { - let hash = try? keccak256(data: data) - return hash ?? Data([]) + if !result.keys.isEmpty { + let finalKey = result.keys[0] + finalResult.keys = [ + VerifierLookupResponse.Key( + pub_key_X: finalKey.pub_key_X, + pub_key_Y: finalKey.pub_key_Y, + address: finalKey.address + ), + ] + } + + return finalResult +} + +internal func kCombinations(elements: ArraySlice, k: Int) -> [[T]] { + if k == 0 || k > elements.count { + return [] + } + + if k == elements.count { + return [Array(elements)] + } + + if k == 1 { + return elements.map { [$0] } + } + + var combs: [[T]] = [] + var tailCombs: [[T]] = [] + + for i in 0 ... (elements.count - k + 1) { + tailCombs = kCombinations(elements: elements[(elements.startIndex + i + 1)...], k: k - 1) + for item in tailCombs { + var extended = [elements[elements.startIndex + i]] + extended.append(contentsOf: item) + combs.append(extended) + } + } + + return combs +} + +internal func thresholdSame(arr: [T], threshold: Int) throws -> T? { + var hashmap = [String: Int]() + let jsonEncoder = JSONEncoder() + jsonEncoder.outputFormatting = .sortedKeys + for (_, value) in arr.enumerated() { + guard let jsonString = String(data: try jsonEncoder.encode(value), encoding: .utf8) else { throw TorusUtilError.encodingFailed("thresholdSame") + } + if let _ = hashmap[jsonString] { + hashmap[jsonString]! += 1 + } else { + hashmap[jsonString] = 1 + } + if hashmap[jsonString] == threshold { + return value + } + } + return nil +} + +internal func calculateMedian(arr: [Int]) -> Int { + let arrLen = arr.count + + if arrLen == 0 { + return 0 + } + + var sortedArr = arr + sortedArr = arr.sorted() + + if (arrLen % 2) != 0 { + return sortedArr[Int(floor(Double(arrLen / 2 - 1)))] + } + + let mid1 = sortedArr[Int(floor(Double(arrLen / 2 - 1)))] + let mid2 = sortedArr[Int(floor(Double(arrLen / 2)))] + + return (mid1 + mid2) / 2 } -func generateAddressFromPubKey(publicKeyX: String, publicKeyY: String) -> String { - let publicKeyHex = publicKeyX.addLeading0sForLength64() + publicKeyY.addLeading0sForLength64() - let publicKeyData = Data(hex: publicKeyHex) - let ethAddrData = keccak256Data(publicKeyData).suffix(20) - let ethAddrlower = ethAddrData.toHexString().addHexPrefix() - return ethAddrlower.toChecksumAddress() +internal func getProxyCoordinatorEndpointIndex(endpoints: [String], verifier: String, verifierId: String) throws -> BigUInt { + let verifierIdString = verifier + verifierId + let hashedVerifierId = try KeyUtils.keccak256Data(verifierIdString) + let proxyEndPointNum = BigInt(hashedVerifierId, radix: 16)!.modulus(BigInt(endpoints.count)) + return proxyEndPointNum.magnitude } diff --git a/Sources/TorusUtils/Helpers/Error.swift b/Sources/TorusUtils/Helpers/Error.swift index 943dcea0..a11f87ba 100644 --- a/Sources/TorusUtils/Helpers/Error.swift +++ b/Sources/TorusUtils/Helpers/Error.swift @@ -2,27 +2,21 @@ import Foundation public enum TorusUtilError: Error, Equatable { case configurationError - case apiRequestFailed - case errInResponse(Any) - case encodingFailed(String? = nil) - case decodingFailed(String? = nil) + case encodingFailed(String = "") + case decodingFailed(String = "") case commitmentRequestFailed case importShareFailed case decryptionFailed - case thresholdError - case promiseFulfilled case privateKeyDeriveFailed - case timeout - case missingNodePubKeyError - case unableToDerive case interpolationFailed - case nodesUnavailable case invalidKeySize + case invalidPubKeySize case runtime(_ msg: String) case retrieveOrImportShareError case metadataNonceMissing - case gatingError(_ msg: String? = nil) - case empty + case pubNonceMissing + case gatingError(_ msg: String = "") + case invalidInput } extension TorusUtilError: CustomDebugStringConvertible { @@ -30,48 +24,36 @@ extension TorusUtilError: CustomDebugStringConvertible { switch self { case .configurationError: return "SDK Configuration incorrect. Network is probably incorrect" - case .apiRequestFailed: - return "API request failed or No response from the node" case let .decodingFailed(response): - return "JSON Decoding error \(response ?? "")" - case let .errInResponse(str): - return "API response error \(str)" + return "JSON Decoding error" + response case .decryptionFailed: return "Decryption Failed" case .commitmentRequestFailed: return "commitment request failed" case .importShareFailed: return "import share failed" - case .thresholdError: - return "Threshold error" - case .promiseFulfilled: - return "Promise fulfilled" case .privateKeyDeriveFailed: return "could not derive private key" - case .timeout: - return "Timeout" - case .missingNodePubKeyError: - return "Missing node pub key for node index" - case .unableToDerive: - return "could not derive private key" case .interpolationFailed: return "lagrange interpolation failed" - case .nodesUnavailable: - return "One or more nodes unavailable" - case .empty: - return "" + case .invalidInput: + return "Input was found to be invalid" case let .runtime(msg): return msg case .invalidKeySize: return "Invalid key size. Expected 32 bytes" + case .invalidPubKeySize: + return "Invalid key size. Expected 64 bytes" case let .encodingFailed(msg): - return "Could not encode data \(msg ?? "")" + return "Could not encode data" + msg case .retrieveOrImportShareError: return "retrieve or import share failed" case .metadataNonceMissing: return "Unable to fetch metadata nonce" case let .gatingError(msg): - return "could not process request \(msg ?? "")" + return "could not process request" + msg + case .pubNonceMissing: + return "Public nonce is missing" } } @@ -88,38 +70,24 @@ extension TorusUtilError: LocalizedError { switch self { case .configurationError: return "SDK Configuration incorrect. Network is probably incorrect" - case .apiRequestFailed: - return "API request failed or No response from the node" case let .decodingFailed(response): - return "JSON Decoding error \(response ?? "")" - case let .errInResponse(str): - return "API response error \(str)" + return "JSON Decoding error" + response case .decryptionFailed: return "Decryption Failed" case .commitmentRequestFailed: return "commitment request failed" - case .thresholdError: - return "Threshold error" - case .promiseFulfilled: - return "Promise fulfilled" - case .timeout: - return "Timeout" - case .unableToDerive: - return "could not derive private key" case .interpolationFailed: return "lagrange interpolation failed" - case .nodesUnavailable: - return "One or more nodes unavailable" - case .empty: - return "" + case .invalidInput: + return "Input was found to be invalid" case let .runtime(msg): return msg case .invalidKeySize: return "Invalid key size. Expected 32 bytes" case let .encodingFailed(msg): - return "Could not encode data \(msg ?? "")" + return "Could not encode data " + msg case let .gatingError(msg): - return "\(msg ?? "")" + return msg default: return "default Error msg" } diff --git a/Sources/TorusUtils/Helpers/JSONRPCRequest.swift b/Sources/TorusUtils/Helpers/JSONRPCRequest.swift deleted file mode 100644 index 32478788..00000000 --- a/Sources/TorusUtils/Helpers/JSONRPCRequest.swift +++ /dev/null @@ -1,238 +0,0 @@ -import BigInt -import Foundation - -import AnyCodable -public struct GetPublicAddressOrKeyAssignParams: Encodable { - public var verifier: String - public var verifier_id: String - public var extended_verifier_id: String? - public var one_key_flow: Bool - public var fetch_node_index: Bool -} - -public struct SignerResponse: Codable { - public var torusNonce: String - public var torusSignature: String - public var torusTimestamp: String - - enum SignerResponseKeys: String, CodingKey { - case torusNonce = "torus-nonce" - case torusTimestamp = "torus-timestamp" - case torusSignature = "torus-signature" - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: SignerResponseKeys.self) - try container.encode(torusNonce, forKey: .torusNonce) - try container.encode(torusSignature, forKey: .torusSignature) - try container.encode(torusTimestamp, forKey: .torusTimestamp) - } - - public init(torusNonce: String, torusTimestamp: String, torusSignature: String) { - self.torusNonce = torusNonce - self.torusTimestamp = torusTimestamp - self.torusSignature = torusSignature - } - - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: SignerResponseKeys.self) - let nonce: String = try container.decode(String.self, forKey: .torusNonce) - let signature: String = try container.decode(String.self, forKey: .torusSignature) - let timestamp: String = try container.decode(String.self, forKey: .torusTimestamp) - self.init(torusNonce: nonce, torusTimestamp: timestamp, torusSignature: signature) - } -} - -public struct KeyAssignRequest: Encodable { - public var id: Int = 10 - public var jsonrpc: String = "2.0" - public var method: String = JRPC_METHODS.LEGACY_KEY_ASSIGN - public var params: Any - public var torusNonce: String - public var torusSignature: String - public var torusTimestamp: String - - enum KeyAssignRequestKeys: String, CodingKey { - case id - case jsonrpc - case method - case params - case torusNonce = "torus-nonce" - case torusTimestamp = "torus-timestamp" - case torusSignature = "torus-signature" - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: KeyAssignRequestKeys.self) - try container.encode(id, forKey: .id) - - try container.encode(jsonrpc, forKey: .jsonrpc) - try container.encode(method, forKey: .method) - - if let _ = params as? [String: String] { - try container.encode(params as! [String: String], forKey: .params) - } - if let _ = params as? [String: [String: [String: String]]] { - try container.encode(params as! [String: [String: [String: String]]], forKey: .params) - } - - try container.encode(torusNonce, forKey: .torusNonce) - try container.encode(torusTimestamp, forKey: .torusTimestamp) - try container.encode(torusSignature, forKey: .torusSignature) - } - - public init(params: Any, signerResponse: SignerResponse) { - self.params = params - torusNonce = signerResponse.torusNonce - torusSignature = signerResponse.torusSignature - torusTimestamp = signerResponse.torusTimestamp - } -} - -public indirect enum MixedValue: Codable { - case integer(Int) - case boolean(Bool) - case string(String) - case mixValue([String: MixedValue]) - case array([MixedValue]) - - public init(from decoder: Decoder) throws { - let container = try decoder.singleValueContainer() - if let value = try? container.decode(Bool.self) { - self = .boolean(value) - } else if let value = try? container.decode(Int.self) { - self = .integer(value) - } else if let value = try? container.decode(String.self) { - self = .string(value) - } else if let value = try? container.decode([String: MixedValue].self) { - self = .mixValue(value) - } else if let value = try? container.decode([MixedValue].self) { - self = .array(value) - } else { - throw DecodingError.dataCorruptedError(in: container, debugDescription: "Invalid mixed value") - } - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.singleValueContainer() - switch self { - case let .integer(value): - try container.encode(value) - case let .boolean(value): - try container.encode(value) - case let .string(value): - try container.encode(value) - case let .mixValue(value): - try container.encode(value) - case let .array(value): - try container.encode(value) - } - } -} - -/// JSON RPC request structure for serialization and deserialization purposes. -public struct JSONRPCrequest: Encodable { - public var jsonrpc: String = "2.0" - public var method: String - public var params: T - public var id: Int = 10 - - enum CodingKeys: String, CodingKey { - case jsonrpc - case method - case params - case id - } -} - -public struct JSONRPCresponse: Decodable { - public var id: Int - public var jsonrpc = "2.0" - public var result: Any? - public var error: ErrorMessage? - public var message: String? - - enum JSONRPCresponseKeys: String, CodingKey { - case id - case jsonrpc - case result - case error - case errorMessage - } - - public init(id: Int, jsonrpc: String, result: Decodable?, error: ErrorMessage?) { - self.id = id - self.jsonrpc = jsonrpc - self.result = result - self.error = error - } - - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: JSONRPCresponseKeys.self) - let id: Int = try container.decode(Int.self, forKey: .id) - let jsonrpc: String = try container.decode(String.self, forKey: .jsonrpc) - let errorMessage = try container.decodeIfPresent(ErrorMessage.self, forKey: .error) - if errorMessage != nil { - self.init(id: id, jsonrpc: jsonrpc, result: nil, error: errorMessage) - return - } - - var result: Decodable? - if let rawValue = try? container.decodeIfPresent(VerifierLookupResponse.self, forKey: .result) { - result = rawValue - } else if let rawValue = try? container.decodeIfPresent(ShareRequestResult.self, forKey: .result) { - result = rawValue - } else if let rawValue = try? container.decodeIfPresent(LegacyShareRequestResult.self, forKey: .result) { - result = rawValue - } else if let rawValue = try? container.decodeIfPresent(CommitmentRequestResponse.self, forKey: .result) { - result = rawValue - } else if let rawValue = try? container.decodeIfPresent(LegacyLookupResponse.self, forKey: .result) { - result = rawValue - } else if let rawValue = try? container.decodeIfPresent(String.self, forKey: .result) { - result = rawValue - } else if let rawValue = try? container.decodeIfPresent(Int.self, forKey: .result) { - result = rawValue - } else if let rawValue = try? container.decodeIfPresent(Bool.self, forKey: .result) { - result = rawValue - } else if let rawValue = try? container.decodeIfPresent([Bool].self, forKey: .result) { - result = rawValue - } else if let rawValue = try? container.decodeIfPresent([Int].self, forKey: .result) { - result = rawValue - } else if let rawValue = try? container.decodeIfPresent([String].self, forKey: .result) { - result = rawValue - } else if let rawValue = try? container.decodeIfPresent([String: String].self, forKey: .result) { - result = rawValue - } else if let rawValue = try? container.decodeIfPresent([String: [[String: String]]].self, forKey: .result) { - result = rawValue - } else if let rawValue = try? container.decodeIfPresent([String: Int].self, forKey: .result) { - result = rawValue - } else if let rawValue = try? container.decodeIfPresent([String: [String: [String: String]]].self, forKey: .result) { - result = rawValue - } else if let rawValue = try? container.decodeIfPresent([String: [String: [String: [String: String?]]]].self, forKey: .result) { - result = rawValue - } else { - result = nil - } - - self.init(id: id, jsonrpc: jsonrpc, result: result, error: nil) - } -} - -public struct ErrorMessage: Codable { - public var code: Int - public var message: String - public var data: String - - enum ErrorMessageKeys: String, CodingKey { - case code - case message - case data - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: ErrorMessageKeys.self) - try container.encode(message, forKey: .message) - try container.encode(code, forKey: .code) - try container.encode(data, forKey: .data) - } -} diff --git a/Sources/TorusUtils/Helpers/KeyUtils.swift b/Sources/TorusUtils/Helpers/KeyUtils.swift new file mode 100644 index 00000000..51e9d45e --- /dev/null +++ b/Sources/TorusUtils/Helpers/KeyUtils.swift @@ -0,0 +1,194 @@ +import BigInt +import Foundation +#if canImport(curveSecp256k1) + import curveSecp256k1 +#endif + +enum TorusKeyType: String, Equatable, Hashable, Codable { + case secp256k1 +} + +public class KeyUtils { + public static func keccak256Data(_ input: String) throws -> String { + guard let data = input.data(using: .utf8) else { throw TorusUtilError.invalidInput } + return try keccak256(data: data).toHexString() + } + + public static func keccak256Data(_ data: Data) throws -> Data { + return try keccak256(data: data) + } + + public static func randomNonce() throws -> String { + return try generateSecret() + } + + public static func generateSecret() throws -> String { + let secret = SecretKey() + return try secret.serialize().addLeading0sForLength64() + } + + internal static func getOrderOfCurve() -> BigInt { + let orderHex = CURVE_N + let order = BigInt(orderHex, radix: 16)! + return order + } + + internal static func generateAddressFromPubKey(publicKeyX: String, publicKeyY: String) throws -> String { + let publicKeyHex = KeyUtils.getPublicKeyFromCoords(pubKeyX: publicKeyX, pubKeyY: publicKeyY, prefixed: false) + let publicKeyData = Data(hex: publicKeyHex) + let ethAddrData = try keccak256Data(publicKeyData).suffix(20) + let ethAddrlower = ethAddrData.toHexString().addHexPrefix().lowercased() + return try toChecksumAddress(hexAddress: ethAddrlower) + } + + internal static func toChecksumAddress(hexAddress: String) throws -> String { + let lowerCaseAddress = hexAddress.stripHexPrefix().lowercased() + let arr = Array(lowerCaseAddress) + let hash = try keccak256Data(lowerCaseAddress.data(using: .utf8) ?? Data()).toHexString() + + var result = String() + for i in 0 ... lowerCaseAddress.count - 1 { + let iIndex = hash.index(hash.startIndex, offsetBy: i) + if let val = hash[iIndex].hexDigitValue, val >= 8 { + result.append(arr[i].uppercased()) + } else { + result.append(arr[i]) + } + } + return result.addHexPrefix() + } + + public static func getPublicKeyCoords(pubKey: String) throws -> (String, String) { + var publicKeyUnprefixed = pubKey + if publicKeyUnprefixed.count > 128 { + publicKeyUnprefixed = publicKeyUnprefixed.strip04Prefix() + } + + if !(publicKeyUnprefixed.count == 128) { + throw TorusUtilError.invalidPubKeySize + } + + return (String(publicKeyUnprefixed.prefix(64)), String(publicKeyUnprefixed.suffix(64))) + } + + public static func getPublicKeyFromCoords(pubKeyX: String, pubKeyY: String, prefixed: Bool = true) -> String { + let X = pubKeyX.addLeading0sForLength64() + let Y = pubKeyY.addLeading0sForLength64() + + return prefixed ? (X + Y).add04PrefixUnchecked() : X + Y + } + + internal static func combinePublicKeys(keys: [String], compressed: Bool = false) throws -> String { + var collection: [PublicKey] = [] + + for item in keys { + try collection.append(PublicKey(hex: item)) + } + + return try combinePublicKeys(keys: collection, compressed: compressed) + } + + internal static func combinePublicKeys(keys: [PublicKey], compressed: Bool = false) throws -> String { + let collection = PublicKeyCollection() + for item in keys { + try collection.insert(key: item) + } + + let added = try PublicKey.combine(collection: collection).serialize(compressed: compressed) + return added + } + + internal static func generateKeyData(privateKey: String) throws -> PrivateKeyData { + let scalar = BigInt(privateKey, radix: 16)! + + let randomNonce = BigInt(try SecretKey().serialize().addLeading0sForLength64(), radix: 16)! + + let oAuthKey = (scalar - randomNonce).modulus(KeyUtils.getOrderOfCurve()) + + let oAuthPubKeyString = try SecretKey(hex: oAuthKey.magnitude.serialize().hexString.addLeading0sForLength64()).toPublic().serialize(compressed: false) + + let finalUserPubKey = try SecretKey(hex: privateKey).toPublic().serialize(compressed: false) + + return PrivateKeyData( + oAuthKey: oAuthKey.magnitude.serialize().hexString.addLeading0sForLength64(), + oAuthPubKey: oAuthPubKeyString, + nonce: randomNonce.magnitude.serialize().hexString.addLeading0sForLength64(), + signingKey: oAuthKey.magnitude.serialize().hexString.addLeading0sForLength64(), + signingPubKey: oAuthPubKeyString, + finalKey: privateKey, + finalPubKey: finalUserPubKey + ) + } + + private static func generateNonceMetadataParams(operation: String, privateKey: BigInt, nonce: BigInt?, serverTimeOffset: Int?) throws -> NonceMetadataParams { + let privKey = try SecretKey(hex: privateKey.magnitude.serialize().hexString.addLeading0sForLength64()) + + var setData = SetNonceData(operation: operation, timestamp: String(BigUInt(trunc(Double((serverTimeOffset ?? 0) + Int(Date().timeIntervalSince1970)))), radix: 16)) + + if nonce != nil { + setData.data = nonce!.magnitude.serialize().hexString.addLeading0sForLength64() + } + + let publicKey = try privKey.toPublic().serialize(compressed: false) + + let encoder = JSONEncoder() + encoder.outputFormatting = .sortedKeys + let encodedData = try encoder + .encode(setData) + + let hash = try KeyUtils.keccak256Data(encodedData).toHexString() + let sigData = try ECDSA.signRecoverable(key: privKey, hash: hash).serialize() + _ = try ECDSA.recover(signature: Signature(hex: sigData), hash: hash) + let (pubKeyX, pubKeyY) = try KeyUtils.getPublicKeyCoords(pubKey: publicKey) + return .init(pub_key_X: pubKeyX, pub_key_Y: pubKeyY, setData: setData, encodedData: encodedData.base64EncodedString(), signature: Data(hex: sigData).base64EncodedString()) + } + + internal static func generateShares(keyType: TorusKeyType = .secp256k1, serverTimeOffset: Int, nodeIndexes: [BigUInt], nodePubKeys: [INodePub], privateKey: String) throws -> [ImportedShare] { + if keyType != TorusKeyType.secp256k1 { + throw TorusUtilError.runtime("Unsupported key type") + } + + let keyData = try generateKeyData(privateKey: privateKey) + + let threshold = Int(trunc(Double((nodePubKeys.count / 2) + 1))) + let degree = threshold - 1 + let nodeIndexesBN = nodeIndexes.map({ BigInt($0) }) + + let poly = try Lagrange.generateRandomPolynomial(degree: degree, secret: BigInt(keyData.oAuthKey, radix: 16)) + let shares = poly.generateShares(shareIndexes: nodeIndexesBN) + let nonceParams = try KeyUtils.generateNonceMetadataParams(operation: "getOrSetNonce", privateKey: BigInt(keyData.signingKey, radix: 16)!, nonce: BigInt(keyData.nonce, radix: 16), serverTimeOffset: serverTimeOffset) + + var encShares: [Ecies] = [] + for i in 0 ..< nodePubKeys.count { + let shareInfo: Share = shares[nodeIndexes[i].magnitude.serialize().hexString.addLeading0sForLength64()]! + + let nodePub = KeyUtils.getPublicKeyFromCoords(pubKeyX: nodePubKeys[i].X, pubKeyY: nodePubKeys[i].Y) + let nodePubKey = try PublicKey(hex: nodePub).serialize(compressed: true) + let encrypted = try MetadataUtils.encrypt(publicKey: nodePubKey, msg: shareInfo.share.magnitude.serialize().hexString.addLeading0sForLength64()) + encShares.append(encrypted) + } + + var sharesData: [ImportedShare] = [] + for i in 0 ..< nodePubKeys.count { + let encrypted = encShares[i] + let (oAuthPubX, oAuthPubY) = try getPublicKeyCoords(pubKey: try PublicKey(hex: keyData.oAuthPubKey).serialize(compressed: false)) + let (signingPubX, signingPubY) = try getPublicKeyCoords(pubKey: try PublicKey(hex: keyData.signingPubKey).serialize(compressed: false)) + let (finalPubX, finalPubY) = try getPublicKeyCoords(pubKey: try PublicKey(hex: keyData.finalPubKey).serialize(compressed: false)) + let finalPoint = try Point(x: finalPubX, y: finalPubY) + let importShare = ImportedShare( + oauth_pub_key_x: oAuthPubX, + oauth_pub_key_y: oAuthPubY, + final_user_point: finalPoint, + signing_pub_key_x: signingPubX, + signing_pub_key_y: signingPubY, + encryptedShare: encrypted.ciphertext, + encryptedShareMetadata: EciesHexOmitCiphertext(from: encrypted), + node_index: Int(nodeIndexes[i].magnitude.serialize().hexString.addLeading0sForLength64(), radix: 16)!, + nonce_data: nonceParams.encodedData, + nonce_signature: nonceParams.signature) + sharesData.append(importShare) + } + + return sharesData + } +} diff --git a/Sources/TorusUtils/Helpers/LangrangeInterpolatePoly.swift b/Sources/TorusUtils/Helpers/LangrangeInterpolatePoly.swift index a284bc23..62df8e57 100644 --- a/Sources/TorusUtils/Helpers/LangrangeInterpolatePoly.swift +++ b/Sources/TorusUtils/Helpers/LangrangeInterpolatePoly.swift @@ -4,177 +4,174 @@ import Foundation import curveSecp256k1 #endif -func modInverse(_ a: BigInt, _ m: BigInt) -> BigInt? { - var (t, newT) = (BigInt(0), BigInt(1)) - var (r, newR) = (m, a) - - while newR != 0 { - let quotient = r / newR - (t, newT) = (newT, t - quotient * newT) - (r, newR) = (newR, r - quotient * newR) +internal class Lagrange { + public static func generatePrivateExcludingIndexes(shareIndexes: [BigInt]) throws -> BigInt { + let key = BigInt(Data(hex: try SecretKey().serialize().addLeading0sForLength64())) + if shareIndexes.contains(where: { $0 == key }) { + return try generatePrivateExcludingIndexes(shareIndexes: shareIndexes) + } + return key } - if r > 1 { - return nil // Modular inverse does not exist - } - if t < 0 { - t += m + public static func generateEmptyBNArray(length: Int) -> [BigInt] { + return Array(repeating: BigInt(0), count: length) } - return t -} - -func generatePrivateExcludingIndexes(shareIndexes: [BigInt]) throws -> BigInt { - let key = BigInt(Data(hex: try SecretKey().serialize().addLeading0sForLength64())) - if shareIndexes.contains(where: { $0 == key }) { - return try generatePrivateExcludingIndexes(shareIndexes: shareIndexes) - } - return key -} - -func generateEmptyBNArray(length: Int) -> [BigInt] { - return Array(repeating: BigInt(0), count: length) -} - -func denominator(i: Int, innerPoints: [Point]) -> BigInt { - var result = BigInt(1) - let xi = innerPoints[i].x - for j in (0 ..< innerPoints.count).reversed() { - if i != j { - var tmp = xi - tmp = tmp - innerPoints[j].x - tmp %= getOrderOfCurve() - result = result * tmp - result %= getOrderOfCurve() + public static func denominator(i: Int, innerPoints: [Point]) -> BigInt { + var result = BigInt(1) + let xi = innerPoints[i].x + for j in (0 ..< innerPoints.count).reversed() { + if i != j { + var tmp = xi + tmp = (tmp - innerPoints[j].x).modulus(KeyUtils.getOrderOfCurve()) + result = (result * tmp).modulus(KeyUtils.getOrderOfCurve()) + } } + return result } - return result -} -func interpolationPoly(i: Int, innerPoints: [Point]) -> [BigInt] { - var coefficients = generateEmptyBNArray(length: innerPoints.count) - let d = denominator(i: i, innerPoints: innerPoints) - if d == BigInt(0) { - fatalError("Denominator for interpolationPoly is 0") - } - coefficients[0] = d.inverse(getOrderOfCurve())! - for k in 0 ..< innerPoints.count { - var newCoefficients = generateEmptyBNArray(length: innerPoints.count) - if k != i { - var j: Int - if k < i { - j = k + 1 - } else { - j = k - } - j -= 1 - while j >= 0 { - newCoefficients[j + 1] = newCoefficients[j + 1] + coefficients[j] % getOrderOfCurve() - var tmp = BigInt(innerPoints[k].x) - tmp = tmp * coefficients[j] % getOrderOfCurve() - newCoefficients[j] = newCoefficients[j] - tmp % getOrderOfCurve() + public static func interpolationPoly(i: Int, innerPoints: [Point]) -> [BigInt] { + var coefficients = generateEmptyBNArray(length: innerPoints.count) + let d = denominator(i: i, innerPoints: innerPoints) + if d == BigInt(0) { + fatalError("Denominator for interpolationPoly is 0") + } + coefficients[0] = d.inverse(KeyUtils.getOrderOfCurve())! + for k in 0 ..< innerPoints.count { + var newCoefficients = generateEmptyBNArray(length: innerPoints.count) + if k != i { + var j: Int + if k < i { + j = k + 1 + } else { + j = k + } j -= 1 + while j >= 0 { + newCoefficients[j + 1] = (newCoefficients[j + 1] + coefficients[j]).modulus(KeyUtils.getOrderOfCurve()) + var tmp = BigInt(innerPoints[k].x) + tmp = (tmp * coefficients[j]).modulus(KeyUtils.getOrderOfCurve()) + newCoefficients[j] = (newCoefficients[j] - tmp).modulus(KeyUtils.getOrderOfCurve()) + j -= 1 + } + coefficients = newCoefficients } - coefficients = newCoefficients } + return coefficients } - return coefficients -} -func pointSort(innerPoints: [Point]) -> [Point] { - var pointArrClone = innerPoints - pointArrClone.sort { $0.x < $1.x } - return pointArrClone -} + public static func pointSort(innerPoints: [Point]) -> [Point] { + var pointArrClone = innerPoints + pointArrClone.sort { $0.x < $1.x } + return pointArrClone + } -func lagrange(unsortedPoints: [Point]) -> Polynomial { - let sortedPoints = pointSort(innerPoints: unsortedPoints) - var polynomial = generateEmptyBNArray(length: sortedPoints.count) - for i in 0 ..< sortedPoints.count { - let coefficients = interpolationPoly(i: i, innerPoints: sortedPoints) - for k in 0 ..< sortedPoints.count { - var tmp = BigInt(sortedPoints[i].y) - tmp = tmp * coefficients[k] % getOrderOfCurve() - polynomial[k] = (polynomial[k] + tmp) % getOrderOfCurve() + public static func lagrange(unsortedPoints: [Point]) -> Polynomial { + let sortedPoints = pointSort(innerPoints: unsortedPoints) + var polynomial = generateEmptyBNArray(length: sortedPoints.count) + for i in 0 ..< sortedPoints.count { + let coefficients = interpolationPoly(i: i, innerPoints: sortedPoints) + for k in 0 ..< sortedPoints.count { + var tmp = BigInt(sortedPoints[i].y) + tmp = (tmp * coefficients[k]).modulus(KeyUtils.getOrderOfCurve()) + polynomial[k] = (polynomial[k] + tmp).modulus(KeyUtils.getOrderOfCurve()) + } } + return Polynomial(polynomial: polynomial) } - return Polynomial(polynomial: polynomial) -} -func lagrangeInterpolatePolynomial(points: [Point]) -> Polynomial { - return lagrange(unsortedPoints: points) -} + public static func lagrangeInterpolatePolynomial(points: [Point]) -> Polynomial { + return lagrange(unsortedPoints: points) + } -func lagrangeInterpolationWithNodeIndex(shares: [BigInt], nodeIndex: [BigInt]) -> BigInt { - let modulus = BigInt(CURVE_N, radix: 16)! + public static func lagrangeInterpolation(shares: [String], nodeIndex: [Int]) throws -> String { + let sharesList: [BigInt] = shares.map({ BigInt($0.addLeading0sForLength64(), radix: 16) }).filter({ $0 != nil }).map({ $0! }) + let indexList: [BigInt] = nodeIndex.map({ BigInt($0) }) - if shares.count != nodeIndex.count { - fatalError("shares not equal to nodeIndex length in lagrangeInterpolation") - } + if sharesList.count != indexList.count { + throw TorusUtilError.runtime("sharesList not equal to indexList length in lagrangeInterpolation") + } - var secret = BigInt(0) - for i in 0 ..< shares.count { - var upper = BigInt(1) - var lower = BigInt(1) - for j in 0 ..< shares.count { - if i != j { - upper *= -nodeIndex[j] - upper %= modulus - var temp = nodeIndex[i] - nodeIndex[j] - temp %= modulus - lower *= temp - lower %= modulus + var secret = BigUInt("0") + var sharesDecrypt = 0 + + for i in 0 ..< sharesList.count { + var upper = BigInt(1) + var lower = BigInt(1) + for j in 0 ..< sharesList.count { + if i != j { + let negatedJ = indexList[j] * BigInt(-1) + upper = upper * negatedJ + upper = upper.modulus(KeyUtils.getOrderOfCurve()) + + var temp = indexList[i] - indexList[j] + temp = temp.modulus(KeyUtils.getOrderOfCurve()) + lower = (lower * temp).modulus(KeyUtils.getOrderOfCurve()) + } } + guard + let inv = lower.inverse(KeyUtils.getOrderOfCurve()) + else { + throw TorusUtilError.decryptionFailed + } + var delta = (upper * inv).modulus(KeyUtils.getOrderOfCurve()) + delta = (delta * sharesList[i]).modulus(KeyUtils.getOrderOfCurve()) + secret = BigUInt((BigInt(secret) + delta).modulus(KeyUtils.getOrderOfCurve())) + sharesDecrypt += 1 } - var delta = upper * modInverse(lower, modulus)! - delta %= modulus - delta = delta * shares[i] - delta %= modulus - secret += delta - } - return secret % modulus -} + if secret == BigUInt(0) { + throw TorusUtilError.interpolationFailed + } -func generateRandomPolynomial(degree: Int, secret: BigInt? = nil, deterministicShares: [Share]? = nil) throws -> Polynomial { - var actualS = secret - if secret == nil { - actualS = try generatePrivateExcludingIndexes(shareIndexes: [BigInt(0)]) + let secretString = secret.serialize().hexString.addLeading0sForLength64() + if sharesDecrypt == sharesList.count { + return secretString + } else { + throw TorusUtilError.interpolationFailed + } } - if deterministicShares == nil { - var poly = [actualS!] - for _ in 0 ..< degree { - let share = try generatePrivateExcludingIndexes(shareIndexes: poly) - poly.append(share) + public static func generateRandomPolynomial(degree: Int, secret: BigInt? = nil, deterministicShares: [Share]? = nil) throws -> Polynomial { + var actualS = secret + if secret == nil { + actualS = try generatePrivateExcludingIndexes(shareIndexes: [BigInt(0)]) } - return Polynomial(polynomial: poly) - } + if deterministicShares == nil { + var poly = [actualS!] + for _ in 0 ..< degree { + let share = try generatePrivateExcludingIndexes(shareIndexes: poly) + poly.append(share) + } - guard let deterministicShares = deterministicShares else { - throw NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "Deterministic shares in generateRandomPolynomial should be an array"]) - } + return Polynomial(polynomial: poly) + } - if deterministicShares.count > degree { - throw NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "Deterministic shares in generateRandomPolynomial should be less or equal than degree to ensure an element of randomness"]) - } + guard let deterministicShares = deterministicShares else { + throw NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "Deterministic shares in generateRandomPolynomial should be an array"]) + } - var points = [String: Point]() - for share in deterministicShares { - points[String(share.shareIndex, radix: 16).addLeading0sForLength64()] = - Point(x: share.shareIndex, y: share.share) - } + if deterministicShares.count > degree { + throw NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "Deterministic shares in generateRandomPolynomial should be less or equal than degree to ensure an element of randomness"]) + } - let remainingDegree = degree - deterministicShares.count - for _ in 0 ..< remainingDegree { - var shareIndex = try generatePrivateExcludingIndexes(shareIndexes: [BigInt(0)]) - while points[shareIndex.description.padding(toLength: 64, withPad: "0", startingAt: 0)] != nil { - shareIndex = try generatePrivateExcludingIndexes(shareIndexes: [BigInt(0)]) + var points = [String: Point]() + for share in deterministicShares { + points[String(share.shareIndex, radix: 16).addLeading0sForLength64()] = + Point(x: share.shareIndex, y: share.share) } - points[String(shareIndex, radix: 16).addLeading0sForLength64()] = Point(x: shareIndex, y: BigInt(Data(hex:try SecretKey().serialize().addLeading0sForLength64()))) - } - points["0"] = Point(x: BigInt(0), y: actualS!) - return lagrangeInterpolatePolynomial(points: Array(points.values)) + let remainingDegree = degree - deterministicShares.count + for _ in 0 ..< remainingDegree { + var shareIndex = try generatePrivateExcludingIndexes(shareIndexes: [BigInt(0)]) + while points[shareIndex.magnitude.serialize().hexString.addLeading0sForLength64()] != nil { + shareIndex = try generatePrivateExcludingIndexes(shareIndexes: [BigInt(0)]) + } + points[shareIndex.magnitude.serialize().hexString.addLeading0sForLength64()] = Point(x: shareIndex, y: BigInt(Data(hex: try SecretKey().serialize().addLeading0sForLength64()))) + } + + points["0"] = Point(x: BigInt(0), y: actualS!) + return lagrangeInterpolatePolynomial(points: Array(points.values)) + } } diff --git a/Sources/TorusUtils/Helpers/MetadataUtils.swift b/Sources/TorusUtils/Helpers/MetadataUtils.swift new file mode 100644 index 00000000..ecb70c0c --- /dev/null +++ b/Sources/TorusUtils/Helpers/MetadataUtils.swift @@ -0,0 +1,109 @@ +import BigInt +import FetchNodeDetails +import Foundation +import OSLog +#if canImport(curveSecp256k1) + import curveSecp256k1 +#endif + +internal class MetadataUtils { + public static func decryptNodeData(eciesData: EciesHexOmitCiphertext, ciphertextHex: String, privKey: String) throws -> String { + let eciesOpts = ECIES( + iv: eciesData.iv, + ephemPublicKey: eciesData.ephemPublicKey, + ciphertext: ciphertextHex, + mac: eciesData.mac + ) + + let decryptedSigBuffer = try decrypt(privateKey: privKey, opts: eciesOpts).hexString + return decryptedSigBuffer + } + + public static func decrypt(privateKey: String, opts: ECIES) throws -> Data { + let secret = try SecretKey(hex: privateKey) + var publicKey = opts.ephemPublicKey + if opts.ephemPublicKey.count == 128 { // missing 04 prefix + publicKey = publicKey.add04PrefixUnchecked() + } + let msg = try EncryptedMessage(cipherText: opts.ciphertext, ephemeralPublicKey: PublicKey(hex: publicKey), iv: opts.iv, mac: opts.mac) + let result = try Encryption.decrypt(sk: secret, encrypted: msg) + return result + } + + public static func encrypt(publicKey: String, msg: String) throws -> Ecies { + let data = Data(hex: msg) + let curveMsg = try Encryption.encrypt(pk: PublicKey(hex: publicKey), plainText: data) + return try .init(iv: curveMsg.iv(), ephemPublicKey: curveMsg.ephemeralPublicKey().serialize(compressed: false), ciphertext: curveMsg.chipherText(), mac: curveMsg.mac()) + } + + internal static func makeUrlRequest(url: String, httpMethod: httpMethod = .post) throws -> URLRequest { + guard + let url = URL(string: url) + else { + throw TorusUtilError.runtime("Invalid Url \(url)") + } + var rq = URLRequest(url: url) + rq.httpMethod = httpMethod.name + rq.addValue("application/json", forHTTPHeaderField: "Content-Type") + rq.addValue("application/json", forHTTPHeaderField: "Accept") + return rq + } + + public static func generateMetadataParams(serverTimeOffset: Int, message: String, privateKey: String, X: String, Y: String, keyType: TorusKeyType? = nil) throws -> MetadataParams { + let privKey = try SecretKey(hex: privateKey) + + let timeStamp = String(BigUInt(TimeInterval(serverTimeOffset) + Date().timeIntervalSince1970), radix: 16) + let setData: MetadataParams.SetData = .init(data: message, timestamp: timeStamp) + let encoder = JSONEncoder() + encoder.outputFormatting = .sortedKeys + let encodedData = try encoder + .encode(setData) + + let hash = try KeyUtils.keccak256Data(encodedData).toHexString() + let sigData = try ECDSA.signRecoverable(key: privKey, hash: hash).serialize() + _ = try ECDSA.recover(signature: Signature(hex: sigData), hash: hash) + return .init(pub_key_X: X, pub_key_Y: Y, setData: setData, signature: Data(hex: sigData).base64EncodedString(), keyType: keyType) + } + + public static func getMetadata(legacyMetadataHost: String, params: GetMetadataParams) async throws -> BigUInt { + let encoder = JSONEncoder() + encoder.outputFormatting = .sortedKeys + var request = try makeUrlRequest(url: "\(legacyMetadataHost)/get") + request.httpBody = try encoder.encode(params) + let urlSession = URLSession(configuration: .default) + let val = try await urlSession.data(for: request) + let data: GetMetadataResponse = try JSONDecoder().decode(GetMetadataResponse.self, from: val.0) + let msg: String = data.message + let ret = BigUInt(msg, radix: 16)! + return ret + } + + public static func getOrSetNonce(legacyMetadataHost: String, serverTimeOffset: Int, X: String, Y: String, privateKey: String? = nil, getOnly: Bool = false, keyType: TorusKeyType? = nil) async throws -> GetOrSetNonceResult { + var data: Data + let msg = getOnly ? "getNonce" : "getOrSetNonce" + let encoder = JSONEncoder() + encoder.outputFormatting = .sortedKeys + if privateKey != nil { + let val = try generateMetadataParams(serverTimeOffset: serverTimeOffset, message: msg, privateKey: privateKey!, X: X, Y: Y) + data = try encoder.encode(val) + } else { + let val = GetNonceParams(pub_key_X: X, pub_key_Y: Y, set_data: GetNonceSetDataParams(data: msg)) + data = try encoder.encode(val) + } + var request = try makeUrlRequest(url: "\(legacyMetadataHost)/get_or_set_nonce") + request.httpBody = data + let urlSession = URLSession(configuration: .default) + let val = try await urlSession.data(for: request) + + let decoded = try JSONDecoder().decode(GetOrSetNonceResult.self, from: val.0) + return decoded + } + + public static func getOrSetSapphireMetadataNonce(metadataHost: String, network: TorusNetwork, X: String, Y: String, serverTimeOffset: Int? = nil, privateKey: String? = nil, getOnly: Bool = false, keyType: TorusKeyType = .secp256k1) async throws -> GetOrSetNonceResult { + if case .sapphire = network { + return try await getOrSetNonce(legacyMetadataHost: metadataHost, serverTimeOffset: serverTimeOffset ?? Int(trunc(Double(0 + Int(Date().timeIntervalSince1970)))), X: X, Y: Y, privateKey: privateKey, getOnly: getOnly, keyType: keyType) + } else { + throw TorusUtilError.metadataNonceMissing + } + } +} diff --git a/Sources/TorusUtils/Helpers/NodeUtils.swift b/Sources/TorusUtils/Helpers/NodeUtils.swift new file mode 100644 index 00000000..41e2f2fe --- /dev/null +++ b/Sources/TorusUtils/Helpers/NodeUtils.swift @@ -0,0 +1,597 @@ +import BigInt +import FetchNodeDetails +import Foundation +import OSLog +#if canImport(curveSecp256k1) + import curveSecp256k1 +#endif + +internal class NodeUtils { + public static func getPubKeyOrKeyAssign( + endpoints: [String], + network: TorusNetwork, + verifier: String, + verifierId: String, + legacyMetadataHost: String, + serverTimeOffset: Int? = nil, + extendedVerifierId: String? = nil) async throws -> KeyLookupResult { + let threshold = Int(trunc(Double((endpoints.count / 2) + 1))) + + let params = GetOrSetKeyParams(distributed_metadata: true, verifier: verifier, verifier_id: verifierId, extended_verifier_id: extendedVerifierId, one_key_flow: true, fetch_node_index: true, client_time: String(Int(trunc(Double((serverTimeOffset ?? 0) + Int(Date().timeIntervalSince1970)))))) + let jsonRPCRequest = JRPCRequest( + method: JRPC_METHODS.GET_OR_SET_KEY, + params: params + ) + let encoder = JSONEncoder() + encoder.outputFormatting = .sortedKeys + let rpcdata = try encoder.encode(jsonRPCRequest) + + var nonceResult: GetOrSetNonceResult? + var nodeIndexes: [Int] = [] + + let (keyResult, lookupResults, errorResult): (KeyLookupResult.KeyResult?, [JRPCResponse?], ErrorMessage?) = try await withThrowingTaskGroup(of: JRPCResponse?.self, returning: (KeyLookupResult.KeyResult?, [JRPCResponse?], ErrorMessage?).self) { group -> (KeyLookupResult.KeyResult?, [JRPCResponse?], ErrorMessage?) in + for endpoint in endpoints { + group.addTask { + do { + var request = try MetadataUtils.makeUrlRequest(url: endpoint) + request.httpBody = rpcdata + let val = try await URLSession(configuration: .default).data(for: request) + let decoded = try JSONDecoder().decode(JRPCResponse.self, from: val.0) + return decoded + } catch { + return nil + } + } + } + var collected = [JRPCResponse?]() + var errorResult: ErrorMessage? + var lookupPubKeys = [JRPCResponse?]() + var keyResult: KeyLookupResult.KeyResult? + for try await value in group { + collected.append(value) + + lookupPubKeys = collected.filter({ $0 != nil && $0?.error == nil }) + + errorResult = try thresholdSame(arr: collected.filter({ $0?.error != nil }).map { $0?.error }, threshold: threshold) as? ErrorMessage + + let normalizedKeyResults = lookupPubKeys.map({ normalizeKeysResult(result: ($0!.result)!) }) + + keyResult = try thresholdSame(arr: normalizedKeyResults, threshold: threshold) + + if keyResult != nil { + group.cancelAll() + } + } + return (keyResult, lookupPubKeys, errorResult) + } + + if keyResult != nil && nonceResult == nil && extendedVerifierId == nil && !TorusUtils.isLegacyNetworkRouteMap(network: network) { + for i in 0 ..< lookupResults.count { + let x1 = lookupResults[i] + if x1 != nil && x1?.error == nil { + let currentNodePubKeyX = x1!.result!.keys[0].pub_key_X.addLeading0sForLength64().lowercased() + let thresholdPubKeyX = keyResult!.keys[0].pub_key_X.addLeading0sForLength64().lowercased() + let pubNonce: PubNonce? = x1!.result!.keys[0].nonce_data?.pubNonce + if pubNonce != nil && currentNodePubKeyX == thresholdPubKeyX { + nonceResult = x1?.result?.keys[0].nonce_data + break + } + } + } + + if nonceResult == nil { + let metadataNonce = try await MetadataUtils.getOrSetSapphireMetadataNonce(metadataHost: legacyMetadataHost, network: network, X: keyResult!.keys[0].pub_key_X, Y: keyResult!.keys[0].pub_key_Y) + nonceResult = metadataNonce + if nonceResult!.nonce != nil { + nonceResult!.nonce = nil + } + } + } + + var serverTimeOffsets: [Int] = [] + if keyResult != nil && (nonceResult != nil || extendedVerifierId != nil || TorusUtils.isLegacyNetworkRouteMap(network: network) || errorResult != nil) { + for i in 0 ..< lookupResults.count { + let x1 = lookupResults[i] + if x1 != nil && x1?.result != nil { + let currentNodePubKey = x1!.result!.keys[0].pub_key_X.lowercased() + let thresholdPubKey = keyResult!.keys[0].pub_key_X.lowercased() + if currentNodePubKey == thresholdPubKey { + let nodeIndex = Int(x1!.result!.node_index) + if nodeIndex != nil { + nodeIndexes.append(nodeIndex!) + } + } + let serverTimeOffset: Int = Int(x1!.result!.server_time_offset ?? "0")! + serverTimeOffsets.append(serverTimeOffset) + } + } + } + + let serverTimeOffset = (keyResult != nil) ? calculateMedian(arr: serverTimeOffsets) : 0 + + return KeyLookupResult( + keyResult: keyResult, + nodeIndexes: nodeIndexes, + serverTimeOffset: serverTimeOffset, + nonceResult: nonceResult, + errorResult: errorResult) + } + + public static func retrieveOrImportShare( + legacyMetadataHost: String, + serverTimeOffset: Int?, + enableOneKey: Bool, + allowHost: String, + network: TorusNetwork, + clientId: String, + endpoints: [String], + verifier: String, + verifierParams: VerifierParams, + idToken: String, + importedShares: [ImportedShare]?, + apiKey: String = "torus-default", + extraParams: TorusUtilsExtraParams + ) async throws -> TorusKey { + let threshold = Int(trunc(Double((endpoints.count / 2) + 1))) + + var allowHostRequest = try MetadataUtils.makeUrlRequest(url: allowHost, httpMethod: .get) + allowHostRequest.addValue(apiKey, forHTTPHeaderField: "x-api-key") + allowHostRequest.addValue(verifier, forHTTPHeaderField: "origin") + allowHostRequest.addValue(verifier, forHTTPHeaderField: "verifier") + allowHostRequest.addValue(verifierParams.verifier_id, forHTTPHeaderField: "verifierid") + allowHostRequest.addValue(network.name, forHTTPHeaderField: "network") + allowHostRequest.addValue(clientId, forHTTPHeaderField: "clientid") + allowHostRequest.addValue("true", forHTTPHeaderField: "enablegating") + let allowHostResult = try await URLSession(configuration: .default).data(for: allowHostRequest) + let allowHostResultData = try JSONDecoder().decode(AllowSuccess.self, from: allowHostResult.0) + if allowHostResultData.success == false { + let errorData = try JSONDecoder().decode(AllowRejected.self, from: allowHostResult.0) + throw TorusUtilError.gatingError("code: \(errorData.code), error: \(errorData.error)") + } + + let sessionAuthKey = SecretKey() + let sessionAuthKeySerialized = try sessionAuthKey.serialize().addLeading0sForLength64() + let pubKey = try sessionAuthKey.toPublic().serialize(compressed: false) + let (pubX, pubY) = try KeyUtils.getPublicKeyCoords(pubKey: pubKey) + let tokenCommitment = try KeyUtils.keccak256Data(idToken) + + var isImportShareReq = false + var importedShareCount = 0 + if importedShares != nil && importedShares!.count > 0 { + if importedShares!.count != endpoints.count { + throw TorusUtilError.importShareFailed + } + isImportShareReq = true + importedShareCount = importedShares!.count + } + + let params = CommitmentRequestParams(messageprefix: "mug00", tokencommitment: tokenCommitment, temppubx: pubX, temppuby: pubY, verifieridentifier: verifier, timestamp: String(BigUInt(trunc(Double((serverTimeOffset ?? 0) + Int(Date().timeIntervalSince1970)))), radix: 16)) + + let jsonRPCRequest = JRPCRequest( + method: JRPC_METHODS.COMMITMENT_REQUEST, + params: params + ) + + let encoder = JSONEncoder() + encoder.outputFormatting = .sortedKeys + let rpcdata = try encoder.encode(jsonRPCRequest) + + let nodeSigs: [CommitmentRequestResult] = try await withThrowingTaskGroup(of: JRPCResponse?.self, returning: [CommitmentRequestResult].self) { group -> [CommitmentRequestResult] in + let minRequiredCommitmments = Int(trunc(Double(endpoints.count * 3 / 4) + 1)) + var received: Int = 0 + for endpoint in endpoints { + group.addTask { + do { + var request = try MetadataUtils.makeUrlRequest(url: endpoint) + request.httpBody = rpcdata + let val = try await URLSession(configuration: .default).data(for: request) + let decoded = try JSONDecoder().decode(JRPCResponse.self, from: val.0) + return decoded + } catch { + return nil + } + } + } + var collected = [CommitmentRequestResult]() + for try await value in group { + if value != nil && value?.error == nil { + collected.append(value!.result!) + received += 1 + if !isImportShareReq { + if received >= minRequiredCommitmments { + group.cancelAll() + } + } + } else { + if isImportShareReq { + // cannot continue, all must pass for import + group.cancelAll() + } + } + } + return collected + } + + if importedShareCount > 0 && !(nodeSigs.count == endpoints.count) { + throw TorusUtilError.commitmentRequestFailed + } + + var thresholdNonceData: GetOrSetNonceResult? + + let sessionExpiry = extraParams.session_token_exp_second + + var shareImportSuccess = false + + var shareResponses = [ShareRequestResult]() + var thresholdPublicKey: KeyAssignment.PublicKey? + + if isImportShareReq { + var importedItems: [ShareRequestParams.ShareRequestItem] = [] + for j in 0 ..< endpoints.count { + let importShare = importedShares![j] + + let shareRequestItem = ShareRequestParams.ShareRequestItem( + verifieridentifier: verifier, + verifier_id: verifierParams.verifier_id, + extended_verifier_id: verifierParams.extended_verifier_id, + idtoken: idToken, + nodesignatures: nodeSigs, + pub_key_x: importShare.oauth_pub_key_x, + pub_key_y: importShare.oauth_pub_key_y, + signing_pub_key_x: importShare.signing_pub_key_x, + signing_pub_key_y: importShare.signing_pub_key_y, + encrypted_share: importShare.encryptedShare, + encrypted_share_metadata: importShare.encryptedShareMetadata, + node_index: importShare.node_index, + key_type: importShare.key_type, + nonce_data: importShare.nonce_data, + nonce_signature: importShare.nonce_signature, + sub_verifier_ids: verifierParams.sub_verifier_ids, + session_token_exp_second: sessionExpiry, + verify_params: verifierParams.verify_params, + sss_endpoint: endpoints[j], + + nonce: extraParams.nonce, + message: extraParams.message, + signature: extraParams.signature, + clientDataJson: extraParams.clientDataJson, + authenticatorData: extraParams.authenticatorData, + publicKey: extraParams.publicKey, + challenge: extraParams.challenge, + rpOrigin: extraParams.rpOrigin, + rpId: extraParams.rpId + ) + + importedItems.append(shareRequestItem) + } + + let params = ShareRequestParams(encrypted: "yes", item: importedItems, client_time: String(Int(trunc(Double((serverTimeOffset ?? 0) + Int(Date().timeIntervalSince1970)))))) + + let jsonRPCRequest = JRPCRequest( + method: JRPC_METHODS.IMPORT_SHARES, + params: params + ) + + let encoder = JSONEncoder() + encoder.outputFormatting = .sortedKeys + let rpcdata = try encoder.encode(jsonRPCRequest) + var request = try MetadataUtils.makeUrlRequest(url: endpoints[Int(try getProxyCoordinatorEndpointIndex(endpoints: endpoints, verifier: verifier, verifierId: verifierParams.verifier_id))]) + request.httpBody = rpcdata + let val = try await URLSession(configuration: .default).data(for: request) + let decoded = try JSONDecoder().decode(JRPCResponse<[ShareRequestResult]>.self, from: val.0) + if decoded.error == nil { + shareImportSuccess = true + } + + if isImportShareReq && !shareImportSuccess { + throw TorusUtilError.importShareFailed + } + + shareResponses = decoded.result! + + let pubkeys = shareResponses.filter({ $0.keys.count > 0 }).map { $0.keys[0].publicKey } + + thresholdPublicKey = try thresholdSame(arr: pubkeys, threshold: threshold) + } else { + (shareResponses, thresholdPublicKey) = try await withThrowingTaskGroup(of: JRPCResponse?.self, returning: ([ShareRequestResult], KeyAssignment.PublicKey?).self) { + group -> ([ShareRequestResult], KeyAssignment.PublicKey?) in + for i in 0 ..< endpoints.count { + group.addTask { + do { + let shareRequestItem = ShareRequestParams.ShareRequestItem( + verifieridentifier: verifier, + verifier_id: verifierParams.verifier_id, + extended_verifier_id: verifierParams.extended_verifier_id, + idtoken: idToken, + nodesignatures: nodeSigs, + sub_verifier_ids: verifierParams.sub_verifier_ids, + session_token_exp_second: sessionExpiry, + verify_params: verifierParams.verify_params, + + nonce: extraParams.nonce, + message: extraParams.message, + signature: extraParams.signature, + clientDataJson: extraParams.clientDataJson, + authenticatorData: extraParams.authenticatorData, + publicKey: extraParams.publicKey, + challenge: extraParams.challenge, + rpOrigin: extraParams.rpOrigin, + rpId: extraParams.rpId + ) + + let params = ShareRequestParams(encrypted: "yes", item: [shareRequestItem], client_time: String(Int(trunc(Double((serverTimeOffset ?? 0) + Int(Date().timeIntervalSince1970)))))) + + let jsonRPCRequest = JRPCRequest( + method: JRPC_METHODS.GET_SHARE_OR_KEY_ASSIGN, + params: params + ) + + let encoder = JSONEncoder() + encoder.outputFormatting = .sortedKeys + let rpcdata = try encoder.encode(jsonRPCRequest) + var request = try MetadataUtils.makeUrlRequest(url: endpoints[i]) + request.httpBody = rpcdata + let val = try await URLSession(configuration: .default).data(for: request) + let decoded = try JSONDecoder().decode(JRPCResponse.self, from: val.0) + return decoded + } catch { + return nil + } + } + } + + var collected = [JRPCResponse?]() + var shareResponses = [ShareRequestResult]() + var thresholdPublicKey: KeyAssignment.PublicKey? + for try await value in group { + collected.append(value) + + shareResponses = collected.filter({ $0 != nil && $0!.result != nil }).map({ $0!.result! }) + + let pubkeys = shareResponses.filter({ $0.keys.count > 0 }).map { $0.keys[0].publicKey } + + thresholdPublicKey = try thresholdSame(arr: pubkeys, threshold: threshold) + + if thresholdPublicKey != nil { + group.cancelAll() + } + } + + return (shareResponses, thresholdPublicKey) + } + } + + if thresholdPublicKey == nil { + throw TorusUtilError.retrieveOrImportShareError + } + + for item in shareResponses { + if thresholdNonceData == nil && verifierParams.extended_verifier_id == nil { + let currentPubKeyX = item.keys[0].publicKey.X.addLeading0sForLength64().lowercased() + let thesholdPubKeyX = thresholdPublicKey!.X.addLeading0sForLength64().lowercased() + let pubNonce: PubNonce? = item.keys[0].nonceData?.pubNonce + if pubNonce != nil && currentPubKeyX == thesholdPubKeyX { + thresholdNonceData = item.keys[0].nonceData + } + } + } + + var serverTimeOffsets: [String] = [] + for item in shareResponses { + serverTimeOffsets.append(item.serverTimeOffset) + } + let serverOffsetTimes = serverTimeOffsets.map({ Int($0) ?? 0 }) + + let serverTimeOffsetResponse: Int = serverTimeOffset ?? calculateMedian(arr: serverOffsetTimes) + + if thresholdNonceData == nil && verifierParams.extended_verifier_id == nil && !TorusUtils.isLegacyNetworkRouteMap(network: network) { + let metadataNonce = try await MetadataUtils.getOrSetSapphireMetadataNonce(metadataHost: legacyMetadataHost, network: network, X: thresholdPublicKey!.X, Y: thresholdPublicKey!.Y, serverTimeOffset: serverTimeOffsetResponse, getOnly: false) + thresholdNonceData = metadataNonce + } + + let thresholdReqCount = (importedShares != nil && importedShares!.count > 0) ? endpoints.count : threshold + + // Invert comparision to return error early + if !(shareResponses.count >= thresholdReqCount && thresholdPublicKey != nil && (thresholdNonceData != nil || verifierParams.extended_verifier_id != nil || TorusUtils.isLegacyNetworkRouteMap(network: network))) { + throw TorusUtilError.retrieveOrImportShareError + } + + var shares: [String?] = [] + var sessionTokenSigs: [String?] = [] + var sessionTokens: [String?] = [] + var nodeIndexes: [Int?] = [] + var sessionTokenDatas: [SessionToken?] = [] + var isNewKeys: [String] = [] + + for item in shareResponses { + isNewKeys.append(item.isNewKey) + + if !item.sessionTokenSigs.isEmpty { + if !item.sessionTokenSigMetadata.isEmpty { + let decrypted = try MetadataUtils.decryptNodeData(eciesData: item.sessionTokenSigMetadata[0], ciphertextHex: item.sessionTokenSigs[0], privKey: sessionAuthKeySerialized) + sessionTokenSigs.append(decrypted) + } else { + sessionTokenSigs.append(item.sessionTokenSigs[0]) + } + } else { + sessionTokenSigs.append(nil) + } + + if !item.sessionTokens.isEmpty { + if !item.sessionTokenMetadata.isEmpty { + let decrypted = try MetadataUtils.decryptNodeData(eciesData: item.sessionTokenMetadata[0], ciphertextHex: item.sessionTokens[0], privKey: sessionAuthKeySerialized) + sessionTokens.append(decrypted) + } else { + sessionTokens.append(item.sessionTokens[0]) + } + } else { + sessionTokens.append(nil) + } + + if !item.keys.isEmpty { + let latestKey = item.keys[0] + nodeIndexes.append(latestKey.nodeIndex) + guard let cipherData = Data(base64Encoded: latestKey.share) else { + throw TorusUtilError.decodingFailed("cipher is not base64 encoded") + } + guard let cipherTextHex = String(data: cipherData, encoding: .utf8) else { + throw TorusUtilError.decodingFailed("cipherData is not utf8") + } + let decrypted = try MetadataUtils.decryptNodeData(eciesData: latestKey.shareMetadata, ciphertextHex: cipherTextHex, privKey: sessionAuthKeySerialized) + shares.append(decrypted) + } else { + nodeIndexes.append(nil) + shares.append(nil) + } + } + + let validSigs = sessionTokenSigs.filter({ $0 != nil }).map({ $0! }) + + if verifierParams.extended_verifier_id == nil && validSigs.count < threshold { + throw TorusUtilError.retrieveOrImportShareError + } + + let validTokens = sessionTokens.filter({ $0 != nil }).map({ $0! }) + + if verifierParams.extended_verifier_id == nil && validTokens.count < threshold { + throw TorusUtilError.runtime("Insufficient number of signatures from nodes") + } + + for (i, item) in sessionTokens.enumerated() { + if item == nil { + sessionTokenDatas.append(nil) + } else { + sessionTokenDatas.append(SessionToken(token: item!.data(using: .utf8)!.base64EncodedString(), signature: sessionTokenSigs[i]!.data(using: .utf8)!.hexString, node_pubx: shareResponses[i].nodePubX, node_puby: shareResponses[i].nodePubY)) + } + } + + var decryptedShares: [Int: String] = [:] + for (i, item) in shares.enumerated() { + if item != nil { + decryptedShares.updateValue(item!, forKey: nodeIndexes[i]!) + } + } + let elements = Array(0 ... decryptedShares.keys.max()!) // Note: torus.js has a bug that this line resolves + + let allCombis = kCombinations(elements: elements.slice, k: threshold) + + var privateKey: String? + + for j in 0 ..< allCombis.count { + let currentCombi = allCombis[j] + let currentCombiShares = decryptedShares.filter({ currentCombi.contains($0.key) }) + let shares = currentCombiShares.map({ $0.value }) + let indices = currentCombiShares.map({ $0.key }) + let derivedPrivateKey = try? Lagrange.lagrangeInterpolation(shares: shares, nodeIndex: indices) + if derivedPrivateKey == nil { + continue + } + let decryptedPubKey = try SecretKey(hex: derivedPrivateKey!).toPublic().serialize(compressed: false) + let (decryptedPubKeyX, decryptedPubKeyY) = try KeyUtils.getPublicKeyCoords(pubKey: decryptedPubKey) + let thresholdPubKeyX = thresholdPublicKey!.X.addLeading0sForLength64().lowercased() + let thresholdPubKeyY = thresholdPublicKey!.Y.addLeading0sForLength64().lowercased() + if decryptedPubKeyX.lowercased() == thresholdPubKeyX && decryptedPubKeyY.lowercased() == thresholdPubKeyY { + privateKey = derivedPrivateKey + break + } + } + + if privateKey == nil { + throw TorusUtilError.privateKeyDeriveFailed + } + + let thresholdIsNewKey: String? = try thresholdSame(arr: isNewKeys, threshold: threshold) + + let oAuthKey = privateKey! + let oAuthPublicKey = try SecretKey(hex: oAuthKey).toPublic().serialize(compressed: false) + let (oAuthPublicKeyX, oAuthPublicKeyY) = try KeyUtils.getPublicKeyCoords(pubKey: oAuthPublicKey) + var metadataNonce = BigInt(thresholdNonceData?.nonce?.addLeading0sForLength64() ?? "0", radix: 16) ?? BigInt(0) + var finalPubKey: String? + var pubNonce: PubNonce? + var typeOfUser: UserType = .v1 + if verifierParams.extended_verifier_id != nil { + typeOfUser = .v2 + finalPubKey = oAuthPublicKey + } else if TorusUtils.isLegacyNetworkRouteMap(network: network) { + if enableOneKey { + let isNewKey = !(thresholdIsNewKey == "true") + let nonce = try await MetadataUtils.getOrSetNonce(legacyMetadataHost: legacyMetadataHost, serverTimeOffset: serverTimeOffsetResponse, X: thresholdPublicKey!.X, Y: thresholdPublicKey!.Y, privateKey: oAuthKey, getOnly: isNewKey) + metadataNonce = BigInt(nonce.nonce?.addLeading0sForLength64() ?? "0", radix: 16) ?? BigInt(0) + typeOfUser = UserType(rawValue: nonce.typeOfUser?.lowercased() ?? "v1")! + if typeOfUser == .v2 { + pubNonce = nonce.pubNonce + let publicNonce = KeyUtils.getPublicKeyFromCoords(pubKeyX: pubNonce!.x, pubKeyY: pubNonce!.y) + finalPubKey = try KeyUtils.combinePublicKeys(keys: [oAuthPublicKey, publicNonce]) + } else { + typeOfUser = .v1 + metadataNonce = BigInt(try await MetadataUtils.getMetadata(legacyMetadataHost: legacyMetadataHost, params: GetMetadataParams(pub_key_X: oAuthPublicKeyX, pub_key_Y: oAuthPublicKeyY))) + let privateKeyWithNonce = (BigInt(oAuthKey.addLeading0sForLength64(), radix: 16)! + BigInt(metadataNonce)).modulus(KeyUtils.getOrderOfCurve()) + finalPubKey = try SecretKey(hex: privateKeyWithNonce.magnitude.serialize().hexString.addLeading0sForLength64()).toPublic().serialize(compressed: false) + } + } else { + typeOfUser = .v1 + metadataNonce = BigInt(try await MetadataUtils.getMetadata(legacyMetadataHost: legacyMetadataHost, params: GetMetadataParams(pub_key_X: oAuthPublicKeyX, pub_key_Y: oAuthPublicKeyY))) + let privateKeyWithNonce = (BigInt(oAuthKey.addLeading0sForLength64(), radix: 16)! + BigInt(metadataNonce)).modulus(KeyUtils.getOrderOfCurve()) + finalPubKey = try SecretKey(hex: privateKeyWithNonce.magnitude.serialize().hexString.addLeading0sForLength64()).toPublic().serialize(compressed: false) + } + } else { + typeOfUser = .v2 + let oAuthPubKey = KeyUtils.getPublicKeyFromCoords(pubKeyX: oAuthPublicKeyX, pubKeyY: oAuthPublicKeyY) + finalPubKey = oAuthPubKey + if thresholdNonceData!.pubNonce != nil && !(thresholdNonceData!.pubNonce!.x.isEmpty || thresholdNonceData!.pubNonce!.y.isEmpty) { + let pubNonceKey = thresholdNonceData!.pubNonce! + + let publicNonce = KeyUtils.getPublicKeyFromCoords(pubKeyX: pubNonceKey.x, pubKeyY: pubNonceKey.y) + finalPubKey = try KeyUtils.combinePublicKeys(keys: [oAuthPubKey, publicNonce]) + pubNonce = PubNonce(x: thresholdNonceData!.pubNonce!.x, y: thresholdNonceData!.pubNonce!.y) + } else { + throw TorusUtilError.pubNonceMissing + } + } + + if finalPubKey == nil { + throw TorusUtilError.retrieveOrImportShareError + } + + let oAuthKeyAddress = try KeyUtils.generateAddressFromPubKey(publicKeyX: oAuthPublicKeyX, publicKeyY: oAuthPublicKeyY) + + let (finalPubX, finalPubY) = try KeyUtils.getPublicKeyCoords(pubKey: finalPubKey!) + let finalEvmAddress = try KeyUtils.generateAddressFromPubKey(publicKeyX: finalPubX, publicKeyY: finalPubY) + + var finalPrivKey = "" + if typeOfUser == .v1 || (typeOfUser == .v2 && metadataNonce > BigInt(0)) { + let privateKeyWithNonce = ((BigInt(oAuthKey.addLeading0sForLength64(), radix: 16) ?? BigInt(0)) + metadataNonce).modulus(KeyUtils.getOrderOfCurve()) + finalPrivKey = privateKeyWithNonce.magnitude.serialize().hexString.addLeading0sForLength64() + } + + var isUpgraded: Bool? + if typeOfUser == .v2 { + isUpgraded = metadataNonce == BigInt(0) + } + + return TorusKey( + finalKeyData: TorusKey.FinalKeyData( + evmAddress: finalEvmAddress, + X: finalPubX, + Y: finalPubY, + privKey: finalPrivKey), + oAuthKeyData: TorusKey.OAuthKeyData( + evmAddress: oAuthKeyAddress, + X: oAuthPublicKeyX, + Y: oAuthPublicKeyY, + privKey: oAuthKey), + sessionData: TorusKey.SessionData( + sessionTokenData: sessionTokenDatas, + sessionAuthKey: sessionAuthKeySerialized), + metadata: TorusPublicKey.Metadata( + pubNonce: pubNonce, + nonce: metadataNonce.magnitude, + typeOfUser: typeOfUser, + upgraded: isUpgraded, + serverTimeOffset: serverTimeOffsetResponse), + nodesData: TorusKey.NodesData( + nodeIndexes: nodeIndexes.filter({ $0 != nil }).map({ $0! }) + ) + ) + } +} diff --git a/Sources/TorusUtils/Helpers/NetworkingHelper.swift b/Sources/TorusUtils/Helpers/httpMethod.swift similarity index 51% rename from Sources/TorusUtils/Helpers/NetworkingHelper.swift rename to Sources/TorusUtils/Helpers/httpMethod.swift index 5bc99605..d238535d 100644 --- a/Sources/TorusUtils/Helpers/NetworkingHelper.swift +++ b/Sources/TorusUtils/Helpers/httpMethod.swift @@ -1,6 +1,6 @@ import Foundation -enum HTTPMethod { +internal enum httpMethod { case get case post @@ -13,10 +13,3 @@ enum HTTPMethod { } } } - -extension TorusUtils { - func createURLSession() -> URLSession { - let session = URLSession(configuration: urlSession.configuration) - return session - } -} diff --git a/Sources/TorusUtils/Helpers/jsonRPC/ErrorMessage.swift b/Sources/TorusUtils/Helpers/jsonRPC/ErrorMessage.swift new file mode 100644 index 00000000..c878cfb3 --- /dev/null +++ b/Sources/TorusUtils/Helpers/jsonRPC/ErrorMessage.swift @@ -0,0 +1,20 @@ +import Foundation + +internal struct ErrorMessage: Codable { + public var code: Int + public var message: String + public var data: String + + enum ErrorMessageKeys: String, CodingKey { + case code + case message + case data + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: ErrorMessageKeys.self) + try container.encode(message, forKey: .message) + try container.encode(code, forKey: .code) + try container.encode(data, forKey: .data) + } +} diff --git a/Sources/TorusUtils/Helpers/jsonRPC/JRPCRequest.swift b/Sources/TorusUtils/Helpers/jsonRPC/JRPCRequest.swift new file mode 100644 index 00000000..15fbcd58 --- /dev/null +++ b/Sources/TorusUtils/Helpers/jsonRPC/JRPCRequest.swift @@ -0,0 +1,16 @@ +import Foundation + +/// JSON RPC request structure for serialization and deserialization purposes. +internal struct JRPCRequest: Encodable { + public var jsonrpc: String = "2.0" + public var method: String + public var params: T + public var id: Int = 10 + + enum CodingKeys: String, CodingKey { + case jsonrpc + case method + case params + case id + } +} diff --git a/Sources/TorusUtils/Helpers/jsonRPC/JRPCResponse.swift b/Sources/TorusUtils/Helpers/jsonRPC/JRPCResponse.swift new file mode 100644 index 00000000..1b79b0f9 --- /dev/null +++ b/Sources/TorusUtils/Helpers/jsonRPC/JRPCResponse.swift @@ -0,0 +1,51 @@ +import Foundation + +internal struct AllowSuccess: Codable { + public let success: Bool +} + +internal struct AllowRejected: Codable { + public let code: Int32 + public let error: String + public let success: Bool +} + +internal struct JRPCResponse: Codable { + public var id: Int + public var jsonrpc = "2.0" + public var result: T? + public var error: ErrorMessage? + public var message: String? + + enum JRPCResponseKeys: String, CodingKey { + case id + case jsonrpc + case result + case error + case errorMessage + } + + public init(id: Int, jsonrpc: String, result: T?, error: ErrorMessage?) { + self.id = id + self.jsonrpc = jsonrpc + self.result = result + self.error = error + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: JRPCResponseKeys.self) + let id: Int = try container.decode(Int.self, forKey: .id) + let jsonrpc: String = try container.decode(String.self, forKey: .jsonrpc) + let errorMessage = try container.decodeIfPresent(ErrorMessage.self, forKey: .error) + if errorMessage != nil { + self.init(id: id, jsonrpc: jsonrpc, result: nil, error: errorMessage) + return + } + + var result: T? + if let rawValue = try? container.decodeIfPresent(T.self, forKey: .result) { + result = rawValue + } + self.init(id: id, jsonrpc: jsonrpc, result: result, error: nil) + } +} diff --git a/Sources/TorusUtils/Helpers/jsonRPC/Requests/CommitmentRequestParams.swift b/Sources/TorusUtils/Helpers/jsonRPC/Requests/CommitmentRequestParams.swift new file mode 100644 index 00000000..1ca18dda --- /dev/null +++ b/Sources/TorusUtils/Helpers/jsonRPC/Requests/CommitmentRequestParams.swift @@ -0,0 +1,10 @@ +import Foundation + +internal struct CommitmentRequestParams: Codable { + public var messageprefix: String + public var tokencommitment: String + public var temppubx: String + public var temppuby: String + public var verifieridentifier: String + public var timestamp: String? +} diff --git a/Sources/TorusUtils/Helpers/jsonRPC/Requests/GetNonceParams.swift b/Sources/TorusUtils/Helpers/jsonRPC/Requests/GetNonceParams.swift new file mode 100644 index 00000000..a7872433 --- /dev/null +++ b/Sources/TorusUtils/Helpers/jsonRPC/Requests/GetNonceParams.swift @@ -0,0 +1,11 @@ +import Foundation + +internal struct GetNonceSetDataParams: Codable { + public var data: String +} + +internal struct GetNonceParams: Codable { + public var pub_key_X: String + public var pub_key_Y: String + public var set_data: GetNonceSetDataParams +} diff --git a/Sources/TorusUtils/Helpers/jsonRPC/Requests/GetOrSetKeyParams.swift b/Sources/TorusUtils/Helpers/jsonRPC/Requests/GetOrSetKeyParams.swift new file mode 100644 index 00000000..89493162 --- /dev/null +++ b/Sources/TorusUtils/Helpers/jsonRPC/Requests/GetOrSetKeyParams.swift @@ -0,0 +1,11 @@ +import Foundation + +internal struct GetOrSetKeyParams: Codable { + public var distributed_metadata: Bool + public var verifier: String + public var verifier_id: String + public var extended_verifier_id: String? + public var one_key_flow: Bool + public var fetch_node_index: Bool + public var client_time: String +} diff --git a/Sources/TorusUtils/Helpers/jsonRPC/Requests/NonceMetadataParams.swift b/Sources/TorusUtils/Helpers/jsonRPC/Requests/NonceMetadataParams.swift new file mode 100644 index 00000000..de6b00ac --- /dev/null +++ b/Sources/TorusUtils/Helpers/jsonRPC/Requests/NonceMetadataParams.swift @@ -0,0 +1,23 @@ +import Foundation + +internal struct NonceMetadataParams { + public var namespace: String? + public var pub_key_X: String + public var pub_key_Y: String + public var set_data: SetNonceData + public var key_type: TorusKeyType + public var signature: String + public var encodedData: String + public var seed: String? + + public init(pub_key_X: String, pub_key_Y: String, setData: SetNonceData, encodedData: String, signature: String, namespace: String? = nil, key_type: TorusKeyType = .secp256k1, seed: String? = nil) { + self.namespace = namespace + self.pub_key_X = pub_key_X + self.pub_key_Y = pub_key_Y + set_data = setData + self.signature = signature + self.seed = seed + self.key_type = key_type + self.encodedData = encodedData + } +} diff --git a/Sources/TorusUtils/Helpers/jsonRPC/Requests/SetNonceData.swift b/Sources/TorusUtils/Helpers/jsonRPC/Requests/SetNonceData.swift new file mode 100644 index 00000000..9d322447 --- /dev/null +++ b/Sources/TorusUtils/Helpers/jsonRPC/Requests/SetNonceData.swift @@ -0,0 +1,28 @@ +import Foundation + +internal struct SetNonceData: Codable { + public var operation: String? + public var data: String? + public var timestamp: String? + public var seed: String? + + public init(operation: String? = nil, data: String? = nil, timestamp: String? = nil, seed: String? = nil) { + self.operation = operation + self.data = data + self.timestamp = timestamp + self.seed = seed + } + + public func encode(to encoder: any Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(operation, forKey: .operation) + try container.encodeIfPresent(data, forKey: .data) + try container.encodeIfPresent(timestamp, forKey: .timestamp) + // There is a bug in the server that expects seed to be empty and not optional, when it checks signatures. It is optional in the interface though. + if seed == nil { + try container.encode("", forKey: .seed) + } else { + try container.encode(seed, forKey: .seed) + } + } +} diff --git a/Sources/TorusUtils/Helpers/jsonRPC/Requests/ShareRequestParams.swift b/Sources/TorusUtils/Helpers/jsonRPC/Requests/ShareRequestParams.swift new file mode 100644 index 00000000..637da76c --- /dev/null +++ b/Sources/TorusUtils/Helpers/jsonRPC/Requests/ShareRequestParams.swift @@ -0,0 +1,63 @@ +import Foundation + +internal struct ShareRequestParams: Codable { + public struct ShareRequestItem: Codable { + public var verifieridentifier: String + public var verifier_id: String? + public var extended_verifier_id: String? + public var idtoken: String + public var nodesignatures: [CommitmentRequestResult?] + public var pub_key_x: String? + public var pub_key_y: String? + public var signing_pub_key_x: String? + public var signing_pub_key_y: String? + public var encrypted_share: String? + public var encrypted_share_metadata: EciesHexOmitCiphertext? + public var node_index: Int? + public var key_type: TorusKeyType? + public var nonce_data: String? + public var nonce_signature: String? + public var sub_verifier_ids: [String]? + public var session_token_exp_second: Int? + public var verify_params: [VerifyParams?]? + public var sss_endpoint: String? + + // TODO: This is a bit of a mess from here due to legacy reasons and should be cleaned up in future. + // Note: Nil values by default are excluded from serialization + public var enable_verifier_id_hash: Bool? // most + public var app_s: String? // meta + public var app_id: String? // meta + public var domain: String? // farcaster + public var nonce: String? // farcaster + public var message: String? // farcaster + public var signature: String? // farcaster, passkey, webauthn + public var clientDataJson: String? // passkey, webauthn + public var authenticatorData: String? // passkey, webauthn + public var publicKey: String? // passkey, webauthn + public var challenge: String? // passkey, webauthn + public var rpOrigin: String? // passkey, webauthn + public var rpId: String? // passkey, webauthn + public var jwk_endpoint: String? // passkey, jwt + public var default_node_set: [String]? // passkey, jwt + public var jwt_verifier_id_field: String? // passkey, jwt + public var jwt_verifier_id_case_sensitive: Bool? // passkey, jwt + public var jwk_keys: String? // passkey, jwt + public var jwt_validation_fields: [String]? // passkey, jwt + public var jwt_validation_values: [String]? // passkey, jwt + public var index: Int? // demo + public var email: String? // demo + public var id: String? // test, jwt, passkey + public var correct_id_token: String? // test + public var verify_param: String? // OrAggregate + public var threshold: Int? // SingleID + public var pub_k_x: String? // Signature + public var pub_k_y: String? // Signature + } + + public var encrypted: String = "yes" + public var item: [ShareRequestItem] + public var use_temp: Bool = true + public var distributed_metadata: Bool = true + public var one_key_flow: Bool = true + public var client_time: String +} diff --git a/Sources/TorusUtils/Helpers/jsonRPC/Responses/CommitmentRequestResult.swift b/Sources/TorusUtils/Helpers/jsonRPC/Responses/CommitmentRequestResult.swift new file mode 100644 index 00000000..9fc6f376 --- /dev/null +++ b/Sources/TorusUtils/Helpers/jsonRPC/Responses/CommitmentRequestResult.swift @@ -0,0 +1,17 @@ +import Foundation + +internal struct CommitmentRequestResult: Codable { + public var signature: String + public var data: String + public var nodepubx: String + public var nodepuby: String + public var nodeindex: String + + public init(data: String, nodepubx: String, nodepuby: String, signature: String, nodeindex: String) { + self.data = data + self.nodepubx = nodepubx + self.nodepuby = nodepuby + self.signature = signature + self.nodeindex = nodeindex + } +} diff --git a/Sources/TorusUtils/Helpers/jsonRPC/Responses/GetMetadataResponse.swift b/Sources/TorusUtils/Helpers/jsonRPC/Responses/GetMetadataResponse.swift new file mode 100644 index 00000000..1b5c360e --- /dev/null +++ b/Sources/TorusUtils/Helpers/jsonRPC/Responses/GetMetadataResponse.swift @@ -0,0 +1,9 @@ +import Foundation + +internal struct GetMetadataResponse: Codable { + public var message: String + + public init(message: String) { + self.message = message + } +} diff --git a/Sources/TorusUtils/Helpers/jsonRPC/Responses/GetOrSetNonceResult.swift b/Sources/TorusUtils/Helpers/jsonRPC/Responses/GetOrSetNonceResult.swift new file mode 100644 index 00000000..2daa7681 --- /dev/null +++ b/Sources/TorusUtils/Helpers/jsonRPC/Responses/GetOrSetNonceResult.swift @@ -0,0 +1,27 @@ +import Foundation + +internal struct GetOrSetNonceResult: Codable { + public var typeOfUser: String? + public var nonce: String? + public var pubNonce: PubNonce? + public var ifps: String? + public var upgraded: Bool? + + public init(typeOfUser: String, nonce: String? = nil, pubNonce: PubNonce? = nil, ifps: String? = nil, upgraded: Bool? = false) { + self.typeOfUser = typeOfUser + self.nonce = nonce + self.pubNonce = pubNonce + self.ifps = ifps + self.upgraded = upgraded + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + typeOfUser = try container.decodeIfPresent(String.self, forKey: .typeOfUser) + nonce = try container.decodeIfPresent(String.self, forKey: .nonce) + pubNonce = try container.decodeIfPresent(PubNonce.self, forKey: .pubNonce) + ifps = try container.decodeIfPresent(String.self, forKey: .ifps) + upgraded = try container.decodeIfPresent(Bool.self, forKey: .upgraded) + } +} diff --git a/Sources/TorusUtils/Helpers/jsonRPC/Responses/KeyAssignment.swift b/Sources/TorusUtils/Helpers/jsonRPC/Responses/KeyAssignment.swift new file mode 100644 index 00000000..7157fae1 --- /dev/null +++ b/Sources/TorusUtils/Helpers/jsonRPC/Responses/KeyAssignment.swift @@ -0,0 +1,49 @@ +import Foundation + +internal struct KeyAssignment: Codable { + let index: String + let publicKey: PublicKey + let threshold: Int + let nodeIndex: Int + let share: String + let shareMetadata: EciesHexOmitCiphertext + let nonceData: GetOrSetNonceResult? + + struct PublicKey: Hashable, Codable { + let X: String + let Y: String + } + + enum CodingKeys: CodingKey { + case index + case public_key + case threshold + case node_index + case share + case share_metadata + case nonce_data + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(index, forKey: .index) + try container.encode(publicKey, forKey: .public_key) + try container.encode(threshold, forKey: .threshold) + try container.encode(nodeIndex, forKey: .node_index) + try container.encode(share, forKey: .share) + try container.encode(shareMetadata, forKey: .share_metadata) + try container.encodeIfPresent(nonceData, forKey: .nonce_data) + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + index = try container.decode(String.self, forKey: .index) + + publicKey = try container.decode(PublicKey.self, forKey: .public_key) + threshold = Int(try container.decode(String.self, forKey: .threshold))! + nodeIndex = Int(try container.decode(String.self, forKey: .node_index))! + share = try container.decode(String.self, forKey: .share) + shareMetadata = try container.decode(EciesHexOmitCiphertext.self, forKey: .share_metadata) + nonceData = try container.decodeIfPresent(GetOrSetNonceResult.self, forKey: .nonce_data) + } +} diff --git a/Sources/TorusUtils/Helpers/jsonRPC/Responses/ShareRequestResult.swift b/Sources/TorusUtils/Helpers/jsonRPC/Responses/ShareRequestResult.swift new file mode 100644 index 00000000..5e72d550 --- /dev/null +++ b/Sources/TorusUtils/Helpers/jsonRPC/Responses/ShareRequestResult.swift @@ -0,0 +1,76 @@ +import Foundation + +internal struct ShareRequestResult: Codable { + let keys: [KeyAssignment] + let sessionTokens: [String] + let sessionTokenMetadata: [EciesHexOmitCiphertext] + let sessionTokenSigs: [String] + let sessionTokenSigMetadata: [EciesHexOmitCiphertext] + let nodePubX: String + let nodePubY: String + let isNewKey: String + let serverTimeOffset: String + + enum CodingKeys: CodingKey { + case keys + case session_tokens + case session_token_metadata + case session_token_sigs + case session_token_sig_metadata + case node_pubx + case node_puby + case is_new_key + case server_time_offset + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(keys, forKey: .keys) + try container.encode(sessionTokens, forKey: .session_tokens) + try container.encode(sessionTokenMetadata, forKey: .session_token_metadata) + try container.encode(sessionTokenSigs, forKey: .session_token_sigs) + try container.encode(sessionTokenSigMetadata, forKey: .session_token_sig_metadata) + try container.encode(nodePubX, forKey: .node_pubx) + try container.encode(nodePubX, forKey: .node_puby) + try container.encode(isNewKey, forKey: .is_new_key) + try container.encode(serverTimeOffset, forKey: .server_time_offset) + } + + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + keys = try container.decode([KeyAssignment].self, forKey: .keys) + nodePubX = try container.decode(String.self, forKey: .node_pubx) + nodePubY = try container.decode(String.self, forKey: .node_puby) + isNewKey = try container.decode(String.self, forKey: .is_new_key) + + if let sessionTokens = try? container.decodeIfPresent([String].self, forKey: .session_tokens) { + self.sessionTokens = sessionTokens + } else { + sessionTokens = [] + } + + if let sessionTokenMetadata = try? container.decodeIfPresent([EciesHexOmitCiphertext].self, forKey: .session_token_metadata) { + self.sessionTokenMetadata = sessionTokenMetadata + } else { + sessionTokenMetadata = [] + } + + if let sessionTokenSigs = try? container.decodeIfPresent([String].self, forKey: .session_token_sigs) { + self.sessionTokenSigs = sessionTokenSigs + } else { + sessionTokenSigs = [] + } + + if let sessionTokenSigMetadata = try? container.decodeIfPresent([EciesHexOmitCiphertext].self, forKey: .session_token_sig_metadata) { + self.sessionTokenSigMetadata = sessionTokenSigMetadata + } else { + sessionTokenSigMetadata = [] + } + + if let serverTimeOffset = try? container.decodeIfPresent(String.self, forKey: .server_time_offset) { + self.serverTimeOffset = serverTimeOffset + } else { + serverTimeOffset = "0" + } + } +} diff --git a/Sources/TorusUtils/Helpers/jsonRPC/Responses/VerifierLookupResponse/LegacyVerifierLookupResponse.swift b/Sources/TorusUtils/Helpers/jsonRPC/Responses/VerifierLookupResponse/LegacyVerifierLookupResponse.swift new file mode 100644 index 00000000..10109b53 --- /dev/null +++ b/Sources/TorusUtils/Helpers/jsonRPC/Responses/VerifierLookupResponse/LegacyVerifierLookupResponse.swift @@ -0,0 +1,42 @@ +import Foundation + +internal struct LegacyVerifierLookupResponse: Codable { + public struct Key: Codable { + let pub_key_X: String + let pub_key_Y: String + let address: String + + init(pub_key_X: String, pub_key_Y: String, address: String) { + self.pub_key_X = pub_key_X + self.pub_key_Y = pub_key_Y + self.address = address + } + + enum JSONRPCresponseKeys: String, CodingKey { + case pub_key_X + case pub_key_Y + case address + } + + public init(from: Decoder) throws { + let container = try from.container(keyedBy: CodingKeys.self) + pub_key_X = try container.decode(String.self, forKey: .pub_key_X) + pub_key_Y = try container.decode(String.self, forKey: .pub_key_Y) + address = try container.decode(String.self, forKey: .address) + } + } + + var keys: [Key] + var server_time_offset: String? + + public init(keys: [Key], serverTimeOffset: String? = nil) { + self.keys = keys + server_time_offset = serverTimeOffset + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + keys = try container.decode([LegacyVerifierLookupResponse.Key].self, forKey: .keys) + server_time_offset = try container.decodeIfPresent(String.self, forKey: .server_time_offset) + } +} diff --git a/Sources/TorusUtils/Interfaces/VerifierLookupResponse.swift b/Sources/TorusUtils/Helpers/jsonRPC/Responses/VerifierLookupResponse/VerifierLookupResponse.swift similarity index 57% rename from Sources/TorusUtils/Interfaces/VerifierLookupResponse.swift rename to Sources/TorusUtils/Helpers/jsonRPC/Responses/VerifierLookupResponse/VerifierLookupResponse.swift index 47b02705..a38f6d68 100644 --- a/Sources/TorusUtils/Interfaces/VerifierLookupResponse.swift +++ b/Sources/TorusUtils/Helpers/jsonRPC/Responses/VerifierLookupResponse/VerifierLookupResponse.swift @@ -1,7 +1,7 @@ import Foundation -struct VerifierLookupResponse: Codable { - struct Key: Codable { +internal struct VerifierLookupResponse: Codable { + public struct Key: Codable { let pub_key_X: String let pub_key_Y: String let address: String @@ -38,11 +38,12 @@ struct VerifierLookupResponse: Codable { } } - var keys: [Key]? + var keys: [Key] var is_new_key: Bool var node_index: String + var server_time_offset: String? - public init(keys: [Key]?, is_new_key: Bool, node_index: String) { + public init(keys: [Key], is_new_key: Bool, node_index: String) { self.keys = keys self.is_new_key = is_new_key self.node_index = node_index @@ -50,40 +51,9 @@ struct VerifierLookupResponse: Codable { public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) - keys = try container.decodeIfPresent([VerifierLookupResponse.Key].self, forKey: .keys) + keys = try container.decode([VerifierLookupResponse.Key].self, forKey: .keys) is_new_key = try container.decode(Bool.self, forKey: .is_new_key) node_index = try container.decode(String.self, forKey: .node_index) + server_time_offset = try container.decodeIfPresent(String.self, forKey: .server_time_offset) } } - -public struct LegacyLookupResponse: Decodable { - public struct KeyLookup: Decodable { - public var index: String - public var metadata: EciesHexOmitCiphertext - public var publicKey: Point - public var share: String - public var threshold: Int - public var verifier: [String: [String]] - - public enum CodingKeys: CodingKey { - case Index - case Metadata - case PublicKey - case Share - case Threshold - case Verifiers - } - - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - index = try container.decode(String.self, forKey: .Index) - metadata = try container.decode(EciesHexOmitCiphertext.self, forKey: .Metadata) - publicKey = try container.decode(Point.self, forKey: .PublicKey) - share = try container.decode(String.self, forKey: .Share) - threshold = try container.decode(Int.self, forKey: .Threshold) - verifier = try container.decode([String: [String]].self, forKey: .Verifiers) - } - } - - public var keys: [KeyLookup] -} diff --git a/Sources/TorusUtils/Interfaces/CommitmentRequestResponse.swift b/Sources/TorusUtils/Interfaces/CommitmentRequestResponse.swift deleted file mode 100644 index 98b6e51e..00000000 --- a/Sources/TorusUtils/Interfaces/CommitmentRequestResponse.swift +++ /dev/null @@ -1,30 +0,0 @@ -import Foundation - -public struct CommitmentRequestResponse: Codable { - public var data: String - public var nodepubx: String - public var nodepuby: String - public var signature: String - - public init(data: String, nodepubx: String, nodepuby: String, signature: String) { - self.data = data - self.nodepubx = nodepubx - self.nodepuby = nodepuby - self.signature = signature - } -} - -extension Array where Element == CommitmentRequestResponse { - public func tostringDict() -> [[String: String]] { - var dictArr = [[String: String]]() - for val in self { - var dict = [String: String]() - dict["data"] = val.data - dict["nodepubx"] = val.nodepubx - dict["nodepuby"] = val.nodepuby - dict["signature"] = val.signature - dictArr.append(dict) - } - return dictArr - } -} diff --git a/Sources/TorusUtils/Interfaces/Ecies.swift b/Sources/TorusUtils/Interfaces/Common/Ecies.swift similarity index 73% rename from Sources/TorusUtils/Interfaces/Ecies.swift rename to Sources/TorusUtils/Interfaces/Common/Ecies.swift index cf5fc141..3ca27b9c 100644 --- a/Sources/TorusUtils/Interfaces/Ecies.swift +++ b/Sources/TorusUtils/Interfaces/Common/Ecies.swift @@ -7,7 +7,7 @@ protocol EciesProtocol { var mac: Data { get } } -public struct ECIES: Codable { +internal struct ECIES: Codable { let iv: String let ephemPublicKey: String let ciphertext: String @@ -23,14 +23,14 @@ public struct ECIES: Codable { } } -public struct EciesHex: Codable { +internal struct EciesHex: Codable { let iv: String let ephemPublicKey: String - let ciphertext: String? + let ciphertext: String let mac: String let mode: String? - init(iv: String, ephemPublicKey: String, ciphertext: String?, mac: String, mode: String?) { + init(iv: String, ephemPublicKey: String, ciphertext: String, mac: String, mode: String?) { self.iv = iv self.ephemPublicKey = ephemPublicKey self.ciphertext = ciphertext @@ -38,12 +38,20 @@ public struct EciesHex: Codable { self.mode = mode } + init(from: Ecies) { + ciphertext = from.ciphertext + iv = from.iv + ephemPublicKey = from.ephemPublicKey + mac = from.mac + mode = "AES256" + } + func omitCiphertext() -> EciesHexOmitCiphertext { return EciesHexOmitCiphertext(iv: iv, ephemPublicKey: ephemPublicKey, mac: mac, mode: mode) } } -public struct EciesHexOmitCiphertext: Decodable { +internal struct EciesHexOmitCiphertext: Codable { var iv: String var ephemPublicKey: String var mac: String @@ -62,9 +70,16 @@ public struct EciesHexOmitCiphertext: Decodable { mac = from.mac mode = from.mode } + + init(from: Ecies) { + iv = from.iv + ephemPublicKey = from.ephemPublicKey + mac = from.mac + mode = "AES256" + } } -public struct Ecies: Codable { +internal struct Ecies: Codable { var iv: String var ephemPublicKey: String var ciphertext: String @@ -78,7 +93,7 @@ public struct Ecies: Codable { } } -struct EciesOmitCiphertext { +internal struct EciesOmitCiphertext { var iv: String var ephemPublicKey: String var mac: String diff --git a/Sources/TorusUtils/Interfaces/Common/INodePub.swift b/Sources/TorusUtils/Interfaces/Common/INodePub.swift new file mode 100644 index 00000000..f8021656 --- /dev/null +++ b/Sources/TorusUtils/Interfaces/Common/INodePub.swift @@ -0,0 +1,16 @@ +import FetchNodeDetails +import Foundation + +internal class INodePub { + let X: String + let Y: String + + init(X: String, Y: String) { + self.X = X + self.Y = Y + } +} + +internal func TorusNodePubModelToINodePub(nodes: [TorusNodePubModel]) -> [INodePub] { + return nodes.map({ INodePub(X: $0.getX(), Y: $0.getY()) }) +} diff --git a/Sources/TorusUtils/Interfaces/Common/ImportedShare.swift b/Sources/TorusUtils/Interfaces/Common/ImportedShare.swift new file mode 100644 index 00000000..4218c932 --- /dev/null +++ b/Sources/TorusUtils/Interfaces/Common/ImportedShare.swift @@ -0,0 +1,32 @@ +import BigInt +import Foundation + +internal struct ImportedShare: Codable { + let oauth_pub_key_x: String + let oauth_pub_key_y: String + let final_user_point: Point + let signing_pub_key_x: String + let signing_pub_key_y: String + let encryptedShare: String + let encryptedShareMetadata: EciesHexOmitCiphertext + let encryptedSeed: String? + let node_index: Int + let key_type: TorusKeyType + let nonce_data: String + let nonce_signature: String + + public init(oauth_pub_key_x: String, oauth_pub_key_y: String, final_user_point: Point, signing_pub_key_x: String, signing_pub_key_y: String, encryptedShare: String, encryptedShareMetadata: EciesHexOmitCiphertext, encryptedSeed: String? = nil, node_index: Int, key_type: TorusKeyType = .secp256k1, nonce_data: String, nonce_signature: String) { + self.oauth_pub_key_x = oauth_pub_key_x + self.oauth_pub_key_y = oauth_pub_key_y + self.final_user_point = final_user_point + self.signing_pub_key_x = signing_pub_key_x + self.signing_pub_key_y = signing_pub_key_y + self.encryptedShare = encryptedShare + self.encryptedShareMetadata = encryptedShareMetadata + self.encryptedSeed = encryptedSeed + self.node_index = node_index + self.key_type = key_type + self.nonce_data = nonce_data + self.nonce_signature = nonce_signature + } +} diff --git a/Sources/TorusUtils/Interfaces/Common/PrivateKeyData.swift b/Sources/TorusUtils/Interfaces/Common/PrivateKeyData.swift new file mode 100644 index 00000000..5b1fcce9 --- /dev/null +++ b/Sources/TorusUtils/Interfaces/Common/PrivateKeyData.swift @@ -0,0 +1,12 @@ +import BigInt +import Foundation + +internal struct PrivateKeyData { + let oAuthKey: String + let oAuthPubKey: String + let nonce: String + let signingKey: String + let signingPubKey: String + let finalKey: String + let finalPubKey: String +} diff --git a/Sources/TorusUtils/Interfaces/Common/PubNonce.swift b/Sources/TorusUtils/Interfaces/Common/PubNonce.swift new file mode 100644 index 00000000..2af7a647 --- /dev/null +++ b/Sources/TorusUtils/Interfaces/Common/PubNonce.swift @@ -0,0 +1,21 @@ +import Foundation + +public class PubNonce: Codable, Equatable { + public static func == (lhs: PubNonce, rhs: PubNonce) -> Bool { + return lhs.x == rhs.x && lhs.y == rhs.y + } + + public var x: String + public var y: String + + internal init(x: String, y: String) { + self.x = x + self.y = y + } + + public required init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + x = try container.decode(String.self, forKey: .x) + y = try container.decode(String.self, forKey: .y) + } +} diff --git a/Sources/TorusUtils/Interfaces/Common/SessionToken.swift b/Sources/TorusUtils/Interfaces/Common/SessionToken.swift new file mode 100644 index 00000000..ccd052bf --- /dev/null +++ b/Sources/TorusUtils/Interfaces/Common/SessionToken.swift @@ -0,0 +1,15 @@ +import Foundation + +public class SessionToken: Codable { + public let token: String + public let signature: String + public let node_pubx: String + public let node_puby: String + + internal init(token: String, signature: String, node_pubx: String, node_puby: String) { + self.token = token + self.signature = signature + self.node_pubx = node_pubx + self.node_puby = node_puby + } +} diff --git a/Sources/TorusUtils/Interfaces/Common/UserType.swift b/Sources/TorusUtils/Interfaces/Common/UserType.swift new file mode 100644 index 00000000..b78007f7 --- /dev/null +++ b/Sources/TorusUtils/Interfaces/Common/UserType.swift @@ -0,0 +1,6 @@ +import Foundation + +public enum UserType: String, Codable, Equatable, Hashable { + case v1 + case v2 +} diff --git a/Sources/TorusUtils/Interfaces/ImportedShare.swift b/Sources/TorusUtils/Interfaces/ImportedShare.swift deleted file mode 100644 index 22b46c99..00000000 --- a/Sources/TorusUtils/Interfaces/ImportedShare.swift +++ /dev/null @@ -1,13 +0,0 @@ -import BigInt -import Foundation - -struct ImportedShare { - let pubKeyX: String - let pubKeyY: String - let encryptedShare: String - let encryptedShareMetadata: EciesHex - let nodeIndex: Int - let keyType: String - let nonceData: String - let nonceSignature: String -} diff --git a/Sources/TorusUtils/Interfaces/KeyAssignInput.swift b/Sources/TorusUtils/Interfaces/KeyAssignInput.swift deleted file mode 100644 index 597ca036..00000000 --- a/Sources/TorusUtils/Interfaces/KeyAssignInput.swift +++ /dev/null @@ -1,107 +0,0 @@ -import Foundation - -public struct KeyIndex: Decodable { - let index: String - let serviceGroupId: String - let tag: String - - enum CodingKeys: CodingKey { - case index - case service_group_id - case tag - } - - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - index = try container.decode(String.self, forKey: .index) - serviceGroupId = try container.decode(String.self, forKey: .service_group_id) - tag = try container.decode(String.self, forKey: .tag) - } -} - -enum keyIndexTag: String { - case imported - case generated -} - -public struct KeyAssignInput { - let endpoints: [String] - let torusNodePubs: [INodePub] - let lastPoint: Int? - let firstPoint: Int? - let verifier: String - let verifierId: String - let signerHost: String - let network: String - let clientId: String -} - -public struct KeyAssignment: Decodable { - let index: String - let publicKey: PublicKey - let threshold: Int - let nodeIndex: Int - let share: String - let shareMetadata: EciesHex - let nonceData: GetOrSetNonceResult? - - struct PublicKey: Hashable, Codable { - let X: String - let Y: String - } - - enum CodingKeys: CodingKey { - case index - case public_key - case threshold - case node_index - case share - case share_metadata - case nonce_data - } - - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - index = try container.decode(String.self, forKey: .index) - - publicKey = try container.decode(PublicKey.self, forKey: .public_key) - threshold = Int(try container.decode(String.self, forKey: .threshold))! - nodeIndex = Int(try container.decode(String.self, forKey: .node_index))! - share = try container.decode(String.self, forKey: .share) - shareMetadata = try container.decode(EciesHex.self, forKey: .share_metadata) - nonceData = try container.decodeIfPresent(GetOrSetNonceResult.self, forKey: .nonce_data) - } -} - -public struct LegacyKeyAssignment: Decodable { - let index: String - let publicKey: PublicKey - let threshold: String - let verifiers: [String: [String]] - let share: String - let metadata: EciesHex - - struct PublicKey: Hashable, Codable { - let X: String - let Y: String - } - - enum CodingKeys: CodingKey { - case Index - case PublicKey - case Threshold - case Verifiers - case Share - case Metadata - } - - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - index = try container.decode(String.self, forKey: .Index) - publicKey = try container.decode(PublicKey.self, forKey: .PublicKey) - threshold = try container.decode(String.self, forKey: .Threshold) - verifiers = try container.decode([String: [String]].self, forKey: .Verifiers) - share = try container.decode(String.self, forKey: .Share) - metadata = try container.decode(EciesHex.self, forKey: .Metadata) - } -} diff --git a/Sources/TorusUtils/Interfaces/KeyLookup/KeyLookupResult.swift b/Sources/TorusUtils/Interfaces/KeyLookup/KeyLookupResult.swift new file mode 100644 index 00000000..4b6b01ba --- /dev/null +++ b/Sources/TorusUtils/Interfaces/KeyLookup/KeyLookupResult.swift @@ -0,0 +1,32 @@ +import Foundation + +internal struct KeyLookupResult { + public struct KeyResult: Codable { + public var keys: [VerifierLookupResponse.Key] + public var is_new_key: Bool + + public init(keys: [VerifierLookupResponse.Key], is_new_key: Bool) { + self.keys = keys + self.is_new_key = is_new_key + } + + public init(is_new_key: Bool) { + keys = [] + self.is_new_key = is_new_key + } + } + + public let keyResult: KeyResult? + public let nodeIndexes: [Int] + public let serverTimeOffset: Int + public let nonceResult: GetOrSetNonceResult? + public let errorResult: ErrorMessage? + + public init(keyResult: KeyResult?, nodeIndexes: [Int], serverTimeOffset: Int, nonceResult: GetOrSetNonceResult?, errorResult: ErrorMessage?) { + self.keyResult = keyResult + self.nodeIndexes = nodeIndexes + self.serverTimeOffset = serverTimeOffset + self.nonceResult = nonceResult + self.errorResult = errorResult + } +} diff --git a/Sources/TorusUtils/Interfaces/KeyLookupResponse.swift b/Sources/TorusUtils/Interfaces/KeyLookupResponse.swift deleted file mode 100644 index a3bcb1c7..00000000 --- a/Sources/TorusUtils/Interfaces/KeyLookupResponse.swift +++ /dev/null @@ -1,65 +0,0 @@ -import Foundation - -public struct LegacyKeyLookupResponse: CustomStringConvertible, Hashable { - public let pubKeyX: String - public let pubKeyY: String - public let keyIndex: String - public let address: String - public var description: String { - return "public key X is \(pubKeyX) public key Y is \(pubKeyY) address is \(address)" - } - - public init(pubKeyX: String, pubKeyY: String, keyIndex: String, address: String) { - self.pubKeyX = pubKeyX - self.pubKeyY = pubKeyY - self.keyIndex = keyIndex - self.address = address - } -} - -public struct KeyLookupResponse: CustomStringConvertible, Hashable { - public let pubKeyX: String - public let pubKeyY: String - public let address: String - public let isNewKey: Bool - - public var description: String { - return "public key X is \(pubKeyX) public key Y is \(pubKeyY) address is \(address)" - } - - public init(pubKeyX: String, pubKeyY: String, address: String, isNewKey: Bool) { - self.pubKeyX = pubKeyX - self.pubKeyY = pubKeyY - self.address = address - self.isNewKey = isNewKey - } -} - -public enum KeyLookupError: Error { - case verifierNotSupported - case verifierAndVerifierIdNotAssigned - case configError - - static func createErrorFromString(errorString: String) -> Self { - if errorString.contains("Verifier not supported") { - return .verifierNotSupported - } else if errorString.contains("Verifier + VerifierID has not yet been assigned") { - return .verifierAndVerifierIdNotAssigned - } else { - return .configError - } - } -} - -extension KeyLookupError: LocalizedError { - public var errorDescription: String? { - switch self { - case .verifierNotSupported: - return "Verifier not supported. Check if you: \n1. Are on the right network (Torus testnet/mainnet) \n2. Have setup a verifier on dashboterard.web3auth.io?" - case .verifierAndVerifierIdNotAssigned: - return "Verifier + VerifierID has not yet been assigned" - case .configError: - return "ConfigurationError" - } - } -} diff --git a/Sources/TorusUtils/Interfaces/KeyLookupResult.swift b/Sources/TorusUtils/Interfaces/KeyLookupResult.swift deleted file mode 100644 index ce04a3cd..00000000 --- a/Sources/TorusUtils/Interfaces/KeyLookupResult.swift +++ /dev/null @@ -1,7 +0,0 @@ -import Foundation - -struct KeyLookupResult { - let keyResult: KeyLookupResponse - let nodeIndexes: [Int] - let nonceResult: GetOrSetNonceResult? -} diff --git a/Sources/TorusUtils/Interfaces/MetaData/MetadataParams.swift b/Sources/TorusUtils/Interfaces/MetaData/MetadataParams.swift new file mode 100644 index 00000000..06ff6440 --- /dev/null +++ b/Sources/TorusUtils/Interfaces/MetaData/MetadataParams.swift @@ -0,0 +1,39 @@ +import Foundation + +internal struct GetMetadataParams: Codable { + public var pub_key_X: String + public var pub_key_Y: String + + public init(pub_key_X: String, pub_key_Y: String) { + self.pub_key_X = pub_key_X + self.pub_key_Y = pub_key_Y + } +} + +internal struct MetadataParams: Codable { + public struct SetData: Codable { + public var data: String // "getNonce" || "getOrSetNonce" || String + public var timestamp: String + + public init(data: String, timestamp: String) { + self.data = data + self.timestamp = timestamp + } + } + + public var namespace: String? + public var pub_key_X: String + public var pub_key_Y: String + public var key_type: TorusKeyType? + public var set_data: SetData + public var signature: String + + public init(pub_key_X: String, pub_key_Y: String, setData: SetData, signature: String, namespace: String? = nil, keyType: TorusKeyType? = nil) { + self.namespace = namespace + self.pub_key_X = pub_key_X + self.pub_key_Y = pub_key_Y + key_type = keyType + set_data = setData + self.signature = signature + } +} diff --git a/Sources/TorusUtils/Interfaces/RetrieveDecryptAndReconstuctResponse.swift b/Sources/TorusUtils/Interfaces/RetrieveDecryptAndReconstuctResponse.swift deleted file mode 100644 index a1981aeb..00000000 --- a/Sources/TorusUtils/Interfaces/RetrieveDecryptAndReconstuctResponse.swift +++ /dev/null @@ -1,17 +0,0 @@ -import Foundation - -public struct RetrieveDecryptAndReconstuctResponse { - public let iv: String - public let ephemPublicKey: String - public let share: String - public let pubKeyX: String - public let pubKeyY: String - - public init(iv: String, ephemPublicKey: String, share: String, pubKeyX: String, pubKeyY: String) { - self.iv = iv - self.ephemPublicKey = ephemPublicKey - self.share = share - self.pubKeyX = pubKeyX - self.pubKeyY = pubKeyY - } -} diff --git a/Sources/TorusUtils/Interfaces/RetrieveSharesResponse.swift b/Sources/TorusUtils/Interfaces/RetrieveSharesResponse.swift deleted file mode 100644 index b9c4dfec..00000000 --- a/Sources/TorusUtils/Interfaces/RetrieveSharesResponse.swift +++ /dev/null @@ -1,28 +0,0 @@ -import BigInt -import Foundation - -public struct RetrieveSharesResponse { - public let ethAddress: String - public let privKey: String - public let sessionTokenData: [SessionToken?] - public let X: String - public let Y: String - public let metadataNonce: BigInt - public let postboxPubKeyX: String - public let postboxPubKeyY: String - public let sessionAuthKey: String - public let nodeIndexes: [Int] - - public init(ethAddress: String, privKey: String, sessionTokenData: [SessionToken?], X: String, Y: String, metadataNonce: BigInt, postboxPubKeyX: String, postboxPubKeyY: String, sessionAuthKey: String, nodeIndexes: [Int]) { - self.ethAddress = ethAddress - self.privKey = privKey - self.sessionTokenData = sessionTokenData - self.X = X - self.Y = Y - self.metadataNonce = metadataNonce - self.postboxPubKeyX = postboxPubKeyX - self.postboxPubKeyY = postboxPubKeyY - self.sessionAuthKey = sessionAuthKey - self.nodeIndexes = nodeIndexes - } -} diff --git a/Sources/TorusUtils/Interfaces/SessionToken.swift b/Sources/TorusUtils/Interfaces/SessionToken.swift deleted file mode 100644 index 98297a94..00000000 --- a/Sources/TorusUtils/Interfaces/SessionToken.swift +++ /dev/null @@ -1,8 +0,0 @@ -import Foundation - -public struct SessionToken { - public let token: String - public let signature: String - public let node_pubx: String - public let node_puby: String -} diff --git a/Sources/TorusUtils/Interfaces/ShareRequestResult.swift b/Sources/TorusUtils/Interfaces/ShareRequestResult.swift deleted file mode 100644 index 89446f92..00000000 --- a/Sources/TorusUtils/Interfaces/ShareRequestResult.swift +++ /dev/null @@ -1,108 +0,0 @@ -import Foundation - -struct ShareRequestResult: Decodable { - let keys: [KeyAssignment] - let sessionTokens: [String] - let sessionTokenMetadata: [EciesHex] - let sessionTokenSigs: [String] - let sessionTokenSigMetadata: [EciesHex] - let nodePubX: String - let nodePubY: String - let isNewKey: String - - enum CodingKeys: CodingKey { - case keys - case session_tokens - case session_token_metadata - case session_token_sigs - case session_token_sig_metadata - case node_pubx - case node_puby - case is_new_key - } - - init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - keys = try container.decode([KeyAssignment].self, forKey: .keys) - nodePubX = try container.decode(String.self, forKey: .node_pubx) - nodePubY = try container.decode(String.self, forKey: .node_puby) - isNewKey = try container.decode(String.self, forKey: .is_new_key) - - if let sessionTokens = try? container.decodeIfPresent([String].self, forKey: .session_tokens) { - self.sessionTokens = sessionTokens - } else { - sessionTokens = [] - } - - if let sessionTokenMetadata = try? container.decodeIfPresent([EciesHex].self, forKey: .session_token_metadata) { - self.sessionTokenMetadata = sessionTokenMetadata - } else { - sessionTokenMetadata = [] - } - - if let sessionTokenSigs = try? container.decodeIfPresent([String].self, forKey: .session_token_sigs) { - self.sessionTokenSigs = sessionTokenSigs - } else { - sessionTokenSigs = [] - } - - if let sessionTokenSigMetadata = try? container.decodeIfPresent([EciesHex].self, forKey: .session_token_sig_metadata) { - self.sessionTokenSigMetadata = sessionTokenSigMetadata - } else { - sessionTokenSigMetadata = [] - } - } -} - -typealias ImportShareRequestResult = ShareRequestResult - -struct LegacyShareRequestResult: Decodable { - let keys: [LegacyKeyAssignment] - let sessionTokens: [String] - let sessionTokenMetadata: [EciesHex] - let sessionTokenSigs: [String] - let sessionTokenSigMetadata: [EciesHex] - let nodePubX: String - let nodePubY: String - - enum CodingKeys: CodingKey { - case keys - case session_tokens - case session_token_metadata - case session_token_sigs - case session_token_sig_metadata - case node_pubx - case node_puby - } - - init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - keys = try container.decode([LegacyKeyAssignment].self, forKey: .keys) - nodePubX = try container.decode(String.self, forKey: .node_pubx) - nodePubY = try container.decode(String.self, forKey: .node_puby) - - if let sessionTokens = try? container.decodeIfPresent([String].self, forKey: .session_tokens) { - self.sessionTokens = sessionTokens - } else { - sessionTokens = [] - } - - if let sessionTokenMetadata = try? container.decodeIfPresent([EciesHex].self, forKey: .session_token_metadata) { - self.sessionTokenMetadata = sessionTokenMetadata - } else { - sessionTokenMetadata = [] - } - - if let sessionTokenSigs = try? container.decodeIfPresent([String].self, forKey: .session_token_sigs) { - self.sessionTokenSigs = sessionTokenSigs - } else { - sessionTokenSigs = [] - } - - if let sessionTokenSigMetadata = try? container.decodeIfPresent([EciesHex].self, forKey: .session_token_sig_metadata) { - self.sessionTokenSigMetadata = sessionTokenSigMetadata - } else { - sessionTokenSigMetadata = [] - } - } -} diff --git a/Sources/TorusUtils/Interfaces/TorusConstants.swift b/Sources/TorusUtils/Interfaces/TorusConstants.swift deleted file mode 100644 index 4b8bb4fc..00000000 --- a/Sources/TorusUtils/Interfaces/TorusConstants.swift +++ /dev/null @@ -1,29 +0,0 @@ -import BigInt -import FetchNodeDetails -import Foundation - -enum TORUS_SAPPHIRE_NETWORK_TYPE { - case SAPPHIRE_DEVNET - case SAPPHIRE_TESTNET - case SAPPHIRE_MAINNET -} - -struct TORUS_SAPPHIRE_NETWORK { - static let SAPPHIRE_DEVNET = "sapphire_devnet" - static let SAPPHIRE_TESTNET = "sapphire_testnet" - static let SAPPHIRE_MAINNET = "sapphire_mainnet" -} - -public class INodePub { - let X: String - let Y: String - - init(X: String, Y: String) { - self.X = X - self.Y = Y - } -} - -public func TorusNodePubModelToINodePub(node: TorusNodePubModel) -> INodePub { - return INodePub(X: node.getX(), Y: node.getY()) -} diff --git a/Sources/TorusUtils/Interfaces/TorusKey.swift b/Sources/TorusUtils/Interfaces/TorusKey.swift new file mode 100644 index 00000000..dbf9c007 --- /dev/null +++ b/Sources/TorusUtils/Interfaces/TorusKey.swift @@ -0,0 +1,68 @@ +import BigInt +import Foundation + +public class TorusKey: Codable { + public class FinalKeyData: Codable { + public let evmAddress: String + public let X: String + public let Y: String + public let privKey: String + + internal init(evmAddress: String, X: String, Y: String, privKey: String) { + self.evmAddress = evmAddress + self.X = X + self.Y = Y + self.privKey = privKey + } + } + + public class OAuthKeyData: Codable { + public let evmAddress: String + public let X: String + public let Y: String + public let privKey: String + + internal init(evmAddress: String, X: String, Y: String, privKey: String) { + self.evmAddress = evmAddress + self.X = X + self.Y = Y + self.privKey = privKey + } + } + + public class SessionData: Codable { + public let sessionTokenData: [SessionToken?] + public let sessionAuthKey: String + + internal init(sessionTokenData: [SessionToken?], sessionAuthKey: String) { + self.sessionTokenData = sessionTokenData + self.sessionAuthKey = sessionAuthKey + } + } + + public class NodesData: Codable { + public let nodeIndexes: [Int] + + internal init(nodeIndexes: [Int]) { + self.nodeIndexes = nodeIndexes + } + } + + internal init(finalKeyData: FinalKeyData, + oAuthKeyData: OAuthKeyData, + sessionData: SessionData, + metadata: TorusPublicKey.Metadata, + nodesData: NodesData) { + self.finalKeyData = finalKeyData + self.oAuthKeyData = oAuthKeyData + self.sessionData = sessionData + self.metadata = metadata + self.nodesData = nodesData + } + + public let finalKeyData: FinalKeyData + public let oAuthKeyData: OAuthKeyData + public let sessionData: SessionData + public let metadata: TorusPublicKey.Metadata + public let nodesData: NodesData +} diff --git a/Sources/TorusUtils/Interfaces/TorusOptions.swift b/Sources/TorusUtils/Interfaces/TorusOptions.swift new file mode 100644 index 00000000..2dd1795e --- /dev/null +++ b/Sources/TorusUtils/Interfaces/TorusOptions.swift @@ -0,0 +1,29 @@ +import FetchNodeDetails +import Foundation + +/// TorusOptions is a configuration class that is used to initialize `TorusUtils`. +public class TorusOptions { + public var enableOneKey: Bool + public var clientId: String + public var network: TorusNetwork + public var serverTimeOffset: Int + public var legacyMetadataHost: String? + + /// Initializes TorusOptions + /// + /// - Parameters: + /// - clientId: The client identity. + /// - network: `TorusNetwork`. Please note that new users should be using .sapphire(.SAPPHIRE_MAINNET). + /// - legacyMetadataHost: The url of the metadata server, this only needs to be supplied if the default is not being used. + /// - serverTimeOffset: The offset from Coordinated Universal Time (UCT). + /// - enableOneKey: Use the oneKey flow. + /// + /// - Returns: `TorusOptions` + public init(clientId: String, network: TorusNetwork, legacyMetadataHost: String? = nil, serverTimeOffset: Int = 0, enableOneKey: Bool = false) { + self.clientId = clientId + self.enableOneKey = enableOneKey + self.network = network + self.serverTimeOffset = serverTimeOffset + self.legacyMetadataHost = legacyMetadataHost + } +} diff --git a/Sources/TorusUtils/Interfaces/TorusPublicKey.swift b/Sources/TorusUtils/Interfaces/TorusPublicKey.swift index 7ff5d783..189f0d08 100644 --- a/Sources/TorusUtils/Interfaces/TorusPublicKey.swift +++ b/Sources/TorusUtils/Interfaces/TorusPublicKey.swift @@ -1,51 +1,64 @@ import BigInt import Foundation -public enum UserType: String { - case v1 - case v2 -} - -public struct TorusPublicKey { - public struct FinalKeyData { +public class TorusPublicKey: Codable { + public class OAuthKeyData: Codable { public let evmAddress: String public let X: String public let Y: String + + internal init(evmAddress: String, X: String, Y: String) { + self.evmAddress = evmAddress + self.X = X + self.Y = Y + } } - public struct OAuthKeyData { + public class FinalKeyData: Codable { public let evmAddress: String public let X: String public let Y: String + + internal init(evmAddress: String, X: String, Y: String) { + self.evmAddress = evmAddress + self.X = X + self.Y = Y + } } - public struct Metadata { + public class Metadata: Codable { public let pubNonce: PubNonce? public let nonce: BigUInt? public let typeOfUser: UserType public let upgraded: Bool? + public let serverTimeOffset: Int + + internal init(pubNonce: PubNonce?, nonce: BigUInt?, typeOfUser: UserType, upgraded: Bool?, serverTimeOffset: Int) { + self.pubNonce = pubNonce + self.nonce = nonce + self.typeOfUser = typeOfUser + self.upgraded = upgraded + self.serverTimeOffset = serverTimeOffset + } } - public struct NodesData { + public class NodesData: Codable { public let nodeIndexes: [Int] + + internal init(nodeIndexes: [Int]) { + self.nodeIndexes = nodeIndexes + } } - public init(finalKeyData: FinalKeyData?, oAuthKeyData: OAuthKeyData?, metadata: Metadata?, nodesData: NodesData?) { + internal init(oAuthKeyData: OAuthKeyData?, finalKeyData: FinalKeyData?, metadata: Metadata?, nodesData: NodesData?) { self.finalKeyData = finalKeyData self.oAuthKeyData = oAuthKeyData self.metadata = metadata self.nodesData = nodesData } - public let finalKeyData: FinalKeyData? public let oAuthKeyData: OAuthKeyData? + public let finalKeyData: FinalKeyData? public let metadata: Metadata? public let nodesData: NodesData? } - -public typealias V2NonceResultType = GetOrSetNonceResult - -struct V1NonceResultType { - let typeOfUser: UserType - let nonce: String? -} diff --git a/Sources/TorusUtils/Interfaces/Toruskey.swift b/Sources/TorusUtils/Interfaces/Toruskey.swift deleted file mode 100644 index 4e38df6d..00000000 --- a/Sources/TorusUtils/Interfaces/Toruskey.swift +++ /dev/null @@ -1,65 +0,0 @@ -import BigInt -import Foundation - -public struct TorusKey { - public struct FinalKeyData { - public let evmAddress: String - public let X: String - public let Y: String - public let privKey: String? - } - - public struct OAuthKeyData { - public let evmAddress: String - public let X: String - public let Y: String - public let privKey: String - } - - public struct SessionData { - public let sessionTokenData: [SessionToken?] - public let sessionAuthKey: String - } - - public struct Metadata { - public let pubNonce: PubNonce? - public let nonce: BigUInt? - public let typeOfUser: UserType - public let upgraded: Bool? - } - - public struct NodesData { - public let nodeIndexes: [Int] - } - - public init(finalKeyData: FinalKeyData?, - oAuthKeyData: OAuthKeyData?, - sessionData: SessionData?, - metadata: Metadata?, - nodesData: NodesData?) { - self.finalKeyData = finalKeyData - self.oAuthKeyData = oAuthKeyData - self.sessionData = sessionData - self.metadata = metadata - self.nodesData = nodesData - } - - public let finalKeyData: FinalKeyData? - public let oAuthKeyData: OAuthKeyData? - public let sessionData: SessionData? - public let metadata: Metadata? - public let nodesData: NodesData? -} - - -// allow response -public struct AllowSuccess : Codable { - public let success: Bool -} - -public struct AllowRejected : Codable { - public let code: Int32 - public let error: String - public let success: Bool -} - diff --git a/Sources/TorusUtils/Interfaces/VerifierParams.swift b/Sources/TorusUtils/Interfaces/VerifierParams.swift deleted file mode 100644 index 18f2800d..00000000 --- a/Sources/TorusUtils/Interfaces/VerifierParams.swift +++ /dev/null @@ -1,13 +0,0 @@ -import Foundation - -public struct VerifierParams { - public let verifier_id: String - public let extended_verifier_id: String? - public let additionalParams: [String: Codable] - - public init(verifier_id: String, extended_verifier_id: String? = nil, additionalParams: [String: Codable] = [:]) { - self.verifier_id = verifier_id - self.extended_verifier_id = extended_verifier_id - self.additionalParams = additionalParams - } -} diff --git a/Sources/TorusUtils/Models/RetrieveSharesResponseModel.swift b/Sources/TorusUtils/Models/RetrieveSharesResponseModel.swift deleted file mode 100644 index d1ccefff..00000000 --- a/Sources/TorusUtils/Models/RetrieveSharesResponseModel.swift +++ /dev/null @@ -1,30 +0,0 @@ -import Foundation - -public struct RetrieveSharesResponseModel { - public let publicAddress: String - public let privateKey: String - - public init(publicKey: String, privateKey: String) { - publicAddress = publicKey - self.privateKey = privateKey - } -} - -// legacy -public struct RetrieveDecryptAndReconstuctResponseModel { - public let iv: String - public let ephemPublicKey: String - public let share: String - public let pubKeyX: String - public let pubKeyY: String - public let mac: String - - public init(iv: String, ephemPublicKey: String, share: String, pubKeyX: String, pubKeyY: String, mac: String) { - self.iv = iv - self.ephemPublicKey = ephemPublicKey - self.share = share - self.pubKeyX = pubKeyX - self.pubKeyY = pubKeyY - self.mac = mac - } -} diff --git a/Sources/TorusUtils/Point.swift b/Sources/TorusUtils/Point.swift index f4414ce3..942f2e84 100644 --- a/Sources/TorusUtils/Point.swift +++ b/Sources/TorusUtils/Point.swift @@ -1,14 +1,31 @@ import BigInt import Foundation import Security +#if canImport(curveSecp256k1) + import curveSecp256k1 +#endif -public class Point: Decodable { +enum PointError: Error { + case encodingNotSupported + case compressedPublicKeyGenerationFailed +} + +internal struct Point: Codable { let x: BigInt let y: BigInt - init(x: String, y: String) { - self.x = BigInt(x, radix: 16)! - self.y = BigInt(y, radix: 16)! + init(x: String, y: String) throws { + if let xCoord = BigInt(x, radix: 16) { + self.x = xCoord + } else { + throw TorusUtilError.invalidInput + } + + if let yCoord = BigInt(y, radix: 16) { + self.y = yCoord + } else { + throw TorusUtilError.invalidInput + } } init(x: BigInt, y: BigInt) { @@ -16,12 +33,12 @@ public class Point: Decodable { self.y = y } - public enum CodingKeys: CodingKey { + enum CodingKeys: CodingKey { case X case Y } - public required init(from decoder: Decoder) throws { + init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) let hexX = try container.decode(String.self, forKey: .X) let hexY = try container.decode(String.self, forKey: .Y) @@ -33,20 +50,24 @@ public class Point: Decodable { func encode(enc: String) throws -> Data { switch enc { case "arr": - let prefix = Data(hex: String().add04Prefix()) - let xData = Data(hex: x.description) - let yData = Data(hex: y.description) - return prefix + xData + yData -// case "elliptic-compressed": -// let publicKey = try getCompressedPublicKey() -// return publicKey + return Data(hex: KeyUtils.getPublicKeyFromCoords(pubKeyX: x.magnitude.serialize().hexString, pubKeyY: y.magnitude.serialize().hexString)) + case "elliptic-compressed": + let keyData = KeyUtils.getPublicKeyFromCoords(pubKeyX: x.magnitude.serialize().hexString, pubKeyY: y.magnitude.serialize().hexString) + let pubKey = try PublicKey(hex: keyData) + return Data(hex: try pubKey.serialize(compressed: true)) default: throw PointError.encodingNotSupported } } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(x.magnitude.serialize().hexString.addLeading0sForLength64(), forKey: .X) + try container.encode(y.magnitude.serialize().hexString.addLeading0sForLength64(), forKey: .Y) + } } -public struct PointHex: Decodable, Hashable, Equatable { +internal struct PointHex: Decodable, Hashable, Equatable { let x: String let y: String @@ -55,8 +76,3 @@ public struct PointHex: Decodable, Hashable, Equatable { y = String(from.y, radix: 16) } } - -enum PointError: Error { - case encodingNotSupported - case compressedPublicKeyGenerationFailed -} diff --git a/Sources/TorusUtils/Polynomial.swift b/Sources/TorusUtils/Polynomial.swift index 4ed66971..92d32ae8 100644 --- a/Sources/TorusUtils/Polynomial.swift +++ b/Sources/TorusUtils/Polynomial.swift @@ -1,10 +1,9 @@ import BigInt -import CryptoKit import Foundation typealias ShareMap = [String: Share] -public struct Polynomial { +internal struct Polynomial { let polynomial: [BigInt] init(polynomial: [BigInt]) { @@ -16,15 +15,14 @@ public struct Polynomial { } func polyEval(x: BigInt) -> BigInt { - var xi = BigInt(x) + let tmpX = x + var xi = BigInt(tmpX) var sum = BigInt(0) sum += polynomial[0] for i in 1 ..< polynomial.count { - let tmp = xi * polynomial[i] - sum += tmp - sum %= getOrderOfCurve() - xi *= x - xi %= getOrderOfCurve() + let tmp = (xi * polynomial[i]) + sum = (sum + tmp).modulus(KeyUtils.getOrderOfCurve()) + xi = (xi * tmpX).modulus(KeyUtils.getOrderOfCurve()) } return sum } @@ -32,15 +30,9 @@ public struct Polynomial { func generateShares(shareIndexes: [BigInt]) -> ShareMap { var shares: ShareMap = [:] for x in 0 ..< shareIndexes.count { - let hexString = shareIndexes[x].serialize().toHexString() + let hexString = shareIndexes[x].magnitude.serialize().hexString.addLeading0sForLength64() shares[hexString] = Share(shareIndex: shareIndexes[x], share: polyEval(x: shareIndexes[x])) } return shares } } - -public func getOrderOfCurve() -> BigInt { - let orderHex = CURVE_N - let order = BigInt(orderHex, radix: 16)! - return order -} diff --git a/Sources/TorusUtils/Share.swift b/Sources/TorusUtils/Share.swift index 11e1498f..1a96d63b 100644 --- a/Sources/TorusUtils/Share.swift +++ b/Sources/TorusUtils/Share.swift @@ -1,13 +1,22 @@ import BigInt import Foundation -public class Share: Codable { +internal class Share: Codable { var share: BigInt var shareIndex: BigInt - public init(shareIndex: String, share: String) { - self.share = BigInt(share, radix: 16)! - self.shareIndex = BigInt(shareIndex, radix: 16)! + public init(shareIndex: String, share: String) throws { + if let si = BigInt(shareIndex, radix: 16) { + self.shareIndex = si + } else { + throw TorusUtilError.invalidInput + } + + if let s = BigInt(share, radix: 16) { + self.share = s + } else { + throw TorusUtilError.invalidInput + } } public init(shareIndex: BigInt, share: BigInt) { diff --git a/Sources/TorusUtils/TorusUtils.swift b/Sources/TorusUtils/TorusUtils.swift index b431e2d7..aa1af7cf 100644 --- a/Sources/TorusUtils/TorusUtils.swift +++ b/Sources/TorusUtils/TorusUtils.swift @@ -2,500 +2,375 @@ import BigInt import FetchNodeDetails import Foundation import OSLog -import AnyCodable #if canImport(curveSecp256k1) import curveSecp256k1 #endif var utilsLogType = OSLogType.default -open class TorusUtils: AbstractTorusUtils { - private var timeout: Int = 30 - var urlSession: URLSession - var serverTimeOffset: TimeInterval = 0 +public class TorusUtils { + private var sessionTime: Int = 86400 // 24 hour + var allowHost: String + + var serverTimeOffset: Int? + var network: TorusNetwork - var modulusValue = BigInt(CURVE_N, radix: 16)! + var clientId: String - var signerHost: String + var enableOneKey: Bool + + var signerHost: String + var legacyMetadataHost: String - public init(loglevel: OSLogType = .default, - urlSession: URLSession = URLSession(configuration: .default), - enableOneKey: Bool = false, - serverTimeOffset: TimeInterval = 0, - network: TorusNetwork, - clientId: String, - legacyMetadataHost: String = "https://metadata.tor.us" - ) { - self.urlSession = urlSession + var apiKey: String = "torus-default" + + /// Initializes TorusUtils with the provided options + /// + /// - Parameters: + /// - params: `TorusOptions` + /// - logLevel: `OSLogType`, only needs to be provided if the default logging level should be changed + /// + /// - Returns: `TorusUtils` + /// + /// - Throws: `TorusUtilError.invalidInput` + public init(params: TorusOptions, loglevel: OSLogType = .default) throws { + var defaultHost = "" + if params.legacyMetadataHost == nil { + if case let .legacy(urlHost) = params.network { + defaultHost = urlHost.metadataMap + } else { + // TODO: Move this into fetchNodeDetails metadataMap + if case let .sapphire(sapphireNetwork) = params.network { + if sapphireNetwork == .SAPPHIRE_MAINNET { + defaultHost = "https://node-1.node.web3auth.io/metadata" + } else { + defaultHost = "https://node-1.dev-node.web3auth.io/metadata" + } + } else { + throw TorusUtilError.invalidInput + } + } + } else { + defaultHost = params.legacyMetadataHost! + } + + serverTimeOffset = params.serverTimeOffset + network = params.network + clientId = params.clientId + allowHost = params.network.signerMap + "/api/allow" utilsLogType = loglevel - self.enableOneKey = enableOneKey - self.allowHost = network.signerMap + "/api/allow" - self.signerHost = network.signerMap + "/api/sign" - self.network = network - self.serverTimeOffset = serverTimeOffset - self.clientId = clientId - self.legacyMetadataHost = legacyMetadataHost + enableOneKey = params.enableOneKey + legacyMetadataHost = defaultHost + signerHost = params.network.signerMap + "/api/sign" + } + + internal static func isLegacyNetworkRouteMap(network: TorusNetwork) -> Bool { + if case .legacy = network { + return true + } + return false + } + + /// Sets the apiKey + /// + /// - Parameters: + /// - apiKey: The api key to be assigned + public func setApiKey(apiKey: String) { + self.apiKey = apiKey } - // MARK: - getPublicAddress + /// Reverts the apiKey for `TorusUtils` to the default value + public func removeApiKey() { + apiKey = "torus-default" + } - public func getPublicAddress(endpoints: [String], torusNodePubs: [TorusNodePubModel], verifier: String, verifierId: String, extendedVerifierId: String? = nil) async throws -> TorusPublicKey { - if isLegacyNetwork() { - return try await getLegacyPublicAddress(endpoints: endpoints, torusNodePubs: torusNodePubs, verifier: verifier, verifierId: verifierId, enableOneKey: enableOneKey) - } else { - return try await getNewPublicAddress(endpoints: endpoints, verifier: verifier, verifierId: verifierId, extendedVerifierId: extendedVerifierId, enableOneKey: enableOneKey) + /// Sets the sessionTime + /// + /// - Parameters: + /// - sessionTime: The amount of time a session should be valid for in seconds, default is 24 hours. + public func setSessionTime(sessionTime: Int) { + self.sessionTime = sessionTime + } + + /// Convenience function to quickly retrieve the postbox key from `TorusKey` + /// + /// - Parameters: + /// - torusKey: `TorusKey` + /// + /// - Returns: `String` + public static func getPostboxKey(torusKey: TorusKey) -> String { + if torusKey.metadata.typeOfUser == .v1 { + return torusKey.finalKeyData.privKey } + return torusKey.oAuthKeyData.privKey } + /// Login for the provided user + /// + /// - Parameters: + /// - endpoints: The endpoints to be queried for the relevant network. + /// - verifier: The verifier to query, this can be a single verifier or an aggregate verifier. + /// - verifier_id: The identity of the user to be queried against the verifier, this is usually an emal. + /// - verifierParams: `VerifierParams` + /// - idToken: This is the identity token of the user. For single verifiers this will be a jwt, in the case of an aggregate verifier, this will be a keccak256 hash of the jwt. + /// + /// - Returns: `TorusKey` + /// + /// - Throws: `TorusUtilError` public func retrieveShares( endpoints: [String], - torusNodePubs: [TorusNodePubModel], - indexes: [BigUInt], verifier: String, verifierParams: VerifierParams, idToken: String, - extraParams: [String: Codable] = [:] + extraParams: TorusUtilsExtraParams = TorusUtilsExtraParams() ) async throws -> TorusKey { - let session = createURLSession() - var allowHostRequest = try makeUrlRequest(url: allowHost, httpMethod: .get) - allowHostRequest.addValue("torus-default", forHTTPHeaderField: "x-api-key") - allowHostRequest.addValue(verifier, forHTTPHeaderField: "origin") - allowHostRequest.addValue(verifier, forHTTPHeaderField: "verifier") - allowHostRequest.addValue(verifierParams.verifier_id, forHTTPHeaderField: "verifierid") - allowHostRequest.addValue(clientId, forHTTPHeaderField: "clientid") - allowHostRequest.addValue(network.name, forHTTPHeaderField: "network") - allowHostRequest.addValue("true", forHTTPHeaderField: "enablegating") - do { - let result = try await session.data(for: allowHostRequest) - let responseData = try JSONDecoder().decode(AllowSuccess.self, from: result.0) - if (responseData.success == false ) { - let errorData = try JSONDecoder().decode(AllowRejected.self, from: result.0) - throw TorusUtilError.gatingError("code: \(errorData.code), error: \(errorData.error)") - } - } catch { - os_log("retrieveShares: signer allow: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .error), type: .error, error.localizedDescription) - throw error + if extraParams.session_token_exp_second == nil { + extraParams.session_token_exp_second = sessionTime } - if isLegacyNetwork() { - let result = try await legacyRetrieveShares(torusNodePubs: torusNodePubs, indexes: indexes, endpoints: endpoints, verifier: verifier, verifierId: verifierParams.verifier_id, idToken: idToken, extraParams: extraParams) - return result - } else { - let result = try await retrieveShare( - legacyMetadataHost: legacyMetadataHost, - allowHost: allowHost, - enableOneKey: enableOneKey, - network: network, - clientId: clientId, - endpoints: endpoints, - verifier: verifier, - verifierParams: verifierParams, - idToken: idToken, - extraParams: extraParams - ) - return result - } + return try await NodeUtils.retrieveOrImportShare(legacyMetadataHost: legacyMetadataHost, serverTimeOffset: serverTimeOffset, enableOneKey: enableOneKey, allowHost: allowHost, network: network, clientId: clientId, endpoints: endpoints, verifier: verifier, verifierParams: verifierParams, idToken: idToken, importedShares: [], apiKey: apiKey, extraParams: extraParams) } - public func getUserTypeAndAddress(endpoints: [String], torusNodePubs: [TorusNodePubModel], verifier: String, verifierId: String, extendedVerifierId: String? = nil) async throws -> TorusPublicKey { - if isLegacyNetwork() { - return try await getLegacyPublicAddress(endpoints: endpoints, torusNodePubs: torusNodePubs, verifier: verifier, verifierId: verifierId, enableOneKey: true) - } else { - return try await getNewPublicAddress(endpoints: endpoints, verifier: verifier, verifierId: verifierId, extendedVerifierId: extendedVerifierId, enableOneKey: true) - } + /// Retrieves user information, defaulting the user type to .v2 + /// + /// - Parameters: + /// - endpoints: The endpoints to be queried for the relevant network. + /// - verifier: The verifier to query, this can be a single verifier or an aggregate verifier. + /// - verifier_id: The identity of the user to be queried against the verifier, this is usually an emal. + /// - extended_verifier_id: This is only used if querying a tss verifier, otherwise it is not supplied. Format is (verifierId + "\u{0015}" + tssTag + "\u{0016}" + randomNonce) + /// + /// - Returns: `TorusPublicKey` + /// + /// - Throws: `TorusUtilError + public func getPublicAddress(endpoints: [String], verifier: String, verifierId: String, extendedVerifierId: String? = nil) async throws -> TorusPublicKey { + return try await getNewPublicAddress(endpoints: endpoints, verifier: verifier, verifierId: verifierId, extendedVerifierId: extendedVerifierId, enableOneKey: enableOneKey) } - private func getNewPublicAddress(endpoints: [String], verifier: String, verifierId: String, extendedVerifierId: String? = nil, enableOneKey: Bool) async throws -> TorusPublicKey { - do { - let result = try await getPubKeyOrKeyAssign(endpoints: endpoints, verifier: verifier, verifierId: verifierId, extendedVerifierId: extendedVerifierId) - let keyResult = result.keyResult - let nodeIndexes = result.nodeIndexes - let (X, Y) = (keyResult.pubKeyX, keyResult.pubKeyY) + /// Imports a private key for the provided user + /// + /// - Parameters: + /// - endpoints: The endpoints to be queried for the relevant network. + /// - nodeIndexes: The node indexes for the endpoints. + /// - nodePubKeys: The public keys for the endpoints. `TorusNodePubModel` + /// - verifier: The verifier to query, this can be a single verifier or an aggregate verifier. + /// - verifier_id: The identity of the user to be queried against the verifier, this is usually an emal. + /// - verifierParams: `VerifierParams` + /// - idToken: This is the identity token of the user. For single verifiers this will be a jwt, in the case of an aggregate verifier, this will be a keccak256 hash of the jwt. + /// - newPrivateKey: The private key that is being imported. + /// + /// - Returns: `TorusKey` + /// + /// - Throws: `TorusUtilError` + public func importPrivateKey( + endpoints: [String], + nodeIndexes: [BigUInt], + nodePubKeys: [TorusNodePubModel], + verifier: String, + verifierParams: VerifierParams, + idToken: String, + newPrivateKey: String, + extraParams: TorusUtilsExtraParams = TorusUtilsExtraParams() + ) async throws -> TorusKey { + let nodePubs = TorusNodePubModelToINodePub(nodes: nodePubKeys) + if endpoints.count != nodeIndexes.count { + throw TorusUtilError.runtime("Length of endpoints must be the same as length of nodeIndexes") + } - let nonceResult = result.nonceResult + let sharesData = try KeyUtils.generateShares(serverTimeOffset: serverTimeOffset ?? 0, nodeIndexes: nodeIndexes, nodePubKeys: nodePubs, privateKey: newPrivateKey) - if nonceResult?.pubNonce?.x == nil && extendedVerifierId == nil && !isLegacyNetwork() { throw TorusUtilError.runtime("metadata nonce is missing in share response") - } + if extraParams.session_token_exp_second == nil { + extraParams.session_token_exp_second = sessionTime + } + + return try await NodeUtils.retrieveOrImportShare(legacyMetadataHost: legacyMetadataHost, serverTimeOffset: serverTimeOffset ?? 0, enableOneKey: enableOneKey, allowHost: allowHost, network: network, clientId: clientId, endpoints: endpoints, verifier: verifier, verifierParams: verifierParams, idToken: idToken, importedShares: sharesData, extraParams: extraParams) + } - var modifiedPubKey: String - var oAuthPubKeyString: String - var pubNonce: PubNonce? + /// Retrieves user information + /// + /// - Parameters: + /// - endpoints: The endpoints to be queried for the relevant network. + /// - verifier: The verifier to query, this can be a single verifier or an aggregate verifier. + /// - verifier_id: The identity of the user to be queried against the verifier, this is usually an emal. + /// - extended_verifier_id: This is only used if querying a tss verifier, otherwise it is not supplied. Format is (verifierId + "\u{0015}" + tssTag + "\u{0016}" + randomNonce) + /// + /// - Returns: `TorusPublicKey` + /// + /// - Throws: `TorusUtilError` + public func getUserTypeAndAddress( + endpoints: [String], + verifier: String, + verifierId: String, + extendedVerifierId: String? = nil + ) async throws -> TorusPublicKey { + return try await getNewPublicAddress(endpoints: endpoints, verifier: verifier, verifierId: verifierId, extendedVerifierId: extendedVerifierId, enableOneKey: true) + } - if extendedVerifierId != nil { - modifiedPubKey = (X.addLeading0sForLength64() + Y.addLeading0sForLength64()).add04Prefix() - oAuthPubKeyString = modifiedPubKey - } else if isLegacyNetwork() { - return try await formatLegacyPublicData(finalKeyResult: result.keyResult, enableOneKey: enableOneKey, isNewKey: result.keyResult.isNewKey) + private func getNewPublicAddress(endpoints: [String], verifier: String, verifierId: String, extendedVerifierId: String? = nil, enableOneKey: Bool) async throws -> TorusPublicKey { + let keyAssignResult = try await NodeUtils.getPubKeyOrKeyAssign(endpoints: endpoints, network: network, verifier: verifier, verifierId: verifierId, legacyMetadataHost: legacyMetadataHost, serverTimeOffset: serverTimeOffset, extendedVerifierId: extendedVerifierId) + + if keyAssignResult.errorResult != nil { + let error = keyAssignResult.errorResult!.message + if error.lowercased().contains("verifier not supported") { + throw TorusUtilError.runtime("Verifier not supported. Check if you: 1. Are on the right network (Torus testnet/mainnet) 2. Have setup a verifier on dashboard.web3auth.io?") } else { - modifiedPubKey = (X.addLeading0sForLength64() + Y.addLeading0sForLength64()).add04Prefix() - oAuthPubKeyString = modifiedPubKey - - let pubNonceX = (nonceResult?.pubNonce?.x ?? "0") - let pubNonceY = (nonceResult?.pubNonce?.y ?? "0") - let noncePub = (pubNonceX.addLeading0sForLength64() + pubNonceY.addLeading0sForLength64()).add04Prefix() - modifiedPubKey = try combinePublicKeys(keys: [modifiedPubKey, noncePub], compressed: false) - pubNonce = nonceResult?.pubNonce + throw TorusUtilError.runtime(error) } + } - let (oAuthX, oAuthY) = try getPublicKeyPointFromPubkeyString(pubKey: oAuthPubKeyString) - let (finalX, finalY) = try getPublicKeyPointFromPubkeyString(pubKey: modifiedPubKey) - - let oAuthAddress = generateAddressFromPubKey(publicKeyX: oAuthX, publicKeyY: oAuthY) - let finalAddress = generateAddressFromPubKey(publicKeyX: finalX, publicKeyY: finalY) - - return .init( - finalKeyData: .init( - evmAddress: finalAddress, - X: finalX, - Y: finalY - ), - oAuthKeyData: .init( - evmAddress: oAuthAddress, - X: oAuthX, - Y: oAuthY - ), - metadata: .init( - pubNonce: pubNonce, - nonce: BigUInt(nonceResult?.nonce ?? "0", radix: 16), - typeOfUser: UserType(rawValue: "v2")!, - upgraded: nonceResult?.upgraded ?? false - ), - nodesData: .init(nodeIndexes: nodeIndexes) - ) + if keyAssignResult.keyResult == nil || keyAssignResult.keyResult?.keys.count == 0 { + throw TorusUtilError.runtime("node results do not match at final lookup") + } - } catch { - throw error + if keyAssignResult.nonceResult == nil && extendedVerifierId == nil && !TorusUtils.isLegacyNetworkRouteMap(network: network) { + throw TorusUtilError.runtime("metadata nonce is missing in share response") } - } - // Legacy - private func getLegacyPublicAddress(endpoints: [String], torusNodePubs: [TorusNodePubModel], verifier: String, verifierId: String, enableOneKey: Bool) async throws -> TorusPublicKey { - do { - var data: LegacyKeyLookupResponse - var isNewKey = false - - do { - data = try await legacyKeyLookup(endpoints: endpoints, verifier: verifier, verifierId: verifierId) - } catch { - if let keyLookupError = error as? KeyLookupError, keyLookupError == .verifierAndVerifierIdNotAssigned { - do { - _ = try await keyAssign(endpoints: endpoints, torusNodePubs: torusNodePubs, verifier: verifier, verifierId: verifierId, signerHost: signerHost, network: network) - data = try await awaitLegacyKeyLookup(endpoints: endpoints, verifier: verifier, verifierId: verifierId, timeout: 1) - isNewKey = true - } catch { - throw TorusUtilError.configurationError - } - } else { - throw error - } + let pubKey = KeyUtils.getPublicKeyFromCoords(pubKeyX: keyAssignResult.keyResult!.keys[0].pub_key_X, pubKeyY: keyAssignResult.keyResult!.keys[0].pub_key_Y) + + var pubNonce: PubNonce? + let nonce: BigUInt = BigUInt(keyAssignResult.nonceResult?.nonce ?? "0", radix: 16) ?? BigUInt(0) + + var oAuthPubKey: String? + var finalPubKey: String? + + let finalServerTimeOffset = serverTimeOffset ?? keyAssignResult.serverTimeOffset + + if extendedVerifierId != nil { + finalPubKey = pubKey + oAuthPubKey = finalPubKey + } else if TorusUtils.isLegacyNetworkRouteMap(network: network) { + let legacyKeysResult = keyAssignResult.keyResult!.keys.map({ + LegacyVerifierLookupResponse.Key(pub_key_X: $0.pub_key_X, pub_key_Y: $0.pub_key_Y, address: $0.address) + }) + let legacyResult = LegacyVerifierLookupResponse(keys: legacyKeysResult, serverTimeOffset: String(finalServerTimeOffset)) + return try await formatLegacyPublicKeyData(finalKeyResult: legacyResult, enableOneKey: enableOneKey, isNewKey: keyAssignResult.keyResult!.is_new_key, serverTimeOffset: finalServerTimeOffset) + } else { + let (X, Y) = try KeyUtils.getPublicKeyCoords(pubKey: pubKey) + oAuthPubKey = KeyUtils.getPublicKeyFromCoords(pubKeyX: X, pubKeyY: Y) + finalPubKey = oAuthPubKey! + if keyAssignResult.nonceResult!.pubNonce != nil && !(keyAssignResult.nonceResult!.pubNonce!.x.isEmpty || keyAssignResult.nonceResult!.pubNonce!.y.isEmpty) { + let pubNonceResult = keyAssignResult.nonceResult!.pubNonce! + let pubNonceKey = KeyUtils.getPublicKeyFromCoords(pubKeyX: pubNonceResult.x, pubKeyY: pubNonceResult.y) + finalPubKey = try KeyUtils.combinePublicKeys(keys: [oAuthPubKey!, pubNonceKey]) + pubNonce = pubNonceResult + } else { + throw TorusUtilError.pubNonceMissing } - let keyLookupData = KeyLookupResponse(pubKeyX: data.pubKeyX, pubKeyY: data.pubKeyY, address: data.address, isNewKey: isNewKey) - let result = try await formatLegacyPublicData(finalKeyResult: keyLookupData, enableOneKey: enableOneKey, isNewKey: isNewKey) - return result - } catch { - throw error } - } - private func legacyRetrieveShares(torusNodePubs: [TorusNodePubModel], - indexes: [BigUInt], - endpoints: [String], verifier: String, verifierId: String, idToken: String, extraParams: [String: Codable]) async throws -> TorusKey { - return try await withThrowingTaskGroup(of: TorusKey.self, body: { [unowned self] group in - group.addTask { [unowned self] in - try await handleRetrieveShares(torusNodePubs: torusNodePubs, - indexes: indexes, - endpoints: endpoints, verifier: verifier, verifierId: verifierId, idToken: idToken, extraParams: extraParams) - } - group.addTask { [unowned self] in - // 60 second timeout for login - try await _Concurrency.Task.sleep(nanoseconds: UInt64(timeout * 60000000000)) - throw TorusUtilError.timeout - } + if oAuthPubKey == nil || finalPubKey == nil { + throw TorusUtilError.privateKeyDeriveFailed + } - do { - for try await val in group { - try Task.checkCancellation() - group.cancelAll() - return val - } - } catch { - group.cancelAll() - throw error - } - throw TorusUtilError.timeout - }) + let (oAuthPubKeyX, oAuthPubKeyY) = try KeyUtils.getPublicKeyCoords(pubKey: oAuthPubKey!) + let oAuthAddress = try KeyUtils.generateAddressFromPubKey(publicKeyX: oAuthPubKeyX, publicKeyY: oAuthPubKeyY) + + let (finalPubKeyX, finalPubKeyY) = try KeyUtils.getPublicKeyCoords(pubKey: finalPubKey!) + let finalAddress = try KeyUtils.generateAddressFromPubKey(publicKeyX: finalPubKeyX, publicKeyY: finalPubKeyY) + + return TorusPublicKey( + oAuthKeyData: TorusPublicKey.OAuthKeyData( + evmAddress: oAuthAddress, + X: oAuthPubKeyX, + Y: oAuthPubKeyY + ), + finalKeyData: TorusPublicKey.FinalKeyData( + evmAddress: finalAddress, + X: finalPubKeyX, + Y: finalPubKeyY + ), + metadata: TorusPublicKey.Metadata( + pubNonce: pubNonce, + nonce: nonce, + typeOfUser: .v2, + upgraded: keyAssignResult.nonceResult?.upgraded ?? false, + serverTimeOffset: finalServerTimeOffset + ), + nodesData: TorusPublicKey.NodesData( + nodeIndexes: keyAssignResult.nodeIndexes + ) + ) } - private func handleRetrieveShares(torusNodePubs: [TorusNodePubModel], - indexes: [BigUInt], - endpoints: [String], verifier: String, verifierId: String, idToken: String, extraParams: [String: Codable]) async throws -> TorusKey { - let privateKey = SecretKey() - let serializedPublicKey = try privateKey.toPublic().serialize(compressed: false) - - // Split key in 2 parts, X and Y - // let publicKeyHex = publicKey.toHexString() - let pubKeyX = String(serializedPublicKey.suffix(128).prefix(64)) - let pubKeyY = String(serializedPublicKey.suffix(64)) - - // Hash the token from OAuth login - - let timestamp = String(Int(getTimestamp())) - - let hashedToken = keccak256Data(idToken.data(using: .utf8) ?? Data()).toHexString() - var lookupPubkeyX: String = "" - var lookupPubkeyY: String = "" - do { - let getPublicAddressData = try await getPublicAddress(endpoints: endpoints, torusNodePubs: torusNodePubs, verifier: verifier, verifierId: verifierId) - guard (getPublicAddressData.finalKeyData?.evmAddress) != nil - else { - throw TorusUtilError.runtime("Unable to provide evmAddress") - } - let localPubkeyX = getPublicAddressData.finalKeyData!.X.addLeading0sForLength64() - let localPubkeyY = getPublicAddressData.finalKeyData!.Y.addLeading0sForLength64() - lookupPubkeyX = localPubkeyX - lookupPubkeyY = localPubkeyY - let commitmentRequestData = try await commitmentRequest(endpoints: endpoints, verifier: verifier, pubKeyX: pubKeyX, pubKeyY: pubKeyY, timestamp: timestamp, tokenCommitment: hashedToken) - os_log("retrieveShares - data after commitment request: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .info), type: .info, commitmentRequestData) - - let (oAuthKeyX, oAuthKeyY, oAuthKey) = try await retrieveDecryptAndReconstruct( - endpoints: endpoints, - indexes: indexes, - extraParams: extraParams, verifier: verifier, tokenCommitment: idToken, nodeSignatures: commitmentRequestData, verifierId: verifierId, lookupPubkeyX: lookupPubkeyX, lookupPubkeyY: lookupPubkeyY, privateKey: privateKey.serialize().addLeading0sForLength64()) - - var metadataNonce: BigUInt - var typeOfUser: UserType = .v1 - var pubKeyNonceResult: PubNonce? - var finalPubKey: String = "" - - if enableOneKey { - let nonceResult = try await getOrSetNonce(x: oAuthKeyX, y: oAuthKeyY, privateKey: oAuthKey, getOnly: true) - metadataNonce = BigUInt(nonceResult.nonce ?? "0", radix: 16) ?? 0 - let nonceType = nonceResult.typeOfUser ?? "v1" - typeOfUser = UserType(rawValue: nonceType) ?? UserType.v1 - if typeOfUser == .v2 { - finalPubKey = (oAuthKeyX.addLeading0sForLength64() + oAuthKeyY.addLeading0sForLength64()).add04Prefix() - let newkey = ((nonceResult.pubNonce?.x.addLeading0sForLength64())! + (nonceResult.pubNonce?.y.addLeading0sForLength64())!).add04Prefix() - finalPubKey = try combinePublicKeys(keys: [finalPubKey, newkey], compressed: false) - pubKeyNonceResult = .init(x: nonceResult.pubNonce!.x, y: nonceResult.pubNonce!.y) - } else { - // for imported keys in legacy networks - metadataNonce = try await getMetadata(dictionary: ["pub_key_X": oAuthKeyX, "pub_key_Y": oAuthKeyY]) - var privateKeyWithNonce = BigInt(metadataNonce) + BigInt(oAuthKey, radix: 16)! - privateKeyWithNonce = privateKeyWithNonce.modulus(modulusValue) - let serializedKey = privateKeyWithNonce.magnitude.serialize().hexString.addLeading0sForLength64() - let finalPrivateKey = try - SecretKey(hex: serializedKey) - finalPubKey = try finalPrivateKey.toPublic().serialize(compressed: false) - } - } else { - // for imported keys in legacy networks - metadataNonce = try await getMetadata(dictionary: ["pub_key_X": oAuthKeyX, "pub_key_Y": oAuthKeyY]) - var privateKeyWithNonce = BigInt(metadataNonce) + BigInt(oAuthKey, radix: 16)! - privateKeyWithNonce = privateKeyWithNonce.modulus(modulusValue) - let finalPrivateKey = try SecretKey(hex: privateKeyWithNonce.magnitude.serialize().hexString.addLeading0sForLength64()) - finalPubKey = try finalPrivateKey.toPublic().serialize(compressed: false) - } + internal func formatLegacyPublicKeyData(finalKeyResult: LegacyVerifierLookupResponse, enableOneKey: Bool, isNewKey: Bool, serverTimeOffset: Int) async throws -> TorusPublicKey { + let firstResult = finalKeyResult.keys[0] + let X = firstResult.pub_key_X + let Y = firstResult.pub_key_Y - let oAuthKeyAddress = generateAddressFromPubKey(publicKeyX: oAuthKeyX, publicKeyY: oAuthKeyY) - let (finalPubX, finalPubY) = try getPublicKeyPointFromPubkeyString(pubKey: finalPubKey) - let finalEvmAddress = generateAddressFromPubKey(publicKeyX: finalPubX, publicKeyY: finalPubY) + var nonceResult: GetOrSetNonceResult? + var finalPubKey: String? + var nonce: BigUInt? + var typeOfUser: UserType + var pubNonce: PubNonce? - var finalPrivKey = "" - if typeOfUser == .v1 || (typeOfUser == .v2 && metadataNonce > BigInt(0)) { - let tempNewKey = BigInt(metadataNonce) + BigInt(oAuthKey, radix: 16)! - let privateKeyWithNonce = tempNewKey.modulus(modulusValue) - finalPrivKey = String(privateKeyWithNonce, radix: 16).addLeading0sForLength64() - } + let oAuthPubKey = KeyUtils.getPublicKeyFromCoords(pubKeyX: X, pubKeyY: Y) + + let finalServertimeOffset = self.serverTimeOffset ?? serverTimeOffset + + if enableOneKey { + nonceResult = try await MetadataUtils.getOrSetNonce(legacyMetadataHost: legacyMetadataHost, serverTimeOffset: finalServertimeOffset, X: X, Y: Y, getOnly: !isNewKey) + nonce = BigUInt(nonceResult!.nonce ?? "0", radix: 16) + typeOfUser = UserType(rawValue: nonceResult?.typeOfUser?.lowercased() ?? "v1")! - var isUpgraded: Bool? = false if typeOfUser == .v1 { - isUpgraded = nil + finalPubKey = oAuthPubKey + nonce = try await MetadataUtils.getMetadata(legacyMetadataHost: legacyMetadataHost, params: GetMetadataParams(pub_key_X: X, pub_key_Y: Y)) + + if nonce! > BigUInt(0) { + let noncePrivateKey = try SecretKey(hex: nonce!.magnitude.serialize().hexString.addLeading0sForLength64()) + let noncePublicKey = try noncePrivateKey.toPublic().serialize(compressed: false) + finalPubKey = try KeyUtils.combinePublicKeys(keys: [finalPubKey!, noncePublicKey]) + } } else if typeOfUser == .v2 { - isUpgraded = metadataNonce == BigUInt(0) + let pubNonceKey = KeyUtils.getPublicKeyFromCoords(pubKeyX: nonceResult!.pubNonce!.x, pubKeyY: nonceResult!.pubNonce!.y) + finalPubKey = try KeyUtils.combinePublicKeys(keys: [oAuthPubKey, pubNonceKey]) + pubNonce = nonceResult!.pubNonce! + } else { + throw TorusUtilError.metadataNonceMissing + } + } else { + typeOfUser = .v1 + finalPubKey = oAuthPubKey + nonce = try await MetadataUtils.getMetadata(legacyMetadataHost: legacyMetadataHost, params: GetMetadataParams(pub_key_X: X, pub_key_Y: Y)) + + if nonce! > BigUInt(0) { + let noncePrivateKey = try SecretKey(hex: nonce!.magnitude.serialize().hexString.addLeading0sForLength64()) + let noncePublicKey = try noncePrivateKey.toPublic().serialize(compressed: false) + finalPubKey = try KeyUtils.combinePublicKeys(keys: [finalPubKey!, noncePublicKey]) } - - return TorusKey( - finalKeyData: .init( - evmAddress: finalEvmAddress, - X: finalPubX, - Y: finalPubY, - privKey: finalPrivKey - ), - oAuthKeyData: .init( - evmAddress: oAuthKeyAddress, - X: oAuthKeyX, - Y: oAuthKeyY, - privKey: oAuthKey - ), - sessionData: .init( - sessionTokenData: [], - sessionAuthKey: "" - ), - metadata: .init( - pubNonce: pubKeyNonceResult, - nonce: BigUInt(metadataNonce), - typeOfUser: typeOfUser, - upgraded: isUpgraded - ), - nodesData: .init(nodeIndexes: []) - ) - } catch { - os_log("Error: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .error), type: .error, error.localizedDescription) - throw error } - } - - open func getTimestamp() -> TimeInterval { - return Date().timeIntervalSince1970 - } - // MARK: - retreiveDecryptAndReconstuct - - private func retrieveDecryptAndReconstruct(endpoints: [String], - indexes: [BigUInt], - extraParams: [String: Codable], verifier: String, tokenCommitment: String, nodeSignatures: [CommitmentRequestResponse], verifierId: String, lookupPubkeyX: String, lookupPubkeyY: String, privateKey: String) async throws -> (String, String, String) { - // Rebuild extraParams - let session = createURLSession() - let threshold = Int(endpoints.count / 2) + 1 - var rpcdata: Data = Data() - - let loadedStrings = extraParams - let valueDict = ["verifieridentifier": verifier, - "verifier_id": verifierId, - "nodesignatures": nodeSignatures.tostringDict(), - "idtoken": tokenCommitment, - ] as [String: Codable] - let finalItem = loadedStrings.merging(valueDict) { current, _ in current } - let params = ["encrypted": "yes", - "item": AnyCodable([finalItem]), - ] as [String: AnyCodable] - - let dataForRequest = ["jsonrpc": "2.0", - "id": 10, - "method": AnyCodable(JRPC_METHODS.LEGACY_SHARE_REQUEST), - "params": AnyCodable(params), - ] as [String: AnyCodable] - do { - rpcdata = try JSONEncoder().encode(dataForRequest) - } catch { - os_log("import share - error: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .error), type: .error, error.localizedDescription) - } + let oAuthAddress = try KeyUtils.generateAddressFromPubKey(publicKeyX: X, publicKeyY: Y) - var shareResponses: [PointHex?] = [] - var resultArray = [Int: RetrieveDecryptAndReconstuctResponseModel]() - var errorStack = [Error]() - var requestArr = [URLRequest]() - for (_, el) in endpoints.enumerated() { - do { - var rq = try makeUrlRequest(url: el) - rq.httpBody = rpcdata - requestArr.append(rq) - } catch { - throw error - } + if typeOfUser == .v2 && finalPubKey == nil { + throw TorusUtilError.privateKeyDeriveFailed } - return try await withThrowingTaskGroup(of: Result.self, body: { [unowned self] group in - for (i, rq) in requestArr.enumerated() { - group.addTask { - do { - let val = try await session.data(for: rq) - return .success(.init(data: val.0, urlResponse: val.1, index: i)) - } catch { - return .failure(error) - } - } - } - for try await val in group { - do { - try Task.checkCancellation() - switch val { - case let .success(model): - let _data = model.data - let i = Int(indexes[model.index]) - 1 - - let decoded = try JSONDecoder().decode(JSONRPCresponse.self, from: _data) - - if decoded.error != nil { - throw TorusUtilError.decodingFailed(decoded.error?.data) - } - os_log("retrieveDecryptAndReconstuct: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .info), type: .info, "\(decoded)") - var X = lookupPubkeyX.addLeading0sForLength64() - var Y = lookupPubkeyY.addLeading0sForLength64() - if let decodedResult = decoded.result as? LegacyLookupResponse { - // case non migration - let keyObj = decodedResult.keys - if let first = keyObj.first { - let pointHex = PointHex(from: first.publicKey) - shareResponses.append(pointHex) - let metadata = first.metadata - let model = RetrieveDecryptAndReconstuctResponseModel(iv: metadata.iv, ephemPublicKey: metadata.ephemPublicKey, share: first.share, pubKeyX: pointHex.x, pubKeyY: pointHex.y, mac: metadata.mac) - resultArray[i] = model - } - } else if let decodedResult = decoded.result as? LegacyShareRequestResult { - // case migration - let keyObj = decodedResult.keys - if let first = keyObj.first { - let pointHex = PointHex(from: .init(x: first.publicKey.X, y: first.publicKey.Y)) - shareResponses.append(pointHex) - let metadata = first.metadata - X = pointHex.x - Y = pointHex.y - let model = RetrieveDecryptAndReconstuctResponseModel(iv: metadata.iv, ephemPublicKey: metadata.ephemPublicKey, share: first.share, pubKeyX: pointHex.x, pubKeyY: pointHex.y, mac: metadata.mac) - resultArray[i] = model - } - } else { - throw TorusUtilError.runtime("decode fail") - } - - // Due to multiple keyAssign - - let lookupShares = shareResponses.filter { $0 != nil } // Nonnil elements - - // Comparing dictionaries, so the order of keys doesn't matter - let keyResult = thresholdSame(arr: lookupShares.map { $0 }, threshold: threshold) // Check if threshold is satisfied - var data: [Int: String] = [:] - if keyResult != nil { - os_log("retreiveIndividualNodeShares - result: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .info), type: .info, resultArray) - data = try decryptIndividualShares(shares: resultArray, privateKey: privateKey) - } else { - throw TorusUtilError.empty - } - os_log("retrieveDecryptAndReconstuct - data after decryptIndividualShares: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .debug), type: .debug, data) - let filteredData = data.filter { $0.value != TorusUtilError.decodingFailed(nil).debugDescription } - - if filteredData.count < threshold { throw TorusUtilError.thresholdError } - let thresholdLagrangeInterpolationData = try thresholdLagrangeInterpolation(data: filteredData, endpoints: endpoints, lookupPubkeyX: X.addLeading0sForLength64(), lookupPubkeyY: Y.addLeading0sForLength64()) - session.invalidateAndCancel() - return thresholdLagrangeInterpolationData - case let .failure(error): - throw error - } - } catch { - errorStack.append(error) - let nsErr = error as NSError - let userInfo = nsErr.userInfo as [String: Any] - if error as? TorusUtilError == .timeout { - group.cancelAll() - session.invalidateAndCancel() - throw error - } - if nsErr.code == -1003 { - // In case node is offline - os_log("retrieveDecryptAndReconstuct: DNS lookup failed, node %@ is probably offline.", log: getTorusLogger(log: TorusUtilsLogger.network, type: .error), type: .error, userInfo["NSErrorFailingURLKey"].debugDescription) - } else if let err = (error as? TorusUtilError) { - if err == TorusUtilError.thresholdError { - os_log("retrieveDecryptAndReconstuct - error: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .error), type: .error, error.localizedDescription) - } - } else { - os_log("retrieveDecryptAndReconstuct - error: %@", log: getTorusLogger(log: TorusUtilsLogger.core, type: .error), type: .error, error.localizedDescription) - } - } - } - throw TorusUtilError.runtime("retrieveDecryptAndReconstuct func failed") - }) + let (finalPubKeyX, finalPubKeyY) = try KeyUtils.getPublicKeyCoords(pubKey: finalPubKey!) + + let finalAddress = try KeyUtils.generateAddressFromPubKey(publicKeyX: finalPubKeyX, publicKeyY: finalPubKeyY) + + return TorusPublicKey( + oAuthKeyData: TorusPublicKey.OAuthKeyData( + evmAddress: oAuthAddress, + X: X.addLeading0sForLength64(), + Y: Y.addLeading0sForLength64() + ), + finalKeyData: TorusPublicKey.FinalKeyData( + evmAddress: finalAddress, + X: finalPubKeyX, + Y: finalPubKeyY + ), + metadata: TorusPublicKey.Metadata( + pubNonce: pubNonce, + nonce: nonce, + typeOfUser: typeOfUser, + upgraded: nonceResult?.upgraded ?? false, + serverTimeOffset: finalServertimeOffset), + nodesData: TorusPublicKey.NodesData(nodeIndexes: []) + ) } } diff --git a/Sources/TorusUtils/TorusUtilsExtraParams.swift b/Sources/TorusUtils/TorusUtilsExtraParams.swift new file mode 100644 index 00000000..d2280b1f --- /dev/null +++ b/Sources/TorusUtils/TorusUtilsExtraParams.swift @@ -0,0 +1,33 @@ +import Foundation + +// TODO: This class is a bit of a mess for legacy reasons and should be cleaned up in future. + +public class TorusUtilsExtraParams: Codable { + var nonce: String? // farcaster + var message: String? // farcaster + var signature: String? // farcaster, passkey, webauthn + var clientDataJson: String? // passkey, webauthn + var authenticatorData: String? // passkey, webauthn + var publicKey: String? // passkey, webauthn + var challenge: String? // passkey, webauthn + var rpOrigin: String? // passkey, webauthn + var rpId: String? // passkey, webauthn + var session_token_exp_second: Int? + var timestamp: Int? // Signature + + public init() {} + + public init(nonce: String? = nil, message: String? = nil, signature: String? = nil, clientDataJson: String? = nil, authenticatorData: String? = nil, publicKey: String? = nil, challenge: String? = nil, rpOrigin: String? = nil, rpId: String? = nil, session_token_exp_second: Int? = nil, timestamp: Int? = nil) { + self.nonce = nonce + self.message = message + self.signature = signature + self.clientDataJson = clientDataJson + self.authenticatorData = authenticatorData + self.publicKey = publicKey + self.challenge = challenge + self.rpOrigin = rpOrigin + self.rpId = rpId + self.session_token_exp_second = session_token_exp_second + self.timestamp = timestamp + } +} diff --git a/Sources/TorusUtils/VerifierParams.swift b/Sources/TorusUtils/VerifierParams.swift new file mode 100644 index 00000000..7c335043 --- /dev/null +++ b/Sources/TorusUtils/VerifierParams.swift @@ -0,0 +1,26 @@ +import Foundation + +public class VerifyParams: Codable { + public var verifier_id: String? + public var idtoken: String? + + public init(verifier_id: String?, idtoken: String?) { + self.verifier_id = verifier_id + self.idtoken = idtoken + } +} + +public class VerifierParams { + // [key: string]: unknown; This should be strongly typed + public let verifier_id: String + public let extended_verifier_id: String? + public let sub_verifier_ids: [String]? + public let verify_params: [VerifyParams]? + + public init(verifier_id: String, extended_verifier_id: String? = nil, sub_verifier_ids: [String]? = nil, verify_params: [VerifyParams]? = nil) { + self.verifier_id = verifier_id + self.extended_verifier_id = extended_verifier_id + self.sub_verifier_ids = sub_verifier_ids + self.verify_params = verify_params + } +} diff --git a/Tests/TorusUtilsTests/AquaTest.swift b/Tests/TorusUtilsTests/AquaTest.swift index 90ec485f..69359a20 100644 --- a/Tests/TorusUtilsTests/AquaTest.swift +++ b/Tests/TorusUtilsTests/AquaTest.swift @@ -1,167 +1,180 @@ import BigInt import FetchNodeDetails import JWTKit +import TorusUtils import XCTest -import CoreMedia -@testable import TorusUtils - class AquaTest: XCTestCase { var TORUS_TEST_EMAIL = "hello@tor.us" var TORUS_TEST_VERIFIER = "torus-test-health" var TORUS_TEST_AGGREGATE_VERIFIER = "torus-test-health-aggregate" var fnd: NodeDetailManager! - var tu: TorusUtils! + var torus: TorusUtils! override func setUp() { super.setUp() fnd = NodeDetailManager(network: .legacy(.AQUA)) - } - - func getFNDAndTUData(verifer: String, veriferID: String, enableOneKey: Bool = false) async throws -> AllNodeDetailsModel { - let nodeDetails = try await fnd.getNodeDetails(verifier: verifer, verifierID: veriferID) - tu = TorusUtils(enableOneKey: enableOneKey, network: .legacy(.AQUA), clientId: "YOUR_CLIENT_ID") - return nodeDetails + torus = try! TorusUtils(params: TorusOptions(clientId: "YOUR_CLIENT_ID", network: .legacy(.AQUA))) } func test_should_fetch_public_address() async throws { let verifier: String = "tkey-google-aqua" let verifierID: String = TORUS_TEST_EMAIL - let nodeDetails = try await getFNDAndTUData(verifer: verifier, veriferID: verifierID) - let val = try await tu.getPublicAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), verifier: verifier, verifierId: verifierID) + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + let val = try await torus.getPublicAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierId: verifierID) + XCTAssertEqual(val.finalKeyData!.evmAddress, "0xDfA967285AC699A70DA340F60d00DB19A272639d") - XCTAssertEqual(val.finalKeyData!.X, "4fc8db5d3fe164a3ab70fd6348721f2be848df2cc02fd2db316a154855a7aa7d") - XCTAssertEqual(val.finalKeyData!.Y, "f76933cbf5fe2916681075bb6cb4cde7d5f6b6ce290071b1b7106747d906457c") + XCTAssertLessThan(val.metadata!.serverTimeOffset, 20) + XCTAssertEqual(val.oAuthKeyData!.evmAddress, "0xDfA967285AC699A70DA340F60d00DB19A272639d") XCTAssertEqual(val.oAuthKeyData!.X, "4fc8db5d3fe164a3ab70fd6348721f2be848df2cc02fd2db316a154855a7aa7d") XCTAssertEqual(val.oAuthKeyData!.Y, "f76933cbf5fe2916681075bb6cb4cde7d5f6b6ce290071b1b7106747d906457c") + + XCTAssertEqual(val.finalKeyData!.evmAddress, "0xDfA967285AC699A70DA340F60d00DB19A272639d") + XCTAssertEqual(val.finalKeyData!.X, "4fc8db5d3fe164a3ab70fd6348721f2be848df2cc02fd2db316a154855a7aa7d") + XCTAssertEqual(val.finalKeyData!.Y, "f76933cbf5fe2916681075bb6cb4cde7d5f6b6ce290071b1b7106747d906457c") XCTAssertNil(val.metadata?.pubNonce) XCTAssertEqual(val.metadata?.nonce, 0) XCTAssertEqual(val.metadata?.upgraded, false) - XCTAssertEqual(val.metadata?.typeOfUser, UserType(rawValue: "v1")) + XCTAssertEqual(val.metadata?.typeOfUser, .v1) } func test_should_fetch_user_type_and_public_addresses() async throws { var verifier: String = "tkey-google-aqua" var verifierID: String = TORUS_TEST_EMAIL - let nodeDetails = try await getFNDAndTUData(verifer: verifier, veriferID: verifierID) - var val = try await tu.getUserTypeAndAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), verifier: verifier, verifierId: verifierID) - XCTAssertEqual(val.oAuthKeyData!.evmAddress, "0xDfA967285AC699A70DA340F60d00DB19A272639d") - XCTAssertEqual(val.oAuthKeyData!.X, "4fc8db5d3fe164a3ab70fd6348721f2be848df2cc02fd2db316a154855a7aa7d") - XCTAssertEqual(val.oAuthKeyData!.Y, "f76933cbf5fe2916681075bb6cb4cde7d5f6b6ce290071b1b7106747d906457c") - XCTAssertEqual(val.finalKeyData!.evmAddress, "0x79F06350eF34Aeed4BE68e26954D405D573f1438") - XCTAssertEqual(val.finalKeyData!.X, "99df45abc8e6ee03d2f94df33be79e939eadfbed20c6b88492782fdc3ef1dfd3") - XCTAssertEqual(val.finalKeyData!.Y, "12bf3e54599a177fdb88f8b22419df7ddf1622e1d2344301edbe090890a72b16") - XCTAssertEqual(val.metadata!.pubNonce!.x, "dc5a031fd2e0b55dbaece314ea125bac9da5f0a916bf156ff36b5ad71380ea32") - XCTAssertEqual(val.metadata!.pubNonce!.y, "affd749b98c209d2f9cf4dacb145d7897f82f1e2924a47b07874302ecc0b8ef1") - XCTAssertEqual(val.metadata?.nonce, 0) - XCTAssertEqual(val.metadata?.upgraded, false) - XCTAssertEqual(val.metadata?.typeOfUser, .v2) + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + let result1 = try await torus.getUserTypeAndAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierId: verifierID) + XCTAssertLessThan(result1.metadata!.serverTimeOffset, 20) + + XCTAssertEqual(result1.oAuthKeyData!.evmAddress, "0xDfA967285AC699A70DA340F60d00DB19A272639d") + XCTAssertEqual(result1.oAuthKeyData!.X, "4fc8db5d3fe164a3ab70fd6348721f2be848df2cc02fd2db316a154855a7aa7d") + XCTAssertEqual(result1.oAuthKeyData!.Y, "f76933cbf5fe2916681075bb6cb4cde7d5f6b6ce290071b1b7106747d906457c") + XCTAssertEqual(result1.finalKeyData!.evmAddress, "0x79F06350eF34Aeed4BE68e26954D405D573f1438") + XCTAssertEqual(result1.finalKeyData!.X, "99df45abc8e6ee03d2f94df33be79e939eadfbed20c6b88492782fdc3ef1dfd3") + XCTAssertEqual(result1.finalKeyData!.Y, "12bf3e54599a177fdb88f8b22419df7ddf1622e1d2344301edbe090890a72b16") + XCTAssertEqual(result1.metadata!.pubNonce!.x, "dc5a031fd2e0b55dbaece314ea125bac9da5f0a916bf156ff36b5ad71380ea32") + XCTAssertEqual(result1.metadata!.pubNonce!.y, "affd749b98c209d2f9cf4dacb145d7897f82f1e2924a47b07874302ecc0b8ef1") + XCTAssertEqual(result1.metadata?.nonce, 0) + XCTAssertEqual(result1.metadata?.upgraded, false) + XCTAssertEqual(result1.metadata?.typeOfUser, .v2) + XCTAssertNotNil(result1.nodesData) + // 1/1 user verifier = "tkey-google-aqua" verifierID = "somev2user@gmail.com" - val = try await tu.getUserTypeAndAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), verifier: verifier, verifierId: verifierID) - XCTAssertEqual(val.oAuthKeyData!.evmAddress, "0x4ea5260fF85678A2a326D08DF9C44d1f559a5828") - XCTAssertEqual(val.oAuthKeyData!.X, "0e6febe33a9d4eeb680cc6b63ff6237ad1971f27adcd7f104a3b1de18eda9337") - XCTAssertEqual(val.oAuthKeyData!.Y, "a5a915561f3543688e71281a850b9ee10b9690f305d9e79028dfc8359192b82d") - XCTAssertEqual(val.finalKeyData!.evmAddress, "0xBc32f315515AdE7010cabC5Fd68c966657A570BD") - XCTAssertEqual(val.finalKeyData!.X, "4897f120584ee18a72b9a6bb92c3ef6e45fc5fdff70beae7dc9325bd01332022") - XCTAssertEqual(val.finalKeyData!.Y, "2066dbef2fcdded4573e3c04d1c04edd5d44662168e636ed9d0b0cbe2e67c968") - XCTAssertEqual(val.finalKeyData!.evmAddress, "0xBc32f315515AdE7010cabC5Fd68c966657A570BD") - XCTAssertEqual(val.metadata?.nonce, 0) - XCTAssertEqual(val.metadata?.upgraded, false) - XCTAssertEqual(val.metadata?.typeOfUser, .v2) + let result2 = try await torus.getUserTypeAndAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierId: verifierID) + + XCTAssertLessThan(result2.metadata!.serverTimeOffset, 20) + XCTAssertEqual(result2.oAuthKeyData!.evmAddress, "0x4ea5260fF85678A2a326D08DF9C44d1f559a5828") + XCTAssertEqual(result2.oAuthKeyData!.X, "0e6febe33a9d4eeb680cc6b63ff6237ad1971f27adcd7f104a3b1de18eda9337") + XCTAssertEqual(result2.oAuthKeyData!.Y, "a5a915561f3543688e71281a850b9ee10b9690f305d9e79028dfc8359192b82d") + XCTAssertEqual(result2.finalKeyData!.evmAddress, "0xBc32f315515AdE7010cabC5Fd68c966657A570BD") + XCTAssertEqual(result2.finalKeyData!.X, "4897f120584ee18a72b9a6bb92c3ef6e45fc5fdff70beae7dc9325bd01332022") + XCTAssertEqual(result2.finalKeyData!.Y, "2066dbef2fcdded4573e3c04d1c04edd5d44662168e636ed9d0b0cbe2e67c968") + XCTAssertEqual(result2.finalKeyData!.evmAddress, "0xBc32f315515AdE7010cabC5Fd68c966657A570BD") + XCTAssertEqual(result2.metadata?.pubNonce?.x, "1601cf4dc4362b219260663d5ec5119699fbca185d08b7acb2e36cad914340d5") + XCTAssertEqual(result2.metadata?.pubNonce?.y, "c2f7871f61ee71b4486ac9fb40ec759099800e737139dc5dfaaaed8c9d77c3c1") + XCTAssertEqual(result2.metadata?.nonce, BigUInt(0)) + XCTAssertEqual(result2.metadata?.upgraded, false) + XCTAssertEqual(result2.metadata?.typeOfUser, .v2) + XCTAssertNotNil(result2.nodesData) + + // 2/n user verifierID = "caspertorus@gmail.com" - val = try await tu.getUserTypeAndAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), verifier: verifier, verifierId: verifierID) - XCTAssertEqual(val.oAuthKeyData!.evmAddress, "0x4ce0D09C3989eb3cC9372cC27fa022D721D737dD") - XCTAssertEqual(val.oAuthKeyData!.X, "e76d2f7fa2c0df324b4ab74629c3af47aa4609c35f1d2b6b90b77a47ab9a1281") - XCTAssertEqual(val.oAuthKeyData!.Y, "b33b35148d72d357070f66372e07fec436001bdb15c098276b120b9ed64c1e5f") - XCTAssertEqual(val.finalKeyData!.evmAddress, "0x5469C5aCB0F30929226AfF4622918DA8E1424a8D") - XCTAssertEqual(val.finalKeyData!.X, "c20fac685bb67169e92f1d5d8894d4eea18753c0ef3b7b1b2224233b2dfa3539") - XCTAssertEqual(val.finalKeyData!.Y, "c4f080b5c8d5c55c8eaba4bec70f668f36db4126f358b491d631fefea7c19d21") - XCTAssertEqual(val.metadata?.nonce, 0) - XCTAssertEqual(val.metadata?.upgraded, false) - XCTAssertEqual(val.metadata?.typeOfUser, .v2) + let result3 = try await torus.getUserTypeAndAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierId: verifierID) + + XCTAssertLessThan(result2.metadata!.serverTimeOffset, 20) + + XCTAssertEqual(result3.oAuthKeyData!.evmAddress, "0x4ce0D09C3989eb3cC9372cC27fa022D721D737dD") + XCTAssertEqual(result3.oAuthKeyData!.X, "e76d2f7fa2c0df324b4ab74629c3af47aa4609c35f1d2b6b90b77a47ab9a1281") + XCTAssertEqual(result3.oAuthKeyData!.Y, "b33b35148d72d357070f66372e07fec436001bdb15c098276b120b9ed64c1e5f") + XCTAssertEqual(result3.finalKeyData!.evmAddress, "0x5469C5aCB0F30929226AfF4622918DA8E1424a8D") + XCTAssertEqual(result3.finalKeyData!.X, "c20fac685bb67169e92f1d5d8894d4eea18753c0ef3b7b1b2224233b2dfa3539") + XCTAssertEqual(result3.finalKeyData!.Y, "c4f080b5c8d5c55c8eaba4bec70f668f36db4126f358b491d631fefea7c19d21") + XCTAssertEqual(result3.metadata?.pubNonce?.x, "17b1ebce1fa874452a96d0c6d74c1445b78f16957c7decc5d2a202b0ce4662f5") + XCTAssertEqual(result3.metadata?.pubNonce?.y, "b5432cb593753e1b3ecf98b05dc03e57bc02c415e1b80a1ffc5a401ec1f0abd6") + XCTAssertEqual(result3.metadata?.nonce, 0) + XCTAssertEqual(result3.metadata?.upgraded, false) + XCTAssertEqual(result3.metadata?.typeOfUser, .v2) + XCTAssertNotNil(result3.nodesData) } - func test_key_assign() async throws { + func test_should_be_able_to_key_assign() async throws { let fakeEmail = generateRandomEmail(of: 6) let verifier: String = "tkey-google-aqua" let verifierID: String = fakeEmail - let nodeDetails = try await getFNDAndTUData(verifer: verifier, veriferID: verifierID) - let data = try await tu.getPublicAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), verifier: verifier, verifierId: verifierID) - XCTAssertNotNil(data.finalKeyData) - XCTAssertNotEqual(data.finalKeyData?.evmAddress, "") + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + let data = try await torus.getPublicAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierId: verifierID) + + XCTAssertNotNil(data.finalKeyData?.evmAddress) + XCTAssertNotNil(data.oAuthKeyData?.evmAddress) XCTAssertEqual(data.metadata?.typeOfUser, .v1) XCTAssertEqual(data.metadata?.upgraded, false) + XCTAssertNotNil(data.nodesData) } - func test_login() async throws { + func test_should_be_able_to_login() async throws { let verifier: String = TORUS_TEST_VERIFIER let verifierID: String = TORUS_TEST_EMAIL let verifierParams = VerifierParams(verifier_id: verifierID) let jwt = try! generateIdToken(email: verifierID) - let extraParams = ["verifieridentifier": verifier, "verifier_id": verifierID] as [String: Codable] - let nodeDetails = try await getFNDAndTUData(verifer: verifier, veriferID: verifierID) - let data = try await tu.retrieveShares(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), indexes: nodeDetails.getTorusIndexes(), verifier: verifier, verifierParams: verifierParams, idToken: jwt, extraParams: extraParams) - - XCTAssertEqual(data.finalKeyData?.evmAddress, "0x9EBE51e49d8e201b40cAA4405f5E0B86d9D27195") - XCTAssertEqual(data.finalKeyData?.X, "c7bcc239f0957bb05bda94757eb4a5f648339424b22435da5cf7a0f2b2323664") - XCTAssertEqual(data.finalKeyData?.Y, "63795690a33e575ee12d832935d563c2b5f2e1b1ffac63c32a4674152f68cb3f") - XCTAssertEqual(data.finalKeyData?.privKey, "f726ce4ac79ae4475d72633c94769a8817aff35eebe2d4790aed7b5d8a84aa1d") - XCTAssertEqual(data.oAuthKeyData?.evmAddress, "0x9EBE51e49d8e201b40cAA4405f5E0B86d9D27195") - XCTAssertEqual(data.oAuthKeyData?.X, "c7bcc239f0957bb05bda94757eb4a5f648339424b22435da5cf7a0f2b2323664") - XCTAssertEqual(data.oAuthKeyData?.Y, "63795690a33e575ee12d832935d563c2b5f2e1b1ffac63c32a4674152f68cb3f") - XCTAssertEqual(data.oAuthKeyData?.privKey, "f726ce4ac79ae4475d72633c94769a8817aff35eebe2d4790aed7b5d8a84aa1d") - XCTAssertEqual(data.sessionData?.sessionTokenData.count, 0) - XCTAssertEqual(data.sessionData?.sessionAuthKey, "") - XCTAssertEqual(data.metadata?.pubNonce, nil) - XCTAssertEqual(data.metadata?.nonce, BigUInt(0)) - XCTAssertEqual(data.metadata?.typeOfUser, .v1) - XCTAssertEqual(data.metadata?.upgraded, nil) + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + let data = try await torus.retrieveShares(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierParams: verifierParams, idToken: jwt) + + XCTAssertLessThan(data.metadata.serverTimeOffset, 20) + + XCTAssertEqual(data.finalKeyData.evmAddress, "0x9EBE51e49d8e201b40cAA4405f5E0B86d9D27195") + XCTAssertEqual(data.finalKeyData.X, "c7bcc239f0957bb05bda94757eb4a5f648339424b22435da5cf7a0f2b2323664") + XCTAssertEqual(data.finalKeyData.Y, "63795690a33e575ee12d832935d563c2b5f2e1b1ffac63c32a4674152f68cb3f") + XCTAssertEqual(data.finalKeyData.privKey, "f726ce4ac79ae4475d72633c94769a8817aff35eebe2d4790aed7b5d8a84aa1d") + XCTAssertEqual(data.oAuthKeyData.evmAddress, "0x9EBE51e49d8e201b40cAA4405f5E0B86d9D27195") + XCTAssertEqual(data.oAuthKeyData.X, "c7bcc239f0957bb05bda94757eb4a5f648339424b22435da5cf7a0f2b2323664") + XCTAssertEqual(data.oAuthKeyData.Y, "63795690a33e575ee12d832935d563c2b5f2e1b1ffac63c32a4674152f68cb3f") + XCTAssertEqual(data.oAuthKeyData.privKey, "f726ce4ac79ae4475d72633c94769a8817aff35eebe2d4790aed7b5d8a84aa1d") + XCTAssertNotNil(data.sessionData) + XCTAssertNil(data.metadata.pubNonce) + XCTAssertEqual(data.metadata.nonce, BigUInt(0)) + XCTAssertEqual(data.metadata.typeOfUser, .v1) + XCTAssertNil(data.metadata.upgraded) + XCTAssertNotNil(data.nodesData) } - func test_aggregate_login() async throws { + func test_should_be_able_to_aggregate_login() async throws { let verifier: String = TORUS_TEST_AGGREGATE_VERIFIER let verifierID: String = TORUS_TEST_EMAIL - let verifierParams = VerifierParams(verifier_id: verifierID) let jwt = try! generateIdToken(email: TORUS_TEST_EMAIL) - let hashedIDToken = keccak256Data(jwt.data(using: .utf8) ?? Data()).toHexString(); - - let extraParams = ["verifier_id": TORUS_TEST_EMAIL, "sub_verifier_ids": [TORUS_TEST_VERIFIER], "verify_params": [["verifier_id": TORUS_TEST_EMAIL, "idtoken": jwt]]] as [String: Codable] - let nodeDetails = try await getFNDAndTUData(verifer: verifier, veriferID: verifierID) - let data = try await tu.retrieveShares(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), indexes: nodeDetails.getTorusIndexes(), verifier: verifier, verifierParams: verifierParams, idToken: hashedIDToken, extraParams: extraParams) - XCTAssertEqual(data.finalKeyData?.evmAddress, "0x5b58d8a16fDA79172cd42Dc3068d5CEf26a5C81D") - XCTAssertEqual(data.finalKeyData?.X, "37a4ac8cbef68e88bcec5909d9b6fffb539187365bb723f3d7bffe56ae80e31d") - XCTAssertEqual(data.finalKeyData?.Y, "f963f2d08ed4dd0da9b8a8d74c6fdaeef7bdcde31f84fcce19fa2173d40b2c10") - XCTAssertEqual(data.finalKeyData?.privKey, "488d39ac548e15cfb0eaf161d86496e1645b09437df21311e24a56c4efd76355") - XCTAssertEqual(data.oAuthKeyData?.evmAddress, "0x5b58d8a16fDA79172cd42Dc3068d5CEf26a5C81D") - XCTAssertEqual(data.oAuthKeyData?.X, "37a4ac8cbef68e88bcec5909d9b6fffb539187365bb723f3d7bffe56ae80e31d") - XCTAssertEqual(data.oAuthKeyData?.Y, "f963f2d08ed4dd0da9b8a8d74c6fdaeef7bdcde31f84fcce19fa2173d40b2c10") - XCTAssertEqual(data.oAuthKeyData?.privKey, "488d39ac548e15cfb0eaf161d86496e1645b09437df21311e24a56c4efd76355") - XCTAssertEqual(data.sessionData?.sessionTokenData.count, 0) - XCTAssertEqual(data.sessionData?.sessionAuthKey, "") - XCTAssertEqual(data.metadata?.pubNonce == nil, true) - XCTAssertEqual(data.metadata?.nonce, BigUInt(0)) - XCTAssertEqual(data.metadata?.typeOfUser == UserType.v1, true) - XCTAssertEqual(data.metadata?.upgraded == nil, true) + let hashedIDToken = try KeyUtils.keccak256Data(jwt) + + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + + let verifierParams = VerifierParams(verifier_id: verifierID, sub_verifier_ids: [TORUS_TEST_VERIFIER], verify_params: [VerifyParams(verifier_id: TORUS_TEST_EMAIL, idtoken: jwt)]) + + let data = try await torus.retrieveShares(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierParams: verifierParams, idToken: hashedIDToken) + XCTAssertEqual(data.finalKeyData.evmAddress, "0x5b58d8a16fDA79172cd42Dc3068d5CEf26a5C81D") + XCTAssertEqual(data.finalKeyData.X, "37a4ac8cbef68e88bcec5909d9b6fffb539187365bb723f3d7bffe56ae80e31d") + XCTAssertEqual(data.finalKeyData.Y, "f963f2d08ed4dd0da9b8a8d74c6fdaeef7bdcde31f84fcce19fa2173d40b2c10") + XCTAssertEqual(data.finalKeyData.privKey, "488d39ac548e15cfb0eaf161d86496e1645b09437df21311e24a56c4efd76355") + XCTAssertEqual(data.oAuthKeyData.evmAddress, "0x5b58d8a16fDA79172cd42Dc3068d5CEf26a5C81D") + XCTAssertEqual(data.oAuthKeyData.X, "37a4ac8cbef68e88bcec5909d9b6fffb539187365bb723f3d7bffe56ae80e31d") + XCTAssertEqual(data.oAuthKeyData.Y, "f963f2d08ed4dd0da9b8a8d74c6fdaeef7bdcde31f84fcce19fa2173d40b2c10") + XCTAssertEqual(data.oAuthKeyData.privKey, "488d39ac548e15cfb0eaf161d86496e1645b09437df21311e24a56c4efd76355") + XCTAssertNil(data.metadata.pubNonce) + XCTAssertEqual(data.metadata.nonce, BigUInt(0)) + XCTAssertEqual(data.metadata.typeOfUser, .v1) + XCTAssertNil(data.metadata.upgraded) + XCTAssertNotNil(data.nodesData) } -} -extension AquaTest { func test_retrieveShares_some_nodes_down() async throws { let verifier: String = TORUS_TEST_VERIFIER let verifierID: String = TORUS_TEST_EMAIL let verifierParams = VerifierParams(verifier_id: verifierID) let jwt = try! generateIdToken(email: verifierID) - let extraParams = ["verifieridentifier": verifier, "verifier_id": verifierID] as [String: Codable] - let nodeDetails = try await getFNDAndTUData(verifer: verifier, veriferID: verifierID) + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) var endpoints = nodeDetails.getTorusNodeEndpoints() - endpoints[0] = "https://ndjnfjbfrj/random" - // should fail if un-commented threshold 4/5 - // endpoints[1] = "https://ndjnfjbfrj/random" - let data = try await tu.retrieveShares(endpoints: endpoints, torusNodePubs: nodeDetails.getTorusNodePub(), indexes: nodeDetails.getTorusIndexes(), verifier: verifier, verifierParams: verifierParams, idToken: jwt, extraParams: extraParams) - XCTAssertEqual(data.finalKeyData?.privKey, "f726ce4ac79ae4475d72633c94769a8817aff35eebe2d4790aed7b5d8a84aa1d") + endpoints[endpoints.count - 1] = "https://ndjnfjbfrj/random" + let data = try await torus.retrieveShares(endpoints: endpoints, verifier: verifier, verifierParams: verifierParams, idToken: jwt) + XCTAssertEqual(data.finalKeyData.privKey, "f726ce4ac79ae4475d72633c94769a8817aff35eebe2d4790aed7b5d8a84aa1d") } } diff --git a/Tests/TorusUtilsTests/BaseTests/Combinations.swift b/Tests/TorusUtilsTests/BaseTests/Combinations.swift new file mode 100644 index 00000000..6a2c6a9f --- /dev/null +++ b/Tests/TorusUtilsTests/BaseTests/Combinations.swift @@ -0,0 +1,39 @@ +import Foundation +@testable import TorusUtils +import XCTest + +class Combinations: XCTestCase { + func test_kCombinations() throws { + let input = [0, 1, 2, 3, 4, 5] + let zero = kCombinations(elements: input.slice, k: 0) + XCTAssertEqual(zero, []) + let greater = kCombinations(elements: input.slice, k: 10) + XCTAssertEqual(greater, []) + let equal = kCombinations(elements: input.slice, k: 6) + XCTAssertEqual(equal, [[0, 1, 2, 3, 4, 5]]) + let one = kCombinations(elements: input.slice, k: 1) + XCTAssertEqual(one, [[0], [1], [2], [3], [4], [5]]) + let two = kCombinations(elements: input.slice, k: 2) + XCTAssertEqual(two, [ + [0, 1], [0, 2], [0, 3], [0, 4], [0, 5], + [1, 2], [1, 3], [1, 4], [1, 5], + [2, 3], [2, 4], [2, 5], + [3, 4], [3, 5], + [4, 5], + ]) + let input2 = [1, 2, 3, 4, 5] + let next = kCombinations(elements: input2.slice, k: 3) + XCTAssertEqual(next, [ + [1, 2, 3], + [1, 2, 4], + [1, 2, 5], + [1, 3, 4], + [1, 3, 5], + [1, 4, 5], + [2, 3, 4], + [2, 3, 5], + [2, 4, 5], + [3, 4, 5], + ]) + } +} diff --git a/Tests/TorusUtilsTests/Helpers/EtherAddress.swift b/Tests/TorusUtilsTests/BaseTests/EtherAddress.swift similarity index 61% rename from Tests/TorusUtilsTests/Helpers/EtherAddress.swift rename to Tests/TorusUtilsTests/BaseTests/EtherAddress.swift index 552a395d..585c9b35 100644 --- a/Tests/TorusUtilsTests/Helpers/EtherAddress.swift +++ b/Tests/TorusUtilsTests/BaseTests/EtherAddress.swift @@ -3,11 +3,10 @@ import Foundation import XCTest class EtherTest: XCTestCase { - func testPublicToEtherAddress() { + func testPublicToEtherAddress() throws { let fullAddress = String("04238569d5e12caf57d34fb5b2a0679c7775b5f61fd18cd69db9cc600a651749c3ec13a9367380b7a024a67f5e663f3afd40175c3223da63f6024b05d0bd9f292e") - let X: String = String(fullAddress.suffix(128).prefix(64)) - let Y: String = String(fullAddress.suffix(64)) - let etherAddress = generateAddressFromPubKey(publicKeyX: X, publicKeyY: Y) + let (X, Y) = try KeyUtils.getPublicKeyCoords(pubKey: fullAddress) + let etherAddress = try KeyUtils.generateAddressFromPubKey(publicKeyX: X, publicKeyY: Y) let finalAddress = "0x048975d4997D7578A3419851639c10318db430b6" XCTAssertEqual(etherAddress, finalAddress) } diff --git a/Tests/TorusUtilsTests/BaseTests/HexEncodedString.swift b/Tests/TorusUtilsTests/BaseTests/HexEncodedString.swift new file mode 100644 index 00000000..162a664c --- /dev/null +++ b/Tests/TorusUtilsTests/BaseTests/HexEncodedString.swift @@ -0,0 +1,19 @@ +import Foundation +@testable import TorusUtils +import XCTest + +class HexEndodedTest: XCTestCase { + func testOddAndEvenStrings() throws { + let odd = "6F6464".hexEncodedToString() + let even = "6576656E".hexEncodedToString() + let extra_zero_padded = "06576656E".hexEncodedToString() + let double_padded = "00006576656E".hexEncodedToString() + let unpadded = "56E".hexEncodedToString() + + XCTAssertEqual(odd, "odd") // 6F 64 64 + XCTAssertEqual(even, "even") // 65 76 65 6E + XCTAssertEqual(extra_zero_padded, "even") // 00 65 76 65 6E + XCTAssertEqual(double_padded, "even") // 00 00 65 76 65 6E + XCTAssertEqual(unpadded, "\u{5}n") // 05 6E + } +} diff --git a/Tests/TorusUtilsTests/Helpers/Lagrange.swift b/Tests/TorusUtilsTests/BaseTests/Lagrange.swift similarity index 75% rename from Tests/TorusUtilsTests/Helpers/Lagrange.swift rename to Tests/TorusUtilsTests/BaseTests/Lagrange.swift index 1a2366c5..bcdd90a1 100644 --- a/Tests/TorusUtilsTests/Helpers/Lagrange.swift +++ b/Tests/TorusUtilsTests/BaseTests/Lagrange.swift @@ -1,8 +1,8 @@ import BigInt import Foundation +@testable import TorusUtils import XCTest -@testable import TorusUtils class LagrangeTest: XCTestCase { var tu: TorusUtils! @@ -13,7 +13,7 @@ class LagrangeTest: XCTestCase { Point(x: BigInt(3), y: BigInt(10)), ] - let polynomial = lagrangeInterpolatePolynomial(points: points) + let polynomial = Lagrange.lagrangeInterpolatePolynomial(points: points) let xValues: [BigInt] = [BigInt(1), BigInt(2), BigInt(3)] let expectedYValues: [BigInt] = [BigInt(2), BigInt(5), BigInt(10)] @@ -24,9 +24,9 @@ class LagrangeTest: XCTestCase { let y = polynomial.polyEval(x: x) - assert(y == expectedY, "Point (\(x), \(y)) does not match the expected value of (\(x), \(expectedY)).") + XCTAssertEqual(y, expectedY) } - - print("All assertions passed.") } + + // TODO: Test other methods } diff --git a/Tests/TorusUtilsTests/Celeste.swift b/Tests/TorusUtilsTests/Celeste.swift new file mode 100644 index 00000000..8f4c3a88 --- /dev/null +++ b/Tests/TorusUtilsTests/Celeste.swift @@ -0,0 +1,171 @@ +import BigInt +import FetchNodeDetails +import Foundation +import TorusUtils +import XCTest + +class CelesteTest: XCTestCase { + var TORUS_TEST_EMAIL = "hello@tor.us" + var TORUS_TEST_VERIFIER = "torus-test-health" + var TORUS_TEST_AGGREGATE_VERIFIER = "torus-test-health-aggregate" + var fnd: NodeDetailManager! + var torus: TorusUtils! + + override func setUp() { + super.setUp() + fnd = NodeDetailManager(network: .legacy(.CELESTE)) + torus = try! TorusUtils(params: TorusOptions(clientId: "YOUR_CLIENT_ID", network: .legacy(.CELESTE))) + } + + func test_should_fetch_public_address() async throws { + let verifier = "tkey-google-celeste" + let verifierID = TORUS_TEST_EMAIL + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + let val = try await torus.getPublicAddress(endpoints: nodeDetails.torusNodeEndpoints, verifier: verifier, verifierId: verifierID) + + XCTAssertEqual(val.finalKeyData!.evmAddress, "0xC3115b9d6FaB99739b23DA9dfcBA47A4Ec4Cd113") + XCTAssertLessThan(val.metadata!.serverTimeOffset, 20) + + XCTAssertEqual(val.finalKeyData!.evmAddress, "0xC3115b9d6FaB99739b23DA9dfcBA47A4Ec4Cd113") + XCTAssertEqual(val.finalKeyData!.X, "b89b9d66b247d7294a98616b95b7bfa1675aa85a1df4d89f2780283864f1b6e9") + XCTAssertEqual(val.finalKeyData!.Y, "65422a8ccd66e638899fc53497e468a9a0bf50d45c9cb85ae0ffcfc13f433ffb") + XCTAssertEqual(val.oAuthKeyData!.evmAddress, "0xC3115b9d6FaB99739b23DA9dfcBA47A4Ec4Cd113") + XCTAssertEqual(val.oAuthKeyData!.X, "b89b9d66b247d7294a98616b95b7bfa1675aa85a1df4d89f2780283864f1b6e9") + XCTAssertEqual(val.oAuthKeyData!.Y, "65422a8ccd66e638899fc53497e468a9a0bf50d45c9cb85ae0ffcfc13f433ffb") + XCTAssertNil(val.metadata?.pubNonce) + XCTAssertEqual(val.metadata?.nonce, 0) + XCTAssertEqual(val.metadata?.upgraded, false) + XCTAssertEqual(val.metadata?.typeOfUser, .v1) + XCTAssertNotNil(val.nodesData) + } + + func test_should_fetch_user_type_and_public_address() async throws { + var verifier: String = "tkey-google-celeste" + var verifierID: String = TORUS_TEST_EMAIL + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + var val = try await torus.getUserTypeAndAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierId: verifierID) + + XCTAssertEqual(val.finalKeyData!.evmAddress, "0xC3115b9d6FaB99739b23DA9dfcBA47A4Ec4Cd113") + XCTAssertLessThan(val.metadata!.serverTimeOffset, 20) + + XCTAssertEqual(val.oAuthKeyData!.evmAddress, "0xC3115b9d6FaB99739b23DA9dfcBA47A4Ec4Cd113") + XCTAssertEqual(val.oAuthKeyData!.X, "b89b9d66b247d7294a98616b95b7bfa1675aa85a1df4d89f2780283864f1b6e9") + XCTAssertEqual(val.oAuthKeyData!.Y, "65422a8ccd66e638899fc53497e468a9a0bf50d45c9cb85ae0ffcfc13f433ffb") + XCTAssertEqual(val.finalKeyData!.X, "b89b9d66b247d7294a98616b95b7bfa1675aa85a1df4d89f2780283864f1b6e9") + XCTAssertEqual(val.finalKeyData!.Y, "65422a8ccd66e638899fc53497e468a9a0bf50d45c9cb85ae0ffcfc13f433ffb") + XCTAssertNil(val.metadata!.pubNonce) + XCTAssertEqual(val.metadata?.nonce, 0) + XCTAssertEqual(val.metadata?.upgraded, false) + XCTAssertEqual(val.metadata?.typeOfUser, .v1) + + verifier = "tkey-google-celeste" + verifierID = "somev2user@gmail.com" + val = try await torus.getUserTypeAndAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierId: verifierID) + + XCTAssertEqual(val.finalKeyData!.evmAddress, "0x8d69CE354DA39413f205FdC8680dE1F3FBBb36e2") + XCTAssertLessThan(val.metadata!.serverTimeOffset, 20) + + XCTAssertEqual(val.oAuthKeyData!.evmAddress, "0xda4afB35493094Dd2C05b186Ca0FABAD96491B21") + XCTAssertEqual(val.oAuthKeyData!.X, "cfa646a2949ebe559205c5c407d734d1b6927f2ea5fbeabfcbc31ab9a985a336") + XCTAssertEqual(val.oAuthKeyData!.Y, "8f988eb8b59515293820aa38af172b153e8d25307db8d5f410407c20e062b6e6") + XCTAssertEqual(val.finalKeyData!.evmAddress, "0x8d69CE354DA39413f205FdC8680dE1F3FBBb36e2") + XCTAssertEqual(val.finalKeyData!.X, "5962144e03b993b0e503eb4e6e0196427f9fc9472f0dfd1be2ca5d4939f91680") + XCTAssertEqual(val.finalKeyData!.Y, "f6e81f01f483110badab18371237d15834f9ecf31c3588c165dae32ec446ac38") + XCTAssertEqual(val.metadata?.pubNonce?.x, "2f630074151394ba1f715986a9215f4e36c9f22fc264ff880ef6d162c1300aa8") + XCTAssertEqual(val.metadata?.pubNonce?.y, "704cb63e5f7a291735c54e22242ef53673642ec1660da00f1abc2e7909da03d7") + XCTAssertEqual(val.metadata?.pubNonce?.x, "2f630074151394ba1f715986a9215f4e36c9f22fc264ff880ef6d162c1300aa8") + XCTAssertEqual(val.metadata?.pubNonce?.y, "704cb63e5f7a291735c54e22242ef53673642ec1660da00f1abc2e7909da03d7") + XCTAssertEqual(val.metadata?.nonce, 0) + XCTAssertEqual(val.metadata?.upgraded, false) + XCTAssertEqual(val.metadata?.typeOfUser, .v2) + XCTAssertNotNil(val.nodesData) + + verifier = "tkey-google-celeste" + verifierID = "caspertorus@gmail.com" + val = try await torus.getUserTypeAndAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierId: verifierID) + + XCTAssertEqual(val.finalKeyData!.evmAddress, "0x8108c29976C458e76f797AD55A3715Ce80a3fe78") + XCTAssertLessThan(val.metadata!.serverTimeOffset, 20) + + XCTAssertEqual(val.oAuthKeyData!.evmAddress, "0xc8c4748ec135196fb482C761da273C31Ec48B099") + XCTAssertEqual(val.oAuthKeyData!.X, "0cc857201e6c304dd893b243e323fe95982e5a99c0994cf902efa2432a672eb4") + XCTAssertEqual(val.oAuthKeyData!.Y, "37a2f53c250b3e1186e38ece3dfcbcb23e325913038703531831b96d3e7b54cc") + XCTAssertEqual(val.finalKeyData!.evmAddress, "0x8108c29976C458e76f797AD55A3715Ce80a3fe78") + XCTAssertEqual(val.finalKeyData!.X, "e95fe2d595ade03f56d9c9a147fbb67705041704f147576fa4a8afbe7dc69470") + XCTAssertEqual(val.finalKeyData!.Y, "3e20e4b331466769c4dd78f4561bfb2849010b4005b09c2ed082380326724ebe") + XCTAssertEqual(val.metadata?.pubNonce?.x, "f8ff2c44cc0abf512d35b35c3c5cbc0eda700d49bc13b72c5492b0cdb2ca3619") + XCTAssertEqual(val.metadata?.pubNonce?.y, "88fb3087cec269c8c39d25b04f15298d33712f13b0f9665821328dfc7a567afb") + XCTAssertEqual(val.metadata?.nonce, 0) + XCTAssertEqual(val.metadata?.upgraded, false) + XCTAssertEqual(val.metadata?.typeOfUser, .v2) + XCTAssertNotNil(val.nodesData) + } + + func test_should_be_able_to_key_assign() async throws { + let fakeEmail = generateRandomEmail(of: 6) + let verifier: String = "tkey-google-celeste" + let verifierID: String = fakeEmail + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + let data = try await torus.getPublicAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierId: verifierID) + XCTAssertNotEqual(data.finalKeyData?.evmAddress, "") + XCTAssertNotEqual(data.oAuthKeyData?.evmAddress, "") + XCTAssertEqual(data.metadata?.typeOfUser, .v1) + XCTAssertEqual(data.metadata?.upgraded, false) + } + + func test_should_be_able_to_login() async throws { + let verifier: String = TORUS_TEST_VERIFIER + let verifierID: String = TORUS_TEST_EMAIL + let jwt = try! generateIdToken(email: verifierID) + let verifierParams = VerifierParams(verifier_id: verifierID) + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + let data = try await torus.retrieveShares(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierParams: verifierParams, idToken: jwt) + + XCTAssertEqual(data.finalKeyData.evmAddress, "0x58420FB83971C4490D8c9B091f8bfC890D716617") + XCTAssertLessThan(data.metadata.serverTimeOffset, 20) + + XCTAssertEqual(data.oAuthKeyData.evmAddress, "0x58420FB83971C4490D8c9B091f8bfC890D716617") + XCTAssertEqual(data.oAuthKeyData.X, "73b82ce0f8201a962636d404fe7a683f37c2267a9528576e1dac9964940add74") + XCTAssertEqual(data.oAuthKeyData.Y, "6d28c46c5385b90322bde74d6c5096e154eae2838399f4d6e8d752f7b0c449c1") + XCTAssertEqual(data.oAuthKeyData.privKey, "0ae056aa938080c9e8bf6641261619e09fd510c91bb5aad14b0de9742085a914") + XCTAssertEqual(data.finalKeyData.evmAddress, "0x58420FB83971C4490D8c9B091f8bfC890D716617") + XCTAssertEqual(data.finalKeyData.X, "73b82ce0f8201a962636d404fe7a683f37c2267a9528576e1dac9964940add74") + XCTAssertEqual(data.finalKeyData.Y, "6d28c46c5385b90322bde74d6c5096e154eae2838399f4d6e8d752f7b0c449c1") + XCTAssertEqual(data.finalKeyData.privKey, "0ae056aa938080c9e8bf6641261619e09fd510c91bb5aad14b0de9742085a914") + XCTAssertNotNil(data.sessionData) + XCTAssertNil(data.metadata.pubNonce) + XCTAssertEqual(data.metadata.nonce, BigUInt(0)) + XCTAssertEqual(data.metadata.typeOfUser, .v1) + XCTAssertNil(data.metadata.upgraded) + XCTAssertNotNil(data.nodesData) + } + + func test_should_be_able_to_aggregate_login() async throws { + let verifier: String = TORUS_TEST_AGGREGATE_VERIFIER + let verifierID: String = TORUS_TEST_EMAIL + let jwt = try! generateIdToken(email: TORUS_TEST_EMAIL) + let hashedIDToken = try KeyUtils.keccak256Data(jwt) + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + + let verifierParams = VerifierParams(verifier_id: verifierID, sub_verifier_ids: [TORUS_TEST_VERIFIER], verify_params: [VerifyParams(verifier_id: verifierID, idtoken: jwt)]) + let data = try await torus.retrieveShares(endpoints: nodeDetails.torusNodeEndpoints, verifier: verifier, verifierParams: verifierParams, idToken: hashedIDToken) + + XCTAssertEqual(data.finalKeyData.evmAddress, "0x535Eb1AefFAc6f699A2a1A5846482d7b5b2BD564") + XCTAssertLessThan(data.metadata.serverTimeOffset, 20) + + XCTAssertEqual(data.oAuthKeyData.evmAddress, "0x535Eb1AefFAc6f699A2a1A5846482d7b5b2BD564") + XCTAssertEqual(data.oAuthKeyData.X, "df6eb11d52e76b388a44896e9442eda17096c2b67b0be957a4ba0b68a70111ca") + XCTAssertEqual(data.oAuthKeyData.Y, "bfd29ab1e97b3f7c444bb3e7ad0acb39d72589371387436c7d623d1e83f3d6eb") + XCTAssertEqual(data.oAuthKeyData.privKey, "356305761eca57f27b09700d76456ad627b084152725dbfdfcfa0abcd9d4f17e") + XCTAssertEqual(data.finalKeyData.evmAddress, "0x535Eb1AefFAc6f699A2a1A5846482d7b5b2BD564") + XCTAssertEqual(data.finalKeyData.X, "df6eb11d52e76b388a44896e9442eda17096c2b67b0be957a4ba0b68a70111ca") + XCTAssertEqual(data.finalKeyData.Y, "bfd29ab1e97b3f7c444bb3e7ad0acb39d72589371387436c7d623d1e83f3d6eb") + XCTAssertEqual(data.finalKeyData.privKey, "356305761eca57f27b09700d76456ad627b084152725dbfdfcfa0abcd9d4f17e") + XCTAssertNotNil(data.sessionData) + XCTAssertNil(data.metadata.pubNonce) + XCTAssertEqual(data.metadata.nonce, BigUInt(0)) + XCTAssertEqual(data.metadata.typeOfUser, .v1) + XCTAssertNil(data.metadata.upgraded) + XCTAssertNotNil(data.nodesData) + } +} diff --git a/Tests/TorusUtilsTests/CyanTest.swift b/Tests/TorusUtilsTests/CyanTest.swift index f1b9982b..8c29c847 100644 --- a/Tests/TorusUtilsTests/CyanTest.swift +++ b/Tests/TorusUtilsTests/CyanTest.swift @@ -1,51 +1,53 @@ import BigInt import FetchNodeDetails import JWTKit +import TorusUtils import XCTest -import CoreMedia -@testable import TorusUtils - class CyanTest: XCTestCase { var TORUS_TEST_EMAIL = "hello@tor.us" var TORUS_TEST_VERIFIER = "torus-test-health" var TORUS_TEST_AGGREGATE_VERIFIER = "torus-test-health-aggregate" var fnd: NodeDetailManager! - var tu: TorusUtils! + var torus: TorusUtils! override func setUp() { super.setUp() fnd = NodeDetailManager(network: .legacy(.CYAN)) - } - - func getFNDAndTUData(verifer: String, veriferID: String, enableOneKey: Bool = false) async throws -> AllNodeDetailsModel { - let nodeDetails = try await fnd.getNodeDetails(verifier: verifer, verifierID: veriferID) - tu = TorusUtils(enableOneKey: enableOneKey, network: .legacy(.CYAN), clientId: "YOUR_CLIENT_ID") - return nodeDetails + torus = try! TorusUtils(params: TorusOptions(clientId: "YOUR_CLIENT_ID", network: .legacy(.CYAN))) } func test_should_fetch_public_address() async throws { let verifier: String = "tkey-google-cyan" let verifierID: String = TORUS_TEST_EMAIL - let nodeDetails = try await getFNDAndTUData(verifer: verifier, veriferID: verifierID) - let val = try await tu.getPublicAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), verifier: verifier, verifierId: verifierID) + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + let val = try await torus.getPublicAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierId: verifierID) + XCTAssertEqual(val.finalKeyData!.evmAddress, "0xA3767911A84bE6907f26C572bc89426dDdDB2825") - XCTAssertEqual(val.finalKeyData!.X, "2853f323437da98ce021d06854f4b292db433c0ad03b204ef223ac2583609a6a") - XCTAssertEqual(val.finalKeyData!.Y, "f026b4788e23523e0c8fcbf0bdcf1c1a62c9cde8f56170309607a7a52a19f7c1") + XCTAssertLessThan(val.metadata!.serverTimeOffset, 20) + XCTAssertEqual(val.oAuthKeyData!.evmAddress, "0xA3767911A84bE6907f26C572bc89426dDdDB2825") XCTAssertEqual(val.oAuthKeyData!.X, "2853f323437da98ce021d06854f4b292db433c0ad03b204ef223ac2583609a6a") XCTAssertEqual(val.oAuthKeyData!.Y, "f026b4788e23523e0c8fcbf0bdcf1c1a62c9cde8f56170309607a7a52a19f7c1") + XCTAssertEqual(val.finalKeyData!.evmAddress, "0xA3767911A84bE6907f26C572bc89426dDdDB2825") + XCTAssertEqual(val.finalKeyData!.X, "2853f323437da98ce021d06854f4b292db433c0ad03b204ef223ac2583609a6a") + XCTAssertEqual(val.finalKeyData!.Y, "f026b4788e23523e0c8fcbf0bdcf1c1a62c9cde8f56170309607a7a52a19f7c1") XCTAssertNil(val.metadata?.pubNonce) XCTAssertEqual(val.metadata?.nonce, 0) XCTAssertEqual(val.metadata?.upgraded, false) XCTAssertEqual(val.metadata?.typeOfUser, UserType(rawValue: "v1")) + XCTAssertNotNil(val.nodesData) } - func test_get_user_type_and_addresses() async throws { + func test_should_fetch_user_type_and_addresses() async throws { var verifier: String = "tkey-google-cyan" var verifierID: String = TORUS_TEST_EMAIL - let nodeDetails = try await getFNDAndTUData(verifer: verifier, veriferID: verifierID) - var data = try await tu.getUserTypeAndAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), verifier: verifier, verifierId: verifierID) + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + var data = try await torus.getUserTypeAndAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierId: verifierID) + + XCTAssertEqual(data.finalKeyData!.evmAddress, "0x3507F0d192a44E436B8a6C32a37d57D022861b1a") + XCTAssertLessThan(data.metadata!.serverTimeOffset, 20) + XCTAssertEqual(data.oAuthKeyData?.evmAddress, "0xA3767911A84bE6907f26C572bc89426dDdDB2825") XCTAssertEqual(data.oAuthKeyData?.X, "2853f323437da98ce021d06854f4b292db433c0ad03b204ef223ac2583609a6a") XCTAssertEqual(data.oAuthKeyData?.Y, "f026b4788e23523e0c8fcbf0bdcf1c1a62c9cde8f56170309607a7a52a19f7c1") @@ -57,11 +59,15 @@ class CyanTest: XCTestCase { XCTAssertEqual(data.metadata?.nonce, BigUInt.zero) XCTAssertEqual(data.metadata?.upgraded, false) XCTAssertEqual(data.metadata?.typeOfUser, .v2) - XCTAssertEqual(data.nodesData?.nodeIndexes, []) + XCTAssertNotNil(data.nodesData) verifier = "tkey-google-cyan" verifierID = "somev2user@gmail.com" - data = try await tu.getUserTypeAndAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), verifier: verifier, verifierId: verifierID) + data = try await torus.getUserTypeAndAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierId: verifierID) + + XCTAssertEqual(data.finalKeyData!.evmAddress, "0x8EA83Ace86EB414747F2b23f03C38A34E0217814") + XCTAssertLessThan(data.metadata!.serverTimeOffset, 20) + XCTAssertEqual(data.oAuthKeyData?.evmAddress, "0x29446f428293a4E6470AEaEDa6EAfA0F842EF54e") XCTAssertEqual(data.oAuthKeyData?.X, "8b6f2048aba8c7833e3b02c5b6522bb18c484ad0025156e428f17fb8d8c34021") XCTAssertEqual(data.oAuthKeyData?.Y, "cd9ba153ff89d665f655d1be4c6912f3ff93996e6fe580d89e78bf1476fef2aa") @@ -73,11 +79,15 @@ class CyanTest: XCTestCase { XCTAssertEqual(data.metadata?.nonce, BigUInt.zero) XCTAssertEqual(data.metadata?.upgraded, false) XCTAssertEqual(data.metadata?.typeOfUser, .v2) - XCTAssertEqual(data.nodesData?.nodeIndexes, []) + XCTAssertNotNil(data.nodesData?.nodeIndexes) verifier = "tkey-google-cyan" verifierID = "caspertorus@gmail.com" - data = try await tu.getUserTypeAndAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), verifier: verifier, verifierId: verifierID) + data = try await torus.getUserTypeAndAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierId: verifierID) + + XCTAssertEqual(data.finalKeyData!.evmAddress, "0xCC1f953f6972a9e3d685d260399D6B85E2117561") + XCTAssertLessThan(data.metadata!.serverTimeOffset, 20) + XCTAssertEqual(data.oAuthKeyData?.evmAddress, "0xe8a19482cbe5FaC896A5860Ca4156fb999DDc73b") XCTAssertEqual(data.oAuthKeyData?.X, "c491ba39155594896b27cf71a804ccf493289d918f40e6ba4d590f1c76139e9e") XCTAssertEqual(data.oAuthKeyData?.Y, "d4649ed9e46461e1af00399a4c65fabb1dc219b3f4af501a7d635c17f57ab553") @@ -89,68 +99,73 @@ class CyanTest: XCTestCase { XCTAssertEqual(data.metadata?.nonce, BigUInt.zero) XCTAssertEqual(data.metadata?.upgraded, false) XCTAssertEqual(data.metadata?.typeOfUser, .v2) - XCTAssertEqual(data.nodesData?.nodeIndexes, []) + XCTAssertNotNil(data.nodesData) } - func test_key_assign() async throws { + func test_should_be_able_to_key_assign() async throws { let fakeEmail = generateRandomEmail(of: 6) let verifier: String = "tkey-google-cyan" let verifierID: String = fakeEmail - let nodeDetails = try await getFNDAndTUData(verifer: verifier, veriferID: verifierID) - let data = try await tu.getPublicAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), verifier: verifier, verifierId: verifierID) + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + let data = try await torus.getPublicAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierId: verifierID) XCTAssertNotEqual(data.finalKeyData?.evmAddress, "") XCTAssertNotEqual(data.oAuthKeyData?.evmAddress, "") XCTAssertEqual(data.metadata?.typeOfUser, .v1) XCTAssertEqual(data.metadata?.upgraded, false) } - func test_login() async throws { + func test_should_be_able_to_login() async throws { let verifier: String = TORUS_TEST_VERIFIER let verifierID: String = TORUS_TEST_EMAIL let jwt = try! generateIdToken(email: verifierID) let verifierParams = VerifierParams(verifier_id: verifierID) - let extraParams = ["verifieridentifier": verifier, "verifier_id": verifierID] as [String: Codable] - let nodeDetails = try await getFNDAndTUData(verifer: verifier, veriferID: verifierID) - let data = try await tu.retrieveShares(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), indexes: nodeDetails.getTorusIndexes(), verifier: verifier, verifierParams: verifierParams, idToken: jwt, extraParams: extraParams) - - XCTAssertEqual(data.finalKeyData?.evmAddress, "0xC615aA03Dd8C9b2dc6F7c43cBDfF2c34bBa47Ec9") - XCTAssertEqual(data.finalKeyData?.X, "e2ed6033951af2851d1bea98799e62fb1ff24b952c1faea17922684678ba42d1") - XCTAssertEqual(data.finalKeyData?.Y, "beef0efad88e81385952c0068ca48e8b9c2121be87cb0ddf18a68806db202359") - XCTAssertEqual(data.finalKeyData?.privKey, "5db51619684b32a2ff2375b4c03459d936179dfba401cb1c176b621e8a2e4ac8") - XCTAssertEqual(data.oAuthKeyData?.evmAddress, "0xC615aA03Dd8C9b2dc6F7c43cBDfF2c34bBa47Ec9") - XCTAssertEqual(data.oAuthKeyData?.X, "e2ed6033951af2851d1bea98799e62fb1ff24b952c1faea17922684678ba42d1") - XCTAssertEqual(data.oAuthKeyData?.Y, "beef0efad88e81385952c0068ca48e8b9c2121be87cb0ddf18a68806db202359") - XCTAssertEqual(data.oAuthKeyData?.privKey, "5db51619684b32a2ff2375b4c03459d936179dfba401cb1c176b621e8a2e4ac8") - XCTAssertEqual(data.sessionData?.sessionTokenData.count, 0) - XCTAssertEqual(data.sessionData?.sessionAuthKey, "") - XCTAssertEqual(data.metadata?.pubNonce, nil) - XCTAssertEqual(data.metadata?.nonce, BigUInt(0)) - XCTAssertEqual(data.metadata?.typeOfUser, .v1) - XCTAssertEqual(data.metadata?.upgraded, nil) + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + let data = try await torus.retrieveShares(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierParams: verifierParams, idToken: jwt) + + XCTAssertEqual(data.finalKeyData.evmAddress, "0xC615aA03Dd8C9b2dc6F7c43cBDfF2c34bBa47Ec9") + XCTAssertLessThan(data.metadata.serverTimeOffset, 20) + + XCTAssertEqual(data.finalKeyData.evmAddress, "0xC615aA03Dd8C9b2dc6F7c43cBDfF2c34bBa47Ec9") + XCTAssertEqual(data.finalKeyData.X, "e2ed6033951af2851d1bea98799e62fb1ff24b952c1faea17922684678ba42d1") + XCTAssertEqual(data.finalKeyData.Y, "beef0efad88e81385952c0068ca48e8b9c2121be87cb0ddf18a68806db202359") + XCTAssertEqual(data.finalKeyData.privKey, "5db51619684b32a2ff2375b4c03459d936179dfba401cb1c176b621e8a2e4ac8") + XCTAssertEqual(data.oAuthKeyData.evmAddress, "0xC615aA03Dd8C9b2dc6F7c43cBDfF2c34bBa47Ec9") + XCTAssertEqual(data.oAuthKeyData.X, "e2ed6033951af2851d1bea98799e62fb1ff24b952c1faea17922684678ba42d1") + XCTAssertEqual(data.oAuthKeyData.Y, "beef0efad88e81385952c0068ca48e8b9c2121be87cb0ddf18a68806db202359") + XCTAssertEqual(data.oAuthKeyData.privKey, "5db51619684b32a2ff2375b4c03459d936179dfba401cb1c176b621e8a2e4ac8") + XCTAssertNil(data.metadata.pubNonce) + XCTAssertEqual(data.metadata.nonce, BigUInt(0)) + XCTAssertEqual(data.metadata.typeOfUser, .v1) + XCTAssertNil(data.metadata.upgraded) + XCTAssertNotNil(data.nodesData) } - func test_aggregate_login() async throws { + func test_should_be_able_to_aggregate_login() async throws { let verifier: String = TORUS_TEST_AGGREGATE_VERIFIER let verifierID: String = TORUS_TEST_EMAIL let jwt = try! generateIdToken(email: TORUS_TEST_EMAIL) - let verifierParams = VerifierParams(verifier_id: verifierID) - let hashedIDToken = keccak256Data(jwt.data(using: .utf8) ?? Data() ).toHexString() - let extraParams = ["verifier_id": TORUS_TEST_EMAIL, "sub_verifier_ids": [TORUS_TEST_VERIFIER], "verify_params": [["verifier_id": TORUS_TEST_EMAIL, "idtoken": jwt]]] as [String: Codable] - let nodeDetails = try await getFNDAndTUData(verifer: verifier, veriferID: verifierID) - let data = try await tu.retrieveShares(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), indexes: nodeDetails.getTorusIndexes(), verifier: verifier, verifierParams: verifierParams, idToken: hashedIDToken, extraParams: extraParams) - XCTAssertEqual(data.finalKeyData?.evmAddress, "0x34117FDFEFBf1ad2DFA6d4c43804E6C710a6fB04") - XCTAssertEqual(data.finalKeyData?.X, "afd12f2476006ef6aa8778190b29676a70039df8688f9dee69c779bdc8ff0223") - XCTAssertEqual(data.finalKeyData?.Y, "e557a5ee879632727f5979d6b9cea69d87e3dab54a8c1b6685d86dfbfcd785dd") - XCTAssertEqual(data.finalKeyData?.privKey, "45a5b62c4ff5490baa75d33bf4f03ba6c5b0095678b0f4055312eef7b780b7bf") - XCTAssertEqual(data.oAuthKeyData?.evmAddress, "0x34117FDFEFBf1ad2DFA6d4c43804E6C710a6fB04") - XCTAssertEqual(data.oAuthKeyData?.X, "afd12f2476006ef6aa8778190b29676a70039df8688f9dee69c779bdc8ff0223") - XCTAssertEqual(data.oAuthKeyData?.Y, "e557a5ee879632727f5979d6b9cea69d87e3dab54a8c1b6685d86dfbfcd785dd") - XCTAssertEqual(data.oAuthKeyData?.privKey, "45a5b62c4ff5490baa75d33bf4f03ba6c5b0095678b0f4055312eef7b780b7bf") - XCTAssertEqual(data.sessionData?.sessionTokenData.count, 0) - XCTAssertEqual(data.sessionData?.sessionAuthKey, "") - XCTAssertEqual(data.metadata?.pubNonce == nil, true) - XCTAssertEqual(data.metadata?.nonce, BigUInt(0)) - XCTAssertEqual(data.metadata?.typeOfUser == UserType.v1, true) - XCTAssertEqual(data.metadata?.upgraded == nil, true) + let verifierParams = VerifierParams(verifier_id: verifierID, sub_verifier_ids: [TORUS_TEST_VERIFIER], verify_params: [VerifyParams(verifier_id: TORUS_TEST_EMAIL, idtoken: jwt)]) + let hashedIDToken = try KeyUtils.keccak256Data(jwt) + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + + let data = try await torus.retrieveShares(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierParams: verifierParams, idToken: hashedIDToken) + + XCTAssertEqual(data.finalKeyData.evmAddress, "0x34117FDFEFBf1ad2DFA6d4c43804E6C710a6fB04") + XCTAssertLessThan(data.metadata.serverTimeOffset, 20) + + XCTAssertEqual(data.finalKeyData.evmAddress, "0x34117FDFEFBf1ad2DFA6d4c43804E6C710a6fB04") + XCTAssertEqual(data.finalKeyData.X, "afd12f2476006ef6aa8778190b29676a70039df8688f9dee69c779bdc8ff0223") + XCTAssertEqual(data.finalKeyData.Y, "e557a5ee879632727f5979d6b9cea69d87e3dab54a8c1b6685d86dfbfcd785dd") + XCTAssertEqual(data.finalKeyData.privKey, "45a5b62c4ff5490baa75d33bf4f03ba6c5b0095678b0f4055312eef7b780b7bf") + XCTAssertEqual(data.oAuthKeyData.evmAddress, "0x34117FDFEFBf1ad2DFA6d4c43804E6C710a6fB04") + XCTAssertEqual(data.oAuthKeyData.X, "afd12f2476006ef6aa8778190b29676a70039df8688f9dee69c779bdc8ff0223") + XCTAssertEqual(data.oAuthKeyData.Y, "e557a5ee879632727f5979d6b9cea69d87e3dab54a8c1b6685d86dfbfcd785dd") + XCTAssertEqual(data.oAuthKeyData.privKey, "45a5b62c4ff5490baa75d33bf4f03ba6c5b0095678b0f4055312eef7b780b7bf") + XCTAssertNotNil(data.sessionData) + XCTAssertNil(data.metadata.pubNonce) + XCTAssertEqual(data.metadata.nonce, BigUInt(0)) + XCTAssertEqual(data.metadata.typeOfUser, .v1) + XCTAssertNil(data.metadata.upgraded) + XCTAssertNotNil(data.nodesData) } } diff --git a/Tests/TorusUtilsTests/Utils/JWTUtils.swift b/Tests/TorusUtilsTests/Helpers/JWTUtils.swift similarity index 76% rename from Tests/TorusUtilsTests/Utils/JWTUtils.swift rename to Tests/TorusUtilsTests/Helpers/JWTUtils.swift index 8a9e2a67..fe4c066c 100644 --- a/Tests/TorusUtilsTests/Utils/JWTUtils.swift +++ b/Tests/TorusUtilsTests/Helpers/JWTUtils.swift @@ -12,6 +12,7 @@ struct TestPayload: JWTPayload, Equatable { case iat case email case audience = "aud" + case name } var subject: SubjectClaim @@ -22,6 +23,7 @@ struct TestPayload: JWTPayload, Equatable { var issuer: IssuerClaim var iat: IssuedAtClaim var email: String + var name: String // call its verify method. func verify(using signer: JWTSigner) throws { @@ -53,12 +55,21 @@ func generateIdToken(email: String) throws -> String { // Parses the JWT and verifies its signature. let today = Date() - let modifiedDate = Calendar.current.date(byAdding: .hour, value: 1, to: today)! + let modifiedDate = Calendar.current.date(byAdding: .minute, value: 2, to: today)! let emailComponent = email.components(separatedBy: "@")[0] let subject = "email|" + emailComponent - let payload = TestPayload(subject: SubjectClaim(stringLiteral: subject), expiration: ExpirationClaim(value: modifiedDate), audience: "torus-key-test", isAdmin: false, emailVerified: true, issuer: "torus-key-test", iat: IssuedAtClaim(value: Date()), email: email) + let payload = TestPayload( + subject: SubjectClaim(stringLiteral: subject), + expiration: ExpirationClaim(value: modifiedDate), // eat + audience: "torus-key-test", + isAdmin: false, + emailVerified: true, + issuer: "torus-key-test", + iat: IssuedAtClaim(value: today), + email: email, + name: email) let jwt = try signers.sign(payload) return jwt } catch { diff --git a/Tests/TorusUtilsTests/IntegrationTest.swift b/Tests/TorusUtilsTests/IntegrationTest.swift deleted file mode 100644 index 8617d165..00000000 --- a/Tests/TorusUtilsTests/IntegrationTest.swift +++ /dev/null @@ -1,129 +0,0 @@ -import BigInt -import FetchNodeDetails -import JWTKit -import XCTest - -@testable import TorusUtils - -class IntegrationTests: XCTestCase { - static var fetchNodeDetails: AllNodeDetailsModel? - // static var nodeDetails: NodeDetails? - static var utils: TorusUtils? - static var endpoints: [String] = [] - static var nodePubKeys: [TorusNodePubModel] = [] - static var privKey: String = "" - - let TORUS_TEST_VERIFIER = "torus-test-health" - let TORUS_TEST_AGGREGATE_VERIFIER = "torus-test-health-aggregate" - let TORUS_TEST_EMAIL = "hello@tor.us" - - // Fake data - let TORUS_TEST_VERIFIER_FAKE = "google-lrc-fakes" - var fnd: NodeDetailManager! - var tu: TorusUtils! - - override func setUp() { - super.setUp() - fnd = NodeDetailManager(network: .legacy(.TESTNET)) - } - - override func setUpWithError() throws { - continueAfterFailure = false - } - - func get_fnd_and_tu_data(verifer: String, veriferID: String, enableOneKey: Bool = false) async throws -> AllNodeDetailsModel { - let nodeDetails = try await fnd.getNodeDetails(verifier: verifer, verifierID: veriferID) - tu = TorusUtils(enableOneKey: enableOneKey, network: .legacy(.TESTNET), clientId: "YOUR_CLIENT_ID") - return nodeDetails - } - - func test_getPublicAddress() async throws { - var nodeDetails = try await get_fnd_and_tu_data(verifer: "google-lrc", veriferID: TORUS_TEST_EMAIL) - let data = try await tu.getPublicAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), verifier: "google-lrc", verifierId: "hello@tor.us") - XCTAssertEqual(data.finalKeyData?.evmAddress, "0x872eEfa7495599A6983d396fE8dcf542457CF33f") - - do { - nodeDetails = try await get_fnd_and_tu_data(verifer: TORUS_TEST_VERIFIER_FAKE, veriferID: TORUS_TEST_EMAIL) - _ = try await tu.getPublicAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), verifier: TORUS_TEST_VERIFIER_FAKE, verifierId: TORUS_TEST_EMAIL) - } catch _ { - } - } - - func test_getUserTypeAndAddress() async throws { - let verifier: String = "tkey-google-lrc" - let verifierID: String = "somev2user@gmail.com" - let nodeDetails = try await get_fnd_and_tu_data(verifer: TORUS_TEST_VERIFIER, veriferID: TORUS_TEST_EMAIL) - let val = try await tu.getUserTypeAndAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), verifier: verifier, verifierId: verifierID) - - XCTAssertEqual(val.finalKeyData?.evmAddress, "0xE91200d82029603d73d6E307DbCbd9A7D0129d8D") - } - -/* TODO: Investigate this further - func test_keyAssign() async throws { - let email = generateRandomEmail(of: 6) - - let nodeDetails = try await get_fnd_and_tu_data(verifer: "google-lrc", veriferID: email) - let val = try await tu.keyAssign(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), verifier: TORUS_TEST_VERIFIER, verifierId: email, signerHost: tu.signerHost, network: .legacy(.TESTNET)) - guard let result = val.result as? [String: Any] else { - throw TorusUtilError.empty - } - let keys = result["keys"] as! [[String: String]] - _ = keys[0]["address"] - - // Add more check to see if address is valid - } -*/ - - func test_keyLookup() async throws { - let nodeDetails = try await get_fnd_and_tu_data(verifer: TORUS_TEST_VERIFIER, veriferID: TORUS_TEST_EMAIL) - let val = try await tu.keyLookup(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: "google-lrc", verifierId: TORUS_TEST_EMAIL) - XCTAssertEqual(val.address, "0x872eEfa7495599A6983d396fE8dcf542457CF33f") - - do { - let nodeDetails = try await get_fnd_and_tu_data(verifer: TORUS_TEST_VERIFIER, veriferID: TORUS_TEST_EMAIL) - _ = try await tu.keyLookup(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: "google-lrc-fake", verifierId: TORUS_TEST_EMAIL) - XCTFail() - } catch let error { - if let keylookupError = error as? KeyLookupError { - XCTAssertEqual(keylookupError, KeyLookupError.verifierNotSupported) - } - } - } - - // MARK: Aggregate tests - - func test_getPublicAddressAggregateLogin() async throws { - let nodeDetails = try await get_fnd_and_tu_data(verifer: TORUS_TEST_VERIFIER, veriferID: TORUS_TEST_EMAIL) - let val = try await tu.getPublicAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), verifier: TORUS_TEST_AGGREGATE_VERIFIER, verifierId: TORUS_TEST_EMAIL) - XCTAssertEqual(val.finalKeyData?.evmAddress, "0x5a165d2Ed4976BD104caDE1b2948a93B72FA91D2") - } - - /* TODO: Investigate this test further - func test_keyAssignAggregateLogin() async throws { - let email = generateRandomEmail(of: 6) - - let nodeDetails = try await get_fnd_and_tu_data(verifer: TORUS_TEST_VERIFIER, veriferID: TORUS_TEST_EMAIL) - let val = try await tu.keyAssign(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), verifier: TORUS_TEST_AGGREGATE_VERIFIER, verifierId: email, signerHost: signerHost, network: .legacy(.TESTNET)) - guard let result = val.result as? [String: Any] else { - throw TorusUtilError.empty - } - let keys = result["keys"] as! [[String: String]] - _ = keys[0]["address"] - - // Add more check to see if address is valid - } - */ - - func test_keyLookupAggregateLogin() async throws { - let nodeDetails = try await get_fnd_and_tu_data(verifer: TORUS_TEST_VERIFIER, veriferID: TORUS_TEST_EMAIL) - let val = try await tu.keyLookup(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: TORUS_TEST_AGGREGATE_VERIFIER, verifierId: TORUS_TEST_EMAIL) - XCTAssertEqual(val.address, "0x5a165d2Ed4976BD104caDE1b2948a93B72FA91D2") - } -} - -extension IntegrationTests {} - -struct ROPSTEN_CONSTANTS { - static let endpoints = ["https://teal-15-1.torusnode.com/jrpc", "https://teal-15-3.torusnode.com/jrpc", "https://teal-15-4.torusnode.com/jrpc", "https://teal-15-5.torusnode.com/jrpc", "https://teal-15-2.torusnode.com/jrpc"] - static let nodePubKeys = [TorusNodePubModel(_X: "1363aad8868cacd7f8946c590325cd463106fb3731f08811ab4302d2deae35c3", _Y: "d77eebe5cdf466b475ec892d5b4cffbe0c1670525debbd97eee6dae2f87a7cbe"), TorusNodePubModel(_X: "7c8cc521c48690f016bea593f67f88ad24f447dd6c31bbab541e59e207bf029d", _Y: "b359f0a82608db2e06b953b36d0c9a473a00458117ca32a5b0f4563a7d539636"), TorusNodePubModel(_X: "8a86543ca17df5687719e2549caa024cf17fe0361e119e741eaee668f8dd0a6f", _Y: "9cdb254ff915a76950d6d13d78ef054d5d0dc34e2908c00bb009a6e4da701891"), TorusNodePubModel(_X: "25a98d9ae006aed1d77e81d58be8f67193d13d01a9888e2923841894f4b0bf9c", _Y: "f63d40df480dacf68922004ed36dbab9e2969181b047730a5ce0797fb6958249"), TorusNodePubModel(_X: "d908f41f8e06324a8a7abcf702adb6a273ce3ae63d86a3d22723e1bbf1438c9a", _Y: "f977530b3ec0e525438c72d1e768380cbc5fb3b38a760ee925053b2e169428ce")] -} diff --git a/Tests/TorusUtilsTests/MainnetTest.swift b/Tests/TorusUtilsTests/MainnetTest.swift index 3c42bd74..2c2382b8 100644 --- a/Tests/TorusUtilsTests/MainnetTest.swift +++ b/Tests/TorusUtilsTests/MainnetTest.swift @@ -1,13 +1,11 @@ import BigInt import FetchNodeDetails import JWTKit +import TorusUtils import XCTest -@testable import TorusUtils - class MainnetTests: XCTestCase { static var fetchNodeDetails: AllNodeDetailsModel? - // static var nodeDetails: NodeDetails? static var utils: TorusUtils? static var endpoints: [String] = [] static var nodePubKeys: [TorusNodePubModel] = [] @@ -16,28 +14,25 @@ class MainnetTests: XCTestCase { let TORUS_TEST_VERIFIER = "torus-test-health" let TORUS_TEST_AGGREGATE_VERIFIER = "torus-test-health-aggregate" let TORUS_TEST_EMAIL = "hello@tor.us" - var signerHost = "https://signer.tor.us/api/sign" - var allowHost = "https://signer.tor.us/api/allow" - // Fake data - let TORUS_TEST_VERIFIER_FAKE = "google-lrc-fakes" var fnd: NodeDetailManager! - var tu: TorusUtils! + var torus: TorusUtils! override func setUp() { super.setUp() fnd = NodeDetailManager(network: .legacy(.MAINNET)) + torus = try! TorusUtils(params: TorusOptions(clientId: "YOUR_CLIENT_ID", network: .legacy(.MAINNET))) } - func get_fnd_and_tu_data(verifer: String, veriferID: String, enableOneKey: Bool = false) async throws -> AllNodeDetailsModel { - let nodeDetails = try await fnd.getNodeDetails(verifier: verifer, verifierID: veriferID) - tu = TorusUtils(enableOneKey: enableOneKey, network: .legacy(.MAINNET), clientId: "YOUR_CLIENT_ID") - return nodeDetails - } + func test_should_fetch_public_address() async throws { + let verifier = "google" + let verifierID = TORUS_TEST_EMAIL + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + let val = try await torus.getPublicAddress(endpoints: nodeDetails.torusNodeEndpoints, verifier: verifier, verifierId: verifierID) + + XCTAssertEqual(val.finalKeyData!.evmAddress, "0x0C44AFBb5395a9e8d28DF18e1326aa0F16b9572A") + XCTAssertLessThan(val.metadata!.serverTimeOffset, 20) - func test_get_public_address() async throws { - let nodeDetails = try await get_fnd_and_tu_data(verifer: "google", veriferID: TORUS_TEST_EMAIL) - let val = try await tu.getPublicAddress(endpoints: nodeDetails.torusNodeEndpoints, torusNodePubs: nodeDetails.torusNodePub, verifier: "google", verifierId: TORUS_TEST_EMAIL) XCTAssertEqual(val.finalKeyData!.evmAddress, "0x0C44AFBb5395a9e8d28DF18e1326aa0F16b9572A") XCTAssertEqual(val.finalKeyData!.X, "3b5655d78978b6fd132562b5cb66b11bcd868bd2a9e16babe4a1ca50178e57d4") XCTAssertEqual(val.finalKeyData!.Y, "15338510798d6b55db28c121d86babcce19eb9f1882f05fae8ee9b52ed09e8f1") @@ -47,30 +42,38 @@ class MainnetTests: XCTestCase { XCTAssertNil(val.metadata?.pubNonce) XCTAssertEqual(val.metadata?.nonce, 0) XCTAssertEqual(val.metadata?.upgraded, false) - XCTAssertEqual(val.metadata?.typeOfUser, UserType(rawValue: "v1")) + XCTAssertEqual(val.metadata?.typeOfUser, .v1) + XCTAssertNotNil(val.nodesData) } - func test_fetch_user_type_and_addresses() async throws { - let verifier1: String = "google" - let verifierID1: String = TORUS_TEST_EMAIL - let nodeDetails = try await get_fnd_and_tu_data(verifer: TORUS_TEST_VERIFIER, veriferID: TORUS_TEST_EMAIL) - var val = try await tu.getUserTypeAndAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), verifier: verifier1, verifierId: verifierID1) + func test_should_fetch_user_type_and_public_address() async throws { + var verifier: String = "google" + var verifierID: String = TORUS_TEST_EMAIL + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + var val = try await torus.getUserTypeAndAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierId: verifierID) XCTAssertEqual(val.finalKeyData!.evmAddress, "0xb2e1c3119f8D8E73de7eaF7A535FB39A3Ae98C5E") - XCTAssertEqual(val.finalKeyData!.X, "072beda348a832aed06044a258cb6a8d428ec7c245c5da92db5da4f3ab433e55") - XCTAssertEqual(val.finalKeyData!.Y, "54ace0d3df2504fa29f17d424a36a0f92703899fad0afee93d010f6d84b310e5") + XCTAssertLessThan(val.metadata!.serverTimeOffset, 20) + + XCTAssertEqual(val.finalKeyData!.evmAddress, "0xb2e1c3119f8D8E73de7eaF7A535FB39A3Ae98C5E") + XCTAssertEqual(val.oAuthKeyData!.evmAddress, "0x0C44AFBb5395a9e8d28DF18e1326aa0F16b9572A") XCTAssertEqual(val.oAuthKeyData!.X, "3b5655d78978b6fd132562b5cb66b11bcd868bd2a9e16babe4a1ca50178e57d4") XCTAssertEqual(val.oAuthKeyData!.Y, "15338510798d6b55db28c121d86babcce19eb9f1882f05fae8ee9b52ed09e8f1") + XCTAssertEqual(val.finalKeyData!.X, "072beda348a832aed06044a258cb6a8d428ec7c245c5da92db5da4f3ab433e55") + XCTAssertEqual(val.finalKeyData!.Y, "54ace0d3df2504fa29f17d424a36a0f92703899fad0afee93d010f6d84b310e5") XCTAssertEqual(val.metadata!.pubNonce!.x, "eb22d93244acf7fcbeb6566da722bc9c8e5433cd28da25ca0650d9cb32806c39") XCTAssertEqual(val.metadata!.pubNonce!.y, "765541e214f067cfc44dcf41e582ae09b71c2e607a301cc8a45e1f316a6ba91c") XCTAssertEqual(val.metadata?.nonce, 0) XCTAssertEqual(val.metadata?.upgraded, false) XCTAssertEqual(val.metadata?.typeOfUser, .v2) - let verifier2: String = "tkey-google" - let verifierID2: String = "somev2user@gmail.com" - val = try await tu.getUserTypeAndAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), verifier: verifier2, verifierId: verifierID2) + verifier = "tkey-google" + verifierID = "somev2user@gmail.com" + val = try await torus.getUserTypeAndAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierId: verifierID) + + XCTAssertEqual(val.finalKeyData!.evmAddress, "0xFf669A15bFFcf32D3C5B40bE9E5d409d60D43526") + XCTAssertLessThan(val.metadata!.serverTimeOffset, 20) XCTAssertEqual(val.oAuthKeyData!.evmAddress, "0xA9c6829e4899b6D630130ebf59D046CA868D7f83") XCTAssertEqual(val.oAuthKeyData!.X, "5566cd940ea540ba1a3ba2ff0f5fd3d9a3a74350ac3baf47b811592ae6ea1c30") @@ -82,92 +85,95 @@ class MainnetTests: XCTestCase { XCTAssertEqual(val.metadata?.pubNonce?.y, "da3aed7f7e9d612052beb1d92ec68a8dcf60faf356985435b424af2423f66672") XCTAssertEqual(val.metadata?.nonce, 0) XCTAssertEqual(val.metadata?.upgraded, false) - XCTAssertEqual(val.metadata?.typeOfUser, UserType(rawValue: "v2")) + XCTAssertEqual(val.metadata?.typeOfUser, .v2) + XCTAssertNotNil(val.nodesData) - let verifier3: String = "tkey-google" - let verifierID3: String = "caspertorus@gmail.com" - val = try await tu.getUserTypeAndAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), verifier: verifier3, verifierId: verifierID3) + verifier = "tkey-google" + verifierID = "caspertorus@gmail.com" + val = try await torus.getUserTypeAndAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierId: verifierID) XCTAssertEqual(val.finalKeyData!.evmAddress, "0x40A4A04fDa1f29a3667152C8830112FBd6A77BDD") - XCTAssertEqual(val.finalKeyData!.X, "6779af3031d9e9eec6b4133b0ae13e367c83a614f92d2008e10c7f3b8e6723bc") - XCTAssertEqual(val.finalKeyData!.Y, "80edc4502abdfb220dd6e2fcfa2dbb058125dc95873e4bfa6877f9c26da7fdff") + XCTAssertLessThan(val.metadata!.serverTimeOffset, 20) + XCTAssertEqual(val.oAuthKeyData!.evmAddress, "0x61E52B6e488EC3dD6FDc0F5ed04a62Bb9c6BeF53") XCTAssertEqual(val.oAuthKeyData!.X, "c01282dd68d2341031a1cff06f70d821cad45140f425f1c25055a8aa64959df8") XCTAssertEqual(val.oAuthKeyData!.Y, "cb3937773bb819d60b780b6d4c2edcf27c0f7090ba1fc2ff42504a8138a8e2d7") + XCTAssertEqual(val.finalKeyData!.evmAddress, "0x40A4A04fDa1f29a3667152C8830112FBd6A77BDD") + XCTAssertEqual(val.finalKeyData!.X, "6779af3031d9e9eec6b4133b0ae13e367c83a614f92d2008e10c7f3b8e6723bc") + XCTAssertEqual(val.finalKeyData!.Y, "80edc4502abdfb220dd6e2fcfa2dbb058125dc95873e4bfa6877f9c26da7fdff") XCTAssertEqual(val.metadata?.pubNonce?.x, "16214bf232167258fb5f98fa9d84968ffec3236aaf0994fc366940c4bc07a5b1") XCTAssertEqual(val.metadata?.pubNonce?.y, "475e8c09d2cc8f6c12a767f51c052b1bf8e8d3a2a2b6818d4b199dc283e80ac4") XCTAssertEqual(val.metadata?.nonce, 0) XCTAssertEqual(val.metadata?.upgraded, false) XCTAssertEqual(val.metadata?.typeOfUser, .v2) + XCTAssertNotNil(val.nodesData) } - func test_key_assign() async throws { - let email = generateRandomEmail(of: 6) - let nodeDetails = try await get_fnd_and_tu_data(verifer: "google", veriferID: email) - let val = try await tu.keyAssign(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), verifier: TORUS_TEST_VERIFIER, verifierId: email, signerHost: tu.signerHost, network: .legacy(.MAINNET)) - guard let result = val.result as? [String: Any] else { - throw TorusUtilError.empty - } - let keys = result["keys"] as! [[String: String]] - _ = keys[0]["address"] - - // Add more check to see if address is valid + func test_should_be_able_to_key_assign() async throws { + let fakeEmail = generateRandomEmail(of: 6) + let verifier: String = "google" + let verifierID: String = fakeEmail + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + let data = try await torus.getPublicAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierId: verifierID) + XCTAssertNotEqual(data.finalKeyData?.evmAddress, "") + XCTAssertNotEqual(data.oAuthKeyData?.evmAddress, "") + XCTAssertEqual(data.metadata?.typeOfUser, .v1) + XCTAssertEqual(data.metadata?.upgraded, false) } - func test_login() async throws { - let jwt = try! generateIdToken(email: TORUS_TEST_EMAIL) - let verifierParams = VerifierParams(verifier_id: TORUS_TEST_EMAIL) - let extraParams = ["verifieridentifier": TORUS_TEST_VERIFIER, "verifier_id": TORUS_TEST_EMAIL] as [String: Codable] - let nodeDetails = try await get_fnd_and_tu_data(verifer: TORUS_TEST_VERIFIER, veriferID: TORUS_TEST_EMAIL) - let data = try await tu.retrieveShares( - endpoints: nodeDetails.getTorusNodeEndpoints(), - torusNodePubs: nodeDetails.getTorusNodePub(), - indexes: nodeDetails.getTorusIndexes(), - verifier: TORUS_TEST_VERIFIER, - verifierParams: verifierParams, - idToken: jwt, - extraParams: extraParams) - - XCTAssertEqual(data.finalKeyData?.evmAddress, "0x90A926b698047b4A87265ba1E9D8b512E8489067") - XCTAssertEqual(data.finalKeyData?.X, "a92d8bf1f01ad62e189a5cb0f606b89aa6df1b867128438c38e3209f3b9fc34f") - XCTAssertEqual(data.finalKeyData?.Y, "0ad1ffaecb2178b02a37c455975368be9b967ead1b281202cc8d48c77618bff1") - XCTAssertEqual(data.finalKeyData?.privKey, "0129494416ab5d5f674692b39fa49680e07d3aac01b9683ee7650e40805d4c44") - XCTAssertEqual(data.oAuthKeyData?.evmAddress, "0x90A926b698047b4A87265ba1E9D8b512E8489067") - XCTAssertEqual(data.oAuthKeyData?.X, "a92d8bf1f01ad62e189a5cb0f606b89aa6df1b867128438c38e3209f3b9fc34f") - XCTAssertEqual(data.oAuthKeyData?.Y, "0ad1ffaecb2178b02a37c455975368be9b967ead1b281202cc8d48c77618bff1") - XCTAssertEqual(data.oAuthKeyData?.privKey, "0129494416ab5d5f674692b39fa49680e07d3aac01b9683ee7650e40805d4c44") - XCTAssertEqual(data.sessionData?.sessionTokenData.count, 0) - XCTAssertEqual(data.sessionData?.sessionAuthKey, "") - XCTAssertEqual(data.metadata?.pubNonce, nil) - XCTAssertEqual(data.metadata?.nonce, BigUInt(0)) - XCTAssertEqual(data.metadata?.typeOfUser, .v1) - XCTAssertEqual(data.metadata?.upgraded, nil) + func test_should_be_able_to_login() async throws { + let verifier: String = TORUS_TEST_VERIFIER + let verifierID: String = TORUS_TEST_EMAIL + let jwt = try! generateIdToken(email: verifierID) + let verifierParams = VerifierParams(verifier_id: verifierID) + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + let data = try await torus.retrieveShares(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierParams: verifierParams, idToken: jwt) + + XCTAssertEqual(data.finalKeyData.evmAddress, "0x90A926b698047b4A87265ba1E9D8b512E8489067") + XCTAssertLessThan(data.metadata.serverTimeOffset, 20) + + XCTAssertEqual(data.oAuthKeyData.evmAddress, "0x90A926b698047b4A87265ba1E9D8b512E8489067") + XCTAssertEqual(data.oAuthKeyData.X, "a92d8bf1f01ad62e189a5cb0f606b89aa6df1b867128438c38e3209f3b9fc34f") + XCTAssertEqual(data.oAuthKeyData.Y, "0ad1ffaecb2178b02a37c455975368be9b967ead1b281202cc8d48c77618bff1") + XCTAssertEqual(data.oAuthKeyData.privKey, "0129494416ab5d5f674692b39fa49680e07d3aac01b9683ee7650e40805d4c44") + XCTAssertEqual(data.finalKeyData.evmAddress, "0x90A926b698047b4A87265ba1E9D8b512E8489067") + XCTAssertEqual(data.finalKeyData.X, "a92d8bf1f01ad62e189a5cb0f606b89aa6df1b867128438c38e3209f3b9fc34f") + XCTAssertEqual(data.finalKeyData.Y, "0ad1ffaecb2178b02a37c455975368be9b967ead1b281202cc8d48c77618bff1") + XCTAssertEqual(data.finalKeyData.privKey, "0129494416ab5d5f674692b39fa49680e07d3aac01b9683ee7650e40805d4c44") + XCTAssertNotNil(data.sessionData) + XCTAssertNil(data.metadata.pubNonce) + XCTAssertEqual(data.metadata.nonce, BigUInt(0)) + XCTAssertEqual(data.metadata.typeOfUser, .v1) + XCTAssertNil(data.metadata.upgraded) + XCTAssertNotNil(data.nodesData) } - func test_aggregate_login() async throws { + func test_should_be_able_to_aggregate_login() async throws { let verifier: String = TORUS_TEST_AGGREGATE_VERIFIER let verifierID: String = TORUS_TEST_EMAIL let jwt = try! generateIdToken(email: TORUS_TEST_EMAIL) - let hashedIDToken = keccak256Data(jwt.data(using: .utf8) ?? Data()).toHexString() - let extraParams = ["verifier_id": TORUS_TEST_EMAIL, "sub_verifier_ids": [TORUS_TEST_VERIFIER], "verify_params": [["verifier_id": TORUS_TEST_EMAIL, "idtoken": jwt]]] as [String: Codable] - let verifierParams = VerifierParams(verifier_id: verifierID) - let nodeDetails = try await get_fnd_and_tu_data(verifer: verifier, veriferID: verifierID) - - let data = try await tu.retrieveShares(endpoints: nodeDetails.torusNodeEndpoints, torusNodePubs: nodeDetails.torusNodePub, indexes: nodeDetails.getTorusIndexes(), verifier: verifier, verifierParams: verifierParams, idToken: hashedIDToken, extraParams: extraParams) - - XCTAssertEqual(data.finalKeyData?.evmAddress, "0x621a4d458cFd345dAE831D9E756F10cC40A50381") - XCTAssertEqual(data.finalKeyData?.X, "52abc69ebec21deacd273dbdcb4d40066b701177bba906a187676e3292e1e236") - XCTAssertEqual(data.finalKeyData?.Y, "5e57e251db2c95c874f7ec852439302a62ef9592c8c50024e3d48018a6f77c7e") - XCTAssertEqual(data.finalKeyData?.privKey, "f55d89088a0c491d797c00da5b2ed6dc9c269c960ff121e45f255d06a91c6534") - XCTAssertEqual(data.oAuthKeyData?.evmAddress, "0x621a4d458cFd345dAE831D9E756F10cC40A50381") - XCTAssertEqual(data.oAuthKeyData?.X, "52abc69ebec21deacd273dbdcb4d40066b701177bba906a187676e3292e1e236") - XCTAssertEqual(data.oAuthKeyData?.Y, "5e57e251db2c95c874f7ec852439302a62ef9592c8c50024e3d48018a6f77c7e") - XCTAssertEqual(data.oAuthKeyData?.privKey, "f55d89088a0c491d797c00da5b2ed6dc9c269c960ff121e45f255d06a91c6534") - XCTAssertEqual(data.sessionData?.sessionTokenData.count, 0) - XCTAssertEqual(data.sessionData?.sessionAuthKey, "") - XCTAssertEqual(data.metadata?.pubNonce, nil) - XCTAssertEqual(data.metadata?.nonce, BigUInt(0)) - XCTAssertEqual(data.metadata?.typeOfUser, .v1) - XCTAssertEqual(data.metadata?.upgraded, nil) + let hashedIDToken = try KeyUtils.keccak256Data(jwt) + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + + let verifierParams = VerifierParams(verifier_id: verifierID, sub_verifier_ids: [TORUS_TEST_VERIFIER], verify_params: [VerifyParams(verifier_id: verifierID, idtoken: jwt)]) + let data = try await torus.retrieveShares(endpoints: nodeDetails.torusNodeEndpoints, verifier: verifier, verifierParams: verifierParams, idToken: hashedIDToken) + + XCTAssertEqual(data.finalKeyData.evmAddress, "0x621a4d458cFd345dAE831D9E756F10cC40A50381") + XCTAssertLessThan(data.metadata.serverTimeOffset, 20) + + XCTAssertEqual(data.oAuthKeyData.evmAddress, "0x621a4d458cFd345dAE831D9E756F10cC40A50381") + XCTAssertEqual(data.oAuthKeyData.X, "52abc69ebec21deacd273dbdcb4d40066b701177bba906a187676e3292e1e236") + XCTAssertEqual(data.oAuthKeyData.Y, "5e57e251db2c95c874f7ec852439302a62ef9592c8c50024e3d48018a6f77c7e") + XCTAssertEqual(data.oAuthKeyData.privKey, "f55d89088a0c491d797c00da5b2ed6dc9c269c960ff121e45f255d06a91c6534") + XCTAssertEqual(data.finalKeyData.evmAddress, "0x621a4d458cFd345dAE831D9E756F10cC40A50381") + XCTAssertEqual(data.finalKeyData.X, "52abc69ebec21deacd273dbdcb4d40066b701177bba906a187676e3292e1e236") + XCTAssertEqual(data.finalKeyData.Y, "5e57e251db2c95c874f7ec852439302a62ef9592c8c50024e3d48018a6f77c7e") + XCTAssertEqual(data.finalKeyData.privKey, "f55d89088a0c491d797c00da5b2ed6dc9c269c960ff121e45f255d06a91c6534") + XCTAssertNotNil(data.sessionData) + XCTAssertNil(data.metadata.pubNonce) + XCTAssertEqual(data.metadata.nonce, BigUInt(0)) + XCTAssertEqual(data.metadata.typeOfUser, .v1) + XCTAssertNil(data.metadata.upgraded) + XCTAssertNotNil(data.nodesData) } } diff --git a/Tests/TorusUtilsTests/SapphireDevnetTest.swift b/Tests/TorusUtilsTests/SapphireDevnetTest.swift new file mode 100644 index 00000000..900c2b3b --- /dev/null +++ b/Tests/TorusUtilsTests/SapphireDevnetTest.swift @@ -0,0 +1,307 @@ +import BigInt +import curveSecp256k1 +import FetchNodeDetails +import JWTKit +import TorusUtils +import XCTest + +final class SapphireDevnetTest: XCTestCase { + let TORUS_TEST_VERIFIER = "torus-test-health" + let TORUS_TEST_AGGREGATE_VERIFIER = "torus-test-health-aggregate" + + let TORUS_TEST_EMAIL = "devnettestuser@tor.us" + let TORUS_HASH_ENABLED_TEST_EMAIL = "saasas@tr.us" + let TORUS_IMPORT_EMAIL = "Sydnie.Lehner73@yahoo.com" + let TORUS_EXTENDED_VERIFIER_EMAIL = "testextenderverifierid@example.com" + let HASH_ENABLED_VERIFIER = "torus-test-verifierid-hash" + + var fnd: NodeDetailManager! + var torus: TorusUtils! + + override func setUp() { + super.setUp() + fnd = NodeDetailManager(network: .sapphire(.SAPPHIRE_DEVNET)) + torus = try! TorusUtils(params: TorusOptions(clientId: "YOUR_CLIENT_ID", network: .sapphire(.SAPPHIRE_DEVNET))) + } + + func test_should_fetch_public_address() async throws { + let verifier = TORUS_TEST_VERIFIER + let verifierID = TORUS_TEST_EMAIL + + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + + let val = try await torus.getPublicAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierId: verifierID) + + XCTAssertEqual(val.oAuthKeyData!.evmAddress, "0x137B3607958562D03Eb3C6086392D1eFa01aA6aa") + XCTAssertEqual(val.oAuthKeyData!.X, "118a674da0c68f16a1123de9611ba655f4db1e336fe1b2d746028d65d22a3c6b") + XCTAssertEqual(val.oAuthKeyData!.Y, "8325432b3a3418d632b4fe93db094d6d83250eea60fe512897c0ad548737f8a5") + XCTAssertEqual(val.finalKeyData!.evmAddress, "0x462A8BF111A55C9354425F875F89B22678c0Bc44") + XCTAssertEqual(val.finalKeyData!.X, "36e257717f746cdd52ba85f24f7c9040db8977d3b0354de70ed43689d24fa1b1") + XCTAssertEqual(val.finalKeyData!.Y, "58ec9768c2fe871b3e2a83cdbcf37ba6a88ad19ec2f6e16a66231732713fd507") + XCTAssertEqual(val.metadata?.pubNonce?.x, "5d03a0df9b3db067d3363733df134598d42873bb4730298a53ee100975d703cc") + XCTAssertEqual(val.metadata?.pubNonce?.y, "279434dcf0ff22f077877a70bcad1732412f853c96f02505547f7ca002b133ed") + XCTAssertEqual(val.metadata?.nonce, BigUInt(0)) + XCTAssertEqual(val.metadata?.upgraded, false) + XCTAssertEqual(val.metadata?.typeOfUser, .v2) + XCTAssertNotNil(val.nodesData) + } + + func test_should_be_able_to_import_key_for_a_new_user() async throws { + let fakeEmail = generateRandomEmail(of: 6) + var jwt = try generateIdToken(email: fakeEmail) + let privateKey = try KeyUtils.generateSecret() + + let verifier = TORUS_TEST_VERIFIER + let verifierID = fakeEmail + + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + + let verifierParams = VerifierParams(verifier_id: verifierID) + + let val = try await torus.importPrivateKey(endpoints: nodeDetails.getTorusNodeSSSEndpoints(), nodeIndexes: nodeDetails.getTorusIndexes(), nodePubKeys: nodeDetails.getTorusNodePub(), verifier: verifier, verifierParams: verifierParams, idToken: jwt, newPrivateKey: privateKey) + XCTAssertEqual(val.finalKeyData.privKey, privateKey) + + jwt = try generateIdToken(email: fakeEmail) + let shareRetrieval = try await torus.retrieveShares(endpoints: nodeDetails.getTorusNodeSSSEndpoints(), verifier: verifier, verifierParams: verifierParams, idToken: jwt) + XCTAssertEqual(shareRetrieval.finalKeyData.privKey, privateKey) + + let addressRetrieval = try await torus.getPublicAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierId: verifierID) + let publicAddress = try SecretKey(hex: privateKey).toPublic().serialize(compressed: false) + let retrievedAddress = KeyUtils.getPublicKeyFromCoords(pubKeyX: addressRetrieval.finalKeyData!.X, pubKeyY: addressRetrieval.finalKeyData!.Y) + XCTAssertEqual(publicAddress, retrievedAddress) + } + + func test_should_be_able_to_key_assign() async throws { + let fakeEmail = generateRandomEmail(of: 6) + let verifier = TORUS_TEST_VERIFIER + let verifierID = fakeEmail + + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + + let data = try await torus.getPublicAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierId: verifierID) + + XCTAssertNotEqual(data.finalKeyData?.evmAddress, "") + XCTAssertNotEqual(data.oAuthKeyData?.evmAddress, "") + XCTAssertEqual(data.metadata?.typeOfUser, .v2) + XCTAssertEqual(data.metadata?.upgraded, false) + } + + func test_should_be_able_to_key_assign_to_tss_verifier_id() async throws { + let fakeEmail = generateRandomEmail(of: 6) + let nonce = 0 + let tssTag = "default" + let tssVerifierID: String = fakeEmail + "\u{0015}" + tssTag + "\u{0016}" + String(nonce) + let verifier = TORUS_TEST_VERIFIER + let verifierID = fakeEmail + + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + + let data = try await torus.getPublicAddress(endpoints: nodeDetails.getTorusNodeSSSEndpoints(), verifier: verifier, verifierId: verifierID, extendedVerifierId: tssVerifierID) + + XCTAssertNotEqual(data.finalKeyData?.evmAddress, "") + XCTAssertNotEqual(data.oAuthKeyData?.evmAddress, "") + XCTAssertEqual(data.metadata?.typeOfUser, .v2) + XCTAssertEqual(data.metadata?.upgraded, false) + } + + func test_should_fetch_public_address_of_tss_verifier_id() async throws { + let email = TORUS_EXTENDED_VERIFIER_EMAIL + let nonce = 0 + let tssTag = "default" + let tssVerifierID: String = email + "\u{0015}" + tssTag + "\u{0016}" + String(nonce) + let verifier = TORUS_TEST_VERIFIER + let verifierID = email + + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + + let val = try await torus.getPublicAddress(endpoints: nodeDetails.getTorusNodeSSSEndpoints(), verifier: verifier, verifierId: verifierID, extendedVerifierId: tssVerifierID) + + XCTAssertLessThan(val.metadata!.serverTimeOffset, 20) + + XCTAssertEqual(val.oAuthKeyData!.evmAddress, "0xBd6Bc8aDC5f2A0526078Fd2016C4335f64eD3a30") + XCTAssertEqual(val.oAuthKeyData!.X, "d45d4ad45ec643f9eccd9090c0a2c753b1c991e361388e769c0dfa90c210348c") + XCTAssertEqual(val.oAuthKeyData!.Y, "fdc151b136aa7df94e97cc7d7007e2b45873c4b0656147ec70aad46e178bce1e") + XCTAssertEqual(val.finalKeyData!.evmAddress, "0xBd6Bc8aDC5f2A0526078Fd2016C4335f64eD3a30") + XCTAssertEqual(val.finalKeyData!.X, "d45d4ad45ec643f9eccd9090c0a2c753b1c991e361388e769c0dfa90c210348c") + XCTAssertEqual(val.finalKeyData!.Y, "fdc151b136aa7df94e97cc7d7007e2b45873c4b0656147ec70aad46e178bce1e") + XCTAssertNil(val.metadata?.pubNonce) + XCTAssertEqual(val.metadata?.nonce, BigUInt(0)) + XCTAssertEqual(val.metadata?.upgraded, false) + XCTAssertEqual(val.metadata?.typeOfUser, .v2) + XCTAssertNotNil(val.nodesData) + } + + func test_should_allow_test_tss_verifier_to_fetch_shares() async throws { + let email = generateRandomEmail(of: 6) + let nonce = 0 + let tssTag = "default" + let tssVerifierID: String = email + "\u{0015}" + tssTag + "\u{0016}" + String(nonce) + let verifier = TORUS_TEST_VERIFIER + let verifierID = email + let token = try generateIdToken(email: email) + + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + + let verifierParams = VerifierParams(verifier_id: verifierID, extended_verifier_id: tssVerifierID) + let data = try await torus.retrieveShares(endpoints: nodeDetails.getTorusNodeSSSEndpoints(), verifier: verifier, verifierParams: verifierParams, idToken: token) + + XCTAssertNotNil(data.finalKeyData.privKey) + XCTAssertNotNil(data.oAuthKeyData.evmAddress) + XCTAssertEqual(data.metadata.typeOfUser, .v2) + XCTAssertEqual(data.metadata.nonce, BigUInt(0)) + XCTAssertEqual(data.metadata.upgraded, true) + } + + func test_should_fetch_public_address_when_verifier_is_hash_enabled() async throws { + let verifier = HASH_ENABLED_VERIFIER + let verifierID = TORUS_TEST_EMAIL + + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + + let val = try await torus.getPublicAddress(endpoints: nodeDetails.getTorusNodeSSSEndpoints(), verifier: verifier, verifierId: verifierID) + + XCTAssertLessThan(val.metadata!.serverTimeOffset, 20) + + XCTAssertEqual(val.oAuthKeyData!.evmAddress, "0xaEafa3Fc7349E897F8fCe981f55bbD249f12aC8C") + XCTAssertEqual(val.oAuthKeyData!.X, "72d9172d7edc623266d6c625db91505e6b64a5524e6d7c7c0184b1bbdea1e986") + XCTAssertEqual(val.oAuthKeyData!.Y, "8c26d557a0a9cb22dc2a30d36bf67de93a0eb6d4ef503a849c7de2d14dcbdaaa") + XCTAssertEqual(val.finalKeyData!.evmAddress, "0x8a7e297e20804786767B1918a5CFa11683e5a3BB") + XCTAssertEqual(val.finalKeyData!.X, "7927d5281aea24fd93f41696f79c91370ec0097ff65e83e95691fffbde6d733a") + XCTAssertEqual(val.finalKeyData!.Y, "f22735f0e72ff225274cf499d50b240b7571063e0584471b2b4dab337ad5d8da") + XCTAssertEqual(val.metadata?.pubNonce?.x, "5712d789f7ecf3435dd9bf1136c2daaa634f0222d64e289d2abe30a729a6a22b") + XCTAssertEqual(val.metadata?.pubNonce?.y, "2d2b4586fd5fd9d15c22f66b61bc475742754a8b96d1edb7b2590e4c4f97b3f0") + XCTAssertEqual(val.metadata?.nonce, BigUInt(0)) + XCTAssertEqual(val.metadata?.upgraded, false) + XCTAssertEqual(val.metadata?.typeOfUser, .v2) + XCTAssertNotNil(val.nodesData) + } + + func test_should_fetch_user_type_and_public_address_when_verifier_is_hash_enabled() async throws { + // duplicated test + let verifier = HASH_ENABLED_VERIFIER + let verifierID = TORUS_TEST_EMAIL + + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + + let val = try await torus.getPublicAddress(endpoints: nodeDetails.getTorusNodeSSSEndpoints(), verifier: verifier, verifierId: verifierID) + + XCTAssertLessThan(val.metadata!.serverTimeOffset, 20) + + XCTAssertEqual(val.oAuthKeyData!.evmAddress, "0xaEafa3Fc7349E897F8fCe981f55bbD249f12aC8C") + XCTAssertEqual(val.oAuthKeyData!.X, "72d9172d7edc623266d6c625db91505e6b64a5524e6d7c7c0184b1bbdea1e986") + XCTAssertEqual(val.oAuthKeyData!.Y, "8c26d557a0a9cb22dc2a30d36bf67de93a0eb6d4ef503a849c7de2d14dcbdaaa") + XCTAssertEqual(val.finalKeyData!.evmAddress, "0x8a7e297e20804786767B1918a5CFa11683e5a3BB") + XCTAssertEqual(val.finalKeyData!.X, "7927d5281aea24fd93f41696f79c91370ec0097ff65e83e95691fffbde6d733a") + XCTAssertEqual(val.finalKeyData!.Y, "f22735f0e72ff225274cf499d50b240b7571063e0584471b2b4dab337ad5d8da") + XCTAssertEqual(val.metadata?.pubNonce?.x, "5712d789f7ecf3435dd9bf1136c2daaa634f0222d64e289d2abe30a729a6a22b") + XCTAssertEqual(val.metadata?.pubNonce?.y, "2d2b4586fd5fd9d15c22f66b61bc475742754a8b96d1edb7b2590e4c4f97b3f0") + XCTAssertEqual(val.metadata?.nonce, BigUInt(0)) + XCTAssertEqual(val.metadata?.upgraded, false) + XCTAssertEqual(val.metadata?.typeOfUser, .v2) + XCTAssertNotNil(val.nodesData) + } + + func test_should_be_able_to_login_when_verifier_is_hash_enabled() async throws { + let verifier = HASH_ENABLED_VERIFIER + let verifierID = TORUS_TEST_EMAIL + let jwt = try generateIdToken(email: verifierID) + + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + + let verifierParams = VerifierParams(verifier_id: verifierID) + + let val = try await torus.retrieveShares(endpoints: nodeDetails.getTorusNodeSSSEndpoints(), verifier: verifier, verifierParams: verifierParams, idToken: jwt) + + XCTAssertLessThan(val.metadata.serverTimeOffset, 20) + + XCTAssertEqual(val.finalKeyData.evmAddress, "0x8a7e297e20804786767B1918a5CFa11683e5a3BB") + XCTAssertEqual(val.finalKeyData.X, "7927d5281aea24fd93f41696f79c91370ec0097ff65e83e95691fffbde6d733a") + XCTAssertEqual(val.finalKeyData.Y, "f22735f0e72ff225274cf499d50b240b7571063e0584471b2b4dab337ad5d8da") + XCTAssertEqual(val.finalKeyData.privKey, "f161f63a84f1c935525ec0bda74bc5a15de6a9a7be28fad237ef6162df335fe6") + XCTAssertEqual(val.oAuthKeyData.evmAddress, "0xaEafa3Fc7349E897F8fCe981f55bbD249f12aC8C") + XCTAssertEqual(val.oAuthKeyData.X, "72d9172d7edc623266d6c625db91505e6b64a5524e6d7c7c0184b1bbdea1e986") + XCTAssertEqual(val.oAuthKeyData.Y, "8c26d557a0a9cb22dc2a30d36bf67de93a0eb6d4ef503a849c7de2d14dcbdaaa") + XCTAssertEqual(val.oAuthKeyData.privKey, "62e110d9d698979c1966d14b2759006cf13be7dfc86a63ff30812e2032163f2f") + XCTAssertEqual(val.metadata.pubNonce!.x, "5712d789f7ecf3435dd9bf1136c2daaa634f0222d64e289d2abe30a729a6a22b") + XCTAssertEqual(val.metadata.pubNonce!.y, "2d2b4586fd5fd9d15c22f66b61bc475742754a8b96d1edb7b2590e4c4f97b3f0") + XCTAssertEqual(val.metadata.nonce, BigUInt("8e80e560ae59319938f7ef727ff2c5346caac1c7f5be96d3076e3342ad1d20b7", radix: 16)) + XCTAssertEqual(val.metadata.upgraded, false) + XCTAssertEqual(val.metadata.typeOfUser, .v2) + XCTAssertNotNil(val.nodesData) + } + + func test_should_be_able_to_login() async throws { + let verifier = TORUS_TEST_VERIFIER + let verifierID = TORUS_TEST_EMAIL + let jwt = try generateIdToken(email: verifierID) + + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + + let verifierParams = VerifierParams(verifier_id: verifierID) + + let val = try await torus.retrieveShares(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierParams: verifierParams, idToken: jwt) + + XCTAssertLessThan(val.metadata.serverTimeOffset, 20) + + XCTAssertEqual(val.finalKeyData.evmAddress, "0x462A8BF111A55C9354425F875F89B22678c0Bc44") + XCTAssertEqual(val.finalKeyData.X, "36e257717f746cdd52ba85f24f7c9040db8977d3b0354de70ed43689d24fa1b1") + XCTAssertEqual(val.finalKeyData.Y, "58ec9768c2fe871b3e2a83cdbcf37ba6a88ad19ec2f6e16a66231732713fd507") + XCTAssertEqual(val.finalKeyData.privKey, "230dad9f42039569e891e6b066ff5258b14e9764ef5176d74aeb594d1a744203") + XCTAssertEqual(val.oAuthKeyData.evmAddress, "0x137B3607958562D03Eb3C6086392D1eFa01aA6aa") + XCTAssertEqual(val.oAuthKeyData.X, "118a674da0c68f16a1123de9611ba655f4db1e336fe1b2d746028d65d22a3c6b") + XCTAssertEqual(val.oAuthKeyData.Y, "8325432b3a3418d632b4fe93db094d6d83250eea60fe512897c0ad548737f8a5") + XCTAssertEqual(val.oAuthKeyData.privKey, "6b3c872a269aa8994a5acc8cdd70ea3d8d182d42f8af421c0c39ea124e9b66fa") + XCTAssertEqual(val.metadata.pubNonce!.x, "5d03a0df9b3db067d3363733df134598d42873bb4730298a53ee100975d703cc") + XCTAssertEqual(val.metadata.pubNonce!.y, "279434dcf0ff22f077877a70bcad1732412f853c96f02505547f7ca002b133ed") + + XCTAssertEqual(val.metadata.nonce, BigUInt("b7d126751b68ecd09e371a23898e6819dee54708a5ead4f6fe83cdc79c0f1c4a", radix: 16)) + XCTAssertEqual(val.metadata.upgraded, false) + XCTAssertEqual(val.metadata.typeOfUser, .v2) + XCTAssertNotNil(val.nodesData) + } + + func test_should_be_able_to_aggregate_login() async throws { + let email: String = generateRandomEmail(of: 6) + let jwt = try! generateIdToken(email: email) + let hashedIDToken = try KeyUtils.keccak256Data(jwt) + let verifierParams = VerifierParams(verifier_id: email, sub_verifier_ids: [TORUS_TEST_VERIFIER], verify_params: [VerifyParams(verifier_id: email, idtoken: jwt)]) + let nodeDetails = try await fnd.getNodeDetails(verifier: TORUS_TEST_AGGREGATE_VERIFIER, verifierID: email) + let data = try await torus.retrieveShares(endpoints: nodeDetails.getTorusNodeSSSEndpoints(), verifier: TORUS_TEST_AGGREGATE_VERIFIER, verifierParams: verifierParams, idToken: hashedIDToken) + + XCTAssertLessThan(data.metadata.serverTimeOffset, 20) + XCTAssertNotNil(data.finalKeyData.privKey) + XCTAssertNotNil(data.oAuthKeyData.evmAddress) + XCTAssertEqual(data.metadata.typeOfUser, .v2) + } + + func test_should_be_able_to_update_sessiontime_of_the_token_signature_data() async throws { + let verifier: String = TORUS_TEST_VERIFIER + let verifierID: String = TORUS_TEST_EMAIL + let jwt = try! generateIdToken(email: verifierID) + + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + + let verifierParams = VerifierParams(verifier_id: verifierID) + + let customSessionTime = Int(3600) + torus.setSessionTime(sessionTime: customSessionTime) + + let data = try await torus.retrieveShares(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierParams: verifierParams, idToken: jwt) + + let signatures = data.sessionData.sessionTokenData.map({ $0!.token }) + let parsedSignatures = signatures.map({ + let data = Data(base64Encoded: $0.data(using: .utf8)!)! + let hexString = String(data: data, encoding: .utf8)! + let json = hexString.hexEncodedToString() + return json + }) + let now = Int(Date().timeIntervalSince1970) + for item in parsedSignatures { + let json = try JSONSerialization.jsonObject(with: item.data(using: .utf8)!) as? [String: Any] + let exp = json!["exp"] as! Int + let sessionTime = exp - now + XCTAssertGreaterThanOrEqual(sessionTime, customSessionTime - 30) + XCTAssertLessThanOrEqual(sessionTime, customSessionTime + 30) + } + } +} diff --git a/Tests/TorusUtilsTests/SapphireMainnetTests.swift b/Tests/TorusUtilsTests/SapphireMainnetTests.swift new file mode 100644 index 00000000..ac29a202 --- /dev/null +++ b/Tests/TorusUtilsTests/SapphireMainnetTests.swift @@ -0,0 +1,286 @@ +import BigInt +import curveSecp256k1 +import FetchNodeDetails +import JWTKit +import TorusUtils +import XCTest + +class SapphireMainnetTests: XCTestCase { + static var fetchNodeDetails: AllNodeDetailsModel? + static var utils: TorusUtils? + static var endpoints: [String] = [] + static var nodePubKeys: [TorusNodePubModel] = [] + static var privKey: String = "" + + let TORUS_TEST_EMAIL = "hello@tor.us" + let TORUS_TEST_VERIFIER = "torus-test-health" + let TORUS_TEST_AGGREGATE_VERIFIER = "torus-aggregate-sapphire-mainnet" + let HASH_ENABLED_VERIFIER = "torus-test-verifierid-hash" + let TORUS_EXTENDED_VERIFIER_EMAIL = "testextenderverifierid@example.com" + + var fnd: NodeDetailManager! + var torus: TorusUtils! + + override func setUp() { + super.setUp() + fnd = NodeDetailManager(network: .sapphire(.SAPPHIRE_MAINNET)) + torus = try! TorusUtils(params: TorusOptions(clientId: "YOUR_CLIENT_ID", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true)) + } + + func test_should_fetch_public_address() async throws { + let verifier = "tkey-google-sapphire-mainnet" + let verifierID = TORUS_TEST_EMAIL + + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + + let val = try await torus.getPublicAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierId: verifierID) + + XCTAssertEqual(val.oAuthKeyData!.evmAddress, "0xb1a49C6E50a1fC961259a8c388EAf5953FA5152b") + XCTAssertEqual(val.oAuthKeyData!.X, "a9f5a463aefb16e90f4cbb9de4a5b6b7f6c6a3831cefa0f20cccb9e7c7b01c20") + XCTAssertEqual(val.oAuthKeyData!.Y, "3376c6734da57ab3a67c7792eeea20707d16992dd2c827a59499f4c056b00d08") + XCTAssertEqual(val.finalKeyData!.evmAddress, "0x327b2742768B436d09153429E762FADB54413Ded") + XCTAssertEqual(val.finalKeyData!.X, "1567e030ca76e520c180c50bc6baed07554ebc35c3132495451173e9310d8be5") + XCTAssertEqual(val.finalKeyData!.Y, "123c0560757ffe6498bf2344165d0f295ea74eb8884683675e5f17ae7bb41cdb") + XCTAssertEqual(val.metadata?.pubNonce?.x, "56e803db7710adbfe0ecca35bc6a3ad27e966df142e157e76e492773c88e8433") + XCTAssertEqual(val.metadata?.pubNonce?.y, "f4168594c1126ca731756dd480f992ee73b0834ba4b787dd892a9211165f50a3") + XCTAssertEqual(val.metadata?.nonce, BigUInt(0)) + XCTAssertEqual(val.metadata?.upgraded, false) + XCTAssertEqual(val.metadata?.typeOfUser, .v2) + XCTAssertNotNil(val.nodesData) + } + + func test_should_be_able_to_key_assign() async throws { + let fakeEmail = generateRandomEmail(of: 6) + let verifier = "tkey-google-sapphire-mainnet" + let verifierID = fakeEmail + + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + + let data = try await torus.getPublicAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierId: verifierID) + + XCTAssertNotEqual(data.finalKeyData?.evmAddress, "") + XCTAssertNotEqual(data.oAuthKeyData?.evmAddress, "") + XCTAssertEqual(data.metadata?.typeOfUser, .v2) + XCTAssertEqual(data.metadata?.upgraded, false) + } + + func test_should_be_able_to_key_assign_to_tss_verifier_id() async throws { + let fakeEmail = generateRandomEmail(of: 6) + let nonce = 0 + let tssTag = "default" + let tssVerifierID: String = fakeEmail + "\u{0015}" + tssTag + "\u{0016}" + String(nonce) + let verifier = "tkey-google-sapphire-mainnet" + let verifierID = fakeEmail + + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + + let data = try await torus.getPublicAddress(endpoints: nodeDetails.getTorusNodeSSSEndpoints(), verifier: verifier, verifierId: verifierID, extendedVerifierId: tssVerifierID) + + XCTAssertNotEqual(data.finalKeyData?.evmAddress, "") + XCTAssertNotEqual(data.oAuthKeyData?.evmAddress, "") + XCTAssertEqual(data.metadata?.typeOfUser, .v2) + XCTAssertEqual(data.metadata?.upgraded, false) + } + + func test_should_fetch_public_address_of_tss_verifier_id() async throws { + let email = TORUS_EXTENDED_VERIFIER_EMAIL + let nonce = 0 + let tssTag = "default" + let tssVerifierID: String = email + "\u{0015}" + tssTag + "\u{0016}" + String(nonce) + let verifier = TORUS_TEST_VERIFIER + let verifierID = email + + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + + let val = try await torus.getPublicAddress(endpoints: nodeDetails.getTorusNodeSSSEndpoints(), verifier: verifier, verifierId: verifierID, extendedVerifierId: tssVerifierID) + + XCTAssertLessThan(val.metadata!.serverTimeOffset, 20) + + XCTAssertEqual(val.oAuthKeyData!.evmAddress, "0x98EC5b049c5C0Dc818C69e95CF43534AEB80261A") + XCTAssertEqual(val.oAuthKeyData!.X, "a772c71ca6c650506f26a180456a6bdf462996781a10f1740f4e65314f360f29") + XCTAssertEqual(val.oAuthKeyData!.Y, "776c2178ff4620c67197b2f26b1222503919ff26a7cbd0fdbc91a2c9764e56cb") + XCTAssertEqual(val.finalKeyData!.evmAddress, "0x98EC5b049c5C0Dc818C69e95CF43534AEB80261A") + XCTAssertEqual(val.finalKeyData!.X, "a772c71ca6c650506f26a180456a6bdf462996781a10f1740f4e65314f360f29") + XCTAssertEqual(val.finalKeyData!.Y, "776c2178ff4620c67197b2f26b1222503919ff26a7cbd0fdbc91a2c9764e56cb") + XCTAssertNil(val.metadata?.pubNonce) + XCTAssertEqual(val.metadata?.nonce, BigUInt(0)) + XCTAssertEqual(val.metadata?.upgraded, false) + XCTAssertEqual(val.metadata?.typeOfUser, .v2) + XCTAssertNotNil(val.nodesData) + } + + func test_should_allow_test_tss_verifier_to_fetch_shares() async throws { + let email = generateRandomEmail(of: 6) + let nonce = 0 + let tssTag = "default" + let tssVerifierID: String = email + "\u{0015}" + tssTag + "\u{0016}" + String(nonce) + let verifier = TORUS_TEST_VERIFIER + let verifierID = email + let token = try generateIdToken(email: email) + + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + + let verifierParams = VerifierParams(verifier_id: verifierID, extended_verifier_id: tssVerifierID) + let data = try await torus.retrieveShares(endpoints: nodeDetails.getTorusNodeSSSEndpoints(), verifier: verifier, verifierParams: verifierParams, idToken: token) + + XCTAssertNotNil(data.finalKeyData.privKey) + XCTAssertNotNil(data.oAuthKeyData.evmAddress) + XCTAssertEqual(data.metadata.typeOfUser, .v2) + XCTAssertEqual(data.metadata.nonce, BigUInt(0)) + XCTAssertEqual(data.metadata.upgraded, true) + } + + func test_should_fetch_public_address_when_verifier_is_hash_enabled() async throws { + let verifier = HASH_ENABLED_VERIFIER + let verifierID = TORUS_TEST_EMAIL + + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + + let val = try await torus.getPublicAddress(endpoints: nodeDetails.getTorusNodeSSSEndpoints(), verifier: verifier, verifierId: verifierID) + + XCTAssertLessThan(val.metadata!.serverTimeOffset, 20) + + XCTAssertEqual(val.oAuthKeyData!.evmAddress, "0xeBe48BE7693a36Ff562D18c4494AC4496A45EaaC") + XCTAssertEqual(val.oAuthKeyData!.X, "147d0a97d498ac17172dd92546617e06f2c32c405d414dfc06632b8fbcba93d8") + XCTAssertEqual(val.oAuthKeyData!.Y, "cc6e57662c3866c4316c05b0fe902db9aaf5541fbf5fda854c3b4634eceeb43c") + XCTAssertEqual(val.finalKeyData!.evmAddress, "0xCb76F4C8cbAe524997787B57efeeD99f6D3BD5AB") + XCTAssertEqual(val.finalKeyData!.X, "b943bfdc29c515195270d3a219da6a57bcaf6e58e57d03e2accb8c716e6949c8") + XCTAssertEqual(val.finalKeyData!.Y, "a0fe9ac87310d302a821f89a747d80c9b7dc5cbd0956571f84b09e58d11eee90") + XCTAssertEqual(val.metadata?.pubNonce?.x, "498ed301af25a3b7136f478fa58677c79a6d6fe965bc13002a6f459b896313bd") + XCTAssertEqual(val.metadata?.pubNonce?.y, "d6feb9a1e0d6d0627fbb1ce75682bc09ab4cf0e2da4f0f7fcac0ba9d07596c8f") + XCTAssertEqual(val.metadata?.nonce, BigUInt(0)) + XCTAssertEqual(val.metadata?.upgraded, false) + XCTAssertEqual(val.metadata?.typeOfUser, .v2) + XCTAssertNotNil(val.nodesData) + } + + func test_should_fetch_user_type_and_public_address_when_verifier_is_hash_enabled() async throws { + // duplicated test + let verifier = HASH_ENABLED_VERIFIER + let verifierID = TORUS_TEST_EMAIL + + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + + let val = try await torus.getPublicAddress(endpoints: nodeDetails.getTorusNodeSSSEndpoints(), verifier: verifier, verifierId: verifierID) + + XCTAssertLessThan(val.metadata!.serverTimeOffset, 20) + + XCTAssertEqual(val.oAuthKeyData!.evmAddress, "0xeBe48BE7693a36Ff562D18c4494AC4496A45EaaC") + XCTAssertEqual(val.oAuthKeyData!.X, "147d0a97d498ac17172dd92546617e06f2c32c405d414dfc06632b8fbcba93d8") + XCTAssertEqual(val.oAuthKeyData!.Y, "cc6e57662c3866c4316c05b0fe902db9aaf5541fbf5fda854c3b4634eceeb43c") + XCTAssertEqual(val.finalKeyData!.evmAddress, "0xCb76F4C8cbAe524997787B57efeeD99f6D3BD5AB") + XCTAssertEqual(val.finalKeyData!.X, "b943bfdc29c515195270d3a219da6a57bcaf6e58e57d03e2accb8c716e6949c8") + XCTAssertEqual(val.finalKeyData!.Y, "a0fe9ac87310d302a821f89a747d80c9b7dc5cbd0956571f84b09e58d11eee90") + XCTAssertEqual(val.metadata?.pubNonce?.x, "498ed301af25a3b7136f478fa58677c79a6d6fe965bc13002a6f459b896313bd") + XCTAssertEqual(val.metadata?.pubNonce?.y, "d6feb9a1e0d6d0627fbb1ce75682bc09ab4cf0e2da4f0f7fcac0ba9d07596c8f") + XCTAssertEqual(val.metadata?.nonce, BigUInt(0)) + XCTAssertEqual(val.metadata?.upgraded, false) + XCTAssertEqual(val.metadata?.typeOfUser, .v2) + XCTAssertNotNil(val.nodesData) + } + + func test_should_be_able_to_login_when_verifier_is_hash_enabled() async throws { + let verifier = HASH_ENABLED_VERIFIER + let verifierID = TORUS_TEST_EMAIL + let jwt = try generateIdToken(email: verifierID) + + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + + let verifierParams = VerifierParams(verifier_id: verifierID) + + let val = try await torus.retrieveShares(endpoints: nodeDetails.getTorusNodeSSSEndpoints(), verifier: verifier, verifierParams: verifierParams, idToken: jwt) + + XCTAssertLessThan(val.metadata.serverTimeOffset, 20) + + XCTAssertEqual(val.finalKeyData.evmAddress, "0xCb76F4C8cbAe524997787B57efeeD99f6D3BD5AB") + XCTAssertEqual(val.finalKeyData.X, "b943bfdc29c515195270d3a219da6a57bcaf6e58e57d03e2accb8c716e6949c8") + XCTAssertEqual(val.finalKeyData.Y, "a0fe9ac87310d302a821f89a747d80c9b7dc5cbd0956571f84b09e58d11eee90") + XCTAssertEqual(val.finalKeyData.privKey, "13941ecd812b08d8a33a20bc975f0cd1c3f82de25b20c0c863ba5f21580b65f6") + XCTAssertEqual(val.oAuthKeyData.evmAddress, "0xeBe48BE7693a36Ff562D18c4494AC4496A45EaaC") + XCTAssertEqual(val.oAuthKeyData.X, "147d0a97d498ac17172dd92546617e06f2c32c405d414dfc06632b8fbcba93d8") + XCTAssertEqual(val.oAuthKeyData.Y, "cc6e57662c3866c4316c05b0fe902db9aaf5541fbf5fda854c3b4634eceeb43c") + XCTAssertEqual(val.oAuthKeyData.privKey, "d768b327cbde681e5850a7d14f1c724bba2b8f8ab7fe2b1c4f1ee6979fc25478") + XCTAssertEqual(val.metadata.pubNonce!.x, "498ed301af25a3b7136f478fa58677c79a6d6fe965bc13002a6f459b896313bd") + XCTAssertEqual(val.metadata.pubNonce!.y, "d6feb9a1e0d6d0627fbb1ce75682bc09ab4cf0e2da4f0f7fcac0ba9d07596c8f") + XCTAssertEqual(val.metadata.nonce, BigUInt("3c2b6ba5b54ca0ba4ae978eb48429a84c47b7b3e526b35e7d46dd716887f52bf", radix: 16)) + XCTAssertEqual(val.metadata.upgraded, false) + XCTAssertEqual(val.metadata.typeOfUser, .v2) + XCTAssertNotNil(val.nodesData) + } + + func test_should_be_able_to_login() async throws { + let verifier = TORUS_TEST_VERIFIER + let verifierID = TORUS_TEST_EMAIL + let jwt = try generateIdToken(email: verifierID) + + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + + let verifierParams = VerifierParams(verifier_id: verifierID) + + let val = try await torus.retrieveShares(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierParams: verifierParams, idToken: jwt) + + XCTAssertLessThan(val.metadata.serverTimeOffset, 20) + + XCTAssertEqual(val.finalKeyData.evmAddress, "0x70520A7F04868ACad901683699Fa32765C9F6871") + XCTAssertEqual(val.finalKeyData.X, "adff099b5d3b1e238b43fba1643cfa486e8d9e8de22c1e6731d06a5303f9025b") + XCTAssertEqual(val.finalKeyData.Y, "21060328e7889afd303acb63201b6493e3061057d1d81279931ab4a6cabf94d4") + XCTAssertEqual(val.finalKeyData.privKey, "dfb39b84e0c64b8c44605151bf8670ae6eda232056265434729b6a8a50fa3419") + XCTAssertEqual(val.oAuthKeyData.evmAddress, "0x925c97404F1aBdf4A8085B93edC7B9F0CEB3C673") + XCTAssertEqual(val.oAuthKeyData.X, "5cd8625fc01c7f7863a58c914a8c43b2833b3d0d5059350bab4acf6f4766a33d") + XCTAssertEqual(val.oAuthKeyData.Y, "198a4989615c5c2c7fa4d49c076ea7765743d09816bb998acb9ff54f5db4a391") + XCTAssertEqual(val.oAuthKeyData.privKey, "90a219ac78273e82e36eaa57c15f9070195e436644319d6b9aea422bb4d31906") + XCTAssertEqual(val.metadata.pubNonce!.x, "ab4d287c263ab1bb83c37646d0279764e50fe4b0c34de4da113657866ddcf318") + XCTAssertEqual(val.metadata.pubNonce!.y, "ad35db2679dfad4b62d77cf753d7b98f73c902e5d101cc2c3c1209ece6d94382") + XCTAssertEqual(val.metadata.nonce, BigUInt("4f1181d8689f0d0960f1a6f9fe26e03e557bdfba11f4b6c8d7b1285e9c271b13", radix: 16)) + XCTAssertEqual(val.metadata.upgraded, false) + XCTAssertEqual(val.metadata.typeOfUser, .v2) + XCTAssertNotNil(val.nodesData) + } + + func test_should_be_able_to_aggregate_login() async throws { + let email: String = generateRandomEmail(of: 6) + let jwt = try! generateIdToken(email: email) + let hashedIDToken = try KeyUtils.keccak256Data(jwt) + let verifierParams = VerifierParams(verifier_id: email, sub_verifier_ids: [TORUS_TEST_VERIFIER], verify_params: [VerifyParams(verifier_id: email, idtoken: jwt)]) + + let nodeDetails = try await fnd.getNodeDetails(verifier: TORUS_TEST_AGGREGATE_VERIFIER, verifierID: email) + + let data = try await torus.retrieveShares(endpoints: nodeDetails.getTorusNodeSSSEndpoints(), verifier: TORUS_TEST_AGGREGATE_VERIFIER, verifierParams: verifierParams, idToken: hashedIDToken) + + XCTAssertLessThan(data.metadata.serverTimeOffset, 20) + XCTAssertNotNil(data.finalKeyData.privKey) + XCTAssertNotNil(data.oAuthKeyData.evmAddress) + XCTAssertEqual(data.metadata.typeOfUser, .v2) + } + + func test_should_be_able_to_update_sessiontime_of_the_token_signature_data() async throws { + let verifier: String = TORUS_TEST_VERIFIER + let verifierID: String = TORUS_TEST_EMAIL + let jwt = try! generateIdToken(email: verifierID) + + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + + let verifierParams = VerifierParams(verifier_id: verifierID) + + let customSessionTime = Int(3600) + torus.setSessionTime(sessionTime: customSessionTime) + + let data = try await torus.retrieveShares(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierParams: verifierParams, idToken: jwt) + + let signatures = data.sessionData.sessionTokenData.map({ $0!.token }) + let parsedSignatures = signatures.map({ + let data = Data(base64Encoded: $0.data(using: .utf8)!)! + let hexString = String(data: data, encoding: .utf8)! + let json = hexString.hexEncodedToString() + return json + }) + let now = Int(Date().timeIntervalSince1970) + for item in parsedSignatures { + let json = try JSONSerialization.jsonObject(with: item.data(using: .utf8)!) as? [String: Any] + let exp = json!["exp"] as! Int + let sessionTime = exp - now + XCTAssertGreaterThanOrEqual(sessionTime, customSessionTime - 30) + XCTAssertLessThanOrEqual(sessionTime, customSessionTime + 30) + } + } +} diff --git a/Tests/TorusUtilsTests/SapphireTest.swift b/Tests/TorusUtilsTests/SapphireTest.swift deleted file mode 100644 index 94114c34..00000000 --- a/Tests/TorusUtilsTests/SapphireTest.swift +++ /dev/null @@ -1,381 +0,0 @@ -import BigInt -import FetchNodeDetails -import JWTKit -import XCTest -import curveSecp256k1 - -@testable import TorusUtils - -final class SapphireTest: XCTestCase { - static var fetchNodeDetails: AllNodeDetailsModel? - // static var nodeDetails: NodeDetails? - static var utils: TorusUtils? - static var endpoints: [String] = [] - static var nodePubKeys: [TorusNodePubModel] = [] - static var privKey: String = "" - - let TORUS_TEST_VERIFIER = "torus-test-health" - let TORUS_TEST_AGGREGATE_VERIFIER = "torus-test-health-aggregate" - let TORUS_TEST_EMAIL = "devnettestuser@tor.us" - let TORUS_HASH_ENABLED_TEST_EMAIL = "saasas@tr.us"; - let TORUS_IMPORT_EMAIL = "Sydnie.Lehner73@yahoo.com" - let TORUS_EXTENDED_VERIFIER_EMAIL = "testextenderverifierid@example.com" - let HashEnabledVerifier = "torus-test-verifierid-hash" - - var fnd: NodeDetailManager! - var torus: TorusUtils! - - override func setUp() { - super.setUp() - fnd = NodeDetailManager(network: .sapphire(.SAPPHIRE_DEVNET)) - } - - func get_fnd_and_tu_data(verifer: String, veriferID: String, enableOneKey: Bool = false) async throws -> AllNodeDetailsModel { - let nodeDetails = try await fnd.getNodeDetails(verifier: verifer, verifierID: veriferID) - torus = TorusUtils(enableOneKey: enableOneKey, network: .sapphire(.SAPPHIRE_DEVNET), clientId: "YOUR_CLIENT_ID") - return nodeDetails - } - - func testFetchPublicAddress() async throws { - let nodeDetails = try await get_fnd_and_tu_data(verifer: TORUS_TEST_VERIFIER, veriferID: TORUS_TEST_EMAIL) - - let val = try await torus.getPublicAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.torusNodePub, verifier: TORUS_TEST_VERIFIER, verifierId: TORUS_TEST_EMAIL) - XCTAssertEqual(val.oAuthKeyData!.evmAddress, "0x137B3607958562D03Eb3C6086392D1eFa01aA6aa") - XCTAssertEqual(val.oAuthKeyData!.X, "118a674da0c68f16a1123de9611ba655f4db1e336fe1b2d746028d65d22a3c6b") - XCTAssertEqual(val.oAuthKeyData!.Y, "8325432b3a3418d632b4fe93db094d6d83250eea60fe512897c0ad548737f8a5") - XCTAssertEqual(val.finalKeyData!.evmAddress, "0x462A8BF111A55C9354425F875F89B22678c0Bc44") - XCTAssertEqual(val.finalKeyData!.X, "36e257717f746cdd52ba85f24f7c9040db8977d3b0354de70ed43689d24fa1b1") - XCTAssertEqual(val.finalKeyData!.Y, "58ec9768c2fe871b3e2a83cdbcf37ba6a88ad19ec2f6e16a66231732713fd507") - XCTAssertEqual(val.metadata?.pubNonce?.x, "5d03a0df9b3db067d3363733df134598d42873bb4730298a53ee100975d703cc") - XCTAssertEqual(val.metadata?.pubNonce?.y, "279434dcf0ff22f077877a70bcad1732412f853c96f02505547f7ca002b133ed") - XCTAssertEqual(val.metadata?.nonce, BigUInt.zero) - XCTAssertEqual(val.metadata?.upgraded, false) - XCTAssertEqual(val.metadata?.typeOfUser, UserType(rawValue: "v2")) - } - - func testKeepPublicAddressSame() async throws { - let nodeDetails = try await get_fnd_and_tu_data(verifer: TORUS_TEST_VERIFIER, veriferID: TORUS_TEST_EMAIL) - - let publicAddress = try await torus.getPublicAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), verifier: TORUS_TEST_VERIFIER, verifierId: TORUS_TEST_EMAIL) - let publicAddress2 = try await torus.getPublicAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), verifier: TORUS_TEST_VERIFIER, verifierId: TORUS_TEST_EMAIL) - - XCTAssertEqual(publicAddress.finalKeyData?.evmAddress, publicAddress2.finalKeyData?.evmAddress) - XCTAssertNotEqual(publicAddress.finalKeyData?.evmAddress, nil) - XCTAssertNotEqual(publicAddress2.finalKeyData?.evmAddress, "") - } - - func testFetchPublicAddressAndUserType() async throws { - let nodeDetails = try await get_fnd_and_tu_data(verifer: TORUS_TEST_VERIFIER, veriferID: TORUS_TEST_EMAIL) - - let result = try await torus.getPublicAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), verifier: TORUS_TEST_VERIFIER, verifierId: TORUS_TEST_EMAIL) - - XCTAssertEqual(result.finalKeyData?.evmAddress.lowercased(), "0x462a8bf111a55c9354425f875f89b22678c0bc44".lowercased()) - - XCTAssertEqual(result.metadata?.typeOfUser, .v2) - - XCTAssertEqual(result.metadata?.pubNonce?.x, "5d03a0df9b3db067d3363733df134598d42873bb4730298a53ee100975d703cc") - - XCTAssertEqual(result.metadata?.pubNonce?.y, "279434dcf0ff22f077877a70bcad1732412f853c96f02505547f7ca002b133ed") - } - - func testKeyAssignSapphireDevnet() async throws { - let fakeEmail = generateRandomEmail(of: 6) - let verifier: String = TORUS_TEST_VERIFIER - let verifierID: String = fakeEmail - let nodeDetails = try await get_fnd_and_tu_data(verifer: verifier, veriferID: verifierID) - let data = try await torus.getPublicAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), verifier: verifier, verifierId: verifierID) - XCTAssertNotNil(data.finalKeyData) - XCTAssertNotEqual(data.finalKeyData?.evmAddress, "") - XCTAssertEqual(data.metadata?.typeOfUser, .v2) - } - - func testAbleToLogin() async throws { - let token = try generateIdToken(email: TORUS_TEST_EMAIL) - - let verifierParams = VerifierParams(verifier_id: TORUS_TEST_EMAIL) - - let nodeDetails = try await get_fnd_and_tu_data(verifer: TORUS_TEST_VERIFIER, veriferID: TORUS_TEST_EMAIL) - - let data = try await torus.retrieveShares( - endpoints: nodeDetails.getTorusNodeEndpoints(), - torusNodePubs: nodeDetails.getTorusNodePub(), - indexes: nodeDetails.getTorusIndexes(), - verifier: TORUS_TEST_VERIFIER, - verifierParams: verifierParams, - idToken: token - ) - - XCTAssertEqual(data.finalKeyData?.evmAddress, "0x462A8BF111A55C9354425F875F89B22678c0Bc44") - XCTAssertEqual(data.finalKeyData?.X, "36e257717f746cdd52ba85f24f7c9040db8977d3b0354de70ed43689d24fa1b1") - XCTAssertEqual(data.finalKeyData?.Y, "58ec9768c2fe871b3e2a83cdbcf37ba6a88ad19ec2f6e16a66231732713fd507") - XCTAssertEqual(data.finalKeyData?.privKey, "230dad9f42039569e891e6b066ff5258b14e9764ef5176d74aeb594d1a744203") - XCTAssertEqual(data.oAuthKeyData?.evmAddress, "0x137B3607958562D03Eb3C6086392D1eFa01aA6aa") - XCTAssertEqual(data.oAuthKeyData?.X, "118a674da0c68f16a1123de9611ba655f4db1e336fe1b2d746028d65d22a3c6b") - XCTAssertEqual(data.oAuthKeyData?.Y, "8325432b3a3418d632b4fe93db094d6d83250eea60fe512897c0ad548737f8a5") - XCTAssertEqual(data.oAuthKeyData?.privKey, "6b3c872a269aa8994a5acc8cdd70ea3d8d182d42f8af421c0c39ea124e9b66fa") - XCTAssertNotEqual(data.sessionData?.sessionTokenData.count, 0) - XCTAssertNotEqual(data.sessionData?.sessionAuthKey, "") - XCTAssertEqual(data.metadata?.pubNonce?.x, "5d03a0df9b3db067d3363733df134598d42873bb4730298a53ee100975d703cc") - XCTAssertEqual(data.metadata?.pubNonce?.y, "279434dcf0ff22f077877a70bcad1732412f853c96f02505547f7ca002b133ed") - XCTAssertEqual(data.metadata?.nonce?.serialize().toHexString(), "b7d126751b68ecd09e371a23898e6819dee54708a5ead4f6fe83cdc79c0f1c4a") - XCTAssertEqual(data.metadata?.typeOfUser, .v2) - XCTAssertEqual(data.metadata?.upgraded, false) - } - - func testNewUserLogin() async throws { - let fakeEmail = generateRandomEmail(of: 6) - let verifierId = fakeEmail // faker random address - let token = try generateIdToken(email: verifierId) - - let verifierParams = VerifierParams(verifier_id: verifierId) - - let nodeDetails = try await get_fnd_and_tu_data(verifer: TORUS_TEST_VERIFIER, veriferID: verifierId) - - let data = try await torus.retrieveShares( - endpoints: nodeDetails.getTorusNodeEndpoints(), - torusNodePubs: nodeDetails.getTorusNodePub(), - indexes: nodeDetails.getTorusIndexes(), - verifier: TORUS_TEST_VERIFIER, - verifierParams: verifierParams, - idToken: token - ) - - XCTAssertEqual(data.metadata?.typeOfUser, .v2) - XCTAssertEqual(data.metadata?.upgraded, false) - XCTAssertNotEqual(data.finalKeyData?.evmAddress, "") - XCTAssertNotEqual(data.finalKeyData?.X, "") - XCTAssertNotEqual(data.finalKeyData?.Y, "") - XCTAssertNotEqual(data.finalKeyData?.privKey, "") - XCTAssertNotEqual(data.oAuthKeyData?.evmAddress, "") - XCTAssertNotEqual(data.oAuthKeyData?.X, "") - XCTAssertNotEqual(data.oAuthKeyData?.Y, "") - XCTAssertNotEqual(data.oAuthKeyData?.privKey, "") - XCTAssertNotEqual(data.sessionData?.sessionTokenData.count, 0) - XCTAssertNotEqual(data.sessionData?.sessionAuthKey, "") - XCTAssertNotEqual(data.metadata?.pubNonce?.x, "") - XCTAssertNotEqual(data.metadata?.pubNonce?.y, "") - } - - func testNodeDownAbleToLogin() async throws { - let token = try generateIdToken(email: TORUS_TEST_EMAIL) - - let verifierParams = VerifierParams(verifier_id: TORUS_TEST_EMAIL) - let nodeDetails = try await get_fnd_and_tu_data(verifer: TORUS_TEST_VERIFIER, veriferID: TORUS_TEST_EMAIL) - - var torusNodeEndpoints = nodeDetails.getTorusNodeSSSEndpoints() - torusNodeEndpoints[1] = "https://example.com" - - let data = try await torus.retrieveShares(endpoints: torusNodeEndpoints, - torusNodePubs: nodeDetails.getTorusNodePub(), indexes: nodeDetails.getTorusIndexes(), - verifier: TORUS_TEST_VERIFIER, verifierParams: verifierParams, idToken: token) - - XCTAssertEqual(data.finalKeyData?.evmAddress, "0x462A8BF111A55C9354425F875F89B22678c0Bc44") - XCTAssertEqual(data.finalKeyData?.X, "36e257717f746cdd52ba85f24f7c9040db8977d3b0354de70ed43689d24fa1b1") - XCTAssertEqual(data.finalKeyData?.Y, "58ec9768c2fe871b3e2a83cdbcf37ba6a88ad19ec2f6e16a66231732713fd507") - XCTAssertEqual(data.finalKeyData?.privKey, "230dad9f42039569e891e6b066ff5258b14e9764ef5176d74aeb594d1a744203") - XCTAssertEqual(data.oAuthKeyData?.evmAddress, "0x137B3607958562D03Eb3C6086392D1eFa01aA6aa") - XCTAssertEqual(data.oAuthKeyData?.X, "118a674da0c68f16a1123de9611ba655f4db1e336fe1b2d746028d65d22a3c6b") - XCTAssertEqual(data.oAuthKeyData?.Y, "8325432b3a3418d632b4fe93db094d6d83250eea60fe512897c0ad548737f8a5") - XCTAssertEqual(data.oAuthKeyData?.privKey, "6b3c872a269aa8994a5acc8cdd70ea3d8d182d42f8af421c0c39ea124e9b66fa") - XCTAssertNotEqual(data.sessionData?.sessionTokenData.count, 0) - XCTAssertNotEqual(data.sessionData?.sessionAuthKey, "") - XCTAssertEqual(data.metadata?.pubNonce?.x, "5d03a0df9b3db067d3363733df134598d42873bb4730298a53ee100975d703cc") - XCTAssertEqual(data.metadata?.pubNonce?.y, "279434dcf0ff22f077877a70bcad1732412f853c96f02505547f7ca002b133ed") - XCTAssertEqual(data.metadata?.nonce?.serialize().toHexString(), "b7d126751b68ecd09e371a23898e6819dee54708a5ead4f6fe83cdc79c0f1c4a") - XCTAssertEqual(data.metadata?.typeOfUser, .v2) - XCTAssertEqual(data.metadata?.upgraded, false) - } - - func testPubAdderessOfTssVerifierId() async throws { - let email = TORUS_EXTENDED_VERIFIER_EMAIL - let nonce = 0 - let tssTag = "default" - let tssVerifierId = "\(email)\u{0015}\(tssTag)\u{0016}\(nonce)" - let nodeDetails = try await get_fnd_and_tu_data(verifer: TORUS_TEST_VERIFIER, veriferID: email) - - let pubAddress = try await torus.getPublicAddress(endpoints: nodeDetails.getTorusNodeSSSEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), verifier: TORUS_TEST_VERIFIER, verifierId: TORUS_TEST_EMAIL, extendedVerifierId: tssVerifierId) - - XCTAssertEqual(pubAddress.oAuthKeyData!.evmAddress, "0xBd6Bc8aDC5f2A0526078Fd2016C4335f64eD3a30") - XCTAssertEqual(pubAddress.oAuthKeyData!.X, "d45d4ad45ec643f9eccd9090c0a2c753b1c991e361388e769c0dfa90c210348c") - XCTAssertEqual(pubAddress.oAuthKeyData!.Y, "fdc151b136aa7df94e97cc7d7007e2b45873c4b0656147ec70aad46e178bce1e") - XCTAssertEqual(pubAddress.finalKeyData!.evmAddress, "0xBd6Bc8aDC5f2A0526078Fd2016C4335f64eD3a30") - XCTAssertEqual(pubAddress.finalKeyData!.X, "d45d4ad45ec643f9eccd9090c0a2c753b1c991e361388e769c0dfa90c210348c") - XCTAssertEqual(pubAddress.finalKeyData!.Y, "fdc151b136aa7df94e97cc7d7007e2b45873c4b0656147ec70aad46e178bce1e") - XCTAssertEqual(pubAddress.metadata?.pubNonce?.x, nil) - XCTAssertEqual(pubAddress.metadata?.pubNonce?.y, nil) - XCTAssertEqual(pubAddress.metadata?.nonce, BigUInt("0")) - XCTAssertEqual(pubAddress.metadata?.upgraded, false) - XCTAssertEqual(pubAddress.metadata?.typeOfUser, UserType(rawValue: "v2")) - } - - func testAssignKeyToTssVerifier() async throws { - let fakeEmail = generateRandomEmail(of: 6) - let verifierId = fakeEmail // faker random address - let nonce = 0 - let tssTag = "default" - let tssVerifierId = "\(verifierId)\u{0015}\(tssTag)\u{0016}\(nonce)" - - let nodeDetails = try await get_fnd_and_tu_data(verifer: TORUS_TEST_VERIFIER, veriferID: verifierId) - let keyData = try await torus.getPublicAddress(endpoints: nodeDetails.getTorusNodeSSSEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), verifier: TORUS_TEST_VERIFIER, verifierId: verifierId, extendedVerifierId: tssVerifierId) - XCTAssertNotEqual(keyData.finalKeyData?.evmAddress, nil) - XCTAssertNotEqual(keyData.finalKeyData?.evmAddress, "") - XCTAssertEqual(keyData.metadata?.typeOfUser, .v2) - XCTAssertEqual(keyData.metadata?.nonce, BigUInt("0")) - XCTAssertEqual(keyData.metadata?.upgraded, false) - } - - func testAllowTssVerifierIdFetchShare() async throws { - let email = generateRandomEmail(of: 6) // faker random address ??? - let verifierId = TORUS_TEST_EMAIL - let nonce = 0 - let tssTag = "default" - let tssVerifierId = "\(email)\u{0015}\(tssTag)\u{0016}\(nonce)" - - let token = try generateIdToken(email: email) - let nodeDetails = try await get_fnd_and_tu_data(verifer: TORUS_TEST_VERIFIER, veriferID: verifierId) - let verifierParams = VerifierParams(verifier_id: verifierId, extended_verifier_id: tssVerifierId) - - let result = try await torus.retrieveShares(endpoints: nodeDetails.getTorusNodeEndpoints(), - torusNodePubs: nodeDetails.getTorusNodePub(), indexes: nodeDetails.getTorusIndexes(), - verifier: TORUS_TEST_VERIFIER, verifierParams: verifierParams, idToken: token) - - XCTAssertNotEqual(result.finalKeyData?.privKey, nil) - XCTAssertNotEqual(result.finalKeyData?.evmAddress, nil) - XCTAssertEqual(result.metadata?.typeOfUser, .v2) - XCTAssertEqual(result.metadata?.nonce, BigUInt("0")) - XCTAssertEqual(result.metadata?.upgraded, true) - } - - func testFetchPubAdderessWhenHashEnabled() async throws { - let nodeDetails = try await get_fnd_and_tu_data(verifer: TORUS_TEST_VERIFIER, veriferID: HashEnabledVerifier) - let pubAddress = try await torus.getPublicAddress(endpoints: nodeDetails.getTorusNodeSSSEndpoints(), - torusNodePubs: nodeDetails.getTorusNodePub(), - verifier: HashEnabledVerifier, verifierId: TORUS_HASH_ENABLED_TEST_EMAIL) - XCTAssertEqual(pubAddress.oAuthKeyData!.evmAddress, "0x4135ad20D2E9ACF37D64E7A6bD8AC34170d51219") - XCTAssertEqual(pubAddress.oAuthKeyData!.X, "9c591943683c0e5675f99626cea84153a3c5b72c6e7840f8b8b53d0f2bb50c67") - XCTAssertEqual(pubAddress.oAuthKeyData!.Y, "9d9896d82e565a2d5d437745af6e4560f3564c2ac0d0edcb72e0b508b3ac05a0") - XCTAssertEqual(pubAddress.finalKeyData!.evmAddress, "0xF79b5ffA48463eba839ee9C97D61c6063a96DA03") - XCTAssertEqual(pubAddress.finalKeyData!.X, "21cd0ae3168d60402edb8bd65c58ff4b3e0217127d5bb5214f03f84a76f24d8a") - XCTAssertEqual(pubAddress.finalKeyData!.Y, "575b7a4d0ef9921b3b1b84f30d412e87bc69b4eab83f6706e247cceb9e985a1e") - XCTAssertEqual(pubAddress.metadata?.pubNonce?.x, "d6404befc44e3ab77a8387829d77e9c77a9c2fb37ae314c3a59bdc108d70349d") - XCTAssertEqual(pubAddress.metadata?.pubNonce?.y, "1054dfe297f1d977ccc436109cbcce64e95b27f93efc0f1dab739c9146eda2e") - XCTAssertEqual(pubAddress.metadata?.nonce, BigUInt.zero) - XCTAssertEqual(pubAddress.metadata?.upgraded, false) - XCTAssertEqual(pubAddress.metadata?.typeOfUser, UserType(rawValue: "v2")) - } - - func testLoginWhenHashEnabled() async throws { - let email = TORUS_TEST_EMAIL - let token = try generateIdToken(email: email) - let verifierParams = VerifierParams(verifier_id: email) - let nodeDetails = try await get_fnd_and_tu_data(verifer: HashEnabledVerifier, veriferID: HashEnabledVerifier) - let result = try await torus.retrieveShares(endpoints: nodeDetails.getTorusNodeSSSEndpoints(), - torusNodePubs: nodeDetails.getTorusNodePub(), indexes: nodeDetails.getTorusIndexes(), - verifier: HashEnabledVerifier, verifierParams: verifierParams, idToken: token) - XCTAssertEqual(result.finalKeyData?.evmAddress, "0x8a7e297e20804786767B1918a5CFa11683e5a3BB") - XCTAssertEqual(result.finalKeyData?.X, "7927d5281aea24fd93f41696f79c91370ec0097ff65e83e95691fffbde6d733a") - XCTAssertEqual(result.finalKeyData?.Y, "f22735f0e72ff225274cf499d50b240b7571063e0584471b2b4dab337ad5d8da") - XCTAssertEqual(result.finalKeyData?.privKey, "f161f63a84f1c935525ec0bda74bc5a15de6a9a7be28fad237ef6162df335fe6") - XCTAssertEqual(result.oAuthKeyData?.evmAddress, "0xaEafa3Fc7349E897F8fCe981f55bbD249f12aC8C") - XCTAssertEqual(result.oAuthKeyData?.X, "72d9172d7edc623266d6c625db91505e6b64a5524e6d7c7c0184b1bbdea1e986") - XCTAssertEqual(result.oAuthKeyData?.Y, "8c26d557a0a9cb22dc2a30d36bf67de93a0eb6d4ef503a849c7de2d14dcbdaaa") - XCTAssertEqual(result.oAuthKeyData?.privKey, "62e110d9d698979c1966d14b2759006cf13be7dfc86a63ff30812e2032163f2f") - XCTAssertNotEqual(result.sessionData?.sessionTokenData.count, 0) - XCTAssertNotEqual(result.sessionData?.sessionAuthKey, "") - XCTAssertEqual(result.metadata?.pubNonce?.x, "5712d789f7ecf3435dd9bf1136c2daaa634f0222d64e289d2abe30a729a6a22b") - XCTAssertEqual(result.metadata?.pubNonce?.y, "2d2b4586fd5fd9d15c22f66b61bc475742754a8b96d1edb7b2590e4c4f97b3f0") - XCTAssertEqual(result.metadata?.nonce?.serialize().toHexString(), "8e80e560ae59319938f7ef727ff2c5346caac1c7f5be96d3076e3342ad1d20b7") - XCTAssertEqual(result.metadata?.typeOfUser, .v2) - XCTAssertEqual(result.metadata?.upgraded, false) - } - - func testAggregrateLoginWithEmail(email: String) async throws { - let verifier: String = TORUS_TEST_AGGREGATE_VERIFIER - let verifierID: String = email - let jwt = try! generateIdToken(email: email) - let hashedIDToken = keccak256Data(jwt.data(using: .utf8) ?? Data()).toHexString() - let extraParams = ["verifier_id": email, "sub_verifier_ids": [TORUS_TEST_VERIFIER], "verify_params": [["verifier_id": email, "idtoken": jwt]]] as [String: Codable] - - let nodeManager = NodeDetailManager(network: .sapphire(.SAPPHIRE_DEVNET)) - let endpoint = try await nodeManager.getNodeDetails(verifier: HashEnabledVerifier, verifierID: verifierID) - - let verifierParams = VerifierParams(verifier_id: verifierID) - let nodeDetails = try await get_fnd_and_tu_data(verifer: verifier, veriferID: verifierID) - - let data = try await torus.retrieveShares(endpoints: endpoint.torusNodeEndpoints, torusNodePubs: nodeDetails.getTorusNodePub(), indexes: nodeDetails.getTorusIndexes(), verifier: verifier, verifierParams: verifierParams, idToken: hashedIDToken, extraParams: extraParams) - - XCTAssertNotNil(data.finalKeyData?.evmAddress) - XCTAssertNotEqual(data.finalKeyData?.evmAddress, "") - XCTAssertNotNil(data.oAuthKeyData?.evmAddress) - XCTAssertEqual(data.metadata?.typeOfUser == UserType.v2, true) - XCTAssertNotNil(data.metadata?.nonce) - XCTAssertEqual(data.metadata?.upgraded, false) - } - - func testAggregateLoginWithFixedEmail() async throws { - // This fixed email was previously known to trigger an edge case that - // revealed a bug in our share decryption implementation. - let email = "hEJTRg@gmail.com" - try await testAggregrateLoginWithEmail(email: email) - } - - /* TODO: Investigate further - func testAggregateLoginWithRandomEmail() async throws { - let email = generateRandomEmail(of: 6) - try await testAggregrateLoginWithEmail(email: email) - } - */ - - - func testGating() async throws { - let torus = TorusUtils(enableOneKey: true, network: .sapphire(.SAPPHIRE_MAINNET), clientId: "YOUR_CLIENT_ID") - let token = try generateIdToken(email: TORUS_TEST_EMAIL) - - let verifierParams = VerifierParams(verifier_id: TORUS_TEST_EMAIL) - - let nodeDetails = try await get_fnd_and_tu_data(verifer: "w3a-auth0-demo", veriferID: TORUS_TEST_EMAIL) - - do { - _ = try await torus.retrieveShares( - endpoints: nodeDetails.getTorusNodeEndpoints(), - torusNodePubs: nodeDetails.getTorusNodePub(), - indexes: nodeDetails.getTorusIndexes(), - verifier: "w3a-auth0-demo", - verifierParams: verifierParams, - idToken: token - ) - XCTAssert(false, "Should not pass") - } catch { - XCTAssertEqual(error.localizedDescription.errorDescription!,"code: 1001, error: Invalid Web3Auth client id, obtain a client ID at https://dashboard.web3auth.io") - } - - } - - func testencryption() async throws { - let torus = TorusUtils(enableOneKey: true, network: .sapphire(.SAPPHIRE_MAINNET), clientId: "YOUR_CLIENT_ID") - - let pk = curveSecp256k1.SecretKey() - let pk_str = try pk.serialize() - - let msg = "hello test data" - let encryptData = try torus.encrypt(publicKey: pk.toPublic().serialize(compressed: false), msg: msg) - - let curveMsg = try Encryption.encrypt(pk: pk.toPublic(), plainText: msg.data(using: .utf8)!) - let em = try EncryptedMessage(cipherText: encryptData.ciphertext, ephemeralPublicKey: PublicKey(hex: encryptData.ephemPublicKey) , iv: encryptData.iv, mac: encryptData.mac) - - let eciesData = ECIES(iv: encryptData.iv, ephemPublicKey: encryptData.ephemPublicKey, ciphertext: encryptData.ciphertext, mac: encryptData.mac) - let emp = try curveMsg.ephemeralPublicKey().serialize(compressed: false); - let eciesData2 = try ECIES(iv: curveMsg.iv(), ephemPublicKey: emp, ciphertext: curveMsg.chipherText(), mac: curveMsg.mac()) - - _ = try torus.decrypt(privateKey: pk_str, opts: eciesData) - _ = try torus.decrypt(privateKey: pk_str, opts: eciesData2) - - let result = try Encryption.decrypt(sk: pk, encrypted: em) - let result2 = try Encryption.decrypt(sk: pk, encrypted: curveMsg) - - XCTAssertEqual(msg.data(using: .utf8)!, result) - XCTAssertEqual(msg.data(using: .utf8)!, result2) - - } - -} diff --git a/Tests/TorusUtilsTests/StubURLProtocolTest.swift b/Tests/TorusUtilsTests/StubURLProtocolTest.swift deleted file mode 100644 index 4b48764f..00000000 --- a/Tests/TorusUtilsTests/StubURLProtocolTest.swift +++ /dev/null @@ -1,19 +0,0 @@ -import FetchNodeDetails -import Foundation -import OSLog -import TorusUtils -import XCTest - -final class StubURLProtocolTests: XCTestCase {} - -public class StubMockTorusUtils: TorusUtils { - override open func getTimestamp() -> TimeInterval { - let ret = 0.0 - print("[StubMockTorusUtils] getTimeStamp(): ", ret) - return ret - } -} - -let endpoints = ["https://teal-15-1.torusnode.com/jrpc", "https://teal-15-3.torusnode.com/jrpc", "https://teal-15-4.torusnode.com/jrpc", "https://teal-15-5.torusnode.com/jrpc", "https://teal-15-2.torusnode.com/jrpc"] - -let nodePubKeys = [TorusNodePubModel(_X: "1363aad8868cacd7f8946c590325cd463106fb3731f08811ab4302d2deae35c3", _Y: "d77eebe5cdf466b475ec892d5b4cffbe0c1670525debbd97eee6dae2f87a7cbe"), TorusNodePubModel(_X: "7c8cc521c48690f016bea593f67f88ad24f447dd6c31bbab541e59e207bf029d", _Y: "b359f0a82608db2e06b953b36d0c9a473a00458117ca32a5b0f4563a7d539636"), TorusNodePubModel(_X: "8a86543ca17df5687719e2549caa024cf17fe0361e119e741eaee668f8dd0a6f", _Y: "9cdb254ff915a76950d6d13d78ef054d5d0dc34e2908c00bb009a6e4da701891"), TorusNodePubModel(_X: "25a98d9ae006aed1d77e81d58be8f67193d13d01a9888e2923841894f4b0bf9c", _Y: "f63d40df480dacf68922004ed36dbab9e2969181b047730a5ce0797fb6958249"), TorusNodePubModel(_X: "d908f41f8e06324a8a7abcf702adb6a273ce3ae63d86a3d22723e1bbf1438c9a", _Y: "f977530b3ec0e525438c72d1e768380cbc5fb3b38a760ee925053b2e169428ce")] diff --git a/Tests/TorusUtilsTests/TestnetTest.swift b/Tests/TorusUtilsTests/TestnetTest.swift index 003b5a88..9b1c9f9e 100644 --- a/Tests/TorusUtilsTests/TestnetTest.swift +++ b/Tests/TorusUtilsTests/TestnetTest.swift @@ -1,34 +1,31 @@ import BigInt import FetchNodeDetails import JWTKit +import TorusUtils import XCTest -import CoreMedia -@testable import TorusUtils - class TestnetTest: XCTestCase { var TORUS_TEST_EMAIL = "archit1@tor.us" var TORUS_TEST_VERIFIER = "torus-test-health" var TORUS_TEST_AGGREGATE_VERIFIER = "torus-test-health-aggregate" var fnd: NodeDetailManager! - var tu: TorusUtils! + var torus: TorusUtils! override func setUp() { super.setUp() fnd = NodeDetailManager(network: .legacy(.TESTNET)) + torus = try! TorusUtils(params: TorusOptions(clientId: "YOUR_CLIENT_ID", network: .legacy(.TESTNET))) } - func getFNDAndTUData(verifer: String, veriferID: String, enableOneKey: Bool = false) async throws -> AllNodeDetailsModel { - let nodeDetails = try await fnd.getNodeDetails(verifier: verifer, verifierID: veriferID) - tu = TorusUtils(enableOneKey: enableOneKey, network: .legacy(.TESTNET), clientId: "YOUR_CLIENT_ID") - return nodeDetails - } + func test_should_fetch_public_address() async throws { + let verifier = "google-lrc" + let verifierID = TORUS_TEST_EMAIL + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + let val = try await torus.getPublicAddress(endpoints: nodeDetails.torusNodeEndpoints, verifier: verifier, verifierId: verifierID) + + XCTAssertEqual(val.finalKeyData!.evmAddress, "0x9bcBAde70546c0796c00323CD1b97fa0a425A506") + XCTAssertLessThan(val.metadata!.serverTimeOffset, 20) - func test_get_public_address() async throws { - let verifier: String = "google-lrc" - let verifierID: String = TORUS_TEST_EMAIL - let nodeDetails = try await getFNDAndTUData(verifer: verifier, veriferID: verifierID) - let val = try await tu.getPublicAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), verifier: verifier, verifierId: verifierID) XCTAssertEqual(val.finalKeyData!.evmAddress, "0x9bcBAde70546c0796c00323CD1b97fa0a425A506") XCTAssertEqual(val.finalKeyData!.X, "894f633b3734ddbf08867816bc55da60803c1e7c2a38b148b7fb2a84160a1bb5") XCTAssertEqual(val.finalKeyData!.Y, "1cf2ea7ac63ee1a34da2330413692ba8538bf7cd6512327343d918e0102a1438") @@ -38,104 +35,138 @@ class TestnetTest: XCTestCase { XCTAssertNil(val.metadata?.pubNonce) XCTAssertEqual(val.metadata?.nonce, 0) XCTAssertEqual(val.metadata?.upgraded, false) - XCTAssertEqual(val.metadata?.typeOfUser, UserType(rawValue: "v1")) + XCTAssertEqual(val.metadata?.typeOfUser, .v1) + XCTAssertNotNil(val.nodesData) } - func test_getUserTypeAndAddress_testnet() async throws { - let verifier: String = "google-lrc" - let verifierID: String = TORUS_TEST_EMAIL - let nodeDetails = try await getFNDAndTUData(verifer: verifier, veriferID: verifierID) - let val = try await tu.getUserTypeAndAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), verifier: verifier, verifierId: verifierID) + func test_should_fetch_user_type_and_public_address() async throws { + var verifier: String = "google-lrc" + var verifierID: String = TORUS_TEST_EMAIL + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + var val = try await torus.getUserTypeAndAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierId: verifierID) + + XCTAssertEqual(val.finalKeyData!.evmAddress, "0xf5804f608C233b9cdA5952E46EB86C9037fd6842") + XCTAssertLessThan(val.metadata!.serverTimeOffset, 20) + XCTAssertEqual(val.oAuthKeyData!.evmAddress, "0x9bcBAde70546c0796c00323CD1b97fa0a425A506") XCTAssertEqual(val.oAuthKeyData!.X, "894f633b3734ddbf08867816bc55da60803c1e7c2a38b148b7fb2a84160a1bb5") XCTAssertEqual(val.oAuthKeyData!.Y, "1cf2ea7ac63ee1a34da2330413692ba8538bf7cd6512327343d918e0102a1438") - XCTAssertEqual(val.finalKeyData!.evmAddress, "0xf5804f608C233b9cdA5952E46EB86C9037fd6842") XCTAssertEqual(val.finalKeyData!.X, "ed737569a557b50722a8b5c0e4e5ca30cef1ede2f5674a0616b78246bb93dfd0") XCTAssertEqual(val.finalKeyData!.Y, "d9e8e6c54c12c4da38c2f0d1047fcf6089036127738f4ef72a83431339586ca9") - XCTAssertEqual(val.metadata?.pubNonce?.x, "f3f7caefd6540d923c9993113f34226371bd6714a5be6882dedc95a6a929a8") - XCTAssertEqual(val.metadata?.pubNonce?.y, "f28620603601ce54fa0d70fd691fb72ff52f5bf164bf1a91617922eaad8cc7a5") + XCTAssertEqual(val.metadata!.pubNonce!.x, "f3f7caefd6540d923c9993113f34226371bd6714a5be6882dedc95a6a929a8") + XCTAssertEqual(val.metadata!.pubNonce!.y, "f28620603601ce54fa0d70fd691fb72ff52f5bf164bf1a91617922eaad8cc7a5") XCTAssertEqual(val.metadata?.nonce, 0) XCTAssertEqual(val.metadata?.upgraded, false) XCTAssertEqual(val.metadata?.typeOfUser, .v2) + + verifier = "tkey-google-lrc" + verifierID = "somev2user@gmail.com" + val = try await torus.getUserTypeAndAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierId: verifierID) + + XCTAssertEqual(val.finalKeyData!.evmAddress, "0xE91200d82029603d73d6E307DbCbd9A7D0129d8D") + XCTAssertLessThan(val.metadata!.serverTimeOffset, 20) + + XCTAssertEqual(val.oAuthKeyData!.evmAddress, "0x376597141d8d219553378313d18590F373B09795") + XCTAssertEqual(val.oAuthKeyData!.X, "86cd2db15b7a9937fa8ab7d0bf8e7f4113b64d1f4b2397aad35d6d4749d2fb6c") + XCTAssertEqual(val.oAuthKeyData!.Y, "86ef47a3724144331c31a3a322d85b6fc1a5d113b41eaa0052053b6e3c74a3e2") + XCTAssertEqual(val.finalKeyData!.evmAddress, "0xE91200d82029603d73d6E307DbCbd9A7D0129d8D") + XCTAssertEqual(val.finalKeyData!.X, "c350e338dde24df986915992fea6e0aef3560c245ca144ee7fe1498784c4ef4e") + XCTAssertEqual(val.finalKeyData!.Y, "a605e52b65d3635f89654519dfa7e31f7b45f206ef4189866ad0c2240d40f97f") + XCTAssertEqual(val.metadata?.pubNonce?.x, "ad121b67fa550da814bbbd54ec7070705d058c941e04c03e07967b07b2f90345") + XCTAssertEqual(val.metadata?.pubNonce?.y, "bfe2395b177a72ebb836aaf24cedff2f14cd9ed49047990f5cdb99e4981b5753") + XCTAssertEqual(val.metadata?.nonce, 0) + XCTAssertEqual(val.metadata?.upgraded, false) + XCTAssertEqual(val.metadata?.typeOfUser, .v2) + XCTAssertNotNil(val.nodesData) + + verifier = "tkey-google-lrc" + verifierID = "caspertorus@gmail.com" + val = try await torus.getUserTypeAndAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierId: verifierID) + + XCTAssertEqual(val.finalKeyData!.evmAddress, "0x1016DA7c47A04C76036637Ea02AcF1d29c64a456") + XCTAssertLessThan(val.metadata!.serverTimeOffset, 20) + + XCTAssertEqual(val.oAuthKeyData!.evmAddress, "0xd45383fbF04BccFa0450d7d8ee453ca86b7C6544") + XCTAssertEqual(val.oAuthKeyData!.X, "d25cc473fbb448d20b5551f3c9aa121e1924b3d197353347187c47ad13ecd5d8") + XCTAssertEqual(val.oAuthKeyData!.Y, "3394000f43160a925e6c3017dde1354ecb2b61739571c6584f58edd6b923b0f5") + XCTAssertEqual(val.finalKeyData!.evmAddress, "0x1016DA7c47A04C76036637Ea02AcF1d29c64a456") + XCTAssertEqual(val.finalKeyData!.X, "d3e222f6b23f0436b7c86e9cc4164eb5ea8448e4c0e7539c8b4f7fd00e8ec5c7") + XCTAssertEqual(val.finalKeyData!.Y, "1c47f5faccec6cf57c36919f6f0941fe3d8d65033cf2cc78f209304386044222") + XCTAssertEqual(val.metadata?.pubNonce?.x, "4f86b0e69992d1551f1b16ceb0909453dbe17b9422b030ee6c5471c2e16b65d0") + XCTAssertEqual(val.metadata?.pubNonce?.y, "640384f3d39debb04c4e9fe5a5ec6a1b494b0ad66d00ac9be6f166f21d116ca4") + XCTAssertEqual(val.metadata?.nonce, 0) + XCTAssertEqual(val.metadata?.upgraded, true) + XCTAssertEqual(val.metadata?.typeOfUser, .v2) + XCTAssertNotNil(val.nodesData) } - /* TODO: Investigate further - func test_key_assign_testnet() async throws { + func test_should_be_able_to_key_assign() async throws { let fakeEmail = generateRandomEmail(of: 6) let verifier: String = "google-lrc" let verifierID: String = fakeEmail - let nodeDetails = try await getFNDAndTUData(verifer: verifier, veriferID: verifierID) - let data = try await tu.getPublicAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), verifier: verifier, verifierId: verifierID) - XCTAssertNotNil(data.finalKeyData) + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + let data = try await torus.getPublicAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierId: verifierID) XCTAssertNotEqual(data.finalKeyData?.evmAddress, "") + XCTAssertNotEqual(data.oAuthKeyData?.evmAddress, "") XCTAssertEqual(data.metadata?.typeOfUser, .v1) + XCTAssertEqual(data.metadata?.upgraded, false) } - */ - func test_login_testnet() async throws { + func test_should_be_able_to_login() async throws { let verifier: String = TORUS_TEST_VERIFIER let verifierID: String = TORUS_TEST_EMAIL - let verifierParams = VerifierParams(verifier_id: verifierID) let jwt = try! generateIdToken(email: verifierID) - let extraParams = ["verifieridentifier": verifier, "verifier_id": verifierID] as [String: Codable] - let nodeDetails = try await getFNDAndTUData(verifer: verifier, veriferID: verifierID) - let data = try await tu.retrieveShares(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), indexes: nodeDetails.getTorusIndexes(), verifier: verifier, verifierParams: verifierParams, idToken: jwt, extraParams: extraParams) - - XCTAssertEqual(data.finalKeyData?.evmAddress, "0xF8d2d3cFC30949C1cb1499C9aAC8F9300535a8d6") - XCTAssertEqual(data.finalKeyData?.X, "6de2e34d488dd6a6b596524075b032a5d5eb945bcc33923ab5b88fd4fd04b5fd") - XCTAssertEqual(data.finalKeyData?.Y, "d5fb7b51b846e05362461357ec6e8ca075ea62507e2d5d7253b72b0b960927e9") - XCTAssertEqual(data.finalKeyData?.privKey, "9b0fb017db14a0a25ed51f78a258713c8ae88b5e58a43acb70b22f9e2ee138e3") - XCTAssertEqual(data.oAuthKeyData?.evmAddress, "0xF8d2d3cFC30949C1cb1499C9aAC8F9300535a8d6") - XCTAssertEqual(data.oAuthKeyData?.X, "6de2e34d488dd6a6b596524075b032a5d5eb945bcc33923ab5b88fd4fd04b5fd") - XCTAssertEqual(data.oAuthKeyData?.Y, "d5fb7b51b846e05362461357ec6e8ca075ea62507e2d5d7253b72b0b960927e9") - XCTAssertEqual(data.oAuthKeyData?.privKey, "9b0fb017db14a0a25ed51f78a258713c8ae88b5e58a43acb70b22f9e2ee138e3") - XCTAssertEqual(data.sessionData?.sessionTokenData.count, 0) - XCTAssertEqual(data.sessionData?.sessionAuthKey, "") - XCTAssertEqual(data.metadata?.pubNonce, nil) - XCTAssertEqual(data.metadata?.nonce, BigUInt(0)) - XCTAssertEqual(data.metadata?.typeOfUser, .v1) - XCTAssertEqual(data.metadata?.upgraded, nil) + let verifierParams = VerifierParams(verifier_id: verifierID) + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + let data = try await torus.retrieveShares(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierParams: verifierParams, idToken: jwt) + + XCTAssertEqual(data.finalKeyData.evmAddress, "0xF8d2d3cFC30949C1cb1499C9aAC8F9300535a8d6") + XCTAssertLessThan(data.metadata.serverTimeOffset, 20) + + XCTAssertEqual(data.oAuthKeyData.evmAddress, "0xF8d2d3cFC30949C1cb1499C9aAC8F9300535a8d6") + XCTAssertEqual(data.oAuthKeyData.X, "6de2e34d488dd6a6b596524075b032a5d5eb945bcc33923ab5b88fd4fd04b5fd") + XCTAssertEqual(data.oAuthKeyData.Y, "d5fb7b51b846e05362461357ec6e8ca075ea62507e2d5d7253b72b0b960927e9") + XCTAssertEqual(data.oAuthKeyData.privKey, "9b0fb017db14a0a25ed51f78a258713c8ae88b5e58a43acb70b22f9e2ee138e3") + XCTAssertEqual(data.finalKeyData.evmAddress, "0xF8d2d3cFC30949C1cb1499C9aAC8F9300535a8d6") + XCTAssertEqual(data.finalKeyData.X, "6de2e34d488dd6a6b596524075b032a5d5eb945bcc33923ab5b88fd4fd04b5fd") + XCTAssertEqual(data.finalKeyData.Y, "d5fb7b51b846e05362461357ec6e8ca075ea62507e2d5d7253b72b0b960927e9") + XCTAssertEqual(data.finalKeyData.privKey, "9b0fb017db14a0a25ed51f78a258713c8ae88b5e58a43acb70b22f9e2ee138e3") + XCTAssertNotNil(data.sessionData) + XCTAssertNil(data.metadata.pubNonce) + XCTAssertEqual(data.metadata.nonce, BigUInt(0)) + XCTAssertEqual(data.metadata.typeOfUser, .v1) + XCTAssertNil(data.metadata.upgraded) + XCTAssertNotNil(data.nodesData) } - func test_aggregate_login_testnet() async throws { + func test_should_be_able_to_aggregate_login() async throws { let verifier: String = TORUS_TEST_AGGREGATE_VERIFIER let verifierID: String = TORUS_TEST_EMAIL - let verifierParams = VerifierParams(verifier_id: verifierID) let jwt = try! generateIdToken(email: TORUS_TEST_EMAIL) - let hashedIDToken = keccak256Data(jwt.data(using: .utf8) ?? Data() ).toHexString() - let extraParams = ["verifier_id": TORUS_TEST_EMAIL, "sub_verifier_ids": [TORUS_TEST_VERIFIER], "verify_params": [["verifier_id": TORUS_TEST_EMAIL, "idtoken": jwt]]] as [String: Codable] - let nodeDetails = try await getFNDAndTUData(verifer: verifier, veriferID: verifierID) - let data = try await tu.retrieveShares(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), indexes: nodeDetails.getTorusIndexes(), verifier: verifier, verifierParams: verifierParams, idToken: hashedIDToken, extraParams: extraParams) - XCTAssertEqual(data.finalKeyData?.evmAddress, "0x938a40E155d118BD31E439A9d92D67bd55317965") - XCTAssertEqual(data.finalKeyData?.X, "1c50e34ef5b7afcf5b0c6501a6ae00ec3a09a321dd885c5073dd122e2a251b95") - XCTAssertEqual(data.finalKeyData?.Y, "2cc74beb28f2c4a7c4034f80836d51b2781b36fefbeafb4eb1cd055bdf73b1e6") - XCTAssertEqual(data.finalKeyData?.privKey, "3cbfa57d702327ec1af505adc88ad577804a1a7780bc013ed9e714c547fb5cb1") - XCTAssertEqual(data.oAuthKeyData?.evmAddress, "0x938a40E155d118BD31E439A9d92D67bd55317965") - XCTAssertEqual(data.oAuthKeyData?.X, "1c50e34ef5b7afcf5b0c6501a6ae00ec3a09a321dd885c5073dd122e2a251b95") - XCTAssertEqual(data.oAuthKeyData?.Y, "2cc74beb28f2c4a7c4034f80836d51b2781b36fefbeafb4eb1cd055bdf73b1e6") - XCTAssertEqual(data.oAuthKeyData?.privKey, "3cbfa57d702327ec1af505adc88ad577804a1a7780bc013ed9e714c547fb5cb1") - XCTAssertEqual(data.sessionData?.sessionTokenData.count, 0) - XCTAssertEqual(data.sessionData?.sessionAuthKey, "") - XCTAssertEqual(data.metadata?.pubNonce, nil) - XCTAssertEqual(data.metadata?.nonce, BigUInt(0)) - XCTAssertEqual(data.metadata?.typeOfUser, .v1) - XCTAssertEqual(data.metadata?.upgraded, nil) - } -} + let hashedIDToken = try KeyUtils.keccak256Data(jwt) + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) -extension TestnetTest { - func test_retrieveShares_some_nodes_down() async throws { - let verifier: String = TORUS_TEST_VERIFIER - let verifierID: String = TORUS_TEST_EMAIL - let verifierParams = VerifierParams(verifier_id: verifierID) - let jwt = try! generateIdToken(email: verifierID) - let extraParams = ["verifieridentifier": verifier, "verifier_id": verifierID] as [String: Codable] - let nodeDetails = try await getFNDAndTUData(verifer: verifier, veriferID: verifierID) - var endpoints = nodeDetails.getTorusNodeEndpoints() - endpoints[0] = "https://ndjnfjbfrj/random" - // should fail if un-commented threshold 4/5 - // endpoints[1] = "https://ndjnfjbfrj/random" - let data = try await tu.retrieveShares(endpoints: endpoints, torusNodePubs: nodeDetails.getTorusNodePub(), indexes: nodeDetails.getTorusIndexes(), verifier: verifier, verifierParams: verifierParams, idToken: jwt, extraParams: extraParams) - XCTAssertEqual(data.finalKeyData?.privKey, "9b0fb017db14a0a25ed51f78a258713c8ae88b5e58a43acb70b22f9e2ee138e3") + let verifierParams = VerifierParams(verifier_id: verifierID, + sub_verifier_ids: [TORUS_TEST_VERIFIER], + verify_params: [VerifyParams(verifier_id: verifierID, idtoken: jwt)]) + let data = try await torus.retrieveShares(endpoints: nodeDetails.torusNodeEndpoints, verifier: verifier, verifierParams: verifierParams, idToken: hashedIDToken) + + XCTAssertEqual(data.finalKeyData.evmAddress, "0x938a40E155d118BD31E439A9d92D67bd55317965") + XCTAssertLessThan(data.metadata.serverTimeOffset, 20) + + XCTAssertEqual(data.oAuthKeyData.evmAddress, "0x938a40E155d118BD31E439A9d92D67bd55317965") + XCTAssertEqual(data.oAuthKeyData.X, "1c50e34ef5b7afcf5b0c6501a6ae00ec3a09a321dd885c5073dd122e2a251b95") + XCTAssertEqual(data.oAuthKeyData.Y, "2cc74beb28f2c4a7c4034f80836d51b2781b36fefbeafb4eb1cd055bdf73b1e6") + XCTAssertEqual(data.oAuthKeyData.privKey, "3cbfa57d702327ec1af505adc88ad577804a1a7780bc013ed9e714c547fb5cb1") + XCTAssertEqual(data.finalKeyData.evmAddress, "0x938a40E155d118BD31E439A9d92D67bd55317965") + XCTAssertEqual(data.finalKeyData.X, "1c50e34ef5b7afcf5b0c6501a6ae00ec3a09a321dd885c5073dd122e2a251b95") + XCTAssertEqual(data.finalKeyData.Y, "2cc74beb28f2c4a7c4034f80836d51b2781b36fefbeafb4eb1cd055bdf73b1e6") + XCTAssertEqual(data.finalKeyData.privKey, "3cbfa57d702327ec1af505adc88ad577804a1a7780bc013ed9e714c547fb5cb1") + XCTAssertNotNil(data.sessionData) + XCTAssertNil(data.metadata.pubNonce) + XCTAssertEqual(data.metadata.nonce, BigUInt(0)) + XCTAssertEqual(data.metadata.typeOfUser, .v1) + XCTAssertNil(data.metadata.upgraded) + XCTAssertNotNil(data.nodesData) } } diff --git a/Tests/TorusUtilsTests/Utils/MockTorusUtils.swift b/Tests/TorusUtilsTests/Utils/MockTorusUtils.swift deleted file mode 100644 index 3dccf9cf..00000000 --- a/Tests/TorusUtilsTests/Utils/MockTorusUtils.swift +++ /dev/null @@ -1,41 +0,0 @@ -import BigInt -import FetchNodeDetails -import Foundation -import TorusUtils - -class MockTorusUtils: AbstractTorusUtils { - func retrieveShares(endpoints: [String], torusNodePubs: [TorusNodePubModel], indexes: [BigUInt], verifier: String, verifierParams: VerifierParams, idToken: String, extraParams: [String: Codable]) async throws -> TorusKey { - return TorusKey(finalKeyData: nil, oAuthKeyData: nil, sessionData: nil, metadata: nil, nodesData: nil) - } - - func getPublicAddress(endpoints: [String], torusNodePubs: [TorusNodePubModel], verifier: String, verifierId: String, extendedVerifierId: String?) async throws -> TorusPublicKey { -// GetPublicAddressResult(address: "") - return TorusPublicKey(finalKeyData: nil, oAuthKeyData: nil, metadata: nil, nodesData: nil) - } - - var nodePubKeys: [TorusNodePubModel] - - init() { - nodePubKeys = [] - } - - func setTorusNodePubKeys(nodePubKeys: [TorusNodePubModel]) { - self.nodePubKeys = nodePubKeys - } - - func retrieveShares(torusNodePubs: [TorusNodePubModel], endpoints: [String], verifier: String, verifierId: String, idToken: String, extraParams: Data) async throws -> RetrieveSharesResponseModel { - return .init(publicKey: "", privateKey: "") - } - - func getPublicAddress(endpoints: [String], torusNodePubs: [TorusNodePubModel], verifier: String, verifierId: String, isExtended: Bool) async throws -> GetPublicAddressResult { - return .init(address: "") - } - - func getUserTypeAndAddress(endpoints: [String], torusNodePub: [TorusNodePubModel], verifier: String, verifierID: String, doesKeyAssign: Bool) async throws -> GetUserAndAddress { - return .init(typeOfUser: .v1, address: "", x: "", y: "") - } - - func getOrSetNonce(x: String, y: String, privateKey: String?, getOnly: Bool) async throws -> GetOrSetNonceResult { - return GetOrSetNonceResult(typeOfUser: "v1") - } -} diff --git a/Tests/TorusUtilsTests/Utils/StubURLProtocol.swift b/Tests/TorusUtilsTests/Utils/StubURLProtocol.swift deleted file mode 100644 index 13204c0a..00000000 --- a/Tests/TorusUtilsTests/Utils/StubURLProtocol.swift +++ /dev/null @@ -1,518 +0,0 @@ -import Foundation - -private func mustDecodeJSON(_ s: String) -> [String: Any] { - return try! JSONSerialization.jsonObject(with: Data(s.utf8), options: []) as! [String: Any] -} - -private func httpBodyStreamToData(stream: InputStream?) -> Data? { - guard let bodyStream = stream else { return nil } - bodyStream.open() - - // Will read 16 chars per iteration. Can use bigger buffer if needed - let bufferSize: Int = 16 - - let buffer = UnsafeMutablePointer.allocate(capacity: bufferSize) - - var dat = Data() - - while bodyStream.hasBytesAvailable { - let readDat = bodyStream.read(buffer, maxLength: bufferSize) - dat.append(buffer, count: readDat) - } - - buffer.deallocate() - - bodyStream.close() - - return dat -} - -private func stubMatcher(host: String, scheme: String, path: String, method: String, requestHeaders: [String: String]) -> (URLRequest) -> Bool { - return { (req: URLRequest) -> Bool in - if req.url?.host != host || req.url?.scheme != scheme || req.url?.path != path || req.httpMethod != method { - return false - } - for (name, value) in requestHeaders { - if req.value(forHTTPHeaderField: name) != value { - return false - } - } - return true - } -} - -private func stubMatcherWithBody(host: String, scheme: String, path: String, method: String, requestHeaders: [String: String], body: [String: Any]) -> (URLRequest) -> Bool { - return { (req: URLRequest) -> Bool in - if !stubMatcher(host: host, scheme: scheme, path: path, method: method, requestHeaders: requestHeaders)(req) { - return false - } - guard - let bodyData = StubURLProtocol.property(forKey: httpBodyKey, in: req) as? Data, - let jsonBody = (try? JSONSerialization.jsonObject(with: bodyData, options: [])) as? [String: Any] - else { - return false - } - return NSDictionary(dictionary: jsonBody).isEqual(to: body) - } -} - -private let injectedURLs: Set = [ - URL(string: "https://www.googleapis.com/userinfo/v2/me"), - URL(string: "https://ropsten.infura.io/v3/b8cdb0e4cff24599a286bf8e87ff1c96"), - URL(string: "https://teal-15-4.torusnode.com/jrpc"), - URL(string: "https://teal-15-2.torusnode.com/jrpc"), - URL(string: "https://teal-15-1.torusnode.com/jrpc"), - URL(string: "https://teal-15-3.torusnode.com/jrpc"), - URL(string: "https://teal-15-5.torusnode.com/jrpc"), - URL(string: "https://metadata.tor.us/get"), - URL(string: "https://signer.tor.us/api/allow"), -] - -private let httpBodyKey = "StubURLProtocolHTTPBody" - -private struct Stub { - let requestMatcher: (URLRequest) -> Bool - let responseBody: Data? - let statusCode: Int - let responseHeaders: [String: String] -} - -public class StubURLProtocol: URLProtocol { - private static let terminateUnknownRequest = true - - private static let stubs = injectedStubs - - private static let urls = injectedURLs - - // Match and return - private class func matchStub(req: URLRequest) -> Stub? { - var inputReq: URLRequest - if let httpBodyData = httpBodyStreamToData(stream: req.httpBodyStream) { - let mutableReq = (req as NSURLRequest).mutableCopy() as! NSMutableURLRequest - setProperty(httpBodyData, forKey: httpBodyKey, in: mutableReq) - inputReq = mutableReq as URLRequest - } else { - inputReq = req - } - for stub in stubs { - if stub.requestMatcher(inputReq) { - return stub - } - } - return nil - } - - // To check if this protocol can handle the given request. - override public class func canInit(with request: URLRequest) -> Bool { - var cleanURL: URL? { - var comp = URLComponents() - comp.scheme = request.url?.scheme - comp.host = request.url?.host - comp.path = request.url?.path ?? "/" - return comp.url - } - if urls.contains(cleanURL) { - return true - } - return terminateUnknownRequest - } - - override public class func canonicalRequest(for request: URLRequest) -> URLRequest { - return request - } - - // This is where you create the mock response as per your test case and send it to the URLProtocolClient. - override public func startLoading() { - guard let url = request.url else { - fatalError("Request has no URL") - } - var cleanURL: URL? { - var comp = URLComponents() - comp.scheme = url.scheme - comp.host = url.host - comp.path = url.path - return comp.url - } - if !StubURLProtocol.urls.contains(cleanURL) { - fatalError("URL not mocked, inconsistent injectedURLs: \(url.absoluteString)") - } - if let stub = StubURLProtocol.matchStub(req: request) { - let res = HTTPURLResponse(url: url, statusCode: stub.statusCode, httpVersion: nil, headerFields: stub.responseHeaders)! - client?.urlProtocol(self, didReceive: res, cacheStoragePolicy: .notAllowed) - if let d = stub.responseBody { - client?.urlProtocol(self, didLoad: d) - } - } else { - fatalError("URL not mocked: \(url.absoluteString)") - } - client?.urlProtocolDidFinishLoading(self) - } - - // This is called if the request gets canceled or completed. - override public func stopLoading() { - } -} - -private let injectedStubs: [Stub] = [ - Stub( - requestMatcher: stubMatcher( - host: "www.googleapis.com", - scheme: "https", - path: "/userinfo/v2/me", - method: "GET", - requestHeaders: mustDecodeJSON(#"{"Content-Type":"application/json","Authorization":"Bearer ya29.a0ARrdaM96u3PfVhg9xbkCPuecmF6YaylxRcJwKJTlHY8kwwuSyKbqme2qBbTdLoVORMZy4n8Al5Wr1HCnfjCesU38W1xkSgFNoPhRgTen6Zqxyr_tOddJw6-TUUbe45z6Zvkbx8DzBHShQkm-KbbNzh_M00kh","Accept":"application/json"}"#) as! [String: String] - ), - responseBody: Data(#"{"id":"109111953856031799639","email":"michael@tor.us","verified_email":true,"name":"Michael Lee","given_name":"Michael","family_name":"Lee","picture":"https://lh3.googleusercontent.com/a/AATXAJwsBb98gSYjVNlBBAhXJjvqNOw2GDSeTf0I6SJh=s96-c","locale":"en","hd":"tor.us"}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Date":"Sun, 17 Oct 2021 10:57:29 GMT","x-frame-options":"SAMEORIGIN","Pragma":"no-cache","x-xss-protection":"0","Content-Encoding":"gzip","Server":"ESF","Cache-Control":"no-cache, no-store, max-age=0, must-revalidate","Vary":"Origin, X-Origin, Referer","Alt-Svc":"h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-Q050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\"","x-content-type-options":"nosniff","Content-Length":"234","Content-Type":"application/json; charset=UTF-8","Expires":"Mon, 01 Jan 1990 00:00:00 GMT"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "ropsten.infura.io", - scheme: "https", - path: "/v3/b8cdb0e4cff24599a286bf8e87ff1c96", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Content-Type":"application/json","Accept":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"jsonrpc":"2.0","method":"eth_call","id":1,"params":[{"to":"0x4023d2a0d330bf11426b12c6144cfb96b7fa6183","data":"0x76671808"},"latest"]}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","id":1,"result":"0x000000000000000000000000000000000000000000000000000000000000000f"}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Vary":"Accept-Encoding, Origin","Date":"Sun, 17 Oct 2021 10:57:30 GMT","Content-Length":"102","Content-Type":"application/json"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "ropsten.infura.io", - scheme: "https", - path: "/v3/b8cdb0e4cff24599a286bf8e87ff1c96", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Content-Type":"application/json","Accept":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"jsonrpc":"2.0","method":"eth_call","id":1,"params":[{"to":"0x4023d2a0d330bf11426b12c6144cfb96b7fa6183","data":"0x135022c2000000000000000000000000000000000000000000000000000000000000000f"},"latest"]}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","id":1,"result":"0x000000000000000000000000000000000000000000000000000000000000000f00000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000005000000000000000000000000455d2ba3f20fa83b9f824e665dd201d908c79dce000000000000000000000000b452bbd6f4d52d87f33336aad921538bf8dfdf67000000000000000000000000e3c0493536f20d090c8f9427d8fdfe548af3266200000000000000000000000054ac312ed9ba51cdd65f182487f29a3999dbf4e200000000000000000000000057f7a525608dc540fefc3e851700a4189d19142d"}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Content-Length":"870","Vary":"Accept-Encoding, Origin","Content-Type":"application/json","Date":"Sun, 17 Oct 2021 10:57:31 GMT"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "ropsten.infura.io", - scheme: "https", - path: "/v3/b8cdb0e4cff24599a286bf8e87ff1c96", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Accept":"application/json","Content-Type":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"jsonrpc":"2.0","method":"eth_call","id":1,"params":[{"to":"0x4023d2a0d330bf11426b12c6144cfb96b7fa6183","data":"0xbafb358100000000000000000000000054ac312ed9ba51cdd65f182487f29a3999dbf4e2"},"latest"]}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","id":1,"result":"0x00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000425a98d9ae006aed1d77e81d58be8f67193d13d01a9888e2923841894f4b0bf9cf63d40df480dacf68922004ed36dbab9e2969181b047730a5ce0797fb695824900000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000001b7465616c2d31352d352e746f7275736e6f64652e636f6d3a343433000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Date":"Sun, 17 Oct 2021 10:57:31 GMT","Content-Type":"application/json","Content-Length":"678","Vary":"Accept-Encoding, Origin"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "ropsten.infura.io", - scheme: "https", - path: "/v3/b8cdb0e4cff24599a286bf8e87ff1c96", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Accept":"application/json","Content-Type":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"jsonrpc":"2.0","method":"eth_call","id":1,"params":[{"to":"0x4023d2a0d330bf11426b12c6144cfb96b7fa6183","data":"0xbafb3581000000000000000000000000455d2ba3f20fa83b9f824e665dd201d908c79dce"},"latest"]}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","id":1,"result":"0x00000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000011363aad8868cacd7f8946c590325cd463106fb3731f08811ab4302d2deae35c3d77eebe5cdf466b475ec892d5b4cffbe0c1670525debbd97eee6dae2f87a7cbe00000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000001b7465616c2d31352d312e746f7275736e6f64652e636f6d3a343433000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Vary":"Accept-Encoding, Origin","Date":"Sun, 17 Oct 2021 10:57:31 GMT","Content-Length":"678","Content-Type":"application/json"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "ropsten.infura.io", - scheme: "https", - path: "/v3/b8cdb0e4cff24599a286bf8e87ff1c96", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Content-Type":"application/json","Accept":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"jsonrpc":"2.0","method":"eth_call","id":1,"params":[{"to":"0x4023d2a0d330bf11426b12c6144cfb96b7fa6183","data":"0xbafb3581000000000000000000000000b452bbd6f4d52d87f33336aad921538bf8dfdf67"},"latest"]}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","id":1,"result":"0x00000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000027c8cc521c48690f016bea593f67f88ad24f447dd6c31bbab541e59e207bf029db359f0a82608db2e06b953b36d0c9a473a00458117ca32a5b0f4563a7d53963600000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000001b7465616c2d31352d332e746f7275736e6f64652e636f6d3a343433000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Date":"Sun, 17 Oct 2021 10:57:31 GMT","Vary":"Accept-Encoding, Origin","Content-Type":"application/json","Content-Length":"678"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "ropsten.infura.io", - scheme: "https", - path: "/v3/b8cdb0e4cff24599a286bf8e87ff1c96", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Accept":"application/json","Content-Type":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"jsonrpc":"2.0","method":"eth_call","id":1,"params":[{"to":"0x4023d2a0d330bf11426b12c6144cfb96b7fa6183","data":"0xbafb358100000000000000000000000057f7a525608dc540fefc3e851700a4189d19142d"},"latest"]}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","id":1,"result":"0x00000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000005d908f41f8e06324a8a7abcf702adb6a273ce3ae63d86a3d22723e1bbf1438c9af977530b3ec0e525438c72d1e768380cbc5fb3b38a760ee925053b2e169428ce00000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000001b7465616c2d31352d322e746f7275736e6f64652e636f6d3a343433000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Vary":"Accept-Encoding, Origin","Content-Length":"678","Content-Type":"application/json","Date":"Sun, 17 Oct 2021 10:57:31 GMT"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "ropsten.infura.io", - scheme: "https", - path: "/v3/b8cdb0e4cff24599a286bf8e87ff1c96", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Accept":"application/json","Content-Type":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"jsonrpc":"2.0","method":"eth_call","id":1,"params":[{"to":"0x4023d2a0d330bf11426b12c6144cfb96b7fa6183","data":"0xbafb3581000000000000000000000000e3c0493536f20d090c8f9427d8fdfe548af32662"},"latest"]}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","id":1,"result":"0x00000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000038a86543ca17df5687719e2549caa024cf17fe0361e119e741eaee668f8dd0a6f9cdb254ff915a76950d6d13d78ef054d5d0dc34e2908c00bb009a6e4da70189100000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000001b7465616c2d31352d342e746f7275736e6f64652e636f6d3a343433000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Date":"Sun, 17 Oct 2021 10:57:31 GMT","Content-Length":"678","Content-Type":"application/json","Vary":"Accept-Encoding, Origin"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "teal-15-4.torusnode.com", - scheme: "https", - path: "/jrpc", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Accept":"application/json","Content-Type":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"jsonrpc":"2.0","method":"VerifierLookupRequest","id":10,"params":{"verifier":"torus-direct-mock-ios","verifier_id":"michael@tor.us"}}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","result":{"keys":[{"key_index":"1c724","pub_key_X":"22d225892d5d149c0486bfb358b143568d1a951c39d5ada061a48c06c48afe39","pub_key_Y":"fcd9074bff4b5097489b79f951146d66bbcd05dc6acf68b8d0afc271fb73cf64","address":"0x22f2Ce611cE0d0ff4DA661d3a4C4B7A60B2b13F8"}]},"id":10}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Vary":"Origin","Server":"nginx/1.19.9","Content-Length":"281","Content-Type":"application/json","Date":"Sun, 17 Oct 2021 10:57:32 GMT"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "teal-15-2.torusnode.com", - scheme: "https", - path: "/jrpc", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Content-Type":"application/json","Accept":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"jsonrpc":"2.0","method":"VerifierLookupRequest","id":10,"params":{"verifier":"torus-direct-mock-ios","verifier_id":"michael@tor.us"}}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","result":{"keys":[{"key_index":"1c724","pub_key_X":"22d225892d5d149c0486bfb358b143568d1a951c39d5ada061a48c06c48afe39","pub_key_Y":"fcd9074bff4b5097489b79f951146d66bbcd05dc6acf68b8d0afc271fb73cf64","address":"0x22f2Ce611cE0d0ff4DA661d3a4C4B7A60B2b13F8"}]},"id":10}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Vary":"Origin","Server":"nginx/1.19.9","Content-Length":"281","Content-Type":"application/json","Date":"Sun, 17 Oct 2021 10:57:32 GMT"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "teal-15-1.torusnode.com", - scheme: "https", - path: "/jrpc", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Accept":"application/json","Content-Type":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"jsonrpc":"2.0","method":"VerifierLookupRequest","id":10,"params":{"verifier":"torus-direct-mock-ios","verifier_id":"michael@tor.us"}}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","result":{"keys":[{"key_index":"1c724","pub_key_X":"22d225892d5d149c0486bfb358b143568d1a951c39d5ada061a48c06c48afe39","pub_key_Y":"fcd9074bff4b5097489b79f951146d66bbcd05dc6acf68b8d0afc271fb73cf64","address":"0x22f2Ce611cE0d0ff4DA661d3a4C4B7A60B2b13F8"}]},"id":10}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Content-Length":"281","Vary":"Origin","Content-Type":"application/json","Server":"nginx/1.19.9","Date":"Sun, 17 Oct 2021 10:57:32 GMT"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "teal-15-3.torusnode.com", - scheme: "https", - path: "/jrpc", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Accept":"application/json","Content-Type":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"jsonrpc":"2.0","method":"VerifierLookupRequest","id":10,"params":{"verifier":"torus-direct-mock-ios","verifier_id":"michael@tor.us"}}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","result":{"keys":[{"key_index":"1c724","pub_key_X":"22d225892d5d149c0486bfb358b143568d1a951c39d5ada061a48c06c48afe39","pub_key_Y":"fcd9074bff4b5097489b79f951146d66bbcd05dc6acf68b8d0afc271fb73cf64","address":"0x22f2Ce611cE0d0ff4DA661d3a4C4B7A60B2b13F8"}]},"id":10}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Date":"Sun, 17 Oct 2021 10:57:32 GMT","Content-Length":"281","Content-Type":"application/json","Server":"nginx/1.19.9","Vary":"Origin"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcher( - host: "signer.tor.us", - scheme: "https", - path: "/api/allow", - method: "GET", - requestHeaders: mustDecodeJSON(#"{"Origin":"torus-direct-mock-ios","Accept":"application/json","Content-Type":"application/json","x-api-key":"torus-default"}"#) as! [String: String] - ), - responseBody: Data(#"{"success":true}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Content-Length":"16","access-control-allow-headers":"pubkeyx,pubkeyy,x-api-key,x-embed-host,content-type,authorization,verifier,verifier_id","access-control-max-age":"86400","access-control-allow-methods":"GET,OPTIONS","Access-Control-Allow-Origin":"*","Date":"Sun, 17 Oct 2021 10:57:32 GMT","Content-Type":"application/json"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "teal-15-5.torusnode.com", - scheme: "https", - path: "/jrpc", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Accept":"application/json","Content-Type":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"jsonrpc":"2.0","method":"VerifierLookupRequest","id":10,"params":{"verifier":"torus-direct-mock-ios","verifier_id":"michael@tor.us"}}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","result":{"keys":[{"key_index":"1c724","pub_key_X":"22d225892d5d149c0486bfb358b143568d1a951c39d5ada061a48c06c48afe39","pub_key_Y":"fcd9074bff4b5097489b79f951146d66bbcd05dc6acf68b8d0afc271fb73cf64","address":"0x22f2Ce611cE0d0ff4DA661d3a4C4B7A60B2b13F8"}]},"id":10}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Vary":"Origin","Content-Length":"281","Server":"nginx/1.19.9","Content-Type":"application/json","Date":"Sun, 17 Oct 2021 10:57:32 GMT"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "metadata.tor.us", - scheme: "https", - path: "/get", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Content-Type":"application/json","Accept":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"pub_key_X":"22d225892d5d149c0486bfb358b143568d1a951c39d5ada061a48c06c48afe39","pub_key_Y":"fcd9074bff4b5097489b79f951146d66bbcd05dc6acf68b8d0afc271fb73cf64"}"#) - ), - responseBody: Data(#"{"message":""}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"x-download-options":"noopen","x-permitted-cross-domain-policies":"none","x-content-type-options":"nosniff","Strict-Transport-Security":"max-age=15552000; includeSubDomains","x-dns-prefetch-control":"off","x-xss-protection":"0","content-security-policy":"default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests","x-frame-options":"SAMEORIGIN","referrer-policy":"no-referrer","Date":"Sun, 17 Oct 2021 10:57:32 GMT","Content-Type":"application/json; charset=utf-8","expect-ct":"max-age=0","Etag":"W/\"e-JWOqSwGs6lhRJiUZe/mVb6Mua74\"","Content-Length":"14","Vary":"Origin, Accept-Encoding"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "teal-15-1.torusnode.com", - scheme: "https", - path: "/jrpc", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Accept":"application/json","Content-Type":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"jsonrpc":"2.0","method":"CommitmentRequest","id":10,"params":{"messageprefix":"mug00","temppuby":"03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e","temppubx":"3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025","tokencommitment":"f9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b","timestamp":"0","verifieridentifier":"torus-direct-mock-ios"}}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","result":{"signature":"f94f88b5a2fff06463fe0cb4569a652a11f351061dcd5b15e466274e374eb2992632153bda0c017d9c83916b82f1daa3ee5ac9990201d73a18915224a828b6a41b","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","nodepubx":"1363aad8868cacd7f8946c590325cd463106fb3731f08811ab4302d2deae35c3","nodepuby":"d77eebe5cdf466b475ec892d5b4cffbe0c1670525debbd97eee6dae2f87a7cbe"},"id":10}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Server":"nginx/1.19.9","Content-Type":"application/json","Vary":"Origin","Date":"Sun, 17 Oct 2021 10:57:32 GMT","Content-Length":"606"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "teal-15-3.torusnode.com", - scheme: "https", - path: "/jrpc", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Content-Type":"application/json","Accept":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"jsonrpc":"2.0","method":"CommitmentRequest","id":10,"params":{"messageprefix":"mug00","temppuby":"03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e","temppubx":"3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025","tokencommitment":"f9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b","timestamp":"0","verifieridentifier":"torus-direct-mock-ios"}}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","result":{"signature":"ee5b3560bc5b394326ddb784970eb27c995b77ceac9ce04ddffe72a52542dffd7b90b30c50b69481b43f04a0373b632798bac8fcdf8d695ead606200e0a24fc41c","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","nodepubx":"7c8cc521c48690f016bea593f67f88ad24f447dd6c31bbab541e59e207bf029d","nodepuby":"b359f0a82608db2e06b953b36d0c9a473a00458117ca32a5b0f4563a7d539636"},"id":10}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Server":"nginx/1.19.9","Content-Type":"application/json","Vary":"Origin","Date":"Sun, 17 Oct 2021 10:57:32 GMT","Content-Length":"606"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "teal-15-4.torusnode.com", - scheme: "https", - path: "/jrpc", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Accept":"application/json","Content-Type":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"jsonrpc":"2.0","method":"CommitmentRequest","id":10,"params":{"messageprefix":"mug00","temppuby":"03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e","temppubx":"3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025","tokencommitment":"f9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b","timestamp":"0","verifieridentifier":"torus-direct-mock-ios"}}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","result":{"signature":"739487dab15bc238d32db83faf7b0aeb57f6863ac079aa331605eee9e076567c5cfa588978128af9d2c160d92a30197ccec8ab8c24ea68a3ac540a2534f65e261c","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","nodepubx":"8a86543ca17df5687719e2549caa024cf17fe0361e119e741eaee668f8dd0a6f","nodepuby":"9cdb254ff915a76950d6d13d78ef054d5d0dc34e2908c00bb009a6e4da701891"},"id":10}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Vary":"Origin","Server":"nginx/1.19.9","Content-Length":"606","Content-Type":"application/json","Date":"Sun, 17 Oct 2021 10:57:32 GMT"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "teal-15-5.torusnode.com", - scheme: "https", - path: "/jrpc", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Content-Type":"application/json","Accept":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"jsonrpc":"2.0","method":"CommitmentRequest","id":10,"params":{"messageprefix":"mug00","temppuby":"03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e","temppubx":"3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025","tokencommitment":"f9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b","timestamp":"0","verifieridentifier":"torus-direct-mock-ios"}}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","result":{"signature":"d24ccf58546df41bc8506b467e017ec64d941feb442a02001bea1c014dbe4d6b01317473884284d038ea116e6040ab25dad9901ee94d41dd33674cd105bc32151b","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","nodepubx":"25a98d9ae006aed1d77e81d58be8f67193d13d01a9888e2923841894f4b0bf9c","nodepuby":"f63d40df480dacf68922004ed36dbab9e2969181b047730a5ce0797fb6958249"},"id":10}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Vary":"Origin","Server":"nginx/1.19.9","Content-Length":"606","Content-Type":"application/json","Date":"Sun, 17 Oct 2021 10:57:32 GMT"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "teal-15-2.torusnode.com", - scheme: "https", - path: "/jrpc", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Accept":"application/json","Content-Type":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"jsonrpc":"2.0","method":"CommitmentRequest","id":10,"params":{"messageprefix":"mug00","temppuby":"03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e","temppubx":"3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025","tokencommitment":"f9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b","timestamp":"0","verifieridentifier":"torus-direct-mock-ios"}}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","result":{"signature":"ed5d0191d91c02b427d6482cec5d5380026218a1adecfefd6f892903577abb5d43f303302b1eac90b7d225beeb66c8c9ed9ebde8ccfe5994b3fb5f028cf571411c","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","nodepubx":"d908f41f8e06324a8a7abcf702adb6a273ce3ae63d86a3d22723e1bbf1438c9a","nodepuby":"f977530b3ec0e525438c72d1e768380cbc5fb3b38a760ee925053b2e169428ce"},"id":10}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Server":"nginx/1.19.9","Content-Length":"606","Content-Type":"application/json","Vary":"Origin","Date":"Sun, 17 Oct 2021 10:57:32 GMT"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "teal-15-3.torusnode.com", - scheme: "https", - path: "/jrpc", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Accept":"application/json","Content-Type":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"params":{"encrypted":"yes","item":[{"verifieridentifier":"torus-direct-mock-ios","nodesignatures":[{"signature":"f94f88b5a2fff06463fe0cb4569a652a11f351061dcd5b15e466274e374eb2992632153bda0c017d9c83916b82f1daa3ee5ac9990201d73a18915224a828b6a41b","nodepubx":"1363aad8868cacd7f8946c590325cd463106fb3731f08811ab4302d2deae35c3","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","nodepuby":"d77eebe5cdf466b475ec892d5b4cffbe0c1670525debbd97eee6dae2f87a7cbe"},{"nodepubx":"7c8cc521c48690f016bea593f67f88ad24f447dd6c31bbab541e59e207bf029d","nodepuby":"b359f0a82608db2e06b953b36d0c9a473a00458117ca32a5b0f4563a7d539636","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","signature":"ee5b3560bc5b394326ddb784970eb27c995b77ceac9ce04ddffe72a52542dffd7b90b30c50b69481b43f04a0373b632798bac8fcdf8d695ead606200e0a24fc41c"},{"signature":"739487dab15bc238d32db83faf7b0aeb57f6863ac079aa331605eee9e076567c5cfa588978128af9d2c160d92a30197ccec8ab8c24ea68a3ac540a2534f65e261c","nodepubx":"8a86543ca17df5687719e2549caa024cf17fe0361e119e741eaee668f8dd0a6f","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","nodepuby":"9cdb254ff915a76950d6d13d78ef054d5d0dc34e2908c00bb009a6e4da701891"},{"data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","signature":"d24ccf58546df41bc8506b467e017ec64d941feb442a02001bea1c014dbe4d6b01317473884284d038ea116e6040ab25dad9901ee94d41dd33674cd105bc32151b","nodepuby":"f63d40df480dacf68922004ed36dbab9e2969181b047730a5ce0797fb6958249","nodepubx":"25a98d9ae006aed1d77e81d58be8f67193d13d01a9888e2923841894f4b0bf9c"}],"verifier_id":"michael@tor.us","idtoken":"eyJhbGciOiJSUzI1NiIsImtpZCI6ImFkZDhjMGVlNjIzOTU0NGFmNTNmOTM3MTJhNTdiMmUyNmY5NDMzNTIiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiI2MzYxOTk0NjUyNDItZmQ3dWp0b3JwdnZ1ZHRzbDN1M2V2OTBuaWplY3RmcW0uYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiI2MzYxOTk0NjUyNDItZmQ3dWp0b3JwdnZ1ZHRzbDN1M2V2OTBuaWplY3RmcW0uYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMDkxMTE5NTM4NTYwMzE3OTk2MzkiLCJoZCI6InRvci51cyIsImVtYWlsIjoibWljaGFlbEB0b3IudXMiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXRfaGFzaCI6InRUNDhSck1vdGFFbi1UN3dzc2U3QnciLCJub25jZSI6InZSU2tPZWwyQTkiLCJuYW1lIjoiTWljaGFlbCBMZWUiLCJwaWN0dXJlIjoiaHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tL2EvQUFUWEFKd3NCYjk4Z1NZalZObEJCQWhYSmp2cU5PdzJHRFNlVGYwSTZTSmg9czk2LWMiLCJnaXZlbl9uYW1lIjoiTWljaGFlbCIsImZhbWlseV9uYW1lIjoiTGVlIiwibG9jYWxlIjoiZW4iLCJpYXQiOjE2MzQ0NjgyNDksImV4cCI6MTYzNDQ3MTg0OX0.XGu1tm_OqlSrc5BMDMzOrlhxLZo1YnpCUT0_j2U1mQt86nJzf_Hp85JfapZj2QeeUz91H6-Ei8FR1i4ICEfjMcoZOW1Azc89qUNfUgWeyjqZ7wCHSsbHAwabE74RFAS9YAja8_ynUvCARfDEtoqcreNgmbw3ZntzAqpuuNBXYfbr87kMvu_wZ7fWjLKM91CvuXytQBwtieTyjAFnTXmEL60Pdu-JSQfHCbS5H39ZHlnYxEO6qztIjvbnQokhjHDGc4PMCx0wfzrEet1ojNOCnbfmaYE5NQudquzQNZtqZfn8f4B-sQhECElnOXagHlafWO5RayS0dCb1mTfr8orcCA"}]},"id":10,"method":"ShareRequest","jsonrpc":"2.0"}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","result":{"keys":[{"Index":"1c724","PublicKey":{"X":"22d225892d5d149c0486bfb358b143568d1a951c39d5ada061a48c06c48afe39","Y":"fcd9074bff4b5097489b79f951146d66bbcd05dc6acf68b8d0afc271fb73cf64"},"Threshold":1,"Verifiers":{"torus-direct-mock-ios":["michael@tor.us"]},"Share":"NGNmMDY4M2M0ZjVlMzAzZTE1YWE0YWU3NDQwZjJiNWQ2ZWVkN2U2MjcxZGQ3MjVjMTA2OGY5Njk3MTM0ODRmNmFmYjQwNjhhYjkyMGM3MTY0MWFjNWZjYTBiMGVhMTQw","Metadata":{"iv":"95d1859aa5f86d87f13ed672d12e2d10","ephemPublicKey":"0403aa155f2605555d7399378e71146420e8d4eac9fd911ee57134da846f0e1e60702397386f0ec1226c2e7616283739922d9b654570bce4fd775021ee7bfb6451","mac":"aabadefa3f0d1d7530425595e2b54faaafb9ee3e3ff7c8ad14f8f8572095ba4e","mode":"AES256"}}]},"id":10}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Vary":"Origin","Content-Length":"722","Date":"Sun, 17 Oct 2021 10:57:32 GMT","Content-Type":"application/json","Server":"nginx/1.19.9"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "teal-15-1.torusnode.com", - scheme: "https", - path: "/jrpc", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Content-Type":"application/json","Accept":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"params":{"encrypted":"yes","item":[{"verifieridentifier":"torus-direct-mock-ios","nodesignatures":[{"signature":"f94f88b5a2fff06463fe0cb4569a652a11f351061dcd5b15e466274e374eb2992632153bda0c017d9c83916b82f1daa3ee5ac9990201d73a18915224a828b6a41b","nodepubx":"1363aad8868cacd7f8946c590325cd463106fb3731f08811ab4302d2deae35c3","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","nodepuby":"d77eebe5cdf466b475ec892d5b4cffbe0c1670525debbd97eee6dae2f87a7cbe"},{"nodepubx":"7c8cc521c48690f016bea593f67f88ad24f447dd6c31bbab541e59e207bf029d","nodepuby":"b359f0a82608db2e06b953b36d0c9a473a00458117ca32a5b0f4563a7d539636","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","signature":"ee5b3560bc5b394326ddb784970eb27c995b77ceac9ce04ddffe72a52542dffd7b90b30c50b69481b43f04a0373b632798bac8fcdf8d695ead606200e0a24fc41c"},{"signature":"739487dab15bc238d32db83faf7b0aeb57f6863ac079aa331605eee9e076567c5cfa588978128af9d2c160d92a30197ccec8ab8c24ea68a3ac540a2534f65e261c","nodepubx":"8a86543ca17df5687719e2549caa024cf17fe0361e119e741eaee668f8dd0a6f","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","nodepuby":"9cdb254ff915a76950d6d13d78ef054d5d0dc34e2908c00bb009a6e4da701891"},{"data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","signature":"d24ccf58546df41bc8506b467e017ec64d941feb442a02001bea1c014dbe4d6b01317473884284d038ea116e6040ab25dad9901ee94d41dd33674cd105bc32151b","nodepuby":"f63d40df480dacf68922004ed36dbab9e2969181b047730a5ce0797fb6958249","nodepubx":"25a98d9ae006aed1d77e81d58be8f67193d13d01a9888e2923841894f4b0bf9c"}],"verifier_id":"michael@tor.us","idtoken":"eyJhbGciOiJSUzI1NiIsImtpZCI6ImFkZDhjMGVlNjIzOTU0NGFmNTNmOTM3MTJhNTdiMmUyNmY5NDMzNTIiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiI2MzYxOTk0NjUyNDItZmQ3dWp0b3JwdnZ1ZHRzbDN1M2V2OTBuaWplY3RmcW0uYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiI2MzYxOTk0NjUyNDItZmQ3dWp0b3JwdnZ1ZHRzbDN1M2V2OTBuaWplY3RmcW0uYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMDkxMTE5NTM4NTYwMzE3OTk2MzkiLCJoZCI6InRvci51cyIsImVtYWlsIjoibWljaGFlbEB0b3IudXMiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXRfaGFzaCI6InRUNDhSck1vdGFFbi1UN3dzc2U3QnciLCJub25jZSI6InZSU2tPZWwyQTkiLCJuYW1lIjoiTWljaGFlbCBMZWUiLCJwaWN0dXJlIjoiaHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tL2EvQUFUWEFKd3NCYjk4Z1NZalZObEJCQWhYSmp2cU5PdzJHRFNlVGYwSTZTSmg9czk2LWMiLCJnaXZlbl9uYW1lIjoiTWljaGFlbCIsImZhbWlseV9uYW1lIjoiTGVlIiwibG9jYWxlIjoiZW4iLCJpYXQiOjE2MzQ0NjgyNDksImV4cCI6MTYzNDQ3MTg0OX0.XGu1tm_OqlSrc5BMDMzOrlhxLZo1YnpCUT0_j2U1mQt86nJzf_Hp85JfapZj2QeeUz91H6-Ei8FR1i4ICEfjMcoZOW1Azc89qUNfUgWeyjqZ7wCHSsbHAwabE74RFAS9YAja8_ynUvCARfDEtoqcreNgmbw3ZntzAqpuuNBXYfbr87kMvu_wZ7fWjLKM91CvuXytQBwtieTyjAFnTXmEL60Pdu-JSQfHCbS5H39ZHlnYxEO6qztIjvbnQokhjHDGc4PMCx0wfzrEet1ojNOCnbfmaYE5NQudquzQNZtqZfn8f4B-sQhECElnOXagHlafWO5RayS0dCb1mTfr8orcCA"}]},"id":10,"method":"ShareRequest","jsonrpc":"2.0"}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","result":{"keys":[{"Index":"1c724","PublicKey":{"X":"22d225892d5d149c0486bfb358b143568d1a951c39d5ada061a48c06c48afe39","Y":"fcd9074bff4b5097489b79f951146d66bbcd05dc6acf68b8d0afc271fb73cf64"},"Threshold":1,"Verifiers":{"torus-direct-mock-ios":["michael@tor.us"]},"Share":"ZjBjNTEyNDI1MTBmOThiMGJjNDhhZjdhOTgwZjNkYTM0YjhmYmVkYzRjZTA2NzI1ZmI4MDExYWQ1MTc3YTUwNzFkYjNmNDNhYzA2NGNjYjkzYWIxYjY0YWZkY2I2NzMy","Metadata":{"iv":"e72d1cbaef1868cfbe241c3a84bb0a26","ephemPublicKey":"048b20e455385773ea58f59b0da8bde5cbe07f46155f6793fb120cd0fac8113ecf31adfcf5c07a8457d0973b93902c59fd156496ccf3746b9d44ce3de671360109","mac":"d9e7d9b565dc815a4969928296630bbc8102f080d3bcabb8f91df08f6cdb3f74","mode":"AES256"}}]},"id":10}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Server":"nginx/1.19.9","Content-Length":"722","Vary":"Origin","Content-Type":"application/json","Date":"Sun, 17 Oct 2021 10:57:32 GMT"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "teal-15-5.torusnode.com", - scheme: "https", - path: "/jrpc", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Accept":"application/json","Content-Type":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"params":{"encrypted":"yes","item":[{"verifieridentifier":"torus-direct-mock-ios","nodesignatures":[{"signature":"f94f88b5a2fff06463fe0cb4569a652a11f351061dcd5b15e466274e374eb2992632153bda0c017d9c83916b82f1daa3ee5ac9990201d73a18915224a828b6a41b","nodepubx":"1363aad8868cacd7f8946c590325cd463106fb3731f08811ab4302d2deae35c3","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","nodepuby":"d77eebe5cdf466b475ec892d5b4cffbe0c1670525debbd97eee6dae2f87a7cbe"},{"nodepubx":"7c8cc521c48690f016bea593f67f88ad24f447dd6c31bbab541e59e207bf029d","nodepuby":"b359f0a82608db2e06b953b36d0c9a473a00458117ca32a5b0f4563a7d539636","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","signature":"ee5b3560bc5b394326ddb784970eb27c995b77ceac9ce04ddffe72a52542dffd7b90b30c50b69481b43f04a0373b632798bac8fcdf8d695ead606200e0a24fc41c"},{"signature":"739487dab15bc238d32db83faf7b0aeb57f6863ac079aa331605eee9e076567c5cfa588978128af9d2c160d92a30197ccec8ab8c24ea68a3ac540a2534f65e261c","nodepubx":"8a86543ca17df5687719e2549caa024cf17fe0361e119e741eaee668f8dd0a6f","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","nodepuby":"9cdb254ff915a76950d6d13d78ef054d5d0dc34e2908c00bb009a6e4da701891"},{"data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","signature":"d24ccf58546df41bc8506b467e017ec64d941feb442a02001bea1c014dbe4d6b01317473884284d038ea116e6040ab25dad9901ee94d41dd33674cd105bc32151b","nodepuby":"f63d40df480dacf68922004ed36dbab9e2969181b047730a5ce0797fb6958249","nodepubx":"25a98d9ae006aed1d77e81d58be8f67193d13d01a9888e2923841894f4b0bf9c"}],"verifier_id":"michael@tor.us","idtoken":"eyJhbGciOiJSUzI1NiIsImtpZCI6ImFkZDhjMGVlNjIzOTU0NGFmNTNmOTM3MTJhNTdiMmUyNmY5NDMzNTIiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiI2MzYxOTk0NjUyNDItZmQ3dWp0b3JwdnZ1ZHRzbDN1M2V2OTBuaWplY3RmcW0uYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiI2MzYxOTk0NjUyNDItZmQ3dWp0b3JwdnZ1ZHRzbDN1M2V2OTBuaWplY3RmcW0uYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMDkxMTE5NTM4NTYwMzE3OTk2MzkiLCJoZCI6InRvci51cyIsImVtYWlsIjoibWljaGFlbEB0b3IudXMiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXRfaGFzaCI6InRUNDhSck1vdGFFbi1UN3dzc2U3QnciLCJub25jZSI6InZSU2tPZWwyQTkiLCJuYW1lIjoiTWljaGFlbCBMZWUiLCJwaWN0dXJlIjoiaHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tL2EvQUFUWEFKd3NCYjk4Z1NZalZObEJCQWhYSmp2cU5PdzJHRFNlVGYwSTZTSmg9czk2LWMiLCJnaXZlbl9uYW1lIjoiTWljaGFlbCIsImZhbWlseV9uYW1lIjoiTGVlIiwibG9jYWxlIjoiZW4iLCJpYXQiOjE2MzQ0NjgyNDksImV4cCI6MTYzNDQ3MTg0OX0.XGu1tm_OqlSrc5BMDMzOrlhxLZo1YnpCUT0_j2U1mQt86nJzf_Hp85JfapZj2QeeUz91H6-Ei8FR1i4ICEfjMcoZOW1Azc89qUNfUgWeyjqZ7wCHSsbHAwabE74RFAS9YAja8_ynUvCARfDEtoqcreNgmbw3ZntzAqpuuNBXYfbr87kMvu_wZ7fWjLKM91CvuXytQBwtieTyjAFnTXmEL60Pdu-JSQfHCbS5H39ZHlnYxEO6qztIjvbnQokhjHDGc4PMCx0wfzrEet1ojNOCnbfmaYE5NQudquzQNZtqZfn8f4B-sQhECElnOXagHlafWO5RayS0dCb1mTfr8orcCA"}]},"id":10,"method":"ShareRequest","jsonrpc":"2.0"}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","result":{"keys":[{"Index":"1c724","PublicKey":{"X":"22d225892d5d149c0486bfb358b143568d1a951c39d5ada061a48c06c48afe39","Y":"fcd9074bff4b5097489b79f951146d66bbcd05dc6acf68b8d0afc271fb73cf64"},"Threshold":1,"Verifiers":{"torus-direct-mock-ios":["michael@tor.us"]},"Share":"MzUyMTg4ZjEyMzc1NDAwZjk0MDIxOTgyNGJjNjZkM2U1MmZmM2Y0YjJjZWFkOTQzN2M0N2ZjMjMxMDFkYzQ5YzY5NjZiZTUzM2MwMDg2NTE1OGRlNThiNDc5N2M5Yjgy","Metadata":{"iv":"c73e422b8c1ca9bbe10caa04d8d6e79d","ephemPublicKey":"046ac88f638dc83e4eef85b9bea2de984449ad7587cc5c652451632d2ecc1509b1fa43180768d9c6e5e513d48f2bd8c69d450a4e279a0dbbdb5e7d917e54405e84","mac":"eb941f9a9317d7b27f7bda11988b6478a87bed80d644ccf6b09131e4a488bcd4","mode":"AES256"}}]},"id":10}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Content-Length":"722","Vary":"Origin","Date":"Sun, 17 Oct 2021 10:57:32 GMT","Server":"nginx/1.19.9","Content-Type":"application/json"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "teal-15-2.torusnode.com", - scheme: "https", - path: "/jrpc", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Accept":"application/json","Content-Type":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"params":{"encrypted":"yes","item":[{"verifieridentifier":"torus-direct-mock-ios","nodesignatures":[{"signature":"f94f88b5a2fff06463fe0cb4569a652a11f351061dcd5b15e466274e374eb2992632153bda0c017d9c83916b82f1daa3ee5ac9990201d73a18915224a828b6a41b","nodepubx":"1363aad8868cacd7f8946c590325cd463106fb3731f08811ab4302d2deae35c3","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","nodepuby":"d77eebe5cdf466b475ec892d5b4cffbe0c1670525debbd97eee6dae2f87a7cbe"},{"nodepubx":"7c8cc521c48690f016bea593f67f88ad24f447dd6c31bbab541e59e207bf029d","nodepuby":"b359f0a82608db2e06b953b36d0c9a473a00458117ca32a5b0f4563a7d539636","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","signature":"ee5b3560bc5b394326ddb784970eb27c995b77ceac9ce04ddffe72a52542dffd7b90b30c50b69481b43f04a0373b632798bac8fcdf8d695ead606200e0a24fc41c"},{"signature":"739487dab15bc238d32db83faf7b0aeb57f6863ac079aa331605eee9e076567c5cfa588978128af9d2c160d92a30197ccec8ab8c24ea68a3ac540a2534f65e261c","nodepubx":"8a86543ca17df5687719e2549caa024cf17fe0361e119e741eaee668f8dd0a6f","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","nodepuby":"9cdb254ff915a76950d6d13d78ef054d5d0dc34e2908c00bb009a6e4da701891"},{"data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","signature":"d24ccf58546df41bc8506b467e017ec64d941feb442a02001bea1c014dbe4d6b01317473884284d038ea116e6040ab25dad9901ee94d41dd33674cd105bc32151b","nodepuby":"f63d40df480dacf68922004ed36dbab9e2969181b047730a5ce0797fb6958249","nodepubx":"25a98d9ae006aed1d77e81d58be8f67193d13d01a9888e2923841894f4b0bf9c"}],"verifier_id":"michael@tor.us","idtoken":"eyJhbGciOiJSUzI1NiIsImtpZCI6ImFkZDhjMGVlNjIzOTU0NGFmNTNmOTM3MTJhNTdiMmUyNmY5NDMzNTIiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiI2MzYxOTk0NjUyNDItZmQ3dWp0b3JwdnZ1ZHRzbDN1M2V2OTBuaWplY3RmcW0uYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiI2MzYxOTk0NjUyNDItZmQ3dWp0b3JwdnZ1ZHRzbDN1M2V2OTBuaWplY3RmcW0uYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMDkxMTE5NTM4NTYwMzE3OTk2MzkiLCJoZCI6InRvci51cyIsImVtYWlsIjoibWljaGFlbEB0b3IudXMiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXRfaGFzaCI6InRUNDhSck1vdGFFbi1UN3dzc2U3QnciLCJub25jZSI6InZSU2tPZWwyQTkiLCJuYW1lIjoiTWljaGFlbCBMZWUiLCJwaWN0dXJlIjoiaHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tL2EvQUFUWEFKd3NCYjk4Z1NZalZObEJCQWhYSmp2cU5PdzJHRFNlVGYwSTZTSmg9czk2LWMiLCJnaXZlbl9uYW1lIjoiTWljaGFlbCIsImZhbWlseV9uYW1lIjoiTGVlIiwibG9jYWxlIjoiZW4iLCJpYXQiOjE2MzQ0NjgyNDksImV4cCI6MTYzNDQ3MTg0OX0.XGu1tm_OqlSrc5BMDMzOrlhxLZo1YnpCUT0_j2U1mQt86nJzf_Hp85JfapZj2QeeUz91H6-Ei8FR1i4ICEfjMcoZOW1Azc89qUNfUgWeyjqZ7wCHSsbHAwabE74RFAS9YAja8_ynUvCARfDEtoqcreNgmbw3ZntzAqpuuNBXYfbr87kMvu_wZ7fWjLKM91CvuXytQBwtieTyjAFnTXmEL60Pdu-JSQfHCbS5H39ZHlnYxEO6qztIjvbnQokhjHDGc4PMCx0wfzrEet1ojNOCnbfmaYE5NQudquzQNZtqZfn8f4B-sQhECElnOXagHlafWO5RayS0dCb1mTfr8orcCA"}]},"id":10,"method":"ShareRequest","jsonrpc":"2.0"}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","result":{"keys":[{"Index":"1c724","PublicKey":{"X":"22d225892d5d149c0486bfb358b143568d1a951c39d5ada061a48c06c48afe39","Y":"fcd9074bff4b5097489b79f951146d66bbcd05dc6acf68b8d0afc271fb73cf64"},"Threshold":1,"Verifiers":{"torus-direct-mock-ios":["michael@tor.us"]},"Share":"OTNhMzBjODY1YjM4OTNiNWQxOWQ2MmNmZmY1YjUzNTE1NzViZjZiMmM3ZmM0YWFmZTRiYzY0ZjA3YjkzNjU0MzczYzhjNmIyYjQ0ZjIzNTIyZWUwOGRmZWVjNzFlMjVk","Metadata":{"iv":"6e8150c48e9eaae7f03d71fe339e8ddf","ephemPublicKey":"048a363e0572bb294e979e5588488d3f702ea99df104b1b9a82e52505d85983d6ea11061a70a9bd99b2e77a0dc5e816eb1080618f96865ef318129711cd9f6634c","mac":"94d7c5a01d2a01379abb3a3a7c604910f8d58ac0f75c427392ea7c8c8085509c","mode":"AES256"}}]},"id":10}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Vary":"Origin","Server":"nginx/1.19.9","Content-Length":"722","Content-Type":"application/json","Date":"Sun, 17 Oct 2021 10:57:32 GMT"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "teal-15-4.torusnode.com", - scheme: "https", - path: "/jrpc", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Accept":"application/json","Content-Type":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"params":{"encrypted":"yes","item":[{"verifieridentifier":"torus-direct-mock-ios","nodesignatures":[{"signature":"f94f88b5a2fff06463fe0cb4569a652a11f351061dcd5b15e466274e374eb2992632153bda0c017d9c83916b82f1daa3ee5ac9990201d73a18915224a828b6a41b","nodepubx":"1363aad8868cacd7f8946c590325cd463106fb3731f08811ab4302d2deae35c3","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","nodepuby":"d77eebe5cdf466b475ec892d5b4cffbe0c1670525debbd97eee6dae2f87a7cbe"},{"nodepubx":"7c8cc521c48690f016bea593f67f88ad24f447dd6c31bbab541e59e207bf029d","nodepuby":"b359f0a82608db2e06b953b36d0c9a473a00458117ca32a5b0f4563a7d539636","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","signature":"ee5b3560bc5b394326ddb784970eb27c995b77ceac9ce04ddffe72a52542dffd7b90b30c50b69481b43f04a0373b632798bac8fcdf8d695ead606200e0a24fc41c"},{"signature":"739487dab15bc238d32db83faf7b0aeb57f6863ac079aa331605eee9e076567c5cfa588978128af9d2c160d92a30197ccec8ab8c24ea68a3ac540a2534f65e261c","nodepubx":"8a86543ca17df5687719e2549caa024cf17fe0361e119e741eaee668f8dd0a6f","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","nodepuby":"9cdb254ff915a76950d6d13d78ef054d5d0dc34e2908c00bb009a6e4da701891"},{"data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","signature":"d24ccf58546df41bc8506b467e017ec64d941feb442a02001bea1c014dbe4d6b01317473884284d038ea116e6040ab25dad9901ee94d41dd33674cd105bc32151b","nodepuby":"f63d40df480dacf68922004ed36dbab9e2969181b047730a5ce0797fb6958249","nodepubx":"25a98d9ae006aed1d77e81d58be8f67193d13d01a9888e2923841894f4b0bf9c"}],"verifier_id":"michael@tor.us","idtoken":"eyJhbGciOiJSUzI1NiIsImtpZCI6ImFkZDhjMGVlNjIzOTU0NGFmNTNmOTM3MTJhNTdiMmUyNmY5NDMzNTIiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiI2MzYxOTk0NjUyNDItZmQ3dWp0b3JwdnZ1ZHRzbDN1M2V2OTBuaWplY3RmcW0uYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiI2MzYxOTk0NjUyNDItZmQ3dWp0b3JwdnZ1ZHRzbDN1M2V2OTBuaWplY3RmcW0uYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMDkxMTE5NTM4NTYwMzE3OTk2MzkiLCJoZCI6InRvci51cyIsImVtYWlsIjoibWljaGFlbEB0b3IudXMiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXRfaGFzaCI6InRUNDhSck1vdGFFbi1UN3dzc2U3QnciLCJub25jZSI6InZSU2tPZWwyQTkiLCJuYW1lIjoiTWljaGFlbCBMZWUiLCJwaWN0dXJlIjoiaHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tL2EvQUFUWEFKd3NCYjk4Z1NZalZObEJCQWhYSmp2cU5PdzJHRFNlVGYwSTZTSmg9czk2LWMiLCJnaXZlbl9uYW1lIjoiTWljaGFlbCIsImZhbWlseV9uYW1lIjoiTGVlIiwibG9jYWxlIjoiZW4iLCJpYXQiOjE2MzQ0NjgyNDksImV4cCI6MTYzNDQ3MTg0OX0.XGu1tm_OqlSrc5BMDMzOrlhxLZo1YnpCUT0_j2U1mQt86nJzf_Hp85JfapZj2QeeUz91H6-Ei8FR1i4ICEfjMcoZOW1Azc89qUNfUgWeyjqZ7wCHSsbHAwabE74RFAS9YAja8_ynUvCARfDEtoqcreNgmbw3ZntzAqpuuNBXYfbr87kMvu_wZ7fWjLKM91CvuXytQBwtieTyjAFnTXmEL60Pdu-JSQfHCbS5H39ZHlnYxEO6qztIjvbnQokhjHDGc4PMCx0wfzrEet1ojNOCnbfmaYE5NQudquzQNZtqZfn8f4B-sQhECElnOXagHlafWO5RayS0dCb1mTfr8orcCA"}]},"id":10,"method":"ShareRequest","jsonrpc":"2.0"}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","result":{"keys":[{"Index":"1c724","PublicKey":{"X":"22d225892d5d149c0486bfb358b143568d1a951c39d5ada061a48c06c48afe39","Y":"fcd9074bff4b5097489b79f951146d66bbcd05dc6acf68b8d0afc271fb73cf64"},"Threshold":1,"Verifiers":{"torus-direct-mock-ios":["michael@tor.us"]},"Share":"M2U2OGMxYzg0ODFhMDAxNTFkOWE1MTMyMmZjNjlkOWQ0MWUzZjgzZDQ0NGJlNmQ1YzdlMDEwNzliZTRhYjg4OTdmM2Y3YWRiNjcwZDZhMTA5MDk4NjE2OGI2OTBlZWM2","Metadata":{"iv":"29a6a7bb27cd3a9a13cfb47818e894a0","ephemPublicKey":"0489299b0ccc867e2596e2069dce3c129e163f9e8c47c51c2dd2ea5aa56af88b4cfa4cfab34ece86512dc0995fcbab1fe9206609cafa648a66bc35d95c1795dd41","mac":"541759eb560a77517057c452b11113630e2ac32de7ba2addab8643ff52a19f59","mode":"AES256"}}]},"id":10}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Date":"Sun, 17 Oct 2021 10:57:33 GMT","Content-Type":"application/json","Content-Length":"722","Vary":"Origin","Server":"nginx/1.19.9"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "metadata.tor.us", - scheme: "https", - path: "/get", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Accept":"application/json","Content-Type":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"pub_key_X":"22d225892d5d149c0486bfb358b143568d1a951c39d5ada061a48c06c48afe39","pub_key_Y":"fcd9074bff4b5097489b79f951146d66bbcd05dc6acf68b8d0afc271fb73cf64"}"#) - ), - responseBody: Data(#"{"message":""}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Content-Type":"application/json; charset=utf-8","Etag":"W/\"e-JWOqSwGs6lhRJiUZe/mVb6Mua74\"","x-xss-protection":"0","x-content-type-options":"nosniff","Vary":"Origin, Accept-Encoding","x-frame-options":"SAMEORIGIN","referrer-policy":"no-referrer","content-security-policy":"default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests","Date":"Sun, 17 Oct 2021 10:57:33 GMT","x-dns-prefetch-control":"off","x-permitted-cross-domain-policies":"none","Strict-Transport-Security":"max-age=15552000; includeSubDomains","x-download-options":"noopen","Content-Length":"14","expect-ct":"max-age=0"}"#) as! [String: String] - ), -] diff --git a/Tests/TorusUtilsTests/oneKeyTest.swift b/Tests/TorusUtilsTests/oneKeyTest.swift index 9a85d823..dd679d1b 100644 --- a/Tests/TorusUtilsTests/oneKeyTest.swift +++ b/Tests/TorusUtilsTests/oneKeyTest.swift @@ -1,88 +1,151 @@ import BigInt import FetchNodeDetails import JWTKit +import TorusUtils import XCTest -import CoreMedia -@testable import TorusUtils - class OneKeyTest: XCTestCase { var TORUS_TEST_EMAIL = "hello@tor.us" var TORUS_TEST_VERIFIER = "torus-test-health" var TORUS_TEST_AGGREGATE_VERIFIER = "torus-test-health-aggregate" var fnd: NodeDetailManager! - var tu: TorusUtils! + var torus: TorusUtils! override func setUp() { super.setUp() fnd = NodeDetailManager(network: .legacy(.TESTNET)) + torus = try! TorusUtils(params: TorusOptions(clientId: "YOUR_CLIENT_ID", network: .legacy(.TESTNET), enableOneKey: true)) } - func getFNDAndTUData(verifer: String, veriferID: String, enableOneKey: Bool = true) async throws -> AllNodeDetailsModel { - do { - let nodeDetails = try await fnd.getNodeDetails(verifier: verifer, verifierID: veriferID) - tu = TorusUtils(enableOneKey: enableOneKey, network: .legacy(.TESTNET), clientId: "YOUR_CLIENT_ID") - return nodeDetails - } catch { - throw error - } - } - - func test_fetch_public_address() async throws { + func test_should_still_fetch_v1_address_correctly() async throws { let verifier = "google-lrc" let verifierID = "himanshu@tor.us" - let nodeDetails = try await getFNDAndTUData(verifer: verifier, veriferID: verifierID) - let data = try await tu.getPublicAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), verifier: verifier, verifierId: verifierID) - XCTAssertEqual(data.finalKeyData?.evmAddress, "0xf1e76fcDD28b5AA06De01de508fF21589aB9017E") + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + let data = try await torus.getPublicAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierId: verifierID) + XCTAssertLessThan(data.metadata!.serverTimeOffset, 20) + + XCTAssertEqual(data.finalKeyData?.evmAddress, "0x930abEDDCa6F9807EaE77A3aCc5c78f20B168Fd1") + + XCTAssertEqual(data.oAuthKeyData!.evmAddress, "0xf1e76fcDD28b5AA06De01de508fF21589aB9017E") + XCTAssertEqual(data.oAuthKeyData!.X, "b3f2b4d8b746353fe670e0c39ac9adb58056d4d7b718d06b623612d4ec49268b") + XCTAssertEqual(data.oAuthKeyData!.Y, "ac9f79dff78add39cdba380dbbf517c20cf2c1e06b32842a90a84a31f6eb9a9a") + XCTAssertEqual(data.finalKeyData!.evmAddress, "0x930abEDDCa6F9807EaE77A3aCc5c78f20B168Fd1") + XCTAssertEqual(data.finalKeyData!.X, "12f6b90d66bda29807cf9ff14b2e537c25080154fc4fafed446306e8356ff425") + XCTAssertEqual(data.finalKeyData!.Y, "e7c92e164b83e1b53e41e5d87d478bb07d7b19d105143e426e1ef08f7b37f224") + XCTAssertNil(data.metadata!.pubNonce) + XCTAssertEqual(data.metadata!.nonce, BigUInt("186a20d9b00315855ff5622a083aca6b2d34ef66ef6e0a4de670f5b2fde37e0d", radix: 16)) + XCTAssertEqual(data.metadata!.typeOfUser, .v1) + XCTAssertEqual(data.metadata!.upgraded, false) + XCTAssertNotNil(data.nodesData) } - func test_login() async throws { - let verifier: String = TORUS_TEST_VERIFIER + func test_should_still_login_v1_account_correctly() async throws { let email = TORUS_TEST_EMAIL - let verifierID: String = email let jwt = try! generateIdToken(email: email) - let verifierParams = VerifierParams(verifier_id: verifierID) - let extraParams = ["verifier_id": email] as [String: Codable] - let nodeDetails = try await getFNDAndTUData(verifer: verifier, veriferID: verifierID) - let data = try await tu.retrieveShares(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), indexes: nodeDetails.getTorusIndexes(), verifier: verifier, verifierParams: verifierParams, idToken: jwt, extraParams: extraParams) - XCTAssertEqual(data.finalKeyData?.privKey, "296045a5599afefda7afbdd1bf236358baff580a0fe2db62ae5c1bbe817fbae4") - } - - func test_login_v2() async throws { let verifier: String = TORUS_TEST_VERIFIER - let verifierID: String = TORUS_TEST_EMAIL - let jwt = try! generateIdToken(email: verifierID) + let verifierID: String = email let verifierParams = VerifierParams(verifier_id: verifierID) - let extraParams = ["verifier_id": verifierID] as [String: Codable] - let nodeDetails = try await getFNDAndTUData(verifer: verifier, veriferID: verifierID) - let data = try await tu.retrieveShares(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), indexes: nodeDetails.getTorusIndexes(), verifier: verifier, verifierParams: verifierParams, idToken: jwt, extraParams: extraParams) - XCTAssertEqual(data.oAuthKeyData?.privKey, "068ee4f97468ef1ae95d18554458d372e31968190ae38e377be59d8b3c9f7a25") - XCTAssertEqual(data.oAuthKeyData?.evmAddress, "0xEfd7eDAebD0D99D1B7C8424b54835457dD005Dc4") - XCTAssertEqual(data.finalKeyData?.privKey, "296045a5599afefda7afbdd1bf236358baff580a0fe2db62ae5c1bbe817fbae4") - XCTAssertEqual(data.finalKeyData?.evmAddress, "0x53010055542cCc0f2b6715a5c53838eC4aC96EF7") + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + let data = try await torus.retrieveShares(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierParams: verifierParams, idToken: jwt) + + XCTAssertLessThan(data.metadata.serverTimeOffset, 20) + + XCTAssertEqual(data.finalKeyData.evmAddress, "0x53010055542cCc0f2b6715a5c53838eC4aC96EF7") + XCTAssertEqual(data.finalKeyData.X, "3fa78a0bfb9ec48810bf1ee332360def2600c4aef528ff8b1e49a0d304722c91") + XCTAssertEqual(data.finalKeyData.Y, "46aaca39fc00c0f88f63a79989697c70eeeeec6489300c493dd07a5608ded0d4") + XCTAssertEqual(data.finalKeyData.privKey, "296045a5599afefda7afbdd1bf236358baff580a0fe2db62ae5c1bbe817fbae4") + XCTAssertEqual(data.oAuthKeyData.evmAddress, "0xEfd7eDAebD0D99D1B7C8424b54835457dD005Dc4") + XCTAssertEqual(data.oAuthKeyData.X, "18409385c38e9729eb6b7837dc8f234256233ffab1ed7eeb1c23b230333396b4") + XCTAssertEqual(data.oAuthKeyData.Y, "17d35ffc722d7a8dd88353815e9553cacf567c5f3b8d082adac9d653367ce47a") + XCTAssertEqual(data.oAuthKeyData.privKey, "068ee4f97468ef1ae95d18554458d372e31968190ae38e377be59d8b3c9f7a25") + XCTAssertEqual(data.metadata.pubNonce!.x, "8e8c399d8ba00ff88e6c42eb40c10661f822868ba2ad8fe12a8830e996b1e25d") + XCTAssertEqual(data.metadata.pubNonce!.y, "554b12253694bf9eb98485441bba7ba220b78cb78ee21664e96f934d10b1494d") + XCTAssertEqual(data.metadata.nonce, BigUInt("22d160abe5320fe2be52a57c7aca8fe5d7e5eff104ff4d2b32767e3344e040bf", radix: 16)) + XCTAssertEqual(data.metadata.typeOfUser, .v2) + XCTAssertEqual(data.metadata.upgraded, false) + XCTAssertNotNil(data.nodesData) } - func test_aggregate_login() async throws { + func test_should_still_aggregate_v1_user_correctly() async throws { let verifier: String = TORUS_TEST_AGGREGATE_VERIFIER let verifierID: String = TORUS_TEST_EMAIL let jwt = try! generateIdToken(email: TORUS_TEST_EMAIL) - let verifierParams = VerifierParams(verifier_id: verifierID) - let hashedIDToken = keccak256Data( jwt.data(using: .utf8) ?? Data() ).toHexString() - let extraParams = ["verifier_id": TORUS_TEST_EMAIL, "sub_verifier_ids": [TORUS_TEST_VERIFIER], "verify_params": [["verifier_id": TORUS_TEST_EMAIL, "idtoken": jwt]]] as [String: Codable] - let nodeDetails = try await getFNDAndTUData(verifer: verifier, veriferID: verifierID) - let data = try await tu.retrieveShares(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), indexes: nodeDetails.getTorusIndexes(), verifier: verifier, verifierParams: verifierParams, idToken: hashedIDToken, extraParams: extraParams) - XCTAssertEqual(data.finalKeyData?.evmAddress, "0xE1155dB406dAD89DdeE9FB9EfC29C8EedC2A0C8B") + let verifierParams = VerifierParams(verifier_id: verifierID, sub_verifier_ids: [TORUS_TEST_VERIFIER], verify_params: [VerifyParams(verifier_id: TORUS_TEST_EMAIL, idtoken: jwt)]) + let hashedIDToken = try KeyUtils.keccak256Data(jwt) + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + let data = try await torus.retrieveShares(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierParams: verifierParams, idToken: hashedIDToken) + + XCTAssertLessThan(data.metadata.serverTimeOffset, 20) + + XCTAssertEqual(data.finalKeyData.evmAddress, "0xE1155dB406dAD89DdeE9FB9EfC29C8EedC2A0C8B") + XCTAssertEqual(data.finalKeyData.X, "78658b2671f1bd6a488baf2afb8ce6f8d8b9a1a70842130b3c8756a9d51d9723") + XCTAssertEqual(data.finalKeyData.Y, "2e5840f47d645afa4bfe93c3715e65974051080d7a1e474eef8d68752924f4fb") + XCTAssertEqual(data.finalKeyData.privKey, "ad47959db4cb2e63e641bac285df1b944f54d1a1cecdaeea40042b60d53c35d2") + XCTAssertEqual(data.oAuthKeyData.evmAddress, "0x5a165d2Ed4976BD104caDE1b2948a93B72FA91D2") + XCTAssertEqual(data.oAuthKeyData.X, "aba2b085ae6390b3eb26802c3239bb7e3b9ed8ea6e1dcc28aeb67432571f20fc") + XCTAssertEqual(data.oAuthKeyData.Y, "f1a2163cba5620b7b40241a6112e7918e9445b0b9cfbbb9d77b2de6f61ed5c27") + XCTAssertEqual(data.oAuthKeyData.privKey, "d9733fc1098151f3e3289673e7c69c4ed46cbbdbc13416560e14741524d2d51a") + XCTAssertEqual(data.metadata.pubNonce!.x, "376c0ac5e15686633061cf5833dd040365f91377686d7ab5338c5202bd963a2f") + XCTAssertEqual(data.metadata.pubNonce!.y, "794d7edb6a5ec0307dd40789274b377f37f293b0410a6cbd303db309536099b7") + XCTAssertEqual(data.metadata.nonce, BigUInt("d3d455dcab49dc700319244e9e187f443596f2acbce238cff1c215d8809fa1f9", radix: 16)) + XCTAssertEqual(data.metadata.typeOfUser, .v2) + XCTAssertEqual(data.metadata.upgraded, false) + XCTAssertNotNil(data.nodesData) } - /* TODO: Investigate this further - func test_key_assign() async throws { + func test_should_be_able_to_key_assign() async throws { let fakeEmail = generateRandomEmail(of: 6) - let verifier: String = "google-lrc" + let verifier: String = TORUS_TEST_VERIFIER let verifierID: String = fakeEmail - let nodeDetails = try await getFNDAndTUData(verifer: verifier, veriferID: verifierID) - let data = try await tu.getPublicAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), torusNodePubs: nodeDetails.getTorusNodePub(), verifier: verifier, verifierId: verifierID) - XCTAssertNotNil(data) + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + let data = try await torus.getPublicAddress(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierId: verifierID) + + XCTAssertEqual(data.metadata?.typeOfUser, .v2) + XCTAssertEqual(data.metadata?.upgraded, false) XCTAssertNotEqual(data.finalKeyData?.evmAddress, "") + XCTAssertNotEqual(data.oAuthKeyData?.evmAddress, "") + } + + func test_should_be_able_to_key_assign_via_login() async throws { + let fakeEmail = generateRandomEmail(of: 6) + let verifier: String = TORUS_TEST_VERIFIER + let verifierID: String = fakeEmail + let jwt = try! generateIdToken(email: verifierID) + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + let verifierParams = VerifierParams(verifier_id: verifierID) + let data = try await torus.retrieveShares(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierParams: verifierParams, idToken: jwt) + + XCTAssertEqual(data.metadata.typeOfUser, .v2) + XCTAssertNotEqual(data.metadata.nonce, BigUInt(0)) + XCTAssertEqual(data.metadata.upgraded, false) + XCTAssertNotEqual(data.finalKeyData.evmAddress, "") + XCTAssertNotEqual(data.oAuthKeyData.evmAddress, "") + } + + func test_should_still_login_v2_account_correctly() async throws { + let email = "Jonathan.Nolan@hotmail.com" + let jwt = try! generateIdToken(email: email) + let verifier: String = TORUS_TEST_VERIFIER + let verifierID: String = email + let verifierParams = VerifierParams(verifier_id: verifierID) + let nodeDetails = try await fnd.getNodeDetails(verifier: verifier, verifierID: verifierID) + let data = try await torus.retrieveShares(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierParams: verifierParams, idToken: jwt) + + XCTAssertLessThan(data.metadata.serverTimeOffset, 20) + + XCTAssertEqual(data.finalKeyData.evmAddress, "0x2876820fd9536BD5dd874189A85d71eE8bDf64c2") + XCTAssertEqual(data.finalKeyData.X, "ad4c223520aac9bc3ec72399869601fd59f29363471131914e2ed2bc4ba46e54") + XCTAssertEqual(data.finalKeyData.Y, "802c6e40b22b49b5ef73fa49b194c2037267215fa01683aa86746907aab37ae1") + XCTAssertEqual(data.finalKeyData.privKey, "9ec5b0504e252e35218c7ce1e4660eac190a1505abfbec7102946f92ed750075") + XCTAssertEqual(data.oAuthKeyData.evmAddress, "0x54de3Df0CA76AAe3e171FB410F0626Ab759f3c24") + XCTAssertEqual(data.oAuthKeyData.X, "49d69b8550bb0eba77595c73bf57f0463ff96adf6b50d44f9e1bcf2b3fb7976e") + XCTAssertEqual(data.oAuthKeyData.Y, "d63bac65bdfc7484a28d4362347bbd098095db190c14a4ce9dbaafe74803eccc") + XCTAssertEqual(data.oAuthKeyData.privKey, "f4b7e0fb1e6f6fbac539c55e22aff2900947de652d2d6254a9cd8709f505f83a") + XCTAssertEqual(data.metadata.pubNonce!.x, "f494a5bf06a2f0550aafb6aabeb495bd6ea3ef92eaa736819b5b0ad6bfbf1aab") + XCTAssertEqual(data.metadata.pubNonce!.y, "35df3d3a14f88cbba0cfd092a1e5a0e4e725ba52a8d45719614555542d701f18") + XCTAssertEqual(data.metadata.nonce, BigUInt("aa0dcf552fb5be7a5c52b783c1b61c1aca7113872e172a5818994715c8a5497c", radix: 16)) + XCTAssertEqual(data.metadata.typeOfUser, .v2) + XCTAssertEqual(data.metadata.upgraded, false) + XCTAssertNotNil(data.nodesData) } - */ } diff --git a/Torus-utils.podspec b/Torus-utils.podspec index e5b249bd..2dd1b3ec 100644 --- a/Torus-utils.podspec +++ b/Torus-utils.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = "Torus-utils" - spec.version = "8.1.2" + spec.version = "9.0.0" spec.ios.deployment_target = "13.0" spec.summary = "Retrieve user shares" spec.homepage = "https://github.com/torusresearch/torus-utils-swift" @@ -10,7 +10,6 @@ Pod::Spec.new do |spec| spec.module_name = "TorusUtils" spec.source = { :git => "https://github.com/torusresearch/torus-utils-swift.git", :tag => spec.version } spec.source_files = "Sources/TorusUtils/*.{swift,json}","Sources/TorusUtils/**/*.{swift,json}" - spec.dependency 'Torus-fetchNodeDetails', '~> 6.0.1' + spec.dependency 'Torus-fetchNodeDetails', '~> 6.0.3' spec.dependency 'curvelib.swift', '~> 1.0.1' - spec.dependency 'AnyCodable-FlightSchool', '~> 0.6.0' end diff --git a/cocoapods/Podfile.lock b/cocoapods/Podfile.lock index a05e6c42..b2c3d277 100644 --- a/cocoapods/Podfile.lock +++ b/cocoapods/Podfile.lock @@ -1,20 +1,17 @@ PODS: - - AnyCodable-FlightSchool (0.6.7) - BigInt (5.2.0) - curvelib.swift (1.0.1) - - Torus-fetchNodeDetails (6.0.0): + - Torus-fetchNodeDetails (6.0.3): - BigInt (~> 5.2.0) - - Torus-utils (8.0.3): - - AnyCodable-FlightSchool (~> 0.6.0) + - Torus-utils (9.0.0): - curvelib.swift (~> 1.0.1) - - Torus-fetchNodeDetails (~> 6.0.0) + - Torus-fetchNodeDetails (~> 6.0.3) DEPENDENCIES: - Torus-utils (from `../`) SPEC REPOS: https://github.com/CocoaPods/Specs.git: - - AnyCodable-FlightSchool - BigInt - curvelib.swift - Torus-fetchNodeDetails @@ -24,11 +21,10 @@ EXTERNAL SOURCES: :path: "../" SPEC CHECKSUMS: - AnyCodable-FlightSchool: 261cbe76757802b17d471b9059b21e6fa5edf57b BigInt: f668a80089607f521586bbe29513d708491ef2f7 curvelib.swift: d0746ae82bee34016c06da3567a97e493b3c979f - Torus-fetchNodeDetails: e27940bc2151f80b76e3732987a52ea802eb34be - Torus-utils: ce29be461bc6ae9a946d23188d1d3a50bfa4c667 + Torus-fetchNodeDetails: 6c349f47cbca36a4b3f276fe26d03c1b39b20949 + Torus-utils: 0f993fffd66a66a0423092c9ddea2cbff4d298df PODFILE CHECKSUM: 2d35466879f2d32f53c6ccbca958796c381f0e62 diff --git a/cocoapods/TestApplication.xcodeproj/project.pbxproj b/cocoapods/TestApplication.xcodeproj/project.pbxproj index 86cb4c38..bdccd572 100644 --- a/cocoapods/TestApplication.xcodeproj/project.pbxproj +++ b/cocoapods/TestApplication.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 52; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -11,8 +11,6 @@ 515E7B19247E652F0092EA9F /* TestApplicationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515E7B18247E652F0092EA9F /* TestApplicationTests.swift */; }; 515E7B1B247E652F0092EA9F /* TestApplication.h in Headers */ = {isa = PBXBuildFile; fileRef = 515E7B0D247E652F0092EA9F /* TestApplication.h */; settings = {ATTRIBUTES = (Public, ); }; }; C002FB4B4921F3B884E56B53 /* Pods_TestApplication.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 33DD5637C4B93179658AF996 /* Pods_TestApplication.framework */; }; - FB036776285F59AC004DEA97 /* TestApplicationTests.xctest in Resources */ = {isa = PBXBuildFile; fileRef = 515E7B13247E652F0092EA9F /* TestApplicationTests.xctest */; }; - FB8C5CAE28759F5800CB3C54 /* TestApplication.framework in Resources */ = {isa = PBXBuildFile; fileRef = 515E7B0A247E652F0092EA9F /* TestApplication.framework */; platformFilter = ios; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -31,7 +29,7 @@ 33DD5637C4B93179658AF996 /* Pods_TestApplication.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_TestApplication.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 3E2D7627985D802D622C4CDA /* Pods-TestApplication-TestApplicationTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-TestApplication-TestApplicationTests.release.xcconfig"; path = "Target Support Files/Pods-TestApplication-TestApplicationTests/Pods-TestApplication-TestApplicationTests.release.xcconfig"; sourceTree = ""; }; 4A05A45AD7D3DA9579477D6D /* Pods_TestApplication_TestApplicationTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_TestApplication_TestApplicationTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 515E7B0A247E652F0092EA9F /* TestApplication.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TestApplication.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 515E7B0A247E652F0092EA9F /* TestApplication.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TestApplication.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 515E7B0D247E652F0092EA9F /* TestApplication.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestApplication.h; sourceTree = ""; }; 515E7B0E247E652F0092EA9F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 515E7B13247E652F0092EA9F /* TestApplicationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TestApplicationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -177,8 +175,9 @@ 515E7B01247E652F0092EA9F /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 1150; - LastUpgradeCheck = 1150; + LastUpgradeCheck = 1540; ORGANIZATIONNAME = torus; TargetAttributes = { 515E7B09247E652F0092EA9F = { @@ -213,7 +212,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - FB8C5CAE28759F5800CB3C54 /* TestApplication.framework in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -221,7 +219,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - FB036776285F59AC004DEA97 /* TestApplicationTests.xctest in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -322,6 +319,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -344,6 +342,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -355,6 +354,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -385,6 +385,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -407,6 +408,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -418,6 +420,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -442,12 +445,14 @@ isa = XCBuildConfiguration; baseConfigurationReference = 991B2F67E76DF3DBF4500D2D /* Pods-TestApplication.debug.xcconfig */; buildSettings = { + CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 2Q63NCPY55; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; INFOPLIST_FILE = TestApplication/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 13.4; @@ -456,6 +461,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14"; PRODUCT_BUNDLE_IDENTIFIER = torus.TestApplication; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; @@ -469,12 +475,14 @@ isa = XCBuildConfiguration; baseConfigurationReference = 1CC8F5CD8A6C11076C7B9EA2 /* Pods-TestApplication.release.xcconfig */; buildSettings = { + CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 2Q63NCPY55; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_MODULE_VERIFIER = YES; INFOPLIST_FILE = TestApplication/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 13.4; @@ -483,6 +491,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); + MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu11 gnu++14"; PRODUCT_BUNDLE_IDENTIFIER = torus.TestApplication; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES;