From 84554ae71f3dbd4f98cd065cdf9bde3e5706fe8d Mon Sep 17 00:00:00 2001 From: Matias Griese Date: Wed, 20 Jan 2021 18:53:38 +0200 Subject: [PATCH] Fixed page metadata being double-escaped [#3121] --- CHANGELOG.md | 1 + system/src/Grav/Common/Page/Page.php | 14 +++++++++----- system/src/Grav/Common/Twig/Twig.php | 2 +- .../Flex/Pages/Traits/PageLegacyTrait.php | 13 ++++++++----- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b040f8866..cb875aa93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ * Flex Pages: Fixed fatal error when trying to move a page to Root (/) [#3161](https://github.com/getgrav/grav/issues/3161) * Fixed twig parsing errors in pages where twig is parsed after markdown [#3162](https://github.com/getgrav/grav/issues/3162) * Fixed `lighttpd.conf` access-deny rule [#1876](https://github.com/getgrav/grav/issues/1876) + * Fixed page metadata being double-escaped [#3121](https://github.com/getgrav/grav/issues/3121) # v1.7.0 ## 01/19/2021 diff --git a/system/src/Grav/Common/Page/Page.php b/system/src/Grav/Common/Page/Page.php index 42338a74e..344a7ba60 100644 --- a/system/src/Grav/Common/Page/Page.php +++ b/system/src/Grav/Common/Page/Page.php @@ -1674,8 +1674,12 @@ class Page implements PageInterface 'generator' => 'GravCMS' ]; + $config = Grav::instance()['config']; + + $escape = !$config->get('system.strict_mode.twig_compat', false) || $config->get('system.twig.autoescape', true); + // Get initial metadata for the page - $metadata = array_merge($metadata, Grav::instance()['config']->get('site.metadata', [])); + $metadata = array_merge($metadata, $config->get('site.metadata', [])); if (isset($this->header->metadata) && is_array($this->header->metadata)) { // Merge any site.metadata settings in with page metadata @@ -1694,7 +1698,7 @@ class Page implements PageInterface $this->metadata[$prop_key] = [ 'name' => $prop_key, 'property' => $prop_key, - 'content' => htmlspecialchars($prop_value, ENT_QUOTES, 'UTF-8') + 'content' => $escape ? htmlspecialchars($prop_value, ENT_QUOTES, 'UTF-8') : $prop_value ]; } } else { @@ -1703,16 +1707,16 @@ class Page implements PageInterface if (in_array($key, $header_tag_http_equivs, true)) { $this->metadata[$key] = [ 'http_equiv' => $key, - 'content' => htmlspecialchars($value, ENT_QUOTES, 'UTF-8') + 'content' => $escape ? htmlspecialchars($value, ENT_QUOTES, 'UTF-8') : $value ]; } elseif ($key === 'charset') { - $this->metadata[$key] = ['charset' => htmlspecialchars($value, ENT_QUOTES, 'UTF-8')]; + $this->metadata[$key] = ['charset' => $escape ? htmlspecialchars($value, ENT_QUOTES, 'UTF-8') : $value]; } else { // if it's a social metadata with separator, render as property $separator = strpos($key, ':'); $hasSeparator = $separator && $separator < strlen($key) - 1; $entry = [ - 'content' => htmlspecialchars($value, ENT_QUOTES, 'UTF-8') + 'content' => $escape ? htmlspecialchars($value, ENT_QUOTES, 'UTF-8') : $value ]; if ($hasSeparator && !Utils::startsWith($key, 'twitter')) { diff --git a/system/src/Grav/Common/Twig/Twig.php b/system/src/Grav/Common/Twig/Twig.php index 1b6f73698..7284fb686 100644 --- a/system/src/Grav/Common/Twig/Twig.php +++ b/system/src/Grav/Common/Twig/Twig.php @@ -141,7 +141,7 @@ class Twig $params['cache'] = new FilesystemCache($cachePath, FilesystemCache::FORCE_BYTECODE_INVALIDATION); } - if (!$config->get('system.strict_mode.twig_compat', true)) { + if (!$config->get('system.strict_mode.twig_compat', false)) { // Force autoescape on for all files if in strict mode. $params['autoescape'] = 'html'; } elseif (!empty($this->autoescape)) { diff --git a/system/src/Grav/Framework/Flex/Pages/Traits/PageLegacyTrait.php b/system/src/Grav/Framework/Flex/Pages/Traits/PageLegacyTrait.php index d7c0014f3..6d09b2acf 100644 --- a/system/src/Grav/Framework/Flex/Pages/Traits/PageLegacyTrait.php +++ b/system/src/Grav/Framework/Flex/Pages/Traits/PageLegacyTrait.php @@ -606,15 +606,18 @@ trait PageLegacyTrait if (null === $this->_metadata) { $this->_metadata = []; + $config = Grav::instance()['config']; + // Set the Generator tag $defaultMetadata = ['generator' => 'GravCMS']; - $siteMetadata = Grav::instance()['config']->get('site.metadata', []); + $siteMetadata = $config->get('site.metadata', []); $headerMetadata = $this->getNestedProperty('header.metadata', []); // Get initial metadata for the page $metadata = array_merge($defaultMetadata, $siteMetadata, $headerMetadata); $header_tag_http_equivs = ['content-type', 'default-style', 'refresh', 'x-ua-compatible']; + $escape = !$config->get('system.strict_mode.twig_compat', false) || $config->get('system.twig.autoescape', true); // Build an array of meta objects.. foreach ($metadata as $key => $value) { @@ -629,7 +632,7 @@ trait PageLegacyTrait $this->_metadata[$prop_key] = [ 'name' => $prop_key, 'property' => $prop_key, - 'content' => htmlspecialchars($prop_value, ENT_QUOTES | ENT_HTML5, 'UTF-8') + 'content' => $escape ? htmlspecialchars($prop_value, ENT_QUOTES | ENT_HTML5, 'UTF-8') : $prop_value ]; } } elseif ($value) { @@ -637,16 +640,16 @@ trait PageLegacyTrait if (in_array($key, $header_tag_http_equivs, true)) { $this->_metadata[$key] = [ 'http_equiv' => $key, - 'content' => htmlspecialchars($value, ENT_QUOTES | ENT_HTML5, 'UTF-8') + 'content' => $escape ? htmlspecialchars($value, ENT_QUOTES | ENT_HTML5, 'UTF-8') : $value ]; } elseif ($key === 'charset') { - $this->_metadata[$key] = ['charset' => htmlspecialchars($value, ENT_QUOTES | ENT_HTML5, 'UTF-8')]; + $this->_metadata[$key] = ['charset' => $escape ? htmlspecialchars($value, ENT_QUOTES | ENT_HTML5, 'UTF-8') : $value]; } else { // if it's a social metadata with separator, render as property $separator = strpos($key, ':'); $hasSeparator = $separator && $separator < strlen($key) - 1; $entry = [ - 'content' => htmlspecialchars($value, ENT_QUOTES | ENT_HTML5, 'UTF-8') + 'content' => $escape ? htmlspecialchars($value, ENT_QUOTES | ENT_HTML5, 'UTF-8') : $value ]; if ($hasSeparator && !Utils::startsWith($key, 'twitter')) {