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

Add ability to re-fetch intent for 3ds2 #5138

Merged
merged 2 commits into from Jul 21, 2022
Merged

Conversation

jameswoo-stripe
Copy link
Contributor

@jameswoo-stripe jameswoo-stripe commented Jun 10, 2022

Summary

We're seeing a few issues with web flows, where a user can race the "processing" or "requires_action" state by closing the web view after the 3DS2 challenge has succeeded, but before the PaymentIntent has updated. You can reproduce some of these states in the PaymentSheet Example app by entering the 3220 card number, tapping "complete" then quickly tapping "close". The PaymentIntent status will be "requires_action" or "processing", and the payment will fail even though it succeeded on the backend.

This patch:

  • Ensures that successful stripe intents emit a success flow outcome, rather than cancelled, regardless if the flow outcome was cancelled or not
  • new refreshStripeIntent abstract method
  • SetupIntentFlowResultProcessor implements refreshStripeIntent (as retrieve)
  • Ensures that cancelled, processing, card payments/setups have retries to retrieve the intent

Motivation

Fixes https://jira.corp.stripe.com/browse/RUN_MOBILESDK-986
Analogue to https://github.com/stripe-ios/stripe-ios/pull/1096

Testing

  • Added tests
  • Modified tests
  • Manually verified

Manual testing:

  • Tested with live mode (3ds2-test-backend)
  • Tested with payment sheet test cards

Changelog

  • [Fixed] Fixed an issue where PaymentSheet will show a failure even when 3DS2 Payment/SetupIntent is successful

@github-actions
Copy link
Contributor

github-actions bot commented Jun 10, 2022

Diffuse output:

OLD: paymentsheet-example-release-master.apk (signature: none)
NEW: paymentsheet-example-release-pr.apk (signature: none)

          │           compressed           │          uncompressed          
          ├───────────┬───────────┬────────┼───────────┬───────────┬────────
 APK      │ old       │ new       │ diff   │ old       │ new       │ diff   
──────────┼───────────┼───────────┼────────┼───────────┼───────────┼────────
      dex │  15.3 MiB │  15.3 MiB │ +757 B │  51.7 MiB │  51.7 MiB │ +652 B 
     arsc │   1.8 MiB │   1.8 MiB │    0 B │   1.8 MiB │   1.8 MiB │    0 B 
 manifest │     4 KiB │     4 KiB │    0 B │  18.5 KiB │  18.5 KiB │    0 B 
      res │ 870.7 KiB │ 870.7 KiB │    0 B │   1.4 MiB │   1.4 MiB │    0 B 
   native │   2.5 MiB │   2.5 MiB │    0 B │   5.9 MiB │   5.9 MiB │    0 B 
    asset │     3 MiB │     3 MiB │    0 B │     3 MiB │     3 MiB │    0 B 
    other │  81.7 KiB │  81.7 KiB │    0 B │ 155.5 KiB │ 155.5 KiB │    0 B 
──────────┼───────────┼───────────┼────────┼───────────┼───────────┼────────
    total │  23.5 MiB │  23.5 MiB │ +757 B │  63.9 MiB │  63.9 MiB │ +652 B 

         │          raw           │             unique             
         ├────────┬────────┬──────┼────────┬────────┬──────────────
 DEX     │ old    │ new    │ diff │ old    │ new    │ diff         
─────────┼────────┼────────┼──────┼────────┼────────┼──────────────
   files │      4 │      4 │    0 │        │        │              
 strings │ 250160 │ 250166 │   +6 │ 213275 │ 213279 │ +4 (+18 -14) 
   types │  44119 │  44120 │   +1 │  40499 │  40500 │ +1 (+3 -2)   
 classes │  37701 │  37702 │   +1 │  37701 │  37702 │ +1 (+3 -2)   
 methods │ 220526 │ 220534 │   +8 │ 212576 │ 212584 │ +8 (+22 -14) 
  fields │ 162578 │ 162577 │   -1 │ 161543 │ 161542 │ -1 (+12 -13) 

 ARSC    │ old  │ new  │ diff 
─────────┼──────┼──────┼──────
 configs │  292 │  292 │  0   
 entries │ 6223 │ 6223 │  0
APK
    compressed    │   uncompressed   │                
─────────┬────────┼─────────┬────────┤                
 size    │ diff   │ size    │ diff   │ path           
─────────┼────────┼─────────┼────────┼────────────────
 2.2 MiB │ +757 B │ 6.8 MiB │ +652 B │ ∆ classes3.dex 
─────────┼────────┼─────────┼────────┼────────────────
 2.2 MiB │ +757 B │ 6.8 MiB │ +652 B │ (total)
DEX
STRINGS:

   old    │ new    │ diff         
  ────────┼────────┼──────────────
   213275 │ 213279 │ +4 (+18 -14) 
  + �
  
  ���
  
  ���
  
  ���
  ������0�����*�0������ �*�����H�0�*�0�H�@
  + �
  ���
  ��
  ���
  �� 
  ���
  ���
  ���
  ����2�0�B���¢����R���������0�0�¢��
  ������R�����0	X�T¢��
  ¨�
  
  + N
  ���
  ���
  ���
  ���
  
  ���
  
  ���
  ���
  
  ���
  
  ���
  
  ���
  ���
  ���
  ���
  ���
  ���
  �� 
  ������2�����0�����0�0�B9��������0�������������0�0����	��0
  ������0�����
  ��0�¢����J+������0�2�����0�2�����0�2�����0�H�@ø�¢����J����0�2�����0�2�����0�2�������0�H�J1������0�2�����0�2�����0�2��������0�0�H�@ø�¢����J1� ����0�2�����0�2�����0�2��������0�0�H�@ø�¢�������
  ���¨�!
  + z
  ���
  
  ���
  
  ���
  ��
  
  ���
  
  ���
  ���
  
  ���
  
  ���
  
  ���
  
  ���
  ���
  ���
  ���
  ���
  ���
  ���
  ���
  ���
  ���
  �� 
  ���
  ���
  ���
  ���
  ���
  �0� 9*����*�0�*����� �*�����H�0�2�0�:�9B?��������0����������0
  0	������0���
  ��0�������0���������0�¢����J+������82�����0
  2�����0�2�����0
  H¤@ø�¢����J'����8�2�����82�� ��0!2������0
  H_¢���#J��_��0!2��%��0�2��&��0!H�J��'��8�2��(��0)H�@ø�¢���*J1�+����82��,��0
  2�����0�2�-������0
  0.H¤@ø�¢���/J!�0��82��,��0
  2�����0�H�@ø�¢���1J1�2����82��,��0
  2�����0�2�-������0
  0.H¤@ø�¢���/J��3��042�����0�2��5��04H�J��6��042�����0�2��7��0!H�J��8��042�����0�H�R�����0�X��¢��
  R��
  ��0�X��¢��
  R���������0
  0	X��¢��
  R�����0�X��¢��
  R�����0X��¢��
  ������R�����0�X��¢��
  ���:;���
  ���¨�<
  + _delayMs
  + (Landroid/content/Context;Ljavax/inject/Provider;Lcom/stripe/android/networking/StripeRepository;Lcom/stripe/android/core/Logger;Lkotlin/coroutines/CoroutineContext;Lcom/stripe/android/core/networking/RetryDelaySupplier;)V
  + Lcom/stripe/android/payments/PaymentFlowResultProcessor_WhenMappings;
  + Lcom/stripe/android/payments/PaymentFlowResultProcessor_refreshStripeIntentUntilTerminalState_1;
  + Lcom/stripe/android/payments/PaymentFlowResultProcessor_refreshStripeIntentUntilTerminalState_2;
  + SMAP
  PaymentFlowResultProcessor.kt
  Kotlin
  *S Kotlin
  *F
  + 1 PaymentFlowResultProcessor.kt
  com/stripe/android/payments/PaymentFlowResultProcessor_processResult_2
  + 2 fake.kt
  kotlin/jvm/internal/FakeKt
  *L
  1#1,376:1
  1#2:377
  *E
  
  + SMAP
  StripePaymentController.kt
  Kotlin
  *S Kotlin
  *F
  + 1 StripePaymentController.kt
  com/stripe/android/StripePaymentController
  + 2 fake.kt
  kotlin/jvm/internal/FakeKt
  *L
  1#1,593:1
  1#2:594
  *E
  
  + access_determineFlowOutcome
  + access_refreshStripeIntentUntilTerminalState
  + com.stripe.android.payments.PaymentFlowResultProcessor
  + com.stripe.android.payments.PaymentFlowResultProcessor_refreshStripeIntentUntilTerminalState_2
  + determineFlowOutcome
  + originalFlowOutcome
  + refreshStripeIntent
  
  - �
  ���
  ��
  ���
  �� 
  ���
  �������2�0�B���¢����R���������0�0�¢��
  ������¨��
  - N
  ���
  ���
  ���
  ���
  
  ���
  
  ���
  ���
  
  ���
  
  ���
  
  ���
  ���
  ���
  ���
  ���
  ���
  �� 
  ������2�����0�����0�0�B9��������0�������������0�0����	��0
  ������0�����
  ��0�¢����J+������0�2�����0�2�����0�2�����0�H�@ø�¢����J����0�2�����0�2�����0�2�������0�H�J!����0�2�����0�2�����0�H�@ø�¢����J1������0�2�����0�2�����0�2��������0�0 H�@ø�¢���!���
  ���¨�
  - T
  ���
  ���
  ���
  ���
  
  ���
  
  ���
  ���
  
  ���
  
  ���
  
  ���
  
  ���
  ���
  ���
  ���
  ���
  ���
  �� 
  ������ &2�����0�����0�0�:�&BA��������0�������������0�0����	��0
  ������0�����
  ��0�������0�¢����J+������0�2�����0�2�����0�2�����0�H�@ø�¢����J����0�2�����0�2�����0�2�������0�H�J!����0�2�� ��0�2�����0�H�@ø�¢���!J1�����0�2�� ��0�2�����0�2�#������0�0_H�@ø�¢���%R�����0�¢��
  ���������
  ���¨�'
  - t
  ���
  
  ���
  
  ���
  ��
  
  ���
  
  ���
  ���
  
  ���
  
  ���
  
  ���
  ���
  ���
  ���
  ���
  ���
  ���
  ���
  ���
  ���
  �� 
  ���
  ���
  ���
  ���
  ���
  �0� 2*����*�0�*����� �*�����H�0�2�0�:�2B5��������0����������0
  0	������0���
  ��0�������0�¢����J+������82�����0
  2�����0�2�����0
  H¤@ø�¢����J'����8�2�����82�����0�2�� ����0
  H_¢���!J����8�2��#��0_H�@ø�¢���%J!�&��82��'��0
  2�����0�H¤@ø�¢���(J1�)����82��'��0
  2�����0�2�*������0
  0+H¤@ø�¢���,J��-��0.2�����0�2��/��0.H�J��0��0.2�����0�2��1��0�H�R�����0�X��¢��
  R��
  ��0�X��¢��
  R���������0
  0	X��¢��
  R�����0X��¢��
  ������R�����0�X��¢��
  ���34���
  ���¨�5
  - ()Lcom/stripe/android/core/networking/RetryDelaySupplier;
  
