load data-client-id via endpoint when needed

This commit is contained in:
David Remer 2020-08-13 14:20:47 +03:00
parent 4f72597a9a
commit 56b510e8fc
6 changed files with 138 additions and 17 deletions

View file

@ -5,6 +5,7 @@ import CheckoutBootstap from './modules/ContextBootstrap/CheckoutBootstap';
import Renderer from './modules/Renderer/Renderer';
import ErrorHandler from './modules/ErrorHandler';
import CreditCardRenderer from "./modules/Renderer/CreditCardRenderer";
import dataClientIdAttributeHandler from "./modules/DataClientIdAttributeHandler";
const bootstrap = () => {
const errorHandler = new ErrorHandler(PayPalCommerceGateway.labels.error.generic);
@ -57,15 +58,20 @@ document.addEventListener(
}
const script = document.createElement('script');
script.addEventListener('load', (event) => {
bootstrap();
});
script.setAttribute('src', PayPalCommerceGateway.button.url);
Object.entries(PayPalCommerceGateway.script_attributes).forEach(
(keyValue) => {
script.setAttribute(keyValue[0], keyValue[1]);
}
);
script.addEventListener('load', (event) => {
bootstrap();
});
if (PayPalCommerceGateway.data_client_id.set_attribute) {
dataClientIdAttributeHandler(script, PayPalCommerceGateway.data_client_id);
return;
}
document.body.append(script);
},

View file

@ -0,0 +1,52 @@
const storageKey = 'ppcp-data-client-id';
const validateToken = (token, user) => {
if (! token) {
return false;
}
if (token.user !== user) {
return false;
}
const currentTime = new Date().getTime();
const isExpired = currentTime >= token.expiration * 1000;
return ! isExpired;
}
const storedTokenForUser = (user) => {
const token = JSON.parse(sessionStorage.getItem(storageKey));
if (validateToken(token, user)) {
return token.token;
}
return null;
}
const storeToken = (token) => {
sessionStorage.setItem(storageKey, JSON.stringify(token));
}
const dataClientIdAttributeHandler = (script, config) => {
const token = storedTokenForUser(config.user);
if (token) {
script.setAttribute('data-client-token', token);
document.body.append(script);
return;
}
fetch(config.endpoint, {
method: 'POST',
body: JSON.stringify({
nonce: config.nonce
})
}).then((res)=>{
return res.json();
}).then((data)=>{
const isValid = validateToken(data, config.user);
if (!isValid) {
return;
}
storeToken(data);
script.setAttribute('data-client-token', data.token);
document.body.append(script);
});
}
export default dataClientIdAttributeHandler;

View file

@ -11,6 +11,7 @@ use Inpsyde\PayPalCommerce\Button\Assets\SmartButtonInterface;
use Inpsyde\PayPalCommerce\Button\Endpoint\ApproveOrderEndpoint;
use Inpsyde\PayPalCommerce\Button\Endpoint\ChangeCartEndpoint;
use Inpsyde\PayPalCommerce\Button\Endpoint\CreateOrderEndpoint;
use Inpsyde\PayPalCommerce\Button\Endpoint\DataClientIdEndpoint;
use Inpsyde\PayPalCommerce\Button\Endpoint\RequestData;
use Inpsyde\PayPalCommerce\Button\Exception\RuntimeException;
use Inpsyde\PayPalCommerce\Button\Helper\ThreeDSecure;
@ -106,6 +107,14 @@ return [
$threeDSecure = $container->get('button.helper.three-d-secure');
return new ApproveOrderEndpoint($requestData, $apiClient, $sessionHandler, $threeDSecure);
},
'button.endpoint.data-client-id' => static function(ContainerInterface $container) : DataClientIdEndpoint {
$requestData = $container->get('button.request-data');
$tokenEndpoint = $container->get('api.endpoint.identity-token');
return new DataClientIdEndpoint(
$requestData,
$tokenEndpoint
);
},
'button.helper.three-d-secure' => static function (ContainerInterface $container): ThreeDSecure {
return new ThreeDSecure();
},

View file

