| 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 |