diff --git a/app/code/Magento/AdminAnalytics/composer.json b/app/code/Magento/AdminAnalytics/composer.json index db80a78a645c5..81a3bde775cdf 100644 --- a/app/code/Magento/AdminAnalytics/composer.json +++ b/app/code/Magento/AdminAnalytics/composer.json @@ -1,29 +1,31 @@ { "name": "magento/module-admin-analytics", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.3-p2", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-config": "*", - "magento/module-store": "*", - "magento/module-ui": "*", - "magento/module-release-notification": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-config": "101.1.*", + "magento/module-store": "101.0.*", + "magento/module-ui": "101.1.*", + "magento/module-release-notification": "100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { - "files": [ - "registration.php" - ], - "psr-4": { - "Magento\\AdminAnalytics\\": "" - } + "files": [ + "registration.php" + ], + "psr-4": { + "Magento\\AdminAnalytics\\": "" + } } } + diff --git a/app/code/Magento/AdminAnalytics/i18n/en_US.csv b/app/code/Magento/AdminAnalytics/i18n/en_US.csv new file mode 100644 index 0000000000000..fa17e425e13dd --- /dev/null +++ b/app/code/Magento/AdminAnalytics/i18n/en_US.csv @@ -0,0 +1,3 @@ +"Allow Adobe to collect usage data to improve user experience and offer in-product guidance", "Allow Adobe to collect usage data to improve user experience and offer in-product guidance" +"

By clicking on Allow, you agree that we may collect anonymous usage data from you to:

  1. Help us improve the Magento Admin user experience
  2. Provide interactive in-product guidance, such as technical support and tips to improve utilization of the product from within the Admin UI. This may include notifications of new features, product support/guidance, onboarding information, tooltips, and more.

All usage data that we collect for this purpose cannot be used to individually identify you and is used only to improve the Magento Admin UI and related products and services.

You can learn more and opt-out at any time by following the instructions in merchant documentation.

", "

By clicking on Allow, you agree that we may collect anonymous usage data from you to:

  1. Help us improve the Magento Admin user experience
  2. Provide interactive in-product guidance, such as technical support and tips to improve utilization of the product from within the Admin UI. This may include notifications of new features, product support/guidance, onboarding information, tooltips, and more.

All usage data that we collect for this purpose cannot be used to individually identify you and is used only to improve the Magento Admin UI and related products and services.

You can learn more and opt-out at any time by following the instructions in merchant documentation.

" + diff --git a/app/code/Magento/AdminAnalytics/view/adminhtml/layout/adminhtml_dashboard_index.xml b/app/code/Magento/AdminAnalytics/view/adminhtml/layout/adminhtml_dashboard_index.xml index 3069db1ecc2bb..ca14b20acae5e 100644 --- a/app/code/Magento/AdminAnalytics/view/adminhtml/layout/adminhtml_dashboard_index.xml +++ b/app/code/Magento/AdminAnalytics/view/adminhtml/layout/adminhtml_dashboard_index.xml @@ -19,4 +19,4 @@ - \ No newline at end of file + diff --git a/app/code/Magento/AdminAnalytics/view/adminhtml/ui_component/admin_usage_notification.xml b/app/code/Magento/AdminAnalytics/view/adminhtml/ui_component/admin_usage_notification.xml index fcd1c4ebbbcdf..b8196c8ae090e 100644 --- a/app/code/Magento/AdminAnalytics/view/adminhtml/ui_component/admin_usage_notification.xml +++ b/app/code/Magento/AdminAnalytics/view/adminhtml/ui_component/admin_usage_notification.xml @@ -49,7 +49,7 @@ true - + @@ -82,11 +82,7 @@ release-notification-text - Help us improve Magento Admin by allowing us to collect usage data.

-

All usage data that we collect for this purpose cannot be used to individually identify you and is used only to improve the Magento Admin and related products and services.

-

You can learn more and opt out at any time by following the instructions in merchant documentation.

-]]>
+ By clicking on Allow, you agree that we may collect anonymous usage data from you to:

All usage data that we collect for this purpose cannot be used to individually identify you and is used only to improve the Magento Admin UI and related products and services.

You can learn more and opt-out at any time by following the instructions in merchant documentation.

]]>
diff --git a/app/code/Magento/AdminNotification/composer.json b/app/code/Magento/AdminNotification/composer.json index d421fc869621b..c6d0d22d7fce0 100644 --- a/app/code/Magento/AdminNotification/composer.json +++ b/app/code/Magento/AdminNotification/composer.json @@ -1,24 +1,25 @@ { "name": "magento/module-admin-notification", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.6", "require": { "php": "~7.3.0||~7.4.0", "lib-libxml": "*", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-media-storage": "*", - "magento/module-store": "*", - "magento/module-ui": "*", - "magento/module-config": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-media-storage": "100.3.*", + "magento/module-store": "101.0.*", + "magento/module-ui": "101.1.*", + "magento/module-config": "101.1.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -28,3 +29,4 @@ } } } + diff --git a/app/code/Magento/AdvancedPricingImportExport/composer.json b/app/code/Magento/AdvancedPricingImportExport/composer.json index ea6a39fba2c3d..3c6dbb95b7fd1 100644 --- a/app/code/Magento/AdvancedPricingImportExport/composer.json +++ b/app/code/Magento/AdvancedPricingImportExport/composer.json @@ -1,25 +1,26 @@ { "name": "magento/module-advanced-pricing-import-export", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.5", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-catalog": "*", - "magento/module-catalog-import-export": "*", - "magento/module-catalog-inventory": "*", - "magento/module-customer": "*", - "magento/module-eav": "*", - "magento/module-import-export": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-catalog-import-export": "101.0.*", + "magento/module-catalog-inventory": "100.3.*", + "magento/module-customer": "102.0.*", + "magento/module-eav": "102.0.*", + "magento/module-import-export": "100.3.*", + "magento/module-store": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -29,3 +30,4 @@ } } } + diff --git a/app/code/Magento/AdvancedSearch/composer.json b/app/code/Magento/AdvancedSearch/composer.json index 720309b619e43..84181e0a42988 100644 --- a/app/code/Magento/AdvancedSearch/composer.json +++ b/app/code/Magento/AdvancedSearch/composer.json @@ -1,25 +1,26 @@ { "name": "magento/module-advanced-search", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.5", "require": { - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-catalog-search": "*", - "magento/module-config": "*", - "magento/module-customer": "*", - "magento/module-search": "*", - "magento/module-store": "*", + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-catalog-search": "101.0.*", + "magento/module-config": "101.1.*", + "magento/module-customer": "102.0.*", + "magento/module-search": "101.0.*", + "magento/module-store": "101.0.*", "php": "~7.3.0||~7.4.0" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -29,3 +30,4 @@ } } } + diff --git a/app/code/Magento/Amqp/composer.json b/app/code/Magento/Amqp/composer.json index 9e7a035112b04..716bcd9284d41 100644 --- a/app/code/Magento/Amqp/composer.json +++ b/app/code/Magento/Amqp/composer.json @@ -1,20 +1,21 @@ { "name": "magento/module-amqp", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.5", "require": { - "magento/framework": "*", - "magento/framework-amqp": "*", - "magento/framework-message-queue": "*", + "magento/framework": "102.0.*", + "magento/framework-amqp": "100.3.*", + "magento/framework-message-queue": "100.3.*", "php": "~7.3.0||~7.4.0" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -24,3 +25,4 @@ } } } + diff --git a/app/code/Magento/AmqpStore/composer.json b/app/code/Magento/AmqpStore/composer.json index 70a10810ece21..91455fde9ac96 100644 --- a/app/code/Magento/AmqpStore/composer.json +++ b/app/code/Magento/AmqpStore/composer.json @@ -1,24 +1,25 @@ { "name": "magento/module-amqp-store", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.2", "require": { - "magento/framework": "*", - "magento/framework-amqp": "*", - "magento/module-store": "*", + "magento/framework": "102.0.*", + "magento/framework-amqp": "100.3.*", + "magento/module-store": "101.0.*", "php": "~7.3.0||~7.4.0" }, "suggest": { - "magento/module-asynchronous-operations": "*", - "magento/framework-message-queue": "*" + "magento/module-asynchronous-operations": "100.3.*", + "magento/framework-message-queue": "100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -28,3 +29,4 @@ } } } + diff --git a/app/code/Magento/Analytics/composer.json b/app/code/Magento/Analytics/composer.json index 84f8af066bf11..9f55cb06beb5b 100644 --- a/app/code/Magento/Analytics/composer.json +++ b/app/code/Magento/Analytics/composer.json @@ -1,19 +1,20 @@ { "name": "magento/module-analytics", "description": "N/A", - "require": { - "php": "~7.3.0||~7.4.0", - "magento/module-backend": "*", - "magento/module-config": "*", - "magento/module-integration": "*", - "magento/module-store": "*", - "magento/framework": "*" - }, "type": "magento2-module", "license": [ "OSL-3.0", "AFL-3.0" ], + "version": "100.3.7", + "require": { + "php": "~7.3.0||~7.4.0", + "magento/module-backend": "101.0.*", + "magento/module-config": "101.1.*", + "magento/module-integration": "100.3.*", + "magento/module-store": "101.0.*", + "magento/framework": "102.0.*" + }, "autoload": { "files": [ "registration.php" @@ -23,3 +24,4 @@ } } } + diff --git a/app/code/Magento/AsynchronousOperations/composer.json b/app/code/Magento/AsynchronousOperations/composer.json index c9d87a8d31115..e55b8aa9d3ac6 100644 --- a/app/code/Magento/AsynchronousOperations/composer.json +++ b/app/code/Magento/AsynchronousOperations/composer.json @@ -1,26 +1,27 @@ { "name": "magento/module-asynchronous-operations", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7", "require": { - "magento/framework": "*", - "magento/framework-bulk": "*", - "magento/module-authorization": "*", - "magento/module-backend": "*", - "magento/module-ui": "*", + "magento/framework": "102.0.*", + "magento/framework-bulk": "100.3.*", + "magento/module-authorization": "100.3.*", + "magento/module-backend": "101.0.*", + "magento/module-ui": "101.1.*", "php": "~7.3.0||~7.4.0" }, "suggest": { - "magento/module-admin-notification": "*", + "magento/module-admin-notification": "100.3.*", "magento/module-logging": "*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -30,3 +31,4 @@ } } } + diff --git a/app/code/Magento/Authorization/composer.json b/app/code/Magento/Authorization/composer.json index 401444404ca3e..e34385020f555 100644 --- a/app/code/Magento/Authorization/composer.json +++ b/app/code/Magento/Authorization/composer.json @@ -1,19 +1,20 @@ { "name": "magento/module-authorization", "description": "Authorization module provides access to Magento ACL functionality.", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.6", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -23,3 +24,4 @@ } } } + diff --git a/app/code/Magento/Authorizenet/composer.json b/app/code/Magento/Authorizenet/composer.json index c496a08c11b5c..a29143ddb9a0e 100644 --- a/app/code/Magento/Authorizenet/composer.json +++ b/app/code/Magento/Authorizenet/composer.json @@ -1,28 +1,29 @@ { "name": "magento/module-authorizenet", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.6", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-checkout": "*", - "magento/module-payment": "*", - "magento/module-quote": "*", - "magento/module-sales": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-checkout": "100.3.*", + "magento/module-payment": "100.3.*", + "magento/module-quote": "101.1.*", + "magento/module-sales": "102.0.*", + "magento/module-store": "101.0.*" }, "suggest": { - "magento/module-config": "*" + "magento/module-config": "101.1.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -32,3 +33,4 @@ } } } + diff --git a/app/code/Magento/AuthorizenetAcceptjs/composer.json b/app/code/Magento/AuthorizenetAcceptjs/composer.json index 65baca04c8c06..16e5b5e14a9d9 100644 --- a/app/code/Magento/AuthorizenetAcceptjs/composer.json +++ b/app/code/Magento/AuthorizenetAcceptjs/composer.json @@ -1,25 +1,26 @@ { "name": "magento/module-authorizenet-acceptjs", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.5", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-payment": "*", - "magento/module-sales": "*", - "magento/module-config": "*", - "magento/module-backend": "*", - "magento/module-checkout": "*", - "magento/module-store": "*", - "magento/module-quote": "*" + "magento/framework": "102.0.*", + "magento/module-payment": "100.3.*", + "magento/module-sales": "102.0.*", + "magento/module-config": "101.1.*", + "magento/module-backend": "101.0.*", + "magento/module-checkout": "100.3.*", + "magento/module-store": "101.0.*", + "magento/module-quote": "101.1.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -29,3 +30,4 @@ } } } + diff --git a/app/code/Magento/AuthorizenetCardinal/composer.json b/app/code/Magento/AuthorizenetCardinal/composer.json index 3cfaf48397c01..874ecd5580978 100644 --- a/app/code/Magento/AuthorizenetCardinal/composer.json +++ b/app/code/Magento/AuthorizenetCardinal/composer.json @@ -1,25 +1,26 @@ { "name": "magento/module-authorizenet-cardinal", "description": "Provides a possibility to enable 3-D Secure 2.0 support for Authorize.Net Acceptjs.", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.2", "require": { "php": "~7.3.0||~7.4.0", - "magento/module-authorizenet-acceptjs": "*", - "magento/framework": "*", - "magento/module-cardinal-commerce": "*", - "magento/module-payment": "*", - "magento/module-sales": "*", - "magento/module-quote": "*", - "magento/module-checkout": "*", - "magento/module-store": "*" + "magento/module-authorizenet-acceptjs": "100.3.*", + "magento/framework": "102.0.*", + "magento/module-cardinal-commerce": "100.3.*", + "magento/module-payment": "100.3.*", + "magento/module-sales": "102.0.*", + "magento/module-quote": "101.1.*", + "magento/module-checkout": "100.3.*", + "magento/module-store": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -29,3 +30,4 @@ } } } + diff --git a/app/code/Magento/AuthorizenetGraphQl/composer.json b/app/code/Magento/AuthorizenetGraphQl/composer.json index 50d2441abc14a..b61e8c099d289 100644 --- a/app/code/Magento/AuthorizenetGraphQl/composer.json +++ b/app/code/Magento/AuthorizenetGraphQl/composer.json @@ -2,18 +2,19 @@ "name": "magento/module-authorizenet-graph-ql", "description": "N/A", "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "version": "100.3.3", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-quote-graph-ql": "*" + "magento/framework": "102.0.*", + "magento/module-quote-graph-ql": "100.3.*" }, "suggest": { - "magento/module-graph-ql": "*" + "magento/module-graph-ql": "100.3.*" }, - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -23,3 +24,4 @@ } } } + diff --git a/app/code/Magento/Backend/composer.json b/app/code/Magento/Backend/composer.json index 3cd6a25241caf..2aff2938bbc2e 100644 --- a/app/code/Magento/Backend/composer.json +++ b/app/code/Magento/Backend/composer.json @@ -1,37 +1,38 @@ { "name": "magento/module-backend", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "101.0.7", "require": { - "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backup": "*", - "magento/module-catalog": "*", - "magento/module-config": "*", - "magento/module-customer": "*", - "magento/module-developer": "*", - "magento/module-directory": "*", - "magento/module-eav": "*", - "magento/module-quote": "*", - "magento/module-reports": "*", - "magento/module-require-js": "*", - "magento/module-sales": "*", - "magento/module-security": "*", - "magento/module-store": "*", - "magento/module-translation": "*", - "magento/module-ui": "*", - "magento/module-user": "*" + "php": "~7.3.0||~7.4.0", + "magento/framework": "102.0.*", + "magento/module-backup": "100.3.*", + "magento/module-catalog": "103.0.*", + "magento/module-config": "101.1.*", + "magento/module-customer": "102.0.*", + "magento/module-developer": "100.3.*", + "magento/module-directory": "100.3.*", + "magento/module-eav": "102.0.*", + "magento/module-quote": "101.1.*", + "magento/module-reports": "100.3.*", + "magento/module-require-js": "100.3.*", + "magento/module-sales": "102.0.*", + "magento/module-security": "100.3.*", + "magento/module-store": "101.0.*", + "magento/module-translation": "100.3.*", + "magento/module-ui": "101.1.*", + "magento/module-user": "101.1.*" }, "suggest": { - "magento/module-theme": "*" + "magento/module-theme": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -41,3 +42,4 @@ } } } + diff --git a/app/code/Magento/Backup/Model/Fs/Collection.php b/app/code/Magento/Backup/Model/Fs/Collection.php index b17c17f7074fb..090130e808ef8 100644 --- a/app/code/Magento/Backup/Model/Fs/Collection.php +++ b/app/code/Magento/Backup/Model/Fs/Collection.php @@ -3,6 +3,8 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Backup\Model\Fs; use Magento\Framework\App\Filesystem\DirectoryList; @@ -45,6 +47,7 @@ class Collection extends \Magento\Framework\Data\Collection\Filesystem * @param \Magento\Backup\Helper\Data $backupData * @param \Magento\Framework\Filesystem $filesystem * @param \Magento\Backup\Model\Backup $backup + * @throws \Magento\Framework\Exception\FileSystemException */ public function __construct( \Magento\Framework\Data\Collection\EntityFactory $entityFactory, @@ -55,7 +58,6 @@ public function __construct( $this->_backupData = $backupData; parent::__construct($entityFactory); - $this->_filesystem = $filesystem; $this->_backup = $backup; $this->_varDirectory = $filesystem->getDirectoryWrite(DirectoryList::VAR_DIR); @@ -87,12 +89,17 @@ public function __construct( * Create .htaccess file and deny backups directory access from web * * @return void + * @throws \Magento\Framework\Exception\FileSystemException */ protected function _hideBackupsForApache() { $filename = '.htaccess'; - if (!$this->_varDirectory->isFile($filename)) { - $this->_varDirectory->writeFile($filename, 'deny from all'); + $driver = $this->_varDirectory->getDriver(); + $absolutePath = $driver->getAbsolutePath($this->_varDirectory->getAbsolutePath(), $filename); + if (!$driver->isFile($absolutePath)) { + $resource = $driver->fileOpen($absolutePath, 'w+'); + $driver->fileWrite($resource, 'deny from all'); + $driver->fileClose($resource); } } diff --git a/app/code/Magento/Backup/Test/Unit/Model/Fs/CollectionTest.php b/app/code/Magento/Backup/Test/Unit/Model/Fs/CollectionTest.php index 2d26edb7c5bfe..67276144587c4 100644 --- a/app/code/Magento/Backup/Test/Unit/Model/Fs/CollectionTest.php +++ b/app/code/Magento/Backup/Test/Unit/Model/Fs/CollectionTest.php @@ -22,9 +22,14 @@ public function testConstructor() \Magento\Backup\Helper\Data::class )->disableOriginalConstructor()->getMock(); $backupData->expects($this->any())->method('getExtensions')->willReturn([]); - + $driver = $this->getMockBuilder( + \Magento\Framework\Filesystem\DriverInterface::class + )->disableOriginalConstructor() + ->getMock(); $directoryWrite->expects($this->any())->method('create')->with('backups'); - $directoryWrite->expects($this->any())->method('getAbsolutePath')->with('backups'); + $directoryWrite->expects($this->any())->method('getAbsolutePath')->willReturn(''); + $directoryWrite->expects($this->at(3))->method('getAbsolutePath')->with('backups'); + $directoryWrite->expects($this->any())->method('getDriver')->willReturn($driver); $classObject = $helper->getObject( \Magento\Backup\Model\Fs\Collection::class, diff --git a/app/code/Magento/Backup/composer.json b/app/code/Magento/Backup/composer.json index 9a5904beda550..cac9fcc81809e 100644 --- a/app/code/Magento/Backup/composer.json +++ b/app/code/Magento/Backup/composer.json @@ -1,21 +1,22 @@ { "name": "magento/module-backup", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.6-p2", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-cron": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-cron": "100.3.*", + "magento/module-store": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -25,3 +26,4 @@ } } } + diff --git a/app/code/Magento/Braintree/composer.json b/app/code/Magento/Braintree/composer.json index 7627959c5d330..e8ea0747c7ed6 100644 --- a/app/code/Magento/Braintree/composer.json +++ b/app/code/Magento/Braintree/composer.json @@ -1,38 +1,39 @@ { "name": "magento/module-braintree", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7-p2", "require": { "php": "~7.3.0||~7.4.0", "braintree/braintree_php": "3.35.0", - "magento/framework": "*", + "magento/framework": "102.0.*", "magento/magento-composer-installer": "*", - "magento/module-catalog": "*", - "magento/module-backend": "*", - "magento/module-checkout": "*", - "magento/module-config": "*", - "magento/module-customer": "*", - "magento/module-directory": "*", - "magento/module-instant-purchase": "*", - "magento/module-payment": "*", - "magento/module-paypal": "*", - "magento/module-quote": "*", - "magento/module-sales": "*", - "magento/module-ui": "*", - "magento/module-vault": "*", - "magento/module-multishipping": "*", - "magento/module-theme": "*" + "magento/module-catalog": "103.0.*", + "magento/module-backend": "101.0.*", + "magento/module-checkout": "100.3.*", + "magento/module-config": "101.1.*", + "magento/module-customer": "102.0.*", + "magento/module-directory": "100.3.*", + "magento/module-instant-purchase": "100.3.*", + "magento/module-payment": "100.3.*", + "magento/module-paypal": "100.3.*", + "magento/module-quote": "101.1.*", + "magento/module-sales": "102.0.*", + "magento/module-ui": "101.1.*", + "magento/module-vault": "101.1.*", + "magento/module-multishipping": "100.3.*", + "magento/module-theme": "101.0.*" }, "suggest": { - "magento/module-checkout-agreements": "*" + "magento/module-checkout-agreements": "100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -42,3 +43,4 @@ } } } + diff --git a/app/code/Magento/Braintree/etc/csp_whitelist.xml b/app/code/Magento/Braintree/etc/csp_whitelist.xml index b023d2adf03fd..5ee0755bcc18d 100644 --- a/app/code/Magento/Braintree/etc/csp_whitelist.xml +++ b/app/code/Magento/Braintree/etc/csp_whitelist.xml @@ -21,5 +21,17 @@ t.paypal.com + + + payments.sandbox.braintree-api.com + origin-analytics-sand.sandbox.braintree-api.com + assets.braintreegateway.com + + + + + assets.braintreegateway.com + + diff --git a/app/code/Magento/BraintreeGraphQl/composer.json b/app/code/Magento/BraintreeGraphQl/composer.json index ceac826dd5ee4..5c7e94cfad80b 100644 --- a/app/code/Magento/BraintreeGraphQl/composer.json +++ b/app/code/Magento/BraintreeGraphQl/composer.json @@ -2,21 +2,22 @@ "name": "magento/module-braintree-graph-ql", "description": "N/A", "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "version": "100.3.4", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-braintree": "*", - "magento/module-store": "*", - "magento/module-quote": "*", - "magento/module-quote-graph-ql": "*" + "magento/framework": "102.0.*", + "magento/module-braintree": "100.3.*", + "magento/module-store": "101.0.*", + "magento/module-quote": "101.1.*", + "magento/module-quote-graph-ql": "100.3.*" }, "suggest": { - "magento/module-graph-ql": "*" + "magento/module-graph-ql": "100.3.*" }, - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -26,3 +27,4 @@ } } } + diff --git a/app/code/Magento/Bundle/composer.json b/app/code/Magento/Bundle/composer.json index 1b5ca24ee098c..98018a973b267 100644 --- a/app/code/Magento/Bundle/composer.json +++ b/app/code/Magento/Bundle/composer.json @@ -1,38 +1,39 @@ { "name": "magento/module-bundle", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-catalog-inventory": "*", - "magento/module-catalog-rule": "*", - "magento/module-checkout": "*", - "magento/module-config": "*", - "magento/module-customer": "*", - "magento/module-eav": "*", - "magento/module-gift-message": "*", - "magento/module-media-storage": "*", - "magento/module-quote": "*", - "magento/module-sales": "*", - "magento/module-store": "*", - "magento/module-tax": "*", - "magento/module-ui": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-catalog-inventory": "100.3.*", + "magento/module-catalog-rule": "101.1.*", + "magento/module-checkout": "100.3.*", + "magento/module-config": "101.1.*", + "magento/module-customer": "102.0.*", + "magento/module-eav": "102.0.*", + "magento/module-gift-message": "100.3.*", + "magento/module-media-storage": "100.3.*", + "magento/module-quote": "101.1.*", + "magento/module-sales": "102.0.*", + "magento/module-store": "101.0.*", + "magento/module-tax": "100.3.*", + "magento/module-ui": "101.1.*" }, "suggest": { - "magento/module-webapi": "*", - "magento/module-bundle-sample-data": "*", - "magento/module-sales-rule": "*" + "magento/module-webapi": "100.3.*", + "magento/module-bundle-sample-data": "Sample Data version: 100.3.*", + "magento/module-sales-rule": "101.1.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -42,3 +43,4 @@ } } } + diff --git a/app/code/Magento/BundleGraphQl/composer.json b/app/code/Magento/BundleGraphQl/composer.json index cb49ab78588b3..49713edfe728e 100644 --- a/app/code/Magento/BundleGraphQl/composer.json +++ b/app/code/Magento/BundleGraphQl/composer.json @@ -2,20 +2,21 @@ "name": "magento/module-bundle-graph-ql", "description": "N/A", "type": "magento2-module", - "require": { - "php": "~7.3.0||~7.4.0", - "magento/module-catalog": "*", - "magento/module-bundle": "*", - "magento/module-catalog-graph-ql": "*", - "magento/module-quote": "*", - "magento/module-quote-graph-ql": "*", - "magento/module-store": "*", - "magento/framework": "*" - }, "license": [ "OSL-3.0", "AFL-3.0" ], + "version": "100.3.5", + "require": { + "php": "~7.3.0||~7.4.0", + "magento/module-catalog": "103.0.*", + "magento/module-bundle": "100.3.*", + "magento/module-catalog-graph-ql": "100.3.*", + "magento/module-quote": "101.1.*", + "magento/module-quote-graph-ql": "100.3.*", + "magento/module-store": "101.0.*", + "magento/framework": "102.0.*" + }, "autoload": { "files": [ "registration.php" @@ -25,3 +26,4 @@ } } } + diff --git a/app/code/Magento/BundleImportExport/composer.json b/app/code/Magento/BundleImportExport/composer.json index faca3eac9a721..22fc539047201 100644 --- a/app/code/Magento/BundleImportExport/composer.json +++ b/app/code/Magento/BundleImportExport/composer.json @@ -1,24 +1,25 @@ { "name": "magento/module-bundle-import-export", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.6", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-bundle": "*", - "magento/module-store": "*", - "magento/module-catalog": "*", - "magento/module-catalog-import-export": "*", - "magento/module-eav": "*", - "magento/module-import-export": "*" + "magento/framework": "102.0.*", + "magento/module-bundle": "100.3.*", + "magento/module-store": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-catalog-import-export": "101.0.*", + "magento/module-eav": "102.0.*", + "magento/module-import-export": "100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -28,3 +29,4 @@ } } } + diff --git a/app/code/Magento/CacheInvalidate/composer.json b/app/code/Magento/CacheInvalidate/composer.json index 7801554c890e1..19461bb422162 100644 --- a/app/code/Magento/CacheInvalidate/composer.json +++ b/app/code/Magento/CacheInvalidate/composer.json @@ -1,19 +1,20 @@ { "name": "magento/module-cache-invalidate", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.5", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-page-cache": "*" + "magento/framework": "102.0.*", + "magento/module-page-cache": "100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -23,3 +24,4 @@ } } } + diff --git a/app/code/Magento/Captcha/composer.json b/app/code/Magento/Captcha/composer.json index 3c3aa58c3fe2f..2bdd269ee51f4 100644 --- a/app/code/Magento/Captcha/composer.json +++ b/app/code/Magento/Captcha/composer.json @@ -1,26 +1,27 @@ { "name": "magento/module-captcha", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-checkout": "*", - "magento/module-customer": "*", - "magento/module-store": "*", - "magento/module-authorization": "*", + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-checkout": "100.3.*", + "magento/module-customer": "102.0.*", + "magento/module-store": "101.0.*", + "magento/module-authorization": "100.3.*", "laminas/laminas-captcha": "^2.7.1", "laminas/laminas-db": "^2.8.2", "laminas/laminas-session": "^2.7.3" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -30,3 +31,4 @@ } } } + diff --git a/app/code/Magento/CardinalCommerce/composer.json b/app/code/Magento/CardinalCommerce/composer.json index 8b2989ef915e1..07b3c8ac7518d 100644 --- a/app/code/Magento/CardinalCommerce/composer.json +++ b/app/code/Magento/CardinalCommerce/composer.json @@ -1,21 +1,22 @@ { "name": "magento/module-cardinal-commerce", "description": "Provides a possibility to enable 3-D Secure 2.0 support for payment methods.", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.3", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-checkout": "*", - "magento/module-payment": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-checkout": "100.3.*", + "magento/module-payment": "100.3.*", + "magento/module-store": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -25,3 +26,4 @@ } } } + diff --git a/app/code/Magento/Catalog/Model/Product/Option/Type/File/ValidatorFile.php b/app/code/Magento/Catalog/Model/Product/Option/Type/File/ValidatorFile.php index fef4999a1174a..65e9c889787c5 100644 --- a/app/code/Magento/Catalog/Model/Product/Option/Type/File/ValidatorFile.php +++ b/app/code/Magento/Catalog/Model/Product/Option/Type/File/ValidatorFile.php @@ -3,15 +3,16 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\Catalog\Model\Product\Option\Type\File; use Magento\Catalog\Model\Product; -use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Catalog\Model\Product\Exception as ProductException; +use Magento\Framework\App\Filesystem\DirectoryList; +use Magento\Framework\App\ObjectManager; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Math\Random; -use Magento\Framework\App\ObjectManager; /** * Validator class. Represents logic for validation file given from product option @@ -179,9 +180,10 @@ public function validate($processingParams, $option) $filePath = $dispersion; $tmpDirectory = $this->filesystem->getDirectoryRead(DirectoryList::SYS_TMP); + // phpcs:ignore Magento2.Security.InsecureFunction $fileHash = md5($tmpDirectory->readFile($tmpDirectory->getRelativePath($fileInfo['tmp_name']))); $fileRandomName = $this->random->getRandomString(32); - $filePath .= '/' .$fileRandomName; + $filePath .= '/' . $fileRandomName; $fileFullPath = $this->mediaDirectory->getAbsolutePath($this->quotePath . $filePath); $upload->addFilter(new \Zend_Filter_File_Rename(['target' => $fileFullPath, 'overwrite' => true])); @@ -202,8 +204,10 @@ public function validate($processingParams, $option) $_height = 0; if ($tmpDirectory->isReadable($tmpDirectory->getRelativePath($fileInfo['tmp_name']))) { + // phpcs:ignore Magento2.Functions.DiscouragedFunction if (filesize($fileInfo['tmp_name'])) { if ($this->isImageValidator->isValid($fileInfo['tmp_name'])) { + // phpcs:ignore Magento2.Functions.DiscouragedFunction $imageSize = getimagesize($fileInfo['tmp_name']); } } else { @@ -255,8 +259,12 @@ protected function initFilesystem() // Directory listing and hotlink secure $path = $this->path . '/.htaccess'; - if (!$this->mediaDirectory->isFile($path)) { - $this->mediaDirectory->writeFile($path, "Order deny,allow\nDeny from all"); + $driver = $this->mediaDirectory->getDriver(); + $absolutePath = $driver->getAbsolutePath($this->mediaDirectory->getAbsolutePath(), $path); + if (!$driver->isFile($absolutePath)) { + $resource = $driver->fileOpen($absolutePath, 'w+'); + $driver->fileWrite($resource, "Order deny,allow\nDeny from all"); + $driver->fileClose($resource); } } @@ -265,9 +273,11 @@ protected function initFilesystem() * * @return bool * @todo need correctly name + * @SuppressWarnings(PHPMD.Superglobals) */ protected function validateContentLength() { + // phpcs:disable Magento2.Security.Superglobal return isset($_SERVER['CONTENT_LENGTH']) && $_SERVER['CONTENT_LENGTH'] > $this->fileSize->getMaxFileSize(); } } diff --git a/app/code/Magento/Catalog/Model/Product/Option/Type/File/ValidatorInfo.php b/app/code/Magento/Catalog/Model/Product/Option/Type/File/ValidatorInfo.php index 100ad37273cff..14c92fee71444 100644 --- a/app/code/Magento/Catalog/Model/Product/Option/Type/File/ValidatorInfo.php +++ b/app/code/Magento/Catalog/Model/Product/Option/Type/File/ValidatorInfo.php @@ -6,13 +6,22 @@ namespace Magento\Catalog\Model\Product\Option\Type\File; +use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Framework\Exception\InputException; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\File\Size; +use Magento\Framework\Filesystem; +use Magento\Framework\Filesystem\Io\File as IoFile; +use Magento\MediaStorage\Helper\File\Storage\Database; +use Magento\MediaStorage\Model\File\Validator\NotProtectedExtension; + /** * Validator for existing files. */ class ValidatorInfo extends Validator { /** - * @var \Magento\MediaStorage\Helper\File\Storage\Database + * @var Database */ protected $coreFileStorageDatabase; @@ -36,24 +45,39 @@ class ValidatorInfo extends Validator */ protected $fileRelativePath; + /** + * @var IoFile + */ + private $ioFile; + /** + * @var NotProtectedExtension + */ + private $fileValidator; + /** * Construct method * - * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig - * @param \Magento\Framework\Filesystem $filesystem - * @param \Magento\Framework\File\Size $fileSize - * @param \Magento\MediaStorage\Helper\File\Storage\Database $coreFileStorageDatabase + * @param ScopeConfigInterface $scopeConfig + * @param Filesystem $filesystem + * @param Size $fileSize + * @param Database $coreFileStorageDatabase * @param ValidateFactory $validateFactory + * @param NotProtectedExtension $fileValidator + * @param IoFile $ioFile */ public function __construct( - \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, - \Magento\Framework\Filesystem $filesystem, - \Magento\Framework\File\Size $fileSize, - \Magento\MediaStorage\Helper\File\Storage\Database $coreFileStorageDatabase, - \Magento\Catalog\Model\Product\Option\Type\File\ValidateFactory $validateFactory + ScopeConfigInterface $scopeConfig, + Filesystem $filesystem, + Size $fileSize, + Database $coreFileStorageDatabase, + ValidateFactory $validateFactory, + NotProtectedExtension $fileValidator, + IoFile $ioFile ) { $this->coreFileStorageDatabase = $coreFileStorageDatabase; $this->validateFactory = $validateFactory; + $this->fileValidator = $fileValidator; + $this->ioFile = $ioFile; parent::__construct($scopeConfig, $filesystem, $fileSize); } @@ -94,27 +118,42 @@ public function validate($optionValue, $option) $validatorChain = $this->validateFactory->create(); try { $validatorChain = $this->buildImageValidator($validatorChain, $option, $this->fileFullPath); - } catch (\Magento\Framework\Exception\InputException $notImage) { + } catch (InputException $notImage) { return false; } - $result = false; - if ($validatorChain->isValid($this->fileFullPath, $optionValue['title'])) { - $result = $this->rootDirectory->isReadable($this->fileRelativePath) + if ($this->validatePath($optionValue) && $validatorChain->isValid($this->fileFullPath, $optionValue['title'])) { + return $this->rootDirectory->isReadable($this->fileRelativePath) && isset($optionValue['secret_key']) && $this->buildSecretKey($this->fileRelativePath) == $optionValue['secret_key']; - } elseif ($validatorChain->getErrors()) { + } else { $errors = $this->getValidatorErrors($validatorChain->getErrors(), $optionValue, $option); - if (count($errors) > 0) { - throw new \Magento\Framework\Exception\LocalizedException(__(implode("\n", $errors))); + throw new LocalizedException(__(implode("\n", $errors))); } - } else { - throw new \Magento\Framework\Exception\LocalizedException( + throw new LocalizedException( __("The product's required option(s) weren't entered. Make sure the options are entered and try again.") ); } - return $result; + } + + /** + * Validate quote_path and order_path. + * + * @param array $optionValuePath + * @return bool + */ + private function validatePath(array $optionValuePath): bool + { + foreach ([$optionValuePath['quote_path'], $optionValuePath['order_path']] as $path) { + $pathInfo = $this->ioFile->getPathInfo($path); + if (isset($pathInfo['extension'])) { + if (!$this->fileValidator->isValid($pathInfo['extension'])) { + return false; + } + } + } + return true; } /** @@ -125,6 +164,7 @@ public function validate($optionValue, $option) */ protected function buildSecretKey($fileRelativePath) { + // phpcs:ignore Magento2.Security.InsecureFunction return substr(md5($this->rootDirectory->readFile($fileRelativePath)), 0, 20); } diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminAddImageToWYSIWYGProductTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminAddImageToWYSIWYGProductTest.xml index 4044490c92334..4091946add97d 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminAddImageToWYSIWYGProductTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminAddImageToWYSIWYGProductTest.xml @@ -75,8 +75,12 @@ - - + + + + + + diff --git a/app/code/Magento/Catalog/composer.json b/app/code/Magento/Catalog/composer.json index 6dde1d76e5e81..78886e6bcc897 100644 --- a/app/code/Magento/Catalog/composer.json +++ b/app/code/Magento/Catalog/composer.json @@ -1,48 +1,49 @@ { "name": "magento/module-catalog", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "103.0.7-p2", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-authorization": "*", - "magento/module-asynchronous-operations": "*", - "magento/module-backend": "*", - "magento/module-catalog-inventory": "*", - "magento/module-catalog-rule": "*", - "magento/module-catalog-url-rewrite": "*", - "magento/module-checkout": "*", - "magento/module-cms": "*", - "magento/module-config": "*", - "magento/module-customer": "*", - "magento/module-directory": "*", - "magento/module-eav": "*", - "magento/module-indexer": "*", - "magento/module-media-storage": "*", - "magento/module-msrp": "*", - "magento/module-page-cache": "*", - "magento/module-product-alert": "*", - "magento/module-quote": "*", - "magento/module-store": "*", - "magento/module-tax": "*", - "magento/module-theme": "*", - "magento/module-ui": "*", - "magento/module-url-rewrite": "*", - "magento/module-widget": "*", - "magento/module-wishlist": "*" + "magento/framework": "102.0.*", + "magento/module-authorization": "100.3.*", + "magento/module-asynchronous-operations": "100.3.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog-inventory": "100.3.*", + "magento/module-catalog-rule": "101.1.*", + "magento/module-catalog-url-rewrite": "100.3.*", + "magento/module-checkout": "100.3.*", + "magento/module-cms": "103.0.*", + "magento/module-config": "101.1.*", + "magento/module-customer": "102.0.*", + "magento/module-directory": "100.3.*", + "magento/module-eav": "102.0.*", + "magento/module-indexer": "100.3.*", + "magento/module-media-storage": "100.3.*", + "magento/module-msrp": "100.3.*", + "magento/module-page-cache": "100.3.*", + "magento/module-product-alert": "100.3.*", + "magento/module-quote": "101.1.*", + "magento/module-store": "101.0.*", + "magento/module-tax": "100.3.*", + "magento/module-theme": "101.0.*", + "magento/module-ui": "101.1.*", + "magento/module-url-rewrite": "101.1.*", + "magento/module-widget": "101.1.*", + "magento/module-wishlist": "101.1.*" }, "suggest": { - "magento/module-cookie": "*", - "magento/module-sales": "*", - "magento/module-catalog-sample-data": "*" + "magento/module-cookie": "100.3.*", + "magento/module-sales": "102.0.*", + "magento/module-catalog-sample-data": "Sample Data version: 100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -52,3 +53,4 @@ } } } + diff --git a/app/code/Magento/Catalog/etc/config.xml b/app/code/Magento/Catalog/etc/config.xml index 20511f4ff2295..ffc0e1ae47568 100644 --- a/app/code/Magento/Catalog/etc/config.xml +++ b/app/code/Magento/Catalog/etc/config.xml @@ -64,6 +64,9 @@ tmp media/catalog/product/cache/ catalog + + catalog/category + custom_options diff --git a/app/code/Magento/CatalogAnalytics/composer.json b/app/code/Magento/CatalogAnalytics/composer.json index 43fb4c8a6f433..b16104e837011 100644 --- a/app/code/Magento/CatalogAnalytics/composer.json +++ b/app/code/Magento/CatalogAnalytics/composer.json @@ -1,17 +1,18 @@ { "name": "magento/module-catalog-analytics", "description": "N/A", - "require": { - "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-catalog": "*", - "magento/module-analytics": "*" - }, "type": "magento2-module", "license": [ "OSL-3.0", "AFL-3.0" ], + "version": "100.3.5", + "require": { + "php": "~7.3.0||~7.4.0", + "magento/framework": "102.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-analytics": "100.3.*" + }, "autoload": { "files": [ "registration.php" @@ -21,3 +22,4 @@ } } } + diff --git a/app/code/Magento/CatalogCmsGraphQl/composer.json b/app/code/Magento/CatalogCmsGraphQl/composer.json index aa7a742f2f315..01252fd327175 100644 --- a/app/code/Magento/CatalogCmsGraphQl/composer.json +++ b/app/code/Magento/CatalogCmsGraphQl/composer.json @@ -2,21 +2,22 @@ "name": "magento/module-catalog-cms-graph-ql", "description": "N/A", "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "version": "100.3.1", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-catalog": "*", - "magento/module-cms-graph-ql": "*" + "magento/framework": "102.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-cms-graph-ql": "100.3.*" }, "suggest": { - "magento/module-graph-ql": "*", - "magento/module-cms": "*", - "magento/module-catalog-graph-ql": "*" + "magento/module-graph-ql": "100.3.*", + "magento/module-cms": "103.0.*", + "magento/module-catalog-graph-ql": "100.3.*" }, - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -26,3 +27,4 @@ } } } + diff --git a/app/code/Magento/CatalogCustomerGraphQl/composer.json b/app/code/Magento/CatalogCustomerGraphQl/composer.json index a7c887af0379b..8a381f0a62847 100644 --- a/app/code/Magento/CatalogCustomerGraphQl/composer.json +++ b/app/code/Magento/CatalogCustomerGraphQl/composer.json @@ -2,18 +2,19 @@ "name": "magento/module-catalog-customer-graph-ql", "description": "N/A", "type": "magento2-module", - "require": { - "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-catalog": "*", - "magento/module-customer": "*", - "magento/module-catalog-graph-ql": "*", - "magento/module-store": "*" - }, "license": [ "OSL-3.0", "AFL-3.0" ], + "version": "100.3.1", + "require": { + "php": "~7.3.0||~7.4.0", + "magento/framework": "102.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-customer": "102.0.*", + "magento/module-catalog-graph-ql": "100.3.*", + "magento/module-store": "101.0.*" + }, "autoload": { "files": [ "registration.php" @@ -23,3 +24,4 @@ } } } + diff --git a/app/code/Magento/CatalogGraphQl/composer.json b/app/code/Magento/CatalogGraphQl/composer.json index d6e9bfa3c0505..cc5c091334719 100644 --- a/app/code/Magento/CatalogGraphQl/composer.json +++ b/app/code/Magento/CatalogGraphQl/composer.json @@ -2,26 +2,27 @@ "name": "magento/module-catalog-graph-ql", "description": "N/A", "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "version": "100.3.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/module-eav": "*", - "magento/module-catalog": "*", - "magento/module-catalog-inventory": "*", - "magento/module-search": "*", - "magento/module-store": "*", - "magento/module-eav-graph-ql": "*", - "magento/module-catalog-search": "*", - "magento/framework": "*" + "magento/module-eav": "102.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-catalog-inventory": "100.3.*", + "magento/module-search": "101.0.*", + "magento/module-store": "101.0.*", + "magento/module-eav-graph-ql": "100.3.*", + "magento/module-catalog-search": "101.0.*", + "magento/framework": "102.0.*" }, "suggest": { - "magento/module-graph-ql": "*", - "magento/module-graph-ql-cache": "*", - "magento/module-store-graph-ql": "*" + "magento/module-graph-ql": "100.3.*", + "magento/module-graph-ql-cache": "100.3.*", + "magento/module-store-graph-ql": "100.3.*" }, - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -31,3 +32,4 @@ } } } + diff --git a/app/code/Magento/CatalogImportExport/composer.json b/app/code/Magento/CatalogImportExport/composer.json index 92a6620827990..b40193c1a0c26 100644 --- a/app/code/Magento/CatalogImportExport/composer.json +++ b/app/code/Magento/CatalogImportExport/composer.json @@ -1,29 +1,30 @@ { "name": "magento/module-catalog-import-export", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "101.0.7", "require": { "php": "~7.3.0||~7.4.0", "ext-ctype": "*", - "magento/framework": "*", - "magento/module-catalog": "*", - "magento/module-catalog-inventory": "*", - "magento/module-catalog-url-rewrite": "*", - "magento/module-customer": "*", - "magento/module-eav": "*", - "magento/module-import-export": "*", - "magento/module-media-storage": "*", - "magento/module-store": "*", - "magento/module-tax": "*", - "magento/module-authorization": "*" + "magento/framework": "102.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-catalog-inventory": "100.3.*", + "magento/module-catalog-url-rewrite": "100.3.*", + "magento/module-customer": "102.0.*", + "magento/module-eav": "102.0.*", + "magento/module-import-export": "100.3.*", + "magento/module-media-storage": "100.3.*", + "magento/module-store": "101.0.*", + "magento/module-tax": "100.3.*", + "magento/module-authorization": "100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -33,3 +34,4 @@ } } } + diff --git a/app/code/Magento/CatalogInventory/Model/Quote/Item/QuantityValidator.php b/app/code/Magento/CatalogInventory/Model/Quote/Item/QuantityValidator.php index 2ccb726f2c625..6adef9ef786c1 100644 --- a/app/code/Magento/CatalogInventory/Model/Quote/Item/QuantityValidator.php +++ b/app/code/Magento/CatalogInventory/Model/Quote/Item/QuantityValidator.php @@ -179,7 +179,7 @@ public function validate(Observer $observer) * Check item for options */ if ($options) { - $qty = $product->getTypeInstance()->prepareQuoteItemQty($qty, $product); + $qty = $product->getTypeInstance()->prepareQuoteItemQty($quoteItem->getQty(), $product); $quoteItem->setData('qty', $qty); if ($stockStatus) { $this->checkOptionsQtyIncrements($quoteItem, $options); diff --git a/app/code/Magento/CatalogInventory/Model/Quote/Item/QuantityValidator/Initializer/Option.php b/app/code/Magento/CatalogInventory/Model/Quote/Item/QuantityValidator/Initializer/Option.php index a48b9ae5f0808..59d9485b345c8 100644 --- a/app/code/Magento/CatalogInventory/Model/Quote/Item/QuantityValidator/Initializer/Option.php +++ b/app/code/Magento/CatalogInventory/Model/Quote/Item/QuantityValidator/Initializer/Option.php @@ -120,7 +120,7 @@ public function initialize( /** * if option's qty was updates we also need to update quote item qty */ - $quoteItem->setData('qty', (int) $qty); + $quoteItem->setData('qty', (int) $result->getItemQty()); } if ($result->getMessage() !== null) { $option->setMessage($result->getMessage()); diff --git a/app/code/Magento/CatalogInventory/Test/Unit/Model/Quote/Item/QuantityValidator/Initializer/OptionTest.php b/app/code/Magento/CatalogInventory/Test/Unit/Model/Quote/Item/QuantityValidator/Initializer/OptionTest.php index 3232532f1581d..8a9d78670a5b1 100644 --- a/app/code/Magento/CatalogInventory/Test/Unit/Model/Quote/Item/QuantityValidator/Initializer/OptionTest.php +++ b/app/code/Magento/CatalogInventory/Test/Unit/Model/Quote/Item/QuantityValidator/Initializer/OptionTest.php @@ -5,6 +5,9 @@ */ namespace Magento\CatalogInventory\Test\Unit\Model\Quote\Item\QuantityValidator\Initializer; +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class OptionTest extends \PHPUnit\Framework\TestCase { /** @@ -79,6 +82,7 @@ protected function setUp(): void 'setBackorders', '__wakeup', ]; + $this->optionMock = $this->createPartialMock(\Magento\Quote\Model\Quote\Item\Option::class, $optionMethods); $store = $this->createPartialMock(\Magento\Store\Model\Store::class, ['getWebsiteId', '__wakeup']); @@ -206,6 +210,7 @@ public function testInitializeWhenResultIsDecimalGetBackordersMessageHasOptionQt $this->optionMock->expects($this->once())->method('setBackorders')->with('backorders'); $this->stockItemMock->expects($this->once())->method('unsIsChildItem'); + $this->resultMock->expects($this->once())->method('getItemQty')->willReturn($qty); $this->validator->initialize($this->optionMock, $this->quoteItemMock, $qty); } diff --git a/app/code/Magento/CatalogInventory/composer.json b/app/code/Magento/CatalogInventory/composer.json index b810e6613aebb..46022d499bf50 100644 --- a/app/code/Magento/CatalogInventory/composer.json +++ b/app/code/Magento/CatalogInventory/composer.json @@ -1,25 +1,26 @@ { "name": "magento/module-catalog-inventory", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7-p2", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-catalog": "*", - "magento/module-config": "*", - "magento/module-customer": "*", - "magento/module-eav": "*", - "magento/module-quote": "*", - "magento/module-store": "*", - "magento/module-ui": "*" + "magento/framework": "102.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-config": "101.1.*", + "magento/module-customer": "102.0.*", + "magento/module-eav": "102.0.*", + "magento/module-quote": "101.1.*", + "magento/module-store": "101.0.*", + "magento/module-ui": "101.1.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -30,3 +31,4 @@ }, "abandoned": "magento/inventory-composer-metapackage" } + diff --git a/app/code/Magento/CatalogInventoryGraphQl/composer.json b/app/code/Magento/CatalogInventoryGraphQl/composer.json index d6d5b01091341..fbb7ed4074608 100644 --- a/app/code/Magento/CatalogInventoryGraphQl/composer.json +++ b/app/code/Magento/CatalogInventoryGraphQl/composer.json @@ -2,17 +2,18 @@ "name": "magento/module-catalog-inventory-graph-ql", "description": "N/A", "type": "magento2-module", - "require": { - "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-store": "*", - "magento/module-catalog": "*", - "magento/module-catalog-inventory": "*" - }, "license": [ "OSL-3.0", "AFL-3.0" ], + "version": "100.3.5", + "require": { + "php": "~7.3.0||~7.4.0", + "magento/framework": "102.0.*", + "magento/module-store": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-catalog-inventory": "100.3.*" + }, "autoload": { "files": [ "registration.php" @@ -22,3 +23,4 @@ } } } + diff --git a/app/code/Magento/CatalogRule/composer.json b/app/code/Magento/CatalogRule/composer.json index 7c40ca8a9a33a..fa81bb64fb976 100644 --- a/app/code/Magento/CatalogRule/composer.json +++ b/app/code/Magento/CatalogRule/composer.json @@ -1,29 +1,30 @@ { "name": "magento/module-catalog-rule", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "101.1.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-customer": "*", - "magento/module-eav": "*", - "magento/module-rule": "*", - "magento/module-store": "*", - "magento/module-ui": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-customer": "102.0.*", + "magento/module-eav": "102.0.*", + "magento/module-rule": "100.3.*", + "magento/module-store": "101.0.*", + "magento/module-ui": "101.1.*" }, "suggest": { - "magento/module-import-export": "*", - "magento/module-catalog-rule-sample-data": "*" + "magento/module-import-export": "100.3.*", + "magento/module-catalog-rule-sample-data": "Sample Data version: 100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -33,3 +34,4 @@ } } } + diff --git a/app/code/Magento/CatalogRuleConfigurable/composer.json b/app/code/Magento/CatalogRuleConfigurable/composer.json index 19274fbae146f..afc18e74cc6df 100644 --- a/app/code/Magento/CatalogRuleConfigurable/composer.json +++ b/app/code/Magento/CatalogRuleConfigurable/composer.json @@ -1,25 +1,26 @@ { "name": "magento/module-catalog-rule-configurable", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.6", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", + "magento/framework": "102.0.*", "magento/magento-composer-installer": "*", - "magento/module-catalog": "*", - "magento/module-catalog-rule": "*", - "magento/module-configurable-product": "*" + "magento/module-catalog": "103.0.*", + "magento/module-catalog-rule": "101.1.*", + "magento/module-configurable-product": "100.3.*" }, "suggest": { - "magento/module-catalog-rule": "*" + "magento/module-catalog-rule": "101.1.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -29,3 +30,4 @@ } } } + diff --git a/app/code/Magento/CatalogRuleGraphQl/composer.json b/app/code/Magento/CatalogRuleGraphQl/composer.json index ecf57716a9c0a..8360df7080ad0 100644 --- a/app/code/Magento/CatalogRuleGraphQl/composer.json +++ b/app/code/Magento/CatalogRuleGraphQl/composer.json @@ -1,24 +1,26 @@ { - "name": "magento/module-catalog-rule-graph-ql", - "description": "N/A", - "type": "magento2-module", - "require": { - "php": "~7.3.0||~7.4.0", - "magento/framework": "*" - }, - "suggest": { - "magento/module-catalog-rule": "*" - }, - "license": [ - "OSL-3.0", - "AFL-3.0" - ], - "autoload": { - "files": [ - "registration.php" + "name": "magento/module-catalog-rule-graph-ql", + "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" ], - "psr-4": { - "Magento\\CatalogRuleGraphQl\\": "" + "version": "100.3.1", + "require": { + "php": "~7.3.0||~7.4.0", + "magento/framework": "102.0.*" + }, + "suggest": { + "magento/module-catalog-rule": "101.1.*" + }, + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Magento\\CatalogRuleGraphQl\\": "" + } } - } } + diff --git a/app/code/Magento/CatalogSearch/composer.json b/app/code/Magento/CatalogSearch/composer.json index 1efece402fd84..2e8f86180e6e0 100644 --- a/app/code/Magento/CatalogSearch/composer.json +++ b/app/code/Magento/CatalogSearch/composer.json @@ -1,32 +1,33 @@ { "name": "magento/module-catalog-search", "description": "Catalog search", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "101.0.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-indexer": "*", - "magento/module-catalog-inventory": "*", - "magento/module-customer": "*", - "magento/module-directory": "*", - "magento/module-eav": "*", - "magento/module-search": "*", - "magento/module-store": "*", - "magento/module-theme": "*", - "magento/module-ui": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-indexer": "100.3.*", + "magento/module-catalog-inventory": "100.3.*", + "magento/module-customer": "102.0.*", + "magento/module-directory": "100.3.*", + "magento/module-eav": "102.0.*", + "magento/module-search": "101.0.*", + "magento/module-store": "101.0.*", + "magento/module-theme": "101.0.*", + "magento/module-ui": "101.1.*" }, "suggest": { - "magento/module-config": "*" + "magento/module-config": "101.1.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -36,3 +37,4 @@ } } } + diff --git a/app/code/Magento/CatalogUrlRewrite/composer.json b/app/code/Magento/CatalogUrlRewrite/composer.json index fe489bcf0a3a0..b00d2d95f9b31 100644 --- a/app/code/Magento/CatalogUrlRewrite/composer.json +++ b/app/code/Magento/CatalogUrlRewrite/composer.json @@ -1,29 +1,30 @@ { "name": "magento/module-catalog-url-rewrite", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-catalog-import-export": "*", - "magento/module-eav": "*", - "magento/module-import-export": "*", - "magento/module-store": "*", - "magento/module-ui": "*", - "magento/module-url-rewrite": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-catalog-import-export": "101.0.*", + "magento/module-eav": "102.0.*", + "magento/module-import-export": "100.3.*", + "magento/module-store": "101.0.*", + "magento/module-ui": "101.1.*", + "magento/module-url-rewrite": "101.1.*" }, "suggest": { - "magento/module-webapi": "*" + "magento/module-webapi": "100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -33,3 +34,4 @@ } } } + diff --git a/app/code/Magento/CatalogUrlRewriteGraphQl/composer.json b/app/code/Magento/CatalogUrlRewriteGraphQl/composer.json index 3b64d51b85568..cee780694eba0 100644 --- a/app/code/Magento/CatalogUrlRewriteGraphQl/composer.json +++ b/app/code/Magento/CatalogUrlRewriteGraphQl/composer.json @@ -2,21 +2,22 @@ "name": "magento/module-catalog-url-rewrite-graph-ql", "description": "N/A", "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "version": "100.3.6", "require": { "php": "~7.3.0||~7.4.0", - "magento/module-store": "*", - "magento/module-catalog": "*", - "magento/framework": "*" + "magento/module-store": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/framework": "102.0.*" }, "suggest": { - "magento/module-catalog-url-rewrite": "*", - "magento/module-catalog-graph-ql": "*", - "magento/module-url-rewrite-graph-ql": "*" + "magento/module-catalog-url-rewrite": "100.3.*", + "magento/module-catalog-graph-ql": "100.3.*", + "magento/module-url-rewrite-graph-ql": "100.3.*" }, - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -26,3 +27,4 @@ } } } + diff --git a/app/code/Magento/CatalogWidget/composer.json b/app/code/Magento/CatalogWidget/composer.json index 305fb3ec47ad6..6a2bd9105e5ff 100644 --- a/app/code/Magento/CatalogWidget/composer.json +++ b/app/code/Magento/CatalogWidget/composer.json @@ -1,27 +1,28 @@ { "name": "magento/module-catalog-widget", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-customer": "*", - "magento/module-eav": "*", - "magento/module-rule": "*", - "magento/module-store": "*", - "magento/module-widget": "*", - "magento/module-wishlist": "*", - "magento/module-theme": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-customer": "102.0.*", + "magento/module-eav": "102.0.*", + "magento/module-rule": "100.3.*", + "magento/module-store": "101.0.*", + "magento/module-widget": "101.1.*", + "magento/module-wishlist": "101.1.*", + "magento/module-theme": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -31,3 +32,4 @@ } } } + diff --git a/app/code/Magento/Checkout/composer.json b/app/code/Magento/Checkout/composer.json index 2c9da4716b497..74d16db916e76 100644 --- a/app/code/Magento/Checkout/composer.json +++ b/app/code/Magento/Checkout/composer.json @@ -1,41 +1,42 @@ { "name": "magento/module-checkout", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-authorization": "*", - "magento/module-captcha": "*", - "magento/module-catalog": "*", - "magento/module-catalog-inventory": "*", - "magento/module-config": "*", - "magento/module-customer": "*", - "magento/module-directory": "*", - "magento/module-eav": "*", - "magento/module-msrp": "*", - "magento/module-page-cache": "*", - "magento/module-payment": "*", - "magento/module-quote": "*", - "magento/module-sales": "*", - "magento/module-sales-rule": "*", - "magento/module-security": "*", - "magento/module-shipping": "*", - "magento/module-store": "*", - "magento/module-tax": "*", - "magento/module-theme": "*", - "magento/module-ui": "*" + "magento/framework": "102.0.*", + "magento/module-authorization": "100.3.*", + "magento/module-captcha": "100.3.*", + "magento/module-catalog": "103.0.*", + "magento/module-catalog-inventory": "100.3.*", + "magento/module-config": "101.1.*", + "magento/module-customer": "102.0.*", + "magento/module-directory": "100.3.*", + "magento/module-eav": "102.0.*", + "magento/module-msrp": "100.3.*", + "magento/module-page-cache": "100.3.*", + "magento/module-payment": "100.3.*", + "magento/module-quote": "101.1.*", + "magento/module-sales": "102.0.*", + "magento/module-sales-rule": "101.1.*", + "magento/module-security": "100.3.*", + "magento/module-shipping": "100.3.*", + "magento/module-store": "101.0.*", + "magento/module-tax": "100.3.*", + "magento/module-theme": "101.0.*", + "magento/module-ui": "101.1.*" }, "suggest": { - "magento/module-cookie": "*" + "magento/module-cookie": "100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -45,3 +46,4 @@ } } } + diff --git a/app/code/Magento/CheckoutAgreements/composer.json b/app/code/Magento/CheckoutAgreements/composer.json index 1741de53e8637..21ccd2d478dcf 100644 --- a/app/code/Magento/CheckoutAgreements/composer.json +++ b/app/code/Magento/CheckoutAgreements/composer.json @@ -1,22 +1,23 @@ { "name": "magento/module-checkout-agreements", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.6", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-checkout": "*", - "magento/module-quote": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-checkout": "100.3.*", + "magento/module-quote": "101.1.*", + "magento/module-store": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -26,3 +27,4 @@ } } } + diff --git a/app/code/Magento/CheckoutAgreementsGraphQl/composer.json b/app/code/Magento/CheckoutAgreementsGraphQl/composer.json index 26b80a4457b4a..7aeb7719dcd86 100644 --- a/app/code/Magento/CheckoutAgreementsGraphQl/composer.json +++ b/app/code/Magento/CheckoutAgreementsGraphQl/composer.json @@ -2,19 +2,20 @@ "name": "magento/module-checkout-agreements-graph-ql", "description": "N/A", "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "version": "100.3.2", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-store": "*", - "magento/module-checkout-agreements": "*" + "magento/framework": "102.0.*", + "magento/module-store": "101.0.*", + "magento/module-checkout-agreements": "100.3.*" }, "suggest": { - "magento/module-graph-ql": "*" + "magento/module-graph-ql": "100.3.*" }, - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -24,3 +25,4 @@ } } } + diff --git a/app/code/Magento/Cms/Controller/Adminhtml/Page/PostDataProcessor.php b/app/code/Magento/Cms/Controller/Adminhtml/Page/PostDataProcessor.php index 71b620a1632ca..d104b11b2dd5c 100644 --- a/app/code/Magento/Cms/Controller/Adminhtml/Page/PostDataProcessor.php +++ b/app/code/Magento/Cms/Controller/Adminhtml/Page/PostDataProcessor.php @@ -10,6 +10,7 @@ use Magento\Framework\App\ObjectManager; use Magento\Framework\Config\Dom\ValidationException; use Magento\Framework\Config\Dom\ValidationSchemaException; +use Magento\Cms\Model\Page\CustomLayout\CustomLayoutValidator; /** * Controller helper for user input. @@ -36,23 +37,32 @@ class PostDataProcessor */ private $validationState; + /** + * @var CustomLayoutValidator + */ + private $customLayoutValidator; + /** * @param \Magento\Framework\Stdlib\DateTime\Filter\Date $dateFilter * @param \Magento\Framework\Message\ManagerInterface $messageManager * @param \Magento\Framework\View\Model\Layout\Update\ValidatorFactory $validatorFactory - * @param DomValidationState $validationState + * @param DomValidationState|null $validationState + * @param CustomLayoutValidator|null $customLayoutValidator */ public function __construct( \Magento\Framework\Stdlib\DateTime\Filter\Date $dateFilter, \Magento\Framework\Message\ManagerInterface $messageManager, \Magento\Framework\View\Model\Layout\Update\ValidatorFactory $validatorFactory, - DomValidationState $validationState = null + DomValidationState $validationState = null, + CustomLayoutValidator $customLayoutValidator = null ) { $this->dateFilter = $dateFilter; $this->messageManager = $messageManager; $this->validatorFactory = $validatorFactory; $this->validationState = $validationState ?: ObjectManager::getInstance()->get(DomValidationState::class); + $this->customLayoutValidator = $customLayoutValidator + ?: ObjectManager::getInstance()->get(CustomLayoutValidator::class); } /** @@ -146,6 +156,9 @@ private function validateData($data, $layoutXmlValidator) ) { return false; } + if (!$this->customLayoutValidator->validate($data)) { + return false; + } } catch (ValidationException $e) { return false; } catch (ValidationSchemaException $e) { diff --git a/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFiles.php b/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFiles.php index fa873930aaade..e9ca54e31442a 100644 --- a/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFiles.php +++ b/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFiles.php @@ -61,7 +61,7 @@ public function __construct( public function execute() { $resultJson = $this->resultJsonFactory->create(); - + $result = []; if (!$this->getRequest()->isPost()) { $result = ['error' => true, 'message' => __('Wrong request.')]; /** @var \Magento\Framework\Controller\Result\Json $resultJson */ @@ -94,8 +94,7 @@ public function execute() // phpcs:ignore Magento2.Exceptions.ThrowCatch } catch (\Exception $e) { $result = ['error' => true, 'message' => $e->getMessage()]; - - return $resultJson->setData($result); } + return $resultJson->setData($result); } } diff --git a/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFolder.php b/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFolder.php index dba91a60ba1cc..683a486c9f6bb 100644 --- a/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFolder.php +++ b/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFolder.php @@ -66,17 +66,16 @@ public function __construct( */ public function execute() { + $result = []; try { $path = $this->getStorage()->getCmsWysiwygImages()->getCurrentPath(); $this->getStorage()->deleteDirectory($path); - - return $this->resultRawFactory->create(); } catch (\Exception $e) { $result = ['error' => true, 'message' => $e->getMessage()]; - /** @var Json $resultJson */ - $resultJson = $this->resultJsonFactory->create(); - - return $resultJson->setData($result); } + /** @var Json $resultJson */ + $resultJson = $this->resultJsonFactory->create(); + + return $resultJson->setData($result); } } diff --git a/app/code/Magento/Cms/Model/Page/CustomLayout/CustomLayoutValidator.php b/app/code/Magento/Cms/Model/Page/CustomLayout/CustomLayoutValidator.php new file mode 100644 index 0000000000000..c8c3924aea28f --- /dev/null +++ b/app/code/Magento/Cms/Model/Page/CustomLayout/CustomLayoutValidator.php @@ -0,0 +1,87 @@ +pageRepository = $pageRepository; + $this->messageManager = $messageManager; + } + + /** + * Validates layout update and custom layout update for CMS page + * + * @param array $data + * @return bool + * @throws LocalizedException + */ + public function validate(array $data) : bool + { + [$layoutUpdate, $customLayoutUpdate, $oldLayoutUpdate, $oldCustomLayoutUpdate] = $this->getLayoutUpdates($data); + if (isset($data['page_id'])) { + if ($layoutUpdate && $oldLayoutUpdate !== $layoutUpdate + || $customLayoutUpdate && $oldCustomLayoutUpdate !== $customLayoutUpdate + ) { + throw new LocalizedException(__('Custom layout update text cannot be changed, only removed')); + } + } else { + if ($layoutUpdate || $customLayoutUpdate) { + throw new LocalizedException(__('Custom layout update text cannot be changed, only removed')); + } + } + return true; + } + + /** + * Gets page layout update values + * + * @param array $data + * @return array + * @throws \Magento\Framework\Exception\NoSuchEntityException + */ + private function getLayoutUpdates(array $data) : array + { + $layoutUpdate = $data['layout_update_xml'] ?? null; + $customLayoutUpdate = $data['custom_layout_update_xml'] ?? null; + $oldLayoutUpdate = null; + $oldCustomLayoutUpdate = null; + if (isset($data['page_id'])) { + $page = $this->pageRepository->getById($data['page_id']); + $oldLayoutUpdate = $page->getId() ? $page->getLayoutUpdateXml() : null; + $oldCustomLayoutUpdate = $page->getId() ? $page->getCustomLayoutUpdateXml() : null; + } + + return [$layoutUpdate, $customLayoutUpdate, $oldLayoutUpdate, $oldCustomLayoutUpdate]; + } +} diff --git a/app/code/Magento/Cms/Model/Wysiwyg/Images/Storage.php b/app/code/Magento/Cms/Model/Wysiwyg/Images/Storage.php index 10fe208ce6651..8561efbe837f3 100644 --- a/app/code/Magento/Cms/Model/Wysiwyg/Images/Storage.php +++ b/app/code/Magento/Cms/Model/Wysiwyg/Images/Storage.php @@ -9,8 +9,10 @@ namespace Magento\Cms\Model\Wysiwyg\Images; use Magento\Cms\Helper\Wysiwyg\Images; +use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\App\ObjectManager; +use Magento\Framework\Exception\LocalizedException; /** * Wysiwyg Images model. @@ -22,6 +24,7 @@ * @SuppressWarnings(PHPMD.TooManyFields) * @SuppressWarnings(PHPMD.CouplingBetweenObjects) * @SuppressWarnings(PHPMD.CookieAndSessionMisuse) + * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) * * @api * @since 100.0.2 @@ -34,6 +37,9 @@ class Storage extends \Magento\Framework\DataObject const THUMB_PLACEHOLDER_PATH_SUFFIX = 'Magento_Cms::images/placeholder_thumbnail.jpg'; + private const MEDIA_GALLERY_IMAGE_FOLDERS_CONFIG_PATH + = 'system/media_storage_configuration/allowed_resources/media_gallery_image_folders'; + /** * Config object * @@ -152,6 +158,21 @@ class Storage extends \Magento\Framework\DataObject */ private $ioFile; + /** + * @var ScopeConfigInterface + */ + private $coreConfig; + + /** + * @var string + */ + private $allowedPathPattern; + + /** + * @var array + */ + private $allowedDirs; + /** * Construct * @@ -174,6 +195,7 @@ class Storage extends \Magento\Framework\DataObject * @param \Magento\Framework\Filesystem\DriverInterface $file * @param \Magento\Framework\Filesystem\Io\File|null $ioFile * @param \Psr\Log\LoggerInterface|null $logger + * @param ScopeConfigInterface $coreConfig * * @throws \Magento\Framework\Exception\FileSystemException * @SuppressWarnings(PHPMD.ExcessiveParameterList) @@ -197,7 +219,8 @@ public function __construct( array $data = [], \Magento\Framework\Filesystem\DriverInterface $file = null, \Magento\Framework\Filesystem\Io\File $ioFile = null, - \Psr\Log\LoggerInterface $logger = null + \Psr\Log\LoggerInterface $logger = null, + ScopeConfigInterface $coreConfig = null ) { $this->_session = $session; $this->_backendUrl = $backendUrl; @@ -217,7 +240,31 @@ public function __construct( $this->_dirs = $dirs; $this->file = $file ?: ObjectManager::getInstance()->get(\Magento\Framework\Filesystem\Driver\File::class); $this->ioFile = $ioFile ?: ObjectManager::getInstance()->get(\Magento\Framework\Filesystem\Io\File::class); + $this->coreConfig = $coreConfig ?: ObjectManager::getInstance()->get(ScopeConfigInterface::class); parent::__construct($data); + $this->initStorage(); + } + + /** + * Initialize storage by creating wysiwyg image folders + * + * @return void + */ + private function initStorage(): void + { + $imageFolders = $this->coreConfig->getValue( + self::MEDIA_GALLERY_IMAGE_FOLDERS_CONFIG_PATH, + 'default' + ); + foreach ($imageFolders as $folder) { + try { + $this->_directory->create($folder); + } catch (LocalizedException $e) { + $this->logger->error( + sprintf("Creating media gallery image folder %s caused error: %s", $folder, $e->getMessage()) + ); + } + } } /** @@ -245,6 +292,7 @@ protected function createSubDirectories($path) * Prepare and get conditions for exclude directories * * @return array + * @deprecated */ protected function getConditionsForExcludeDirs() { @@ -272,6 +320,7 @@ protected function getConditionsForExcludeDirs() * @param \Magento\Framework\Data\Collection\Filesystem $collection * @param array $conditions * @return \Magento\Framework\Data\Collection\Filesystem + * @deprecated */ protected function removeItemFromCollection($collection, $conditions) { @@ -309,9 +358,11 @@ public function getDirsCollection($path) ->setCollectRecursively(false) ->setOrder('basename', \Magento\Framework\Data\Collection\Filesystem::SORT_ORDER_ASC); - $conditions = $this->getConditionsForExcludeDirs(); + if (!$this->isDirectoryAllowed($path)) { + $collection->setDirsFilter($this->getAllowedDirMask($path)); + } - return $this->removeItemFromCollection($collection, $conditions); + return $collection; } /** @@ -326,6 +377,8 @@ public function getDirsCollection($path) */ public function getFilesCollection($path, $type = null) { + $collectFiles = $this->isDirectoryAllowed($path); + if ($this->_coreFileStorageDb->checkDbUsage()) { $files = $this->_storageDatabaseFactory->create()->getDirectoryFiles($path); @@ -341,7 +394,7 @@ public function getFilesCollection($path, $type = null) )->setCollectDirs( false )->setCollectFiles( - true + $collectFiles )->setCollectRecursively( false )->setOrder( @@ -372,6 +425,7 @@ public function getFilesCollection($path, $type = null) } try { + // phpcs:ignore Magento2.Functions.DiscouragedFunction $size = getimagesize($item->getFilename()); if (is_array($size)) { @@ -428,12 +482,18 @@ public function createDirectory($name, $path) ); } - $relativePath = $this->_directory->getRelativePath($path); + if (!($this->isDirectoryAllowed(rtrim($path, '/') . '/' . $name))) { + throw new \Magento\Framework\Exception\LocalizedException( + __('We cannot create the folder under the selected directory.') + ); + } + + $relativePath = (string)$this->_directory->getRelativePath($path); if (!$this->_directory->isDirectory($relativePath) || !$this->_directory->isWritable($relativePath)) { $path = $this->_cmsWysiwygImages->getStorageRoot(); } - $newPath = $path . '/' . $name; + $newPath = rtrim($path, '/') . '/' . $name; $relativeNewPath = $this->_directory->getRelativePath($newPath); if ($this->_directory->isDirectory($relativeNewPath)) { throw new \Magento\Framework\Exception\LocalizedException( @@ -469,14 +529,16 @@ public function createDirectory($name, $path) */ public function deleteDirectory($path) { - if ($this->_coreFileStorageDb->checkDbUsage()) { - $this->_directoryDatabaseFactory->create()->deleteDirectory($path); - } - if (!$this->isPathAllowed($path, $this->getConditionsForExcludeDirs())) { + if (!$this->isDirectoryAllowed($this->file->getParentDirectory($path))) { throw new \Magento\Framework\Exception\LocalizedException( - __('We cannot delete directory %1.', $this->_getRelativePathToRoot($path)) + __('We cannot delete the selected directory.') ); } + + if ($this->_coreFileStorageDb->checkDbUsage()) { + $this->_directoryDatabaseFactory->create()->deleteDirectory($path); + } + try { $this->_deleteByPath($path); $path = $this->getThumbnailRoot() . $this->_getRelativePathToRoot($path); @@ -516,6 +578,11 @@ protected function _deleteByPath($path) */ public function deleteFile($target) { + if (!$this->isDirectoryAllowed($this->file->getParentDirectory($target))) { + throw new \Magento\Framework\Exception\LocalizedException( + __('We can\'t delete the file right now.') + ); + } $relativePath = $this->_directory->getRelativePath($target); if ($this->_directory->isFile($relativePath)) { $this->_directory->delete($relativePath); @@ -549,9 +616,9 @@ public function uploadFile($targetPath, $type = null) $targetPath = $targetPath . DIRECTORY_SEPARATOR; } - if (!$this->isPathAllowed($targetPath, $this->getConditionsForExcludeDirs()) || strlen($targetPath) > 255) { + if (!($this->isDirectoryAllowed($targetPath))) { throw new \Magento\Framework\Exception\LocalizedException( - __('We can\'t upload the file to current folder right now. Please try another folder.') + __('We can\'t upload the file to the current folder right now. Please try another folder.') ); } @@ -573,7 +640,7 @@ public function uploadFile($targetPath, $type = null) } // create thumbnail - $this->resizeFile($targetPath . '/' . $uploader->getUploadedFileName(), true); + $this->resizeFile(rtrim($targetPath, '/') . '/' . ltrim($uploader->getUploadedFileName(), '/'), true); return $result; } @@ -734,7 +801,7 @@ public function getAllowedExtensions($type = null) */ public function getThumbnailRoot() { - return $this->_cmsWysiwygImages->getStorageRoot() . '/' . self::THUMBS_DIRECTORY_NAME; + return rtrim($this->_cmsWysiwygImages->getStorageRoot(), '/') . '/' . self::THUMBS_DIRECTORY_NAME; } /** @@ -875,27 +942,105 @@ private function getExtensionsList($type = null): array } /** - * Check if path is not in excluded dirs. + * Check if directory is allowed * - * @param string $path Absolute path - * @param array $conditions Exclude conditions + * @param string $directoryPath Absolute path to a directory * @return bool */ - private function isPathAllowed($path, array $conditions): bool + private function isDirectoryAllowed($directoryPath): bool { - $isAllowed = true; - $regExp = $conditions['reg_exp'] ? '~' . implode('|', array_keys($conditions['reg_exp'])) . '~i' : null; $storageRoot = $this->_cmsWysiwygImages->getStorageRoot(); $storageRootLength = strlen($storageRoot); + $mediaSubPathname = substr($directoryPath, $storageRootLength); + if (!$mediaSubPathname) { + return false; + } + $mediaSubPathname = ltrim($mediaSubPathname, '/'); + return preg_match($this->getAllowedPathPattern(), $mediaSubPathname) == 1; + } - $mediaSubPathname = substr($path, $storageRootLength); - $rootChildParts = explode('/', '/' . ltrim($mediaSubPathname, '/')); + /** + * Get allowed path pattern + * + * @return string + */ + private function getAllowedPathPattern() + { + if (null === $this->allowedPathPattern) { + $mediaGalleryImageFolders = $this->coreConfig->getValue( + self::MEDIA_GALLERY_IMAGE_FOLDERS_CONFIG_PATH, + 'default' + ); + $regExp = '/^('; + $or = ''; + foreach ($mediaGalleryImageFolders as $folder) { + $folderPattern = str_replace('/', '[\/]+', $folder); + $regExp .= $or . $folderPattern . '\b(?!-)(?:\/?[a-zA-Z0-9\-\_]+)*\/?$'; + $or = '|'; + } + $regExp .= ')/'; + $this->allowedPathPattern = $regExp; + } + return $this->allowedPathPattern; + } + + /** + * Get allowed media gallery image folders + * + * Example: + * [ + * [0 => 'wysiwyg'], + * [0 => 'catalog', 1 => 'category'] + * ]; + * + * @return array + */ + private function getAllowedDirs(): array + { + if (null == $this->allowedDirs) { + $imageFolders = $this->coreConfig->getValue( + self::MEDIA_GALLERY_IMAGE_FOLDERS_CONFIG_PATH, + 'default' + ); + + $this->allowedDirs = []; + foreach ($imageFolders as $folder) { + $this->allowedDirs[] = explode('/', $folder); + } + } + return $this->allowedDirs; + } - if (array_key_exists($rootChildParts[1], $conditions['plain']) - || ($regExp && preg_match($regExp, $path))) { - $isAllowed = false; + /** + * Get allowed dir mask. + * + * @param string $path + * @return string + */ + private function getAllowedDirMask(string $path) + { + $allowedDirs = $this->getAllowedDirs(); + // subfolder level under storage root + $subfolderLevel = 1; + $storageRoot = $this->_cmsWysiwygImages->getStorageRoot(); + $storageRootLength = strlen($storageRoot); + $mediaSubPathname = substr($path, $storageRootLength); + // Filter out the irrelevant allowed dirs for the path from the $allowedDirs array + if ($mediaSubPathname) { + $pathSegments = explode('/', trim($mediaSubPathname, '/')); + foreach ($pathSegments as $index => $pathSegment) { + // Find indexes of the relevant allowed dirs based on the path segment + $subDirKeys = array_keys(array_column($allowedDirs, $index), $pathSegment); + $dirs = []; + // Rebuild the allowed dirs based on the found indexes + foreach ($subDirKeys as $subDirKey) { + $dirs[] = $allowedDirs[$subDirKey]; + } + $allowedDirs = $dirs; + $subfolderLevel++; + } } - return $isAllowed; + return '/^(' . implode('|', array_unique(array_column($allowedDirs, $subfolderLevel - 1))) . ')$/'; } } diff --git a/app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminExpandMediaGalleryFolderActionGroup.xml b/app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminExpandMediaGalleryFolderActionGroup.xml new file mode 100644 index 0000000000000..f8a89a8ed3ac9 --- /dev/null +++ b/app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminExpandMediaGalleryFolderActionGroup.xml @@ -0,0 +1,22 @@ + + + + + + + Expands the provided Folder Name in the Media Gallery. + + + + + + + + + diff --git a/app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminMediaGalleryClickOkButtonTinyMceActionGroup.xml b/app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminMediaGalleryClickOkButtonTinyMceActionGroup.xml new file mode 100644 index 0000000000000..6177eb298b9c3 --- /dev/null +++ b/app/code/Magento/Cms/Test/Mftf/ActionGroup/AdminMediaGalleryClickOkButtonTinyMceActionGroup.xml @@ -0,0 +1,20 @@ + + + + + + + Click ok button on upload image tinyMce popup. + + + + + + + diff --git a/app/code/Magento/Cms/Test/Mftf/ActionGroup/ClickInsertEditImageTinyMCEButtonActionGroup.xml b/app/code/Magento/Cms/Test/Mftf/ActionGroup/ClickInsertEditImageTinyMCEButtonActionGroup.xml new file mode 100644 index 0000000000000..1685898743596 --- /dev/null +++ b/app/code/Magento/Cms/Test/Mftf/ActionGroup/ClickInsertEditImageTinyMCEButtonActionGroup.xml @@ -0,0 +1,19 @@ + + + + + + + Clicks on the 'Insert/edit image' TinyMCE button. + + + + + + diff --git a/app/code/Magento/Cms/Test/Mftf/ActionGroup/DeleteFolderActionGroup.xml b/app/code/Magento/Cms/Test/Mftf/ActionGroup/DeleteFolderActionGroup.xml new file mode 100644 index 0000000000000..8af88b95d44d0 --- /dev/null +++ b/app/code/Magento/Cms/Test/Mftf/ActionGroup/DeleteFolderActionGroup.xml @@ -0,0 +1,27 @@ + + + + + + Deletes the provided folder by name from the Media Gallery. + + + + + + + + + + + + + + + diff --git a/app/code/Magento/Cms/Test/Mftf/Section/TinyMCESection.xml b/app/code/Magento/Cms/Test/Mftf/Section/TinyMCESection.xml index e159424838e16..a60480a411378 100644 --- a/app/code/Magento/Cms/Test/Mftf/Section/TinyMCESection.xml +++ b/app/code/Magento/Cms/Test/Mftf/Section/TinyMCESection.xml @@ -53,6 +53,7 @@ + @@ -62,6 +63,8 @@ + +
diff --git a/app/code/Magento/Cms/Test/Mftf/Test/AdminMediaGalleryPopupUploadImagesWithoutErrorTest.xml b/app/code/Magento/Cms/Test/Mftf/Test/AdminMediaGalleryPopupUploadImagesWithoutErrorTest.xml index bc1688c9d692b..95c12c05337d9 100644 --- a/app/code/Magento/Cms/Test/Mftf/Test/AdminMediaGalleryPopupUploadImagesWithoutErrorTest.xml +++ b/app/code/Magento/Cms/Test/Mftf/Test/AdminMediaGalleryPopupUploadImagesWithoutErrorTest.xml @@ -33,6 +33,17 @@ + + + + + + + + + + + @@ -40,9 +51,23 @@ - - + + + + + + + + + + + + + + + + @@ -53,9 +78,23 @@ - - + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/Cms/Test/Unit/Model/Wysiwyg/Images/StorageTest.php b/app/code/Magento/Cms/Test/Unit/Model/Wysiwyg/Images/StorageTest.php index 91f481127f38e..a660fbbf83458 100644 --- a/app/code/Magento/Cms/Test/Unit/Model/Wysiwyg/Images/StorageTest.php +++ b/app/code/Magento/Cms/Test/Unit/Model/Wysiwyg/Images/StorageTest.php @@ -6,8 +6,10 @@ namespace Magento\Cms\Test\Unit\Model\Wysiwyg\Images; use Magento\Cms\Model\Wysiwyg\Images\Storage\Collection as StorageCollection; +use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\DataObject; +use Magento\Framework\Exception\LocalizedException; /** * @SuppressWarnings(PHPMD.LongVariable) @@ -26,92 +28,92 @@ class StorageTest extends \PHPUnit\Framework\TestCase /** * @var \Magento\Cms\Model\Wysiwyg\Images\Storage */ - protected $imagesStorage; + private $imagesStorage; /** * @var \PHPUnit\Framework\MockObject\MockObject */ - protected $filesystemMock; + private $filesystemMock; /** * @var \PHPUnit\Framework\MockObject\MockObject */ - protected $adapterFactoryMock; + private $adapterFactoryMock; /** * @var \PHPUnit\Framework\MockObject\MockObject */ - protected $imageHelperMock; + private $imageHelperMock; /** * @var array() */ - protected $resizeParameters; + private $resizeParameters; /** * @var \Magento\Cms\Model\Wysiwyg\Images\Storage\CollectionFactory|\PHPUnit\Framework\MockObject\MockObject */ - protected $storageCollectionFactoryMock; + private $storageCollectionFactoryMock; /** * @var \Magento\MediaStorage\Model\File\Storage\FileFactory|\PHPUnit\Framework\MockObject\MockObject */ - protected $storageFileFactoryMock; + private $storageFileFactoryMock; /** * @var \Magento\MediaStorage\Model\File\Storage\DatabaseFactory|\PHPUnit\Framework\MockObject\MockObject */ - protected $storageDatabaseFactoryMock; + private $storageDatabaseFactoryMock; /** * @var \Magento\MediaStorage\Model\File\Storage\Directory\DatabaseFactory|\PHPUnit\Framework\MockObject\MockObject */ - protected $directoryDatabaseFactoryMock; + private $directoryDatabaseFactoryMock; /** * @var \Magento\MediaStorage\Model\File\Storage\Directory\Database|\PHPUnit\Framework\MockObject\MockObject */ - protected $directoryCollectionMock; + private $directoryCollectionMock; /** * @var \Magento\MediaStorage\Model\File\UploaderFactory|\PHPUnit\Framework\MockObject\MockObject */ - protected $uploaderFactoryMock; + private $uploaderFactoryMock; /** * @var \Magento\Backend\Model\Session|\PHPUnit\Framework\MockObject\MockObject */ - protected $sessionMock; + private $sessionMock; /** * @var \Magento\Backend\Model\Url|\PHPUnit\Framework\MockObject\MockObject */ - protected $backendUrlMock; + private $backendUrlMock; /** * @var \Magento\Framework\Filesystem\Directory\Write|\PHPUnit\Framework\MockObject\MockObject */ - protected $directoryMock; + private $directoryMock; /** * @var \Magento\Framework\Filesystem\DriverInterface|\PHPUnit\Framework\MockObject\MockObject */ - protected $driverMock; + private $driverMock; /** * @var \Magento\MediaStorage\Helper\File\Storage\Database|\PHPUnit\Framework\MockObject\MockObject */ - protected $coreFileStorageMock; + private $coreFileStorageMock; /** * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager|\PHPUnit\Framework\MockObject\MockObject */ - protected $objectManagerHelper; + private $objectManagerHelper; /** * @var \Magento\Framework\Filesystem\Io\File|\PHPUnit\Framework\MockObject\MockObject */ - protected $ioFileMock; + private $ioFileMock; /** * @var \Magento\Framework\Filesystem\Driver\File|\PHPUnit\Framework\MockObject\MockObject @@ -125,6 +127,11 @@ class StorageTest extends \PHPUnit\Framework\TestCase 'gif' => 'image/png', ]; + /** + * @var \Magento\Framework\App\Config\ScopeConfigInterface|MockObject + */ + private $coreConfigMock; + /** * @return void * @SuppressWarnings(PHPMD.ExcessiveMethodLength) @@ -229,6 +236,21 @@ function ($path) { 'image_allowed' => $this->allowedImageExtensions, ]; + $this->coreConfigMock = $this->getMockBuilder(ScopeConfigInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $config = [ + 'target', + 'folder1', + 'folder2/subfolder21', + 'folder2/subfolder22', + 'folder3/subfolder31/subfolder32' + ]; + $this->coreConfigMock->expects($this->any()) + ->method('getValue') + ->with('system/media_storage_configuration/allowed_resources/media_gallery_image_folders') + ->willReturn($config); + $this->imagesStorage = $this->objectManagerHelper->getObject( \Magento\Cms\Model\Wysiwyg\Images\Storage::class, [ @@ -252,7 +274,8 @@ function ($path) { ], 'data' => [], 'file' => $this->fileMock, - 'ioFile' => $this->ioFileMock + 'ioFile' => $this->ioFileMock, + 'coreConfig' => $this->coreConfigMock ] ); } @@ -278,11 +301,8 @@ public function testGetResizeHeight() */ public function testDeleteDirectoryOverRoot() { - $this->expectException(\Magento\Framework\Exception\LocalizedException::class); - $this->expectExceptionMessage('Directory /storage/some/another/dir is not under storage root path.'); - - $this->driverMock->expects($this->atLeastOnce())->method('getRealPathSafety')->willReturnArgument(0); - $this->directoryMock->expects($this->atLeastOnce())->method('getAbsolutePath')->willReturnArgument(0); + $this->expectException('Magento\Framework\Exception\LocalizedException'); + $this->expectExceptionMessage('We cannot delete the selected directory.'); $this->imagesStorage->deleteDirectory(self::INVALID_DIRECTORY_OVER_ROOT); } @@ -291,11 +311,8 @@ public function testDeleteDirectoryOverRoot() */ public function testDeleteRootDirectory() { - $this->expectException(\Magento\Framework\Exception\LocalizedException::class); - $this->expectExceptionMessage('We can\'t delete root directory /storage/root/dir right now.'); - - $this->driverMock->expects($this->atLeastOnce())->method('getRealPathSafety')->willReturnArgument(0); - $this->directoryMock->expects($this->atLeastOnce())->method('getAbsolutePath')->willReturnArgument(0); + $this->expectException('Magento\Framework\Exception\LocalizedException'); + $this->expectExceptionMessage('We cannot delete the selected directory.'); $this->imagesStorage->deleteDirectory(self::STORAGE_ROOT_DIR); } @@ -320,7 +337,11 @@ public function testGetDirsCollectionCreateSubDirectories() ->method('create') ->with(rtrim(self::STORAGE_ROOT_DIR, '/') . '/' . $directoryName); - $this->generalTestGetDirsCollection(self::STORAGE_ROOT_DIR); + $this->generalTestGetDirsCollection( + self::STORAGE_ROOT_DIR, + 1, + '/^(target|folder1|folder2|folder3)$/' + ); } /** @@ -330,45 +351,9 @@ public function testGetDirsCollectionCreateSubDirectories() * @param array $expectedRemoveKeys * @dataProvider dirsCollectionDataProvider */ - public function testGetDirsCollection($exclude, $include, $fileNames, $expectedRemoveKeys) + public function testGetDirsCollection($path, $callNum, $dirsFilter = '') { - $this->imagesStorage = $this->objectManagerHelper->getObject( - \Magento\Cms\Model\Wysiwyg\Images\Storage::class, - [ - 'session' => $this->sessionMock, - 'backendUrl' => $this->backendUrlMock, - 'cmsWysiwygImages' => $this->imageHelperMock, - 'coreFileStorageDb' => $this->coreFileStorageMock, - 'filesystem' => $this->filesystemMock, - 'imageFactory' => $this->adapterFactoryMock, - 'assetRepo' => $this->createMock(\Magento\Framework\View\Asset\Repository::class), - 'storageCollectionFactory' => $this->storageCollectionFactoryMock, - 'storageFileFactory' => $this->storageFileFactoryMock, - 'storageDatabaseFactory' => $this->storageDatabaseFactoryMock, - 'directoryDatabaseFactory' => $this->directoryDatabaseFactoryMock, - 'uploaderFactory' => $this->uploaderFactoryMock, - 'resizeParameters' => $this->resizeParameters, - 'dirs' => [ - 'exclude' => $exclude, - 'include' => $include, - ], - ] - ); - - $collection = []; - foreach ($fileNames as $filename) { - /** @var \Magento\Framework\DataObject|\PHPUnit\Framework\MockObject\MockObject $objectMock */ - $objectMock = $this->getMockBuilder(DataObject::class) - ->addMethods(['getFilename']) - ->disableOriginalConstructor() - ->getMock(); - $objectMock->expects($this->any()) - ->method('getFilename') - ->willReturn(self::STORAGE_ROOT_DIR . $filename); - $collection[] = $objectMock; - } - - $this->generalTestGetDirsCollection(self::STORAGE_ROOT_DIR, $collection, $expectedRemoveKeys); + $this->generalTestGetDirsCollection($path, $callNum, $dirsFilter); } /** @@ -378,48 +363,36 @@ public function dirsCollectionDataProvider() { return [ [ - 'exclude' => [ - ['name' => 'dress'], - ], - 'include' => [], - 'filenames' => [], - 'expectRemoveKeys' => [], + 'path' => self::STORAGE_ROOT_DIR, + 'callNum' => 1, + 'dirsFilter' => '/^(target|folder1|folder2|folder3)$/' ], [ - 'exclude' => [], - 'include' => [], - 'filenames' => [ - '/dress', - ], - 'expectRemoveKeys' => [], + 'path' => self::STORAGE_ROOT_DIR . 'target', + 'callNum' => 0, ], [ - 'exclude' => [ - ['name' => 'dress'], - ], - 'include' => [], - 'filenames' => [ - '/collection', - ], - 'expectRemoveKeys' => [], + 'path' => self::STORAGE_ROOT_DIR . 'folder1/subfolder', + 'callNum' => 0, ], [ - 'exclude' => [ - ['name' => 'gear', 'regexp' => 1], - ['name' => 'home', 'regexp' => 1], - ['name' => 'collection'], - ['name' => 'dress'], - ], - 'include' => [ - ['name' => 'home', 'regexp' => 1], - ['name' => 'collection'], - ], - 'filenames' => [ - '/dress', - '/collection', - '/gear', - ], - 'expectRemoveKeys' => [[0], [2]], + 'path' => self::STORAGE_ROOT_DIR . 'folder2', + 'callNum' => 1, + 'dirsFilter' => '/^(subfolder21|subfolder22)$/' + ], + [ + 'path' => self::STORAGE_ROOT_DIR . 'folder3/subfolder31', + 'callNum' => 1, + 'dirsFilter' => '/^(subfolder32)$/' + ], + [ + 'path' => self::STORAGE_ROOT_DIR . 'folder3/subfolder31/subfolder32', + 'callNum' => 0, + ], + [ + 'path' => self::STORAGE_ROOT_DIR . 'unknown', + 'callNum' => 1, + 'dirsFilter' => '/^()$/' ], ]; } @@ -428,10 +401,11 @@ public function dirsCollectionDataProvider() * General conditions for testGetDirsCollection tests * * @param string $path - * @param array $collectionArray - * @param array $expectedRemoveKeys + * @param int $callNum + * @param string $dirsFilter + * @throws \Exception */ - protected function generalTestGetDirsCollection($path, $collectionArray = [], $expectedRemoveKeys = []) + protected function generalTestGetDirsCollection(string $path, int $callNum, string $dirsFilter) { /** @var StorageCollection|\PHPUnit\Framework\MockObject\MockObject $storageCollectionMock */ $storageCollectionMock = $this->getMockBuilder(\Magento\Cms\Model\Wysiwyg\Images\Storage\Collection::class) @@ -453,12 +427,9 @@ protected function generalTestGetDirsCollection($path, $collectionArray = [], $e ->method('setOrder') ->with('basename', \Magento\Framework\Data\Collection\Filesystem::SORT_ORDER_ASC) ->willReturnSelf(); - $storageCollectionMock->expects($this->once()) - ->method('getIterator') - ->willReturn(new \ArrayIterator($collectionArray)); - $storageCollectionInvMock = $storageCollectionMock->expects($this->exactly(count($expectedRemoveKeys))) - ->method('removeItemByKey'); - call_user_func_array([$storageCollectionInvMock, 'withConsecutive'], $expectedRemoveKeys); + $storageCollectionMock->expects($this->exactly($callNum)) + ->method('setDirsFilter') + ->with($dirsFilter); $this->storageCollectionFactoryMock->expects($this->once()) ->method('create') @@ -473,7 +444,7 @@ public function testUploadFile() $targetPath = self::STORAGE_ROOT_DIR . $path; $fileName = 'image.gif'; $realPath = $targetPath . '/' . $fileName; - $thumbnailTargetPath = self::STORAGE_ROOT_DIR . '/.thumbs' . $path; + $thumbnailTargetPath = self::STORAGE_ROOT_DIR . '.thumbs' . $path; $thumbnailDestination = $thumbnailTargetPath . '/' . $fileName; $type = 'image'; $result = [ @@ -541,7 +512,7 @@ public function testUploadFile() } /** - * + * Test upload file with excessive path */ public function testUploadFileWithExcessivePath() { @@ -554,4 +525,18 @@ public function testUploadFileWithExcessivePath() $type = 'image'; $this->imagesStorage->uploadFile($targetPath, $type); } + + /** + * Test create directory with invalid name + */ + public function testCreateDirectoryWithInvalidName() + { + $name = 'папка'; + $path = '/tmp/path'; + $this->expectException(LocalizedException::class); + $this->expectExceptionMessage( + (string)__('Please rename the folder using only letters, numbers, underscores and dashes.') + ); + $this->imagesStorage->createDirectory($name, $path); + } } diff --git a/app/code/Magento/Cms/composer.json b/app/code/Magento/Cms/composer.json index 8d69320102b5e..1a5b400e92d6c 100644 --- a/app/code/Magento/Cms/composer.json +++ b/app/code/Magento/Cms/composer.json @@ -1,30 +1,31 @@ { "name": "magento/module-cms", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "103.0.7-p2", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-email": "*", - "magento/module-media-storage": "*", - "magento/module-store": "*", - "magento/module-theme": "*", - "magento/module-ui": "*", - "magento/module-variable": "*", - "magento/module-widget": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-email": "101.0.*", + "magento/module-media-storage": "100.3.*", + "magento/module-store": "101.0.*", + "magento/module-theme": "101.0.*", + "magento/module-ui": "101.1.*", + "magento/module-variable": "100.3.*", + "magento/module-widget": "101.1.*" }, "suggest": { - "magento/module-cms-sample-data": "*" + "magento/module-cms-sample-data": "Sample Data version: 100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -34,3 +35,4 @@ } } } + diff --git a/app/code/Magento/Cms/etc/config.xml b/app/code/Magento/Cms/etc/config.xml index d7a9e172f59a6..c5b75f6da3a78 100644 --- a/app/code/Magento/Cms/etc/config.xml +++ b/app/code/Magento/Cms/etc/config.xml @@ -30,7 +30,9 @@ - wysiwyg + + wysiwyg + diff --git a/app/code/Magento/Cms/i18n/en_US.csv b/app/code/Magento/Cms/i18n/en_US.csv index 2947c567d75ff..ac4e1c7e0abf0 100644 --- a/app/code/Magento/Cms/i18n/en_US.csv +++ b/app/code/Magento/Cms/i18n/en_US.csv @@ -78,7 +78,7 @@ Pages,Pages "Please rename the folder using only letters, numbers, underscores and dashes.","Please rename the folder using only letters, numbers, underscores and dashes." "We found a directory with the same name. Please try another folder name.","We found a directory with the same name. Please try another folder name." "We cannot create a new directory.","We cannot create a new directory." -"We cannot delete directory %1.","We cannot delete directory %1." +"We cannot delete the selected directory.","We cannot delete the selected directory." "We can't upload the file right now.","We can't upload the file right now." "We can't delete root directory %1 right now.","We can't delete root directory %1 right now." "Directory %1 is not under storage root path.","Directory %1 is not under storage root path." @@ -156,3 +156,6 @@ Enable,Enable "Custom Theme","Custom Theme" "Custom Layout","Custom Layout" "Edit Page Design","Edit Page Design" +"We cannot create the folder under the selected directory.","We cannot create the folder under the selected directory." +"We can't delete the file right now.", "We can't delete the file right now." +"We can't upload the file to the current folder right now. Please try another folder.","We can't upload the file to the current folder right now. Please try another folder." diff --git a/app/code/Magento/CmsGraphQl/composer.json b/app/code/Magento/CmsGraphQl/composer.json index c0c07dddd4dc2..a1ba0f006fbd9 100644 --- a/app/code/Magento/CmsGraphQl/composer.json +++ b/app/code/Magento/CmsGraphQl/composer.json @@ -2,21 +2,22 @@ "name": "magento/module-cms-graph-ql", "description": "N/A", "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "version": "100.3.5", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-cms": "*", - "magento/module-widget": "*" + "magento/framework": "102.0.*", + "magento/module-cms": "103.0.*", + "magento/module-widget": "101.1.*" }, "suggest": { - "magento/module-graph-ql": "*", - "magento/module-graph-ql-cache": "*", - "magento/module-store-graph-ql": "*" + "magento/module-graph-ql": "100.3.*", + "magento/module-graph-ql-cache": "100.3.*", + "magento/module-store-graph-ql": "100.3.*" }, - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -26,3 +27,4 @@ } } } + diff --git a/app/code/Magento/CmsUrlRewrite/composer.json b/app/code/Magento/CmsUrlRewrite/composer.json index 80e150771975f..b90706a863911 100644 --- a/app/code/Magento/CmsUrlRewrite/composer.json +++ b/app/code/Magento/CmsUrlRewrite/composer.json @@ -1,21 +1,22 @@ { "name": "magento/module-cms-url-rewrite", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.6", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-cms": "*", - "magento/module-store": "*", - "magento/module-url-rewrite": "*" + "magento/framework": "102.0.*", + "magento/module-cms": "103.0.*", + "magento/module-store": "101.0.*", + "magento/module-url-rewrite": "101.1.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -25,3 +26,4 @@ } } } + diff --git a/app/code/Magento/CmsUrlRewriteGraphQl/composer.json b/app/code/Magento/CmsUrlRewriteGraphQl/composer.json index d8fbbb4c2e6fd..9b6336e5627ec 100644 --- a/app/code/Magento/CmsUrlRewriteGraphQl/composer.json +++ b/app/code/Magento/CmsUrlRewriteGraphQl/composer.json @@ -2,21 +2,22 @@ "name": "magento/module-cms-url-rewrite-graph-ql", "description": "N/A", "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "version": "100.3.5", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-cms": "*", - "magento/module-store": "*", - "magento/module-url-rewrite-graph-ql": "*" + "magento/framework": "102.0.*", + "magento/module-cms": "103.0.*", + "magento/module-store": "101.0.*", + "magento/module-url-rewrite-graph-ql": "100.3.*" }, "suggest": { - "magento/module-cms-url-rewrite": "*", - "magento/module-catalog-graph-ql": "*" + "magento/module-cms-url-rewrite": "100.3.*", + "magento/module-catalog-graph-ql": "100.3.*" }, - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -26,3 +27,4 @@ } } } + diff --git a/app/code/Magento/Config/composer.json b/app/code/Magento/Config/composer.json index 63eca42a6ac48..94e8e0fdbe40c 100644 --- a/app/code/Magento/Config/composer.json +++ b/app/code/Magento/Config/composer.json @@ -1,25 +1,26 @@ { "name": "magento/module-config", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "101.1.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-cron": "*", - "magento/module-deploy": "*", - "magento/module-directory": "*", - "magento/module-email": "*", - "magento/module-media-storage": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-cron": "100.3.*", + "magento/module-deploy": "100.3.*", + "magento/module-directory": "100.3.*", + "magento/module-email": "101.0.*", + "magento/module-media-storage": "100.3.*", + "magento/module-store": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -29,3 +30,4 @@ } } } + diff --git a/app/code/Magento/ConfigurableImportExport/composer.json b/app/code/Magento/ConfigurableImportExport/composer.json index e27510166a421..2e900764ae1af 100644 --- a/app/code/Magento/ConfigurableImportExport/composer.json +++ b/app/code/Magento/ConfigurableImportExport/composer.json @@ -1,24 +1,25 @@ { "name": "magento/module-configurable-import-export", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.5", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-catalog": "*", - "magento/module-catalog-import-export": "*", - "magento/module-configurable-product": "*", - "magento/module-eav": "*", - "magento/module-import-export": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-catalog-import-export": "101.0.*", + "magento/module-configurable-product": "100.3.*", + "magento/module-eav": "102.0.*", + "magento/module-import-export": "100.3.*", + "magento/module-store": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -28,3 +29,4 @@ } } } + diff --git a/app/code/Magento/ConfigurableProduct/Plugin/Model/Attribute/Backend/AttributeValidation.php b/app/code/Magento/ConfigurableProduct/Plugin/Model/Attribute/Backend/AttributeValidation.php index 4a11137b62af6..468d028289c2f 100644 --- a/app/code/Magento/ConfigurableProduct/Plugin/Model/Attribute/Backend/AttributeValidation.php +++ b/app/code/Magento/ConfigurableProduct/Plugin/Model/Attribute/Backend/AttributeValidation.php @@ -3,13 +3,17 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\ConfigurableProduct\Plugin\Model\Attribute\Backend; +use Closure; use Magento\Catalog\Api\Data\ProductInterface; use Magento\ConfigurableProduct\Model\Product\Type\Configurable; +use Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend; +use Magento\Framework\DataObject; /** - * Skip validate attributes used for create configurable product + * Skip validate attributes used for create configurable product. */ class AttributeValidation { @@ -19,29 +23,36 @@ class AttributeValidation private $configurableProductType; /** - * AttributeValidation constructor. + * @var array + */ + private $unskippableAttributes; + + /** * @param Configurable $configurableProductType + * @param array $unskippableAttributes */ public function __construct( - Configurable $configurableProductType + Configurable $configurableProductType, + array $unskippableAttributes = [] ) { $this->configurableProductType = $configurableProductType; + $this->unskippableAttributes = $unskippableAttributes; } /** - * @param \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend $subject + * Around plugin to skip attribute validation used for create configurable product. + * + * @param AbstractBackend $subject * @param \Closure $proceed - * @param \Magento\Framework\DataObject $entity + * @param DataObject $entity * @return bool */ - public function aroundValidate( - \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend $subject, - \Closure $proceed, - \Magento\Framework\DataObject $entity - ) { + public function aroundValidate(AbstractBackend $subject, Closure $proceed, DataObject $entity) + { $attribute = $subject->getAttribute(); if ($entity instanceof ProductInterface && $entity->getTypeId() == Configurable::TYPE_CODE + && !in_array($attribute->getAttributeCode(), $this->unskippableAttributes) && in_array( $attribute->getAttributeId(), $this->configurableProductType->getUsedProductAttributeIds($entity), @@ -50,6 +61,7 @@ public function aroundValidate( ) { return true; } + return $proceed($entity); } } diff --git a/app/code/Magento/ConfigurableProduct/composer.json b/app/code/Magento/ConfigurableProduct/composer.json index 7b1b1a18416f5..a589c33214dc9 100644 --- a/app/code/Magento/ConfigurableProduct/composer.json +++ b/app/code/Magento/ConfigurableProduct/composer.json @@ -1,38 +1,39 @@ { "name": "magento/module-configurable-product", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7-p2", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-catalog-inventory": "*", - "magento/module-checkout": "*", - "magento/module-customer": "*", - "magento/module-eav": "*", - "magento/module-media-storage": "*", - "magento/module-quote": "*", - "magento/module-store": "*", - "magento/module-ui": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-catalog-inventory": "100.3.*", + "magento/module-checkout": "100.3.*", + "magento/module-customer": "102.0.*", + "magento/module-eav": "102.0.*", + "magento/module-media-storage": "100.3.*", + "magento/module-quote": "101.1.*", + "magento/module-store": "101.0.*", + "magento/module-ui": "101.1.*" }, "suggest": { - "magento/module-msrp": "*", - "magento/module-webapi": "*", - "magento/module-sales": "*", - "magento/module-sales-rule": "*", - "magento/module-product-video": "*", - "magento/module-configurable-sample-data": "*", - "magento/module-product-links-sample-data": "*", - "magento/module-tax": "*" + "magento/module-msrp": "100.3.*", + "magento/module-webapi": "100.3.*", + "magento/module-sales": "102.0.*", + "magento/module-sales-rule": "101.1.*", + "magento/module-product-video": "100.3.*", + "magento/module-configurable-sample-data": "Sample Data version: 100.3.*", + "magento/module-product-links-sample-data": "Sample Data version: 100.3.*", + "magento/module-tax": "100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -42,3 +43,4 @@ } } } + diff --git a/app/code/Magento/ConfigurableProduct/etc/di.xml b/app/code/Magento/ConfigurableProduct/etc/di.xml index c8a278df92dc6..2c4f1dc71010e 100644 --- a/app/code/Magento/ConfigurableProduct/etc/di.xml +++ b/app/code/Magento/ConfigurableProduct/etc/di.xml @@ -33,6 +33,13 @@ + + + + custom_layout_update + + + diff --git a/app/code/Magento/ConfigurableProductGraphQl/composer.json b/app/code/Magento/ConfigurableProductGraphQl/composer.json index 76ec4ad3153e2..2ec04a79c7e4f 100644 --- a/app/code/Magento/ConfigurableProductGraphQl/composer.json +++ b/app/code/Magento/ConfigurableProductGraphQl/composer.json @@ -2,19 +2,20 @@ "name": "magento/module-configurable-product-graph-ql", "description": "N/A", "type": "magento2-module", - "require": { - "php": "~7.3.0||~7.4.0", - "magento/module-catalog": "*", - "magento/module-configurable-product": "*", - "magento/module-catalog-graph-ql": "*", - "magento/module-quote": "*", - "magento/module-quote-graph-ql": "*", - "magento/framework": "*" - }, "license": [ "OSL-3.0", "AFL-3.0" ], + "version": "100.3.6", + "require": { + "php": "~7.3.0||~7.4.0", + "magento/module-catalog": "103.0.*", + "magento/module-configurable-product": "100.3.*", + "magento/module-catalog-graph-ql": "100.3.*", + "magento/module-quote": "101.1.*", + "magento/module-quote-graph-ql": "100.3.*", + "magento/framework": "102.0.*" + }, "autoload": { "files": [ "registration.php" @@ -24,3 +25,4 @@ } } } + diff --git a/app/code/Magento/ConfigurableProductSales/composer.json b/app/code/Magento/ConfigurableProductSales/composer.json index edac2b7782dcc..c75b4a51dde28 100644 --- a/app/code/Magento/ConfigurableProductSales/composer.json +++ b/app/code/Magento/ConfigurableProductSales/composer.json @@ -1,24 +1,25 @@ { "name": "magento/module-configurable-product-sales", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.5", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-catalog": "*", - "magento/module-sales": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-sales": "102.0.*", + "magento/module-store": "101.0.*" }, "suggest": { - "magento/module-configurable-product": "*" + "magento/module-configurable-product": "100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -28,3 +29,4 @@ } } } + diff --git a/app/code/Magento/Contact/composer.json b/app/code/Magento/Contact/composer.json index 1600c1e0c2543..2c4b2a05d8f9f 100644 --- a/app/code/Magento/Contact/composer.json +++ b/app/code/Magento/Contact/composer.json @@ -1,22 +1,23 @@ { "name": "magento/module-contact", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-cms": "*", - "magento/module-config": "*", - "magento/module-customer": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-cms": "103.0.*", + "magento/module-config": "101.1.*", + "magento/module-customer": "102.0.*", + "magento/module-store": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -26,3 +27,4 @@ } } } + diff --git a/app/code/Magento/Cookie/composer.json b/app/code/Magento/Cookie/composer.json index 5a47a5c7993bf..5ae6d953f9398 100644 --- a/app/code/Magento/Cookie/composer.json +++ b/app/code/Magento/Cookie/composer.json @@ -1,22 +1,23 @@ { "name": "magento/module-cookie", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.6", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-store": "101.0.*" }, "suggest": { - "magento/module-backend": "*" + "magento/module-backend": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -26,3 +27,4 @@ } } } + diff --git a/app/code/Magento/Cron/composer.json b/app/code/Magento/Cron/composer.json index 00da35140744b..b6e90c76ec625 100644 --- a/app/code/Magento/Cron/composer.json +++ b/app/code/Magento/Cron/composer.json @@ -1,22 +1,23 @@ { "name": "magento/module-cron", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.6", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-store": "101.0.*" }, "suggest": { - "magento/module-config": "*" + "magento/module-config": "101.1.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -26,3 +27,4 @@ } } } + diff --git a/app/code/Magento/Csp/composer.json b/app/code/Magento/Csp/composer.json index 352735712b1b0..77deb34e7972b 100644 --- a/app/code/Magento/Csp/composer.json +++ b/app/code/Magento/Csp/composer.json @@ -1,19 +1,20 @@ { "name": "magento/module-csp", "description": "CSP module enables Content Security Policies for Magento", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.1-p2", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-store": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -23,3 +24,4 @@ } } } + diff --git a/app/code/Magento/Csp/etc/config.xml b/app/code/Magento/Csp/etc/config.xml index c13cd37ca0340..f0a70946b49a3 100644 --- a/app/code/Magento/Csp/etc/config.xml +++ b/app/code/Magento/Csp/etc/config.xml @@ -38,6 +38,11 @@ 1 0 0 + + http + https + blob + connect-src @@ -87,6 +92,9 @@ 1 0 0 + + data + frame-src @@ -98,7 +106,7 @@ frame-ancestors 1 - 1 + 0 0 0 @@ -115,6 +123,9 @@ 1 0 0 + + data + @@ -138,6 +149,11 @@ 1 0 0 + + http + https + blob + connect-src @@ -187,6 +203,9 @@ 1 0 0 + + data + frame-src @@ -215,6 +234,9 @@ 1 0 0 + + data + diff --git a/app/code/Magento/Csp/etc/csp_whitelist.xml b/app/code/Magento/Csp/etc/csp_whitelist.xml new file mode 100644 index 0000000000000..b0cce028ac8b6 --- /dev/null +++ b/app/code/Magento/Csp/etc/csp_whitelist.xml @@ -0,0 +1,17 @@ + + + + + + + data: + + + + diff --git a/app/code/Magento/CurrencySymbol/composer.json b/app/code/Magento/CurrencySymbol/composer.json index 746cfa0ed033d..ee00f26cb7333 100644 --- a/app/code/Magento/CurrencySymbol/composer.json +++ b/app/code/Magento/CurrencySymbol/composer.json @@ -1,23 +1,24 @@ { "name": "magento/module-currency-symbol", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.6", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-config": "*", - "magento/module-directory": "*", - "magento/module-page-cache": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-config": "101.1.*", + "magento/module-directory": "100.3.*", + "magento/module-page-cache": "100.3.*", + "magento/module-store": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -27,3 +28,4 @@ } } } + diff --git a/app/code/Magento/Customer/Controller/Account/EditPost.php b/app/code/Magento/Customer/Controller/Account/EditPost.php index fe201f417b408..3a8069ef5cda2 100644 --- a/app/code/Magento/Customer/Controller/Account/EditPost.php +++ b/app/code/Magento/Customer/Controller/Account/EditPost.php @@ -4,6 +4,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\Customer\Controller\Account; @@ -191,6 +192,7 @@ public function validateForCsrf(RequestInterface $request): ?bool * Change customer email or password action * * @return Redirect + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ public function execute() { @@ -207,7 +209,7 @@ public function execute() try { // whether a customer enabled change email option - $this->processChangeEmailRequest($currentCustomerDataObject); + $isEmailChanged = $this->processChangeEmailRequest($currentCustomerDataObject); // whether a customer enabled change password option $isPasswordChanged = $this->changeCustomerPassword($currentCustomerDataObject->getEmail()); @@ -223,7 +225,12 @@ public function execute() ); $this->dispatchSuccessEvent($customerCandidateDataObject); $this->messageManager->addSuccessMessage(__('You saved the account information.')); - + // logout from current session if password or email changed. + if ($isPasswordChanged || $isEmailChanged) { + $this->session->logout(); + $this->session->start(); + return $resultRedirect->setPath('customer/account/login'); + } return $resultRedirect->setPath('customer/account'); } catch (InvalidEmailOrPasswordException $e) { $this->messageManager->addErrorMessage($this->escaper->escapeHtml($e->getMessage())); @@ -340,7 +347,7 @@ protected function changeCustomerPassword($email) * Process change email request * * @param CustomerInterface $currentCustomerDataObject - * @return void + * @return bool * @throws InvalidEmailOrPasswordException * @throws UserLockedException */ @@ -353,13 +360,15 @@ private function processChangeEmailRequest(CustomerInterface $currentCustomerDat $currentCustomerDataObject->getId(), $this->getRequest()->getPost('current_password') ); - $this->sessionCleaner->clearFor($currentCustomerDataObject->getId()); + $this->sessionCleaner->clearFor((int) $currentCustomerDataObject->getId()); + return true; } catch (InvalidEmailOrPasswordException $e) { throw new InvalidEmailOrPasswordException( __("The password doesn't match this account. Verify the password and try again.") ); } } + return false; } /** diff --git a/app/code/Magento/Customer/Model/Customer/Attribute/Validator/File.php b/app/code/Magento/Customer/Model/Customer/Attribute/Validator/File.php index dc674c5c3929c..050cb12451f57 100644 --- a/app/code/Magento/Customer/Model/Customer/Attribute/Validator/File.php +++ b/app/code/Magento/Customer/Model/Customer/Attribute/Validator/File.php @@ -37,7 +37,7 @@ public function __construct(EavConfig $eavConfig) public function validate(AttributeInterface $customAttribute): void { $attribute = $this->eavConfig->getAttribute(Customer::ENTITY, $customAttribute->getAttributeCode()); - if ($attribute->getFrontendInput() === 'file') { + if ($attribute->getFrontendInput() === 'file' && !empty($customAttribute->getValue())) { if (!preg_match( '#^/[a-zA-Z0-9_-]/[a-zA-Z0-9_-]/[a-zA-Z0-9_-]+.[a-z]{3,6}$#', $customAttribute->getValue() diff --git a/app/code/Magento/Customer/Model/Metadata/Form/File.php b/app/code/Magento/Customer/Model/Metadata/Form/File.php index 33470f965aff0..b5f2145344574 100644 --- a/app/code/Magento/Customer/Model/Metadata/Form/File.php +++ b/app/code/Magento/Customer/Model/Metadata/Form/File.php @@ -3,6 +3,8 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Customer\Model\Metadata\Form; use Magento\Customer\Model\FileProcessor; @@ -14,6 +16,7 @@ use Magento\Framework\Exception\LocalizedException; use Magento\Framework\File\UploaderFactory; use Magento\Framework\Filesystem; +use Magento\Framework\Filesystem\Io\File as IoFile; /** * Processes files that are save for customer. @@ -62,6 +65,11 @@ class File extends AbstractData */ protected $fileProcessorFactory; + /** + * @var IoFile|null + */ + private $ioFile; + /** * Constructor * @@ -77,6 +85,7 @@ class File extends AbstractData * @param Filesystem $fileSystem * @param UploaderFactory $uploaderFactory * @param \Magento\Customer\Model\FileProcessorFactory|null $fileProcessorFactory + * @param IoFile|null $ioFile * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -91,7 +100,8 @@ public function __construct( \Magento\MediaStorage\Model\File\Validator\NotProtectedExtension $fileValidator, Filesystem $fileSystem, UploaderFactory $uploaderFactory, - \Magento\Customer\Model\FileProcessorFactory $fileProcessorFactory = null + \Magento\Customer\Model\FileProcessorFactory $fileProcessorFactory = null, + IoFile $ioFile = null ) { parent::__construct($localeDate, $logger, $attribute, $localeResolver, $value, $entityTypeCode, $isAjax); $this->urlEncoder = $urlEncoder; @@ -101,6 +111,8 @@ public function __construct( $this->fileProcessorFactory = $fileProcessorFactory ?: ObjectManager::getInstance() ->get(\Magento\Customer\Model\FileProcessorFactory::class); $this->fileProcessor = $this->fileProcessorFactory->create(['entityTypeCode' => $this->_entityTypeCode]); + $this->ioFile = $ioFile ?: ObjectManager::getInstance() + ->get(IoFile::class); } /** @@ -176,7 +188,7 @@ protected function _validateByRules($value) { $label = $value['name']; $rules = $this->getAttribute()->getValidationRules(); - $extension = $this->fileProcessor->getStat($value['name'])['extension']; + $extension = $this->ioFile->getPathInfo($value['name'])['extension']; $fileExtensions = ArrayObjectSearch::getArrayElementByName( $rules, 'file_extensions' @@ -230,7 +242,7 @@ protected function _isUploadedFile($filename) } // This case is required for file uploader UI component - $temporaryFile = FileProcessor::TMP_DIR . '/' . $this->fileProcessor->getStat($filename)['basename']; + $temporaryFile = FileProcessor::TMP_DIR . '/' . $this->ioFile->getPathInfo($filename)['basename']; if ($this->fileProcessor->isExist($temporaryFile)) { return true; } diff --git a/app/code/Magento/Customer/Model/ResourceModel/Customer.php b/app/code/Magento/Customer/Model/ResourceModel/Customer.php index 1477287f79f4b..804f5dbb5e05c 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/Customer.php +++ b/app/code/Magento/Customer/Model/ResourceModel/Customer.php @@ -3,14 +3,15 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\Customer\Model\ResourceModel; use Magento\Customer\Model\AccountConfirmation; use Magento\Customer\Model\Customer\NotificationStorage; use Magento\Framework\App\ObjectManager; -use Magento\Framework\Validator\Exception as ValidatorException; use Magento\Framework\Exception\AlreadyExistsException; +use Magento\Framework\Validator\Exception as ValidatorException; /** * Customer entity resource model @@ -85,7 +86,7 @@ public function __construct( $this->accountConfirmation = $accountConfirmation ?: ObjectManager::getInstance() ->get(AccountConfirmation::class); $this->setType('customer'); - $this->setConnection('customer_read', 'customer_write'); + $this->setConnection('customer_read'); $this->storeManager = $storeManager; } @@ -403,4 +404,45 @@ public function changeResetPasswordLinkToken(\Magento\Customer\Model\Customer $c } return $this; } + + /** + * Gets the session cut off timestamp string for provided customer id. + * + * @param int $customerId + * @return int|null + */ + public function findSessionCutOff(int $customerId): ?int + { + $connection = $this->getConnection(); + $select = $connection->select()->from( + ['customer_table' => $this->getTable('customer_entity')], + ['session_cutoff' => 'customer_table.session_cutoff'] + )->where( + 'entity_id =?', + $customerId + )->limit( + 1 + ); + $lookup = $connection->fetchRow($select); + if (empty($lookup) || $lookup['session_cutoff'] == null) { + return null; + } + return strtotime($lookup['session_cutoff']); + } + + /** + * Update session cutoff column value for customer + * + * @param int $customerId + * @param int $timestamp + * @return void + */ + public function updateSessionCutOff(int $customerId, int $timestamp): void + { + $this->getConnection()->update( + $this->getTable('customer_entity'), + ['session_cutoff' => $this->dateTime->formatDate($timestamp)], + $this->getConnection()->quoteInto('entity_id = ?', $customerId) + ); + } } diff --git a/app/code/Magento/Customer/Model/ResourceModel/Visitor.php b/app/code/Magento/Customer/Model/ResourceModel/Visitor.php index c3a82307ba465..aa2596ccb8001 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/Visitor.php +++ b/app/code/Magento/Customer/Model/ResourceModel/Visitor.php @@ -3,12 +3,12 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\Customer\Model\ResourceModel; /** - * Class Visitor - * @package Magento\Customer\Model\ResourceModel + * Class for Visitor Resource Model */ class Visitor extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb { @@ -59,7 +59,6 @@ protected function _prepareDataForSave(\Magento\Framework\Model\AbstractModel $v { return [ 'customer_id' => $visitor->getCustomerId(), - 'session_id' => $visitor->getSessionId(), 'last_visit_at' => $visitor->getLastVisitAt() ]; } @@ -95,4 +94,45 @@ public function clean(\Magento\Customer\Model\Visitor $object) return $this; } + + /** + * Gets created at value for the visitor id. + * + * @param int $visitorId + * @return int|null + */ + public function fetchCreatedAt(int $visitorId): ?int + { + $connection = $this->getConnection(); + $select = $connection->select()->from( + ['visitor_table' => $this->getTable('customer_visitor')], + ['created_at' => 'visitor_table.created_at'] + )->where( + 'visitor_table.visitor_id = ?', + (string) $visitorId + )->limit( + 1 + ); + $lookup = $connection->fetchRow($select); + if (empty($lookup) || $lookup['created_at'] == null) { + return null; + } + return strtotime($lookup['created_at']); + } + + /** + * Update visitor session created at column value + * + * @param int $visitorId + * @param int $timestamp + * @return void + */ + public function updateCreatedAt(int $visitorId, int $timestamp): void + { + $this->getConnection()->update( + $this->getTable('customer_visitor'), + ['created_at' => $this->dateTime->formatDate($timestamp)], + $this->getConnection()->quoteInto('visitor_id = ?', $visitorId) + ); + } } diff --git a/app/code/Magento/Customer/Model/Session.php b/app/code/Magento/Customer/Model/Session.php index e1a8f53c208ff..192dd2274a71b 100644 --- a/app/code/Magento/Customer/Model/Session.php +++ b/app/code/Magento/Customer/Model/Session.php @@ -3,6 +3,8 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Customer\Model; use Magento\Customer\Api\CustomerRepositoryInterface; @@ -11,6 +13,7 @@ use Magento\Customer\Model\Config\Share; use Magento\Customer\Model\ResourceModel\Customer as ResourceCustomer; use Magento\Framework\App\ObjectManager; +use Magento\Framework\Session\Generic; /** * Customer session model @@ -70,7 +73,7 @@ class Session extends \Magento\Framework\Session\SessionManager protected $_configShare; /** - * @var \Magento\Framework\Session\Generic + * @var Generic */ protected $_session; @@ -132,7 +135,7 @@ class Session extends \Magento\Framework\Session\SessionManager * @param ResourceCustomer $customerResource * @param CustomerFactory $customerFactory * @param \Magento\Framework\UrlFactory $urlFactory - * @param \Magento\Framework\Session\Generic $session + * @param Generic $session * @param \Magento\Framework\Event\ManagerInterface $eventManager * @param \Magento\Framework\App\Http\Context $httpContext * @param CustomerRepositoryInterface $customerRepository @@ -158,7 +161,7 @@ public function __construct( ResourceCustomer $customerResource, CustomerFactory $customerFactory, \Magento\Framework\UrlFactory $urlFactory, - \Magento\Framework\Session\Generic $session, + Generic $session, \Magento\Framework\Event\ManagerInterface $eventManager, \Magento\Framework\App\Http\Context $httpContext, CustomerRepositoryInterface $customerRepository, @@ -176,6 +179,10 @@ public function __construct( $this->customerRepository = $customerRepository; $this->_eventManager = $eventManager; $this->_httpContext = $httpContext; + $this->groupManagement = $groupManagement; + $this->response = $response; + $this->accountConfirmation = $accountConfirmation ?: ObjectManager::getInstance() + ->get(AccountConfirmation::class); parent::__construct( $request, $sidResolver, @@ -187,10 +194,6 @@ public function __construct( $cookieMetadataFactory, $appState ); - $this->groupManagement = $groupManagement; - $this->response = $response; - $this->accountConfirmation = $accountConfirmation ?: ObjectManager::getInstance() - ->get(AccountConfirmation::class); $this->_eventManager->dispatch('customer_session_init', ['customer_session' => $this]); } @@ -310,7 +313,11 @@ public function setCustomer(Customer $customerModel) public function getCustomer() { if ($this->_customerModel === null) { - $this->_customerModel = $this->_customerFactory->create()->load($this->getCustomerId()); + $this->_customerModel = $this->_customerFactory->create(); + + if ($this->getCustomerId()) { + $this->_customerResource->load($this->_customerModel, $this->getCustomerId()); + } } return $this->_customerModel; @@ -504,8 +511,9 @@ public function logout() /** * Authenticate controller action by login customer * - * @param bool|null $loginUrl - * @return bool + * @param bool|null $loginUrl + * @return bool + * @throws \Magento\Framework\Exception\SessionException */ public function authenticate($loginUrl = null) { diff --git a/app/code/Magento/Customer/Model/Session/SessionCleaner.php b/app/code/Magento/Customer/Model/Session/SessionCleaner.php index 1423c94782535..b8bc4b59fadd0 100644 --- a/app/code/Magento/Customer/Model/Session/SessionCleaner.php +++ b/app/code/Magento/Customer/Model/Session/SessionCleaner.php @@ -8,14 +8,14 @@ namespace Magento\Customer\Model\Session; use Magento\Customer\Api\SessionCleanerInterface; +use Magento\Customer\Model\ResourceModel\Customer as CustomerResourceModel; +use Magento\Customer\Model\ResourceModel\Visitor as VisitorResourceModel; use Magento\Customer\Model\ResourceModel\Visitor\CollectionFactory as VisitorCollectionFactory; use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Framework\App\ObjectManager; use Magento\Framework\Intl\DateTimeFactory; -use Magento\Framework\Session\Config; use Magento\Framework\Session\SaveHandlerInterface; use Magento\Framework\Session\SessionManagerInterface; -use Magento\Framework\Stdlib\DateTime; -use Magento\Store\Model\ScopeInterface; /** * Deletes all session data which relates to customer, including current session data. @@ -50,20 +50,42 @@ class SessionCleaner implements SessionCleanerInterface private $saveHandler; /** - * @inheritdoc + * @var CustomerResourceModel + */ + private $customerResourceModel; + + /** + * @var VisitorResourceModel + */ + private $visitorResourceModel; + + /** + * @param ScopeConfigInterface $scopeConfig + * @param DateTimeFactory $dateTimeFactory + * @param VisitorCollectionFactory $visitorCollectionFactory + * @param SessionManagerInterface $sessionManager + * @param SaveHandlerInterface $saveHandler + * @param CustomerResourceModel|null $customerResourceModel + * @param VisitorResourceModel|null $visitorResourceModel */ public function __construct( ScopeConfigInterface $scopeConfig, DateTimeFactory $dateTimeFactory, VisitorCollectionFactory $visitorCollectionFactory, SessionManagerInterface $sessionManager, - SaveHandlerInterface $saveHandler + SaveHandlerInterface $saveHandler, + CustomerResourceModel $customerResourceModel = null, + VisitorResourceModel $visitorResourceModel = null ) { $this->scopeConfig = $scopeConfig; $this->dateTimeFactory = $dateTimeFactory; $this->visitorCollectionFactory = $visitorCollectionFactory; $this->sessionManager = $sessionManager; $this->saveHandler = $saveHandler; + $this->customerResourceModel = $customerResourceModel + ?: ObjectManager::getInstance()->get(CustomerResourceModel::class); + $this->visitorResourceModel = $visitorResourceModel + ?: ObjectManager::getInstance()->get(VisitorResourceModel::class); } /** @@ -71,30 +93,12 @@ public function __construct( */ public function clearFor(int $customerId): void { - if ($this->sessionManager->isSessionExists()) { - //delete old session and move data to the new session - //use this instead of $this->sessionManager->regenerateId because last one doesn't delete old session - // phpcs:ignore Magento2.Functions.DiscouragedFunction - session_regenerate_id(true); - } - - $sessionLifetime = $this->scopeConfig->getValue( - Config::XML_PATH_COOKIE_LIFETIME, - ScopeInterface::SCOPE_STORE - ); $dateTime = $this->dateTimeFactory->create(); - $activeSessionsTime = $dateTime->setTimestamp($dateTime->getTimestamp() - $sessionLifetime) - ->format(DateTime::DATETIME_PHP_FORMAT); - /** @var \Magento\Customer\Model\ResourceModel\Visitor\Collection $visitorCollection */ - $visitorCollection = $this->visitorCollectionFactory->create(); - $visitorCollection->addFieldToFilter('customer_id', $customerId); - $visitorCollection->addFieldToFilter('last_visit_at', ['from' => $activeSessionsTime]); - /** @var \Magento\Customer\Model\Visitor $visitor */ - foreach ($visitorCollection->getItems() as $visitor) { - $sessionId = $visitor->getSessionId(); - $this->sessionManager->start(); - $this->saveHandler->destroy($sessionId); - $this->sessionManager->writeClose(); + $timestamp = $dateTime->getTimestamp(); + $this->customerResourceModel->updateSessionCutOff($customerId, $timestamp); + if ($this->sessionManager->getVisitorData() !== null) { + $visitorId = $this->sessionManager->getVisitorData()['visitor_id']; + $this->visitorResourceModel->updateCreatedAt((int) $visitorId, $timestamp + 1); } } } diff --git a/app/code/Magento/Customer/Model/Session/Validators/CutoffValidator.php b/app/code/Magento/Customer/Model/Session/Validators/CutoffValidator.php new file mode 100644 index 0000000000000..a86afdcf4ec37 --- /dev/null +++ b/app/code/Magento/Customer/Model/Session/Validators/CutoffValidator.php @@ -0,0 +1,85 @@ +customerResource = $customerResource; + $this->visitorResource = $visitorResource; + $this->visitorSession = $visitorSession; + } + + /** + * Validate session + * + * @param SessionManagerInterface $session + * @return void + * @throws SessionException + */ + public function validate(SessionManagerInterface $session): void + { + try { + $visitor = $this->visitorSession->getVisitorData(); + if ($visitor !== null + && array_key_exists('customer_id', $visitor) + && array_key_exists('visitor_id', $visitor) + ) { + $cutoff = $this->customerResource->findSessionCutOff((int) $visitor['customer_id']); + $sessionCreationTime = $this->visitorResource->fetchCreatedAt((int) $visitor['visitor_id']); + if (isset($cutoff, $sessionCreationTime) && $cutoff > $sessionCreationTime) { + throw new SessionException( + new Phrase('The session has expired, please login again.') + ); + } + } + } catch (SessionException $e) { + $session->destroy(['clear_storage' => false]); + // throw core session exception + throw $e; + } + } +} diff --git a/app/code/Magento/Customer/Model/Visitor.php b/app/code/Magento/Customer/Model/Visitor.php index 1f1487c58c168..86b03d887a00d 100644 --- a/app/code/Magento/Customer/Model/Visitor.php +++ b/app/code/Magento/Customer/Model/Visitor.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\Customer\Model; @@ -90,7 +91,6 @@ class Visitor extends \Magento\Framework\Model\AbstractModel * @param array $ignores * @param array $data * @param RequestSafetyInterface|null $requestSafety - * * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -184,6 +184,24 @@ public function initByRequest($observer) return $this; } + /** + * @inheritdoc + */ + public function beforeSave() + { + $this->unsetData("session_id"); + return parent::beforeSave(); + } + + /** + * @inheritdoc + */ + public function afterSave() + { + $this->setSessionId($this->session->getSessionId()); + return parent::afterSave(); + } + /** * Save visitor by request * diff --git a/app/code/Magento/Customer/Setup/Patch/Data/SessionIDColumnCleanUp.php b/app/code/Magento/Customer/Setup/Patch/Data/SessionIDColumnCleanUp.php new file mode 100644 index 0000000000000..961be514d9ba9 --- /dev/null +++ b/app/code/Magento/Customer/Setup/Patch/Data/SessionIDColumnCleanUp.php @@ -0,0 +1,102 @@ +moduleDataSetup = $moduleDataSetup; + $this->logger = $logger; + } + + /** + * @inheritdoc + */ + public function apply() + { + try { + $this->cleanCustomerVisitorTable(); + } catch (\Throwable $e) { + $this->logger->warning( + 'Customer module SessionIDColumnCleanUp patch experienced an error and could not be completed.' + . ' Please submit a support ticket or email us at security@magento.com.' + ); + + return $this; + } + + return $this; + } + + /** + * Remove session id from customer_visitor table. + * + * @throws \Zend_Db_Statement_Exception + */ + private function cleanCustomerVisitorTable() + { + $tableName = $this->moduleDataSetup->getTable('customer_visitor'); + // phpcs:ignore Magento2.SQL.RawQuery + $rawQuery = sprintf( + 'UPDATE %s SET session_id = NULL WHERE session_id IS NOT NULL LIMIT 1000', + $tableName + ); + + $adapter = $this->moduleDataSetup->getConnection(); + if ($adapter instanceof Mysql) { + do { + $result = $adapter->rawQuery($rawQuery)->rowCount(); + } while ($result > 0); + } else { + do { + $result = $adapter->query($rawQuery)->rowCount(); + } while ($result > 0); + } + } + + /** + * @inheritdoc + */ + public static function getDependencies() + { + return []; + } + + /** + * @inheritdoc + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/FileTest.php b/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/FileTest.php index 21d0c44ecade0..bb299afd7f225 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/FileTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/FileTest.php @@ -128,6 +128,8 @@ public function testExtractValueNoRequestScope($expected, $attributeCode = '', $ 'entityTypeCode' => self::ENTITY_TYPE, ]); + $model->setRequestScope(''); + $this->assertEquals($expected, $model->extractValue($this->requestMock)); if (!empty($attributeCode)) { unset($_FILES[$attributeCode]); diff --git a/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/ImageTest.php b/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/ImageTest.php index 81941a718b619..b127ed0d9962d 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/ImageTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/ImageTest.php @@ -3,7 +3,6 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ - declare(strict_types=1); namespace Magento\Customer\Test\Unit\Model\Metadata\Form; @@ -26,7 +25,6 @@ use Magento\Framework\Filesystem\Io\File; use Magento\Framework\Url\EncoderInterface; use Magento\MediaStorage\Model\File\Validator\NotProtectedExtension; -use PHPUnit_Framework_MockObject_MockObject; /** * Tests Metadata/Form/Image class @@ -100,6 +98,9 @@ class ImageTest extends AbstractFormTestCase */ private $driverMock; + /** + * @inheritdoc + */ protected function setUp(): void { parent::setUp(); @@ -201,14 +202,6 @@ public function testValidateIsNotValidFile() ->method('getStoreLabel') ->willReturn('File Input Field Label'); - $this->fileProcessorMock->expects($this->once()) - ->method('getStat') - ->with($value['tmp_name']) - ->willReturn([ - 'extension' => 'txt', - 'basename' => 'tmp_file.txt', - ]); - $this->fileProcessorMock->expects($this->once()) ->method('isExist') ->with(FileProcessor::TMP_DIR . '/' . $value['tmp_name']) @@ -238,20 +231,12 @@ public function testValidate() ->method('getStoreLabel') ->willReturn('File Input Field Label'); - $this->fileProcessorMock->expects($this->once()) - ->method('getStat') - ->with($value['tmp_name']) - ->willReturn([ - 'extension' => 'gif', - 'basename' => 'logo.gif', - ]); - $this->fileProcessorMock->expects($this->once()) ->method('isExist') ->with(FileProcessor::TMP_DIR . '/' . $value['name']) ->willReturn(true); - $this->ioFileSystemMock->expects($this->any()) + $this->ioFileSystemMock->expects($this->once()) ->method('getPathInfo') ->with($value['name']) ->willReturn([ @@ -299,20 +284,12 @@ public function testValidateMaxFileSize() ->method('getValidationRules') ->willReturn([$validationRuleMock]); - $this->fileProcessorMock->expects($this->once()) - ->method('getStat') - ->with($value['tmp_name']) - ->willReturn([ - 'extension' => 'gif', - 'basename' => 'logo.gif', - ]); - $this->fileProcessorMock->expects($this->once()) ->method('isExist') ->with(FileProcessor::TMP_DIR . '/' . $value['name']) ->willReturn(true); - $this->ioFileSystemMock->expects($this->any()) + $this->ioFileSystemMock->expects($this->once()) ->method('getPathInfo') ->with($value['name']) ->willReturn([ @@ -359,20 +336,12 @@ public function testValidateMaxImageWidth() ->method('getValidationRules') ->willReturn([$validationRuleMock]); - $this->fileProcessorMock->expects($this->once()) - ->method('getStat') - ->with($value['tmp_name']) - ->willReturn([ - 'extension' => 'gif', - 'basename' => 'logo.gif', - ]); - $this->fileProcessorMock->expects($this->once()) ->method('isExist') ->with(FileProcessor::TMP_DIR . '/' . $value['name']) ->willReturn(true); - $this->ioFileSystemMock->expects($this->any()) + $this->ioFileSystemMock->expects($this->once()) ->method('getPathInfo') ->with($value['name']) ->willReturn([ @@ -419,20 +388,12 @@ public function testValidateMaxImageHeight() ->method('getValidationRules') ->willReturn([$validationRuleMock]); - $this->fileProcessorMock->expects($this->once()) - ->method('getStat') - ->with($value['tmp_name']) - ->willReturn([ - 'extension' => 'gif', - 'basename' => 'logo.gif', - ]); - $this->fileProcessorMock->expects($this->once()) ->method('isExist') ->with(FileProcessor::TMP_DIR . '/' . $value['name']) ->willReturn(true); - $this->ioFileSystemMock->expects($this->any()) + $this->ioFileSystemMock->expects($this->once()) ->method('getPathInfo') ->with($value['name']) ->willReturn([ diff --git a/app/code/Magento/Customer/Test/Unit/Model/VisitorTest.php b/app/code/Magento/Customer/Test/Unit/Model/VisitorTest.php index 485152e93ac71..c4ed73313eaec 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/VisitorTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/VisitorTest.php @@ -9,8 +9,7 @@ use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; /** - * Class VisitorTest - * @package Magento\Customer\Model + * Class for test for Customer/Model/Visitor */ class VisitorTest extends \PHPUnit\Framework\TestCase { @@ -59,6 +58,7 @@ protected function setUp(): void 'addCommitCallback', 'commit', 'clean', + 'load', ])->disableOriginalConstructor()->getMock(); $this->resource->expects($this->any())->method('getIdFieldName')->willReturn('visitor_id'); $this->resource->expects($this->any())->method('addCommitCallback')->willReturnSelf(); diff --git a/app/code/Magento/Customer/composer.json b/app/code/Magento/Customer/composer.json index 4602404a87a54..847c1a5ea8767 100644 --- a/app/code/Magento/Customer/composer.json +++ b/app/code/Magento/Customer/composer.json @@ -1,42 +1,43 @@ { "name": "magento/module-customer", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "102.0.7-p2", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-authorization": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-checkout": "*", - "magento/module-config": "*", - "magento/module-directory": "*", - "magento/module-eav": "*", - "magento/module-integration": "*", - "magento/module-media-storage": "*", - "magento/module-newsletter": "*", - "magento/module-page-cache": "*", - "magento/module-quote": "*", - "magento/module-review": "*", - "magento/module-sales": "*", - "magento/module-store": "*", - "magento/module-tax": "*", - "magento/module-theme": "*", - "magento/module-ui": "*", - "magento/module-wishlist": "*" + "magento/framework": "102.0.*", + "magento/module-authorization": "100.3.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-checkout": "100.3.*", + "magento/module-config": "101.1.*", + "magento/module-directory": "100.3.*", + "magento/module-eav": "102.0.*", + "magento/module-integration": "100.3.*", + "magento/module-media-storage": "100.3.*", + "magento/module-newsletter": "100.3.*", + "magento/module-page-cache": "100.3.*", + "magento/module-quote": "101.1.*", + "magento/module-review": "100.3.*", + "magento/module-sales": "102.0.*", + "magento/module-store": "101.0.*", + "magento/module-tax": "100.3.*", + "magento/module-theme": "101.0.*", + "magento/module-ui": "101.1.*", + "magento/module-wishlist": "101.1.*" }, "suggest": { - "magento/module-cookie": "*", - "magento/module-customer-sample-data": "*", - "magento/module-webapi": "*" + "magento/module-cookie": "100.3.*", + "magento/module-customer-sample-data": "Sample Data version: 100.3.*", + "magento/module-webapi": "100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -46,3 +47,4 @@ } } } + diff --git a/app/code/Magento/Customer/etc/db_schema.xml b/app/code/Magento/Customer/etc/db_schema.xml index 9f6d75f8ff64f..086f74d24d598 100644 --- a/app/code/Magento/Customer/etc/db_schema.xml +++ b/app/code/Magento/Customer/etc/db_schema.xml @@ -50,6 +50,8 @@ + @@ -508,7 +510,10 @@ comment="Visitor ID"/> - + + diff --git a/app/code/Magento/Customer/etc/db_schema_whitelist.json b/app/code/Magento/Customer/etc/db_schema_whitelist.json index 1e04a75ab300b..35650f0c38bf7 100644 --- a/app/code/Magento/Customer/etc/db_schema_whitelist.json +++ b/app/code/Magento/Customer/etc/db_schema_whitelist.json @@ -29,7 +29,8 @@ "failures_num": true, "first_failure": true, "lock_expired": true, - "lock_expires": true + "lock_expires": true, + "session_cutoff": true }, "index": { "CUSTOMER_ENTITY_STORE_ID": true, @@ -328,6 +329,7 @@ "visitor_id": true, "customer_id": true, "session_id": true, + "created_at": true, "last_visit_at": true }, "index": { diff --git a/app/code/Magento/Customer/etc/di.xml b/app/code/Magento/Customer/etc/di.xml index 6118b3aee9d90..e3c0186c860c5 100644 --- a/app/code/Magento/Customer/etc/di.xml +++ b/app/code/Magento/Customer/etc/di.xml @@ -62,6 +62,16 @@ + + + + Magento\Framework\Session\Validator + + Magento\Customer\Model\Session\Validators\CutoffValidator + + + + Magento\Customer\Model\Config\Share\Proxy @@ -69,6 +79,7 @@ Magento\Customer\Model\ResourceModel\Customer\Proxy Magento\Customer\Model\Session\Storage Magento\Customer\Api\CustomerRepositoryInterface\Proxy + SessionValidator diff --git a/app/code/Magento/CustomerAnalytics/composer.json b/app/code/Magento/CustomerAnalytics/composer.json index abd9e93d89583..6e1c55a0de032 100644 --- a/app/code/Magento/CustomerAnalytics/composer.json +++ b/app/code/Magento/CustomerAnalytics/composer.json @@ -1,17 +1,18 @@ { "name": "magento/module-customer-analytics", "description": "N/A", - "require": { - "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-customer": "*", - "magento/module-analytics": "*" - }, "type": "magento2-module", "license": [ "OSL-3.0", "AFL-3.0" ], + "version": "100.3.5", + "require": { + "php": "~7.3.0||~7.4.0", + "magento/framework": "102.0.*", + "magento/module-customer": "102.0.*", + "magento/module-analytics": "100.3.*" + }, "autoload": { "files": [ "registration.php" @@ -21,3 +22,4 @@ } } } + diff --git a/app/code/Magento/CustomerDownloadableGraphQl/composer.json b/app/code/Magento/CustomerDownloadableGraphQl/composer.json index f7cdbb0dc86d6..bcf171dc2d807 100644 --- a/app/code/Magento/CustomerDownloadableGraphQl/composer.json +++ b/app/code/Magento/CustomerDownloadableGraphQl/composer.json @@ -2,19 +2,20 @@ "name": "magento/module-customer-downloadable-graph-ql", "description": "N/A", "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "version": "100.3.1", "require": { "php": "~7.3.0||~7.4.0", - "magento/module-downloadable-graph-ql": "*", - "magento/module-graph-ql": "*", - "magento/framework": "*" + "magento/module-downloadable-graph-ql": "100.3.*", + "magento/module-graph-ql": "100.3.*", + "magento/framework": "102.0.*" }, "suggest": { - "magento/module-catalog-graph-ql": "*" + "magento/module-catalog-graph-ql": "100.3.*" }, - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -24,3 +25,4 @@ } } } + diff --git a/app/code/Magento/CustomerGraphQl/composer.json b/app/code/Magento/CustomerGraphQl/composer.json index 2ec396ca8ee92..628a5965546ad 100644 --- a/app/code/Magento/CustomerGraphQl/composer.json +++ b/app/code/Magento/CustomerGraphQl/composer.json @@ -2,22 +2,23 @@ "name": "magento/module-customer-graph-ql", "description": "N/A", "type": "magento2-module", - "require": { - "php": "~7.3.0||~7.4.0", - "magento/module-authorization": "*", - "magento/module-customer": "*", - "magento/module-eav": "*", - "magento/module-graph-ql": "*", - "magento/module-newsletter": "*", - "magento/module-integration": "*", - "magento/module-store": "*", - "magento/framework": "*", - "magento/module-directory": "*" - }, "license": [ "OSL-3.0", "AFL-3.0" ], + "version": "100.3.6", + "require": { + "php": "~7.3.0||~7.4.0", + "magento/module-authorization": "100.3.*", + "magento/module-customer": "102.0.*", + "magento/module-eav": "102.0.*", + "magento/module-graph-ql": "100.3.*", + "magento/module-newsletter": "100.3.*", + "magento/module-integration": "100.3.*", + "magento/module-store": "101.0.*", + "magento/framework": "102.0.*", + "magento/module-directory": "100.3.*" + }, "autoload": { "files": [ "registration.php" @@ -27,3 +28,4 @@ } } } + diff --git a/app/code/Magento/CustomerImportExport/composer.json b/app/code/Magento/CustomerImportExport/composer.json index 8104ea01875a6..6591aaf9c6762 100644 --- a/app/code/Magento/CustomerImportExport/composer.json +++ b/app/code/Magento/CustomerImportExport/composer.json @@ -1,24 +1,25 @@ { "name": "magento/module-customer-import-export", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-customer": "*", - "magento/module-directory": "*", - "magento/module-eav": "*", - "magento/module-import-export": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-customer": "102.0.*", + "magento/module-directory": "100.3.*", + "magento/module-eav": "102.0.*", + "magento/module-import-export": "100.3.*", + "magento/module-store": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -28,3 +29,4 @@ } } } + diff --git a/app/code/Magento/Deploy/composer.json b/app/code/Magento/Deploy/composer.json index d8668dbb84874..9229a40d700d6 100644 --- a/app/code/Magento/Deploy/composer.json +++ b/app/code/Magento/Deploy/composer.json @@ -1,22 +1,23 @@ { "name": "magento/module-deploy", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.6", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-config": "*", - "magento/module-require-js": "*", - "magento/module-store": "*", - "magento/module-user": "*" + "magento/framework": "102.0.*", + "magento/module-config": "101.1.*", + "magento/module-require-js": "100.3.*", + "magento/module-store": "101.0.*", + "magento/module-user": "101.1.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "cli_commands.php", @@ -27,3 +28,4 @@ } } } + diff --git a/app/code/Magento/Developer/composer.json b/app/code/Magento/Developer/composer.json index c5c949ec45f62..c5b2f0b974405 100644 --- a/app/code/Magento/Developer/composer.json +++ b/app/code/Magento/Developer/composer.json @@ -1,20 +1,21 @@ { "name": "magento/module-developer", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.6", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-config": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-config": "101.1.*", + "magento/module-store": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -24,3 +25,4 @@ } } } + diff --git a/app/code/Magento/Dhl/composer.json b/app/code/Magento/Dhl/composer.json index d81ae0d7b4969..a2421ad4d2d0f 100644 --- a/app/code/Magento/Dhl/composer.json +++ b/app/code/Magento/Dhl/composer.json @@ -1,31 +1,32 @@ { "name": "magento/module-dhl", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.6", "require": { "php": "~7.3.0||~7.4.0", "lib-libxml": "*", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-catalog-inventory": "*", - "magento/module-config": "*", - "magento/module-directory": "*", - "magento/module-quote": "*", - "magento/module-sales": "*", - "magento/module-shipping": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-catalog-inventory": "100.3.*", + "magento/module-config": "101.1.*", + "magento/module-directory": "100.3.*", + "magento/module-quote": "101.1.*", + "magento/module-sales": "102.0.*", + "magento/module-shipping": "100.3.*", + "magento/module-store": "101.0.*" }, "suggest": { - "magento/module-checkout": "*" + "magento/module-checkout": "100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -35,3 +36,4 @@ } } } + diff --git a/app/code/Magento/Directory/composer.json b/app/code/Magento/Directory/composer.json index e3646d38fe64d..bd0e4fae9bf10 100644 --- a/app/code/Magento/Directory/composer.json +++ b/app/code/Magento/Directory/composer.json @@ -1,22 +1,23 @@ { "name": "magento/module-directory", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7", "require": { "php": "~7.3.0||~7.4.0", "lib-libxml": "*", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-config": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-config": "101.1.*", + "magento/module-store": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -26,3 +27,4 @@ } } } + diff --git a/app/code/Magento/DirectoryGraphQl/composer.json b/app/code/Magento/DirectoryGraphQl/composer.json index ef473e1c43b94..2a504bcc207f1 100644 --- a/app/code/Magento/DirectoryGraphQl/composer.json +++ b/app/code/Magento/DirectoryGraphQl/composer.json @@ -2,17 +2,18 @@ "name": "magento/module-directory-graph-ql", "description": "N/A", "type": "magento2-module", - "require": { - "php": "~7.3.0||~7.4.0", - "magento/module-directory": "*", - "magento/module-store": "*", - "magento/module-graph-ql": "*", - "magento/framework": "*" - }, "license": [ "OSL-3.0", "AFL-3.0" ], + "version": "100.3.4", + "require": { + "php": "~7.3.0||~7.4.0", + "magento/module-directory": "100.3.*", + "magento/module-store": "101.0.*", + "magento/module-graph-ql": "100.3.*", + "magento/framework": "102.0.*" + }, "autoload": { "files": [ "registration.php" @@ -22,3 +23,4 @@ } } } + diff --git a/app/code/Magento/Downloadable/composer.json b/app/code/Magento/Downloadable/composer.json index 992bdbd1e263c..4ccc7b1330ea9 100644 --- a/app/code/Magento/Downloadable/composer.json +++ b/app/code/Magento/Downloadable/composer.json @@ -1,37 +1,38 @@ { "name": "magento/module-downloadable", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-catalog-inventory": "*", - "magento/module-checkout": "*", - "magento/module-config": "*", - "magento/module-customer": "*", - "magento/module-directory": "*", - "magento/module-eav": "*", - "magento/module-gift-message": "*", - "magento/module-media-storage": "*", - "magento/module-quote": "*", - "magento/module-sales": "*", - "magento/module-store": "*", - "magento/module-tax": "*", - "magento/module-theme": "*", - "magento/module-ui": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-catalog-inventory": "100.3.*", + "magento/module-checkout": "100.3.*", + "magento/module-config": "101.1.*", + "magento/module-customer": "102.0.*", + "magento/module-directory": "100.3.*", + "magento/module-eav": "102.0.*", + "magento/module-gift-message": "100.3.*", + "magento/module-media-storage": "100.3.*", + "magento/module-quote": "101.1.*", + "magento/module-sales": "102.0.*", + "magento/module-store": "101.0.*", + "magento/module-tax": "100.3.*", + "magento/module-theme": "101.0.*", + "magento/module-ui": "101.1.*" }, "suggest": { - "magento/module-downloadable-sample-data": "*" + "magento/module-downloadable-sample-data": "Sample Data version: 100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -41,3 +42,4 @@ } } } + diff --git a/app/code/Magento/DownloadableGraphQl/composer.json b/app/code/Magento/DownloadableGraphQl/composer.json index 185a50f77cc15..bb0d6a4b0dc93 100644 --- a/app/code/Magento/DownloadableGraphQl/composer.json +++ b/app/code/Magento/DownloadableGraphQl/composer.json @@ -2,21 +2,22 @@ "name": "magento/module-downloadable-graph-ql", "description": "N/A", "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "version": "100.3.5", "require": { "php": "~7.3.0||~7.4.0", - "magento/module-catalog": "*", - "magento/module-downloadable": "*", - "magento/module-quote": "*", - "magento/module-quote-graph-ql": "*", - "magento/framework": "*" + "magento/module-catalog": "103.0.*", + "magento/module-downloadable": "100.3.*", + "magento/module-quote": "101.1.*", + "magento/module-quote-graph-ql": "100.3.*", + "magento/framework": "102.0.*" }, "suggest": { - "magento/module-catalog-graph-ql": "*" + "magento/module-catalog-graph-ql": "100.3.*" }, - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -26,3 +27,4 @@ } } } + diff --git a/app/code/Magento/DownloadableImportExport/composer.json b/app/code/Magento/DownloadableImportExport/composer.json index 6dd7043fc02a9..c156946725052 100644 --- a/app/code/Magento/DownloadableImportExport/composer.json +++ b/app/code/Magento/DownloadableImportExport/composer.json @@ -1,24 +1,25 @@ { "name": "magento/module-downloadable-import-export", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-catalog": "*", - "magento/module-catalog-import-export": "*", - "magento/module-downloadable": "*", - "magento/module-eav": "*", - "magento/module-import-export": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-catalog-import-export": "101.0.*", + "magento/module-downloadable": "100.3.*", + "magento/module-eav": "102.0.*", + "magento/module-import-export": "100.3.*", + "magento/module-store": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -28,3 +29,4 @@ } } } + diff --git a/app/code/Magento/Eav/composer.json b/app/code/Magento/Eav/composer.json index 5636b0d05841c..fb59bc1808b4e 100644 --- a/app/code/Magento/Eav/composer.json +++ b/app/code/Magento/Eav/composer.json @@ -1,23 +1,24 @@ { "name": "magento/module-eav", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "102.0.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-config": "*", - "magento/module-media-storage": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-config": "101.1.*", + "magento/module-media-storage": "100.3.*", + "magento/module-store": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -27,3 +28,4 @@ } } } + diff --git a/app/code/Magento/EavGraphQl/composer.json b/app/code/Magento/EavGraphQl/composer.json index ba4138f67cf62..ad7fde9a0aa7a 100644 --- a/app/code/Magento/EavGraphQl/composer.json +++ b/app/code/Magento/EavGraphQl/composer.json @@ -2,18 +2,19 @@ "name": "magento/module-eav-graph-ql", "description": "N/A", "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "version": "100.3.5", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-eav": "*" + "magento/framework": "102.0.*", + "magento/module-eav": "102.0.*" }, "suggest": { - "magento/module-graph-ql": "*" + "magento/module-graph-ql": "100.3.*" }, - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -23,3 +24,4 @@ } } } + diff --git a/app/code/Magento/Elasticsearch/composer.json b/app/code/Magento/Elasticsearch/composer.json index 28aee5bf7c047..0c286f2b0e004 100644 --- a/app/code/Magento/Elasticsearch/composer.json +++ b/app/code/Magento/Elasticsearch/composer.json @@ -1,27 +1,28 @@ { "name": "magento/module-elasticsearch", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "version": "100.3.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/module-advanced-search": "*", - "magento/module-catalog": "*", - "magento/module-catalog-search": "*", - "magento/module-customer": "*", - "magento/module-eav": "*", - "magento/module-search": "*", - "magento/module-store": "*", - "magento/module-catalog-inventory": "*", - "magento/framework": "*", + "magento/module-advanced-search": "100.3.*", + "magento/module-catalog": "103.0.*", + "magento/module-catalog-search": "101.0.*", + "magento/module-customer": "102.0.*", + "magento/module-eav": "102.0.*", + "magento/module-search": "101.0.*", + "magento/module-store": "101.0.*", + "magento/module-catalog-inventory": "100.3.*", + "magento/framework": "102.0.*", "elasticsearch/elasticsearch": "~2.0||~5.1||~6.1||~7.6" }, "suggest": { - "magento/module-config": "*" + "magento/module-config": "101.1.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -31,3 +32,4 @@ } } } + diff --git a/app/code/Magento/Elasticsearch6/composer.json b/app/code/Magento/Elasticsearch6/composer.json index 2abf615c9f74c..71dc8ba4ceaab 100644 --- a/app/code/Magento/Elasticsearch6/composer.json +++ b/app/code/Magento/Elasticsearch6/composer.json @@ -1,23 +1,24 @@ { "name": "magento/module-elasticsearch-6", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "version": "100.3.6", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-advanced-search": "*", - "magento/module-catalog-search": "*", - "magento/module-search": "*", - "magento/module-elasticsearch": "*", + "magento/framework": "102.0.*", + "magento/module-advanced-search": "100.3.*", + "magento/module-catalog-search": "101.0.*", + "magento/module-search": "101.0.*", + "magento/module-elasticsearch": "100.3.*", "elasticsearch/elasticsearch": "~2.0||~5.1||~6.1||~7.6" }, "suggest": { - "magento/module-config": "*" + "magento/module-config": "101.1.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -27,3 +28,4 @@ } } } + diff --git a/app/code/Magento/Elasticsearch7/composer.json b/app/code/Magento/Elasticsearch7/composer.json index 64fbacc139531..ebce45f59211c 100644 --- a/app/code/Magento/Elasticsearch7/composer.json +++ b/app/code/Magento/Elasticsearch7/composer.json @@ -1,23 +1,24 @@ { "name": "magento/module-elasticsearch-7", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "version": "100.3.2", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-advanced-search": "*", - "magento/module-catalog-search": "*", - "magento/module-search": "*", - "magento/module-elasticsearch": "*", + "magento/framework": "102.0.*", + "magento/module-advanced-search": "100.3.*", + "magento/module-catalog-search": "101.0.*", + "magento/module-search": "101.0.*", + "magento/module-elasticsearch": "100.3.*", "elasticsearch/elasticsearch": "~2.0||~5.1||~6.1||~7.6 " }, "suggest": { - "magento/module-config": "*" + "magento/module-config": "101.1.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -27,3 +28,4 @@ } } } + diff --git a/app/code/Magento/Email/composer.json b/app/code/Magento/Email/composer.json index a85c6177c8a48..c201da971cf15 100644 --- a/app/code/Magento/Email/composer.json +++ b/app/code/Magento/Email/composer.json @@ -1,29 +1,30 @@ { "name": "magento/module-email", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "101.0.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-cms": "*", - "magento/module-config": "*", - "magento/module-store": "*", - "magento/module-theme": "*", - "magento/module-require-js": "*", - "magento/module-media-storage": "*", - "magento/module-variable": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-cms": "103.0.*", + "magento/module-config": "101.1.*", + "magento/module-store": "101.0.*", + "magento/module-theme": "101.0.*", + "magento/module-require-js": "100.3.*", + "magento/module-media-storage": "100.3.*", + "magento/module-variable": "100.3.*" }, "suggest": { - "magento/module-theme": "*" + "magento/module-theme": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -33,3 +34,4 @@ } } } + diff --git a/app/code/Magento/EncryptionKey/composer.json b/app/code/Magento/EncryptionKey/composer.json index 6677a5b181f83..03912fed221d2 100644 --- a/app/code/Magento/EncryptionKey/composer.json +++ b/app/code/Magento/EncryptionKey/composer.json @@ -1,20 +1,21 @@ { "name": "magento/module-encryption-key", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.6", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-config": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-config": "101.1.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -24,3 +25,4 @@ } } } + diff --git a/app/code/Magento/Fedex/composer.json b/app/code/Magento/Fedex/composer.json index 575311e148457..3b36d342332a5 100644 --- a/app/code/Magento/Fedex/composer.json +++ b/app/code/Magento/Fedex/composer.json @@ -1,27 +1,28 @@ { "name": "magento/module-fedex", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.6", "require": { "php": "~7.3.0||~7.4.0", "lib-libxml": "*", - "magento/framework": "*", - "magento/module-catalog": "*", - "magento/module-catalog-inventory": "*", - "magento/module-config": "*", - "magento/module-directory": "*", - "magento/module-quote": "*", - "magento/module-sales": "*", - "magento/module-shipping": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-catalog-inventory": "100.3.*", + "magento/module-config": "101.1.*", + "magento/module-directory": "100.3.*", + "magento/module-quote": "101.1.*", + "magento/module-sales": "102.0.*", + "magento/module-shipping": "100.3.*", + "magento/module-store": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -31,3 +32,4 @@ } } } + diff --git a/app/code/Magento/GiftMessage/composer.json b/app/code/Magento/GiftMessage/composer.json index cdf0533c3270d..655bc7dd1cafe 100644 --- a/app/code/Magento/GiftMessage/composer.json +++ b/app/code/Magento/GiftMessage/composer.json @@ -1,30 +1,31 @@ { "name": "magento/module-gift-message", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.5", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-checkout": "*", - "magento/module-customer": "*", - "magento/module-quote": "*", - "magento/module-sales": "*", - "magento/module-store": "*", - "magento/module-ui": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-checkout": "100.3.*", + "magento/module-customer": "102.0.*", + "magento/module-quote": "101.1.*", + "magento/module-sales": "102.0.*", + "magento/module-store": "101.0.*", + "magento/module-ui": "101.1.*" }, "suggest": { - "magento/module-eav": "*", - "magento/module-multishipping": "*" + "magento/module-eav": "102.0.*", + "magento/module-multishipping": "100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -34,3 +35,4 @@ } } } + diff --git a/app/code/Magento/GoogleAdwords/composer.json b/app/code/Magento/GoogleAdwords/composer.json index a37470115584f..ab859a6f329c0 100644 --- a/app/code/Magento/GoogleAdwords/composer.json +++ b/app/code/Magento/GoogleAdwords/composer.json @@ -1,20 +1,21 @@ { "name": "magento/module-google-adwords", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.6", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-sales": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-sales": "102.0.*", + "magento/module-store": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -24,3 +25,4 @@ } } } + diff --git a/app/code/Magento/GoogleAnalytics/composer.json b/app/code/Magento/GoogleAnalytics/composer.json index 64d210c4f4811..10b9cdf06bebf 100644 --- a/app/code/Magento/GoogleAnalytics/composer.json +++ b/app/code/Magento/GoogleAnalytics/composer.json @@ -1,24 +1,25 @@ { "name": "magento/module-google-analytics", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.5", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-cookie": "*", - "magento/module-sales": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-cookie": "100.3.*", + "magento/module-sales": "102.0.*", + "magento/module-store": "101.0.*" }, "suggest": { - "magento/module-config": "*" + "magento/module-config": "101.1.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -28,3 +29,4 @@ } } } + diff --git a/app/code/Magento/GoogleOptimizer/composer.json b/app/code/Magento/GoogleOptimizer/composer.json index 426526a922ec8..4a15864d271ed 100644 --- a/app/code/Magento/GoogleOptimizer/composer.json +++ b/app/code/Magento/GoogleOptimizer/composer.json @@ -1,24 +1,25 @@ { "name": "magento/module-google-optimizer", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.6", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-cms": "*", - "magento/module-google-analytics": "*", - "magento/module-store": "*", - "magento/module-ui": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-cms": "103.0.*", + "magento/module-google-analytics": "100.3.*", + "magento/module-store": "101.0.*", + "magento/module-ui": "101.1.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -28,3 +29,4 @@ } } } + diff --git a/app/code/Magento/GraphQl/composer.json b/app/code/Magento/GraphQl/composer.json index 904d41c97953e..5c34f5518b1c8 100644 --- a/app/code/Magento/GraphQl/composer.json +++ b/app/code/Magento/GraphQl/composer.json @@ -2,19 +2,20 @@ "name": "magento/module-graph-ql", "description": "N/A", "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "version": "100.3.6", "require": { "php": "~7.3.0||~7.4.0", - "magento/module-eav": "*", - "magento/framework": "*" + "magento/module-eav": "102.0.*", + "magento/framework": "102.0.*" }, "suggest": { - "magento/module-webapi": "*", - "magento/module-graph-ql-cache": "*" + "magento/module-webapi": "100.3.*", + "magento/module-graph-ql-cache": "100.3.*" }, - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -24,3 +25,4 @@ } } } + diff --git a/app/code/Magento/GraphQlCache/composer.json b/app/code/Magento/GraphQlCache/composer.json index 4cfdd0c4f660a..5613963d20dc6 100644 --- a/app/code/Magento/GraphQlCache/composer.json +++ b/app/code/Magento/GraphQlCache/composer.json @@ -2,16 +2,17 @@ "name": "magento/module-graph-ql-cache", "description": "N/A", "type": "magento2-module", - "require": { - "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-page-cache": "*", - "magento/module-graph-ql": "*" - }, "license": [ "OSL-3.0", "AFL-3.0" ], + "version": "100.3.3", + "require": { + "php": "~7.3.0||~7.4.0", + "magento/framework": "102.0.*", + "magento/module-page-cache": "100.3.*", + "magento/module-graph-ql": "100.3.*" + }, "autoload": { "files": [ "registration.php" @@ -21,3 +22,4 @@ } } } + diff --git a/app/code/Magento/GroupedCatalogInventory/composer.json b/app/code/Magento/GroupedCatalogInventory/composer.json index 0d91d939494a8..1246ab7e0c4f9 100644 --- a/app/code/Magento/GroupedCatalogInventory/composer.json +++ b/app/code/Magento/GroupedCatalogInventory/composer.json @@ -1,21 +1,22 @@ { "name": "magento/module-grouped-catalog-inventory", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.4", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-catalog": "*", - "magento/module-catalog-inventory": "*", - "magento/module-grouped-product": "*" + "magento/framework": "102.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-catalog-inventory": "100.3.*", + "magento/module-grouped-product": "100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -25,3 +26,4 @@ } } } + diff --git a/app/code/Magento/GroupedImportExport/composer.json b/app/code/Magento/GroupedImportExport/composer.json index 8806058c2bfc8..f8fd40fa61529 100644 --- a/app/code/Magento/GroupedImportExport/composer.json +++ b/app/code/Magento/GroupedImportExport/composer.json @@ -1,23 +1,24 @@ { "name": "magento/module-grouped-import-export", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.5", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-catalog": "*", - "magento/module-catalog-import-export": "*", - "magento/module-eav": "*", - "magento/module-grouped-product": "*", - "magento/module-import-export": "*" + "magento/framework": "102.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-catalog-import-export": "101.0.*", + "magento/module-eav": "102.0.*", + "magento/module-grouped-product": "100.3.*", + "magento/module-import-export": "100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -27,3 +28,4 @@ } } } + diff --git a/app/code/Magento/GroupedProduct/composer.json b/app/code/Magento/GroupedProduct/composer.json index 448b7556089bf..78faaab2f0fca 100644 --- a/app/code/Magento/GroupedProduct/composer.json +++ b/app/code/Magento/GroupedProduct/composer.json @@ -1,33 +1,34 @@ { "name": "magento/module-grouped-product", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-catalog-inventory": "*", - "magento/module-checkout": "*", - "magento/module-customer": "*", - "magento/module-eav": "*", - "magento/module-media-storage": "*", - "magento/module-msrp": "*", - "magento/module-quote": "*", - "magento/module-sales": "*", - "magento/module-store": "*", - "magento/module-ui": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-catalog-inventory": "100.3.*", + "magento/module-checkout": "100.3.*", + "magento/module-customer": "102.0.*", + "magento/module-eav": "102.0.*", + "magento/module-media-storage": "100.3.*", + "magento/module-msrp": "100.3.*", + "magento/module-quote": "101.1.*", + "magento/module-sales": "102.0.*", + "magento/module-store": "101.0.*", + "magento/module-ui": "101.1.*" }, "suggest": { - "magento/module-grouped-product-sample-data": "*" + "magento/module-grouped-product-sample-data": "Sample Data version: 100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -37,3 +38,4 @@ } } } + diff --git a/app/code/Magento/GroupedProductGraphQl/composer.json b/app/code/Magento/GroupedProductGraphQl/composer.json index 5784acb5f5d04..78472898b1ad3 100644 --- a/app/code/Magento/GroupedProductGraphQl/composer.json +++ b/app/code/Magento/GroupedProductGraphQl/composer.json @@ -2,17 +2,18 @@ "name": "magento/module-grouped-product-graph-ql", "description": "N/A", "type": "magento2-module", - "require": { - "php": "~7.3.0||~7.4.0", - "magento/module-grouped-product": "*", - "magento/module-catalog": "*", - "magento/module-catalog-graph-ql": "*", - "magento/framework": "*" - }, "license": [ "OSL-3.0", "AFL-3.0" ], + "version": "100.3.6", + "require": { + "php": "~7.3.0||~7.4.0", + "magento/module-grouped-product": "100.3.*", + "magento/module-catalog": "103.0.*", + "magento/module-catalog-graph-ql": "100.3.*", + "magento/framework": "102.0.*" + }, "autoload": { "files": [ "registration.php" @@ -22,3 +23,4 @@ } } } + diff --git a/app/code/Magento/ImportExport/composer.json b/app/code/Magento/ImportExport/composer.json index 3be5c03dc2828..b510c11501e49 100644 --- a/app/code/Magento/ImportExport/composer.json +++ b/app/code/Magento/ImportExport/composer.json @@ -1,25 +1,26 @@ { "name": "magento/module-import-export", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7", "require": { "php": "~7.3.0||~7.4.0", "ext-ctype": "*", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-eav": "*", - "magento/module-media-storage": "*", - "magento/module-store": "*", - "magento/module-ui": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-eav": "102.0.*", + "magento/module-media-storage": "100.3.*", + "magento/module-store": "101.0.*", + "magento/module-ui": "101.1.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -29,3 +30,4 @@ } } } + diff --git a/app/code/Magento/Indexer/composer.json b/app/code/Magento/Indexer/composer.json index 07d652e9fa2b5..1710e73baa3d6 100644 --- a/app/code/Magento/Indexer/composer.json +++ b/app/code/Magento/Indexer/composer.json @@ -1,19 +1,20 @@ { "name": "magento/module-indexer", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -23,3 +24,4 @@ } } } + diff --git a/app/code/Magento/InstantPurchase/composer.json b/app/code/Magento/InstantPurchase/composer.json index 0807926b755a0..92286600cb29a 100644 --- a/app/code/Magento/InstantPurchase/composer.json +++ b/app/code/Magento/InstantPurchase/composer.json @@ -6,16 +6,17 @@ "OSL-3.0", "AFL-3.0" ], + "version": "100.3.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/module-store": "*", - "magento/module-catalog": "*", - "magento/module-customer": "*", - "magento/module-sales": "*", - "magento/module-shipping": "*", - "magento/module-quote": "*", - "magento/module-vault": "*", - "magento/framework": "*" + "magento/module-store": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-customer": "102.0.*", + "magento/module-sales": "102.0.*", + "magento/module-shipping": "100.3.*", + "magento/module-quote": "101.1.*", + "magento/module-vault": "101.1.*", + "magento/framework": "102.0.*" }, "autoload": { "files": [ @@ -26,3 +27,4 @@ } } } + diff --git a/app/code/Magento/Integration/composer.json b/app/code/Magento/Integration/composer.json index 0b9752c743213..7b9a4f1297061 100644 --- a/app/code/Magento/Integration/composer.json +++ b/app/code/Magento/Integration/composer.json @@ -1,24 +1,25 @@ { "name": "magento/module-integration", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.6", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-authorization": "*", - "magento/module-backend": "*", - "magento/module-customer": "*", - "magento/module-security": "*", - "magento/module-store": "*", - "magento/module-user": "*" + "magento/framework": "102.0.*", + "magento/module-authorization": "100.3.*", + "magento/module-backend": "101.0.*", + "magento/module-customer": "102.0.*", + "magento/module-security": "100.3.*", + "magento/module-store": "101.0.*", + "magento/module-user": "101.1.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -28,3 +29,4 @@ } } } + diff --git a/app/code/Magento/LayeredNavigation/composer.json b/app/code/Magento/LayeredNavigation/composer.json index fa3c90dbbd774..623e0dd018ee0 100644 --- a/app/code/Magento/LayeredNavigation/composer.json +++ b/app/code/Magento/LayeredNavigation/composer.json @@ -1,20 +1,21 @@ { "name": "magento/module-layered-navigation", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.5", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-catalog": "*", - "magento/module-config": "*" + "magento/framework": "102.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-config": "101.1.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -24,3 +25,4 @@ } } } + diff --git a/app/code/Magento/Marketplace/composer.json b/app/code/Magento/Marketplace/composer.json index 42bbcf151a17b..d9838864e492b 100644 --- a/app/code/Magento/Marketplace/composer.json +++ b/app/code/Magento/Marketplace/composer.json @@ -1,19 +1,20 @@ { "name": "magento/module-marketplace", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.5", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -23,3 +24,4 @@ } } } + diff --git a/app/code/Magento/MediaGallery/composer.json b/app/code/Magento/MediaGallery/composer.json index bc76f565d3358..bbb56496e0e25 100644 --- a/app/code/Magento/MediaGallery/composer.json +++ b/app/code/Magento/MediaGallery/composer.json @@ -1,18 +1,19 @@ { "name": "magento/module-media-gallery", "description": "Magento module responsible for media handling", - "require": { - "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-media-gallery-api": "*", - "magento/module-cms": "*", - "magento/module-catalog": "*" - }, "type": "magento2-module", "license": [ "OSL-3.0", "AFL-3.0" ], + "version": "100.3.2", + "require": { + "php": "~7.3.0||~7.4.0", + "magento/framework": "102.0.*", + "magento/module-media-gallery-api": "100.3.*", + "magento/module-cms": "103.0.*", + "magento/module-catalog": "103.0.*" + }, "autoload": { "files": [ "registration.php" @@ -22,3 +23,4 @@ } } } + diff --git a/app/code/Magento/MediaGalleryApi/composer.json b/app/code/Magento/MediaGalleryApi/composer.json index 8bea8ee95b55a..ceedb9bdc4cc2 100644 --- a/app/code/Magento/MediaGalleryApi/composer.json +++ b/app/code/Magento/MediaGalleryApi/composer.json @@ -1,15 +1,16 @@ { "name": "magento/module-media-gallery-api", "description": "Magento module responsible for media gallery asset attributes storage and management", - "require": { - "php": "~7.3.0||~7.4.0", - "magento/framework": "*" - }, "type": "magento2-module", "license": [ "OSL-3.0", "AFL-3.0" ], + "version": "100.3.1", + "require": { + "php": "~7.3.0||~7.4.0", + "magento/framework": "102.0.*" + }, "autoload": { "files": [ "registration.php" @@ -19,3 +20,4 @@ } } } + diff --git a/app/code/Magento/MediaStorage/Model/File/Storage.php b/app/code/Magento/MediaStorage/Model/File/Storage.php index 861f2d82c7e7b..ce1a73c06b413 100644 --- a/app/code/Magento/MediaStorage/Model/File/Storage.php +++ b/app/code/Magento/MediaStorage/Model/File/Storage.php @@ -11,7 +11,7 @@ use Magento\Framework\Model\AbstractModel; /** - * Class Storage + * Media File Storage * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) * @api @@ -156,8 +156,8 @@ public function getSyncFlag() /** * Retrieve storage model - * If storage not defined - retrieve current storage * + * If storage not defined - retrieve current storage * params = array( * connection => string, - define connection for model if needed * init => bool - force initialization process for storage model @@ -289,9 +289,10 @@ public function getScriptConfig() $config['media_directory'] = $this->filesystem->getDirectoryRead(DirectoryList::MEDIA)->getAbsolutePath(); $allowedResources = $this->_coreConfig->getValue(self::XML_PATH_MEDIA_RESOURCE_WHITELIST, 'default'); - foreach ($allowedResources as $allowedResource) { - $config['allowed_resources'][] = $allowedResource; - } + array_walk_recursive($allowedResources, function ($value) use (&$resources) { + $resources[] = $value; + }, $resources); + $config['allowed_resources'] = $resources; $config['update_time'] = $this->_scopeConfig->getValue( self::XML_PATH_MEDIA_UPDATE_TIME, diff --git a/app/code/Magento/MediaStorage/Model/File/Storage/Config.php b/app/code/Magento/MediaStorage/Model/File/Storage/Config.php index 8181b67b3692c..9775aef1146ca 100644 --- a/app/code/Magento/MediaStorage/Model/File/Storage/Config.php +++ b/app/code/Magento/MediaStorage/Model/File/Storage/Config.php @@ -10,6 +10,9 @@ use Magento\Framework\Filesystem\File\Write; use Magento\Framework\Exception\FileSystemException; +/** + * Media storage file storage config + */ class Config { /** @@ -34,14 +37,17 @@ class Config protected $rootDirectory; /** + * Config constructor. + * * @param \Magento\MediaStorage\Model\File\Storage $storage * @param \Magento\Framework\Filesystem $filesystem * @param string $cacheFile + * @throws FileSystemException */ public function __construct( \Magento\MediaStorage\Model\File\Storage $storage, \Magento\Framework\Filesystem $filesystem, - $cacheFile + string $cacheFile ) { $this->config = $storage->getScriptConfig(); $this->rootDirectory = $filesystem->getDirectoryWrite(DirectoryList::ROOT); diff --git a/app/code/Magento/MediaStorage/composer.json b/app/code/Magento/MediaStorage/composer.json index 72084c65da6cd..83d6dbece5a90 100644 --- a/app/code/Magento/MediaStorage/composer.json +++ b/app/code/Magento/MediaStorage/composer.json @@ -1,23 +1,24 @@ { "name": "magento/module-media-storage", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7-p2", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-config": "*", - "magento/module-store": "*", - "magento/module-catalog": "*", - "magento/module-theme": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-config": "101.1.*", + "magento/module-store": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-theme": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -27,3 +28,4 @@ } } } + diff --git a/app/code/Magento/MessageQueue/composer.json b/app/code/Magento/MessageQueue/composer.json index feec3edcabad7..094db7dae7dd7 100644 --- a/app/code/Magento/MessageQueue/composer.json +++ b/app/code/Magento/MessageQueue/composer.json @@ -1,19 +1,20 @@ { "name": "magento/module-message-queue", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7", "require": { - "magento/framework": "*", + "magento/framework": "102.0.*", "magento/magento-composer-installer": "*", "php": "~7.3.0||~7.4.0" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -23,3 +24,4 @@ } } } + diff --git a/app/code/Magento/Msrp/composer.json b/app/code/Magento/Msrp/composer.json index 5c9d2e4cf58fa..a3a085317f340 100644 --- a/app/code/Magento/Msrp/composer.json +++ b/app/code/Magento/Msrp/composer.json @@ -1,27 +1,28 @@ { "name": "magento/module-msrp", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.6", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-catalog": "*", - "magento/module-downloadable": "*", - "magento/module-eav": "*", - "magento/module-store": "*", - "magento/module-tax": "*" + "magento/framework": "102.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-downloadable": "100.3.*", + "magento/module-eav": "102.0.*", + "magento/module-store": "101.0.*", + "magento/module-tax": "100.3.*" }, "suggest": { - "magento/module-bundle": "*", - "magento/module-msrp-sample-data": "*" + "magento/module-bundle": "100.3.*", + "magento/module-msrp-sample-data": "Sample Data version: 100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -31,3 +32,4 @@ } } } + diff --git a/app/code/Magento/MsrpConfigurableProduct/composer.json b/app/code/Magento/MsrpConfigurableProduct/composer.json index 53d274a3c4006..eed9ebf73381a 100644 --- a/app/code/Magento/MsrpConfigurableProduct/composer.json +++ b/app/code/Magento/MsrpConfigurableProduct/composer.json @@ -1,21 +1,22 @@ { "name": "magento/module-msrp-configurable-product", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.4", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-catalog": "*", - "magento/module-msrp": "*", - "magento/module-configurable-product": "*" + "magento/framework": "102.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-msrp": "100.3.*", + "magento/module-configurable-product": "100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -25,3 +26,4 @@ } } } + diff --git a/app/code/Magento/MsrpGroupedProduct/composer.json b/app/code/Magento/MsrpGroupedProduct/composer.json index 5c426b5910ad7..937b022e2956c 100644 --- a/app/code/Magento/MsrpGroupedProduct/composer.json +++ b/app/code/Magento/MsrpGroupedProduct/composer.json @@ -1,21 +1,22 @@ { "name": "magento/module-msrp-grouped-product", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.5", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-catalog": "*", - "magento/module-msrp": "*", - "magento/module-grouped-product": "*" + "magento/framework": "102.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-msrp": "100.3.*", + "magento/module-grouped-product": "100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -25,3 +26,4 @@ } } } + diff --git a/app/code/Magento/Multishipping/Model/Checkout/Type/Multishipping.php b/app/code/Magento/Multishipping/Model/Checkout/Type/Multishipping.php index 7fa674505461e..bc1ec52ade04e 100644 --- a/app/code/Magento/Multishipping/Model/Checkout/Type/Multishipping.php +++ b/app/code/Magento/Multishipping/Model/Checkout/Type/Multishipping.php @@ -508,8 +508,7 @@ public function setShippingItemsInformation($info) protected function _addShippingItem($quoteItemId, $data) { $qty = isset($data['qty']) ? (int)$data['qty'] : 1; - //$qty = $qty > 0 ? $qty : 1; - $addressId = isset($data['address']) ? $data['address'] : false; + $addressId = isset($data['address']) ? (int)$data['address'] : false; $quoteItem = $this->getQuote()->getItemById($quoteItemId); if ($addressId && $quoteItem) { @@ -1118,7 +1117,7 @@ function ($address) { $this->getCustomer()->getAddresses() ); - return !is_numeric($addressId) || in_array($addressId, $applicableAddressIds); + return in_array($addressId, $applicableAddressIds); } /** diff --git a/app/code/Magento/Multishipping/composer.json b/app/code/Magento/Multishipping/composer.json index 8834603562332..1d4d4b96dfd4e 100644 --- a/app/code/Magento/Multishipping/composer.json +++ b/app/code/Magento/Multishipping/composer.json @@ -1,28 +1,29 @@ { "name": "magento/module-multishipping", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7-p2", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-checkout": "*", - "magento/module-customer": "*", - "magento/module-directory": "*", - "magento/module-payment": "*", - "magento/module-quote": "*", - "magento/module-sales": "*", - "magento/module-store": "*", - "magento/module-tax": "*", - "magento/module-theme": "*", - "magento/module-captcha": "*" + "magento/framework": "102.0.*", + "magento/module-checkout": "100.3.*", + "magento/module-customer": "102.0.*", + "magento/module-directory": "100.3.*", + "magento/module-payment": "100.3.*", + "magento/module-quote": "101.1.*", + "magento/module-sales": "102.0.*", + "magento/module-store": "101.0.*", + "magento/module-tax": "100.3.*", + "magento/module-theme": "101.0.*", + "magento/module-captcha": "100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -32,3 +33,4 @@ } } } + diff --git a/app/code/Magento/MysqlMq/composer.json b/app/code/Magento/MysqlMq/composer.json index 92f1cf4c6964e..52d6e43236304 100644 --- a/app/code/Magento/MysqlMq/composer.json +++ b/app/code/Magento/MysqlMq/composer.json @@ -1,20 +1,21 @@ { "name": "magento/module-mysql-mq", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.5", "require": { - "magento/framework": "*", + "magento/framework": "102.0.*", "magento/magento-composer-installer": "*", - "magento/module-store": "*", + "magento/module-store": "101.0.*", "php": "~7.3.0||~7.4.0" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -24,3 +25,4 @@ } } } + diff --git a/app/code/Magento/NewRelicReporting/composer.json b/app/code/Magento/NewRelicReporting/composer.json index ca4c72d5a3aad..1b235f7633027 100644 --- a/app/code/Magento/NewRelicReporting/composer.json +++ b/app/code/Magento/NewRelicReporting/composer.json @@ -1,25 +1,26 @@ { "name": "magento/module-new-relic-reporting", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.5", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", + "magento/framework": "102.0.*", "magento/magento-composer-installer": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-config": "*", - "magento/module-configurable-product": "*", - "magento/module-customer": "*", - "magento/module-store": "*" + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-config": "101.1.*", + "magento/module-configurable-product": "100.3.*", + "magento/module-customer": "102.0.*", + "magento/module-store": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -29,3 +30,4 @@ } } } + diff --git a/app/code/Magento/Newsletter/composer.json b/app/code/Magento/Newsletter/composer.json index cc0d717a1958d..ffce8d69b9f37 100644 --- a/app/code/Magento/Newsletter/composer.json +++ b/app/code/Magento/Newsletter/composer.json @@ -1,26 +1,27 @@ { "name": "magento/module-newsletter", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-cms": "*", - "magento/module-customer": "*", - "magento/module-eav": "*", - "magento/module-email": "*", - "magento/module-require-js": "*", - "magento/module-store": "*", - "magento/module-widget": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-cms": "103.0.*", + "magento/module-customer": "102.0.*", + "magento/module-eav": "102.0.*", + "magento/module-email": "101.0.*", + "magento/module-require-js": "100.3.*", + "magento/module-store": "101.0.*", + "magento/module-widget": "101.1.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -30,3 +31,4 @@ } } } + diff --git a/app/code/Magento/OfflinePayments/composer.json b/app/code/Magento/OfflinePayments/composer.json index 56c7eb2778c48..87a5c348aa75f 100644 --- a/app/code/Magento/OfflinePayments/composer.json +++ b/app/code/Magento/OfflinePayments/composer.json @@ -1,23 +1,24 @@ { "name": "magento/module-offline-payments", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.5", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-checkout": "*", - "magento/module-payment": "*" + "magento/framework": "102.0.*", + "magento/module-checkout": "100.3.*", + "magento/module-payment": "100.3.*" }, "suggest": { - "magento/module-config": "*" + "magento/module-config": "101.1.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -27,3 +28,4 @@ } } } + diff --git a/app/code/Magento/OfflineShipping/composer.json b/app/code/Magento/OfflineShipping/composer.json index 7cd6f05f8ad1c..8ce99f1369d57 100644 --- a/app/code/Magento/OfflineShipping/composer.json +++ b/app/code/Magento/OfflineShipping/composer.json @@ -1,31 +1,32 @@ { "name": "magento/module-offline-shipping", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.6", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-config": "*", - "magento/module-directory": "*", - "magento/module-quote": "*", - "magento/module-sales": "*", - "magento/module-sales-rule": "*", - "magento/module-shipping": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-config": "101.1.*", + "magento/module-directory": "100.3.*", + "magento/module-quote": "101.1.*", + "magento/module-sales": "102.0.*", + "magento/module-sales-rule": "101.1.*", + "magento/module-shipping": "100.3.*", + "magento/module-store": "101.0.*" }, "suggest": { - "magento/module-checkout": "*", - "magento/module-offline-shipping-sample-data": "*" + "magento/module-checkout": "100.3.*", + "magento/module-offline-shipping-sample-data": "Sample Data version: 100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -35,3 +36,4 @@ } } } + diff --git a/app/code/Magento/PageCache/composer.json b/app/code/Magento/PageCache/composer.json index 506fd54886d92..527ecabf05c75 100644 --- a/app/code/Magento/PageCache/composer.json +++ b/app/code/Magento/PageCache/composer.json @@ -1,21 +1,22 @@ { "name": "magento/module-page-cache", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-config": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-config": "101.1.*", + "magento/module-store": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -25,3 +26,4 @@ } } } + diff --git a/app/code/Magento/Payment/composer.json b/app/code/Magento/Payment/composer.json index 6ee0baec247f3..fde3395a75d9c 100644 --- a/app/code/Magento/Payment/composer.json +++ b/app/code/Magento/Payment/composer.json @@ -1,24 +1,25 @@ { "name": "magento/module-payment", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-checkout": "*", - "magento/module-config": "*", - "magento/module-directory": "*", - "magento/module-quote": "*", - "magento/module-sales": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-checkout": "100.3.*", + "magento/module-config": "101.1.*", + "magento/module-directory": "100.3.*", + "magento/module-quote": "101.1.*", + "magento/module-sales": "102.0.*", + "magento/module-store": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -28,3 +29,4 @@ } } } + diff --git a/app/code/Magento/Paypal/Controller/Express/AbstractExpress/PlaceOrder.php b/app/code/Magento/Paypal/Controller/Express/AbstractExpress/PlaceOrder.php index 055af4162d5f3..149a36f168b23 100644 --- a/app/code/Magento/Paypal/Controller/Express/AbstractExpress/PlaceOrder.php +++ b/app/code/Magento/Paypal/Controller/Express/AbstractExpress/PlaceOrder.php @@ -11,7 +11,8 @@ use Magento\Paypal\Model\Api\ProcessableException as ApiProcessableException; /** - * Class PlaceOrder + * Finalizes the PayPal order and executes payment + * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class PlaceOrder extends \Magento\Paypal\Controller\Express\AbstractExpress @@ -99,6 +100,7 @@ public function execute() // prepare session to success or cancellation page $this->_getCheckoutSession()->clearHelperData(); + $this->_getSession()->unsQuoteId(); // "last successful quote" $quoteId = $this->_getQuote()->getId(); diff --git a/app/code/Magento/Paypal/Controller/Express/OnAuthorization.php b/app/code/Magento/Paypal/Controller/Express/OnAuthorization.php index 0d7ec3fc6f32d..1085b1eecc039 100644 --- a/app/code/Magento/Paypal/Controller/Express/OnAuthorization.php +++ b/app/code/Magento/Paypal/Controller/Express/OnAuthorization.php @@ -113,17 +113,11 @@ public function __construct( public function execute(): ResultInterface { $controllerResult = $this->resultFactory->create(ResultFactory::TYPE_JSON); - $quoteId = $this->getRequest()->getParam('quoteId'); $payerId = $this->getRequest()->getParam('payerId'); $tokenId = $this->getRequest()->getParam('paymentToken'); - $customerId = $this->getRequest()->getParam('customerId') ?: $this->_customerSession->getId(); try { - if ($quoteId) { - $quote = $customerId ? $this->cartRepository->get($quoteId) : $this->guestCartRepository->get($quoteId); - } else { - $quote = $this->_getQuote(); - } + $quote = $this->_getQuote(); $responseContent = [ 'success' => true, diff --git a/app/code/Magento/Paypal/composer.json b/app/code/Magento/Paypal/composer.json index 389544b6a17a4..aa50ce47d264b 100644 --- a/app/code/Magento/Paypal/composer.json +++ b/app/code/Magento/Paypal/composer.json @@ -1,39 +1,40 @@ { "name": "magento/module-paypal", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7-p2", "require": { "php": "~7.3.0||~7.4.0", "lib-libxml": "*", - "magento/framework": "*", - "magento/module-authorization": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-checkout": "*", - "magento/module-config": "*", - "magento/module-customer": "*", - "magento/module-directory": "*", - "magento/module-eav": "*", - "magento/module-instant-purchase": "*", - "magento/module-payment": "*", - "magento/module-quote": "*", - "magento/module-sales": "*", - "magento/module-store": "*", - "magento/module-tax": "*", - "magento/module-theme": "*", - "magento/module-ui": "*", - "magento/module-vault": "*" + "magento/framework": "102.0.*", + "magento/module-authorization": "100.3.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-checkout": "100.3.*", + "magento/module-config": "101.1.*", + "magento/module-customer": "102.0.*", + "magento/module-directory": "100.3.*", + "magento/module-eav": "102.0.*", + "magento/module-instant-purchase": "100.3.*", + "magento/module-payment": "100.3.*", + "magento/module-quote": "101.1.*", + "magento/module-sales": "102.0.*", + "magento/module-store": "101.0.*", + "magento/module-tax": "100.3.*", + "magento/module-theme": "101.0.*", + "magento/module-ui": "101.1.*", + "magento/module-vault": "101.1.*" }, "suggest": { - "magento/module-checkout-agreements": "*" + "magento/module-checkout-agreements": "100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -43,3 +44,4 @@ } } } + diff --git a/app/code/Magento/Paypal/etc/csp_whitelist.xml b/app/code/Magento/Paypal/etc/csp_whitelist.xml index 932664bde9e09..de75e877cb1da 100644 --- a/app/code/Magento/Paypal/etc/csp_whitelist.xml +++ b/app/code/Magento/Paypal/etc/csp_whitelist.xml @@ -29,6 +29,17 @@ www.paypal.com www.sandbox.paypal.com + pilot-payflowlink.paypal.com + + + + + pilot-payflowlink.paypal.com + + + + + www.sandbox.paypal.com diff --git a/app/code/Magento/Paypal/view/frontend/web/js/in-context/express-checkout-smart-buttons.js b/app/code/Magento/Paypal/view/frontend/web/js/in-context/express-checkout-smart-buttons.js index ad7e86f2e99e0..0acf14fd189bf 100644 --- a/app/code/Magento/Paypal/view/frontend/web/js/in-context/express-checkout-smart-buttons.js +++ b/app/code/Magento/Paypal/view/frontend/web/js/in-context/express-checkout-smart-buttons.js @@ -85,8 +85,6 @@ define([ var params = { paymentToken: data.paymentToken, payerId: data.payerID, - quoteId: clientConfig.quoteId || '', - customerId: clientConfig.customerId || '', 'form_key': clientConfig.formKey }; diff --git a/app/code/Magento/PaypalCaptcha/composer.json b/app/code/Magento/PaypalCaptcha/composer.json index b88eb2f1a552e..5a82dec5c2bd6 100644 --- a/app/code/Magento/PaypalCaptcha/composer.json +++ b/app/code/Magento/PaypalCaptcha/composer.json @@ -1,24 +1,25 @@ { "name": "magento/module-paypal-captcha", "description": "Provides CAPTCHA validation for PayPal Payflow Pro", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.3", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-captcha": "*", - "magento/module-checkout": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-captcha": "100.3.*", + "magento/module-checkout": "100.3.*", + "magento/module-store": "101.0.*" }, "suggest": { - "magento/module-paypal": "*" + "magento/module-paypal": "100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -28,3 +29,4 @@ } } } + diff --git a/app/code/Magento/PaypalGraphQl/composer.json b/app/code/Magento/PaypalGraphQl/composer.json index 8d012be3492dd..e65831c866f5b 100644 --- a/app/code/Magento/PaypalGraphQl/composer.json +++ b/app/code/Magento/PaypalGraphQl/composer.json @@ -1,28 +1,29 @@ { "name": "magento/module-paypal-graph-ql", "description": "GraphQl support for Paypal", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.2", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-quote": "*", - "magento/module-checkout": "*", - "magento/module-paypal": "*", - "magento/module-quote-graph-ql": "*", - "magento/module-sales": "*", - "magento/module-payment": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-quote": "101.1.*", + "magento/module-checkout": "100.3.*", + "magento/module-paypal": "100.3.*", + "magento/module-quote-graph-ql": "100.3.*", + "magento/module-sales": "102.0.*", + "magento/module-payment": "100.3.*", + "magento/module-store": "101.0.*" }, "suggest": { - "magento/module-graph-ql": "*" + "magento/module-graph-ql": "100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -32,3 +33,4 @@ } } } + diff --git a/app/code/Magento/Persistent/composer.json b/app/code/Magento/Persistent/composer.json index 68fe5cb47c00e..e47515d341c05 100644 --- a/app/code/Magento/Persistent/composer.json +++ b/app/code/Magento/Persistent/composer.json @@ -1,24 +1,25 @@ { "name": "magento/module-persistent", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-checkout": "*", - "magento/module-cron": "*", - "magento/module-customer": "*", - "magento/module-page-cache": "*", - "magento/module-quote": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-checkout": "100.3.*", + "magento/module-cron": "100.3.*", + "magento/module-customer": "102.0.*", + "magento/module-page-cache": "100.3.*", + "magento/module-quote": "101.1.*", + "magento/module-store": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -28,3 +29,4 @@ } } } + diff --git a/app/code/Magento/ProductAlert/composer.json b/app/code/Magento/ProductAlert/composer.json index bfe2a43b373ce..1777af31dadf7 100644 --- a/app/code/Magento/ProductAlert/composer.json +++ b/app/code/Magento/ProductAlert/composer.json @@ -1,26 +1,27 @@ { "name": "magento/module-product-alert", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-customer": "*", - "magento/module-store": "*", - "magento/module-theme": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-customer": "102.0.*", + "magento/module-store": "101.0.*", + "magento/module-theme": "101.0.*" }, "suggest": { - "magento/module-config": "*" + "magento/module-config": "101.1.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -30,3 +31,4 @@ } } } + diff --git a/app/code/Magento/ProductVideo/composer.json b/app/code/Magento/ProductVideo/composer.json index b7268338398a7..750193f0416d9 100644 --- a/app/code/Magento/ProductVideo/composer.json +++ b/app/code/Magento/ProductVideo/composer.json @@ -1,28 +1,29 @@ { "name": "magento/module-product-video", "description": "Add Video to Products", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", + "magento/framework": "102.0.*", "magento/magento-composer-installer": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-eav": "*", - "magento/module-media-storage": "*", - "magento/module-store": "*" + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-eav": "102.0.*", + "magento/module-media-storage": "100.3.*", + "magento/module-store": "101.0.*" }, "suggest": { - "magento/module-customer": "*", - "magento/module-config": "*" + "magento/module-customer": "102.0.*", + "magento/module-config": "101.1.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -32,3 +33,4 @@ } } } + diff --git a/app/code/Magento/Quote/composer.json b/app/code/Magento/Quote/composer.json index 31312fae26e78..cd73363cd51cc 100644 --- a/app/code/Magento/Quote/composer.json +++ b/app/code/Magento/Quote/composer.json @@ -1,35 +1,36 @@ { "name": "magento/module-quote", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "101.1.7-p2", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-authorization": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-catalog-inventory": "*", - "magento/module-checkout": "*", - "magento/module-customer": "*", - "magento/module-directory": "*", - "magento/module-eav": "*", - "magento/module-payment": "*", - "magento/module-sales": "*", - "magento/module-sales-sequence": "*", - "magento/module-shipping": "*", - "magento/module-store": "*", - "magento/module-tax": "*" + "magento/framework": "102.0.*", + "magento/module-authorization": "100.3.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-catalog-inventory": "100.3.*", + "magento/module-checkout": "100.3.*", + "magento/module-customer": "102.0.*", + "magento/module-directory": "100.3.*", + "magento/module-eav": "102.0.*", + "magento/module-payment": "100.3.*", + "magento/module-sales": "102.0.*", + "magento/module-sales-sequence": "100.3.*", + "magento/module-shipping": "100.3.*", + "magento/module-store": "101.0.*", + "magento/module-tax": "100.3.*" }, "suggest": { - "magento/module-webapi": "*" + "magento/module-webapi": "100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -39,3 +40,4 @@ } } } + diff --git a/app/code/Magento/Quote/etc/webapi.xml b/app/code/Magento/Quote/etc/webapi.xml index 686bdce07de5f..79d98968ea198 100644 --- a/app/code/Magento/Quote/etc/webapi.xml +++ b/app/code/Magento/Quote/etc/webapi.xml @@ -65,7 +65,7 @@ - %cart_id% + %cart_id% @@ -237,7 +237,7 @@ - %cart_id% + %cart_id% @@ -246,7 +246,7 @@ - %cart_id% + %cart_id% diff --git a/app/code/Magento/QuoteAnalytics/composer.json b/app/code/Magento/QuoteAnalytics/composer.json index 4bfb7172c4c83..5b43e0b67dbc6 100644 --- a/app/code/Magento/QuoteAnalytics/composer.json +++ b/app/code/Magento/QuoteAnalytics/composer.json @@ -1,17 +1,18 @@ { "name": "magento/module-quote-analytics", "description": "N/A", - "require": { - "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-quote": "*", - "magento/module-analytics": "*" - }, "type": "magento2-module", "license": [ "OSL-3.0", "AFL-3.0" ], + "version": "100.3.6", + "require": { + "php": "~7.3.0||~7.4.0", + "magento/framework": "102.0.*", + "magento/module-quote": "101.1.*", + "magento/module-analytics": "100.3.*" + }, "autoload": { "files": [ "registration.php" @@ -21,3 +22,4 @@ } } } + diff --git a/app/code/Magento/QuoteGraphQl/Model/Resolver/PlaceOrder.php b/app/code/Magento/QuoteGraphQl/Model/Resolver/PlaceOrder.php index 3a10c773c5f22..397455a2412a5 100644 --- a/app/code/Magento/QuoteGraphQl/Model/Resolver/PlaceOrder.php +++ b/app/code/Magento/QuoteGraphQl/Model/Resolver/PlaceOrder.php @@ -15,6 +15,7 @@ use Magento\Framework\GraphQl\Query\ResolverInterface; use Magento\Framework\GraphQl\Schema\Type\ResolveInfo; use Magento\Quote\Api\CartManagementInterface; +use Magento\Quote\Api\PaymentMethodManagementInterface; use Magento\QuoteGraphQl\Model\Cart\GetCartForUser; use Magento\Sales\Api\OrderRepositoryInterface; use Magento\QuoteGraphQl\Model\Cart\CheckCartCheckoutAllowance; @@ -44,22 +45,30 @@ class PlaceOrder implements ResolverInterface */ private $checkCartCheckoutAllowance; + /** + * @var PaymentMethodManagementInterface + */ + private $paymentMethodManagement; + /** * @param GetCartForUser $getCartForUser * @param CartManagementInterface $cartManagement * @param OrderRepositoryInterface $orderRepository * @param CheckCartCheckoutAllowance $checkCartCheckoutAllowance + * @param PaymentMethodManagementInterface $paymentMethodManagement */ public function __construct( GetCartForUser $getCartForUser, CartManagementInterface $cartManagement, OrderRepositoryInterface $orderRepository, - CheckCartCheckoutAllowance $checkCartCheckoutAllowance + CheckCartCheckoutAllowance $checkCartCheckoutAllowance, + PaymentMethodManagementInterface $paymentMethodManagement ) { $this->getCartForUser = $getCartForUser; $this->cartManagement = $cartManagement; $this->orderRepository = $orderRepository; $this->checkCartCheckoutAllowance = $checkCartCheckoutAllowance; + $this->paymentMethodManagement = $paymentMethodManagement; } /** @@ -84,7 +93,8 @@ public function resolve(Field $field, $context, ResolveInfo $info, array $value } try { - $orderId = $this->cartManagement->placeOrder($cart->getId()); + $cartId = $cart->getId(); + $orderId = $this->cartManagement->placeOrder($cartId, $this->paymentMethodManagement->get($cartId)); $order = $this->orderRepository->get($orderId); return [ diff --git a/app/code/Magento/QuoteGraphQl/composer.json b/app/code/Magento/QuoteGraphQl/composer.json index 0652d39b5f426..591b083c3c575 100644 --- a/app/code/Magento/QuoteGraphQl/composer.json +++ b/app/code/Magento/QuoteGraphQl/composer.json @@ -2,26 +2,27 @@ "name": "magento/module-quote-graph-ql", "description": "N/A", "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "version": "100.3.7-p2", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-quote": "*", - "magento/module-checkout": "*", - "magento/module-catalog": "*", - "magento/module-store": "*", - "magento/module-customer": "*", - "magento/module-customer-graph-ql": "*", - "magento/module-sales": "*", - "magento/module-directory": "*", - "magento/module-graph-ql": "*" + "magento/framework": "102.0.*", + "magento/module-quote": "101.1.*", + "magento/module-checkout": "100.3.*", + "magento/module-catalog": "103.0.*", + "magento/module-store": "101.0.*", + "magento/module-customer": "102.0.*", + "magento/module-customer-graph-ql": "100.3.*", + "magento/module-sales": "102.0.*", + "magento/module-directory": "100.3.*", + "magento/module-graph-ql": "100.3.*" }, "suggest": { - "magento/module-graph-ql-cache": "*" + "magento/module-graph-ql-cache": "100.3.*" }, - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -31,3 +32,4 @@ } } } + diff --git a/app/code/Magento/RelatedProductGraphQl/composer.json b/app/code/Magento/RelatedProductGraphQl/composer.json index 2cb851d56e58e..9780777710267 100644 --- a/app/code/Magento/RelatedProductGraphQl/composer.json +++ b/app/code/Magento/RelatedProductGraphQl/composer.json @@ -2,19 +2,20 @@ "name": "magento/module-related-product-graph-ql", "description": "N/A", "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "version": "100.3.2", "require": { "php": "~7.3.0||~7.4.0", - "magento/module-catalog": "*", - "magento/module-catalog-graph-ql": "*", - "magento/framework": "*" + "magento/module-catalog": "103.0.*", + "magento/module-catalog-graph-ql": "100.3.*", + "magento/framework": "102.0.*" }, "suggest": { - "magento/module-graph-ql": "*" + "magento/module-graph-ql": "100.3.*" }, - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -24,3 +25,4 @@ } } } + diff --git a/app/code/Magento/ReleaseNotification/composer.json b/app/code/Magento/ReleaseNotification/composer.json index c2e347bc66ef0..bf0f200186b8d 100644 --- a/app/code/Magento/ReleaseNotification/composer.json +++ b/app/code/Magento/ReleaseNotification/composer.json @@ -1,21 +1,22 @@ { "name": "magento/module-release-notification", "description": "N/A", - "require": { - "php": "~7.3.0||~7.4.0", - "magento/module-user": "*", - "magento/module-backend": "*", - "magento/module-ui": "*", - "magento/framework": "*" - }, - "suggest": { - "magento/module-config": "*" - }, "type": "magento2-module", "license": [ "OSL-3.0", "AFL-3.0" ], + "version": "100.3.5", + "require": { + "php": "~7.3.0||~7.4.0", + "magento/module-user": "101.1.*", + "magento/module-backend": "101.0.*", + "magento/module-ui": "101.1.*", + "magento/framework": "102.0.*" + }, + "suggest": { + "magento/module-config": "101.1.*" + }, "autoload": { "files": [ "registration.php" @@ -25,3 +26,4 @@ } } } + diff --git a/app/code/Magento/Reports/composer.json b/app/code/Magento/Reports/composer.json index f1fe6c1e2c83a..88c1e0b84c46e 100644 --- a/app/code/Magento/Reports/composer.json +++ b/app/code/Magento/Reports/composer.json @@ -1,34 +1,35 @@ { "name": "magento/module-reports", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-catalog-inventory": "*", - "magento/module-cms": "*", - "magento/module-config": "*", - "magento/module-customer": "*", - "magento/module-downloadable": "*", - "magento/module-eav": "*", - "magento/module-quote": "*", - "magento/module-review": "*", - "magento/module-sales": "*", - "magento/module-sales-rule": "*", - "magento/module-store": "*", - "magento/module-tax": "*", - "magento/module-widget": "*", - "magento/module-wishlist": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-catalog-inventory": "100.3.*", + "magento/module-cms": "103.0.*", + "magento/module-config": "101.1.*", + "magento/module-customer": "102.0.*", + "magento/module-downloadable": "100.3.*", + "magento/module-eav": "102.0.*", + "magento/module-quote": "101.1.*", + "magento/module-review": "100.3.*", + "magento/module-sales": "102.0.*", + "magento/module-sales-rule": "101.1.*", + "magento/module-store": "101.0.*", + "magento/module-tax": "100.3.*", + "magento/module-widget": "101.1.*", + "magento/module-wishlist": "101.1.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -38,3 +39,4 @@ } } } + diff --git a/app/code/Magento/RequireJs/composer.json b/app/code/Magento/RequireJs/composer.json index 9c3b84e88df53..2ab9e363d5f82 100644 --- a/app/code/Magento/RequireJs/composer.json +++ b/app/code/Magento/RequireJs/composer.json @@ -1,18 +1,19 @@ { "name": "magento/module-require-js", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.5", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*" + "magento/framework": "102.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -22,3 +23,4 @@ } } } + diff --git a/app/code/Magento/Review/composer.json b/app/code/Magento/Review/composer.json index 5a428ae15fd67..72260cc061de2 100644 --- a/app/code/Magento/Review/composer.json +++ b/app/code/Magento/Review/composer.json @@ -1,30 +1,31 @@ { "name": "magento/module-review", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-customer": "*", - "magento/module-eav": "*", - "magento/module-newsletter": "*", - "magento/module-store": "*", - "magento/module-theme": "*", - "magento/module-ui": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-customer": "102.0.*", + "magento/module-eav": "102.0.*", + "magento/module-newsletter": "100.3.*", + "magento/module-store": "101.0.*", + "magento/module-theme": "101.0.*", + "magento/module-ui": "101.1.*" }, "suggest": { - "magento/module-cookie": "*", - "magento/module-review-sample-data": "*" + "magento/module-cookie": "100.3.*", + "magento/module-review-sample-data": "Sample Data version: 100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -34,3 +35,4 @@ } } } + diff --git a/app/code/Magento/ReviewAnalytics/composer.json b/app/code/Magento/ReviewAnalytics/composer.json index d18ec43a93ac1..c6184128a2a85 100644 --- a/app/code/Magento/ReviewAnalytics/composer.json +++ b/app/code/Magento/ReviewAnalytics/composer.json @@ -1,17 +1,18 @@ { "name": "magento/module-review-analytics", "description": "N/A", - "require": { - "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-review": "*", - "magento/module-analytics": "*" - }, "type": "magento2-module", "license": [ "OSL-3.0", "AFL-3.0" ], + "version": "100.3.5", + "require": { + "php": "~7.3.0||~7.4.0", + "magento/framework": "102.0.*", + "magento/module-review": "100.3.*", + "magento/module-analytics": "100.3.*" + }, "autoload": { "files": [ "registration.php" @@ -21,3 +22,4 @@ } } } + diff --git a/app/code/Magento/Robots/composer.json b/app/code/Magento/Robots/composer.json index 2035010b0ce8b..18ff2a44bb097 100644 --- a/app/code/Magento/Robots/composer.json +++ b/app/code/Magento/Robots/composer.json @@ -1,22 +1,23 @@ { "name": "magento/module-robots", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "101.0.5", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-store": "101.0.*" }, "suggest": { - "magento/module-theme": "*" + "magento/module-theme": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -26,3 +27,4 @@ } } } + diff --git a/app/code/Magento/Rss/composer.json b/app/code/Magento/Rss/composer.json index bd845acc12f9a..68e9feae0cb39 100644 --- a/app/code/Magento/Rss/composer.json +++ b/app/code/Magento/Rss/composer.json @@ -1,21 +1,22 @@ { "name": "magento/module-rss", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.5", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-customer": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-customer": "102.0.*", + "magento/module-store": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -25,3 +26,4 @@ } } } + diff --git a/app/code/Magento/Rule/composer.json b/app/code/Magento/Rule/composer.json index 0ab2b6780dcad..b47563e7789ce 100644 --- a/app/code/Magento/Rule/composer.json +++ b/app/code/Magento/Rule/composer.json @@ -1,23 +1,24 @@ { "name": "magento/module-rule", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.6", "require": { "php": "~7.3.0||~7.4.0", "lib-libxml": "*", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-eav": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-eav": "102.0.*", + "magento/module-store": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -27,3 +28,4 @@ } } } + diff --git a/app/code/Magento/Sales/composer.json b/app/code/Magento/Sales/composer.json index 411ad3739d560..4f23a2b7405e0 100644 --- a/app/code/Magento/Sales/composer.json +++ b/app/code/Magento/Sales/composer.json @@ -1,45 +1,46 @@ { "name": "magento/module-sales", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "102.0.7-p2", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-authorization": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-bundle": "*", - "magento/module-catalog-inventory": "*", - "magento/module-checkout": "*", - "magento/module-config": "*", - "magento/module-customer": "*", - "magento/module-directory": "*", - "magento/module-eav": "*", - "magento/module-gift-message": "*", - "magento/module-media-storage": "*", - "magento/module-payment": "*", - "magento/module-quote": "*", - "magento/module-reports": "*", - "magento/module-sales-rule": "*", - "magento/module-sales-sequence": "*", - "magento/module-shipping": "*", - "magento/module-store": "*", - "magento/module-tax": "*", - "magento/module-theme": "*", - "magento/module-ui": "*", - "magento/module-widget": "*", - "magento/module-wishlist": "*" + "magento/framework": "102.0.*", + "magento/module-authorization": "100.3.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-bundle": "100.3.*", + "magento/module-catalog-inventory": "100.3.*", + "magento/module-checkout": "100.3.*", + "magento/module-config": "101.1.*", + "magento/module-customer": "102.0.*", + "magento/module-directory": "100.3.*", + "magento/module-eav": "102.0.*", + "magento/module-gift-message": "100.3.*", + "magento/module-media-storage": "100.3.*", + "magento/module-payment": "100.3.*", + "magento/module-quote": "101.1.*", + "magento/module-reports": "100.3.*", + "magento/module-sales-rule": "101.1.*", + "magento/module-sales-sequence": "100.3.*", + "magento/module-shipping": "100.3.*", + "magento/module-store": "101.0.*", + "magento/module-tax": "100.3.*", + "magento/module-theme": "101.0.*", + "magento/module-ui": "101.1.*", + "magento/module-widget": "101.1.*", + "magento/module-wishlist": "101.1.*" }, "suggest": { - "magento/module-sales-sample-data": "*" + "magento/module-sales-sample-data": "Sample Data version: 100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -49,3 +50,4 @@ } } } + diff --git a/app/code/Magento/Sales/view/frontend/layout/sales_email_order_shipment_track.xml b/app/code/Magento/Sales/view/frontend/layout/sales_email_order_shipment_track.xml index 489317cfa65c7..b54fc57b71159 100644 --- a/app/code/Magento/Sales/view/frontend/layout/sales_email_order_shipment_track.xml +++ b/app/code/Magento/Sales/view/frontend/layout/sales_email_order_shipment_track.xml @@ -8,7 +8,7 @@ - + Magento\Sales\Block\DataProviders\Email\Shipment\TrackingUrl diff --git a/app/code/Magento/Sales/view/frontend/layout/sales_guest_printshipment.xml b/app/code/Magento/Sales/view/frontend/layout/sales_guest_printshipment.xml index b55a114091a11..a79068bc21e06 100644 --- a/app/code/Magento/Sales/view/frontend/layout/sales_guest_printshipment.xml +++ b/app/code/Magento/Sales/view/frontend/layout/sales_guest_printshipment.xml @@ -15,7 +15,7 @@ - + diff --git a/app/code/Magento/SalesAnalytics/composer.json b/app/code/Magento/SalesAnalytics/composer.json index ca7926f2d8b5a..fc5eefc232fd6 100644 --- a/app/code/Magento/SalesAnalytics/composer.json +++ b/app/code/Magento/SalesAnalytics/composer.json @@ -1,17 +1,18 @@ { "name": "magento/module-sales-analytics", "description": "N/A", - "require": { - "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-sales": "*", - "magento/module-analytics": "*" - }, "type": "magento2-module", "license": [ "OSL-3.0", "AFL-3.0" ], + "version": "100.3.5", + "require": { + "php": "~7.3.0||~7.4.0", + "magento/framework": "102.0.*", + "magento/module-sales": "102.0.*", + "magento/module-analytics": "100.3.*" + }, "autoload": { "files": [ "registration.php" @@ -21,3 +22,4 @@ } } } + diff --git a/app/code/Magento/SalesGraphQl/composer.json b/app/code/Magento/SalesGraphQl/composer.json index 8e9d95836e189..8e774f589a9f3 100644 --- a/app/code/Magento/SalesGraphQl/composer.json +++ b/app/code/Magento/SalesGraphQl/composer.json @@ -2,16 +2,17 @@ "name": "magento/module-sales-graph-ql", "description": "N/A", "type": "magento2-module", - "require": { - "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-sales": "*", - "magento/module-graph-ql": "*" - }, "license": [ "OSL-3.0", "AFL-3.0" ], + "version": "100.3.4", + "require": { + "php": "~7.3.0||~7.4.0", + "magento/framework": "102.0.*", + "magento/module-sales": "102.0.*", + "magento/module-graph-ql": "100.3.*" + }, "autoload": { "files": [ "registration.php" @@ -21,3 +22,4 @@ } } } + diff --git a/app/code/Magento/SalesInventory/composer.json b/app/code/Magento/SalesInventory/composer.json index 6a91b04a7c0d9..1861c8c80b2b1 100644 --- a/app/code/Magento/SalesInventory/composer.json +++ b/app/code/Magento/SalesInventory/composer.json @@ -1,22 +1,23 @@ { "name": "magento/module-sales-inventory", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.5", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-catalog": "*", - "magento/module-catalog-inventory": "*", - "magento/module-sales": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-catalog-inventory": "100.3.*", + "magento/module-sales": "102.0.*", + "magento/module-store": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -26,3 +27,4 @@ } } } + diff --git a/app/code/Magento/SalesRule/composer.json b/app/code/Magento/SalesRule/composer.json index 572e191093275..9d8b8e3cc750a 100644 --- a/app/code/Magento/SalesRule/composer.json +++ b/app/code/Magento/SalesRule/composer.json @@ -1,40 +1,41 @@ { "name": "magento/module-sales-rule", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "101.1.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-catalog-rule": "*", - "magento/module-config": "*", - "magento/module-customer": "*", - "magento/module-directory": "*", - "magento/module-eav": "*", - "magento/module-payment": "*", - "magento/module-quote": "*", - "magento/module-reports": "*", - "magento/module-rule": "*", - "magento/module-sales": "*", - "magento/module-shipping": "*", - "magento/module-store": "*", - "magento/module-ui": "*", - "magento/module-widget": "*", - "magento/module-captcha": "*", - "magento/module-checkout": "*", - "magento/module-authorization": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-catalog-rule": "101.1.*", + "magento/module-config": "101.1.*", + "magento/module-customer": "102.0.*", + "magento/module-directory": "100.3.*", + "magento/module-eav": "102.0.*", + "magento/module-payment": "100.3.*", + "magento/module-quote": "101.1.*", + "magento/module-reports": "100.3.*", + "magento/module-rule": "100.3.*", + "magento/module-sales": "102.0.*", + "magento/module-shipping": "100.3.*", + "magento/module-store": "101.0.*", + "magento/module-ui": "101.1.*", + "magento/module-widget": "101.1.*", + "magento/module-captcha": "100.3.*", + "magento/module-checkout": "100.3.*", + "magento/module-authorization": "100.3.*" }, "suggest": { - "magento/module-sales-rule-sample-data": "*" + "magento/module-sales-rule-sample-data": "Sample Data version: 100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -44,3 +45,4 @@ } } } + diff --git a/app/code/Magento/SalesSequence/composer.json b/app/code/Magento/SalesSequence/composer.json index a0f9cb45cafc8..1f0e81c304d99 100644 --- a/app/code/Magento/SalesSequence/composer.json +++ b/app/code/Magento/SalesSequence/composer.json @@ -1,18 +1,19 @@ { "name": "magento/module-sales-sequence", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.5", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*" + "magento/framework": "102.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -22,3 +23,4 @@ } } } + diff --git a/app/code/Magento/SampleData/composer.json b/app/code/Magento/SampleData/composer.json index 30efc94bc9274..347c0e6e81a69 100644 --- a/app/code/Magento/SampleData/composer.json +++ b/app/code/Magento/SampleData/composer.json @@ -1,21 +1,22 @@ { "name": "magento/module-sample-data", "description": "Sample Data fixtures", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.5", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*" + "magento/framework": "102.0.*" }, "suggest": { - "magento/sample-data-media": "*" + "magento/sample-data-media": "Sample Data version: 100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "cli_commands.php", @@ -26,3 +27,4 @@ } } } + diff --git a/app/code/Magento/Search/composer.json b/app/code/Magento/Search/composer.json index 3df1dc5935ad8..dc4d14b60c4f1 100644 --- a/app/code/Magento/Search/composer.json +++ b/app/code/Magento/Search/composer.json @@ -1,23 +1,24 @@ { "name": "magento/module-search", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "101.0.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-catalog-search": "*", - "magento/module-reports": "*", - "magento/module-store": "*", - "magento/module-ui": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog-search": "101.0.*", + "magento/module-reports": "100.3.*", + "magento/module-store": "101.0.*", + "magento/module-ui": "101.1.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -27,3 +28,4 @@ } } } + diff --git a/app/code/Magento/Security/Block/Config/Backend/Session/SessionSize.php b/app/code/Magento/Security/Block/Config/Backend/Session/SessionSize.php new file mode 100644 index 0000000000000..68d6481044b5c --- /dev/null +++ b/app/code/Magento/Security/Block/Config/Backend/Session/SessionSize.php @@ -0,0 +1,76 @@ +json = $json; + } + + /** + * @inheritdoc + */ + protected function _getElementHtml(AbstractElement $element) + { + $html = parent::_getElementHtml($element); + $originalData = $element->getOriginalData(); + $maxSessionSizeAdminSelector = '#' . $element->getHtmlId(); + $jsString = ''; + + $html .= $jsString; + return $html; + } + + /** + * Get HTML for the modal content body when user switches to disable + * + * @param string $templatePath + * @return string + * @throws ValidatorException + */ + private function getModalContentBody(string $templatePath) + { + $templateFileName = $this->getTemplateFile($templatePath); + + return $this->fetchView($templateFileName); + } +} diff --git a/app/code/Magento/Security/Model/AdminSessionInfo.php b/app/code/Magento/Security/Model/AdminSessionInfo.php index 77d864965baca..c14d399e98cac 100644 --- a/app/code/Magento/Security/Model/AdminSessionInfo.php +++ b/app/code/Magento/Security/Model/AdminSessionInfo.php @@ -3,12 +3,13 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Security\Model; /** * Admin Session Info Model * - * @method string getSessionId() * @method int getUserId() getUserId() * @method int getStatus() * @method string getUpdatedAt() diff --git a/app/code/Magento/Security/Model/AdminSessionsManager.php b/app/code/Magento/Security/Model/AdminSessionsManager.php index 7503fe04ba480..af4221fab8d28 100644 --- a/app/code/Magento/Security/Model/AdminSessionsManager.php +++ b/app/code/Magento/Security/Model/AdminSessionsManager.php @@ -3,17 +3,19 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\Security\Model; use Magento\Framework\HTTP\PhpEnvironment\RemoteAddress; -use \Magento\Security\Model\ResourceModel\AdminSessionInfo\CollectionFactory; +use Magento\Security\Model\ResourceModel\AdminSessionInfo\CollectionFactory; /** * Admin Sessions Manager Model * * @api * @since 100.1.0 + * @SuppressWarnings(PHPMD.CookieAndSessionMisuse) */ class AdminSessionsManager { @@ -114,7 +116,7 @@ public function processLogin() $result = $this->createAdminSessionInfoCollection()->updateActiveSessionsStatus( AdminSessionInfo::LOGGED_OUT_BY_LOGIN, $this->getCurrentSession()->getUserId(), - $this->getCurrentSession()->getSessionId(), + $this->getCurrentSession()->getId(), $olderThen ); if ($result) { @@ -173,8 +175,15 @@ public function processLogout() public function getCurrentSession() { if (!$this->currentSession) { + $adminSessionInfoId = $this->authSession->getAdminSessionInfoId(); + if (!$adminSessionInfoId) { + $this->createNewSession(); + $adminSessionInfoId = $this->authSession->getAdminSessionInfoId(); + $this->logoutOtherUserSessions(); + } + $this->currentSession = $this->adminSessionInfoFactory->create(); - $this->currentSession->load($this->authSession->getSessionId(), 'session_id'); + $this->currentSession->load($adminSessionInfoId, 'id'); } return $this->currentSession; @@ -256,7 +265,7 @@ public function logoutOtherUserSessions() ->filterByUser( $this->authSession->getUser()->getId(), \Magento\Security\Model\AdminSessionInfo::LOGGED_IN, - $this->authSession->getSessionId() + $this->authSession->getAdminSessionInfoId() ) ->filterExpiredSessions($this->securityConfig->getAdminSessionLifetime()) ->loadData(); @@ -290,22 +299,26 @@ public function cleanExpiredSessions() */ protected function createNewSession() { - $this->adminSessionInfoFactory + $adminSessionInfo = $this->adminSessionInfoFactory ->create() ->setData( [ - 'session_id' => $this->authSession->getSessionId(), 'user_id' => $this->authSession->getUser()->getId(), 'ip' => $this->remoteAddress->getRemoteAddress(), 'status' => AdminSessionInfo::LOGGED_IN ] )->save(); + $this->authSession->setAdminSessionInfoId($adminSessionInfo->getId()); + return $this; } /** + * Creates admin session information collection + * * @return \Magento\Security\Model\ResourceModel\AdminSessionInfo\Collection + * * @since 100.1.0 */ protected function createAdminSessionInfoCollection() @@ -314,11 +327,8 @@ protected function createAdminSessionInfoCollection() } /** - * Calculates diff between now and last session updated_at - * and decides whether new prolong must be triggered or not - * - * This is done to limit amount of session prolongs and updates to database - * within some period of time - X + * Calculates diff between now and last session updated_at and decides whether new prolong must be triggered or not + * This is done to limit amount of session prolongs and updates to database within some period of time - X * X - is calculated in getIntervalBetweenConsecutiveProlongs() * * @see getIntervalBetweenConsecutiveProlongs() diff --git a/app/code/Magento/Security/Model/Config/Backend/Session/SessionSize.php b/app/code/Magento/Security/Model/Config/Backend/Session/SessionSize.php new file mode 100644 index 0000000000000..33db3aa27f5a4 --- /dev/null +++ b/app/code/Magento/Security/Model/Config/Backend/Session/SessionSize.php @@ -0,0 +1,40 @@ +getValue(); + if ($value === '0') { + $value = 0; + } else { + $value = (int)$value; + if ($value === null || $value <= 0) { + $value = 256000; + } + } + $this->setValue((string)$value); + return $this; + } +} diff --git a/app/code/Magento/Security/Model/ResourceModel/AdminSessionInfo.php b/app/code/Magento/Security/Model/ResourceModel/AdminSessionInfo.php index 334449d74d195..ffb6cbf51d74a 100644 --- a/app/code/Magento/Security/Model/ResourceModel/AdminSessionInfo.php +++ b/app/code/Magento/Security/Model/ResourceModel/AdminSessionInfo.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\Security\Model\ResourceModel; @@ -23,7 +24,7 @@ class AdminSessionInfo extends \Magento\Framework\Model\ResourceModel\Db\Abstrac /** * @param \Magento\Framework\Model\ResourceModel\Db\Context $context * @param \Magento\Framework\Stdlib\DateTime $dateTime - * @param null $connectionName + * @param string|null $connectionName */ public function __construct( \Magento\Framework\Model\ResourceModel\Db\Context $context, @@ -87,7 +88,7 @@ public function updateStatusByUserId( 'user_id = ?' => (int) $userId, ]; if (!empty($excludedSessionIds)) { - $whereStatement['session_id NOT IN (?)'] = $excludedSessionIds; + $whereStatement['id NOT IN (?)'] = $excludedSessionIds; } if (!empty($withStatuses)) { $whereStatement['status IN (?)'] = $withStatuses; diff --git a/app/code/Magento/Security/Model/ResourceModel/AdminSessionInfo/Collection.php b/app/code/Magento/Security/Model/ResourceModel/AdminSessionInfo/Collection.php index 7c4e521419563..aee9010f468f4 100644 --- a/app/code/Magento/Security/Model/ResourceModel/AdminSessionInfo/Collection.php +++ b/app/code/Magento/Security/Model/ResourceModel/AdminSessionInfo/Collection.php @@ -3,6 +3,8 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Security\Model\ResourceModel\AdminSessionInfo; /** @@ -103,7 +105,7 @@ public function filterByUser( $this->addFieldToFilter('user_id', $userId); $this->addFieldToFilter('status', $status); if (null !== $sessionIdToExclude) { - $this->addFieldToFilter('session_id', ['neq' => $sessionIdToExclude]); + $this->addFieldToFilter('id', ['neq' => $sessionIdToExclude]); } return $this; } diff --git a/app/code/Magento/Security/Setup/Patch/Data/SessionIDColumnCleanUp.php b/app/code/Magento/Security/Setup/Patch/Data/SessionIDColumnCleanUp.php new file mode 100644 index 0000000000000..f868698505609 --- /dev/null +++ b/app/code/Magento/Security/Setup/Patch/Data/SessionIDColumnCleanUp.php @@ -0,0 +1,102 @@ +moduleDataSetup = $moduleDataSetup; + $this->logger = $logger; + } + + /** + * @inheritdoc + */ + public function apply() + { + try { + $this->cleanAdminUserSessionTable(); + } catch (\Throwable $e) { + $this->logger->warning( + 'Security module SessionIDColumnCleanUp patch experienced an error and could not be completed.' + . ' Please submit a support ticket or email us at security@magento.com.' + ); + + return $this; + } + + return $this; + } + + /** + * Remove session id from admin_user_session table. + * + * @throws \Zend_Db_Statement_Exception + */ + private function cleanAdminUserSessionTable() + { + $tableName = $this->moduleDataSetup->getTable('admin_user_session'); + // phpcs:ignore Magento2.SQL.RawQuery + $rawQuery = sprintf( + 'UPDATE %s SET session_id = NULL WHERE session_id IS NOT NULL LIMIT 1000', + $tableName + ); + + $adapter = $this->moduleDataSetup->getConnection(); + if ($adapter instanceof Mysql) { + do { + $result = $adapter->rawQuery($rawQuery)->rowCount(); + } while ($result > 0); + } else { + do { + $result = $adapter->query($rawQuery)->rowCount(); + } while ($result > 0); + } + } + + /** + * @inheritdoc + */ + public static function getDependencies() + { + return []; + } + + /** + * @inheritdoc + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Security/Test/Unit/Model/AdminSessionsManagerTest.php b/app/code/Magento/Security/Test/Unit/Model/AdminSessionsManagerTest.php index 6f0c3e1cccf87..8aa1359a21e16 100644 --- a/app/code/Magento/Security/Test/Unit/Model/AdminSessionsManagerTest.php +++ b/app/code/Magento/Security/Test/Unit/Model/AdminSessionsManagerTest.php @@ -3,43 +3,51 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\Security\Test\Unit\Model; +use Magento\Backend\Model\Auth\Session; use Magento\Framework\HTTP\PhpEnvironment\RemoteAddress; use Magento\Framework\Stdlib\DateTime\DateTime; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Security\Model\AdminSessionInfo; +use Magento\Security\Model\AdminSessionInfoFactory; use Magento\Security\Model\AdminSessionsManager; use Magento\Security\Model\ConfigInterface; +use Magento\Security\Model\ResourceModel\AdminSessionInfo\Collection; +use Magento\Security\Model\ResourceModel\AdminSessionInfo\CollectionFactory; +use Magento\User\Model\User; +use PHPUnit\Framework\TestCase; /** * Test class for AdminSessionsManager testing * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class AdminSessionsManagerTest extends \PHPUnit\Framework\TestCase +class AdminSessionsManagerTest extends TestCase { /** @var AdminSessionsManager */ protected $model; - /** @var \Magento\Security\Model\AdminSessionInfo */ + /** @var AdminSessionInfo */ protected $currentSessionMock; - /** @var \Magento\Backend\Model\Auth\Session */ + /** @var Session */ protected $authSessionMock; /** @var ConfigInterface */ protected $securityConfigMock; - /** @var \Magento\User\Model\User */ + /** @var User */ protected $userMock; - /** @var \Magento\Security\Model\ResourceModel\AdminSessionInfo\CollectionFactory */ + /** @var CollectionFactory */ protected $adminSessionInfoCollectionFactoryMock; - /** @var \Magento\Security\Model\ResourceModel\AdminSessionInfo\Collection */ + /** @var Collection */ protected $adminSessionInfoCollectionMock; - /** @var \Magento\Security\Model\AdminSessionInfoFactory */ + /** @var AdminSessionInfoFactory */ protected $adminSessionInfoFactoryMock; /** @@ -47,7 +55,7 @@ class AdminSessionsManagerTest extends \PHPUnit\Framework\TestCase */ protected $dateTimeMock; - /** @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager */ + /** @var ObjectManager */ protected $objectManager; /* @@ -63,18 +71,28 @@ protected function setUp(): void { $this->objectManager = new ObjectManager($this); - $this->authSessionMock = $this->createPartialMock( - \Magento\Backend\Model\Auth\Session::class, - ['isActive', 'getStatus', 'getUser', 'getId', 'getSessionId', 'getUpdatedAt'] - ); + $this->authSessionMock = $this->getMockBuilder(Session::class) + ->addMethods( + [ + 'isActive', + 'getStatus', + 'getUser', + 'getId', + 'getUpdatedAt', + 'getAdminSessionInfoId', + 'setAdminSessionInfoId' + ] + ) + ->disableOriginalConstructor() + ->getMock(); $this->adminSessionInfoCollectionFactoryMock = $this->createPartialMock( - \Magento\Security\Model\ResourceModel\AdminSessionInfo\CollectionFactory::class, + CollectionFactory::class, ['create'] ); $this->adminSessionInfoCollectionMock = $this->createPartialMock( - \Magento\Security\Model\ResourceModel\AdminSessionInfo\Collection::class, + Collection::class, [ 'filterByUser', 'filterExpiredSessions', @@ -87,27 +105,21 @@ protected function setUp(): void ); $this->adminSessionInfoFactoryMock = $this->createPartialMock( - \Magento\Security\Model\AdminSessionInfoFactory::class, + AdminSessionInfoFactory::class, ['create'] ); - $this->currentSessionMock = $this->createPartialMock(\Magento\Security\Model\AdminSessionInfo::class, [ - 'isActive', - 'getStatus', - 'load', - 'setData', - 'setIsOtherSessionsTerminated', - 'save', - 'getUserId', - 'getSessionId', - 'getUpdatedAt' - ]); - - $this->securityConfigMock = $this->getMockBuilder(\Magento\Security\Model\ConfigInterface::class) + $this->currentSessionMock = $this->getMockBuilder(AdminSessionInfo::class) + ->addMethods(['isActive', 'getStatus', 'getUserId', 'getUpdatedAt']) + ->onlyMethods(['load', 'setData', 'setIsOtherSessionsTerminated', 'save', 'getId']) ->disableOriginalConstructor() ->getMock(); - $this->userMock = $this->createPartialMock(\Magento\User\Model\User::class, ['getId']); + $this->securityConfigMock = $this->getMockBuilder(ConfigInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->userMock = $this->createPartialMock(User::class, ['getId']); $this->dateTimeMock = $this->getMockBuilder(DateTime::class) ->disableOriginalConstructor() @@ -118,7 +130,7 @@ protected function setUp(): void ->getMock(); $this->model = $this->objectManager->getObject( - \Magento\Security\Model\AdminSessionsManager::class, + AdminSessionsManager::class, [ 'securityConfig' => $this->securityConfigMock, 'authSession' => $this->authSessionMock, @@ -138,19 +150,18 @@ public function testProcessLogin() $useId = 1; $sessionLifetime = 100; $ip = 12345; - $sessionId = 50; $timestamp = time(); $olderThen = $timestamp - $sessionLifetime; + $adminSessionInfoId = 50; + $this->authSessionMock->expects($this->any()) + ->method('getAdminSessionInfoId') + ->willReturn($adminSessionInfoId); $this->adminSessionInfoFactoryMock->expects($this->exactly(2)) ->method('create') ->willReturn($this->currentSessionMock); - $this->authSessionMock->expects($this->exactly(2)) - ->method('getSessionId') - ->willReturn($sessionId); - $this->authSessionMock->expects($this->once()) ->method('getUser') ->willReturn($this->userMock); @@ -169,7 +180,6 @@ public function testProcessLogin() $this->currentSessionMock->expects($this->once()) ->method('save') ->willReturnSelf(); - $this->dateTimeMock->expects($this->once()) ->method('gmtTimestamp') ->willReturn($timestamp); @@ -186,9 +196,9 @@ public function testProcessLogin() ->method('getUserId') ->willReturn($useId); - $this->currentSessionMock->expects($this->once()) - ->method('getSessionId') - ->willReturn($sessionId); + $this->currentSessionMock->expects($this->any()) + ->method('getId') + ->willReturn($adminSessionInfoId); $this->adminSessionInfoCollectionFactoryMock->expects($this->once()) ->method('create') @@ -196,9 +206,9 @@ public function testProcessLogin() $this->adminSessionInfoCollectionMock->expects($this->once())->method('updateActiveSessionsStatus') ->with( - \Magento\Security\Model\AdminSessionInfo::LOGGED_OUT_BY_LOGIN, + AdminSessionInfo::LOGGED_OUT_BY_LOGIN, $useId, - $sessionId, + $adminSessionInfoId, $olderThen ) ->willReturn(1); @@ -216,18 +226,17 @@ public function testProcessLogin() */ public function testProcessProlong() { - $sessionId = 50; $lastUpdatedAt = '2015-12-31 23:59:59'; $newUpdatedAt = '2016-01-01 00:00:30'; + $adminSessionInfoId = 50; + $this->authSessionMock->expects($this->any()) + ->method('getAdminSessionInfoId') + ->willReturn($adminSessionInfoId); $this->adminSessionInfoFactoryMock->expects($this->any()) ->method('create') ->willReturn($this->currentSessionMock); - $this->authSessionMock->expects($this->once()) - ->method('getSessionId') - ->willReturn($sessionId); - $this->currentSessionMock->expects($this->once()) ->method('load') ->willReturnSelf(); @@ -261,23 +270,22 @@ public function testProcessProlong() */ public function testProcessLogout() { - $sessionId = 50; + $adminSessionInfoId = 50; + $this->authSessionMock->expects($this->any()) + ->method('getAdminSessionInfoId') + ->willReturn($adminSessionInfoId); $this->adminSessionInfoFactoryMock->expects($this->any()) ->method('create') ->willReturn($this->currentSessionMock); - $this->authSessionMock->expects($this->once()) - ->method('getSessionId') - ->willReturn($sessionId); - $this->currentSessionMock->expects($this->once()) ->method('load') ->willReturnSelf(); $this->currentSessionMock->expects($this->once()) ->method('setData') - ->with('status', \Magento\Security\Model\AdminSessionInfo::LOGGED_OUT) + ->with('status', AdminSessionInfo::LOGGED_OUT) ->willReturnSelf(); $this->currentSessionMock->expects($this->once()) @@ -292,16 +300,15 @@ public function testProcessLogout() */ public function testGetCurrentSession() { - $sessionId = 50; + $adminSessionInfoId = 50; + $this->authSessionMock->expects($this->any()) + ->method('getAdminSessionInfoId') + ->willReturn($adminSessionInfoId); $this->adminSessionInfoFactoryMock->expects($this->any()) ->method('create') ->willReturn($this->currentSessionMock); - $this->authSessionMock->expects($this->once()) - ->method('getSessionId') - ->willReturn($sessionId); - $this->currentSessionMock->expects($this->once()) ->method('load') ->willReturnSelf(); @@ -338,13 +345,35 @@ public function testCleanExpiredSessions() */ public function testGetLogoutReasonMessage($expectedResult, $sessionStatus) { - $this->adminSessionInfoFactoryMock->expects($this->once()) + $this->adminSessionInfoFactoryMock->expects($this->exactly(2)) ->method('create') ->willReturn($this->currentSessionMock); + $this->authSessionMock->expects($this->any()) + ->method('getUser') + ->willReturn($this->userMock); + $this->currentSessionMock->expects($this->once()) + ->method('setData') + ->willReturn($this->currentSessionMock); + $this->currentSessionMock->expects($this->once()) + ->method('save') + ->willReturn($this->currentSessionMock); + $this->adminSessionInfoCollectionFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->adminSessionInfoCollectionMock); + $this->adminSessionInfoCollectionMock->expects($this->once())->method('filterByUser') + ->willReturnSelf(); + $this->adminSessionInfoCollectionMock->expects($this->once()) + ->method('filterExpiredSessions') + ->willReturnSelf(); + $this->adminSessionInfoCollectionMock->expects($this->once()) + ->method('loadData') + ->willReturnSelf(); + $this->adminSessionInfoCollectionMock->expects($this->once()) + ->method('setDataToAll') + ->willReturnSelf(); $this->currentSessionMock->expects($this->once()) ->method('getStatus') ->willReturn($sessionStatus); - $this->assertEquals($expectedResult, $this->model->getLogoutReasonMessage()); } @@ -359,23 +388,23 @@ public function dataProviderLogoutReasonMessage() 'Someone logged into this account from another device or browser.' . ' Your current session is terminated.' ), - 'sessionStatus' => \Magento\Security\Model\AdminSessionInfo::LOGGED_OUT_BY_LOGIN + 'sessionStatus' => AdminSessionInfo::LOGGED_OUT_BY_LOGIN ], [ 'expectedResult' => __('Your current session is terminated by another user of this account.'), - 'sessionStatus' => \Magento\Security\Model\AdminSessionInfo::LOGGED_OUT_MANUALLY + 'sessionStatus' => AdminSessionInfo::LOGGED_OUT_MANUALLY ], [ 'expectedResult' => __('Your current session has been expired.'), - 'sessionStatus' => \Magento\Security\Model\AdminSessionInfo::LOGGED_OUT + 'sessionStatus' => AdminSessionInfo::LOGGED_OUT ], [ 'expectedResult' => __('Your account is temporarily disabled. Please try again later.'), - 'sessionStatus' => \Magento\Security\Model\AdminSessionsManager::LOGOUT_REASON_USER_LOCKED + 'sessionStatus' => AdminSessionsManager::LOGOUT_REASON_USER_LOCKED ], [ 'expectedResult' => '', - 'sessionStatus' => \Magento\Security\Model\AdminSessionInfo::LOGGED_IN + 'sessionStatus' => AdminSessionInfo::LOGGED_IN ] ]; } @@ -397,7 +426,7 @@ public function testGetSessionsForCurrentUser() ->method('getId') ->willReturn($useId); $this->adminSessionInfoCollectionMock->expects($this->once())->method('filterByUser') - ->with($useId, \Magento\Security\Model\AdminSessionInfo::LOGGED_IN) + ->with($useId, AdminSessionInfo::LOGGED_IN) ->willReturnSelf(); $this->securityConfigMock->expects($this->once()) ->method('getAdminSessionLifetime') @@ -420,22 +449,24 @@ public function testLogoutOtherUserSessions() { $useId = 1; $sessionLifetime = 100; - $sessionId = 50; + $adminSessionInfoId = 50; + $this->authSessionMock->expects($this->any()) + ->method('getAdminSessionInfoId') + ->willReturn($adminSessionInfoId); + $this->adminSessionInfoCollectionFactoryMock->expects($this->once()) ->method('create') ->willReturn($this->adminSessionInfoCollectionMock); $this->authSessionMock->expects($this->once()) ->method('getUser') ->willReturn($this->userMock); - $this->authSessionMock->expects($this->once()) - ->method('getSessionId') - ->willReturn($sessionId); + $this->userMock->expects($this->once()) ->method('getId') ->willReturn($useId); $this->adminSessionInfoCollectionMock->expects($this->once()) ->method('filterByUser') - ->with($useId, \Magento\Security\Model\AdminSessionInfo::LOGGED_IN, $sessionId) + ->with($useId, AdminSessionInfo::LOGGED_IN, $adminSessionInfoId) ->willReturnSelf(); $this->securityConfigMock->expects($this->once()) ->method('getAdminSessionLifetime') @@ -449,7 +480,7 @@ public function testLogoutOtherUserSessions() ->willReturnSelf(); $this->adminSessionInfoCollectionMock->expects($this->once()) ->method('setDataToAll') - ->with($this->equalTo('status'), \Magento\Security\Model\AdminSessionInfo::LOGGED_OUT_MANUALLY) + ->with($this->equalTo('status'), AdminSessionInfo::LOGGED_OUT_MANUALLY) ->willReturnSelf(); $this->adminSessionInfoCollectionMock->expects($this->once()) ->method('save'); diff --git a/app/code/Magento/Security/Test/Unit/Model/ResourceModel/AdminSessionInfo/CollectionTest.php b/app/code/Magento/Security/Test/Unit/Model/ResourceModel/AdminSessionInfo/CollectionTest.php index 8300e21490761..2a492a3de7b09 100644 --- a/app/code/Magento/Security/Test/Unit/Model/ResourceModel/AdminSessionInfo/CollectionTest.php +++ b/app/code/Magento/Security/Test/Unit/Model/ResourceModel/AdminSessionInfo/CollectionTest.php @@ -102,7 +102,7 @@ public function testFilterByUser() ->withConsecutive( ['user_id', $userId], ['status', $status], - ['session_id', ['neq' => $sessionIdToExclude]] + ['id', ['neq' => $sessionIdToExclude]] ) ->willReturnSelf(); diff --git a/app/code/Magento/Security/Test/Unit/Model/ResourceModel/AdminSessionInfoTest.php b/app/code/Magento/Security/Test/Unit/Model/ResourceModel/AdminSessionInfoTest.php index 288f94ff92248..7f175160dee0a 100644 --- a/app/code/Magento/Security/Test/Unit/Model/ResourceModel/AdminSessionInfoTest.php +++ b/app/code/Magento/Security/Test/Unit/Model/ResourceModel/AdminSessionInfoTest.php @@ -82,7 +82,7 @@ public function testUpdateStatusByUserId() 'user_id = ?' => (int) $userId, ]; if (!empty($excludedSessionIds)) { - $whereStatement['session_id NOT IN (?)'] = $excludedSessionIds; + $whereStatement['id NOT IN (?)'] = $excludedSessionIds; } if (!empty($withStatuses)) { $whereStatement['status IN (?)'] = $withStatuses; diff --git a/app/code/Magento/Security/composer.json b/app/code/Magento/Security/composer.json index 4978f0c628f96..4ed5b483faca9 100644 --- a/app/code/Magento/Security/composer.json +++ b/app/code/Magento/Security/composer.json @@ -1,24 +1,26 @@ { "name": "magento/module-security", "description": "Security management module", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.6-p2", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-store": "*", - "magento/module-user": "*" + "magento/framework": "102.0.*", + "magento/module-config": "101.1.*", + "magento/module-backend": "101.0.*", + "magento/module-store": "101.0.*", + "magento/module-user": "101.1.*" }, "suggest": { - "magento/module-customer": "*" + "magento/module-customer": "102.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -28,3 +30,4 @@ } } } + diff --git a/app/code/Magento/Security/etc/adminhtml/system.xml b/app/code/Magento/Security/etc/adminhtml/system.xml index 71513361a694e..18753facb19cf 100644 --- a/app/code/Magento/Security/etc/adminhtml/system.xml +++ b/app/code/Magento/Security/etc/adminhtml/system.xml @@ -36,6 +36,29 @@
+
+ + + + + Are You Sure About Your Max Session Size in Admin Settings? + Magento_Security::system/config/session_size_admin/modal_content_body.phtml + required-entry validate-zero-or-greater validate-digits + Magento\Security\Block\Config\Backend\Session\SessionSize + Magento\Security\Model\Config\Backend\Session\SessionSize + Limit the maximum session size in bytes. Use 0 to disable. + + + + Are You Sure About Your Max Session Size in Storefront Settings? + Magento_Security::system/config/session_size_storefront/modal_content_body.phtml + required-entry validate-zero-or-greater validate-digits + Magento\Security\Block\Config\Backend\Session\SessionSize + Magento\Security\Model\Config\Backend\Session\SessionSize + Limit the maximum session size in bytes. Use 0 to disable. + + +
diff --git a/app/code/Magento/Security/etc/config.xml b/app/code/Magento/Security/etc/config.xml index 046969058f215..bdc0bc7207861 100644 --- a/app/code/Magento/Security/etc/config.xml +++ b/app/code/Magento/Security/etc/config.xml @@ -15,6 +15,12 @@ 10 + + + 256000 + 256000 + + 1 diff --git a/app/code/Magento/Security/etc/db_schema.xml b/app/code/Magento/Security/etc/db_schema.xml index 5052f5642cb53..1cf9c29efaec4 100644 --- a/app/code/Magento/Security/etc/db_schema.xml +++ b/app/code/Magento/Security/etc/db_schema.xml @@ -10,7 +10,8 @@ - + +
+

+ escapeHtml(__('Warning')) ?> + escapeHtml(__(': You are about to set max session size in admin to be lower than recommended ' . + 'default session size. Low max session size in admin could break admin functionalities such as admin ' . + 'panel login. Are you sure you want to make this change?')) ?> +

+
diff --git a/app/code/Magento/Security/view/adminhtml/templates/system/config/session_size_storefront/modal_content_body.phtml b/app/code/Magento/Security/view/adminhtml/templates/system/config/session_size_storefront/modal_content_body.phtml new file mode 100644 index 0000000000000..3a15b6a735ed3 --- /dev/null +++ b/app/code/Magento/Security/view/adminhtml/templates/system/config/session_size_storefront/modal_content_body.phtml @@ -0,0 +1,15 @@ + +
+

+ escapeHtml(__('Warning')) ?> + escapeHtml(__(': You are about to set max session size in storefront to be lower than ' . + ' recommended default session size. Low max session size in storefront could break storefront ' . + 'functionalities such as customer login. Are you sure you want to make this change?')) ?> +

+
diff --git a/app/code/Magento/Security/view/adminhtml/web/js/system/config/session-size.js b/app/code/Magento/Security/view/adminhtml/web/js/system/config/session-size.js new file mode 100644 index 0000000000000..6d95a73fe6b6b --- /dev/null +++ b/app/code/Magento/Security/view/adminhtml/web/js/system/config/session-size.js @@ -0,0 +1,58 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'jquery', + 'mage/translate', + 'Magento_Ui/js/modal/confirm', + 'domReady!' +], function ($, $t, confirm) { + 'use strict'; + + return function (config, inputEl) { + var $inputEl = $(inputEl); + + $inputEl.on('blur', function () { + var inputVal = parseInt($inputEl.val(), 10); + + if (256000 > inputVal) { + confirm({ + title: $t(config.modalTitleText), + content: $t(config.modalContentBody), + buttons: [{ + text: $t('No'), + class: 'action-secondary action-dismiss', + + /** + * Close modal and trigger 'cancel' action on click + */ + click: function (event) { + this.closeModal(event); + } + }, { + text: $t('Yes'), + class: 'action-primary action-accept', + + /** + * Close modal and trigger 'confirm' action on click + */ + click: function (event) { + this.closeModal(event, true); + } + }], + actions: { + + /** + * Revert back to original value + */ + cancel: function () { + $inputEl.val(256000); + } + } + }); + } + }); + }; +}); diff --git a/app/code/Magento/SendFriend/composer.json b/app/code/Magento/SendFriend/composer.json index 17c908ab33e3e..426b8b6869d58 100644 --- a/app/code/Magento/SendFriend/composer.json +++ b/app/code/Magento/SendFriend/composer.json @@ -1,24 +1,25 @@ { "name": "magento/module-send-friend", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.5", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-catalog": "*", - "magento/module-customer": "*", - "magento/module-store": "*", - "magento/module-captcha": "*", - "magento/module-authorization": "*", - "magento/module-theme": "*" + "magento/framework": "102.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-customer": "102.0.*", + "magento/module-store": "101.0.*", + "magento/module-captcha": "100.3.*", + "magento/module-authorization": "100.3.*", + "magento/module-theme": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -28,3 +29,4 @@ } } } + diff --git a/app/code/Magento/SendFriendGraphQl/composer.json b/app/code/Magento/SendFriendGraphQl/composer.json index 456780c1c1841..1770047deb0cd 100644 --- a/app/code/Magento/SendFriendGraphQl/composer.json +++ b/app/code/Magento/SendFriendGraphQl/composer.json @@ -2,17 +2,18 @@ "name": "magento/module-send-friend-graph-ql", "description": "N/A", "type": "magento2-module", - "require": { - "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-catalog": "*", - "magento/module-send-friend": "*", - "magento/module-graph-ql": "*" - }, "license": [ "OSL-3.0", "AFL-3.0" ], + "version": "100.3.4", + "require": { + "php": "~7.3.0||~7.4.0", + "magento/framework": "102.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-send-friend": "100.3.*", + "magento/module-graph-ql": "100.3.*" + }, "autoload": { "files": [ "registration.php" @@ -22,3 +23,4 @@ } } } + diff --git a/app/code/Magento/Shipping/composer.json b/app/code/Magento/Shipping/composer.json index 5ea8430226ad8..a420a8f236403 100644 --- a/app/code/Magento/Shipping/composer.json +++ b/app/code/Magento/Shipping/composer.json @@ -1,37 +1,38 @@ { "name": "magento/module-shipping", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7", "require": { "php": "~7.3.0||~7.4.0", "ext-gd": "*", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-catalog-inventory": "*", - "magento/module-contact": "*", - "magento/module-customer": "*", - "magento/module-directory": "*", - "magento/module-payment": "*", - "magento/module-quote": "*", - "magento/module-sales": "*", - "magento/module-store": "*", - "magento/module-tax": "*", - "magento/module-ui": "*", - "magento/module-user": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-catalog-inventory": "100.3.*", + "magento/module-contact": "100.3.*", + "magento/module-customer": "102.0.*", + "magento/module-directory": "100.3.*", + "magento/module-payment": "100.3.*", + "magento/module-quote": "101.1.*", + "magento/module-sales": "102.0.*", + "magento/module-store": "101.0.*", + "magento/module-tax": "100.3.*", + "magento/module-ui": "101.1.*", + "magento/module-user": "101.1.*" }, "suggest": { - "magento/module-fedex": "*", - "magento/module-ups": "*", - "magento/module-config": "*" + "magento/module-fedex": "100.3.*", + "magento/module-ups": "100.3.*", + "magento/module-config": "101.1.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -41,3 +42,4 @@ } } } + diff --git a/app/code/Magento/Signifyd/composer.json b/app/code/Magento/Signifyd/composer.json index ee9ca2c4e03e2..9f109d9605c45 100644 --- a/app/code/Magento/Signifyd/composer.json +++ b/app/code/Magento/Signifyd/composer.json @@ -1,29 +1,30 @@ { "name": "magento/module-signifyd", "description": "Submitting Case Entry to Signifyd on Order Creation", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.6", "require": { - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-checkout": "*", - "magento/module-config": "*", - "magento/module-customer": "*", - "magento/module-directory": "*", - "magento/module-payment": "*", - "magento/module-sales": "*", - "magento/module-store": "*", + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-checkout": "100.3.*", + "magento/module-config": "101.1.*", + "magento/module-customer": "102.0.*", + "magento/module-directory": "100.3.*", + "magento/module-payment": "100.3.*", + "magento/module-sales": "102.0.*", + "magento/module-store": "101.0.*", "php": "~7.3.0||~7.4.0" }, "suggest": { - "magento/module-config": "*" + "magento/module-config": "101.1.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -33,3 +34,4 @@ } } } + diff --git a/app/code/Magento/Sitemap/composer.json b/app/code/Magento/Sitemap/composer.json index 6a9f20ac8bddf..12dba4ca98dcc 100644 --- a/app/code/Magento/Sitemap/composer.json +++ b/app/code/Magento/Sitemap/composer.json @@ -1,30 +1,31 @@ { "name": "magento/module-sitemap", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-catalog-url-rewrite": "*", - "magento/module-cms": "*", - "magento/module-config": "*", - "magento/module-eav": "*", - "magento/module-media-storage": "*", - "magento/module-robots": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-catalog-url-rewrite": "100.3.*", + "magento/module-cms": "103.0.*", + "magento/module-config": "101.1.*", + "magento/module-eav": "102.0.*", + "magento/module-media-storage": "100.3.*", + "magento/module-robots": "101.0.*", + "magento/module-store": "101.0.*" }, "suggest": { - "magento/module-config": "*" + "magento/module-config": "101.1.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -34,3 +35,4 @@ } } } + diff --git a/app/code/Magento/Store/composer.json b/app/code/Magento/Store/composer.json index e6f7f0d5ac274..c9dc48fd3dd3a 100644 --- a/app/code/Magento/Store/composer.json +++ b/app/code/Magento/Store/composer.json @@ -1,29 +1,30 @@ { "name": "magento/module-store", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "101.0.7-p2", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-catalog": "*", - "magento/module-config": "*", - "magento/module-directory": "*", - "magento/module-media-storage": "*", - "magento/module-ui": "*", - "magento/module-customer": "*", - "magento/module-authorization": "*", - "magento/module-backend": "*" + "magento/framework": "102.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-config": "101.1.*", + "magento/module-directory": "100.3.*", + "magento/module-media-storage": "100.3.*", + "magento/module-ui": "101.1.*", + "magento/module-customer": "102.0.*", + "magento/module-authorization": "100.3.*", + "magento/module-backend": "101.0.*" }, "suggest": { - "magento/module-deploy": "*" + "magento/module-deploy": "100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -33,3 +34,4 @@ } } } + diff --git a/app/code/Magento/Store/etc/config.xml b/app/code/Magento/Store/etc/config.xml index 2872b82566454..0629a9175433f 100644 --- a/app/code/Magento/Store/etc/config.xml +++ b/app/code/Magento/Store/etc/config.xml @@ -124,6 +124,7 @@ pl py asp + aspx sh cgi htm diff --git a/app/code/Magento/Store/etc/di.xml b/app/code/Magento/Store/etc/di.xml index 8f4151b8fc966..817ea23dc851e 100644 --- a/app/code/Magento/Store/etc/di.xml +++ b/app/code/Magento/Store/etc/di.xml @@ -170,6 +170,11 @@ Magento\Store\Model\ScopeInterface::SCOPE_STORE + + + Magento\Store\Model\ScopeInterface::SCOPE_STORE + + Magento\Store\Model\ScopeInterface::SCOPE_STORE diff --git a/app/code/Magento/StoreGraphQl/composer.json b/app/code/Magento/StoreGraphQl/composer.json index a7cab5851a9ee..d9b98c262f288 100644 --- a/app/code/Magento/StoreGraphQl/composer.json +++ b/app/code/Magento/StoreGraphQl/composer.json @@ -2,16 +2,17 @@ "name": "magento/module-store-graph-ql", "description": "N/A", "type": "magento2-module", - "require": { - "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-store": "*", - "magento/module-graph-ql": "*" - }, "license": [ "OSL-3.0", "AFL-3.0" ], + "version": "100.3.5", + "require": { + "php": "~7.3.0||~7.4.0", + "magento/framework": "102.0.*", + "magento/module-store": "101.0.*", + "magento/module-graph-ql": "100.3.*" + }, "autoload": { "files": [ "registration.php" @@ -21,3 +22,4 @@ } } } + diff --git a/app/code/Magento/Swagger/composer.json b/app/code/Magento/Swagger/composer.json index 759e72350b0a6..8030035289a9c 100644 --- a/app/code/Magento/Swagger/composer.json +++ b/app/code/Magento/Swagger/composer.json @@ -1,18 +1,19 @@ { "name": "magento/module-swagger", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.6", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*" + "magento/framework": "102.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -22,3 +23,4 @@ } } } + diff --git a/app/code/Magento/SwaggerWebapi/composer.json b/app/code/Magento/SwaggerWebapi/composer.json index 78021f7cb4ec5..fb10f60133a3d 100644 --- a/app/code/Magento/SwaggerWebapi/composer.json +++ b/app/code/Magento/SwaggerWebapi/composer.json @@ -1,19 +1,20 @@ { "name": "magento/module-swagger-webapi", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.5", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-swagger": "*" + "magento/framework": "102.0.*", + "magento/module-swagger": "100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -23,3 +24,4 @@ } } } + diff --git a/app/code/Magento/SwaggerWebapiAsync/composer.json b/app/code/Magento/SwaggerWebapiAsync/composer.json index 283b2fe1f1758..e7840b358982d 100644 --- a/app/code/Magento/SwaggerWebapiAsync/composer.json +++ b/app/code/Magento/SwaggerWebapiAsync/composer.json @@ -1,22 +1,23 @@ { "name": "magento/module-swagger-webapi-async", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.5", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-swagger": "*" + "magento/framework": "102.0.*", + "magento/module-swagger": "100.3.*" }, "suggest": { - "magento/module-config": "*" + "magento/module-config": "101.1.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -26,3 +27,4 @@ } } } + diff --git a/app/code/Magento/Swatches/composer.json b/app/code/Magento/Swatches/composer.json index 2c9b7a03ba011..3ef3308187084 100644 --- a/app/code/Magento/Swatches/composer.json +++ b/app/code/Magento/Swatches/composer.json @@ -1,32 +1,33 @@ { "name": "magento/module-swatches", "description": "Add Swatches to Products", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-config": "*", - "magento/module-configurable-product": "*", - "magento/module-customer": "*", - "magento/module-eav": "*", - "magento/module-page-cache": "*", - "magento/module-media-storage": "*", - "magento/module-store": "*", - "magento/module-theme": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-config": "101.1.*", + "magento/module-configurable-product": "100.3.*", + "magento/module-customer": "102.0.*", + "magento/module-eav": "102.0.*", + "magento/module-page-cache": "100.3.*", + "magento/module-media-storage": "100.3.*", + "magento/module-store": "101.0.*", + "magento/module-theme": "101.0.*" }, "suggest": { - "magento/module-layered-navigation": "*", - "magento/module-swatches-sample-data": "*" + "magento/module-layered-navigation": "100.3.*", + "magento/module-swatches-sample-data": "Sample Data version: 100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -36,3 +37,4 @@ } } } + diff --git a/app/code/Magento/SwatchesGraphQl/composer.json b/app/code/Magento/SwatchesGraphQl/composer.json index 383575302e6ae..b4e92ddf2db69 100644 --- a/app/code/Magento/SwatchesGraphQl/composer.json +++ b/app/code/Magento/SwatchesGraphQl/composer.json @@ -2,19 +2,20 @@ "name": "magento/module-swatches-graph-ql", "description": "N/A", "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "version": "100.3.6", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-swatches": "*", - "magento/module-catalog": "*" + "magento/framework": "102.0.*", + "magento/module-swatches": "100.3.*", + "magento/module-catalog": "103.0.*" }, "suggest": { - "magento/module-catalog-graph-ql": "*" + "magento/module-catalog-graph-ql": "100.3.*" }, - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -24,3 +25,4 @@ } } } + diff --git a/app/code/Magento/SwatchesLayeredNavigation/composer.json b/app/code/Magento/SwatchesLayeredNavigation/composer.json index 3b987f8096f18..86e145fd4c125 100644 --- a/app/code/Magento/SwatchesLayeredNavigation/composer.json +++ b/app/code/Magento/SwatchesLayeredNavigation/composer.json @@ -1,19 +1,20 @@ { "name": "magento/module-swatches-layered-navigation", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.5", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", + "magento/framework": "102.0.*", "magento/magento-composer-installer": "*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -23,3 +24,4 @@ } } } + diff --git a/app/code/Magento/Tax/composer.json b/app/code/Magento/Tax/composer.json index 65c668553cd14..3edaed7233def 100644 --- a/app/code/Magento/Tax/composer.json +++ b/app/code/Magento/Tax/composer.json @@ -1,34 +1,35 @@ { "name": "magento/module-tax", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-checkout": "*", - "magento/module-config": "*", - "magento/module-customer": "*", - "magento/module-directory": "*", - "magento/module-eav": "*", - "magento/module-page-cache": "*", - "magento/module-quote": "*", - "magento/module-reports": "*", - "magento/module-sales": "*", - "magento/module-shipping": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-checkout": "100.3.*", + "magento/module-config": "101.1.*", + "magento/module-customer": "102.0.*", + "magento/module-directory": "100.3.*", + "magento/module-eav": "102.0.*", + "magento/module-page-cache": "100.3.*", + "magento/module-quote": "101.1.*", + "magento/module-reports": "100.3.*", + "magento/module-sales": "102.0.*", + "magento/module-shipping": "100.3.*", + "magento/module-store": "101.0.*" }, "suggest": { - "magento/module-tax-sample-data": "*" + "magento/module-tax-sample-data": "Sample Data version: 100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -38,3 +39,4 @@ } } } + diff --git a/app/code/Magento/TaxGraphQl/composer.json b/app/code/Magento/TaxGraphQl/composer.json index b97e414cacb67..55e8846e23386 100644 --- a/app/code/Magento/TaxGraphQl/composer.json +++ b/app/code/Magento/TaxGraphQl/composer.json @@ -2,18 +2,19 @@ "name": "magento/module-tax-graph-ql", "description": "N/A", "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "version": "100.3.5", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*" + "magento/framework": "102.0.*" }, "suggest": { - "magento/module-tax": "*", - "magento/module-catalog-graph-ql": "*" + "magento/module-tax": "100.3.*", + "magento/module-catalog-graph-ql": "100.3.*" }, - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -23,3 +24,4 @@ } } } + diff --git a/app/code/Magento/TaxImportExport/composer.json b/app/code/Magento/TaxImportExport/composer.json index ee24deb9d3246..02def4ec8fc0e 100644 --- a/app/code/Magento/TaxImportExport/composer.json +++ b/app/code/Magento/TaxImportExport/composer.json @@ -1,22 +1,23 @@ { "name": "magento/module-tax-import-export", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.5", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-directory": "*", - "magento/module-store": "*", - "magento/module-tax": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-directory": "100.3.*", + "magento/module-store": "101.0.*", + "magento/module-tax": "100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -26,3 +27,4 @@ } } } + diff --git a/app/code/Magento/Theme/Controller/Adminhtml/System/Design/Theme/Save.php b/app/code/Magento/Theme/Controller/Adminhtml/System/Design/Theme/Save.php index d79d662bf4a3a..033a82c6292ea 100644 --- a/app/code/Magento/Theme/Controller/Adminhtml/System/Design/Theme/Save.php +++ b/app/code/Magento/Theme/Controller/Adminhtml/System/Design/Theme/Save.php @@ -7,8 +7,9 @@ namespace Magento\Theme\Controller\Adminhtml\System\Design\Theme; /** - * Class Save + * Class Save use to save Theme data * @deprecated 100.2.0 + * @SuppressWarnings(PHPMD.AllPurposeAction) */ class Save extends \Magento\Theme\Controller\Adminhtml\System\Design\Theme { @@ -51,7 +52,9 @@ public function execute() if ($theme && !$theme->isEditable()) { throw new \Magento\Framework\Exception\LocalizedException(__('This theme is not editable.')); } - $theme->addData($themeData); + $theme->addData( + $this->extractMutableData($themeData) + ); if (isset($themeData['preview']['delete'])) { $theme->getThemeImage()->removePreviewImage(); } @@ -80,4 +83,18 @@ public function execute() ? $this->_redirect('adminhtml/*/edit', ['id' => $theme->getId()]) : $this->_redirect('adminhtml/*/'); } + + /** + * Extract required attributes + * + * @param array $postData + * @return array + */ + private function extractMutableData(array $postData): array + { + if (!empty($postData['theme_title'])) { + return ['theme_title' => $postData['theme_title']]; + } + return []; + } } diff --git a/app/code/Magento/Theme/Model/Theme/Image/Path.php b/app/code/Magento/Theme/Model/Theme/Image/Path.php index 2e435d4498713..a337eefe5cc92 100644 --- a/app/code/Magento/Theme/Model/Theme/Image/Path.php +++ b/app/code/Magento/Theme/Model/Theme/Image/Path.php @@ -103,6 +103,6 @@ public function getImagePreviewDirectory() */ public function getTemporaryDirectory() { - return $this->mediaDirectory->getRelativePath('/theme/origin'); + return $this->mediaDirectory->getAbsolutePath('theme/origin'); } } diff --git a/app/code/Magento/Theme/Test/Mftf/Test/AdminDesignConfigMediaGalleryImageUploadTest.xml b/app/code/Magento/Theme/Test/Mftf/Test/AdminDesignConfigMediaGalleryImageUploadTest.xml index f46328ac151b1..7bfb33058a17a 100644 --- a/app/code/Magento/Theme/Test/Mftf/Test/AdminDesignConfigMediaGalleryImageUploadTest.xml +++ b/app/code/Magento/Theme/Test/Mftf/Test/AdminDesignConfigMediaGalleryImageUploadTest.xml @@ -36,9 +36,16 @@ - + + + + + + + + @@ -62,17 +69,18 @@ - + + - - + + - - - - - + + + + + diff --git a/app/code/Magento/Theme/Test/Unit/Model/Theme/Image/PathTest.php b/app/code/Magento/Theme/Test/Unit/Model/Theme/Image/PathTest.php index 752a45c18c88a..4100cf4bef1bb 100644 --- a/app/code/Magento/Theme/Test/Unit/Model/Theme/Image/PathTest.php +++ b/app/code/Magento/Theme/Test/Unit/Model/Theme/Image/PathTest.php @@ -50,8 +50,8 @@ protected function setUp(): void $this->mediaDirectory->expects($this->any()) ->method('getRelativePath') - ->with('/theme/origin') - ->willReturn('/theme/origin'); + ->with('theme/origin') + ->willReturn('theme/origin'); $this->filesystem->expects($this->any())->method('getDirectoryRead') ->with(DirectoryList::MEDIA) @@ -62,17 +62,17 @@ protected function setUp(): void $this->_assetRepo, $this->_storeManager ); - - $this->_model = new Path($this->filesystem, $this->_assetRepo, $this->_storeManager); } public function testGetPreviewImageUrl() { /** @var $theme \Magento\Theme\Model\Theme|\PHPUnit\Framework\MockObject\MockObject */ - $theme = $this->createPartialMock( - \Magento\Theme\Model\Theme::class, - ['getPreviewImage', 'isPhysical', '__wakeup'] - ); + $theme = $this->getMockBuilder(\Magento\Theme\Model\Theme::class) + ->disableOriginalConstructor() + ->addMethods(['getPreviewImage']) + ->onlyMethods(['isPhysical', '__wakeup']) + ->getMock(); + $theme->expects($this->any()) ->method('getPreviewImage') ->willReturn('image.png'); @@ -89,10 +89,11 @@ public function testGetPreviewImagePath() $expectedPath = 'theme/preview/preview.jpg'; /** @var $theme \Magento\Theme\Model\Theme|\PHPUnit\Framework\MockObject\MockObject */ - $theme = $this->createPartialMock( - \Magento\Theme\Model\Theme::class, - ['getPreviewImage', 'isPhysical', '__wakeup'] - ); + $theme = $this->getMockBuilder(\Magento\Theme\Model\Theme::class) + ->disableOriginalConstructor() + ->addMethods(['getPreviewImage']) + ->onlyMethods(['isPhysical', '__wakeup']) + ->getMock(); $this->mediaDirectory->expects($this->once()) ->method('getAbsolutePath') @@ -138,8 +139,11 @@ public function testImagePreviewDirectoryGetter() */ public function testTemporaryDirectoryGetter() { + $this->mediaDirectory->expects($this->any()) + ->method('getAbsolutePath') + ->willReturn('/foo/theme/origin'); $this->assertEquals( - '/theme/origin', + '/foo/theme/origin', $this->model->getTemporaryDirectory() ); } diff --git a/app/code/Magento/Theme/composer.json b/app/code/Magento/Theme/composer.json index 63779c6f9bf5d..b67fca0a60486 100644 --- a/app/code/Magento/Theme/composer.json +++ b/app/code/Magento/Theme/composer.json @@ -1,33 +1,34 @@ { "name": "magento/module-theme", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "101.0.7-p2", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-cms": "*", - "magento/module-config": "*", - "magento/module-customer": "*", - "magento/module-eav": "*", - "magento/module-media-storage": "*", - "magento/module-require-js": "*", - "magento/module-store": "*", - "magento/module-ui": "*", - "magento/module-widget": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-cms": "103.0.*", + "magento/module-config": "101.1.*", + "magento/module-customer": "102.0.*", + "magento/module-eav": "102.0.*", + "magento/module-media-storage": "100.3.*", + "magento/module-require-js": "100.3.*", + "magento/module-store": "101.0.*", + "magento/module-ui": "101.1.*", + "magento/module-widget": "101.1.*" }, "suggest": { - "magento/module-theme-sample-data": "*", - "magento/module-deploy": "*", - "magento/module-directory": "*" + "magento/module-theme-sample-data": "Sample Data version: 100.3.*", + "magento/module-deploy": "100.3.*", + "magento/module-directory": "100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -37,3 +38,4 @@ } } } + diff --git a/app/code/Magento/ThemeGraphQl/composer.json b/app/code/Magento/ThemeGraphQl/composer.json index cee740d449b37..8f305ee4539a5 100644 --- a/app/code/Magento/ThemeGraphQl/composer.json +++ b/app/code/Magento/ThemeGraphQl/composer.json @@ -2,17 +2,18 @@ "name": "magento/module-theme-graph-ql", "description": "N/A", "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "version": "100.3.4", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*" + "magento/framework": "102.0.*" }, "suggest": { - "magento/module-store-graph-ql": "*" + "magento/module-store-graph-ql": "100.3.*" }, - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -22,3 +23,4 @@ } } } + diff --git a/app/code/Magento/Tinymce3/composer.json b/app/code/Magento/Tinymce3/composer.json index b934cb4bcbff2..8a80314ecea0a 100644 --- a/app/code/Magento/Tinymce3/composer.json +++ b/app/code/Magento/Tinymce3/composer.json @@ -1,24 +1,24 @@ { "name": "magento/module-tinymce-3", "description": "N/A", - "require": { - "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-ui": "*", - "magento/module-variable": "*", - "magento/module-widget": "*", - "magento/module-cms": "*" - - }, - "suggest": { - "magento/module-cms": "*" - }, "type": "magento2-module", "license": [ "OSL-3.0", "AFL-3.0" ], + "version": "100.3.7", + "require": { + "php": "~7.3.0||~7.4.0", + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-ui": "101.1.*", + "magento/module-variable": "100.3.*", + "magento/module-widget": "101.1.*", + "magento/module-cms": "103.0.*" + }, + "suggest": { + "magento/module-cms": "103.0.*" + }, "autoload": { "files": [ "registration.php" @@ -28,3 +28,4 @@ } } } + diff --git a/app/code/Magento/Translation/composer.json b/app/code/Magento/Translation/composer.json index 7f67749fa88f4..668209a79273a 100644 --- a/app/code/Magento/Translation/composer.json +++ b/app/code/Magento/Translation/composer.json @@ -1,25 +1,26 @@ { "name": "magento/module-translation", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-developer": "*", - "magento/module-store": "*", - "magento/module-theme": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-developer": "100.3.*", + "magento/module-store": "101.0.*", + "magento/module-theme": "101.0.*" }, "suggest": { - "magento/module-deploy": "*" + "magento/module-deploy": "100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -29,3 +30,4 @@ } } } + diff --git a/app/code/Magento/Ui/composer.json b/app/code/Magento/Ui/composer.json index 05051d7010d4e..a2f9855c39378 100644 --- a/app/code/Magento/Ui/composer.json +++ b/app/code/Magento/Ui/composer.json @@ -1,27 +1,28 @@ { "name": "magento/module-ui", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "101.1.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-authorization": "*", - "magento/module-backend": "*", - "magento/module-eav": "*", - "magento/module-store": "*", - "magento/module-user": "*", - "magento/module-cms": "*" + "magento/framework": "102.0.*", + "magento/module-authorization": "100.3.*", + "magento/module-backend": "101.0.*", + "magento/module-eav": "102.0.*", + "magento/module-store": "101.0.*", + "magento/module-user": "101.1.*", + "magento/module-cms": "103.0.*" }, "suggest": { - "magento/module-config": "*" + "magento/module-config": "101.1.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -31,3 +32,4 @@ } } } + diff --git a/app/code/Magento/Ups/composer.json b/app/code/Magento/Ups/composer.json index fa8962f0af592..1b23eccf98e72 100644 --- a/app/code/Magento/Ups/composer.json +++ b/app/code/Magento/Ups/composer.json @@ -1,28 +1,29 @@ { "name": "magento/module-ups", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-catalog-inventory": "*", - "magento/module-directory": "*", - "magento/module-quote": "*", - "magento/module-sales": "*", - "magento/module-shipping": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog-inventory": "100.3.*", + "magento/module-directory": "100.3.*", + "magento/module-quote": "101.1.*", + "magento/module-sales": "102.0.*", + "magento/module-shipping": "100.3.*", + "magento/module-store": "101.0.*" }, "suggest": { - "magento/module-config": "*" + "magento/module-config": "101.1.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -32,3 +33,4 @@ } } } + diff --git a/app/code/Magento/UrlRewrite/composer.json b/app/code/Magento/UrlRewrite/composer.json index 59e6fee9ea904..cf09d85d336a3 100644 --- a/app/code/Magento/UrlRewrite/composer.json +++ b/app/code/Magento/UrlRewrite/composer.json @@ -1,24 +1,25 @@ { "name": "magento/module-url-rewrite", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "101.1.6", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-catalog-url-rewrite": "*", - "magento/module-cms": "*", - "magento/module-cms-url-rewrite": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-catalog-url-rewrite": "100.3.*", + "magento/module-cms": "103.0.*", + "magento/module-cms-url-rewrite": "100.3.*", + "magento/module-store": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -28,3 +29,4 @@ } } } + diff --git a/app/code/Magento/UrlRewriteGraphQl/composer.json b/app/code/Magento/UrlRewriteGraphQl/composer.json index 766ad3ab46ebd..da3b3d50e1bb5 100644 --- a/app/code/Magento/UrlRewriteGraphQl/composer.json +++ b/app/code/Magento/UrlRewriteGraphQl/composer.json @@ -2,18 +2,19 @@ "name": "magento/module-url-rewrite-graph-ql", "description": "N/A", "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "version": "100.3.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-url-rewrite": "*" + "magento/framework": "102.0.*", + "magento/module-url-rewrite": "101.1.*" }, "suggest": { - "magento/module-graph-ql": "*" + "magento/module-graph-ql": "100.3.*" }, - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -23,3 +24,4 @@ } } } + diff --git a/app/code/Magento/User/composer.json b/app/code/Magento/User/composer.json index 8ac1677bdfe81..d17e47a247a0e 100644 --- a/app/code/Magento/User/composer.json +++ b/app/code/Magento/User/composer.json @@ -1,24 +1,25 @@ { "name": "magento/module-user", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "101.1.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-authorization": "*", - "magento/module-backend": "*", - "magento/module-email": "*", - "magento/module-integration": "*", - "magento/module-security": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-authorization": "100.3.*", + "magento/module-backend": "101.0.*", + "magento/module-email": "101.0.*", + "magento/module-integration": "100.3.*", + "magento/module-security": "100.3.*", + "magento/module-store": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -28,3 +29,4 @@ } } } + diff --git a/app/code/Magento/Usps/composer.json b/app/code/Magento/Usps/composer.json index 3d5c0669c679d..74dad74bd5628 100644 --- a/app/code/Magento/Usps/composer.json +++ b/app/code/Magento/Usps/composer.json @@ -1,27 +1,28 @@ { "name": "magento/module-usps", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.6", "require": { "php": "~7.3.0||~7.4.0", "lib-libxml": "*", - "magento/framework": "*", - "magento/module-catalog": "*", - "magento/module-catalog-inventory": "*", - "magento/module-config": "*", - "magento/module-directory": "*", - "magento/module-quote": "*", - "magento/module-sales": "*", - "magento/module-shipping": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-catalog-inventory": "100.3.*", + "magento/module-config": "101.1.*", + "magento/module-directory": "100.3.*", + "magento/module-quote": "101.1.*", + "magento/module-sales": "102.0.*", + "magento/module-shipping": "100.3.*", + "magento/module-store": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -31,3 +32,4 @@ } } } + diff --git a/app/code/Magento/Variable/Model/Variable.php b/app/code/Magento/Variable/Model/Variable.php index ac4f45da5779b..2b2de32eafaec 100644 --- a/app/code/Magento/Variable/Model/Variable.php +++ b/app/code/Magento/Variable/Model/Variable.php @@ -5,6 +5,10 @@ */ namespace Magento\Variable\Model; +use Magento\Framework\Model\AbstractModel; +use Magento\Framework\Validator\HTML\WYSIWYGValidatorInterface; +use Magento\Framework\App\ObjectManager; + /** * Custom variable model * @@ -16,7 +20,7 @@ * @api * @since 100.0.2 */ -class Variable extends \Magento\Framework\Model\AbstractModel +class Variable extends AbstractModel { const TYPE_TEXT = 'text'; @@ -32,6 +36,11 @@ class Variable extends \Magento\Framework\Model\AbstractModel */ protected $_escaper = null; + /** + * @var WYSIWYGValidatorInterface + */ + private $wysiwygValidator; + /** * @param \Magento\Framework\Model\Context $context * @param \Magento\Framework\Registry $registry @@ -39,6 +48,7 @@ class Variable extends \Magento\Framework\Model\AbstractModel * @param \Magento\Variable\Model\ResourceModel\Variable $resource * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection * @param array $data + * @param WYSIWYGValidatorInterface|null $wysiwygValidator */ public function __construct( \Magento\Framework\Model\Context $context, @@ -46,10 +56,13 @@ public function __construct( \Magento\Framework\Escaper $escaper, \Magento\Variable\Model\ResourceModel\Variable $resource, \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null, - array $data = [] + array $data = [], + ?WYSIWYGValidatorInterface $wysiwygValidator = null ) { $this->_escaper = $escaper; parent::__construct($context, $registry, $resource, $resourceCollection, $data); + $this->wysiwygValidator = $wysiwygValidator + ?? ObjectManager::getInstance()->get(WYSIWYGValidatorInterface::class); } /** @@ -122,6 +135,21 @@ public function getValue($type = null) return $this->getData('html_value'); } + /** + * @inheritDoc + */ + public function beforeSave() + { + $html_field = $this->getValue(self::TYPE_HTML); + parent::beforeSave(); + + //Validating HTML content. + if ($html_field && $html_field !== $this->getOrigData('html_value')) { + $this->wysiwygValidator->validate($html_field); + } + return $this; + } + /** * Validation of object data. Checking for unique variable code * diff --git a/app/code/Magento/Variable/Test/Unit/Model/VariableTest.php b/app/code/Magento/Variable/Test/Unit/Model/VariableTest.php index 8d206225c4030..11f5f3e179da3 100644 --- a/app/code/Magento/Variable/Test/Unit/Model/VariableTest.php +++ b/app/code/Magento/Variable/Test/Unit/Model/VariableTest.php @@ -5,10 +5,18 @@ */ namespace Magento\Variable\Test\Unit\Model; +use Magento\Framework\Escaper; +use Magento\Framework\Phrase; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Variable\Model\ResourceModel\Variable; use Magento\Variable\Model\ResourceModel\Variable\Collection; +use Magento\Framework\Validator\HTML\WYSIWYGValidatorInterface; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\TestCase as TestCase; +use Magento\Framework\Validation\ValidationException; +use Throwable; -class VariableTest extends \PHPUnit\Framework\TestCase +class VariableTest extends TestCase { /** * @var \Magento\Variable\Model\Variable @@ -16,37 +24,43 @@ class VariableTest extends \PHPUnit\Framework\TestCase private $model; /** - * @var \Magento\Framework\Escaper|\PHPUnit\Framework\MockObject\MockObject + * @var Escaper|MockObject */ private $escaperMock; /** - * @var \Magento\Variable\Model\ResourceModel\Variable|\PHPUnit\Framework\MockObject\MockObject + * @var Variable|MockObject */ private $resourceMock; /** - * @var \Magento\Variable\Model\ResourceModel\Variable\Collection|\PHPUnit\Framework\MockObject\MockObject + * @var Collection|MockObject */ private $resourceCollectionMock; /** - * @var \Magento\Framework\Phrase + * @var Phrase */ private $validationFailedPhrase; /** - * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager + * @var ObjectManager */ private $objectManager; + /** + * @var WYSIWYGValidatorInterface + */ + private $wysiwygValidator; + protected function setUp(): void { + $this->wysiwygValidator = $this->createMock(WYSIWYGValidatorInterface::class); $this->objectManager = new ObjectManager($this); - $this->escaperMock = $this->getMockBuilder(\Magento\Framework\Escaper::class) + $this->escaperMock = $this->getMockBuilder(Escaper::class) ->disableOriginalConstructor() ->getMock(); - $this->resourceMock = $this->getMockBuilder(\Magento\Variable\Model\ResourceModel\Variable::class) + $this->resourceMock = $this->getMockBuilder(Variable::class) ->disableOriginalConstructor() ->getMock(); $this->resourceCollectionMock = $this->getMockBuilder(Collection::class) @@ -58,6 +72,7 @@ protected function setUp(): void 'escaper' => $this->escaperMock, 'resource' => $this->resourceMock, 'resourceCollection' => $this->resourceCollectionMock, + 'wysiwygValidator' => $this->wysiwygValidator ] ); $this->validationFailedPhrase = __('Validation has failed.'); @@ -188,4 +203,57 @@ public function validateMissingInfoDataProvider() 'Missing name' => ['some-code', ''], ]; } + + /** + * Test Variable validation. + * + * @param string $value + * @param bool $isChanged + * @param bool $isValidated + * @param bool $exceptionThrown + * @dataProvider getWysiwygValidationCases + */ + public function testBeforeSave(string $value, bool $isChanged, bool $isValidated, bool $exceptionThrown): void + { + $actuallyThrown = false; + + if (!$isValidated) { + $this->wysiwygValidator->expects($this->any()) + ->method('validate') + ->willThrowException(new ValidationException(__('HTML is invalid'))); + } else { + $this->wysiwygValidator->expects($this->any())->method('validate'); + } + + $this->model->setData('html_value', $value); + + if (!$isChanged) { + $this->model->setOrigData('html_value', $value); + } else { + $this->model->setOrigData('html_value', $value . '-OLD'); + } + + try { + $this->model->beforeSave(); + } catch (Throwable $exception) { + $actuallyThrown = true; + } + + $this->assertEquals($exceptionThrown, $actuallyThrown); + } + + /** + * Validation cases. + * + * @return array + */ + public function getWysiwygValidationCases(): array + { + return [ + 'changed-html-value-without-exception' => ['Test Html',true,true,false], + 'changed-html-value-with-exception' => ['Test Html',true,false,true], + 'no-changed-html-value-without-exception' => ['Test Html',false,false,false], + 'no-html-value-with-exception' => ['',true,false,false] + ]; + } } diff --git a/app/code/Magento/Variable/composer.json b/app/code/Magento/Variable/composer.json index e6eed40a814db..71f124f810f7c 100644 --- a/app/code/Magento/Variable/composer.json +++ b/app/code/Magento/Variable/composer.json @@ -1,22 +1,23 @@ { "name": "magento/module-variable", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.5-p2", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-store": "*", - "magento/module-config": "*", - "magento/module-ui": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-store": "101.0.*", + "magento/module-config": "101.1.*", + "magento/module-ui": "101.1.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -26,3 +27,4 @@ } } } + diff --git a/app/code/Magento/Vault/composer.json b/app/code/Magento/Vault/composer.json index 31d5ceb906246..b7e95d8601d67 100644 --- a/app/code/Magento/Vault/composer.json +++ b/app/code/Magento/Vault/composer.json @@ -1,25 +1,25 @@ { "name": "magento/module-vault", - "description": "", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "101.1.7-p2", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-checkout": "*", - "magento/module-customer": "*", - "magento/module-payment": "*", - "magento/module-quote": "*", - "magento/module-sales": "*", - "magento/module-store": "*", - "magento/module-theme": "*" + "magento/framework": "102.0.*", + "magento/module-checkout": "100.3.*", + "magento/module-customer": "102.0.*", + "magento/module-payment": "100.3.*", + "magento/module-quote": "101.1.*", + "magento/module-sales": "102.0.*", + "magento/module-store": "101.0.*", + "magento/module-theme": "101.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -29,3 +29,4 @@ } } } + diff --git a/app/code/Magento/VaultGraphQl/composer.json b/app/code/Magento/VaultGraphQl/composer.json index aff9a700fbcad..581ce3b39bbbe 100644 --- a/app/code/Magento/VaultGraphQl/composer.json +++ b/app/code/Magento/VaultGraphQl/composer.json @@ -2,16 +2,17 @@ "name": "magento/module-vault-graph-ql", "description": "N/A", "type": "magento2-module", - "require": { - "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-vault": "*", - "magento/module-graph-ql": "*" - }, "license": [ "OSL-3.0", "AFL-3.0" ], + "version": "100.3.3", + "require": { + "php": "~7.3.0||~7.4.0", + "magento/framework": "102.0.*", + "magento/module-vault": "101.1.*", + "magento/module-graph-ql": "100.3.*" + }, "autoload": { "files": [ "registration.php" @@ -21,3 +22,4 @@ } } } + diff --git a/app/code/Magento/Version/composer.json b/app/code/Magento/Version/composer.json index d2b2127446c21..5943bc6b0c82b 100644 --- a/app/code/Magento/Version/composer.json +++ b/app/code/Magento/Version/composer.json @@ -1,18 +1,19 @@ { "name": "magento/module-version", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.5", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*" + "magento/framework": "102.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -22,3 +23,4 @@ } } } + diff --git a/app/code/Magento/Webapi/Controller/Rest/InputParamsResolver.php b/app/code/Magento/Webapi/Controller/Rest/InputParamsResolver.php index 723e274d1e5fa..c9cc4e9791b67 100644 --- a/app/code/Magento/Webapi/Controller/Rest/InputParamsResolver.php +++ b/app/code/Magento/Webapi/Controller/Rest/InputParamsResolver.php @@ -6,12 +6,18 @@ namespace Magento\Webapi\Controller\Rest; +use Magento\Framework\Api\SimpleDataObjectConverter; +use Magento\Framework\App\ObjectManager; +use Magento\Framework\Reflection\MethodsMap; +use Magento\Framework\Webapi\Exception; use Magento\Framework\Webapi\ServiceInputProcessor; use Magento\Framework\Webapi\Rest\Request as RestRequest; use Magento\Webapi\Controller\Rest\Router\Route; /** * This class is responsible for retrieving resolved input data + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class InputParamsResolver { @@ -46,33 +52,40 @@ class InputParamsResolver private $requestValidator; /** - * Initialize dependencies - * + * @var MethodsMap + */ + private $methodsMap; + + /** * @param RestRequest $request * @param ParamsOverrider $paramsOverrider * @param ServiceInputProcessor $serviceInputProcessor * @param Router $router * @param RequestValidator $requestValidator + * @param MethodsMap|null $methodsMap */ public function __construct( RestRequest $request, ParamsOverrider $paramsOverrider, ServiceInputProcessor $serviceInputProcessor, Router $router, - RequestValidator $requestValidator + RequestValidator $requestValidator, + MethodsMap $methodsMap = null ) { $this->request = $request; $this->paramsOverrider = $paramsOverrider; $this->serviceInputProcessor = $serviceInputProcessor; $this->router = $router; $this->requestValidator = $requestValidator; + $this->methodsMap = $methodsMap ?: ObjectManager::getInstance() + ->get(MethodsMap::class); } /** * Process and resolve input parameters * * @return array - * @throws \Magento\Framework\Webapi\Exception + * @throws Exception */ public function resolve() { @@ -81,6 +94,7 @@ public function resolve() $serviceMethodName = $route->getServiceMethod(); $serviceClassName = $route->getServiceClass(); $inputData = $this->getInputData(); + return $this->serviceInputProcessor->process($serviceClassName, $serviceMethodName, $inputData); } @@ -108,6 +122,7 @@ public function getInputData() } else { $inputData = $this->request->getRequestData(); } + $this->validateParameters($serviceClassName, $serviceMethodName, array_keys($route->getParameters())); return $this->paramsOverrider->override($inputData, $route->getParameters()); } @@ -122,6 +137,46 @@ public function getRoute() if (!$this->route) { $this->route = $this->router->match($this->request); } + return $this->route; } + + /** + * Validate that parameters are really used in the current request. + * + * @param string $serviceClassName + * @param string $serviceMethodName + * @param array $paramOverriders + */ + private function validateParameters( + string $serviceClassName, + string $serviceMethodName, + array $paramOverriders + ): void { + $methodParams = $this->methodsMap->getMethodParams($serviceClassName, $serviceMethodName); + foreach ($paramOverriders as $key => $param) { + $arrayKeys = explode('.', $param); + $value = array_shift($arrayKeys); + + foreach ($methodParams as $serviceMethodParam) { + $serviceMethodParamName = $serviceMethodParam[MethodsMap::METHOD_META_NAME]; + $serviceMethodType = $serviceMethodParam[MethodsMap::METHOD_META_TYPE]; + + $camelCaseValue = SimpleDataObjectConverter::snakeCaseToCamelCase($value); + if ($serviceMethodParamName === $value || $serviceMethodParamName === $camelCaseValue) { + if (count($arrayKeys) > 0) { + $camelCaseKey = SimpleDataObjectConverter::snakeCaseToCamelCase('set_' . $arrayKeys[0]); + $this->validateParameters($serviceMethodType, $camelCaseKey, [implode('.', $arrayKeys)]); + } + unset($paramOverriders[$key]); + break; + } + } + } + if (!empty($paramOverriders)) { + throw new \UnexpectedValueException( + __('The current request does not expect the next parameters: ' . implode(', ', $paramOverriders)) + ); + } + } } diff --git a/app/code/Magento/Webapi/composer.json b/app/code/Magento/Webapi/composer.json index 11382cc318554..9014764152541 100644 --- a/app/code/Magento/Webapi/composer.json +++ b/app/code/Magento/Webapi/composer.json @@ -1,26 +1,27 @@ { "name": "magento/module-webapi", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.6-p2", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-authorization": "*", - "magento/module-backend": "*", - "magento/module-integration": "*", - "magento/module-store": "*" + "magento/framework": "102.0.*", + "magento/module-authorization": "100.3.*", + "magento/module-backend": "101.0.*", + "magento/module-integration": "100.3.*", + "magento/module-store": "101.0.*" }, "suggest": { - "magento/module-user": "*", - "magento/module-customer": "*" + "magento/module-user": "101.1.*", + "magento/module-customer": "102.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -30,3 +31,4 @@ } } } + diff --git a/app/code/Magento/WebapiAsync/composer.json b/app/code/Magento/WebapiAsync/composer.json index 73e3503da2123..00248e0452421 100644 --- a/app/code/Magento/WebapiAsync/composer.json +++ b/app/code/Magento/WebapiAsync/composer.json @@ -1,24 +1,25 @@ { "name": "magento/module-webapi-async", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-webapi": "*", - "magento/module-asynchronous-operations": "*" + "magento/framework": "102.0.*", + "magento/module-webapi": "100.3.*", + "magento/module-asynchronous-operations": "100.3.*" }, "suggest": { - "magento/module-user": "*", - "magento/module-customer": "*" + "magento/module-user": "101.1.*", + "magento/module-customer": "102.0.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -28,3 +29,4 @@ } } } + diff --git a/app/code/Magento/WebapiSecurity/composer.json b/app/code/Magento/WebapiSecurity/composer.json index 5b48ed8644709..cc8e430b7fabf 100644 --- a/app/code/Magento/WebapiSecurity/composer.json +++ b/app/code/Magento/WebapiSecurity/composer.json @@ -1,19 +1,20 @@ { "name": "magento/module-webapi-security", "description": "WebapiSecurity module provides option to loosen security on some webapi resources.", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.5", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-webapi": "*" + "magento/framework": "102.0.*", + "magento/module-webapi": "100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -23,3 +24,4 @@ } } } + diff --git a/app/code/Magento/Weee/composer.json b/app/code/Magento/Weee/composer.json index 7024de0f595c7..815287284817b 100644 --- a/app/code/Magento/Weee/composer.json +++ b/app/code/Magento/Weee/composer.json @@ -1,33 +1,34 @@ { "name": "magento/module-weee", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.6", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-checkout": "*", - "magento/module-customer": "*", - "magento/module-directory": "*", - "magento/module-eav": "*", - "magento/module-page-cache": "*", - "magento/module-quote": "*", - "magento/module-sales": "*", - "magento/module-store": "*", - "magento/module-tax": "*", - "magento/module-ui": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-checkout": "100.3.*", + "magento/module-customer": "102.0.*", + "magento/module-directory": "100.3.*", + "magento/module-eav": "102.0.*", + "magento/module-page-cache": "100.3.*", + "magento/module-quote": "101.1.*", + "magento/module-sales": "102.0.*", + "magento/module-store": "101.0.*", + "magento/module-tax": "100.3.*", + "magento/module-ui": "101.1.*" }, "suggest": { - "magento/module-bundle": "*" + "magento/module-bundle": "100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -37,3 +38,4 @@ } } } + diff --git a/app/code/Magento/WeeeGraphQl/composer.json b/app/code/Magento/WeeeGraphQl/composer.json index be7e50ab2fca1..a60ac08477fd6 100644 --- a/app/code/Magento/WeeeGraphQl/composer.json +++ b/app/code/Magento/WeeeGraphQl/composer.json @@ -2,20 +2,21 @@ "name": "magento/module-weee-graph-ql", "description": "N/A", "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "version": "100.3.5", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-store": "*", - "magento/module-tax": "*", - "magento/module-weee": "*" + "magento/framework": "102.0.*", + "magento/module-store": "101.0.*", + "magento/module-tax": "100.3.*", + "magento/module-weee": "100.3.*" }, "suggest": { - "magento/module-catalog-graph-ql": "*" + "magento/module-catalog-graph-ql": "100.3.*" }, - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -25,3 +26,4 @@ } } } + diff --git a/app/code/Magento/Widget/Model/Widget/Instance.php b/app/code/Magento/Widget/Model/Widget/Instance.php index f65c94abfd194..52f0fd9ba6f09 100644 --- a/app/code/Magento/Widget/Model/Widget/Instance.php +++ b/app/code/Magento/Widget/Model/Widget/Instance.php @@ -662,6 +662,7 @@ public function generateLayoutUpdateXml($container, $templatePath = '') } elseif (is_array($value)) { $value = implode(',', $value); } + $this->validateWidgetParameters($name); if ($name && strlen((string)$value)) { // phpcs:ignore Magento2.Functions.DiscouragedFunction $value = html_entity_decode($value); @@ -702,6 +703,23 @@ private function validateLayoutUpdateXml(string $xml): void } } + /** + * Check if widget parameter doesn't contains payload + * + * @param string $param + * @throws LocalizedException + */ + private function validateWidgetParameters(string $param): void + { + try { + if (!preg_match('/^\w+$/', $param)) { + throw new LocalizedException(__('Layout update is invalid')); + } + } catch (ValidationException|ValidationSchemaException $e) { + throw new LocalizedException(__('Layout update is invalid')); + } + } + /** * Invalidate related cache types * diff --git a/app/code/Magento/Widget/composer.json b/app/code/Magento/Widget/composer.json index 3f0f7fb212d4a..0df44990474d2 100644 --- a/app/code/Magento/Widget/composer.json +++ b/app/code/Magento/Widget/composer.json @@ -1,27 +1,28 @@ { "name": "magento/module-widget", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "101.1.5-p2", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-cms": "*", - "magento/module-store": "*", - "magento/module-theme": "*", - "magento/module-variable": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-cms": "103.0.*", + "magento/module-store": "101.0.*", + "magento/module-theme": "101.0.*", + "magento/module-variable": "100.3.*" }, "suggest": { - "magento/module-widget-sample-data": "*" + "magento/module-widget-sample-data": "Sample Data version: 100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -31,3 +32,4 @@ } } } + diff --git a/app/code/Magento/Wishlist/Controller/Shared/Allcart.php b/app/code/Magento/Wishlist/Controller/Shared/Allcart.php index 6300b14dcf515..2a4825fadcd26 100644 --- a/app/code/Magento/Wishlist/Controller/Shared/Allcart.php +++ b/app/code/Magento/Wishlist/Controller/Shared/Allcart.php @@ -3,13 +3,21 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + +declare(strict_types=1); + namespace Magento\Wishlist\Controller\Shared; +use Magento\Framework\App\Action\Action; use Magento\Framework\App\Action\Context; +use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\Wishlist\Model\ItemCarrier; use Magento\Framework\Controller\ResultFactory; -class Allcart extends \Magento\Framework\App\Action\Action +/** + * Wishlist Allcart Controller + */ +class Allcart extends Action implements HttpPostActionInterface { /** * @var WishlistProvider diff --git a/app/code/Magento/Wishlist/composer.json b/app/code/Magento/Wishlist/composer.json index b426ffe01cecc..00f3afc63bd8a 100644 --- a/app/code/Magento/Wishlist/composer.json +++ b/app/code/Magento/Wishlist/composer.json @@ -1,37 +1,38 @@ { "name": "magento/module-wishlist", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "101.1.7-p2", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-catalog": "*", - "magento/module-catalog-inventory": "*", - "magento/module-checkout": "*", - "magento/module-customer": "*", - "magento/module-rss": "*", - "magento/module-sales": "*", - "magento/module-store": "*", - "magento/module-theme": "*", - "magento/module-ui": "*", - "magento/module-captcha": "*" + "magento/framework": "102.0.*", + "magento/module-backend": "101.0.*", + "magento/module-catalog": "103.0.*", + "magento/module-catalog-inventory": "100.3.*", + "magento/module-checkout": "100.3.*", + "magento/module-customer": "102.0.*", + "magento/module-rss": "100.3.*", + "magento/module-sales": "102.0.*", + "magento/module-store": "101.0.*", + "magento/module-theme": "101.0.*", + "magento/module-ui": "101.1.*", + "magento/module-captcha": "100.3.*" }, "suggest": { - "magento/module-configurable-product": "*", - "magento/module-downloadable": "*", - "magento/module-bundle": "*", - "magento/module-cookie": "*", - "magento/module-grouped-product": "*", - "magento/module-wishlist-sample-data": "*" + "magento/module-configurable-product": "100.3.*", + "magento/module-downloadable": "100.3.*", + "magento/module-bundle": "100.3.*", + "magento/module-cookie": "100.3.*", + "magento/module-grouped-product": "100.3.*", + "magento/module-wishlist-sample-data": "Sample Data version: 100.3.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -41,3 +42,4 @@ } } } + diff --git a/app/code/Magento/WishlistAnalytics/composer.json b/app/code/Magento/WishlistAnalytics/composer.json index 309257f857ed2..ed03d31735d66 100644 --- a/app/code/Magento/WishlistAnalytics/composer.json +++ b/app/code/Magento/WishlistAnalytics/composer.json @@ -1,17 +1,18 @@ { "name": "magento/module-wishlist-analytics", "description": "N/A", - "require": { - "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-wishlist": "*", - "magento/module-analytics": "*" - }, "type": "magento2-module", "license": [ "OSL-3.0", "AFL-3.0" ], + "version": "100.3.5", + "require": { + "php": "~7.3.0||~7.4.0", + "magento/framework": "102.0.*", + "magento/module-wishlist": "101.1.*", + "magento/module-analytics": "100.3.*" + }, "autoload": { "files": [ "registration.php" @@ -21,3 +22,4 @@ } } } + diff --git a/app/code/Magento/WishlistGraphQl/composer.json b/app/code/Magento/WishlistGraphQl/composer.json index 7a3fca599a4b3..25e358fdd0a6c 100644 --- a/app/code/Magento/WishlistGraphQl/composer.json +++ b/app/code/Magento/WishlistGraphQl/composer.json @@ -2,17 +2,18 @@ "name": "magento/module-wishlist-graph-ql", "description": "N/A", "type": "magento2-module", - "require": { - "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/module-catalog-graph-ql": "*", - "magento/module-wishlist": "*", - "magento/module-store": "*" - }, "license": [ "OSL-3.0", "AFL-3.0" ], + "version": "100.3.4", + "require": { + "php": "~7.3.0||~7.4.0", + "magento/framework": "102.0.*", + "magento/module-catalog-graph-ql": "100.3.*", + "magento/module-wishlist": "101.1.*", + "magento/module-store": "101.0.*" + }, "autoload": { "files": [ "registration.php" @@ -22,3 +23,4 @@ } } } + diff --git a/app/design/adminhtml/Magento/backend/Magento_AdminAnalytics/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_AdminAnalytics/web/css/source/_module.less index 05c0653a9bac3..cb6991638fe56 100644 --- a/app/design/adminhtml/Magento/backend/Magento_AdminAnalytics/web/css/source/_module.less +++ b/app/design/adminhtml/Magento/backend/Magento_AdminAnalytics/web/css/source/_module.less @@ -29,6 +29,12 @@ } } + .modal-list { + margin-left: 0; + padding-left: 40px; + padding-top: 5px; + } + -webkit-transform: translateX(0); -webkit-transition: -webkit-transform 0s; transition: transform 0s; diff --git a/app/design/adminhtml/Magento/backend/composer.json b/app/design/adminhtml/Magento/backend/composer.json index 249441be1753e..f1cac8df6baf3 100644 --- a/app/design/adminhtml/Magento/backend/composer.json +++ b/app/design/adminhtml/Magento/backend/composer.json @@ -1,21 +1,23 @@ { "name": "magento/theme-adminhtml-backend", "description": "N/A", + "type": "magento2-theme", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.6-p2", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*" + "magento/framework": "102.0.*" }, - "type": "magento2-theme", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" ] } } + diff --git a/app/design/frontend/Magento/blank/composer.json b/app/design/frontend/Magento/blank/composer.json index 066d0cd1cc9f2..1e5b7838a1c77 100644 --- a/app/design/frontend/Magento/blank/composer.json +++ b/app/design/frontend/Magento/blank/composer.json @@ -1,21 +1,23 @@ { "name": "magento/theme-frontend-blank", "description": "N/A", + "type": "magento2-theme", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*" + "magento/framework": "102.0.*" }, - "type": "magento2-theme", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" ] } } + diff --git a/app/design/frontend/Magento/luma/composer.json b/app/design/frontend/Magento/luma/composer.json index 16bed43fe8cbf..9565a29dfb5bc 100644 --- a/app/design/frontend/Magento/luma/composer.json +++ b/app/design/frontend/Magento/luma/composer.json @@ -1,22 +1,24 @@ { "name": "magento/theme-frontend-luma", "description": "N/A", + "type": "magento2-theme", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.3.7", "require": { "php": "~7.3.0||~7.4.0", - "magento/framework": "*", - "magento/theme-frontend-blank": "*" + "magento/framework": "102.0.*", + "magento/theme-frontend-blank": "100.3.*" }, - "type": "magento2-theme", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" ] } } + diff --git a/app/etc/di.xml b/app/etc/di.xml index 5472ed2c5ad09..ace043beb6222 100644 --- a/app/etc/di.xml +++ b/app/etc/di.xml @@ -670,6 +670,9 @@ Magento\Framework\Data\OptionSourceInterface Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface + + Magento\Framework\Model\ResourceModel\AbstractResource + @@ -1743,6 +1746,11 @@ Magento\Framework\App\Config\ScopeConfigInterface::SCOPE_TYPE_DEFAULT + + + Magento\Framework\App\Config\ScopeConfigInterface::SCOPE_TYPE_DEFAULT + + @@ -1877,4 +1885,41 @@ + + + + + Magento\Framework\Webapi\Validator\EntityArrayValidator + Magento\Framework\Webapi\Validator\SearchCriteriaValidator + + + + + + 20 + + + + + 300 + + + + + + + Magento\Framework\GraphQl\Query\Resolver\Argument\Validator\SearchCriteriaValidator + + + + + + 300 + + + + + 20 + + diff --git a/app/i18n/Magento/de_DE/composer.json b/app/i18n/Magento/de_DE/composer.json index 5a488a3e32c2b..52ff460df2bcd 100644 --- a/app/i18n/Magento/de_DE/composer.json +++ b/app/i18n/Magento/de_DE/composer.json @@ -1,6 +1,7 @@ { "name": "magento/language-de_de", "description": "German (Germany) language", + "type": "magento2-language", "license": [ "OSL-3.0", "AFL-3.0" @@ -8,13 +9,14 @@ "config": { "sort-packages": true }, + "version": "100.3.4", "require": { - "magento/framework": "*" + "magento/framework": "102.0.*" }, - "type": "magento2-language", "autoload": { "files": [ "registration.php" ] } } + diff --git a/app/i18n/Magento/en_US/composer.json b/app/i18n/Magento/en_US/composer.json index 1108c70de28a6..c5a642da174d1 100644 --- a/app/i18n/Magento/en_US/composer.json +++ b/app/i18n/Magento/en_US/composer.json @@ -1,6 +1,7 @@ { "name": "magento/language-en_us", "description": "English (United States) language", + "type": "magento2-language", "license": [ "OSL-3.0", "AFL-3.0" @@ -8,13 +9,14 @@ "config": { "sort-packages": true }, + "version": "100.3.4", "require": { - "magento/framework": "*" + "magento/framework": "102.0.*" }, - "type": "magento2-language", "autoload": { "files": [ "registration.php" ] } } + diff --git a/app/i18n/Magento/es_ES/composer.json b/app/i18n/Magento/es_ES/composer.json index 5bc3cb5730adf..6b5ba3536482a 100644 --- a/app/i18n/Magento/es_ES/composer.json +++ b/app/i18n/Magento/es_ES/composer.json @@ -1,6 +1,7 @@ { "name": "magento/language-es_es", "description": "Spanish (Spain) language", + "type": "magento2-language", "license": [ "OSL-3.0", "AFL-3.0" @@ -8,13 +9,14 @@ "config": { "sort-packages": true }, + "version": "100.3.4", "require": { - "magento/framework": "*" + "magento/framework": "102.0.*" }, - "type": "magento2-language", "autoload": { "files": [ "registration.php" ] } } + diff --git a/app/i18n/Magento/fr_FR/composer.json b/app/i18n/Magento/fr_FR/composer.json index 50c541308673b..1577e52b72ada 100644 --- a/app/i18n/Magento/fr_FR/composer.json +++ b/app/i18n/Magento/fr_FR/composer.json @@ -1,6 +1,7 @@ { "name": "magento/language-fr_fr", "description": "French (France) language", + "type": "magento2-language", "license": [ "OSL-3.0", "AFL-3.0" @@ -8,13 +9,14 @@ "config": { "sort-packages": true }, + "version": "100.3.4", "require": { - "magento/framework": "*" + "magento/framework": "102.0.*" }, - "type": "magento2-language", "autoload": { "files": [ "registration.php" ] } } + diff --git a/app/i18n/Magento/nl_NL/composer.json b/app/i18n/Magento/nl_NL/composer.json index a182e179d4103..73ecfa783f470 100644 --- a/app/i18n/Magento/nl_NL/composer.json +++ b/app/i18n/Magento/nl_NL/composer.json @@ -1,6 +1,7 @@ { "name": "magento/language-nl_nl", "description": "Dutch (Netherlands) language", + "type": "magento2-language", "license": [ "OSL-3.0", "AFL-3.0" @@ -8,13 +9,14 @@ "config": { "sort-packages": true }, + "version": "100.3.4", "require": { - "magento/framework": "*" + "magento/framework": "102.0.*" }, - "type": "magento2-language", "autoload": { "files": [ "registration.php" ] } } + diff --git a/app/i18n/Magento/pt_BR/composer.json b/app/i18n/Magento/pt_BR/composer.json index 46734cc09b363..6a9653c2bdbfd 100644 --- a/app/i18n/Magento/pt_BR/composer.json +++ b/app/i18n/Magento/pt_BR/composer.json @@ -1,6 +1,7 @@ { "name": "magento/language-pt_br", "description": "Portuguese (Brazil) language", + "type": "magento2-language", "license": [ "OSL-3.0", "AFL-3.0" @@ -8,13 +9,14 @@ "config": { "sort-packages": true }, + "version": "100.3.4", "require": { - "magento/framework": "*" + "magento/framework": "102.0.*" }, - "type": "magento2-language", "autoload": { "files": [ "registration.php" ] } } + diff --git a/app/i18n/Magento/zh_Hans_CN/composer.json b/app/i18n/Magento/zh_Hans_CN/composer.json index ce214ce649f56..ecfd5cdcccb14 100644 --- a/app/i18n/Magento/zh_Hans_CN/composer.json +++ b/app/i18n/Magento/zh_Hans_CN/composer.json @@ -1,6 +1,7 @@ { "name": "magento/language-zh_hans_cn", "description": "Chinese (China) language", + "type": "magento2-language", "license": [ "OSL-3.0", "AFL-3.0" @@ -8,13 +9,14 @@ "config": { "sort-packages": true }, + "version": "100.3.4", "require": { - "magento/framework": "*" + "magento/framework": "102.0.*" }, - "type": "magento2-language", "autoload": { "files": [ "registration.php" ] } } + diff --git a/composer.json b/composer.json index aebe7a5a94882..ed2c9120e2552 100644 --- a/composer.json +++ b/composer.json @@ -10,6 +10,7 @@ "preferred-install": "dist", "sort-packages": true }, + "version": "2.3.7-p2", "require": { "php": "~7.3.0||~7.4.0", "ext-bcmath": "*", @@ -45,6 +46,7 @@ "laminas/laminas-dependency-plugin": "^1.0 || ^2.0", "laminas/laminas-di": "^2.6.1", "laminas/laminas-eventmanager": "^3.0.0", + "laminas/laminas-escaper": "2.7.0", "laminas/laminas-feed": "^2.9.0", "laminas/laminas-form": "^2.10.0", "laminas/laminas-http": "^2.6.0", @@ -83,6 +85,31 @@ "webonyx/graphql-php": "^0.13.8", "wikimedia/less.php": "~1.8.0" }, + "suggest": { + "ext-pcntl": "Need for run processes in parallel mode" + }, + "autoload": { + "exclude-from-classmap": [ + "**/dev/**", + "**/update/**", + "**/Test/**" + ], + "files": [ + "app/etc/NonComposerComponentRegistration.php" + ], + "psr-0": { + "": [ + "app/code/", + "generated/code/" + ] + }, + "psr-4": { + "Magento\\": "app/code/Magento/", + "Magento\\Framework\\": "lib/internal/Magento/Framework/", + "Magento\\Setup\\": "setup/src/Magento/Setup/", + "Zend\\Mvc\\Controller\\": "setup/src/Zend/Mvc/Controller/" + } + }, "require-dev": { "allure-framework/allure-phpunit": "~1.2.0", "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", @@ -98,256 +125,232 @@ "sebastian/phpcpd": "~5.0.0", "squizlabs/php_codesniffer": "~3.5.4" }, - "suggest": { - "ext-pcntl": "Need for run processes in parallel mode" + "conflict": { + "gene/bluefoot": "*" }, "replace": { - "magento/module-marketplace": "*", - "magento/module-admin-analytics": "*", - "magento/module-admin-notification": "*", - "magento/module-advanced-pricing-import-export": "*", - "magento/module-amqp": "*", - "magento/module-amqp-store": "*", - "magento/module-analytics": "*", - "magento/module-asynchronous-operations": "*", - "magento/module-authorization": "*", - "magento/module-authorizenet": "*", - "magento/module-authorizenet-acceptjs": "*", - "magento/module-authorizenet-cardinal": "*", - "magento/module-authorizenet-graph-ql": "*", - "magento/module-advanced-search": "*", - "magento/module-backend": "*", - "magento/module-backup": "*", - "magento/module-braintree": "*", - "magento/module-braintree-graph-ql": "*", - "magento/module-bundle": "*", - "magento/module-bundle-graph-ql": "*", - "magento/module-bundle-import-export": "*", - "magento/module-cache-invalidate": "*", - "magento/module-captcha": "*", - "magento/module-cardinal-commerce": "*", - "magento/module-catalog": "*", - "magento/module-catalog-customer-graph-ql": "*", - "magento/module-catalog-analytics": "*", - "magento/module-catalog-import-export": "*", - "magento/module-catalog-inventory": "*", - "magento/module-catalog-inventory-graph-ql": "*", - "magento/module-catalog-rule": "*", - "magento/module-catalog-rule-graph-ql": "*", - "magento/module-catalog-rule-configurable": "*", - "magento/module-catalog-search": "*", - "magento/module-catalog-url-rewrite": "*", - "magento/module-catalog-widget": "*", - "magento/module-checkout": "*", - "magento/module-checkout-agreements": "*", - "magento/module-checkout-agreements-graph-ql": "*", - "magento/module-cms": "*", - "magento/module-cms-url-rewrite": "*", - "magento/module-config": "*", - "magento/module-configurable-import-export": "*", - "magento/module-configurable-product": "*", - "magento/module-configurable-product-sales": "*", - "magento/module-contact": "*", - "magento/module-cookie": "*", - "magento/module-cron": "*", - "magento/module-currency-symbol": "*", - "magento/module-customer": "*", - "magento/module-customer-analytics": "*", - "magento/module-customer-downloadable-graph-ql": "*", - "magento/module-customer-import-export": "*", - "magento/module-deploy": "*", - "magento/module-developer": "*", - "magento/module-dhl": "*", - "magento/module-directory": "*", - "magento/module-directory-graph-ql": "*", - "magento/module-downloadable": "*", - "magento/module-downloadable-graph-ql": "*", - "magento/module-downloadable-import-export": "*", - "magento/module-eav": "*", - "magento/module-elasticsearch": "*", - "magento/module-elasticsearch-6": "*", - "magento/module-elasticsearch-7": "*", - "magento/module-email": "*", - "magento/module-encryption-key": "*", - "magento/module-fedex": "*", - "magento/module-gift-message": "*", - "magento/module-google-adwords": "*", - "magento/module-google-analytics": "*", - "magento/module-google-optimizer": "*", - "magento/module-graph-ql": "*", - "magento/module-graph-ql-cache": "*", - "magento/module-catalog-graph-ql": "*", - "magento/module-catalog-cms-graph-ql": "*", - "magento/module-catalog-url-rewrite-graph-ql": "*", - "magento/module-configurable-product-graph-ql": "*", - "magento/module-customer-graph-ql": "*", - "magento/module-eav-graph-ql": "*", - "magento/module-swatches-graph-ql": "*", - "magento/module-tax-graph-ql": "*", - "magento/module-url-rewrite-graph-ql": "*", - "magento/module-cms-url-rewrite-graph-ql": "*", - "magento/module-weee-graph-ql": "*", - "magento/module-cms-graph-ql": "*", - "magento/module-grouped-import-export": "*", - "magento/module-grouped-product": "*", - "magento/module-grouped-catalog-inventory": "*", - "magento/module-grouped-product-graph-ql": "*", - "magento/module-import-export": "*", - "magento/module-indexer": "*", - "magento/module-instant-purchase": "*", - "magento/module-integration": "*", - "magento/module-layered-navigation": "*", - "magento/module-media-gallery": "*", - "magento/module-media-gallery-api": "*", - "magento/module-media-storage": "*", - "magento/module-message-queue": "*", - "magento/module-msrp": "*", - "magento/module-msrp-configurable-product": "*", - "magento/module-msrp-grouped-product": "*", - "magento/module-multishipping": "*", - "magento/module-mysql-mq": "*", - "magento/module-new-relic-reporting": "*", - "magento/module-newsletter": "*", - "magento/module-offline-payments": "*", - "magento/module-offline-shipping": "*", - "magento/module-page-cache": "*", - "magento/module-payment": "*", - "magento/module-paypal": "*", - "magento/module-paypal-captcha": "*", - "magento/module-paypal-graph-ql": "*", - "magento/module-persistent": "*", - "magento/module-product-alert": "*", - "magento/module-product-video": "*", - "magento/module-quote": "*", - "magento/module-quote-analytics": "*", - "magento/module-quote-graph-ql": "*", - "magento/module-related-product-graph-ql": "*", - "magento/module-release-notification": "*", - "magento/module-reports": "*", - "magento/module-require-js": "*", - "magento/module-review": "*", - "magento/module-review-analytics": "*", - "magento/module-robots": "*", - "magento/module-rss": "*", - "magento/module-rule": "*", - "magento/module-sales": "*", - "magento/module-sales-analytics": "*", - "magento/module-sales-graph-ql": "*", - "magento/module-sales-inventory": "*", - "magento/module-sales-rule": "*", - "magento/module-sales-sequence": "*", - "magento/module-sample-data": "*", - "magento/module-search": "*", - "magento/module-security": "*", - "magento/module-send-friend": "*", - "magento/module-send-friend-graph-ql": "*", - "magento/module-shipping": "*", - "magento/module-signifyd": "*", - "magento/module-sitemap": "*", - "magento/module-store": "*", - "magento/module-store-graph-ql": "*", - "magento/module-swagger": "*", - "magento/module-swagger-webapi": "*", - "magento/module-swagger-webapi-async": "*", - "magento/module-swatches": "*", - "magento/module-swatches-layered-navigation": "*", - "magento/module-tax": "*", - "magento/module-tax-import-export": "*", - "magento/module-theme": "*", - "magento/module-theme-graph-ql": "*", - "magento/module-translation": "*", - "magento/module-ui": "*", - "magento/module-ups": "*", - "magento/module-url-rewrite": "*", - "magento/module-user": "*", - "magento/module-usps": "*", - "magento/module-variable": "*", - "magento/module-vault": "*", - "magento/module-vault-graph-ql": "*", - "magento/module-version": "*", - "magento/module-webapi": "*", - "magento/module-webapi-async": "*", - "magento/module-webapi-security": "*", - "magento/module-weee": "*", - "magento/module-widget": "*", - "magento/module-wishlist": "*", - "magento/module-wishlist-graph-ql": "*", - "magento/module-wishlist-analytics": "*", - "magento/theme-adminhtml-backend": "*", - "magento/theme-frontend-blank": "*", - "magento/theme-frontend-luma": "*", - "magento/language-de_de": "*", - "magento/language-en_us": "*", - "magento/language-es_es": "*", - "magento/language-fr_fr": "*", - "magento/language-nl_nl": "*", - "magento/language-pt_br": "*", - "magento/language-zh_hans_cn": "*", - "magento/framework": "*", - "magento/framework-amqp": "*", - "magento/framework-bulk": "*", - "magento/framework-message-queue": "*", + "magento/module-marketplace": "100.3.5", + "magento/module-admin-analytics": "100.3.3-p2", + "magento/module-admin-notification": "100.3.6", + "magento/module-advanced-pricing-import-export": "100.3.5", + "magento/module-amqp": "100.3.5", + "magento/module-amqp-store": "100.3.2", + "magento/module-analytics": "100.3.7", + "magento/module-asynchronous-operations": "100.3.7", + "magento/module-authorization": "100.3.6", + "magento/module-authorizenet": "100.3.6", + "magento/module-authorizenet-acceptjs": "100.3.5", + "magento/module-authorizenet-cardinal": "100.3.2", + "magento/module-authorizenet-graph-ql": "100.3.3", + "magento/module-advanced-search": "100.3.5", + "magento/module-backend": "101.0.7", + "magento/module-backup": "100.3.6-p2", + "magento/module-braintree": "100.3.7-p2", + "magento/module-braintree-graph-ql": "100.3.4", + "magento/module-bundle": "100.3.7", + "magento/module-bundle-graph-ql": "100.3.5", + "magento/module-bundle-import-export": "100.3.6", + "magento/module-cache-invalidate": "100.3.5", + "magento/module-captcha": "100.3.7", + "magento/module-cardinal-commerce": "100.3.3", + "magento/module-catalog": "103.0.7-p2", + "magento/module-catalog-customer-graph-ql": "100.3.1", + "magento/module-catalog-analytics": "100.3.5", + "magento/module-catalog-import-export": "101.0.7", + "magento/module-catalog-inventory": "100.3.7-p2", + "magento/module-catalog-inventory-graph-ql": "100.3.5", + "magento/module-catalog-rule": "101.1.7", + "magento/module-catalog-rule-graph-ql": "100.3.1", + "magento/module-catalog-rule-configurable": "100.3.6", + "magento/module-catalog-search": "101.0.7", + "magento/module-catalog-url-rewrite": "100.3.7", + "magento/module-catalog-widget": "100.3.7", + "magento/module-checkout": "100.3.7", + "magento/module-checkout-agreements": "100.3.6", + "magento/module-checkout-agreements-graph-ql": "100.3.2", + "magento/module-cms": "103.0.7-p2", + "magento/module-cms-url-rewrite": "100.3.6", + "magento/module-config": "101.1.7", + "magento/module-configurable-import-export": "100.3.5", + "magento/module-configurable-product": "100.3.7-p2", + "magento/module-configurable-product-sales": "100.3.5", + "magento/module-contact": "100.3.7", + "magento/module-cookie": "100.3.6", + "magento/module-cron": "100.3.6", + "magento/module-currency-symbol": "100.3.6", + "magento/module-customer": "102.0.7-p2", + "magento/module-customer-analytics": "100.3.5", + "magento/module-customer-downloadable-graph-ql": "100.3.1", + "magento/module-customer-import-export": "100.3.7", + "magento/module-deploy": "100.3.6", + "magento/module-developer": "100.3.6", + "magento/module-dhl": "100.3.6", + "magento/module-directory": "100.3.7", + "magento/module-directory-graph-ql": "100.3.4", + "magento/module-downloadable": "100.3.7", + "magento/module-downloadable-graph-ql": "100.3.5", + "magento/module-downloadable-import-export": "100.3.7", + "magento/module-eav": "102.0.7", + "magento/module-elasticsearch": "100.3.7", + "magento/module-elasticsearch-6": "100.3.6", + "magento/module-elasticsearch-7": "100.3.2", + "magento/module-email": "101.0.7", + "magento/module-encryption-key": "100.3.6", + "magento/module-fedex": "100.3.6", + "magento/module-gift-message": "100.3.5", + "magento/module-google-adwords": "100.3.6", + "magento/module-google-analytics": "100.3.5", + "magento/module-google-optimizer": "100.3.6", + "magento/module-graph-ql": "100.3.6", + "magento/module-graph-ql-cache": "100.3.3", + "magento/module-catalog-graph-ql": "100.3.7", + "magento/module-catalog-cms-graph-ql": "100.3.1", + "magento/module-catalog-url-rewrite-graph-ql": "100.3.6", + "magento/module-configurable-product-graph-ql": "100.3.6", + "magento/module-customer-graph-ql": "100.3.6", + "magento/module-eav-graph-ql": "100.3.5", + "magento/module-swatches-graph-ql": "100.3.6", + "magento/module-tax-graph-ql": "100.3.5", + "magento/module-url-rewrite-graph-ql": "100.3.7", + "magento/module-cms-url-rewrite-graph-ql": "100.3.5", + "magento/module-weee-graph-ql": "100.3.5", + "magento/module-cms-graph-ql": "100.3.5", + "magento/module-grouped-import-export": "100.3.5", + "magento/module-grouped-product": "100.3.7", + "magento/module-grouped-catalog-inventory": "100.3.4", + "magento/module-grouped-product-graph-ql": "100.3.6", + "magento/module-import-export": "100.3.7", + "magento/module-indexer": "100.3.7", + "magento/module-instant-purchase": "100.3.7", + "magento/module-integration": "100.3.6", + "magento/module-layered-navigation": "100.3.5", + "magento/module-media-gallery": "100.3.2", + "magento/module-media-gallery-api": "100.3.1", + "magento/module-media-storage": "100.3.7-p2", + "magento/module-message-queue": "100.3.7", + "magento/module-msrp": "100.3.6", + "magento/module-msrp-configurable-product": "100.3.4", + "magento/module-msrp-grouped-product": "100.3.5", + "magento/module-multishipping": "100.3.7-p2", + "magento/module-mysql-mq": "100.3.5", + "magento/module-new-relic-reporting": "100.3.5", + "magento/module-newsletter": "100.3.7", + "magento/module-offline-payments": "100.3.5", + "magento/module-offline-shipping": "100.3.6", + "magento/module-page-cache": "100.3.7", + "magento/module-payment": "100.3.7", + "magento/module-paypal": "100.3.7-p2", + "magento/module-paypal-captcha": "100.3.3", + "magento/module-paypal-graph-ql": "100.3.2", + "magento/module-persistent": "100.3.7", + "magento/module-product-alert": "100.3.7", + "magento/module-product-video": "100.3.7", + "magento/module-quote": "101.1.7-p2", + "magento/module-quote-analytics": "100.3.6", + "magento/module-quote-graph-ql": "100.3.7-p2", + "magento/module-related-product-graph-ql": "100.3.2", + "magento/module-release-notification": "100.3.5", + "magento/module-reports": "100.3.7", + "magento/module-require-js": "100.3.5", + "magento/module-review": "100.3.7", + "magento/module-review-analytics": "100.3.5", + "magento/module-robots": "101.0.5", + "magento/module-rss": "100.3.5", + "magento/module-rule": "100.3.6", + "magento/module-sales": "102.0.7-p2", + "magento/module-sales-analytics": "100.3.5", + "magento/module-sales-graph-ql": "100.3.4", + "magento/module-sales-inventory": "100.3.5", + "magento/module-sales-rule": "101.1.7", + "magento/module-sales-sequence": "100.3.5", + "magento/module-sample-data": "100.3.5", + "magento/module-search": "101.0.7", + "magento/module-security": "100.3.6-p2", + "magento/module-send-friend": "100.3.5", + "magento/module-send-friend-graph-ql": "100.3.4", + "magento/module-shipping": "100.3.7", + "magento/module-signifyd": "100.3.6", + "magento/module-sitemap": "100.3.7", + "magento/module-store": "101.0.7-p2", + "magento/module-store-graph-ql": "100.3.5", + "magento/module-swagger": "100.3.6", + "magento/module-swagger-webapi": "100.3.5", + "magento/module-swagger-webapi-async": "100.3.5", + "magento/module-swatches": "100.3.7", + "magento/module-swatches-layered-navigation": "100.3.5", + "magento/module-tax": "100.3.7", + "magento/module-tax-import-export": "100.3.5", + "magento/module-theme": "101.0.7-p2", + "magento/module-theme-graph-ql": "100.3.4", + "magento/module-translation": "100.3.7", + "magento/module-ui": "101.1.7", + "magento/module-ups": "100.3.7", + "magento/module-url-rewrite": "101.1.6", + "magento/module-user": "101.1.7", + "magento/module-usps": "100.3.6", + "magento/module-variable": "100.3.5-p2", + "magento/module-vault": "101.1.7-p2", + "magento/module-vault-graph-ql": "100.3.3", + "magento/module-version": "100.3.5", + "magento/module-webapi": "100.3.6-p2", + "magento/module-webapi-async": "100.3.7", + "magento/module-webapi-security": "100.3.5", + "magento/module-weee": "100.3.6", + "magento/module-widget": "101.1.5-p2", + "magento/module-wishlist": "101.1.7-p2", + "magento/module-wishlist-graph-ql": "100.3.4", + "magento/module-wishlist-analytics": "100.3.5", + "magento/theme-adminhtml-backend": "100.3.6-p2", + "magento/theme-frontend-blank": "100.3.7", + "magento/theme-frontend-luma": "100.3.7", + "magento/language-de_de": "100.3.4", + "magento/language-en_us": "100.3.4", + "magento/language-es_es": "100.3.4", + "magento/language-fr_fr": "100.3.4", + "magento/language-nl_nl": "100.3.4", + "magento/language-pt_br": "100.3.4", + "magento/language-zh_hans_cn": "100.3.4", + "magento/framework": "102.0.7-p2", + "magento/framework-amqp": "100.3.6", + "magento/framework-bulk": "100.3.6", + "magento/framework-message-queue": "100.3.7", "trentrichardson/jquery-timepicker-addon": "1.4.3", "components/jquery": "1.11.0", "blueimp/jquery-file-upload": "5.6.14", "components/jqueryui": "1.10.4", "twbs/bootstrap": "3.1.0", "tinymce/tinymce": "3.4.7", - "magento/module-tinymce-3": "*", - "magento/module-csp": "*" + "magento/module-tinymce-3": "100.3.7", + "magento/module-csp": "100.3.1-p2" }, - "conflict": { - "gene/bluefoot": "*" + "autoload-dev": { + "psr-4": { + "Magento\\PhpStan\\": "dev/tests/static/framework/Magento/PhpStan/", + "Magento\\Sniffs\\": "dev/tests/static/framework/Magento/Sniffs/", + "Magento\\TestFramework\\Inspection\\": "dev/tests/static/framework/Magento/TestFramework/Inspection/", + "Magento\\TestFramework\\Utility\\": "dev/tests/static/framework/Magento/TestFramework/Utility/", + "Magento\\Tools\\": "dev/tools/Magento/Tools/", + "Magento\\Tools\\Sanity\\": "dev/build/publication/sanity/Magento/Tools/Sanity/" + } }, + "prefer-stable": true, "extra": { "component_paths": { - "trentrichardson/jquery-timepicker-addon": "lib/web/jquery/jquery-ui-timepicker-addon.js", + "blueimp/jquery-file-upload": "lib/web/jquery/fileUploader", "components/jquery": [ "lib/web/jquery.js", "lib/web/jquery/jquery.min.js", "lib/web/jquery/jquery-migrate.js" ], - "blueimp/jquery-file-upload": "lib/web/jquery/fileUploader", "components/jqueryui": [ "lib/web/jquery/jquery-ui.js" ], + "tinymce/tinymce": "lib/web/tiny_mce_4", + "trentrichardson/jquery-timepicker-addon": "lib/web/jquery/jquery-ui-timepicker-addon.js", "twbs/bootstrap": [ "lib/web/jquery/jquery.tabs.js" - ], - "tinymce/tinymce": "lib/web/tiny_mce_4" - } - }, - "autoload": { - "psr-4": { - "Magento\\Framework\\": "lib/internal/Magento/Framework/", - "Magento\\Setup\\": "setup/src/Magento/Setup/", - "Magento\\": "app/code/Magento/", - "Zend\\Mvc\\Controller\\": "setup/src/Zend/Mvc/Controller/" - }, - "psr-0": { - "": [ - "app/code/", - "generated/code/" ] - }, - "files": [ - "app/etc/NonComposerComponentRegistration.php" - ], - "exclude-from-classmap": [ - "**/dev/**", - "**/update/**", - "**/Test/**" - ] - }, - "autoload-dev": { - "psr-4": { - "Magento\\Sniffs\\": "dev/tests/static/framework/Magento/Sniffs/", - "Magento\\Tools\\": "dev/tools/Magento/Tools/", - "Magento\\Tools\\Sanity\\": "dev/build/publication/sanity/Magento/Tools/Sanity/", - "Magento\\TestFramework\\Inspection\\": "dev/tests/static/framework/Magento/TestFramework/Inspection/", - "Magento\\TestFramework\\Utility\\": "dev/tests/static/framework/Magento/TestFramework/Utility/", - "Magento\\PhpStan\\": "dev/tests/static/framework/Magento/PhpStan/" } - }, - "prefer-stable": true + } } + diff --git a/composer.lock b/composer.lock index d9c525f9069f6..eba8c68454dd4 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "59fe6c18be4dc5e34be8c682e91f903b", + "content-hash": "027c857a7c93c3b61d5a516b4e1fe679", "packages": [ { "name": "braintree/braintree_php", @@ -6521,12 +6521,12 @@ "version": "1.1.8", "source": { "type": "git", - "url": "https://github.com/allure-framework/allure-php-commons.git", + "url": "https://github.com/allure-framework/allure-php-api.git", "reference": "5ae2deac1c7e1b992cfa572167370de45bdd346d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/allure-framework/allure-php-commons/zipball/5ae2deac1c7e1b992cfa572167370de45bdd346d", + "url": "https://api.github.com/repos/allure-framework/allure-php-api/zipball/5ae2deac1c7e1b992cfa572167370de45bdd346d", "reference": "5ae2deac1c7e1b992cfa572167370de45bdd346d", "shasum": "" }, @@ -6569,7 +6569,7 @@ ], "support": { "email": "allure@yandex-team.ru", - "issues": "https://github.com/allure-framework/allure-php-commons/issues", + "issues": "https://github.com/allure-framework/allure-php-api/issues", "source": "https://github.com/allure-framework/allure-php-api" }, "time": "2020-03-13T10:47:35+00:00" @@ -8479,16 +8479,16 @@ }, { "name": "magento/magento2-functional-testing-framework", - "version": "2.7.0", + "version": "2.7.1", "source": { "type": "git", "url": "https://github.com/magento/magento2-functional-testing-framework.git", - "reference": "690619fee29238cc87dca7a81413ce2fa7ecd161" + "reference": "4802c6779855c326ffddc9db250b6c4404b1d02d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/magento/magento2-functional-testing-framework/zipball/690619fee29238cc87dca7a81413ce2fa7ecd161", - "reference": "690619fee29238cc87dca7a81413ce2fa7ecd161", + "url": "https://api.github.com/repos/magento/magento2-functional-testing-framework/zipball/4802c6779855c326ffddc9db250b6c4404b1d02d", + "reference": "4802c6779855c326ffddc9db250b6c4404b1d02d", "shasum": "" }, "require": { @@ -8569,9 +8569,9 @@ ], "support": { "issues": "https://github.com/magento/magento2-functional-testing-framework/issues", - "source": "https://github.com/magento/magento2-functional-testing-framework/tree/2.7.0" + "source": "https://github.com/magento/magento2-functional-testing-framework/tree/2.7.1" }, - "time": "2021-02-24T20:38:08+00:00" + "time": "2021-03-30T19:49:22+00:00" }, { "name": "mikey179/vfsstream", @@ -12107,5 +12107,5 @@ "lib-libxml": "*" }, "platform-dev": [], - "plugin-api-version": "2.0.0" + "plugin-api-version": "2.1.0" } diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/etc/webapi.xml b/dev/tests/api-functional/_files/Magento/TestModule1/etc/webapi.xml index 9a705f6aca373..5943b7a5ab1ee 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule1/etc/webapi.xml +++ b/dev/tests/api-functional/_files/Magento/TestModule1/etc/webapi.xml @@ -72,6 +72,16 @@ + + + + + + + + %param_id% + + diff --git a/dev/tests/api-functional/testsuite/Magento/AsynchronousOperations/Api/OperationRepositoryInterfaceTest.php b/dev/tests/api-functional/testsuite/Magento/AsynchronousOperations/Api/OperationRepositoryInterfaceTest.php index 0e8cdb6ef37ef..354e8fb5f58bb 100644 --- a/dev/tests/api-functional/testsuite/Magento/AsynchronousOperations/Api/OperationRepositoryInterfaceTest.php +++ b/dev/tests/api-functional/testsuite/Magento/AsynchronousOperations/Api/OperationRepositoryInterfaceTest.php @@ -36,6 +36,7 @@ public function testGetListByBulkStartTime() ], ], 'current_page' => 1, + 'page_size' => 20, ], ]; @@ -93,6 +94,7 @@ public function testGetList() ], ], 'current_page' => 1, + 'page_size' => 20, ], ]; diff --git a/dev/tests/api-functional/testsuite/Magento/Customer/Api/AccountManagementCustomAttributesTest.php b/dev/tests/api-functional/testsuite/Magento/Customer/Api/AccountManagementCustomAttributesTest.php index bb236f5577d50..8387ca32004e9 100644 --- a/dev/tests/api-functional/testsuite/Magento/Customer/Api/AccountManagementCustomAttributesTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Customer/Api/AccountManagementCustomAttributesTest.php @@ -3,17 +3,21 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + +declare(strict_types=1); + namespace Magento\Customer\Api; use Magento\Customer\Api\Data\CustomerInterface; -use Magento\Customer\Model\AccountManagement; use Magento\Framework\Api\AttributeValue; use Magento\Framework\Api\CustomAttributesDataInterface; use Magento\Framework\App\Filesystem\DirectoryList; +use Magento\Framework\Filesystem\Directory\DenyListPathValidator; +use Magento\Framework\Filesystem\Directory\WriteFactory; +use Magento\Framework\Webapi\Exception as HTTPExceptionCodes; use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\Helper\Customer as CustomerHelper; use Magento\TestFramework\TestCase\WebapiAbstract; -use Magento\Framework\Webapi\Exception as HTTPExceptionCodes; /** * Test class for Customer's custom attributes @@ -104,8 +108,16 @@ protected function tearDown(): void } } $this->accountManagement = null; - $mediaDirectory = $this->fileSystem->getDirectoryWrite(DirectoryList::MEDIA); - $mediaDirectory->delete(CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER); + $writeFactory = Bootstrap::getObjectManager() + ->get(WriteFactory::class); + $mediaDirectory = $writeFactory->create(DirectoryList::MEDIA); + $denyListPathValidator = Bootstrap::getObjectManager() + ->create(DenyListPathValidator::class, ['driver' => $mediaDirectory->getDriver()]); + $denyListPathValidator->addException($mediaDirectory->getAbsolutePath() . ".htaccess"); + $writeFactoryBypassDenyList = Bootstrap::getObjectManager() + ->create(WriteFactory::class, ['denyListPathValidator' => $denyListPathValidator]); + $mediaDirectoryBypassDenyList = $writeFactoryBypassDenyList->create(DirectoryList::MEDIA); + $mediaDirectoryBypassDenyList->delete(CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER); } /** diff --git a/dev/tests/api-functional/testsuite/Magento/Framework/Api/Search/SearchTest.php b/dev/tests/api-functional/testsuite/Magento/Framework/Api/Search/SearchTest.php index e6bc36684ed80..6caff4bfad296 100644 --- a/dev/tests/api-functional/testsuite/Magento/Framework/Api/Search/SearchTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Framework/Api/Search/SearchTest.php @@ -38,7 +38,7 @@ public function testCatalogSearch() ] ] ], - 'page_size' => 999, + 'page_size' => 300, 'current_page' => 0, ], ]; diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Framework/QueryComplexityLimiterTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Framework/QueryComplexityLimiterTest.php index 2ab7f50b86ae9..07e9f12fbf20d 100644 --- a/dev/tests/api-functional/testsuite/Magento/GraphQl/Framework/QueryComplexityLimiterTest.php +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Framework/QueryComplexityLimiterTest.php @@ -28,6 +28,16 @@ public function testQueryComplexityIsLimited() products { items { name + nameAlias: name + ...configurableFields + ... on BundleProduct { + items { + options { + uid + label + } + } + } categories { id position @@ -323,6 +333,12 @@ public function testQueryComplexityIsLimited() percentage_value website_id } + tier_prices { + customer_group_id + qty + percentage_value + website_id + } new_to_date new_from_date tier_price @@ -390,9 +406,19 @@ public function testQueryComplexityIsLimited() } } } + +fragment configurableFields on ConfigurableProduct { + variants { + attributes { + uid + code + label + } + } +} QUERY; - self::expectExceptionMessageMatches('/Max query complexity should be 300 but got 302/'); + self::expectExceptionMessageMatches('/Max query complexity should be 300 but got 317/'); //Use POST request because request uri is too large for some servers $this->graphQlMutation($query); } diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditmemoListTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditmemoListTest.php index a15e656afc472..265b381f8cbc0 100644 --- a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditmemoListTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/CreditmemoListTest.php @@ -10,22 +10,22 @@ use Magento\TestFramework\TestCase\WebapiAbstract; /** - * Class CreditmemoListTest + * Class CreditmemoListTest for Magento sales webapi */ class CreditmemoListTest extends WebapiAbstract { /** - * Resource path + * Resource path constant */ const RESOURCE_PATH = '/V1/creditmemos'; /** - * Service read name + * Service read name constant */ const SERVICE_READ_NAME = 'salesCreditmemoRepositoryV1'; /** - * Service version + * Service version constant */ const SERVICE_VERSION = 'V1'; @@ -84,7 +84,7 @@ public function testCreditmemoList() $searchCriteriaBuilder->addFilters([$stateFilter]); $searchCriteriaBuilder->addFilters([$incrementFilter, $zeroStatusFilter]); $searchCriteriaBuilder->addSortOrder($sortOrder); - + $searchCriteriaBuilder->setPageSize(20); $searchData = $searchCriteriaBuilder->create()->__toArray(); $requestData = ['searchCriteria' => $searchData]; diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/InvoiceCommentsListTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/InvoiceCommentsListTest.php index 0b0ea949c7365..671d01039726f 100644 --- a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/InvoiceCommentsListTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/InvoiceCommentsListTest.php @@ -8,7 +8,7 @@ use Magento\TestFramework\TestCase\WebapiAbstract; /** - * Class InvoiceCommentsListTest + * Class InvoiceCommentsListTest for Magento sales webapi */ class InvoiceCommentsListTest extends WebapiAbstract { diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/InvoiceListTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/InvoiceListTest.php index 761a212f727db..12830da07450d 100644 --- a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/InvoiceListTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/InvoiceListTest.php @@ -9,7 +9,7 @@ use Magento\TestFramework\TestCase\WebapiAbstract; /** - * Class InvoiceListTest + * Class InvoiceListTest for Magento sales webapi */ class InvoiceListTest extends WebapiAbstract { @@ -71,6 +71,7 @@ public function testInvoiceList() $searchCriteriaBuilder->addFilters([$stateFilter]); $searchCriteriaBuilder->addFilters([$incrementFilter, $zeroStatusFilter]); $searchCriteriaBuilder->addSortOrder($sortOrder); + $searchCriteriaBuilder->setPageSize(20); $searchData = $searchCriteriaBuilder->create()->__toArray(); $requestData = ['searchCriteria' => $searchData]; diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderListTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderListTest.php index 605e616ed3a64..b4f95fdb03ff6 100644 --- a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderListTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/OrderListTest.php @@ -8,8 +8,7 @@ use Magento\TestFramework\TestCase\WebapiAbstract; /** - * Class OrderListTest - * @package Magento\Sales\Service\V1 + * Class OrderListTest for Magento sales webapi */ class OrderListTest extends WebapiAbstract { @@ -135,6 +134,7 @@ private function getSearchData() : array $searchCriteriaBuilder->addFilters([$filter1]); $searchCriteriaBuilder->addFilters([$filter2, $filter3]); $searchCriteriaBuilder->addSortOrder($sortOrder); + $searchCriteriaBuilder->setPageSize(20); $searchData = $searchCriteriaBuilder->create()->__toArray(); return $searchData; diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipmentListTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipmentListTest.php index cfd503d4209f4..a50cf43052f26 100644 --- a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipmentListTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipmentListTest.php @@ -8,7 +8,7 @@ use Magento\TestFramework\TestCase\WebapiAbstract; /** - * Class ShipmentListTest + * Class ShipmentListTest for Magento sales webapi */ class ShipmentListTest extends WebapiAbstract { @@ -67,7 +67,7 @@ public function testShipmentList() $searchCriteriaBuilder->addFilters([$filter1, $filter2]); $searchCriteriaBuilder->addFilters([$filter3]); $searchCriteriaBuilder->addSortOrder($sortOrder); - + $searchCriteriaBuilder->setPageSize(20); $searchData = $searchCriteriaBuilder->create()->__toArray(); $requestData = ['searchCriteria' => $searchData]; diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/TransactionTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/TransactionTest.php index 8e6bfffea4a5f..496356359f268 100644 --- a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/TransactionTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/TransactionTest.php @@ -12,12 +12,12 @@ use Magento\TestFramework\TestCase\WebapiAbstract; /** - * Class TransactionReadTest + * Class TransactionReadTest for Magento sales webapi */ class TransactionTest extends WebapiAbstract { /** - * Service read name + * Service read name constant */ const SERVICE_READ_NAME = 'salesTransactionRepositoryV1'; @@ -27,7 +27,7 @@ class TransactionTest extends WebapiAbstract const RESOURCE_PATH = '/V1/transactions'; /** - * Service version + * Service version constant */ const SERVICE_VERSION = 'V1'; @@ -145,7 +145,7 @@ public function testTransactionList() $searchCriteriaBuilder->addFilters([$filter1, $filter2]); $searchCriteriaBuilder->addFilters([$filter3, $filter4]); $searchCriteriaBuilder->addSortOrder($sortOrder); - + $searchCriteriaBuilder->setPageSize(20); $searchData = $searchCriteriaBuilder->create()->__toArray(); $requestData = ['searchCriteria' => $searchData]; diff --git a/dev/tests/api-functional/testsuite/Magento/SalesRule/Api/CouponManagementTest.php b/dev/tests/api-functional/testsuite/Magento/SalesRule/Api/CouponManagementTest.php index 3a0013d943861..77b025773e735 100644 --- a/dev/tests/api-functional/testsuite/Magento/SalesRule/Api/CouponManagementTest.php +++ b/dev/tests/api-functional/testsuite/Magento/SalesRule/Api/CouponManagementTest.php @@ -156,7 +156,7 @@ protected function getList($ruleId) ], ], 'current_page' => 1, - 'page_size' => 9999, + 'page_size' => 300, ], ]; diff --git a/dev/tests/api-functional/testsuite/Magento/SalesRule/Api/CouponRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/SalesRule/Api/CouponRepositoryTest.php index b25f9a21c26e4..6d4f548aed530 100644 --- a/dev/tests/api-functional/testsuite/Magento/SalesRule/Api/CouponRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/SalesRule/Api/CouponRepositoryTest.php @@ -134,6 +134,7 @@ public function testGetListWithMultipleFiltersAndSorting() $searchCriteriaBuilder->addFilters([$filter1, $filter2]); $searchCriteriaBuilder->addFilters([$filter3]); $searchCriteriaBuilder->addSortOrder($sortOrder); + $searchCriteriaBuilder->setPageSize(20); $searchData = $searchCriteriaBuilder->create()->__toArray(); $requestData = ['searchCriteria' => $searchData]; diff --git a/dev/tests/api-functional/testsuite/Magento/SalesRule/Api/RuleRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/SalesRule/Api/RuleRepositoryTest.php index 0618638d82ea1..8f79420af65df 100644 --- a/dev/tests/api-functional/testsuite/Magento/SalesRule/Api/RuleRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/SalesRule/Api/RuleRepositoryTest.php @@ -212,6 +212,7 @@ public function testGetListWithMultipleFiltersAndSorting() $searchCriteriaBuilder->addFilters([$filter1, $filter2]); $searchCriteriaBuilder->addFilters([$filter3]); $searchCriteriaBuilder->addSortOrder($sortOrder); + $searchCriteriaBuilder->setPageSize(20); $searchData = $searchCriteriaBuilder->create()->__toArray(); $requestData = ['searchCriteria' => $searchData]; diff --git a/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/CoreRoutingTest.php b/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/CoreRoutingTest.php index 1476e6b31912b..00eaa70deaa04 100644 --- a/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/CoreRoutingTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Webapi/Routing/CoreRoutingTest.php @@ -9,10 +9,13 @@ */ namespace Magento\Webapi\Routing; +use Magento\Framework\Webapi\Rest\Request; +use Magento\Integration\Model\Integration; +use Magento\TestFramework\Authentication\OauthHelper; use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\TestCase\Webapi\Adapter\Rest\RestClient; -class CoreRoutingTest extends \Magento\Webapi\Routing\BaseService +class CoreRoutingTest extends BaseService { public function testBasicRoutingExplicitPath() { @@ -20,7 +23,7 @@ public function testBasicRoutingExplicitPath() $serviceInfo = [ 'rest' => [ 'resourcePath' => '/V1/testmodule1/' . $itemId, - 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_GET, + 'httpMethod' => Request::HTTP_METHOD_GET, ], 'soap' => [ 'service' => 'testModule1AllSoapAndRestV1', @@ -38,7 +41,7 @@ public function testDisabledIntegrationAuthorizationException() $serviceInfo = [ 'rest' => [ 'resourcePath' => '/V1/testmodule1/' . $itemId, - 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_GET, + 'httpMethod' => Request::HTTP_METHOD_GET, ], 'soap' => [ 'service' => 'testModule1AllSoapAndRestV1', @@ -48,11 +51,11 @@ public function testDisabledIntegrationAuthorizationException() $requestData = ['itemId' => $itemId]; /** Disable integration associated with active OAuth credentials. */ - $credentials = \Magento\TestFramework\Authentication\OauthHelper::getApiAccessCredentials(); - /** @var \Magento\Integration\Model\Integration $integration */ + $credentials = OauthHelper::getApiAccessCredentials(); + /** @var Integration $integration */ $integration = $credentials['integration']; $originalStatus = $integration->getStatus(); - $integration->setStatus(\Magento\Integration\Model\Integration::STATUS_INACTIVE)->save(); + $integration->setStatus(Integration::STATUS_INACTIVE)->save(); try { $this->assertUnauthorizedException($serviceInfo, $requestData); @@ -83,9 +86,37 @@ public function testRestNoAcceptHeader() $this->_markTestAsRestOnly(); /** @var $curlClient RestClient */ $curlClient = Bootstrap::getObjectManager()->get( - \Magento\TestFramework\TestCase\Webapi\Adapter\Rest\RestClient::class + RestClient::class ); $response = $curlClient->get('/V1/testmodule1/resource1/1', [], ['Accept:']); $this->assertEquals('testProduct1', $response['name'], "Empty Accept header failed to return response."); } + + /** + * Verifies that exception is thrown when the request contains unexpected parameters. + * + * @return void + */ + public function testRequestParamsUnexpectedValueException(): void + { + $this->_markTestAsRestOnly(); + $expectedMessage = "Internal Error. Details are available in Magento log file. Report ID: webapi-"; + $unexpectedMessage = "\"%fieldName\" is required. Enter and try again."; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/testmodule1/withParam', + 'httpMethod' => Request::HTTP_METHOD_PUT, + ], + ]; + + try { + $this->_webApiCall($serviceInfo); + } catch (\Exception $e) { + $exceptionResult = $this->processRestExceptionResult($e); + $actualMessage = $exceptionResult['message']; + $this->assertStringNotContainsString($unexpectedMessage, $actualMessage); + $this->assertStringContainsString($expectedMessage, $actualMessage); + } + } } diff --git a/dev/tests/integration/testsuite/Magento/Backend/Model/Auth/SessionTest.php b/dev/tests/integration/testsuite/Magento/Backend/Model/Auth/SessionTest.php index fcbd413d977e6..322c0274e1f40 100644 --- a/dev/tests/integration/testsuite/Magento/Backend/Model/Auth/SessionTest.php +++ b/dev/tests/integration/testsuite/Magento/Backend/Model/Auth/SessionTest.php @@ -39,6 +39,7 @@ protected function setUp(): void ->setCurrentScope(\Magento\Backend\App\Area\FrontNameResolver::AREA_CODE); $this->auth = $this->objectManager->create(\Magento\Backend\Model\Auth::class); $this->authSession = $this->objectManager->create(\Magento\Backend\Model\Auth\Session::class); + $this->authSession->setUser($this->objectManager->create(\Magento\User\Model\User::class)); $this->auth->setAuthStorage($this->authSession); $this->auth->logout(); } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/CreateHandlerTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/CreateHandlerTest.php index 5642eb5cdcebf..3fe2b0af9c6c8 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/CreateHandlerTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Gallery/CreateHandlerTest.php @@ -102,15 +102,14 @@ public function testExecuteWithImageDuplicate(): void * Check sanity of posted image file name. * * @param string $imageFileName - * * @dataProvider illegalFilenameDataProvider * @return void */ public function testExecuteWithIllegalFilename(string $imageFileName): void { - $this->expectExceptionMessageMatches("\"/^((?!\.\.\/).)*$/\""); - $this->expectExceptionMessageMatches("\".+ file doesn't exist.\""); - $this->expectException(\Magento\Framework\Exception\FileSystemException::class); + $this->expectException(\Magento\Framework\Exception\ValidatorException::class); + $this->expectExceptionMessageMatches('".+ is not a valid file path"'); + $data = [ 'media_gallery' => ['images' => ['image' => ['file' => $imageFileName, 'label' => 'New image']]], ]; diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Option/Type/File/ValidatorInfoTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Option/Type/File/ValidatorInfoTest.php index 0718e3f3b9d64..b7ad2d61e8acd 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Option/Type/File/ValidatorInfoTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Option/Type/File/ValidatorInfoTest.php @@ -6,11 +6,27 @@ namespace Magento\Catalog\Model\Product\Option\Type\File; +use Magento\Catalog\Model\Product\Media\Config; +use Magento\Catalog\Model\Product\Option; +use Magento\Framework\App\Filesystem\DirectoryList; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\File\Size; +use Magento\Framework\Filesystem; +use Magento\Framework\ObjectManagerInterface; +use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\MockObject\MockObject; +use Zend_Validate; +use Zend_Validate_File_ExcludeExtension; +use Zend_Validate_File_Extension; +use Zend_Validate_File_FilesSize; +use Zend_Validate_File_ImageSize; + /** - * @magentoDataFixture Magento/Catalog/_files/validate_image_info.php + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class ValidatorInfoTest extends \PHPUnit\Framework\TestCase +class ValidatorInfoTest extends TestCase { /** * @var ValidatorInfo @@ -18,7 +34,7 @@ class ValidatorInfoTest extends \PHPUnit\Framework\TestCase protected $model; /** - * @var \Magento\Framework\ObjectManagerInterface + * @var ObjectManagerInterface */ protected $objectManager; @@ -26,26 +42,23 @@ class ValidatorInfoTest extends \PHPUnit\Framework\TestCase protected $maxFileSizeInMb; /** - * @var \Magento\Catalog\Model\Product\Option\Type\File\ValidateFactory|\PHPUnit\Framework\MockObject\MockObject + * @var ValidateFactory|MockObject */ protected $validateFactoryMock; /** - * {@inheritdoc} + * @inheritdoc */ protected function setUp(): void { - $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - /** @var \Magento\Framework\File\Size $fileSize */ - $fileSize = $this->objectManager->create(\Magento\Framework\File\Size::class); + $this->objectManager = Bootstrap::getObjectManager(); + /** @var Size $fileSize */ + $fileSize = $this->objectManager->create(Size::class); $this->maxFileSizeInMb = $fileSize->getMaxFileSizeInMb(); - $this->validateFactoryMock = $this->createPartialMock( - \Magento\Catalog\Model\Product\Option\Type\File\ValidateFactory::class, - ['create'] - ); + $this->validateFactoryMock = $this->createPartialMock(ValidateFactory::class, ['create']); $this->model = $this->objectManager->create( - \Magento\Catalog\Model\Product\Option\Type\File\ValidatorInfo::class, + ValidatorInfo::class, [ 'validateFactory' => $this->validateFactoryMock, ] @@ -53,11 +66,12 @@ protected function setUp(): void } /** + * @magentoDataFixture Magento/Catalog/_files/validate_image_info.php * @return void */ - public function testExceptionWithErrors() + public function testExceptionWithErrors(): void { - $this->expectException(\Magento\Framework\Exception\LocalizedException::class); + $this->expectException(LocalizedException::class); $this->expectExceptionMessage( "The file 'test.jpg' for 'MediaOption' has an invalid extension.\n" . "The file 'test.jpg' for 'MediaOption' has an invalid extension.\n" @@ -68,70 +82,77 @@ public function testExceptionWithErrors() ) ); - $validateMock = $this->createPartialMock(\Zend_Validate::class, ['isValid', 'getErrors']); + $validateMock = $this->createPartialMock(Zend_Validate::class, ['isValid', 'getErrors']); $validateMock->expects($this->once())->method('isValid')->willReturn(false); - $validateMock->expects($this->exactly(2))->method('getErrors')->willReturn([ - \Zend_Validate_File_ExcludeExtension::FALSE_EXTENSION, - \Zend_Validate_File_Extension::FALSE_EXTENSION, - \Zend_Validate_File_ImageSize::WIDTH_TOO_BIG, - \Zend_Validate_File_FilesSize::TOO_BIG, + $validateMock->expects($this->exactly(1))->method('getErrors')->willReturn([ + Zend_Validate_File_ExcludeExtension::FALSE_EXTENSION, + Zend_Validate_File_Extension::FALSE_EXTENSION, + Zend_Validate_File_ImageSize::WIDTH_TOO_BIG, + Zend_Validate_File_FilesSize::TOO_BIG, ]); - $this->validateFactoryMock->expects($this->once()) - ->method('create') - ->willReturn($validateMock); + $this->validateFactoryMock->expects($this->once())->method('create')->willReturn($validateMock); - $this->model->validate( - $this->getOptionValue(), - $this->getProductOption() - ); + $this->model->validate($this->getOptionValue(), $this->getProductOption()); } /** + * @magentoDataFixture Magento/Catalog/_files/validate_image_info.php * @return void */ - public function testExceptionWithoutErrors() + public function testExceptionWithoutErrors(): void { - $this->expectException(\Magento\Framework\Exception\LocalizedException::class); + $this->expectException(LocalizedException::class); $this->expectExceptionMessage( "The product's required option(s) weren't entered. Make sure the options are entered and try again." ); - $validateMock = $this->createPartialMock(\Zend_Validate::class, ['isValid', 'getErrors']); + $validateMock = $this->createPartialMock(Zend_Validate::class, ['isValid', 'getErrors']); $validateMock->expects($this->once())->method('isValid')->willReturn(false); - $validateMock->expects($this->exactly(1))->method('getErrors')->willReturn(false); + $validateMock->expects($this->exactly(1))->method('getErrors')->willReturn([]); $this->validateFactoryMock->expects($this->once()) ->method('create') ->willReturn($validateMock); - $this->model->validate( - $this->getOptionValue(), - $this->getProductOption() + $this->model->validate($this->getOptionValue(), $this->getProductOption()); + } + + /** + * @magentoDataFixture Magento/Catalog/_files/validate_image_info_another.php + * @return void + */ + public function testExceptionWrongExtension(): void + { + $this->expectException(LocalizedException::class); + $this->expectExceptionMessage( + "The product's required option(s) weren't entered. Make sure the options are entered and try again." ); + + $validateMock = $this->createPartialMock(Zend_Validate::class, ['isValid', 'getErrors']); + $validateMock->expects($this->exactly(1))->method('getErrors')->willReturn([]); + $this->validateFactoryMock->expects($this->once())->method('create')->willReturn($validateMock); + + $this->model->validate($this->getOptionValue('magento_small_image.svg'), $this->getProductOption()); } /** + * @magentoDataFixture Magento/Catalog/_files/validate_image_info.php * @return void */ - public function testValidate() + public function testValidate(): void { //use actual zend class to test changed functionality - $validate = $this->objectManager->create(\Zend_Validate::class); - $this->validateFactoryMock->expects($this->once()) - ->method('create') - ->willReturn($validate); - $this->assertTrue( - $this->model->validate( - $this->getOptionValue(), - $this->getProductOption() - ) - ); + $validate = $this->objectManager->create(Zend_Validate::class); + $this->validateFactoryMock->expects($this->once())->method('create')->willReturn($validate); + + $result = $this->model->validate($this->getOptionValue(), $this->getProductOption()); + $this->assertTrue($result); } /** * @param array $options - * @return \Magento\Catalog\Model\Product\Option + * @return Option */ - protected function getProductOption(array $options = []) + protected function getProductOption(array $options = []): Option { $data = [ 'option_id' => '1', @@ -154,34 +175,35 @@ protected function getProductOption(array $options = []) 'price' => '5.0000', 'price_type' => 'fixed', ]; - $option = $this->objectManager->create( - \Magento\Catalog\Model\Product\Option::class, + + return $this->objectManager->create( + Option::class, [ 'data' => array_merge($data, $options) ] ); - - return $option; } /** + * @param string|null $fileName * @return array */ - protected function getOptionValue() + protected function getOptionValue(?string $fileName = 'magento_small_image.jpg'): array { - /** @var \Magento\Catalog\Model\Product\Media\Config $config */ - $config = $this->objectManager->get(\Magento\Catalog\Model\Product\Media\Config::class); - $file = $config->getBaseTmpMediaPath() . '/magento_small_image.jpg'; + /** @var Config $config */ + $config = $this->objectManager->get(Config::class); + $file = $config->getBaseTmpMediaPath() . '/' . $fileName; - /** @var \Magento\Framework\Filesystem $filesystem */ - $filesystem = $this->objectManager->get(\Magento\Framework\Filesystem::class); - $tmpDirectory = $filesystem->getDirectoryRead(\Magento\Framework\App\Filesystem\DirectoryList::MEDIA); + /** @var Filesystem $filesystem */ + $filesystem = $this->objectManager->get(Filesystem::class); + $tmpDirectory = $filesystem->getDirectoryRead(DirectoryList::MEDIA); $filePath = $tmpDirectory->getAbsolutePath($file); return [ 'title' => 'test.jpg', 'quote_path' => $file, 'order_path' => $file, + // phpcs:ignore Magento2.Security.InsecureFunction 'secret_key' => substr(md5(file_get_contents($filePath)), 0, 20), ]; } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/validate_image_info_another.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/validate_image_info_another.php new file mode 100644 index 0000000000000..f4a265bf484d3 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/validate_image_info_another.php @@ -0,0 +1,31 @@ +get(Filesystem::class); + +/** @var Magento\Catalog\Model\Product\Media\Config $config */ +$config = $objectManager->get(Config::class); + +/** @var $mediaDirectory WriteInterface */ +$mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA); +$mediaDirectory->create($config->getBaseTmpMediaPath()); + +$targetTmpFilePath = $mediaDirectory->getAbsolutePath($config->getBaseTmpMediaPath() . '/magento_small_image.svg'); +$mediaDirectory->getDriver()->filePutContents( + $targetTmpFilePath, + file_get_contents(__DIR__ . '/magento_small_image.jpg') +); +// Copying the image to target dir is not necessary because during product save, it will be moved there from tmp dir diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/validate_image_info_another_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/validate_image_info_another_rollback.php new file mode 100644 index 0000000000000..f7f5552c630e6 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/validate_image_info_another_rollback.php @@ -0,0 +1,28 @@ +create(Filesystem::class); + +/** @var Config $config */ +$config = $objectManager->get(Config::class); + +/** @var $tmpDirectory WriteInterface */ +$tmpDirectory = $filesystem->getDirectoryRead(DirectoryList::MEDIA); + +$targetTmpFilePath = $tmpDirectory->getAbsolutePath($config->getBaseTmpMediaPath() . '/magento_small_image.svg'); +if (file_exists($targetTmpFilePath)) { + unlink($targetTmpFilePath); +} diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ValidateTest.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ValidateTest.php index 0e1b20d50a372..2549896c1c2b3 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ValidateTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/Import/ValidateTest.php @@ -17,6 +17,7 @@ * Integration test for \Magento\CatalogImportExport\Model\Import\Product class. * * @magentoAppArea adminhtml + * @magentoDataFixtureBeforeTransaction Magento/Catalog/_files/enable_reindex_schedule.php */ class ValidateTest extends \PHPUnit\Framework\TestCase { diff --git a/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_address_another_customer.php b/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_address_another_customer.php new file mode 100644 index 0000000000000..6d90833d8101a --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_address_another_customer.php @@ -0,0 +1,51 @@ +get(AddressFactory::class)->create(); +$customerRepository = $objectManager->get(CustomerRepositoryInterface::class); +$customer = $customerRepository->get('customer_with_addresses@test.com'); +$addresses = $customer->getAddresses(); +$addressFirst = array_shift($addresses); +$quoteShippingAddress->importCustomerAddressData($addressFirst); + +$productRepository = $objectManager->create(ProductRepositoryInterface::class); +$product = $productRepository->get('simple'); + +$websiteRepository = $objectManager->get(WebsiteRepositoryInterface::class); +$mainWebsite = $websiteRepository->get('base'); + +$accountManagement = $objectManager->create(AccountManagementInterface::class); + +$quoteRepository = $objectManager->get(CartRepositoryInterface::class); +$quote = $objectManager->get(QuoteFactory::class)->create(); +$quote->setStoreId($mainWebsite->getDefaultStore()->getId()) + ->setIsActive(true) + ->setIsMultiShipping(false) + ->assignCustomerWithAddressChange($customer) + ->setShippingAddress($quoteShippingAddress) + ->setBillingAddress($quoteShippingAddress) + ->setCheckoutMethod('customer') + ->setPasswordHash($accountManagement->getPasswordHash('password')) + ->setReservedOrderId('test_order_999') + ->setCustomerEmail('aaa2@aaa.com') + ->addProduct($product, 2); +$quoteRepository->save($quote); diff --git a/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_address_another_customer_rollback.php b/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_address_another_customer_rollback.php new file mode 100644 index 0000000000000..87b445d0f7be4 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Checkout/_files/quote_with_address_another_customer_rollback.php @@ -0,0 +1,23 @@ +get(SearchCriteriaBuilder::class); +$searchCriteria = $searchCriteriaBuilder->addFilter('reserved_order_id', 'test_order_999')->create(); + +/** @var CartRepositoryInterface $quoteRepository */ +$quoteRepository = $objectManager->get(CartRepositoryInterface::class); +$items = $quoteRepository->getList($searchCriteria)->getItems(); +$item = array_pop($items); +$quoteRepository->delete($item); diff --git a/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/PageDesignTest.php b/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/PageDesignTest.php index cb6ea60a5efdc..f0cd6d8df1fc1 100644 --- a/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/PageDesignTest.php +++ b/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/PageDesignTest.php @@ -18,6 +18,7 @@ use Magento\Framework\Message\MessageInterface; use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\TestCase\AbstractBackendController; +use Magento\Cms\Controller\Adminhtml\Page\PostDataProcessor; /** * Test the saving CMS pages design via admin area interface. @@ -61,6 +62,11 @@ class PageDesignTest extends AbstractBackendController */ private $pagesToDelete = []; + /** + * @var PostDataProcessor + */ + private $postDataProcessor; + /** * @inheritDoc */ @@ -71,6 +77,7 @@ protected function setUp(): void $this->aclBuilder = Bootstrap::getObjectManager()->get(Builder::class); $this->pageRetriever = Bootstrap::getObjectManager()->get(GetPageByIdentifierInterface::class); $this->scopeConfig = Bootstrap::getObjectManager()->get(ScopeConfigInterface::class); + $this->postDataProcessor = Bootstrap::getObjectManager()->get(PostDataProcessor::class); } /** @@ -222,4 +229,22 @@ public function testSaveLayoutXml(): void $this->assertEmpty($updated->getCustomLayoutUpdateXml()); $this->assertEmpty($updated->getLayoutUpdateXml()); } + + /** + * Test create CMS page with invalid layout update + * + * @return void + */ + public function testSaveWithCustomLayoutUpdate(): void + { + $requestData = [ + PageInterface::IDENTIFIER => 'randomidentified', + PageInterface::TITLE => 'page title', + PageInterface::CUSTOM_THEME => '1', + PageInterface::PAGE_LAYOUT => 'empty', + PageInterface::CUSTOM_LAYOUT_UPDATE_XML => '', + PageInterface::LAYOUT_UPDATE_XML => '', + ]; + $this->assertFalse($this->postDataProcessor->validate($requestData)); + } } diff --git a/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFilesTest.php b/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFilesTest.php index 7d9309d199660..3086224bf20f8 100644 --- a/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFilesTest.php +++ b/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFilesTest.php @@ -4,15 +4,32 @@ * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Cms\Controller\Adminhtml\Wysiwyg\Images; +use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\App\Filesystem\DirectoryList; +use Magento\Framework\Exception\FileSystemException; +use Magento\Framework\Filesystem\Directory\DenyListPathValidator; +use Magento\Framework\Filesystem\Directory\WriteFactory; +use Magento\Framework\Filesystem\Directory\WriteInterface; /** * Test for \Magento\Cms\Controller\Adminhtml\Wysiwyg\Images\DeleteFiles class. + * + * @magentoAppArea adminhtml */ class DeleteFilesTest extends \PHPUnit\Framework\TestCase { + private const MEDIA_GALLERY_IMAGE_FOLDERS_CONFIG_PATH + = 'system/media_storage_configuration/allowed_resources/media_gallery_image_folders'; + + /** + * @var array + */ + private $origConfigValue; + /** * @var \Magento\Cms\Controller\Adminhtml\Wysiwyg\Images\DeleteFiles */ @@ -24,7 +41,7 @@ class DeleteFilesTest extends \PHPUnit\Framework\TestCase private $imagesHelper; /** - * @var \Magento\Framework\Filesystem\Directory\WriteInterface + * @var WriteInterface */ private $mediaDirectory; @@ -48,27 +65,55 @@ class DeleteFilesTest extends \PHPUnit\Framework\TestCase */ private $objectManager; + /** + * @var DirectoryList + */ + private $directoryList; + + /** + * @var WriteInterface + */ + private $bypassDenyListWrite; + /** * @inheritdoc + * @throws FileSystemException */ protected function setUp(): void { $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - $directoryName = 'directory1'; + $directoryName = 'testDir'; + $this->directoryList = $this->objectManager->get(DirectoryList::class); $this->filesystem = $this->objectManager->get(\Magento\Framework\Filesystem::class); /** @var \Magento\Cms\Helper\Wysiwyg\Images $imagesHelper */ $this->imagesHelper = $this->objectManager->get(\Magento\Cms\Helper\Wysiwyg\Images::class); $this->mediaDirectory = $this->filesystem->getDirectoryWrite(DirectoryList::MEDIA); - $this->fullDirectoryPath = $this->imagesHelper->getStorageRoot() . '/' . $directoryName; + $this->fullDirectoryPath = $this->imagesHelper->getStorageRoot() . $directoryName; $this->mediaDirectory->create($this->mediaDirectory->getRelativePath($this->fullDirectoryPath)); $filePath = $this->fullDirectoryPath . DIRECTORY_SEPARATOR . $this->fileName; $fixtureDir = realpath(__DIR__ . '/../../../../../Catalog/_files'); copy($fixtureDir . '/' . $this->fileName, $filePath); - $path = $this->fullDirectoryPath . '/.htaccess'; - if (!$this->mediaDirectory->isFile($path)) { - $this->mediaDirectory->writeFile($path, "Order deny,allow\nDeny from all"); - } $this->model = $this->objectManager->get(\Magento\Cms\Controller\Adminhtml\Wysiwyg\Images\DeleteFiles::class); + $config = $this->objectManager->get(ScopeConfigInterface::class); + $this->origConfigValue = $config->getValue( + self::MEDIA_GALLERY_IMAGE_FOLDERS_CONFIG_PATH, + 'default' + ); + $scopeConfig = $this->objectManager->get(\Magento\Framework\App\Config\MutableScopeConfigInterface::class); + $scopeConfig->setValue( + self::MEDIA_GALLERY_IMAGE_FOLDERS_CONFIG_PATH, + array_merge($this->origConfigValue, ['testDir']), + ); + } + + protected function tearDown(): void + { + $this->mediaDirectory->delete($this->mediaDirectory->getRelativePath($this->fullDirectoryPath)); + $scopeConfig = $this->objectManager->get(\Magento\Framework\App\Config\MutableScopeConfigInterface::class); + $scopeConfig->setValue( + self::MEDIA_GALLERY_IMAGE_FOLDERS_CONFIG_PATH, + $this->origConfigValue + ); } /** @@ -124,14 +169,28 @@ public function executeDataProvider(): array */ public function testDeleteHtaccess() { + $testDir = $this->imagesHelper->getStorageRoot() . "directory1"; + $this->mediaDirectory->create($this->mediaDirectory->getRelativePath($testDir)); + $path = $testDir . '/.htaccess'; + $denyListPathValidator = $this->objectManager + ->create(DenyListPathValidator::class, ['driver' => $this->mediaDirectory->getDriver()]); + $denyListPathValidator->addException($path); + $bypassDenyListWriteFactory = $this->objectManager->create(WriteFactory::class, [ + 'denyListPathValidator' => $denyListPathValidator + ]); + $this->bypassDenyListWrite = $bypassDenyListWriteFactory + ->create($this->directoryList->getPath(DirectoryList::MEDIA)); + if (!$this->bypassDenyListWrite->isFile($path)) { + $this->bypassDenyListWrite->writeFile($path, "Order deny,allow\nDeny from all"); + } $this->model->getRequest()->setMethod('POST') ->setPostValue('files', [$this->imagesHelper->idEncode('.htaccess')]); - $this->model->getStorage()->getSession()->setCurrentPath($this->fullDirectoryPath); + $this->model->getStorage()->getSession()->setCurrentPath($testDir); $this->model->execute(); $this->assertTrue( - $this->mediaDirectory->isExist( - $this->mediaDirectory->getRelativePath($this->fullDirectoryPath . '/' . '.htaccess') + $this->bypassDenyListWrite->isExist( + $this->bypassDenyListWrite->getRelativePath($testDir . '/' . '.htaccess') ) ); } @@ -184,7 +243,7 @@ public static function tearDownAfterClass(): void { $filesystem = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() ->get(\Magento\Framework\Filesystem::class); - /** @var \Magento\Framework\Filesystem\Directory\WriteInterface $directory */ + /** @var WriteInterface $directory */ $directory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA); if ($directory->isExist('wysiwyg')) { $directory->delete('wysiwyg'); diff --git a/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFolderTest.php b/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFolderTest.php index 47e829c7a57a6..36391ed4a2284 100644 --- a/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFolderTest.php +++ b/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFolderTest.php @@ -6,6 +6,7 @@ namespace Magento\Cms\Controller\Adminhtml\Wysiwyg\Images; +use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\App\Response\HttpFactory as ResponseFactory; @@ -14,6 +15,19 @@ */ class DeleteFolderTest extends \PHPUnit\Framework\TestCase { + private const MEDIA_GALLERY_IMAGE_FOLDERS_CONFIG_PATH + = 'system/media_storage_configuration/allowed_resources/media_gallery_image_folders'; + + /** + * @var array + */ + private $origConfigValue; + + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager; + /** * @var \Magento\Cms\Controller\Adminhtml\Wysiwyg\Images\DeleteFolder */ @@ -49,14 +63,38 @@ class DeleteFolderTest extends \PHPUnit\Framework\TestCase */ protected function setUp(): void { - $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - $this->filesystem = $objectManager->get(\Magento\Framework\Filesystem::class); + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->filesystem = $this->objectManager->get(\Magento\Framework\Filesystem::class); $this->mediaDirectory = $this->filesystem->getDirectoryWrite(DirectoryList::MEDIA); /** @var \Magento\Cms\Helper\Wysiwyg\Images $imagesHelper */ - $this->imagesHelper = $objectManager->get(\Magento\Cms\Helper\Wysiwyg\Images::class); + $this->imagesHelper = $this->objectManager->get(\Magento\Cms\Helper\Wysiwyg\Images::class); $this->fullDirectoryPath = $this->imagesHelper->getStorageRoot(); - $this->responseFactory = $objectManager->get(ResponseFactory::class); - $this->model = $objectManager->get(\Magento\Cms\Controller\Adminhtml\Wysiwyg\Images\DeleteFolder::class); + $this->mediaDirectory->create($this->mediaDirectory->getRelativePath($this->fullDirectoryPath)); + $this->responseFactory = $this->objectManager->get(ResponseFactory::class); + $this->model = $this->objectManager->get(\Magento\Cms\Controller\Adminhtml\Wysiwyg\Images\DeleteFolder::class); + $config = $this->objectManager->get(ScopeConfigInterface::class); + $this->origConfigValue = $config->getValue( + self::MEDIA_GALLERY_IMAGE_FOLDERS_CONFIG_PATH, + 'default' + ); + $scopeConfig = $this->objectManager->get(\Magento\Framework\App\Config\MutableScopeConfigInterface::class); + $scopeConfig->setValue( + self::MEDIA_GALLERY_IMAGE_FOLDERS_CONFIG_PATH, + array_merge($this->origConfigValue, ['testDir']), + ); + } + + protected function tearDown(): void + { + $directoryName = 'testDir'; + $this->mediaDirectory->delete( + $this->mediaDirectory->getRelativePath($this->imagesHelper->getStorageRoot() . '/' . $directoryName) + ); + $scopeConfig = $this->objectManager->get(\Magento\Framework\App\Config\MutableScopeConfigInterface::class); + $scopeConfig->setValue( + self::MEDIA_GALLERY_IMAGE_FOLDERS_CONFIG_PATH, + $this->origConfigValue + ); } /** @@ -68,21 +106,14 @@ protected function setUp(): void */ public function testExecute() { - $directoryName = DIRECTORY_SEPARATOR . 'NewDirectory'; - $this->mediaDirectory->create( - $this->mediaDirectory->getRelativePath($this->fullDirectoryPath . $directoryName) - ); - $this->model->getRequest()->setParams(['node' => $this->imagesHelper->idEncode($directoryName)]); + $directoryName = 'testDir/NewDirectory'; + $path = $this->mediaDirectory->getRelativePath($this->fullDirectoryPath . $directoryName); + $this->mediaDirectory->create($path); + $this->model->getRequest()->setParams(['node' => $this->imagesHelper->idEncode($path)]); $this->model->getRequest()->setMethod('POST'); $this->model->execute(); - $this->assertFalse( - $this->mediaDirectory->isExist( - $this->mediaDirectory->getRelativePath( - $this->fullDirectoryPath . $directoryName - ) - ) - ); + $this->assertFalse($this->mediaDirectory->isExist($path)); } /** @@ -118,7 +149,10 @@ public function testExecuteWithLinkedMedia() */ public function testExecuteWithWrongDirectoryName() { - $directoryName = '/../../etc/'; + $directoryName = 'testDir/../../../etc/'; + $testDir = $this->mediaDirectory->getRelativePath($this->fullDirectoryPath . 'testDir'); + $this->mediaDirectory->create($testDir); + $this->assertFileExists($this->fullDirectoryPath . $directoryName); $this->model->getRequest()->setParams(['node' => $this->imagesHelper->idEncode($directoryName)]); $this->model->execute(); @@ -134,7 +168,7 @@ public function testExecuteWithWrongDirectoryName() public function testExecuteWithExcludedDirectoryName() { $directoryName = 'downloadable'; - $expectedResponseMessage = 'We cannot delete directory /downloadable.'; + $expectedResponseMessage = 'We cannot delete the selected directory.'; $mediaDirectory = $this->filesystem->getDirectoryWrite(DirectoryList::MEDIA); $mediaDirectory->create($directoryName); $this->assertFileExists($this->fullDirectoryPath . $directoryName); diff --git a/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/NewFolderTest.php b/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/NewFolderTest.php index 90f299be1078c..b23e78a2bc6a5 100644 --- a/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/NewFolderTest.php +++ b/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/NewFolderTest.php @@ -6,6 +6,7 @@ namespace Magento\Cms\Controller\Adminhtml\Wysiwyg\Images; +use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\App\Filesystem\DirectoryList; /** @@ -13,6 +14,19 @@ */ class NewFolderTest extends \PHPUnit\Framework\TestCase { + private const MEDIA_GALLERY_IMAGE_FOLDERS_CONFIG_PATH + = 'system/media_storage_configuration/allowed_resources/media_gallery_image_folders'; + + /** + * @var array + */ + private $origConfigValue; + + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager; + /** * @var \Magento\Cms\Controller\Adminhtml\Wysiwyg\Images\NewFolder */ @@ -48,13 +62,34 @@ class NewFolderTest extends \PHPUnit\Framework\TestCase */ protected function setUp(): void { - $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - $this->filesystem = $objectManager->get(\Magento\Framework\Filesystem::class); + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->filesystem = $this->objectManager->get(\Magento\Framework\Filesystem::class); /** @var \Magento\Cms\Helper\Wysiwyg\Images $imagesHelper */ - $this->imagesHelper = $objectManager->get(\Magento\Cms\Helper\Wysiwyg\Images::class); + $this->imagesHelper = $this->objectManager->get(\Magento\Cms\Helper\Wysiwyg\Images::class); $this->mediaDirectory = $this->filesystem->getDirectoryWrite(DirectoryList::MEDIA); - $this->fullDirectoryPath = $this->imagesHelper->getStorageRoot(); - $this->model = $objectManager->get(\Magento\Cms\Controller\Adminhtml\Wysiwyg\Images\NewFolder::class); + $this->fullDirectoryPath = $this->imagesHelper->getStorageRoot() . '/testDir'; + $this->mediaDirectory->create($this->mediaDirectory->getRelativePath($this->fullDirectoryPath)); + $this->model = $this->objectManager->get(\Magento\Cms\Controller\Adminhtml\Wysiwyg\Images\NewFolder::class); + $config = $this->objectManager->get(ScopeConfigInterface::class); + $this->origConfigValue = $config->getValue( + self::MEDIA_GALLERY_IMAGE_FOLDERS_CONFIG_PATH, + 'default' + ); + $scopeConfig = $this->objectManager->get(\Magento\Framework\App\Config\MutableScopeConfigInterface::class); + $scopeConfig->setValue( + self::MEDIA_GALLERY_IMAGE_FOLDERS_CONFIG_PATH, + array_merge($this->origConfigValue, ['testDir']), + ); + } + + protected function tearDown(): void + { + $this->mediaDirectory->delete($this->mediaDirectory->getRelativePath($this->fullDirectoryPath)); + $scopeConfig = $this->objectManager->get(\Magento\Framework\App\Config\MutableScopeConfigInterface::class); + $scopeConfig->setValue( + self::MEDIA_GALLERY_IMAGE_FOLDERS_CONFIG_PATH, + $this->origConfigValue + ); } /** @@ -91,7 +126,7 @@ public function testExecuteWithLinkedMedia() ->setPostValue('name', $this->dirName); $this->model->getStorage() ->getSession() - ->setCurrentPath($this->fullDirectoryPath . DIRECTORY_SEPARATOR . 'wysiwyg'); + ->setCurrentPath($this->imagesHelper->getStorageRoot() . DIRECTORY_SEPARATOR . 'wysiwyg'); $this->model->execute(); $this->assertTrue(is_dir($linkedDirectoryPath . DIRECTORY_SEPARATOR . $this->dirName)); diff --git a/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/UploadTest.php b/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/UploadTest.php index ddadb62cfdb5d..6b1a20ab8cb8f 100644 --- a/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/UploadTest.php +++ b/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/UploadTest.php @@ -8,6 +8,7 @@ namespace Magento\Cms\Controller\Adminhtml\Wysiwyg\Images; +use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\Controller\Result\Json as JsonResponse; use Magento\Framework\App\Response\HttpFactory as ResponseFactory; @@ -18,6 +19,14 @@ */ class UploadTest extends \PHPUnit\Framework\TestCase { + private const MEDIA_GALLERY_IMAGE_FOLDERS_CONFIG_PATH + = 'system/media_storage_configuration/allowed_resources/media_gallery_image_folders'; + + /** + * @var array + */ + private $origConfigValue; + /** * @var \Magento\Cms\Controller\Adminhtml\Wysiwyg\Images\Upload */ @@ -58,20 +67,26 @@ class UploadTest extends \PHPUnit\Framework\TestCase */ private $responseFactory; + /** + * @var \Magento\Cms\Helper\Wysiwyg\Images + */ + private $imagesHelper; + /** * @inheritdoc */ protected function setUp(): void { $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - $directoryName = 'directory1'; + $directoryName = 'testDir'; $excludedDirName = 'downloadable'; $this->filesystem = $this->objectManager->get(\Magento\Framework\Filesystem::class); /** @var \Magento\Cms\Helper\Wysiwyg\Images $imagesHelper */ - $imagesHelper = $this->objectManager->get(\Magento\Cms\Helper\Wysiwyg\Images::class); + $this->imagesHelper = $this->objectManager->get(\Magento\Cms\Helper\Wysiwyg\Images::class); $this->mediaDirectory = $this->filesystem->getDirectoryWrite(DirectoryList::MEDIA); - $this->fullDirectoryPath = $imagesHelper->getStorageRoot() . DIRECTORY_SEPARATOR . $directoryName; - $this->fullExcludedDirectoryPath = $imagesHelper->getStorageRoot() . DIRECTORY_SEPARATOR . $excludedDirName; + $this->fullDirectoryPath = $this->imagesHelper->getStorageRoot() . DIRECTORY_SEPARATOR . $directoryName; + $this->fullExcludedDirectoryPath = $this->imagesHelper->getStorageRoot() + . DIRECTORY_SEPARATOR . $excludedDirName; $this->mediaDirectory->create($this->mediaDirectory->getRelativePath($this->fullDirectoryPath)); $this->responseFactory = $this->objectManager->get(ResponseFactory::class); $this->model = $this->objectManager->get(\Magento\Cms\Controller\Adminhtml\Wysiwyg\Images\Upload::class); @@ -87,6 +102,29 @@ protected function setUp(): void 'size' => filesize($fixtureDir), ], ]; + $config = $this->objectManager->get(ScopeConfigInterface::class); + $this->origConfigValue = $config->getValue( + self::MEDIA_GALLERY_IMAGE_FOLDERS_CONFIG_PATH, + 'default' + ); + $scopeConfig = $this->objectManager->get(\Magento\Framework\App\Config\MutableScopeConfigInterface::class); + $scopeConfig->setValue( + self::MEDIA_GALLERY_IMAGE_FOLDERS_CONFIG_PATH, + array_merge($this->origConfigValue, ['testDir']), + ); + } + + protected function tearDown(): void + { + $directoryName = 'testDir'; + $this->mediaDirectory->delete( + $this->mediaDirectory->getRelativePath($this->imagesHelper->getStorageRoot() . '/' . $directoryName) + ); + $scopeConfig = $this->objectManager->get(\Magento\Framework\App\Config\MutableScopeConfigInterface::class); + $scopeConfig->setValue( + self::MEDIA_GALLERY_IMAGE_FOLDERS_CONFIG_PATH, + $this->origConfigValue + ); } /** @@ -130,7 +168,7 @@ public function testExecute() */ public function testExecuteWithExcludedDirectory() { - $expectedError = 'We can\'t upload the file to current folder right now. Please try another folder.'; + $expectedError = 'We can\'t upload the file to the current folder right now. Please try another folder.'; $this->model->getRequest()->setParams(['type' => 'image/png']); $this->model->getRequest()->setMethod('POST'); $this->model->getStorage()->getSession()->setCurrentPath($this->fullExcludedDirectoryPath); diff --git a/dev/tests/integration/testsuite/Magento/Cms/Model/Wysiwyg/Images/StorageTest.php b/dev/tests/integration/testsuite/Magento/Cms/Model/Wysiwyg/Images/StorageTest.php index 9be1178704d02..af2bd7932fa46 100644 --- a/dev/tests/integration/testsuite/Magento/Cms/Model/Wysiwyg/Images/StorageTest.php +++ b/dev/tests/integration/testsuite/Magento/Cms/Model/Wysiwyg/Images/StorageTest.php @@ -6,7 +6,13 @@ */ namespace Magento\Cms\Model\Wysiwyg\Images; +use Magento\Cms\Model\Wysiwyg\Images\Storage\Collection; +use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\App\Filesystem\DirectoryList; +use Magento\Framework\DataObject; +use Magento\Framework\Filesystem; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Framework\Filesystem\DriverInterface; /** * Test methods of class Storage @@ -18,10 +24,8 @@ */ class StorageTest extends \PHPUnit\Framework\TestCase { - /** - * @var string - */ - protected static $_baseDir; + private const MEDIA_GALLERY_IMAGE_FOLDERS_CONFIG_PATH + = 'system/media_storage_configuration/allowed_resources/media_gallery_image_folders'; /** * @var \Magento\Framework\ObjectManagerInterface @@ -29,52 +33,73 @@ class StorageTest extends \PHPUnit\Framework\TestCase private $objectManager; /** - * @var \Magento\Framework\Filesystem + * @var Filesystem */ private $filesystem; /** - * @var \Magento\Cms\Model\Wysiwyg\Images\Storage + * @var Storage */ private $storage; /** - * @inheritdoc + * @var DriverInterface */ - // phpcs:disable - public static function setUpBeforeClass(): void - { - self::$_baseDir = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\Cms\Helper\Wysiwyg\Images::class - )->getCurrentPath() . 'MagentoCmsModelWysiwygImagesStorageTest'; - if (!file_exists(self::$_baseDir)) { - mkdir(self::$_baseDir); - } - touch(self::$_baseDir . '/1.swf'); - } - // phpcs:enable + private $driver; + + /** + * @var array + */ + private $origConfigValue; + + /** + * @var \Magento\Framework\Filesystem\Directory\WriteInterface + */ + private $mediaDirectory; + + /** + * @var string + */ + private $fullDirectoryPath; + + /** + * @var \Magento\Cms\Helper\Wysiwyg\Images + */ + private $imagesHelper; /** * @inheritdoc */ - // phpcs:ignore - public static function tearDownAfterClass(): void + protected function setUp(): void { - \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - \Magento\Framework\Filesystem\Driver\File::class - )->deleteDirectory( - self::$_baseDir + $this->objectManager = Bootstrap::getObjectManager(); + $this->filesystem = $this->objectManager->get(Filesystem::class); + $this->imagesHelper = $this->objectManager->get(\Magento\Cms\Helper\Wysiwyg\Images::class); + $this->mediaDirectory = $this->filesystem->getDirectoryWrite(DirectoryList::MEDIA); + $this->fullDirectoryPath = $this->imagesHelper->getStorageRoot() . '/MagentoCmsModelWysiwygImagesStorageTest'; + $this->mediaDirectory->create($this->mediaDirectory->getRelativePath($this->fullDirectoryPath)); + $config = $this->objectManager->get(ScopeConfigInterface::class); + $this->origConfigValue = $config->getValue( + self::MEDIA_GALLERY_IMAGE_FOLDERS_CONFIG_PATH, + 'default' + ); + $scopeConfig = $this->objectManager->get(\Magento\Framework\App\Config\MutableScopeConfigInterface::class); + $scopeConfig->setValue( + self::MEDIA_GALLERY_IMAGE_FOLDERS_CONFIG_PATH, + array_merge($this->origConfigValue, ['MagentoCmsModelWysiwygImagesStorageTest']), ); + $this->storage = $this->objectManager->create(Storage::class); + $this->driver = Bootstrap::getObjectManager()->get(DriverInterface::class); } - /** - * @inheritdoc - */ - public function setUp(): void + protected function tearDown(): void { - $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - $this->filesystem = $this->objectManager->get(\Magento\Framework\Filesystem::class); - $this->storage = $this->objectManager->create(\Magento\Cms\Model\Wysiwyg\Images\Storage::class); + $this->mediaDirectory->delete($this->mediaDirectory->getRelativePath($this->fullDirectoryPath)); + $scopeConfig = $this->objectManager->get(\Magento\Framework\App\Config\MutableScopeConfigInterface::class); + $scopeConfig->setValue( + self::MEDIA_GALLERY_IMAGE_FOLDERS_CONFIG_PATH, + $this->origConfigValue + ); } /** @@ -83,16 +108,32 @@ public function setUp(): void */ public function testGetFilesCollection(): void { - \Magento\TestFramework\Helper\Bootstrap::getInstance() + Bootstrap::getInstance() ->loadArea(\Magento\Backend\App\Area\FrontNameResolver::AREA_CODE); - $collection = $this->storage->getFilesCollection(self::$_baseDir, 'media'); - $this->assertInstanceOf(\Magento\Cms\Model\Wysiwyg\Images\Storage\Collection::class, $collection); + $fileName = 'magento_image.jpg'; + $imagePath = realpath(__DIR__ . '/../../../../Catalog/_files/' . $fileName); + $mediaDirectory = $this->filesystem->getDirectoryWrite(DirectoryList::MEDIA); + $modifiableFilePath = $mediaDirectory->getAbsolutePath('MagentoCmsModelWysiwygImagesStorageTest/' . $fileName); + $this->driver->copy( + $imagePath, + $modifiableFilePath + ); + $this->storage->resizeFile($modifiableFilePath); + $collection = $this->storage->getFilesCollection($this->fullDirectoryPath, '/image'); + $this->assertInstanceOf(Collection::class, $collection); foreach ($collection as $item) { - $this->assertInstanceOf(\Magento\Framework\DataObject::class, $item); - $this->assertStringEndsWith('/1.swf', $item->getUrl()); - $this->assertStringMatchesFormat( - 'http://%s/static/%s/adminhtml/%s/%s/Magento_Cms/images/placeholder_thumbnail.jpg', - $item->getThumbUrl() + $thumbUrl = parse_url($item->getThumbUrl(), PHP_URL_PATH); + $this->assertInstanceOf(DataObject::class, $item); + $this->assertStringEndsWith('/' . $fileName, $item->getUrl()); + $this->assertEquals( + '/pub/media/.thumbsMagentoCmsModelWysiwygImagesStorageTest/magento_image.jpg', + $thumbUrl, + "Check if Thumbnail URL is equal to the generated URL" + ); + $this->assertEquals( + 'image/jpeg', + $item->getMimeType(), + "Check if Mime Type is equal to the image in the file system" ); return; } @@ -116,9 +157,9 @@ public function testGetThumbsPath(): void public function testDeleteDirectory(): void { $path = $this->objectManager->get(\Magento\Cms\Helper\Wysiwyg\Images::class)->getCurrentPath(); - $dir = 'testDeleteDirectory'; + $dir = 'MagentoCmsModelWysiwygImagesStorageTest/testDeleteDirectory'; $fullPath = $path . $dir; - $this->storage->createDirectory($dir, $path); + $this->storage->createDirectory('testDeleteDirectory', $path . '/MagentoCmsModelWysiwygImagesStorageTest'); $this->assertFileExists($fullPath); $this->storage->deleteDirectory($fullPath); $this->assertFileDoesNotExist($fullPath); @@ -126,12 +167,12 @@ public function testDeleteDirectory(): void /** * @return void - * */ public function testDeleteDirectoryWithExcludedDirPath(): void { - $this->expectExceptionMessage("We cannot delete directory /downloadable."); $this->expectException(\Magento\Framework\Exception\LocalizedException::class); + $this->expectExceptionMessage('We cannot delete the selected directory.'); + $dir = $this->objectManager->get(\Magento\Cms\Helper\Wysiwyg\Images::class)->getCurrentPath() . 'downloadable'; $this->storage->deleteDirectory($dir); } @@ -142,7 +183,7 @@ public function testDeleteDirectoryWithExcludedDirPath(): void public function testUploadFile(): void { $fileName = 'magento_small_image.jpg'; - $tmpDirectory = $this->filesystem->getDirectoryWrite(\Magento\Framework\App\Filesystem\DirectoryList::SYS_TMP); + $tmpDirectory = $this->filesystem->getDirectoryWrite(DirectoryList::SYS_TMP); $filePath = $tmpDirectory->getAbsolutePath($fileName); // phpcs:disable $fixtureDir = realpath(__DIR__ . '/../../../../Catalog/_files'); @@ -156,23 +197,23 @@ public function testUploadFile(): void 'size' => 12500, ]; - $this->storage->uploadFile(self::$_baseDir); - $this->assertTrue(is_file(self::$_baseDir . DIRECTORY_SEPARATOR . $fileName)); + $this->storage->uploadFile($this->fullDirectoryPath); + $this->assertTrue(is_file($this->fullDirectoryPath . DIRECTORY_SEPARATOR . $fileName)); // phpcs:enable } /** * @return void - * */ public function testUploadFileWithExcludedDirPath(): void { + $this->expectException(\Magento\Framework\Exception\LocalizedException::class); $this->expectExceptionMessage( - "We can't upload the file to current folder right now. Please try another folder." + 'We can\'t upload the file to the current folder right now. Please try another folder.' ); - $this->expectException(\Magento\Framework\Exception\LocalizedException::class); + $fileName = 'magento_small_image.jpg'; - $tmpDirectory = $this->filesystem->getDirectoryWrite(\Magento\Framework\App\Filesystem\DirectoryList::SYS_TMP); + $tmpDirectory = $this->filesystem->getDirectoryWrite(DirectoryList::SYS_TMP); $filePath = $tmpDirectory->getAbsolutePath($fileName); // phpcs:disable $fixtureDir = realpath(__DIR__ . '/../../../../Catalog/_files'); @@ -198,13 +239,13 @@ public function testUploadFileWithExcludedDirPath(): void * * @return void * @dataProvider testUploadFileWithWrongExtensionDataProvider - * */ public function testUploadFileWithWrongExtension(string $fileName, string $fileType, ?string $storageType): void { - $this->expectExceptionMessage("File validation failed."); $this->expectException(\Magento\Framework\Exception\LocalizedException::class); - $tmpDirectory = $this->filesystem->getDirectoryWrite(\Magento\Framework\App\Filesystem\DirectoryList::SYS_TMP); + $this->expectExceptionMessage('File validation failed.'); + + $tmpDirectory = $this->filesystem->getDirectoryWrite(DirectoryList::SYS_TMP); $filePath = $tmpDirectory->getAbsolutePath($fileName); // phpcs:disable $fixtureDir = realpath(__DIR__ . '/../../../_files'); @@ -218,8 +259,8 @@ public function testUploadFileWithWrongExtension(string $fileName, string $fileT 'size' => 12500, ]; - $this->storage->uploadFile(self::$_baseDir, $storageType); - $this->assertFalse(is_file(self::$_baseDir . DIRECTORY_SEPARATOR . $fileName)); + $this->storage->uploadFile($this->fullDirectoryPath, $storageType); + $this->assertFalse(is_file($this->fullDirectoryPath . DIRECTORY_SEPARATOR . $fileName)); // phpcs:enable } @@ -247,10 +288,11 @@ public function testUploadFileWithWrongExtensionDataProvider(): array */ public function testUploadFileWithWrongFile(): void { - $this->expectExceptionMessage("File validation failed."); $this->expectException(\Magento\Framework\Exception\LocalizedException::class); + $this->expectExceptionMessage('File validation failed.'); + $fileName = 'file.gif'; - $tmpDirectory = $this->filesystem->getDirectoryWrite(\Magento\Framework\App\Filesystem\DirectoryList::SYS_TMP); + $tmpDirectory = $this->filesystem->getDirectoryWrite(DirectoryList::SYS_TMP); $filePath = $tmpDirectory->getAbsolutePath($fileName); // phpcs:disable $file = fopen($filePath, "wb"); @@ -264,8 +306,8 @@ public function testUploadFileWithWrongFile(): void 'size' => 12500, ]; - $this->storage->uploadFile(self::$_baseDir); - $this->assertFalse(is_file(self::$_baseDir . DIRECTORY_SEPARATOR . $fileName)); + $this->storage->uploadFile($this->fullDirectoryPath); + $this->assertFalse(is_file($this->fullDirectoryPath . DIRECTORY_SEPARATOR . $fileName)); // phpcs:enable } @@ -274,13 +316,13 @@ public function testUploadFileWithWrongFile(): void * * @param string $directory * @param string $filename - * @param string $expectedUrl + * @param array $expectedUrls * @return void * @magentoAppIsolation enabled * @magentoAppArea adminhtml * @dataProvider getThumbnailUrlDataProvider */ - public function testGetThumbnailUrl(string $directory, string $filename, string $expectedUrl): void + public function testGetThumbnailUrl(string $directory, string $filename, array $expectedUrls): void { $root = $this->storage->getCmsWysiwygImages()->getStorageRoot(); $directory = implode('/', array_filter([rtrim($root, '/'), trim($directory, '/')])); @@ -292,8 +334,8 @@ public function testGetThumbnailUrl(string $directory, string $filename, string foreach ($collection as $item) { $paths[] = parse_url($item->getThumbUrl(), PHP_URL_PATH); } - $this->assertEquals([$expectedUrl], $paths); - $this->storage->deleteFile($path); + $this->assertEquals($expectedUrls, $paths); + $this->mediaDirectory->delete($path); } /** @@ -307,17 +349,27 @@ public function getThumbnailUrlDataProvider(): array [ '/', 'image1.png', - '/pub/media/.thumbs/image1.png' + [] ], [ '/cms', 'image2.png', - '/pub/media/.thumbscms/image2.png' + [] ], [ '/cms/pages', 'image3.png', - '/pub/media/.thumbscms/pages/image3.png' + [] + ], + [ + '/MagentoCmsModelWysiwygImagesStorageTest', + 'image2.png', + ['/pub/media/.thumbsMagentoCmsModelWysiwygImagesStorageTest/image2.png'] + ], + [ + '/MagentoCmsModelWysiwygImagesStorageTest/pages', + 'image3.png', + ['/pub/media/.thumbsMagentoCmsModelWysiwygImagesStorageTest/pages/image3.png'] ] ]; } diff --git a/dev/tests/integration/testsuite/Magento/Csp/Model/Collector/ConfigCollectorTest.php b/dev/tests/integration/testsuite/Magento/Csp/Model/Collector/ConfigCollectorTest.php index 46156f0b83907..cf6287ed5b4e1 100644 --- a/dev/tests/integration/testsuite/Magento/Csp/Model/Collector/ConfigCollectorTest.php +++ b/dev/tests/integration/testsuite/Magento/Csp/Model/Collector/ConfigCollectorTest.php @@ -45,7 +45,7 @@ private function getExpectedPolicies(): array 'child-src', false, ['http://magento.com', 'http://devdocs.magento.com'], - ['http'], + ['http', 'https', 'blob'], true, true, false, @@ -62,9 +62,9 @@ private function getExpectedPolicies(): array [], true ), - 'font-src' => new FetchPolicy('font-src', false, [], [], true), + 'font-src' => new FetchPolicy('font-src', false, [], ['data'], true), 'frame-src' => new FetchPolicy('frame-src', false, [], [], true, false, false, [], [], true), - 'img-src' => new FetchPolicy('img-src', false, [], [], true), + 'img-src' => new FetchPolicy('img-src', false, [], ['data'], true), 'manifest-src' => new FetchPolicy('manifest-src', false, [], [], true), 'media-src' => new FetchPolicy('media-src', false, [], [], true), 'object-src' => new FetchPolicy('object-src', false, [], [], true), diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagementTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagementTest.php index b2ab4a5037ccb..2d750f3839a3c 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagementTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagementTest.php @@ -14,6 +14,7 @@ use Magento\Framework\Exception\State\ExpiredException; use Magento\Framework\Reflection\DataObjectProcessor; use Magento\Framework\Session\SessionManagerInterface; +use Magento\Framework\Stdlib\DateTime; use Magento\Framework\Url as UrlBuilder; use Magento\Store\Model\StoreManagerInterface; use Magento\TestFramework\Helper\Bootstrap; @@ -105,14 +106,15 @@ protected function setUp(): void */ protected function tearDown(): void { - /** @var \Magento\Customer\Model\CustomerRegistry $customerRegistry */ $customerRegistry = $this->objectManager->get(\Magento\Customer\Model\CustomerRegistry::class); - /** @var \Magento\Customer\Model\CustomerRegistry $addressRegistry */ $addressRegistry = $this->objectManager->get(\Magento\Customer\Model\AddressRegistry::class); //Cleanup customer from registry $customerRegistry->remove(1); $addressRegistry->remove(1); $addressRegistry->remove(2); + $resourceModel = $this->objectManager->get(\Magento\Customer\Model\ResourceModel\Visitor::class); + $resourceModel->getConnection()->delete($resourceModel->getMainTable()); + parent::tearDown(); } /** @@ -134,14 +136,20 @@ public function testLogin() public function testLoginWrongPassword() { $this->expectException(\Magento\Framework\Exception\InvalidEmailOrPasswordException::class); + // Customer email and password are pulled from the fixture customer.php $this->accountManagement->authenticate('customer@example.com', 'wrongPassword'); } + /** + * Test attempt to login with wrong user name + * + */ public function testLoginWrongUsername() { - $this->expectExceptionMessage("Invalid login or password."); $this->expectException(\Magento\Framework\Exception\InvalidEmailOrPasswordException::class); + $this->expectExceptionMessage('Invalid login or password.'); + // Customer email and password are pulled from the fixture customer.php $this->accountManagement->authenticate('non_existing_user', '_Password123'); } @@ -154,37 +162,69 @@ public function testChangePassword() { /** @var SessionManagerInterface $session */ $session = $this->objectManager->get(SessionManagerInterface::class); - $oldSessionId = $session->getSessionId(); - $session->setTestData('test'); - $this->accountManagement->changePassword('customer@example.com', 'password', 'new_Password123'); + $customerId = 1; + $time = time(); - $this->assertTrue( - $oldSessionId !== $session->getSessionId(), - 'Customer session id wasn\'t regenerated after change password' - ); + $session->start(); - $session->destroy(); - $session->setSessionId($oldSessionId); + // open new session + $activeSessionId = uniqid("active-$time-"); + $this->startNewSession($activeSessionId); + $activeVisitor = $this->createVisitorSession($activeSessionId, $customerId); + $session->setVisitorData($activeVisitor->getData()); - $this->assertNull($session->getTestData(), 'Customer session data wasn\'t cleaned'); + // open new session + $currentSessionId = uniqid("current-$time-"); + $this->startNewSession($currentSessionId); + $currentVisitor = $this->createVisitorSession($currentSessionId, $customerId); + $session->setVisitorData($currentVisitor->getData()); + + $this->assertNull($this->getCustomerCutoff($customerId), 'Customer cutoff session should not be set.'); + // change password + $this->accountManagement->changePassword('customer@example.com', 'password', 'new_Password123'); + $this->assertEquals( + $currentSessionId, + $session->getSessionId(), + 'Current session was renewed' + ); + + // open customer active session + $this->startNewSession($activeSessionId); + $this->assertNotNull($this->getCustomerCutoff($customerId), 'Customer cutoff session should be set.'); + // Make sure current visitor session is updated. + $this->assertLessThanOrEqual( + $this->getCustomerCutoff($customerId), + $this->getVisitorCreatedAt($activeVisitor->getId()) + ); + $this->assertGreaterThan( + $this->getCustomerCutoff($customerId), + $this->getVisitorCreatedAt($currentVisitor->getId()) + ); $this->accountManagement->authenticate('customer@example.com', 'new_Password123'); } /** * @magentoDataFixture Magento/Customer/_files/customer.php - **/ + * + */ public function testChangePasswordWrongPassword() { - $this->expectExceptionMessage("The password doesn't match this account. Verify the password and try again."); $this->expectException(\Magento\Framework\Exception\InvalidEmailOrPasswordException::class); + $this->expectExceptionMessage('The password doesn\'t match this account. Verify the password and try again.'); + $this->accountManagement->changePassword('customer@example.com', 'wrongPassword', 'new_Password123'); } + /** + * Test change password on the wrong user + * + */ public function testChangePasswordWrongUser() { - $this->expectExceptionMessage("Invalid login or password."); $this->expectException(\Magento\Framework\Exception\InvalidEmailOrPasswordException::class); + $this->expectExceptionMessage('Invalid login or password.'); + $this->accountManagement->changePassword('wrong.email@example.com', '_Password123', 'new_Password123'); } @@ -209,11 +249,11 @@ public function testActivateAccount() /** * @magentoDataFixture Magento/Customer/_files/inactive_customer.php - * */ public function testActivateCustomerConfirmationKeyWrongKey() { $this->expectException(\Magento\Framework\Exception\State\InputMismatchException::class); + /** @var \Magento\Customer\Model\Customer $customerModel */ $customerModel = $this->objectManager->create(\Magento\Customer\Model\Customer::class); $customerModel->load(1); @@ -250,11 +290,11 @@ public function testActivateCustomerWrongAccount() /** * @magentoDataFixture Magento/Customer/_files/inactive_customer.php * @magentoAppArea frontend - * */ public function testActivateCustomerAlreadyActive() { $this->expectException(\Magento\Framework\Exception\State\InvalidTransitionException::class); + /** @var \Magento\Customer\Model\Customer $customerModel */ $customerModel = $this->objectManager->create(\Magento\Customer\Model\Customer::class); $customerModel->load(1); @@ -275,11 +315,11 @@ public function testValidateResetPasswordLinkToken() /** * @magentoDataFixture Magento/Customer/_files/customer.php - * */ public function testValidateResetPasswordLinkTokenExpired() { $this->expectException(\Magento\Framework\Exception\State\ExpiredException::class); + $resetToken = 'lsdj579slkj5987slkj595lkj'; $this->setResetPasswordData($resetToken, '1970-01-01'); $this->accountManagement->validateResetPasswordLinkToken(1, $resetToken); @@ -324,11 +364,11 @@ public function testValidateResetPasswordLinkTokenWrongUser() * Test for resetPassword() method when reset for the second time * * @magentoDataFixture Magento/Customer/_files/customer.php - * */ public function testResetPasswordTokenSecondTime() { $this->expectException(\Magento\Framework\Exception\State\InputMismatchException::class); + $resetToken = 'lsdj579slkj5987slkj595lkj'; $password = 'new_Password123'; $email = 'customer@example.com'; @@ -367,11 +407,11 @@ public function testValidateResetPasswordLinkTokenWithoutId() } /** * @magentoDataFixture Magento/Customer/_files/two_customers.php - * */ public function testValidateResetPasswordLinkTokenAmbiguous() { $this->expectException(\Magento\Framework\Exception\State\ExpiredException::class); + $token = 'randomStr123'; $this->setResetPasswordData($token, 'Y-m-d H:i:s', 1); $this->setResetPasswordData($token, 'Y-m-d H:i:s', 2); @@ -383,11 +423,51 @@ public function testValidateResetPasswordLinkTokenAmbiguous() */ public function testResetPassword() { + /** @var SessionManagerInterface $session */ + $session = $this->objectManager->get(SessionManagerInterface::class); + $time = time(); + $customerId = 1; + + $session->start(); + + // open new session + $activeSessionId = uniqid("active-$time-"); + $this->startNewSession($activeSessionId); + $activeVisitor = $this->createVisitorSession($activeSessionId, $customerId); + $session->setVisitorData($activeVisitor->getData()); + + // open new session + $currentSessionId = uniqid("current-$time-"); + $this->startNewSession($currentSessionId); + $currentVisitor = $this->createVisitorSession($currentSessionId, $customerId); + $session->setVisitorData($currentVisitor->getData()); + $resetToken = 'lsdj579slkj5987slkj595lkj'; $password = 'new_Password123'; + $this->assertNull($this->getCustomerCutoff($customerId), 'Customer cutoff session should not be set.'); + $this->setResetPasswordData($resetToken, 'Y-m-d H:i:s'); $this->assertTrue($this->accountManagement->resetPassword('customer@example.com', $resetToken, $password)); + + $this->assertEquals( + $currentSessionId, + $session->getSessionId(), + 'Current session was renewed' + ); + + // open customer active session + $this->startNewSession($activeSessionId); + $this->assertNotNull($this->getCustomerCutoff($customerId), 'Customer cutoff session should be set.'); + // Make sure current visitor session is updated. + $this->assertLessThanOrEqual( + $this->getCustomerCutoff($customerId), + $this->getVisitorCreatedAt($activeVisitor->getId()) + ); + $this->assertGreaterThan( + $this->getCustomerCutoff($customerId), + $this->getVisitorCreatedAt($currentVisitor->getId()) + ); } /** @@ -480,11 +560,11 @@ public function testResetPasswordWithoutEmail() } /** * @magentoDataFixture Magento/Customer/_files/two_customers.php - * */ public function testResetPasswordAmbiguousToken() { $this->expectException(\Magento\Framework\Exception\State\ExpiredException::class); + $resetToken = 'lsdj579slkj5987slkj595lkj'; $password = 'new_Password123'; $this->setResetPasswordData($resetToken, 'Y-m-d H:i:s', 1); @@ -538,11 +618,11 @@ public function testResendConfirmationNoEmail() /** * @magentoDataFixture Magento/Customer/_files/customer.php - * */ public function testResendConfirmationNotNeeded() { $this->expectException(\Magento\Framework\Exception\State\InvalidTransitionException::class); + $this->accountManagement->resendConfirmation('customer@example.com', 1); } @@ -718,4 +798,66 @@ protected function setResetPasswordData( $customerModel->setRpTokenCreatedAt(date($date)); $customerModel->save(); } + + /** + * Returns the customers cutoff value + * + * @param int $customerId + * @return mixed + */ + private function getCustomerCutoff( + int $customerId + ) { + $customerModel = $this->objectManager->get(\Magento\Customer\Model\ResourceModel\Customer::class); + return $customerModel->findSessionCutOff($customerId); + } + + /** + * Returns the visitors created at value + * + * @param int $visitorId + * @return mixed + */ + private function getVisitorCreatedAt( + int $visitorId + ) { + $visitorModel = $this->objectManager->get(\Magento\Customer\Model\ResourceModel\Visitor::class); + return $visitorModel->fetchCreatedAt($visitorId); + } + + /** + * Starts a new session + * + * @param string $sessionId + */ + private function startNewSession(string $sessionId): void + { + /** @var SessionManagerInterface $session */ + $session = $this->objectManager->get(SessionManagerInterface::class); + // close session and cleanup session variable + $session->writeClose(); + $session->clearStorage(); + // open new session + $session->setSessionId($sessionId); + $session->start(); + } + + /** + * Creates a new visitor session + * + * @param string $sessionId + * @param int|null $customerId + * @return Visitor + * @throws \Exception + */ + private function createVisitorSession(string $sessionId, ?int $customerId = null): Visitor + { + /** @var Visitor $visitor */ + $visitor = Bootstrap::getObjectManager()->create(Visitor::class); + $visitor->setCustomerId($customerId); + $visitor->setSessionId($sessionId); + $visitor->setLastVisitAt((new \DateTime())->format(DateTime::DATETIME_PHP_FORMAT)); + $visitor->save(); + return $visitor; + } } diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/Metadata/Form/ImageTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/Metadata/Form/ImageTest.php index 4122ada789572..9b8ad360ef399 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Model/Metadata/Form/ImageTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/Metadata/Form/ImageTest.php @@ -107,7 +107,7 @@ public function testProcessCustomerAddressValue() $actual = $processCustomerAddressValueMethod->invoke($image, $imageFile); $this->assertEquals($this->expectedFileName, $actual); $this->assertFileExists($expectedPath); - $this->assertFileNotExists($tmpFilePath); + $this->assertFileDoesNotExist($tmpFilePath); } /** @@ -150,13 +150,14 @@ public function testProcessCustomerValue() $processCustomerAddressValueMethod->setAccessible(true); $result = $processCustomerAddressValueMethod->invoke($image, $imageFile); $this->assertInstanceOf('Magento\Framework\Api\ImageContent', $result); - $this->assertFileNotExists($tmpFilePath); + $this->assertFileDoesNotExist($tmpFilePath); } /** * Test for processCustomerValue method with invalid value * * @magentoAppIsolation enabled + * * @throws FileSystemException * @throws \ReflectionException */ diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/SessionTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/SessionTest.php index 364f010689d90..1e4854c0809f0 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Model/SessionTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/SessionTest.php @@ -6,16 +6,17 @@ namespace Magento\Customer\Model; use Magento\Framework\App\PageCache\FormKey; +use Magento\Framework\App\Response\Http as HttpResponse; use Magento\Framework\App\ResponseInterface; use Magento\Framework\Session\SidResolverInterface; use Magento\Framework\Stdlib\Cookie\CookieMetadataFactory; use Magento\Framework\Stdlib\Cookie\PublicCookieMetadata; use Magento\TestFramework\Helper\Bootstrap; -use Magento\Framework\App\Response\Http as HttpResponse; /** * @magentoDataFixture Magento/Customer/_files/customer.php * @magentoAppIsolation enabled + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class SessionTest extends \PHPUnit\Framework\TestCase { @@ -124,7 +125,7 @@ public function testNoSid(): void $this->assertStringNotContainsString(SidResolverInterface::SESSION_ID_QUERY_PARAM . '=', $location); $beforeAuthUrl = $this->_customerSession->getData('before_auth_url'); $this->assertNotEmpty($beforeAuthUrl); - $this->assertStringNotContainsString(SidResolverInterface::SESSION_ID_QUERY_PARAM .'=', $beforeAuthUrl); + $this->assertStringNotContainsString(SidResolverInterface::SESSION_ID_QUERY_PARAM . '=', $beforeAuthUrl); $this->_customerSession->authenticate('/customer/account'); $location = (string)$this->response->getHeader('Location'); diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/VisitorTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/VisitorTest.php index 0d5a5f262d1a6..71781244362b8 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Model/VisitorTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/VisitorTest.php @@ -63,23 +63,23 @@ public function testBindCustomerLogout() */ public function testClean() { - $customerIdNow = 1; + $customerIdNow = '1'; + $createdAtNow = date('Y-m-d H:i:s', time()); $lastVisitNow = date('Y-m-d H:i:s', time()); - $sessionIdNow = 'asaswljxvgklasdflkjasieasd'; $customerIdPast = null; + $createdAtPast = date('Y-m-d H:i:s', time() - 172800); $lastVisitPast = date('Y-m-d H:i:s', time() - 172800); - $sessionIdPast = 'kui0aa57nqddl8vk7k6ohgi352'; /** @var \Magento\Customer\Model\Visitor $visitor */ $visitor = Bootstrap::getObjectManager()->get(\Magento\Customer\Model\Visitor::class); $visitor->setCustomerId($customerIdPast); - $visitor->setSessionId($sessionIdPast); + $visitor->setCreatedAt($createdAtPast); $visitor->setLastVisitAt($lastVisitPast); $visitor->save(); $visitorIdPast = $visitor->getId(); $visitor->unsetData(); $visitor->setCustomerId($customerIdNow); - $visitor->setSessionId($sessionIdNow); + $visitor->setCreatedAt($createdAtNow); $visitor->setLastVisitAt($lastVisitNow); $visitor->save(); $visitorIdNow = $visitor->getId(); @@ -90,19 +90,16 @@ public function testClean() $this->assertEquals([], $visitor->getData()); $visitor->unsetData(); $visitor->load($visitorIdNow); - $this->assertEquals( - [ - 'visitor_id' => $visitorIdNow, - 'customer_id' => $customerIdNow, - 'session_id' => $sessionIdNow, - 'last_visit_at' => $lastVisitNow - ], - $visitor->getData() - ); + $result = $visitor->getData(); + $this->assertEquals($visitorIdNow, $result['visitor_id']); + $this->assertEquals($customerIdNow, $result['customer_id']); + $this->assertGreaterThanOrEqual(strtotime($createdAtNow), strtotime($result['created_at'])); + $this->assertEquals($lastVisitNow, $result['last_visit_at']); + $this->assertNull($result['session_id']); } /** - * Authenticate customer and return its DTO + * Authenticate customer and return its DTOCustomer/Model/VisitorTest * @param string $username * @param string $password * @return \Magento\Customer\Api\Data\CustomerInterface diff --git a/dev/tests/integration/testsuite/Magento/Framework/HTTP/AsyncClientInterfaceTest.php b/dev/tests/integration/testsuite/Magento/Framework/HTTP/AsyncClientInterfaceTest.php index aeec81dfbd8db..5cf6e44408899 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/HTTP/AsyncClientInterfaceTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/HTTP/AsyncClientInterfaceTest.php @@ -35,16 +35,16 @@ protected function setUp(): void */ public function testRequest(): void { - $request = new Request('https://magento.com/home-page', Request::METHOD_GET, [], null); + $request = new Request('https://magento.com', Request::METHOD_GET, [], null); $response1 = $this->client->request($request); $response2 = $this->client->request($request); $this->assertEquals(200, $response2->get()->getStatusCode()); $this->assertEquals(200, $response1->get()->getStatusCode()); - $this->assertStringContainsString('Magento. All Rights Reserved', $response1->get()->getBody()); - $this->assertStringContainsString('Magento. All Rights Reserved', $response2->get()->getBody()); + $this->assertStringContainsString('Magento Commerce', $response1->get()->getBody()); + $this->assertStringContainsString('Magento Commerce', $response2->get()->getBody()); $date1 = new \DateTime($response1->get()->getHeaders()['date']); $date2 = new \DateTime($response2->get()->getHeaders()['date']); - $this->assertLessThanOrEqual(1, abs($date1->format('U') - $date2->format('U'))); + $this->assertLessThanOrEqual(1, abs((int)$date1->format('U') - (int)$date2->format('U'))); } /** diff --git a/dev/tests/integration/testsuite/Magento/Framework/Session/SaveHandler/DbTableTest.php b/dev/tests/integration/testsuite/Magento/Framework/Session/SaveHandler/DbTableTest.php index 28c0bc8e73f7a..363eec6fc5626 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Session/SaveHandler/DbTableTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Session/SaveHandler/DbTableTest.php @@ -6,6 +6,7 @@ namespace Magento\Framework\Session\SaveHandler; use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Encryption\EncryptorInterface; class DbTableTest extends \PHPUnit\Framework\TestCase { @@ -77,6 +78,11 @@ class DbTableTest extends \PHPUnit\Framework\TestCase */ protected $_sessionTable; + /** + * @var EncryptorInterface + */ + private $_encryptor; + /** * @return void */ @@ -89,6 +95,7 @@ protected function setUp(): void $resource = $this->_objectManager->get(\Magento\Framework\App\ResourceConnection::class); $this->_connection = $resource->getConnection(); $this->_sessionTable = $resource->getTableName('session'); + $this->_encryptor = $this->_objectManager->get(EncryptorInterface::class); // session stores serialized objects with protected properties // we need to test this case to ensure that DB adapter successfully processes "\0" symbols in serialized data @@ -121,10 +128,14 @@ public function testOpenAndClose() */ public function testWriteReadDestroy() { + // We have to use serialize here. + // phpcs:ignore Magento2.Security.InsecureFunction $data = serialize($this->_sessionData[self::SESSION_NEW]); $this->_model->write(self::SESSION_ID, $data); $this->assertEquals($data, $this->_model->read(self::SESSION_ID)); + // We have to use serialize here. + // phpcs:ignore Magento2.Security.InsecureFunction $data = serialize($this->_sessionData[self::SESSION_EXISTS]); $this->_model->write(self::SESSION_ID, $data); $this->assertEquals($data, $this->_model->read(self::SESSION_ID)); @@ -151,6 +162,8 @@ public function testGc() */ public function testWriteEncoded() { + // We have to use serialize here. + // phpcs:ignore Magento2.Security.InsecureFunction $data = serialize($this->_sessionData[self::SESSION_NEW]); $this->_model->write(self::SESSION_ID, $data); @@ -159,10 +172,10 @@ public function testWriteEncoded() )->where( self::COLUMN_SESSION_ID . ' = :' . self::COLUMN_SESSION_ID ); - $bind = [self::COLUMN_SESSION_ID => self::SESSION_ID]; + $bind = [self::COLUMN_SESSION_ID => $this->_encryptor->hash(self::SESSION_ID)]; $session = $this->_connection->fetchRow($select, $bind); - $this->assertEquals(self::SESSION_ID, $session[self::COLUMN_SESSION_ID]); + $this->assertEquals($this->_encryptor->hash(self::SESSION_ID), $session[self::COLUMN_SESSION_ID]); $this->assertTrue( ctype_digit((string)$session[self::COLUMN_SESSION_EXPIRES]), 'Value of session expire field must have integer type' @@ -179,6 +192,7 @@ public function readEncodedDataProvider() { // we can't use object data as a fixture because not encoded serialized object // might cause DB adapter fatal error, so we have to use array as a fixture + // phpcs:ignore Magento2.Security.InsecureFunction $sessionData = serialize($this->_sourceData[self::SESSION_NEW]); return [ 'session_encoded' => ['$sessionData' => base64_encode($sessionData)], @@ -197,10 +211,15 @@ public function readEncodedDataProvider() */ public function testReadEncoded($sessionData) { - $sessionRecord = [self::COLUMN_SESSION_ID => self::SESSION_ID, self::COLUMN_SESSION_DATA => $sessionData]; + $sessionRecord = [ + self::COLUMN_SESSION_ID => $this->_encryptor->hash(self::SESSION_ID), + self::COLUMN_SESSION_DATA => $sessionData + ]; $this->_connection->insertOnDuplicate($this->_sessionTable, $sessionRecord, [self::COLUMN_SESSION_DATA]); $sessionData = $this->_model->read(self::SESSION_ID); + // We have to use unserialize here. + // phpcs:ignore Magento2.Security.InsecureFunction $this->assertEquals($this->_sourceData[self::SESSION_NEW], unserialize($sessionData)); } } diff --git a/dev/tests/integration/testsuite/Magento/Multishipping/Controller/Checkout/AddressesPostTest.php b/dev/tests/integration/testsuite/Magento/Multishipping/Controller/Checkout/AddressesPostTest.php new file mode 100644 index 0000000000000..93fd4b07bf7de --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Multishipping/Controller/Checkout/AddressesPostTest.php @@ -0,0 +1,150 @@ +quoteRepository = $this->_objectManager->get(QuoteRepository::class); + } + + /** + * @magentoDataFixture Magento/Checkout/_files/quote_with_address_saved.php + */ + public function testExecute(): void + { + $quote = $this->getQuote('test_order_1'); + $this->setMultiShippingToQuote($quote); + $quoteItems = $quote->getItems(); + $quoteItemId = array_shift($quoteItems)->getItemId(); + $this->loginCustomer(); + + $qty = 3; + $productPrice = 10; + $request = [ + 'ship' => [ + 1 => [ + $quoteItemId => [ + 'qty' => $qty, + 'address' => 1, + ], + ], + ] + ]; + $this->getRequest()->setMethod(HttpRequest::METHOD_POST); + $this->getRequest()->setPostValue($request); + $this->dispatch('multishipping/checkout/addressesPost'); + $freshQuote = $this->getQuote('test_order_1'); + + $this->assertEquals($qty, $freshQuote->getItemsQty()); + $this->assertEquals($productPrice * $qty, $freshQuote->getGrandTotal()); + } + + /** + * @magentoDataFixture Magento/Checkout/_files/quote_with_address_saved.php + */ + public function testExecuteFail(): void + { + $msg = 'Verify the shipping address information and continue.'; + + $quote = $this->getQuote('test_order_1'); + $this->setMultiShippingToQuote($quote); + $quoteItems = $quote->getItems(); + $quoteItemId = array_shift($quoteItems)->getItemId(); + $this->loginCustomer(); + $request = [ + 'ship' => [ + 1 => [ + $quoteItemId => [ + 'qty' => 1, + 'address' => $quoteItemId . 'zb3', + ], + ], + ], + ]; + $this->getRequest()->setMethod(HttpRequest::METHOD_POST); + $this->getRequest()->setPostValue($request); + $this->dispatch('multishipping/checkout/addressesPost'); + + $this->assertSessionMessages($this->equalTo([$msg]), MessageInterface::TYPE_ERROR); + } + + /** + * @param CartInterface $quote + * @return void + */ + private function setMultiShippingToQuote(CartInterface $quote): void + { + $quote->setIsMultiShipping(1); + $this->quoteRepository->save($quote); + } + + /** + * Authenticates customer and creates customer session. + * + * @return void + */ + private function loginCustomer(): void + { + $logger = $this->createMock(LoggerInterface::class); + /** @var AccountManagementInterface $service */ + $service = $this->_objectManager->create(AccountManagementInterface::class); + try { + $customer = $service->authenticate('customer@example.com', 'password'); + } catch (LocalizedException $e) { + $this->fail($e->getMessage()); + } + /** @var CustomerSession $customerSession */ + $customerSession = $this->_objectManager->get(CustomerSession::class, [$logger]); + $customerSession->setCustomerDataAsLoggedIn($customer); + } + + /** + * Gets quote by reserved order id. + * + * @param string $reservedOrderId + * @return CartInterface + */ + private function getQuote(string $reservedOrderId): CartInterface + { + /** @var SearchCriteriaBuilder $searchCriteriaBuilder */ + $searchCriteriaBuilder = $this->_objectManager->create(SearchCriteriaBuilder::class); + $searchCriteria = $searchCriteriaBuilder->addFilter('reserved_order_id', $reservedOrderId)->create(); + /** @var QuoteRepository $quoteRepository */ + $quoteRepository = $this->_objectManager->get(QuoteRepository::class); + $items = $quoteRepository->getList($searchCriteria)->getItems(); + + return array_pop($items); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Security/Model/AdminSessionsManagerTest.php b/dev/tests/integration/testsuite/Magento/Security/Model/AdminSessionsManagerTest.php index 2a7632f88e4f8..2fd624f86501e 100644 --- a/dev/tests/integration/testsuite/Magento/Security/Model/AdminSessionsManagerTest.php +++ b/dev/tests/integration/testsuite/Magento/Security/Model/AdminSessionsManagerTest.php @@ -5,6 +5,9 @@ */ namespace Magento\Security\Model; +/** + * @magentoAppArea adminhtml + */ class AdminSessionsManagerTest extends \PHPUnit\Framework\TestCase { /** @@ -79,9 +82,9 @@ public function testProcessLogout() \Magento\TestFramework\Bootstrap::ADMIN_NAME, \Magento\TestFramework\Bootstrap::ADMIN_PASSWORD ); - $sessionId = $this->authSession->getSessionId(); + $adminSessionInfoId = $this->authSession->getAdminSessionInfoId(); $this->auth->logout(); - $this->adminSessionInfo->load($sessionId, 'session_id'); + $this->adminSessionInfo->load($adminSessionInfoId, 'id'); $this->assertEquals($this->adminSessionInfo->getStatus(), AdminSessionInfo::LOGGED_OUT); } @@ -96,8 +99,8 @@ public function testIsAdminSessionIsCreated() \Magento\TestFramework\Bootstrap::ADMIN_NAME, \Magento\TestFramework\Bootstrap::ADMIN_PASSWORD ); - $sessionId = $this->authSession->getSessionId(); - $this->adminSessionInfo->load($sessionId, 'session_id'); + $adminSessionInfoId = $this->authSession->getAdminSessionInfoId(); + $this->adminSessionInfo->load($adminSessionInfoId, 'id'); $this->assertGreaterThanOrEqual(1, (int)$this->adminSessionInfo->getId()); $this->auth->logout(); } @@ -122,7 +125,8 @@ public function testTerminateOtherSessionsProcessLogin() \Magento\TestFramework\Bootstrap::ADMIN_NAME, \Magento\TestFramework\Bootstrap::ADMIN_PASSWORD ); - $session->load('669e2e3d752e8', 'session_id'); + $adminSessionInfoId = $this->authSession->getAdminSessionInfoId(); + $session->load($adminSessionInfoId, 'id'); $this->assertEquals( AdminSessionInfo::LOGGED_OUT_BY_LOGIN, (int) $session->getStatus() @@ -140,11 +144,11 @@ public function testGetCurrentSession() \Magento\TestFramework\Bootstrap::ADMIN_NAME, \Magento\TestFramework\Bootstrap::ADMIN_PASSWORD ); - $sessionId = $this->authSession->getSessionId(); - $this->adminSessionInfo->load($sessionId, 'session_id'); + $adminSessionInfoId = $this->authSession->getAdminSessionInfoId(); + $this->adminSessionInfo->load($adminSessionInfoId, 'id'); $this->assertEquals( - $this->adminSessionInfo->getSessionId(), - $this->adminSessionsManager->getCurrentSession()->getSessionId() + $this->adminSessionInfo->getId(), + $this->adminSessionsManager->getCurrentSession()->getId() ); } @@ -186,10 +190,11 @@ protected function getCollectionForLogoutOtherUserSessions(\Magento\Security\Mod { /** @var \Magento\Security\Model\ResourceModel\AdminSessionInfo\Collection $collection */ $collection = $session->getResourceCollection(); + $adminSessionInfoId = $this->authSession->getAdminSessionInfoId(); $collection->filterByUser( $this->authSession->getUser()->getId(), \Magento\Security\Model\AdminSessionInfo::LOGGED_IN, - $this->authSession->getSessionId() + $adminSessionInfoId ) ->filterExpiredSessions(100) ->load(); diff --git a/dev/tests/integration/testsuite/Magento/Security/Model/Plugin/AuthSessionTest.php b/dev/tests/integration/testsuite/Magento/Security/Model/Plugin/AuthSessionTest.php index 2414c78721ac9..9b0e4b10dfdd3 100644 --- a/dev/tests/integration/testsuite/Magento/Security/Model/Plugin/AuthSessionTest.php +++ b/dev/tests/integration/testsuite/Magento/Security/Model/Plugin/AuthSessionTest.php @@ -91,7 +91,7 @@ public function testConsecutiveProcessProlong() \Magento\TestFramework\Bootstrap::ADMIN_NAME, \Magento\TestFramework\Bootstrap::ADMIN_PASSWORD ); - $sessionId = $this->authSession->getSessionId(); + $adminSessionInfoId = $this->authSession->getAdminSessionInfoId(); $prolongsDiff = log($this->securityConfig->getAdminSessionLifetime()) - 2; // X from comment above $dateInPast = $this->dateTime->formatDate($this->authSession->getUpdatedAt() - $prolongsDiff); $this->adminSessionsManager->getCurrentSession() @@ -100,15 +100,14 @@ public function testConsecutiveProcessProlong() $dateInPast ) ->save(); - $this->adminSessionInfo->load($sessionId, 'session_id'); + $this->adminSessionInfo->load($adminSessionInfoId, 'id'); $oldUpdatedAt = $this->adminSessionInfo->getUpdatedAt(); $this->authSession->prolong(); - $this->adminSessionInfo->load($sessionId, 'session_id'); + $this->adminSessionInfo->load($adminSessionInfoId, 'id'); $updatedAt = $this->adminSessionInfo->getUpdatedAt(); $this->assertSame(strtotime($oldUpdatedAt), strtotime($updatedAt)); } - /** * Test of prolong user action * session manager will trigger new prolong if previous prolong was more than X sec ago @@ -123,7 +122,7 @@ public function testProcessProlong() \Magento\TestFramework\Bootstrap::ADMIN_NAME, \Magento\TestFramework\Bootstrap::ADMIN_PASSWORD ); - $sessionId = $this->authSession->getSessionId(); + $adminSessionInfoId = $this->authSession->getAdminSessionInfoId(); $prolongsDiff = 4 * log($this->securityConfig->getAdminSessionLifetime()) + 2; // X from comment above $dateInPast = $this->dateTime->formatDate($this->authSession->getUpdatedAt() - $prolongsDiff); $this->adminSessionsManager->getCurrentSession() @@ -132,10 +131,10 @@ public function testProcessProlong() $dateInPast ) ->save(); - $this->adminSessionInfo->load($sessionId, 'session_id'); + $this->adminSessionInfo->load($adminSessionInfoId, 'id'); $oldUpdatedAt = $this->adminSessionInfo->getUpdatedAt(); $this->authSession->prolong(); - $this->adminSessionInfo->load($sessionId, 'session_id'); + $this->adminSessionInfo->load($adminSessionInfoId, 'id'); $updatedAt = $this->adminSessionInfo->getUpdatedAt(); $this->assertGreaterThan(strtotime($oldUpdatedAt), strtotime($updatedAt)); diff --git a/dev/tests/integration/testsuite/Magento/Security/Model/ResourceModel/AdminSessionInfoTest.php b/dev/tests/integration/testsuite/Magento/Security/Model/ResourceModel/AdminSessionInfoTest.php index e2092badcfbe0..5319d6de7264e 100644 --- a/dev/tests/integration/testsuite/Magento/Security/Model/ResourceModel/AdminSessionInfoTest.php +++ b/dev/tests/integration/testsuite/Magento/Security/Model/ResourceModel/AdminSessionInfoTest.php @@ -37,7 +37,6 @@ protected function tearDown(): void public function getTestData() { return [ - 'session_id' => '569e273d752e9', 'user_id' => 1, 'status' => 1, 'created_at' => '2016-01-21 15:00:00', diff --git a/dev/tests/integration/testsuite/Magento/Widget/Model/Widget/InstanceTest.php b/dev/tests/integration/testsuite/Magento/Widget/Model/Widget/InstanceTest.php index 1770898938e1d..0a56027f0f23a 100644 --- a/dev/tests/integration/testsuite/Magento/Widget/Model/Widget/InstanceTest.php +++ b/dev/tests/integration/testsuite/Magento/Widget/Model/Widget/InstanceTest.php @@ -77,9 +77,9 @@ public function testGetWidgetSupportedContainers() $this->_model->setType(\Magento\Catalog\Block\Product\Widget\NewWidget::class); $containers = $this->_model->getWidgetSupportedContainers(); $this->assertIsArray($containers); - $this->assertContains('sidebar.main',$containers); - $this->assertContains('content',$containers); - $this->assertContains('sidebar.additional',$containers); + $this->assertContains('sidebar.main', $containers); + $this->assertContains('content', $containers); + $this->assertContains('sidebar.additional', $containers); return $this->_model; } @@ -135,7 +135,10 @@ public function testGenerateLayoutUpdateXml(\Magento\Widget\Model\Widget\Instanc $this->assertStringContainsString('fixed', $result); $this->assertStringContainsString('types', $result); $this->assertStringContainsString('type_1,type_2', $result); - $this->assertStringContainsString('conditions_encoded', $result); + $this->assertStringContainsString( + 'conditions_encoded', + $result + ); $this->assertStringContainsString('`Magento||CatalogWidget||Model||Rule||Condition||Combine`', $result); $this->assertStringContainsString('`Magento||CatalogWidget||Model||Rule||Condition||Product`', $result); } @@ -168,4 +171,22 @@ public function beforeSaveDataProvider() ] ]; } + + /** + * @param Instance $model + * @depends testGetWidgetConfigAsArray + */ + public function testGenerateLayoutUpdateXmlWithInvalidParamName(\Magento\Widget\Model\Widget\Instance $model) + { + $params = [ + 'block_id' => '2', + 'block_id2' + . '' => 'some_value', + ]; + $this->expectException('\Magento\Framework\Exception\LocalizedException'); + $this->expectExceptionMessage('Layout update is invalid'); + $model->setData('widget_parameters', $params); + $model->generateLayoutUpdateXml('content'); + } } diff --git a/dev/tests/integration/testsuite/Magento/Wishlist/Controller/SharedTest.php b/dev/tests/integration/testsuite/Magento/Wishlist/Controller/SharedTest.php index 1e4f6c6584e9a..3e1c3451a08c7 100644 --- a/dev/tests/integration/testsuite/Magento/Wishlist/Controller/SharedTest.php +++ b/dev/tests/integration/testsuite/Magento/Wishlist/Controller/SharedTest.php @@ -4,8 +4,12 @@ * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Wishlist\Controller; +use Magento\Framework\App\Request\Http as HttpRequest; + class SharedTest extends \Magento\TestFramework\TestCase\AbstractController { /** @@ -14,6 +18,7 @@ class SharedTest extends \Magento\TestFramework\TestCase\AbstractController */ public function testAllcartAction() { + $this->getRequest()->setMethod(HttpRequest::METHOD_POST); $this->getRequest()->setParam('code', 'fixture_unique_code'); $this->dispatch('wishlist/shared/allcart'); diff --git a/lib/internal/Magento/Framework/Amqp/composer.json b/lib/internal/Magento/Framework/Amqp/composer.json index fc65e37d12ecf..d50ffdda7ef39 100644 --- a/lib/internal/Magento/Framework/Amqp/composer.json +++ b/lib/internal/Magento/Framework/Amqp/composer.json @@ -1,25 +1,27 @@ { "name": "magento/framework-amqp", "description": "N/A", - "config": { - "sort-packages": true - }, "type": "magento2-library", "license": [ "OSL-3.0", "AFL-3.0" ], + "config": { + "sort-packages": true + }, + "version": "100.3.6", "require": { - "magento/framework": "*", + "magento/framework": "102.0.*", "php": "~7.3.0||~7.4.0", "php-amqplib/php-amqplib": "~2.7.0||~2.10.0" }, "autoload": { - "psr-4": { - "Magento\\Framework\\Amqp\\": "" - }, "files": [ "registration.php" - ] + ], + "psr-4": { + "Magento\\Framework\\Amqp\\": "" + } } } + diff --git a/lib/internal/Magento/Framework/Bulk/composer.json b/lib/internal/Magento/Framework/Bulk/composer.json index b8e0992182169..b3f65a7bd8fea 100644 --- a/lib/internal/Magento/Framework/Bulk/composer.json +++ b/lib/internal/Magento/Framework/Bulk/composer.json @@ -1,24 +1,26 @@ { "name": "magento/framework-bulk", "description": "N/A", - "config": { - "sort-packages": true - }, "type": "magento2-library", "license": [ "OSL-3.0", "AFL-3.0" ], + "config": { + "sort-packages": true + }, + "version": "100.3.6", "require": { - "magento/framework": "*", + "magento/framework": "102.0.*", "php": "~7.3.0||~7.4.0" }, "autoload": { - "psr-4": { - "Magento\\Framework\\Bulk\\": "" - }, "files": [ "registration.php" - ] + ], + "psr-4": { + "Magento\\Framework\\Bulk\\": "" + } } } + diff --git a/lib/internal/Magento/Framework/Filesystem/Directory/CompositePathValidator.php b/lib/internal/Magento/Framework/Filesystem/Directory/CompositePathValidator.php new file mode 100644 index 0000000000000..0be7d63963e4f --- /dev/null +++ b/lib/internal/Magento/Framework/Filesystem/Directory/CompositePathValidator.php @@ -0,0 +1,42 @@ +validators = $validators; + } + + /** + * @inheritDoc + */ + public function validate( + string $directoryPath, + string $path, + ?string $scheme = null, + bool $absolutePath = false + ): void { + foreach ($this->validators as $validator) { + $validator->validate($directoryPath, $path, $scheme, $absolutePath); + } + } +} diff --git a/lib/internal/Magento/Framework/Filesystem/Directory/DenyListPathValidator.php b/lib/internal/Magento/Framework/Filesystem/Directory/DenyListPathValidator.php new file mode 100644 index 0000000000000..fe49a37ba234e --- /dev/null +++ b/lib/internal/Magento/Framework/Filesystem/Directory/DenyListPathValidator.php @@ -0,0 +1,105 @@ +driver = $driver; + } + + /** + * @inheritDoc + */ + public function validate( + string $directoryPath, + string $path, + ?string $scheme = null, + bool $absolutePath = false + ): void { + $realDirectoryPath = $this->driver->getRealPathSafety($directoryPath); + $fullPath = $this->driver->getAbsolutePath( + $realDirectoryPath . DIRECTORY_SEPARATOR, + $path, + $scheme + ); + if (!$absolutePath) { + $actualPath = $this->driver->getRealPathSafety($fullPath); + } else { + $actualPath = $this->driver->getRealPathSafety($path); + } + + if (in_array($fullPath, $this->exceptionList, true)) { + return; + } + + foreach ($this->fileDenyList as $file) { + $baseName = pathinfo($actualPath, PATHINFO_BASENAME); + if (strpos($baseName, $file) !== false || preg_match('#' . "\." . $file . '#', $fullPath)) { + throw new ValidatorException( + new Phrase('"%1" is not a valid file path', [$path]) + ); + } + } + } + + /** + * Allow addition of new exceptions given full path + * + * @param string $fullPath + */ + public function addException(string $fullPath) + { + if (!in_array($fullPath, $this->exceptionList)) { + array_push($this->exceptionList, $fullPath); + } + } + + /** + * Allow addition of new exceptions given full path + * + * @param string $fullPath + */ + public function removeException(string $fullPath) + { + if (($key = array_search($fullPath, $this->exceptionList)) !== false) { + unset($this->exceptionList[$key]); + } + } +} diff --git a/lib/internal/Magento/Framework/Filesystem/Directory/Write.php b/lib/internal/Magento/Framework/Filesystem/Directory/Write.php index f926a72726e21..46ea7e390be52 100644 --- a/lib/internal/Magento/Framework/Filesystem/Directory/Write.php +++ b/lib/internal/Magento/Framework/Filesystem/Directory/Write.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\Framework\Filesystem\Directory; @@ -54,6 +55,7 @@ public function __construct( */ protected function assertWritable($path) { + $this->validatePath($path); if ($this->isWritable($path) === false) { $path = $this->getAbsolutePath($path); throw new FileSystemException(new Phrase('The path "%1" is not writable.', [$path])); @@ -109,6 +111,7 @@ public function create($path = null) public function renameFile($path, $newPath, WriteInterface $targetDirectory = null) { $this->validatePath($path); + $this->validatePath($newPath); $this->assertIsFile($path); $targetDirectory = $targetDirectory ?: $this; if (!$targetDirectory->isExist($this->driver->getParentDirectory($newPath))) { @@ -116,7 +119,7 @@ public function renameFile($path, $newPath, WriteInterface $targetDirectory = nu } $absolutePath = $this->driver->getAbsolutePath($this->path, $path); $absoluteNewPath = $targetDirectory->getAbsolutePath($newPath); - return $this->driver->rename($absolutePath, $absoluteNewPath, $targetDirectory->driver); + return $this->driver->rename($absolutePath, $absoluteNewPath, $targetDirectory->getDriver()); } /** @@ -132,6 +135,7 @@ public function renameFile($path, $newPath, WriteInterface $targetDirectory = nu public function copyFile($path, $destination, WriteInterface $targetDirectory = null) { $this->validatePath($path); + $this->validatePath($destination); $this->assertIsFile($path); $targetDirectory = $targetDirectory ?: $this; @@ -157,6 +161,7 @@ public function copyFile($path, $destination, WriteInterface $targetDirectory = public function createSymlink($path, $destination, WriteInterface $targetDirectory = null) { $this->validatePath($path); + $this->validatePath($destination); $targetDirectory = $targetDirectory ?: $this; $parentDirectory = $this->driver->getParentDirectory($destination); if (!$targetDirectory->isExist($parentDirectory)) { @@ -234,8 +239,9 @@ private function deleteFilesRecursively(string $path) foreach ($entitiesList as $entityPath) { if ($this->driver->isFile($entityPath)) { try { + $this->validatePath($entityPath); $this->driver->deleteFile($entityPath); - } catch (FileSystemException $e) { + } catch (FileSystemException | ValidatorException $e) { $exceptionMessages[] = $e->getMessage(); } } @@ -349,7 +355,12 @@ public function openFile($path, $mode = 'w') */ public function writeFile($path, $content, $mode = 'w+') { - return $this->openFile($path, $mode)->write($content); + $this->validatePath($path); + $file = $this->openFile($path, $mode); + $result = $file->write($content); + $file->close(); + + return $result; } /** diff --git a/lib/internal/Magento/Framework/Filesystem/Directory/WriteFactory.php b/lib/internal/Magento/Framework/Filesystem/Directory/WriteFactory.php index ff14b12f62047..c9369130c320d 100644 --- a/lib/internal/Magento/Framework/Filesystem/Directory/WriteFactory.php +++ b/lib/internal/Magento/Framework/Filesystem/Directory/WriteFactory.php @@ -3,10 +3,16 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + +declare(strict_types=1); + namespace Magento\Framework\Filesystem\Directory; use Magento\Framework\Filesystem\DriverPool; +/** + * The factory of the filesystem directory instances for write operations. + */ class WriteFactory { /** @@ -16,14 +22,25 @@ class WriteFactory */ private $driverPool; + /** + * Deny List Validator + * + * @var DenyListPathValidator + */ + private $denyListPathValidator; + /** * Constructor * * @param DriverPool $driverPool + * @param DenyListPathValidator|null $denyListPathValidator */ - public function __construct(DriverPool $driverPool) - { + public function __construct( + DriverPool $driverPool, + ?DenyListPathValidator $denyListPathValidator = null + ) { $this->driverPool = $driverPool; + $this->denyListPathValidator = $denyListPathValidator; } /** @@ -32,7 +49,7 @@ public function __construct(DriverPool $driverPool) * @param string $path * @param string $driverCode * @param int $createPermissions - * @return \Magento\Framework\Filesystem\Directory\Write + * @return Write */ public function create($path, $driverCode = DriverPool::FILE, $createPermissions = null) { @@ -41,12 +58,23 @@ public function create($path, $driverCode = DriverPool::FILE, $createPermissions $this->driverPool ); + if ($this->denyListPathValidator === null) { + $this->denyListPathValidator = new DenyListPathValidator($driver); + } + + $validators = [ + 'pathValidator' => new PathValidator($driver), + 'denyListPathValidator' => $this->denyListPathValidator + ]; + + $pathValidator = new CompositePathValidator($validators); + return new Write( $factory, $driver, $path, $createPermissions, - new PathValidator($driver) + $pathValidator ); } } diff --git a/lib/internal/Magento/Framework/Filesystem/Test/Unit/Directory/WriteTest.php b/lib/internal/Magento/Framework/Filesystem/Test/Unit/Directory/WriteTest.php index b408e83a17e46..dbc5ac2a24978 100644 --- a/lib/internal/Magento/Framework/Filesystem/Test/Unit/Directory/WriteTest.php +++ b/lib/internal/Magento/Framework/Filesystem/Test/Unit/Directory/WriteTest.php @@ -48,7 +48,7 @@ protected function setUp(): void $this->fileFactory, $this->driver, $this->path, - 'cool-permissions' + 0555 ); } diff --git a/lib/internal/Magento/Framework/Filter/Input/MaliciousCode.php b/lib/internal/Magento/Framework/Filter/Input/MaliciousCode.php index 55a8a5a3742f9..532816a01fea4 100644 --- a/lib/internal/Magento/Framework/Filter/Input/MaliciousCode.php +++ b/lib/internal/Magento/Framework/Filter/Input/MaliciousCode.php @@ -8,6 +8,9 @@ namespace Magento\Framework\Filter\Input; +/** + * Class responsible for filtering malicious code. + */ class MaliciousCode implements \Zend_Filter_Interface { /** @@ -31,6 +34,8 @@ class MaliciousCode implements \Zend_Filter_Interface 'onload|onunload|onerror)=[^<]*(?=\/*\>)/Uis', //tags '/<\/?(script|meta|link|frame|iframe|object).*>/Uis', + //scripts + '/<\?\s*?(php|=).*>/Uis', //base64 usage '/src=[^<]*base64[^<]*(?=\/*\>)/Uis', ]; diff --git a/lib/internal/Magento/Framework/Filter/Test/Unit/Input/MaliciousCodeTest.php b/lib/internal/Magento/Framework/Filter/Test/Unit/Input/MaliciousCodeTest.php index 1a1eea19e9415..4d1bb0e85d25a 100644 --- a/lib/internal/Magento/Framework/Filter/Test/Unit/Input/MaliciousCodeTest.php +++ b/lib/internal/Magento/Framework/Filter/Test/Unit/Input/MaliciousCodeTest.php @@ -110,7 +110,19 @@ public function filterDataProvider() 'Nested malicious tags' => [ 'pt>alert(1);pt>', 'alert(1);', - ] + ], + 'Nested scripts' => [ + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + ], ]; } diff --git a/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php b/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php index 2b9ce9b01b5c4..46e43ef6fe7ca 100644 --- a/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php +++ b/lib/internal/Magento/Framework/GraphQl/Query/QueryComplexityLimiter.php @@ -7,10 +7,16 @@ namespace Magento\Framework\GraphQl\Query; +use GraphQL\Language\AST\Node; +use GraphQL\Language\AST\NodeKind; +use GraphQL\Language\Parser; +use GraphQL\Language\Source; +use GraphQL\Language\Visitor; use GraphQL\Validator\DocumentValidator; use GraphQL\Validator\Rules\DisableIntrospection; use GraphQL\Validator\Rules\QueryDepth; use GraphQL\Validator\Rules\QueryComplexity; +use Magento\Framework\GraphQl\Exception\GraphQlInputException; /** * QueryComplexityLimiter @@ -57,6 +63,7 @@ public function __construct( * Sets limits for query complexity * * @return void + * @throws GraphQlInputException */ public function execute(): void { @@ -66,4 +73,39 @@ public function execute(): void ); DocumentValidator::addRule(new QueryDepth($this->queryDepth)); } + + /** + * Performs a preliminary field count check before performing more extensive query validation. + * + * This is necessary for performance optimization, as extremely large queries require a substantial + * amount of time to fully validate and can affect server performance. + * + * @param string $query + * @throws GraphQlInputException + */ + public function validateFieldCount(string $query): void + { + if (!empty($query)) { + $totalFieldCount = 0; + $queryAst = Parser::parse(new Source($query ?: '', 'GraphQL')); + Visitor::visit( + $queryAst, + [ + 'leave' => [ + NodeKind::FIELD => function (Node $node) use (&$totalFieldCount) { + $totalFieldCount++; + } + ] + ] + ); + + if ($totalFieldCount > $this->queryComplexity) { + throw new GraphQlInputException(__( + 'Max query complexity should be %1 but got %2.', + $this->queryComplexity, + $totalFieldCount + )); + } + } + } } diff --git a/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php b/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php index 3cebcc86063f3..aab54e93a7eb5 100644 --- a/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php +++ b/lib/internal/Magento/Framework/GraphQl/Query/QueryProcessor.php @@ -8,6 +8,7 @@ namespace Magento\Framework\GraphQl\Query; use Magento\Framework\GraphQl\Exception\ExceptionFormatter; +use Magento\Framework\GraphQl\Exception\GraphQlInputException; use Magento\Framework\GraphQl\Query\Resolver\ContextInterface; use Magento\Framework\GraphQl\Schema; @@ -57,6 +58,7 @@ public function __construct( * @param array|null $variableValues * @param string|null $operationName * @return Promise|array + * @throws GraphQlInputException */ public function process( Schema $schema, @@ -66,6 +68,7 @@ public function process( string $operationName = null ) : array { if (!$this->exceptionFormatter->shouldShowDetail()) { + $this->queryComplexityLimiter->validateFieldCount($source); $this->queryComplexityLimiter->execute(); } diff --git a/lib/internal/Magento/Framework/GraphQl/Query/Resolver/Argument/Validator/CompositeValidator.php b/lib/internal/Magento/Framework/GraphQl/Query/Resolver/Argument/Validator/CompositeValidator.php new file mode 100644 index 0000000000000..a49388de06e7f --- /dev/null +++ b/lib/internal/Magento/Framework/GraphQl/Query/Resolver/Argument/Validator/CompositeValidator.php @@ -0,0 +1,48 @@ +validators = $validators; + } + + /** + * @inheritDoc + */ + public function validate(Field $field, $args): void + { + foreach ($this->validators as $validator) { + $validator->validate($field, $args); + } + } +} diff --git a/lib/internal/Magento/Framework/GraphQl/Query/Resolver/Argument/Validator/SearchCriteriaValidator.php b/lib/internal/Magento/Framework/GraphQl/Query/Resolver/Argument/Validator/SearchCriteriaValidator.php new file mode 100644 index 0000000000000..9a7f513833f02 --- /dev/null +++ b/lib/internal/Magento/Framework/GraphQl/Query/Resolver/Argument/Validator/SearchCriteriaValidator.php @@ -0,0 +1,44 @@ +maxPageSize = $maxPageSize; + } + + /** + * @inheritDoc + */ + public function validate(Field $field, $args): void + { + if (isset($args['pageSize']) && $args['pageSize'] > $this->maxPageSize) { + throw new GraphQlInputException( + __("Maximum pageSize is %max", ['max' => $this->maxPageSize]) + ); + } + } +} diff --git a/lib/internal/Magento/Framework/GraphQl/Query/Resolver/Argument/ValidatorInterface.php b/lib/internal/Magento/Framework/GraphQl/Query/Resolver/Argument/ValidatorInterface.php new file mode 100644 index 0000000000000..6249a99f64a84 --- /dev/null +++ b/lib/internal/Magento/Framework/GraphQl/Query/Resolver/Argument/ValidatorInterface.php @@ -0,0 +1,27 @@ +resolverFactory = $resolverFactory; + $this->resolveInfoFactory = $resolveInfoFactory; + $this->argumentValidator = $argumentValidator; + } + + /** + * Create a resolver promise + * + * @param Field $field + * @return callable + */ + public function create(Field $field): callable + { + $resolver = $this->resolverFactory->createByClass($field->getResolver()); + return function ($value, $args, $context, $info) use ($resolver, $field) { + $wrapperInfo = $this->resolveInfoFactory->create($info); + $this->argumentValidator->validate($field, $args); + return $resolver->resolve($field, $context, $wrapperInfo, $value, $args); + }; + } +} diff --git a/lib/internal/Magento/Framework/GraphQl/Schema/Type/Output/ElementMapper/Formatter/Fields.php b/lib/internal/Magento/Framework/GraphQl/Schema/Type/Output/ElementMapper/Formatter/Fields.php index ad9fb675a6d70..0ed64113d1314 100644 --- a/lib/internal/Magento/Framework/GraphQl/Schema/Type/Output/ElementMapper/Formatter/Fields.php +++ b/lib/internal/Magento/Framework/GraphQl/Schema/Type/Output/ElementMapper/Formatter/Fields.php @@ -10,14 +10,13 @@ use Magento\Framework\GraphQl\Config\Data\WrappedTypeProcessor; use Magento\Framework\GraphQl\Config\Element\Field; use Magento\Framework\GraphQl\Config\Element\TypeInterface; +use Magento\Framework\GraphQl\Query\Resolver\PromiseFactory; use Magento\Framework\GraphQl\Schema\Type\Input\InputMapper; use Magento\Framework\GraphQl\Schema\Type\Output\ElementMapper\FormatterInterface; use Magento\Framework\GraphQl\Schema\Type\Output\OutputMapper; use Magento\Framework\GraphQl\Schema\Type\OutputTypeInterface; use Magento\Framework\GraphQl\Schema\Type\ScalarTypes; use Magento\Framework\ObjectManagerInterface; -use Magento\Framework\GraphQl\Schema\Type\ResolveInfoFactory; -use Magento\Framework\GraphQl\Query\Resolver\Factory as ResolverFactory; /** * Convert fields of the given 'type' config element to the objects compatible with GraphQL schema generator. @@ -50,14 +49,9 @@ class Fields implements FormatterInterface private $wrappedTypeProcessor; /** - * @var ResolveInfoFactory + * @var PromiseFactory */ - private $resolveInfoFactory; - - /** - * @var ResolverFactory - */ - private $resolverFactory; + private $promiseFactory; /** * @param ObjectManagerInterface $objectManager @@ -65,8 +59,10 @@ class Fields implements FormatterInterface * @param InputMapper $inputMapper * @param ScalarTypes $scalarTypes * @param WrappedTypeProcessor $wrappedTypeProcessor - * @param ResolveInfoFactory $resolveInfoFactory - * @param ResolverFactory $resolverFactory + * @param mixed $resolveInfoFactory + * @param mixed $resolverFactory + * @param PromiseFactory|null $promiseFactory + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function __construct( ObjectManagerInterface $objectManager, @@ -74,16 +70,16 @@ public function __construct( InputMapper $inputMapper, ScalarTypes $scalarTypes, WrappedTypeProcessor $wrappedTypeProcessor, - ResolveInfoFactory $resolveInfoFactory, - ?ResolverFactory $resolverFactory = null + $resolveInfoFactory = null, + $resolverFactory = null, + ?PromiseFactory $promiseFactory = null ) { $this->objectManager = $objectManager; $this->outputMapper = $outputMapper; $this->inputMapper = $inputMapper; $this->scalarTypes = $scalarTypes; $this->wrappedTypeProcessor = $wrappedTypeProcessor; - $this->resolveInfoFactory = $resolveInfoFactory; - $this->resolverFactory = $resolverFactory ?? $this->objectManager->get(ResolverFactory::class); + $this->promiseFactory = $promiseFactory ?? $this->objectManager->get(PromiseFactory::class); } /** @@ -157,13 +153,7 @@ private function getFieldConfig( } if ($field->getResolver() != null) { - $resolver = $this->resolverFactory->createByClass($field->getResolver()); - - $fieldConfig['resolve'] = - function ($value, $args, $context, $info) use ($resolver, $field) { - $wrapperInfo = $this->resolveInfoFactory->create($info); - return $resolver->resolve($field, $context, $wrapperInfo, $value, $args); - }; + $fieldConfig['resolve'] = $this->promiseFactory->create($field); } return $this->formatArguments($field, $fieldConfig); } diff --git a/lib/internal/Magento/Framework/GraphQl/Test/Unit/Query/Resolver/Argument/Validator/CompositeValidatorTest.php b/lib/internal/Magento/Framework/GraphQl/Test/Unit/Query/Resolver/Argument/Validator/CompositeValidatorTest.php new file mode 100644 index 0000000000000..4169659b46dcf --- /dev/null +++ b/lib/internal/Magento/Framework/GraphQl/Test/Unit/Query/Resolver/Argument/Validator/CompositeValidatorTest.php @@ -0,0 +1,39 @@ +disableOriginalConstructor() + ->getMock(); + $args = ['a' => 123]; + $validatorA = self::getMockBuilder(ValidatorInterface::class)->getMock(); + $validatorA->expects(self::once()) + ->method('validate') + ->with($field, $args); + $validatorB = self::getMockBuilder(ValidatorInterface::class)->getMock(); + $validatorB->expects(self::once()) + ->method('validate') + ->with($field, $args); + + $composite = new CompositeValidator([$validatorA, $validatorB]); + $composite->validate($field, $args); + } +} diff --git a/lib/internal/Magento/Framework/GraphQl/Test/Unit/Query/Resolver/Argument/Validator/SearchCriteriaValidatorTest.php b/lib/internal/Magento/Framework/GraphQl/Test/Unit/Query/Resolver/Argument/Validator/SearchCriteriaValidatorTest.php new file mode 100644 index 0000000000000..d9aa18831aa9e --- /dev/null +++ b/lib/internal/Magento/Framework/GraphQl/Test/Unit/Query/Resolver/Argument/Validator/SearchCriteriaValidatorTest.php @@ -0,0 +1,43 @@ +disableOriginalConstructor() + ->getMock(); + $validator->validate($field, ['pageSize' => 3]); + } + + public function testValidInvalidMaxValue() + { + $this->expectException(GraphQlInputException::class); + $this->expectExceptionMessage("Maximum pageSize is 3"); + $validator = new SearchCriteriaValidator(3); + $field = self::getMockBuilder(Field::class) + ->disableOriginalConstructor() + ->getMock(); + $validator->validate($field, ['pageSize' => 4]); + } +} diff --git a/lib/internal/Magento/Framework/GraphQl/Test/Unit/Query/Resolver/PromiseFactoryTest.php b/lib/internal/Magento/Framework/GraphQl/Test/Unit/Query/Resolver/PromiseFactoryTest.php new file mode 100644 index 0000000000000..bef5de6624911 --- /dev/null +++ b/lib/internal/Magento/Framework/GraphQl/Test/Unit/Query/Resolver/PromiseFactoryTest.php @@ -0,0 +1,82 @@ +getMock(); + $infoDefinition = self::getMockBuilder(ResolveInfoDefinition::class) + ->disableOriginalConstructor() + ->getMock(); + $info = self::getMockBuilder(ResolveInfo::class) + ->disableOriginalConstructor() + ->getMock(); + + /** @var Field $field */ + $field = self::getMockBuilder(Field::class) + ->disableOriginalConstructor() + ->getMock(); + + /** @var ResolverFactory $resolverFactory */ + $resolverFactory = self::getMockBuilder(ResolverFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $resolverFactory->method('createByClass') + ->willReturn($resolver); + + /** @var ResolveInfoFactory $resolveInfoFactory */ + $resolveInfoFactory = self::getMockBuilder(ResolveInfoFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $resolveInfoFactory->expects(self::once()) + ->method('create') + ->with($infoDefinition) + ->willReturn($info); + + /** @var ValidatorInterface $argumentValidator */ + $argumentValidator = self::getMockBuilder(ValidatorInterface::class) + ->getMock(); + + $argumentValidator->expects(self::once()) + ->method('validate') + ->with($field, ['my_args']); + + $resolver->expects(self::once()) + ->method('resolve') + ->with($field, 'my_context', $info, ['my_value'], ['my_args']) + ->willReturn('abc'); + + $factory = new PromiseFactory( + $resolverFactory, + $resolveInfoFactory, + $argumentValidator + ); + + $promise = $factory->create($field); + $result = $promise(['my_value'], ['my_args'], 'my_context', $infoDefinition); + + self::assertSame('abc', $result); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/composer.json b/lib/internal/Magento/Framework/MessageQueue/composer.json index 056f1d40c39cf..d7cfcda899b55 100644 --- a/lib/internal/Magento/Framework/MessageQueue/composer.json +++ b/lib/internal/Magento/Framework/MessageQueue/composer.json @@ -1,24 +1,26 @@ { "name": "magento/framework-message-queue", "description": "N/A", - "config": { - "sort-packages": true - }, "type": "magento2-library", "license": [ "OSL-3.0", "AFL-3.0" ], + "config": { + "sort-packages": true + }, + "version": "100.3.7", "require": { - "magento/framework": "*", + "magento/framework": "102.0.*", "php": "~7.3.0||~7.4.0" }, "autoload": { - "psr-4": { - "Magento\\Framework\\MessageQueue\\": "" - }, "files": [ "registration.php" - ] + ], + "psr-4": { + "Magento\\Framework\\MessageQueue\\": "" + } } } + diff --git a/lib/internal/Magento/Framework/Session/CompositeValidator.php b/lib/internal/Magento/Framework/Session/CompositeValidator.php new file mode 100644 index 0000000000000..b9d93673a3afd --- /dev/null +++ b/lib/internal/Magento/Framework/Session/CompositeValidator.php @@ -0,0 +1,38 @@ +validators = $validators; + } + + /** + * @inheritDoc + */ + public function validate(SessionManagerInterface $session): void + { + foreach ($this->validators as $validator) { + $validator->validate($session); + } + } +} diff --git a/lib/internal/Magento/Framework/Session/SaveHandler.php b/lib/internal/Magento/Framework/Session/SaveHandler.php index 3a85705967669..e0d4f9ccaf435 100644 --- a/lib/internal/Magento/Framework/Session/SaveHandler.php +++ b/lib/internal/Magento/Framework/Session/SaveHandler.php @@ -5,14 +5,21 @@ */ namespace Magento\Framework\Session; -use Magento\Framework\Session\Config\ConfigInterface; +use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\SessionException; +use Magento\Framework\Session\Config\ConfigInterface; +use Psr\Log\LoggerInterface; /** * Magento session save handler */ class SaveHandler implements SaveHandlerInterface { + /** + * @var LoggerInterface + */ + private $logger; + /** * Session handler * @@ -35,19 +42,30 @@ class SaveHandler implements SaveHandlerInterface */ private $defaultHandler; + /** + * @var SessionMaxSizeConfig + */ + private $sessionMaxSizeConfig; + /** * @param SaveHandlerFactory $saveHandlerFactory * @param ConfigInterface $sessionConfig + * @param LoggerInterface $logger + * @param SessionMaxSizeConfig $sessionMaxSizeConfigs * @param string $default */ public function __construct( SaveHandlerFactory $saveHandlerFactory, ConfigInterface $sessionConfig, + LoggerInterface $logger, + SessionMaxSizeConfig $sessionMaxSizeConfigs, $default = self::DEFAULT_HANDLER ) { $this->saveHandlerFactory = $saveHandlerFactory; $this->sessionConfig = $sessionConfig; + $this->logger = $logger; $this->defaultHandler = $default; + $this->sessionMaxSizeConfig = $sessionMaxSizeConfigs; } /** @@ -89,10 +107,26 @@ public function read($sessionId) * @param string $sessionId * @param string $data * @return bool + * @throws LocalizedException */ public function write($sessionId, $data) { - return $this->callSafely('write', $sessionId, $data); + $sessionMaxSize = $this->sessionMaxSizeConfig->getSessionMaxSize(); + $sessionSize = strlen($data); + + if ($sessionMaxSize === null || $sessionMaxSize >= $sessionSize) { + return $this->callSafely('write', $sessionId, $data); + } + + $this->logger->warning( + sprintf( + 'Session size of %d exceeded allowed session max size of %d.', + $sessionSize, + $sessionMaxSize + ) + ); + + return $this->callSafely('write', $sessionId, $this->read($sessionId)); } /** diff --git a/lib/internal/Magento/Framework/Session/SaveHandler/DbTable.php b/lib/internal/Magento/Framework/Session/SaveHandler/DbTable.php index cf3449a8c3fcf..2f5a5a8610bf9 100644 --- a/lib/internal/Magento/Framework/Session/SaveHandler/DbTable.php +++ b/lib/internal/Magento/Framework/Session/SaveHandler/DbTable.php @@ -6,6 +6,9 @@ namespace Magento\Framework\Session\SaveHandler; +use Magento\Framework\App\ObjectManager; +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Encryption\EncryptorInterface; use Magento\Framework\Exception\SessionException; use Magento\Framework\Phrase; @@ -28,16 +31,28 @@ class DbTable extends \SessionHandler */ protected $connection; + /** + * @var EncryptorInterface + */ + private $encryptor; + /** * Constructor * - * @param \Magento\Framework\App\ResourceConnection $resource + * @param ResourceConnection $resource + * @param EncryptorInterface|null $encryptor + * @throws SessionException */ - public function __construct(\Magento\Framework\App\ResourceConnection $resource) - { + public function __construct( + ResourceConnection $resource, + EncryptorInterface $encryptor = null + ) { $this->_sessionTable = $resource->getTableName('session'); $this->connection = $resource->getConnection(); $this->checkConnection(); + $this->encryptor = $encryptor ?: ObjectManager::getInstance()->get( + EncryptorInterface::class + ); } /** @@ -98,7 +113,7 @@ public function read($sessionId) )->where( 'session_id = :session_id' ); - $bind = ['session_id' => $sessionId]; + $bind = ['session_id' => $this->encryptor->hash($sessionId)]; $data = $this->connection->fetchOne($select, $bind); // check if session data is a base64 encoded string @@ -118,8 +133,9 @@ public function read($sessionId) */ public function write($sessionId, $sessionData) { + $hashedSessionId = $this->encryptor->hash($sessionId); // need to use write connection to get the most fresh DB sessions - $bindValues = ['session_id' => $sessionId]; + $bindValues = ['session_id' => $hashedSessionId]; $select = $this->connection->select()->from($this->_sessionTable)->where('session_id = :session_id'); $exists = $this->connection->fetchOne($select, $bindValues); @@ -128,9 +144,9 @@ public function write($sessionId, $sessionData) $bind = ['session_expires' => time(), 'session_data' => $sessionData]; if ($exists) { - $this->connection->update($this->_sessionTable, $bind, ['session_id=?' => $sessionId]); + $this->connection->update($this->_sessionTable, $bind, ['session_id=?' => $hashedSessionId]); } else { - $bind['session_id'] = $sessionId; + $bind['session_id'] = $hashedSessionId; $this->connection->insert($this->_sessionTable, $bind); } return true; @@ -144,7 +160,7 @@ public function write($sessionId, $sessionData) */ public function destroy($sessionId) { - $where = ['session_id = ?' => $sessionId]; + $where = ['session_id = ?' => $this->encryptor->hash($sessionId)]; $this->connection->delete($this->_sessionTable, $where); return true; } diff --git a/lib/internal/Magento/Framework/Session/SessionManager.php b/lib/internal/Magento/Framework/Session/SessionManager.php index 1810423b63e16..beb8916b361bc 100644 --- a/lib/internal/Magento/Framework/Session/SessionManager.php +++ b/lib/internal/Magento/Framework/Session/SessionManager.php @@ -215,6 +215,8 @@ public function start() $this->_addHost(); \Magento\Framework\Profiler::stop('session_start'); + } else { + $this->validator->validate($this); } // phpstan:ignore $this->storage->init(isset($_SESSION) ? $_SESSION : []); diff --git a/lib/internal/Magento/Framework/Session/SessionMaxSizeConfig.php b/lib/internal/Magento/Framework/Session/SessionMaxSizeConfig.php new file mode 100644 index 0000000000000..e67f33e4f4584 --- /dev/null +++ b/lib/internal/Magento/Framework/Session/SessionMaxSizeConfig.php @@ -0,0 +1,84 @@ +_scopeConfig = $scopeConfig; + $this->_scopeType = $scopeType; + $this->state = $state; + } + + /** + * Get configuration for session max size + * + * @return int|null + * @throws LocalizedException + */ + public function getSessionMaxSize(): ?int + { + $path = self::XML_PATH_MAX_SESSION_SIZE_STOREFRONT; + + if ($this->state->getAreaCode() === Area::AREA_ADMINHTML) { + $path = self::XML_PATH_MAX_SESSION_SIZE_ADMIN; + } + + $result = (int)$this->_scopeConfig->getValue($path, $this->_scopeType); + + if ($result <= 0) { + return null; + } else { + return $result; + } + } +} diff --git a/lib/internal/Magento/Framework/Session/Test/Unit/SaveHandler/DbTableTest.php b/lib/internal/Magento/Framework/Session/Test/Unit/SaveHandler/DbTableTest.php index 9ca064d2717d0..aa9bbc4532d4c 100644 --- a/lib/internal/Magento/Framework/Session/Test/Unit/SaveHandler/DbTableTest.php +++ b/lib/internal/Magento/Framework/Session/Test/Unit/SaveHandler/DbTableTest.php @@ -153,11 +153,15 @@ public function testRead($isDataEncoded) */ protected function _prepareResourceMock($connection) { + + $encryptor = $this->createMock(\Magento\Framework\Encryption\EncryptorInterface::class); + $encryptor->expects($this->any())->method('hash')->willReturnArgument(0); + $resource = $this->createMock(\Magento\Framework\App\ResourceConnection::class); $resource->expects($this->once())->method('getTableName')->willReturn(self::SESSION_TABLE); $resource->expects($this->once())->method('getConnection')->willReturn($connection); - $this->_model = new \Magento\Framework\Session\SaveHandler\DbTable($resource); + $this->_model = new \Magento\Framework\Session\SaveHandler\DbTable($resource, $encryptor); } /** @@ -182,9 +186,7 @@ protected function _prepareMockForRead($isDataEncoded) )->with( self::SESSION_TABLE, [self::COLUMN_SESSION_DATA] - )->willReturnSelf( - - ); + )->willReturnSelf(); $connection->expects( $this->once() )->method( @@ -250,7 +252,10 @@ protected function _prepareMockForWrite($sessionExists) ); $connection->expects($this->once())->method('isTableExists')->willReturn(true); $connection->expects($this->once())->method('select')->willReturnSelf(); - $connection->expects($this->once())->method('from')->with(self::SESSION_TABLE)->willReturnSelf(); + $connection->expects($this->once()) + ->method('from') + ->with(self::SESSION_TABLE) + ->willReturnSelf(); $connection->expects( $this->once() )->method( diff --git a/lib/internal/Magento/Framework/Session/Test/Unit/SaveHandlerTest.php b/lib/internal/Magento/Framework/Session/Test/Unit/SaveHandlerTest.php new file mode 100644 index 0000000000000..a3e3d51b96625 --- /dev/null +++ b/lib/internal/Magento/Framework/Session/Test/Unit/SaveHandlerTest.php @@ -0,0 +1,134 @@ +configMock = $this->getMockBuilder(ConfigInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->sessionMaxSizeConfigMock = $this->getMockBuilder(SaveHandlerFactory::class) + ->disableOriginalConstructor() + ->setMethods(['getSessionMaxSize']) + ->getMock(); + + $this->saveHandlerAdapterMock = $this->getMockBuilder(SaveHandlerInterface::class) + ->disableOriginalConstructor() + ->setMethods(['write']) + ->getMockForAbstractClass(); + + $this->saveHandlerAdapterMock->expects($this->any()) + ->method('write') + ->willReturn(true); + + $this->saveHandlerFactoryMock = $this->getMockBuilder(SaveHandlerFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + + $this->saveHandlerFactoryMock->expects($this->any()) + ->method('create') + ->willReturn($this->saveHandlerAdapterMock); + + $this->helper = new ObjectManager($this); + $this->saveHandler = $this->helper->getObject( + SaveHandler::class, + [ + 'saveHandlerFactory' => $this->saveHandlerFactoryMock, + 'sessionConfig' => $this->configMock, + 'sessionMaxSizeConfig' => $this->sessionMaxSizeConfigMock, + ] + ); + } + + public function testWriteSessionMaxSizeValid() + { + $this->sessionMaxSizeConfigMock->expects($this->once()) + ->method('getSessionMaxSize') + ->willReturn(9); + + $this->saveHandlerAdapterMock->expects($this->never()) + ->method('read'); + + $this->assertTrue($this->saveHandler->write("test_session_id", "testdata")); + } + + public function testWriteSessionMaxSizeNull() + { + $this->sessionMaxSizeConfigMock->expects($this->once()) + ->method('getSessionMaxSize') + ->willReturn(null); + + $this->saveHandlerAdapterMock->expects($this->never()) + ->method('read'); + + $this->assertTrue($this->saveHandler->write("test_session_id", "testdata")); + } + + public function testWriteMoreThanSessionMaxSize() + { + $this->sessionMaxSizeConfigMock->expects($this->once()) + ->method('getSessionMaxSize') + ->willReturn(1); + + $this->saveHandlerAdapterMock->expects($this->once()) + ->method('read') + ->with('test_session_id'); + + $this->assertTrue($this->saveHandler->write("test_session_id", "testdata")); + } +} diff --git a/lib/internal/Magento/Framework/View/Element/UiComponent/Argument/Interpreter/ConfigurableObject.php b/lib/internal/Magento/Framework/View/Element/UiComponent/Argument/Interpreter/ConfigurableObject.php index 2691bc21357b0..026fc15ba2ed9 100644 --- a/lib/internal/Magento/Framework/View/Element/UiComponent/Argument/Interpreter/ConfigurableObject.php +++ b/lib/internal/Magento/Framework/View/Element/UiComponent/Argument/Interpreter/ConfigurableObject.php @@ -15,7 +15,7 @@ use Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface; /** - * Class ConfigurableObject + * Configurable ui component argument interpreter. */ class ConfigurableObject implements InterpreterInterface { @@ -24,6 +24,11 @@ class ConfigurableObject implements InterpreterInterface */ private $classWhitelist = []; + /** + * @var array + */ + private $deniedClassList = []; + /** * @var ObjectManagerInterface */ @@ -52,17 +57,20 @@ class ConfigurableObject implements InterpreterInterface * @param array $classWhitelist * @param ClassReader|null $classReader * @param ConfigInterface|null $objectManagerConfig + * @param array $deniedClassList */ public function __construct( ObjectManagerInterface $objectManager, InterpreterInterface $argumentInterpreter, array $classWhitelist = [], ClassReader $classReader = null, - ConfigInterface $objectManagerConfig = null + ConfigInterface $objectManagerConfig = null, + array $deniedClassList = [] ) { $this->objectManager = $objectManager; $this->argumentInterpreter = $argumentInterpreter; $this->classWhitelist = $classWhitelist; + $this->deniedClassList = $deniedClassList; $this->classReader = $classReader ?? $objectManager->get(ClassReader::class); $this->objectManagerConfig = $objectManagerConfig ?? $objectManager->get(ConfigInterface::class); } @@ -72,6 +80,7 @@ public function __construct( */ public function evaluate(array $data) { + $type = null; if (isset($data['value'])) { $className = $data['value']; $arguments = []; @@ -104,6 +113,21 @@ public function evaluate(array $data) } } + if ($type === null) { + $type = $this->objectManagerConfig->getInstanceType( + $this->objectManagerConfig->getPreference($className) + ); + $classParents = array_merge([$type], $this->getParents($type)); + } + + $deniedIntersection = array_intersect($classParents, $this->deniedClassList); + + if (!empty($deniedIntersection)) { + throw new \InvalidArgumentException( + sprintf('Class argument is invalid: %s', $className) + ); + } + return $this->objectManager->create($className, $arguments); } @@ -115,12 +139,14 @@ public function evaluate(array $data) */ private function getParents(string $type) { - $classParents = $this->classReader->getParents($type); + $classParents = $this->classReader->getParents($type) ?? []; foreach ($classParents as $parent) { if (empty($parent)) { continue; } + //@codingStandardsIgnoreStart $classParents = array_merge($classParents, $this->getParents($parent)); + //@codingStandardsIgnoreEnd } return $classParents; diff --git a/lib/internal/Magento/Framework/View/Test/Unit/UiComponent/Argument/Interpreter/ConfigurableObjectTest.php b/lib/internal/Magento/Framework/View/Test/Unit/UiComponent/Argument/Interpreter/ConfigurableObjectTest.php index 98e3cc0c8c42e..4e4d141a4d707 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/UiComponent/Argument/Interpreter/ConfigurableObjectTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/UiComponent/Argument/Interpreter/ConfigurableObjectTest.php @@ -60,11 +60,19 @@ protected function setUp(): void 'objectManager' => $this->objectManager, 'argumentInterpreter' => $this->interpreter, 'classWhitelist' => [ + // @phpstan-ignore-next-line \Foo\Bar\ClassA::class, + // @phpstan-ignore-next-line \Foo\Bar\InterfaceA::class, ], 'classReader' => $this->classReader, 'objectManagerConfig' => $this->objectManagerConfig, + 'deniedClassList' => [ + // @phpstan-ignore-next-line + \Foo\Bar\ClassC::class, + // @phpstan-ignore-next-line + \Foo\Bar\InterfaceC::class, + ], ] ); } @@ -100,11 +108,9 @@ public function testValidCombinations( $this->interpreter ->method('evaluate') ->willReturnCallback( - - function (array $arg) { - return $arg['value']; - } - + function (array $arg) { + return $arg['value']; + } ); $actualResult = $this->configurableObject->evaluate($data); @@ -145,11 +151,9 @@ public function testInvalidCombinations( $this->interpreter ->method('evaluate') ->willReturnCallback( - - function (array $arg) { - return $arg['value']; - } - + function (array $arg) { + return $arg['value']; + } ); $actualResult = $this->configurableObject->evaluate($data); @@ -179,10 +183,12 @@ public function validDataProvider() [ ['MyFooClass', ['Something', 'skipme']], ['Something', ['dontcare', 'SomethingElse']], + // @phpstan-ignore-next-line ['SomethingElse', [\Foo\Bar\ClassA::class, 'unrelated']], ['skipme', []], ['dontcare', []], ['unrelated', []], + // @phpstan-ignore-next-line [\Foo\Bar\ClassA::class, []] ], [] @@ -199,10 +205,12 @@ public function validDataProvider() [ ['MyFooClass', ['Something', 'skipme']], ['Something', ['dontcare', 'SomethingElse']], + // @phpstan-ignore-next-line ['SomethingElse', [\Foo\Bar\ClassA::class, 'unrelated']], ['skipme', []], ['dontcare', []], ['unrelated', []], + // @phpstan-ignore-next-line [\Foo\Bar\ClassA::class, []] ], ['myarg' => 'bar'] @@ -219,11 +227,15 @@ public function validDataProvider() [ ['MyFooClass', ['Something', 'skipme']], ['Something', ['dontcare', 'SomethingElse']], + // @phpstan-ignore-next-line ['SomethingElse', [\Foo\Bar\ClassA::class, 'unrelated']], ['skipme', []], ['dontcare', []], + // @phpstan-ignore-next-line ['unrelated', [\Foo\Bar\InterfaceA::class]], + // @phpstan-ignore-next-line [\Foo\Bar\ClassA::class, []], + // @phpstan-ignore-next-line [\Foo\Bar\InterfaceA::class, []] ], ['myarg' => 'bar'] @@ -273,6 +285,31 @@ public function invalidDataProvider() \InvalidArgumentException::class, 'Class argument is invalid: MyFooClass' ], + [ + [ + 'argument' => [ + 'class' => ['value' => 'MyFooClass'], + 'myarg' => ['value' => 'bar'], + ], + ], + 'MyFooClass', + [ + ['MyFooClass', ['Something', 'skipme']], + ['Something', ['dontcare', 'SomethingElse']], + // @phpstan-ignore-next-line + ['SomethingElse', [\Foo\Bar\ClassC::class, 'unrelated']], + ['skipme', []], + ['dontcare', []], + // @phpstan-ignore-next-line + ['unrelated', [\Foo\Bar\InterfaceC::class]], + // @phpstan-ignore-next-line + [\Foo\Bar\ClassC::class, []], + // @phpstan-ignore-next-line + [\Foo\Bar\InterfaceC::class, []], + ], + \InvalidArgumentException::class, + 'Class argument is invalid: MyFooClass', + ], ]; } } diff --git a/lib/internal/Magento/Framework/Webapi/ServiceInputProcessor.php b/lib/internal/Magento/Framework/Webapi/ServiceInputProcessor.php index d02264a761fb0..d15b9a45039e6 100644 --- a/lib/internal/Magento/Framework/Webapi/ServiceInputProcessor.php +++ b/lib/internal/Magento/Framework/Webapi/ServiceInputProcessor.php @@ -11,7 +11,9 @@ use Magento\Framework\Api\AttributeValue; use Magento\Framework\Api\AttributeValueFactory; +use Magento\Framework\Api\SearchCriteriaInterface; use Magento\Framework\Api\SimpleDataObjectConverter; +use Magento\Framework\App\ObjectManager; use Magento\Framework\Exception\InputException; use Magento\Framework\Exception\SerializationException; use Magento\Framework\ObjectManager\ConfigInterface; @@ -21,12 +23,14 @@ use Magento\Framework\Reflection\TypeProcessor; use Magento\Framework\Webapi\Exception as WebapiException; use Magento\Framework\Webapi\CustomAttribute\PreprocessorInterface; +use Magento\Framework\Webapi\Validator\ServiceInputValidatorInterface; use Zend\Code\Reflection\ClassReflection; /** * Deserialize arguments from API requests. * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @SuppressWarnings(PHPMD.ExcessiveParameterList) * @api * @since 100.0.2 */ @@ -84,6 +88,16 @@ class ServiceInputProcessor implements ServicePayloadConverterInterface */ private $attributesPreprocessorsMap = []; + /** + * @var ServiceInputValidatorInterface + */ + private $serviceInputValidator; + + /** + * @var int + */ + private $defaultPageSize; + /** * Initialize dependencies. * @@ -92,9 +106,11 @@ class ServiceInputProcessor implements ServicePayloadConverterInterface * @param AttributeValueFactory $attributeValueFactory * @param CustomAttributeTypeLocatorInterface $customAttributeTypeLocator * @param MethodsMap $methodsMap - * @param ServiceTypeToEntityTypeMap $serviceTypeToEntityTypeMap - * @param ConfigInterface $config + * @param ServiceTypeToEntityTypeMap|null $serviceTypeToEntityTypeMap + * @param ConfigInterface|null $config * @param array $customAttributePreprocessors + * @param ServiceInputValidatorInterface|null $serviceInputValidator + * @param int $defaultPageSize */ public function __construct( TypeProcessor $typeProcessor, @@ -104,7 +120,9 @@ public function __construct( MethodsMap $methodsMap, ServiceTypeToEntityTypeMap $serviceTypeToEntityTypeMap = null, ConfigInterface $config = null, - array $customAttributePreprocessors = [] + array $customAttributePreprocessors = [], + ServiceInputValidatorInterface $serviceInputValidator = null, + int $defaultPageSize = 20 ) { $this->typeProcessor = $typeProcessor; $this->objectManager = $objectManager; @@ -112,10 +130,13 @@ public function __construct( $this->customAttributeTypeLocator = $customAttributeTypeLocator; $this->methodsMap = $methodsMap; $this->serviceTypeToEntityTypeMap = $serviceTypeToEntityTypeMap - ?: \Magento\Framework\App\ObjectManager::getInstance()->get(ServiceTypeToEntityTypeMap::class); + ?: ObjectManager::getInstance()->get(ServiceTypeToEntityTypeMap::class); $this->config = $config - ?: \Magento\Framework\App\ObjectManager::getInstance()->get(ConfigInterface::class); + ?: ObjectManager::getInstance()->get(ConfigInterface::class); $this->customAttributePreprocessors = $customAttributePreprocessors; + $this->serviceInputValidator = $serviceInputValidator + ?: ObjectManager::getInstance()->get(ServiceInputValidatorInterface::class); + $this->defaultPageSize = $defaultPageSize >= 10 ? $defaultPageSize : 10; } /** @@ -128,7 +149,7 @@ public function __construct( private function getNameFinder() { if ($this->nameFinder === null) { - $this->nameFinder = \Magento\Framework\App\ObjectManager::getInstance() + $this->nameFinder = ObjectManager::getInstance() ->get(\Magento\Framework\Reflection\NameFinder::class); } return $this->nameFinder; @@ -232,6 +253,7 @@ private function getConstructorData(string $className, array $data): array * @throws \Exception * @throws SerializationException * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.NPathComplexity) */ protected function _createFromArray($className, $data) { @@ -284,9 +306,17 @@ protected function _createFromArray($className, $data) ) ); } + $this->serviceInputValidator->validateEntityValue($object, $propertyName, $setterValue); $object->{$setterName}($setterValue); } } + + if ($object instanceof SearchCriteriaInterface + && $object->getPageSize() === null + ) { + $object->setPageSize($this->defaultPageSize); + } + return $object; } @@ -470,6 +500,7 @@ public function convertValue($data, $type) $result = is_array($data) ? [] : null; $itemType = $this->typeProcessor->getArrayItemType($type); if (is_array($data)) { + $this->serviceInputValidator->validateComplexArrayType($itemType, $data); foreach ($data as $key => $item) { $result[$key] = $this->_createFromArray($itemType, $item); } diff --git a/lib/internal/Magento/Framework/Webapi/Test/Unit/ServiceInputProcessorTest.php b/lib/internal/Magento/Framework/Webapi/Test/Unit/ServiceInputProcessorTest.php index 352bbcce4b1ac..1ba03dc34a6bb 100644 --- a/lib/internal/Magento/Framework/Webapi/Test/Unit/ServiceInputProcessorTest.php +++ b/lib/internal/Magento/Framework/Webapi/Test/Unit/ServiceInputProcessorTest.php @@ -11,12 +11,14 @@ use Magento\Framework\Webapi\ServiceTypeToEntityTypeMap; use Magento\Framework\Webapi\Test\Unit\ServiceInputProcessor\SimpleConstructor; use Magento\Framework\Webapi\Test\Unit\ServiceInputProcessor\WebapiBuilderFactory; +use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Webapi\Test\Unit\ServiceInputProcessor\AssociativeArray; use Magento\Framework\Webapi\Test\Unit\ServiceInputProcessor\DataArray; use Magento\Framework\Webapi\Test\Unit\ServiceInputProcessor\ObjectWithCustomAttributes; use Magento\Webapi\Test\Unit\Service\Entity\DataArrayData; use Magento\Framework\Webapi\Test\Unit\ServiceInputProcessor\Nested; use Magento\Webapi\Test\Unit\Service\Entity\NestedData; +use Magento\Framework\Webapi\Validator\EntityArrayValidator; use Magento\Framework\Webapi\Test\Unit\ServiceInputProcessor\Simple; use Magento\Framework\Webapi\Test\Unit\ServiceInputProcessor\SimpleArray; use Magento\Webapi\Test\Unit\Service\Entity\SimpleArrayData; @@ -126,7 +128,8 @@ function () use ($objectManager) { 'customAttributeTypeLocator' => $this->customAttributeTypeLocator, 'attributeValueFactory' => $this->attributeValueFactoryMock, 'methodsMap' => $this->methodsMap, - 'serviceTypeToEntityTypeMap' => $this->serviceTypeToEntityTypeMap + 'serviceTypeToEntityTypeMap' => $this->serviceTypeToEntityTypeMap, + 'serviceInputValidator' => new EntityArrayValidator(50) ] ); @@ -322,6 +325,26 @@ public function testArrayOfDataObjectProperties() $this->assertEquals('Second', $second->getName()); } + public function testArrayOfDataObjectPropertiesIsValidated() + { + $this->expectException(LocalizedException::class); + $this->expectErrorMessage( + 'Maximum items of type "\\' . Simple::class . '" is 50' + ); + $objects = []; + for ($i = 0; $i < 51; $i++) { + $objects[] = ['entityId' => $i + 1, 'name' => 'Item' . $i]; + } + $data = [ + 'dataObjects' => $objects, + ]; + $this->serviceInputProcessor->process( + TestService::class, + 'dataArray', + $data + ); + } + public function testNestedSimpleArrayProperties() { $data = ['arrayData' => ['ids' => [1, 2, 3, 4]]]; diff --git a/lib/internal/Magento/Framework/Webapi/Test/Unit/Validator/CompositeValidatorTest.php b/lib/internal/Magento/Framework/Webapi/Test/Unit/Validator/CompositeValidatorTest.php new file mode 100644 index 0000000000000..5c71ebce9f92e --- /dev/null +++ b/lib/internal/Magento/Framework/Webapi/Test/Unit/Validator/CompositeValidatorTest.php @@ -0,0 +1,52 @@ +getMock(); + $validatorA->expects(self::once()) + ->method('validateEntityValue') + ->with($object, 'foo', 'abc'); + $validatorB = self::getMockBuilder(ServiceInputValidatorInterface::class)->getMock(); + $validatorB->expects(self::once()) + ->method('validateEntityValue') + ->with($object, 'foo', 'abc'); + + $composite = new CompositeServiceInputValidator([$validatorA, $validatorB]); + $composite->validateEntityValue($object, 'foo', 'abc'); + } + + public function testValidateComplexArrayType() + { + $items = [['item1']]; + $validatorA = self::getMockBuilder(ServiceInputValidatorInterface::class)->getMock(); + $validatorA->expects(self::once()) + ->method('validateComplexArrayType') + ->with('foo', $items); + $validatorB = self::getMockBuilder(ServiceInputValidatorInterface::class)->getMock(); + $validatorB->expects(self::once()) + ->method('validateComplexArrayType') + ->with('foo', $items); + + $composite = new CompositeServiceInputValidator([$validatorA, $validatorB]); + $composite->validateComplexArrayType('foo', $items); + } +} diff --git a/lib/internal/Magento/Framework/Webapi/Test/Unit/Validator/EntityArrayValidatorTest.php b/lib/internal/Magento/Framework/Webapi/Test/Unit/Validator/EntityArrayValidatorTest.php new file mode 100644 index 0000000000000..18d70bd599dcd --- /dev/null +++ b/lib/internal/Magento/Framework/Webapi/Test/Unit/Validator/EntityArrayValidatorTest.php @@ -0,0 +1,36 @@ +validateComplexArrayType("foo", [[],[],[]]); + } + + public function testFailsDataWhenAboveLimit() + { + $this->expectException(LocalizedException::class); + $this->expectErrorMessage('Maximum items of type "foo" is 3'); + $validator = new EntityArrayValidator(3); + $validator->validateComplexArrayType("foo", [[],[],[],[]]); + } +} diff --git a/lib/internal/Magento/Framework/Webapi/Test/Unit/Validator/SearchCriteriaValidatorTest.php b/lib/internal/Magento/Framework/Webapi/Test/Unit/Validator/SearchCriteriaValidatorTest.php new file mode 100644 index 0000000000000..aee09498fab68 --- /dev/null +++ b/lib/internal/Magento/Framework/Webapi/Test/Unit/Validator/SearchCriteriaValidatorTest.php @@ -0,0 +1,39 @@ +validateEntityValue($searchCriteria, 'pageSize', 2); + } + + public function testFailsPageSizeWhenAboveMaxLimit() + { + $this->expectException(LocalizedException::class); + $this->expectErrorMessage('Maximum SearchCriteria pageSize is 3'); + $searchCriteria = new SearchCriteria(); + $validator = new SearchCriteriaValidator(3); + $validator->validateEntityValue($searchCriteria, 'pageSize', 4); + } +} diff --git a/lib/internal/Magento/Framework/Webapi/Validator/CompositeServiceInputValidator.php b/lib/internal/Magento/Framework/Webapi/Validator/CompositeServiceInputValidator.php new file mode 100644 index 0000000000000..d905236b36832 --- /dev/null +++ b/lib/internal/Magento/Framework/Webapi/Validator/CompositeServiceInputValidator.php @@ -0,0 +1,55 @@ +validators = $validators; + } + + /** + * @inheritDoc + */ + public function validateComplexArrayType(string $className, array $items): void + { + foreach ($this->validators as $validator) { + $validator->validateComplexArrayType($className, $items); + } + } + + /** + * @inheritDoc + */ + public function validateEntityValue(object $entity, string $propertyName, $value): void + { + foreach ($this->validators as $validator) { + $validator->validateEntityValue($entity, $propertyName, $value); + } + } +} diff --git a/lib/internal/Magento/Framework/Webapi/Validator/EntityArrayValidator.php b/lib/internal/Magento/Framework/Webapi/Validator/EntityArrayValidator.php new file mode 100644 index 0000000000000..5d48cb4ec53a4 --- /dev/null +++ b/lib/internal/Magento/Framework/Webapi/Validator/EntityArrayValidator.php @@ -0,0 +1,53 @@ +complexArrayItemLimit = $complexArrayItemLimit; + } + + /** + * @inheritDoc + */ + public function validateComplexArrayType(string $className, array $items): void + { + if (count($items) > $this->complexArrayItemLimit) { + throw new LocalizedException( + __( + 'Maximum items of type "%type" is %max', + ['type' => $className, 'max' => $this->complexArrayItemLimit] + ) + ); + } + } + + /** + * @inheritDoc + * phpcs:disable Magento2.CodeAnalysis.EmptyBlock + */ + public function validateEntityValue(object $entity, string $propertyName, $value): void + { + } +} diff --git a/lib/internal/Magento/Framework/Webapi/Validator/SearchCriteriaValidator.php b/lib/internal/Magento/Framework/Webapi/Validator/SearchCriteriaValidator.php new file mode 100644 index 0000000000000..bcabef90a5630 --- /dev/null +++ b/lib/internal/Magento/Framework/Webapi/Validator/SearchCriteriaValidator.php @@ -0,0 +1,54 @@ +maximumPageSize = $maximumPageSize; + } + + /** + * @inheritDoc + * phpcs:disable Magento2.CodeAnalysis.EmptyBlock + */ + public function validateComplexArrayType(string $className, array $items): void + { + } + + /** + * @inheritDoc + */ + public function validateEntityValue(object $entity, string $propertyName, $value): void + { + if ($entity instanceof SearchCriteriaInterface + && $propertyName === 'pageSize' + && $value > $this->maximumPageSize + ) { + throw new LocalizedException( + __('Maximum SearchCriteria pageSize is %max', ['max' => $this->maximumPageSize]) + ); + } + } +} diff --git a/lib/internal/Magento/Framework/Webapi/Validator/ServiceInputValidatorInterface.php b/lib/internal/Magento/Framework/Webapi/Validator/ServiceInputValidatorInterface.php new file mode 100644 index 0000000000000..002f4cb7958e2 --- /dev/null +++ b/lib/internal/Magento/Framework/Webapi/Validator/ServiceInputValidatorInterface.php @@ -0,0 +1,37 @@ +=3.0.0 as an optional alternative image processing library" }, "autoload": { - "psr-4": { - "Magento\\Framework\\": "" - }, "files": [ "registration.php" - ] + ], + "psr-4": { + "Magento\\Framework\\": "" + } } } + diff --git a/lib/web/mage/adminhtml/browser.js b/lib/web/mage/adminhtml/browser.js index 7780ac524fa49..0edc58b09ceb2 100644 --- a/lib/web/mage/adminhtml/browser.js +++ b/lib/web/mage/adminhtml/browser.js @@ -415,8 +415,14 @@ define([ }, context: self.element, showLoader: true - }).done($.proxy(function () { - self.tree.jstree('refresh', self.activeNode.id); + }).done($.proxy(function (data) { + if (data.error) { + alert({ + content: data.message + }); + } else { + self.tree.jstree('refresh', self.activeNode.id); + } }, this)); }, @@ -457,13 +463,21 @@ define([ }, context: self.element, showLoader: true - }).done($.proxy(function () { - self.reload(); - self.element.find('#delete_files, #insert_files').toggleClass(self.options.hidden, true); + }).done($.proxy(function (data) { + if (data.error) { + alert({ + content: data.message + }); + } else { + self.reload(); + self.element.find('#delete_files, #insert_files').toggleClass( + self.options.hidden, true + ); - $(window).trigger('fileDeleted.mediabrowser', { - ids: ids - }); + $(window).trigger('fileDeleted.mediabrowser', { + ids: ids + }); + } }, this)); }, diff --git a/setup/src/Magento/Setup/Console/Command/UpgradeCommand.php b/setup/src/Magento/Setup/Console/Command/UpgradeCommand.php index 55081c5a9c9a4..1682253851e55 100644 --- a/setup/src/Magento/Setup/Console/Command/UpgradeCommand.php +++ b/setup/src/Magento/Setup/Console/Command/UpgradeCommand.php @@ -137,6 +137,13 @@ protected function execute(InputInterface $input, OutputInterface $output) 'Please re-run Magento compile command. Use the command "setup:di:compile"' ); } + $output->writeln( + "Media files stored outside of 'Media Gallery Allowed' folders" + . " will not be available to the media gallery." + ); + $output->writeln( + 'Please refer to Developer Guide for more details.' + ); } catch (\Exception $e) { $output->writeln($e->getMessage()); return \Magento\Framework\Console\Cli::RETURN_FAILURE; diff --git a/setup/src/Magento/Setup/Test/Unit/Console/Command/UpgradeCommandTest.php b/setup/src/Magento/Setup/Test/Unit/Console/Command/UpgradeCommandTest.php index 6fa6f67250fd1..079bb6ae244d7 100644 --- a/setup/src/Magento/Setup/Test/Unit/Console/Command/UpgradeCommandTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Console/Command/UpgradeCommandTest.php @@ -92,7 +92,8 @@ public function testExecute($options, $deployMode, $expectedString, $expectedOpt ->method('installDataFixtures'); $this->assertSame(Cli::RETURN_SUCCESS, $this->commandTester->execute($options)); - $this->assertEquals($expectedString, $this->commandTester->getDisplay()); + $display = $this->commandTester->getDisplay(); + $this->assertStringContainsString($expectedString, $display); } /**