diff --git a/config/packages/test/_sylius.yaml b/config/packages/test/_sylius.yaml index 9da08880cd..8446871a02 100644 --- a/config/packages/test/_sylius.yaml +++ b/config/packages/test/_sylius.yaml @@ -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 diff --git a/features/admin/payment/managing_payment_methods/editing_payment_method.feature b/features/admin/payment/managing_payment_methods/editing_payment_method.feature index ecbb14057e..7e724ae885 100644 --- a/features/admin/payment/managing_payment_methods/editing_payment_method.feature +++ b/features/admin/payment/managing_payment_methods/editing_payment_method.feature @@ -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 diff --git a/src/Sylius/Behat/Context/Ui/Admin/ManagingPaymentMethodsContext.php b/src/Sylius/Behat/Context/Ui/Admin/ManagingPaymentMethodsContext.php index e18aca5cdf..af001a5151 100644 --- a/src/Sylius/Behat/Context/Ui/Admin/ManagingPaymentMethodsContext.php +++ b/src/Sylius/Behat/Context/Ui/Admin/ManagingPaymentMethodsContext.php @@ -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 */ diff --git a/src/Sylius/Behat/Page/Admin/PaymentMethod/UpdatePage.php b/src/Sylius/Behat/Page/Admin/PaymentMethod/UpdatePage.php index fda17356c7..8a280170a9 100644 --- a/src/Sylius/Behat/Page/Admin/PaymentMethod/UpdatePage.php +++ b/src/Sylius/Behat/Page/Admin/PaymentMethod/UpdatePage.php @@ -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]', ]); } } diff --git a/src/Sylius/Behat/Page/Admin/PaymentMethod/UpdatePageInterface.php b/src/Sylius/Behat/Page/Admin/PaymentMethod/UpdatePageInterface.php index 86e86e7e73..449c505aa3 100644 --- a/src/Sylius/Behat/Page/Admin/PaymentMethod/UpdatePageInterface.php +++ b/src/Sylius/Behat/Page/Admin/PaymentMethod/UpdatePageInterface.php @@ -29,6 +29,8 @@ interface UpdatePageInterface extends BaseUpdatePageInterface public function isFactoryNameFieldDisabled(): bool; + public function isUsePayumFieldDisabled(): bool; + public function isPaymentMethodEnabled(): bool; public function isPaymentMethodInSandboxMode(): bool; diff --git a/src/Sylius/Bundle/PaymentBundle/Checker/GatewayConfigEncryptionChecker.php b/src/Sylius/Bundle/PaymentBundle/Checker/GatewayConfigEncryptionChecker.php new file mode 100644 index 0000000000..d398901712 --- /dev/null +++ b/src/Sylius/Bundle/PaymentBundle/Checker/GatewayConfigEncryptionChecker.php @@ -0,0 +1,33 @@ + $disabledGatewayFactories + */ + public function __construct( + private array $disabledGatewayFactories, + ) { + } + + public function isEncryptionEnabled(GatewayConfigInterface $gatewayConfig): bool + { + return !in_array($gatewayConfig->getFactoryName(), $this->disabledGatewayFactories, true); + } +} diff --git a/src/Sylius/Bundle/PaymentBundle/Checker/GatewayConfigEncryptionCheckerInterface.php b/src/Sylius/Bundle/PaymentBundle/Checker/GatewayConfigEncryptionCheckerInterface.php new file mode 100644 index 0000000000..5c8b28e908 --- /dev/null +++ b/src/Sylius/Bundle/PaymentBundle/Checker/GatewayConfigEncryptionCheckerInterface.php @@ -0,0 +1,12 @@ + $entityEncrypter * @param class-string $entityClass - * @param array $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) ; } } diff --git a/src/Sylius/Bundle/PaymentBundle/Resources/config/services/encryption/encryption.xml b/src/Sylius/Bundle/PaymentBundle/Resources/config/services/encryption/encryption.xml index db83ca6ec1..329cefb58f 100644 --- a/src/Sylius/Bundle/PaymentBundle/Resources/config/services/encryption/encryption.xml +++ b/src/Sylius/Bundle/PaymentBundle/Resources/config/services/encryption/encryption.xml @@ -17,6 +17,11 @@ xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd" > + + %sylius.encryption.disabled_for_factories% + + + %env(resolve:SYLIUS_PAYMENT_ENCRYPTION_KEY_PATH)% @@ -33,7 +38,7 @@ %sylius.model.gateway_config.class% - %sylius.encryption.disabled_for_factories% + diff --git a/src/Sylius/Bundle/PaymentBundle/Tests/Checker/GatewayConfigEncryptionCheckerTest.php b/src/Sylius/Bundle/PaymentBundle/Tests/Checker/GatewayConfigEncryptionCheckerTest.php new file mode 100644 index 0000000000..99e2a9f357 --- /dev/null +++ b/src/Sylius/Bundle/PaymentBundle/Tests/Checker/GatewayConfigEncryptionCheckerTest.php @@ -0,0 +1,41 @@ +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)); + } +} diff --git a/src/Sylius/Bundle/PayumBundle/Checker/GatewayConfigEncryptionChecker.php b/src/Sylius/Bundle/PayumBundle/Checker/GatewayConfigEncryptionChecker.php new file mode 100644 index 0000000000..ceae6744d6 --- /dev/null +++ b/src/Sylius/Bundle/PayumBundle/Checker/GatewayConfigEncryptionChecker.php @@ -0,0 +1,36 @@ +decorated->isEncryptionEnabled($gatewayConfig) && + !$gatewayConfig->getUsePayum() + ; + } +} diff --git a/src/Sylius/Bundle/PayumBundle/Checker/PayumGatewayConfigEncryptionChecker.php b/src/Sylius/Bundle/PayumBundle/Checker/PayumGatewayConfigEncryptionChecker.php index 15bb908894..24751e78b8 100644 --- a/src/Sylius/Bundle/PayumBundle/Checker/PayumGatewayConfigEncryptionChecker.php +++ b/src/Sylius/Bundle/PayumBundle/Checker/PayumGatewayConfigEncryptionChecker.php @@ -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() ; } } diff --git a/src/Sylius/Bundle/PayumBundle/Checker/PayumGatewayConfigEncryptionCheckerInterface.php b/src/Sylius/Bundle/PayumBundle/Checker/PayumGatewayConfigEncryptionCheckerInterface.php index fc21ce6fb2..11196be7da 100644 --- a/src/Sylius/Bundle/PayumBundle/Checker/PayumGatewayConfigEncryptionCheckerInterface.php +++ b/src/Sylius/Bundle/PayumBundle/Checker/PayumGatewayConfigEncryptionCheckerInterface.php @@ -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; diff --git a/src/Sylius/Bundle/PayumBundle/DependencyInjection/Compiler/ConditionalGatewayConfigEncryptionCheckerDecoratorPass.php b/src/Sylius/Bundle/PayumBundle/DependencyInjection/Compiler/ConditionalGatewayConfigEncryptionCheckerDecoratorPass.php new file mode 100644 index 0000000000..e6e00d6ee0 --- /dev/null +++ b/src/Sylius/Bundle/PayumBundle/DependencyInjection/Compiler/ConditionalGatewayConfigEncryptionCheckerDecoratorPass.php @@ -0,0 +1,37 @@ +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')); + } +} diff --git a/src/Sylius/Bundle/PayumBundle/Form/Extension/CryptedGatewayConfigTypeExtension.php b/src/Sylius/Bundle/PayumBundle/Form/Extension/CryptedGatewayConfigTypeExtension.php index 4a1ca0a9e1..3805788e53 100644 --- a/src/Sylius/Bundle/PayumBundle/Form/Extension/CryptedGatewayConfigTypeExtension.php +++ b/src/Sylius/Bundle/PayumBundle/Form/Extension/CryptedGatewayConfigTypeExtension.php @@ -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; } diff --git a/src/Sylius/Bundle/PayumBundle/Form/Extension/PayumGatewayConfigTypeExtension.php b/src/Sylius/Bundle/PayumBundle/Form/Extension/PayumGatewayConfigTypeExtension.php index 7be99ab1f1..d5b1030976 100644 --- a/src/Sylius/Bundle/PayumBundle/Form/Extension/PayumGatewayConfigTypeExtension.php +++ b/src/Sylius/Bundle/PayumBundle/Form/Extension/PayumGatewayConfigTypeExtension.php @@ -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); diff --git a/src/Sylius/Bundle/PayumBundle/SyliusPayumBundle.php b/src/Sylius/Bundle/PayumBundle/SyliusPayumBundle.php index acf57702c8..9901c5e8a8 100644 --- a/src/Sylius/Bundle/PayumBundle/SyliusPayumBundle.php +++ b/src/Sylius/Bundle/PayumBundle/SyliusPayumBundle.php @@ -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()); } diff --git a/src/Sylius/Bundle/PayumBundle/Tests/Checker/GatewayConfigEncryptionCheckerTest.php b/src/Sylius/Bundle/PayumBundle/Tests/Checker/GatewayConfigEncryptionCheckerTest.php new file mode 100644 index 0000000000..9dda87a196 --- /dev/null +++ b/src/Sylius/Bundle/PayumBundle/Tests/Checker/GatewayConfigEncryptionCheckerTest.php @@ -0,0 +1,57 @@ +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)); + } +} diff --git a/src/Sylius/Bundle/PayumBundle/Tests/DependencyInjection/Compiler/ConditionalGatewayConfigEncryptionCheckerDecoratorPassTest.php b/src/Sylius/Bundle/PayumBundle/Tests/DependencyInjection/Compiler/ConditionalGatewayConfigEncryptionCheckerDecoratorPassTest.php new file mode 100644 index 0000000000..34c45c5051 --- /dev/null +++ b/src/Sylius/Bundle/PayumBundle/Tests/DependencyInjection/Compiler/ConditionalGatewayConfigEncryptionCheckerDecoratorPassTest.php @@ -0,0 +1,46 @@ +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()); + } +} diff --git a/src/Sylius/Bundle/PayumBundle/phpunit.xml.dist b/src/Sylius/Bundle/PayumBundle/phpunit.xml.dist index 99985f0ea0..20f2829b34 100644 --- a/src/Sylius/Bundle/PayumBundle/phpunit.xml.dist +++ b/src/Sylius/Bundle/PayumBundle/phpunit.xml.dist @@ -9,7 +9,7 @@ - + ./Tests/ diff --git a/src/Sylius/Component/Payment/Encryption/Encrypter.php b/src/Sylius/Component/Payment/Encryption/Encrypter.php index c0a5bd2763..cd43efd6d7 100644 --- a/src/Sylius/Component/Payment/Encryption/Encrypter.php +++ b/src/Sylius/Component/Payment/Encryption/Encrypter.php @@ -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( diff --git a/src/Sylius/Component/Payment/Encryption/EncrypterInterface.php b/src/Sylius/Component/Payment/Encryption/EncrypterInterface.php index 7572af98e9..363dc4df7d 100644 --- a/src/Sylius/Component/Payment/Encryption/EncrypterInterface.php +++ b/src/Sylius/Component/Payment/Encryption/EncrypterInterface.php @@ -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; diff --git a/src/Sylius/Component/Payment/Encryption/EncryptionCheckTrait.php b/src/Sylius/Component/Payment/Encryption/EncryptionCheckTrait.php new file mode 100644 index 0000000000..93e1c90614 --- /dev/null +++ b/src/Sylius/Component/Payment/Encryption/EncryptionCheckTrait.php @@ -0,0 +1,23 @@ +isEncrypted(current($resource->getConfig()))) { + return; + } + $decryptedConfig = []; foreach ($resource->getConfig() as $key => $value) { $decryptedConfig[$key] = unserialize($this->encrypter->decrypt($value)); diff --git a/src/Sylius/Component/Payment/Encryption/PaymentRequestEncrypter.php b/src/Sylius/Component/Payment/Encryption/PaymentRequestEncrypter.php index 83e69ba65d..19b8dc27ed 100644 --- a/src/Sylius/Component/Payment/Encryption/PaymentRequestEncrypter.php +++ b/src/Sylius/Component/Payment/Encryption/PaymentRequestEncrypter.php @@ -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)); diff --git a/src/Sylius/Component/Payment/Model/GatewayConfig.php b/src/Sylius/Component/Payment/Model/GatewayConfig.php index c4fe8f89ef..68410ac6c3 100644 --- a/src/Sylius/Component/Payment/Model/GatewayConfig.php +++ b/src/Sylius/Component/Payment/Model/GatewayConfig.php @@ -15,7 +15,7 @@ namespace Sylius\Component\Payment\Model; class GatewayConfig implements GatewayConfigInterface { - protected mixed $id; + protected mixed $id = null; protected ?string $factoryName = null; diff --git a/src/Sylius/Component/Payment/spec/Encryption/GatewayConfigEncrypterSpec.php b/src/Sylius/Component/Payment/spec/Encryption/GatewayConfigEncrypterSpec.php index 14c1755750..2e3095f147 100644 --- a/src/Sylius/Component/Payment/spec/Encryption/GatewayConfigEncrypterSpec.php +++ b/src/Sylius/Component/Payment/spec/Encryption/GatewayConfigEncrypterSpec.php @@ -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); } diff --git a/src/Sylius/Component/Payment/spec/Encryption/PaymentRequestEncrypterSpec.php b/src/Sylius/Component/Payment/spec/Encryption/PaymentRequestEncrypterSpec.php index d33b30917d..24527cd401 100644 --- a/src/Sylius/Component/Payment/spec/Encryption/PaymentRequestEncrypterSpec.php +++ b/src/Sylius/Component/Payment/spec/Encryption/PaymentRequestEncrypterSpec.php @@ -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(); diff --git a/tests/Functional/Encryption/GatewayConfigEncryptionTest.php b/tests/Functional/Encryption/GatewayConfigEncryptionTest.php index 20ed97c706..9dc6c6f1d2 100644 --- a/tests/Functional/Encryption/GatewayConfigEncryptionTest.php +++ b/tests/Functional/Encryption/GatewayConfigEncryptionTest.php @@ -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);