diff --git a/app/code/Magento/Config/Model/Config/Backend/Baseurl.php b/app/code/Magento/Config/Model/Config/Backend/Baseurl.php index 09fd99773813117a71b43240eaafc5b96bf967ca..8a7a75d3d8db05893c3753bf408332c7e7fc7539 100644 --- a/app/code/Magento/Config/Model/Config/Backend/Baseurl.php +++ b/app/code/Magento/Config/Model/Config/Backend/Baseurl.php @@ -12,6 +12,11 @@ class Baseurl extends \Magento\Framework\App\Config\Value */ protected $_mergeService; + /** + * @var array + */ + private $allowedSchemes = ['http', 'https']; + /** * @param \Magento\Framework\Model\Context $context * @param \Magento\Framework\Registry $registry @@ -185,6 +190,36 @@ class Baseurl extends \Magento\Framework\App\Config\Value } } + /** + * Check that URL contains allowed symbols + * + * @param string $value + * @return void + * @throws \Magento\Framework\Exception\LocalizedException + */ + private function validateUrl($value) { + if (!filter_var($value, FILTER_VALIDATE_URL)) { + throw new \Magento\Framework\Exception\LocalizedException( + __('Domain Name can contain only letters, digits and hyphen.') + ); + } + } + + /** + * Check that scheme there is in list of allowed schemes + * + * @param string $value + * @return void + * @throws \Magento\Framework\Exception\LocalizedException + */ + private function validateSchemes($value) { + if (!in_array($value, $this->allowedSchemes)) { + throw new \Magento\Framework\Exception\LocalizedException( + __('You can use only following schemes: %1', implode(', ', $this->allowedSchemes)) + ); + } + } + /** * Whether the provided value can be considered as a fully qualified URL * @@ -194,7 +229,14 @@ class Baseurl extends \Magento\Framework\App\Config\Value private function _isFullyQualifiedUrl($value) { $url = parse_url($value); - return isset($url['scheme']) && isset($url['host']) && preg_match('/\/$/', $value); + + $result = isset($url['scheme']) && isset($url['host']) && preg_match('/\/$/', $value); + if ($result) { + $this->validateSchemes($url['scheme']); + $this->validateUrl($value); + } + + return $result; } /** diff --git a/dev/tests/integration/testsuite/Magento/Config/Model/Config/Backend/BaseurlTest.php b/dev/tests/integration/testsuite/Magento/Config/Model/Config/Backend/BaseurlTest.php index 0ce30e5b2984120c7e325a151d96c0ef044affa6..5a2db8ccb22fa0484ab71c04f8a6bbc4cbc7b0e6 100644 --- a/dev/tests/integration/testsuite/Magento/Config/Model/Config/Backend/BaseurlTest.php +++ b/dev/tests/integration/testsuite/Magento/Config/Model/Config/Backend/BaseurlTest.php @@ -95,33 +95,44 @@ class BaseurlTest extends \PHPUnit_Framework_TestCase $unsecurePlaceholder = '{{unsecure_base_url}}'; $unsecureSuffix = '{{unsecure_base_url}}test/'; $unsecureWrongSuffix = '{{unsecure_base_url}}test'; + $unsecureWrongDomainName = 'http://example.com_test/'; $securePlaceholder = '{{secure_base_url}}'; $secureSuffix = '{{secure_base_url}}test/'; $secureWrongSuffix = '{{secure_base_url}}test'; + $secureWrongDomainName = 'https://example.com_test/'; return [ ['', 'not a valid URL'], ['', 'example.com'], ['', 'http://example.com'], ['', 'http://example.com/uri'], + ['', $unsecureWrongDomainName], [\Magento\Store\Model\Store::XML_PATH_UNSECURE_BASE_URL, ''], [\Magento\Store\Model\Store::XML_PATH_UNSECURE_BASE_URL, $baseSuffix], [\Magento\Store\Model\Store::XML_PATH_UNSECURE_BASE_URL, $unsecureSuffix], [\Magento\Store\Model\Store::XML_PATH_UNSECURE_BASE_URL, $unsecurePlaceholder], + [\Magento\Store\Model\Store::XML_PATH_UNSECURE_BASE_URL, $unsecureWrongDomainName], [\Magento\Store\Model\Store::XML_PATH_UNSECURE_BASE_LINK_URL, ''], [\Magento\Store\Model\Store::XML_PATH_UNSECURE_BASE_LINK_URL, $baseSuffix], [\Magento\Store\Model\Store::XML_PATH_UNSECURE_BASE_LINK_URL, $unsecureWrongSuffix], + [\Magento\Store\Model\Store::XML_PATH_UNSECURE_BASE_LINK_URL, $unsecureWrongDomainName], [\Magento\Store\Model\Store::XML_PATH_UNSECURE_BASE_MEDIA_URL, $unsecureWrongSuffix], + [\Magento\Store\Model\Store::XML_PATH_UNSECURE_BASE_MEDIA_URL, $unsecureWrongDomainName], [\Magento\Store\Model\Store::XML_PATH_UNSECURE_BASE_STATIC_URL, $unsecureWrongSuffix], + [\Magento\Store\Model\Store::XML_PATH_UNSECURE_BASE_STATIC_URL, $unsecureWrongDomainName], [\Magento\Store\Model\Store::XML_PATH_SECURE_BASE_URL, ''], [\Magento\Store\Model\Store::XML_PATH_SECURE_BASE_URL, $baseSuffix], [\Magento\Store\Model\Store::XML_PATH_SECURE_BASE_URL, $secureSuffix], [\Magento\Store\Model\Store::XML_PATH_SECURE_BASE_URL, $securePlaceholder], + [\Magento\Store\Model\Store::XML_PATH_SECURE_BASE_URL, $secureWrongDomainName], [\Magento\Store\Model\Store::XML_PATH_SECURE_BASE_LINK_URL, ''], [\Magento\Store\Model\Store::XML_PATH_SECURE_BASE_LINK_URL, $baseSuffix], [\Magento\Store\Model\Store::XML_PATH_SECURE_BASE_LINK_URL, $secureWrongSuffix], + [\Magento\Store\Model\Store::XML_PATH_SECURE_BASE_LINK_URL, $secureWrongDomainName], [\Magento\Store\Model\Store::XML_PATH_SECURE_BASE_MEDIA_URL, $secureWrongSuffix], + [\Magento\Store\Model\Store::XML_PATH_SECURE_BASE_MEDIA_URL, $secureWrongDomainName], [\Magento\Store\Model\Store::XML_PATH_SECURE_BASE_STATIC_URL, $secureWrongSuffix], + [\Magento\Store\Model\Store::XML_PATH_SECURE_BASE_STATIC_URL, $secureWrongDomainName], ]; } } diff --git a/setup/config/di.config.php b/setup/config/di.config.php index 804f18462065aa3af62cbba93d1fa5339b548f7e..b0dcb452ccd4030cf9736e6ab4a521199d1a899f 100644 --- a/setup/config/di.config.php +++ b/setup/config/di.config.php @@ -21,6 +21,7 @@ return [ \Magento\Setup\Controller\Environment::class, \Magento\Setup\Controller\DependencyCheck::class, \Magento\Setup\Controller\DatabaseCheck::class, + \Magento\Setup\Controller\UrlCheck::class, \Magento\Setup\Controller\ValidateAdminCredentials::class, \Magento\Setup\Controller\AddDatabase::class, \Magento\Setup\Controller\WebConfiguration::class, diff --git a/setup/pub/magento/setup/web-configuration.js b/setup/pub/magento/setup/web-configuration.js index 03a0fc7845dda90225d3be867f4bf9ddd1621f63..47458056b33b52f8913017a5f6f7c6317fd98347 100644 --- a/setup/pub/magento/setup/web-configuration.js +++ b/setup/pub/magento/setup/web-configuration.js @@ -5,7 +5,7 @@ 'use strict'; angular.module('web-configuration', ['ngStorage']) - .controller('webConfigurationController', ['$scope', '$state', '$localStorage', function ($scope, $state, $localStorage) { + .controller('webConfigurationController', ['$scope', '$state', '$localStorage', '$http', function ($scope, $state, $localStorage, $http) { $scope.config = { address: { base_url: '', @@ -119,4 +119,28 @@ angular.module('web-configuration', ['ngStorage']) $scope.webconfig.submitted = false; } }); + + // Validate URL + $scope.validateUrl = function () { + if (!$scope.webconfig.submitted) { + $http.post('index.php/url-check', $scope.config) + .success(function (data) { + $scope.validateUrl.result = data; + if ($scope.validateUrl.result.successUrl && $scope.validateUrl.result.successSecureUrl) { + $scope.nextState(); + } + if (!$scope.validateUrl.result.successUrl) { + $scope.webconfig.submitted = true; + $scope.webconfig.base_url.$setValidity('url', false); + } + if (!$scope.validateUrl.result.successSecureUrl) { + $scope.webconfig.submitted = true; + $scope.webconfig.https.$setValidity('url', false); + } + }) + .error(function (data) { + $scope.validateUrl.failed = data; + }); + } + }; }]); diff --git a/setup/src/Magento/Setup/Console/Command/InstallStoreConfigurationCommand.php b/setup/src/Magento/Setup/Console/Command/InstallStoreConfigurationCommand.php index 928fe1e3d4b8d32f7bc4656bf6c00ac500972234..6ebd387d409c90d743fed756839a3b2da678b454 100644 --- a/setup/src/Magento/Setup/Console/Command/InstallStoreConfigurationCommand.php +++ b/setup/src/Magento/Setup/Console/Command/InstallStoreConfigurationCommand.php @@ -20,7 +20,6 @@ use Magento\Store\Model\Store; use Magento\Framework\Validator\Locale; use Magento\Framework\Validator\Timezone; use Magento\Framework\Validator\Currency; -use Magento\Framework\Url\Validator; /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) @@ -180,15 +179,12 @@ class InstallStoreConfigurationCommand extends AbstractSetupCommand } switch ($key) { case StoreConfigurationDataMapper::KEY_BASE_URL: - /** @var Validator $url */ if (strcmp($value, '{{base_url}}') == 0) { break; } - $url = $this->objectManager->get(\Magento\Framework\Url\Validator::class); - if (!$url->isValid($value)) { - $errorMsgs = $url->getMessages(); - $errors[] = '<error>' . 'Command option \'' . StoreConfigurationDataMapper::KEY_BASE_URL - . '\': ' . $errorMsgs[Validator::INVALID_URL] .'</error>'; + $errorMsg = $this->validateUrl($value, StoreConfigurationDataMapper::KEY_BASE_URL); + if ($errorMsg !== '') { + $errors[] = $errorMsg; } break; case StoreConfigurationDataMapper::KEY_LANGUAGE: @@ -229,18 +225,11 @@ class InstallStoreConfigurationCommand extends AbstractSetupCommand break; case StoreConfigurationDataMapper::KEY_BASE_URL_SECURE: try { - /** @var Validator $url */ - $url = $this->objectManager->get(\Magento\Framework\Url\Validator::class); - $errorMsgs = ''; - if (!$url->isValid($value)) { - $errorMsgs = $url->getMessages(); - if (!empty($errorMsgs)) { - $errors[] = '<error>' . 'Command option \'' - . StoreConfigurationDataMapper::KEY_BASE_URL_SECURE - . '\': ' . $errorMsgs[Validator::INVALID_URL] .'</error>'; - } + $errorMsg = $this->validateUrl($value, StoreConfigurationDataMapper::KEY_BASE_URL_SECURE); + if ($errorMsg !== '') { + $errors[] = $errorMsg; } - if (empty($errorMsgs) && strpos($value, 'https:') === false) { + if (empty($errorMsg) && strpos($value, 'https:') === false) { throw new LocalizedException(new \Magento\Framework\Phrase("Invalid secure URL.")); } } catch (LocalizedException $e) { @@ -310,4 +299,26 @@ class InstallStoreConfigurationCommand extends AbstractSetupCommand } return $errorMsg; } + + /** + * Validate URL + * + * @param string $url + * @param string $option + * @return string + */ + private function validateUrl($url, $option) + { + $errorMsg = ''; + + if (!filter_var($url, FILTER_VALIDATE_URL)) { + $errorMsg = sprintf( + '<error>Command option \'%s\': Invalid URL \'%s\'.</error>', + $option, + $url + ); + } + + return $errorMsg; + } } diff --git a/setup/src/Magento/Setup/Controller/UrlCheck.php b/setup/src/Magento/Setup/Controller/UrlCheck.php new file mode 100644 index 0000000000000000000000000000000000000000..f7bee654c186338546b82bf44f8d60e496becb48 --- /dev/null +++ b/setup/src/Magento/Setup/Controller/UrlCheck.php @@ -0,0 +1,42 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Setup\Controller; + +use Zend\Mvc\Controller\AbstractActionController; +use Zend\View\Model\JsonModel; +use Zend\Json\Json; + +class UrlCheck extends AbstractActionController +{ + /** + * Validate URL + * + * @return JsonModel + */ + public function indexAction() + { + $params = Json::decode($this->getRequest()->getContent(), Json::TYPE_ARRAY); + $result = ['successUrl' => false, 'successSecureUrl' => true]; + + // Validating of Base URL + if (isset($params['address']['actual_base_url']) + && filter_var($params['address']['actual_base_url'], FILTER_VALIDATE_URL) + ) { + $result['successUrl'] = true; + } + + // Validating of Secure Base URL + if (!empty($params['https']['admin']) || !empty($params['https']['front'])) { + if (!(isset($params['https']['text']) + && filter_var($params['https']['text'], FILTER_VALIDATE_URL)) + ) { + $result['successSecureUrl'] = false; + } + } + + return new JsonModel(array_merge($result)); + } +} diff --git a/setup/src/Magento/Setup/Test/Unit/Console/Command/InstallStoreConfigurationCommandTest.php b/setup/src/Magento/Setup/Test/Unit/Console/Command/InstallStoreConfigurationCommandTest.php index 6f5ab3a5a64c537751cc8964229e35869b06c8e5..17ba8b11d551b46e319d20ed2b0cccc8a6172564 100644 --- a/setup/src/Magento/Setup/Test/Unit/Console/Command/InstallStoreConfigurationCommandTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Console/Command/InstallStoreConfigurationCommandTest.php @@ -155,7 +155,12 @@ class InstallStoreConfigurationCommandTest extends \PHPUnit_Framework_TestCase return [ [ ['--' . StoreConfigurationDataMapper::KEY_BASE_URL => 'sampleUrl'], - 'Command option \'' . StoreConfigurationDataMapper::KEY_BASE_URL . '\': Invalid URL.' + 'Command option \'' . StoreConfigurationDataMapper::KEY_BASE_URL . '\': Invalid URL \'sampleUrl\'.' + ], + [ + ['--' . StoreConfigurationDataMapper::KEY_BASE_URL => 'http://example.com_test'], + 'Command option \'' . StoreConfigurationDataMapper::KEY_BASE_URL + . '\': Invalid URL \'http://example.com_test\'.' ], [ ['--' . StoreConfigurationDataMapper::KEY_LANGUAGE => 'sampleLanguage'], @@ -187,6 +192,11 @@ class InstallStoreConfigurationCommandTest extends \PHPUnit_Framework_TestCase 'Command option \'' . StoreConfigurationDataMapper::KEY_BASE_URL_SECURE . '\': Invalid secure URL.' ], + [ + ['--' . StoreConfigurationDataMapper::KEY_BASE_URL_SECURE => 'https://sample.com_test'], + 'Command option \'' . StoreConfigurationDataMapper::KEY_BASE_URL_SECURE + . '\': Invalid URL \'https://sample.com_test\'.' + ], [ ['--' . StoreConfigurationDataMapper::KEY_IS_SECURE_ADMIN => 'invalidValue'], 'Command option \'' . StoreConfigurationDataMapper::KEY_IS_SECURE_ADMIN @@ -197,6 +207,7 @@ class InstallStoreConfigurationCommandTest extends \PHPUnit_Framework_TestCase 'Command option \'' . StoreConfigurationDataMapper::KEY_ADMIN_USE_SECURITY_KEY . '\': Invalid value. Possible values (0|1).' ], + ]; } } diff --git a/setup/src/Magento/Setup/Test/Unit/Controller/UrlCheckTest.php b/setup/src/Magento/Setup/Test/Unit/Controller/UrlCheckTest.php new file mode 100644 index 0000000000000000000000000000000000000000..bad4ce0f0356db098dfbc387c0fec710f0833a7c --- /dev/null +++ b/setup/src/Magento/Setup/Test/Unit/Controller/UrlCheckTest.php @@ -0,0 +1,114 @@ +<?php +/** + * Copyright © 2016 Magento. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Setup\Test\Unit\Controller; + +use Magento\Setup\Controller\UrlCheck; +use Zend\Stdlib\RequestInterface; +use Zend\View\Model\JsonModel; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; + +class UrlCheckTest extends \PHPUnit_Framework_TestCase +{ + /** + * @param string $requestJson + * @param array $expectedResult + * @dataProvider indexActionDataProvider + */ + public function testIndexAction($requestJson, $expectedResult) + { + /** @var ObjectManagerHelper $objectManagerHelper */ + $objectManagerHelper = new ObjectManagerHelper($this); + + /** @var RequestInterface|\PHPUnit_Framework_MockObject_MockObject $requestMock */ + $requestMock = $this->getMockBuilder(RequestInterface::class) + ->getMockForAbstractClass(); + $requestMock->expects($this->once()) + ->method('getContent') + ->willReturn($requestJson); + + $controller = $objectManagerHelper->getObject(UrlCheck::class); + $objectManagerHelper->setBackwardCompatibleProperty($controller, 'request', $requestMock); + + $this->assertEquals(new JsonModel($expectedResult), $controller->indexAction()); + } + + /** + * @return array + */ + public function indexActionDataProvider() + { + return [ + [ + 'requestJson' => json_encode([ + 'address' => [ + 'actual_base_url' => 'http://localhost' + ] + ]), + 'expectedResult' => ['successUrl' => true, 'successSecureUrl' => true] + ], + [ + 'requestJson' => json_encode([ + 'address' => [ + 'actual_base_url' => 'http://localhost.com_test' + ] + ]), + 'expectedResult' => ['successUrl' => false, 'successSecureUrl' => true] + ], + [ + 'requestJson' => json_encode([ + 'address' => [ + 'actual_base_url' => 'http://localhost.com_test' + ], + 'https' => [ + 'admin' => false, + 'front' => false, + 'text' => '' + ] + ]), + 'expectedResult' => ['successUrl' => false, 'successSecureUrl' => true] + ], + [ + 'requestJson' => json_encode([ + 'address' => [ + 'actual_base_url' => 'http://localhost.com:8080' + ], + 'https' => [ + 'admin' => true, + 'front' => false, + 'text' => 'https://example.com.ua/' + ] + ]), + 'expectedResult' => ['successUrl' => true, 'successSecureUrl' => true] + ], + [ + 'requestJson' => json_encode([ + 'address' => [ + 'actual_base_url' => 'http://localhost.com:8080/folder_name/' + ], + 'https' => [ + 'admin' => false, + 'front' => true, + 'text' => 'https://example.com.ua/' + ] + ]), + 'expectedResult' => ['successUrl' => true, 'successSecureUrl' => true] + ], + [ + 'requestJson' => json_encode([ + 'address' => [ + 'actual_base_url' => 'http://localhost.com:8080/folder_name/' + ], + 'https' => [ + 'admin' => true, + 'front' => true, + 'text' => 'https://example.com.ua:8090/folder_name/' + ] + ]), + 'expectedResult' => ['successUrl' => true, 'successSecureUrl' => true] + ], + ]; + } +} diff --git a/setup/view/magento/setup/web-configuration.phtml b/setup/view/magento/setup/web-configuration.phtml index 35aa19484ed53f39bf37ae0e90e7b76c7f5efe87..ab2a00342b715b05f215d1d3e12010b0fc4993cc 100644 --- a/setup/view/magento/setup/web-configuration.phtml +++ b/setup/view/magento/setup/web-configuration.phtml @@ -30,7 +30,7 @@ $hints = [ <div class="nav-bar-outer-actions"> <div class="outer-actions-inner-wrap"> <div class="btn-wrap btn-wrap-triangle-right btn-wrap-next"> - <button type="button" class="btn btn-prime" ng-click="nextState()" dis>Next</button> + <button type="button" class="btn btn-prime" ng-click="validateUrl()" dis>Next</button> </div> <div class="btn-wrap btn-wrap-triangle-left btn-wrap-prev"> <button type="button" class="btn" ng-click="previousState()">Back</button> @@ -40,6 +40,13 @@ $hints = [ <h2 class="page-sub-title">{{$state.current.header}}</h2> +<div + class="message message-error" + ng-show="validateUrl.failed !== undefined" +> + <span class="message-text">{{validateUrl.failed}}</span> +</div> + <form name="webconfig" role="form"