From 3aed780443418c9cbc6054fa78ba45f8d74a0ba8 Mon Sep 17 00:00:00 2001 From: Rodrigo Primo Date: Tue, 8 Sep 2020 16:31:39 -0300 Subject: [PATCH 1/2] Paypal gateway: protect code against a fatal error This commit changes the order of the error handling check to protect the code against a possible fatal error if wp_safe_remote_post() returns an instance of WP_Error(). --- .../includes/class-wc-gateway-paypal-api-handler.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/includes/gateways/paypal/includes/class-wc-gateway-paypal-api-handler.php b/includes/gateways/paypal/includes/class-wc-gateway-paypal-api-handler.php index 445e250bed5..6d012d4ecc6 100644 --- a/includes/gateways/paypal/includes/class-wc-gateway-paypal-api-handler.php +++ b/includes/gateways/paypal/includes/class-wc-gateway-paypal-api-handler.php @@ -115,10 +115,10 @@ class WC_Gateway_Paypal_API_Handler { WC_Gateway_Paypal::log( 'DoCapture Response: ' . wc_print_r( $raw_response, true ) ); - if ( empty( $raw_response['body'] ) ) { - return new WP_Error( 'paypal-api', 'Empty Response' ); - } elseif ( is_wp_error( $raw_response ) ) { + if ( is_wp_error( $raw_response ) ) { return $raw_response; + } elseif ( empty( $raw_response['body'] ) ) { + return new WP_Error( 'paypal-api', 'Empty Response' ); } parse_str( $raw_response['body'], $response ); @@ -148,10 +148,10 @@ class WC_Gateway_Paypal_API_Handler { WC_Gateway_Paypal::log( 'Refund Response: ' . wc_print_r( $raw_response, true ) ); - if ( empty( $raw_response['body'] ) ) { - return new WP_Error( 'paypal-api', 'Empty Response' ); - } elseif ( is_wp_error( $raw_response ) ) { + if ( is_wp_error( $raw_response ) ) { return $raw_response; + } elseif ( empty( $raw_response['body'] ) ) { + return new WP_Error( 'paypal-api', 'Empty Response' ); } parse_str( $raw_response['body'], $response ); From 140dafb704e14124f86cdd727208ad7b9fedc368 Mon Sep 17 00:00:00 2001 From: vedanshujain Date: Fri, 18 Sep 2020 17:12:33 +0530 Subject: [PATCH 2/2] Add unit tests for when PayPal API will return error --- .../paypal/class-wc-gateway-paypal-test.php | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 tests/php/includes/gateways/paypal/class-wc-gateway-paypal-test.php diff --git a/tests/php/includes/gateways/paypal/class-wc-gateway-paypal-test.php b/tests/php/includes/gateways/paypal/class-wc-gateway-paypal-test.php new file mode 100644 index 00000000000..3fb1c7a919f --- /dev/null +++ b/tests/php/includes/gateways/paypal/class-wc-gateway-paypal-test.php @@ -0,0 +1,98 @@ +save(); + + update_post_meta( $order->get_id(), '_paypal_status', 'pending' ); + update_post_meta( $order->get_id(), '_transaction_id', $this->transaction_id_26960 ); + $order->set_payment_method( 'paypal' ); + $order->save(); + + // Force HTTP error. + add_filter( 'pre_http_request', array( $this, '__return_paypal_error' ), 10, 2 ); + + ( new WC_Gateway_Paypal() )->capture_payment( $order->get_id() ); + + // reset error. + remove_filter( 'pre_http_request', array( $this, '__return_paypal_error' ) ); + + $order_notes = wc_get_order_notes( array( 'order_id' => $order->get_id() ) ); + $latest_note = current( $order_notes ); + $this->assertContains( $this->error_message_26960, $latest_note->content ); + } + + /** + * Test do_capture when API returns error. + * + * see @link https://github.com/woocommerce/woocommerce/issues/26960 + */ + public function test_refund_transaction_when_api_return_error() { + $order = WC_Helper_Order::create_order(); + $order->save(); + + update_post_meta( $order->get_id(), '_paypal_status', 'pending' ); + update_post_meta( $order->get_id(), '_transaction_id', $this->transaction_id_26960 ); + $order->set_payment_method( 'paypal' ); + $order->save(); + + // Force HTTP error. + add_filter( 'pre_http_request', array( $this, '__return_paypal_error' ), 10, 2 ); + + // Force refunds check to true. + $paypal_gateway = $this->getMockBuilder( WC_Gateway_Paypal::class )->setMethods( array( 'can_refund_order' ) )->getMock(); + $paypal_gateway->method( 'can_refund_order' )->willReturn( 'true' ); + + $response = $paypal_gateway->process_refund( $order ); + + // reset error. + remove_filter( 'pre_http_request', array( $this, '__return_paypal_error' ) ); + + $this->assertWPError( $response ); + $this->assertContains( $this->error_message_26960, $response->get_error_message() ); + } + + /** + * Utility function for raising error when this is a PayPal request using transaction_id_26960. + * + * @param bool $value Original pre-value, likely to be false. + * @param array $parsed_url Parsed URL object. + * + * @return bool|WP_Error Raise error or return original value. + */ + public function __return_paypal_error( $value, $parsed_url ) { + if ( isset( $parsed_url['body'] ) && isset( $parsed_url['body']['AUTHORIZATIONID'] ) && $this->transaction_id_26960 === $parsed_url['body']['AUTHORIZATIONID'] ) { + return new WP_Error( 'error', $this->error_message_26960 ); + } + if ( isset( $parsed_url['body'] ) && isset( $parsed_url['body']['TRANSACTIONID'] ) && $this->transaction_id_26960 === $parsed_url['body']['TRANSACTIONID'] ) { + return new WP_Error( 'error', $this->error_message_26960 ); + } + return $value; + } + +}