From: Dan Brown Date: Sun, 12 Sep 2021 15:19:17 +0000 (+0100) Subject: Altered the parsing of custom head to prevent htmlentities on content X-Git-Tag: v21.08.3~1^2~2 X-Git-Url: http://source.bookstackapp.com/bookstack/commitdiff_plain/ef459ca4c45bd2450ecd5d67a4d73c07f836ab25 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 --- diff --git a/app/Util/CspService.php b/app/Util/CspService.php index ec5021371..812e1a4be 100644 --- a/app/Util/CspService.php +++ b/app/Util/CspService.php @@ -12,7 +12,7 @@ class CspService public function __construct(string $nonce = '') { - $this->nonce = $nonce ?: Str::random(16); + $this->nonce = $nonce ?: Str::random(24); } /** diff --git a/app/Util/HtmlNonceApplicator.php b/app/Util/HtmlNonceApplicator.php index 2653b7075..07298577c 100644 --- a/app/Util/HtmlNonceApplicator.php +++ b/app/Util/HtmlNonceApplicator.php @@ -21,10 +21,10 @@ class HtmlNonceApplicator return $html; } - $html = '' . $html . ''; + $html = '' . $html . ''; 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 diff --git a/tests/Settings/CustomHeadContentTest.php b/tests/Settings/CustomHeadContentTest.php index 59d5fc06c..94ef4711d 100644 --- a/tests/Settings/CustomHeadContentTest.php +++ b/tests/Settings/CustomHeadContentTest.php @@ -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('
cat
'); } + + public function test_nonce_application_handles_edge_cases() + { + $mockCSP = $this->mock(CspService::class); + $mockCSP->shouldReceive('getNonce')->andReturn('abc123'); + + $content = trim(' + + + + + + + '); + + $expectedOutput = trim(' + + + + + + + '); + + $this->setSettings(['app-custom-head' => $content]); + $resp = $this->get('/login'); + $resp->assertSee($expectedOutput); + } }