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

Handle 402 errors so it won't be hijacked by the hosting provider error page #8102

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from

Conversation

zmaglica
Copy link
Contributor

Fixes #8080, #8079, #6546

Changes proposed in this Pull Request

Stripe typically returns a 402 status code when a payment method is invalid. However, this standard response can be intercepted by some hosting companies, leading to a significant issue. These companies replace the expected 402 error with their custom error pages, formatted differently from what the client anticipates.

This PR resolves this problem by returning 400 status code instead of 402, on the AJAX calls where the status code is known that could be hijacked.

Testing instructions

Test 1:

  1. Create a test site on Jurassic Ninja.
  2. Install and activate all the required plugins.
  3. Install the WooCommerce Payments.
  4. Complete WooCommerce Payments KYC flow.
  5. As a merchant, navigate to Pages > Add new.
  6. Add the Checkout block to the page.
  7. Go to the store page and add a product to your cart.
  8. Go to the newly created Checkout page.
  9. Checkout with any failure cards (i.e 4000000000009995)
  10. Error message should be visible.

Test 2:

You can skip steps from 1-4 if you have already configured JN site with WooPayments.

  1. Create a test site on Jurassic Ninja.
  2. Install and activate all the required plugins.
  3. Install the WooCommerce Payments.
  4. Complete WooCommerce Payments KYC flow.
  5. Go to the My Account > Add payment method page.
  6. Fill the form in with card number 4000000000000002.
  7. Click on the "Add payment method" button.
  8. Error message should be visible.

  • Run npm run changelog to add a changelog file, choose patch to leave it empty if the change is not significant. You can add multiple changelog files in one PR by running this command a few times.
  • Covered with tests (or have a good reason not to test in description ☝️)
  • Tested on mobile (or does not apply)

Post merge

@zmaglica zmaglica requested review from frosso and a team January 30, 2024 17:12
@botwoo
Copy link
Collaborator

botwoo commented Jan 30, 2024

Test the build

Option 1. Jetpack Beta

  • Install and activate Jetpack Beta.
  • Use this build by searching for PR number 8102 or branch name fix/8080-handle-402-errors in your-test.site/wp-admin/admin.php?page=jetpack-beta&plugin=woocommerce-payments

Option 2. Jurassic Ninja - available for logged-in A12s

🚀 Launch a JN site with this branch 🚀

ℹ️ Install this Tampermonkey script to get more options.


Build info:

  • Latest commit: 5bb9431
  • Build time: 2024-02-21 13:23:12 UTC

Note: the build is updated when a new commit is pushed to this PR.

Copy link
Contributor

github-actions bot commented Jan 30, 2024

Size Change: 0 B

Total Size: 1.26 MB

ℹ️ View Unchanged
Filename Size
release/woocommerce-payments/assets/css/admin.css 1.06 kB
release/woocommerce-payments/assets/css/success.css 158 B
release/woocommerce-payments/dist/blocks-checkout-rtl.css 1.81 kB
release/woocommerce-payments/dist/blocks-checkout.css 1.81 kB
release/woocommerce-payments/dist/blocks-checkout.js 85.2 kB
release/woocommerce-payments/dist/checkout-rtl.css 318 B
release/woocommerce-payments/dist/checkout.css 319 B
release/woocommerce-payments/dist/checkout.js 36.4 kB
release/woocommerce-payments/dist/index-rtl.css 37.2 kB
release/woocommerce-payments/dist/index.css 37.2 kB
release/woocommerce-payments/dist/index.js 290 kB
release/woocommerce-payments/dist/multi-currency-analytics.js 1.05 kB
release/woocommerce-payments/dist/multi-currency-rtl.css 3.25 kB
release/woocommerce-payments/dist/multi-currency-switcher-block.js 59.4 kB
release/woocommerce-payments/dist/multi-currency.css 3.25 kB
release/woocommerce-payments/dist/multi-currency.js 54.4 kB
release/woocommerce-payments/dist/order-rtl.css 707 B
release/woocommerce-payments/dist/order.css 708 B
release/woocommerce-payments/dist/order.js 41.6 kB
release/woocommerce-payments/dist/payment-gateways-rtl.css 1.19 kB
release/woocommerce-payments/dist/payment-gateways.css 1.19 kB
release/woocommerce-payments/dist/payment-gateways.js 38.3 kB
release/woocommerce-payments/dist/payment-request-rtl.css 153 B
release/woocommerce-payments/dist/payment-request.css 153 B
release/woocommerce-payments/dist/payment-request.js 12.3 kB
release/woocommerce-payments/dist/product-details.js 919 B
release/woocommerce-payments/dist/settings-rtl.css 10.2 kB
release/woocommerce-payments/dist/settings.css 10.2 kB
release/woocommerce-payments/dist/settings.js 230 kB
release/woocommerce-payments/dist/subscription-edit-page.js 669 B
release/woocommerce-payments/dist/subscription-product-onboarding-modal-rtl.css 519 B
release/woocommerce-payments/dist/subscription-product-onboarding-modal.css 519 B
release/woocommerce-payments/dist/subscription-product-onboarding-modal.js 19.4 kB
release/woocommerce-payments/dist/subscription-product-onboarding-toast.js 710 B
release/woocommerce-payments/dist/subscriptions-empty-state-rtl.css 117 B
release/woocommerce-payments/dist/subscriptions-empty-state.css 117 B
release/woocommerce-payments/dist/subscriptions-empty-state.js 18.5 kB
release/woocommerce-payments/dist/tos-rtl.css 230 B
release/woocommerce-payments/dist/tos.css 231 B
release/woocommerce-payments/dist/tos.js 21 kB
release/woocommerce-payments/dist/woopay-direct-checkout.js 3.34 kB
release/woocommerce-payments/dist/woopay-express-button-rtl.css 153 B
release/woocommerce-payments/dist/woopay-express-button.css 153 B
release/woocommerce-payments/dist/woopay-express-button.js 52.6 kB
release/woocommerce-payments/dist/woopay-rtl.css 4.18 kB
release/woocommerce-payments/dist/woopay.css 4.19 kB
release/woocommerce-payments/dist/woopay.js 70.9 kB
release/woocommerce-payments/includes/subscriptions/assets/css/plugin-page.css 622 B
release/woocommerce-payments/includes/subscriptions/assets/js/plugin-page.js 812 B
release/woocommerce-payments/vendor/automattic/jetpack-assets/build/i18n-loader.js 2.43 kB
release/woocommerce-payments/vendor/automattic/jetpack-assets/src/js/i18n-loader.js 1.01 kB
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/tracks-ajax.js 522 B
release/woocommerce-payments/vendor/automattic/jetpack-connection/dist/tracks-callables.js 581 B
release/woocommerce-payments/vendor/automattic/jetpack-identity-crisis/babel.config.js 160 B
release/woocommerce-payments/vendor/automattic/jetpack-identity-crisis/build/index.css 2.37 kB
release/woocommerce-payments/vendor/automattic/jetpack-identity-crisis/build/index.js 13.5 kB
release/woocommerce-payments/vendor/automattic/jetpack-identity-crisis/build/index.rtl.css 2.37 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/about.css 1.03 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/admin-empty-state.css 291 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/admin-order-statuses.css 403 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/admin.css 3.6 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/checkout.css 299 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/modal.css 742 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/view-subscription.css 572 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/css/wcs-upgrade.css 411 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/admin-pointers.js 544 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/admin.js 9.4 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/jstz.js 6.8 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/jstz.min.js 3.83 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/meta-boxes-coupon.js 544 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/meta-boxes-subscription.js 2.52 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/moment.js 22.1 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/moment.min.js 11.6 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/payment-method-restrictions.js 1.29 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/admin/wcs-meta-boxes-order.js 502 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/frontend/payment-methods.js 355 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/frontend/single-product.js 429 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/frontend/view-subscription.js 1.38 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/frontend/wcs-cart.js 781 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/modal.js 1.1 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/assets/js/wcs-upgrade.js 1.27 kB
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/build/index.css 392 B
release/woocommerce-payments/vendor/woocommerce/subscriptions-core/build/index.js 3.05 kB

compressed-size-action

