├── .github └── workflows │ └── main.yml ├── .gitignore ├── CustomAuth.podspec ├── CustomAuthDemo ├── CustomAuthDemo.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ └── swiftpm │ │ │ └── Package.resolved │ └── xcshareddata │ │ └── xcschemes │ │ ├── CustomAuthDemo.xcscheme │ │ ├── CustomAuthDemoTests.xcscheme │ │ └── CustomAuthDemoUITests.xcscheme ├── CustomAuthDemo │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── Contents.json │ ├── ContentView.swift │ ├── CustomAuthDemo.swift │ ├── CustomAuthSDKDemo.entitlements │ ├── Info.plist │ └── Preview Content │ │ └── Preview Assets.xcassets │ │ └── Contents.json ├── CustomAuthDemoTests │ ├── CustomAuthDemoTests.swift │ └── Info.plist └── CustomAuthDemoUITests │ ├── CustomAuthDemoUITests.swift │ └── Info.plist ├── Development.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ ├── IDEWorkspaceChecks.plist │ ├── WorkspaceSettings.xcsettings │ └── swiftpm │ └── Package.resolved ├── License.md ├── Package.resolved ├── Package.swift ├── README.md ├── Sources └── CustomAuth │ ├── Common │ ├── AggregateVerifierParams │ │ ├── AggregateLoginParams.swift │ │ └── AggregateVerifierType.swift │ ├── HashParams.swift │ ├── LoginParams │ │ ├── Auth0ClientOptions.swift │ │ ├── Auth0JwtLoginType.swift │ │ ├── BaseLoginOptions.swift │ │ ├── EmailFlowType.swift │ │ ├── LoginType.swift │ │ ├── SubVerifierDetails.swift │ │ └── TorusSubVerifierInfo.swift │ ├── LoginResponses │ │ ├── LoginWindowResponse.swift │ │ ├── TorusAggregateLoginResponse.swift │ │ └── TorusLoginResponse.swift │ ├── Passkeys │ │ ├── AuthenticatorTransports.swift │ │ └── PassKeyExtraParams.swift │ ├── PopupResponse.swift │ ├── RedirectResultParams.swift │ ├── State.swift │ ├── TorusGenericContainer.swift │ └── VerifierResponses │ │ ├── TorusAggregateVerifierResponse.swift │ │ ├── TorusSingleVerifierResponse.swift │ │ ├── TorusVerifierResponses.swift │ │ └── UserInfo.swift │ ├── CustomAuth.swift │ ├── CustomAuthArgs.swift │ ├── Extension │ ├── Data+extension.swift │ ├── String+extension.swift │ └── URLComponents+extension.swift │ ├── Handlers │ ├── AuthenticationManager.swift │ ├── DiscordLoginHandler.swift │ ├── FacebookLoginHandler.swift │ ├── GoogleLoginHandler.swift │ ├── HandlerFactory.swift │ ├── JWTLoginHandler.swift │ ├── MockLoginHandler.swift │ ├── Protocol │ │ ├── AbstractLoginHandler.swift │ │ ├── CreateHandlerParams.swift │ │ └── ILoginHandler.swift │ ├── TwitchLoginHandler.swift │ └── Web3AuthPasswordlessLoginHandler.swift │ └── Helpers │ ├── Common.swift │ └── Error.swift ├── Tests ├── CustomAuthTests │ ├── CustomAuthTests.swift │ └── XCTestManifests.swift └── LinuxMain.swift └── cocoapods ├── Podfile ├── Podfile.lock ├── cptest.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcschemes │ └── cptest.xcscheme ├── cptest.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ ├── IDEWorkspaceChecks.plist │ └── WorkspaceSettings.xcsettings └── cptest ├── AppDelegate.swift ├── Assets.xcassets ├── AppIcon.appiconset │ └── Contents.json └── Contents.json ├── ContentView.swift ├── Info.plist ├── LoginView.swift ├── Preview Content └── Preview Assets.xcassets │ └── Contents.json ├── SceneDelegate.swift ├── UserInfoView.swift └── ViewModel.swift /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | 2 | 3 | # This is a basic workflow to help you get started with Actions 4 | 5 | name: CI 6 | 7 | # Controls when the workflow will run 8 | on: 9 | # Triggers the workflow on push or pull request events but only for the master branch 10 | push: 11 | branches: 12 | - master 13 | pull_request: 14 | branches: 15 | - master 16 | 17 | # Allows you to run this workflow manually from the Actions tab 18 | workflow_dispatch: 19 | 20 | # Checkout the code, and run mxcl's xcodebuild action to run the unit tests 21 | jobs: 22 | build: 23 | runs-on: macOS-latest 24 | strategy: 25 | matrix: 26 | platform: 27 | - iOS 28 | steps: 29 | - uses: actions/checkout@v4 30 | - name: Remove Development.xcworkspace to avoid tooling confusion 31 | run: rm -rf Development.xcworkspace 32 | - uses: mxcl/xcodebuild@v3.0.0 33 | with: 34 | platform: ${{ matrix.platform }} 35 | action: test 36 | scheme: CustomAuth 37 | code-coverage: true 38 | upload-logs: always 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## User settings 6 | xcuserdata/ 7 | 8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 9 | *.xcscmblueprint 10 | *.xccheckout 11 | 12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 13 | build/ 14 | DerivedData/ 15 | *.moved-aside 16 | *.pbxuser 17 | !default.pbxuser 18 | *.mode1v3 19 | !default.mode1v3 20 | *.mode2v3 21 | !default.mode2v3 22 | *.perspectivev3 23 | !default.perspectivev3 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | 28 | ## App packaging 29 | *.ipa 30 | *.dSYM.zip 31 | *.dSYM 32 | 33 | ## Playgrounds 34 | timeline.xctimeline 35 | playground.xcworkspace 36 | 37 | # Swift Package Manager 38 | # 39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 40 | # Packages/ 41 | # Package.pins 42 | # Package.resolved 43 | # *.xcodeproj 44 | # 45 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 46 | # hence it is not needed unless you have added a package configuration file to your project 47 | .swiftpm 48 | .swiftpm/ 49 | 50 | .build/ 51 | 52 | # CocoaPods 53 | # 54 | # We recommend against adding the Pods directory to your .gitignore. However 55 | # you should judge for yourself, the pros and cons are mentioned at: 56 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 57 | # 58 | Pods/ 59 | # 60 | # Add this line if you want to avoid checking in source code from the Xcode workspace 61 | # *.xcworkspace 62 | 63 | # Carthage 64 | # 65 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 66 | # Carthage/Checkouts 67 | 68 | Carthage/Build/ 69 | 70 | # Accio dependency management 71 | Dependencies/ 72 | .accio/ 73 | 74 | # fastlane 75 | # 76 | # It is recommended to not store the screenshots in the git repo. 77 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 78 | # For more information about the recommended setup visit: 79 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 80 | 81 | fastlane/report.xml 82 | fastlane/Preview.html 83 | fastlane/screenshots/**/*.png 84 | fastlane/test_output 85 | 86 | # Code Injection 87 | # 88 | # After new code Injection tools there's a generated folder /iOSInjectionProject 89 | # https://github.com/johnno1962/injectionforxcode 90 | 91 | iOSInjectionProject/ 92 | 93 | .idea/ 94 | 95 | .DS_Store 96 | -------------------------------------------------------------------------------- /CustomAuth.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |spec| 2 | spec.name = "CustomAuth" 3 | spec.version = "11.0.2" 4 | spec.platform = :ios, "14.0" 5 | spec.summary = "Swift SDK that allows applications to directly interact with the Torus Network, similar to how Torus Wallet does." 6 | spec.homepage = "https://github.com/torusresearch/customauth-swift-sdk" 7 | spec.license = { :type => 'BSD', :file => 'License.md' } 8 | spec.swift_version = "5.3" 9 | spec.author = { "Torus Labs" => "hello@tor.us" } 10 | spec.module_name = "CustomAuth" 11 | spec.source = { :git => "https://github.com/torusresearch/customauth-swift-sdk.git", :tag => spec.version } 12 | spec.source_files = "Sources/CustomAuth/*.{swift}","Sources/CustomAuth/**/*.{swift}" 13 | spec.dependency 'Torus-utils', '~> 10.0.0' 14 | spec.dependency 'JWTDecode', '~> 3.2.0' 15 | end 16 | -------------------------------------------------------------------------------- /CustomAuthDemo/CustomAuthDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 54; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 275FCF862C8EABF40010F33B /* CustomAuth in Frameworks */ = {isa = PBXBuildFile; productRef = 275FCF852C8EABF40010F33B /* CustomAuth */; }; 11 | 511CEAD02452D4EC00A7ACE9 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 511CEACF2452D4EC00A7ACE9 /* ContentView.swift */; }; 12 | 511CEAD22452D4EF00A7ACE9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 511CEAD12452D4EF00A7ACE9 /* Assets.xcassets */; }; 13 | 511CEAD52452D4EF00A7ACE9 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 511CEAD42452D4EF00A7ACE9 /* Preview Assets.xcassets */; }; 14 | 511CEAE32452D4EF00A7ACE9 /* CustomAuthDemoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 511CEAE22452D4EF00A7ACE9 /* CustomAuthDemoTests.swift */; }; 15 | 511CEAEE2452D4EF00A7ACE9 /* CustomAuthDemoUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 511CEAED2452D4EF00A7ACE9 /* CustomAuthDemoUITests.swift */; }; 16 | 51775EB72484B66A00A29680 /* CustomAuth in Frameworks */ = {isa = PBXBuildFile; productRef = 51775EB62484B66A00A29680 /* CustomAuth */; }; 17 | B37E3CEE2C1CF30F00B63F41 /* CustomAuthDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B37E3CED2C1CF30F00B63F41 /* CustomAuthDemo.swift */; }; 18 | B37E3CF12C1E1C6E00B63F41 /* CustomAuth in Frameworks */ = {isa = PBXBuildFile; productRef = B37E3CF02C1E1C6E00B63F41 /* CustomAuth */; }; 19 | B37E3CF32C1E23B700B63F41 /* CustomAuth in Frameworks */ = {isa = PBXBuildFile; productRef = B37E3CF22C1E23B700B63F41 /* CustomAuth */; }; 20 | /* End PBXBuildFile section */ 21 | 22 | /* Begin PBXContainerItemProxy section */ 23 | 511CEADF2452D4EF00A7ACE9 /* PBXContainerItemProxy */ = { 24 | isa = PBXContainerItemProxy; 25 | containerPortal = 511CEAC02452D4EC00A7ACE9 /* Project object */; 26 | proxyType = 1; 27 | remoteGlobalIDString = 511CEAC72452D4EC00A7ACE9; 28 | remoteInfo = CustomAuthDemo; 29 | }; 30 | 511CEAEA2452D4EF00A7ACE9 /* PBXContainerItemProxy */ = { 31 | isa = PBXContainerItemProxy; 32 | containerPortal = 511CEAC02452D4EC00A7ACE9 /* Project object */; 33 | proxyType = 1; 34 | remoteGlobalIDString = 511CEAC72452D4EC00A7ACE9; 35 | remoteInfo = CustomAuthDemo; 36 | }; 37 | /* End PBXContainerItemProxy section */ 38 | 39 | /* Begin PBXFileReference section */ 40 | 511CEAC82452D4EC00A7ACE9 /* CustomAuthDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CustomAuthDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | 511CEACF2452D4EC00A7ACE9 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 42 | 511CEAD12452D4EF00A7ACE9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 43 | 511CEAD42452D4EF00A7ACE9 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 44 | 511CEAD92452D4EF00A7ACE9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 45 | 511CEADE2452D4EF00A7ACE9 /* CustomAuthDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CustomAuthDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 46 | 511CEAE22452D4EF00A7ACE9 /* CustomAuthDemoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomAuthDemoTests.swift; sourceTree = ""; }; 47 | 511CEAE42452D4EF00A7ACE9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 48 | 511CEAE92452D4EF00A7ACE9 /* CustomAuthDemoUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CustomAuthDemoUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 49 | 511CEAED2452D4EF00A7ACE9 /* CustomAuthDemoUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomAuthDemoUITests.swift; sourceTree = ""; }; 50 | 511CEAEF2452D4EF00A7ACE9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 51 | A3C24F222A70FAF9002F4FC9 /* customauth-swift-sdk */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = "customauth-swift-sdk"; path = ..; sourceTree = ""; }; 52 | B37E3CED2C1CF30F00B63F41 /* CustomAuthDemo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomAuthDemo.swift; sourceTree = ""; }; 53 | /* End PBXFileReference section */ 54 | 55 | /* Begin PBXFrameworksBuildPhase section */ 56 | 511CEAC52452D4EC00A7ACE9 /* Frameworks */ = { 57 | isa = PBXFrameworksBuildPhase; 58 | buildActionMask = 2147483647; 59 | files = ( 60 | 51775EB72484B66A00A29680 /* CustomAuth in Frameworks */, 61 | 275FCF862C8EABF40010F33B /* CustomAuth in Frameworks */, 62 | ); 63 | runOnlyForDeploymentPostprocessing = 0; 64 | }; 65 | 511CEADB2452D4EF00A7ACE9 /* Frameworks */ = { 66 | isa = PBXFrameworksBuildPhase; 67 | buildActionMask = 2147483647; 68 | files = ( 69 | B37E3CF32C1E23B700B63F41 /* CustomAuth in Frameworks */, 70 | ); 71 | runOnlyForDeploymentPostprocessing = 0; 72 | }; 73 | 511CEAE62452D4EF00A7ACE9 /* Frameworks */ = { 74 | isa = PBXFrameworksBuildPhase; 75 | buildActionMask = 2147483647; 76 | files = ( 77 | B37E3CF12C1E1C6E00B63F41 /* CustomAuth in Frameworks */, 78 | ); 79 | runOnlyForDeploymentPostprocessing = 0; 80 | }; 81 | /* End PBXFrameworksBuildPhase section */ 82 | 83 | /* Begin PBXGroup section */ 84 | 511CEABF2452D4EC00A7ACE9 = { 85 | isa = PBXGroup; 86 | children = ( 87 | A3C24F212A70FAF9002F4FC9 /* Packages */, 88 | 511CEACA2452D4EC00A7ACE9 /* CustomAuthDemo */, 89 | 511CEAE12452D4EF00A7ACE9 /* CustomAuthDemoTests */, 90 | 511CEAEC2452D4EF00A7ACE9 /* CustomAuthDemoUITests */, 91 | 511CEAC92452D4EC00A7ACE9 /* Products */, 92 | B37E3CEF2C1E1C6E00B63F41 /* Frameworks */, 93 | ); 94 | sourceTree = ""; 95 | }; 96 | 511CEAC92452D4EC00A7ACE9 /* Products */ = { 97 | isa = PBXGroup; 98 | children = ( 99 | 511CEAC82452D4EC00A7ACE9 /* CustomAuthDemo.app */, 100 | 511CEADE2452D4EF00A7ACE9 /* CustomAuthDemoTests.xctest */, 101 | 511CEAE92452D4EF00A7ACE9 /* CustomAuthDemoUITests.xctest */, 102 | ); 103 | name = Products; 104 | sourceTree = ""; 105 | }; 106 | 511CEACA2452D4EC00A7ACE9 /* CustomAuthDemo */ = { 107 | isa = PBXGroup; 108 | children = ( 109 | B37E3CED2C1CF30F00B63F41 /* CustomAuthDemo.swift */, 110 | 511CEACF2452D4EC00A7ACE9 /* ContentView.swift */, 111 | 511CEAD12452D4EF00A7ACE9 /* Assets.xcassets */, 112 | 511CEAD92452D4EF00A7ACE9 /* Info.plist */, 113 | 511CEAD32452D4EF00A7ACE9 /* Preview Content */, 114 | ); 115 | path = CustomAuthDemo; 116 | sourceTree = ""; 117 | }; 118 | 511CEAD32452D4EF00A7ACE9 /* Preview Content */ = { 119 | isa = PBXGroup; 120 | children = ( 121 | 511CEAD42452D4EF00A7ACE9 /* Preview Assets.xcassets */, 122 | ); 123 | path = "Preview Content"; 124 | sourceTree = ""; 125 | }; 126 | 511CEAE12452D4EF00A7ACE9 /* CustomAuthDemoTests */ = { 127 | isa = PBXGroup; 128 | children = ( 129 | 511CEAE22452D4EF00A7ACE9 /* CustomAuthDemoTests.swift */, 130 | 511CEAE42452D4EF00A7ACE9 /* Info.plist */, 131 | ); 132 | path = CustomAuthDemoTests; 133 | sourceTree = ""; 134 | }; 135 | 511CEAEC2452D4EF00A7ACE9 /* CustomAuthDemoUITests */ = { 136 | isa = PBXGroup; 137 | children = ( 138 | 511CEAED2452D4EF00A7ACE9 /* CustomAuthDemoUITests.swift */, 139 | 511CEAEF2452D4EF00A7ACE9 /* Info.plist */, 140 | ); 141 | path = CustomAuthDemoUITests; 142 | sourceTree = ""; 143 | }; 144 | A3C24F212A70FAF9002F4FC9 /* Packages */ = { 145 | isa = PBXGroup; 146 | children = ( 147 | A3C24F222A70FAF9002F4FC9 /* customauth-swift-sdk */, 148 | ); 149 | name = Packages; 150 | sourceTree = ""; 151 | }; 152 | B37E3CEF2C1E1C6E00B63F41 /* Frameworks */ = { 153 | isa = PBXGroup; 154 | children = ( 155 | ); 156 | name = Frameworks; 157 | sourceTree = ""; 158 | }; 159 | /* End PBXGroup section */ 160 | 161 | /* Begin PBXNativeTarget section */ 162 | 511CEAC72452D4EC00A7ACE9 /* CustomAuthDemo */ = { 163 | isa = PBXNativeTarget; 164 | buildConfigurationList = 511CEAF22452D4EF00A7ACE9 /* Build configuration list for PBXNativeTarget "CustomAuthDemo" */; 165 | buildPhases = ( 166 | 511CEAC42452D4EC00A7ACE9 /* Sources */, 167 | 511CEAC52452D4EC00A7ACE9 /* Frameworks */, 168 | 511CEAC62452D4EC00A7ACE9 /* Resources */, 169 | ); 170 | buildRules = ( 171 | ); 172 | dependencies = ( 173 | ); 174 | name = CustomAuthDemo; 175 | packageProductDependencies = ( 176 | 51775EB62484B66A00A29680 /* CustomAuth */, 177 | 275FCF852C8EABF40010F33B /* CustomAuth */, 178 | ); 179 | productName = CustomAuthDemo; 180 | productReference = 511CEAC82452D4EC00A7ACE9 /* CustomAuthDemo.app */; 181 | productType = "com.apple.product-type.application"; 182 | }; 183 | 511CEADD2452D4EF00A7ACE9 /* CustomAuthDemoTests */ = { 184 | isa = PBXNativeTarget; 185 | buildConfigurationList = 511CEAF52452D4EF00A7ACE9 /* Build configuration list for PBXNativeTarget "CustomAuthDemoTests" */; 186 | buildPhases = ( 187 | 511CEADA2452D4EF00A7ACE9 /* Sources */, 188 | 511CEADB2452D4EF00A7ACE9 /* Frameworks */, 189 | 511CEADC2452D4EF00A7ACE9 /* Resources */, 190 | ); 191 | buildRules = ( 192 | ); 193 | dependencies = ( 194 | 511CEAE02452D4EF00A7ACE9 /* PBXTargetDependency */, 195 | ); 196 | name = CustomAuthDemoTests; 197 | packageProductDependencies = ( 198 | B37E3CF22C1E23B700B63F41 /* CustomAuth */, 199 | ); 200 | productName = CustomAuthDemoTests; 201 | productReference = 511CEADE2452D4EF00A7ACE9 /* CustomAuthDemoTests.xctest */; 202 | productType = "com.apple.product-type.bundle.unit-test"; 203 | }; 204 | 511CEAE82452D4EF00A7ACE9 /* CustomAuthDemoUITests */ = { 205 | isa = PBXNativeTarget; 206 | buildConfigurationList = 511CEAF82452D4EF00A7ACE9 /* Build configuration list for PBXNativeTarget "CustomAuthDemoUITests" */; 207 | buildPhases = ( 208 | 511CEAE52452D4EF00A7ACE9 /* Sources */, 209 | 511CEAE62452D4EF00A7ACE9 /* Frameworks */, 210 | 511CEAE72452D4EF00A7ACE9 /* Resources */, 211 | ); 212 | buildRules = ( 213 | ); 214 | dependencies = ( 215 | 511CEAEB2452D4EF00A7ACE9 /* PBXTargetDependency */, 216 | ); 217 | name = CustomAuthDemoUITests; 218 | packageProductDependencies = ( 219 | B37E3CF02C1E1C6E00B63F41 /* CustomAuth */, 220 | ); 221 | productName = CustomAuthDemoUITests; 222 | productReference = 511CEAE92452D4EF00A7ACE9 /* CustomAuthDemoUITests.xctest */; 223 | productType = "com.apple.product-type.bundle.ui-testing"; 224 | }; 225 | /* End PBXNativeTarget section */ 226 | 227 | /* Begin PBXProject section */ 228 | 511CEAC02452D4EC00A7ACE9 /* Project object */ = { 229 | isa = PBXProject; 230 | attributes = { 231 | BuildIndependentTargetsInParallel = YES; 232 | LastSwiftUpdateCheck = 1140; 233 | LastUpgradeCheck = 1540; 234 | ORGANIZATIONNAME = Shubham; 235 | TargetAttributes = { 236 | 511CEAC72452D4EC00A7ACE9 = { 237 | CreatedOnToolsVersion = 11.4.1; 238 | }; 239 | 511CEADD2452D4EF00A7ACE9 = { 240 | CreatedOnToolsVersion = 11.4.1; 241 | TestTargetID = 511CEAC72452D4EC00A7ACE9; 242 | }; 243 | 511CEAE82452D4EF00A7ACE9 = { 244 | CreatedOnToolsVersion = 11.4.1; 245 | TestTargetID = 511CEAC72452D4EC00A7ACE9; 246 | }; 247 | }; 248 | }; 249 | buildConfigurationList = 511CEAC32452D4EC00A7ACE9 /* Build configuration list for PBXProject "CustomAuthDemo" */; 250 | compatibilityVersion = "Xcode 9.3"; 251 | developmentRegion = en; 252 | hasScannedForEncodings = 0; 253 | knownRegions = ( 254 | en, 255 | Base, 256 | ); 257 | mainGroup = 511CEABF2452D4EC00A7ACE9; 258 | packageReferences = ( 259 | 275FCF842C8EABF40010F33B /* XCRemoteSwiftPackageReference "customauth-swift-sdk" */, 260 | ); 261 | productRefGroup = 511CEAC92452D4EC00A7ACE9 /* Products */; 262 | projectDirPath = ""; 263 | projectRoot = ""; 264 | targets = ( 265 | 511CEAC72452D4EC00A7ACE9 /* CustomAuthDemo */, 266 | 511CEADD2452D4EF00A7ACE9 /* CustomAuthDemoTests */, 267 | 511CEAE82452D4EF00A7ACE9 /* CustomAuthDemoUITests */, 268 | ); 269 | }; 270 | /* End PBXProject section */ 271 | 272 | /* Begin PBXResourcesBuildPhase section */ 273 | 511CEAC62452D4EC00A7ACE9 /* Resources */ = { 274 | isa = PBXResourcesBuildPhase; 275 | buildActionMask = 2147483647; 276 | files = ( 277 | 511CEAD52452D4EF00A7ACE9 /* Preview Assets.xcassets in Resources */, 278 | 511CEAD22452D4EF00A7ACE9 /* Assets.xcassets in Resources */, 279 | ); 280 | runOnlyForDeploymentPostprocessing = 0; 281 | }; 282 | 511CEADC2452D4EF00A7ACE9 /* Resources */ = { 283 | isa = PBXResourcesBuildPhase; 284 | buildActionMask = 2147483647; 285 | files = ( 286 | ); 287 | runOnlyForDeploymentPostprocessing = 0; 288 | }; 289 | 511CEAE72452D4EF00A7ACE9 /* Resources */ = { 290 | isa = PBXResourcesBuildPhase; 291 | buildActionMask = 2147483647; 292 | files = ( 293 | ); 294 | runOnlyForDeploymentPostprocessing = 0; 295 | }; 296 | /* End PBXResourcesBuildPhase section */ 297 | 298 | /* Begin PBXSourcesBuildPhase section */ 299 | 511CEAC42452D4EC00A7ACE9 /* Sources */ = { 300 | isa = PBXSourcesBuildPhase; 301 | buildActionMask = 2147483647; 302 | files = ( 303 | 511CEAD02452D4EC00A7ACE9 /* ContentView.swift in Sources */, 304 | B37E3CEE2C1CF30F00B63F41 /* CustomAuthDemo.swift in Sources */, 305 | ); 306 | runOnlyForDeploymentPostprocessing = 0; 307 | }; 308 | 511CEADA2452D4EF00A7ACE9 /* Sources */ = { 309 | isa = PBXSourcesBuildPhase; 310 | buildActionMask = 2147483647; 311 | files = ( 312 | 511CEAE32452D4EF00A7ACE9 /* CustomAuthDemoTests.swift in Sources */, 313 | ); 314 | runOnlyForDeploymentPostprocessing = 0; 315 | }; 316 | 511CEAE52452D4EF00A7ACE9 /* Sources */ = { 317 | isa = PBXSourcesBuildPhase; 318 | buildActionMask = 2147483647; 319 | files = ( 320 | 511CEAEE2452D4EF00A7ACE9 /* CustomAuthDemoUITests.swift in Sources */, 321 | ); 322 | runOnlyForDeploymentPostprocessing = 0; 323 | }; 324 | /* End PBXSourcesBuildPhase section */ 325 | 326 | /* Begin PBXTargetDependency section */ 327 | 511CEAE02452D4EF00A7ACE9 /* PBXTargetDependency */ = { 328 | isa = PBXTargetDependency; 329 | target = 511CEAC72452D4EC00A7ACE9 /* CustomAuthDemo */; 330 | targetProxy = 511CEADF2452D4EF00A7ACE9 /* PBXContainerItemProxy */; 331 | }; 332 | 511CEAEB2452D4EF00A7ACE9 /* PBXTargetDependency */ = { 333 | isa = PBXTargetDependency; 334 | target = 511CEAC72452D4EC00A7ACE9 /* CustomAuthDemo */; 335 | targetProxy = 511CEAEA2452D4EF00A7ACE9 /* PBXContainerItemProxy */; 336 | }; 337 | /* End PBXTargetDependency section */ 338 | 339 | /* Begin XCBuildConfiguration section */ 340 | 511CEAF02452D4EF00A7ACE9 /* Debug */ = { 341 | isa = XCBuildConfiguration; 342 | buildSettings = { 343 | ALWAYS_SEARCH_USER_PATHS = NO; 344 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 345 | CLANG_ANALYZER_NONNULL = YES; 346 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 347 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 348 | CLANG_CXX_LIBRARY = "libc++"; 349 | CLANG_ENABLE_MODULES = YES; 350 | CLANG_ENABLE_OBJC_ARC = YES; 351 | CLANG_ENABLE_OBJC_WEAK = YES; 352 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 353 | CLANG_WARN_BOOL_CONVERSION = YES; 354 | CLANG_WARN_COMMA = YES; 355 | CLANG_WARN_CONSTANT_CONVERSION = YES; 356 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 357 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 358 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 359 | CLANG_WARN_EMPTY_BODY = YES; 360 | CLANG_WARN_ENUM_CONVERSION = YES; 361 | CLANG_WARN_INFINITE_RECURSION = YES; 362 | CLANG_WARN_INT_CONVERSION = YES; 363 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 364 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 365 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 366 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 367 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 368 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 369 | CLANG_WARN_STRICT_PROTOTYPES = YES; 370 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 371 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 372 | CLANG_WARN_UNREACHABLE_CODE = YES; 373 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 374 | COPY_PHASE_STRIP = NO; 375 | DEBUG_INFORMATION_FORMAT = dwarf; 376 | ENABLE_STRICT_OBJC_MSGSEND = YES; 377 | ENABLE_TESTABILITY = YES; 378 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 379 | GCC_C_LANGUAGE_STANDARD = gnu11; 380 | GCC_DYNAMIC_NO_PIC = NO; 381 | GCC_NO_COMMON_BLOCKS = YES; 382 | GCC_OPTIMIZATION_LEVEL = 0; 383 | GCC_PREPROCESSOR_DEFINITIONS = ( 384 | "DEBUG=1", 385 | "$(inherited)", 386 | ); 387 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 388 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 389 | GCC_WARN_UNDECLARED_SELECTOR = YES; 390 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 391 | GCC_WARN_UNUSED_FUNCTION = YES; 392 | GCC_WARN_UNUSED_VARIABLE = YES; 393 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 394 | MACOSX_DEPLOYMENT_TARGET = 10.15; 395 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 396 | MTL_FAST_MATH = YES; 397 | ONLY_ACTIVE_ARCH = YES; 398 | SDKROOT = iphoneos; 399 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 400 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 401 | }; 402 | name = Debug; 403 | }; 404 | 511CEAF12452D4EF00A7ACE9 /* Release */ = { 405 | isa = XCBuildConfiguration; 406 | buildSettings = { 407 | ALWAYS_SEARCH_USER_PATHS = NO; 408 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 409 | CLANG_ANALYZER_NONNULL = YES; 410 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 411 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 412 | CLANG_CXX_LIBRARY = "libc++"; 413 | CLANG_ENABLE_MODULES = YES; 414 | CLANG_ENABLE_OBJC_ARC = YES; 415 | CLANG_ENABLE_OBJC_WEAK = YES; 416 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 417 | CLANG_WARN_BOOL_CONVERSION = YES; 418 | CLANG_WARN_COMMA = YES; 419 | CLANG_WARN_CONSTANT_CONVERSION = YES; 420 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 421 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 422 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 423 | CLANG_WARN_EMPTY_BODY = YES; 424 | CLANG_WARN_ENUM_CONVERSION = YES; 425 | CLANG_WARN_INFINITE_RECURSION = YES; 426 | CLANG_WARN_INT_CONVERSION = YES; 427 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 428 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 429 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 430 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 431 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 432 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 433 | CLANG_WARN_STRICT_PROTOTYPES = YES; 434 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 435 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 436 | CLANG_WARN_UNREACHABLE_CODE = YES; 437 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 438 | COPY_PHASE_STRIP = NO; 439 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 440 | ENABLE_NS_ASSERTIONS = NO; 441 | ENABLE_STRICT_OBJC_MSGSEND = YES; 442 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 443 | GCC_C_LANGUAGE_STANDARD = gnu11; 444 | GCC_NO_COMMON_BLOCKS = YES; 445 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 446 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 447 | GCC_WARN_UNDECLARED_SELECTOR = YES; 448 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 449 | GCC_WARN_UNUSED_FUNCTION = YES; 450 | GCC_WARN_UNUSED_VARIABLE = YES; 451 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 452 | MACOSX_DEPLOYMENT_TARGET = 10.15; 453 | MTL_ENABLE_DEBUG_INFO = NO; 454 | MTL_FAST_MATH = YES; 455 | SDKROOT = iphoneos; 456 | SWIFT_COMPILATION_MODE = wholemodule; 457 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 458 | VALIDATE_PRODUCT = YES; 459 | }; 460 | name = Release; 461 | }; 462 | 511CEAF32452D4EF00A7ACE9 /* Debug */ = { 463 | isa = XCBuildConfiguration; 464 | buildSettings = { 465 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 466 | CODE_SIGN_ENTITLEMENTS = ""; 467 | CODE_SIGN_STYLE = Automatic; 468 | DEVELOPMENT_ASSET_PATHS = "\"CustomAuthDemo/Preview Content\""; 469 | DEVELOPMENT_TEAM = 2Q63NCPY55; 470 | ENABLE_PREVIEWS = YES; 471 | INFOPLIST_FILE = CustomAuthDemo/Info.plist; 472 | IPHONEOS_DEPLOYMENT_TARGET = 16.0; 473 | LD_RUNPATH_SEARCH_PATHS = ( 474 | "$(inherited)", 475 | "@executable_path/Frameworks", 476 | ); 477 | PRODUCT_BUNDLE_IDENTIFIER = com.torus.CustomAuthDemo; 478 | PRODUCT_NAME = "$(TARGET_NAME)"; 479 | SWIFT_VERSION = 5.0; 480 | TARGETED_DEVICE_FAMILY = "1,2"; 481 | }; 482 | name = Debug; 483 | }; 484 | 511CEAF42452D4EF00A7ACE9 /* Release */ = { 485 | isa = XCBuildConfiguration; 486 | buildSettings = { 487 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 488 | CODE_SIGN_ENTITLEMENTS = ""; 489 | CODE_SIGN_STYLE = Automatic; 490 | DEVELOPMENT_ASSET_PATHS = "\"CustomAuthDemo/Preview Content\""; 491 | DEVELOPMENT_TEAM = 2Q63NCPY55; 492 | ENABLE_PREVIEWS = YES; 493 | INFOPLIST_FILE = CustomAuthDemo/Info.plist; 494 | IPHONEOS_DEPLOYMENT_TARGET = 16.0; 495 | LD_RUNPATH_SEARCH_PATHS = ( 496 | "$(inherited)", 497 | "@executable_path/Frameworks", 498 | ); 499 | PRODUCT_BUNDLE_IDENTIFIER = com.torus.CustomAuthDemo; 500 | PRODUCT_NAME = "$(TARGET_NAME)"; 501 | SWIFT_VERSION = 5.0; 502 | TARGETED_DEVICE_FAMILY = "1,2"; 503 | }; 504 | name = Release; 505 | }; 506 | 511CEAF62452D4EF00A7ACE9 /* Debug */ = { 507 | isa = XCBuildConfiguration; 508 | buildSettings = { 509 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 510 | BUNDLE_LOADER = "$(TEST_HOST)"; 511 | CODE_SIGN_STYLE = Automatic; 512 | INFOPLIST_FILE = CustomAuthDemoTests/Info.plist; 513 | IPHONEOS_DEPLOYMENT_TARGET = 16.0; 514 | LD_RUNPATH_SEARCH_PATHS = ( 515 | "$(inherited)", 516 | "@executable_path/Frameworks", 517 | "@loader_path/Frameworks", 518 | ); 519 | PRODUCT_BUNDLE_IDENTIFIER = torus.CustomAuthDemoTests; 520 | PRODUCT_NAME = "$(TARGET_NAME)"; 521 | SWIFT_VERSION = 5.0; 522 | TARGETED_DEVICE_FAMILY = "1,2"; 523 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/CustomAuthDemo.app/CustomAuthDemo"; 524 | }; 525 | name = Debug; 526 | }; 527 | 511CEAF72452D4EF00A7ACE9 /* Release */ = { 528 | isa = XCBuildConfiguration; 529 | buildSettings = { 530 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 531 | BUNDLE_LOADER = "$(TEST_HOST)"; 532 | CODE_SIGN_STYLE = Automatic; 533 | INFOPLIST_FILE = CustomAuthDemoTests/Info.plist; 534 | IPHONEOS_DEPLOYMENT_TARGET = 16.0; 535 | LD_RUNPATH_SEARCH_PATHS = ( 536 | "$(inherited)", 537 | "@executable_path/Frameworks", 538 | "@loader_path/Frameworks", 539 | ); 540 | PRODUCT_BUNDLE_IDENTIFIER = torus.CustomAuthDemoTests; 541 | PRODUCT_NAME = "$(TARGET_NAME)"; 542 | SWIFT_VERSION = 5.0; 543 | TARGETED_DEVICE_FAMILY = "1,2"; 544 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/CustomAuthDemo.app/CustomAuthDemo"; 545 | }; 546 | name = Release; 547 | }; 548 | 511CEAF92452D4EF00A7ACE9 /* Debug */ = { 549 | isa = XCBuildConfiguration; 550 | buildSettings = { 551 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 552 | CODE_SIGN_STYLE = Automatic; 553 | INFOPLIST_FILE = CustomAuthDemoUITests/Info.plist; 554 | IPHONEOS_DEPLOYMENT_TARGET = 16.0; 555 | LD_RUNPATH_SEARCH_PATHS = ( 556 | "$(inherited)", 557 | "@executable_path/Frameworks", 558 | "@loader_path/Frameworks", 559 | ); 560 | PRODUCT_BUNDLE_IDENTIFIER = torus.CustomAuthDemoUITests; 561 | PRODUCT_NAME = "$(TARGET_NAME)"; 562 | SWIFT_VERSION = 5.0; 563 | TARGETED_DEVICE_FAMILY = "1,2"; 564 | TEST_TARGET_NAME = CustomAuthDemo; 565 | }; 566 | name = Debug; 567 | }; 568 | 511CEAFA2452D4EF00A7ACE9 /* Release */ = { 569 | isa = XCBuildConfiguration; 570 | buildSettings = { 571 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 572 | CODE_SIGN_STYLE = Automatic; 573 | INFOPLIST_FILE = CustomAuthDemoUITests/Info.plist; 574 | IPHONEOS_DEPLOYMENT_TARGET = 16.0; 575 | LD_RUNPATH_SEARCH_PATHS = ( 576 | "$(inherited)", 577 | "@executable_path/Frameworks", 578 | "@loader_path/Frameworks", 579 | ); 580 | PRODUCT_BUNDLE_IDENTIFIER = torus.CustomAuthDemoUITests; 581 | PRODUCT_NAME = "$(TARGET_NAME)"; 582 | SWIFT_VERSION = 5.0; 583 | TARGETED_DEVICE_FAMILY = "1,2"; 584 | TEST_TARGET_NAME = CustomAuthDemo; 585 | }; 586 | name = Release; 587 | }; 588 | /* End XCBuildConfiguration section */ 589 | 590 | /* Begin XCConfigurationList section */ 591 | 511CEAC32452D4EC00A7ACE9 /* Build configuration list for PBXProject "CustomAuthDemo" */ = { 592 | isa = XCConfigurationList; 593 | buildConfigurations = ( 594 | 511CEAF02452D4EF00A7ACE9 /* Debug */, 595 | 511CEAF12452D4EF00A7ACE9 /* Release */, 596 | ); 597 | defaultConfigurationIsVisible = 0; 598 | defaultConfigurationName = Release; 599 | }; 600 | 511CEAF22452D4EF00A7ACE9 /* Build configuration list for PBXNativeTarget "CustomAuthDemo" */ = { 601 | isa = XCConfigurationList; 602 | buildConfigurations = ( 603 | 511CEAF32452D4EF00A7ACE9 /* Debug */, 604 | 511CEAF42452D4EF00A7ACE9 /* Release */, 605 | ); 606 | defaultConfigurationIsVisible = 0; 607 | defaultConfigurationName = Release; 608 | }; 609 | 511CEAF52452D4EF00A7ACE9 /* Build configuration list for PBXNativeTarget "CustomAuthDemoTests" */ = { 610 | isa = XCConfigurationList; 611 | buildConfigurations = ( 612 | 511CEAF62452D4EF00A7ACE9 /* Debug */, 613 | 511CEAF72452D4EF00A7ACE9 /* Release */, 614 | ); 615 | defaultConfigurationIsVisible = 0; 616 | defaultConfigurationName = Release; 617 | }; 618 | 511CEAF82452D4EF00A7ACE9 /* Build configuration list for PBXNativeTarget "CustomAuthDemoUITests" */ = { 619 | isa = XCConfigurationList; 620 | buildConfigurations = ( 621 | 511CEAF92452D4EF00A7ACE9 /* Debug */, 622 | 511CEAFA2452D4EF00A7ACE9 /* Release */, 623 | ); 624 | defaultConfigurationIsVisible = 0; 625 | defaultConfigurationName = Release; 626 | }; 627 | /* End XCConfigurationList section */ 628 | 629 | /* Begin XCRemoteSwiftPackageReference section */ 630 | 275FCF842C8EABF40010F33B /* XCRemoteSwiftPackageReference "customauth-swift-sdk" */ = { 631 | isa = XCRemoteSwiftPackageReference; 632 | repositoryURL = "https://github.com/torusresearch/customauth-swift-sdk/"; 633 | requirement = { 634 | kind = exactVersion; 635 | version = 11.0.0; 636 | }; 637 | }; 638 | /* End XCRemoteSwiftPackageReference section */ 639 | 640 | /* Begin XCSwiftPackageProductDependency section */ 641 | 275FCF852C8EABF40010F33B /* CustomAuth */ = { 642 | isa = XCSwiftPackageProductDependency; 643 | package = 275FCF842C8EABF40010F33B /* XCRemoteSwiftPackageReference "customauth-swift-sdk" */; 644 | productName = CustomAuth; 645 | }; 646 | 51775EB62484B66A00A29680 /* CustomAuth */ = { 647 | isa = XCSwiftPackageProductDependency; 648 | productName = CustomAuth; 649 | }; 650 | B37E3CF02C1E1C6E00B63F41 /* CustomAuth */ = { 651 | isa = XCSwiftPackageProductDependency; 652 | productName = CustomAuth; 653 | }; 654 | B37E3CF22C1E23B700B63F41 /* CustomAuth */ = { 655 | isa = XCSwiftPackageProductDependency; 656 | productName = CustomAuth; 657 | }; 658 | /* End XCSwiftPackageProductDependency section */ 659 | }; 660 | rootObject = 511CEAC02452D4EC00A7ACE9 /* Project object */; 661 | } 662 | -------------------------------------------------------------------------------- /CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded 6 | 7 | PreviewsEnabled 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "originHash" : "18b632e2194394e0c1a608ed933754bf428e89a5fb32ba332befd79edc99e5f5", 3 | "pins" : [ 4 | { 5 | "identity" : "bigint", 6 | "kind" : "remoteSourceControl", 7 | "location" : "https://github.com/attaswift/BigInt.git", 8 | "state" : { 9 | "revision" : "793a7fac0bfc318e85994bf6900652e827aef33e", 10 | "version" : "5.4.1" 11 | } 12 | }, 13 | { 14 | "identity" : "curvelib.swift", 15 | "kind" : "remoteSourceControl", 16 | "location" : "https://github.com/tkey/curvelib.swift", 17 | "state" : { 18 | "revision" : "432bf1abe7ff505fc2ac9fcf697341ff5b2dc6d0", 19 | "version" : "2.0.0" 20 | } 21 | }, 22 | { 23 | "identity" : "customauth-swift-sdk", 24 | "kind" : "remoteSourceControl", 25 | "location" : "https://github.com/torusresearch/customauth-swift-sdk/", 26 | "state" : { 27 | "revision" : "a06983fa1525f2ca2aa58229dafd94faf88cdc0e", 28 | "version" : "11.0.0" 29 | } 30 | }, 31 | { 32 | "identity" : "fetch-node-details-swift", 33 | "kind" : "remoteSourceControl", 34 | "location" : "https://github.com/torusresearch/fetch-node-details-swift", 35 | "state" : { 36 | "revision" : "52fb5efaa94e0fe3775913ab00964bcb51601c2a", 37 | "version" : "8.0.0" 38 | } 39 | }, 40 | { 41 | "identity" : "jwtdecode.swift", 42 | "kind" : "remoteSourceControl", 43 | "location" : "https://github.com/auth0/JWTDecode.swift.git", 44 | "state" : { 45 | "revision" : "1e153ef009969543191970c66b7c60163c0b4a65", 46 | "version" : "3.2.0" 47 | } 48 | }, 49 | { 50 | "identity" : "torus-utils-swift", 51 | "kind" : "remoteSourceControl", 52 | "location" : "https://github.com/torusresearch/torus-utils-swift.git", 53 | "state" : { 54 | "revision" : "baa822fc67bdb208ed1a2dc5b3c10485cfca15df", 55 | "version" : "10.0.0" 56 | } 57 | } 58 | ], 59 | "version" : 3 60 | } 61 | -------------------------------------------------------------------------------- /CustomAuthDemo/CustomAuthDemo.xcodeproj/xcshareddata/xcschemes/CustomAuthDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 43 | 49 | 50 | 51 | 57 | 63 | 64 | 65 | 71 | 77 | 78 | 79 | 80 | 81 | 86 | 87 | 88 | 89 | 99 | 101 | 107 | 108 | 109 | 110 | 116 | 118 | 124 | 125 | 126 | 127 | 129 | 130 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /CustomAuthDemo/CustomAuthDemo.xcodeproj/xcshareddata/xcschemes/CustomAuthDemoTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 9 | 10 | 16 | 17 | 19 | 25 | 26 | 27 | 28 | 29 | 39 | 41 | 47 | 48 | 49 | 50 | 56 | 57 | 59 | 60 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /CustomAuthDemo/CustomAuthDemo.xcodeproj/xcshareddata/xcschemes/CustomAuthDemoUITests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 9 | 10 | 16 | 17 | 19 | 25 | 26 | 27 | 28 | 29 | 39 | 41 | 47 | 48 | 49 | 50 | 56 | 57 | 63 | 64 | 65 | 66 | 68 | 69 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /CustomAuthDemo/CustomAuthDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /CustomAuthDemo/CustomAuthDemo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /CustomAuthDemo/CustomAuthDemo/ContentView.swift: -------------------------------------------------------------------------------- 1 | import CustomAuth 2 | import SwiftUI 3 | 4 | struct ContentView: View { 5 | @State private var inputDetail: String = "" 6 | 7 | var body: some View { 8 | VStack { 9 | Button(action: { 10 | Task { 11 | do { 12 | let sub = SingleLoginParams(typeOfLogin: .google, verifier: "w3a-google-demo", clientId: "519228911939-cri01h55lsjbsia1k7ll6qpalrus75ps.apps.googleusercontent.com") 13 | 14 | let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .SAPPHIRE_MAINNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") 15 | let customAuth = try CustomAuth(config: customAuthArgs) 16 | let torusLoginResponse = try await customAuth.triggerLogin(args: sub) 17 | let encoded = try JSONEncoder().encode(torusLoginResponse) 18 | print(String(data: encoded, encoding: .utf8)!) 19 | } catch { 20 | print(error) 21 | } 22 | } 23 | }, label: { 24 | Text("Google Login") 25 | }) 26 | 27 | Button(action: { 28 | Task { 29 | do { 30 | let sub = SingleLoginParams(typeOfLogin: .discord, verifier: "w3a-discord-demo", clientId: "1151006428610433095") 31 | 32 | let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .SAPPHIRE_MAINNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") 33 | 34 | let customAuth = try CustomAuth(config: customAuthArgs) 35 | let torusLoginResponse = try await customAuth.triggerLogin(args: sub) 36 | let encoded = try JSONEncoder().encode(torusLoginResponse) 37 | print(String(data: encoded, encoding: .utf8)!) 38 | } catch { 39 | print(error) 40 | } 41 | } 42 | }, label: { 43 | Text("Discord Login") 44 | }) 45 | 46 | Button(action: { 47 | Task { 48 | do { 49 | let sub = SingleLoginParams(typeOfLogin: .facebook, verifier: "w3a-facebook-demo", clientId: "342380202252650") 50 | 51 | let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .SAPPHIRE_MAINNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") 52 | 53 | let customAuth = try CustomAuth(config: customAuthArgs) 54 | let torusLoginResponse = try await customAuth.triggerLogin(args: sub) 55 | let encoded = try JSONEncoder().encode(torusLoginResponse) 56 | print(String(data: encoded, encoding: .utf8)!) 57 | } catch { 58 | print(error) 59 | } 60 | } 61 | }, label: { 62 | Text("Facebook Login") 63 | }) 64 | 65 | Button(action: { 66 | Task { 67 | do { 68 | let sub = SingleLoginParams(typeOfLogin: .twitch, verifier: "w3a-twitch-demo", clientId: "3k7e70gowvxjaxg71hjnc8h8ih3bpf") 69 | let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .SAPPHIRE_MAINNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") 70 | let customAuth = try CustomAuth(config: customAuthArgs) 71 | let torusLoginResponse = try await customAuth.triggerLogin(args: sub) 72 | let encoded = try JSONEncoder().encode(torusLoginResponse) 73 | print(String(data: encoded, encoding: .utf8)!) 74 | } catch { 75 | print(error) 76 | } 77 | } 78 | }, label: { 79 | Text("Twitch Login") 80 | }) 81 | 82 | Button(action: { 83 | Task { 84 | do { 85 | let sub = SingleLoginParams(typeOfLogin: .apple, verifier: "w3a-auth0-demo", clientId: "hUVVf4SEsZT7syOiL0gLU9hFEtm2gQ6O", jwtParams: Auth0ClientOptions(connection: "apple", domain: "web3auth.au.auth0.com")) 86 | let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .SAPPHIRE_MAINNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") 87 | 88 | let customAuth = try CustomAuth(config: customAuthArgs) 89 | let torusLoginResponse = try await customAuth.triggerLogin(args: sub) 90 | let encoded = try JSONEncoder().encode(torusLoginResponse) 91 | print(String(data: encoded, encoding: .utf8)!) 92 | } catch { 93 | print(error) 94 | } 95 | } 96 | }, label: { 97 | Text("Apple Login") 98 | }) 99 | 100 | Button(action: { 101 | Task { 102 | do { 103 | let sub = SingleLoginParams(typeOfLogin: .github, verifier: "w3a-auth0-demo", clientId: "hUVVf4SEsZT7syOiL0gLU9hFEtm2gQ6O", jwtParams: Auth0ClientOptions(connection: "github", domain: "web3auth.au.auth0.com", verifierIdField: "sub")) 104 | let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .SAPPHIRE_MAINNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") 105 | let customAuth = try CustomAuth(config: customAuthArgs) 106 | let torusLoginResponse = try await customAuth.triggerLogin(args: sub) 107 | let encoded = try JSONEncoder().encode(torusLoginResponse) 108 | print(String(data: encoded, encoding: .utf8)!) 109 | } catch { 110 | print(error) 111 | } 112 | } 113 | }, label: { 114 | Text("GitHub Login") 115 | }) 116 | 117 | Button(action: { 118 | Task { 119 | do { 120 | let sub = SingleLoginParams(typeOfLogin: .email_password, 121 | verifier: "torus-auth0-email-password", clientId: "sqKRBVSdwa4WLkaq419U7Bamlh5vK1H7", 122 | jwtParams: Auth0ClientOptions( 123 | connection: "Username-Password-Authentication", 124 | domain: "torus-test.auth0.com", 125 | verifierIdField: "name")) 126 | let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .TESTNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") 127 | let customAuth = try CustomAuth(config: customAuthArgs) 128 | let torusLoginResponse = try await customAuth.triggerLogin(args: sub) 129 | let encoded = try JSONEncoder().encode(torusLoginResponse) 130 | print(String(data: encoded, encoding: .utf8)!) 131 | } catch { 132 | print(error) 133 | } 134 | } 135 | }, label: { 136 | Text("Email Password") 137 | }) 138 | 139 | Label( 140 | title: { Text("Hosted Passwordless") }, 141 | icon: { Image(systemName: "circle") } 142 | ) 143 | TextField( 144 | "Email or Phone Number", 145 | text: $inputDetail 146 | ) 147 | .disableAutocorrection(true) 148 | .border(.secondary) 149 | 150 | Button(action: { 151 | Task { 152 | do { 153 | let sub = SingleLoginParams(typeOfLogin: .email_passwordless, 154 | verifier: "torus-auth0-email-passwordless-lrc", clientId: "P7PJuBCXIHP41lcyty0NEb7Lgf7Zme8Q", 155 | jwtParams: Auth0ClientOptions(verifierIdField: "name", login_hint: inputDetail, flow_type: .link)) 156 | let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .TESTNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") 157 | let customAuth = try CustomAuth(config: customAuthArgs) 158 | let torusLoginResponse = try await customAuth.triggerLogin(args: sub) 159 | let encoded = try JSONEncoder().encode(torusLoginResponse) 160 | print(String(data: encoded, encoding: .utf8)!) 161 | } catch { 162 | print(error) 163 | } 164 | } 165 | }, label: { 166 | Text("Email Passwordless") 167 | }) 168 | 169 | 170 | Button(action: { 171 | Task { 172 | do { 173 | let sub = SingleLoginParams(typeOfLogin: .sms_passwordless, 174 | verifier: "torus-sms-passwordless-lrc", clientId: "P7PJuBCXIHP41lcyty0NEb7Lgf7Zme8Q", 175 | jwtParams: Auth0ClientOptions(login_hint: inputDetail, flow_type: .code)) 176 | let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .TESTNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") 177 | let customAuth = try CustomAuth(config: customAuthArgs) 178 | let torusLoginResponse = try await customAuth.triggerLogin(args: sub) 179 | let encoded = try JSONEncoder().encode(torusLoginResponse) 180 | print(String(data: encoded, encoding: .utf8)!) 181 | } catch { 182 | print(error) 183 | } 184 | } 185 | }, label: { 186 | Text("SMS Passwordless") 187 | }) 188 | 189 | Label( 190 | title: { Text("Aggregate Verifiers") }, 191 | icon: { Image(systemName: "circle") } 192 | ) 193 | 194 | Button(action: { 195 | Task { 196 | do { 197 | let aggregateLoginParams = AggregateLoginParams(aggregateVerifierType: AggregateVerifierType.single_id_verifier, verifierIdentifier: "aggregate-sapphire", subVerifierDetailsArray: [SingleLoginParams(typeOfLogin: .google, verifier: "w3a-google", clientId: "519228911939-cri01h55lsjbsia1k7ll6qpalrus75ps.apps.googleusercontent.com")]) 198 | 199 | let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .SAPPHIRE_MAINNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") 200 | let customAuth = try CustomAuth(config: customAuthArgs) 201 | let torusLoginResponse = try await customAuth.triggerAggregateLogin(args: aggregateLoginParams) 202 | let encoded = try JSONEncoder().encode(torusLoginResponse) 203 | print(String(data: encoded, encoding: .utf8)!) 204 | } catch { 205 | print(error) 206 | } 207 | } 208 | }, label: { 209 | Text("Aggregate Gmail") 210 | }) 211 | 212 | Button(action: { 213 | Task { 214 | do { 215 | let subVerifierDetailsArray = SingleLoginParams(typeOfLogin: .github, verifier: "w3a-a0-github", clientId: "hiLqaop0amgzCC0AXo4w0rrG9abuJTdu", jwtParams: OAuthClientOptions(domain: "web3auth.au.auth0.com", verifierIdField: "email")) 216 | let aggregateLoginParams = AggregateLoginParams(aggregateVerifierType: AggregateVerifierType.single_id_verifier, verifierIdentifier: "aggregate-sapphire", subVerifierDetailsArray: [subVerifierDetailsArray]) 217 | 218 | let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .SAPPHIRE_MAINNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") 219 | let customAuth = try CustomAuth(config: customAuthArgs) 220 | let torusLoginResponse = try await customAuth.triggerAggregateLogin(args: aggregateLoginParams) 221 | let encoded = try JSONEncoder().encode(torusLoginResponse) 222 | print(String(data: encoded, encoding: .utf8)!) 223 | } catch { 224 | print(error) 225 | } 226 | } 227 | }, label: { 228 | Text("Aggregate GitHub") 229 | }) 230 | } 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /CustomAuthDemo/CustomAuthDemo/CustomAuthDemo.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | @main 4 | struct CustomAuthDemo: App { 5 | var body: some Scene { 6 | WindowGroup { 7 | NavigationStack { 8 | ContentView() 9 | } 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /CustomAuthDemo/CustomAuthDemo/CustomAuthSDKDemo.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | aps-environment 6 | development 7 | com.apple.developer.associated-domains 8 | 9 | applinks:backend.relayer.dev.tor.us 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /CustomAuthDemo/CustomAuthDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleURLTypes 20 | 21 | 22 | CFBundleTypeRole 23 | Viewer 24 | CFBundleURLName 25 | tdsdk 26 | CFBundleURLSchemes 27 | 28 | tdsdk://tdsdk/oauthCallback 29 | 30 | 31 | 32 | CFBundleVersion 33 | 1 34 | LSRequiresIPhoneOS 35 | 36 | UIApplicationSceneManifest 37 | 38 | UIApplicationSupportsMultipleScenes 39 | 40 | UISceneConfigurations 41 | 42 | UIWindowSceneSessionRoleApplication 43 | 44 | 45 | UISceneConfigurationName 46 | Default Configuration 47 | 48 | 49 | 50 | 51 | UILaunchStoryboardName 52 | LaunchScreen 53 | UIRequiredDeviceCapabilities 54 | 55 | armv7 56 | 57 | UISupportedInterfaceOrientations 58 | 59 | UIInterfaceOrientationPortrait 60 | UIInterfaceOrientationLandscapeLeft 61 | UIInterfaceOrientationLandscapeRight 62 | 63 | UISupportedInterfaceOrientations~ipad 64 | 65 | UIInterfaceOrientationPortrait 66 | UIInterfaceOrientationPortraitUpsideDown 67 | UIInterfaceOrientationLandscapeLeft 68 | UIInterfaceOrientationLandscapeRight 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /CustomAuthDemo/CustomAuthDemo/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /CustomAuthDemo/CustomAuthDemoTests/CustomAuthDemoTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import CustomAuthDemo 3 | 4 | class CustomAuthDemoTests: XCTestCase { 5 | 6 | override func setUpWithError() throws { 7 | } 8 | 9 | override func tearDownWithError() throws { 10 | } 11 | 12 | func testExample() throws { 13 | } 14 | 15 | func testPerformanceExample() throws { 16 | self.measure { 17 | } 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /CustomAuthDemo/CustomAuthDemoTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /CustomAuthDemo/CustomAuthDemoUITests/CustomAuthDemoUITests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import CustomAuthDemo 3 | 4 | class CustomAuthDemoUITests: XCTestCase { 5 | 6 | override func setUpWithError() throws { 7 | continueAfterFailure = false 8 | } 9 | 10 | override func tearDownWithError() throws { 11 | } 12 | 13 | func testExample() throws { 14 | 15 | } 16 | 17 | func testLaunchPerformance() throws { 18 | measure(metrics: [XCTApplicationLaunchMetric.init()]) { 19 | XCUIApplication().launch() 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /CustomAuthDemo/CustomAuthDemoUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | NSAppTransportSecurity 14 | 15 | NSAllowsArbitraryLoads 16 | 17 | 18 | CFBundleName 19 | $(PRODUCT_NAME) 20 | CFBundlePackageType 21 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 22 | CFBundleShortVersionString 23 | 1.0 24 | CFBundleVersion 25 | 1 26 | 27 | 28 | -------------------------------------------------------------------------------- /Development.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Development.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Development.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded 6 | 7 | PreviewsEnabled 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Development.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "pins" : [ 3 | { 4 | "identity" : "bigint", 5 | "kind" : "remoteSourceControl", 6 | "location" : "https://github.com/attaswift/BigInt.git", 7 | "state" : { 8 | "revision" : "0ed110f7555c34ff468e72e1686e59721f2b0da6", 9 | "version" : "5.3.0" 10 | } 11 | }, 12 | { 13 | "identity" : "curvelib.swift", 14 | "kind" : "remoteSourceControl", 15 | "location" : "https://github.com/tkey/curvelib.swift", 16 | "state" : { 17 | "revision" : "9f88bd5e56d1df443a908f7a7e81ae4f4d9170ea", 18 | "version" : "1.0.1" 19 | } 20 | }, 21 | { 22 | "identity" : "fetch-node-details-swift", 23 | "kind" : "remoteSourceControl", 24 | "location" : "https://github.com/torusresearch/fetch-node-details-swift", 25 | "state" : { 26 | "revision" : "4bd96c33ba8d02d9e27190c5c7cedf09cfdfd656", 27 | "version" : "6.0.3" 28 | } 29 | }, 30 | { 31 | "identity" : "jwt-kit", 32 | "kind" : "remoteSourceControl", 33 | "location" : "https://github.com/vapor/jwt-kit.git", 34 | "state" : { 35 | "revision" : "e05513b5aec24f88012b6e3034115b6bc915356a", 36 | "version" : "4.13.2" 37 | } 38 | }, 39 | { 40 | "identity" : "jwtdecode.swift", 41 | "kind" : "remoteSourceControl", 42 | "location" : "https://github.com/auth0/JWTDecode.swift.git", 43 | "state" : { 44 | "revision" : "58af7278797871e460d79496621b3e5366b865b2", 45 | "version" : "3.1.0" 46 | } 47 | }, 48 | { 49 | "identity" : "swift-crypto", 50 | "kind" : "remoteSourceControl", 51 | "location" : "https://github.com/apple/swift-crypto.git", 52 | "state" : { 53 | "revision" : "f0525da24dc3c6cbb2b6b338b65042bc91cbc4bb", 54 | "version" : "3.3.0" 55 | } 56 | }, 57 | { 58 | "identity" : "torus-utils-swift", 59 | "kind" : "remoteSourceControl", 60 | "location" : "https://github.com/torusresearch/torus-utils-swift.git", 61 | "state" : { 62 | "revision" : "303dc2cf41db7c10f769855edad0e717ced2d554", 63 | "version" : "9.0.0" 64 | } 65 | } 66 | ], 67 | "version" : 2 68 | } 69 | -------------------------------------------------------------------------------- /License.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 Torus Labs Private Limited (https://tor.us) 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 12 | -------------------------------------------------------------------------------- /Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "pins" : [ 3 | { 4 | "identity" : "bigint", 5 | "kind" : "remoteSourceControl", 6 | "location" : "https://github.com/attaswift/BigInt", 7 | "state" : { 8 | "revision" : "0ed110f7555c34ff468e72e1686e59721f2b0da6", 9 | "version" : "5.3.0" 10 | } 11 | }, 12 | { 13 | "identity" : "curvelib.swift", 14 | "kind" : "remoteSourceControl", 15 | "location" : "https://github.com/tkey/curvelib.swift", 16 | "state" : { 17 | "revision" : "432bf1abe7ff505fc2ac9fcf697341ff5b2dc6d0", 18 | "version" : "2.0.0" 19 | } 20 | }, 21 | { 22 | "identity" : "fetch-node-details-swift", 23 | "kind" : "remoteSourceControl", 24 | "location" : "https://github.com/torusresearch/fetch-node-details-swift", 25 | "state" : { 26 | "revision" : "52fb5efaa94e0fe3775913ab00964bcb51601c2a", 27 | "version" : "8.0.0" 28 | } 29 | }, 30 | { 31 | "identity" : "jwt-kit", 32 | "kind" : "remoteSourceControl", 33 | "location" : "https://github.com/vapor/jwt-kit.git", 34 | "state" : { 35 | "revision" : "9e929d925434b91857661bcd455d1bd53f00bf22", 36 | "version" : "4.13.0" 37 | } 38 | }, 39 | { 40 | "identity" : "jwtdecode.swift", 41 | "kind" : "remoteSourceControl", 42 | "location" : "https://github.com/auth0/JWTDecode.swift.git", 43 | "state" : { 44 | "revision" : "1e153ef009969543191970c66b7c60163c0b4a65", 45 | "version" : "3.2.0" 46 | } 47 | }, 48 | { 49 | "identity" : "swift-crypto", 50 | "kind" : "remoteSourceControl", 51 | "location" : "https://github.com/apple/swift-crypto.git", 52 | "state" : { 53 | "revision" : "33a20e650c33f6d72d822d558333f2085effa3dc", 54 | "version" : "2.5.0" 55 | } 56 | }, 57 | { 58 | "identity" : "torus-utils-swift", 59 | "kind" : "remoteSourceControl", 60 | "location" : "https://github.com/torusresearch/torus-utils-swift.git", 61 | "state" : { 62 | "revision" : "baa822fc67bdb208ed1a2dc5b3c10485cfca15df", 63 | "version" : "10.0.0" 64 | } 65 | } 66 | ], 67 | "version" : 2 68 | } 69 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.7 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "CustomAuth", 8 | platforms: [ 9 | .iOS(.v14), .macOS(.v11) 10 | ], 11 | products: [ 12 | .library( 13 | name: "CustomAuth", 14 | targets: ["CustomAuth"]) 15 | ], 16 | dependencies: [ 17 | .package(url: "https://github.com/torusresearch/torus-utils-swift.git", from: "10.0.0"), 18 | .package(url: "https://github.com/auth0/JWTDecode.swift.git", from: "3.2.0"), 19 | // NB: jwt-kit may only be a test dependency or it will break cocoapods support 20 | .package(url: "https://github.com/vapor/jwt-kit.git", from: "4.13.0"), 21 | ], 22 | targets: [ 23 | .target( 24 | name: "CustomAuth", 25 | dependencies: [.product(name: "JWTDecode", package: "JWTDecode.swift"), .product(name: "TorusUtils", package: "torus-utils-swift")]), 26 | .testTarget( 27 | name: "CustomAuthTests", 28 | dependencies: ["CustomAuth", .product(name: "JWTKit", package: "jwt-kit")]) 29 | ], swiftLanguageVersions: [.v5] 30 | ) 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # customauth-swift-sdk 2 | 3 | ## Introduction 4 | 5 | This repo allows iOS applications to retrieve keys stored on the Torus Network 6 | directly. The attestation layer for the Torus Network is generalizable, below is 7 | an example of how to access keys via the SDK via Google. You can read more about 8 | interactions with the Torus Network 9 | [here](https://medium.com/toruslabs/key-assignments-resolution-and-retrieval-afb984500612). 10 | 11 | ## 🩹 Examples 12 | 13 | Checkout the example of `CustomAuth iOS/Swift SDK` in our 14 | [CustomAuthDemo directory.](https://github.com/torusresearch/customauth-swift-sdk/tree/master/CustomAuthDemo) 15 | 16 | ## Usage 17 | 18 | ### 1. Installation 19 | 20 | #### Swift package manager 21 | 22 | In project settings, add the Github URL as a swift package dependency. 23 | 24 | ```swift 25 | import PackageDescription 26 | 27 | let package = Package( 28 | name: "CustomAuth", 29 | dependencies: [ 30 | .package(name: "CustomAuth", url: "https://github.com/torusresearch/customauth-swift-sdk", from: "11.0.0")) 31 | ] 32 | ) 33 | ``` 34 | 35 | #### Cocoapods 36 | 37 | ```ruby 38 | pod 'CustomAuth', '~> 11.0.0' 39 | ``` 40 | 41 | ### 2. Initialization and Login 42 | 43 | Initalize the SDK depending and then you can use the login you require. 44 | 45 | ```swift 46 | import CustomAuth 47 | 48 | let config = CustomAuthArgs(urlScheme: ", enableOneKey: true, web3AuthClientId: "your-web3auth-client-id") 49 | 50 | 51 | let customAuth = try CustomAuth(config: config) 52 | 53 | ``` 54 | 55 | The example login below does so for a single google login. `redirectURL` refers to url for the login flow to 56 | redirect back to your app, it should use the scheme known to your application. 57 | 58 | 59 | ``` 60 | let sub = SingleLoginParams(typeOfLogin: .google, verifier: "", clientId: "", redirectURL: " TorusLoginResponse { 57 | let loginHandler = try HandlerFactory.createHandler(params: CreateHandlerParams(typeOfLogin: args.typeOfLogin, verifier: args.verifier, clientId: args.clientId, urlScheme: config.urlScheme, redirectURL: args.redirectURL, jwtParams: args.jwtParams, customState: args.customState, web3AuthNetwork: self.config.network, web3AuthClientId: self.config.web3AuthClientId)) 58 | 59 | var loginParams: LoginWindowResponse 60 | if args.hash != nil && args.queryParams != nil { 61 | let (error, hashParams, instanceParams) = try handleRedirectParameters(hash: args.hash!, queryParameters: args.queryParams!) 62 | if !error.isEmpty { 63 | throw CASDKError.redirectParamsError(msg: error) 64 | } 65 | loginParams = LoginWindowResponse(accessToken: hashParams.params["access_token"], idToken: hashParams.params["idToken"], ref: hashParams.params["ref"] ?? "", extraParams: hashParams.params["extra_params"], extraParamsPassed: hashParams.params["extra_params_passed"]!, state: instanceParams) 66 | } else { 67 | loginParams = try await loginHandler.handleLoginWindow(popupFeatures: config.popupFeatures) 68 | } 69 | 70 | let userInfo = try await loginHandler.getUserInfo(params: loginParams, storageServerUrl: nil) 71 | 72 | let verifyParams: VerifierParams = VerifierParams(verifier_id: userInfo.verifierId) 73 | 74 | let torusKey = try await getTorusKey(verifier: userInfo.verifier, verifier_id: userInfo.verifierId, verifierParams: verifyParams, idToken: loginParams.idToken ?? loginParams.accessToken ?? "") 75 | 76 | let returnedInfo = UserInfo(email: userInfo.email, name: userInfo.name, profileImage: userInfo.profileImage, aggregateVerifier: userInfo.aggregateVerifier, verifier: userInfo.verifier, verifierId: userInfo.verifierId, typeOfLogin: userInfo.typeOfLogin, ref: userInfo.ref, //extraVerifierParams: userInfo.extraVerifierParams, 77 | accessToken: loginParams.accessToken, idToken: loginParams.idToken, extraParams: loginParams.extraParams, extraParamsPassed: loginParams.extraParamsPassed, state: loginParams.state) 78 | 79 | return TorusLoginResponse(singleVerifierResponse: TorusSingleVerifierResponse(userInfo: returnedInfo, loginResponse: loginParams), torusKey: torusKey) 80 | } 81 | 82 | /// Initiates a login using a aggregate verifier 83 | /// 84 | /// - Parameters: 85 | /// - params: `AggregateLoginParams` 86 | /// 87 | /// - Returns: `TorusAggregateLoginResponse` 88 | /// 89 | /// - Throws: `CASDKError`, `TorusUtilError` 90 | public func triggerAggregateLogin(args: AggregateLoginParams) async throws -> TorusAggregateLoginResponse { 91 | if args.subVerifierDetailsArray.isEmpty { 92 | throw CASDKError.invalidParameters 93 | } 94 | if args.subVerifierDetailsArray.count != 1 && args.aggregateVerifierType == AggregateVerifierType.single_id_verifier { 95 | throw CASDKError.invalidParameters 96 | } 97 | 98 | var loginParamsArray: [LoginWindowResponse] = [] 99 | var userInfoArray: [UserInfo] = [] 100 | for subverifierDetail in args.subVerifierDetailsArray { 101 | let loginHandler = try HandlerFactory.createHandler(params: CreateHandlerParams(typeOfLogin: subverifierDetail.typeOfLogin, verifier: subverifierDetail.verifier, clientId: subverifierDetail.clientId, urlScheme: config.urlScheme, redirectURL: subverifierDetail.redirectURL, jwtParams: subverifierDetail.jwtParams, customState: subverifierDetail.customState, web3AuthNetwork: self.config.network, web3AuthClientId: self.config.web3AuthClientId)) 102 | var loginParams: LoginWindowResponse 103 | var userInfo: UserInfo 104 | if subverifierDetail.hash != nil && subverifierDetail.queryParams != nil { 105 | let (error, hashParams, instanceParams) = try handleRedirectParameters(hash: subverifierDetail.hash!, queryParameters: subverifierDetail.queryParams!) 106 | if !error.isEmpty { 107 | throw CASDKError.redirectParamsError(msg: error) 108 | } 109 | loginParams = LoginWindowResponse(accessToken: hashParams.params["access_token"], idToken: hashParams.params["idToken"], ref: hashParams.params["ref"] ?? "", extraParams: hashParams.params["extra_params"], extraParamsPassed: hashParams.params["extra_params_passed"]!, state: instanceParams) 110 | } else { 111 | loginParams = try await loginHandler.handleLoginWindow(popupFeatures: config.popupFeatures) 112 | } 113 | 114 | let info = try await loginHandler.getUserInfo(params: loginParams, storageServerUrl: nil) 115 | userInfo = UserInfo(email: info.email, name: info.name, profileImage: info.profileImage, aggregateVerifier: args.verifierIdentifier, verifier: info.verifier, verifierId: info.verifierId, typeOfLogin: info.typeOfLogin, ref: info.ref, //extraVerifierParams: info.extraVerifierParams, 116 | accessToken: loginParams.accessToken, idToken: loginParams.idToken, extraParams: loginParams.extraParams, extraParamsPassed: loginParams.extraParamsPassed, state: loginParams.state) 117 | loginParamsArray.append(loginParams) 118 | userInfoArray.append(userInfo) 119 | } 120 | 121 | var subVerifierIds: [String] = [] 122 | var aggregateVerifierParams: [VerifyParams] = [] 123 | var aggregateIdTokenSeeds: [String] = [] 124 | var aggregateVerifierId: String = "" 125 | 126 | for i in 0 ..< args.subVerifierDetailsArray.count { 127 | let loginParams = loginParamsArray[i] 128 | let userInfo = userInfoArray[i] 129 | 130 | aggregateVerifierParams.append(VerifyParams(verifier_id: userInfo.verifierId, idtoken: loginParams.idToken ?? loginParams.accessToken!)) 131 | aggregateIdTokenSeeds.append(loginParams.idToken ?? loginParams.accessToken!) 132 | subVerifierIds.append(userInfo.verifier) 133 | aggregateVerifierId = userInfo.verifierId 134 | } 135 | aggregateIdTokenSeeds.sort() 136 | let joined = aggregateIdTokenSeeds.joined(separator: "\u{29}").data(using: .utf8)! 137 | let aggregateIdToken = try keccak256(data: joined).hexString 138 | let aggregateParams: VerifierParams = VerifierParams(verifier_id: aggregateVerifierId, extended_verifier_id: nil, sub_verifier_ids: subVerifierIds, verify_params: aggregateVerifierParams) 139 | 140 | let aggregateTorusKey = try await getTorusKey(verifier: args.verifierIdentifier, verifier_id: aggregateVerifierId, verifierParams: aggregateParams, idToken: aggregateIdToken) 141 | 142 | var aggregateVerifierResponses: [TorusAggregateVerifierResponse] = [] 143 | for i in 0 ..< userInfoArray.count { 144 | let loginParams = loginParamsArray[i] 145 | let userInfo = userInfoArray[i] 146 | aggregateVerifierResponses.append(TorusAggregateVerifierResponse(userInfo: userInfo, loginResponse: loginParams)) 147 | } 148 | 149 | return TorusAggregateLoginResponse(torusAggregateVerifierResponse: aggregateVerifierResponses, torusKey: aggregateTorusKey) 150 | } 151 | 152 | /// Retrieves the key details 153 | /// 154 | /// - Parameters: 155 | /// - verifier: `String` 156 | /// - verifierParams: `VerifierParams` 157 | /// - idToken: `String` 158 | /// 159 | /// - Returns: `TorusKey` 160 | /// 161 | /// - Throws: `CASDKError`, `TorusUtilError`, `FetchNodeError` 162 | public func getTorusKey(verifier: String, verifier_id: String, verifierParams: VerifierParams, idToken: String, extraParams: TorusUtilsExtraParams? = nil) async throws -> TorusKey { 163 | let nodeDetails = try await nodeDetailManager.getNodeDetails(verifier: verifier, verifierID: verifier_id) 164 | 165 | return try await torus.retrieveShares(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierParams: verifierParams, idToken: idToken) 166 | } 167 | 168 | /// Retrieves the aggregate key details 169 | /// 170 | /// - Parameters: 171 | /// - verifier: `String` 172 | /// - verifierParams: `VerifierParams` 173 | /// - subVerifierInfoArray: `TorusSubVerifierInfo` 174 | /// 175 | /// - Returns: `TorusKey` 176 | /// 177 | /// - Throws: `CASDKError`, `TorusUtilError`, `FetchNodeError` 178 | public func getAggregateTorusKey(verifier: String, verifierParams: VerifierParams, subVerifierInfoArray: [TorusSubVerifierInfo]) async throws -> TorusKey { 179 | let nodeDetails = try await nodeDetailManager.getNodeDetails(verifier: verifier, verifierID: verifierParams.verifier_id) 180 | 181 | var aggregateIdTokenSeeds: [String] = [] 182 | var subVerifierIds: [String] = [] 183 | 184 | var verifyParams: [VerifyParams] = [] 185 | for i in 0 ..< subVerifierInfoArray.count { 186 | let userInfo = subVerifierInfoArray[i] 187 | verifyParams.append(VerifyParams(verifier_id: verifierParams.verifier_id, idtoken: userInfo.idToken)) 188 | subVerifierIds.append(userInfo.verifier) 189 | aggregateIdTokenSeeds.append(userInfo.idToken) 190 | } 191 | 192 | aggregateIdTokenSeeds.sort() 193 | let joined = aggregateIdTokenSeeds.joined(separator: "\u{29}").data(using: .utf8)! 194 | let aggregateIdToken = try keccak256(data: joined).hexString 195 | let params: VerifierParams = VerifierParams(verifier_id: verifierParams.verifier_id, extended_verifier_id: verifierParams.extended_verifier_id, sub_verifier_ids: subVerifierIds, verify_params: verifyParams) 196 | 197 | return try await torus.retrieveShares(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierParams: params, idToken: aggregateIdToken) 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /Sources/CustomAuth/CustomAuthArgs.swift: -------------------------------------------------------------------------------- 1 | import FetchNodeDetails 2 | import Foundation 3 | 4 | public class CustomAuthArgs { 5 | public let urlScheme: String 6 | public let metadataUrl: String 7 | public let network: Web3AuthNetwork 8 | public let enableLogging: Bool 9 | public let enableOneKey: Bool 10 | public let apiKey: String 11 | public let popupFeatures: String? 12 | public let storageServerUrl: String 13 | public let web3AuthClientId: String 14 | public let serverTimeOffset: Int 15 | public let useDkg: Bool // TODO: Implement usage of this 16 | 17 | public init(urlScheme: String, 18 | network: Web3AuthNetwork, 19 | metadataUrl: String = "https://metadata.tor.us", 20 | enableLogging: Bool = false, 21 | apiKey: String = "torus-default", 22 | storageServerUrl: String = "https://session.web3auth.io", 23 | enableOneKey: Bool = false, 24 | web3AuthClientId: String, 25 | useDkg: Bool = true, 26 | serverTimeOffset: Int = 0, 27 | popupFeatures: String? = nil 28 | ) { 29 | self.urlScheme = urlScheme 30 | self.metadataUrl = metadataUrl 31 | self.network = network 32 | self.enableLogging = enableLogging 33 | self.enableOneKey = enableOneKey 34 | self.apiKey = apiKey 35 | self.popupFeatures = popupFeatures 36 | self.storageServerUrl = storageServerUrl 37 | self.web3AuthClientId = web3AuthClientId 38 | self.serverTimeOffset = serverTimeOffset 39 | self.useDkg = useDkg 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Sources/CustomAuth/Extension/Data+extension.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | internal extension Data { 4 | func toBase64URL() -> String { 5 | var result = base64EncodedString() 6 | result = result.replacingOccurrences(of: "+", with: "-") 7 | result = result.replacingOccurrences(of: "/", with: "_") 8 | result = result.replacingOccurrences(of: "=", with: "") 9 | return result 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Sources/CustomAuth/Extension/String+extension.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | internal extension String { 4 | func fromBase64URL() throws -> String { 5 | var base64 = self 6 | base64 = base64.replacingOccurrences(of: "-", with: "+") 7 | base64 = base64.replacingOccurrences(of: "_", with: "/") 8 | while base64.count % 4 != 0 { 9 | base64 = base64.appending("=") 10 | } 11 | guard let data = Data(base64Encoded: base64) else { 12 | throw CASDKError.decodingFailed 13 | } 14 | return String(data: data, encoding: .utf8)! 15 | } 16 | 17 | var parametersFromQueryString: [String: String] { 18 | return dictionaryBySplitting("&", keyValueSeparator: "=") 19 | } 20 | 21 | func dictionaryBySplitting(_ elementSeparator: String, keyValueSeparator: String) -> [String: String] { 22 | var string = self 23 | 24 | if hasPrefix(elementSeparator) { 25 | string = String(dropFirst(1)) 26 | } 27 | 28 | var parameters = [String: String]() 29 | 30 | let scanner = Scanner(string: string) 31 | 32 | while !scanner.isAtEnd { 33 | let key = scanner.scanUpToString(keyValueSeparator) 34 | _ = scanner.scanString(keyValueSeparator) 35 | 36 | let value = scanner.scanUpToString(elementSeparator) 37 | _ = scanner.scanString(elementSeparator) 38 | 39 | if let key = key { 40 | if let value = value { 41 | if key.contains(elementSeparator) { 42 | var keys = key.components(separatedBy: elementSeparator) 43 | if let key = keys.popLast() { 44 | parameters.updateValue(value, forKey: String(key)) 45 | } 46 | for flag in keys { 47 | parameters.updateValue("", forKey: flag) 48 | } 49 | } else { 50 | parameters.updateValue(value, forKey: key) 51 | } 52 | } else { 53 | parameters.updateValue("", forKey: key) 54 | } 55 | } 56 | } 57 | 58 | return parameters 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Sources/CustomAuth/Extension/URLComponents+extension.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | internal extension URLComponents { 4 | mutating func setQueryItems(with parameters: [String: String]) { 5 | queryItems = parameters.map { URLQueryItem(name: $0.key, value: $0.value) } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Sources/CustomAuth/Handlers/AuthenticationManager.swift: -------------------------------------------------------------------------------- 1 | import AuthenticationServices 2 | #if os(macOS) 3 | import AppKit 4 | #else 5 | import UIKit 6 | #endif 7 | 8 | internal class AuthenticationManager: NSObject, ASWebAuthenticationPresentationContextProviding { 9 | public func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor { 10 | var window: ASPresentationAnchor? 11 | #if os(macOS) 12 | window = NSApplication.shared.windows.first { $0.isKeyWindow } 13 | #else 14 | window = UIApplication.shared.windows.first { $0.isKeyWindow } 15 | #endif 16 | 17 | return window ?? ASPresentationAnchor() 18 | } 19 | 20 | func webAuth(url: URL, callbackURLScheme: String, prefersEphemeralWebBrowserSession: Bool, 21 | completion: @escaping (Result) -> Void) { 22 | let authSession = ASWebAuthenticationSession(url: url, callbackURLScheme: callbackURLScheme) { url, error in 23 | if let error = error { 24 | completion(.failure(error)) 25 | } else if let url = url { 26 | completion(.success(url)) 27 | } 28 | } 29 | 30 | DispatchQueue.main.async { [weak self] in 31 | guard let self = self else { 32 | return 33 | } 34 | authSession.presentationContextProvider = self 35 | authSession.prefersEphemeralWebBrowserSession = prefersEphemeralWebBrowserSession 36 | authSession.start() 37 | } 38 | } 39 | 40 | public func authenticationManagerWrapper(url: URL, callbackURLScheme: String, prefersEphemeralWebBrowserSession: Bool) async throws -> URL { 41 | return try await withCheckedThrowingContinuation { continuation in 42 | webAuth(url: url, callbackURLScheme: callbackURLScheme, prefersEphemeralWebBrowserSession: prefersEphemeralWebBrowserSession) { result in 43 | switch result { 44 | case let .success(url): 45 | continuation.resume(returning: url) 46 | case let .failure(error): 47 | continuation.resume(throwing: error) 48 | } 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Sources/CustomAuth/Handlers/DiscordLoginHandler.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | internal class DiscordInfo: Codable { 4 | public var id: String 5 | public var username: String 6 | public var avatar: String? 7 | public var discriminator: String 8 | public var email: String 9 | } 10 | 11 | internal class DiscordLoginHandler: AbstractLoginHandler { 12 | private var response_type: String = "token" 13 | private var scope: String = "identify email" 14 | private var prompt: String = "none" 15 | 16 | override public init(params: CreateHandlerParams) throws { 17 | try super.init(params: params) 18 | try setFinalUrl() 19 | } 20 | 21 | override public func setFinalUrl() throws { 22 | var urlComponents = URLComponents() 23 | 24 | var params: [String: String] = [:] 25 | 26 | if self.params.jwtParams != nil { 27 | params = try (JSONSerialization.jsonObject(with: try JSONEncoder().encode(self.params.jwtParams), options: []) as! [String: String]) 28 | } 29 | 30 | params.merge([ 31 | "state": try state(), 32 | "response_type": response_type, 33 | "client_id": self.params.clientId, 34 | "redirect_uri": self.params.redirectURL, 35 | "prompt": prompt, 36 | "scope": scope], uniquingKeysWith: { _, new in new }) 37 | urlComponents.scheme = "https" 38 | urlComponents.host = "discord.com" 39 | urlComponents.path = "/api/oauth2/authorize" 40 | urlComponents.setQueryItems(with: params) 41 | 42 | finalUrl = urlComponents 43 | } 44 | 45 | override public func getUserInfo(params: LoginWindowResponse, storageServerUrl: String?) async throws -> TorusVerifierResponse { 46 | guard let accessToken = params.accessToken else { 47 | throw CASDKError.accessTokenNotProvided 48 | } 49 | 50 | var urlRequest = makeUrlRequest(url: "https://discord.com/api/users/@me", method: "GET") 51 | urlRequest.addValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization") 52 | 53 | let (data, _) = try await URLSession.shared.data(for: urlRequest) 54 | let result = try JSONDecoder().decode(DiscordInfo.self, from: data) 55 | 56 | let profileImage = result.avatar == nil ? "https://cdn.discordapp.com/embed/avatars/" + String(Int(result.discriminator)! % 5) + ".png" : 57 | "https://cdn.discordapp.com/avatars/${id}/" + result.avatar! + ".png?size=2048" 58 | 59 | return TorusVerifierResponse(email: result.email, name: result.username + "#" + result.discriminator, profileImage: profileImage, verifier: self.params.verifier, verifierId: result.id, typeOfLogin: self.params.typeOfLogin) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Sources/CustomAuth/Handlers/FacebookLoginHandler.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | internal class FacebookPictureData: Codable { 4 | public var url: String 5 | } 6 | 7 | internal class FacebookPicture: Codable { 8 | public var data: FacebookPictureData 9 | } 10 | 11 | internal class FacebookInfo: Codable { 12 | public var id: String 13 | public var name: String 14 | public var picture: FacebookPicture 15 | public var email: String 16 | } 17 | 18 | internal class FacebookLoginHandler: AbstractLoginHandler { 19 | private var response_type: String = "token" 20 | private var scope: String = "public_profile email" 21 | 22 | override public init(params: CreateHandlerParams) throws { 23 | try super.init(params: params) 24 | try setFinalUrl() 25 | } 26 | 27 | override public func setFinalUrl() throws { 28 | var urlComponents = URLComponents() 29 | 30 | var params: [String: String] = [:] 31 | 32 | if self.params.jwtParams != nil { 33 | params = try (JSONSerialization.jsonObject(with: try JSONEncoder().encode(self.params.jwtParams), options: []) as! [String: String]) 34 | } 35 | 36 | params.merge([ 37 | "state": try state(), 38 | "response_type": response_type, 39 | "client_id": self.params.clientId, 40 | "redirect_uri": self.params.redirectURL, 41 | "scope": scope], uniquingKeysWith: { _, new in new }) 42 | urlComponents.scheme = "https" 43 | urlComponents.host = "www.facebook.com" 44 | urlComponents.path = "/v15.0/dialog/oauth" 45 | urlComponents.setQueryItems(with: params) 46 | 47 | finalUrl = urlComponents 48 | } 49 | 50 | override public func getUserInfo(params: LoginWindowResponse, storageServerUrl: String?) async throws -> TorusVerifierResponse { 51 | guard let accessToken = params.accessToken else { 52 | throw CASDKError.accessTokenNotProvided 53 | } 54 | 55 | var urlRequest = makeUrlRequest(url: "https://graph.facebook.com/me?fields=name,email,picture.type(large)", method: "GET") 56 | urlRequest.addValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization") 57 | 58 | let (data, _) = try await URLSession.shared.data(for: urlRequest) 59 | 60 | let result = try JSONDecoder().decode(FacebookInfo.self, from: data) 61 | 62 | return TorusVerifierResponse(email: result.email, name: result.name, profileImage: result.picture.data.url, verifier: self.params.verifier, verifierId: result.id, typeOfLogin: self.params.typeOfLogin) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Sources/CustomAuth/Handlers/GoogleLoginHandler.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | internal class GoogleInfo: Codable { 4 | public var name: String 5 | public var picture: String 6 | public var email: String 7 | } 8 | 9 | internal class GoogleLoginHandler: AbstractLoginHandler { 10 | private var response_type: String = "token id_token" 11 | private var scope: String = "profile email openid" 12 | private var prompt: String = "select_account" 13 | 14 | override public init(params: CreateHandlerParams) throws { 15 | try super.init(params: params) 16 | try setFinalUrl() 17 | } 18 | 19 | override public func setFinalUrl() throws { 20 | var urlComponents = URLComponents() 21 | 22 | var params: [String: String] = [:] 23 | 24 | if self.params.jwtParams != nil { 25 | params = try (JSONSerialization.jsonObject(with: try JSONEncoder().encode(self.params.jwtParams), options: []) as! [String: String]) 26 | } 27 | 28 | params.merge([ 29 | "state": try state(), 30 | "response_type": response_type, 31 | "client_id": self.params.clientId, 32 | "prompt": prompt, 33 | "redirect_uri": self.params.redirectURL, 34 | "scope": scope, 35 | "nonce": nonce, 36 | ], uniquingKeysWith: { _, new in new }) 37 | urlComponents.scheme = "https" 38 | urlComponents.host = "accounts.google.com" 39 | urlComponents.path = "/o/oauth2/v2/auth" 40 | urlComponents.setQueryItems(with: params) 41 | 42 | finalUrl = urlComponents 43 | } 44 | 45 | override public func getUserInfo(params: LoginWindowResponse, storageServerUrl: String?) async throws -> TorusVerifierResponse { 46 | guard let accessToken = params.accessToken else { 47 | throw CASDKError.accessTokenNotProvided 48 | } 49 | 50 | var urlRequest = makeUrlRequest(url: "https://www.googleapis.com/userinfo/v2/me", method: "GET") 51 | urlRequest.addValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization") 52 | 53 | let (data, _) = try await URLSession.shared.data(for: urlRequest) 54 | 55 | let result = try JSONDecoder().decode(GoogleInfo.self, from: data) 56 | 57 | return TorusVerifierResponse(email: result.email, name: result.name, profileImage: result.picture, verifier: self.params.verifier, verifierId: result.email.lowercased(), typeOfLogin: self.params.typeOfLogin) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Sources/CustomAuth/Handlers/HandlerFactory.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | internal class HandlerFactory { 4 | static func createHandler( 5 | params: CreateHandlerParams 6 | ) throws -> ILoginHandler { 7 | if params.verifier.isEmpty { 8 | throw CASDKError.invalidVerifier 9 | } 10 | 11 | if params.clientId.isEmpty { 12 | throw CASDKError.invalidClientID 13 | } 14 | 15 | let domain = params.jwtParams?.domain 16 | let hint = params.jwtParams?.login_hint 17 | let idToken = params.jwtParams?.id_token 18 | let accessToken = params.jwtParams?.access_token 19 | 20 | switch params.typeOfLogin { 21 | case .google: 22 | return try GoogleLoginHandler(params: params) 23 | case .facebook: 24 | return try FacebookLoginHandler(params: params) 25 | case .twitch: 26 | return try TwitchLoginHandler(params: params) 27 | case .discord: 28 | return try DiscordLoginHandler(params: params) 29 | case .reddit: break 30 | case .apple: break 31 | case .github: break 32 | case .linkedin: break 33 | case .twitter: break 34 | case .weibo: break 35 | case .line: break 36 | case .email_password: break 37 | case .email_passwordless: 38 | if hint == nil { 39 | throw CASDKError.invalidAuth0Options 40 | } 41 | return try Web3AuthPasswordlessHandler(params: params) 42 | case .sms_passwordless: 43 | if hint == nil { 44 | throw CASDKError.invalidAuth0Options 45 | } 46 | return try Web3AuthPasswordlessHandler(params: params) 47 | case .jwt: break 48 | } 49 | 50 | if idToken != nil || accessToken != nil { 51 | return try MockLoginHandler(params: params) 52 | } 53 | 54 | if domain == nil { 55 | throw CASDKError.invalidAuth0Options 56 | } 57 | 58 | return try JWTLoginHandler(params: params) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Sources/CustomAuth/Handlers/JWTLoginHandler.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import JWTDecode 3 | 4 | internal class Auth0UserInfo: Codable { 5 | public let picture: String 6 | public let email: String 7 | public let name: String 8 | public let sub: String 9 | public let nickname: String 10 | 11 | public init(picture: String, email: String, name: String, sub: String, nickname: String) { 12 | self.picture = picture 13 | self.email = email 14 | self.name = name 15 | self.sub = sub 16 | self.nickname = nickname 17 | } 18 | } 19 | 20 | internal class JWTLoginHandler: AbstractLoginHandler { 21 | private var response_type: String = "token id_token" 22 | private var scope: String = "openid profile email" 23 | private var prompt: String = "login" 24 | 25 | override public init(params: CreateHandlerParams) throws { 26 | try super.init(params: params) 27 | try setFinalUrl() 28 | } 29 | 30 | override public func setFinalUrl() throws { 31 | var urlComponents = URLComponents() 32 | 33 | if self.params.jwtParams == nil { 34 | throw CASDKError.invalidAuth0Options 35 | } 36 | 37 | var connection = self.params.jwtParams?.connection 38 | if connection == nil { 39 | connection = loginToConnection(loginType: self.params.typeOfLogin) 40 | } 41 | 42 | let encoded = try JSONEncoder().encode(self.params.jwtParams) 43 | let serialized = try JSONSerialization.jsonObject(with: encoded, options: [.fragmentsAllowed, .mutableContainers]) 44 | 45 | var params: [String: String] = serialized as! [String: String] 46 | params.merge([ 47 | "state": try state(), 48 | "response_type": response_type, 49 | "client_id": self.params.clientId, 50 | "prompt": prompt, 51 | "redirect_uri": self.params.redirectURL, 52 | "scope": scope, 53 | "connection": connection!, 54 | "nonce": nonce, 55 | ], uniquingKeysWith: { _, new in new }) 56 | urlComponents.scheme = "https" 57 | urlComponents.host = self.params.jwtParams?.domain 58 | urlComponents.path = "/authorize" 59 | urlComponents.setQueryItems(with: params) 60 | 61 | finalUrl = urlComponents 62 | } 63 | 64 | override public func getUserInfo(params: LoginWindowResponse, storageServerUrl: String?) async throws -> TorusVerifierResponse { 65 | let accessToken = params.accessToken 66 | let idToken = params.idToken 67 | let verifierIdField = self.params.jwtParams?.verifierIdField 68 | let isVerifierCaseSensitive = self.params.jwtParams?.isVerifierIdCaseSensitive != nil ? Bool(self.params.jwtParams!.isVerifierIdCaseSensitive)! : true 69 | 70 | if accessToken != nil { 71 | let domain = self.params.jwtParams?.domain 72 | var user_route_info = self.params.jwtParams?.user_info_route ?? "/userinfo" 73 | 74 | if !user_route_info.hasPrefix("/") { 75 | user_route_info = "/" + user_route_info 76 | } 77 | 78 | var urlComponents = URLComponents() 79 | urlComponents.scheme = "https" 80 | urlComponents.host = domain 81 | urlComponents.path = user_route_info 82 | 83 | var urlRequest = makeUrlRequest(url: urlComponents.string!, method: "GET") 84 | urlRequest.addValue("Bearer \(accessToken!)", forHTTPHeaderField: "Authorization") 85 | 86 | let (data, _) = try await URLSession.shared.data(for: urlRequest) 87 | let result = try JSONDecoder().decode(Auth0UserInfo.self, from: data) 88 | 89 | return TorusVerifierResponse(email: result.email, name: result.name, profileImage: result.picture, verifier: self.params.verifier, verifierId: try self.params.jwtParams?.verifierIdField ?? getVerifierId(userInfo: result, typeOfLogin: self.params.typeOfLogin, verifierIdField: verifierIdField, isVerifierIdCaseSensitive: isVerifierCaseSensitive), typeOfLogin: self.params.typeOfLogin) 90 | } 91 | 92 | if idToken == nil { 93 | throw CASDKError.idTokenNotProvided 94 | } else { 95 | let decodedToken = try decode(jwt: idToken!) 96 | let result = Auth0UserInfo(picture: decodedToken.body["picture"] as? String ?? "", email: decodedToken.body["email"] as? String ?? "", name: decodedToken.body["name"] as? String ?? "", sub: decodedToken.body["sub"] as? String ?? "", nickname: decodedToken.body["nickname"] as? String ?? "") 97 | 98 | return TorusVerifierResponse(email: result.email, name: result.name, profileImage: result.picture, verifier: self.params.verifier, verifierId: try getVerifierId(userInfo: result, typeOfLogin: self.params.typeOfLogin, verifierIdField: verifierIdField, isVerifierIdCaseSensitive: isVerifierCaseSensitive), typeOfLogin: self.params.typeOfLogin) 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /Sources/CustomAuth/Handlers/MockLoginHandler.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import JWTDecode 3 | 4 | internal class MockLoginHandler: AbstractLoginHandler { 5 | override public init(params: CreateHandlerParams) throws { 6 | try super.init(params: params) 7 | try setFinalUrl() 8 | } 9 | 10 | override public func setFinalUrl() throws { 11 | if self.params.jwtParams == nil { 12 | throw CASDKError.invalidAuth0Options 13 | } 14 | 15 | var connection = self.params.jwtParams?.connection 16 | if connection == nil { 17 | connection = loginToConnection(loginType: self.params.typeOfLogin) 18 | } 19 | 20 | var params: [String: String] = try (JSONSerialization.jsonObject(with: try JSONEncoder().encode(self.params.jwtParams), options: []) as! [String: String]) 21 | params.merge([ 22 | "state": try state(), 23 | "client_id": self.params.clientId, 24 | "connection": connection!, 25 | "nonce": nonce, 26 | ], uniquingKeysWith: { _, new in new }) 27 | 28 | var urlComponents = URLComponents() 29 | urlComponents.scheme = "https" 30 | urlComponents.host = self.params.jwtParams?.domain 31 | urlComponents.path = "/authorize" 32 | urlComponents.fragment = params.compactMap({ (key, value) -> String in 33 | return "\(key)=\(value)" 34 | }).joined(separator: "&") 35 | finalUrl = urlComponents 36 | } 37 | 38 | public override func handleLoginWindow(popupFeatures: String?) async throws -> LoginWindowResponse { 39 | 40 | let urlWithTokenInfo = URL(string: finalUrl.string!)! 41 | 42 | var tokenInfo = parseURL(url: urlWithTokenInfo) 43 | let access_token = tokenInfo["access_token"] 44 | let id_token = tokenInfo["id_token"] 45 | let ref = tokenInfo["ref"] 46 | 47 | tokenInfo.removeValue(forKey: "access_token") 48 | tokenInfo.removeValue(forKey: "id_token") 49 | tokenInfo.removeValue(forKey: "ref") 50 | return LoginWindowResponse(accessToken: access_token, idToken: id_token, ref: ref ?? "", state: TorusGenericContainer(params: tokenInfo)) 51 | } 52 | 53 | override public func getUserInfo(params: LoginWindowResponse, storageServerUrl: String?) async throws -> TorusVerifierResponse { 54 | let accessToken = params.accessToken 55 | let idToken = params.idToken 56 | let verifierIdField = self.params.jwtParams?.verifierIdField 57 | let isVerifierCaseSensitive = self.params.jwtParams?.isVerifierIdCaseSensitive != nil ? Bool(self.params.jwtParams!.isVerifierIdCaseSensitive)! : true 58 | 59 | if accessToken != nil { 60 | let domain = self.params.jwtParams?.domain 61 | var user_route_info = self.params.jwtParams?.user_info_route ?? "/userinfo" 62 | 63 | if !user_route_info.hasPrefix("/") { 64 | user_route_info = "/" + user_route_info 65 | } 66 | 67 | var urlComponents = URLComponents() 68 | urlComponents.scheme = "https" 69 | urlComponents.host = domain 70 | urlComponents.path = user_route_info 71 | 72 | var urlRequest = makeUrlRequest(url: urlComponents.string!, method: "GET") 73 | urlRequest.addValue("Bearer \(accessToken!)", forHTTPHeaderField: "Authorization") 74 | 75 | let (data, _) = try await URLSession.shared.data(for: urlRequest) 76 | 77 | let result = try JSONDecoder().decode(Auth0UserInfo.self, from: data) 78 | 79 | return TorusVerifierResponse(email: result.email, name: result.name, profileImage: result.picture, verifier: self.params.verifier, verifierId: try getVerifierId(userInfo: result, typeOfLogin: self.params.typeOfLogin, verifierIdField: verifierIdField, isVerifierIdCaseSensitive: isVerifierCaseSensitive), typeOfLogin: self.params.typeOfLogin) 80 | } 81 | 82 | if idToken == nil { 83 | throw CASDKError.idTokenNotProvided 84 | } else { 85 | let decodedToken = try decode(jwt: idToken!) 86 | let result = Auth0UserInfo(picture: decodedToken.body["picture"] as? String ?? "", email: decodedToken.body["email"] as? String ?? "", name: decodedToken.body["name"] as? String ?? "", sub: decodedToken.body["sub"] as? String ?? "", nickname: decodedToken.body["nickname"] as? String ?? "") 87 | 88 | return TorusVerifierResponse(email: result.email, name: result.name, profileImage: result.picture, verifier: self.params.verifier, verifierId: try getVerifierId(userInfo: result, typeOfLogin: self.params.typeOfLogin, verifierIdField: verifierIdField, isVerifierIdCaseSensitive: isVerifierCaseSensitive), typeOfLogin: self.params.typeOfLogin) 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /Sources/CustomAuth/Handlers/Protocol/AbstractLoginHandler.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import FetchNodeDetails 3 | #if canImport(curveSecp256k1) 4 | import curveSecp256k1 5 | #endif 6 | 7 | internal class AbstractLoginHandler: ILoginHandler { 8 | public var nonce: String 9 | 10 | public var finalUrl: URLComponents 11 | 12 | public var params: CreateHandlerParams 13 | 14 | public init(params: CreateHandlerParams) throws { 15 | self.nonce = try SecretKey().serialize().addLeading0sForLength64() 16 | finalUrl = URLComponents() 17 | self.params = params 18 | } 19 | 20 | public func state() throws -> String { 21 | let encoder = JSONEncoder() 22 | encoder.outputFormatting = .sortedKeys 23 | let state = State(instanceId: nonce, verifier: params.verifier, typeOfLogin: params.typeOfLogin.rawValue, redirectUri: params.urlScheme, customState: params.customState, client: params.web3AuthClientId) 24 | return try encoder.encode(state).toBase64URL() 25 | } 26 | 27 | public func getUserInfo(params: LoginWindowResponse, storageServerUrl: String?) async throws -> TorusVerifierResponse { 28 | fatalError("getUserInfo must be implemented by concrete classes") 29 | } 30 | 31 | public func handleLoginWindow(popupFeatures: String?) async throws -> LoginWindowResponse { 32 | guard let callbackURLScheme = URL(string: params.urlScheme)?.scheme else { 33 | throw CASDKError.invalidCallbackURLScheme 34 | } 35 | 36 | let urlWithTokenInfo = try await AuthenticationManager().authenticationManagerWrapper(url: finalUrl.url!, callbackURLScheme: callbackURLScheme, prefersEphemeralWebBrowserSession: false) 37 | 38 | var tokenInfo = parseURL(url: urlWithTokenInfo) 39 | let access_token = tokenInfo["access_token"] 40 | let id_token = tokenInfo["id_token"] 41 | let ref = tokenInfo["ref"] 42 | 43 | tokenInfo.removeValue(forKey: "access_token") 44 | tokenInfo.removeValue(forKey: "id_token") 45 | tokenInfo.removeValue(forKey: "ref") 46 | return LoginWindowResponse(accessToken: access_token, idToken: id_token, ref: ref ?? "", state: TorusGenericContainer(params: tokenInfo)) 47 | } 48 | 49 | public func setFinalUrl() throws { 50 | throw CASDKError.invalidMethod(msg: "setFinalUrl cannot be called by abstract class") 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Sources/CustomAuth/Handlers/Protocol/CreateHandlerParams.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import FetchNodeDetails 3 | 4 | internal class CreateHandlerParams { 5 | public let typeOfLogin: LoginType 6 | public let verifier: String 7 | public let clientId: String 8 | public let urlScheme: String 9 | public let redirectURL: String 10 | public let jwtParams: Auth0ClientOptions? 11 | public let customState: TorusGenericContainer? 12 | public let web3AuthNetwork: Web3AuthNetwork 13 | public let web3AuthClientId: String 14 | 15 | public init(typeOfLogin: LoginType, verifier: String, clientId: String, urlScheme: String, redirectURL: String, jwtParams: Auth0ClientOptions? = nil, customState: TorusGenericContainer? = nil, web3AuthNetwork: Web3AuthNetwork, web3AuthClientId: String) { 16 | self.typeOfLogin = typeOfLogin 17 | self.verifier = verifier 18 | self.clientId = clientId 19 | self.urlScheme = urlScheme 20 | self.jwtParams = jwtParams 21 | self.customState = customState 22 | self.redirectURL = redirectURL 23 | self.web3AuthNetwork = web3AuthNetwork 24 | self.web3AuthClientId = web3AuthClientId 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/CustomAuth/Handlers/Protocol/ILoginHandler.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | internal protocol ILoginHandler { 4 | var params: CreateHandlerParams { get set } 5 | var nonce: String { get set } 6 | var finalUrl: URLComponents { get set } 7 | 8 | func getUserInfo(params: LoginWindowResponse, storageServerUrl: String?) async throws -> TorusVerifierResponse 9 | 10 | func handleLoginWindow(popupFeatures: String?) async throws -> LoginWindowResponse 11 | 12 | func setFinalUrl() throws 13 | } 14 | -------------------------------------------------------------------------------- /Sources/CustomAuth/Handlers/TwitchLoginHandler.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | internal class TwitchInfo: Codable { 4 | public var id: String 5 | public var email: String? 6 | public var display_name: String 7 | public var profile_image_url: String 8 | } 9 | 10 | internal class TwitchRootInfo: Codable { 11 | public var data: [TwitchInfo] 12 | } 13 | 14 | internal class TwitchLoginHandler: AbstractLoginHandler { 15 | private var response_type: String = "token" 16 | private var scope: String = "user:read:email" 17 | 18 | override public init(params: CreateHandlerParams) throws { 19 | try super.init(params: params) 20 | try setFinalUrl() 21 | } 22 | 23 | override public func setFinalUrl() throws { 24 | var urlComponents = URLComponents() 25 | 26 | var params: [String: String] = [:] 27 | 28 | if self.params.jwtParams != nil { 29 | params = try (JSONSerialization.jsonObject(with: try JSONEncoder().encode(self.params.jwtParams), options: []) as! [String: String]) 30 | } 31 | 32 | params.merge([ 33 | "state": try state(), 34 | "response_type": response_type, 35 | "client_id": self.params.clientId, 36 | "redirect_uri": self.params.redirectURL, 37 | "scope": scope, 38 | "force_verify": "true", 39 | ], uniquingKeysWith: { _, new in new }) 40 | urlComponents.scheme = "https" 41 | urlComponents.host = "id.twitch.tv" 42 | urlComponents.path = "/oauth2/authorize" 43 | urlComponents.setQueryItems(with: params) 44 | 45 | finalUrl = urlComponents 46 | } 47 | 48 | override public func getUserInfo(params: LoginWindowResponse, storageServerUrl: String?) async throws -> TorusVerifierResponse { 49 | guard let accessToken = params.accessToken else { 50 | throw CASDKError.accessTokenNotProvided 51 | } 52 | 53 | var urlRequest = makeUrlRequest(url: "https://api.twitch.tv/helix/users", method: "GET") 54 | urlRequest.addValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization") 55 | urlRequest.addValue(self.params.clientId, forHTTPHeaderField: "Client-ID") 56 | 57 | let (data, _) = try await URLSession.shared.data(for: urlRequest) 58 | let result = try JSONDecoder().decode(TwitchRootInfo.self, from: data) 59 | 60 | guard let userdata = result.data.first else { 61 | throw CASDKError.decodingFailed 62 | } 63 | 64 | return TorusVerifierResponse(email: userdata.email ?? "", name: userdata.display_name, profileImage: userdata.profile_image_url, verifier: self.params.verifier, verifierId: userdata.id, typeOfLogin: self.params.typeOfLogin) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Sources/CustomAuth/Handlers/Web3AuthPasswordlessLoginHandler.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import JWTDecode 3 | 4 | internal class Web3AuthPasswordlessHandler: AbstractLoginHandler { 5 | private var response_type: String = "token id_token" 6 | private var scope: String = "openid profile email" 7 | private var prompt: String = "login" 8 | 9 | override public init(params: CreateHandlerParams) throws { 10 | try super.init(params: params) 11 | try setFinalUrl() 12 | } 13 | 14 | override public func setFinalUrl() throws { 15 | if self.params.jwtParams == nil { 16 | throw CASDKError.invalidAuth0Options 17 | } 18 | 19 | let domain = self.params.jwtParams?.domain 20 | 21 | var urlComponents = URLComponents() 22 | 23 | var connection = self.params.jwtParams!.connection 24 | if connection == nil { 25 | connection = loginToConnection(loginType: self.params.typeOfLogin) 26 | } 27 | 28 | let encoded = try JSONEncoder().encode(self.params.jwtParams) 29 | let serialized = try JSONSerialization.jsonObject(with: encoded, options: [.fragmentsAllowed, .mutableContainers]) 30 | 31 | var params: [String: String] = serialized as! [String: String] 32 | params.merge([ 33 | "state": try state(), 34 | "response_type": response_type, 35 | "client_id": self.params.clientId, 36 | "prompt": prompt, 37 | "redirect_uri": self.params.redirectURL, 38 | "scope": scope, 39 | "connection": connection!, 40 | "nonce": nonce, 41 | "network": self.params.web3AuthNetwork.name, 42 | "flow_type": self.params.jwtParams?.flow_type?.rawValue ?? EmailFlowType.code.rawValue 43 | ], uniquingKeysWith: { _, new in new }) 44 | // workaround for plus not being encoded 45 | params["login_hint"]! = params["login_hint"]!.replacingOccurrences(of: "+", with: "%2B") 46 | urlComponents.scheme = "https" 47 | urlComponents.host = domain ?? "passwordless.web3auth.io" 48 | urlComponents.path = domain == nil ? "/v6/authorize" : "/authorize" 49 | urlComponents.setQueryItems(with: params) 50 | 51 | finalUrl = urlComponents 52 | } 53 | 54 | override public func getUserInfo(params: LoginWindowResponse, storageServerUrl: String?) async throws -> TorusVerifierResponse { 55 | let idToken = params.idToken 56 | let verifierIdField = self.params.jwtParams?.verifierIdField 57 | let isVerifierCaseSensitive = self.params.jwtParams?.isVerifierIdCaseSensitive != nil ? Bool(self.params.jwtParams!.isVerifierIdCaseSensitive)! : true 58 | 59 | if idToken == nil { 60 | throw CASDKError.idTokenNotProvided 61 | } else { 62 | let decodedToken = try decode(jwt: idToken!) 63 | let result = Auth0UserInfo(picture: decodedToken.body["picture"] as? String ?? "", email: decodedToken.body["email"] as? String ?? "", name: decodedToken.body["name"] as? String ?? "", sub: "", nickname: "") 64 | 65 | return TorusVerifierResponse(email: result.email.lowercased(), name: result.name.lowercased(), profileImage: result.picture, verifier: self.params.verifier, verifierId: try getVerifierId(userInfo: result, typeOfLogin: self.params.typeOfLogin, verifierIdField: verifierIdField, isVerifierIdCaseSensitive: isVerifierCaseSensitive), typeOfLogin: self.params.typeOfLogin) 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Sources/CustomAuth/Helpers/Common.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | internal func loginToConnection(loginType: LoginType) -> String { 4 | switch loginType { 5 | case .apple: break 6 | case .google: break 7 | case .facebook: break 8 | case .reddit: break 9 | case .twitch: break 10 | case .discord: break 11 | case .github: break 12 | case .linkedin: break 13 | case .twitter: break 14 | case .weibo: break 15 | case .line: break 16 | case .email_password: return "Username-Password-Authentication" 17 | case .email_passwordless: return "email" 18 | case .sms_passwordless: return "sms" 19 | case .jwt: break 20 | } 21 | return loginType.rawValue 22 | } 23 | 24 | internal func caseSensitiveField(field: String, isCaseSensitive: Bool) -> String{ 25 | return isCaseSensitive ? field : field.lowercased() 26 | } 27 | 28 | internal func getVerifierId( 29 | userInfo: Auth0UserInfo, 30 | typeOfLogin: LoginType, 31 | verifierIdField: String? = nil, 32 | isVerifierIdCaseSensitive: Bool = true 33 | ) throws -> String { 34 | let name = userInfo.name 35 | let sub = userInfo.sub 36 | 37 | let encoded = try JSONEncoder().encode(userInfo) 38 | let json = try JSONSerialization.jsonObject(with: encoded, options: []) as! [String: String] 39 | 40 | if verifierIdField != nil { 41 | return json[caseSensitiveField(field: verifierIdField!, isCaseSensitive: isVerifierIdCaseSensitive)]! 42 | } 43 | 44 | switch typeOfLogin { 45 | case .email_password: return name 46 | case .email_passwordless: return name 47 | case .sms_passwordless: return caseSensitiveField(field: name, isCaseSensitive: isVerifierIdCaseSensitive) 48 | case .google: return sub 49 | case .facebook: return sub 50 | case .reddit: return sub 51 | case .twitch: return sub 52 | case .apple: return sub 53 | case .github: return sub 54 | case .discord: return sub 55 | case .linkedin: return sub 56 | case .twitter: return sub 57 | case .weibo: return sub 58 | case .line: return sub 59 | case .jwt: return caseSensitiveField(field: sub, isCaseSensitive: isVerifierIdCaseSensitive) 60 | } 61 | } 62 | 63 | func handleRedirectParameters(hash: String, queryParameters: TorusGenericContainer) throws -> (String, TorusGenericContainer, TorusGenericContainer) { 64 | var hashParams: [String: String] = [:] 65 | let hashSplit = hash.split(separator: "&") 66 | hashSplit.forEach({ 67 | let paramSplit = $0.split(separator: "=") 68 | hashParams.updateValue(String(paramSplit[1]), forKey: String(paramSplit[0])) 69 | }) 70 | 71 | var instanceParams: [String: String] = [:] 72 | var error = "" 73 | if hashParams.count > 0 && hashParams["state"] != nil { 74 | let instanceSplit = try hashParams["state"]!.fromBase64URL().split(separator: "&") 75 | instanceSplit.forEach({ 76 | let paramSplit = $0.split(separator: "=") 77 | instanceParams.updateValue(String(paramSplit[1]), forKey: String(paramSplit[0])) 78 | }) 79 | if hashParams["error_description"] != nil { 80 | error = hashParams["error_description"]! 81 | } else if hashParams["error"] != nil { 82 | error = hashParams["error"]! 83 | } 84 | } else if queryParameters.params.count > 0 && queryParameters.params["state"] != nil { 85 | let instanceSplit = try queryParameters.params["state"]!.fromBase64URL().split(separator: "&") 86 | instanceSplit.forEach({ 87 | let paramSplit = $0.split(separator: "=") 88 | instanceParams.updateValue(String(paramSplit[1]), forKey: String(paramSplit[0])) 89 | }) 90 | if queryParameters.params["error"] != nil { 91 | error = queryParameters.params["error"]! 92 | } 93 | } 94 | 95 | return (error, TorusGenericContainer(params: hashParams), TorusGenericContainer(params: instanceParams)) 96 | } 97 | 98 | func parseURL(url: URL) -> [String: String] { 99 | var responseParameters = [String: String]() 100 | if let query = url.query { 101 | responseParameters.merge(query.parametersFromQueryString, uniquingKeysWith: { _, new in new }) 102 | } 103 | if let fragment = url.fragment, !fragment.isEmpty { 104 | responseParameters.merge(fragment.parametersFromQueryString, uniquingKeysWith: { _, new in new }) 105 | } 106 | return responseParameters 107 | } 108 | 109 | func makeUrlRequest(url: String, method: String) -> URLRequest { 110 | var rq = URLRequest(url: URL(string: url)!) 111 | rq.httpMethod = method 112 | rq.addValue("application/json", forHTTPHeaderField: "Content-Type") 113 | rq.addValue("application/json", forHTTPHeaderField: "Accept") 114 | return rq 115 | } 116 | -------------------------------------------------------------------------------- /Sources/CustomAuth/Helpers/Error.swift: -------------------------------------------------------------------------------- 1 | public enum CASDKError: Error { 2 | case decodingFailed 3 | case encodingFailed 4 | case accessTokenNotProvided 5 | case idTokenNotProvided 6 | case invalidParameters 7 | case invalidCallbackURLScheme 8 | case invalidAuth0Options 9 | case invalidVerifier 10 | case invalidClientID 11 | case invalidMethod(msg: String) 12 | case redirectParamsError(msg: String) 13 | case unsupportedLoginType 14 | 15 | public var errorDescription: String { 16 | switch self { 17 | case .decodingFailed: 18 | return "decoding failed" 19 | case .encodingFailed: 20 | return "encoding failed" 21 | case .accessTokenNotProvided: 22 | return "access token not provided" 23 | case .idTokenNotProvided: 24 | return "id token not provided" 25 | case .invalidCallbackURLScheme: 26 | return "callback scheme is invalid" 27 | case .invalidParameters: 28 | return "parameters are missing or invalid" 29 | case .invalidAuth0Options: 30 | return "auth0 options are missing or invalid" 31 | case .invalidMethod(msg: let msg): 32 | return msg 33 | case .redirectParamsError(msg: let msg): 34 | return msg 35 | case .invalidVerifier: 36 | return "invalid verifier" 37 | case .invalidClientID: 38 | return "invalid client ID" 39 | case .unsupportedLoginType: 40 | return "Unsupported. Please use a different type of login" 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Tests/CustomAuthTests/CustomAuthTests.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import JWTDecode 3 | import XCTest 4 | 5 | final class CustomAuthTests: XCTestCase { 6 | func test_jwtDecodeTest() { 7 | let idToken = "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcnVzLmF1LmF1dGgwLmNvbS8iLCJhdWQiOiJLRzd6azg5WDNRZ3R0U3lYOU5KNGZHRXlGTmhPY0pUdyIsIm5hbWUiOiJkaHJ1dkB0b3IudXMiLCJlbWFpbCI6ImRocnV2QHRvci51cyIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwiLCJpYXQiOjE2NTQ2NzcwMTQsImVhdCI6MTY1NDY3NzMxNCwiZXhwIjoxNjU0Njc3MzE0fQ.3nzDGeSiQwfTVmL4T4-e5N19eD280GjtosFzcGjhWv_sUCV2YkM3i7iFIpUq7AxoPXjai5v7GTTPRu1zHPL6bg" 8 | let _ = try! decode(jwt: idToken) 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Tests/CustomAuthTests/XCTestManifests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | #if !canImport(ObjectiveC) 4 | public func allTests() -> [XCTestCaseEntry] { 5 | return [ 6 | testCase(CustomAuthTests.allTests) 7 | ] 8 | } 9 | #endif 10 | -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | import CustomAuthTests 4 | 5 | var tests = [XCTestCaseEntry]() 6 | tests += CustomAuthTests.allTests() 7 | XCTMain(tests) 8 | -------------------------------------------------------------------------------- /cocoapods/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | platform :ios, '14.0' 3 | source 'https://github.com/CocoaPods/Specs.git' 4 | 5 | target 'cptest' do 6 | use_frameworks! 7 | pod 'Torus-utils', '~> 10.0.0' 8 | pod 'CustomAuth', :path=>"../" 9 | # Pods for cptest 10 | 11 | post_install do |installer_representation| 12 | installer_representation.pods_project.targets.each do |target| 13 | target.build_configurations.each do |config| 14 | config.build_settings['ONLY_ACTIVE_ARCH'] = 'NO' 15 | config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '14.0' 16 | end 17 | end 18 | end 19 | 20 | end 21 | -------------------------------------------------------------------------------- /cocoapods/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - BigInt (5.2.0) 3 | - curvelib.swift (2.0.0) 4 | - CustomAuth (11.0.0): 5 | - JWTDecode (~> 3.2.0) 6 | - Torus-utils (~> 10.0.0) 7 | - JWTDecode (3.2.0) 8 | - Torus-fetchNodeDetails (8.0.0): 9 | - BigInt (~> 5.2.0) 10 | - Torus-utils (10.0.0): 11 | - curvelib.swift (~> 2.0.0) 12 | - Torus-fetchNodeDetails (~> 8.0.0) 13 | 14 | DEPENDENCIES: 15 | - CustomAuth (from `../`) 16 | - Torus-utils (~> 10.0.0) 17 | 18 | SPEC REPOS: 19 | https://github.com/CocoaPods/Specs.git: 20 | - BigInt 21 | - curvelib.swift 22 | - JWTDecode 23 | - Torus-fetchNodeDetails 24 | - Torus-utils 25 | 26 | EXTERNAL SOURCES: 27 | CustomAuth: 28 | :path: "../" 29 | 30 | SPEC CHECKSUMS: 31 | BigInt: f668a80089607f521586bbe29513d708491ef2f7 32 | curvelib.swift: b9223e5cac801effed8a5fe8968e952b3fe427a5 33 | CustomAuth: 3d9d95477f35d9560bdd595283f2103bce44538c 34 | JWTDecode: 7dae24cb9bf9b608eae61e5081029ec169bb5527 35 | Torus-fetchNodeDetails: 2a5fbb222ec28af4128d64e4c2d520c7db456b78 36 | Torus-utils: 4a1db3d9c1aa221df312ffa7ec154e7e4719850a 37 | 38 | PODFILE CHECKSUM: f4a1d2e407b10056607aa36892f54a3affc05ffa 39 | 40 | COCOAPODS: 1.15.2 41 | -------------------------------------------------------------------------------- /cocoapods/cptest.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 54; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 51CF48C02493A34C0000D501 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51CF48BF2493A34C0000D501 /* SceneDelegate.swift */; }; 11 | 51CF48C42493A34D0000D501 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 51CF48C32493A34D0000D501 /* Assets.xcassets */; }; 12 | 51CF48C72493A34D0000D501 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 51CF48C62493A34D0000D501 /* Preview Assets.xcassets */; }; 13 | 77780FDF4E728A0496F42009 /* Pods_cptest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F2E0FC8146E62B6EB56A5A3C /* Pods_cptest.framework */; }; 14 | B3E673212C5935A00006A66B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3E673202C5935A00006A66B /* AppDelegate.swift */; }; 15 | B3E673232C59366C0006A66B /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3E673222C59366C0006A66B /* ContentView.swift */; }; 16 | FCF292E9290A525300132DC5 /* ViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCF292E8290A525300132DC5 /* ViewModel.swift */; }; 17 | FCF292EB290A5DE300132DC5 /* UserInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCF292EA290A5DE300132DC5 /* UserInfoView.swift */; }; 18 | FCF292ED290A6E6C00132DC5 /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCF292EC290A6E6C00132DC5 /* LoginView.swift */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXFileReference section */ 22 | 51CF48BA2493A34C0000D501 /* cptest.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = cptest.app; sourceTree = BUILT_PRODUCTS_DIR; }; 23 | 51CF48BF2493A34C0000D501 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 24 | 51CF48C32493A34D0000D501 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 25 | 51CF48C62493A34D0000D501 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 26 | 51CF48CB2493A34D0000D501 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 27 | A0255E8F3CDAC6C5FAF1D494 /* Pods-cptest.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-cptest.release.xcconfig"; path = "Target Support Files/Pods-cptest/Pods-cptest.release.xcconfig"; sourceTree = ""; }; 28 | B3E673202C5935A00006A66B /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 29 | B3E673222C59366C0006A66B /* ContentView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 30 | BBD4C42A80D1902311E2555B /* Pods-cptest.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-cptest.debug.xcconfig"; path = "Target Support Files/Pods-cptest/Pods-cptest.debug.xcconfig"; sourceTree = ""; }; 31 | F2E0FC8146E62B6EB56A5A3C /* Pods_cptest.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_cptest.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 32 | FCF292E8290A525300132DC5 /* ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewModel.swift; sourceTree = ""; }; 33 | FCF292EA290A5DE300132DC5 /* UserInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserInfoView.swift; sourceTree = ""; }; 34 | FCF292EC290A6E6C00132DC5 /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = ""; }; 35 | /* End PBXFileReference section */ 36 | 37 | /* Begin PBXFrameworksBuildPhase section */ 38 | 51CF48B72493A34C0000D501 /* Frameworks */ = { 39 | isa = PBXFrameworksBuildPhase; 40 | buildActionMask = 2147483647; 41 | files = ( 42 | 77780FDF4E728A0496F42009 /* Pods_cptest.framework in Frameworks */, 43 | ); 44 | runOnlyForDeploymentPostprocessing = 0; 45 | }; 46 | /* End PBXFrameworksBuildPhase section */ 47 | 48 | /* Begin PBXGroup section */ 49 | 51CF48B12493A34C0000D501 = { 50 | isa = PBXGroup; 51 | children = ( 52 | 51CF48BC2493A34C0000D501 /* cptest */, 53 | 51CF48BB2493A34C0000D501 /* Products */, 54 | 804BF8A7379AC3C7D8F56A01 /* Pods */, 55 | D032DC5AC5ECFC2A9E49B8A1 /* Frameworks */, 56 | ); 57 | sourceTree = ""; 58 | }; 59 | 51CF48BB2493A34C0000D501 /* Products */ = { 60 | isa = PBXGroup; 61 | children = ( 62 | 51CF48BA2493A34C0000D501 /* cptest.app */, 63 | ); 64 | name = Products; 65 | sourceTree = ""; 66 | }; 67 | 51CF48BC2493A34C0000D501 /* cptest */ = { 68 | isa = PBXGroup; 69 | children = ( 70 | B3E673202C5935A00006A66B /* AppDelegate.swift */, 71 | 51CF48BF2493A34C0000D501 /* SceneDelegate.swift */, 72 | FCF292E8290A525300132DC5 /* ViewModel.swift */, 73 | B3E673222C59366C0006A66B /* ContentView.swift */, 74 | FCF292EC290A6E6C00132DC5 /* LoginView.swift */, 75 | FCF292EA290A5DE300132DC5 /* UserInfoView.swift */, 76 | 51CF48C32493A34D0000D501 /* Assets.xcassets */, 77 | 51CF48CB2493A34D0000D501 /* Info.plist */, 78 | 51CF48C52493A34D0000D501 /* Preview Content */, 79 | ); 80 | path = cptest; 81 | sourceTree = ""; 82 | }; 83 | 51CF48C52493A34D0000D501 /* Preview Content */ = { 84 | isa = PBXGroup; 85 | children = ( 86 | 51CF48C62493A34D0000D501 /* Preview Assets.xcassets */, 87 | ); 88 | path = "Preview Content"; 89 | sourceTree = ""; 90 | }; 91 | 804BF8A7379AC3C7D8F56A01 /* Pods */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | BBD4C42A80D1902311E2555B /* Pods-cptest.debug.xcconfig */, 95 | A0255E8F3CDAC6C5FAF1D494 /* Pods-cptest.release.xcconfig */, 96 | ); 97 | path = Pods; 98 | sourceTree = ""; 99 | }; 100 | D032DC5AC5ECFC2A9E49B8A1 /* Frameworks */ = { 101 | isa = PBXGroup; 102 | children = ( 103 | F2E0FC8146E62B6EB56A5A3C /* Pods_cptest.framework */, 104 | ); 105 | name = Frameworks; 106 | sourceTree = ""; 107 | }; 108 | /* End PBXGroup section */ 109 | 110 | /* Begin PBXNativeTarget section */ 111 | 51CF48B92493A34C0000D501 /* cptest */ = { 112 | isa = PBXNativeTarget; 113 | buildConfigurationList = 51CF48CE2493A34D0000D501 /* Build configuration list for PBXNativeTarget "cptest" */; 114 | buildPhases = ( 115 | 276CD9986FE396026EFBBBE9 /* [CP] Check Pods Manifest.lock */, 116 | 51CF48B62493A34C0000D501 /* Sources */, 117 | 51CF48B72493A34C0000D501 /* Frameworks */, 118 | 51CF48B82493A34C0000D501 /* Resources */, 119 | 6A0A25194E5990B031819186 /* [CP] Embed Pods Frameworks */, 120 | ); 121 | buildRules = ( 122 | ); 123 | dependencies = ( 124 | ); 125 | name = cptest; 126 | productName = cptest; 127 | productReference = 51CF48BA2493A34C0000D501 /* cptest.app */; 128 | productType = "com.apple.product-type.application"; 129 | }; 130 | /* End PBXNativeTarget section */ 131 | 132 | /* Begin PBXProject section */ 133 | 51CF48B22493A34C0000D501 /* Project object */ = { 134 | isa = PBXProject; 135 | attributes = { 136 | BuildIndependentTargetsInParallel = YES; 137 | LastSwiftUpdateCheck = 1150; 138 | LastUpgradeCheck = 1540; 139 | ORGANIZATIONNAME = torus; 140 | TargetAttributes = { 141 | 51CF48B92493A34C0000D501 = { 142 | CreatedOnToolsVersion = 11.5; 143 | }; 144 | }; 145 | }; 146 | buildConfigurationList = 51CF48B52493A34C0000D501 /* Build configuration list for PBXProject "cptest" */; 147 | compatibilityVersion = "Xcode 9.3"; 148 | developmentRegion = en; 149 | hasScannedForEncodings = 0; 150 | knownRegions = ( 151 | en, 152 | Base, 153 | ); 154 | mainGroup = 51CF48B12493A34C0000D501; 155 | productRefGroup = 51CF48BB2493A34C0000D501 /* Products */; 156 | projectDirPath = ""; 157 | projectRoot = ""; 158 | targets = ( 159 | 51CF48B92493A34C0000D501 /* cptest */, 160 | ); 161 | }; 162 | /* End PBXProject section */ 163 | 164 | /* Begin PBXResourcesBuildPhase section */ 165 | 51CF48B82493A34C0000D501 /* Resources */ = { 166 | isa = PBXResourcesBuildPhase; 167 | buildActionMask = 2147483647; 168 | files = ( 169 | 51CF48C72493A34D0000D501 /* Preview Assets.xcassets in Resources */, 170 | 51CF48C42493A34D0000D501 /* Assets.xcassets in Resources */, 171 | ); 172 | runOnlyForDeploymentPostprocessing = 0; 173 | }; 174 | /* End PBXResourcesBuildPhase section */ 175 | 176 | /* Begin PBXShellScriptBuildPhase section */ 177 | 276CD9986FE396026EFBBBE9 /* [CP] Check Pods Manifest.lock */ = { 178 | isa = PBXShellScriptBuildPhase; 179 | buildActionMask = 2147483647; 180 | files = ( 181 | ); 182 | inputFileListPaths = ( 183 | ); 184 | inputPaths = ( 185 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 186 | "${PODS_ROOT}/Manifest.lock", 187 | ); 188 | name = "[CP] Check Pods Manifest.lock"; 189 | outputFileListPaths = ( 190 | ); 191 | outputPaths = ( 192 | "$(DERIVED_FILE_DIR)/Pods-cptest-checkManifestLockResult.txt", 193 | ); 194 | runOnlyForDeploymentPostprocessing = 0; 195 | shellPath = /bin/sh; 196 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 197 | showEnvVarsInLog = 0; 198 | }; 199 | 6A0A25194E5990B031819186 /* [CP] Embed Pods Frameworks */ = { 200 | isa = PBXShellScriptBuildPhase; 201 | buildActionMask = 2147483647; 202 | files = ( 203 | ); 204 | inputFileListPaths = ( 205 | "${PODS_ROOT}/Target Support Files/Pods-cptest/Pods-cptest-frameworks-${CONFIGURATION}-input-files.xcfilelist", 206 | ); 207 | name = "[CP] Embed Pods Frameworks"; 208 | outputFileListPaths = ( 209 | "${PODS_ROOT}/Target Support Files/Pods-cptest/Pods-cptest-frameworks-${CONFIGURATION}-output-files.xcfilelist", 210 | ); 211 | runOnlyForDeploymentPostprocessing = 0; 212 | shellPath = /bin/sh; 213 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-cptest/Pods-cptest-frameworks.sh\"\n"; 214 | showEnvVarsInLog = 0; 215 | }; 216 | /* End PBXShellScriptBuildPhase section */ 217 | 218 | /* Begin PBXSourcesBuildPhase section */ 219 | 51CF48B62493A34C0000D501 /* Sources */ = { 220 | isa = PBXSourcesBuildPhase; 221 | buildActionMask = 2147483647; 222 | files = ( 223 | B3E673212C5935A00006A66B /* AppDelegate.swift in Sources */, 224 | FCF292ED290A6E6C00132DC5 /* LoginView.swift in Sources */, 225 | B3E673232C59366C0006A66B /* ContentView.swift in Sources */, 226 | 51CF48C02493A34C0000D501 /* SceneDelegate.swift in Sources */, 227 | FCF292E9290A525300132DC5 /* ViewModel.swift in Sources */, 228 | FCF292EB290A5DE300132DC5 /* UserInfoView.swift in Sources */, 229 | ); 230 | runOnlyForDeploymentPostprocessing = 0; 231 | }; 232 | /* End PBXSourcesBuildPhase section */ 233 | 234 | /* Begin XCBuildConfiguration section */ 235 | 51CF48CC2493A34D0000D501 /* Debug */ = { 236 | isa = XCBuildConfiguration; 237 | buildSettings = { 238 | ALWAYS_SEARCH_USER_PATHS = NO; 239 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 240 | CLANG_ANALYZER_NONNULL = YES; 241 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 242 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 243 | CLANG_CXX_LIBRARY = "libc++"; 244 | CLANG_ENABLE_MODULES = YES; 245 | CLANG_ENABLE_OBJC_ARC = YES; 246 | CLANG_ENABLE_OBJC_WEAK = YES; 247 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 248 | CLANG_WARN_BOOL_CONVERSION = YES; 249 | CLANG_WARN_COMMA = YES; 250 | CLANG_WARN_CONSTANT_CONVERSION = YES; 251 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 252 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 253 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 254 | CLANG_WARN_EMPTY_BODY = YES; 255 | CLANG_WARN_ENUM_CONVERSION = YES; 256 | CLANG_WARN_INFINITE_RECURSION = YES; 257 | CLANG_WARN_INT_CONVERSION = YES; 258 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 259 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 260 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 261 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 262 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 263 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 264 | CLANG_WARN_STRICT_PROTOTYPES = YES; 265 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 266 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 267 | CLANG_WARN_UNREACHABLE_CODE = YES; 268 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 269 | COPY_PHASE_STRIP = NO; 270 | DEBUG_INFORMATION_FORMAT = dwarf; 271 | ENABLE_STRICT_OBJC_MSGSEND = YES; 272 | ENABLE_TESTABILITY = YES; 273 | GCC_C_LANGUAGE_STANDARD = gnu11; 274 | GCC_DYNAMIC_NO_PIC = NO; 275 | GCC_NO_COMMON_BLOCKS = YES; 276 | GCC_OPTIMIZATION_LEVEL = 0; 277 | GCC_PREPROCESSOR_DEFINITIONS = ( 278 | "DEBUG=1", 279 | "$(inherited)", 280 | ); 281 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 282 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 283 | GCC_WARN_UNDECLARED_SELECTOR = YES; 284 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 285 | GCC_WARN_UNUSED_FUNCTION = YES; 286 | GCC_WARN_UNUSED_VARIABLE = YES; 287 | IPHONEOS_DEPLOYMENT_TARGET = 13.0; 288 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 289 | MTL_FAST_MATH = YES; 290 | ONLY_ACTIVE_ARCH = YES; 291 | SDKROOT = iphoneos; 292 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 293 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 294 | }; 295 | name = Debug; 296 | }; 297 | 51CF48CD2493A34D0000D501 /* Release */ = { 298 | isa = XCBuildConfiguration; 299 | buildSettings = { 300 | ALWAYS_SEARCH_USER_PATHS = NO; 301 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 302 | CLANG_ANALYZER_NONNULL = YES; 303 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 304 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 305 | CLANG_CXX_LIBRARY = "libc++"; 306 | CLANG_ENABLE_MODULES = YES; 307 | CLANG_ENABLE_OBJC_ARC = YES; 308 | CLANG_ENABLE_OBJC_WEAK = YES; 309 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 310 | CLANG_WARN_BOOL_CONVERSION = YES; 311 | CLANG_WARN_COMMA = YES; 312 | CLANG_WARN_CONSTANT_CONVERSION = YES; 313 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 314 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 315 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 316 | CLANG_WARN_EMPTY_BODY = YES; 317 | CLANG_WARN_ENUM_CONVERSION = YES; 318 | CLANG_WARN_INFINITE_RECURSION = YES; 319 | CLANG_WARN_INT_CONVERSION = YES; 320 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 321 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 322 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 323 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 324 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 325 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 326 | CLANG_WARN_STRICT_PROTOTYPES = YES; 327 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 328 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 329 | CLANG_WARN_UNREACHABLE_CODE = YES; 330 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 331 | COPY_PHASE_STRIP = NO; 332 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 333 | ENABLE_NS_ASSERTIONS = NO; 334 | ENABLE_STRICT_OBJC_MSGSEND = YES; 335 | GCC_C_LANGUAGE_STANDARD = gnu11; 336 | GCC_NO_COMMON_BLOCKS = YES; 337 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 338 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 339 | GCC_WARN_UNDECLARED_SELECTOR = YES; 340 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 341 | GCC_WARN_UNUSED_FUNCTION = YES; 342 | GCC_WARN_UNUSED_VARIABLE = YES; 343 | IPHONEOS_DEPLOYMENT_TARGET = 13.0; 344 | MTL_ENABLE_DEBUG_INFO = NO; 345 | MTL_FAST_MATH = YES; 346 | SDKROOT = iphoneos; 347 | SWIFT_COMPILATION_MODE = wholemodule; 348 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 349 | VALIDATE_PRODUCT = YES; 350 | }; 351 | name = Release; 352 | }; 353 | 51CF48CF2493A34D0000D501 /* Debug */ = { 354 | isa = XCBuildConfiguration; 355 | baseConfigurationReference = BBD4C42A80D1902311E2555B /* Pods-cptest.debug.xcconfig */; 356 | buildSettings = { 357 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 358 | CODE_SIGN_STYLE = Automatic; 359 | DEVELOPMENT_ASSET_PATHS = "\"cptest/Preview Content\""; 360 | DEVELOPMENT_TEAM = 2Q63NCPY55; 361 | ENABLE_PREVIEWS = YES; 362 | "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; 363 | INFOPLIST_FILE = cptest/Info.plist; 364 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 365 | LD_RUNPATH_SEARCH_PATHS = ( 366 | "$(inherited)", 367 | "@executable_path/Frameworks", 368 | ); 369 | PRODUCT_BUNDLE_IDENTIFIER = torus.cptest; 370 | PRODUCT_NAME = "$(TARGET_NAME)"; 371 | SWIFT_VERSION = 5.0; 372 | TARGETED_DEVICE_FAMILY = "1,2"; 373 | }; 374 | name = Debug; 375 | }; 376 | 51CF48D02493A34D0000D501 /* Release */ = { 377 | isa = XCBuildConfiguration; 378 | baseConfigurationReference = A0255E8F3CDAC6C5FAF1D494 /* Pods-cptest.release.xcconfig */; 379 | buildSettings = { 380 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 381 | CODE_SIGN_STYLE = Automatic; 382 | DEVELOPMENT_ASSET_PATHS = "\"cptest/Preview Content\""; 383 | DEVELOPMENT_TEAM = 2Q63NCPY55; 384 | ENABLE_PREVIEWS = YES; 385 | "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; 386 | INFOPLIST_FILE = cptest/Info.plist; 387 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 388 | LD_RUNPATH_SEARCH_PATHS = ( 389 | "$(inherited)", 390 | "@executable_path/Frameworks", 391 | ); 392 | PRODUCT_BUNDLE_IDENTIFIER = torus.cptest; 393 | PRODUCT_NAME = "$(TARGET_NAME)"; 394 | SWIFT_VERSION = 5.0; 395 | TARGETED_DEVICE_FAMILY = "1,2"; 396 | }; 397 | name = Release; 398 | }; 399 | /* End XCBuildConfiguration section */ 400 | 401 | /* Begin XCConfigurationList section */ 402 | 51CF48B52493A34C0000D501 /* Build configuration list for PBXProject "cptest" */ = { 403 | isa = XCConfigurationList; 404 | buildConfigurations = ( 405 | 51CF48CC2493A34D0000D501 /* Debug */, 406 | 51CF48CD2493A34D0000D501 /* Release */, 407 | ); 408 | defaultConfigurationIsVisible = 0; 409 | defaultConfigurationName = Release; 410 | }; 411 | 51CF48CE2493A34D0000D501 /* Build configuration list for PBXNativeTarget "cptest" */ = { 412 | isa = XCConfigurationList; 413 | buildConfigurations = ( 414 | 51CF48CF2493A34D0000D501 /* Debug */, 415 | 51CF48D02493A34D0000D501 /* Release */, 416 | ); 417 | defaultConfigurationIsVisible = 0; 418 | defaultConfigurationName = Release; 419 | }; 420 | /* End XCConfigurationList section */ 421 | }; 422 | rootObject = 51CF48B22493A34C0000D501 /* Project object */; 423 | } 424 | -------------------------------------------------------------------------------- /cocoapods/cptest.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /cocoapods/cptest.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /cocoapods/cptest.xcodeproj/xcshareddata/xcschemes/cptest.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /cocoapods/cptest.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /cocoapods/cptest.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /cocoapods/cptest.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /cocoapods/cptest/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | @UIApplicationMain 4 | class AppDelegate: UIResponder, UIApplicationDelegate { 5 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 6 | // Override point for customization after application launch. 7 | return true 8 | } 9 | 10 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 11 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /cocoapods/cptest/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /cocoapods/cptest/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /cocoapods/cptest/ContentView.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct ContentView: View { 4 | @ObservedObject var vm: ViewModel 5 | 6 | var body: some View { 7 | NavigationView { 8 | VStack { 9 | if vm.user != nil { 10 | UserInfoView(vm: vm) 11 | } else { 12 | LoginView(vm: vm) 13 | } 14 | } 15 | .alert(isPresented: $vm.showingAlert) { 16 | Alert(title: Text("Error"), message: Text("Login failed!"), dismissButton: .default(Text("OK"))) 17 | } 18 | .navigationBarTitle(Text("CustomAuth App")) 19 | } 20 | } 21 | } 22 | 23 | struct ContentView_Previews: PreviewProvider { 24 | static var previews: some View { 25 | ContentView(vm: .init()) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /cocoapods/cptest/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleURLTypes 20 | 21 | 22 | CFBundleTypeRole 23 | Editor 24 | CFBundleURLSchemes 25 | 26 | tdsdk 27 | tdsdk-swift 28 | tdsdk 29 | com.torus.CustomAuthDemo 30 | com.googleusercontent.apps.238941746713-vfap8uumijal4ump28p9jd3lbe6onqt4 31 | 32 | 33 | 34 | CFBundleTypeRole 35 | Editor 36 | CFBundleURLSchemes 37 | 38 | torus 39 | 40 | 41 | 42 | CFBundleVersion 43 | 1 44 | LSRequiresIPhoneOS 45 | 46 | UIApplicationSceneManifest 47 | 48 | UIApplicationSupportsMultipleScenes 49 | 50 | UISceneConfigurations 51 | 52 | UIWindowSceneSessionRoleApplication 53 | 54 | 55 | UISceneConfigurationName 56 | Default Configuration 57 | UISceneDelegateClassName 58 | $(PRODUCT_MODULE_NAME).SceneDelegate 59 | 60 | 61 | 62 | 63 | UILaunchStoryboardName 64 | LaunchScreen 65 | UIRequiredDeviceCapabilities 66 | 67 | armv7 68 | 69 | UISupportedInterfaceOrientations 70 | 71 | UIInterfaceOrientationPortrait 72 | UIInterfaceOrientationLandscapeLeft 73 | UIInterfaceOrientationLandscapeRight 74 | 75 | UISupportedInterfaceOrientations~ipad 76 | 77 | UIInterfaceOrientationPortrait 78 | UIInterfaceOrientationPortraitUpsideDown 79 | UIInterfaceOrientationLandscapeLeft 80 | UIInterfaceOrientationLandscapeRight 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /cocoapods/cptest/LoginView.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct LoginView: View { 4 | @ObservedObject var vm: ViewModel 5 | var body: some View { 6 | List { 7 | Section(header: Text("Single Logins")) { 8 | Group { 9 | Button(action: { 10 | vm.googleLogin() 11 | }, label: { 12 | Text("Google Login") 13 | }) 14 | } 15 | 16 | Button(action: { 17 | vm.discordLogin() 18 | }, label: { 19 | Text("Discord Login") 20 | }) 21 | 22 | Button(action: { 23 | vm.facebookLogin() 24 | }, label: { 25 | Text("Facebook Login") 26 | }) 27 | 28 | Button(action: { 29 | vm.twitchLogin() 30 | }, label: { 31 | Text("Twitch Login") 32 | }) 33 | 34 | Button(action: { 35 | vm.githubLogin() 36 | }, label: { 37 | Text("Github Login") 38 | }) 39 | 40 | Button(action: { 41 | vm.appleLogin() 42 | }, label: { 43 | Text("Apple Login") 44 | }) 45 | 46 | Button(action: { 47 | vm.emailPasswordLogin() 48 | }, label: { 49 | Text("Email-Password Login") 50 | }) 51 | } 52 | } 53 | .foregroundColor(.black) 54 | } 55 | } 56 | 57 | struct LoginView_Previews: PreviewProvider { 58 | static var previews: some View { 59 | LoginView(vm: .init()) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /cocoapods/cptest/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /cocoapods/cptest/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | import CustomAuth 2 | import SwiftUI 3 | 4 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 5 | var window: UIWindow? 6 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { 7 | let vm = ViewModel() 8 | let contentView = ContentView(vm: vm) 9 | 10 | if let windowScene = scene as? UIWindowScene { 11 | let window = UIWindow(windowScene: windowScene) 12 | window.rootViewController = UIHostingController(rootView: contentView) 13 | self.window = window 14 | window.makeKeyAndVisible() 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /cocoapods/cptest/UserInfoView.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct UserInfoView: View { 4 | @ObservedObject var vm: ViewModel 5 | 6 | var body: some View { 7 | if let user = vm.user { 8 | List { 9 | Section { 10 | Text("\(user.privateKey)") 11 | } header: { 12 | Text("Private key") 13 | } 14 | Section { 15 | Text("\(user.publicAddress)") 16 | } 17 | header: { 18 | Text("Public Address") 19 | } 20 | Section { 21 | let encoded = try! JSONEncoder().encode(user.userInfo) 22 | Text(String(data: encoded, encoding: .utf8)!) 23 | } 24 | header: { 25 | Text("User Info") 26 | } 27 | } 28 | .listStyle(.automatic) 29 | .navigationBarItems(trailing: Button { 30 | vm.removeUser() 31 | } 32 | label: { 33 | Image(systemName: "xmark.circle.fill") 34 | .foregroundColor(.black) 35 | }) 36 | } 37 | } 38 | } 39 | 40 | struct UserInfoView_Previews: PreviewProvider { 41 | static var previews: some View { 42 | UserInfoView(vm: ViewModel()) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /cocoapods/cptest/ViewModel.swift: -------------------------------------------------------------------------------- 1 | import CustomAuth 2 | import Foundation 3 | 4 | struct User { 5 | var publicAddress: String 6 | var privateKey: String 7 | var userInfo: UserInfo 8 | } 9 | 10 | class ViewModel: ObservableObject { 11 | @Published var user: User? 12 | @Published var showingAlert: Bool = false 13 | private var testnetNetworkUrl: String = "https://rpc.ankr.com/eth_ropsten" 14 | 15 | func removeUser() { 16 | user = nil 17 | } 18 | } 19 | 20 | extension ViewModel { 21 | func googleLogin() { 22 | Task { 23 | do { 24 | let sub = SingleLoginParams(typeOfLogin: .google, verifier: "w3a-google-demo", clientId: "519228911939-cri01h55lsjbsia1k7ll6qpalrus75ps.apps.googleusercontent.com") 25 | 26 | let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .SAPPHIRE_MAINNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") 27 | let customAuth = try CustomAuth(config: customAuthArgs) 28 | let torusLoginResponse = try await customAuth.triggerLogin(args: sub) 29 | 30 | DispatchQueue.main.async { 31 | self.user = User(publicAddress: torusLoginResponse.torusKey.finalKeyData.evmAddress, privateKey: torusLoginResponse.torusKey.finalKeyData.privKey, userInfo: torusLoginResponse.singleVerifierResponse.userInfo) 32 | } 33 | } catch { 34 | print(error) 35 | } 36 | } 37 | } 38 | 39 | func discordLogin() { 40 | Task { 41 | do { 42 | let sub = SingleLoginParams(typeOfLogin: .discord, verifier: "w3a-discord-demo", clientId: "1151006428610433095") 43 | 44 | let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .SAPPHIRE_MAINNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") 45 | 46 | let customAuth = try CustomAuth(config: customAuthArgs) 47 | let torusLoginResponse = try await customAuth.triggerLogin(args: sub) 48 | 49 | DispatchQueue.main.async { 50 | self.user = User(publicAddress: torusLoginResponse.torusKey.finalKeyData.evmAddress, privateKey: torusLoginResponse.torusKey.finalKeyData.privKey, userInfo: torusLoginResponse.singleVerifierResponse.userInfo) 51 | } 52 | } catch { 53 | print(error) 54 | } 55 | } 56 | } 57 | 58 | func facebookLogin() { 59 | Task { 60 | do { 61 | let sub = SingleLoginParams(typeOfLogin: .facebook, verifier: "w3a-facebook-demo", clientId: "342380202252650") 62 | 63 | let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .SAPPHIRE_MAINNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") 64 | 65 | let customAuth = try CustomAuth(config: customAuthArgs) 66 | let torusLoginResponse = try await customAuth.triggerLogin(args: sub) 67 | DispatchQueue.main.async { 68 | self.user = User(publicAddress: torusLoginResponse.torusKey.finalKeyData.evmAddress, privateKey: torusLoginResponse.torusKey.finalKeyData.privKey, userInfo: torusLoginResponse.singleVerifierResponse.userInfo) 69 | } 70 | } catch { 71 | print(error) 72 | } 73 | } 74 | } 75 | 76 | func twitchLogin() { 77 | Task { 78 | do { 79 | let sub = SingleLoginParams(typeOfLogin: .twitch, verifier: "w3a-twitch-demo", clientId: "3k7e70gowvxjaxg71hjnc8h8ih3bpf") 80 | let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .SAPPHIRE_MAINNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") 81 | let customAuth = try CustomAuth(config: customAuthArgs) 82 | let torusLoginResponse = try await customAuth.triggerLogin(args: sub) 83 | DispatchQueue.main.async { 84 | self.user = User(publicAddress: torusLoginResponse.torusKey.finalKeyData.evmAddress, privateKey: torusLoginResponse.torusKey.finalKeyData.privKey, userInfo: torusLoginResponse.singleVerifierResponse.userInfo) 85 | } 86 | } catch { 87 | print(error) 88 | } 89 | } 90 | } 91 | 92 | func githubLogin() { 93 | Task { 94 | do { 95 | let sub = SingleLoginParams(typeOfLogin: .github, verifier: "w3a-auth0-demo", clientId: "hUVVf4SEsZT7syOiL0gLU9hFEtm2gQ6O", jwtParams: Auth0ClientOptions(connection: "github", domain: "web3auth.au.auth0.com", verifierIdField: "sub")) 96 | let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .SAPPHIRE_MAINNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") 97 | let customAuth = try CustomAuth(config: customAuthArgs) 98 | let torusLoginResponse = try await customAuth.triggerLogin(args: sub) 99 | DispatchQueue.main.async { 100 | self.user = User(publicAddress: torusLoginResponse.torusKey.finalKeyData.evmAddress, privateKey: torusLoginResponse.torusKey.finalKeyData.privKey, userInfo: torusLoginResponse.singleVerifierResponse.userInfo) 101 | } 102 | } catch { 103 | print(error) 104 | } 105 | } 106 | } 107 | 108 | func appleLogin() { 109 | Task { 110 | do { 111 | let sub = SingleLoginParams(typeOfLogin: .apple, verifier: "w3a-auth0-demo", clientId: "hUVVf4SEsZT7syOiL0gLU9hFEtm2gQ6O", jwtParams: Auth0ClientOptions(connection: "apple", domain: "web3auth.au.auth0.com")) 112 | let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .SAPPHIRE_MAINNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") 113 | 114 | let customAuth = try CustomAuth(config: customAuthArgs) 115 | let torusLoginResponse = try await customAuth.triggerLogin(args: sub) 116 | 117 | DispatchQueue.main.async { 118 | self.user = User(publicAddress: torusLoginResponse.torusKey.finalKeyData.evmAddress, privateKey: torusLoginResponse.torusKey.finalKeyData.privKey, userInfo: torusLoginResponse.singleVerifierResponse.userInfo) 119 | } 120 | } catch { 121 | print(error) 122 | } 123 | } 124 | } 125 | 126 | func emailPasswordLogin() { 127 | Task { 128 | do { 129 | let sub = SingleLoginParams(typeOfLogin: .email_password, 130 | verifier: "torus-auth0-email-password", clientId: "sqKRBVSdwa4WLkaq419U7Bamlh5vK1H7", 131 | jwtParams: Auth0ClientOptions( 132 | connection: "Username-Password-Authentication", 133 | domain: "torus-test.auth0.com", 134 | verifierIdField: "name")) 135 | let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .TESTNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") 136 | let customAuth = try CustomAuth(config: customAuthArgs) 137 | let torusLoginResponse = try await customAuth.triggerLogin(args: sub) 138 | DispatchQueue.main.async { 139 | self.user = User(publicAddress: torusLoginResponse.torusKey.finalKeyData.evmAddress, privateKey: torusLoginResponse.torusKey.finalKeyData.privKey, userInfo: torusLoginResponse.singleVerifierResponse.userInfo) 140 | } 141 | } catch { 142 | print(error) 143 | } 144 | } 145 | } 146 | } 147 | --------------------------------------------------------------------------------