Skip to content

Commit 0d7d933

Browse files
committed
In <script type=unknown> are not escaped HTML
1 parent 6915fe2 commit 0d7d933

2 files changed

Lines changed: 98 additions & 1 deletion

File tree

src/Latte/Compiler/Escaper.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,8 @@ public function enterHtmlText(?ElementNode $node): void
133133
$this->subState = match (true) {
134134
$name === 'style' => self::Css,
135135
self::isJSScript($node) => self::JavaScript,
136-
default => self::HtmlText,
136+
self::isHtmlScript($node) => self::HtmlText,
137+
default => self::Text,
137138
};
138139
} else {
139140
$this->state = self::HtmlText;
@@ -204,6 +205,7 @@ public function escape(string $str): string
204205
self::HtmlComment => 'LR\Filters::escapeHtmlComment(' . $str . ')',
205206
self::HtmlBogusTag => 'LR\Filters::escapeHtml(' . $str . ')',
206207
self::HtmlRawText => match ($this->subState) {
208+
self::Text => 'LR\Filters::convertJSToHtmlRawText(' . $str . ')', // sanitization, escaping is not possible
207209
self::HtmlText => 'LR\Filters::escapeHtmlRawTextHtml(' . $str . ')',
208210
self::JavaScript => 'LR\Filters::escapeJs(' . $str . ')',
209211
self::Css => 'LR\Filters::escapeCss(' . $str . ')',
@@ -261,4 +263,13 @@ public static function isJSScript(ElementNode $el): bool
261263
&& ($type === true || $type === null || $type === ''
262264
|| is_string($type) && preg_match('#((application|text)/(((x-)?java|ecma|j|live)script|json)|text/plain|module|importmap)$#Ai', $type));
263265
}
266+
267+
268+
private static function isHtmlScript(ElementNode $el): bool
269+
{
270+
$type = $el->getAttribute('type');
271+
return strcasecmp($el->name, 'script') === 0
272+
&& is_string($type) && preg_match('#text/((x-)?template|html)$#Ai', $type);
273+
274+
}
264275
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<?php
2+
3+
/**
4+
* Test: Unknown type of <script>
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
use Latte\Runtime\Html;
10+
use Tester\Assert;
11+
12+
require __DIR__ . '/../bootstrap.php';
13+
14+
15+
$latte = new Latte\Engine;
16+
$latte->setLoader(new Latte\Loaders\StringLoader);
17+
18+
// escaping of string
19+
Assert::match(
20+
'<script type="foo"> <div title=" <>\' "> <>\' </div> </script>',
21+
$latte->renderToString('<script type="foo"> <div title=" {="<>\'"} "> {="<>\'"} </div> </script>'),
22+
);
23+
24+
// escaping of Html object
25+
Assert::match(
26+
'<script type="foo"> <div title=\'<\/script>\'></div> </script>',
27+
$latte->renderToString(
28+
'<script type="foo"> {$foo} </script>',
29+
['foo' => new Html("<div title='</script>'></div>")],
30+
),
31+
);
32+
33+
// include
34+
Assert::exception(
35+
fn() => $latte->renderToString('{define a}<script></script>{/define} <script type="foo">{include a}</script>'),
36+
Latte\RuntimeException::class,
37+
'Including block a with content type HTML into incompatible type HTML/RAW+TEXT.',
38+
);
39+
40+
// content of <script> is RAWTEXT
41+
Assert::match(
42+
<<<'XX'
43+
<script type="foo">
44+
<div n:foreach="[a, b] as $i">def</div>
45+
</script>
46+
<div>a</div>
47+
<div>b</div>
48+
49+
XX,
50+
$latte->renderToString(
51+
<<<'XX'
52+
53+
{var $i = def}
54+
<script type="foo">
55+
<div n:foreach="[a, b] as $i">{$i}</div>
56+
</script>
57+
<div n:foreach="[a, b] as $i">{$i}</div>
58+
59+
XX,
60+
),
61+
);
62+
63+
// content of <script> changed to html
64+
Assert::match(
65+
<<<'XX'
66+
<script type="foo">
67+
<div>a</div>
68+
<div>b</div>
69+
</script>
70+
<div>a</div>
71+
<div>b</div>
72+
73+
XX,
74+
$latte->renderToString(
75+
<<<'XX'
76+
77+
{var $i = def}
78+
<script type="foo">
79+
{contentType html}
80+
<div n:foreach="[a, b] as $i">{$i}</div>
81+
</script>
82+
<div n:foreach="[a, b] as $i">{$i}</div>
83+
84+
XX,
85+
),
86+
);

0 commit comments

Comments
 (0)