Skip to content

Commit b67d77d

Browse files
authored
Merge pull request #3346 from magento-honey-badgers/2.3.0-qwerty-bugs
[honey] MAGETWO-95645: PHP Files Can Be Uploaded via File (attachment) Customer Attributes
2 parents 7acd03d + 35a375d commit b67d77d

File tree

8 files changed

+198
-13
lines changed

8 files changed

+198
-13
lines changed

app/code/Magento/CatalogGraphQl/Model/Resolver/Products/Query/Search.php

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
use Magento\CatalogGraphQl\Model\Resolver\Products\SearchCriteria\Helper\Filter as FilterHelper;
1313
use Magento\CatalogGraphQl\Model\Resolver\Products\SearchResult;
1414
use Magento\CatalogGraphQl\Model\Resolver\Products\SearchResultFactory;
15-
use Magento\Framework\EntityManager\EntityManager;
1615
use Magento\Search\Api\SearchInterface;
1716

1817
/**
@@ -45,31 +44,42 @@ class Search
4544
*/
4645
private $metadataPool;
4746

47+
/**
48+
* @var \Magento\Search\Model\Search\PageSizeProvider
49+
*/
50+
private $pageSizeProvider;
51+
4852
/**
4953
* @param SearchInterface $search
5054
* @param FilterHelper $filterHelper
5155
* @param Filter $filterQuery
5256
* @param SearchResultFactory $searchResultFactory
57+
* @param \Magento\Framework\EntityManager\MetadataPool $metadataPool
58+
* @param \Magento\Search\Model\Search\PageSizeProvider $pageSize
5359
*/
5460
public function __construct(
5561
SearchInterface $search,
5662
FilterHelper $filterHelper,
5763
Filter $filterQuery,
5864
SearchResultFactory $searchResultFactory,
59-
\Magento\Framework\EntityManager\MetadataPool $metadataPool
65+
\Magento\Framework\EntityManager\MetadataPool $metadataPool,
66+
\Magento\Search\Model\Search\PageSizeProvider $pageSize
6067
) {
6168
$this->search = $search;
6269
$this->filterHelper = $filterHelper;
6370
$this->filterQuery = $filterQuery;
6471
$this->searchResultFactory = $searchResultFactory;
6572
$this->metadataPool = $metadataPool;
73+
$this->pageSizeProvider = $pageSize;
6674
}
6775

6876
/**
6977
* Return results of full text catalog search of given term, and will return filtered results if filter is specified
7078
*
7179
* @param SearchCriteriaInterface $searchCriteria
80+
* @param ResolveInfo $info
7281
* @return SearchResult
82+
* @throws \Exception
7383
*/
7484
public function getResult(SearchCriteriaInterface $searchCriteria, ResolveInfo $info) : SearchResult
7585
{
@@ -79,7 +89,8 @@ public function getResult(SearchCriteriaInterface $searchCriteria, ResolveInfo $
7989
$realPageSize = $searchCriteria->getPageSize();
8090
$realCurrentPage = $searchCriteria->getCurrentPage();
8191
// Current page must be set to 0 and page size to max for search to grab all ID's as temporary workaround
82-
$searchCriteria->setPageSize(PHP_INT_MAX);
92+
$pageSize = $this->pageSizeProvider->getMaxPageSize();
93+
$searchCriteria->setPageSize($pageSize);
8394
$searchCriteria->setCurrentPage(0);
8495
$itemsResults = $this->search->search($searchCriteria);
8596

app/code/Magento/Eav/Model/Attribute/Data/File.php

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,7 @@ public function extractValue(RequestInterface $request)
120120
}
121121

122122
/**
123-
* Validate file by attribute validate rules
124-
* Return array of errors
123+
* Validate file by attribute validate rules and return array of errors
125124
*
126125
* @param array $value
127126
* @return string[]
@@ -147,7 +146,7 @@ protected function _validateByRules($value)
147146
return $this->_fileValidator->getMessages();
148147
}
149148

150-
if (!is_uploaded_file($value['tmp_name'])) {
149+
if (!empty($value['tmp_name']) && !is_uploaded_file($value['tmp_name'])) {
151150
return [__('"%1" is not a valid file.', $label)];
152151
}
153152

@@ -174,12 +173,22 @@ public function validateValue($value)
174173
if ($this->getIsAjaxRequest()) {
175174
return true;
176175
}
176+
$fileData = $value;
177+
178+
if (is_string($value) && !empty($value)) {
179+
$dir = $this->_directory->getAbsolutePath($this->getAttribute()->getEntityType()->getEntityTypeCode());
180+
$fileData = [
181+
'size' => filesize($dir . $value),
182+
'name' => $value,
183+
'tmp_name' => $dir . $value
184+
];
185+
}
177186

178187
$errors = [];
179188
$attribute = $this->getAttribute();
180189

181190
$toDelete = !empty($value['delete']) ? true : false;
182-
$toUpload = !empty($value['tmp_name']) ? true : false;
191+
$toUpload = !empty($value['tmp_name']) || is_string($value) && !empty($value) ? true : false;
183192

184193
if (!$toUpload && !$toDelete && $this->getEntity()->getData($attribute->getAttributeCode())) {
185194
return true;
@@ -195,11 +204,13 @@ public function validateValue($value)
195204
}
196205

197206
if ($toUpload) {
198-
$errors = array_merge($errors, $this->_validateByRules($value));
207+
$errors = array_merge($errors, $this->_validateByRules($fileData));
199208
}
200209

201210
if (count($errors) == 0) {
202211
return true;
212+
} elseif (is_string($value) && !empty($value)) {
213+
$this->_directory->delete($dir . $value);
203214
}
204215

205216
return $errors;

app/code/Magento/Elasticsearch/etc/di.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,4 +413,12 @@
413413
<argument name="fieldTypeResolver" xsi:type="object">\Magento\Elasticsearch\Elasticsearch5\Model\Adapter\FieldMapper\Product\FieldProvider\FieldType\Resolver\CompositeResolver</argument>
414414
</arguments>
415415
</type>
416+
<type name="Magento\Search\Model\Search\PageSizeProvider">
417+
<arguments>
418+
<argument name="pageSizeBySearchEngine" xsi:type="array">
419+
<item name="elasticsearch" xsi:type="number">2147483647</item>
420+
<item name="elasticsearch5" xsi:type="number">2147483647</item>
421+
</argument>
422+
</arguments>
423+
</type>
416424
</config>
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Search\Model\Search;
9+
10+
/**
11+
* Returns max page size by search engine name
12+
* @api
13+
*/
14+
class PageSizeProvider
15+
{
16+
/**
17+
* @var \Magento\Search\Model\EngineResolver
18+
*/
19+
private $engineResolver;
20+
21+
/**
22+
* @var array
23+
*/
24+
private $pageSizeBySearchEngine;
25+
26+
/**
27+
* @param \Magento\Search\Model\EngineResolver $engineResolver
28+
* @param array $pageSizeBySearchEngine
29+
*/
30+
public function __construct(
31+
\Magento\Search\Model\EngineResolver $engineResolver,
32+
array $pageSizeBySearchEngine = []
33+
) {
34+
$this->engineResolver = $engineResolver;
35+
$this->pageSizeBySearchEngine = $pageSizeBySearchEngine;
36+
}
37+
38+
/**
39+
* Returns max_page_size depends on engine
40+
*
41+
* @return integer
42+
*/
43+
public function getMaxPageSize() : int
44+
{
45+
$searchEngine = $this->engineResolver->getCurrentSearchEngine();
46+
47+
$pageSize = PHP_INT_MAX;
48+
if (isset($this->pageSizeBySearchEngine[$searchEngine])) {
49+
$pageSize = $this->pageSizeBySearchEngine[$searchEngine];
50+
}
51+
52+
return (int)$pageSize;
53+
}
54+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Search\Test\Unit\Model\Search;
9+
10+
use Magento\Search\Model\Search\PageSizeProvider;
11+
12+
class PageSizeProviderTest extends \PHPUnit\Framework\TestCase
13+
{
14+
/**
15+
* @var PageSizeProvider
16+
*/
17+
private $model;
18+
19+
/**
20+
* @var \Magento\Search\Model\EngineResolver|\PHPUnit_Framework_MockObject_MockObject
21+
*/
22+
private $pageSizeBySearchEngineMock;
23+
24+
public function setUp()
25+
{
26+
$this->pageSizeBySearchEngineMock = $this->getMockBuilder(\Magento\Search\Model\EngineResolver::class)
27+
->disableOriginalConstructor()
28+
->getMock();
29+
30+
$this->model = new PageSizeProvider(
31+
32+
$this->pageSizeBySearchEngineMock,
33+
['search' => 10,
34+
'catalogSearch3' => 11
35+
]
36+
);
37+
}
38+
39+
/**
40+
* @param string $searchEngine
41+
* @param int $size
42+
* @dataProvider getPageSizeDataProvider
43+
*/
44+
public function testGetPageSize($searchEngine, $size)
45+
{
46+
$this->pageSizeBySearchEngineMock
47+
->expects($this->once())
48+
->method('getCurrentSearchEngine')
49+
->willReturn($searchEngine);
50+
$this->assertEquals($size, $this->model->getMaxPageSize());
51+
}
52+
53+
public function getPageSizeDataProvider()
54+
{
55+
return [
56+
['search', 10],
57+
['catalogSearch3', 11],
58+
['newSearch', PHP_INT_MAX]
59+
];
60+
}
61+
}

dev/tests/js/jasmine/tests/lib/mage/validation.test.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1142,4 +1142,24 @@ define([
11421142
)).toEqual(true);
11431143
});
11441144
});
1145+
1146+
describe('Testing validate-forbidden-extensions', function () {
1147+
it('validate-forbidden-extensions', function () {
1148+
var el1 = $('<input type="text" value="" ' +
1149+
'class="validate-extensions" data-validation-params="php,phtml">').get(0);
1150+
1151+
expect($.validator.methods['validate-forbidden-extensions']
1152+
.call($.validator.prototype, 'php', el1, null)).toEqual(false);
1153+
expect($.validator.methods['validate-forbidden-extensions']
1154+
.call($.validator.prototype, 'php,phtml', el1, null)).toEqual(false);
1155+
expect($.validator.methods['validate-forbidden-extensions']
1156+
.call($.validator.prototype, 'html', el1, null)).toEqual(true);
1157+
expect($.validator.methods['validate-forbidden-extensions']
1158+
.call($.validator.prototype, 'html,png', el1, null)).toEqual(true);
1159+
expect($.validator.methods['validate-forbidden-extensions']
1160+
.call($.validator.prototype, 'php,html', el1, null)).toEqual(false);
1161+
expect($.validator.methods['validate-forbidden-extensions']
1162+
.call($.validator.prototype, 'html,php', el1, null)).toEqual(false);
1163+
});
1164+
});
11451165
});

