Commit 7c44b28c authored by Pierre RAMBAUD's avatar Pierre RAMBAUD
Browse files

Do not use invalid order by or order way parameters

parent 6c9c2f1c
......@@ -35,6 +35,8 @@ use Symfony\Component\Validator\Validation;
class ValidateCore
{
public const ORDER_BY_REGEXP = '/^(?:(`?)[\w!_-]+\1\.)?(?:(`?)[\w!_-]+\2)$/';
const ADMIN_PASSWORD_LENGTH = 8;
const PASSWORD_LENGTH = 5;
......@@ -774,7 +776,7 @@ class ValidateCore
*/
public static function isOrderBy($order)
{
return preg_match('/^[a-zA-Z0-9.!_-]+$/', $order);
return preg_match(static::ORDER_BY_REGEXP, $order);
}
/**
......
......@@ -76,15 +76,17 @@ final class CmsPageCategoryQueryBuilder extends AbstractDoctrineQueryBuilder
public function getSearchQueryBuilder(SearchCriteriaInterface $searchCriteria)
{
$qb = $this->getQueryBuilder($searchCriteria->getFilters());
$qb
->select('cc.`id_cms_category`, cc.`id_parent`, cc.`active`, cc.`position`, ccl.`name`, ccl.`description`')
->groupBy('cc.`id_cms_category`')
->orderBy(
$this->getModifiedOrderBy($searchCriteria->getOrderBy()),
->groupBy('cc.`id_cms_category`');
$orderBy = $this->getModifiedOrderBy($searchCriteria->getOrderBy());
if (!empty($orderBy)) {
$qb->orderBy(
$orderBy,
$searchCriteria->getOrderWay()
)
;
);
}
$this->searchCriteriaApplicator->applyPagination($searchCriteria, $qb);
......@@ -189,7 +191,7 @@ final class CmsPageCategoryQueryBuilder extends AbstractDoctrineQueryBuilder
private function getModifiedOrderBy($orderBy)
{
if ('id_cms_category' === $orderBy) {
$orderBy = 'cc.`id_cms_category`';
$orderBy = 'cc.id_cms_category';
}
return $orderBy;
......
......@@ -81,12 +81,17 @@ final class WebserviceKeyQueryBuilder extends AbstractDoctrineQueryBuilder
public function getSearchQueryBuilder(SearchCriteriaInterface $searchCriteria)
{
$qb = $this->getQueryBuilder($searchCriteria->getFilters());
$qb->select('wa.`id_webservice_account`, wa.`key`, wa.`description`, wa.`active`')
->orderBy(
$this->getModifiedOrderBy($searchCriteria->getOrderBy()),
$qb->select('wa.`id_webservice_account`, wa.`key`, wa.`description`, wa.`active`');
$orderBy = $searchCriteria->getOrderBy();
if (!empty($orderBy)) {
$qb->orderBy(
$this->getModifiedOrderBy($orderBy),
$searchCriteria->getOrderWay()
)
->groupBy('wa.`id_webservice_account`');
);
}
$qb->groupBy('wa.`id_webservice_account`');
$this->searchCriteriaApplicator->applyPagination($searchCriteria, $qb);
......@@ -146,6 +151,6 @@ final class WebserviceKeyQueryBuilder extends AbstractDoctrineQueryBuilder
*/
private function getModifiedOrderBy($orderBy)
{
return 'wa.`' . $orderBy . '`';
return 'wa.' . $orderBy;
}
}
......@@ -28,9 +28,10 @@ namespace PrestaShop\PrestaShop\Core\Search;
use PrestaShop\PrestaShop\Core\Grid\Search\SearchCriteriaInterface;
use Symfony\Component\HttpFoundation\ParameterBag;
use Validate;
/**
* This class is responsible of managing filters of Listing pages.
* This class is responsible for managing filters of Listing pages.
*/
class Filters extends ParameterBag implements SearchCriteriaInterface
{
......@@ -66,7 +67,7 @@ class Filters extends ParameterBag implements SearchCriteriaInterface
public static function getDefaults()
{
return [
'limit' => self::LIST_LIMIT,
'limit' => static::LIST_LIMIT,
'offset' => 0,
'orderBy' => null,
'sortOrder' => null,
......@@ -79,7 +80,12 @@ class Filters extends ParameterBag implements SearchCriteriaInterface
*/
public function getOrderBy()
{
return $this->get('orderBy');
$orderBy = $this->get('orderBy');
if (!Validate::isOrderBy($orderBy)) {
return null;
}
return $orderBy;
}
/**
......@@ -87,7 +93,12 @@ class Filters extends ParameterBag implements SearchCriteriaInterface
*/
public function getOrderWay()
{
return $this->get('sortOrder');
$orderWay = $this->get('sortOrder');
if (!Validate::isOrderWay(strtoupper($orderWay))) {
return null;
}
return $orderWay;
}
/**
......
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/
declare(strict_types=1);
namespace Tests\Resources;
use PrestaShop\PrestaShop\Core\Search\Filters;
class SampleFilters extends Filters
{
/**
* {@inheritdoc}
*/
public static function getDefaults()
{
return [
'limit' => 51,
'offset' => 42,
'orderBy' => 'id_sample',
'sortOrder' => 'desc',
'filters' => [],
];
}
}
......@@ -29,6 +29,7 @@ namespace Tests\Unit\Core\Search\Builder;
use PHPUnit\Framework\TestCase;
use PrestaShop\PrestaShop\Core\Search\Builder\ClassFiltersBuilder;
use PrestaShop\PrestaShop\Core\Search\Filters;
use Tests\Resources\SampleFilters;
class ClassFiltersBuilderTest extends TestCase
{
......@@ -83,20 +84,3 @@ class ClassFiltersBuilderTest extends TestCase
$this->assertInstanceOf(SampleFilters::class, $builtFilters);
}
}
class SampleFilters extends Filters
{
/**
* {@inheritdoc}
*/
public static function getDefaults()
{
return [
'limit' => 42,
'offset' => 0,
'orderBy' => 'id_sample',
'sortOrder' => 'desc',
'filters' => [],
];
}
}
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/
declare(strict_types=1);
namespace Tests\Unit\Core\Search;
use PHPUnit\Framework\TestCase;
use PrestaShop\PrestaShop\Core\Search\Filters;
use Tests\Resources\SampleFilters;
class FiltersTest extends TestCase
{
public function testFiltersBuildDefaults(): void
{
$filters = Filters::buildDefaults();
$this->assertEquals(0, $filters->getOffset());
$this->assertEquals(null, $filters->getOrderBy());
$this->assertEquals(null, $filters->getOrderWay());
$this->assertEquals(10, $filters->getLimit());
$this->assertEquals([], $filters->getFilters());
}
public function testSampleFiltersBuildDefaults(): void
{
$filters = SampleFilters::buildDefaults();
$this->assertEquals(42, $filters->getOffset());
$this->assertEquals('id_sample', $filters->getOrderBy());
$this->assertEquals('desc', $filters->getOrderWay());
$this->assertEquals(51, $filters->getLimit());
$this->assertEquals([], $filters->getFilters());
}
/**
* @dataProvider getValidOrderBy
*/
public function testValidOrderBy(string $validOrderBy): void
{
$filters = new SampleFilters(['orderBy' => $validOrderBy]);
$this->assertEquals($validOrderBy, $filters->getOrderBy());
$filters = new Filters(['orderBy' => $validOrderBy]);
$this->assertEquals($validOrderBy, $filters->getOrderBy());
}
public function getValidOrderBy(): iterable
{
yield ['test'];
yield ['test_underscore'];
yield ['test-hyphen'];
yield ['test-69'];
yield ['test-amazing!'];
yield ['ca.test'];
yield ['`ca`.test'];
yield ['ca.`test`'];
yield ['`ca`.`test`'];
}
/**
* @dataProvider getInvalidOrderBy
*/
public function testInvalidOrderByd(string $invalidOrderBy): void
{
$filters = new Filters(['orderBy' => $invalidOrderBy]);
$this->assertNull($filters->getOrderBy());
}
public function getInvalidOrderBy(): iterable
{
// Special characters are not accepted
yield ['test?'];
yield ['test$'];
yield ['test€'];
yield ['test%'];
yield ['test)'];
yield ['test('];
yield ['test '];
yield [' test'];
// Incorrect dots
yield ['.ca.test'];
yield ['ca.test.'];
// Opening back-quotes without closing (or vice versa)
yield ['`ca.test'];
yield ['ca`.test'];
yield ['ca.`test'];
yield ['ca.test`'];
yield ['`ca.test`'];
yield ['ca`.test`'];
// Back-quotes must wrap alias or column not open in the middle
yield ['test`test`'];
yield ['test`test`test'];
yield ['test`test`.test'];
yield ['test`test`test.test'];
yield ['ca.test`test`.'];
}
/**
* @dataProvider getValidOrderWay
*/
public function testSampleFiltersWithValidOrderWay(string $orderWay): void
{
$filters = new SampleFilters(['sortOrder' => $orderWay]);
$this->assertEquals($orderWay, $filters->getOrderWay());
$filters = new Filters(['sortOrder' => $orderWay]);
$this->assertEquals($orderWay, $filters->getOrderWay());
}
public function getValidOrderWay(): iterable
{
yield ['ASC'];
yield ['DESC'];
yield ['asc'];
yield ['desc'];
yield ['dEsC'];
yield ['AsC'];
}
/**
* @dataProvider getInvalidOrderWay
*/
public function testSampleFiltersWithInvalidOrderWay(string $orderWay): void
{
$filters = new Filters(['sortOrder' => $orderWay]);
$this->assertNull($filters->getOrderWay());
}
public function getInvalidOrderWay(): iterable
{
yield ['test'];
yield ['RAND()'];
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment