Skip to content

Commit

Permalink
MC-23553: Invalid Template Strings when Translate Inline enabled
Browse files Browse the repository at this point in the history
  • Loading branch information
mastiuhin-olexandr committed Feb 9, 2021
1 parent 55c4ff8 commit 1a481b4
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 6 deletions.
39 changes: 38 additions & 1 deletion lib/internal/Magento/Framework/Escaper.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\Framework;

Expand Down Expand Up @@ -258,8 +259,16 @@ private function escapeAttributeValue($name, $value)
public function escapeHtmlAttr($string, $escapeSingleQuote = true)
{
if ($escapeSingleQuote) {
return $this->getEscaper()->escapeHtmlAttr((string) $string);
$translateInline = $this->getTranslateInline();

if ($translateInline->isAllowed()) {
return $this->inlineSensitiveEscapeHthmlAttr((string) $string);
}

return $this->getEscaper()
->escapeHtmlAttr((string) $string);
}

return htmlspecialchars((string)$string, $this->htmlSpecialCharsFlag, 'UTF-8', false);
}

Expand Down Expand Up @@ -476,4 +485,32 @@ private function getTranslateInline()

return $this->translateInline;
}

/**
* Inline sensitive escape attribute value.
*
* @param string $text
* @return string
*/
private function inlineSensitiveEscapeHthmlAttr(string $text): string
{
$escaper = $this->getEscaper();
$firstCharacters = substr($text, 0, 3);
$lastCharacters = substr($text, -3, 3);

if ($firstCharacters === '{{{' && $lastCharacters === '}}}') {
$textLength = strlen($text);
$text = substr($text, 3, $textLength - 6);
$strings = explode('}}{{', $text);
$escapedStrings = [];

foreach ($strings as $string) {
$escapedStrings[] = $escaper->escapeHtmlAttr($string);
}

return '{{{' . implode('}}{{', $escapedStrings) . '}}}';
}

return $escaper->escapeHtmlAttr($text);
}
}
68 changes: 63 additions & 5 deletions lib/internal/Magento/Framework/Test/Unit/EscaperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use Magento\Framework\ZendEscaper;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
use Magento\Framework\Translate\Inline\StateInterface;

/**
* \Magento\Framework\Escaper test case
Expand All @@ -24,6 +25,11 @@ class EscaperTest extends TestCase
*/
protected $escaper;

/**
* @var ObjectManager
*/
private $objectManagerHelper;

/**
* @var ZendEscaper
*/
Expand All @@ -44,14 +50,14 @@ class EscaperTest extends TestCase
*/
protected function setUp(): void
{
$objectManagerHelper = new ObjectManager($this);
$this->objectManagerHelper = new ObjectManager($this);
$this->escaper = new Escaper();
$this->zendEscaper = new ZendEscaper();
$this->translateInline = $objectManagerHelper->getObject(Inline::class);
$this->translateInline = $this->objectManagerHelper->getObject(Inline::class);
$this->loggerMock = $this->getMockForAbstractClass(LoggerInterface::class);
$objectManagerHelper->setBackwardCompatibleProperty($this->escaper, 'escaper', $this->zendEscaper);
$objectManagerHelper->setBackwardCompatibleProperty($this->escaper, 'logger', $this->loggerMock);
$objectManagerHelper->setBackwardCompatibleProperty(
$this->objectManagerHelper->setBackwardCompatibleProperty($this->escaper, 'escaper', $this->zendEscaper);
$this->objectManagerHelper->setBackwardCompatibleProperty($this->escaper, 'logger', $this->loggerMock);
$this->objectManagerHelper->setBackwardCompatibleProperty(
$this->escaper,
'translateInline',
$this->translateInline
Expand Down Expand Up @@ -169,6 +175,58 @@ public function testEscapeHtml($data, $expected, $allowedTags = [])
$this->assertEquals($expected, $actual);
}

/**
* Tests escapeHtmlAttr method when Inline translate is configured.
*
* @param string $input
* @param string $output
* @return void
* @dataProvider escapeHtmlAttrWithInlineProvider
*/
public function testEscapeHtmlAttrWithInline(string $input, string $output): void
{
$this->objectManagerHelper->setBackwardCompatibleProperty(
$this->translateInline,
'isAllowed',
true
);
$stateMock = $this->createMock(StateInterface::class);
$stateMock->method('isEnabled')
->willReturn(true);
$this->objectManagerHelper->setBackwardCompatibleProperty(
$this->translateInline,
'state',
$stateMock
);


$actual = $this->escaper->escapeHtmlAttr($input);
$this->assertEquals($output, $actual);
}

/**
* Data provider for escapeHtmlAttrWithInline test.
*
* @return array
*/
public function escapeHtmlAttrWithInlineProvider(): array
{
return [
[
'{{{Search entire store here...}}}',
'{{{Search entire store here...}}}',
],
[
'{{{Product search}}{{Translated to language}}{{themeMagento/Luma}}}',
'{{{Product search}}{{Translated to language}}{{themeMagento/Luma}}}',
],
[
'Simple string',
'Simple string',
],
];
}

/**
* @covers \Magento\Framework\Escaper::escapeHtml
* @dataProvider escapeHtmlInvalidDataProvider
Expand Down

0 comments on commit 1a481b4

Please sign in to comment.