Skip to content

Commit

Permalink
[ECP-9425] Implement custom token factory
Browse files Browse the repository at this point in the history
  • Loading branch information
Can Demiralp committed Aug 26, 2024
1 parent 4d8e346 commit ccf34e4
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 0 deletions.
122 changes: 122 additions & 0 deletions src/Model/JWTFactoryV2.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
<?php declare(strict_types=1);

namespace Adyen\Shopware\Model;

use Doctrine\DBAL\Connection;
use Lcobucci\JWT\Configuration;
use Lcobucci\JWT\UnencryptedToken;
use Shopware\Core\Checkout\Payment\Cart\Token\TokenFactoryInterfaceV2;
use Shopware\Core\Checkout\Payment\Cart\Token\TokenStruct;
use Shopware\Core\Checkout\Payment\PaymentException;
use Shopware\Core\Defaults;
use Shopware\Core\Framework\Uuid\Uuid;

class JWTFactoryV2 implements TokenFactoryInterfaceV2
{
/**
* @internal
*/
public function __construct(
private Configuration $configuration,
private readonly Connection $connection
) {
}

public function generateToken(TokenStruct $tokenStruct): string
{
$expires = new \DateTimeImmutable('@' . time());

// @see https://github.com/php/php-src/issues/9950
if ($tokenStruct->getExpires() > 0) {
$expires = $expires->modify(
sprintf('+%d seconds', $tokenStruct->getExpires())
);
} else {
$expires = $expires->modify(
sprintf('-%d seconds', abs($tokenStruct->getExpires()))
);
}

$jwtTokenBuilder = $this->configuration->builder()
->identifiedBy(Uuid::randomHex())
->issuedAt(new \DateTimeImmutable('@' . time()))
->canOnlyBeUsedAfter(new \DateTimeImmutable('@' . time()))
->expiresAt($expires)
->withClaim('pmi', $tokenStruct->getPaymentMethodId())
->withClaim('ful', $tokenStruct->getFinishUrl())
->withClaim('eul', $tokenStruct->getErrorUrl());

$transactionId = $tokenStruct->getTransactionId();
if ($transactionId !== '' && $transactionId !== null) {
$jwtTokenBuilder = $jwtTokenBuilder->relatedTo($transactionId);
}

$token = $jwtTokenBuilder->getToken($this->configuration->signer(), $this->configuration->signingKey())->toString();
$this->write(
$token,
$expires
);

return $token;
}

/**
* @param non-empty-string $token
*/
public function parseToken(string $token): TokenStruct
{
try {
/** @var UnencryptedToken $jwtToken */
$jwtToken = $this->configuration->parser()->parse($token);
} catch (\Throwable $e) {
throw PaymentException::invalidToken($token, $e);
}

if (!$this->configuration->validator()->validate($jwtToken, ...$this->configuration->validationConstraints())) {
throw PaymentException::invalidToken($token);
}

$errorUrl = $jwtToken->claims()->get('eul');

/** @var \DateTimeImmutable $expires */
$expires = $jwtToken->claims()->get('exp');

return new TokenStruct(
$jwtToken->claims()->get('jti'),
$token,
$jwtToken->claims()->get('pmi'),
$jwtToken->claims()->get('sub'),
$jwtToken->claims()->get('ful'),
$expires->getTimestamp(),
$errorUrl
);
}

public function invalidateToken(string $token): bool
{
$this->delete($token);

return false;
}

private function write(string $token, \DateTimeImmutable $expires): void
{
$this->connection->insert('payment_token', [
'token' => self::normalize($token),
'expires' => $expires->format(Defaults::STORAGE_DATE_TIME_FORMAT),
]);
}

private function delete(string $token): void
{
$this->connection->executeStatement(
'DELETE FROM payment_token WHERE token = :token',
['token' => self::normalize($token)]
);
}

private static function normalize(string $token): string
{
return substr(hash('sha256', $token), 0, 32);
}
}
6 changes: 6 additions & 0 deletions src/Resources/config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -103,5 +103,11 @@
<argument type="service"
id="Adyen\Shopware\Framework\Cookie\AdyenCookieProvider.inner"/>
</service>

<!-- Models -->
<service id="Adyen\Shopware\Model\JWTFactoryV2" autowire="true">
<argument type="service" id="shopware.jwt_config"/>
<argument type="service" id="Doctrine\DBAL\Connection"/>
</service>
</services>
</container>

0 comments on commit ccf34e4

Please sign in to comment.