[PaymentBundle] Use a single encryption method

This commit is contained in:
Wojdylak 2024-10-29 14:50:34 +01:00
parent 1055a2afa7
commit 2126d7e3fa
No known key found for this signature in database
GPG key ID: 7509E560A6821ABE
29 changed files with 479 additions and 43 deletions

View file

@ -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

View file

@ -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

View file

@ -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
*/

View file

@ -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]',
]);
}
}

View file

@ -29,6 +29,8 @@ interface UpdatePageInterface extends BaseUpdatePageInterface
public function isFactoryNameFieldDisabled(): bool;
public function isUsePayumFieldDisabled(): bool;
public function isPaymentMethodEnabled(): bool;
public function isPaymentMethodInSandboxMode(): bool;

View file

@ -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);
}
}

View file

@ -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;
}

View file

@ -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)
;
}
}

View file

@ -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" />

View file

@ -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));
}
}

View file

@ -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()
;
}
}

View file

@ -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()
;
}
}

View file

@ -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;

View file

@ -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'));
}
}

View file

@ -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;
}

View file

@ -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);

View file

@ -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());
}

View file

@ -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));
}
}

View file

@ -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());
}
}

View file

@ -9,7 +9,7 @@
</php>
<testsuites>
<testsuite name="SyliusUserBundle Test Suite">
<testsuite name="SyliusPayumBundle Test Suite">
<directory>./Tests/</directory>
</testsuite>
</testsuites>

View file

@ -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(

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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));

View file

@ -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));

View file

@ -15,7 +15,7 @@ namespace Sylius\Component\Payment\Model;
class GatewayConfig implements GatewayConfigInterface
{
protected mixed $id;
protected mixed $id = null;
protected ?string $factoryName = null;

View file

@ -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);
}

View file

@ -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();

View file

@ -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);