From c8ad86753649430c3531a0a22ab92e29df338a8f Mon Sep 17 00:00:00 2001 From: Pavel Bystritsky Date: Fri, 20 Mar 2020 13:44:07 +0200 Subject: [PATCH 01/17] security-package/issues/154: Add reCAPTCHA support for customer acccount edit. --- .../Observer/EditCustomerObserver.php | 70 +++++++++++++++++++ ReCaptchaCustomer/etc/adminhtml/system.xml | 5 ++ ReCaptchaCustomer/etc/config.xml | 1 + ReCaptchaCustomer/etc/frontend/events.xml | 3 + .../frontend/layout/customer_account_edit.xml | 29 ++++++++ .../view/frontend/web/css/source/_module.less | 2 +- 6 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 ReCaptchaCustomer/Observer/EditCustomerObserver.php create mode 100644 ReCaptchaCustomer/view/frontend/layout/customer_account_edit.xml diff --git a/ReCaptchaCustomer/Observer/EditCustomerObserver.php b/ReCaptchaCustomer/Observer/EditCustomerObserver.php new file mode 100644 index 00000000..88c6beec --- /dev/null +++ b/ReCaptchaCustomer/Observer/EditCustomerObserver.php @@ -0,0 +1,70 @@ +url = $url; + $this->isCaptchaEnabled = $isCaptchaEnabled; + $this->requestHandler = $requestHandler; + } + + /** + * @param Observer $observer + * @return void + * @throws \Magento\Framework\Exception\LocalizedException + */ + public function execute(Observer $observer): void + { + $key = 'customer_edit'; + if ($this->isCaptchaEnabled->isCaptchaEnabledFor($key)) { + /** @var Action $controller */ + $controller = $observer->getControllerAction(); + $request = $controller->getRequest(); + $response = $controller->getResponse(); + $redirectOnFailureUrl = $this->url->getUrl('*/*/edit', ['_secure' => true]); + + $this->requestHandler->execute($key, $request, $response, $redirectOnFailureUrl); + } + } +} diff --git a/ReCaptchaCustomer/etc/adminhtml/system.xml b/ReCaptchaCustomer/etc/adminhtml/system.xml index c83b515a..2d109bd9 100644 --- a/ReCaptchaCustomer/etc/adminhtml/system.xml +++ b/ReCaptchaCustomer/etc/adminhtml/system.xml @@ -25,6 +25,11 @@ Magento\ReCaptchaApi\Model\OptionSource\Type + + + Magento\ReCaptchaApi\Model\OptionSource\Type + diff --git a/ReCaptchaCustomer/etc/config.xml b/ReCaptchaCustomer/etc/config.xml index e3ead5e4..11ee5351 100644 --- a/ReCaptchaCustomer/etc/config.xml +++ b/ReCaptchaCustomer/etc/config.xml @@ -13,6 +13,7 @@ + diff --git a/ReCaptchaCustomer/etc/frontend/events.xml b/ReCaptchaCustomer/etc/frontend/events.xml index aec4e0a7..8166d9b6 100644 --- a/ReCaptchaCustomer/etc/frontend/events.xml +++ b/ReCaptchaCustomer/etc/frontend/events.xml @@ -16,6 +16,9 @@ + + + diff --git a/ReCaptchaCustomer/view/frontend/layout/customer_account_edit.xml b/ReCaptchaCustomer/view/frontend/layout/customer_account_edit.xml new file mode 100644 index 00000000..11a1de9a --- /dev/null +++ b/ReCaptchaCustomer/view/frontend/layout/customer_account_edit.xml @@ -0,0 +1,29 @@ + + + + + + + + customer_edit + + + + Magento_ReCaptchaFrontendUi/js/reCaptcha + + + + + + + + diff --git a/ReCaptchaCustomer/view/frontend/web/css/source/_module.less b/ReCaptchaCustomer/view/frontend/web/css/source/_module.less index 8ef62177..997ed413 100644 --- a/ReCaptchaCustomer/view/frontend/web/css/source/_module.less +++ b/ReCaptchaCustomer/view/frontend/web/css/source/_module.less @@ -2,7 +2,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -.login-container, .form-login { +.login-container, .form-login, .form-edit-account { .g-recaptcha { margin-bottom: 10px !important; } From 53d8db2de47c8338b65f836fb2be2b11ce1c1d70 Mon Sep 17 00:00:00 2001 From: Oleksandr Miroshnichenko Date: Tue, 2 Jun 2020 17:46:28 -0500 Subject: [PATCH 02/17] PB-582: Fix Page Builder builds --- TwoFactorAuth/Test/Mftf/Data/UserRoleData.xml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 TwoFactorAuth/Test/Mftf/Data/UserRoleData.xml diff --git a/TwoFactorAuth/Test/Mftf/Data/UserRoleData.xml b/TwoFactorAuth/Test/Mftf/Data/UserRoleData.xml new file mode 100644 index 00000000..16a4bca3 --- /dev/null +++ b/TwoFactorAuth/Test/Mftf/Data/UserRoleData.xml @@ -0,0 +1,15 @@ + + + + + + + Magento_TwoFactorAuth::tfa + + + From b122b3e4637379117c392f9b8c5a688c9fb597b0 Mon Sep 17 00:00:00 2001 From: Pavel Bystritsky Date: Tue, 9 Jun 2020 15:58:38 +0300 Subject: [PATCH 03/17] security-package/issues/234: Auto-fill browser functionality can override API keys for reCAPCTH and block Admin Panel access --- ReCaptchaVersion2Checkbox/etc/adminhtml/system.xml | 6 ++++-- ReCaptchaVersion2Checkbox/etc/config.xml | 2 ++ ReCaptchaVersion2Invisible/etc/adminhtml/system.xml | 6 ++++-- ReCaptchaVersion2Invisible/etc/config.xml | 2 ++ ReCaptchaVersion3Invisible/etc/adminhtml/system.xml | 6 ++++-- ReCaptchaVersion3Invisible/etc/config.xml | 2 ++ 6 files changed, 18 insertions(+), 6 deletions(-) diff --git a/ReCaptchaVersion2Checkbox/etc/adminhtml/system.xml b/ReCaptchaVersion2Checkbox/etc/adminhtml/system.xml index 6b89c488..0d4cdb04 100644 --- a/ReCaptchaVersion2Checkbox/etc/adminhtml/system.xml +++ b/ReCaptchaVersion2Checkbox/etc/adminhtml/system.xml @@ -6,9 +6,10 @@ showInStore="0"> - + Magento\Config\Model\Config\Backend\Encrypted - + Magento\Config\Model\Config\Backend\Encrypted + normal light @@ -19,6 +20,7 @@ + normal light diff --git a/ReCaptchaVersion2Invisible/etc/adminhtml/system.xml b/ReCaptchaVersion2Invisible/etc/adminhtml/system.xml index 470ba0bf..cff4f217 100644 --- a/ReCaptchaVersion2Invisible/etc/adminhtml/system.xml +++ b/ReCaptchaVersion2Invisible/etc/adminhtml/system.xml @@ -6,9 +6,10 @@ showInStore="0"> - + Magento\Config\Model\Config\Backend\Encrypted - + Magento\Config\Model\Config\Backend\Encrypted + inline light @@ -19,6 +20,7 @@ + inline light diff --git a/ReCaptchaVersion3Invisible/etc/adminhtml/system.xml b/ReCaptchaVersion3Invisible/etc/adminhtml/system.xml index 379b6156..66afc6ea 100644 --- a/ReCaptchaVersion3Invisible/etc/adminhtml/system.xml +++ b/ReCaptchaVersion3Invisible/etc/adminhtml/system.xml @@ -6,9 +6,10 @@ showInStore="0"> - + Magento\Config\Model\Config\Backend\Encrypted - + Magento\Config\Model\Config\Backend\Encrypted + 0.5 inline @@ -20,6 +21,7 @@ + 0.5 inline From fcfaebf7e5f881de104beebd4544355075e7a740 Mon Sep 17 00:00:00 2001 From: Pavel Bystritsky Date: Wed, 10 Jun 2020 20:44:18 +0300 Subject: [PATCH 04/17] security-package/issues/234: Auto-fill browser functionality can override API keys for reCAPCTH and block Admin Panel access - copyright fix. --- ReCaptchaVersion2Checkbox/etc/adminhtml/system.xml | 7 +++++++ ReCaptchaVersion2Invisible/etc/adminhtml/system.xml | 7 +++++++ ReCaptchaVersion3Invisible/etc/adminhtml/system.xml | 7 +++++++ 3 files changed, 21 insertions(+) diff --git a/ReCaptchaVersion2Checkbox/etc/adminhtml/system.xml b/ReCaptchaVersion2Checkbox/etc/adminhtml/system.xml index 0d4cdb04..f2c5124e 100644 --- a/ReCaptchaVersion2Checkbox/etc/adminhtml/system.xml +++ b/ReCaptchaVersion2Checkbox/etc/adminhtml/system.xml @@ -1,3 +1,10 @@ + + diff --git a/ReCaptchaVersion2Invisible/etc/adminhtml/system.xml b/ReCaptchaVersion2Invisible/etc/adminhtml/system.xml index cff4f217..66ca5d88 100644 --- a/ReCaptchaVersion2Invisible/etc/adminhtml/system.xml +++ b/ReCaptchaVersion2Invisible/etc/adminhtml/system.xml @@ -1,3 +1,10 @@ + + diff --git a/ReCaptchaVersion3Invisible/etc/adminhtml/system.xml b/ReCaptchaVersion3Invisible/etc/adminhtml/system.xml index 66afc6ea..eaa206bd 100644 --- a/ReCaptchaVersion3Invisible/etc/adminhtml/system.xml +++ b/ReCaptchaVersion3Invisible/etc/adminhtml/system.xml @@ -1,3 +1,10 @@ + + From cb7b8fc9698065d225633c1614e067fef9d2515e Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Mon, 15 Jun 2020 15:22:41 -0500 Subject: [PATCH 05/17] MQE-2194: fix mftf tests static check failures --- .../Mftf/ActionGroup/FillSecurityTxtConfigurationActionGroup.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/Securitytxt/Test/Mftf/ActionGroup/FillSecurityTxtConfigurationActionGroup.xml b/Securitytxt/Test/Mftf/ActionGroup/FillSecurityTxtConfigurationActionGroup.xml index 14a52f41..6b59f3ff 100644 --- a/Securitytxt/Test/Mftf/ActionGroup/FillSecurityTxtConfigurationActionGroup.xml +++ b/Securitytxt/Test/Mftf/ActionGroup/FillSecurityTxtConfigurationActionGroup.xml @@ -14,7 +14,6 @@ - From 42d27ea4381e43686e69d5766cfc380224c7ad93 Mon Sep 17 00:00:00 2001 From: Ji Lu Date: Mon, 15 Jun 2020 15:35:26 -0500 Subject: [PATCH 06/17] MQE-2194: fix mftf tests static check failures --- .../Mftf/ActionGroup/FillSecurityTxtConfigurationActionGroup.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/Securitytxt/Test/Mftf/ActionGroup/FillSecurityTxtConfigurationActionGroup.xml b/Securitytxt/Test/Mftf/ActionGroup/FillSecurityTxtConfigurationActionGroup.xml index 14a52f41..6b59f3ff 100644 --- a/Securitytxt/Test/Mftf/ActionGroup/FillSecurityTxtConfigurationActionGroup.xml +++ b/Securitytxt/Test/Mftf/ActionGroup/FillSecurityTxtConfigurationActionGroup.xml @@ -14,7 +14,6 @@ - From 00f9c9b4d78d9100b52c712b87228b837489099d Mon Sep 17 00:00:00 2001 From: Nathan Smith Date: Tue, 16 Jun 2020 12:18:55 -0500 Subject: [PATCH 07/17] MC-35119: U2F Key registration error in Chrome on Ubuntu --- TwoFactorAuth/Model/Provider/Engine/U2fKey/WebAuthn.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TwoFactorAuth/Model/Provider/Engine/U2fKey/WebAuthn.php b/TwoFactorAuth/Model/Provider/Engine/U2fKey/WebAuthn.php index c314f8ca..6553a38e 100644 --- a/TwoFactorAuth/Model/Provider/Engine/U2fKey/WebAuthn.php +++ b/TwoFactorAuth/Model/Provider/Engine/U2fKey/WebAuthn.php @@ -298,7 +298,7 @@ public function getPublicKeyFromRegistrationData(array $data): array return [ 'key' => $attestationObject['attestationData']['keyBytes'], 'id' => $credentialData['id'], - 'aaguid' => $attestationObject['attestationData']['aaguid'] ?? null + 'aaguid' => base64_encode($attestationObject['attestationData']['aaguid']) ?? null ]; } From 674b8db56e626978bc4feb57b06dde9655d5d239 Mon Sep 17 00:00:00 2001 From: Pavel Bystritsky Date: Tue, 2 Jun 2020 18:04:54 +0300 Subject: [PATCH 08/17] magento/security-package#224: Recaptcha badge is not shown on checkout login form if 'Invisible Badge Position' is 'Bottom Left/Right' Merge pull request #5738 from magento-honey-badgers/2.4-develop-241-sync [honey] MC-33700: TransportBuilder unable to send emails of Content-Type "text/plain" --- .../web/js/nonInlineReCaptchaRenderer.js | 46 +++++++++++++++++++ .../view/frontend/web/js/reCaptcha.js | 7 ++- 2 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 ReCaptchaFrontendUi/view/frontend/web/js/nonInlineReCaptchaRenderer.js diff --git a/ReCaptchaFrontendUi/view/frontend/web/js/nonInlineReCaptchaRenderer.js b/ReCaptchaFrontendUi/view/frontend/web/js/nonInlineReCaptchaRenderer.js new file mode 100644 index 00000000..66f54404 --- /dev/null +++ b/ReCaptchaFrontendUi/view/frontend/web/js/nonInlineReCaptchaRenderer.js @@ -0,0 +1,46 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'jquery' +], function ($) { + 'use strict'; + + var reCaptchaEntities = [], + initialized = false, + rendererRecaptchaId = 'recaptcha-invisible', + rendererReCaptcha = null; + + return { + add: function (reCaptchaEntity, parameters) { + if (parameters.size === 'invisible' && parameters.badge !== 'inline') { + if (!initialized) { + this._init(); + grecaptcha.render(rendererRecaptchaId, parameters); + setInterval(this._resolveVisibility, 100); + initialized = true; + } + + reCaptchaEntities.push(reCaptchaEntity); + } + }, + + _resolveVisibility: function () { + reCaptchaEntities.some( + (entity) => { + return entity.is(":visible") + // 900 is some magic z-index value of modal popups. + && (entity.closest("[data-role='modal']").length == 0 || entity.zIndex() > 900) + }) ? rendererReCaptcha.show() : rendererReCaptcha.hide(); + }, + + _init: function () { + rendererReCaptcha = $('
', { + 'id': rendererRecaptchaId + }); + $('body').append(rendererReCaptcha); + } + }; +}); diff --git a/ReCaptchaFrontendUi/view/frontend/web/js/reCaptcha.js b/ReCaptchaFrontendUi/view/frontend/web/js/reCaptcha.js index 63688881..14835df9 100644 --- a/ReCaptchaFrontendUi/view/frontend/web/js/reCaptcha.js +++ b/ReCaptchaFrontendUi/view/frontend/web/js/reCaptcha.js @@ -11,9 +11,10 @@ define( 'jquery', 'ko', 'Magento_ReCaptchaFrontendUi/js/registry', - 'Magento_ReCaptchaFrontendUi/js/reCaptchaScriptLoader' + 'Magento_ReCaptchaFrontendUi/js/reCaptchaScriptLoader', + 'Magento_ReCaptchaFrontendUi/js/nonInlineReCaptchaRenderer', ], - function (Component, $, ko, registry, reCaptchaLoader, undefined) { + function (Component, $, ko, registry, reCaptchaLoader,nonInlineReCaptchaRenderer, undefined) { 'use strict'; return Component.extend({ @@ -117,6 +118,8 @@ define( this.settings.rendering ); + nonInlineReCaptchaRenderer.add($reCaptcha, parameters); + // eslint-disable-next-line no-undef widgetId = grecaptcha.render(this.getReCaptchaId(), parameters); this.initParentForm($parentForm, widgetId); From 4ff78d97621810e17bbd6ee1c3eb843b8974e1cc Mon Sep 17 00:00:00 2001 From: Pavel Bystritsky Date: Tue, 16 Jun 2020 20:08:40 +0300 Subject: [PATCH 09/17] magento/security-package#224: Recaptcha badge is not shown on checkout login form if 'Invisible Badge Position' is 'Bottom Left/Right' --- .../web/js/nonInlineReCaptchaRenderer.js | 34 +++++++++++------- .../view/frontend/web/js/reCaptcha.js | 36 +++++++++---------- 2 files changed, 38 insertions(+), 32 deletions(-) diff --git a/ReCaptchaFrontendUi/view/frontend/web/js/nonInlineReCaptchaRenderer.js b/ReCaptchaFrontendUi/view/frontend/web/js/nonInlineReCaptchaRenderer.js index 66f54404..a0926a96 100644 --- a/ReCaptchaFrontendUi/view/frontend/web/js/nonInlineReCaptchaRenderer.js +++ b/ReCaptchaFrontendUi/view/frontend/web/js/nonInlineReCaptchaRenderer.js @@ -14,29 +14,39 @@ define([ rendererReCaptcha = null; return { + /** + * Add reCaptcha entity to checklist. + * + * @param {jQuery} reCaptchaEntity + * @param {Object} parameters + */ add: function (reCaptchaEntity, parameters) { - if (parameters.size === 'invisible' && parameters.badge !== 'inline') { - if (!initialized) { - this._init(); - grecaptcha.render(rendererRecaptchaId, parameters); - setInterval(this._resolveVisibility, 100); - initialized = true; - } - - reCaptchaEntities.push(reCaptchaEntity); + if (!initialized) { + this.init(); + grecaptcha.render(rendererRecaptchaId, parameters); + setInterval(this.resolveVisibility, 100); + initialized = true; } + + reCaptchaEntities.push(reCaptchaEntity); }, - _resolveVisibility: function () { + /** + * Show additional reCaptcha instance if any other should be visible, otherwise hide it. + */ + resolveVisibility: function () { reCaptchaEntities.some( (entity) => { return entity.is(":visible") // 900 is some magic z-index value of modal popups. - && (entity.closest("[data-role='modal']").length == 0 || entity.zIndex() > 900) + && (entity.closest("[data-role='modal']").length === 0 || entity.zIndex() > 900) }) ? rendererReCaptcha.show() : rendererReCaptcha.hide(); }, - _init: function () { + /** + * Initialize additional reCaptcha instance. + */ + init: function () { rendererReCaptcha = $('
', { 'id': rendererRecaptchaId }); diff --git a/ReCaptchaFrontendUi/view/frontend/web/js/reCaptcha.js b/ReCaptchaFrontendUi/view/frontend/web/js/reCaptcha.js index 14835df9..e17b91eb 100644 --- a/ReCaptchaFrontendUi/view/frontend/web/js/reCaptcha.js +++ b/ReCaptchaFrontendUi/view/frontend/web/js/reCaptcha.js @@ -14,7 +14,7 @@ define( 'Magento_ReCaptchaFrontendUi/js/reCaptchaScriptLoader', 'Magento_ReCaptchaFrontendUi/js/nonInlineReCaptchaRenderer', ], - function (Component, $, ko, registry, reCaptchaLoader,nonInlineReCaptchaRenderer, undefined) { + function (Component, $, ko, registry, reCaptchaLoader,nonInlineReCaptchaRenderer) { 'use strict'; return Component.extend({ @@ -23,7 +23,6 @@ define( template: 'Magento_ReCaptchaFrontendUi/reCaptcha', reCaptchaId: 'recaptcha' }, - _isApiRegistered: undefined, initialize: function () { this._super(); @@ -76,8 +75,7 @@ define( * Initialize reCAPTCHA after first rendering */ initCaptcha: function () { - var me = this, - $parentForm, + var $parentForm, $wrapper, $reCaptcha, widgetId, @@ -103,22 +101,23 @@ define( $reCaptcha.attr('id', this.getReCaptchaId()); $parentForm = $wrapper.parents('form'); - me = this; parameters = _.extend( { 'callback': function (token) { // jscs:ignore jsDoc - me.reCaptchaCallback(token); - me.validateReCaptcha(true); - }, + this.reCaptchaCallback(token); + this.validateReCaptcha(true); + }.bind(this), 'expired-callback': function () { - me.validateReCaptcha(false); - } + this.validateReCaptcha(false); + }.bind(this) }, this.settings.rendering ); - nonInlineReCaptchaRenderer.add($reCaptcha, parameters); + if (parameters.size === 'invisible' && parameters.badge !== 'inline') { + nonInlineReCaptchaRenderer.add($reCaptcha, parameters) + } // eslint-disable-next-line no-undef widgetId = grecaptcha.render(this.getReCaptchaId(), parameters); @@ -137,18 +136,17 @@ define( * @param {String} widgetId */ initParentForm: function (parentForm, widgetId) { - var me = this, - listeners; + var listeners; if (this.getIsInvisibleRecaptcha() && parentForm.length > 0) { parentForm.submit(function (event) { - if (!me.tokenField.value) { + if (!this.tokenField.value) { // eslint-disable-next-line no-undef grecaptcha.execute(widgetId); event.preventDefault(event); event.stopImmediatePropagation(); } - }); + }.bind(this)); // Move our (last) handler topmost. We need this to avoid submit bindings with ko. listeners = $._data(parentForm[0], 'events').submit; @@ -173,14 +171,12 @@ define( * Render reCAPTCHA */ renderReCaptcha: function () { - var me = this; - if (window.grecaptcha && window.grecaptcha.render) { // Check if reCAPTCHA is already loaded - me.initCaptcha(); + this.initCaptcha(); } else { // Wait for reCAPTCHA to be loaded $(window).on('recaptchaapiready', function () { - me.initCaptcha(); - }); + this.initCaptcha(); + }.bind(this)); } }, From 2c2008b35b89b173c57b6b36638a0547c496672e Mon Sep 17 00:00:00 2001 From: Pavel Bystritsky Date: Fri, 12 Jun 2020 12:38:21 +0300 Subject: [PATCH 10/17] magento/security-package#242: ReCAPTCHA v2 ("I am not a robot") for Newsletter Subscription displays with error. --- ReCaptchaNewsletter/etc/adminhtml/system.xml | 2 +- .../view/frontend/layout/default.xml | 7 ------- .../view/frontend/web/css/source/_module.less | 16 ++++++++++++++++ 3 files changed, 17 insertions(+), 8 deletions(-) create mode 100644 ReCaptchaNewsletter/view/frontend/web/css/source/_module.less diff --git a/ReCaptchaNewsletter/etc/adminhtml/system.xml b/ReCaptchaNewsletter/etc/adminhtml/system.xml index f70a2969..ca0109b6 100644 --- a/ReCaptchaNewsletter/etc/adminhtml/system.xml +++ b/ReCaptchaNewsletter/etc/adminhtml/system.xml @@ -12,7 +12,7 @@ - + If enabled, a badge will be displayed in every page. Magento\ReCaptchaAdminUi\Model\OptionSource\Type diff --git a/ReCaptchaNewsletter/view/frontend/layout/default.xml b/ReCaptchaNewsletter/view/frontend/layout/default.xml index 82c684a2..992d56d7 100644 --- a/ReCaptchaNewsletter/view/frontend/layout/default.xml +++ b/ReCaptchaNewsletter/view/frontend/layout/default.xml @@ -17,13 +17,6 @@ ifconfig="recaptcha_frontend/type_for/newsletter"> newsletter - - true - - bottomright - invisible - - diff --git a/ReCaptchaNewsletter/view/frontend/web/css/source/_module.less b/ReCaptchaNewsletter/view/frontend/web/css/source/_module.less new file mode 100644 index 00000000..563319cd --- /dev/null +++ b/ReCaptchaNewsletter/view/frontend/web/css/source/_module.less @@ -0,0 +1,16 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +.block.newsletter { + .field-recaptcha { + .field { + .control { + &:before { + content: none; + } + } + } + } +} From a31d7014c16c15a6697d094681b35d23f92e7d7b Mon Sep 17 00:00:00 2001 From: Pavel Bystritsky Date: Wed, 17 Jun 2020 00:10:57 +0300 Subject: [PATCH 11/17] Static tests fix. --- .../web/js/nonInlineReCaptchaRenderer.js | 16 +++++++++++++--- .../view/frontend/web/js/reCaptcha.js | 4 ++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/ReCaptchaFrontendUi/view/frontend/web/js/nonInlineReCaptchaRenderer.js b/ReCaptchaFrontendUi/view/frontend/web/js/nonInlineReCaptchaRenderer.js index a0926a96..10a77456 100644 --- a/ReCaptchaFrontendUi/view/frontend/web/js/nonInlineReCaptchaRenderer.js +++ b/ReCaptchaFrontendUi/view/frontend/web/js/nonInlineReCaptchaRenderer.js @@ -33,18 +33,28 @@ define([ /** * Show additional reCaptcha instance if any other should be visible, otherwise hide it. + * + * @private */ resolveVisibility: function () { reCaptchaEntities.some( - (entity) => { - return entity.is(":visible") + /** + * Check if reCaptcha instance is visible. + * + * @param {jQuery} entity + * @returns {Boolean} + */ + function (entity) { + return entity.is(':visible') && // 900 is some magic z-index value of modal popups. - && (entity.closest("[data-role='modal']").length === 0 || entity.zIndex() > 900) + (entity.closest('[data-role=\'modal\']').length === 0 || entity.zIndex() > 900) }) ? rendererReCaptcha.show() : rendererReCaptcha.hide(); }, /** * Initialize additional reCaptcha instance. + * + * @private */ init: function () { rendererReCaptcha = $('
', { diff --git a/ReCaptchaFrontendUi/view/frontend/web/js/reCaptcha.js b/ReCaptchaFrontendUi/view/frontend/web/js/reCaptcha.js index e17b91eb..2c951331 100644 --- a/ReCaptchaFrontendUi/view/frontend/web/js/reCaptcha.js +++ b/ReCaptchaFrontendUi/view/frontend/web/js/reCaptcha.js @@ -12,9 +12,9 @@ define( 'ko', 'Magento_ReCaptchaFrontendUi/js/registry', 'Magento_ReCaptchaFrontendUi/js/reCaptchaScriptLoader', - 'Magento_ReCaptchaFrontendUi/js/nonInlineReCaptchaRenderer', + 'Magento_ReCaptchaFrontendUi/js/nonInlineReCaptchaRenderer' ], - function (Component, $, ko, registry, reCaptchaLoader,nonInlineReCaptchaRenderer) { + function (Component, $, ko, registry, reCaptchaLoader, nonInlineReCaptchaRenderer) { 'use strict'; return Component.extend({ From bd4465a26488c35d64f860b484a90262f7b2387a Mon Sep 17 00:00:00 2001 From: Lena Orobei Date: Tue, 16 Jun 2020 16:27:08 -0500 Subject: [PATCH 12/17] Fix JS code styles --- .../web/js/nonInlineReCaptchaRenderer.js | 12 +++++----- .../view/frontend/web/js/reCaptcha.js | 22 ++++++++++++------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/ReCaptchaFrontendUi/view/frontend/web/js/nonInlineReCaptchaRenderer.js b/ReCaptchaFrontendUi/view/frontend/web/js/nonInlineReCaptchaRenderer.js index a0926a96..ab622f45 100644 --- a/ReCaptchaFrontendUi/view/frontend/web/js/nonInlineReCaptchaRenderer.js +++ b/ReCaptchaFrontendUi/view/frontend/web/js/nonInlineReCaptchaRenderer.js @@ -3,6 +3,7 @@ * See COPYING.txt for license details. */ +/* global grecaptcha */ define([ 'jquery' ], function ($) { @@ -35,12 +36,11 @@ define([ * Show additional reCaptcha instance if any other should be visible, otherwise hide it. */ resolveVisibility: function () { - reCaptchaEntities.some( - (entity) => { - return entity.is(":visible") - // 900 is some magic z-index value of modal popups. - && (entity.closest("[data-role='modal']").length === 0 || entity.zIndex() > 900) - }) ? rendererReCaptcha.show() : rendererReCaptcha.hide(); + reCaptchaEntities.some(function (entity) { + return entity.is(':visible') && + // 900 is some magic z-index value of modal popups. + (entity.closest('[data-role=\'modal\']').length === 0 || entity.zIndex() > 900); + }) ? rendererReCaptcha.show() : rendererReCaptcha.hide(); }, /** diff --git a/ReCaptchaFrontendUi/view/frontend/web/js/reCaptcha.js b/ReCaptchaFrontendUi/view/frontend/web/js/reCaptcha.js index e17b91eb..ddd627f2 100644 --- a/ReCaptchaFrontendUi/view/frontend/web/js/reCaptcha.js +++ b/ReCaptchaFrontendUi/view/frontend/web/js/reCaptcha.js @@ -3,18 +3,17 @@ * See COPYING.txt for license details. */ -/* eslint-disable no-undef */ -// jscs:disable jsDoc +/* global grecaptcha */ define( [ 'uiComponent', 'jquery', 'ko', + 'underscore', 'Magento_ReCaptchaFrontendUi/js/registry', 'Magento_ReCaptchaFrontendUi/js/reCaptchaScriptLoader', - 'Magento_ReCaptchaFrontendUi/js/nonInlineReCaptchaRenderer', - ], - function (Component, $, ko, registry, reCaptchaLoader,nonInlineReCaptchaRenderer) { + 'Magento_ReCaptchaFrontendUi/js/nonInlineReCaptchaRenderer' + ], function (Component, $, ko, _, registry, reCaptchaLoader, nonInlineReCaptchaRenderer) { 'use strict'; return Component.extend({ @@ -24,6 +23,9 @@ define( reCaptchaId: 'recaptcha' }, + /** + * @inheritdoc + */ initialize: function () { this._super(); this._loadApi(); @@ -116,7 +118,7 @@ define( ); if (parameters.size === 'invisible' && parameters.badge !== 'inline') { - nonInlineReCaptchaRenderer.add($reCaptcha, parameters) + nonInlineReCaptchaRenderer.add($reCaptcha, parameters); } // eslint-disable-next-line no-undef @@ -161,6 +163,11 @@ define( } }, + /** + * Validates reCAPTCHA + * @param {*} state + * @returns {jQuery} + */ validateReCaptcha: function (state) { if (!this.getIsInvisibleRecaptcha()) { return $(document).find('input[type=checkbox].required-captcha').prop('checked', state); @@ -188,5 +195,4 @@ define( return this.reCaptchaId; } }); - } -); + }); From cfefd376b6a6828f6a8c26021d9fedda40f44bd1 Mon Sep 17 00:00:00 2001 From: Nathan Smith Date: Wed, 17 Jun 2020 11:58:53 -0500 Subject: [PATCH 13/17] MC-35119: U2F Key registration error in Chrome on Ubuntu --- TwoFactorAuth/Model/Provider/Engine/U2fKey/WebAuthn.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/TwoFactorAuth/Model/Provider/Engine/U2fKey/WebAuthn.php b/TwoFactorAuth/Model/Provider/Engine/U2fKey/WebAuthn.php index 6553a38e..e9e499d2 100644 --- a/TwoFactorAuth/Model/Provider/Engine/U2fKey/WebAuthn.php +++ b/TwoFactorAuth/Model/Provider/Engine/U2fKey/WebAuthn.php @@ -298,7 +298,9 @@ public function getPublicKeyFromRegistrationData(array $data): array return [ 'key' => $attestationObject['attestationData']['keyBytes'], 'id' => $credentialData['id'], - 'aaguid' => base64_encode($attestationObject['attestationData']['aaguid']) ?? null + 'aaguid' => empty($attestationObject['attestationData']['aaguid']) + ? null + : base64_encode($attestationObject['attestationData']['aaguid']) ]; } From e390f83b5a7803e70f64a4289f7564312e18b60d Mon Sep 17 00:00:00 2001 From: Pavel Bystritsky Date: Wed, 22 Jul 2020 12:48:30 +0300 Subject: [PATCH 14/17] MC-35563: Unexpected reCAPTCHA Badge style appear when loading product page. --- .../view/frontend/web/js/nonInlineReCaptchaRenderer.js | 1 + 1 file changed, 1 insertion(+) diff --git a/ReCaptchaFrontendUi/view/frontend/web/js/nonInlineReCaptchaRenderer.js b/ReCaptchaFrontendUi/view/frontend/web/js/nonInlineReCaptchaRenderer.js index ab622f45..b9f16c2e 100644 --- a/ReCaptchaFrontendUi/view/frontend/web/js/nonInlineReCaptchaRenderer.js +++ b/ReCaptchaFrontendUi/view/frontend/web/js/nonInlineReCaptchaRenderer.js @@ -50,6 +50,7 @@ define([ rendererReCaptcha = $('
', { 'id': rendererRecaptchaId }); + rendererReCaptcha.hide(); $('body').append(rendererReCaptcha); } }; From dfa87e914e85e16c015f9eefb63b6025571c533d Mon Sep 17 00:00:00 2001 From: Valerii Naida Date: Wed, 22 Jul 2020 19:03:38 -0500 Subject: [PATCH 15/17] security-package/issues/154: Add reCAPTCHA support for customer account edit --- ReCaptchaCustomer/Observer/EditCustomerObserver.php | 6 +++++- ReCaptchaCustomer/view/frontend/web/css/source/_module.less | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ReCaptchaCustomer/Observer/EditCustomerObserver.php b/ReCaptchaCustomer/Observer/EditCustomerObserver.php index 88c6beec..6ab19f0e 100644 --- a/ReCaptchaCustomer/Observer/EditCustomerObserver.php +++ b/ReCaptchaCustomer/Observer/EditCustomerObserver.php @@ -15,7 +15,9 @@ use Magento\ReCaptchaUi\Model\RequestHandlerInterface; /** - * EditCustomerObserver + * NewsletterObserver + * + * Process the response during customer account editing */ class EditCustomerObserver implements ObserverInterface { @@ -50,6 +52,8 @@ public function __construct( } /** + * @inheritdoc + * * @param Observer $observer * @return void * @throws \Magento\Framework\Exception\LocalizedException diff --git a/ReCaptchaCustomer/view/frontend/web/css/source/_module.less b/ReCaptchaCustomer/view/frontend/web/css/source/_module.less index 997ed413..f2958ae5 100644 --- a/ReCaptchaCustomer/view/frontend/web/css/source/_module.less +++ b/ReCaptchaCustomer/view/frontend/web/css/source/_module.less @@ -2,7 +2,9 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -.login-container, .form-login, .form-edit-account { +.login-container, +.form-login, +.form-edit-account { .g-recaptcha { margin-bottom: 10px !important; } From 3e798f95e00de52d9eeaa6686ef51257310216ad Mon Sep 17 00:00:00 2001 From: Pavel Bystritsky Date: Thu, 23 Jul 2020 10:42:44 +0300 Subject: [PATCH 16/17] security-package/issues/154: Add reCAPTCHA support for customer account edit. --- ReCaptchaCustomer/etc/adminhtml/system.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReCaptchaCustomer/etc/adminhtml/system.xml b/ReCaptchaCustomer/etc/adminhtml/system.xml index e16615ce..27b3bd28 100644 --- a/ReCaptchaCustomer/etc/adminhtml/system.xml +++ b/ReCaptchaCustomer/etc/adminhtml/system.xml @@ -28,7 +28,7 @@ - Magento\ReCaptchaApi\Model\OptionSource\Type + Magento\ReCaptchaAdminUi\Model\OptionSource\Type From 8ebc157793f23bae5e40ac509e81db45f6af5202 Mon Sep 17 00:00:00 2001 From: Pavel Bystritsky Date: Mon, 3 Aug 2020 16:53:25 +0300 Subject: [PATCH 17/17] magento/security-package#260: Cover reCAPTCHA for customer account edit with integration tests. --- .../Test/Integration/EditFromTest.php | 316 ++++++++++++++++++ 1 file changed, 316 insertions(+) create mode 100644 ReCaptchaCustomer/Test/Integration/EditFromTest.php diff --git a/ReCaptchaCustomer/Test/Integration/EditFromTest.php b/ReCaptchaCustomer/Test/Integration/EditFromTest.php new file mode 100644 index 00000000..b62e0983 --- /dev/null +++ b/ReCaptchaCustomer/Test/Integration/EditFromTest.php @@ -0,0 +1,316 @@ +mutableScopeConfig = $this->_objectManager->get(MutableScopeConfig::class); + $this->formKey = $this->_objectManager->get(FormKey::class); + $this->customerRepository = $this->_objectManager->get(CustomerRepositoryInterface::class); + $this->session = $this->_objectManager->get(Session::class); + $this->url = $this->_objectManager->get(UrlInterface::class); + + $this->captchaValidationResultMock = $this->createMock(ValidationResult::class); + $captchaValidationResultMock = $this->createMock(Validator::class); + $captchaValidationResultMock->expects($this->any()) + ->method('isValid') + ->willReturn($this->captchaValidationResultMock); + $this->_objectManager->addSharedInstance($captchaValidationResultMock, Validator::class); + } + + /** + * @magentoConfigFixture default_store customer/captcha/enable 0 + * @magentoConfigFixture base_website recaptcha_frontend/type_invisible/public_key test_public_key + * @magentoConfigFixture base_website recaptcha_frontend/type_invisible/private_key test_private_key + */ + public function testGetRequestIfReCaptchaIsDisabled(): void + { + $this->setConfig(false, 'test_public_key', 'test_private_key'); + + $this->checkSuccessfulGetResponse(); + } + + /** + * @magentoConfigFixture default_store customer/captcha/enable 0 + * @magentoConfigFixture base_website recaptcha_frontend/type_for/customer_edit invisible + * + * It's needed for proper work of "ifconfig" in layout during tests running + * @magentoConfigFixture default_store recaptcha_frontend/type_for/customer_edit invisible + */ + public function testGetRequestIfReCaptchaKeysAreNotConfigured(): void + { + $this->setConfig(true, null, null); + + $this->checkSuccessfulGetResponse(); + } + + /** + * @magentoConfigFixture default_store customer/captcha/enable 0 + * @magentoConfigFixture base_website recaptcha_frontend/type_invisible/public_key test_public_key + * @magentoConfigFixture base_website recaptcha_frontend/type_invisible/private_key test_private_key + * @magentoConfigFixture base_website recaptcha_frontend/type_for/customer_edit invisible + * + * It's needed for proper work of "ifconfig" in layout during tests running + * @magentoConfigFixture default_store recaptcha_frontend/type_for/customer_edit invisible + */ + public function testGetRequestIfReCaptchaIsEnabled(): void + { + $this->setConfig(true, 'test_public_key', 'test_private_key'); + + $this->checkSuccessfulGetResponse(true); + } + + /** + * @magentoConfigFixture default_store customer/captcha/enable 0 + * @magentoConfigFixture base_website recaptcha_frontend/type_invisible/public_key test_public_key + * @magentoConfigFixture base_website recaptcha_frontend/type_invisible/private_key test_private_key + */ + public function testPostRequestIfReCaptchaIsDisabled(): void + { + $this->setConfig(false, 'test_public_key', 'test_private_key'); + + $this->checkSuccessfulPostResponse(); + } + + /** + * @magentoConfigFixture default_store customer/captcha/enable 0 + * @magentoConfigFixture base_website recaptcha_frontend/type_for/customer_edit invisible + */ + public function testPostRequestIfReCaptchaKeysAreNotConfigured(): void + { + $this->setConfig(true, null, null); + + $this->checkSuccessfulPostResponse(); + } + + /** + * @magentoConfigFixture default_store customer/captcha/enable 0 + * @magentoConfigFixture base_website recaptcha_frontend/type_invisible/public_key test_public_key + * @magentoConfigFixture base_website recaptcha_frontend/type_invisible/private_key test_private_key + * @magentoConfigFixture base_website recaptcha_frontend/type_for/customer_edit invisible + */ + public function testPostRequestWithSuccessfulReCaptchaValidation(): void + { + $this->setConfig(true, 'test_public_key', 'test_private_key'); + $this->captchaValidationResultMock->expects($this->once())->method('isValid')->willReturn(true); + + $this->checkSuccessfulPostResponse( + [CaptchaResponseResolverInterface::PARAM_RECAPTCHA => 'test'] + ); + } + + /** + * @magentoConfigFixture default_store customer/captcha/enable 0 + * @magentoConfigFixture base_website recaptcha_frontend/type_invisible/public_key test_public_key + * @magentoConfigFixture base_website recaptcha_frontend/type_invisible/private_key test_private_key + * @magentoConfigFixture base_website recaptcha_frontend/type_for/customer_edit invisible + */ + public function testPostRequestIfReCaptchaParameterIsMissed(): void + { + $this->setConfig(true, 'test_public_key', 'test_private_key'); + + $this->checkFailedPostResponse(); + } + + /** + * @magentoConfigFixture default_store customer/captcha/enable 0 + * @magentoConfigFixture base_website recaptcha_frontend/type_invisible/public_key test_public_key + * @magentoConfigFixture base_website recaptcha_frontend/type_invisible/private_key test_private_key + * @magentoConfigFixture base_website recaptcha_frontend/type_for/customer_edit invisible + */ + public function testPostRequestWithFailedReCaptchaValidation(): void + { + $this->setConfig(true, 'test_public_key', 'test_private_key'); + $this->captchaValidationResultMock->expects($this->once())->method('isValid')->willReturn(false); + + $this->checkFailedPostResponse( + [CaptchaResponseResolverInterface::PARAM_RECAPTCHA => 'test'] + ); + } + + /** + * @param bool $shouldContainReCaptcha + * @return void + */ + private function checkSuccessfulGetResponse($shouldContainReCaptcha = false): void + { + $this->session->loginById(1); + $this->dispatch('customer/account/edit'); + $content = $this->getResponse()->getBody(); + + self::assertNotEmpty($content); + + $shouldContainReCaptcha + ? $this->assertStringContainsString('field-recaptcha', $content) + : $this->assertStringNotContainsString('field-recaptcha', $content); + + self::assertEmpty($this->getSessionMessages(MessageInterface::TYPE_ERROR)); + } + + /** + * @param array $postValues + * @return void + */ + private function checkSuccessfulPostResponse(array $postValues = []): void + { + $this->session->loginById(1); + $this->makePostRequest($postValues); + + $this->assertRedirect(self::equalTo($this->url->getRouteUrl('customer/account'))); + self::assertEmpty($this->getSessionMessages(MessageInterface::TYPE_ERROR)); + + $customer = $this->customerRepository->getById(1); + $this->assertEquals('Test First Name', $customer->getFirstname()); + $this->assertEquals('Test Last Name', $customer->getLastname()); + $this->assertEquals('customer@example.com', $customer->getEmail()); + } + + /** + * @param array $postValues + * @return void + */ + private function checkFailedPostResponse(array $postValues = []): void + { + $this->session->loginById(1); + $this->makePostRequest($postValues); + + $this->assertRedirect(self::stringStartsWith($this->url->getRouteUrl('customer/account/edit'))); + $this->assertSessionMessages( + self::equalTo(['reCAPTCHA verification failed']), + MessageInterface::TYPE_ERROR + ); + + $customer = $this->customerRepository->getById(1); + $this->assertEquals('John', $customer->getFirstname()); + $this->assertEquals('Smith', $customer->getLastname()); + $this->assertEquals('customer@example.com', $customer->getEmail()); + } + + /** + * @param array $postValues + * @return void + */ + private function makePostRequest(array $postValues = []): void + { + $this->getRequest() + ->setMethod(Http::METHOD_POST) + ->setPostValue( + array_replace_recursive( + [ + 'form_key' => $this->formKey->getFormKey(), + 'firstname' => 'Test First Name', + 'lastname' => 'Test Last Name', + ], + $postValues + ) + ); + + $this->dispatch('customer/account/editpost'); + } + + /** + * @param bool $isEnabled + * @param string|null $public + * @param string|null $private + * @return void + */ + private function setConfig(bool $isEnabled, ?string $public, ?string $private): void + { + $this->mutableScopeConfig->setValue( + 'recaptcha_frontend/type_for/customer_edit', + $isEnabled ? 'invisible' : null, + ScopeInterface::SCOPE_WEBSITE + ); + $this->mutableScopeConfig->setValue( + 'recaptcha_frontend/type_invisible/public_key', + $public, + ScopeInterface::SCOPE_WEBSITE + ); + $this->mutableScopeConfig->setValue( + 'recaptcha_frontend/type_invisible/private_key', + $private, + ScopeInterface::SCOPE_WEBSITE + ); + } + + protected function tearDown(): void + { + parent::tearDown(); + + $this->mutableScopeConfig->setValue( + 'recaptcha_frontend/type_for/customer_edit', + null, + ScopeInterface::SCOPE_WEBSITE + ); + $this->mutableScopeConfig->setValue( + 'recaptcha_frontend/type_invisible/public_key', + null, + ScopeInterface::SCOPE_WEBSITE + ); + $this->mutableScopeConfig->setValue( + 'recaptcha_frontend/type_invisible/private_key', + null, + ScopeInterface::SCOPE_WEBSITE + ); + } +}