OLD | NEW |
1 # -*- coding: utf-8 -*- | 1 # -*- coding: utf-8 -*- |
2 """ | 2 """ |
3 jinja2.sandbox | 3 jinja2.sandbox |
4 ~~~~~~~~~~~~~~ | 4 ~~~~~~~~~~~~~~ |
5 | 5 |
6 Adds a sandbox layer to Jinja as it was the default behavior in the old | 6 Adds a sandbox layer to Jinja as it was the default behavior in the old |
7 Jinja 1 releases. This sandbox is slightly different from Jinja 1 as the | 7 Jinja 1 releases. This sandbox is slightly different from Jinja 1 as the |
8 default behavior is easier to use. | 8 default behavior is easier to use. |
9 | 9 |
10 The behavior can be changed by subclassing the environment. | 10 The behavior can be changed by subclassing the environment. |
11 | 11 |
12 :copyright: (c) 2010 by the Jinja Team. | 12 :copyright: (c) 2010 by the Jinja Team. |
13 :license: BSD. | 13 :license: BSD. |
14 """ | 14 """ |
15 import operator | 15 import operator |
16 from jinja2.environment import Environment | 16 from jinja2.environment import Environment |
17 from jinja2.exceptions import SecurityError | 17 from jinja2.exceptions import SecurityError |
18 from jinja2.utils import FunctionType, MethodType, TracebackType, CodeType, \ | 18 from jinja2._compat import string_types, function_type, method_type, \ |
19 FrameType, GeneratorType | 19 traceback_type, code_type, frame_type, generator_type, PY2 |
20 | 20 |
21 | 21 |
22 #: maximum number of items a range may produce | 22 #: maximum number of items a range may produce |
23 MAX_RANGE = 100000 | 23 MAX_RANGE = 100000 |
24 | 24 |
25 #: attributes of function objects that are considered unsafe. | 25 #: attributes of function objects that are considered unsafe. |
26 UNSAFE_FUNCTION_ATTRIBUTES = set(['func_closure', 'func_code', 'func_dict', | 26 UNSAFE_FUNCTION_ATTRIBUTES = set(['func_closure', 'func_code', 'func_dict', |
27 'func_defaults', 'func_globals']) | 27 'func_defaults', 'func_globals']) |
28 | 28 |
29 #: unsafe method attributes. function attributes are unsafe for methods too | 29 #: unsafe method attributes. function attributes are unsafe for methods too |
30 UNSAFE_METHOD_ATTRIBUTES = set(['im_class', 'im_func', 'im_self']) | 30 UNSAFE_METHOD_ATTRIBUTES = set(['im_class', 'im_func', 'im_self']) |
31 | 31 |
| 32 #: unsafe generator attirbutes. |
| 33 UNSAFE_GENERATOR_ATTRIBUTES = set(['gi_frame', 'gi_code']) |
| 34 |
| 35 # On versions > python 2 the special attributes on functions are gone, |
| 36 # but they remain on methods and generators for whatever reason. |
| 37 if not PY2: |
| 38 UNSAFE_FUNCTION_ATTRIBUTES = set() |
32 | 39 |
33 import warnings | 40 import warnings |
34 | 41 |
35 # make sure we don't warn in python 2.6 about stuff we don't care about | 42 # make sure we don't warn in python 2.6 about stuff we don't care about |
36 warnings.filterwarnings('ignore', 'the sets module', DeprecationWarning, | 43 warnings.filterwarnings('ignore', 'the sets module', DeprecationWarning, |
37 module='jinja2.sandbox') | 44 module='jinja2.sandbox') |
38 | 45 |
39 from collections import deque | 46 from collections import deque |
40 | 47 |
41 _mutable_set_types = (set,) | 48 _mutable_set_types = (set,) |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
83 'append', 'appendleft', 'clear', 'extend', 'extendleft', 'pop', | 90 'append', 'appendleft', 'clear', 'extend', 'extendleft', 'pop', |
84 'popleft', 'remove', 'rotate' | 91 'popleft', 'remove', 'rotate' |
85 ])) | 92 ])) |
86 ) | 93 ) |
87 | 94 |
88 | 95 |
89 def safe_range(*args): | 96 def safe_range(*args): |
90 """A range that can't generate ranges with a length of more than | 97 """A range that can't generate ranges with a length of more than |
91 MAX_RANGE items. | 98 MAX_RANGE items. |
92 """ | 99 """ |
93 rng = xrange(*args) | 100 rng = range(*args) |
94 if len(rng) > MAX_RANGE: | 101 if len(rng) > MAX_RANGE: |
95 raise OverflowError('range too big, maximum size for range is %d' % | 102 raise OverflowError('range too big, maximum size for range is %d' % |
96 MAX_RANGE) | 103 MAX_RANGE) |
97 return rng | 104 return rng |
98 | 105 |
99 | 106 |
100 def unsafe(f): | 107 def unsafe(f): |
101 """Marks a function or method as unsafe. | 108 """Marks a function or method as unsafe. |
102 | 109 |
103 :: | 110 :: |
104 | 111 |
105 @unsafe | 112 @unsafe |
106 def delete(self): | 113 def delete(self): |
107 pass | 114 pass |
108 """ | 115 """ |
109 f.unsafe_callable = True | 116 f.unsafe_callable = True |
110 return f | 117 return f |
111 | 118 |
112 | 119 |
113 def is_internal_attribute(obj, attr): | 120 def is_internal_attribute(obj, attr): |
114 """Test if the attribute given is an internal python attribute. For | 121 """Test if the attribute given is an internal python attribute. For |
115 example this function returns `True` for the `func_code` attribute of | 122 example this function returns `True` for the `func_code` attribute of |
116 python objects. This is useful if the environment method | 123 python objects. This is useful if the environment method |
117 :meth:`~SandboxedEnvironment.is_safe_attribute` is overriden. | 124 :meth:`~SandboxedEnvironment.is_safe_attribute` is overridden. |
118 | 125 |
119 >>> from jinja2.sandbox import is_internal_attribute | 126 >>> from jinja2.sandbox import is_internal_attribute |
120 >>> is_internal_attribute(lambda: None, "func_code") | 127 >>> is_internal_attribute(lambda: None, "func_code") |
121 True | 128 True |
122 >>> is_internal_attribute((lambda x:x).func_code, 'co_code') | 129 >>> is_internal_attribute((lambda x:x).func_code, 'co_code') |
123 True | 130 True |
124 >>> is_internal_attribute(str, "upper") | 131 >>> is_internal_attribute(str, "upper") |
125 False | 132 False |
126 """ | 133 """ |
127 if isinstance(obj, FunctionType): | 134 if isinstance(obj, function_type): |
128 if attr in UNSAFE_FUNCTION_ATTRIBUTES: | 135 if attr in UNSAFE_FUNCTION_ATTRIBUTES: |
129 return True | 136 return True |
130 elif isinstance(obj, MethodType): | 137 elif isinstance(obj, method_type): |
131 if attr in UNSAFE_FUNCTION_ATTRIBUTES or \ | 138 if attr in UNSAFE_FUNCTION_ATTRIBUTES or \ |
132 attr in UNSAFE_METHOD_ATTRIBUTES: | 139 attr in UNSAFE_METHOD_ATTRIBUTES: |
133 return True | 140 return True |
134 elif isinstance(obj, type): | 141 elif isinstance(obj, type): |
135 if attr == 'mro': | 142 if attr == 'mro': |
136 return True | 143 return True |
137 elif isinstance(obj, (CodeType, TracebackType, FrameType)): | 144 elif isinstance(obj, (code_type, traceback_type, frame_type)): |
138 return True | 145 return True |
139 elif isinstance(obj, GeneratorType): | 146 elif isinstance(obj, generator_type): |
140 if attr == 'gi_frame': | 147 if attr in UNSAFE_GENERATOR_ATTRIBUTES: |
141 return True | 148 return True |
142 return attr.startswith('__') | 149 return attr.startswith('__') |
143 | 150 |
144 | 151 |
145 def modifies_known_mutable(obj, attr): | 152 def modifies_known_mutable(obj, attr): |
146 """This function checks if an attribute on a builtin mutable object | 153 """This function checks if an attribute on a builtin mutable object |
147 (list, dict, set or deque) would modify it if called. It also supports | 154 (list, dict, set or deque) would modify it if called. It also supports |
148 the "user"-versions of the objects (`sets.Set`, `UserDict.*` etc.) and | 155 the "user"-versions of the objects (`sets.Set`, `UserDict.*` etc.) and |
149 with Python 2.6 onwards the abstract base classes `MutableSet`, | 156 with Python 2.6 onwards the abstract base classes `MutableSet`, |
150 `MutableMapping`, and `MutableSequence`. | 157 `MutableMapping`, and `MutableSequence`. |
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
292 | 299 |
293 .. versionadded:: 2.6 | 300 .. versionadded:: 2.6 |
294 """ | 301 """ |
295 return self.unop_table[operator](arg) | 302 return self.unop_table[operator](arg) |
296 | 303 |
297 def getitem(self, obj, argument): | 304 def getitem(self, obj, argument): |
298 """Subscribe an object from sandboxed code.""" | 305 """Subscribe an object from sandboxed code.""" |
299 try: | 306 try: |
300 return obj[argument] | 307 return obj[argument] |
301 except (TypeError, LookupError): | 308 except (TypeError, LookupError): |
302 if isinstance(argument, basestring): | 309 if isinstance(argument, string_types): |
303 try: | 310 try: |
304 attr = str(argument) | 311 attr = str(argument) |
305 except Exception: | 312 except Exception: |
306 pass | 313 pass |
307 else: | 314 else: |
308 try: | 315 try: |
309 value = getattr(obj, attr) | 316 value = getattr(obj, attr) |
310 except AttributeError: | 317 except AttributeError: |
311 pass | 318 pass |
312 else: | 319 else: |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
352 class ImmutableSandboxedEnvironment(SandboxedEnvironment): | 359 class ImmutableSandboxedEnvironment(SandboxedEnvironment): |
353 """Works exactly like the regular `SandboxedEnvironment` but does not | 360 """Works exactly like the regular `SandboxedEnvironment` but does not |
354 permit modifications on the builtin mutable objects `list`, `set`, and | 361 permit modifications on the builtin mutable objects `list`, `set`, and |
355 `dict` by using the :func:`modifies_known_mutable` function. | 362 `dict` by using the :func:`modifies_known_mutable` function. |
356 """ | 363 """ |
357 | 364 |
358 def is_safe_attribute(self, obj, attr, value): | 365 def is_safe_attribute(self, obj, attr, value): |
359 if not SandboxedEnvironment.is_safe_attribute(self, obj, attr, value): | 366 if not SandboxedEnvironment.is_safe_attribute(self, obj, attr, value): |
360 return False | 367 return False |
361 return not modifies_known_mutable(obj, attr) | 368 return not modifies_known_mutable(obj, attr) |
OLD | NEW |