diff --git a/Checkout.podspec b/Checkout.podspec index 1dddd689..25ce3c95 100644 --- a/Checkout.podspec +++ b/Checkout.podspec @@ -20,5 +20,6 @@ Pod::Spec.new do |s| s.exclude_files = "Checkout/Samples/**" s.dependency 'CheckoutEventLoggerKit', '~> 1.2.4' + s.dependency 'Risk', '2.0.1' end diff --git a/Checkout/Source/Tokenisation/CheckoutAPIService.swift b/Checkout/Source/Tokenisation/CheckoutAPIService.swift index 10ac0fc0..93b33d47 100644 --- a/Checkout/Source/Tokenisation/CheckoutAPIService.swift +++ b/Checkout/Source/Tokenisation/CheckoutAPIService.swift @@ -1,6 +1,6 @@ // // CheckoutAPIService.swift -// +// // // Created by Harry Brown on 23/11/2021. // @@ -8,6 +8,7 @@ import Foundation import UIKit import CheckoutEventLoggerKit +import Risk public protocol CheckoutAPIProtocol { func createToken(_ paymentSource: PaymentSource, completion: @escaping (Result) -> Void) @@ -15,12 +16,20 @@ public protocol CheckoutAPIProtocol { var correlationID: String { get } } +protocol RiskProtocol: AnyObject { + func configure(completion: @escaping (Result) -> Void) + func publishData (cardToken: String?, completion: @escaping (Result) -> Void) +} + +extension Risk: RiskProtocol {} + final public class CheckoutAPIService: CheckoutAPIProtocol { private let requestExecutor: RequestExecuting private let requestFactory: RequestProviding private let tokenRequestFactory: TokenRequestProviding private let tokenDetailsFactory: TokenDetailsProviding private let logManager: LogManaging.Type + private var riskSDK: RiskProtocol private let publicKey: String private let environment: BaseURLProviding @@ -41,7 +50,18 @@ final public class CheckoutAPIService: CheckoutAPIProtocol { let tokenRequestFactory = TokenRequestFactory(cardValidator: cardValidator, decoder: snakeCaseJSONDecoder) let tokenDetailsFactory = TokenDetailsFactory() let logManager = LogManager.self - + + var riskEnvironment: RiskEnvironment + switch environment { + case .production: + riskEnvironment = .production + case .sandbox: + riskEnvironment = .sandbox + } + + let riskConfig = RiskConfig(publicKey: publicKey, environment: riskEnvironment, framesMode: true) + let riskSDK = Risk.init(config: riskConfig) + logManager.setup( environment: environment, logger: CheckoutEventLogger(productName: Constants.Product.name), @@ -57,7 +77,8 @@ final public class CheckoutAPIService: CheckoutAPIProtocol { requestFactory: requestFactory, tokenRequestFactory: tokenRequestFactory, tokenDetailsFactory: tokenDetailsFactory, - logManager: logManager) + logManager: logManager, + riskSDK: riskSDK) } init( @@ -67,7 +88,8 @@ final public class CheckoutAPIService: CheckoutAPIProtocol { requestFactory: RequestProviding, tokenRequestFactory: TokenRequestProviding, tokenDetailsFactory: TokenDetailsProviding, - logManager: LogManaging.Type + logManager: LogManaging.Type, + riskSDK: RiskProtocol ) { self.publicKey = publicKey self.environment = environment @@ -76,6 +98,7 @@ final public class CheckoutAPIService: CheckoutAPIProtocol { self.tokenRequestFactory = tokenRequestFactory self.tokenDetailsFactory = tokenDetailsFactory self.logManager = logManager + self.riskSDK = riskSDK } /// The create token method tokenises the user’s card details. @@ -126,12 +149,22 @@ final public class CheckoutAPIService: CheckoutAPIProtocol { requestParameters, responseType: TokenResponse.self, responseErrorType: TokenisationError.ServerError.self - ) { [tokenDetailsFactory, logManager, logTokenResponse] tokenResponseResult, httpURLResponse in + ) { [weak self, tokenDetailsFactory, logManager, logTokenResponse] tokenResponseResult, httpURLResponse in logTokenResponse(tokenResponseResult, httpURLResponse) switch tokenResponseResult { case .response(let tokenResponse): let tokenDetails = tokenDetailsFactory.create(tokenResponse: tokenResponse) + + guard let self else { return } + self.riskSDK.configure { configurationResult in + switch configurationResult { + case .failure: break + case .success(): + self.riskSDK.publishData(cardToken: tokenDetails.token) { _ in } + } + } + completion(.success(tokenDetails)) case .errorResponse(let errorResponse): completion(.failure(.serverError(errorResponse))) diff --git a/CheckoutTests/Stubs/StubRisk.swift b/CheckoutTests/Stubs/StubRisk.swift new file mode 100644 index 00000000..b7985603 --- /dev/null +++ b/CheckoutTests/Stubs/StubRisk.swift @@ -0,0 +1,28 @@ +// +// StubRisk.swift +// +// +// Created by Precious Ossai on 20/02/2024. +// + +import Foundation +@testable import Risk +@testable import Checkout + +// swiftlint:disable large_tuple +class StubRisk: RiskProtocol { + + var configureCalledCount = 0 + var publishDataCalledCount = 0 + + func configure(completion: @escaping (Result) -> Void) { + configureCalledCount += 1 + completion(.success(())) + } + + func publishData (cardToken: String? = nil, completion: @escaping (Result) -> Void) { + publishDataCalledCount += 1 + completion(.success(PublishRiskData(deviceSessionId: "dsid_testDeviceSessionId"))) + } +} + diff --git a/CheckoutTests/Tokenisation/CheckoutAPIServiceTests.swift b/CheckoutTests/Tokenisation/CheckoutAPIServiceTests.swift index 076c28d4..e1d83a01 100644 --- a/CheckoutTests/Tokenisation/CheckoutAPIServiceTests.swift +++ b/CheckoutTests/Tokenisation/CheckoutAPIServiceTests.swift @@ -24,6 +24,7 @@ final class CheckoutAPIServiceTests: XCTestCase { private var stubRequestFactory: StubRequestFactory! = StubRequestFactory() private var stubTokenRequestFactory: StubTokenRequestFactory! = StubTokenRequestFactory() private var stubTokenDetailsFactory: StubTokenDetailsFactory! = StubTokenDetailsFactory() + private var stubRisk: StubRisk! = .init() override func setUp() { @@ -36,7 +37,8 @@ final class CheckoutAPIServiceTests: XCTestCase { requestFactory: stubRequestFactory, tokenRequestFactory: stubTokenRequestFactory, tokenDetailsFactory: stubTokenDetailsFactory, - logManager: StubLogManager.self + logManager: StubLogManager.self, + riskSDK: stubRisk ) } @@ -49,6 +51,7 @@ final class CheckoutAPIServiceTests: XCTestCase { stubTokenRequestFactory = nil stubSecurityCodeRequestExecutor = nil stubTokenDetailsFactory = nil + stubRisk = nil super.tearDown() } @@ -90,6 +93,8 @@ final class CheckoutAPIServiceTests: XCTestCase { .init(tokenID: "token", scheme: "visa", httpStatusCode: 200, serverError: nil) )) + XCTAssertEqual(stubRisk.configureCalledCount, 1) + XCTAssertEqual(stubRisk.publishDataCalledCount, 1) XCTAssertEqual(result, .success(tokenDetails)) } @@ -213,7 +218,8 @@ extension CheckoutAPIServiceTests { requestFactory: stubRequestFactory, tokenRequestFactory: stubTokenRequestFactory, tokenDetailsFactory: stubTokenDetailsFactory, - logManager: StubLogManager.self + logManager: StubLogManager.self, + riskSDK: stubRisk ) } diff --git a/Package.resolved b/Package.resolved index ae979003..b692b452 100644 --- a/Package.resolved +++ b/Package.resolved @@ -9,6 +9,24 @@ "version" : "1.2.4" } }, + { + "identity" : "checkout-risk-sdk-ios", + "kind" : "remoteSourceControl", + "location" : "https://github.com/checkout/checkout-risk-sdk-ios.git", + "state" : { + "revision" : "4823f05166dca8392a41b56b975515c7e0f1a8da", + "version" : "2.0.1" + } + }, + { + "identity" : "fingerprintjs-pro-ios", + "kind" : "remoteSourceControl", + "location" : "https://github.com/fingerprintjs/fingerprintjs-pro-ios", + "state" : { + "revision" : "ceb8b845ec99727ee9f78869a51688c6daa16bd8", + "version" : "2.2.0" + } + }, { "identity" : "phonenumberkit", "kind" : "remoteSourceControl", diff --git a/Package.swift b/Package.swift index ece677b6..6644d9da 100644 --- a/Package.swift +++ b/Package.swift @@ -18,6 +18,9 @@ let package = Package( .package( url: "https://github.com/marmelroy/PhoneNumberKit.git", exact: "3.5.9"), + .package( + url: "https://github.com/checkout/checkout-risk-sdk-ios.git", + exact: "2.0.1"), .package( url: "https://github.com/checkout/checkout-event-logger-ios-framework.git", from: "1.2.4" @@ -29,6 +32,7 @@ let package = Package( dependencies: [ .product(name: "CheckoutEventLoggerKit", package: "checkout-event-logger-ios-framework"), + .product(name: "Risk", package: "checkout-risk-sdk-ios"), "PhoneNumberKit", "Checkout" ], @@ -43,6 +47,7 @@ let package = Package( dependencies: [ .product(name: "CheckoutEventLoggerKit", package: "checkout-event-logger-ios-framework"), + .product(name: "Risk", package: "checkout-risk-sdk-ios"), ], path: "Checkout/Source" ), diff --git a/iOS Example Frame SPM/iOS Example Frame SPM.xcodeproj/project.pbxproj b/iOS Example Frame SPM/iOS Example Frame SPM.xcodeproj/project.pbxproj index a1fa79bf..e8a01531 100644 --- a/iOS Example Frame SPM/iOS Example Frame SPM.xcodeproj/project.pbxproj +++ b/iOS Example Frame SPM/iOS Example Frame SPM.xcodeproj/project.pbxproj @@ -34,6 +34,7 @@ 16900D442AE6BA38009A7CE9 /* SecurityCodeComponentUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16900D432AE6BA38009A7CE9 /* SecurityCodeComponentUITests.swift */; }; 16900D702AEAD30D009A7CE9 /* XCUIElement+TestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16900D6F2AEAD30D009A7CE9 /* XCUIElement+TestHelpers.swift */; }; 169DF1482A7BFB1B00891DF0 /* CardSchemeFormatSnapshotTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 169DF1472A7BFB1B00891DF0 /* CardSchemeFormatSnapshotTests.swift */; }; + 16BA563F2B8FA6CE000775F9 /* Frames in Frameworks */ = {isa = PBXBuildFile; productRef = 16BA563E2B8FA6CE000775F9 /* Frames */; }; 16C3F8402A7927ED00690639 /* SnapshotTesting in Frameworks */ = {isa = PBXBuildFile; productRef = 16C3F83F2A7927ED00690639 /* SnapshotTesting */; }; 16C3F8422A7956EA00690639 /* CardValidationSnapshotTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16C3F8412A7956EA00690639 /* CardValidationSnapshotTests.swift */; }; 16E0AD482A8455F0003C9DDC /* Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16E0AD472A8455F0003C9DDC /* Helper.swift */; }; @@ -227,6 +228,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 16BA563F2B8FA6CE000775F9 /* Frames in Frameworks */, 1629C08C2AF90379001BD3D9 /* Frames in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -529,6 +531,7 @@ name = "iOS Example Frame"; packageProductDependencies = ( 1629C08B2AF90379001BD3D9 /* Frames */, + 16BA563E2B8FA6CE000775F9 /* Frames */, ); productName = "iOS Example Frame"; productReference = 16AE74C32A5C1EBB0031F794 /* iOS Example Frame.app */; @@ -577,7 +580,7 @@ mainGroup = E6646F8120CE6C0900D8353A; packageReferences = ( 16C3F83E2A7927ED00690639 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */, - 1629C08A2AF90379001BD3D9 /* XCRemoteSwiftPackageReference "frames-ios" */, + 16BA563D2B8FA6CE000775F9 /* XCRemoteSwiftPackageReference "frames-ios" */, ); productRefGroup = E6646F8120CE6C0900D8353A; projectDirPath = ""; @@ -1231,12 +1234,12 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ - 1629C08A2AF90379001BD3D9 /* XCRemoteSwiftPackageReference "frames-ios" */ = { + 16BA563D2B8FA6CE000775F9 /* XCRemoteSwiftPackageReference "frames-ios" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/checkout/frames-ios"; requirement = { - kind = exactVersion; - version = 4.3.1; + branch = "PRISM-10522-risk-i-os-is-added-to-frames-i-os"; + kind = branch; }; }; 16C3F83E2A7927ED00690639 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */ = { @@ -1252,17 +1255,19 @@ /* Begin XCSwiftPackageProductDependency section */ 1629C08B2AF90379001BD3D9 /* Frames */ = { isa = XCSwiftPackageProductDependency; - package = 1629C08A2AF90379001BD3D9 /* XCRemoteSwiftPackageReference "frames-ios" */; productName = Frames; }; 1629C08D2AF905A4001BD3D9 /* Frames */ = { isa = XCSwiftPackageProductDependency; - package = 1629C08A2AF90379001BD3D9 /* XCRemoteSwiftPackageReference "frames-ios" */; productName = Frames; }; 1629C08F2AF905A8001BD3D9 /* Frames */ = { isa = XCSwiftPackageProductDependency; - package = 1629C08A2AF90379001BD3D9 /* XCRemoteSwiftPackageReference "frames-ios" */; + productName = Frames; + }; + 16BA563E2B8FA6CE000775F9 /* Frames */ = { + isa = XCSwiftPackageProductDependency; + package = 16BA563D2B8FA6CE000775F9 /* XCRemoteSwiftPackageReference "frames-ios" */; productName = Frames; }; 16C3F83F2A7927ED00690639 /* SnapshotTesting */ = { diff --git a/iOS Example Frame SPM/iOS Example Frame SPM.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/iOS Example Frame SPM/iOS Example Frame SPM.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 5020815b..60cc759d 100644 --- a/iOS Example Frame SPM/iOS Example Frame SPM.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/iOS Example Frame SPM/iOS Example Frame SPM.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -9,13 +9,31 @@ "version" : "1.2.4" } }, + { + "identity" : "checkout-risk-sdk-ios", + "kind" : "remoteSourceControl", + "location" : "https://github.com/checkout/checkout-risk-sdk-ios.git", + "state" : { + "revision" : "4823f05166dca8392a41b56b975515c7e0f1a8da", + "version" : "2.0.1" + } + }, + { + "identity" : "fingerprintjs-pro-ios", + "kind" : "remoteSourceControl", + "location" : "https://github.com/fingerprintjs/fingerprintjs-pro-ios", + "state" : { + "revision" : "ceb8b845ec99727ee9f78869a51688c6daa16bd8", + "version" : "2.2.0" + } + }, { "identity" : "frames-ios", "kind" : "remoteSourceControl", "location" : "https://github.com/checkout/frames-ios", "state" : { - "revision" : "347e873ff9702d5783709bed5d4b6b28adfca3ab", - "version" : "4.3.1" + "branch" : "PRISM-10522-risk-i-os-is-added-to-frames-i-os", + "revision" : "de71eed3638875dac5af1d3ca01de6e5704420ea" } }, { diff --git a/iOS Example Frame/Podfile b/iOS Example Frame/Podfile index 45e5257c..e27f69de 100644 --- a/iOS Example Frame/Podfile +++ b/iOS Example Frame/Podfile @@ -6,7 +6,8 @@ target 'iOS Example Frame' do use_frameworks! # Pods for iOS Example Custom - pod 'Frames', '4.3.1' + # pod 'Frames', '4.3.1' + pod 'Frames', :git => 'https://github.com/checkout/frames-ios', :branch => 'PRISM-10522-risk-i-os-is-added-to-frames-i-os' end