Skip to content

Commit 186ef13

Browse files
author
Yuri Kovsher
committed
MAGETWO-21201: CLONE - Apply SUPEE-1805: Issue with disablign allow_url_fopen using the CMS WYSIWYG editor (patch)
1 parent a437b12 commit 186ef13

File tree

8 files changed

+484
-13
lines changed

8 files changed

+484
-13
lines changed

app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Directive.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
namespace Magento\Cms\Controller\Adminhtml\Wysiwyg;
77

88
use Magento\Backend\App\Action;
9+
use SebastianBergmann\Exporter\Exception;
910

1011
class Directive extends \Magento\Backend\App\Action
1112
{
@@ -37,15 +38,16 @@ public function execute()
3738
{
3839
$directive = $this->getRequest()->getParam('___directive');
3940
$directive = $this->urlDecoder->decode($directive);
40-
$url = $this->_objectManager->create('Magento\Email\Model\Template\Filter')->filter($directive);
41+
$imagePath = $this->_objectManager->create('Magento\Cms\Model\Template\Filter')->filter($directive);
4142
/** @var \Magento\Framework\Image\Adapter\AdapterInterface $image */
4243
$image = $this->_objectManager->get('Magento\Framework\Image\AdapterFactory')->create();
4344
$response = $this->getResponse();
4445
try {
45-
$image->open($url);
46+
$image->open($imagePath);
4647
$response->setHeader('Content-Type', $image->getMimeType())->setBody($image->getImage());
4748
} catch (\Exception $e) {
48-
$image->open($this->_objectManager->get('Magento\Cms\Model\Wysiwyg\Config')->getSkinImagePlaceholderUrl());
49+
$imagePath = $this->_objectManager->get('Magento\Cms\Model\Wysiwyg\Config')->getSkinImagePlaceholderPath();
50+
$image->open($imagePath);
4951
$response->setHeader('Content-Type', $image->getMimeType())->setBody($image->getImage());
5052
$this->_objectManager->get('Psr\Log\LoggerInterface')->critical($e);
5153
}

app/code/Magento/Cms/Model/Template/Filter.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,10 @@ public function setUseSessionInUrl($flag)
2727
$this->_useSessionInUrl = (bool)$flag;
2828
return $this;
2929
}
30+
31+
public function mediaDirective($construction)
32+
{
33+
$params = $this->_getIncludeParameters($construction[2]);
34+
return $this->_storeManager->getStore()->getBaseMediaDir() . '/' . $params['url'];
35+
}
3036
}

app/code/Magento/Cms/Model/Wysiwyg/Config.php

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ class Config extends \Magento\Framework\Object
1919
*/
2020
const WYSIWYG_STATUS_CONFIG_PATH = 'cms/wysiwyg/enabled';
2121

22+
/**
23+
*
24+
*/
25+
const WYSIWYG_SKIN_IMAGE_PLACEHOLDER_ID = 'Magento_Cms::images/wysiwyg_skin_image.png';
26+
2227
/**
2328
* Wysiwyg status hidden
2429
*/
@@ -78,6 +83,11 @@ class Config extends \Magento\Framework\Object
7883
*/
7984
protected $_backendUrl;
8085

