From 9a1dc93bcbb261072291bc183714c3ec2ab5ef24 Mon Sep 17 00:00:00 2001 From: Mubarak Sadoon Date: Tue, 8 Aug 2023 13:38:17 -0400 Subject: [PATCH] [MBL-736] Upgrade PerimeterX (#1839) * updated perimeterX integration for version 3 * Added final configuration piece to start PerimeterX * formatting * Opted to update the print statement to be inline with the previous print statements for PerimeterX captcha state. Also removed the fatalError. * removed inline comment --- Kickstarter-iOS/AppDelegate.swift | 27 ++-- Kickstarter-iOS/AppDelegateViewModel.swift | 19 --- .../AppDelegateViewModelTests.swift | 24 ---- Kickstarter.xcodeproj/project.pbxproj | 58 ++++----- .../xcshareddata/swiftpm/Package.resolved | 4 +- KsApi/ErrorHandler.swift | 6 +- KsApi/Service.swift | 7 +- KsApi/ServiceType.swift | 7 +- KsApi/ServiceTypeTests.swift | 8 -- KsApi/extensions/NSURLSession.swift | 4 +- KsApi/lib/KsApiNotification.swift | 5 - KsApi/px/MockPerimeterXTypes.swift | 31 +---- KsApi/px/PerimeterXClient.swift | 64 ++++------ KsApi/px/PerimeterXClientTests.swift | 118 ------------------ KsApi/px/PerimeterXTypes.swift | 36 +----- 15 files changed, 73 insertions(+), 345 deletions(-) delete mode 100644 KsApi/lib/KsApiNotification.swift delete mode 100644 KsApi/px/PerimeterXClientTests.swift diff --git a/Kickstarter-iOS/AppDelegate.swift b/Kickstarter-iOS/AppDelegate.swift index b14337802b..7784dff2b6 100644 --- a/Kickstarter-iOS/AppDelegate.swift +++ b/Kickstarter-iOS/AppDelegate.swift @@ -219,6 +219,12 @@ internal final class AppDelegate: UIResponder, UIApplicationDelegate { .messageBannerViewController?.showBanner(with: success ? .success : .error, message: message) } + self.viewModel.outputs.configurePerimeterX + .observeValues { + AppEnvironment.current.apiService.perimeterXClient + .start(policyDomains: [AppEnvironment.current.apiService.serverConfig.apiBaseUrl.host ?? ""]) + } + NotificationCenter.default .addObserver(forName: Notification.Name.ksr_sessionStarted, object: nil, queue: nil) { [weak self] _ in self?.viewModel.inputs.userSessionStarted() @@ -268,15 +274,6 @@ internal final class AppDelegate: UIResponder, UIApplicationDelegate { self?.viewModel.inputs.configUpdatedNotificationObserved() } - NotificationCenter.default - .addObserver( - forName: Notification.Name.ksr_perimeterXCaptcha, - object: nil, - queue: nil - ) { [weak self] note in - self?.viewModel.inputs.perimeterXCaptchaTriggeredWithUserInfo(note.userInfo) - } - self.window?.tintColor = .ksr_create_700 self.viewModel.inputs.applicationDidFinishLaunching( @@ -284,12 +281,6 @@ internal final class AppDelegate: UIResponder, UIApplicationDelegate { launchOptions: launchOptions ) - self.viewModel.outputs.goToPerimeterXCaptcha - .observeForControllerAction() - .observeValues { response in - self.goToPerimeterXCaptcha(response) - } - UNUserNotificationCenter.current().delegate = self return self.viewModel.outputs.applicationDidFinishLaunchingReturnValue @@ -407,10 +398,6 @@ internal final class AppDelegate: UIResponder, UIApplicationDelegate { self.rootTabBarController?.switchToMessageThread(messageThread) } - private func goToPerimeterXCaptcha(_ response: PerimeterXBlockResponseType) { - response.displayCaptcha(on: self.window?.rootViewController) - } - private func goToCreatorMessageThread(_ projectId: Param, _ messageThread: MessageThread) { self.rootTabBarController? .switchToCreatorMessageThread(projectId: projectId, messageThread: messageThread) @@ -436,7 +423,7 @@ internal final class AppDelegate: UIResponder, UIApplicationDelegate { _ = AppEnvironment.current.remoteConfigClient? .addOnConfigUpdateListener { configUpdate, error in guard let realtimeUpdateError = error else { - print("🔮 Remote Config Keys Update: \(configUpdate?.updatedKeys)") + print("🔮 Remote Config Keys Update: \(String(describing: configUpdate?.updatedKeys))") return } diff --git a/Kickstarter-iOS/AppDelegateViewModel.swift b/Kickstarter-iOS/AppDelegateViewModel.swift index f7d0e227ac..cc137190d6 100644 --- a/Kickstarter-iOS/AppDelegateViewModel.swift +++ b/Kickstarter-iOS/AppDelegateViewModel.swift @@ -79,9 +79,6 @@ public protocol AppDelegateViewModelInputs { /// Call when Remote Config configuration has failed func remoteConfigClientConfigurationFailed() - /// Call when Perimeter X Captcha is triggered - func perimeterXCaptchaTriggeredWithUserInfo(_ userInfo: [AnyHashable: Any]?) - /// Call when the contextual PushNotification dialog should be presented. func showNotificationDialog(notification: Notification) @@ -144,9 +141,6 @@ public protocol AppDelegateViewModelOutputs { /// Emits a message thread when we should navigate to it. var goToMessageThread: Signal { get } - /// Emits when we should display the Perimeter X Captcha view. - var goToPerimeterXCaptcha: Signal { get } - /// Emits when the root view controller should navigate to the user's profile. var goToProfile: Signal<(), Never> { get } @@ -763,13 +757,6 @@ public final class AppDelegateViewModel: AppDelegateViewModelType, AppDelegateVi .filter(isTrue) .mapConst(0) - self.goToPerimeterXCaptcha = self.perimeterXCaptchaTriggeredWithUserInfoProperty.signal.skipNil() - .map { userInfo -> PerimeterXBlockResponseType? in - guard let response = userInfo["response"] as? PerimeterXBlockResponseType else { return nil } - return response - } - .skipNil() - self.configureSegmentWithBraze = self.applicationLaunchOptionsProperty.signal .skipNil() .map { _ in @@ -948,11 +935,6 @@ public final class AppDelegateViewModel: AppDelegateViewModelType, AppDelegateVi self.remoteConfigClientConfigurationFailedProperty.value = () } - private let perimeterXCaptchaTriggeredWithUserInfoProperty = MutableProperty<[AnyHashable: Any]?>(nil) - public func perimeterXCaptchaTriggeredWithUserInfo(_ userInfo: [AnyHashable: Any]?) { - self.perimeterXCaptchaTriggeredWithUserInfoProperty.value = userInfo - } - public let applicationIconBadgeNumber: Signal public let configureAppCenterWithData: Signal public let configureFirebase: Signal<(), Never> @@ -968,7 +950,6 @@ public final class AppDelegateViewModel: AppDelegateViewModelType, AppDelegateVi public let goToDiscovery: Signal public let goToLoginWithIntent: Signal public let goToMessageThread: Signal - public let goToPerimeterXCaptcha: Signal public let goToProfile: Signal<(), Never> public let goToProjectActivities: Signal public let goToMobileSafari: Signal diff --git a/Kickstarter-iOS/AppDelegateViewModelTests.swift b/Kickstarter-iOS/AppDelegateViewModelTests.swift index a0a2b0c1c5..2583ecc5be 100644 --- a/Kickstarter-iOS/AppDelegateViewModelTests.swift +++ b/Kickstarter-iOS/AppDelegateViewModelTests.swift @@ -26,7 +26,6 @@ final class AppDelegateViewModelTests: TestCase { private let goToDiscovery = TestObserver() private let goToProjectActivities = TestObserver() private let goToLoginWithIntent = TestObserver() - private let goToPerimeterXCaptcha = TestObserver() private let goToProfile = TestObserver<(), Never>() private let goToMobileSafari = TestObserver() private let goToSearch = TestObserver<(), Never>() @@ -75,7 +74,6 @@ final class AppDelegateViewModelTests: TestCase { self.vm.outputs.goToDashboard.observe(self.goToDashboard.observer) self.vm.outputs.goToDiscovery.observe(self.goToDiscovery.observer) self.vm.outputs.goToLoginWithIntent.observe(self.goToLoginWithIntent.observer) - self.vm.outputs.goToPerimeterXCaptcha.observe(self.goToPerimeterXCaptcha.observer) self.vm.outputs.goToProfile.observe(self.goToProfile.observer) self.vm.outputs.goToMobileSafari.observe(self.goToMobileSafari.observer) self.vm.outputs.goToProjectActivities.observe(self.goToProjectActivities.observer) @@ -2222,28 +2220,6 @@ final class AppDelegateViewModelTests: TestCase { } } - func testGoToPerimeterXCaptcha_Captcha() { - self.goToPerimeterXCaptcha.assertDidNotEmitValue() - - let response = MockPerimeterXBlockResponse(blockType: .Captcha) - - self.vm.inputs.perimeterXCaptchaTriggeredWithUserInfo(["response": response]) - - self.goToPerimeterXCaptcha.assertValueCount(1) - XCTAssertEqual(self.goToPerimeterXCaptcha.values.last?.type, .Captcha) - } - - func testGoToPerimeterXCaptcha_Blocked() { - self.goToPerimeterXCaptcha.assertDidNotEmitValue() - - let response = MockPerimeterXBlockResponse(blockType: .Block) - - self.vm.inputs.perimeterXCaptchaTriggeredWithUserInfo(["response": response]) - - self.goToPerimeterXCaptcha.assertValueCount(1) - XCTAssertEqual(self.goToPerimeterXCaptcha.values.last?.type, .Block) - } - func testFeatureFlagsRetainedInConfig_NotRelease() { let mockBundle = MockBundle( bundleIdentifier: KickstarterBundleIdentifier.beta.rawValue diff --git a/Kickstarter.xcodeproj/project.pbxproj b/Kickstarter.xcodeproj/project.pbxproj index 24c2a7c49e..33599562ba 100644 --- a/Kickstarter.xcodeproj/project.pbxproj +++ b/Kickstarter.xcodeproj/project.pbxproj @@ -229,7 +229,6 @@ 19047FCF2889D4BC00BDD1A8 /* GraphAPI.CreateSetupIntentInput+CreateSetupIntentInputTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19047FCE2889D4BC00BDD1A8 /* GraphAPI.CreateSetupIntentInput+CreateSetupIntentInputTests.swift */; }; 19047FD12889D6DC00BDD1A8 /* ClientSecretEnvelope+CreateSetupIntentMutation.DataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19047FD02889D6DC00BDD1A8 /* ClientSecretEnvelope+CreateSetupIntentMutation.DataTests.swift */; }; 191A4B4C28FF3AF8009D62A5 /* ReactiveExtensions-TestHelpers in Frameworks */ = {isa = PBXBuildFile; productRef = 191A4B4B28FF3AF8009D62A5 /* ReactiveExtensions-TestHelpers */; }; - 191EDC6728E29BB9009B41B2 /* PerimeterX in Frameworks */ = {isa = PBXBuildFile; productRef = 191EDC6628E29BB9009B41B2 /* PerimeterX */; }; 19338D9B2A0D4E2300075F29 /* Stripe in Frameworks */ = {isa = PBXBuildFile; productRef = 19338D9A2A0D4E2300075F29 /* Stripe */; }; 1937A72328C9570A00DD732D /* ErroredBackingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1937A72228C9570900DD732D /* ErroredBackingView.swift */; }; 1937A72628C959DD00DD732D /* FundingGraphViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7ED205B1E83240D00BFFA01 /* FundingGraphViewTests.swift */; }; @@ -244,13 +243,14 @@ 194A8E4E2A13FB010099583B /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 194A8E4D2A13FB010099583B /* GoogleService-Info.plist */; }; 194C002E2A68447200621DC3 /* TriggerThirdPartyEventInputTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 609309922A605563004297AF /* TriggerThirdPartyEventInputTests.swift */; }; 194C002F2A6844B300621DC3 /* GraphAPI.TriggerThirdPartyEventInput+TriggerThirdPartyEventInputTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6093098E2A6054D8004297AF /* GraphAPI.TriggerThirdPartyEventInput+TriggerThirdPartyEventInputTests.swift */; }; + 195747162A71AF0B00D43CA3 /* PerimeterX_SDK in Frameworks */ = {isa = PBXBuildFile; productRef = 195747152A71AF0B00D43CA3 /* PerimeterX_SDK */; }; + 195747182A71AF1700D43CA3 /* PerimeterX_SDK in Frameworks */ = {isa = PBXBuildFile; productRef = 195747172A71AF1700D43CA3 /* PerimeterX_SDK */; }; + 1957471A2A71AF3200D43CA3 /* PerimeterX_SDK in Frameworks */ = {isa = PBXBuildFile; productRef = 195747192A71AF3200D43CA3 /* PerimeterX_SDK */; }; 1965436D28C807FB00457EC6 /* PledgePaymentMethodsViewControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 192016C728B6731A0046919B /* PledgePaymentMethodsViewControllerTests.swift */; }; 1965437428C811B000457EC6 /* ProjectNotificationsViewControllerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77F6E764212355C3005A5C55 /* ProjectNotificationsViewControllerTests.swift */; }; 1965437E28C8165200457EC6 /* ProjectPageNavigationBarViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 06AF78772710DB57009587F1 /* ProjectPageNavigationBarViewTests.swift */; }; 19821C85299D392400EF312F /* AppboySegment in Frameworks */ = {isa = PBXBuildFile; productRef = 19821C84299D392400EF312F /* AppboySegment */; }; 19821C87299D3E8300EF312F /* AppboySegment in Frameworks */ = {isa = PBXBuildFile; productRef = 19821C86299D3E8300EF312F /* AppboySegment */; }; - 198E574B28E2705100D5B8A9 /* PerimeterX in Frameworks */ = {isa = PBXBuildFile; productRef = 198E574A28E2705100D5B8A9 /* PerimeterX */; }; - 198E574D28E2705E00D5B8A9 /* PerimeterX in Frameworks */ = {isa = PBXBuildFile; productRef = 198E574C28E2705E00D5B8A9 /* PerimeterX */; }; 1996AA1F2A5F1BC400AE2ED0 /* StripePaymentSheet in Frameworks */ = {isa = PBXBuildFile; productRef = 1996AA1E2A5F1BC400AE2ED0 /* StripePaymentSheet */; }; 1996AA312A5F39CC00AE2ED0 /* PledgePaymentMethodsViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6534D3D22E789B900E9D279 /* PledgePaymentMethodsViewModelTests.swift */; }; 1996AA322A5F3A3200AE2ED0 /* Stripe+PaymentMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1923770928DA2AE300F68635 /* Stripe+PaymentMethod.swift */; }; @@ -675,7 +675,6 @@ 8A1F155624DB609D00E0C000 /* DateFormatter+ISOFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A1F155524DB609D00E0C000 /* DateFormatter+ISOFormatter.swift */; }; 8A1F155824DC657E00E0C000 /* Project.RewardDataLenses.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A1F155724DC657E00E0C000 /* Project.RewardDataLenses.swift */; }; 8A1F65E6262660CB00A28E74 /* PerimeterXClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A1F65E4262660CB00A28E74 /* PerimeterXClient.swift */; }; - 8A1F65F2262660EF00A28E74 /* PerimeterXClientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A1F65E3262660CB00A28E74 /* PerimeterXClientTests.swift */; }; 8A213CEB239EAEA400BBB4C7 /* TrackingClientType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A213CE4239EAEA400BBB4C7 /* TrackingClientType.swift */; }; 8A213CEF239EAEA400BBB4C7 /* KSRAnalytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A213CE8239EAEA400BBB4C7 /* KSRAnalytics.swift */; }; 8A213CF3239EAEB700BBB4C7 /* KSRAnalyticsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A213CE7239EAEA400BBB4C7 /* KSRAnalyticsTests.swift */; }; @@ -789,7 +788,6 @@ 8ACD29F7243E48260044BC17 /* PledgePaymentMethodsDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8ACD29F6243E48260044BC17 /* PledgePaymentMethodsDataSource.swift */; }; 8ACF36D1262745520026E74D /* MockService.swift in Sources */ = {isa = PBXBuildFile; fileRef = D01587761EEB2ED6006E7684 /* MockService.swift */; }; 8ACF36E22627481C0026E74D /* ApiDateProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A1F66022627300900A28E74 /* ApiDateProtocol.swift */; }; - 8ACF36EA2627486D0026E74D /* KsApiNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8ACF36E92627486D0026E74D /* KsApiNotification.swift */; }; 8ACF36F7262763960026E74D /* MockPerimeterXTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A1F65EA262660DB00A28E74 /* MockPerimeterXTypes.swift */; }; 8ACF558923E8D467001654A2 /* TryDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8ACF558823E8D467001654A2 /* TryDecodable.swift */; }; 8ACF95AE248957B10064FC4C /* ManagePledgeDataSourceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8ACF95AD248957B10064FC4C /* ManagePledgeDataSourceTests.swift */; }; @@ -2253,7 +2251,6 @@ 8A1A93D124C602300012FB43 /* PledgeShippingSummaryViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PledgeShippingSummaryViewModel.swift; sourceTree = ""; }; 8A1F155524DB609D00E0C000 /* DateFormatter+ISOFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DateFormatter+ISOFormatter.swift"; sourceTree = ""; }; 8A1F155724DC657E00E0C000 /* Project.RewardDataLenses.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Project.RewardDataLenses.swift; sourceTree = ""; }; - 8A1F65E3262660CB00A28E74 /* PerimeterXClientTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PerimeterXClientTests.swift; sourceTree = ""; }; 8A1F65E4262660CB00A28E74 /* PerimeterXClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PerimeterXClient.swift; sourceTree = ""; }; 8A1F65EA262660DB00A28E74 /* MockPerimeterXTypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockPerimeterXTypes.swift; sourceTree = ""; }; 8A1F66022627300900A28E74 /* ApiDateProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiDateProtocol.swift; sourceTree = ""; }; @@ -2361,7 +2358,6 @@ 8AC3E135269F781200168BF8 /* ErrorEnvelope+LocalizedDescription.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ErrorEnvelope+LocalizedDescription.swift"; sourceTree = ""; }; 8ACB32A724ABC2DB00A03968 /* RewardAddOnSelectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RewardAddOnSelectionViewController.swift; sourceTree = ""; }; 8ACD29F6243E48260044BC17 /* PledgePaymentMethodsDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PledgePaymentMethodsDataSource.swift; sourceTree = ""; }; - 8ACF36E92627486D0026E74D /* KsApiNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KsApiNotification.swift; sourceTree = ""; }; 8ACF558823E8D467001654A2 /* TryDecodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TryDecodable.swift; sourceTree = ""; }; 8ACF95AD248957B10064FC4C /* ManagePledgeDataSourceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManagePledgeDataSourceTests.swift; sourceTree = ""; }; 8AD48632235939AF00A1463E /* StripeTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StripeTypes.swift; sourceTree = ""; }; @@ -3156,9 +3152,9 @@ 60DA50FE28C38DDB002E2DF1 /* AlamofireImage in Frameworks */, 1996AA1F2A5F1BC400AE2ED0 /* StripePaymentSheet in Frameworks */, 06634FC72807A4EB00950F60 /* Prelude_UIKit in Frameworks */, - 198E574B28E2705100D5B8A9 /* PerimeterX in Frameworks */, 6078106F2A04191C0050D4F7 /* FirebaseAnalytics in Frameworks */, 19821C87299D3E8300EF312F /* AppboySegment in Frameworks */, + 195747182A71AF1700D43CA3 /* PerimeterX_SDK in Frameworks */, 60DA510F28C7E04B002E2DF1 /* Kingfisher in Frameworks */, 6078106B2A0419130050D4F7 /* FirebaseCrashlytics in Frameworks */, 19A6665F2A045F2A00708F8B /* FirebaseRemoteConfig in Frameworks */, @@ -3188,11 +3184,11 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 195747162A71AF0B00D43CA3 /* PerimeterX_SDK in Frameworks */, 60EAD1C728D25A36009F9474 /* AppCenterDistribute in Frameworks */, 06EA2D4C280F76B700F4DE2E /* Prelude in Frameworks */, A73924001D27230B004524C3 /* Kickstarter_Framework.framework in Frameworks */, 19821C85299D392400EF312F /* AppboySegment in Frameworks */, - 191EDC6728E29BB9009B41B2 /* PerimeterX in Frameworks */, D0B45B6B1EF858C00020A8DA /* KsApi.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -3212,12 +3208,12 @@ buildActionMask = 2147483647; files = ( 06634FBE2807A4C300950F60 /* Apollo in Frameworks */, + 1957471A2A71AF3200D43CA3 /* PerimeterX_SDK in Frameworks */, 06634FC52807A4EB00950F60 /* Prelude in Frameworks */, 06634FC02807A4C300950F60 /* ApolloAPI in Frameworks */, 06634FC22807A4C300950F60 /* ApolloUtils in Frameworks */, 1998BCB228F60ED400D04077 /* ReactiveExtensions in Frameworks */, 60DA511428C96A65002E2DF1 /* SwiftSoup in Frameworks */, - 198E574D28E2705E00D5B8A9 /* PerimeterX in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5867,7 +5863,6 @@ children = ( 8A1F65EA262660DB00A28E74 /* MockPerimeterXTypes.swift */, 8A1F65E4262660CB00A28E74 /* PerimeterXClient.swift */, - 8A1F65E3262660CB00A28E74 /* PerimeterXClientTests.swift */, 476A2A6325DEED2600EB6A56 /* PerimeterXTypes.swift */, ); path = px; @@ -6794,7 +6789,6 @@ D01587711EEB2ED6006E7684 /* EncodableTests.swift */, D01587721EEB2ED6006E7684 /* EncodableType.swift */, 7703B42123217D4F00169EF3 /* EnvironmentType.swift */, - 8ACF36E92627486D0026E74D /* KsApiNotification.swift */, D01587731EEB2ED6006E7684 /* Method.swift */, D01587741EEB2ED6006E7684 /* MimeType.swift */, D01587751EEB2ED6006E7684 /* Route.swift */, @@ -7131,7 +7125,6 @@ 60DA510E28C7E04B002E2DF1 /* Kingfisher */, 606754BC28CF91D60033CD5E /* FacebookCore */, 606754BE28CF91DD0033CD5E /* FacebookLogin */, - 198E574A28E2705100D5B8A9 /* PerimeterX */, 19821C86299D3E8300EF312F /* AppboySegment */, 6078106A2A0419130050D4F7 /* FirebaseCrashlytics */, 6078106C2A0419170050D4F7 /* FirebasePerformance */, @@ -7139,6 +7132,7 @@ 19A6665E2A045F2A00708F8B /* FirebaseRemoteConfig */, 19338D9A2A0D4E2300075F29 /* Stripe */, 1996AA1E2A5F1BC400AE2ED0 /* StripePaymentSheet */, + 195747172A71AF1700D43CA3 /* PerimeterX_SDK */, ); productName = "Library-iOS"; productReference = A755113C1C8642B3005355CF /* Library.framework */; @@ -7207,8 +7201,8 @@ packageProductDependencies = ( 06EA2D4B280F76B700F4DE2E /* Prelude */, 60EAD1C628D25A36009F9474 /* AppCenterDistribute */, - 191EDC6628E29BB9009B41B2 /* PerimeterX */, 19821C84299D392400EF312F /* AppboySegment */, + 195747152A71AF0B00D43CA3 /* PerimeterX_SDK */, ); productName = Kickstarter; productReference = A7D1F9451C850B7C000D41D5 /* KickDebug.app */; @@ -7258,8 +7252,8 @@ 06634FC12807A4C300950F60 /* ApolloUtils */, 06634FC42807A4EB00950F60 /* Prelude */, 60DA511328C96A65002E2DF1 /* SwiftSoup */, - 198E574C28E2705E00D5B8A9 /* PerimeterX */, 1998BCB128F60ED400D04077 /* ReactiveExtensions */, + 195747192A71AF3200D43CA3 /* PerimeterX_SDK */, ); productName = KsApi; productReference = D01587501EEB2DE4006E7684 /* KsApi.framework */; @@ -8861,7 +8855,6 @@ D79440572203A63300D0A747 /* CreatePaymentSourceEnvelope.swift in Sources */, D08CD1F921910DF5009F89F0 /* UnwatchProjectMutation.swift in Sources */, D6AE52281FD1B4BA00BEC788 /* CategoryEnvelope.swift in Sources */, - 8ACF36EA2627486D0026E74D /* KsApiNotification.swift in Sources */, D6ED386A1F796C26006CAAE9 /* GraphCategoriesEnvelopeLenses.swift in Sources */, 8ADCCCA6264C97940079D308 /* CommentsEnvelope.swift in Sources */, D755ECA92319AF4D0096F189 /* CreateBackingEnvelope.swift in Sources */, @@ -8917,7 +8910,6 @@ 066C0AE726CC17610048F4D8 /* WatchProjectMutationTemplate.swift in Sources */, 20A0938A2666578D00DEC258 /* CommentTests.swift in Sources */, 06962F8D273B36A700FB0B3D /* PostCommentMutationTemplate.swift in Sources */, - 8A1F65F2262660EF00A28E74 /* PerimeterXClientTests.swift in Sources */, 77272D382370AB8E003B7A9C /* BackingPaymentSourceTests.swift in Sources */, 8A15574326951A4B00017845 /* Backing+BackingFragmentTests.swift in Sources */, 0665C74B26E930BC00A0EDA1 /* FetchProjectQueryTemplate.swift in Sources */, @@ -10377,7 +10369,7 @@ repositoryURL = "https://github.com/PerimeterX/px-iOS-Framework"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 1.13.9; + minimumVersion = 3.0.3; }; }; 606754B728CF8A190033CD5E /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */ = { @@ -10466,16 +10458,26 @@ package = 194C593E28F5E7FF00453249 /* XCRemoteSwiftPackageReference "Kickstarter-ReactiveExtensions" */; productName = "ReactiveExtensions-TestHelpers"; }; - 191EDC6628E29BB9009B41B2 /* PerimeterX */ = { - isa = XCSwiftPackageProductDependency; - package = 602C97D628DB787900919CA8 /* XCRemoteSwiftPackageReference "px-iOS-Framework" */; - productName = PerimeterX; - }; 19338D9A2A0D4E2300075F29 /* Stripe */ = { isa = XCSwiftPackageProductDependency; package = 194520C12888542100CA9B88 /* XCRemoteSwiftPackageReference "stripe-ios" */; productName = Stripe; }; + 195747152A71AF0B00D43CA3 /* PerimeterX_SDK */ = { + isa = XCSwiftPackageProductDependency; + package = 602C97D628DB787900919CA8 /* XCRemoteSwiftPackageReference "px-iOS-Framework" */; + productName = PerimeterX_SDK; + }; + 195747172A71AF1700D43CA3 /* PerimeterX_SDK */ = { + isa = XCSwiftPackageProductDependency; + package = 602C97D628DB787900919CA8 /* XCRemoteSwiftPackageReference "px-iOS-Framework" */; + productName = PerimeterX_SDK; + }; + 195747192A71AF3200D43CA3 /* PerimeterX_SDK */ = { + isa = XCSwiftPackageProductDependency; + package = 602C97D628DB787900919CA8 /* XCRemoteSwiftPackageReference "px-iOS-Framework" */; + productName = PerimeterX_SDK; + }; 19821C84299D392400EF312F /* AppboySegment */ = { isa = XCSwiftPackageProductDependency; package = 19821C83299D392300EF312F /* XCRemoteSwiftPackageReference "appboy-segment-ios" */; @@ -10486,16 +10488,6 @@ package = 19821C83299D392300EF312F /* XCRemoteSwiftPackageReference "appboy-segment-ios" */; productName = AppboySegment; }; - 198E574A28E2705100D5B8A9 /* PerimeterX */ = { - isa = XCSwiftPackageProductDependency; - package = 602C97D628DB787900919CA8 /* XCRemoteSwiftPackageReference "px-iOS-Framework" */; - productName = PerimeterX; - }; - 198E574C28E2705E00D5B8A9 /* PerimeterX */ = { - isa = XCSwiftPackageProductDependency; - package = 602C97D628DB787900919CA8 /* XCRemoteSwiftPackageReference "px-iOS-Framework" */; - productName = PerimeterX; - }; 1996AA1E2A5F1BC400AE2ED0 /* StripePaymentSheet */ = { isa = XCSwiftPackageProductDependency; package = 194520C12888542100CA9B88 /* XCRemoteSwiftPackageReference "stripe-ios" */; diff --git a/Kickstarter.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Kickstarter.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index d1eaba217a..93a4527a77 100644 --- a/Kickstarter.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Kickstarter.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -221,8 +221,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/PerimeterX/px-iOS-Framework", "state" : { - "revision" : "50eec61be35fcece00b4b6580367f16cc8a4f96d", - "version" : "1.16.3" + "revision" : "e02362af109f8d78dcd5588f96be3846982cbfcd", + "version" : "3.0.4" } }, { diff --git a/KsApi/ErrorHandler.swift b/KsApi/ErrorHandler.swift index 5452c5365c..e1b4f4de7a 100644 --- a/KsApi/ErrorHandler.swift +++ b/KsApi/ErrorHandler.swift @@ -4,10 +4,10 @@ public protocol ErrorHandler { /** Given a URL Response and data, this method will allow for custom error handling logic. - - parameter response: An `HTTPURLResponse` object with response data from a request. - - parameter data: Data` associated with the request + - parameter data: `Data` associated with the request + - parameter response: An `URLResponse` object with response data from a request. - returns: A boolean indicating whether or not the error was handled. */ - func handleError(response: HTTPURLResponse, and data: Data) -> Bool + func handleResponse(data: Data, response: URLResponse) -> Bool } diff --git a/KsApi/Service.swift b/KsApi/Service.swift index afe59e93cf..7406c10802 100644 --- a/KsApi/Service.swift +++ b/KsApi/Service.swift @@ -1,9 +1,9 @@ import Apollo import Foundation -import PerimeterX import Prelude import ReactiveExtensions import ReactiveSwift +import UIKit public extension Bundle { var _buildVersion: String { @@ -50,14 +50,11 @@ public struct Service: ServiceType { // Global override required for injecting custom User-Agent header in ajax requests UserDefaults.standard.register(defaults: ["UserAgent": Service.userAgent]) - // Initialize PerimeterX - PXManager.sharedInstance().start(with: Secrets.PerimeterX.appId) - // Configure GraphQL Client GraphQL.shared.configure( with: serverConfig.graphQLEndpointUrl, headers: self.defaultHeaders, - additionalHeaders: { perimeterXClient.headers() } + additionalHeaders: { [:] } ) } diff --git a/KsApi/ServiceType.swift b/KsApi/ServiceType.swift index e18320d00d..f69e60b942 100644 --- a/KsApi/ServiceType.swift +++ b/KsApi/ServiceType.swift @@ -526,12 +526,7 @@ extension ServiceType { headers["X-KICKSTARTER-CLIENT"] = self.serverConfig.apiClientAuth.clientId headers["Kickstarter-iOS-App-UUID"] = self.deviceIdentifier - return headers.withAllValuesFrom(self.pxHeaders) - } - - // PerimeterX authorization header - internal var pxHeaders: [String: String] { - return self.perimeterXClient.headers() + return headers } func graphMutationRequestBody(mutation: String, input: [String: Any]) -> [String: Any] { diff --git a/KsApi/ServiceTypeTests.swift b/KsApi/ServiceTypeTests.swift index f438b74912..475b68690a 100644 --- a/KsApi/ServiceTypeTests.swift +++ b/KsApi/ServiceTypeTests.swift @@ -97,7 +97,6 @@ final class ServiceTypeTests: XCTestCase { ) XCTAssertEqual( [ - "PX-AUTH-TEST": "foobar", "Kickstarter-iOS-App": "1234567890", "Authorization": "token cafebeef", "Accept-Language": "ksr", @@ -120,7 +119,6 @@ final class ServiceTypeTests: XCTestCase { ) XCTAssertEqual( [ - "PX-AUTH-TEST": "foobar", "Kickstarter-iOS-App": "1234567890", "Authorization": "token cafebeef", "Accept-Language": "ksr", @@ -144,7 +142,6 @@ final class ServiceTypeTests: XCTestCase { ) XCTAssertEqual( [ - "PX-AUTH-TEST": "foobar", "Kickstarter-iOS-App": "1234567890", "Authorization": "token cafebeef", "Accept-Language": "ksr", @@ -168,7 +165,6 @@ final class ServiceTypeTests: XCTestCase { ) XCTAssertEqual( [ - "PX-AUTH-TEST": "foobar", "Kickstarter-iOS-App": "1234567890", "Authorization": "token cafebeef", "Accept-Language": "ksr", @@ -201,7 +197,6 @@ final class ServiceTypeTests: XCTestCase { ) XCTAssertEqual( [ - "PX-AUTH-TEST": "foobar", "Kickstarter-iOS-App": "1234567890", "Authorization": "token cafebeef", "Accept-Language": "ksr", @@ -226,7 +221,6 @@ final class ServiceTypeTests: XCTestCase { ) XCTAssertEqual( [ - "PX-AUTH-TEST": "foobar", "Kickstarter-iOS-App": "\(testToolBuildNumber())", "Authorization": "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", "Accept-Language": "en", @@ -267,7 +261,6 @@ final class ServiceTypeTests: XCTestCase { ) XCTAssertEqual( [ - "PX-AUTH-TEST": "foobar", "Kickstarter-iOS-App": "\(testToolBuildNumber())", "Authorization": "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", "Accept-Language": "en", @@ -302,7 +295,6 @@ final class ServiceTypeTests: XCTestCase { XCTAssertEqual(request?.allHTTPHeaderFields?["Kickstarter-App-Id"], self.service.appId) XCTAssertEqual(request?.allHTTPHeaderFields?["Kickstarter-iOS-App"], self.service.buildVersion) XCTAssertEqual(request?.allHTTPHeaderFields?["X-KICKSTARTER-CLIENT"], "deadbeef") - XCTAssertEqual(request?.allHTTPHeaderFields?["PX-AUTH-TEST"], "foobar") XCTAssertEqual(request?.allHTTPHeaderFields?["User-Agent"], userAgent()) XCTAssertEqual( request?.allHTTPHeaderFields?["Kickstarter-iOS-App-UUID"], diff --git a/KsApi/extensions/NSURLSession.swift b/KsApi/extensions/NSURLSession.swift index d01107626c..4fa0c14b6a 100644 --- a/KsApi/extensions/NSURLSession.swift +++ b/KsApi/extensions/NSURLSession.swift @@ -34,8 +34,8 @@ internal extension URLSession { .flatMap(.concat) { data, response -> SignalProducer in guard let response = response as? HTTPURLResponse else { fatalError() } - /// `error` is `nil` or `handleError` returns `false`. - guard [nil, false].contains(error?.handleError(response: response, and: data)) else { return .empty } + guard [nil, false].contains(error?.handleResponse(data: data, response: response)) + else { return .empty } guard self.isValidResponse(response: response) else { if let json = parseJSONData(data) as? [String: Any] { diff --git a/KsApi/lib/KsApiNotification.swift b/KsApi/lib/KsApiNotification.swift deleted file mode 100644 index 92d006370c..0000000000 --- a/KsApi/lib/KsApiNotification.swift +++ /dev/null @@ -1,5 +0,0 @@ -import Foundation - -extension Notification.Name { - public static let ksr_perimeterXCaptcha = Notification.Name(rawValue: "KsApiNotification.PerimeterXCaptcha") -} diff --git a/KsApi/px/MockPerimeterXTypes.swift b/KsApi/px/MockPerimeterXTypes.swift index 625bee2ebd..34e9be2b50 100644 --- a/KsApi/px/MockPerimeterXTypes.swift +++ b/KsApi/px/MockPerimeterXTypes.swift @@ -1,37 +1,8 @@ import Foundation -import PerimeterX +import PerimeterX_SDK extension PerimeterXClient { static var mock: PerimeterXClient = PerimeterXClient( - manager: MockPerimeterXManager(), dateType: ApiMockDate.self ) } - -struct MockPerimeterXBlockResponse: PerimeterXBlockResponseType { - var blockType: PXBlockType - - var type: PXBlockType { - return self.blockType - } - - func displayCaptcha(on _: UIViewController?) {} -} - -final class MockPerimeterXManager: PerimeterXManagerType { - var headers: [AnyHashable: Any] = ["PX-AUTH-TEST": "foobar"] - var responseType: PerimeterXBlockResponseType? - var vid: String = "test-vid-id" - - func getVid() -> String! { - return self.vid - } - - func httpHeaders() -> [AnyHashable: Any]! { - return self.headers - } - - func checkError(_: [AnyHashable: Any]!) -> PerimeterXBlockResponseType? { - return self.responseType - } -} diff --git a/KsApi/px/PerimeterXClient.swift b/KsApi/px/PerimeterXClient.swift index 3a1c990c2d..219777f24d 100644 --- a/KsApi/px/PerimeterXClient.swift +++ b/KsApi/px/PerimeterXClient.swift @@ -1,9 +1,13 @@ import Foundation -import PerimeterX +import PerimeterX_SDK public class PerimeterXClient: NSObject, PerimeterXClientType { - let dateType: ApiDateProtocol.Type - let manager: PerimeterXManagerType + private let dateType: ApiDateProtocol.Type + private var policy = PXPolicy() + + public var vid: String? { + PerimeterX.vid() + } /** Custom `HTTPCookie` adding Perimeter X protection to native webviews. @@ -13,59 +17,39 @@ public class PerimeterXClient: NSObject, PerimeterXClientType { .domain: "www.perimeterx.com", // Change according to the domain the webview will use .path: "/", .name: "_pxmvid", - .value: self.manager.getVid() as Any, + .value: self.vid ?? "", .expires: self.dateType.init(timeIntervalSinceNow: 3_600).date ]) }() public init( - manager: PerimeterXManagerType = PXManager.sharedInstance(), dateType: ApiDateProtocol.Type = Date.self ) { - self.manager = manager self.dateType = dateType super.init() - - /// When this isn't a mock we'll set the delegate and have debug logging in the console. - (self.manager as? PXManager)?.delegate = self - } - - public func handleError(response: HTTPURLResponse, and data: Data) -> Bool { - /// We have a `403` statusCode. - guard response.statusCode == 403 else { return false } - - guard - /// We have `JSON`. - let jsonData = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any], - /// We have a `PXBlockResponse`. - let response: PerimeterXBlockResponseType = self.manager.checkError(jsonData), - /// The response's `PXBlockType` is `Block` or `Captcha`. - [.Block, .Captcha].contains(response.type) - else { return false } - - DispatchQueue.main.async { - NotificationCenter.default.post( - name: Notification.Name.ksr_perimeterXCaptcha, - object: nil, - userInfo: ["response": response] - ) - } - - return true } public func headers() -> [String: String] { - return (self.manager.httpHeaders() as? [String: String]) ?? [:] + return PerimeterX.headersForURLRequest() ?? [:] } -} -extension PerimeterXClient: PXManagerDelegate { - public func managerReady(_ httpHeaders: [AnyHashable: Any]!) { - print("❎ Perimeter X headers ready: \(String(describing: httpHeaders))") + public func start(policyDomains: Set) { + self.policy.set(domains: policyDomains, forAppId: Secrets.PerimeterX.appId) + + try? PerimeterX.start(appId: Secrets.PerimeterX.appId, delegate: nil, policy: self.policy) } - public func newHeaders(_ httpHeaders: [AnyHashable: Any]!) { - print("❎ Perimeter X headers were refreshed: \(String(describing: httpHeaders))") + public func handleResponse(data: Data, response: URLResponse) -> Bool { + PerimeterX.handleResponse(response: response, data: data) { result in + switch result { + case .cancelled: + print("❎ Perimeter X CAPTCHA was cancelled.") + case .solved: + print("❎ Perimeter X CAPTCHA was solved.") + @unknown default: + print("❎ Perimeter X CAPTCHA was unknown.") + } + } } } diff --git a/KsApi/px/PerimeterXClientTests.swift b/KsApi/px/PerimeterXClientTests.swift deleted file mode 100644 index 8d7ed077ce..0000000000 --- a/KsApi/px/PerimeterXClientTests.swift +++ /dev/null @@ -1,118 +0,0 @@ -@testable import KsApi -import PerimeterX -import Prelude -import XCTest - -final class PerimeterXClientTests: XCTestCase { - func testCookie() { - let manager = MockPerimeterXManager() - let client = PerimeterXClient(manager: manager, dateType: ApiMockDate.self) - - guard let cookie = client.cookie else { - XCTFail("Where's my cookie?") - return - } - - XCTAssertEqual(cookie.domain, "www.perimeterx.com") - XCTAssertEqual(cookie.path, "/") - XCTAssertEqual(cookie.name, "_pxmvid") - XCTAssertEqual(cookie.value, manager.getVid()) - XCTAssertEqual(cookie.expiresDate, ApiMockDate.init(timeIntervalSinceNow: 3_600).date) - } - - func testHeaders() { - let manager = MockPerimeterXManager() - let client = PerimeterXClient(manager: manager, dateType: ApiMockDate.self) - - XCTAssertEqual(client.headers(), ["PX-AUTH-TEST": "foobar"]) - } - - func testHeaders_IncorrectHeader() { - let manager = MockPerimeterXManager() - let client = PerimeterXClient(manager: manager, dateType: ApiMockDate.self) - - XCTAssertNotEqual(client.headers(), ["PX-INCORRECT-HEADER": "foobar"]) - } - - func testHandleError_StatusCode_403_Captcha() { - let manager = MockPerimeterXManager() - manager.responseType = MockPerimeterXBlockResponse(blockType: .Captcha) - let client = PerimeterXClient(manager: manager, dateType: ApiMockDate.self) - - let data = "{}".data(using: .utf8, allowLossyConversion: false) - guard let response = HTTPURLResponse( - url: URL(string: "http://api.ksr.com/v1/test?key=value")!, - statusCode: 403, - httpVersion: nil, - headerFields: nil - ) else { - XCTFail("Could not unwrap HTTPURLResponse.") - return - } - - XCTAssertTrue(client.handleError(response: response, and: data!)) - - expectation(forNotification: Notification.Name.ksr_perimeterXCaptcha, object: nil) { note in - Thread.isMainThread && (note.userInfo?["response"] as? PerimeterXBlockResponseType)?.type == .Captcha - } - - waitForExpectations(timeout: 0.01, handler: nil) - } - - func testHandleError_StatusCode_403_Block() { - let manager = MockPerimeterXManager() - manager.responseType = MockPerimeterXBlockResponse(blockType: .Block) - let client = PerimeterXClient(manager: manager, dateType: ApiMockDate.self) - - let data = "{}".data(using: .utf8, allowLossyConversion: false) - guard let response = HTTPURLResponse( - url: URL(string: "http://api.ksr.com/v1/test?key=value")!, - statusCode: 403, - httpVersion: nil, - headerFields: nil - ) else { - XCTFail("Could not unwrap HTTPURLResponse.") - return - } - - XCTAssertTrue(client.handleError(response: response, and: data!)) - - expectation(forNotification: Notification.Name.ksr_perimeterXCaptcha, object: nil) { note in - Thread.isMainThread && (note.userInfo?["response"] as? PerimeterXBlockResponseType)?.type == .Block - } - - waitForExpectations(timeout: 0.01, handler: nil) - } - - func testHandleError_StatusCode_200() { - let manager = MockPerimeterXManager() - manager.responseType = MockPerimeterXBlockResponse(blockType: .NotPXBlock) - let client = PerimeterXClient(manager: manager, dateType: ApiMockDate.self) - - let data = "{}".data(using: .utf8, allowLossyConversion: false) - guard let response = HTTPURLResponse( - url: URL(string: "http://api.ksr.com/v1/test?key=value")!, - statusCode: 200, - httpVersion: nil, - headerFields: nil - ) else { - XCTFail("Could not unwrap HTTPURLResponse.") - return - } - - var notificationResponse: MockPerimeterXBlockResponse? - - let token = NotificationCenter.default.addObserver( - forName: Notification.Name.ksr_perimeterXCaptcha, - object: nil, - queue: OperationQueue.main - ) { note in - notificationResponse = note.object as? MockPerimeterXBlockResponse - } - - XCTAssertFalse(client.handleError(response: response, and: data!)) - XCTAssertNil(notificationResponse) - - NotificationCenter.default.removeObserver(token) - } -} diff --git a/KsApi/px/PerimeterXTypes.swift b/KsApi/px/PerimeterXTypes.swift index 0089d09722..cb367cfae2 100644 --- a/KsApi/px/PerimeterXTypes.swift +++ b/KsApi/px/PerimeterXTypes.swift @@ -1,5 +1,5 @@ import Foundation -import PerimeterX +import PerimeterX_SDK // MARK: - PerimeterXClientType @@ -7,36 +7,12 @@ public protocol PerimeterXClientType: ErrorHandler { /// Returns an optional `HTTPCookie` for use in authenticating web views to Perimeter X. var cookie: HTTPCookie? { get } + /// Returns an optional `String` cookie VID to PerimeterX + var vid: String? { get } + /// Returns a dictionary of `[String: String]`, representing httpHeaders from Perimeter X. func headers() -> [String: String] -} - -// MARK: - PerimeterXManagerType - -public protocol PerimeterXManagerType { - func checkError(_ responseJson: [AnyHashable: Any]!) -> PerimeterXBlockResponseType? - func getVid() -> String! - func httpHeaders() -> [AnyHashable: Any]! -} - -extension PXManager: PerimeterXManagerType { - public func checkError(_ responseJson: [AnyHashable: Any]!) -> PerimeterXBlockResponseType? { - self.checkError(responseJson) as PerimeterXBlockResponseType - } -} - -// MARK: - PerimeterXBlockResponseType - -public protocol PerimeterXBlockResponseType { - var type: PXBlockType { get } - - func displayCaptcha(on vc: UIViewController?) -} -extension PXBlockResponse: PerimeterXBlockResponseType { - public func displayCaptcha(on vc: UIViewController?) { - PXManager.sharedInstance()?.handle(self, with: vc) { - print("❎ Perimeter X CAPTCHA was successful.") - } - } + /// Calls the start method to configure the SDK with allowable domains + func start(policyDomains: Set) }