From 24ef63a00466fc533d37829131dc43e95255dbef Mon Sep 17 00:00:00 2001 From: Samantha Cannillo Date: Thu, 8 Jul 2021 11:15:48 -0500 Subject: [PATCH 1/5] WIP --- BraintreeDropIn.xcodeproj/project.pbxproj | 8 +++---- Demo/Application/DemoAppDelegate.swift | 5 ++++ .../DemoDropInViewController.swift | 1 + Demo/Application/Settings/DemoSettings.swift | 4 ++++ Sources/BraintreeDropIn/BTDropInController.m | 23 +++++++++++++++++++ .../BraintreeDropIn/Models/BTDropInResult.m | 22 ++++++++++++++++++ .../Public/BraintreeDropIn/BTDropInRequest.h | 7 ++++++ .../Public/BraintreeDropIn/BTDropInResult.h | 7 ++++++ 8 files changed, 73 insertions(+), 4 deletions(-) diff --git a/BraintreeDropIn.xcodeproj/project.pbxproj b/BraintreeDropIn.xcodeproj/project.pbxproj index 90c5db90..86d627a1 100644 --- a/BraintreeDropIn.xcodeproj/project.pbxproj +++ b/BraintreeDropIn.xcodeproj/project.pbxproj @@ -647,8 +647,6 @@ A56C416C1D833348000DFFAB /* BraintreeDropIn */ = { isa = PBXGroup; children = ( - A52900CF1D8903A600032220 /* Components */, - 4295626726053C9F003680BD /* Resources */, A56C41B51D83381E000DFFAB /* BTAPIClient_Internal_Category.h */, A56C41A61D8335C7000DFFAB /* BTCardFormViewController.h */, A56C41871D833568000DFFAB /* BTCardFormViewController.m */, @@ -665,13 +663,15 @@ A56C41B71D833A6B000DFFAB /* BTUIKBarButtonItem_Internal_Declaration.h */, A56C41AC1D8335C7000DFFAB /* BTVaultManagementViewController.h */, A56C418D1D833568000DFFAB /* BTVaultManagementViewController.m */, + A52900CF1D8903A600032220 /* Components */, A56C41851D8334D7000DFFAB /* Custom Views */, - A56C416F1D833348000DFFAB /* Info.plist */, A52900E21D8903A600032220 /* Helpers */, + A56C416F1D833348000DFFAB /* Info.plist */, A52900E61D8903A600032220 /* Localization */, A56C41841D8334D1000DFFAB /* Models */, - A529011B1D8903A600032220 /* Vector Art */, A56C41861D8334DD000DFFAB /* Public */, + 4295626726053C9F003680BD /* Resources */, + A529011B1D8903A600032220 /* Vector Art */, ); path = BraintreeDropIn; sourceTree = ""; diff --git a/Demo/Application/DemoAppDelegate.swift b/Demo/Application/DemoAppDelegate.swift index 2b5bdba7..5020d20b 100644 --- a/Demo/Application/DemoAppDelegate.swift +++ b/Demo/Application/DemoAppDelegate.swift @@ -92,6 +92,11 @@ class DemoAppDelegate: UIResponder, UIApplicationDelegate { if testArguments.contains("-SaveCardToggleVisible") { UserDefaults.standard.set(true, forKey:"BraintreeDemoAllowVaultCardOverrideSetting") } + + UserDefaults.standard.set(false, forKey:"BraintreeDemoCollectDeviceDataSetting") + if testArguments.contains("-CollectDeviceData") { + UserDefaults.standard.set(true, forKey:"BraintreeDemoCollectDeviceDataSetting") + } UserDefaults.standard.set(true, forKey:"BraintreeDemoVaultCardSetting") if testArguments.contains("-VaultCardIsFalse") { diff --git a/Demo/Application/DemoDropInViewController.swift b/Demo/Application/DemoDropInViewController.swift index e660f8a9..e77a4385 100644 --- a/Demo/Application/DemoDropInViewController.swift +++ b/Demo/Application/DemoDropInViewController.swift @@ -48,6 +48,7 @@ class DemoDropInViewController: DemoBaseViewController, DemoDropInViewDelegate { dropInRequest.cardholderNameSetting = DemoSettings.cardholderNameSetting dropInRequest.vaultCard = DemoSettings.vaultCardSetting dropInRequest.allowVaultCardOverride = DemoSettings.allowVaultCardOverrideSetting + dropInRequest.collectDeviceData = DemoSettings.collectDeviceDataSetting if ProcessInfo.processInfo.arguments.contains("-PayPalOneTime") { dropInRequest.payPalRequest = BTPayPalCheckoutRequest(amount: "4.77") diff --git a/Demo/Application/Settings/DemoSettings.swift b/Demo/Application/Settings/DemoSettings.swift index 431adf66..93306f03 100644 --- a/Demo/Application/Settings/DemoSettings.swift +++ b/Demo/Application/Settings/DemoSettings.swift @@ -113,6 +113,10 @@ class DemoSettings { static var allowVaultCardOverrideSetting: Bool { return UserDefaults.standard.bool(forKey: "BraintreeDemoAllowVaultCardOverrideSetting") } + + static var collectDeviceDataSetting: Bool { + return UserDefaults.standard.bool(forKey: "BraintreeDemoCollectDeviceDataSetting") + } static var colorSchemeSetting: BTDropInColorScheme { get { diff --git a/Sources/BraintreeDropIn/BTDropInController.m b/Sources/BraintreeDropIn/BTDropInController.m index ed8f8edd..75ee2cdf 100644 --- a/Sources/BraintreeDropIn/BTDropInController.m +++ b/Sources/BraintreeDropIn/BTDropInController.m @@ -22,6 +22,26 @@ #import #endif +// Import PayPalDataCollector (Swift) module +#if __has_include() // CocoaPods +#import + +#elif SWIFT_PACKAGE // SPM +/* Use @import for SPM support + * See https://forums.swift.org/t/using-a-swift-package-in-a-mixed-swift-and-objective-c-project/27348 + */ +@import PayPalDataCollector; + +#elif __has_include("Braintree-Swift.h") // CocoaPods for ReactNative +/* Use quoted style when importing Swift headers for ReactNative support + * See https://github.com/braintree/braintree_ios/issues/671 + */ +#import "Braintree-Swift.h" + +#else // Carthage +#import +#endif + #define BT_ANIMATION_SLIDE_SPEED 0.35 #define BT_ANIMATION_TRANSITION_SPEED 0.1 #define BT_HALF_SHEET_MARGIN 5 @@ -412,6 +432,8 @@ - (void)paymentDriver:(__unused id)driver requestsDismissalOfViewController:(UIV [viewController dismissViewControllerAnimated:YES completion:nil]; } +#pragma mark BTPaymentSelectionViewControllerDelegate + - (void)selectionCompletedWithPaymentMethodType:(BTDropInPaymentMethodType)type nonce:(BTPaymentMethodNonce *)nonce error:(NSError *)error { if (error == nil) { [[NSUserDefaults standardUserDefaults] setInteger:type forKey:@"BT_dropInLastSelectedPaymentMethodType"]; @@ -419,6 +441,7 @@ - (void)selectionCompletedWithPaymentMethodType:(BTDropInPaymentMethodType)type BTDropInResult *result = [BTDropInResult new]; result.paymentMethodType = type; result.paymentMethod = nonce; + result.deviceData = [PPDataCollector collectPayPalDeviceData]; if ([BTUIKViewUtil isPaymentMethodTypeACreditCard:result.paymentMethodType] && [self.configuration.json[@"threeDSecureEnabled"] isTrue] && self.dropInRequest.threeDSecureRequest) { [self.paymentSelectionViewController showLoadingScreen:YES]; [self threeDSecureVerification:nonce]; diff --git a/Sources/BraintreeDropIn/Models/BTDropInResult.m b/Sources/BraintreeDropIn/Models/BTDropInResult.m index 85261d43..f02432e2 100644 --- a/Sources/BraintreeDropIn/Models/BTDropInResult.m +++ b/Sources/BraintreeDropIn/Models/BTDropInResult.m @@ -11,6 +11,26 @@ #import #endif +// Import PayPalDataCollector (Swift) module +#if __has_include() // CocoaPods +#import + +#elif SWIFT_PACKAGE // SPM +/* Use @import for SPM support + * See https://forums.swift.org/t/using-a-swift-package-in-a-mixed-swift-and-objective-c-project/27348 + */ +@import PayPalDataCollector; + +#elif __has_include("Braintree-Swift.h") // CocoaPods for ReactNative +/* Use quoted style when importing Swift headers for ReactNative support + * See https://github.com/braintree/braintree_ios/issues/671 + */ +#import "Braintree-Swift.h" + +#else // Carthage +#import +#endif + NSString *const BTDropInResultErrorDomain = @"com.braintreepayments.BTDropInResultErrorDomain"; @implementation BTDropInResult @@ -45,6 +65,7 @@ + (void)mostRecentPaymentMethodForAPIClient:(BTAPIClient * _Nullable)apiClient if (lastSelectedPaymentOptionType == BTDropInPaymentMethodTypeApplePay) { BTDropInResult *result = [BTDropInResult new]; result.paymentMethodType = lastSelectedPaymentOptionType; + result.deviceData = [PPDataCollector collectPayPalDeviceData]; completion(result, nil); return; } @@ -66,6 +87,7 @@ + (void)mostRecentPaymentMethodForAPIClient:(BTAPIClient * _Nullable)apiClient BTDropInResult *result; if (paymentMethodNonces.count > 0) { result = [BTDropInResult new]; + result.deviceData = [PPDataCollector collectPayPalDeviceData]; BTPaymentMethodNonce *paymentMethod = paymentMethodNonces.firstObject; result.paymentMethodType = [BTUIKViewUtil paymentMethodTypeForPaymentInfoType:paymentMethod.type]; result.paymentMethod = paymentMethod; diff --git a/Sources/BraintreeDropIn/Public/BraintreeDropIn/BTDropInRequest.h b/Sources/BraintreeDropIn/Public/BraintreeDropIn/BTDropInRequest.h index 4d3210c2..6ff1e31d 100644 --- a/Sources/BraintreeDropIn/Public/BraintreeDropIn/BTDropInRequest.h +++ b/Sources/BraintreeDropIn/Public/BraintreeDropIn/BTDropInRequest.h @@ -73,6 +73,13 @@ typedef NS_ENUM(NSInteger, BTFormFieldSetting) { /// Optional: Customization options for Braintree Drop-in's user interface. @property (nonatomic, strong, nullable) BTDropInUICustomization *uiCustomization; +/// Optional: When true, Drop-In will use Braintree's advanced fraud protection service to collect device data. The resulting `deviceData` string will be available on `BTDropInResult.deviceData`. +/// +/// This enables you to collect data about a customer's device and correlate it with a session identifier on your server. Collecting and passing this data with transactions helps reduce decline rates. +/// +/// Defaults to false +@property (nonatomic, assign) BOOL collectDeviceData; + @end NS_ASSUME_NONNULL_END diff --git a/Sources/BraintreeDropIn/Public/BraintreeDropIn/BTDropInResult.h b/Sources/BraintreeDropIn/Public/BraintreeDropIn/BTDropInResult.h index 6a233a35..31f617df 100644 --- a/Sources/BraintreeDropIn/Public/BraintreeDropIn/BTDropInResult.h +++ b/Sources/BraintreeDropIn/Public/BraintreeDropIn/BTDropInResult.h @@ -44,6 +44,13 @@ typedef NS_ENUM(NSInteger, BTDropInErrorType) { /// The payment method nonce @property (nonatomic, strong, nullable) BTPaymentMethodNonce *paymentMethod; +/** + * A `deviceData` string that should be passed into server-side calls, such as `Transaction.sale`. This enables you to collect data about a customer's device and correlate it with a session identifier on your server. + * + * Collecting and passing this data with transactions helps reduce decline rates. + */ +@property (nonatomic, strong, nullable) NSString *deviceData; + /** * Fetch a `BTDropInResult` with the customer's most recently vaulted payment method. * If the last payment method selected from Drop-in was Apple Pay, a `BTDropInResult` with From 2b3ba6c11b822eff37a614342411889b6aa87ee2 Mon Sep 17 00:00:00 2001 From: Samantha Cannillo Date: Thu, 8 Jul 2021 11:15:58 -0500 Subject: [PATCH 2/5] Revert "WIP" This reverts commit 24ef63a00466fc533d37829131dc43e95255dbef. --- BraintreeDropIn.xcodeproj/project.pbxproj | 8 +++---- Demo/Application/DemoAppDelegate.swift | 5 ---- .../DemoDropInViewController.swift | 1 - Demo/Application/Settings/DemoSettings.swift | 4 ---- Sources/BraintreeDropIn/BTDropInController.m | 23 ------------------- .../BraintreeDropIn/Models/BTDropInResult.m | 22 ------------------ .../Public/BraintreeDropIn/BTDropInRequest.h | 7 ------ .../Public/BraintreeDropIn/BTDropInResult.h | 7 ------ 8 files changed, 4 insertions(+), 73 deletions(-) diff --git a/BraintreeDropIn.xcodeproj/project.pbxproj b/BraintreeDropIn.xcodeproj/project.pbxproj index 86d627a1..90c5db90 100644 --- a/BraintreeDropIn.xcodeproj/project.pbxproj +++ b/BraintreeDropIn.xcodeproj/project.pbxproj @@ -647,6 +647,8 @@ A56C416C1D833348000DFFAB /* BraintreeDropIn */ = { isa = PBXGroup; children = ( + A52900CF1D8903A600032220 /* Components */, + 4295626726053C9F003680BD /* Resources */, A56C41B51D83381E000DFFAB /* BTAPIClient_Internal_Category.h */, A56C41A61D8335C7000DFFAB /* BTCardFormViewController.h */, A56C41871D833568000DFFAB /* BTCardFormViewController.m */, @@ -663,15 +665,13 @@ A56C41B71D833A6B000DFFAB /* BTUIKBarButtonItem_Internal_Declaration.h */, A56C41AC1D8335C7000DFFAB /* BTVaultManagementViewController.h */, A56C418D1D833568000DFFAB /* BTVaultManagementViewController.m */, - A52900CF1D8903A600032220 /* Components */, A56C41851D8334D7000DFFAB /* Custom Views */, - A52900E21D8903A600032220 /* Helpers */, A56C416F1D833348000DFFAB /* Info.plist */, + A52900E21D8903A600032220 /* Helpers */, A52900E61D8903A600032220 /* Localization */, A56C41841D8334D1000DFFAB /* Models */, - A56C41861D8334DD000DFFAB /* Public */, - 4295626726053C9F003680BD /* Resources */, A529011B1D8903A600032220 /* Vector Art */, + A56C41861D8334DD000DFFAB /* Public */, ); path = BraintreeDropIn; sourceTree = ""; diff --git a/Demo/Application/DemoAppDelegate.swift b/Demo/Application/DemoAppDelegate.swift index 5020d20b..2b5bdba7 100644 --- a/Demo/Application/DemoAppDelegate.swift +++ b/Demo/Application/DemoAppDelegate.swift @@ -92,11 +92,6 @@ class DemoAppDelegate: UIResponder, UIApplicationDelegate { if testArguments.contains("-SaveCardToggleVisible") { UserDefaults.standard.set(true, forKey:"BraintreeDemoAllowVaultCardOverrideSetting") } - - UserDefaults.standard.set(false, forKey:"BraintreeDemoCollectDeviceDataSetting") - if testArguments.contains("-CollectDeviceData") { - UserDefaults.standard.set(true, forKey:"BraintreeDemoCollectDeviceDataSetting") - } UserDefaults.standard.set(true, forKey:"BraintreeDemoVaultCardSetting") if testArguments.contains("-VaultCardIsFalse") { diff --git a/Demo/Application/DemoDropInViewController.swift b/Demo/Application/DemoDropInViewController.swift index e77a4385..e660f8a9 100644 --- a/Demo/Application/DemoDropInViewController.swift +++ b/Demo/Application/DemoDropInViewController.swift @@ -48,7 +48,6 @@ class DemoDropInViewController: DemoBaseViewController, DemoDropInViewDelegate { dropInRequest.cardholderNameSetting = DemoSettings.cardholderNameSetting dropInRequest.vaultCard = DemoSettings.vaultCardSetting dropInRequest.allowVaultCardOverride = DemoSettings.allowVaultCardOverrideSetting - dropInRequest.collectDeviceData = DemoSettings.collectDeviceDataSetting if ProcessInfo.processInfo.arguments.contains("-PayPalOneTime") { dropInRequest.payPalRequest = BTPayPalCheckoutRequest(amount: "4.77") diff --git a/Demo/Application/Settings/DemoSettings.swift b/Demo/Application/Settings/DemoSettings.swift index 93306f03..431adf66 100644 --- a/Demo/Application/Settings/DemoSettings.swift +++ b/Demo/Application/Settings/DemoSettings.swift @@ -113,10 +113,6 @@ class DemoSettings { static var allowVaultCardOverrideSetting: Bool { return UserDefaults.standard.bool(forKey: "BraintreeDemoAllowVaultCardOverrideSetting") } - - static var collectDeviceDataSetting: Bool { - return UserDefaults.standard.bool(forKey: "BraintreeDemoCollectDeviceDataSetting") - } static var colorSchemeSetting: BTDropInColorScheme { get { diff --git a/Sources/BraintreeDropIn/BTDropInController.m b/Sources/BraintreeDropIn/BTDropInController.m index 75ee2cdf..ed8f8edd 100644 --- a/Sources/BraintreeDropIn/BTDropInController.m +++ b/Sources/BraintreeDropIn/BTDropInController.m @@ -22,26 +22,6 @@ #import #endif -// Import PayPalDataCollector (Swift) module -#if __has_include() // CocoaPods -#import - -#elif SWIFT_PACKAGE // SPM -/* Use @import for SPM support - * See https://forums.swift.org/t/using-a-swift-package-in-a-mixed-swift-and-objective-c-project/27348 - */ -@import PayPalDataCollector; - -#elif __has_include("Braintree-Swift.h") // CocoaPods for ReactNative -/* Use quoted style when importing Swift headers for ReactNative support - * See https://github.com/braintree/braintree_ios/issues/671 - */ -#import "Braintree-Swift.h" - -#else // Carthage -#import -#endif - #define BT_ANIMATION_SLIDE_SPEED 0.35 #define BT_ANIMATION_TRANSITION_SPEED 0.1 #define BT_HALF_SHEET_MARGIN 5 @@ -432,8 +412,6 @@ - (void)paymentDriver:(__unused id)driver requestsDismissalOfViewController:(UIV [viewController dismissViewControllerAnimated:YES completion:nil]; } -#pragma mark BTPaymentSelectionViewControllerDelegate - - (void)selectionCompletedWithPaymentMethodType:(BTDropInPaymentMethodType)type nonce:(BTPaymentMethodNonce *)nonce error:(NSError *)error { if (error == nil) { [[NSUserDefaults standardUserDefaults] setInteger:type forKey:@"BT_dropInLastSelectedPaymentMethodType"]; @@ -441,7 +419,6 @@ - (void)selectionCompletedWithPaymentMethodType:(BTDropInPaymentMethodType)type BTDropInResult *result = [BTDropInResult new]; result.paymentMethodType = type; result.paymentMethod = nonce; - result.deviceData = [PPDataCollector collectPayPalDeviceData]; if ([BTUIKViewUtil isPaymentMethodTypeACreditCard:result.paymentMethodType] && [self.configuration.json[@"threeDSecureEnabled"] isTrue] && self.dropInRequest.threeDSecureRequest) { [self.paymentSelectionViewController showLoadingScreen:YES]; [self threeDSecureVerification:nonce]; diff --git a/Sources/BraintreeDropIn/Models/BTDropInResult.m b/Sources/BraintreeDropIn/Models/BTDropInResult.m index f02432e2..85261d43 100644 --- a/Sources/BraintreeDropIn/Models/BTDropInResult.m +++ b/Sources/BraintreeDropIn/Models/BTDropInResult.m @@ -11,26 +11,6 @@ #import #endif -// Import PayPalDataCollector (Swift) module -#if __has_include() // CocoaPods -#import - -#elif SWIFT_PACKAGE // SPM -/* Use @import for SPM support - * See https://forums.swift.org/t/using-a-swift-package-in-a-mixed-swift-and-objective-c-project/27348 - */ -@import PayPalDataCollector; - -#elif __has_include("Braintree-Swift.h") // CocoaPods for ReactNative -/* Use quoted style when importing Swift headers for ReactNative support - * See https://github.com/braintree/braintree_ios/issues/671 - */ -#import "Braintree-Swift.h" - -#else // Carthage -#import -#endif - NSString *const BTDropInResultErrorDomain = @"com.braintreepayments.BTDropInResultErrorDomain"; @implementation BTDropInResult @@ -65,7 +45,6 @@ + (void)mostRecentPaymentMethodForAPIClient:(BTAPIClient * _Nullable)apiClient if (lastSelectedPaymentOptionType == BTDropInPaymentMethodTypeApplePay) { BTDropInResult *result = [BTDropInResult new]; result.paymentMethodType = lastSelectedPaymentOptionType; - result.deviceData = [PPDataCollector collectPayPalDeviceData]; completion(result, nil); return; } @@ -87,7 +66,6 @@ + (void)mostRecentPaymentMethodForAPIClient:(BTAPIClient * _Nullable)apiClient BTDropInResult *result; if (paymentMethodNonces.count > 0) { result = [BTDropInResult new]; - result.deviceData = [PPDataCollector collectPayPalDeviceData]; BTPaymentMethodNonce *paymentMethod = paymentMethodNonces.firstObject; result.paymentMethodType = [BTUIKViewUtil paymentMethodTypeForPaymentInfoType:paymentMethod.type]; result.paymentMethod = paymentMethod; diff --git a/Sources/BraintreeDropIn/Public/BraintreeDropIn/BTDropInRequest.h b/Sources/BraintreeDropIn/Public/BraintreeDropIn/BTDropInRequest.h index 6ff1e31d..4d3210c2 100644 --- a/Sources/BraintreeDropIn/Public/BraintreeDropIn/BTDropInRequest.h +++ b/Sources/BraintreeDropIn/Public/BraintreeDropIn/BTDropInRequest.h @@ -73,13 +73,6 @@ typedef NS_ENUM(NSInteger, BTFormFieldSetting) { /// Optional: Customization options for Braintree Drop-in's user interface. @property (nonatomic, strong, nullable) BTDropInUICustomization *uiCustomization; -/// Optional: When true, Drop-In will use Braintree's advanced fraud protection service to collect device data. The resulting `deviceData` string will be available on `BTDropInResult.deviceData`. -/// -/// This enables you to collect data about a customer's device and correlate it with a session identifier on your server. Collecting and passing this data with transactions helps reduce decline rates. -/// -/// Defaults to false -@property (nonatomic, assign) BOOL collectDeviceData; - @end NS_ASSUME_NONNULL_END diff --git a/Sources/BraintreeDropIn/Public/BraintreeDropIn/BTDropInResult.h b/Sources/BraintreeDropIn/Public/BraintreeDropIn/BTDropInResult.h index 31f617df..6a233a35 100644 --- a/Sources/BraintreeDropIn/Public/BraintreeDropIn/BTDropInResult.h +++ b/Sources/BraintreeDropIn/Public/BraintreeDropIn/BTDropInResult.h @@ -44,13 +44,6 @@ typedef NS_ENUM(NSInteger, BTDropInErrorType) { /// The payment method nonce @property (nonatomic, strong, nullable) BTPaymentMethodNonce *paymentMethod; -/** - * A `deviceData` string that should be passed into server-side calls, such as `Transaction.sale`. This enables you to collect data about a customer's device and correlate it with a session identifier on your server. - * - * Collecting and passing this data with transactions helps reduce decline rates. - */ -@property (nonatomic, strong, nullable) NSString *deviceData; - /** * Fetch a `BTDropInResult` with the customer's most recently vaulted payment method. * If the last payment method selected from Drop-in was Apple Pay, a `BTDropInResult` with From 5b45d42210c945bea24377988516a034956d6767 Mon Sep 17 00:00:00 2001 From: Samantha Cannillo Date: Thu, 8 Jul 2021 11:49:15 -0500 Subject: [PATCH 3/5] Add deviceData property to BTDropInResult; populate it with PPDataCollector deviceData --- .../BraintreeDropIn/Models/BTDropInResult.m | 29 +++++++++++++++++++ .../Public/BraintreeDropIn/BTDropInResult.h | 9 ++++++ 2 files changed, 38 insertions(+) diff --git a/Sources/BraintreeDropIn/Models/BTDropInResult.m b/Sources/BraintreeDropIn/Models/BTDropInResult.m index 85261d43..2909693e 100644 --- a/Sources/BraintreeDropIn/Models/BTDropInResult.m +++ b/Sources/BraintreeDropIn/Models/BTDropInResult.m @@ -11,10 +11,39 @@ #import #endif +// Import PayPalDataCollector (Swift) module +#if __has_include() // CocoaPods +#import + +#elif SWIFT_PACKAGE // SPM +/* Use @import for SPM support + * See https://forums.swift.org/t/using-a-swift-package-in-a-mixed-swift-and-objective-c-project/27348 + */ +@import PayPalDataCollector; + +#elif __has_include("Braintree-Swift.h") // CocoaPods for ReactNative +/* Use quoted style when importing Swift headers for ReactNative support + * See https://github.com/braintree/braintree_ios/issues/671 + */ +#import "Braintree-Swift.h" + +#else // Carthage +#import +#endif + NSString *const BTDropInResultErrorDomain = @"com.braintreepayments.BTDropInResultErrorDomain"; @implementation BTDropInResult +- (instancetype)init { + self = [super init]; + if (self) { + _deviceData = [PPDataCollector collectPayPalDeviceData]; + } + + return self; +} + #pragma mark - Prefetch BTDropInResult static NSUserDefaults *_userDefaults = nil; diff --git a/Sources/BraintreeDropIn/Public/BraintreeDropIn/BTDropInResult.h b/Sources/BraintreeDropIn/Public/BraintreeDropIn/BTDropInResult.h index 6a233a35..b9a0e984 100644 --- a/Sources/BraintreeDropIn/Public/BraintreeDropIn/BTDropInResult.h +++ b/Sources/BraintreeDropIn/Public/BraintreeDropIn/BTDropInResult.h @@ -44,6 +44,15 @@ typedef NS_ENUM(NSInteger, BTDropInErrorType) { /// The payment method nonce @property (nonatomic, strong, nullable) BTPaymentMethodNonce *paymentMethod; +/** + * A `deviceData` string that represents data about a customer's device. This is generated from Braintree's advanced fraud protection service. + * + * `deviceData` should be passed into server-side calls, such as `Transaction.sale`. This enables you to collect data about a customer's device and correlate it with a session identifier on your server. + * + * Collecting and passing this data with transactions helps reduce decline rates and detect fraudulent transactions. + */ +@property (nonatomic, strong, nullable) NSString *deviceData; + /** * Fetch a `BTDropInResult` with the customer's most recently vaulted payment method. * If the last payment method selected from Drop-in was Apple Pay, a `BTDropInResult` with From 7641ace5506ef08c904320804b799fb4f4d735c8 Mon Sep 17 00:00:00 2001 From: Samantha Cannillo Date: Thu, 8 Jul 2021 14:41:58 -0500 Subject: [PATCH 4/5] Add tests for deviceData collection in BTDropInResult --- BraintreeDropIn.xcodeproj/project.pbxproj | 4 ++++ Sources/BraintreeDropIn/Models/BTDropInResult.m | 12 +++++++++++- .../BraintreeDropIn/Models/BTDropInResult_Internal.h | 4 ++++ UnitTests/BTDropInRequestTests.m | 5 +++++ UnitTests/BTDropInResultTests.swift | 9 +++++++++ UnitTests/MockPPDataCollector.swift | 12 ++++++++++++ 6 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 UnitTests/MockPPDataCollector.swift diff --git a/BraintreeDropIn.xcodeproj/project.pbxproj b/BraintreeDropIn.xcodeproj/project.pbxproj index 90c5db90..6298705f 100644 --- a/BraintreeDropIn.xcodeproj/project.pbxproj +++ b/BraintreeDropIn.xcodeproj/project.pbxproj @@ -81,6 +81,7 @@ 42EA70662616682800B7E626 /* BTDropInResult_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 42EA70652616682800B7E626 /* BTDropInResult_Internal.h */; }; 8005E86125BB32A6003EC2AC /* MockVenmoDriver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8005E86025BB32A6003EC2AC /* MockVenmoDriver.swift */; }; 8005E86625BB34B5003EC2AC /* MockAPIClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8005E86525BB34B5003EC2AC /* MockAPIClient.swift */; }; + 8038FA13269789ED007BE751 /* MockPPDataCollector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8038FA12269789ED007BE751 /* MockPPDataCollector.swift */; }; 8053850226162ED80085B16C /* BTConfiguration+DropIn.h in Headers */ = {isa = PBXBuildFile; fileRef = 8053850126162ED80085B16C /* BTConfiguration+DropIn.h */; settings = {ATTRIBUTES = (Private, ); }; }; 80538508261630430085B16C /* BTConfiguration+DropIn.m in Sources */ = {isa = PBXBuildFile; fileRef = 80538507261630430085B16C /* BTConfiguration+DropIn.m */; }; 805952552615247900DAB6C3 /* BTDropInLocalization_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 805952542615247900DAB6C3 /* BTDropInLocalization_Internal.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -244,6 +245,7 @@ 8005E86525BB34B5003EC2AC /* MockAPIClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAPIClient.swift; sourceTree = ""; }; 800FC5E125802B5600DEE132 /* BTUIKMasterCardVectorArtView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BTUIKMasterCardVectorArtView.m; sourceTree = ""; }; 800FC5E225802B5600DEE132 /* BTUIKMasterCardVectorArtView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BTUIKMasterCardVectorArtView.h; sourceTree = ""; }; + 8038FA12269789ED007BE751 /* MockPPDataCollector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockPPDataCollector.swift; sourceTree = ""; }; 8053850126162ED80085B16C /* BTConfiguration+DropIn.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "BTConfiguration+DropIn.h"; sourceTree = ""; }; 80538507261630430085B16C /* BTConfiguration+DropIn.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "BTConfiguration+DropIn.m"; sourceTree = ""; }; 805952542615247900DAB6C3 /* BTDropInLocalization_Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BTDropInLocalization_Internal.h; sourceTree = ""; }; @@ -621,6 +623,7 @@ 8005E86025BB32A6003EC2AC /* MockVenmoDriver.swift */, 4237D7FD25E5BF8D006F6CE3 /* UIFont+BTUIKTests.swift */, 42A10AD8230EE4D600892302 /* UnitTests-Bridging-Header.h */, + 8038FA12269789ED007BE751 /* MockPPDataCollector.swift */, ); path = UnitTests; sourceTree = ""; @@ -961,6 +964,7 @@ A50ED7A61D8AF8C400A78EF0 /* BTPaymentSelectionViewControllerTests.m in Sources */, 425B83982347D3990015D1A4 /* BTUIKAppearanceTests.swift in Sources */, 4245DAF3256C721D00F1A413 /* FakeApplication.swift in Sources */, + 8038FA13269789ED007BE751 /* MockPPDataCollector.swift in Sources */, 0358590B203E09E200FCE1B7 /* BTDropInRequestTests.m in Sources */, 4225EA87257EC59600923CE3 /* BTPaymentMethodNonce+DropInTests.swift in Sources */, ); diff --git a/Sources/BraintreeDropIn/Models/BTDropInResult.m b/Sources/BraintreeDropIn/Models/BTDropInResult.m index 2909693e..bbf50c37 100644 --- a/Sources/BraintreeDropIn/Models/BTDropInResult.m +++ b/Sources/BraintreeDropIn/Models/BTDropInResult.m @@ -35,10 +35,14 @@ @implementation BTDropInResult +// For testing +static Class PayPalDataCollectorClass; +static NSString *PayPalDataCollectorClassString = @"PPDataCollector"; + - (instancetype)init { self = [super init]; if (self) { - _deviceData = [PPDataCollector collectPayPalDeviceData]; + _deviceData = [PayPalDataCollectorClass collectPayPalDeviceData]; } return self; @@ -118,4 +122,10 @@ - (NSString *)paymentDescription { } } +#pragma mark - Test Helpers + ++ (void)setPayPalDataCollectorClass:(Class)payPalDataCollectorClass { + PayPalDataCollectorClass = payPalDataCollectorClass; +} + @end diff --git a/Sources/BraintreeDropIn/Models/BTDropInResult_Internal.h b/Sources/BraintreeDropIn/Models/BTDropInResult_Internal.h index 2cfd4916..07cd0310 100644 --- a/Sources/BraintreeDropIn/Models/BTDropInResult_Internal.h +++ b/Sources/BraintreeDropIn/Models/BTDropInResult_Internal.h @@ -11,6 +11,10 @@ NS_ASSUME_NONNULL_BEGIN + (void)mostRecentPaymentMethodForAPIClient:(BTAPIClient * _Nullable)apiClient completion:(void (^)(BTDropInResult * _Nullable result, NSError * _Nullable error))completion; +// Exposed for testing +// The `PPDataCollector` class, exposed internally for injecting test doubles for unit tests ++ (void)setPayPalDataCollectorClass:(nonnull Class)payPalDataCollectorClass; + @end NS_ASSUME_NONNULL_END diff --git a/UnitTests/BTDropInRequestTests.m b/UnitTests/BTDropInRequestTests.m index be436f32..24c50f17 100644 --- a/UnitTests/BTDropInRequestTests.m +++ b/UnitTests/BTDropInRequestTests.m @@ -72,4 +72,9 @@ - (void)test_copyProperties { XCTAssertEqual(@"GEN", copiedRequest.threeDSecureRequest.additionalInformation.shippingMethodIndicator); } +-(void)testDropInResult_PPData { +// id classMock = OCMClassMock([PPDataCollector class]); +// OCMStub(ClassMethod([classMock collectPayPalDeviceData])).andReturn(aValue); +} + @end diff --git a/UnitTests/BTDropInResultTests.swift b/UnitTests/BTDropInResultTests.swift index a6559787..284fd262 100644 --- a/UnitTests/BTDropInResultTests.swift +++ b/UnitTests/BTDropInResultTests.swift @@ -99,4 +99,13 @@ class BTDropInResultTests: XCTestCase { waitForExpectations(timeout: 1.0) } + + func testInit_callsPayPalDataCollectorCollectDeviceData_andSetsDeviceData() { + BTDropInResult.setPayPalDataCollectorClass(MockPPDataCollector.self) + + let dropInResult = BTDropInResult() + + XCTAssertTrue(MockPPDataCollector.didCollectDeviceData) + XCTAssertEqual(dropInResult.deviceData, "{\"correlation_id\":\"fake-client-metadata\"}") + } } diff --git a/UnitTests/MockPPDataCollector.swift b/UnitTests/MockPPDataCollector.swift new file mode 100644 index 00000000..a7f261b9 --- /dev/null +++ b/UnitTests/MockPPDataCollector.swift @@ -0,0 +1,12 @@ +import Foundation +@testable import PayPalDataCollector + +class MockPPDataCollector: PPDataCollector { + + public static var didCollectDeviceData = false + + override class func collectPayPalDeviceData() -> String { + didCollectDeviceData = true + return "{\"correlation_id\":\"fake-client-metadata\"}" + } +} From 5b33769f86ab32d2ed2eeecbd1c43cb56988241b Mon Sep 17 00:00:00 2001 From: Samantha Cannillo Date: Thu, 8 Jul 2021 14:53:53 -0500 Subject: [PATCH 5/5] Add changelog entry --- CHANGELOG.md | 3 +++ UnitTests/BTDropInRequestTests.m | 5 ----- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a882824..8f132147 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Braintree iOS Drop-in SDK - Release Notes +## unreleased +* Add `deviceData` to `BTDropInResult` + ## 9.1.0 (2021-07-01) * Increase valid Discover card length to 19 digits * iOS 15 Support diff --git a/UnitTests/BTDropInRequestTests.m b/UnitTests/BTDropInRequestTests.m index 24c50f17..be436f32 100644 --- a/UnitTests/BTDropInRequestTests.m +++ b/UnitTests/BTDropInRequestTests.m @@ -72,9 +72,4 @@ - (void)test_copyProperties { XCTAssertEqual(@"GEN", copiedRequest.threeDSecureRequest.additionalInformation.shippingMethodIndicator); } --(void)testDropInResult_PPData { -// id classMock = OCMClassMock([PPDataCollector class]); -// OCMStub(ClassMethod([classMock collectPayPalDeviceData])).andReturn(aValue); -} - @end