224 lines
7.1 KiB
PHP
224 lines
7.1 KiB
PHP
<?php
|
|
/**
|
|
* WC_Payments_Http class.
|
|
*
|
|
* @package WooCommerce\Payments
|
|
*/
|
|
|
|
defined( 'ABSPATH' ) || exit;
|
|
|
|
use WCPay\Exceptions\API_Exception;
|
|
use WCPay\Exceptions\Connection_Exception;
|
|
use WCPay\Logger;
|
|
|
|
/**
|
|
* A wrapper around Jetpack HTTP request library. Necessary to increase
|
|
* the testability of WC_Payments_API_Client, and allow dependency
|
|
* injection.
|
|
*/
|
|
class WC_Payments_Http implements WC_Payments_Http_Interface {
|
|
|
|
/**
|
|
* Jetpack connection handler.
|
|
*
|
|
* @var Automattic\Jetpack\Connection\Manager
|
|
*/
|
|
private $connection_manager;
|
|
|
|
/**
|
|
* WC_Payments_Http constructor.
|
|
*
|
|
* @param Automattic\Jetpack\Connection\Manager $connection_manager - Jetpack connection handler.
|
|
*/
|
|
public function __construct( $connection_manager ) {
|
|
$this->connection_manager = $connection_manager;
|
|
}
|
|
|
|
/**
|
|
* Initializes this class's WP hooks.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function init_hooks() {
|
|
add_filter( 'allowed_redirect_hosts', [ $this, 'allowed_redirect_hosts' ] );
|
|
}
|
|
|
|
/**
|
|
* Sends a remote request through Jetpack.
|
|
*
|
|
* @param array $args - The arguments to passed to Jetpack.
|
|
* @param string $body - The body passed on to the HTTP request.
|
|
* @param bool $is_site_specific - If true, the site ID will be included in the request url. Defaults to true.
|
|
* @param bool $use_user_token - If true, the request will be signed with the Jetpack connection owner user token rather than blog token. Defaults to false.
|
|
*
|
|
* @return array HTTP response on success.
|
|
* @throws API_Exception - If not connected or request failed.
|
|
*/
|
|
public function remote_request( $args, $body = null, $is_site_specific = true, $use_user_token = false ) {
|
|
// Make sure we're not sending requests if Jetpack is not connected.
|
|
if ( ! $this->is_connected() ) {
|
|
Logger::error( 'HTTP_REQUEST_ERROR Site is not connected to WordPress.com' );
|
|
throw new API_Exception(
|
|
__( 'Site is not connected to WordPress.com', 'woocommerce-payments' ),
|
|
'wcpay_wpcom_not_connected',
|
|
409 // HTTP Conflict status code.
|
|
);
|
|
}
|
|
|
|
$args['blog_id'] = $this->get_blog_id();
|
|
|
|
if ( $use_user_token ) {
|
|
$args['user_id'] = $this->connection_manager->get_connection_owner_id();
|
|
}
|
|
|
|
if ( $is_site_specific ) {
|
|
// We expect `url` to include a `%s` placeholder which will allow us inject the blog id.
|
|
$url = explode( '?', $args['url'], 2 );
|
|
$url[0] = sprintf( $url[0], $args['blog_id'] );
|
|
$args['url'] = implode( '?', $url );
|
|
}
|
|
|
|
return self::make_request( $args, $body );
|
|
}
|
|
|
|
/**
|
|
* Queries the WordPress.com REST API with a user token.
|
|
*
|
|
* @param string $path REST API path.
|
|
* @param string $version REST API version. Default is `2`.
|
|
* @param array $args Arguments to {@see WP_Http}. Default is `array()`.
|
|
* @param string|array $body Body passed to {@see WP_Http}. Default is `null`.
|
|
* @param string $base_api_path REST API root. Default is `wpcom`.
|
|
*
|
|
* @return array|\WP_Error $response Response data, else WP_Error on failure.
|
|
*/
|
|
public function wpcom_json_api_request_as_user(
|
|
$path,
|
|
$version = '2',
|
|
$args = [],
|
|
$body = null,
|
|
$base_api_path = 'wpcom'
|
|
) {
|
|
return Automattic\Jetpack\Connection\Client::wpcom_json_api_request_as_user( $path, $version, $args, $body, $base_api_path );
|
|
}
|
|
|
|
/**
|
|
* Makes a request through Jetpack.
|
|
*
|
|
* @param array $args - The arguments passed to Jetpack.
|
|
* @param string $body - The body passed to the HTTP request.
|
|
*
|
|
* @return array HTTP response on success.
|
|
* @throws Connection_Exception - If request returns WP_Error.
|
|
*/
|
|
private static function make_request( $args, $body ) {
|
|
$response = Automattic\Jetpack\Connection\Client::remote_request( $args, $body );
|
|
|
|
if ( is_wp_error( $response ) || ! is_array( $response ) ) {
|
|
Logger::error( 'HTTP_REQUEST_ERROR ' . var_export( $response, true ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_var_export
|
|
$message = sprintf(
|
|
// translators: %1: original error message.
|
|
__( 'Http request failed. Reason: %1$s', 'woocommerce-payments' ),
|
|
$response->get_error_message()
|
|
);
|
|
throw new Connection_Exception( $message, 'wcpay_http_request_failed', 500 );
|
|
}
|
|
|
|
return $response;
|
|
}
|
|
|
|
/**
|
|
* Checks if Jetpack is connected.
|
|
*
|
|
* Checks if connection is authenticated in the same way as Jetpack_Client or Jetpack Connection Client does.
|
|
*
|
|
* @return bool true if Jetpack connection has access token.
|
|
*/
|
|
public function is_connected() {
|
|
return $this->connection_manager->is_connected() && $this->connection_manager->has_connected_owner();
|
|
}
|
|
|
|
|
|
/**
|
|
* Checks if the current user is connected to WordPress.com.
|
|
*
|
|
* @return bool true if the current user is connected.
|
|
*/
|
|
public function is_user_connected() {
|
|
return $this->connection_manager->is_user_connected();
|
|
}
|
|
|
|
/**
|
|
* Get the wpcom user data of the current connected user.
|
|
*
|
|
* @return bool|array An array with the WPCOM user data on success, false otherwise.
|
|
*/
|
|
public function get_connected_user_data() {
|
|
return $this->connection_manager->get_connected_user_data();
|
|
}
|
|
|
|
/**
|
|
* Checks if the site has an admin who is also a connection owner.
|
|
*
|
|
* @return bool True if Jetpack connection has an owner.
|
|
*/
|
|
public function has_connection_owner() {
|
|
return ! empty( $this->connection_manager->get_connection_owner_id() );
|
|
}
|
|
|
|
/**
|
|
* Gets the current WP.com blog ID.
|
|
*
|
|
* @return integer Current WPCOM blog ID.
|
|
*/
|
|
public function get_blog_id() {
|
|
return Jetpack_Options::get_option( 'id' );
|
|
}
|
|
|
|
/**
|
|
* Starts the Jetpack connection process. Note that running this function will immediately redirect
|
|
* to the Jetpack flow, so any PHP code after it will never be executed.
|
|
*
|
|
* @param string $redirect - URL to redirect to after the connection process is over.
|
|
*
|
|
* @throws API_Exception - Exception thrown on failure.
|
|
*/
|
|
public function start_connection( $redirect ) {
|
|
// Register the site to wp.com.
|
|
if ( ! $this->connection_manager->is_connected() ) {
|
|
$result = $this->connection_manager->try_registration();
|
|
if ( is_wp_error( $result ) ) {
|
|
throw new API_Exception( $result->get_error_message(), 'wcpay_jetpack_register_site_failed', 500 );
|
|
}
|
|
}
|
|
|
|
// Redirect the user to the Jetpack user connection flow.
|
|
add_filter( 'jetpack_use_iframe_authorization_flow', '__return_false' );
|
|
// Same logic as in WC-Admin.
|
|
$calypso_env = defined( 'WOOCOMMERCE_CALYPSO_ENVIRONMENT' ) && in_array( WOOCOMMERCE_CALYPSO_ENVIRONMENT, [ 'development', 'wpcalypso', 'horizon', 'stage' ], true ) ? WOOCOMMERCE_CALYPSO_ENVIRONMENT : 'production';
|
|
wp_safe_redirect(
|
|
add_query_arg(
|
|
[
|
|
'from' => 'woocommerce-core-profiler',
|
|
'plugin_name' => 'woocommerce-payments',
|
|
'calypso_env' => $calypso_env,
|
|
],
|
|
$this->connection_manager->get_authorization_url( null, $redirect )
|
|
)
|
|
);
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Filter function to add WP.com to the list of allowed redirect hosts
|
|
*
|
|
* @param array $hosts - array of allowed hosts.
|
|
*
|
|
* @return array allowed hosts
|
|
*/
|
|
public function allowed_redirect_hosts( $hosts ) {
|
|
$hosts[] = 'jetpack.wordpress.com';
|
|
return $hosts;
|
|
}
|
|
}
|