Skip to content

Commit 3a42052

Browse files
authored
Merge pull request #3531 from magento-borg/BugFixPR
[2.3-develop] Bug Fixes
2 parents 1773f41 + a297c29 commit 3a42052

File tree

49 files changed

+1300
-264
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1300
-264
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
namespace Magento\Captcha\CustomerData;
10+
11+
use Magento\Customer\CustomerData\SectionSourceInterface;
12+
13+
/**
14+
* Captcha section
15+
*/
16+
class Captcha extends \Magento\Framework\DataObject implements SectionSourceInterface
17+
{
18+
/**
19+
* @var array
20+
*/
21+
private $formIds;
22+
23+
/**
24+
* @var \Magento\Captcha\Helper\Data
25+
*/
26+
private $helper;
27+
28+
/**
29+
* @param \Magento\Captcha\Helper\Data $helper
30+
* @param array $formIds
31+
* @param array $data
32+
* @codeCoverageIgnore
33+
*/
34+
public function __construct(
35+
\Magento\Captcha\Helper\Data $helper,
36+
array $formIds,
37+
array $data = []
38+
) {
39+
parent::__construct($data);
40+
$this->helper = $helper;
41+
$this->formIds = $formIds;
42+
}
43+
44+
/**
45+
* @inheritdoc
46+
*/
47+
public function getSectionData() :array
48+
{
49+
$data = [];
50+
51+
foreach ($this->formIds as $formId) {
52+
$captchaModel = $this->helper->getCaptcha($formId);
53+
$data[$formId] = [
54+
'isRequired' => $captchaModel->isRequired(),
55+
'timestamp' => time()
56+
];
57+
}
58+
59+
return $data;
60+
}
61+
}

app/code/Magento/Captcha/Model/Checkout/ConfigProvider.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
*/
66
namespace Magento\Captcha\Model\Checkout;
77

8+
/**
9+
* Configuration provider for Captcha rendering.
10+
*/
811
class ConfigProvider implements \Magento\Checkout\Model\ConfigProviderInterface
912
{
1013
/**
@@ -38,7 +41,7 @@ public function __construct(
3841
}
3942

4043
/**
41-
* {@inheritdoc}
44+
* @inheritdoc
4245
*/
4346
public function getConfig()
4447
{
@@ -49,7 +52,8 @@ public function getConfig()
4952
'imageHeight' => $this->getImageHeight($formId),
5053
'imageSrc' => $this->getImageSrc($formId),
5154
'refreshUrl' => $this->getRefreshUrl(),
52-
'isRequired' => $this->isRequired($formId)
55+
'isRequired' => $this->isRequired($formId),
56+
'timestamp' => time()
5357
];
5458
}
5559
return $config;

app/code/Magento/Captcha/Model/Customer/Plugin/AjaxLogin.php

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,15 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6-
declare(strict_types=1);
76

87
namespace Magento\Captcha\Model\Customer\Plugin;
98

109
use Magento\Captcha\Helper\Data as CaptchaHelper;
11-
use Magento\Customer\Controller\Ajax\Login;
12-
use Magento\Framework\Controller\Result\Json;
13-
use Magento\Framework\Controller\Result\JsonFactory;
1410
use Magento\Framework\Session\SessionManagerInterface;
11+
use Magento\Framework\Controller\Result\JsonFactory;
1512

