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?
| Comment | File | Size | Author |
|---|---|---|---|
| #8 | uc_stripe-3168978-8-js-stripe-makes-the-checkout-form-unusable.patch | 501 bytes | bamboodigital |
Comments
Comment #2
bamboodigital commentedComment #3
bamboodigital commentedComment #4
Rafal LukawieckiIn 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..
Comment #5
bamboodigital commentedComment #6
bamboodigital commentedUpdate. 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?
Comment #7
bamboodigital commentedComment #8
bamboodigital commentedAnother 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
Comment #9
andraeray commentedHey 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.
Comment #10
andraeray commentedLooks good! Great fix.
I tested while changing saved address, and country, while proceeding with form errors, and it works as expected.
Comment #12
andraeray commentedCommitted.
Comment #13
andraeray commentedComment #14
Rafal LukawieckiThank 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.