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

Added fingerprint check validation for card and us bank #4207

Merged
merged 11 commits into from
Nov 1, 2024
Prev Previous commit
Next Next commit
implemented suggestions
joyceqin-stripe committed Oct 31, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
commit cb1ae836e31e5327b910fbb0bf557acb485a5600
Original file line number Diff line number Diff line change
@@ -217,6 +217,7 @@ import Foundation
case paymentSheetFormCompleted = "mc_form_completed"
case paymentSheetCardNumberCompleted = "mc_card_number_completed"
case paymentSheetDeferredIntentPaymentMethodIdMismatch = "mc_deferred_intent_payment_method_id_mismatch"
case paymentSheetDeferredIntentPaymentMethodFingerprintMismatch = "mc_deferred_intent_payment_method_fingerprint_mismatch"

// MARK: - v1/elements/session
case paymentSheetElementsSessionLoadFailed = "mc_elements_session_load_failed"
Original file line number Diff line number Diff line change
@@ -82,7 +82,7 @@ extension PaymentSheet {
}
} else {
// 4b. Server-side confirmation
try PaymentSheetDeferredValidator.validatePaymentMethodId(intentPaymentMethod: paymentIntent.paymentMethod, paymentMethod: paymentMethod)
try PaymentSheetDeferredValidator.validatePaymentMethod(intentPaymentMethod: paymentIntent.paymentMethod, paymentMethod: paymentMethod)
paymentHandler.handleNextAction(
for: paymentIntent,
with: authenticationContext,
@@ -110,7 +110,7 @@ extension PaymentSheet {
}
} else {
// 4b. Server-side confirmation
try PaymentSheetDeferredValidator.validatePaymentMethodId(intentPaymentMethod: setupIntent.paymentMethod, paymentMethod: paymentMethod)
try PaymentSheetDeferredValidator.validatePaymentMethod(intentPaymentMethod: setupIntent.paymentMethod, paymentMethod: paymentMethod)
paymentHandler.handleNextAction(
for: setupIntent,
with: authenticationContext,
Original file line number Diff line number Diff line change
@@ -28,7 +28,7 @@ struct PaymentSheetDeferredValidator {
guard paymentIntent.captureMethod == captureMethod else {
throw PaymentSheetError.deferredIntentValidationFailed(message: "Your PaymentIntent captureMethod (\(paymentIntent.captureMethod)) does not match the PaymentSheet.IntentConfiguration amount (\(captureMethod)).")
}
try validatePaymentMethodId(intentPaymentMethod: paymentIntent.paymentMethod, paymentMethod: paymentMethod)
try validatePaymentMethod(intentPaymentMethod: paymentIntent.paymentMethod, paymentMethod: paymentMethod)
/*
Manual confirmation is only available using FlowController because merchants own the final step of confirmation.
Showing a successful payment in the complete flow may be misleading when merchants still need to do a final confirmation which could fail e.g., bad network
@@ -47,13 +47,14 @@ struct PaymentSheetDeferredValidator {
guard setupIntent.usage == setupFutureUsage else {
throw PaymentSheetError.deferredIntentValidationFailed(message: "Your SetupIntent usage (\(setupIntent.usage)) does not match the PaymentSheet.IntentConfiguration setupFutureUsage (\(String(describing: setupFutureUsage))).")
}
try validatePaymentMethodId(intentPaymentMethod: setupIntent.paymentMethod, paymentMethod: paymentMethod)
try validatePaymentMethod(intentPaymentMethod: setupIntent.paymentMethod, paymentMethod: paymentMethod)
}

static func validatePaymentMethodId(intentPaymentMethod: STPPaymentMethod?, paymentMethod: STPPaymentMethod) throws {
static func validatePaymentMethod(intentPaymentMethod: STPPaymentMethod?, paymentMethod: STPPaymentMethod) throws {
guard let intentPaymentMethod = intentPaymentMethod else { return }
guard intentPaymentMethod.stripeId == paymentMethod.stripeId else {
if intentPaymentMethod.type == paymentMethod.type {
// Payment methods of type card and us_bank_account can be cloned, leading to mismatched pm ids, but their fingerprints should still match
switch paymentMethod.type.identifier {
case "card":
try validateFingerprint(intentFingerprint: intentPaymentMethod.card?.fingerprint, fingerprint: paymentMethod.card?.fingerprint)
@@ -89,7 +90,7 @@ struct PaymentSheetDeferredValidator {
1. Create a new Intent each time before you call the `confirmHandler`, or
2. Update the existing Intent with the desired `paymentMethod` before calling the `confirmHandler`.
"""
let errorAnalytic = ErrorAnalytic(event: .paymentSheetDeferredIntentPaymentMethodIdMismatch, error: PaymentSheetError.unknown(debugDescription: errorMessage))
let errorAnalytic = ErrorAnalytic(event: .paymentSheetDeferredIntentPaymentMethodFingerprintMismatch, error: PaymentSheetError.unknown(debugDescription: errorMessage))
STPAnalyticsClient.sharedClient.log(analytic: errorAnalytic)
throw PaymentSheetError.deferredIntentValidationFailed(message: errorMessage)
}
Original file line number Diff line number Diff line change
@@ -79,7 +79,7 @@ final class PaymentSheetDeferredValidatorTests: XCTestCase {
paymentMethodJson["id"] = testCard.stripeId
let testCardPi = STPFixtures.makePaymentIntent(paymentMethodJson: paymentMethodJson)

XCTAssertNoThrow(try PaymentSheetDeferredValidator.validatePaymentMethodId(intentPaymentMethod: testCardPi.paymentMethod,
XCTAssertNoThrow(try PaymentSheetDeferredValidator.validatePaymentMethod(intentPaymentMethod: testCardPi.paymentMethod,
paymentMethod: testCard))
}

@@ -92,7 +92,7 @@ final class PaymentSheetDeferredValidatorTests: XCTestCase {
guard let intentPaymentMethod = testCardPi.paymentMethod else {
return
}
XCTAssertThrowsError(try PaymentSheetDeferredValidator.validatePaymentMethodId(intentPaymentMethod: testCardPi.paymentMethod,
XCTAssertThrowsError(try PaymentSheetDeferredValidator.validatePaymentMethod(intentPaymentMethod: testCardPi.paymentMethod,
paymentMethod: testUSBankAccount)) { error in
XCTAssertEqual("\(error)", """
An error occurred in PaymentSheet. \nThere is a mismatch between the payment method ID on your Intent: \(intentPaymentMethod.stripeId) and the payment method passed into the `confirmHandler`: \(testUSBankAccount.stripeId).
@@ -110,7 +110,7 @@ final class PaymentSheetDeferredValidatorTests: XCTestCase {
func testPaymentIntentNilPaymentMethod() throws {
let testCard = STPPaymentMethod._testCard()
let nilPaymentMethodPi = STPFixtures.makePaymentIntent()
XCTAssertNoThrow(try PaymentSheetDeferredValidator.validatePaymentMethodId(intentPaymentMethod: nilPaymentMethodPi.paymentMethod,
XCTAssertNoThrow(try PaymentSheetDeferredValidator.validatePaymentMethod(intentPaymentMethod: nilPaymentMethodPi.paymentMethod,
paymentMethod: testCard))
}

@@ -120,7 +120,7 @@ final class PaymentSheetDeferredValidatorTests: XCTestCase {
paymentMethodJson["id"] = testCard.stripeId
let testCardSi = STPFixtures.makeSetupIntent(paymentMethodJson: paymentMethodJson)

XCTAssertNoThrow(try PaymentSheetDeferredValidator.validatePaymentMethodId(intentPaymentMethod: testCardSi.paymentMethod,
XCTAssertNoThrow(try PaymentSheetDeferredValidator.validatePaymentMethod(intentPaymentMethod: testCardSi.paymentMethod,
paymentMethod: testCard))
}

@@ -133,7 +133,7 @@ final class PaymentSheetDeferredValidatorTests: XCTestCase {
guard let intentPaymentMethod = testCardSi.paymentMethod else {
return
}
XCTAssertThrowsError(try PaymentSheetDeferredValidator.validatePaymentMethodId(intentPaymentMethod: testCardSi.paymentMethod,
XCTAssertThrowsError(try PaymentSheetDeferredValidator.validatePaymentMethod(intentPaymentMethod: testCardSi.paymentMethod,
paymentMethod: testUSBankAccount)) { error in
XCTAssertEqual("\(error)", """
An error occurred in PaymentSheet. \nThere is a mismatch between the payment method ID on your Intent: \(intentPaymentMethod.stripeId) and the payment method passed into the `confirmHandler`: \(testUSBankAccount.stripeId).
@@ -151,7 +151,7 @@ final class PaymentSheetDeferredValidatorTests: XCTestCase {
func testSetupIntentNilPaymentMethod() throws {
let testCard = STPPaymentMethod._testCard()
let nilPaymentMethodSi = STPFixtures.makeSetupIntent()
XCTAssertNoThrow(try PaymentSheetDeferredValidator.validatePaymentMethodId(intentPaymentMethod: nilPaymentMethodSi.paymentMethod,
XCTAssertNoThrow(try PaymentSheetDeferredValidator.validatePaymentMethod(intentPaymentMethod: nilPaymentMethodSi.paymentMethod,
paymentMethod: testCard))
}