Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…package into develop
  • Loading branch information
mage-os-ci committed Sep 12, 2023
2 parents 872629f + 68488df commit 5722e40
Show file tree
Hide file tree
Showing 47 changed files with 2,208 additions and 384 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Welcome to the Magento Security Package community project!
## Overview

Magento security package provides a set of security-related features including two-factor authentication for admins, Google ReCAPTCHA support for various forms, and Security.txt to support vulnerability
disclosure practices.
disclosure practices.

## Documentation

Expand Down
6 changes: 3 additions & 3 deletions ReCaptchaCheckout/Block/LayoutProcessor/Checkout/Onepage.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,14 @@ public function process($jsLayout)
$key = 'place_order';
if ($this->isCaptchaEnabled->isCaptchaEnabledFor($key)) {
$jsLayout['components']['checkout']['children']['steps']['children']['billing-step']['children']
['payment']['children']['beforeMethods']['children']['place-order-recaptcha-container']['children']
['payment']['children']['payments-list']['children']['before-place-order']['children']
['place-order-recaptcha']['settings'] = $this->captchaUiConfigResolver->get($key);
} else {
if (isset($jsLayout['components']['checkout']['children']['steps']['children']['billing-step']['children']
['payment']['children']['beforeMethods']['children']['place-order-recaptcha-container']['children']
['payment']['children']['payments-list']['children']['before-place-order']['children']
['place-order-recaptcha'])) {
unset($jsLayout['components']['checkout']['children']['steps']['children']['billing-step']['children']
['payment']['children']['beforeMethods']['children']['place-order-recaptcha-container']
['payment']['children']['payments-list']['children']['before-place-order']
['children']['place-order-recaptcha']);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\ReCaptchaCheckout\Test\Unit\Block\LayoutProcessor\Checkout;

use Magento\Framework\DataObject;
use Magento\ReCaptchaCheckout\Block\LayoutProcessor\Checkout\Onepage;
use Magento\ReCaptchaUi\Model\IsCaptchaEnabledInterface;
use Magento\ReCaptchaUi\Model\UiConfigResolverInterface;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;

class OnepageTest extends TestCase
{
/**
* @var UiConfigResolverInterface|MockObject
*/
private $uiConfigResolver;

/**
* @var IsCaptchaEnabledInterface|MockObject
*/
private $isCaptchEnabled;

/**
* @var Onepage
*/
private $model;

/**
* @var array
*/
private $jsLayout = [
'components' => [
'checkout' => [
'children' => [
'steps' => [
'children' => [
'shipping-step' => [
'children' => [
'shippingAddress' => [
'children' => [
'customer-email' => [
'children' => [
'recaptcha' => []
]
]
]
]
]
],
'billing-step' => [
'children' => [
'payment' => [
'children' => [
'customer-email' => [
'children' => [
'recaptcha' => []
]
],
'payments-list' => [
'children' => [
'before-place-order' => [
'children' => [
'place-order-recaptcha' => []
]
]
]
]
]
]
]
]
]
],
'authentication' => [
'children' => [
'recaptcha' => []
]
]
]
]
]
];

/**
* @inheritdoc
*/
protected function setUp(): void
{
parent::setUp();
$this->uiConfigResolver = $this->getMockForAbstractClass(UiConfigResolverInterface::class);
$this->isCaptchEnabled = $this->getMockForAbstractClass(IsCaptchaEnabledInterface::class);
$this->model = new Onepage(
$this->uiConfigResolver,
$this->isCaptchEnabled
);
}

/**
* @dataProvider processDataProvider
*/
public function testProcess(array $mocks, array $expected): void
{
$this->uiConfigResolver->method('get')
->willReturnMap($mocks['uiConfigResolver']);
$this->isCaptchEnabled->method('isCaptchaEnabledFor')
->willReturnMap($mocks['isCaptchaEnabled']);
$prefix = 'components/checkout/children/';
$config = new DataObject($this->model->process($this->jsLayout));
$actual = [];
foreach (array_keys($expected) as $path) {
$actual[$path] = $config->getDataByPath($prefix.$path);
}
$this->assertSame($expected, $actual);
}

public function processDataProvider(): array
{
return [
[
[
'isCaptchaEnabled' => [
['customer_login', false],
['place_order', false],
],
'uiConfigResolver' => [
['customer_login', ['type' => 'invisible']],
['place_order', ['type' => 'robot']],
],
],
[
'steps/children/shipping-step/children/shippingAddress/children/customer-email/children' => [],
'steps/children/billing-step/children/payment/children/customer-email/children' => [],
'authentication/children' => [],
'steps/children/billing-step/children/payment/children/payments-list/children/before-place-order/' .
'children' => [],
]
],
[
[
'isCaptchaEnabled' => [
['customer_login', true],
['place_order', true],
],
'uiConfigResolver' => [
['customer_login', ['type' => 'invisible']],
['place_order', ['type' => 'robot']],
],
],
[
'steps/children/shipping-step/children/shippingAddress/children/' .
'customer-email/children' => ['recaptcha' => ['settings' => ['type' => 'invisible']]],
'steps/children/billing-step/children/payment/children/' .
'customer-email/children' => ['recaptcha' => ['settings' => ['type' => 'invisible']]],
'authentication/children' => ['recaptcha' => ['settings' => ['type' => 'invisible']]],
'steps/children/billing-step/children/payment/children/payments-list/children/before-place-order/' .
'children' => ['place-order-recaptcha' => ['settings' => ['type' => 'robot']]],
]
]
];
}
}
14 changes: 7 additions & 7 deletions ReCaptchaCheckout/view/frontend/layout/checkout_index_index.xml
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,18 @@
</item>
</item>
</item>
<item name="beforeMethods" xsi:type="array">
<item name="payments-list" xsi:type="array">
<item name="children" xsi:type="array">
<item name="place-order-recaptcha-container" xsi:type="array">
<item name="component" xsi:type="string">uiComponent</item>
<item name="template" xsi:type="string">Magento_ReCaptchaCheckout/payment-recaptcha-container</item>
<item name="displayArea" xsi:type="string">beforeMethods</item>
<item name="before-place-order" xsi:type="array">
<item name="children" xsi:type="array">
<item name="place-order-recaptcha" xsi:type="array">
<item name="component" xsi:type="string">Magento_ReCaptchaWebapiUi/js/webapiReCaptcha</item>
<item name="displayArea" xsi:type="string">place-order-recaptcha</item>
<item name="component" xsi:type="string">Magento_ReCaptchaCheckout/js/reCaptchaCheckout</item>
<item name="displayArea" xsi:type="string">before-place-order</item>
<item name="configSource" xsi:type="string">checkoutConfig</item>
<item name="reCaptchaId" xsi:type="string">recaptcha-checkout-place-order</item>
<item name="skipPayments" xsi:type="array">

</item>
</item>
</item>
</item>
Expand Down
27 changes: 21 additions & 6 deletions ReCaptchaCheckout/view/frontend/web/js/model/place-order-mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,20 @@ define([

return function (placeOrder) {
return wrapper.wrap(placeOrder, function (originalAction, serviceUrl, payload, messageContainer) {
var recaptchaDeferred;
var recaptchaDeferred,
reCaptchaId,
$activeReCaptcha;

if (recaptchaRegistry.triggers.hasOwnProperty('recaptcha-checkout-place-order')) {
$activeReCaptcha = $('.recaptcha-checkout-place-order:visible .g-recaptcha');

if ($activeReCaptcha.length > 0) {
reCaptchaId = $activeReCaptcha.last().attr('id');
}

if (reCaptchaId !== undefined && recaptchaRegistry.triggers.hasOwnProperty(reCaptchaId)) {
//ReCaptcha is present for checkout
recaptchaDeferred = $.Deferred();
recaptchaRegistry.addListener('recaptcha-checkout-place-order', function (token) {
recaptchaRegistry.addListener(reCaptchaId, function (token) {
//Add reCaptcha value to place-order request and resolve deferred with the API call results
payload.xReCaptchaValue = token;
originalAction(serviceUrl, payload, messageContainer).done(function () {
Expand All @@ -29,9 +37,16 @@ define([
});
});
//Trigger ReCaptcha validation
recaptchaRegistry.triggers['recaptcha-checkout-place-order']();
//remove listener so that place order action is only triggered by the 'Place Order' button
recaptchaRegistry.removeListener('recaptcha-checkout-place-order');
recaptchaRegistry.triggers[reCaptchaId]();

if (
!recaptchaRegistry._isInvisibleType.hasOwnProperty(reCaptchaId) ||
recaptchaRegistry._isInvisibleType[reCaptchaId] === false
) {
//remove listener so that place order action is only triggered by the 'Place Order' button
recaptchaRegistry.removeListener(reCaptchaId);
}

return recaptchaDeferred;
}

Expand Down
80 changes: 80 additions & 0 deletions ReCaptchaCheckout/view/frontend/web/js/reCaptchaCheckout.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/

define(
[
'Magento_ReCaptchaWebapiUi/js/webapiReCaptcha',
'jquery'
],
function (Component, $) {
'use strict';

var reCaptchaIds = new WeakMap(),
uuid = 0;

return Component.extend({
defaults: {
template: 'Magento_ReCaptchaCheckout/reCaptcha',
skipPayments: [] // List of payment methods that do not require this reCaptcha
},

/**
* Render reCAPTCHA for payment method
*
* @param {Object} method
*/
renderReCaptchaFor: function (method) {
var reCaptcha;

if (this.isCheckoutReCaptchaRequiredFor(method)) {
reCaptcha = $.extend(true, {}, this, {reCaptchaId: this.getReCaptchaIdFor(method)});
reCaptcha.renderReCaptcha();
}
},

/**
* Get reCAPTCHA ID for payment method
*
* @param {Object} method
* @returns {String}
*/
getReCaptchaIdFor: function (method) {
if (!reCaptchaIds.has(method)) {
reCaptchaIds.set(method, this.getReCaptchaId() + '-' + uuid++);
}
return reCaptchaIds.get(method);
},

/**
* Check whether checkout reCAPTCHA is required for payment method
*
* @param {Object} method
* @returns {Boolean}
*/
isCheckoutReCaptchaRequiredFor: function (method) {
return !this.skipPayments || !this.skipPayments.hasOwnProperty(method.getCode());
},

/**
* @inheritdoc
*/
initCaptcha: function () {
var $wrapper,
$recaptchaResponseInput;

this._super();
// Since there will be multiple reCaptcha in the payment form,
// they may override each other if the form data is serialized and submitted.
// Instead, the reCaptcha response will be collected in the callback: reCaptchaCallback()
// and sent in the request header X-ReCaptcha
$wrapper = $('#' + this.getReCaptchaId() + '-wrapper');
$recaptchaResponseInput = $wrapper.find('[name=g-recaptcha-response]');
if ($recaptchaResponseInput.length) {
$recaptchaResponseInput.prop('disabled', true);
}
}
});
}
);
28 changes: 28 additions & 0 deletions ReCaptchaCheckout/view/frontend/web/template/reCaptcha.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<!--
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-->
<!-- ko if: (isCheckoutReCaptchaRequiredFor($parents[1]))-->
<div class="recaptcha-checkout-place-order" data-bind="{
attr: {
'id': getReCaptchaIdFor($parents[1]) + '-wrapper'
},
'afterRender': renderReCaptchaFor($parents[1])
}">
<div class="g-recaptcha"></div>
<!-- ko if: (!getIsInvisibleRecaptcha()) -->
<div class="field">
<div class="control">
<input type="checkbox"
value=""
class="required-captcha checkbox"
name="recaptcha-validate-"
data-validate="{required:true}"
tabindex="-1">
</div>
</div>
<!-- /ko -->
</div>
<!-- /ko -->
2 changes: 1 addition & 1 deletion ReCaptchaCheckoutSalesRule/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ Google reCAPTCHA ensures that a human being, rather than a computer (or “bot

This module provides the reCAPTCHA implementations related to coupon code apply action on checkout cart & payment.

For more information please visit the Magento document for reCAPTCHA.
For more information please visit the Magento document for reCAPTCHA.
Loading

0 comments on commit 5722e40

Please sign in to comment.