From 712cea4825f6067e1e7ed629abc2bd9eed157a12 Mon Sep 17 00:00:00 2001 From: magento packaging service Date: Fri, 9 Aug 2024 13:58:55 +0000 Subject: [PATCH] Magento Release 2.4.4-p10 --- .../AdminAnalytics/ViewModel/Metadata.php | 30 +- app/code/Magento/AdminAnalytics/composer.json | 25 +- .../view/adminhtml/templates/tracking.phtml | 26 +- .../Magento/AdminNotification/composer.json | 24 +- .../AdvancedPricingImportExport/composer.json | 30 +- app/code/Magento/AdvancedSearch/composer.json | 28 +- app/code/Magento/Amqp/composer.json | 18 +- app/code/Magento/AmqpStore/composer.json | 22 +- ...minAdvancedReportingPageUrlActionGroup.xml | 2 +- app/code/Magento/Analytics/composer.json | 18 +- .../AsynchronousOperations/composer.json | 26 +- app/code/Magento/Authorization/composer.json | 16 +- app/code/Magento/AwsS3/composer.json | 14 +- .../Block/System/Store/Grid/Render/Group.php | 10 +- app/code/Magento/Backend/composer.json | 50 +- .../Magento/Backend/etc/adminhtml/system.xml | 3 + app/code/Magento/Backup/composer.json | 20 +- ...tAddProductToCartFromBundleActionGroup.xml | 4 + app/code/Magento/Bundle/composer.json | 52 +- .../view/type/bundle/option/radio.phtml | 50 +- app/code/Magento/BundleGraphQl/composer.json | 28 +- .../Magento/BundleImportExport/composer.json | 26 +- .../Magento/CacheInvalidate/composer.json | 16 +- ...ontCaptchaOnOnepageCheckoutPyamentTest.xml | 2 + app/code/Magento/Captcha/composer.json | 26 +- .../Magento/CardinalCommerce/composer.json | 20 +- .../Adminhtml/Product/NewAction.php | 25 +- .../Option/Type/File/ValidatorInfo.php | 11 +- .../Section/StorefrontCategoryMainSection.xml | 1 + .../AdminApplyTierPriceToProductTest.xml | 1 + ...ProductAttributeUpdateAddedToQueueTest.xml | 2 + ...ctedUserAddCategoryFromProductPageTest.xml | 1 + ...ularPriceInStockEnabledFlatCatalogTest.xml | 6 +- .../Test/Mftf/Test/EndToEndB2CAdminTest.xml | 4 + ...torefrontProductWithEmptyAttributeTest.xml | 12 +- .../Adminhtml/Product/NewActionTest.php | 81 +- .../Unit/Pricing/Render/FinalPriceBoxTest.php | 33 + app/code/Magento/Catalog/composer.json | 70 +- app/code/Magento/Catalog/i18n/en_US.csv | 2 + .../view/adminhtml/web/js/category-tree.js | 5 +- .../Magento/CatalogAnalytics/composer.json | 14 +- .../Magento/CatalogCmsGraphQl/composer.json | 22 +- .../CatalogCustomerGraphQl/composer.json | 16 +- app/code/Magento/CatalogGraphQl/composer.json | 36 +- .../Model/Import/Product.php | 6 + .../Magento/CatalogImportExport/composer.json | 34 +- .../Magento/CatalogInventory/composer.json | 28 +- .../CatalogInventoryGraphQl/composer.json | 18 +- app/code/Magento/CatalogRule/composer.json | 32 +- .../CatalogRuleConfigurable/composer.json | 22 +- .../Magento/CatalogRuleGraphQl/composer.json | 14 +- app/code/Magento/CatalogSearch/composer.json | 38 +- .../Magento/CatalogUrlRewrite/composer.json | 32 +- .../CatalogUrlRewriteGraphQl/composer.json | 26 +- ...frontProductGridUIUpdatesOnDesktopTest.xml | 1 + app/code/Magento/CatalogWidget/composer.json | 32 +- .../Controller/Sidebar/UpdateItemQty.php | 16 +- .../Checkout/Model/DefaultConfigProvider.php | 12 +- .../Model/ShippingInformationManagement.php | 34 +- .../Checkout/Observer/CspPolicyObserver.php | 69 + .../AssertMiniCartEmptyActionGroup.xml | 3 +- .../CheckoutPlaceOrderActionGroup.xml | 4 + ...ckoutAsCustomerUsingDefaultAddressTest.xml | 3 +- ...utAsCustomerUsingNonDefaultAddressTest.xml | 2 + ...ntCheckoutWithSpecialPriceProductsTest.xml | 2 + ...refrontCustomerLoginDuringCheckoutTest.xml | 3 +- ...ontVerifySecureURLRedirectCheckoutTest.xml | 4 +- .../Controller/Sidebar/UpdateItemQtyTest.php | 35 + app/code/Magento/Checkout/composer.json | 57 +- .../Magento/Checkout/etc/adminhtml/system.xml | 19 +- app/code/Magento/Checkout/etc/config.xml | 16 + .../Magento/Checkout/etc/frontend/events.xml | 4 + app/code/Magento/Checkout/i18n/en_US.csv | 1 + ...dminDeleteAllTermConditionsActionGroup.xml | 27 + .../Mftf/Helper/CheckoutAgreementsHelpers.php | 61 + .../Mftf/Section/AdminTermGridSection.xml | 2 + .../AdminCreateActiveHtmlTermEntityTest.xml | 7 +- .../AdminCreateActiveTextTermEntityTest.xml | 4 +- .../Magento/CheckoutAgreements/composer.json | 22 +- .../CheckoutAgreementsGraphQl/composer.json | 18 +- .../Magento/Cms/Controller/Noroute/Index.php | 7 +- .../Unit/Controller/Noroute/IndexTest.php | 12 +- app/code/Magento/Cms/composer.json | 34 +- app/code/Magento/CmsGraphQl/composer.json | 24 +- app/code/Magento/CmsUrlRewrite/composer.json | 20 +- .../CmsUrlRewriteGraphQl/composer.json | 24 +- .../Magento/CompareListGraphQl/composer.json | 14 +- .../Block/System/Config/Form/Field/File.php | 4 +- .../Config/Model/Config/Backend/File.php | 23 +- .../System/Config/Form/Field/FileTest.php | 81 +- app/code/Magento/Config/composer.json | 28 +- app/code/Magento/Config/i18n/en_US.csv | 1 + .../ConfigurableImportExport/composer.json | 26 +- .../CreateNewAttributeActionGroup.xml | 1 + ...igurableProductAttributeNameDesignData.xml | 2 +- .../CatalogProductsSection.xml | 2 +- .../ConfigurableProductSection.xml | 2 +- ...hVisualSwatchAttributePrependMediaTest.xml | 41 +- .../Magento/ConfigurableProduct/composer.json | 50 +- .../ConfigurableProductGraphQl/composer.json | 24 +- .../ConfigurableProductSales/composer.json | 22 +- app/code/Magento/Contact/composer.json | 22 +- app/code/Magento/Cookie/composer.json | 18 +- app/code/Magento/Cron/composer.json | 18 +- app/code/Magento/Csp/Block/Sri/Hashes.php | 94 + .../Magento/Csp/Helper/CspNonceProvider.php | 86 + app/code/Magento/Csp/Helper/InlineUtil.php | 54 +- .../Csp/Model/Collector/ConfigCollector.php | 31 +- .../Processor/PostProcessor/Integrity.php | 89 + .../Package/Processor/PostProcessor/Map.php | 139 + .../Magento/Csp/Model/Mode/ConfigManager.php | 62 +- .../Csp/Model/SubresourceIntegrity.php | 34 + .../SubresourceIntegrity/HashGenerator.php | 37 + .../Model/SubresourceIntegrityCollector.php | 49 + .../Model/SubresourceIntegrityRepository.php | 211 + .../SubresourceIntegrityRepositoryPool.php | 53 + .../AddDefaultPropertiesToGroupPlugin.php | 81 + .../Csp/Plugin/GenerateAssetIntegrity.php | 91 + .../Plugin/RemoveAllAssetIntegrityHashes.php | 69 + .../Csp/Plugin/StoreAssetIntegrityHashes.php | 70 + .../Unit/Model/Mode/ConfigManagerTest.php | 80 +- .../SubresourceIntegrityRepositoryTest.php | 130 + .../AddDefaultPropertiesToGroupPluginTest.php | 113 + .../Plugin/StoreAssetIntegrityHashesTest.php | 96 + app/code/Magento/Csp/composer.json | 18 +- app/code/Magento/Csp/etc/acl.xml | 22 + app/code/Magento/Csp/etc/adminhtml/system.xml | 35 + app/code/Magento/Csp/etc/di.xml | 23 + .../layout/sales_order_create_index.xml | 17 + .../Csp/view/base/templates/sri/hashes.phtml | 18 + app/code/Magento/Csp/view/base/web/js/sri.js | 13 + .../frontend/layout/checkout_index_index.xml | 17 + ...kCurrencyConverterApiConfigurationTest.xml | 2 + app/code/Magento/CurrencySymbol/composer.json | 24 +- .../Api/AccountManagementInterface.php | 3 +- .../Customer/Controller/Account/Confirm.php | 78 +- .../Controller/Account/Confirmation.php | 62 +- .../Customer/Controller/Account/EditPost.php | 108 +- .../Customer/Model/AccountConfirmation.php | 75 +- .../Customer/Model/AccountManagement.php | 106 +- .../Customer/Model/EmailNotification.php | 73 +- .../Plugin/ClearSessionsAfterLogoutPlugin.php | 108 + .../Model/Plugin/CustomerNotification.php | 70 +- .../Customer/Model/Plugin/UpdateCustomer.php | 26 +- .../Customer/Model/ResourceModel/Customer.php | 132 +- .../ResourceModel/CustomerRepository.php | 42 +- ...stRowEditLinkOnCustomerGridActionGroup.xml | 1 - ...inChangeSingleCustomerGroupViaGridTest.xml | 4 + .../Mftf/Test/AdminDeleteCustomerTest.xml | 8 + .../Mftf/Test/EndToEndB2CLoggedInUserTest.xml | 2 + .../Unit/Controller/Account/ConfirmTest.php | 86 +- .../Model/Plugin/CustomerNotificationTest.php | 25 +- app/code/Magento/Customer/composer.json | 56 +- .../Magento/Customer/etc/adminhtml/system.xml | 4 + app/code/Magento/Customer/etc/config.xml | 1 + app/code/Magento/Customer/etc/frontend/di.xml | 3 + .../Magento/CustomerAnalytics/composer.json | 14 +- .../CustomerDownloadableGraphQl/composer.json | 18 +- .../Magento/CustomerGraphQl/composer.json | 30 +- .../CustomerImportExport/composer.json | 26 +- app/code/Magento/Deploy/composer.json | 22 +- app/code/Magento/Developer/composer.json | 18 +- app/code/Magento/Dhl/composer.json | 34 +- app/code/Magento/Directory/composer.json | 20 +- .../Magento/DirectoryGraphQl/composer.json | 16 +- app/code/Magento/Downloadable/composer.json | 48 +- .../Magento/DownloadableGraphQl/composer.json | 28 +- .../DownloadableImportExport/composer.json | 26 +- app/code/Magento/Eav/composer.json | 24 +- app/code/Magento/EavGraphQl/composer.json | 16 +- .../SearchAdapter/Query/Builder/Sort.php | 3 +- app/code/Magento/Elasticsearch/composer.json | 32 +- app/code/Magento/Elasticsearch6/composer.json | 24 +- app/code/Magento/Elasticsearch7/composer.json | 24 +- .../Magento/Email/Model/Template/Filter.php | 13 +- app/code/Magento/Email/composer.json | 34 +- .../Command/UpdateEncryptionKeyCommand.php | 141 + app/code/Magento/EncryptionKey/composer.json | 18 +- app/code/Magento/EncryptionKey/etc/di.xml | 7 + .../Fedex/Model/Config/Backend/FedexUrl.php | 75 + .../Model/Config/Backend/FedexUrlTest.php | 131 + app/code/Magento/Fedex/composer.json | 30 +- .../Magento/Fedex/etc/adminhtml/system.xml | 2 + app/code/Magento/Fedex/i18n/en_US.csv | 1 + app/code/Magento/GiftMessage/composer.json | 34 +- .../Magento/GiftMessageGraphQl/composer.json | 16 +- app/code/Magento/GoogleAdwords/composer.json | 18 +- .../Magento/GoogleAnalytics/composer.json | 22 +- .../Magento/GoogleOptimizer/composer.json | 26 +- app/code/Magento/GraphQl/composer.json | 22 +- app/code/Magento/GraphQlCache/composer.json | 18 +- .../GroupedCatalogInventory/composer.json | 20 +- .../Magento/GroupedImportExport/composer.json | 24 +- app/code/Magento/GroupedProduct/composer.json | 42 +- .../GroupedProductGraphQl/composer.json | 16 +- .../Adminhtml/Export/File/Download.php | 17 +- .../Controller/Adminhtml/History/Download.php | 29 +- .../Adminhtml/History/DownloadTest.php | 28 +- app/code/Magento/ImportExport/composer.json | 26 +- app/code/Magento/Indexer/composer.json | 16 +- .../Magento/InstantPurchase/composer.json | 18 +- .../Adminhtml/Integration/Edit/Tab/Info.php | 22 +- .../Controller/Adminhtml/Integration.php | 30 +- .../Controller/Adminhtml/Integration/Save.php | 22 +- app/code/Magento/Integration/composer.json | 28 +- app/code/Magento/Integration/i18n/en_US.csv | 1 + .../Magento/JwtFrameworkAdapter/composer.json | 14 +- .../Model/SecretBasedJwksFactory.php | 3 + app/code/Magento/JwtUserToken/composer.json | 18 +- .../Magento/LayeredNavigation/composer.json | 18 +- .../AdminLoginAsCustomerLoggingFilterTest.xml | 2 + .../Magento/LoginAsCustomer/composer.json | 22 +- .../LoginAsCustomerAdminUi/composer.json | 29 +- .../Magento/LoginAsCustomerApi/composer.json | 10 +- .../LoginAsCustomerAssistance/composer.json | 29 +- .../LoginAsCustomerFrontendUi/composer.json | 17 +- .../LoginAsCustomerGraphQl/composer.json | 26 +- .../Magento/LoginAsCustomerLog/composer.json | 27 +- .../LoginAsCustomerPageCache/composer.json | 21 +- .../LoginAsCustomerQuote/composer.json | 23 +- .../LoginAsCustomerSales/composer.json | 23 +- app/code/Magento/Marketplace/composer.json | 16 +- .../view/adminhtml/templates/index.phtml | 6 +- app/code/Magento/MediaContent/composer.json | 14 +- .../Magento/MediaContentApi/composer.json | 12 +- .../Magento/MediaContentCatalog/composer.json | 18 +- .../Magento/MediaContentCms/composer.json | 14 +- .../MediaContentSynchronization/composer.json | 24 +- .../composer.json | 12 +- .../composer.json | 16 +- .../composer.json | 16 +- app/code/Magento/MediaGallery/composer.json | 14 +- .../Magento/MediaGalleryApi/composer.json | 10 +- .../Magento/MediaGalleryCatalog/composer.json | 14 +- .../composer.json | 24 +- .../MediaGalleryCatalogUi/composer.json | 20 +- .../Magento/MediaGalleryCmsUi/composer.json | 14 +- .../MediaGalleryIntegration/composer.json | 32 +- .../MediaGalleryMetadata/composer.json | 12 +- .../MediaGalleryMetadataApi/composer.json | 10 +- .../MediaGalleryRenditions/composer.json | 24 +- .../MediaGalleryRenditionsApi/composer.json | 10 +- .../MediaGallerySynchronization/composer.json | 16 +- .../composer.json | 12 +- .../composer.json | 16 +- app/code/Magento/MediaGalleryUi/composer.json | 32 +- .../Magento/MediaGalleryUiApi/composer.json | 16 +- app/code/Magento/MediaStorage/composer.json | 30 +- app/code/Magento/MessageQueue/composer.json | 16 +- app/code/Magento/Msrp/composer.json | 28 +- .../MsrpConfigurableProduct/composer.json | 20 +- .../Magento/MsrpGroupedProduct/composer.json | 20 +- app/code/Magento/Multishipping/composer.json | 34 +- app/code/Magento/MysqlMq/composer.json | 18 +- .../Magento/NewRelicReporting/composer.json | 26 +- .../Newsletter/Controller/Adminhtml/Queue.php | 11 +- ...ingDeleteNewsletterTemplateActionGroup.xml | 2 + ...nNewsletterTemplateFromGridActionGroup.xml | 2 + app/code/Magento/Newsletter/composer.json | 32 +- .../Magento/NewsletterGraphQl/composer.json | 22 +- .../Magento/OfflinePayments/composer.json | 22 +- .../Magento/OfflineShipping/composer.json | 36 +- .../Magento/PageCache/Controller/Block.php | 86 +- .../Test/Unit/Controller/Block/EsiTest.php | 20 +- .../Test/Unit/Controller/Block/RenderTest.php | 20 +- app/code/Magento/PageCache/composer.json | 20 +- .../PageCache/etc/adminhtml/system.xml | 4 + app/code/Magento/PageCache/etc/config.xml | 1 + app/code/Magento/PageCache/etc/di.xml | 1 + app/code/Magento/Payment/composer.json | 28 +- app/code/Magento/PaymentGraphQl/composer.json | 18 +- .../Magento/Paypal/Block/PayLater/Banner.php | 3 +- .../Paypal/Block/PayLater/LayoutProcessor.php | 3 +- app/code/Magento/Paypal/Model/Config.php | 109 +- .../Paypal/Model/SmartButtonConfig.php | 4 +- .../Model/_files/expected_style_config.php | 12 +- app/code/Magento/Paypal/composer.json | 51 +- ...frontPaymentsCaptchaWithPayflowProTest.xml | 2 + app/code/Magento/PaypalCaptcha/composer.json | 22 +- app/code/Magento/PaypalGraphQl/composer.json | 34 +- ...CartPersistenceUnderLongTermCookieTest.xml | 1 + app/code/Magento/Persistent/composer.json | 26 +- app/code/Magento/ProductAlert/composer.json | 32 +- app/code/Magento/ProductVideo/composer.json | 28 +- .../Quote/Model/BillingAddressManagement.php | 13 +- app/code/Magento/Quote/Model/Quote.php | 28 +- .../Quote/Model/QuoteAddressValidator.php | 84 +- .../Quote/Model/ShippingMethodManagement.php | 29 +- .../Magento/Quote/Plugin/QuoteAddress.php | 67 + .../Quote/Plugin/ValidateQuoteOrigOrder.php | 65 + .../Quote/Test/Unit/Model/QuoteTest.php | 13 +- .../Model/ShippingMethodManagementTest.php | 214 +- app/code/Magento/Quote/composer.json | 44 +- app/code/Magento/Quote/etc/webapi_rest/di.xml | 4 + app/code/Magento/Quote/i18n/en_US.csv | 3 + app/code/Magento/QuoteAnalytics/composer.json | 14 +- .../Magento/QuoteBundleOptions/composer.json | 12 +- .../QuoteConfigurableOptions/composer.json | 12 +- .../QuoteDownloadableLinks/composer.json | 12 +- .../Model/Resolver/RemoveItemFromCart.php | 3 +- app/code/Magento/QuoteGraphQl/composer.json | 40 +- .../RelatedProductGraphQl/composer.json | 18 +- .../Magento/ReleaseNotification/composer.json | 22 +- app/code/Magento/RemoteStorage/composer.json | 36 +- .../Controller/Adminhtml/Report/Review.php | 34 +- .../Controller/Adminhtml/Report/Sales.php | 27 +- app/code/Magento/Reports/composer.json | 48 +- app/code/Magento/RequireJs/composer.json | 14 +- app/code/Magento/Review/composer.json | 34 +- .../Magento/ReviewAnalytics/composer.json | 14 +- app/code/Magento/ReviewGraphQl/composer.json | 22 +- app/code/Magento/Robots/composer.json | 18 +- app/code/Magento/Rss/composer.json | 20 +- app/code/Magento/Rule/composer.json | 22 +- .../Sales/Block/Adminhtml/Order/View.php | 10 +- .../Controller/Adminhtml/Order/AddComment.php | 9 +- .../Adminhtml/Order/Create/LoadBlock.php | 55 +- .../Adminhtml/Order/Creditmemo/Cancel.php | 5 +- .../Adminhtml/Order/Creditmemo/NewAction.php | 2 +- .../Adminhtml/Order/Creditmemo/Save.php | 5 +- .../Adminhtml/Order/Creditmemo/Start.php | 2 +- .../Adminhtml/Order/Creditmemo/UpdateQty.php | 2 +- .../Adminhtml/Order/Creditmemo/VoidAction.php | 5 +- app/code/Magento/Sales/Helper/Admin.php | 62 - ...teToNewOrderPageNewCustomerActionGroup.xml | 23 + ...tCreateOrderWithDifferentAddressesTest.xml | 3 +- .../Order/Create/SidebarPermissionCheck.php | 42 + app/code/Magento/Sales/composer.json | 64 +- .../Magento/Sales/etc/adminhtml/system.xml | 12 + app/code/Magento/Sales/etc/config.xml | 15 + app/code/Magento/Sales/etc/csp_whitelist.xml | 22 + .../layout/sales_order_create_index.xml | 3 + .../sales_order_create_load_block_data.xml | 3 + .../sales_order_create_load_block_sidebar.xml | 3 + .../templates/order/comments/view.phtml | 20 +- .../templates/order/create/sidebar.phtml | 22 +- app/code/Magento/SalesAnalytics/composer.json | 14 +- app/code/Magento/SalesGraphQl/composer.json | 24 +- app/code/Magento/SalesInventory/composer.json | 22 +- .../Adminhtml/Promo/Quote/Generate.php | 109 +- ...StorefrontApplyDiscountCodeActionGroup.xml | 2 +- .../Adminhtml/Promo/Quote/GenerateTest.php | 228 +- app/code/Magento/SalesRule/composer.json | 58 +- .../SalesRule/etc/adminhtml/system.xml | 13 +- app/code/Magento/SalesRule/etc/config.xml | 1 + app/code/Magento/SalesRule/etc/di.xml | 9 +- app/code/Magento/SalesRule/i18n/en_US.csv | 3 + app/code/Magento/SalesSequence/composer.json | 14 +- app/code/Magento/SampleData/composer.json | 16 +- ...DisabledTillMinimumSearchLengthHitTest.xml | 3 + app/code/Magento/Search/composer.json | 24 +- .../NewCustomerPasswordComplexityTest.xml | 4 + app/code/Magento/Security/composer.json | 24 +- app/code/Magento/SendFriend/composer.json | 26 +- .../Magento/SendFriendGraphQl/composer.json | 16 +- .../Adminhtml/Order/Shipment/NewAction.php | 59 +- .../Adminhtml/Order/Shipment/Save.php | 2 +- .../Adminhtml/Order/Shipment/Start.php | 12 +- .../Order/Shipment/NewActionTest.php | 81 +- app/code/Magento/Shipping/composer.json | 46 +- app/code/Magento/Shipping/etc/acl.xml | 2 +- app/code/Magento/Sitemap/composer.json | 34 +- app/code/Magento/Store/Model/Group.php | 35 +- .../StorefrontSwitchStoreViewActionGroup.xml | 1 + app/code/Magento/Store/composer.json | 32 +- app/code/Magento/Store/etc/config.xml | 1 + app/code/Magento/StoreGraphQl/composer.json | 16 +- app/code/Magento/Swagger/composer.json | 14 +- app/code/Magento/SwaggerWebapi/composer.json | 16 +- .../Magento/SwaggerWebapiAsync/composer.json | 18 +- ...AssertStorefrontSwatchColorActionGroup.xml | 3 +- .../AssertSwatchColorActionGroup.xml | 3 +- .../Mftf/Section/AdminManageSwatchSection.xml | 1 + .../StorefrontFilterByImageSwatchTest.xml | 3 +- ...tSwatchProductWithFileCustomOptionTest.xml | 3 + .../Renderer/Listing/ConfigurableTest.php | 15 +- app/code/Magento/Swatches/composer.json | 38 +- .../Magento/SwatchesGraphQl/composer.json | 20 +- .../SwatchesLayeredNavigation/composer.json | 14 +- .../Test/AdminCheckCreditMemoTotalsTest.xml | 2 + app/code/Magento/Tax/composer.json | 44 +- app/code/Magento/TaxGraphQl/composer.json | 16 +- .../Controller/Adminhtml/Rate.php | 5 +- .../Controller/Adminhtml/Rate/ExportPost.php | 19 +- .../Controller/Adminhtml/Rate/ImportPost.php | 65 +- .../Magento/TaxImportExport/composer.json | 24 +- .../view/adminhtml/layout/tax_rule_edit.xml | 3 +- app/code/Magento/Theme/composer.json | 40 +- .../Theme/view/adminhtml/requirejs-config.js | 7 - .../Theme/view/frontend/requirejs-config.js | 3 - app/code/Magento/ThemeGraphQl/composer.json | 14 +- app/code/Magento/Translation/composer.json | 24 +- app/code/Magento/Ui/composer.json | 26 +- app/code/Magento/Ups/composer.json | 30 +- .../Test/Mftf/Data/UrlRewriteData.xml | 4 +- app/code/Magento/UrlRewrite/composer.json | 28 +- .../Magento/UrlRewriteGraphQl/composer.json | 16 +- .../Test/AdminCreateActiveUserEntityTest.xml | 2 +- app/code/Magento/User/composer.json | 28 +- app/code/Magento/Usps/Helper/Data.php | 12 +- app/code/Magento/Usps/Model/Carrier.php | 16 + .../Usps/Model/Config/Backend/UspsUrl.php | 76 + .../Setup/Patch/Data/UpdateAllowedMethods.php | 13 +- .../Usps/Test/Unit/Helper/DataTest.php | 8 + .../Usps/Test/Unit/Model/CarrierTest.php | 3 +- .../Unit/Model/Config/Backend/UspsUrlTest.php | 124 + app/code/Magento/Usps/composer.json | 30 +- .../Magento/Usps/etc/adminhtml/system.xml | 2 + app/code/Magento/Usps/etc/config.xml | 2 +- app/code/Magento/Usps/i18n/en_US.csv | 9 + app/code/Magento/Variable/composer.json | 22 +- app/code/Magento/Vault/composer.json | 29 +- app/code/Magento/VaultGraphQl/composer.json | 14 +- app/code/Magento/Version/composer.json | 14 +- .../Controller/Rest/InputParamsResolver.php | 22 + app/code/Magento/Webapi/composer.json | 26 +- app/code/Magento/WebapiAsync/composer.json | 24 +- app/code/Magento/WebapiSecurity/composer.json | 16 +- app/code/Magento/Weee/composer.json | 40 +- app/code/Magento/WeeeGraphQl/composer.json | 20 +- .../Magento/Widget/Model/Widget/Instance.php | 22 +- app/code/Magento/Widget/composer.json | 32 +- app/code/Magento/Wishlist/composer.json | 48 +- .../Magento/WishlistAnalytics/composer.json | 14 +- .../Magento/WishlistGraphQl/composer.json | 22 +- .../adminhtml/Magento/backend/composer.json | 14 +- .../frontend/Magento/blank/composer.json | 14 +- .../frontend/Magento/blank/i18n/en_US.csv | 1 + .../frontend/Magento/luma/composer.json | 16 +- .../frontend/Magento/luma/i18n/en_US.csv | 1 + app/etc/di.xml | 3 +- app/i18n/Magento/de_DE/composer.json | 6 +- app/i18n/Magento/en_US/composer.json | 6 +- app/i18n/Magento/es_ES/composer.json | 6 +- app/i18n/Magento/fr_FR/composer.json | 6 +- app/i18n/Magento/nl_NL/composer.json | 6 +- app/i18n/Magento/pt_BR/composer.json | 6 +- app/i18n/Magento/zh_Hans_CN/composer.json | 6 +- composer.json | 539 +- composer.lock | 79 +- .../TestCase/GraphQlAbstract.php | 4 +- .../Customer/Api/AccountManagementTest.php | 36 +- .../Customer/Api/CustomerRepositoryTest.php | 41 +- .../GraphQl/Catalog/ProductPriceTest.php | 13 +- .../GraphQl/Customer/IsEmailAvailableTest.php | 35 +- .../SubscribeEmailToNewsletterTest.php | 23 +- .../GraphQl/Quote/CartPromotionsTest.php | 6 +- .../Quote/Customer/RemoveItemFromCartTest.php | 55 +- .../Plugin/CustomerAfterPluginTest.php | 28 +- .../Magento/TestFramework/ErrorLog/Logger.php | 11 +- .../PublisherConsumerController.php | 7 +- .../Command/ProductAttributesCleanUpTest.php | 1 + .../Indexer/Product/Flat/ProcessorTest.php | 11 +- .../Model/Product/CreateCustomOptionsTest.php | 6 +- .../testsuite/Magento/Csp/CspUtilTest.php | 3 +- .../Csp/Helper/CspNonceProviderMock.php | 68 + .../Magento/Csp/Helper/InlineUtilTest.php | 9 +- .../Model/Collector/ConfigCollectorTest.php | 16 +- .../AccountManagement/CreateAccountTest.php | 2 + .../Customer/Model/AccountManagementTest.php | 32 +- .../View/Element/AbstractBlockTest.php | 5 +- .../Controller/Subscriber/NewActionTest.php | 15 +- .../Magento/Quote/Model/Quote/AddressTest.php | 4 +- .../Quote/Model/QuoteManagementTest.php | 8 +- .../Magento/Quote/Model/QuoteTest.php | 2 +- .../Model/ShippingMethodManagementTest.php | 9 +- .../Adminhtml/Order/Creditmemo/SaveTest.php | 5 + .../Magento/Sales/Helper/AdminTest.php | 4 +- .../Rule/Action/Discount/CartFixedTest.php | 9 +- .../Adminhtml/Order/Shipment/SaveTest.php | 8 +- .../Tax/Model/Sales/Total/Quote/TaxTest.php | 14 +- .../Magento/Tax/Model/TaxCalculationTest.php | 23 +- .../Integrity/Magento/Payment/MethodsTest.php | 11 +- .../Magento/Ups/Model/CarrierTest.php | 75 +- .../Ups/_files/ups_rates_response_option9.xml | 299 + .../constraint_modification.mariadb10427.php | 59 + .../constraint_modification.mysql829.php | 59 + .../rollback.mariadb10427.php | 27 + .../rollback.mysql829.php | 27 + .../table_removal.mariadb10427.php | 14 + .../table_removal.mysql829.php | 14 + .../table_rename.mariadb10427.php | 15 + .../table_rename.mysql829.php | 15 + .../fixture/dry_run_log.mysql829.php | 58 + .../fixture/shards.mariadb10427.php | 38 + .../fixture/shards.mysql829.php | 38 + .../disabling_tables.mariadb10427.php | 14 + .../disabling_tables.mysql829.php | 14 + .../Annotation/DataProviderFromFile.php | 6 +- .../TestFramework/TestCase/SetupTestCase.php | 38 +- .../Setup/DeclarativeInstallerTest.php | 38 +- .../testsuite/Magento/Setup/ShardingTest.php | 24 +- .../Test/Js/_files/blacklist/magento.txt | 2 + .../grunt/tools/collect-validation-files.js | 110 +- lib/internal/GnuFreeFont/gpl-3.0.txt | 674 + .../Magento/Framework/Amqp/Config.php | 20 +- .../Magento/Framework/Amqp/composer.json | 18 +- .../Magento/Framework/App/Http/Context.php | 28 +- .../App/Test/Unit/Http/ContextTest.php | 39 +- .../Magento/Framework/Bulk/composer.json | 18 +- .../DB/Adapter/SqlVersionProvider.php | 40 + .../Framework/Data/Form/Element/Image.php | 20 +- .../Data/Test/Unit/Form/Element/ImageTest.php | 65 +- lib/internal/Magento/Framework/DataObject.php | 3 +- .../Filesystem/Directory/PathValidator.php | 7 +- .../Framework/Filesystem/File/Write.php | 19 +- .../Test/Unit/Directory/PathValidatorTest.php | 6 +- .../Framework/Filter/Input/MaliciousCode.php | 31 +- .../Framework/Filter/Input/Purifier.php | 46 + .../Filter/Input/PurifierInterface.php | 19 + .../Magento/Framework/Filter/Template.php | 127 +- .../Filter/Template/FilteringDepthMeter.php | 52 + .../Filter/Template/SignatureProvider.php | 53 + .../Test/Unit/Input/MaliciousCodeTest.php | 48 +- .../Unit/Template/SignatureProviderTest.php | 54 + .../Filter/Test/Unit/TemplateTest.php | 61 +- .../Magento/Framework/Mail/EmailMessage.php | 46 +- .../Framework/MessageQueue/composer.json | 18 +- .../Magento/Framework/RegexValidator.php | 53 + .../Framework/Search/Request/Binder.php | 2 +- .../Schema/Dto/Factories/Table.php | 98 +- .../Framework/Setup/Test/Unit/ListsTest.php | 27 +- .../DB/Adapter/SqlVersionProviderTest.php | 8 +- .../Framework/Url/Test/Unit/ValidatorTest.php | 12 + .../Magento/Framework/Url/Validator.php | 12 +- .../Framework/View/Asset/Collection.php | 8 +- .../View/Asset/GroupedCollection.php | 23 +- .../Framework/View/Element/AbstractBlock.php | 54 +- .../Framework/View/Layout/etc/head.xsd | 9 + .../Test/Unit/Element/AbstractBlockTest.php | 55 +- .../Webapi/ServiceInputProcessor.php | 8 + lib/internal/Magento/Framework/composer.json | 13 +- lib/internal/Magento/Framework/composer.lock | 3985 ++ .../fileUploader/vendor/jquery.ui.widget.js | 1508 +- lib/web/jquery/jquery-ui.js | 36624 ++++++++-------- lib/web/jquery/jquery.validate.js | 37 +- lib/web/jquery/patches/jquery-ui-sortable.js | 298 - lib/web/jquery/ui-modules/data.js | 44 +- .../jquery/ui-modules/disable-selection.js | 56 +- lib/web/jquery/ui-modules/effect.js | 1888 +- .../jquery/ui-modules/effects/effect-blind.js | 92 +- .../ui-modules/effects/effect-bounce.js | 146 +- .../jquery/ui-modules/effects/effect-clip.js | 82 +- .../jquery/ui-modules/effects/effect-drop.js | 92 +- .../ui-modules/effects/effect-explode.js | 182 +- .../jquery/ui-modules/effects/effect-fade.js | 58 +- .../jquery/ui-modules/effects/effect-fold.js | 142 +- .../ui-modules/effects/effect-highlight.js | 78 +- .../jquery/ui-modules/effects/effect-puff.js | 50 +- .../ui-modules/effects/effect-pulsate.js | 78 +- .../jquery/ui-modules/effects/effect-scale.js | 82 +- .../jquery/ui-modules/effects/effect-shake.js | 94 +- .../jquery/ui-modules/effects/effect-size.js | 350 +- .../jquery/ui-modules/effects/effect-slide.js | 104 +- .../ui-modules/effects/effect-transfer.js | 42 +- lib/web/jquery/ui-modules/focusable.js | 110 +- lib/web/jquery/ui-modules/form-reset-mixin.js | 106 +- lib/web/jquery/ui-modules/jquery-patch.js | 100 +- lib/web/jquery/ui-modules/keycode.js | 56 +- lib/web/jquery/ui-modules/labels.js | 76 +- lib/web/jquery/ui-modules/position.js | 976 +- lib/web/jquery/ui-modules/scroll-parent.js | 56 +- lib/web/jquery/ui-modules/tabbable.js | 34 +- lib/web/jquery/ui-modules/unique-id.js | 64 +- lib/web/jquery/ui-modules/version.js | 22 +- lib/web/jquery/ui-modules/widget.js | 1466 +- .../jquery/ui-modules/widgets/accordion.js | 1198 +- .../jquery/ui-modules/widgets/autocomplete.js | 1301 +- lib/web/jquery/ui-modules/widgets/button.js | 842 +- .../ui-modules/widgets/checkboxradio.js | 531 +- .../jquery/ui-modules/widgets/controlgroup.js | 558 +- .../jquery/ui-modules/widgets/datepicker.js | 4430 +- lib/web/jquery/ui-modules/widgets/dialog.js | 1860 +- .../jquery/ui-modules/widgets/draggable.js | 2480 +- .../jquery/ui-modules/widgets/droppable.js | 964 +- lib/web/jquery/ui-modules/widgets/menu.js | 1384 +- lib/web/jquery/ui-modules/widgets/mouse.js | 440 +- .../jquery/ui-modules/widgets/progressbar.js | 302 +- .../jquery/ui-modules/widgets/resizable.js | 2340 +- .../jquery/ui-modules/widgets/selectable.js | 596 +- .../jquery/ui-modules/widgets/selectmenu.js | 1340 +- lib/web/jquery/ui-modules/widgets/slider.js | 1468 +- lib/web/jquery/ui-modules/widgets/sortable.js | 3193 +- lib/web/jquery/ui-modules/widgets/spinner.js | 1116 +- lib/web/jquery/ui-modules/widgets/tabs.js | 1802 +- lib/web/jquery/ui-modules/widgets/tooltip.js | 1003 +- lib/web/legacy-build.min.js | 5 +- lib/web/moment.js | 5 +- lib/web/prototype/prototype.js | 12 +- pub/errors/default/page.phtml | 4 +- pub/errors/processor.php | 2 +- pub/media/.htaccess | 2 +- setup/pub/fonts/opensans/LICENSE-2.0.txt | 202 + 593 files changed, 52900 insertions(+), 41270 deletions(-) mode change 100644 => 100755 app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/NewActionTest.php create mode 100644 app/code/Magento/Checkout/Observer/CspPolicyObserver.php create mode 100644 app/code/Magento/CheckoutAgreements/Test/Mftf/ActionGroup/AdminDeleteAllTermConditionsActionGroup.xml create mode 100644 app/code/Magento/CheckoutAgreements/Test/Mftf/Helper/CheckoutAgreementsHelpers.php create mode 100644 app/code/Magento/Csp/Block/Sri/Hashes.php create mode 100644 app/code/Magento/Csp/Helper/CspNonceProvider.php create mode 100644 app/code/Magento/Csp/Model/Deploy/Package/Processor/PostProcessor/Integrity.php create mode 100644 app/code/Magento/Csp/Model/Deploy/Package/Processor/PostProcessor/Map.php create mode 100644 app/code/Magento/Csp/Model/SubresourceIntegrity.php create mode 100644 app/code/Magento/Csp/Model/SubresourceIntegrity/HashGenerator.php create mode 100644 app/code/Magento/Csp/Model/SubresourceIntegrityCollector.php create mode 100644 app/code/Magento/Csp/Model/SubresourceIntegrityRepository.php create mode 100644 app/code/Magento/Csp/Model/SubresourceIntegrityRepositoryPool.php create mode 100644 app/code/Magento/Csp/Plugin/AddDefaultPropertiesToGroupPlugin.php create mode 100644 app/code/Magento/Csp/Plugin/GenerateAssetIntegrity.php create mode 100644 app/code/Magento/Csp/Plugin/RemoveAllAssetIntegrityHashes.php create mode 100644 app/code/Magento/Csp/Plugin/StoreAssetIntegrityHashes.php create mode 100644 app/code/Magento/Csp/Test/Unit/Model/SubresourceIntegrityRepositoryTest.php create mode 100644 app/code/Magento/Csp/Test/Unit/Plugin/AddDefaultPropertiesToGroupPluginTest.php create mode 100644 app/code/Magento/Csp/Test/Unit/Plugin/StoreAssetIntegrityHashesTest.php create mode 100644 app/code/Magento/Csp/etc/acl.xml create mode 100644 app/code/Magento/Csp/etc/adminhtml/system.xml create mode 100644 app/code/Magento/Csp/view/adminhtml/layout/sales_order_create_index.xml create mode 100644 app/code/Magento/Csp/view/base/templates/sri/hashes.phtml create mode 100644 app/code/Magento/Csp/view/base/web/js/sri.js create mode 100644 app/code/Magento/Csp/view/frontend/layout/checkout_index_index.xml create mode 100644 app/code/Magento/Customer/Model/Plugin/ClearSessionsAfterLogoutPlugin.php create mode 100644 app/code/Magento/EncryptionKey/Console/Command/UpdateEncryptionKeyCommand.php create mode 100755 app/code/Magento/Fedex/Model/Config/Backend/FedexUrl.php create mode 100755 app/code/Magento/Fedex/Test/Unit/Model/Config/Backend/FedexUrlTest.php mode change 100644 => 100755 app/code/Magento/PageCache/Controller/Block.php create mode 100644 app/code/Magento/Quote/Plugin/QuoteAddress.php create mode 100644 app/code/Magento/Quote/Plugin/ValidateQuoteOrigOrder.php create mode 100644 app/code/Magento/Sales/Test/Mftf/ActionGroup/AdminNavigateToNewOrderPageNewCustomerActionGroup.xml create mode 100644 app/code/Magento/Sales/ViewModel/Order/Create/SidebarPermissionCheck.php create mode 100644 app/code/Magento/Sales/etc/csp_whitelist.xml mode change 100644 => 100755 app/code/Magento/SalesRule/Controller/Adminhtml/Promo/Quote/Generate.php mode change 100644 => 100755 app/code/Magento/SalesRule/Test/Unit/Controller/Adminhtml/Promo/Quote/GenerateTest.php mode change 100644 => 100755 app/code/Magento/SalesRule/etc/adminhtml/system.xml mode change 100644 => 100755 app/code/Magento/SalesRule/etc/config.xml mode change 100644 => 100755 app/code/Magento/SalesRule/etc/di.xml mode change 100644 => 100755 app/code/Magento/SalesRule/i18n/en_US.csv create mode 100644 app/code/Magento/Usps/Model/Config/Backend/UspsUrl.php create mode 100644 app/code/Magento/Usps/Test/Unit/Model/Config/Backend/UspsUrlTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Csp/Helper/CspNonceProviderMock.php create mode 100644 dev/tests/integration/testsuite/Magento/Ups/_files/ups_rates_response_option9.xml create mode 100644 dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/declarative_installer/constraint_modification.mariadb10427.php create mode 100644 dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/declarative_installer/constraint_modification.mysql829.php create mode 100644 dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/declarative_installer/rollback.mariadb10427.php create mode 100644 dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/declarative_installer/rollback.mysql829.php create mode 100644 dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/declarative_installer/table_removal.mariadb10427.php create mode 100644 dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/declarative_installer/table_removal.mysql829.php create mode 100644 dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/declarative_installer/table_rename.mariadb10427.php create mode 100644 dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/declarative_installer/table_rename.mysql829.php create mode 100644 dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/dry_run_log.mysql829.php create mode 100644 dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule2/fixture/shards.mariadb10427.php create mode 100644 dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule2/fixture/shards.mysql829.php create mode 100644 dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule9/fixture/declarative_installer/disabling_tables.mariadb10427.php create mode 100644 dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule9/fixture/declarative_installer/disabling_tables.mysql829.php create mode 100644 lib/internal/GnuFreeFont/gpl-3.0.txt create mode 100644 lib/internal/Magento/Framework/Filter/Input/Purifier.php create mode 100644 lib/internal/Magento/Framework/Filter/Input/PurifierInterface.php create mode 100644 lib/internal/Magento/Framework/Filter/Template/FilteringDepthMeter.php create mode 100644 lib/internal/Magento/Framework/Filter/Template/SignatureProvider.php create mode 100644 lib/internal/Magento/Framework/Filter/Test/Unit/Template/SignatureProviderTest.php create mode 100644 lib/internal/Magento/Framework/RegexValidator.php create mode 100644 lib/internal/Magento/Framework/composer.lock delete mode 100644 lib/web/jquery/patches/jquery-ui-sortable.js create mode 100644 setup/pub/fonts/opensans/LICENSE-2.0.txt diff --git a/app/code/Magento/AdminAnalytics/ViewModel/Metadata.php b/app/code/Magento/AdminAnalytics/ViewModel/Metadata.php index 15d4afef086c..1d8421e74376 100644 --- a/app/code/Magento/AdminAnalytics/ViewModel/Metadata.php +++ b/app/code/Magento/AdminAnalytics/ViewModel/Metadata.php @@ -9,7 +9,9 @@ namespace Magento\AdminAnalytics\ViewModel; use Magento\Config\Model\Config\Backend\Admin\Custom; +use Magento\Csp\Helper\CspNonceProvider; use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Framework\App\ObjectManager; use Magento\Framework\App\ProductMetadataInterface; use Magento\Backend\Model\Auth\Session; use Magento\Framework\App\State; @@ -21,6 +23,11 @@ */ class Metadata implements ArgumentInterface { + /** + * @var string + */ + private $nonce; + /** * @var State */ @@ -41,22 +48,33 @@ class Metadata implements ArgumentInterface */ private $config; + /** + * @var CspNonceProvider + */ + private $nonceProvider; + /** * @param ProductMetadataInterface $productMetadata * @param Session $authSession * @param State $appState * @param ScopeConfigInterface $config + * @param CspNonceProvider|null $nonceProvider */ public function __construct( ProductMetadataInterface $productMetadata, Session $authSession, State $appState, - ScopeConfigInterface $config + ScopeConfigInterface $config, + CspNonceProvider $nonceProvider = null ) { $this->productMetadata = $productMetadata; $this->authSession = $authSession; $this->appState = $appState; $this->config = $config; + + $this->nonceProvider = $nonceProvider ?: ObjectManager::getInstance()->get(CspNonceProvider::class); + + $this->nonce = $this->nonceProvider->generateNonce(); } /** @@ -156,4 +174,14 @@ public function getCurrentUserRoleName(): string { return $this->authSession->getUser()->getRole()->getRoleName(); } + + /** + * Get a random nonce for each request. + * + * @return string + */ + public function getNonce(): string + { + return $this->nonce; + } } diff --git a/app/code/Magento/AdminAnalytics/composer.json b/app/code/Magento/AdminAnalytics/composer.json index ef3829fd149c..b3e463f67181 100644 --- a/app/code/Magento/AdminAnalytics/composer.json +++ b/app/code/Magento/AdminAnalytics/composer.json @@ -1,23 +1,25 @@ { "name": "magento/module-admin-analytics", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.4.4-p9", "require": { "php": "~7.4.0||~8.1.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-config": "*", - "magento/module-store": "*", - "magento/module-ui": "*", - "magento/module-release-notification": "*" + "magento/framework": "103.0.*", + "magento/module-backend": "102.0.*", + "magento/module-config": "101.2.*", + "magento/module-store": "101.1.*", + "magento/module-ui": "101.2.*", + "magento/module-release-notification": "100.4.*", + "magento/module-csp": "100.4.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -27,3 +29,4 @@ } } } + diff --git a/app/code/Magento/AdminAnalytics/view/adminhtml/templates/tracking.phtml b/app/code/Magento/AdminAnalytics/view/adminhtml/templates/tracking.phtml index 4b155e1a5ae5..0ccd4d1b2608 100644 --- a/app/code/Magento/AdminAnalytics/view/adminhtml/templates/tracking.phtml +++ b/app/code/Magento/AdminAnalytics/view/adminhtml/templates/tracking.phtml @@ -6,6 +6,7 @@ /** * @var \Magento\Framework\View\Helper\SecureHtmlRenderer $secureRenderer + * @var \Magento\Framework\Escaper $escaper */ ?> @@ -22,18 +23,25 @@ getMetadata(); +$nonce = $escaper->escapeJs($metadata->getNonce()); $scriptString = ' var adminAnalyticsMetadata = { - "secure_base_url": "' . $block->escapeJs($metadata->getSecureBaseUrlForScope()) . '", - "version": "' . $block->escapeJs($metadata->getMagentoVersion()) . '", - "product_edition": "' . $block->escapeJs($metadata->getProductEdition()) . '", - "user": "' . $block->escapeJs($metadata->getCurrentUser()) . '", - "mode": "' . $block->escapeJs($metadata->getMode()) . '", - "store_name_default": "' . $block->escapeJs($metadata->getStoreNameForScope()) . '", - "admin_user_created": "' . $block->escapeJs($metadata->getCurrentUserCreatedDate()) . '", - "admin_user_logdate": "' . $block->escapeJs($metadata->getCurrentUserLogDate()) . '", - "admin_user_role_name": "' . $block->escapeJs($metadata->getCurrentUserRoleName()) . '" + "secure_base_url": "' . $escaper->escapeJs($metadata->getSecureBaseUrlForScope()) . '", + "version": "' . $escaper->escapeJs($metadata->getMagentoVersion()) . '", + "product_edition": "' . $escaper->escapeJs($metadata->getProductEdition()) . '", + "user": "' . $escaper->escapeJs($metadata->getCurrentUser()) . '", + "mode": "' . $escaper->escapeJs($metadata->getMode()) . '", + "store_name_default": "' . $escaper->escapeJs($metadata->getStoreNameForScope()) . '", + "admin_user_created": "' . $escaper->escapeJs($metadata->getCurrentUserCreatedDate()) . '", + "admin_user_logdate": "' . $escaper->escapeJs($metadata->getCurrentUserLogDate()) . '", + "admin_user_role_name": "' . $escaper->escapeJs($metadata->getCurrentUserRoleName()) . '" }; + + var digitalData = { + "nonce": "' . $nonce . '" + }; + + var cspNonce = "' . $nonce . '"; '; ?> renderTag('script', [], $scriptString, false); ?> diff --git a/app/code/Magento/AdminNotification/composer.json b/app/code/Magento/AdminNotification/composer.json index 28ca1f626a2c..6bfb98da0224 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.4.3", "require": { "php": "~7.4.0||~8.1.0", "lib-libxml": "*", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-media-storage": "*", - "magento/module-store": "*", - "magento/module-ui": "*", - "magento/module-config": "*" + "magento/framework": "103.0.*", + "magento/module-backend": "102.0.*", + "magento/module-media-storage": "100.4.*", + "magento/module-store": "101.1.*", + "magento/module-ui": "101.2.*", + "magento/module-config": "101.2.*" }, - "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 59ea74cf4ddc..f40a9ef5750c 100644 --- a/app/code/Magento/AdvancedPricingImportExport/composer.json +++ b/app/code/Magento/AdvancedPricingImportExport/composer.json @@ -1,26 +1,27 @@ { "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.4.4", "require": { "php": "~7.4.0||~8.1.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/module-directory": "*" + "magento/framework": "103.0.*", + "magento/module-catalog": "104.0.*", + "magento/module-catalog-import-export": "101.1.*", + "magento/module-catalog-inventory": "100.4.*", + "magento/module-customer": "103.0.*", + "magento/module-eav": "102.1.*", + "magento/module-import-export": "101.0.*", + "magento/module-store": "101.1.*", + "magento/module-directory": "100.4.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -30,3 +31,4 @@ } } } + diff --git a/app/code/Magento/AdvancedSearch/composer.json b/app/code/Magento/AdvancedSearch/composer.json index 30205c5255cd..52d4a2b3deb8 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.4.2", "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": "103.0.*", + "magento/module-backend": "102.0.*", + "magento/module-catalog": "104.0.*", + "magento/module-catalog-search": "102.0.*", + "magento/module-config": "101.2.*", + "magento/module-customer": "103.0.*", + "magento/module-search": "101.1.*", + "magento/module-store": "101.1.*", "php": "~7.4.0||~8.1.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 c7d8d49fb000..6f2b360634d3 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.4.2", "require": { - "magento/framework": "*", - "magento/framework-amqp": "*", - "magento/framework-message-queue": "*", + "magento/framework": "103.0.*", + "magento/framework-amqp": "100.4.*", + "magento/framework-message-queue": "100.4.*", "php": "~7.4.0||~8.1.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 4d4685dda0b5..53d1e8d12db2 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.4.2", "require": { - "magento/framework": "*", - "magento/framework-amqp": "*", - "magento/module-store": "*", + "magento/framework": "103.0.*", + "magento/framework-amqp": "100.4.*", + "magento/module-store": "101.1.*", "php": "~7.4.0||~8.1.0" }, "suggest": { - "magento/module-asynchronous-operations": "*", - "magento/framework-message-queue": "*" + "magento/module-asynchronous-operations": "100.4.*", + "magento/framework-message-queue": "100.4.*" }, - "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/Test/Mftf/ActionGroup/AssertAdminAdvancedReportingPageUrlActionGroup.xml b/app/code/Magento/Analytics/Test/Mftf/ActionGroup/AssertAdminAdvancedReportingPageUrlActionGroup.xml index ac4fca843a36..3f0bedd344d2 100644 --- a/app/code/Magento/Analytics/Test/Mftf/ActionGroup/AssertAdminAdvancedReportingPageUrlActionGroup.xml +++ b/app/code/Magento/Analytics/Test/Mftf/ActionGroup/AssertAdminAdvancedReportingPageUrlActionGroup.xml @@ -15,6 +15,6 @@ - + diff --git a/app/code/Magento/Analytics/composer.json b/app/code/Magento/Analytics/composer.json index 9bf08b4b068c..2a29c61b93ae 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.4.0||~8.1.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.4.4-p4", + "require": { + "php": "~7.4.0||~8.1.0", + "magento/module-backend": "102.0.*", + "magento/module-config": "101.2.*", + "magento/module-integration": "100.4.*", + "magento/module-store": "101.1.*", + "magento/framework": "103.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 b09ca94052e8..ba34d2f770ee 100644 --- a/app/code/Magento/AsynchronousOperations/composer.json +++ b/app/code/Magento/AsynchronousOperations/composer.json @@ -1,27 +1,28 @@ { "name": "magento/module-asynchronous-operations", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.4.4", "require": { - "magento/framework": "*", - "magento/framework-message-queue": "*", - "magento/framework-bulk": "*", - "magento/module-authorization": "*", - "magento/module-backend": "*", - "magento/module-ui": "*", + "magento/framework": "103.0.*", + "magento/framework-message-queue": "100.4.*", + "magento/framework-bulk": "101.0.*", + "magento/module-authorization": "100.4.*", + "magento/module-backend": "102.0.*", + "magento/module-ui": "101.2.*", "php": "~7.4.0||~8.1.0" }, "suggest": { - "magento/module-admin-notification": "*", + "magento/module-admin-notification": "100.4.*", "magento/module-logging": "*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -31,3 +32,4 @@ } } } + diff --git a/app/code/Magento/Authorization/composer.json b/app/code/Magento/Authorization/composer.json index d122e8b29b46..b4b0fa6ab43a 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.4.4", "require": { "php": "~7.4.0||~8.1.0", - "magento/framework": "*", - "magento/module-backend": "*" + "magento/framework": "103.0.*", + "magento/module-backend": "102.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/AwsS3/composer.json b/app/code/Magento/AwsS3/composer.json index 470580df35f5..874341cce831 100644 --- a/app/code/Magento/AwsS3/composer.json +++ b/app/code/Magento/AwsS3/composer.json @@ -1,20 +1,21 @@ { "name": "magento/module-aws-s3", "description": "N/A", + "type": "magento2-module", + "license": [ + "proprietary" + ], "config": { "sort-packages": true }, + "version": "100.4.2", "require": { "php": "~7.4.0||~8.1.0", - "magento/framework": "*", - "magento/module-remote-storage": "*", + "magento/framework": "103.0.*", + "magento/module-remote-storage": "100.4.*", "league/flysystem": "^2.0", "league/flysystem-aws-s3-v3": "^2.0" }, - "type": "magento2-module", - "license": [ - "proprietary" - ], "autoload": { "files": [ "registration.php" @@ -24,3 +25,4 @@ } } } + diff --git a/app/code/Magento/Backend/Block/System/Store/Grid/Render/Group.php b/app/code/Magento/Backend/Block/System/Store/Grid/Render/Group.php index 3d7154eb20f9..34d588c2dc08 100644 --- a/app/code/Magento/Backend/Block/System/Store/Grid/Render/Group.php +++ b/app/code/Magento/Backend/Block/System/Store/Grid/Render/Group.php @@ -3,8 +3,12 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Backend\Block\System\Store\Grid\Render; +use Magento\Framework\DataObject; + /** * Store render group * @@ -13,9 +17,9 @@ class Group extends \Magento\Backend\Block\Widget\Grid\Column\Renderer\AbstractRenderer { /** - * {@inheritdoc} + * @inheritDoc */ - public function render(\Magento\Framework\DataObject $row) + public function render(DataObject $row) { if (!$row->getData($this->getColumn()->getIndex())) { return null; @@ -28,6 +32,6 @@ public function render(\Magento\Framework\DataObject $row) '">' . $this->escapeHtml($row->getData($this->getColumn()->getIndex())) . '
' - . '(' . __('Code') . ': ' . $row->getGroupCode() . ')'; + . '(' . __('Code') . ': ' . $this->escapeHtml($row->getGroupCode()) . ')'; } } diff --git a/app/code/Magento/Backend/composer.json b/app/code/Magento/Backend/composer.json index 65aa05fe71e5..4d55a6b661ac 100644 --- a/app/code/Magento/Backend/composer.json +++ b/app/code/Magento/Backend/composer.json @@ -1,38 +1,39 @@ { "name": "magento/module-backend", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "102.0.4-p9", "require": { "php": "~7.4.0||~8.1.0", - "magento/framework": "*", - "magento/module-backup": "*", - "magento/module-catalog": "*", - "magento/module-config": "*", - "magento/module-cms": "*", - "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": "*" + "magento/framework": "103.0.*", + "magento/module-backup": "100.4.*", + "magento/module-catalog": "104.0.*", + "magento/module-config": "101.2.*", + "magento/module-cms": "104.0.*", + "magento/module-customer": "103.0.*", + "magento/module-developer": "100.4.*", + "magento/module-directory": "100.4.*", + "magento/module-eav": "102.1.*", + "magento/module-quote": "101.2.*", + "magento/module-reports": "100.4.*", + "magento/module-require-js": "100.4.*", + "magento/module-sales": "103.0.*", + "magento/module-security": "100.4.*", + "magento/module-store": "101.1.*", + "magento/module-translation": "100.4.*", + "magento/module-ui": "101.2.*", + "magento/module-user": "101.2.*" }, "suggest": { - "magento/module-theme": "*" + "magento/module-theme": "101.1.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php", @@ -43,3 +44,4 @@ } } } + diff --git a/app/code/Magento/Backend/etc/adminhtml/system.xml b/app/code/Magento/Backend/etc/adminhtml/system.xml index 57cc36da95cf..04a52530e52c 100644 --- a/app/code/Magento/Backend/etc/adminhtml/system.xml +++ b/app/code/Magento/Backend/etc/adminhtml/system.xml @@ -10,6 +10,9 @@ + + + diff --git a/app/code/Magento/Backup/composer.json b/app/code/Magento/Backup/composer.json index e7437a3077aa..137a008f1020 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.4.4", "require": { "php": "~7.4.0||~8.1.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-cron": "*", - "magento/module-store": "*" + "magento/framework": "103.0.*", + "magento/module-backend": "102.0.*", + "magento/module-cron": "100.4.*", + "magento/module-store": "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/Bundle/Test/Mftf/ActionGroup/StoreFrontAddProductToCartFromBundleActionGroup.xml b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/StoreFrontAddProductToCartFromBundleActionGroup.xml index 7038ad90b81b..45e26cf327dc 100644 --- a/app/code/Magento/Bundle/Test/Mftf/ActionGroup/StoreFrontAddProductToCartFromBundleActionGroup.xml +++ b/app/code/Magento/Bundle/Test/Mftf/ActionGroup/StoreFrontAddProductToCartFromBundleActionGroup.xml @@ -17,11 +17,15 @@ + + + + diff --git a/app/code/Magento/Bundle/composer.json b/app/code/Magento/Bundle/composer.json index 47be75a42c25..782f460495f3 100644 --- a/app/code/Magento/Bundle/composer.json +++ b/app/code/Magento/Bundle/composer.json @@ -1,39 +1,40 @@ { "name": "magento/module-bundle", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "101.0.4-p7", "require": { "php": "~7.4.0||~8.1.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/module-directory": "*" + "magento/framework": "103.0.*", + "magento/module-backend": "102.0.*", + "magento/module-catalog": "104.0.*", + "magento/module-catalog-inventory": "100.4.*", + "magento/module-catalog-rule": "101.2.*", + "magento/module-checkout": "100.4.*", + "magento/module-config": "101.2.*", + "magento/module-customer": "103.0.*", + "magento/module-eav": "102.1.*", + "magento/module-gift-message": "100.4.*", + "magento/module-media-storage": "100.4.*", + "magento/module-quote": "101.2.*", + "magento/module-sales": "103.0.*", + "magento/module-store": "101.1.*", + "magento/module-tax": "100.4.*", + "magento/module-ui": "101.2.*", + "magento/module-directory": "100.4.*" }, "suggest": { - "magento/module-webapi": "*", - "magento/module-bundle-sample-data": "*", - "magento/module-sales-rule": "*" + "magento/module-webapi": "100.4.*", + "magento/module-bundle-sample-data": "Sample Data version: 100.4.*", + "magento/module-sales-rule": "101.2.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -43,3 +44,4 @@ } } } + diff --git a/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle/option/radio.phtml b/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle/option/radio.phtml index 706b28049470..5f3e219866ba 100644 --- a/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle/option/radio.phtml +++ b/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle/option/radio.phtml @@ -4,6 +4,8 @@ * See COPYING.txt for license details. */ use Magento\Bundle\ViewModel\ValidateQuantity; + +// phpcs:disable Generic.Files.LineLength.TooLong ?> getOption(); ?> @@ -20,42 +22,45 @@ $viewModel = $block->getData('validateQuantityViewModel');
- showSingle()) : ?> + showSingle()): ?> getSelectionTitlePrice($_selections[0]) ?> getTierPriceRenderer()->renderTierPrice($_selections[0]) ?> - - getRequired()) : ?> + + getRequired()): ?>
isSalable())?'':' checked="checked" ' ?> + isSalable())?'':' checked="checked" ' ?> value=""/>
- +
getRequired()) { echo 'data-validate="{\'validate-one-required-by-name\':true}"'; }?> + getRequired()) { + echo 'data-validate="{\'validate-one-required-by-name\':true}"'; + } ?> name="bundle_option[escapeHtmlAttr($_option->getId()) ?>]" data-selector="bundle_option[escapeHtmlAttr($_option->getId()) ?>]" - isSelected($_selection)) { echo ' checked="checked"'; } ?> - isSaleable()) { echo ' disabled="disabled"'; } ?> - value="escapeHtmlAttr($_selection->getSelectionId()) ?>"/> + isSelected($_selection)) { echo ' checked="checked"'; } ?> + isSaleable()) { echo ' disabled="disabled"'; } ?> + value="escapeHtmlAttr($_selection->getSelectionId()) ?>" + data-errors-message-box="#validation-message-box-radio"/>
+
- id="bundle-option-escapeHtmlAttr($_option->getId()) ?>-qty-input" - class="input-text qty" - type="number" - min="0" - data-validate="escapeHtmlAttr($viewModel->getQuantityValidators()) ?>" - name="bundle_option_qty[escapeHtmlAttr($_option->getId()) ?>]" - data-selector="bundle_option_qty[escapeHtmlAttr($_option->getId()) ?>]" - value="escapeHtmlAttr($_defaultQty) ?>"/> + id="bundle-option-escapeHtmlAttr($_option->getId()) ?>-qty-input" + class="input-text qty" + type="number" + min="0" + data-validate="escapeHtmlAttr($viewModel->getQuantityValidators()) ?>" + name="bundle_option_qty[escapeHtmlAttr($_option->getId()) ?>]" + data-selector="bundle_option_qty[escapeHtmlAttr($_option->getId()) ?>]" + value="escapeHtmlAttr($_defaultQty) ?>"/>
diff --git a/app/code/Magento/BundleGraphQl/composer.json b/app/code/Magento/BundleGraphQl/composer.json index 70a619cbf683..62f133708593 100644 --- a/app/code/Magento/BundleGraphQl/composer.json +++ b/app/code/Magento/BundleGraphQl/composer.json @@ -2,23 +2,24 @@ "name": "magento/module-bundle-graph-ql", "description": "N/A", "type": "magento2-module", - "require": { - "php": "~7.4.0||~8.1.0", - "magento/module-catalog": "*", - "magento/module-bundle": "*", - "magento/module-graph-ql": "*", - "magento/module-catalog-graph-ql": "*", - "magento/module-quote": "*", - "magento/module-quote-graph-ql": "*", - "magento/module-store": "*", - "magento/module-sales": "*", - "magento/module-sales-graph-ql": "*", - "magento/framework": "*" - }, "license": [ "OSL-3.0", "AFL-3.0" ], + "version": "100.4.4", + "require": { + "php": "~7.4.0||~8.1.0", + "magento/module-catalog": "104.0.*", + "magento/module-bundle": "101.0.*", + "magento/module-graph-ql": "100.4.*", + "magento/module-catalog-graph-ql": "100.4.*", + "magento/module-quote": "101.2.*", + "magento/module-quote-graph-ql": "100.4.*", + "magento/module-store": "101.1.*", + "magento/module-sales": "103.0.*", + "magento/module-sales-graph-ql": "100.4.*", + "magento/framework": "103.0.*" + }, "autoload": { "files": [ "registration.php" @@ -28,3 +29,4 @@ } } } + diff --git a/app/code/Magento/BundleImportExport/composer.json b/app/code/Magento/BundleImportExport/composer.json index ff7d0acc7c48..1c5cf7e70ab1 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.4.3", "require": { "php": "~7.4.0||~8.1.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": "103.0.*", + "magento/module-bundle": "101.0.*", + "magento/module-store": "101.1.*", + "magento/module-catalog": "104.0.*", + "magento/module-catalog-import-export": "101.1.*", + "magento/module-eav": "102.1.*", + "magento/module-import-export": "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/CacheInvalidate/composer.json b/app/code/Magento/CacheInvalidate/composer.json index c756a5fe602e..7985a50cb2e2 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.4.2", "require": { "php": "~7.4.0||~8.1.0", - "magento/framework": "*", - "magento/module-page-cache": "*" + "magento/framework": "103.0.*", + "magento/module-page-cache": "100.4.*" }, - "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/Test/Mftf/Test/StorefrontCaptchaOnOnepageCheckoutPyamentTest.xml b/app/code/Magento/Captcha/Test/Mftf/Test/StorefrontCaptchaOnOnepageCheckoutPyamentTest.xml index 912e637dc534..4ab4ec7f055f 100644 --- a/app/code/Magento/Captcha/Test/Mftf/Test/StorefrontCaptchaOnOnepageCheckoutPyamentTest.xml +++ b/app/code/Magento/Captcha/Test/Mftf/Test/StorefrontCaptchaOnOnepageCheckoutPyamentTest.xml @@ -21,6 +21,7 @@ + 20 @@ -62,6 +63,7 @@ + diff --git a/app/code/Magento/Captcha/composer.json b/app/code/Magento/Captcha/composer.json index b276555326eb..a90ec4cd5568 100644 --- a/app/code/Magento/Captcha/composer.json +++ b/app/code/Magento/Captcha/composer.json @@ -1,27 +1,28 @@ { "name": "magento/module-captcha", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.4.4-p4", "require": { "php": "~7.4.0||~8.1.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-checkout": "*", - "magento/module-customer": "*", - "magento/module-sales": "*", - "magento/module-store": "*", - "magento/module-authorization": "*", + "magento/framework": "103.0.*", + "magento/module-backend": "102.0.*", + "magento/module-checkout": "100.4.*", + "magento/module-customer": "103.0.*", + "magento/module-sales": "103.0.*", + "magento/module-store": "101.1.*", + "magento/module-authorization": "100.4.*", "laminas/laminas-captcha": "^2.11.0", "laminas/laminas-db": "^2.13.4", "laminas/laminas-session": "^2.12.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/CardinalCommerce/composer.json b/app/code/Magento/CardinalCommerce/composer.json index 4c49c92cec1e..097783f77e43 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.4.2", "require": { "php": "~7.4.0||~8.1.0", - "magento/framework": "*", - "magento/module-checkout": "*", - "magento/module-payment": "*", - "magento/module-store": "*" + "magento/framework": "103.0.*", + "magento/module-checkout": "100.4.*", + "magento/module-payment": "100.4.*", + "magento/module-store": "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/Catalog/Controller/Adminhtml/Product/NewAction.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/NewAction.php index 0b1ef98c386c..ea14dbc1ce62 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/NewAction.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/NewAction.php @@ -4,18 +4,21 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Catalog\Controller\Adminhtml\Product; -use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface; -use Magento\Backend\App\Action; use Magento\Catalog\Controller\Adminhtml\Product; +use Magento\Framework\App\Action\HttpGetActionInterface as HttpGetActionInterface; use Magento\Framework\App\ObjectManager; +use Magento\Framework\RegexValidator; class NewAction extends \Magento\Catalog\Controller\Adminhtml\Product implements HttpGetActionInterface { /** * @var Initialization\StockDataFilter * @deprecated 101.0.0 + * @see Initialization\StockDataFilter */ protected $stockFilter; @@ -30,23 +33,32 @@ class NewAction extends \Magento\Catalog\Controller\Adminhtml\Product implements protected $resultForwardFactory; /** - * @param Action\Context $context + * @var RegexValidator + */ + private RegexValidator $regexValidator; + + /** + * @param Context $context * @param Builder $productBuilder * @param Initialization\StockDataFilter $stockFilter * @param \Magento\Framework\View\Result\PageFactory $resultPageFactory * @param \Magento\Backend\Model\View\Result\ForwardFactory $resultForwardFactory + * @param RegexValidator|null $regexValidator */ public function __construct( \Magento\Backend\App\Action\Context $context, Product\Builder $productBuilder, Initialization\StockDataFilter $stockFilter, \Magento\Framework\View\Result\PageFactory $resultPageFactory, - \Magento\Backend\Model\View\Result\ForwardFactory $resultForwardFactory + \Magento\Backend\Model\View\Result\ForwardFactory $resultForwardFactory, + RegexValidator $regexValidator = null ) { $this->stockFilter = $stockFilter; parent::__construct($context, $productBuilder); $this->resultPageFactory = $resultPageFactory; $this->resultForwardFactory = $resultForwardFactory; + $this->regexValidator = $regexValidator + ?: ObjectManager::getInstance()->get(RegexValidator::class); } /** @@ -56,6 +68,11 @@ public function __construct( */ public function execute() { + $typeId = $this->getRequest()->getParam('type'); + if (!$this->regexValidator->validateParamRegex($typeId)) { + return $this->resultForwardFactory->create()->forward('noroute'); + } + if (!$this->getRequest()->getParam('set')) { return $this->resultForwardFactory->create()->forward('noroute'); } 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 4c4daccb9017..8afbdf7425ca 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 @@ -49,6 +49,7 @@ class ValidatorInfo extends Validator * @var IoFile */ private $ioFile; + /** * @var NotProtectedExtension */ @@ -147,12 +148,14 @@ 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; - } + + if (isset($pathInfo['extension']) + && (empty($pathInfo['extension']) || !$this->fileValidator->isValid($pathInfo['extension'])) + ) { + return false; } } + return true; } diff --git a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryMainSection.xml b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryMainSection.xml index f3a0919f6c72..cf419c8f27c0 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryMainSection.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Section/StorefrontCategoryMainSection.xml @@ -40,5 +40,6 @@ + diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminApplyTierPriceToProductTest/AdminApplyTierPriceToProductTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminApplyTierPriceToProductTest/AdminApplyTierPriceToProductTest.xml index 8add42ec7493..b2d36589dd25 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminApplyTierPriceToProductTest/AdminApplyTierPriceToProductTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminApplyTierPriceToProductTest/AdminApplyTierPriceToProductTest.xml @@ -230,6 +230,7 @@ + diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminMassProductAttributeUpdateAddedToQueueTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminMassProductAttributeUpdateAddedToQueueTest.xml index c887ed5b4281..1d75f49ab674 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminMassProductAttributeUpdateAddedToQueueTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminMassProductAttributeUpdateAddedToQueueTest.xml @@ -46,8 +46,10 @@ + + diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminRestrictedUserAddCategoryFromProductPageTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminRestrictedUserAddCategoryFromProductPageTest.xml index 795c2ac77acd..fb4a4a2bfac8 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminRestrictedUserAddCategoryFromProductPageTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminRestrictedUserAddCategoryFromProductPageTest.xml @@ -97,6 +97,7 @@ + diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatCatalogTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatCatalogTest.xml index 3af6de07e561..71c82f654310 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatCatalogTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/AdminUpdateSimpleProductWithRegularPriceInStockEnabledFlatCatalogTest.xml @@ -6,7 +6,7 @@ */ --> - @@ -26,6 +26,9 @@ + + + @@ -33,6 +36,7 @@ + diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/EndToEndB2CAdminTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/EndToEndB2CAdminTest.xml index 3cb36ae2c373..33e34018b5f4 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/EndToEndB2CAdminTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/EndToEndB2CAdminTest.xml @@ -21,8 +21,12 @@ + + + + diff --git a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontProductWithEmptyAttributeTest.xml b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontProductWithEmptyAttributeTest.xml index 203fa753d10f..5376441021d6 100644 --- a/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontProductWithEmptyAttributeTest.xml +++ b/app/code/Magento/Catalog/Test/Mftf/Test/StorefrontProductWithEmptyAttributeTest.xml @@ -26,22 +26,24 @@ - + - + + + - + - + @@ -49,6 +51,6 @@ - + diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/NewActionTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/NewActionTest.php old mode 100644 new mode 100755 index 974c85b2b5c9..b1b649bf551c --- a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/NewActionTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/NewActionTest.php @@ -16,6 +16,9 @@ use Magento\Catalog\Controller\Adminhtml\Product\NewAction; use Magento\Catalog\Model\Product; use Magento\Catalog\Test\Unit\Controller\Adminhtml\ProductTest; +use Magento\Framework\RegexValidator; +use Magento\Framework\Validator\Regex; +use Magento\Framework\Validator\RegexFactory; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use Magento\Framework\View\Result\PageFactory; use PHPUnit\Framework\MockObject\MockObject; @@ -42,6 +45,26 @@ class NewActionTest extends ProductTest */ protected $initializationHelper; + /** + * @var RegexValidator|MockObject + */ + private $regexValidator; + + /** + * @var RegexFactory + */ + private $regexValidatorFactoryMock; + + /** + * @var Regex|MockObject + */ + private $regexValidatorMock; + + /** + * @var ForwardFactory&MockObject|MockObject + */ + private $resultForwardFactory; + protected function setUp(): void { $this->productBuilder = $this->createPartialMock( @@ -63,37 +86,69 @@ protected function setUp(): void ->disableOriginalConstructor() ->setMethods(['create']) ->getMock(); - $resultPageFactory->expects($this->atLeastOnce()) - ->method('create') - ->willReturn($this->resultPage); $this->resultForward = $this->getMockBuilder(Forward::class) ->disableOriginalConstructor() ->getMock(); - $resultForwardFactory = $this->getMockBuilder(ForwardFactory::class) + $this->resultForwardFactory = $this->getMockBuilder(ForwardFactory::class) + ->disableOriginalConstructor() + ->onlyMethods(['create']) + ->getMock(); + + $this->regexValidatorFactoryMock = $this->getMockBuilder(RegexFactory::class) ->disableOriginalConstructor() ->setMethods(['create']) ->getMock(); - $resultForwardFactory->expects($this->any()) - ->method('create') - ->willReturn($this->resultForward); + $this->regexValidatorMock = $this->createMock(Regex::class); + $this->regexValidatorFactoryMock->method('create') + ->willReturn($this->regexValidatorMock); + $this->regexValidator = new regexValidator($this->regexValidatorFactoryMock); $this->action = (new ObjectManager($this))->getObject( NewAction::class, [ 'context' => $this->initContext(), 'productBuilder' => $this->productBuilder, 'resultPageFactory' => $resultPageFactory, - 'resultForwardFactory' => $resultForwardFactory, + 'resultForwardFactory' => $this->resultForwardFactory, + 'regexValidator' => $this->regexValidator, ] ); } - public function testExecute() + /** + * @return void + */ + public function testExecute(): void { - $this->action->getRequest()->expects($this->any())->method('getParam')->willReturn(true); - $this->action->getRequest()->expects($this->any())->method('getFullActionName') - ->willReturn('catalog_product_new'); - $this->action->execute(); + $value = 'catalog_product_new'; + + $this->action->getRequest()->expects($this->any())->method('getParam')->willReturn($value); + $this->regexValidatorMock->expects($this->any()) + ->method('isValid') + ->with($value) + ->willReturn(true); + + $this->assertEquals(true, $this->regexValidator->validateParamRegex($value)); + } + + /** + * @return void + */ + public function testExecuteWithError(): void + { + $value = 'simple\' and true()]|*[self%3a%3ahandle%20or%20self%3a%3alayout'; + + $this->action->getRequest()->expects($this->any()) + ->method('getParam') + ->willReturn($value); + $this->resultForwardFactory->expects($this->any()) + ->method('create') + ->willReturn($this->resultForward); + $this->resultForward->expects($this->once()) + ->method('forward') + ->with('noroute') + ->willReturn(true); + $this->assertTrue($this->action->execute()); } } diff --git a/app/code/Magento/Catalog/Test/Unit/Pricing/Render/FinalPriceBoxTest.php b/app/code/Magento/Catalog/Test/Unit/Pricing/Render/FinalPriceBoxTest.php index f3831e50ef3d..a97c75d32da1 100644 --- a/app/code/Magento/Catalog/Test/Unit/Pricing/Render/FinalPriceBoxTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Pricing/Render/FinalPriceBoxTest.php @@ -15,8 +15,11 @@ use Magento\Catalog\Pricing\Render\FinalPriceBox; use Magento\Framework\App\Cache\StateInterface; use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Framework\App\DeploymentConfig; use Magento\Framework\App\State; +use Magento\Framework\Config\ConfigOptionsListConstants; use Magento\Framework\Event\Test\Unit\ManagerStub; +use Magento\Framework\ObjectManagerInterface; use Magento\Framework\Pricing\Amount\AmountInterface; use Magento\Framework\Pricing\Price\PriceInterface; use Magento\Framework\Pricing\PriceInfoInterface; @@ -96,11 +99,27 @@ class FinalPriceBoxTest extends TestCase */ private $minimalPriceCalculator; + /** + * @var DeploymentConfig|MockObject + */ + private $deploymentConfig; + + /** + * @var ObjectManagerInterface|MockObject + */ + private $objectManagerMock; + /** * @inheritDoc + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ protected function setUp(): void { + $this->objectManagerMock = $this->getMockBuilder(ObjectManagerInterface::class) + ->disableOriginalConstructor() + ->onlyMethods(['get']) + ->getMockForAbstractClass(); + \Magento\Framework\App\ObjectManager::setInstance($this->objectManagerMock); $this->product = $this->getMockBuilder(Product::class) ->addMethods(['getCanShowPrice']) ->onlyMethods(['getPriceInfo', 'isSalable', 'getId']) @@ -183,6 +202,11 @@ protected function setUp(): void ->disableOriginalConstructor() ->getMockForAbstractClass(); + $this->deploymentConfig = $this->createPartialMock( + DeploymentConfig::class, + ['get'] + ); + $this->minimalPriceCalculator = $this->getMockForAbstractClass(MinimalPriceCalculatorInterface::class); $this->object = $objectManager->getObject( FinalPriceBox::class, @@ -455,6 +479,15 @@ public function testHidePrice(): void */ public function testGetCacheKey(): void { + $this->objectManagerMock->expects($this->any()) + ->method('get') + ->with(DeploymentConfig::class) + ->willReturn($this->deploymentConfig); + + $this->deploymentConfig->expects($this->any()) + ->method('get') + ->with(ConfigOptionsListConstants::CONFIG_PATH_CRYPT_KEY) + ->willReturn('448198e08af35844a42d3c93c1ef4e03'); $result = $this->object->getCacheKey(); $this->assertStringEndsWith('list-category-page', $result); } diff --git a/app/code/Magento/Catalog/composer.json b/app/code/Magento/Catalog/composer.json index 6597e88e9d99..bd56668a1a1d 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": "104.0.4-p10", "require": { "php": "~7.4.0||~8.1.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": "103.0.*", + "magento/module-authorization": "100.4.*", + "magento/module-asynchronous-operations": "100.4.*", + "magento/module-backend": "102.0.*", + "magento/module-catalog-inventory": "100.4.*", + "magento/module-catalog-rule": "101.2.*", + "magento/module-catalog-url-rewrite": "100.4.*", + "magento/module-checkout": "100.4.*", + "magento/module-cms": "104.0.*", + "magento/module-config": "101.2.*", + "magento/module-customer": "103.0.*", + "magento/module-directory": "100.4.*", + "magento/module-eav": "102.1.*", + "magento/module-indexer": "100.4.*", + "magento/module-media-storage": "100.4.*", + "magento/module-msrp": "100.4.*", + "magento/module-page-cache": "100.4.*", + "magento/module-product-alert": "100.4.*", + "magento/module-quote": "101.2.*", + "magento/module-store": "101.1.*", + "magento/module-tax": "100.4.*", + "magento/module-theme": "101.1.*", + "magento/module-ui": "101.2.*", + "magento/module-url-rewrite": "102.0.*", + "magento/module-widget": "101.2.*", + "magento/module-wishlist": "101.2.*" }, "suggest": { - "magento/module-cookie": "*", - "magento/module-sales": "*", - "magento/module-catalog-sample-data": "*" + "magento/module-cookie": "100.4.*", + "magento/module-sales": "103.0.*", + "magento/module-catalog-sample-data": "Sample Data version: 100.4.*" }, - "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/i18n/en_US.csv b/app/code/Magento/Catalog/i18n/en_US.csv index d5ba3b75493e..34d31f1c9a6f 100644 --- a/app/code/Magento/Catalog/i18n/en_US.csv +++ b/app/code/Magento/Catalog/i18n/en_US.csv @@ -816,4 +816,6 @@ Details,Details "Are you sure you want to delete this category?","Are you sure you want to delete this category?" "Attribute Set Information","Attribute Set Information" "Failed to retrieve product links for ""%1""","Failed to retrieve product links for ""%1""" +"The url has invalid characters. Please correct and try again.","The url has invalid characters. Please correct and try again." + diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/category-tree.js b/app/code/Magento/Catalog/view/adminhtml/web/js/category-tree.js index d292bd126593..b4d4ed12d20b 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/category-tree.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/category-tree.js @@ -5,10 +5,9 @@ define([ 'jquery', - 'mageUtils', 'jquery/ui', 'jquery/jstree/jquery.jstree' -], function ($, utils) { +], function ($) { 'use strict'; $.widget('mage.categoryTree', { @@ -87,7 +86,7 @@ define([ // jscs:disable requireCamelCaseOrUpperCaseIdentifiers result = { id: node.id, - text: utils.unescape(node.name) + ' (' + node.product_count + ')', + text: node.name + ' (' + node.product_count + ')', li_attr: { class: node.cls + (!!node.disabled ? ' disabled' : '') //eslint-disable-line no-extra-boolean-cast }, diff --git a/app/code/Magento/CatalogAnalytics/composer.json b/app/code/Magento/CatalogAnalytics/composer.json index a41a47fa4764..2fb9f4fb021c 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.4.0||~8.1.0", - "magento/framework": "*", - "magento/module-catalog": "*", - "magento/module-analytics": "*" - }, "type": "magento2-module", "license": [ "OSL-3.0", "AFL-3.0" ], + "version": "100.4.2", + "require": { + "php": "~7.4.0||~8.1.0", + "magento/framework": "103.0.*", + "magento/module-catalog": "104.0.*", + "magento/module-analytics": "100.4.*" + }, "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 cf9e76f3b2ea..b32b4635745c 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.4.1", "require": { "php": "~7.4.0||~8.1.0", - "magento/framework": "*", - "magento/module-catalog": "*", - "magento/module-cms-graph-ql": "*" + "magento/framework": "103.0.*", + "magento/module-catalog": "104.0.*", + "magento/module-cms-graph-ql": "100.4.*" }, "suggest": { - "magento/module-graph-ql": "*", - "magento/module-cms": "*", - "magento/module-catalog-graph-ql": "*" + "magento/module-graph-ql": "100.4.*", + "magento/module-cms": "104.0.*", + "magento/module-catalog-graph-ql": "100.4.*" }, - "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 b1743ae96496..c7062a2d03e6 100644 --- a/app/code/Magento/CatalogCustomerGraphQl/composer.json +++ b/app/code/Magento/CatalogCustomerGraphQl/composer.json @@ -2,17 +2,18 @@ "name": "magento/module-catalog-customer-graph-ql", "description": "N/A", "type": "magento2-module", - "require": { - "php": "~7.4.0||~8.1.0", - "magento/framework": "*", - "magento/module-catalog": "*", - "magento/module-customer": "*", - "magento/module-catalog-graph-ql": "*" - }, "license": [ "OSL-3.0", "AFL-3.0" ], + "version": "100.4.4", + "require": { + "php": "~7.4.0||~8.1.0", + "magento/framework": "103.0.*", + "magento/module-catalog": "104.0.*", + "magento/module-customer": "103.0.*", + "magento/module-catalog-graph-ql": "100.4.*" + }, "autoload": { "files": [ "registration.php" @@ -22,3 +23,4 @@ } } } + diff --git a/app/code/Magento/CatalogGraphQl/composer.json b/app/code/Magento/CatalogGraphQl/composer.json index c289f84a359b..bd3626743f4d 100644 --- a/app/code/Magento/CatalogGraphQl/composer.json +++ b/app/code/Magento/CatalogGraphQl/composer.json @@ -2,28 +2,29 @@ "name": "magento/module-catalog-graph-ql", "description": "N/A", "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "version": "100.4.4", "require": { "php": "~7.4.0||~8.1.0", - "magento/module-eav": "*", - "magento/module-catalog": "*", - "magento/module-catalog-inventory": "*", - "magento/module-directory": "*", - "magento/module-search": "*", - "magento/module-store": "*", - "magento/module-eav-graph-ql": "*", - "magento/module-catalog-search": "*", - "magento/framework": "*", - "magento/module-graph-ql": "*", - "magento/module-advanced-search": "*" + "magento/module-eav": "102.1.*", + "magento/module-catalog": "104.0.*", + "magento/module-catalog-inventory": "100.4.*", + "magento/module-directory": "100.4.*", + "magento/module-search": "101.1.*", + "magento/module-store": "101.1.*", + "magento/module-eav-graph-ql": "100.4.*", + "magento/module-catalog-search": "102.0.*", + "magento/framework": "103.0.*", + "magento/module-graph-ql": "100.4.*", + "magento/module-advanced-search": "100.4.*" }, "suggest": { - "magento/module-graph-ql-cache": "*", - "magento/module-store-graph-ql": "*" + "magento/module-graph-ql-cache": "100.4.*", + "magento/module-store-graph-ql": "100.4.*" }, - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -33,3 +34,4 @@ } } } + diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product.php b/app/code/Magento/CatalogImportExport/Model/Import/Product.php index 25dc5360c8df..3ad96737bf32 100644 --- a/app/code/Magento/CatalogImportExport/Model/Import/Product.php +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product.php @@ -47,6 +47,7 @@ */ class Product extends AbstractEntity { + private const COL_NAME_FORMAT = '/[\x00-\x1F\x7F]/'; private const DEFAULT_GLOBAL_MULTIPLE_VALUE_SEPARATOR = ','; public const CONFIG_KEY_PRODUCT_TYPES = 'global/importexport/import_product_types'; private const HASH_ALGORITHM = 'sha256'; @@ -1611,6 +1612,11 @@ protected function _saveProducts() $bunch[$rowNum][self::URL_KEY] = $rowData[self::URL_KEY] = $urlKey; } + if (!empty($rowData[self::COL_NAME])) { + // remove null byte character + $rowData[self::COL_NAME] = preg_replace(self::COL_NAME_FORMAT, '', $rowData[self::COL_NAME]); + } + $rowSku = $rowData[self::COL_SKU]; $rowSkuNormalized = mb_strtolower($rowSku); diff --git a/app/code/Magento/CatalogImportExport/composer.json b/app/code/Magento/CatalogImportExport/composer.json index dac8624086df..817c7e65cb94 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.1.4-p4", "require": { "php": "~7.4.0||~8.1.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": "103.0.*", + "magento/module-catalog": "104.0.*", + "magento/module-catalog-inventory": "100.4.*", + "magento/module-catalog-url-rewrite": "100.4.*", + "magento/module-customer": "103.0.*", + "magento/module-eav": "102.1.*", + "magento/module-import-export": "101.0.*", + "magento/module-media-storage": "100.4.*", + "magento/module-store": "101.1.*", + "magento/module-tax": "100.4.*", + "magento/module-authorization": "100.4.*" }, - "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/composer.json b/app/code/Magento/CatalogInventory/composer.json index 4b7fee72c434..18c51001c091 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.4.4", "require": { "php": "~7.4.0||~8.1.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": "103.0.*", + "magento/module-catalog": "104.0.*", + "magento/module-config": "101.2.*", + "magento/module-customer": "103.0.*", + "magento/module-eav": "102.1.*", + "magento/module-quote": "101.2.*", + "magento/module-store": "101.1.*", + "magento/module-ui": "101.2.*" }, - "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 38685524d534..92f6224abc5a 100644 --- a/app/code/Magento/CatalogInventoryGraphQl/composer.json +++ b/app/code/Magento/CatalogInventoryGraphQl/composer.json @@ -2,18 +2,19 @@ "name": "magento/module-catalog-inventory-graph-ql", "description": "N/A", "type": "magento2-module", - "require": { - "php": "~7.4.0||~8.1.0", - "magento/framework": "*", - "magento/module-store": "*", - "magento/module-catalog": "*", - "magento/module-catalog-inventory": "*", - "magento/module-graph-ql": "*" - }, "license": [ "OSL-3.0", "AFL-3.0" ], + "version": "100.4.1", + "require": { + "php": "~7.4.0||~8.1.0", + "magento/framework": "103.0.*", + "magento/module-store": "101.1.*", + "magento/module-catalog": "104.0.*", + "magento/module-catalog-inventory": "100.4.*", + "magento/module-graph-ql": "100.4.*" + }, "autoload": { "files": [ "registration.php" @@ -23,3 +24,4 @@ } } } + diff --git a/app/code/Magento/CatalogRule/composer.json b/app/code/Magento/CatalogRule/composer.json index 531a12ac017e..43a970bc52a6 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.2.4", "require": { "php": "~7.4.0||~8.1.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": "103.0.*", + "magento/module-backend": "102.0.*", + "magento/module-catalog": "104.0.*", + "magento/module-customer": "103.0.*", + "magento/module-eav": "102.1.*", + "magento/module-rule": "100.4.*", + "magento/module-store": "101.1.*", + "magento/module-ui": "101.2.*" }, "suggest": { - "magento/module-import-export": "*", - "magento/module-catalog-rule-sample-data": "*" + "magento/module-import-export": "101.0.*", + "magento/module-catalog-rule-sample-data": "Sample Data version: 100.4.*" }, - "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 68da972ae94f..46a0b604835a 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.4.3", "require": { "php": "~7.4.0||~8.1.0", - "magento/framework": "*", + "magento/framework": "103.0.*", "magento/magento-composer-installer": "*", - "magento/module-catalog": "*", - "magento/module-catalog-rule": "*", - "magento/module-configurable-product": "*" + "magento/module-catalog": "104.0.*", + "magento/module-catalog-rule": "101.2.*", + "magento/module-configurable-product": "100.4.*" }, "suggest": { - "magento/module-catalog-rule": "*" + "magento/module-catalog-rule": "101.2.*" }, - "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 2c8c3ef20c96..6bd7ef191d89 100644 --- a/app/code/Magento/CatalogRuleGraphQl/composer.json +++ b/app/code/Magento/CatalogRuleGraphQl/composer.json @@ -2,17 +2,18 @@ "name": "magento/module-catalog-rule-graph-ql", "description": "N/A", "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "version": "100.4.2", "require": { "php": "~7.4.0||~8.1.0", - "magento/framework": "*" + "magento/framework": "103.0.*" }, "suggest": { - "magento/module-catalog-rule": "*" + "magento/module-catalog-rule": "101.2.*" }, - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -22,3 +23,4 @@ } } } + diff --git a/app/code/Magento/CatalogSearch/composer.json b/app/code/Magento/CatalogSearch/composer.json index 465d7daeebe1..a3a5246e1992 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": "102.0.4", "require": { "php": "~7.4.0||~8.1.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": "103.0.*", + "magento/module-backend": "102.0.*", + "magento/module-catalog": "104.0.*", + "magento/module-indexer": "100.4.*", + "magento/module-catalog-inventory": "100.4.*", + "magento/module-customer": "103.0.*", + "magento/module-directory": "100.4.*", + "magento/module-eav": "102.1.*", + "magento/module-search": "101.1.*", + "magento/module-store": "101.1.*", + "magento/module-theme": "101.1.*", + "magento/module-ui": "101.2.*" }, "suggest": { - "magento/module-config": "*" + "magento/module-config": "101.2.*" }, - "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 ce409e2186fa..490ad57b35a6 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.4.4", "require": { "php": "~7.4.0||~8.1.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": "103.0.*", + "magento/module-backend": "102.0.*", + "magento/module-catalog": "104.0.*", + "magento/module-catalog-import-export": "101.1.*", + "magento/module-eav": "102.1.*", + "magento/module-import-export": "101.0.*", + "magento/module-store": "101.1.*", + "magento/module-ui": "101.2.*", + "magento/module-url-rewrite": "102.0.*" }, "suggest": { - "magento/module-webapi": "*" + "magento/module-webapi": "100.4.*" }, - "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 025234af6f86..d79c2ab17f61 100644 --- a/app/code/Magento/CatalogUrlRewriteGraphQl/composer.json +++ b/app/code/Magento/CatalogUrlRewriteGraphQl/composer.json @@ -2,23 +2,24 @@ "name": "magento/module-catalog-url-rewrite-graph-ql", "description": "N/A", "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "version": "100.4.3", "require": { "php": "~7.4.0||~8.1.0", - "magento/module-store": "*", - "magento/module-catalog": "*", - "magento/module-catalog-graph-ql": "*", - "magento/module-url-rewrite-graph-ql": "*", - "magento/framework": "*" + "magento/module-store": "101.1.*", + "magento/module-catalog": "104.0.*", + "magento/module-catalog-graph-ql": "100.4.*", + "magento/module-url-rewrite-graph-ql": "100.4.*", + "magento/framework": "103.0.*" }, "suggest": { - "magento/module-catalog-url-rewrite": "*", - "magento/module-catalog-graph-ql": "*", - "magento/module-url-rewrite-graph-ql": "*" + "magento/module-catalog-url-rewrite": "100.4.*", + "magento/module-catalog-graph-ql": "100.4.*", + "magento/module-url-rewrite-graph-ql": "100.4.*" }, - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -28,3 +29,4 @@ } } } + diff --git a/app/code/Magento/CatalogWidget/Test/Mftf/Test/StorefrontProductGridUIUpdatesOnDesktopTest.xml b/app/code/Magento/CatalogWidget/Test/Mftf/Test/StorefrontProductGridUIUpdatesOnDesktopTest.xml index 5590aa1cdcef..e833c8e72f47 100644 --- a/app/code/Magento/CatalogWidget/Test/Mftf/Test/StorefrontProductGridUIUpdatesOnDesktopTest.xml +++ b/app/code/Magento/CatalogWidget/Test/Mftf/Test/StorefrontProductGridUIUpdatesOnDesktopTest.xml @@ -61,6 +61,7 @@ + diff --git a/app/code/Magento/CatalogWidget/composer.json b/app/code/Magento/CatalogWidget/composer.json index 33c5e3b3ba3e..bb74be273a5e 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.4.4-p2", "require": { "php": "~7.4.0||~8.1.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": "103.0.*", + "magento/module-backend": "102.0.*", + "magento/module-catalog": "104.0.*", + "magento/module-customer": "103.0.*", + "magento/module-eav": "102.1.*", + "magento/module-rule": "100.4.*", + "magento/module-store": "101.1.*", + "magento/module-widget": "101.2.*", + "magento/module-wishlist": "101.2.*", + "magento/module-theme": "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/Checkout/Controller/Sidebar/UpdateItemQty.php b/app/code/Magento/Checkout/Controller/Sidebar/UpdateItemQty.php index 44e40c57f661..abaecf51b076 100644 --- a/app/code/Magento/Checkout/Controller/Sidebar/UpdateItemQty.php +++ b/app/code/Magento/Checkout/Controller/Sidebar/UpdateItemQty.php @@ -3,19 +3,25 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); + namespace Magento\Checkout\Controller\Sidebar; use Magento\Checkout\Model\Cart\RequestQuantityProcessor; use Magento\Checkout\Model\Sidebar; use Magento\Framework\App\Action\Action; use Magento\Framework\App\Action\Context; +use Magento\Framework\App\Action\HttpPostActionInterface; use Magento\Framework\App\ObjectManager; use Magento\Framework\App\Response\Http; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Json\Helper\Data; use Psr\Log\LoggerInterface; -class UpdateItemQty extends Action +/** + * Class used to update item quantity. + */ +class UpdateItemQty extends Action implements HttpPostActionInterface { /** * @var Sidebar @@ -61,12 +67,18 @@ public function __construct( } /** + * Action for Quantity update + * * @return $this */ public function execute() { $itemId = (int)$this->getRequest()->getParam('item_id'); - $itemQty = $this->getRequest()->getParam('item_qty') * 1; + $itemQty = (int)$this->getRequest()->getParam('item_qty'); + + if ($itemQty <= 0) { + return $this->jsonResponse(__('Invalid Item Quantity Requested.')); + } $itemQty = $this->quantityProcessor->prepareQuantity($itemQty); try { diff --git a/app/code/Magento/Checkout/Model/DefaultConfigProvider.php b/app/code/Magento/Checkout/Model/DefaultConfigProvider.php index 9e31c4d77301..dd4080bcc39d 100644 --- a/app/code/Magento/Checkout/Model/DefaultConfigProvider.php +++ b/app/code/Magento/Checkout/Model/DefaultConfigProvider.php @@ -31,6 +31,7 @@ use Magento\Quote\Model\QuoteIdMaskFactory; use Magento\Store\Model\ScopeInterface; use Magento\Ui\Component\Form\Element\Multiline; +use Magento\Framework\Escaper; /** * Default Config Provider for checkout @@ -191,6 +192,11 @@ class DefaultConfigProvider implements ConfigProviderInterface */ private $configPostProcessor; + /** + * @var Escaper + */ + private $escaper; + /** * @param CheckoutHelper $checkoutHelper * @param Session $checkoutSession @@ -222,6 +228,7 @@ class DefaultConfigProvider implements ConfigProviderInterface * @param AddressMetadataInterface $addressMetadata * @param AttributeOptionManagementInterface $attributeOptionManager * @param CustomerAddressDataProvider|null $customerAddressData + * @param Escaper|null $escaper * @codeCoverageIgnore * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ @@ -255,7 +262,8 @@ public function __construct( CaptchaConfigPostProcessorInterface $configPostProcessor, AddressMetadataInterface $addressMetadata = null, AttributeOptionManagementInterface $attributeOptionManager = null, - CustomerAddressDataProvider $customerAddressData = null + CustomerAddressDataProvider $customerAddressData = null, + Escaper $escaper = null ) { $this->checkoutHelper = $checkoutHelper; $this->checkoutSession = $checkoutSession; @@ -289,6 +297,7 @@ public function __construct( $this->customerAddressData = $customerAddressData ?: ObjectManager::getInstance()->get(CustomerAddressDataProvider::class); $this->configPostProcessor = $configPostProcessor; + $this->escaper = $escaper ?? ObjectManager::getInstance()->get(Escaper::class); } /** @@ -343,6 +352,7 @@ public function getConfig() 'shipping/shipping_policy/shipping_policy_content', ScopeInterface::SCOPE_STORE ); + $policyContent = $this->escaper->escapeHtml($policyContent); $output['shippingPolicy'] = [ 'isEnabled' => $this->scopeConfig->isSetFlag( 'shipping/shipping_policy/enable_shipping_policy', diff --git a/app/code/Magento/Checkout/Model/ShippingInformationManagement.php b/app/code/Magento/Checkout/Model/ShippingInformationManagement.php index f397a8ddc9cf..f08c48c55efa 100644 --- a/app/code/Magento/Checkout/Model/ShippingInformationManagement.php +++ b/app/code/Magento/Checkout/Model/ShippingInformationManagement.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ +declare(strict_types=1); namespace Magento\Checkout\Model; @@ -39,60 +40,62 @@ class ShippingInformationManagement implements ShippingInformationManagementInte /** * @var PaymentMethodManagementInterface */ - protected $paymentMethodManagement; + protected PaymentMethodManagementInterface $paymentMethodManagement; /** * @var PaymentDetailsFactory */ - protected $paymentDetailsFactory; + protected PaymentDetailsFactory $paymentDetailsFactory; /** * @var CartTotalRepositoryInterface */ - protected $cartTotalsRepository; + protected CartTotalRepositoryInterface $cartTotalsRepository; /** * @var CartRepositoryInterface */ - protected $quoteRepository; - + protected CartRepositoryInterface $quoteRepository; /** * @var Logger */ - protected $logger; + protected Logger $logger; /** * @var QuoteAddressValidator */ - protected $addressValidator; + protected QuoteAddressValidator $addressValidator; /** * @var AddressRepositoryInterface * @deprecated 100.2.0 + * @see AddressRepositoryInterface */ - protected $addressRepository; + protected AddressRepositoryInterface $addressRepository; /** * @var ScopeConfigInterface * @deprecated 100.2.0 + * @see ScopeConfigInterface */ - protected $scopeConfig; + protected ScopeConfigInterface $scopeConfig; /** * @var TotalsCollector * @deprecated 100.2.0 + * @see TotalsCollector */ - protected $totalsCollector; + protected TotalsCollector $totalsCollector; /** * @var CartExtensionFactory */ - private $cartExtensionFactory; + private CartExtensionFactory $cartExtensionFactory; /** * @var ShippingAssignmentFactory */ - protected $shippingAssignmentFactory; + protected ShippingAssignmentFactory $shippingAssignmentFactory; /** * @var ShippingFactory @@ -262,8 +265,11 @@ protected function validateQuote(Quote $quote): void * @param string $method * @return CartInterface */ - private function prepareShippingAssignment(CartInterface $quote, AddressInterface $address, $method): CartInterface - { + private function prepareShippingAssignment( + CartInterface $quote, + AddressInterface $address, + string $method + ): CartInterface { $cartExtension = $quote->getExtensionAttributes(); if ($cartExtension === null) { $cartExtension = $this->cartExtensionFactory->create(); diff --git a/app/code/Magento/Checkout/Observer/CspPolicyObserver.php b/app/code/Magento/Checkout/Observer/CspPolicyObserver.php new file mode 100644 index 000000000000..10c6e7aefac1 --- /dev/null +++ b/app/code/Magento/Checkout/Observer/CspPolicyObserver.php @@ -0,0 +1,69 @@ +inlineTranslate = $inlineTranslate; + $this->dynamicCollector = $dynamicCollector; + } + + /** + * Override CSP policy for checkout page wit inline translation + * + * @param Observer $observer + * @return void + * + * @throws \Exception + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function execute(Observer $observer): void + { + if ($this->inlineTranslate->isAllowed()) { + $policy = new FetchPolicy( + 'script-src', + false, + [], + [], + true, + true, + false, + [], + [] + ); + + $this->dynamicCollector->add($policy); + } + } +} diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/AssertMiniCartEmptyActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/AssertMiniCartEmptyActionGroup.xml index 649421a53040..2119e5c43f7b 100644 --- a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/AssertMiniCartEmptyActionGroup.xml +++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/AssertMiniCartEmptyActionGroup.xml @@ -13,8 +13,9 @@ Validates that the provided Product Count appears in the Storefront Header next to the Shopping Cart icon. Clicks on the Mini Shopping Cart icon. Validates that the 'No Items' message is present and correct in the Storefront Mini Shopping Cart. + - + diff --git a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutPlaceOrderActionGroup.xml b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutPlaceOrderActionGroup.xml index 48c515a3dd19..4269e647cf7f 100644 --- a/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutPlaceOrderActionGroup.xml +++ b/app/code/Magento/Checkout/Test/Mftf/ActionGroup/CheckoutPlaceOrderActionGroup.xml @@ -17,8 +17,12 @@ + + + + diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/OnePageCheckoutAsCustomerUsingDefaultAddressTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/OnePageCheckoutAsCustomerUsingDefaultAddressTest.xml index 64f392d39edc..f770e7f42cae 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/OnePageCheckoutAsCustomerUsingDefaultAddressTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/OnePageCheckoutAsCustomerUsingDefaultAddressTest.xml @@ -20,11 +20,11 @@ + 560 - @@ -40,6 +40,7 @@ + diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/OnePageCheckoutAsCustomerUsingNonDefaultAddressTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/OnePageCheckoutAsCustomerUsingNonDefaultAddressTest.xml index b60b60d5d0dc..a235da133af7 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/OnePageCheckoutAsCustomerUsingNonDefaultAddressTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/OnePageCheckoutAsCustomerUsingNonDefaultAddressTest.xml @@ -20,6 +20,7 @@ + 560 @@ -40,6 +41,7 @@ + diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCheckoutWithSpecialPriceProductsTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCheckoutWithSpecialPriceProductsTest.xml index 1a85bb0bee1e..07d1378d0052 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCheckoutWithSpecialPriceProductsTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCheckoutWithSpecialPriceProductsTest.xml @@ -18,6 +18,7 @@ + @@ -105,6 +106,7 @@ + diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerLoginDuringCheckoutTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerLoginDuringCheckoutTest.xml index eb76748a81c9..ec4593cf133b 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerLoginDuringCheckoutTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontCustomerLoginDuringCheckoutTest.xml @@ -19,6 +19,7 @@ + @@ -39,9 +40,9 @@ - + diff --git a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontVerifySecureURLRedirectCheckoutTest.xml b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontVerifySecureURLRedirectCheckoutTest.xml index 901c5c3598db..af5af1d2a096 100644 --- a/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontVerifySecureURLRedirectCheckoutTest.xml +++ b/app/code/Magento/Checkout/Test/Mftf/Test/StorefrontVerifySecureURLRedirectCheckoutTest.xml @@ -45,8 +45,10 @@ - + + + diff --git a/app/code/Magento/Checkout/Test/Unit/Controller/Sidebar/UpdateItemQtyTest.php b/app/code/Magento/Checkout/Test/Unit/Controller/Sidebar/UpdateItemQtyTest.php index 400f6ddfe26f..959cebea1747 100644 --- a/app/code/Magento/Checkout/Test/Unit/Controller/Sidebar/UpdateItemQtyTest.php +++ b/app/code/Magento/Checkout/Test/Unit/Controller/Sidebar/UpdateItemQtyTest.php @@ -19,6 +19,9 @@ use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; +/** + * Class used to execute test cases for update item quantity + */ class UpdateItemQtyTest extends TestCase { /** @@ -244,4 +247,36 @@ public function testExecuteWithException(): void $this->assertEquals('json represented', $this->updateItemQty->execute()); } + + /** + * @return void + */ + public function testExecuteWithInvalidItemQty(): void + { + $error = [ + 'success' => false, + 'error_message' => 'Invalid Item Quantity Requested.' + ]; + $jsonResult = json_encode($error); + $this->requestMock + ->method('getParam') + ->withConsecutive(['item_id', null], ['item_qty', null]) + ->willReturnOnConsecutiveCalls('1', '{{7+2}}'); + + $this->sidebarMock->expects($this->once()) + ->method('getResponseData') + ->with('Invalid Item Quantity Requested.') + ->willReturn($error); + + $this->jsonHelperMock->expects($this->once()) + ->method('jsonEncode') + ->with($error) + ->willReturn($jsonResult); + + $this->responseMock->expects($this->once()) + ->method('representJson') + ->willReturn($jsonResult); + + $this->assertEquals($jsonResult, $this->updateItemQty->execute()); + } } diff --git a/app/code/Magento/Checkout/composer.json b/app/code/Magento/Checkout/composer.json index f277184d8986..926f3e55b2c0 100644 --- a/app/code/Magento/Checkout/composer.json +++ b/app/code/Magento/Checkout/composer.json @@ -1,41 +1,43 @@ { "name": "magento/module-checkout", "description": "N/A", + "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], "config": { "sort-packages": true }, + "version": "100.4.4-p9", "require": { "php": "~7.4.0||~8.1.0", - "magento/framework": "*", - "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/module-authorization": "*" + "magento/framework": "103.0.*", + "magento/module-captcha": "100.4.*", + "magento/module-catalog": "104.0.*", + "magento/module-catalog-inventory": "100.4.*", + "magento/module-config": "101.2.*", + "magento/module-customer": "103.0.*", + "magento/module-directory": "100.4.*", + "magento/module-eav": "102.1.*", + "magento/module-msrp": "100.4.*", + "magento/module-page-cache": "100.4.*", + "magento/module-payment": "100.4.*", + "magento/module-quote": "101.2.*", + "magento/module-sales": "103.0.*", + "magento/module-sales-rule": "101.2.*", + "magento/module-security": "100.4.*", + "magento/module-shipping": "100.4.*", + "magento/module-store": "101.1.*", + "magento/module-tax": "100.4.*", + "magento/module-theme": "101.1.*", + "magento/module-ui": "101.2.*", + "magento/module-authorization": "100.4.*", + "magento/module-csp": "100.4.*" }, "suggest": { - "magento/module-cookie": "*" + "magento/module-cookie": "100.4.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -45,3 +47,4 @@ } } } + diff --git a/app/code/Magento/Checkout/etc/adminhtml/system.xml b/app/code/Magento/Checkout/etc/adminhtml/system.xml index b56566a043c3..944914b34e1e 100644 --- a/app/code/Magento/Checkout/etc/adminhtml/system.xml +++ b/app/code/Magento/Checkout/etc/adminhtml/system.xml @@ -13,6 +13,11 @@ Magento_Checkout::checkout + + + Magento\Config\Model\Config\Source\Yesno + Enabling this setting will allow unauthenticated users to query if an e-mail address is already associated with a customer account. This can be used to enhance the checkout workflow for guests that do not realize they already have an account but comes at the cost of exposing information to unauthenticated users. + Magento\Config\Model\Config\Source\Yesno @@ -23,7 +28,7 @@ - \Magento\Checkout\Model\Adminhtml\BillingAddressDisplayOptions + Magento\Checkout\Model\Adminhtml\BillingAddressDisplayOptions @@ -101,5 +106,17 @@ +
+ + + + + + If empty, Default Report URI for storefront will be used. + validate-url + + + +
diff --git a/app/code/Magento/Checkout/etc/config.xml b/app/code/Magento/Checkout/etc/config.xml index eac0bd849da3..ef4afdf8d4b2 100644 --- a/app/code/Magento/Checkout/etc/config.xml +++ b/app/code/Magento/Checkout/etc/config.xml @@ -9,6 +9,7 @@ + 0 1 1 0 @@ -55,5 +56,20 @@ + + + + 0 + + + + + + 0 + 1 + + + + diff --git a/app/code/Magento/Checkout/etc/frontend/events.xml b/app/code/Magento/Checkout/etc/frontend/events.xml index 901b652201db..90e2236ee9d6 100644 --- a/app/code/Magento/Checkout/etc/frontend/events.xml +++ b/app/code/Magento/Checkout/etc/frontend/events.xml @@ -12,4 +12,8 @@ + + + diff --git a/app/code/Magento/Checkout/i18n/en_US.csv b/app/code/Magento/Checkout/i18n/en_US.csv index ca118f21f244..de0c4717e417 100644 --- a/app/code/Magento/Checkout/i18n/en_US.csv +++ b/app/code/Magento/Checkout/i18n/en_US.csv @@ -186,3 +186,4 @@ Payment,Payment "Show Cross-sell Items in the Shopping Cart","Show Cross-sell Items in the Shopping Cart" "You added %1 to your shopping cart.","You added %1 to your shopping cart." "The shipping method is missing. Select the shipping method and try again.","The shipping method is missing. Select the shipping method and try again." +"Invalid Item Quantity Requested.","Invalid Item Quantity Requested." diff --git a/app/code/Magento/CheckoutAgreements/Test/Mftf/ActionGroup/AdminDeleteAllTermConditionsActionGroup.xml b/app/code/Magento/CheckoutAgreements/Test/Mftf/ActionGroup/AdminDeleteAllTermConditionsActionGroup.xml new file mode 100644 index 000000000000..fec0a686d839 --- /dev/null +++ b/app/code/Magento/CheckoutAgreements/Test/Mftf/ActionGroup/AdminDeleteAllTermConditionsActionGroup.xml @@ -0,0 +1,27 @@ + + + + + + Deletes all rows one by one on the 'Terms and Conditions' page. + + + + + + {{AdminTermGridSection.allTermRows}} + {{AdminMainActionsSection.delete}} + {{AdminConfirmationModalSection.ok}} + You deleted the condition. + {{AdminMessagesSection.success}} + + + + + diff --git a/app/code/Magento/CheckoutAgreements/Test/Mftf/Helper/CheckoutAgreementsHelpers.php b/app/code/Magento/CheckoutAgreements/Test/Mftf/Helper/CheckoutAgreementsHelpers.php new file mode 100644 index 000000000000..7f0150b274f4 --- /dev/null +++ b/app/code/Magento/CheckoutAgreements/Test/Mftf/Helper/CheckoutAgreementsHelpers.php @@ -0,0 +1,61 @@ +getModule("\\" . MagentoWebDriver::class); + $webDriver = $magentoWebDriver->webDriver; + + $magentoWebDriver->waitForPageLoad(30); + $rows = $webDriver->findElements(WebDriverBy::xpath($rowsToDelete)); + while (!empty($rows)) { + $rows[0]->click(); + $magentoWebDriver->waitForPageLoad(30); + $magentoWebDriver->waitForElementVisible($deleteButton, 10); + $magentoWebDriver->click($deleteButton); + $magentoWebDriver->waitForPageLoad(30); + $magentoWebDriver->waitForElementVisible($modalAcceptButton, 10); + $magentoWebDriver->click($modalAcceptButton); + $magentoWebDriver->waitForPageLoad(60); + $magentoWebDriver->waitForText($successMessage, 10, $successMessageContainer); + $rows = $webDriver->findElements(WebDriverBy::xpath($rowsToDelete)); + } + } catch (Exception $exception) { + $this->fail($exception->getMessage()); + } + } +} diff --git a/app/code/Magento/CheckoutAgreements/Test/Mftf/Section/AdminTermGridSection.xml b/app/code/Magento/CheckoutAgreements/Test/Mftf/Section/AdminTermGridSection.xml index 326f9dcce432..ab198fbfb4ec 100644 --- a/app/code/Magento/CheckoutAgreements/Test/Mftf/Section/AdminTermGridSection.xml +++ b/app/code/Magento/CheckoutAgreements/Test/Mftf/Section/AdminTermGridSection.xml @@ -14,5 +14,7 @@ + + diff --git a/app/code/Magento/CheckoutAgreements/Test/Mftf/Test/AdminCreateActiveHtmlTermEntityTest.xml b/app/code/Magento/CheckoutAgreements/Test/Mftf/Test/AdminCreateActiveHtmlTermEntityTest.xml index c597d3d660dc..4c1a25811564 100644 --- a/app/code/Magento/CheckoutAgreements/Test/Mftf/Test/AdminCreateActiveHtmlTermEntityTest.xml +++ b/app/code/Magento/CheckoutAgreements/Test/Mftf/Test/AdminCreateActiveHtmlTermEntityTest.xml @@ -32,10 +32,9 @@ - - - - + + + diff --git a/app/code/Magento/CheckoutAgreements/Test/Mftf/Test/AdminCreateActiveTextTermEntityTest.xml b/app/code/Magento/CheckoutAgreements/Test/Mftf/Test/AdminCreateActiveTextTermEntityTest.xml index a90c3536ec74..f0c2bac75982 100644 --- a/app/code/Magento/CheckoutAgreements/Test/Mftf/Test/AdminCreateActiveTextTermEntityTest.xml +++ b/app/code/Magento/CheckoutAgreements/Test/Mftf/Test/AdminCreateActiveTextTermEntityTest.xml @@ -20,9 +20,7 @@ - - - + diff --git a/app/code/Magento/CheckoutAgreements/composer.json b/app/code/Magento/CheckoutAgreements/composer.json index 753bef25e3e6..e5cc74b014ea 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.4.3-p7", "require": { "php": "~7.4.0||~8.1.0", - "magento/framework": "*", - "magento/module-backend": "*", - "magento/module-checkout": "*", - "magento/module-quote": "*", - "magento/module-store": "*" + "magento/framework": "103.0.*", + "magento/module-backend": "102.0.*", + "magento/module-checkout": "100.4.*", + "magento/module-quote": "101.2.*", + "magento/module-store": "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/CheckoutAgreementsGraphQl/composer.json b/app/code/Magento/CheckoutAgreementsGraphQl/composer.json index de6bc855e784..f75215e0e3e1 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.4.1", "require": { "php": "~7.4.0||~8.1.0", - "magento/framework": "*", - "magento/module-store": "*", - "magento/module-checkout-agreements": "*" + "magento/framework": "103.0.*", + "magento/module-store": "101.1.*", + "magento/module-checkout-agreements": "100.4.*" }, "suggest": { - "magento/module-graph-ql": "*" + "magento/module-graph-ql": "100.4.*" }, - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -24,3 +25,4 @@ } } } + diff --git a/app/code/Magento/Cms/Controller/Noroute/Index.php b/app/code/Magento/Cms/Controller/Noroute/Index.php index b30beae73dce..5475e7960dd2 100644 --- a/app/code/Magento/Cms/Controller/Noroute/Index.php +++ b/app/code/Magento/Cms/Controller/Noroute/Index.php @@ -6,15 +6,17 @@ */ namespace Magento\Cms\Controller\Noroute; +use Magento\Framework\Controller\Result\ForwardFactory; + /** * @SuppressWarnings(PHPMD.AllPurposeAction) */ class Index extends \Magento\Framework\App\Action\Action { /** - * @var \Magento\Framework\Controller\Result\ForwardFactory + * @var ForwardFactory */ - protected $resultForwardFactory; + protected ForwardFactory $resultForwardFactory; /** * @param \Magento\Framework\App\Action\Context $context @@ -48,6 +50,7 @@ public function execute() if ($resultPage) { $resultPage->setStatusHeader(404, '1.1', 'Not Found'); $resultPage->setHeader('Status', '404 File not found'); + $resultPage->setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0', true); return $resultPage; } else { /** @var \Magento\Framework\Controller\Result\Forward $resultForward */ diff --git a/app/code/Magento/Cms/Test/Unit/Controller/Noroute/IndexTest.php b/app/code/Magento/Cms/Test/Unit/Controller/Noroute/IndexTest.php index 665b79fdf48b..6d4dcfc0711d 100644 --- a/app/code/Magento/Cms/Test/Unit/Controller/Noroute/IndexTest.php +++ b/app/code/Magento/Cms/Test/Unit/Controller/Noroute/IndexTest.php @@ -29,17 +29,17 @@ class IndexTest extends TestCase /** * @var Index */ - protected $_controller; + protected Index $_controller; /** * @var MockObject */ - protected $_cmsHelperMock; + protected MockObject $_cmsHelperMock; /** * @var MockObject */ - protected $_requestMock; + protected MockObject $_requestMock; /** * @var ForwardFactory|MockObject @@ -121,8 +121,10 @@ public function testExecuteResultPage(): void ->willReturn($this->resultPageMock); $this->resultPageMock ->method('setHeader') - ->with('Status', '404 File not found') - ->willReturn($this->resultPageMock); + ->withConsecutive( + ['Status', '404 File not found'], + ['Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0'] + )->willReturn($this->resultPageMock); $this->_cmsHelperMock->expects( $this->once() )->method( diff --git a/app/code/Magento/Cms/composer.json b/app/code/Magento/Cms/composer.json index b3b2ba31db37..4edaefe5474e 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": "104.0.4-p2", "require": { "php": "~7.4.0||~8.1.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": "103.0.*", + "magento/module-backend": "102.0.*", + "magento/module-catalog": "104.0.*", + "magento/module-email": "101.1.*", + "magento/module-media-storage": "100.4.*", + "magento/module-store": "101.1.*", + "magento/module-theme": "101.1.*", + "magento/module-ui": "101.2.*", + "magento/module-variable": "100.4.*", + "magento/module-widget": "101.2.*" }, "suggest": { - "magento/module-cms-sample-data": "*" + "magento/module-cms-sample-data": "Sample Data version: 100.4.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -34,3 +35,4 @@ } } } + diff --git a/app/code/Magento/CmsGraphQl/composer.json b/app/code/Magento/CmsGraphQl/composer.json index b2550344299f..31cdf1b9242e 100644 --- a/app/code/Magento/CmsGraphQl/composer.json +++ b/app/code/Magento/CmsGraphQl/composer.json @@ -2,22 +2,23 @@ "name": "magento/module-cms-graph-ql", "description": "N/A", "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "version": "100.4.2", "require": { "php": "~7.4.0||~8.1.0", - "magento/framework": "*", - "magento/module-cms": "*", - "magento/module-widget": "*", - "magento/module-store": "*" + "magento/framework": "103.0.*", + "magento/module-cms": "104.0.*", + "magento/module-widget": "101.2.*", + "magento/module-store": "101.1.*" }, "suggest": { - "magento/module-graph-ql": "*", - "magento/module-graph-ql-cache": "*", - "magento/module-store-graph-ql": "*" + "magento/module-graph-ql": "100.4.*", + "magento/module-graph-ql-cache": "100.4.*", + "magento/module-store-graph-ql": "100.4.*" }, - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -27,3 +28,4 @@ } } } + diff --git a/app/code/Magento/CmsUrlRewrite/composer.json b/app/code/Magento/CmsUrlRewrite/composer.json index 8fb9bbfff22e..d9e13faaab10 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.4.3", "require": { "php": "~7.4.0||~8.1.0", - "magento/framework": "*", - "magento/module-cms": "*", - "magento/module-store": "*", - "magento/module-url-rewrite": "*" + "magento/framework": "103.0.*", + "magento/module-cms": "104.0.*", + "magento/module-store": "101.1.*", + "magento/module-url-rewrite": "102.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/CmsUrlRewriteGraphQl/composer.json b/app/code/Magento/CmsUrlRewriteGraphQl/composer.json index 70a598d26d57..05fb964b8e51 100644 --- a/app/code/Magento/CmsUrlRewriteGraphQl/composer.json +++ b/app/code/Magento/CmsUrlRewriteGraphQl/composer.json @@ -2,22 +2,23 @@ "name": "magento/module-cms-url-rewrite-graph-ql", "description": "N/A", "type": "magento2-module", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "version": "100.4.2", "require": { "php": "~7.4.0||~8.1.0", - "magento/framework": "*", - "magento/module-cms": "*", - "magento/module-store": "*", - "magento/module-url-rewrite-graph-ql": "*", - "magento/module-cms-graph-ql": "*" + "magento/framework": "103.0.*", + "magento/module-cms": "104.0.*", + "magento/module-store": "101.1.*", + "magento/module-url-rewrite-graph-ql": "100.4.*", + "magento/module-cms-graph-ql": "100.4.*" }, "suggest": { - "magento/module-cms-url-rewrite": "*", - "magento/module-catalog-graph-ql": "*" + "magento/module-cms-url-rewrite": "100.4.*", + "magento/module-catalog-graph-ql": "100.4.*" }, - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -27,3 +28,4 @@ } } } + diff --git a/app/code/Magento/CompareListGraphQl/composer.json b/app/code/Magento/CompareListGraphQl/composer.json index e8fb5d588852..bae7c7a6e376 100644 --- a/app/code/Magento/CompareListGraphQl/composer.json +++ b/app/code/Magento/CompareListGraphQl/composer.json @@ -2,16 +2,17 @@ "name": "magento/module-compare-list-graph-ql", "description": "N/A", "type": "magento2-module", - "require": { - "php": "~7.4.0||~8.1.0", - "magento/framework": "*", - "magento/module-catalog": "*", - "magento/module-customer": "*" - }, "license": [ "OSL-3.0", "AFL-3.0" ], + "version": "100.4.1", + "require": { + "php": "~7.4.0||~8.1.0", + "magento/framework": "103.0.*", + "magento/module-catalog": "104.0.*", + "magento/module-customer": "103.0.*" + }, "autoload": { "files": [ "registration.php" @@ -21,3 +22,4 @@ } } } + diff --git a/app/code/Magento/Config/Block/System/Config/Form/Field/File.php b/app/code/Magento/Config/Block/System/Config/Form/Field/File.php index 6ebd85af7a5d..edc3d3e97707 100644 --- a/app/code/Magento/Config/Block/System/Config/Form/Field/File.php +++ b/app/code/Magento/Config/Block/System/Config/Form/Field/File.php @@ -9,6 +9,8 @@ * * @author Magento Core Team */ +declare(strict_types=1); + namespace Magento\Config\Block\System\Config\Form\Field; class File extends \Magento\Framework\Data\Form\Element\File @@ -35,7 +37,7 @@ protected function _getDeleteCheckbox() $html = ''; if ((string)$this->getValue()) { $label = __('Delete File'); - $html .= '
' . $this->getValue() . ' '; + $html .= '
' . $this->_escaper->escapeHtml($this->getValue()) . ' '; $html .= 'assertStringContainsString($this->testData['before_element_html'], $html); diff --git a/app/code/Magento/Config/composer.json b/app/code/Magento/Config/composer.json index 61100e6336c2..46c7dfb2a145 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.2.4-p10", "require": { "php": "~7.4.0||~8.1.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": "103.0.*", + "magento/module-backend": "102.0.*", + "magento/module-cron": "100.4.*", + "magento/module-deploy": "100.4.*", + "magento/module-directory": "100.4.*", + "magento/module-email": "101.1.*", + "magento/module-media-storage": "100.4.*", + "magento/module-store": "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/Config/i18n/en_US.csv b/app/code/Magento/Config/i18n/en_US.csv index ceb1efdc8b77..b7e1e4c7611b 100644 --- a/app/code/Magento/Config/i18n/en_US.csv +++ b/app/code/Magento/Config/i18n/en_US.csv @@ -119,3 +119,4 @@ Dashboard,Dashboard "Store Email Addresses Section","Store Email Addresses Section" "Email to a Friend","Email to a Friend" "Taiwan","Taiwan, Province of China" +"Invalid file name", "Invalid file name" diff --git a/app/code/Magento/ConfigurableImportExport/composer.json b/app/code/Magento/ConfigurableImportExport/composer.json index 98205def6a79..6280f47609db 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.4.2", "require": { "php": "~7.4.0||~8.1.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": "103.0.*", + "magento/module-catalog": "104.0.*", + "magento/module-catalog-import-export": "101.1.*", + "magento/module-configurable-product": "100.4.*", + "magento/module-eav": "102.1.*", + "magento/module-import-export": "101.0.*", + "magento/module-store": "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/ConfigurableProduct/Test/Mftf/ActionGroup/CreateNewAttributeActionGroup.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/CreateNewAttributeActionGroup.xml index 9925aba09fb8..0f0ea705971e 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/CreateNewAttributeActionGroup.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/ActionGroup/CreateNewAttributeActionGroup.xml @@ -51,6 +51,7 @@ + diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Data/ConfigurableProductAttributeNameDesignData.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Data/ConfigurableProductAttributeNameDesignData.xml index 0018f5996c9b..ec8fc99b46bb 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Data/ConfigurableProductAttributeNameDesignData.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Data/ConfigurableProductAttributeNameDesignData.xml @@ -12,7 +12,7 @@ Shoes 60 100 - design + design123 red red123 blue diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/ConfigurableProductAttributeNameDesignSection/CatalogProductsSection.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/ConfigurableProductAttributeNameDesignSection/CatalogProductsSection.xml index fb71d6cbda2a..df3fffb6f716 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/ConfigurableProductAttributeNameDesignSection/CatalogProductsSection.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/ConfigurableProductAttributeNameDesignSection/CatalogProductsSection.xml @@ -14,7 +14,7 @@ - + diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/ConfigurableProductAttributeNameDesignSection/ConfigurableProductSection.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/ConfigurableProductAttributeNameDesignSection/ConfigurableProductSection.xml index 8099f30941f7..437411d7c041 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/ConfigurableProductAttributeNameDesignSection/ConfigurableProductSection.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Section/ConfigurableProductAttributeNameDesignSection/ConfigurableProductSection.xml @@ -12,7 +12,7 @@ - + diff --git a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontGalleryConfigurableProductWithVisualSwatchAttributePrependMediaTest.xml b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontGalleryConfigurableProductWithVisualSwatchAttributePrependMediaTest.xml index c76d49a76d94..61d4eb230b9e 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontGalleryConfigurableProductWithVisualSwatchAttributePrependMediaTest.xml +++ b/app/code/Magento/ConfigurableProduct/Test/Mftf/Test/StorefrontGalleryConfigurableProductWithVisualSwatchAttributePrependMediaTest.xml @@ -106,7 +106,9 @@ - + + + @@ -115,14 +117,16 @@ - + - + + + @@ -130,7 +134,10 @@ - + + + + |{{Magento2.filename}}.*.jpg| @@ -157,7 +164,13 @@ - + + + + + + + |{{MagentoLogo.filename}}.*.png| @@ -196,7 +209,10 @@ - + + + + |{{Magento2.filename}}.*.jpg| @@ -223,7 +239,13 @@ - + + + + + + + |{{Magento3.filename}}.*.jpg| @@ -262,7 +284,10 @@ - + + + + |{{Magento2.filename}}.*.jpg| diff --git a/app/code/Magento/ConfigurableProduct/composer.json b/app/code/Magento/ConfigurableProduct/composer.json index 67b1ad2b2ed3..940a1d858164 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.4.4-p7", "require": { "php": "~7.4.0||~8.1.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": "103.0.*", + "magento/module-backend": "102.0.*", + "magento/module-catalog": "104.0.*", + "magento/module-catalog-inventory": "100.4.*", + "magento/module-checkout": "100.4.*", + "magento/module-customer": "103.0.*", + "magento/module-eav": "102.1.*", + "magento/module-media-storage": "100.4.*", + "magento/module-quote": "101.2.*", + "magento/module-store": "101.1.*", + "magento/module-ui": "101.2.*" }, "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.4.*", + "magento/module-webapi": "100.4.*", + "magento/module-sales": "103.0.*", + "magento/module-sales-rule": "101.2.*", + "magento/module-product-video": "100.4.*", + "magento/module-configurable-sample-data": "Sample Data version: 100.4.*", + "magento/module-product-links-sample-data": "Sample Data version: 100.4.*", + "magento/module-tax": "100.4.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -42,3 +43,4 @@ } } } + diff --git a/app/code/Magento/ConfigurableProductGraphQl/composer.json b/app/code/Magento/ConfigurableProductGraphQl/composer.json index b839227511d8..c6afeab187bd 100644 --- a/app/code/Magento/ConfigurableProductGraphQl/composer.json +++ b/app/code/Magento/ConfigurableProductGraphQl/composer.json @@ -2,21 +2,22 @@ "name": "magento/module-configurable-product-graph-ql", "description": "N/A", "type": "magento2-module", - "require": { - "php": "~7.4.0||~8.1.0", - "magento/module-catalog": "*", - "magento/module-configurable-product": "*", - "magento/module-graph-ql": "*", - "magento/module-catalog-graph-ql": "*", - "magento/module-quote": "*", - "magento/module-quote-graph-ql": "*", - "magento/module-catalog-inventory": "*", - "magento/framework": "*" - }, "license": [ "OSL-3.0", "AFL-3.0" ], + "version": "100.4.4", + "require": { + "php": "~7.4.0||~8.1.0", + "magento/module-catalog": "104.0.*", + "magento/module-configurable-product": "100.4.*", + "magento/module-graph-ql": "100.4.*", + "magento/module-catalog-graph-ql": "100.4.*", + "magento/module-quote": "101.2.*", + "magento/module-quote-graph-ql": "100.4.*", + "magento/module-catalog-inventory": "100.4.*", + "magento/framework": "103.0.*" + }, "autoload": { "files": [ "registration.php" @@ -26,3 +27,4 @@ } } } + diff --git a/app/code/Magento/ConfigurableProductSales/composer.json b/app/code/Magento/ConfigurableProductSales/composer.json index 55b2e78bd24d..4256442b87ac 100644 --- a/app/code/Magento/ConfigurableProductSales/composer.json +++ b/app/code/Magento/ConfigurableProductSales/composer.json @@ -1,22 +1,23 @@ { "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.4.2", "require": { "php": "~7.4.0||~8.1.0", - "magento/framework": "*", - "magento/module-catalog": "*", - "magento/module-sales": "*", - "magento/module-store": "*", - "magento/module-configurable-product": "*" + "magento/framework": "103.0.*", + "magento/module-catalog": "104.0.*", + "magento/module-sales": "103.0.*", + "magento/module-store": "101.1.*", + "magento/module-configurable-product": "100.4.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -26,3 +27,4 @@ } } } + diff --git a/app/code/Magento/Contact/composer.json b/app/code/Magento/Contact/composer.json index 00ea8f865928..55e8dae73c64 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.4.4", "require": { "php": "~7.4.0||~8.1.0", - "magento/framework": "*", - "magento/module-cms": "*", - "magento/module-config": "*", - "magento/module-customer": "*", - "magento/module-store": "*" + "magento/framework": "103.0.*", + "magento/module-cms": "104.0.*", + "magento/module-config": "101.2.*", + "magento/module-customer": "103.0.*", + "magento/module-store": "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/Cookie/composer.json b/app/code/Magento/Cookie/composer.json index 6a5752792f7f..597019ad6211 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.4.4", "require": { "php": "~7.4.0||~8.1.0", - "magento/framework": "*", - "magento/module-store": "*" + "magento/framework": "103.0.*", + "magento/module-store": "101.1.*" }, "suggest": { - "magento/module-backend": "*" + "magento/module-backend": "102.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 0468a95b457c..6cc88e7583af 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.4.4", "require": { "php": "~7.4.0||~8.1.0", - "magento/framework": "*", - "magento/module-store": "*" + "magento/framework": "103.0.*", + "magento/module-store": "101.1.*" }, "suggest": { - "magento/module-config": "*" + "magento/module-config": "101.2.*" }, - "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/Block/Sri/Hashes.php b/app/code/Magento/Csp/Block/Sri/Hashes.php new file mode 100644 index 000000000000..7b67ec4ca534 --- /dev/null +++ b/app/code/Magento/Csp/Block/Sri/Hashes.php @@ -0,0 +1,94 @@ +integrityRepositoryPool = $integrityRepositoryPool ?: ObjectManager::getInstance() + ->get(SubresourceIntegrityRepositoryPool::class); + + $this->serializer = $serializer ?: ObjectManager::getInstance() + ->get(SerializerInterface::class); + } + + /** + * Retrieves integrity hashes in serialized format. + * + * @throws LocalizedException + * + * @return string + */ + public function getSerialized(): string + { + $result = []; + + $baseUrl = $this->_urlBuilder->getBaseUrl( + ["_type" => UrlInterface::URL_TYPE_STATIC] + ); + + $integrityRepository = $this->integrityRepositoryPool->get( + Package::BASE_AREA + ); + + foreach ($integrityRepository->getAll() as $integrity) { + $url = $baseUrl . $integrity->getPath(); + + $result[$url] = $integrity->getHash(); + } + + $integrityRepository = $this->integrityRepositoryPool->get( + $this->_appState->getAreaCode() + ); + + foreach ($integrityRepository->getAll() as $integrity) { + $url = $baseUrl . $integrity->getPath(); + + $result[$url] = $integrity->getHash(); + } + + return $this->serializer->serialize($result); + } +} diff --git a/app/code/Magento/Csp/Helper/CspNonceProvider.php b/app/code/Magento/Csp/Helper/CspNonceProvider.php new file mode 100644 index 000000000000..14cfc859b321 --- /dev/null +++ b/app/code/Magento/Csp/Helper/CspNonceProvider.php @@ -0,0 +1,86 @@ +random = $random; + $this->dynamicCollector = $dynamicCollector; + } + + /** + * Generate nonce and add it to the CSP header + * + * @return string + * @throws LocalizedException + */ + public function generateNonce(): string + { + if (empty($this->nonce)) { + $this->nonce = $this->random->getRandomString( + self::NONCE_LENGTH, + Random::CHARS_DIGITS . Random::CHARS_LOWERS + ); + + $policy = new FetchPolicy( + 'script-src', + false, + [], + [], + false, + false, + false, + [$this->nonce], + [] + ); + + $this->dynamicCollector->add($policy); + } + + return base64_encode($this->nonce); + } +} diff --git a/app/code/Magento/Csp/Helper/InlineUtil.php b/app/code/Magento/Csp/Helper/InlineUtil.php index f2a70fe465de..be6ac32485fa 100644 --- a/app/code/Magento/Csp/Helper/InlineUtil.php +++ b/app/code/Magento/Csp/Helper/InlineUtil.php @@ -45,6 +45,14 @@ class InlineUtil implements InlineUtilInterface, SecurityProcessorInterface */ private $configCollector; + /** + * @var CspNonceProvider + */ + private CspNonceProvider $nonceProvider; + + /** + * @var array[] + */ private static $tagMeta = [ 'script' => ['id' => 'script-src', 'remote' => ['src'], 'hash' => true], 'style' => ['id' => 'style-src', 'remote' => [], 'hash' => true], @@ -67,17 +75,20 @@ class InlineUtil implements InlineUtilInterface, SecurityProcessorInterface * @param bool $useUnsafeHashes Use 'unsafe-hashes' policy (not supported by CSP v2). * @param HtmlRenderer|null $htmlRenderer * @param ConfigCollector|null $configCollector + * @param CspNonceProvider|null $nonceProvider */ public function __construct( DynamicCollector $dynamicCollector, bool $useUnsafeHashes = false, ?HtmlRenderer $htmlRenderer = null, - ?ConfigCollector $configCollector = null + ?ConfigCollector $configCollector = null, + ?CspNonceProvider $nonceProvider = null ) { $this->dynamicCollector = $dynamicCollector; $this->useUnsafeHashes = $useUnsafeHashes; $this->htmlRenderer = $htmlRenderer ?? ObjectManager::getInstance()->get(HtmlRenderer::class); $this->configCollector = $configCollector ?? ObjectManager::getInstance()->get(ConfigCollector::class); + $this->nonceProvider = $nonceProvider ?? ObjectManager::getInstance()->get(CspNonceProvider::class); } /** @@ -200,19 +211,34 @@ public function processTag(TagData $tagData): TagData && !empty(self::$tagMeta[$tagData->getTag()]['hash']) && $this->isInlineDisabled(self::$tagMeta[$tagData->getTag()]['id']) ) { - $this->dynamicCollector->add( - new FetchPolicy( - $policyId, - false, - [], - [], - false, - false, - false, - [], - $this->generateHashValue($tagData->getContent()) - ) - ); + /** create new tagData with a nonce */ + if ($tagData->getTag() === 'script') { + $nonce = $this->nonceProvider->generateNonce(); + $tagAttributes = $tagData->getAttributes(); + $tagAttributes['nonce'] = $nonce; + $newTagData = new TagData( + $tagData->getTag(), + $tagAttributes, + $tagData->getContent(), + $tagData->isTextContent() + ); + + $tagData = $newTagData; + } else { + $this->dynamicCollector->add( + new FetchPolicy( + $policyId, + false, + [], + [], + false, + false, + false, + [], + $this->generateHashValue($tagData->getContent()) + ) + ); + } } } diff --git a/app/code/Magento/Csp/Model/Collector/ConfigCollector.php b/app/code/Magento/Csp/Model/Collector/ConfigCollector.php index 34711fe5d8a2..1ae4badbc934 100644 --- a/app/code/Magento/Csp/Model/Collector/ConfigCollector.php +++ b/app/code/Magento/Csp/Model/Collector/ConfigCollector.php @@ -11,6 +11,8 @@ use Magento\Csp\Model\Collector\Config\PolicyReaderPool; use Magento\Framework\App\Area; use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Framework\App\ObjectManager; +use Magento\Framework\App\Request\Http; use Magento\Framework\App\State; use Magento\Store\Model\StoreManagerInterface; use Magento\Store\Model\ScopeInterface; @@ -40,22 +42,32 @@ class ConfigCollector implements PolicyCollectorInterface */ private $storeManager; + /** + * @var Http + */ + private Http $request; + /** * @param ScopeConfigInterface $config * @param PolicyReaderPool $readersPool * @param State $state * @param StoreManagerInterface $storeManager + * @param Http|null $request */ public function __construct( ScopeConfigInterface $config, PolicyReaderPool $readersPool, State $state, - StoreManagerInterface $storeManager + StoreManagerInterface $storeManager, + ?Http $request = null ) { $this->config = $config; $this->readersPool = $readersPool; $this->state = $state; $this->storeManager = $storeManager; + + $this->request = $request + ?? ObjectManager::getInstance()->get(Http::class); } /** @@ -74,11 +86,26 @@ public function collect(array $defaultPolicies = []): array } if ($configArea) { - $policiesConfig = $this->config->getValue( + $policiesConfigGlobal = $this->config->getValue( 'csp/policies/' . $configArea, ScopeInterface::SCOPE_STORE, $this->storeManager->getStore() ); + + $policiesConfigLocal = $this->config->getValue( + sprintf( + 'csp/policies/%s_%s', + $configArea, + $this->request->getFullActionName() + ), + ScopeInterface::SCOPE_STORE, + $this->storeManager->getStore() + ); + + $policiesConfig = is_array($policiesConfigLocal) ? + array_replace_recursive($policiesConfigGlobal, $policiesConfigLocal) : + $policiesConfigGlobal; + if (is_array($policiesConfig) && $policiesConfig) { foreach ($policiesConfig as $policyConfig) { $collected[] = $this->readersPool->getReader($policyConfig['policy_id']) diff --git a/app/code/Magento/Csp/Model/Deploy/Package/Processor/PostProcessor/Integrity.php b/app/code/Magento/Csp/Model/Deploy/Package/Processor/PostProcessor/Integrity.php new file mode 100644 index 000000000000..41e81752632f --- /dev/null +++ b/app/code/Magento/Csp/Model/Deploy/Package/Processor/PostProcessor/Integrity.php @@ -0,0 +1,89 @@ +filesystem = $filesystem; + $this->hashGenerator = $hashGenerator; + $this->integrityFactory = $integrityFactory; + $this->integrityCollector = $integrityCollector; + } + + /** + * @inheritdoc + */ + public function process(Package $package, array $options): bool + { + $staticDir = $this->filesystem->getDirectoryRead( + DirectoryList::ROOT + ); + + foreach ($package->getFiles() as $file) { + if ($file->getExtension() == "js") { + $integrity = $this->integrityFactory->create( + [ + "data" => [ + 'hash' => $this->hashGenerator->generate( + $staticDir->readFile($file->getSourcePath()) + ), + 'path' => $file->getDeployedFilePath() + ] + ] + ); + + $this->integrityCollector->collect($integrity); + } + } + + return true; + } +} diff --git a/app/code/Magento/Csp/Model/Deploy/Package/Processor/PostProcessor/Map.php b/app/code/Magento/Csp/Model/Deploy/Package/Processor/PostProcessor/Map.php new file mode 100644 index 000000000000..4e97517a165c --- /dev/null +++ b/app/code/Magento/Csp/Model/Deploy/Package/Processor/PostProcessor/Map.php @@ -0,0 +1,139 @@ +minification = $minification; + $this->integrityFactory = $integrityFactory; + $this->hashGenerator = $hashGenerator; + $this->driver = $driver; + $this->integrityCollector = $integrityCollector; + $this->filesystem = $filesystem; + parent::__construct($deployStaticFile, $formatter, $packageFileFactory, $minification); + } + + /** + * @inheritdoc + * + * @throws FileSystemException + */ + public function process(Package $package, array $options): bool + { + parent::process($package, $options); + $fileName = $this->minification->addMinifiedSign(RepositoryMap::REQUIRE_JS_MAP_NAME); + $path = $package->getPath(); + $relativePath = $path . DIRECTORY_SEPARATOR . $fileName; + + if ($this->fileExists($relativePath)) { + $dir = $this->filesystem->getDirectoryWrite(DirectoryList::STATIC_VIEW); + $absolutePath = $dir->getAbsolutePath($relativePath); + $fileContent = $this->driver->fileGetContents($absolutePath); + + if ($fileContent) { + $integrity = $this->integrityFactory->create( + [ + "data" => [ + 'hash' => $this->hashGenerator->generate($fileContent), + 'path' => $relativePath + ] + ] + ); + $this->integrityCollector->collect($integrity); + } + } + return true; + } + + /** + * Check if file exist + * + * @param string $path + * @return bool + * @throws FileSystemException + */ + private function fileExists(string $path): bool + { + $dir = $this->filesystem->getDirectoryWrite(DirectoryList::STATIC_VIEW); + return $dir->isExist($path); + } +} diff --git a/app/code/Magento/Csp/Model/Mode/ConfigManager.php b/app/code/Magento/Csp/Model/Mode/ConfigManager.php index 9f10154604d5..bc31a4198254 100644 --- a/app/code/Magento/Csp/Model/Mode/ConfigManager.php +++ b/app/code/Magento/Csp/Model/Mode/ConfigManager.php @@ -7,6 +7,8 @@ namespace Magento\Csp\Model\Mode; +use Magento\Framework\App\Request\Http; +use Magento\Framework\App\ObjectManager; use Magento\Csp\Api\Data\ModeConfiguredInterface; use Magento\Csp\Api\ModeConfigManagerInterface; use Magento\Csp\Model\Mode\Data\ModeConfigured; @@ -36,16 +38,29 @@ class ConfigManager implements ModeConfigManagerInterface */ private $state; + /** + * @var Http + */ + private Http $request; + /** * @param ScopeConfigInterface $config * @param Store $store * @param State $state + * @param Http|null $request */ - public function __construct(ScopeConfigInterface $config, Store $store, State $state) - { + public function __construct( + ScopeConfigInterface $config, + Store $store, + State $state, + ?Http $request = null + ) { $this->config = $config; $this->storeModel = $store; $this->state = $state; + + $this->request = $request + ?? ObjectManager::getInstance()->get(Http::class); } /** @@ -54,25 +69,58 @@ public function __construct(ScopeConfigInterface $config, Store $store, State $s public function getConfigured(): ModeConfiguredInterface { $area = $this->state->getAreaCode(); + if ($area === Area::AREA_ADMINHTML) { $configArea = 'admin'; } elseif ($area === Area::AREA_FRONTEND) { $configArea = 'storefront'; } else { - throw new \RuntimeException('CSP can only be configured for storefront or admin area'); + throw new \RuntimeException( + 'CSP can only be configured for storefront or admin area' + ); } - $reportOnly = $this->config->isSetFlag( - 'csp/mode/' . $configArea .'/report_only', + $reportOnly = $this->config->getValue( + sprintf( + 'csp/mode/%s_%s/report_only', + $configArea, + $this->request->getFullActionName() + ), ScopeInterface::SCOPE_STORE, $this->storeModel->getStore() ); + + if ($reportOnly === null) { + // Fallback to default configuration. + $reportOnly = $this->config->getValue( + 'csp/mode/' . $configArea .'/report_only', + ScopeInterface::SCOPE_STORE, + $this->storeModel->getStore() + ); + } + $reportUri = $this->config->getValue( - 'csp/mode/' . $configArea .'/report_uri', + sprintf( + 'csp/mode/%s_%s/report_uri', + $configArea, + $this->request->getFullActionName() + ), ScopeInterface::SCOPE_STORE, $this->storeModel->getStore() ); - return new ModeConfigured($reportOnly, !empty($reportUri) ? $reportUri : null); + if (empty($reportUri)) { + // Fallback to default configuration. + $reportUri = $this->config->getValue( + 'csp/mode/' . $configArea .'/report_uri', + ScopeInterface::SCOPE_STORE, + $this->storeModel->getStore() + ); + } + + return new ModeConfigured( + (bool) $reportOnly, + !empty($reportUri) ? $reportUri : null + ); } } diff --git a/app/code/Magento/Csp/Model/SubresourceIntegrity.php b/app/code/Magento/Csp/Model/SubresourceIntegrity.php new file mode 100644 index 000000000000..0a2824c93027 --- /dev/null +++ b/app/code/Magento/Csp/Model/SubresourceIntegrity.php @@ -0,0 +1,34 @@ +getData("path"); + } + + /** + * Gets an integrity hash. + * + * @return string|null + */ + public function getHash(): ?string + { + return $this->getData("hash"); + } +} diff --git a/app/code/Magento/Csp/Model/SubresourceIntegrity/HashGenerator.php b/app/code/Magento/Csp/Model/SubresourceIntegrity/HashGenerator.php new file mode 100644 index 000000000000..be78a1a0c66b --- /dev/null +++ b/app/code/Magento/Csp/Model/SubresourceIntegrity/HashGenerator.php @@ -0,0 +1,37 @@ +data = $data; + } + + /** + * Collects given Integrity object. + * + * @param SubresourceIntegrity $integrity + * + * @return void + */ + public function collect(SubresourceIntegrity $integrity): void + { + $this->data[] = $integrity; + } + + /** + * Provides all collected Integrity objects. + * + * @return SubresourceIntegrity[] + */ + public function release(): array + { + return $this->data; + } +} diff --git a/app/code/Magento/Csp/Model/SubresourceIntegrityRepository.php b/app/code/Magento/Csp/Model/SubresourceIntegrityRepository.php new file mode 100644 index 000000000000..7cc83466ab07 --- /dev/null +++ b/app/code/Magento/Csp/Model/SubresourceIntegrityRepository.php @@ -0,0 +1,211 @@ +cache = $cache; + $this->serializer = $serializer; + $this->integrityFactory = $integrityFactory; + $this->context = $context; + } + + /** + * Gets an Integrity object by path. + * + * @param string $path + * + * @return SubresourceIntegrity|null + */ + public function getByPath(string $path): ?SubresourceIntegrity + { + $data = $this->getData(); + + if (isset($data[$path])) { + return $this->integrityFactory->create( + [ + "data" => [ + "path" => $path, + "hash" => $data[$path] + ] + ] + ); + } + + return null; + } + + /** + * Gets all available Integrity objects. + * + * @return SubresourceIntegrity[] + */ + public function getAll(): array + { + $result = []; + + foreach ($this->getData() as $path => $hash) { + $result[] = $this->integrityFactory->create( + [ + "data" => [ + "path" => $path, + "hash" => $hash + ] + ] + ); + } + + return $result; + } + + /** + * Saves Integrity object. + * + * @param SubresourceIntegrity $integrity + * + * @return bool + */ + public function save(SubresourceIntegrity $integrity): bool + { + $data = $this->getData(); + + $data[$integrity->getPath()] = $integrity->getHash(); + + $this->data = $data; + + return $this->cache->save( + $this->serializer->serialize($this->data), + $this->getCacheKey(), + [self::CACHE_PREFIX] + ); + } + + /** + * Saves a bunch of Integrity objects. + * + * @param SubresourceIntegrity[] $bunch + * + * @return bool + */ + public function saveBunch(array $bunch): bool + { + $data = $this->getData(); + + foreach ($bunch as $integrity) { + $data[$integrity->getPath()] = $integrity->getHash(); + } + + $this->data = $data; + + return $this->cache->save( + $this->serializer->serialize($this->data), + $this->getCacheKey(), + [self::CACHE_PREFIX] + ); + } + + /** + * Deletes all Integrity objects. + * + * @return bool + */ + public function deleteAll(): bool + { + $this->data = null; + + return $this->cache->remove( + $this->getCacheKey() + ); + } + + /** + * Loads integrity data from a storage. + * + * @return array + */ + private function getData(): array + { + if ($this->data === null) { + $cache = $this->cache->load($this->getCacheKey()); + + $this->data = $cache ? $this->serializer->unserialize($cache) : []; + } + + return $this->data; + } + + /** + * Gets a cache key based on current context. + * + * @return string + */ + private function getCacheKey(): string + { + $cacheKey = self::CACHE_PREFIX; + + if ($this->context) { + $cacheKey .= "_" . $this->context; + } + + return $cacheKey; + } +} diff --git a/app/code/Magento/Csp/Model/SubresourceIntegrityRepositoryPool.php b/app/code/Magento/Csp/Model/SubresourceIntegrityRepositoryPool.php new file mode 100644 index 000000000000..5ad9c6c676de --- /dev/null +++ b/app/code/Magento/Csp/Model/SubresourceIntegrityRepositoryPool.php @@ -0,0 +1,53 @@ +integrityRepositoryFactory = $integrityRepositoryFactory; + } + + /** + * Gets subresource integrity repository by given context. + * + * @param string $context + * + * @return SubresourceIntegrityRepository + */ + public function get(string $context): SubresourceIntegrityRepository + { + if (!isset($this->repositories[$context])) { + $this->repositories[$context] = $this->integrityRepositoryFactory->create( + [ + "context" => $context + ] + ); + } + + return $this->repositories[$context]; + } +} diff --git a/app/code/Magento/Csp/Plugin/AddDefaultPropertiesToGroupPlugin.php b/app/code/Magento/Csp/Plugin/AddDefaultPropertiesToGroupPlugin.php new file mode 100644 index 000000000000..159e2180427a --- /dev/null +++ b/app/code/Magento/Csp/Plugin/AddDefaultPropertiesToGroupPlugin.php @@ -0,0 +1,81 @@ +state = $state; + $this->integrityRepositoryPool = $integrityRepositoryPool; + } + + /** + * Before Plugin to add Properties to JS assets + * + * @param GroupedCollection $subject + * @param AssetInterface $asset + * @param array $properties + * @return array + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function beforeGetFilteredProperties( + GroupedCollection $subject, + AssetInterface $asset, + array $properties = [] + ): array { + if ($asset instanceof LocalInterface) { + $integrityRepository = $this->integrityRepositoryPool->get( + Package::BASE_AREA + ); + + $integrity = $integrityRepository->getByPath($asset->getPath()); + + if (!$integrity) { + $integrityRepository = $this->integrityRepositoryPool->get( + $this->state->getAreaCode() + ); + + $integrity = $integrityRepository->getByPath($asset->getPath()); + } + + if ($integrity && $integrity->getHash()) { + $properties['attributes']['integrity'] = $integrity->getHash(); + $properties['attributes']['crossorigin'] = 'anonymous'; + } + } + + return [$asset, $properties]; + } +} diff --git a/app/code/Magento/Csp/Plugin/GenerateAssetIntegrity.php b/app/code/Magento/Csp/Plugin/GenerateAssetIntegrity.php new file mode 100644 index 000000000000..2b461588fa5a --- /dev/null +++ b/app/code/Magento/Csp/Plugin/GenerateAssetIntegrity.php @@ -0,0 +1,91 @@ +hashGenerator = $hashGenerator; + $this->integrityFactory = $integrityFactory; + $this->integrityCollector = $integrityCollector; + } + + /** + * Generates integrity for RequireJs config. + * + * @param FileManager $subject + * @param File $result + * + * @return File + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterCreateRequireJsConfigAsset( + FileManager $subject, + File $result + ): File { + if (PHP_SAPI == 'cli') { + if (in_array($result->getContentType(), self::CONTENT_TYPES)) { + $integrity = $this->integrityFactory->create( + [ + "data" => [ + 'hash' => $this->hashGenerator->generate( + $result->getContent() + ), + 'path' => $result->getPath() + ] + ] + ); + + $this->integrityCollector->collect($integrity); + } + } + + return $result; + } +} diff --git a/app/code/Magento/Csp/Plugin/RemoveAllAssetIntegrityHashes.php b/app/code/Magento/Csp/Plugin/RemoveAllAssetIntegrityHashes.php new file mode 100644 index 000000000000..85b97e9091c5 --- /dev/null +++ b/app/code/Magento/Csp/Plugin/RemoveAllAssetIntegrityHashes.php @@ -0,0 +1,69 @@ +integrityRepositoryPool = $integrityRepositoryPool; + } + + /** + * Removes existing integrity hashes before static content deploy + * + * @param DeployStaticContent $subject + * @param array $options + * + * @return void + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function beforeDeploy( + DeployStaticContent $subject, + array $options + ): void { + if (PHP_SAPI == 'cli' && !$this->isRefreshContentVersionOnly($options)) { + foreach ([Package::BASE_AREA, Area::AREA_FRONTEND, Area::AREA_ADMINHTML] as $area) { + $this->integrityRepositoryPool->get($area) + ->deleteAll(); + } + } + } + + /** + * Checks if only version refresh is requested. + * + * @param array $options + * + * @return bool + */ + private function isRefreshContentVersionOnly(array $options): bool + { + return isset($options[DeployStaticOptions::REFRESH_CONTENT_VERSION_ONLY]) + && $options[DeployStaticOptions::REFRESH_CONTENT_VERSION_ONLY]; + } +} diff --git a/app/code/Magento/Csp/Plugin/StoreAssetIntegrityHashes.php b/app/code/Magento/Csp/Plugin/StoreAssetIntegrityHashes.php new file mode 100644 index 000000000000..e5674dd3a78e --- /dev/null +++ b/app/code/Magento/Csp/Plugin/StoreAssetIntegrityHashes.php @@ -0,0 +1,70 @@ +integrityCollector = $integrityCollector; + $this->integrityRepositoryPool = $integrityRepositoryPool; + } + + /** + * Stores generated integrity hashes after static content deploy + * + * @param DeployStaticContent $subject + * @param mixed $result + * @param array $options + * + * @return void + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterDeploy( + DeployStaticContent $subject, + $result, + array $options + ): void { + $bunches = []; + + foreach ($this->integrityCollector->release() as $integrity) { + $area = explode("/", $integrity->getPath())[0]; + + $bunches[$area][] = $integrity; + } + + foreach ($bunches as $area => $bunch) { + $this->integrityRepositoryPool->get($area) + ->saveBunch($bunch); + } + } +} diff --git a/app/code/Magento/Csp/Test/Unit/Model/Mode/ConfigManagerTest.php b/app/code/Magento/Csp/Test/Unit/Model/Mode/ConfigManagerTest.php index 3660e063387a..9fff6efa407e 100644 --- a/app/code/Magento/Csp/Test/Unit/Model/Mode/ConfigManagerTest.php +++ b/app/code/Magento/Csp/Test/Unit/Model/Mode/ConfigManagerTest.php @@ -12,8 +12,10 @@ use Magento\Csp\Model\Mode\Data\ModeConfigured; use Magento\Framework\App\Area; use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Framework\App\Request\Http; use Magento\Framework\App\State; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Store\Model\ScopeInterface; use Magento\Store\Model\Store; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -44,6 +46,11 @@ class ConfigManagerTest extends TestCase */ private $stateMock; + /** + * @var Http|MockObject + */ + private $requestMock; + /** * Set Up */ @@ -54,13 +61,15 @@ protected function setUp(): void $this->scopeConfigMock = $this->getMockForAbstractClass(ScopeConfigInterface::class); $this->storeMock = $this->createMock(Store::class); $this->stateMock = $this->createMock(State::class); + $this->requestMock = $this->createMock(Http::class); $this->model = $objectManager->getObject( ConfigManager::class, [ 'config' => $this->scopeConfigMock, 'storeModel' => $this->storeMock, - 'state' => $this->stateMock + 'state' => $this->stateMock, + 'request' => $this->requestMock, ] ); } @@ -102,4 +111,73 @@ public function testConfiguredCSPForAdminArea() $this->assertInstanceOf(ModeConfigured::class, $result); } + + /** + * Test storefront checkout page CSP config. + * + * @return void + * + */ + public function testCheckoutPageReportOnly(): void + { + $this->requestMock->expects($this->exactly(2)) + ->method('getFullActionName') + ->willReturn('checkout_index_index'); + + $this->stateMock->expects($this->once()) + ->method('getAreaCode') + ->willReturn(Area::AREA_FRONTEND); + + $matcher = $this->exactly(2); + $this->scopeConfigMock->expects($matcher) + ->method('getValue') + ->willReturnCallback(function () use ($matcher) { + return match ($matcher->getInvocationCount()) { + 1 => ['csp/mode/checkout_index_index/report_only', ScopeInterface::SCOPE_STORE, null], + 2 => ['csp/mode/checkout_index_index/report_uri', ScopeInterface::SCOPE_STORE, null], + }; + }) + ->willReturnOnConsecutiveCalls(true, 'testReportUri'); + + $result = $this->model->getConfigured(); + + $this->assertInstanceOf(ModeConfigured::class, $result); + $this->assertTrue($result->isReportOnly()); + $this->assertEquals($result->getReportUri(), 'testReportUri'); + } + + /** + * Test non checkout page CSP config. + * + * @return void + */ + public function testNonCheckoutPageReportOnly(): void + { + $this->requestMock->expects($this->exactly(2)) + ->method('getFullActionName') + ->willReturn('dashboard_index_index'); + + $this->stateMock->expects($this->once()) + ->method('getAreaCode') + ->willReturn(Area::AREA_ADMINHTML); + + $matcher = $this->exactly(4); + $this->scopeConfigMock->expects($matcher) + ->method('getValue') + ->willReturnCallback(function () use ($matcher) { + return match ($matcher->getInvocationCount()) { + 1 => ['csp/mode/dashboard_index_index/report_only', ScopeInterface::SCOPE_STORE, null], + 2 => ['csp/mode/admin/report_only', ScopeInterface::SCOPE_STORE, null], + 3 => ['csp/mode/dashboard_index_index/report_uri', ScopeInterface::SCOPE_STORE, null], + 4 => ['csp/mode/admin/report_uri', ScopeInterface::SCOPE_STORE, null], + }; + }) + ->willReturnOnConsecutiveCalls(null, true, null, 'testPageReportUri'); + + $result = $this->model->getConfigured(); + + $this->assertInstanceOf(ModeConfigured::class, $result); + $this->assertTrue($result->isReportOnly()); + $this->assertEquals($result->getReportUri(), 'testPageReportUri'); + } } diff --git a/app/code/Magento/Csp/Test/Unit/Model/SubresourceIntegrityRepositoryTest.php b/app/code/Magento/Csp/Test/Unit/Model/SubresourceIntegrityRepositoryTest.php new file mode 100644 index 000000000000..bc75d35f8fd9 --- /dev/null +++ b/app/code/Magento/Csp/Test/Unit/Model/SubresourceIntegrityRepositoryTest.php @@ -0,0 +1,130 @@ +cacheMock = $this->getMockBuilder(CacheInterface::class) + ->disableOriginalConstructor() + ->onlyMethods(['save', 'load']) + ->getMockForAbstractClass(); + $this->serializerMock = $this->getMockBuilder(SerializerInterface::class) + ->disableOriginalConstructor() + ->onlyMethods(['serialize', 'unserialize']) + ->getMockForAbstractClass(); + $this->integrityFactoryMock = $this->getMockBuilder(SubresourceIntegrityFactory::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->subresourceIntegrityRepository = new SubresourceIntegrityRepository( + $this->cacheMock, + $this->serializerMock, + $this->integrityFactoryMock + ); + } + + /** Test save repository + * + * + * @return void + */ + public function testSave(): void + { + $data = new SubresourceIntegrity( + [ + 'hash' => 'testhash', + 'path' => 'js/jquery.js' + ] + ); + + $expected[$data->getPath()] = $data->getHash(); + $serialized = json_encode($expected); + $this->cacheMock->expects($this->once())->method('load')->willReturn(false); + $this->serializerMock->expects($this->once())->method('serialize')->with($expected)->willReturn($serialized); + $this->cacheMock->expects($this->once())->method('save')->willReturn(true); + $this->assertTrue($this->subresourceIntegrityRepository->save($data)); + } + + /** Test that cache saves in bunch + * + * + * @return void + */ + public function testSaveBunch(): void + { + $bunch1 = new SubresourceIntegrity( + [ + 'hash' => 'testhash', + 'path' => 'js/jquery.js' + ] + ); + + $bunch2 = new SubresourceIntegrity( + [ + 'hash' => 'testhash2', + 'path' => 'js/test.js' + ] + ); + + $bunches = [$bunch1, $bunch2]; + + $expected = []; + + foreach ($bunches as $bunch) { + $expected[$bunch->getPath()] = $bunch->getHash(); + } + $serializedBunch = json_encode($expected); + $this->cacheMock->expects($this->once())->method('load')->willReturn(false); + $this->serializerMock->expects($this->once())->method('serialize') + ->with($expected)->willReturn($serializedBunch); + $this->cacheMock->expects($this->once())->method('save')->willReturn(true); + $this->assertTrue($this->subresourceIntegrityRepository->saveBunch($bunches)); + } +} diff --git a/app/code/Magento/Csp/Test/Unit/Plugin/AddDefaultPropertiesToGroupPluginTest.php b/app/code/Magento/Csp/Test/Unit/Plugin/AddDefaultPropertiesToGroupPluginTest.php new file mode 100644 index 000000000000..3e6b08f17bb7 --- /dev/null +++ b/app/code/Magento/Csp/Test/Unit/Plugin/AddDefaultPropertiesToGroupPluginTest.php @@ -0,0 +1,113 @@ +integrityRepositoryPoolMock = $this->getMockBuilder(SubresourceIntegrityRepositoryPool::class) + ->disableOriginalConstructor() + ->onlyMethods(['get']) + ->getMock(); + $this->assetInterfaceMock = $this->getMockBuilder(File::class) + ->disableOriginalConstructor() + ->onlyMethods(['getPath']) + ->getMockForAbstractClass(); + $this->stateMock = $this->getMockBuilder(State::class) + ->disableOriginalConstructor() + ->onlyMethods(['getAreaCode']) + ->getMock(); + $this->plugin = new AddDefaultPropertiesToGroupPlugin( + $this->stateMock, + $this->integrityRepositoryPoolMock + ); + } + + /** + * Test for plugin with Js assets + * + * @return void + */ + public function testBeforeGetFilteredProperties(): void + { + $integrityRepositoryMock = $this->getMockBuilder(SubresourceIntegrityRepository::class) + ->disableOriginalConstructor() + ->onlyMethods(['getByPath']) + ->getMock(); + $groupedCollectionMock = $this->getMockBuilder(GroupedCollection::class) + ->disableOriginalConstructor() + ->getMock(); + $path = 'jquery.js'; + $area = 'base'; + + $data = new SubresourceIntegrity( + [ + 'hash' => 'testhash', + 'path' => $path + ] + ); + $properties['attributes']['integrity'] = $data->getHash(); + $properties['attributes']['crossorigin'] = 'anonymous'; + $expected = [$this->assetInterfaceMock, $properties]; + $this->integrityRepositoryPoolMock->expects($this->once())->method('get')->with($area) + ->willReturn( + $integrityRepositoryMock + ); + $this->assetInterfaceMock->expects($this->once())->method('getPath')->willReturn($path); + $integrityRepositoryMock->expects($this->once())->method('getByPath')->with($path)->willReturn($data); + $this->assertEquals( + $expected, + $this->plugin->beforeGetFilteredProperties( + $groupedCollectionMock, + $this->assetInterfaceMock + ) + ); + } +} diff --git a/app/code/Magento/Csp/Test/Unit/Plugin/StoreAssetIntegrityHashesTest.php b/app/code/Magento/Csp/Test/Unit/Plugin/StoreAssetIntegrityHashesTest.php new file mode 100644 index 000000000000..7ac1d462015c --- /dev/null +++ b/app/code/Magento/Csp/Test/Unit/Plugin/StoreAssetIntegrityHashesTest.php @@ -0,0 +1,96 @@ +integrityRepositoryPoolMock = $this->getMockBuilder(SubresourceIntegrityRepositoryPool::class) + ->disableOriginalConstructor() + ->onlyMethods(['get']) + ->getMock(); + $this->integrityCollectorMock = $this->getMockBuilder(SubresourceIntegrityCollector::class) + ->disableOriginalConstructor() + ->onlyMethods(['release']) + ->getMock(); + $this->plugin = new StoreAssetIntegrityHashes( + $this->integrityCollectorMock, + $this->integrityRepositoryPoolMock, + ); + } + + /** + * Test After Deploy method of plugin + * + * @return void + * @doesNotPerformAssertions + */ + public function testAfterDeploy(): void + { + $bunch1 = new SubresourceIntegrity( + [ + 'hash' => 'testhash', + 'path' => 'adminhtml/js/jquery.js' + ] + ); + + $bunch2 = new SubresourceIntegrity( + [ + 'hash' => 'testhash2', + 'path' => 'frontend/js/test.js' + ] + ); + + $bunches = [$bunch1, $bunch2]; + $deployStaticContentMock = $this->getMockBuilder(DeployStaticContent::class) + ->disableOriginalConstructor() + ->getMock(); + $subResourceIntegrityMock = $this->getMockBuilder(SubresourceIntegrityRepository::class) + ->disableOriginalConstructor() + ->onlyMethods(['saveBunch']) + ->getMock(); + $this->integrityCollectorMock->expects($this->once())->method('release')->willReturn($bunches); + $this->integrityRepositoryPoolMock->expects($this->any())->method('get')->willReturn($subResourceIntegrityMock); + $subResourceIntegrityMock->expects($this->any())->method('saveBunch')->willReturn(true); + $this->plugin->afterDeploy($deployStaticContentMock, null, []); + } +} diff --git a/app/code/Magento/Csp/composer.json b/app/code/Magento/Csp/composer.json index 2079a30d9206..2b4d209abeb2 100644 --- a/app/code/Magento/Csp/composer.json +++ b/app/code/Magento/Csp/composer.json @@ -1,19 +1,22 @@ { "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.4.3-p9", "require": { "php": "~7.4.0||~8.1.0", - "magento/framework": "*", - "magento/module-store": "*" + "magento/framework": "103.0.*", + "magento/module-store": "101.1.*", + "magento/module-require-js": "100.4.*", + "magento/module-deploy": "100.4.*" }, - "type": "magento2-module", - "license": [ - "OSL-3.0", - "AFL-3.0" - ], "autoload": { "files": [ "registration.php" @@ -23,3 +26,4 @@ } } } + diff --git a/app/code/Magento/Csp/etc/acl.xml b/app/code/Magento/Csp/etc/acl.xml new file mode 100644 index 000000000000..da62f053ab4a --- /dev/null +++ b/app/code/Magento/Csp/etc/acl.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/Csp/etc/adminhtml/system.xml b/app/code/Magento/Csp/etc/adminhtml/system.xml new file mode 100644 index 000000000000..38b2a6834bdb --- /dev/null +++ b/app/code/Magento/Csp/etc/adminhtml/system.xml @@ -0,0 +1,35 @@ + + + + +
+ + security + Magento_Csp::config + + + + + + + URI to report CSP violations on storefront. Used for all storefront pages that don't have own URI configured above. + validate-url + + + + + + + URI to report CSP violations in admin area. Used for all admin pages that don't have own URI configured above. + validate-url + + + +
+
+
diff --git a/app/code/Magento/Csp/etc/di.xml b/app/code/Magento/Csp/etc/di.xml index 5e90c4b0c866..79c688f8cf0b 100644 --- a/app/code/Magento/Csp/etc/di.xml +++ b/app/code/Magento/Csp/etc/di.xml @@ -110,4 +110,27 @@ Magento\Csp\Model\BlockCache + + + + Magento\Csp\Model\Deploy\Package\Processor\PostProcessor\Integrity + + + + + + + + + + + + + + + + + Magento\Framework\Filesystem\Driver\File + + diff --git a/app/code/Magento/Csp/view/adminhtml/layout/sales_order_create_index.xml b/app/code/Magento/Csp/view/adminhtml/layout/sales_order_create_index.xml new file mode 100644 index 000000000000..73fe99913466 --- /dev/null +++ b/app/code/Magento/Csp/view/adminhtml/layout/sales_order_create_index.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + diff --git a/app/code/Magento/Csp/view/base/templates/sri/hashes.phtml b/app/code/Magento/Csp/view/base/templates/sri/hashes.phtml new file mode 100644 index 000000000000..e9d666a50550 --- /dev/null +++ b/app/code/Magento/Csp/view/base/templates/sri/hashes.phtml @@ -0,0 +1,18 @@ + + +getSerialized(); +$scriptString = <<', $content ); - $this->assertStringContainsString("", $content); + $this->assertStringContainsString("\n let myVar = 1;\n", $content); $header = $this->getResponse()->getHeader('Content-Security-Policy'); $this->assertNotEmpty($header); $this->assertStringContainsString('http://my.magento.com', $header->getFieldValue()); - $this->assertStringContainsString('\'sha256-H4RRnauTM2X2Xg/z9zkno1crqhsaY3uKKu97uwmnXXE=\'', $header->getFieldValue()); } } diff --git a/dev/tests/integration/testsuite/Magento/Csp/Helper/CspNonceProviderMock.php b/dev/tests/integration/testsuite/Magento/Csp/Helper/CspNonceProviderMock.php new file mode 100644 index 000000000000..75ec9abbe177 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Csp/Helper/CspNonceProviderMock.php @@ -0,0 +1,68 @@ +random = $random; + $this->dynamicCollector = $dynamicCollector; + } + + /** + * Generate nonce and add it to the CSP header + * + * @return string + */ + public function generateNonce(): string + { + $cspNonce = 'nonce-1234567890abcdef'; + + $policy = new FetchPolicy( + 'script-src', + false, + [], + [], + false, + false, + false, + [$cspNonce], + [] + ); + + $this->dynamicCollector->add($policy); + + return $cspNonce; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Csp/Helper/InlineUtilTest.php b/dev/tests/integration/testsuite/Magento/Csp/Helper/InlineUtilTest.php index ab1b702ab1a0..89ac8ab50e68 100644 --- a/dev/tests/integration/testsuite/Magento/Csp/Helper/InlineUtilTest.php +++ b/dev/tests/integration/testsuite/Magento/Csp/Helper/InlineUtilTest.php @@ -44,7 +44,8 @@ public function setUp(): void { Bootstrap::getObjectManager()->configure([ 'preferences' => [ - DynamicCollector::class => DynamicCollectorMock::class + DynamicCollector::class => DynamicCollectorMock::class, + CspNonceProvider::class => CspNonceProviderMock::class ] ]); $this->util = Bootstrap::getObjectManager()->get(InlineUtil::class); @@ -116,7 +117,7 @@ public function getTags(): array 'script', ['type' => 'text/javascript'], "\n let someVar = 25;\n document.getElementById('test').innerText = someVar;\n", - "", [ new FetchPolicy( @@ -127,8 +128,8 @@ public function getTags(): array false, false, false, - [], - ['U+SKpEef030N2YgyKKdIBIvPy8Fmd42N/JcTZgQV+DA=' => 'sha256'] + ['nonce-1234567890abcdef'], + [] ) ] ], 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 cf6287ed5b4e..e8e1365489ab 100644 --- a/dev/tests/integration/testsuite/Magento/Csp/Model/Collector/ConfigCollectorTest.php +++ b/dev/tests/integration/testsuite/Magento/Csp/Model/Collector/ConfigCollectorTest.php @@ -12,6 +12,7 @@ use Magento\Csp\Model\Policy\FlagPolicy; use Magento\Csp\Model\Policy\PluginTypesPolicy; use Magento\Csp\Model\Policy\SandboxPolicy; +use Magento\Framework\App\RequestInterface; use PHPUnit\Framework\TestCase; use Magento\TestFramework\Helper\Bootstrap; @@ -25,12 +26,18 @@ class ConfigCollectorTest extends TestCase */ private $collector; + /** + * @var RequestInterface + */ + private $request; + /** * @inheritDoc */ protected function setUp(): void { $this->collector = Bootstrap::getObjectManager()->get(ConfigCollector::class); + $this->request = Bootstrap::getObjectManager()->get(RequestInterface::class); } /** @@ -68,7 +75,7 @@ private function getExpectedPolicies(): array 'manifest-src' => new FetchPolicy('manifest-src', false, [], [], true), 'media-src' => new FetchPolicy('media-src', false, [], [], true), 'object-src' => new FetchPolicy('object-src', false, [], [], true), - 'script-src' => new FetchPolicy('script-src', false, [], [], true, false, false, [], [], false, true), + 'script-src' => new FetchPolicy('script-src', false, [], [], true, true, true, [], [], false, true), 'style-src' => new FetchPolicy('style-src', false, [], [], true), 'base-uri' => new FetchPolicy('base-uri', false, [], [], true), 'plugin-types' => new PluginTypesPolicy( @@ -172,11 +179,18 @@ private function getExpectedPolicies(): array * @magentoConfigFixture default_store csp/policies/storefront/mixed_content/policy_id block-all-mixed-content * @magentoConfigFixture default_store csp/policies/storefront/base/policy_id base-uri * @magentoConfigFixture default_store csp/policies/storefront/base/inline 0 + * @magentoConfigFixture default_store csp/policies/storefront_checkout_index_index/scripts/policy_id script-src + * @magentoConfigFixture default_store csp/policies/storefront_checkout_index_index/scripts/self 1 + * @magentoConfigFixture default_store csp/policies/storefront_checkout_index_index/scripts/inline 1 + * @magentoConfigFixture default_store csp/policies/storefront_checkout_index_index/scripts/eval 1 * @magentoConfigFixture default_store csp/policies/storefront/upgrade/policy_id upgrade-insecure-requests * @return void */ public function testCollecting(): void { + $this->request->setRouteName('checkout'); + $this->request->setControllerName('index'); + $this->request->setActionName('index'); $policies = $this->collector->collect([new FlagPolicy('upgrade-insecure-requests')]); $expectedPolicies = $this->getExpectedPolicies(); $this->assertNotEmpty($policies); diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagement/CreateAccountTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagement/CreateAccountTest.php index bd2c26e449d7..8b1f393f00ee 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagement/CreateAccountTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagement/CreateAccountTest.php @@ -421,6 +421,8 @@ public function testCreateNewCustomerWithPasswordHashWithNotAllowedCountry(): vo $customerData = $this->customerRepository->getById($customerId); $customerData->getAddresses()[1]->setRegion(null)->setCountryId($allowedCountryIdForSecondWebsite) ->setRegionId(null); + $customerData->getAddresses()[1]->setIsDefaultBilling(true); + $customerData->getAddresses()[1]->setIsDefaultShipping(true); $customerData->setStoreId($store->getId())->setWebsiteId($store->getWebsiteId())->setId(null); $password = $this->random->getRandomString(8); $passwordHash = $this->encryptor->getHash($password, true); diff --git a/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagementTest.php b/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagementTest.php index de4a592f46c9..b7c2dea1b5e0 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagementTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Model/AccountManagementTest.php @@ -9,6 +9,7 @@ use Magento\Customer\Api\AccountManagementInterface; use Magento\Customer\Api\AddressRepositoryInterface; use Magento\Customer\Api\Data\AddressInterface; +use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\Exception\InputException; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Exception\State\ExpiredException; @@ -16,6 +17,7 @@ use Magento\Framework\Session\SessionManagerInterface; use Magento\Framework\Stdlib\DateTime; use Magento\Framework\Url as UrlBuilder; +use Magento\Store\Model\ScopeInterface; use Magento\Store\Model\StoreManagerInterface; use Magento\TestFramework\Helper\Bootstrap; @@ -331,7 +333,7 @@ public function testValidateResetPasswordLinkTokenExpired() public function testValidateResetPasswordLinkTokenInvalid() { $resetToken = 'lsdj579slkj5987slkj595lkj'; - $invalidToken = 0; + $invalidToken = '0'; $this->setResetPasswordData($resetToken, 'Y-m-d H:i:s'); try { $this->accountManagement->validateResetPasswordLinkToken(1, $invalidToken); @@ -481,7 +483,7 @@ public function testResetPasswordTokenExpired() public function testResetPasswordTokenInvalid() { $resetToken = 'lsdj579slkj5987slkj595lkj'; - $invalidToken = 0; + $invalidToken = '0'; $password = 'new_Password123'; $this->setResetPasswordData($resetToken, 'Y-m-d H:i:s'); @@ -604,7 +606,18 @@ public function testResendConfirmationNotNeeded() */ public function testIsEmailAvailable() { - $this->assertFalse($this->accountManagement->isEmailAvailable('customer@example.com', 1)); + $scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); + $guestLoginConfig = $scopeConfig->getValue( + AccountManagement::GUEST_CHECKOUT_LOGIN_OPTION_SYS_CONFIG, + ScopeInterface::SCOPE_WEBSITE, + 1 + ); + + if (!$guestLoginConfig) { + $this->assertTrue($this->accountManagement->isEmailAvailable('customer@example.com', 1)); + } else { + $this->assertFalse($this->accountManagement->isEmailAvailable('customer@example.com', 1)); + } } /** @@ -612,7 +625,18 @@ public function testIsEmailAvailable() */ public function testIsEmailAvailableNoWebsiteSpecified() { - $this->assertFalse($this->accountManagement->isEmailAvailable('customer@example.com')); + $scopeConfig = $this->objectManager->get(ScopeConfigInterface::class); + $guestLoginConfig = $scopeConfig->getValue( + AccountManagement::GUEST_CHECKOUT_LOGIN_OPTION_SYS_CONFIG, + ScopeInterface::SCOPE_WEBSITE, + 1 + ); + + if (!$guestLoginConfig) { + $this->assertTrue($this->accountManagement->isEmailAvailable('customer@example.com')); + } else { + $this->assertFalse($this->accountManagement->isEmailAvailable('customer@example.com')); + } } /** diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Element/AbstractBlockTest.php b/dev/tests/integration/testsuite/Magento/Framework/View/Element/AbstractBlockTest.php index f584b8f7cfcd..d886a9189502 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/View/Element/AbstractBlockTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/View/Element/AbstractBlockTest.php @@ -26,6 +26,9 @@ class AbstractBlockTest extends \PHPUnit\Framework\TestCase */ protected $_layout = null; + /** + * @var array + */ protected static $_mocks = []; /** @@ -573,7 +576,7 @@ public function testGetCacheKey() $this->assertNotEquals($name, $key); $block->setCacheKey('key'); - $this->assertEquals(AbstractBlock::CACHE_KEY_PREFIX . 'key', $block->getCacheKey()); + $this->assertEquals(AbstractBlock::CUSTOM_CACHE_KEY_PREFIX . 'key', $block->getCacheKey()); } /** diff --git a/dev/tests/integration/testsuite/Magento/Newsletter/Controller/Subscriber/NewActionTest.php b/dev/tests/integration/testsuite/Magento/Newsletter/Controller/Subscriber/NewActionTest.php index fc1aad57e57e..00445aa6978b 100644 --- a/dev/tests/integration/testsuite/Magento/Newsletter/Controller/Subscriber/NewActionTest.php +++ b/dev/tests/integration/testsuite/Magento/Newsletter/Controller/Subscriber/NewActionTest.php @@ -8,11 +8,14 @@ namespace Magento\Newsletter\Controller\Subscriber; use Magento\Customer\Api\CustomerRepositoryInterface; +use Magento\Customer\Model\AccountManagement; use Magento\Customer\Model\Session; use Magento\Customer\Model\Url; +use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\App\Request\Http as HttpRequest; use Magento\Newsletter\Model\ResourceModel\Subscriber as SubscriberResource; use Magento\Newsletter\Model\ResourceModel\Subscriber\CollectionFactory; +use Magento\Store\Model\ScopeInterface; use Magento\TestFramework\TestCase\AbstractController; use Laminas\Stdlib\Parameters; @@ -205,8 +208,18 @@ public function testWithEmailAssignedToAnotherCustomer(): void $this->session->loginById(1); $this->prepareRequest('customer2@search.example.com'); $this->dispatch('newsletter/subscriber/new'); + $scopeConfig = $this->_objectManager->get(ScopeConfigInterface::class); + $guestLoginConfig = $scopeConfig->getValue( + AccountManagement::GUEST_CHECKOUT_LOGIN_OPTION_SYS_CONFIG, + ScopeInterface::SCOPE_WEBSITE, + 1 + ); - $this->performAsserts('This email address is already assigned to another user.'); + if ($guestLoginConfig) { + $this->performAsserts('This email address is already assigned to another user.'); + } else { + $this->performAsserts('This email address is already subscribed.'); + } } /** diff --git a/dev/tests/integration/testsuite/Magento/Quote/Model/Quote/AddressTest.php b/dev/tests/integration/testsuite/Magento/Quote/Model/Quote/AddressTest.php index 41300fbd8175..1ea4e7a2ddf7 100644 --- a/dev/tests/integration/testsuite/Magento/Quote/Model/Quote/AddressTest.php +++ b/dev/tests/integration/testsuite/Magento/Quote/Model/Quote/AddressTest.php @@ -172,7 +172,7 @@ public function testSameAsBillingWhenCustomerHasNoDefaultShippingAddress($unsetI /** @var AddressRepositoryInterface $addressRepository */ $addressRepository = Bootstrap::getObjectManager() ->create(AddressRepositoryInterface::class); - $this->_customer->setDefaultShipping(-1) + $this->_customer->setDefaultShipping(1) ->setAddresses( [ $addressRepository->getById($this->_address->getId()), @@ -211,7 +211,7 @@ public function testSameAsBillingWhenCustomerHasDefaultShippingAddress() /** @var AddressRepositoryInterface $addressRepository */ $addressRepository = Bootstrap::getObjectManager() ->create(AddressRepositoryInterface::class); - $this->_customer->setDefaultShipping(2) + $this->_customer->setDefaultShipping(1) ->setAddresses([$addressRepository->getById($this->_address->getId())]); $this->_customer = $this->customerRepository->save($this->_customer); // we should save the customer data in order to be able to use it diff --git a/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteManagementTest.php b/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteManagementTest.php index 9ebf3e98da69..a6b7a42bc5a6 100644 --- a/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteManagementTest.php +++ b/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteManagementTest.php @@ -34,6 +34,7 @@ * * @see \Magento\Quote\Model\QuoteManagement * @magentoDbIsolation enabled + * @magentoAppIsolation enabled * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class QuoteManagementTest extends TestCase @@ -196,7 +197,6 @@ public function testSubmitWithDeletedItem(): void $this->cartManagement->placeOrder($quote->getId()); } - /** * Tries to create order with product that has child items and one of them * was deleted when item data check is disabled on quote load. @@ -237,7 +237,11 @@ public function testSubmitWithItemOutOfStockWithDisabledInventoryCheck(): void { $this->makeProductOutOfStock('simple'); $quote = $this->getQuoteByReservedOrderId->execute('test01'); - $this->expectExceptionObject(new LocalizedException(__('The shipping method is missing. Select the shipping method and try again.'))); + $this->expectExceptionObject( + new LocalizedException( + __('The shipping method is missing. Select the shipping method and try again.') + ) + ); $this->cartManagement->placeOrder($quote->getId()); } diff --git a/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteTest.php b/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteTest.php index 7bda40c44062..00a8307c126a 100644 --- a/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteTest.php +++ b/dev/tests/integration/testsuite/Magento/Quote/Model/QuoteTest.php @@ -32,7 +32,7 @@ * Tests for quote model. * * @see \Magento\Quote\Model\Quote - * + * @magentoAppIsolation enabled * @magentoDbIsolation enabled * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ diff --git a/dev/tests/integration/testsuite/Magento/Quote/Model/ShippingMethodManagementTest.php b/dev/tests/integration/testsuite/Magento/Quote/Model/ShippingMethodManagementTest.php index e938945f2c41..3479201179d7 100644 --- a/dev/tests/integration/testsuite/Magento/Quote/Model/ShippingMethodManagementTest.php +++ b/dev/tests/integration/testsuite/Magento/Quote/Model/ShippingMethodManagementTest.php @@ -32,6 +32,7 @@ use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\Quote\Model\GetQuoteByReservedOrderId; use PHPUnit\Framework\TestCase; +use Magento\Customer\Model\Session; /** * Test for shipping methods management @@ -319,10 +320,16 @@ public function testEstimateByAddressWithInclExclTaxAndVATGroup() $this->changeCustomerAddress($customer->getDefaultShipping()); $quote = $this->objectManager->get(GetQuoteByReservedOrderId::class)->execute('test01'); + $addressRepository = $this->objectManager->get(AddressRepositoryInterface::class); + $address = $addressRepository->getById(1); + $address->setIsDefaultShipping(true); + $customer->setAddresses([$address]); + $customerSession = $this->objectManager->get(Session::class); + $customerSession->loginById($customer->getId()); /** @var ShippingMethodManagementInterface $shippingEstimation */ $shippingEstimation = $this->objectManager->get(ShippingMethodManagementInterface::class); - $result = $shippingEstimation->estimateByAddressId($quote->getId(), $customer->getDefaultShipping()); + $result = $shippingEstimation->estimateByAddressId($quote->getId(), (int)$customer->getDefaultShipping()); $this->assertEquals(6.05, $result[0]->getPriceInclTax()); $this->assertEquals(5.0, $result[0]->getPriceExclTax()); diff --git a/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/SaveTest.php b/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/SaveTest.php index bbd6d27d688d..d0b403852139 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/SaveTest.php +++ b/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/SaveTest.php @@ -21,6 +21,11 @@ */ class SaveTest extends AbstractCreditmemoControllerTest { + /** + * @var string + */ + protected $resource = 'Magento_Sales::creditmemo'; + /** * @var string */ diff --git a/dev/tests/integration/testsuite/Magento/Sales/Helper/AdminTest.php b/dev/tests/integration/testsuite/Magento/Sales/Helper/AdminTest.php index 7b41f9890d74..17f402faf2c5 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/Helper/AdminTest.php +++ b/dev/tests/integration/testsuite/Magento/Sales/Helper/AdminTest.php @@ -76,7 +76,7 @@ public function escapeHtmlWithLinksDataProvider(): array ], [ 'Foo', - 'Foo', + 'Foo', 'allowedTags' => ['a'], ], [ @@ -86,7 +86,7 @@ public function escapeHtmlWithLinksDataProvider(): array ], [ "Foo", - 'Foo', + 'Foo', 'allowedTags' => ['a'], ], [ diff --git a/dev/tests/integration/testsuite/Magento/SalesRule/Model/Rule/Action/Discount/CartFixedTest.php b/dev/tests/integration/testsuite/Magento/SalesRule/Model/Rule/Action/Discount/CartFixedTest.php index 2dbba6660486..30f7c60d5f49 100644 --- a/dev/tests/integration/testsuite/Magento/SalesRule/Model/Rule/Action/Discount/CartFixedTest.php +++ b/dev/tests/integration/testsuite/Magento/SalesRule/Model/Rule/Action/Discount/CartFixedTest.php @@ -47,6 +47,11 @@ */ class CartFixedTest extends TestCase { + /** + * @var float + */ + private const EPSILON = 0.0000000001; + /** * @var GuestCartManagementInterface */ @@ -521,11 +526,11 @@ public function testDiscountsWhenByPercentRuleAppliedFirstAndCartFixedRuleSecond $item = array_shift($items); $this->assertEquals('simple1', $item->getSku()); $this->assertEquals(5.99, $item->getPrice()); - $this->assertEquals($expectedDiscounts[$item->getSku()], $item->getDiscountAmount()); + $this->assertEqualsWithDelta($expectedDiscounts[$item->getSku()], $item->getDiscountAmount(), self::EPSILON); $item = array_shift($items); $this->assertEquals('simple2', $item->getSku()); $this->assertEquals(15.99, $item->getPrice()); - $this->assertEquals($expectedDiscounts[$item->getSku()], $item->getDiscountAmount()); + $this->assertEqualsWithDelta($expectedDiscounts[$item->getSku()], $item->getDiscountAmount(), self::EPSILON); } public function discountByPercentDataProvider() diff --git a/dev/tests/integration/testsuite/Magento/Shipping/Controller/Adminhtml/Order/Shipment/SaveTest.php b/dev/tests/integration/testsuite/Magento/Shipping/Controller/Adminhtml/Order/Shipment/SaveTest.php index e3374064aa3c..043ba86dce3e 100644 --- a/dev/tests/integration/testsuite/Magento/Shipping/Controller/Adminhtml/Order/Shipment/SaveTest.php +++ b/dev/tests/integration/testsuite/Magento/Shipping/Controller/Adminhtml/Order/Shipment/SaveTest.php @@ -18,6 +18,11 @@ */ class SaveTest extends AbstractShipmentControllerTest { + /** + * @var string + */ + protected $resource = 'Magento_Sales::ship'; + /** * @var string */ @@ -105,8 +110,7 @@ private function prepareRequest(array $params = []) ] ); - $data = $params ?? []; - $this->getRequest()->setPostValue($data); + $this->getRequest()->setPostValue($params); return $order; } diff --git a/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/TaxTest.php b/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/TaxTest.php index a119b6259b5f..f3b43d9f2cca 100644 --- a/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/TaxTest.php +++ b/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/TaxTest.php @@ -23,6 +23,11 @@ */ class TaxTest extends \Magento\TestFramework\Indexer\TestCase { + /** + * @var float + */ + private const EPSILON = 0.0000000001; + /** * Utility object for setting up tax rates, tax classes and tax rules * @@ -176,7 +181,7 @@ public function testFullDiscountWithDeltaRoundingFix() protected function verifyItem($item, $expectedItemData) { foreach ($expectedItemData as $key => $value) { - $this->assertEquals($value, $item->getData($key), 'item ' . $key . ' is incorrect'); + $this->assertEqualsWithDelta($value, $item->getData($key), self::EPSILON, 'item ' . $key . ' is incorrect'); } return $this; @@ -247,7 +252,12 @@ protected function verifyQuoteAddress($quoteAddress, $expectedAddressData) if ($key == 'applied_taxes') { $this->verifyAppliedTaxes($quoteAddress->getAppliedTaxes(), $value); } else { - $this->assertEquals($value, $quoteAddress->getData($key), 'Quote address ' . $key . ' is incorrect'); + $this->assertEqualsWithDelta( + $value, + $quoteAddress->getData($key), + self::EPSILON, + 'Quote address ' . $key . ' is incorrect' + ); } } diff --git a/dev/tests/integration/testsuite/Magento/Tax/Model/TaxCalculationTest.php b/dev/tests/integration/testsuite/Magento/Tax/Model/TaxCalculationTest.php index 604a444883a2..fde67cc7c209 100644 --- a/dev/tests/integration/testsuite/Magento/Tax/Model/TaxCalculationTest.php +++ b/dev/tests/integration/testsuite/Magento/Tax/Model/TaxCalculationTest.php @@ -16,15 +16,16 @@ class TaxCalculationTest extends \PHPUnit\Framework\TestCase { /** - * Object Manager - * + * @var float + */ + private const EPSILON = 0.0000000001; + + /** * @var \Magento\Framework\ObjectManagerInterface */ private $objectManager; /** - * Tax calculation service - * * @var \Magento\Tax\Api\TaxCalculationInterface */ private $taxCalculationService; @@ -108,7 +109,7 @@ public function testCalculateTaxUnitBased($quoteDetailsData, $expected) ); $taxDetails = $this->taxCalculationService->calculateTax($quoteDetails, 1); - $this->assertEquals($expected, $this->convertObjectToArray($taxDetails)); + $this->assertEqualsWithDelta($expected, $this->convertObjectToArray($taxDetails), self::EPSILON); } /** @@ -1286,7 +1287,7 @@ public function testCalculateTaxRowBased($quoteDetailsData, $expectedTaxDetails) $taxDetails = $this->taxCalculationService->calculateTax($quoteDetails); - $this->assertEquals($expectedTaxDetails, $this->convertObjectToArray($taxDetails)); + $this->assertEqualsWithDelta($expectedTaxDetails, $this->convertObjectToArray($taxDetails), self::EPSILON); } /** @@ -2387,7 +2388,11 @@ public function testMultiRulesRowBased($quoteDetailsData, $expectedTaxDetails) $taxDetails = $this->taxCalculationService->calculateTax($quoteDetails); - $this->assertEquals($expectedTaxDetails, $this->convertObjectToArray($taxDetails)); + $this->assertEqualsWithDelta( + $expectedTaxDetails, + $this->convertObjectToArray($taxDetails), + self::EPSILON + ); } /** @@ -2424,7 +2429,7 @@ public function testMultiRulesTotalBased($quoteDetailsData, $expectedTaxDetails) $taxDetails = $this->taxCalculationService->calculateTax($quoteDetails); - $this->assertEquals($expectedTaxDetails, $this->convertObjectToArray($taxDetails)); + $this->assertEqualsWithDelta($expectedTaxDetails, $this->convertObjectToArray($taxDetails), self::EPSILON); } /** @@ -2471,7 +2476,7 @@ public function testMultiRulesUnitBased($quoteDetailsData, $expectedTaxDetails) $taxDetails = $this->taxCalculationService->calculateTax($quoteDetails); - $this->assertEquals($expectedTaxDetails, $this->convertObjectToArray($taxDetails)); + $this->assertEqualsWithDelta($expectedTaxDetails, $this->convertObjectToArray($taxDetails), self::EPSILON); } /** diff --git a/dev/tests/integration/testsuite/Magento/Test/Integrity/Magento/Payment/MethodsTest.php b/dev/tests/integration/testsuite/Magento/Test/Integrity/Magento/Payment/MethodsTest.php index eb5c66cc9c77..773b90b8ba2e 100644 --- a/dev/tests/integration/testsuite/Magento/Test/Integrity/Magento/Payment/MethodsTest.php +++ b/dev/tests/integration/testsuite/Magento/Test/Integrity/Magento/Payment/MethodsTest.php @@ -26,7 +26,16 @@ class MethodsTest extends \PHPUnit\Framework\TestCase */ public function testPaymentMethod($code, $methodClass) { - if (in_array($code, ['free', 'substitution', 'vault', 'payflowpro_cc_vault', 'fake_vault'])) { + $skipBlockTemplates = [ + 'free', + 'substitution', + 'vault', + 'payflowpro_cc_vault', + 'fake_vault', + 'braintree_cc_vault', + 'braintree_paypal_vault' + ]; + if (in_array($code, $skipBlockTemplates)) { return; } Bootstrap::getObjectManager()->configure($this->getTestConfiguration()); diff --git a/dev/tests/integration/testsuite/Magento/Ups/Model/CarrierTest.php b/dev/tests/integration/testsuite/Magento/Ups/Model/CarrierTest.php index 0cedcca254f8..5758d523876b 100644 --- a/dev/tests/integration/testsuite/Magento/Ups/Model/CarrierTest.php +++ b/dev/tests/integration/testsuite/Magento/Ups/Model/CarrierTest.php @@ -14,13 +14,13 @@ use Magento\Framework\HTTP\AsyncClient\Response; use Magento\Framework\HTTP\AsyncClientInterface; use Magento\Quote\Model\Quote\Address\RateRequest; +use Magento\Quote\Model\Quote\Address\RateRequestFactory; use Magento\Quote\Model\Quote\Address\RateResult\Error; +use Magento\Shipping\Model\Shipment\Request; use Magento\TestFramework\Helper\Bootstrap; -use Magento\Quote\Model\Quote\Address\RateRequestFactory; use Magento\TestFramework\HTTP\AsyncClientInterfaceMock; -use PHPUnit\Framework\TestCase; use PHPUnit\Framework\MockObject\MockObject; -use Magento\Shipping\Model\Shipment\Request; +use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; /** @@ -113,29 +113,54 @@ public function testGetShipConfirmUrlLive() } /** - * Collect free rates. + * Collect rates for UPS Ground method. * * @magentoConfigFixture current_store carriers/ups/active 1 - * @magentoConfigFixture current_store carriers/ups/type UPS - * @magentoConfigFixture current_store carriers/ups/allowed_methods 1DA,GND - * @magentoConfigFixture current_store carriers/ups/free_method GND + * @magentoConfigFixture current_store carriers/ups/type UPS_XML + * @magentoConfigFixture current_store carriers/ups/allowed_methods 03 + * @magentoConfigFixture current_store carriers/ups/free_method 03 + * @magentoConfigFixture default_store carriers/ups/shipper_number 12345 + * @magentoConfigFixture default_store carriers/ups/origin_shipment Shipments Originating in the United States + * @magentoConfigFixture default_store carriers/ups/username user + * @magentoConfigFixture default_store carriers/ups/password pass + * @magentoConfigFixture default_store carriers/ups/access_license_number acn + * @magentoConfigFixture default_store carriers/ups/debug 1 + * @magentoConfigFixture default_store currency/options/allow USD,EUR + * @magentoConfigFixture default_store currency/options/base USD */ public function testCollectFreeRates() { - $rateRequest = Bootstrap::getObjectManager()->get(RateRequestFactory::class)->create(); - $rateRequest->setDestCountryId('US'); - $rateRequest->setDestRegionId('CA'); - $rateRequest->setDestPostcode('90001'); - $rateRequest->setPackageQty(1); - $rateRequest->setPackageWeight(1); - $rateRequest->setFreeMethodWeight(0); - $rateRequest->setLimitCarrier($this->carrier::CODE); - $rateRequest->setFreeShipping(true); - $rateResult = $this->carrier->collectRates($rateRequest); - $result = $rateResult->asArray(); - $methods = $result[$this->carrier::CODE]['methods']; - $this->assertEquals(0, $methods['GND']['price']); - $this->assertNotEquals(0, $methods['1DA']['price']); + $request = Bootstrap::getObjectManager()->create( + RateRequest::class, + [ + 'data' => [ + 'dest_country' => 'US', + 'dest_postal' => '90001', + 'package_weight' => '1', + 'package_qty' => '1', + 'free_method_weight' => '5', + 'product' => '11', + 'action' => 'Rate', + 'unit_measure' => 'KGS', + 'free_shipping' => '1', + 'base_currency' => new DataObject(['code' => 'USD']) + ] + ] + ); + //phpcs:disable Magento2.Functions.DiscouragedFunction + $this->httpClient->nextResponses( + [ + new Response( + 200, + [], + file_get_contents(__DIR__ . "/../_files/ups_rates_response_option9.xml") + ) + ] + ); + + $rates = $this->carrier->collectRates($request)->getAllRates(); + $this->assertEquals('19.19', $rates[0]->getPrice()); + $this->assertEquals('03', $rates[0]->getMethod()); } /** @@ -181,7 +206,7 @@ public function testCollectRates(int $negotiable, int $tax, int $responseId, str new Response( 200, [], - file_get_contents(__DIR__ ."/../_files/ups_rates_response_option$responseId.xml") + file_get_contents(__DIR__ . "/../_files/ups_rates_response_option$responseId.xml") ) ] ); @@ -245,9 +270,9 @@ public function collectRatesDataProvider() public function testRequestToShipment(): void { //phpcs:disable Magento2.Functions.DiscouragedFunction - $expectedShipmentRequest = file_get_contents(__DIR__ .'/../_files/ShipmentConfirmRequest.xml'); - $shipmentResponse = file_get_contents(__DIR__ .'/../_files/ShipmentConfirmResponse.xml'); - $acceptResponse = file_get_contents(__DIR__ .'/../_files/ShipmentAcceptResponse.xml'); + $expectedShipmentRequest = file_get_contents(__DIR__ . '/../_files/ShipmentConfirmRequest.xml'); + $shipmentResponse = file_get_contents(__DIR__ . '/../_files/ShipmentConfirmResponse.xml'); + $acceptResponse = file_get_contents(__DIR__ . '/../_files/ShipmentAcceptResponse.xml'); //phpcs:enable Magento2.Functions.DiscouragedFunction $this->httpClient->nextResponses( [ diff --git a/dev/tests/integration/testsuite/Magento/Ups/_files/ups_rates_response_option9.xml b/dev/tests/integration/testsuite/Magento/Ups/_files/ups_rates_response_option9.xml new file mode 100644 index 000000000000..2e5c4bc0ddbf --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Ups/_files/ups_rates_response_option9.xml @@ -0,0 +1,299 @@ + + + + + + Rating and Service + 1.0 + + 1 + Success + + + + 12 + + Your invoice may vary from the displayed reference rates + + + LBS + + 20.0 + + + USD + 43.19 + + + USD + 0.00 + + + USD + 43.19 + + 3 + + + + USD + 43.19 + + + USD + 0.00 + + + USD + 43.19 + + 20.0 + + + LBS + + 20.0 + + + + + + 14 + + Your invoice may vary from the displayed reference rates + + + LBS + + 20.0 + + + USD + 122.34 + + + USD + 0.00 + + + USD + 122.34 + + 1 + 8:00 A.M. + + + USD + 122.34 + + + USD + 0.00 + + + USD + 122.34 + + 20.0 + + + LBS + + 20.0 + + + + + + 03 + + Your invoice may vary from the displayed reference rates + + + LBS + + 20.0 + + + USD + 19.19 + + + USD + 0.00 + + + USD + 19.19 + + + + + + USD + 19.19 + + + USD + 0.00 + + + USD + 19.19 + + 20.0 + + + LBS + + 20.0 + + + + + + 13 + + Your invoice may vary from the displayed reference rates + + + LBS + + 20.0 + + + USD + 82.24 + + + USD + 0.00 + + + USD + 82.24 + + 1 + + + + USD + 82.24 + + + USD + 0.00 + + + USD + 82.24 + + 20.0 + + + LBS + + 20.0 + + + + + + 01 + + Your invoice may vary from the displayed reference rates + + + LBS + + 20.0 + + + USD + 88.14 + + + USD + 0.00 + + + USD + 88.14 + + 1 + 10:30 A.M. + + + USD + 88.14 + + + USD + 0.00 + + + USD + 88.14 + + 20.0 + + + LBS + + 20.0 + + + + + + 02 + + Your invoice may vary from the displayed reference rates + + + LBS + + 20.0 + + + USD + 57.11 + + + USD + 0.00 + + + USD + 57.11 + + 2 + + + + USD + 57.11 + + + USD + 0.00 + + + USD + 57.11 + + 20.0 + + + LBS + + 20.0 + + + + diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/declarative_installer/constraint_modification.mariadb10427.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/declarative_installer/constraint_modification.mariadb10427.php new file mode 100644 index 000000000000..f00c9a1eb08c --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/declarative_installer/constraint_modification.mariadb10427.php @@ -0,0 +1,59 @@ + 'CREATE TABLE `auto_increment_test` ( + `int_auto_increment_with_nullable` int(10) unsigned NOT NULL AUTO_INCREMENT, + `int_disabled_auto_increment` smallint(5) unsigned DEFAULT 0, + UNIQUE KEY `AUTO_INCREMENT_TEST_INT_AUTO_INCREMENT_WITH_NULLABLE` (`int_auto_increment_with_nullable`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci', + 'reference_table' => 'CREATE TABLE `reference_table` ( + `tinyint_ref` tinyint(4) NOT NULL AUTO_INCREMENT, + `tinyint_without_padding` tinyint(4) NOT NULL DEFAULT 0, + `bigint_without_padding` bigint(20) NOT NULL DEFAULT 0, + `smallint_without_padding` smallint(6) NOT NULL DEFAULT 0, + `integer_without_padding` int(11) NOT NULL DEFAULT 0, + `smallint_with_big_padding` smallint(6) NOT NULL DEFAULT 0, + `smallint_without_default` smallint(6) DEFAULT NULL, + `int_without_unsigned` int(11) DEFAULT NULL, + `int_unsigned` int(10) unsigned DEFAULT NULL, + `bigint_default_nullable` bigint(20) unsigned DEFAULT 1, + `bigint_not_default_not_nullable` bigint(20) unsigned NOT NULL, + `smallint_ref` smallint(6) NOT NULL DEFAULT 0, + PRIMARY KEY (`tinyint_ref`,`smallint_ref`), + UNIQUE KEY `REFERENCE_TABLE_SMALLINT_REF` (`smallint_ref`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci', + 'test_table' => 'CREATE TABLE `test_table` ( + `smallint` smallint(6) DEFAULT NULL, + `tinyint` tinyint(4) DEFAULT NULL, + `bigint` bigint(20) DEFAULT 0, + `float` float(12,10) DEFAULT 0.0000000000, + `double` double(245,10) DEFAULT 11111111.1111110000, + `decimal` decimal(15,4) DEFAULT 0.0000, + `date` date DEFAULT NULL, + `timestamp` timestamp NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), + `datetime` datetime DEFAULT \'0000-00-00 00:00:00\', + `longtext` longtext DEFAULT NULL, + `mediumtext` mediumtext DEFAULT NULL, + `varchar` varchar(254) DEFAULT NULL, + `char` char(255) DEFAULT NULL, + `mediumblob` mediumblob DEFAULT NULL, + `blob` blob DEFAULT NULL, + `boolean` tinyint(1) DEFAULT NULL, + `integer_main` int(10) unsigned DEFAULT NULL, + `smallint_main` smallint(6) NOT NULL DEFAULT 0, + UNIQUE KEY `TEST_TABLE_SMALLINT_FLOAT` (`smallint`,`float`), + UNIQUE KEY `TEST_TABLE_DOUBLE` (`double`), + KEY `TEST_TABLE_TINYINT_BIGINT` (`tinyint`,`bigint`), + KEY `TEST_TABLE_SMALLINT_MAIN_REFERENCE_TABLE_SMALLINT_REF` (`smallint_main`), + KEY `FK_FB77604C299EB8612D01E4AF8D9931F2` (`integer_main`), + CONSTRAINT `FK_FB77604C299EB8612D01E4AF8D9931F2` FOREIGN KEY (`integer_main`) REFERENCES `auto_increment_test` (`int_auto_increment_with_nullable`) ON DELETE CASCADE, + CONSTRAINT `TEST_TABLE_SMALLINT_MAIN_REFERENCE_TABLE_SMALLINT_REF` FOREIGN KEY (`smallint_main`) REFERENCES `reference_table` (`smallint_ref`) ON DELETE CASCADE, + CONSTRAINT `TEST_TABLE_TINYINT_REFERENCE_TABLE_TINYINT_REF` FOREIGN KEY (`tinyint`) REFERENCES `reference_table` (`tinyint_ref`) ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci', +]; diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/declarative_installer/constraint_modification.mysql829.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/declarative_installer/constraint_modification.mysql829.php new file mode 100644 index 000000000000..65a70da8d660 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/declarative_installer/constraint_modification.mysql829.php @@ -0,0 +1,59 @@ + 'CREATE TABLE `auto_increment_test` ( + `int_auto_increment_with_nullable` int unsigned NOT NULL AUTO_INCREMENT, + `int_disabled_auto_increment` smallint unsigned DEFAULT \'0\', + UNIQUE KEY `AUTO_INCREMENT_TEST_INT_AUTO_INCREMENT_WITH_NULLABLE` (`int_auto_increment_with_nullable`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3', + 'reference_table' => 'CREATE TABLE `reference_table` ( + `tinyint_ref` tinyint NOT NULL AUTO_INCREMENT, + `tinyint_without_padding` tinyint NOT NULL DEFAULT \'0\', + `bigint_without_padding` bigint NOT NULL DEFAULT \'0\', + `smallint_without_padding` smallint NOT NULL DEFAULT \'0\', + `integer_without_padding` int NOT NULL DEFAULT \'0\', + `smallint_with_big_padding` smallint NOT NULL DEFAULT \'0\', + `smallint_without_default` smallint DEFAULT NULL, + `int_without_unsigned` int DEFAULT NULL, + `int_unsigned` int unsigned DEFAULT NULL, + `bigint_default_nullable` bigint unsigned DEFAULT \'1\', + `bigint_not_default_not_nullable` bigint unsigned NOT NULL, + `smallint_ref` smallint NOT NULL DEFAULT \'0\', + PRIMARY KEY (`tinyint_ref`,`smallint_ref`), + UNIQUE KEY `REFERENCE_TABLE_SMALLINT_REF` (`smallint_ref`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3', + 'test_table' => 'CREATE TABLE `test_table` ( + `smallint` smallint DEFAULT NULL, + `tinyint` tinyint DEFAULT NULL, + `bigint` bigint DEFAULT \'0\', + `float` float(12,10) DEFAULT \'0.0000000000\', + `double` double(245,10) DEFAULT \'11111111.1111110000\', + `decimal` decimal(15,4) DEFAULT \'0.0000\', + `date` date DEFAULT NULL, + `timestamp` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `datetime` datetime DEFAULT \'0000-00-00 00:00:00\', + `longtext` longtext, + `mediumtext` mediumtext, + `varchar` varchar(254) DEFAULT NULL, + `char` char(255) DEFAULT NULL, + `mediumblob` mediumblob, + `blob` blob, + `boolean` tinyint(1) DEFAULT NULL, + `integer_main` int unsigned DEFAULT NULL, + `smallint_main` smallint NOT NULL DEFAULT \'0\', + UNIQUE KEY `TEST_TABLE_SMALLINT_FLOAT` (`smallint`,`float`), + UNIQUE KEY `TEST_TABLE_DOUBLE` (`double`), + KEY `TEST_TABLE_TINYINT_BIGINT` (`tinyint`,`bigint`), + KEY `TEST_TABLE_SMALLINT_MAIN_REFERENCE_TABLE_SMALLINT_REF` (`smallint_main`), + KEY `FK_FB77604C299EB8612D01E4AF8D9931F2` (`integer_main`), + CONSTRAINT `FK_FB77604C299EB8612D01E4AF8D9931F2` FOREIGN KEY (`integer_main`) REFERENCES `auto_increment_test` (`int_auto_increment_with_nullable`) ON DELETE CASCADE, + CONSTRAINT `TEST_TABLE_SMALLINT_MAIN_REFERENCE_TABLE_SMALLINT_REF` FOREIGN KEY (`smallint_main`) REFERENCES `reference_table` (`smallint_ref`) ON DELETE CASCADE, + CONSTRAINT `TEST_TABLE_TINYINT_REFERENCE_TABLE_TINYINT_REF` FOREIGN KEY (`tinyint`) REFERENCES `reference_table` (`tinyint_ref`) ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3', +]; diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/declarative_installer/rollback.mariadb10427.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/declarative_installer/rollback.mariadb10427.php new file mode 100644 index 000000000000..45cb5f6938b4 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/declarative_installer/rollback.mariadb10427.php @@ -0,0 +1,27 @@ + [ + 'store' => 'CREATE TABLE `store` ( + `store_owner_id` smallint(6) DEFAULT NULL COMMENT \'Store Owner Reference\', + KEY `STORE_STORE_OWNER_ID_STORE_OWNER_OWNER_ID` (`store_owner_id`), + CONSTRAINT `STORE_STORE_OWNER_ID_STORE_OWNER_OWNER_ID` FOREIGN KEY (`store_owner_id`) REFERENCES `store_owner` (`owner_id`) ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci', + 'store_owner' => 'CREATE TABLE `store_owner` ( + `owner_id` smallint(6) NOT NULL AUTO_INCREMENT, + `store_owner_name` varchar(255) DEFAULT NULL COMMENT \'Store Owner Name\', + PRIMARY KEY (`owner_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci COMMENT=\'Store owner information\'' + ], + 'after' => [ + 'store' => 'CREATE TABLE `store` ( + `store_owner` varchar(255) DEFAULT NULL COMMENT \'Store Owner Name\' +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci' + ] +]; diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/declarative_installer/rollback.mysql829.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/declarative_installer/rollback.mysql829.php new file mode 100644 index 000000000000..57b70edd9e3f --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/declarative_installer/rollback.mysql829.php @@ -0,0 +1,27 @@ + [ + 'store' => 'CREATE TABLE `store` ( + `store_owner_id` smallint DEFAULT NULL COMMENT \'Store Owner Reference\', + KEY `STORE_STORE_OWNER_ID_STORE_OWNER_OWNER_ID` (`store_owner_id`), + CONSTRAINT `STORE_STORE_OWNER_ID_STORE_OWNER_OWNER_ID` FOREIGN KEY (`store_owner_id`) REFERENCES `store_owner` (`owner_id`) ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3', + 'store_owner' => 'CREATE TABLE `store_owner` ( + `owner_id` smallint NOT NULL AUTO_INCREMENT, + `store_owner_name` varchar(255) DEFAULT NULL COMMENT \'Store Owner Name\', + PRIMARY KEY (`owner_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COMMENT=\'Store owner information\'' + ], + 'after' => [ + 'store' => 'CREATE TABLE `store` ( + `store_owner` varchar(255) DEFAULT NULL COMMENT \'Store Owner Name\' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3' + ] +]; diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/declarative_installer/table_removal.mariadb10427.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/declarative_installer/table_removal.mariadb10427.php new file mode 100644 index 000000000000..bc469f23f6e2 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/declarative_installer/table_removal.mariadb10427.php @@ -0,0 +1,14 @@ + 'CREATE TABLE `auto_increment_test` ( + `int_auto_increment_with_nullable` int(10) unsigned NOT NULL AUTO_INCREMENT, + `int_disabled_auto_increment` smallint(5) unsigned DEFAULT 0, + UNIQUE KEY `AUTO_INCREMENT_TEST_INT_AUTO_INCREMENT_WITH_NULLABLE` (`int_auto_increment_with_nullable`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci' +]; diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/declarative_installer/table_removal.mysql829.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/declarative_installer/table_removal.mysql829.php new file mode 100644 index 000000000000..9ca6fcbc2275 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/declarative_installer/table_removal.mysql829.php @@ -0,0 +1,14 @@ + 'CREATE TABLE `auto_increment_test` ( + `int_auto_increment_with_nullable` int unsigned NOT NULL AUTO_INCREMENT, + `int_disabled_auto_increment` smallint unsigned DEFAULT \'0\', + UNIQUE KEY `AUTO_INCREMENT_TEST_INT_AUTO_INCREMENT_WITH_NULLABLE` (`int_auto_increment_with_nullable`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3' +]; diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/declarative_installer/table_rename.mariadb10427.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/declarative_installer/table_rename.mariadb10427.php new file mode 100644 index 000000000000..3c62923cf256 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/declarative_installer/table_rename.mariadb10427.php @@ -0,0 +1,15 @@ + 'CREATE TABLE `some_table` ( + `some_column` varchar(255) DEFAULT NULL COMMENT \'Some Column Name\' +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci', + 'after' => 'CREATE TABLE `some_table_renamed` ( + `some_column` varchar(255) DEFAULT NULL COMMENT \'Some Column Name\' +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci', +]; diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/declarative_installer/table_rename.mysql829.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/declarative_installer/table_rename.mysql829.php new file mode 100644 index 000000000000..cb8f53d499a5 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/declarative_installer/table_rename.mysql829.php @@ -0,0 +1,15 @@ + 'CREATE TABLE `some_table` ( + `some_column` varchar(255) DEFAULT NULL COMMENT \'Some Column Name\' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3', + 'after' => 'CREATE TABLE `some_table_renamed` ( + `some_column` varchar(255) DEFAULT NULL COMMENT \'Some Column Name\' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3', +]; diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/dry_run_log.mysql829.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/dry_run_log.mysql829.php new file mode 100644 index 000000000000..4d4922107431 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/dry_run_log.mysql829.php @@ -0,0 +1,58 @@ + 'CREATE TABLE `test_table_one` ( + `smallint` smallint(6) NOT NULL AUTO_INCREMENT, + `varchar` varchar(254) DEFAULT NULL, + PRIMARY KEY (`smallint`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci', + 'test_table_two' => 'CREATE TABLE `test_table_two` ( + `smallint` smallint(6) NOT NULL AUTO_INCREMENT, + `varchar` varchar(254) DEFAULT NULL, + PRIMARY KEY (`smallint`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci', + 'reference_table' => 'CREATE TABLE `reference_table` ( + `tinyint_ref` tinyint(4) NOT NULL AUTO_INCREMENT, + `tinyint_without_padding` tinyint(4) NOT NULL DEFAULT 0, + `bigint_without_padding` bigint(20) NOT NULL DEFAULT 0, + `smallint_without_padding` smallint(6) NOT NULL DEFAULT 0, + `integer_without_padding` int(11) NOT NULL DEFAULT 0, + `smallint_with_big_padding` smallint(6) NOT NULL DEFAULT 0, + `smallint_without_default` smallint(6) DEFAULT NULL, + `int_without_unsigned` int(11) DEFAULT NULL, + `int_unsigned` int(10) unsigned DEFAULT NULL, + `bigint_default_nullable` bigint(20) unsigned DEFAULT 1, + `bigint_not_default_not_nullable` bigint(20) unsigned NOT NULL, + PRIMARY KEY (`tinyint_ref`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci', + 'auto_increment_test' => 'CREATE TABLE `auto_increment_test` ( + `int_auto_increment_with_nullable` int(10) unsigned NOT NULL AUTO_INCREMENT, + `int_disabled_auto_increment` smallint(5) unsigned DEFAULT 0, + UNIQUE KEY `AUTO_INCREMENT_TEST_INT_AUTO_INCREMENT_WITH_NULLABLE` (`int_auto_increment_with_nullable`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci' +]; diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule2/fixture/shards.mysql829.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule2/fixture/shards.mysql829.php new file mode 100644 index 000000000000..2507abeef299 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule2/fixture/shards.mysql829.php @@ -0,0 +1,38 @@ + 'CREATE TABLE `test_table_one` ( + `smallint` smallint NOT NULL AUTO_INCREMENT, + `varchar` varchar(254) DEFAULT NULL, + PRIMARY KEY (`smallint`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3', + 'test_table_two' => 'CREATE TABLE `test_table_two` ( + `smallint` smallint NOT NULL AUTO_INCREMENT, + `varchar` varchar(254) DEFAULT NULL, + PRIMARY KEY (`smallint`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3', + 'reference_table' => 'CREATE TABLE `reference_table` ( + `tinyint_ref` tinyint NOT NULL AUTO_INCREMENT, + `tinyint_without_padding` tinyint NOT NULL DEFAULT \'0\', + `bigint_without_padding` bigint NOT NULL DEFAULT \'0\', + `smallint_without_padding` smallint NOT NULL DEFAULT \'0\', + `integer_without_padding` int NOT NULL DEFAULT \'0\', + `smallint_with_big_padding` smallint NOT NULL DEFAULT \'0\', + `smallint_without_default` smallint DEFAULT NULL, + `int_without_unsigned` int DEFAULT NULL, + `int_unsigned` int unsigned DEFAULT NULL, + `bigint_default_nullable` bigint unsigned DEFAULT \'1\', + `bigint_not_default_not_nullable` bigint unsigned NOT NULL, + PRIMARY KEY (`tinyint_ref`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3', + 'auto_increment_test' => 'CREATE TABLE `auto_increment_test` ( + `int_auto_increment_with_nullable` int unsigned NOT NULL AUTO_INCREMENT, + `int_disabled_auto_increment` smallint unsigned DEFAULT \'0\', + UNIQUE KEY `AUTO_INCREMENT_TEST_INT_AUTO_INCREMENT_WITH_NULLABLE` (`int_auto_increment_with_nullable`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3' +]; diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule9/fixture/declarative_installer/disabling_tables.mariadb10427.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule9/fixture/declarative_installer/disabling_tables.mariadb10427.php new file mode 100644 index 000000000000..bc469f23f6e2 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule9/fixture/declarative_installer/disabling_tables.mariadb10427.php @@ -0,0 +1,14 @@ + 'CREATE TABLE `auto_increment_test` ( + `int_auto_increment_with_nullable` int(10) unsigned NOT NULL AUTO_INCREMENT, + `int_disabled_auto_increment` smallint(5) unsigned DEFAULT 0, + UNIQUE KEY `AUTO_INCREMENT_TEST_INT_AUTO_INCREMENT_WITH_NULLABLE` (`int_auto_increment_with_nullable`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci' +]; diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule9/fixture/declarative_installer/disabling_tables.mysql829.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule9/fixture/declarative_installer/disabling_tables.mysql829.php new file mode 100644 index 000000000000..9ca6fcbc2275 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule9/fixture/declarative_installer/disabling_tables.mysql829.php @@ -0,0 +1,14 @@ + 'CREATE TABLE `auto_increment_test` ( + `int_auto_increment_with_nullable` int unsigned NOT NULL AUTO_INCREMENT, + `int_disabled_auto_increment` smallint unsigned DEFAULT \'0\', + UNIQUE KEY `AUTO_INCREMENT_TEST_INT_AUTO_INCREMENT_WITH_NULLABLE` (`int_auto_increment_with_nullable`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3' +]; diff --git a/dev/tests/setup-integration/framework/Magento/TestFramework/Annotation/DataProviderFromFile.php b/dev/tests/setup-integration/framework/Magento/TestFramework/Annotation/DataProviderFromFile.php index b7c45b628b44..c43c4f483531 100644 --- a/dev/tests/setup-integration/framework/Magento/TestFramework/Annotation/DataProviderFromFile.php +++ b/dev/tests/setup-integration/framework/Magento/TestFramework/Annotation/DataProviderFromFile.php @@ -20,14 +20,16 @@ class DataProviderFromFile /** * @var string */ - const FALLBACK_VALUE = 'default'; + public const FALLBACK_VALUE = 'default'; /** * @var array */ - const POSSIBLE_SUFFIXES = [ + public const POSSIBLE_SUFFIXES = [ SqlVersionProvider::MYSQL_8_0_VERSION => 'mysql8', SqlVersionProvider::MARIA_DB_10_VERSION => 'mariadb10', + SqlVersionProvider::MYSQL_8_0_29_VERSION => 'mysql829', + SqlVersionProvider::MARIA_DB_10_4_27_VERSION => 'mariadb10427' ]; /** diff --git a/dev/tests/setup-integration/framework/Magento/TestFramework/TestCase/SetupTestCase.php b/dev/tests/setup-integration/framework/Magento/TestFramework/TestCase/SetupTestCase.php index 95f7e5b46316..6db21ba5b591 100644 --- a/dev/tests/setup-integration/framework/Magento/TestFramework/TestCase/SetupTestCase.php +++ b/dev/tests/setup-integration/framework/Magento/TestFramework/TestCase/SetupTestCase.php @@ -7,10 +7,12 @@ namespace Magento\TestFramework\TestCase; +use Magento\Framework\App\ResourceConnection; use Magento\Framework\DB\Adapter\ConnectionException; use Magento\Framework\DB\Adapter\SqlVersionProvider; use Magento\TestFramework\Annotation\DataProviderFromFile; use Magento\TestFramework\Helper\Bootstrap; +use Zend_Db_Statement_Exception; /** * Instance of Setup test case. Used in order to tweak dataProviders functionality. @@ -32,17 +34,25 @@ class SetupTestCase extends \PHPUnit\Framework\TestCase implements MutableDataIn */ private $sqlVersionProvider; + /** + * @var ResourceConnection + */ + private ResourceConnection $resourceConnection; + /** * @inheritDoc */ public function __construct( $name = null, array $data = [], - $dataName = '' + $dataName = '', + ResourceConnection $resourceConnection = null ) { parent::__construct($name, $data, $dataName); - $this->sqlVersionProvider = Bootstrap::getObjectManager()->get(SqlVersionProvider::class); + $objectManager = Bootstrap::getObjectManager(); + $this->sqlVersionProvider = $objectManager->get(SqlVersionProvider::class); + $this->resourceConnection = $resourceConnection ?? $objectManager->get(ResourceConnection::class); } /** @@ -97,7 +107,13 @@ private function getDbKey(): string $this->dbKey = DataProviderFromFile::FALLBACK_VALUE; foreach (DataProviderFromFile::POSSIBLE_SUFFIXES as $possibleVersion => $suffix) { - if (strpos($this->getDatabaseVersion(), (string)$possibleVersion) !== false) { + if ($this->sqlVersionProvider->isMysqlGte8029()) { + $this->dbKey = DataProviderFromFile::POSSIBLE_SUFFIXES[SqlVersionProvider::MYSQL_8_0_29_VERSION]; + break; + } elseif ($this->sqlVersionProvider->isMariaDBGte10427()) { + $this->dbKey = DataProviderFromFile::POSSIBLE_SUFFIXES[SqlVersionProvider::MARIA_DB_10_4_27_VERSION]; + break; + } elseif (strpos($this->getDatabaseVersion(), (string)$possibleVersion) !== false) { $this->dbKey = $suffix; break; } @@ -105,4 +121,20 @@ private function getDbKey(): string return $this->dbKey; } + + /** + * Checks if the DB connection Aurora RDS + * + * @param string $resource + * @return bool + */ + public function isUsingAuroraDb(string $resource = ResourceConnection::DEFAULT_CONNECTION): bool + { + try { + $this->resourceConnection->getConnection($resource)->query('SELECT AURORA_VERSION();'); + return true; + } catch (Zend_Db_Statement_Exception $e) { + return false; + } + } } diff --git a/dev/tests/setup-integration/testsuite/Magento/Setup/DeclarativeInstallerTest.php b/dev/tests/setup-integration/testsuite/Magento/Setup/DeclarativeInstallerTest.php index e88d47a02c0d..3a5e03fbff64 100644 --- a/dev/tests/setup-integration/testsuite/Magento/Setup/DeclarativeInstallerTest.php +++ b/dev/tests/setup-integration/testsuite/Magento/Setup/DeclarativeInstallerTest.php @@ -216,7 +216,7 @@ public function testInstallationWithConstraintsModification() ); self::assertNull($diff->getAll()); $shardData = $this->describeTable->describeShard(Sharding::DEFAULT_CONNECTION); - self::assertEquals($this->getTrimmedData(), $shardData); + $this->assertTableCreationStatements($this->getTrimmedData(), $shardData); } /** @@ -246,7 +246,7 @@ public function testInstallationWithDroppingTables() ); self::assertNull($diff->getAll()); $shardData = $this->describeTable->describeShard(Sharding::DEFAULT_CONNECTION); - self::assertEquals($this->getData(), $shardData); + $this->assertTableCreationStatements($this->getData(), $shardData); } /** @@ -305,6 +305,10 @@ public function testInstallWithCodeBaseRollback() $this->cliCommand->install( ['Magento_TestSetupDeclarationModule1'] ); + + if ($this->isUsingAuroraDb()) { + $this->markTestSkipped('Test skipped in AWS Aurora'); + } $beforeRollback = $this->describeTable->describeShard('default'); self::assertEquals($this->getTrimmedData()['before'], $beforeRollback); //Move db_schema.xml file and tried to install @@ -344,7 +348,9 @@ public function testTableRename() $this->resourceConnection->getTableName('some_table'), $dataToMigrate ); - self::assertEquals($this->getData()['before'], $before['some_table']); + $this->isUsingAuroraDb() ? + $this->assertStringContainsString($before['some_table'], $this->getTrimmedData()['before']) : + $this->assertEquals($this->getData()['before'], $before['some_table']); //Move db_schema.xml file and tried to install $this->moduleManager->updateRevision( 'Magento_TestSetupDeclarationModule1', @@ -355,7 +361,9 @@ public function testTableRename() $this->cliCommand->upgrade(); $after = $this->describeTable->describeShard('default'); - self::assertEquals($this->getData()['after'], $after['some_table_renamed']); + $this->isUsingAuroraDb() ? + $this->assertStringContainsString($after['some_table_renamed'], $this->getTrimmedData()['after']) : + $this->assertEquals($this->getData()['after'], $after['some_table_renamed']); $select = $adapter->select() ->from($this->resourceConnection->getTableName('some_table_renamed')); self::assertEquals([$dataToMigrate], $adapter->fetchAll($select)); @@ -459,6 +467,26 @@ public function testInstallationWithDisablingTables() ); self::assertNull($diff->getAll()); $shardData = $this->describeTable->describeShard(Sharding::DEFAULT_CONNECTION); - self::assertEquals($this->getData(), $shardData); + $this->assertTableCreationStatements($this->getData(), $shardData); + } + + /** + * Assert table creation statements + * + * @param array $expectedData + * @param array $actualData + */ + private function assertTableCreationStatements(array $expectedData, array $actualData): void + { + if (!$this->isUsingAuroraDb()) { + $this->assertEquals($expectedData, $actualData); + } else { + ksort($expectedData); + ksort($actualData); + $this->assertSameSize($expectedData, $actualData); + foreach ($expectedData as $key => $value) { + $this->assertStringContainsString($actualData[$key], $value); + } + } } } diff --git a/dev/tests/setup-integration/testsuite/Magento/Setup/ShardingTest.php b/dev/tests/setup-integration/testsuite/Magento/Setup/ShardingTest.php index ed219fb89a56..3ee7d3a26635 100644 --- a/dev/tests/setup-integration/testsuite/Magento/Setup/ShardingTest.php +++ b/dev/tests/setup-integration/testsuite/Magento/Setup/ShardingTest.php @@ -78,7 +78,7 @@ public function testInstall() self::assertCount(2, $default); self::assertCount(1, $shard1); self::assertCount(1, $shard2); - self::assertEquals($this->getData(), array_replace($default, $shard1, $shard2)); + $this->assertTableCreationStatements($this->getData(), array_replace($default, $shard1, $shard2)); } /** @@ -99,6 +99,26 @@ public function testUpgrade() self::assertCount(2, $default); self::assertCount(1, $shard1); self::assertCount(1, $shard2); - self::assertEquals($this->getData(), array_replace($default, $shard1, $shard2)); + $this->assertTableCreationStatements($this->getData(), array_replace($default, $shard1, $shard2)); + } + + /** + * Assert table creation statements + * + * @param array $expectedData + * @param array $actualData + */ + private function assertTableCreationStatements(array $expectedData, array $actualData): void + { + if (!$this->isUsingAuroraDb()) { + $this->assertEquals($expectedData, $actualData); + } else { + ksort($expectedData); + ksort($actualData); + $this->assertSameSize($expectedData, $actualData); + foreach ($expectedData as $key => $value) { + $this->assertStringContainsString($actualData[$key], $value); + } + } } } diff --git a/dev/tests/static/testsuite/Magento/Test/Js/_files/blacklist/magento.txt b/dev/tests/static/testsuite/Magento/Test/Js/_files/blacklist/magento.txt index 336b0739405f..40a6661b35ec 100644 --- a/dev/tests/static/testsuite/Magento/Test/Js/_files/blacklist/magento.txt +++ b/dev/tests/static/testsuite/Magento/Test/Js/_files/blacklist/magento.txt @@ -12,9 +12,11 @@ lib/web/mage/adminhtml/varienLoader.js lib/web/magnifier/magnifier.js lib/web/magnifier/magnify.js lib/web/varien/js.js +lib/web/prototype/**/*.js // MINIFIED FILES app/code/**/*.min.js +lib/web/legacy-build.min.js // TEST vendor/magento/magento-coding-standard/Magento2/Tests/Eslint/* diff --git a/dev/tools/grunt/tools/collect-validation-files.js b/dev/tools/grunt/tools/collect-validation-files.js index 15fb5e50be0a..d707a276a960 100644 --- a/dev/tools/grunt/tools/collect-validation-files.js +++ b/dev/tools/grunt/tools/collect-validation-files.js @@ -3,58 +3,60 @@ * See COPYING.txt for license details. */ -'use strict'; - -var glob = require('glob'), - fs = require('fs'), - _ = require('underscore'), - fst = require('../tools/fs-tools'), - pc = require('../configs/path'); - -module.exports = { - readFiles: function (paths) { - var data = []; - - _.each(paths, function (path) { - data = _.union(data, fst.getData(path)); - }); - - return data; - }, - - getFilesForValidate: function () { - var blackListFiles = glob.sync(pc.static.blacklist + '*.txt'), - whiteListFiles = glob.sync(pc.static.whitelist + '*.txt'), - blackList = this.readFiles(blackListFiles).filter(this.isListEntryValid), - whiteList = this.readFiles(whiteListFiles).filter(this.isListEntryValid), - files = [], - entireBlackList = []; - - fst.arrayRead(blackList, function (data) { - entireBlackList = _.union(entireBlackList, data); - }); - - fst.arrayRead(whiteList, function (data) { - files = _.difference(data, entireBlackList); - }); - - return files; - }, - - isListEntryValid: function(line) { - line = line.trim(); - return line.length > 0 && line.startsWith('// ') !== true; - }, - - getFiles: function (file) { - if (file) { - return file.split(','); +module.exports = (function (glob, fs, _, fst, pc) { + 'use strict'; + return { + readFiles: function (paths) { + var data = []; + + _.each(paths, function (path) { + data = _.union(data, fst.getData(path)); + }); + + return data; + }, + + getFilesForValidate: function () { + var blackListFiles = glob.sync(pc.static.blacklist + '*.txt'), + whiteListFiles = glob.sync(pc.static.whitelist + '*.txt'), + blackList = this.readFiles(blackListFiles).filter(this.isListEntryValid), + whiteList = this.readFiles(whiteListFiles).filter(this.isListEntryValid), + files = [], + entireBlackList = []; + + fst.arrayRead(blackList, function (data) { + entireBlackList = _.union(entireBlackList, data); + }); + + fst.arrayRead(whiteList, function (data) { + files = _.difference(data, entireBlackList); + }); + + return files; + }, + + isListEntryValid: function (line) { + line = line.trim(); + return line.length > 0 && line.startsWith('// ') !== true; + }, + + getFiles: function (file) { + var files; + + if (file) { + return file.split(','); + } + + if (!fs.existsSync(pc.static.tmp)) { + fst.write(pc.static.tmp, this.getFilesForValidate()); + } + + files = fst.getData(pc.static.tmp); + if (files.length === 1 && files[0] === '') { + files = []; + } + + return files; } - - if (!fs.existsSync(pc.static.tmp)) { - fst.write(pc.static.tmp, this.getFilesForValidate()); - } - - return fst.getData(pc.static.tmp); - } -}; + }; +})(require('glob'),require('fs'),require('underscore'),require('../tools/fs-tools'),require('../configs/path')); diff --git a/lib/internal/GnuFreeFont/gpl-3.0.txt b/lib/internal/GnuFreeFont/gpl-3.0.txt new file mode 100644 index 000000000000..f288702d2fa1 --- /dev/null +++ b/lib/internal/GnuFreeFont/gpl-3.0.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/lib/internal/Magento/Framework/Amqp/Config.php b/lib/internal/Magento/Framework/Amqp/Config.php index 44e033f4a7b8..3769ed51f73e 100644 --- a/lib/internal/Magento/Framework/Amqp/Config.php +++ b/lib/internal/Magento/Framework/Amqp/Config.php @@ -23,20 +23,20 @@ class Config /** * Queue config key */ - const QUEUE_CONFIG = 'queue'; + public const QUEUE_CONFIG = 'queue'; /** * Amqp config key */ - const AMQP_CONFIG = 'amqp'; + public const AMQP_CONFIG = 'amqp'; - const HOST = 'host'; - const PORT = 'port'; - const USERNAME = 'user'; - const PASSWORD = 'password'; - const VIRTUALHOST = 'virtualhost'; - const SSL = 'ssl'; - const SSL_OPTIONS = 'ssl_options'; + public const HOST = 'host'; + public const PORT = 'port'; + public const USERNAME = 'user'; + public const PASSWORD = 'password'; + public const VIRTUALHOST = 'virtualhost'; + public const SSL = 'ssl'; + public const SSL_OPTIONS = 'ssl_options'; /** * Deployment configuration @@ -140,7 +140,7 @@ public function getValue($key) */ private function createConnection(): AbstractConnection { - $sslEnabled = trim($this->getValue(self::SSL)) === 'true'; + $sslEnabled = $this->getValue(self::SSL) && trim($this->getValue(self::SSL)) === 'true'; $options = new FactoryOptions(); $options->setHost($this->getValue(self::HOST)); $options->setPort($this->getValue(self::PORT)); diff --git a/lib/internal/Magento/Framework/Amqp/composer.json b/lib/internal/Magento/Framework/Amqp/composer.json index 5727ccb3eaa8..722127a70423 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.4.2-p1", "require": { - "magento/framework": "*", + "magento/framework": "103.0.*", "php": "~7.4.0||~8.1.0", "php-amqplib/php-amqplib": "~3.1.0" }, "autoload": { - "psr-4": { - "Magento\\Framework\\Amqp\\": "" - }, "files": [ "registration.php" - ] + ], + "psr-4": { + "Magento\\Framework\\Amqp\\": "" + } } } + diff --git a/lib/internal/Magento/Framework/App/Http/Context.php b/lib/internal/Magento/Framework/App/Http/Context.php index 79a15110234c..13e0b4f7a68d 100644 --- a/lib/internal/Magento/Framework/App/Http/Context.php +++ b/lib/internal/Magento/Framework/App/Http/Context.php @@ -5,7 +5,9 @@ */ namespace Magento\Framework\App\Http; +use Magento\Framework\App\DeploymentConfig; use Magento\Framework\App\ObjectManager; +use Magento\Framework\Config\ConfigOptionsListConstants; use Magento\Framework\Serialize\Serializer\Json; /** @@ -16,7 +18,7 @@ class Context /** * Currency cache context */ - const CONTEXT_CURRENCY = 'current_currency'; + public const CONTEXT_CURRENCY = 'current_currency'; /** * Data storage @@ -35,6 +37,11 @@ class Context */ private $serializer; + /** + * @var DeploymentConfig + */ + private DeploymentConfig $deploymentConfig; + /** * @param array $data * @param array $default @@ -112,8 +119,11 @@ public function getVaryString() { $data = $this->getData(); if (!empty($data)) { + $salt = (string)$this->getDeploymentConfig()->get( + ConfigOptionsListConstants::CONFIG_PATH_CRYPT_KEY + ); ksort($data); - return sha1($this->serializer->serialize($data)); + return hash('sha256', $this->serializer->serialize($data) . '|' . $salt); } return null; } @@ -130,4 +140,18 @@ public function toArray() 'default' => $this->default ]; } + + /** + * Get DeploymentConfig + * + * @return DeploymentConfig + */ + private function getDeploymentConfig() : DeploymentConfig + { + if (!isset($this->deploymentConfig)) { + $this->deploymentConfig = ObjectManager::getInstance() + ->get(DeploymentConfig::class); + } + return $this->deploymentConfig; + } } diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Http/ContextTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Http/ContextTest.php index a1ab0f3d3f5f..17aeb7498832 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/Http/ContextTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/Http/ContextTest.php @@ -7,7 +7,10 @@ namespace Magento\Framework\App\Test\Unit\Http; +use Magento\Framework\App\DeploymentConfig; use Magento\Framework\App\Http\Context; +use Magento\Framework\Config\ConfigOptionsListConstants; +use Magento\Framework\ObjectManagerInterface; use Magento\Framework\Serialize\Serializer\Json; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use PHPUnit\Framework\MockObject\MockObject; @@ -25,6 +28,16 @@ class ContextTest extends TestCase */ protected $object; + /** + * @var DeploymentConfig|MockObject + */ + private $deploymentConfig; + + /** + * @var ObjectManagerInterface|MockObject + */ + private $objectManagerMock; + /** * @var Json|MockObject */ @@ -32,6 +45,12 @@ class ContextTest extends TestCase protected function setUp(): void { + $this->objectManagerMock = $this->getMockBuilder(ObjectManagerInterface::class) + ->disableOriginalConstructor() + ->onlyMethods(['create']) + ->getMockForAbstractClass(); + \Magento\Framework\App\ObjectManager::setInstance($this->objectManagerMock); + $this->objectManager = new ObjectManager($this); $this->serializerMock = $this->getMockBuilder(Json::class) ->setMethods(['serialize']) @@ -50,6 +69,10 @@ function ($value) { 'serializer' => $this->serializerMock ] ); + $this->deploymentConfig = $this->createPartialMock( + DeploymentConfig::class, + ['get'] + ); } public function testGetValue() @@ -81,6 +104,16 @@ public function testGetData() public function testGetVaryString() { + $this->objectManagerMock->expects($this->any()) + ->method('get') + ->with(DeploymentConfig::class) + ->willReturn($this->deploymentConfig); + + $this->deploymentConfig->expects($this->any()) + ->method('get') + ->with(ConfigOptionsListConstants::CONFIG_PATH_CRYPT_KEY) + ->willReturn('448198e08af35844a42d3c93c1ef4e03'); + $this->object->setValue('key2', 'value2', 'default2'); $this->object->setValue('key1', 'value1', 'default1'); $data = [ @@ -88,7 +121,11 @@ public function testGetVaryString() 'key1' => 'value1' ]; ksort($data); - $this->assertEquals(sha1(json_encode($data)), $this->object->getVaryString()); + + $salt = $this->deploymentConfig->get(ConfigOptionsListConstants::CONFIG_PATH_CRYPT_KEY); + $cacheKey = hash('sha256', $this->serializerMock->serialize($data) . '|' . $salt); + + $this->assertEquals($cacheKey, $this->object->getVaryString()); } public function testToArray() diff --git a/lib/internal/Magento/Framework/Bulk/composer.json b/lib/internal/Magento/Framework/Bulk/composer.json index 7733ce9fea4c..0e601aac8ade 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": "101.0.1", "require": { - "magento/framework": "*", + "magento/framework": "103.0.*", "php": "~7.4.0||~8.1.0" }, "autoload": { - "psr-4": { - "Magento\\Framework\\Bulk\\": "" - }, "files": [ "registration.php" - ] + ], + "psr-4": { + "Magento\\Framework\\Bulk\\": "" + } } } + diff --git a/lib/internal/Magento/Framework/DB/Adapter/SqlVersionProvider.php b/lib/internal/Magento/Framework/DB/Adapter/SqlVersionProvider.php index def51db16454..9383804dcaaf 100644 --- a/lib/internal/Magento/Framework/DB/Adapter/SqlVersionProvider.php +++ b/lib/internal/Magento/Framework/DB/Adapter/SqlVersionProvider.php @@ -25,6 +25,12 @@ class SqlVersionProvider public const MARIA_DB_10_VERSION = '10.'; + public const MYSQL_8_0_29_VERSION = '8.0.29'; + + public const MARIA_DB_10_4_VERSION = '10.4.'; + + public const MARIA_DB_10_4_27_VERSION = '10.4.27'; + /**#@-*/ /** @@ -116,4 +122,38 @@ private function fetchSqlVersion(string $resource): string return $versionOutput[self::VERSION_VAR_NAME]; } + + /** + * Check if MariaDB version is greater than equal to 10.4.27 + * + * @return bool + * @throws ConnectionException + */ + public function isMariaDBGte10427(): bool + { + $sqlExactVersion = $this->fetchSqlVersion(ResourceConnection::DEFAULT_CONNECTION); + //check if mariadb is 10.4 or 10.5 + $pattern="/^10.([4-5]\.).*$/"; + if (preg_match($pattern, $this->getSqlVersion()) && version_compare($sqlExactVersion, '10.4.27', '>=')) { + return true; + } + return false; + } + + /** + * Check if MySQL version is greater than equal to 8.0.29 + * + * @return bool + * @throws ConnectionException + */ + public function isMysqlGte8029() + { + $sqlVersion = $this->getSqlVersion(); + $isMariaDB = str_contains($sqlVersion, SqlVersionProvider::MARIA_DB_10_VERSION); + $sqlExactVersion = $this->fetchSqlVersion(ResourceConnection::DEFAULT_CONNECTION); + if (!$isMariaDB && version_compare($sqlExactVersion, '8.0.29', '>=')) { + return true; + } + return false; + } } diff --git a/lib/internal/Magento/Framework/Data/Form/Element/Image.php b/lib/internal/Magento/Framework/Data/Form/Element/Image.php index 5a0cab45d44d..fd463ae2c18b 100644 --- a/lib/internal/Magento/Framework/Data/Form/Element/Image.php +++ b/lib/internal/Magento/Framework/Data/Form/Element/Image.php @@ -9,9 +9,12 @@ * * @author Magento Core Team */ +declare(strict_types=1); + namespace Magento\Framework\Data\Form\Element; use Magento\Framework\App\ObjectManager; +use Magento\Framework\Escaper; use Magento\Framework\Math\Random; use Magento\Framework\UrlInterface; use Magento\Framework\View\Helper\SecureHtmlRenderer; @@ -36,7 +39,7 @@ class Image extends \Magento\Framework\Data\Form\Element\AbstractElement /** * @param Factory $factoryElement * @param CollectionFactory $factoryCollection - * @param \Magento\Framework\Escaper $escaper + * @param Escaper $escaper * @param UrlInterface $urlBuilder * @param array $data * @param SecureHtmlRenderer|null $secureRenderer @@ -45,7 +48,7 @@ class Image extends \Magento\Framework\Data\Form\Element\AbstractElement public function __construct( Factory $factoryElement, CollectionFactory $factoryCollection, - \Magento\Framework\Escaper $escaper, + Escaper $escaper, UrlInterface $urlBuilder, $data = [], ?SecureHtmlRenderer $secureRenderer = null, @@ -69,7 +72,7 @@ public function getElementHtml() { $html = ''; - if ((string)$this->getValue()) { + if ((string)$this->getEscapedValue()) { $url = $this->_getUrl(); if (!preg_match("/^http\:\/\/|https\:\/\//", $url)) { @@ -89,10 +92,10 @@ public function getElementHtml() '" id="' . $this->getHtmlId() . '_image" title="' . - $this->getValue() . + $this->getEscapedValue() . '"' . ' alt="' . - $this->getValue() . + $this->getEscapedValue() . '" height="22" width="22" class="small-image-preview v-middle" ' . $this->_getUiId() . ' />' . @@ -118,7 +121,7 @@ public function getElementHtml() protected function _getDeleteCheckbox() { $html = ''; - if ($this->getValue()) { + if ($this->getEscapedValue()) { $label = (string)new \Magento\Framework\Phrase('Delete Image'); $html .= ''; $html .= ''; + return ''; } /** @@ -161,7 +165,7 @@ protected function _getHiddenInput() */ protected function _getUrl() { - return $this->getValue(); + return $this->getEscapedValue(); } /** diff --git a/lib/internal/Magento/Framework/Data/Test/Unit/Form/Element/ImageTest.php b/lib/internal/Magento/Framework/Data/Test/Unit/Form/Element/ImageTest.php index 54f9aca25762..265d2a942722 100644 --- a/lib/internal/Magento/Framework/Data/Test/Unit/Form/Element/ImageTest.php +++ b/lib/internal/Magento/Framework/Data/Test/Unit/Form/Element/ImageTest.php @@ -21,6 +21,7 @@ use PHPUnit\Framework\TestCase; use Magento\Framework\Math\Random; use Magento\Framework\View\Helper\SecureHtmlRenderer; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; /** * Test for the widget. @@ -44,11 +45,16 @@ class ImageTest extends TestCase */ protected $_image; + /** + * @var array + */ + protected $testData; + protected function setUp(): void { + $objectManager = new ObjectManager($this); $factoryMock = $this->createMock(Factory::class); $collectionFactoryMock = $this->createMock(CollectionFactory::class); - $escaperMock = $this->createMock(Escaper::class); $this->urlBuilder = $this->createMock(Url::class); $randomMock = $this->createMock(Random::class); $randomMock->method('getRandomString')->willReturn('some-rando-string'); @@ -67,18 +73,30 @@ function (string $tag, array $attrs, ?string $content): string { return "<$tag {$attrs->serialize()}>$content"; } ); - $this->_image = new Image( - $factoryMock, - $collectionFactoryMock, - $escaperMock, - $this->urlBuilder, - [], - $secureRendererMock, - $randomMock + + $this->_image = $objectManager->getObject( + Image::class, + [ + 'factoryMock'=>$factoryMock, + 'collectionFactoryMock'=>$collectionFactoryMock, + 'urlBuilder' => $this->urlBuilder, + '_escaper' => $objectManager->getObject(Escaper::class), + 'random' => $randomMock, + 'secureRenderer' => $secureRendererMock, + ] ); + + $this->testData = [ + 'html_id_prefix' => 'test_id_prefix_', + 'html_id' => 'test_id', + 'html_id_suffix' => '_test_id_suffix', + 'path' => 'catalog/product/placeholder', + 'value' => 'test_value', + ]; + $formMock = new DataObject(); - $formMock->getHtmlIdPrefix('id_prefix'); - $formMock->getHtmlIdPrefix('id_suffix'); + $formMock->getHtmlIdPrefix($this->testData['html_id_prefix']); + $formMock->getHtmlIdPrefix($this->testData['html_id_suffix']); $this->_image->setForm($formMock); } @@ -117,21 +135,32 @@ public function testGetElementHtmlWithoutValue() */ public function testGetElementHtmlWithValue() { - $this->_image->setValue('test_value'); - $this->urlBuilder->expects($this->once()) - ->method('getBaseUrl') - ->with(['_type' => UrlInterface::URL_TYPE_MEDIA]) - ->willReturn('http://localhost/media/'); + $url = 'http://test.example.com/media/'; + + $this->_image->setValue($this->testData['value']); + $this->_image->setHtmlId($this->testData['html_id']); + + $this->urlBuilder->expects($this->once())->method('getBaseUrl') + ->with(['_type' => UrlInterface::URL_TYPE_MEDIA])->willReturn($url); + + $expectedHtmlId = $this->testData['html_id']; + $html = $this->_image->getElementHtml(); + $this->assertStringContainsString('class="input-file"', $html); $this->assertStringContainsString('assertStringContainsString('type="file"', $html); $this->assertStringContainsString('value="test_value"', $html); + $this->assertStringContainsString( - 'assertStringContainsString("imagePreview('_image');\nreturn false;", $html); + + $this->assertStringContainsString("imagePreview('{$expectedHtmlId}_image');\nreturn false;", $html); $this->assertStringContainsString('getDataByPath($key); } else { $data = $this->_getData($key); diff --git a/lib/internal/Magento/Framework/Filesystem/Directory/PathValidator.php b/lib/internal/Magento/Framework/Filesystem/Directory/PathValidator.php index 9ecbfa6c9d2a..231686dee8af 100644 --- a/lib/internal/Magento/Framework/Filesystem/Directory/PathValidator.php +++ b/lib/internal/Magento/Framework/Filesystem/Directory/PathValidator.php @@ -54,8 +54,11 @@ public function validate( $actualPath = $this->driver->getRealPathSafety($path); } - if (mb_strpos($actualPath, $realDirectoryPath) !== 0 - && rtrim($path, DIRECTORY_SEPARATOR) !== $realDirectoryPath + if (preg_match('/(?:^-|\s-\S)/', $path) + || ( + mb_strpos($actualPath, $realDirectoryPath) !== 0 + && rtrim($path, DIRECTORY_SEPARATOR) !== $realDirectoryPath + ) ) { throw new ValidatorException( new Phrase( diff --git a/lib/internal/Magento/Framework/Filesystem/File/Write.php b/lib/internal/Magento/Framework/Filesystem/File/Write.php index 913421aa91ad..14b00408999e 100644 --- a/lib/internal/Magento/Framework/Filesystem/File/Write.php +++ b/lib/internal/Magento/Framework/Filesystem/File/Write.php @@ -8,6 +8,7 @@ use Magento\Framework\Filesystem\DriverInterface; use Magento\Framework\Exception\FileSystemException; +use Magento\Framework\Phrase; class Write extends Read implements WriteInterface { @@ -28,17 +29,21 @@ public function __construct($path, DriverInterface $driver, $mode) * Assert file existence for proper mode * * @return void - * @throws \Magento\Framework\Exception\FileSystemException + * @throws FileSystemException */ protected function assertValid() { $fileExists = $this->driver->isExists($this->path); - if (!$fileExists && preg_match('/r/', $this->mode)) { + if (preg_match('/(?:^-|\s-)/', basename($this->path))) { + throw new FileSystemException( + new Phrase('The filename "%1" contains invalid characters', [basename($this->path)]) + ); + } elseif (!$fileExists && preg_match('/r/', $this->mode)) { throw new FileSystemException( - new \Magento\Framework\Phrase('The "%1" file doesn\'t exist.', [$this->path]) + new Phrase('The "%1" file doesn\'t exist.', [$this->path]) ); } elseif ($fileExists && preg_match('/x/', $this->mode)) { - throw new FileSystemException(new \Magento\Framework\Phrase('The file "%1" already exists', [$this->path])); + throw new FileSystemException(new Phrase('The file "%1" already exists', [$this->path])); } } @@ -55,7 +60,7 @@ public function write($data) return $this->driver->fileWrite($this->resource, $data); } catch (FileSystemException $e) { throw new FileSystemException( - new \Magento\Framework\Phrase('Cannot write to the "%1" file. %2', [$this->path, $e->getMessage()]) + new Phrase('Cannot write to the "%1" file. %2', [$this->path, $e->getMessage()]) ); } } @@ -75,7 +80,7 @@ public function writeCsv(array $data, $delimiter = ',', $enclosure = '"') return $this->driver->filePutCsv($this->resource, $data, $delimiter, $enclosure); } catch (FileSystemException $e) { throw new FileSystemException( - new \Magento\Framework\Phrase('Cannot write to the "%1" file. %2', [$this->path, $e->getMessage()]) + new Phrase('Cannot write to the "%1" file. %2', [$this->path, $e->getMessage()]) ); } } @@ -92,7 +97,7 @@ public function flush() return $this->driver->fileFlush($this->resource); } catch (FileSystemException $e) { throw new FileSystemException( - new \Magento\Framework\Phrase('Cannot flush the "%1" file. %2', [$this->path, $e->getMessage()]) + new Phrase('Cannot flush the "%1" file. %2', [$this->path, $e->getMessage()]) ); } } diff --git a/lib/internal/Magento/Framework/Filesystem/Test/Unit/Directory/PathValidatorTest.php b/lib/internal/Magento/Framework/Filesystem/Test/Unit/Directory/PathValidatorTest.php index b74268a86953..717e12df7f9a 100644 --- a/lib/internal/Magento/Framework/Filesystem/Test/Unit/Directory/PathValidatorTest.php +++ b/lib/internal/Magento/Framework/Filesystem/Test/Unit/Directory/PathValidatorTest.php @@ -1,7 +1,5 @@ purifier = $purifier ?? ObjectManager::getInstance()->get(PurifierInterface::class); + } + /** * Regular expressions for cutting malicious code * * @var string[] */ - protected $_expressions = [ + protected array $_expressions = [ //comments, must be first '/(\/\*.*\*\/)/Us', //tabs @@ -41,15 +55,16 @@ class MaliciousCode implements \Zend_Filter_Interface * Filter value * * @param string|array $value - * @return string|array Filtered value + * @return string|array */ public function filter($value) { $replaced = 0; do { - $value = preg_replace($this->_expressions, '', $value, -1, $replaced); + $value = preg_replace($this->_expressions, '', $value ?? '', -1, $replaced); } while ($replaced !== 0); - return $value; + + return $this->purifier->purify($value); } /** @@ -58,7 +73,7 @@ public function filter($value) * @param string $expression * @return $this */ - public function addExpression($expression) + public function addExpression(string $expression) :self { if (!in_array($expression, $this->_expressions)) { $this->_expressions[] = $expression; @@ -72,7 +87,7 @@ public function addExpression($expression) * @param array $expressions * @return $this */ - public function setExpressions(array $expressions) + public function setExpressions(array $expressions) :self { $this->_expressions = $expressions; return $this; diff --git a/lib/internal/Magento/Framework/Filter/Input/Purifier.php b/lib/internal/Magento/Framework/Filter/Input/Purifier.php new file mode 100644 index 000000000000..1603f70b8f7e --- /dev/null +++ b/lib/internal/Magento/Framework/Filter/Input/Purifier.php @@ -0,0 +1,46 @@ +set(self::CACHE_DEFINITION, null); + + $this->purifier = $purifier ?? ObjectManager::getInstance()->create(HTMLPurifier::class, ['config' => $config]); + } + + /** + * Purify Html Content from malicious code + * + * @param string|array $content + * @return mixed + */ + public function purify($content) :mixed + { + return is_array($content) ? $this->purifier->purifyArray($content) : $this->purifier->purify($content); + } +} diff --git a/lib/internal/Magento/Framework/Filter/Input/PurifierInterface.php b/lib/internal/Magento/Framework/Filter/Input/PurifierInterface.php new file mode 100644 index 000000000000..25e590fd3a9e --- /dev/null +++ b/lib/internal/Magento/Framework/Filter/Input/PurifierInterface.php @@ -0,0 +1,19 @@ +string = $string; $this->setVariables($variables); @@ -118,6 +135,12 @@ public function __construct( $this->variableResolver = $variableResolver ?? ObjectManager::getInstance() ->get(VariableResolverInterface::class); + $this->signatureProvider = $signatureProvider ?? ObjectManager::getInstance() + ->get(SignatureProvider::class); + + $this->filteringDepthMeter = $filteringDepthMeter ?? ObjectManager::getInstance() + ->get(FilteringDepthMeter::class); + if (empty($directiveProcessors)) { $this->directiveProcessors = [ 'depend' => ObjectManager::getInstance()->get(DependDirective::class), @@ -180,6 +203,60 @@ public function filter($value) )->render()); } + $this->filteringDepthMeter->descend(); + + // Processing of template directives. + $templateDirectivesResults = $this->processDirectives($value); + + foreach ($templateDirectivesResults as $result) { + $value = str_replace($result['directive'], $result['output'], $value); + } + + // Processing of deferred directives received from child templates + // or nested directives. + $deferredDirectivesResults = $this->processDirectives($value, true); + + foreach ($deferredDirectivesResults as $result) { + $value = str_replace($result['directive'], $result['output'], $value); + } + + if ($this->filteringDepthMeter->showMark() > 1) { + // Signing own deferred directives (if any). + $signature = $this->signatureProvider->get(); + + foreach ($templateDirectivesResults as $result) { + if ($result['directive'] === $result['output']) { + $value = str_replace( + $result['output'], + $signature . $result['output'] . $signature, + $value + ); + } + } + } + + $value = $this->afterFilter($value); + + $this->filteringDepthMeter->ascend(); + + return $value; + } + + /** + * Processes template directives and returns an array that contains results produced by each directive. + * + * @param string $value + * @param bool $isSigned + * + * @return array + * + * @throws InvalidArgumentException + * @throws LocalizedException + */ + private function processDirectives($value, $isSigned = false): array + { + $results = []; + foreach ($this->directiveProcessors as $directiveProcessor) { if (!$directiveProcessor instanceof DirectiveProcessorInterface) { throw new InvalidArgumentException( @@ -187,15 +264,57 @@ public function filter($value) ); } - if (preg_match_all($directiveProcessor->getRegularExpression(), $value, $constructions, PREG_SET_ORDER)) { + $pattern = $directiveProcessor->getRegularExpression(); + + if ($isSigned) { + $pattern = $this->embedSignatureIntoPattern($pattern); + } + + if (preg_match_all($pattern, $value, $constructions, PREG_SET_ORDER)) { foreach ($constructions as $construction) { $replacedValue = $directiveProcessor->process($construction, $this, $this->templateVars); - $value = str_replace($construction[0], $replacedValue, $value); + + $results[] = [ + 'directive' => $construction[0], + 'output' => $replacedValue + ]; } } } - return $this->afterFilter($value); + return $results; + } + + /** + * Modifies given regular expression pattern to be able to recognize signed directives. + * + * @param string $pattern + * + * @return string + * + * @throws LocalizedException + */ + private function embedSignatureIntoPattern(string $pattern): string + { + $signature = $this->signatureProvider->get(); + + $closingDelimiters = [ + '(' => ')', + '{' => '}', + '[' => ']', + '<' => '>' + ]; + + $closingDelimiter = $openingDelimiter = substr(trim($pattern), 0, 1); + + if (array_key_exists($openingDelimiter, $closingDelimiters)) { + $closingDelimiter = $closingDelimiters[$openingDelimiter]; + } + + $pattern = substr_replace($pattern, $signature, strpos($pattern, $openingDelimiter) + 1, 0); + $pattern = substr_replace($pattern, $signature, strrpos($pattern, $closingDelimiter), 0); + + return $pattern; } /** diff --git a/lib/internal/Magento/Framework/Filter/Template/FilteringDepthMeter.php b/lib/internal/Magento/Framework/Filter/Template/FilteringDepthMeter.php new file mode 100644 index 000000000000..57257325be79 --- /dev/null +++ b/lib/internal/Magento/Framework/Filter/Template/FilteringDepthMeter.php @@ -0,0 +1,52 @@ +depth++; + } + + /** + * Decreases filtering depth. + * + * @return void + */ + public function ascend() + { + $this->depth--; + } + + /** + * Shows current filtering depth. + * + * @return int + */ + public function showMark(): int + { + return $this->depth; + } +} diff --git a/lib/internal/Magento/Framework/Filter/Template/SignatureProvider.php b/lib/internal/Magento/Framework/Filter/Template/SignatureProvider.php new file mode 100644 index 000000000000..3e476f3e5d79 --- /dev/null +++ b/lib/internal/Magento/Framework/Filter/Template/SignatureProvider.php @@ -0,0 +1,53 @@ +random = $random; + } + + /** + * Generates a random string which will be used as a signature during runtime. + * + * @return string + * + * @throws \Magento\Framework\Exception\LocalizedException + */ + public function get(): string + { + if ($this->signature === null) { + $this->signature = $this->random->getRandomString(32); + } + + return $this->signature; + } +} 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 779a5256fedc..a1b773c65352 100644 --- a/lib/internal/Magento/Framework/Filter/Test/Unit/Input/MaliciousCodeTest.php +++ b/lib/internal/Magento/Framework/Filter/Test/Unit/Input/MaliciousCodeTest.php @@ -8,16 +8,37 @@ namespace Magento\Framework\Filter\Test\Unit\Input; use Magento\Framework\Filter\Input\MaliciousCode; +use Magento\Framework\Filter\Input\PurifierInterface; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; class MaliciousCodeTest extends TestCase { - /** @var MaliciousCode */ - protected $filter; + /** + * @var MockObject|PurifierInterface $purifier + */ + private MockObject $purifier; + + /** + * @var MaliciousCode $filter + */ + private MaliciousCode $filter; protected function setUp(): void { - $this->filter = new MaliciousCode(); + $this->purifier = $this->getMockBuilder(PurifierInterface::class) + ->disableOriginalConstructor() + ->onlyMethods(['purify']) + ->getMockForAbstractClass(); + + $objectManager = new ObjectManager($this); + + $this->filter = $objectManager->getObject( + MaliciousCode::class, + ['purifier' => $this->purifier] + ); + parent::setUp(); } @@ -28,11 +49,11 @@ protected function setUp(): void */ public function testFilter($input, $expectedOutput) { - $this->assertEquals( - $expectedOutput, - $this->filter->filter($input), - 'Malicious code is not filtered out correctly.' - ); + $this->purifier->expects(self::atLeastOnce()) + ->method('purify') + ->willReturn($expectedOutput); + + self::assertEquals($expectedOutput, $this->filter->filter($input)); } /** @@ -125,6 +146,7 @@ public function filterDataProvider() '', '', ], + 'Null Value' => [null, ''], ]; } @@ -134,6 +156,11 @@ public function filterDataProvider() public function testAddExpression() { $customExpression = '/<\/?(customMalicious).*>/Uis'; + + $this->purifier->expects(self::atLeastOnce()) + ->method('purify') + ->willReturn('Custom malicious tag is removed customMalicious'); + $this->filter->addExpression($customExpression); $this->assertEquals( /** Tabs should be filtered out along with custom malicious code */ @@ -151,6 +178,11 @@ public function testAddExpression() public function testSetExpression() { $customExpression = '/<\/?(customMalicious).*>/Uis'; + + $this->purifier->expects(self::atLeastOnce()) + ->method('purify') + ->willReturn("Custom \tmalicious tag\t\t is removed customMalicious"); + $this->filter->setExpressions([$customExpression]); $this->assertEquals( /** Tabs should not be filtered out along with custom malicious code */ diff --git a/lib/internal/Magento/Framework/Filter/Test/Unit/Template/SignatureProviderTest.php b/lib/internal/Magento/Framework/Filter/Test/Unit/Template/SignatureProviderTest.php new file mode 100644 index 000000000000..3703c1e2d173 --- /dev/null +++ b/lib/internal/Magento/Framework/Filter/Test/Unit/Template/SignatureProviderTest.php @@ -0,0 +1,54 @@ +random = $this->createPartialMock( + Random::class, + ['getRandomString'] + ); + + $this->signatureProvider = new SignatureProvider( + $this->random + ); + } + + public function testGet() + { + $expectedResult = 'Z0FFbeCU2R8bsVGJuTdkXyiiZBzsaceV'; + + $this->random->expects($this->once()) + ->method('getRandomString') + ->with(32) + ->willReturn($expectedResult); + + $this->assertEquals($expectedResult, $this->signatureProvider->get()); + + $this->random->expects($this->never()) + ->method('getRandomString'); + + $this->assertEquals($expectedResult, $this->signatureProvider->get()); + } +} diff --git a/lib/internal/Magento/Framework/Filter/Test/Unit/TemplateTest.php b/lib/internal/Magento/Framework/Filter/Test/Unit/TemplateTest.php index 973f7ac1d268..bb459f147023 100644 --- a/lib/internal/Magento/Framework/Filter/Test/Unit/TemplateTest.php +++ b/lib/internal/Magento/Framework/Filter/Test/Unit/TemplateTest.php @@ -9,8 +9,11 @@ use Magento\Framework\DataObject; use Magento\Framework\Filter\Template; +use Magento\Framework\Filter\Template\SignatureProvider; +use Magento\Framework\Filter\Template\FilteringDepthMeter; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use Magento\Store\Model\Store; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; /** @@ -28,11 +31,43 @@ class TemplateTest extends TestCase */ private $store; + /** + * @var SignatureProvider|MockObject + */ + protected $signatureProvider; + + /** + * @var FilteringDepthMeter|MockObject + */ + protected $filteringDepthMeter; + protected function setUp(): void { $objectManager = new ObjectManager($this); - $this->templateFilter = $objectManager->getObject(Template::class); + $this->store = $objectManager->getObject(Store::class); + + $this->signatureProvider = $this->createPartialMock( + SignatureProvider::class, + ['get'] + ); + + $this->signatureProvider->expects($this->any()) + ->method('get') + ->willReturn('Z0FFbeCU2R8bsVGJuTdkXyiiZBzsaceV'); + + $this->filteringDepthMeter = $this->createPartialMock( + FilteringDepthMeter::class, + ['showMark'] + ); + + $this->templateFilter = $objectManager->getObject( + Template::class, + [ + 'signatureProvider' => $this->signatureProvider, + 'filteringDepthMeter' => $this->filteringDepthMeter + ] + ); } /** @@ -44,6 +79,10 @@ public function testAfterFilter() $value = 'test string'; $expectedResult = 'TEST STRING'; + $this->filteringDepthMeter->expects($this->any()) + ->method('showMark') + ->willReturn(1); + // Build arbitrary object to pass into the addAfterFilterCallback method $callbackObject = $this->getMockBuilder('stdObject') ->setMethods(['afterFilterCallbackMethod']) @@ -72,6 +111,10 @@ public function testAfterFilterCallbackReset() $value = 'test string'; $expectedResult = 'TEST STRING'; + $this->filteringDepthMeter->expects($this->any()) + ->method('showMark') + ->willReturn(1); + // Build arbitrary object to pass into the addAfterFilterCallback method $callbackObject = $this->getMockBuilder('stdObject') ->setMethods(['afterFilterCallbackMethod']) @@ -127,7 +170,7 @@ public function getTemplateAndExpectedResults($type)
    {{for in order.all_visible_items}}
  • - name: , lastname: , age: + name: , lastname: , age:
  • {{/for}}
@@ -137,14 +180,14 @@ public function getTemplateAndExpectedResults($type) $template = <<