mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-06 14:57:26 +08:00
Add previous token validation for OnboardingUrl
Add retries on listen_for_merchant_id() to wait for client_id and signature
This commit is contained in:
parent
a35bea207e
commit
c035cdaf3e
6 changed files with 184 additions and 17 deletions
|
@ -66,6 +66,13 @@ class OnboardingUrl {
|
|||
*/
|
||||
private $cache_ttl = 3 * MONTH_IN_SECONDS;
|
||||
|
||||
/**
|
||||
* The TTL for the previous token cache.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $previous_cache_ttl = 60;
|
||||
|
||||
/**
|
||||
* The constructor
|
||||
*
|
||||
|
@ -84,20 +91,19 @@ class OnboardingUrl {
|
|||
}
|
||||
|
||||
/**
|
||||
* Validates the token, if it's valid then delete it.
|
||||
* If it's invalid don't delete it, to prevent malicious requests from invalidating the token.
|
||||
* Instances the object with a $token.
|
||||
*
|
||||
* @param Cache $cache The cache object where the URL is stored.
|
||||
* @param string $onboarding_token The token to validate.
|
||||
* @param string $token The token to validate.
|
||||
* @param int $user_id User ID to associate the link with.
|
||||
* @return bool
|
||||
* @return false|self
|
||||
*/
|
||||
public static function validate_token_and_delete( Cache $cache, string $onboarding_token, int $user_id ): bool {
|
||||
if ( ! $onboarding_token ) {
|
||||
public static function make_from_token( Cache $cache, string $token, int $user_id ) {
|
||||
if ( ! $token ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$token_data = json_decode( UrlHelper::url_safe_base64_decode( $onboarding_token ) ?: '', true );
|
||||
$token_data = json_decode( UrlHelper::url_safe_base64_decode( $token ) ?: '', true );
|
||||
|
||||
if ( ! $token_data ) {
|
||||
return false;
|
||||
|
@ -111,20 +117,57 @@ class OnboardingUrl {
|
|||
return false;
|
||||
}
|
||||
|
||||
$onboarding_url = new self( $cache, $token_data['k'], $token_data['u'] );
|
||||
return new self( $cache, $token_data['k'], $token_data['u'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the token, if it's valid then delete it.
|
||||
* If it's invalid don't delete it, to prevent malicious requests from invalidating the token.
|
||||
*
|
||||
* @param Cache $cache The cache object where the URL is stored.
|
||||
* @param string $token The token to validate.
|
||||
* @param int $user_id User ID to associate the link with.
|
||||
* @return bool
|
||||
*/
|
||||
public static function validate_token_and_delete( Cache $cache, string $token, int $user_id ): bool {
|
||||
$onboarding_url = self::make_from_token( $cache, $token, $user_id );
|
||||
|
||||
if ( $onboarding_url === false ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! $onboarding_url->load() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ( $onboarding_url->token() ?: '' ) !== $onboarding_token ) {
|
||||
if ( ( $onboarding_url->token() ?: '' ) !== $token ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$onboarding_url->replace_previous_token( $token );
|
||||
$onboarding_url->delete();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the token against the previous token.
|
||||
* Useful to don't throw errors on burst calls to endpoints.
|
||||
*
|
||||
* @param Cache $cache The cache object where the URL is stored.
|
||||
* @param string $token The token to validate.
|
||||
* @param int $user_id User ID to associate the link with.
|
||||
* @return bool
|
||||
*/
|
||||
public static function validate_previous_token( Cache $cache, string $token, int $user_id ): bool {
|
||||
$onboarding_url = self::make_from_token( $cache, $token, $user_id );
|
||||
|
||||
if ( $onboarding_url === false ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $onboarding_url->check_previous_token( $token );
|
||||
}
|
||||
|
||||
/**
|
||||
* Load cached data if is valid and initialize object.
|
||||
*
|
||||
|
@ -315,4 +358,43 @@ class OnboardingUrl {
|
|||
return implode( '_', array( $this->cache_key_prefix, $this->user_id ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the compiled cache key of the previous token
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function previous_cache_key(): string {
|
||||
return $this->cache_key() . '_previous';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks it the previous token matches the token provided.
|
||||
*
|
||||
* @param string $previous_token The previous token.
|
||||
* @return bool
|
||||
*/
|
||||
private function check_previous_token( string $previous_token ): bool {
|
||||
if ( ! $this->cache->has( $this->previous_cache_key() ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$cached_token = $this->cache->get( $this->previous_cache_key() );
|
||||
|
||||
return $cached_token === $previous_token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the previous token.
|
||||
*
|
||||
* @param string $previous_token The previous token.
|
||||
* @return void
|
||||
*/
|
||||
private function replace_previous_token( string $previous_token ): void {
|
||||
$this->cache->set(
|
||||
$this->previous_cache_key(),
|
||||
$previous_token,
|
||||
$this->previous_cache_ttl
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,12 +9,14 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\Onboarding\Render;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PartnerReferrals;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Repository\PartnerReferralsData;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Helper\OnboardingUrl;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
|
||||
use WooCommerce\WooCommerce\Logging\Logger\NullLogger;
|
||||
|
||||
/**
|
||||
* Class OnboardingRenderer
|
||||
|
@ -56,6 +58,13 @@ class OnboardingRenderer {
|
|||
*/
|
||||
protected $cache;
|
||||
|
||||
/**
|
||||
* The logger
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* OnboardingRenderer constructor.
|
||||
*
|
||||
|
@ -64,19 +73,22 @@ class OnboardingRenderer {
|
|||
* @param PartnerReferrals $sandbox_partner_referrals The PartnerReferrals for sandbox.
|
||||
* @param PartnerReferralsData $partner_referrals_data The default partner referrals data.
|
||||
* @param Cache $cache The cache.
|
||||
* @param ?LoggerInterface $logger The logger.
|
||||
*/
|
||||
public function __construct(
|
||||
Settings $settings,
|
||||
PartnerReferrals $production_partner_referrals,
|
||||
PartnerReferrals $sandbox_partner_referrals,
|
||||
PartnerReferralsData $partner_referrals_data,
|
||||
Cache $cache
|
||||
Cache $cache,
|
||||
LoggerInterface $logger = null
|
||||
) {
|
||||
$this->settings = $settings;
|
||||
$this->production_partner_referrals = $production_partner_referrals;
|
||||
$this->sandbox_partner_referrals = $sandbox_partner_referrals;
|
||||
$this->partner_referrals_data = $partner_referrals_data;
|
||||
$this->cache = $cache;
|
||||
$this->logger = $logger ?: new NullLogger();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -102,9 +114,12 @@ class OnboardingRenderer {
|
|||
$onboarding_url = new OnboardingUrl( $this->cache, $cache_key, get_current_user_id() );
|
||||
|
||||
if ( $onboarding_url->load() ) {
|
||||
$this->logger->debug( 'Loaded onbording URL from cache: ' . $cache_key );
|
||||
return $onboarding_url->get() ?: '';
|
||||
}
|
||||
|
||||
$this->logger->info( 'Generating onboarding URL for: ' . $cache_key );
|
||||
|
||||
$onboarding_url->init();
|
||||
|
||||
$data = $this->partner_referrals_data
|
||||
|
@ -116,6 +131,8 @@ class OnboardingRenderer {
|
|||
$onboarding_url->set( $url );
|
||||
$onboarding_url->persist();
|
||||
|
||||
$this->logger->info( 'Persisted onboarding URL for: ' . $cache_key );
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue