diff --git a/core/lib/Drupal/Core/Template/TwigEnvironment.php b/core/lib/Drupal/Core/Template/TwigEnvironment.php index 9225712..08faaf7 100644 --- a/core/lib/Drupal/Core/Template/TwigEnvironment.php +++ b/core/lib/Drupal/Core/Template/TwigEnvironment.php @@ -58,6 +58,10 @@ public function __construct($root, \Twig_LoaderInterface $loader = NULL, $option // Ensure autoescaping is always on. $options['autoescape'] = TRUE; + $policy = new TwigSandboxPolicy(); + $sandbox = new \Twig_Extension_Sandbox($policy, TRUE); + $this->addExtension($sandbox); + $this->loader = $loader; parent::__construct($this->loader, $options); } diff --git a/core/lib/Drupal/Core/Template/TwigSandboxPolicy.php b/core/lib/Drupal/Core/Template/TwigSandboxPolicy.php new file mode 100644 index 0000000..3ca65f2 --- /dev/null +++ b/core/lib/Drupal/Core/Template/TwigSandboxPolicy.php @@ -0,0 +1,59 @@ + - {{ title_prefix }} {% if not page %} diff --git a/core/tests/Drupal/Tests/Core/Template/TwigSandboxTest.php b/core/tests/Drupal/Tests/Core/Template/TwigSandboxTest.php new file mode 100644 index 0000000..46ed159 --- /dev/null +++ b/core/tests/Drupal/Tests/Core/Template/TwigSandboxTest.php @@ -0,0 +1,89 @@ +addExtension($sandbox); + + $entity = $this->getMock('Drupal\Core\Entity\EntityInterface'); + + $caught = FALSE; + try { + $twig->render('{{ entity.delete }}', ['entity' => $entity]); + } catch (\Twig_Sandbox_SecurityError $e) { + $caught = TRUE; + } + $this->assertTrue($caught, '\Twig_sandbox_security exception was thrown when entity was tried to be removed.'); + + $caught = FALSE; + try { + $twig->render('{{ entity.save }}', ['entity' => $entity]); + } catch (\Twig_Sandbox_SecurityError $e) { + $caught = TRUE; + } + $this->assertTrue($caught, '\Twig_sandbox_security exception was thrown when entity was tried to be saved.'); + + $caught = FALSE; + try { + $twig->render('{{ entity.create }}', ['entity' => $entity]); + } catch (\Twig_Sandbox_SecurityError $e) { + $caught = TRUE; + } + $this->assertTrue($caught, '\Twig_sandbox_security exception was thrown when new entity was tried to be created.'); + } + + public function testEntitySafeMethods() { + $loader = new \Twig_Loader_String(); + $twig = new \Twig_Environment($loader); + $policy = new TwigSandboxPolicy(); + $sandbox = new \Twig_Extension_Sandbox($policy, TRUE); + $twig->addExtension($sandbox); + + $entity = $this->getMock('Drupal\Core\Entity\EntityInterface'); + $entity->expects($this->atLeastOnce()) + ->method('hasLinkTemplate') + ->with('test') + ->willReturn(TRUE); + $result = $twig->render('{{ entity.hasLinkTemplate("test") }}', ['entity' => $entity]); + $this->assertTrue((bool)$result, 'Sandbox policy allows has* functions to be called.'); + + $entity = $this->getMock('Drupal\Core\Entity\EntityInterface'); + $entity->expects($this->atLeastOnce()) + ->method('isNew') + ->willReturn(TRUE); + $result = $twig->render('{{ entity.isNew }}', ['entity' => $entity]); + $this->assertTrue((bool)$result, 'Sandbox policy allows is* functions to be called.'); + + $entity = $this->getMock('Drupal\Core\Entity\EntityInterface'); + $entity->expects($this->atLeastOnce()) + ->method('getEntityType') + ->willReturn('test'); + $result = $twig->render('{{ entity.getEntityType }}', ['entity' => $entity]); + $this->assertEquals($result, 'test', 'Sandbox policy allows get* functions to be called.'); + } + +} diff --git a/core/themes/bartik/templates/node.html.twig b/core/themes/bartik/templates/node.html.twig index 25144bf..1d1afd3 100644 --- a/core/themes/bartik/templates/node.html.twig +++ b/core/themes/bartik/templates/node.html.twig @@ -4,12 +4,10 @@ * Bartik's theme implementation to display a node. * * Available variables: - * - node: Full node entity. - * - id: The node ID. - * - bundle: The type of the node, for example, "page" or "article". - * - authorid: The user ID of the node author. - * - createdtime: Time the node was published formatted in Unix timestamp. - * - changedtime: Time the node was changed formatted in Unix timestamp. + * - node: The node entity with limited access to object properties and methods. + Only "getter" methods (method names starting with "get", "has", or "is") + and a few common attributes such as "id" and "label" are available. Calling + other methods (such as node.delete) will result in an exception. * - label: The title of the node. * - content: All node items. Use {{ content }} to print them all, * or print a subset such as {{ content.field_example }}. Use @@ -64,7 +62,7 @@ {% set classes = [ 'node', - 'node--type-' ~ node.bundle|clean_class, + 'node--type-' ~ node.getType()|clean_class, node.isPromoted() ? 'node--promoted', node.isSticky() ? 'node--sticky', not node.isPublished() ? 'node--unpublished', diff --git a/core/themes/classy/templates/content/node.html.twig b/core/themes/classy/templates/content/node.html.twig index 5d746a6..cbc1899 100644 --- a/core/themes/classy/templates/content/node.html.twig +++ b/core/themes/classy/templates/content/node.html.twig @@ -4,12 +4,10 @@ * Theme override to display a node. * * Available variables: - * - node: Full node entity. - * - id: The node ID. - * - bundle: The type of the node, for example, "page" or "article". - * - authorid: The user ID of the node author. - * - createdtime: Time the node was published formatted in Unix timestamp. - * - changedtime: Time the node was changed formatted in Unix timestamp. + * - node: The node entity with limited access to object properties and methods. + Only "getter" methods (method names starting with "get", "has", or "is") + and a few common attributes such as "id" and "label" are available. Calling + other methods (such as node.delete) will result in an exception. * - label: The title of the node. * - content: All node items. Use {{ content }} to print them all, * or print a subset such as {{ content.field_example }}. Use @@ -68,7 +66,7 @@ {% set classes = [ 'node', - 'node--type-' ~ node.bundle|clean_class, + 'node--type-' ~ node.getType()|clean_class, node.isPromoted() ? 'node--promoted', node.isSticky() ? 'node--sticky', not node.isPublished() ? 'node--unpublished', diff --git a/core/themes/classy/templates/content/taxonomy-term.html.twig b/core/themes/classy/templates/content/taxonomy-term.html.twig index 7e0446e..4284950 100644 --- a/core/themes/classy/templates/content/taxonomy-term.html.twig +++ b/core/themes/classy/templates/content/taxonomy-term.html.twig @@ -26,7 +26,7 @@ {% set classes = [ 'taxonomy-term', - 'vocabulary-' ~ term.bundle|clean_class, + 'vocabulary-' ~ term.getType()|clean_class, ] %}