diff --git a/.codeclimate.yml b/.codeclimate.yml new file mode 100644 index 00000000..881160fa --- /dev/null +++ b/.codeclimate.yml @@ -0,0 +1,5 @@ +exclude_paths: + - "TouchID.xcodeproj" + - "**/*.h" + - "**/*.m" + - "**/*.swift" diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 00000000..7899ea66 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,58 @@ +{ + "rules": { + "array-bracket-spacing": [2, "never"], + "brace-style": [2, "1tbs"], + "comma-dangle": [2, "never"], + "comma-spacing": [2, { + "before": false, + "after": true + }], + "comma-style": [2, "last"], + "eol-last": 2, + "indent": [2, 2], + "key-spacing": [2, { + "beforeColon": false, + "afterColon": true + }], + "linebreak-style": [2, "unix"], + "max-nested-callbacks": [2, 2], + "new-parens": 2, + "no-nested-ternary": 2, + "no-new-object": 2, + "no-spaced-func": 2, + "no-trailing-spaces": 2, + "no-unneeded-ternary": 2, + "object-curly-spacing": [2, "never"], + "padded-blocks": [2, "never"], + "quote-props": [2, "as-needed"], + "quotes": [2, "single"], + "semi": [2, "always"], + "semi-spacing": [2, { + "before": false, + "after": true + }], + "space-after-keywords": [2, "always"], + "space-before-blocks": [2, "always"], + "space-before-function-paren": [2, "never"], + "space-in-parens": [2, "never"], + "space-infix-ops": 2, + "space-return-throw-case": 2, + "space-unary-ops": [2, { + "words": true, + "nonwords": false + }], + "spaced-comment": [2, "always"], + "wrap-regex": 2 + }, + "env": { + "amd": true, + "es6": true, + "node": true + }, + "ecmaFeatures": { + "jsx": true + }, + "plugins": [ + "react" + ] +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..74aa6636 --- /dev/null +++ b/.gitignore @@ -0,0 +1,27 @@ +# Xcode +# +build/ +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata +*.xccheckout +*.moved-aside +DerivedData +*.hmap +*.ipa +*.xcuserstate + +# npm +# +node_modules/ +npm-debug.log + +# System +# +.DS_Store diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 00000000..58bc6eed --- /dev/null +++ b/.jshintrc @@ -0,0 +1,4 @@ +{ + "esnext": true, + "node": true +} diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..1ac5273a --- /dev/null +++ b/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node_js: + - "0.12" + - "iojs" diff --git a/ApplePayManager.android.js b/ApplePayManager.android.js new file mode 100644 index 00000000..e092f1d6 --- /dev/null +++ b/ApplePayManager.android.js @@ -0,0 +1,17 @@ +/** + * Stub of ApplePayManager for Android. + * + * @providesModule ApplePayManager + * @flow + */ +'use strict'; + +var warning = require('warning'); + +var ApplePayManager = { + test: function() { + warning('Not yet implemented for Android.'); + } +}; + +module.exports = ApplePayManager; diff --git a/ApplePayManager.h b/ApplePayManager.h new file mode 100644 index 00000000..048c1ee2 --- /dev/null +++ b/ApplePayManager.h @@ -0,0 +1,14 @@ +@import UIKit; +@import PassKit; + +#import "RCTBridgeModule.h" + +@interface ApplePayManager : NSObject +@property NSString *paymentProcessor; +@property NSString *paymentProcessorPublicKey; +@property NSString *backendUrl; + +@property (nonatomic, strong) RCTResponseSenderBlock callback; +@property (nonatomic, strong) PKPayment *payment; +@property (nonatomic, copy) void (^completion)(PKPaymentAuthorizationStatus); +@end \ No newline at end of file diff --git a/ApplePayManager.ios.js b/ApplePayManager.ios.js new file mode 100644 index 00000000..f7b9bb1c --- /dev/null +++ b/ApplePayManager.ios.js @@ -0,0 +1,90 @@ +/** + * @providesModule ApplePayManager + * @flow + */ +'use strict'; + +var React = require('react-native'); +var { + NativeModules +} = React; + +var NativeApplePayManager = NativeModules.ApplePayManager; + +/** + * High-level docs for the ApplePayManager iOS API can be written here. + */ + +var ApplePayManager = { + canMakePayments: NativeApplePayManager.canMakePayments, + + canMakePaymentsUsingNetworks: NativeApplePayManager.canMakePaymentsUsingNetworks, + + paymentRequest: function(opts, items) { + var summaryItems = JSON.parse(JSON.stringify(items)); + var options = opts || {}; + options.DEV = __DEV__; + + // Setup total item + var totalItem = { + label: opts.merchantName, + amount: getTotal(items).toString() + }; + + // Add total item to items + summaryItems.push(totalItem); + + // Set amounts as strings + summaryItems.forEach(function(i) { + i.amount = i.amount.toString(); + }); + + return new Promise(function(resolve, reject) { + NativeApplePayManager.paymentRequest(options, summaryItems, function(error, token) { + if (error) { + return reject(error); + } + + resolve(token); + }); + }); + }, + + success: function() { + return new Promise(function(resolve, reject) { + NativeApplePayManager.success(function(error) { + if (error) { + return reject(error); + } + + resolve(true); + }); + }); + }, + + failure: function() { + return new Promise(function(resolve, reject) { + NativeApplePayManager.failure(function(error) { + if (error) { + return reject(error); + } + + resolve(true); + }); + }); + }, + + getTotal: getTotal +}; + +function getTotal(items) { + var total = 0; + + items.forEach(function(i) { + total+= i.amount; + }); + + return total; +} + +module.exports = ApplePayManager; diff --git a/ApplePayManager.m b/ApplePayManager.m new file mode 100644 index 00000000..0463009a --- /dev/null +++ b/ApplePayManager.m @@ -0,0 +1,139 @@ +#import "ApplePayManager.h" +#import "RCTUtils.h" +#import "RCTLog.h" +#import "StripeManager.h" + +@implementation ApplePayManager + +RCT_EXPORT_MODULE() + +// Checks if user can make payments with ApplePay +// +// This functionality may not be supported by their hardware, or it may be +// restricted by parental controls +RCT_EXPORT_METHOD(canMakePayments: (RCTResponseSenderBlock)callback) +{ + if([PKPaymentAuthorizationViewController canMakePayments]) { + callback(@[@true]); + } else { + callback(@[@false]); + } +} + + +// Checks if user can make payments with ApplePay and if a payment card is +// configured +// +// This functionality may not be supported by their hardware, or it may be +// restricted by parental controls +RCT_EXPORT_METHOD(canMakePaymentsUsingNetworks: (RCTResponseSenderBlock)callback) +{ + NSArray *paymentNetworks = @[PKPaymentNetworkAmex, PKPaymentNetworkMasterCard, PKPaymentNetworkVisa]; + + if ([PKPaymentAuthorizationViewController canMakePaymentsUsingNetworks:paymentNetworks]) { + callback(@[@true]); + } else { + callback(@[@false]); + } +} + + +RCT_EXPORT_METHOD(paymentRequest: (NSDictionary *)args + items: (NSArray *)items + callback:(RCTResponseSenderBlock)callback) +{ + // Set callback to self so we can use it later + self.callback = callback; + + // Set Payment Processor + if (!args[@"paymentProcessor"] || !args[@"paymentProcessorPublicKey"]) { + RCTLogError(@"[ApplePay] Your must provide a payment processor and a public key."); + } + + self.paymentProcessor = args[@"paymentProcessor"]; + self.paymentProcessorPublicKey = args[@"paymentProcessorPublicKey"]; + self.backendUrl = args[@"backendUrl"]; + + // Setup Payment Request + PKPaymentRequest *request = [[PKPaymentRequest alloc] init]; + + // Merchant/Currency Setup + request.countryCode = args[@"countryCode"]; + request.currencyCode = args[@"currencyCode"]; + request.merchantIdentifier = args[@"merchantIdentifier"]; + + request.merchantCapabilities = PKMerchantCapabilityDebit; + request.supportedNetworks = @[PKPaymentNetworkAmex, PKPaymentNetworkMasterCard, PKPaymentNetworkVisa]; + + + // Setup product, discount, shipping and total + NSMutableArray *summaryItems = [NSMutableArray array]; + + for (NSDictionary *i in items) { + NSLog(@"Item: %@", i[@"label"]); + PKPaymentSummaryItem *item = [[PKPaymentSummaryItem alloc] init]; + item.label = i[@"label"]; + item.amount = [NSDecimalNumber decimalNumberWithString:i[@"amount"]]; + + [summaryItems addObject:item]; + } + + // Add Payment Items to request + request.paymentSummaryItems = summaryItems; + + // Show Payment Sheet + PKPaymentAuthorizationViewController *const viewController = [[PKPaymentAuthorizationViewController alloc] initWithPaymentRequest: request]; + viewController.delegate = self; + + UIViewController *ctrl = [[[[UIApplication sharedApplication] delegate] window] rootViewController]; + [ctrl presentViewController:viewController animated:YES completion:nil]; + + NSLog(@"Payment Authorization Controller visible."); +} + +RCT_EXPORT_METHOD(success:(RCTResponseSenderBlock)callback) +{ + self.completion(PKPaymentAuthorizationStatusSuccess); + callback(@[[NSNull null]]); +} + +RCT_EXPORT_METHOD(failure:(RCTResponseSenderBlock)callback) +{ + self.completion(PKPaymentAuthorizationStatusFailure); + callback(@[[NSNull null]]); +} + +// Payment authorized handler +- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller + didAuthorizePayment:(PKPayment *)payment + completion:(void (^)(PKPaymentAuthorizationStatus))completion +{ + self.payment = payment; + + // Set completion to self so we can call it from JS + NSLog(@"completion: %@", completion); + self.completion = completion; + + // Select Payment Processor + NSLog(@"Payment Processor: %@", self.paymentProcessor); + + if ([self.paymentProcessor isEqual: @"stripe"]) { + [StripeManager handlePaymentAuthorizationWithPayment:self.paymentProcessorPublicKey + payment:payment + completion:completion + callback:self.callback]; + } else { + RCTLogError(@"[ApplePay] Your payment provider is not yet supported."); + return; + } +} + +// Finish handler +-(void)paymentAuthorizationViewControllerDidFinish:(PKPaymentAuthorizationViewController *)controller +{ + NSLog(@"Payment Authorization Controller dismissed."); + [controller dismissViewControllerAnimated:YES completion:nil]; +} + +@end + diff --git a/ApplePayManager.xcodeproj/project.pbxproj b/ApplePayManager.xcodeproj/project.pbxproj new file mode 100644 index 00000000..e59a45ca --- /dev/null +++ b/ApplePayManager.xcodeproj/project.pbxproj @@ -0,0 +1,465 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 13BE3DEE1AC21097009241FE /* ApplePayManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13BE3DED1AC21097009241FE /* ApplePayManager.m */; }; + AD0A351F1B41B9CC00D6F830 /* STPAPIClient+ApplePay.m in Sources */ = {isa = PBXBuildFile; fileRef = AD0A34E21B41B9CC00D6F830 /* STPAPIClient+ApplePay.m */; }; + AD0A35201B41B9CC00D6F830 /* Stripe+ApplePay.m in Sources */ = {isa = PBXBuildFile; fileRef = AD0A34E31B41B9CC00D6F830 /* Stripe+ApplePay.m */; }; + AD0A35211B41B9CC00D6F830 /* STPCheckoutInternalUIWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = AD0A34FB1B41B9CC00D6F830 /* STPCheckoutInternalUIWebViewController.m */; }; + AD0A35221B41B9CC00D6F830 /* STPCheckoutOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = AD0A34FC1B41B9CC00D6F830 /* STPCheckoutOptions.m */; }; + AD0A35231B41B9CC00D6F830 /* STPCheckoutViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = AD0A34FD1B41B9CC00D6F830 /* STPCheckoutViewController.m */; }; + AD0A35241B41B9CC00D6F830 /* STPColorUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = AD0A35001B41B9CC00D6F830 /* STPColorUtils.m */; }; + AD0A35251B41B9CC00D6F830 /* STPIOSCheckoutWebViewAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = AD0A35021B41B9CC00D6F830 /* STPIOSCheckoutWebViewAdapter.m */; }; + AD0A35261B41B9CC00D6F830 /* STPOSXCheckoutWebViewAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = AD0A35041B41B9CC00D6F830 /* STPOSXCheckoutWebViewAdapter.m */; }; + AD0A35271B41B9CC00D6F830 /* STPStrictURLProtocol.m in Sources */ = {isa = PBXBuildFile; fileRef = AD0A35061B41B9CC00D6F830 /* STPStrictURLProtocol.m */; }; + AD0A35281B41B9CC00D6F830 /* STPAPIClient.m in Sources */ = {isa = PBXBuildFile; fileRef = AD0A35161B41B9CC00D6F830 /* STPAPIClient.m */; }; + AD0A35291B41B9CC00D6F830 /* STPAPIConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = AD0A35181B41B9CC00D6F830 /* STPAPIConnection.m */; }; + AD0A352A1B41B9CC00D6F830 /* STPBankAccount.m in Sources */ = {isa = PBXBuildFile; fileRef = AD0A35191B41B9CC00D6F830 /* STPBankAccount.m */; }; + AD0A352B1B41B9CC00D6F830 /* STPCard.m in Sources */ = {isa = PBXBuildFile; fileRef = AD0A351A1B41B9CC00D6F830 /* STPCard.m */; }; + AD0A352C1B41B9CC00D6F830 /* STPFormEncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = AD0A351C1B41B9CC00D6F830 /* STPFormEncoder.m */; }; + AD0A352D1B41B9CC00D6F830 /* STPToken.m in Sources */ = {isa = PBXBuildFile; fileRef = AD0A351D1B41B9CC00D6F830 /* STPToken.m */; }; + AD0A352E1B41B9CC00D6F830 /* StripeError.m in Sources */ = {isa = PBXBuildFile; fileRef = AD0A351E1B41B9CC00D6F830 /* StripeError.m */; }; + AD0A35471B41D99700D6F830 /* StripeManager.m in Sources */ = {isa = PBXBuildFile; fileRef = AD0A35461B41D99700D6F830 /* StripeManager.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 58B511D91A9E6C8500147676 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "include/$(PRODUCT_NAME)"; + dstSubfolderSpec = 16; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 134814201AA4EA6300B7C361 /* libApplePayManager.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libApplePayManager.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 13BE3DEC1AC21097009241FE /* ApplePayManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ApplePayManager.h; sourceTree = ""; }; + 13BE3DED1AC21097009241FE /* ApplePayManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ApplePayManager.m; sourceTree = ""; }; + AD0A34E21B41B9CC00D6F830 /* STPAPIClient+ApplePay.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "STPAPIClient+ApplePay.m"; sourceTree = ""; }; + AD0A34E31B41B9CC00D6F830 /* Stripe+ApplePay.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "Stripe+ApplePay.m"; sourceTree = ""; }; + AD0A34E51B41B9CC00D6F830 /* Project-Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "Project-Debug.xcconfig"; sourceTree = ""; }; + AD0A34E61B41B9CC00D6F830 /* Project-Release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "Project-Release.xcconfig"; sourceTree = ""; }; + AD0A34E71B41B9CC00D6F830 /* Project-Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "Project-Shared.xcconfig"; sourceTree = ""; }; + AD0A34E81B41B9CC00D6F830 /* StripeiOS Tests-Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "StripeiOS Tests-Debug.xcconfig"; sourceTree = ""; }; + AD0A34E91B41B9CC00D6F830 /* StripeiOS Tests-Release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "StripeiOS Tests-Release.xcconfig"; sourceTree = ""; }; + AD0A34EA1B41B9CC00D6F830 /* StripeiOS Tests-Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "StripeiOS Tests-Shared.xcconfig"; sourceTree = ""; }; + AD0A34EB1B41B9CC00D6F830 /* StripeiOS-Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "StripeiOS-Debug.xcconfig"; sourceTree = ""; }; + AD0A34EC1B41B9CC00D6F830 /* StripeiOS-Release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "StripeiOS-Release.xcconfig"; sourceTree = ""; }; + AD0A34ED1B41B9CC00D6F830 /* StripeiOS-Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "StripeiOS-Shared.xcconfig"; sourceTree = ""; }; + AD0A34EE1B41B9CC00D6F830 /* StripeiOSStatic.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = StripeiOSStatic.xcconfig; sourceTree = ""; }; + AD0A34EF1B41B9CC00D6F830 /* StripeiOSStaticFramework.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = StripeiOSStaticFramework.xcconfig; sourceTree = ""; }; + AD0A34F01B41B9CC00D6F830 /* StripeiOSStaticFrameworkWithoutApplePay.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = StripeiOSStaticFrameworkWithoutApplePay.xcconfig; sourceTree = ""; }; + AD0A34F11B41B9CC00D6F830 /* StripeiOSStaticWithoutApplePay.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = StripeiOSStaticWithoutApplePay.xcconfig; sourceTree = ""; }; + AD0A34F21B41B9CC00D6F830 /* StripeOSX-Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "StripeOSX-Debug.xcconfig"; sourceTree = ""; }; + AD0A34F31B41B9CC00D6F830 /* StripeOSX-Release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "StripeOSX-Release.xcconfig"; sourceTree = ""; }; + AD0A34F41B41B9CC00D6F830 /* StripeOSX-Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "StripeOSX-Shared.xcconfig"; sourceTree = ""; }; + AD0A34F51B41B9CC00D6F830 /* StripeOSXTests-Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "StripeOSXTests-Debug.xcconfig"; sourceTree = ""; }; + AD0A34F61B41B9CC00D6F830 /* StripeOSXTests-Release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "StripeOSXTests-Release.xcconfig"; sourceTree = ""; }; + AD0A34F71B41B9CC00D6F830 /* StripeOSXTests-Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "StripeOSXTests-Shared.xcconfig"; sourceTree = ""; }; + AD0A34F91B41B9CC00D6F830 /* STPCheckoutDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPCheckoutDelegate.h; sourceTree = ""; }; + AD0A34FA1B41B9CC00D6F830 /* STPCheckoutInternalUIWebViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPCheckoutInternalUIWebViewController.h; sourceTree = ""; }; + AD0A34FB1B41B9CC00D6F830 /* STPCheckoutInternalUIWebViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPCheckoutInternalUIWebViewController.m; sourceTree = ""; }; + AD0A34FC1B41B9CC00D6F830 /* STPCheckoutOptions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPCheckoutOptions.m; sourceTree = ""; }; + AD0A34FD1B41B9CC00D6F830 /* STPCheckoutViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPCheckoutViewController.m; sourceTree = ""; }; + AD0A34FE1B41B9CC00D6F830 /* STPCheckoutWebViewAdapter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPCheckoutWebViewAdapter.h; sourceTree = ""; }; + AD0A34FF1B41B9CC00D6F830 /* STPColorUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPColorUtils.h; sourceTree = ""; }; + AD0A35001B41B9CC00D6F830 /* STPColorUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPColorUtils.m; sourceTree = ""; }; + AD0A35011B41B9CC00D6F830 /* STPIOSCheckoutWebViewAdapter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPIOSCheckoutWebViewAdapter.h; sourceTree = ""; }; + AD0A35021B41B9CC00D6F830 /* STPIOSCheckoutWebViewAdapter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPIOSCheckoutWebViewAdapter.m; sourceTree = ""; }; + AD0A35031B41B9CC00D6F830 /* STPOSXCheckoutWebViewAdapter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPOSXCheckoutWebViewAdapter.h; sourceTree = ""; }; + AD0A35041B41B9CC00D6F830 /* STPOSXCheckoutWebViewAdapter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPOSXCheckoutWebViewAdapter.m; sourceTree = ""; }; + AD0A35051B41B9CC00D6F830 /* STPStrictURLProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPStrictURLProtocol.h; sourceTree = ""; }; + AD0A35061B41B9CC00D6F830 /* STPStrictURLProtocol.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPStrictURLProtocol.m; sourceTree = ""; }; + AD0A35071B41B9CC00D6F830 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + AD0A350A1B41B9CC00D6F830 /* STPAPIClient+ApplePay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "STPAPIClient+ApplePay.h"; sourceTree = ""; }; + AD0A350B1B41B9CC00D6F830 /* Stripe+ApplePay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Stripe+ApplePay.h"; sourceTree = ""; }; + AD0A350D1B41B9CC00D6F830 /* STPCheckoutOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPCheckoutOptions.h; sourceTree = ""; }; + AD0A350E1B41B9CC00D6F830 /* STPCheckoutViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPCheckoutViewController.h; sourceTree = ""; }; + AD0A350F1B41B9CC00D6F830 /* STPAPIClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPAPIClient.h; sourceTree = ""; }; + AD0A35101B41B9CC00D6F830 /* STPBankAccount.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPBankAccount.h; sourceTree = ""; }; + AD0A35111B41B9CC00D6F830 /* STPCard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPCard.h; sourceTree = ""; }; + AD0A35121B41B9CC00D6F830 /* STPNullabilityMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPNullabilityMacros.h; sourceTree = ""; }; + AD0A35131B41B9CC00D6F830 /* STPToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPToken.h; sourceTree = ""; }; + AD0A35141B41B9CC00D6F830 /* Stripe.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Stripe.h; sourceTree = ""; }; + AD0A35151B41B9CC00D6F830 /* StripeError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StripeError.h; sourceTree = ""; }; + AD0A35161B41B9CC00D6F830 /* STPAPIClient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPAPIClient.m; sourceTree = ""; }; + AD0A35171B41B9CC00D6F830 /* STPAPIConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPAPIConnection.h; sourceTree = ""; }; + AD0A35181B41B9CC00D6F830 /* STPAPIConnection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPAPIConnection.m; sourceTree = ""; }; + AD0A35191B41B9CC00D6F830 /* STPBankAccount.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPBankAccount.m; sourceTree = ""; }; + AD0A351A1B41B9CC00D6F830 /* STPCard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPCard.m; sourceTree = ""; }; + AD0A351B1B41B9CC00D6F830 /* STPFormEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPFormEncoder.h; sourceTree = ""; }; + AD0A351C1B41B9CC00D6F830 /* STPFormEncoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPFormEncoder.m; sourceTree = ""; }; + AD0A351D1B41B9CC00D6F830 /* STPToken.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPToken.m; sourceTree = ""; }; + AD0A351E1B41B9CC00D6F830 /* StripeError.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StripeError.m; sourceTree = ""; }; + AD0A35451B41D99700D6F830 /* StripeManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StripeManager.h; sourceTree = ""; }; + AD0A35461B41D99700D6F830 /* StripeManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StripeManager.m; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 58B511D81A9E6C8500147676 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 134814211AA4EA7D00B7C361 /* Products */ = { + isa = PBXGroup; + children = ( + 134814201AA4EA6300B7C361 /* libApplePayManager.a */, + ); + name = Products; + sourceTree = ""; + }; + 58B511D21A9E6C8500147676 = { + isa = PBXGroup; + children = ( + AD0A34DF1B41B9CC00D6F830 /* Frameworks */, + 13BE3DEC1AC21097009241FE /* ApplePayManager.h */, + 13BE3DED1AC21097009241FE /* ApplePayManager.m */, + AD0A35451B41D99700D6F830 /* StripeManager.h */, + AD0A35461B41D99700D6F830 /* StripeManager.m */, + 134814211AA4EA7D00B7C361 /* Products */, + ); + sourceTree = ""; + }; + AD0A34DF1B41B9CC00D6F830 /* Frameworks */ = { + isa = PBXGroup; + children = ( + AD0A34E01B41B9CC00D6F830 /* Stripe */, + ); + path = Frameworks; + sourceTree = ""; + }; + AD0A34E01B41B9CC00D6F830 /* Stripe */ = { + isa = PBXGroup; + children = ( + AD0A34E11B41B9CC00D6F830 /* ApplePay */, + AD0A34E41B41B9CC00D6F830 /* BuildConfigurations */, + AD0A34F81B41B9CC00D6F830 /* Checkout */, + AD0A35071B41B9CC00D6F830 /* Info.plist */, + AD0A35081B41B9CC00D6F830 /* PublicHeaders */, + AD0A35161B41B9CC00D6F830 /* STPAPIClient.m */, + AD0A35171B41B9CC00D6F830 /* STPAPIConnection.h */, + AD0A35181B41B9CC00D6F830 /* STPAPIConnection.m */, + AD0A35191B41B9CC00D6F830 /* STPBankAccount.m */, + AD0A351A1B41B9CC00D6F830 /* STPCard.m */, + AD0A351B1B41B9CC00D6F830 /* STPFormEncoder.h */, + AD0A351C1B41B9CC00D6F830 /* STPFormEncoder.m */, + AD0A351D1B41B9CC00D6F830 /* STPToken.m */, + AD0A351E1B41B9CC00D6F830 /* StripeError.m */, + ); + path = Stripe; + sourceTree = ""; + }; + AD0A34E11B41B9CC00D6F830 /* ApplePay */ = { + isa = PBXGroup; + children = ( + AD0A34E21B41B9CC00D6F830 /* STPAPIClient+ApplePay.m */, + AD0A34E31B41B9CC00D6F830 /* Stripe+ApplePay.m */, + ); + path = ApplePay; + sourceTree = ""; + }; + AD0A34E41B41B9CC00D6F830 /* BuildConfigurations */ = { + isa = PBXGroup; + children = ( + AD0A34E51B41B9CC00D6F830 /* Project-Debug.xcconfig */, + AD0A34E61B41B9CC00D6F830 /* Project-Release.xcconfig */, + AD0A34E71B41B9CC00D6F830 /* Project-Shared.xcconfig */, + AD0A34E81B41B9CC00D6F830 /* StripeiOS Tests-Debug.xcconfig */, + AD0A34E91B41B9CC00D6F830 /* StripeiOS Tests-Release.xcconfig */, + AD0A34EA1B41B9CC00D6F830 /* StripeiOS Tests-Shared.xcconfig */, + AD0A34EB1B41B9CC00D6F830 /* StripeiOS-Debug.xcconfig */, + AD0A34EC1B41B9CC00D6F830 /* StripeiOS-Release.xcconfig */, + AD0A34ED1B41B9CC00D6F830 /* StripeiOS-Shared.xcconfig */, + AD0A34EE1B41B9CC00D6F830 /* StripeiOSStatic.xcconfig */, + AD0A34EF1B41B9CC00D6F830 /* StripeiOSStaticFramework.xcconfig */, + AD0A34F01B41B9CC00D6F830 /* StripeiOSStaticFrameworkWithoutApplePay.xcconfig */, + AD0A34F11B41B9CC00D6F830 /* StripeiOSStaticWithoutApplePay.xcconfig */, + AD0A34F21B41B9CC00D6F830 /* StripeOSX-Debug.xcconfig */, + AD0A34F31B41B9CC00D6F830 /* StripeOSX-Release.xcconfig */, + AD0A34F41B41B9CC00D6F830 /* StripeOSX-Shared.xcconfig */, + AD0A34F51B41B9CC00D6F830 /* StripeOSXTests-Debug.xcconfig */, + AD0A34F61B41B9CC00D6F830 /* StripeOSXTests-Release.xcconfig */, + AD0A34F71B41B9CC00D6F830 /* StripeOSXTests-Shared.xcconfig */, + ); + path = BuildConfigurations; + sourceTree = ""; + }; + AD0A34F81B41B9CC00D6F830 /* Checkout */ = { + isa = PBXGroup; + children = ( + AD0A34F91B41B9CC00D6F830 /* STPCheckoutDelegate.h */, + AD0A34FA1B41B9CC00D6F830 /* STPCheckoutInternalUIWebViewController.h */, + AD0A34FB1B41B9CC00D6F830 /* STPCheckoutInternalUIWebViewController.m */, + AD0A34FC1B41B9CC00D6F830 /* STPCheckoutOptions.m */, + AD0A34FD1B41B9CC00D6F830 /* STPCheckoutViewController.m */, + AD0A34FE1B41B9CC00D6F830 /* STPCheckoutWebViewAdapter.h */, + AD0A34FF1B41B9CC00D6F830 /* STPColorUtils.h */, + AD0A35001B41B9CC00D6F830 /* STPColorUtils.m */, + AD0A35011B41B9CC00D6F830 /* STPIOSCheckoutWebViewAdapter.h */, + AD0A35021B41B9CC00D6F830 /* STPIOSCheckoutWebViewAdapter.m */, + AD0A35031B41B9CC00D6F830 /* STPOSXCheckoutWebViewAdapter.h */, + AD0A35041B41B9CC00D6F830 /* STPOSXCheckoutWebViewAdapter.m */, + AD0A35051B41B9CC00D6F830 /* STPStrictURLProtocol.h */, + AD0A35061B41B9CC00D6F830 /* STPStrictURLProtocol.m */, + ); + path = Checkout; + sourceTree = ""; + }; + AD0A35081B41B9CC00D6F830 /* PublicHeaders */ = { + isa = PBXGroup; + children = ( + AD0A35091B41B9CC00D6F830 /* ApplePay */, + AD0A350C1B41B9CC00D6F830 /* Checkout */, + AD0A350F1B41B9CC00D6F830 /* STPAPIClient.h */, + AD0A35101B41B9CC00D6F830 /* STPBankAccount.h */, + AD0A35111B41B9CC00D6F830 /* STPCard.h */, + AD0A35121B41B9CC00D6F830 /* STPNullabilityMacros.h */, + AD0A35131B41B9CC00D6F830 /* STPToken.h */, + AD0A35141B41B9CC00D6F830 /* Stripe.h */, + AD0A35151B41B9CC00D6F830 /* StripeError.h */, + ); + path = PublicHeaders; + sourceTree = ""; + }; + AD0A35091B41B9CC00D6F830 /* ApplePay */ = { + isa = PBXGroup; + children = ( + AD0A350A1B41B9CC00D6F830 /* STPAPIClient+ApplePay.h */, + AD0A350B1B41B9CC00D6F830 /* Stripe+ApplePay.h */, + ); + path = ApplePay; + sourceTree = ""; + }; + AD0A350C1B41B9CC00D6F830 /* Checkout */ = { + isa = PBXGroup; + children = ( + AD0A350D1B41B9CC00D6F830 /* STPCheckoutOptions.h */, + AD0A350E1B41B9CC00D6F830 /* STPCheckoutViewController.h */, + ); + path = Checkout; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 58B511DA1A9E6C8500147676 /* ApplePayManager */ = { + isa = PBXNativeTarget; + buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "ApplePayManager" */; + buildPhases = ( + 58B511D71A9E6C8500147676 /* Sources */, + 58B511D81A9E6C8500147676 /* Frameworks */, + 58B511D91A9E6C8500147676 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ApplePayManager; + productName = RCTDataManager; + productReference = 134814201AA4EA6300B7C361 /* libApplePayManager.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 58B511D31A9E6C8500147676 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0610; + ORGANIZATIONNAME = Facebook; + TargetAttributes = { + 58B511DA1A9E6C8500147676 = { + CreatedOnToolsVersion = 6.1.1; + }; + }; + }; + buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "ApplePayManager" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 58B511D21A9E6C8500147676; + productRefGroup = 58B511D21A9E6C8500147676; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 58B511DA1A9E6C8500147676 /* ApplePayManager */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 58B511D71A9E6C8500147676 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + AD0A35281B41B9CC00D6F830 /* STPAPIClient.m in Sources */, + AD0A35211B41B9CC00D6F830 /* STPCheckoutInternalUIWebViewController.m in Sources */, + AD0A35471B41D99700D6F830 /* StripeManager.m in Sources */, + AD0A35201B41B9CC00D6F830 /* Stripe+ApplePay.m in Sources */, + AD0A352E1B41B9CC00D6F830 /* StripeError.m in Sources */, + AD0A35261B41B9CC00D6F830 /* STPOSXCheckoutWebViewAdapter.m in Sources */, + 13BE3DEE1AC21097009241FE /* ApplePayManager.m in Sources */, + AD0A352B1B41B9CC00D6F830 /* STPCard.m in Sources */, + AD0A35271B41B9CC00D6F830 /* STPStrictURLProtocol.m in Sources */, + AD0A35291B41B9CC00D6F830 /* STPAPIConnection.m in Sources */, + AD0A352A1B41B9CC00D6F830 /* STPBankAccount.m in Sources */, + AD0A35251B41B9CC00D6F830 /* STPIOSCheckoutWebViewAdapter.m in Sources */, + AD0A351F1B41B9CC00D6F830 /* STPAPIClient+ApplePay.m in Sources */, + AD0A35241B41B9CC00D6F830 /* STPColorUtils.m in Sources */, + AD0A352C1B41B9CC00D6F830 /* STPFormEncoder.m in Sources */, + AD0A352D1B41B9CC00D6F830 /* STPToken.m in Sources */, + AD0A35231B41B9CC00D6F830 /* STPCheckoutViewController.m in Sources */, + AD0A35221B41B9CC00D6F830 /* STPCheckoutOptions.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 58B511ED1A9E6C8500147676 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 7.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 58B511EE1A9E6C8500147676 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 7.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 58B511F01A9E6C8500147676 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../React/**", + "$(SRCROOT)/../../node_modules/react-native/React/**", + ); + LIBRARY_SEARCH_PATHS = "$(inherited)"; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = ApplePayManager; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 58B511F11A9E6C8500147676 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(SRCROOT)/../../React/**", + ); + LIBRARY_SEARCH_PATHS = "$(inherited)"; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = ApplePayManager; + SKIP_INSTALL = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "ApplePayManager" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 58B511ED1A9E6C8500147676 /* Debug */, + 58B511EE1A9E6C8500147676 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "ApplePayManager" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 58B511F01A9E6C8500147676 /* Debug */, + 58B511F11A9E6C8500147676 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 58B511D31A9E6C8500147676 /* Project object */; +} diff --git a/ApplePayManager.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ApplePayManager.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..919434a6 --- /dev/null +++ b/ApplePayManager.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Frameworks/Stripe/ApplePay/STPAPIClient+ApplePay.m b/Frameworks/Stripe/ApplePay/STPAPIClient+ApplePay.m new file mode 100755 index 00000000..c1479785 --- /dev/null +++ b/Frameworks/Stripe/ApplePay/STPAPIClient+ApplePay.m @@ -0,0 +1,86 @@ +// +// STPAPIClient+ApplePay.m +// Stripe +// +// Created by Jack Flintermann on 12/19/14. +// + +#import "STPAPIClient+ApplePay.h" +#import + +@implementation STPAPIClient (ApplePay) + +- (void)createTokenWithPayment:(PKPayment *)payment completion:(STPCompletionBlock)completion { + [self createTokenWithData:[self.class formEncodedDataForPayment:payment] completion:completion]; +} + ++ (NSData *)formEncodedDataForPayment:(PKPayment *)payment { + NSCAssert(payment != nil, @"Cannot create a token with a nil payment."); + NSMutableCharacterSet *set = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy]; + [set removeCharactersInString:@"+="]; + NSString *paymentString = + [[[NSString alloc] initWithData:payment.token.paymentData encoding:NSUTF8StringEncoding] stringByAddingPercentEncodingWithAllowedCharacters:set]; + __block NSString *payloadString = [@"pk_token=" stringByAppendingString:paymentString]; + + if (payment.billingAddress) { + NSMutableDictionary *params = [NSMutableDictionary dictionary]; + + NSString *firstName = (__bridge_transfer NSString*)ABRecordCopyValue(payment.billingAddress, kABPersonFirstNameProperty); + NSString *lastName = (__bridge_transfer NSString*)ABRecordCopyValue(payment.billingAddress, kABPersonLastNameProperty); + if (firstName.length && lastName.length) { + params[@"name"] = [NSString stringWithFormat:@"%@ %@", firstName, lastName]; + } + + ABMultiValueRef addressValues = ABRecordCopyValue(payment.billingAddress, kABPersonAddressProperty); + if (addressValues != NULL) { + if (ABMultiValueGetCount(addressValues) > 0) { + CFDictionaryRef dict = ABMultiValueCopyValueAtIndex(addressValues, 0); + NSString *line1 = CFDictionaryGetValue(dict, kABPersonAddressStreetKey); + if (line1) { + params[@"address_line1"] = line1; + } + NSString *city = CFDictionaryGetValue(dict, kABPersonAddressCityKey); + if (city) { + params[@"address_city"] = city; + } + NSString *state = CFDictionaryGetValue(dict, kABPersonAddressStateKey); + if (state) { + params[@"address_state"] = state; + } + NSString *zip = CFDictionaryGetValue(dict, kABPersonAddressZIPKey); + if (zip) { + params[@"address_zip"] = zip; + } + NSString *country = CFDictionaryGetValue(dict, kABPersonAddressCountryKey); + if (country) { + params[@"address_country"] = country; + } + CFRelease(dict); + [params enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, __unused BOOL *stop) { + NSString *param = [NSString stringWithFormat:@"&card[%@]=%@", key, [obj stringByAddingPercentEncodingWithAllowedCharacters:set]]; + payloadString = [payloadString stringByAppendingString:param]; + }]; + } + CFRelease(addressValues); + } + } + + if (payment.token.paymentInstrumentName) { + NSString *param = [NSString stringWithFormat:@"&pk_token_instrument_name=%@", payment.token.paymentInstrumentName]; + payloadString = [payloadString stringByAppendingString:param]; + } + + if (payment.token.paymentNetwork) { + NSString *param = [NSString stringWithFormat:@"&pk_token_payment_network=%@", payment.token.paymentNetwork]; + payloadString = [payloadString stringByAppendingString:param]; + } + + if (payment.token.transactionIdentifier) { + NSString *param = [NSString stringWithFormat:@"&pk_token_transaction_id=%@", payment.token.transactionIdentifier]; + payloadString = [payloadString stringByAppendingString:param]; + } + + return [payloadString dataUsingEncoding:NSUTF8StringEncoding]; +} + +@end diff --git a/Frameworks/Stripe/ApplePay/Stripe+ApplePay.m b/Frameworks/Stripe/ApplePay/Stripe+ApplePay.m new file mode 100755 index 00000000..2d191b28 --- /dev/null +++ b/Frameworks/Stripe/ApplePay/Stripe+ApplePay.m @@ -0,0 +1,43 @@ +// +// Stripe+ApplePay.m +// Stripe +// +// Created by Jack Flintermann on 9/17/14. +// + +#import "Stripe+ApplePay.h" +#import "STPAPIClient.h" + +@implementation Stripe (ApplePay) + ++ (BOOL)canSubmitPaymentRequest:(PKPaymentRequest *)paymentRequest { + if (paymentRequest == nil) { + return NO; + } + return [PKPaymentAuthorizationViewController canMakePaymentsUsingNetworks:paymentRequest.supportedNetworks]; +} + ++ (PKPaymentRequest *)paymentRequestWithMerchantIdentifier:(NSString *)merchantIdentifier { + if (![PKPaymentRequest class]) { + return nil; + } + PKPaymentRequest *paymentRequest = [PKPaymentRequest new]; + [paymentRequest setMerchantIdentifier:merchantIdentifier]; + [paymentRequest setSupportedNetworks:@[PKPaymentNetworkAmex, PKPaymentNetworkMasterCard, PKPaymentNetworkVisa]]; + [paymentRequest setMerchantCapabilities:PKMerchantCapability3DS]; + [paymentRequest setCountryCode:@"US"]; + [paymentRequest setCurrencyCode:@"USD"]; + return paymentRequest; +} + ++ (void)createTokenWithPayment:(PKPayment *)payment completion:(STPCompletionBlock)handler { + [self createTokenWithPayment:payment operationQueue:[NSOperationQueue mainQueue] completion:handler]; +} + ++ (void)createTokenWithPayment:(PKPayment *)payment operationQueue:(NSOperationQueue *)queue completion:(STPCompletionBlock)handler { + STPAPIClient *client = [[STPAPIClient alloc] init]; + client.operationQueue = queue; + [client createTokenWithPayment:payment completion:handler]; +} + +@end diff --git a/Frameworks/Stripe/BuildConfigurations/Project-Debug.xcconfig b/Frameworks/Stripe/BuildConfigurations/Project-Debug.xcconfig new file mode 100755 index 00000000..b4a119b9 --- /dev/null +++ b/Frameworks/Stripe/BuildConfigurations/Project-Debug.xcconfig @@ -0,0 +1,57 @@ +// +// Project-Debug.xcconfig +// +// Generated by BuildSettingExtractor on 4/27/15 +// https://github.com/dempseyatgithub/BuildSettingExtractor +// + +#include "Project-Shared.xcconfig" + + +// Strip Debug Symbols During Copy +// +// Activating this setting causes binary files which are copied during the build (e.g., +// in a Copy Bundle Resources or Copy Files build phase) to be stripped of debugging +// symbols. It does not cause the linked product of a target to be stripped (use Strip +// Linked Product for that). + +COPY_PHASE_STRIP = NO + + +GCC_DYNAMIC_NO_PIC = NO + + +GCC_OPTIMIZATION_LEVEL = 0 + + +GCC_PREPROCESSOR_DEFINITIONS = DEBUG=1 $(inherited) + + +GCC_SYMBOLS_PRIVATE_EXTERN = NO + + +// Build Active Architecture Only +// +// When checked, only the active architecture is built for faster debugging turnaround + +ONLY_ACTIVE_ARCH = YES + +// iOS Deployment Target +// +// Code will load on this and later versions of iOS. Framework APIs that are unavailable +// in earlier versions will be weak-linked; your code should check for null function +// pointers or specific system versions before calling newer APIs. +// +// iOS 4.3 - Code will not load on systems earlier than 4.3. [4.3] +// iOS 5.0 - Code will not load on systems earlier than 5.0. [5.0] +// iOS 5.1 - Code will not load on systems earlier than 5.1. [5.1] +// iOS 6.0 - Code will not load on systems earlier than 6.0. [6.0] +// iOS 6.1 - Code will not load on systems earlier than 6.1. [6.1] +// iOS 7.0 - Code will not load on systems earlier than 7.0. [7.0] +// iOS 7.1 - Code will not load on systems earlier than 7.1. [7.1] +// iOS 8.0 - Code will not load on systems earlier than 8.0. [8.0] +// iOS 8.1 - Code will not load on systems earlier than 8.1. [8.1] +// iOS 8.2 - Code will not load on systems earlier than 8.2. [8.2] +// iOS 8.3 - Code will not load on systems earlier than 8.3. [8.3] + +IPHONEOS_DEPLOYMENT_TARGET = 6.0 diff --git a/Frameworks/Stripe/BuildConfigurations/Project-Release.xcconfig b/Frameworks/Stripe/BuildConfigurations/Project-Release.xcconfig new file mode 100755 index 00000000..f9999348 --- /dev/null +++ b/Frameworks/Stripe/BuildConfigurations/Project-Release.xcconfig @@ -0,0 +1,52 @@ +// +// Project-Release.xcconfig +// +// Generated by BuildSettingExtractor on 4/27/15 +// https://github.com/dempseyatgithub/BuildSettingExtractor +// + +#include "Project-Shared.xcconfig" + + +// Strip Debug Symbols During Copy +// +// Activating this setting causes binary files which are copied during the build (e.g., +// in a Copy Bundle Resources or Copy Files build phase) to be stripped of debugging +// symbols. It does not cause the linked product of a target to be stripped (use Strip +// Linked Product for that). + +COPY_PHASE_STRIP = YES + + +ENABLE_NS_ASSERTIONS = NO + + +GCC_PREPROCESSOR_DEFINITIONS = NDEBUG + + +// Validate Built Product +// +// Activating this setting will cause Xcode to perform validation checks on the product +// as part of the build process. + +VALIDATE_PRODUCT = YES + +// iOS Deployment Target +// +// Code will load on this and later versions of iOS. Framework APIs that are unavailable +// in earlier versions will be weak-linked; your code should check for null function +// pointers or specific system versions before calling newer APIs. +// +// iOS 4.3 - Code will not load on systems earlier than 4.3. [4.3] +// iOS 5.0 - Code will not load on systems earlier than 5.0. [5.0] +// iOS 5.1 - Code will not load on systems earlier than 5.1. [5.1] +// iOS 6.0 - Code will not load on systems earlier than 6.0. [6.0] +// iOS 6.1 - Code will not load on systems earlier than 6.1. [6.1] +// iOS 7.0 - Code will not load on systems earlier than 7.0. [7.0] +// iOS 7.1 - Code will not load on systems earlier than 7.1. [7.1] +// iOS 8.0 - Code will not load on systems earlier than 8.0. [8.0] +// iOS 8.1 - Code will not load on systems earlier than 8.1. [8.1] +// iOS 8.2 - Code will not load on systems earlier than 8.2. [8.2] +// iOS 8.3 - Code will not load on systems earlier than 8.3. [8.3] + +IPHONEOS_DEPLOYMENT_TARGET = 8.0 diff --git a/Frameworks/Stripe/BuildConfigurations/Project-Shared.xcconfig b/Frameworks/Stripe/BuildConfigurations/Project-Shared.xcconfig new file mode 100755 index 00000000..308b1023 --- /dev/null +++ b/Frameworks/Stripe/BuildConfigurations/Project-Shared.xcconfig @@ -0,0 +1,125 @@ +// +// Project-Shared.xcconfig +// +// Generated by BuildSettingExtractor on 4/27/15 +// https://github.com/dempseyatgithub/BuildSettingExtractor +// + + +// Always Search User Paths +// +// If enabled both #include -style and #include "header.h"-style directives +// will search the paths in "User Header Search Paths" before "Header Search Paths", with +// the consequence that user headers (such as your own String.h header) would have +// precedence over system headers when using #include . This is done using the +// -iquote flag for the paths provided in "User Header Search Paths". If disabled and +// your compiler fully supports separate user paths, user headers will only be accessible +// with #include "header.h"-style preprocessor directives. +// +// For backwards compatibility reasons, this setting is enabled by default, but disabling +// it is strongly recommended. + +ALWAYS_SEARCH_USER_PATHS = NO + + +CLANG_ENABLE_OBJC_ARC = YES + + +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES + + +CLANG_WARN_BOOL_CONVERSION = YES + + +CLANG_WARN_CONSTANT_CONVERSION = YES + + +CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES + + +CLANG_WARN_EMPTY_BODY = YES + + +CLANG_WARN_ENUM_CONVERSION = YES + + +CLANG_WARN_INT_CONVERSION = YES + + +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES + + +CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES + + +CLANG_WARN_UNREACHABLE_CODE = YES + + +ENABLE_STRICT_OBJC_MSGSEND = YES + + +GCC_C_LANGUAGE_STANDARD = gnu99 + + +// Compiler for C/C++/Objective-C +// +// The compiler to use for C, C++, and Objective-C. + +GCC_VERSION = com.apple.compilers.llvm.clang.1_0 + + +GCC_WARN_64_TO_32_BIT_CONVERSION = YES + + +GCC_WARN_ABOUT_MISSING_NEWLINE = YES + + +GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES + + +GCC_WARN_ABOUT_RETURN_TYPE = YES + + +GCC_WARN_SIGN_COMPARE = YES + + +GCC_WARN_UNDECLARED_SELECTOR = YES + + +GCC_WARN_UNINITIALIZED_AUTOS = YES + + +GCC_WARN_UNUSED_FUNCTION = YES + + +GCC_WARN_UNUSED_VARIABLE = YES + +// Precompiled Header Uses Files From Build Directory +// +// This setting allows for better control of sharing precompiled prefix header files +// between projects. By default, Xcode assumes that the prefix header file may include +// header files from the build directory if the build directory is outside of the project +// directory. (Xcode cannot determine this ahead of time since other projects may not +// have been built into the shared build directory at the time the information is +// needed.) +// +// If your prefix file never includes files from the build directory you may set this to +// "NO" to improve sharing of precompiled headers. If the prefix does use files from a +// build directory which is inside your project directory, you may set this to "YES" to +// avoid unintended sharing that may result in build failures. + +PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR = NO + + +// Base SDK +// +// The name or path of the base SDK being used during the build. The product will be +// built against the headers and libraries located inside the indicated SDK. This path +// will be prepended to all search paths, and will be passed through the environment to +// the compiler and linker. Additional SDKs can be specified in the ADDITIONAL_SDKS +// setting. + +SDKROOT = iphoneos + + +WARNING_CFLAGS = -Wall -Wextra -Wundef -Wfloat-equal diff --git a/Frameworks/Stripe/BuildConfigurations/StripeOSX-Debug.xcconfig b/Frameworks/Stripe/BuildConfigurations/StripeOSX-Debug.xcconfig new file mode 100755 index 00000000..1ff05b1f --- /dev/null +++ b/Frameworks/Stripe/BuildConfigurations/StripeOSX-Debug.xcconfig @@ -0,0 +1,11 @@ +// +// StripeOSX-Debug.xcconfig +// +// Generated by BuildSettingExtractor on 4/27/15 +// https://github.com/dempseyatgithub/BuildSettingExtractor +// + +#include "StripeOSX-Shared.xcconfig" + + +GCC_PREPROCESSOR_DEFINITIONS = DEBUG=1 $(inherited) \ No newline at end of file diff --git a/Frameworks/Stripe/BuildConfigurations/StripeOSX-Release.xcconfig b/Frameworks/Stripe/BuildConfigurations/StripeOSX-Release.xcconfig new file mode 100755 index 00000000..727af80b --- /dev/null +++ b/Frameworks/Stripe/BuildConfigurations/StripeOSX-Release.xcconfig @@ -0,0 +1,22 @@ +// +// StripeOSX-Release.xcconfig +// +// Generated by BuildSettingExtractor on 4/27/15 +// https://github.com/dempseyatgithub/BuildSettingExtractor +// + +#include "StripeOSX-Shared.xcconfig" + + +// Debug Information Format +// +// This setting controls the format of debug information used by the developer tools. +// +// DWARF - Object files and linked products will use DWARF as the debug information +// format. [dwarf] +// DWARF with dSYM File - Object files and linked products will use DWARF as the debug +// information format, and Xcode will also produce a dSYM file containing the debug +// information from the individual object files (except that a dSYM file is not needed +// and will not be created for static library or object file products). [dwarf-with-dsym] + +DEBUG_INFORMATION_FORMAT = dwarf-with-dsym \ No newline at end of file diff --git a/Frameworks/Stripe/BuildConfigurations/StripeOSX-Shared.xcconfig b/Frameworks/Stripe/BuildConfigurations/StripeOSX-Shared.xcconfig new file mode 100755 index 00000000..91f46437 --- /dev/null +++ b/Frameworks/Stripe/BuildConfigurations/StripeOSX-Shared.xcconfig @@ -0,0 +1,184 @@ +// +// StripeOSX-Shared.xcconfig +// +// Generated by BuildSettingExtractor on 4/27/15 +// https://github.com/dempseyatgithub/BuildSettingExtractor +// + + +CLANG_CXX_LANGUAGE_STANDARD = gnu++0x + + +CLANG_CXX_LIBRARY = libc++ + + +CLANG_ENABLE_MODULES = YES + + +CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR + + +CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR + + +// Combine High Resolution Artwork +// +// Combines image files at different resolutions into one multi-page TIFF file that is +// HiDPI compliant for Mac OS X 10.7 and later. Only image files in the same directory +// and with the same base name and extension are combined. The file names must conform to +// the naming convention used in HiDPI. + +COMBINE_HIDPI_IMAGES = YES + + +// Current Project Version +// +// This setting defines the the current version of the project. The value must be a +// integer or floating point number like 57 or 365.8. + +CURRENT_PROJECT_VERSION = 1 + + +// Defines Module +// +// If enabled, the product will be treated as defining its own module. This enables +// automatic production of LLVM module map files when appropriate, and allows the product +// to be imported as a module. + +DEFINES_MODULE = YES + + +// Compatibility Version +// +// Determines the compatibility version of the resulting library, bundle, or framework +// binary. + +DYLIB_COMPATIBILITY_VERSION = 1 + + +// Current Library Version +// +// This setting defines the the current version of any framework built by the project. +// Like "Current Project Version", the value must be an integer or floating point number +// like 57 or 365.8. By default it is set to $(CURRENT_PROJECT_VERSION). + +DYLIB_CURRENT_VERSION = 1 + + +// Dynamic Library Install Name Base +// +// Sets the base value for the internal "install path" (LC_ID_DYLIB) in a dynamic +// library. This will be combined with the EXECUTABLE_PATH to form the full install path. +// Setting LD_DYLIB_INSTALL_NAME directly will override this setting. This setting +// defaults to the target's INSTALL_PATH. It is ignored when building any product other +// than a dynamic library. [-install_name] + +DYLIB_INSTALL_NAME_BASE = @rpath + + +// Framework Version +// +// Framework bundles are versioned by having contents in subfolders of a version folder +// that has links to the current version and its contents. + +FRAMEWORK_VERSION = A + + +GCC_TREAT_WARNINGS_AS_ERRORS = YES + + +GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR + + +GCC_WARN_SHADOW = YES + + +GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE + + +// Info.plist File +// +// This is the project-relative path to the plist file that contains the Info.plist +// information used by bundles. + +INFOPLIST_FILE = Stripe/Info.plist + + +// Installation Directory +// +// The directory to install the build products in. This path is prepended by the +// 'Installation Build Products Location' (i.e., $(DSTROOT)). + +INSTALL_PATH = $(LOCAL_LIBRARY_DIR)/Frameworks + + +// Runpath Search Paths +// +// This is a list of paths to be added to the runpath search path list for the image +// being created. At runtime, dyld uses the runpath when searching for dylibs whose load +// path begins with '@rpath/'. [-rpath] + +LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/../Frameworks @loader_path/Frameworks + + +// OS X Deployment Target +// +// Code will load on this and later versions of OS X. Framework APIs that are +// unavailable in earlier versions will be weak-linked; your code should check for null +// function pointers or specific system versions before calling newer APIs. +// +// Compiler Default - Code will load on any Mac OS system that supports the APIs that are +// used. +// OS X 10.4 - Code will not load on systems earlier than 10.4. [10.4] +// OS X 10.5 - Code will not load on systems earlier than 10.5. [10.5] +// OS X 10.6 - Code will not load on systems earlier than 10.6. [10.6] +// OS X 10.7 - Code will not load on systems earlier than 10.7. [10.7] +// OS X 10.8 - Code will not load on systems earlier than 10.8. [10.8] +// OS X 10.9 - Code will not load on systems earlier than 10.9. [10.9] + +MACOSX_DEPLOYMENT_TARGET = 10.9 + + +// Product Name +// +// This is the basename of the product generated. + +PRODUCT_NAME = StripeOSX + + +// Base SDK +// +// The name or path of the base SDK being used during the build. The product will be +// built against the headers and libraries located inside the indicated SDK. This path +// will be prepended to all search paths, and will be passed through the environment to +// the compiler and linker. Additional SDKs can be specified in the ADDITIONAL_SDKS +// setting. + +SDKROOT = macosx + + +// Skip Install +// +// Activating this setting when deployment locations are used causes the product to be +// built into an alternative location instead of the install location. + +SKIP_INSTALL = YES + + +// Versioning Name Prefix +// +// Used as a prefix for the name of the version info symbol in the generated versioning +// source file. If you prefix your exported symbols you will probably want to set this +// to the same prefix. + +VERSION_INFO_PREFIX = + + +// Versioning System +// +// Selects the process used for version-stamping generated files. +// +// None - Use no versioning system. [] +// Apple Generic - Use the current project version setting. [apple-generic] + +VERSIONING_SYSTEM = apple-generic diff --git a/Frameworks/Stripe/BuildConfigurations/StripeOSXTests-Debug.xcconfig b/Frameworks/Stripe/BuildConfigurations/StripeOSXTests-Debug.xcconfig new file mode 100755 index 00000000..49c7ca3e --- /dev/null +++ b/Frameworks/Stripe/BuildConfigurations/StripeOSXTests-Debug.xcconfig @@ -0,0 +1,11 @@ +// +// StripeOSXTests-Debug.xcconfig +// +// Generated by BuildSettingExtractor on 4/27/15 +// https://github.com/dempseyatgithub/BuildSettingExtractor +// + +#include "StripeOSXTests-Shared.xcconfig" + + +GCC_PREPROCESSOR_DEFINITIONS = DEBUG=1 $(inherited) \ No newline at end of file diff --git a/Frameworks/Stripe/BuildConfigurations/StripeOSXTests-Release.xcconfig b/Frameworks/Stripe/BuildConfigurations/StripeOSXTests-Release.xcconfig new file mode 100755 index 00000000..846dc6db --- /dev/null +++ b/Frameworks/Stripe/BuildConfigurations/StripeOSXTests-Release.xcconfig @@ -0,0 +1,22 @@ +// +// StripeOSXTests-Release.xcconfig +// +// Generated by BuildSettingExtractor on 4/27/15 +// https://github.com/dempseyatgithub/BuildSettingExtractor +// + +#include "StripeOSXTests-Shared.xcconfig" + + +// Debug Information Format +// +// This setting controls the format of debug information used by the developer tools. +// +// DWARF - Object files and linked products will use DWARF as the debug information +// format. [dwarf] +// DWARF with dSYM File - Object files and linked products will use DWARF as the debug +// information format, and Xcode will also produce a dSYM file containing the debug +// information from the individual object files (except that a dSYM file is not needed +// and will not be created for static library or object file products). [dwarf-with-dsym] + +DEBUG_INFORMATION_FORMAT = dwarf-with-dsym diff --git a/Frameworks/Stripe/BuildConfigurations/StripeOSXTests-Shared.xcconfig b/Frameworks/Stripe/BuildConfigurations/StripeOSXTests-Shared.xcconfig new file mode 100755 index 00000000..f1bb664b --- /dev/null +++ b/Frameworks/Stripe/BuildConfigurations/StripeOSXTests-Shared.xcconfig @@ -0,0 +1,107 @@ +// +// StripeOSXTests-Shared.xcconfig +// +// Generated by BuildSettingExtractor on 4/27/15 +// https://github.com/dempseyatgithub/BuildSettingExtractor +// + + +CLANG_CXX_LANGUAGE_STANDARD = gnu++0x + + +CLANG_CXX_LIBRARY = libc++ + + +CLANG_ENABLE_MODULES = YES + + +CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR + + +CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR + + +// Combine High Resolution Artwork +// +// Combines image files at different resolutions into one multi-page TIFF file that is +// HiDPI compliant for Mac OS X 10.7 and later. Only image files in the same directory +// and with the same base name and extension are combined. The file names must conform to +// the naming convention used in HiDPI. + +COMBINE_HIDPI_IMAGES = YES + + +// Framework Search Paths +// +// This is a list of paths to folders containing frameworks to be searched by the +// compiler for both included or imported header files when compiling C, Objective-C, +// C++, or Objective-C++, and by the linker for frameworks used by the product. Paths are +// delimited by whitespace, so any paths with spaces in them need to be properly quoted. +// [-F] + +FRAMEWORK_SEARCH_PATHS = $(DEVELOPER_FRAMEWORKS_DIR) $(inherited) + + +GCC_TREAT_WARNINGS_AS_ERRORS = YES + + +GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR + + +GCC_WARN_SHADOW = YES + + +GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE + + +// Info.plist File +// +// This is the project-relative path to the plist file that contains the Info.plist +// information used by bundles. + +INFOPLIST_FILE = Tests/Tests/Info.plist + + +// Runpath Search Paths +// +// This is a list of paths to be added to the runpath search path list for the image +// being created. At runtime, dyld uses the runpath when searching for dylibs whose load +// path begins with '@rpath/'. [-rpath] + +LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/../Frameworks @loader_path/../Frameworks + + +// OS X Deployment Target +// +// Code will load on this and later versions of OS X. Framework APIs that are +// unavailable in earlier versions will be weak-linked; your code should check for null +// function pointers or specific system versions before calling newer APIs. +// +// Compiler Default - Code will load on any Mac OS system that supports the APIs that are +// used. +// OS X 10.4 - Code will not load on systems earlier than 10.4. [10.4] +// OS X 10.5 - Code will not load on systems earlier than 10.5. [10.5] +// OS X 10.6 - Code will not load on systems earlier than 10.6. [10.6] +// OS X 10.7 - Code will not load on systems earlier than 10.7. [10.7] +// OS X 10.8 - Code will not load on systems earlier than 10.8. [10.8] +// OS X 10.9 - Code will not load on systems earlier than 10.9. [10.9] + +MACOSX_DEPLOYMENT_TARGET = 10.10 + + +// Product Name +// +// This is the basename of the product generated. + +PRODUCT_NAME = $(TARGET_NAME) + + +// Base SDK +// +// The name or path of the base SDK being used during the build. The product will be +// built against the headers and libraries located inside the indicated SDK. This path +// will be prepended to all search paths, and will be passed through the environment to +// the compiler and linker. Additional SDKs can be specified in the ADDITIONAL_SDKS +// setting. + +SDKROOT = macosx \ No newline at end of file diff --git a/Frameworks/Stripe/BuildConfigurations/StripeiOS Tests-Debug.xcconfig b/Frameworks/Stripe/BuildConfigurations/StripeiOS Tests-Debug.xcconfig new file mode 100755 index 00000000..3dd2bfc7 --- /dev/null +++ b/Frameworks/Stripe/BuildConfigurations/StripeiOS Tests-Debug.xcconfig @@ -0,0 +1,30 @@ +// +// StripeiOS Tests-Debug.xcconfig +// +// Generated by BuildSettingExtractor on 4/27/15 +// https://github.com/dempseyatgithub/BuildSettingExtractor +// + +#include "StripeiOS Tests-Shared.xcconfig" + +GCC_PREPROCESSOR_DEFINITIONS = DEBUG=1 $(inherited) + +// iOS Deployment Target +// +// Code will load on this and later versions of iOS. Framework APIs that are unavailable +// in earlier versions will be weak-linked; your code should check for null function +// pointers or specific system versions before calling newer APIs. +// +// iOS 4.3 - Code will not load on systems earlier than 4.3. [4.3] +// iOS 5.0 - Code will not load on systems earlier than 5.0. [5.0] +// iOS 5.1 - Code will not load on systems earlier than 5.1. [5.1] +// iOS 6.0 - Code will not load on systems earlier than 6.0. [6.0] +// iOS 6.1 - Code will not load on systems earlier than 6.1. [6.1] +// iOS 7.0 - Code will not load on systems earlier than 7.0. [7.0] +// iOS 7.1 - Code will not load on systems earlier than 7.1. [7.1] +// iOS 8.0 - Code will not load on systems earlier than 8.0. [8.0] +// iOS 8.1 - Code will not load on systems earlier than 8.1. [8.1] +// iOS 8.2 - Code will not load on systems earlier than 8.2. [8.2] +// iOS 8.3 - Code will not load on systems earlier than 8.3. [8.3] + +IPHONEOS_DEPLOYMENT_TARGET = 6.0 diff --git a/Frameworks/Stripe/BuildConfigurations/StripeiOS Tests-Release.xcconfig b/Frameworks/Stripe/BuildConfigurations/StripeiOS Tests-Release.xcconfig new file mode 100755 index 00000000..660f2c06 --- /dev/null +++ b/Frameworks/Stripe/BuildConfigurations/StripeiOS Tests-Release.xcconfig @@ -0,0 +1,28 @@ +// +// StripeiOS Tests-Release.xcconfig +// +// Generated by BuildSettingExtractor on 4/27/15 +// https://github.com/dempseyatgithub/BuildSettingExtractor +// + +#include "StripeiOS Tests-Shared.xcconfig" + +// iOS Deployment Target +// +// Code will load on this and later versions of iOS. Framework APIs that are unavailable +// in earlier versions will be weak-linked; your code should check for null function +// pointers or specific system versions before calling newer APIs. +// +// iOS 4.3 - Code will not load on systems earlier than 4.3. [4.3] +// iOS 5.0 - Code will not load on systems earlier than 5.0. [5.0] +// iOS 5.1 - Code will not load on systems earlier than 5.1. [5.1] +// iOS 6.0 - Code will not load on systems earlier than 6.0. [6.0] +// iOS 6.1 - Code will not load on systems earlier than 6.1. [6.1] +// iOS 7.0 - Code will not load on systems earlier than 7.0. [7.0] +// iOS 7.1 - Code will not load on systems earlier than 7.1. [7.1] +// iOS 8.0 - Code will not load on systems earlier than 8.0. [8.0] +// iOS 8.1 - Code will not load on systems earlier than 8.1. [8.1] +// iOS 8.2 - Code will not load on systems earlier than 8.2. [8.2] +// iOS 8.3 - Code will not load on systems earlier than 8.3. [8.3] + +IPHONEOS_DEPLOYMENT_TARGET = 8.0 diff --git a/Frameworks/Stripe/BuildConfigurations/StripeiOS Tests-Shared.xcconfig b/Frameworks/Stripe/BuildConfigurations/StripeiOS Tests-Shared.xcconfig new file mode 100755 index 00000000..0217c60b --- /dev/null +++ b/Frameworks/Stripe/BuildConfigurations/StripeiOS Tests-Shared.xcconfig @@ -0,0 +1,89 @@ +// +// StripeiOS Tests-Shared.xcconfig +// +// Generated by BuildSettingExtractor on 4/27/15 +// https://github.com/dempseyatgithub/BuildSettingExtractor +// + + +CLANG_CXX_LANGUAGE_STANDARD = gnu++0x + + +CLANG_CXX_LIBRARY = libc++ + + +CLANG_ENABLE_MODULES = YES + + +CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR + + +CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR + + +// Code Signing Identity +// +// The name ("common name") of a valid code-signing certificate in a keychain within your +// keychain path. A missing or invalid certificate will cause a build error. + +CODE_SIGN_IDENTITY = iPhone Developer + + +// Framework Search Paths +// +// This is a list of paths to folders containing frameworks to be searched by the +// compiler for both included or imported header files when compiling C, Objective-C, +// C++, or Objective-C++, and by the linker for frameworks used by the product. Paths are +// delimited by whitespace, so any paths with spaces in them need to be properly quoted. +// [-F] + +FRAMEWORK_SEARCH_PATHS = $(SDKROOT)/Developer/Library/Frameworks $(inherited) + + +GCC_TREAT_WARNINGS_AS_ERRORS = YES + + +GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR + + +GCC_WARN_SHADOW = YES + + +GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE + + +// Header Search Paths +// +// This is a list of paths to folders to be searched by the compiler for included or +// imported header files when compiling C, Objective-C, C++, or Objective-C++. Paths are +// delimited by whitespace, so any paths with spaces in them need to be properly quoted. +// [-I] + +HEADER_SEARCH_PATHS = $(inherited) + + +// Info.plist File +// +// This is the project-relative path to the plist file that contains the Info.plist +// information used by bundles. + +INFOPLIST_FILE = Tests/Tests/Info.plist + + +// Runpath Search Paths +// +// This is a list of paths to be added to the runpath search path list for the image +// being created. At runtime, dyld uses the runpath when searching for dylibs whose load +// path begins with '@rpath/'. [-rpath] + +LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @loader_path/Frameworks + + +OTHER_CFLAGS = + + +// Product Name +// +// This is the basename of the product generated. + +PRODUCT_NAME = $(TARGET_NAME) diff --git a/Frameworks/Stripe/BuildConfigurations/StripeiOS-Debug.xcconfig b/Frameworks/Stripe/BuildConfigurations/StripeiOS-Debug.xcconfig new file mode 100755 index 00000000..0aa0741a --- /dev/null +++ b/Frameworks/Stripe/BuildConfigurations/StripeiOS-Debug.xcconfig @@ -0,0 +1,11 @@ +// +// StripeiOS-Debug.xcconfig +// +// Generated by BuildSettingExtractor on 4/27/15 +// https://github.com/dempseyatgithub/BuildSettingExtractor +// + +#include "StripeiOS-Shared.xcconfig" + + +GCC_PREPROCESSOR_DEFINITIONS = DEBUG=1 $(inherited) diff --git a/Frameworks/Stripe/BuildConfigurations/StripeiOS-Release.xcconfig b/Frameworks/Stripe/BuildConfigurations/StripeiOS-Release.xcconfig new file mode 100755 index 00000000..ae96632a --- /dev/null +++ b/Frameworks/Stripe/BuildConfigurations/StripeiOS-Release.xcconfig @@ -0,0 +1,12 @@ +// +// StripeiOS-Release.xcconfig +// +// Generated by BuildSettingExtractor on 4/27/15 +// https://github.com/dempseyatgithub/BuildSettingExtractor +// + +#include "StripeiOS-Shared.xcconfig" + +//********************************************// +//* Currently no build settings in this file *// +//********************************************// diff --git a/Frameworks/Stripe/BuildConfigurations/StripeiOS-Shared.xcconfig b/Frameworks/Stripe/BuildConfigurations/StripeiOS-Shared.xcconfig new file mode 100755 index 00000000..457bf896 --- /dev/null +++ b/Frameworks/Stripe/BuildConfigurations/StripeiOS-Shared.xcconfig @@ -0,0 +1,178 @@ +// +// StripeiOS-Shared.xcconfig +// +// Generated by BuildSettingExtractor on 4/27/15 +// https://github.com/dempseyatgithub/BuildSettingExtractor +// + + +CLANG_CXX_LANGUAGE_STANDARD = gnu++0x + + +CLANG_CXX_LIBRARY = libc++ + + +CLANG_ENABLE_MODULES = YES + + +CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR + + +CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR + + +// Code Signing Identity +// +// The name ("common name") of a valid code-signing certificate in a keychain within your +// keychain path. A missing or invalid certificate will cause a build error. + +CODE_SIGN_IDENTITY[sdk=iphoneos*] = iPhone Developer + + +// Current Project Version +// +// This setting defines the the current version of the project. The value must be a +// integer or floating point number like 57 or 365.8. + +CURRENT_PROJECT_VERSION = 1 + + +// Defines Module +// +// If enabled, the product will be treated as defining its own module. This enables +// automatic production of LLVM module map files when appropriate, and allows the product +// to be imported as a module. + +DEFINES_MODULE = YES + + +// Compatibility Version +// +// Determines the compatibility version of the resulting library, bundle, or framework +// binary. + +DYLIB_COMPATIBILITY_VERSION = 1 + + +// Current Library Version +// +// This setting defines the the current version of any framework built by the project. +// Like "Current Project Version", the value must be an integer or floating point number +// like 57 or 365.8. By default it is set to $(CURRENT_PROJECT_VERSION). + +DYLIB_CURRENT_VERSION = 1 + + +// Dynamic Library Install Name Base +// +// Sets the base value for the internal "install path" (LC_ID_DYLIB) in a dynamic +// library. This will be combined with the EXECUTABLE_PATH to form the full install path. +// Setting LD_DYLIB_INSTALL_NAME directly will override this setting. This setting +// defaults to the target's INSTALL_PATH. It is ignored when building any product other +// than a dynamic library. [-install_name] + +DYLIB_INSTALL_NAME_BASE = @rpath + + +GCC_TREAT_WARNINGS_AS_ERRORS = YES + + +GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR + + +GCC_WARN_SHADOW = YES + + +GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE + + +// Info.plist File +// +// This is the project-relative path to the plist file that contains the Info.plist +// information used by bundles. + +INFOPLIST_FILE = Stripe/Info.plist + + +// Installation Directory +// +// The directory to install the build products in. This path is prepended by the +// 'Installation Build Products Location' (i.e., $(DSTROOT)). + +INSTALL_PATH = $(LOCAL_LIBRARY_DIR)/Frameworks + + +// iOS Deployment Target +// +// Code will load on this and later versions of iOS. Framework APIs that are unavailable +// in earlier versions will be weak-linked; your code should check for null function +// pointers or specific system versions before calling newer APIs. +// +// iOS 4.3 - Code will not load on systems earlier than 4.3. [4.3] +// iOS 5.0 - Code will not load on systems earlier than 5.0. [5.0] +// iOS 5.1 - Code will not load on systems earlier than 5.1. [5.1] +// iOS 6.0 - Code will not load on systems earlier than 6.0. [6.0] +// iOS 6.1 - Code will not load on systems earlier than 6.1. [6.1] +// iOS 7.0 - Code will not load on systems earlier than 7.0. [7.0] +// iOS 7.1 - Code will not load on systems earlier than 7.1. [7.1] +// iOS 8.0 - Code will not load on systems earlier than 8.0. [8.0] +// iOS 8.1 - Code will not load on systems earlier than 8.1. [8.1] +// iOS 8.2 - Code will not load on systems earlier than 8.2. [8.2] +// iOS 8.3 - Code will not load on systems earlier than 8.3. [8.3] + +IPHONEOS_DEPLOYMENT_TARGET = 6.0 + + +// Runpath Search Paths +// +// This is a list of paths to be added to the runpath search path list for the image +// being created. At runtime, dyld uses the runpath when searching for dylibs whose load +// path begins with '@rpath/'. [-rpath] + +LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @loader_path/Frameworks + + +// Product Name +// +// This is the basename of the product generated. + +PRODUCT_NAME = Stripe + + +// Skip Install +// +// Activating this setting when deployment locations are used causes the product to be +// built into an alternative location instead of the install location. + +SKIP_INSTALL = YES + + +// Targeted Device Family +// +// The build system uses the selected device to set the correct value for the +// UIDeviceFamily key it adds to the target's Info.plist file. +// +// iPhone - Application is built for iPhone and iPod touch. +// iPad - Application is built for iPad. +// iPhone/iPad - Application is built Universal for iPhone, iPod touch, and iPad. + +TARGETED_DEVICE_FAMILY = 1,2 + + +// Versioning Name Prefix +// +// Used as a prefix for the name of the version info symbol in the generated versioning +// source file. If you prefix your exported symbols you will probably want to set this +// to the same prefix. + +VERSION_INFO_PREFIX = + + +// Versioning System +// +// Selects the process used for version-stamping generated files. +// +// None - Use no versioning system. [] +// Apple Generic - Use the current project version setting. [apple-generic] + +VERSIONING_SYSTEM = apple-generic diff --git a/Frameworks/Stripe/BuildConfigurations/StripeiOSStatic.xcconfig b/Frameworks/Stripe/BuildConfigurations/StripeiOSStatic.xcconfig new file mode 100755 index 00000000..3d4dcb0f --- /dev/null +++ b/Frameworks/Stripe/BuildConfigurations/StripeiOSStatic.xcconfig @@ -0,0 +1,109 @@ +// +// StripeiOSStatic-Shared.xcconfig +// +// Generated by BuildSettingExtractor on 4/27/15 +// https://github.com/dempseyatgithub/BuildSettingExtractor +// + +// Strip Debug Symbols During Copy +// +// Activating this setting causes binary files which are copied during the build (e.g., +// in a Copy Bundle Resources or Copy Files build phase) to be stripped of debugging +// symbols. It does not cause the linked product of a target to be stripped (use Strip +// Linked Product for that). + +COPY_PHASE_STRIP = NO + +CLANG_CXX_LANGUAGE_STANDARD = gnu++0x + + +CLANG_CXX_LIBRARY = libc++ + + +CLANG_ENABLE_MODULES = YES + + +CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR + + +CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR + + +// Dead Code Stripping +// +// Activating this setting causes the -dead_strip flag to be passed to ld(1) via cc(1) to +// turn on dead code stripping. If this option is selected, -gfull (not -gused) must be +// used to generate debugging symbols in order to have them correctly stripped. +// [-dead_strip] + +DEAD_CODE_STRIPPING = NO + + +GCC_TREAT_WARNINGS_AS_ERRORS = YES + + +GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR + + +GCC_WARN_SHADOW = YES + + +GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE + + +// iOS Deployment Target +// +// Code will load on this and later versions of iOS. Framework APIs that are unavailable +// in earlier versions will be weak-linked; your code should check for null function +// pointers or specific system versions before calling newer APIs. +// +// iOS 4.3 - Code will not load on systems earlier than 4.3. [4.3] +// iOS 5.0 - Code will not load on systems earlier than 5.0. [5.0] +// iOS 5.1 - Code will not load on systems earlier than 5.1. [5.1] +// iOS 6.0 - Code will not load on systems earlier than 6.0. [6.0] +// iOS 6.1 - Code will not load on systems earlier than 6.1. [6.1] +// iOS 7.0 - Code will not load on systems earlier than 7.0. [7.0] +// iOS 7.1 - Code will not load on systems earlier than 7.1. [7.1] +// iOS 8.0 - Code will not load on systems earlier than 8.0. [8.0] +// iOS 8.1 - Code will not load on systems earlier than 8.1. [8.1] +// iOS 8.2 - Code will not load on systems earlier than 8.2. [8.2] +// iOS 8.3 - Code will not load on systems earlier than 8.3. [8.3] + +IPHONEOS_DEPLOYMENT_TARGET = 8.1 + + +// Other Linker Flags +// +// Options defined in this setting are passed to invocations of the linker. + +OTHER_LDFLAGS = -ObjC + + +// Product Name +// +// This is the basename of the product generated. + +PRODUCT_NAME = Stripe + + +// Skip Install +// +// Activating this setting when deployment locations are used causes the product to be +// built into an alternative location instead of the install location. + +SKIP_INSTALL = YES + + +// Strip Style +// +// Defines the level of symbol stripping to be performed on the linked product of the +// build. The default value is defined by the target's product type. +// +// All Symbols - Completely strips the binary, removing the symbol table and relocation +// information. [all, -s] +// Non-Global Symbols - Strips non-global symbols, but saves external symbols. +// [non-global, -x] +// Debugging Symbols - Strips debugging symbols, but saves local and global symbols. +// [debugging, -S] + +STRIP_STYLE = non-global diff --git a/Frameworks/Stripe/BuildConfigurations/StripeiOSStaticFramework.xcconfig b/Frameworks/Stripe/BuildConfigurations/StripeiOSStaticFramework.xcconfig new file mode 100755 index 00000000..19b77c02 --- /dev/null +++ b/Frameworks/Stripe/BuildConfigurations/StripeiOSStaticFramework.xcconfig @@ -0,0 +1,19 @@ +// +// StripeiOSStaticFramework-Shared.xcconfig +// +// Generated by BuildSettingExtractor on 4/27/15 +// https://github.com/dempseyatgithub/BuildSettingExtractor +// + + +GCC_TREAT_WARNINGS_AS_ERRORS = YES + + +GCC_WARN_SHADOW = YES + + +// Product Name +// +// This is the basename of the product generated. + +PRODUCT_NAME = $(TARGET_NAME) diff --git a/Frameworks/Stripe/BuildConfigurations/StripeiOSStaticFrameworkWithoutApplePay.xcconfig b/Frameworks/Stripe/BuildConfigurations/StripeiOSStaticFrameworkWithoutApplePay.xcconfig new file mode 100755 index 00000000..12ffde28 --- /dev/null +++ b/Frameworks/Stripe/BuildConfigurations/StripeiOSStaticFrameworkWithoutApplePay.xcconfig @@ -0,0 +1,19 @@ +// +// StripeiOSStaticFrameworkWithoutApplePay-Shared.xcconfig +// +// Generated by BuildSettingExtractor on 4/27/15 +// https://github.com/dempseyatgithub/BuildSettingExtractor +// + + +GCC_TREAT_WARNINGS_AS_ERRORS = YES + + +GCC_WARN_SHADOW = YES + + +// Product Name +// +// This is the basename of the product generated. + +PRODUCT_NAME = $(TARGET_NAME) \ No newline at end of file diff --git a/Frameworks/Stripe/BuildConfigurations/StripeiOSStaticWithoutApplePay.xcconfig b/Frameworks/Stripe/BuildConfigurations/StripeiOSStaticWithoutApplePay.xcconfig new file mode 100755 index 00000000..4c135f1f --- /dev/null +++ b/Frameworks/Stripe/BuildConfigurations/StripeiOSStaticWithoutApplePay.xcconfig @@ -0,0 +1,85 @@ +// +// StripeiOSStaticWithoutApplePay-Shared.xcconfig +// +// Generated by BuildSettingExtractor on 4/27/15 +// https://github.com/dempseyatgithub/BuildSettingExtractor +// + +// Strip Debug Symbols During Copy +// +// Activating this setting causes binary files which are copied during the build (e.g., +// in a Copy Bundle Resources or Copy Files build phase) to be stripped of debugging +// symbols. It does not cause the linked product of a target to be stripped (use Strip +// Linked Product for that). + +COPY_PHASE_STRIP = NO + + +CLANG_CXX_LANGUAGE_STANDARD = gnu++0x + + +CLANG_CXX_LIBRARY = libc++ + + +CLANG_ENABLE_MODULES = YES + + +CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR + + +CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR + + +GCC_TREAT_WARNINGS_AS_ERRORS = YES + + +GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR + + +GCC_WARN_SHADOW = YES + + +GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE + + +// iOS Deployment Target +// +// Code will load on this and later versions of iOS. Framework APIs that are unavailable +// in earlier versions will be weak-linked; your code should check for null function +// pointers or specific system versions before calling newer APIs. +// +// iOS 4.3 - Code will not load on systems earlier than 4.3. [4.3] +// iOS 5.0 - Code will not load on systems earlier than 5.0. [5.0] +// iOS 5.1 - Code will not load on systems earlier than 5.1. [5.1] +// iOS 6.0 - Code will not load on systems earlier than 6.0. [6.0] +// iOS 6.1 - Code will not load on systems earlier than 6.1. [6.1] +// iOS 7.0 - Code will not load on systems earlier than 7.0. [7.0] +// iOS 7.1 - Code will not load on systems earlier than 7.1. [7.1] +// iOS 8.0 - Code will not load on systems earlier than 8.0. [8.0] +// iOS 8.1 - Code will not load on systems earlier than 8.1. [8.1] +// iOS 8.2 - Code will not load on systems earlier than 8.2. [8.2] +// iOS 8.3 - Code will not load on systems earlier than 8.3. [8.3] + +IPHONEOS_DEPLOYMENT_TARGET = 8.1 + + +// Other Linker Flags +// +// Options defined in this setting are passed to invocations of the linker. + +OTHER_LDFLAGS = -ObjC + + +// Product Name +// +// This is the basename of the product generated. + +PRODUCT_NAME = Stripe + + +// Skip Install +// +// Activating this setting when deployment locations are used causes the product to be +// built into an alternative location instead of the install location. + +SKIP_INSTALL = YES \ No newline at end of file diff --git a/Frameworks/Stripe/Checkout/STPCheckoutDelegate.h b/Frameworks/Stripe/Checkout/STPCheckoutDelegate.h new file mode 100755 index 00000000..dc2d5291 --- /dev/null +++ b/Frameworks/Stripe/Checkout/STPCheckoutDelegate.h @@ -0,0 +1,20 @@ +// +// STPCheckoutDelegate.h +// Stripe +// +// Created by Jack Flintermann on 1/7/15. +// Copyright (c) 2015 Stripe, Inc. All rights reserved. +// + +#import +#import "STPNullabilityMacros.h" + +@protocol STPCheckoutWebViewAdapter; +@protocol STPCheckoutDelegate +- (void)checkoutAdapterDidStartLoad:(stp_nonnull id)adapter; +- (void)checkoutAdapterDidFinishLoad:(stp_nonnull id)adapter; +- (void)checkoutAdapter:(stp_nonnull id)adapter + didTriggerEvent:(stp_nonnull NSString *)event + withPayload:(stp_nonnull NSDictionary *)payload; +- (void)checkoutAdapter:(stp_nonnull id)adapter didError:(stp_nonnull NSError *)error; +@end diff --git a/Frameworks/Stripe/Checkout/STPCheckoutInternalUIWebViewController.h b/Frameworks/Stripe/Checkout/STPCheckoutInternalUIWebViewController.h new file mode 100755 index 00000000..6f3c4de3 --- /dev/null +++ b/Frameworks/Stripe/Checkout/STPCheckoutInternalUIWebViewController.h @@ -0,0 +1,29 @@ +// +// STPCheckoutInternalUIWebViewController.h +// Stripe +// +// Created by Jack Flintermann on 1/7/15. +// Copyright (c) 2015 Stripe, Inc. All rights reserved. +// + +#if TARGET_OS_IPHONE + +#import +#import + +#import "STPCheckoutDelegate.h" +#import "STPCheckoutViewController.h" +#import "STPNullabilityMacros.h" + +@interface STPCheckoutInternalUIWebViewController : UIViewController + +- (stp_nonnull instancetype)initWithCheckoutViewController:(stp_nonnull STPCheckoutViewController *)checkoutViewController; + +@property (weak, nonatomic, readonly, stp_nullable) STPCheckoutViewController *checkoutController; +@property (weak, nonatomic, readonly, stp_nullable) UIView *webView; +@property (nonatomic, stp_nonnull) STPCheckoutOptions *options; +@property (nonatomic, weak, stp_nullable) id delegate; + +@end + +#endif diff --git a/Frameworks/Stripe/Checkout/STPCheckoutInternalUIWebViewController.m b/Frameworks/Stripe/Checkout/STPCheckoutInternalUIWebViewController.m new file mode 100755 index 00000000..78c8cd29 --- /dev/null +++ b/Frameworks/Stripe/Checkout/STPCheckoutInternalUIWebViewController.m @@ -0,0 +1,235 @@ +// +// STPCheckoutInternalUIWebViewController.m +// Stripe +// +// Created by Jack Flintermann on 1/7/15. +// Copyright (c) 2015 Stripe, Inc. All rights reserved. +// + +#import + +#if TARGET_OS_IPHONE + +#import "STPAPIClient.h" +#import "STPCheckoutOptions.h" +#import "STPCheckoutWebViewAdapter.h" +#import "STPIOSCheckoutWebViewAdapter.h" +#import "STPCheckoutInternalUIWebViewController.h" +#import "STPCheckoutViewController.h" +#import "StripeError.h" +#import "STPToken.h" +#import "STPColorUtils.h" + +#define FAUXPAS_IGNORED_IN_METHOD(...) + +@interface STPCheckoutInternalUIWebViewController () +@property (nonatomic) BOOL statusBarHidden; +@property (weak, nonatomic, stp_nullable) UIView *webView; +@property (nonatomic, stp_nullable) STPIOSCheckoutWebViewAdapter *adapter; +@property (nonatomic, stp_nonnull) NSURL *url; +@property (weak, nonatomic, stp_nullable) UIActivityIndicatorView *activityIndicator; +@property (nonatomic) BOOL backendChargeSuccessful; +@property (nonatomic, stp_nullable) NSError *backendChargeError; +@end + +@implementation STPCheckoutInternalUIWebViewController + +- (instancetype)initWithCheckoutViewController:(STPCheckoutViewController *)checkoutViewController { + self = [super initWithNibName:nil bundle:nil]; + if (self) { + if ([self respondsToSelector:@selector(setEdgesForExtendedLayout:)]) { + self.edgesForExtendedLayout = UIRectEdgeNone; + } + _options = checkoutViewController.options; + _url = [NSURL URLWithString:checkoutURLString]; + UIBarButtonItem *cancelItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancel:)]; + self.navigationItem.leftBarButtonItem = cancelItem; + _checkoutController = checkoutViewController; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSString *userAgent = [[[UIWebView alloc] init] stringByEvaluatingJavaScriptFromString:@"window.navigator.userAgent"]; + if ([userAgent rangeOfString:checkoutUserAgent].location == NSNotFound) { + userAgent = [NSString stringWithFormat:@"%@ %@/%@", userAgent, checkoutUserAgent, STPSDKVersion]; + NSDictionary *defaults = @{ @"UserAgent": userAgent }; + [[NSUserDefaults standardUserDefaults] registerDefaults:defaults]; + } + }); + } + return self; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + self.adapter = [[STPIOSCheckoutWebViewAdapter alloc] init]; + self.adapter.delegate = self; + UIWebView *webView = self.adapter.webView; + webView.scrollView.delegate = self; + [self.view addSubview:webView]; + + if (self.options.logoColor && [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) { + self.view.backgroundColor = self.options.logoColor; + webView.backgroundColor = self.options.logoColor; + webView.opaque = NO; + } + + webView.translatesAutoresizingMaskIntoConstraints = NO; + [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[webView]-0-|" + options:NSLayoutFormatDirectionLeadingToTrailing + metrics:nil + views:NSDictionaryOfVariableBindings(webView)]]; + [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[webView]-0-|" + options:NSLayoutFormatDirectionLeadingToTrailing + metrics:nil + views:NSDictionaryOfVariableBindings(webView)]]; + + [self.adapter loadRequest:[NSURLRequest requestWithURL:self.url]]; + self.webView = webView; + + UIActivityIndicatorViewStyle style = UIActivityIndicatorViewStyleGray; + if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad && self.options.logoColor && + ![STPColorUtils colorIsLight:self.options.logoColor]) { + style = UIActivityIndicatorViewStyleWhiteLarge; + } + UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:style]; + activityIndicator.hidesWhenStopped = YES; + activityIndicator.translatesAutoresizingMaskIntoConstraints = NO; + [self.view addSubview:activityIndicator]; + self.activityIndicator = activityIndicator; + [self.view addConstraint:[NSLayoutConstraint constraintWithItem:activityIndicator + attribute:NSLayoutAttributeCenterX + relatedBy:NSLayoutRelationEqual + toItem:self.view + attribute:NSLayoutAttributeCenterX + multiplier:1 + constant:0.0]]; + [self.view addConstraint:[NSLayoutConstraint constraintWithItem:activityIndicator + attribute:NSLayoutAttributeCenterY + relatedBy:NSLayoutRelationEqual + toItem:self.view + attribute:NSLayoutAttributeCenterY + multiplier:1 + constant:0]]; +} + +- (void)cancel:(__unused id)sender { + [self.delegate checkoutController:self.checkoutController didFinishWithStatus:STPPaymentStatusUserCancelled error:nil]; + [self cleanup]; +} + +- (void)cleanup { + [self.adapter cleanup]; +} + +- (UIStatusBarStyle)preferredStatusBarStyle { + if (self.options.logoColor && self.checkoutController.navigationBarHidden) { + FAUXPAS_IGNORED_IN_METHOD(APIAvailability); + return [STPColorUtils colorIsLight:self.options.logoColor] ? UIStatusBarStyleDefault : UIStatusBarStyleLightContent; + } + return UIStatusBarStyleDefault; +} + +- (void)setLogoColor:(STP_COLOR_CLASS *)color { + self.options.logoColor = color; + if ([self.checkoutController respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)]) { + FAUXPAS_IGNORED_IN_METHOD(APIAvailability); + [[UIApplication sharedApplication] setStatusBarStyle:[self preferredStatusBarStyle] animated:YES]; + [self.checkoutController setNeedsStatusBarAppearanceUpdate]; + } +} + +#pragma mark STPCheckoutAdapterDelegate + +- (void)checkoutAdapterDidStartLoad:(id)adapter { + NSString *optionsJavaScript = [NSString stringWithFormat:@"window.%@ = %@;", checkoutOptionsGlobal, [self.options stringifiedJSONRepresentation]]; + [adapter evaluateJavaScript:optionsJavaScript]; + [self.activityIndicator startAnimating]; +} + +- (void)checkoutAdapter:(id)adapter didTriggerEvent:(NSString *)event withPayload:(NSDictionary *)payload { + if ([event isEqualToString:STPCheckoutEventOpen]) { + if (payload != nil && payload[@"logoColor"]) { + [self setLogoColor:[STPColorUtils colorForHexCode:payload[@"logoColor"]]]; + } + } else if ([event isEqualToString:STPCheckoutEventTokenize]) { + STPToken *token = nil; + if (payload != nil && payload[@"token"] != nil) { + token = [[STPToken alloc] initWithAttributeDictionary:payload[@"token"]]; + } + [self.delegate checkoutController:self.checkoutController + didCreateToken:token + completion:^(STPBackendChargeResult status, NSError *error) { + self.backendChargeSuccessful = (status == STPBackendChargeResultSuccess); + self.backendChargeError = error; + if (status == STPBackendChargeResultSuccess) { + [adapter evaluateJavaScript:payload[@"success"]]; + } else { + NSString *failure = payload[@"failure"]; + NSString *encodedError = @""; + if (error.localizedDescription) { + encodedError = [[NSString alloc] + initWithData:[NSJSONSerialization dataWithJSONObject:@[error.localizedDescription] options:0 error:nil] + encoding:NSUTF8StringEncoding]; + encodedError = [encodedError substringWithRange:NSMakeRange(2, encodedError.length - 4)]; + } + NSString *script = [NSString stringWithFormat:failure, encodedError]; + [adapter evaluateJavaScript:script]; + } + }]; + } else if ([event isEqualToString:STPCheckoutEventFinish]) { + if (self.backendChargeSuccessful) { + [self.delegate checkoutController:self.checkoutController didFinishWithStatus:STPPaymentStatusSuccess error:nil]; + } else { + [self.delegate checkoutController:self.checkoutController didFinishWithStatus:STPPaymentStatusError error:self.backendChargeError]; + } + [self cleanup]; + } else if ([event isEqualToString:STPCheckoutEventCancel]) { + [self.delegate checkoutController:self.checkoutController didFinishWithStatus:STPPaymentStatusUserCancelled error:nil]; + [self cleanup]; + } else if ([event isEqualToString:STPCheckoutEventError]) { + NSError *error = [[NSError alloc] initWithDomain:StripeDomain code:STPCheckoutError userInfo:payload]; + [self.delegate checkoutController:self.checkoutController didFinishWithStatus:STPPaymentStatusError error:error]; + [self cleanup]; + } +} + +- (void)checkoutAdapterDidFinishLoad:(__unused id)adapter { + [UIView animateWithDuration:0.1 + animations:^{ + self.activityIndicator.alpha = 0; + [self.navigationController setNavigationBarHidden:YES animated:YES]; + } + completion:^(__unused BOOL finished) { [self.activityIndicator stopAnimating]; }]; +} + +- (void)checkoutAdapter:(__unused id)adapter didError:(NSError *)error { + [self.activityIndicator stopAnimating]; + [self.delegate checkoutController:self.checkoutController didFinishWithStatus:STPPaymentStatusError error:error]; + [self cleanup]; +} + +- (void)scrollViewDidScroll:(UIScrollView *)scrollView { + NSDictionary *options = [self checkoutDisplayOptionsForScrollViewOffset:scrollView.contentOffset]; + BOOL statusBarHidden = [options[@"statusBarHidden"] boolValue]; + NSString *backgroundColorHex = options[@"backgroundColor"]; + UIColor *color = backgroundColorHex ? [STPColorUtils colorForHexCode:backgroundColorHex] : [UIColor whiteColor]; + if ([self respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)]) { + self.statusBarHidden = statusBarHidden; + [UIView animateWithDuration:0.1 animations:^{ [self setNeedsStatusBarAppearanceUpdate]; }]; + [[UIApplication sharedApplication] setStatusBarHidden:[self prefersStatusBarHidden] withAnimation:UIStatusBarAnimationSlide]; + } + self.webView.backgroundColor = color; +} + +- (BOOL)prefersStatusBarHidden { + return self.statusBarHidden; +} + +- (NSDictionary *)checkoutDisplayOptionsForScrollViewOffset:(CGPoint)offset { + NSString *javascript = [NSString stringWithFormat:@"try { window.StripeCheckoutDidScroll(%@, %@) } catch(e){ null };", @(offset.x), @(offset.y)]; + NSString *output = [self.adapter evaluateJavaScript:javascript]; + return [NSJSONSerialization JSONObjectWithData:[output dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil] ?: @{}; +} + +@end + +#endif diff --git a/Frameworks/Stripe/Checkout/STPCheckoutOptions.m b/Frameworks/Stripe/Checkout/STPCheckoutOptions.m new file mode 100755 index 00000000..b14ce22f --- /dev/null +++ b/Frameworks/Stripe/Checkout/STPCheckoutOptions.m @@ -0,0 +1,111 @@ +// +// STPCheckoutOptions.m +// StripeExample +// +// Created by Jack Flintermann on 10/6/14. +// + +#import "Stripe.h" +#import "STPCheckoutOptions.h" +#import "STPColorUtils.h" + +@implementation STPCheckoutOptions + +- (instancetype)initWithPublishableKey:(NSString *)publishableKey { + self = [super init]; + if (self) { + _publishableKey = publishableKey; + _companyName = [[NSBundle mainBundle] infoDictionary][@"CFBundleDisplayName"]; + _purchaseCurrency = @"USD"; + } + return self; +} + +- (instancetype)init { + return [self initWithPublishableKey:[Stripe defaultPublishableKey]]; +} + +- (NSString *)stringifiedJSONRepresentation { + NSMutableDictionary *values = [NSMutableDictionary dictionary]; + if (self.publishableKey) { + values[@"publishableKey"] = self.publishableKey; + } + if (self.logoURL) { + values[@"logoURL"] = [self.logoURL absoluteString]; + } + if (self.logoColor) { + values[@"logoColor"] = [STPColorUtils hexCodeForColor:self.logoColor]; + } + if (self.companyName) { + values[@"companyName"] = self.companyName; + } + if (self.purchaseDescription) { + values[@"purchaseDescription"] = self.purchaseDescription; + } + if (self.purchaseAmount != 0) { + values[@"purchaseAmount"] = @(self.purchaseAmount); + } + if (self.customerEmail) { + values[@"customerEmail"] = self.customerEmail; + } + if (self.purchaseLabel) { + values[@"purchaseLabel"] = self.purchaseLabel; + } + if (self.purchaseCurrency) { + values[@"purchaseCurrency"] = [self.purchaseCurrency uppercaseString]; + } + if (self.enableRememberMe) { + values[@"enableRememberMe"] = self.enableRememberMe; + } + if (self.enablePostalCode) { + values[@"enablePostalCode"] = self.enablePostalCode; + } + if (self.requireBillingAddress) { + values[@"requireBillingAddress"] = self.requireBillingAddress; + } + + return [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:values options:0 error:nil] encoding:NSUTF8StringEncoding]; +} + +- (void)setLogoImage:(STP_IMAGE_CLASS * __stp_nullable)logoImage { + _logoImage = logoImage; + NSString *base64; +#if TARGET_OS_IPHONE + NSData *pngRepresentation = UIImagePNGRepresentation(logoImage); + if ([pngRepresentation respondsToSelector:@selector(base64EncodedStringWithOptions:)]) { + base64 = [pngRepresentation base64EncodedStringWithOptions:0]; + } +#else + NSData *imageData = [logoImage TIFFRepresentation]; + NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData:imageData]; + imageData = [imageRep representationUsingType:NSPNGFileType + properties:@{NSImageCompressionFactor: @1.0}]; + base64 = [imageData base64EncodedStringWithOptions:0]; +#endif + if (base64) { + NSString *dataURLString = [NSString stringWithFormat:@"data:png;base64,%@", base64]; + self.logoURL = [NSURL URLWithString:dataURLString]; + } +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(__unused NSZone *)zone { + STPCheckoutOptions *options = [[[self class] alloc] init]; + options.publishableKey = self.publishableKey; + options.logoURL = self.logoURL; + options.logoImage = self.logoImage; + options.logoColor = self.logoColor; + options.companyName = self.companyName; + options.purchaseDescription = self.purchaseDescription; + options.purchaseAmount = self.purchaseAmount; + options.customerEmail = self.customerEmail; + options.purchaseLabel = self.purchaseLabel; + options.purchaseCurrency = self.purchaseCurrency; + options.enableRememberMe = self.enableRememberMe; + options.enablePostalCode = self.enablePostalCode; + options.requireBillingAddress = self.requireBillingAddress; + return options; +} + +@end diff --git a/Frameworks/Stripe/Checkout/STPCheckoutViewController.m b/Frameworks/Stripe/Checkout/STPCheckoutViewController.m new file mode 100755 index 00000000..eaa30ce3 --- /dev/null +++ b/Frameworks/Stripe/Checkout/STPCheckoutViewController.m @@ -0,0 +1,186 @@ +// +// STPCheckoutViewController.m +// StripeExample +// +// Created by Jack Flintermann on 9/15/14. +// + +#import "STPCheckoutViewController.h" +#import "STPCheckoutOptions.h" +#import "STPToken.h" +#import "Stripe.h" +#import "STPColorUtils.h" +#import "STPStrictURLProtocol.h" +#import "STPCheckoutWebViewAdapter.h" +#import "STPCheckoutDelegate.h" + +#define FAUXPAS_IGNORED_IN_METHOD(...) + +#if TARGET_OS_IPHONE +#pragma mark - iOS + +#import "STPIOSCheckoutWebViewAdapter.h" +#import "STPCheckoutInternalUIWebViewController.h" + +@interface STPCheckoutViewController () +@property (nonatomic, weak) STPCheckoutInternalUIWebViewController *webViewController; +@property (nonatomic) UIStatusBarStyle previousStyle; +@end + +@implementation STPCheckoutViewController + +- (instancetype)initWithOptions:(STPCheckoutOptions *)options { + STPCheckoutInternalUIWebViewController *webViewController = [[STPCheckoutInternalUIWebViewController alloc] initWithCheckoutViewController:self]; + webViewController.options = options; + self = [super initWithRootViewController:webViewController]; + if (self) { + self.navigationBar.translucent = NO; + _webViewController = webViewController; + _previousStyle = [[UIApplication sharedApplication] statusBarStyle]; + if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) { + self.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; + } + } + return self; +} + +- (void)viewWillAppear:(BOOL)animated { + NSCAssert(self.checkoutDelegate, @"You must provide a delegate to STPCheckoutViewController before showing it."); + [super viewWillAppear:animated]; +} + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + [[UIApplication sharedApplication] setStatusBarStyle:self.previousStyle animated:YES]; +} + +- (UIViewController *)childViewControllerForStatusBarStyle { + return self.webViewController; +} + +- (void)setCheckoutDelegate:(id)delegate { + self.webViewController.delegate = delegate; +} + +- (id)checkoutDelegate { + return self.webViewController.delegate; +} + +- (STPCheckoutOptions *)options { + return self.webViewController.options; +} + +@end + +#else // OSX +#pragma mark - OSX + +#import "STPOSXCheckoutWebViewAdapter.h" + +@interface STPCheckoutViewController () +@property (nonatomic) STPOSXCheckoutWebViewAdapter *adapter; +@property (nonatomic) BOOL backendChargeSuccessful; +@property (nonatomic) NSError *backendChargeError; +@end + +@implementation STPCheckoutViewController + +- (instancetype)initWithNibName:(__unused NSString *)nibNameOrNil bundle:(__unused NSBundle *)nibBundleOrNil { + return [self initWithOptions:[[STPCheckoutOptions alloc] init]]; +} + +- (instancetype)initWithCoder:(__unused NSCoder *)coder { + return [self initWithOptions:[[STPCheckoutOptions alloc] init]]; +} + +- (instancetype)initWithOptions:(STPCheckoutOptions *)options { + self = [super initWithNibName:nil bundle:nil]; + if (self) { + _options = options; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ [NSURLProtocol registerClass:[STPStrictURLProtocol class]]; }); + } + return self; +} + +- (void)loadView { + NSView *view = [[NSView alloc] initWithFrame:CGRectZero]; + self.view = view; + if (!self.adapter) { + self.adapter = [STPOSXCheckoutWebViewAdapter new]; + self.adapter.delegate = self; + NSURL *url = [NSURL URLWithString:checkoutURLString]; + [self.adapter loadRequest:[NSURLRequest requestWithURL:url]]; + } + NSView *webView = self.adapter.webView; + [self.view addSubview:webView]; + webView.translatesAutoresizingMaskIntoConstraints = NO; + [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[webView]-0-|" + options:NSLayoutFormatDirectionLeadingToTrailing + metrics:nil + views:NSDictionaryOfVariableBindings(webView)]]; + [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[webView]-0-|" + options:NSLayoutFormatDirectionLeadingToTrailing + metrics:nil + views:NSDictionaryOfVariableBindings(webView)]]; +} + +#pragma mark STPCheckoutDelegate + +- (void)checkoutAdapterDidStartLoad:(id)adapter { + NSString *optionsJavaScript = [NSString stringWithFormat:@"window.%@ = %@;", checkoutOptionsGlobal, [self.options stringifiedJSONRepresentation]]; + [adapter evaluateJavaScript:optionsJavaScript]; +} + +- (void)checkoutAdapter:(id)adapter didTriggerEvent:(NSString *)event withPayload:(NSDictionary *)payload { + if ([event isEqualToString:STPCheckoutEventOpen]) { + // no-op for now + } else if ([event isEqualToString:STPCheckoutEventTokenize]) { + STPToken *token = nil; + if (payload != nil && payload[@"token"] != nil) { + token = [[STPToken alloc] initWithAttributeDictionary:payload[@"token"]]; + } + [self.checkoutDelegate checkoutController:self + didCreateToken:token + completion:^(STPBackendChargeResult status, NSError *error) { + self.backendChargeSuccessful = (status == STPBackendChargeResultSuccess); + self.backendChargeError = error; + if (status == STPBackendChargeResultSuccess) { + [adapter evaluateJavaScript:payload[@"success"]]; + } else { + NSString *encodedError = @""; + if (error.localizedDescription) { + encodedError = [[NSString alloc] + initWithData:[NSJSONSerialization dataWithJSONObject:@[error.localizedDescription] options:0 error:nil] + encoding:NSUTF8StringEncoding]; + encodedError = [encodedError substringWithRange:NSMakeRange(2, encodedError.length - 4)]; + } + NSString *failure = payload[@"failure"]; + NSString *script = [NSString stringWithFormat:failure, encodedError]; + [adapter evaluateJavaScript:script]; + } + }]; + } else if ([event isEqualToString:STPCheckoutEventFinish]) { + if (self.backendChargeSuccessful) { + [self.checkoutDelegate checkoutController:self didFinishWithStatus:STPPaymentStatusSuccess error:nil]; + } else { + [self.checkoutDelegate checkoutController:self didFinishWithStatus:STPPaymentStatusError error:self.backendChargeError]; + } + } else if ([event isEqualToString:STPCheckoutEventCancel]) { + [self.checkoutDelegate checkoutController:self didFinishWithStatus:STPPaymentStatusUserCancelled error:nil]; + } else if ([event isEqualToString:STPCheckoutEventError]) { + NSError *error = [[NSError alloc] initWithDomain:StripeDomain code:STPCheckoutError userInfo:payload]; + [self.checkoutDelegate checkoutController:self didFinishWithStatus:STPPaymentStatusError error:error]; + } +} + +- (void)checkoutAdapterDidFinishLoad:(__unused id)adapter { +} + +- (void)checkoutAdapter:(__unused id)adapter didError:(NSError *)error { + [self.checkoutDelegate checkoutController:self didFinishWithStatus:STPPaymentStatusError error:error]; +} + +@end + +#endif diff --git a/Frameworks/Stripe/Checkout/STPCheckoutWebViewAdapter.h b/Frameworks/Stripe/Checkout/STPCheckoutWebViewAdapter.h new file mode 100755 index 00000000..4031c379 --- /dev/null +++ b/Frameworks/Stripe/Checkout/STPCheckoutWebViewAdapter.h @@ -0,0 +1,43 @@ +// +// STPCheckoutWebViewAdapter.h +// Stripe +// +// Created by Jack Flintermann on 1/7/15. +// Copyright (c) 2015 Stripe, Inc. All rights reserved. +// + +#import +#if TARGET_OS_IPHONE +#define STP_VIEW_CLASS UIView +#import +#else +#define STP_VIEW_CLASS NSView +#import +#endif + +#import "STPNullabilityMacros.h" + +static NSString * __stp_nonnull const checkoutOptionsGlobal = @"StripeCheckoutOptions"; +static NSString * __stp_nonnull const checkoutRedirectPrefix = @"/-/"; +static NSString * __stp_nonnull const checkoutUserAgent = @"Stripe"; +static NSString * __stp_nonnull const checkoutRPCScheme = @"stripecheckout"; + +static NSString * __stp_nonnull const checkoutHost = @"checkout.stripe.com"; +static NSString * __stp_nonnull const checkoutURLString = @"https://checkout.stripe.com/v3/ios/index.html"; + +static NSString * __stp_nonnull const STPCheckoutEventOpen = @"CheckoutDidOpen"; +static NSString * __stp_nonnull const STPCheckoutEventTokenize = @"CheckoutDidTokenize"; +static NSString * __stp_nonnull const STPCheckoutEventCancel = @"CheckoutDidCancel"; +static NSString * __stp_nonnull const STPCheckoutEventFinish = @"CheckoutDidFinish"; +static NSString * __stp_nonnull const STPCheckoutEventError = @"CheckoutDidError"; + +@protocol STPCheckoutDelegate; +@protocol STPCheckoutWebViewAdapter + +@property (nonatomic, weak, stp_nullable) id delegate; +@property (nonatomic, readonly, stp_nullable) STP_VIEW_CLASS *webView; +- (void)loadRequest:(stp_nonnull NSURLRequest *)request; +- (stp_nullable NSString *)evaluateJavaScript:(stp_nonnull NSString *)js; +- (void)cleanup; + +@end diff --git a/Frameworks/Stripe/Checkout/STPColorUtils.h b/Frameworks/Stripe/Checkout/STPColorUtils.h new file mode 100755 index 00000000..683d2fd6 --- /dev/null +++ b/Frameworks/Stripe/Checkout/STPColorUtils.h @@ -0,0 +1,27 @@ +// +// STPColorUtils.h +// Stripe +// +// Created by Jack Flintermann on 11/3/14. +// +// + +#import +#if TARGET_OS_IPHONE +#import +#define STP_COLOR_CLASS UIColor +#else +#import +#define STP_COLOR_CLASS NSColor +#endif + +#import "STPNullabilityMacros.h" + +@interface STPColorUtils : NSObject + ++ (BOOL)colorIsLight:(stp_nonnull STP_COLOR_CLASS *)color; + ++ (stp_nonnull STP_COLOR_CLASS *)colorForHexCode:(stp_nonnull NSString *)hexCode; ++ (stp_nonnull NSString *)hexCodeForColor:(stp_nonnull STP_COLOR_CLASS *)color; + +@end diff --git a/Frameworks/Stripe/Checkout/STPColorUtils.m b/Frameworks/Stripe/Checkout/STPColorUtils.m new file mode 100755 index 00000000..4277fc3b --- /dev/null +++ b/Frameworks/Stripe/Checkout/STPColorUtils.m @@ -0,0 +1,72 @@ +// +// STPColorUtils.m +// Stripe +// +// Created by Jack Flintermann on 11/3/14. +// +// + +#import "STPColorUtils.h" + +@implementation STPColorUtils + +// Some of this code is adapted from https://github.com/nicklockwood/ColorUtils + ++ (BOOL)colorIsLight:(STP_COLOR_CLASS *)color { + CGColorSpaceModel model = CGColorSpaceGetModel(CGColorGetColorSpace(color.CGColor)); + const CGFloat *components = CGColorGetComponents(color.CGColor); + switch (model) { + case kCGColorSpaceModelMonochrome: { + return components[1] > 0.5; + } + case kCGColorSpaceModelRGB: { + CGFloat colorBrightness = ((components[0] * 299) + (components[1] * 587) + (components[2] * 114)) / 1000; + return colorBrightness > 0.5; + } + default: { return YES; } + } +} + ++ (STP_COLOR_CLASS *)colorForHexCode:(NSString *)aHexCode { + NSString *hexCode = [aHexCode stringByReplacingOccurrencesOfString:@"#" withString:@""]; + if (hexCode.length != 6) { + return [STP_COLOR_CLASS blackColor]; + } + uint32_t rgb; + NSScanner *scanner = [NSScanner scannerWithString:hexCode]; + [scanner scanHexInt:&rgb]; + CGFloat red = ((rgb & 0xFF0000) >> 16) / 255.0f; + CGFloat green = ((rgb & 0x00FF00) >> 8) / 255.0f; + CGFloat blue = (rgb & 0x0000FF) / 255.0f; + return [STP_COLOR_CLASS colorWithRed:red green:green blue:blue alpha:1.0f]; +} + ++ (NSString *)hexCodeForColor:(STP_COLOR_CLASS *)color { + uint8_t rgb[3]; + CGColorSpaceModel model = CGColorSpaceGetModel(CGColorGetColorSpace(color.CGColor)); + const CGFloat *components = CGColorGetComponents(color.CGColor); + switch (model) { + case kCGColorSpaceModelMonochrome: { + rgb[0] = (uint8_t)(components[0] * 255); + rgb[1] = (uint8_t)(components[0] * 255); + rgb[2] = (uint8_t)(components[0] * 255); + break; + } + case kCGColorSpaceModelRGB: { + rgb[0] = (uint8_t)(components[0] * 255); + rgb[1] = (uint8_t)(components[1] * 255); + rgb[2] = (uint8_t)(components[2] * 255); + break; + } + default: { + rgb[0] = 0; + rgb[1] = 0; + rgb[2] = 0; + break; + } + } + unsigned long rgbValue = (unsigned long)((rgb[0] << 16) + (rgb[1] << 8) + rgb[2]); + return [NSString stringWithFormat:@"#%.6lx", rgbValue]; +} + +@end diff --git a/Frameworks/Stripe/Checkout/STPIOSCheckoutWebViewAdapter.h b/Frameworks/Stripe/Checkout/STPIOSCheckoutWebViewAdapter.h new file mode 100755 index 00000000..b80f60d6 --- /dev/null +++ b/Frameworks/Stripe/Checkout/STPIOSCheckoutWebViewAdapter.h @@ -0,0 +1,21 @@ +// +// STPIOSCheckoutWebViewAdapter.h +// Stripe +// +// Created by Jack Flintermann on 1/7/15. +// Copyright (c) 2015 Stripe, Inc. All rights reserved. +// + +#if TARGET_OS_IPHONE + +#import +#import + +#import "STPCheckoutWebViewAdapter.h" +#import "STPNullabilityMacros.h" + +@interface STPIOSCheckoutWebViewAdapter : NSObject +@property (nonatomic, stp_nullable) UIWebView *webView; +@end + +#endif diff --git a/Frameworks/Stripe/Checkout/STPIOSCheckoutWebViewAdapter.m b/Frameworks/Stripe/Checkout/STPIOSCheckoutWebViewAdapter.m new file mode 100755 index 00000000..a5204f57 --- /dev/null +++ b/Frameworks/Stripe/Checkout/STPIOSCheckoutWebViewAdapter.m @@ -0,0 +1,110 @@ +// +// STPIOSCheckoutWebViewAdapter.m +// Stripe +// +// Created by Jack Flintermann on 1/7/15. +// Copyright (c) 2015 Stripe, Inc. All rights reserved. +// + +#import + +#if TARGET_OS_IPHONE + +#import "STPIOSCheckoutWebViewAdapter.h" +#import "STPStrictURLProtocol.h" +#import "STPCheckoutDelegate.h" + +@implementation STPIOSCheckoutWebViewAdapter + +@synthesize delegate; + +- (instancetype)init { + self = [super init]; + if (self) { + _webView = [[UIWebView alloc] initWithFrame:CGRectZero]; + _webView.delegate = self; + _webView.keyboardDisplayRequiresUserAction = NO; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ [NSURLProtocol registerClass:[STPStrictURLProtocol class]]; }); + } + return self; +} + +- (void)dealloc { + _webView.delegate = nil; +} + +- (void)loadRequest:(NSURLRequest *)request { + [self.webView loadRequest:request]; +} + +- (NSString *)evaluateJavaScript:(NSString *)js { + return [self.webView stringByEvaluatingJavaScriptFromString:js]; +} + +- (void)cleanup { + if ([self.webView isLoading]) { + [self.webView stopLoading]; + } +} + +#pragma mark - UIWebViewDelegate + +- (void)webViewDidStartLoad:(__unused UIWebView *)webView { + dispatch_async(dispatch_get_main_queue(), ^{ + [self.delegate checkoutAdapterDidStartLoad:self]; + }); +} + +- (BOOL)webView:(__unused UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { + NSURL *url = request.URL; + switch (navigationType) { + case UIWebViewNavigationTypeLinkClicked: { + if ([url.host isEqualToString:checkoutHost]) { + if ([url.path rangeOfString:checkoutRedirectPrefix].location == 0) { + [[UIApplication sharedApplication] openURL:url]; + return NO; + } + return YES; + } + return NO; + } + case UIWebViewNavigationTypeOther: { + if ([url.scheme isEqualToString:checkoutRPCScheme]) { + NSString *event = url.host; + NSString *path = [url.path componentsSeparatedByString:@"/"][1]; + NSDictionary *payload = @{}; + if (path != nil) { + payload = [NSJSONSerialization JSONObjectWithData:[path dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil]; + } + dispatch_async(dispatch_get_main_queue(), ^{ + [self.delegate checkoutAdapter:self didTriggerEvent:event withPayload:payload]; + }); + return NO; + } + return YES; + } + default: + // add tracking + return NO; + } +} + +- (void)webViewDidFinishLoad:(__unused UIWebView *)webView { + dispatch_async(dispatch_get_main_queue(), ^{ + [self.delegate checkoutAdapterDidFinishLoad:self]; + }); +} + +- (void)webView:(__unused UIWebView *)webView didFailLoadWithError:(NSError *)error { + // Cancellation callbacks are handled directly by the webview, so no need to catch them here. + if ([error code] != NSURLErrorCancelled) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self.delegate checkoutAdapter:self didError:error]; + }); + } +} + +@end + +#endif diff --git a/Frameworks/Stripe/Checkout/STPOSXCheckoutWebViewAdapter.h b/Frameworks/Stripe/Checkout/STPOSXCheckoutWebViewAdapter.h new file mode 100755 index 00000000..b0ce08cc --- /dev/null +++ b/Frameworks/Stripe/Checkout/STPOSXCheckoutWebViewAdapter.h @@ -0,0 +1,21 @@ +// +// STPOSXCheckoutWebViewAdapter.h +// Stripe +// +// Created by Jack Flintermann on 1/7/15. +// Copyright (c) 2015 Stripe, Inc. All rights reserved. +// + +#if !TARGET_OS_IPHONE + +#import +#import + +#import "STPCheckoutWebViewAdapter.h" +#import "STPNullabilityMacros.h" + +@interface STPOSXCheckoutWebViewAdapter : NSObject +@property (nonatomic, stp_nullable) WebView *webView; +@end + +#endif diff --git a/Frameworks/Stripe/Checkout/STPOSXCheckoutWebViewAdapter.m b/Frameworks/Stripe/Checkout/STPOSXCheckoutWebViewAdapter.m new file mode 100755 index 00000000..edfd14c8 --- /dev/null +++ b/Frameworks/Stripe/Checkout/STPOSXCheckoutWebViewAdapter.m @@ -0,0 +1,149 @@ +// +// STPOSXCheckoutWebViewAdapter.m +// Stripe +// +// Created by Jack Flintermann on 1/7/15. +// Copyright (c) 2015 Stripe, Inc. All rights reserved. +// + +#import + +#if !TARGET_OS_IPHONE + +#import "STPOSXCheckoutWebViewAdapter.h" +#import "STPStrictURLProtocol.h" +#import "STPCheckoutWebViewAdapter.h" +#import "STPCheckoutDelegate.h" + +@implementation STPOSXCheckoutWebViewAdapter + +@synthesize delegate; + +- (instancetype)init { + self = [super init]; + if (self) { + _webView = [[WebView alloc] initWithFrame:CGRectZero]; + _webView.drawsBackground = NO; + _webView.frameLoadDelegate = self; + _webView.policyDelegate = self; + _webView.resourceLoadDelegate = self; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ [NSURLProtocol registerClass:[STPStrictURLProtocol class]]; }); + } + return self; +} + +- (void)dealloc { + _webView.frameLoadDelegate = nil; + _webView.policyDelegate = nil; + _webView.resourceLoadDelegate = nil; +} + +- (void)loadRequest:(NSURLRequest *)request { + [self.webView.mainFrame loadRequest:request]; +} + +- (NSString *)evaluateJavaScript:(NSString *)js { + return [self.webView.windowScriptObject evaluateWebScript:js]; +} + +- (void)cleanup { + if ([self.webView isLoading]) { + [self.webView stopLoading:nil]; + } +} + +#pragma mark - ResourceLoadDelegate +- (NSURLRequest *)webView:(__unused WebView *)sender + resource:(__unused id)identifier + willSendRequest:(NSURLRequest *)request + redirectResponse:(__unused NSURLResponse *)redirectResponse + fromDataSource:(__unused WebDataSource *)dataSource { + return request; +} + +- (id)webView:(__unused WebView *)sender identifierForInitialRequest:(NSURLRequest *)request fromDataSource:(__unused WebDataSource *)dataSource { + return request.URL; +} + +- (void)webView:(__unused WebView *)sender resource:(id)identifier didFailLoadingWithError:(NSError *)error fromDataSource:(WebDataSource *)dataSource { + if ([identifier isEqual:dataSource.initialRequest.URL]) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self.delegate checkoutAdapter:self didError:error]; + }); + } +} + +#pragma mark - WebPolicyDelegate +- (void)webView:(__unused WebView *)webView +decidePolicyForNavigationAction:(NSDictionary *)actionInformation + request:(NSURLRequest *)request + frame:(__unused WebFrame *)frame +decisionListener:(id)listener { + NSURL *url = request.URL; + if ([NSURLProtocol propertyForKey:STPStrictURLProtocolRequestKey inRequest:request] != nil) { + [listener use]; + return; + } + WebNavigationType navigationType = [actionInformation[WebActionNavigationTypeKey] integerValue]; + switch (navigationType) { + case WebNavigationTypeLinkClicked: { + if ([url.host isEqualToString:checkoutHost]) { + if ([url.path rangeOfString:checkoutRedirectPrefix].location == 0) { + [[NSWorkspace sharedWorkspace] openURL:url]; + [listener ignore]; + return; + } + [listener use]; + return; + } + [listener ignore]; + break; + } + case WebNavigationTypeOther: { + if ([url.scheme isEqualToString:checkoutRPCScheme]) { + NSString *event = url.host; + NSString *path = [url.path componentsSeparatedByString:@"/"][1]; + NSDictionary *payload = @{}; + if (path != nil) { + payload = [NSJSONSerialization JSONObjectWithData:[path dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil]; + } + dispatch_async(dispatch_get_main_queue(), ^{ + [self.delegate checkoutAdapter:self didTriggerEvent:event withPayload:payload]; + }); + [listener ignore]; + return; + } + [listener use]; + break; + } + default: + // add tracking + [listener ignore]; + break; + } +} + +#pragma mark - WebFrameLoadDelegate +- (void)webView:(__unused WebView *)sender didStartProvisionalLoadForFrame:(__unused WebFrame *)frame { + dispatch_async(dispatch_get_main_queue(), ^{ + [self.delegate checkoutAdapterDidStartLoad:self]; + }); +} + +- (void)webView:(__unused WebView *)sender didFailLoadWithError:(NSError *)error + forFrame:(__unused WebFrame *)frame { + dispatch_async(dispatch_get_main_queue(), ^{ + [self.delegate checkoutAdapter:self didError:error]; + }); +} + +- (void)webView:(__unused WebView *)sender didFinishLoadForFrame:(__unused WebFrame *)frame { + dispatch_async(dispatch_get_main_queue(), ^{ + [self.delegate checkoutAdapterDidFinishLoad:self]; + }); +} + +@end + +#endif diff --git a/Frameworks/Stripe/Checkout/STPStrictURLProtocol.h b/Frameworks/Stripe/Checkout/STPStrictURLProtocol.h new file mode 100755 index 00000000..9709cee0 --- /dev/null +++ b/Frameworks/Stripe/Checkout/STPStrictURLProtocol.h @@ -0,0 +1,20 @@ +// +// STPStrictURLProtocol.h +// Stripe +// +// Created by Jack Flintermann on 1/7/15. +// Copyright (c) 2015 Stripe, Inc. All rights reserved. +// + +#import + +#import "STPNullabilityMacros.h" + +static NSString * __stp_nonnull const STPStrictURLProtocolRequestKey = @"STPStrictURLProtocolRequestKey"; + +/** + * This URL protocol treats any non-20x or 30x response from checkout as an error (unlike the default UIWebView behavior, which e.g. displays a 404 page). + */ +@interface STPStrictURLProtocol : NSURLProtocol +@property (nonatomic, strong, stp_nullable) NSURLConnection *connection; +@end diff --git a/Frameworks/Stripe/Checkout/STPStrictURLProtocol.m b/Frameworks/Stripe/Checkout/STPStrictURLProtocol.m new file mode 100755 index 00000000..e937a260 --- /dev/null +++ b/Frameworks/Stripe/Checkout/STPStrictURLProtocol.m @@ -0,0 +1,71 @@ +// +// STPStrictURLProtocol.m +// Stripe +// +// Created by Jack Flintermann on 1/7/15. +// Copyright (c) 2015 Stripe, Inc. All rights reserved. +// + +#import "STPStrictURLProtocol.h" +#import "StripeError.h" + +@interface STPStrictURLProtocol() +@end + +@implementation STPStrictURLProtocol + ++ (BOOL)canInitWithRequest:(NSURLRequest *)request { + return [self propertyForKey:STPStrictURLProtocolRequestKey inRequest:request] != nil; +} + ++ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request { + return request; +} + +- (void)startLoading { + NSMutableURLRequest *newRequest = [self.request mutableCopy]; + [self.class removePropertyForKey:STPStrictURLProtocolRequestKey inRequest:newRequest]; + self.connection = [NSURLConnection connectionWithRequest:[newRequest copy] delegate:self]; +} + +- (void)stopLoading { + [self.connection cancel]; + self.connection = nil; +} + +- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { + if ([response isKindOfClass:[NSHTTPURLResponse class]]) { + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; + // 30x redirects are automatically followed and will not reach here, + // so we only need to check for successful 20x status codes. + if (httpResponse.statusCode / 100 != 2 && httpResponse.statusCode != 301) { + NSError *error = [[NSError alloc] initWithDomain:StripeDomain + code:STPConnectionError + userInfo:@{ + NSLocalizedDescriptionKey: STPUnexpectedError, + STPErrorMessageKey: @"Stripe Checkout couldn't open. Please check your internet connection and try " + @"again. If the problem persists, please contact support@stripe.com." + }]; + [self.client URLProtocol:self didFailWithError:error]; + [connection cancel]; + self.connection = nil; + return; + } + } + [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; +} + +- (void)connection:(__unused NSURLConnection *)connection didReceiveData:(NSData *)data { + [self.client URLProtocol:self didLoadData:data]; +} + +- (void)connectionDidFinishLoading:(__unused NSURLConnection *)connection { + [self.client URLProtocolDidFinishLoading:self]; +} + +- (void)connection:(__unused NSURLConnection *)connection didFailWithError:(NSError *)error { + [self.client URLProtocol:self didFailWithError:error]; +} + + +@end diff --git a/Frameworks/Stripe/Info.plist b/Frameworks/Stripe/Info.plist new file mode 100755 index 00000000..2f0e6799 --- /dev/null +++ b/Frameworks/Stripe/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + com.stripe.$(PRODUCT_NAME:rfc1034identifier) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + $(CURRENT_LIBRARY_VERSION) + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/Frameworks/Stripe/PublicHeaders/ApplePay/STPAPIClient+ApplePay.h b/Frameworks/Stripe/PublicHeaders/ApplePay/STPAPIClient+ApplePay.h new file mode 100755 index 00000000..6b80f1df --- /dev/null +++ b/Frameworks/Stripe/PublicHeaders/ApplePay/STPAPIClient+ApplePay.h @@ -0,0 +1,27 @@ +// +// STPAPIClient+ApplePay.h +// Stripe +// +// Created by Jack Flintermann on 12/19/14. +// + +#import +#import + +#import "STPAPIClient.h" +#import "STPNullabilityMacros.h" + +@interface STPAPIClient (ApplePay) + +/** + * Converts a PKPayment object into a Stripe token using the Stripe API. + * + * @param payment The user's encrypted payment information as returned from a PKPaymentAuthorizationViewController. Cannot be nil. + * @param completion The callback to run with the returned Stripe token (and any errors that may have occurred). + */ +- (void)createTokenWithPayment:(stp_nonnull PKPayment *)payment completion:(stp_nonnull STPCompletionBlock)completion; + +// Form-encodes a PKPayment object for POSTing to the Stripe API. This method is used internally by STPAPIClient; you should not use it in your own code. ++ (stp_nonnull NSData *)formEncodedDataForPayment:(stp_nonnull PKPayment *)payment; + +@end diff --git a/Frameworks/Stripe/PublicHeaders/ApplePay/Stripe+ApplePay.h b/Frameworks/Stripe/PublicHeaders/ApplePay/Stripe+ApplePay.h new file mode 100755 index 00000000..7db4881f --- /dev/null +++ b/Frameworks/Stripe/PublicHeaders/ApplePay/Stripe+ApplePay.h @@ -0,0 +1,64 @@ +// +// Stripe+ApplePay.h +// Stripe +// +// Created by Jack Flintermann on 9/17/14. +// + +#import +#import + +#import "Stripe.h" +#import "STPAPIClient+ApplePay.h" +#import "STPNullabilityMacros.h" + +@class Stripe; + +@interface Stripe (ApplePay) + +/** + * Whether or not this device is capable of using Apple Pay. This checks both whether the user is running an iPhone 6/6+ or later, iPad Air 2 or later, or iPad + *mini 3 or later, as well as whether or not they have stored any cards in Apple Pay on their device. + * + * @param paymentRequest The return value of this method depends on the supportedNetworks property of this payment request, which by default should be + *@[PKPaymentNetworkAmex, PKPaymentNetworkMasterCard, PKPaymentNetworkVisa]. + * + * @return whether or not the user is currently able to pay with Apple Pay. + */ ++ (BOOL)canSubmitPaymentRequest:(stp_nullable PKPaymentRequest *)paymentRequest; + +/** + * A convenience method to return a PKPaymentRequest with sane default values. You will still need to configure the paymentSummaryItems property to indicate + *what the user is purchasing, as well as the optional requiredShippingAddressFields, requiredBillingAddressFields, and shippingMethods properties to indicate + *what contact information your application requires. + * + * @param merchantIdentifier Your Apple Merchant ID, as obtained at https://developer.apple.com/account/ios/identifiers/merchant/merchantCreate.action + * + * @return a PKPaymentRequest with proper default values. Returns nil if running on < iOS8. + */ ++ (stp_nullable PKPaymentRequest *)paymentRequestWithMerchantIdentifier:(stp_nonnull NSString *)merchantIdentifier; + +#pragma mark - deprecated methods + +/** + * Securely convert your user's Apple Pay payment information into a Stripe token, which you can then safely store on your server and use to charge the user. + * The URL connection will run on the main queue. Uses the value of [Stripe defaultPublishableKey] for authentication. + * + * @param payment The PKPayment instance to convert, as returned from a PKPaymentAuthorizationViewController + * @param handler Code to run when the token has been returned (along with any errors encountered). + * @deprecated use [[STPAPIClient sharedClient] createTokenWithPayment:completion:] instead. + */ ++ (void)createTokenWithPayment:(stp_nonnull PKPayment *)payment completion:(stp_nonnull STPCompletionBlock)handler __attribute__((deprecated)); + +/** + * Securely convert your user's Apple Pay payment information into a Stripe token, which you can then safely store on your server and use to charge the user. + * The URL connection will run on the main queue. Uses the value of [Stripe defaultPublishableKey] for authentication. + * + * @param payment The PKPayment instance to convert, as returned from a PKPaymentAuthorizationViewController + * @param queue The operation queue on which to run the URL connection. @see NSURLConnection + * @param handler Code to run when the token has been returned (along with any errors encountered). + * @deprecated use [[STPAPIClient sharedClient] createTokenWithPayment:completion:] instead. + */ ++ (void)createTokenWithPayment:(stp_nonnull PKPayment *)payment operationQueue:(stp_nonnull NSOperationQueue *)queue completion:(stp_nonnull STPCompletionBlock)handler __attribute__((deprecated)); + +@end diff --git a/Frameworks/Stripe/PublicHeaders/Checkout/STPCheckoutOptions.h b/Frameworks/Stripe/PublicHeaders/Checkout/STPCheckoutOptions.h new file mode 100755 index 00000000..992c89cf --- /dev/null +++ b/Frameworks/Stripe/PublicHeaders/Checkout/STPCheckoutOptions.h @@ -0,0 +1,114 @@ +// +// STPCheckoutOptions.h +// StripeExample +// +// Created by Jack Flintermann on 10/6/14. +// + +#import +#if TARGET_OS_IPHONE +#import +#define STP_IMAGE_CLASS UIImage +#else +#import +#define STP_IMAGE_CLASS NSImage +#endif + +#import "STPNullabilityMacros.h" + +/** + * This class represents a configurable set of options that you can pass to an STPCheckoutViewController to control the appearance of + * Stripe Checkout. For more information on how these properties behave, see https://stripe.com/docs/checkout#integration-custom + */ +@interface STPCheckoutOptions : NSObject + +-(stp_nonnull instancetype)initWithPublishableKey:(stp_nonnull NSString *)publishableKey; + +#pragma mark - Required options + +/** + * The Stripe publishable key to use for your Checkout requests. Defaults to [Stripe defaultPublishableKey]. Required. + */ +@property (nonatomic, copy, stp_nonnull) NSString *publishableKey; + +#pragma mark - Strongly recommended options + +/** + * This can be an external image URL that will load in the header of Stripe Checkout. This takes precedent over the logoImage property. The recommended minimum + * size for this image is 128x128px. + */ +@property (nonatomic, copy, stp_nullable) NSURL *logoURL; + +/** + * You can also specify a local UIImage to be used as the Checkout logo header (see logoURL). + */ +@property (nonatomic, stp_nullable) STP_IMAGE_CLASS *logoImage; + +/** + * This specifies the color of the header shown in Stripe Checkout. If you specify a logoURL (but not a logoImage) and leave this property nil, Checkout will + * auto-detect the background color of the image you point to and use that as the header color. + */ +#if TARGET_OS_IPHONE +@property (nonatomic, copy, stp_nullable) UIColor *logoColor; +#else +@property (nonatomic, copy, stp_nullable) NSColor *logoColor; +#endif + +/** + * The name of your company or website. Displayed in the header. Defaults to your app's name. + */ +@property (nonatomic, copy, stp_nullable) NSString *companyName; + +/** + * A description of the product or service being purchased. Appears in the header. + */ +@property (nonatomic, copy, stp_nullable) NSString *purchaseDescription; + +/** + * The amount (in cents) that's shown to the user. Note that this is for display purposes only; you will still have to explicitly specify the amount when you + * create a charge using the Stripe API. + * @warning don't forget this is in cents! So for a $10 charge, specify 1000 here. + */ +@property (nonatomic) NSUInteger purchaseAmount; + +/** + * If you already know the email address of your user, you can provide it to Checkout to be pre-filled. + */ +@property (nonatomic, copy, stp_nullable) NSString *customerEmail; + +#pragma mark - Additional options + +/** + * The label of the payment button in the Checkout form (e.g. “Subscribe”, “Pay {{amount}}”, etc.). If you include {{amount}}, it will be replaced by the + * provided amount. Otherwise, the amount will be appended to the end of your label. Defaults to "Pay {{amount}}". + */ +@property (nonatomic, copy, stp_nullable) NSString *purchaseLabel; + +/** + * The currency of the amount (3-letter ISO code). The default is "USD". + */ +@property (nonatomic, copy, stp_nonnull) NSString *purchaseCurrency; + +/** + * Specify whether to include the option to "Remember Me" for future purchases (true or false). The default is true. + */ +@property (nonatomic, copy, stp_nullable) NSNumber *enableRememberMe; + +/** + * Specify whether Checkout should validate your user's billing ZIP code (true or false). The default is false. + */ +@property (nonatomic, copy, stp_nullable) NSNumber *enablePostalCode; + +/** + * Specify whether Checkout should require the user to enter their billing address. The default is false. + */ +@property (nonatomic, copy, stp_nullable) NSNumber *requireBillingAddress; + +/** + * Used internally by Stripe Checkout. + * + * @return a JSON string representing the options. + */ +- (stp_nonnull NSString *)stringifiedJSONRepresentation; + +@end diff --git a/Frameworks/Stripe/PublicHeaders/Checkout/STPCheckoutViewController.h b/Frameworks/Stripe/PublicHeaders/Checkout/STPCheckoutViewController.h new file mode 100755 index 00000000..8313ce59 --- /dev/null +++ b/Frameworks/Stripe/PublicHeaders/Checkout/STPCheckoutViewController.h @@ -0,0 +1,92 @@ +// +// STPCheckoutViewController.h +// StripeExample +// +// Created by Jack Flintermann on 9/15/14. +// + +#import +#if TARGET_OS_IPHONE +#import +#else +#import +#endif + +#import "STPNullabilityMacros.h" + +typedef NS_ENUM(NSInteger, STPPaymentStatus) { + STPPaymentStatusSuccess, // The transaction was a success. + STPPaymentStatusError, // The transaction failed. + STPPaymentStatusUserCancelled, // The user Cancelled the payment sheet. +}; + +@class STPCheckoutOptions, STPToken; +@protocol STPCheckoutViewControllerDelegate; + +/** + Controls a UIWebView that loads an iOS-optimized version of Stripe Checkout that you can present modally. Note that this functionality is considered in beta + and may change. + */ +#if TARGET_OS_IPHONE +@interface STPCheckoutViewController : UINavigationController +#else +@interface STPCheckoutViewController : NSViewController +#endif + +/** + * Creates an STPCheckoutViewController with the desired options. The options are copied at this step, so changing any of their values after instantiating an + *STPCheckoutViewController will have no effect. + * + * @param options A configuration object that describes how to display Stripe Checkout. + * + */ +- (stp_nonnull instancetype)initWithOptions:(stp_nonnull STPCheckoutOptions *)options NS_DESIGNATED_INITIALIZER; +@property (nonatomic, readonly, copy, stp_nonnull) STPCheckoutOptions *options; + +/** + * Note: you must set a delegate before showing an STPViewController. + */ +@property (nonatomic, weak, stp_nullable) id checkoutDelegate; + +@end + +@protocol STPCheckoutViewControllerDelegate + +/** + * Called when the checkout view controller has finished displaying the "success" or "error" animation. At this point, the controller is done with its work. + * You should dismiss the view controller at this point, probably by calling `dismissViewControllerAnimated:completion:`. + * + * @param controller the checkout view controller that has finished. + * @param status the result of the payment (success, failure, or cancelled by the user). You should use this to determine whether to proceed to the success + *state, for example. + * @param error the returned error, if it exists. Can be nil. + */ +- (void)checkoutController:(stp_nonnull STPCheckoutViewController *)controller didFinishWithStatus:(STPPaymentStatus)status error:(stp_nullable NSError *)error; + +/** + * Use these options to inform Stripe Checkout of the success or failure of your backend charge. + */ +typedef NS_ENUM(NSInteger, STPBackendChargeResult) { + STPBackendChargeResultSuccess, // Passing this value will display a "success" animation in the payment button. + STPBackendChargeResultFailure, // Passing this value will display an "error" animation in the payment button. +}; + +typedef void (^STPTokenSubmissionHandler)(STPBackendChargeResult status, NSError * __stp_nullable error); + +/** + * After the user has provided valid credit card information and pressed the "pay" button, Checkout will communicate with Stripe and obtain a tokenized version + of their credit card. + + At this point, you should submit this token to your backend, which should use this token to create a charge. For more information on this, see + // The delegate must call completion with an appropriate authorization status, as may be determined + // by submitting the payment credential to a processing gateway for payment authorization. + * + * @param controller the checkout controller being presented + * @param token a Stripe token + * @param completion call this function with STPBackendChargeResultSuccess/Failure when you're done charging your user + */ +- (void)checkoutController:(stp_nonnull STPCheckoutViewController *)controller + didCreateToken:(stp_nonnull STPToken *)token + completion:(stp_nonnull STPTokenSubmissionHandler)completion; + +@end diff --git a/Frameworks/Stripe/PublicHeaders/STPAPIClient.h b/Frameworks/Stripe/PublicHeaders/STPAPIClient.h new file mode 100755 index 00000000..730d4016 --- /dev/null +++ b/Frameworks/Stripe/PublicHeaders/STPAPIClient.h @@ -0,0 +1,201 @@ +// +// STPAPIClient.h +// StripeExample +// +// Created by Jack Flintermann on 12/18/14. +// Copyright (c) 2014 Stripe. All rights reserved. +// + +#import +#import "STPNullabilityMacros.h" + +static NSString *const __stp_nonnull STPSDKVersion = @"4.0.3"; + +@class STPBankAccount, STPCard, STPToken; + +/** + * A callback to be run with the response from the Stripe API. + * + * @param token The Stripe token from the response. Will be nil if an error occurs. @see STPToken + * @param error The error returned from the response, or nil in one occurs. @see StripeError.h for possible values. + */ +typedef void (^STPCompletionBlock)(STPToken * __stp_nullable token, NSError * __stp_nullable error); + +/** + A top-level class that imports the rest of the Stripe SDK. This class used to contain several methods to create Stripe tokens, but those are now deprecated in + favor of STPAPIClient. + */ +@interface Stripe : NSObject + +/** + * Set your Stripe API key with this method. New instances of STPAPIClient will be initialized with this value. You should call this method as early as + * possible in your application's lifecycle, preferably in your AppDelegate. + * + * @param publishableKey Your publishable key, obtained from https://stripe.com/account/apikeys + * @warning Make sure not to ship your test API keys to the App Store! This will log a warning if you use your test key in a release build. + */ ++ (void)setDefaultPublishableKey:(stp_nonnull NSString *)publishableKey; + +/// The current default publishable key. ++ (stp_nullable NSString *)defaultPublishableKey; +@end + +/// A client for making connections to the Stripe API. +@interface STPAPIClient : NSObject + +/** + * A shared singleton API client. Its API key will be initially equal to [Stripe defaultPublishableKey]. + */ ++ (stp_nonnull instancetype)sharedClient; +- (stp_nonnull instancetype)initWithPublishableKey:(stp_nonnull NSString *)publishableKey NS_DESIGNATED_INITIALIZER; + +/** + * @see [Stripe setDefaultPublishableKey:] + */ +@property (nonatomic, copy, stp_nullable) NSString *publishableKey; + +/** + * The operation queue on which to run the url connection and delegate methods. Cannot be nil. @see NSURLConnection + */ +@property (nonatomic, stp_nonnull) NSOperationQueue *operationQueue; + +@end + +#pragma mark Bank Accounts + +@interface STPAPIClient (BankAccounts) + +/** + * Converts an STPBankAccount object into a Stripe token using the Stripe API. + * + * @param bankAccount The user's bank account details. Cannot be nil. @see https://stripe.com/docs/api#create_bank_account_token + * @param completion The callback to run with the returned Stripe token (and any errors that may have occurred). + */ +- (void)createTokenWithBankAccount:(stp_nonnull STPBankAccount *)bankAccount completion:(__stp_nullable STPCompletionBlock)completion; + +@end + +#pragma mark Credit Cards + +@interface STPAPIClient (CreditCards) + +/** + * Converts an STPCard object into a Stripe token using the Stripe API. + * + * @param card The user's card details. Cannot be nil. @see https://stripe.com/docs/api#create_card_token + * @param completion The callback to run with the returned Stripe token (and any errors that may have occurred). + */ +- (void)createTokenWithCard:(stp_nonnull STPCard *)card completion:(stp_nullable STPCompletionBlock)completion; + +@end + +// These methods are used internally and exposed here only for the sake of writing tests more easily. You should not use them in your own application. +@interface STPAPIClient (PrivateMethods) + +- (void)createTokenWithData:(stp_nonnull NSData *)data completion:(stp_nullable STPCompletionBlock)completion; + +@end + +#pragma mark - Deprecated Methods +// These methods are deprecated. You should instead use STPAPIClient to create tokens. +// Example: [Stripe createTokenWithCard:card completion:completion]; +// becomes [[STPAPIClient sharedClient] createTokenWithCard:card completion:completion]; +@interface Stripe (Deprecated) + +/** + * Securely convert your user's credit card details into a Stripe token, which you can then safely store on your server and use to charge the user. The URL + *connection will run on the main queue. Uses the value of [Stripe defaultPublishableKey] for authentication. + * + * @param card The user's card details. @see STPCard + * @param handler Code to run when the user's card has been turned into a Stripe token. + * @deprecated Use STPAPIClient instead. + */ ++ (void)createTokenWithCard:(stp_nonnull STPCard *)card completion:(stp_nullable STPCompletionBlock)handler __attribute__((deprecated)); + +/** + * Securely convert your user's credit card details into a Stripe token, which you can then safely store on your server and use to charge the user. The URL + *connection will run on the main queue. + * + * @param card The user's card details. @see STPCard + * @param publishableKey The API key to use to authenticate with Stripe. Get this at https://stripe.com/account/apikeys . + * @param handler Code to run when the user's card has been turned into a Stripe token. + * @deprecated Use STPAPIClient instead. + */ ++ (void)createTokenWithCard:(stp_nonnull STPCard *)card publishableKey:(stp_nonnull NSString *)publishableKey completion:(stp_nullable STPCompletionBlock)handler __attribute__((deprecated)); + +/** + * Securely convert your user's credit card details into a Stripe token, which you can then safely store on your server and use to charge the user. + * + * @param card The user's card details. @see STPCard + * @param queue The operation queue on which to run the URL connection. @see NSURLConnection + * @param handler Code to run when the user's card has been turned into a Stripe token. + * @deprecated Use STPAPIClient instead. + */ ++ (void)createTokenWithCard:(stp_nonnull STPCard *)card operationQueue:(stp_nonnull NSOperationQueue *)queue completion:(stp_nullable STPCompletionBlock)handler __attribute__((deprecated)); + +/** + * Securely convert your user's credit card details into a Stripe token, which you can then safely store on your server and use to charge the user. + * + * @param card The user's card details. @see STPCard + * @param publishableKey The API key to use to authenticate with Stripe. Get this at https://stripe.com/account/apikeys . + * @param queue The operation queue on which to run the URL connection. @see NSURLConnection + * @param handler Code to run when the user's card has been turned into a Stripe token. + * @deprecated Use STPAPIClient instead. + */ ++ (void)createTokenWithCard:(stp_nonnull STPCard *)card + publishableKey:(stp_nonnull NSString *)publishableKey + operationQueue:(stp_nonnull NSOperationQueue *)queue + completion:(stp_nullable STPCompletionBlock)handler __attribute__((deprecated)); + +/** + * Securely convert your user's credit card details into a Stripe token, which you can then safely store on your server and use to charge the user. The URL + *connection will run on the main queue. Uses the value of [Stripe defaultPublishableKey] for authentication. + * + * @param bankAccount The user's bank account details. @see STPBankAccount + * @param handler Code to run when the user's card has been turned into a Stripe token. + * @deprecated Use STPAPIClient instead. + */ ++ (void)createTokenWithBankAccount:(stp_nonnull STPBankAccount *)bankAccount completion:(stp_nullable STPCompletionBlock)handler __attribute__((deprecated)); + +/** + * Securely convert your user's credit card details into a Stripe token, which you can then safely store on your server and use to charge the user. The URL + *connection will run on the main queue. Uses the value of [Stripe defaultPublishableKey] for authentication. + * + * @param bankAccount The user's bank account details. @see STPBankAccount + * @param publishableKey The API key to use to authenticate with Stripe. Get this at https://stripe.com/account/apikeys . + * @param handler Code to run when the user's card has been turned into a Stripe token. + * @deprecated Use STPAPIClient instead. + */ ++ (void)createTokenWithBankAccount:(stp_nonnull STPBankAccount *)bankAccount + publishableKey:(stp_nonnull NSString *)publishableKey + completion:(stp_nullable STPCompletionBlock)handler __attribute__((deprecated)); + +/** + * Securely convert your user's credit card details into a Stripe token, which you can then safely store on your server and use to charge the user. The URL + *connection will run on the main queue. Uses the value of [Stripe defaultPublishableKey] for authentication. + * + * @param bankAccount The user's bank account details. @see STPBankAccount + * @param queue The operation queue on which to run the URL connection. @see NSURLConnection + * @param handler Code to run when the user's card has been turned into a Stripe token. + * @deprecated Use STPAPIClient instead. + */ ++ (void)createTokenWithBankAccount:(stp_nonnull STPBankAccount *)bankAccount + operationQueue:(stp_nonnull NSOperationQueue *)queue + completion:(stp_nullable STPCompletionBlock)handler __attribute__((deprecated)); + +/** + * Securely convert your user's credit card details into a Stripe token, which you can then safely store on your server and use to charge the user. The URL + *connection will run on the main queue. Uses the value of [Stripe defaultPublishableKey] for authentication. + * + * @param bankAccount The user's bank account details. @see STPBankAccount + * @param publishableKey The API key to use to authenticate with Stripe. Get this at https://stripe.com/account/apikeys . + * @param queue The operation queue on which to run the URL connection. @see NSURLConnection + * @param handler Code to run when the user's card has been turned into a Stripe token. + * @deprecated Use STPAPIClient instead. + */ ++ (void)createTokenWithBankAccount:(stp_nonnull STPBankAccount *)bankAccount + publishableKey:(stp_nonnull NSString *)publishableKey + operationQueue:(stp_nonnull NSOperationQueue *)queue + completion:(stp_nullable STPCompletionBlock)handler __attribute__((deprecated)); + +@end diff --git a/Frameworks/Stripe/PublicHeaders/STPBankAccount.h b/Frameworks/Stripe/PublicHeaders/STPBankAccount.h new file mode 100755 index 00000000..dcc7ec43 --- /dev/null +++ b/Frameworks/Stripe/PublicHeaders/STPBankAccount.h @@ -0,0 +1,77 @@ +// +// STPBankAccount.h +// Stripe +// +// Created by Charles Scalesse on 10/1/14. +// +// + +#import +#import "STPNullabilityMacros.h" + +/** + * Representation of a user's credit card details. You can assemble these with information that your user enters and + * then create Stripe tokens with them using an STPAPIClient. @see https://stripe.com/docs/api#create_bank_account_token + */ +@interface STPBankAccount : NSObject + +/** + * The account number for the bank account. Currently must be a checking account. + */ +@property (nonatomic, copy, stp_nullable) NSString *accountNumber; + +/** + * The routing number for the bank account. This should be the ACH routing number, not the wire routing number. + */ +@property (nonatomic, copy, stp_nullable) NSString *routingNumber; + +/** + * The country the bank account is in. + */ +@property (nonatomic, copy, stp_nullable) NSString *country; + +/** + * The default currency for the bank account. + */ +@property (nonatomic, copy, stp_nullable) NSString *currency; + +#pragma mark - These fields are only present on objects returned from the Stripe API. +/** + * The Stripe ID for the bank account. + */ +@property (nonatomic, readonly, stp_nullable) NSString *bankAccountId; + +/** + * The last 4 digits of the account number. + */ +@property (nonatomic, readonly, stp_nullable) NSString *last4; + +/** + * The name of the bank that owns the account. + */ +@property (nonatomic, readonly, stp_nullable) NSString *bankName; + +/** + * A proxy for the account number, this uniquely identifies the account and can be used to compare equality of different bank accounts. + */ +@property (nonatomic, readonly, stp_nullable) NSString *fingerprint; + +/** + * Whether or not the bank account has been validated via microdeposits or other means. + */ +@property (nonatomic, readonly) BOOL validated; + +/** + * Whether or not the bank account is currently disabled. + */ +@property (nonatomic, readonly) BOOL disabled; + +@end + + +// This method is used internally by Stripe to deserialize API responses and exposed here for convenience and testing purposes only. You should not use it in your own code. +@interface STPBankAccount (PrivateMethods) + +- (stp_nonnull instancetype)initWithAttributeDictionary:(stp_nonnull NSDictionary *)attributeDictionary; + +@end diff --git a/Frameworks/Stripe/PublicHeaders/STPCard.h b/Frameworks/Stripe/PublicHeaders/STPCard.h new file mode 100755 index 00000000..dba17f59 --- /dev/null +++ b/Frameworks/Stripe/PublicHeaders/STPCard.h @@ -0,0 +1,138 @@ +// +// STPCard.h +// Stripe +// +// Created by Saikat Chakrabarti on 11/2/12. +// +// + +#import +#import "STPNullabilityMacros.h" + +typedef NS_ENUM(NSInteger, STPCardFundingType) { + STPCardFundingTypeDebit, + STPCardFundingTypeCredit, + STPCardFundingTypePrepaid, + STPCardFundingTypeOther, +}; + +typedef NS_ENUM(NSInteger, STPCardBrand) { + STPCardBrandVisa, + STPCardBrandAmex, + STPCardBrandMasterCard, + STPCardBrandDiscover, + STPCardBrandJCB, + STPCardBrandDinersClub, + STPCardBrandUnknown, +}; + +/** + * Representation of a user's credit card details. You can assemble these with information that your user enters and + * then create Stripe tokens with them using an STPAPIClient. @see https://stripe.com/docs/api#cards + */ +@interface STPCard : NSObject + +/** + * The card's number. This will be nil for cards retrieved from the Stripe API. + */ +@property (nonatomic, copy, stp_nullable) NSString *number; + +/** + * The last 4 digits of the card. Unlike number, this will be present on cards retrieved from the Stripe API. + */ +@property (nonatomic, readonly, stp_nullable) NSString *last4; + +/** + * The card's expiration month. + */ +@property (nonatomic) NSUInteger expMonth; + +/** + * The card's expiration year. + */ +@property (nonatomic) NSUInteger expYear; + +/** + * The card's security code, found on the back. This will be nil for cards retrieved from the Stripe API. + */ +@property (nonatomic, copy, stp_nullable) NSString *cvc; + +/** + * The cardholder's name. + */ +@property (nonatomic, copy, stp_nullable) NSString *name; + +/** + * The cardholder's address. + */ +@property (nonatomic, copy, stp_nullable) NSString *addressLine1; +@property (nonatomic, copy, stp_nullable) NSString *addressLine2; +@property (nonatomic, copy, stp_nullable) NSString *addressCity; +@property (nonatomic, copy, stp_nullable) NSString *addressState; +@property (nonatomic, copy, stp_nullable) NSString *addressZip; +@property (nonatomic, copy, stp_nullable) NSString *addressCountry; + +/** + * The Stripe ID for the card. + */ +@property (nonatomic, readonly, stp_nullable) NSString *cardId; + +/** + * The issuer of the card. + */ +@property (nonatomic, readonly) STPCardBrand brand; + +/** + * The issuer of the card. + * Can be one of "Visa", "American Express", "MasterCard", "Discover", "JCB", "Diners Club", or "Unknown" + * @deprecated use "brand" instead. + */ +@property (nonatomic, readonly, stp_nonnull) NSString *type __attribute__((deprecated)); + +/** + * The funding source for the card (credit, debit, prepaid, or other) + */ +@property (nonatomic, readonly) STPCardFundingType funding; + +/** + * A proxy for the card's number, this uniquely identifies the credit card and can be used to compare different cards. + */ +@property (nonatomic, readonly, stp_nullable) NSString *fingerprint; + +/** + * Two-letter ISO code representing the issuing country of the card. + */ +@property (nonatomic, readonly, stp_nullable) NSString *country; + +// These validation methods work as described in +// http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/KeyValueCoding/Articles/Validation.html#//apple_ref/doc/uid/20002173-CJBDBHCB + +- (BOOL)validateNumber:(__stp_nullable id * __stp_nullable )ioValue + error:(NSError * __stp_nullable * __stp_nullable )outError; +- (BOOL)validateCvc:(__stp_nullable id * __stp_nullable )ioValue + error:(NSError * __stp_nullable * __stp_nullable )outError; +- (BOOL)validateExpMonth:(__stp_nullable id * __stp_nullable )ioValue + error:(NSError * __stp_nullable * __stp_nullable )outError; +- (BOOL)validateExpYear:(__stp_nullable id * __stp_nullable)ioValue + error:(NSError * __stp_nullable * __stp_nullable )outError; + +/** + * This validates a fully populated card to check for all errors, including ones that come about + * from the interaction of more than one property. It will also do all the validations on individual + * properties, so if you only want to call one method on your card to validate it after setting all the + * properties, call this one + * + * @param outError a pointer to an NSError that, after calling this method, will be populated with an error if the card is not valid. See StripeError.h for + possible values + * + * @return whether or not the card is valid. + */ +- (BOOL)validateCardReturningError:(NSError * __stp_nullable * __stp_nullable)outError; + +@end + +// This method is used internally by Stripe to deserialize API responses and exposed here for convenience and testing purposes only. You should not use it in +// your own code. +@interface STPCard (PrivateMethods) +- (stp_nonnull instancetype)initWithAttributeDictionary:(stp_nonnull NSDictionary *)attributeDictionary; +@end diff --git a/Frameworks/Stripe/PublicHeaders/STPNullabilityMacros.h b/Frameworks/Stripe/PublicHeaders/STPNullabilityMacros.h new file mode 100755 index 00000000..6576ec97 --- /dev/null +++ b/Frameworks/Stripe/PublicHeaders/STPNullabilityMacros.h @@ -0,0 +1,32 @@ +// +// STPNullabilityMacros.h +// Stripe +// +// Created by Jack Flintermann on 5/1/15. +// Copyright (c) 2015 Stripe, Inc. All rights reserved. +// +// Based on https://gist.github.com/steipete/d9f519858fe5fb5533eb + +#pragma once + +#if __has_feature(nullability) +#define STP_ASSUME_NONNULL_BEGIN _Pragma("clang assume_nonnull begin") +#define STP_ASSUME_NONNULL_END _Pragma("clang assume_nonnull end") +#define stp_nullable nullable +#define stp_nonnull nonnull +#define stp_null_unspecified null_unspecified +#define stp_null_resettable null_resettable +#define __stp_nullable __nullable +#define __stp_nonnull __nonnull +#define __stp_null_unspecified __null_unspecified +#else +#define STP_ASSUME_NONNULL_BEGIN +#define STP_ASSUME_NONNULL_END +#define stp_nullable +#define stp_nonnull +#define stp_null_unspecified +#define stp_null_resettable +#define __stp_nullable +#define __stp_nonnull +#define __stp_null_unspecified +#endif diff --git a/Frameworks/Stripe/PublicHeaders/STPToken.h b/Frameworks/Stripe/PublicHeaders/STPToken.h new file mode 100755 index 00000000..e9c033fc --- /dev/null +++ b/Frameworks/Stripe/PublicHeaders/STPToken.h @@ -0,0 +1,72 @@ +// +// STPToken.h +// Stripe +// +// Created by Saikat Chakrabarti on 11/5/12. +// +// + +#import +#import "STPNullabilityMacros.h" + +@class STPCard; +@class STPBankAccount; + +/** + * A token returned from submitting payment details to the Stripe API. You should not have to instantiate one of these directly. + */ +@interface STPToken : NSObject + +/** + * You cannot directly instantiate an STPToken. You should only use one that has been returned from an STPAPIClient callback. + */ +- (stp_nonnull instancetype) init __attribute__((unavailable("You cannot directly instantiate an STPToken. You should only use one that has been returned from an STPAPIClient callback."))); + +/** + * The value of the token. You can store this value on your server and use it to make charges and customers. @see + * https://stripe.com/docs/mobile/ios#sending-tokens + */ +@property (nonatomic, readonly, stp_nonnull) NSString *tokenId; + +/** + * Whether or not this token was created in livemode. Will be YES if you used your Live Publishable Key, and NO if you used your Test Publishable Key. + */ +@property (nonatomic, readonly) BOOL livemode; + +/** + * The credit card details that were used to create the token. Will only be set if the token was created via a credit card or Apple Pay, otherwise it will be + * nil. + */ +@property (nonatomic, readonly, stp_nullable) STPCard *card; + +/** + * The bank account details that were used to create the token. Will only be set if the token was created with a bank account, otherwise it will be nil. + */ +@property (nonatomic, readonly, stp_nullable) STPBankAccount *bankAccount; + +/** + * When the token was created. + */ +@property (nonatomic, readonly, stp_nullable) NSDate *created; + +typedef void (^STPCardServerResponseCallback)(NSURLResponse * __stp_nullable response, NSData * __stp_nullable data, NSError * __stp_nullable error); + +/** + * Form-encode the token and post those parameters to your backend URL. + * + * @param url the URL to upload the token details to + * @param params optional parameters to additionally include in the POST body + * @param handler code to execute with your server's response + * @deprecated you should write your own networking code to talk to your server. + */ +- (void)postToURL:(stp_nonnull NSURL *)url withParams:(stp_nullable NSDictionary *)params completion:(stp_nullable STPCardServerResponseCallback)handler __attribute((deprecated)); + +@end + +// This method is used internally by Stripe to deserialize API responses and exposed here for convenience and testing purposes only. You should not use it in +// your own code. +@interface STPToken (PrivateMethods) + +- (stp_nonnull instancetype)initWithAttributeDictionary:(stp_nonnull NSDictionary *)attributeDictionary; + +@end diff --git a/Frameworks/Stripe/PublicHeaders/Stripe.h b/Frameworks/Stripe/PublicHeaders/Stripe.h new file mode 100755 index 00000000..2b4ece18 --- /dev/null +++ b/Frameworks/Stripe/PublicHeaders/Stripe.h @@ -0,0 +1,24 @@ +// +// Stripe.h +// Stripe +// +// Created by Saikat Chakrabarti on 10/30/12. +// Copyright (c) 2012 Stripe. All rights reserved. +// + +#import "STPAPIClient.h" +#import "StripeError.h" +#import "STPBankAccount.h" +#import "STPCard.h" +#import "STPToken.h" +#import "STPNullabilityMacros.h" + +#if __has_include("STPCheckoutOptions.h") +#import "STPCheckoutOptions.h" +#import "STPCheckoutViewController.h" +#endif + +#if __has_include("Stripe+ApplePay.h") && TARGET_OS_IPHONE +#import "Stripe+ApplePay.h" +#import "STPAPIClient+ApplePay.h" +#endif diff --git a/Frameworks/Stripe/PublicHeaders/StripeError.h b/Frameworks/Stripe/PublicHeaders/StripeError.h new file mode 100755 index 00000000..cd9d791f --- /dev/null +++ b/Frameworks/Stripe/PublicHeaders/StripeError.h @@ -0,0 +1,66 @@ +// +// StripeError.h +// Stripe +// +// Created by Saikat Chakrabarti on 11/4/12. +// +// + +#import +#import "STPNullabilityMacros.h" + +/** + * All Stripe iOS errors will be under this domain. + */ +FOUNDATION_EXPORT NSString * __stp_nonnull const StripeDomain; + +typedef NS_ENUM(NSInteger, STPErrorCode) { + STPConnectionError = 40, // Trouble connecting to Stripe. + STPInvalidRequestError = 50, // Your request had invalid parameters. + STPAPIError = 60, // General-purpose API error (should be rare). + STPCardError = 70, // Something was wrong with the given card (most common). + STPCheckoutError = 80, // Stripe Checkout encountered an error. +}; + +#pragma mark userInfo keys + +// A developer-friendly error message that explains what went wrong. You probably +// shouldn't show this to your users, but might want to use it yourself. +FOUNDATION_EXPORT NSString * __stp_nonnull const STPErrorMessageKey; + +// What went wrong with your STPCard (e.g., STPInvalidCVC. See below for full list). +FOUNDATION_EXPORT NSString * __stp_nonnull const STPCardErrorCodeKey; + +// Which parameter on the STPCard had an error (e.g., "cvc"). Useful for marking up the +// right UI element. +FOUNDATION_EXPORT NSString * __stp_nonnull const STPErrorParameterKey; + +#pragma mark STPCardErrorCodeKeys + +// (Usually determined locally:) +FOUNDATION_EXPORT NSString * __stp_nonnull const STPInvalidNumber; +FOUNDATION_EXPORT NSString * __stp_nonnull const STPInvalidExpMonth; +FOUNDATION_EXPORT NSString * __stp_nonnull const STPInvalidExpYear; +FOUNDATION_EXPORT NSString * __stp_nonnull const STPInvalidCVC; + +// (Usually sent from the server:) +FOUNDATION_EXPORT NSString * __stp_nonnull const STPIncorrectNumber; +FOUNDATION_EXPORT NSString * __stp_nonnull const STPExpiredCard; +FOUNDATION_EXPORT NSString * __stp_nonnull const STPCardDeclined; +FOUNDATION_EXPORT NSString * __stp_nonnull const STPProcessingError; +FOUNDATION_EXPORT NSString * __stp_nonnull const STPIncorrectCVC; + +#pragma mark Strings + +#define STPCardErrorInvalidNumberUserMessage NSLocalizedString(@"Your card's number is invalid", @"Error when the card number is not valid") +#define STPCardErrorInvalidCVCUserMessage NSLocalizedString(@"Your card's security code is invalid", @"Error when the card's CVC is not valid") +#define STPCardErrorInvalidExpMonthUserMessage \ + NSLocalizedString(@"Your card's expiration month is invalid", @"Error when the card's expiration month is not valid") +#define STPCardErrorInvalidExpYearUserMessage \ + NSLocalizedString(@"Your card's expiration year is invalid", @"Error when the card's expiration year is not valid") +#define STPCardErrorExpiredCardUserMessage NSLocalizedString(@"Your card has expired", @"Error when the card has already expired") +#define STPCardErrorDeclinedUserMessage NSLocalizedString(@"Your card was declined", @"Error when the card was declined by the credit card networks") +#define STPUnexpectedError \ + NSLocalizedString(@"There was an unexpected error -- try again in a few seconds", @"Unexpected error, such as a 500 from Stripe or a JSON parse error") +#define STPCardErrorProcessingErrorUserMessage \ + NSLocalizedString(@"There was an error processing your card -- try again in a few seconds", @"Error when there is a problem processing the credit card") diff --git a/Frameworks/Stripe/STPAPIClient.m b/Frameworks/Stripe/STPAPIClient.m new file mode 100755 index 00000000..ef3622e6 --- /dev/null +++ b/Frameworks/Stripe/STPAPIClient.m @@ -0,0 +1,309 @@ +// +// STPAPIClient.m +// StripeExample +// +// Created by Jack Flintermann on 12/18/14. +// Copyright (c) 2014 Stripe. All rights reserved. +// + +#import +#if TARGET_OS_IPHONE +#import +#import +#endif + +#import "STPAPIClient.h" +#import "STPAPIConnection.h" +#import "STPFormEncoder.h" +#import "STPBankAccount.h" +#import "STPCard.h" +#import "STPToken.h" +#import "StripeError.h" + +static NSString *const apiURLBase = @"api.stripe.com"; +static NSString *const apiVersion = @"v1"; +static NSString *const tokenEndpoint = @"tokens"; +static NSString *STPDefaultPublishableKey; +static char kAssociatedClientKey; + +@implementation Stripe + ++ (void)setDefaultPublishableKey:(NSString *)publishableKey { + STPDefaultPublishableKey = publishableKey; +} + ++ (NSString *)defaultPublishableKey { + return STPDefaultPublishableKey; +} + +@end + +@interface STPAPIClient () +@property (nonatomic, readwrite) NSURL *apiURL; +@end + +@implementation STPAPIClient + ++ (instancetype)sharedClient { + static id sharedClient; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ sharedClient = [[self alloc] init]; }); + return sharedClient; +} + +- (instancetype)init { + return [self initWithPublishableKey:[Stripe defaultPublishableKey]]; +} + +- (instancetype)initWithPublishableKey:(NSString *)publishableKey { + self = [super init]; + if (self) { + [self.class validateKey:publishableKey]; + _apiURL = [[[NSURL URLWithString:[NSString stringWithFormat:@"https://%@", apiURLBase]] URLByAppendingPathComponent:apiVersion] + URLByAppendingPathComponent:tokenEndpoint]; + _publishableKey = [publishableKey copy]; + _operationQueue = [NSOperationQueue mainQueue]; + } + return self; +} + +- (void)setOperationQueue:(NSOperationQueue *)operationQueue { + NSCAssert(operationQueue, @"Operation queue cannot be nil."); + _operationQueue = operationQueue; +} + +- (void)createTokenWithData:(NSData *)data completion:(STPCompletionBlock)completion { + NSCAssert(data != nil, @"'data' is required to create a token"); + NSCAssert(completion != nil, @"'completion' is required to use the token that is created"); + + NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:self.apiURL]; + request.HTTPMethod = @"POST"; + request.HTTPBody = data; + [request setValue:[self.class JSONStringForObject:[self.class stripeUserAgentDetails]] forHTTPHeaderField:@"X-Stripe-User-Agent"]; + [request setValue:[@"Bearer " stringByAppendingString:self.publishableKey] forHTTPHeaderField:@"Authorization"]; + + STPAPIConnection *connection = [[STPAPIConnection alloc] initWithRequest:request]; + + // use the runtime to ensure we're not dealloc'ed before completion + objc_setAssociatedObject(connection, &kAssociatedClientKey, self, OBJC_ASSOCIATION_RETAIN); + + [connection runOnOperationQueue:self.operationQueue + completion:^(NSURLResponse *response, NSData *body, NSError *requestError) { + if (requestError) { + // If this is an error that Stripe returned, let's handle it as a StripeDomain error + if (body) { + NSDictionary *jsonDictionary = [NSJSONSerialization JSONObjectWithData:body options:0 error:NULL]; + if ([jsonDictionary valueForKey:@"error"] != nil) { + completion(nil, [self.class errorFromStripeResponse:jsonDictionary]); + return; + } + } + completion(nil, requestError); + return; + } else { + NSDictionary *jsonDictionary = [NSJSONSerialization JSONObjectWithData:body options:0 error:NULL]; + if (!jsonDictionary) { + NSDictionary *userInfo = @{ + NSLocalizedDescriptionKey: STPUnexpectedError, + STPErrorMessageKey: @"The response from Stripe failed to get parsed into valid JSON." + }; + NSError *error = [[NSError alloc] initWithDomain:StripeDomain code:STPAPIError userInfo:userInfo]; + completion(nil, error); + } else if ([(NSHTTPURLResponse *)response statusCode] == 200) { + completion([[STPToken alloc] initWithAttributeDictionary:jsonDictionary], nil); + } else { + completion(nil, [self.class errorFromStripeResponse:jsonDictionary]); + } + } + // at this point it's safe to be dealloced + objc_setAssociatedObject(connection, &kAssociatedClientKey, nil, OBJC_ASSOCIATION_RETAIN); + }]; +} + +#pragma mark - private helpers + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-variable" ++ (void)validateKey:(NSString *)publishableKey { + NSCAssert(publishableKey != nil && ![publishableKey isEqualToString:@""], + @"You must use a valid publishable key to create a token. For more info, see https://stripe.com/docs/stripe.js"); + BOOL secretKey = [publishableKey hasPrefix:@"sk_"]; + NSCAssert(!secretKey, + @"You are using a secret key to create a token, instead of the publishable one. For more info, see https://stripe.com/docs/stripe.js"); +#ifndef DEBUG + if ([publishableKey.lowercaseString hasPrefix:@"pk_test"]) { + NSLog(@"⚠️ Warning! You're building your app in a non-debug configuration, but appear to be using your Stripe test key. Make sure not to submit to " + @"the App Store with your test keys!⚠️"); + } +#endif +} +#pragma clang diagnostic pop + ++ (NSError *)errorFromStripeResponse:(NSDictionary *)jsonDictionary { + NSDictionary *errorDictionary = jsonDictionary[@"error"]; + NSString *type = errorDictionary[@"type"]; + NSString *devMessage = errorDictionary[@"message"]; + NSString *parameter = errorDictionary[@"param"]; + NSInteger code = 0; + + // There should always be a message and type for the error + if (devMessage == nil || type == nil) { + NSDictionary *userInfo = @{ + NSLocalizedDescriptionKey: STPUnexpectedError, + STPErrorMessageKey: @"Could not interpret the error response that was returned from Stripe." + }; + return [[NSError alloc] initWithDomain:StripeDomain code:STPAPIError userInfo:userInfo]; + } + + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + userInfo[STPErrorMessageKey] = devMessage; + + if (parameter) { + userInfo[STPErrorParameterKey] = [STPFormEncoder stringByReplacingSnakeCaseWithCamelCase:parameter]; + } + + if ([type isEqualToString:@"api_error"]) { + code = STPAPIError; + userInfo[NSLocalizedDescriptionKey] = STPUnexpectedError; + } else if ([type isEqualToString:@"invalid_request_error"]) { + code = STPInvalidRequestError; + userInfo[NSLocalizedDescriptionKey] = devMessage; + } else if ([type isEqualToString:@"card_error"]) { + code = STPCardError; + NSDictionary *errorCodes = @{ + @"incorrect_number": @{@"code": STPIncorrectNumber, @"message": STPCardErrorInvalidNumberUserMessage}, + @"invalid_number": @{@"code": STPInvalidNumber, @"message": STPCardErrorInvalidNumberUserMessage}, + @"invalid_expiry_month": @{@"code": STPInvalidExpMonth, @"message": STPCardErrorInvalidExpMonthUserMessage}, + @"invalid_expiry_year": @{@"code": STPInvalidExpYear, @"message": STPCardErrorInvalidExpYearUserMessage}, + @"invalid_cvc": @{@"code": STPInvalidCVC, @"message": STPCardErrorInvalidCVCUserMessage}, + @"expired_card": @{@"code": STPExpiredCard, @"message": STPCardErrorExpiredCardUserMessage}, + @"incorrect_cvc": @{@"code": STPIncorrectCVC, @"message": STPCardErrorInvalidCVCUserMessage}, + @"card_declined": @{@"code": STPCardDeclined, @"message": STPCardErrorDeclinedUserMessage}, + @"processing_error": @{@"code": STPProcessingError, @"message": STPCardErrorProcessingErrorUserMessage}, + }; + NSDictionary *codeMapEntry = errorCodes[errorDictionary[@"code"]]; + + if (codeMapEntry) { + userInfo[STPCardErrorCodeKey] = codeMapEntry[@"code"]; + userInfo[NSLocalizedDescriptionKey] = codeMapEntry[@"message"]; + } else { + userInfo[STPCardErrorCodeKey] = errorDictionary[@"code"]; + userInfo[NSLocalizedDescriptionKey] = devMessage; + } + } + + return [[NSError alloc] initWithDomain:StripeDomain code:code userInfo:userInfo]; +} + +#pragma mark Utility methods - + ++ (NSDictionary *)stripeUserAgentDetails { + NSMutableDictionary *details = [@{ + @"lang": @"objective-c", + @"bindings_version": STPSDKVersion, + } mutableCopy]; +#if TARGET_OS_IPHONE + NSString *version = [UIDevice currentDevice].systemVersion; + if (version) { + details[@"os_version"] = version; + } + struct utsname systemInfo; + uname(&systemInfo); + NSString *deviceType = @(systemInfo.machine); + if (deviceType) { + details[@"type"] = deviceType; + } + NSString *model = [UIDevice currentDevice].localizedModel; + if (model) { + details[@"model"] = model; + } + if ([[UIDevice currentDevice] respondsToSelector:@selector(identifierForVendor)]) { + NSString *vendorIdentifier = [[[UIDevice currentDevice] performSelector:@selector(identifierForVendor)] performSelector:@selector(UUIDString)]; + if (vendorIdentifier) { + details[@"vendor_identifier"] = vendorIdentifier; + } + } +#endif + return [details copy]; +} + ++ (NSString *)JSONStringForObject:(id)object { + return [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:object options:0 error:NULL] encoding:NSUTF8StringEncoding]; +} + +@end + +#pragma mark - Bank Accounts +@implementation STPAPIClient (BankAccounts) + +- (void)createTokenWithBankAccount:(STPBankAccount *)bankAccount completion:(STPCompletionBlock)completion { + [self createTokenWithData:[STPFormEncoder formEncodedDataForBankAccount:bankAccount] completion:completion]; +} + +@end + +#pragma mark - Credit Cards +@implementation STPAPIClient (CreditCards) + +- (void)createTokenWithCard:(STPCard *)card completion:(STPCompletionBlock)completion { + [self createTokenWithData:[STPFormEncoder formEncodedDataForCard:card] completion:completion]; +} + +@end + +@implementation Stripe (Deprecated) + ++ (id)alloc { + NSCAssert(NO, @"'Stripe' is a static class and cannot be instantiated."); + return nil; +} + ++ (void)createTokenWithCard:(STPCard *)card + publishableKey:(NSString *)publishableKey + operationQueue:(NSOperationQueue *)queue + completion:(STPCompletionBlock)handler { + NSCAssert(card != nil, @"'card' is required to create a token"); + STPAPIClient *client = [[STPAPIClient alloc] initWithPublishableKey:publishableKey]; + client.operationQueue = queue; + [client createTokenWithCard:card completion:handler]; +} + ++ (void)createTokenWithBankAccount:(STPBankAccount *)bankAccount + publishableKey:(NSString *)publishableKey + operationQueue:(NSOperationQueue *)queue + completion:(STPCompletionBlock)handler { + NSCAssert(bankAccount != nil, @"'bankAccount' is required to create a token"); + NSCAssert(handler != nil, @"'handler' is required to use the token that is created"); + + STPAPIClient *client = [[STPAPIClient alloc] initWithPublishableKey:publishableKey]; + client.operationQueue = queue; + [client createTokenWithBankAccount:bankAccount completion:handler]; +} + +#pragma mark Shorthand methods - + ++ (void)createTokenWithCard:(STPCard *)card completion:(STPCompletionBlock)handler { + [self createTokenWithCard:card publishableKey:[self defaultPublishableKey] completion:handler]; +} + ++ (void)createTokenWithCard:(STPCard *)card publishableKey:(NSString *)publishableKey completion:(STPCompletionBlock)handler { + [self createTokenWithCard:card publishableKey:publishableKey operationQueue:[NSOperationQueue mainQueue] completion:handler]; +} + ++ (void)createTokenWithCard:(STPCard *)card operationQueue:(NSOperationQueue *)queue completion:(STPCompletionBlock)handler { + [self createTokenWithCard:card publishableKey:[self defaultPublishableKey] operationQueue:queue completion:handler]; +} + ++ (void)createTokenWithBankAccount:(STPBankAccount *)bankAccount completion:(STPCompletionBlock)handler { + [self createTokenWithBankAccount:bankAccount publishableKey:[self defaultPublishableKey] completion:handler]; +} + ++ (void)createTokenWithBankAccount:(STPBankAccount *)bankAccount publishableKey:(NSString *)publishableKey completion:(STPCompletionBlock)handler { + [self createTokenWithBankAccount:bankAccount publishableKey:publishableKey operationQueue:[NSOperationQueue mainQueue] completion:handler]; +} + ++ (void)createTokenWithBankAccount:(STPBankAccount *)bankAccount operationQueue:(NSOperationQueue *)queue completion:(STPCompletionBlock)handler { + [self createTokenWithBankAccount:bankAccount publishableKey:[self defaultPublishableKey] operationQueue:queue completion:handler]; +} + +@end diff --git a/Frameworks/Stripe/STPAPIConnection.h b/Frameworks/Stripe/STPAPIConnection.h new file mode 100755 index 00000000..a1dc3b63 --- /dev/null +++ b/Frameworks/Stripe/STPAPIConnection.h @@ -0,0 +1,28 @@ +// +// STPAPIConnection.h +// Stripe +// +// Created by Jack Flintermann on 1/8/15. +// Copyright (c) 2015 Stripe, Inc. All rights reserved. +// + +#import +#import "STPNullabilityMacros.h" + +typedef void (^STPAPIConnectionCompletionBlock)(NSURLResponse * __stp_nullable response, NSData * __stp_nullable body, NSError * __stp_nullable requestError); + +// Like NSURLConnection but verifies that the server isn't using a revoked certificate. +@interface STPAPIConnection : NSObject + +- (stp_nonnull instancetype)initWithRequest:(stp_nonnull NSURLRequest *)request; +- (void)runOnOperationQueue:(stp_nonnull NSOperationQueue *)queue completion:(stp_nullable STPAPIConnectionCompletionBlock)handler; + +@property (nonatomic) BOOL started; +@property (nonatomic, copy, stp_nonnull) NSURLRequest *request; +@property (nonatomic, strong, stp_nullable) NSURLConnection *connection; +@property (nonatomic, strong, stp_nullable) NSMutableData *receivedData; +@property (nonatomic, strong, stp_nullable) NSURLResponse *receivedResponse; +@property (nonatomic, strong, stp_nullable) NSError *overrideError; // Replaces the request's error +@property (nonatomic, copy, stp_nullable) STPAPIConnectionCompletionBlock completionBlock; + +@end diff --git a/Frameworks/Stripe/STPAPIConnection.m b/Frameworks/Stripe/STPAPIConnection.m new file mode 100755 index 00000000..23af28de --- /dev/null +++ b/Frameworks/Stripe/STPAPIConnection.m @@ -0,0 +1,77 @@ +// +// STPAPIConnection.m +// Stripe +// +// Created by Jack Flintermann on 1/8/15. +// Copyright (c) 2015 Stripe, Inc. All rights reserved. +// + +#import "STPAPIConnection.h" +#import "STPAPIClient.h" +#import "StripeError.h" +#import + +@implementation STPAPIConnection + +- (instancetype)initWithRequest:(NSURLRequest *)request { + if (self = [super init]) { + _request = request; + _connection = [[NSURLConnection alloc] initWithRequest:_request delegate:self startImmediately:NO]; + _receivedData = [[NSMutableData alloc] init]; + } + return self; +} + +- (void)runOnOperationQueue:(NSOperationQueue *)queue completion:(STPAPIConnectionCompletionBlock)handler { + NSCAssert(!self.started, @"This API connection has already started."); + NSCAssert(queue, @"'queue' is required"); + NSCAssert(handler, @"'handler' is required"); + + self.started = YES; + self.completionBlock = handler; + [self.connection setDelegateQueue:queue]; + [self.connection start]; +} + +#pragma mark NSURLConnectionDataDelegate + +- (void)connection:(__unused NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { + self.receivedResponse = response; +} + +- (void)connection:(__unused NSURLConnection *)connection didReceiveData:(NSData *)data { + [self.receivedData appendData:data]; +} + +- (void)connectionDidFinishLoading:(__unused NSURLConnection *)connection { + self.connection = nil; + self.completionBlock(self.receivedResponse, self.receivedData, nil); + self.receivedData = nil; + self.receivedResponse = nil; +} + +#pragma mark NSURLConnectionDelegate + +- (void)connection:(__unused NSURLConnection *)connection didFailWithError:(NSError *)error { + self.connection = nil; + self.receivedData = nil; + self.receivedResponse = nil; + self.completionBlock(self.receivedResponse, self.receivedData, self.overrideError ?: error); +} + +- (void)connection:(__unused NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { + if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { + SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust]; + SecTrustResultType resultType; + SecTrustEvaluate(serverTrust, &resultType); + [challenge.sender performDefaultHandlingForAuthenticationChallenge:challenge]; + } else if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodDefault]) { + // If this is an HTTP Authorization request, just continue. We want to bubble this back through the + // request's error handler. + [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge]; + } else { + [challenge.sender performDefaultHandlingForAuthenticationChallenge:challenge]; + } +} + +@end diff --git a/Frameworks/Stripe/STPBankAccount.m b/Frameworks/Stripe/STPBankAccount.m new file mode 100755 index 00000000..fd92b8e6 --- /dev/null +++ b/Frameworks/Stripe/STPBankAccount.m @@ -0,0 +1,88 @@ +// +// STPBankAccount.m +// Stripe +// +// Created by Charles Scalesse on 10/1/14. +// +// + +#import "STPBankAccount.h" + +@interface STPBankAccount () + +@property (nonatomic, readwrite) NSString *bankAccountId; +@property (nonatomic, readwrite) NSString *last4; +@property (nonatomic, readwrite) NSString *bankName; +@property (nonatomic, readwrite) NSString *fingerprint; +@property (nonatomic, readwrite) BOOL validated; +@property (nonatomic, readwrite) BOOL disabled; + +@end + +@implementation STPBankAccount + +#pragma mark - Getters + +- (NSString *)last4 { + if (_last4) { + return _last4; + } else if (self.accountNumber && self.accountNumber.length >= 4) { + return [self.accountNumber substringFromIndex:(self.accountNumber.length - 4)]; + } else { + return nil; + } +} + +#pragma mark - Equality + +- (BOOL)isEqual:(STPBankAccount *)bankAccount { + return [self isEqualToBankAccount:bankAccount]; +} + +- (NSUInteger)hash { + return [self.fingerprint hash]; +} + +- (BOOL)isEqualToBankAccount:(STPBankAccount *)bankAccount { + if (self == bankAccount) { + return YES; + } + + if (!bankAccount || ![bankAccount isKindOfClass:self.class]) { + return NO; + } + + return [self.accountNumber ?: @"" isEqualToString:bankAccount.accountNumber ?: @""] && + [self.routingNumber ?: @"" isEqualToString:bankAccount.routingNumber ?: @""] && + [self.country ?: @"" isEqualToString:bankAccount.country ?: @""] && [self.last4 ?: @"" isEqualToString:bankAccount.last4 ?: @""] && + [self.bankName ?: @"" isEqualToString:bankAccount.bankName ?: @""] && [self.currency ?: @"" isEqualToString:bankAccount.currency ?: @""]; +} + +@end + +@implementation STPBankAccount (PrivateMethods) + +- (instancetype)initWithAttributeDictionary:(NSDictionary *)attributeDictionary { + self = [self init]; + if (self) { + // sanitize NSNull + NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; + [attributeDictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, __unused BOOL *stop) { + if (obj != [NSNull null]) { + dictionary[key] = obj; + } + }]; + + _bankAccountId = dictionary[@"id"]; + _last4 = dictionary[@"last4"]; + _bankName = dictionary[@"bank_name"]; + _country = dictionary[@"country"]; + _fingerprint = dictionary[@"fingerprint"]; + _currency = dictionary[@"currency"]; + _validated = [dictionary[@"validated"] boolValue]; + _disabled = [dictionary[@"disabled"] boolValue]; + } + return self; +} + +@end diff --git a/Frameworks/Stripe/STPCard.m b/Frameworks/Stripe/STPCard.m new file mode 100755 index 00000000..6a194752 --- /dev/null +++ b/Frameworks/Stripe/STPCard.m @@ -0,0 +1,387 @@ +// +// STPCard.m +// Stripe +// +// Created by Saikat Chakrabarti on 11/2/12. +// +// + +#import "STPCard.h" +#import "StripeError.h" + +@interface STPCard () + +@property (nonatomic, readwrite) NSString *cardId; +@property (nonatomic, readwrite) NSString *last4; +@property (nonatomic, readwrite) STPCardBrand brand; +@property (nonatomic, readwrite) STPCardFundingType funding; +@property (nonatomic, readwrite) NSString *fingerprint; +@property (nonatomic, readwrite) NSString *country; + +@end + +@implementation STPCard + +- (instancetype)init { + self = [super init]; + if (self) { + _brand = STPCardBrandUnknown; + _funding = STPCardFundingTypeOther; + } + + return self; +} + +- (NSString *)last4 { + if (_last4) { + return _last4; + } else if (self.number && self.number.length >= 4) { + return [self.number substringFromIndex:(self.number.length - 4)]; + } else { + return nil; + } +} + +- (STPCardBrand)brand { + if (_brand == STPCardBrandUnknown) { + return [self.class cardTypeFromNumber:self.number]; + } + return _brand; +} + +- (NSString *)type { + switch (self.brand) { + case STPCardBrandAmex: + return @"American Express"; + case STPCardBrandDinersClub: + return @"Diners Club"; + case STPCardBrandDiscover: + return @"Discover"; + case STPCardBrandJCB: + return @"JCB"; + case STPCardBrandMasterCard: + return @"MasterCard"; + case STPCardBrandVisa: + return @"Visa"; + default: + return @"Unknown"; + } +} + +- (BOOL)validateNumber:(id *)ioValue error:(NSError **)outError { + if (*ioValue == nil) { + return [STPCard handleValidationErrorForParameter:@"number" error:outError]; + } + + NSString *ioValueString = (NSString *)*ioValue; + NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"[\\s+|-]" options:NSRegularExpressionCaseInsensitive error:NULL]; + + NSString *rawNumber = [regex stringByReplacingMatchesInString:ioValueString options:0 range:NSMakeRange(0, [ioValueString length]) withTemplate:@""]; + + if (rawNumber == nil || rawNumber.length < 10 || rawNumber.length > 19 || ![STPCard isLuhnValidString:rawNumber]) { + return [STPCard handleValidationErrorForParameter:@"number" error:outError]; + } + return YES; +} + +- (BOOL)validateCvc:(id *)ioValue error:(NSError **)outError { + if (*ioValue == nil) { + return [STPCard handleValidationErrorForParameter:@"number" error:outError]; + } + NSString *cvc = [(NSString *)*ioValue stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; + BOOL validCvcLength = ({ + BOOL valid; + switch (self.brand) { + case STPCardBrandAmex: + case STPCardBrandUnknown: + valid = (cvc.length == 3 || cvc.length == 4); + break; + default: + valid = (cvc.length == 3); + break; + } + valid; + }); + + if (![STPCard isNumericOnlyString:cvc] || !validCvcLength) { + return [STPCard handleValidationErrorForParameter:@"cvc" error:outError]; + } + return YES; +} + +- (BOOL)validateExpMonth:(id *)ioValue error:(NSError **)outError { + if (*ioValue == nil) { + return [STPCard handleValidationErrorForParameter:@"expMonth" error:outError]; + } + + NSString *ioValueString = [(NSString *)*ioValue stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; + NSInteger expMonthInt = [ioValueString integerValue]; + + if ((![STPCard isNumericOnlyString:ioValueString] || expMonthInt > 12 || expMonthInt < 1)) { + return [STPCard handleValidationErrorForParameter:@"expMonth" error:outError]; + } else if ([self expYear] && [STPCard isExpiredMonth:expMonthInt andYear:[self expYear] atDate:[NSDate date]]) { + NSUInteger currentYear = [STPCard currentYear]; + // If the year is in the past, this is actually a problem with the expYear parameter, but it still means this month is not a valid month. This is pretty + // rare - it means someone set expYear on the card without validating it + if (currentYear > [self expYear]) { + return [STPCard handleValidationErrorForParameter:@"expYear" error:outError]; + } else { + return [STPCard handleValidationErrorForParameter:@"expMonth" error:outError]; + } + } + return YES; +} + +- (BOOL)validateExpYear:(id *)ioValue error:(NSError **)outError { + if (*ioValue == nil) { + return [STPCard handleValidationErrorForParameter:@"expYear" error:outError]; + } + + NSString *ioValueString = [(NSString *)*ioValue stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; + NSInteger expYearInt = [ioValueString integerValue]; + + if ((![STPCard isNumericOnlyString:ioValueString] || expYearInt < [STPCard currentYear])) { + return [STPCard handleValidationErrorForParameter:@"expYear" error:outError]; + } else if ([self expMonth] && [STPCard isExpiredMonth:[self expMonth] andYear:expYearInt atDate:[NSDate date]]) { + return [STPCard handleValidationErrorForParameter:@"expMonth" error:outError]; + } + + return YES; +} + +- (BOOL)validateCardReturningError:(NSError **)outError { + // Order matters here + NSString *numberRef = [self number]; + NSString *expMonthRef = [NSString stringWithFormat:@"%lu", (unsigned long)[self expMonth]]; + NSString *expYearRef = [NSString stringWithFormat:@"%lu", (unsigned long)[self expYear]]; + NSString *cvcRef = [self cvc]; + + // Make sure expMonth, expYear, and number are set. Validate CVC if it is provided + return [self validateNumber:&numberRef error:outError] && [self validateExpYear:&expYearRef error:outError] && + [self validateExpMonth:&expMonthRef error:outError] && (cvcRef == nil || [self validateCvc:&cvcRef error:outError]); +} + +- (BOOL)isEqual:(id)other { + return [self isEqualToCard:other]; +} + +- (NSUInteger)hash { + return [self.fingerprint hash] ?: [self.number hash]; +} + +- (BOOL)isEqualToCard:(STPCard *)other { + if (self == other) { + return YES; + } + + if (!other || ![other isKindOfClass:self.class]) { + return NO; + } + + return self.expMonth == other.expMonth && self.expYear == other.expYear && [self.number ?: @"" isEqualToString:other.number ?: @""] && + [self.cvc ?: @"" isEqualToString:other.cvc ?: @""] && [self.name ?: @"" isEqualToString:other.name ?: @""] && + [self.addressLine1 ?: @"" isEqualToString:other.addressLine1 ?: @""] && [self.addressLine2 ?: @"" isEqualToString:other.addressLine2 ?: @""] && + [self.addressCity ?: @"" isEqualToString:other.addressCity ?: @""] && [self.addressState ?: @"" isEqualToString:other.addressState ?: @""] && + [self.addressZip ?: @"" isEqualToString:other.addressZip ?: @""] && [self.addressCountry ?: @"" isEqualToString:other.addressCountry ?: @""]; +} + +#pragma mark Private Helpers ++ (BOOL)isLuhnValidString:(NSString *)number { + BOOL isOdd = true; + NSInteger sum = 0; + + NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init]; + for (NSInteger index = [number length] - 1; index >= 0; index--) { + NSString *digit = [number substringWithRange:NSMakeRange(index, 1)]; + NSNumber *digitNumber = [numberFormatter numberFromString:digit]; + + if (digitNumber == nil) { + return NO; + } + + NSInteger digitInteger = [digitNumber intValue]; + isOdd = !isOdd; + if (isOdd) { + digitInteger *= 2; + } + + if (digitInteger > 9) { + digitInteger -= 9; + } + + sum += digitInteger; + } + + return sum % 10 == 0; +} + ++ (BOOL)isNumericOnlyString:(NSString *)aString { + NSCharacterSet *numericOnly = [NSCharacterSet decimalDigitCharacterSet]; + NSCharacterSet *aStringSet = [NSCharacterSet characterSetWithCharactersInString:aString]; + + return [numericOnly isSupersetOfSet:aStringSet]; +} + ++ (NSCalendar *)gregorianCalendar { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated" +#pragma clang diagnostic ignored "-Wunreachable-code" +#pragma clang diagnostic ignored "-Wtautological-compare" + NSString *identifier = (&NSCalendarIdentifierGregorian != nil) ? NSCalendarIdentifierGregorian : NSGregorianCalendar; +#pragma clang diagnostic pop + return [[NSCalendar alloc] initWithCalendarIdentifier:identifier]; +} + ++ (BOOL)isExpiredMonth:(NSInteger)month andYear:(NSInteger)year atDate:(NSDate *)date { + NSDateComponents *components = [[NSDateComponents alloc] init]; + [components setYear:year]; + // Cards expire at end of month + [components setMonth:month + 1]; + [components setDay:1]; + NSDate *expiryDate = [[self gregorianCalendar] dateFromComponents:components]; + return ([expiryDate compare:date] == NSOrderedAscending); +} + ++ (NSInteger)currentYear { + NSDateComponents *components = [[self gregorianCalendar] components:NSCalendarUnitYear fromDate:[NSDate date]]; + return [components year]; +} + ++ (BOOL)handleValidationErrorForParameter:(NSString *)parameter error:(NSError **)outError { + if (outError != nil) { + if ([parameter isEqualToString:@"number"]) { + *outError = [self createErrorWithMessage:STPCardErrorInvalidNumberUserMessage + parameter:parameter + cardErrorCode:STPInvalidNumber + devErrorMessage:@"Card number must be between 10 and 19 digits long and Luhn valid."]; + } else if ([parameter isEqualToString:@"cvc"]) { + *outError = [self createErrorWithMessage:STPCardErrorInvalidCVCUserMessage + parameter:parameter + cardErrorCode:STPInvalidCVC + devErrorMessage:@"Card CVC must be numeric, 3 digits for Visa, Discover, MasterCard, JCB, and Discover cards, and 3 or 4 " + @"digits for American Express cards."]; + } else if ([parameter isEqualToString:@"expMonth"]) { + *outError = [self createErrorWithMessage:STPCardErrorInvalidExpMonthUserMessage + parameter:parameter + cardErrorCode:STPInvalidExpMonth + devErrorMessage:@"expMonth must be less than 13"]; + } else if ([parameter isEqualToString:@"expYear"]) { + *outError = [self createErrorWithMessage:STPCardErrorInvalidExpYearUserMessage + parameter:parameter + cardErrorCode:STPInvalidExpYear + devErrorMessage:@"expYear must be this year or a year in the future"]; + } else { + // This should not be possible since this is a private method so we + // know exactly how it is called. We use STPAPIError for all errors + // that are unexpected within the bindings as well. + *outError = [[NSError alloc] initWithDomain:StripeDomain + code:STPAPIError + userInfo:@{ + NSLocalizedDescriptionKey: STPUnexpectedError, + STPErrorMessageKey: @"There was an error within the Stripe client library when trying to generate the " + @"proper validation error. Contact support@stripe.com if you see this." + }]; + } + } + return NO; +} + ++ (NSError *)createErrorWithMessage:(NSString *)userMessage + parameter:(NSString *)parameter + cardErrorCode:(NSString *)cardErrorCode + devErrorMessage:(NSString *)devMessage { + return [[NSError alloc] initWithDomain:StripeDomain + code:STPCardError + userInfo:@{ + NSLocalizedDescriptionKey: userMessage, + STPErrorParameterKey: parameter, + STPCardErrorCodeKey: cardErrorCode, + STPErrorMessageKey: devMessage + }]; +} + ++ (STPCardBrand)cardTypeFromNumber:(NSString *)number { + if ([number hasPrefix:@"34"] || [number hasPrefix:@"37"]) { + return STPCardBrandAmex; + } else if ([number hasPrefix:@"60"] || [number hasPrefix:@"62"] || [number hasPrefix:@"64"] || [number hasPrefix:@"65"]) { + return STPCardBrandDiscover; + } else if ([number hasPrefix:@"35"]) { + return STPCardBrandJCB; + } else if ([number hasPrefix:@"30"] || [number hasPrefix:@"36"] || [number hasPrefix:@"38"] || [number hasPrefix:@"39"]) { + return STPCardBrandDinersClub; + } else if ([number hasPrefix:@"4"]) { + return STPCardBrandVisa; + } else if ([number hasPrefix:@"5"]) { + return STPCardBrandMasterCard; + } else { + return STPCardBrandUnknown; + } +} + +@end + + +@implementation STPCard(PrivateMethods) + +- (instancetype)initWithAttributeDictionary:(NSDictionary *)attributeDictionary { + self = [self init]; + + NSMutableDictionary *dict = [NSMutableDictionary dictionary]; + + [attributeDictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, __unused BOOL *stop) { + if (obj != [NSNull null]) { + dict[key] = obj; + } + }]; + + if (self) { + _cardId = dict[@"id"]; + _number = dict[@"number"]; + _cvc = dict[@"cvc"]; + _name = dict[@"name"]; + _last4 = dict[@"last4"]; + NSString *brand = dict[@"brand"] ?: dict[@"type"]; + if ([brand isEqualToString:@"Visa"]) { + _brand = STPCardBrandVisa; + } else if ([brand isEqualToString:@"American Express"]) { + _brand = STPCardBrandAmex; + } else if ([brand isEqualToString:@"MasterCard"]) { + _brand = STPCardBrandMasterCard; + } else if ([brand isEqualToString:@"Discover"]) { + _brand = STPCardBrandDiscover; + } else if ([brand isEqualToString:@"JCB"]) { + _brand = STPCardBrandJCB; + } else if ([brand isEqualToString:@"Diners Club"]) { + _brand = STPCardBrandDinersClub; + } else { + _brand = STPCardBrandUnknown; + } + NSString *funding = dict[@"funding"]; + if ([funding.lowercaseString isEqualToString:@"credit"]) { + _funding = STPCardFundingTypeCredit; + } else if ([funding.lowercaseString isEqualToString:@"debit"]) { + _funding = STPCardFundingTypeDebit; + } else if ([funding.lowercaseString isEqualToString:@"prepaid"]) { + _funding = STPCardFundingTypePrepaid; + } else { + _funding = STPCardFundingTypeOther; + } + _fingerprint = dict[@"fingerprint"]; + _country = dict[@"country"]; + // Support both camelCase and snake_case keys + _expMonth = [(dict[@"exp_month"] ?: dict[@"expMonth"])intValue]; + _expYear = [(dict[@"exp_year"] ?: dict[@"expYear"])intValue]; + _addressLine1 = dict[@"address_line1"] ?: dict[@"addressLine1"]; + _addressLine2 = dict[@"address_line2"] ?: dict[@"addressLine2"]; + _addressCity = dict[@"address_city"] ?: dict[@"addressCity"]; + _addressState = dict[@"address_state"] ?: dict[@"addressState"]; + _addressZip = dict[@"address_zip"] ?: dict[@"addressZip"]; + _addressCountry = dict[@"address_country"] ?: dict[@"addressCountry"]; + } + + return self; +} + +@end + + diff --git a/Frameworks/Stripe/STPFormEncoder.h b/Frameworks/Stripe/STPFormEncoder.h new file mode 100755 index 00000000..cfebb8fb --- /dev/null +++ b/Frameworks/Stripe/STPFormEncoder.h @@ -0,0 +1,24 @@ +// +// STPFormEncoder.h +// Stripe +// +// Created by Jack Flintermann on 1/8/15. +// Copyright (c) 2015 Stripe, Inc. All rights reserved. +// + +#import +#import "STPNullabilityMacros.h" + +@class STPBankAccount, STPCard; + +@interface STPFormEncoder : NSObject + ++ (stp_nonnull NSData *)formEncodedDataForBankAccount:(stp_nonnull STPBankAccount *)bankAccount; + ++ (stp_nonnull NSData *)formEncodedDataForCard:(stp_nonnull STPCard *)card; + ++ (stp_nonnull NSString *)stringByURLEncoding:(stp_nonnull NSString *)string; + ++ (stp_nonnull NSString *)stringByReplacingSnakeCaseWithCamelCase:(stp_nonnull NSString *)input; + +@end diff --git a/Frameworks/Stripe/STPFormEncoder.m b/Frameworks/Stripe/STPFormEncoder.m new file mode 100755 index 00000000..0983e7bf --- /dev/null +++ b/Frameworks/Stripe/STPFormEncoder.m @@ -0,0 +1,120 @@ +// +// STPFormEncoder.m +// Stripe +// +// Created by Jack Flintermann on 1/8/15. +// Copyright (c) 2015 Stripe, Inc. All rights reserved. +// + +#import "STPFormEncoder.h" +#import "STPBankAccount.h" +#import "STPCard.h" + +@implementation STPFormEncoder + ++ (NSData *)formEncodedDataForBankAccount:(STPBankAccount *)bankAccount { + NSCAssert(bankAccount != nil, @"Cannot create a token with a nil bank account."); + NSMutableDictionary *params = [NSMutableDictionary dictionary]; + NSMutableArray *parts = [NSMutableArray array]; + + if (bankAccount.accountNumber) { + params[@"account_number"] = bankAccount.accountNumber; + } + if (bankAccount.routingNumber) { + params[@"routing_number"] = bankAccount.routingNumber; + } + if (bankAccount.country) { + params[@"country"] = bankAccount.country; + } + if (bankAccount.currency) { + params[@"currency"] = bankAccount.currency; + } + + [params enumerateKeysAndObjectsUsingBlock:^(id key, id val, __unused BOOL *stop) { + [parts addObject:[NSString stringWithFormat:@"bank_account[%@]=%@", key, [self.class stringByURLEncoding:val]]]; + }]; + + return [[parts componentsJoinedByString:@"&"] dataUsingEncoding:NSUTF8StringEncoding]; +} + ++ (NSData *)formEncodedDataForCard:(STPCard *)card { + NSCAssert(card != nil, @"Cannot create a token with a nil card."); + NSMutableDictionary *params = [NSMutableDictionary dictionary]; + + if (card.number) { + params[@"number"] = card.number; + } + if (card.cvc) { + params[@"cvc"] = card.cvc; + } + if (card.name) { + params[@"name"] = card.name; + } + if (card.addressLine1) { + params[@"address_line1"] = card.addressLine1; + } + if (card.addressLine2) { + params[@"address_line2"] = card.addressLine2; + } + if (card.addressCity) { + params[@"address_city"] = card.addressCity; + } + if (card.addressState) { + params[@"address_state"] = card.addressState; + } + if (card.addressZip) { + params[@"address_zip"] = card.addressZip; + } + if (card.addressCountry) { + params[@"address_country"] = card.addressCountry; + } + if (card.expMonth) { + params[@"exp_month"] = @(card.expMonth).stringValue; + } + if (card.expYear) { + params[@"exp_year"] = @(card.expYear).stringValue; + } + + NSMutableArray *parts = [NSMutableArray array]; + + [params enumerateKeysAndObjectsUsingBlock:^(id key, id val, __unused BOOL *stop) { + [parts addObject:[NSString stringWithFormat:@"card[%@]=%@", key, [self.class stringByURLEncoding:val]]]; + + }]; + + return [[parts componentsJoinedByString:@"&"] dataUsingEncoding:NSUTF8StringEncoding]; +} + +/* This code is adapted from the code by David DeLong in this StackOverflow post: + http://stackoverflow.com/questions/3423545/objective-c-iphone-percent-encode-a-string . It is protected under the terms of a Creative Commons + license: http://creativecommons.org/licenses/by-sa/3.0/ + */ ++ (NSString *)stringByURLEncoding:(NSString *)string { + NSMutableString *output = [NSMutableString string]; + const unsigned char *source = (const unsigned char *)[string UTF8String]; + NSInteger sourceLen = strlen((const char *)source); + for (int i = 0; i < sourceLen; ++i) { + const unsigned char thisChar = source[i]; + if (thisChar == ' ') { + [output appendString:@"+"]; + } else if (thisChar == '.' || thisChar == '-' || thisChar == '_' || thisChar == '~' || (thisChar >= 'a' && thisChar <= 'z') || + (thisChar >= 'A' && thisChar <= 'Z') || (thisChar >= '0' && thisChar <= '9')) { + [output appendFormat:@"%c", thisChar]; + } else { + [output appendFormat:@"%%%02X", thisChar]; + } + } + return output; +} + ++ (NSString *)stringByReplacingSnakeCaseWithCamelCase:(NSString *)input { + NSArray *parts = [input componentsSeparatedByString:@"_"]; + NSMutableString *camelCaseParam = [NSMutableString string]; + [parts enumerateObjectsUsingBlock:^(NSString *part, NSUInteger idx, __unused BOOL *stop) { + [camelCaseParam appendString:(idx == 0 ? part : [part capitalizedString])]; + }]; + + return [camelCaseParam copy]; +} + +@end diff --git a/Frameworks/Stripe/STPToken.m b/Frameworks/Stripe/STPToken.m new file mode 100755 index 00000000..712d4c8a --- /dev/null +++ b/Frameworks/Stripe/STPToken.m @@ -0,0 +1,85 @@ +// +// STPToken.m +// Stripe +// +// Created by Saikat Chakrabarti on 11/5/12. +// +// + +#import "STPToken.h" +#import "STPCard.h" +#import "STPBankAccount.h" + +@implementation STPToken + +- (instancetype)initWithAttributeDictionary:(NSDictionary *)attributeDictionary { + self = [super init]; + + if (self) { + _tokenId = attributeDictionary[@"id"] ?: @""; + _livemode = [attributeDictionary[@"livemode"] boolValue]; + _created = [NSDate dateWithTimeIntervalSince1970:[attributeDictionary[@"created"] doubleValue]]; + + NSDictionary *cardDictionary = attributeDictionary[@"card"]; + if (cardDictionary) { + _card = [[STPCard alloc] initWithAttributeDictionary:cardDictionary]; + } + + NSDictionary *bankAccountDictionary = attributeDictionary[@"bank_account"]; + if (bankAccountDictionary) { + _bankAccount = [[STPBankAccount alloc] initWithAttributeDictionary:bankAccountDictionary]; + } + } + + return self; +} + +- (NSString *)description { + NSString *token = self.tokenId ?: @"Unknown token"; + NSString *livemode = self.livemode ? @"live mode" : @"test mode"; + + return [NSString stringWithFormat:@"%@ (%@)", token, livemode]; +} + +- (void)postToURL:(NSURL *)url withParams:(NSMutableDictionary *)params completion:(STPCardServerResponseCallback)handler { + NSMutableString *body = [NSMutableString stringWithFormat:@"stripeToken=%@", self.tokenId]; + + [params enumerateKeysAndObjectsUsingBlock:^(id key, id obj, __unused BOOL *stop) { [body appendFormat:@"&%@=%@", key, obj]; }]; + + NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url]; + request.HTTPMethod = @"POST"; + request.HTTPBody = [body dataUsingEncoding:NSUTF8StringEncoding]; + + [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:handler]; +} + +- (BOOL)isEqual:(id)object { + return [self isEqualToToken:object]; +} + +- (NSUInteger)hash { + return [self.tokenId hash]; +} + +- (BOOL)isEqualToToken:(STPToken *)object { + if (self == object) { + return YES; + } + + if (!object || ![object isKindOfClass:self.class]) { + return NO; + } + + if ((self.card || object.card) && (![self.card isEqual:object.card])) { + return NO; + } + + if ((self.bankAccount || object.bankAccount) && (![self.bankAccount isEqual:object.bankAccount])) { + return NO; + } + + return self.livemode == object.livemode && [self.tokenId isEqualToString:object.tokenId] && [self.created isEqualToDate:object.created] && + [self.card isEqual:object.card] && [self.tokenId isEqualToString:object.tokenId] && [self.created isEqualToDate:object.created]; +} + +@end diff --git a/Frameworks/Stripe/StripeError.m b/Frameworks/Stripe/StripeError.m new file mode 100755 index 00000000..c66a7900 --- /dev/null +++ b/Frameworks/Stripe/StripeError.m @@ -0,0 +1,23 @@ +// +// StripeError.m +// Stripe +// +// Created by Saikat Chakrabarti on 11/4/12. +// +// + +#import "StripeError.h" + +NSString *const StripeDomain = @"com.stripe.lib"; +NSString *const STPCardErrorCodeKey = @"com.stripe.lib:CardErrorCodeKey"; +NSString *const STPErrorMessageKey = @"com.stripe.lib:ErrorMessageKey"; +NSString *const STPErrorParameterKey = @"com.stripe.lib:ErrorParameterKey"; +NSString *const STPInvalidNumber = @"com.stripe.lib:InvalidNumber"; +NSString *const STPInvalidExpMonth = @"com.stripe.lib:InvalidExpiryMonth"; +NSString *const STPInvalidExpYear = @"com.stripe.lib:InvalidExpiryYear"; +NSString *const STPInvalidCVC = @"com.stripe.lib:InvalidCVC"; +NSString *const STPIncorrectNumber = @"com.stripe.lib:IncorrectNumber"; +NSString *const STPExpiredCard = @"com.stripe.lib:ExpiredCard"; +NSString *const STPCardDeclined = @"com.stripe.lib:CardDeclined"; +NSString *const STPProcessingError = @"com.stripe.lib:ProcessingError"; +NSString *const STPIncorrectCVC = @"com.stripe.lib:IncorrectCVC"; diff --git a/README.md b/README.md new file mode 100644 index 00000000..372e702f --- /dev/null +++ b/README.md @@ -0,0 +1,191 @@ +# react-native-apple-pay + +[![npm version](https://img.shields.io/npm/v/react-native-apple-pay.svg?style=flat-square)](https://www.npmjs.com/package/react-native-apple-pay) +[![npm downloads](https://img.shields.io/npm/dm/react-native-apple-pay.svg?style=flat-square)](https://www.npmjs.com/package/react-native-apple-pay) +[![Code Climate](https://img.shields.io/codeclimate/github/naoufal/react-native-apple-pay.svg?style=flat-square)](https://codeclimate.com/github/naoufal/react-native-apple-pay) + +__`react-native-apple-pay`__ is a React Native library for accepting payments with Apple Pay. + +__Note: This library is still in progress.__ + +## Documentation +- [Install](https://github.com/naoufal/react-native-apple-pay#install) +- [Supported Payment Processors](https://github.com/naoufal/react-native-apple-pay#supported-payment-processors) +- [Methods](https://github.com/naoufal/react-native-apple-pay#methods) +- [License](https://github.com/naoufal/react-native-apple-pay#license) + +## Install +```shell +npm i --save react-native-apple-pay +``` + +## Supported Payment Processors +- [ ] Adyen +- [ ] Authorize.Net +- [ ] Bank of America Merchant Services +- [ ] Braintree +- [ ] Chase Paymentech +- [ ] CyberSource +- [ ] DataCash +- [ ] First Data +- [ ] Global Payments +- [ ] Judo Payments +- [ ] Simplify +- [x] Stripe +- [ ] TSYS +- [ ] Vantiv +- [ ] Worldpay + +## Methods + +### canMakePayments() +Checks if Apple Pay is available. + +__Example__ +```js + +ApplePay.canMakePayments() + .then(() => { + // Success code + }) + .catch(err => { + // Failure code + }); +``` + +--- + +### canMakePaymentsWithNetworks(supportedNetworks) +Checks if the user's card is supported by the merchant. + +__Arguments__ +- [`supportedNetworks`](https://developer.apple.com/library/ios/documentation/PassKit/Reference/PKPaymentRequest_Ref/#//apple_ref/doc/constant_group/Payment_Networks) - An `Array` of `Strings` representing the payment processing protocols you support. + +__Example__ +```js +var merchantOptions = { + paymentProcessor: 'stripe', + merchantIdentifier: 'merchant.yourapp.you', + supportedNetworks: ['PKPaymentNetworkMasterCard', 'PKPaymentNetworkVisa'], + merchantCapabilities: ['PKMerchantCapability3DS', 'PKMerchantCapabilityEMV'], + countryCode: 'US', + currencyCode: 'USD' +}; + +ApplePay.canMakePaymentsWithNetworks(merchantOptions.supportedNetworks) + .then(() => { + // Success code + }) + .catch(err => { + // Failure code + }); +``` + +--- + +### paymentRequest(merchantOptions, paymentItems) +Initializes Apple Pay. + +__Arguments__ +- `merchantOptions` - An `Object` that will be served to setup the payment request. +- `summaryItems` - An `Array` containing the items the customer will be purchasing. + +__merchantOptions__ +- `paymentProcessor` - A `String` representing your payment processor. +- `paymentProcessorPublicKey` - A `String` representing your public key. +- [`merchantIdentifier`](https://developer.apple.com/library/ios/documentation/PassKit/Reference/PKPaymentRequest_Ref/#//apple_ref/occ/instp/PKPaymentRequest/merchantIdentifier) - A `String` representing your merchant identifier. +- [`supportedNetworks`](https://developer.apple.com/library/ios/documentation/PassKit/Reference/PKPaymentRequest_Ref/#//apple_ref/doc/constant_group/Payment_Networks) - An `Array` of `Strings` representing the payment processing protocols you support. +- [`merchantCapabilities`](https://developer.apple.com/library/ios/documentation/PassKit/Reference/PKPaymentRequest_Ref/#//apple_ref/c/tdef/PKMerchantCapability) -An `Array` of `Strings` representing the payment networks that you support. +- [`countryCode`](https://developer.apple.com/library/ios/documentation/PassKit/Reference/PKPaymentRequest_Ref/#//apple_ref/occ/instp/PKPaymentRequest/countryCode) - A `String` representing the two-letter `ISO 3166` country code for the country where the payment will be processed. +- [`currencyCode`](https://developer.apple.com/library/ios/documentation/PassKit/Reference/PKPaymentRequest_Ref/#//apple_ref/occ/instp/PKPaymentRequest/currencyCode) - A `String` representing the three-letter `ISO 4217` currency code of the currency you will use to charge the customer. + +__summaryItem__ +- `label` - A `String` representing the summary name. +- `amount` - A `Number` with two decimal places representing the summary price. + +__Example__ +```js +var merchantOptions = { + paymentProcessor: 'stripe', + merchantIdentifier: 'merchant.yourapp.you', + supportedNetworks: ['PKPaymentNetworkMasterCard', 'PKPaymentNetworkVisa'], + merchantCapabilities: ['PKMerchantCapability3DS', 'PKMerchantCapabilityEMV'], + countryCode: 'US', + currencyCode: 'USD' +}; + +var summaryItems = [ + { + label: 'Hockey Stick', + amount: 88.88 + } +]; + +ApplePay.paymentRequest(merchantOptions, summaryItems) + .then(chargeTokenOnServer) + .then(ApplePay.success) + .catch(error => { + // Log error + ApplePay.failure(); + }); + +function chargeTokenOnServer(token) {...} +``` + +--- + +### success() +Displays a success animation to the user and dismisses the Apple Pay view. + +__Example__ +```js +ApplePay.success() + .then(() => { + this.props.navigator.push(successRoute); + }); +``` + +--- + +### failure() +Displays a failure animation to the user and dismisses the Apple Pay view. + +__Example__ +```js +ApplePay.failure() + .then(() => { + AlertIOS.alert('Payment Failed'); + }); +``` + +--- + +### getTotal(summaryItems) +Returns the total charge of the summary items. + +__Example__ +```js +var summaryItems = [ + { + label: 'Adult Batman Costume', + amount: 79.99 + }, + { + label: 'Child Batman Costume', + amount: 59.99 + }, + { + label: 'Discount', + amount: -40 + }, +]; + +ApplePay.getTotal(summaryItems) // 99.98 +``` + +## License +Copyright (c) 2015, Naoufal Kadhom + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/StripeManager.h b/StripeManager.h new file mode 100644 index 00000000..4d1f0cf8 --- /dev/null +++ b/StripeManager.h @@ -0,0 +1,9 @@ +#import "Stripe.h" +#import "RCTBridgeModule.h" + +@interface StripeManager : NSObject ++ (void)handlePaymentAuthorizationWithPayment:(NSString *)publishableKey + payment:(PKPayment *)payment + completion:(void (^)(PKPaymentAuthorizationStatus))completion + callback:(RCTResponseSenderBlock)callback; +@end diff --git a/StripeManager.m b/StripeManager.m new file mode 100644 index 00000000..9fc8d5ce --- /dev/null +++ b/StripeManager.m @@ -0,0 +1,52 @@ +#import "StripeManager.h" +#import "ApplePayManager.h" + +@implementation StripeManager + ++ (void)handlePaymentAuthorizationWithPayment:(NSString *)publishableKey + payment:(PKPayment *)payment + completion:(void (^)(PKPaymentAuthorizationStatus))completion + callback:(RCTResponseSenderBlock)callback + +{ + // Set Stripe Pubishable Key + [Stripe setDefaultPublishableKey:publishableKey]; + + // Create Token + +// [[STPAPIClient sharedClient] createTokenWithPayment:payment completion:^(STPToken *token, NSError *error) +// { +// // Error creating token with Stripe +// if (error) { +// NSLog(@"error: %@", error); +// completion(PKPaymentAuthorizationStatusFailure); +// return; +// } + +// [self createBackendChargeWithToken:token completion:completion]; +// +// }]; + + // Creating Tokens with ApplePay Test Cards currently fails. So for now we'll just create tokens with a Stripe Test Card. + STPCard *card = [[STPCard alloc] init]; + card.number = @"4242 4242 4242 4242"; + card.expMonth = 11; + card.expYear = 19; + card.cvc = @"310"; + + [[STPAPIClient sharedClient] createTokenWithCard:card completion:^(STPToken *token, NSError *error) + { + if (error) { + NSLog(@"Stripe Error: %@", error); + completion(PKPaymentAuthorizationStatusFailure); + return; + } else { + NSLog(@"Stripe Token: %@", token.tokenId); + + // Send token to JS + callback(@[[NSNull null], token.tokenId]); + } + }]; +} + +@end diff --git a/package.json b/package.json new file mode 100644 index 00000000..4a157ce9 --- /dev/null +++ b/package.json @@ -0,0 +1,39 @@ +{ + "name": "react-native-apple-pay", + "version": "0.0.0", + "description": "React Native library for accepting payments with Apple Pay.", + "scripts": { + "lint": "node_modules/.bin/eslint .", + "test": "npm run lint" + }, + "main": "ApplePayManager.ios.js", + "repository": { + "type": "git", + "url": "https://github.com/naoufal/react-native-apple-pay.git" + }, + "keywords": [ + "react-native", + "react", + "native", + "apple-pay", + "pay", + "payments", + "touch-id", + "stripe", + "react-component", + "react-native-component" + ], + "author": "Naoufal Kadhom (https://github.com/naoufal)", + "license": "ISC", + "bugs": { + "url": "https://github.com/naoufal/react-native-apple-pay/issues" + }, + "homepage": "https://github.com/naoufal/react-native-apple-pay", + "peerDependencies": { + "react-native": ">=0.4.0" + }, + "devDependencies": { + "eslint": "0.24.1", + "eslint-plugin-react": "2.7.1" + } +}