@ -12,6 +12,7 @@ use Inpsyde\PayPalCommerce\ApiClient\Repository\PayeeRepository;
use Inpsyde\PayPalCommerce\Button\Endpoint\ApproveOrderEndpoint;
use Inpsyde\PayPalCommerce\Button\Endpoint\ChangeCartEndpoint;
use Inpsyde\PayPalCommerce\Button\Endpoint\CreateOrderEndpoint;
use Inpsyde\PayPalCommerce\Button\Endpoint\DataClientIdEndpoint;
use Inpsyde\PayPalCommerce\Button\Endpoint\RequestData;
use Inpsyde\PayPalCommerce\Session\SessionHandler;
use Inpsyde\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
@ -305,6 +306,12 @@ class SmartButton implements SmartButtonInterface
$this->requestData->enqueueNonceFix();
$localize = [
'script_attributes' => $this->attributes(),
'data_client_id' => [
'set_attribute' => $this->dccIsEnabled() || $this->canSaveVaultToken(),
'endpoint' => home_url(\WC_AJAX::get_endpoint(DataClientIdEndpoint::ENDPOINT)),
'nonce' => wp_create_nonce(DataClientIdEndpoint::nonce()),
'user' => get_current_user_id(),
],
'redirect' => wc_get_checkout_url(),
'context' => $this->context(),
'ajax' => [
@ -408,22 +415,9 @@ class SmartButton implements SmartButtonInterface
private function attributes(): array
{
$attributes = [
return [
'data-partner-attribution-id' => $this->bnCodeForContext($this->context()),
];
try {
if (!is_user_logged_in()) {
return $attributes;
}
if (! $this->dccIsEnabled() && ! $this->canSaveVaultToken()) {
return $attributes;
}
$clientToken = $this->identityToken->generateForCustomer((int) get_current_user_id());
$attributes['data-client-token'] = $clientToken->token();
return $attributes;
} catch (RuntimeException $exception) {
return $attributes;
}
}
/**

View file

@ -10,6 +10,7 @@ use Inpsyde\PayPalCommerce\Button\Assets\SmartButton;
use Inpsyde\PayPalCommerce\Button\Endpoint\ApproveOrderEndpoint;
use Inpsyde\PayPalCommerce\Button\Endpoint\ChangeCartEndpoint;
use Inpsyde\PayPalCommerce\Button\Endpoint\CreateOrderEndpoint;
use Inpsyde\PayPalCommerce\Button\Endpoint\DataClientIdEndpoint;
use Inpsyde\PayPalCommerce\Button\Endpoint\RequestData;
use Interop\Container\ServiceProviderInterface;
use Psr\Container\ContainerInterface;
@ -49,6 +50,17 @@ class ButtonModule implements ModuleInterface
$smartButton->enqueue();
});
add_action(
'wc_ajax_' . DataClientIdEndpoint::ENDPOINT,
static function () use ($container) {
$endpoint = $container->get('button.endpoint.data-client-id');
/**
* @var DataClientIdEndpoint $endpoint
*/
$endpoint->handleRequest();
}
);
add_action(
'wc_ajax_' . ChangeCartEndpoint::ENDPOINT,
static function () use ($container) {

View file

@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
namespace Inpsyde\PayPalCommerce\Button\Endpoint;
use Inpsyde\PayPalCommerce\ApiClient\Endpoint\IdentityToken;
use Inpsyde\PayPalCommerce\ApiClient\Exception\RuntimeException;
class DataClientIdEndpoint implements EndpointInterface
{
public const ENDPOINT = 'data-client-id';
private $requestData;
private $identityToken;
public function __construct(
RequestData $requestData,
IdentityToken $identityToken
) {
$this->requestData = $requestData;
$this->identityToken = $identityToken;
}
public static function nonce(): string
{
return self::ENDPOINT;
}
public function handleRequest(): bool
{
try {
$this->requestData->readRequest($this->nonce());
$userId = get_current_user_id();
$token = $this->identityToken->generateForCustomer($userId);
wp_send_json([
'token' => $token->token(),
'expiration' => $token->expirationTimestamp(),
'user' => get_current_user_id(),
]);
return true;
} catch (RuntimeException $error) {
wp_send_json_error($error->getMessage());
return false;
}
}
}