lib/internal/Magento/Framework/Data/Form/Element/Text.php

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,13 @@
44
* See COPYING.txt for license details.
55
*/
66

7-
/**
8-
* Form text element
9-
*
10-
* @author Magento Core Team <[email protected]>
11-
*/
127
namespace Magento\Framework\Data\Form\Element;
138

149
use Magento\Framework\Escaper;
1510

11+
/**
12+
* Form text element
13+
*/
1614
class Text extends AbstractElement
1715
{
1816
/**
@@ -65,6 +63,7 @@ public function getHtmlAttributes()
6563
'placeholder',
6664
'data-form-part',
6765
'data-role',
66+
'data-validation-params',
6867
'data-action'
6968
];
7069
}

lib/web/mage/validation.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -881,6 +881,27 @@
881881
},
882882
$.mage.__('Please enter a valid number in this field.')
883883
],
884+
'validate-forbidden-extensions': [
885+
function (v, elem) {
886+
var forbiddenExtensions = $(elem).attr('data-validation-params'),
887+
forbiddenExtensionsArray = forbiddenExtensions.split(','),
888+
extensionsArray = v.split(','),
889+
result = true;
890+
891+
this.validateExtensionsMessage = $.mage.__('Forbidden extensions has been used. Avoid usage of ') +
892+
forbiddenExtensions;
893+
894+
$.each(extensionsArray, function (key, extension) {
895+
if (forbiddenExtensionsArray.indexOf(extension) !== -1) {
896+
result = false;
897+
}
898+
});
899+
900+
return result;
901+
}, function () {
902+
return this.validateExtensionsMessage;
903+
}
904+
],
884905
'validate-digits-range': [
885906
function (v, elm, param) {
886907
var numValue, dataAttrRange, classNameRange, result, range, m, classes, ii;

0 commit comments

Comments
 (0)