diff --git a/CHANGELOG b/CHANGELOG index de9f268d5..7318ae04b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -97,7 +97,12 @@ * improved the performance of the filesystem loader * removed features that were deprecated in 1.x -* 1.35.2 (2018-XX-XX) +* 1.35.3 (2018-XX-XX) + + * added missing else clause to avoid infinite loops + * fixed .. (range operator) in sandbox policy + +* 1.35.2 (2018-03-03) * fixed a regression in the way the profiler is registered in templates diff --git a/lib/Twig/Lexer.php b/lib/Twig/Lexer.php index ad6dc12ec..fa06eaeaf 100644 --- a/lib/Twig/Lexer.php +++ b/lib/Twig/Lexer.php @@ -314,6 +314,9 @@ class Twig_Lexer $this->popState(); ++$this->cursor; + } else { + // unlexable + throw new Twig_Error_Syntax(sprintf('Unexpected character "%s".', $this->code[$this->cursor]), $this->lineno, $this->source); } } diff --git a/lib/Twig/NodeVisitor/Sandbox.php b/lib/Twig/NodeVisitor/Sandbox.php index c8f87bd65..46ac722dd 100644 --- a/lib/Twig/NodeVisitor/Sandbox.php +++ b/lib/Twig/NodeVisitor/Sandbox.php @@ -46,6 +46,11 @@ final class Twig_NodeVisitor_Sandbox extends Twig_BaseNodeVisitor $this->functions[$node->getAttribute('name')] = $node; } + // the .. operator is equivalent to the range() function + if ($node instanceof Twig_Node_Expression_Binary_Range && !isset($this->functions['range'])) { + $this->functions['range'] = $node; + } + // wrap print to check __toString() calls if ($node instanceof Twig_Node_Print) { return new Twig_Node_SandboxedPrint($node->getNode('expr'), $node->getTemplateLine(), $node->getNodeTag()); diff --git a/test/Twig/Tests/Extension/SandboxTest.php b/test/Twig/Tests/Extension/SandboxTest.php index 10f83bd63..20443aab1 100644 --- a/test/Twig/Tests/Extension/SandboxTest.php +++ b/test/Twig/Tests/Extension/SandboxTest.php @@ -36,6 +36,7 @@ class Twig_Tests_Extension_SandboxTest extends \PHPUnit\Framework\TestCase '1_layout' => '{% block content %}{% endblock %}', '1_child' => "{% extends \"1_layout\" %}\n{% block content %}\n{{ \"a\"|json_encode }}\n{% endblock %}", '1_include' => '{{ include("1_basic1", sandboxed=true) }}', + '1_range_operator' => '{{ (1..2)[0] }}', ); } @@ -143,6 +144,18 @@ class Twig_Tests_Extension_SandboxTest extends \PHPUnit\Framework\TestCase } } + public function testSandboxUnallowedRangeOperator() + { + $twig = $this->getEnvironment(true, array(), self::$templates); + try { + $twig->loadTemplate('1_range_operator')->render(self::$params); + $this->fail('Sandbox throws a SecurityError exception if the unallowed range operator is called'); + } catch (Twig_Sandbox_SecurityError $e) { + $this->assertInstanceOf('Twig_Sandbox_SecurityNotAllowedFunctionError', $e, 'Exception should be an instance of Twig_Sandbox_SecurityNotAllowedFunctionError'); + $this->assertEquals('range', $e->getFunctionName(), 'Exception should be raised on the "range" function'); + } + } + public function testSandboxAllowMethodFoo() { $twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array('FooObject' => 'foo')); @@ -191,6 +204,12 @@ class Twig_Tests_Extension_SandboxTest extends \PHPUnit\Framework\TestCase $this->assertEquals('bar', $twig->loadTemplate('1_basic7')->render(self::$params), 'Sandbox allow some functions'); } + public function testSandboxAllowRangeOperator() + { + $twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array(), array(), array('range')); + $this->assertEquals('1', $twig->loadTemplate('1_range_operator')->render(self::$params), 'Sandbox allow the range operator'); + } + public function testSandboxAllowFunctionsCaseInsensitive() { foreach (array('getfoobar', 'getFoobar', 'getFooBar') as $name) {