fixed sandbox mode (__toString() method check was not enforced if called implicitly...
authorFabien Potencier <fabien.potencier@gmail.com>
Tue, 25 May 2010 16:01:48 +0000 (18:01 +0200)
committerFabien Potencier <fabien.potencier@gmail.com>
Tue, 25 May 2010 16:01:55 +0000 (18:01 +0200)
CHANGELOG
lib/Twig/Node/SandboxPrint.php [new file with mode: 0644]
lib/Twig/NodeVisitor/Sandbox.php
test/Twig/Tests/Extension/SandboxTest.php

index fc1b1fc..aad80f2 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -3,6 +3,7 @@
 Backward incompatibilities:
  * The short notation of the `block` tag changed.
 
+ * fixed sandbox mode (__toString() method check was not enforced if called implicitly from a simple statement like {{ article }})
  * added a 'as' string to the block tag short notation ({% block title "Title" %} must now be {% block title as "Title" %})
  * added an exception when a child template has a non-empty body (as it is always ignored when rendering)
 
diff --git a/lib/Twig/Node/SandboxPrint.php b/lib/Twig/Node/SandboxPrint.php
new file mode 100644 (file)
index 0000000..a2f98be
--- /dev/null
@@ -0,0 +1,44 @@
+<?php
+
+/*
+ * This file is part of Twig.
+ *
+ * (c) 2010 Fabien Potencier
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Twig_Node_SandboxPrint adds a check for the __toString() method
+ * when the variable is an object and the sandbox is activated.
+ *
+ * When there is a simple Print statement, like {{ article }},
+ * and if the sandbox is enabled, we need to check that the __toString()
+ * method is allowed if 'article' is an object.
+ *
+ * @package    twig
+ * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
+ * @version    SVN: $Id$
+ */
+class Twig_Node_SandboxPrint extends Twig_Node_Print
+{
+    public function compile($compiler)
+    {
+        $compiler
+            ->addDebugInfo($this)
+            ->write('if ($this->env->hasExtension(\'sandbox\') && is_object(')
+            ->subcompile($this->expr)
+            ->raw('))'."\n")
+            ->write('{'."\n")
+            ->indent()
+            ->write('$this->env->getExtension(\'sandbox\')->checkMethodAllowed(')
+            ->subcompile($this->expr)
+            ->raw(', \'__toString\');'."\n")
+            ->outdent()
+            ->write('}'."\n")
+        ;
+
+        parent::compile($compiler);
+    }
+}
index 197a4e7..55f751d 100644 (file)
@@ -34,6 +34,11 @@ class Twig_NodeVisitor_Sandbox implements Twig_NodeVisitorInterface
                     $this->filters[$filter[0]] = true;
                 }
             }
+
+            // look for simple print statement ({{ article }})
+            if ($node instanceof Twig_Node_Print && $node->getExpression() instanceof Twig_Node_Expression_Name) {
+                return new Twig_Node_SandboxPrint($node->getExpression(), $node->getLine(), $node->getTag());
+            }
         }
 
         return $node;
index 28e5591..25f4d01 100644 (file)
@@ -27,6 +27,7 @@ class Twig_Tests_Extension_SandboxTest extends PHPUnit_Framework_TestCase
             '1_basic2' => '{{ name|upper }}',
             '1_basic3' => '{% if name %}foo{% endif %}',
             '1_basic4' => '{{ obj.bar }}',
+            '1_basic5' => '{{ obj }}',
             '1_basic'  => '{% if obj.foo %}{{ obj.foo|upper }}{% endif %}',
         );
     }
@@ -64,9 +65,19 @@ class Twig_Tests_Extension_SandboxTest extends PHPUnit_Framework_TestCase
         } catch (Twig_Sandbox_SecurityError $e) {
         }
 
+        $twig = $this->getEnvironment(true, self::$templates);
+        try {
+            $twig->loadTemplate('1_basic5')->render(self::$params);
+            $this->fail('Sandbox throws a SecurityError exception if an unallowed method (__toString()) is called in the template');
+        } catch (Twig_Sandbox_SecurityError $e) {
+        }
+
         $twig = $this->getEnvironment(true, self::$templates, array(), array(), array('Object' => 'foo'));
         $this->assertEquals('foo', $twig->loadTemplate('1_basic1')->render(self::$params), 'Sandbox allow some methods');
 
+        $twig = $this->getEnvironment(true, self::$templates, array(), array(), array('Object' => '__toString'));
+        $this->assertEquals('foo', $twig->loadTemplate('1_basic5')->render(self::$params), 'Sandbox allow some methods');
+
         $twig = $this->getEnvironment(true, self::$templates, array(), array('upper'));
         $this->assertEquals('FABIEN', $twig->loadTemplate('1_basic2')->render(self::$params), 'Sandbox allow some filters');
 
@@ -115,6 +126,11 @@ class Object
 {
     public $bar = 'bar';
 
+    public function __toString()
+    {
+        return 'foo';
+    }
+
     public function foo()
     {
         return 'foo';