From 5b3bc33b360845367a949c05240455ccb1891f5e Mon Sep 17 00:00:00 2001 From: David Grudl Date: Wed, 11 Oct 2023 13:49:57 +0200 Subject: [PATCH] implemented mandatory escaping (cannot be disabled using |noescape) --- src/Latte/Compiler/Escaper.php | 20 +++++++++++++++++++ src/Latte/Compiler/Nodes/Php/ModifierNode.php | 6 +++--- src/Latte/Runtime/Filters.php | 9 +++++++++ tests/common/contentType.html.css.phpt | 2 +- tests/common/contentType.html.javascript.phpt | 2 +- tests/common/contentType.html.phpt | 4 ++-- .../common/contentType.html.script-html.phpt | 2 +- .../contentType.html.script-unknown.phpt | 6 ++++++ tests/filters/escapeHtmlQuotes.phpt | 20 +++++++++++++++++++ 9 files changed, 63 insertions(+), 8 deletions(-) create mode 100644 tests/filters/escapeHtmlQuotes.phpt diff --git a/src/Latte/Compiler/Escaper.php b/src/Latte/Compiler/Escaper.php index 175ab28d0..32f8af7ff 100644 --- a/src/Latte/Compiler/Escaper.php +++ b/src/Latte/Compiler/Escaper.php @@ -220,6 +220,26 @@ public function escape(string $str): string } + public function escapeMandatory(string $str): string + { + return match ($this->contentType) { + ContentType::Html => match ($this->state) { + self::HtmlAttribute => "LR\\Filters::escapeHtmlQuotes($str)", + self::HtmlRawText => match ($this->subType) { + self::HtmlText => 'LR\Filters::convertHtmlToHtmlRawText(' . $str . ')', + default => "LR\\Filters::convertJSToHtmlRawText($str)", + }, + default => $str, + }, + ContentType::Xml => match ($this->state) { + self::HtmlAttribute => "LR\\Filters::escapeHtmlQuotes($str)", + default => $str, + }, + default => $str, + }; + } + + public function check(string $str): string { if ($this->state === self::HtmlAttribute && $this->subType === self::Url) { diff --git a/src/Latte/Compiler/Nodes/Php/ModifierNode.php b/src/Latte/Compiler/Nodes/Php/ModifierNode.php index 340b83b8f..6f71d09e7 100644 --- a/src/Latte/Compiler/Nodes/Php/ModifierNode.php +++ b/src/Latte/Compiler/Nodes/Php/ModifierNode.php @@ -68,9 +68,9 @@ public function printSimple(PrintContext $context, string $expr): string $expr = $escaper->check($expr); } - if ($escape) { - $expr = $escaper->escape($expr); - } + $expr = $escape + ? $escaper->escape($expr) + : $escaper->escapeMandatory($expr); return $expr; } diff --git a/src/Latte/Runtime/Filters.php b/src/Latte/Runtime/Filters.php index 64ccb110e..47032e131 100644 --- a/src/Latte/Runtime/Filters.php +++ b/src/Latte/Runtime/Filters.php @@ -116,6 +116,15 @@ public static function escapeHtmlRawTextHtml($s): string } + /** + * Escapes only quotes. + */ + public static function escapeHtmlQuotes($s): string + { + return strtr((string) $s, ['"' => '"', "'" => ''']); + } + + /** * Escapes string for use everywhere inside XML (except for comments and tags). */ diff --git a/tests/common/contentType.html.css.phpt b/tests/common/contentType.html.css.phpt index 103bd8f3d..2950a0880 100644 --- a/tests/common/contentType.html.css.phpt +++ b/tests/common/contentType.html.css.phpt @@ -57,6 +57,6 @@ Assert::match( // no escape Assert::match( - '', + '', $latte->renderToString('"|noescape}'), ); diff --git a/tests/common/contentType.html.javascript.phpt b/tests/common/contentType.html.javascript.phpt index 9a433973b..167168ff0 100644 --- a/tests/common/contentType.html.javascript.phpt +++ b/tests/common/contentType.html.javascript.phpt @@ -131,6 +131,6 @@ Assert::match( // no escape Assert::match( - '', + '', $latte->renderToString('"|noescape}'), ); diff --git a/tests/common/contentType.html.phpt b/tests/common/contentType.html.phpt index 3986bbea2..8e7d70285 100644 --- a/tests/common/contentType.html.phpt +++ b/tests/common/contentType.html.phpt @@ -35,12 +35,12 @@ Assert::match( // no escape in attribute Assert::match( - '

">

', + '

', $latte->renderToString('

"|noescape}>

'), ); // no escape in JS attribute Assert::match( - '

">

', + '

', $latte->renderToString('

"|noescape}">

'), ); diff --git a/tests/common/contentType.html.script-html.phpt b/tests/common/contentType.html.script-html.phpt index bca1fcff3..27851bb42 100644 --- a/tests/common/contentType.html.script-html.phpt +++ b/tests/common/contentType.html.script-html.phpt @@ -32,7 +32,7 @@ Assert::match( // no escape Assert::match( - '', + '', $latte->renderToString('"|noescape}'), ); diff --git a/tests/common/contentType.html.script-unknown.phpt b/tests/common/contentType.html.script-unknown.phpt index b1120a402..dc8fce580 100644 --- a/tests/common/contentType.html.script-unknown.phpt +++ b/tests/common/contentType.html.script-unknown.phpt @@ -37,6 +37,12 @@ Assert::exception( 'Including block a with content type HTML into incompatible type HTML/RAW/TEXT.', ); +// no escape +Assert::match( + '', + $latte->renderToString('"|noescape}'), +); + // content of