Problem

On the checkout page, when there is an error, for example a required field not filled in, and you click Submit, there will be form error which triggers a Stripe error and message to refresh the page. This renders the form unusable until the page is refreshed which is a poor user experience if you just forgot to input a City or accept the Terms and Conditions.

$('#uc-cart-checkout-form', context).once('uc_stripe', function(){
Once function prevents stripe from reloading. Any dom changes to stripe area will destroy element as a Stripe security feature

I can bypass the above experience by removing the .once function, so that the uc_stripe.js can run even if the DOM has changed which I presume to be the cause of this behaviour. This applies to Submitting the checkout form.

However the DOM also changes when using uc_vat_number module which validates the VAT number field using Ajax and adjusts the payment-pane for subtotal and totals. I then get a new error:

Uncaught (in promise) IntegrationError: We could not retrieve data from the specified Element.
Please make sure the Element you are attempting to use is still mounted.

Is it possible to allow Stripe to run safely even if the DOM changes both on Ajax and on Submit with an error?

Comments

bamboodigital created an issue. See original summary.

bamboodigital’s picture

Title: JS - .once() » JS - Stripe makes the checkout form unusable when there's a form error
bamboodigital’s picture

Issue summary: View changes
Rafal Lukawiecki’s picture

In some cases refreshing the page does not help, either. When uc_vat_number throws a form validation error, the uc_stripe message says “Sorry, for security reasons your card cannot be processed. Please refresh this page and try again. If the problem persists please check that Javascript is enabled your browser.” Unfortunately, refreshing the page does not clear this error. Also, correcting the mistake is not possible for the user because the Review Order button is disabled. The user has to restart the checkout and be careful to enter everything correctly, which is a poor experience...

This is an issue even if using a different payment method, such as PayPal. The error generated by uc_stripe is hidden, but it is still disabling the Review Order button. The root cause of this issue may be related to issue #3124343: Not inputting card holder name generates error.. asks to refresh page..

bamboodigital’s picture

Issue summary: View changes
bamboodigital’s picture

Update. This issue resolves when the setting " Show the order total preview on the payment pane. " is disabled.

That means that table id="uc-order-total-preview" is not present on the DOM or updated when the Country select or the VAT field changes. I believe that the Stripe throws the Integration error when the "uc-order-total-preview" pane is changed on the DOM.

Perhaps this gives a clue, is it perhaps possible to remount the Stripe element after AJAX changes on the checkout?

bamboodigital’s picture

Assigned: bamboodigital » Unassigned
bamboodigital’s picture

Status: Active » Needs review
StatusFileSize
new501 bytes

Another update:

We have discovered that the checkout form ID changes on errors, for example, 'uc-cart-checkout-form--2'. I believe it's a Drupal Ajax behaviour.

$('#uc-cart-checkout-form', context) is the code on line 14 of uc_stripe.js. With the above form ID having changed, the uc_stripe code won't find the changed form.

A possible solution we've found is to target the form class, which will find the checkout form even if the ID changes. This seems to resolve our problem but does this solution open up other (security) issues we perhaps haven't thought of?

$('.uc-cart-checkout-form', context)

Thanks in advance!
Enda

andraeray’s picture

Hey bamboodigital,

Good find, I think this is a good solution, I don't see any security risks with using the class instead of the ID.

My main concern is if stripe checkout still works properly even while changing things like country and other fields that trigger ajax. I haven't tested that.

andraeray’s picture

Status: Needs review » Reviewed & tested by the community

Looks good! Great fix.

I tested while changing saved address, and country, while proceeding with form errors, and it works as expected.

  • bamboodigital authored 8462aaf on 7.x-3.x
    Issue #3168978 by bamboodigital, AndraeRay, Rafal Lukawiecki: JS -...
andraeray’s picture

Status: Reviewed & tested by the community » Fixed

Committed.

andraeray’s picture

Rafal Lukawiecki’s picture

Thank you, @bamboodigital and @AndraeRay, very much. We will continue to test, intensively, over the next two weeks. My main concern would be if targeting the class, instead of the specific form id, could expose the checkout workflow to some form of a CSRF attack. We have been thinking about that and we do not think that it would be likely, but it may be a good idea for you and perhaps others, more in touch with the nature of form IDs and CSRF, to comment.

I think we may also have a way to work around the somewhat related #3169359: Don't mount Stripe card element unless Stripe is selected as the payment method, will be back with more information later. Once again, thank you for the commit.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.