From 6dd0034c0a15a4bc09588bef4667e7f88456442a Mon Sep 17 00:00:00 2001
From: Philipp Stracker
Date: Wed, 26 Feb 2025 10:35:43 +0100
Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=A7=20non-working=20version=20of=20int?=
=?UTF-8?q?ernal=20REST=20service?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
modules/ppcp-settings/services.php | 11 +++-
.../src/Endpoint/CommonRestEndpoint.php | 65 ++++++++++++++++++-
.../src/Service/AuthenticationManager.php | 58 ++++++++---------
.../src/Service/InternalRestService.php | 57 ++++++++++++++++
4 files changed, 154 insertions(+), 37 deletions(-)
create mode 100644 modules/ppcp-settings/src/Service/InternalRestService.php
diff --git a/modules/ppcp-settings/services.php b/modules/ppcp-settings/services.php
index d2dd9df97..edb8b37d6 100644
--- a/modules/ppcp-settings/services.php
+++ b/modules/ppcp-settings/services.php
@@ -49,6 +49,7 @@ use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
use WooCommerce\PayPalCommerce\PayLaterConfigurator\Endpoint\SaveConfig;
use WooCommerce\PayPalCommerce\WcGateway\Helper\Environment;
use WooCommerce\PayPalCommerce\WcGateway\Helper\ConnectionState;
+use WooCommerce\PayPalCommerce\Settings\Service\InternalRestService;
return array(
'settings.url' => static function ( ContainerInterface $container ) : string {
@@ -172,7 +173,10 @@ return array(
return new OnboardingRestEndpoint( $container->get( 'settings.data.onboarding' ) );
},
'settings.rest.common' => static function ( ContainerInterface $container ) : CommonRestEndpoint {
- return new CommonRestEndpoint( $container->get( 'settings.data.general' ) );
+ return new CommonRestEndpoint(
+ $container->get( 'settings.data.general' ),
+ $container->get( 'settings.service.rest-service' )
+ );
},
'settings.rest.payment' => static function ( ContainerInterface $container ) : PaymentRestEndpoint {
return new PaymentRestEndpoint(
@@ -313,10 +317,13 @@ return array(
$container->get( 'api.env.endpoint.login-seller' ),
$container->get( 'api.repository.partner-referrals-data' ),
$container->get( 'settings.connection-state' ),
- $container->get( 'api.endpoint.partners' ),
+ $container->get( 'settings.service.rest-service' ),
$container->get( 'woocommerce.logger.woocommerce' )
);
},
+ 'settings.service.rest-service' => static function ( ContainerInterface $container ) : InternalRestService {
+ return new InternalRestService();
+ },
'settings.service.sanitizer' => static function ( ContainerInterface $container ) : DataSanitizer {
return new DataSanitizer();
},
diff --git a/modules/ppcp-settings/src/Endpoint/CommonRestEndpoint.php b/modules/ppcp-settings/src/Endpoint/CommonRestEndpoint.php
index bbd29c744..82aa06b29 100644
--- a/modules/ppcp-settings/src/Endpoint/CommonRestEndpoint.php
+++ b/modules/ppcp-settings/src/Endpoint/CommonRestEndpoint.php
@@ -13,6 +13,7 @@ use WP_REST_Server;
use WP_REST_Response;
use WP_REST_Request;
use WooCommerce\PayPalCommerce\Settings\Data\GeneralSettings;
+use WooCommerce\PayPalCommerce\Settings\Service\InternalRestService;
/**
* REST controller for "common" settings, which are used and modified by
@@ -22,6 +23,11 @@ use WooCommerce\PayPalCommerce\Settings\Data\GeneralSettings;
* internal data model.
*/
class CommonRestEndpoint extends RestEndpoint {
+ /**
+ * Full REST path to the merchant-details endpoint, relative to the namespace.
+ */
+ protected const SELLER_ACCOUNT_PATH = 'common/seller-account';
+
/**
* The base path for this REST controller.
*
@@ -36,6 +42,13 @@ class CommonRestEndpoint extends RestEndpoint {
*/
protected GeneralSettings $settings;
+ /**
+ * Internal REST handler, used to authenticate internal requests.
+ *
+ * @var InternalRestService
+ */
+ protected InternalRestService $rest_service;
+
/**
* Field mapping for request to profile transformation.
*
@@ -104,10 +117,27 @@ class CommonRestEndpoint extends RestEndpoint {
/**
* Constructor.
*
- * @param GeneralSettings $settings The settings instance.
+ * @param GeneralSettings $settings The settings instance.
+ * @param InternalRestService $rest_service Internal REST handler, for authentication.
*/
- public function __construct( GeneralSettings $settings ) {
- $this->settings = $settings;
+ public function __construct( GeneralSettings $settings, InternalRestService $rest_service ) {
+ $this->settings = $settings;
+ $this->rest_service = $rest_service;
+ }
+
+ /**
+ * Returns the path to the "Get Seller Account Details" REST route.
+ * This is an internal route which is consumed by the plugin itself during onboarding.
+ *
+ * @param bool $full_route Whether to return the full endpoint path or just the route name.
+ * @return string The full path to the REST endpoint.
+ */
+ public static function seller_account_route( bool $full_route = false ) : string {
+ if ( $full_route ) {
+ return '/' . static::NAMESPACE . '/' . self::SELLER_ACCOUNT_PATH;
+ }
+
+ return self::SELLER_ACCOUNT_PATH;
}
/**
@@ -155,6 +185,24 @@ class CommonRestEndpoint extends RestEndpoint {
'permission_callback' => array( $this, 'check_permission' ),
)
);
+
+ /**
+ * GET /wp-json/wc/v3/wc_paypal/common/seller-account
+ */
+ register_rest_route(
+ static::NAMESPACE,
+ self::seller_account_route(),
+ array(
+ 'methods' => WP_REST_Server::READABLE,
+ 'callback' => array( $this, 'get_seller_account_info' ),
+ 'permission_callback' => function ( WP_REST_Request $request ) {
+ $token = $request->get_header( 'X-Internal-Token' );
+ $endpoint = self::seller_account_route();
+
+ return $this->rest_service->verify_token( $token, $endpoint );
+ },
+ )
+ );
}
/**
@@ -205,6 +253,17 @@ class CommonRestEndpoint extends RestEndpoint {
return $this->return_success( $js_data, $extra_data );
}
+ /**
+ * Requests details from the PayPal API.
+ *
+ * Used during onboarding to enrich the merchant details in the DB.
+ *
+ * @return WP_REST_Response Seller details, provided by PayPal's API.
+ */
+ public function get_seller_account_info() : WP_REST_Response {
+ return $this->return_success( array( 'country' => 'XY' ) );
+ }
+
/**
* Appends the "merchant" attribute to the extra_data collection, which
* contains details about the merchant's PayPal account, like the merchant ID.
diff --git a/modules/ppcp-settings/src/Service/AuthenticationManager.php b/modules/ppcp-settings/src/Service/AuthenticationManager.php
index 1637c73a6..b48a7554a 100644
--- a/modules/ppcp-settings/src/Service/AuthenticationManager.php
+++ b/modules/ppcp-settings/src/Service/AuthenticationManager.php
@@ -27,6 +27,7 @@ use WooCommerce\PayPalCommerce\Settings\DTO\MerchantConnectionDTO;
use WooCommerce\PayPalCommerce\Webhooks\WebhookRegistrar;
use WooCommerce\PayPalCommerce\Settings\Enum\SellerTypeEnum;
use WooCommerce\PayPalCommerce\WcGateway\Helper\ConnectionState;
+use WooCommerce\PayPalCommerce\Settings\Endpoint\CommonRestEndpoint;
/**
* Class that manages the connection to PayPal.
@@ -75,22 +76,22 @@ class AuthenticationManager {
private ConnectionState $connection_state;
/**
- * Partners endpoint.
+ * Internal REST service, to consume own REST handlers in a separate request.
*
- * @var PartnersEndpoint
+ * @var InternalRestService
*/
- private PartnersEndpoint $partners_endpoint;
+ private InternalRestService $rest_service;
/**
* Constructor.
*
- * @param GeneralSettings $common_settings Data model that stores the connection details.
- * @param EnvironmentConfig $connection_host API host for direct authentication.
- * @param EnvironmentConfig $login_endpoint API handler to fetch merchant credentials.
- * @param PartnerReferralsData $referrals_data Partner referrals data.
- * @param ConnectionState $connection_state Connection state manager.
- * @param PartnersEndpoint $partners_endpoint Partners endpoint.
- * @param ?LoggerInterface $logger Logging instance.
+ * @param GeneralSettings $common_settings Data model that stores the connection details.
+ * @param EnvironmentConfig $connection_host API host for direct authentication.
+ * @param EnvironmentConfig $login_endpoint API handler to fetch merchant credentials.
+ * @param PartnerReferralsData $referrals_data Partner referrals data.
+ * @param ConnectionState $connection_state Connection state manager.
+ * @param InternalRestService $rest_service Allows calling internal REST endpoints.
+ * @param ?LoggerInterface $logger Logging instance.
*/
public function __construct(
GeneralSettings $common_settings,
@@ -98,16 +99,16 @@ class AuthenticationManager {
EnvironmentConfig $login_endpoint,
PartnerReferralsData $referrals_data,
ConnectionState $connection_state,
- PartnersEndpoint $partners_endpoint,
+ InternalRestService $rest_service,
?LoggerInterface $logger = null
) {
- $this->common_settings = $common_settings;
- $this->connection_host = $connection_host;
- $this->login_endpoint = $login_endpoint;
- $this->referrals_data = $referrals_data;
- $this->connection_state = $connection_state;
- $this->partners_endpoint = $partners_endpoint;
- $this->logger = $logger ?: new NullLogger();
+ $this->common_settings = $common_settings;
+ $this->connection_host = $connection_host;
+ $this->login_endpoint = $login_endpoint;
+ $this->referrals_data = $referrals_data;
+ $this->connection_state = $connection_state;
+ $this->rest_service = $rest_service;
+ $this->logger = $logger ?: new NullLogger();
}
/**
@@ -281,17 +282,10 @@ class AuthenticationManager {
*/
$connection = $this->common_settings->get_merchant_data();
- try {
- $seller_status = $this->partners_endpoint->seller_status();
- } catch ( PayPalApiException $exception ) {
- $seller_status = null;
- }
-
- $connection->is_sandbox = $use_sandbox;
- $connection->client_id = $credentials['client_id'];
- $connection->client_secret = $credentials['client_secret'];
- $connection->merchant_id = $credentials['merchant_id'];
- $connection->merchant_country = ! is_null( $seller_status ) ? $seller_status->country() : '';
+ $connection->is_sandbox = $use_sandbox;
+ $connection->client_id = $credentials['client_id'];
+ $connection->client_secret = $credentials['client_secret'];
+ $connection->merchant_id = $credentials['merchant_id'];
$this->update_connection_details( $connection );
}
@@ -451,14 +445,14 @@ class AuthenticationManager {
}
try {
- // TODO: this call only reliably works in the _next_ request, because in the current request the PartnersEndpoint instance might be initialized with an empty merchant_id.
- $seller_status = $this->partners_endpoint->seller_status();
+ $endpoint = CommonRestEndpoint::seller_account_route( true );
+ $details = $this->rest_service->get_data( $endpoint );
// Request the merchant details via a PayPal API request.
$connection = $this->common_settings->get_merchant_data();
// Enrich the connection details with additional details.
- $connection->merchant_country = $seller_status->country();
+ $connection->merchant_country = $details['country'];
// Persist the changes.
$this->common_settings->set_merchant_data( $connection );
diff --git a/modules/ppcp-settings/src/Service/InternalRestService.php b/modules/ppcp-settings/src/Service/InternalRestService.php
new file mode 100644
index 000000000..a83e5fdcf
--- /dev/null
+++ b/modules/ppcp-settings/src/Service/InternalRestService.php
@@ -0,0 +1,57 @@
+generate_token( $endpoint );
+ $rest_url = rest_url( $endpoint );
+
+ $response = wp_remote_get(
+ $rest_url,
+ array(
+ 'headers' => array(
+ 'X-Internal-Token' => $token,
+ 'Content-Type' => 'application/json',
+ ),
+ )
+ );
+
+ if ( is_wp_error( $response ) ) {
+ return array();
+ }
+
+ $body = wp_remote_retrieve_body( $response );
+
+ try {
+ $json = json_decode( $body, true, 512, JSON_THROW_ON_ERROR );
+ } catch ( Throwable $exception ) {
+ return array();
+ }
+
+ if ( ! $json || empty( $json['success'] ) ) {
+ return array();
+ }
+
+ return $json['data'];
+ }
+
+ public function verify_token( string $token, string $endpoint ) : bool {
+ $expected_token = $this->generate_token( $endpoint );
+
+ return $expected_token === $token;
+ }
+
+ private function generate_token( string $token_id ) : string {
+ return base64_encode( $token_id );
+ }
+}