mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-08-30 05:00:51 +08:00
Add security to the onboarding return URL.
This commit is contained in:
parent
5a0b0b41a9
commit
96eae6c690
8 changed files with 630 additions and 9 deletions
|
@ -127,4 +127,18 @@ class PartnerReferralsData {
|
|||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append the validation token to the return_url
|
||||
*
|
||||
* @param array $data The referral data.
|
||||
* @param string $token The token to be appended.
|
||||
* @return array
|
||||
*/
|
||||
public function append_onboarding_token( array $data, string $token ): array {
|
||||
$separator = strpos( $data['partner_config_override']['return_url'], '?' ) === false ? '?' : '&';
|
||||
|
||||
$data['partner_config_override']['return_url'] .= $separator . 'ppcpToken=' . $token;
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
|
18
modules/ppcp-onboarding/src/Exception/RuntimeException.php
Normal file
18
modules/ppcp-onboarding/src/Exception/RuntimeException.php
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
/**
|
||||
* The modules Runtime Exception.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\Onboarding\Exception
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Onboarding\Exception;
|
||||
|
||||
/**
|
||||
* Class RuntimeException
|
||||
*/
|
||||
class RuntimeException extends \RuntimeException {
|
||||
|
||||
|
||||
}
|
318
modules/ppcp-onboarding/src/Helper/OnboardingUrl.php
Normal file
318
modules/ppcp-onboarding/src/Helper/OnboardingUrl.php
Normal file
|
@ -0,0 +1,318 @@
|
|||
<?php
|
||||
/**
|
||||
* Manages an Onboarding Url / Token to preserve /v2/customer/partner-referrals action_url integrity.
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\Onboarding\Helper
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Onboarding\Helper;
|
||||
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* Class OnboardingUrl
|
||||
*/
|
||||
class OnboardingUrl {
|
||||
|
||||
/**
|
||||
* The user ID to associate with the cache key
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $user_id;
|
||||
|
||||
/**
|
||||
* The cryptographically secure secret
|
||||
*
|
||||
* @var ?string
|
||||
*/
|
||||
private $secret = null;
|
||||
|
||||
/**
|
||||
* Unix Timestamp when token was generated
|
||||
*
|
||||
* @var ?int
|
||||
*/
|
||||
private $time = null;
|
||||
|
||||
/**
|
||||
* The "action_url" from /v2/customer/partner-referrals
|
||||
*
|
||||
* @var ?string
|
||||
*/
|
||||
private $url = null;
|
||||
|
||||
/**
|
||||
* The cache object
|
||||
*
|
||||
* @var Cache
|
||||
*/
|
||||
private $cache;
|
||||
|
||||
/**
|
||||
* The prefix for the cache key
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $cache_key_prefix;
|
||||
|
||||
/**
|
||||
* The TTL for the cache.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $cache_ttl = 3 * MONTH_IN_SECONDS;
|
||||
|
||||
/**
|
||||
* The constructor
|
||||
*
|
||||
* @param Cache $cache The cache object to store the URL.
|
||||
* @param string $cache_key_prefix The prefix for the cache entry.
|
||||
* @param int $user_id User ID to associate the link with.
|
||||
*/
|
||||
public function __construct(
|
||||
Cache $cache,
|
||||
string $cache_key_prefix,
|
||||
int $user_id
|
||||
) {
|
||||
$this->cache = $cache;
|
||||
$this->cache_key_prefix = $cache_key_prefix;
|
||||
$this->user_id = $user_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 $onboarding_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 $onboarding_token, int $user_id ): bool {
|
||||
if ( ! $onboarding_token ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$token_data = json_decode( UrlHelper::url_safe_base64_decode( $onboarding_token ) ?: '', true );
|
||||
|
||||
if ( ! $token_data ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $token_data['u'] ) || ! isset( $token_data['k'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( $token_data['u'] !== $user_id ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$onboarding_url = new self( $cache, $token_data['k'], $token_data['u'] );
|
||||
|
||||
if ( ! $onboarding_url->load() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ( $onboarding_url->token() ?: '' ) !== $onboarding_token ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$onboarding_url->delete();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load cached data if is valid and initialize object.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function load(): bool {
|
||||
if ( ! $this->cache->has( $this->cache_key() ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$cached_data = $this->cache->get( $this->cache_key() );
|
||||
|
||||
if ( ! $this->validate_cache_data( $cached_data ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->secret = $cached_data['secret'];
|
||||
$this->time = $cached_data['time'];
|
||||
$this->url = $cached_data['url'];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the object
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function init(): void {
|
||||
try {
|
||||
$this->secret = bin2hex( random_bytes( 16 ) );
|
||||
} catch ( \Exception $e ) {
|
||||
$this->secret = wp_generate_password( 16 );
|
||||
}
|
||||
|
||||
$this->time = time();
|
||||
$this->url = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates data from cache
|
||||
*
|
||||
* @param array $cache_data The data retrieved from the cache.
|
||||
* @return bool
|
||||
*/
|
||||
private function validate_cache_data( $cache_data ): bool {
|
||||
if ( ! is_array( $cache_data ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
! ( $cache_data['user_id'] ?? false )
|
||||
|| ! ( $cache_data['hash_check'] ?? false )
|
||||
|| ! ( $cache_data['secret'] ?? false )
|
||||
|| ! ( $cache_data['time'] ?? false )
|
||||
|| ! ( $cache_data['url'] ?? false )
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( $cache_data['user_id'] !== $this->user_id ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Detect if salt has changed.
|
||||
if ( $cache_data['hash_check'] !== wp_hash( '' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we want we can also validate time for expiration eventually.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL
|
||||
*
|
||||
* @return string
|
||||
* @throws RuntimeException Throws in case the URL isn't initialized.
|
||||
*/
|
||||
public function get(): string {
|
||||
if ( null === $this->url ) {
|
||||
throw new RuntimeException( 'Object not initialized.' );
|
||||
}
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Token
|
||||
*
|
||||
* @return string
|
||||
* @throws RuntimeException Throws in case the object isn't initialized.
|
||||
*/
|
||||
public function token(): string {
|
||||
if (
|
||||
null === $this->secret
|
||||
|| null === $this->time
|
||||
|| null === $this->user_id
|
||||
) {
|
||||
throw new RuntimeException( 'Object not initialized.' );
|
||||
}
|
||||
|
||||
// Trim the hash to make sure the token isn't too long.
|
||||
$hash = substr(
|
||||
wp_hash(
|
||||
implode(
|
||||
'|',
|
||||
array(
|
||||
$this->cache_key_prefix,
|
||||
$this->user_id,
|
||||
$this->secret,
|
||||
$this->time,
|
||||
)
|
||||
)
|
||||
),
|
||||
0,
|
||||
32
|
||||
);
|
||||
|
||||
$token = wp_json_encode(
|
||||
array(
|
||||
'k' => $this->cache_key_prefix,
|
||||
'u' => $this->user_id,
|
||||
'h' => $hash,
|
||||
)
|
||||
);
|
||||
|
||||
if ( ! $token ) {
|
||||
throw new RuntimeException( 'Unable to generate token.' );
|
||||
}
|
||||
|
||||
return UrlHelper::url_safe_base64_encode( $token );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the URL
|
||||
*
|
||||
* @param string $url The URL to store in the cache.
|
||||
* @return void
|
||||
*/
|
||||
public function set( string $url ): void {
|
||||
$this->url = $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Persists the URL and related data in cache
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function persist(): void {
|
||||
if (
|
||||
null === $this->secret
|
||||
|| null === $this->time
|
||||
|| null === $this->user_id
|
||||
|| null === $this->url
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->cache->set(
|
||||
$this->cache_key(),
|
||||
array(
|
||||
'hash_check' => wp_hash( '' ), // To detect if salt has changed.
|
||||
'secret' => $this->secret,
|
||||
'time' => $this->time,
|
||||
'user_id' => $this->user_id,
|
||||
'url' => $this->url,
|
||||
),
|
||||
$this->cache_ttl
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the token from cache
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete(): void {
|
||||
$this->cache->delete( $this->cache_key() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the compiled cache key
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function cache_key(): string {
|
||||
return implode( '_', array( $this->cache_key_prefix, $this->user_id ) );
|
||||
}
|
||||
|
||||
}
|
42
modules/ppcp-onboarding/src/Helper/UrlHelper.php
Normal file
42
modules/ppcp-onboarding/src/Helper/UrlHelper.php
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
/**
|
||||
* Provides Helper functions for URL handling
|
||||
*
|
||||
* @package WooCommerce\PayPalCommerce\Onboarding\Helper
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Onboarding\Helper;
|
||||
|
||||
/**
|
||||
* Class OnboardingUrl
|
||||
*/
|
||||
class UrlHelper {
|
||||
|
||||
/**
|
||||
* Does a base64 encode of a string safe to be used on a URL
|
||||
*
|
||||
* @param string $string The string to be encoded.
|
||||
* @return string
|
||||
*/
|
||||
public static function url_safe_base64_encode( string $string ): string {
|
||||
//phpcs:disable WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
|
||||
$encoded_string = base64_encode( $string );
|
||||
$url_safe_string = str_replace( array( '+', '/' ), array( '-', '_' ), $encoded_string );
|
||||
return rtrim( $url_safe_string, '=' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Does a base64 decode of a string URL safe string
|
||||
*
|
||||
* @param string $url_safe_string The string to be decoded.
|
||||
* @return false|string
|
||||
*/
|
||||
public static function url_safe_base64_decode( string $url_safe_string ) {
|
||||
$padded_string = str_pad( $url_safe_string, strlen( $url_safe_string ) % 4, '=', STR_PAD_RIGHT );
|
||||
$encoded_string = str_replace( array( '-', '_' ), array( '+', '/' ), $padded_string );
|
||||
//phpcs:disable WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
|
||||
return base64_decode( $encoded_string );
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@ 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;
|
||||
|
||||
/**
|
||||
|
@ -96,14 +97,24 @@ class OnboardingRenderer {
|
|||
|
||||
$environment = $is_production ? 'production' : 'sandbox';
|
||||
$product = 'PPCP' === $data['products'][0] ? 'ppcp' : 'express_checkout';
|
||||
if ( $this->cache->has( $environment . '-' . $product ) ) {
|
||||
return $this->cache->get( $environment . '-' . $product );
|
||||
$cache_key = $environment . '-' . $product;
|
||||
|
||||
$onboarding_url = new OnboardingUrl( $this->cache, $cache_key, get_current_user_id() );
|
||||
|
||||
if ( $onboarding_url->load() ) {
|
||||
return $onboarding_url->get() ?: '';
|
||||
}
|
||||
|
||||
$onboarding_url->init();
|
||||
|
||||
$data = $this->partner_referrals_data
|
||||
->append_onboarding_token( $data, $onboarding_url->token() ?: '' );
|
||||
|
||||
$url = $is_production ? $this->production_partner_referrals->signup_link( $data ) : $this->sandbox_partner_referrals->signup_link( $data );
|
||||
$url = add_query_arg( $args, $url );
|
||||
|
||||
$this->cache->set( $environment . '-' . $product, $url, 3 * MONTH_IN_SECONDS );
|
||||
$onboarding_url->set( $url );
|
||||
$onboarding_url->persist();
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
|
|
@ -9,12 +9,15 @@ declare(strict_types=1);
|
|||
|
||||
namespace WooCommerce\PayPalCommerce\WcGateway\Settings;
|
||||
|
||||
use WooCommerce\PayPalCommerce\AdminNotices\Entity\Message;
|
||||
use WooCommerce\PayPalCommerce\AdminNotices\Repository\Repository;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Authentication\PayPalBearer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
|
||||
use WooCommerce\PayPalCommerce\Http\RedirectorInterface;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\State;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Helper\OnboardingUrl;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\DCCProductStatus;
|
||||
use WooCommerce\PayPalCommerce\WcGateway\Helper\PayUponInvoiceProductStatus;
|
||||
|
@ -168,7 +171,7 @@ class SettingsListener {
|
|||
* Listens if the merchant ID should be updated.
|
||||
*/
|
||||
public function listen_for_merchant_id() {
|
||||
if ( ! $this->is_valid_site_request() || $this->state->current_state() === State::STATE_ONBOARDED ) {
|
||||
if ( ! $this->is_valid_site_request() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -177,17 +180,23 @@ class SettingsListener {
|
|||
* phpcs:disable WordPress.Security.NonceVerification.Missing
|
||||
* phpcs:disable WordPress.Security.NonceVerification.Recommended
|
||||
*/
|
||||
if ( ! isset( $_GET['merchantIdInPayPal'] ) || ! isset( $_GET['merchantId'] ) ) {
|
||||
if ( ! isset( $_GET['merchantIdInPayPal'] ) || ! isset( $_GET['merchantId'] ) || ! isset( $_GET['ppcpToken'] ) ) {
|
||||
return;
|
||||
}
|
||||
$merchant_id = sanitize_text_field( wp_unslash( $_GET['merchantIdInPayPal'] ) );
|
||||
$merchant_email = sanitize_text_field( wp_unslash( $_GET['merchantId'] ) );
|
||||
|
||||
$merchant_id = sanitize_text_field( wp_unslash( $_GET['merchantIdInPayPal'] ) );
|
||||
$merchant_email = sanitize_text_field( wp_unslash( $_GET['merchantId'] ) );
|
||||
$onboarding_token = sanitize_text_field( wp_unslash( $_GET['ppcpToken'] ) );
|
||||
// phpcs:enable WordPress.Security.NonceVerification.Missing
|
||||
// phpcs:enable WordPress.Security.NonceVerification.Recommended
|
||||
|
||||
$this->settings->set( 'merchant_id', $merchant_id );
|
||||
$this->settings->set( 'merchant_email', $merchant_email );
|
||||
|
||||
if ( ! OnboardingUrl::validate_token_and_delete( $this->signup_link_cache, $onboarding_token, get_current_user_id() ) ) {
|
||||
$this->onboarding_redirect( false );
|
||||
}
|
||||
|
||||
$is_sandbox = $this->settings->has( 'sandbox_on' ) && $this->settings->get( 'sandbox_on' );
|
||||
if ( $is_sandbox ) {
|
||||
$this->settings->set( 'merchant_id_sandbox', $merchant_id );
|
||||
|
@ -203,8 +212,23 @@ class SettingsListener {
|
|||
*/
|
||||
do_action( 'woocommerce_paypal_payments_onboarding_before_redirect' );
|
||||
|
||||
$redirect_url = $this->get_onboarding_redirect_url();
|
||||
if ( ! $this->settings->has( 'client_id' ) || ! $this->settings->get( 'client_id' ) ) {
|
||||
$this->onboarding_redirect( false );
|
||||
}
|
||||
|
||||
$this->onboarding_redirect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to the onboarding URL.
|
||||
*
|
||||
* @param bool $success Should redirect to the success or error URL.
|
||||
* @return void
|
||||
*/
|
||||
private function onboarding_redirect( bool $success = true ): void {
|
||||
$redirect_url = $this->get_onboarding_redirect_url();
|
||||
|
||||
if ( ! $success ) {
|
||||
$redirect_url = add_query_arg( 'ppcp-onboarding-error', '1', $redirect_url );
|
||||
}
|
||||
|
||||
|
|
|
@ -685,9 +685,10 @@
|
|||
<code>listen_for_merchant_id</code>
|
||||
<code>listen_for_vaulting_enabled</code>
|
||||
</MissingReturnType>
|
||||
<PossiblyInvalidArgument occurrences="3">
|
||||
<PossiblyInvalidArgument occurrences="4">
|
||||
<code>wp_unslash( $_GET['merchantId'] )</code>
|
||||
<code>wp_unslash( $_GET['merchantIdInPayPal'] )</code>
|
||||
<code>wp_unslash( $_GET['ppcpToken'] )</code>
|
||||
<code>wp_unslash( $_POST['ppcp-nonce'] )</code>
|
||||
</PossiblyInvalidArgument>
|
||||
</file>
|
||||
|
|
193
tests/PHPUnit/Onboarding/Helper/OnboardingUrlTest.php
Normal file
193
tests/PHPUnit/Onboarding/Helper/OnboardingUrlTest.php
Normal file
|
@ -0,0 +1,193 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace WooCommerce\PayPalCommerce\Onboarding\Helper;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
|
||||
use WooCommerce\PayPalCommerce\Onboarding\Exception\RuntimeException;
|
||||
use function Brain\Monkey\Functions\when;
|
||||
|
||||
class OnboardingUrlTest extends TestCase
|
||||
{
|
||||
private $cache;
|
||||
private $cache_key_prefix = 'test_prefix';
|
||||
private $user_id = 123;
|
||||
private $onboardingUrl;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
if (!defined('MONTH_IN_SECONDS')) {
|
||||
define( 'MONTH_IN_SECONDS', 30 * 24 * 60 * 60 );
|
||||
}
|
||||
|
||||
when('wp_hash')->alias(function($string) {
|
||||
return hash('md5', $string);
|
||||
});
|
||||
|
||||
$this->cache = \Mockery::mock(Cache::class);
|
||||
$this->onboardingUrl = new OnboardingUrl($this->cache, $this->cache_key_prefix, $this->user_id);
|
||||
}
|
||||
|
||||
public function test_validate_token_and_delete_valid()
|
||||
{
|
||||
// Prepare the data
|
||||
$cacheData = [
|
||||
'hash_check' => wp_hash(''),
|
||||
'secret' => 'test_secret',
|
||||
'time' => time(),
|
||||
'user_id' => $this->user_id,
|
||||
'url' => 'https://example.com'
|
||||
];
|
||||
|
||||
$token = [
|
||||
'k' => $this->cache_key_prefix,
|
||||
'u' => $this->user_id,
|
||||
'h' => substr(wp_hash(implode( '|', array(
|
||||
$this->cache_key_prefix,
|
||||
$cacheData['user_id'],
|
||||
$cacheData['secret'],
|
||||
$cacheData['time'],
|
||||
))), 0, 32)
|
||||
];
|
||||
|
||||
$onboarding_token = UrlHelper::url_safe_base64_encode(json_encode($token));
|
||||
|
||||
// Expectations
|
||||
$this->cache->shouldReceive('has')->once()->andReturn(true);
|
||||
$this->cache->shouldReceive('get')->once()->andReturn($cacheData);
|
||||
$this->cache->shouldReceive('delete')->once();
|
||||
|
||||
$this->assertTrue(
|
||||
OnboardingUrl::validate_token_and_delete($this->cache, $onboarding_token, $this->user_id)
|
||||
);
|
||||
}
|
||||
|
||||
public function test_load_valid()
|
||||
{
|
||||
// Expectations
|
||||
$this->cache->shouldReceive('has')->once()->andReturn(true);
|
||||
$this->cache->shouldReceive('get')->once()->andReturn([
|
||||
'hash_check' => wp_hash(''),
|
||||
'secret' => 'test_secret',
|
||||
'time' => time(),
|
||||
'user_id' => $this->user_id,
|
||||
'url' => 'https://example.com'
|
||||
]);
|
||||
|
||||
$this->assertTrue($this->onboardingUrl->load());
|
||||
}
|
||||
|
||||
public function test_load_invalid()
|
||||
{
|
||||
// Expectations
|
||||
$this->cache->shouldReceive('has')->once()->andReturn(false);
|
||||
|
||||
$this->assertFalse($this->onboardingUrl->load());
|
||||
}
|
||||
|
||||
public function test_get_not_initialized()
|
||||
{
|
||||
$this->expectException(RuntimeException::class);
|
||||
$this->expectExceptionMessage('Object not initialized.');
|
||||
|
||||
$this->onboardingUrl->get();
|
||||
}
|
||||
|
||||
public function test_token_not_initialized()
|
||||
{
|
||||
$this->expectException(RuntimeException::class);
|
||||
$this->expectExceptionMessage('Object not initialized.');
|
||||
|
||||
$this->onboardingUrl->token();
|
||||
}
|
||||
|
||||
public function test_persist_not_initialized()
|
||||
{
|
||||
// Expectations
|
||||
$this->cache->shouldReceive('set')->never();
|
||||
|
||||
$this->onboardingUrl->persist();
|
||||
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
|
||||
public function test_delete()
|
||||
{
|
||||
// Expectations
|
||||
$this->cache->shouldReceive('delete')->once();
|
||||
|
||||
$this->onboardingUrl->delete();
|
||||
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
|
||||
public function test_init()
|
||||
{
|
||||
$this->onboardingUrl->init();
|
||||
|
||||
$token = $this->onboardingUrl->token();
|
||||
$this->assertNotEmpty($token);
|
||||
}
|
||||
|
||||
public function test_set_and_get()
|
||||
{
|
||||
$this->onboardingUrl->init();
|
||||
$this->onboardingUrl->set('https://example.com');
|
||||
|
||||
$url = $this->onboardingUrl->get();
|
||||
$this->assertEquals('https://example.com', $url);
|
||||
}
|
||||
|
||||
public function test_persist()
|
||||
{
|
||||
$this->onboardingUrl->init();
|
||||
$this->onboardingUrl->set('https://example.com');
|
||||
|
||||
// Expectations
|
||||
$this->cache->shouldReceive('set')->once();
|
||||
|
||||
$this->onboardingUrl->persist();
|
||||
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
|
||||
public function test_token()
|
||||
{
|
||||
$this->onboardingUrl->init();
|
||||
$this->onboardingUrl->set('https://example.com');
|
||||
|
||||
$token = $this->onboardingUrl->token();
|
||||
$this->assertNotEmpty($token);
|
||||
}
|
||||
|
||||
public function test_validate_token_and_delete_invalid()
|
||||
{
|
||||
// Prepare the data
|
||||
$token = [
|
||||
'k' => $this->cache_key_prefix,
|
||||
'u' => $this->user_id,
|
||||
'h' => 'invalid_hash'
|
||||
];
|
||||
|
||||
$onboarding_token = UrlHelper::url_safe_base64_encode(json_encode($token));
|
||||
|
||||
// Expectations
|
||||
$this->cache->shouldReceive('has')->once()->andReturn(true);
|
||||
$this->cache->shouldReceive('get')->once()->andReturn([
|
||||
'hash_check' => wp_hash(''),
|
||||
'secret' => 'test_secret',
|
||||
'time' => time(),
|
||||
'user_id' => $this->user_id,
|
||||
'url' => 'https://example.com'
|
||||
]);
|
||||
$this->cache->shouldReceive('delete')->never();
|
||||
|
||||
$this->assertFalse(
|
||||
OnboardingUrl::validate_token_and_delete($this->cache, $onboarding_token, $this->user_id)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue