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

fix: Store API tokenized cart nonce verification #8840

Merged
merged 4 commits into from
May 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions changelog/fix-store-api-tokenized-cart-nonce-verification
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: fix

fix: Store API tokenized cart nonce verification
3 changes: 3 additions & 0 deletions client/tokenized-payment-request/cart-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ export default class PaymentRequestCartApi {

this.cartRequestHeaders = {
Nonce: response.headers.get( 'Nonce' ),
// this header will be overwritten by a filter in the backend to overcome nonce overwrites in this middleware:
// https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce-blocks/assets/js/middleware/store-api-nonce.js
'X-WooPayments-Store-Api-Nonce': response.headers.get( 'Nonce' ),
'Cart-Token': response.headers.get( 'Cart-Token' ),
'X-WooPayments-Express-Payment-Request-Nonce': response.headers.get(
'X-WooPayments-Express-Payment-Request-Nonce'
Expand Down
24 changes: 24 additions & 0 deletions includes/class-wc-payments-payment-request-button-handler.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ public function init() {

if ( WC_Payments_Features::is_tokenized_cart_prb_enabled() ) {
add_filter( 'rest_pre_dispatch', [ $this, 'tokenized_cart_store_api_address_normalization' ], 10, 3 );
add_filter( 'rest_pre_dispatch', [ $this, 'tokenized_cart_store_api_nonce_overwrite' ], 10, 3 );
add_filter(
'rest_post_dispatch',
[ $this, 'tokenized_cart_store_api_nonce_headers' ],
Expand All @@ -120,6 +121,29 @@ public function init() {
}
}

/**
* The nonce supplied by the frontend can be overwritten in this middleware:
* https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce-blocks/assets/js/middleware/store-api-nonce.js
*
* This is a workaround to use instead a different nonce key, when supplied.
*
* @param mixed $response Response to replace the requested version with.
* @param \WP_REST_Server $server Server instance.
* @param \WP_REST_Request $request Request used to generate the response.
*
* @return mixed
*/
public function tokenized_cart_store_api_nonce_overwrite( $response, $server, $request ) {
$nonce = $request->get_header( 'X-WooPayments-Store-Api-Nonce' );
if ( empty( $nonce ) ) {
return $response;
}

$request->set_header( 'Nonce', $nonce );

return $response;
}

/**
* Google Pay/Apple Pay parameters for address data might need some massaging for some of the countries.
* Ensuring that the Store API doesn't throw a `rest_invalid_param` error message for some of those scenarios.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,28 @@ private static function get_shipping_option_rate_id( $instance_id ) {
return $method->get_rate_id();
}

public function test_tokenized_cart_nonce_overwrite_when_header_not_present() {
$request = new WP_REST_Request();
$request->set_header( 'X-WooPayments-Store-Api-Nonce', null );
$request->set_header( 'Nonce', 'original-nonce-value' );
$request->set_header( 'Content-Type', 'application/json' );

$this->pr->tokenized_cart_store_api_nonce_overwrite( null, null, $request );

$this->assertSame( 'original-nonce-value', $request->get_header( 'Nonce' ) );
}

public function test_tokenized_cart_nonce_overwrite_when_header_is_present() {
$request = new WP_REST_Request();
$request->set_header( 'X-WooPayments-Store-Api-Nonce', 'new-nonce-value' );
$request->set_header( 'Nonce', 'original-nonce-value' );
$request->set_header( 'Content-Type', 'application/json' );

$this->pr->tokenized_cart_store_api_nonce_overwrite( null, null, $request );

$this->assertSame( 'new-nonce-value', $request->get_header( 'Nonce' ) );
}

public function test_tokenized_cart_address_avoid_normalization_when_missing_header() {
$request = new WP_REST_Request();
$request->set_header( 'X-WooPayments-Express-Payment-Request', null );
Expand Down
Loading