diff --git a/CHANGELOG.md b/CHANGELOG.md index 63a331317..1a6db621d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,7 @@ * Fixed `system://` stream is causing issues in Admin, making Media tab to disappear and possibly causing other issues [#3072](https://github.com/getgrav/grav/issues/3072) * Fixed CLI self-upgrade from Grav 1.6 [#3079](https://github.com/getgrav/grav/issues/3079) * Fixed `bin/grav yamllinter -a` and `-f` not following symlinks [#3080](https://github.com/getgrav/grav/issues/3080) + * Fixed `|safe_email` filter to return safe and escaped UTF-8 HTML [#3072](https://github.com/getgrav/grav/issues/3072) # v1.7.0-rc.17 ## 10/07/2020 diff --git a/system/src/Grav/Common/Twig/TwigExtension.php b/system/src/Grav/Common/Twig/TwigExtension.php index 695ff4990..39efc9ae4 100644 --- a/system/src/Grav/Common/Twig/TwigExtension.php +++ b/system/src/Grav/Common/Twig/TwigExtension.php @@ -129,7 +129,7 @@ class TwigExtension extends AbstractExtension implements GlobalsInterface new TwigFilter('rtrim', [$this, 'rtrimFilter']), new TwigFilter('pad', [$this, 'padFilter']), new TwigFilter('regex_replace', [$this, 'regexReplace']), - new TwigFilter('safe_email', [$this, 'safeEmailFilter']), + new TwigFilter('safe_email', [$this, 'safeEmailFilter'], ['is_safe' => ['html']]), new TwigFilter('safe_truncate', ['\Grav\Common\Utils', 'safeTruncate']), new TwigFilter('safe_truncate_html', ['\Grav\Common\Utils', 'safeTruncateHTML']), new TwigFilter('sort_by_key', [$this, 'sortByKeyFilter']), @@ -267,14 +267,23 @@ class TwigExtension extends AbstractExtension implements GlobalsInterface */ public function safeEmailFilter($str) { - $email = ''; - for ($i = 0, $len = strlen($str); $i < $len; $i++) { - $j = random_int(0, 1); + static $list = [ + '"' => '"', + "'" => ''', + '&' => '&', + '<' => '<', + '>' => '>', + '@' => '@' + ]; - $email .= $j === 0 ? '&#' . ord($str[$i]) . ';' : $str[$i]; + $characters = mb_str_split($str, 1, 'UTF-8'); + + $encoded = ''; + foreach ($characters as $chr) { + $encoded .= $list[$chr] ?? (random_int(0, 1) ? '&#' . mb_ord($chr) . ';' : $chr); } - return str_replace('@', '@', $email); + return $encoded; } /**