From db7819446195d6e242bc86d86e61047bb56dfa38 Mon Sep 17 00:00:00 2001 From: Paulo Rodrigues Pinto Date: Sat, 7 Jan 2017 19:05:28 +0000 Subject: [PATCH 01/15] Fix tests (#199) --- .travis.yml | 10 +++++-- Tests/Functional/BaseTestCase.php | 2 +- .../TestBundle/Controller/OrderController.php | 1 - .../config/{default.yml => config.yml} | 3 +- Tests/Functional/config/database.php | 8 ++--- Tests/Functional/config/doctrine.yml | 2 +- Tests/Functional/config/framework.php | 29 +++++++++++++++++++ Tests/Functional/config/framework.yml | 12 -------- Tests/Functional/config/twig.yml | 7 ----- composer.json | 4 ++- 10 files changed, 46 insertions(+), 32 deletions(-) rename Tests/Functional/config/{default.yml => config.yml} (84%) create mode 100644 Tests/Functional/config/framework.php delete mode 100644 Tests/Functional/config/framework.yml delete mode 100644 Tests/Functional/config/twig.yml diff --git a/.travis.yml b/.travis.yml index 814b7bc1..4f834bc9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,10 +14,9 @@ matrix: - php: 5.3 env: SYMFONY_VERSION=2.8.* # Symfony 3 doesn't support PHP 5.3 - php: 5.6 - env: SYMFONY_VERSION=3.1.* - # HHVM + env: SYMFONY_VERSION=3.2.* - php: hhvm - env: SYMFONY_VERSION=3.1.* + env: SYMFONY_VERSION=3.2.* # current PHP with all relevant Symfony versions - php: 7.0 env: SYMFONY_VERSION=2.3.* @@ -25,7 +24,12 @@ matrix: env: SYMFONY_VERSION=2.8.* - php: 7.0 env: SYMFONY_VERSION=3.1.* + - php: 7.0 + env: SYMFONY_VERSION=3.2.* + - php: 7.1 + env: SYMFONY_VERSION=3.2.* - php: 7.0 env: SYMFONY_VERSION=dev-master allow_failures: - env: SYMFONY_VERSION=dev-master + - php: 7.1 diff --git a/Tests/Functional/BaseTestCase.php b/Tests/Functional/BaseTestCase.php index ab5fca4b..d27d2476 100644 --- a/Tests/Functional/BaseTestCase.php +++ b/Tests/Functional/BaseTestCase.php @@ -10,7 +10,7 @@ class BaseTestCase extends WebTestCase protected static function createKernel(array $options = array()) { return self::$kernel = new AppKernel( - isset($options['config']) ? $options['config'] : 'default.yml' + isset($options['config']) ? $options['config'] : 'config.yml' ); } diff --git a/Tests/Functional/TestBundle/Controller/OrderController.php b/Tests/Functional/TestBundle/Controller/OrderController.php index 95de50ee..a4c5adcd 100755 --- a/Tests/Functional/TestBundle/Controller/OrderController.php +++ b/Tests/Functional/TestBundle/Controller/OrderController.php @@ -32,7 +32,6 @@ public function paymentDetailsAction(Order $order) $form = $this->get('form.factory')->create($formType, null, array( 'currency' => 'EUR', 'amount' => $order->getAmount(), - 'csrf_protection' => false, 'predefined_data' => array( 'paypal_express_checkout' => array( 'foo' => 'bar', diff --git a/Tests/Functional/config/default.yml b/Tests/Functional/config/config.yml similarity index 84% rename from Tests/Functional/config/default.yml rename to Tests/Functional/config/config.yml index de21a814..a317b7d0 100644 --- a/Tests/Functional/config/default.yml +++ b/Tests/Functional/config/config.yml @@ -1,7 +1,6 @@ imports: - - { resource: framework.yml } - { resource: doctrine.yml } - - { resource: twig.yml } + - { resource: framework.php } jms_payment_core: secret: test diff --git a/Tests/Functional/config/database.php b/Tests/Functional/config/database.php index 0713fcb1..568a7c61 100755 --- a/Tests/Functional/config/database.php +++ b/Tests/Functional/config/database.php @@ -1,8 +1,8 @@ loadFromExtension('doctrine', array( - 'dbal' => array( - 'driver' => 'pdo_sqlite', - 'path' => tempnam(sys_get_temp_dir(), 'database'), - ), + 'dbal' => array( + 'driver' => 'pdo_sqlite', + 'path' => tempnam(sys_get_temp_dir(), 'database'), + ), )); diff --git a/Tests/Functional/config/doctrine.yml b/Tests/Functional/config/doctrine.yml index a7fc036e..47ee7747 100644 --- a/Tests/Functional/config/doctrine.yml +++ b/Tests/Functional/config/doctrine.yml @@ -9,4 +9,4 @@ doctrine: auto_mapping: true services: - em: "@doctrine.orm.entity_manager" \ No newline at end of file + em: "@doctrine.orm.entity_manager" diff --git a/Tests/Functional/config/framework.php b/Tests/Functional/config/framework.php new file mode 100644 index 00000000..c13330b1 --- /dev/null +++ b/Tests/Functional/config/framework.php @@ -0,0 +1,29 @@ + false); + +if (Kernel::MAJOR_VERSION == 2 && Kernel::MINOR_VERSION < 7) { + // The 'assets' configuration is only available for Symfony >= 2.7 + $assets = array(); +} + +$container->loadFromExtension('framework', array_merge($assets, array( + 'secret' => 'test', + 'test' => true, + 'session' => array( + 'storage_id' => 'session.storage.mock_file', + ), + 'templating' => array( + 'engines' => array('twig', 'php'), + ), + 'router' => array( + 'resource' => '%kernel.root_dir%/config/routing.yml', + ), + 'form' => true, + 'validation' => array( + 'enabled' => true, + 'enable_annotations' => true, + ), +))); diff --git a/Tests/Functional/config/framework.yml b/Tests/Functional/config/framework.yml deleted file mode 100644 index 701edc1b..00000000 --- a/Tests/Functional/config/framework.yml +++ /dev/null @@ -1,12 +0,0 @@ -framework: - secret: test - test: ~ - session: - storage_id: session.storage.mock_file - form: true - csrf_protection: true - validation: - enabled: true - enable_annotations: true - router: - resource: "%kernel.root_dir%/config/routing.yml" diff --git a/Tests/Functional/config/twig.yml b/Tests/Functional/config/twig.yml deleted file mode 100644 index f95d3bc0..00000000 --- a/Tests/Functional/config/twig.yml +++ /dev/null @@ -1,7 +0,0 @@ -framework: - templating: - engines: [twig, php] - -twig: - debug: "%kernel.debug%" - strict_variables: "%kernel.debug%" \ No newline at end of file diff --git a/composer.json b/composer.json index d8884511..bdaa17a5 100644 --- a/composer.json +++ b/composer.json @@ -47,7 +47,9 @@ "symfony/routing": "~2.3|~3.0", "symfony/templating": "~2.3|~3.0", "symfony/twig-bundle": "~2.3|~3.0", - "symfony/twig-bridge": "~2.3|~3.0" + "symfony/twig-bridge": "~2.3|~3.0", + "twig/twig": "~1.0" + }, "autoload": { "psr-0": { "JMS\\Payment\\CoreBundle": "" } From 0b51daa78cfbeb45c08d389c91903058af0089ec Mon Sep 17 00:00:00 2001 From: Paulo Rodrigues Pinto Date: Sun, 15 Jan 2017 16:15:08 +0000 Subject: [PATCH 02/15] Refactor ExtendedDataType (#202) --- CHANGELOG.md | 7 ++++ Entity/ExtendedDataType.php | 66 ++++++++++++++++++++------------- Model/ExtendedDataInterface.php | 3 +- 3 files changed, 50 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index edde1545..5b6d6901 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,13 @@ All notable changes to this project are documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [1.3.0] - (Unreleased) +### Changed +- `JMS\Payment\CoreBundle\Model\ExtendedDataInterface` has changed. If any of your classes implement this interface, you need to update them accordingly: + - Added missing `mayBePersisted` method + - Added missing `$persist` parameter to `set` method +- `JMS\Payment\CoreBundle\EntityExtendedDataType::convertToDatabaseValue` now throws an exception when attempting to convert an object which does not implement `JMS\Payment\CoreBundle\Model\ExtendedDataInterface`. + ## [1.2.0] - 2016-10-03 ### Added - Added support for Symfony 3.0. Note that Symfony 3.0 introduces BC breaks. This means that you'll probably need to do more than simply updating to version `1.2.0` of this bundle for your code to keep working under Symfony 3.0. Please see Symfony's [Upgrade Guide](https://github.com/symfony/symfony/blob/master/UPGRADE-3.0.md) for information on what you need to change. diff --git a/Entity/ExtendedDataType.php b/Entity/ExtendedDataType.php index 6049f441..c2006a97 100644 --- a/Entity/ExtendedDataType.php +++ b/Entity/ExtendedDataType.php @@ -6,6 +6,7 @@ use Doctrine\DBAL\Types\ConversionException; use Doctrine\DBAL\Types\ObjectType; use JMS\Payment\CoreBundle\Cryptography\EncryptionServiceInterface; +use JMS\Payment\CoreBundle\Model\ExtendedDataInterface; /* * Copyright 2010 Johannes M. Schmitt @@ -41,23 +42,35 @@ public static function getEncryptionService() public function convertToDatabaseValue($extendedData, AbstractPlatform $platform) { - if (null === $extendedData) { + if ($extendedData === null) { return null; } - $reflection = new \ReflectionProperty($extendedData, 'data'); - $reflection->setAccessible(true); - $data = $reflection->getValue($extendedData); - $reflection->setAccessible(false); + if (!$extendedData instanceof ExtendedDataInterface) { + throw new \InvalidArgumentException( + '$extendedData must implement JMS\Payment\CoreBundle\Model\ExtendedDataInterface' + ); + } - foreach ($data as $name => $value) { - if (false === $value[2]) { - unset($data[$name]); + $data = array(); + + foreach (array_keys($extendedData->all()) as $name) { + if (!$extendedData->mayBePersisted($name)) { continue; } - if (true === $value[1]) { - $data[$name][0] = self::$encryptionService->encrypt(serialize($value[0])); + + $value = $extendedData->get($name); + $isEncryptionRequired = $extendedData->isEncryptionRequired($name); + + if ($isEncryptionRequired) { + $value = self::$encryptionService->encrypt(serialize($value)); } + + $data[$name] = array( + $value, + $isEncryptionRequired, + $mayBePersisted = true, + ); } return parent::convertToDatabaseValue($data, $platform); @@ -67,25 +80,28 @@ public function convertToPHPValue($value, AbstractPlatform $platform) { $data = parent::convertToPHPValue($value, $platform); - if (null === $data) { + if ($data === null) { return null; - } elseif (is_array($data)) { - foreach ($data as $name => $value) { - if (true === $value[1]) { - $data[$name][0] = unserialize(self::$encryptionService->decrypt($value[0])); - } - } - - $extendedData = new ExtendedData(); - $reflection = new \ReflectionProperty($extendedData, 'data'); - $reflection->setAccessible(true); - $reflection->setValue($extendedData, $data); - $reflection->setAccessible(false); + } - return $extendedData; - } else { + if (!is_array($data)) { throw ConversionException::conversionFailed($value, $this->getName()); } + + $extendedData = new ExtendedData(); + + foreach ($data as $name => $value) { + $isEncryptionRequired = (bool) $value[1]; + $value = $value[0]; + + if ($isEncryptionRequired) { + $value = unserialize(self::$encryptionService->decrypt($value)); + } + + $extendedData->set($name, $value, $isEncryptionRequired); + } + + return $extendedData; } public function getName() diff --git a/Model/ExtendedDataInterface.php b/Model/ExtendedDataInterface.php index 8c8a88c4..88658257 100644 --- a/Model/ExtendedDataInterface.php +++ b/Model/ExtendedDataInterface.php @@ -21,8 +21,9 @@ interface ExtendedDataInterface { public function isEncryptionRequired($name); + public function mayBePersisted($name); public function remove($name); - public function set($name, $value, $encrypt = true); + public function set($name, $value, $encrypt = true, $persist = true); public function get($name); public function has($name); public function all(); From 58e452ac2144cc3c4c8463366d1e8fb048e811bd Mon Sep 17 00:00:00 2001 From: Paulo Rodrigues Pinto Date: Sun, 15 Jan 2017 16:30:37 +0000 Subject: [PATCH 03/15] Deprecate payment.encryption_service in favor of payment.crypto.mcrypt (#203) * Deprecate payment.encryption_service in favor of payment.crypto.mcrypt * Enable travis caching of dependencies --- .travis.yml | 5 ++ .travis/install.php | 2 - CHANGELOG.md | 3 + .../Compiler/LegacyCryptoPass.php | 56 +++++++++++++++++++ .../JMSPaymentCoreExtension.php | 7 +-- JMSPaymentCoreBundle.php | 4 +- Resources/config/payment.xml | 18 ++++-- Tests/Functional/config/framework.php | 2 +- phpunit.xml.dist | 2 +- 9 files changed, 84 insertions(+), 15 deletions(-) create mode 100644 DependencyInjection/Compiler/LegacyCryptoPass.php diff --git a/.travis.yml b/.travis.yml index 4f834bc9..2a806356 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,11 @@ branches: only: - master +cache: + directories: + - vendor + - venv + before_install: ./.travis/before_install.php install: ./.travis/install.php script: ./.travis/script.php diff --git a/.travis/install.php b/.travis/install.php index 985ba6cf..318a9ba2 100755 --- a/.travis/install.php +++ b/.travis/install.php @@ -3,8 +3,6 @@ include_once 'common.php'; -run('composer self-update'); - if (isLatestPhp() && isLatestSymfony()) { // Make sure composer.json references all necessary components by having one // job run a `composer update`. Since `composer update` will install the diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b6d6901..e230b8df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Added missing `$persist` parameter to `set` method - `JMS\Payment\CoreBundle\EntityExtendedDataType::convertToDatabaseValue` now throws an exception when attempting to convert an object which does not implement `JMS\Payment\CoreBundle\Model\ExtendedDataInterface`. +### Deprecated +- The service `payment.encryption_service` has been deprecated and is now an alias to `payment.crypto.mcrypt`. Parameters specified for `payment.encryption_service` are automatically set for `payment.crypto.mcrypt` so no changes are required in service configuration until `payment.encryption_service` is removed in 2.0. + ## [1.2.0] - 2016-10-03 ### Added - Added support for Symfony 3.0. Note that Symfony 3.0 introduces BC breaks. This means that you'll probably need to do more than simply updating to version `1.2.0` of this bundle for your code to keep working under Symfony 3.0. Please see Symfony's [Upgrade Guide](https://github.com/symfony/symfony/blob/master/UPGRADE-3.0.md) for information on what you need to change. diff --git a/DependencyInjection/Compiler/LegacyCryptoPass.php b/DependencyInjection/Compiler/LegacyCryptoPass.php new file mode 100644 index 00000000..51414d98 --- /dev/null +++ b/DependencyInjection/Compiler/LegacyCryptoPass.php @@ -0,0 +1,56 @@ +has('payment.encryption_service')) { + return; + } + + if (!$container->has('payment.crypto.mcrypt')) { + return; + } + + $parameters = array( + 'class' => 'JMS\Payment\CoreBundle\Cryptography\MCryptEncryptionService', + 'secret' => '', + 'cipher' => 'rijndael-256', + 'mode' => 'ctr', + ); + + foreach ($parameters as $parameter => $defaultValue) { + if (!$container->hasParameter('payment.encryption_service.'.$parameter)) { + continue; + } + + if (!$container->hasParameter('payment.crypto.mcrypt.'.$parameter)) { + continue; + } + + $legacyValue = $container->getParameter('payment.encryption_service.'.$parameter); + $modernValue = $container->getParameter('payment.crypto.mcrypt.'.$parameter); + + // Parameters set for payment.crypto.mcrypt take precedence over + // ones set for payment.encryption_service + if ($modernValue !== $defaultValue) { + $container->setParameter('payment.crypto.mcrypt.'.$parameter, $modernValue); + } elseif ($legacyValue !== $defaultValue) { + $container->setParameter('payment.crypto.mcrypt.'.$parameter, $legacyValue); + @trigger_error('payment.encryption_service.'.$parameter.' has been deprecated in favor of payment.crypto.mcrypt.'.$parameter.' and will be removed in 2.0', E_USER_NOTICE); + } + } + } +} diff --git a/DependencyInjection/JMSPaymentCoreExtension.php b/DependencyInjection/JMSPaymentCoreExtension.php index 17990f29..01cf15c9 100644 --- a/DependencyInjection/JMSPaymentCoreExtension.php +++ b/DependencyInjection/JMSPaymentCoreExtension.php @@ -9,7 +9,6 @@ use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; use Symfony\Component\HttpKernel\DependencyInjection\Extension; -use Symfony\Component\HttpKernel\Kernel; /* * Copyright 2010 Johannes M. Schmitt @@ -50,11 +49,7 @@ public function load(array $configs, ContainerBuilder $container) $config = $processor->process($configuration->getConfigTree(), $configs); if (isset($config['secret'])) { - $container->setParameter('payment.encryption_service.secret', $config['secret']); - } - - if (version_compare(Kernel::VERSION, '2.1.0-DEV', '<')) { - $container->removeDefinition('payment.form.choose_payment_method_type'); + $container->setParameter('payment.crypto.mcrypt.secret', $config['secret']); } } } diff --git a/JMSPaymentCoreBundle.php b/JMSPaymentCoreBundle.php index a077fb5f..dd7aa057 100644 --- a/JMSPaymentCoreBundle.php +++ b/JMSPaymentCoreBundle.php @@ -4,6 +4,7 @@ use JMS\Payment\CoreBundle\DependencyInjection\Compiler\AddPaymentMethodFormTypesPass; use JMS\Payment\CoreBundle\DependencyInjection\Compiler\AddPaymentPluginsPass; +use JMS\Payment\CoreBundle\DependencyInjection\Compiler\LegacyCryptoPass; use JMS\Payment\CoreBundle\Entity\ExtendedDataType; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; @@ -28,7 +29,7 @@ class JMSPaymentCoreBundle extends Bundle { public function boot() { - ExtendedDataType::setEncryptionService($this->container->get('payment.encryption_service')); + ExtendedDataType::setEncryptionService($this->container->get('payment.crypto.mcrypt')); } public function build(ContainerBuilder $builder) @@ -37,5 +38,6 @@ public function build(ContainerBuilder $builder) $builder->addCompilerPass(new AddPaymentPluginsPass()); $builder->addCompilerPass(new AddPaymentMethodFormTypesPass()); + $builder->addCompilerPass(new LegacyCryptoPass()); } } diff --git a/Resources/config/payment.xml b/Resources/config/payment.xml index 4085213a..b4a101f3 100644 --- a/Resources/config/payment.xml +++ b/Resources/config/payment.xml @@ -15,10 +15,17 @@ JMS\Payment\CoreBundle\Form\ChoosePaymentMethodType JMS\Payment\CoreBundle\Form\Transformer\ChoosePaymentMethodTransformer + JMS\Payment\CoreBundle\Cryptography\MCryptEncryptionService + + rijndael-256 + ctr + + JMS\Payment\CoreBundle\Cryptography\MCryptEncryptionService rijndael-256 ctr + @@ -38,10 +45,13 @@ - - %payment.encryption_service.secret% - %payment.encryption_service.cipher% - %payment.encryption_service.mode% + + + + + %payment.crypto.mcrypt.secret% + %payment.crypto.mcrypt.cipher% + %payment.crypto.mcrypt.mode% diff --git a/Tests/Functional/config/framework.php b/Tests/Functional/config/framework.php index c13330b1..536a1f68 100644 --- a/Tests/Functional/config/framework.php +++ b/Tests/Functional/config/framework.php @@ -4,7 +4,7 @@ $assets = array('assets' => false); -if (Kernel::MAJOR_VERSION == 2 && Kernel::MINOR_VERSION < 7) { +if (version_compare(Kernel::VERSION, '2.7', '<')) { // The 'assets' configuration is only available for Symfony >= 2.7 $assets = array(); } diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 03f2f128..35941ea0 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -12,7 +12,7 @@ bootstrap="Tests/bootstrap.php" > - + ./Tests/ From 78c38cf6fe69bfdffd01af23d6dcba5e208c78db Mon Sep 17 00:00:00 2001 From: Paulo Rodrigues Pinto Date: Sun, 15 Jan 2017 19:51:14 +0000 Subject: [PATCH 04/15] Make encryption optional (#204) Encryption is now optional and disabled by default, unless the `secret` configuration option is set. This ensures existing installations keep working as expected. The reason for disabling encryption by default is in order for us to be able to use utility commands to setup encryption, for example, generating keys. This would not be possible if encryption would be enabled by default, in which case configuration validation would fail when trying to run the command. --- CHANGELOG.md | 2 + .../Compiler/LegacyCryptoPass.php | 2 +- DependencyInjection/Configuration.php | 57 +++++++-- .../JMSPaymentCoreExtension.php | 20 ++- Entity/ExtendedDataType.php | 4 +- JMSPaymentCoreBundle.php | 4 +- Resources/doc/setup.rst | 8 +- .../Configuration/ConfigurationTest.php | 115 ++++++++++++++++++ .../PaymentWorkflowNoEncryptionTest.php | 11 ++ Tests/Functional/SchemaTest.php | 9 ++ Tests/Functional/config/config.yml | 10 +- .../config/config_no_encryption.yml | 2 + Tests/Functional/config/default.yml | 10 ++ composer.json | 3 +- 14 files changed, 223 insertions(+), 34 deletions(-) create mode 100644 Tests/DependencyInjection/Configuration/ConfigurationTest.php create mode 100755 Tests/Functional/PaymentWorkflowNoEncryptionTest.php create mode 100644 Tests/Functional/config/config_no_encryption.yml create mode 100644 Tests/Functional/config/default.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index e230b8df..25d6a17c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,9 +9,11 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Added missing `mayBePersisted` method - Added missing `$persist` parameter to `set` method - `JMS\Payment\CoreBundle\EntityExtendedDataType::convertToDatabaseValue` now throws an exception when attempting to convert an object which does not implement `JMS\Payment\CoreBundle\Model\ExtendedDataInterface`. +- Encryption is now optional and disabled by default, unless the `secret` configuration option is set. This ensures existing installations keep working as expected. ### Deprecated - The service `payment.encryption_service` has been deprecated and is now an alias to `payment.crypto.mcrypt`. Parameters specified for `payment.encryption_service` are automatically set for `payment.crypto.mcrypt` so no changes are required in service configuration until `payment.encryption_service` is removed in 2.0. +- The `secret` configuration option has been deprecated in favor of `encryption.secret` and will be removed in 2.0. ## [1.2.0] - 2016-10-03 ### Added diff --git a/DependencyInjection/Compiler/LegacyCryptoPass.php b/DependencyInjection/Compiler/LegacyCryptoPass.php index 51414d98..e60b17dc 100644 --- a/DependencyInjection/Compiler/LegacyCryptoPass.php +++ b/DependencyInjection/Compiler/LegacyCryptoPass.php @@ -49,7 +49,7 @@ public function process(ContainerBuilder $container) $container->setParameter('payment.crypto.mcrypt.'.$parameter, $modernValue); } elseif ($legacyValue !== $defaultValue) { $container->setParameter('payment.crypto.mcrypt.'.$parameter, $legacyValue); - @trigger_error('payment.encryption_service.'.$parameter.' has been deprecated in favor of payment.crypto.mcrypt.'.$parameter.' and will be removed in 2.0', E_USER_NOTICE); + @trigger_error('payment.encryption_service.'.$parameter.' has been deprecated in favor of payment.crypto.mcrypt.'.$parameter.' and will be removed in 2.0', E_USER_DEPRECATED); } } } diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index aadeb886..e115fb61 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -3,6 +3,7 @@ namespace JMS\Payment\CoreBundle\DependencyInjection; use Symfony\Component\Config\Definition\Builder\TreeBuilder; +use Symfony\Component\Config\Definition\ConfigurationInterface; /* * Copyright 2010 Johannes M. Schmitt @@ -20,18 +21,58 @@ * limitations under the License. */ -class Configuration +class Configuration implements ConfigurationInterface { - public function getConfigTree() + private $alias; + + public function __construct($alias) { - $tb = new TreeBuilder(); + $this->alias = $alias; + } - return $tb - ->root('jms_payment_core', 'array') - ->children() - ->scalarNode('secret')->isRequired()->cannotBeEmpty()->end() + public function getConfigTreeBuilder() + { + $builder = new TreeBuilder(); + + $builder->root($this->alias, 'array') + ->children() + ->arrayNode('encryption') + ->canBeEnabled() + ->addDefaultsIfNotSet() + ->children() + ->scalarNode('secret') + ->cannotBeEmpty() + ->end() + ->end() + ->validate() + ->ifTrue(function ($config) { + return $config['enabled'] && empty($config['secret']); + }) + ->thenInvalid('An encryption secret is required') + ->end() + ->end() + ->scalarNode('secret') + ->cannotBeEmpty() + ->info("The 'secret' configuration option has been deprecated in favor of 'encryption.secret' and will be removed in 2.0") ->end() ->end() - ->buildTree(); + ->beforeNormalization() + ->ifTrue(function ($config) { + return !empty($config['secret']); + }) + ->then(function ($config) { + @trigger_error("The 'secret' configuration option has been deprecated in favor of 'encryption.secret' and will be removed in 2.0", E_USER_DEPRECATED); + + $config['encryption'] = array( + 'enabled' => true, + 'secret' => $config['secret'], + ); + + return $config; + }) + ->end() + ; + + return $builder; } } diff --git a/DependencyInjection/JMSPaymentCoreExtension.php b/DependencyInjection/JMSPaymentCoreExtension.php index 01cf15c9..280ef0bb 100644 --- a/DependencyInjection/JMSPaymentCoreExtension.php +++ b/DependencyInjection/JMSPaymentCoreExtension.php @@ -3,7 +3,6 @@ namespace JMS\Payment\CoreBundle\DependencyInjection; use JMS\Payment\CoreBundle\Entity\ExtendedDataType; -use Symfony\Component\Config\Definition\Processor; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface; @@ -44,12 +43,21 @@ public function load(array $configs, ContainerBuilder $container) $xmlLoader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $xmlLoader->load('payment.xml'); - $configuration = new Configuration(); - $processor = new Processor(); - $config = $processor->process($configuration->getConfigTree(), $configs); + $config = $this->processConfiguration( + $this->getConfiguration($configs, $container), + $configs + ); - if (isset($config['secret'])) { - $container->setParameter('payment.crypto.mcrypt.secret', $config['secret']); + if ($config['encryption']['enabled']) { + $container->setParameter('payment.crypto.mcrypt.secret', $config['encryption']['secret']); + } else { + $container->removeAlias('payment.encryption_service'); + $container->removeDefinition('payment.crypto.mcrypt'); } } + + public function getConfiguration(array $config, ContainerBuilder $container) + { + return new Configuration($this->getAlias()); + } } diff --git a/Entity/ExtendedDataType.php b/Entity/ExtendedDataType.php index c2006a97..e058ab9e 100644 --- a/Entity/ExtendedDataType.php +++ b/Entity/ExtendedDataType.php @@ -62,7 +62,7 @@ public function convertToDatabaseValue($extendedData, AbstractPlatform $platform $value = $extendedData->get($name); $isEncryptionRequired = $extendedData->isEncryptionRequired($name); - if ($isEncryptionRequired) { + if ($isEncryptionRequired && self::$encryptionService) { $value = self::$encryptionService->encrypt(serialize($value)); } @@ -94,7 +94,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) $isEncryptionRequired = (bool) $value[1]; $value = $value[0]; - if ($isEncryptionRequired) { + if ($isEncryptionRequired && self::$encryptionService) { $value = unserialize(self::$encryptionService->decrypt($value)); } diff --git a/JMSPaymentCoreBundle.php b/JMSPaymentCoreBundle.php index dd7aa057..33300284 100644 --- a/JMSPaymentCoreBundle.php +++ b/JMSPaymentCoreBundle.php @@ -29,7 +29,9 @@ class JMSPaymentCoreBundle extends Bundle { public function boot() { - ExtendedDataType::setEncryptionService($this->container->get('payment.crypto.mcrypt')); + if ($this->container->has('payment.crypto.mcrypt')) { + ExtendedDataType::setEncryptionService($this->container->get('payment.crypto.mcrypt')); + } } public function build(ContainerBuilder $builder) diff --git a/Resources/doc/setup.rst b/Resources/doc/setup.rst index 037ec03d..5ac499fb 100644 --- a/Resources/doc/setup.rst +++ b/Resources/doc/setup.rst @@ -43,12 +43,8 @@ And then use it in your configuration: # app/config/config.yml jms_payment_core: - secret: yoursecret - - .. code-block :: xml - - - + encryption: + secret: yoursecret .. note :: diff --git a/Tests/DependencyInjection/Configuration/ConfigurationTest.php b/Tests/DependencyInjection/Configuration/ConfigurationTest.php new file mode 100644 index 00000000..ebe4ad3a --- /dev/null +++ b/Tests/DependencyInjection/Configuration/ConfigurationTest.php @@ -0,0 +1,115 @@ +assertConfigurationIsValid(array()); + $this->assertConfigurationIsInvalid(array('secret' => '')); + + $this->assertConfigurationEquals( + array(), + array('encryption' => array('enabled' => false)) + ); + } + + public function testSecret() + { + $this->assertConfigurationIsValid(array('secret' => 'foo')); + + $this->assertConfigurationEquals( + array('secret' => 'foo'), + array( + 'secret' => 'foo', + 'encryption' => array( + 'enabled' => true, + 'secret' => 'foo', + ), + ) + ); + } + + public function testEncryptionDisabled() + { + $this->assertConfigurationIsValid(array()); + $this->assertConfigurationIsValid(array('encryption' => false)); + + $this->assertConfigurationEquals( + array(), + array('encryption' => array( + 'enabled' => false, + )) + ); + + $this->assertConfigurationEquals( + array('encryption' => false), + array('encryption' => array( + 'enabled' => false, + )) + ); + + $this->assertConfigurationEquals( + array('encryption' => array( + 'enabled' => false, + )), + array('encryption' => array( + 'enabled' => false, + )) + ); + } + + public function testEncryptionEnabled() + { + $this->assertConfigurationIsInvalid(array('encryption' => true)); + + $this->assertConfigurationIsInvalid(array('encryption' => array( + 'enabled' => true, + ))); + + $this->assertConfigurationIsValid(array('encryption' => array( + 'enabled' => true, + 'secret' => 'foo', + ))); + + $this->assertConfigurationEquals( + array('encryption' => array( + 'enabled' => true, + 'secret' => 'foo', + )), + array('encryption' => array( + 'enabled' => true, + 'secret' => 'foo', + )) + ); + } + + protected function getConfiguration() + { + return new Configuration('jms_payment_core'); + } + + protected function assertConfigurationIsInvalid(array $config, $expected = null, $useRegExp = false) + { + parent::assertConfigurationIsInvalid(array($config), $expected, $useRegExp); + } + + protected function assertConfigurationIsValid(array $config, $breadcrumbPath = null) + { + parent::assertConfigurationIsValid(array($config), $breadcrumbPath); + } + + protected function assertConfigurationEquals($config, $expected, $breadcrumbPath = null) + { + $this->assertProcessedConfigurationEquals($config, $expected, $breadcrumbPath); + } + + protected function assertProcessedConfigurationEquals(array $config, array $expected, $breadcrumbPath = null) + { + parent::assertProcessedConfigurationEquals(array($config), $expected, $breadcrumbPath); + } +} diff --git a/Tests/Functional/PaymentWorkflowNoEncryptionTest.php b/Tests/Functional/PaymentWorkflowNoEncryptionTest.php new file mode 100755 index 00000000..379e850b --- /dev/null +++ b/Tests/Functional/PaymentWorkflowNoEncryptionTest.php @@ -0,0 +1,11 @@ + 'config_no_encryption.yml')); + } +} diff --git a/Tests/Functional/SchemaTest.php b/Tests/Functional/SchemaTest.php index bc23c613..6d6d08d4 100644 --- a/Tests/Functional/SchemaTest.php +++ b/Tests/Functional/SchemaTest.php @@ -7,6 +7,9 @@ class SchemaTest extends BaseTestCase { + /** + * @runInSeparateProcess + */ public function testLegacySchemaIsValid() { if (!Legacy::supportsSecureRandom()) { @@ -18,6 +21,9 @@ public function testLegacySchemaIsValid() $this->doTestSchemaIsValid(); } + /** + * @runInSeparateProcess + */ public function testSchemaIsValid() { if (Legacy::supportsSecureRandom()) { @@ -29,6 +35,9 @@ public function testSchemaIsValid() $this->doTestSchemaIsValid(); } + /** + * @runInSeparateProcess + */ private function doTestSchemaIsValid() { $this->createClient(); diff --git a/Tests/Functional/config/config.yml b/Tests/Functional/config/config.yml index a317b7d0..9e504f1f 100644 --- a/Tests/Functional/config/config.yml +++ b/Tests/Functional/config/config.yml @@ -1,13 +1,5 @@ imports: - - { resource: doctrine.yml } - - { resource: framework.php } + - { resource: default.yml } jms_payment_core: secret: test - -jms_payment_paypal: - username: schmit_1283340315_biz_api1.gmail.com - password: 1283340321 - signature: A93vj6VJ.ZIRNjbI6GFgi4N2Km.5ATLs-EinlyWk2htEGX0xc3L8YIBo - return_url: http://paypal.test/payment - cancel_url: http://paypal.test/payment diff --git a/Tests/Functional/config/config_no_encryption.yml b/Tests/Functional/config/config_no_encryption.yml new file mode 100644 index 00000000..d1f99aee --- /dev/null +++ b/Tests/Functional/config/config_no_encryption.yml @@ -0,0 +1,2 @@ +imports: + - { resource: default.yml } diff --git a/Tests/Functional/config/default.yml b/Tests/Functional/config/default.yml new file mode 100644 index 00000000..23244d55 --- /dev/null +++ b/Tests/Functional/config/default.yml @@ -0,0 +1,10 @@ +imports: + - { resource: doctrine.yml } + - { resource: framework.php } + +jms_payment_paypal: + username: schmit_1283340315_biz_api1.gmail.com + password: 1283340321 + signature: A93vj6VJ.ZIRNjbI6GFgi4N2Km.5ATLs-EinlyWk2htEGX0xc3L8YIBo + return_url: http://paypal.test/payment + cancel_url: http://paypal.test/payment diff --git a/composer.json b/composer.json index bdaa17a5..7e0f43a1 100644 --- a/composer.json +++ b/composer.json @@ -48,7 +48,8 @@ "symfony/templating": "~2.3|~3.0", "symfony/twig-bundle": "~2.3|~3.0", "symfony/twig-bridge": "~2.3|~3.0", - "twig/twig": "~1.0" + "twig/twig": "~1.0", + "matthiasnoback/symfony-config-test": "^2.1" }, "autoload": { From 4ab38b5d063ecc64e712fe2fe1bdb25b8ff58c33 Mon Sep 17 00:00:00 2001 From: Paulo Rodrigues Pinto Date: Mon, 16 Jan 2017 02:14:58 +0000 Subject: [PATCH 05/15] Allow custom encryption providers (#205) --- CHANGELOG.md | 5 +- .../AddPaymentMethodFormTypesPass.php | 12 ++--- .../Compiler/AddPaymentPluginsPass.php | 2 +- .../Compiler/ConfigureEncryptionPass.php | 34 +++++++++++++ ...ryptoPass.php => LegacyEncryptionPass.php} | 20 ++++---- DependencyInjection/Configuration.php | 5 +- .../JMSPaymentCoreExtension.php | 12 ++++- JMSPaymentCoreBundle.php | 10 ++-- Resources/config/payment.xml | 23 +++++---- .../Configuration/ConfigurationTest.php | 10 +++- Tests/Functional/AppKernel.php | 2 +- Tests/Functional/BasePaymentWorkflowTest.php | 51 +++++++++++++++++++ Tests/Functional/BaseTestCase.php | 2 +- .../PaymentWorkflowNoEncryptionTest.php | 14 ++++- Tests/Functional/PaymentWorkflowTest.php | 30 ++--------- .../Resources}/config/config.yml | 0 .../config/config_no_encryption.yml | 0 .../Resources}/config/database.php | 0 .../Resources}/config/default.yml | 12 ++++- .../Resources}/config/framework.php | 2 +- .../Resources}/config/routing.yml | 0 Tests/Functional/config/doctrine.yml | 12 ----- 22 files changed, 177 insertions(+), 81 deletions(-) create mode 100644 DependencyInjection/Compiler/ConfigureEncryptionPass.php rename DependencyInjection/Compiler/{LegacyCryptoPass.php => LegacyEncryptionPass.php} (63%) create mode 100755 Tests/Functional/BasePaymentWorkflowTest.php rename Tests/Functional/{ => TestBundle/Resources}/config/config.yml (100%) rename Tests/Functional/{ => TestBundle/Resources}/config/config_no_encryption.yml (100%) rename Tests/Functional/{ => TestBundle/Resources}/config/database.php (100%) rename Tests/Functional/{ => TestBundle/Resources}/config/default.yml (55%) rename Tests/Functional/{ => TestBundle/Resources}/config/framework.php (88%) rename Tests/Functional/{ => TestBundle/Resources}/config/routing.yml (100%) delete mode 100644 Tests/Functional/config/doctrine.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 25d6a17c..f1023702 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,9 +12,12 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Encryption is now optional and disabled by default, unless the `secret` configuration option is set. This ensures existing installations keep working as expected. ### Deprecated -- The service `payment.encryption_service` has been deprecated and is now an alias to `payment.crypto.mcrypt`. Parameters specified for `payment.encryption_service` are automatically set for `payment.crypto.mcrypt` so no changes are required in service configuration until `payment.encryption_service` is removed in 2.0. +- The service `payment.encryption_service` has been deprecated and is now an alias to `payment.encryption.mcrypt`. Parameters specified for `payment.encryption_service` are automatically set for `payment.encryption.mcrypt` so no changes are required in service configuration until `payment.encryption_service` is removed in 2.0. - The `secret` configuration option has been deprecated in favor of `encryption.secret` and will be removed in 2.0. +### Added +- Added support for custom encryption providers. + ## [1.2.0] - 2016-10-03 ### Added - Added support for Symfony 3.0. Note that Symfony 3.0 introduces BC breaks. This means that you'll probably need to do more than simply updating to version `1.2.0` of this bundle for your code to keep working under Symfony 3.0. Please see Symfony's [Upgrade Guide](https://github.com/symfony/symfony/blob/master/UPGRADE-3.0.md) for information on what you need to change. diff --git a/DependencyInjection/Compiler/AddPaymentMethodFormTypesPass.php b/DependencyInjection/Compiler/AddPaymentMethodFormTypesPass.php index 35c58e66..dbf3f285 100755 --- a/DependencyInjection/Compiler/AddPaymentMethodFormTypesPass.php +++ b/DependencyInjection/Compiler/AddPaymentMethodFormTypesPass.php @@ -20,21 +20,21 @@ public function process(ContainerBuilder $container) } $paymentMethodFormTypes = array(); - foreach ($container->findTaggedServiceIds('payment.method_form_type') as $id => $attributes) { + foreach ($container->findTaggedServiceIds('payment.method_form_type') as $id => $attrs) { $definition = $container->getDefinition($id); // check that this definition is also registered as a form type - $attributes = $definition->getTag('form.type'); - if (!$attributes) { + $attrs = $definition->getTag('form.type'); + if (!$attrs) { throw new \RuntimeException(sprintf('The service "%s" is marked as payment method form type (tagged with "payment.method_form_type"), but is not registered as a form type with the Form Component. Please also add a "form.type" tag.', $id)); } - if (!isset($attributes[0]['alias'])) { + if (!isset($attrs[0]['alias'])) { throw new \RuntimeException(sprintf('Please define an alias attribute for tag "form.type" of service "%s".', $id)); } - $paymentMethodFormTypes[$attributes[0]['alias']] = Legacy::supportsFormTypeName() - ? $attributes[0]['alias'] + $paymentMethodFormTypes[$attrs[0]['alias']] = Legacy::supportsFormTypeName() + ? $attrs[0]['alias'] : $definition->getClass() ; } diff --git a/DependencyInjection/Compiler/AddPaymentPluginsPass.php b/DependencyInjection/Compiler/AddPaymentPluginsPass.php index 19c574a3..b08db293 100644 --- a/DependencyInjection/Compiler/AddPaymentPluginsPass.php +++ b/DependencyInjection/Compiler/AddPaymentPluginsPass.php @@ -31,7 +31,7 @@ public function process(ContainerBuilder $container) } $def = $container->findDefinition('payment.plugin_controller'); - foreach ($container->findTaggedServiceIds('payment.plugin') as $id => $attr) { + foreach ($container->findTaggedServiceIds('payment.plugin') as $id => $attrs) { $def->addMethodCall('addPlugin', array(new Reference($id))); } } diff --git a/DependencyInjection/Compiler/ConfigureEncryptionPass.php b/DependencyInjection/Compiler/ConfigureEncryptionPass.php new file mode 100644 index 00000000..6cc6c912 --- /dev/null +++ b/DependencyInjection/Compiler/ConfigureEncryptionPass.php @@ -0,0 +1,34 @@ +getParameter('payment.encryption.enabled')) { + return; + } + + $providers = array(); + + foreach ($container->findTaggedServiceIds('payment.encryption') as $id => $attrs) { + if (!isset($attrs[0]['alias'])) { + throw new \RuntimeException("Please define an alias attribute for tag 'payment.encryption' of service '$id'"); + } + + $providers[$attrs[0]['alias']] = $id; + } + + $configuredProvider = $container->getParameter('payment.encryption'); + + if (!array_key_exists($configuredProvider, $providers)) { + throw new \RuntimeException("The configured encryption provider ($configuredProvider) must match the alias of one of the services tagged with 'payment.encryption'"); + } + + $container->setAlias('payment.encryption', $providers[$configuredProvider]); + } +} diff --git a/DependencyInjection/Compiler/LegacyCryptoPass.php b/DependencyInjection/Compiler/LegacyEncryptionPass.php similarity index 63% rename from DependencyInjection/Compiler/LegacyCryptoPass.php rename to DependencyInjection/Compiler/LegacyEncryptionPass.php index e60b17dc..7a0f748e 100644 --- a/DependencyInjection/Compiler/LegacyCryptoPass.php +++ b/DependencyInjection/Compiler/LegacyEncryptionPass.php @@ -7,12 +7,12 @@ /** * The service `payment.encryption_service` has been deprecated in favor of - * `payment.crypto.mcrypt`. This compiler pass makes sure parameters specified - * for `payment.encryption_service` are instead set for `payment.crypto.mcrypt`. + * `payment.encryption.mcrypt`. This compiler pass makes sure parameters specified + * for `payment.encryption_service` are instead set for `payment.encryption.mcrypt`. * * @deprecated 1.3 Will be removed in 2.0 */ -class LegacyCryptoPass implements CompilerPassInterface +class LegacyEncryptionPass implements CompilerPassInterface { public function process(ContainerBuilder $container) { @@ -20,7 +20,7 @@ public function process(ContainerBuilder $container) return; } - if (!$container->has('payment.crypto.mcrypt')) { + if (!$container->has('payment.encryption.mcrypt')) { return; } @@ -36,20 +36,20 @@ public function process(ContainerBuilder $container) continue; } - if (!$container->hasParameter('payment.crypto.mcrypt.'.$parameter)) { + if (!$container->hasParameter('payment.encryption.mcrypt.'.$parameter)) { continue; } $legacyValue = $container->getParameter('payment.encryption_service.'.$parameter); - $modernValue = $container->getParameter('payment.crypto.mcrypt.'.$parameter); + $modernValue = $container->getParameter('payment.encryption.mcrypt.'.$parameter); - // Parameters set for payment.crypto.mcrypt take precedence over + // Parameters set for payment.encryption.mcrypt take precedence over // ones set for payment.encryption_service if ($modernValue !== $defaultValue) { - $container->setParameter('payment.crypto.mcrypt.'.$parameter, $modernValue); + $container->setParameter('payment.encryption.mcrypt.'.$parameter, $modernValue); } elseif ($legacyValue !== $defaultValue) { - $container->setParameter('payment.crypto.mcrypt.'.$parameter, $legacyValue); - @trigger_error('payment.encryption_service.'.$parameter.' has been deprecated in favor of payment.crypto.mcrypt.'.$parameter.' and will be removed in 2.0', E_USER_DEPRECATED); + $container->setParameter('payment.encryption.mcrypt.'.$parameter, $legacyValue); + @trigger_error('payment.encryption_service.'.$parameter.' has been deprecated in favor of payment.encryption.mcrypt.'.$parameter.' and will be removed in 2.0', E_USER_DEPRECATED); } } } diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index e115fb61..06892e7c 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -40,9 +40,8 @@ public function getConfigTreeBuilder() ->canBeEnabled() ->addDefaultsIfNotSet() ->children() - ->scalarNode('secret') - ->cannotBeEmpty() - ->end() + ->scalarNode('provider')->defaultValue('mcrypt')->end() + ->scalarNode('secret')->cannotBeEmpty()->end() ->end() ->validate() ->ifTrue(function ($config) { diff --git a/DependencyInjection/JMSPaymentCoreExtension.php b/DependencyInjection/JMSPaymentCoreExtension.php index 280ef0bb..90ad12e8 100644 --- a/DependencyInjection/JMSPaymentCoreExtension.php +++ b/DependencyInjection/JMSPaymentCoreExtension.php @@ -48,11 +48,19 @@ public function load(array $configs, ContainerBuilder $container) $configs ); + $container->setParameter('payment.encryption.enabled', $config['encryption']['enabled']); + if ($config['encryption']['enabled']) { - $container->setParameter('payment.crypto.mcrypt.secret', $config['encryption']['secret']); + $container->setParameter('payment.encryption', $config['encryption']['provider']); + $container->setParameter('payment.encryption.secret', $config['encryption']['secret']); + + foreach (array('mcrypt') as $provider) { + $container->setParameter("payment.encryption.$provider.secret", $config['encryption']['secret']); + } } else { $container->removeAlias('payment.encryption_service'); - $container->removeDefinition('payment.crypto.mcrypt'); + $container->removeDefinition('payment.encryption.mcrypt'); + $container->removeDefinition('payment.encryption'); } } diff --git a/JMSPaymentCoreBundle.php b/JMSPaymentCoreBundle.php index 33300284..341643f0 100644 --- a/JMSPaymentCoreBundle.php +++ b/JMSPaymentCoreBundle.php @@ -4,7 +4,8 @@ use JMS\Payment\CoreBundle\DependencyInjection\Compiler\AddPaymentMethodFormTypesPass; use JMS\Payment\CoreBundle\DependencyInjection\Compiler\AddPaymentPluginsPass; -use JMS\Payment\CoreBundle\DependencyInjection\Compiler\LegacyCryptoPass; +use JMS\Payment\CoreBundle\DependencyInjection\Compiler\ConfigureEncryptionPass; +use JMS\Payment\CoreBundle\DependencyInjection\Compiler\LegacyEncryptionPass; use JMS\Payment\CoreBundle\Entity\ExtendedDataType; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; @@ -29,8 +30,8 @@ class JMSPaymentCoreBundle extends Bundle { public function boot() { - if ($this->container->has('payment.crypto.mcrypt')) { - ExtendedDataType::setEncryptionService($this->container->get('payment.crypto.mcrypt')); + if ($this->container->has('payment.encryption')) { + ExtendedDataType::setEncryptionService($this->container->get('payment.encryption')); } } @@ -40,6 +41,7 @@ public function build(ContainerBuilder $builder) $builder->addCompilerPass(new AddPaymentPluginsPass()); $builder->addCompilerPass(new AddPaymentMethodFormTypesPass()); - $builder->addCompilerPass(new LegacyCryptoPass()); + $builder->addCompilerPass(new LegacyEncryptionPass()); + $builder->addCompilerPass(new ConfigureEncryptionPass()); } } diff --git a/Resources/config/payment.xml b/Resources/config/payment.xml index b4a101f3..b6238d5c 100644 --- a/Resources/config/payment.xml +++ b/Resources/config/payment.xml @@ -15,12 +15,12 @@ JMS\Payment\CoreBundle\Form\ChoosePaymentMethodType JMS\Payment\CoreBundle\Form\Transformer\ChoosePaymentMethodTransformer - JMS\Payment\CoreBundle\Cryptography\MCryptEncryptionService - - rijndael-256 - ctr + JMS\Payment\CoreBundle\Cryptography\MCryptEncryptionService + + rijndael-256 + ctr - + JMS\Payment\CoreBundle\Cryptography\MCryptEncryptionService rijndael-256 @@ -45,13 +45,14 @@ - - + + - - %payment.crypto.mcrypt.secret% - %payment.crypto.mcrypt.cipher% - %payment.crypto.mcrypt.mode% + + %payment.encryption.mcrypt.secret% + %payment.encryption.mcrypt.cipher% + %payment.encryption.mcrypt.mode% + diff --git a/Tests/DependencyInjection/Configuration/ConfigurationTest.php b/Tests/DependencyInjection/Configuration/ConfigurationTest.php index ebe4ad3a..9579e4ac 100644 --- a/Tests/DependencyInjection/Configuration/ConfigurationTest.php +++ b/Tests/DependencyInjection/Configuration/ConfigurationTest.php @@ -14,7 +14,10 @@ public function testNoSecret() $this->assertConfigurationEquals( array(), - array('encryption' => array('enabled' => false)) + array('encryption' => array( + 'enabled' => false, + 'provider' => 'mcrypt', + )) ); } @@ -29,6 +32,7 @@ public function testSecret() 'encryption' => array( 'enabled' => true, 'secret' => 'foo', + 'provider' => 'mcrypt', ), ) ); @@ -43,6 +47,7 @@ public function testEncryptionDisabled() array(), array('encryption' => array( 'enabled' => false, + 'provider' => 'mcrypt', )) ); @@ -50,6 +55,7 @@ public function testEncryptionDisabled() array('encryption' => false), array('encryption' => array( 'enabled' => false, + 'provider' => 'mcrypt', )) ); @@ -59,6 +65,7 @@ public function testEncryptionDisabled() )), array('encryption' => array( 'enabled' => false, + 'provider' => 'mcrypt', )) ); } @@ -84,6 +91,7 @@ public function testEncryptionEnabled() array('encryption' => array( 'enabled' => true, 'secret' => 'foo', + 'provider' => 'mcrypt', )) ); } diff --git a/Tests/Functional/AppKernel.php b/Tests/Functional/AppKernel.php index e4a729f6..0ec32fa8 100644 --- a/Tests/Functional/AppKernel.php +++ b/Tests/Functional/AppKernel.php @@ -16,7 +16,7 @@ public function __construct($config) $fs = new Filesystem(); if (!$fs->isAbsolutePath($config)) { - $config = __DIR__.'/config/'.$config; + $config = __DIR__.'/TestBundle/Resources/config/'.$config; } if (!file_exists($config)) { diff --git a/Tests/Functional/BasePaymentWorkflowTest.php b/Tests/Functional/BasePaymentWorkflowTest.php new file mode 100755 index 00000000..6fa5c5d2 --- /dev/null +++ b/Tests/Functional/BasePaymentWorkflowTest.php @@ -0,0 +1,51 @@ +getContainer()->get('em'); + + $stmt = $em->getConnection()->prepare( + 'SELECT extended_data FROM payment_instructions WHERE id = '.$paymentInstruction->getId() + ); + + $stmt->execute(); + $result = $stmt->fetchAll(); + + return unserialize($result[0]['extended_data']); + } + + protected function doTestPaymentDetails() + { + $client = $this->createClient(); + $this->importDatabaseSchema(); + + $em = self::$kernel->getContainer()->get('em'); + $router = self::$kernel->getContainer()->get('router'); + + $order = new Order(123.45); + $em->persist($order); + $em->flush(); + + $crawler = $client->request('GET', $router->generate('payment_details', array('id' => $order->getId()))); + $form = $crawler->selectButton('submit_btn')->form(); + $form['jms_choose_payment_method[method]']->select('paypal_express_checkout'); + $client->submit($form); + + $response = $client->getResponse(); + $this->assertSame(201, $response->getStatusCode(), substr($response, 0, 2000)); + + $em->clear(); + $order = $em->getRepository('TestBundle:Order')->find($order->getId()); + $this->assertTrue(Number::compare(123.45, $order->getPaymentInstruction()->getAmount(), '==')); + $this->assertEquals('bar', $order->getPaymentInstruction()->getExtendedData()->get('foo')); + + return $order; + } +} diff --git a/Tests/Functional/BaseTestCase.php b/Tests/Functional/BaseTestCase.php index d27d2476..cf617960 100644 --- a/Tests/Functional/BaseTestCase.php +++ b/Tests/Functional/BaseTestCase.php @@ -20,7 +20,7 @@ protected function setUp() $fs->remove(sys_get_temp_dir().'/JMSPaymentCoreBundle/'); } - final protected function importDatabaseSchema() + protected function importDatabaseSchema() { $em = self::$kernel->getContainer()->get('doctrine.orm.entity_manager'); diff --git a/Tests/Functional/PaymentWorkflowNoEncryptionTest.php b/Tests/Functional/PaymentWorkflowNoEncryptionTest.php index 379e850b..a12ec5a1 100755 --- a/Tests/Functional/PaymentWorkflowNoEncryptionTest.php +++ b/Tests/Functional/PaymentWorkflowNoEncryptionTest.php @@ -2,10 +2,22 @@ namespace JMS\Payment\CoreBundle\Tests\Functional; -class PaymentWorkflowNoEncryptionTest extends PaymentWorkflowTest +class PaymentWorkflowNoEncryptionTest extends BasePaymentWorkflowTest { protected static function createKernel(array $options = array()) { return parent::createKernel(array('config' => 'config_no_encryption.yml')); } + + /** + * @runInSeparateProcess + */ + public function testPaymentDetails() + { + $order = parent::doTestPaymentDetails(); + + $extendedData = $this->getRawExtendedData($order->getPaymentInstruction()); + $this->assertArrayHasKey('foo', $extendedData); + $this->assertEquals('bar', $extendedData['foo'][0]); + } } diff --git a/Tests/Functional/PaymentWorkflowTest.php b/Tests/Functional/PaymentWorkflowTest.php index 9a0a8f4e..f6fb7829 100755 --- a/Tests/Functional/PaymentWorkflowTest.php +++ b/Tests/Functional/PaymentWorkflowTest.php @@ -2,37 +2,17 @@ namespace JMS\Payment\CoreBundle\Tests\Functional; -use JMS\Payment\CoreBundle\Tests\Functional\TestBundle\Entity\Order; -use JMS\Payment\CoreBundle\Util\Number; - -class PaymentWorkflowTest extends BaseTestCase +class PaymentWorkflowTest extends BasePaymentWorkflowTest { /** * @runInSeparateProcess */ public function testPaymentDetails() { - $client = $this->createClient(); - $this->importDatabaseSchema(); - - $em = self::$kernel->getContainer()->get('em'); - $router = self::$kernel->getContainer()->get('router'); - - $order = new Order(123.45); - $em->persist($order); - $em->flush(); - - $crawler = $client->request('GET', $router->generate('payment_details', array('id' => $order->getId()))); - $form = $crawler->selectButton('submit_btn')->form(); - $form['jms_choose_payment_method[method]']->select('paypal_express_checkout'); - $client->submit($form); - - $response = $client->getResponse(); - $this->assertSame(201, $response->getStatusCode(), substr($response, 0, 2000)); + $order = parent::doTestPaymentDetails(); - $em->clear(); - $order = $em->getRepository('TestBundle:Order')->find($order->getId()); - $this->assertTrue(Number::compare(123.45, $order->getPaymentInstruction()->getAmount(), '==')); - $this->assertEquals('bar', $order->getPaymentInstruction()->getExtendedData()->get('foo')); + $extendedData = $this->getRawExtendedData($order->getPaymentInstruction()); + $this->assertArrayHasKey('foo', $extendedData); + $this->assertNotEquals('bar', $extendedData['foo'][0]); } } diff --git a/Tests/Functional/config/config.yml b/Tests/Functional/TestBundle/Resources/config/config.yml similarity index 100% rename from Tests/Functional/config/config.yml rename to Tests/Functional/TestBundle/Resources/config/config.yml diff --git a/Tests/Functional/config/config_no_encryption.yml b/Tests/Functional/TestBundle/Resources/config/config_no_encryption.yml similarity index 100% rename from Tests/Functional/config/config_no_encryption.yml rename to Tests/Functional/TestBundle/Resources/config/config_no_encryption.yml diff --git a/Tests/Functional/config/database.php b/Tests/Functional/TestBundle/Resources/config/database.php similarity index 100% rename from Tests/Functional/config/database.php rename to Tests/Functional/TestBundle/Resources/config/database.php diff --git a/Tests/Functional/config/default.yml b/Tests/Functional/TestBundle/Resources/config/default.yml similarity index 55% rename from Tests/Functional/config/default.yml rename to Tests/Functional/TestBundle/Resources/config/default.yml index 23244d55..ae8f3662 100644 --- a/Tests/Functional/config/default.yml +++ b/Tests/Functional/TestBundle/Resources/config/default.yml @@ -1,7 +1,17 @@ imports: - - { resource: doctrine.yml } + - { resource: database.php } - { resource: framework.php } +doctrine: + orm: + auto_generate_proxy_classes: "%kernel.debug%" + entity_managers: + default: + auto_mapping: true + +services: + em: "@doctrine.orm.entity_manager" + jms_payment_paypal: username: schmit_1283340315_biz_api1.gmail.com password: 1283340321 diff --git a/Tests/Functional/config/framework.php b/Tests/Functional/TestBundle/Resources/config/framework.php similarity index 88% rename from Tests/Functional/config/framework.php rename to Tests/Functional/TestBundle/Resources/config/framework.php index 536a1f68..6a0af72b 100644 --- a/Tests/Functional/config/framework.php +++ b/Tests/Functional/TestBundle/Resources/config/framework.php @@ -19,7 +19,7 @@ 'engines' => array('twig', 'php'), ), 'router' => array( - 'resource' => '%kernel.root_dir%/config/routing.yml', + 'resource' => '%kernel.root_dir%/TestBundle/Resources/config/routing.yml', ), 'form' => true, 'validation' => array( diff --git a/Tests/Functional/config/routing.yml b/Tests/Functional/TestBundle/Resources/config/routing.yml similarity index 100% rename from Tests/Functional/config/routing.yml rename to Tests/Functional/TestBundle/Resources/config/routing.yml diff --git a/Tests/Functional/config/doctrine.yml b/Tests/Functional/config/doctrine.yml deleted file mode 100644 index 47ee7747..00000000 --- a/Tests/Functional/config/doctrine.yml +++ /dev/null @@ -1,12 +0,0 @@ -imports: - - { resource: database.php } - -doctrine: - orm: - auto_generate_proxy_classes: "%kernel.debug%" - entity_managers: - default: - auto_mapping: true - -services: - em: "@doctrine.orm.entity_manager" From 46129917a192a41e704404722bf6d82d785a2251 Mon Sep 17 00:00:00 2001 From: Paulo Rodrigues Pinto Date: Mon, 16 Jan 2017 02:41:54 +0000 Subject: [PATCH 06/15] Add encryption provider for defuse/php-encryption (#206) --- .travis.yml | 15 +++--- .travis/common.php | 4 +- .travis/install.php | 5 -- CHANGELOG.md | 5 ++ Cryptography/DefusePhpEncryptionService.php | 26 ++++++++++ .../JMSPaymentCoreExtension.php | 3 +- Resources/config/payment.xml | 8 ++++ .../DefusePhpEncryptionServiceTest.php | 48 +++++++++++++++++++ .../MCryptEncryptionServiceTest.php | 4 ++ Tests/Entity/ExtendedDataTypeTest.php | 6 +-- .../Functional/PaymentWorkflowMcryptTest.php | 27 +++++++++++ .../TestBundle/Resources/config/config.yml | 4 +- .../Resources/config/config_mcrypt.yml | 5 ++ .../Resources/config/config_no_encryption.yml | 2 + composer.json | 8 ++-- 15 files changed, 145 insertions(+), 25 deletions(-) create mode 100644 Cryptography/DefusePhpEncryptionService.php create mode 100644 Tests/Cryptography/DefusePhpEncryptionServiceTest.php create mode 100755 Tests/Functional/PaymentWorkflowMcryptTest.php create mode 100644 Tests/Functional/TestBundle/Resources/config/config_mcrypt.yml diff --git a/.travis.yml b/.travis.yml index 2a806356..a89a2e0d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,25 +16,22 @@ script: ./.travis/script.php matrix: include: # old PHP versions with latest Symfony version - - php: 5.3 + - php: 5.4 env: SYMFONY_VERSION=2.8.* # Symfony 3 doesn't support PHP 5.3 - php: 5.6 env: SYMFONY_VERSION=3.2.* + - php: 7.0 + env: SYMFONY_VERSION=3.2.* - php: hhvm env: SYMFONY_VERSION=3.2.* # current PHP with all relevant Symfony versions - - php: 7.0 + - php: 7.1 env: SYMFONY_VERSION=2.3.* - - php: 7.0 + - php: 7.1 env: SYMFONY_VERSION=2.8.* - - php: 7.0 - env: SYMFONY_VERSION=3.1.* - - php: 7.0 - env: SYMFONY_VERSION=3.2.* - php: 7.1 env: SYMFONY_VERSION=3.2.* - - php: 7.0 + - php: 7.1 env: SYMFONY_VERSION=dev-master allow_failures: - env: SYMFONY_VERSION=dev-master - - php: 7.1 diff --git a/.travis/common.php b/.travis/common.php index 4cdbda96..bc236c31 100644 --- a/.travis/common.php +++ b/.travis/common.php @@ -12,12 +12,12 @@ function isHhvm() function isLatestPhp() { - return getPhpVersion() === '7.0'; + return getPhpVersion() === '7.1'; } function isLatestSymfony() { - return getSymfonyVersion() === '3.1.*'; + return getSymfonyVersion() === '3.2.*'; } function getSymfonyVersion() diff --git a/.travis/install.php b/.travis/install.php index 318a9ba2..54bc680c 100755 --- a/.travis/install.php +++ b/.travis/install.php @@ -10,11 +10,6 @@ // latest symfony version. run('composer update --prefer-dist'); } else { - if (getPhpVersion() === '5.3') { - // Prevent Travis throwing an out of memory error - run('echo "memory_limit=-1" >> ~/.phpenv/versions/5.3/etc/conf.d/travis.ini'); - } - run('composer require --prefer-dist symfony/symfony:'.getSymfonyVersion()); } diff --git a/CHANGELOG.md b/CHANGELOG.md index f1023702..66c9330e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,11 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ### Added - Added support for custom encryption providers. +- Added support for data encryption with [defuse/php-encryption](https://github.com/defuse/php-encryption). +- Added ability to configure which crypto provider should be used. Current available options are `mcrypt` (not recommended since it will be removed in PHP 7.2) and `defuse_php_encryption`. + +### Removed +- Removed support for PHP 5.3. If you're still using PHP 5.3, please consider upgrading since it reached End Of Life in August 2014. Otherwise, use `1.2.*`. ## [1.2.0] - 2016-10-03 ### Added diff --git a/Cryptography/DefusePhpEncryptionService.php b/Cryptography/DefusePhpEncryptionService.php new file mode 100644 index 00000000..2ffe7597 --- /dev/null +++ b/Cryptography/DefusePhpEncryptionService.php @@ -0,0 +1,26 @@ +key = Key::loadFromAsciiSafeString($secret); + } + + public function decrypt($encryptedValue) + { + return Crypto::decrypt($encryptedValue, $this->key); + } + + public function encrypt($rawValue) + { + return Crypto::encrypt($rawValue, $this->key); + } +} diff --git a/DependencyInjection/JMSPaymentCoreExtension.php b/DependencyInjection/JMSPaymentCoreExtension.php index 90ad12e8..e5258674 100644 --- a/DependencyInjection/JMSPaymentCoreExtension.php +++ b/DependencyInjection/JMSPaymentCoreExtension.php @@ -54,12 +54,13 @@ public function load(array $configs, ContainerBuilder $container) $container->setParameter('payment.encryption', $config['encryption']['provider']); $container->setParameter('payment.encryption.secret', $config['encryption']['secret']); - foreach (array('mcrypt') as $provider) { + foreach (array('mcrypt', 'defuse_php_encryption') as $provider) { $container->setParameter("payment.encryption.$provider.secret", $config['encryption']['secret']); } } else { $container->removeAlias('payment.encryption_service'); $container->removeDefinition('payment.encryption.mcrypt'); + $container->removeDefinition('payment.encryption.defuse_php_encryption'); $container->removeDefinition('payment.encryption'); } } diff --git a/Resources/config/payment.xml b/Resources/config/payment.xml index b6238d5c..7b01e7cd 100644 --- a/Resources/config/payment.xml +++ b/Resources/config/payment.xml @@ -20,6 +20,9 @@ rijndael-256 ctr + JMS\Payment\CoreBundle\Cryptography\DefusePhpEncryptionService + + JMS\Payment\CoreBundle\Cryptography\MCryptEncryptionService @@ -55,6 +58,11 @@ + + %payment.encryption.defuse_php_encryption.secret% + + + diff --git a/Tests/Cryptography/DefusePhpEncryptionServiceTest.php b/Tests/Cryptography/DefusePhpEncryptionServiceTest.php new file mode 100644 index 00000000..45bfed6b --- /dev/null +++ b/Tests/Cryptography/DefusePhpEncryptionServiceTest.php @@ -0,0 +1,48 @@ +assertNotEquals($data, $service1->encrypt($data)); + $this->assertNotEquals($data, $service2->encrypt($data)); + + $this->assertEquals($data, $service1->decrypt($service1->encrypt($data))); + $this->assertEquals($data, $service2->decrypt($service2->encrypt($data))); + $this->assertEquals($data, $service3->decrypt($service1->encrypt($data))); + } + + /** + * @dataProvider getTestData + * @expectedException \Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException + */ + public function testEncryptDecryptFailure($data) + { + $service1 = new DefusePhpEncryptionService('def00000290a4b250a1b24c41f3076b5e3955e1a51d8535a5dbcf209d17f1eb8d772349cbd12af5dc8f4b05d43ca900489c0fb5aa5c4c5190ccffb5663ae4831e3022fc6'); + $service2 = new DefusePhpEncryptionService('def00000000bdbf82c58d9fbd77d15fa5314bdafebe7586e03b0679ef09f622577afe58485b2a4b3c2e74a16a7375ad348f29e9254a57237691fdf2d71b1d78cd3958497'); + + $this->assertNotEquals($data, $service1->decrypt($service2->encrypt($data))); + } + + public function getTestData() + { + return array( + array('this is some test data, very sensitive stuff'), + array('12345674234'), + array('123'), + array('4565-3346-2124-5653'), + array('HDarfg$§fasHaha&$%§'), + ); + } +} diff --git a/Tests/Cryptography/MCryptEncryptionServiceTest.php b/Tests/Cryptography/MCryptEncryptionServiceTest.php index 432d4c3b..9c9cbe6e 100644 --- a/Tests/Cryptography/MCryptEncryptionServiceTest.php +++ b/Tests/Cryptography/MCryptEncryptionServiceTest.php @@ -8,6 +8,10 @@ class MCryptEncryptionServiceTest extends \PHPUnit_Framework_TestCase { protected function setUp() { + if (version_compare(phpversion(), '7.1', '>=')) { + $this->markTestSkipped('mcrypt is deprecated since PHP 7.1'); + } + if (false !== strpos(PHP_OS, 'WIN')) { $this->markTestSkipped('Windows is not suited for generating random data.'); } diff --git a/Tests/Entity/ExtendedDataTypeTest.php b/Tests/Entity/ExtendedDataTypeTest.php index 41807c2e..a4bf4abd 100644 --- a/Tests/Entity/ExtendedDataTypeTest.php +++ b/Tests/Entity/ExtendedDataTypeTest.php @@ -3,7 +3,7 @@ namespace JMS\Payment\CoreBundle\Tests\Entity; use Doctrine\DBAL\Types\Type; -use JMS\Payment\CoreBundle\Cryptography\MCryptEncryptionService; +use JMS\Payment\CoreBundle\Cryptography\DefusePhpEncryptionService; use JMS\Payment\CoreBundle\Entity\ExtendedData; use JMS\Payment\CoreBundle\Entity\ExtendedDataType; @@ -20,7 +20,7 @@ protected function setUp() public function testStaticSetGetEncryptionService() { - $service = new MCryptEncryptionService('foo'); + $service = new DefusePhpEncryptionService('def00000812bba10524777c97f1155877f0c91a4fac2c9f3d71a39d0df7214eab90d492faa58d2db667c5003c3c2228e3f19ad493ae86c74079a600a1ed51cd65e21f28e'); $this->assertNull(ExtendedDataType::getEncryptionService()); ExtendedDataType::setEncryptionService($service); @@ -37,7 +37,7 @@ public function testGetName() public function testConversion() { - ExtendedDataType::setEncryptionService(new MCryptEncryptionService('foo')); + ExtendedDataType::setEncryptionService(new DefusePhpEncryptionService('def00000812bba10524777c97f1155877f0c91a4fac2c9f3d71a39d0df7214eab90d492faa58d2db667c5003c3c2228e3f19ad493ae86c74079a600a1ed51cd65e21f28e')); $extendedData = new ExtendedData(); $extendedData->set('foo', 'foo', false); diff --git a/Tests/Functional/PaymentWorkflowMcryptTest.php b/Tests/Functional/PaymentWorkflowMcryptTest.php new file mode 100755 index 00000000..c10d224f --- /dev/null +++ b/Tests/Functional/PaymentWorkflowMcryptTest.php @@ -0,0 +1,27 @@ + 'config_mcrypt.yml')); + } + + /** + * @runInSeparateProcess + */ + public function testPaymentDetails() + { + if (version_compare(phpversion(), '7.1', '>=')) { + $this->markTestSkipped('mcrypt is deprecated since PHP 7.1'); + } + + $order = parent::doTestPaymentDetails(); + + $extendedData = $this->getRawExtendedData($order->getPaymentInstruction()); + $this->assertArrayHasKey('foo', $extendedData); + $this->assertNotEquals('bar', $extendedData['foo'][0]); + } +} diff --git a/Tests/Functional/TestBundle/Resources/config/config.yml b/Tests/Functional/TestBundle/Resources/config/config.yml index 9e504f1f..c19cbf54 100644 --- a/Tests/Functional/TestBundle/Resources/config/config.yml +++ b/Tests/Functional/TestBundle/Resources/config/config.yml @@ -2,4 +2,6 @@ imports: - { resource: default.yml } jms_payment_core: - secret: test + encryption: + provider: defuse_php_encryption + secret: def00000812bba10524777c97f1155877f0c91a4fac2c9f3d71a39d0df7214eab90d492faa58d2db667c5003c3c2228e3f19ad493ae86c74079a600a1ed51cd65e21f28e diff --git a/Tests/Functional/TestBundle/Resources/config/config_mcrypt.yml b/Tests/Functional/TestBundle/Resources/config/config_mcrypt.yml new file mode 100644 index 00000000..9e504f1f --- /dev/null +++ b/Tests/Functional/TestBundle/Resources/config/config_mcrypt.yml @@ -0,0 +1,5 @@ +imports: + - { resource: default.yml } + +jms_payment_core: + secret: test diff --git a/Tests/Functional/TestBundle/Resources/config/config_no_encryption.yml b/Tests/Functional/TestBundle/Resources/config/config_no_encryption.yml index d1f99aee..c74c782a 100644 --- a/Tests/Functional/TestBundle/Resources/config/config_no_encryption.yml +++ b/Tests/Functional/TestBundle/Resources/config/config_no_encryption.yml @@ -1,2 +1,4 @@ imports: - { resource: default.yml } + +jms_payment_core: ~ \ No newline at end of file diff --git a/composer.json b/composer.json index 7e0f43a1..0c301e6c 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "jms/payment-core-bundle", "type": "symfony-bundle", - "description": "This bundle is providing the foundation for various payment plugins.", + "description": "A unified API for processing payments with Symfony", "keywords": ["payment"], "homepage": "http://jmspaymentcorebundle.readthedocs.io", "license": "Apache2", @@ -20,8 +20,7 @@ } ], "require": { - "php": ">=5.3.2", - "ext-mcrypt": "*", + "php": ">=5.4", "doctrine/common": "~2.3", "doctrine/dbal": "~2.3", "doctrine/orm": "~2.3", @@ -33,7 +32,8 @@ "symfony/options-resolver": "~2.3|~3.0", "symfony/http-foundation": "~2.3|~3.0", "symfony/http-kernel": "~2.3|~3.0", - "symfony/validator": "~2.3|~3.0" + "symfony/validator": "~2.3|~3.0", + "defuse/php-encryption": "~2.0" }, "require-dev": { "phpunit/phpunit": "~4.8|~5.4", From d96294091d9cc35b3fca4c2d354fe9b2cb21c234 Mon Sep 17 00:00:00 2001 From: Paulo Rodrigues Pinto Date: Mon, 16 Jan 2017 16:28:18 +0000 Subject: [PATCH 07/15] Make defuse the default encryption provider (#207) Only applies when using the 'encryption.secret' option. If the 'secret' configuration option is used, mcrypt will still be the default in order to maintain BC. --- CHANGELOG.md | 5 ++-- DependencyInjection/Configuration.php | 18 ++++++++----- .../JMSPaymentCoreExtension.php | 2 +- Resources/doc/setup.rst | 11 ++++---- .../Configuration/ConfigurationTest.php | 25 +++++++++++++++---- 5 files changed, 42 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 66c9330e..7d900b72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,11 +9,12 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Added missing `mayBePersisted` method - Added missing `$persist` parameter to `set` method - `JMS\Payment\CoreBundle\EntityExtendedDataType::convertToDatabaseValue` now throws an exception when attempting to convert an object which does not implement `JMS\Payment\CoreBundle\Model\ExtendedDataInterface`. -- Encryption is now optional and disabled by default, unless the `secret` configuration option is set. This ensures existing installations keep working as expected. +- Encryption is now optional and disabled by default, unless the `secret` configuration option is set. +- `defuse_php_encryption` is now the default encryption provider, unless when using the `secret` configuration option, in which case the default is set to `mcrypt`. ### Deprecated - The service `payment.encryption_service` has been deprecated and is now an alias to `payment.encryption.mcrypt`. Parameters specified for `payment.encryption_service` are automatically set for `payment.encryption.mcrypt` so no changes are required in service configuration until `payment.encryption_service` is removed in 2.0. -- The `secret` configuration option has been deprecated in favor of `encryption.secret` and will be removed in 2.0. +- The `secret` configuration option has been deprecated in favor of `encryption.secret` and will be removed in 2.0. Please note that if you start using `encryption.secret` you also need to set `encryption.provider` to `mcrypt` since mcrypt is not the default when using the `encryption.*` options. ### Added - Added support for custom encryption providers. diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 06892e7c..9d731d29 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -40,19 +40,19 @@ public function getConfigTreeBuilder() ->canBeEnabled() ->addDefaultsIfNotSet() ->children() - ->scalarNode('provider')->defaultValue('mcrypt')->end() + ->scalarNode('provider')->defaultValue('defuse_php_encryption')->end() ->scalarNode('secret')->cannotBeEmpty()->end() ->end() ->validate() ->ifTrue(function ($config) { - return $config['enabled'] && empty($config['secret']); + return $config['enabled'] && !array_key_exists('secret', $config); }) ->thenInvalid('An encryption secret is required') ->end() ->end() ->scalarNode('secret') ->cannotBeEmpty() - ->info("The 'secret' configuration option has been deprecated in favor of 'encryption.secret' and will be removed in 2.0") + ->info($this->getSecretDeprecationMessage()) ->end() ->end() ->beforeNormalization() @@ -60,11 +60,12 @@ public function getConfigTreeBuilder() return !empty($config['secret']); }) ->then(function ($config) { - @trigger_error("The 'secret' configuration option has been deprecated in favor of 'encryption.secret' and will be removed in 2.0", E_USER_DEPRECATED); + @trigger_error($this->getSecretDeprecationMessage(), E_USER_DEPRECATED); $config['encryption'] = array( - 'enabled' => true, - 'secret' => $config['secret'], + 'enabled' => true, + 'provider' => 'mcrypt', + 'secret' => $config['secret'], ); return $config; @@ -74,4 +75,9 @@ public function getConfigTreeBuilder() return $builder; } + + private function getSecretDeprecationMessage() + { + return "The 'secret' configuration option has been deprecated in favor of 'encryption.secret' and will be removed in 2.0. Please note that if you start using 'encryption.secret' you also need to set 'encryption.provider' to 'mcrypt' since mcrypt is not the default when using the 'encryption.*' options."; + } } diff --git a/DependencyInjection/JMSPaymentCoreExtension.php b/DependencyInjection/JMSPaymentCoreExtension.php index e5258674..167e9bbc 100644 --- a/DependencyInjection/JMSPaymentCoreExtension.php +++ b/DependencyInjection/JMSPaymentCoreExtension.php @@ -59,9 +59,9 @@ public function load(array $configs, ContainerBuilder $container) } } else { $container->removeAlias('payment.encryption_service'); + $container->removeDefinition('payment.encryption'); $container->removeDefinition('payment.encryption.mcrypt'); $container->removeDefinition('payment.encryption.defuse_php_encryption'); - $container->removeDefinition('payment.encryption'); } } diff --git a/Resources/doc/setup.rst b/Resources/doc/setup.rst index 5ac499fb..7755704e 100644 --- a/Resources/doc/setup.rst +++ b/Resources/doc/setup.rst @@ -31,9 +31,10 @@ You can generate the secret with the following command: .. code-block :: bash - # Feel free to increase the length of the generated string by - # passing a larger number to openssl_random_pseudo_bytes - php -r 'echo bin2hex(openssl_random_pseudo_bytes(16))."\n";' + php -r ' + require "vendor/autoload.php"; + echo (\Defuse\Crypto\Key::createNewRandomKey())->saveToAsciiSafeString()."\n"; + ' And then use it in your configuration: @@ -44,9 +45,9 @@ And then use it in your configuration: # app/config/config.yml jms_payment_core: encryption: - secret: yoursecret + secret: output_of_above_command -.. note :: +.. warning :: If you change the secret, all data encrypted with the old secret will become unreadable. diff --git a/Tests/DependencyInjection/Configuration/ConfigurationTest.php b/Tests/DependencyInjection/Configuration/ConfigurationTest.php index 9579e4ac..99c6440b 100644 --- a/Tests/DependencyInjection/Configuration/ConfigurationTest.php +++ b/Tests/DependencyInjection/Configuration/ConfigurationTest.php @@ -16,7 +16,7 @@ public function testNoSecret() array(), array('encryption' => array( 'enabled' => false, - 'provider' => 'mcrypt', + 'provider' => 'defuse_php_encryption', )) ); } @@ -47,7 +47,7 @@ public function testEncryptionDisabled() array(), array('encryption' => array( 'enabled' => false, - 'provider' => 'mcrypt', + 'provider' => 'defuse_php_encryption', )) ); @@ -55,7 +55,7 @@ public function testEncryptionDisabled() array('encryption' => false), array('encryption' => array( 'enabled' => false, - 'provider' => 'mcrypt', + 'provider' => 'defuse_php_encryption', )) ); @@ -65,7 +65,7 @@ public function testEncryptionDisabled() )), array('encryption' => array( 'enabled' => false, - 'provider' => 'mcrypt', + 'provider' => 'defuse_php_encryption', )) ); } @@ -83,6 +83,21 @@ public function testEncryptionEnabled() 'secret' => 'foo', ))); + $this->assertConfigurationIsValid(array('encryption' => array( + 'secret' => 'foo', + ))); + + $this->assertConfigurationEquals( + array('encryption' => array( + 'secret' => 'foo', + )), + array('encryption' => array( + 'enabled' => true, + 'secret' => 'foo', + 'provider' => 'defuse_php_encryption', + )) + ); + $this->assertConfigurationEquals( array('encryption' => array( 'enabled' => true, @@ -91,7 +106,7 @@ public function testEncryptionEnabled() array('encryption' => array( 'enabled' => true, 'secret' => 'foo', - 'provider' => 'mcrypt', + 'provider' => 'defuse_php_encryption', )) ); } From 5d51e60759312411d34ce09fc836c2da521cf3c9 Mon Sep 17 00:00:00 2001 From: Paulo Rodrigues Pinto Date: Thu, 19 Jan 2017 00:38:45 +0000 Subject: [PATCH 08/15] Add command for generating encryption keys (#208) --- CHANGELOG.md | 1 + Command/GenerateKeyCommand.php | 24 ++++++++++ Resources/doc/setup.rst | 5 +- .../Command/GenerateKeyCommandTest.php | 48 +++++++++++++++++++ 4 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 Command/GenerateKeyCommand.php create mode 100644 Tests/Functional/Command/GenerateKeyCommandTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d900b72..35b44c05 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - Added support for custom encryption providers. - Added support for data encryption with [defuse/php-encryption](https://github.com/defuse/php-encryption). - Added ability to configure which crypto provider should be used. Current available options are `mcrypt` (not recommended since it will be removed in PHP 7.2) and `defuse_php_encryption`. +- Added console command to generate an encryption key for use with `defuse_php_encryption`. ### Removed - Removed support for PHP 5.3. If you're still using PHP 5.3, please consider upgrading since it reached End Of Life in August 2014. Otherwise, use `1.2.*`. diff --git a/Command/GenerateKeyCommand.php b/Command/GenerateKeyCommand.php new file mode 100644 index 00000000..a3ba623d --- /dev/null +++ b/Command/GenerateKeyCommand.php @@ -0,0 +1,24 @@ +setName('jms_payment_core:generate-key') + ->setDescription('Generate an encryption key') + ; + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $output->writeln(Key::createNewRandomKey()->saveToAsciiSafeString()); + } +} diff --git a/Resources/doc/setup.rst b/Resources/doc/setup.rst index 7755704e..6273f435 100644 --- a/Resources/doc/setup.rst +++ b/Resources/doc/setup.rst @@ -31,10 +31,7 @@ You can generate the secret with the following command: .. code-block :: bash - php -r ' - require "vendor/autoload.php"; - echo (\Defuse\Crypto\Key::createNewRandomKey())->saveToAsciiSafeString()."\n"; - ' + bin/console jms_payment_core:generate-key And then use it in your configuration: diff --git a/Tests/Functional/Command/GenerateKeyCommandTest.php b/Tests/Functional/Command/GenerateKeyCommandTest.php new file mode 100644 index 00000000..424afdad --- /dev/null +++ b/Tests/Functional/Command/GenerateKeyCommandTest.php @@ -0,0 +1,48 @@ +add(new GenerateKeyCommand()); + + $this->command = $application->find('jms_payment_core:generate-key'); + + parent::setUp(); + } + + /** + * @runInSeparateProcess + */ + public function testGeneration() + { + $key = trim($this->execute(array())); + + $cipher = new DefusePhpEncryptionService($key); + + $this->assertNotEmpty($key); + $this->assertEquals('foo', $cipher->decrypt($cipher->encrypt('foo'))); + } + + private function execute(array $input) + { + $commandTester = new CommandTester($this->command); + + $commandTester->execute(array_merge(array( + 'command' => $this->command->getName(), + ), $input)); + + return $commandTester->getDisplay(); + } +} From cceca8af6e270db12f59ea2319dd29379e861da6 Mon Sep 17 00:00:00 2001 From: Paulo Rodrigues Pinto Date: Sun, 22 Jan 2017 17:37:59 +0000 Subject: [PATCH 09/15] Deprecate usage of mcrypt (#200) --- CHANGELOG.md | 3 ++- Cryptography/MCryptEncryptionService.php | 8 +++++--- README.md | 2 +- Resources/doc/guides/mcrypt.rst | 4 ++++ Resources/doc/setup.rst | 24 +++++++++--------------- 5 files changed, 21 insertions(+), 20 deletions(-) create mode 100644 Resources/doc/guides/mcrypt.rst diff --git a/CHANGELOG.md b/CHANGELOG.md index 35b44c05..06789a13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,12 +15,13 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p ### Deprecated - The service `payment.encryption_service` has been deprecated and is now an alias to `payment.encryption.mcrypt`. Parameters specified for `payment.encryption_service` are automatically set for `payment.encryption.mcrypt` so no changes are required in service configuration until `payment.encryption_service` is removed in 2.0. - The `secret` configuration option has been deprecated in favor of `encryption.secret` and will be removed in 2.0. Please note that if you start using `encryption.secret` you also need to set `encryption.provider` to `mcrypt` since mcrypt is not the default when using the `encryption.*` options. +- `JMS\Payment\CoreBundle\Cryptography\MCryptEncryptionService` has been deprecated and will be removed in 2.0 (`mcrypt` has been deprecated in PHP 7.1 and is removed in PHP 7.2). Refer to http://jmspaymentcorebundle.readthedocs.io/en/stable/guides/mcrypt.html for instructions on how to migrate away from `mcrypt`. ### Added - Added support for custom encryption providers. - Added support for data encryption with [defuse/php-encryption](https://github.com/defuse/php-encryption). -- Added ability to configure which crypto provider should be used. Current available options are `mcrypt` (not recommended since it will be removed in PHP 7.2) and `defuse_php_encryption`. - Added console command to generate an encryption key for use with `defuse_php_encryption`. +- Added ability to configure which encryption provider should be used. Current available options are `mcrypt` (not recommended since it will be removed in PHP 7.2) and `defuse_php_encryption`. ### Removed - Removed support for PHP 5.3. If you're still using PHP 5.3, please consider upgrading since it reached End Of Life in August 2014. Otherwise, use `1.2.*`. diff --git a/Cryptography/MCryptEncryptionService.php b/Cryptography/MCryptEncryptionService.php index e8a0ffb5..54d8e48b 100644 --- a/Cryptography/MCryptEncryptionService.php +++ b/Cryptography/MCryptEncryptionService.php @@ -46,11 +46,13 @@ public function __construct($secret, $cipher = 'rijndael-256', $mode = 'ctr') throw new \RuntimeException('The mcrypt extension must be loaded.'); } - if (!in_array($cipher, mcrypt_list_algorithms(), true)) { + @trigger_error('mcrypt has been deprecated in PHP 7.1 and is removed in PHP 7.2. Refer to http://jmspaymentcorebundle.readthedocs.io/en/stable/guides/mcrypt.html for instructions on how to migrate away from mcrypt', E_USER_DEPRECATED); + + if (!in_array($cipher, @mcrypt_list_algorithms(), true)) { throw new \InvalidArgumentException(sprintf('The cipher "%s" is not supported.', $cipher)); } - if (!in_array($mode, mcrypt_list_modes(), true)) { + if (!in_array($mode, @mcrypt_list_modes(), true)) { throw new \InvalidArgumentException(sprintf('The mode "%s" is not supported.', $mode)); } @@ -62,7 +64,7 @@ public function __construct($secret, $cipher = 'rijndael-256', $mode = 'ctr') } $key = hash('sha256', $secret, true); - if (strlen($key) > $size = mcrypt_get_key_size($this->cipher, $this->mode)) { + if (strlen($key) > $size = @mcrypt_get_key_size($this->cipher, $this->mode)) { $key = substr($key, 0, $size); } $this->key = $key; diff --git a/README.md b/README.md index e44b8fb4..6f16ea36 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Features: - Persistence of financial entities (such as payments, transactions, etc.) - Transaction management including retry logic - Encryption of sensitive data -- Supports [many](http://jmspaymentcorebundle.readthedocs.io/en/latest/backends.html) payment backends out of the box +- Supports [many](http://jmspaymentcorebundle.readthedocs.io/en/stable/backends.html) payment backends out of the box - Easily support other payment backends # Documentation diff --git a/Resources/doc/guides/mcrypt.rst b/Resources/doc/guides/mcrypt.rst new file mode 100644 index 00000000..92c310f1 --- /dev/null +++ b/Resources/doc/guides/mcrypt.rst @@ -0,0 +1,4 @@ +Migrating from Mcrypt +===================== + +Coming soon diff --git a/Resources/doc/setup.rst b/Resources/doc/setup.rst index 6273f435..e09d2b0d 100644 --- a/Resources/doc/setup.rst +++ b/Resources/doc/setup.rst @@ -25,9 +25,7 @@ And register the bundle in your ``AppKernel.php``: Configuration ------------- -The configuration is as simple as setting a random secret which will be used for encrypting data, in case this is requested. - -You can generate the secret with the following command: +The configuration is as simple as setting an encryption key which will be used for encrypting data. You can generate a random key with the following command: .. code-block :: bash @@ -35,22 +33,20 @@ You can generate the secret with the following command: And then use it in your configuration: -.. configuration-block :: - - .. code-block :: yaml +.. code-block :: yaml - # app/config/config.yml - jms_payment_core: - encryption: - secret: output_of_above_command + # app/config/config.yml + jms_payment_core: + encryption: + secret: output_of_above_command .. warning :: - If you change the secret, all data encrypted with the old secret will become unreadable. + If you change the ``secret`` or the ``crypto`` provider, all encrypted data will become unreadable. Create database tables ---------------------- -This bundle requires a few database tables to function. You can create these tables as follows. +This bundle requires a few database tables, which you can create as follows. If you're not using database migrations: @@ -65,14 +61,13 @@ Or, if you're using migrations: bin/console doctrine:migrations:diff bin/console doctrine:migrations:migrate -.. warning :: +.. note :: It's assumed you have entity auto mapping enabled, which is usually the case. If you don't, you need to either enable it: .. code-block :: yaml # app/config/config.yml - doctrine: orm: auto_mapping: true @@ -82,7 +77,6 @@ Or, if you're using migrations: .. code-block :: yaml # app/config/config.yml - doctrine: orm: mappings: From 8ea0b3a10cba35af038ce63713ac7d27b0d01f8d Mon Sep 17 00:00:00 2001 From: Paulo Rodrigues Pinto Date: Sun, 22 Jan 2017 17:49:09 +0000 Subject: [PATCH 10/15] Prepare release 1.3.0 --- CHANGELOG.md | 7 +++++-- composer.json | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 06789a13..ed3db181 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,14 +3,15 @@ All notable changes to this project are documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). -## [1.3.0] - (Unreleased) +## [1.3.0] - 2017-01-22 ### Changed - `JMS\Payment\CoreBundle\Model\ExtendedDataInterface` has changed. If any of your classes implement this interface, you need to update them accordingly: - Added missing `mayBePersisted` method - Added missing `$persist` parameter to `set` method - `JMS\Payment\CoreBundle\EntityExtendedDataType::convertToDatabaseValue` now throws an exception when attempting to convert an object which does not implement `JMS\Payment\CoreBundle\Model\ExtendedDataInterface`. -- Encryption is now optional and disabled by default, unless the `secret` configuration option is set. +- Encryption is now optional and disabled by default, unless the `secret` or `encryption.secret` configuration options are set. - `defuse_php_encryption` is now the default encryption provider, unless when using the `secret` configuration option, in which case the default is set to `mcrypt`. +- The EntityManager is no longer closed when an Exception is thrown (#145) ### Deprecated - The service `payment.encryption_service` has been deprecated and is now an alias to `payment.encryption.mcrypt`. Parameters specified for `payment.encryption_service` are automatically set for `payment.encryption.mcrypt` so no changes are required in service configuration until `payment.encryption_service` is removed in 2.0. @@ -18,6 +19,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - `JMS\Payment\CoreBundle\Cryptography\MCryptEncryptionService` has been deprecated and will be removed in 2.0 (`mcrypt` has been deprecated in PHP 7.1 and is removed in PHP 7.2). Refer to http://jmspaymentcorebundle.readthedocs.io/en/stable/guides/mcrypt.html for instructions on how to migrate away from `mcrypt`. ### Added +- Added ``method_options`` and ``choice_options`` to form. See the [documentation](http://jmspaymentcorebundle.readthedocs.io/en/stable/payment_form.html#choice-options) for more information. +- Added a guides section to the documentation - Added support for custom encryption providers. - Added support for data encryption with [defuse/php-encryption](https://github.com/defuse/php-encryption). - Added console command to generate an encryption key for use with `defuse_php_encryption`. diff --git a/composer.json b/composer.json index 0c301e6c..2fd060a8 100644 --- a/composer.json +++ b/composer.json @@ -58,7 +58,7 @@ "target-dir": "JMS/Payment/CoreBundle", "extra": { "branch-alias": { - "dev-master": "1.2-dev" + "dev-master": "1.3-dev" } } } From 047528837de5d47ac9b68a36d5ec8317566892ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Wed, 8 Feb 2017 18:49:47 +0100 Subject: [PATCH 11/15] Avoid reliance on kernel version Fixes #212 --- .../AddPaymentMethodFormTypesPass.php | 6 +-- Form/ChoosePaymentMethodType.php | 17 ++++---- Tests/Form/ChoosePaymentMethodTypeTest.php | 26 ++++++------ .../TestBundle/Controller/OrderController.php | 6 +-- Util/Legacy.php | 40 ++++++++++++++----- 5 files changed, 60 insertions(+), 35 deletions(-) diff --git a/DependencyInjection/Compiler/AddPaymentMethodFormTypesPass.php b/DependencyInjection/Compiler/AddPaymentMethodFormTypesPass.php index dbf3f285..709ecf4f 100755 --- a/DependencyInjection/Compiler/AddPaymentMethodFormTypesPass.php +++ b/DependencyInjection/Compiler/AddPaymentMethodFormTypesPass.php @@ -33,9 +33,9 @@ public function process(ContainerBuilder $container) throw new \RuntimeException(sprintf('Please define an alias attribute for tag "form.type" of service "%s".', $id)); } - $paymentMethodFormTypes[$attrs[0]['alias']] = Legacy::supportsFormTypeName() - ? $attrs[0]['alias'] - : $definition->getClass() + $paymentMethodFormTypes[$attrs[0]['alias']] = Legacy::supportsFormTypeClass() + ? $definition->getClass() + : $attrs[0]['alias'] ; } diff --git a/Form/ChoosePaymentMethodType.php b/Form/ChoosePaymentMethodType.php index f0439064..294a2788 100755 --- a/Form/ChoosePaymentMethodType.php +++ b/Form/ChoosePaymentMethodType.php @@ -92,15 +92,18 @@ protected function buildChoiceList(FormBuilderInterface $builder, array $options $label = 'form.label.'.$method; if (Legacy::formChoicesAsValues()) { - $options['choices'][$method] = $label; - } else { $options['choices'][$label] = $method; + if (Legacy::needsChoicesAsValuesOption()) { + $options['choices_as_values'] = true; + } + } else { + $options['choices'][$method] = $label; } } - $type = Legacy::supportsFormTypeName() - ? 'choice' - : 'Symfony\Component\Form\Extension\Core\Type\ChoiceType' + $type = Legacy::supportsFormTypeClass() + ? 'Symfony\Component\Form\Extension\Core\Type\ChoiceType' + : 'choice' ; $builder->add('method', $type, $options); @@ -161,11 +164,11 @@ public function configureOptions(OptionsResolver $resolver) 'choice_options' => 'array', ); - if (Legacy::supportsFormTypeConfigureOptions()) { + if (Legacy::supportsOptionsResolverSetAllowedTypesAsArray()) { $resolver->setAllowedTypes($allowedTypes); } else { foreach ($allowedTypes as $key => $value) { - $resolver->addAllowedTypes($key, $value); + $resolver->setAllowedTypes($key, $value); } } } diff --git a/Tests/Form/ChoosePaymentMethodTypeTest.php b/Tests/Form/ChoosePaymentMethodTypeTest.php index d7e6ad22..dec0ccf5 100644 --- a/Tests/Form/ChoosePaymentMethodTypeTest.php +++ b/Tests/Form/ChoosePaymentMethodTypeTest.php @@ -58,7 +58,7 @@ public function testMethodData() public function testMethodChoices() { - if (Legacy::formChoicesAsValues()) { + if (!Legacy::formChoicesAsValues()) { $this->markTestSkipped(); } @@ -72,7 +72,7 @@ public function testMethodChoices() public function testLegacyMethodChoices() { - if (!Legacy::formChoicesAsValues()) { + if (Legacy::formChoicesAsValues()) { $this->markTestSkipped(); } @@ -104,7 +104,7 @@ public function testDefaultMethod() public function testAllowedMethods() { - if (Legacy::formChoicesAsValues()) { + if (!Legacy::formChoicesAsValues()) { $this->markTestSkipped(); } @@ -122,7 +122,7 @@ public function testAllowedMethods() public function testLegacyAllowedMethods() { - if (!Legacy::formChoicesAsValues()) { + if (Legacy::formChoicesAsValues()) { $this->markTestSkipped(); } @@ -173,9 +173,9 @@ private function createForm($options = array(), $data = array()) 'currency' => 'EUR', ), $options); - $form = Legacy::supportsFormTypeName() - ? 'jms_choose_payment_method' - : 'JMS\Payment\CoreBundle\Form\ChoosePaymentMethodType' + $form = Legacy::supportsFormTypeClass() + ? 'JMS\Payment\CoreBundle\Form\ChoosePaymentMethodType' + : 'jms_choose_payment_method' ; $form = $this->factory->create($form, null, $options); @@ -196,10 +196,10 @@ protected function getExtensions() { $pluginType = new ExpressCheckoutType(); - if (Legacy::supportsFormTypeName()) { - $pluginTypeName = $pluginType->getName(); - } else { + if (Legacy::supportsFormTypeClass()) { $pluginTypeName = get_class($pluginType); + } else { + $pluginTypeName = $pluginType->getName(); } $type = new ChoosePaymentMethodType($this->pluginController, array( @@ -207,13 +207,13 @@ protected function getExtensions() 'bar' => $pluginTypeName, )); - if (Legacy::supportsFormTypeName()) { + if (Legacy::supportsFormTypeClass()) { + $extensions = array($pluginType, $type); + } else { $extensions = array( $pluginType->getName() => $pluginType, $type->getName() => $type, ); - } else { - $extensions = array($pluginType, $type); } return array(new PreloadedExtension($extensions, array())); diff --git a/Tests/Functional/TestBundle/Controller/OrderController.php b/Tests/Functional/TestBundle/Controller/OrderController.php index a4c5adcd..ffdb0ac4 100755 --- a/Tests/Functional/TestBundle/Controller/OrderController.php +++ b/Tests/Functional/TestBundle/Controller/OrderController.php @@ -24,9 +24,9 @@ class OrderController extends Controller */ public function paymentDetailsAction(Order $order) { - $formType = Legacy::supportsFormTypeName() - ? 'jms_choose_payment_method' - : 'JMS\Payment\CoreBundle\Form\ChoosePaymentMethodType' + $formType = Legacy::supportsFormTypeClass() + ? 'JMS\Payment\CoreBundle\Form\ChoosePaymentMethodType' + : 'jms_choose_payment_method' ; $form = $this->get('form.factory')->create($formType, null, array( diff --git a/Util/Legacy.php b/Util/Legacy.php index f239ad9a..cf619c39 100644 --- a/Util/Legacy.php +++ b/Util/Legacy.php @@ -11,23 +11,30 @@ class Legacy { /** - * Symfony 3.0 removes support for form type names. + * Symfony 2.8 adds support for form type as FQCN. * - * Instead of referencing types by name, they must be referenced by their + * Instead of referencing types by name, they should be referenced by their * fully-qualified class name (FQCN). */ - public static function supportsFormTypeName() + public static function supportsFormTypeClass() { - return version_compare(Kernel::VERSION, '3.0.0', '<'); + return method_exists( + 'Symfony\Component\Form\AbstractType', + 'getBlockPrefix' + ); } /** - * Symfony 3.0 requires using `configureOptions` instead of `setDefaultOptions` - * in form types. + * Before Symfony 2.6, setAllowedTypes() and addAllowedTypes() expected the + * values to be given as an array mapping option names to allowed types: + * $resolver->setAllowedTypes(array('port' => array('null', 'int'))); */ - public static function supportsFormTypeConfigureOptions() + public static function supportsOptionsResolverSetAllowedTypesAsArray() { - return version_compare(Kernel::VERSION, '3.0.0', '<'); + return !method_exists( + 'Symfony\Component\OptionsResolver\OptionsResolver', + 'setDefined' + ); } /** @@ -43,7 +50,22 @@ public static function supportsFormTypeConfigureOptions() */ public static function formChoicesAsValues() { - return version_compare(Kernel::VERSION, '3.0.0', '<'); + return method_exists( + 'Symfony\Component\Form\AbstractType', + 'configureOptions' + ); + } + + /** + * When using `choices_as_values` before Symfony 3.0, one must make sure to + * set the `choices_as_values` option to true + */ + public static function needsChoicesAsValuesOption() + { + return self::formChoicesAsValues() && method_exists( + 'Symfony\Component\Form\FormTypeInterface', + 'setDefaultOptions' + ); } /** From bbd1da735bc2ce9f744de5ec88bc99ab26201c22 Mon Sep 17 00:00:00 2001 From: Paulo Rodrigues Pinto Date: Thu, 15 Jun 2017 13:45:15 +0100 Subject: [PATCH 12/15] No longer build for HHVM --- .travis.yml | 2 -- .travis/before_install.php | 6 ++---- .travis/common.php | 5 ----- 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index a89a2e0d..5cd4c752 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,8 +22,6 @@ matrix: env: SYMFONY_VERSION=3.2.* - php: 7.0 env: SYMFONY_VERSION=3.2.* - - php: hhvm - env: SYMFONY_VERSION=3.2.* # current PHP with all relevant Symfony versions - php: 7.1 env: SYMFONY_VERSION=2.3.* diff --git a/.travis/before_install.php b/.travis/before_install.php index b3479f12..4bc9986c 100755 --- a/.travis/before_install.php +++ b/.travis/before_install.php @@ -3,7 +3,5 @@ include_once 'common.php'; -if (!isHhvm()) { - // Disable XDebug - run('phpenv config-rm xdebug.ini'); -} +// Disable XDebug +run('phpenv config-rm xdebug.ini'); diff --git a/.travis/common.php b/.travis/common.php index bc236c31..7a332d33 100644 --- a/.travis/common.php +++ b/.travis/common.php @@ -5,11 +5,6 @@ function shouldBuildDocs() return isLatestPhp() && isLatestSymfony(); } -function isHhvm() -{ - return getPhpVersion() === 'hhvm'; -} - function isLatestPhp() { return getPhpVersion() === '7.1'; From 350d021f0fd5d5c4aeff20d019d22ab3186acc53 Mon Sep 17 00:00:00 2001 From: Paulo Rodrigues Pinto Date: Thu, 15 Jun 2017 13:49:46 +0100 Subject: [PATCH 13/15] Test for symfony 3.3 --- .travis.yml | 2 +- .travis/common.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5cd4c752..6cdaefe9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,7 +28,7 @@ matrix: - php: 7.1 env: SYMFONY_VERSION=2.8.* - php: 7.1 - env: SYMFONY_VERSION=3.2.* + env: SYMFONY_VERSION=3.3.* - php: 7.1 env: SYMFONY_VERSION=dev-master allow_failures: diff --git a/.travis/common.php b/.travis/common.php index 7a332d33..2c6087db 100644 --- a/.travis/common.php +++ b/.travis/common.php @@ -12,7 +12,7 @@ function isLatestPhp() function isLatestSymfony() { - return getSymfonyVersion() === '3.2.*'; + return getSymfonyVersion() === '3.3.*'; } function getSymfonyVersion() From 271d26d5dc6822cc5971fe0d6e72dfd36d1ceb21 Mon Sep 17 00:00:00 2001 From: phcorp Date: Fri, 28 Jul 2017 13:08:25 +0200 Subject: [PATCH 14/15] Replace abandoned project by most advanced fork --- Resources/doc/backends.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/doc/backends.rst b/Resources/doc/backends.rst index c8c69393..297a41c2 100755 --- a/Resources/doc/backends.rst +++ b/Resources/doc/backends.rst @@ -9,7 +9,7 @@ This is the list of currently supported payment backends, through community-crea If you have implemented a payment backend, please add it to this list by `editing this file on GitHub `_ and submitting a Pull Request. - `Adyen `_ -- `Atos SIPS `_ +- `Atos SIPS `_ - `Be2Bill (Rentabiliweb) `_ - `Dotpay `_ - `Ogone `_ From 69822854b63a30084a765ce8e43e6acb5bb22efd Mon Sep 17 00:00:00 2001 From: Paulo Rodrigues Pinto Date: Sun, 19 Nov 2017 15:29:39 +0000 Subject: [PATCH 15/15] Remove paypal plugin dependency (#220) * Cache and test dirs for tests should be in tmp directory * Add a TestPlugin to use instead of the paypal plugin * Remove all references to paypal plugin in favor of the test plugin --- Tests/Form/ChoosePaymentMethodTypeTest.php | 6 +++--- Tests/Functional/AppKernel.php | 10 ++++++++-- Tests/Functional/BasePaymentWorkflowTest.php | 2 +- .../Functional/BasicEntityInteractionsTest.php | 2 +- .../TestBundle/Controller/OrderController.php | 2 +- .../TestBundle/Resources/config/default.yml | 7 ------- .../DependencyInjection/TestPluginExtension.php | 17 +++++++++++++++++ .../TestPlugin/Form/TestPluginType.php | 17 +++++++++++++++++ .../Functional/TestPlugin/Plugin/TestPlugin.php | 13 +++++++++++++ .../TestPlugin/Resources/config/services.yml | 11 +++++++++++ .../Functional/TestPlugin/TestPluginBundle.php | 9 +++++++++ composer.json | 1 - 12 files changed, 81 insertions(+), 16 deletions(-) create mode 100644 Tests/Functional/TestPlugin/DependencyInjection/TestPluginExtension.php create mode 100644 Tests/Functional/TestPlugin/Form/TestPluginType.php create mode 100644 Tests/Functional/TestPlugin/Plugin/TestPlugin.php create mode 100644 Tests/Functional/TestPlugin/Resources/config/services.yml create mode 100644 Tests/Functional/TestPlugin/TestPluginBundle.php diff --git a/Tests/Form/ChoosePaymentMethodTypeTest.php b/Tests/Form/ChoosePaymentMethodTypeTest.php index dec0ccf5..4f7de9e5 100644 --- a/Tests/Form/ChoosePaymentMethodTypeTest.php +++ b/Tests/Form/ChoosePaymentMethodTypeTest.php @@ -3,8 +3,8 @@ namespace JMS\Payment\CoreBundle\Tests\Form\ChoosePaymentMethodTypeTest; use JMS\Payment\CoreBundle\Form\ChoosePaymentMethodType; +use JMS\Payment\CoreBundle\Tests\Functional\TestPlugin\Form\TestPluginType; use JMS\Payment\CoreBundle\Util\Legacy; -use JMS\Payment\PaypalBundle\Form\ExpressCheckoutType; use Symfony\Component\Form\PreloadedExtension; use Symfony\Component\Form\Test\TypeTestCase; use Symfony\Component\HttpKernel\Kernel; @@ -50,7 +50,7 @@ public function testMethodData() $config = $form->get('data_'.$method)->getConfig(); $this->assertInstanceOf( - 'JMS\Payment\PaypalBundle\Form\ExpressCheckoutType', + 'JMS\Payment\CoreBundle\Tests\Functional\TestPlugin\Form\TestPluginType', $config->getType()->getInnerType() ); } @@ -194,7 +194,7 @@ protected function setUp() protected function getExtensions() { - $pluginType = new ExpressCheckoutType(); + $pluginType = new TestPluginType(); if (Legacy::supportsFormTypeClass()) { $pluginTypeName = get_class($pluginType); diff --git a/Tests/Functional/AppKernel.php b/Tests/Functional/AppKernel.php index 0ec32fa8..bd8be997 100644 --- a/Tests/Functional/AppKernel.php +++ b/Tests/Functional/AppKernel.php @@ -2,6 +2,7 @@ namespace JMS\Payment\CoreBundle\Tests\Functional; +use JMS\Payment\CoreBundle\Tests\Functional\TestPlugin\TestPluginBundle; use Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\HttpKernel\Kernel; @@ -34,7 +35,7 @@ public function registerBundles() new \Symfony\Bundle\TwigBundle\TwigBundle(), new \JMS\Payment\CoreBundle\Tests\Functional\TestBundle\TestBundle(), new \JMS\Payment\CoreBundle\JMSPaymentCoreBundle(), - new \JMS\Payment\PaypalBundle\JMSPaymentPaypalBundle(), + new TestPluginBundle(), new \Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(), ); } @@ -46,6 +47,11 @@ public function registerContainerConfiguration(LoaderInterface $loader) public function getCacheDir() { - return sys_get_temp_dir().'/JMSPaymentCoreBundle'; + return sys_get_temp_dir().'/JMSPaymentCoreBundle/cache'; + } + + public function getLogDir() + { + return sys_get_temp_dir().'/JMSPaymentCoreBundle/logs'; } } diff --git a/Tests/Functional/BasePaymentWorkflowTest.php b/Tests/Functional/BasePaymentWorkflowTest.php index 6fa5c5d2..a6cbbdc2 100755 --- a/Tests/Functional/BasePaymentWorkflowTest.php +++ b/Tests/Functional/BasePaymentWorkflowTest.php @@ -35,7 +35,7 @@ protected function doTestPaymentDetails() $crawler = $client->request('GET', $router->generate('payment_details', array('id' => $order->getId()))); $form = $crawler->selectButton('submit_btn')->form(); - $form['jms_choose_payment_method[method]']->select('paypal_express_checkout'); + $form['jms_choose_payment_method[method]']->select('test_plugin'); $client->submit($form); $response = $client->getResponse(); diff --git a/Tests/Functional/BasicEntityInteractionsTest.php b/Tests/Functional/BasicEntityInteractionsTest.php index 0f9edea1..c48d4866 100644 --- a/Tests/Functional/BasicEntityInteractionsTest.php +++ b/Tests/Functional/BasicEntityInteractionsTest.php @@ -17,7 +17,7 @@ public function testIndependentCredit() $c = self::$kernel->getContainer(); $ppc = $c->get('payment.plugin_controller'); $em = $c->get('doctrine.orm.entity_manager'); - $instruction = new PaymentInstruction(123.45, 'EUR', 'paypal_express_checkout'); + $instruction = new PaymentInstruction(123.45, 'EUR', 'test_plugin'); $ppc->createPaymentInstruction($instruction); $credit = $ppc->createIndependentCredit($instruction->getId(), 123); diff --git a/Tests/Functional/TestBundle/Controller/OrderController.php b/Tests/Functional/TestBundle/Controller/OrderController.php index ffdb0ac4..06ed6a6d 100755 --- a/Tests/Functional/TestBundle/Controller/OrderController.php +++ b/Tests/Functional/TestBundle/Controller/OrderController.php @@ -33,7 +33,7 @@ public function paymentDetailsAction(Order $order) 'currency' => 'EUR', 'amount' => $order->getAmount(), 'predefined_data' => array( - 'paypal_express_checkout' => array( + 'test_plugin' => array( 'foo' => 'bar', ), ), diff --git a/Tests/Functional/TestBundle/Resources/config/default.yml b/Tests/Functional/TestBundle/Resources/config/default.yml index ae8f3662..e17a56e0 100644 --- a/Tests/Functional/TestBundle/Resources/config/default.yml +++ b/Tests/Functional/TestBundle/Resources/config/default.yml @@ -11,10 +11,3 @@ doctrine: services: em: "@doctrine.orm.entity_manager" - -jms_payment_paypal: - username: schmit_1283340315_biz_api1.gmail.com - password: 1283340321 - signature: A93vj6VJ.ZIRNjbI6GFgi4N2Km.5ATLs-EinlyWk2htEGX0xc3L8YIBo - return_url: http://paypal.test/payment - cancel_url: http://paypal.test/payment diff --git a/Tests/Functional/TestPlugin/DependencyInjection/TestPluginExtension.php b/Tests/Functional/TestPlugin/DependencyInjection/TestPluginExtension.php new file mode 100644 index 00000000..636060b5 --- /dev/null +++ b/Tests/Functional/TestPlugin/DependencyInjection/TestPluginExtension.php @@ -0,0 +1,17 @@ +load('services.yml'); + } +} \ No newline at end of file diff --git a/Tests/Functional/TestPlugin/Form/TestPluginType.php b/Tests/Functional/TestPlugin/Form/TestPluginType.php new file mode 100644 index 00000000..cc232a0a --- /dev/null +++ b/Tests/Functional/TestPlugin/Form/TestPluginType.php @@ -0,0 +1,17 @@ +