Skip to content

Commit

Permalink
Merge pull request #1113 from buckaroo-it/BP-3689-Add-CSP-Content-Sec…
Browse files Browse the repository at this point in the history
…urity-Policy-improvements

Bp 3689 add csp content security policy improvements
  • Loading branch information
vegimcarkaxhija authored Dec 3, 2024
2 parents f33b491 + 60d6eaf commit f8a1430
Show file tree
Hide file tree
Showing 12 changed files with 280 additions and 19 deletions.
10 changes: 10 additions & 0 deletions Block/Cart/BuckarooConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,14 @@ public function getBuckarooConfigJson()
$configProvider = $this->configProviderFactory->get('buckaroo_fee');
return $this->jsonEncoder->serialize($configProvider->getConfig());
}

/**
* Get CSP nonce
*
* @return string
*/
public function getCspNonce()
{
return $this->getData('cspNonce') ?: '';
}
}
12 changes: 11 additions & 1 deletion Block/Checkout/Success.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class Success extends \Magento\Checkout\Block\Onepage\Success
protected $currentCustomer;

/**
* @param Template\Context $context
* @param \Magento\Framework\View\Element\Template\Context $context
* @param \Magento\Checkout\Model\Session $checkoutSession
* @param \Magento\Sales\Model\Order\Config $orderConfig
* @param \Magento\Framework\App\Http\Context $httpContext
Expand All @@ -52,4 +52,14 @@ public function __construct(
);
$this->currentCustomer = $currentCustomer;
}

/**
* Get CSP nonce
*
* @return string
*/
public function getCspNonce()
{
return $this->getData('cspNonce') ?: '';
}
}
63 changes: 63 additions & 0 deletions Factory/CspNonceProviderFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php
declare(strict_types=1);

namespace Buckaroo\Magento2\Factory;

use Magento\Framework\ObjectManagerInterface;
use Magento\Csp\Helper\CspNonceProvider as MagentoCspNonceProvider;
use Buckaroo\Magento2\Helper\CustomCspNonceProvider;
use Psr\Log\LoggerInterface;

/**
* Factory to provide the appropriate CspNonceProvider
*/
class CspNonceProviderFactory
{
/**
* @var ObjectManagerInterface
*/
private ObjectManagerInterface $objectManager;

/**
* @var LoggerInterface
*/
private LoggerInterface $logger;

public function __construct(
ObjectManagerInterface $objectManager,
LoggerInterface $logger
) {
$this->objectManager = $objectManager;
$this->logger = $logger;
}

/**
* Create an instance of CspNonceProvider
*
* @return MagentoCspNonceProvider|CustomCspNonceProvider|null
*/
public function create()
{
// Attempt to use Magento's CspNonceProvider if it exists
if (class_exists(MagentoCspNonceProvider::class)) {
try {
return $this->objectManager->get(MagentoCspNonceProvider::class);
} catch (\Exception $e) {
$this->logger->error('Failed to instantiate Magento CspNonceProvider: ' . $e->getMessage());
}
}

// Fallback to custom CspNonceProvider
if (class_exists(CustomCspNonceProvider::class)) {
try {
return $this->objectManager->get(CustomCspNonceProvider::class);
} catch (\Exception $e) {
$this->logger->error('Failed to instantiate Custom CspNonceProvider: ' . $e->getMessage());
}
}

// If neither class is available, log a warning
$this->logger->warning('No CspNonceProvider available.');
return null;
}
}
63 changes: 63 additions & 0 deletions Helper/CustomCspNonceProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php
declare(strict_types=1);

namespace Buckaroo\Magento2\Helper;

use Magento\Framework\Math\Random;
use Magento\Framework\Exception\LocalizedException;
use Magento\Csp\Model\Collector\DynamicCollector;
use Magento\Csp\Model\Policy\FetchPolicy;

/**
* Custom CSP Nonce Provider for Magento versions without Magento\Csp\Helper\CspNonceProvider
*/
class CustomCspNonceProvider
{
private const NONCE_LENGTH = 32;

private string $nonce;

private Random $random;

private DynamicCollector $dynamicCollector;

public function __construct(
Random $random,
DynamicCollector $dynamicCollector
) {
$this->random = $random;
$this->dynamicCollector = $dynamicCollector;
}

/**
* Generate nonce and add it to the CSP header
*
* @return string
* @throws LocalizedException
*/
public function generateNonce(): string
{
if (empty($this->nonce)) {
$this->nonce = $this->random->getRandomString(
self::NONCE_LENGTH,
Random::CHARS_DIGITS . Random::CHARS_LOWERS
);

$policy = new FetchPolicy(
'script-src',
false,
[],
[],
false,
false,
false,
[$this->nonce],
[]
);

$this->dynamicCollector->add($policy);
}

return base64_encode($this->nonce);
}
}
46 changes: 46 additions & 0 deletions Observer/AddCspNonce.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php declare(strict_types=1);

namespace Buckaroo\Magento2\Observer;

use Magento\Framework\Event\Observer;
use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\View\Element\Template;
use Buckaroo\Magento2\Factory\CspNonceProviderFactory;

class AddCspNonce implements ObserverInterface
{
/**
* @var \Magento\Csp\Helper\CspNonceProvider|\Buckaroo\Magento2\Helper\CustomCspNonceProvider|null
*/
private $cspNonceProvider;

public function __construct(
CspNonceProviderFactory $cspNonceProviderFactory
) {
$this->cspNonceProvider = $cspNonceProviderFactory->create();
}

public function execute(Observer $observer)
{
/** @var Template $block */
$block = $observer->getEvent()->getBlock();
if (false === $block instanceof Template) {
return;
}

// Retrieve the block name
$nameInLayout = $block->getNameInLayout();
// Check if $nameInLayout is a non-empty string
if (!is_string($nameInLayout) || strpos($nameInLayout, 'buckaroo_magento2') === false) {
return;
}

if ($this->cspNonceProvider) {
try {
$nonce = $this->cspNonceProvider->generateNonce();
$block->assign('cspNonce', $nonce);
} catch (\Exception $e) {
}
}
}
}
26 changes: 26 additions & 0 deletions etc/frontend/events.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0"?>
<!--
/**
* NOTICE OF LICENSE
*
* This source file is subject to the MIT License
* It is available through the world-wide-web at this URL:
* https://tldrlegal.com/license/mit-license
* If you are unable to obtain it through the world-wide-web, please send an email
* to [email protected] so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade this module to newer
* versions in the future. If you wish to customize this module for your
* needs please contact [email protected] for more information.
*
* @copyright Copyright (c) Buckaroo B.V.
* @license https://tldrlegal.com/license/mit-license
*/
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
<event name="view_block_abstract_to_html_before">
<observer name="buckaroo_magento2_update_order_status" instance="Buckaroo\Magento2\Observer\AddCspNonce" />
</event>
</config>
4 changes: 3 additions & 1 deletion view/frontend/templates/cart/buckaroo_config.phtml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@
* @copyright Copyright (c) Buckaroo B.V.
* @license https://tldrlegal.com/license/mit-license
*/

/** @var string $cspNonce */
?>
<div id="buckaroo-fee-cart" data-bind="scope:'buckarooFeeCart'">
<!-- ko template: getTemplate() --><!-- /ko -->
<script>
<script nonce="<?= $block->getCspNonce() ?>">
window.buckarooConfig = <?= /* @noEscape */ $block->getBuckarooConfigJson(); ?>;
</script>
</div>
4 changes: 3 additions & 1 deletion view/frontend/templates/catalog/product/view/applepay.phtml
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@
* @copyright Copyright (c) Buckaroo B.V.
* @license https://tldrlegal.com/license/mit-license
*/

/** @var string $cspNonce */
?>
<?php if ($block->canShowButton('Product')): ?>
<div id="apple-pay-catalog-product-view-component" data-bind="scope:'applepayproductcomponent'">
<!-- ko template: getTemplate() --><!-- /ko -->

