X-Git-Url: http://source.bookstackapp.com/bookstack/blobdiff_plain/fd44e4ba74b7615e196dcafa4f1eddc634c0b44d..refs/pull/5721/head:/app/Util/HtmlNonceApplicator.php diff --git a/app/Util/HtmlNonceApplicator.php b/app/Util/HtmlNonceApplicator.php index eb2cf2687..3a798e848 100644 --- a/app/Util/HtmlNonceApplicator.php +++ b/app/Util/HtmlNonceApplicator.php @@ -2,51 +2,52 @@ namespace BookStack\Util; -use DOMDocument; use DOMElement; use DOMNodeList; -use DOMXPath; class HtmlNonceApplicator { + protected static string $placeholder = '[CSP_NONCE_VALUE]'; + /** - * Apply the given nonce to all scripts and styles in the given html. + * Prepare the given HTML content with nonce attributes including a placeholder + * value which we can target later. */ - public static function apply(string $html, string $nonce): string + public static function prepare(string $html): string { if (empty($html)) { return $html; } - $html = '' . $html . ''; - libxml_use_internal_errors(true); - $doc = new DOMDocument(); - $doc->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8')); - $xPath = new DOMXPath($doc); + // LIBXML_SCHEMA_CREATE was found to be required here otherwise + // the PHP DOMDocument handling will attempt to format/close + // HTML tags within scripts and therefore change JS content. + $doc = new HtmlDocument($html, LIBXML_SCHEMA_CREATE); // Apply to scripts - $scriptElems = $xPath->query('//script'); - static::addNonceAttributes($scriptElems, $nonce); + $scriptElems = $doc->queryXPath('//script'); + static::addNonceAttributes($scriptElems, static::$placeholder); // Apply to styles - $styleElems = $xPath->query('//style'); - static::addNonceAttributes($styleElems, $nonce); + $styleElems = $doc->queryXPath('//style'); + static::addNonceAttributes($styleElems, static::$placeholder); - $returnHtml = ''; - $topElems = $doc->documentElement->childNodes->item(0)->childNodes; - foreach ($topElems as $child) { - $returnHtml .= $doc->saveHTML($child); - } + return $doc->getBodyInnerHtml(); + } - return $returnHtml; + /** + * Apply the give nonce value to the given prepared HTML. + */ + public static function apply(string $html, string $nonce): string + { + return str_replace(static::$placeholder, $nonce, $html); } - protected static function addNonceAttributes(DOMNodeList $nodes, string $nonce): void + protected static function addNonceAttributes(DOMNodeList $nodes, string $attrValue): void { /** @var DOMElement $node */ foreach ($nodes as $node) { - $node->setAttribute('nonce', $nonce); + $node->setAttribute('nonce', $attrValue); } } - }