Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: HMAC verification on IPN callback for security #561

Merged
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion alma/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
},
"require": {
"php": "^5.6 || ~7.0 || ~7.1 || ~7.2 || ~7.3 || ~7.4 || ~8.0 || ~8.1",
"alma/alma-php-client": "^2.1.0",
"alma/alma-php-client": "^2.2.0",
"ext-json": "*",
"ext-openssl": "*",
"prestashop/prestashop-accounts-installer": "^v1.0.4",
Expand Down
27 changes: 22 additions & 5 deletions alma/controllers/front/ipn.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
*/

use Alma\PrestaShop\API\MismatchException;
use Alma\PrestaShop\Exceptions\RefundException;
use Alma\PrestaShop\Builders\Validators\PaymentValidationBuilder;
use Alma\PrestaShop\Exceptions\PaymentValidationException;
use Alma\PrestaShop\Logger;
use Alma\PrestaShop\Traits\AjaxTrait;
use Alma\PrestaShop\Validators\PaymentValidation;
Expand All @@ -40,8 +41,21 @@ class AlmaIpnModuleFrontController extends ModuleFrontController
{
use AjaxTrait;

/**
* @var bool
*/
public $ssl = true;
Francois-Gomis marked this conversation as resolved.
Show resolved Hide resolved

/**
* @var Context
*/
public $context;

/**
* @var PaymentValidation
Francois-Gomis marked this conversation as resolved.
Show resolved Hide resolved
*/
protected $paymentValidation;

/**
* IPN constructor
*
Expand All @@ -51,14 +65,14 @@ public function __construct()
{
parent::__construct();
$this->context = Context::getContext();
Francois-Gomis marked this conversation as resolved.
Show resolved Hide resolved
$paymentValidationBuilder = new PaymentValidationBuilder();
$this->paymentValidation = $paymentValidationBuilder->getInstance();
}

/**
* @return void
*
* @throws PrestaShopException
* @throws RefundException
* @throws MismatchException
*/
public function postProcess()
{
Expand All @@ -67,10 +81,13 @@ public function postProcess()
header('Content-Type: application/json');

$paymentId = Tools::getValue('pid');
$validator = new PaymentValidation($this->context, $this->module);

try {
$validator->validatePayment($paymentId);
$this->paymentValidation->checkSignature($paymentId, Configuration::get('ALMA_API_KEY'), $_SERVER['HTTP_X_ALMA_SIGNATURE']);
$this->paymentValidation->validatePayment($paymentId);
} catch (PaymentValidationException $e) {
Logger::instance()->error('[Alma] IPN Payment Validation Error - Message : ' . $e->getMessage());
$this->ajaxRenderAndExit(json_encode(['error' => $e->getMessage()]), 500);
} catch (PaymentValidationError $e) {
Logger::instance()->error('ipn payment_validation_error - Message : ' . $e->getMessage());
$this->ajaxRenderAndExit(json_encode(['error' => $e->getMessage()]), 500);
Expand Down
43 changes: 43 additions & 0 deletions alma/exceptions/PaymentValidationException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php
/**
* 2018-2024 Alma SAS.
*
* THE MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* @author Alma SAS <[email protected]>
* @copyright 2018-2024 Alma SAS
* @license https://opensource.org/licenses/MIT The MIT License
*/

namespace Alma\PrestaShop\Exceptions;

if (!defined('_PS_VERSION_')) {
exit;
}

class PaymentValidationException extends AlmaException
{
/**
* @var \Cart
*/
public $cart;
Francois-Gomis marked this conversation as resolved.
Show resolved Hide resolved

public function __construct($cart = null, $message = '', $code = 0, $previous = null)
{
parent::__construct($message, $code, $previous);
$this->cart = $cart;
}
}
52 changes: 52 additions & 0 deletions alma/lib/Builders/Validators/PaymentValidationBuilder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php
/**
* 2018-2024 Alma SAS.
*
* THE MIT LICENSE
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* @author Alma SAS <[email protected]>
* @copyright 2018-2024 Alma SAS
* @license https://opensource.org/licenses/MIT The MIT License
*/

namespace Alma\PrestaShop\Builders\Validators;

use Alma\PrestaShop\Traits\BuilderTrait;
use Alma\PrestaShop\Validators\PaymentValidation;

if (!defined('_PS_VERSION_')) {
exit;
}

/**
* PaymentValidationBuilder.
*/
class PaymentValidationBuilder
{
use BuilderTrait;

/**
* @return PaymentValidation
*/
public function getInstance()
{
return new PaymentValidation(
$this->getContextFactory(),
$this->getModuleFactory(),
$this->getClientPaymentValidator()
);
}
}
2 changes: 0 additions & 2 deletions alma/lib/Helpers/ShareOfCheckoutHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,6 @@ public function isSocActivated()
|| empty($shareOfCheckoutEnabledDate)
|| !$this->dateHelper->isValidTimeStamp($shareOfCheckoutEnabledDate)
) {
Logger::instance()->info('Share Of Checkout is disabled or invalide date');

return false;
}

Expand Down
15 changes: 15 additions & 0 deletions alma/lib/Traits/BuilderTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

namespace Alma\PrestaShop\Traits;

use Alma\API\Lib\PaymentValidator;
use Alma\PrestaShop\Factories\AddressFactory;
use Alma\PrestaShop\Factories\CarrierFactory;
use Alma\PrestaShop\Factories\CartFactory;
Expand Down Expand Up @@ -1202,4 +1203,18 @@ public function getInsuranceApiService($insuranceApiService = null)

return new InsuranceApiService();
}

/**
* @param PaymentValidator $clientPaymentValidator
*
* @return PaymentValidator
*/
public function getClientPaymentValidator($clientPaymentValidator = null)
{
if ($clientPaymentValidator) {
Benjamin-Freoua-Alma marked this conversation as resolved.
Show resolved Hide resolved
return $clientPaymentValidator;
}

return new PaymentValidator();
}
}
42 changes: 39 additions & 3 deletions alma/lib/Validators/PaymentValidation.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@
namespace Alma\PrestaShop\Validators;

use Alma\API\Entities\Payment;
use Alma\API\Lib\PaymentValidator;
use Alma\API\RequestError;
use Alma\PrestaShop\API\MismatchException;
use Alma\PrestaShop\Builders\Helpers\PriceHelperBuilder;
use Alma\PrestaShop\Builders\Helpers\SettingsHelperBuilder;
use Alma\PrestaShop\Builders\Services\OrderServiceBuilder;
use Alma\PrestaShop\Exceptions\PaymentValidationException;
use Alma\PrestaShop\Helpers\ClientHelper;
use Alma\PrestaShop\Helpers\PriceHelper;
use Alma\PrestaShop\Helpers\RefundHelper;
Expand Down Expand Up @@ -68,15 +70,23 @@ class PaymentValidation
* @var OrderService
*/
protected $orderService;
/**
* @var PaymentValidator
*/
protected $paymentValidator;

/**
* @param $context
* @param $module
*/
public function __construct($context, $module)
{
public function __construct(
$context,
$module,
$clientPaymentValidator
) {
$this->context = $context;
$this->module = $module;
$this->paymentValidator = $clientPaymentValidator;

$settingsHelperBuilder = new SettingsHelperBuilder();
$this->settingsHelper = $settingsHelperBuilder->getInstance();
Expand Down Expand Up @@ -312,6 +322,9 @@ public function validatePayment($almaPaymentId)
* @param $cartId
*
* @return \OrderCore|null
*
* @throws \PrestaShopDatabaseException
* @throws \PrestaShopException
*/
private function getOrderByCartId($cartId)
Benjamin-Freoua-Alma marked this conversation as resolved.
Show resolved Hide resolved
{
Expand All @@ -330,7 +343,7 @@ private function getOrderByCartId($cartId)
* When calculating cart amount from an IPN call.
*
* @param \Cart $cart
* @param \Customer $cart
* @param \Customer $customer
*
* @return float
*/
Expand All @@ -347,4 +360,27 @@ private function getCartTotals($cart, $customer)

return $cartTotals;
}

/**
* @param string $paymentId
* @param string $apiKey
* @param string $signature
*
* @throws PaymentValidationException
*/
public function checkSignature($paymentId, $apiKey, $signature)
{
if (!$paymentId) {
Benjamin-Freoua-Alma marked this conversation as resolved.
Show resolved Hide resolved
throw new PaymentValidationException(null, '[Alma] Payment ID is missing');
}
if (!$apiKey) {
throw new PaymentValidationException(null, '[Alma] Api key is missing');
}
if (!$signature) {
throw new PaymentValidationException(null, '[Alma] Signature is missing');
}
if (!$this->paymentValidator->isHmacValidated($paymentId, $apiKey, $signature)) {
throw new PaymentValidationException(null, '[Alma] Signature is invalid');
}
}
}
5 changes: 5 additions & 0 deletions alma/lib/Validators/PaymentValidationError.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@
exit;
}

/**
* Class PaymentValidationError.
*
* @deprecated Use PaymentValidationException instead
*/
class PaymentValidationError extends \Exception
{
public $cart;
Expand Down
Loading