86+
/**
87+
* @var \Magento\Store\Model\StoreManagerInterface
88+
*/
89+
protected $_storeManager;
90+
8191
/**
8292
* @param \Magento\Backend\Model\UrlInterface $backendUrl
8393
* @param \Magento\Framework\Event\ManagerInterface $eventManager
@@ -86,6 +96,7 @@ class Config extends \Magento\Framework\Object
8696
* @param \Magento\Core\Model\Variable\Config $variableConfig
8797
* @param \Magento\Widget\Model\Widget\Config $widgetConfig
8898
* @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
99+
* @param \Magento\Store\Model\StoreManagerInterface $storeManager
89100
* @param array $windowSize
90101
* @param array $data
91102
*/
@@ -97,6 +108,7 @@ public function __construct(
97108
\Magento\Core\Model\Variable\Config $variableConfig,
98109
\Magento\Widget\Model\Widget\Config $widgetConfig,
99110
\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
111+
\Magento\Store\Model\StoreManagerInterface $storeManager,
100112
array $windowSize = [],
101113
array $data = []
102114
) {
@@ -108,6 +120,7 @@ public function __construct(
108120
$this->_variableConfig = $variableConfig;
109121
$this->_widgetConfig = $widgetConfig;
110122
$this->_windowSize = $windowSize;
123+
$this->_storeManager = $storeManager;
111124
parent::__construct($data);
112125
}
113126

@@ -189,7 +202,19 @@ public function getConfig($data = [])
189202
*/
190203
public function getSkinImagePlaceholderUrl()
191204
{
192-
return $this->_assetRepo->getUrl('Magento_Cms::images/wysiwyg_skin_image.png');
205+
return $this->_assetRepo->getUrl(self::WYSIWYG_SKIN_IMAGE_PLACEHOLDER_ID);
206+
}
207+
208+
/**
209+
* Return path for skin images placeholder
210+
*
211+
* @return string
212+
*/
213+
public function getSkinImagePlaceholderPath()
214+
{
215+
$staticPath = $this->_storeManager->getStore()->getBaseStaticDir();
216+
$placeholderPath = $this->_assetRepo->createAsset(self::WYSIWYG_SKIN_IMAGE_PLACEHOLDER_ID)->getPath();
217+
return $staticPath . '/' . $placeholderPath;
193218
}
194219

195220
/**

app/code/Magento/Store/Model/Store.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,26 @@ public function getBaseUrl($type = \Magento\Framework\UrlInterface::URL_TYPE_LIN
594594
return $this->_baseUrlCache[$cacheKey];
595595
}
596596

597+
/**
598+
* Retrieve base media directory path
599+
*
600+
* @return string
601+
*/
602+
public function getBaseMediaDir()
603+
{
604+
return $this->filesystem->getUri(DirectoryList::MEDIA);
605+
}
606+
607+
/**
608+
* Retrieve base static directory path
609+
*
610+
* @return string
611+
*/
612+
public function getBaseStaticDir()
613+
{
614+
return $this->filesystem->getUri(DirectoryList::STATIC_VIEW);
615+
}
616+
597617
/**
598618
* Append script file name to url in case when server rewrites are disabled
599619
*
Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
<?php
2+
/**
3+
* {license_notice}
4+
*
5+
* @copyright {copyright}
6+
* @license {license_link}
7+
*/
8+
namespace Magento\Cms\Controller\Adminhtml\Wysiwyg;
9+
10+
/**
11+
* @covers \Magento\Cms\Controller\Adminhtml\Wysiwyg\Directive
12+
*/
13+
class DirectiveTest extends \PHPUnit_Framework_TestCase
14+
{
15+
const IMAGE_PATH = 'pub/media/wysiwyg/image.jpg';
16+
17+
/**
18+
* @var \Magento\Cms\Controller\Adminhtml\Wysiwyg\Directive
19+
*/
20+
protected $wysiwygDirective;
21+
22+
/**
23+
* @var \Magento\Backend\App\Action\Context|\PHPUnit_Framework_MockObject_MockObject
24+
*/
25+
protected $actionContextMock;
26+
27+
/**
28+
* @var \Magento\Framework\App\RequestInterface|\PHPUnit_Framework_MockObject_MockObject
29+
*/
30+
protected $requestMock;
31+
32+
/**
33+
* @var \Magento\Framework\Url\DecoderInterface|\PHPUnit_Framework_MockObject_MockObject
34+
*/
35+
protected $urlDecoderMock;
36+
37+
/**
38+
* @var \Magento\Framework\ObjectManagerInterface|\PHPUnit_Framework_MockObject_MockObject
39+
*/
40+
protected $objectManagerMock;
41+
42+
/**
43+
* @var \Magento\Cms\Model\Template\Filter|\PHPUnit_Framework_MockObject_MockObject
44+
*/
45+
protected $templateFilterMock;
46+
47+
/**
48+
* @var \Magento\Framework\Image\AdapterFactory|\PHPUnit_Framework_MockObject_MockObject
49+
*/
50+
protected $imageAdapterFactoryMock;
51+
52+
/**
53+
* @var \Magento\Framework\Image\Adapter\AdapterInterface|\PHPUnit_Framework_MockObject_MockObject
54+
*/
55+
protected $imageAdapterMock;
56+
57+
/**
58+
* @var \Magento\Framework\App\ResponseInterface|\PHPUnit_Framework_MockObject_MockObject
59+
*/
60+
protected $responseMock;
61+
62+
/**
63+
* @var \Magento\Cms\Model\Wysiwyg\Config|\PHPUnit_Framework_MockObject_MockObject
64+
*/
65+
protected $wysiwygConfigMock;
66+
67+
/**
68+
* @var \Psr\Log\LoggerInterface|\PHPUnit_Framework_MockObject_MockObject
69+
*/
70+
protected $loggerMock;
71+
72+
protected function setUp()
73+
{
74+
$this->actionContextMock = $this->getMockBuilder('Magento\Backend\App\Action\Context')
75+
->disableOriginalConstructor()
76+
->getMock();
77+
$this->requestMock = $this->getMockBuilder('Magento\Framework\App\RequestInterface')
78+
->disableOriginalConstructor()
79+
->getMock();
80+
$this->urlDecoderMock = $this->getMockBuilder('Magento\Framework\Url\DecoderInterface')
81+
->disableOriginalConstructor()
82+
->getMock();
83+
$this->objectManagerMock = $this->getMockBuilder('Magento\Framework\ObjectManagerInterface')
84+
->disableOriginalConstructor()
85+
->getMock();
86+
$this->templateFilterMock = $this->getMockBuilder('Magento\Cms\Model\Template\Filter')
87+
->disableOriginalConstructor()
88+
->getMock();
89+
$this->imageAdapterFactoryMock = $this->getMockBuilder('Magento\Framework\Image\AdapterFactory')
90+
->disableOriginalConstructor()
91+
->getMock();
92+
$this->imageAdapterMock = $this->getMockBuilder('Magento\Framework\Image\Adapter\AdapterInterface')
93+
->disableOriginalConstructor()
94+
->setMethods(
95+
[
96+
'getMimeType',
97+
'getColorAt',
98+
'getImage',
99+
'watermark',
100+
'refreshImageDimensions',
101+
'checkDependencies',
102+
'createPngFromString',
103+
'open',
104+
'resize',
105+
'crop',
106+
'save',
107+
'rotate'
108+
]
109+
)
110+
->getMock();
111+
$this->responseMock = $this->getMockBuilder('Magento\Framework\App\ResponseInterface')
112+
->disableOriginalConstructor()
113+
->setMethods(['setHeader', 'setBody', 'sendResponse'])
114+
->getMock();
115+
$this->wysiwygConfigMock = $this->getMockBuilder('Magento\Cms\Model\Wysiwyg\Config')
116+
->disableOriginalConstructor()
117+
->getMock();
118+
$this->loggerMock = $this->getMockBuilder('Psr\Log\LoggerInterface')
119+
->disableOriginalConstructor()
120+
->getMock();
121+
122+
$this->actionContextMock->expects($this->any())
123+
->method('getRequest')
124+
->willReturn($this->requestMock);
125+
$this->actionContextMock->expects($this->any())
126+
->method('getResponse')
127+
->willReturn($this->responseMock);
128+
$this->actionContextMock->expects($this->any())
129+
->method('getObjectManager')
130+
->willReturn($this->objectManagerMock);
131+
132+
$objectManager = new \Magento\TestFramework\Helper\ObjectManager($this);
133+
$this->wysiwygDirective = $objectManager->getObject(
134+
'Magento\Cms\Controller\Adminhtml\Wysiwyg\Directive',
135+
[
136+
'context' => $this->actionContextMock,
137+
'urlDecoder' => $this->urlDecoderMock
138+
]
139+
);
140+
}
141+
142+
/**
143+
* @covers \Magento\Cms\Controller\Adminhtml\Wysiwyg\Directive::execute
144+
*/
145+
public function testExecute()
146+
{
147+
$mimeType = 'image/jpeg';
148+
$imageBody = 'abcdefghijklmnopqrstuvwxyz0123456789';
149+
$this->prepareExecuteTest();
150+
151+
$this->imageAdapterMock->expects($this->once())
152+
->method('open')
153+
->with(self::IMAGE_PATH);
154+
$this->imageAdapterMock->expects($this->once())
155+
->method('getMimeType')
156+
->willReturn($mimeType);
157+
$this->responseMock->expects($this->once())
158+
->method('setHeader')
159+
->with('Content-Type', $mimeType)
160+
->willReturnSelf();
161+
$this->imageAdapterMock->expects($this->once())
162+
->method('getImage')
163+
->willReturn($imageBody);
164+
$this->responseMock->expects($this->once())
165+
->method('setBody')
166+
->with($imageBody)
167+
->willReturnSelf();
168+
169+
$this->wysiwygDirective->execute();
170+
}
171+
172+
/**
173+
* @covers \Magento\Cms\Controller\Adminhtml\Wysiwyg\Directive::execute
174+
*/
175+
public function testExecuteException()
176+
{
177+
$exception = new \Exception('epic fail');
178+
$placeholderPath = 'pub/static/adminhtml/Magento/backend/en_US/Magento_Cms/images/wysiwyg_skin_image.png';
179+
$mimeType = 'image/png';
180+
$imageBody = '0123456789abcdefghijklmnopqrstuvwxyz';
181+
$this->prepareExecuteTest();
182+
183+
$this->imageAdapterMock->expects($this->at(0))
184+
->method('open')
185+
->with(self::IMAGE_PATH)
186+
->willThrowException($exception);
187+
$this->wysiwygConfigMock->expects($this->once())
188+
->method('getSkinImagePlaceholderPath')
189+
->willReturn($placeholderPath);
190+
$this->imageAdapterMock->expects($this->at(1))
191+
->method('open')
192+
->with($placeholderPath);
193+
$this->imageAdapterMock->expects($this->once())
194+
->method('getMimeType')
195+
->willReturn($mimeType);
196+
$this->responseMock->expects($this->once())
197+
->method('setHeader')
198+
->with('Content-Type', $mimeType)
199+
->willReturnSelf();
200+
$this->imageAdapterMock->expects($this->once())
201+
->method('getImage')
202+
->willReturn($imageBody);
203+
$this->responseMock->expects($this->once())
204+
->method('setBody')
205+
->with($imageBody)
206+
->willReturnSelf();
207+
$this->loggerMock->expects($this->once())
208+
->method('critical')
209+
->with($exception);
210+
211+
$this->wysiwygDirective->execute();
212+
}
213+
214+
protected function prepareExecuteTest()
215+
{
216+
$directiveParam = 'e3ttZWRpYSB1cmw9Ind5c2l3eWcvYnVubnkuanBnIn19';
217+
$directive = '{{media url="wysiwyg/image.jpg"}}';
218+
219+
$this->requestMock->expects($this->once())
220+
->method('getParam')
221+
->with('___directive')
222+
->willReturn($directiveParam);
223+
$this->urlDecoderMock->expects($this->once())
224+
->method('decode')
225+
->with($directiveParam)
226+
->willReturn($directive);
227+
$this->objectManagerMock->expects($this->once())
228+
->method('create')
229+
->with('Magento\Cms\Model\Template\Filter')
230+
->willReturn($this->templateFilterMock);
231+
$this->templateFilterMock->expects($this->once())
232+
->method('filter')
233+
->with($directive)
234+
->willReturn(self::IMAGE_PATH);
235+
$this->objectManagerMock->expects($this->any())
236+
->method('get')
237+
->willReturnMap(
238+
[
239+
['Magento\Framework\Image\AdapterFactory', $this->imageAdapterFactoryMock],
240+
['Magento\Cms\Model\Wysiwyg\Config', $this->wysiwygConfigMock],
241+
['Psr\Log\LoggerInterface', $this->loggerMock]
242+
]
243+
);
244+
$this->imageAdapterFactoryMock->expects($this->once())
245+
->method('create')
246+
->willReturn($this->imageAdapterMock);
247+
}
248+
}

0 commit comments

Comments
 (0)