Altered the parsing of custom head to prevent htmlentities on content
Was causing things like emjoi within script content to be somewhat mangled. Instead we force UTF8 only parsing via XML declaration. Added test to cover. For #2923
This commit is contained in:
parent
fb80bb5d58
commit
ef459ca4c4
3 changed files with 40 additions and 3 deletions
|
@ -12,7 +12,7 @@ class CspService
|
|||
|
||||
public function __construct(string $nonce = '')
|
||||
{
|
||||
$this->nonce = $nonce ?: Str::random(16);
|
||||
$this->nonce = $nonce ?: Str::random(24);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -21,10 +21,10 @@ class HtmlNonceApplicator
|
|||
return $html;
|
||||
}
|
||||
|
||||
$html = '<body>' . $html . '</body>';
|
||||
$html = '<?xml encoding="utf-8" ?><body>' . $html . '</body>';
|
||||
libxml_use_internal_errors(true);
|
||||
$doc = new DOMDocument();
|
||||
$doc->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'), LIBXML_SCHEMA_CREATE);
|
||||
$doc->loadHTML($html, LIBXML_SCHEMA_CREATE);
|
||||
$xPath = new DOMXPath($doc);
|
||||
|
||||
// Apply to scripts
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Tests\Settings;
|
||||
|
||||
use BookStack\Util\CspService;
|
||||
use Tests\TestCase;
|
||||
|
||||
class CustomHeadContentTest extends TestCase
|
||||
|
@ -26,4 +27,40 @@ class CustomHeadContentTest extends TestCase
|
|||
$resp = $this->get('/login');
|
||||
$resp->assertSee('<div id="hello">cat</div>');
|
||||
}
|
||||
|
||||
public function test_nonce_application_handles_edge_cases()
|
||||
{
|
||||
$mockCSP = $this->mock(CspService::class);
|
||||
$mockCSP->shouldReceive('getNonce')->andReturn('abc123');
|
||||
|
||||
$content = trim('
|
||||
<script>console.log("cat");</script>
|
||||
<script type="text/html"><\script>const a = `<div></div>`<\/\script></script>
|
||||
<script >const a = `<div></div>`;</script>
|
||||
<script type="<script text>test">const c = `<div></div>`;</script>
|
||||
<script
|
||||
type="text/html"
|
||||
>
|
||||
const a = `<\script><\/script>`;
|
||||
const b = `<script`;
|
||||
</script>
|
||||
<SCRIPT>const b = `↗️£`;</SCRIPT>
|
||||
');
|
||||
|
||||
$expectedOutput = trim('
|
||||
<script nonce="abc123">console.log("cat");</script>
|
||||
<script type="text/html" nonce="abc123"><\script>const a = `<div></div>`<\/\script></script>
|
||||
<script nonce="abc123">const a = `<div></div>`;</script>
|
||||
<script type="<script text>test" nonce="abc123">const c = `<div></div>`;</script>
|
||||
<script type="text/html" nonce="abc123">
|
||||
const a = `<\script><\/script>`;
|
||||
const b = `<script`;
|
||||
</script>
|
||||
<script nonce="abc123">const b = `↗️£`;</script>
|
||||
');
|
||||
|
||||
$this->setSettings(['app-custom-head' => $content]);
|
||||
$resp = $this->get('/login');
|
||||
$resp->assertSee($expectedOutput);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue