From 72a83f30942b1f87cbed7eac5b1c5a164e91d1d4 Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Thu, 6 Jun 2024 08:07:59 +0200 Subject: [PATCH 01/24] re-align customauth This PR seeks to re-align the current implementation of custom-auth-swift to that of the web implementation of CustomAuth. This will reduce the overhead of differences a developer would need to remember between the two and provide an overall better experience. This will also provide better long term maintainability and make feature parity simpler to implement between the two. Note this is a breaking change and needs to be released as a major version. --- .github/workflows/main.yml | 4 +- CustomAuth.podspec | 4 +- .../CustomAuthDemo.xcodeproj/project.pbxproj | 96 ++-- .../xcshareddata/WorkspaceSettings.xcsettings | 2 + .../xcshareddata/swiftpm/Package.resolved | 159 +++--- .../xcschemes/CustomAuthDemo.xcscheme | 2 +- .../xcschemes/CustomAuthDemoTests.xcscheme | 73 +++ .../xcschemes/CustomAuthDemoUITests.xcscheme | 73 +++ .../CustomAuthDemo/AppDelegate.swift | 32 -- .../Base.lproj/LaunchScreen.storyboard | 25 - .../CustomAuthDemo/ContentView.swift | 489 ++++++----------- .../CustomAuthDemo/CustomAuthDemo.swift | 12 + CustomAuthDemo/CustomAuthDemo/Info.plist | 11 +- .../CustomAuthDemo/SceneDelegate.swift | 84 --- .../CustomAuthDemoTests.swift | 16 +- .../CustomAuthDemoUITests.swift | 27 +- .../xcshareddata/swiftpm/Package.resolved | 106 +--- Notice.md | 4 - Package.resolved | 141 +++-- Package.swift | 14 +- README.md | 155 +----- .../AggregateLoginParams.swift | 13 + .../AggregateVerifierType.swift | 5 + Sources/CustomAuth/Common/HashParams.swift | 11 + .../LoginParams/Auth0ClientOptions.swift | 61 +++ .../LoginParams/Auth0JwtLoginType.swift | 12 + .../Common/LoginParams/BaseLoginOptions.swift | 38 ++ .../HybridAggregateLoginParams.swift | 11 + .../Common/LoginParams/LoginType.swift | 17 + .../LoginParams/SubVerifierDetails.swift | 25 + .../LoginParams/TorusSubVerifierInfo.swift | 13 + .../LoginResponses/LoginWindowResponse.swift | 19 + .../TorusAggregateLoginResponse.swift | 12 + .../TorusHybridAggregateLoginResponse.swift | 12 + .../LoginResponses/TorusLoginResponse.swift | 12 + .../Passkeys/AuthenticatorTransports.swift | 9 + .../Common/Passkeys/PassKeyExtraParams.swift | 27 + Sources/CustomAuth/Common/PopupResponse.swift | 11 + .../Common/RedirectResultParams.swift | 11 + Sources/CustomAuth/Common/State.swift | 28 + .../Common/TorusGenericContainer.swift | 9 + .../TorusAggregateVerifierResponse.swift | 11 + .../TorusSingleVerifierResponse.swift | 11 + .../TorusVerifierResponses.swift | 26 + .../Common/VerifierResponses/UserInfo.swift | 35 ++ Sources/CustomAuth/CustomAuth.swift | 473 ++++++++-------- Sources/CustomAuth/CustomAuthArgs.swift | 28 + Sources/CustomAuth/CustomAuthFactory.swift | 49 -- .../Extension/CASDK+extension.swift | 144 ----- .../CustomAuth/Extension/Data+extension.swift | 11 + Sources/CustomAuth/Extension/Dictionary.swift | 78 --- Sources/CustomAuth/Extension/OSLog.swift | 31 -- .../Extension/String+extension.swift | 60 ++ Sources/CustomAuth/Extension/String.swift | 156 ------ .../Extension/URLComponents+extension.swift | 7 + .../Handlers/AuthenticationManager.swift | 52 ++ .../Handlers/DiscordLoginHandler.swift | 105 ++-- .../Handlers/FacebookLoginHandler.swift | 112 ++-- .../Handlers/GoogleLoginHandler.swift | 144 ++--- .../CustomAuth/Handlers/HandlerFactory.swift | 48 ++ .../CustomAuth/Handlers/JWTLoginHandler.swift | 182 +++---- .../Handlers/MockLoginHandler.swift | 91 ++++ .../Handlers/PasswordlessLoginHandler.swift | 85 +++ .../Protocol/AbstractLoginHandler.swift | 78 ++- .../Protocol/CreateHandlerParams.swift | 21 + .../Handlers/Protocol/ILoginHandler.swift | 13 + .../Handlers/RedditLoginHandler.swift | 104 ++-- .../Handlers/TwitchLoginHandler.swift | 115 ++-- .../CustomAuth/Helpers/ASWebAuthSession.swift | 44 -- Sources/CustomAuth/Helpers/Common.swift | 107 ++++ Sources/CustomAuth/Helpers/Error.swift | 49 +- .../Helpers/ExternalURLHandler.swift | 27 - Sources/CustomAuth/Helpers/SFURLHandler.swift | 92 ---- Sources/CustomAuth/Helpers/URL.swift | 63 --- Sources/CustomAuth/Models/Browser.swift | 18 - .../CustomAuth/Models/LoginProviders.swift | 38 -- .../Models/SubVerifierDetails.swift | 49 -- Tests/CustomAuthTests/CustomAuthTests.swift | 110 +--- Tests/CustomAuthTests/IntegrationTests.swift | 146 ----- Tests/CustomAuthTests/MockCASDKFactory.swift | 25 - Tests/CustomAuthTests/MockTorusUtils.swift | 73 --- Tests/CustomAuthTests/StubURLProtocol.swift | 514 ------------------ .../StubURLProtocolTests.swift | 30 - 83 files changed, 2129 insertions(+), 3411 deletions(-) create mode 100644 CustomAuthDemo/CustomAuthDemo.xcodeproj/xcshareddata/xcschemes/CustomAuthDemoTests.xcscheme create mode 100644 CustomAuthDemo/CustomAuthDemo.xcodeproj/xcshareddata/xcschemes/CustomAuthDemoUITests.xcscheme delete mode 100644 CustomAuthDemo/CustomAuthDemo/AppDelegate.swift delete mode 100644 CustomAuthDemo/CustomAuthDemo/Base.lproj/LaunchScreen.storyboard create mode 100644 CustomAuthDemo/CustomAuthDemo/CustomAuthDemo.swift delete mode 100644 CustomAuthDemo/CustomAuthDemo/SceneDelegate.swift delete mode 100644 Notice.md create mode 100644 Sources/CustomAuth/Common/AggregateVerifierParams/AggregateLoginParams.swift create mode 100644 Sources/CustomAuth/Common/AggregateVerifierParams/AggregateVerifierType.swift create mode 100644 Sources/CustomAuth/Common/HashParams.swift create mode 100644 Sources/CustomAuth/Common/LoginParams/Auth0ClientOptions.swift create mode 100644 Sources/CustomAuth/Common/LoginParams/Auth0JwtLoginType.swift create mode 100644 Sources/CustomAuth/Common/LoginParams/BaseLoginOptions.swift create mode 100644 Sources/CustomAuth/Common/LoginParams/HybridAggregateLoginParams.swift create mode 100644 Sources/CustomAuth/Common/LoginParams/LoginType.swift create mode 100644 Sources/CustomAuth/Common/LoginParams/SubVerifierDetails.swift create mode 100644 Sources/CustomAuth/Common/LoginParams/TorusSubVerifierInfo.swift create mode 100644 Sources/CustomAuth/Common/LoginResponses/LoginWindowResponse.swift create mode 100644 Sources/CustomAuth/Common/LoginResponses/TorusAggregateLoginResponse.swift create mode 100644 Sources/CustomAuth/Common/LoginResponses/TorusHybridAggregateLoginResponse.swift create mode 100644 Sources/CustomAuth/Common/LoginResponses/TorusLoginResponse.swift create mode 100644 Sources/CustomAuth/Common/Passkeys/AuthenticatorTransports.swift create mode 100644 Sources/CustomAuth/Common/Passkeys/PassKeyExtraParams.swift create mode 100644 Sources/CustomAuth/Common/PopupResponse.swift create mode 100644 Sources/CustomAuth/Common/RedirectResultParams.swift create mode 100644 Sources/CustomAuth/Common/State.swift create mode 100644 Sources/CustomAuth/Common/TorusGenericContainer.swift create mode 100644 Sources/CustomAuth/Common/VerifierResponses/TorusAggregateVerifierResponse.swift create mode 100644 Sources/CustomAuth/Common/VerifierResponses/TorusSingleVerifierResponse.swift create mode 100644 Sources/CustomAuth/Common/VerifierResponses/TorusVerifierResponses.swift create mode 100644 Sources/CustomAuth/Common/VerifierResponses/UserInfo.swift create mode 100644 Sources/CustomAuth/CustomAuthArgs.swift delete mode 100644 Sources/CustomAuth/CustomAuthFactory.swift delete mode 100644 Sources/CustomAuth/Extension/CASDK+extension.swift create mode 100644 Sources/CustomAuth/Extension/Data+extension.swift delete mode 100644 Sources/CustomAuth/Extension/Dictionary.swift delete mode 100644 Sources/CustomAuth/Extension/OSLog.swift create mode 100644 Sources/CustomAuth/Extension/String+extension.swift delete mode 100644 Sources/CustomAuth/Extension/String.swift create mode 100644 Sources/CustomAuth/Extension/URLComponents+extension.swift create mode 100644 Sources/CustomAuth/Handlers/AuthenticationManager.swift create mode 100644 Sources/CustomAuth/Handlers/HandlerFactory.swift create mode 100644 Sources/CustomAuth/Handlers/MockLoginHandler.swift create mode 100644 Sources/CustomAuth/Handlers/PasswordlessLoginHandler.swift create mode 100644 Sources/CustomAuth/Handlers/Protocol/CreateHandlerParams.swift create mode 100644 Sources/CustomAuth/Handlers/Protocol/ILoginHandler.swift delete mode 100644 Sources/CustomAuth/Helpers/ASWebAuthSession.swift create mode 100644 Sources/CustomAuth/Helpers/Common.swift delete mode 100644 Sources/CustomAuth/Helpers/ExternalURLHandler.swift delete mode 100644 Sources/CustomAuth/Helpers/SFURLHandler.swift delete mode 100644 Sources/CustomAuth/Helpers/URL.swift delete mode 100644 Sources/CustomAuth/Models/Browser.swift delete mode 100644 Sources/CustomAuth/Models/LoginProviders.swift delete mode 100644 Sources/CustomAuth/Models/SubVerifierDetails.swift delete mode 100644 Tests/CustomAuthTests/IntegrationTests.swift delete mode 100644 Tests/CustomAuthTests/MockCASDKFactory.swift delete mode 100644 Tests/CustomAuthTests/MockTorusUtils.swift delete mode 100644 Tests/CustomAuthTests/StubURLProtocol.swift delete mode 100644 Tests/CustomAuthTests/StubURLProtocolTests.swift diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 47f64ff..4cad100 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -26,10 +26,10 @@ jobs: platform: - iOS steps: - - uses: actions/checkout@v2.3.4 + - uses: actions/checkout@v4 - name: Remove Development.xcworkspace to avoid tooling confusion run: rm -rf Development.xcworkspace - - uses: mxcl/xcodebuild@v1 + - uses: mxcl/xcodebuild@v3.0.0 with: platform: ${{ matrix.platform }} action: test diff --git a/CustomAuth.podspec b/CustomAuth.podspec index 023db6e..6a4c024 100644 --- a/CustomAuth.podspec +++ b/CustomAuth.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = "CustomAuth" - spec.version = "10.0.1" + spec.version = "11.0.0" spec.platform = :ios, "13.0" spec.summary = "Swift SDK that allows applications to directly interact with the Torus Network, similar to how Torus Wallet does." spec.homepage = "https://github.com/torusresearch/customauth-swift-sdk" @@ -10,6 +10,6 @@ Pod::Spec.new do |spec| spec.module_name = "CustomAuth" spec.source = { :git => "https://github.com/torusresearch/customauth-swift-sdk.git", :tag => spec.version } spec.source_files = "Sources/CustomAuth/*.{swift}","Sources/CustomAuth/**/*.{swift}" - spec.dependency 'Torus-utils', '~> 8.1.0' + spec.dependency 'Torus-utils', '~> 9.0.0' spec.dependency 'JWTDecode', '~> 3.1.0' end diff --git a/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.pbxproj b/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.pbxproj index f62f369..208ada2 100644 --- a/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.pbxproj +++ b/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.pbxproj @@ -7,16 +7,15 @@ objects = { /* Begin PBXBuildFile section */ - 511CEACC2452D4EC00A7ACE9 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 511CEACB2452D4EC00A7ACE9 /* AppDelegate.swift */; }; - 511CEACE2452D4EC00A7ACE9 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 511CEACD2452D4EC00A7ACE9 /* SceneDelegate.swift */; }; 511CEAD02452D4EC00A7ACE9 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 511CEACF2452D4EC00A7ACE9 /* ContentView.swift */; }; 511CEAD22452D4EF00A7ACE9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 511CEAD12452D4EF00A7ACE9 /* Assets.xcassets */; }; 511CEAD52452D4EF00A7ACE9 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 511CEAD42452D4EF00A7ACE9 /* Preview Assets.xcassets */; }; - 511CEAD82452D4EF00A7ACE9 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 511CEAD62452D4EF00A7ACE9 /* LaunchScreen.storyboard */; }; 511CEAE32452D4EF00A7ACE9 /* CustomAuthDemoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 511CEAE22452D4EF00A7ACE9 /* CustomAuthDemoTests.swift */; }; 511CEAEE2452D4EF00A7ACE9 /* CustomAuthDemoUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 511CEAED2452D4EF00A7ACE9 /* CustomAuthDemoUITests.swift */; }; 51775EB72484B66A00A29680 /* CustomAuth in Frameworks */ = {isa = PBXBuildFile; productRef = 51775EB62484B66A00A29680 /* CustomAuth */; }; - B36D0EFF2BA033AD008F4C71 /* PromiseKit in Frameworks */ = {isa = PBXBuildFile; productRef = B36D0EFE2BA033AD008F4C71 /* PromiseKit */; }; + B37E3CEE2C1CF30F00B63F41 /* CustomAuthDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B37E3CED2C1CF30F00B63F41 /* CustomAuthDemo.swift */; }; + B37E3CF12C1E1C6E00B63F41 /* CustomAuth in Frameworks */ = {isa = PBXBuildFile; productRef = B37E3CF02C1E1C6E00B63F41 /* CustomAuth */; }; + B37E3CF32C1E23B700B63F41 /* CustomAuth in Frameworks */ = {isa = PBXBuildFile; productRef = B37E3CF22C1E23B700B63F41 /* CustomAuth */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -38,12 +37,9 @@ /* Begin PBXFileReference section */ 511CEAC82452D4EC00A7ACE9 /* CustomAuthDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CustomAuthDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 511CEACB2452D4EC00A7ACE9 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 511CEACD2452D4EC00A7ACE9 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 511CEACF2452D4EC00A7ACE9 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 511CEAD12452D4EF00A7ACE9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 511CEAD42452D4EF00A7ACE9 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; - 511CEAD72452D4EF00A7ACE9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 511CEAD92452D4EF00A7ACE9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 511CEADE2452D4EF00A7ACE9 /* CustomAuthDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CustomAuthDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 511CEAE22452D4EF00A7ACE9 /* CustomAuthDemoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomAuthDemoTests.swift; sourceTree = ""; }; @@ -51,9 +47,8 @@ 511CEAE92452D4EF00A7ACE9 /* CustomAuthDemoUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CustomAuthDemoUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 511CEAED2452D4EF00A7ACE9 /* CustomAuthDemoUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomAuthDemoUITests.swift; sourceTree = ""; }; 511CEAEF2452D4EF00A7ACE9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 51721D842474E4B700C22BAD /* torus-direct-swift-sdk */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "torus-direct-swift-sdk"; path = ..; sourceTree = ""; }; - 517C5F5D24693F9D006D5A43 /* CustomAuthDemo.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = CustomAuthDemo.entitlements; sourceTree = ""; }; A3C24F222A70FAF9002F4FC9 /* customauth-swift-sdk */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = "customauth-swift-sdk"; path = ..; sourceTree = ""; }; + B37E3CED2C1CF30F00B63F41 /* CustomAuthDemo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomAuthDemo.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -62,7 +57,6 @@ buildActionMask = 2147483647; files = ( 51775EB72484B66A00A29680 /* CustomAuth in Frameworks */, - B36D0EFF2BA033AD008F4C71 /* PromiseKit in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -70,6 +64,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + B37E3CF32C1E23B700B63F41 /* CustomAuth in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -77,20 +72,13 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + B37E3CF12C1E1C6E00B63F41 /* CustomAuth in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 18B4F998A7F88C302F18BA73 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 51721D842474E4B700C22BAD /* torus-direct-swift-sdk */, - ); - name = Frameworks; - sourceTree = ""; - }; 511CEABF2452D4EC00A7ACE9 = { isa = PBXGroup; children = ( @@ -99,8 +87,7 @@ 511CEAE12452D4EF00A7ACE9 /* CustomAuthDemoTests */, 511CEAEC2452D4EF00A7ACE9 /* CustomAuthDemoUITests */, 511CEAC92452D4EC00A7ACE9 /* Products */, - A84257F51AACA6652F347CFD /* Pods */, - 18B4F998A7F88C302F18BA73 /* Frameworks */, + B37E3CEF2C1E1C6E00B63F41 /* Frameworks */, ); sourceTree = ""; }; @@ -117,12 +104,9 @@ 511CEACA2452D4EC00A7ACE9 /* CustomAuthDemo */ = { isa = PBXGroup; children = ( - 517C5F5D24693F9D006D5A43 /* CustomAuthDemo.entitlements */, - 511CEACB2452D4EC00A7ACE9 /* AppDelegate.swift */, - 511CEACD2452D4EC00A7ACE9 /* SceneDelegate.swift */, + B37E3CED2C1CF30F00B63F41 /* CustomAuthDemo.swift */, 511CEACF2452D4EC00A7ACE9 /* ContentView.swift */, 511CEAD12452D4EF00A7ACE9 /* Assets.xcassets */, - 511CEAD62452D4EF00A7ACE9 /* LaunchScreen.storyboard */, 511CEAD92452D4EF00A7ACE9 /* Info.plist */, 511CEAD32452D4EF00A7ACE9 /* Preview Content */, ); @@ -163,11 +147,11 @@ name = Packages; sourceTree = ""; }; - A84257F51AACA6652F347CFD /* Pods */ = { + B37E3CEF2C1E1C6E00B63F41 /* Frameworks */ = { isa = PBXGroup; children = ( ); - path = Pods; + name = Frameworks; sourceTree = ""; }; /* End PBXGroup section */ @@ -188,7 +172,6 @@ name = CustomAuthDemo; packageProductDependencies = ( 51775EB62484B66A00A29680 /* CustomAuth */, - B36D0EFE2BA033AD008F4C71 /* PromiseKit */, ); productName = CustomAuthDemo; productReference = 511CEAC82452D4EC00A7ACE9 /* CustomAuthDemo.app */; @@ -208,6 +191,9 @@ 511CEAE02452D4EF00A7ACE9 /* PBXTargetDependency */, ); name = CustomAuthDemoTests; + packageProductDependencies = ( + B37E3CF22C1E23B700B63F41 /* CustomAuth */, + ); productName = CustomAuthDemoTests; productReference = 511CEADE2452D4EF00A7ACE9 /* CustomAuthDemoTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; @@ -226,6 +212,9 @@ 511CEAEB2452D4EF00A7ACE9 /* PBXTargetDependency */, ); name = CustomAuthDemoUITests; + packageProductDependencies = ( + B37E3CF02C1E1C6E00B63F41 /* CustomAuth */, + ); productName = CustomAuthDemoUITests; productReference = 511CEAE92452D4EF00A7ACE9 /* CustomAuthDemoUITests.xctest */; productType = "com.apple.product-type.bundle.ui-testing"; @@ -236,8 +225,9 @@ 511CEAC02452D4EC00A7ACE9 /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 1140; - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1540; ORGANIZATIONNAME = Shubham; TargetAttributes = { 511CEAC72452D4EC00A7ACE9 = { @@ -263,7 +253,6 @@ ); mainGroup = 511CEABF2452D4EC00A7ACE9; packageReferences = ( - B36D0EFD2BA033AD008F4C71 /* XCRemoteSwiftPackageReference "PromiseKit" */, ); productRefGroup = 511CEAC92452D4EC00A7ACE9 /* Products */; projectDirPath = ""; @@ -281,7 +270,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 511CEAD82452D4EF00A7ACE9 /* LaunchScreen.storyboard in Resources */, 511CEAD52452D4EF00A7ACE9 /* Preview Assets.xcassets in Resources */, 511CEAD22452D4EF00A7ACE9 /* Assets.xcassets in Resources */, ); @@ -308,9 +296,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 511CEACC2452D4EC00A7ACE9 /* AppDelegate.swift in Sources */, - 511CEACE2452D4EC00A7ACE9 /* SceneDelegate.swift in Sources */, 511CEAD02452D4EC00A7ACE9 /* ContentView.swift in Sources */, + B37E3CEE2C1CF30F00B63F41 /* CustomAuthDemo.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -345,22 +332,12 @@ }; /* End PBXTargetDependency section */ -/* Begin PBXVariantGroup section */ - 511CEAD62452D4EF00A7ACE9 /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 511CEAD72452D4EF00A7ACE9 /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - /* Begin XCBuildConfiguration section */ 511CEAF02452D4EF00A7ACE9 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -394,6 +371,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -423,6 +401,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -456,6 +435,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -485,7 +465,7 @@ DEVELOPMENT_TEAM = 2Q63NCPY55; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = CustomAuthDemo/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 13.3; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -507,7 +487,7 @@ DEVELOPMENT_TEAM = 2Q63NCPY55; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = CustomAuthDemo/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 13.3; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -526,7 +506,7 @@ BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = CustomAuthDemoTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 13.4; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -547,7 +527,7 @@ BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = CustomAuthDemoTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 13.4; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -567,6 +547,7 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = CustomAuthDemoUITests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -586,6 +567,7 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = CustomAuthDemoUITests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -640,26 +622,18 @@ }; /* End XCConfigurationList section */ -/* Begin XCRemoteSwiftPackageReference section */ - B36D0EFD2BA033AD008F4C71 /* XCRemoteSwiftPackageReference "PromiseKit" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/mxcl/PromiseKit"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 8.1.1; - }; - }; -/* End XCRemoteSwiftPackageReference section */ - /* Begin XCSwiftPackageProductDependency section */ 51775EB62484B66A00A29680 /* CustomAuth */ = { isa = XCSwiftPackageProductDependency; productName = CustomAuth; }; - B36D0EFE2BA033AD008F4C71 /* PromiseKit */ = { + B37E3CF02C1E1C6E00B63F41 /* CustomAuth */ = { isa = XCSwiftPackageProductDependency; - package = B36D0EFD2BA033AD008F4C71 /* XCRemoteSwiftPackageReference "PromiseKit" */; - productName = PromiseKit; + productName = CustomAuth; + }; + B37E3CF22C1E23B700B63F41 /* CustomAuth */ = { + isa = XCSwiftPackageProductDependency; + productName = CustomAuth; }; /* End XCSwiftPackageProductDependency section */ }; diff --git a/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings index f9b0d7c..a6f6fb2 100644 --- a/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ b/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -2,6 +2,8 @@ + IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded + PreviewsEnabled diff --git a/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 3a07809..f186bd8 100644 --- a/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,97 +1,68 @@ { - "object": { - "pins": [ - { - "package": "AnyCodable", - "repositoryURL": "https://github.com/Flight-School/AnyCodable", - "state": { - "branch": null, - "revision": "862808b2070cd908cb04f9aafe7de83d35f81b05", - "version": "0.6.7" - } - }, - { - "package": "BigInt", - "repositoryURL": "https://github.com/attaswift/BigInt.git", - "state": { - "branch": null, - "revision": "0ed110f7555c34ff468e72e1686e59721f2b0da6", - "version": "5.3.0" - } - }, - { - "package": "CryptoSwift", - "repositoryURL": "https://github.com/krzyzanowskim/CryptoSwift", - "state": { - "branch": null, - "revision": "7892a123f7e8d0fe62f9f03728b17bbd4f94df5c", - "version": "1.8.1" - } - }, - { - "package": "curvelib.swift", - "repositoryURL": "https://github.com/tkey/curvelib.swift", - "state": { - "branch": null, - "revision": "7dad3bf1793de263f83406c08c18c9316abf082f", - "version": "0.1.2" - } - }, - { - "package": "FetchNodeDetails", - "repositoryURL": "https://github.com/torusresearch/fetch-node-details-swift", - "state": { - "branch": null, - "revision": "d591af500f32ce3c88d04af9bb74d746585acfea", - "version": "5.1.0" - } - }, - { - "package": "jwt-kit", - "repositoryURL": "https://github.com/vapor/jwt-kit.git", - "state": { - "branch": null, - "revision": "e05513b5aec24f88012b6e3034115b6bc915356a", - "version": "4.13.2" - } - }, - { - "package": "JWTDecode", - "repositoryURL": "https://github.com/auth0/JWTDecode.swift.git", - "state": { - "branch": null, - "revision": "58af7278797871e460d79496621b3e5366b865b2", - "version": "3.1.0" - } - }, - { - "package": "PromiseKit", - "repositoryURL": "https://github.com/mxcl/PromiseKit", - "state": { - "branch": null, - "revision": "cb70b070cde06837cd10a1febdf6105c1a3bb348", - "version": "8.1.1" - } - }, - { - "package": "swift-crypto", - "repositoryURL": "https://github.com/apple/swift-crypto.git", - "state": { - "branch": null, - "revision": "f0525da24dc3c6cbb2b6b338b65042bc91cbc4bb", - "version": "3.3.0" - } - }, - { - "package": "TorusUtils", - "repositoryURL": "https://github.com/torusresearch/torus-utils-swift.git", - "state": { - "branch": null, - "revision": "04c62fd5f73f21bd01b7c07e08f6135db26c5940", - "version": "8.0.0" - } + "pins" : [ + { + "identity" : "bigint", + "kind" : "remoteSourceControl", + "location" : "https://github.com/attaswift/BigInt.git", + "state" : { + "revision" : "0ed110f7555c34ff468e72e1686e59721f2b0da6", + "version" : "5.3.0" } - ] - }, - "version": 1 + }, + { + "identity" : "curvelib.swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/tkey/curvelib.swift", + "state" : { + "revision" : "9f88bd5e56d1df443a908f7a7e81ae4f4d9170ea", + "version" : "1.0.1" + } + }, + { + "identity" : "fetch-node-details-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/torusresearch/fetch-node-details-swift", + "state" : { + "revision" : "4bd96c33ba8d02d9e27190c5c7cedf09cfdfd656", + "version" : "6.0.3" + } + }, + { + "identity" : "jwt-kit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/vapor/jwt-kit.git", + "state" : { + "revision" : "c2595b9ad7f512d7f334830b4df1fed6e917946a", + "version" : "4.13.4" + } + }, + { + "identity" : "jwtdecode.swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/auth0/JWTDecode.swift.git", + "state" : { + "revision" : "58af7278797871e460d79496621b3e5366b865b2", + "version" : "3.1.0" + } + }, + { + "identity" : "swift-crypto", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-crypto.git", + "state" : { + "revision" : "bc1c29221f6dfeb0ebbfbc98eb95cd3d4967868e", + "version" : "3.4.0" + } + }, + { + "identity" : "torus-utils-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/torusresearch/torus-utils-swift.git", + "state" : { + "revision" : "7788752bed699b3d34e78c2c51174f814d02610b", + "version" : "9.0.0" + } + } + ], + "version" : 2 } diff --git a/CustomAuthDemo/CustomAuthDemo.xcodeproj/xcshareddata/xcschemes/CustomAuthDemo.xcscheme b/CustomAuthDemo/CustomAuthDemo.xcodeproj/xcshareddata/xcschemes/CustomAuthDemo.xcscheme index 87ee52d..5723986 100644 --- a/CustomAuthDemo/CustomAuthDemo.xcodeproj/xcshareddata/xcschemes/CustomAuthDemo.xcscheme +++ b/CustomAuthDemo/CustomAuthDemo.xcodeproj/xcshareddata/xcschemes/CustomAuthDemo.xcscheme @@ -1,6 +1,6 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CustomAuthDemo/CustomAuthDemo.xcodeproj/xcshareddata/xcschemes/CustomAuthDemoUITests.xcscheme b/CustomAuthDemo/CustomAuthDemo.xcodeproj/xcshareddata/xcschemes/CustomAuthDemoUITests.xcscheme new file mode 100644 index 0000000..23e22d8 --- /dev/null +++ b/CustomAuthDemo/CustomAuthDemo.xcodeproj/xcshareddata/xcschemes/CustomAuthDemoUITests.xcscheme @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CustomAuthDemo/CustomAuthDemo/AppDelegate.swift b/CustomAuthDemo/CustomAuthDemo/AppDelegate.swift deleted file mode 100644 index 39ad318..0000000 --- a/CustomAuthDemo/CustomAuthDemo/AppDelegate.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// AppDelegate.swift -// CustomAuthDemo -// -// Created by Shubham on 24/4/20. -// Copyright © 2020 Shubham. All rights reserved. -// - -import UIKit - -@UIApplicationMain -class AppDelegate: UIResponder, UIApplicationDelegate, UISceneDelegate { - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - // Override point for customization after application launch. - return true - } - // MARK: UISceneSession Lifecycle - - func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { - // Called when a new scene session is being created. - // Use this method to select a configuration to create the new scene with. - return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) - } - - func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { - // Called when the user discards a scene session. - // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. - // Use this method to release any resources that were specific to the discarded scenes, as they will not return. - } - -} diff --git a/CustomAuthDemo/CustomAuthDemo/Base.lproj/LaunchScreen.storyboard b/CustomAuthDemo/CustomAuthDemo/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index 865e932..0000000 --- a/CustomAuthDemo/CustomAuthDemo/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/CustomAuthDemo/CustomAuthDemo/ContentView.swift b/CustomAuthDemo/CustomAuthDemo/ContentView.swift index 3839f54..0e19e94 100644 --- a/CustomAuthDemo/CustomAuthDemo/ContentView.swift +++ b/CustomAuthDemo/CustomAuthDemo/ContentView.swift @@ -1,338 +1,171 @@ -// -// ContentView.swift -// CustomAuthDemo -// -// Created by Shubham on 24/4/20. -// Copyright © 2020 Shubham. All rights reserved. -// - -import CryptoSwift import CustomAuth -import FetchNodeDetails -import PromiseKit -import SafariServices import SwiftUI struct ContentView: View { - @State var showSafari = false - + var body: some View { - NavigationView { - List { - Section(header: Text("Single Logins")) { - // Group { - Button(action: { - let sub = SubVerifierDetails(loginType: .web, - loginProvider: .google, - clientId: "221898609709-obfn3p63741l5333093430j3qeiinaa8.apps.googleusercontent.com", - verifier: "google-lrc", - redirectURL: "tdsdk://tdsdk/oauthCallback", - browserRedirectURL: "https://scripts.toruswallet.io/redirect.html") - - let tdsdk = CustomAuth(web3AuthClientId: "221898609709-obfn3p63741l5333093430j3qeiinaa8.apps.googleusercontent.com", aggregateVerifierType: .singleLogin, aggregateVerifier: "google-lrc", subVerifierDetails: [sub], network: .legacy(.TESTNET)) - Task { - do { - let loginData = try await tdsdk.triggerLogin().torusKey.finalKeyData! - print(loginData) - } catch { - print("Error occured") - } - } - }, label: { - Text("Google Login") - }) - - Button(action: { - let sub = SubVerifierDetails(loginType: .web, - loginProvider: .reddit, - clientId: "rXIp6g2y3h1wqg", - verifier: "reddit-shubs", - redirectURL: "tdsdk://tdsdk/oauthCallback") - let tdsdk = CustomAuth(web3AuthClientId: "rXIp6g2y3h1wqg", aggregateVerifierType: .singleLogin, aggregateVerifier: "reddit-shubs", subVerifierDetails: [sub], network: .legacy(.TESTNET)) - Task { - do { - let loginData = try await tdsdk.triggerLogin().torusKey.finalKeyData! - print(loginData) - } catch { - print("Error occured") - } - } - }, label: { - Text("Reddit Login") - }) - - Button(action: { - let sub = SubVerifierDetails(loginType: .web, - loginProvider: .discord, - clientId: "700259843063152661", - verifier: "discord-shubs", - redirectURL: "tdsdk://tdsdk/oauthCallback") - let tdsdk = CustomAuth(web3AuthClientId: "700259843063152661", aggregateVerifierType: .singleLogin, aggregateVerifier: "discord-shubs", subVerifierDetails: [sub], network: .legacy(.TESTNET)) - Task { - do { - let loginData = try await tdsdk.triggerLogin().torusKey.finalKeyData! - print(loginData) - } catch { - print("Error occured") - } - } - }, label: { - Text("Discord Login") - }) - - Button(action: { - let sub = SubVerifierDetails(loginType: .web, - loginProvider: .facebook, - clientId: "659561074900150", - verifier: "facebook-shubs", - redirectURL: "tdsdk://tdsdk/oauthCallback", browserRedirectURL: "https://scripts.toruswallet.io/redirect.html") - - let tdsdk = CustomAuth(web3AuthClientId: "221898609709-obfn3p63741l5333093430j3qeiinaa8.apps.googleusercontent.com", aggregateVerifierType: .singleLogin, aggregateVerifier: "facebook-shubs", subVerifierDetails: [sub], network: .legacy(.TESTNET)) - Task { - do { - let loginData = try await tdsdk.triggerLogin().torusKey.finalKeyData! - print(loginData) - } catch { - print("Error occured") - } - } - }, label: { - Text("Facebook Login") - }) - - Button(action: { - let sub = SubVerifierDetails(loginType: .web, - loginProvider: .twitch, - clientId: "p560duf74b2bidzqu6uo0b3ot7qaao", - verifier: "twitch-shubs", - redirectURL: "tdsdk://tdsdk/oauthCallback") - let tdsdk = CustomAuth(web3AuthClientId: "p560duf74b2bidzqu6uo0b3ot7qaao", aggregateVerifierType: .singleLogin, aggregateVerifier: "twitch-shubs", subVerifierDetails: [sub], network: .legacy(.TESTNET)) - Task { - do { - let loginData = try await tdsdk.triggerLogin().torusKey.finalKeyData! - print(loginData) - } catch { - print("Error occured") - } - } - }, label: { - Text("Twitch Login") - }) - - Button(action: { - let sub = SubVerifierDetails(loginType: .web, - loginProvider: .twitter, - clientId: "A7H8kkcmyFRlusJQ9dZiqBLraG2yWIsO", - verifier: "torus-auth0-twitter-lrc", - redirectURL: "tdsdk://tdsdk/oauthCallback", - jwtParams: ["domain": "torus-test.auth0.com"]) - - let tdsdk = CustomAuth(web3AuthClientId: "A7H8kkcmyFRlusJQ9dZiqBLraG2yWIsO", aggregateVerifierType: .singleLogin, aggregateVerifier: "torus-auth0-twitter-lrc", subVerifierDetails: [sub], network: .legacy(.TESTNET)) - Task { - do { - let loginData = try await tdsdk.triggerLogin().torusKey.finalKeyData! - print(loginData) - } catch { - print("Error occured") - } - } - }, label: { - Text("Twitter Login") - }) - - Button(action: { - let sub = SubVerifierDetails(loginType: .web, - loginProvider: .github, - clientId: "PC2a4tfNRvXbT48t89J5am0oFM21Nxff", - verifier: "torus-auth0-github-lrc", - redirectURL: "tdsdk://tdsdk/oauthCallback", - browserRedirectURL: "https://scripts.toruswallet.io/redirect.html", - jwtParams: ["domain": "torus-test.auth0.com"]) - - let tdsdk = CustomAuth(web3AuthClientId: "PC2a4tfNRvXbT48t89J5am0oFM21Nxff", aggregateVerifierType: .singleLogin, aggregateVerifier: "torus-auth0-github-lrc", subVerifierDetails: [sub], network: .legacy(.TESTNET)) - Task { - do { - let loginData = try await tdsdk.triggerLogin().torusKey.finalKeyData! - print(loginData) - } catch { - print("Error occured") - } - } - }, label: { - Text("Github Login") - }) - - Button(action: { - let sub = SubVerifierDetails(loginType: .web, - loginProvider: .linkedin, - clientId: "59YxSgx79Vl3Wi7tQUBqQTRTxWroTuoc", - verifier: "torus-auth0-linkedin-lrc", - redirectURL: "tdsdk://tdsdk/oauthCallback", - jwtParams: ["domain": "torus-test.auth0.com"]) - - let tdsdk = CustomAuth(web3AuthClientId: "59YxSgx79Vl3Wi7tQUBqQTRTxWroTuoc", aggregateVerifierType: .singleLogin, aggregateVerifier: "torus-auth0-linkedin-lrc", subVerifierDetails: [sub], network: .legacy(.TESTNET)) - Task { - do { - let loginData = try await tdsdk.triggerLogin().torusKey.finalKeyData! - print(loginData) - } catch { - print("Error occured") - } - } - }, label: { - Text("Linkedin Login") - }) - - Button(action: { - let sub = SubVerifierDetails(loginType: .web, - loginProvider: .apple, - clientId: "m1Q0gvDfOyZsJCZ3cucSQEe9XMvl9d9L", - verifier: "torus-auth0-apple-lrc", - redirectURL: "tdsdk://tdsdk/oauthCallback", - jwtParams: ["domain": "torus-test.auth0.com"]) - - let tdsdk = CustomAuth(web3AuthClientId: "m1Q0gvDfOyZsJCZ3cucSQEe9XMvl9d9L", aggregateVerifierType: .singleLogin, aggregateVerifier: "torus-auth0-apple-lrc", subVerifierDetails: [sub], network: .legacy(.TESTNET)) - Task { - do { - let loginData = try await tdsdk.triggerLogin().torusKey.finalKeyData! - print(loginData) - } catch { - print("Error occured") - } - } - }, label: { - Text("Apple Login") - }) - // } - - // Group { - Button(action: { - let sub = SubVerifierDetails(loginType: .web, - loginProvider: .jwt, - clientId: "P7PJuBCXIHP41lcyty0NEb7Lgf7Zme8Q", - verifier: "torus-auth0-email-passwordless", - redirectURL: "tdsdk://tdsdk/oauthCallback", - jwtParams: ["domain": "torus-test.auth0.com", "verifier_id_field": "name"]) - - let tdsdk = CustomAuth(web3AuthClientId: "P7PJuBCXIHP41lcyty0NEb7Lgf7Zme8Q", aggregateVerifierType: .singleLogin, aggregateVerifier: "torus-auth0-email-passwordless", subVerifierDetails: [sub], network: .legacy(.TESTNET)) - Task { - do { - let loginData = try await tdsdk.triggerLogin().torusKey.finalKeyData! - print(loginData) - } catch { - print("Error occured") - } - } - }, label: { - Text("Email-password Login") - }) - - Button(action: { - let sub = SubVerifierDetails(loginType: .web, - loginProvider: .kakao, - clientId: "wpkcc7alGJjEgjaL6q5AWRqgRWHFsdTL", - verifier: "torus-auth0-kakao-lrc", - redirectURL: "tdsdk://tdsdk/oauthCallback", - jwtParams: ["domain": "torus-test.auth0.com"]) - - let tdsdk = CustomAuth(web3AuthClientId: "wpkcc7alGJjEgjaL6q5AWRqgRWHFsdTL", aggregateVerifierType: .singleLogin, aggregateVerifier: "torus-auth0-kakao-lrc", subVerifierDetails: [sub], network: .legacy(.TESTNET)) - Task { - do { - let loginData = try await tdsdk.triggerLogin().torusKey.finalKeyData! - print(loginData) - } catch { - print("Error occured") - } - } - }, label: { - Text("Kakao Login") - }) - - Button(action: { - let sub = SubVerifierDetails(loginType: .web, - loginProvider: .apple, - clientId: "dhFGlWQMoACOI5oS5A1jFglp772OAWr1", - verifier: "torus-auth0-weibo-lrc", - redirectURL: "tdsdk://tdsdk/oauthCallback", - jwtParams: ["domain": "torus-test.auth0.com"]) - - let tdsdk = CustomAuth(web3AuthClientId: "dhFGlWQMoACOI5oS5A1jFglp772OAWr1", aggregateVerifierType: .singleLogin, aggregateVerifier: "torus-auth0-weibo-lrc", subVerifierDetails: [sub], network: .legacy(.TESTNET)) - Task { - do { - let loginData = try await tdsdk.triggerLogin().torusKey.finalKeyData! - print(loginData) - } catch { - print("Error occured") - } - } - }, label: { - Text("Weibo Login") - }) - - Button(action: { - let sub = SubVerifierDetails(loginType: .web, - loginProvider: .wechat, - clientId: "cewDD3i6F1vtHeV1KIbaxUZ8vJQjJZ8V", - verifier: "torus-auth0-wechat-lrc", - redirectURL: "tdsdk://tdsdk/oauthCallback", - jwtParams: ["domain": "torus-test.auth0.com"]) - - let tdsdk = CustomAuth(web3AuthClientId: "cewDD3i6F1vtHeV1KIbaxUZ8vJQjJZ8V", aggregateVerifierType: .singleLogin, aggregateVerifier: "torus-auth0-wechat-lrc", subVerifierDetails: [sub], network: .legacy(.TESTNET)) - Task { - do { - let loginData = try await tdsdk.triggerLogin().torusKey.finalKeyData! - print(loginData) - } catch { - print("Error occured") - } - } - }, label: { - Text("Wechat Login") - }) + VStack { + Button(action: { + Task { + do { + let sub = SingleLoginParams(typeOfLogin: .google, verifier: "google-lrc", clientId: "221898609709-obfn3p63741l5333093430j3qeiinaa8.apps.googleusercontent.com", redirectURL: "https://scripts.toruswallet.io/redirect.html") + + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_DEVNET), enableOneKey: true, web3AuthClientId: "BAh0_c0G8U8GoMUIYDcX_f65fU_N9O0mWz6xM6RqBfaaAlYsTha8oOef7ifXPjd_bCTJdfWQemmrbY6KepC7XNA") + + let customAuth = try CustomAuth(config: customAuthArgs) + let torusLoginResponse = try await customAuth.triggerLogin(args: sub) + let encoded = try JSONEncoder().encode(torusLoginResponse) + debugPrint(String(data: encoded, encoding: .utf8)!) + } catch { + debugPrint(error) + } + } - // } - - Section(header: Text("Single ID verifier")) { - Button(action: { - let sub = SubVerifierDetails(loginType: .installed, - loginProvider: .google, - clientId: "238941746713-vfap8uumijal4ump28p9jd3lbe6onqt4.apps.googleusercontent.com", - verifier: "google-ios", - redirectURL: "com.googleusercontent.apps.238941746713-vfap8uumijal4ump28p9jd3lbe6onqt4:/oauthredirect") - let tdsdk = CustomAuth(web3AuthClientId: "238941746713-vfap8uumijal4ump28p9jd3lbe6onqt4.apps.googleusercontent.com", aggregateVerifierType: .singleIdVerifier, aggregateVerifier: "multigoogle-torus", subVerifierDetails: [sub], network: .legacy(.TESTNET)) - Task { - do { - let loginData = try await tdsdk.triggerLogin().torusKey.finalKeyData! - print(loginData) - } catch { - print("Error occured") - } - } - }, label: { - Text("Google Login - Deep link flow") - }) + }, label: { + Text("Google Login") + }) + + Button(action: { + Task { + do { + let sub = SingleLoginParams(typeOfLogin: .discord, verifier: "dhruv-discord", clientId: "1034724991972954172", redirectURL: "https://scripts.toruswallet.io/redirect.html") + + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "BHgArYmWwSeq21czpcarYh0EVq2WWOzflX-NTK-tY1-1pauPzHKRRLgpABkmYiIV_og9jAvoIxQ8L3Smrwe04Lw") + + let customAuth = try CustomAuth(config: customAuthArgs) + let torusLoginResponse = try await customAuth.triggerLogin(args: sub) + let encoded = try JSONEncoder().encode(torusLoginResponse) + print(String(data: encoded, encoding: .utf8)!) + } catch { + print(error) + } + } - - }.navigationBarTitle(Text("DirectAuth app")) + }, label: { + Text("Discord Login") + }) + + + Button(action: { + Task { + do { + let sub = SingleLoginParams(typeOfLogin: .facebook, verifier: "w3a-facebook-demo", + clientId: "342380202252650", + redirectURL: "https://scripts.toruswallet.io/redirect.html") + + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + + let customAuth = try CustomAuth(config: customAuthArgs) + let torusLoginResponse = try await customAuth.triggerLogin(args: sub) + let encoded = try JSONEncoder().encode(torusLoginResponse) + debugPrint(String(data: encoded, encoding: .utf8)!) + } catch { + debugPrint(error) + } + + } + }, label: { + Text("Facebook Login") + }) + + Button(action: { + let sub = SubVerifierDetails(typeOfLogin: .reddit, + verifier: "reddit-shubs", clientId: "rXIp6g2y3h1wqg", + redirectURL: "tdsdk://tdsdk/oauthCallback") + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + Task { + do { + let customAuth = try CustomAuth(config: customAuthArgs) + let torusLoginResponse = try await customAuth.triggerLogin(args: sub) + let encoded = try JSONEncoder().encode(torusLoginResponse) + print(String(data: encoded, encoding: .utf8)!) + } catch { + print(error) + } + } + }, label: { + Text("Reddit Login") + }) + + Button(action: { + let sub = SubVerifierDetails(typeOfLogin: .twitch, + verifier: "twitch-shubs", clientId: "p560duf74b2bidzqu6uo0b3ot7qaao", + redirectURL: "tdsdk://tdsdk/oauthCallback") + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + Task { + do { + let customAuth = try CustomAuth(config: customAuthArgs) + let torusLoginResponse = try await customAuth.triggerLogin(args: sub) + let encoded = try JSONEncoder().encode(torusLoginResponse) + print(String(data: encoded, encoding: .utf8)!) + } catch { + print(error) + } + } + }, label: { + Text("Twitch Login") + }) + + Button(action: { + let sub = SubVerifierDetails(typeOfLogin: .apple, + verifier: "w3a-auth0-demo", clientId: "hUVVf4SEsZT7syOiL0gLU9hFEtm2gQ6O", + redirectURL: "tdsdk://tdsdk/oauthCallback", jwtParams: Auth0ClientOptions(domain: "web3auth.au.auth0.com")) + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + Task { + do { + let customAuth = try CustomAuth(config: customAuthArgs) + let torusLoginResponse = try await customAuth.triggerLogin(args: sub) + let encoded = try JSONEncoder().encode(torusLoginResponse) + print(String(data: encoded, encoding: .utf8)!) + } catch { + print(error) + } + } + }, label: { + Text("Apple Login") + }) + + Button(action: { + let sub = SubVerifierDetails(typeOfLogin: .jwt, + verifier: "w3a-auth0-demo", clientId: "hUVVf4SEsZT7syOiL0gLU9hFEtm2gQ6O", + redirectURL: "tdsdk://tdsdk/oauthCallback", jwtParams: Auth0ClientOptions(connection: "github", domain: "web3auth.au.auth0.com", verifierIdField: "sub")) + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + Task { + do { + let customAuth = try CustomAuth(config: customAuthArgs) + let torusLoginResponse = try await customAuth.triggerLogin(args: sub) + let encoded = try JSONEncoder().encode(torusLoginResponse) + print(String(data: encoded, encoding: .utf8)!) + } catch { + print(error) + } + } + }, label: { + Text("JWT Login") + }) + + Button(action: { + let sub = SubVerifierDetails(typeOfLogin: .email_password, + verifier: "torus-auth0-email-password", clientId: "sqKRBVSdwa4WLkaq419U7Bamlh5vK1H7", + redirectURL: "tdsdk://tdsdk/oauthCallback", jwtParams: Auth0ClientOptions( + connection: "Username-Password-Authentication", + domain: "torus-test.auth0.com", + verifierIdField: "name")) + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + Task { + do { + let customAuth = try CustomAuth(config: customAuthArgs) + let torusLoginResponse = try await customAuth.triggerLogin(args: sub) + let encoded = try JSONEncoder().encode(torusLoginResponse) + print(String(data: encoded, encoding: .utf8)!) + } catch { + print(error) + } + } + }, label: { + Text("Email Password") + }) + } } } - -struct SafariView: UIViewControllerRepresentable { - typealias UIViewControllerType = SFSafariViewController - - var url: URL? - - func makeUIViewController(context: UIViewControllerRepresentableContext) -> SFSafariViewController { - return SFSafariViewController(url: url!) - } - - func updateUIViewController(_ safariViewController: SFSafariViewController, context: UIViewControllerRepresentableContext) { - } -} - -struct ContentView_Previews: PreviewProvider { - static var previews: some View { - ContentView() - } -} diff --git a/CustomAuthDemo/CustomAuthDemo/CustomAuthDemo.swift b/CustomAuthDemo/CustomAuthDemo/CustomAuthDemo.swift new file mode 100644 index 0000000..feb4574 --- /dev/null +++ b/CustomAuthDemo/CustomAuthDemo/CustomAuthDemo.swift @@ -0,0 +1,12 @@ +import SwiftUI + +@main +struct CustomAuthDemo: App { + var body: some Scene { + WindowGroup { + NavigationStack { + ContentView() + } + } + } +} diff --git a/CustomAuthDemo/CustomAuthDemo/Info.plist b/CustomAuthDemo/CustomAuthDemo/Info.plist index 46d87e4..4152026 100644 --- a/CustomAuthDemo/CustomAuthDemo/Info.plist +++ b/CustomAuthDemo/CustomAuthDemo/Info.plist @@ -20,13 +20,12 @@ CFBundleTypeRole - Editor + Viewer + CFBundleURLName + tdsdk CFBundleURLSchemes - tdsdk-swift - tdsdk - com.torus.CustomAuthDemo - com.googleusercontent.apps.238941746713-vfap8uumijal4ump28p9jd3lbe6onqt4 + tdsdk://tdsdk/oauthCallback @@ -45,8 +44,6 @@ UISceneConfigurationName Default Configuration - UISceneDelegateClassName - $(PRODUCT_MODULE_NAME).SceneDelegate diff --git a/CustomAuthDemo/CustomAuthDemo/SceneDelegate.swift b/CustomAuthDemo/CustomAuthDemo/SceneDelegate.swift deleted file mode 100644 index e0f970e..0000000 --- a/CustomAuthDemo/CustomAuthDemo/SceneDelegate.swift +++ /dev/null @@ -1,84 +0,0 @@ -// SceneDelegate.swift -// CustomAuthDemo -// -// Created by Shubham on 24/4/20. -// Copyright © 2020 Shubham. All rights reserved. -// - -import UIKit -import SwiftUI -import CustomAuth - -class SceneDelegate: UIResponder, UIWindowSceneDelegate { - - var window: UIWindow? - - // Handle Universal logins - func scene(_ scene: UIScene, continue userActivity: NSUserActivity) { - guard userActivity.activityType == NSUserActivityTypeBrowsingWeb, - let urlToOpen = userActivity.webpageURL else { - return - } - CustomAuth.handle(url: urlToOpen) - } - - // Hanlde Deep linkings - func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { - guard let url = URLContexts.first?.url else { - return - } - CustomAuth.handle(url: url) - } - - func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { - // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. - // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. - // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). - - // Create the SwiftUI view that provides the window contents. - let contentView = ContentView() - - // Use a UIHostingController as window root view controller. - if let windowScene = scene as? UIWindowScene { - let window = UIWindow(windowScene: windowScene) - window.rootViewController = UIHostingController(rootView: contentView) - self.window = window - window.makeKeyAndVisible() - } - } - - func sceneDidDisconnect(_ scene: UIScene) { - // Called as the scene is being released by the system. - // This occurs shortly after the scene enters the background, or when its session is discarded. - // Release any resources associated with this scene that can be re-created the next time the scene connects. - // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead). - } - - func sceneDidBecomeActive(_ scene: UIScene) { - // Called when the scene has moved from an inactive state to an active state. - // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. - } - - func sceneWillResignActive(_ scene: UIScene) { - // Called when the scene will move from an active state to an inactive state. - // This may occur due to temporary interruptions (ex. an incoming phone call). - } - - func sceneWillEnterForeground(_ scene: UIScene) { - // Called as the scene transitions from the background to the foreground. - // Use this method to undo the changes made on entering the background. - } - - func sceneDidEnterBackground(_ scene: UIScene) { - // Called as the scene transitions from the foreground to the background. - // Use this method to save data, release shared resources, and store enough scene-specific state information - // to restore the scene back to its current state. - } - -} - -struct SceneDelegate_Previews: PreviewProvider { - static var previews: some View { - /*@START_MENU_TOKEN@*/Text("Hello, World!")/*@END_MENU_TOKEN@*/ - } -} diff --git a/CustomAuthDemo/CustomAuthDemoTests/CustomAuthDemoTests.swift b/CustomAuthDemo/CustomAuthDemoTests/CustomAuthDemoTests.swift index e90dfa1..2a1647c 100644 --- a/CustomAuthDemo/CustomAuthDemoTests/CustomAuthDemoTests.swift +++ b/CustomAuthDemo/CustomAuthDemoTests/CustomAuthDemoTests.swift @@ -1,33 +1,19 @@ -// -// CustomAuthDemoTests.swift -// CustomAuthDemoTests -// -// Created by Shubham on 24/4/20. -// Copyright © 2020 Shubham. All rights reserved. -// - import XCTest -@testable import CustomAuthDemo +import CustomAuthDemo class CustomAuthDemoTests: XCTestCase { override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation of each test method in the class. } override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation of each test method in the class. } func testExample() throws { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct results. } func testPerformanceExample() throws { - // This is an example of a performance test case. self.measure { - // Put the code you want to measure the time of here. } } diff --git a/CustomAuthDemo/CustomAuthDemoUITests/CustomAuthDemoUITests.swift b/CustomAuthDemo/CustomAuthDemoUITests/CustomAuthDemoUITests.swift index cd64582..3d48c4c 100644 --- a/CustomAuthDemo/CustomAuthDemoUITests/CustomAuthDemoUITests.swift +++ b/CustomAuthDemo/CustomAuthDemoUITests/CustomAuthDemoUITests.swift @@ -1,43 +1,22 @@ -// -// CustomAuthDemoUITests.swift -// CustomAuthDemoUITests -// -// Created by Shubham on 24/4/20. -// Copyright © 2020 Shubham. All rights reserved. -// - import XCTest +import CustomAuthDemo class CustomAuthDemoUITests: XCTestCase { - + override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation of each test method in the class. - - // In UI tests it is usually best to stop immediately when a failure occurs. continueAfterFailure = false - - // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. } override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation of each test method in the class. } func testExample() throws { - // UI tests must launch the application that they test. - let app = XCUIApplication() - app.launch() - // Use recording to get started writing UI tests. - // Use XCTAssert and related functions to verify your tests produce the correct results. } func testLaunchPerformance() throws { - if #available(macOS 10.15, iOS 13.0, tvOS 13.0, *) { - // This measures how long it takes to launch your application. - measure(metrics: [XCTOSSignpostMetric.applicationLaunch]) { + measure(metrics: [XCTApplicationLaunchMetric.init()]) { XCUIApplication().launch() } - } } } diff --git a/Development.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Development.xcworkspace/xcshareddata/swiftpm/Package.resolved index 3a07809..9efd57e 100644 --- a/Development.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Development.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,97 +1,15 @@ { - "object": { - "pins": [ - { - "package": "AnyCodable", - "repositoryURL": "https://github.com/Flight-School/AnyCodable", - "state": { - "branch": null, - "revision": "862808b2070cd908cb04f9aafe7de83d35f81b05", - "version": "0.6.7" - } - }, - { - "package": "BigInt", - "repositoryURL": "https://github.com/attaswift/BigInt.git", - "state": { - "branch": null, - "revision": "0ed110f7555c34ff468e72e1686e59721f2b0da6", - "version": "5.3.0" - } - }, - { - "package": "CryptoSwift", - "repositoryURL": "https://github.com/krzyzanowskim/CryptoSwift", - "state": { - "branch": null, - "revision": "7892a123f7e8d0fe62f9f03728b17bbd4f94df5c", - "version": "1.8.1" - } - }, - { - "package": "curvelib.swift", - "repositoryURL": "https://github.com/tkey/curvelib.swift", - "state": { - "branch": null, - "revision": "7dad3bf1793de263f83406c08c18c9316abf082f", - "version": "0.1.2" - } - }, - { - "package": "FetchNodeDetails", - "repositoryURL": "https://github.com/torusresearch/fetch-node-details-swift", - "state": { - "branch": null, - "revision": "d591af500f32ce3c88d04af9bb74d746585acfea", - "version": "5.1.0" - } - }, - { - "package": "jwt-kit", - "repositoryURL": "https://github.com/vapor/jwt-kit.git", - "state": { - "branch": null, - "revision": "e05513b5aec24f88012b6e3034115b6bc915356a", - "version": "4.13.2" - } - }, - { - "package": "JWTDecode", - "repositoryURL": "https://github.com/auth0/JWTDecode.swift.git", - "state": { - "branch": null, - "revision": "58af7278797871e460d79496621b3e5366b865b2", - "version": "3.1.0" - } - }, - { - "package": "PromiseKit", - "repositoryURL": "https://github.com/mxcl/PromiseKit", - "state": { - "branch": null, - "revision": "cb70b070cde06837cd10a1febdf6105c1a3bb348", - "version": "8.1.1" - } - }, - { - "package": "swift-crypto", - "repositoryURL": "https://github.com/apple/swift-crypto.git", - "state": { - "branch": null, - "revision": "f0525da24dc3c6cbb2b6b338b65042bc91cbc4bb", - "version": "3.3.0" - } - }, - { - "package": "TorusUtils", - "repositoryURL": "https://github.com/torusresearch/torus-utils-swift.git", - "state": { - "branch": null, - "revision": "04c62fd5f73f21bd01b7c07e08f6135db26c5940", - "version": "8.0.0" - } + "originHash" : "15db2e52658433a7d473400cc03eb7d9196e5e1ee7c0636fcf9c95b35e7c0bf1", + "pins" : [ + { + "identity" : "promisekit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/mxcl/PromiseKit", + "state" : { + "revision" : "cb70b070cde06837cd10a1febdf6105c1a3bb348", + "version" : "8.1.1" } - ] - }, - "version": 1 + } + ], + "version" : 3 } diff --git a/Notice.md b/Notice.md deleted file mode 100644 index ea74098..0000000 --- a/Notice.md +++ /dev/null @@ -1,4 +0,0 @@ -Following code was borrowed/inspired from web3swift library (Apache 2.0 license) -- SFSafariViewControoler implementation -- Dictionary extension for splitting string -- String extension diff --git a/Package.resolved b/Package.resolved index 6675452..c12425b 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,79 +1,68 @@ { - "object": { - "pins": [ - { - "package": "AnyCodable", - "repositoryURL": "https://github.com/Flight-School/AnyCodable", - "state": { - "branch": null, - "revision": "862808b2070cd908cb04f9aafe7de83d35f81b05", - "version": "0.6.7" - } - }, - { - "package": "BigInt", - "repositoryURL": "https://github.com/attaswift/BigInt", - "state": { - "branch": null, - "revision": "0ed110f7555c34ff468e72e1686e59721f2b0da6", - "version": "5.3.0" - } - }, - { - "package": "curvelib.swift", - "repositoryURL": "https://github.com/tkey/curvelib.swift", - "state": { - "branch": null, - "revision": "9f88bd5e56d1df443a908f7a7e81ae4f4d9170ea", - "version": "1.0.1" - } - }, - { - "package": "FetchNodeDetails", - "repositoryURL": "https://github.com/torusresearch/fetch-node-details-swift.git", - "state": { - "branch": null, - "revision": "f085d3d85a4f36b57cfef8f0871ac8df1dd4f6f1", - "version": "6.0.1" - } - }, - { - "package": "jwt-kit", - "repositoryURL": "https://github.com/vapor/jwt-kit.git", - "state": { - "branch": null, - "revision": "9e929d925434b91857661bcd455d1bd53f00bf22", - "version": "4.13.0" - } - }, - { - "package": "JWTDecode", - "repositoryURL": "https://github.com/auth0/JWTDecode.swift.git", - "state": { - "branch": null, - "revision": "58af7278797871e460d79496621b3e5366b865b2", - "version": "3.1.0" - } - }, - { - "package": "swift-crypto", - "repositoryURL": "https://github.com/apple/swift-crypto.git", - "state": { - "branch": null, - "revision": "33a20e650c33f6d72d822d558333f2085effa3dc", - "version": "2.5.0" - } - }, - { - "package": "TorusUtils", - "repositoryURL": "https://github.com/torusresearch/torus-utils-swift.git", - "state": { - "branch": null, - "revision": "f20a23bb11b3c144650ff17048f94068f410ceae", - "version": "8.1.0" - } + "pins" : [ + { + "identity" : "bigint", + "kind" : "remoteSourceControl", + "location" : "https://github.com/attaswift/BigInt", + "state" : { + "revision" : "0ed110f7555c34ff468e72e1686e59721f2b0da6", + "version" : "5.3.0" } - ] - }, - "version": 1 + }, + { + "identity" : "curvelib.swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/tkey/curvelib.swift", + "state" : { + "revision" : "9f88bd5e56d1df443a908f7a7e81ae4f4d9170ea", + "version" : "1.0.1" + } + }, + { + "identity" : "fetch-node-details-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/torusresearch/fetch-node-details-swift.git", + "state" : { + "revision" : "4bd96c33ba8d02d9e27190c5c7cedf09cfdfd656", + "version" : "6.0.3" + } + }, + { + "identity" : "jwt-kit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/vapor/jwt-kit.git", + "state" : { + "revision" : "9e929d925434b91857661bcd455d1bd53f00bf22", + "version" : "4.13.0" + } + }, + { + "identity" : "jwtdecode.swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/auth0/JWTDecode.swift.git", + "state" : { + "revision" : "58af7278797871e460d79496621b3e5366b865b2", + "version" : "3.1.0" + } + }, + { + "identity" : "swift-crypto", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-crypto.git", + "state" : { + "revision" : "33a20e650c33f6d72d822d558333f2085effa3dc", + "version" : "2.5.0" + } + }, + { + "identity" : "torus-utils-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/torusresearch/torus-utils-swift.git", + "state" : { + "revision" : "303dc2cf41db7c10f769855edad0e717ced2d554", + "version" : "9.0.0" + } + } + ], + "version" : 2 } diff --git a/Package.swift b/Package.swift index 96c1926..00a2b64 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.5 +// swift-tools-version:5.7 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription @@ -6,7 +6,7 @@ import PackageDescription let package = Package( name: "CustomAuth", platforms: [ - .iOS(.v13) + .iOS(.v13), .macOS(.v11) ], products: [ .library( @@ -14,15 +14,15 @@ let package = Package( targets: ["CustomAuth"]) ], dependencies: [ - .package(url: "https://github.com/torusresearch/torus-utils-swift.git", from: "8.1.0"), - .package(name: "jwt-kit", url: "https://github.com/vapor/jwt-kit.git", from: "4.13.0"), - .package(name: "JWTDecode", url: "https://github.com/auth0/JWTDecode.swift.git", from: "3.1.0"), - .package(url: "https://github.com/tkey/curvelib.swift", from: "1.0.0"), + .package(url: "https://github.com/torusresearch/torus-utils-swift.git", from: "9.0.0"), + .package(url: "https://github.com/auth0/JWTDecode.swift.git", from: "3.1.0"), + // NB: jwt-kit may only be a test dependency or it will break cocoapods support + .package(url: "https://github.com/vapor/jwt-kit.git", from: "4.13.0"), ], targets: [ .target( name: "CustomAuth", - dependencies: ["JWTDecode", .product(name: "curveSecp256k1", package: "curvelib.swift"), .product(name: "TorusUtils", package: "torus-utils-swift")]), + dependencies: [.product(name: "JWTDecode", package: "JWTDecode.swift"), .product(name: "TorusUtils", package: "torus-utils-swift")]), .testTarget( name: "CustomAuthTests", dependencies: ["CustomAuth", .product(name: "JWTKit", package: "jwt-kit")]) diff --git a/README.md b/README.md index 37f6e38..5ce3818 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,6 @@ an example of how to access keys via the SDK via Google. You can read more about interactions with the Torus Network [here](https://medium.com/toruslabs/key-assignments-resolution-and-retrieval-afb984500612). -## Features - -- All API's return Promises (mxcl/PromiseKit). You can import - "yannickl/AwaitKit" to convert APIs to async/await format. - ## 🩹 Examples Checkout the example of `CustomAuth iOS/Swift SDK` in our @@ -32,7 +27,7 @@ import PackageDescription let package = Package( name: "CustomAuth", dependencies: [ - .package(name: "CustomAuth", url: "https://github.com/torusresearch/customauth-swift-sdk", from: "2.4.0")) + .package(name: "CustomAuth", url: "https://github.com/torusresearch/customauth-swift-sdk", from: "11.0.0")) ] ) ``` @@ -40,41 +35,36 @@ let package = Package( #### Cocoapods ```ruby -pod 'CustomAuth', '~> 5.0.0' +pod 'CustomAuth', '~> 11.0.0' ``` -#### Manual import or other packages - -If you require a package manager other than SPM or Cocoapods, do reach out to -hello@tor.us or alternatively clone the repo manually and import as a framework -in your project - -### 2. Initialization +### 2. Initialization and Login -Initalize the SDK depending on the login you require. The example below does so -for a single google login. `redirectURL` refers to a url for the login flow to -redirect into your app, it should have a scheme that is registered by your app, -for example `com.mycompany.myapp://redirect`. `browserRedirectURL` refers to a -page that the browser should use in the login flow, it should have a http or -https scheme. +Initalize the SDK depending and then you can use the login you require. ```swift import CustomAuth -let sub = SubVerifierDetails(loginType: .installed, // default .web - loginProvider: .google, - clientId: "", - verifierName: "", - redirectURL: "", - browserRedirectURL: "") +let config = CustomAuthArgs(urlScheme: ", enableOneKey: true, web3AuthClientId: "your-web3auth-client-id") + + +let customAuth = try CustomAuth(config: config) + +``` + +The example login below does so for a single google login. `redirectURL` refers to url for the login flow to +redirect back to your app, it should use the scheme known to your application. -let tdsdk = CustomAuth(aggregateVerifierType: "", aggregateVerifierName: "", subVerifierDetails: [sub], network: ) -// controller is used to present a SFSafariViewController. -tdsdk.triggerLogin(controller: ?, browserType: , modalPresentationStyle: ).done{ data in - print("private key rebuild", data) -}.catch{ err in - print(err) +``` +let sub = SingleLoginParams(typeOfLogin: .google, verifier: "", clientId: "", redirectURL: ") { - guard let url = URLContexts.first?.url else { - return - } - CustomAuth.handle(url: url) -} -``` - -- For Storyboard, implement the following in your app AppDelegate: - -```swift -func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { - if url.host == "my-wallet-app" { - CustomAuth.handle(url: url) - } - return true -} -``` - -#### Universal Links - -Universal Links allow your users to intelligently follow links to content inside -your app or to your website. Checkout -[Documentation](https://developer.apple.com/ios/universal-links/) for -implementation. - -- For Swift UI, - -```swift -func scene(_ scene: UIScene, continue userActivity: NSUserActivity) { - guard userActivity.activityType == NSUserActivityTypeBrowsingWeb, let urlToOpen = userActivity.webpageURL else { - return - } - CustomAuth.handle(url: urlToOpen) -} -``` - -- For Storyboard, - -```swift -func application(_ application: UIApplication, continue userActivity: UIUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool -{ - // Get URL components from the incoming user activity - guard userActivity.activityType == NSUserActivityTypeBrowsingWeb, - let incomingURL = userActivity.webpageURL, - let components = NSURLComponents(url: incomingURL, resolvingAgainstBaseURL: true) else { - return false - } - CustomAuth.handle(url: incomingURL) -} - -``` - -After this you're good to go, reach out to hello@tor.us to get your verifier -spun up on the testnet today! +You can setup the redirectURL using URL Schemes and adding the relevant URLScheme to URL Types for your project. This package makes use of ASWebAuthenticationSession underneath and is done in such a way that it can provide its' own presentation context if necessary. ## Requirements - Swift 5 -## Using CustomAuthFactory - -The `CASDKFactoryProtocol` provides a way to modify the mechanism of discovering -torus nodes in `FetchNodeDetails` and performing key retrieval in `TorusUtils`, -which can be useful in scenarios such as mocking or advanced customization. -Developers who want to use this mechanism should implement -`CASDKFactoryProtocol` in Sources/CustomAuth/CustomAuth.swift, and then pass the -instance into the `init` of `CustomAuth`, for example: - -```swift -let tdsdk = CustomAuth( - aggregateVerifierType: "", - aggregateVerifierName: "", - subVerifierDetails: [sub], - factory: customFactory, - network: myNetworkm - loglevel: myLoglevel -) -``` - ## 💬 Troubleshooting and Discussions - Have a look at our diff --git a/Sources/CustomAuth/Common/AggregateVerifierParams/AggregateLoginParams.swift b/Sources/CustomAuth/Common/AggregateVerifierParams/AggregateLoginParams.swift new file mode 100644 index 0000000..2e64f30 --- /dev/null +++ b/Sources/CustomAuth/Common/AggregateVerifierParams/AggregateLoginParams.swift @@ -0,0 +1,13 @@ +import Foundation + +public class AggregateLoginParams: Codable { + public let aggregateVerifierType: AggregateVerifierType + public let verifierIdentifier: String + public let subVerifierDetailsArray: [SingleLoginParams] + + public init(aggregateVerifierType: AggregateVerifierType, verifierIdentifier: String, subVerifierDetailsArray: [SingleLoginParams]) { + self.aggregateVerifierType = aggregateVerifierType + self.verifierIdentifier = verifierIdentifier + self.subVerifierDetailsArray = subVerifierDetailsArray + } +} diff --git a/Sources/CustomAuth/Common/AggregateVerifierParams/AggregateVerifierType.swift b/Sources/CustomAuth/Common/AggregateVerifierParams/AggregateVerifierType.swift new file mode 100644 index 0000000..cc6fedd --- /dev/null +++ b/Sources/CustomAuth/Common/AggregateVerifierParams/AggregateVerifierType.swift @@ -0,0 +1,5 @@ +import Foundation + +public enum AggregateVerifierType: String, Codable, Equatable, Hashable { + case single_id_verifier +} diff --git a/Sources/CustomAuth/Common/HashParams.swift b/Sources/CustomAuth/Common/HashParams.swift new file mode 100644 index 0000000..41724b6 --- /dev/null +++ b/Sources/CustomAuth/Common/HashParams.swift @@ -0,0 +1,11 @@ +import Foundation + +public class HashParams: Codable { + public let access_token: String + public let id_token: String? + + public init(access_token: String, id_token: String? = nil) { + self.access_token = access_token + self.id_token = id_token + } +} diff --git a/Sources/CustomAuth/Common/LoginParams/Auth0ClientOptions.swift b/Sources/CustomAuth/Common/LoginParams/Auth0ClientOptions.swift new file mode 100644 index 0000000..4821b13 --- /dev/null +++ b/Sources/CustomAuth/Common/LoginParams/Auth0ClientOptions.swift @@ -0,0 +1,61 @@ +import Foundation + +public class Auth0ClientOptions: BaseLoginOptions { + public let domain: String? + public let client_id: String? + public let redirect_url: String? + public let leeway: Int? + public let verifierIdField: String? + public let isVerifierIdCaseSensitive: String + public let id_token: String? + public let access_token: String? + public let user_info_route: String? + public let login_hint: String? + + private enum CodingKeys: CodingKey { + case domain, + client_id, + redirect_url, + leeway, + verifierIdField, + isVerifierIdCaseSensitive, + id_token, + access_token, + user_info_route, + login_hint + } + + public init(display: String? = nil, prompt: String? = nil, max_age: Int? = nil, ui_locales: String? = nil, id_token_hint: String? = nil, arc_values: String? = nil, scope: String? = nil, audience: String? = nil, connection: String? = nil, domain: String? = nil, client_id: String? = nil, redirect_url: String? = nil, leeway: Int? = nil, verifierIdField: String? = nil, isVerifierIdCaseSensitive: Bool = false, id_token: String? = nil, access_token: String? = nil, user_info_route: String? = nil, login_hint: String? = nil) { + self.domain = domain + self.redirect_url = redirect_url + self.leeway = leeway + self.verifierIdField = verifierIdField + self.isVerifierIdCaseSensitive = isVerifierIdCaseSensitive ? "true" : "false" + self.id_token = id_token + self.access_token = access_token + self.user_info_route = user_info_route + self.client_id = client_id + self.login_hint = login_hint + + super.init(display: display, prompt: prompt, max_age: max_age, ui_locales: ui_locales, id_token_hint: id_token_hint, arc_values: arc_values, scope: scope, audience: audience, connection: connection) + } + + required init(from decoder: any Decoder) throws { + fatalError("init(from:) has not been implemented") + } + + public override func encode(to encoder: any Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(self.domain, forKey: .domain) + try container.encodeIfPresent(self.redirect_url, forKey: .redirect_url) + try container.encodeIfPresent(self.leeway, forKey: .leeway) + try container.encodeIfPresent(self.verifierIdField, forKey: .verifierIdField) + try container.encodeIfPresent(self.isVerifierIdCaseSensitive, forKey: .isVerifierIdCaseSensitive) + try container.encodeIfPresent(self.user_info_route, forKey: .user_info_route) + try container.encodeIfPresent(self.access_token, forKey: .access_token) + try container.encodeIfPresent(self.id_token, forKey: .id_token) + try container.encodeIfPresent(self.client_id, forKey: .client_id) + try container.encodeIfPresent(self.login_hint, forKey: .login_hint) + } +} diff --git a/Sources/CustomAuth/Common/LoginParams/Auth0JwtLoginType.swift b/Sources/CustomAuth/Common/LoginParams/Auth0JwtLoginType.swift new file mode 100644 index 0000000..121d4cf --- /dev/null +++ b/Sources/CustomAuth/Common/LoginParams/Auth0JwtLoginType.swift @@ -0,0 +1,12 @@ +import Foundation + +public enum Auth0JwtLoginType: String, Equatable, Hashable, Codable { + case apple + case github + case linkedin + case twitter + case weibo + case line + case email_password + case passwordless +} diff --git a/Sources/CustomAuth/Common/LoginParams/BaseLoginOptions.swift b/Sources/CustomAuth/Common/LoginParams/BaseLoginOptions.swift new file mode 100644 index 0000000..a718c63 --- /dev/null +++ b/Sources/CustomAuth/Common/LoginParams/BaseLoginOptions.swift @@ -0,0 +1,38 @@ +import Foundation + +public class BaseLoginOptions: Codable { + public let display: String? + public let prompt: String? + public let max_age: String? + public let ui_locales: String? + public let id_token_hint: String? + public let arc_values: String? + public let scope: String? + public let audience: String? + public let connection: String? + + public init(display: String? = nil, prompt: String? = nil, max_age: Int? = nil, ui_locales: String? = nil, id_token_hint: String? = nil, arc_values: String? = nil, scope: String? = nil, audience: String? = nil, connection: String? = nil) { + self.display = display + self.prompt = prompt + self.max_age = max_age != nil ? String(max_age!) : nil + self.ui_locales = ui_locales + self.id_token_hint = id_token_hint + self.arc_values = arc_values + self.scope = scope + self.audience = audience + self.connection = connection + } + + public func encode(to encoder: any Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(self.display, forKey: .display) + try container.encodeIfPresent(self.prompt, forKey: .prompt) + try container.encodeIfPresent(self.max_age, forKey: .max_age) + try container.encodeIfPresent(self.ui_locales, forKey: .ui_locales) + try container.encodeIfPresent(self.id_token_hint, forKey: .id_token_hint) + try container.encodeIfPresent(self.arc_values, forKey: .arc_values) + try container.encodeIfPresent(self.scope, forKey: .scope) + try container.encodeIfPresent(self.audience, forKey: .audience) + try container.encodeIfPresent(self.connection, forKey: .connection) + } +} diff --git a/Sources/CustomAuth/Common/LoginParams/HybridAggregateLoginParams.swift b/Sources/CustomAuth/Common/LoginParams/HybridAggregateLoginParams.swift new file mode 100644 index 0000000..5fe21fb --- /dev/null +++ b/Sources/CustomAuth/Common/LoginParams/HybridAggregateLoginParams.swift @@ -0,0 +1,11 @@ +import Foundation + +public class HybridAggregateLoginParams: Codable { + public let singleLogin: SingleLoginParams + public let aggregateLoginParams: AggregateLoginParams + + public init(singleLogin: SingleLoginParams, aggregateLoginParams: AggregateLoginParams) { + self.singleLogin = singleLogin + self.aggregateLoginParams = aggregateLoginParams + } +} diff --git a/Sources/CustomAuth/Common/LoginParams/LoginType.swift b/Sources/CustomAuth/Common/LoginParams/LoginType.swift new file mode 100644 index 0000000..d260882 --- /dev/null +++ b/Sources/CustomAuth/Common/LoginParams/LoginType.swift @@ -0,0 +1,17 @@ +import Foundation + +public enum LoginType: String, Equatable, Hashable, Codable { + case google + case facebook + case discord + case reddit + case twitch + case apple + case github + case linkedin + case twitter + case weibo + case line + case email_password + case passwordless +} diff --git a/Sources/CustomAuth/Common/LoginParams/SubVerifierDetails.swift b/Sources/CustomAuth/Common/LoginParams/SubVerifierDetails.swift new file mode 100644 index 0000000..d3c2aae --- /dev/null +++ b/Sources/CustomAuth/Common/LoginParams/SubVerifierDetails.swift @@ -0,0 +1,25 @@ +import Foundation + +public class SubVerifierDetails: Codable { + public let typeOfLogin: LoginType + public let verifier: String + public let clientId: String + public let redirectURL: String + public let jwtParams: Auth0ClientOptions? + public let hash: String? + public let queryParams: TorusGenericContainer? + public let customState: TorusGenericContainer? + + public init(typeOfLogin: LoginType, verifier: String, clientId: String, redirectURL: String, jwtParams: Auth0ClientOptions? = nil, hash: String? = nil, queryParams: TorusGenericContainer? = nil, customState: TorusGenericContainer? = nil) { + self.typeOfLogin = typeOfLogin + self.verifier = verifier + self.clientId = clientId + self.jwtParams = jwtParams + self.hash = hash + self.queryParams = queryParams + self.customState = customState + self.redirectURL = redirectURL + } +} + +public typealias SingleLoginParams = SubVerifierDetails diff --git a/Sources/CustomAuth/Common/LoginParams/TorusSubVerifierInfo.swift b/Sources/CustomAuth/Common/LoginParams/TorusSubVerifierInfo.swift new file mode 100644 index 0000000..74f9873 --- /dev/null +++ b/Sources/CustomAuth/Common/LoginParams/TorusSubVerifierInfo.swift @@ -0,0 +1,13 @@ +import Foundation + +public class TorusSubVerifierInfo: Codable { + public let verifier: String + public let idToken: String + public let extraVerifierParams: PassKeyExtraParams? + + public init(verifier: String, idToken: String, extraVerifierParams: PassKeyExtraParams? = nil) { + self.verifier = verifier + self.idToken = idToken + self.extraVerifierParams = extraVerifierParams + } +} diff --git a/Sources/CustomAuth/Common/LoginResponses/LoginWindowResponse.swift b/Sources/CustomAuth/Common/LoginResponses/LoginWindowResponse.swift new file mode 100644 index 0000000..b7d29ea --- /dev/null +++ b/Sources/CustomAuth/Common/LoginResponses/LoginWindowResponse.swift @@ -0,0 +1,19 @@ +import Foundation + +public class LoginWindowResponse: Codable { + public let accessToken: String? + public let idToken: String? + public let ref: String + public let extraParams: String? + public let extraParamsPassed: String? + public let state: TorusGenericContainer + + public init(accessToken: String? = nil, idToken: String? = nil, ref: String, extraParams: String? = nil, extraParamsPassed: String? = nil, state: TorusGenericContainer) { + self.accessToken = accessToken + self.idToken = idToken + self.ref = ref + self.extraParams = extraParams + self.extraParamsPassed = extraParamsPassed + self.state = state + } +} diff --git a/Sources/CustomAuth/Common/LoginResponses/TorusAggregateLoginResponse.swift b/Sources/CustomAuth/Common/LoginResponses/TorusAggregateLoginResponse.swift new file mode 100644 index 0000000..d051f10 --- /dev/null +++ b/Sources/CustomAuth/Common/LoginResponses/TorusAggregateLoginResponse.swift @@ -0,0 +1,12 @@ +import Foundation +import TorusUtils + +public class TorusAggregateLoginResponse: Codable { + public let torusAggregateVerifierResponse: [TorusAggregateVerifierResponse] + public let torusKey: TorusKey + + public init(torusAggregateVerifierResponse: [TorusAggregateVerifierResponse], torusKey: TorusKey) { + self.torusAggregateVerifierResponse = torusAggregateVerifierResponse + self.torusKey = torusKey + } +} diff --git a/Sources/CustomAuth/Common/LoginResponses/TorusHybridAggregateLoginResponse.swift b/Sources/CustomAuth/Common/LoginResponses/TorusHybridAggregateLoginResponse.swift new file mode 100644 index 0000000..80eb821 --- /dev/null +++ b/Sources/CustomAuth/Common/LoginResponses/TorusHybridAggregateLoginResponse.swift @@ -0,0 +1,12 @@ +import Foundation +import TorusUtils + +public class TorusHybridAggregateLoginResponse: Codable { + public let singleLogin: TorusAggregateLoginResponse + public let aggregateLogins: [TorusKey] + + public init(singleLogin: TorusAggregateLoginResponse, aggregateLogins: [TorusKey]) { + self.singleLogin = singleLogin + self.aggregateLogins = aggregateLogins + } +} diff --git a/Sources/CustomAuth/Common/LoginResponses/TorusLoginResponse.swift b/Sources/CustomAuth/Common/LoginResponses/TorusLoginResponse.swift new file mode 100644 index 0000000..e4b666c --- /dev/null +++ b/Sources/CustomAuth/Common/LoginResponses/TorusLoginResponse.swift @@ -0,0 +1,12 @@ +import Foundation +import TorusUtils + +public class TorusLoginResponse: Codable { + public let singleVerifierResponse: TorusSingleVerifierResponse + public let torusKey: TorusKey + + public init(singleVerifierResponse: TorusSingleVerifierResponse, torusKey: TorusKey) { + self.singleVerifierResponse = singleVerifierResponse + self.torusKey = torusKey + } +} diff --git a/Sources/CustomAuth/Common/Passkeys/AuthenticatorTransports.swift b/Sources/CustomAuth/Common/Passkeys/AuthenticatorTransports.swift new file mode 100644 index 0000000..30a3275 --- /dev/null +++ b/Sources/CustomAuth/Common/Passkeys/AuthenticatorTransports.swift @@ -0,0 +1,9 @@ +import Foundation + +public enum AuthenticatorTransports: String, Equatable, Hashable, Codable { + case ble + case hybrid + case inside = "internal" + case nfc + case usb +} diff --git a/Sources/CustomAuth/Common/Passkeys/PassKeyExtraParams.swift b/Sources/CustomAuth/Common/Passkeys/PassKeyExtraParams.swift new file mode 100644 index 0000000..924fbc0 --- /dev/null +++ b/Sources/CustomAuth/Common/Passkeys/PassKeyExtraParams.swift @@ -0,0 +1,27 @@ +import Foundation + +public class PassKeyExtraParams: Codable { + public let signature: String? + public let clientDataJson: String? + public let authenticatorJsonData: String? + public let publicKey: String? + public let challenge: String? + public let rpOrigin: String? + public let rpId: String? + public let credId: String? + public let transports: [AuthenticatorTransports]? + public let username: String? + + init(signature: String?, clientDataJson: String? = nil, authenticatorJsonData: String? = nil, publicKey: String? = nil, challenge: String? = nil, rpOrigin: String? = nil, rpId: String? = nil, credId: String? = nil, transports: [AuthenticatorTransports]? = nil, username: String? = nil) { + self.signature = signature + self.clientDataJson = clientDataJson + self.authenticatorJsonData = authenticatorJsonData + self.publicKey = publicKey + self.challenge = challenge + self.rpOrigin = rpOrigin + self.rpId = rpId + self.credId = credId + self.transports = transports + self.username = username + } +} diff --git a/Sources/CustomAuth/Common/PopupResponse.swift b/Sources/CustomAuth/Common/PopupResponse.swift new file mode 100644 index 0000000..bf7c7b6 --- /dev/null +++ b/Sources/CustomAuth/Common/PopupResponse.swift @@ -0,0 +1,11 @@ +import Foundation + +public class PopupResponse: Codable { + public let hashParams: HashParams + public let instanceParams: TorusGenericContainer + + public init(hashParams: HashParams, instanceParams: TorusGenericContainer) { + self.hashParams = hashParams + self.instanceParams = instanceParams + } +} diff --git a/Sources/CustomAuth/Common/RedirectResultParams.swift b/Sources/CustomAuth/Common/RedirectResultParams.swift new file mode 100644 index 0000000..6260d3b --- /dev/null +++ b/Sources/CustomAuth/Common/RedirectResultParams.swift @@ -0,0 +1,11 @@ +import Foundation + +public class RedirectResultParams: Codable { + public let relaceUrl: Bool + public let clearLoginDetails: Bool + + public init(relaceUrl: Bool, clearLoginDetails: Bool) { + self.relaceUrl = relaceUrl + self.clearLoginDetails = clearLoginDetails + } +} diff --git a/Sources/CustomAuth/Common/State.swift b/Sources/CustomAuth/Common/State.swift new file mode 100644 index 0000000..fdf1d76 --- /dev/null +++ b/Sources/CustomAuth/Common/State.swift @@ -0,0 +1,28 @@ +import Foundation + +internal class State: Codable { + public var customState: TorusGenericContainer? + public var instanceId: String + public var verifier: String + public var typeOfLogin: String + public var redirectUri: String + public var redirectToAndroid: String = "true" + + public init(instanceId: String, verifier: String, typeOfLogin: String, redirectUri: String, customState: TorusGenericContainer? = nil) { + self.customState = customState + self.instanceId = instanceId + self.verifier = verifier + self.typeOfLogin = typeOfLogin + self.redirectUri = redirectUri + } + + public func encode(to encoder: any Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(customState, forKey: .customState) + try container.encode(instanceId, forKey: .instanceId) + try container.encode(verifier, forKey: .verifier) + try container.encode(typeOfLogin, forKey: .typeOfLogin) + try container.encode(redirectToAndroid, forKey: .redirectToAndroid) + try container.encode(redirectUri, forKey: .redirectUri) + } +} diff --git a/Sources/CustomAuth/Common/TorusGenericContainer.swift b/Sources/CustomAuth/Common/TorusGenericContainer.swift new file mode 100644 index 0000000..ca1abf0 --- /dev/null +++ b/Sources/CustomAuth/Common/TorusGenericContainer.swift @@ -0,0 +1,9 @@ +import Foundation + +public class TorusGenericContainer: Codable { + public let params: [String: String] + + init(params: [String: String]) { + self.params = params + } +} diff --git a/Sources/CustomAuth/Common/VerifierResponses/TorusAggregateVerifierResponse.swift b/Sources/CustomAuth/Common/VerifierResponses/TorusAggregateVerifierResponse.swift new file mode 100644 index 0000000..86cf42a --- /dev/null +++ b/Sources/CustomAuth/Common/VerifierResponses/TorusAggregateVerifierResponse.swift @@ -0,0 +1,11 @@ +import Foundation + +public class TorusAggregateVerifierResponse: Codable { + public let userInfo: UserInfo + public let loginResponse: LoginWindowResponse + + public init(userInfo: UserInfo, loginResponse: LoginWindowResponse) { + self.userInfo = userInfo + self.loginResponse = loginResponse + } +} diff --git a/Sources/CustomAuth/Common/VerifierResponses/TorusSingleVerifierResponse.swift b/Sources/CustomAuth/Common/VerifierResponses/TorusSingleVerifierResponse.swift new file mode 100644 index 0000000..6f55103 --- /dev/null +++ b/Sources/CustomAuth/Common/VerifierResponses/TorusSingleVerifierResponse.swift @@ -0,0 +1,11 @@ +import Foundation + +public class TorusSingleVerifierResponse: Codable { + public let userInfo: UserInfo + public let loginResponse: LoginWindowResponse + + public init(userInfo: UserInfo, loginResponse: LoginWindowResponse) { + self.userInfo = userInfo + self.loginResponse = loginResponse + } +} diff --git a/Sources/CustomAuth/Common/VerifierResponses/TorusVerifierResponses.swift b/Sources/CustomAuth/Common/VerifierResponses/TorusVerifierResponses.swift new file mode 100644 index 0000000..f66c938 --- /dev/null +++ b/Sources/CustomAuth/Common/VerifierResponses/TorusVerifierResponses.swift @@ -0,0 +1,26 @@ +import Foundation +import TorusUtils + +public class TorusVerifierResponse: Codable { + public let email: String + public let name: String + public let profileImage: String + public let aggregateVerifier: String? + public let verifier: String + public let verifierId: String + public let typeOfLogin: LoginType + public let ref: String? + public let extraVerifierParams: PassKeyExtraParams? + + public init(email: String, name: String, profileImage: String, aggregateVerifier: String? = nil, verifier: String, verifierId: String, typeOfLogin: LoginType, ref: String? = nil, extraVerifierParams: PassKeyExtraParams? = nil) { + self.email = email + self.name = name + self.profileImage = profileImage + self.aggregateVerifier = aggregateVerifier + self.verifier = verifier + self.verifierId = verifierId + self.typeOfLogin = typeOfLogin + self.ref = ref + self.extraVerifierParams = extraVerifierParams + } +} diff --git a/Sources/CustomAuth/Common/VerifierResponses/UserInfo.swift b/Sources/CustomAuth/Common/VerifierResponses/UserInfo.swift new file mode 100644 index 0000000..f9895df --- /dev/null +++ b/Sources/CustomAuth/Common/VerifierResponses/UserInfo.swift @@ -0,0 +1,35 @@ +import Foundation + +public class UserInfo: Codable { + public let email: String + public let name: String + public let profileImage: String + public let aggregateVerifier: String? + public let verifier: String + public let verifierId: String + public let typeOfLogin: LoginType + public let ref: String? + public let extraVerifierParams: PassKeyExtraParams? + public let accessToken: String? + public let idToken: String? + public let extraParams: String? + public let extraParamsPassed: String? + public let state: TorusGenericContainer + + public init(email: String, name: String, profileImage: String, aggregateVerifier: String? = nil, verifier: String, verifierId: String, typeOfLogin: LoginType, ref: String? = nil, extraVerifierParams: PassKeyExtraParams? = nil, accessToken: String? = nil, idToken: String? = nil, extraParams: String? = nil, extraParamsPassed: String? = nil, state: TorusGenericContainer) { + self.email = email + self.name = name + self.profileImage = profileImage + self.aggregateVerifier = aggregateVerifier + self.verifier = verifier + self.verifierId = verifierId + self.typeOfLogin = typeOfLogin + self.ref = ref + self.extraVerifierParams = extraVerifierParams + self.accessToken = accessToken + self.idToken = idToken + self.extraParams = extraParams + self.extraParamsPassed = extraParamsPassed + self.state = state + } +} diff --git a/Sources/CustomAuth/CustomAuth.swift b/Sources/CustomAuth/CustomAuth.swift index f3d9857..e658c68 100644 --- a/Sources/CustomAuth/CustomAuth.swift +++ b/Sources/CustomAuth/CustomAuth.swift @@ -1,264 +1,259 @@ -// -// CustomAuth class -// CustomAuth -// -// Created by Shubham Rathi on 24/4/2020. -// - import FetchNodeDetails import Foundation import OSLog import TorusUtils -import UIKit -import curveSecp256k1 - -// Global variable -var tsSdkLogType = OSLogType.default - -public struct TorusKeyData { - public let torusKey : TorusKey - public var userInfo : [String: Any] - - public init(torusKey: TorusKey, userInfo: [String : Any]) { - self.torusKey = torusKey - self.userInfo = userInfo - } -} +#if canImport(curveSecp256k1) + import curveSecp256k1 +#endif + +public class CustomAuth { + public let isInitialized: Bool = false + + public let config: CustomAuthArgs -/// Provides integration of an iOS app with Torus CustomAuth. -open class CustomAuth { - var nodeDetailManager: NodeDetailManager - var torusUtils: AbstractTorusUtils - var urlSession: URLSession - var enableOneKey: Bool - /// You can pass your own custom url rather than using our default infura url, - /// can be used to get around the Ropsten depreciation from Infura API. - var networkUrl: String? - public let aggregateVerifierType: verifierTypes? - public let aggregateVerifier: String - public let subVerifierDetails: [SubVerifierDetails] - public var authorizeURLHandler: URLOpenerTypes? - var observer: NSObjectProtocol? // useful for Notifications - var network : TorusNetwork - - /// Initiate an CustomAuth instance. + public let torus: TorusUtils + + public let nodeDetailManager: NodeDetailManager + + /// Initializes CustomAuth with the provided options + /// /// - Parameters: - /// - aggregateVerifierType: Type of the verifier. Use `singleLogin` for single providers. Only `singleLogin` and `singleIdVerifier` is supported currently. - /// - aggregateVerifier: Name of the verifier to be used.. - /// - subVerifierDetails: Details of each subverifiers to be used. - /// - factory: Providng mocking by implementing TDSDKFactoryProtocol. - /// - network: Etherum network to be used. - /// - loglevel: Indicates the log level of this instance. All logs lower than this level will be ignored. - public init(web3AuthClientId: String ,aggregateVerifierType: verifierTypes, aggregateVerifier: String, subVerifierDetails: [SubVerifierDetails], network: TorusNetwork, loglevel: OSLogType = .debug, urlSession: URLSession = URLSession.shared, enableOneKey: Bool = false, networkUrl: String? = nil) { - tsSdkLogType = loglevel - self.networkUrl = networkUrl - self.enableOneKey = enableOneKey - // factory method - self.nodeDetailManager = NodeDetailManager(network: network) - self.urlSession = urlSession - - self.torusUtils = TorusUtils( loglevel: loglevel, urlSession: urlSession, enableOneKey: enableOneKey, serverTimeOffset: 1000, network: network, clientId: web3AuthClientId) + /// - params: `CustomAuthArgs` + /// + /// - Returns: `CustomAuth` + /// + /// - Throws: `CASDKError.invalidCallbackURLScheme`, `TorusUtilError.invalidInput` + public init(config: CustomAuthArgs) throws { + if URL(string: config.urlScheme)?.scheme == nil { + throw CASDKError.invalidCallbackURLScheme + } - // verifier details - self.aggregateVerifier = aggregateVerifier - self.aggregateVerifierType = aggregateVerifierType - self.subVerifierDetails = subVerifierDetails - self.network = network + self.config = config + + let nodeDetails = NodeDetailManager(network: config.network) + nodeDetailManager = nodeDetails + + let torusOptions = TorusOptions( + clientId: config.web3AuthClientId, + network: config.network, + legacyMetadataHost: config.metadataUrl, + serverTimeOffset: config.serverTimeOffset, + enableOneKey: config.enableOneKey) + let torusUtils = try TorusUtils(params: torusOptions) + torus = torusUtils + + torus.setApiKey(apiKey: config.apiKey ?? "") } - - /// Initiate an CustomAuth instance. + + /// Initiates a login using a single verifier + /// /// - Parameters: - /// - aggregateVerifierType: Type of the verifier. Use `singleLogin` for single providers. Only `singleLogin` and `singleIdVerifier` is supported currently. - /// - aggregateVerifier: Name of the verifier to be used.. - /// - subVerifierDetails: Details of each subverifiers to be used. - public convenience init(web3AuthClientId: String ,aggregateVerifierType: verifierTypes, aggregateVerifier: String, subVerifierDetails: [SubVerifierDetails], network: TorusNetwork, enableOneKey: Bool = false, networkUrl: String? = nil) { - // let factory = CASDKFactory() - self.init(web3AuthClientId: web3AuthClientId, aggregateVerifierType: aggregateVerifierType, aggregateVerifier: aggregateVerifier, subVerifierDetails: subVerifierDetails, network: network, loglevel: .debug, enableOneKey: enableOneKey, networkUrl: networkUrl) - } - - // public convenience init(web3AuthClientId: String ,aggregateVerifierType: verifierTypes, aggregateVerifier: String, subVerifierDetails: [SubVerifierDetails], network: TorusNetwork, loglevel: OSLogType = .debug, enableOneKey: Bool = false, networkUrl: String? = nil) { - //// let factory = CASDKFactory() - // self.init(web3AuthClientId: web3AuthClientId, aggregateVerifierType: aggregateVerifierType, aggregateVerifier: aggregateVerifier, subVerifierDetails: subVerifierDetails, network: network, loglevel: loglevel, enableOneKey: enableOneKey, networkUrl: networkUrl) - // } - - /// Retrieve information of Torus nodes from a predefined Etherum contract. - /// - Returns: An array of URLs to the nodes. - open func getNodeDetailsFromContract(verifier: String, verfierID: String) async throws -> AllNodeDetailsModel { - let nodeDetails = try await nodeDetailManager.getNodeDetails(verifier: verifier, verifierID: verfierID) - return nodeDetails + /// - params: `SingleLoginParams` + /// + /// - Returns: `TorusLoginResponse` + /// + /// - Throws: `CASDKError`, `TorusUtilError` + public func triggerLogin(args: SingleLoginParams) async throws -> TorusLoginResponse { + 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)) + + var loginParams: LoginWindowResponse + if args.hash != nil && args.queryParams != nil { + let (error, hashParams, instanceParams) = try handleRedirectParameters(hash: args.hash!, queryParameters: args.queryParams!) + if !error.isEmpty { + throw CASDKError.redirectParamsError(msg: error) + } + 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) + } else { + loginParams = try await loginHandler.handleLoginWindow(popupFeatures: config.popupFeatures) + } + + let userInfo = try await loginHandler.getUserInfo(params: loginParams, storageServerUrl: nil) + + let verifyParams: VerifierParams = VerifierParams(verifier_id: userInfo.verifierId) + + let torusKey = try await getTorusKey(verifier: userInfo.verifier, verifierParams: verifyParams, idToken: loginParams.idToken ?? loginParams.accessToken ?? "") + + 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, accessToken: loginParams.accessToken, idToken: loginParams.idToken, extraParams: loginParams.extraParams, extraParamsPassed: loginParams.extraParamsPassed, state: loginParams.state) + + return TorusLoginResponse(singleVerifierResponse: TorusSingleVerifierResponse(userInfo: returnedInfo, loginResponse: loginParams), torusKey: torusKey) } - - /// Trigger login flow. + + /// Initiates a login using a aggregate verifier + /// /// - Parameters: - /// - controller: A `UIViewController` used for providing context for the login flow. - /// - browserType: Indicates the way to open the browser for login flow. Use `.external` for opening system safari, or `.asWebAuthSession` for opening an in-app ASwebAuthenticationSession. - /// - modalPresentationStyle: Indicates the UIModalPresentationStyle for the popup. - /// - Returns: A promise that resolve with a Dictionary that contain at least `privateKey` and `publicAddress` field.. - open func triggerLogin(controller: UIViewController? = nil, browserType: URLOpenerTypes = .asWebAuthSession, modalPresentationStyle: UIModalPresentationStyle = .fullScreen) async throws -> TorusKeyData { - os_log("triggerLogin called with %@ %@", log: getTorusLogger(log: CASDKLogger.core, type: .info), type: .info, browserType.rawValue, modalPresentationStyle.rawValue) - // Set browser - authorizeURLHandler = browserType - - switch aggregateVerifierType { - case .singleLogin: - return try await handleSingleLogins(controller: controller, modalPresentationStyle: modalPresentationStyle) - case .andAggregateVerifier: - return try await handleAndAggregateVerifier(controller: controller) - case .orAggregateVerifier: - return try await handleOrAggregateVerifier(controller: controller) - case .singleIdVerifier: - return try await handleSingleIdVerifier(controller: controller, modalPresentationStyle: modalPresentationStyle) - case .none: - throw CASDKError.methodUnavailable + /// - params: `AggregateLoginParams` + /// + /// - Returns: `TorusAggregateLoginResponse` + /// + /// - Throws: `CASDKError`, `TorusUtilError` + public func triggerAggregateLogin(args: AggregateLoginParams) async throws -> TorusAggregateLoginResponse { + if args.subVerifierDetailsArray.isEmpty { + throw CASDKError.invalidParameters } - } - - open func handleSingleLogins(controller: UIViewController?, modalPresentationStyle: UIModalPresentationStyle = .fullScreen) async throws -> TorusKeyData { - if let subVerifier = subVerifierDetails.first { - let loginURL = subVerifier.getLoginURL() - await openURL(url: loginURL, view: controller, modalPresentationStyle: modalPresentationStyle) - do { - let url = try await withUnsafeThrowingContinuation { (continuation: UnsafeContinuation) in - observeCallbackWithError { url, err in - guard - err == nil, - let url = url - else { - continuation.resume(throwing: err!) - return - } - - continuation.resume(returning: url) - return - } + if args.subVerifierDetailsArray.count == 1 && args.aggregateVerifierType == AggregateVerifierType.single_id_verifier { + throw CASDKError.invalidParameters + } + + var loginParamsArray: [LoginWindowResponse] = [] + var userInfoArray: [UserInfo] = [] + for subverifierDetail in args.subVerifierDetailsArray { + 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)) + var loginParams: LoginWindowResponse + var userInfo: UserInfo + if subverifierDetail.hash != nil && subverifierDetail.queryParams != nil { + let (error, hashParams, instanceParams) = try handleRedirectParameters(hash: subverifierDetail.hash!, queryParameters: subverifierDetail.queryParams!) + if !error.isEmpty { + throw CASDKError.redirectParamsError(msg: error) } - let responseParameters = self.parseURL(url: url) - os_log("ResponseParams after redirect: %@", log: getTorusLogger(log: CASDKLogger.core, type: .info), type: .info, responseParameters) - - let newData = try await subVerifier.getUserInfo(responseParameters: responseParameters) - os_log("getUserInfo newData: %@", log: getTorusLogger(log: CASDKLogger.core, type: .info), type: .info, newData) - var data = newData - let verifierId = data["verifierId"] as! String - let idToken = data["tokenForKeys"] as! String - data.removeValue(forKey: "tokenForKeys") - data.removeValue(forKey: "verifierId") - - - let torusKey = try await getTorusKey(verifier: self.aggregateVerifier, verifierId: verifierId, idToken: idToken, userData: data) - var mergedUserInfo = newData.merging(responseParameters) { (_, new) in new } - mergedUserInfo["verifier"] = self.aggregateVerifier - let result = TorusKeyData(torusKey: torusKey, userInfo: mergedUserInfo) - return result - } catch { - os_log("handleSingleLogin: err: %s", log: getTorusLogger(log: CASDKLogger.core, type: .error), type: .error, error.localizedDescription) - throw error + 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) + } else { + loginParams = try await loginHandler.handleLoginWindow(popupFeatures: config.popupFeatures) } - - // Open in external safari + + let info = try await loginHandler.getUserInfo(params: loginParams, storageServerUrl: nil) + 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, accessToken: loginParams.accessToken, idToken: loginParams.idToken, extraParams: loginParams.extraParams, extraParamsPassed: loginParams.extraParamsPassed, state: loginParams.state) + loginParamsArray.append(loginParams) + userInfoArray.append(userInfo) + } + + var subVerifierIds: [String] = [] + var aggregateVerifierParams: [VerifyParams] = [] + var aggregateIdTokenSeeds: [String] = [] + var aggregateVerifierId: String = "" + + for i in 0 ..< args.subVerifierDetailsArray.count { + let loginParams = loginParamsArray[i] + let userInfo = userInfoArray[i] + + aggregateVerifierParams.append(VerifyParams(verifier_id: userInfo.verifierId, idtoken: loginParams.idToken!)) + aggregateIdTokenSeeds.append(loginParams.idToken ?? loginParams.accessToken!) + subVerifierIds.append(userInfo.verifier) + aggregateVerifierId = userInfo.verifierId + } + aggregateIdTokenSeeds.sort() + let joined = aggregateIdTokenSeeds.joined(separator: "\u{29}").data(using: .utf8)! + let aggregateIdToken = try keccak256(data: joined) + let aggregateParams: VerifierParams = VerifierParams(verifier_id: aggregateVerifierId, extended_verifier_id: nil, sub_verifier_ids: subVerifierIds, verify_params: aggregateVerifierParams) + + let aggregateTorusKey = try await getTorusKey(verifier: aggregateVerifierId, verifierParams: aggregateParams, idToken: String(data: aggregateIdToken, encoding: .utf8)!) + + var aggregateVerifierResponses: [TorusAggregateVerifierResponse] = [] + for i in 0 ..< userInfoArray.count { + let loginParams = loginParamsArray[i] + let userInfo = userInfoArray[i] + aggregateVerifierResponses.append(TorusAggregateVerifierResponse(userInfo: userInfo, loginResponse: loginParams)) } - throw CASDKError.unknownError + + return TorusAggregateLoginResponse(torusAggregateVerifierResponse: aggregateVerifierResponses, torusKey: aggregateTorusKey) } - - open func handleSingleIdVerifier(controller: UIViewController?, modalPresentationStyle: UIModalPresentationStyle = .fullScreen) async throws -> TorusKeyData { - if let subVerifier = subVerifierDetails.first { - let loginURL = subVerifier.getLoginURL() - await MainActor.run(body: { - openURL(url: loginURL, view: controller, modalPresentationStyle: modalPresentationStyle) - }) - - do { - let url = try await withUnsafeThrowingContinuation { (continuation: UnsafeContinuation) in - observeCallbackWithError { url, err in - guard - err == nil, - let url = url - else { - continuation.resume(throwing: err!) - return - } - - continuation.resume(returning: url) - return - } - } - let responseParameters = self.parseURL(url: url) - os_log("ResponseParams after redirect: %@", log: getTorusLogger(log: CASDKLogger.core, type: .info), type: .info, responseParameters) - - let newData = try await subVerifier.getUserInfo(responseParameters: responseParameters) - var data = newData - let verifierId = data["verifierId"] as! String - let idToken = data["tokenForKeys"] as! String - data.removeValue(forKey: "tokenForKeys") - data.removeValue(forKey: "verifierId") - let aggTorusKey = try await getAggregateTorusKey(verifier: self.aggregateVerifier, verifierId: verifierId, idToken: idToken, subVerifierDetails: subVerifier, userData: newData) - var mergedUserInfo = newData.merging(responseParameters) { (_, new) in new } - mergedUserInfo["verifier"] = self.aggregateVerifier - let result = TorusKeyData(torusKey: aggTorusKey, userInfo: mergedUserInfo) - return result - } catch { - os_log("handleSingleIdVerifier err: %s", log: getTorusLogger(log: CASDKLogger.core, type: .error), type: .error, error.localizedDescription) - throw error + + /// Initiates a login using a hybrid verifier + /// + /// - Parameters: + /// - params: `HybridAggregateLoginParams` + /// + /// - Returns: `TorusHybridAggregateLoginResponse` + /// + /// - Throws: `CASDKError`, `TorusUtilError` + public func triggerHybridAggregateLogin(args: HybridAggregateLoginParams) async throws -> TorusHybridAggregateLoginResponse { + if args.aggregateLoginParams.subVerifierDetailsArray.isEmpty { + throw CASDKError.invalidParameters + } + if args.aggregateLoginParams.subVerifierDetailsArray.count == 1 && args.aggregateLoginParams.aggregateVerifierType == AggregateVerifierType.single_id_verifier { + throw CASDKError.invalidParameters + } + + let loginHandler = try HandlerFactory.createHandler(params: CreateHandlerParams(typeOfLogin: args.singleLogin.typeOfLogin, verifier: args.singleLogin.verifier, clientId: args.singleLogin.clientId, urlScheme: config.urlScheme, redirectURL: args.singleLogin.redirectURL, jwtParams: args.singleLogin.jwtParams, customState: args.singleLogin.customState)) + + var loginParams: LoginWindowResponse + if args.singleLogin.hash != nil && args.singleLogin.queryParams != nil { + let (error, hashParams, instanceParams) = try handleRedirectParameters(hash: args.singleLogin.hash!, queryParameters: args.singleLogin.queryParams!) + if !error.isEmpty { + throw CASDKError.redirectParamsError(msg: error) } - + 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) + } else { + loginParams = try await loginHandler.handleLoginWindow(popupFeatures: config.popupFeatures) } - throw CASDKError.unknownError - - } - - func handleAndAggregateVerifier(controller: UIViewController?) async throws -> TorusKeyData { - // TODO: implement verifier - throw CASDKError.methodUnavailable - } - - func handleOrAggregateVerifier(controller: UIViewController?) async throws -> TorusKeyData { - // TODO: implement verifier - throw CASDKError.methodUnavailable + + let userInfo = try await loginHandler.getUserInfo(params: loginParams, storageServerUrl: nil) + + let verifyParams: VerifierParams = VerifierParams(verifier_id: userInfo.verifierId) + + let torusKey = try await getTorusKey(verifier: userInfo.verifier, verifierParams: verifyParams, idToken: loginParams.idToken!) + + 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, accessToken: loginParams.accessToken, idToken: loginParams.idToken, extraParams: loginParams.extraParams, extraParamsPassed: loginParams.extraParamsPassed, state: loginParams.state) + + var subVerifierIds: [String] = [] + var aggregateVerifierParams: [VerifyParams] = [] + var aggregateIdTokenSeeds: [String] = [] + var aggregateVerifierId: String = "" + for i in 0 ..< args.aggregateLoginParams.subVerifierDetailsArray.count { + let sub = args.aggregateLoginParams.subVerifierDetailsArray[i] + aggregateVerifierParams.append(VerifyParams(verifier_id: userInfo.verifierId, idtoken: loginParams.idToken!)) + aggregateIdTokenSeeds.append(loginParams.idToken ?? loginParams.accessToken!) + subVerifierIds.append(sub.verifier) + aggregateVerifierId = userInfo.verifierId + } + aggregateIdTokenSeeds.sort() + let joined = aggregateIdTokenSeeds.joined(separator: "\u{29}").data(using: .utf8)! + let aggregateIdToken = try keccak256(data: joined) + let aggregateParams: VerifierParams = VerifierParams(verifier_id: aggregateVerifierId, extended_verifier_id: nil, sub_verifier_ids: subVerifierIds, verify_params: aggregateVerifierParams) + + let aggregateTorusKey = try await getTorusKey(verifier: args.aggregateLoginParams.verifierIdentifier, verifierParams: aggregateParams, idToken: String(data: aggregateIdToken, encoding: .utf8)!) + + let aggregateResponse = TorusAggregateVerifierResponse(userInfo: returnedInfo, loginResponse: loginParams) + + let aggregateLogin = TorusAggregateLoginResponse(torusAggregateVerifierResponse: [aggregateResponse], torusKey: torusKey) + + return TorusHybridAggregateLoginResponse(singleLogin: aggregateLogin, aggregateLogins: [aggregateTorusKey]) } - - /// Retrieve the Torus key from the nodes given an already known token. Useful if a custom login flow is required. + + /// Retrieves the key details + /// /// - Parameters: - /// - verifier: A verifier is a unique identifier for your OAuth registration on the torus network. The public/private keys generated for a user are scoped to a verifier. - /// - verifierId: The unique identifier to publicly represent a user on a verifier. e.g: email, sub etc. other fields can be classified as verifierId, - /// - idToken: Access token received from the OAuth provider. - /// - userData: Custom data that will be returned with `privateKey` and `publicAddress`. - /// - Returns: A promise that resolve with a Dictionary that contain at least `privateKey` and `publicAddress` field.. - open func getTorusKey(verifier: String, verifierId: String, idToken: String, userData: [String: Any] = [:]) async throws -> TorusKey { - let extraParams = ["verifier_id": verifierId] as [String: Codable] - let verifierParams = VerifierParams(verifier_id: verifierId) - do { - let nodeDetails = try await nodeDetailManager.getNodeDetails(verifier: verifier, verifierID: verifierId) - // retrieveShares internall checks if network is legacy and calls getPublicAddress if required. - let responseFromRetrieveShares : TorusKey = try await torusUtils.retrieveShares(endpoints: nodeDetails.torusNodeEndpoints, torusNodePubs: nodeDetails.torusNodePub, indexes: nodeDetails.torusIndexes, verifier: verifier, verifierParams: verifierParams, idToken: idToken, extraParams: extraParams) - - return responseFromRetrieveShares - } catch { - os_log("handleSingleLogin: err: %s", log: getTorusLogger(log: CASDKLogger.core, type: .error), type: .error, error.localizedDescription) - throw error - } + /// - verifier: `String` + /// - verifierParams: `VerifierParams` + /// - idToken: `String` + /// + /// - Returns: `TorusKey` + /// + /// - Throws: `CASDKError`, `TorusUtilError`, `FetchNodeError` + func getTorusKey(verifier: String, verifierParams: VerifierParams, idToken: String) async throws -> TorusKey { + let nodeDetails = try await nodeDetailManager.getNodeDetails(verifier: verifier, verifierID: verifierParams.verifier_id) + + return try await torus.retrieveShares(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierParams: verifierParams, idToken: idToken) } - - /// Retrieve the Torus key from the nodes given an already known token. Useful if a custom aggregate login flow is required. + + /// Retrieves the aggregate key details + /// /// - Parameters: - /// - verifier: A verifier is a unique identifier for your OAuth registration on the torus network. The public/private keys generated for a user are scoped to a verifier. - /// - verifierId: The unique identifier to publicly represent a user on a verifier. e.g: email, sub etc. other fields can be classified as verifierId, - /// - subVerifierDetails: An array of verifiers to be used for the aggregate login flow, with their respective token and verifier name. - /// - Returns: A promise that resolve with a Dictionary that contain at least `privateKey` and `publicAddress` field.. - open func getAggregateTorusKey(verifier: String, verifierId: String, idToken: String, subVerifierDetails: SubVerifierDetails, userData: [String: Any] = [:]) async throws -> TorusKey { - let extraParams = ["verifieridentifier": verifier, "verifier_id": verifierId, "sub_verifier_ids": [subVerifierDetails.verifier], "verify_params": [["verifier_id": verifierId, "idtoken": idToken]]] as [String: Codable] - let hashedOnce = try keccak256(data: Data(idToken.utf8)) - - let verifierParams = VerifierParams(verifier_id: verifierId) - - do { - let nodeDetails = try await getNodeDetailsFromContract(verifier: verifier, verfierID: verifierId) - - // retrieveShares internall checks if network is legacy and calls getPublicAddress if required. - let responseFromRetrieveShares :TorusKey = try await self.torusUtils.retrieveShares(endpoints: nodeDetails.torusNodeEndpoints, torusNodePubs: nodeDetails.torusNodePub, indexes: nodeDetails.torusIndexes, verifier: verifier, verifierParams: verifierParams, idToken: hashedOnce.toHexString(), extraParams: extraParams) - - return responseFromRetrieveShares - } catch { - os_log("handleSingleIdVerifier err: %@", log: getTorusLogger(log: CASDKLogger.core, type: .error), type: .error, error.localizedDescription) - throw error + /// - verifier: `String` + /// - verifierParams: `VerifierParams` + /// - subVerifierInfoArray: `TorusSubVerifierInfo` + /// + /// - Returns: `TorusKey` + /// + /// - Throws: `CASDKError`, `TorusUtilError`, `FetchNodeError` + func getAggregateTorusKey(verifier: String, verifierParams: VerifierParams, subVerifierInfoArray: [TorusSubVerifierInfo]) async throws -> TorusKey { + let nodeDetails = try await nodeDetailManager.getNodeDetails(verifier: verifier, verifierID: verifierParams.verifier_id) + + var aggregateIdTokenSeeds: [String] = [] + var subVerifierIds: [String] = [] + + var verifyParams: [VerifyParams] = [] + for i in 0 ..< subVerifierInfoArray.count { + let userInfo = subVerifierInfoArray[i] + verifyParams.append(VerifyParams(verifier_id: verifierParams.verifier_id, idtoken: userInfo.idToken)) + subVerifierIds.append(userInfo.verifier) + aggregateIdTokenSeeds.append(userInfo.idToken) } + + aggregateIdTokenSeeds.sort() + let joined = aggregateIdTokenSeeds.joined(separator: "\u{29}").data(using: .utf8)! + let aggregateIdToken = try keccak256(data: joined) + let params: VerifierParams = VerifierParams(verifier_id: verifierParams.verifier_id, extended_verifier_id: verifierParams.extended_verifier_id, sub_verifier_ids: subVerifierIds, verify_params: verifyParams) + + return try await torus.retrieveShares(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierParams: params, idToken: String(data: aggregateIdToken, encoding: .utf8)!) } } diff --git a/Sources/CustomAuth/CustomAuthArgs.swift b/Sources/CustomAuth/CustomAuthArgs.swift new file mode 100644 index 0000000..f7a0879 --- /dev/null +++ b/Sources/CustomAuth/CustomAuthArgs.swift @@ -0,0 +1,28 @@ +import FetchNodeDetails +import Foundation + +public class CustomAuthArgs { + public let urlScheme: String + public let metadataUrl: String? + public let network: TorusNetwork + public let enableLogging: Bool + public let enableOneKey: Bool + public let apiKey: String? + public let popupFeatures: String? + public let storageServerUrl: String? + public let web3AuthClientId: String + public let serverTimeOffset: Int + + public init(urlScheme: String, metadataUrl: String? = nil, network: TorusNetwork, enableLogging: Bool = false, enableOneKey: Bool, apiKey: String? = nil, popupFeatures: String? = nil, storageServerUrl: String? = nil, web3AuthClientId: String, serverTimeOffset: Int = 0, legacyMetadataHost: String? = nil) { + self.urlScheme = urlScheme + self.metadataUrl = metadataUrl + self.network = network + self.enableLogging = enableLogging + self.enableOneKey = enableOneKey + self.apiKey = apiKey + self.popupFeatures = popupFeatures + self.storageServerUrl = storageServerUrl + self.web3AuthClientId = web3AuthClientId + self.serverTimeOffset = serverTimeOffset + } +} diff --git a/Sources/CustomAuth/CustomAuthFactory.swift b/Sources/CustomAuth/CustomAuthFactory.swift deleted file mode 100644 index c77151c..0000000 --- a/Sources/CustomAuth/CustomAuthFactory.swift +++ /dev/null @@ -1,49 +0,0 @@ -// -// File.swift -// -// -// Created by Shubham on 30/7/21. -// - -import FetchNodeDetails -import Foundation -import OSLog -import TorusUtils - -/// A protocol should be implmented by users of `CustomAuth`. It provides a way -/// to stub or mock the CustomAuth for testing. -public protocol CASDKFactoryProtocol { - func createTorusUtils(loglevel: OSLogType, urlSession: URLSession, enableOneKey: Bool, network: TorusNetwork) -> AbstractTorusUtils -// func createFetchNodeDetails(network: TorusNetwork, urlSession: URLSession, networkUrl: String?) -> AllNodeDetailsModel -} - -//public class CASDKFactory: CASDKFactoryProtocol { -// public func createFetchNodeDetails(network: TorusNetwork, urlSession: URLSession = URLSession.shared, networkUrl: String? = nil) -> FetchNodeDetails { -// var proxyAddress: String = "" -// switch network { -// case .MAINNET: -// proxyAddress = FetchNodeDetails.proxyAddressMainnet -// case .TESTNET: -// proxyAddress = FetchNodeDetails.proxyAddressTestnet -// case .CYAN: -// proxyAddress = FetchNodeDetails.proxyAddressCyan -// case .AQUA: -// proxyAddress = FetchNodeDetails.proxyAddressAqua -// case .CELESTE: -// proxyAddress = FetchNodeDetails.proxyAddressCeleste -// default: -// proxyAddress = FetchNodeDetails.proxyAddressMainnet -// } -// guard let networkUrl = networkUrl else { return FetchNodeDetails(proxyAddress: proxyAddress, network: network, urlSession: urlSession) } -// return FetchNodeDetails(proxyAddress: proxyAddress, network: .CUSTOM(path: networkUrl), urlSession: urlSession) -// } -// -// public func createTorusUtils(loglevel: OSLogType, urlSession: URLSession = URLSession.shared, enableOneKey: Bool, network: TorusNetwork) -> AbstractTorusUtils { -// let allowHost = network.signerMap.appending("/api/allow") -// let signerHost = network.signerMap.appending("/api/sign") -// return TorusUtils(loglevel: loglevel, urlSession: urlSession, enableOneKey: enableOneKey, signerHost: signerHost, allowHost: allowHost, network: network) -// } -// -// public init() { -// } -//} diff --git a/Sources/CustomAuth/Extension/CASDK+extension.swift b/Sources/CustomAuth/Extension/CASDK+extension.swift deleted file mode 100644 index e2d7e69..0000000 --- a/Sources/CustomAuth/Extension/CASDK+extension.swift +++ /dev/null @@ -1,144 +0,0 @@ -// -// CustomAuth class -// CustomAuth -// -// Created by Shubham Rathi on 18/05/2020. -// - -import Foundation -import OSLog -import SafariServices -import TorusUtils - -typealias torus = CustomAuth - -// MARK: - verifier types - -public enum verifierTypes: String { - case singleLogin = "single_login" - case singleIdVerifier = "single_id_verifier" - case andAggregateVerifier = "and_aggregate_verifier" - case orAggregateVerifier = "or_aggregate_verifier" -} - -// MARK: - torus extension -extension CustomAuth { - - public class var notificationCenter: NotificationCenter { - return NotificationCenter.default - } - - public class var notificationQueue: OperationQueue { - return OperationQueue.main - } - - static let didHandleCallbackURL: Notification.Name = .init("TSDSDKCallbackNotification") - - public func removeCallbackNotificationObserver() { - if let observer = observer { - CustomAuth.notificationCenter.removeObserver(observer) - } - } - - public func observeCallback(_ block: @escaping (_ url: URL) -> Void) { - self.observer = CustomAuth.notificationCenter.addObserver( - forName: CustomAuth.didHandleCallbackURL, - object: nil, - queue: OperationQueue.main) { [weak self] notification in - self?.removeCallbackNotificationObserver() - os_log("notification.userInfo: %s", log: getTorusLogger(log: CASDKLogger.core, type: .info), type: .info, notification.userInfo.debugDescription) - if let urlFromUserInfo = notification.userInfo?["URL"] as? URL { - os_log("executing callback block", log: getTorusLogger(log: CASDKLogger.core, type: .error), type: .error) - block(urlFromUserInfo) - } else { - assertionFailure() - } - } - } - - - public func observeCallbackWithError(_ block: @escaping (_ url: URL?, _ err: String?) -> Void) { - self.observer = CustomAuth.notificationCenter.addObserver( - forName: CustomAuth.didHandleCallbackURL, - object: nil, - queue: OperationQueue.main) { [weak self] notification in - self?.removeCallbackNotificationObserver() - os_log("notification.userInfo: %s", log: getTorusLogger(log: CASDKLogger.core, type: - .info), type: .info, notification.userInfo.debugDescription) - if let errorFromUserInfo = notification.userInfo?["ERROR"] as? String { - os_log("executing error callback block", log: getTorusLogger(log: CASDKLogger.core, type: .error), type: .error) - block(nil, errorFromUserInfo) - } - else if let urlFromUserInfo = notification.userInfo?["URL"] as? URL { - os_log("executing callback block", log: getTorusLogger(log: CASDKLogger.core, type: .error), type: .info) - block(urlFromUserInfo, nil) - - } else { - assertionFailure() - } - } - } - - @MainActor public func openURL(url: String, view: UIViewController?, modalPresentationStyle: UIModalPresentationStyle) { - os_log("opening URL: %s", log: getTorusLogger(log: CASDKLogger.core, type: .info), type: .info, url) - switch authorizeURLHandler { - case .external: - let handler = ExternalURLHandler() - handler.handle(URL(string: url)!, modalPresentationStyle: modalPresentationStyle) - case .sfsafari: - guard let controller = view else { - os_log("UIViewController not available. Please modify triggerLogin(controller:)", log: getTorusLogger(log: CASDKLogger.core, type: .error), type: .error) - return - } - let handler = SFURLHandler(viewController: controller) - handler.handle(URL(string: url)!, modalPresentationStyle: modalPresentationStyle) - case .asWebAuthSession: - let handler = ASWebAuthSession(redirectURL: self.subVerifierDetails.first?.redirectURL ?? "") - handler.handle(URL(string: url)!, modalPresentationStyle: modalPresentationStyle) - case .none: - os_log("Cannot access specified browser", log: getTorusLogger(log: CASDKLogger.core, type: .error), type: .error) - } - } - - func makeUrlRequest(url: String, method: String) -> URLRequest { - var rq = URLRequest(url: URL(string: url)!) - rq.httpMethod = method - rq.addValue("application/json", forHTTPHeaderField: "Content-Type") - rq.addValue("application/json", forHTTPHeaderField: "Accept") - return rq - } - - public class func handle(url: URL) { - // CustomAuth.logger.info("Posting notification after Universal link/deep link flow") - let notification = Notification(name: CustomAuth.didHandleCallbackURL, object: nil, userInfo: ["URL": url]) - notificationCenter.post(notification) - } - - public class func handleError(err: String) { - // CustomAuth.logger.info("Posting notification after Universal link/deep link flow") - let notification = Notification(name: CustomAuth.didHandleCallbackURL, object: nil, userInfo: ["ERROR": err]) - notificationCenter.post(notification) - } - - public func parseURL(url: URL) -> [String: String] { - var responseParameters = [String: String]() - if let query = url.query { - responseParameters += query.parametersFromQueryString - } - if let fragment = url.fragment, !fragment.isEmpty { - responseParameters += fragment.parametersFromQueryString - } - return responseParameters - } - - // Run on main block - static func main(block: @escaping () -> Void) { - if Thread.isMainThread { - block() - } else { - DispatchQueue.main.async { - block() - } - } - } -} diff --git a/Sources/CustomAuth/Extension/Data+extension.swift b/Sources/CustomAuth/Extension/Data+extension.swift new file mode 100644 index 0000000..6b50f81 --- /dev/null +++ b/Sources/CustomAuth/Extension/Data+extension.swift @@ -0,0 +1,11 @@ +import Foundation + +internal extension Data { + func toBase64URL() -> String { + var result = base64EncodedString() + result = result.replacingOccurrences(of: "+", with: "-") + result = result.replacingOccurrences(of: "/", with: "_") + result = result.replacingOccurrences(of: "=", with: "") + return result + } +} diff --git a/Sources/CustomAuth/Extension/Dictionary.swift b/Sources/CustomAuth/Extension/Dictionary.swift deleted file mode 100644 index ec7c313..0000000 --- a/Sources/CustomAuth/Extension/Dictionary.swift +++ /dev/null @@ -1,78 +0,0 @@ -// -// File.swift -// -// -// Created by Shubham on 29/4/20. -// - -import Foundation - -extension Dictionary { - func join(_ other: Dictionary) -> Dictionary { - var joinedDictionary = Dictionary() - - for (key, value) in self { - joinedDictionary.updateValue(value, forKey: key) - } - - for (key, value) in other { - joinedDictionary.updateValue(value, forKey: key) - } - - return joinedDictionary - } - - var urlEncodedQuery: String { - var parts = [String]() - - for (key, value) in self { - let keyString = "\(key)".urlEncoded - let valueString = "\(value)".urlEncoded - let query = "\(keyString)=\(valueString)" - parts.append(query) - } - - return parts.joined(separator: "&") - } - - mutating func merge(_ dictionaries: [K: V]...) { - for dict in dictionaries { - for (key, value) in dict { - if let v = value as? Value, let k = key as? Key { - updateValue(v, forKey: k) - } - } - } - } - - func map(_ transform: (Key, Value) -> (K, V)) -> [K: V] { - var results: [K: V] = [:] - for k in keys { - if let value = self[k] { - let (u, w) = transform(k, value) - results.updateValue(w, forKey: u) - } - } - return results - } -} - -// -// extension Dictionary { -// @available(swift, introduced: 3.2, obsoleted: 4.0) -// public func filter(_ isIncluded: (Key, Value) throws -> Bool) rethrows -> [Key: Value] { -// var resultDictionary = [Key: Value](minimumCapacity: count) -// for (key, value) in self { -// if try isIncluded(key, value) { -// resultDictionary[key] = value -// } -// } -// return resultDictionary -// } -// } - -func += (left: inout [K: V], right: [K: V]) { left.merge(right) } -func + (left: [K: V], right: [K: V]) -> [K: V] { return left.join(right) } -func += (left: inout [K: V]?, right: [K: V]) { - if left != nil { left?.merge(right) } else { left = right } -} diff --git a/Sources/CustomAuth/Extension/OSLog.swift b/Sources/CustomAuth/Extension/OSLog.swift deleted file mode 100644 index 17f6127..0000000 --- a/Sources/CustomAuth/Extension/OSLog.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// Created by Michael Lee on 13/9/2021. -// - -import Foundation -import os.log - -public let subsystem = Bundle.main.bundleIdentifier ?? "com.torus.CustomAuth" -// -// typealias OriginalOSLogFunction = (_ message: StaticString, _ dso: UnsafeRawPointer? , _ log: OSLog , _ type: OSLogType , _ args: CVarArg...) -> Void -// -// typealias ConvertedOSLogFunction = (_ message: StaticString, _ dso: UnsafeRawPointer? , _ log: OSLog , _ type: OSLogType , _ args: [CVarArg]) -> Void -// -// let os_logv = unsafeBitCast(os_log as OriginalOSLogFunction, to: ConvertedOSLogFunction.self) - -public struct CASDKLogger { - static let inactiveLog = OSLog.disabled - static let core = OSLog(subsystem: subsystem, category: "core") -} - -@available(macOS 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) -func getTorusLogger(log: OSLog = .default, type: OSLogType = .default) -> OSLog { - var logCheck: OSLog { tsSdkLogType.rawValue <= type.rawValue ? log : CASDKLogger.inactiveLog } - return logCheck -} - -// @available(macOS 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) -// func log(_ message: StaticString, dso: UnsafeRawPointer? = #dsohandle, log: OSLog = .default, type: OSLogType = .default, _ args: CVarArg...){ -// var logCheck: OSLog { tsSdkLogType.rawValue <= type.rawValue ? log : TDSDKLogger.inactiveLog} -// os_logv(message, dso, logCheck, type, args) -// } diff --git a/Sources/CustomAuth/Extension/String+extension.swift b/Sources/CustomAuth/Extension/String+extension.swift new file mode 100644 index 0000000..989cc2e --- /dev/null +++ b/Sources/CustomAuth/Extension/String+extension.swift @@ -0,0 +1,60 @@ +import Foundation + +internal extension String { + func fromBase64URL() throws -> String { + var base64 = self + base64 = base64.replacingOccurrences(of: "-", with: "+") + base64 = base64.replacingOccurrences(of: "_", with: "/") + while base64.count % 4 != 0 { + base64 = base64.appending("=") + } + guard let data = Data(base64Encoded: base64) else { + throw CASDKError.decodingFailed + } + return String(data: data, encoding: .utf8)! + } + + var parametersFromQueryString: [String: String] { + return dictionaryBySplitting("&", keyValueSeparator: "=") + } + + func dictionaryBySplitting(_ elementSeparator: String, keyValueSeparator: String) -> [String: String] { + var string = self + + if hasPrefix(elementSeparator) { + string = String(dropFirst(1)) + } + + var parameters = [String: String]() + + let scanner = Scanner(string: string) + + while !scanner.isAtEnd { + let key = scanner.scanUpToString(keyValueSeparator) + _ = scanner.scanString(keyValueSeparator) + + let value = scanner.scanUpToString(elementSeparator) + _ = scanner.scanString(elementSeparator) + + if let key = key { + if let value = value { + if key.contains(elementSeparator) { + var keys = key.components(separatedBy: elementSeparator) + if let key = keys.popLast() { + parameters.updateValue(value, forKey: String(key)) + } + for flag in keys { + parameters.updateValue("", forKey: flag) + } + } else { + parameters.updateValue(value, forKey: key) + } + } else { + parameters.updateValue("", forKey: key) + } + } + } + + return parameters + } +} diff --git a/Sources/CustomAuth/Extension/String.swift b/Sources/CustomAuth/Extension/String.swift deleted file mode 100644 index 78bd290..0000000 --- a/Sources/CustomAuth/Extension/String.swift +++ /dev/null @@ -1,156 +0,0 @@ -import Foundation - -extension String { - var parametersFromQueryString: [String: String] { - return dictionaryBySplitting("&", keyValueSeparator: "=") - } - - /// Encodes url string making it ready to be passed as a query parameter. This encodes pretty much everything apart from - /// alphanumerics and a few other characters compared to standard query encoding. - var urlEncoded: String { - let customAllowedSet = CharacterSet(charactersIn: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~") - return addingPercentEncoding(withAllowedCharacters: customAllowedSet)! - } - - var urlQueryEncoded: String? { - return addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) - } - - /// Returns new url query string by appending query parameter encoding it first, if specified. - func urlQueryByAppending(parameter name: String, value: String, encode: Bool = true, _ encodeError: ((String, String) -> Void)? = nil) -> String? { - if value.isEmpty { - return self - } else if let value = encode ? value.urlQueryEncoded : value { - return "\(self)\(isEmpty ? "" : "&")\(name)=\(value)" - } else { - encodeError?(name, value) - return nil - } - } - - /// Returns new url string by appending query string at the end. - func urlByAppending(query: String) -> String { - return "\(self)\(contains("?") ? "&" : "?")\(query)" - } - - fileprivate func dictionaryBySplitting(_ elementSeparator: String, keyValueSeparator: String) -> [String: String] { - var string = self - - if hasPrefix(elementSeparator) { - string = String(dropFirst(1)) - } - - var parameters = [String: String]() - - let scanner = Scanner(string: string) - - while !scanner.isAtEnd { - if #available(iOS 13.0, tvOS 13.0, OSX 10.15, watchOS 6.0, *) { - let key = scanner.scanUpToString(keyValueSeparator) - _ = scanner.scanString(keyValueSeparator) - - let value = scanner.scanUpToString(elementSeparator) - _ = scanner.scanString(elementSeparator) - - if let key = key { - if let value = value { - if key.contains(elementSeparator) { - var keys = key.components(separatedBy: elementSeparator) - if let key = keys.popLast() { - parameters.updateValue(value, forKey: String(key)) - } - for flag in keys { - parameters.updateValue("", forKey: flag) - } - } else { - parameters.updateValue(value, forKey: key) - } - } else { - parameters.updateValue("", forKey: key) - } - } - } else { - var key: NSString? - scanner.scanUpTo(keyValueSeparator, into: &key) - scanner.scanString(keyValueSeparator, into: nil) - - var value: NSString? - scanner.scanUpTo(elementSeparator, into: &value) - scanner.scanString(elementSeparator, into: nil) - if let key = key as String? { - if let value = value as String? { - if key.contains(elementSeparator) { - var keys = key.components(separatedBy: elementSeparator) - if let key = keys.popLast() { - parameters.updateValue(value, forKey: String(key)) - } - for flag in keys { - parameters.updateValue("", forKey: flag) - } - } else { - parameters.updateValue(value, forKey: key) - } - } else { - parameters.updateValue("", forKey: key) - } - } - } - } - - return parameters - } - - static func randomString(length: Int) -> String { - let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" - return String((0 ..< length).map { _ in letters.randomElement()! }) - } - - func fromBase64URL() -> String? { - var base64 = self - base64 = base64.replacingOccurrences(of: "-", with: "+") - base64 = base64.replacingOccurrences(of: "_", with: "/") - while base64.count % 4 != 0 { - base64 = base64.appending("=") - } - guard let data = Data(base64Encoded: base64) else { - return nil - } - return String(data: data, encoding: .utf8) - } - - func toBase64URL() -> String { - var result = Data(utf8).base64EncodedString() - result = result.replacingOccurrences(of: "+", with: "-") - result = result.replacingOccurrences(of: "/", with: "_") - result = result.replacingOccurrences(of: "=", with: "") - return result - } - - var safeStringByRemovingPercentEncoding: String { - return self.removingPercentEncoding ?? self - } - - mutating func dropLast() { - remove(at: index(before: endIndex)) - } - - subscript(bounds: CountableClosedRange) -> String { - let start = index(startIndex, offsetBy: bounds.lowerBound) - let end = index(startIndex, offsetBy: bounds.upperBound) - return String(self[start ... end]) - } - - subscript(bounds: CountableRange) -> String { - let start = index(startIndex, offsetBy: bounds.lowerBound) - let end = index(startIndex, offsetBy: bounds.upperBound) - return String(self[start ..< end]) - } -} - -extension String.Encoding { - var charset: String { - let charset = CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding(rawValue)) - // swiftlint:disable:next force_cast superfluous_disable_command - return charset! as String - } -} diff --git a/Sources/CustomAuth/Extension/URLComponents+extension.swift b/Sources/CustomAuth/Extension/URLComponents+extension.swift new file mode 100644 index 0000000..c5edd08 --- /dev/null +++ b/Sources/CustomAuth/Extension/URLComponents+extension.swift @@ -0,0 +1,7 @@ +import Foundation + +internal extension URLComponents { + mutating func setQueryItems(with parameters: [String: String]) { + queryItems = parameters.map { URLQueryItem(name: $0.key, value: $0.value) } + } +} diff --git a/Sources/CustomAuth/Handlers/AuthenticationManager.swift b/Sources/CustomAuth/Handlers/AuthenticationManager.swift new file mode 100644 index 0000000..dce0268 --- /dev/null +++ b/Sources/CustomAuth/Handlers/AuthenticationManager.swift @@ -0,0 +1,52 @@ +import AuthenticationServices +#if os(macOS) + import AppKit +#else + import UIKit +#endif + +internal class AuthenticationManager: NSObject, ASWebAuthenticationPresentationContextProviding { + public func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor { + var window: ASPresentationAnchor? + #if os(macOS) + window = NSApplication.shared.windows.first { $0.isKeyWindow } + #else + window = UIApplication.shared.windows.first { $0.isKeyWindow } + #endif + + return window ?? ASPresentationAnchor() + } + + func webAuth(url: URL, callbackURLScheme: String, prefersEphemeralWebBrowserSession: Bool, + completion: @escaping (Result) -> Void) { + let authSession = ASWebAuthenticationSession(url: url, callbackURLScheme: callbackURLScheme) { url, error in + if let error = error { + completion(.failure(error)) + } else if let url = url { + completion(.success(url)) + } + } + + DispatchQueue.main.async { [weak self] in + guard let self = self else { + return + } + authSession.presentationContextProvider = self + authSession.prefersEphemeralWebBrowserSession = prefersEphemeralWebBrowserSession + authSession.start() + } + } + + public func authenticationManagerWrapper(url: URL, callbackURLScheme: String, prefersEphemeralWebBrowserSession: Bool) async throws -> URL { + return try await withCheckedThrowingContinuation { continuation in + webAuth(url: url, callbackURLScheme: callbackURLScheme, prefersEphemeralWebBrowserSession: prefersEphemeralWebBrowserSession) { result in + switch result { + case let .success(url): + continuation.resume(returning: url) + case let .failure(error): + continuation.resume(throwing: error) + } + } + } + } +} diff --git a/Sources/CustomAuth/Handlers/DiscordLoginHandler.swift b/Sources/CustomAuth/Handlers/DiscordLoginHandler.swift index 7a67eb0..d733793 100644 --- a/Sources/CustomAuth/Handlers/DiscordLoginHandler.swift +++ b/Sources/CustomAuth/Handlers/DiscordLoginHandler.swift @@ -1,80 +1,61 @@ -// -// DiscordLoginHandler.swift -// -// -// Created by Shubham on 13/11/20. -// - import Foundation -class DiscordLoginHandler: AbstractLoginHandler { - let loginType: SubVerifierType - let clientID: String - let redirectURL: String - let browserRedirectURL: String? - let state: String - var userInfo: [String: Any]? - let nonce = String.randomString(length: 10) - let jwtParams: [String: String] - let defaultParams: [String: String] - var urlSession: URLSession +internal class DiscordInfo: Codable { + public var id: String + public var username: String + public var avatar: String? + public var discriminator: String + public var email: String +} - public init(loginType: SubVerifierType = .web, clientID: String, redirectURL: String, browserRedirectURL: String?, jwtParams: [String: String] = [:], urlSession: URLSession = URLSession.shared) { - self.loginType = loginType - self.clientID = clientID - self.redirectURL = redirectURL - self.jwtParams = jwtParams - self.browserRedirectURL = browserRedirectURL - defaultParams = ["scope": "email identify", "response_type": "token"] - self.urlSession = urlSession +internal class DiscordLoginHandler: AbstractLoginHandler { + private var response_type: String = "token" + private var scope: String = "identify email" + private var prompt: String = "none" - let tempState = ["nonce": nonce, "redirectUri": self.redirectURL, "redirectToAndroid": "true"] - let jsonData = try! JSONSerialization.data(withJSONObject: tempState, options: .prettyPrinted) - state = String(data: jsonData, encoding: .utf8)!.toBase64URL() + override public init(clientId: String, verifier: String, urlScheme: String, redirectURL: String, typeOfLogin: LoginType, jwtParams: Auth0ClientOptions? = nil, customState: TorusGenericContainer? = nil) throws { + try super.init(clientId: clientId, verifier: verifier, urlScheme: urlScheme, redirectURL: redirectURL, typeOfLogin: typeOfLogin, jwtParams: jwtParams, customState: customState) + try setFinalUrl() } - func getUserInfo(responseParameters: [String: String]) async throws -> [String: Any] { - return try await handleLogin(responseParameters: responseParameters) - } + override public func setFinalUrl() throws { + var urlComponents = URLComponents() - func getLoginURL() -> String { - // left join - var tempParams = defaultParams - tempParams.merge(["redirect_uri": browserRedirectURL ?? redirectURL, "client_id": clientID, "state": state]) { _, new in new } - tempParams.merge(jwtParams) { _, new in new } + var params: [String: String] = [:] - // Reconstruct URL - var urlComponents = URLComponents() + if jwtParams != nil { + params = try (JSONSerialization.jsonObject(with: try JSONEncoder().encode(jwtParams), options: []) as! [String: String]) + } + + params.merge([ + "state": try state(), + "response_type": response_type, + "client_id": clientId, + "redirect_uri": redirectURL, + "prompt": prompt, + "scope": scope], uniquingKeysWith: { _, new in new }) urlComponents.scheme = "https" urlComponents.host = "discord.com" urlComponents.path = "/api/oauth2/authorize" - urlComponents.setQueryItems(with: tempParams) + urlComponents.setQueryItems(with: params) - return urlComponents.url!.absoluteString - // return "https://discord.com/api/oauth2/authorize?response_type=token" + "&client_id=\(self.clientId)&scope=email identify&redirect_uri=\(newRedirectURL)".addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)! + finalUrl = urlComponents } - func getVerifierFromUserInfo() -> String { - return userInfo?["id"] as? String ?? "" - } - - func handleLogin(responseParameters: [String: String]) async throws -> [String: Any] { - if let accessToken = responseParameters["access_token"] { - var request = makeUrlRequest(url: "https://discordapp.com/api/users/@me", method: "GET") - request.addValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization") - do { - let val = try await urlSession.data(for: request) - let data = try JSONSerialization.jsonObject(with: val.0) as? [String: Any] ?? [:] - userInfo = data - var newData: [String: Any] = ["userInfo": userInfo as Any] - newData["tokenForKeys"] = accessToken - newData["verifierId"] = getVerifierFromUserInfo() - return newData - } catch { - throw CASDKError.getUserInfoFailed - } - } else { + override public func getUserInfo(params: LoginWindowResponse, storageServerUrl: String?) async throws -> TorusVerifierResponse { + guard let accessToken = params.accessToken else { throw CASDKError.accessTokenNotProvided } + + var urlRequest = makeUrlRequest(url: "https://discord.com/api/users/@me", method: "GET") + urlRequest.addValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization") + + let (data, _) = try await URLSession.shared.data(for: urlRequest) + let result = try JSONDecoder().decode(DiscordInfo.self, from: data) + + let profileImage = result.avatar == nil ? "https://cdn.discordapp.com/embed/avatars/" + String(Int(result.discriminator)! % 5) + ".png" : + "https://cdn.discordapp.com/avatars/${id}/" + result.avatar! + ".png?size=2048" + + return TorusVerifierResponse(email: result.email, name: result.username + "#" + result.discriminator, profileImage: profileImage, verifier: verifier, verifierId: result.id, typeOfLogin: typeOfLogin) } } diff --git a/Sources/CustomAuth/Handlers/FacebookLoginHandler.swift b/Sources/CustomAuth/Handlers/FacebookLoginHandler.swift index 7d8a51f..0081886 100644 --- a/Sources/CustomAuth/Handlers/FacebookLoginHandler.swift +++ b/Sources/CustomAuth/Handlers/FacebookLoginHandler.swift @@ -1,82 +1,64 @@ -// -// GoogleLoginHandler.swift -// -// -// Created by Shubham on 13/11/20. -// - import Foundation -class FacebookLoginHandler: AbstractLoginHandler { - let loginType: SubVerifierType - let clientID: String - let redirectURL: String - let browserRedirectURL: String? - let nonce = String.randomString(length: 10) - let state: String - var userInfo: [String: Any]? - let jwtParams: [String: String] - let defaultParams: [String: String] - var urlSession: URLSession +internal class FacebookPictureData: Codable { + public var url: String +} - public init(loginType: SubVerifierType = .web, clientID: String, redirectURL: String, browserRedirectURL: String?, jwtParams: [String: String] = [:], urlSession: URLSession = URLSession.shared) { - self.loginType = loginType - self.clientID = clientID - self.redirectURL = redirectURL - self.jwtParams = jwtParams - self.browserRedirectURL = browserRedirectURL - self.defaultParams = ["scope": "public_profile email", "response_type": "token"] - self.urlSession = urlSession +internal class FacebookPicture: Codable { + public var data: FacebookPictureData +} - let tempState = ["nonce": self.nonce, "redirectUri": self.redirectURL, "redirectToAndroid": "true"] - let jsonData = try! JSONSerialization.data(withJSONObject: tempState, options: .prettyPrinted) - self.state = String(data: jsonData, encoding: .utf8)!.toBase64URL() - } +internal class FacebookInfo: Codable { + public var id: String + public var name: String + public var picture: FacebookPicture + public var email: String +} - func getUserInfo(responseParameters: [String: String]) async throws -> [String: Any] { - return try await self.handleLogin(responseParameters: responseParameters) - } +internal class FacebookLoginHandler: AbstractLoginHandler { + private var response_type: String = "token" + private var scope: String = "public_profile email" - func getLoginURL() -> String { - // left join - var tempParams = self.defaultParams - tempParams.merge(["redirect_uri": self.browserRedirectURL ?? self.redirectURL, "client_id": self.clientID, "state": self.state]) {(_, new ) in new} - tempParams.merge(self.jwtParams) {(_, new ) in new} + override public init(clientId: String, verifier: String, urlScheme: String, redirectURL: String, typeOfLogin: LoginType, jwtParams: Auth0ClientOptions? = nil, customState: TorusGenericContainer? = nil) throws { + try super.init(clientId: clientId, verifier: verifier, urlScheme: urlScheme, redirectURL: redirectURL, typeOfLogin: typeOfLogin, jwtParams: jwtParams, customState: customState) + try setFinalUrl() + } - // Reconstruct URL + override public func setFinalUrl() throws { var urlComponents = URLComponents() + + var params: [String: String] = [:] + + if jwtParams != nil { + params = try (JSONSerialization.jsonObject(with: try JSONEncoder().encode(jwtParams), options: []) as! [String: String]) + } + + params.merge([ + "state": try state(), + "response_type": response_type, + "client_id": clientId, + "redirect_uri": redirectURL, + "scope": scope], uniquingKeysWith: { _, new in new }) urlComponents.scheme = "https" urlComponents.host = "www.facebook.com" - urlComponents.path = "/v6.0/dialog/oauth" - urlComponents.setQueryItems(with: tempParams) - - return urlComponents.url!.absoluteString - // return "https://www.facebook.com/v6.0/dialog/oauth?response_type=token&client_id=\(self.clientId)" + "&state=random&scope=public_profile email&redirect_uri=\(newRedirectURL)".addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)! - } + urlComponents.path = "/v15.0/dialog/oauth" + urlComponents.setQueryItems(with: params) - func getVerifierFromUserInfo() -> String { - return self.userInfo?["id"] as? String ?? "" + finalUrl = urlComponents } - func handleLogin(responseParameters: [String: String]) async throws -> [String: Any] { - - if let accessToken = responseParameters["access_token"] { - var request = makeUrlRequest(url: "https://graph.facebook.com/me?fields=name,email,picture.type(large)", method: "GET") - request.addValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization") - do { - let val = try await self.urlSession.data(for: request) - let data = try JSONSerialization.jsonObject(with: val.0) as? [String: Any] ?? [:] - self.userInfo = data - var newData: [String: Any] = ["userInfo": self.userInfo as Any] - newData["tokenForKeys"] = accessToken - newData["verifierId"] = self.getVerifierFromUserInfo() - return newData - } catch { - throw CASDKError.getUserInfoFailed - } - } else { + override public func getUserInfo(params: LoginWindowResponse, storageServerUrl: String?) async throws -> TorusVerifierResponse { + guard let accessToken = params.accessToken else { throw CASDKError.accessTokenNotProvided } - } + var urlRequest = makeUrlRequest(url: "https://graph.facebook.com/me?fields=name,email,picture.type(large)", method: "GET") + urlRequest.addValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization") + + let (data, _) = try await URLSession.shared.data(for: urlRequest) + + let result = try JSONDecoder().decode(FacebookInfo.self, from: data) + + return TorusVerifierResponse(email: result.email, name: result.name, profileImage: result.picture.data.url, verifier: verifier, verifierId: result.id, typeOfLogin: typeOfLogin) + } } diff --git a/Sources/CustomAuth/Handlers/GoogleLoginHandler.swift b/Sources/CustomAuth/Handlers/GoogleLoginHandler.swift index 6d10fe7..c733582 100644 --- a/Sources/CustomAuth/Handlers/GoogleLoginHandler.swift +++ b/Sources/CustomAuth/Handlers/GoogleLoginHandler.swift @@ -1,123 +1,59 @@ -// -// GoogleLoginHandler.swift -// -// -// Created by Shubham on 13/11/20. -// - import Foundation -class GoogleloginHandler: AbstractLoginHandler { - let loginType: SubVerifierType - let clientID: String - let redirectURL: String - let browserRedirectURL: String? - var userInfo: [String: Any]? - let nonce = String.randomString(length: 10) - let state: String - let jwtParams: [String: String] - let defaultParams: [String: String] - var urlSession: URLSession +internal class GoogleInfo: Codable { + public var name: String + public var picture: String + public var email: String +} - public init(loginType: SubVerifierType = .web, clientID: String, redirectURL: String, browserRedirectURL: String?, jwtParams: [String: String] = [:], urlSession: URLSession = URLSession.shared) { - self.loginType = loginType - self.clientID = clientID - self.redirectURL = redirectURL - self.jwtParams = jwtParams - self.browserRedirectURL = browserRedirectURL - self.defaultParams = ["nonce": nonce, "scope": "profile+email+openid"] - self.urlSession = urlSession +internal class GoogleLoginHandler: AbstractLoginHandler { + private var response_type: String = "token id_token" + private var scope: String = "profile email openid" + private var prompt: String = "select_account" - let tempState = ["nonce": self.nonce, "redirectUri": self.redirectURL, "redirectToAndroid": "true"] - let jsonData = try! JSONSerialization.data(withJSONObject: tempState, options: .prettyPrinted) - self.state = String(data: jsonData, encoding: .utf8)!.toBase64URL() + override public init(clientId: String, verifier: String, urlScheme: String, redirectURL: String, typeOfLogin: LoginType, jwtParams: Auth0ClientOptions? = nil, customState: TorusGenericContainer? = nil) throws { + try super.init(clientId: clientId, verifier: verifier, urlScheme: urlScheme, redirectURL: redirectURL, typeOfLogin: typeOfLogin, jwtParams: jwtParams, customState: customState) + try setFinalUrl() } - func getUserInfo(responseParameters: [String: String]) async throws -> [String: Any] { - return try await self.handleLogin(responseParameters: responseParameters) - } + override public func setFinalUrl() throws { + var urlComponents = URLComponents() - func getLoginURL() -> String { - // handling different OAuth applications - let googleResponseType: String - switch self.loginType { - case .installed: googleResponseType = "code" - case .web: googleResponseType = "id_token+token" - } + var params: [String: String] = [:] - // left join - var tempParams = self.defaultParams - tempParams.merge(["redirect_uri": self.browserRedirectURL ?? self.redirectURL, "client_id": self.clientID, "response_type": googleResponseType, "state": self.state]) {(_, new ) in new} - tempParams.merge(self.jwtParams) {(_, new ) in new} + if jwtParams != nil { + params = try (JSONSerialization.jsonObject(with: try JSONEncoder().encode(jwtParams), options: []) as! [String: String]) + } - // Reconstruct URL - var urlComponents = URLComponents() + params.merge([ + "state": try state(), + "response_type": response_type, + "client_id": clientId, + "prompt": prompt, + "redirect_uri": redirectURL, + "scope": scope, + "nonce": nonce, + ], uniquingKeysWith: { _, new in new }) urlComponents.scheme = "https" urlComponents.host = "accounts.google.com" urlComponents.path = "/o/oauth2/v2/auth" - urlComponents.setQueryItems(with: tempParams) - return urlComponents.url!.absoluteString -// return "https://accounts.google.com/o/oauth2/v2/auth?response_type=\(googleResponseType)&client_id=\(self.clientID)&nonce=123&redirect_uri=\(self.redirectURL)&scope=profile+email+openid" - } + urlComponents.setQueryItems(with: params) - func getVerifierFromUserInfo() -> String { - return self.userInfo?["email"] as? String ?? "" + finalUrl = urlComponents } - func handleLogin(responseParameters: [String: String]) async throws -> [String: Any] { + override public func getUserInfo(params: LoginWindowResponse, storageServerUrl: String?) async throws -> TorusVerifierResponse { + guard let accessToken = params.accessToken else { + throw CASDKError.accessTokenNotProvided + } + + var urlRequest = makeUrlRequest(url: "https://www.googleapis.com/userinfo/v2/me", method: "GET") + urlRequest.addValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization") - switch self.loginType { - case .installed: - var request: URLRequest = makeUrlRequest(url: "https://oauth2.googleapis.com/token", method: "POST") - var data: Data - if let code = responseParameters["code"] { - request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") - data = "grant_type=authorization_code&redirect_uri=\(self.redirectURL)&client_id=\(self.clientID)&code=\(code)".data(using: .utf8)! + let (data, _) = try await URLSession.shared.data(for: urlRequest) - request.httpBody = data - // Send request to retreive access token and id_token - do { - let val = try await self.urlSession.data(for: request) - let valData = try JSONSerialization.jsonObject(with: val.0) as? [String: Any] ?? [:] - // Retreive user info - if let accessToken = valData["access_token"], let idToken = valData["id_token"] { - var request = makeUrlRequest(url: "https://www.googleapis.com/userinfo/v2/me", method: "GET") - request.addValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization") - let val2 = try await urlSession.data(for: request) - let data = val2.0 - let dictionary = try JSONSerialization.jsonObject(with: data, options: []) as! [String: Any] - self.userInfo = dictionary - var newData: [String: Any] = ["userInfo": self.userInfo as Any] - newData["tokenForKeys"] = idToken - newData["verifierId"] = self.getVerifierFromUserInfo() - return newData - } else { - throw CASDKError.accessTokenNotProvided - } - } catch { - throw CASDKError.accessTokenAPIFailed - } - } else { - throw CASDKError.authGrantNotProvided - } - case .web: - if let accessToken = responseParameters["access_token"], let idToken = responseParameters["id_token"] { - var request = makeUrlRequest(url: "https://www.googleapis.com/userinfo/v2/me", method: "GET") - request.addValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization") - do { - let val = try await self.urlSession.data(for: request) - let data = try JSONSerialization.jsonObject(with: val.0) as? [String: Any] ?? [:] - self.userInfo = data - var newData: [String: Any] = ["userInfo": self.userInfo as Any] - newData["tokenForKeys"] = idToken - newData["verifierId"] = self.getVerifierFromUserInfo() - return newData - } catch { - throw CASDKError.accessTokenAPIFailed - } - } else { - throw CASDKError.getUserInfoFailed - } - } + let result = try JSONDecoder().decode(GoogleInfo.self, from: data) + + return TorusVerifierResponse(email: result.email, name: result.name, profileImage: result.picture, verifier: verifier, verifierId: result.email.lowercased(), typeOfLogin: typeOfLogin) } } diff --git a/Sources/CustomAuth/Handlers/HandlerFactory.swift b/Sources/CustomAuth/Handlers/HandlerFactory.swift new file mode 100644 index 0000000..aee28ed --- /dev/null +++ b/Sources/CustomAuth/Handlers/HandlerFactory.swift @@ -0,0 +1,48 @@ +import Foundation + +internal class HandlerFactory { + static func createHandler( + params: CreateHandlerParams + ) throws -> ILoginHandler { + if params.verifier.isEmpty { + throw CASDKError.invalidVerifier + } + + if params.clientId.isEmpty { + throw CASDKError.invalidClientID + } + + switch params.typeOfLogin { + case .google: + return try GoogleLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin, jwtParams: params.jwtParams, customState: params.customState) + case .facebook: + return try FacebookLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin, jwtParams: params.jwtParams, customState: params.customState) + case .reddit: + return try RedditLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin, jwtParams: params.jwtParams, customState: params.customState) + case .twitch: + return try TwitchLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin, jwtParams: params.jwtParams, customState: params.customState) + case .discord: + return try DiscordLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin, jwtParams: params.jwtParams, customState: params.customState) + case .apple: break + case .github: break + case .linkedin: break + case .twitter: break + case .weibo: break + case .line: break + case .email_password: break + case .passwordless: return try PasswordlessLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin, jwtParams: params.jwtParams, customState: params.customState) + } + + + if params.jwtParams?.id_token != nil || params.jwtParams?.access_token != nil { + return try MockLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin, jwtParams: params.jwtParams, customState: params.customState) + } + + let domain = params.jwtParams?.domain + if domain == nil { + throw CASDKError.invalidAuth0Options + } + + return try JWTLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin, jwtParams: params.jwtParams, customState: params.customState) + } +} diff --git a/Sources/CustomAuth/Handlers/JWTLoginHandler.swift b/Sources/CustomAuth/Handlers/JWTLoginHandler.swift index 41a8a80..0599e02 100644 --- a/Sources/CustomAuth/Handlers/JWTLoginHandler.swift +++ b/Sources/CustomAuth/Handlers/JWTLoginHandler.swift @@ -1,129 +1,101 @@ -// -// File.swift -// -// -// Created by Shubham on 13/11/20. -// - import Foundation import JWTDecode -import TorusUtils -class JWTLoginHandler: AbstractLoginHandler { - let loginType: SubVerifierType - let clientID: String - let redirectURL: String - let browserRedirectURL: String? - var userInfo: [String: Any]? - let nonce = String.randomString(length: 10) - let state: String - let defaultParams: [String: String] - let jwtParams: [String: String] - let connection: LoginProviders - var urlSession: URLSession +internal class Auth0UserInfo: Codable { + public let picture: String + public let email: String + public let name: String + public let sub: String + public let nickname: String + + public init(picture: String, email: String, name: String, sub: String, nickname: String) { + self.picture = picture + self.email = email + self.name = name + self.sub = sub + self.nickname = nickname + } +} - public init(loginType: SubVerifierType = .web, clientID: String, redirectURL: String, browserRedirectURL: String?, jwtParams: [String: String], connection: LoginProviders, urlSession: URLSession = URLSession.shared) { - self.loginType = loginType - self.clientID = clientID - self.redirectURL = redirectURL - self.connection = connection - self.browserRedirectURL = browserRedirectURL - self.jwtParams = jwtParams - defaultParams = ["scope": "openid profile email", "response_type": "token id_token", "nonce": nonce] - self.urlSession = urlSession +internal class JWTLoginHandler: AbstractLoginHandler { + private var response_type: String = "token id_token" + private var scope: String = "openid profile email" + private var prompt: String = "login" - let tempState = ["nonce": nonce, "redirectUri": self.redirectURL, "redirectToAndroid": "true"] - let jsonData = try! JSONSerialization.data(withJSONObject: tempState, options: .prettyPrinted) - state = String(data: jsonData, encoding: .utf8)!.toBase64URL() -// self.state = ["nonce": self.nonce, "redirectUri": self.redirectURL, "redirectToAndroid": "true"].description.toBase64URL() + override public init(clientId: String, verifier: String, urlScheme: String, redirectURL: String, typeOfLogin: LoginType, jwtParams: Auth0ClientOptions? = nil, customState: TorusGenericContainer? = nil) throws { + try super.init(clientId: clientId, verifier: verifier, urlScheme: urlScheme, redirectURL: redirectURL, typeOfLogin: typeOfLogin, jwtParams: jwtParams, customState: customState) + try setFinalUrl() } - func getUserInfo(responseParameters: [String: String]) async throws -> [String: Any] { - return try await handleLogin(responseParameters: responseParameters) - } + override public func setFinalUrl() throws { + var urlComponents = URLComponents() - func getLoginURL() -> String { - // left join - var tempParams = defaultParams - let paramsToJoin: [String: String] = ["redirect_uri": browserRedirectURL ?? redirectURL, "client_id": clientID, "domain": jwtParams["domain"]!, "state": state] - tempParams.merge(paramsToJoin) { _, new in new } - tempParams.merge(jwtParams) { _, new in new } + if jwtParams == nil { + throw CASDKError.invalidAuth0Options + } + + var connection = jwtParams?.connection + if connection == nil { + connection = loginToConnection(loginType: typeOfLogin) + } - // Reconstruct URL - var urlComponents = URLComponents() + let encoded = try JSONEncoder().encode(jwtParams) + let serialized = try JSONSerialization.jsonObject(with: encoded, options: [.fragmentsAllowed, .mutableContainers]) + + var params: [String: String] = serialized as! [String: String] + params.merge([ + "state": try state(), + "response_type": response_type, + "client_id": clientId, + "prompt": prompt, + "redirect_uri": redirectURL, + "scope": scope, + "connection": connection!, + "nonce": nonce, + ], uniquingKeysWith: { _, new in new }) urlComponents.scheme = "https" - urlComponents.host = jwtParams["domain"] - urlComponents.path = "/authorize" - urlComponents.setQueryItems(with: tempParams) + urlComponents.host = jwtParams?.domain + urlComponents.path = "/passwordless/start" + urlComponents.setQueryItems(with: params) - // return string - return urlComponents.url!.absoluteString + finalUrl = urlComponents } - func getVerifierFromUserInfo() -> String { - var res: String - let lowerCased = jwtParams["isVerifierIdCaseSensitive"] ?? "false" + override public func getUserInfo(params: LoginWindowResponse, storageServerUrl: String?) async throws -> TorusVerifierResponse { + let accessToken = params.accessToken + let idToken = params.idToken + let verifierIdField = jwtParams?.verifierIdField + let isVerifierCaseSensitive = jwtParams?.isVerifierIdCaseSensitive != nil ? Bool(jwtParams!.isVerifierIdCaseSensitive)! : true - if jwtParams["verifierIdField"] != nil { - let field = jwtParams["verifierIdField"]! - res = userInfo![field] as! String - } else { - switch connection { - case .apple, .weibo, .github, .twitter, .linkedin, .line, .jwt: - res = userInfo!["sub"] as! String - case .email_password: - res = userInfo!["name"] as! String - default: - return "verifier not supported" + if accessToken != nil { + let domain = jwtParams?.domain + var user_route_info = jwtParams?.user_info_route ?? "/userinfo" + + if !user_route_info.hasPrefix("/") { + user_route_info = "/" + user_route_info } - } - if lowerCased == "true" { - return res.lowercased() - } else { - return res - } - } + var urlComponents = URLComponents() + urlComponents.scheme = "https" + urlComponents.host = domain + urlComponents.path = user_route_info - func handleLogin(responseParameters: [String: String]) async throws -> [String: Any] { + var urlRequest = makeUrlRequest(url: urlComponents.string!, method: "GET") + urlRequest.addValue("Bearer \(accessToken!)", forHTTPHeaderField: "Authorization") - // Reconstruct URL - var urlComponents = URLComponents() - urlComponents.scheme = "https" - urlComponents.host = jwtParams["domain"] - urlComponents.path = "/userinfo" + let (data, _) = try await URLSession.shared.data(for: urlRequest) + let result = try JSONDecoder().decode(Auth0UserInfo.self, from: data) - if let accessToken = responseParameters["access_token"] { - var request = makeUrlRequest(url: urlComponents.url!.absoluteString, method: "GET") - request.addValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization") - do { - let val = try await urlSession.data(for: request) - let data = try JSONSerialization.jsonObject(with: val.0) as? [String: Any] ?? [:] - self.userInfo = data - if responseParameters["error"] != nil { - throw responseParameters["error"]! - } - var newData: [String: Any] = ["userInfo": self.userInfo as Any] - newData["tokenForKeys"] = responseParameters["id_token"] - newData["verifierId"] = self.getVerifierFromUserInfo() - return newData + return TorusVerifierResponse(email: result.email, name: result.name, profileImage: result.picture, verifier: verifier, verifierId: try jwtParams?.verifierIdField ?? getVerifierId(userInfo: result, typeOfLogin: typeOfLogin, verifierIdField: verifierIdField, isVerifierIdCaseSensitive: isVerifierCaseSensitive), typeOfLogin: typeOfLogin) + } - } catch { - throw CASDKError.getUserInfoFailed - } - } else if let idToken = responseParameters["id_token"] { - do { - let decodedData = try decode(jwt: idToken) - userInfo = decodedData.body - var newData: [String: Any] = userInfo! - newData["tokenForKeys"] = idToken - newData["verifierId"] = getVerifierFromUserInfo() - return newData - } catch { - throw TorusUtilError.runtime("Invalid ID toke") - } + if idToken == nil { + throw CASDKError.idTokenNotProvided } else { - throw CASDKError.accessTokenNotProvided + let decodedToken = try decode(jwt: idToken!) + 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 ?? "") + + return TorusVerifierResponse(email: result.email, name: result.name, profileImage: result.picture, verifier: verifier, verifierId: try jwtParams?.verifierIdField ?? getVerifierId(userInfo: result, typeOfLogin: typeOfLogin, verifierIdField: verifierIdField, isVerifierIdCaseSensitive: isVerifierCaseSensitive), typeOfLogin: typeOfLogin) } } } diff --git a/Sources/CustomAuth/Handlers/MockLoginHandler.swift b/Sources/CustomAuth/Handlers/MockLoginHandler.swift new file mode 100644 index 0000000..df17a0f --- /dev/null +++ b/Sources/CustomAuth/Handlers/MockLoginHandler.swift @@ -0,0 +1,91 @@ +import Foundation +import JWTDecode + +internal class MockLoginHandler: AbstractLoginHandler { + override public init(clientId: String, verifier: String, urlScheme: String, redirectURL: String, typeOfLogin: LoginType, jwtParams: Auth0ClientOptions? = nil, customState: TorusGenericContainer? = nil) throws { + try super.init(clientId: clientId, verifier: verifier, urlScheme: urlScheme, redirectURL: redirectURL, typeOfLogin: typeOfLogin, jwtParams: jwtParams, customState: customState) + try setFinalUrl() + } + + override public func setFinalUrl() throws { + if jwtParams == nil { + throw CASDKError.invalidAuth0Options + } + + var connection = jwtParams?.connection + if connection == nil { + connection = loginToConnection(loginType: typeOfLogin) + } + + var params: [String: String] = try (JSONSerialization.jsonObject(with: try JSONEncoder().encode(jwtParams), options: []) as! [String: String]) + params.merge([ + "state": try state(), + "client_id": clientId, + "connection": connection!, + "nonce": nonce, + ], uniquingKeysWith: { _, new in new }) + + var urlComponents = URLComponents() + urlComponents.scheme = "https" + urlComponents.host = jwtParams?.domain + urlComponents.path = "/authorize" + urlComponents.fragment = params.compactMap({ (key, value) -> String in + return "\(key)=\(value)" + }).joined(separator: "&") + finalUrl = urlComponents + } + + public override func handleLoginWindow(popupFeatures: String?) async throws -> LoginWindowResponse { + + let urlWithTokenInfo = URL(string: finalUrl.string!)! + + var tokenInfo = parseURL(url: urlWithTokenInfo) + let access_token = tokenInfo["access_token"] + let id_token = tokenInfo["id_token"] + let ref = tokenInfo["ref"] + + tokenInfo.removeValue(forKey: "access_token") + tokenInfo.removeValue(forKey: "id_token") + tokenInfo.removeValue(forKey: "ref") + return LoginWindowResponse(accessToken: access_token, idToken: id_token, ref: ref ?? "", state: TorusGenericContainer(params: tokenInfo)) + } + + override public func getUserInfo(params: LoginWindowResponse, storageServerUrl: String?) async throws -> TorusVerifierResponse { + let accessToken = params.accessToken + let idToken = params.idToken + let verifierIdField = jwtParams?.verifierIdField + let isVerifierCaseSensitive = jwtParams?.isVerifierIdCaseSensitive != nil ? Bool(jwtParams!.isVerifierIdCaseSensitive)! : true + + if accessToken != nil { + let domain = jwtParams?.domain + var user_route_info = jwtParams?.user_info_route ?? "/userinfo" + + if !user_route_info.hasPrefix("/") { + user_route_info = "/" + user_route_info + } + + var urlComponents = URLComponents() + urlComponents.scheme = "https" + urlComponents.host = domain + urlComponents.path = user_route_info + + var urlRequest = makeUrlRequest(url: urlComponents.string!, method: "GET") + urlRequest.addValue("Bearer \(accessToken!)", forHTTPHeaderField: "Authorization") + + let (data, _) = try await URLSession.shared.data(for: urlRequest) + + let result = try JSONDecoder().decode(Auth0UserInfo.self, from: data) + + return TorusVerifierResponse(email: result.email, name: result.name, profileImage: result.picture, verifier: verifier, verifierId: try jwtParams?.verifierIdField ?? getVerifierId(userInfo: result, typeOfLogin: typeOfLogin, verifierIdField: verifierIdField, isVerifierIdCaseSensitive: isVerifierCaseSensitive), typeOfLogin: typeOfLogin) + } + + if idToken == nil { + throw CASDKError.idTokenNotProvided + } else { + let decodedToken = try decode(jwt: idToken!) + 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 ?? "") + + return TorusVerifierResponse(email: result.email, name: result.name, profileImage: result.picture, verifier: verifier, verifierId: try jwtParams?.verifierIdField ?? getVerifierId(userInfo: result, typeOfLogin: typeOfLogin, verifierIdField: verifierIdField, isVerifierIdCaseSensitive: isVerifierCaseSensitive), typeOfLogin: typeOfLogin) + } + } +} diff --git a/Sources/CustomAuth/Handlers/PasswordlessLoginHandler.swift b/Sources/CustomAuth/Handlers/PasswordlessLoginHandler.swift new file mode 100644 index 0000000..2176c18 --- /dev/null +++ b/Sources/CustomAuth/Handlers/PasswordlessLoginHandler.swift @@ -0,0 +1,85 @@ +import Foundation +import JWTDecode + +internal class PasswordlessLoginHandler: AbstractLoginHandler { + private var response_type: String = "token id_token" + private var scope: String = "openid profile email" + private var prompt: String = "login" + + override public init(clientId: String, verifier: String, urlScheme: String, redirectURL: String, typeOfLogin: LoginType, jwtParams: Auth0ClientOptions? = nil, customState: TorusGenericContainer? = nil) throws { + try super.init(clientId: clientId, verifier: verifier, urlScheme: urlScheme, redirectURL: redirectURL, typeOfLogin: typeOfLogin, jwtParams: jwtParams, customState: customState) + try setFinalUrl() + } + + override public func setFinalUrl() throws { + var urlComponents = URLComponents() + + if jwtParams == nil { + throw CASDKError.invalidAuth0Options + } + + var connection = jwtParams?.connection + if connection == nil { + connection = loginToConnection(loginType: typeOfLogin) + } + + let encoded = try JSONEncoder().encode(jwtParams) + let serialized = try JSONSerialization.jsonObject(with: encoded, options: [.fragmentsAllowed, .mutableContainers]) + + var params: [String: String] = serialized as! [String: String] + params.merge([ + "state": try state(), + "response_type": response_type, + "client_id": clientId, + "prompt": prompt, + "redirect_uri": redirectURL, + "scope": scope, + "connection": connection!, + "nonce": nonce, + ], uniquingKeysWith: { _, new in new }) + urlComponents.scheme = "https" + urlComponents.host = jwtParams?.domain + urlComponents.path = "/authorize" + urlComponents.setQueryItems(with: params) + + finalUrl = urlComponents + } + + override public func getUserInfo(params: LoginWindowResponse, storageServerUrl: String?) async throws -> TorusVerifierResponse { + let accessToken = params.accessToken + let idToken = params.idToken + let verifierIdField = jwtParams?.verifierIdField + let isVerifierCaseSensitive = jwtParams?.isVerifierIdCaseSensitive != nil ? Bool(jwtParams!.isVerifierIdCaseSensitive)! : true + + if accessToken != nil { + let domain = jwtParams?.domain + var user_route_info = jwtParams?.user_info_route ?? "/userinfo" + + if !user_route_info.hasPrefix("/") { + user_route_info = "/" + user_route_info + } + + var urlComponents = URLComponents() + urlComponents.scheme = "https" + urlComponents.host = domain + urlComponents.path = user_route_info + + var urlRequest = makeUrlRequest(url: urlComponents.string!, method: "GET") + urlRequest.addValue("Bearer \(accessToken!)", forHTTPHeaderField: "Authorization") + + let (data, _) = try await URLSession.shared.data(for: urlRequest) + let result = try JSONDecoder().decode(Auth0UserInfo.self, from: data) + + return TorusVerifierResponse(email: result.email, name: result.name, profileImage: result.picture, verifier: verifier, verifierId: try jwtParams?.verifierIdField ?? getVerifierId(userInfo: result, typeOfLogin: typeOfLogin, verifierIdField: verifierIdField, isVerifierIdCaseSensitive: isVerifierCaseSensitive), typeOfLogin: typeOfLogin) + } + + if idToken == nil { + throw CASDKError.idTokenNotProvided + } else { + let decodedToken = try decode(jwt: idToken!) + 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 ?? "") + + return TorusVerifierResponse(email: result.email, name: result.name, profileImage: result.picture, verifier: verifier, verifierId: try jwtParams?.verifierIdField ?? getVerifierId(userInfo: result, typeOfLogin: typeOfLogin, verifierIdField: verifierIdField, isVerifierIdCaseSensitive: isVerifierCaseSensitive), typeOfLogin: typeOfLogin) + } + } +} diff --git a/Sources/CustomAuth/Handlers/Protocol/AbstractLoginHandler.swift b/Sources/CustomAuth/Handlers/Protocol/AbstractLoginHandler.swift index 06d9e37..464fd7f 100644 --- a/Sources/CustomAuth/Handlers/Protocol/AbstractLoginHandler.swift +++ b/Sources/CustomAuth/Handlers/Protocol/AbstractLoginHandler.swift @@ -1,15 +1,69 @@ -// -// AbstractLoginHandler.swift -// -// -// Created by Shubham on 13/11/20. -// - import Foundation +#if canImport(curveSecp256k1) + import curveSecp256k1 +#endif + +internal class AbstractLoginHandler: ILoginHandler { + public var clientId: String + + public var nonce: String + + public var finalUrl: URLComponents + + public var urlScheme: String + + public var redirectURL: String + + public var verifier: String + + public var typeOfLogin: LoginType + + public var jwtParams: Auth0ClientOptions? + + public var customState: TorusGenericContainer? + + public init(clientId: String, verifier: String, urlScheme: String, redirectURL: String, typeOfLogin: LoginType, jwtParams: Auth0ClientOptions? = nil, customState: TorusGenericContainer? = nil) throws { + self.clientId = clientId + nonce = try SecretKey().serialize().addLeading0sForLength64() + finalUrl = URLComponents() + self.verifier = verifier + self.urlScheme = urlScheme + self.typeOfLogin = typeOfLogin + self.jwtParams = jwtParams + self.customState = customState + self.redirectURL = redirectURL + } + + public func state() throws -> String { + let encoder = JSONEncoder() + encoder.outputFormatting = .sortedKeys + let state = State(instanceId: nonce, verifier: verifier, typeOfLogin: typeOfLogin.rawValue, redirectUri: urlScheme, customState: customState) + return try encoder.encode(state).toBase64URL() + } + + public func getUserInfo(params: LoginWindowResponse, storageServerUrl: String?) async throws -> TorusVerifierResponse { + fatalError("getUserInfo must be implemented by concrete classes") + } + + public func handleLoginWindow(popupFeatures: String?) async throws -> LoginWindowResponse { + guard let callbackURLScheme = URL(string: urlScheme)?.scheme else { + throw CASDKError.invalidCallbackURLScheme + } + + let urlWithTokenInfo = try await AuthenticationManager().authenticationManagerWrapper(url: finalUrl.url!, callbackURLScheme: callbackURLScheme, prefersEphemeralWebBrowserSession: false) + + var tokenInfo = parseURL(url: urlWithTokenInfo) + let access_token = tokenInfo["access_token"] + let id_token = tokenInfo["id_token"] + let ref = tokenInfo["ref"] + + tokenInfo.removeValue(forKey: "access_token") + tokenInfo.removeValue(forKey: "id_token") + tokenInfo.removeValue(forKey: "ref") + return LoginWindowResponse(accessToken: access_token, idToken: id_token, ref: ref ?? "", state: TorusGenericContainer(params: tokenInfo)) + } -public protocol AbstractLoginHandler { - func getLoginURL() -> String - func getUserInfo(responseParameters: [String: String]) async throws -> [String: Any] - func getVerifierFromUserInfo() -> String - func handleLogin(responseParameters: [String: String]) async throws -> [String: Any] + public func setFinalUrl() throws { + throw CASDKError.invalidMethod(msg: "setFinalUrl cannot be called by abstract class") + } } diff --git a/Sources/CustomAuth/Handlers/Protocol/CreateHandlerParams.swift b/Sources/CustomAuth/Handlers/Protocol/CreateHandlerParams.swift new file mode 100644 index 0000000..5db8380 --- /dev/null +++ b/Sources/CustomAuth/Handlers/Protocol/CreateHandlerParams.swift @@ -0,0 +1,21 @@ +import Foundation + +internal class CreateHandlerParams: Codable { + public let typeOfLogin: LoginType + public let verifier: String + public let clientId: String + public let urlScheme: String + public let redirectURL: String + public let jwtParams: Auth0ClientOptions? + public let customState: TorusGenericContainer? + + public init(typeOfLogin: LoginType, verifier: String, clientId: String, urlScheme: String, redirectURL: String, jwtParams: Auth0ClientOptions? = nil, customState: TorusGenericContainer? = nil) { + self.typeOfLogin = typeOfLogin + self.verifier = verifier + self.clientId = clientId + self.urlScheme = urlScheme + self.jwtParams = jwtParams + self.customState = customState + self.redirectURL = redirectURL + } +} diff --git a/Sources/CustomAuth/Handlers/Protocol/ILoginHandler.swift b/Sources/CustomAuth/Handlers/Protocol/ILoginHandler.swift new file mode 100644 index 0000000..3201741 --- /dev/null +++ b/Sources/CustomAuth/Handlers/Protocol/ILoginHandler.swift @@ -0,0 +1,13 @@ +import Foundation + +internal protocol ILoginHandler { + var clientId: String { get set } + var nonce: String { get set } + var finalUrl: URLComponents { get set } + + func getUserInfo(params: LoginWindowResponse, storageServerUrl: String?) async throws -> TorusVerifierResponse + + func handleLoginWindow(popupFeatures: String?) async throws -> LoginWindowResponse + + func setFinalUrl() throws +} diff --git a/Sources/CustomAuth/Handlers/RedditLoginHandler.swift b/Sources/CustomAuth/Handlers/RedditLoginHandler.swift index 2f4248f..85ab16e 100644 --- a/Sources/CustomAuth/Handlers/RedditLoginHandler.swift +++ b/Sources/CustomAuth/Handlers/RedditLoginHandler.swift @@ -1,82 +1,58 @@ -// -// RedditLoginHandler.swift -// -// -// Created by Shubham on 13/11/20. -// - import Foundation -class RedditLoginHandler: AbstractLoginHandler { - let loginType: SubVerifierType - let clientID: String - let redirectURL: String - let browserRedirectURL: String? - var userInfo: [String: Any]? - let nonce = String.randomString(length: 10) - let state: String - let jwtParams: [String: String] - let defaultParams: [String: String] - var urlSession: URLSession +internal class RedditInfo: Codable { + public var name: String + public var icon_image: String? +} - public init(loginType: SubVerifierType = .web, clientID: String, redirectURL: String, browserRedirectURL: String?, jwtParams: [String: String] = [:], urlSession: URLSession = URLSession.shared) { - self.loginType = loginType - self.clientID = clientID - self.redirectURL = redirectURL - self.jwtParams = jwtParams - self.browserRedirectURL = browserRedirectURL - self.defaultParams = ["scope": "identity", "response_type": "token", "state": "randomstate"] - self.urlSession = urlSession +internal class RedditLoginHandler: AbstractLoginHandler { + private var response_type: String = "token" + private var scope: String = "identity" - let tempState = ["nonce": self.nonce, "redirectUri": self.redirectURL, "redirectToAndroid": "true"] - let jsonData = try! JSONSerialization.data(withJSONObject: tempState, options: .prettyPrinted) - self.state = String(data: jsonData, encoding: .utf8)!.toBase64URL() + override public init(clientId: String, verifier: String, urlScheme: String, redirectURL: String, typeOfLogin: LoginType, jwtParams: Auth0ClientOptions? = nil, customState: TorusGenericContainer? = nil) throws { + try super.init(clientId: clientId, verifier: verifier, urlScheme: urlScheme, redirectURL: redirectURL, typeOfLogin: typeOfLogin, jwtParams: jwtParams, customState: customState) + try setFinalUrl() } - func getUserInfo(responseParameters: [String: String]) async throws -> [String: Any] { - return try await self.handleLogin(responseParameters: responseParameters) - } + override public func setFinalUrl() throws { + var urlComponents = URLComponents() - func getLoginURL() -> String { - // left join - var tempParams = self.defaultParams - tempParams.merge(["redirect_uri": self.browserRedirectURL ?? self.redirectURL, "client_id": self.clientID, "state": self.state]) {(_, new ) in new} - tempParams.merge(self.jwtParams) {(_, new ) in new} + var params: [String: String] = [:] - // Reconstruct URL - var urlComponents = URLComponents() + if jwtParams != nil { + params = try (JSONSerialization.jsonObject(with: try JSONEncoder().encode(jwtParams), options: []) as! [String: String]) + } + + params.merge([ + "state": try state(), + "response_type": response_type, + "client_id": clientId, + "redirect_uri": redirectURL, + "scope": scope, + ], uniquingKeysWith: { _, new in new }) urlComponents.scheme = "https" urlComponents.host = "www.reddit.com" urlComponents.path = "/api/v1/authorize" - urlComponents.setQueryItems(with: tempParams) - - return urlComponents.url!.absoluteString - // return "https://www.reddit.com/api/v1/authorize?client_id=\(self.clientId)&redirect_uri=\(newRedirectURL)&response_type=token&scope=identity&state=dfasdfs" - } + urlComponents.setQueryItems(with: params) - func getVerifierFromUserInfo() -> String { - return self.userInfo?["name"] as? String ?? "" + finalUrl = urlComponents } - func handleLogin(responseParameters: [String: String]) async throws -> [String: Any] { - - if let accessToken = responseParameters["access_token"] { - var request = makeUrlRequest(url: "https://oauth.reddit.com/api/v1/me", method: "GET") - request.addValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization") - do { - let val = try await self.urlSession.data(for: request) - let data = try JSONSerialization.jsonObject(with: val.0) as? [String: Any] ?? [:] - self.userInfo = data - var newData: [String: Any] = ["userInfo": self.userInfo as Any] - newData["tokenForKeys"] = accessToken - newData["verifierId"] = self.getVerifierFromUserInfo() - return newData - } catch { - throw CASDKError.getUserInfoFailed - } - } else { + override public func getUserInfo(params: LoginWindowResponse, storageServerUrl: String?) async throws -> TorusVerifierResponse { + guard let accessToken = params.accessToken else { throw CASDKError.accessTokenNotProvided } - } + var urlRequest = makeUrlRequest(url: "https://oauth.reddit.com/api/v1/me", method: "GET") + urlRequest.addValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization") + + let (data, _) = try await URLSession.shared.data(for: urlRequest) + + let result = try JSONDecoder().decode(RedditInfo.self, from: data) + + var profileImage = result.icon_image ?? "" + profileImage = profileImage.split(separator: "?").count > 0 ? String(profileImage.split(separator: "?")[0]) : profileImage + + return TorusVerifierResponse(email: "", name: result.name, profileImage: profileImage, verifier: verifier, verifierId: result.name.lowercased(), typeOfLogin: typeOfLogin) + } } diff --git a/Sources/CustomAuth/Handlers/TwitchLoginHandler.swift b/Sources/CustomAuth/Handlers/TwitchLoginHandler.swift index 958e9e1..1723669 100644 --- a/Sources/CustomAuth/Handlers/TwitchLoginHandler.swift +++ b/Sources/CustomAuth/Handlers/TwitchLoginHandler.swift @@ -1,87 +1,66 @@ -// -// GoogleLoginHandler.swift -// -// -// Created by Shubham on 13/11/20. -// - import Foundation -class TwitchLoginHandler: AbstractLoginHandler { - let loginType: SubVerifierType - let clientID: String - let redirectURL: String - let browserRedirectURL: String? - var userInfo: [String: Any]? - let nonce = String.randomString(length: 10) - let state: String - let jwtParams: [String: String] - let defaultParams: [String: String] = ["scope": "user:read:email", "response_type": "token", "force_verify": "false"] - var urlSession: URLSession +internal class TwitchInfo: Codable { + public var id: String + public var email: String? + public var display_name: String + public var profile_image_url: String +} - public init(loginType: SubVerifierType = .web, clientID: String, redirectURL: String, browserRedirectURL: String?, jwtParams: [String: String] = [:], urlSession: URLSession = URLSession.shared) { - self.loginType = loginType - self.clientID = clientID - self.redirectURL = redirectURL - self.jwtParams = jwtParams - self.browserRedirectURL = browserRedirectURL - self.urlSession = urlSession +internal class TwitchRootInfo: Codable { + public var data: [TwitchInfo] +} - let tempState = ["nonce": self.nonce, "redirectUri": self.redirectURL, "redirectToAndroid": "true"] - let jsonData = try! JSONSerialization.data(withJSONObject: tempState, options: .prettyPrinted) - self.state = String(data: jsonData, encoding: .utf8)!.toBase64URL() - } +internal class TwitchLoginHandler: AbstractLoginHandler { + private var response_type: String = "token" + private var scope: String = "user:read:email" - func getUserInfo(responseParameters: [String: String]) async throws-> [String: Any] { - return try await self.handleLogin(responseParameters: responseParameters) + override public init(clientId: String, verifier: String, urlScheme: String, redirectURL: String, typeOfLogin: LoginType, jwtParams: Auth0ClientOptions? = nil, customState: TorusGenericContainer? = nil) throws { + try super.init(clientId: clientId, verifier: verifier, urlScheme: urlScheme, redirectURL: redirectURL, typeOfLogin: typeOfLogin, jwtParams: jwtParams, customState: customState) + try setFinalUrl() } - func getLoginURL() -> String { - // left join - var tempParams = self.defaultParams - tempParams.merge(["redirect_uri": self.browserRedirectURL ?? self.redirectURL, "client_id": self.clientID, "state": self.state]) {(_, new ) in new} - tempParams.merge(self.jwtParams) {(_, new ) in new} - - // Reconstruct URL + override public func setFinalUrl() throws { var urlComponents = URLComponents() + + var params: [String: String] = [:] + + if jwtParams != nil { + params = try (JSONSerialization.jsonObject(with: try JSONEncoder().encode(jwtParams), options: []) as! [String: String]) + } + + params.merge([ + "state": try state(), + "response_type": response_type, + "client_id": clientId, + "redirect_uri": redirectURL, + "scope": scope, + "force_verify": "true", + ], uniquingKeysWith: { _, new in new }) urlComponents.scheme = "https" urlComponents.host = "id.twitch.tv" urlComponents.path = "/oauth2/authorize" - urlComponents.setQueryItems(with: tempParams) + urlComponents.setQueryItems(with: params) - return urlComponents.url!.absoluteString - // return "https://id.twitch.tv/oauth2/authorize?client_id=p560duf74b2bidzqu6uo0b3ot7qaao&"+"redirect_uri=\(newRedirectURL)&response_type=token&scope=user:read:email&state=554455&force_verify=false".addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)! + finalUrl = urlComponents } - func getVerifierFromUserInfo() -> String { - if let newData = self.userInfo?["data"] as? [[String: Any]], let temp = newData.first, let id = temp["id"] as? String { - return id - } else { - return "nil" + override public func getUserInfo(params: LoginWindowResponse, storageServerUrl: String?) async throws -> TorusVerifierResponse { + guard let accessToken = params.accessToken else { + throw CASDKError.accessTokenNotProvided } - } - - func handleLogin(responseParameters: [String: String]) async throws -> [String: Any] { - if let accessToken = responseParameters["access_token"] { - var request = makeUrlRequest(url: "https://api.twitch.tv/helix/users", method: "GET") - request.addValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization") - request.addValue("p560duf74b2bidzqu6uo0b3ot7qaao", forHTTPHeaderField: "Client-ID") - do { - let val = try await self.urlSession.data(for: request) - let data = try JSONSerialization.jsonObject(with: val.0) as? [String: Any] ?? [:] - self.userInfo = data - var newData: [String: Any] = ["userInfo": self.userInfo as Any] - newData["tokenForKeys"] = accessToken - newData["verifierId"] = self.getVerifierFromUserInfo() - return newData - - } catch { - throw CASDKError.getUserInfoFailed - } - } else { - throw CASDKError.accessTokenNotProvided + var urlRequest = makeUrlRequest(url: "https://api.twitch.tv/helix/users", method: "GET") + urlRequest.addValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization") + urlRequest.addValue(self.clientId, forHTTPHeaderField: "Client-ID") + + let (data, _) = try await URLSession.shared.data(for: urlRequest) + let result = try JSONDecoder().decode(TwitchRootInfo.self, from: data) + + guard let userdata = result.data.first else { + throw CASDKError.decodingFailed } - } + return TorusVerifierResponse(email: userdata.email ?? "", name: userdata.display_name, profileImage: userdata.profile_image_url, verifier: verifier, verifierId: userdata.id, typeOfLogin: typeOfLogin) + } } diff --git a/Sources/CustomAuth/Helpers/ASWebAuthSession.swift b/Sources/CustomAuth/Helpers/ASWebAuthSession.swift deleted file mode 100644 index 3b66d6d..0000000 --- a/Sources/CustomAuth/Helpers/ASWebAuthSession.swift +++ /dev/null @@ -1,44 +0,0 @@ -// -// File.swift -// -// -// Created by Dhruv Jaiswal on 05/08/22. -// - -import AuthenticationServices -import Foundation - -open class ASWebAuthSession: NSObject, TorusURLHandlerTypes { - var redirectURL: URL? - // Ensure that there is a strong reference to the ASWebAuthenticationSession instance when the session is in progress. - private var authSession: ASWebAuthenticationSession? - public init(redirectURL: String) { - self.redirectURL = URL(string: redirectURL) - } - - public func handle(_ url: URL, modalPresentationStyle: UIModalPresentationStyle) { - let redirectURLScheme = redirectURL?.scheme ?? CustomAuth.didHandleCallbackURL.rawValue - authSession = ASWebAuthenticationSession( - url: url, callbackURLScheme: redirectURLScheme) { callbackURL, authError in - guard - authError == nil, - let callbackURL = callbackURL - else { - print(authError?.localizedDescription as? String ?? "") - let errStr = authError?.localizedDescription as? String ?? "Something went wrong!!" - CustomAuth.handleError(err: errStr) - return - } - CustomAuth.handle(url: callbackURL) - } - authSession?.presentationContextProvider = self - authSession?.start() - } -} - -extension ASWebAuthSession: ASWebAuthenticationPresentationContextProviding { - public func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor { - let window = UIApplication.shared.windows.first { $0.isKeyWindow } - return window ?? ASPresentationAnchor() - } -} diff --git a/Sources/CustomAuth/Helpers/Common.swift b/Sources/CustomAuth/Helpers/Common.swift new file mode 100644 index 0000000..2915de4 --- /dev/null +++ b/Sources/CustomAuth/Helpers/Common.swift @@ -0,0 +1,107 @@ +import Foundation + +internal func loginToConnection(loginType: LoginType) -> String { + switch loginType { + case .apple: break + case .google: break + case .facebook: break + case .reddit: break + case .twitch: break + case .discord: break + case .github: break + case .linkedin: break + case .twitter: break + case .weibo: break + case .line: break + case .email_password: return "Username-Password-Authentication" + case .passwordless: return "email" + } + return loginType.rawValue +} + +internal func getVerifierId( + userInfo: Auth0UserInfo, + typeOfLogin: LoginType, + verifierIdField: String? = nil, + isVerifierIdCaseSensitive: Bool = true +) throws -> String { + let name = userInfo.name + let sub = userInfo.sub + + let encoded = try JSONEncoder().encode(userInfo) + let json = try JSONSerialization.jsonObject(with: encoded, options: []) as! [String: String] + + if verifierIdField != nil { + return json[isVerifierIdCaseSensitive ? verifierIdField!.lowercased() : verifierIdField!]! + } + + switch typeOfLogin { + case .google: return sub + case .facebook: return sub + case .reddit: return sub + case .twitch: return sub + case .apple: return sub + case .github: return sub + case .discord: return sub + case .linkedin: return sub + case .twitter: return sub + case .weibo: return sub + case .line: return sub + case .email_password: return name + case .passwordless: return name + } +} + +func handleRedirectParameters(hash: String, queryParameters: TorusGenericContainer) throws -> (String, TorusGenericContainer, TorusGenericContainer) { + var hashParams: [String: String] = [:] + let hashSplit = hash.split(separator: "&") + hashSplit.forEach({ + let paramSplit = $0.split(separator: "=") + hashParams.updateValue(String(paramSplit[1]), forKey: String(paramSplit[0])) + }) + + var instanceParams: [String: String] = [:] + var error = "" + if hashParams.count > 0 && hashParams["state"] != nil { + let instanceSplit = try hashParams["state"]!.fromBase64URL().split(separator: "&") + instanceSplit.forEach({ + let paramSplit = $0.split(separator: "=") + instanceParams.updateValue(String(paramSplit[1]), forKey: String(paramSplit[0])) + }) + if hashParams["error_description"] != nil { + error = hashParams["error_description"]! + } else if hashParams["error"] != nil { + error = hashParams["error"]! + } + } else if queryParameters.params.count > 0 && queryParameters.params["state"] != nil { + let instanceSplit = try queryParameters.params["state"]!.fromBase64URL().split(separator: "&") + instanceSplit.forEach({ + let paramSplit = $0.split(separator: "=") + instanceParams.updateValue(String(paramSplit[1]), forKey: String(paramSplit[0])) + }) + if queryParameters.params["error"] != nil { + error = queryParameters.params["error"]! + } + } + + return (error, TorusGenericContainer(params: hashParams), TorusGenericContainer(params: instanceParams)) +} + +func parseURL(url: URL) -> [String: String] { + var responseParameters = [String: String]() + if let query = url.query { + responseParameters.merge(query.parametersFromQueryString, uniquingKeysWith: { _, new in new }) + } + if let fragment = url.fragment, !fragment.isEmpty { + responseParameters.merge(fragment.parametersFromQueryString, uniquingKeysWith: { _, new in new }) + } + return responseParameters +} + +func makeUrlRequest(url: String, method: String) -> URLRequest { + var rq = URLRequest(url: URL(string: url)!) + rq.httpMethod = method + rq.addValue("application/json", forHTTPHeaderField: "Content-Type") + rq.addValue("application/json", forHTTPHeaderField: "Accept") + return rq +} diff --git a/Sources/CustomAuth/Helpers/Error.swift b/Sources/CustomAuth/Helpers/Error.swift index e92ef0f..2af425d 100644 --- a/Sources/CustomAuth/Helpers/Error.swift +++ b/Sources/CustomAuth/Helpers/Error.swift @@ -1,31 +1,40 @@ public enum CASDKError: Error { - case getUserInfoFailed case decodingFailed - case accessTokenAPIFailed + case encodingFailed case accessTokenNotProvided - case authGrantNotProvided - case idTokenFailed - case unknownError - case methodUnavailable + case idTokenNotProvided + case invalidParameters + case invalidCallbackURLScheme + case invalidAuth0Options + case invalidVerifier + case invalidClientID + case invalidMethod(msg: String) + case redirectParamsError(msg: String) public var errorDescription: String { switch self { - case .getUserInfoFailed: - return "Unable to get verifier ID" case .decodingFailed: - return "decodingFailed" - case .accessTokenAPIFailed: - return "API failed for retrieving access token" + return "decoding failed" + case .encodingFailed: + return "encoding failed" case .accessTokenNotProvided: - return "access token unavailable in data" - case .authGrantNotProvided: - return "authorization grant not available" - case .idTokenFailed: - return "idTokenFailed" - case .unknownError: - return "unknownError" - case .methodUnavailable: - return "method unavailable/unimplemented" + return "access token not provided" + case .idTokenNotProvided: + return "id token not provided" + case .invalidCallbackURLScheme: + return "callback scheme is invalid" + case .invalidParameters: + return "parameters are missing or invalid" + case .invalidAuth0Options: + return "auth0 options are missing or invalid" + case .invalidMethod(msg: let msg): + return msg + case .redirectParamsError(msg: let msg): + return msg + case .invalidVerifier: + return "invalid verifier" + case .invalidClientID: + return "invalid client ID" } } } diff --git a/Sources/CustomAuth/Helpers/ExternalURLHandler.swift b/Sources/CustomAuth/Helpers/ExternalURLHandler.swift deleted file mode 100644 index caef7b3..0000000 --- a/Sources/CustomAuth/Helpers/ExternalURLHandler.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// ExternalURLHandler.swift -// -// -// Created by Shubham on 18/6/20. -// - -import Foundation -import UIKit - -class ExternalURLHandler: TorusURLHandlerTypes { - @objc open func handle(_ url: URL, modalPresentationStyle: UIModalPresentationStyle) { - #if os(iOS) || os(tvOS) - #if !OAUTH_APP_EXTENSIONS - if #available(iOS 10.0, tvOS 10.0, *) { - UIApplication.shared.open(url) - } else { - UIApplication.shared.openURL(url) - } - #endif - #elseif os(watchOS) - // WATCHOS: not implemented - #elseif os(OSX) - NSWorkspace.shared.open(url) - #endif - } -} diff --git a/Sources/CustomAuth/Helpers/SFURLHandler.swift b/Sources/CustomAuth/Helpers/SFURLHandler.swift deleted file mode 100644 index 5b02f62..0000000 --- a/Sources/CustomAuth/Helpers/SFURLHandler.swift +++ /dev/null @@ -1,92 +0,0 @@ -// MARK: Open SFSafariViewController - -import Foundation -import SafariServices - -import UIKit - -open class SFURLHandler: NSObject, SFSafariViewControllerDelegate, TorusURLHandlerTypes { - public typealias Transition = (_ controller: SFSafariViewController, _ handler: SFURLHandler) -> Void - open var present: Transition - open var dismiss: Transition - var observers = [String: NSObjectProtocol]() - - // configure default presentation and dismissal code - open var animated: Bool = true - open var presentCompletion: (() -> Void)? - open var dismissCompletion: (() -> Void)? - open var delay: UInt32? = 1 - - /// init - public init(viewController: UIViewController) { - present = { [weak viewController] controller, handler in - viewController?.present(controller, animated: handler.animated, completion: handler.presentCompletion) - } - dismiss = { [weak viewController] _, handler in - viewController?.dismiss(animated: handler.animated, completion: handler.dismissCompletion) - } - } - - public init(present: @escaping Transition, dismiss: @escaping Transition) { - // self.oauthSwift = oauthSwift - self.present = present - self.dismiss = dismiss - } - - @objc open func handle(_ url: URL, modalPresentationStyle: UIModalPresentationStyle = .fullScreen) { - let controller = SFSafariViewController(url: url) - controller.modalPresentationStyle = modalPresentationStyle - controller.dismissButtonStyle = .cancel - controller.delegate = self - - // Present on main queue - present(controller, self) - - let key = UUID().uuidString - - observers[key] = CustomAuth.notificationCenter.addObserver( - forName: CustomAuth.didHandleCallbackURL, - object: nil, - queue: OperationQueue.main, - using: { _ in - if let observer = self.observers[key] { - CustomAuth.notificationCenter.removeObserver(observer) - self.observers.removeValue(forKey: key) - } - self.dismiss(controller, self) - // TODO: dismiss on main queue - } - ) - } - - /// Clear internal observers on authentification flow - open func clearObservers() { - clearLocalObservers() - // self.CustomAuth?.removeCallbackNotificationObserver() - } - - open func clearLocalObservers() { - for (_, observer) in observers { - CustomAuth.notificationCenter.removeObserver(observer) - } - observers.removeAll() - } - - /// SFSafari delegates implementation - open weak var delegate: SFSafariViewControllerDelegate? - - public func safariViewController(_ controller: SFSafariViewController, activityItemsFor URL: Foundation.URL, title: String?) -> [UIActivity] { - return delegate?.safariViewController?(controller, activityItemsFor: URL, title: title) ?? [] - } - - public func safariViewControllerDidFinish(_ controller: SFSafariViewController) { - // "Done" pressed - clearObservers() - dismiss(controller, self) - delegate?.safariViewControllerDidFinish?(controller) - } - - public func safariViewController(_ controller: SFSafariViewController, didCompleteInitialLoad didLoadSuccessfully: Bool) { - delegate?.safariViewController?(controller, didCompleteInitialLoad: didLoadSuccessfully) - } -} diff --git a/Sources/CustomAuth/Helpers/URL.swift b/Sources/CustomAuth/Helpers/URL.swift deleted file mode 100644 index d2fac35..0000000 --- a/Sources/CustomAuth/Helpers/URL.swift +++ /dev/null @@ -1,63 +0,0 @@ -// -// File.swift -// -// -// Created by Shubham on 13/11/20. -// - -import Foundation - -func makeUrlRequest(url: String, method: String) -> URLRequest { - var rq = URLRequest(url: URL(string: url)!) - rq.httpMethod = method - rq.addValue("application/json", forHTTPHeaderField: "Content-Type") - rq.addValue("application/json", forHTTPHeaderField: "Accept") - return rq -} - -extension URLComponents { - mutating func setQueryItems(with parameters: [String: String]) { - queryItems = parameters.map { URLQueryItem(name: $0.key, value: $0.value) } - } -} - -extension URL { - var queryDictionary: [String: String]? { - guard let query = query else { return nil } - - var queryStrings = [String: String]() - for pair in query.components(separatedBy: "&") { - let key = pair.components(separatedBy: "=")[0] - - let value = pair - .components(separatedBy: "=")[1] - .replacingOccurrences(of: "+", with: " ") - .removingPercentEncoding ?? "" - - queryStrings[key] = value - } - return queryStrings - } -} - -/* -Fix for the issue - https://www.swiftbysundell.com/articles/making-async-system-apis-backward-compatible/ -*/ -@available(iOS, deprecated: 15.0, message: "Use the built-in API instead") -extension URLSession { - func data(for request: URLRequest, delegate: URLSessionTaskDelegate? = nil) async throws -> (Data, URLResponse) { - try await withCheckedThrowingContinuation { continuation in - let task = self.dataTask(with: request) { data, response, error in - guard let data = data, let response = response else { - let error = error ?? URLError(.badServerResponse) - return continuation.resume(throwing: error) - } - - continuation.resume(returning: (data, response)) - } - - task.resume() - } - } -} diff --git a/Sources/CustomAuth/Models/Browser.swift b/Sources/CustomAuth/Models/Browser.swift deleted file mode 100644 index 78862e3..0000000 --- a/Sources/CustomAuth/Models/Browser.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// Browser.swift -// -// Created by Shubham on 18/6/20. -// - -import Foundation -import UIKit - -public protocol TorusURLHandlerTypes { - func handle(_ url: URL, modalPresentationStyle: UIModalPresentationStyle) -} - -public enum URLOpenerTypes: String { - case external - case sfsafari - case asWebAuthSession -} diff --git a/Sources/CustomAuth/Models/LoginProviders.swift b/Sources/CustomAuth/Models/LoginProviders.swift deleted file mode 100644 index 267ee77..0000000 --- a/Sources/CustomAuth/Models/LoginProviders.swift +++ /dev/null @@ -1,38 +0,0 @@ -import Foundation - -// MARK: - login providers - -public enum LoginProviders: String { - case google - case facebook - case twitch - case reddit - case discord - case apple - case github - case linkedin - case kakao - case twitter - case weibo - case line - case wechat - case email_password = "Username-Password-Authentication" - case jwt - - func getHandler(loginType: SubVerifierType, clientID: String, redirectURL: String, browserRedirectURL: String?, jwtParams: [String: String], urlSession: URLSession = URLSession.shared) -> AbstractLoginHandler { - switch self { - case .google: - return GoogleloginHandler(loginType: loginType, clientID: clientID, redirectURL: redirectURL, browserRedirectURL: browserRedirectURL, jwtParams: jwtParams, urlSession: urlSession) - case .facebook: - return FacebookLoginHandler(loginType: loginType, clientID: clientID, redirectURL: redirectURL, browserRedirectURL: browserRedirectURL, jwtParams: jwtParams, urlSession: urlSession) - case .twitch: - return TwitchLoginHandler(loginType: loginType, clientID: clientID, redirectURL: redirectURL, browserRedirectURL: browserRedirectURL, jwtParams: jwtParams, urlSession: urlSession) - case .reddit: - return RedditLoginHandler(loginType: loginType, clientID: clientID, redirectURL: redirectURL, browserRedirectURL: browserRedirectURL, jwtParams: jwtParams, urlSession: urlSession) - case .discord: - return DiscordLoginHandler(loginType: loginType, clientID: clientID, redirectURL: redirectURL, browserRedirectURL: browserRedirectURL, jwtParams: jwtParams, urlSession: urlSession) - case .apple, .github, .linkedin, .twitter, .weibo, .kakao, .line, .wechat, .email_password, .jwt: - return JWTLoginHandler(loginType: loginType, clientID: clientID, redirectURL: redirectURL, browserRedirectURL: browserRedirectURL, jwtParams: jwtParams, connection: self, urlSession: urlSession) - } - } -} diff --git a/Sources/CustomAuth/Models/SubVerifierDetails.swift b/Sources/CustomAuth/Models/SubVerifierDetails.swift deleted file mode 100644 index 1fac38f..0000000 --- a/Sources/CustomAuth/Models/SubVerifierDetails.swift +++ /dev/null @@ -1,49 +0,0 @@ -// -// SubverifierDetails.swift -// -// -// Created by Shubham on 1/6/20. -// -import Foundation - -// Type of OAuth application created. ex. google web app/google iOS app -public enum SubVerifierType: String { - case installed - case web -} - -// MARK: - subverifierdetails - -public struct SubVerifierDetails { - public let loginType: SubVerifierType - public let clientId: String - public let verifier: String - public let loginProvider: LoginProviders - public let redirectURL: String - public let handler: AbstractLoginHandler - public var urlSession: URLSession - - public enum codingKeys: String, CodingKey { - case clientId - case loginProvider - case subVerifierId - } - - public init(loginType: SubVerifierType = .web, loginProvider: LoginProviders, clientId: String, verifier: String, redirectURL: String, browserRedirectURL: String? = nil, jwtParams: [String: String] = [:], urlSession: URLSession = URLSession.shared) { - self.loginType = loginType - self.clientId = clientId - self.loginProvider = loginProvider - self.verifier = verifier - self.redirectURL = redirectURL - self.urlSession = urlSession - handler = self.loginProvider.getHandler(loginType: loginType, clientID: self.clientId, redirectURL: self.redirectURL, browserRedirectURL: browserRedirectURL, jwtParams: jwtParams, urlSession: urlSession) - } - - public func getLoginURL() -> String { - return handler.getLoginURL() - } - - public func getUserInfo(responseParameters: [String: String]) async throws -> [String: Any] { - return try await handler.getUserInfo(responseParameters: responseParameters) - } -} diff --git a/Tests/CustomAuthTests/CustomAuthTests.swift b/Tests/CustomAuthTests/CustomAuthTests.swift index dd9aee3..585dd13 100644 --- a/Tests/CustomAuthTests/CustomAuthTests.swift +++ b/Tests/CustomAuthTests/CustomAuthTests.swift @@ -1,114 +1,10 @@ -@testable import CustomAuth +import Foundation import JWTDecode -import TorusUtils -import UIKit import XCTest -import curveSecp256k1 -final class MockSDKTest: XCTestCase { +final class CustomAuthTests: XCTestCase { func test_jwtDecodeTest() { let idToken = "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL3RvcnVzLmF1LmF1dGgwLmNvbS8iLCJhdWQiOiJLRzd6azg5WDNRZ3R0U3lYOU5KNGZHRXlGTmhPY0pUdyIsIm5hbWUiOiJkaHJ1dkB0b3IudXMiLCJlbWFpbCI6ImRocnV2QHRvci51cyIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwiLCJpYXQiOjE2NTQ2NzcwMTQsImVhdCI6MTY1NDY3NzMxNCwiZXhwIjoxNjU0Njc3MzE0fQ.3nzDGeSiQwfTVmL4T4-e5N19eD280GjtosFzcGjhWv_sUCV2YkM3i7iFIpUq7AxoPXjai5v7GTTPRu1zHPL6bg" - let decodedData = try! decode(jwt: idToken) - print(decodedData) - } - - func testGetTorusKey() async throws { - let expectation = XCTestExpectation(description: "getTorusKey should correctly proxy input and output to/from TorusUtils") - - let expectedPrivateKey = try fakeData.generatePrivateKey() - let expectedPublicAddress = try fakeData.generatePublicKey() - let expectedVerifier = fakeData.generateVerifier() - let expectedVerfierId = fakeData.generateRandomEmail(of: 6) - - let CustomAuth = CustomAuth(web3AuthClientId:"YOUR_CLIENT_ID", aggregateVerifierType: .singleLogin, aggregateVerifier: expectedVerifier, subVerifierDetails: [], network: .legacy(.MAINNET)) - - let mockTorusUtils = MockTorusUtils() - CustomAuth.torusUtils = mockTorusUtils - // Set Mock data - mockTorusUtils.retrieveShares_output["privateKey"] = expectedPrivateKey - mockTorusUtils.retrieveShares_output["publicAddress"] = expectedPublicAddress - do { - let nodeDetails = try await CustomAuth.getNodeDetailsFromContract(verifier: expectedVerifier, verfierID: expectedVerfierId) - let data = try await CustomAuth.getTorusKey(verifier: expectedVerifier, verifierId: expectedVerfierId, idToken: fakeData.generateVerifier()) - let mockTorusUtils = CustomAuth.torusUtils as! MockAbstractTorusUtils - let FinalKeyData = data.finalKeyData! - print(FinalKeyData) - XCTAssertEqual(mockTorusUtils.retrieveShares_input["endpoints"] as? [String], nodeDetails.getTorusNodeEndpoints()) - XCTAssertEqual(mockTorusUtils.retrieveShares_input["verifierIdentifier"] as? String, expectedVerifier) - XCTAssertEqual(mockTorusUtils.retrieveShares_input["verifierId"] as? String, expectedVerfierId) - XCTAssertEqual(FinalKeyData.privKey, expectedPrivateKey) - XCTAssertEqual(FinalKeyData.evmAddress, expectedPublicAddress) - expectation.fulfill() - } catch { - XCTFail(error.localizedDescription) - expectation.fulfill() - } - } - - func testGetAggregateTorusKey() async throws { - let expectation = XCTestExpectation(description: "getAggregateTorusKey should correctly proxy input and output to/from TorusUtils") - - let expectedPrivateKey = try fakeData.generatePrivateKey() - let expectedPublicAddress = try fakeData.generatePublicKey() - let expectedVerifier = fakeData.generateVerifier() - let expectedVerfierId = fakeData.generateRandomEmail(of: 6) - - let subVerifier = [SubVerifierDetails(loginProvider: .jwt, clientId: fakeData.generateVerifier(), verifier: expectedVerifier, redirectURL: fakeData.generateVerifier())] - - let CustomAuth = CustomAuth(web3AuthClientId:"YOUR_CLIENT_ID", aggregateVerifierType: .singleIdVerifier, aggregateVerifier: expectedVerifier, subVerifierDetails: subVerifier, network: .legacy(.MAINNET)) -// var mockTorusUtils = CustomAuth.torusUtils as! MockAbstractTorusUtils - let mockTorusUtils = MockTorusUtils() - CustomAuth.torusUtils = mockTorusUtils - - // Set Mock data - mockTorusUtils.retrieveShares_output["privateKey"] = expectedPrivateKey - mockTorusUtils.retrieveShares_output["publicAddress"] = expectedPublicAddress - do { - - let nodeDetails = try await CustomAuth.getNodeDetailsFromContract(verifier: expectedVerifier, verfierID: expectedVerfierId) - let data = try await CustomAuth.getAggregateTorusKey(verifier: expectedVerifier, verifierId: expectedVerfierId, idToken: fakeData.generateVerifier(), subVerifierDetails: subVerifier[0]) - print("Data", data) - let FinalKeyData = data.finalKeyData! - let mockTorusUtils = CustomAuth.torusUtils as! MockAbstractTorusUtils - XCTAssertEqual(mockTorusUtils.retrieveShares_input["endpoints"] as? [String], nodeDetails.getTorusNodeEndpoints()) - XCTAssertEqual(mockTorusUtils.retrieveShares_input["verifierIdentifier"] as? String, expectedVerifier) - XCTAssertEqual(mockTorusUtils.retrieveShares_input["verifierId"] as? String, expectedVerfierId) - XCTAssertEqual(FinalKeyData.privKey, expectedPrivateKey) - XCTAssertEqual(FinalKeyData.evmAddress, expectedPublicAddress) - expectation.fulfill() - } catch { - XCTFail(error.localizedDescription) - expectation.fulfill() - } - } - - static var allTests = [ - ("testGetTorusKey", testGetTorusKey) -// ("testGetAggregateTorusKey", testGetAggregateTorusKey), - ] -} - -class fakeData { - static func generateVerifier() -> String { - return String.randomString(length: 10) - } - - static func generatePrivateKey() throws -> String { - let privateKey = curveSecp256k1.SecretKey(); - return try privateKey.serialize() - } - - static func generatePublicKey() throws -> String { - let privateKey = curveSecp256k1.SecretKey(); - return try privateKey.toPublic().serialize(compressed: false); - } - - static func generateRandomEmail(of length: Int) -> String { - let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" - var s = "" - for _ in 0 ..< length { - s.append(letters.randomElement()!) - } - return s + "@gmail.com" + let _ = try! decode(jwt: idToken) } } diff --git a/Tests/CustomAuthTests/IntegrationTests.swift b/Tests/CustomAuthTests/IntegrationTests.swift deleted file mode 100644 index 26dd8a6..0000000 --- a/Tests/CustomAuthTests/IntegrationTests.swift +++ /dev/null @@ -1,146 +0,0 @@ -// -// File.swift -// -// -// Created by Shubham on 5/10/21. -// - -@testable import CustomAuth -import Foundation -import JWTKit -import XCTest - -final class IntegrationTests: XCTestCase { - static var sdk: CustomAuth? - var sub: SubVerifierDetails! - - override func setUp() { - super.setUp() - let sub = SubVerifierDetails(loginType: .web, - loginProvider: .google, - clientId: "221898609709-obfn3p63741l5333093430j3qeiinaa8.apps.googleusercontent.com", - verifier: "google-lrc", - redirectURL: "com.googleusercontent.apps.238941746713-vfap8uumijal4ump28p9jd3lbe6onqt4:/oauthredirect", - browserRedirectURL: "https://scripts.toruswallet.io/redirect.html") - - IntegrationTests.sdk = CustomAuth(web3AuthClientId:"YOUR_CLIENT_ID", aggregateVerifierType: .singleLogin, aggregateVerifier: "torus-test-ios-public", subVerifierDetails: [sub], network: .legacy(.CYAN)) - } - - func test_getTorusKey() async throws { - let TORUS_TEST_VERIFIER = "torus-test-health" - let email = "hello@tor.us" - let jwt = try! generateIdToken(email: email) - let data = try await IntegrationTests.sdk?.getTorusKey(verifier: TORUS_TEST_VERIFIER, verifierId: email, idToken: jwt) - let finalKeyDataDict = data!.finalKeyData! - let evmAddress = finalKeyDataDict.evmAddress - XCTAssertEqual(evmAddress, "0xC615aA03Dd8C9b2dc6F7c43cBDfF2c34bBa47Ec9") - } - - let TORUS_TEST_EMAIL = "saasas@tr.us" - let TORUS_IMPORT_EMAIL = "importeduser2@tor.us" - - let TORUS_EXTENDED_VERIFIER_EMAIL = "testextenderverifierid@example.com" - - let TORUS_TEST_VERIFIER = "torus-test-health" - - let TORUS_TEST_AGGREGATE_VERIFIER = "torus-test-health-aggregate" - let HashEnabledVerifier = "torus-test-verifierid-hash" - - func test_Sapphire_getTorusKey() async throws { - let sub = SubVerifierDetails(loginType: .web, - loginProvider: .google, - clientId: "221898609709-obfn3p63741l5333093430j3qeiinaa8.apps.googleusercontent.com", - verifier: "google-lrc", - redirectURL: "com.googleusercontent.apps.238941746713-vfap8uumijal4ump28p9jd3lbe6onqt4:/oauthredirect", - browserRedirectURL: "https://scripts.toruswallet.io/redirect.html") - let sdk = CustomAuth(web3AuthClientId:"221898609709-obfn3p63741l5333093430j3qeiinaa8.apps.googleusercontent.com", aggregateVerifierType: .singleLogin, aggregateVerifier: "torus-test-ios-public", subVerifierDetails: [sub], network: .sapphire(.SAPPHIRE_DEVNET)) - - let jwt = try! generateIdToken(email: TORUS_TEST_EMAIL) - let data = try await sdk.getTorusKey(verifier: TORUS_TEST_VERIFIER, verifierId: TORUS_TEST_EMAIL, idToken: jwt) - let finalKeyDataDict = data.finalKeyData! - let evmAddress = finalKeyDataDict.evmAddress - XCTAssertEqual(evmAddress, "0x81001206C06AD09b3611b593aEEd3A607d79871E") - } - - func test_Sapphire_getTorusKey_gated() async throws { - let sub = SubVerifierDetails(loginType: .web, - loginProvider: .jwt, - clientId: "221898609709-obfn3p63741l5333093430j3qeiinaa8.apps.googleusercontent.com", - verifier: "torus-test-ios-public", - redirectURL: "com.googleusercontent.apps.238941746713-vfap8uumijal4ump28p9jd3lbe6onqt4:/oauthredirect", - browserRedirectURL: "https://scripts.toruswallet.io/redirect.html") - let sdk = CustomAuth(web3AuthClientId:"221898609709-obfn3p63741l5333093430j3qeiinaa8.apps.googleusercontent.com", aggregateVerifierType: .singleLogin, aggregateVerifier: "torus-test-ios-public", subVerifierDetails: [sub], network: .sapphire(.SAPPHIRE_DEVNET)) - - let jwt = try! generateIdToken(email: TORUS_TEST_EMAIL) - let data = try await sdk.getTorusKey(verifier: TORUS_TEST_VERIFIER, verifierId: TORUS_TEST_EMAIL, idToken: jwt) - let finalKeyDataDict = data.finalKeyData! - let evmAddress = finalKeyDataDict.evmAddress - XCTAssertEqual(evmAddress, "0x81001206C06AD09b3611b593aEEd3A607d79871E") - } -} - -// JWT payload structure. -struct TestPayload: JWTPayload, Equatable { - enum CodingKeys: String, CodingKey { - case subject = "sub" - case expiration = "exp" - case isAdmin = "admin" - case emailVerified = "email_verified" - case issuer = "iss" - case iat - case email - case audience = "aud" - } - - var subject: SubjectClaim - var expiration: ExpirationClaim - var audience: AudienceClaim - var isAdmin: Bool - let emailVerified: Bool - var issuer: IssuerClaim - var iat: IssuedAtClaim - var email: String - - // call its verify method. - func verify(using signer: JWTSigner) throws { - try expiration.verifyNotExpired() - } -} - -func generateRandomEmail(of length: Int) -> String { - let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" - var s = "" - for _ in 0 ..< length { - s.append(letters.randomElement()!) - } - return s + "@gmail.com" -} - -func generateIdToken(email: String) throws -> String { - let verifierPrivateKeyForSigning = - """ - -----BEGIN PRIVATE KEY----- - MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCCD7oLrcKae+jVZPGx52Cb/lKhdKxpXjl9eGNa1MlY57A== - -----END PRIVATE KEY----- - """ - - do { - let signers = JWTSigners() - let keys = try ECDSAKey.private(pem: verifierPrivateKeyForSigning) - signers.use(.es256(key: keys)) - - // Parses the JWT and verifies its signature. - let today = Date() - let modifiedDate = Calendar.current.date(byAdding: .hour, value: 1, to: today)! - - let emailComponent = email.components(separatedBy: "@")[0] - let subject = "email|" + emailComponent - - let payload = TestPayload(subject: SubjectClaim(stringLiteral: subject), expiration: ExpirationClaim(value: modifiedDate), audience: "torus-key-test", isAdmin: false, emailVerified: true, issuer: "torus-key-test", iat: IssuedAtClaim(value: Date()), email: email) - let jwt = try signers.sign(payload) - return jwt - } catch { - print(error) - throw error - } -} diff --git a/Tests/CustomAuthTests/MockCASDKFactory.swift b/Tests/CustomAuthTests/MockCASDKFactory.swift deleted file mode 100644 index 8be08dd..0000000 --- a/Tests/CustomAuthTests/MockCASDKFactory.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// File.swift -// -// -// Created by Shubham on 31/7/21. -// - -import CustomAuth -import FetchNodeDetails -import Foundation -import OSLog -import TorusUtils - -public class MockFactory: CASDKFactoryProtocol { - init() {} - - public func createTorusUtils(loglevel: OSLogType, urlSession: URLSession, enableOneKey: Bool, network: TorusNetwork) -> AbstractTorusUtils { - MockTorusUtils() - } - -// public func createFetchNodeDetails(network: TorusNetwork, urlSession: URLSession, networkUrl: String? = nil) -> AllNodeDetailsModel { -// let net = network == .MAINNET ? "0xf20336e16B5182637f09821c27BDe29b0AFcfe80" : "0x6258c9d6c12ed3edda59a1a6527e469517744aa7" -// return AllNodeDetailsModel(proxyAddress: net, network: network) -// } -} diff --git a/Tests/CustomAuthTests/MockTorusUtils.swift b/Tests/CustomAuthTests/MockTorusUtils.swift deleted file mode 100644 index 659a0fc..0000000 --- a/Tests/CustomAuthTests/MockTorusUtils.swift +++ /dev/null @@ -1,73 +0,0 @@ -import CustomAuth -import FetchNodeDetails -import Foundation -import BigInt -@testable import TorusUtils - -// Added so the that we can assign values later. -public protocol MockAbstractTorusUtils { - var retrieveShares_input: [String: Any] { get set } - var retrieveShares_output: [String: String] { get set } -} - -class MockTorusUtils: AbstractTorusUtils, MockAbstractTorusUtils { - - func retrieveShares(endpoints: [String], torusNodePubs: [TorusNodePubModel], indexes: [BigUInt], verifier: String, verifierParams: VerifierParams, idToken: String, extraParams: [String : Codable]) async throws -> TorusKey { - retrieveShares_input = [ - "endpoints": endpoints, - "verifierIdentifier": verifier, - "verifierId": verifierParams.verifier_id, - "idToken": idToken, - "extraParams": extraParams - ] - let finalKeyData : TorusKey.FinalKeyData = .init(evmAddress: retrieveShares_output["publicAddress"] ?? "", X: "", Y: "", privKey: retrieveShares_output["privateKey"] ?? "") - return TorusKey(finalKeyData: finalKeyData, oAuthKeyData: nil, sessionData: nil, metadata: nil, nodesData: nil) - } - - func getPublicAddress(endpoints: [String], torusNodePubs: [TorusNodePubModel], verifier: String, verifierId: String, extendedVerifierId: String?) async throws -> TorusPublicKey { - return .init(finalKeyData: nil, oAuthKeyData: nil, metadata: nil, nodesData: nil) - } - - func getUserTypeAndAddress(endpoints: [String], torusNodePubs: [TorusNodePubModel]?, verifier: String, verifierID: String, doesKeyAssign: Bool)async throws -> GetUserAndAddress{ - return .init(typeOfUser: .v1, address: "", x: "", y: "") - } - - func getOrSetNonce(x: String, y: String, privateKey: String?, getOnly: Bool) async throws -> GetOrSetNonceResult { - return GetOrSetNonceResult(typeOfUser: "v1") - } - - var retrieveShares_input: [String: Any] = [:] - var retrieveShares_output: [String: String] = [ - "privateKey": "", - "publicAddress": "" - ] - - var label: String? - var nodePubKeys: [TorusNodePubModel]? - - init() { - } - - func setTorusNodePubKeys(nodePubKeys: [TorusNodePubModel]) { - self.nodePubKeys = nodePubKeys - } - - func getPublicAddress(endpoints: [String], torusNodePubs: [TorusNodePubModel], verifier: String, verifierId: String, isExtended: Bool) async throws -> [String: String] { - return (["publicAddress": retrieveShares_output["publicAddress"] ?? ""]) - } - - func retrieveShares(torusNodePubs: [TorusNodePubModel], endpoints: [String], verifier verifierIdentifier: String, verifierId: String, idToken: String, extraParams: Data) async throws -> [String: String] { - retrieveShares_input = [ - "endpoints": endpoints, - "verifierIdentifier": verifierIdentifier, - "verifierId": verifierId, - "idToken": idToken, - "extraParams": extraParams - ] - return retrieveShares_output - } - - func getPostBoxKey(torusKey: RetrieveSharesResponseModel) -> String { - return "" - } -} diff --git a/Tests/CustomAuthTests/StubURLProtocol.swift b/Tests/CustomAuthTests/StubURLProtocol.swift deleted file mode 100644 index 5086acd..0000000 --- a/Tests/CustomAuthTests/StubURLProtocol.swift +++ /dev/null @@ -1,514 +0,0 @@ -import Foundation - -private func mustDecodeJSON(_ s: String) -> [String: Any] { - return try! JSONSerialization.jsonObject(with: Data(s.utf8), options: []) as! [String: Any] -} - -private func httpBodyStreamToData(stream: InputStream?) -> Data? { - guard let bodyStream = stream else { return nil } - bodyStream.open() - - // Will read 16 chars per iteration. Can use bigger buffer if needed - let bufferSize: Int = 16 - - let buffer = UnsafeMutablePointer.allocate(capacity: bufferSize) - - var dat = Data() - - while bodyStream.hasBytesAvailable { - let readDat = bodyStream.read(buffer, maxLength: bufferSize) - dat.append(buffer, count: readDat) - } - - buffer.deallocate() - - bodyStream.close() - - return dat -} - -private func stubMatcher(host: String, scheme: String, path: String, method: String, requestHeaders: [String: String]) -> (URLRequest) -> Bool { - return { (req: URLRequest) -> Bool in - if req.url?.host != host || req.url?.scheme != scheme || req.url?.path != path || req.httpMethod != method { - return false - } - for (name, value) in requestHeaders { - if req.value(forHTTPHeaderField: name) != value { - return false - } - } - return true - } -} - -private func stubMatcherWithBody(host: String, scheme: String, path: String, method: String, requestHeaders: [String: String], body: [String: Any]) -> (URLRequest) -> Bool { - return { (req: URLRequest) -> Bool in - if !stubMatcher(host: host, scheme: scheme, path: path, method: method, requestHeaders: requestHeaders)(req) { - return false - } - guard - let bodyData = StubURLProtocol.property(forKey: httpBodyKey, in: req) as? Data, - let jsonBody = (try? JSONSerialization.jsonObject(with: bodyData, options: [])) as? [String: Any] - else { - return false - } - return NSDictionary(dictionary: jsonBody).isEqual(to: body) - } -} - -private let injectedURLs: Set = [ - URL(string: "https://www.googleapis.com/userinfo/v2/me"), - URL(string: "https://ropsten.infura.io/v3/7f287687b3d049e2bea7b64869ee30a3"), - URL(string: "https://teal-15-4.torusnode.com/jrpc"), - URL(string: "https://teal-15-2.torusnode.com/jrpc"), - URL(string: "https://teal-15-1.torusnode.com/jrpc"), - URL(string: "https://teal-15-3.torusnode.com/jrpc"), - URL(string: "https://teal-15-5.torusnode.com/jrpc"), - URL(string: "https://signer.tor.us/api/allow"), - URL(string: "https://metadata.tor.us/get") -] - -private let injectedStubs: [Stub] = [ - Stub( - requestMatcher: stubMatcher( - host: "www.googleapis.com", - scheme: "https", - path: "/userinfo/v2/me", - method: "GET", - requestHeaders: mustDecodeJSON(#"{"Content-Type":"application/json","Authorization":"Bearer ya29.a0ARrdaM96u3PfVhg9xbkCPuecmF6YaylxRcJwKJTlHY8kwwuSyKbqme2qBbTdLoVORMZy4n8Al5Wr1HCnfjCesU38W1xkSgFNoPhRgTen6Zqxyr_tOddJw6-TUUbe45z6Zvkbx8DzBHShQkm-KbbNzh_M00kh","Accept":"application/json"}"#) as! [String: String] - ), - responseBody: Data(#"{"id":"109111953856031799639","email":"michael@tor.us","verified_email":true,"name":"Michael Lee","given_name":"Michael","family_name":"Lee","picture":"https://lh3.googleusercontent.com/a/AATXAJwsBb98gSYjVNlBBAhXJjvqNOw2GDSeTf0I6SJh=s96-c","locale":"en","hd":"tor.us"}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Date":"Sun, 17 Oct 2021 10:57:29 GMT","x-frame-options":"SAMEORIGIN","Pragma":"no-cache","x-xss-protection":"0","Content-Encoding":"gzip","Server":"ESF","Cache-Control":"no-cache, no-store, max-age=0, must-revalidate","Vary":"Origin, X-Origin, Referer","Alt-Svc":"h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-T051=\":443\"; ma=2592000,h3-Q050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\"","x-content-type-options":"nosniff","Content-Length":"234","Content-Type":"application/json; charset=UTF-8","Expires":"Mon, 01 Jan 1990 00:00:00 GMT"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "ropsten.infura.io", - scheme: "https", - path: "/v3/b8cdb0e4cff24599a286bf8e87ff1c96", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Content-Type":"application/json","Accept":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"jsonrpc":"2.0","method":"eth_call","id":1,"params":[{"to":"0x4023d2a0d330bf11426b12c6144cfb96b7fa6183","data":"0x76671808"},"latest"]}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","id":1,"result":"0x000000000000000000000000000000000000000000000000000000000000000f"}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Vary":"Accept-Encoding, Origin","Date":"Sun, 17 Oct 2021 10:57:30 GMT","Content-Length":"102","Content-Type":"application/json"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "ropsten.infura.io", - scheme: "https", - path: "/v3/b8cdb0e4cff24599a286bf8e87ff1c96", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Content-Type":"application/json","Accept":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"jsonrpc":"2.0","method":"eth_call","id":1,"params":[{"to":"0x4023d2a0d330bf11426b12c6144cfb96b7fa6183","data":"0x135022c2000000000000000000000000000000000000000000000000000000000000000f"},"latest"]}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","id":1,"result":"0x000000000000000000000000000000000000000000000000000000000000000f00000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000005000000000000000000000000455d2ba3f20fa83b9f824e665dd201d908c79dce000000000000000000000000b452bbd6f4d52d87f33336aad921538bf8dfdf67000000000000000000000000e3c0493536f20d090c8f9427d8fdfe548af3266200000000000000000000000054ac312ed9ba51cdd65f182487f29a3999dbf4e200000000000000000000000057f7a525608dc540fefc3e851700a4189d19142d"}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Content-Length":"870","Vary":"Accept-Encoding, Origin","Content-Type":"application/json","Date":"Sun, 17 Oct 2021 10:57:31 GMT"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "ropsten.infura.io", - scheme: "https", - path: "/v3/b8cdb0e4cff24599a286bf8e87ff1c96", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Accept":"application/json","Content-Type":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"jsonrpc":"2.0","method":"eth_call","id":1,"params":[{"to":"0x4023d2a0d330bf11426b12c6144cfb96b7fa6183","data":"0xbafb358100000000000000000000000054ac312ed9ba51cdd65f182487f29a3999dbf4e2"},"latest"]}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","id":1,"result":"0x00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000425a98d9ae006aed1d77e81d58be8f67193d13d01a9888e2923841894f4b0bf9cf63d40df480dacf68922004ed36dbab9e2969181b047730a5ce0797fb695824900000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000001b7465616c2d31352d352e746f7275736e6f64652e636f6d3a343433000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Date":"Sun, 17 Oct 2021 10:57:31 GMT","Content-Type":"application/json","Content-Length":"678","Vary":"Accept-Encoding, Origin"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "ropsten.infura.io", - scheme: "https", - path: "/v3/b8cdb0e4cff24599a286bf8e87ff1c96", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Accept":"application/json","Content-Type":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"jsonrpc":"2.0","method":"eth_call","id":1,"params":[{"to":"0x4023d2a0d330bf11426b12c6144cfb96b7fa6183","data":"0xbafb3581000000000000000000000000455d2ba3f20fa83b9f824e665dd201d908c79dce"},"latest"]}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","id":1,"result":"0x00000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000011363aad8868cacd7f8946c590325cd463106fb3731f08811ab4302d2deae35c3d77eebe5cdf466b475ec892d5b4cffbe0c1670525debbd97eee6dae2f87a7cbe00000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000001b7465616c2d31352d312e746f7275736e6f64652e636f6d3a343433000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Vary":"Accept-Encoding, Origin","Date":"Sun, 17 Oct 2021 10:57:31 GMT","Content-Length":"678","Content-Type":"application/json"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "ropsten.infura.io", - scheme: "https", - path: "/v3/b8cdb0e4cff24599a286bf8e87ff1c96", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Content-Type":"application/json","Accept":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"jsonrpc":"2.0","method":"eth_call","id":1,"params":[{"to":"0x4023d2a0d330bf11426b12c6144cfb96b7fa6183","data":"0xbafb3581000000000000000000000000b452bbd6f4d52d87f33336aad921538bf8dfdf67"},"latest"]}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","id":1,"result":"0x00000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000027c8cc521c48690f016bea593f67f88ad24f447dd6c31bbab541e59e207bf029db359f0a82608db2e06b953b36d0c9a473a00458117ca32a5b0f4563a7d53963600000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000001b7465616c2d31352d332e746f7275736e6f64652e636f6d3a343433000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Date":"Sun, 17 Oct 2021 10:57:31 GMT","Vary":"Accept-Encoding, Origin","Content-Type":"application/json","Content-Length":"678"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "ropsten.infura.io", - scheme: "https", - path: "/v3/b8cdb0e4cff24599a286bf8e87ff1c96", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Accept":"application/json","Content-Type":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"jsonrpc":"2.0","method":"eth_call","id":1,"params":[{"to":"0x4023d2a0d330bf11426b12c6144cfb96b7fa6183","data":"0xbafb358100000000000000000000000057f7a525608dc540fefc3e851700a4189d19142d"},"latest"]}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","id":1,"result":"0x00000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000005d908f41f8e06324a8a7abcf702adb6a273ce3ae63d86a3d22723e1bbf1438c9af977530b3ec0e525438c72d1e768380cbc5fb3b38a760ee925053b2e169428ce00000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000001b7465616c2d31352d322e746f7275736e6f64652e636f6d3a343433000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Vary":"Accept-Encoding, Origin","Content-Length":"678","Content-Type":"application/json","Date":"Sun, 17 Oct 2021 10:57:31 GMT"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "ropsten.infura.io", - scheme: "https", - path: "/v3/b8cdb0e4cff24599a286bf8e87ff1c96", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Accept":"application/json","Content-Type":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"jsonrpc":"2.0","method":"eth_call","id":1,"params":[{"to":"0x4023d2a0d330bf11426b12c6144cfb96b7fa6183","data":"0xbafb3581000000000000000000000000e3c0493536f20d090c8f9427d8fdfe548af32662"},"latest"]}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","id":1,"result":"0x00000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000038a86543ca17df5687719e2549caa024cf17fe0361e119e741eaee668f8dd0a6f9cdb254ff915a76950d6d13d78ef054d5d0dc34e2908c00bb009a6e4da70189100000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000001b7465616c2d31352d342e746f7275736e6f64652e636f6d3a343433000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Date":"Sun, 17 Oct 2021 10:57:31 GMT","Content-Length":"678","Content-Type":"application/json","Vary":"Accept-Encoding, Origin"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "teal-15-4.torusnode.com", - scheme: "https", - path: "/jrpc", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Accept":"application/json","Content-Type":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"jsonrpc":"2.0","method":"VerifierLookupRequest","id":10,"params":{"verifier":"torus-direct-mock-ios","verifier_id":"michael@tor.us"}}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","result":{"keys":[{"key_index":"1c724","pub_key_X":"22d225892d5d149c0486bfb358b143568d1a951c39d5ada061a48c06c48afe39","pub_key_Y":"fcd9074bff4b5097489b79f951146d66bbcd05dc6acf68b8d0afc271fb73cf64","address":"0x22f2Ce611cE0d0ff4DA661d3a4C4B7A60B2b13F8"}]},"id":10}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Vary":"Origin","Server":"nginx/1.19.9","Content-Length":"281","Content-Type":"application/json","Date":"Sun, 17 Oct 2021 10:57:32 GMT"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "teal-15-2.torusnode.com", - scheme: "https", - path: "/jrpc", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Content-Type":"application/json","Accept":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"jsonrpc":"2.0","method":"VerifierLookupRequest","id":10,"params":{"verifier":"torus-direct-mock-ios","verifier_id":"michael@tor.us"}}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","result":{"keys":[{"key_index":"1c724","pub_key_X":"22d225892d5d149c0486bfb358b143568d1a951c39d5ada061a48c06c48afe39","pub_key_Y":"fcd9074bff4b5097489b79f951146d66bbcd05dc6acf68b8d0afc271fb73cf64","address":"0x22f2Ce611cE0d0ff4DA661d3a4C4B7A60B2b13F8"}]},"id":10}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Vary":"Origin","Server":"nginx/1.19.9","Content-Length":"281","Content-Type":"application/json","Date":"Sun, 17 Oct 2021 10:57:32 GMT"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "teal-15-1.torusnode.com", - scheme: "https", - path: "/jrpc", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Accept":"application/json","Content-Type":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"jsonrpc":"2.0","method":"VerifierLookupRequest","id":10,"params":{"verifier":"torus-direct-mock-ios","verifier_id":"michael@tor.us"}}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","result":{"keys":[{"key_index":"1c724","pub_key_X":"22d225892d5d149c0486bfb358b143568d1a951c39d5ada061a48c06c48afe39","pub_key_Y":"fcd9074bff4b5097489b79f951146d66bbcd05dc6acf68b8d0afc271fb73cf64","address":"0x22f2Ce611cE0d0ff4DA661d3a4C4B7A60B2b13F8"}]},"id":10}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Content-Length":"281","Vary":"Origin","Content-Type":"application/json","Server":"nginx/1.19.9","Date":"Sun, 17 Oct 2021 10:57:32 GMT"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "teal-15-3.torusnode.com", - scheme: "https", - path: "/jrpc", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Accept":"application/json","Content-Type":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"jsonrpc":"2.0","method":"VerifierLookupRequest","id":10,"params":{"verifier":"torus-direct-mock-ios","verifier_id":"michael@tor.us"}}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","result":{"keys":[{"key_index":"1c724","pub_key_X":"22d225892d5d149c0486bfb358b143568d1a951c39d5ada061a48c06c48afe39","pub_key_Y":"fcd9074bff4b5097489b79f951146d66bbcd05dc6acf68b8d0afc271fb73cf64","address":"0x22f2Ce611cE0d0ff4DA661d3a4C4B7A60B2b13F8"}]},"id":10}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Date":"Sun, 17 Oct 2021 10:57:32 GMT","Content-Length":"281","Content-Type":"application/json","Server":"nginx/1.19.9","Vary":"Origin"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcher( - host: "signer.tor.us", - scheme: "https", - path: "/api/allow", - method: "GET", - requestHeaders: mustDecodeJSON(#"{"Origin":"torus-direct-mock-ios","Accept":"application/json","Content-Type":"application/json","x-api-key":"torus-default"}"#) as! [String: String] - ), - responseBody: Data(#"{"success":true}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Content-Length":"16","access-control-allow-headers":"pubkeyx,pubkeyy,x-api-key,x-embed-host,content-type,authorization,verifier,verifier_id","access-control-max-age":"86400","access-control-allow-methods":"GET,OPTIONS","Access-Control-Allow-Origin":"*","Date":"Sun, 17 Oct 2021 10:57:32 GMT","Content-Type":"application/json"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "teal-15-5.torusnode.com", - scheme: "https", - path: "/jrpc", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Accept":"application/json","Content-Type":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"jsonrpc":"2.0","method":"VerifierLookupRequest","id":10,"params":{"verifier":"torus-direct-mock-ios","verifier_id":"michael@tor.us"}}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","result":{"keys":[{"key_index":"1c724","pub_key_X":"22d225892d5d149c0486bfb358b143568d1a951c39d5ada061a48c06c48afe39","pub_key_Y":"fcd9074bff4b5097489b79f951146d66bbcd05dc6acf68b8d0afc271fb73cf64","address":"0x22f2Ce611cE0d0ff4DA661d3a4C4B7A60B2b13F8"}]},"id":10}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Vary":"Origin","Content-Length":"281","Server":"nginx/1.19.9","Content-Type":"application/json","Date":"Sun, 17 Oct 2021 10:57:32 GMT"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "metadata.tor.us", - scheme: "https", - path: "/get", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Content-Type":"application/json","Accept":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"pub_key_X":"22d225892d5d149c0486bfb358b143568d1a951c39d5ada061a48c06c48afe39","pub_key_Y":"fcd9074bff4b5097489b79f951146d66bbcd05dc6acf68b8d0afc271fb73cf64"}"#) - ), - responseBody: Data(#"{"message":""}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"x-download-options":"noopen","x-permitted-cross-domain-policies":"none","x-content-type-options":"nosniff","Strict-Transport-Security":"max-age=15552000; includeSubDomains","x-dns-prefetch-control":"off","x-xss-protection":"0","content-security-policy":"default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests","x-frame-options":"SAMEORIGIN","referrer-policy":"no-referrer","Date":"Sun, 17 Oct 2021 10:57:32 GMT","Content-Type":"application/json; charset=utf-8","expect-ct":"max-age=0","Etag":"W/\"e-JWOqSwGs6lhRJiUZe/mVb6Mua74\"","Content-Length":"14","Vary":"Origin, Accept-Encoding"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "teal-15-1.torusnode.com", - scheme: "https", - path: "/jrpc", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Accept":"application/json","Content-Type":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"jsonrpc":"2.0","method":"CommitmentRequest","id":10,"params":{"messageprefix":"mug00","temppuby":"03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e","temppubx":"3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025","tokencommitment":"f9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b","timestamp":"0","verifieridentifier":"torus-direct-mock-ios"}}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","result":{"signature":"f94f88b5a2fff06463fe0cb4569a652a11f351061dcd5b15e466274e374eb2992632153bda0c017d9c83916b82f1daa3ee5ac9990201d73a18915224a828b6a41b","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","nodepubx":"1363aad8868cacd7f8946c590325cd463106fb3731f08811ab4302d2deae35c3","nodepuby":"d77eebe5cdf466b475ec892d5b4cffbe0c1670525debbd97eee6dae2f87a7cbe"},"id":10}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Server":"nginx/1.19.9","Content-Type":"application/json","Vary":"Origin","Date":"Sun, 17 Oct 2021 10:57:32 GMT","Content-Length":"606"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "teal-15-3.torusnode.com", - scheme: "https", - path: "/jrpc", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Content-Type":"application/json","Accept":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"jsonrpc":"2.0","method":"CommitmentRequest","id":10,"params":{"messageprefix":"mug00","temppuby":"03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e","temppubx":"3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025","tokencommitment":"f9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b","timestamp":"0","verifieridentifier":"torus-direct-mock-ios"}}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","result":{"signature":"ee5b3560bc5b394326ddb784970eb27c995b77ceac9ce04ddffe72a52542dffd7b90b30c50b69481b43f04a0373b632798bac8fcdf8d695ead606200e0a24fc41c","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","nodepubx":"7c8cc521c48690f016bea593f67f88ad24f447dd6c31bbab541e59e207bf029d","nodepuby":"b359f0a82608db2e06b953b36d0c9a473a00458117ca32a5b0f4563a7d539636"},"id":10}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Server":"nginx/1.19.9","Content-Type":"application/json","Vary":"Origin","Date":"Sun, 17 Oct 2021 10:57:32 GMT","Content-Length":"606"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "teal-15-4.torusnode.com", - scheme: "https", - path: "/jrpc", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Accept":"application/json","Content-Type":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"jsonrpc":"2.0","method":"CommitmentRequest","id":10,"params":{"messageprefix":"mug00","temppuby":"03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e","temppubx":"3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025","tokencommitment":"f9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b","timestamp":"0","verifieridentifier":"torus-direct-mock-ios"}}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","result":{"signature":"739487dab15bc238d32db83faf7b0aeb57f6863ac079aa331605eee9e076567c5cfa588978128af9d2c160d92a30197ccec8ab8c24ea68a3ac540a2534f65e261c","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","nodepubx":"8a86543ca17df5687719e2549caa024cf17fe0361e119e741eaee668f8dd0a6f","nodepuby":"9cdb254ff915a76950d6d13d78ef054d5d0dc34e2908c00bb009a6e4da701891"},"id":10}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Vary":"Origin","Server":"nginx/1.19.9","Content-Length":"606","Content-Type":"application/json","Date":"Sun, 17 Oct 2021 10:57:32 GMT"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "teal-15-5.torusnode.com", - scheme: "https", - path: "/jrpc", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Content-Type":"application/json","Accept":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"jsonrpc":"2.0","method":"CommitmentRequest","id":10,"params":{"messageprefix":"mug00","temppuby":"03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e","temppubx":"3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025","tokencommitment":"f9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b","timestamp":"0","verifieridentifier":"torus-direct-mock-ios"}}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","result":{"signature":"d24ccf58546df41bc8506b467e017ec64d941feb442a02001bea1c014dbe4d6b01317473884284d038ea116e6040ab25dad9901ee94d41dd33674cd105bc32151b","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","nodepubx":"25a98d9ae006aed1d77e81d58be8f67193d13d01a9888e2923841894f4b0bf9c","nodepuby":"f63d40df480dacf68922004ed36dbab9e2969181b047730a5ce0797fb6958249"},"id":10}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Vary":"Origin","Server":"nginx/1.19.9","Content-Length":"606","Content-Type":"application/json","Date":"Sun, 17 Oct 2021 10:57:32 GMT"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "teal-15-2.torusnode.com", - scheme: "https", - path: "/jrpc", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Accept":"application/json","Content-Type":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"jsonrpc":"2.0","method":"CommitmentRequest","id":10,"params":{"messageprefix":"mug00","temppuby":"03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e","temppubx":"3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025","tokencommitment":"f9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b","timestamp":"0","verifieridentifier":"torus-direct-mock-ios"}}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","result":{"signature":"ed5d0191d91c02b427d6482cec5d5380026218a1adecfefd6f892903577abb5d43f303302b1eac90b7d225beeb66c8c9ed9ebde8ccfe5994b3fb5f028cf571411c","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","nodepubx":"d908f41f8e06324a8a7abcf702adb6a273ce3ae63d86a3d22723e1bbf1438c9a","nodepuby":"f977530b3ec0e525438c72d1e768380cbc5fb3b38a760ee925053b2e169428ce"},"id":10}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Server":"nginx/1.19.9","Content-Length":"606","Content-Type":"application/json","Vary":"Origin","Date":"Sun, 17 Oct 2021 10:57:32 GMT"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "teal-15-3.torusnode.com", - scheme: "https", - path: "/jrpc", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Accept":"application/json","Content-Type":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"params":{"encrypted":"yes","item":[{"verifieridentifier":"torus-direct-mock-ios","nodesignatures":[{"signature":"f94f88b5a2fff06463fe0cb4569a652a11f351061dcd5b15e466274e374eb2992632153bda0c017d9c83916b82f1daa3ee5ac9990201d73a18915224a828b6a41b","nodepubx":"1363aad8868cacd7f8946c590325cd463106fb3731f08811ab4302d2deae35c3","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","nodepuby":"d77eebe5cdf466b475ec892d5b4cffbe0c1670525debbd97eee6dae2f87a7cbe"},{"nodepubx":"7c8cc521c48690f016bea593f67f88ad24f447dd6c31bbab541e59e207bf029d","nodepuby":"b359f0a82608db2e06b953b36d0c9a473a00458117ca32a5b0f4563a7d539636","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","signature":"ee5b3560bc5b394326ddb784970eb27c995b77ceac9ce04ddffe72a52542dffd7b90b30c50b69481b43f04a0373b632798bac8fcdf8d695ead606200e0a24fc41c"},{"signature":"739487dab15bc238d32db83faf7b0aeb57f6863ac079aa331605eee9e076567c5cfa588978128af9d2c160d92a30197ccec8ab8c24ea68a3ac540a2534f65e261c","nodepubx":"8a86543ca17df5687719e2549caa024cf17fe0361e119e741eaee668f8dd0a6f","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","nodepuby":"9cdb254ff915a76950d6d13d78ef054d5d0dc34e2908c00bb009a6e4da701891"},{"data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","signature":"d24ccf58546df41bc8506b467e017ec64d941feb442a02001bea1c014dbe4d6b01317473884284d038ea116e6040ab25dad9901ee94d41dd33674cd105bc32151b","nodepuby":"f63d40df480dacf68922004ed36dbab9e2969181b047730a5ce0797fb6958249","nodepubx":"25a98d9ae006aed1d77e81d58be8f67193d13d01a9888e2923841894f4b0bf9c"}],"verifier_id":"michael@tor.us","idtoken":"eyJhbGciOiJSUzI1NiIsImtpZCI6ImFkZDhjMGVlNjIzOTU0NGFmNTNmOTM3MTJhNTdiMmUyNmY5NDMzNTIiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiI2MzYxOTk0NjUyNDItZmQ3dWp0b3JwdnZ1ZHRzbDN1M2V2OTBuaWplY3RmcW0uYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiI2MzYxOTk0NjUyNDItZmQ3dWp0b3JwdnZ1ZHRzbDN1M2V2OTBuaWplY3RmcW0uYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMDkxMTE5NTM4NTYwMzE3OTk2MzkiLCJoZCI6InRvci51cyIsImVtYWlsIjoibWljaGFlbEB0b3IudXMiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXRfaGFzaCI6InRUNDhSck1vdGFFbi1UN3dzc2U3QnciLCJub25jZSI6InZSU2tPZWwyQTkiLCJuYW1lIjoiTWljaGFlbCBMZWUiLCJwaWN0dXJlIjoiaHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tL2EvQUFUWEFKd3NCYjk4Z1NZalZObEJCQWhYSmp2cU5PdzJHRFNlVGYwSTZTSmg9czk2LWMiLCJnaXZlbl9uYW1lIjoiTWljaGFlbCIsImZhbWlseV9uYW1lIjoiTGVlIiwibG9jYWxlIjoiZW4iLCJpYXQiOjE2MzQ0NjgyNDksImV4cCI6MTYzNDQ3MTg0OX0.XGu1tm_OqlSrc5BMDMzOrlhxLZo1YnpCUT0_j2U1mQt86nJzf_Hp85JfapZj2QeeUz91H6-Ei8FR1i4ICEfjMcoZOW1Azc89qUNfUgWeyjqZ7wCHSsbHAwabE74RFAS9YAja8_ynUvCARfDEtoqcreNgmbw3ZntzAqpuuNBXYfbr87kMvu_wZ7fWjLKM91CvuXytQBwtieTyjAFnTXmEL60Pdu-JSQfHCbS5H39ZHlnYxEO6qztIjvbnQokhjHDGc4PMCx0wfzrEet1ojNOCnbfmaYE5NQudquzQNZtqZfn8f4B-sQhECElnOXagHlafWO5RayS0dCb1mTfr8orcCA"}]},"id":10,"method":"ShareRequest","jsonrpc":"2.0"}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","result":{"keys":[{"Index":"1c724","PublicKey":{"X":"22d225892d5d149c0486bfb358b143568d1a951c39d5ada061a48c06c48afe39","Y":"fcd9074bff4b5097489b79f951146d66bbcd05dc6acf68b8d0afc271fb73cf64"},"Threshold":1,"Verifiers":{"torus-direct-mock-ios":["michael@tor.us"]},"Share":"NGNmMDY4M2M0ZjVlMzAzZTE1YWE0YWU3NDQwZjJiNWQ2ZWVkN2U2MjcxZGQ3MjVjMTA2OGY5Njk3MTM0ODRmNmFmYjQwNjhhYjkyMGM3MTY0MWFjNWZjYTBiMGVhMTQw","Metadata":{"iv":"95d1859aa5f86d87f13ed672d12e2d10","ephemPublicKey":"0403aa155f2605555d7399378e71146420e8d4eac9fd911ee57134da846f0e1e60702397386f0ec1226c2e7616283739922d9b654570bce4fd775021ee7bfb6451","mac":"aabadefa3f0d1d7530425595e2b54faaafb9ee3e3ff7c8ad14f8f8572095ba4e","mode":"AES256"}}]},"id":10}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Vary":"Origin","Content-Length":"722","Date":"Sun, 17 Oct 2021 10:57:32 GMT","Content-Type":"application/json","Server":"nginx/1.19.9"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "teal-15-1.torusnode.com", - scheme: "https", - path: "/jrpc", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Content-Type":"application/json","Accept":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"params":{"encrypted":"yes","item":[{"verifieridentifier":"torus-direct-mock-ios","nodesignatures":[{"signature":"f94f88b5a2fff06463fe0cb4569a652a11f351061dcd5b15e466274e374eb2992632153bda0c017d9c83916b82f1daa3ee5ac9990201d73a18915224a828b6a41b","nodepubx":"1363aad8868cacd7f8946c590325cd463106fb3731f08811ab4302d2deae35c3","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","nodepuby":"d77eebe5cdf466b475ec892d5b4cffbe0c1670525debbd97eee6dae2f87a7cbe"},{"nodepubx":"7c8cc521c48690f016bea593f67f88ad24f447dd6c31bbab541e59e207bf029d","nodepuby":"b359f0a82608db2e06b953b36d0c9a473a00458117ca32a5b0f4563a7d539636","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","signature":"ee5b3560bc5b394326ddb784970eb27c995b77ceac9ce04ddffe72a52542dffd7b90b30c50b69481b43f04a0373b632798bac8fcdf8d695ead606200e0a24fc41c"},{"signature":"739487dab15bc238d32db83faf7b0aeb57f6863ac079aa331605eee9e076567c5cfa588978128af9d2c160d92a30197ccec8ab8c24ea68a3ac540a2534f65e261c","nodepubx":"8a86543ca17df5687719e2549caa024cf17fe0361e119e741eaee668f8dd0a6f","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","nodepuby":"9cdb254ff915a76950d6d13d78ef054d5d0dc34e2908c00bb009a6e4da701891"},{"data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","signature":"d24ccf58546df41bc8506b467e017ec64d941feb442a02001bea1c014dbe4d6b01317473884284d038ea116e6040ab25dad9901ee94d41dd33674cd105bc32151b","nodepuby":"f63d40df480dacf68922004ed36dbab9e2969181b047730a5ce0797fb6958249","nodepubx":"25a98d9ae006aed1d77e81d58be8f67193d13d01a9888e2923841894f4b0bf9c"}],"verifier_id":"michael@tor.us","idtoken":"eyJhbGciOiJSUzI1NiIsImtpZCI6ImFkZDhjMGVlNjIzOTU0NGFmNTNmOTM3MTJhNTdiMmUyNmY5NDMzNTIiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiI2MzYxOTk0NjUyNDItZmQ3dWp0b3JwdnZ1ZHRzbDN1M2V2OTBuaWplY3RmcW0uYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiI2MzYxOTk0NjUyNDItZmQ3dWp0b3JwdnZ1ZHRzbDN1M2V2OTBuaWplY3RmcW0uYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMDkxMTE5NTM4NTYwMzE3OTk2MzkiLCJoZCI6InRvci51cyIsImVtYWlsIjoibWljaGFlbEB0b3IudXMiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXRfaGFzaCI6InRUNDhSck1vdGFFbi1UN3dzc2U3QnciLCJub25jZSI6InZSU2tPZWwyQTkiLCJuYW1lIjoiTWljaGFlbCBMZWUiLCJwaWN0dXJlIjoiaHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tL2EvQUFUWEFKd3NCYjk4Z1NZalZObEJCQWhYSmp2cU5PdzJHRFNlVGYwSTZTSmg9czk2LWMiLCJnaXZlbl9uYW1lIjoiTWljaGFlbCIsImZhbWlseV9uYW1lIjoiTGVlIiwibG9jYWxlIjoiZW4iLCJpYXQiOjE2MzQ0NjgyNDksImV4cCI6MTYzNDQ3MTg0OX0.XGu1tm_OqlSrc5BMDMzOrlhxLZo1YnpCUT0_j2U1mQt86nJzf_Hp85JfapZj2QeeUz91H6-Ei8FR1i4ICEfjMcoZOW1Azc89qUNfUgWeyjqZ7wCHSsbHAwabE74RFAS9YAja8_ynUvCARfDEtoqcreNgmbw3ZntzAqpuuNBXYfbr87kMvu_wZ7fWjLKM91CvuXytQBwtieTyjAFnTXmEL60Pdu-JSQfHCbS5H39ZHlnYxEO6qztIjvbnQokhjHDGc4PMCx0wfzrEet1ojNOCnbfmaYE5NQudquzQNZtqZfn8f4B-sQhECElnOXagHlafWO5RayS0dCb1mTfr8orcCA"}]},"id":10,"method":"ShareRequest","jsonrpc":"2.0"}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","result":{"keys":[{"Index":"1c724","PublicKey":{"X":"22d225892d5d149c0486bfb358b143568d1a951c39d5ada061a48c06c48afe39","Y":"fcd9074bff4b5097489b79f951146d66bbcd05dc6acf68b8d0afc271fb73cf64"},"Threshold":1,"Verifiers":{"torus-direct-mock-ios":["michael@tor.us"]},"Share":"ZjBjNTEyNDI1MTBmOThiMGJjNDhhZjdhOTgwZjNkYTM0YjhmYmVkYzRjZTA2NzI1ZmI4MDExYWQ1MTc3YTUwNzFkYjNmNDNhYzA2NGNjYjkzYWIxYjY0YWZkY2I2NzMy","Metadata":{"iv":"e72d1cbaef1868cfbe241c3a84bb0a26","ephemPublicKey":"048b20e455385773ea58f59b0da8bde5cbe07f46155f6793fb120cd0fac8113ecf31adfcf5c07a8457d0973b93902c59fd156496ccf3746b9d44ce3de671360109","mac":"d9e7d9b565dc815a4969928296630bbc8102f080d3bcabb8f91df08f6cdb3f74","mode":"AES256"}}]},"id":10}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Server":"nginx/1.19.9","Content-Length":"722","Vary":"Origin","Content-Type":"application/json","Date":"Sun, 17 Oct 2021 10:57:32 GMT"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "teal-15-5.torusnode.com", - scheme: "https", - path: "/jrpc", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Accept":"application/json","Content-Type":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"params":{"encrypted":"yes","item":[{"verifieridentifier":"torus-direct-mock-ios","nodesignatures":[{"signature":"f94f88b5a2fff06463fe0cb4569a652a11f351061dcd5b15e466274e374eb2992632153bda0c017d9c83916b82f1daa3ee5ac9990201d73a18915224a828b6a41b","nodepubx":"1363aad8868cacd7f8946c590325cd463106fb3731f08811ab4302d2deae35c3","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","nodepuby":"d77eebe5cdf466b475ec892d5b4cffbe0c1670525debbd97eee6dae2f87a7cbe"},{"nodepubx":"7c8cc521c48690f016bea593f67f88ad24f447dd6c31bbab541e59e207bf029d","nodepuby":"b359f0a82608db2e06b953b36d0c9a473a00458117ca32a5b0f4563a7d539636","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","signature":"ee5b3560bc5b394326ddb784970eb27c995b77ceac9ce04ddffe72a52542dffd7b90b30c50b69481b43f04a0373b632798bac8fcdf8d695ead606200e0a24fc41c"},{"signature":"739487dab15bc238d32db83faf7b0aeb57f6863ac079aa331605eee9e076567c5cfa588978128af9d2c160d92a30197ccec8ab8c24ea68a3ac540a2534f65e261c","nodepubx":"8a86543ca17df5687719e2549caa024cf17fe0361e119e741eaee668f8dd0a6f","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","nodepuby":"9cdb254ff915a76950d6d13d78ef054d5d0dc34e2908c00bb009a6e4da701891"},{"data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","signature":"d24ccf58546df41bc8506b467e017ec64d941feb442a02001bea1c014dbe4d6b01317473884284d038ea116e6040ab25dad9901ee94d41dd33674cd105bc32151b","nodepuby":"f63d40df480dacf68922004ed36dbab9e2969181b047730a5ce0797fb6958249","nodepubx":"25a98d9ae006aed1d77e81d58be8f67193d13d01a9888e2923841894f4b0bf9c"}],"verifier_id":"michael@tor.us","idtoken":"eyJhbGciOiJSUzI1NiIsImtpZCI6ImFkZDhjMGVlNjIzOTU0NGFmNTNmOTM3MTJhNTdiMmUyNmY5NDMzNTIiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiI2MzYxOTk0NjUyNDItZmQ3dWp0b3JwdnZ1ZHRzbDN1M2V2OTBuaWplY3RmcW0uYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiI2MzYxOTk0NjUyNDItZmQ3dWp0b3JwdnZ1ZHRzbDN1M2V2OTBuaWplY3RmcW0uYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMDkxMTE5NTM4NTYwMzE3OTk2MzkiLCJoZCI6InRvci51cyIsImVtYWlsIjoibWljaGFlbEB0b3IudXMiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXRfaGFzaCI6InRUNDhSck1vdGFFbi1UN3dzc2U3QnciLCJub25jZSI6InZSU2tPZWwyQTkiLCJuYW1lIjoiTWljaGFlbCBMZWUiLCJwaWN0dXJlIjoiaHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tL2EvQUFUWEFKd3NCYjk4Z1NZalZObEJCQWhYSmp2cU5PdzJHRFNlVGYwSTZTSmg9czk2LWMiLCJnaXZlbl9uYW1lIjoiTWljaGFlbCIsImZhbWlseV9uYW1lIjoiTGVlIiwibG9jYWxlIjoiZW4iLCJpYXQiOjE2MzQ0NjgyNDksImV4cCI6MTYzNDQ3MTg0OX0.XGu1tm_OqlSrc5BMDMzOrlhxLZo1YnpCUT0_j2U1mQt86nJzf_Hp85JfapZj2QeeUz91H6-Ei8FR1i4ICEfjMcoZOW1Azc89qUNfUgWeyjqZ7wCHSsbHAwabE74RFAS9YAja8_ynUvCARfDEtoqcreNgmbw3ZntzAqpuuNBXYfbr87kMvu_wZ7fWjLKM91CvuXytQBwtieTyjAFnTXmEL60Pdu-JSQfHCbS5H39ZHlnYxEO6qztIjvbnQokhjHDGc4PMCx0wfzrEet1ojNOCnbfmaYE5NQudquzQNZtqZfn8f4B-sQhECElnOXagHlafWO5RayS0dCb1mTfr8orcCA"}]},"id":10,"method":"ShareRequest","jsonrpc":"2.0"}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","result":{"keys":[{"Index":"1c724","PublicKey":{"X":"22d225892d5d149c0486bfb358b143568d1a951c39d5ada061a48c06c48afe39","Y":"fcd9074bff4b5097489b79f951146d66bbcd05dc6acf68b8d0afc271fb73cf64"},"Threshold":1,"Verifiers":{"torus-direct-mock-ios":["michael@tor.us"]},"Share":"MzUyMTg4ZjEyMzc1NDAwZjk0MDIxOTgyNGJjNjZkM2U1MmZmM2Y0YjJjZWFkOTQzN2M0N2ZjMjMxMDFkYzQ5YzY5NjZiZTUzM2MwMDg2NTE1OGRlNThiNDc5N2M5Yjgy","Metadata":{"iv":"c73e422b8c1ca9bbe10caa04d8d6e79d","ephemPublicKey":"046ac88f638dc83e4eef85b9bea2de984449ad7587cc5c652451632d2ecc1509b1fa43180768d9c6e5e513d48f2bd8c69d450a4e279a0dbbdb5e7d917e54405e84","mac":"eb941f9a9317d7b27f7bda11988b6478a87bed80d644ccf6b09131e4a488bcd4","mode":"AES256"}}]},"id":10}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Content-Length":"722","Vary":"Origin","Date":"Sun, 17 Oct 2021 10:57:32 GMT","Server":"nginx/1.19.9","Content-Type":"application/json"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "teal-15-2.torusnode.com", - scheme: "https", - path: "/jrpc", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Accept":"application/json","Content-Type":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"params":{"encrypted":"yes","item":[{"verifieridentifier":"torus-direct-mock-ios","nodesignatures":[{"signature":"f94f88b5a2fff06463fe0cb4569a652a11f351061dcd5b15e466274e374eb2992632153bda0c017d9c83916b82f1daa3ee5ac9990201d73a18915224a828b6a41b","nodepubx":"1363aad8868cacd7f8946c590325cd463106fb3731f08811ab4302d2deae35c3","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","nodepuby":"d77eebe5cdf466b475ec892d5b4cffbe0c1670525debbd97eee6dae2f87a7cbe"},{"nodepubx":"7c8cc521c48690f016bea593f67f88ad24f447dd6c31bbab541e59e207bf029d","nodepuby":"b359f0a82608db2e06b953b36d0c9a473a00458117ca32a5b0f4563a7d539636","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","signature":"ee5b3560bc5b394326ddb784970eb27c995b77ceac9ce04ddffe72a52542dffd7b90b30c50b69481b43f04a0373b632798bac8fcdf8d695ead606200e0a24fc41c"},{"signature":"739487dab15bc238d32db83faf7b0aeb57f6863ac079aa331605eee9e076567c5cfa588978128af9d2c160d92a30197ccec8ab8c24ea68a3ac540a2534f65e261c","nodepubx":"8a86543ca17df5687719e2549caa024cf17fe0361e119e741eaee668f8dd0a6f","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","nodepuby":"9cdb254ff915a76950d6d13d78ef054d5d0dc34e2908c00bb009a6e4da701891"},{"data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","signature":"d24ccf58546df41bc8506b467e017ec64d941feb442a02001bea1c014dbe4d6b01317473884284d038ea116e6040ab25dad9901ee94d41dd33674cd105bc32151b","nodepuby":"f63d40df480dacf68922004ed36dbab9e2969181b047730a5ce0797fb6958249","nodepubx":"25a98d9ae006aed1d77e81d58be8f67193d13d01a9888e2923841894f4b0bf9c"}],"verifier_id":"michael@tor.us","idtoken":"eyJhbGciOiJSUzI1NiIsImtpZCI6ImFkZDhjMGVlNjIzOTU0NGFmNTNmOTM3MTJhNTdiMmUyNmY5NDMzNTIiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiI2MzYxOTk0NjUyNDItZmQ3dWp0b3JwdnZ1ZHRzbDN1M2V2OTBuaWplY3RmcW0uYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiI2MzYxOTk0NjUyNDItZmQ3dWp0b3JwdnZ1ZHRzbDN1M2V2OTBuaWplY3RmcW0uYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMDkxMTE5NTM4NTYwMzE3OTk2MzkiLCJoZCI6InRvci51cyIsImVtYWlsIjoibWljaGFlbEB0b3IudXMiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXRfaGFzaCI6InRUNDhSck1vdGFFbi1UN3dzc2U3QnciLCJub25jZSI6InZSU2tPZWwyQTkiLCJuYW1lIjoiTWljaGFlbCBMZWUiLCJwaWN0dXJlIjoiaHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tL2EvQUFUWEFKd3NCYjk4Z1NZalZObEJCQWhYSmp2cU5PdzJHRFNlVGYwSTZTSmg9czk2LWMiLCJnaXZlbl9uYW1lIjoiTWljaGFlbCIsImZhbWlseV9uYW1lIjoiTGVlIiwibG9jYWxlIjoiZW4iLCJpYXQiOjE2MzQ0NjgyNDksImV4cCI6MTYzNDQ3MTg0OX0.XGu1tm_OqlSrc5BMDMzOrlhxLZo1YnpCUT0_j2U1mQt86nJzf_Hp85JfapZj2QeeUz91H6-Ei8FR1i4ICEfjMcoZOW1Azc89qUNfUgWeyjqZ7wCHSsbHAwabE74RFAS9YAja8_ynUvCARfDEtoqcreNgmbw3ZntzAqpuuNBXYfbr87kMvu_wZ7fWjLKM91CvuXytQBwtieTyjAFnTXmEL60Pdu-JSQfHCbS5H39ZHlnYxEO6qztIjvbnQokhjHDGc4PMCx0wfzrEet1ojNOCnbfmaYE5NQudquzQNZtqZfn8f4B-sQhECElnOXagHlafWO5RayS0dCb1mTfr8orcCA"}]},"id":10,"method":"ShareRequest","jsonrpc":"2.0"}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","result":{"keys":[{"Index":"1c724","PublicKey":{"X":"22d225892d5d149c0486bfb358b143568d1a951c39d5ada061a48c06c48afe39","Y":"fcd9074bff4b5097489b79f951146d66bbcd05dc6acf68b8d0afc271fb73cf64"},"Threshold":1,"Verifiers":{"torus-direct-mock-ios":["michael@tor.us"]},"Share":"OTNhMzBjODY1YjM4OTNiNWQxOWQ2MmNmZmY1YjUzNTE1NzViZjZiMmM3ZmM0YWFmZTRiYzY0ZjA3YjkzNjU0MzczYzhjNmIyYjQ0ZjIzNTIyZWUwOGRmZWVjNzFlMjVk","Metadata":{"iv":"6e8150c48e9eaae7f03d71fe339e8ddf","ephemPublicKey":"048a363e0572bb294e979e5588488d3f702ea99df104b1b9a82e52505d85983d6ea11061a70a9bd99b2e77a0dc5e816eb1080618f96865ef318129711cd9f6634c","mac":"94d7c5a01d2a01379abb3a3a7c604910f8d58ac0f75c427392ea7c8c8085509c","mode":"AES256"}}]},"id":10}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Vary":"Origin","Server":"nginx/1.19.9","Content-Length":"722","Content-Type":"application/json","Date":"Sun, 17 Oct 2021 10:57:32 GMT"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "teal-15-4.torusnode.com", - scheme: "https", - path: "/jrpc", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Accept":"application/json","Content-Type":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"params":{"encrypted":"yes","item":[{"verifieridentifier":"torus-direct-mock-ios","nodesignatures":[{"signature":"f94f88b5a2fff06463fe0cb4569a652a11f351061dcd5b15e466274e374eb2992632153bda0c017d9c83916b82f1daa3ee5ac9990201d73a18915224a828b6a41b","nodepubx":"1363aad8868cacd7f8946c590325cd463106fb3731f08811ab4302d2deae35c3","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","nodepuby":"d77eebe5cdf466b475ec892d5b4cffbe0c1670525debbd97eee6dae2f87a7cbe"},{"nodepubx":"7c8cc521c48690f016bea593f67f88ad24f447dd6c31bbab541e59e207bf029d","nodepuby":"b359f0a82608db2e06b953b36d0c9a473a00458117ca32a5b0f4563a7d539636","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","signature":"ee5b3560bc5b394326ddb784970eb27c995b77ceac9ce04ddffe72a52542dffd7b90b30c50b69481b43f04a0373b632798bac8fcdf8d695ead606200e0a24fc41c"},{"signature":"739487dab15bc238d32db83faf7b0aeb57f6863ac079aa331605eee9e076567c5cfa588978128af9d2c160d92a30197ccec8ab8c24ea68a3ac540a2534f65e261c","nodepubx":"8a86543ca17df5687719e2549caa024cf17fe0361e119e741eaee668f8dd0a6f","data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","nodepuby":"9cdb254ff915a76950d6d13d78ef054d5d0dc34e2908c00bb009a6e4da701891"},{"data":"mug00\u001cf9a9e61d68072c950e5dc8baf824b810d52073e9e3748e35f9a534502bac8a5b\u001c3b695585f9c5ac4a4f036757c8873d01f51b68d5e8f0274e2dc4ebbc7daa7025\u001c03b18e36aa6c864091cd7d6536d30a3808c772f18479d753e12847266144c10e\u001ctorus-direct-mock-ios\u001c1634468252","signature":"d24ccf58546df41bc8506b467e017ec64d941feb442a02001bea1c014dbe4d6b01317473884284d038ea116e6040ab25dad9901ee94d41dd33674cd105bc32151b","nodepuby":"f63d40df480dacf68922004ed36dbab9e2969181b047730a5ce0797fb6958249","nodepubx":"25a98d9ae006aed1d77e81d58be8f67193d13d01a9888e2923841894f4b0bf9c"}],"verifier_id":"michael@tor.us","idtoken":"eyJhbGciOiJSUzI1NiIsImtpZCI6ImFkZDhjMGVlNjIzOTU0NGFmNTNmOTM3MTJhNTdiMmUyNmY5NDMzNTIiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhenAiOiI2MzYxOTk0NjUyNDItZmQ3dWp0b3JwdnZ1ZHRzbDN1M2V2OTBuaWplY3RmcW0uYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiI2MzYxOTk0NjUyNDItZmQ3dWp0b3JwdnZ1ZHRzbDN1M2V2OTBuaWplY3RmcW0uYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMDkxMTE5NTM4NTYwMzE3OTk2MzkiLCJoZCI6InRvci51cyIsImVtYWlsIjoibWljaGFlbEB0b3IudXMiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXRfaGFzaCI6InRUNDhSck1vdGFFbi1UN3dzc2U3QnciLCJub25jZSI6InZSU2tPZWwyQTkiLCJuYW1lIjoiTWljaGFlbCBMZWUiLCJwaWN0dXJlIjoiaHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tL2EvQUFUWEFKd3NCYjk4Z1NZalZObEJCQWhYSmp2cU5PdzJHRFNlVGYwSTZTSmg9czk2LWMiLCJnaXZlbl9uYW1lIjoiTWljaGFlbCIsImZhbWlseV9uYW1lIjoiTGVlIiwibG9jYWxlIjoiZW4iLCJpYXQiOjE2MzQ0NjgyNDksImV4cCI6MTYzNDQ3MTg0OX0.XGu1tm_OqlSrc5BMDMzOrlhxLZo1YnpCUT0_j2U1mQt86nJzf_Hp85JfapZj2QeeUz91H6-Ei8FR1i4ICEfjMcoZOW1Azc89qUNfUgWeyjqZ7wCHSsbHAwabE74RFAS9YAja8_ynUvCARfDEtoqcreNgmbw3ZntzAqpuuNBXYfbr87kMvu_wZ7fWjLKM91CvuXytQBwtieTyjAFnTXmEL60Pdu-JSQfHCbS5H39ZHlnYxEO6qztIjvbnQokhjHDGc4PMCx0wfzrEet1ojNOCnbfmaYE5NQudquzQNZtqZfn8f4B-sQhECElnOXagHlafWO5RayS0dCb1mTfr8orcCA"}]},"id":10,"method":"ShareRequest","jsonrpc":"2.0"}"#) - ), - responseBody: Data(#"{"jsonrpc":"2.0","result":{"keys":[{"Index":"1c724","PublicKey":{"X":"22d225892d5d149c0486bfb358b143568d1a951c39d5ada061a48c06c48afe39","Y":"fcd9074bff4b5097489b79f951146d66bbcd05dc6acf68b8d0afc271fb73cf64"},"Threshold":1,"Verifiers":{"torus-direct-mock-ios":["michael@tor.us"]},"Share":"M2U2OGMxYzg0ODFhMDAxNTFkOWE1MTMyMmZjNjlkOWQ0MWUzZjgzZDQ0NGJlNmQ1YzdlMDEwNzliZTRhYjg4OTdmM2Y3YWRiNjcwZDZhMTA5MDk4NjE2OGI2OTBlZWM2","Metadata":{"iv":"29a6a7bb27cd3a9a13cfb47818e894a0","ephemPublicKey":"0489299b0ccc867e2596e2069dce3c129e163f9e8c47c51c2dd2ea5aa56af88b4cfa4cfab34ece86512dc0995fcbab1fe9206609cafa648a66bc35d95c1795dd41","mac":"541759eb560a77517057c452b11113630e2ac32de7ba2addab8643ff52a19f59","mode":"AES256"}}]},"id":10}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Date":"Sun, 17 Oct 2021 10:57:33 GMT","Content-Type":"application/json","Content-Length":"722","Vary":"Origin","Server":"nginx/1.19.9"}"#) as! [String: String] - ), - - Stub( - requestMatcher: stubMatcherWithBody( - host: "metadata.tor.us", - scheme: "https", - path: "/get", - method: "POST", - requestHeaders: mustDecodeJSON(#"{"Accept":"application/json","Content-Type":"application/json"}"#) as! [String: String], - body: mustDecodeJSON(#"{"pub_key_X":"22d225892d5d149c0486bfb358b143568d1a951c39d5ada061a48c06c48afe39","pub_key_Y":"fcd9074bff4b5097489b79f951146d66bbcd05dc6acf68b8d0afc271fb73cf64"}"#) - ), - responseBody: Data(#"{"message":""}"#.utf8), - statusCode: 200, - responseHeaders: mustDecodeJSON(#"{"Content-Type":"application/json; charset=utf-8","Etag":"W/\"e-JWOqSwGs6lhRJiUZe/mVb6Mua74\"","x-xss-protection":"0","x-content-type-options":"nosniff","Vary":"Origin, Accept-Encoding","x-frame-options":"SAMEORIGIN","referrer-policy":"no-referrer","content-security-policy":"default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests","Date":"Sun, 17 Oct 2021 10:57:33 GMT","x-dns-prefetch-control":"off","x-permitted-cross-domain-policies":"none","Strict-Transport-Security":"max-age=15552000; includeSubDomains","x-download-options":"noopen","Content-Length":"14","expect-ct":"max-age=0"}"#) as! [String: String] - ) -] - -private let httpBodyKey = "StubURLProtocolHTTPBody" - -private struct Stub { - let requestMatcher: (URLRequest) -> Bool - let responseBody: Data? - let statusCode: Int - let responseHeaders: [String: String] -} - -public class StubURLProtocol: URLProtocol { - private static let terminateUnknownRequest = true - - private static let stubs = injectedStubs - - private static let urls = injectedURLs - - private class func matchStub(req: URLRequest) -> Stub? { - var inputReq: URLRequest - if let httpBodyData = httpBodyStreamToData(stream: req.httpBodyStream) { - let mutableReq = (req as NSURLRequest).mutableCopy() as! NSMutableURLRequest - setProperty(httpBodyData, forKey: httpBodyKey, in: mutableReq) - inputReq = mutableReq as URLRequest - } else { - inputReq = req - } - for stub in stubs { - if stub.requestMatcher(inputReq) { - return stub - } - } - return nil - } - - override public class func canInit(with request: URLRequest) -> Bool { - var cleanURL: URL? { - var comp = URLComponents() - comp.scheme = request.url?.scheme - comp.host = request.url?.host - comp.path = request.url?.path ?? "/" - return comp.url - } - if urls.contains(cleanURL) { - return true - } - return terminateUnknownRequest - } - - override public class func canonicalRequest(for request: URLRequest) -> URLRequest { - return request - } - - override public func startLoading() { - guard let url = request.url else { - fatalError("Request has no URL") - } - var cleanURL: URL? { - var comp = URLComponents() - comp.scheme = url.scheme - comp.host = url.host - comp.path = url.path - return comp.url - } - if !StubURLProtocol.urls.contains(cleanURL) { - fatalError("URL not mocked, inconsistent injectedURLs: \(url.absoluteString)") - } - if let stub = StubURLProtocol.matchStub(req: request) { - let res = HTTPURLResponse(url: url, statusCode: stub.statusCode, httpVersion: nil, headerFields: stub.responseHeaders)! - client?.urlProtocol(self, didReceive: res, cacheStoragePolicy: .notAllowed) - if let d = stub.responseBody { - client?.urlProtocol(self, didLoad: d) - } - } else { - fatalError("URL not mocked: \(url.absoluteString)") - } - client?.urlProtocolDidFinishLoading(self) - } - - override public func stopLoading() { - } -} diff --git a/Tests/CustomAuthTests/StubURLProtocolTests.swift b/Tests/CustomAuthTests/StubURLProtocolTests.swift deleted file mode 100644 index a5ef2ca..0000000 --- a/Tests/CustomAuthTests/StubURLProtocolTests.swift +++ /dev/null @@ -1,30 +0,0 @@ -import CustomAuth -import FetchNodeDetails -import Foundation -import OSLog -import TorusUtils -import XCTest - -final class StubURLProtocolTests: XCTestCase {} - -public class StubMockTorusUtils: TorusUtils { - override open func getTimestamp() -> TimeInterval { - let ret = 0.0 - print("[StubMockTorusUtils] getTimeStamp(): ", ret) - return ret - } - - open func generatePrivateKeyData() -> Data? { - let ret = Data(base64Encoded: "FBz7bssmbsV6jBWoOJpkVOu14+6/Xgyt1pxTycODG08=") - return ret - } -} - -public class StubMockCASDKFactory: CASDKFactoryProtocol { - public func createTorusUtils(loglevel: OSLogType, urlSession: URLSession, enableOneKey: Bool, network: TorusNetwork) -> AbstractTorusUtils { - return StubMockTorusUtils(loglevel: loglevel, urlSession: urlSession, enableOneKey: enableOneKey, network: .sapphire(.SAPPHIRE_DEVNET), clientId: "Your Client ID") - } - - public init() { - } -} From b33d7a8e98c36f1ddd0ea884bdee50fad4faedbc Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Tue, 30 Jul 2024 17:00:37 +0200 Subject: [PATCH 02/24] update: cocoapods example application --- cocoapods/Podfile | 17 +- cocoapods/Podfile.lock | 48 +-- cocoapods/cptest.xcodeproj/project.pbxproj | 38 +- .../xcshareddata/xcschemes/cptest.xcscheme | 2 +- cocoapods/cptest/AppDelegate.swift | 18 - .../cptest/Base.lproj/LaunchScreen.storyboard | 25 -- cocoapods/cptest/ContentView.swift | 12 +- cocoapods/cptest/LoginView.swift | 47 +-- cocoapods/cptest/SceneDelegate.swift | 61 --- cocoapods/cptest/UserInfoView.swift | 14 +- cocoapods/cptest/ViewModel.swift | 350 +++++++++--------- 11 files changed, 238 insertions(+), 394 deletions(-) delete mode 100644 cocoapods/cptest/Base.lproj/LaunchScreen.storyboard diff --git a/cocoapods/Podfile b/cocoapods/Podfile index b95d373..3388940 100644 --- a/cocoapods/Podfile +++ b/cocoapods/Podfile @@ -3,17 +3,18 @@ platform :ios, '14.0' source 'https://github.com/CocoaPods/Specs.git' target 'cptest' do - # Comment the next line if you don't want to use dynamic frameworks use_frameworks! - # pod 'Torus-utils', '~>' -# pod 'SingleFactorAuth', '~> 2.0.1' -# pod 'CustomAuth', :path=>"../" + pod 'Torus-utils', '~> 9.0.0' + pod 'CustomAuth', :path=>"../" # Pods for cptest - post_install do |installer| - installer.pods_project.build_configurations.each do |config| - config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = "arm64" + post_install do |installer_representation| + installer_representation.pods_project.targets.each do |target| + target.build_configurations.each do |config| + config.build_settings['ONLY_ACTIVE_ARCH'] = 'NO' + config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0' + end end end + end - diff --git a/cocoapods/Podfile.lock b/cocoapods/Podfile.lock index dbc3a61..f1cdccb 100644 --- a/cocoapods/Podfile.lock +++ b/cocoapods/Podfile.lock @@ -1,52 +1,40 @@ PODS: - - BigInt (5.0.0) - - CryptoSwift (1.7.1) - - CustomAuth (6.0.1): + - BigInt (5.2.0) + - curvelib.swift (1.0.1) + - CustomAuth (11.0.0): - JWTDecode (~> 3.1.0) - - Torus-utils (~> 5.1.1) - - GenericJSON (2.0.2) + - Torus-utils (~> 9.0.0) - JWTDecode (3.1.0) - - secp256k1.swift (0.1.4) - - Torus-fetchNodeDetails (4.0.1): - - web3.swift (~> 0.9.3) - - Torus-utils (5.1.1): - - CryptoSwift (~> 1.7.1) - - secp256k1.swift (~> 0.1.4) - - Torus-fetchNodeDetails (~> 4.0.1) - - web3.swift (0.9.3): - - BigInt (~> 5.0.0) - - GenericJSON (~> 2.0) - - secp256k1.swift (~> 0.1) + - Torus-fetchNodeDetails (6.0.3): + - BigInt (~> 5.2.0) + - Torus-utils (9.0.0): + - curvelib.swift (~> 1.0.1) + - Torus-fetchNodeDetails (~> 6.0.3) DEPENDENCIES: - CustomAuth (from `../`) + - Torus-utils (~> 9.0.0) SPEC REPOS: https://github.com/CocoaPods/Specs.git: - BigInt - - CryptoSwift - - GenericJSON + - curvelib.swift - JWTDecode - - secp256k1.swift - Torus-fetchNodeDetails - Torus-utils - - web3.swift EXTERNAL SOURCES: CustomAuth: :path: "../" SPEC CHECKSUMS: - BigInt: 74b4d88367b0e819d9f77393549226d36faeb0d8 - CryptoSwift: d3d18dc357932f7e6d580689e065cf1f176007c1 - CustomAuth: fd705ef3394ece58f4d7912a9653746d075884ad - GenericJSON: 79a840eeb77030962e8cf02a62d36bd413b67626 + BigInt: f668a80089607f521586bbe29513d708491ef2f7 + curvelib.swift: d0746ae82bee34016c06da3567a97e493b3c979f + CustomAuth: 03df324125a03626232ae742175aeda26a065e66 JWTDecode: 3eaab1e06b6f4dcbdd6716aff09ba4c2104ca8b7 - secp256k1.swift: a7e7a214f6db6ce5db32cc6b2b45e5c4dd633634 - Torus-fetchNodeDetails: a92d02f1bfe91bd61c90f92d64df023babaa5bfa - Torus-utils: 9b167655f8882ad0cff7ab76685da0728d9c9cea - web3.swift: c6c3bf1f853743f8a7a58d263e5f7e46545e22c7 + Torus-fetchNodeDetails: 6c349f47cbca36a4b3f276fe26d03c1b39b20949 + Torus-utils: 0f993fffd66a66a0423092c9ddea2cbff4d298df -PODFILE CHECKSUM: f833fcc5131fdff361e66d13954083588b75e937 +PODFILE CHECKSUM: 9b208a8d1d57bbade0916f1ca893014f4b177c68 -COCOAPODS: 1.12.1 +COCOAPODS: 1.13.0 diff --git a/cocoapods/cptest.xcodeproj/project.pbxproj b/cocoapods/cptest.xcodeproj/project.pbxproj index fee35ae..cf50eb7 100644 --- a/cocoapods/cptest.xcodeproj/project.pbxproj +++ b/cocoapods/cptest.xcodeproj/project.pbxproj @@ -3,17 +3,16 @@ archiveVersion = 1; classes = { }; - objectVersion = 51; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ - 51CF48BE2493A34C0000D501 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51CF48BD2493A34C0000D501 /* AppDelegate.swift */; }; 51CF48C02493A34C0000D501 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51CF48BF2493A34C0000D501 /* SceneDelegate.swift */; }; - 51CF48C22493A34C0000D501 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51CF48C12493A34C0000D501 /* ContentView.swift */; }; 51CF48C42493A34D0000D501 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 51CF48C32493A34D0000D501 /* Assets.xcassets */; }; 51CF48C72493A34D0000D501 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 51CF48C62493A34D0000D501 /* Preview Assets.xcassets */; }; - 51CF48CA2493A34D0000D501 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 51CF48C82493A34D0000D501 /* LaunchScreen.storyboard */; }; 77780FDF4E728A0496F42009 /* Pods_cptest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F2E0FC8146E62B6EB56A5A3C /* Pods_cptest.framework */; }; + B3E673212C5935A00006A66B /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3E673202C5935A00006A66B /* AppDelegate.swift */; }; + B3E673232C59366C0006A66B /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3E673222C59366C0006A66B /* ContentView.swift */; }; FCF292E9290A525300132DC5 /* ViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCF292E8290A525300132DC5 /* ViewModel.swift */; }; FCF292EB290A5DE300132DC5 /* UserInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCF292EA290A5DE300132DC5 /* UserInfoView.swift */; }; FCF292ED290A6E6C00132DC5 /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCF292EC290A6E6C00132DC5 /* LoginView.swift */; }; @@ -21,14 +20,13 @@ /* Begin PBXFileReference section */ 51CF48BA2493A34C0000D501 /* cptest.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = cptest.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 51CF48BD2493A34C0000D501 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 51CF48BF2493A34C0000D501 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; - 51CF48C12493A34C0000D501 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 51CF48C32493A34D0000D501 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 51CF48C62493A34D0000D501 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; - 51CF48C92493A34D0000D501 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 51CF48CB2493A34D0000D501 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 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 = ""; }; + B3E673202C5935A00006A66B /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + B3E673222C59366C0006A66B /* ContentView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 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 = ""; }; F2E0FC8146E62B6EB56A5A3C /* Pods_cptest.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_cptest.framework; sourceTree = BUILT_PRODUCTS_DIR; }; FCF292E8290A525300132DC5 /* ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewModel.swift; sourceTree = ""; }; @@ -69,14 +67,13 @@ 51CF48BC2493A34C0000D501 /* cptest */ = { isa = PBXGroup; children = ( - 51CF48BD2493A34C0000D501 /* AppDelegate.swift */, + B3E673202C5935A00006A66B /* AppDelegate.swift */, 51CF48BF2493A34C0000D501 /* SceneDelegate.swift */, - 51CF48C12493A34C0000D501 /* ContentView.swift */, FCF292E8290A525300132DC5 /* ViewModel.swift */, + B3E673222C59366C0006A66B /* ContentView.swift */, FCF292EC290A6E6C00132DC5 /* LoginView.swift */, FCF292EA290A5DE300132DC5 /* UserInfoView.swift */, 51CF48C32493A34D0000D501 /* Assets.xcassets */, - 51CF48C82493A34D0000D501 /* LaunchScreen.storyboard */, 51CF48CB2493A34D0000D501 /* Info.plist */, 51CF48C52493A34D0000D501 /* Preview Content */, ); @@ -136,8 +133,9 @@ 51CF48B22493A34C0000D501 /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 1150; - LastUpgradeCheck = 1210; + LastUpgradeCheck = 1540; ORGANIZATIONNAME = torus; TargetAttributes = { 51CF48B92493A34C0000D501 = { @@ -168,7 +166,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 51CF48CA2493A34D0000D501 /* LaunchScreen.storyboard in Resources */, 51CF48C72493A34D0000D501 /* Preview Assets.xcassets in Resources */, 51CF48C42493A34D0000D501 /* Assets.xcassets in Resources */, ); @@ -223,33 +220,23 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + B3E673212C5935A00006A66B /* AppDelegate.swift in Sources */, FCF292ED290A6E6C00132DC5 /* LoginView.swift in Sources */, - 51CF48BE2493A34C0000D501 /* AppDelegate.swift in Sources */, + B3E673232C59366C0006A66B /* ContentView.swift in Sources */, 51CF48C02493A34C0000D501 /* SceneDelegate.swift in Sources */, FCF292E9290A525300132DC5 /* ViewModel.swift in Sources */, - 51CF48C22493A34C0000D501 /* ContentView.swift in Sources */, FCF292EB290A5DE300132DC5 /* UserInfoView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ -/* Begin PBXVariantGroup section */ - 51CF48C82493A34D0000D501 /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 51CF48C92493A34D0000D501 /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - /* Begin XCBuildConfiguration section */ 51CF48CC2493A34D0000D501 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -311,6 +298,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; diff --git a/cocoapods/cptest.xcodeproj/xcshareddata/xcschemes/cptest.xcscheme b/cocoapods/cptest.xcodeproj/xcshareddata/xcschemes/cptest.xcscheme index 82306bf..95c1ac2 100644 --- a/cocoapods/cptest.xcodeproj/xcshareddata/xcschemes/cptest.xcscheme +++ b/cocoapods/cptest.xcodeproj/xcshareddata/xcschemes/cptest.xcscheme @@ -1,6 +1,6 @@ UISceneConfiguration { - // Called when a new scene session is being created. - // Use this method to select a configuration to create the new scene with. return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) } - - func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { - // Called when the user discards a scene session. - // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. - // Use this method to release any resources that were specific to the discarded scenes, as they will not return. - } } diff --git a/cocoapods/cptest/Base.lproj/LaunchScreen.storyboard b/cocoapods/cptest/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index 865e932..0000000 --- a/cocoapods/cptest/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/cocoapods/cptest/ContentView.swift b/cocoapods/cptest/ContentView.swift index 1690ad4..c91a6dc 100644 --- a/cocoapods/cptest/ContentView.swift +++ b/cocoapods/cptest/ContentView.swift @@ -1,11 +1,3 @@ -// -// ContentView.swift -// CustomAuthDemo -// -// Created by Shubham on 24/4/20. -// Copyright © 2020 Shubham. All rights reserved. -// - import SwiftUI struct ContentView: View { @@ -21,8 +13,8 @@ struct ContentView: View { } } .alert(isPresented: $vm.showingAlert) { - Alert(title: Text("Error"), message: Text("Login failed!"), dismissButton: .default(Text("OK"))) - } + Alert(title: Text("Error"), message: Text("Login failed!"), dismissButton: .default(Text("OK"))) + } .navigationBarTitle(Text("CustomAuth App")) } } diff --git a/cocoapods/cptest/LoginView.swift b/cocoapods/cptest/LoginView.swift index b506e1a..ea34161 100644 --- a/cocoapods/cptest/LoginView.swift +++ b/cocoapods/cptest/LoginView.swift @@ -1,18 +1,9 @@ -// -// LoginView.swift -// cptest -// -// Created by Dhruv Jaiswal on 27/10/22. -// Copyright © 2022 torus. All rights reserved. -// - import SwiftUI struct LoginView: View { @ObservedObject var vm: ViewModel var body: some View { List { - Section(header: Text("Single Logins")) { Group { Button(action: { @@ -75,37 +66,17 @@ struct LoginView: View { }, label: { Text("Apple Login") }) - } - - Button(action: { - vm.emailPasswordlessLogin() - }, label: { - Text("Email-password Login") - }) - - Button(action: { - vm.kakaoLogin() - }, label: { - Text("Kakao Login") - }) - - Button(action: { - vm.weiboLogin() - }, label: { - Text("Weibo Login") - }) - - Button(action: { - vm.wechatLogin() - }, label: { - Text("Wechat Login") - }) - - Section(header: Text("Single ID verifier")) { + + Button(action: { + vm.weiboLogin() + }, label: { + Text("Weibo Login") + }) + Button(action: { - vm.googleDeepLinkFlowLogin() + vm.emailPasswordLogin() }, label: { - Text("Google Login - Deep link flow") + Text("Email-Password Login") }) } } diff --git a/cocoapods/cptest/SceneDelegate.swift b/cocoapods/cptest/SceneDelegate.swift index 53de3f2..ac7dc8d 100644 --- a/cocoapods/cptest/SceneDelegate.swift +++ b/cocoapods/cptest/SceneDelegate.swift @@ -1,45 +1,12 @@ -// -// SceneDelegate.swift -// cptest -// -// Created by Shubham on 12/6/20. -// Copyright © 2020 torus. All rights reserved. -// - import CustomAuth import SwiftUI -import UIKit class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? - - // Handle Universal logins - func scene(_ scene: UIScene, continue userActivity: NSUserActivity) { - guard userActivity.activityType == NSUserActivityTypeBrowsingWeb, - let urlToOpen = userActivity.webpageURL else { - return - } - CustomAuth.handle(url: urlToOpen) - } - - // Hanlde Deep linkings - func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { - guard let url = URLContexts.first?.url else { - return - } - CustomAuth.handle(url: url) - } - func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { - // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. - // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. - // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). - - // Create the SwiftUI view that provides the window contents. let vm = ViewModel() let contentView = ContentView(vm: vm) - // Use a UIHostingController as window root view controller. if let windowScene = scene as? UIWindowScene { let window = UIWindow(windowScene: windowScene) window.rootViewController = UIHostingController(rootView: contentView) @@ -47,32 +14,4 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { window.makeKeyAndVisible() } } - - func sceneDidDisconnect(_ scene: UIScene) { - // Called as the scene is being released by the system. - // This occurs shortly after the scene enters the background, or when its session is discarded. - // Release any resources associated with this scene that can be re-created the next time the scene connects. - // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead). - } - - func sceneDidBecomeActive(_ scene: UIScene) { - // Called when the scene has moved from an inactive state to an active state. - // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. - } - - func sceneWillResignActive(_ scene: UIScene) { - // Called when the scene will move from an active state to an inactive state. - // This may occur due to temporary interruptions (ex. an incoming phone call). - } - - func sceneWillEnterForeground(_ scene: UIScene) { - // Called as the scene transitions from the background to the foreground. - // Use this method to undo the changes made on entering the background. - } - - func sceneDidEnterBackground(_ scene: UIScene) { - // Called as the scene transitions from the foreground to the background. - // Use this method to save data, release shared resources, and store enough scene-specific state information - // to restore the scene back to its current state. - } } diff --git a/cocoapods/cptest/UserInfoView.swift b/cocoapods/cptest/UserInfoView.swift index 0e92d92..3adcc57 100644 --- a/cocoapods/cptest/UserInfoView.swift +++ b/cocoapods/cptest/UserInfoView.swift @@ -1,11 +1,3 @@ -// -// UserInfoView.swift -// cptest -// -// Created by Dhruv Jaiswal on 27/10/22. -// Copyright © 2022 torus. All rights reserved. -// - import SwiftUI struct UserInfoView: View { @@ -26,10 +18,8 @@ struct UserInfoView: View { Text("Public Address") } Section { - ForEach(user.userInfo.sorted(by: >), id: \.key) { key, value in - - Text("\(key): \(value)") - } + let encoded = try! JSONEncoder().encode(user.userInfo) + Text(String(data: encoded, encoding: .utf8)!) } header: { Text("User Info") diff --git a/cocoapods/cptest/ViewModel.swift b/cocoapods/cptest/ViewModel.swift index bd25496..8dcf819 100644 --- a/cocoapods/cptest/ViewModel.swift +++ b/cocoapods/cptest/ViewModel.swift @@ -1,230 +1,248 @@ -// -// ViewModel.swift -// cptest -// -// Created by Dhruv Jaiswal on 27/10/22. -// Copyright © 2022 torus. All rights reserved. -// - import CustomAuth import Foundation struct User { var publicAddress: String var privateKey: String - var userInfo: [String: String] + var userInfo: UserInfo } class ViewModel: ObservableObject { @Published var user: User? @Published var showingAlert: Bool = false private var testnetNetworkUrl: String = "https://rpc.ankr.com/eth_ropsten" - private var customAuth: CustomAuth? { - didSet { - triggerLogin() - } - } func removeUser() { user = nil - customAuth = nil } +} + +extension ViewModel { + func googlePolygonLogin() { + let sub = SubVerifierDetails(typeOfLogin: .google, verifier: "polygon-ios-test", clientId: "908137525998-fs00a3go5r7fpbntmui4lb8nhuqqtmaa.apps.googleusercontent.com", redirectURL: "https://scripts.toruswallet.io/redirect.html") + + let options = CustomAuthArgs(urlScheme: "torus://org.torusresearch.sample/redirect", network: .legacy(.CYAN), enableOneKey: true, web3AuthClientId: "CLIENT ID") - func triggerLogin() { - let vc = UIApplication.shared.keyWindow?.rootViewController Task { do { - let data = try await customAuth?.triggerLogin(controller: vc) ?? [:] - decodeData(data: data) + let customAuth = try CustomAuth(config: options) + + let keyDetails = try await customAuth.triggerLogin(args: sub) + + user = User(publicAddress: keyDetails.torusKey.finalKeyData.evmAddress, privateKey: keyDetails.torusKey.finalKeyData.privKey, userInfo: keyDetails.singleVerifierResponse.userInfo) } catch { print(error) - self.showingAlert = true } } } - func decodeData(data: [String: Any]) { - guard let privKey = data["privateKey"] as? String, - let pubAddress = data["publicAddress"] as? String, - let userInfo = data["userInfo"] as? [String: Any] else { return } - let dict: [String: String] = userInfo.compactMapValues { $0 as? String } - DispatchQueue.main.async { [weak self] in - self?.user = User(publicAddress: pubAddress, privateKey: privKey, userInfo: dict) - } - } -} + func googleLogin() { + let sub = SubVerifierDetails(typeOfLogin: .google, verifier: "google-lrc", clientId: "221898609709-obfn3p63741l5333093430j3qeiinaa8.apps.googleusercontent.com", redirectURL: "https://scripts.toruswallet.io/redirect.html") -extension ViewModel { - func googlePolygonLogin() { - let sub = SubVerifierDetails(loginType: .web, - loginProvider: .google, - clientId: "908137525998-fs00a3go5r7fpbntmui4lb8nhuqqtmaa.apps.googleusercontent.com", - verifier: "polygon-ios-test", - redirectURL: "torus://org.torusresearch.sample/redirect", - browserRedirectURL: "https://scripts.toruswallet.io/redirect.html", - jwtParams: ["prompt": "login"], - urlSession: URLSession.shared) - customAuth = CustomAuth(aggregateVerifierType: .singleLogin, aggregateVerifier: "polygon-ios-test", subVerifierDetails: [sub], network: .CYAN, urlSession: URLSession.shared) - } + let options = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "CLIENT ID") - func googleLogin() { - let sub = SubVerifierDetails(loginType: .web, - loginProvider: .google, - clientId: "221898609709-obfn3p63741l5333093430j3qeiinaa8.apps.googleusercontent.com", - verifier: "google-lrc", - redirectURL: "tdsdk://tdsdk/oauthCallback", - browserRedirectURL: "https://scripts.toruswallet.io/redirect.html", - jwtParams: ["prompt": "login"]) - - customAuth = CustomAuth(aggregateVerifierType: .singleLogin, aggregateVerifier: "google-lrc", subVerifierDetails: [sub], factory: CASDKFactory(), network: .TESTNET) + Task { + do { + let customAuth = try CustomAuth(config: options) + + let keyDetails = try await customAuth.triggerLogin(args: sub) + + user = User(publicAddress: keyDetails.torusKey.finalKeyData.evmAddress, privateKey: keyDetails.torusKey.finalKeyData.privKey, userInfo: keyDetails.singleVerifierResponse.userInfo) + } catch { + print(error) + } + } } func redditLogin() { - let sub = SubVerifierDetails(loginType: .web, - loginProvider: .reddit, - clientId: "rXIp6g2y3h1wqg", - verifier: "reddit-shubs", - redirectURL: "tdsdk://tdsdk/oauthCallback", - urlSession: URLSession.shared) - customAuth = CustomAuth(aggregateVerifierType: .singleLogin, aggregateVerifier: "reddit-shubs", subVerifierDetails: [sub], factory: CASDKFactory(), network: .TESTNET, urlSession: URLSession.shared) + let sub = SubVerifierDetails(typeOfLogin: .reddit, verifier: "reddit-shubs", clientId: "rXIp6g2y3h1wqg", redirectURL: "https://scripts.toruswallet.io/redirect.html") + + let options = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "CLIENT ID") + + Task { + do { + let customAuth = try CustomAuth(config: options) + + let keyDetails = try await customAuth.triggerLogin(args: sub) + + user = User(publicAddress: keyDetails.torusKey.finalKeyData.evmAddress, privateKey: keyDetails.torusKey.finalKeyData.privKey, userInfo: keyDetails.singleVerifierResponse.userInfo) + } catch { + print(error) + } + } } func discordLogin() { - let sub = SubVerifierDetails(loginType: .web, - loginProvider: .discord, - clientId: "1034724991972954172", - verifier: "dhruv-discord", - redirectURL: "tdsdk://tdsdk/oauthCallback", - browserRedirectURL: "https://scripts.toruswallet.io/redirect.html", - urlSession: URLSession.shared) - customAuth = CustomAuth(aggregateVerifierType: .singleLogin, aggregateVerifier: "dhruv-discord", subVerifierDetails: [sub], factory: CASDKFactory(), network: .TESTNET, urlSession: URLSession.shared) + let sub = SubVerifierDetails(typeOfLogin: .discord, verifier: "dhruv-discord", clientId: "1034724991972954172", redirectURL: "https://scripts.toruswallet.io/redirect.html") + + let options = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "CLIENT ID") + + Task { + do { + let customAuth = try CustomAuth(config: options) + + let keyDetails = try await customAuth.triggerLogin(args: sub) + + user = User(publicAddress: keyDetails.torusKey.finalKeyData.evmAddress, privateKey: keyDetails.torusKey.finalKeyData.privKey, userInfo: keyDetails.singleVerifierResponse.userInfo) + } catch { + print(error) + } + } } func facebookLogin() { - let sub = SubVerifierDetails(loginType: .web, - loginProvider: .facebook, - clientId: "659561074900150", - verifier: "facebook-shubs", - redirectURL: "tdsdk://tdsdk/oauthCallback", - browserRedirectURL: "https://scripts.toruswallet.io/redirect.html", - urlSession: URLSession.shared) - - customAuth = CustomAuth(aggregateVerifierType: .singleLogin, aggregateVerifier: "facebook-shubs", subVerifierDetails: [sub], factory: CASDKFactory(), network: .TESTNET, urlSession: URLSession.shared) + let sub = SubVerifierDetails(typeOfLogin: .facebook, verifier: "facebook-shubs", clientId: "659561074900150", redirectURL: "https://scripts.toruswallet.io/redirect.html") + + let options = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "CLIENT ID") + + Task { + do { + let customAuth = try CustomAuth(config: options) + + let keyDetails = try await customAuth.triggerLogin(args: sub) + + user = User(publicAddress: keyDetails.torusKey.finalKeyData.evmAddress, privateKey: keyDetails.torusKey.finalKeyData.privKey, userInfo: keyDetails.singleVerifierResponse.userInfo) + } catch { + print(error) + } + } } func twitchLogin() { - let sub = SubVerifierDetails(loginType: .web, - loginProvider: .twitch, - clientId: "p560duf74b2bidzqu6uo0b3ot7qaao", - verifier: "twitch-shubs", - redirectURL: "tdsdk://tdsdk/oauthCallback", - urlSession: URLSession.shared) - customAuth = CustomAuth(aggregateVerifierType: .singleLogin, aggregateVerifier: "twitch-shubs", subVerifierDetails: [sub], factory: CASDKFactory(), network: .TESTNET, urlSession: URLSession.shared) + let sub = SubVerifierDetails(typeOfLogin: .twitch, verifier: "twitch-shubs", clientId: "p560duf74b2bidzqu6uo0b3ot7qaao", redirectURL: "https://scripts.toruswallet.io/redirect.html") + + let options = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "CLIENT ID") + + Task { + do { + let customAuth = try CustomAuth(config: options) + + let keyDetails = try await customAuth.triggerLogin(args: sub) + + user = User(publicAddress: keyDetails.torusKey.finalKeyData.evmAddress, privateKey: keyDetails.torusKey.finalKeyData.privKey, userInfo: keyDetails.singleVerifierResponse.userInfo) + } catch { + print(error) + } + } } func twitterLogin() { - let sub = SubVerifierDetails(loginType: .web, - loginProvider: .twitter, - clientId: "A7H8kkcmyFRlusJQ9dZiqBLraG2yWIsO", - verifier: "torus-auth0-twitter-lrc", - redirectURL: "tdsdk://tdsdk/oauthCallback", - jwtParams: ["domain": "torus-test.auth0.com", "connection": "twitter"], - urlSession: URLSession.shared) - - customAuth = CustomAuth(aggregateVerifierType: .singleLogin, aggregateVerifier: "torus-auth0-twitter-lrc", subVerifierDetails: [sub], factory: CASDKFactory(), network: .TESTNET, urlSession: URLSession.shared) + let sub = SubVerifierDetails(typeOfLogin: .twitter, verifier: "torus-auth0-twitter-lrc", clientId: "A7H8kkcmyFRlusJQ9dZiqBLraG2yWIsO", redirectURL: "https://scripts.toruswallet.io/redirect.html") + + let options = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "CLIENT ID") + + Task { + do { + let customAuth = try CustomAuth(config: options) + + let keyDetails = try await customAuth.triggerLogin(args: sub) + + user = User(publicAddress: keyDetails.torusKey.finalKeyData.evmAddress, privateKey: keyDetails.torusKey.finalKeyData.privKey, userInfo: keyDetails.singleVerifierResponse.userInfo) + } catch { + print(error) + } + } } func githubLogin() { - let sub = SubVerifierDetails(loginType: .web, - loginProvider: .github, - clientId: "PC2a4tfNRvXbT48t89J5am0oFM21Nxff", - verifier: "torus-auth0-github-lrc", - redirectURL: "tdsdk://tdsdk/oauthCallback", - jwtParams: ["domain": "torus-test.auth0.com", "connection": "github"], - urlSession: URLSession.shared) - - customAuth = CustomAuth(aggregateVerifierType: .singleLogin, aggregateVerifier: "torus-auth0-github-lrc", subVerifierDetails: [sub], factory: CASDKFactory(), network: .TESTNET, urlSession: URLSession.shared) + let sub = SubVerifierDetails(typeOfLogin: .github, verifier: "torus-auth0-github-lrc", clientId: "PC2a4tfNRvXbT48t89J5am0oFM21Nxff", redirectURL: "https://scripts.toruswallet.io/redirect.html") + + let options = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "CLIENT ID") + + Task { + do { + let customAuth = try CustomAuth(config: options) + + let keyDetails = try await customAuth.triggerLogin(args: sub) + + user = User(publicAddress: keyDetails.torusKey.finalKeyData.evmAddress, privateKey: keyDetails.torusKey.finalKeyData.privKey, userInfo: keyDetails.singleVerifierResponse.userInfo) + } catch { + print(error) + } + } } func linkedinLogin() { - let sub = SubVerifierDetails(loginType: .web, - loginProvider: .linkedin, - clientId: "59YxSgx79Vl3Wi7tQUBqQTRTxWroTuoc", - verifier: "torus-auth0-linkedin-lrc", - redirectURL: "tdsdk://tdsdk/oauthCallback", - jwtParams: ["domain": "torus-test.auth0.com", "connection": "linkedin"], - urlSession: URLSession.shared) - - customAuth = CustomAuth(aggregateVerifierType: .singleLogin, aggregateVerifier: "torus-auth0-linkedin-lrc", subVerifierDetails: [sub], factory: CASDKFactory(), network: .TESTNET, urlSession: URLSession.shared, networkUrl: testnetNetworkUrl) + let sub = SubVerifierDetails(typeOfLogin: .linkedin, verifier: "torus-auth0-linkedin-lrc", clientId: "59YxSgx79Vl3Wi7tQUBqQTRTxWroTuoc", redirectURL: "https://scripts.toruswallet.io/redirect.html") + + let options = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "CLIENT ID") + + Task { + do { + let customAuth = try CustomAuth(config: options) + + let keyDetails = try await customAuth.triggerLogin(args: sub) + + user = User(publicAddress: keyDetails.torusKey.finalKeyData.evmAddress, privateKey: keyDetails.torusKey.finalKeyData.privKey, userInfo: keyDetails.singleVerifierResponse.userInfo) + } catch { + print(error) + } + } } func appleLogin() { - let sub = SubVerifierDetails(loginType: .web, - loginProvider: .apple, - clientId: "m1Q0gvDfOyZsJCZ3cucSQEe9XMvl9d9L", - verifier: "torus-auth0-apple-lrc", - redirectURL: "tdsdk://tdsdk/oauthCallback", - jwtParams: ["domain": "torus-test.auth0.com", "connection": "apple"], - urlSession: URLSession.shared) - - customAuth = CustomAuth(aggregateVerifierType: .singleLogin, aggregateVerifier: "torus-auth0-apple-lrc", subVerifierDetails: [sub], factory: CASDKFactory(), network: .TESTNET, urlSession: URLSession.shared, networkUrl: testnetNetworkUrl) - } + let sub = SubVerifierDetails(typeOfLogin: .apple, verifier: "torus-auth0-apple-lrc", clientId: "m1Q0gvDfOyZsJCZ3cucSQEe9XMvl9d9L", redirectURL: "https://scripts.toruswallet.io/redirect.html") - func emailPasswordlessLogin() { - let sub = SubVerifierDetails(loginType: .web, - loginProvider: .jwt, - clientId: "P7PJuBCXIHP41lcyty0NEb7Lgf7Zme8Q", - verifier: "torus-auth0-email-passwordless", - redirectURL: "tdsdk://tdsdk/oauthCallback", - jwtParams: ["domain": "torus-test.auth0.com", "verifier_id_field": "name"], - urlSession: URLSession.shared) + let options = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "CLIENT ID") - customAuth = CustomAuth(aggregateVerifierType: .singleLogin, aggregateVerifier: "torus-auth0-email-passwordless", subVerifierDetails: [sub], factory: CASDKFactory(), network: .TESTNET, urlSession: URLSession.shared, networkUrl: testnetNetworkUrl) - } + Task { + do { + let customAuth = try CustomAuth(config: options) - func kakaoLogin() { - let sub = SubVerifierDetails(loginType: .web, - loginProvider: .kakao, - clientId: "wpkcc7alGJjEgjaL6q5AWRqgRWHFsdTL", - verifier: "torus-auth0-kakao-lrc", - redirectURL: "tdsdk://tdsdk/oauthCallback", - jwtParams: ["domain": "torus-test.auth0.com"], - urlSession: URLSession.shared) + let keyDetails = try await customAuth.triggerLogin(args: sub) - customAuth = CustomAuth(aggregateVerifierType: .singleLogin, aggregateVerifier: "torus-auth0-kakao-lrc", subVerifierDetails: [sub], factory: CASDKFactory(), network: .TESTNET, urlSession: URLSession.shared, networkUrl: testnetNetworkUrl) + user = User(publicAddress: keyDetails.torusKey.finalKeyData.evmAddress, privateKey: keyDetails.torusKey.finalKeyData.privKey, userInfo: keyDetails.singleVerifierResponse.userInfo) + } catch { + print(error) + } + } } func weiboLogin() { - let sub = SubVerifierDetails(loginType: .web, - loginProvider: .apple, - clientId: "dhFGlWQMoACOI5oS5A1jFglp772OAWr1", - verifier: "torus-auth0-weibo-lrc", - redirectURL: "tdsdk://tdsdk/oauthCallback", - jwtParams: ["domain": "torus-test.auth0.com"], - urlSession: URLSession.shared) - - customAuth = CustomAuth(aggregateVerifierType: .singleLogin, aggregateVerifier: "torus-auth0-weibo-lrc", subVerifierDetails: [sub], factory: CASDKFactory(), network: .TESTNET, urlSession: URLSession.shared, networkUrl: testnetNetworkUrl) - } + let sub = SubVerifierDetails( + typeOfLogin: .weibo, + verifier: "torus-auth0-weibo-lrc", + clientId: "dhFGlWQMoACOI5oS5A1jFglp772OAWr1", + redirectURL: "tdsdk://tdsdk/oauthCallback") + + let options = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "CLIENT ID") + + Task { + do { + let customAuth = try CustomAuth(config: options) - func wechatLogin() { - let sub = SubVerifierDetails(loginType: .web, - loginProvider: .wechat, - clientId: "cewDD3i6F1vtHeV1KIbaxUZ8vJQjJZ8V", - verifier: "torus-auth0-wechat-lrc", - redirectURL: "tdsdk://tdsdk/oauthCallback", - jwtParams: ["domain": "torus-test.auth0.com"], - urlSession: URLSession.shared) + let keyDetails = try await customAuth.triggerLogin(args: sub) - customAuth = CustomAuth(aggregateVerifierType: .singleLogin, aggregateVerifier: "torus-auth0-wechat-lrc", subVerifierDetails: [sub], factory: CASDKFactory(), network: .TESTNET, urlSession: URLSession.shared) + user = User(publicAddress: keyDetails.torusKey.finalKeyData.evmAddress, privateKey: keyDetails.torusKey.finalKeyData.privKey, userInfo: keyDetails.singleVerifierResponse.userInfo) + } catch { + print(error) + } + } } + + func emailPasswordLogin() { + let sub = SubVerifierDetails( + typeOfLogin: .email_password, + verifier: "torus-auth0-email-password", + clientId: "sqKRBVSdwa4WLkaq419U7Bamlh5vK1H7", + redirectURL: "tdsdk://tdsdk/oauthCallback", + jwtParams: Auth0ClientOptions( + connection: "Username-Password-Authentication", + domain: "torus-test.auth0.com", + verifierIdField: "name")) - func googleDeepLinkFlowLogin() { - let sub = SubVerifierDetails(loginType: .installed, - loginProvider: .google, - clientId: "238941746713-vfap8uumijal4ump28p9jd3lbe6onqt4.apps.googleusercontent.com", - verifier: "google-ios", - redirectURL: "com.googleusercontent.apps.238941746713-vfap8uumijal4ump28p9jd3lbe6onqt4:/oauthredirect", - urlSession: URLSession.shared) - customAuth = CustomAuth(aggregateVerifierType: .singleIdVerifier, aggregateVerifier: "multigoogle-torus", subVerifierDetails: [sub], factory: CASDKFactory(), network: .TESTNET, urlSession: URLSession.shared) + let options = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + + Task { + do { + let customAuth = try CustomAuth(config: options) + + let keyDetails = try await customAuth.triggerLogin(args: sub) + + user = User(publicAddress: keyDetails.torusKey.finalKeyData.evmAddress, privateKey: keyDetails.torusKey.finalKeyData.privKey, userInfo: keyDetails.singleVerifierResponse.userInfo) + } catch { + print(error) + } + } } } From dfa6cb5e935524c0b32c430dcbbc32f02503e337 Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Wed, 31 Jul 2024 05:08:42 +0200 Subject: [PATCH 03/24] update --- .../xcschemes/CustomAuthDemoTests.xcscheme | 9 --- .../CustomAuthDemo/ContentView.swift | 2 +- .../xcshareddata/swiftpm/Package.resolved | 65 +++++++++++++++++-- 3 files changed, 60 insertions(+), 16 deletions(-) diff --git a/CustomAuthDemo/CustomAuthDemo.xcodeproj/xcshareddata/xcschemes/CustomAuthDemoTests.xcscheme b/CustomAuthDemo/CustomAuthDemo.xcodeproj/xcshareddata/xcschemes/CustomAuthDemoTests.xcscheme index 5e0c2e2..3d2399c 100644 --- a/CustomAuthDemo/CustomAuthDemo.xcodeproj/xcshareddata/xcschemes/CustomAuthDemoTests.xcscheme +++ b/CustomAuthDemo/CustomAuthDemo.xcodeproj/xcshareddata/xcschemes/CustomAuthDemoTests.xcscheme @@ -53,15 +53,6 @@ savedToolIdentifier = "" useCustomWorkingDirectory = "NO" debugDocumentVersioning = "YES"> - - - - diff --git a/CustomAuthDemo/CustomAuthDemo/ContentView.swift b/CustomAuthDemo/CustomAuthDemo/ContentView.swift index 0e19e94..8bf9724 100644 --- a/CustomAuthDemo/CustomAuthDemo/ContentView.swift +++ b/CustomAuthDemo/CustomAuthDemo/ContentView.swift @@ -126,7 +126,7 @@ struct ContentView: View { }) Button(action: { - let sub = SubVerifierDetails(typeOfLogin: .jwt, + let sub = SubVerifierDetails(typeOfLogin: .github, verifier: "w3a-auth0-demo", clientId: "hUVVf4SEsZT7syOiL0gLU9hFEtm2gQ6O", redirectURL: "tdsdk://tdsdk/oauthCallback", jwtParams: Auth0ClientOptions(connection: "github", domain: "web3auth.au.auth0.com", verifierIdField: "sub")) let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") diff --git a/Development.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Development.xcworkspace/xcshareddata/swiftpm/Package.resolved index 9efd57e..3c3c0e7 100644 --- a/Development.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Development.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,15 +1,68 @@ { - "originHash" : "15db2e52658433a7d473400cc03eb7d9196e5e1ee7c0636fcf9c95b35e7c0bf1", "pins" : [ { - "identity" : "promisekit", + "identity" : "bigint", "kind" : "remoteSourceControl", - "location" : "https://github.com/mxcl/PromiseKit", + "location" : "https://github.com/attaswift/BigInt.git", "state" : { - "revision" : "cb70b070cde06837cd10a1febdf6105c1a3bb348", - "version" : "8.1.1" + "revision" : "0ed110f7555c34ff468e72e1686e59721f2b0da6", + "version" : "5.3.0" + } + }, + { + "identity" : "curvelib.swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/tkey/curvelib.swift", + "state" : { + "revision" : "9f88bd5e56d1df443a908f7a7e81ae4f4d9170ea", + "version" : "1.0.1" + } + }, + { + "identity" : "fetch-node-details-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/torusresearch/fetch-node-details-swift", + "state" : { + "revision" : "4bd96c33ba8d02d9e27190c5c7cedf09cfdfd656", + "version" : "6.0.3" + } + }, + { + "identity" : "jwt-kit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/vapor/jwt-kit.git", + "state" : { + "revision" : "e05513b5aec24f88012b6e3034115b6bc915356a", + "version" : "4.13.2" + } + }, + { + "identity" : "jwtdecode.swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/auth0/JWTDecode.swift.git", + "state" : { + "revision" : "58af7278797871e460d79496621b3e5366b865b2", + "version" : "3.1.0" + } + }, + { + "identity" : "swift-crypto", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-crypto.git", + "state" : { + "revision" : "f0525da24dc3c6cbb2b6b338b65042bc91cbc4bb", + "version" : "3.3.0" + } + }, + { + "identity" : "torus-utils-swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/torusresearch/torus-utils-swift.git", + "state" : { + "revision" : "303dc2cf41db7c10f769855edad0e717ced2d554", + "version" : "9.0.0" } } ], - "version" : 3 + "version" : 2 } From caf4c5865054687996991253ec1ca1a3c4e8c17e Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Thu, 5 Sep 2024 02:00:21 +0200 Subject: [PATCH 04/24] review comments Check defaults for CustomAuthArgs Check login types, implement caseSensitiveField helper function, use helper in getVerifierId --- .../Common/LoginParams/LoginType.swift | 3 ++ Sources/CustomAuth/CustomAuth.swift | 4 +- Sources/CustomAuth/CustomAuthArgs.swift | 21 +++++++++-- .../CustomAuth/Handlers/HandlerFactory.swift | 37 +++++++++++++++---- Sources/CustomAuth/Helpers/Common.swift | 16 ++++++-- 5 files changed, 65 insertions(+), 16 deletions(-) diff --git a/Sources/CustomAuth/Common/LoginParams/LoginType.swift b/Sources/CustomAuth/Common/LoginParams/LoginType.swift index d260882..4463237 100644 --- a/Sources/CustomAuth/Common/LoginParams/LoginType.swift +++ b/Sources/CustomAuth/Common/LoginParams/LoginType.swift @@ -14,4 +14,7 @@ public enum LoginType: String, Equatable, Hashable, Codable { case line case email_password case passwordless + case email_passwordless + case sms_passwordless + case jwt } diff --git a/Sources/CustomAuth/CustomAuth.swift b/Sources/CustomAuth/CustomAuth.swift index e658c68..3978b9d 100644 --- a/Sources/CustomAuth/CustomAuth.swift +++ b/Sources/CustomAuth/CustomAuth.swift @@ -42,7 +42,7 @@ public class CustomAuth { let torusUtils = try TorusUtils(params: torusOptions) torus = torusUtils - torus.setApiKey(apiKey: config.apiKey ?? "") + torus.setApiKey(apiKey: config.apiKey) } /// Initiates a login using a single verifier @@ -219,7 +219,7 @@ public class CustomAuth { /// - Returns: `TorusKey` /// /// - Throws: `CASDKError`, `TorusUtilError`, `FetchNodeError` - func getTorusKey(verifier: String, verifierParams: VerifierParams, idToken: String) async throws -> TorusKey { + func getTorusKey(verifier: String, verifierParams: VerifierParams, idToken: String, extraParams: TorusUtilsExtraParams? = nil) async throws -> TorusKey { let nodeDetails = try await nodeDetailManager.getNodeDetails(verifier: verifier, verifierID: verifierParams.verifier_id) return try await torus.retrieveShares(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierParams: verifierParams, idToken: idToken) diff --git a/Sources/CustomAuth/CustomAuthArgs.swift b/Sources/CustomAuth/CustomAuthArgs.swift index f7a0879..5234360 100644 --- a/Sources/CustomAuth/CustomAuthArgs.swift +++ b/Sources/CustomAuth/CustomAuthArgs.swift @@ -3,17 +3,29 @@ import Foundation public class CustomAuthArgs { public let urlScheme: String - public let metadataUrl: String? + public let metadataUrl: String public let network: TorusNetwork public let enableLogging: Bool public let enableOneKey: Bool - public let apiKey: String? + public let apiKey: String public let popupFeatures: String? - public let storageServerUrl: String? + public let storageServerUrl: String public let web3AuthClientId: String public let serverTimeOffset: Int + public let useDkg: Bool // TODO: Implement usage of this - public init(urlScheme: String, metadataUrl: String? = nil, network: TorusNetwork, enableLogging: Bool = false, enableOneKey: Bool, apiKey: String? = nil, popupFeatures: String? = nil, storageServerUrl: String? = nil, web3AuthClientId: String, serverTimeOffset: Int = 0, legacyMetadataHost: String? = nil) { + public init(urlScheme: String, + network: TorusNetwork, + metadataUrl: String = "https://metadata.tor.us", + enableLogging: Bool = false, + apiKey: String = "torus-default", + storageServerUrl: String = "https://session.web3auth.io", + enableOneKey: Bool = false, + web3AuthClientId: String, + useDkg: Bool, + serverTimeOffset: Int = 0, + popupFeatures: String? = nil + ) { self.urlScheme = urlScheme self.metadataUrl = metadataUrl self.network = network @@ -24,5 +36,6 @@ public class CustomAuthArgs { self.storageServerUrl = storageServerUrl self.web3AuthClientId = web3AuthClientId self.serverTimeOffset = serverTimeOffset + self.useDkg = useDkg } } diff --git a/Sources/CustomAuth/Handlers/HandlerFactory.swift b/Sources/CustomAuth/Handlers/HandlerFactory.swift index aee28ed..8221679 100644 --- a/Sources/CustomAuth/Handlers/HandlerFactory.swift +++ b/Sources/CustomAuth/Handlers/HandlerFactory.swift @@ -1,23 +1,31 @@ import Foundation -internal class HandlerFactory { +internal class HandlerFactory { static func createHandler( params: CreateHandlerParams ) throws -> ILoginHandler { if params.verifier.isEmpty { throw CASDKError.invalidVerifier } - + if params.clientId.isEmpty { throw CASDKError.invalidClientID } + let domain = params.jwtParams?.domain + let hint = params.jwtParams?.login_hint + let idToken = params.jwtParams?.id_token + let accessToken = params.jwtParams?.access_token + switch params.typeOfLogin { case .google: return try GoogleLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin, jwtParams: params.jwtParams, customState: params.customState) case .facebook: return try FacebookLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin, jwtParams: params.jwtParams, customState: params.customState) case .reddit: + if idToken != nil || accessToken != nil { + return try MockLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin, jwtParams: params.jwtParams, customState: params.customState) + } return try RedditLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin, jwtParams: params.jwtParams, customState: params.customState) case .twitch: return try TwitchLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin, jwtParams: params.jwtParams, customState: params.customState) @@ -30,15 +38,30 @@ internal class HandlerFactory { case .weibo: break case .line: break case .email_password: break - case .passwordless: return try PasswordlessLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin, jwtParams: params.jwtParams, customState: params.customState) + case .passwordless: + if domain == nil || hint == nil { + throw CASDKError.invalidAuth0Options + } + return try PasswordlessLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin, jwtParams: params.jwtParams, customState: params.customState) + case .email_passwordless: + if domain == nil || hint == nil { + throw CASDKError.invalidAuth0Options + } + throw CASDKError.invalidAuth0Options + // TODO: implement web3authpasswordlesshandler for this + case .sms_passwordless: + if hint == nil { + throw CASDKError.invalidAuth0Options + } + throw CASDKError.invalidAuth0Options + // TODO: implement web3authpasswordlesshandler for this + case .jwt: break } - - if params.jwtParams?.id_token != nil || params.jwtParams?.access_token != nil { + if idToken != nil || accessToken != nil { return try MockLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin, jwtParams: params.jwtParams, customState: params.customState) } - - let domain = params.jwtParams?.domain + if domain == nil { throw CASDKError.invalidAuth0Options } diff --git a/Sources/CustomAuth/Helpers/Common.swift b/Sources/CustomAuth/Helpers/Common.swift index 2915de4..ed32df2 100644 --- a/Sources/CustomAuth/Helpers/Common.swift +++ b/Sources/CustomAuth/Helpers/Common.swift @@ -15,10 +15,17 @@ internal func loginToConnection(loginType: LoginType) -> String { case .line: break case .email_password: return "Username-Password-Authentication" case .passwordless: return "email" + case .email_passwordless: return "email" + case .sms_passwordless: return "sms" + case .jwt: break } return loginType.rawValue } +internal func caseSensitiveField(field: String, isCaseSensitive: Bool) -> String{ + return isCaseSensitive ? field : field.lowercased() +} + internal func getVerifierId( userInfo: Auth0UserInfo, typeOfLogin: LoginType, @@ -32,10 +39,14 @@ internal func getVerifierId( let json = try JSONSerialization.jsonObject(with: encoded, options: []) as! [String: String] if verifierIdField != nil { - return json[isVerifierIdCaseSensitive ? verifierIdField!.lowercased() : verifierIdField!]! + return json[caseSensitiveField(field: verifierIdField!, isCaseSensitive: isVerifierIdCaseSensitive)]! } switch typeOfLogin { + case .passwordless: return name + case .email_password: return name + case .email_passwordless: return name + case .sms_passwordless: return caseSensitiveField(field: name, isCaseSensitive: isVerifierIdCaseSensitive) case .google: return sub case .facebook: return sub case .reddit: return sub @@ -47,8 +58,7 @@ internal func getVerifierId( case .twitter: return sub case .weibo: return sub case .line: return sub - case .email_password: return name - case .passwordless: return name + case .jwt: return caseSensitiveField(field: sub, isCaseSensitive: isVerifierIdCaseSensitive) } } From 44d02d04a13441e9d8c278536d5da4753e5496b2 Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Thu, 5 Sep 2024 09:50:12 +0200 Subject: [PATCH 05/24] remove passkeyextra params commenting it out since it will need to be put back in the passkeys implementation --- .../Common/LoginParams/TorusSubVerifierInfo.swift | 6 +++--- .../CustomAuth/Common/Passkeys/PassKeyExtraParams.swift | 2 ++ .../VerifierResponses/TorusVerifierResponses.swift | 7 ++++--- .../CustomAuth/Common/VerifierResponses/UserInfo.swift | 7 ++++--- Sources/CustomAuth/CustomAuth.swift | 9 ++++++--- 5 files changed, 19 insertions(+), 12 deletions(-) diff --git a/Sources/CustomAuth/Common/LoginParams/TorusSubVerifierInfo.swift b/Sources/CustomAuth/Common/LoginParams/TorusSubVerifierInfo.swift index 74f9873..b737871 100644 --- a/Sources/CustomAuth/Common/LoginParams/TorusSubVerifierInfo.swift +++ b/Sources/CustomAuth/Common/LoginParams/TorusSubVerifierInfo.swift @@ -3,11 +3,11 @@ import Foundation public class TorusSubVerifierInfo: Codable { public let verifier: String public let idToken: String - public let extraVerifierParams: PassKeyExtraParams? + // public let extraVerifierParams: PassKeyExtraParams? - public init(verifier: String, idToken: String, extraVerifierParams: PassKeyExtraParams? = nil) { + public init(verifier: String, idToken: String) { //, extraVerifierParams: PassKeyExtraParams? = nil) { self.verifier = verifier self.idToken = idToken - self.extraVerifierParams = extraVerifierParams + // self.extraVerifierParams = extraVerifierParams } } diff --git a/Sources/CustomAuth/Common/Passkeys/PassKeyExtraParams.swift b/Sources/CustomAuth/Common/Passkeys/PassKeyExtraParams.swift index 924fbc0..c881ddc 100644 --- a/Sources/CustomAuth/Common/Passkeys/PassKeyExtraParams.swift +++ b/Sources/CustomAuth/Common/Passkeys/PassKeyExtraParams.swift @@ -1,3 +1,4 @@ +/* import Foundation public class PassKeyExtraParams: Codable { @@ -25,3 +26,4 @@ public class PassKeyExtraParams: Codable { self.username = username } } +*/ diff --git a/Sources/CustomAuth/Common/VerifierResponses/TorusVerifierResponses.swift b/Sources/CustomAuth/Common/VerifierResponses/TorusVerifierResponses.swift index f66c938..b45dc29 100644 --- a/Sources/CustomAuth/Common/VerifierResponses/TorusVerifierResponses.swift +++ b/Sources/CustomAuth/Common/VerifierResponses/TorusVerifierResponses.swift @@ -10,9 +10,10 @@ public class TorusVerifierResponse: Codable { public let verifierId: String public let typeOfLogin: LoginType public let ref: String? - public let extraVerifierParams: PassKeyExtraParams? + // public let extraVerifierParams: PassKeyExtraParams? - public init(email: String, name: String, profileImage: String, aggregateVerifier: String? = nil, verifier: String, verifierId: String, typeOfLogin: LoginType, ref: String? = nil, extraVerifierParams: PassKeyExtraParams? = nil) { + public init(email: String, name: String, profileImage: String, aggregateVerifier: String? = nil, verifier: String, verifierId: String, typeOfLogin: LoginType, ref: String? = nil) { + //, extraVerifierParams: PassKeyExtraParams? = nil) { self.email = email self.name = name self.profileImage = profileImage @@ -21,6 +22,6 @@ public class TorusVerifierResponse: Codable { self.verifierId = verifierId self.typeOfLogin = typeOfLogin self.ref = ref - self.extraVerifierParams = extraVerifierParams + // self.extraVerifierParams = extraVerifierParams } } diff --git a/Sources/CustomAuth/Common/VerifierResponses/UserInfo.swift b/Sources/CustomAuth/Common/VerifierResponses/UserInfo.swift index f9895df..5b3f605 100644 --- a/Sources/CustomAuth/Common/VerifierResponses/UserInfo.swift +++ b/Sources/CustomAuth/Common/VerifierResponses/UserInfo.swift @@ -9,14 +9,15 @@ public class UserInfo: Codable { public let verifierId: String public let typeOfLogin: LoginType public let ref: String? - public let extraVerifierParams: PassKeyExtraParams? + // public let extraVerifierParams: PassKeyExtraParams? public let accessToken: String? public let idToken: String? public let extraParams: String? public let extraParamsPassed: String? public let state: TorusGenericContainer - public init(email: String, name: String, profileImage: String, aggregateVerifier: String? = nil, verifier: String, verifierId: String, typeOfLogin: LoginType, ref: String? = nil, extraVerifierParams: PassKeyExtraParams? = nil, accessToken: String? = nil, idToken: String? = nil, extraParams: String? = nil, extraParamsPassed: String? = nil, state: TorusGenericContainer) { + public init(email: String, name: String, profileImage: String, aggregateVerifier: String? = nil, verifier: String, verifierId: String, typeOfLogin: LoginType, ref: String? = nil, // extraVerifierParams: PassKeyExtraParams? = nil, + accessToken: String? = nil, idToken: String? = nil, extraParams: String? = nil, extraParamsPassed: String? = nil, state: TorusGenericContainer) { self.email = email self.name = name self.profileImage = profileImage @@ -25,7 +26,7 @@ public class UserInfo: Codable { self.verifierId = verifierId self.typeOfLogin = typeOfLogin self.ref = ref - self.extraVerifierParams = extraVerifierParams + // extraVerifierParams = extraVerifierParams self.accessToken = accessToken self.idToken = idToken self.extraParams = extraParams diff --git a/Sources/CustomAuth/CustomAuth.swift b/Sources/CustomAuth/CustomAuth.swift index 3978b9d..9cf6ea0 100644 --- a/Sources/CustomAuth/CustomAuth.swift +++ b/Sources/CustomAuth/CustomAuth.swift @@ -73,7 +73,8 @@ public class CustomAuth { let torusKey = try await getTorusKey(verifier: userInfo.verifier, verifierParams: verifyParams, idToken: loginParams.idToken ?? loginParams.accessToken ?? "") - 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, accessToken: loginParams.accessToken, idToken: loginParams.idToken, extraParams: loginParams.extraParams, extraParamsPassed: loginParams.extraParamsPassed, state: loginParams.state) + 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, + accessToken: loginParams.accessToken, idToken: loginParams.idToken, extraParams: loginParams.extraParams, extraParamsPassed: loginParams.extraParamsPassed, state: loginParams.state) return TorusLoginResponse(singleVerifierResponse: TorusSingleVerifierResponse(userInfo: returnedInfo, loginResponse: loginParams), torusKey: torusKey) } @@ -111,7 +112,8 @@ public class CustomAuth { } let info = try await loginHandler.getUserInfo(params: loginParams, storageServerUrl: nil) - 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, accessToken: loginParams.accessToken, idToken: loginParams.idToken, extraParams: loginParams.extraParams, extraParamsPassed: loginParams.extraParamsPassed, state: loginParams.state) + 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, + accessToken: loginParams.accessToken, idToken: loginParams.idToken, extraParams: loginParams.extraParams, extraParamsPassed: loginParams.extraParamsPassed, state: loginParams.state) loginParamsArray.append(loginParams) userInfoArray.append(userInfo) } @@ -182,7 +184,8 @@ public class CustomAuth { let torusKey = try await getTorusKey(verifier: userInfo.verifier, verifierParams: verifyParams, idToken: loginParams.idToken!) - 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, accessToken: loginParams.accessToken, idToken: loginParams.idToken, extraParams: loginParams.extraParams, extraParamsPassed: loginParams.extraParamsPassed, state: loginParams.state) + 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, + accessToken: loginParams.accessToken, idToken: loginParams.idToken, extraParams: loginParams.extraParams, extraParamsPassed: loginParams.extraParamsPassed, state: loginParams.state) var subVerifierIds: [String] = [] var aggregateVerifierParams: [VerifyParams] = [] From 1cc8fb78117cf2d3f74120f859c9496ca9d0f126 Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Mon, 9 Sep 2024 06:15:01 +0200 Subject: [PATCH 06/24] make useDKG optional and defaulted to true --- Sources/CustomAuth/CustomAuthArgs.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/CustomAuth/CustomAuthArgs.swift b/Sources/CustomAuth/CustomAuthArgs.swift index 5234360..310b054 100644 --- a/Sources/CustomAuth/CustomAuthArgs.swift +++ b/Sources/CustomAuth/CustomAuthArgs.swift @@ -22,7 +22,7 @@ public class CustomAuthArgs { storageServerUrl: String = "https://session.web3auth.io", enableOneKey: Bool = false, web3AuthClientId: String, - useDkg: Bool, + useDkg: Bool = true, serverTimeOffset: Int = 0, popupFeatures: String? = nil ) { From aa257918072bd920122b687decc22a6f9aaa3e64 Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Mon, 9 Sep 2024 08:05:29 +0200 Subject: [PATCH 07/24] fix: swapped urls for passwordless and jwt --- Sources/CustomAuth/Handlers/JWTLoginHandler.swift | 2 +- Sources/CustomAuth/Handlers/PasswordlessLoginHandler.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/CustomAuth/Handlers/JWTLoginHandler.swift b/Sources/CustomAuth/Handlers/JWTLoginHandler.swift index 0599e02..f07e372 100644 --- a/Sources/CustomAuth/Handlers/JWTLoginHandler.swift +++ b/Sources/CustomAuth/Handlers/JWTLoginHandler.swift @@ -55,7 +55,7 @@ internal class JWTLoginHandler: AbstractLoginHandler { ], uniquingKeysWith: { _, new in new }) urlComponents.scheme = "https" urlComponents.host = jwtParams?.domain - urlComponents.path = "/passwordless/start" + urlComponents.path = "/authorize" urlComponents.setQueryItems(with: params) finalUrl = urlComponents diff --git a/Sources/CustomAuth/Handlers/PasswordlessLoginHandler.swift b/Sources/CustomAuth/Handlers/PasswordlessLoginHandler.swift index 2176c18..4c2b2d7 100644 --- a/Sources/CustomAuth/Handlers/PasswordlessLoginHandler.swift +++ b/Sources/CustomAuth/Handlers/PasswordlessLoginHandler.swift @@ -39,7 +39,7 @@ internal class PasswordlessLoginHandler: AbstractLoginHandler { ], uniquingKeysWith: { _, new in new }) urlComponents.scheme = "https" urlComponents.host = jwtParams?.domain - urlComponents.path = "/authorize" + urlComponents.path = "/passwordless/start" urlComponents.setQueryItems(with: params) finalUrl = urlComponents From b22ff1be9c2fb519b08490bc87530cefc7f584f1 Mon Sep 17 00:00:00 2001 From: Mohammad Shahbaz Alam Date: Mon, 9 Sep 2024 11:58:42 +0530 Subject: [PATCH 08/24] New configs and verifier details --- .../CustomAuthDemo.xcodeproj/project.pbxproj | 20 ++++ .../xcshareddata/swiftpm/Package.resolved | 10 +- .../CustomAuthDemo/ContentView.swift | 113 ++++++++++-------- 3 files changed, 85 insertions(+), 58 deletions(-) diff --git a/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.pbxproj b/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.pbxproj index 208ada2..9b6516f 100644 --- a/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.pbxproj +++ b/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 275FCF862C8EABF40010F33B /* CustomAuth in Frameworks */ = {isa = PBXBuildFile; productRef = 275FCF852C8EABF40010F33B /* CustomAuth */; }; 511CEAD02452D4EC00A7ACE9 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 511CEACF2452D4EC00A7ACE9 /* ContentView.swift */; }; 511CEAD22452D4EF00A7ACE9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 511CEAD12452D4EF00A7ACE9 /* Assets.xcassets */; }; 511CEAD52452D4EF00A7ACE9 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 511CEAD42452D4EF00A7ACE9 /* Preview Assets.xcassets */; }; @@ -57,6 +58,7 @@ buildActionMask = 2147483647; files = ( 51775EB72484B66A00A29680 /* CustomAuth in Frameworks */, + 275FCF862C8EABF40010F33B /* CustomAuth in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -172,6 +174,7 @@ name = CustomAuthDemo; packageProductDependencies = ( 51775EB62484B66A00A29680 /* CustomAuth */, + 275FCF852C8EABF40010F33B /* CustomAuth */, ); productName = CustomAuthDemo; productReference = 511CEAC82452D4EC00A7ACE9 /* CustomAuthDemo.app */; @@ -253,6 +256,7 @@ ); mainGroup = 511CEABF2452D4EC00A7ACE9; packageReferences = ( + 275FCF842C8EABF40010F33B /* XCRemoteSwiftPackageReference "customauth-swift-sdk" */, ); productRefGroup = 511CEAC92452D4EC00A7ACE9 /* Products */; projectDirPath = ""; @@ -622,7 +626,23 @@ }; /* End XCConfigurationList section */ +/* Begin XCRemoteSwiftPackageReference section */ + 275FCF842C8EABF40010F33B /* XCRemoteSwiftPackageReference "customauth-swift-sdk" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/torusresearch/customauth-swift-sdk/"; + requirement = { + branch = features_update; + kind = branch; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + /* Begin XCSwiftPackageProductDependency section */ + 275FCF852C8EABF40010F33B /* CustomAuth */ = { + isa = XCSwiftPackageProductDependency; + package = 275FCF842C8EABF40010F33B /* XCRemoteSwiftPackageReference "customauth-swift-sdk" */; + productName = CustomAuth; + }; 51775EB62484B66A00A29680 /* CustomAuth */ = { isa = XCSwiftPackageProductDependency; productName = CustomAuth; diff --git a/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index f186bd8..05c608e 100644 --- a/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -5,8 +5,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/attaswift/BigInt.git", "state" : { - "revision" : "0ed110f7555c34ff468e72e1686e59721f2b0da6", - "version" : "5.3.0" + "revision" : "793a7fac0bfc318e85994bf6900652e827aef33e", + "version" : "5.4.1" } }, { @@ -50,8 +50,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-crypto.git", "state" : { - "revision" : "bc1c29221f6dfeb0ebbfbc98eb95cd3d4967868e", - "version" : "3.4.0" + "revision" : "9f95b4d033a4edd3814b48608db3f2ca90c7218b", + "version" : "3.7.0" } }, { @@ -59,7 +59,7 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/torusresearch/torus-utils-swift.git", "state" : { - "revision" : "7788752bed699b3d34e78c2c51174f814d02610b", + "revision" : "303dc2cf41db7c10f769855edad0e717ced2d554", "version" : "9.0.0" } } diff --git a/CustomAuthDemo/CustomAuthDemo/ContentView.swift b/CustomAuthDemo/CustomAuthDemo/ContentView.swift index 8bf9724..dbde22e 100644 --- a/CustomAuthDemo/CustomAuthDemo/ContentView.swift +++ b/CustomAuthDemo/CustomAuthDemo/ContentView.swift @@ -8,16 +8,15 @@ struct ContentView: View { Button(action: { Task { do { - let sub = SingleLoginParams(typeOfLogin: .google, verifier: "google-lrc", clientId: "221898609709-obfn3p63741l5333093430j3qeiinaa8.apps.googleusercontent.com", redirectURL: "https://scripts.toruswallet.io/redirect.html") - - let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_DEVNET), enableOneKey: true, web3AuthClientId: "BAh0_c0G8U8GoMUIYDcX_f65fU_N9O0mWz6xM6RqBfaaAlYsTha8oOef7ifXPjd_bCTJdfWQemmrbY6KepC7XNA") + let sub = SingleLoginParams(typeOfLogin: .google, verifier: "w3a-google-demo", clientId: "519228911939-cri01h55lsjbsia1k7ll6qpalrus75ps.apps.googleusercontent.com", redirectURL: "https://scripts.toruswallet.io/redirect.html") + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") let customAuth = try CustomAuth(config: customAuthArgs) let torusLoginResponse = try await customAuth.triggerLogin(args: sub) let encoded = try JSONEncoder().encode(torusLoginResponse) - debugPrint(String(data: encoded, encoding: .utf8)!) + print(String(data: encoded, encoding: .utf8)!) } catch { - debugPrint(error) + print(error) } } @@ -28,9 +27,9 @@ struct ContentView: View { Button(action: { Task { do { - let sub = SingleLoginParams(typeOfLogin: .discord, verifier: "dhruv-discord", clientId: "1034724991972954172", redirectURL: "https://scripts.toruswallet.io/redirect.html") + let sub = SingleLoginParams(typeOfLogin: .discord, verifier: "w3a-discord-demo", clientId: "1151006428610433095", redirectURL: "https://scripts.toruswallet.io/redirect.html") - let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "BHgArYmWwSeq21czpcarYh0EVq2WWOzflX-NTK-tY1-1pauPzHKRRLgpABkmYiIV_og9jAvoIxQ8L3Smrwe04Lw") + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") let customAuth = try CustomAuth(config: customAuthArgs) let torusLoginResponse = try await customAuth.triggerLogin(args: sub) @@ -39,7 +38,6 @@ struct ContentView: View { } catch { print(error) } - } }, label: { Text("Discord Login") @@ -47,32 +45,27 @@ struct ContentView: View { Button(action: { - Task { - do { - let sub = SingleLoginParams(typeOfLogin: .facebook, verifier: "w3a-facebook-demo", - clientId: "342380202252650", - redirectURL: "https://scripts.toruswallet.io/redirect.html") - - let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") - - let customAuth = try CustomAuth(config: customAuthArgs) - let torusLoginResponse = try await customAuth.triggerLogin(args: sub) - let encoded = try JSONEncoder().encode(torusLoginResponse) - debugPrint(String(data: encoded, encoding: .utf8)!) - } catch { - debugPrint(error) - } - - } + Task { + do { + let sub = SingleLoginParams(typeOfLogin: .facebook, verifier: "w3a-facebook-demo", clientId: "342380202252650", redirectURL: "https://scripts.toruswallet.io/redirect.html") + + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + + let customAuth = try CustomAuth(config: customAuthArgs) + let torusLoginResponse = try await customAuth.triggerLogin(args: sub) + let encoded = try JSONEncoder().encode(torusLoginResponse) + print(String(data: encoded, encoding: .utf8)!) + } catch { + print(error) + } + } }, label: { Text("Facebook Login") }) Button(action: { - let sub = SubVerifierDetails(typeOfLogin: .reddit, - verifier: "reddit-shubs", clientId: "rXIp6g2y3h1wqg", - redirectURL: "tdsdk://tdsdk/oauthCallback") - let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + let sub = SingleLoginParams(typeOfLogin: .twitch, verifier: "w3a-twitch-demo", clientId: "3k7e70gowvxjaxg71hjnc8h8ih3bpf", redirectURL: "https://scripts.toruswallet.io/redirect.html") + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") Task { do { let customAuth = try CustomAuth(config: customAuthArgs) @@ -84,14 +77,12 @@ struct ContentView: View { } } }, label: { - Text("Reddit Login") + Text("Twitch Login") }) Button(action: { - let sub = SubVerifierDetails(typeOfLogin: .twitch, - verifier: "twitch-shubs", clientId: "p560duf74b2bidzqu6uo0b3ot7qaao", - redirectURL: "tdsdk://tdsdk/oauthCallback") - let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + let sub = SingleLoginParams(typeOfLogin: .apple, verifier: "w3a-auth0-demo", clientId: "hUVVf4SEsZT7syOiL0gLU9hFEtm2gQ6O", redirectURL: "https://scripts.toruswallet.io/redirect.html", jwtParams: Auth0ClientOptions(connection: "apple", domain: "web3auth.au.auth0.com")) + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") Task { do { let customAuth = try CustomAuth(config: customAuthArgs) @@ -103,13 +94,11 @@ struct ContentView: View { } } }, label: { - Text("Twitch Login") + Text("Apple Login") }) Button(action: { - let sub = SubVerifierDetails(typeOfLogin: .apple, - verifier: "w3a-auth0-demo", clientId: "hUVVf4SEsZT7syOiL0gLU9hFEtm2gQ6O", - redirectURL: "tdsdk://tdsdk/oauthCallback", jwtParams: Auth0ClientOptions(domain: "web3auth.au.auth0.com")) + let sub = SingleLoginParams(typeOfLogin: .github, verifier: "w3a-auth0-demo", clientId: "hUVVf4SEsZT7syOiL0gLU9hFEtm2gQ6O", redirectURL: "https://scripts.toruswallet.io/redirect.html", jwtParams: Auth0ClientOptions(connection: "github", domain: "web3auth.au.auth0.com", verifierIdField: "sub")) let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") Task { do { @@ -122,14 +111,17 @@ struct ContentView: View { } } }, label: { - Text("Apple Login") + Text("JWT Login") }) Button(action: { - let sub = SubVerifierDetails(typeOfLogin: .github, - verifier: "w3a-auth0-demo", clientId: "hUVVf4SEsZT7syOiL0gLU9hFEtm2gQ6O", - redirectURL: "tdsdk://tdsdk/oauthCallback", jwtParams: Auth0ClientOptions(connection: "github", domain: "web3auth.au.auth0.com", verifierIdField: "sub")) - let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + let sub = SingleLoginParams(typeOfLogin: .email_password, + verifier: "torus-auth0-email-password", clientId: "sqKRBVSdwa4WLkaq419U7Bamlh5vK1H7", + redirectURL: "tdsdk://tdsdk/oauthCallback", jwtParams: Auth0ClientOptions( + connection: "Username-Password-Authentication", + domain: "torus-test.auth0.com", + verifierIdField: "name")) + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") Task { do { let customAuth = try CustomAuth(config: customAuthArgs) @@ -141,21 +133,17 @@ struct ContentView: View { } } }, label: { - Text("JWT Login") + Text("Email Password") }) Button(action: { - let sub = SubVerifierDetails(typeOfLogin: .email_password, - verifier: "torus-auth0-email-password", clientId: "sqKRBVSdwa4WLkaq419U7Bamlh5vK1H7", - redirectURL: "tdsdk://tdsdk/oauthCallback", jwtParams: Auth0ClientOptions( - connection: "Username-Password-Authentication", - domain: "torus-test.auth0.com", - verifierIdField: "name")) - let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + let aggregateLoginParams = AggregateLoginParams(aggregateVerifierType: AggregateVerifierType.single_id_verifier, verifierIdentifier: "aggregate-sapphire", subVerifierDetailsArray: [SingleLoginParams(typeOfLogin: .google, verifier: "w3a-google", clientId: "519228911939-cri01h55lsjbsia1k7ll6qpalrus75ps.apps.googleusercontent.com", redirectURL: "https://scripts.toruswallet.io/redirect.html")]) + + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") Task { do { let customAuth = try CustomAuth(config: customAuthArgs) - let torusLoginResponse = try await customAuth.triggerLogin(args: sub) + let torusLoginResponse = try await customAuth.triggerAggregateLogin(args: aggregateLoginParams) let encoded = try JSONEncoder().encode(torusLoginResponse) print(String(data: encoded, encoding: .utf8)!) } catch { @@ -163,7 +151,26 @@ struct ContentView: View { } } }, label: { - Text("Email Password") + Text("Aggregate Google") + }) + + Button(action: { + let subVerifierDetailsArray = SingleLoginParams(typeOfLogin: .jwt, verifier: "w3a-a0-email-passwordless", clientId: "QiEf8qZ9IoasbZsbHvjKZku4LdnRC1Ct", redirectURL: "https://scripts.toruswallet.io/redirect.html", jwtParams: Auth0ClientOptions(domain:"web3auth.au.auth0.com")) + let aggregateLoginParams = AggregateLoginParams(aggregateVerifierType: AggregateVerifierType.single_id_verifier, verifierIdentifier: "aggregate-sapphire", subVerifierDetailsArray: [subVerifierDetailsArray]) + + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + Task { + do { + let customAuth = try CustomAuth(config: customAuthArgs) + let torusLoginResponse = try await customAuth.triggerAggregateLogin(args: aggregateLoginParams) + let encoded = try JSONEncoder().encode(torusLoginResponse) + print(String(data: encoded, encoding: .utf8)!) + } catch { + print(error) + } + } + }, label: { + Text("Aggregate Email") }) } From 6053f8ee52ebfd0f006b811a1232a1864340d572 Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Mon, 9 Sep 2024 08:33:10 +0200 Subject: [PATCH 09/24] fix: comparison for aggregate single id verifiers --- .../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 2 +- Sources/CustomAuth/CustomAuth.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 05c608e..1f99184 100644 --- a/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -59,7 +59,7 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/torusresearch/torus-utils-swift.git", "state" : { - "revision" : "303dc2cf41db7c10f769855edad0e717ced2d554", + "revision" : "7788752bed699b3d34e78c2c51174f814d02610b", "version" : "9.0.0" } } diff --git a/Sources/CustomAuth/CustomAuth.swift b/Sources/CustomAuth/CustomAuth.swift index 9cf6ea0..f9e22f9 100644 --- a/Sources/CustomAuth/CustomAuth.swift +++ b/Sources/CustomAuth/CustomAuth.swift @@ -91,7 +91,7 @@ public class CustomAuth { if args.subVerifierDetailsArray.isEmpty { throw CASDKError.invalidParameters } - if args.subVerifierDetailsArray.count == 1 && args.aggregateVerifierType == AggregateVerifierType.single_id_verifier { + if args.subVerifierDetailsArray.count != 1 && args.aggregateVerifierType == AggregateVerifierType.single_id_verifier { throw CASDKError.invalidParameters } From 9d995f2afbb0ecbd63f3f32459665d1e8cefb448 Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Mon, 9 Sep 2024 08:38:57 +0200 Subject: [PATCH 10/24] deprecate reddit login handler --- Sources/CustomAuth/Handlers/HandlerFactory.swift | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Sources/CustomAuth/Handlers/HandlerFactory.swift b/Sources/CustomAuth/Handlers/HandlerFactory.swift index 8221679..cfda29c 100644 --- a/Sources/CustomAuth/Handlers/HandlerFactory.swift +++ b/Sources/CustomAuth/Handlers/HandlerFactory.swift @@ -22,15 +22,17 @@ internal class HandlerFactory { return try GoogleLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin, jwtParams: params.jwtParams, customState: params.customState) case .facebook: return try FacebookLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin, jwtParams: params.jwtParams, customState: params.customState) - case .reddit: - if idToken != nil || accessToken != nil { - return try MockLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin, jwtParams: params.jwtParams, customState: params.customState) - } - return try RedditLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin, jwtParams: params.jwtParams, customState: params.customState) case .twitch: return try TwitchLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin, jwtParams: params.jwtParams, customState: params.customState) case .discord: return try DiscordLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin, jwtParams: params.jwtParams, customState: params.customState) + case .reddit: break + /* reddit deprecated implicit flow + if idToken != nil || accessToken != nil { + return try MockLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin, jwtParams: params.jwtParams, customState: params.customState) + } + return try RedditLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin, jwtParams: params.jwtParams, customState: params.customState) + */ case .apple: break case .github: break case .linkedin: break From 6df8e2fa0c91982e5d5386b5ad9a2700802935dc Mon Sep 17 00:00:00 2001 From: Mohammad Shahbaz Alam Date: Mon, 9 Sep 2024 12:15:21 +0530 Subject: [PATCH 11/24] nits --- .../xcshareddata/swiftpm/Package.resolved | 2 +- CustomAuthDemo/CustomAuthDemo/ContentView.swift | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 1f99184..05c608e 100644 --- a/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -59,7 +59,7 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/torusresearch/torus-utils-swift.git", "state" : { - "revision" : "7788752bed699b3d34e78c2c51174f814d02610b", + "revision" : "303dc2cf41db7c10f769855edad0e717ced2d554", "version" : "9.0.0" } } diff --git a/CustomAuthDemo/CustomAuthDemo/ContentView.swift b/CustomAuthDemo/CustomAuthDemo/ContentView.swift index dbde22e..c50b0d0 100644 --- a/CustomAuthDemo/CustomAuthDemo/ContentView.swift +++ b/CustomAuthDemo/CustomAuthDemo/ContentView.swift @@ -136,6 +136,11 @@ struct ContentView: View { Text("Email Password") }) + Label( + title: { Text("Aggregate Verifiers") }, + icon: { Image(systemName: "circle") } + ) + Button(action: { let aggregateLoginParams = AggregateLoginParams(aggregateVerifierType: AggregateVerifierType.single_id_verifier, verifierIdentifier: "aggregate-sapphire", subVerifierDetailsArray: [SingleLoginParams(typeOfLogin: .google, verifier: "w3a-google", clientId: "519228911939-cri01h55lsjbsia1k7ll6qpalrus75ps.apps.googleusercontent.com", redirectURL: "https://scripts.toruswallet.io/redirect.html")]) @@ -151,11 +156,11 @@ struct ContentView: View { } } }, label: { - Text("Aggregate Google") + Text("Aggregate Gmail") }) Button(action: { - let subVerifierDetailsArray = SingleLoginParams(typeOfLogin: .jwt, verifier: "w3a-a0-email-passwordless", clientId: "QiEf8qZ9IoasbZsbHvjKZku4LdnRC1Ct", redirectURL: "https://scripts.toruswallet.io/redirect.html", jwtParams: Auth0ClientOptions(domain:"web3auth.au.auth0.com")) + let subVerifierDetailsArray = SingleLoginParams(typeOfLogin: .email_passwordless, verifier: "w3a-a0-email-passwordless", clientId: "QiEf8qZ9IoasbZsbHvjKZku4LdnRC1Ct", redirectURL: "https://scripts.toruswallet.io/redirect.html", jwtParams: Auth0ClientOptions(domain: "web3auth.au.auth0.com", verifierIdField: "email")) let aggregateLoginParams = AggregateLoginParams(aggregateVerifierType: AggregateVerifierType.single_id_verifier, verifierIdentifier: "aggregate-sapphire", subVerifierDetailsArray: [subVerifierDetailsArray]) let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") @@ -170,7 +175,7 @@ struct ContentView: View { } } }, label: { - Text("Aggregate Email") + Text("Aggregate Email Passwordless") }) } From 32a85c7fce700805c28137e9d17a0d5e2bd1b4c6 Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Mon, 9 Sep 2024 09:21:23 +0200 Subject: [PATCH 12/24] update --- .../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 2 +- CustomAuthDemo/CustomAuthDemo/ContentView.swift | 2 +- .../CustomAuth/Common/LoginParams/Auth0ClientOptions.swift | 2 ++ Sources/CustomAuth/CustomAuth.swift | 4 ++-- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 05c608e..1f99184 100644 --- a/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -59,7 +59,7 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/torusresearch/torus-utils-swift.git", "state" : { - "revision" : "303dc2cf41db7c10f769855edad0e717ced2d554", + "revision" : "7788752bed699b3d34e78c2c51174f814d02610b", "version" : "9.0.0" } } diff --git a/CustomAuthDemo/CustomAuthDemo/ContentView.swift b/CustomAuthDemo/CustomAuthDemo/ContentView.swift index c50b0d0..77142b6 100644 --- a/CustomAuthDemo/CustomAuthDemo/ContentView.swift +++ b/CustomAuthDemo/CustomAuthDemo/ContentView.swift @@ -160,7 +160,7 @@ struct ContentView: View { }) Button(action: { - let subVerifierDetailsArray = SingleLoginParams(typeOfLogin: .email_passwordless, verifier: "w3a-a0-email-passwordless", clientId: "QiEf8qZ9IoasbZsbHvjKZku4LdnRC1Ct", redirectURL: "https://scripts.toruswallet.io/redirect.html", jwtParams: Auth0ClientOptions(domain: "web3auth.au.auth0.com", verifierIdField: "email")) + let subVerifierDetailsArray = SingleLoginParams(typeOfLogin: .email_passwordless, verifier: "w3a-a0-email-passwordless", clientId: "QiEf8qZ9IoasbZsbHvjKZku4LdnRC1Ct", redirectURL: "https://scripts.toruswallet.io/redirect.html", jwtParams: OAuthClientOptions(domain: "web3auth.au.auth0.com", verifierIdField: "email")) let aggregateLoginParams = AggregateLoginParams(aggregateVerifierType: AggregateVerifierType.single_id_verifier, verifierIdentifier: "aggregate-sapphire", subVerifierDetailsArray: [subVerifierDetailsArray]) let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") diff --git a/Sources/CustomAuth/Common/LoginParams/Auth0ClientOptions.swift b/Sources/CustomAuth/Common/LoginParams/Auth0ClientOptions.swift index 4821b13..f9e7899 100644 --- a/Sources/CustomAuth/Common/LoginParams/Auth0ClientOptions.swift +++ b/Sources/CustomAuth/Common/LoginParams/Auth0ClientOptions.swift @@ -59,3 +59,5 @@ public class Auth0ClientOptions: BaseLoginOptions { try container.encodeIfPresent(self.login_hint, forKey: .login_hint) } } + +public typealias OAuthClientOptions = Auth0ClientOptions diff --git a/Sources/CustomAuth/CustomAuth.swift b/Sources/CustomAuth/CustomAuth.swift index f9e22f9..ae8b2ef 100644 --- a/Sources/CustomAuth/CustomAuth.swift +++ b/Sources/CustomAuth/CustomAuth.swift @@ -127,7 +127,7 @@ public class CustomAuth { let loginParams = loginParamsArray[i] let userInfo = userInfoArray[i] - aggregateVerifierParams.append(VerifyParams(verifier_id: userInfo.verifierId, idtoken: loginParams.idToken!)) + aggregateVerifierParams.append(VerifyParams(verifier_id: userInfo.verifierId, idtoken: loginParams.idToken ?? loginParams.accessToken!)) aggregateIdTokenSeeds.append(loginParams.idToken ?? loginParams.accessToken!) subVerifierIds.append(userInfo.verifier) aggregateVerifierId = userInfo.verifierId @@ -137,7 +137,7 @@ public class CustomAuth { let aggregateIdToken = try keccak256(data: joined) let aggregateParams: VerifierParams = VerifierParams(verifier_id: aggregateVerifierId, extended_verifier_id: nil, sub_verifier_ids: subVerifierIds, verify_params: aggregateVerifierParams) - let aggregateTorusKey = try await getTorusKey(verifier: aggregateVerifierId, verifierParams: aggregateParams, idToken: String(data: aggregateIdToken, encoding: .utf8)!) + let aggregateTorusKey = try await getTorusKey(verifier: aggregateVerifierId, verifierParams: aggregateParams, idToken: aggregateIdToken.hexString) var aggregateVerifierResponses: [TorusAggregateVerifierResponse] = [] for i in 0 ..< userInfoArray.count { From 39a47bb3cd87be24f84f327edbc5375aa86e1268 Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Mon, 9 Sep 2024 09:22:42 +0200 Subject: [PATCH 13/24] default for redirect url in subverifier details --- Sources/CustomAuth/Common/LoginParams/SubVerifierDetails.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/CustomAuth/Common/LoginParams/SubVerifierDetails.swift b/Sources/CustomAuth/Common/LoginParams/SubVerifierDetails.swift index d3c2aae..fc9acb6 100644 --- a/Sources/CustomAuth/Common/LoginParams/SubVerifierDetails.swift +++ b/Sources/CustomAuth/Common/LoginParams/SubVerifierDetails.swift @@ -10,7 +10,7 @@ public class SubVerifierDetails: Codable { public let queryParams: TorusGenericContainer? public let customState: TorusGenericContainer? - public init(typeOfLogin: LoginType, verifier: String, clientId: String, redirectURL: String, jwtParams: Auth0ClientOptions? = nil, hash: String? = nil, queryParams: TorusGenericContainer? = nil, customState: TorusGenericContainer? = nil) { + public init(typeOfLogin: LoginType, verifier: String, clientId: String, redirectURL: String = "https://scripts.toruswallet.io/redirect.html", jwtParams: Auth0ClientOptions? = nil, hash: String? = nil, queryParams: TorusGenericContainer? = nil, customState: TorusGenericContainer? = nil) { self.typeOfLogin = typeOfLogin self.verifier = verifier self.clientId = clientId From 984c0fdf9509b3ccaecf876765bab26862c1f04c Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Mon, 9 Sep 2024 09:56:51 +0200 Subject: [PATCH 14/24] fix: aggregate login --- Sources/CustomAuth/CustomAuth.swift | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Sources/CustomAuth/CustomAuth.swift b/Sources/CustomAuth/CustomAuth.swift index ae8b2ef..ee255fc 100644 --- a/Sources/CustomAuth/CustomAuth.swift +++ b/Sources/CustomAuth/CustomAuth.swift @@ -71,7 +71,7 @@ public class CustomAuth { let verifyParams: VerifierParams = VerifierParams(verifier_id: userInfo.verifierId) - let torusKey = try await getTorusKey(verifier: userInfo.verifier, verifierParams: verifyParams, idToken: loginParams.idToken ?? loginParams.accessToken ?? "") + let torusKey = try await getTorusKey(verifier: userInfo.verifier, verifier_id: userInfo.verifierId, verifierParams: verifyParams, idToken: loginParams.idToken ?? loginParams.accessToken ?? "") 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, accessToken: loginParams.accessToken, idToken: loginParams.idToken, extraParams: loginParams.extraParams, extraParamsPassed: loginParams.extraParamsPassed, state: loginParams.state) @@ -134,10 +134,10 @@ public class CustomAuth { } aggregateIdTokenSeeds.sort() let joined = aggregateIdTokenSeeds.joined(separator: "\u{29}").data(using: .utf8)! - let aggregateIdToken = try keccak256(data: joined) + let aggregateIdToken = try keccak256(data: joined).hexString let aggregateParams: VerifierParams = VerifierParams(verifier_id: aggregateVerifierId, extended_verifier_id: nil, sub_verifier_ids: subVerifierIds, verify_params: aggregateVerifierParams) - let aggregateTorusKey = try await getTorusKey(verifier: aggregateVerifierId, verifierParams: aggregateParams, idToken: aggregateIdToken.hexString) + let aggregateTorusKey = try await getTorusKey(verifier: args.verifierIdentifier, verifier_id: aggregateVerifierId, verifierParams: aggregateParams, idToken: aggregateIdToken) var aggregateVerifierResponses: [TorusAggregateVerifierResponse] = [] for i in 0 ..< userInfoArray.count { @@ -182,7 +182,7 @@ public class CustomAuth { let verifyParams: VerifierParams = VerifierParams(verifier_id: userInfo.verifierId) - let torusKey = try await getTorusKey(verifier: userInfo.verifier, verifierParams: verifyParams, idToken: loginParams.idToken!) + let torusKey = try await getTorusKey(verifier: userInfo.verifier, verifier_id: userInfo.verifierId, verifierParams: verifyParams, idToken: loginParams.idToken!) 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, accessToken: loginParams.accessToken, idToken: loginParams.idToken, extraParams: loginParams.extraParams, extraParamsPassed: loginParams.extraParamsPassed, state: loginParams.state) @@ -203,7 +203,7 @@ public class CustomAuth { let aggregateIdToken = try keccak256(data: joined) let aggregateParams: VerifierParams = VerifierParams(verifier_id: aggregateVerifierId, extended_verifier_id: nil, sub_verifier_ids: subVerifierIds, verify_params: aggregateVerifierParams) - let aggregateTorusKey = try await getTorusKey(verifier: args.aggregateLoginParams.verifierIdentifier, verifierParams: aggregateParams, idToken: String(data: aggregateIdToken, encoding: .utf8)!) + let aggregateTorusKey = try await getTorusKey(verifier: args.aggregateLoginParams.verifierIdentifier, verifier_id: aggregateVerifierId, verifierParams: aggregateParams, idToken: String(data: aggregateIdToken, encoding: .utf8)!) let aggregateResponse = TorusAggregateVerifierResponse(userInfo: returnedInfo, loginResponse: loginParams) @@ -222,8 +222,8 @@ public class CustomAuth { /// - Returns: `TorusKey` /// /// - Throws: `CASDKError`, `TorusUtilError`, `FetchNodeError` - func getTorusKey(verifier: String, verifierParams: VerifierParams, idToken: String, extraParams: TorusUtilsExtraParams? = nil) async throws -> TorusKey { - let nodeDetails = try await nodeDetailManager.getNodeDetails(verifier: verifier, verifierID: verifierParams.verifier_id) + func getTorusKey(verifier: String, verifier_id: String, verifierParams: VerifierParams, idToken: String, extraParams: TorusUtilsExtraParams? = nil) async throws -> TorusKey { + let nodeDetails = try await nodeDetailManager.getNodeDetails(verifier: verifier, verifierID: verifier_id) return try await torus.retrieveShares(endpoints: nodeDetails.getTorusNodeEndpoints(), verifier: verifier, verifierParams: verifierParams, idToken: idToken) } From 5aca4a48002c158d9f5a19027497ae538a639df3 Mon Sep 17 00:00:00 2001 From: Mohammad Shahbaz Alam Date: Mon, 9 Sep 2024 13:49:23 +0530 Subject: [PATCH 15/24] nits for configs --- .../xcshareddata/swiftpm/Package.resolved | 2 +- .../CustomAuthDemo/ContentView.swift | 22 +++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 1f99184..05c608e 100644 --- a/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -59,7 +59,7 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/torusresearch/torus-utils-swift.git", "state" : { - "revision" : "7788752bed699b3d34e78c2c51174f814d02610b", + "revision" : "303dc2cf41db7c10f769855edad0e717ced2d554", "version" : "9.0.0" } } diff --git a/CustomAuthDemo/CustomAuthDemo/ContentView.swift b/CustomAuthDemo/CustomAuthDemo/ContentView.swift index 77142b6..bc5c1a4 100644 --- a/CustomAuthDemo/CustomAuthDemo/ContentView.swift +++ b/CustomAuthDemo/CustomAuthDemo/ContentView.swift @@ -8,7 +8,7 @@ struct ContentView: View { Button(action: { Task { do { - let sub = SingleLoginParams(typeOfLogin: .google, verifier: "w3a-google-demo", clientId: "519228911939-cri01h55lsjbsia1k7ll6qpalrus75ps.apps.googleusercontent.com", redirectURL: "https://scripts.toruswallet.io/redirect.html") + let sub = SingleLoginParams(typeOfLogin: .google, verifier: "w3a-google-demo", clientId: "519228911939-cri01h55lsjbsia1k7ll6qpalrus75ps.apps.googleusercontent.com") let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") let customAuth = try CustomAuth(config: customAuthArgs) @@ -27,7 +27,7 @@ struct ContentView: View { Button(action: { Task { do { - let sub = SingleLoginParams(typeOfLogin: .discord, verifier: "w3a-discord-demo", clientId: "1151006428610433095", redirectURL: "https://scripts.toruswallet.io/redirect.html") + let sub = SingleLoginParams(typeOfLogin: .discord, verifier: "w3a-discord-demo", clientId: "1151006428610433095") let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") @@ -47,7 +47,7 @@ struct ContentView: View { Button(action: { Task { do { - let sub = SingleLoginParams(typeOfLogin: .facebook, verifier: "w3a-facebook-demo", clientId: "342380202252650", redirectURL: "https://scripts.toruswallet.io/redirect.html") + let sub = SingleLoginParams(typeOfLogin: .facebook, verifier: "w3a-facebook-demo", clientId: "342380202252650") let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") @@ -64,7 +64,7 @@ struct ContentView: View { }) Button(action: { - let sub = SingleLoginParams(typeOfLogin: .twitch, verifier: "w3a-twitch-demo", clientId: "3k7e70gowvxjaxg71hjnc8h8ih3bpf", redirectURL: "https://scripts.toruswallet.io/redirect.html") + let sub = SingleLoginParams(typeOfLogin: .twitch, verifier: "w3a-twitch-demo", clientId: "3k7e70gowvxjaxg71hjnc8h8ih3bpf") let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") Task { do { @@ -81,7 +81,7 @@ struct ContentView: View { }) Button(action: { - let sub = SingleLoginParams(typeOfLogin: .apple, verifier: "w3a-auth0-demo", clientId: "hUVVf4SEsZT7syOiL0gLU9hFEtm2gQ6O", redirectURL: "https://scripts.toruswallet.io/redirect.html", jwtParams: Auth0ClientOptions(connection: "apple", domain: "web3auth.au.auth0.com")) + let sub = SingleLoginParams(typeOfLogin: .apple, verifier: "w3a-auth0-demo", clientId: "hUVVf4SEsZT7syOiL0gLU9hFEtm2gQ6O", jwtParams: Auth0ClientOptions(connection: "apple", domain: "web3auth.au.auth0.com")) let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") Task { do { @@ -98,7 +98,7 @@ struct ContentView: View { }) Button(action: { - let sub = SingleLoginParams(typeOfLogin: .github, verifier: "w3a-auth0-demo", clientId: "hUVVf4SEsZT7syOiL0gLU9hFEtm2gQ6O", redirectURL: "https://scripts.toruswallet.io/redirect.html", jwtParams: Auth0ClientOptions(connection: "github", domain: "web3auth.au.auth0.com", verifierIdField: "sub")) + let sub = SingleLoginParams(typeOfLogin: .github, verifier: "w3a-auth0-demo", clientId: "hUVVf4SEsZT7syOiL0gLU9hFEtm2gQ6O", jwtParams: Auth0ClientOptions(connection: "github", domain: "web3auth.au.auth0.com", verifierIdField: "sub")) let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") Task { do { @@ -111,13 +111,13 @@ struct ContentView: View { } } }, label: { - Text("JWT Login") + Text("GitHub Login") }) Button(action: { let sub = SingleLoginParams(typeOfLogin: .email_password, verifier: "torus-auth0-email-password", clientId: "sqKRBVSdwa4WLkaq419U7Bamlh5vK1H7", - redirectURL: "tdsdk://tdsdk/oauthCallback", jwtParams: Auth0ClientOptions( + jwtParams: Auth0ClientOptions( connection: "Username-Password-Authentication", domain: "torus-test.auth0.com", verifierIdField: "name")) @@ -142,7 +142,7 @@ struct ContentView: View { ) Button(action: { - let aggregateLoginParams = AggregateLoginParams(aggregateVerifierType: AggregateVerifierType.single_id_verifier, verifierIdentifier: "aggregate-sapphire", subVerifierDetailsArray: [SingleLoginParams(typeOfLogin: .google, verifier: "w3a-google", clientId: "519228911939-cri01h55lsjbsia1k7ll6qpalrus75ps.apps.googleusercontent.com", redirectURL: "https://scripts.toruswallet.io/redirect.html")]) + let aggregateLoginParams = AggregateLoginParams(aggregateVerifierType: AggregateVerifierType.single_id_verifier, verifierIdentifier: "aggregate-sapphire", subVerifierDetailsArray: [SingleLoginParams(typeOfLogin: .google, verifier: "w3a-google", clientId: "519228911939-cri01h55lsjbsia1k7ll6qpalrus75ps.apps.googleusercontent.com")]) let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") Task { @@ -160,7 +160,7 @@ struct ContentView: View { }) Button(action: { - let subVerifierDetailsArray = SingleLoginParams(typeOfLogin: .email_passwordless, verifier: "w3a-a0-email-passwordless", clientId: "QiEf8qZ9IoasbZsbHvjKZku4LdnRC1Ct", redirectURL: "https://scripts.toruswallet.io/redirect.html", jwtParams: OAuthClientOptions(domain: "web3auth.au.auth0.com", verifierIdField: "email")) + let subVerifierDetailsArray = SingleLoginParams(typeOfLogin: .github, verifier: "w3a-a0-github", clientId: "hiLqaop0amgzCC0AXo4w0rrG9abuJTdu", jwtParams: OAuthClientOptions(domain: "web3auth.au.auth0.com", verifierIdField: "email")) let aggregateLoginParams = AggregateLoginParams(aggregateVerifierType: AggregateVerifierType.single_id_verifier, verifierIdentifier: "aggregate-sapphire", subVerifierDetailsArray: [subVerifierDetailsArray]) let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") @@ -175,7 +175,7 @@ struct ContentView: View { } } }, label: { - Text("Aggregate Email Passwordless") + Text("Aggregate GitHub") }) } From b6a314fcd9dbe75bcd8ec27240a4dc4efc37817f Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Mon, 9 Sep 2024 10:22:46 +0200 Subject: [PATCH 16/24] convenience init for domain in auth0clientoptions --- .../Common/LoginParams/Auth0ClientOptions.swift | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Sources/CustomAuth/Common/LoginParams/Auth0ClientOptions.swift b/Sources/CustomAuth/Common/LoginParams/Auth0ClientOptions.swift index f9e7899..1b9897b 100644 --- a/Sources/CustomAuth/Common/LoginParams/Auth0ClientOptions.swift +++ b/Sources/CustomAuth/Common/LoginParams/Auth0ClientOptions.swift @@ -26,7 +26,16 @@ public class Auth0ClientOptions: BaseLoginOptions { } public init(display: String? = nil, prompt: String? = nil, max_age: Int? = nil, ui_locales: String? = nil, id_token_hint: String? = nil, arc_values: String? = nil, scope: String? = nil, audience: String? = nil, connection: String? = nil, domain: String? = nil, client_id: String? = nil, redirect_url: String? = nil, leeway: Int? = nil, verifierIdField: String? = nil, isVerifierIdCaseSensitive: Bool = false, id_token: String? = nil, access_token: String? = nil, user_info_route: String? = nil, login_hint: String? = nil) { - self.domain = domain + + // This is for convenience in case a full url gets passed in + // https:// is added back in later when it is constructed from + // URLComponents() + var domainHost = domain + if domain != nil && domain!.starts(with: "https://") { + domainHost = URL(string: domain!)?.host + } + + self.domain = domainHost self.redirect_url = redirect_url self.leeway = leeway self.verifierIdField = verifierIdField From 045d57c57c1bfcc5fa951dd510e6f840c5af8d88 Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Mon, 9 Sep 2024 10:23:24 +0200 Subject: [PATCH 17/24] Update Package.resolved --- .../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 05c608e..1f99184 100644 --- a/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -59,7 +59,7 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/torusresearch/torus-utils-swift.git", "state" : { - "revision" : "303dc2cf41db7c10f769855edad0e717ced2d554", + "revision" : "7788752bed699b3d34e78c2c51174f814d02610b", "version" : "9.0.0" } } From 735257ebc65fe7b01d324436ce4a07850ff27b73 Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Tue, 10 Sep 2024 05:04:27 +0200 Subject: [PATCH 18/24] refactor: remove hybridaggregatelogin and reddithandler --- .../xcshareddata/swiftpm/Package.resolved | 28 +++------ .../HybridAggregateLoginParams.swift | 11 ---- .../TorusHybridAggregateLoginResponse.swift | 12 ---- Sources/CustomAuth/CustomAuth.swift | 63 ------------------- .../CustomAuth/Handlers/HandlerFactory.swift | 6 -- .../Handlers/RedditLoginHandler.swift | 58 ----------------- 6 files changed, 10 insertions(+), 168 deletions(-) delete mode 100644 Sources/CustomAuth/Common/LoginParams/HybridAggregateLoginParams.swift delete mode 100644 Sources/CustomAuth/Common/LoginResponses/TorusHybridAggregateLoginResponse.swift delete mode 100644 Sources/CustomAuth/Handlers/RedditLoginHandler.swift diff --git a/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 1f99184..ad8b511 100644 --- a/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,4 +1,5 @@ { + "originHash" : "18b632e2194394e0c1a608ed933754bf428e89a5fb32ba332befd79edc99e5f5", "pins" : [ { "identity" : "bigint", @@ -19,21 +20,21 @@ } }, { - "identity" : "fetch-node-details-swift", + "identity" : "customauth-swift-sdk", "kind" : "remoteSourceControl", - "location" : "https://github.com/torusresearch/fetch-node-details-swift", + "location" : "https://github.com/torusresearch/customauth-swift-sdk/", "state" : { - "revision" : "4bd96c33ba8d02d9e27190c5c7cedf09cfdfd656", - "version" : "6.0.3" + "branch" : "features_update", + "revision" : "045d57c57c1bfcc5fa951dd510e6f840c5af8d88" } }, { - "identity" : "jwt-kit", + "identity" : "fetch-node-details-swift", "kind" : "remoteSourceControl", - "location" : "https://github.com/vapor/jwt-kit.git", + "location" : "https://github.com/torusresearch/fetch-node-details-swift", "state" : { - "revision" : "c2595b9ad7f512d7f334830b4df1fed6e917946a", - "version" : "4.13.4" + "revision" : "4bd96c33ba8d02d9e27190c5c7cedf09cfdfd656", + "version" : "6.0.3" } }, { @@ -45,15 +46,6 @@ "version" : "3.1.0" } }, - { - "identity" : "swift-crypto", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-crypto.git", - "state" : { - "revision" : "9f95b4d033a4edd3814b48608db3f2ca90c7218b", - "version" : "3.7.0" - } - }, { "identity" : "torus-utils-swift", "kind" : "remoteSourceControl", @@ -64,5 +56,5 @@ } } ], - "version" : 2 + "version" : 3 } diff --git a/Sources/CustomAuth/Common/LoginParams/HybridAggregateLoginParams.swift b/Sources/CustomAuth/Common/LoginParams/HybridAggregateLoginParams.swift deleted file mode 100644 index 5fe21fb..0000000 --- a/Sources/CustomAuth/Common/LoginParams/HybridAggregateLoginParams.swift +++ /dev/null @@ -1,11 +0,0 @@ -import Foundation - -public class HybridAggregateLoginParams: Codable { - public let singleLogin: SingleLoginParams - public let aggregateLoginParams: AggregateLoginParams - - public init(singleLogin: SingleLoginParams, aggregateLoginParams: AggregateLoginParams) { - self.singleLogin = singleLogin - self.aggregateLoginParams = aggregateLoginParams - } -} diff --git a/Sources/CustomAuth/Common/LoginResponses/TorusHybridAggregateLoginResponse.swift b/Sources/CustomAuth/Common/LoginResponses/TorusHybridAggregateLoginResponse.swift deleted file mode 100644 index 80eb821..0000000 --- a/Sources/CustomAuth/Common/LoginResponses/TorusHybridAggregateLoginResponse.swift +++ /dev/null @@ -1,12 +0,0 @@ -import Foundation -import TorusUtils - -public class TorusHybridAggregateLoginResponse: Codable { - public let singleLogin: TorusAggregateLoginResponse - public let aggregateLogins: [TorusKey] - - public init(singleLogin: TorusAggregateLoginResponse, aggregateLogins: [TorusKey]) { - self.singleLogin = singleLogin - self.aggregateLogins = aggregateLogins - } -} diff --git a/Sources/CustomAuth/CustomAuth.swift b/Sources/CustomAuth/CustomAuth.swift index ee255fc..2447993 100644 --- a/Sources/CustomAuth/CustomAuth.swift +++ b/Sources/CustomAuth/CustomAuth.swift @@ -149,69 +149,6 @@ public class CustomAuth { return TorusAggregateLoginResponse(torusAggregateVerifierResponse: aggregateVerifierResponses, torusKey: aggregateTorusKey) } - /// Initiates a login using a hybrid verifier - /// - /// - Parameters: - /// - params: `HybridAggregateLoginParams` - /// - /// - Returns: `TorusHybridAggregateLoginResponse` - /// - /// - Throws: `CASDKError`, `TorusUtilError` - public func triggerHybridAggregateLogin(args: HybridAggregateLoginParams) async throws -> TorusHybridAggregateLoginResponse { - if args.aggregateLoginParams.subVerifierDetailsArray.isEmpty { - throw CASDKError.invalidParameters - } - if args.aggregateLoginParams.subVerifierDetailsArray.count == 1 && args.aggregateLoginParams.aggregateVerifierType == AggregateVerifierType.single_id_verifier { - throw CASDKError.invalidParameters - } - - let loginHandler = try HandlerFactory.createHandler(params: CreateHandlerParams(typeOfLogin: args.singleLogin.typeOfLogin, verifier: args.singleLogin.verifier, clientId: args.singleLogin.clientId, urlScheme: config.urlScheme, redirectURL: args.singleLogin.redirectURL, jwtParams: args.singleLogin.jwtParams, customState: args.singleLogin.customState)) - - var loginParams: LoginWindowResponse - if args.singleLogin.hash != nil && args.singleLogin.queryParams != nil { - let (error, hashParams, instanceParams) = try handleRedirectParameters(hash: args.singleLogin.hash!, queryParameters: args.singleLogin.queryParams!) - if !error.isEmpty { - throw CASDKError.redirectParamsError(msg: error) - } - 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) - } else { - loginParams = try await loginHandler.handleLoginWindow(popupFeatures: config.popupFeatures) - } - - let userInfo = try await loginHandler.getUserInfo(params: loginParams, storageServerUrl: nil) - - let verifyParams: VerifierParams = VerifierParams(verifier_id: userInfo.verifierId) - - let torusKey = try await getTorusKey(verifier: userInfo.verifier, verifier_id: userInfo.verifierId, verifierParams: verifyParams, idToken: loginParams.idToken!) - - 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, - accessToken: loginParams.accessToken, idToken: loginParams.idToken, extraParams: loginParams.extraParams, extraParamsPassed: loginParams.extraParamsPassed, state: loginParams.state) - - var subVerifierIds: [String] = [] - var aggregateVerifierParams: [VerifyParams] = [] - var aggregateIdTokenSeeds: [String] = [] - var aggregateVerifierId: String = "" - for i in 0 ..< args.aggregateLoginParams.subVerifierDetailsArray.count { - let sub = args.aggregateLoginParams.subVerifierDetailsArray[i] - aggregateVerifierParams.append(VerifyParams(verifier_id: userInfo.verifierId, idtoken: loginParams.idToken!)) - aggregateIdTokenSeeds.append(loginParams.idToken ?? loginParams.accessToken!) - subVerifierIds.append(sub.verifier) - aggregateVerifierId = userInfo.verifierId - } - aggregateIdTokenSeeds.sort() - let joined = aggregateIdTokenSeeds.joined(separator: "\u{29}").data(using: .utf8)! - let aggregateIdToken = try keccak256(data: joined) - let aggregateParams: VerifierParams = VerifierParams(verifier_id: aggregateVerifierId, extended_verifier_id: nil, sub_verifier_ids: subVerifierIds, verify_params: aggregateVerifierParams) - - let aggregateTorusKey = try await getTorusKey(verifier: args.aggregateLoginParams.verifierIdentifier, verifier_id: aggregateVerifierId, verifierParams: aggregateParams, idToken: String(data: aggregateIdToken, encoding: .utf8)!) - - let aggregateResponse = TorusAggregateVerifierResponse(userInfo: returnedInfo, loginResponse: loginParams) - - let aggregateLogin = TorusAggregateLoginResponse(torusAggregateVerifierResponse: [aggregateResponse], torusKey: torusKey) - - return TorusHybridAggregateLoginResponse(singleLogin: aggregateLogin, aggregateLogins: [aggregateTorusKey]) - } - /// Retrieves the key details /// /// - Parameters: diff --git a/Sources/CustomAuth/Handlers/HandlerFactory.swift b/Sources/CustomAuth/Handlers/HandlerFactory.swift index cfda29c..8bcd9bb 100644 --- a/Sources/CustomAuth/Handlers/HandlerFactory.swift +++ b/Sources/CustomAuth/Handlers/HandlerFactory.swift @@ -27,12 +27,6 @@ internal class HandlerFactory { case .discord: return try DiscordLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin, jwtParams: params.jwtParams, customState: params.customState) case .reddit: break - /* reddit deprecated implicit flow - if idToken != nil || accessToken != nil { - return try MockLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin, jwtParams: params.jwtParams, customState: params.customState) - } - return try RedditLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin, jwtParams: params.jwtParams, customState: params.customState) - */ case .apple: break case .github: break case .linkedin: break diff --git a/Sources/CustomAuth/Handlers/RedditLoginHandler.swift b/Sources/CustomAuth/Handlers/RedditLoginHandler.swift deleted file mode 100644 index 85ab16e..0000000 --- a/Sources/CustomAuth/Handlers/RedditLoginHandler.swift +++ /dev/null @@ -1,58 +0,0 @@ -import Foundation - -internal class RedditInfo: Codable { - public var name: String - public var icon_image: String? -} - -internal class RedditLoginHandler: AbstractLoginHandler { - private var response_type: String = "token" - private var scope: String = "identity" - - override public init(clientId: String, verifier: String, urlScheme: String, redirectURL: String, typeOfLogin: LoginType, jwtParams: Auth0ClientOptions? = nil, customState: TorusGenericContainer? = nil) throws { - try super.init(clientId: clientId, verifier: verifier, urlScheme: urlScheme, redirectURL: redirectURL, typeOfLogin: typeOfLogin, jwtParams: jwtParams, customState: customState) - try setFinalUrl() - } - - override public func setFinalUrl() throws { - var urlComponents = URLComponents() - - var params: [String: String] = [:] - - if jwtParams != nil { - params = try (JSONSerialization.jsonObject(with: try JSONEncoder().encode(jwtParams), options: []) as! [String: String]) - } - - params.merge([ - "state": try state(), - "response_type": response_type, - "client_id": clientId, - "redirect_uri": redirectURL, - "scope": scope, - ], uniquingKeysWith: { _, new in new }) - urlComponents.scheme = "https" - urlComponents.host = "www.reddit.com" - urlComponents.path = "/api/v1/authorize" - urlComponents.setQueryItems(with: params) - - finalUrl = urlComponents - } - - override public func getUserInfo(params: LoginWindowResponse, storageServerUrl: String?) async throws -> TorusVerifierResponse { - guard let accessToken = params.accessToken else { - throw CASDKError.accessTokenNotProvided - } - - var urlRequest = makeUrlRequest(url: "https://oauth.reddit.com/api/v1/me", method: "GET") - urlRequest.addValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization") - - let (data, _) = try await URLSession.shared.data(for: urlRequest) - - let result = try JSONDecoder().decode(RedditInfo.self, from: data) - - var profileImage = result.icon_image ?? "" - profileImage = profileImage.split(separator: "?").count > 0 ? String(profileImage.split(separator: "?")[0]) : profileImage - - return TorusVerifierResponse(email: "", name: result.name, profileImage: profileImage, verifier: verifier, verifierId: result.name.lowercased(), typeOfLogin: typeOfLogin) - } -} From 7aa5c2201be1b7383f32474f6ee7564df36eccfd Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Tue, 10 Sep 2024 05:06:58 +0200 Subject: [PATCH 19/24] catch up to v20 changes --- CustomAuth.podspec | 2 +- .../xcshareddata/swiftpm/Package.resolved | 32 ++- .../CustomAuthDemo/ContentView.swift | 153 ++++++++----- Package.resolved | 4 +- Package.swift | 2 +- .../LoginParams/Auth0ClientOptions.swift | 10 +- .../Common/LoginParams/EmailFlowType.swift | 6 + Sources/CustomAuth/Common/State.swift | 5 +- Sources/CustomAuth/CustomAuth.swift | 4 +- .../Handlers/DiscordLoginHandler.swift | 14 +- .../Handlers/FacebookLoginHandler.swift | 14 +- .../Handlers/GoogleLoginHandler.swift | 14 +- .../CustomAuth/Handlers/HandlerFactory.swift | 22 +- .../CustomAuth/Handlers/JWTLoginHandler.swift | 30 +-- .../Handlers/MockLoginHandler.swift | 28 +-- .../Handlers/PasswordlessLoginHandler.swift | 85 ------- .../Protocol/AbstractLoginHandler.swift | 31 +-- .../Protocol/CreateHandlerParams.swift | 9 +- .../Handlers/Protocol/ILoginHandler.swift | 2 +- .../Handlers/TwitchLoginHandler.swift | 16 +- .../Web3AuthPasswordlessLoginHandler.swift | 68 ++++++ cocoapods/Podfile.lock | 2 +- cocoapods/cptest/LoginView.swift | 32 +-- cocoapods/cptest/ViewModel.swift | 212 +++++------------- 24 files changed, 352 insertions(+), 445 deletions(-) create mode 100644 Sources/CustomAuth/Common/LoginParams/EmailFlowType.swift delete mode 100644 Sources/CustomAuth/Handlers/PasswordlessLoginHandler.swift create mode 100644 Sources/CustomAuth/Handlers/Web3AuthPasswordlessLoginHandler.swift diff --git a/CustomAuth.podspec b/CustomAuth.podspec index 6a4c024..821ce54 100644 --- a/CustomAuth.podspec +++ b/CustomAuth.podspec @@ -10,6 +10,6 @@ Pod::Spec.new do |spec| spec.module_name = "CustomAuth" spec.source = { :git => "https://github.com/torusresearch/customauth-swift-sdk.git", :tag => spec.version } spec.source_files = "Sources/CustomAuth/*.{swift}","Sources/CustomAuth/**/*.{swift}" - spec.dependency 'Torus-utils', '~> 9.0.0' + spec.dependency 'Torus-utils', '~> 9.0.1' spec.dependency 'JWTDecode', '~> 3.1.0' end diff --git a/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index ad8b511..7c37236 100644 --- a/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,4 @@ { - "originHash" : "18b632e2194394e0c1a608ed933754bf428e89a5fb32ba332befd79edc99e5f5", "pins" : [ { "identity" : "bigint", @@ -20,21 +19,21 @@ } }, { - "identity" : "customauth-swift-sdk", + "identity" : "fetch-node-details-swift", "kind" : "remoteSourceControl", - "location" : "https://github.com/torusresearch/customauth-swift-sdk/", + "location" : "https://github.com/torusresearch/fetch-node-details-swift", "state" : { - "branch" : "features_update", - "revision" : "045d57c57c1bfcc5fa951dd510e6f840c5af8d88" + "revision" : "4bd96c33ba8d02d9e27190c5c7cedf09cfdfd656", + "version" : "6.0.3" } }, { - "identity" : "fetch-node-details-swift", + "identity" : "jwt-kit", "kind" : "remoteSourceControl", - "location" : "https://github.com/torusresearch/fetch-node-details-swift", + "location" : "https://github.com/vapor/jwt-kit.git", "state" : { - "revision" : "4bd96c33ba8d02d9e27190c5c7cedf09cfdfd656", - "version" : "6.0.3" + "revision" : "c2595b9ad7f512d7f334830b4df1fed6e917946a", + "version" : "4.13.4" } }, { @@ -46,15 +45,24 @@ "version" : "3.1.0" } }, + { + "identity" : "swift-crypto", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-crypto.git", + "state" : { + "revision" : "81bee98e706aee68d39ed5996db069ef2b313d62", + "version" : "3.7.1" + } + }, { "identity" : "torus-utils-swift", "kind" : "remoteSourceControl", "location" : "https://github.com/torusresearch/torus-utils-swift.git", "state" : { - "revision" : "7788752bed699b3d34e78c2c51174f814d02610b", - "version" : "9.0.0" + "revision" : "eda55b8537a600e657d19d4c452c0a36f217883c", + "version" : "9.0.1" } } ], - "version" : 3 + "version" : 2 } diff --git a/CustomAuthDemo/CustomAuthDemo/ContentView.swift b/CustomAuthDemo/CustomAuthDemo/ContentView.swift index bc5c1a4..fc72ba5 100644 --- a/CustomAuthDemo/CustomAuthDemo/ContentView.swift +++ b/CustomAuthDemo/CustomAuthDemo/ContentView.swift @@ -2,6 +2,7 @@ import CustomAuth import SwiftUI struct ContentView: View { + @State private var inputDetail: String = "" var body: some View { VStack { @@ -9,7 +10,7 @@ struct ContentView: View { Task { do { let sub = SingleLoginParams(typeOfLogin: .google, verifier: "w3a-google-demo", clientId: "519228911939-cri01h55lsjbsia1k7ll6qpalrus75ps.apps.googleusercontent.com") - + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") let customAuth = try CustomAuth(config: customAuthArgs) let torusLoginResponse = try await customAuth.triggerLogin(args: sub) @@ -18,19 +19,18 @@ struct ContentView: View { } catch { print(error) } - } }, label: { Text("Google Login") }) - + Button(action: { Task { do { let sub = SingleLoginParams(typeOfLogin: .discord, verifier: "w3a-discord-demo", clientId: "1151006428610433095") - + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") - + let customAuth = try CustomAuth(config: customAuthArgs) let torusLoginResponse = try await customAuth.triggerLogin(args: sub) let encoded = try JSONEncoder().encode(torusLoginResponse) @@ -42,32 +42,31 @@ struct ContentView: View { }, label: { Text("Discord Login") }) - - - Button(action: { - Task { - do { - let sub = SingleLoginParams(typeOfLogin: .facebook, verifier: "w3a-facebook-demo", clientId: "342380202252650") - - let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") - - let customAuth = try CustomAuth(config: customAuthArgs) - let torusLoginResponse = try await customAuth.triggerLogin(args: sub) - let encoded = try JSONEncoder().encode(torusLoginResponse) - print(String(data: encoded, encoding: .utf8)!) - } catch { - print(error) - } - } - }, label: { - Text("Facebook Login") - }) - + + Button(action: { + Task { + do { + let sub = SingleLoginParams(typeOfLogin: .facebook, verifier: "w3a-facebook-demo", clientId: "342380202252650") + + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + + let customAuth = try CustomAuth(config: customAuthArgs) + let torusLoginResponse = try await customAuth.triggerLogin(args: sub) + let encoded = try JSONEncoder().encode(torusLoginResponse) + print(String(data: encoded, encoding: .utf8)!) + } catch { + print(error) + } + } + }, label: { + Text("Facebook Login") + }) + Button(action: { - let sub = SingleLoginParams(typeOfLogin: .twitch, verifier: "w3a-twitch-demo", clientId: "3k7e70gowvxjaxg71hjnc8h8ih3bpf") - let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") Task { do { + let sub = SingleLoginParams(typeOfLogin: .twitch, verifier: "w3a-twitch-demo", clientId: "3k7e70gowvxjaxg71hjnc8h8ih3bpf") + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") let customAuth = try CustomAuth(config: customAuthArgs) let torusLoginResponse = try await customAuth.triggerLogin(args: sub) let encoded = try JSONEncoder().encode(torusLoginResponse) @@ -79,12 +78,13 @@ struct ContentView: View { }, label: { Text("Twitch Login") }) - + Button(action: { - let sub = SingleLoginParams(typeOfLogin: .apple, verifier: "w3a-auth0-demo", clientId: "hUVVf4SEsZT7syOiL0gLU9hFEtm2gQ6O", jwtParams: Auth0ClientOptions(connection: "apple", domain: "web3auth.au.auth0.com")) - let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") Task { do { + let sub = SingleLoginParams(typeOfLogin: .apple, verifier: "w3a-auth0-demo", clientId: "hUVVf4SEsZT7syOiL0gLU9hFEtm2gQ6O", jwtParams: Auth0ClientOptions(connection: "apple", domain: "web3auth.au.auth0.com")) + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + let customAuth = try CustomAuth(config: customAuthArgs) let torusLoginResponse = try await customAuth.triggerLogin(args: sub) let encoded = try JSONEncoder().encode(torusLoginResponse) @@ -96,12 +96,12 @@ struct ContentView: View { }, label: { Text("Apple Login") }) - + Button(action: { - let sub = SingleLoginParams(typeOfLogin: .github, verifier: "w3a-auth0-demo", clientId: "hUVVf4SEsZT7syOiL0gLU9hFEtm2gQ6O", jwtParams: Auth0ClientOptions(connection: "github", domain: "web3auth.au.auth0.com", verifierIdField: "sub")) - let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") Task { do { + let sub = SingleLoginParams(typeOfLogin: .github, verifier: "w3a-auth0-demo", clientId: "hUVVf4SEsZT7syOiL0gLU9hFEtm2gQ6O", jwtParams: Auth0ClientOptions(connection: "github", domain: "web3auth.au.auth0.com", verifierIdField: "sub")) + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") let customAuth = try CustomAuth(config: customAuthArgs) let torusLoginResponse = try await customAuth.triggerLogin(args: sub) let encoded = try JSONEncoder().encode(torusLoginResponse) @@ -113,17 +113,17 @@ struct ContentView: View { }, label: { Text("GitHub Login") }) - + Button(action: { - let sub = SingleLoginParams(typeOfLogin: .email_password, - verifier: "torus-auth0-email-password", clientId: "sqKRBVSdwa4WLkaq419U7Bamlh5vK1H7", - jwtParams: Auth0ClientOptions( - connection: "Username-Password-Authentication", - domain: "torus-test.auth0.com", - verifierIdField: "name")) - let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") Task { do { + let sub = SingleLoginParams(typeOfLogin: .email_password, + verifier: "torus-auth0-email-password", clientId: "sqKRBVSdwa4WLkaq419U7Bamlh5vK1H7", + jwtParams: Auth0ClientOptions( + connection: "Username-Password-Authentication", + domain: "torus-test.auth0.com", + verifierIdField: "name")) + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") let customAuth = try CustomAuth(config: customAuthArgs) let torusLoginResponse = try await customAuth.triggerLogin(args: sub) let encoded = try JSONEncoder().encode(torusLoginResponse) @@ -137,16 +137,66 @@ struct ContentView: View { }) Label( - title: { Text("Aggregate Verifiers") }, + title: { Text("Hosted Passwordless") }, icon: { Image(systemName: "circle") } ) + TextField( + "Email or Phone Number", + text: $inputDetail + ) + .disableAutocorrection(true) + .border(.secondary) Button(action: { - let aggregateLoginParams = AggregateLoginParams(aggregateVerifierType: AggregateVerifierType.single_id_verifier, verifierIdentifier: "aggregate-sapphire", subVerifierDetailsArray: [SingleLoginParams(typeOfLogin: .google, verifier: "w3a-google", clientId: "519228911939-cri01h55lsjbsia1k7ll6qpalrus75ps.apps.googleusercontent.com")]) - - let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") Task { do { + let sub = SingleLoginParams(typeOfLogin: .email_passwordless, + verifier: "torus-auth0-email-passwordless-lrc", clientId: "P7PJuBCXIHP41lcyty0NEb7Lgf7Zme8Q", + jwtParams: Auth0ClientOptions(verifierIdField: "name", login_hint: inputDetail, flow_type: .link)) + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + let customAuth = try CustomAuth(config: customAuthArgs) + let torusLoginResponse = try await customAuth.triggerLogin(args: sub) + let encoded = try JSONEncoder().encode(torusLoginResponse) + print(String(data: encoded, encoding: .utf8)!) + } catch { + print(error) + } + } + }, label: { + Text("Email Passwordless") + }) + + + Button(action: { + Task { + do { + let sub = SingleLoginParams(typeOfLogin: .sms_passwordless, + verifier: "torus-sms-passwordless-lrc", clientId: "P7PJuBCXIHP41lcyty0NEb7Lgf7Zme8Q", + jwtParams: Auth0ClientOptions(login_hint: inputDetail, flow_type: .code)) + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + let customAuth = try CustomAuth(config: customAuthArgs) + let torusLoginResponse = try await customAuth.triggerLogin(args: sub) + let encoded = try JSONEncoder().encode(torusLoginResponse) + print(String(data: encoded, encoding: .utf8)!) + } catch { + print(error) + } + } + }, label: { + Text("SMS Passwordless") + }) + + Label( + title: { Text("Aggregate Verifiers") }, + icon: { Image(systemName: "circle") } + ) + + Button(action: { + Task { + do { + let aggregateLoginParams = AggregateLoginParams(aggregateVerifierType: AggregateVerifierType.single_id_verifier, verifierIdentifier: "aggregate-sapphire", subVerifierDetailsArray: [SingleLoginParams(typeOfLogin: .google, verifier: "w3a-google", clientId: "519228911939-cri01h55lsjbsia1k7ll6qpalrus75ps.apps.googleusercontent.com")]) + + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") let customAuth = try CustomAuth(config: customAuthArgs) let torusLoginResponse = try await customAuth.triggerAggregateLogin(args: aggregateLoginParams) let encoded = try JSONEncoder().encode(torusLoginResponse) @@ -158,14 +208,14 @@ struct ContentView: View { }, label: { Text("Aggregate Gmail") }) - + Button(action: { - let subVerifierDetailsArray = SingleLoginParams(typeOfLogin: .github, verifier: "w3a-a0-github", clientId: "hiLqaop0amgzCC0AXo4w0rrG9abuJTdu", jwtParams: OAuthClientOptions(domain: "web3auth.au.auth0.com", verifierIdField: "email")) - let aggregateLoginParams = AggregateLoginParams(aggregateVerifierType: AggregateVerifierType.single_id_verifier, verifierIdentifier: "aggregate-sapphire", subVerifierDetailsArray: [subVerifierDetailsArray]) - - let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") Task { do { + let subVerifierDetailsArray = SingleLoginParams(typeOfLogin: .github, verifier: "w3a-a0-github", clientId: "hiLqaop0amgzCC0AXo4w0rrG9abuJTdu", jwtParams: OAuthClientOptions(domain: "web3auth.au.auth0.com", verifierIdField: "email")) + let aggregateLoginParams = AggregateLoginParams(aggregateVerifierType: AggregateVerifierType.single_id_verifier, verifierIdentifier: "aggregate-sapphire", subVerifierDetailsArray: [subVerifierDetailsArray]) + + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") let customAuth = try CustomAuth(config: customAuthArgs) let torusLoginResponse = try await customAuth.triggerAggregateLogin(args: aggregateLoginParams) let encoded = try JSONEncoder().encode(torusLoginResponse) @@ -177,7 +227,6 @@ struct ContentView: View { }, label: { Text("Aggregate GitHub") }) - } } } diff --git a/Package.resolved b/Package.resolved index c12425b..8997069 100644 --- a/Package.resolved +++ b/Package.resolved @@ -59,8 +59,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/torusresearch/torus-utils-swift.git", "state" : { - "revision" : "303dc2cf41db7c10f769855edad0e717ced2d554", - "version" : "9.0.0" + "revision" : "eda55b8537a600e657d19d4c452c0a36f217883c", + "version" : "9.0.1" } } ], diff --git a/Package.swift b/Package.swift index 00a2b64..1269605 100644 --- a/Package.swift +++ b/Package.swift @@ -14,7 +14,7 @@ let package = Package( targets: ["CustomAuth"]) ], dependencies: [ - .package(url: "https://github.com/torusresearch/torus-utils-swift.git", from: "9.0.0"), + .package(url: "https://github.com/torusresearch/torus-utils-swift.git", from: "9.0.1"), .package(url: "https://github.com/auth0/JWTDecode.swift.git", from: "3.1.0"), // NB: jwt-kit may only be a test dependency or it will break cocoapods support .package(url: "https://github.com/vapor/jwt-kit.git", from: "4.13.0"), diff --git a/Sources/CustomAuth/Common/LoginParams/Auth0ClientOptions.swift b/Sources/CustomAuth/Common/LoginParams/Auth0ClientOptions.swift index 1b9897b..1b7e7cb 100644 --- a/Sources/CustomAuth/Common/LoginParams/Auth0ClientOptions.swift +++ b/Sources/CustomAuth/Common/LoginParams/Auth0ClientOptions.swift @@ -10,7 +10,8 @@ public class Auth0ClientOptions: BaseLoginOptions { public let id_token: String? public let access_token: String? public let user_info_route: String? - public let login_hint: String? + public var login_hint: String? + public let flow_type: EmailFlowType? private enum CodingKeys: CodingKey { case domain, @@ -22,10 +23,11 @@ public class Auth0ClientOptions: BaseLoginOptions { id_token, access_token, user_info_route, - login_hint + login_hint, + flow_type } - public init(display: String? = nil, prompt: String? = nil, max_age: Int? = nil, ui_locales: String? = nil, id_token_hint: String? = nil, arc_values: String? = nil, scope: String? = nil, audience: String? = nil, connection: String? = nil, domain: String? = nil, client_id: String? = nil, redirect_url: String? = nil, leeway: Int? = nil, verifierIdField: String? = nil, isVerifierIdCaseSensitive: Bool = false, id_token: String? = nil, access_token: String? = nil, user_info_route: String? = nil, login_hint: String? = nil) { + public init(display: String? = nil, prompt: String? = nil, max_age: Int? = nil, ui_locales: String? = nil, id_token_hint: String? = nil, arc_values: String? = nil, scope: String? = nil, audience: String? = nil, connection: String? = nil, domain: String? = nil, client_id: String? = nil, redirect_url: String? = nil, leeway: Int? = nil, verifierIdField: String? = nil, isVerifierIdCaseSensitive: Bool = false, id_token: String? = nil, access_token: String? = nil, user_info_route: String? = nil, login_hint: String? = nil, flow_type: EmailFlowType? = nil) { // This is for convenience in case a full url gets passed in // https:// is added back in later when it is constructed from @@ -45,6 +47,7 @@ public class Auth0ClientOptions: BaseLoginOptions { self.user_info_route = user_info_route self.client_id = client_id self.login_hint = login_hint + self.flow_type = flow_type super.init(display: display, prompt: prompt, max_age: max_age, ui_locales: ui_locales, id_token_hint: id_token_hint, arc_values: arc_values, scope: scope, audience: audience, connection: connection) } @@ -66,6 +69,7 @@ public class Auth0ClientOptions: BaseLoginOptions { try container.encodeIfPresent(self.id_token, forKey: .id_token) try container.encodeIfPresent(self.client_id, forKey: .client_id) try container.encodeIfPresent(self.login_hint, forKey: .login_hint) + try container.encodeIfPresent(self.flow_type, forKey: .flow_type) } } diff --git a/Sources/CustomAuth/Common/LoginParams/EmailFlowType.swift b/Sources/CustomAuth/Common/LoginParams/EmailFlowType.swift new file mode 100644 index 0000000..2f1b097 --- /dev/null +++ b/Sources/CustomAuth/Common/LoginParams/EmailFlowType.swift @@ -0,0 +1,6 @@ +import Foundation + +public enum EmailFlowType: String, Equatable, Hashable, Codable { + case link + case code +} diff --git a/Sources/CustomAuth/Common/State.swift b/Sources/CustomAuth/Common/State.swift index fdf1d76..db9909f 100644 --- a/Sources/CustomAuth/Common/State.swift +++ b/Sources/CustomAuth/Common/State.swift @@ -7,13 +7,15 @@ internal class State: Codable { public var typeOfLogin: String public var redirectUri: String public var redirectToAndroid: String = "true" + public var client: String? - public init(instanceId: String, verifier: String, typeOfLogin: String, redirectUri: String, customState: TorusGenericContainer? = nil) { + public init(instanceId: String, verifier: String, typeOfLogin: String, redirectUri: String, customState: TorusGenericContainer? = nil, client: String?) { self.customState = customState self.instanceId = instanceId self.verifier = verifier self.typeOfLogin = typeOfLogin self.redirectUri = redirectUri + self.client = client } public func encode(to encoder: any Encoder) throws { @@ -24,5 +26,6 @@ internal class State: Codable { try container.encode(typeOfLogin, forKey: .typeOfLogin) try container.encode(redirectToAndroid, forKey: .redirectToAndroid) try container.encode(redirectUri, forKey: .redirectUri) + try container.encodeIfPresent(client, forKey: .client) } } diff --git a/Sources/CustomAuth/CustomAuth.swift b/Sources/CustomAuth/CustomAuth.swift index 2447993..3eeb158 100644 --- a/Sources/CustomAuth/CustomAuth.swift +++ b/Sources/CustomAuth/CustomAuth.swift @@ -54,7 +54,7 @@ public class CustomAuth { /// /// - Throws: `CASDKError`, `TorusUtilError` public func triggerLogin(args: SingleLoginParams) async throws -> TorusLoginResponse { - 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)) + 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)) var loginParams: LoginWindowResponse if args.hash != nil && args.queryParams != nil { @@ -98,7 +98,7 @@ public class CustomAuth { var loginParamsArray: [LoginWindowResponse] = [] var userInfoArray: [UserInfo] = [] for subverifierDetail in args.subVerifierDetailsArray { - 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)) + 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)) var loginParams: LoginWindowResponse var userInfo: UserInfo if subverifierDetail.hash != nil && subverifierDetail.queryParams != nil { diff --git a/Sources/CustomAuth/Handlers/DiscordLoginHandler.swift b/Sources/CustomAuth/Handlers/DiscordLoginHandler.swift index d733793..8c7409d 100644 --- a/Sources/CustomAuth/Handlers/DiscordLoginHandler.swift +++ b/Sources/CustomAuth/Handlers/DiscordLoginHandler.swift @@ -13,8 +13,8 @@ internal class DiscordLoginHandler: AbstractLoginHandler { private var scope: String = "identify email" private var prompt: String = "none" - override public init(clientId: String, verifier: String, urlScheme: String, redirectURL: String, typeOfLogin: LoginType, jwtParams: Auth0ClientOptions? = nil, customState: TorusGenericContainer? = nil) throws { - try super.init(clientId: clientId, verifier: verifier, urlScheme: urlScheme, redirectURL: redirectURL, typeOfLogin: typeOfLogin, jwtParams: jwtParams, customState: customState) + override public init(params: CreateHandlerParams) throws { + try super.init(params: params) try setFinalUrl() } @@ -23,15 +23,15 @@ internal class DiscordLoginHandler: AbstractLoginHandler { var params: [String: String] = [:] - if jwtParams != nil { - params = try (JSONSerialization.jsonObject(with: try JSONEncoder().encode(jwtParams), options: []) as! [String: String]) + if self.params.jwtParams != nil { + params = try (JSONSerialization.jsonObject(with: try JSONEncoder().encode(self.params.jwtParams), options: []) as! [String: String]) } params.merge([ "state": try state(), "response_type": response_type, - "client_id": clientId, - "redirect_uri": redirectURL, + "client_id": self.params.clientId, + "redirect_uri": self.params.redirectURL, "prompt": prompt, "scope": scope], uniquingKeysWith: { _, new in new }) urlComponents.scheme = "https" @@ -56,6 +56,6 @@ internal class DiscordLoginHandler: AbstractLoginHandler { let profileImage = result.avatar == nil ? "https://cdn.discordapp.com/embed/avatars/" + String(Int(result.discriminator)! % 5) + ".png" : "https://cdn.discordapp.com/avatars/${id}/" + result.avatar! + ".png?size=2048" - return TorusVerifierResponse(email: result.email, name: result.username + "#" + result.discriminator, profileImage: profileImage, verifier: verifier, verifierId: result.id, typeOfLogin: typeOfLogin) + return TorusVerifierResponse(email: result.email, name: result.username + "#" + result.discriminator, profileImage: profileImage, verifier: self.params.verifier, verifierId: result.id, typeOfLogin: self.params.typeOfLogin) } } diff --git a/Sources/CustomAuth/Handlers/FacebookLoginHandler.swift b/Sources/CustomAuth/Handlers/FacebookLoginHandler.swift index 0081886..2f22259 100644 --- a/Sources/CustomAuth/Handlers/FacebookLoginHandler.swift +++ b/Sources/CustomAuth/Handlers/FacebookLoginHandler.swift @@ -19,8 +19,8 @@ internal class FacebookLoginHandler: AbstractLoginHandler { private var response_type: String = "token" private var scope: String = "public_profile email" - override public init(clientId: String, verifier: String, urlScheme: String, redirectURL: String, typeOfLogin: LoginType, jwtParams: Auth0ClientOptions? = nil, customState: TorusGenericContainer? = nil) throws { - try super.init(clientId: clientId, verifier: verifier, urlScheme: urlScheme, redirectURL: redirectURL, typeOfLogin: typeOfLogin, jwtParams: jwtParams, customState: customState) + override public init(params: CreateHandlerParams) throws { + try super.init(params: params) try setFinalUrl() } @@ -29,15 +29,15 @@ internal class FacebookLoginHandler: AbstractLoginHandler { var params: [String: String] = [:] - if jwtParams != nil { - params = try (JSONSerialization.jsonObject(with: try JSONEncoder().encode(jwtParams), options: []) as! [String: String]) + if self.params.jwtParams != nil { + params = try (JSONSerialization.jsonObject(with: try JSONEncoder().encode(self.params.jwtParams), options: []) as! [String: String]) } params.merge([ "state": try state(), "response_type": response_type, - "client_id": clientId, - "redirect_uri": redirectURL, + "client_id": self.params.clientId, + "redirect_uri": self.params.redirectURL, "scope": scope], uniquingKeysWith: { _, new in new }) urlComponents.scheme = "https" urlComponents.host = "www.facebook.com" @@ -59,6 +59,6 @@ internal class FacebookLoginHandler: AbstractLoginHandler { let result = try JSONDecoder().decode(FacebookInfo.self, from: data) - return TorusVerifierResponse(email: result.email, name: result.name, profileImage: result.picture.data.url, verifier: verifier, verifierId: result.id, typeOfLogin: typeOfLogin) + return TorusVerifierResponse(email: result.email, name: result.name, profileImage: result.picture.data.url, verifier: self.params.verifier, verifierId: result.id, typeOfLogin: self.params.typeOfLogin) } } diff --git a/Sources/CustomAuth/Handlers/GoogleLoginHandler.swift b/Sources/CustomAuth/Handlers/GoogleLoginHandler.swift index c733582..bf89a8c 100644 --- a/Sources/CustomAuth/Handlers/GoogleLoginHandler.swift +++ b/Sources/CustomAuth/Handlers/GoogleLoginHandler.swift @@ -11,8 +11,8 @@ internal class GoogleLoginHandler: AbstractLoginHandler { private var scope: String = "profile email openid" private var prompt: String = "select_account" - override public init(clientId: String, verifier: String, urlScheme: String, redirectURL: String, typeOfLogin: LoginType, jwtParams: Auth0ClientOptions? = nil, customState: TorusGenericContainer? = nil) throws { - try super.init(clientId: clientId, verifier: verifier, urlScheme: urlScheme, redirectURL: redirectURL, typeOfLogin: typeOfLogin, jwtParams: jwtParams, customState: customState) + override public init(params: CreateHandlerParams) throws { + try super.init(params: params) try setFinalUrl() } @@ -21,16 +21,16 @@ internal class GoogleLoginHandler: AbstractLoginHandler { var params: [String: String] = [:] - if jwtParams != nil { - params = try (JSONSerialization.jsonObject(with: try JSONEncoder().encode(jwtParams), options: []) as! [String: String]) + if self.params.jwtParams != nil { + params = try (JSONSerialization.jsonObject(with: try JSONEncoder().encode(self.params.jwtParams), options: []) as! [String: String]) } params.merge([ "state": try state(), "response_type": response_type, - "client_id": clientId, + "client_id": self.params.clientId, "prompt": prompt, - "redirect_uri": redirectURL, + "redirect_uri": self.params.redirectURL, "scope": scope, "nonce": nonce, ], uniquingKeysWith: { _, new in new }) @@ -54,6 +54,6 @@ internal class GoogleLoginHandler: AbstractLoginHandler { let result = try JSONDecoder().decode(GoogleInfo.self, from: data) - return TorusVerifierResponse(email: result.email, name: result.name, profileImage: result.picture, verifier: verifier, verifierId: result.email.lowercased(), typeOfLogin: typeOfLogin) + return TorusVerifierResponse(email: result.email, name: result.name, profileImage: result.picture, verifier: self.params.verifier, verifierId: result.email.lowercased(), typeOfLogin: self.params.typeOfLogin) } } diff --git a/Sources/CustomAuth/Handlers/HandlerFactory.swift b/Sources/CustomAuth/Handlers/HandlerFactory.swift index 8bcd9bb..824757e 100644 --- a/Sources/CustomAuth/Handlers/HandlerFactory.swift +++ b/Sources/CustomAuth/Handlers/HandlerFactory.swift @@ -19,13 +19,13 @@ internal class HandlerFactory { switch params.typeOfLogin { case .google: - return try GoogleLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin, jwtParams: params.jwtParams, customState: params.customState) + return try GoogleLoginHandler(params: params) case .facebook: - return try FacebookLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin, jwtParams: params.jwtParams, customState: params.customState) + return try FacebookLoginHandler(params: params) case .twitch: - return try TwitchLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin, jwtParams: params.jwtParams, customState: params.customState) + return try TwitchLoginHandler(params: params) case .discord: - return try DiscordLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin, jwtParams: params.jwtParams, customState: params.customState) + return try DiscordLoginHandler(params: params) case .reddit: break case .apple: break case .github: break @@ -38,30 +38,28 @@ internal class HandlerFactory { if domain == nil || hint == nil { throw CASDKError.invalidAuth0Options } - return try PasswordlessLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin, jwtParams: params.jwtParams, customState: params.customState) + throw CASDKError.invalidAuth0Options case .email_passwordless: - if domain == nil || hint == nil { + if hint == nil { throw CASDKError.invalidAuth0Options } - throw CASDKError.invalidAuth0Options - // TODO: implement web3authpasswordlesshandler for this + return try Web3AuthPasswordlessHandler(params: params) case .sms_passwordless: if hint == nil { throw CASDKError.invalidAuth0Options } - throw CASDKError.invalidAuth0Options - // TODO: implement web3authpasswordlesshandler for this + return try Web3AuthPasswordlessHandler(params: params) case .jwt: break } if idToken != nil || accessToken != nil { - return try MockLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin, jwtParams: params.jwtParams, customState: params.customState) + return try MockLoginHandler(params: params) } if domain == nil { throw CASDKError.invalidAuth0Options } - return try JWTLoginHandler(clientId: params.clientId, verifier: params.verifier, urlScheme: params.urlScheme, redirectURL: params.redirectURL, typeOfLogin: params.typeOfLogin, jwtParams: params.jwtParams, customState: params.customState) + return try JWTLoginHandler(params: params) } } diff --git a/Sources/CustomAuth/Handlers/JWTLoginHandler.swift b/Sources/CustomAuth/Handlers/JWTLoginHandler.swift index f07e372..7d12aec 100644 --- a/Sources/CustomAuth/Handlers/JWTLoginHandler.swift +++ b/Sources/CustomAuth/Handlers/JWTLoginHandler.swift @@ -22,39 +22,39 @@ internal class JWTLoginHandler: AbstractLoginHandler { private var scope: String = "openid profile email" private var prompt: String = "login" - override public init(clientId: String, verifier: String, urlScheme: String, redirectURL: String, typeOfLogin: LoginType, jwtParams: Auth0ClientOptions? = nil, customState: TorusGenericContainer? = nil) throws { - try super.init(clientId: clientId, verifier: verifier, urlScheme: urlScheme, redirectURL: redirectURL, typeOfLogin: typeOfLogin, jwtParams: jwtParams, customState: customState) + override public init(params: CreateHandlerParams) throws { + try super.init(params: params) try setFinalUrl() } override public func setFinalUrl() throws { var urlComponents = URLComponents() - if jwtParams == nil { + if self.params.jwtParams == nil { throw CASDKError.invalidAuth0Options } - var connection = jwtParams?.connection + var connection = self.params.jwtParams?.connection if connection == nil { - connection = loginToConnection(loginType: typeOfLogin) + connection = loginToConnection(loginType: self.params.typeOfLogin) } - let encoded = try JSONEncoder().encode(jwtParams) + let encoded = try JSONEncoder().encode(self.params.jwtParams) let serialized = try JSONSerialization.jsonObject(with: encoded, options: [.fragmentsAllowed, .mutableContainers]) var params: [String: String] = serialized as! [String: String] params.merge([ "state": try state(), "response_type": response_type, - "client_id": clientId, + "client_id": self.params.clientId, "prompt": prompt, - "redirect_uri": redirectURL, + "redirect_uri": self.params.redirectURL, "scope": scope, "connection": connection!, "nonce": nonce, ], uniquingKeysWith: { _, new in new }) urlComponents.scheme = "https" - urlComponents.host = jwtParams?.domain + urlComponents.host = self.params.jwtParams?.domain urlComponents.path = "/authorize" urlComponents.setQueryItems(with: params) @@ -64,12 +64,12 @@ internal class JWTLoginHandler: AbstractLoginHandler { override public func getUserInfo(params: LoginWindowResponse, storageServerUrl: String?) async throws -> TorusVerifierResponse { let accessToken = params.accessToken let idToken = params.idToken - let verifierIdField = jwtParams?.verifierIdField - let isVerifierCaseSensitive = jwtParams?.isVerifierIdCaseSensitive != nil ? Bool(jwtParams!.isVerifierIdCaseSensitive)! : true + let verifierIdField = self.params.jwtParams?.verifierIdField + let isVerifierCaseSensitive = self.params.jwtParams?.isVerifierIdCaseSensitive != nil ? Bool(self.params.jwtParams!.isVerifierIdCaseSensitive)! : true if accessToken != nil { - let domain = jwtParams?.domain - var user_route_info = jwtParams?.user_info_route ?? "/userinfo" + let domain = self.params.jwtParams?.domain + var user_route_info = self.params.jwtParams?.user_info_route ?? "/userinfo" if !user_route_info.hasPrefix("/") { user_route_info = "/" + user_route_info @@ -86,7 +86,7 @@ internal class JWTLoginHandler: AbstractLoginHandler { let (data, _) = try await URLSession.shared.data(for: urlRequest) let result = try JSONDecoder().decode(Auth0UserInfo.self, from: data) - return TorusVerifierResponse(email: result.email, name: result.name, profileImage: result.picture, verifier: verifier, verifierId: try jwtParams?.verifierIdField ?? getVerifierId(userInfo: result, typeOfLogin: typeOfLogin, verifierIdField: verifierIdField, isVerifierIdCaseSensitive: isVerifierCaseSensitive), typeOfLogin: typeOfLogin) + 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) } if idToken == nil { @@ -95,7 +95,7 @@ internal class JWTLoginHandler: AbstractLoginHandler { let decodedToken = try decode(jwt: idToken!) 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 ?? "") - return TorusVerifierResponse(email: result.email, name: result.name, profileImage: result.picture, verifier: verifier, verifierId: try jwtParams?.verifierIdField ?? getVerifierId(userInfo: result, typeOfLogin: typeOfLogin, verifierIdField: verifierIdField, isVerifierIdCaseSensitive: isVerifierCaseSensitive), typeOfLogin: typeOfLogin) + 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) } } } diff --git a/Sources/CustomAuth/Handlers/MockLoginHandler.swift b/Sources/CustomAuth/Handlers/MockLoginHandler.swift index df17a0f..96f164a 100644 --- a/Sources/CustomAuth/Handlers/MockLoginHandler.swift +++ b/Sources/CustomAuth/Handlers/MockLoginHandler.swift @@ -2,32 +2,32 @@ import Foundation import JWTDecode internal class MockLoginHandler: AbstractLoginHandler { - override public init(clientId: String, verifier: String, urlScheme: String, redirectURL: String, typeOfLogin: LoginType, jwtParams: Auth0ClientOptions? = nil, customState: TorusGenericContainer? = nil) throws { - try super.init(clientId: clientId, verifier: verifier, urlScheme: urlScheme, redirectURL: redirectURL, typeOfLogin: typeOfLogin, jwtParams: jwtParams, customState: customState) + override public init(params: CreateHandlerParams) throws { + try super.init(params: params) try setFinalUrl() } override public func setFinalUrl() throws { - if jwtParams == nil { + if self.params.jwtParams == nil { throw CASDKError.invalidAuth0Options } - var connection = jwtParams?.connection + var connection = self.params.jwtParams?.connection if connection == nil { - connection = loginToConnection(loginType: typeOfLogin) + connection = loginToConnection(loginType: self.params.typeOfLogin) } - var params: [String: String] = try (JSONSerialization.jsonObject(with: try JSONEncoder().encode(jwtParams), options: []) as! [String: String]) + var params: [String: String] = try (JSONSerialization.jsonObject(with: try JSONEncoder().encode(self.params.jwtParams), options: []) as! [String: String]) params.merge([ "state": try state(), - "client_id": clientId, + "client_id": self.params.clientId, "connection": connection!, "nonce": nonce, ], uniquingKeysWith: { _, new in new }) var urlComponents = URLComponents() urlComponents.scheme = "https" - urlComponents.host = jwtParams?.domain + urlComponents.host = self.params.jwtParams?.domain urlComponents.path = "/authorize" urlComponents.fragment = params.compactMap({ (key, value) -> String in return "\(key)=\(value)" @@ -53,12 +53,12 @@ internal class MockLoginHandler: AbstractLoginHandler { override public func getUserInfo(params: LoginWindowResponse, storageServerUrl: String?) async throws -> TorusVerifierResponse { let accessToken = params.accessToken let idToken = params.idToken - let verifierIdField = jwtParams?.verifierIdField - let isVerifierCaseSensitive = jwtParams?.isVerifierIdCaseSensitive != nil ? Bool(jwtParams!.isVerifierIdCaseSensitive)! : true + let verifierIdField = self.params.jwtParams?.verifierIdField + let isVerifierCaseSensitive = self.params.jwtParams?.isVerifierIdCaseSensitive != nil ? Bool(self.params.jwtParams!.isVerifierIdCaseSensitive)! : true if accessToken != nil { - let domain = jwtParams?.domain - var user_route_info = jwtParams?.user_info_route ?? "/userinfo" + let domain = self.params.jwtParams?.domain + var user_route_info = self.params.jwtParams?.user_info_route ?? "/userinfo" if !user_route_info.hasPrefix("/") { user_route_info = "/" + user_route_info @@ -76,7 +76,7 @@ internal class MockLoginHandler: AbstractLoginHandler { let result = try JSONDecoder().decode(Auth0UserInfo.self, from: data) - return TorusVerifierResponse(email: result.email, name: result.name, profileImage: result.picture, verifier: verifier, verifierId: try jwtParams?.verifierIdField ?? getVerifierId(userInfo: result, typeOfLogin: typeOfLogin, verifierIdField: verifierIdField, isVerifierIdCaseSensitive: isVerifierCaseSensitive), typeOfLogin: typeOfLogin) + 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) } if idToken == nil { @@ -85,7 +85,7 @@ internal class MockLoginHandler: AbstractLoginHandler { let decodedToken = try decode(jwt: idToken!) 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 ?? "") - return TorusVerifierResponse(email: result.email, name: result.name, profileImage: result.picture, verifier: verifier, verifierId: try jwtParams?.verifierIdField ?? getVerifierId(userInfo: result, typeOfLogin: typeOfLogin, verifierIdField: verifierIdField, isVerifierIdCaseSensitive: isVerifierCaseSensitive), typeOfLogin: typeOfLogin) + 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) } } } diff --git a/Sources/CustomAuth/Handlers/PasswordlessLoginHandler.swift b/Sources/CustomAuth/Handlers/PasswordlessLoginHandler.swift deleted file mode 100644 index 4c2b2d7..0000000 --- a/Sources/CustomAuth/Handlers/PasswordlessLoginHandler.swift +++ /dev/null @@ -1,85 +0,0 @@ -import Foundation -import JWTDecode - -internal class PasswordlessLoginHandler: AbstractLoginHandler { - private var response_type: String = "token id_token" - private var scope: String = "openid profile email" - private var prompt: String = "login" - - override public init(clientId: String, verifier: String, urlScheme: String, redirectURL: String, typeOfLogin: LoginType, jwtParams: Auth0ClientOptions? = nil, customState: TorusGenericContainer? = nil) throws { - try super.init(clientId: clientId, verifier: verifier, urlScheme: urlScheme, redirectURL: redirectURL, typeOfLogin: typeOfLogin, jwtParams: jwtParams, customState: customState) - try setFinalUrl() - } - - override public func setFinalUrl() throws { - var urlComponents = URLComponents() - - if jwtParams == nil { - throw CASDKError.invalidAuth0Options - } - - var connection = jwtParams?.connection - if connection == nil { - connection = loginToConnection(loginType: typeOfLogin) - } - - let encoded = try JSONEncoder().encode(jwtParams) - let serialized = try JSONSerialization.jsonObject(with: encoded, options: [.fragmentsAllowed, .mutableContainers]) - - var params: [String: String] = serialized as! [String: String] - params.merge([ - "state": try state(), - "response_type": response_type, - "client_id": clientId, - "prompt": prompt, - "redirect_uri": redirectURL, - "scope": scope, - "connection": connection!, - "nonce": nonce, - ], uniquingKeysWith: { _, new in new }) - urlComponents.scheme = "https" - urlComponents.host = jwtParams?.domain - urlComponents.path = "/passwordless/start" - urlComponents.setQueryItems(with: params) - - finalUrl = urlComponents - } - - override public func getUserInfo(params: LoginWindowResponse, storageServerUrl: String?) async throws -> TorusVerifierResponse { - let accessToken = params.accessToken - let idToken = params.idToken - let verifierIdField = jwtParams?.verifierIdField - let isVerifierCaseSensitive = jwtParams?.isVerifierIdCaseSensitive != nil ? Bool(jwtParams!.isVerifierIdCaseSensitive)! : true - - if accessToken != nil { - let domain = jwtParams?.domain - var user_route_info = jwtParams?.user_info_route ?? "/userinfo" - - if !user_route_info.hasPrefix("/") { - user_route_info = "/" + user_route_info - } - - var urlComponents = URLComponents() - urlComponents.scheme = "https" - urlComponents.host = domain - urlComponents.path = user_route_info - - var urlRequest = makeUrlRequest(url: urlComponents.string!, method: "GET") - urlRequest.addValue("Bearer \(accessToken!)", forHTTPHeaderField: "Authorization") - - let (data, _) = try await URLSession.shared.data(for: urlRequest) - let result = try JSONDecoder().decode(Auth0UserInfo.self, from: data) - - return TorusVerifierResponse(email: result.email, name: result.name, profileImage: result.picture, verifier: verifier, verifierId: try jwtParams?.verifierIdField ?? getVerifierId(userInfo: result, typeOfLogin: typeOfLogin, verifierIdField: verifierIdField, isVerifierIdCaseSensitive: isVerifierCaseSensitive), typeOfLogin: typeOfLogin) - } - - if idToken == nil { - throw CASDKError.idTokenNotProvided - } else { - let decodedToken = try decode(jwt: idToken!) - 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 ?? "") - - return TorusVerifierResponse(email: result.email, name: result.name, profileImage: result.picture, verifier: verifier, verifierId: try jwtParams?.verifierIdField ?? getVerifierId(userInfo: result, typeOfLogin: typeOfLogin, verifierIdField: verifierIdField, isVerifierIdCaseSensitive: isVerifierCaseSensitive), typeOfLogin: typeOfLogin) - } - } -} diff --git a/Sources/CustomAuth/Handlers/Protocol/AbstractLoginHandler.swift b/Sources/CustomAuth/Handlers/Protocol/AbstractLoginHandler.swift index 464fd7f..4365667 100644 --- a/Sources/CustomAuth/Handlers/Protocol/AbstractLoginHandler.swift +++ b/Sources/CustomAuth/Handlers/Protocol/AbstractLoginHandler.swift @@ -1,43 +1,26 @@ import Foundation +import FetchNodeDetails #if canImport(curveSecp256k1) import curveSecp256k1 #endif internal class AbstractLoginHandler: ILoginHandler { - public var clientId: String - public var nonce: String public var finalUrl: URLComponents - public var urlScheme: String - - public var redirectURL: String - - public var verifier: String - - public var typeOfLogin: LoginType - - public var jwtParams: Auth0ClientOptions? - - public var customState: TorusGenericContainer? + public var params: CreateHandlerParams - public init(clientId: String, verifier: String, urlScheme: String, redirectURL: String, typeOfLogin: LoginType, jwtParams: Auth0ClientOptions? = nil, customState: TorusGenericContainer? = nil) throws { - self.clientId = clientId - nonce = try SecretKey().serialize().addLeading0sForLength64() + public init(params: CreateHandlerParams) throws { + self.nonce = try SecretKey().serialize().addLeading0sForLength64() finalUrl = URLComponents() - self.verifier = verifier - self.urlScheme = urlScheme - self.typeOfLogin = typeOfLogin - self.jwtParams = jwtParams - self.customState = customState - self.redirectURL = redirectURL + self.params = params } public func state() throws -> String { let encoder = JSONEncoder() encoder.outputFormatting = .sortedKeys - let state = State(instanceId: nonce, verifier: verifier, typeOfLogin: typeOfLogin.rawValue, redirectUri: urlScheme, customState: customState) + let state = State(instanceId: nonce, verifier: params.verifier, typeOfLogin: params.typeOfLogin.rawValue, redirectUri: params.urlScheme, customState: params.customState, client: params.web3AuthClientId) return try encoder.encode(state).toBase64URL() } @@ -46,7 +29,7 @@ internal class AbstractLoginHandler: ILoginHandler { } public func handleLoginWindow(popupFeatures: String?) async throws -> LoginWindowResponse { - guard let callbackURLScheme = URL(string: urlScheme)?.scheme else { + guard let callbackURLScheme = URL(string: params.urlScheme)?.scheme else { throw CASDKError.invalidCallbackURLScheme } diff --git a/Sources/CustomAuth/Handlers/Protocol/CreateHandlerParams.swift b/Sources/CustomAuth/Handlers/Protocol/CreateHandlerParams.swift index 5db8380..b685675 100644 --- a/Sources/CustomAuth/Handlers/Protocol/CreateHandlerParams.swift +++ b/Sources/CustomAuth/Handlers/Protocol/CreateHandlerParams.swift @@ -1,6 +1,7 @@ import Foundation +import FetchNodeDetails -internal class CreateHandlerParams: Codable { +internal class CreateHandlerParams { public let typeOfLogin: LoginType public let verifier: String public let clientId: String @@ -8,8 +9,10 @@ internal class CreateHandlerParams: Codable { public let redirectURL: String public let jwtParams: Auth0ClientOptions? public let customState: TorusGenericContainer? + public let web3AuthNetwork: TorusNetwork + public let web3AuthClientId: String - public init(typeOfLogin: LoginType, verifier: String, clientId: String, urlScheme: String, redirectURL: String, jwtParams: Auth0ClientOptions? = nil, customState: TorusGenericContainer? = nil) { + public init(typeOfLogin: LoginType, verifier: String, clientId: String, urlScheme: String, redirectURL: String, jwtParams: Auth0ClientOptions? = nil, customState: TorusGenericContainer? = nil, web3AuthNetwork: TorusNetwork, web3AuthClientId: String) { self.typeOfLogin = typeOfLogin self.verifier = verifier self.clientId = clientId @@ -17,5 +20,7 @@ internal class CreateHandlerParams: Codable { self.jwtParams = jwtParams self.customState = customState self.redirectURL = redirectURL + self.web3AuthNetwork = web3AuthNetwork + self.web3AuthClientId = web3AuthClientId } } diff --git a/Sources/CustomAuth/Handlers/Protocol/ILoginHandler.swift b/Sources/CustomAuth/Handlers/Protocol/ILoginHandler.swift index 3201741..ea522ba 100644 --- a/Sources/CustomAuth/Handlers/Protocol/ILoginHandler.swift +++ b/Sources/CustomAuth/Handlers/Protocol/ILoginHandler.swift @@ -1,7 +1,7 @@ import Foundation internal protocol ILoginHandler { - var clientId: String { get set } + var params: CreateHandlerParams { get set } var nonce: String { get set } var finalUrl: URLComponents { get set } diff --git a/Sources/CustomAuth/Handlers/TwitchLoginHandler.swift b/Sources/CustomAuth/Handlers/TwitchLoginHandler.swift index 1723669..a106c15 100644 --- a/Sources/CustomAuth/Handlers/TwitchLoginHandler.swift +++ b/Sources/CustomAuth/Handlers/TwitchLoginHandler.swift @@ -15,8 +15,8 @@ internal class TwitchLoginHandler: AbstractLoginHandler { private var response_type: String = "token" private var scope: String = "user:read:email" - override public init(clientId: String, verifier: String, urlScheme: String, redirectURL: String, typeOfLogin: LoginType, jwtParams: Auth0ClientOptions? = nil, customState: TorusGenericContainer? = nil) throws { - try super.init(clientId: clientId, verifier: verifier, urlScheme: urlScheme, redirectURL: redirectURL, typeOfLogin: typeOfLogin, jwtParams: jwtParams, customState: customState) + override public init(params: CreateHandlerParams) throws { + try super.init(params: params) try setFinalUrl() } @@ -25,15 +25,15 @@ internal class TwitchLoginHandler: AbstractLoginHandler { var params: [String: String] = [:] - if jwtParams != nil { - params = try (JSONSerialization.jsonObject(with: try JSONEncoder().encode(jwtParams), options: []) as! [String: String]) + if self.params.jwtParams != nil { + params = try (JSONSerialization.jsonObject(with: try JSONEncoder().encode(self.params.jwtParams), options: []) as! [String: String]) } params.merge([ "state": try state(), "response_type": response_type, - "client_id": clientId, - "redirect_uri": redirectURL, + "client_id": self.params.clientId, + "redirect_uri": self.params.redirectURL, "scope": scope, "force_verify": "true", ], uniquingKeysWith: { _, new in new }) @@ -52,7 +52,7 @@ internal class TwitchLoginHandler: AbstractLoginHandler { var urlRequest = makeUrlRequest(url: "https://api.twitch.tv/helix/users", method: "GET") urlRequest.addValue("Bearer \(accessToken)", forHTTPHeaderField: "Authorization") - urlRequest.addValue(self.clientId, forHTTPHeaderField: "Client-ID") + urlRequest.addValue(self.params.clientId, forHTTPHeaderField: "Client-ID") let (data, _) = try await URLSession.shared.data(for: urlRequest) let result = try JSONDecoder().decode(TwitchRootInfo.self, from: data) @@ -61,6 +61,6 @@ internal class TwitchLoginHandler: AbstractLoginHandler { throw CASDKError.decodingFailed } - return TorusVerifierResponse(email: userdata.email ?? "", name: userdata.display_name, profileImage: userdata.profile_image_url, verifier: verifier, verifierId: userdata.id, typeOfLogin: typeOfLogin) + 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) } } diff --git a/Sources/CustomAuth/Handlers/Web3AuthPasswordlessLoginHandler.swift b/Sources/CustomAuth/Handlers/Web3AuthPasswordlessLoginHandler.swift new file mode 100644 index 0000000..6fa2884 --- /dev/null +++ b/Sources/CustomAuth/Handlers/Web3AuthPasswordlessLoginHandler.swift @@ -0,0 +1,68 @@ +import Foundation +import JWTDecode + +internal class Web3AuthPasswordlessHandler: AbstractLoginHandler { + private var response_type: String = "token id_token" + private var scope: String = "openid profile email" + private var prompt: String = "login" + + override public init(params: CreateHandlerParams) throws { + try super.init(params: params) + try setFinalUrl() + } + + override public func setFinalUrl() throws { + if self.params.jwtParams == nil { + throw CASDKError.invalidAuth0Options + } + + let domain = self.params.jwtParams?.domain + + var urlComponents = URLComponents() + + var connection = self.params.jwtParams!.connection + if connection == nil { + connection = loginToConnection(loginType: self.params.typeOfLogin) + } + + let encoded = try JSONEncoder().encode(self.params.jwtParams) + let serialized = try JSONSerialization.jsonObject(with: encoded, options: [.fragmentsAllowed, .mutableContainers]) + + var params: [String: String] = serialized as! [String: String] + params.merge([ + "state": try state(), + "response_type": response_type, + "client_id": self.params.clientId, + "prompt": prompt, + "redirect_uri": self.params.redirectURL, + "scope": scope, + "connection": connection!, + "nonce": nonce, + "network": self.params.web3AuthNetwork.name, + "flow_type": self.params.jwtParams?.flow_type?.rawValue ?? EmailFlowType.code.rawValue + ], uniquingKeysWith: { _, new in new }) + // workaround for plus not being encoded + params["login_hint"]! = params["login_hint"]!.replacingOccurrences(of: "+", with: "%2B") + urlComponents.scheme = "https" + urlComponents.host = domain ?? "passwordless.web3auth.io" + urlComponents.path = domain == nil ? "/v6/authorize" : "/authorize" + urlComponents.setQueryItems(with: params) + + finalUrl = urlComponents + } + + override public func getUserInfo(params: LoginWindowResponse, storageServerUrl: String?) async throws -> TorusVerifierResponse { + let idToken = params.idToken + let verifierIdField = self.params.jwtParams?.verifierIdField + let isVerifierCaseSensitive = self.params.jwtParams?.isVerifierIdCaseSensitive != nil ? Bool(self.params.jwtParams!.isVerifierIdCaseSensitive)! : true + + if idToken == nil { + throw CASDKError.idTokenNotProvided + } else { + let decodedToken = try decode(jwt: idToken!) + let result = Auth0UserInfo(picture: decodedToken.body["picture"] as? String ?? "", email: decodedToken.body["email"] as? String ?? "", name: decodedToken.body["name"] as? String ?? "", sub: "", nickname: "") + + 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) + } + } +} diff --git a/cocoapods/Podfile.lock b/cocoapods/Podfile.lock index f1cdccb..9ff44a6 100644 --- a/cocoapods/Podfile.lock +++ b/cocoapods/Podfile.lock @@ -35,6 +35,6 @@ SPEC CHECKSUMS: Torus-fetchNodeDetails: 6c349f47cbca36a4b3f276fe26d03c1b39b20949 Torus-utils: 0f993fffd66a66a0423092c9ddea2cbff4d298df -PODFILE CHECKSUM: 9b208a8d1d57bbade0916f1ca893014f4b177c68 +PODFILE CHECKSUM: 3f0652a4c9819c7b293e6a1f91fd5a27a70c0533 COCOAPODS: 1.13.0 diff --git a/cocoapods/cptest/LoginView.swift b/cocoapods/cptest/LoginView.swift index ea34161..d21f43c 100644 --- a/cocoapods/cptest/LoginView.swift +++ b/cocoapods/cptest/LoginView.swift @@ -6,12 +6,6 @@ struct LoginView: View { List { Section(header: Text("Single Logins")) { Group { - Button(action: { - vm.googlePolygonLogin() - }, label: { - Text("Google Polygon") - }) - Button(action: { vm.googleLogin() }, label: { @@ -19,12 +13,6 @@ struct LoginView: View { }) } - Button(action: { - vm.redditLogin() - }, label: { - Text("Reddit Login") - }) - Button(action: { vm.discordLogin() }, label: { @@ -43,36 +31,18 @@ struct LoginView: View { Text("Twitch Login") }) - Button(action: { - vm.twitterLogin() - }, label: { - Text("Twitter Login") - }) - Button(action: { vm.githubLogin() }, label: { Text("Github Login") }) - Button(action: { - vm.linkedinLogin() - }, label: { - Text("Linkedin Login") - }) - Button(action: { vm.appleLogin() }, label: { Text("Apple Login") }) - - Button(action: { - vm.weiboLogin() - }, label: { - Text("Weibo Login") - }) - + Button(action: { vm.emailPasswordLogin() }, label: { diff --git a/cocoapods/cptest/ViewModel.swift b/cocoapods/cptest/ViewModel.swift index 8dcf819..c7665d6 100644 --- a/cocoapods/cptest/ViewModel.swift +++ b/cocoapods/cptest/ViewModel.swift @@ -18,54 +18,18 @@ class ViewModel: ObservableObject { } extension ViewModel { - func googlePolygonLogin() { - let sub = SubVerifierDetails(typeOfLogin: .google, verifier: "polygon-ios-test", clientId: "908137525998-fs00a3go5r7fpbntmui4lb8nhuqqtmaa.apps.googleusercontent.com", redirectURL: "https://scripts.toruswallet.io/redirect.html") - - let options = CustomAuthArgs(urlScheme: "torus://org.torusresearch.sample/redirect", network: .legacy(.CYAN), enableOneKey: true, web3AuthClientId: "CLIENT ID") - - Task { - do { - let customAuth = try CustomAuth(config: options) - - let keyDetails = try await customAuth.triggerLogin(args: sub) - - user = User(publicAddress: keyDetails.torusKey.finalKeyData.evmAddress, privateKey: keyDetails.torusKey.finalKeyData.privKey, userInfo: keyDetails.singleVerifierResponse.userInfo) - } catch { - print(error) - } - } - } - func googleLogin() { - let sub = SubVerifierDetails(typeOfLogin: .google, verifier: "google-lrc", clientId: "221898609709-obfn3p63741l5333093430j3qeiinaa8.apps.googleusercontent.com", redirectURL: "https://scripts.toruswallet.io/redirect.html") - - let options = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "CLIENT ID") - - Task { - do { - let customAuth = try CustomAuth(config: options) - - let keyDetails = try await customAuth.triggerLogin(args: sub) - - user = User(publicAddress: keyDetails.torusKey.finalKeyData.evmAddress, privateKey: keyDetails.torusKey.finalKeyData.privKey, userInfo: keyDetails.singleVerifierResponse.userInfo) - } catch { - print(error) - } - } - } - - func redditLogin() { - let sub = SubVerifierDetails(typeOfLogin: .reddit, verifier: "reddit-shubs", clientId: "rXIp6g2y3h1wqg", redirectURL: "https://scripts.toruswallet.io/redirect.html") - - let options = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "CLIENT ID") - Task { do { - let customAuth = try CustomAuth(config: options) + let sub = SingleLoginParams(typeOfLogin: .google, verifier: "w3a-google-demo", clientId: "519228911939-cri01h55lsjbsia1k7ll6qpalrus75ps.apps.googleusercontent.com") - let keyDetails = try await customAuth.triggerLogin(args: sub) + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + let customAuth = try CustomAuth(config: customAuthArgs) + let torusLoginResponse = try await customAuth.triggerLogin(args: sub) - user = User(publicAddress: keyDetails.torusKey.finalKeyData.evmAddress, privateKey: keyDetails.torusKey.finalKeyData.privKey, userInfo: keyDetails.singleVerifierResponse.userInfo) + DispatchQueue.main.async { + self.user = User(publicAddress: torusLoginResponse.torusKey.finalKeyData.evmAddress, privateKey: torusLoginResponse.torusKey.finalKeyData.privKey, userInfo: torusLoginResponse.singleVerifierResponse.userInfo) + } } catch { print(error) } @@ -73,17 +37,18 @@ extension ViewModel { } func discordLogin() { - let sub = SubVerifierDetails(typeOfLogin: .discord, verifier: "dhruv-discord", clientId: "1034724991972954172", redirectURL: "https://scripts.toruswallet.io/redirect.html") - - let options = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "CLIENT ID") - Task { do { - let customAuth = try CustomAuth(config: options) + let sub = SingleLoginParams(typeOfLogin: .discord, verifier: "w3a-discord-demo", clientId: "1151006428610433095") - let keyDetails = try await customAuth.triggerLogin(args: sub) + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") - user = User(publicAddress: keyDetails.torusKey.finalKeyData.evmAddress, privateKey: keyDetails.torusKey.finalKeyData.privKey, userInfo: keyDetails.singleVerifierResponse.userInfo) + let customAuth = try CustomAuth(config: customAuthArgs) + let torusLoginResponse = try await customAuth.triggerLogin(args: sub) + + DispatchQueue.main.async { + self.user = User(publicAddress: torusLoginResponse.torusKey.finalKeyData.evmAddress, privateKey: torusLoginResponse.torusKey.finalKeyData.privKey, userInfo: torusLoginResponse.singleVerifierResponse.userInfo) + } } catch { print(error) } @@ -91,17 +56,17 @@ extension ViewModel { } func facebookLogin() { - let sub = SubVerifierDetails(typeOfLogin: .facebook, verifier: "facebook-shubs", clientId: "659561074900150", redirectURL: "https://scripts.toruswallet.io/redirect.html") - - let options = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "CLIENT ID") - Task { do { - let customAuth = try CustomAuth(config: options) + let sub = SingleLoginParams(typeOfLogin: .facebook, verifier: "w3a-facebook-demo", clientId: "342380202252650") - let keyDetails = try await customAuth.triggerLogin(args: sub) + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") - user = User(publicAddress: keyDetails.torusKey.finalKeyData.evmAddress, privateKey: keyDetails.torusKey.finalKeyData.privKey, userInfo: keyDetails.singleVerifierResponse.userInfo) + let customAuth = try CustomAuth(config: customAuthArgs) + let torusLoginResponse = try await customAuth.triggerLogin(args: sub) + DispatchQueue.main.async { + self.user = User(publicAddress: torusLoginResponse.torusKey.finalKeyData.evmAddress, privateKey: torusLoginResponse.torusKey.finalKeyData.privKey, userInfo: torusLoginResponse.singleVerifierResponse.userInfo) + } } catch { print(error) } @@ -109,35 +74,15 @@ extension ViewModel { } func twitchLogin() { - let sub = SubVerifierDetails(typeOfLogin: .twitch, verifier: "twitch-shubs", clientId: "p560duf74b2bidzqu6uo0b3ot7qaao", redirectURL: "https://scripts.toruswallet.io/redirect.html") - - let options = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "CLIENT ID") - Task { do { - let customAuth = try CustomAuth(config: options) - - let keyDetails = try await customAuth.triggerLogin(args: sub) - - user = User(publicAddress: keyDetails.torusKey.finalKeyData.evmAddress, privateKey: keyDetails.torusKey.finalKeyData.privKey, userInfo: keyDetails.singleVerifierResponse.userInfo) - } catch { - print(error) - } - } - } - - func twitterLogin() { - let sub = SubVerifierDetails(typeOfLogin: .twitter, verifier: "torus-auth0-twitter-lrc", clientId: "A7H8kkcmyFRlusJQ9dZiqBLraG2yWIsO", redirectURL: "https://scripts.toruswallet.io/redirect.html") - - let options = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "CLIENT ID") - - Task { - do { - let customAuth = try CustomAuth(config: options) - - let keyDetails = try await customAuth.triggerLogin(args: sub) - - user = User(publicAddress: keyDetails.torusKey.finalKeyData.evmAddress, privateKey: keyDetails.torusKey.finalKeyData.privKey, userInfo: keyDetails.singleVerifierResponse.userInfo) + let sub = SingleLoginParams(typeOfLogin: .twitch, verifier: "w3a-twitch-demo", clientId: "3k7e70gowvxjaxg71hjnc8h8ih3bpf") + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + let customAuth = try CustomAuth(config: customAuthArgs) + let torusLoginResponse = try await customAuth.triggerLogin(args: sub) + DispatchQueue.main.async { + self.user = User(publicAddress: torusLoginResponse.torusKey.finalKeyData.evmAddress, privateKey: torusLoginResponse.torusKey.finalKeyData.privKey, userInfo: torusLoginResponse.singleVerifierResponse.userInfo) + } } catch { print(error) } @@ -145,35 +90,15 @@ extension ViewModel { } func githubLogin() { - let sub = SubVerifierDetails(typeOfLogin: .github, verifier: "torus-auth0-github-lrc", clientId: "PC2a4tfNRvXbT48t89J5am0oFM21Nxff", redirectURL: "https://scripts.toruswallet.io/redirect.html") - - let options = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "CLIENT ID") - Task { do { - let customAuth = try CustomAuth(config: options) - - let keyDetails = try await customAuth.triggerLogin(args: sub) - - user = User(publicAddress: keyDetails.torusKey.finalKeyData.evmAddress, privateKey: keyDetails.torusKey.finalKeyData.privKey, userInfo: keyDetails.singleVerifierResponse.userInfo) - } catch { - print(error) - } - } - } - - func linkedinLogin() { - let sub = SubVerifierDetails(typeOfLogin: .linkedin, verifier: "torus-auth0-linkedin-lrc", clientId: "59YxSgx79Vl3Wi7tQUBqQTRTxWroTuoc", redirectURL: "https://scripts.toruswallet.io/redirect.html") - - let options = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "CLIENT ID") - - Task { - do { - let customAuth = try CustomAuth(config: options) - - let keyDetails = try await customAuth.triggerLogin(args: sub) - - user = User(publicAddress: keyDetails.torusKey.finalKeyData.evmAddress, privateKey: keyDetails.torusKey.finalKeyData.privKey, userInfo: keyDetails.singleVerifierResponse.userInfo) + let sub = SingleLoginParams(typeOfLogin: .github, verifier: "w3a-auth0-demo", clientId: "hUVVf4SEsZT7syOiL0gLU9hFEtm2gQ6O", jwtParams: Auth0ClientOptions(connection: "github", domain: "web3auth.au.auth0.com", verifierIdField: "sub")) + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + let customAuth = try CustomAuth(config: customAuthArgs) + let torusLoginResponse = try await customAuth.triggerLogin(args: sub) + DispatchQueue.main.async { + self.user = User(publicAddress: torusLoginResponse.torusKey.finalKeyData.evmAddress, privateKey: torusLoginResponse.torusKey.finalKeyData.privKey, userInfo: torusLoginResponse.singleVerifierResponse.userInfo) + } } catch { print(error) } @@ -181,65 +106,38 @@ extension ViewModel { } func appleLogin() { - let sub = SubVerifierDetails(typeOfLogin: .apple, verifier: "torus-auth0-apple-lrc", clientId: "m1Q0gvDfOyZsJCZ3cucSQEe9XMvl9d9L", redirectURL: "https://scripts.toruswallet.io/redirect.html") - - let options = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "CLIENT ID") - Task { do { - let customAuth = try CustomAuth(config: options) + let sub = SingleLoginParams(typeOfLogin: .apple, verifier: "w3a-auth0-demo", clientId: "hUVVf4SEsZT7syOiL0gLU9hFEtm2gQ6O", jwtParams: Auth0ClientOptions(connection: "apple", domain: "web3auth.au.auth0.com")) + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") - let keyDetails = try await customAuth.triggerLogin(args: sub) + let customAuth = try CustomAuth(config: customAuthArgs) + let torusLoginResponse = try await customAuth.triggerLogin(args: sub) - user = User(publicAddress: keyDetails.torusKey.finalKeyData.evmAddress, privateKey: keyDetails.torusKey.finalKeyData.privKey, userInfo: keyDetails.singleVerifierResponse.userInfo) + DispatchQueue.main.async { + self.user = User(publicAddress: torusLoginResponse.torusKey.finalKeyData.evmAddress, privateKey: torusLoginResponse.torusKey.finalKeyData.privKey, userInfo: torusLoginResponse.singleVerifierResponse.userInfo) + } } catch { print(error) } } } - func weiboLogin() { - let sub = SubVerifierDetails( - typeOfLogin: .weibo, - verifier: "torus-auth0-weibo-lrc", - clientId: "dhFGlWQMoACOI5oS5A1jFglp772OAWr1", - redirectURL: "tdsdk://tdsdk/oauthCallback") - - let options = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "CLIENT ID") - - Task { - do { - let customAuth = try CustomAuth(config: options) - - let keyDetails = try await customAuth.triggerLogin(args: sub) - - user = User(publicAddress: keyDetails.torusKey.finalKeyData.evmAddress, privateKey: keyDetails.torusKey.finalKeyData.privKey, userInfo: keyDetails.singleVerifierResponse.userInfo) - } catch { - print(error) - } - } - } - func emailPasswordLogin() { - let sub = SubVerifierDetails( - typeOfLogin: .email_password, - verifier: "torus-auth0-email-password", - clientId: "sqKRBVSdwa4WLkaq419U7Bamlh5vK1H7", - redirectURL: "tdsdk://tdsdk/oauthCallback", - jwtParams: Auth0ClientOptions( - connection: "Username-Password-Authentication", - domain: "torus-test.auth0.com", - verifierIdField: "name")) - - let options = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") - Task { do { - let customAuth = try CustomAuth(config: options) - - let keyDetails = try await customAuth.triggerLogin(args: sub) - - user = User(publicAddress: keyDetails.torusKey.finalKeyData.evmAddress, privateKey: keyDetails.torusKey.finalKeyData.privKey, userInfo: keyDetails.singleVerifierResponse.userInfo) + let sub = SingleLoginParams(typeOfLogin: .email_password, + verifier: "torus-auth0-email-password", clientId: "sqKRBVSdwa4WLkaq419U7Bamlh5vK1H7", + jwtParams: Auth0ClientOptions( + connection: "Username-Password-Authentication", + domain: "torus-test.auth0.com", + verifierIdField: "name")) + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + let customAuth = try CustomAuth(config: customAuthArgs) + let torusLoginResponse = try await customAuth.triggerLogin(args: sub) + DispatchQueue.main.async { + self.user = User(publicAddress: torusLoginResponse.torusKey.finalKeyData.evmAddress, privateKey: torusLoginResponse.torusKey.finalKeyData.privKey, userInfo: torusLoginResponse.singleVerifierResponse.userInfo) + } } catch { print(error) } From 9190676f623e3627c410a2df61606365210cf8b6 Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Sun, 6 Oct 2024 01:17:20 +0200 Subject: [PATCH 20/24] refactor: update to latest torusutils --- CustomAuth.podspec | 4 ++-- Package.resolved | 10 +++++----- Package.swift | 2 +- Sources/CustomAuth/CustomAuthArgs.swift | 4 ++-- .../Handlers/Protocol/CreateHandlerParams.swift | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/CustomAuth.podspec b/CustomAuth.podspec index 821ce54..f951509 100644 --- a/CustomAuth.podspec +++ b/CustomAuth.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = "CustomAuth" - spec.version = "11.0.0" + spec.version = "12.0.0" spec.platform = :ios, "13.0" spec.summary = "Swift SDK that allows applications to directly interact with the Torus Network, similar to how Torus Wallet does." spec.homepage = "https://github.com/torusresearch/customauth-swift-sdk" @@ -10,6 +10,6 @@ Pod::Spec.new do |spec| spec.module_name = "CustomAuth" spec.source = { :git => "https://github.com/torusresearch/customauth-swift-sdk.git", :tag => spec.version } spec.source_files = "Sources/CustomAuth/*.{swift}","Sources/CustomAuth/**/*.{swift}" - spec.dependency 'Torus-utils', '~> 9.0.1' + spec.dependency 'Torus-utils', '~> 10.0.0' spec.dependency 'JWTDecode', '~> 3.1.0' end diff --git a/Package.resolved b/Package.resolved index 8997069..f326077 100644 --- a/Package.resolved +++ b/Package.resolved @@ -21,10 +21,10 @@ { "identity" : "fetch-node-details-swift", "kind" : "remoteSourceControl", - "location" : "https://github.com/torusresearch/fetch-node-details-swift.git", + "location" : "https://github.com/torusresearch/fetch-node-details-swift", "state" : { - "revision" : "4bd96c33ba8d02d9e27190c5c7cedf09cfdfd656", - "version" : "6.0.3" + "branch" : "encapsulate_torusnetwork", + "revision" : "2fcd108ea89a48f092a955017977a299129d20c7" } }, { @@ -59,8 +59,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/torusresearch/torus-utils-swift.git", "state" : { - "revision" : "eda55b8537a600e657d19d4c452c0a36f217883c", - "version" : "9.0.1" + "branch" : "encapsulate_torusnetwork", + "revision" : "ef50d543ee773ebcde6ac386ac831e9ccaceef8f" } } ], diff --git a/Package.swift b/Package.swift index 1269605..44c1036 100644 --- a/Package.swift +++ b/Package.swift @@ -14,7 +14,7 @@ let package = Package( targets: ["CustomAuth"]) ], dependencies: [ - .package(url: "https://github.com/torusresearch/torus-utils-swift.git", from: "9.0.1"), + .package(url: "https://github.com/torusresearch/torus-utils-swift.git", branch: "encapsulate_torusnetwork"), .package(url: "https://github.com/auth0/JWTDecode.swift.git", from: "3.1.0"), // NB: jwt-kit may only be a test dependency or it will break cocoapods support .package(url: "https://github.com/vapor/jwt-kit.git", from: "4.13.0"), diff --git a/Sources/CustomAuth/CustomAuthArgs.swift b/Sources/CustomAuth/CustomAuthArgs.swift index 310b054..2128b94 100644 --- a/Sources/CustomAuth/CustomAuthArgs.swift +++ b/Sources/CustomAuth/CustomAuthArgs.swift @@ -4,7 +4,7 @@ import Foundation public class CustomAuthArgs { public let urlScheme: String public let metadataUrl: String - public let network: TorusNetwork + public let network: Web3AuthNetwork public let enableLogging: Bool public let enableOneKey: Bool public let apiKey: String @@ -15,7 +15,7 @@ public class CustomAuthArgs { public let useDkg: Bool // TODO: Implement usage of this public init(urlScheme: String, - network: TorusNetwork, + network: Web3AuthNetwork, metadataUrl: String = "https://metadata.tor.us", enableLogging: Bool = false, apiKey: String = "torus-default", diff --git a/Sources/CustomAuth/Handlers/Protocol/CreateHandlerParams.swift b/Sources/CustomAuth/Handlers/Protocol/CreateHandlerParams.swift index b685675..2238657 100644 --- a/Sources/CustomAuth/Handlers/Protocol/CreateHandlerParams.swift +++ b/Sources/CustomAuth/Handlers/Protocol/CreateHandlerParams.swift @@ -9,10 +9,10 @@ internal class CreateHandlerParams { public let redirectURL: String public let jwtParams: Auth0ClientOptions? public let customState: TorusGenericContainer? - public let web3AuthNetwork: TorusNetwork + public let web3AuthNetwork: Web3AuthNetwork public let web3AuthClientId: String - public init(typeOfLogin: LoginType, verifier: String, clientId: String, urlScheme: String, redirectURL: String, jwtParams: Auth0ClientOptions? = nil, customState: TorusGenericContainer? = nil, web3AuthNetwork: TorusNetwork, web3AuthClientId: String) { + public init(typeOfLogin: LoginType, verifier: String, clientId: String, urlScheme: String, redirectURL: String, jwtParams: Auth0ClientOptions? = nil, customState: TorusGenericContainer? = nil, web3AuthNetwork: Web3AuthNetwork, web3AuthClientId: String) { self.typeOfLogin = typeOfLogin self.verifier = verifier self.clientId = clientId From 87bc95ff920865474108d6c6545a07938b2aa25d Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Wed, 9 Oct 2024 06:28:19 +0200 Subject: [PATCH 21/24] update error description for .passwordless --- Sources/CustomAuth/Handlers/HandlerFactory.swift | 2 +- Sources/CustomAuth/Helpers/Error.swift | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Sources/CustomAuth/Handlers/HandlerFactory.swift b/Sources/CustomAuth/Handlers/HandlerFactory.swift index 824757e..68322cf 100644 --- a/Sources/CustomAuth/Handlers/HandlerFactory.swift +++ b/Sources/CustomAuth/Handlers/HandlerFactory.swift @@ -36,7 +36,7 @@ internal class HandlerFactory { case .email_password: break case .passwordless: if domain == nil || hint == nil { - throw CASDKError.invalidAuth0Options + throw CASDKError.unsupportedLoginType } throw CASDKError.invalidAuth0Options case .email_passwordless: diff --git a/Sources/CustomAuth/Helpers/Error.swift b/Sources/CustomAuth/Helpers/Error.swift index 2af425d..be82494 100644 --- a/Sources/CustomAuth/Helpers/Error.swift +++ b/Sources/CustomAuth/Helpers/Error.swift @@ -10,6 +10,7 @@ public enum CASDKError: Error { case invalidClientID case invalidMethod(msg: String) case redirectParamsError(msg: String) + case unsupportedLoginType public var errorDescription: String { switch self { @@ -35,6 +36,8 @@ public enum CASDKError: Error { return "invalid verifier" case .invalidClientID: return "invalid client ID" + case .unsupportedLoginType: + return "Unsupported. Please use a different type of login" } } } From 41ec6b1c0d7c5d84834a5170263209d76cfcb56e Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Wed, 9 Oct 2024 06:31:18 +0200 Subject: [PATCH 22/24] fix --- Sources/CustomAuth/Handlers/HandlerFactory.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/CustomAuth/Handlers/HandlerFactory.swift b/Sources/CustomAuth/Handlers/HandlerFactory.swift index 68322cf..49bcc12 100644 --- a/Sources/CustomAuth/Handlers/HandlerFactory.swift +++ b/Sources/CustomAuth/Handlers/HandlerFactory.swift @@ -36,9 +36,9 @@ internal class HandlerFactory { case .email_password: break case .passwordless: if domain == nil || hint == nil { - throw CASDKError.unsupportedLoginType + throw CASDKError.invalidAuth0Options } - throw CASDKError.invalidAuth0Options + throw CASDKError.unsupportedLoginType case .email_passwordless: if hint == nil { throw CASDKError.invalidAuth0Options From 8dab48a110a537f64aead084d46d8e1179a3a881 Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Thu, 24 Oct 2024 09:40:30 +0200 Subject: [PATCH 23/24] update swift example --- CustomAuth.podspec | 4 ++-- .../xcshareddata/swiftpm/Package.resolved | 16 +++++++------- .../CustomAuthDemo/ContentView.swift | 22 +++++++++---------- Package.resolved | 16 +++++++------- Package.swift | 6 ++--- .../Common/LoginParams/LoginType.swift | 1 - .../CustomAuth/Handlers/HandlerFactory.swift | 5 ----- Sources/CustomAuth/Helpers/Common.swift | 2 -- cocoapods/cptest/ViewModel.swift | 2 +- 9 files changed, 33 insertions(+), 41 deletions(-) diff --git a/CustomAuth.podspec b/CustomAuth.podspec index f951509..31c7e30 100644 --- a/CustomAuth.podspec +++ b/CustomAuth.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = "CustomAuth" - spec.version = "12.0.0" + spec.version = "11.0.0" spec.platform = :ios, "13.0" spec.summary = "Swift SDK that allows applications to directly interact with the Torus Network, similar to how Torus Wallet does." spec.homepage = "https://github.com/torusresearch/customauth-swift-sdk" @@ -11,5 +11,5 @@ Pod::Spec.new do |spec| spec.source = { :git => "https://github.com/torusresearch/customauth-swift-sdk.git", :tag => spec.version } spec.source_files = "Sources/CustomAuth/*.{swift}","Sources/CustomAuth/**/*.{swift}" spec.dependency 'Torus-utils', '~> 10.0.0' - spec.dependency 'JWTDecode', '~> 3.1.0' + spec.dependency 'JWTDecode', '~> 3.2.0' end diff --git a/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 7c37236..e0337bf 100644 --- a/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/CustomAuthDemo/CustomAuthDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -14,8 +14,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/tkey/curvelib.swift", "state" : { - "revision" : "9f88bd5e56d1df443a908f7a7e81ae4f4d9170ea", - "version" : "1.0.1" + "revision" : "432bf1abe7ff505fc2ac9fcf697341ff5b2dc6d0", + "version" : "2.0.0" } }, { @@ -23,8 +23,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/torusresearch/fetch-node-details-swift", "state" : { - "revision" : "4bd96c33ba8d02d9e27190c5c7cedf09cfdfd656", - "version" : "6.0.3" + "revision" : "52fb5efaa94e0fe3775913ab00964bcb51601c2a", + "version" : "8.0.0" } }, { @@ -41,8 +41,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/auth0/JWTDecode.swift.git", "state" : { - "revision" : "58af7278797871e460d79496621b3e5366b865b2", - "version" : "3.1.0" + "revision" : "1e153ef009969543191970c66b7c60163c0b4a65", + "version" : "3.2.0" } }, { @@ -59,8 +59,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/torusresearch/torus-utils-swift.git", "state" : { - "revision" : "eda55b8537a600e657d19d4c452c0a36f217883c", - "version" : "9.0.1" + "revision" : "baa822fc67bdb208ed1a2dc5b3c10485cfca15df", + "version" : "10.0.0" } } ], diff --git a/CustomAuthDemo/CustomAuthDemo/ContentView.swift b/CustomAuthDemo/CustomAuthDemo/ContentView.swift index fc72ba5..d4c514e 100644 --- a/CustomAuthDemo/CustomAuthDemo/ContentView.swift +++ b/CustomAuthDemo/CustomAuthDemo/ContentView.swift @@ -11,7 +11,7 @@ struct ContentView: View { do { let sub = SingleLoginParams(typeOfLogin: .google, verifier: "w3a-google-demo", clientId: "519228911939-cri01h55lsjbsia1k7ll6qpalrus75ps.apps.googleusercontent.com") - let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .SAPPHIRE_MAINNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") let customAuth = try CustomAuth(config: customAuthArgs) let torusLoginResponse = try await customAuth.triggerLogin(args: sub) let encoded = try JSONEncoder().encode(torusLoginResponse) @@ -29,7 +29,7 @@ struct ContentView: View { do { let sub = SingleLoginParams(typeOfLogin: .discord, verifier: "w3a-discord-demo", clientId: "1151006428610433095") - let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .SAPPHIRE_MAINNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") let customAuth = try CustomAuth(config: customAuthArgs) let torusLoginResponse = try await customAuth.triggerLogin(args: sub) @@ -48,7 +48,7 @@ struct ContentView: View { do { let sub = SingleLoginParams(typeOfLogin: .facebook, verifier: "w3a-facebook-demo", clientId: "342380202252650") - let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .SAPPHIRE_MAINNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") let customAuth = try CustomAuth(config: customAuthArgs) let torusLoginResponse = try await customAuth.triggerLogin(args: sub) @@ -66,7 +66,7 @@ struct ContentView: View { Task { do { let sub = SingleLoginParams(typeOfLogin: .twitch, verifier: "w3a-twitch-demo", clientId: "3k7e70gowvxjaxg71hjnc8h8ih3bpf") - let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .SAPPHIRE_MAINNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") let customAuth = try CustomAuth(config: customAuthArgs) let torusLoginResponse = try await customAuth.triggerLogin(args: sub) let encoded = try JSONEncoder().encode(torusLoginResponse) @@ -83,7 +83,7 @@ struct ContentView: View { Task { do { let sub = SingleLoginParams(typeOfLogin: .apple, verifier: "w3a-auth0-demo", clientId: "hUVVf4SEsZT7syOiL0gLU9hFEtm2gQ6O", jwtParams: Auth0ClientOptions(connection: "apple", domain: "web3auth.au.auth0.com")) - let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .SAPPHIRE_MAINNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") let customAuth = try CustomAuth(config: customAuthArgs) let torusLoginResponse = try await customAuth.triggerLogin(args: sub) @@ -101,7 +101,7 @@ struct ContentView: View { Task { do { let sub = SingleLoginParams(typeOfLogin: .github, verifier: "w3a-auth0-demo", clientId: "hUVVf4SEsZT7syOiL0gLU9hFEtm2gQ6O", jwtParams: Auth0ClientOptions(connection: "github", domain: "web3auth.au.auth0.com", verifierIdField: "sub")) - let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .SAPPHIRE_MAINNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") let customAuth = try CustomAuth(config: customAuthArgs) let torusLoginResponse = try await customAuth.triggerLogin(args: sub) let encoded = try JSONEncoder().encode(torusLoginResponse) @@ -123,7 +123,7 @@ struct ContentView: View { connection: "Username-Password-Authentication", domain: "torus-test.auth0.com", verifierIdField: "name")) - let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .TESTNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") let customAuth = try CustomAuth(config: customAuthArgs) let torusLoginResponse = try await customAuth.triggerLogin(args: sub) let encoded = try JSONEncoder().encode(torusLoginResponse) @@ -153,7 +153,7 @@ struct ContentView: View { let sub = SingleLoginParams(typeOfLogin: .email_passwordless, verifier: "torus-auth0-email-passwordless-lrc", clientId: "P7PJuBCXIHP41lcyty0NEb7Lgf7Zme8Q", jwtParams: Auth0ClientOptions(verifierIdField: "name", login_hint: inputDetail, flow_type: .link)) - let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .TESTNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") let customAuth = try CustomAuth(config: customAuthArgs) let torusLoginResponse = try await customAuth.triggerLogin(args: sub) let encoded = try JSONEncoder().encode(torusLoginResponse) @@ -173,7 +173,7 @@ struct ContentView: View { let sub = SingleLoginParams(typeOfLogin: .sms_passwordless, verifier: "torus-sms-passwordless-lrc", clientId: "P7PJuBCXIHP41lcyty0NEb7Lgf7Zme8Q", jwtParams: Auth0ClientOptions(login_hint: inputDetail, flow_type: .code)) - let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .TESTNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") let customAuth = try CustomAuth(config: customAuthArgs) let torusLoginResponse = try await customAuth.triggerLogin(args: sub) let encoded = try JSONEncoder().encode(torusLoginResponse) @@ -196,7 +196,7 @@ struct ContentView: View { do { let aggregateLoginParams = AggregateLoginParams(aggregateVerifierType: AggregateVerifierType.single_id_verifier, verifierIdentifier: "aggregate-sapphire", subVerifierDetailsArray: [SingleLoginParams(typeOfLogin: .google, verifier: "w3a-google", clientId: "519228911939-cri01h55lsjbsia1k7ll6qpalrus75ps.apps.googleusercontent.com")]) - let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .SAPPHIRE_MAINNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") let customAuth = try CustomAuth(config: customAuthArgs) let torusLoginResponse = try await customAuth.triggerAggregateLogin(args: aggregateLoginParams) let encoded = try JSONEncoder().encode(torusLoginResponse) @@ -215,7 +215,7 @@ struct ContentView: View { let subVerifierDetailsArray = SingleLoginParams(typeOfLogin: .github, verifier: "w3a-a0-github", clientId: "hiLqaop0amgzCC0AXo4w0rrG9abuJTdu", jwtParams: OAuthClientOptions(domain: "web3auth.au.auth0.com", verifierIdField: "email")) let aggregateLoginParams = AggregateLoginParams(aggregateVerifierType: AggregateVerifierType.single_id_verifier, verifierIdentifier: "aggregate-sapphire", subVerifierDetailsArray: [subVerifierDetailsArray]) - let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .SAPPHIRE_MAINNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") let customAuth = try CustomAuth(config: customAuthArgs) let torusLoginResponse = try await customAuth.triggerAggregateLogin(args: aggregateLoginParams) let encoded = try JSONEncoder().encode(torusLoginResponse) diff --git a/Package.resolved b/Package.resolved index f326077..dec33db 100644 --- a/Package.resolved +++ b/Package.resolved @@ -14,8 +14,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/tkey/curvelib.swift", "state" : { - "revision" : "9f88bd5e56d1df443a908f7a7e81ae4f4d9170ea", - "version" : "1.0.1" + "revision" : "432bf1abe7ff505fc2ac9fcf697341ff5b2dc6d0", + "version" : "2.0.0" } }, { @@ -23,8 +23,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/torusresearch/fetch-node-details-swift", "state" : { - "branch" : "encapsulate_torusnetwork", - "revision" : "2fcd108ea89a48f092a955017977a299129d20c7" + "revision" : "52fb5efaa94e0fe3775913ab00964bcb51601c2a", + "version" : "8.0.0" } }, { @@ -41,8 +41,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/auth0/JWTDecode.swift.git", "state" : { - "revision" : "58af7278797871e460d79496621b3e5366b865b2", - "version" : "3.1.0" + "revision" : "1e153ef009969543191970c66b7c60163c0b4a65", + "version" : "3.2.0" } }, { @@ -59,8 +59,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/torusresearch/torus-utils-swift.git", "state" : { - "branch" : "encapsulate_torusnetwork", - "revision" : "ef50d543ee773ebcde6ac386ac831e9ccaceef8f" + "revision" : "baa822fc67bdb208ed1a2dc5b3c10485cfca15df", + "version" : "10.0.0" } } ], diff --git a/Package.swift b/Package.swift index 44c1036..779cb64 100644 --- a/Package.swift +++ b/Package.swift @@ -6,7 +6,7 @@ import PackageDescription let package = Package( name: "CustomAuth", platforms: [ - .iOS(.v13), .macOS(.v11) + .iOS(.v14), .macOS(.v11) ], products: [ .library( @@ -14,8 +14,8 @@ let package = Package( targets: ["CustomAuth"]) ], dependencies: [ - .package(url: "https://github.com/torusresearch/torus-utils-swift.git", branch: "encapsulate_torusnetwork"), - .package(url: "https://github.com/auth0/JWTDecode.swift.git", from: "3.1.0"), + .package(url: "https://github.com/torusresearch/torus-utils-swift.git", from: "10.0.0"), + .package(url: "https://github.com/auth0/JWTDecode.swift.git", from: "3.2.0"), // NB: jwt-kit may only be a test dependency or it will break cocoapods support .package(url: "https://github.com/vapor/jwt-kit.git", from: "4.13.0"), ], diff --git a/Sources/CustomAuth/Common/LoginParams/LoginType.swift b/Sources/CustomAuth/Common/LoginParams/LoginType.swift index 4463237..115b375 100644 --- a/Sources/CustomAuth/Common/LoginParams/LoginType.swift +++ b/Sources/CustomAuth/Common/LoginParams/LoginType.swift @@ -13,7 +13,6 @@ public enum LoginType: String, Equatable, Hashable, Codable { case weibo case line case email_password - case passwordless case email_passwordless case sms_passwordless case jwt diff --git a/Sources/CustomAuth/Handlers/HandlerFactory.swift b/Sources/CustomAuth/Handlers/HandlerFactory.swift index 49bcc12..f0f5a47 100644 --- a/Sources/CustomAuth/Handlers/HandlerFactory.swift +++ b/Sources/CustomAuth/Handlers/HandlerFactory.swift @@ -34,11 +34,6 @@ internal class HandlerFactory { case .weibo: break case .line: break case .email_password: break - case .passwordless: - if domain == nil || hint == nil { - throw CASDKError.invalidAuth0Options - } - throw CASDKError.unsupportedLoginType case .email_passwordless: if hint == nil { throw CASDKError.invalidAuth0Options diff --git a/Sources/CustomAuth/Helpers/Common.swift b/Sources/CustomAuth/Helpers/Common.swift index ed32df2..cf54c44 100644 --- a/Sources/CustomAuth/Helpers/Common.swift +++ b/Sources/CustomAuth/Helpers/Common.swift @@ -14,7 +14,6 @@ internal func loginToConnection(loginType: LoginType) -> String { case .weibo: break case .line: break case .email_password: return "Username-Password-Authentication" - case .passwordless: return "email" case .email_passwordless: return "email" case .sms_passwordless: return "sms" case .jwt: break @@ -43,7 +42,6 @@ internal func getVerifierId( } switch typeOfLogin { - case .passwordless: return name case .email_password: return name case .email_passwordless: return name case .sms_passwordless: return caseSensitiveField(field: name, isCaseSensitive: isVerifierIdCaseSensitive) diff --git a/cocoapods/cptest/ViewModel.swift b/cocoapods/cptest/ViewModel.swift index c7665d6..5ebe0cb 100644 --- a/cocoapods/cptest/ViewModel.swift +++ b/cocoapods/cptest/ViewModel.swift @@ -132,7 +132,7 @@ extension ViewModel { connection: "Username-Password-Authentication", domain: "torus-test.auth0.com", verifierIdField: "name")) - let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .legacy(.TESTNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .TESTNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") let customAuth = try CustomAuth(config: customAuthArgs) let torusLoginResponse = try await customAuth.triggerLogin(args: sub) DispatchQueue.main.async { From 8e6dd98a6be549f197c00891b33d3f5d07ec7d1d Mon Sep 17 00:00:00 2001 From: metalurgical <97008724+metalurgical@users.noreply.github.com> Date: Thu, 24 Oct 2024 09:54:57 +0200 Subject: [PATCH 24/24] update cocoapods example --- CustomAuth.podspec | 2 +- cocoapods/Podfile | 4 +-- cocoapods/Podfile.lock | 32 +++++++++++----------- cocoapods/cptest.xcodeproj/project.pbxproj | 4 +-- cocoapods/cptest/ViewModel.swift | 12 ++++---- 5 files changed, 27 insertions(+), 27 deletions(-) diff --git a/CustomAuth.podspec b/CustomAuth.podspec index 31c7e30..c2ebec7 100644 --- a/CustomAuth.podspec +++ b/CustomAuth.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |spec| spec.name = "CustomAuth" spec.version = "11.0.0" - spec.platform = :ios, "13.0" + spec.platform = :ios, "14.0" spec.summary = "Swift SDK that allows applications to directly interact with the Torus Network, similar to how Torus Wallet does." spec.homepage = "https://github.com/torusresearch/customauth-swift-sdk" spec.license = { :type => 'BSD', :file => 'License.md' } diff --git a/cocoapods/Podfile b/cocoapods/Podfile index 3388940..af1ad6d 100644 --- a/cocoapods/Podfile +++ b/cocoapods/Podfile @@ -4,7 +4,7 @@ source 'https://github.com/CocoaPods/Specs.git' target 'cptest' do use_frameworks! - pod 'Torus-utils', '~> 9.0.0' + pod 'Torus-utils', '~> 10.0.0' pod 'CustomAuth', :path=>"../" # Pods for cptest @@ -12,7 +12,7 @@ target 'cptest' do installer_representation.pods_project.targets.each do |target| target.build_configurations.each do |config| config.build_settings['ONLY_ACTIVE_ARCH'] = 'NO' - config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0' + config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '14.0' end end end diff --git a/cocoapods/Podfile.lock b/cocoapods/Podfile.lock index 9ff44a6..c02b47e 100644 --- a/cocoapods/Podfile.lock +++ b/cocoapods/Podfile.lock @@ -1,19 +1,19 @@ PODS: - BigInt (5.2.0) - - curvelib.swift (1.0.1) + - curvelib.swift (2.0.0) - CustomAuth (11.0.0): - - JWTDecode (~> 3.1.0) - - Torus-utils (~> 9.0.0) - - JWTDecode (3.1.0) - - Torus-fetchNodeDetails (6.0.3): + - JWTDecode (~> 3.2.0) + - Torus-utils (~> 10.0.0) + - JWTDecode (3.2.0) + - Torus-fetchNodeDetails (8.0.0): - BigInt (~> 5.2.0) - - Torus-utils (9.0.0): - - curvelib.swift (~> 1.0.1) - - Torus-fetchNodeDetails (~> 6.0.3) + - Torus-utils (10.0.0): + - curvelib.swift (~> 2.0.0) + - Torus-fetchNodeDetails (~> 8.0.0) DEPENDENCIES: - CustomAuth (from `../`) - - Torus-utils (~> 9.0.0) + - Torus-utils (~> 10.0.0) SPEC REPOS: https://github.com/CocoaPods/Specs.git: @@ -29,12 +29,12 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: BigInt: f668a80089607f521586bbe29513d708491ef2f7 - curvelib.swift: d0746ae82bee34016c06da3567a97e493b3c979f - CustomAuth: 03df324125a03626232ae742175aeda26a065e66 - JWTDecode: 3eaab1e06b6f4dcbdd6716aff09ba4c2104ca8b7 - Torus-fetchNodeDetails: 6c349f47cbca36a4b3f276fe26d03c1b39b20949 - Torus-utils: 0f993fffd66a66a0423092c9ddea2cbff4d298df + curvelib.swift: b9223e5cac801effed8a5fe8968e952b3fe427a5 + CustomAuth: 3d9d95477f35d9560bdd595283f2103bce44538c + JWTDecode: 7dae24cb9bf9b608eae61e5081029ec169bb5527 + Torus-fetchNodeDetails: 2a5fbb222ec28af4128d64e4c2d520c7db456b78 + Torus-utils: 4a1db3d9c1aa221df312ffa7ec154e7e4719850a -PODFILE CHECKSUM: 3f0652a4c9819c7b293e6a1f91fd5a27a70c0533 +PODFILE CHECKSUM: f4a1d2e407b10056607aa36892f54a3affc05ffa -COCOAPODS: 1.13.0 +COCOAPODS: 1.15.2 diff --git a/cocoapods/cptest.xcodeproj/project.pbxproj b/cocoapods/cptest.xcodeproj/project.pbxproj index cf50eb7..ac107c2 100644 --- a/cocoapods/cptest.xcodeproj/project.pbxproj +++ b/cocoapods/cptest.xcodeproj/project.pbxproj @@ -361,7 +361,7 @@ ENABLE_PREVIEWS = YES; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; INFOPLIST_FILE = cptest/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -384,7 +384,7 @@ ENABLE_PREVIEWS = YES; "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; INFOPLIST_FILE = cptest/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/cocoapods/cptest/ViewModel.swift b/cocoapods/cptest/ViewModel.swift index 5ebe0cb..dd24a72 100644 --- a/cocoapods/cptest/ViewModel.swift +++ b/cocoapods/cptest/ViewModel.swift @@ -23,7 +23,7 @@ extension ViewModel { do { let sub = SingleLoginParams(typeOfLogin: .google, verifier: "w3a-google-demo", clientId: "519228911939-cri01h55lsjbsia1k7ll6qpalrus75ps.apps.googleusercontent.com") - let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .SAPPHIRE_MAINNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") let customAuth = try CustomAuth(config: customAuthArgs) let torusLoginResponse = try await customAuth.triggerLogin(args: sub) @@ -41,7 +41,7 @@ extension ViewModel { do { let sub = SingleLoginParams(typeOfLogin: .discord, verifier: "w3a-discord-demo", clientId: "1151006428610433095") - let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .SAPPHIRE_MAINNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") let customAuth = try CustomAuth(config: customAuthArgs) let torusLoginResponse = try await customAuth.triggerLogin(args: sub) @@ -60,7 +60,7 @@ extension ViewModel { do { let sub = SingleLoginParams(typeOfLogin: .facebook, verifier: "w3a-facebook-demo", clientId: "342380202252650") - let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .SAPPHIRE_MAINNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") let customAuth = try CustomAuth(config: customAuthArgs) let torusLoginResponse = try await customAuth.triggerLogin(args: sub) @@ -77,7 +77,7 @@ extension ViewModel { Task { do { let sub = SingleLoginParams(typeOfLogin: .twitch, verifier: "w3a-twitch-demo", clientId: "3k7e70gowvxjaxg71hjnc8h8ih3bpf") - let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .SAPPHIRE_MAINNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") let customAuth = try CustomAuth(config: customAuthArgs) let torusLoginResponse = try await customAuth.triggerLogin(args: sub) DispatchQueue.main.async { @@ -93,7 +93,7 @@ extension ViewModel { Task { do { let sub = SingleLoginParams(typeOfLogin: .github, verifier: "w3a-auth0-demo", clientId: "hUVVf4SEsZT7syOiL0gLU9hFEtm2gQ6O", jwtParams: Auth0ClientOptions(connection: "github", domain: "web3auth.au.auth0.com", verifierIdField: "sub")) - let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .SAPPHIRE_MAINNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") let customAuth = try CustomAuth(config: customAuthArgs) let torusLoginResponse = try await customAuth.triggerLogin(args: sub) DispatchQueue.main.async { @@ -109,7 +109,7 @@ extension ViewModel { Task { do { let sub = SingleLoginParams(typeOfLogin: .apple, verifier: "w3a-auth0-demo", clientId: "hUVVf4SEsZT7syOiL0gLU9hFEtm2gQ6O", jwtParams: Auth0ClientOptions(connection: "apple", domain: "web3auth.au.auth0.com")) - let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .sapphire(.SAPPHIRE_MAINNET), enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") + let customAuthArgs = CustomAuthArgs(urlScheme: "tdsdk://tdsdk/oauthCallback", network: .SAPPHIRE_MAINNET, enableOneKey: true, web3AuthClientId: "BPi5PB_UiIZ-cPz1GtV5i1I2iOSOHuimiXBI0e-Oe_u6X3oVAbCiAZOTEBtTXw4tsluTITPqA8zMsfxIKMjiqNQ") let customAuth = try CustomAuth(config: customAuthArgs) let torusLoginResponse = try await customAuth.triggerLogin(args: sub)