From 460189d0007de4c32b226925ab983435152c0dfa Mon Sep 17 00:00:00 2001 From: Okhan Okbay Date: Tue, 20 Feb 2024 17:35:44 +0000 Subject: [PATCH 01/18] Drop Risk instance's singleton status --- .swiftpm/xcode/xcshareddata/xcschemes/Risk.xcscheme | 12 ++++++++++++ Sources/Risk/Risk.swift | 10 ++-------- {Sources => Tests}/Mocks/MockAPIService.swift | 0 {Sources => Tests}/Mocks/MockDeviceDataService.swift | 0 .../Mocks/MockFingerprintService.swift | 0 {Sources => Tests}/Mocks/MockLoggerService.swift | 0 6 files changed, 14 insertions(+), 8 deletions(-) rename {Sources => Tests}/Mocks/MockAPIService.swift (100%) rename {Sources => Tests}/Mocks/MockDeviceDataService.swift (100%) rename {Sources => Tests}/Mocks/MockFingerprintService.swift (100%) rename {Sources => Tests}/Mocks/MockLoggerService.swift (100%) diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/Risk.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/Risk.xcscheme index 5463c12..e819aa6 100644 --- a/.swiftpm/xcode/xcshareddata/xcschemes/Risk.xcscheme +++ b/.swiftpm/xcode/xcshareddata/xcschemes/Risk.xcscheme @@ -28,6 +28,18 @@ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES" shouldAutocreateTestPlan = "YES"> + + + + + + Void) { - guard sharedInstance === nil else { - return completion(sharedInstance) - } - let internalConfig = RiskSDKInternalConfig(config: config) let loggerService = LoggerService(internalConfig: internalConfig) let deviceDataService = DeviceDataService(config: internalConfig, loggerService: loggerService) @@ -53,7 +48,6 @@ public class Risk { let fingerprintPublicKey = configuration.fingerprintIntegration.publicKey! let fingerprintService = FingerprintService(fingerprintPublicKey: fingerprintPublicKey, internalConfig: internalConfig, loggerService: loggerService) let riskInstance = Risk(fingerprintService: fingerprintService, deviceDataService: deviceDataService, loggerService: loggerService) - sharedInstance = riskInstance completion(riskInstance) } @@ -62,12 +56,12 @@ public class Risk { } public func publishData (cardToken: String? = nil, completion: @escaping (Result) -> Void) { - fingerprintService.publishData { fpResult in + fingerprintService.publishData { [weak self] fpResult in switch fpResult { case .failure(let errorMessage): completion(.failure(errorMessage)) case .success(let requestId): - self.persistFpData(cardToken: cardToken, fingerprintRequestId: requestId, completion: completion) + self?.persistFpData(cardToken: cardToken, fingerprintRequestId: requestId, completion: completion) } } } diff --git a/Sources/Mocks/MockAPIService.swift b/Tests/Mocks/MockAPIService.swift similarity index 100% rename from Sources/Mocks/MockAPIService.swift rename to Tests/Mocks/MockAPIService.swift diff --git a/Sources/Mocks/MockDeviceDataService.swift b/Tests/Mocks/MockDeviceDataService.swift similarity index 100% rename from Sources/Mocks/MockDeviceDataService.swift rename to Tests/Mocks/MockDeviceDataService.swift diff --git a/Sources/Mocks/MockFingerprintService.swift b/Tests/Mocks/MockFingerprintService.swift similarity index 100% rename from Sources/Mocks/MockFingerprintService.swift rename to Tests/Mocks/MockFingerprintService.swift diff --git a/Sources/Mocks/MockLoggerService.swift b/Tests/Mocks/MockLoggerService.swift similarity index 100% rename from Sources/Mocks/MockLoggerService.swift rename to Tests/Mocks/MockLoggerService.swift From 9f71f67dc2b3e10e12c3809008284b5b23d560b5 Mon Sep 17 00:00:00 2001 From: Okhan Okbay Date: Tue, 20 Feb 2024 17:42:19 +0000 Subject: [PATCH 02/18] Update RiskError --- Sources/Risk/DeviceDataService.swift | 6 +++--- Sources/Risk/FingerprintService.swift | 2 +- Sources/Risk/Risk.swift | 26 +++++++++++++++++++------- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/Sources/Risk/DeviceDataService.swift b/Sources/Risk/DeviceDataService.swift index f836143..f22c361 100644 --- a/Sources/Risk/DeviceDataService.swift +++ b/Sources/Risk/DeviceDataService.swift @@ -64,14 +64,14 @@ struct DeviceDataService: DeviceDataServiceProtocol { guard configuration.fingerprintIntegration.enabled && configuration.fingerprintIntegration.publicKey != nil else { loggerService.log(riskEvent: .publishDisabled, deviceSessionId: nil, requestId: nil, error: RiskLogError(reason: "getConfiguration", message: "Integration disabled", status: nil, type: "Error")) - return completion(.failure(RiskError.description("Integration disabled"))) + return completion(.failure(RiskError.integrationDisabled)) } completion(.success(configuration)) case .failure(let error): loggerService.log(riskEvent: .loadFailure, deviceSessionId: nil, requestId: nil, error: RiskLogError(reason: "getConfiguration", message: error.localizedDescription, status: nil, type: "Error")) - return completion(.failure(RiskError.description("Error retrieving configuration"))) + return completion(.failure(RiskError.couldNotRetrieveConfiguration)) } } } @@ -97,7 +97,7 @@ struct DeviceDataService: DeviceDataServiceProtocol { case .failure(let error): loggerService.log(riskEvent: .publishFailure, deviceSessionId: nil, requestId: nil, error: RiskLogError(reason: "persistFpData", message: error.localizedDescription, status: nil, type: "Error")) - completion(.failure(RiskError.description("Error persisting risk data"))) + completion(.failure(RiskError.couldNotPersisRiskData)) } } } diff --git a/Sources/Risk/FingerprintService.swift b/Sources/Risk/FingerprintService.swift index e00cfd9..e9f0cdd 100644 --- a/Sources/Risk/FingerprintService.swift +++ b/Sources/Risk/FingerprintService.swift @@ -50,7 +50,7 @@ final class FingerprintService: FingerprintServiceProtocol { case .failure(let error): self?.loggerService.log(riskEvent: .publishFailure, deviceSessionId: nil, requestId: nil, error: RiskLogError(reason: "publishData", message: error.localizedDescription, status: nil, type: "Error")) - return completion(.failure(RiskError.description("Error publishing risk data"))) + return completion(.failure(RiskError.couldNotPublishRiskData)) case let .success(response): self?.loggerService.log(riskEvent: .collected, deviceSessionId: nil, requestId: response.requestId, error: nil) self?.requestId = response.requestId diff --git a/Sources/Risk/Risk.swift b/Sources/Risk/Risk.swift index 9348f93..59afd67 100644 --- a/Sources/Risk/Risk.swift +++ b/Sources/Risk/Risk.swift @@ -12,15 +12,27 @@ public struct PublishRiskData { public let deviceSessionId: String } -public enum RiskError: Error, Equatable { - case description(String) +public enum RiskError: LocalizedError, Equatable { + case integrationDisabled + case couldNotPublishRiskData + case couldNotRetrieveConfiguration + case couldNotPersisRiskData - var localizedDescription: String { - switch self { - case .description(let errorMessage): - return errorMessage - } + public var errorDescription: String? { + switch self { + case .integrationDisabled: + return "Integration disabled" + + case .couldNotPublishRiskData: + return "Error publishing risk data" + + case .couldNotRetrieveConfiguration: + return "Error retrieving configuration" + + case .couldNotPersisRiskData: + return "Error persisting risk data" } + } } public class Risk { From 6fd70e1239dfe86c5538901009b28a862514aa6a Mon Sep 17 00:00:00 2001 From: Okhan Okbay Date: Tue, 20 Feb 2024 17:47:09 +0000 Subject: [PATCH 03/18] Breakdown different types into different files --- Sources/Risk/Models/PublishRiskData.swift | 12 ++++++ Sources/Risk/Models/RiskIntegrationType.swift | 13 ++++++ .../Risk/Models/RiskSDKInternalConfig.swift | 39 ++++++++++++++++++ Sources/Risk/Models/SourceType.swift | 13 ++++++ Sources/Risk/Risk.swift | 27 ------------ Sources/Risk/RiskError.swift | 31 ++++++++++++++ Sources/Risk/RiskSDKConfig.swift | 41 ------------------- 7 files changed, 108 insertions(+), 68 deletions(-) create mode 100644 Sources/Risk/Models/PublishRiskData.swift create mode 100644 Sources/Risk/Models/RiskIntegrationType.swift create mode 100644 Sources/Risk/Models/RiskSDKInternalConfig.swift create mode 100644 Sources/Risk/Models/SourceType.swift create mode 100644 Sources/Risk/RiskError.swift diff --git a/Sources/Risk/Models/PublishRiskData.swift b/Sources/Risk/Models/PublishRiskData.swift new file mode 100644 index 0000000..eb4b918 --- /dev/null +++ b/Sources/Risk/Models/PublishRiskData.swift @@ -0,0 +1,12 @@ +// +// PublishRiskData.swift +// +// +// Created by Precious Ossai on 30/10/2023. +// + +import Foundation + +public struct PublishRiskData { + public let deviceSessionId: String +} diff --git a/Sources/Risk/Models/RiskIntegrationType.swift b/Sources/Risk/Models/RiskIntegrationType.swift new file mode 100644 index 0000000..906d94b --- /dev/null +++ b/Sources/Risk/Models/RiskIntegrationType.swift @@ -0,0 +1,13 @@ +// +// RiskIntegrationType.swift +// +// +// Created by Precious Ossai on 20/02/2024. +// + +import Foundation + +enum RiskIntegrationType: String, Codable { + case standalone = "RiskIosStandalone" + case inFrames = "RiskIosInFramesIos" +} diff --git a/Sources/Risk/Models/RiskSDKInternalConfig.swift b/Sources/Risk/Models/RiskSDKInternalConfig.swift new file mode 100644 index 0000000..dc61107 --- /dev/null +++ b/Sources/Risk/Models/RiskSDKInternalConfig.swift @@ -0,0 +1,39 @@ +// +// RiskSDKInternalConfig.swift +// +// +// Created by Precious Ossai on 20/02/2024. +// + +import Foundation + +struct RiskSDKInternalConfig { + let merchantPublicKey: String + let deviceDataEndpoint: String + let fingerprintEndpoint: String + let integrationType: RiskIntegrationType + let sourceType: SourceType + let framesMode: Bool + let environment: RiskEnvironment + + init(config: RiskConfig) { + merchantPublicKey = config.publicKey + environment = config.environment + framesMode = config.framesMode + integrationType = framesMode ? .inFrames : .standalone + sourceType = framesMode ? .cardToken : .riskSDK + + switch environment { + case .qa: + deviceDataEndpoint = "https://prism-qa.ckotech.co/collect" + fingerprintEndpoint = "https://fpjs.cko-qa.ckotech.co" + case .sandbox: + deviceDataEndpoint = "https://risk.sandbox.checkout.com/collect" + fingerprintEndpoint = "https://fpjs.sandbox.checkout.com" + case .prod: + deviceDataEndpoint = "https://risk.checkout.com/collect" + fingerprintEndpoint = "https://fpjs.checkout.com" + } + } + +} diff --git a/Sources/Risk/Models/SourceType.swift b/Sources/Risk/Models/SourceType.swift new file mode 100644 index 0000000..c2b450c --- /dev/null +++ b/Sources/Risk/Models/SourceType.swift @@ -0,0 +1,13 @@ +// +// SourceType.swift +// +// +// Created by Precious Ossai on 20/02/2024. +// + +import Foundation + +enum SourceType: String { + case cardToken = "card_token" + case riskSDK = "riskios" +} diff --git a/Sources/Risk/Risk.swift b/Sources/Risk/Risk.swift index 59afd67..86ed7bb 100644 --- a/Sources/Risk/Risk.swift +++ b/Sources/Risk/Risk.swift @@ -8,33 +8,6 @@ import Foundation -public struct PublishRiskData { - public let deviceSessionId: String -} - -public enum RiskError: LocalizedError, Equatable { - case integrationDisabled - case couldNotPublishRiskData - case couldNotRetrieveConfiguration - case couldNotPersisRiskData - - public var errorDescription: String? { - switch self { - case .integrationDisabled: - return "Integration disabled" - - case .couldNotPublishRiskData: - return "Error publishing risk data" - - case .couldNotRetrieveConfiguration: - return "Error retrieving configuration" - - case .couldNotPersisRiskData: - return "Error persisting risk data" - } - } -} - public class Risk { private let fingerprintService: FingerprintService private let deviceDataService: DeviceDataService diff --git a/Sources/Risk/RiskError.swift b/Sources/Risk/RiskError.swift new file mode 100644 index 0000000..e90f226 --- /dev/null +++ b/Sources/Risk/RiskError.swift @@ -0,0 +1,31 @@ +// +// RiskError.swift +// +// +// Created by Precious Ossai on 13/10/2023. +// + +import Foundation + +public enum RiskError: LocalizedError, Equatable { + case integrationDisabled + case couldNotPublishRiskData + case couldNotRetrieveConfiguration + case couldNotPersisRiskData + + public var errorDescription: String? { + switch self { + case .integrationDisabled: + return "Integration disabled" + + case .couldNotPublishRiskData: + return "Error publishing risk data" + + case .couldNotRetrieveConfiguration: + return "Error retrieving configuration" + + case .couldNotPersisRiskData: + return "Error persisting risk data" + } + } +} diff --git a/Sources/Risk/RiskSDKConfig.swift b/Sources/Risk/RiskSDKConfig.swift index 1528e51..1170993 100644 --- a/Sources/Risk/RiskSDKConfig.swift +++ b/Sources/Risk/RiskSDKConfig.swift @@ -15,16 +15,6 @@ public enum RiskEnvironment: String { case prod } -enum RiskIntegrationType: String, Codable { - case standalone = "RiskIosStandalone" - case inFrames = "RiskIosInFramesIos" -} - -enum SourceType: String { - case cardToken = "card_token" - case riskSDK = "riskios" -} - public struct RiskConfig { public let publicKey: String public let environment: RiskEnvironment @@ -36,34 +26,3 @@ public struct RiskConfig { self.framesMode = framesMode } } - -struct RiskSDKInternalConfig { - let merchantPublicKey: String - let deviceDataEndpoint: String - let fingerprintEndpoint: String - let integrationType: RiskIntegrationType - let sourceType: SourceType - let framesMode: Bool - let environment: RiskEnvironment - - init(config: RiskConfig) { - merchantPublicKey = config.publicKey - environment = config.environment - framesMode = config.framesMode - integrationType = framesMode ? .inFrames : .standalone - sourceType = framesMode ? .cardToken : .riskSDK - - switch environment { - case .qa: - deviceDataEndpoint = "https://prism-qa.ckotech.co/collect" - fingerprintEndpoint = "https://fpjs.cko-qa.ckotech.co" - case .sandbox: - deviceDataEndpoint = "https://risk.sandbox.checkout.com/collect" - fingerprintEndpoint = "https://fpjs.sandbox.checkout.com" - case .prod: - deviceDataEndpoint = "https://risk.checkout.com/collect" - fingerprintEndpoint = "https://fpjs.checkout.com" - } - } - -} From ca13b170d6d9d111ac59c1d3272d7eef7b6e4690 Mon Sep 17 00:00:00 2001 From: Okhan Okbay Date: Tue, 20 Feb 2024 19:03:16 +0000 Subject: [PATCH 04/18] Refactor --- Sources/Risk/DeviceDataService.swift | 2 +- Sources/Risk/Risk.swift | 105 ++++++++++++++------------- Sources/Risk/RiskError.swift | 4 + 3 files changed, 61 insertions(+), 50 deletions(-) diff --git a/Sources/Risk/DeviceDataService.swift b/Sources/Risk/DeviceDataService.swift index f22c361..f7fffb2 100644 --- a/Sources/Risk/DeviceDataService.swift +++ b/Sources/Risk/DeviceDataService.swift @@ -10,7 +10,7 @@ import Foundation struct FingerprintIntegration: Decodable, Equatable { let enabled: Bool - let publicKey: String? + let publicKey: String } struct DeviceDataConfiguration: Decodable, Equatable { diff --git a/Sources/Risk/Risk.swift b/Sources/Risk/Risk.swift index 86ed7bb..e1aabff 100644 --- a/Sources/Risk/Risk.swift +++ b/Sources/Risk/Risk.swift @@ -8,57 +8,64 @@ import Foundation -public class Risk { - private let fingerprintService: FingerprintService - private let deviceDataService: DeviceDataService - private let loggerService: LoggerServiceProtocol - - private init(fingerprintService: FingerprintService, deviceDataService: DeviceDataService, loggerService: LoggerServiceProtocol) { - self.fingerprintService = fingerprintService - self.deviceDataService = deviceDataService - self.loggerService = loggerService +public final class Risk { + private let internalConfig: RiskSDKInternalConfig + private let deviceDataService: DeviceDataService + private let loggerService: LoggerServiceProtocol + + private var fingerprintService: FingerprintService? + + private init(config: RiskConfig) { + internalConfig = RiskSDKInternalConfig(config: config) + loggerService = LoggerService(internalConfig: internalConfig) + deviceDataService = DeviceDataService(config: internalConfig, loggerService: loggerService) + } + + public func configure(config: RiskConfig, completion: @escaping (Error?) -> Void) { + deviceDataService.getConfiguration { [weak self] result in + guard let self = self else { return } + + switch result { + case .success(let configuration): + let fingerprintPublicKey = configuration.fingerprintIntegration.publicKey + self.fingerprintService = FingerprintService(fingerprintPublicKey: fingerprintPublicKey, + internalConfig: self.internalConfig, + loggerService: self.loggerService) + completion(nil) + + case .failure(let error): + return completion(error) + } } - - public static func getInstance(config: RiskConfig, completion: @escaping (Risk?) -> Void) { - let internalConfig = RiskSDKInternalConfig(config: config) - let loggerService = LoggerService(internalConfig: internalConfig) - let deviceDataService = DeviceDataService(config: internalConfig, loggerService: loggerService) - - deviceDataService.getConfiguration { result in - - switch result { - case .failure: - return completion(nil) - case .success(let configuration): - let fingerprintPublicKey = configuration.fingerprintIntegration.publicKey! - let fingerprintService = FingerprintService(fingerprintPublicKey: fingerprintPublicKey, internalConfig: internalConfig, loggerService: loggerService) - let riskInstance = Risk(fingerprintService: fingerprintService, deviceDataService: deviceDataService, loggerService: loggerService) - - completion(riskInstance) - } - - } + } + + public func publishData (cardToken: String? = nil, completion: @escaping (Result) -> Void) { + guard let fingerprintService = fingerprintService else { + completion(.failure(.fingerprintServiceIsNotConfigured)) + return } - - public func publishData (cardToken: String? = nil, completion: @escaping (Result) -> Void) { - fingerprintService.publishData { [weak self] fpResult in - switch fpResult { - case .failure(let errorMessage): - completion(.failure(errorMessage)) - case .success(let requestId): - self?.persistFpData(cardToken: cardToken, fingerprintRequestId: requestId, completion: completion) - } - } + + fingerprintService.publishData { [weak self] fpResult in + guard let self = self else { return } + + switch fpResult { + case .success(let requestId): + self.persistFpData(cardToken: cardToken, fingerprintRequestId: requestId, completion: completion) + + case .failure(let error): + completion(.failure(error)) + } } - - private func persistFpData(cardToken: String?, fingerprintRequestId: String, completion: @escaping (Result) -> Void) { - self.deviceDataService.persistFpData(fingerprintRequestId: fingerprintRequestId, cardToken: cardToken) { result in - switch result { - case .success(let response): - completion(.success(PublishRiskData(deviceSessionId: response.deviceSessionId))) - case .failure(let errorMessage): - completion(.failure(errorMessage)) - } - } + } + + private func persistFpData(cardToken: String?, fingerprintRequestId: String, completion: @escaping (Result) -> Void) { + self.deviceDataService.persistFpData(fingerprintRequestId: fingerprintRequestId, cardToken: cardToken) { result in + switch result { + case .success(let response): + completion(.success(PublishRiskData(deviceSessionId: response.deviceSessionId))) + case .failure(let error): + completion(.failure(error)) + } } + } } diff --git a/Sources/Risk/RiskError.swift b/Sources/Risk/RiskError.swift index e90f226..d6d70b2 100644 --- a/Sources/Risk/RiskError.swift +++ b/Sources/Risk/RiskError.swift @@ -12,6 +12,7 @@ public enum RiskError: LocalizedError, Equatable { case couldNotPublishRiskData case couldNotRetrieveConfiguration case couldNotPersisRiskData + case fingerprintServiceIsNotConfigured public var errorDescription: String? { switch self { @@ -26,6 +27,9 @@ public enum RiskError: LocalizedError, Equatable { case .couldNotPersisRiskData: return "Error persisting risk data" + + case .fingerprintServiceIsNotConfigured: + return "Fingerprint service is not configured. Please call configure() method first." } } } From 46247e0243e37acf54d14beff55f7dfb542821f9 Mon Sep 17 00:00:00 2001 From: Okhan Okbay Date: Tue, 20 Feb 2024 19:12:15 +0000 Subject: [PATCH 05/18] Exclude sample projects from SPM distribution --- Package.swift | 6 ++---- Sources/{Core => Risk/Logging}/Constants.swift | 0 Sources/{Core => Risk/Logging}/LoggerService.swift | 2 +- Sources/Risk/Models/RiskSDKInternalConfig.swift | 2 +- Sources/Risk/RiskSDKConfig.swift | 2 +- Sources/Risk/{ => Services}/APIService.swift | 0 Sources/Risk/{ => Services}/DeviceDataService.swift | 0 Sources/Risk/{ => Services}/FingerprintService.swift | 0 Sources/Risk/{ => Services}/RiskError.swift | 0 iOSExampleRiskCocoapods/Package.swift | 5 +++++ iOSExampleRiskSPM/Package.swift | 5 +++++ 11 files changed, 15 insertions(+), 7 deletions(-) rename Sources/{Core => Risk/Logging}/Constants.swift (100%) rename Sources/{Core => Risk/Logging}/LoggerService.swift (99%) rename Sources/Risk/{ => Services}/APIService.swift (100%) rename Sources/Risk/{ => Services}/DeviceDataService.swift (100%) rename Sources/Risk/{ => Services}/FingerprintService.swift (100%) rename Sources/Risk/{ => Services}/RiskError.swift (100%) create mode 100644 iOSExampleRiskCocoapods/Package.swift create mode 100644 iOSExampleRiskSPM/Package.swift diff --git a/Package.swift b/Package.swift index 5269dae..ed27c53 100644 --- a/Package.swift +++ b/Package.swift @@ -16,12 +16,10 @@ let package = Package( dependencies: [ .package( url: "https://github.com/fingerprintjs/fingerprintjs-pro-ios", - .exact("2.2.0") - ), + exact: "2.2.0"), .package( url: "https://github.com/checkout/checkout-event-logger-ios-framework.git", - from: "1.2.4" - ) + from: "1.2.4") ], targets: [ .target( diff --git a/Sources/Core/Constants.swift b/Sources/Risk/Logging/Constants.swift similarity index 100% rename from Sources/Core/Constants.swift rename to Sources/Risk/Logging/Constants.swift diff --git a/Sources/Core/LoggerService.swift b/Sources/Risk/Logging/LoggerService.swift similarity index 99% rename from Sources/Core/LoggerService.swift rename to Sources/Risk/Logging/LoggerService.swift index 96654ce..2f529f7 100644 --- a/Sources/Core/LoggerService.swift +++ b/Sources/Risk/Logging/LoggerService.swift @@ -120,7 +120,7 @@ struct LoggerService: LoggerServiceProtocol { switch internalConfig.environment { case .qa, .sandbox: logEnvironment = .sandbox - case .prod: + case .production: logEnvironment = .production } diff --git a/Sources/Risk/Models/RiskSDKInternalConfig.swift b/Sources/Risk/Models/RiskSDKInternalConfig.swift index dc61107..964f19b 100644 --- a/Sources/Risk/Models/RiskSDKInternalConfig.swift +++ b/Sources/Risk/Models/RiskSDKInternalConfig.swift @@ -30,7 +30,7 @@ struct RiskSDKInternalConfig { case .sandbox: deviceDataEndpoint = "https://risk.sandbox.checkout.com/collect" fingerprintEndpoint = "https://fpjs.sandbox.checkout.com" - case .prod: + case .production: deviceDataEndpoint = "https://risk.checkout.com/collect" fingerprintEndpoint = "https://fpjs.checkout.com" } diff --git a/Sources/Risk/RiskSDKConfig.swift b/Sources/Risk/RiskSDKConfig.swift index 1170993..326e742 100644 --- a/Sources/Risk/RiskSDKConfig.swift +++ b/Sources/Risk/RiskSDKConfig.swift @@ -12,7 +12,7 @@ import FingerprintPro public enum RiskEnvironment: String { case qa case sandbox - case prod + case production } public struct RiskConfig { diff --git a/Sources/Risk/APIService.swift b/Sources/Risk/Services/APIService.swift similarity index 100% rename from Sources/Risk/APIService.swift rename to Sources/Risk/Services/APIService.swift diff --git a/Sources/Risk/DeviceDataService.swift b/Sources/Risk/Services/DeviceDataService.swift similarity index 100% rename from Sources/Risk/DeviceDataService.swift rename to Sources/Risk/Services/DeviceDataService.swift diff --git a/Sources/Risk/FingerprintService.swift b/Sources/Risk/Services/FingerprintService.swift similarity index 100% rename from Sources/Risk/FingerprintService.swift rename to Sources/Risk/Services/FingerprintService.swift diff --git a/Sources/Risk/RiskError.swift b/Sources/Risk/Services/RiskError.swift similarity index 100% rename from Sources/Risk/RiskError.swift rename to Sources/Risk/Services/RiskError.swift diff --git a/iOSExampleRiskCocoapods/Package.swift b/iOSExampleRiskCocoapods/Package.swift new file mode 100644 index 0000000..8c84cf5 --- /dev/null +++ b/iOSExampleRiskCocoapods/Package.swift @@ -0,0 +1,5 @@ +// swift-tools-version:5.6 +// THIS IS TO EXCLUDE SAMPLE PROJECTS FROM PACKAGE DISTRIBUTION +import PackageDescription +let package = Package() +// THIS IS TO EXCLUDE SAMPLE PROJECTS FROM PACKAGE DISTRIBUTION diff --git a/iOSExampleRiskSPM/Package.swift b/iOSExampleRiskSPM/Package.swift new file mode 100644 index 0000000..8c84cf5 --- /dev/null +++ b/iOSExampleRiskSPM/Package.swift @@ -0,0 +1,5 @@ +// swift-tools-version:5.6 +// THIS IS TO EXCLUDE SAMPLE PROJECTS FROM PACKAGE DISTRIBUTION +import PackageDescription +let package = Package() +// THIS IS TO EXCLUDE SAMPLE PROJECTS FROM PACKAGE DISTRIBUTION From 8b8080bf5793e6ffb8e629684f80433170f3113a Mon Sep 17 00:00:00 2001 From: Okhan Okbay Date: Tue, 20 Feb 2024 19:24:53 +0000 Subject: [PATCH 06/18] Fix SPM sample project --- Sources/Risk/Risk.swift | 4 +- .../RiskExample.xcodeproj/project.pbxproj | 6 +- .../xcshareddata/swiftpm/Package.resolved | 9 -- .../RiskExample/ContentView.swift | 94 ++++++++++--------- 4 files changed, 55 insertions(+), 58 deletions(-) diff --git a/Sources/Risk/Risk.swift b/Sources/Risk/Risk.swift index e1aabff..36b3df7 100644 --- a/Sources/Risk/Risk.swift +++ b/Sources/Risk/Risk.swift @@ -15,13 +15,13 @@ public final class Risk { private var fingerprintService: FingerprintService? - private init(config: RiskConfig) { + public init(config: RiskConfig) { internalConfig = RiskSDKInternalConfig(config: config) loggerService = LoggerService(internalConfig: internalConfig) deviceDataService = DeviceDataService(config: internalConfig, loggerService: loggerService) } - public func configure(config: RiskConfig, completion: @escaping (Error?) -> Void) { + public func configure(completion: @escaping (Error?) -> Void) { deviceDataService.getConfiguration { [weak self] result in guard let self = self else { return } diff --git a/iOSExampleRiskSPM/RiskExample.xcodeproj/project.pbxproj b/iOSExampleRiskSPM/RiskExample.xcodeproj/project.pbxproj index 7fde51c..479f5ce 100644 --- a/iOSExampleRiskSPM/RiskExample.xcodeproj/project.pbxproj +++ b/iOSExampleRiskSPM/RiskExample.xcodeproj/project.pbxproj @@ -39,6 +39,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 163EC7632B85320700149296 /* checkout-risk-sdk-ios */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = "checkout-risk-sdk-ios"; path = ..; sourceTree = ""; }; BA0B00452AD6A5280037D9FF /* RiskExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RiskExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; BA0B00482AD6A5280037D9FF /* RiskExampleApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RiskExampleApp.swift; sourceTree = ""; }; BA0B004A2AD6A5280037D9FF /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; usesTabs = 1; }; @@ -84,6 +85,7 @@ BA0B003C2AD6A5280037D9FF = { isa = PBXGroup; children = ( + 163EC7632B85320700149296 /* checkout-risk-sdk-ios */, BA0B00472AD6A5280037D9FF /* RiskExample */, BA0B00582AD6A52A0037D9FF /* RiskExampleTests */, BA0B00622AD6A52A0037D9FF /* RiskExampleUITests */, @@ -610,8 +612,8 @@ isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/checkout/checkout-risk-sdk-ios"; requirement = { - kind = upToNextMajorVersion; - minimumVersion = 1.0.2; + kind = exactVersion; + version = 1.0.4; }; }; /* End XCRemoteSwiftPackageReference section */ diff --git a/iOSExampleRiskSPM/RiskExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/iOSExampleRiskSPM/RiskExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 35434eb..6e7d923 100644 --- a/iOSExampleRiskSPM/RiskExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/iOSExampleRiskSPM/RiskExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -9,15 +9,6 @@ "version" : "1.2.4" } }, - { - "identity" : "checkout-risk-sdk-ios", - "kind" : "remoteSourceControl", - "location" : "https://github.com/checkout/checkout-risk-sdk-ios", - "state" : { - "revision" : "ac2bbb8f99e46a873a5565e44b2b822448f96e38", - "version" : "1.0.2" - } - }, { "identity" : "fingerprintjs-pro-ios", "kind" : "remoteSourceControl", diff --git a/iOSExampleRiskSPM/RiskExample/ContentView.swift b/iOSExampleRiskSPM/RiskExample/ContentView.swift index 664907d..d7d174a 100644 --- a/iOSExampleRiskSPM/RiskExample/ContentView.swift +++ b/iOSExampleRiskSPM/RiskExample/ContentView.swift @@ -11,62 +11,66 @@ import Risk import Foundation struct ContentView: View { - @State private var deviceSessionId: String? + @State private var deviceSessionId: String? @State private var error: String? - @State private var enabled: Bool = false - @State private var checked: Bool = false - @State private var loading: Bool = false + @State private var enabled: Bool = false + @State private var checked: Bool = false + @State private var loading: Bool = false - var body: some View { - Text("Risk iOS Example - SPM").padding(.bottom).frame(maxWidth: .infinity, alignment: .center).font(.title) + @State private var riskSDK: Risk! - VStack(alignment: .leading) { + var body: some View { + Text("Risk iOS Example - SPM").padding(.bottom).frame(maxWidth: .infinity, alignment: .center).font(.title) - Text("Card no: 0000 1234 6549 15151") - Text("Card exp: 12/26") - Text("Card CVV: 500").padding(.bottom) + VStack(alignment: .leading) { - } - .padding().background(Color.gray.opacity(0.1)) + Text("Card no: 0000 1234 6549 15151") + Text("Card exp: 12/26") + Text("Card CVV: 500").padding(.bottom) - Button("Pay $1400") { - guard let publicKey = ProcessInfo.processInfo.environment["SAMPLE_MERCHANT_PUBLIC_KEY"] else { + } + .padding().background(Color.gray.opacity(0.1)) + + Button("Pay $1400") { + guard let publicKey = ProcessInfo.processInfo.environment["SAMPLE_MERCHANT_PUBLIC_KEY"] else { error = "Environment variable (SAMPLE_MERCHANT_PUBLIC_KEY) not set" - - return - } - - let yourConfig = RiskConfig(publicKey: publicKey, environment: RiskEnvironment.qa) - - Risk.getInstance(config: yourConfig) { riskInstance in - checked = true - loading = true - - guard riskInstance != nil else { - loading = false - enabled = false - return - } - enabled = true - - riskInstance?.publishData { result in - - switch result { - case .success(let response): - deviceSessionId = response.deviceSessionId - case .failure(let errorResponse): - deviceSessionId = nil + return + } + + let yourConfig = RiskConfig(publicKey: publicKey, environment: RiskEnvironment.qa) + self.riskSDK = Risk.init(config: yourConfig) + + checked = true + loading = true + + self.riskSDK.configure { errorResponse in + loading = false + + if let errorResponse = errorResponse { + error = errorResponse.localizedDescription + enabled = false + return + } + + enabled = true + + self.riskSDK.publishData { result in + + switch result { + case .success(let response): + deviceSessionId = response.deviceSessionId + case .failure(let errorResponse): + deviceSessionId = nil error = errorResponse.localizedDescription - } - loading = false - } - } - }.padding().background(Color.blue.opacity(0.9)).cornerRadius(8).frame(maxWidth: .infinity, alignment: .center).foregroundColor(.white).padding(.top) + } + } + } + }.padding().background(Color.blue.opacity(0.9)).cornerRadius(8).frame(maxWidth: .infinity, alignment: .center).foregroundColor(.white).padding(.top) Text(error ?? (!checked ? .init() : loading ? "Loading..." : enabled && deviceSessionId != nil ? "Device session id: \(deviceSessionId!)" : "Integration disabled") ).padding(.top).multilineTextAlignment(.center) - } + } } #Preview { - ContentView() + ContentView() } From 906c285f17313df788aa3e052c0b42d0470216b2 Mon Sep 17 00:00:00 2001 From: Okhan Okbay Date: Tue, 20 Feb 2024 19:35:12 +0000 Subject: [PATCH 07/18] Fix unit tests --- Package.swift | 3 +- Sources/Risk/Risk.swift | 2 +- Sources/Risk/Services/DeviceDataService.swift | 2 +- Tests/Mocks/MockAPIService.swift | 1 + Tests/Mocks/MockDeviceDataService.swift | 5 +- Tests/Mocks/MockFingerprintService.swift | 3 +- Tests/Mocks/MockLoggerService.swift | 1 + Tests/RiskTests/RiskTests.swift | 10 +- .../xcschemes/RiskExample.xcscheme | 101 ++++++++++++++++++ 9 files changed, 116 insertions(+), 12 deletions(-) create mode 100644 iOSExampleRiskSPM/RiskExample.xcodeproj/xcshareddata/xcschemes/RiskExample.xcscheme diff --git a/Package.swift b/Package.swift index ed27c53..18a5457 100644 --- a/Package.swift +++ b/Package.swift @@ -34,7 +34,8 @@ let package = Package( path: "Sources"), .testTarget( name: "RiskTests", - dependencies: ["Risk"]) + dependencies: ["Risk"], + path: "Tests") ], swiftLanguageVersions: [.v5] ) diff --git a/Sources/Risk/Risk.swift b/Sources/Risk/Risk.swift index 36b3df7..4c9214e 100644 --- a/Sources/Risk/Risk.swift +++ b/Sources/Risk/Risk.swift @@ -27,7 +27,7 @@ public final class Risk { switch result { case .success(let configuration): - let fingerprintPublicKey = configuration.fingerprintIntegration.publicKey + let fingerprintPublicKey = configuration.fingerprintIntegration.publicKey! self.fingerprintService = FingerprintService(fingerprintPublicKey: fingerprintPublicKey, internalConfig: self.internalConfig, loggerService: self.loggerService) diff --git a/Sources/Risk/Services/DeviceDataService.swift b/Sources/Risk/Services/DeviceDataService.swift index f7fffb2..f22c361 100644 --- a/Sources/Risk/Services/DeviceDataService.swift +++ b/Sources/Risk/Services/DeviceDataService.swift @@ -10,7 +10,7 @@ import Foundation struct FingerprintIntegration: Decodable, Equatable { let enabled: Bool - let publicKey: String + let publicKey: String? } struct DeviceDataConfiguration: Decodable, Equatable { diff --git a/Tests/Mocks/MockAPIService.swift b/Tests/Mocks/MockAPIService.swift index 48120fe..5b46d2c 100644 --- a/Tests/Mocks/MockAPIService.swift +++ b/Tests/Mocks/MockAPIService.swift @@ -6,6 +6,7 @@ // import Foundation +@testable import Risk class MockAPIService: APIServiceProtocol { var expectedResult: Result? diff --git a/Tests/Mocks/MockDeviceDataService.swift b/Tests/Mocks/MockDeviceDataService.swift index 81c6e5f..6abb0ea 100644 --- a/Tests/Mocks/MockDeviceDataService.swift +++ b/Tests/Mocks/MockDeviceDataService.swift @@ -6,6 +6,7 @@ // import Foundation +@testable import Risk class MockDeviceDataService: DeviceDataServiceProtocol { var shouldReturnConfiguration: Bool = true @@ -16,7 +17,7 @@ class MockDeviceDataService: DeviceDataServiceProtocol { let configuration = DeviceDataConfiguration(fingerprintIntegration: FingerprintIntegration(enabled: true, publicKey: "mocked_public_key")) completion(.success(configuration)) } else { - completion(.failure(RiskError.description("Mocked configuration error"))) + completion(.failure(RiskError.couldNotRetrieveConfiguration)) } } @@ -25,7 +26,7 @@ class MockDeviceDataService: DeviceDataServiceProtocol { let response = PersistDeviceDataResponse(deviceSessionId: "mocked_device_session_id") completion(.success(response)) } else { - completion(.failure(RiskError.description("Mocked persistFpData error"))) + completion(.failure(RiskError.couldNotPersisRiskData)) } } } diff --git a/Tests/Mocks/MockFingerprintService.swift b/Tests/Mocks/MockFingerprintService.swift index 0b5061b..277b70b 100644 --- a/Tests/Mocks/MockFingerprintService.swift +++ b/Tests/Mocks/MockFingerprintService.swift @@ -6,6 +6,7 @@ // import Foundation +@testable import Risk class MockFingerprintService: FingerprintServiceProtocol { var shouldSucceed: Bool = true @@ -20,7 +21,7 @@ class MockFingerprintService: FingerprintServiceProtocol { completion(.success(fakeRequestId)) } } else { - let error = RiskError.description("Mocked publishData error") + let error = RiskError.couldNotPublishRiskData completion(.failure(error)) } } diff --git a/Tests/Mocks/MockLoggerService.swift b/Tests/Mocks/MockLoggerService.swift index d61e414..926892a 100644 --- a/Tests/Mocks/MockLoggerService.swift +++ b/Tests/Mocks/MockLoggerService.swift @@ -1,5 +1,6 @@ import Foundation import CheckoutEventLoggerKit +@testable import Risk struct MockLoggerService: LoggerServiceProtocol { private var loggedEvents: [RiskEvent] = [] diff --git a/Tests/RiskTests/RiskTests.swift b/Tests/RiskTests/RiskTests.swift index 305dbfc..bab4a8b 100644 --- a/Tests/RiskTests/RiskTests.swift +++ b/Tests/RiskTests/RiskTests.swift @@ -34,16 +34,14 @@ class RiskTests: XCTestCase { func testGetInstanceWithInvalidPublicKey() { let expectation = self.expectation(description: "Risk instance creation with invalid public key") - var createdRiskInstance: Risk? let invalidConfig = RiskConfig(publicKey: "invalid_public_key", environment: RiskEnvironment.qa) - - Risk.getInstance(config: invalidConfig) { risk in - createdRiskInstance = risk - expectation.fulfill() + let riskSDK = Risk(config: invalidConfig) + riskSDK.configure { error in + XCTAssertNotNil(error) + expectation.fulfill() } waitForExpectations(timeout: 5, handler: nil) - XCTAssertNil(createdRiskInstance) } } diff --git a/iOSExampleRiskSPM/RiskExample.xcodeproj/xcshareddata/xcschemes/RiskExample.xcscheme b/iOSExampleRiskSPM/RiskExample.xcodeproj/xcshareddata/xcschemes/RiskExample.xcscheme new file mode 100644 index 0000000..e08d904 --- /dev/null +++ b/iOSExampleRiskSPM/RiskExample.xcodeproj/xcshareddata/xcschemes/RiskExample.xcscheme @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From d33ef055e54fa1c932e04cad941dd453dcc3d115 Mon Sep 17 00:00:00 2001 From: Precious OSSAI Date: Tue, 27 Feb 2024 11:10:32 +0000 Subject: [PATCH 08/18] chore: clear error before checks in example --- iOSExampleRiskSPM/RiskExample/ContentView.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/iOSExampleRiskSPM/RiskExample/ContentView.swift b/iOSExampleRiskSPM/RiskExample/ContentView.swift index d7d174a..780df5c 100644 --- a/iOSExampleRiskSPM/RiskExample/ContentView.swift +++ b/iOSExampleRiskSPM/RiskExample/ContentView.swift @@ -42,6 +42,7 @@ struct ContentView: View { checked = true loading = true + error = nil self.riskSDK.configure { errorResponse in loading = false From bfc5b19a58b2ceea244a6bec30abce78819aed94 Mon Sep 17 00:00:00 2001 From: Precious OSSAI Date: Tue, 27 Feb 2024 11:10:43 +0000 Subject: [PATCH 09/18] chore: bump version --- .github/partial-readmes/Installation.md | 4 ++-- Risk.podspec | 2 +- Sources/Risk/Logging/Constants.swift | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/partial-readmes/Installation.md b/.github/partial-readmes/Installation.md index ccffc92..acd2468 100644 --- a/.github/partial-readmes/Installation.md +++ b/.github/partial-readmes/Installation.md @@ -9,7 +9,7 @@ We've done our best to support the most common distribution methods on iOS. We a let package = Package( ... dependencies: [ - .package(url: "https://github.com/checkout/checkout-risk-sdk-ios", from: "1.0.3") + .package(url: "https://github.com/checkout/checkout-risk-sdk-ios", from: "1.1.0") ] ... ) @@ -34,7 +34,7 @@ platform :ios, '12.0' use_frameworks! target '' do - pod 'Risk', '~> 1.0.3' + pod 'Risk', '~> 1.1.0' end ``` diff --git a/Risk.podspec b/Risk.podspec index 4755aa5..910bf1a 100644 --- a/Risk.podspec +++ b/Risk.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "Risk" - s.version = "1.0.3" + s.version = "1.1.0" s.summary = "Checkout Risk package in Swift" s.description = <<-DESC Checkout Risk package in Swift. diff --git a/Sources/Risk/Logging/Constants.swift b/Sources/Risk/Logging/Constants.swift index 25efe6d..2295b17 100644 --- a/Sources/Risk/Logging/Constants.swift +++ b/Sources/Risk/Logging/Constants.swift @@ -9,7 +9,7 @@ import Foundation enum Constants { static let productName = "risk-ios-sdk" - static let riskSdkVersion = "1.0.3" + static let riskSdkVersion = "1.1.0" static let userAgent = "checkout-sdk-risk-ios/\(riskSdkVersion)" static let loggerTypeIdentifier = "com.checkout.risk-mobile-sdk" } From b66400373ef71a2178a4abc7855810435f076a66 Mon Sep 17 00:00:00 2001 From: Precious OSSAI Date: Tue, 27 Feb 2024 13:26:26 +0000 Subject: [PATCH 10/18] refactor: update docs --- README.md | 87 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 50 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 8cbd63e..0226c13 100644 --- a/README.md +++ b/README.md @@ -29,56 +29,69 @@ The package helps collect device data for merchants with direct integration (sta ### Usage guide 1. Add `Risk` as a package dependency - _see [Installation guide](https://github.com/checkout/checkout-risk-sdk-ios/blob/main/.github/partial-readmes/Installation.md) on how to add our SDK in your iOS app via SPM or Cocoapods._ 2. Obtain a public API key from [Checkout Dashboard](https://dashboard.checkout.com/developers/keys). - 3. Initialise the package with the `getInstance` method passing in the required configuration (public API key and environment), then publish the device data with the `publishData` method, see example below. + 3. Initialise the package Risk with the public API key and environment `Risk.init(config: yourConfig)` early-on. +
+ Arguments + + ```swift + public struct RiskConfig { + public let publicKey: String + public let environment: RiskEnvironment + public let framesMode: Bool + + public init(publicKey: String, environment: RiskEnvironment, framesMode: Bool = false) { + self.publicKey = publicKey + self.environment = environment + self.framesMode = framesMode + } + } + + public enum RiskEnvironment { + case qa + case sandbox + case production + } + ``` +
+ 4. Use the `configure` to complete your setup, then publish the device data within the closure with the `publishData` method. + +See example below: ```swift +import Risk + // Example usage of package let yourConfig = RiskConfig(publicKey: "pk_qa_xxx", environment: RiskEnvironment.qa) - -Risk.getInstance(config: yourConfig) { riskInstance in - riskInstance?.publishData() { response in - print(response.deviceSessionId) - } -} - ``` -### Public API -The package exposes two methods: -1. `getInstance` - This is a method that returns a singleton instance of Risk. When the method is called, preliminary checks are made to Checkout's internal API(s) that retrieves the public keys used to initialise the package used in collecting device data, if the checks fail or the merchant is disabled, nil will be returned, else, if the checks are successful, the `Risk` instance is returned to the consumer of the package which can now be used to publish the data with the `publishData` method. +self.riskSDK = Risk.init(config: yourConfig) -
- Arguments +self.riskSDK.configure { errorResponse in - ```swift - public struct RiskConfig { - public let publicKey: String - public let environment: RiskEnvironment - public let framesMode: Bool - - public init(publicKey: String, environment: RiskEnvironment, framesMode: Bool = false) { - self.publicKey = publicKey - self.environment = environment - self.framesMode = framesMode - } - } + if let errorResponse = errorResponse { + print(errorResponse.localizedDescription) + return + } - public enum RiskEnvironment { - case qa - case sandbox - case prod - } - ``` -
+ self.riskSDK.publishData { result in + switch result { + case .success(let response): + print(response.deviceSessionId) + case .failure(let errorResponse): + print(errorResponse.localizedDescription) + } + } +} + ``` + +### Public API +Aside the instantiation via the `init` method, the package exposes two methods: +1. `configure` - This method completes your setup after initialisation. When the method is called, preliminary checks are made to Checkout's internal API(s) that retrieves other configurations required for collecting device data, if the checks fail or the merchant is disabled, the error is returned and logged, you can also see more information on your Xcode console while in development mode.
Responses ```swift - public class Risk { + public func configure(completion: @escaping (Error?) -> Void) { ... - - public func publishData(...) ... { - ... - } } ```
From d0cd0325e5df1e9c81f72a4ef572614d6b00c607 Mon Sep 17 00:00:00 2001 From: Precious OSSAI Date: Tue, 27 Feb 2024 17:08:01 +0000 Subject: [PATCH 11/18] refactor!: return and error types --- Sources/Risk/Risk.swift | 107 +++++++++--------- Sources/Risk/RiskSDKConfig.swift | 6 +- Sources/Risk/Services/DeviceDataService.swift | 59 +++++----- .../Risk/Services/FingerprintService.swift | 28 ++--- Sources/Risk/Services/RiskError.swift | 63 +++++++---- Tests/Mocks/MockDeviceDataService.swift | 10 +- Tests/Mocks/MockFingerprintService.swift | 5 +- Tests/RiskTests/DeviceDataServiceTests.swift | 7 +- .../RiskExample.xcodeproj/project.pbxproj | 2 +- .../RiskExample/ContentView.swift | 56 ++++----- 10 files changed, 184 insertions(+), 159 deletions(-) diff --git a/Sources/Risk/Risk.swift b/Sources/Risk/Risk.swift index 4c9214e..0c4900e 100644 --- a/Sources/Risk/Risk.swift +++ b/Sources/Risk/Risk.swift @@ -9,63 +9,64 @@ import Foundation public final class Risk { - private let internalConfig: RiskSDKInternalConfig - private let deviceDataService: DeviceDataService - private let loggerService: LoggerServiceProtocol - - private var fingerprintService: FingerprintService? - - public init(config: RiskConfig) { - internalConfig = RiskSDKInternalConfig(config: config) - loggerService = LoggerService(internalConfig: internalConfig) - deviceDataService = DeviceDataService(config: internalConfig, loggerService: loggerService) - } - - public func configure(completion: @escaping (Error?) -> Void) { - deviceDataService.getConfiguration { [weak self] result in - guard let self = self else { return } - - switch result { - case .success(let configuration): - let fingerprintPublicKey = configuration.fingerprintIntegration.publicKey! - self.fingerprintService = FingerprintService(fingerprintPublicKey: fingerprintPublicKey, - internalConfig: self.internalConfig, - loggerService: self.loggerService) - completion(nil) - - case .failure(let error): - return completion(error) - } + private let internalConfig: RiskSDKInternalConfig + private let deviceDataService: DeviceDataService + private let loggerService: LoggerServiceProtocol + + private var fingerprintService: FingerprintService? + + public init(config: RiskConfig) { + internalConfig = RiskSDKInternalConfig(config: config) + loggerService = LoggerService(internalConfig: internalConfig) + deviceDataService = DeviceDataService(config: internalConfig, loggerService: loggerService) } - } - - public func publishData (cardToken: String? = nil, completion: @escaping (Result) -> Void) { - guard let fingerprintService = fingerprintService else { - completion(.failure(.fingerprintServiceIsNotConfigured)) - return + + public func configure(completion: @escaping (Result) -> Void) { + deviceDataService.getConfiguration { [weak self] result in + guard let self = self else { return } + + switch result { + case .success(let configuration): + self.fingerprintService = FingerprintService( + fingerprintPublicKey: configuration.publicKey, + internalConfig: self.internalConfig, + loggerService: self.loggerService + ) + completion(.success(())) + + case .failure(let error): + completion(.failure(error)) + } + } } - fingerprintService.publishData { [weak self] fpResult in - guard let self = self else { return } - - switch fpResult { - case .success(let requestId): - self.persistFpData(cardToken: cardToken, fingerprintRequestId: requestId, completion: completion) + public func publishData (cardToken: String? = nil, completion: @escaping (Result) -> Void) { + guard let fingerprintService = fingerprintService else { + completion(.failure(.fingerprintServiceIsNotConfigured)) + return + } - case .failure(let error): - completion(.failure(error)) - } + fingerprintService.publishData { [weak self] fpResult in + guard let self = self else { return } + + switch fpResult { + case .success(let requestId): + self.persistFpData(cardToken: cardToken, fingerprintRequestId: requestId, completion: completion) + + case .failure(let error): + completion(.failure(error)) + } + } } - } - - private func persistFpData(cardToken: String?, fingerprintRequestId: String, completion: @escaping (Result) -> Void) { - self.deviceDataService.persistFpData(fingerprintRequestId: fingerprintRequestId, cardToken: cardToken) { result in - switch result { - case .success(let response): - completion(.success(PublishRiskData(deviceSessionId: response.deviceSessionId))) - case .failure(let error): - completion(.failure(error)) - } + + private func persistFpData(cardToken: String?, fingerprintRequestId: String, completion: @escaping (Result) -> Void) { + self.deviceDataService.persistFpData(fingerprintRequestId: fingerprintRequestId, cardToken: cardToken) { result in + switch result { + case .success(let response): + completion(.success(PublishRiskData(deviceSessionId: response.deviceSessionId))) + case .failure(let error): + completion(.failure(error)) + } + } } - } } diff --git a/Sources/Risk/RiskSDKConfig.swift b/Sources/Risk/RiskSDKConfig.swift index 326e742..fa48193 100644 --- a/Sources/Risk/RiskSDKConfig.swift +++ b/Sources/Risk/RiskSDKConfig.swift @@ -16,9 +16,9 @@ public enum RiskEnvironment: String { } public struct RiskConfig { - public let publicKey: String - public let environment: RiskEnvironment - public let framesMode: Bool + let publicKey: String + let environment: RiskEnvironment + let framesMode: Bool public init(publicKey: String, environment: RiskEnvironment, framesMode: Bool = false) { self.publicKey = publicKey diff --git a/Sources/Risk/Services/DeviceDataService.swift b/Sources/Risk/Services/DeviceDataService.swift index f22c361..d50b5b5 100644 --- a/Sources/Risk/Services/DeviceDataService.swift +++ b/Sources/Risk/Services/DeviceDataService.swift @@ -13,16 +13,20 @@ struct FingerprintIntegration: Decodable, Equatable { let publicKey: String? } +struct FingerprintConfiguration: Equatable { + let publicKey: String +} + struct DeviceDataConfiguration: Decodable, Equatable { let fingerprintIntegration: FingerprintIntegration } struct PersistDeviceDataServiceData: Codable, Equatable { - + private enum CodingKeys: String, CodingKey { case integrationType, fingerprintRequestId = "fpRequestId", cardToken } - + let integrationType: RiskIntegrationType let fingerprintRequestId: String let cardToken: String? @@ -30,76 +34,77 @@ struct PersistDeviceDataServiceData: Codable, Equatable { struct PersistDeviceDataResponse: Decodable, Equatable { let deviceSessionId: String - + private enum CodingKeys: String, CodingKey { case deviceSessionId = "deviceSessionId" } } protocol DeviceDataServiceProtocol { - func getConfiguration(completion: @escaping (Result) -> Void) - func persistFpData(fingerprintRequestId: String, cardToken: String?, completion: @escaping (Result) -> Void) + func getConfiguration(completion: @escaping (Result) -> Void) + func persistFpData(fingerprintRequestId: String, cardToken: String?, completion: @escaping (Result) -> Void) } struct DeviceDataService: DeviceDataServiceProtocol { let config: RiskSDKInternalConfig let apiService: APIServiceProtocol let loggerService: LoggerServiceProtocol - + init(config: RiskSDKInternalConfig, apiService: APIServiceProtocol = APIService(), loggerService: LoggerServiceProtocol) { self.config = config self.apiService = apiService self.loggerService = loggerService } - - func getConfiguration(completion: @escaping (Result) -> Void) { + + func getConfiguration(completion: @escaping (Result) -> Void) { let endpoint = "\(config.deviceDataEndpoint)/configuration?integrationType=\(config.integrationType.rawValue)&riskSdkVersion=\(Constants.riskSdkVersion)" let authToken = config.merchantPublicKey - + apiService.getJSONFromAPIWithAuthorization(endpoint: endpoint, authToken: authToken, responseType: DeviceDataConfiguration.self) { result in switch result { case .success(let configuration): - - guard configuration.fingerprintIntegration.enabled && configuration.fingerprintIntegration.publicKey != nil else { - loggerService.log(riskEvent: .publishDisabled, deviceSessionId: nil, requestId: nil, error: RiskLogError(reason: "getConfiguration", message: "Integration disabled", status: nil, type: "Error")) - - return completion(.failure(RiskError.integrationDisabled)) + + guard configuration.fingerprintIntegration.enabled, let fingerprintPublicKey = configuration.fingerprintIntegration.publicKey else { + loggerService.log(riskEvent: .publishDisabled, deviceSessionId: nil, requestId: nil, error: RiskLogError(reason: "getConfiguration", message: RiskError.Configuration.integrationDisabled.localizedDescription, status: nil, type: "Error")) + + return completion(.failure(.integrationDisabled)) } - - completion(.success(configuration)) + + completion(.success( + FingerprintConfiguration.init(publicKey: fingerprintPublicKey))) case .failure(let error): - + loggerService.log(riskEvent: .loadFailure, deviceSessionId: nil, requestId: nil, error: RiskLogError(reason: "getConfiguration", message: error.localizedDescription, status: nil, type: "Error")) - return completion(.failure(RiskError.couldNotRetrieveConfiguration)) + return completion(.failure(.couldNotRetrieveConfiguration)) } } } - - func persistFpData(fingerprintRequestId: String, cardToken: String?, completion: @escaping (Result) -> Void) { + + func persistFpData(fingerprintRequestId: String, cardToken: String?, completion: @escaping (Result) -> Void) { let endpoint = "\(config.deviceDataEndpoint)/fingerprint?riskSdkVersion=\(Constants.riskSdkVersion)" let authToken = config.merchantPublicKey let integrationType = config.integrationType - + let data = PersistDeviceDataServiceData( integrationType: integrationType, fingerprintRequestId: fingerprintRequestId, cardToken: cardToken ) - + apiService.putDataToAPIWithAuthorization(endpoint: endpoint, authToken: authToken, data: data, responseType: PersistDeviceDataResponse.self) { result in - + switch result { case .success(let response): loggerService.log(riskEvent: .published, deviceSessionId: response.deviceSessionId, requestId: fingerprintRequestId, error: nil) - + completion(.success(response)) case .failure(let error): loggerService.log(riskEvent: .publishFailure, deviceSessionId: nil, requestId: nil, error: RiskLogError(reason: "persistFpData", message: error.localizedDescription, status: nil, type: "Error")) - - completion(.failure(RiskError.couldNotPersisRiskData)) + + completion(.failure(.couldNotPersisRiskData)) } } } - + } diff --git a/Sources/Risk/Services/FingerprintService.swift b/Sources/Risk/Services/FingerprintService.swift index e9f0cdd..ea489be 100644 --- a/Sources/Risk/Services/FingerprintService.swift +++ b/Sources/Risk/Services/FingerprintService.swift @@ -9,7 +9,7 @@ import FingerprintPro import Foundation protocol FingerprintServiceProtocol { - func publishData(completion: @escaping (Result) -> Void) + func publishData(completion: @escaping (Result) -> Void) } extension FingerprintServiceProtocol { @@ -17,7 +17,7 @@ extension FingerprintServiceProtocol { var meta = Metadata() meta.setTag(sourceType, forKey: "fpjsSource") meta.setTag(Date().timeIntervalSince1970 * 1000, forKey: "fpjsTimestamp") - + return meta } } @@ -27,7 +27,7 @@ final class FingerprintService: FingerprintServiceProtocol { private let client: FingerprintClientProviding private let internalConfig: RiskSDKInternalConfig private let loggerService: LoggerServiceProtocol - + init(fingerprintPublicKey: String, internalConfig: RiskSDKInternalConfig, loggerService: LoggerServiceProtocol) { let customDomain: Region = .custom(domain: internalConfig.fingerprintEndpoint) let configuration = Configuration(apiKey: fingerprintPublicKey, region: customDomain) @@ -35,30 +35,30 @@ final class FingerprintService: FingerprintServiceProtocol { self.internalConfig = internalConfig self.loggerService = loggerService } - - func publishData(completion: @escaping (Result) -> Void) { - + + func publishData(completion: @escaping (Result) -> Void) { + guard requestId == nil else { return completion(.success(requestId!)) } - + let metadata = createMetadata(sourceType: internalConfig.sourceType.rawValue) - + client.getVisitorIdResponse(metadata) { [weak self] result in - + switch result { case .failure(let error): self?.loggerService.log(riskEvent: .publishFailure, deviceSessionId: nil, requestId: nil, error: RiskLogError(reason: "publishData", message: error.localizedDescription, status: nil, type: "Error")) - - return completion(.failure(RiskError.couldNotPublishRiskData)) + + return completion(.failure(.couldNotPublishRiskData)) case let .success(response): self?.loggerService.log(riskEvent: .collected, deviceSessionId: nil, requestId: response.requestId, error: nil) self?.requestId = response.requestId - + completion(.success(response.requestId)) } } } - - + + } diff --git a/Sources/Risk/Services/RiskError.swift b/Sources/Risk/Services/RiskError.swift index d6d70b2..a2a9cb5 100644 --- a/Sources/Risk/Services/RiskError.swift +++ b/Sources/Risk/Services/RiskError.swift @@ -1,6 +1,6 @@ // // RiskError.swift -// +// // // Created by Precious Ossai on 13/10/2023. // @@ -8,28 +8,45 @@ import Foundation public enum RiskError: LocalizedError, Equatable { - case integrationDisabled - case couldNotPublishRiskData - case couldNotRetrieveConfiguration - case couldNotPersisRiskData - case fingerprintServiceIsNotConfigured - - public var errorDescription: String? { - switch self { - case .integrationDisabled: - return "Integration disabled" - - case .couldNotPublishRiskData: - return "Error publishing risk data" - - case .couldNotRetrieveConfiguration: - return "Error retrieving configuration" - - case .couldNotPersisRiskData: - return "Error persisting risk data" + case configuration(Configuration) + case publish(Publish) +} - case .fingerprintServiceIsNotConfigured: - return "Fingerprint service is not configured. Please call configure() method first." +public extension RiskError { + enum Configuration: LocalizedError { + case integrationDisabled + case couldNotRetrieveConfiguration + + + public var errorDescription: String? { + switch self { + case .integrationDisabled: + return "Integration disabled" + + case .couldNotRetrieveConfiguration: + return "Error retrieving configuration" + } + } + } + + enum Publish: LocalizedError { + case couldNotPublishRiskData + case couldNotPersisRiskData + case fingerprintServiceIsNotConfigured + + + public var errorDescription: String? { + switch self { + case .couldNotPublishRiskData: + return "Error publishing risk data" + + case .couldNotPersisRiskData: + return "Error persisting risk data" + + case .fingerprintServiceIsNotConfigured: + return "Fingerprint service is not configured. Please call configure() method first." + } + } } - } + } diff --git a/Tests/Mocks/MockDeviceDataService.swift b/Tests/Mocks/MockDeviceDataService.swift index 6abb0ea..a5580f3 100644 --- a/Tests/Mocks/MockDeviceDataService.swift +++ b/Tests/Mocks/MockDeviceDataService.swift @@ -12,21 +12,21 @@ class MockDeviceDataService: DeviceDataServiceProtocol { var shouldReturnConfiguration: Bool = true var shouldSucceedPersistFpData: Bool = true - func getConfiguration(completion: @escaping (Result) -> Void) { + func getConfiguration(completion: @escaping (Result) -> Void) { if shouldReturnConfiguration { - let configuration = DeviceDataConfiguration(fingerprintIntegration: FingerprintIntegration(enabled: true, publicKey: "mocked_public_key")) + let configuration = FingerprintConfiguration(publicKey: "mocked_public_key") completion(.success(configuration)) } else { - completion(.failure(RiskError.couldNotRetrieveConfiguration)) + completion(.failure(.couldNotRetrieveConfiguration)) } } - func persistFpData(fingerprintRequestId: String, cardToken: String?, completion: @escaping (Result) -> Void) { + func persistFpData(fingerprintRequestId: String, cardToken: String?, completion: @escaping (Result) -> Void) { if shouldSucceedPersistFpData { let response = PersistDeviceDataResponse(deviceSessionId: "mocked_device_session_id") completion(.success(response)) } else { - completion(.failure(RiskError.couldNotPersisRiskData)) + completion(.failure(.couldNotPersisRiskData)) } } } diff --git a/Tests/Mocks/MockFingerprintService.swift b/Tests/Mocks/MockFingerprintService.swift index 277b70b..3247d89 100644 --- a/Tests/Mocks/MockFingerprintService.swift +++ b/Tests/Mocks/MockFingerprintService.swift @@ -12,7 +12,7 @@ class MockFingerprintService: FingerprintServiceProtocol { var shouldSucceed: Bool = true var requestId: String? - func publishData(completion: @escaping (Result) -> Void) { + func publishData(completion: @escaping (Result) -> Void) { if shouldSucceed { if let requestId = requestId { completion(.success(requestId)) @@ -21,8 +21,7 @@ class MockFingerprintService: FingerprintServiceProtocol { completion(.success(fakeRequestId)) } } else { - let error = RiskError.couldNotPublishRiskData - completion(.failure(error)) + completion(.failure(.couldNotPublishRiskData)) } } } diff --git a/Tests/RiskTests/DeviceDataServiceTests.swift b/Tests/RiskTests/DeviceDataServiceTests.swift index 2433e29..217dd50 100644 --- a/Tests/RiskTests/DeviceDataServiceTests.swift +++ b/Tests/RiskTests/DeviceDataServiceTests.swift @@ -22,12 +22,13 @@ class DeviceDataServiceTests: XCTestCase { let expectation = self.expectation(description: "Configuration received") - let expectedConfiguration = DeviceDataConfiguration(fingerprintIntegration: FingerprintIntegration(enabled: true, publicKey: "mockPublicKey")) + let expectedApiConfiguration = DeviceDataConfiguration(fingerprintIntegration: FingerprintIntegration(enabled: true, publicKey: "mockPublicKey")) + let expectedDeviceDataServiceConfiguration = FingerprintConfiguration(publicKey: "mockPublicKey") - mockAPIService.expectedResult = .success(expectedConfiguration) + mockAPIService.expectedResult = .success(expectedApiConfiguration) deviceDataService.getConfiguration { configuration in - XCTAssertEqual(configuration, .success(expectedConfiguration)) + XCTAssertEqual(configuration, .success(expectedDeviceDataServiceConfiguration)) expectation.fulfill() } diff --git a/iOSExampleRiskSPM/RiskExample.xcodeproj/project.pbxproj b/iOSExampleRiskSPM/RiskExample.xcodeproj/project.pbxproj index 479f5ce..97bb57e 100644 --- a/iOSExampleRiskSPM/RiskExample.xcodeproj/project.pbxproj +++ b/iOSExampleRiskSPM/RiskExample.xcodeproj/project.pbxproj @@ -613,7 +613,7 @@ repositoryURL = "https://github.com/checkout/checkout-risk-sdk-ios"; requirement = { kind = exactVersion; - version = 1.0.4; + version = 1.1.0; }; }; /* End XCRemoteSwiftPackageReference section */ diff --git a/iOSExampleRiskSPM/RiskExample/ContentView.swift b/iOSExampleRiskSPM/RiskExample/ContentView.swift index 780df5c..8fff1dd 100644 --- a/iOSExampleRiskSPM/RiskExample/ContentView.swift +++ b/iOSExampleRiskSPM/RiskExample/ContentView.swift @@ -16,58 +16,60 @@ struct ContentView: View { @State private var enabled: Bool = false @State private var checked: Bool = false @State private var loading: Bool = false - + @State private var riskSDK: Risk! - + var body: some View { Text("Risk iOS Example - SPM").padding(.bottom).frame(maxWidth: .infinity, alignment: .center).font(.title) - + VStack(alignment: .leading) { - + Text("Card no: 0000 1234 6549 15151") Text("Card exp: 12/26") Text("Card CVV: 500").padding(.bottom) - + } .padding().background(Color.gray.opacity(0.1)) - + Button("Pay $1400") { guard let publicKey = ProcessInfo.processInfo.environment["SAMPLE_MERCHANT_PUBLIC_KEY"] else { error = "Environment variable (SAMPLE_MERCHANT_PUBLIC_KEY) not set" return } - + let yourConfig = RiskConfig(publicKey: publicKey, environment: RiskEnvironment.qa) self.riskSDK = Risk.init(config: yourConfig) - + checked = true loading = true - error = nil - - self.riskSDK.configure { errorResponse in + + + self.riskSDK.configure { configurationResult in + loading = false - - if let errorResponse = errorResponse { + + switch configurationResult { + case .failure(let errorResponse): error = errorResponse.localizedDescription enabled = false - return - } - - enabled = true - - self.riskSDK.publishData { result in - - switch result { - case .success(let response): - deviceSessionId = response.deviceSessionId - case .failure(let errorResponse): - deviceSessionId = nil - error = errorResponse.localizedDescription + case .success(): + error = nil + enabled = true + self.riskSDK.publishData { result in + + switch result { + case .success(let response): + deviceSessionId = response.deviceSessionId + case .failure(let errorResponse): + deviceSessionId = nil + error = errorResponse.localizedDescription + } } } + } }.padding().background(Color.blue.opacity(0.9)).cornerRadius(8).frame(maxWidth: .infinity, alignment: .center).foregroundColor(.white).padding(.top) - + Text(error ?? (!checked ? .init() : loading ? "Loading..." : enabled && deviceSessionId != nil ? "Device session id: \(deviceSessionId!)" : "Integration disabled") ).padding(.top).multilineTextAlignment(.center) } } From 3a5c600a45e2ebd31c9b2fbf0e85df55d18f049b Mon Sep 17 00:00:00 2001 From: Precious OSSAI Date: Tue, 27 Feb 2024 17:10:48 +0000 Subject: [PATCH 12/18] chore: remove Risk from external package dependency list in SPM example --- .../RiskExample.xcodeproj/project.pbxproj | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/iOSExampleRiskSPM/RiskExample.xcodeproj/project.pbxproj b/iOSExampleRiskSPM/RiskExample.xcodeproj/project.pbxproj index 97bb57e..c53b861 100644 --- a/iOSExampleRiskSPM/RiskExample.xcodeproj/project.pbxproj +++ b/iOSExampleRiskSPM/RiskExample.xcodeproj/project.pbxproj @@ -16,7 +16,6 @@ BA0B00662AD6A52A0037D9FF /* RiskExampleUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA0B00652AD6A52A0037D9FF /* RiskExampleUITestsLaunchTests.swift */; }; BA13934B2AF9416200D89A8D /* Risk in Frameworks */ = {isa = PBXBuildFile; productRef = BA13934A2AF9416200D89A8D /* Risk */; }; BA1927362B58159E00700874 /* Risk in Frameworks */ = {isa = PBXBuildFile; productRef = BA1927352B58159E00700874 /* Risk */; }; - BA78E54C2B7B84A600317F46 /* Risk in Frameworks */ = {isa = PBXBuildFile; productRef = BA78E54B2B7B84A600317F46 /* Risk */; }; BA9442362AEFE8970037BFCB /* Risk in Frameworks */ = {isa = PBXBuildFile; productRef = BA9442352AEFE8970037BFCB /* Risk */; }; BABAD8F72B72712A00E91DF4 /* Risk in Frameworks */ = {isa = PBXBuildFile; productRef = BABAD8F62B72712A00E91DF4 /* Risk */; }; /* End PBXBuildFile section */ @@ -58,7 +57,6 @@ buildActionMask = 2147483647; files = ( BA1927362B58159E00700874 /* Risk in Frameworks */, - BA78E54C2B7B84A600317F46 /* Risk in Frameworks */, BABAD8F72B72712A00E91DF4 /* Risk in Frameworks */, BA9442362AEFE8970037BFCB /* Risk in Frameworks */, BA13934B2AF9416200D89A8D /* Risk in Frameworks */, @@ -160,7 +158,6 @@ BA13934A2AF9416200D89A8D /* Risk */, BA1927352B58159E00700874 /* Risk */, BABAD8F62B72712A00E91DF4 /* Risk */, - BA78E54B2B7B84A600317F46 /* Risk */, ); productName = RiskExample; productReference = BA0B00452AD6A5280037D9FF /* RiskExample.app */; @@ -235,7 +232,6 @@ ); mainGroup = BA0B003C2AD6A5280037D9FF; packageReferences = ( - BA78E54A2B7B84A600317F46 /* XCRemoteSwiftPackageReference "checkout-risk-sdk-ios" */, ); productRefGroup = BA0B00462AD6A5280037D9FF /* Products */; projectDirPath = ""; @@ -607,17 +603,6 @@ }; /* End XCConfigurationList section */ -/* Begin XCRemoteSwiftPackageReference section */ - BA78E54A2B7B84A600317F46 /* XCRemoteSwiftPackageReference "checkout-risk-sdk-ios" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/checkout/checkout-risk-sdk-ios"; - requirement = { - kind = exactVersion; - version = 1.1.0; - }; - }; -/* End XCRemoteSwiftPackageReference section */ - /* Begin XCSwiftPackageProductDependency section */ BA13934A2AF9416200D89A8D /* Risk */ = { isa = XCSwiftPackageProductDependency; @@ -627,11 +612,6 @@ isa = XCSwiftPackageProductDependency; productName = Risk; }; - BA78E54B2B7B84A600317F46 /* Risk */ = { - isa = XCSwiftPackageProductDependency; - package = BA78E54A2B7B84A600317F46 /* XCRemoteSwiftPackageReference "checkout-risk-sdk-ios" */; - productName = Risk; - }; BA9442352AEFE8970037BFCB /* Risk */ = { isa = XCSwiftPackageProductDependency; productName = Risk; From 6d33d97b5eacdc97aa1fc3cc1ec34b5e1798d8b4 Mon Sep 17 00:00:00 2001 From: Precious OSSAI Date: Wed, 28 Feb 2024 11:24:34 +0000 Subject: [PATCH 13/18] refactor!: update docs --- README.md | 119 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 77 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 0226c13..97201fa 100644 --- a/README.md +++ b/README.md @@ -31,13 +31,13 @@ The package helps collect device data for merchants with direct integration (sta 2. Obtain a public API key from [Checkout Dashboard](https://dashboard.checkout.com/developers/keys). 3. Initialise the package Risk with the public API key and environment `Risk.init(config: yourConfig)` early-on.
- Arguments + Type definitions ```swift public struct RiskConfig { - public let publicKey: String - public let environment: RiskEnvironment - public let framesMode: Bool + let publicKey: String + let environment: RiskEnvironment + let framesMode: Bool public init(publicKey: String, environment: RiskEnvironment, framesMode: Bool = false) { self.publicKey = publicKey @@ -55,6 +55,60 @@ The package helps collect device data for merchants with direct integration (sta
4. Use the `configure` to complete your setup, then publish the device data within the closure with the `publishData` method. +
+ Type definitions + + ```swift + public struct PublishRiskData { + public let deviceSessionId: String + } + + public enum RiskError: LocalizedError, Equatable { + case configuration(Configuration) + case publish(Publish) + } + + public extension RiskError { + enum Configuration: LocalizedError { + case integrationDisabled + case couldNotRetrieveConfiguration + + + public var errorDescription: String? { + switch self { + case .integrationDisabled: + return "Integration disabled" + + case .couldNotRetrieveConfiguration: + return "Error retrieving configuration" + } + } + } + + enum Publish: LocalizedError { + case couldNotPublishRiskData + case couldNotPersisRiskData + case fingerprintServiceIsNotConfigured + + + public var errorDescription: String? { + switch self { + case .couldNotPublishRiskData: + return "Error publishing risk data" + + case .couldNotPersisRiskData: + return "Error persisting risk data" + + case .fingerprintServiceIsNotConfigured: + return "Fingerprint service is not configured. Please call configure() method first." + } + } + } + + } + ``` +
+ See example below: ```swift import Risk @@ -62,35 +116,36 @@ import Risk // Example usage of package let yourConfig = RiskConfig(publicKey: "pk_qa_xxx", environment: RiskEnvironment.qa) -self.riskSDK = Risk.init(config: yourConfig) +self.riskSDK = Risk.init(config: yourConfig) -self.riskSDK.configure { errorResponse in +self.riskSDK.configure { configurationResult in - if let errorResponse = errorResponse { + switch configurationResult { + case .failure(let errorResponse): print(errorResponse.localizedDescription) - return - } - - self.riskSDK.publishData { result in - - switch result { - case .success(let response): - print(response.deviceSessionId) - case .failure(let errorResponse): - print(errorResponse.localizedDescription) + case .success(): + self.riskSDK.publishData { result in + + switch result { + case .success(let response): + print(response.deviceSessionId) + case .failure(let errorResponse): + print(errorResponse.localizedDescription) + } } } -} + +} ``` ### Public API Aside the instantiation via the `init` method, the package exposes two methods: 1. `configure` - This method completes your setup after initialisation. When the method is called, preliminary checks are made to Checkout's internal API(s) that retrieves other configurations required for collecting device data, if the checks fail or the merchant is disabled, the error is returned and logged, you can also see more information on your Xcode console while in development mode.
- Responses + Type definitions ```swift - public func configure(completion: @escaping (Error?) -> Void) { + public func configure(completion: @escaping (Result) -> Void) { ... } ``` @@ -100,35 +155,15 @@ Aside the instantiation via the `init` method, the package exposes two methods: 2. `publishData` - This is used to publish and persist the device data.
- Arguments + Type definitions ```swift - public func publishData(cardToken: String? = nil, completion: @escaping (Result) -> Void) { + public func publishData (cardToken: String? = nil, completion: @escaping (Result) -> Void) { ... } ```
-
- Responses - - ```swift - public struct PublishRiskData { - public let deviceSessionId: String - } - - public enum RiskError: Error, Equatable { - case description(String) - - var localizedDescription: String { - switch self { - case .description(let errorMessage): - return errorMessage - } - } - } - ``` -
### Additional Resources From 0a8cacecce410db70b97e1168976925c32fa68b9 Mon Sep 17 00:00:00 2001 From: Precious OSSAI Date: Wed, 28 Feb 2024 11:25:31 +0000 Subject: [PATCH 14/18] chore: bump version --- .github/partial-readmes/Installation.md | 4 ++-- Risk.podspec | 2 +- Sources/Risk/Logging/Constants.swift | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/partial-readmes/Installation.md b/.github/partial-readmes/Installation.md index acd2468..615e844 100644 --- a/.github/partial-readmes/Installation.md +++ b/.github/partial-readmes/Installation.md @@ -9,7 +9,7 @@ We've done our best to support the most common distribution methods on iOS. We a let package = Package( ... dependencies: [ - .package(url: "https://github.com/checkout/checkout-risk-sdk-ios", from: "1.1.0") + .package(url: "https://github.com/checkout/checkout-risk-sdk-ios", from: "1.1.1") ] ... ) @@ -34,7 +34,7 @@ platform :ios, '12.0' use_frameworks! target '' do - pod 'Risk', '~> 1.1.0' + pod 'Risk', '~> 1.1.1' end ``` diff --git a/Risk.podspec b/Risk.podspec index 910bf1a..db003c5 100644 --- a/Risk.podspec +++ b/Risk.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "Risk" - s.version = "1.1.0" + s.version = "1.1.1" s.summary = "Checkout Risk package in Swift" s.description = <<-DESC Checkout Risk package in Swift. diff --git a/Sources/Risk/Logging/Constants.swift b/Sources/Risk/Logging/Constants.swift index 2295b17..34cc7f4 100644 --- a/Sources/Risk/Logging/Constants.swift +++ b/Sources/Risk/Logging/Constants.swift @@ -9,7 +9,7 @@ import Foundation enum Constants { static let productName = "risk-ios-sdk" - static let riskSdkVersion = "1.1.0" + static let riskSdkVersion = "1.1.1" static let userAgent = "checkout-sdk-risk-ios/\(riskSdkVersion)" static let loggerTypeIdentifier = "com.checkout.risk-mobile-sdk" } From d3f9ae027a07083c51d0515c95bc254aba78dafd Mon Sep 17 00:00:00 2001 From: Precious OSSAI Date: Wed, 28 Feb 2024 13:16:30 +0000 Subject: [PATCH 15/18] chore --- Sources/Risk/Services/RiskError.swift | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Sources/Risk/Services/RiskError.swift b/Sources/Risk/Services/RiskError.swift index a2a9cb5..4e088a7 100644 --- a/Sources/Risk/Services/RiskError.swift +++ b/Sources/Risk/Services/RiskError.swift @@ -7,7 +7,7 @@ import Foundation -public enum RiskError: LocalizedError, Equatable { +public enum RiskError { case configuration(Configuration) case publish(Publish) } @@ -17,7 +17,6 @@ public extension RiskError { case integrationDisabled case couldNotRetrieveConfiguration - public var errorDescription: String? { switch self { case .integrationDisabled: @@ -34,7 +33,6 @@ public extension RiskError { case couldNotPersisRiskData case fingerprintServiceIsNotConfigured - public var errorDescription: String? { switch self { case .couldNotPublishRiskData: @@ -48,5 +46,4 @@ public extension RiskError { } } } - } From bd8adbe6011a14165a96cd31e6bf9a5dd1936b6d Mon Sep 17 00:00:00 2001 From: Precious OSSAI Date: Wed, 28 Feb 2024 13:16:44 +0000 Subject: [PATCH 16/18] chore: update docs --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 97201fa..476d474 100644 --- a/README.md +++ b/README.md @@ -68,12 +68,16 @@ The package helps collect device data for merchants with direct integration (sta case publish(Publish) } + public enum RiskError { + case configuration(Configuration) + case publish(Publish) + } + public extension RiskError { enum Configuration: LocalizedError { case integrationDisabled case couldNotRetrieveConfiguration - public var errorDescription: String? { switch self { case .integrationDisabled: @@ -90,7 +94,6 @@ The package helps collect device data for merchants with direct integration (sta case couldNotPersisRiskData case fingerprintServiceIsNotConfigured - public var errorDescription: String? { switch self { case .couldNotPublishRiskData: @@ -104,7 +107,6 @@ The package helps collect device data for merchants with direct integration (sta } } } - } ```
From e35ecfa7dce654203615804f1616a982591a6399 Mon Sep 17 00:00:00 2001 From: Precious OSSAI Date: Wed, 28 Feb 2024 13:16:57 +0000 Subject: [PATCH 17/18] chore: bump version --- .github/partial-readmes/Installation.md | 4 ++-- Risk.podspec | 2 +- Sources/Risk/Logging/Constants.swift | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/partial-readmes/Installation.md b/.github/partial-readmes/Installation.md index 615e844..da6fb4f 100644 --- a/.github/partial-readmes/Installation.md +++ b/.github/partial-readmes/Installation.md @@ -9,7 +9,7 @@ We've done our best to support the most common distribution methods on iOS. We a let package = Package( ... dependencies: [ - .package(url: "https://github.com/checkout/checkout-risk-sdk-ios", from: "1.1.1") + .package(url: "https://github.com/checkout/checkout-risk-sdk-ios", from: "2.0.0") ] ... ) @@ -34,7 +34,7 @@ platform :ios, '12.0' use_frameworks! target '' do - pod 'Risk', '~> 1.1.1' + pod 'Risk', '~> 2.0.0' end ``` diff --git a/Risk.podspec b/Risk.podspec index db003c5..cba5928 100644 --- a/Risk.podspec +++ b/Risk.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "Risk" - s.version = "1.1.1" + s.version = "2.0.0" s.summary = "Checkout Risk package in Swift" s.description = <<-DESC Checkout Risk package in Swift. diff --git a/Sources/Risk/Logging/Constants.swift b/Sources/Risk/Logging/Constants.swift index 34cc7f4..ad8f99b 100644 --- a/Sources/Risk/Logging/Constants.swift +++ b/Sources/Risk/Logging/Constants.swift @@ -9,7 +9,7 @@ import Foundation enum Constants { static let productName = "risk-ios-sdk" - static let riskSdkVersion = "1.1.1" + static let riskSdkVersion = "2.0.0" static let userAgent = "checkout-sdk-risk-ios/\(riskSdkVersion)" static let loggerTypeIdentifier = "com.checkout.risk-mobile-sdk" } From f18c375e23b1798eef7c2bb4619a06b67ae2a397 Mon Sep 17 00:00:00 2001 From: Precious OSSAI Date: Wed, 28 Feb 2024 13:33:19 +0000 Subject: [PATCH 18/18] chore: bump version --- .github/partial-readmes/Installation.md | 4 ++-- Risk.podspec | 2 +- Sources/Risk/Logging/Constants.swift | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/partial-readmes/Installation.md b/.github/partial-readmes/Installation.md index da6fb4f..efa302a 100644 --- a/.github/partial-readmes/Installation.md +++ b/.github/partial-readmes/Installation.md @@ -9,7 +9,7 @@ We've done our best to support the most common distribution methods on iOS. We a let package = Package( ... dependencies: [ - .package(url: "https://github.com/checkout/checkout-risk-sdk-ios", from: "2.0.0") + .package(url: "https://github.com/checkout/checkout-risk-sdk-ios", from: "2.0.1") ] ... ) @@ -34,7 +34,7 @@ platform :ios, '12.0' use_frameworks! target '' do - pod 'Risk', '~> 2.0.0' + pod 'Risk', '~> 2.0.1' end ``` diff --git a/Risk.podspec b/Risk.podspec index cba5928..6334cfb 100644 --- a/Risk.podspec +++ b/Risk.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "Risk" - s.version = "2.0.0" + s.version = "2.0.1" s.summary = "Checkout Risk package in Swift" s.description = <<-DESC Checkout Risk package in Swift. diff --git a/Sources/Risk/Logging/Constants.swift b/Sources/Risk/Logging/Constants.swift index ad8f99b..c3866a4 100644 --- a/Sources/Risk/Logging/Constants.swift +++ b/Sources/Risk/Logging/Constants.swift @@ -9,7 +9,7 @@ import Foundation enum Constants { static let productName = "risk-ios-sdk" - static let riskSdkVersion = "2.0.0" + static let riskSdkVersion = "2.0.1" static let userAgent = "checkout-sdk-risk-ios/\(riskSdkVersion)" static let loggerTypeIdentifier = "com.checkout.risk-mobile-sdk" }