]> git.immae.eu Git - github/wallabag/wallabag.git/blob - vendor/twig/twig/test/Twig/Tests/Extension/SandboxTest.php
72253c88134f08639e3116effbd6d27d70412446
[github/wallabag/wallabag.git] / vendor / twig / twig / test / Twig / Tests / Extension / SandboxTest.php
1 <?php
2
3 /*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12 class Twig_Tests_Extension_SandboxTest extends PHPUnit_Framework_TestCase
13 {
14 protected static $params, $templates;
15
16 public function setUp()
17 {
18 self::$params = array(
19 'name' => 'Fabien',
20 'obj' => new FooObject(),
21 'arr' => array('obj' => new FooObject()),
22 );
23
24 self::$templates = array(
25 '1_basic1' => '{{ obj.foo }}',
26 '1_basic2' => '{{ name|upper }}',
27 '1_basic3' => '{% if name %}foo{% endif %}',
28 '1_basic4' => '{{ obj.bar }}',
29 '1_basic5' => '{{ obj }}',
30 '1_basic6' => '{{ arr.obj }}',
31 '1_basic7' => '{{ cycle(["foo","bar"], 1) }}',
32 '1_basic8' => '{{ obj.getfoobar }}{{ obj.getFooBar }}',
33 '1_basic' => '{% if obj.foo %}{{ obj.foo|upper }}{% endif %}',
34 '1_layout' => '{% block content %}{% endblock %}',
35 '1_child' => '{% extends "1_layout" %}{% block content %}{{ "a"|json_encode }}{% endblock %}',
36 );
37 }
38
39 /**
40 * @expectedException Twig_Sandbox_SecurityError
41 * @expectedExceptionMessage Filter "json_encode" is not allowed in "1_child".
42 */
43 public function testSandboxWithInheritance()
44 {
45 $twig = $this->getEnvironment(true, array(), self::$templates, array('block'));
46 $twig->loadTemplate('1_child')->render(array());
47 }
48
49 public function testSandboxGloballySet()
50 {
51 $twig = $this->getEnvironment(false, array(), self::$templates);
52 $this->assertEquals('FOO', $twig->loadTemplate('1_basic')->render(self::$params), 'Sandbox does nothing if it is disabled globally');
53
54 $twig = $this->getEnvironment(true, array(), self::$templates);
55 try {
56 $twig->loadTemplate('1_basic1')->render(self::$params);
57 $this->fail('Sandbox throws a SecurityError exception if an unallowed method is called');
58 } catch (Twig_Sandbox_SecurityError $e) {
59 }
60
61 $twig = $this->getEnvironment(true, array(), self::$templates);
62 try {
63 $twig->loadTemplate('1_basic2')->render(self::$params);
64 $this->fail('Sandbox throws a SecurityError exception if an unallowed filter is called');
65 } catch (Twig_Sandbox_SecurityError $e) {
66 }
67
68 $twig = $this->getEnvironment(true, array(), self::$templates);
69 try {
70 $twig->loadTemplate('1_basic3')->render(self::$params);
71 $this->fail('Sandbox throws a SecurityError exception if an unallowed tag is used in the template');
72 } catch (Twig_Sandbox_SecurityError $e) {
73 }
74
75 $twig = $this->getEnvironment(true, array(), self::$templates);
76 try {
77 $twig->loadTemplate('1_basic4')->render(self::$params);
78 $this->fail('Sandbox throws a SecurityError exception if an unallowed property is called in the template');
79 } catch (Twig_Sandbox_SecurityError $e) {
80 }
81
82 $twig = $this->getEnvironment(true, array(), self::$templates);
83 try {
84 $twig->loadTemplate('1_basic5')->render(self::$params);
85 $this->fail('Sandbox throws a SecurityError exception if an unallowed method (__toString()) is called in the template');
86 } catch (Twig_Sandbox_SecurityError $e) {
87 }
88
89 $twig = $this->getEnvironment(true, array(), self::$templates);
90 try {
91 $twig->loadTemplate('1_basic6')->render(self::$params);
92 $this->fail('Sandbox throws a SecurityError exception if an unallowed method (__toString()) is called in the template');
93 } catch (Twig_Sandbox_SecurityError $e) {
94 }
95
96 $twig = $this->getEnvironment(true, array(), self::$templates);
97 try {
98 $twig->loadTemplate('1_basic7')->render(self::$params);
99 $this->fail('Sandbox throws a SecurityError exception if an unallowed function is called in the template');
100 } catch (Twig_Sandbox_SecurityError $e) {
101 }
102
103 $twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array('FooObject' => 'foo'));
104 FooObject::reset();
105 $this->assertEquals('foo', $twig->loadTemplate('1_basic1')->render(self::$params), 'Sandbox allow some methods');
106 $this->assertEquals(1, FooObject::$called['foo'], 'Sandbox only calls method once');
107
108 $twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array('FooObject' => '__toString'));
109 FooObject::reset();
110 $this->assertEquals('foo', $twig->loadTemplate('1_basic5')->render(self::$params), 'Sandbox allow some methods');
111 $this->assertEquals(1, FooObject::$called['__toString'], 'Sandbox only calls method once');
112
113 $twig = $this->getEnvironment(true, array(), self::$templates, array(), array('upper'));
114 $this->assertEquals('FABIEN', $twig->loadTemplate('1_basic2')->render(self::$params), 'Sandbox allow some filters');
115
116 $twig = $this->getEnvironment(true, array(), self::$templates, array('if'));
117 $this->assertEquals('foo', $twig->loadTemplate('1_basic3')->render(self::$params), 'Sandbox allow some tags');
118
119 $twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array(), array('FooObject' => 'bar'));
120 $this->assertEquals('bar', $twig->loadTemplate('1_basic4')->render(self::$params), 'Sandbox allow some properties');
121
122 $twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array(), array(), array('cycle'));
123 $this->assertEquals('bar', $twig->loadTemplate('1_basic7')->render(self::$params), 'Sandbox allow some functions');
124
125 foreach (array('getfoobar', 'getFoobar', 'getFooBar') as $name) {
126 $twig = $this->getEnvironment(true, array(), self::$templates, array(), array(), array('FooObject' => $name));
127 FooObject::reset();
128 $this->assertEquals('foobarfoobar', $twig->loadTemplate('1_basic8')->render(self::$params), 'Sandbox allow methods in a case-insensitive way');
129 $this->assertEquals(2, FooObject::$called['getFooBar'], 'Sandbox only calls method once');
130 }
131 }
132
133 public function testSandboxLocallySetForAnInclude()
134 {
135 self::$templates = array(
136 '2_basic' => '{{ obj.foo }}{% include "2_included" %}{{ obj.foo }}',
137 '2_included' => '{% if obj.foo %}{{ obj.foo|upper }}{% endif %}',
138 );
139
140 $twig = $this->getEnvironment(false, array(), self::$templates);
141 $this->assertEquals('fooFOOfoo', $twig->loadTemplate('2_basic')->render(self::$params), 'Sandbox does nothing if disabled globally and sandboxed not used for the include');
142
143 self::$templates = array(
144 '3_basic' => '{{ obj.foo }}{% sandbox %}{% include "3_included" %}{% endsandbox %}{{ obj.foo }}',
145 '3_included' => '{% if obj.foo %}{{ obj.foo|upper }}{% endif %}',
146 );
147
148 $twig = $this->getEnvironment(true, array(), self::$templates);
149 try {
150 $twig->loadTemplate('3_basic')->render(self::$params);
151 $this->fail('Sandbox throws a SecurityError exception when the included file is sandboxed');
152 } catch (Twig_Sandbox_SecurityError $e) {
153 }
154 }
155
156 public function testMacrosInASandbox()
157 {
158 $twig = $this->getEnvironment(true, array('autoescape' => true), array('index' => <<<EOF
159 {%- import _self as macros %}
160
161 {%- macro test(text) %}<p>{{ text }}</p>{% endmacro %}
162
163 {{- macros.test('username') }}
164 EOF
165 ), array('macro', 'import'), array('escape'));
166
167 $this->assertEquals('<p>username</p>', $twig->loadTemplate('index')->render(array()));
168 }
169
170 protected function getEnvironment($sandboxed, $options, $templates, $tags = array(), $filters = array(), $methods = array(), $properties = array(), $functions = array())
171 {
172 $loader = new Twig_Loader_Array($templates);
173 $twig = new Twig_Environment($loader, array_merge(array('debug' => true, 'cache' => false, 'autoescape' => false), $options));
174 $policy = new Twig_Sandbox_SecurityPolicy($tags, $filters, $methods, $properties, $functions);
175 $twig->addExtension(new Twig_Extension_Sandbox($policy, $sandboxed));
176
177 return $twig;
178 }
179 }
180
181 class FooObject
182 {
183 public static $called = array('__toString' => 0, 'foo' => 0, 'getFooBar' => 0);
184
185 public $bar = 'bar';
186
187 public static function reset()
188 {
189 self::$called = array('__toString' => 0, 'foo' => 0, 'getFooBar' => 0);
190 }
191
192 public function __toString()
193 {
194 ++self::$called['__toString'];
195
196 return 'foo';
197 }
198
199 public function foo()
200 {
201 ++self::$called['foo'];
202
203 return 'foo';
204 }
205
206 public function getFooBar()
207 {
208 ++self::$called['getFooBar'];
209
210 return 'foobar';
211 }
212 }