...✂

@jameswoo-stripe jameswoo-stripe force-pushed the jameswoo/3ds-retry branch 2 times, most recently from e3c5a34 to 8efbbee Compare June 10, 2022 23:01
skyler-stripe
skyler-stripe previously approved these changes Jun 15, 2022
}

@Test
fun `3ds2 canceled with processing intent should succeed`() =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spoke on slack.

The name here indicates that if we end up in the processing state we should emit a success but ... the test is actually checking to see if a processing intent eventually becomes a succeeded, then we can emit success. Maybe we could name this better or add a comment if the name ends being too long. Ditto for the others.

I can look at the test and PR and figure out what's going on, but maybe renaming would make it more explicit. Up to you.

@davidme-stripe
Copy link
Contributor

I'm trying this out and confused by the behavior in the normal approval case: I get into shouldRefreshIntent, and the PI status is requires_capture (indicating a success), but the flowOutcome is cancelled even though the payment was approved. @skyler-stripe was seeing this too. Is this expected? I believe the iOS SDK treats requires_capture as a success.

@davidme-stripe
Copy link
Contributor

It does look like the refresh behavior is working, at least. The initial state of the PI is processing, and then it transitions to requires_capture after the refresh.

@jameswoo-stripe jameswoo-stripe merged commit bb4e8e7 into master Jul 21, 2022
@jameswoo-stripe jameswoo-stripe deleted the jameswoo/3ds-retry branch July 21, 2022 19:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants