Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance payment sheet DX #506

Merged
merged 4 commits into from
Aug 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ PODS:
- Stripe (21.7.0):
- Stripe/Stripe3DS2 (= 21.7.0)
- StripeCore (= 21.7.0)
- stripe-react-native (0.1.5):
- stripe-react-native (0.2.0):
- React
- Stripe (~> 21.7.0)
- Stripe/Stripe3DS2 (21.7.0):
Expand Down Expand Up @@ -421,7 +421,7 @@ SPEC CHECKSUMS:
RNReanimated: e03f7425cb7a38dcf1b644d680d1bfc91c3337ad
RNScreens: 2ad555d4d9fa10b91bb765ca07fe9b29d59573f0
Stripe: 90596971ef49bade169f68bc59369a796b30a045
stripe-react-native: f1b034cb702aa214078d9441b0a4313ac00c020d
stripe-react-native: 656ddaac81d6b4b66e68858de0f7493bd3ffb6b8
StripeCore: c09b492efc3b269a6ff875ad738ca366db97e03b
Yoga: 4bd86afe9883422a7c4028c00e34790f560923d6

Expand Down
2 changes: 2 additions & 0 deletions example/src/screens/PaymentsUICompleteScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ export default function PaymentsUICompleteScreen() {
});
if (!error) {
setPaymentSheetEnabled(true);
} else {
Alert.alert(`Error code: ${error.code}`, error.message);
}
};

Expand Down
4 changes: 3 additions & 1 deletion example/src/screens/PaymentsUICustomScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ export default function PaymentsUICustomScreen() {

if (!error) {
setPaymentSheetEnabled(true);
} else {
Alert.alert(`Error code: ${error.code}`, error.message);
}
if (paymentOption) {
setPaymentMethod(paymentOption);
Expand All @@ -71,7 +73,7 @@ export default function PaymentsUICustomScreen() {
});

if (error) {
console.log('error', error);
Alert.alert(`Error code: ${error.code}`, error.message);
} else if (paymentOption) {
setPaymentMethod({
label: paymentOption.label,
Expand Down
29 changes: 29 additions & 0 deletions ios/Errors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,34 @@ enum CreateTokenErrorType: String {
}

class Errors {
static internal let isPIClientSecretValidRegex: NSRegularExpression? = try? NSRegularExpression(
arekkubaczkowski marked this conversation as resolved.
Show resolved Hide resolved
pattern: "^pi_[^_]+_secret_[^_]+$", options: [])

static internal let isSetiClientSecretValidRegex: NSRegularExpression? = try? NSRegularExpression(
pattern: "^seti_[^_]+_secret_[^_]+$", options: [])

static internal let isEKClientSecretValidRegex: NSRegularExpression? = try? NSRegularExpression(
pattern: "^ek_[^_](.)+$", options: [])

class func isPIClientSecretValid(clientSecret: String) -> Bool {
return (Errors.isPIClientSecretValidRegex?.numberOfMatches(
in: clientSecret,
options: .anchored,
range: NSRange(location: 0, length: clientSecret.count))) == 1
}
class func isSetiClientSecretValid(clientSecret: String) -> Bool {
return (Errors.isSetiClientSecretValidRegex?.numberOfMatches(
in: clientSecret,
options: .anchored,
range: NSRange(location: 0, length: clientSecret.count))) == 1
}
class func isEKClientSecretValid(clientSecret: String) -> Bool {
return (Errors.isEKClientSecretValidRegex?.numberOfMatches(
in: clientSecret,
options: .anchored,
range: NSRange(location: 0, length: clientSecret.count))) == 1
}

class func createError (_ code: String, _ message: String?) -> NSDictionary {
let value: NSDictionary = [
"code": code,
Expand Down Expand Up @@ -83,3 +111,4 @@ class Errors {
return ["error": value]
}
}

20 changes: 17 additions & 3 deletions ios/StripeSdk.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class StripeSdk: RCTEventEmitter, STPApplePayContextDelegate, STPBankSelectionVi
self.merchantIdentifier = merchantIdentifier
resolve(NSNull())
}

@objc(initPaymentSheet:resolver:rejecter:)
func initPaymentSheet(params: NSDictionary, resolver resolve: @escaping RCTPromiseResolveBlock,
rejecter reject: @escaping RCTPromiseRejectBlock) -> Void {
Expand All @@ -82,6 +82,10 @@ class StripeSdk: RCTEventEmitter, STPApplePayContextDelegate, STPBankSelectionVi

if let customerId = params["customerId"] as? String {
if let customerEphemeralKeySecret = params["customerEphemeralKeySecret"] as? String {
if (!Errors.isEKClientSecretValid(clientSecret: customerEphemeralKeySecret)) {
resolve(Errors.createError(PaymentSheetErrorType.Failed.rawValue, "`customerEphemeralKeySecret` format does not match expected client secret formatting."))
return
}
configuration.customer = .init(id: customerId, ephemeralKeySecret: customerEphemeralKeySecret)
}
}
Expand All @@ -95,7 +99,7 @@ class StripeSdk: RCTEventEmitter, STPApplePayContextDelegate, STPBankSelectionVi
func handlePaymentSheetFlowControllerResult(result: Result<PaymentSheet.FlowController, Error>, stripeSdk: StripeSdk?) {
switch result {
case .failure(let error):
resolve(Errors.createError("Failed", error.localizedDescription))
resolve(Errors.createError("Failed", error as NSError))
case .success(let paymentSheetFlowController):
stripeSdk?.paymentSheetFlowController = paymentSheetFlowController
if let paymentOption = stripeSdk?.paymentSheetFlowController?.paymentOption {
Expand All @@ -111,6 +115,11 @@ class StripeSdk: RCTEventEmitter, STPApplePayContextDelegate, STPBankSelectionVi
}

if let paymentIntentClientSecret = params["paymentIntentClientSecret"] as? String {
if (!Errors.isPIClientSecretValid(clientSecret: paymentIntentClientSecret)) {
resolve(Errors.createError(PaymentSheetErrorType.Failed.rawValue, "`secret` format does not match expected client secret formatting."))
return
}

if params["customFlow"] as? Bool == true {
PaymentSheet.FlowController.create(paymentIntentClientSecret: paymentIntentClientSecret,
configuration: configuration) { [weak self] result in
Expand All @@ -121,6 +130,11 @@ class StripeSdk: RCTEventEmitter, STPApplePayContextDelegate, STPBankSelectionVi
resolve([])
}
} else if let setupIntentClientSecret = params["setupIntentClientSecret"] as? String {
if (!Errors.isSetiClientSecretValid(clientSecret: setupIntentClientSecret)) {
resolve(Errors.createError(PaymentSheetErrorType.Failed.rawValue, "`secret` format does not match expected client secret formatting."))
return
}

if params["customFlow"] as? Bool == true {
PaymentSheet.FlowController.create(setupIntentClientSecret: setupIntentClientSecret,
configuration: configuration) { [weak self] result in
Expand Down Expand Up @@ -183,7 +197,7 @@ class StripeSdk: RCTEventEmitter, STPApplePayContextDelegate, STPBankSelectionVi
case .canceled:
resolve(Errors.createError(PaymentSheetErrorType.Canceled.rawValue, "The payment has been canceled"))
case .failed(let error):
resolve(Errors.createError(PaymentSheetErrorType.Failed.rawValue, error.localizedDescription))
resolve(Errors.createError(PaymentSheetErrorType.Failed.rawValue, error as NSError))
}
}
}
Expand Down