Copy link
Contributor

@frosso frosso left a comment

Choose a reason for hiding this comment

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

Looking good, just a minor suggestion to decrease the indentation

Comment on lines 594 to 603
$status_code = 400;
if ( $e instanceof API_Exception ) {
return $e->get_http_code() ?? 400;
$status_code = $e->get_http_code() ?? 400;
// Sometimes hosting companies hijack this status code and return their own predefined error page.
// In this case, we want to return a 400 instead, since it will break the flow of the checkout page.
if ( 402 === $status_code ) {
$status_code = 400;
}
}
return 400;
return $status_code;
Copy link
Contributor

Choose a reason for hiding this comment

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

What are your thoughts on the following alternative, to decrease the indentation due to the cyclomatic complexity?

		$status_code = null;
		if ( $e instanceof API_Exception ) {
			$status_code = $e->get_http_code();
		}

		// Sometimes hosting companies hijack the 402 status code to return their own predefined error page.
		// In this case, we want to return a 400 instead, since it will break the flow of the checkout page.
		if ( 402 === $status_code ) {
			$status_code = 400;
		}

		return $status_code ?? 400;

Copy link
Contributor

Choose a reason for hiding this comment

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

@frosso's suggestion is easier to read 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Addressed here: ffb36ec . Thank you for the feedback.

Copy link
Contributor

@naman03malhotra naman03malhotra left a comment

Choose a reason for hiding this comment

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

I haven't tested it, but left some code quality related comments.

Comment on lines 596 to 601
$status_code = $e->get_http_code() ?? 400;
// Sometimes hosting companies hijack this status code and return their own predefined error page.
// In this case, we want to return a 400 instead, since it will break the flow of the checkout page.
if ( 402 === $status_code ) {
$status_code = 400;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

@zmaglica do you plan to add a test for this change? As I checked the test file does exist.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@zmaglica do you plan to add a test for this change? As I checked the test file does exist.

I am not planning to write tests in this PR for this file, since the tests for this particular file don't exist, as you mentioned too. I will keep this PR as clean as possible and open a new issue to address the issue with the tests.

Copy link
Contributor

Choose a reason for hiding this comment

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

@zmaglica I meant the test file, which is this, does exist :))

IMO, it is always a good idea to write test in the same PR.

Comment on lines 594 to 603
$status_code = 400;
if ( $e instanceof API_Exception ) {
return $e->get_http_code() ?? 400;
$status_code = $e->get_http_code() ?? 400;
// Sometimes hosting companies hijack this status code and return their own predefined error page.
// In this case, we want to return a 400 instead, since it will break the flow of the checkout page.
if ( 402 === $status_code ) {
$status_code = 400;
}
}
return 400;
return $status_code;
Copy link
Contributor

Choose a reason for hiding this comment

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

@frosso's suggestion is easier to read 👍

@naman03malhotra
Copy link
Contributor

The discussion is underway if we should go this route or not.

@jrodger would it okay that we wait for your +1 before merging this?

@jrodger
Copy link
Contributor

jrodger commented Feb 12, 2024

@jrodger would it okay that we wait for your +1 before merging this?

We can go ahead and get this merged. I like that the code is well commented with the reasoning for the change, so if we did decide to remove it in the future it would be easy to understand what was being taken out.

One question, I think I saw that @zmaglica investigated this elsewhere already, but we're definitely not relying on returning the 402 code anywhere in the JavaScript code right?

@zmaglica
Copy link
Contributor Author

@jrodger would it okay that we wait for your +1 before merging this?

We can go ahead and get this merged. I like that the code is well commented with the reasoning for the change, so if we did decide to remove it in the future it would be easy to understand what was being taken out.

One question, I think I saw that @zmaglica investigated this elsewhere already, but we're definitely not relying on returning the 402 code anywhere in the JavaScript code right?

402 can occur on adding the payment method and on the checkout page. I think we still need to address the 402 error on the checkout page. Let me take a look a bit more, and I will comment here results.

Copy link
Contributor

@dmvrtx dmvrtx left a comment

Choose a reason for hiding this comment

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

Looks good to me, code check only.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
6 participants