mirror of
https://github.com/Sylius/Sylius.git
synced 2026-07-05 20:57:12 +00:00
[PaymentBundle] Use a single encryption method
This commit is contained in:
parent
1055a2afa7
commit
2126d7e3fa
29 changed files with 479 additions and 43 deletions
|
|
@ -16,3 +16,8 @@ sylius_state_machine_abstraction:
|
|||
sylius_payment_request: '%test_sylius_state_machine_adapter%'
|
||||
sylius_product_review: '%test_sylius_state_machine_adapter%'
|
||||
sylius_shipment: '%test_sylius_state_machine_adapter%'
|
||||
|
||||
sylius_payment:
|
||||
encryption:
|
||||
disabled_for_factories:
|
||||
- online-disabled
|
||||
|
|
|
|||
|
|
@ -43,3 +43,8 @@ Feature: Editing payment methods
|
|||
Scenario: Being unable to edit gateway factory field of existing payment method
|
||||
When I want to modify the "Offline" payment method
|
||||
Then the factory name field should be disabled
|
||||
|
||||
@todo-api @ui
|
||||
Scenario: Being unable to change usePayum field of an existing payment method
|
||||
When I want to modify the "Offline" payment method
|
||||
Then I should not be able to edit its usePayum field
|
||||
|
|
|
|||
|
|
@ -381,6 +381,14 @@ final readonly class ManagingPaymentMethodsContext implements Context
|
|||
Assert::true($this->updatePage->isFactoryNameFieldDisabled());
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then I should not be able to edit its usePayum field
|
||||
*/
|
||||
public function theUsePayumFieldShouldBeDisabled(): void
|
||||
{
|
||||
Assert::true($this->updatePage->isUsePayumFieldDisabled());
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then this payment method should be enabled
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -48,6 +48,11 @@ class UpdatePage extends BaseUpdatePage implements UpdatePageInterface
|
|||
return 'disabled' === $this->getElement('factory_name')->getAttribute('disabled');
|
||||
}
|
||||
|
||||
public function isUsePayumFieldDisabled(): bool
|
||||
{
|
||||
return 'disabled' === $this->getElement('use_payum')->getAttribute('disabled');
|
||||
}
|
||||
|
||||
public function isAvailableInChannel(string $channelName): bool
|
||||
{
|
||||
return $this
|
||||
|
|
@ -89,6 +94,7 @@ class UpdatePage extends BaseUpdatePage implements UpdatePageInterface
|
|||
'secret_key' => '[data-test-secret-key]',
|
||||
'signature' => '[data-test-signature]',
|
||||
'username' => '[data-test-username]',
|
||||
'use_payum' => '[data-test-use-payum]',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ interface UpdatePageInterface extends BaseUpdatePageInterface
|
|||
|
||||
public function isFactoryNameFieldDisabled(): bool;
|
||||
|
||||
public function isUsePayumFieldDisabled(): bool;
|
||||
|
||||
public function isPaymentMethodEnabled(): bool;
|
||||
|
||||
public function isPaymentMethodInSandboxMode(): bool;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Sylius Sp. z o.o.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sylius\Bundle\PaymentBundle\Checker;
|
||||
|
||||
use Sylius\Component\Payment\Model\GatewayConfigInterface;
|
||||
|
||||
/** @experimental */
|
||||
final readonly class GatewayConfigEncryptionChecker implements GatewayConfigEncryptionCheckerInterface
|
||||
{
|
||||
/**
|
||||
* @param array<string> $disabledGatewayFactories
|
||||
*/
|
||||
public function __construct(
|
||||
private array $disabledGatewayFactories,
|
||||
) {
|
||||
}
|
||||
|
||||
public function isEncryptionEnabled(GatewayConfigInterface $gatewayConfig): bool
|
||||
{
|
||||
return !in_array($gatewayConfig->getFactoryName(), $this->disabledGatewayFactories, true);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
namespace Sylius\Bundle\PaymentBundle\Checker;
|
||||
|
||||
|
||||
use Sylius\Component\Payment\Model\GatewayConfigInterface;
|
||||
|
||||
/** @experimental */
|
||||
interface GatewayConfigEncryptionCheckerInterface
|
||||
{
|
||||
public function isEncryptionEnabled(GatewayConfigInterface $gatewayConfig): bool;
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace Sylius\Bundle\PaymentBundle\Listener;
|
||||
|
||||
use Sylius\Bundle\PaymentBundle\Checker\GatewayConfigEncryptionCheckerInterface;
|
||||
use Sylius\Component\Payment\Encryption\EntityEncrypterInterface;
|
||||
use Sylius\Component\Payment\Model\GatewayConfigInterface;
|
||||
|
||||
|
|
@ -26,12 +27,11 @@ final class GatewayConfigEncryptionListener extends EntityEncryptionListener
|
|||
/**
|
||||
* @param EntityEncrypterInterface<GatewayConfigInterface> $entityEncrypter
|
||||
* @param class-string $entityClass
|
||||
* @param array<string> $disabledGatewayFactories
|
||||
*/
|
||||
public function __construct(
|
||||
EntityEncrypterInterface $entityEncrypter,
|
||||
string $entityClass,
|
||||
private readonly array $disabledGatewayFactories,
|
||||
private readonly GatewayConfigEncryptionCheckerInterface $gatewayConfigEncryptionChecker,
|
||||
) {
|
||||
parent::__construct($entityEncrypter, $entityClass);
|
||||
}
|
||||
|
|
@ -40,7 +40,7 @@ final class GatewayConfigEncryptionListener extends EntityEncryptionListener
|
|||
{
|
||||
return
|
||||
parent::supports($entity) &&
|
||||
!in_array($entity->getFactoryName(), $this->disabledGatewayFactories, true)
|
||||
$this->gatewayConfigEncryptionChecker->isEncryptionEnabled($entity)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,11 @@
|
|||
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"
|
||||
>
|
||||
<services>
|
||||
<service id="sylius.checker.gateway_config_encryption" class="Sylius\Bundle\PaymentBundle\Checker\GatewayConfigEncryptionChecker">
|
||||
<argument on-invalid="null">%sylius.encryption.disabled_for_factories%</argument>
|
||||
</service>
|
||||
<service id="Sylius\Bundle\PaymentBundle\Checker\GatewayConfigEncryptionCheckerInterface" alias="sylius.checker.gateway_config_encryption" />
|
||||
|
||||
<service id="sylius.encrypter" class="Sylius\Component\Payment\Encryption\Encrypter">
|
||||
<argument>%env(resolve:SYLIUS_PAYMENT_ENCRYPTION_KEY_PATH)%</argument>
|
||||
</service>
|
||||
|
|
@ -33,7 +38,7 @@
|
|||
<service id="sylius.listener.gateway_config_encryption" class="Sylius\Bundle\PaymentBundle\Listener\GatewayConfigEncryptionListener">
|
||||
<argument type="service" id="sylius.encrypter.gateway_config" />
|
||||
<argument>%sylius.model.gateway_config.class%</argument>
|
||||
<argument>%sylius.encryption.disabled_for_factories%</argument>
|
||||
<argument type="service" id="sylius.checker.gateway_config_encryption" />
|
||||
<tag name="doctrine.event_listener" event="onFlush" />
|
||||
<tag name="doctrine.event_listener" event="postFlush" />
|
||||
<tag name="doctrine.event_listener" event="postLoad" />
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Sylius Sp. z o.o.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sylius\Bundle\PaymentBundle\Tests\Checker;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Sylius\Bundle\PaymentBundle\Checker\GatewayConfigEncryptionChecker;
|
||||
use Sylius\Component\Payment\Model\GatewayConfigInterface;
|
||||
|
||||
final class GatewayConfigEncryptionCheckerTest extends TestCase
|
||||
{
|
||||
/** @test */
|
||||
public function it_cannot_encrypt_if_factory_name_is_in_disabled_factories(): void
|
||||
{
|
||||
$gatewayConfig = $this->createMock(GatewayConfigInterface::class);
|
||||
$gatewayConfig->method('getFactoryName')->willReturn('offline');
|
||||
|
||||
$checker = new GatewayConfigEncryptionChecker(['offline']);
|
||||
$this->assertFalse($checker->isEncryptionEnabled($gatewayConfig));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_encrypt_if_factory_name_is_not_in_disabled_factories(): void
|
||||
{
|
||||
$gatewayConfig = $this->createMock(GatewayConfigInterface::class);
|
||||
$gatewayConfig->method('getFactoryName')->willReturn('sylius');
|
||||
|
||||
$checker = new GatewayConfigEncryptionChecker(['offline']);
|
||||
$this->assertTrue($checker->isEncryptionEnabled($gatewayConfig));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Sylius Sp. z o.o.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sylius\Bundle\PayumBundle\Checker;
|
||||
|
||||
use Sylius\Bundle\PayumBundle\Model\GatewayConfigInterface;
|
||||
use Sylius\Bundle\PaymentBundle\Checker\GatewayConfigEncryptionCheckerInterface;
|
||||
use Sylius\Component\Payment\Model\GatewayConfigInterface as BaseGatewayConfigInterface;
|
||||
|
||||
/** @experimental */
|
||||
final readonly class GatewayConfigEncryptionChecker implements GatewayConfigEncryptionCheckerInterface
|
||||
{
|
||||
public function __construct(
|
||||
private GatewayConfigEncryptionCheckerInterface $decorated,
|
||||
) {
|
||||
}
|
||||
|
||||
/** @param GatewayConfigInterface $gatewayConfig */
|
||||
public function isEncryptionEnabled(BaseGatewayConfigInterface $gatewayConfig): bool
|
||||
{
|
||||
return
|
||||
$this->decorated->isEncryptionEnabled($gatewayConfig) &&
|
||||
!$gatewayConfig->getUsePayum()
|
||||
;
|
||||
}
|
||||
}
|
||||
|
|
@ -17,9 +17,7 @@ use Payum\Core\Security\CryptedInterface;
|
|||
use Sylius\Bundle\PayumBundle\Model\GatewayConfigInterface;
|
||||
use Sylius\Component\Payment\Model\GatewayConfigInterface as BaseGatewayConfigInterface;
|
||||
|
||||
/**
|
||||
* @experimental
|
||||
*/
|
||||
/** @experimental */
|
||||
final readonly class PayumGatewayConfigEncryptionChecker implements PayumGatewayConfigEncryptionCheckerInterface
|
||||
{
|
||||
/** @param GatewayConfigInterface $gatewayConfig */
|
||||
|
|
@ -27,7 +25,7 @@ final readonly class PayumGatewayConfigEncryptionChecker implements PayumGateway
|
|||
{
|
||||
return
|
||||
$gatewayConfig instanceof CryptedInterface &&
|
||||
true === $gatewayConfig->getUsePayum()
|
||||
$gatewayConfig->getUsePayum()
|
||||
;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,9 +4,7 @@ namespace Sylius\Bundle\PayumBundle\Checker;
|
|||
|
||||
use Sylius\Component\Payment\Model\GatewayConfigInterface;
|
||||
|
||||
/**
|
||||
* @experimental
|
||||
*/
|
||||
/** @experimental */
|
||||
interface PayumGatewayConfigEncryptionCheckerInterface
|
||||
{
|
||||
public function isPayumEncryptionEnabled(GatewayConfigInterface $gatewayConfig): bool;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Sylius Sp. z o.o.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sylius\Bundle\PayumBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Sylius\Bundle\PayumBundle\Checker\GatewayConfigEncryptionChecker;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @experimental
|
||||
*/
|
||||
final class ConditionalGatewayConfigEncryptionCheckerDecoratorPass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
if (!$container->has('sylius.checker.gateway_config_encryption')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$container->register('sylius_payum.checker.gateway_config_encryption', GatewayConfigEncryptionChecker::class)
|
||||
->setDecoratedService('sylius.checker.gateway_config_encryption')
|
||||
->addArgument(new Reference('.inner'));
|
||||
}
|
||||
}
|
||||
|
|
@ -16,7 +16,6 @@ namespace Sylius\Bundle\PayumBundle\Form\Extension;
|
|||
use Payum\Core\Security\CypherInterface;
|
||||
use Sylius\Bundle\PaymentBundle\Form\Type\GatewayConfigType;
|
||||
use Sylius\Bundle\PayumBundle\Checker\PayumGatewayConfigEncryptionCheckerInterface;
|
||||
use Sylius\Bundle\PayumBundle\Model\GatewayConfigInterface;
|
||||
use Symfony\Component\Form\AbstractTypeExtension;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Form\FormEvent;
|
||||
|
|
@ -40,7 +39,7 @@ final class CryptedGatewayConfigTypeExtension extends AbstractTypeExtension
|
|||
->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
|
||||
$gatewayConfig = $event->getData();
|
||||
|
||||
if (false === $this->encryptionChecker->isPayumEncryptionEnabled($gatewayConfig)) {
|
||||
if (!$this->encryptionChecker->isPayumEncryptionEnabled($gatewayConfig)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -51,7 +50,7 @@ final class CryptedGatewayConfigTypeExtension extends AbstractTypeExtension
|
|||
->addEventListener(FormEvents::SUBMIT, function (FormEvent $event) {
|
||||
$gatewayConfig = $event->getData();
|
||||
|
||||
if (false === $this->encryptionChecker->isPayumEncryptionEnabled($gatewayConfig)) {
|
||||
if (!$this->encryptionChecker->isPayumEncryptionEnabled($gatewayConfig)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ final class PayumGatewayConfigTypeExtension extends AbstractTypeExtension
|
|||
$event->getForm()->add('usePayum', CheckboxType::class, [
|
||||
'required' => false,
|
||||
'label' => 'sylius.form.gateway_config.use_payum',
|
||||
'disabled' => !($supportPayum && $supportPaymentRequest),
|
||||
'disabled' => !($supportPayum && $supportPaymentRequest) || null !== $gatewayConfig->getId(),
|
||||
]);
|
||||
|
||||
$event->setData($gatewayConfig);
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace Sylius\Bundle\PayumBundle;
|
||||
|
||||
use Sylius\Bundle\PayumBundle\DependencyInjection\Compiler\ConditionalGatewayConfigEncryptionCheckerDecoratorPass;
|
||||
use Sylius\Bundle\PayumBundle\DependencyInjection\Compiler\InjectContainerIntoControllersPass;
|
||||
use Sylius\Bundle\PayumBundle\DependencyInjection\Compiler\UseTweakedDoctrineStoragePass;
|
||||
use Sylius\Bundle\ResourceBundle\AbstractResourceBundle;
|
||||
|
|
@ -33,6 +34,7 @@ final class SyliusPayumBundle extends AbstractResourceBundle
|
|||
{
|
||||
parent::build($container);
|
||||
|
||||
$container->addCompilerPass(new ConditionalGatewayConfigEncryptionCheckerDecoratorPass());
|
||||
$container->addCompilerPass(new InjectContainerIntoControllersPass());
|
||||
$container->addCompilerPass(new UseTweakedDoctrineStoragePass());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Sylius Sp. z o.o.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sylius\Bundle\PayumBundle\Tests\Checker;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Sylius\Bundle\PaymentBundle\Checker\GatewayConfigEncryptionCheckerInterface as BaseGatewayConfigEncryptionCheckerInterface;
|
||||
use Sylius\Bundle\PayumBundle\Checker\GatewayConfigEncryptionChecker;
|
||||
use Sylius\Bundle\PayumBundle\Model\GatewayConfigInterface;
|
||||
|
||||
final class GatewayConfigEncryptionCheckerTest extends TestCase
|
||||
{
|
||||
/** @test */
|
||||
public function it_cannot_encrypt_when_base_class_returns_false(): void
|
||||
{
|
||||
$gatewayConfig = $this->createMock(GatewayConfigInterface::class);
|
||||
$decoratedChecker = $this->createMock(BaseGatewayConfigEncryptionCheckerInterface::class);
|
||||
$decoratedChecker->method('isEncryptionEnabled')->willReturn(false);
|
||||
|
||||
$checker = new GatewayConfigEncryptionChecker($decoratedChecker);
|
||||
$this->assertFalse($checker->isEncryptionEnabled($gatewayConfig));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_cannot_encrypt_when_gateway_config_use_payum(): void
|
||||
{
|
||||
$gatewayConfig = $this->createMock(GatewayConfigInterface::class);
|
||||
$gatewayConfig->method('getUsePayum')->willReturn(true);
|
||||
$decoratedChecker = $this->createMock(BaseGatewayConfigEncryptionCheckerInterface::class);
|
||||
$decoratedChecker->method('isEncryptionEnabled')->willReturn(true);
|
||||
|
||||
$checker = new GatewayConfigEncryptionChecker($decoratedChecker);
|
||||
$this->assertFalse($checker->isEncryptionEnabled($gatewayConfig));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_can_encrypt_when_base_class_returns_true_and_gateway_config_does_not_use_payum(): void
|
||||
{
|
||||
$gatewayConfig = $this->createMock(GatewayConfigInterface::class);
|
||||
$gatewayConfig->method('getUsePayum')->willReturn(false);
|
||||
$decoratedChecker = $this->createMock(BaseGatewayConfigEncryptionCheckerInterface::class);
|
||||
$decoratedChecker->method('isEncryptionEnabled')->willReturn(true);
|
||||
|
||||
$checker = new GatewayConfigEncryptionChecker($decoratedChecker);
|
||||
$this->assertTrue($checker->isEncryptionEnabled($gatewayConfig));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Sylius Sp. z o.o.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sylius\Bundle\PayumBundle\Tests\DependencyInjection\Compiler;
|
||||
|
||||
use Matthias\SymfonyDependencyInjectionTest\PhpUnit\AbstractCompilerPassTestCase;
|
||||
use Sylius\Bundle\PayumBundle\DependencyInjection\Compiler\ConditionalGatewayConfigEncryptionCheckerDecoratorPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
final class ConditionalGatewayConfigEncryptionCheckerDecoratorPassTest extends AbstractCompilerPassTestCase
|
||||
{
|
||||
/** @test */
|
||||
public function it_registers_gateway_config_encryption_checker_decorator_if_checker_service_exists(): void
|
||||
{
|
||||
$this->setDefinition('sylius.checker.gateway_config_encryption', new Definition());
|
||||
|
||||
$this->compile();
|
||||
|
||||
$this->assertContainerBuilderHasServiceDefinitionWithArgument('sylius_payum.checker.gateway_config_encryption', 0, new Reference('.inner'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_does_not_register_gateway_config_encryption_checker_decorator_if_checker_service_does_not_exist(): void
|
||||
{
|
||||
$this->compile();
|
||||
|
||||
$this->assertContainerBuilderNotHasService('sylius_payum.checker.gateway_config_encryption');
|
||||
}
|
||||
|
||||
protected function registerCompilerPass(ContainerBuilder $container): void
|
||||
{
|
||||
$container->addCompilerPass(new ConditionalGatewayConfigEncryptionCheckerDecoratorPass());
|
||||
}
|
||||
}
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
</php>
|
||||
|
||||
<testsuites>
|
||||
<testsuite name="SyliusUserBundle Test Suite">
|
||||
<testsuite name="SyliusPayumBundle Test Suite">
|
||||
<directory>./Tests/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
|
|
|||
|
|
@ -25,10 +25,6 @@ use Sylius\Component\Payment\Encryption\Exception\EncryptionException;
|
|||
/** @experimental */
|
||||
final class Encrypter implements EncrypterInterface
|
||||
{
|
||||
private const ENCRYPTION_SUFFIX = '#ENCRYPTED';
|
||||
|
||||
private const ENCRYPTION_SUFFIX_LENGTH = 10;
|
||||
|
||||
private ?EncryptionKey $key = null;
|
||||
|
||||
public function __construct(
|
||||
|
|
|
|||
|
|
@ -18,6 +18,10 @@ use Sylius\Component\Payment\Encryption\Exception\EncryptionException;
|
|||
/** @experimental */
|
||||
interface EncrypterInterface
|
||||
{
|
||||
public const ENCRYPTION_SUFFIX = '#ENCRYPTED';
|
||||
|
||||
public const ENCRYPTION_SUFFIX_LENGTH = 10;
|
||||
|
||||
/** @throws EncryptionException */
|
||||
public function encrypt(string $data): string;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Sylius Sp. z o.o.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sylius\Component\Payment\Encryption;
|
||||
|
||||
/** @experimental */
|
||||
trait EncryptionCheckTrait
|
||||
{
|
||||
protected function isEncrypted(mixed $value): bool
|
||||
{
|
||||
return is_string($value) && str_ends_with($value, EncrypterInterface::ENCRYPTION_SUFFIX);
|
||||
}
|
||||
}
|
||||
|
|
@ -22,6 +22,8 @@ use Sylius\Component\Payment\Model\GatewayConfigInterface;
|
|||
*/
|
||||
final readonly class GatewayConfigEncrypter implements EntityEncrypterInterface
|
||||
{
|
||||
use EncryptionCheckTrait;
|
||||
|
||||
public function __construct(
|
||||
private EncrypterInterface $encrypter,
|
||||
) {
|
||||
|
|
@ -39,6 +41,10 @@ final readonly class GatewayConfigEncrypter implements EntityEncrypterInterface
|
|||
|
||||
public function decrypt(EncryptionAwareInterface $resource): void
|
||||
{
|
||||
if (!$this->isEncrypted(current($resource->getConfig()))) {
|
||||
return;
|
||||
}
|
||||
|
||||
$decryptedConfig = [];
|
||||
foreach ($resource->getConfig() as $key => $value) {
|
||||
$decryptedConfig[$key] = unserialize($this->encrypter->decrypt($value));
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ use Sylius\Component\Payment\Model\PaymentRequestInterface;
|
|||
*/
|
||||
final readonly class PaymentRequestEncrypter implements EntityEncrypterInterface
|
||||
{
|
||||
use EncryptionCheckTrait;
|
||||
|
||||
public function __construct(
|
||||
private EncrypterInterface $encrypter,
|
||||
) {
|
||||
|
|
@ -43,10 +45,14 @@ final readonly class PaymentRequestEncrypter implements EntityEncrypterInterface
|
|||
|
||||
public function decrypt(EncryptionAwareInterface $resource): void
|
||||
{
|
||||
if (null !== $resource->getPayload()) {
|
||||
if (null !== $resource->getPayload() && $this->isEncrypted($resource->getPayload())) {
|
||||
$resource->setPayload(unserialize($this->encrypter->decrypt($resource->getPayload())));
|
||||
}
|
||||
|
||||
if (!$this->isEncrypted(current($resource->getResponseData()))) {
|
||||
return;
|
||||
}
|
||||
|
||||
$decryptedRequestData = [];
|
||||
foreach ($resource->getResponseData() as $key => $value) {
|
||||
$decryptedRequestData[$key] = unserialize($this->encrypter->decrypt($value));
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ namespace Sylius\Component\Payment\Model;
|
|||
|
||||
class GatewayConfig implements GatewayConfigInterface
|
||||
{
|
||||
protected mixed $id;
|
||||
protected mixed $id = null;
|
||||
|
||||
protected ?string $factoryName = null;
|
||||
|
||||
|
|
|
|||
|
|
@ -78,7 +78,23 @@ final class GatewayConfigEncrypterSpec extends ObjectBehavior
|
|||
|
||||
$encrypter->decrypt(Argument::any())->shouldNotBeCalled();
|
||||
|
||||
$gatewayConfig->setConfig([])->shouldBeCalled();
|
||||
$gatewayConfig->setConfig(Argument::any())->shouldNotBeCalled();
|
||||
|
||||
$this->decrypt($gatewayConfig);
|
||||
}
|
||||
|
||||
function it_does_not_decrypt_config_when_its_elements_are_not_encrypted_strings(
|
||||
EncrypterInterface $encrypter,
|
||||
GatewayConfigInterface $gatewayConfig,
|
||||
): void {
|
||||
$gatewayConfig->getConfig()->willReturn([
|
||||
'key' => 'not_encrypted_value',
|
||||
'key-two' => 'not_encrypted_value',
|
||||
]);
|
||||
|
||||
$encrypter->decrypt(Argument::any())->shouldNotBeCalled();
|
||||
|
||||
$gatewayConfig->setConfig(Argument::any())->shouldNotBeCalled();
|
||||
|
||||
$this->decrypt($gatewayConfig);
|
||||
}
|
||||
|
|
@ -87,9 +103,9 @@ final class GatewayConfigEncrypterSpec extends ObjectBehavior
|
|||
EncrypterInterface $encrypter,
|
||||
GatewayConfigInterface $gatewayConfig,
|
||||
): void {
|
||||
$gatewayConfig->getConfig()->willReturn(['key' => 'encrypted_value']);
|
||||
$gatewayConfig->getConfig()->willReturn(['key' => 'encrypted_value#ENCRYPTED']);
|
||||
|
||||
$encrypter->decrypt('encrypted_value')->willReturn(serialize('value'));
|
||||
$encrypter->decrypt('encrypted_value#ENCRYPTED')->willReturn(serialize('value'));
|
||||
|
||||
$gatewayConfig->setConfig(['key' => 'value'])->shouldBeCalled();
|
||||
|
||||
|
|
@ -100,11 +116,15 @@ final class GatewayConfigEncrypterSpec extends ObjectBehavior
|
|||
EncrypterInterface $encrypter,
|
||||
GatewayConfigInterface $gatewayConfig,
|
||||
): void {
|
||||
$gatewayConfig->getConfig()->willReturn(['key' => 'encrypted_value']);
|
||||
$gatewayConfig->getConfig()->willReturn([
|
||||
'key' => 'encrypted_value#ENCRYPTED',
|
||||
'key-two' => 'encrypted_value-two#ENCRYPTED',
|
||||
]);
|
||||
|
||||
$encrypter->decrypt('encrypted_value')->willReturn(serialize(['value', 'some_other_value']));
|
||||
$encrypter->decrypt('encrypted_value#ENCRYPTED')->willReturn(serialize(['value', 'some_other_value']));
|
||||
$encrypter->decrypt('encrypted_value-two#ENCRYPTED')->willReturn(serialize('TWO'));
|
||||
|
||||
$gatewayConfig->setConfig(['key' => ['value', 'some_other_value']])->shouldBeCalled();
|
||||
$gatewayConfig->setConfig(['key' => ['value', 'some_other_value'], 'key-two' => 'TWO'])->shouldBeCalled();
|
||||
|
||||
$this->decrypt($gatewayConfig);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -130,8 +130,33 @@ final class PaymentRequestEncrypterSpec extends ObjectBehavior
|
|||
$paymentRequest->getResponseData()->willReturn([]);
|
||||
|
||||
$encrypter->decrypt(Argument::any())->shouldNotBeCalled();
|
||||
$paymentRequest->setResponseData(Argument::any())->shouldNotBeCalled();
|
||||
|
||||
$paymentRequest->setResponseData([])->shouldBeCalled();
|
||||
$this->decrypt($paymentRequest);
|
||||
}
|
||||
|
||||
function it_does_not_decrypt_payment_request_is_not_string(
|
||||
PaymentRequestInterface $paymentRequest,
|
||||
EncrypterInterface $encrypter,
|
||||
): void {
|
||||
$paymentRequest->getPayload()->willReturn(['array']);
|
||||
$paymentRequest->getResponseData()->willReturn([]);
|
||||
|
||||
$encrypter->decrypt(Argument::any())->shouldNotBeCalled();
|
||||
$paymentRequest->setResponseData(Argument::any())->shouldNotBeCalled();
|
||||
|
||||
$this->decrypt($paymentRequest);
|
||||
}
|
||||
|
||||
function it_does_not_decrypt_payment_request_is_not_encrypted_string(
|
||||
PaymentRequestInterface $paymentRequest,
|
||||
EncrypterInterface $encrypter,
|
||||
): void {
|
||||
$paymentRequest->getPayload()->willReturn('not_encrypted_payload');
|
||||
$paymentRequest->getResponseData()->willReturn([]);
|
||||
|
||||
$encrypter->decrypt(Argument::any())->shouldNotBeCalled();
|
||||
$paymentRequest->setResponseData(Argument::any())->shouldNotBeCalled();
|
||||
|
||||
$this->decrypt($paymentRequest);
|
||||
}
|
||||
|
|
@ -140,13 +165,13 @@ final class PaymentRequestEncrypterSpec extends ObjectBehavior
|
|||
PaymentRequestInterface $paymentRequest,
|
||||
EncrypterInterface $encrypter,
|
||||
): void {
|
||||
$paymentRequest->getPayload()->willReturn('encrypted_payload');
|
||||
$paymentRequest->getPayload()->willReturn('encrypted_payload#ENCRYPTED');
|
||||
$paymentRequest->getResponseData()->willReturn([]);
|
||||
|
||||
$encrypter->decrypt('encrypted_payload')->willReturn(serialize('payload'));
|
||||
$encrypter->decrypt('encrypted_payload#ENCRYPTED')->willReturn(serialize('payload'));
|
||||
|
||||
$paymentRequest->setPayload('payload')->shouldBeCalled();
|
||||
$paymentRequest->setResponseData([])->shouldBeCalled();
|
||||
$paymentRequest->setResponseData(Argument::any())->shouldNotBeCalled();
|
||||
|
||||
$this->decrypt($paymentRequest);
|
||||
}
|
||||
|
|
@ -155,13 +180,13 @@ final class PaymentRequestEncrypterSpec extends ObjectBehavior
|
|||
PaymentRequestInterface $paymentRequest,
|
||||
EncrypterInterface $encrypter,
|
||||
): void {
|
||||
$paymentRequest->getPayload()->willReturn('encrypted_payload');
|
||||
$paymentRequest->getPayload()->willReturn('encrypted_payload#ENCRYPTED');
|
||||
$paymentRequest->getResponseData()->willReturn([]);
|
||||
|
||||
$encrypter->decrypt('encrypted_payload')->willReturn(serialize(['key' => 'value']));
|
||||
$encrypter->decrypt('encrypted_payload#ENCRYPTED')->willReturn(serialize(['key' => 'value']));
|
||||
|
||||
$paymentRequest->setPayload(['key' => 'value'])->shouldBeCalled();
|
||||
$paymentRequest->setResponseData([])->shouldBeCalled();
|
||||
$paymentRequest->setResponseData(Argument::any())->shouldNotBeCalled();
|
||||
|
||||
$this->decrypt($paymentRequest);
|
||||
}
|
||||
|
|
@ -170,15 +195,51 @@ final class PaymentRequestEncrypterSpec extends ObjectBehavior
|
|||
PaymentRequestInterface $paymentRequest,
|
||||
EncrypterInterface $encrypter,
|
||||
): void {
|
||||
$paymentRequest->getPayload()->willReturn('encrypted_payload');
|
||||
$paymentRequest->getPayload()->willReturn('encrypted_payload#ENCRYPTED');
|
||||
$paymentRequest->getResponseData()->willReturn([]);
|
||||
|
||||
$object = new \stdClass();
|
||||
|
||||
$encrypter->decrypt('encrypted_payload')->willReturn(serialize($object));
|
||||
$encrypter->decrypt('encrypted_payload#ENCRYPTED')->willReturn(serialize($object));
|
||||
|
||||
$paymentRequest->setPayload($object)->shouldBeCalled();
|
||||
$paymentRequest->setResponseData([])->shouldBeCalled();
|
||||
$paymentRequest->setResponseData(Argument::any())->shouldNotBeCalled();
|
||||
|
||||
$this->decrypt($paymentRequest);
|
||||
}
|
||||
|
||||
function it_does_not_decrypt_response_data_when_its_elements_are_not_strings(
|
||||
PaymentRequestInterface $paymentRequest,
|
||||
EncrypterInterface $encrypter,
|
||||
): void {
|
||||
$paymentRequest->getPayload()->willReturn(null);
|
||||
$paymentRequest->getResponseData()->willReturn([
|
||||
'array' => ['value'],
|
||||
'array-two' => ['value'],
|
||||
]);
|
||||
|
||||
$encrypter->decrypt(Argument::any())->shouldNotBeCalled();
|
||||
|
||||
$paymentRequest->setPayload(null)->shouldNotBeCalled();
|
||||
$paymentRequest->setResponseData(Argument::any())->shouldNotBeCalled();
|
||||
|
||||
$this->decrypt($paymentRequest);
|
||||
}
|
||||
|
||||
function it_does_not_decrypt_response_data_when_its_elements_are_not_encrypted_strings(
|
||||
PaymentRequestInterface $paymentRequest,
|
||||
EncrypterInterface $encrypter,
|
||||
): void {
|
||||
$paymentRequest->getPayload()->willReturn(null);
|
||||
$paymentRequest->getResponseData()->willReturn([
|
||||
'key' => 'not_encrypted_value',
|
||||
'key-two' => 'not_encrypted_value',
|
||||
]);
|
||||
|
||||
$encrypter->decrypt(Argument::any())->shouldNotBeCalled();
|
||||
|
||||
$paymentRequest->setPayload(null)->shouldNotBeCalled();
|
||||
$paymentRequest->setResponseData(Argument::any())->shouldNotBeCalled();
|
||||
|
||||
$this->decrypt($paymentRequest);
|
||||
}
|
||||
|
|
@ -188,9 +249,9 @@ final class PaymentRequestEncrypterSpec extends ObjectBehavior
|
|||
EncrypterInterface $encrypter,
|
||||
): void {
|
||||
$paymentRequest->getPayload()->willReturn(null);
|
||||
$paymentRequest->getResponseData()->willReturn(['key' => 'encrypted_value']);
|
||||
$paymentRequest->getResponseData()->willReturn(['key' => 'encrypted_value#ENCRYPTED']);
|
||||
|
||||
$encrypter->decrypt('encrypted_value')->willReturn(serialize('value'));
|
||||
$encrypter->decrypt('encrypted_value#ENCRYPTED')->willReturn(serialize('value'));
|
||||
|
||||
$paymentRequest->setPayload(null)->shouldNotBeCalled();
|
||||
$paymentRequest->setResponseData(['key' => 'value'])->shouldBeCalled();
|
||||
|
|
@ -203,9 +264,9 @@ final class PaymentRequestEncrypterSpec extends ObjectBehavior
|
|||
EncrypterInterface $encrypter,
|
||||
): void {
|
||||
$paymentRequest->getPayload()->willReturn(null);
|
||||
$paymentRequest->getResponseData()->willReturn(['key' => 'encrypted_value']);
|
||||
$paymentRequest->getResponseData()->willReturn(['key' => 'encrypted_value#ENCRYPTED']);
|
||||
|
||||
$encrypter->decrypt('encrypted_value')->willReturn(serialize(['value', 'some_other_value']));
|
||||
$encrypter->decrypt('encrypted_value#ENCRYPTED')->willReturn(serialize(['value', 'some_other_value']));
|
||||
|
||||
$paymentRequest->setPayload(null)->shouldNotBeCalled();
|
||||
$paymentRequest->setResponseData(['key' => ['value', 'some_other_value']])->shouldBeCalled();
|
||||
|
|
|
|||
|
|
@ -48,11 +48,12 @@ final class GatewayConfigEncryptionTest extends KernelTestCase
|
|||
$this->gatewayConfigRepository = self::getContainer()->get('sylius.repository.gateway_config');
|
||||
$this->gatewayFactory = self::getContainer()->get('sylius.factory.gateway_config');
|
||||
|
||||
$gatewayConfigEncryptionChecker = self::getContainer()->get('sylius.checker.gateway_config_encryption');
|
||||
$encrypter = self::getContainer()->get('sylius.encrypter.gateway_config');
|
||||
self::getContainer()->set('sylius.listener.gateway_config_encryption', new GatewayConfigEncryptionListener(
|
||||
$encrypter,
|
||||
'Sylius\Bundle\PayumBundle\Model\GatewayConfig',
|
||||
['online-disabled'],
|
||||
$gatewayConfigEncryptionChecker,
|
||||
));
|
||||
|
||||
$this->loadFixtures([
|
||||
|
|
@ -66,6 +67,7 @@ final class GatewayConfigEncryptionTest extends KernelTestCase
|
|||
$gatewayConfig = $this->gatewayFactory->createNew();
|
||||
$gatewayConfig->setGatewayName('Online');
|
||||
$gatewayConfig->setFactoryName('online');
|
||||
$gatewayConfig->setUsePayum(false);
|
||||
$gatewayConfig->setConfig(self::$gatewayConfigData);
|
||||
|
||||
$this->gatewayConfigRepository->add($gatewayConfig);
|
||||
|
|
@ -91,6 +93,7 @@ final class GatewayConfigEncryptionTest extends KernelTestCase
|
|||
$gatewayConfig = $this->gatewayFactory->createNew();
|
||||
$gatewayConfig->setGatewayName('online_disabled');
|
||||
$gatewayConfig->setFactoryName('online-disabled');
|
||||
$gatewayConfig->setUsePayum(false);
|
||||
$gatewayConfig->setConfig(self::$gatewayConfigData);
|
||||
|
||||
$this->gatewayConfigRepository->add($gatewayConfig);
|
||||
|
|
@ -110,12 +113,39 @@ final class GatewayConfigEncryptionTest extends KernelTestCase
|
|||
self::assertSame(self::$gatewayConfigData, $gatewayConfigFromDatabase);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_does_not_encrypt_when_gateway_config_use_payum(): void
|
||||
{
|
||||
$gatewayConfig = $this->gatewayFactory->createNew();
|
||||
$gatewayConfig->setGatewayName('Online');
|
||||
$gatewayConfig->setFactoryName('online');
|
||||
$gatewayConfig->setUsePayum(true);
|
||||
$gatewayConfig->setConfig(self::$gatewayConfigData);
|
||||
|
||||
$this->gatewayConfigRepository->add($gatewayConfig);
|
||||
self::assertSame(self::$gatewayConfigData, $gatewayConfig->getConfig());
|
||||
|
||||
$this->entityManager->clear();
|
||||
|
||||
$gatewayConfigFromDatabase = $this->getDatabaseConfigDataForGateway('Online');
|
||||
self::assertSame($gatewayConfig->getConfig(), $gatewayConfigFromDatabase);
|
||||
|
||||
$gatewayFromRepository = $this->gatewayConfigRepository->findOneBy(['gatewayName' => 'Online']);
|
||||
self::assertSame($gatewayConfig->getConfig(), $gatewayFromRepository->getConfig());
|
||||
self::assertSame(self::$gatewayConfigData, $gatewayConfig->getConfig());
|
||||
|
||||
$gatewayConfigFromDatabase = $this->getDatabaseConfigDataForGateway('Online');
|
||||
self::assertSame($gatewayConfig->getConfig(), $gatewayConfigFromDatabase);
|
||||
self::assertSame(self::$gatewayConfigData, $gatewayConfigFromDatabase);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_does_not_encrypt_empty_config(): void
|
||||
{
|
||||
$gatewayConfig = $this->gatewayFactory->createNew();
|
||||
$gatewayConfig->setGatewayName('Online');
|
||||
$gatewayConfig->setFactoryName('online');
|
||||
$gatewayConfig->setUsePayum(false);
|
||||
$gatewayConfig->setConfig([]);
|
||||
|
||||
$this->gatewayConfigRepository->add($gatewayConfig);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue