diff --git a/app/code/Magento/Authorizenet/view/adminhtml/templates/directpost/info.phtml b/app/code/Magento/Authorizenet/view/adminhtml/templates/directpost/info.phtml
index f60bbe670a3e3..25dd6cca9f8eb 100644
--- a/app/code/Magento/Authorizenet/view/adminhtml/templates/directpost/info.phtml
+++ b/app/code/Magento/Authorizenet/view/adminhtml/templates/directpost/info.phtml
@@ -40,9 +40,9 @@ $ccExpYear = $block->getInfoData('cc_exp_year');
'validate-cc-type-select':'#= /* @noEscape */ $code ?>_cc_number'
}">
= $block->escapeHtml(__('Please Select')) ?>
- getCcAvailableTypes() as $typeCode => $typeName) : ?>
+ getCcAvailableTypes() as $typeCode => $typeName): ?>
selected="selected">
+ selected="selected">
= $block->escapeHtml($typeName) ?>
@@ -57,6 +57,9 @@ $ccExpYear = $block->getInfoData('cc_exp_year');
+
= $block->escapeHtml(__('Please enter the letters and numbers from the image')) ?>
@@ -18,11 +21,13 @@ $captcha = $block->getCaptchaModel();
id="captcha"
class="admin__control-text"
type="text"
- name="= $block->escapeHtmlAttr(\Magento\Captcha\Helper\Data::INPUT_NAME_FIELD_VALUE) ?>[= $block->escapeHtml($block->getFormId()) ?>]"
- data-validate="{required:true}"/>
- isCaseSensitive()) :?>
+ name="= /** @noEscape */ $name ?>[= $block->escapeHtmlAttr($block->getFormId()) ?>]"
+ data-validate="{required:true}"/>
+ isCaseSensitive()): ?>
- = $block->escapeHtml(__('Attention : Captcha is case sensitive.'), ['strong']) ?>
+
+ = $block->escapeHtml(__('Attention : Captcha is case sensitive.'), ['strong']) ?>
+
@@ -43,7 +48,10 @@ $captcha = $block->getCaptchaModel();
require(["prototype", "mage/captcha"], function(){
//escapeJs($block->escapeUrl($block->getRefreshUrl())) ?>', '= $block->escapeJs($block->escapeHtml($block->getFormId())) ?>');
+ var captcha = new Captcha(
+ '= $block->escapeJs($block->getRefreshUrl()) ?>',
+ '= $block->escapeJs($block->getFormId()) ?>'
+ );
$('captcha-reload').observe('click', function () {
captcha.refresh(this);
diff --git a/app/code/Magento/Captcha/view/frontend/templates/default.phtml b/app/code/Magento/Captcha/view/frontend/templates/default.phtml
index ead8c590eee94..0d436cc62b790 100644
--- a/app/code/Magento/Captcha/view/frontend/templates/default.phtml
+++ b/app/code/Magento/Captcha/view/frontend/templates/default.phtml
@@ -8,27 +8,46 @@
/** @var \Magento\Captcha\Model\DefaultModel $captcha */
$captcha = $block->getCaptchaModel();
+/** @var bool $validationEnabled */
+$validationEnabled = $block->hasData('frontend_validation') ? $block->getData('frontend_validation') : true;
+$inputName = $block->escapeHtmlAttr(\Magento\Captcha\Helper\Data::INPUT_NAME_FIELD_VALUE);
+$loaderUrl = $block->escapeUrl($block->getViewFileUrl('images/loader-2.gif'));
+$note = $block->escapeHtml(__('
Attention : Captcha is case sensitive.'), ['strong']);
?>
-
-
= $block->escapeHtml(__('Please type the letters and numbers below')) ?>
+
+
+ = $block->escapeHtml(__('Please type the letters and numbers below')) ?>
+
-
+
data-validate="{required:true}"
+ id="captcha_= $block->escapeHtmlAttr($block->getFormId()) ?>"
+ autocomplete="off"/>
- isCaseSensitive()) :?>
-
- = $block->escapeHtml(__('Attention : Captcha is case sensitive.'), ['strong']) ?>
-
+ isCaseSensitive()):?>
+
= /* @noEscape */ $note ?>
diff --git a/app/code/Magento/Checkout/Api/Exception/PaymentProcessingRateLimitExceededException.php b/app/code/Magento/Checkout/Api/Exception/PaymentProcessingRateLimitExceededException.php
index e398bf400391b..018c18112a763 100644
--- a/app/code/Magento/Checkout/Api/Exception/PaymentProcessingRateLimitExceededException.php
+++ b/app/code/Magento/Checkout/Api/Exception/PaymentProcessingRateLimitExceededException.php
@@ -11,7 +11,7 @@
use Magento\Framework\Exception\LocalizedException;
/**
- * Thrown when too many payment processing requests have been initiated by a user.
+ * Thrown when too many payment processing/saving requests have been initiated by a user.
*/
class PaymentProcessingRateLimitExceededException extends LocalizedException
{
diff --git a/app/code/Magento/Checkout/Api/PaymentSavingRateLimiterInterface.php b/app/code/Magento/Checkout/Api/PaymentSavingRateLimiterInterface.php
new file mode 100644
index 0000000000000..c964029ff8b3a
--- /dev/null
+++ b/app/code/Magento/Checkout/Api/PaymentSavingRateLimiterInterface.php
@@ -0,0 +1,25 @@
+ false,
'after' => '-',
'form_id' => 'sales_rule_coupon_request',
- 'image_width' => 230,
- 'image_height' => 230
+ 'img_width' => 230,
+ 'img_height' => 50
]
);
}
diff --git a/app/code/Magento/Checkout/Model/CaptchaPaymentProcessingRateLimiter.php b/app/code/Magento/Checkout/Model/CaptchaPaymentProcessingRateLimiter.php
index 6f71423acbcaa..68860b629c246 100644
--- a/app/code/Magento/Checkout/Model/CaptchaPaymentProcessingRateLimiter.php
+++ b/app/code/Magento/Checkout/Model/CaptchaPaymentProcessingRateLimiter.php
@@ -12,42 +12,23 @@
use Magento\Checkout\Api\Exception\PaymentProcessingRateLimitExceededException;
use Magento\Checkout\Api\PaymentProcessingRateLimiterInterface;
use Magento\Customer\Api\CustomerRepositoryInterface;
-use Magento\Captcha\Model\DefaultModel as Captcha;
use Magento\Captcha\Helper\Data as CaptchaHelper;
use Magento\Captcha\Observer\CaptchaStringResolver as CaptchaResolver;
+use Magento\Framework\App\ObjectManager;
use Magento\Framework\App\RequestInterface;
+use Magento\Framework\Exception\LocalizedException;
/**
- * Utilize CAPTCHA as a rate-limiting mechanism.
+ * Utilize CAPTCHA to limit payment processing requests.
*/
class CaptchaPaymentProcessingRateLimiter implements PaymentProcessingRateLimiterInterface
{
public const CAPTCHA_FORM = 'payment_processing_request';
/**
- * @var UserContextInterface
+ * @var CaptchaRateLimiter
*/
- private $userContext;
-
- /**
- * @var CustomerRepositoryInterface
- */
- private $customerRepo;
-
- /**
- * @var CaptchaHelper
- */
- private $captchaHelper;
-
- /**
- * @var RequestInterface
- */
- private $request;
-
- /**
- * @var CaptchaResolver
- */
- private $captchaResolver;
+ private $limiter;
/**
* CaptchaPaymentProcessingRateLimiter constructor.
@@ -57,19 +38,25 @@ class CaptchaPaymentProcessingRateLimiter implements PaymentProcessingRateLimite
* @param CaptchaHelper $captchaHelper
* @param RequestInterface $request
* @param CaptchaResolver $captchaResolver
+ * @param CaptchaRateLimiterFactory|null $limiterFactory
*/
public function __construct(
UserContextInterface $userContext,
CustomerRepositoryInterface $customerRepo,
CaptchaHelper $captchaHelper,
RequestInterface $request,
- CaptchaResolver $captchaResolver
+ CaptchaResolver $captchaResolver,
+ ?CaptchaRateLimiterFactory $limiterFactory
) {
- $this->userContext = $userContext;
- $this->customerRepo = $customerRepo;
- $this->captchaHelper = $captchaHelper;
- $this->request = $request;
- $this->captchaResolver = $captchaResolver;
+ $limiterFactory = $limiterFactory ?? ObjectManager::getInstance()->get(CaptchaRateLimiterFactory::class);
+ $this->limiter = $limiterFactory->create([
+ 'userContext' => $userContext,
+ 'customerRepo' => $customerRepo,
+ 'captchaHelper' => $captchaHelper,
+ 'captchaResolver' => $captchaResolver,
+ 'request' => $request,
+ 'captchaId' => self::CAPTCHA_FORM
+ ]);
}
/**
@@ -77,47 +64,10 @@ public function __construct(
*/
public function limit(): void
{
- if ($this->userContext->getUserType() !== UserContextInterface::USER_TYPE_GUEST
- && $this->userContext->getUserType() !== UserContextInterface::USER_TYPE_CUSTOMER
- && $this->userContext->getUserType() !== null
- ) {
- return;
+ try {
+ $this->limiter->limit();
+ } catch (LocalizedException $exception) {
+ throw new PaymentProcessingRateLimitExceededException(__($exception->getMessage()), $exception);
}
-
- $login = $this->retrieveLogin();
- /** @var Captcha $captcha */
- $captcha = $this->captchaHelper->getCaptcha(self::CAPTCHA_FORM);
- /** @var PaymentProcessingRateLimitExceededException|null $exception */
- $exception = null;
- if ($captcha->isRequired($login)) {
- $value = $this->captchaResolver->resolve($this->request, self::CAPTCHA_FORM);
- if ($value && !$captcha->isCorrect($value)) {
- $exception = new PaymentProcessingRateLimitExceededException(__('Incorrect CAPTCHA'));
- } elseif (!$value) {
- $exception = new PaymentProcessingRateLimitExceededException(
- __('Please provide CAPTCHA code and try again')
- );
- }
- }
-
- $captcha->logAttempt($login);
- if ($exception) {
- throw $exception;
- }
- }
-
- /**
- * Retrieve current user login.
- *
- * @return string|null
- */
- private function retrieveLogin(): ?string
- {
- $login = null;
- if ($this->userContext->getUserId()) {
- $login = $this->customerRepo->getById($this->userContext->getUserId())->getEmail();
- }
-
- return $login;
}
}
diff --git a/app/code/Magento/Checkout/Model/CaptchaPaymentSavingRateLimiter.php b/app/code/Magento/Checkout/Model/CaptchaPaymentSavingRateLimiter.php
new file mode 100644
index 0000000000000..7d52a1a0e19a0
--- /dev/null
+++ b/app/code/Magento/Checkout/Model/CaptchaPaymentSavingRateLimiter.php
@@ -0,0 +1,55 @@
+limiter = $limiterFactory->create(['captchaId' => self::CAPTCHA_FORM]);
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function limit(): void
+ {
+ try {
+ $this->limiter->limit();
+ } catch (LocalizedException $exception) {
+ throw new PaymentProcessingRateLimitExceededException(
+ __(
+ 'Could not store billing/shipping information at the moment'
+ .' but you can proceed with the checkout'
+ ),
+ $exception
+ );
+ }
+ }
+}
diff --git a/app/code/Magento/Checkout/Model/CaptchaRateLimiter.php b/app/code/Magento/Checkout/Model/CaptchaRateLimiter.php
new file mode 100644
index 0000000000000..e643d61e82b18
--- /dev/null
+++ b/app/code/Magento/Checkout/Model/CaptchaRateLimiter.php
@@ -0,0 +1,129 @@
+userContext = $userContext;
+ $this->customerRepo = $customerRepo;
+ $this->captchaHelper = $captchaHelper;
+ $this->request = $request;
+ $this->captchaResolver = $captchaResolver;
+ $this->captchaId = $captchaId;
+ }
+
+ /**
+ * Validate CAPTCHA if necessary.
+ *
+ * @return void
+ * @throws LocalizedException
+ */
+ public function limit(): void
+ {
+ if ($this->userContext->getUserType() !== UserContextInterface::USER_TYPE_GUEST
+ && $this->userContext->getUserType() !== UserContextInterface::USER_TYPE_CUSTOMER
+ && $this->userContext->getUserType() !== null
+ ) {
+ return;
+ }
+
+ $login = $this->retrieveLogin();
+ /** @var Captcha $captcha */
+ $captcha = $this->captchaHelper->getCaptcha($this->captchaId);
+ /** @var LocalizedException|null $exception */
+ $exception = null;
+ if ($captcha->isRequired($login)) {
+ $value = $this->captchaResolver->resolve($this->request, $this->captchaId);
+ if ($value && !$captcha->isCorrect($value)) {
+ $exception = new LocalizedException(__('Incorrect CAPTCHA'));
+ } elseif (!$value) {
+ $exception = new LocalizedException(
+ __('Please provide CAPTCHA code and try again')
+ );
+ }
+ }
+
+ $captcha->logAttempt($login);
+ if ($exception) {
+ throw $exception;
+ }
+ }
+
+ /**
+ * Retrieve current user login.
+ *
+ * @return string|null
+ */
+ private function retrieveLogin(): ?string
+ {
+ $login = null;
+ if ($this->userContext->getUserId()) {
+ $login = $this->customerRepo->getById($this->userContext->getUserId())->getEmail();
+ }
+
+ return $login;
+ }
+}
diff --git a/app/code/Magento/Checkout/Model/GuestPaymentInformationManagement.php b/app/code/Magento/Checkout/Model/GuestPaymentInformationManagement.php
index 2b2824213df79..0ca398b73a08b 100644
--- a/app/code/Magento/Checkout/Model/GuestPaymentInformationManagement.php
+++ b/app/code/Magento/Checkout/Model/GuestPaymentInformationManagement.php
@@ -7,7 +7,9 @@
namespace Magento\Checkout\Model;
+use Magento\Checkout\Api\Exception\PaymentProcessingRateLimitExceededException;
use Magento\Checkout\Api\PaymentProcessingRateLimiterInterface;
+use Magento\Checkout\Api\PaymentSavingRateLimiterInterface;
use Magento\Framework\App\ObjectManager;
use Magento\Quote\Api\CartRepositoryInterface;
use Magento\Framework\Exception\CouldNotSaveException;
@@ -61,6 +63,16 @@ class GuestPaymentInformationManagement implements \Magento\Checkout\Api\GuestPa
*/
private $paymentsRateLimiter;
+ /**
+ * @var PaymentSavingRateLimiterInterface
+ */
+ private $savingRateLimiter;
+
+ /**
+ * @var bool
+ */
+ private $saveRateLimitDisabled = false;
+
/**
* @param \Magento\Quote\Api\GuestBillingAddressManagementInterface $billingAddressManagement
* @param \Magento\Quote\Api\GuestPaymentMethodManagementInterface $paymentMethodManagement
@@ -69,6 +81,7 @@ class GuestPaymentInformationManagement implements \Magento\Checkout\Api\GuestPa
* @param \Magento\Quote\Model\QuoteIdMaskFactory $quoteIdMaskFactory
* @param CartRepositoryInterface $cartRepository
* @param PaymentProcessingRateLimiterInterface|null $paymentsRateLimiter
+ * @param PaymentSavingRateLimiterInterface|null $savingRateLimiter
* @codeCoverageIgnore
*/
public function __construct(
@@ -78,7 +91,8 @@ public function __construct(
\Magento\Checkout\Api\PaymentInformationManagementInterface $paymentInformationManagement,
\Magento\Quote\Model\QuoteIdMaskFactory $quoteIdMaskFactory,
CartRepositoryInterface $cartRepository,
- ?PaymentProcessingRateLimiterInterface $paymentsRateLimiter = null
+ ?PaymentProcessingRateLimiterInterface $paymentsRateLimiter = null,
+ ?PaymentSavingRateLimiterInterface $savingRateLimiter = null
) {
$this->billingAddressManagement = $billingAddressManagement;
$this->paymentMethodManagement = $paymentMethodManagement;
@@ -88,6 +102,8 @@ public function __construct(
$this->cartRepository = $cartRepository;
$this->paymentsRateLimiter = $paymentsRateLimiter
?? ObjectManager::getInstance()->get(PaymentProcessingRateLimiterInterface::class);
+ $this->savingRateLimiter = $savingRateLimiter
+ ?? ObjectManager::getInstance()->get(PaymentSavingRateLimiterInterface::class);
}
/**
@@ -99,7 +115,14 @@ public function savePaymentInformationAndPlaceOrder(
\Magento\Quote\Api\Data\PaymentInterface $paymentMethod,
\Magento\Quote\Api\Data\AddressInterface $billingAddress = null
) {
- $this->savePaymentInformation($cartId, $email, $paymentMethod, $billingAddress);
+ $this->paymentsRateLimiter->limit();
+ try {
+ //Have to do this hack because of savePaymentInformation() plugins.
+ $this->saveRateLimitDisabled = true;
+ $this->savePaymentInformation($cartId, $email, $paymentMethod, $billingAddress);
+ } finally {
+ $this->saveRateLimitDisabled = false;
+ }
try {
$orderId = $this->cartManagement->placeOrder($cartId);
} catch (\Magento\Framework\Exception\LocalizedException $e) {
@@ -130,7 +153,14 @@ public function savePaymentInformation(
\Magento\Quote\Api\Data\PaymentInterface $paymentMethod,
\Magento\Quote\Api\Data\AddressInterface $billingAddress = null
) {
- $this->paymentsRateLimiter->limit();
+ if (!$this->saveRateLimitDisabled) {
+ try {
+ $this->savingRateLimiter->limit();
+ } catch (PaymentProcessingRateLimitExceededException $ex) {
+ //Limit reached
+ return false;
+ }
+ }
$quoteIdMask = $this->quoteIdMaskFactory->create()->load($cartId, 'masked_id');
/** @var Quote $quote */
diff --git a/app/code/Magento/Checkout/Model/PaymentInformationManagement.php b/app/code/Magento/Checkout/Model/PaymentInformationManagement.php
index a6e448ecdb87e..3b36391530c8f 100644
--- a/app/code/Magento/Checkout/Model/PaymentInformationManagement.php
+++ b/app/code/Magento/Checkout/Model/PaymentInformationManagement.php
@@ -6,7 +6,9 @@
namespace Magento\Checkout\Model;
+use Magento\Checkout\Api\Exception\PaymentProcessingRateLimitExceededException;
use Magento\Checkout\Api\PaymentProcessingRateLimiterInterface;
+use Magento\Checkout\Api\PaymentSavingRateLimiterInterface;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\Exception\CouldNotSaveException;
@@ -58,6 +60,16 @@ class PaymentInformationManagement implements \Magento\Checkout\Api\PaymentInfor
*/
private $paymentRateLimiter;
+ /**
+ * @var PaymentSavingRateLimiterInterface
+ */
+ private $saveRateLimiter;
+
+ /**
+ * @var bool
+ */
+ private $saveRateLimiterDisabled = false;
+
/**
* @param \Magento\Quote\Api\BillingAddressManagementInterface $billingAddressManagement
* @param \Magento\Quote\Api\PaymentMethodManagementInterface $paymentMethodManagement
@@ -65,6 +77,7 @@ class PaymentInformationManagement implements \Magento\Checkout\Api\PaymentInfor
* @param PaymentDetailsFactory $paymentDetailsFactory
* @param \Magento\Quote\Api\CartTotalRepositoryInterface $cartTotalsRepository
* @param PaymentProcessingRateLimiterInterface|null $paymentRateLimiter
+ * @param PaymentSavingRateLimiterInterface|null $saveRateLimiter
* @codeCoverageIgnore
*/
public function __construct(
@@ -73,7 +86,8 @@ public function __construct(
\Magento\Quote\Api\CartManagementInterface $cartManagement,
\Magento\Checkout\Model\PaymentDetailsFactory $paymentDetailsFactory,
\Magento\Quote\Api\CartTotalRepositoryInterface $cartTotalsRepository,
- ?PaymentProcessingRateLimiterInterface $paymentRateLimiter = null
+ ?PaymentProcessingRateLimiterInterface $paymentRateLimiter = null,
+ ?PaymentSavingRateLimiterInterface $saveRateLimiter = null
) {
$this->billingAddressManagement = $billingAddressManagement;
$this->paymentMethodManagement = $paymentMethodManagement;
@@ -82,6 +96,8 @@ public function __construct(
$this->cartTotalsRepository = $cartTotalsRepository;
$this->paymentRateLimiter = $paymentRateLimiter
?? ObjectManager::getInstance()->get(PaymentProcessingRateLimiterInterface::class);
+ $this->saveRateLimiter = $saveRateLimiter
+ ?? ObjectManager::getInstance()->get(PaymentSavingRateLimiterInterface::class);
}
/**
@@ -92,7 +108,14 @@ public function savePaymentInformationAndPlaceOrder(
\Magento\Quote\Api\Data\PaymentInterface $paymentMethod,
\Magento\Quote\Api\Data\AddressInterface $billingAddress = null
) {
- $this->savePaymentInformation($cartId, $paymentMethod, $billingAddress);
+ $this->paymentRateLimiter->limit();
+ try {
+ //Have to do this hack because of plugins for savePaymentInformation()
+ $this->saveRateLimiterDisabled = true;
+ $this->savePaymentInformation($cartId, $paymentMethod, $billingAddress);
+ } finally {
+ $this->saveRateLimiterDisabled = false;
+ }
try {
$orderId = $this->cartManagement->placeOrder($cartId);
} catch (\Magento\Framework\Exception\LocalizedException $e) {
@@ -121,7 +144,14 @@ public function savePaymentInformation(
\Magento\Quote\Api\Data\PaymentInterface $paymentMethod,
\Magento\Quote\Api\Data\AddressInterface $billingAddress = null
) {
- $this->paymentRateLimiter->limit();
+ if (!$this->saveRateLimiterDisabled) {
+ try {
+ $this->saveRateLimiter->limit();
+ } catch (PaymentProcessingRateLimitExceededException $ex) {
+ //Limit reached
+ return false;
+ }
+ }
if ($billingAddress) {
/** @var \Magento\Quote\Api\CartRepositoryInterface $quoteRepository */
diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StoreFrontFreeShippingRecalculationAfterCouponCodeAddedTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StoreFrontFreeShippingRecalculationAfterCouponCodeAddedTest.xml
index d62d092e7a75e..ad000135c6bde 100644
--- a/app/code/Magento/Checkout/Test/Mftf/Test/StoreFrontFreeShippingRecalculationAfterCouponCodeAddedTest.xml
+++ b/app/code/Magento/Checkout/Test/Mftf/Test/StoreFrontFreeShippingRecalculationAfterCouponCodeAddedTest.xml
@@ -85,6 +85,7 @@
+
diff --git a/app/code/Magento/Checkout/Test/Unit/Model/GuestPaymentInformationManagementTest.php b/app/code/Magento/Checkout/Test/Unit/Model/GuestPaymentInformationManagementTest.php
index a8fd14cc433fa..53f33cd67f3cb 100644
--- a/app/code/Magento/Checkout/Test/Unit/Model/GuestPaymentInformationManagementTest.php
+++ b/app/code/Magento/Checkout/Test/Unit/Model/GuestPaymentInformationManagementTest.php
@@ -9,6 +9,7 @@
use Magento\Checkout\Api\Exception\PaymentProcessingRateLimitExceededException;
use Magento\Checkout\Api\PaymentProcessingRateLimiterInterface;
+use Magento\Checkout\Api\PaymentSavingRateLimiterInterface;
use Magento\Checkout\Model\GuestPaymentInformationManagement;
use Magento\Framework\Exception\CouldNotSaveException;
use Magento\Framework\Exception\LocalizedException;
@@ -73,6 +74,11 @@ class GuestPaymentInformationManagementTest extends TestCase
*/
private $limiterMock;
+ /**
+ * @var PaymentSavingRateLimiterInterface|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $saveLimiterMock;
+
protected function setUp(): void
{
$objectManager = new ObjectManager($this);
@@ -91,6 +97,7 @@ protected function setUp(): void
);
$this->loggerMock = $this->getMockForAbstractClass(LoggerInterface::class);
$this->limiterMock = $this->getMockForAbstractClass(PaymentProcessingRateLimiterInterface::class);
+ $this->saveLimiterMock = $this->getMockForAbstractClass(PaymentSavingRateLimiterInterface::class);
$this->model = $objectManager->getObject(
GuestPaymentInformationManagement::class,
[
@@ -99,7 +106,8 @@ protected function setUp(): void
'cartManagement' => $this->cartManagementMock,
'cartRepository' => $this->cartRepositoryMock,
'quoteIdMaskFactory' => $this->quoteIdMaskFactoryMock,
- 'paymentsRateLimiter' => $this->limiterMock
+ 'paymentsRateLimiter' => $this->limiterMock,
+ 'savingRateLimiter' => $this->saveLimiterMock
]
);
$objectManager->setBackwardCompatibleProperty($this->model, 'logger', $this->loggerMock);
@@ -161,11 +169,10 @@ public function testSavePaymentInformation()
*/
public function testSavePaymentInformationLimited(): void
{
- $this->expectException(PaymentProcessingRateLimitExceededException::class);
- $this->limiterMock->method('limit')
+ $this->saveLimiterMock->method('limit')
->willThrowException(new PaymentProcessingRateLimitExceededException(__('Error')));
- $this->savePayment();
+ $this->assertFalse($this->savePayment());
}
public function testSavePaymentInformationWithoutBillingAddress()
diff --git a/app/code/Magento/Checkout/Test/Unit/Model/PaymentInformationManagementTest.php b/app/code/Magento/Checkout/Test/Unit/Model/PaymentInformationManagementTest.php
index d437974450e6f..d8a09a7072794 100644
--- a/app/code/Magento/Checkout/Test/Unit/Model/PaymentInformationManagementTest.php
+++ b/app/code/Magento/Checkout/Test/Unit/Model/PaymentInformationManagementTest.php
@@ -9,6 +9,7 @@
use Magento\Checkout\Api\Exception\PaymentProcessingRateLimitExceededException;
use Magento\Checkout\Api\PaymentProcessingRateLimiterInterface;
+use Magento\Checkout\Api\PaymentSavingRateLimiterInterface;
use Magento\Checkout\Model\PaymentInformationManagement;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Phrase;
@@ -61,10 +62,15 @@ class PaymentInformationManagementTest extends TestCase
private $cartRepositoryMock;
/**
- * @var PaymentProcessingRateLimiterInterface|MockObject
+ * @var PaymentProcessingRateLimiterInterface|\PHPUnit_Framework_MockObject_MockObject
*/
private $rateLimiterMock;
+ /**
+ * @var PaymentSavingRateLimiterInterface|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $saveLimiterMock;
+
protected function setUp(): void
{
$objectManager = new ObjectManager($this);
@@ -80,13 +86,15 @@ protected function setUp(): void
$this->cartRepositoryMock = $this->getMockBuilder(CartRepositoryInterface::class)
->getMock();
$this->rateLimiterMock = $this->getMockForAbstractClass(PaymentProcessingRateLimiterInterface::class);
+ $this->saveLimiterMock = $this->getMockForAbstractClass(PaymentSavingRateLimiterInterface::class);
$this->model = $objectManager->getObject(
PaymentInformationManagement::class,
[
'billingAddressManagement' => $this->billingAddressManagementMock,
'paymentMethodManagement' => $this->paymentMethodManagementMock,
'cartManagement' => $this->cartManagementMock,
- 'paymentRateLimiter' => $this->rateLimiterMock
+ 'paymentRateLimiter' => $this->rateLimiterMock,
+ 'saveRateLimiter' => $this->saveLimiterMock
]
);
$objectManager->setBackwardCompatibleProperty($this->model, 'logger', $this->loggerMock);
@@ -166,11 +174,10 @@ public function testSavePaymentInformation()
*/
public function testSavePaymentInformationLimited(): void
{
- $this->rateLimiterMock->method('limit')
+ $this->saveLimiterMock->method('limit')
->willThrowException(new PaymentProcessingRateLimitExceededException(__('Error')));
- $this->expectException(PaymentProcessingRateLimitExceededException::class);
- $this->savePayment();
+ $this->assertFalse($this->savePayment());
}
public function testSavePaymentInformationWithoutBillingAddress()
diff --git a/app/code/Magento/Checkout/etc/di.xml b/app/code/Magento/Checkout/etc/di.xml
index 0c1d866dfc2fb..1af46c878694b 100644
--- a/app/code/Magento/Checkout/etc/di.xml
+++ b/app/code/Magento/Checkout/etc/di.xml
@@ -51,4 +51,6 @@
+
diff --git a/app/code/Magento/Checkout/view/frontend/web/js/action/set-payment-information-extended.js b/app/code/Magento/Checkout/view/frontend/web/js/action/set-payment-information-extended.js
index ae5b0914e83a6..94d4907395528 100644
--- a/app/code/Magento/Checkout/view/frontend/web/js/action/set-payment-information-extended.js
+++ b/app/code/Magento/Checkout/view/frontend/web/js/action/set-payment-information-extended.js
@@ -15,7 +15,7 @@ define([
'Magento_Checkout/js/action/get-totals',
'Magento_Checkout/js/model/full-screen-loader',
'underscore',
- 'Magento_Checkout/js/model/payment/set-payment-hooks'
+ 'Magento_Checkout/js/model/payment/place-order-hooks'
], function (quote, urlBuilder, storage, errorProcessor, customer, getTotalsAction, fullScreenLoader, _, hooks) {
'use strict';
@@ -79,9 +79,6 @@ define([
).always(
function () {
fullScreenLoader.stopLoader();
- _.each(hooks.afterRequestListeners, function (listener) {
- listener();
- });
}
);
};
diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/payment/set-payment-hooks.js b/app/code/Magento/Checkout/view/frontend/web/js/model/payment/set-payment-hooks.js
deleted file mode 100644
index 5cd31d85c9a29..0000000000000
--- a/app/code/Magento/Checkout/view/frontend/web/js/model/payment/set-payment-hooks.js
+++ /dev/null
@@ -1,13 +0,0 @@
-/**
- * Copyright © Magento, Inc. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-define([], function () {
- 'use strict';
-
- return {
- requestModifiers: [],
- afterRequestListeners: []
- };
-});
diff --git a/app/code/Magento/Checkout/view/frontend/web/js/view/checkout/setPaymentCaptcha.js b/app/code/Magento/Checkout/view/frontend/web/js/view/checkout/setPaymentCaptcha.js
deleted file mode 100644
index 93f3bb8b2a45c..0000000000000
--- a/app/code/Magento/Checkout/view/frontend/web/js/view/checkout/setPaymentCaptcha.js
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
- * Copyright © Magento, Inc. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-define([
- 'Magento_Captcha/js/view/checkout/defaultCaptcha',
- 'Magento_Captcha/js/model/captchaList',
- 'underscore',
- 'Magento_Checkout/js/model/payment/set-payment-hooks'
-],
-function (defaultCaptcha, captchaList, _, setPaymentHooks) {
- 'use strict';
-
- return defaultCaptcha.extend({
- /** @inheritdoc */
- initialize: function () {
- var self = this,
- currentCaptcha;
-
- this._super();
- currentCaptcha = captchaList.getCaptchaByFormId(this.formId);
-
- if (currentCaptcha != null) {
- currentCaptcha.setIsVisible(true);
- this.setCurrentCaptcha(currentCaptcha);
- setPaymentHooks.requestModifiers.push(function (headers) {
- if (self.isRequired()) {
- headers['X-Captcha'] = self.captchaValue()();
- }
- });
- setPaymentHooks.afterRequestListeners.push(function () {
- self.refresh();
- });
- }
- }
- });
-});
diff --git a/app/code/Magento/Multishipping/Block/Checkout/Overview.php b/app/code/Magento/Multishipping/Block/Checkout/Overview.php
index 05da219b67b92..0a0b348973f01 100644
--- a/app/code/Magento/Multishipping/Block/Checkout/Overview.php
+++ b/app/code/Magento/Multishipping/Block/Checkout/Overview.php
@@ -127,8 +127,9 @@ protected function _prepareLayout()
'cacheable' => false,
'after' => '-',
'form_id' => CaptchaPaymentProcessingRateLimiter::CAPTCHA_FORM,
- 'image_width' => 230,
- 'image_height' => 230
+ 'img_width' => 230,
+ 'img_height' => 50,
+ 'frontend_validation' => false
]
);
}
diff --git a/app/code/Magento/Multishipping/Controller/Checkout/OverviewPost.php b/app/code/Magento/Multishipping/Controller/Checkout/OverviewPost.php
index b3333d828a094..734251f18455d 100644
--- a/app/code/Magento/Multishipping/Controller/Checkout/OverviewPost.php
+++ b/app/code/Magento/Multishipping/Controller/Checkout/OverviewPost.php
@@ -13,6 +13,7 @@
use Magento\Customer\Api\CustomerRepositoryInterface;
use Magento\Framework\Exception\PaymentException;
use Magento\Framework\Session\SessionManagerInterface;
+use Magento\Checkout\Api\Exception\PaymentProcessingRateLimitExceededException;
/**
* Placing orders.
@@ -126,6 +127,9 @@ public function execute()
$this->_getCheckout()->getCheckoutSession()->setDisplaySuccess(true);
$this->_redirect('*/*/success');
}
+ } catch (PaymentProcessingRateLimitExceededException $ex) {
+ $this->messageManager->addErrorMessage($ex->getMessage());
+ $this->_redirect('*/*/overview');
} catch (PaymentException $e) {
$message = $e->getMessage();
if (!empty($message)) {
diff --git a/app/code/Magento/Payment/view/adminhtml/templates/form/cc.phtml b/app/code/Magento/Payment/view/adminhtml/templates/form/cc.phtml
index 4b7da0f9b7862..b122da755b873 100644
--- a/app/code/Magento/Payment/view/adminhtml/templates/form/cc.phtml
+++ b/app/code/Magento/Payment/view/adminhtml/templates/form/cc.phtml
@@ -22,8 +22,9 @@ $ccExpYear = $block->getInfoData('cc_exp_year');
- getCcAvailableTypes() as $typeCode => $typeName) : ?>
- selected="selected">
+ getCcAvailableTypes() as $typeCode => $typeName): ?>
+ selected="selected">
= $block->escapeHtml($typeName) ?>
@@ -35,8 +36,13 @@ $ccExpYear = $block->getInfoData('cc_exp_year');
= $block->escapeHtml(__('Credit Card Number')) ?>
-
@@ -47,18 +53,18 @@ $ccExpYear = $block->getInfoData('cc_exp_year');
- getCcMonths() as $k => $v) : ?>
+ getCcMonths() as $k => $v): ?>
selected="selected">
+ selected="selected">
= $block->escapeHtml($v) ?>
- getCcYears() as $k => $v) : ?>
+ getCcYears() as $k => $v): ?>
selected="selected">
+ selected="selected">
= $block->escapeHtml($v) ?>
@@ -66,16 +72,21 @@ $ccExpYear = $block->getInfoData('cc_exp_year');
- hasVerification()) : ?>
+ hasVerification()): ?>
diff --git a/app/code/Magento/Payment/view/adminhtml/templates/transparent/form.phtml b/app/code/Magento/Payment/view/adminhtml/templates/transparent/form.phtml
index 0c1df4e239810..81666132184c3 100644
--- a/app/code/Magento/Payment/view/adminhtml/templates/transparent/form.phtml
+++ b/app/code/Magento/Payment/view/adminhtml/templates/transparent/form.phtml
@@ -31,7 +31,9 @@ $ccExpMonth = $block->getInfoData('cc_exp_month');
"orderSaveUrl":"= $block->escapeUrl($block->getOrderUrl()) ?>",
"cgiUrl":"= $block->escapeUrl($block->getCgiUrl()) ?>",
"expireYearLength":"= $block->escapeHtml($block->getMethodConfigData('cc_year_length')) ?>",
- "nativeAction":"= $block->escapeUrl($block->getUrl('*/*/save', ['_secure' => $block->getRequest()->isSecure()])) ?>"
+ "nativeAction":"= $block->escapeUrl(
+ $block->getUrl('*/*/save', ['_secure' => $block->getRequest()->isSecure()])
+ ) ?>"
}, "validation":[]}'
style="display: none;">
- hasVerification()) : ?>
+ hasVerification()): ?>
diff --git a/app/code/Magento/Payment/view/frontend/templates/form/cc.phtml b/app/code/Magento/Payment/view/frontend/templates/form/cc.phtml
index 3a0a0e864a45e..22e7dfbba6aca 100644
--- a/app/code/Magento/Payment/view/frontend/templates/form/cc.phtml
+++ b/app/code/Magento/Payment/view/frontend/templates/form/cc.phtml
@@ -29,9 +29,9 @@ $ccExpYear = $block->getInfoData('cc_exp_year');
}'
class="select">
= $block->escapeHtml(__('--Please Select--')) ?>
- getCcAvailableTypes() as $typeCode => $typeName) : ?>
+ getCcAvailableTypes() as $typeCode => $typeName): ?>
selected="selected">
+ selected="selected">
= $block->escapeHtml($typeName) ?>
@@ -43,8 +43,15 @@ $ccExpYear = $block->getInfoData('cc_exp_year');
= $block->escapeHtml(__('Credit Card Number')) ?>
-
-
- getCcMonths() as $k => $v) : ?>
+
+ getCcMonths() as $k => $v): ?>
selected="selected">
+ selected="selected">
= $block->escapeHtml($v) ?>
@@ -75,9 +88,9 @@ $ccExpYear = $block->getInfoData('cc_exp_year');
- getCcYears() as $k => $v) : ?>
+ getCcYears() as $k => $v): ?>
selected="selected">
+ " selected="selected">
= $block->escapeHtml($v) ?>
@@ -87,15 +100,23 @@ $ccExpYear = $block->getInfoData('cc_exp_year');
- hasVerification()) : ?>
+ hasVerification()): ?>
= $block->escapeHtml(__('Card Verification Number')) ?>
-
+
getViewFileUrl('Magento_Checkout::cvv.png') . '\" alt=\"' .
$block->escapeHtml(__('Card Verification Number Visual Reference')) .
'\" title=\"' . $block->escapeHtml(__('Card Verification Number Visual Reference')) . '\" />'; ?>
diff --git a/app/code/Magento/Payment/view/frontend/templates/transparent/form.phtml b/app/code/Magento/Payment/view/frontend/templates/transparent/form.phtml
index 0cf8ae8afd260..d49e7cb269731 100644
--- a/app/code/Magento/Payment/view/frontend/templates/transparent/form.phtml
+++ b/app/code/Magento/Payment/view/frontend/templates/transparent/form.phtml
@@ -27,7 +27,9 @@ $content = '
escapeUrl($block->getViewFileUrl('Magento_Che
"cgiUrl":"= $block->escapeUrl($block->getCgiUrl()) ?>",
"dateDelim":"= $block->escapeHtml($block->getDateDelim()) ?>",
"cardFieldsMap":= $block->escapeHtml($block->getCardFieldsMap()) ?>,
- "nativeAction":"= $block->escapeUrl($block->getUrl('checkout/onepage/saveOrder', ['_secure' => $block->getRequest()->isSecure()])) ?>"
+ "nativeAction":"= $block->escapeUrl(
+ $block->getUrl('checkout/onepage/saveOrder', ['_secure' => $block->getRequest()->isSecure()])
+ ) ?>"
}, "validation":[]}'>
@@ -45,9 +47,9 @@ $content = ' escapeUrl($block->getViewFileUrl('Magento_Che
"validate-cc-type-select":"#= /* @noEscape */ $code ?>_cc_number"
}'>
= $block->escapeHtml(__('--Please Select--')) ?>
- getCcAvailableTypes() as $typeCode => $typeName) : ?>
+ getCcAvailableTypes() as $typeCode => $typeName): ?>
selected="selected">
+ selected="selected">
= $block->escapeHtml($typeName) ?>
@@ -59,8 +61,14 @@ $content = ' escapeUrl($block->getViewFileUrl('Magento_Che
escapeUrl($block->getViewFileUrl('Magento_Che
required:true,
"validate-cc-exp":"#= /* @noEscape */ $code ?>_expiration_yr"
}'>
- getCcMonths() as $k => $v) : ?>
+ getCcMonths() as $k => $v): ?>
selected="selected">
+ selected="selected">
= $block->escapeHtml($v) ?>
@@ -97,9 +105,9 @@ $content = '
escapeUrl($block->getViewFileUrl('Magento_Che
- getCcYears() as $k => $v) : ?>
+ getCcYears() as $k => $v): ?>
selected="selected">
+ selected="selected">
= $block->escapeHtml($v) ?>
@@ -109,15 +117,21 @@ $content = ' escapeUrl($block->getViewFileUrl('Magento_Che
- hasVerification()) : ?>
+ hasVerification()): ?>
= $block->escapeHtml(__('Card Verification Number')) ?>
diff --git a/app/code/Magento/Paypal/view/adminhtml/templates/transparent/form.phtml b/app/code/Magento/Paypal/view/adminhtml/templates/transparent/form.phtml
index ae42803a26dd3..1b54d5a76fdd8 100644
--- a/app/code/Magento/Paypal/view/adminhtml/templates/transparent/form.phtml
+++ b/app/code/Magento/Paypal/view/adminhtml/templates/transparent/form.phtml
@@ -31,7 +31,9 @@ $ccExpMonth = $block->getInfoData('cc_exp_month');
"orderSaveUrl":"= $block->escapeUrl($block->getOrderUrl()) ?>",
"cgiUrl":"= $block->escapeUrl($block->getCgiUrl()) ?>",
"expireYearLength":"= $block->escapeHtml($block->getMethodConfigData('cc_year_length')) ?>",
- "nativeAction":"= $block->escapeUrl($block->getUrl('*/*/save', ['_secure' => $block->getRequest()->isSecure()])) ?>"
+ "nativeAction":"= $block->escapeUrl(
+ $block->getUrl('*/*/save', ['_secure' => $block->getRequest()->isSecure()])
+ ) ?>"
}, "validation":[]}'
style="display: none;">
@@ -46,9 +48,10 @@ $ccExpMonth = $block->getInfoData('cc_exp_month');
data-validate='{required:true, "validate-cc-type-select":"#= /* @noEscape */ $code ?>_cc_number"}'
class="admin__control-select">
= $block->escapeHtml(__('Please Select')) ?>
- getCcAvailableTypes() as $typeCode => $typeName) : ?>
+ getCcAvailableTypes() as $typeCode => $typeName): ?>
selected="selected">
+ value="= $block->escapeHtmlAttr($typeCode) ?>"
+ selected="selected">
= $block->escapeHtml($typeName) ?>
@@ -64,6 +67,9 @@ $ccExpMonth = $block->getInfoData('cc_exp_month');
getInfoData('cc_exp_month');
data-container="= /* @noEscape */ $code ?>-cc-month"
class="admin__control-select admin__control-select-month"
data-validate='{required:true, "validate-cc-exp":"#= /* @noEscape */ $code ?>_expiration_yr"}'>
- getCcMonths() as $k => $v) : ?>
+ getCcMonths() as $k => $v): ?>
selected="selected">
+ selected="selected">
= $block->escapeHtml($v) ?>
@@ -98,17 +104,17 @@ $ccExpMonth = $block->getInfoData('cc_exp_month');
- getCcYears() as $k => $v) : ?>
+ getCcYears() as $k => $v): ?>
selected="selected">
+ selected="selected">
= $block->escapeHtml($v) ?>
- hasVerification()) : ?>
+ hasVerification()): ?>
- isVaultEnabled()) : ?>
+ isVaultEnabled()): ?>
paymentMethodManagement = $paymentMethodManagement;
$this->paymentFactory = $paymentFactory;
$this->additionalDataProviderPool = $additionalDataProviderPool;
- $this->paymentRateLimiter = $paymentRateLimiter
- ?? ObjectManager::getInstance()->get(PaymentProcessingRateLimiterInterface::class);
+ $this->paymentRateLimiter = $savingRateLimiter
+ ?? ObjectManager::getInstance()->get(PaymentSavingRateLimiterInterface::class);
}
/**
@@ -77,7 +82,12 @@ public function __construct(
public function execute(Quote $cart, array $paymentData): void
{
try {
- $this->paymentRateLimiter->limit();
+ try {
+ $this->paymentRateLimiter->limit();
+ } catch (PaymentProcessingRateLimitExceededException $ex) {
+ //Limit reached
+ return;
+ }
} catch (PaymentProcessingRateLimitExceededException $exception) {
throw new GraphQlInputException(__($exception->getMessage()), $exception);
}
diff --git a/app/code/Magento/QuoteGraphQl/Test/Unit/Model/Cart/SetPaymentMethodOnCartTest.php b/app/code/Magento/QuoteGraphQl/Test/Unit/Model/Cart/SetPaymentMethodOnCartTest.php
index 281e1233d8bbe..45bd3538fbcb1 100644
--- a/app/code/Magento/QuoteGraphQl/Test/Unit/Model/Cart/SetPaymentMethodOnCartTest.php
+++ b/app/code/Magento/QuoteGraphQl/Test/Unit/Model/Cart/SetPaymentMethodOnCartTest.php
@@ -9,7 +9,7 @@
namespace Magento\QuoteGraphQl\Test\Unit\Model\Cart;
use Magento\Checkout\Api\Exception\PaymentProcessingRateLimitExceededException;
-use Magento\Checkout\Api\PaymentProcessingRateLimiterInterface;
+use Magento\Checkout\Api\PaymentSavingRateLimiterInterface;
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
use Magento\Quote\Model\Quote;
@@ -25,7 +25,7 @@ class SetPaymentMethodOnCartTest extends TestCase
private $model;
/**
- * @var PaymentProcessingRateLimiterInterface|MockObject
+ * @var PaymentSavingRateLimiterInterface|MockObject
*/
private $rateLimiterMock;
@@ -37,10 +37,10 @@ protected function setUp(): void
parent::setUp();
$objectManager = new ObjectManager($this);
- $this->rateLimiterMock = $this->getMockForAbstractClass(PaymentProcessingRateLimiterInterface::class);
+ $this->rateLimiterMock = $this->getMockForAbstractClass(PaymentSavingRateLimiterInterface::class);
$this->model = $objectManager->getObject(
SetPaymentMethodOnCart::class,
- ['paymentRateLimiter' => $this->rateLimiterMock]
+ ['savingRateLimiter' => $this->rateLimiterMock]
);
}
@@ -52,10 +52,9 @@ protected function setUp(): void
public function testLimited(): void
{
$this->rateLimiterMock->method('limit')
- ->willThrowException(new PaymentProcessingRateLimitExceededException(__($message = 'Error')));
- $this->expectException(GraphQlInputException::class);
- $this->expectExceptionMessage($message);
+ ->willThrowException(new PaymentProcessingRateLimitExceededException(__('Error')));
+ //There will be en error if the limiter won't stop the execution
$this->model->execute($this->createMock(Quote::class), []);
}
}
diff --git a/app/code/Magento/SendFriend/Block/Send.php b/app/code/Magento/SendFriend/Block/Send.php
index 6f2154ba29f47..04fe39542d135 100644
--- a/app/code/Magento/SendFriend/Block/Send.php
+++ b/app/code/Magento/SendFriend/Block/Send.php
@@ -240,10 +240,12 @@ protected function _prepareLayout()
'cacheable' => false,
'after' => '-',
'form_id' => 'product_sendtofriend_form',
- 'image_width' => 230,
- 'image_height' => 230
+ 'img_width' => 230,
+ 'img_height' => 50
]
);
}
+
+ return $this;
}
}
diff --git a/dev/tests/integration/testsuite/Magento/Checkout/Model/CaptchaPaymentProcessingRateLimiterTest.php b/dev/tests/integration/testsuite/Magento/Checkout/Model/CaptchaRateLimiterTest.php
similarity index 90%
rename from dev/tests/integration/testsuite/Magento/Checkout/Model/CaptchaPaymentProcessingRateLimiterTest.php
rename to dev/tests/integration/testsuite/Magento/Checkout/Model/CaptchaRateLimiterTest.php
index 2a7b3c29223be..1f858a4d474ad 100644
--- a/dev/tests/integration/testsuite/Magento/Checkout/Model/CaptchaPaymentProcessingRateLimiterTest.php
+++ b/dev/tests/integration/testsuite/Magento/Checkout/Model/CaptchaRateLimiterTest.php
@@ -9,9 +9,9 @@
namespace Magento\Checkout\Model;
use Magento\Captcha\Model\DefaultModel;
-use Magento\Checkout\Api\Exception\PaymentProcessingRateLimitExceededException;
use Magento\Customer\Api\CustomerRepositoryInterface;
use Magento\Framework\App\RequestInterface;
+use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\HTTP\PhpEnvironment\RemoteAddress;
use Magento\TestFramework\Helper\Bootstrap;
use PHPUnit\Framework\TestCase;
@@ -27,10 +27,10 @@
* @magentoAppIsolation enabled
* @magentoAppArea frontend
*/
-class CaptchaPaymentProcessingRateLimiterTest extends TestCase
+class CaptchaRateLimiterTest extends TestCase
{
/**
- * @var CaptchaPaymentProcessingRateLimiter
+ * @var CaptchaRateLimiter
*/
private $model;
@@ -69,7 +69,10 @@ protected function setUp(): void
$this->captchaHelper = $objectManager->get(CaptchaHelper::class);
$this->customerSession = $objectManager->get(CustomerSession::class);
$this->customerRepo = $objectManager->get(CustomerRepositoryInterface::class);
- $this->model = $objectManager->get(CaptchaPaymentProcessingRateLimiter::class);
+ $this->model = $objectManager->create(
+ CaptchaRateLimiter::class,
+ ['captchaId' => 'payment_processing_request']
+ );
}
/**
@@ -95,7 +98,7 @@ public function testLoggedInLimits(): void
try {
$this->model->limit();
$limited = false;
- } catch (PaymentProcessingRateLimitExceededException $exception) {
+ } catch (LocalizedException $exception) {
$limited = true;
}
$this->assertTrue($limited);
@@ -118,7 +121,7 @@ public function testGuestLimits(): void
try {
$this->model->limit();
$limited = false;
- } catch (PaymentProcessingRateLimitExceededException $exception) {
+ } catch (LocalizedException $exception) {
$limited = true;
}
$this->assertTrue($limited);
@@ -141,7 +144,7 @@ public function testCaptchaValidation(): void
try {
$this->model->limit();
$limited = false;
- } catch (PaymentProcessingRateLimitExceededException $exception) {
+ } catch (LocalizedException $exception) {
$limited = true;
}
//CAPTCHA is required
@@ -176,7 +179,7 @@ public function testCaptchaValidation(): void
try {
$this->model->limit();
$limited = false;
- } catch (PaymentProcessingRateLimitExceededException $exception) {
+ } catch (LocalizedException $exception) {
$limited = true;
}
//CAPTCHA was validated
diff --git a/lib/internal/Magento/Framework/App/StaticResource.php b/lib/internal/Magento/Framework/App/StaticResource.php
index 2a4aa3cd4be4b..c39a86752eefe 100644
--- a/lib/internal/Magento/Framework/App/StaticResource.php
+++ b/lib/internal/Magento/Framework/App/StaticResource.php
@@ -9,6 +9,8 @@
use Magento\Framework\ObjectManager\ConfigLoaderInterface;
use Magento\Framework\Filesystem;
use Magento\Framework\Config\ConfigOptionsListConstants;
+use Magento\Framework\Validator\Locale;
+use Magento\Framework\View\Design\Theme\ThemePackageList;
use Psr\Log\LoggerInterface;
use Magento\Framework\Debug;
use Magento\Framework\Filesystem\Driver\File;
@@ -80,6 +82,16 @@ class StaticResource implements \Magento\Framework\AppInterface
*/
private $driver;
+ /**
+ * @var ThemePackageList
+ */
+ private $themePackageList;
+
+ /**
+ * @var Locale
+ */
+ private $localeValidator;
+
/**
* @param State $state
* @param Response\FileInterface $response
@@ -91,6 +103,8 @@ class StaticResource implements \Magento\Framework\AppInterface
* @param ConfigLoaderInterface $configLoader
* @param DeploymentConfig|null $deploymentConfig
* @param File|null $driver
+ * @param ThemePackageList|null $themePackageList
+ * @param Locale|null $localeValidator
*
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
@@ -104,7 +118,9 @@ public function __construct(
\Magento\Framework\ObjectManagerInterface $objectManager,
ConfigLoaderInterface $configLoader,
DeploymentConfig $deploymentConfig = null,
- File $driver = null
+ File $driver = null,
+ ThemePackageList $themePackageList = null,
+ Locale $localeValidator = null
) {
$this->state = $state;
$this->response = $response;
@@ -116,6 +132,8 @@ public function __construct(
$this->configLoader = $configLoader;
$this->deploymentConfig = $deploymentConfig ?: ObjectManager::getInstance()->get(DeploymentConfig::class);
$this->driver = $driver ?: ObjectManager::getInstance()->get(File::class);
+ $this->themePackageList = $themePackageList ?? ObjectManager::getInstance()->get(ThemePackageList::class);
+ $this->localeValidator = $localeValidator ?? ObjectManager::getInstance()->get(Locale::class);
}
/**
@@ -138,6 +156,16 @@ public function launch()
} else {
$path = $this->request->get('resource');
$params = $this->parsePath($path);
+ if (!($this->isThemeAllowed($params['area'] . DIRECTORY_SEPARATOR . $params['theme'])
+ && $this->localeValidator->isValid($params['locale']))
+ ) {
+ if ($appMode == \Magento\Framework\App\State::MODE_PRODUCTION) {
+ $this->response->setHttpResponseCode(404);
+ return $this->response;
+ }
+ throw new \InvalidArgumentException('Requested path ' . $path . ' is wrong.');
+ }
+
$this->state->setAreaCode($params['area']);
$this->objectManager->configure($this->configLoader->load($params['area']));
$file = $params['file'];
@@ -236,4 +264,15 @@ private function getLogger()
return $this->logger;
}
+
+ /**
+ * Check that theme is available.
+ *
+ * @param string $theme
+ * @return bool
+ */
+ private function isThemeAllowed(string $theme): bool
+ {
+ return in_array($theme, array_keys($this->themePackageList->getThemes()));
+ }
}
diff --git a/lib/internal/Magento/Framework/App/Test/Unit/StaticResourceTest.php b/lib/internal/Magento/Framework/App/Test/Unit/StaticResourceTest.php
index e74b424b4941e..abc6643bf7f2b 100644
--- a/lib/internal/Magento/Framework/App/Test/Unit/StaticResourceTest.php
+++ b/lib/internal/Magento/Framework/App/Test/Unit/StaticResourceTest.php
@@ -21,6 +21,8 @@
use Psr\Log\LoggerInterface;
use PHPUnit\Framework\MockObject\MockObject as MockObject;
use Magento\Framework\Filesystem\Driver\File;
+use Magento\Framework\View\Design\Theme\ThemePackageList;
+use Magento\Framework\Validator\Locale;
/**
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -77,6 +79,16 @@ class StaticResourceTest extends \PHPUnit\Framework\TestCase
*/
private $deploymentConfigMock;
+ /**
+ * @var ThemePackageList|MockObject
+ */
+ private $themePackageListMock;
+
+ /**
+ * @var Locale|MockObject
+ */
+ private $localeValidatorMock;
+
/**
* @var StaticResource
*/
@@ -100,6 +112,8 @@ protected function setUp(): void
$this->configLoaderMock = $this->createMock(ConfigLoader::class);
$this->deploymentConfigMock = $this->createMock(DeploymentConfig::class);
$this->driverMock = $this->createMock(File::class);
+ $this->themePackageListMock = $this->createMock(ThemePackageList::class);
+ $this->localeValidatorMock = $this->createMock(Locale::class);
$this->object = new StaticResource(
$this->stateMock,
$this->responseMock,
@@ -110,7 +124,9 @@ protected function setUp(): void
$this->objectManagerMock,
$this->configLoaderMock,
$this->deploymentConfigMock,
- $this->driverMock
+ $this->driverMock,
+ $this->themePackageListMock,
+ $this->localeValidatorMock
);
}
@@ -201,6 +217,17 @@ public function testLaunch(
$this->driverMock->expects($this->once())
->method('getRealPathSafety')
->willReturnArgument(0);
+ $this->themePackageListMock->expects($this->atLeastOnce())->method('getThemes')->willReturn(
+ [
+ 'area/Magento/theme' => [
+ 'area' => 'area',
+ 'vendor' => 'Magento',
+ 'name' => 'theme',
+ ],
+ ]
+ );
+ $this->localeValidatorMock->expects($this->once())->method('isValid')->willReturn(true);
+
$this->object->launch();
}
@@ -322,4 +349,86 @@ public function testLaunchPathAbove()
$this->object->launch();
}
+
+ /**
+ * @param array $themes
+ * @dataProvider themesDataProvider
+ */
+ public function testLaunchWithInvalidTheme(array $themes): void
+ {
+ $this->expectException('InvalidArgumentException');
+ $path = 'frontend/Test/luma/en_US/calendar.css';
+
+ $this->stateMock->expects($this->once())
+ ->method('getMode')
+ ->willReturn(State::MODE_DEVELOPER);
+ $this->requestMock->expects($this->once())
+ ->method('get')
+ ->with('resource')
+ ->willReturn($path);
+ $this->driverMock->expects($this->once())
+ ->method('getRealPathSafety')
+ ->with($path)
+ ->willReturn($path);
+ $this->themePackageListMock->expects($this->once())->method('getThemes')->willReturn($themes);
+ $this->localeValidatorMock->expects($this->never())->method('isValid');
+ $this->expectExceptionMessage('Requested path ' . $path . ' is wrong.');
+
+ $this->object->launch();
+ }
+
+ /**
+ * @param array $themes
+ * @dataProvider themesDataProvider
+ */
+ public function testLaunchWithInvalidLocale(array $themes): void
+ {
+ $this->expectException('InvalidArgumentException');
+ $path = 'frontend/Magento/luma/test/calendar.css';
+
+ $this->stateMock->expects($this->once())
+ ->method('getMode')
+ ->willReturn(State::MODE_DEVELOPER);
+ $this->requestMock->expects($this->once())
+ ->method('get')
+ ->with('resource')
+ ->willReturn($path);
+ $this->driverMock->expects($this->once())
+ ->method('getRealPathSafety')
+ ->with($path)
+ ->willReturn($path);
+ $this->themePackageListMock->expects($this->once())->method('getThemes')->willReturn($themes);
+ $this->localeValidatorMock->expects($this->once())->method('isValid')->willReturn(false);
+ $this->expectExceptionMessage('Requested path ' . $path . ' is wrong.');
+
+ $this->object->launch();
+ }
+
+ /**
+ * @return array
+ */
+ public function themesDataProvider(): array
+ {
+ return [
+ [
+ [
+ 'adminhtml/Magento/backend' => [
+ 'area' => 'adminhtml',
+ 'vendor' => 'Magento',
+ 'name' => 'backend',
+ ],
+ 'frontend/Magento/blank' => [
+ 'area' => 'frontend',
+ 'vendor' => 'Magento',
+ 'name' => 'blank',
+ ],
+ 'frontend/Magento/luma' => [
+ 'area' => 'frontend',
+ 'vendor' => 'Magento',
+ 'name' => 'luma',
+ ],
+ ],
+ ],
+ ];
+ }
}