diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index b984ed5..36c1d33 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -86,6 +86,15 @@ public function getConfigTreeBuilder() ->scalarNode('signature_name')->default('Sign')->end() ->end() ->end() + ->enumNode('validation_by') + ->values(array('url_ipn', 'pbx_retour')) + ->cannotBeEmpty() + ->defaultValue('url_ipn') + ->info("Define the method for IPN validation. Select 'pbx_retour' only if you use 'PBX_REPONSE_A' option.") + ->end() + ->scalarNode('pbx_retour') + ->info("PBX_RETOUR option for validation by 'pbx_retour'") + ->end() ->end() ->end() diff --git a/DependencyInjection/LexikPayboxExtension.php b/DependencyInjection/LexikPayboxExtension.php index 2fdc7da..d9cda45 100644 --- a/DependencyInjection/LexikPayboxExtension.php +++ b/DependencyInjection/LexikPayboxExtension.php @@ -6,6 +6,7 @@ use Symfony\Component\Config\FileLocator; use Symfony\Component\HttpKernel\DependencyInjection\Extension; use Symfony\Component\DependencyInjection\Loader; +use Lexik\Bundle\PayboxBundle\Paybox\Paybox; /** * This is the class that loads and manages your bundle configuration @@ -33,6 +34,28 @@ public function load(array $configs, ContainerBuilder $container) $config['parameters']['public_key'] = __DIR__ . '/../Resources/config/paybox_public_key.pem'; } + if('pbx_retour' == $config['parameters']['validation_by']){ + if(!isset($config['parameters']['pbx_retour']) || !$config['parameters']['pbx_retour']){ + throw new \InvalidArgumentException( + 'The "pbx_retour" option must be set for validation_by "pbx_retour"' + ); + }else{ + // if PXB_REPONDRE_A is used the signature only sign parameter from PBX_RETOUR without 'Sign' parameter + $param_signed = explode(';', $config['parameters']['pbx_retour']); + $param_signed = array_map(function($param){ + return substr($param, 0, strpos($param, ':')); + }, $param_signed); + $param_signed = array_diff($param_signed, array(Paybox::SIGNATURE_PARAMETER)); + + $container->setParameter('lexik_paybox.pbx_retour', $param_signed); + } + }else{ + $container->setParameter('lexik_paybox.pbx_retour', null); + } + $container->setParameter('lexik_paybox.public_key', $config['parameters']['public_key']); + $container->setParameter('lexik_paybox.validation_by', $config['parameters']['validation_by']); + + } } diff --git a/Paybox/System/Base/Response.php b/Paybox/System/Base/Response.php index 223bdf8..36de87b 100644 --- a/Paybox/System/Base/Response.php +++ b/Paybox/System/Base/Response.php @@ -47,6 +47,7 @@ class Response */ private $parameters; + /** * Contructor. * @@ -113,7 +114,13 @@ protected function initData() foreach ($this->getRequestParameters() as $key => $value) { $this->logger->info(sprintf('%s=%s', $key, $value)); - if ($this->parameters['hmac']['signature_name'] !== $key) { + if($this->parameters['hmac']['signature_name'] == $key){ + continue; + } + + if ('url_ipn' == $this->parameters['validation_by']) { + $this->data[$key] = urlencode($value); + } elseif (in_array($key, $this->parameters['pbx_retour'])) { $this->data[$key] = urlencode($value); } } @@ -131,10 +138,7 @@ public function verifySignature() $this->initData(); $this->initSignature(); - $file = fopen($this->parameters['public_key'], 'r'); - $cert = fread($file, 8192); - fclose($file); - + $cert = file_get_contents($this->parameters['public_key']); $publicKey = openssl_get_publickey($cert); $result = openssl_verify( @@ -163,4 +167,5 @@ public function verifySignature() return $result; } + } diff --git a/README.md b/README.md index 5114b66..1ead66c 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,7 @@ lexik_paybox: hmac: algorithm: sha512 # signature algorithm signature_name: Sign # customize the signature parameter name + validation_by: url_ipn ``` The routing collection must be set in your routing.yml @@ -223,6 +224,31 @@ Production By default, getUrl() returns the preproduction url. To toggle in production, you just need to specify 'prod' in parameter of the getUrl('prod') method. +Validation IPN response +----------------------- + +For security, the status returned by PBX_EFFECTUE, PBX_REFUSE, PBX_ANNULE and PBX_ATTENTE, should +not be trusted as it can by altered by malicous user. You must instead use IPN notification. +IPN notification is send directly from Paybox server to the URL you specified either in PBX_REPONDRE_A +option or in Paybox interface. + +If you use PBX_REPONDRE_A option you must specify in your `config.yml` file the following parameters : + +```yml +lexik_paybox: + parameters: + validation_by: pbx_retour + pbx_retour: Mt:M;Ref:R;Auto:A;Erreur:E # report the PBX_RETOUR option you defined in your code +``` + +If you use the Paybox interface, you can let the default parameters : + +```yml +lexik_paybox: + parameters: + validation_by: url_ipn +``` + Resources --------- diff --git a/Tests/Paybox/System/ResponseTest.php b/Tests/Paybox/System/ResponseTest.php index 9545c39..ae93991 100644 --- a/Tests/Paybox/System/ResponseTest.php +++ b/Tests/Paybox/System/ResponseTest.php @@ -51,6 +51,7 @@ protected function initMock(array $parameters, array $messages) 'hmac' => array( 'signature_name' => 'Sign', ), + 'validation_by' => 'url_ipn', ); $this->_response = new Response($request, $logger, $dispatcher, $parameters);