<script>
<script nonce="<?= $cspNonce ?>">
if ('undefined' === typeof window.checkoutConfig) {
window.checkoutConfig = <?= /* @noEscape */ ($block->getApplepayConfig()); ?>;
window.isCustomerLoggedIn = window.checkoutConfig.isCustomerLoggedIn;
Expand Down
3 changes: 2 additions & 1 deletion view/frontend/templates/checkout/cart/paypal-express.phtml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
* @copyright Copyright (c) Buckaroo B.V.
* @license https://tldrlegal.com/license/mit-license
*/
/** @var string $cspNonce */
?>
<?php if ($block->canShowButton('Cart')) : ?>
<div class="box-tocart">
Expand All @@ -29,7 +30,7 @@
</div>
<div class="buckaroo-paypal-express"></div>

<script>
<script nonce="<?= $cspNonce ?>">
showPaypalExpressButton = function() {
require(['jquery', 'buckaroo/paypal-express/pay'], function(jQuery, paypalExpressPay) {
paypalExpressPay.setConfig(<?= /* @noEscape */ json_encode($block->getConfig()); ?>, 'cart');
Expand Down
32 changes: 25 additions & 7 deletions view/frontend/templates/checkout/mrcash/pay.phtml
Original file line number Diff line number Diff line change
@@ -1,3 +1,25 @@
<?php
/**
* NOTICE OF LICENSE
*
* This source file is subject to the MIT License
* It is available through the world-wide-web at this URL:
* https://tldrlegal.com/license/mit-license
* If you are unable to obtain it through the world-wide-web, please send an email
* to support@buckaroo.nl so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade this module to newer
* versions in the future. If you wish to customize this module for your
* needs please contact support@buckaroo.nl for more information.
*
* @copyright Copyright (c) Buckaroo B.V.
* @license https://tldrlegal.com/license/mit-license
*/

/** @var string $cspNonce */
?>
<div id="buckaroo_magento2_payconiq_loader" class="loading-mask"></div>

<div id="buckaroo_magento2_payconiq_container">
Expand All @@ -13,11 +35,9 @@
</div>
</div>

<?php
$key = $block->getTransactionKey();
$script = <<<JS
<script nonce="<?= $cspNonce ?>">
require(['buckaroo/mrcash/pay'], function (mrcashPay) {
var transactionKey = "$key";
var transactionKey = "<?= /* @noEscape */ ($block->getTransactionKey()); ?>";

mrcashPay.setTransactionKey(transactionKey);
mrcashPay.showQrCode();
Expand All @@ -27,6 +47,4 @@
mrcashPay.cancelPayment();
});
}
JS;
?>
<?= /* @noEscape */ $secureRenderer->renderTag('script', [], $script, false); ?>
</script>
32 changes: 25 additions & 7 deletions view/frontend/templates/checkout/payconiq/pay.phtml
Original file line number Diff line number Diff line change
@@ -1,3 +1,25 @@
<?php
/**
* NOTICE OF LICENSE
*
* This source file is subject to the MIT License
* It is available through the world-wide-web at this URL:
* https://tldrlegal.com/license/mit-license
* If you are unable to obtain it through the world-wide-web, please send an email
* to support@buckaroo.nl so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade this module to newer
* versions in the future. If you wish to customize this module for your
* needs please contact support@buckaroo.nl for more information.
*
* @copyright Copyright (c) Buckaroo B.V.
* @license https://tldrlegal.com/license/mit-license
*/

/** @var string $cspNonce */
?>
<div id="buckaroo_magento2_payconiq_loader" class="loading-mask"></div>

<div id="buckaroo_magento2_payconiq_container">
Expand All @@ -10,11 +32,9 @@
</div>
</div>

<?php
$key = $block->getTransactionKey();
$script = <<<JS
<script nonce="<?= $cspNonce ?>">
require(['buckaroo/payconiq/pay'], function (payconiqPay) {
var transactionKey = "$key";
var transactionKey = "<?= /* @noEscape */ $block->getTransactionKey(); ?>";

payconiqPay.setTransactionKey(transactionKey);
payconiqPay.showQrCode();
Expand All @@ -24,6 +44,4 @@
payconiqPay.cancelPayment();
});
}
JS;
?>
<?= /* @noEscape */ $secureRenderer->renderTag('script', [], $script, false); ?>
</script>
4 changes: 3 additions & 1 deletion view/frontend/templates/checkout/success.phtml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@
* @copyright Copyright (c) Buckaroo B.V.
* @license https://tldrlegal.com/license/mit-license
*/

/** @var string $cspNonce */
?>
<script>
<script nonce="<?= $block->getCspNonce() ?>">
window.onload = function(){
require(['Magento_Customer/js/customer-data'], function (customerData) {
var sections = ['cart'];
Expand Down

0 comments on commit f8a1430

Please sign in to comment.