From f6d785e56c4312e8ee40c7232ce9fad79a0133bd Mon Sep 17 00:00:00 2001 From: xjm Date: Fri, 19 Jun 2015 12:16:55 -0500 Subject: [PATCH] Issue #2506133 by alexpott, joelpittet, dawehner, pwolanin: Replace SafeMarkup::set() in \Drupal\Core\Template\Attribute --- .../Drupal/Component/Utility/SafeMarkup.php | 6 ++- .../Component/Utility/SafeStringInterface.php | 36 +++++++++++++++++ core/lib/Drupal/Core/Template/Attribute.php | 10 ++--- .../Drupal/Core/Template/TwigExtension.php | 3 +- .../Component/Utility/SafeMarkupTest.php | 26 +++++++++++++ .../Tests/Core/Template/TwigExtensionTest.php | 39 +++++++++++++++++++ 6 files changed, 110 insertions(+), 10 deletions(-) create mode 100644 core/lib/Drupal/Component/Utility/SafeStringInterface.php diff --git a/core/lib/Drupal/Component/Utility/SafeMarkup.php b/core/lib/Drupal/Component/Utility/SafeMarkup.php index 69d12fedc20a..d97dc2f24d37 100644 --- a/core/lib/Drupal/Component/Utility/SafeMarkup.php +++ b/core/lib/Drupal/Component/Utility/SafeMarkup.php @@ -82,7 +82,7 @@ class SafeMarkup { /** * Checks if a string is safe to output. * - * @param string $string + * @param string|\Drupal\Component\Utility\SafeStringInterface $string * The content to be checked. * @param string $strategy * The escaping strategy. See self::set(). Defaults to 'html'. @@ -91,7 +91,9 @@ class SafeMarkup { * TRUE if the string has been marked secure, FALSE otherwise. */ public static function isSafe($string, $strategy = 'html') { - return isset(static::$safeStrings[(string) $string][$strategy]) || + // Do the instanceof checks first to save unnecessarily casting the object + // to a string. + return $string instanceOf SafeStringInterface || isset(static::$safeStrings[(string) $string][$strategy]) || isset(static::$safeStrings[(string) $string]['all']); } diff --git a/core/lib/Drupal/Component/Utility/SafeStringInterface.php b/core/lib/Drupal/Component/Utility/SafeStringInterface.php new file mode 100644 index 000000000000..372902711127 --- /dev/null +++ b/core/lib/Drupal/Component/Utility/SafeStringInterface.php @@ -0,0 +1,36 @@ +assertFalse(SafeMarkup::isSafe($returned, 'all'), 'String set with "html" provider is not safe for "all"'); } + /** + * Tests SafeMarkup::isSafe() with different objects. + * + * @covers ::isSafe + */ + public function testIsSafe() { + $safe_string = $this->getMock('\Drupal\Component\Utility\SafeStringInterface'); + $this->assertTrue(SafeMarkup::isSafe($safe_string)); + $string_object = new SafeMarkupTestString('test'); + $this->assertFalse(SafeMarkup::isSafe($string_object)); + } + /** * Tests SafeMarkup::setMultiple(). * @@ -258,3 +270,17 @@ class SafeMarkupTest extends UnitTestCase { } } + +class SafeMarkupTestString { + + protected $string; + + public function __construct($string) { + $this->string = $string; + } + + public function __toString() { + return $this->string; + } + +} diff --git a/core/tests/Drupal/Tests/Core/Template/TwigExtensionTest.php b/core/tests/Drupal/Tests/Core/Template/TwigExtensionTest.php index 75d0ef543945..e8718d5fd739 100644 --- a/core/tests/Drupal/Tests/Core/Template/TwigExtensionTest.php +++ b/core/tests/Drupal/Tests/Core/Template/TwigExtensionTest.php @@ -99,4 +99,43 @@ class TwigExtensionTest extends UnitTestCase { $this->assertEquals('test_theme', $result); } + /** + * Tests the escaping of objects implementing SafeStringInterface. + * + * @covers ::escapeFilter + */ + public function testSafeStringEscaping() { + $renderer = $this->getMock('\Drupal\Core\Render\RendererInterface'); + $twig = new \Twig_Environment(NULL, array( + 'debug' => TRUE, + 'cache' => FALSE, + 'autoescape' => TRUE, + 'optimizations' => 0 + )); + $twig_extension = new TwigExtension($renderer); + + // By default, TwigExtension will attempt to cast objects to strings. + // Ensure objects that implement SafeStringInterface are unchanged. + $safe_string = $this->getMock('\Drupal\Component\Utility\SafeStringInterface'); + $this->assertSame($safe_string, $twig_extension->escapeFilter($twig, $safe_string, 'html', 'UTF-8', TRUE)); + + // Ensure objects that do not implement SafeStringInterface are escaped. + $string_object = new TwigExtensionTestString(""); + $this->assertSame('<script>alert('here');</script>', $twig_extension->escapeFilter($twig, $string_object, 'html', 'UTF-8', TRUE)); + } + +} + +class TwigExtensionTestString { + + protected $string; + + public function __construct($string) { + $this->string = $string; + } + + public function __toString() { + return $this->string; + } + }