Skip to content

Commit aecf615

Browse files
AC-9883: Fix Catalog System Config
1 parent 3950014 commit aecf615

File tree

6 files changed

+96
-39
lines changed

6 files changed

+96
-39
lines changed

app/code/Magento/Config/Model/Config/Backend/File.php

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
declare(strict_types=1);
7+
68
namespace Magento\Config\Model\Config\Backend;
79

810
use Exception;
@@ -94,12 +96,20 @@ public function beforeSave()
9496
if (!empty($file)) {
9597
$uploadDir = $this->_getUploadDir();
9698
try {
99+
// sanitize filename
100+
$fileName = strtolower(
101+
preg_replace(
102+
['#[\\s-]+#', '#[^A-Za-z0-9._ -]+#'],
103+
['-', ''],
104+
$file['name']
105+
)
106+
);
97107
/** @var Uploader $uploader */
98108
$uploader = $this->_uploaderFactory->create(['fileId' => $file]);
99109
$uploader->setAllowedExtensions($this->_getAllowedExtensions());
100110
$uploader->setAllowRenameFiles(true);
101111
$uploader->addValidateCallback('size', $this, 'validateMaxSize');
102-
$result = $uploader->save($uploadDir);
112+
$result = $uploader->save($uploadDir, $fileName);
103113
} catch (Exception $e) {
104114
throw new LocalizedException(__('%1', $e->getMessage()));
105115
}
@@ -114,7 +124,7 @@ public function beforeSave()
114124
if (is_array($value) && !empty($value['delete'])) {
115125
$this->setValue('');
116126
} elseif (is_array($value) && !empty($value['value'])) {
117-
$this->setValue($value['value']);
127+
$this->setValueAfterValidation($value['value']);
118128
} else {
119129
$this->unsValue();
120130
}
@@ -266,4 +276,21 @@ protected function _getAllowedExtensions()
266276
{
267277
return [];
268278
}
279+
280+
/**
281+
* Validate if the value is intercepted
282+
*
283+
* @param string $value
284+
* @return void
285+
* @throws LocalizedException
286+
*/
287+
private function setValueAfterValidation($value)
288+
{
289+
// avoid intercepting value
290+
if (!preg_match('/^[A-Za-z0-9._\/ -]*$/', $value)) {
291+
throw new LocalizedException(__('%1', 'Invalid file name'));
292+
}
293+
294+
$this->setValue($value);
295+
}
269296
}

app/code/Magento/Config/Test/Unit/Model/Config/Backend/FileTest.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ public function testBeforeSave()
152152
->willReturn($this->uploaderMock);
153153
$this->uploaderMock->expects($this->once())
154154
->method('save')
155-
->with($uploadDir . '/' . $scope . '/' . $scopeId, null)
155+
->with($uploadDir . '/' . $scope . '/' . $scopeId, $name)
156156
->willReturn($result);
157157

158158
$this->assertEquals($this->model, $this->model->beforeSave());
@@ -197,7 +197,7 @@ public function testBeforeWithoutRequest()
197197
->willReturn($this->uploaderMock);
198198
$this->uploaderMock->expects($this->once())
199199
->method('save')
200-
->with($uploadDir, null)
200+
->with($uploadDir, $name)
201201
->willReturn($result);
202202

203203
$this->assertEquals($this->model, $this->model->beforeSave());
@@ -300,7 +300,7 @@ public function testBeforeSaveWithException()
300300
->willReturn($this->uploaderMock);
301301
$this->uploaderMock->expects($this->once())
302302
->method('save')
303-
->with($uploadDir, null)
303+
->with($uploadDir, $name)
304304
->willThrowException(new \Exception($exception));
305305

306306
$this->model->beforeSave();

app/code/Magento/Config/Test/Unit/Model/Config/Backend/Image/LogoTest.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ protected function setUp(): void
5656
->willReturn($this->uploaderMock);
5757
$this->requestDataMock = $this
5858
->getMockBuilder(RequestDataInterface::class)
59-
->setMethods(['getTmpName'])
59+
->setMethods(['getTmpName', 'getName'])
6060
->getMockForAbstractClass();
6161
$mediaDirectoryMock = $this->getMockBuilder(WriteInterface::class)
6262
->disableOriginalConstructor()
@@ -83,6 +83,9 @@ public function testBeforeSave()
8383
$this->requestDataMock->expects($this->once())
8484
->method('getTmpName')
8585
->willReturn('/tmp/val');
86+
$this->requestDataMock->expects($this->once())
87+
->method('getName')
88+
->willReturn('filename');
8689
$this->uploaderMock->expects($this->once())
8790
->method('setAllowedExtensions')
8891
->with(['jpg', 'jpeg', 'gif', 'png']);

app/code/Magento/Config/i18n/en_US.csv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,3 +122,4 @@ Dashboard,Dashboard
122122
"Web Section","Web Section"
123123
"Store Email Addresses Section","Store Email Addresses Section"
124124
"Email to a Friend","Email to a Friend"
125+
"Invalid file name", "Invalid file name"

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

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
use Magento\Framework\App\ObjectManager;
1111
use Magento\Framework\Escaper;
12+
use Magento\Framework\Exception\LocalizedException;
1213
use Magento\Framework\Math\Random;
1314
use Magento\Framework\UrlInterface;
1415
use Magento\Framework\View\Helper\SecureHtmlRenderer;
@@ -66,35 +67,33 @@ public function __construct(
6667
* Return element html code
6768
*
6869
* @return string
70+
* @throws LocalizedException
6971
*/
7072
public function getElementHtml()
7173
{
7274
$html = '';
7375

74-
if ((string)$this->getValue()) {
76+
if ((string)$this->getEscapedValue()) {
7577
$url = $this->_getUrl();
7678

7779
if (!preg_match("/^http\:\/\/|https\:\/\//", $url)) {
7880
$url = $this->_urlBuilder->getBaseUrl(['_type' => UrlInterface::URL_TYPE_MEDIA]) . $url;
7981
}
8082

8183
$linkId = 'linkId' .$this->random->getRandomString(8);
82-
$html = '<a previewlinkid="' .$linkId .'" href="' .
83-
$url .
84-
'" ' .
84+
$html = '<a previewlinkid="' .$linkId .'" href="' .
85+
$url . '" ' .
8586
$this->_getUiId(
8687
'link'
8788
) .
8889
'>' .
89-
'<img src="' .
90-
$url .
91-
'" id="' .
90+
'<img src="' . $url . '" id="' .
9291
$this->getHtmlId() .
9392
'_image" title="' .
94-
$this->getValue() .
93+
$this->getEscapedValue() .
9594
'"' .
9695
' alt="' .
97-
$this->getValue() .
96+
$this->getEscapedValue() .
9897
'" height="22" width="22" class="small-image-preview v-middle" ' .
9998
$this->_getUiId() .
10099
' />' .
@@ -120,7 +119,7 @@ public function getElementHtml()
120119
protected function _getDeleteCheckbox()
121120
{
122121
$html = '';
123-
if ($this->getValue()) {
122+
if ($this->getEscapedValue()) {
124123
$label = (string)new \Magento\Framework\Phrase('Delete Image');
125124
$html .= '<span class="delete-image">';
126125
$html .= '<input type="checkbox"' .
@@ -153,7 +152,8 @@ protected function _getDeleteCheckbox()
153152
*/
154153
protected function _getHiddenInput()
155154
{
156-
return '<input type="hidden" name="' . parent::getName() . '[value]" value="' . $this->getValue() . '" />';
155+
return '<input type="hidden" name="' . parent::getName() .
156+
'[value]" value="' . $this->getEscapedValue() . '" />';
157157
}
158158

159159
/**
@@ -163,7 +163,7 @@ protected function _getHiddenInput()
163163
*/
164164
protected function _getUrl()
165165
{
166-
return $this->getValue();
166+
return $this->getEscapedValue();
167167
}
168168

169169
/**

lib/internal/Magento/Framework/Data/Test/Unit/Form/Element/ImageTest.php

Lines changed: 47 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515
use Magento\Framework\Data\Form\Element\Image;
1616
use Magento\Framework\DataObject;
1717
use Magento\Framework\Escaper;
18+
use Magento\Framework\Math\Random;
19+
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
1820
use Magento\Framework\Url;
19-
use Magento\Framework\UrlInterface;
21+
use Magento\Framework\View\Helper\SecureHtmlRenderer;
2022
use PHPUnit\Framework\MockObject\MockObject;
2123
use PHPUnit\Framework\TestCase;
22-
use Magento\Framework\Math\Random;
23-
use Magento\Framework\View\Helper\SecureHtmlRenderer;
2424

2525
/**
2626
* Test for the widget.
@@ -44,11 +44,16 @@ class ImageTest extends TestCase
4444
*/
4545
protected $_image;
4646

47+
/**
48+
* @var array
49+
*/
50+
protected $testData;
51+
4752
protected function setUp(): void
4853
{
54+
$objectManager = new ObjectManager($this);
4955
$factoryMock = $this->createMock(Factory::class);
5056
$collectionFactoryMock = $this->createMock(CollectionFactory::class);
51-
$escaperMock = $this->createMock(Escaper::class);
5257
$this->urlBuilder = $this->createMock(Url::class);
5358
$randomMock = $this->createMock(Random::class);
5459
$randomMock->method('getRandomString')->willReturn('some-rando-string');
@@ -67,18 +72,28 @@ function (string $tag, array $attrs, ?string $content): string {
6772
return "<$tag {$attrs->serialize()}>$content</$tag>";
6873
}
6974
);
70-
$this->_image = new Image(
71-
$factoryMock,
72-
$collectionFactoryMock,
73-
$escaperMock,
74-
$this->urlBuilder,
75-
[],
76-
$secureRendererMock,
77-
$randomMock
75+
$this->_image = $objectManager->getObject(
76+
Image::class,
77+
[
78+
'factoryMock'=>$factoryMock,
79+
'collectionFactoryMock'=>$collectionFactoryMock,
80+
'urlBuilder' => $this->urlBuilder,
81+
'_escaper' => $objectManager->getObject(Escaper::class),
82+
'random' => $randomMock,
83+
'secureRenderer' => $secureRendererMock,
84+
]
7885
);
86+
$this->testData = [
87+
'html_id_prefix' => 'test_id_prefix_',
88+
'html_id' => 'test_id',
89+
'html_id_suffix' => '_test_id_suffix',
90+
'path' => 'catalog/product/placeholder',
91+
'value' => 'test_value',
92+
];
93+
7994
$formMock = new DataObject();
80-
$formMock->getHtmlIdPrefix('id_prefix');
81-
$formMock->getHtmlIdPrefix('id_suffix');
95+
$formMock->getHtmlIdPrefix($this->testData['html_id_prefix']);
96+
$formMock->getHtmlIdPrefix($this->testData['html_id_suffix']);
8297
$this->_image->setForm($formMock);
8398
}
8499

@@ -117,21 +132,32 @@ public function testGetElementHtmlWithoutValue()
117132
*/
118133
public function testGetElementHtmlWithValue()
119134
{
120-
$this->_image->setValue('test_value');
121-
$this->urlBuilder->expects($this->once())
122-
->method('getBaseUrl')
123-
->with(['_type' => UrlInterface::URL_TYPE_MEDIA])
124-
->willReturn('http://localhost/media/');
135+
$url = 'http://test.example.com/media/';
136+
137+
$this->_image->setValue($this->testData['value']);
138+
$this->_image->setHtmlId($this->testData['html_id']);
139+
140+
$this->urlBuilder->expects($this->once())->method('getBaseUrl')
141+
->with(['_type' => UrlInterface::URL_TYPE_MEDIA])->willReturn($url);
142+
143+
$expectedHtmlId = $this->testData['html_id'];
144+
125145
$html = $this->_image->getElementHtml();
146+
126147
$this->assertStringContainsString('class="input-file"', $html);
127148
$this->assertStringContainsString('<input', $html);
128149
$this->assertStringContainsString('type="file"', $html);
129150
$this->assertStringContainsString('value="test_value"', $html);
151+
130152
$this->assertStringContainsString(
131-
'<a previewlinkid="linkIdsome-rando-string" href="http://localhost/media/test_value"',
153+
'<a previewlinkid="linkIdsome-rando-string" href="'
154+
. $url
155+
. $this->testData['value']
156+
. '"',
132157
$html
133158
);
134-
$this->assertStringContainsString("imagePreview('_image');\nreturn false;", $html);
159+
160+
$this->assertStringContainsString("imagePreview('{$expectedHtmlId}_image');\nreturn false;", $html);
135161
$this->assertStringContainsString('<input type="checkbox"', $html);
136162
}
137163
}

0 commit comments

Comments
 (0)