1613
/**
17-
* The plugin for ajax login controller.
14+
* Around plugin for login action.
1815
*/
1916
class AjaxLogin
2017
{
@@ -67,14 +64,16 @@ public function __construct(
6764
}
6865

6966
/**
70-
* Validates captcha during request execution.
67+
* Check captcha data on login action.
7168
*
72-
* @param Login $subject
69+
* @param \Magento\Customer\Controller\Ajax\Login $subject
7370
* @param \Closure $proceed
7471
* @return $this
72+
* @SuppressWarnings(PHPMD.NPathComplexity)
73+
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
7574
*/
7675
public function aroundExecute(
77-
Login $subject,
76+
\Magento\Customer\Controller\Ajax\Login $subject,
7877
\Closure $proceed
7978
) {
8079
$captchaFormIdField = 'captcha_form_id';
@@ -99,31 +98,28 @@ public function aroundExecute(
9998
foreach ($this->formIds as $formId) {
10099
if ($formId === $loginFormId) {
101100
$captchaModel = $this->helper->getCaptcha($formId);
102-
103101
if ($captchaModel->isRequired($username)) {
104102
if (!$captchaModel->isCorrect($captchaString)) {
105103
$this->sessionManager->setUsername($username);
106104
$captchaModel->logAttempt($username);
107-
return $this->returnJsonError(__('Incorrect CAPTCHA'), true);
105+
return $this->returnJsonError(__('Incorrect CAPTCHA'));
108106
}
109107
}
110-
111108
$captchaModel->logAttempt($username);
112109
}
113110
}
114111
return $proceed();
115112
}
116113

117114
/**
118-
* Gets Json response.
115+
* Format JSON response.
119116
*
120117
* @param \Magento\Framework\Phrase $phrase
121-
* @param bool $isCaptchaRequired
122-
* @return Json
118+
* @return \Magento\Framework\Controller\Result\Json
123119
*/
124-
private function returnJsonError(\Magento\Framework\Phrase $phrase, bool $isCaptchaRequired = false): Json
120+
private function returnJsonError(\Magento\Framework\Phrase $phrase): \Magento\Framework\Controller\Result\Json
125121
{
126122
$resultJson = $this->resultJsonFactory->create();
127-
return $resultJson->setData(['errors' => true, 'message' => $phrase, 'captcha' => $isCaptchaRequired]);
123+
return $resultJson->setData(['errors' => true, 'message' => $phrase]);
128124
}
129125
}

app/code/Magento/Captcha/Model/DefaultModel.php

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ class DefaultModel extends \Zend\Captcha\Image implements \Magento\Captcha\Model
7878
*/
7979
protected $session;
8080

81+
/**
82+
* @var string
83+
*/
84+
private $words;
85+
8186
/**
8287
* @param \Magento\Framework\Session\SessionManagerInterface $session
8388
* @param \Magento\Captcha\Helper\Data $captchaData
@@ -311,18 +316,18 @@ public function getImgUrl()
311316
*/
312317
public function isCorrect($word)
313318
{
314-
$storedWord = $this->getWord();
319+
$storedWords = $this->getWords();
315320
$this->clearWord();
316321

317-
if (!$word || !$storedWord) {
322+
if (!$word || !$storedWords) {
318323
return false;
319324
}
320325

321326
if (!$this->isCaseSensitive()) {
322-
$storedWord = strtolower($storedWord);
327+
$storedWords = strtolower($storedWords);
323328
$word = strtolower($word);
324329
}
325-
return $word === $storedWord;
330+
return in_array($word, explode(',', $storedWords));
326331
}
327332

328333
/**
@@ -481,14 +486,25 @@ private function getTargetForms()
481486
/**
482487
* Get captcha word
483488
*
484-
* @return string
489+
* @return string|null
485490
*/
486491
public function getWord()
487492
{
488493
$sessionData = $this->session->getData($this->getFormIdKey(self::SESSION_WORD));
489494
return time() < $sessionData['expires'] ? $sessionData['data'] : null;
490495
}
491496

497+
/**
498+
* Get captcha words
499+
*
500+
* @return string|null
501+
*/
502+
private function getWords()
503+
{
504+
$sessionData = $this->session->getData($this->getFormIdKey(self::SESSION_WORD));
505+
return time() < $sessionData['expires'] ? $sessionData['words'] : null;
506+
}
507+
492508
/**
493509
* Set captcha word
494510
*
@@ -498,9 +514,10 @@ public function getWord()
498514
*/
499515
protected function setWord($word)
500516
{
517+
$this->words = $this->words ? $this->words . ',' . $word : $word;
501518
$this->session->setData(
502519
$this->getFormIdKey(self::SESSION_WORD),
503-
['data' => $word, 'expires' => time() + $this->getTimeout()]
520+
['data' => $word, 'words' => $this->words, 'expires' => time() + $this->getTimeout()]
504521
);
505522
$this->word = $word;
506523
return $this;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
/**
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
-->
8+
9+
<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
10+
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Page/etc/SectionObject.xsd">
11+
<section name="StorefrontCustomerSignInPopupFormSection">
12+
<element name="captchaField" type="input" selector="#captcha_user_login"/>
13+
<element name="captchaImg" type="block" selector=".captcha-img"/>
14+
<element name="captchaReload" type="block" selector=".captcha-reload"/>
15+
</section>
16+
</sections>

app/code/Magento/Captcha/Test/Mftf/Test/CaptchaFormsDisplayingTest.xml

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,52 @@
6464
<!--Roll back configuration-->
6565
<scrollToTopOfPage stepKey="ScrollToTop"/>
6666
<click selector="{{CaptchaFormsDisplayingSection.captcha}}" stepKey="ClickToCloseCaptcha"/>
67-
67+
</test>
68+
<test name="CaptchaWithDisabledGuestCheckout">
69+
<annotations>
70+
<features value="Captcha"/>
71+
<stories value="MC-5602 - CAPTCHA doesn't appear in login popup after refreshing page."/>
72+
<title value="Captcha is displaying on login form with disabled guest checkout"/>
73+
<description value="Captcha is displaying on login form with disabled guest checkout"/>
74+
<severity value="MAJOR"/>
75+
<testCaseId value="MAGETWO-96691"/>
76+
<group value="captcha"/>
77+
</annotations>
78+
<before>
79+
<magentoCLI command="config:set checkout/options/guest_checkout 0" stepKey="disableGuestCheckout"/>
80+
<magentoCLI command="config:set customer/captcha/failed_attempts_login 1" stepKey="decreaseLoginAttempt"/>
81+
<createData entity="ApiCategory" stepKey="createCategory"/>
82+
<createData entity="ApiSimpleProduct" stepKey="createSimpleProduct">
83+
<requiredEntity createDataKey="createCategory"/>
84+
</createData>
85+
</before>
86+
<after>
87+
<magentoCLI command="config:set checkout/options/guest_checkout 1" stepKey="enableGuestCheckout"/>
88+
<magentoCLI command="config:set customer/captcha/failed_attempts_login 3" stepKey="increaseLoginAttempt"/>
89+
<deleteData createDataKey="createCategory" stepKey="deleteCategory"/>
90+
<deleteData createDataKey="createSimpleProduct" stepKey="deleteSimpleProduct1"/>
91+
</after>
92+
<amOnPage url="{{StorefrontProductPage.url($$createSimpleProduct.sku$$)}}" stepKey="openProductPage"/>
93+
<waitForPageLoad stepKey="waitForPageLoad"/>
94+
<click selector="{{StorefrontProductActionSection.addToCart}}" stepKey="addToCart" />
95+
<waitForText userInput="You added $$createSimpleProduct.name$$ to your shopping cart." stepKey="waitForText"/>
96+
<click selector="{{StorefrontMinicartSection.showCart}}" stepKey="clickCart"/>
97+
<click selector="{{StorefrontMinicartSection.goToCheckout}}" stepKey="goToCheckout"/>
98+
<waitForElementVisible selector="{{StorefrontCustomerSignInPopupFormSection.email}}" stepKey="waitEmailFieldVisible"/>
99+
<fillField selector="{{StorefrontCustomerSignInPopupFormSection.email}}" userInput="{{Simple_US_Customer.email}}" stepKey="fillCustomerEmail"/>
100+
<fillField selector="{{StorefrontCustomerSignInPopupFormSection.password}}" userInput="incorrectPassword" stepKey="fillIncorrectCustomerPassword"/>
101+
<click selector="{{StorefrontCustomerSignInPopupFormSection.signIn}}" stepKey="clickSignIn"/>
102+
<waitForElementVisible selector="{{StorefrontCustomerSignInPopupFormSection.errorMessage}}" stepKey="seeErrorMessage"/>
103+
<waitForElementVisible selector="{{StorefrontCustomerSignInPopupFormSection.captchaField}}" stepKey="seeCaptchaField"/>
104+
<waitForElementVisible selector="{{StorefrontCustomerSignInPopupFormSection.captchaImg}}" stepKey="seeCaptchaImage"/>
105+
<waitForElementVisible selector="{{StorefrontCustomerSignInPopupFormSection.captchaReload}}" stepKey="seeCaptchaReloadButton"/>
106+
<reloadPage stepKey="refreshPage"/>
107+
<waitForPageLoad stepKey="waitForPageLoad2"/>
108+
<click selector="{{StorefrontMinicartSection.showCart}}" stepKey="clickCart2"/>
109+
<click selector="{{StorefrontMinicartSection.goToCheckout}}" stepKey="goToCheckout2"/>
110+
<waitForElementVisible selector="{{StorefrontCustomerSignInPopupFormSection.email}}" stepKey="waitEmailFieldVisible2"/>
111+
<waitForElementVisible selector="{{StorefrontCustomerSignInPopupFormSection.captchaField}}" stepKey="seeCaptchaField2"/>
112+
<waitForElementVisible selector="{{StorefrontCustomerSignInPopupFormSection.captchaImg}}" stepKey="seeCaptchaImage2"/>
113+
<waitForElementVisible selector="{{StorefrontCustomerSignInPopupFormSection.captchaReload}}" stepKey="seeCaptchaReloadButton2"/>
68114
</test>
69115
</tests>

app/code/Magento/Captcha/Test/Unit/Model/Checkout/ConfigProviderTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ public function testGetConfig($isRequired, $captchaGenerations, $expectedConfig)
7777
->will($this->returnValue('https://magento.com/captcha'));
7878

7979
$config = $this->model->getConfig();
80+
unset($config['captcha'][$this->formId]['timestamp']);
8081
$this->assertEquals($config, $expectedConfig);
8182
}
8283

app/code/Magento/Captcha/Test/Unit/Model/Customer/Plugin/AjaxLoginTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ public function testAroundExecuteIncorrectCaptcha()
158158
$this->resultJsonMock
159159
->expects($this->once())
160160
->method('setData')
161-
->with(['errors' => true, 'message' => __('Incorrect CAPTCHA'), 'captcha' => true])
161+
->with(['errors' => true, 'message' => __('Incorrect CAPTCHA')])
162162
->will($this->returnSelf());
163163

164164
$closure = function () {

app/code/Magento/Captcha/Test/Unit/Model/DefaultTest.php

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,13 @@ public function testIsCorrect()
183183
{
184184
self::$_defaultConfig['case_sensitive'] = '1';
185185
$this->assertFalse($this->_object->isCorrect('abcdef5'));
186-
$sessionData = ['user_create_word' => ['data' => 'AbCdEf5', 'expires' => time() + self::EXPIRE_FRAME]];
186+
$sessionData = [
187+
'user_create_word' => [
188+
'data' => 'AbCdEf5',
189+
'words' => 'AbCdEf5',
190+
'expires' => time() + self::EXPIRE_FRAME
191+
]
192+
];
187193
$this->_object->getSession()->setData($sessionData);
188194
self::$_defaultConfig['case_sensitive'] = '0';
189195
$this->assertTrue($this->_object->isCorrect('abcdef5'));
@@ -224,7 +230,7 @@ public function testGetWord()
224230
{
225231
$this->assertEquals($this->_object->getWord(), 'AbCdEf5');
226232
$this->_object->getSession()->setData(
227-
['user_create_word' => ['data' => 'AbCdEf5', 'expires' => time() - 360]]
233+
['user_create_word' => ['data' => 'AbCdEf5', 'words' => 'AbCdEf5','expires' => time() - 360]]
228234
);
229235
$this->assertNull($this->_object->getWord());
230236
}
@@ -247,7 +253,13 @@ protected function _getSessionStub()
247253
->getMock();
248254
$session->expects($this->any())->method('isLoggedIn')->will($this->returnValue(false));
249255

250-
$session->setData(['user_create_word' => ['data' => 'AbCdEf5', 'expires' => time() + self::EXPIRE_FRAME]]);
256+
$session->setData([
257+
'user_create_word' => [
258+
'data' => 'AbCdEf5',
259+
'words' => 'AbCdEf5',
260+
'expires' => time() + self::EXPIRE_FRAME
261+
]
262+
]);
251263
return $session;
252264
}
253265

app/code/Magento/Captcha/etc/db_schema.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
1010
<table name="captcha_log" resource="default" engine="innodb" comment="Count Login Attempts">
1111
<column xsi:type="varchar" name="type" nullable="false" length="32" comment="Type"/>
12-
<column xsi:type="varchar" name="value" nullable="false" length="32" comment="Value"/>
12+
<column xsi:type="varchar" name="value" nullable="false" length="255" comment="Value"/>
1313
<column xsi:type="int" name="count" padding="10" unsigned="true" nullable="false" identity="false" default="0"
1414
comment="Count"/>
1515
<column xsi:type="timestamp" name="updated_at" on_update="false" nullable="true" comment="Update Time"/>

app/code/Magento/Captcha/etc/frontend/di.xml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,18 @@
2020
</argument>
2121
</arguments>
2222
</type>
23+
<type name="Magento\Captcha\CustomerData\Captcha">
24+
<arguments>
25+
<argument name="formIds" xsi:type="array">
26+
<item name="user_login" xsi:type="string">user_login</item>
27+
</argument>
28+
</arguments>
29+
</type>
30+
<type name="Magento\Customer\CustomerData\SectionPoolInterface">
31+
<arguments>
32+
<argument name="sectionSourceMap" xsi:type="array">
33+
<item name="captcha" xsi:type="string">Magento\Captcha\CustomerData\Captcha</item>
34+
</argument>
35+
</arguments>
36+
</type>
2337
</config>

0 commit comments

Comments
 (0)