11cb0ef41Sopenharmony_ci# -*- coding: utf-8 -*- 21cb0ef41Sopenharmony_ci""" 31cb0ef41Sopenharmony_ci jinja2.sandbox 41cb0ef41Sopenharmony_ci ~~~~~~~~~~~~~~ 51cb0ef41Sopenharmony_ci 61cb0ef41Sopenharmony_ci Adds a sandbox layer to Jinja as it was the default behavior in the old 71cb0ef41Sopenharmony_ci Jinja 1 releases. This sandbox is slightly different from Jinja 1 as the 81cb0ef41Sopenharmony_ci default behavior is easier to use. 91cb0ef41Sopenharmony_ci 101cb0ef41Sopenharmony_ci The behavior can be changed by subclassing the environment. 111cb0ef41Sopenharmony_ci 121cb0ef41Sopenharmony_ci :copyright: (c) 2017 by the Jinja Team. 131cb0ef41Sopenharmony_ci :license: BSD. 141cb0ef41Sopenharmony_ci""" 151cb0ef41Sopenharmony_ciimport types 161cb0ef41Sopenharmony_ciimport operator 171cb0ef41Sopenharmony_cifrom collections import Mapping 181cb0ef41Sopenharmony_cifrom jinja2.environment import Environment 191cb0ef41Sopenharmony_cifrom jinja2.exceptions import SecurityError 201cb0ef41Sopenharmony_cifrom jinja2._compat import string_types, PY2 211cb0ef41Sopenharmony_cifrom jinja2.utils import Markup 221cb0ef41Sopenharmony_ci 231cb0ef41Sopenharmony_cifrom markupsafe import EscapeFormatter 241cb0ef41Sopenharmony_cifrom string import Formatter 251cb0ef41Sopenharmony_ci 261cb0ef41Sopenharmony_ci 271cb0ef41Sopenharmony_ci#: maximum number of items a range may produce 281cb0ef41Sopenharmony_ciMAX_RANGE = 100000 291cb0ef41Sopenharmony_ci 301cb0ef41Sopenharmony_ci#: attributes of function objects that are considered unsafe. 311cb0ef41Sopenharmony_ciif PY2: 321cb0ef41Sopenharmony_ci UNSAFE_FUNCTION_ATTRIBUTES = set(['func_closure', 'func_code', 'func_dict', 331cb0ef41Sopenharmony_ci 'func_defaults', 'func_globals']) 341cb0ef41Sopenharmony_cielse: 351cb0ef41Sopenharmony_ci # On versions > python 2 the special attributes on functions are gone, 361cb0ef41Sopenharmony_ci # but they remain on methods and generators for whatever reason. 371cb0ef41Sopenharmony_ci UNSAFE_FUNCTION_ATTRIBUTES = set() 381cb0ef41Sopenharmony_ci 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_ci#: unsafe method attributes. function attributes are unsafe for methods too 411cb0ef41Sopenharmony_ciUNSAFE_METHOD_ATTRIBUTES = set(['im_class', 'im_func', 'im_self']) 421cb0ef41Sopenharmony_ci 431cb0ef41Sopenharmony_ci#: unsafe generator attirbutes. 441cb0ef41Sopenharmony_ciUNSAFE_GENERATOR_ATTRIBUTES = set(['gi_frame', 'gi_code']) 451cb0ef41Sopenharmony_ci 461cb0ef41Sopenharmony_ci#: unsafe attributes on coroutines 471cb0ef41Sopenharmony_ciUNSAFE_COROUTINE_ATTRIBUTES = set(['cr_frame', 'cr_code']) 481cb0ef41Sopenharmony_ci 491cb0ef41Sopenharmony_ci#: unsafe attributes on async generators 501cb0ef41Sopenharmony_ciUNSAFE_ASYNC_GENERATOR_ATTRIBUTES = set(['ag_code', 'ag_frame']) 511cb0ef41Sopenharmony_ci 521cb0ef41Sopenharmony_ciimport warnings 531cb0ef41Sopenharmony_ci 541cb0ef41Sopenharmony_ci# make sure we don't warn in python 2.6 about stuff we don't care about 551cb0ef41Sopenharmony_ciwarnings.filterwarnings('ignore', 'the sets module', DeprecationWarning, 561cb0ef41Sopenharmony_ci module='jinja2.sandbox') 571cb0ef41Sopenharmony_ci 581cb0ef41Sopenharmony_cifrom collections import deque 591cb0ef41Sopenharmony_ci 601cb0ef41Sopenharmony_ci_mutable_set_types = (set,) 611cb0ef41Sopenharmony_ci_mutable_mapping_types = (dict,) 621cb0ef41Sopenharmony_ci_mutable_sequence_types = (list,) 631cb0ef41Sopenharmony_ci 641cb0ef41Sopenharmony_ci 651cb0ef41Sopenharmony_ci# on python 2.x we can register the user collection types 661cb0ef41Sopenharmony_citry: 671cb0ef41Sopenharmony_ci from UserDict import UserDict, DictMixin 681cb0ef41Sopenharmony_ci from UserList import UserList 691cb0ef41Sopenharmony_ci _mutable_mapping_types += (UserDict, DictMixin) 701cb0ef41Sopenharmony_ci _mutable_set_types += (UserList,) 711cb0ef41Sopenharmony_ciexcept ImportError: 721cb0ef41Sopenharmony_ci pass 731cb0ef41Sopenharmony_ci 741cb0ef41Sopenharmony_ci# if sets is still available, register the mutable set from there as well 751cb0ef41Sopenharmony_citry: 761cb0ef41Sopenharmony_ci from sets import Set 771cb0ef41Sopenharmony_ci _mutable_set_types += (Set,) 781cb0ef41Sopenharmony_ciexcept ImportError: 791cb0ef41Sopenharmony_ci pass 801cb0ef41Sopenharmony_ci 811cb0ef41Sopenharmony_ci#: register Python 2.6 abstract base classes 821cb0ef41Sopenharmony_cifrom collections import MutableSet, MutableMapping, MutableSequence 831cb0ef41Sopenharmony_ci_mutable_set_types += (MutableSet,) 841cb0ef41Sopenharmony_ci_mutable_mapping_types += (MutableMapping,) 851cb0ef41Sopenharmony_ci_mutable_sequence_types += (MutableSequence,) 861cb0ef41Sopenharmony_ci 871cb0ef41Sopenharmony_ci 881cb0ef41Sopenharmony_ci_mutable_spec = ( 891cb0ef41Sopenharmony_ci (_mutable_set_types, frozenset([ 901cb0ef41Sopenharmony_ci 'add', 'clear', 'difference_update', 'discard', 'pop', 'remove', 911cb0ef41Sopenharmony_ci 'symmetric_difference_update', 'update' 921cb0ef41Sopenharmony_ci ])), 931cb0ef41Sopenharmony_ci (_mutable_mapping_types, frozenset([ 941cb0ef41Sopenharmony_ci 'clear', 'pop', 'popitem', 'setdefault', 'update' 951cb0ef41Sopenharmony_ci ])), 961cb0ef41Sopenharmony_ci (_mutable_sequence_types, frozenset([ 971cb0ef41Sopenharmony_ci 'append', 'reverse', 'insert', 'sort', 'extend', 'remove' 981cb0ef41Sopenharmony_ci ])), 991cb0ef41Sopenharmony_ci (deque, frozenset([ 1001cb0ef41Sopenharmony_ci 'append', 'appendleft', 'clear', 'extend', 'extendleft', 'pop', 1011cb0ef41Sopenharmony_ci 'popleft', 'remove', 'rotate' 1021cb0ef41Sopenharmony_ci ])) 1031cb0ef41Sopenharmony_ci) 1041cb0ef41Sopenharmony_ci 1051cb0ef41Sopenharmony_ci 1061cb0ef41Sopenharmony_ciclass _MagicFormatMapping(Mapping): 1071cb0ef41Sopenharmony_ci """This class implements a dummy wrapper to fix a bug in the Python 1081cb0ef41Sopenharmony_ci standard library for string formatting. 1091cb0ef41Sopenharmony_ci 1101cb0ef41Sopenharmony_ci See https://bugs.python.org/issue13598 for information about why 1111cb0ef41Sopenharmony_ci this is necessary. 1121cb0ef41Sopenharmony_ci """ 1131cb0ef41Sopenharmony_ci 1141cb0ef41Sopenharmony_ci def __init__(self, args, kwargs): 1151cb0ef41Sopenharmony_ci self._args = args 1161cb0ef41Sopenharmony_ci self._kwargs = kwargs 1171cb0ef41Sopenharmony_ci self._last_index = 0 1181cb0ef41Sopenharmony_ci 1191cb0ef41Sopenharmony_ci def __getitem__(self, key): 1201cb0ef41Sopenharmony_ci if key == '': 1211cb0ef41Sopenharmony_ci idx = self._last_index 1221cb0ef41Sopenharmony_ci self._last_index += 1 1231cb0ef41Sopenharmony_ci try: 1241cb0ef41Sopenharmony_ci return self._args[idx] 1251cb0ef41Sopenharmony_ci except LookupError: 1261cb0ef41Sopenharmony_ci pass 1271cb0ef41Sopenharmony_ci key = str(idx) 1281cb0ef41Sopenharmony_ci return self._kwargs[key] 1291cb0ef41Sopenharmony_ci 1301cb0ef41Sopenharmony_ci def __iter__(self): 1311cb0ef41Sopenharmony_ci return iter(self._kwargs) 1321cb0ef41Sopenharmony_ci 1331cb0ef41Sopenharmony_ci def __len__(self): 1341cb0ef41Sopenharmony_ci return len(self._kwargs) 1351cb0ef41Sopenharmony_ci 1361cb0ef41Sopenharmony_ci 1371cb0ef41Sopenharmony_cidef inspect_format_method(callable): 1381cb0ef41Sopenharmony_ci if not isinstance(callable, (types.MethodType, 1391cb0ef41Sopenharmony_ci types.BuiltinMethodType)) or \ 1401cb0ef41Sopenharmony_ci callable.__name__ != 'format': 1411cb0ef41Sopenharmony_ci return None 1421cb0ef41Sopenharmony_ci obj = callable.__self__ 1431cb0ef41Sopenharmony_ci if isinstance(obj, string_types): 1441cb0ef41Sopenharmony_ci return obj 1451cb0ef41Sopenharmony_ci 1461cb0ef41Sopenharmony_ci 1471cb0ef41Sopenharmony_cidef safe_range(*args): 1481cb0ef41Sopenharmony_ci """A range that can't generate ranges with a length of more than 1491cb0ef41Sopenharmony_ci MAX_RANGE items. 1501cb0ef41Sopenharmony_ci """ 1511cb0ef41Sopenharmony_ci rng = range(*args) 1521cb0ef41Sopenharmony_ci if len(rng) > MAX_RANGE: 1531cb0ef41Sopenharmony_ci raise OverflowError('range too big, maximum size for range is %d' % 1541cb0ef41Sopenharmony_ci MAX_RANGE) 1551cb0ef41Sopenharmony_ci return rng 1561cb0ef41Sopenharmony_ci 1571cb0ef41Sopenharmony_ci 1581cb0ef41Sopenharmony_cidef unsafe(f): 1591cb0ef41Sopenharmony_ci """Marks a function or method as unsafe. 1601cb0ef41Sopenharmony_ci 1611cb0ef41Sopenharmony_ci :: 1621cb0ef41Sopenharmony_ci 1631cb0ef41Sopenharmony_ci @unsafe 1641cb0ef41Sopenharmony_ci def delete(self): 1651cb0ef41Sopenharmony_ci pass 1661cb0ef41Sopenharmony_ci """ 1671cb0ef41Sopenharmony_ci f.unsafe_callable = True 1681cb0ef41Sopenharmony_ci return f 1691cb0ef41Sopenharmony_ci 1701cb0ef41Sopenharmony_ci 1711cb0ef41Sopenharmony_cidef is_internal_attribute(obj, attr): 1721cb0ef41Sopenharmony_ci """Test if the attribute given is an internal python attribute. For 1731cb0ef41Sopenharmony_ci example this function returns `True` for the `func_code` attribute of 1741cb0ef41Sopenharmony_ci python objects. This is useful if the environment method 1751cb0ef41Sopenharmony_ci :meth:`~SandboxedEnvironment.is_safe_attribute` is overridden. 1761cb0ef41Sopenharmony_ci 1771cb0ef41Sopenharmony_ci >>> from jinja2.sandbox import is_internal_attribute 1781cb0ef41Sopenharmony_ci >>> is_internal_attribute(str, "mro") 1791cb0ef41Sopenharmony_ci True 1801cb0ef41Sopenharmony_ci >>> is_internal_attribute(str, "upper") 1811cb0ef41Sopenharmony_ci False 1821cb0ef41Sopenharmony_ci """ 1831cb0ef41Sopenharmony_ci if isinstance(obj, types.FunctionType): 1841cb0ef41Sopenharmony_ci if attr in UNSAFE_FUNCTION_ATTRIBUTES: 1851cb0ef41Sopenharmony_ci return True 1861cb0ef41Sopenharmony_ci elif isinstance(obj, types.MethodType): 1871cb0ef41Sopenharmony_ci if attr in UNSAFE_FUNCTION_ATTRIBUTES or \ 1881cb0ef41Sopenharmony_ci attr in UNSAFE_METHOD_ATTRIBUTES: 1891cb0ef41Sopenharmony_ci return True 1901cb0ef41Sopenharmony_ci elif isinstance(obj, type): 1911cb0ef41Sopenharmony_ci if attr == 'mro': 1921cb0ef41Sopenharmony_ci return True 1931cb0ef41Sopenharmony_ci elif isinstance(obj, (types.CodeType, types.TracebackType, types.FrameType)): 1941cb0ef41Sopenharmony_ci return True 1951cb0ef41Sopenharmony_ci elif isinstance(obj, types.GeneratorType): 1961cb0ef41Sopenharmony_ci if attr in UNSAFE_GENERATOR_ATTRIBUTES: 1971cb0ef41Sopenharmony_ci return True 1981cb0ef41Sopenharmony_ci elif hasattr(types, 'CoroutineType') and isinstance(obj, types.CoroutineType): 1991cb0ef41Sopenharmony_ci if attr in UNSAFE_COROUTINE_ATTRIBUTES: 2001cb0ef41Sopenharmony_ci return True 2011cb0ef41Sopenharmony_ci elif hasattr(types, 'AsyncGeneratorType') and isinstance(obj, types.AsyncGeneratorType): 2021cb0ef41Sopenharmony_ci if attr in UNSAFE_ASYNC_GENERATOR_ATTRIBUTES: 2031cb0ef41Sopenharmony_ci return True 2041cb0ef41Sopenharmony_ci return attr.startswith('__') 2051cb0ef41Sopenharmony_ci 2061cb0ef41Sopenharmony_ci 2071cb0ef41Sopenharmony_cidef modifies_known_mutable(obj, attr): 2081cb0ef41Sopenharmony_ci """This function checks if an attribute on a builtin mutable object 2091cb0ef41Sopenharmony_ci (list, dict, set or deque) would modify it if called. It also supports 2101cb0ef41Sopenharmony_ci the "user"-versions of the objects (`sets.Set`, `UserDict.*` etc.) and 2111cb0ef41Sopenharmony_ci with Python 2.6 onwards the abstract base classes `MutableSet`, 2121cb0ef41Sopenharmony_ci `MutableMapping`, and `MutableSequence`. 2131cb0ef41Sopenharmony_ci 2141cb0ef41Sopenharmony_ci >>> modifies_known_mutable({}, "clear") 2151cb0ef41Sopenharmony_ci True 2161cb0ef41Sopenharmony_ci >>> modifies_known_mutable({}, "keys") 2171cb0ef41Sopenharmony_ci False 2181cb0ef41Sopenharmony_ci >>> modifies_known_mutable([], "append") 2191cb0ef41Sopenharmony_ci True 2201cb0ef41Sopenharmony_ci >>> modifies_known_mutable([], "index") 2211cb0ef41Sopenharmony_ci False 2221cb0ef41Sopenharmony_ci 2231cb0ef41Sopenharmony_ci If called with an unsupported object (such as unicode) `False` is 2241cb0ef41Sopenharmony_ci returned. 2251cb0ef41Sopenharmony_ci 2261cb0ef41Sopenharmony_ci >>> modifies_known_mutable("foo", "upper") 2271cb0ef41Sopenharmony_ci False 2281cb0ef41Sopenharmony_ci """ 2291cb0ef41Sopenharmony_ci for typespec, unsafe in _mutable_spec: 2301cb0ef41Sopenharmony_ci if isinstance(obj, typespec): 2311cb0ef41Sopenharmony_ci return attr in unsafe 2321cb0ef41Sopenharmony_ci return False 2331cb0ef41Sopenharmony_ci 2341cb0ef41Sopenharmony_ci 2351cb0ef41Sopenharmony_ciclass SandboxedEnvironment(Environment): 2361cb0ef41Sopenharmony_ci """The sandboxed environment. It works like the regular environment but 2371cb0ef41Sopenharmony_ci tells the compiler to generate sandboxed code. Additionally subclasses of 2381cb0ef41Sopenharmony_ci this environment may override the methods that tell the runtime what 2391cb0ef41Sopenharmony_ci attributes or functions are safe to access. 2401cb0ef41Sopenharmony_ci 2411cb0ef41Sopenharmony_ci If the template tries to access insecure code a :exc:`SecurityError` is 2421cb0ef41Sopenharmony_ci raised. However also other exceptions may occur during the rendering so 2431cb0ef41Sopenharmony_ci the caller has to ensure that all exceptions are caught. 2441cb0ef41Sopenharmony_ci """ 2451cb0ef41Sopenharmony_ci sandboxed = True 2461cb0ef41Sopenharmony_ci 2471cb0ef41Sopenharmony_ci #: default callback table for the binary operators. A copy of this is 2481cb0ef41Sopenharmony_ci #: available on each instance of a sandboxed environment as 2491cb0ef41Sopenharmony_ci #: :attr:`binop_table` 2501cb0ef41Sopenharmony_ci default_binop_table = { 2511cb0ef41Sopenharmony_ci '+': operator.add, 2521cb0ef41Sopenharmony_ci '-': operator.sub, 2531cb0ef41Sopenharmony_ci '*': operator.mul, 2541cb0ef41Sopenharmony_ci '/': operator.truediv, 2551cb0ef41Sopenharmony_ci '//': operator.floordiv, 2561cb0ef41Sopenharmony_ci '**': operator.pow, 2571cb0ef41Sopenharmony_ci '%': operator.mod 2581cb0ef41Sopenharmony_ci } 2591cb0ef41Sopenharmony_ci 2601cb0ef41Sopenharmony_ci #: default callback table for the unary operators. A copy of this is 2611cb0ef41Sopenharmony_ci #: available on each instance of a sandboxed environment as 2621cb0ef41Sopenharmony_ci #: :attr:`unop_table` 2631cb0ef41Sopenharmony_ci default_unop_table = { 2641cb0ef41Sopenharmony_ci '+': operator.pos, 2651cb0ef41Sopenharmony_ci '-': operator.neg 2661cb0ef41Sopenharmony_ci } 2671cb0ef41Sopenharmony_ci 2681cb0ef41Sopenharmony_ci #: a set of binary operators that should be intercepted. Each operator 2691cb0ef41Sopenharmony_ci #: that is added to this set (empty by default) is delegated to the 2701cb0ef41Sopenharmony_ci #: :meth:`call_binop` method that will perform the operator. The default 2711cb0ef41Sopenharmony_ci #: operator callback is specified by :attr:`binop_table`. 2721cb0ef41Sopenharmony_ci #: 2731cb0ef41Sopenharmony_ci #: The following binary operators are interceptable: 2741cb0ef41Sopenharmony_ci #: ``//``, ``%``, ``+``, ``*``, ``-``, ``/``, and ``**`` 2751cb0ef41Sopenharmony_ci #: 2761cb0ef41Sopenharmony_ci #: The default operation form the operator table corresponds to the 2771cb0ef41Sopenharmony_ci #: builtin function. Intercepted calls are always slower than the native 2781cb0ef41Sopenharmony_ci #: operator call, so make sure only to intercept the ones you are 2791cb0ef41Sopenharmony_ci #: interested in. 2801cb0ef41Sopenharmony_ci #: 2811cb0ef41Sopenharmony_ci #: .. versionadded:: 2.6 2821cb0ef41Sopenharmony_ci intercepted_binops = frozenset() 2831cb0ef41Sopenharmony_ci 2841cb0ef41Sopenharmony_ci #: a set of unary operators that should be intercepted. Each operator 2851cb0ef41Sopenharmony_ci #: that is added to this set (empty by default) is delegated to the 2861cb0ef41Sopenharmony_ci #: :meth:`call_unop` method that will perform the operator. The default 2871cb0ef41Sopenharmony_ci #: operator callback is specified by :attr:`unop_table`. 2881cb0ef41Sopenharmony_ci #: 2891cb0ef41Sopenharmony_ci #: The following unary operators are interceptable: ``+``, ``-`` 2901cb0ef41Sopenharmony_ci #: 2911cb0ef41Sopenharmony_ci #: The default operation form the operator table corresponds to the 2921cb0ef41Sopenharmony_ci #: builtin function. Intercepted calls are always slower than the native 2931cb0ef41Sopenharmony_ci #: operator call, so make sure only to intercept the ones you are 2941cb0ef41Sopenharmony_ci #: interested in. 2951cb0ef41Sopenharmony_ci #: 2961cb0ef41Sopenharmony_ci #: .. versionadded:: 2.6 2971cb0ef41Sopenharmony_ci intercepted_unops = frozenset() 2981cb0ef41Sopenharmony_ci 2991cb0ef41Sopenharmony_ci def intercept_unop(self, operator): 3001cb0ef41Sopenharmony_ci """Called during template compilation with the name of a unary 3011cb0ef41Sopenharmony_ci operator to check if it should be intercepted at runtime. If this 3021cb0ef41Sopenharmony_ci method returns `True`, :meth:`call_unop` is excuted for this unary 3031cb0ef41Sopenharmony_ci operator. The default implementation of :meth:`call_unop` will use 3041cb0ef41Sopenharmony_ci the :attr:`unop_table` dictionary to perform the operator with the 3051cb0ef41Sopenharmony_ci same logic as the builtin one. 3061cb0ef41Sopenharmony_ci 3071cb0ef41Sopenharmony_ci The following unary operators are interceptable: ``+`` and ``-`` 3081cb0ef41Sopenharmony_ci 3091cb0ef41Sopenharmony_ci Intercepted calls are always slower than the native operator call, 3101cb0ef41Sopenharmony_ci so make sure only to intercept the ones you are interested in. 3111cb0ef41Sopenharmony_ci 3121cb0ef41Sopenharmony_ci .. versionadded:: 2.6 3131cb0ef41Sopenharmony_ci """ 3141cb0ef41Sopenharmony_ci return False 3151cb0ef41Sopenharmony_ci 3161cb0ef41Sopenharmony_ci 3171cb0ef41Sopenharmony_ci def __init__(self, *args, **kwargs): 3181cb0ef41Sopenharmony_ci Environment.__init__(self, *args, **kwargs) 3191cb0ef41Sopenharmony_ci self.globals['range'] = safe_range 3201cb0ef41Sopenharmony_ci self.binop_table = self.default_binop_table.copy() 3211cb0ef41Sopenharmony_ci self.unop_table = self.default_unop_table.copy() 3221cb0ef41Sopenharmony_ci 3231cb0ef41Sopenharmony_ci def is_safe_attribute(self, obj, attr, value): 3241cb0ef41Sopenharmony_ci """The sandboxed environment will call this method to check if the 3251cb0ef41Sopenharmony_ci attribute of an object is safe to access. Per default all attributes 3261cb0ef41Sopenharmony_ci starting with an underscore are considered private as well as the 3271cb0ef41Sopenharmony_ci special attributes of internal python objects as returned by the 3281cb0ef41Sopenharmony_ci :func:`is_internal_attribute` function. 3291cb0ef41Sopenharmony_ci """ 3301cb0ef41Sopenharmony_ci return not (attr.startswith('_') or is_internal_attribute(obj, attr)) 3311cb0ef41Sopenharmony_ci 3321cb0ef41Sopenharmony_ci def is_safe_callable(self, obj): 3331cb0ef41Sopenharmony_ci """Check if an object is safely callable. Per default a function is 3341cb0ef41Sopenharmony_ci considered safe unless the `unsafe_callable` attribute exists and is 3351cb0ef41Sopenharmony_ci True. Override this method to alter the behavior, but this won't 3361cb0ef41Sopenharmony_ci affect the `unsafe` decorator from this module. 3371cb0ef41Sopenharmony_ci """ 3381cb0ef41Sopenharmony_ci return not (getattr(obj, 'unsafe_callable', False) or 3391cb0ef41Sopenharmony_ci getattr(obj, 'alters_data', False)) 3401cb0ef41Sopenharmony_ci 3411cb0ef41Sopenharmony_ci def call_binop(self, context, operator, left, right): 3421cb0ef41Sopenharmony_ci """For intercepted binary operator calls (:meth:`intercepted_binops`) 3431cb0ef41Sopenharmony_ci this function is executed instead of the builtin operator. This can 3441cb0ef41Sopenharmony_ci be used to fine tune the behavior of certain operators. 3451cb0ef41Sopenharmony_ci 3461cb0ef41Sopenharmony_ci .. versionadded:: 2.6 3471cb0ef41Sopenharmony_ci """ 3481cb0ef41Sopenharmony_ci return self.binop_table[operator](left, right) 3491cb0ef41Sopenharmony_ci 3501cb0ef41Sopenharmony_ci def call_unop(self, context, operator, arg): 3511cb0ef41Sopenharmony_ci """For intercepted unary operator calls (:meth:`intercepted_unops`) 3521cb0ef41Sopenharmony_ci this function is executed instead of the builtin operator. This can 3531cb0ef41Sopenharmony_ci be used to fine tune the behavior of certain operators. 3541cb0ef41Sopenharmony_ci 3551cb0ef41Sopenharmony_ci .. versionadded:: 2.6 3561cb0ef41Sopenharmony_ci """ 3571cb0ef41Sopenharmony_ci return self.unop_table[operator](arg) 3581cb0ef41Sopenharmony_ci 3591cb0ef41Sopenharmony_ci def getitem(self, obj, argument): 3601cb0ef41Sopenharmony_ci """Subscribe an object from sandboxed code.""" 3611cb0ef41Sopenharmony_ci try: 3621cb0ef41Sopenharmony_ci return obj[argument] 3631cb0ef41Sopenharmony_ci except (TypeError, LookupError): 3641cb0ef41Sopenharmony_ci if isinstance(argument, string_types): 3651cb0ef41Sopenharmony_ci try: 3661cb0ef41Sopenharmony_ci attr = str(argument) 3671cb0ef41Sopenharmony_ci except Exception: 3681cb0ef41Sopenharmony_ci pass 3691cb0ef41Sopenharmony_ci else: 3701cb0ef41Sopenharmony_ci try: 3711cb0ef41Sopenharmony_ci value = getattr(obj, attr) 3721cb0ef41Sopenharmony_ci except AttributeError: 3731cb0ef41Sopenharmony_ci pass 3741cb0ef41Sopenharmony_ci else: 3751cb0ef41Sopenharmony_ci if self.is_safe_attribute(obj, argument, value): 3761cb0ef41Sopenharmony_ci return value 3771cb0ef41Sopenharmony_ci return self.unsafe_undefined(obj, argument) 3781cb0ef41Sopenharmony_ci return self.undefined(obj=obj, name=argument) 3791cb0ef41Sopenharmony_ci 3801cb0ef41Sopenharmony_ci def getattr(self, obj, attribute): 3811cb0ef41Sopenharmony_ci """Subscribe an object from sandboxed code and prefer the 3821cb0ef41Sopenharmony_ci attribute. The attribute passed *must* be a bytestring. 3831cb0ef41Sopenharmony_ci """ 3841cb0ef41Sopenharmony_ci try: 3851cb0ef41Sopenharmony_ci value = getattr(obj, attribute) 3861cb0ef41Sopenharmony_ci except AttributeError: 3871cb0ef41Sopenharmony_ci try: 3881cb0ef41Sopenharmony_ci return obj[attribute] 3891cb0ef41Sopenharmony_ci except (TypeError, LookupError): 3901cb0ef41Sopenharmony_ci pass 3911cb0ef41Sopenharmony_ci else: 3921cb0ef41Sopenharmony_ci if self.is_safe_attribute(obj, attribute, value): 3931cb0ef41Sopenharmony_ci return value 3941cb0ef41Sopenharmony_ci return self.unsafe_undefined(obj, attribute) 3951cb0ef41Sopenharmony_ci return self.undefined(obj=obj, name=attribute) 3961cb0ef41Sopenharmony_ci 3971cb0ef41Sopenharmony_ci def unsafe_undefined(self, obj, attribute): 3981cb0ef41Sopenharmony_ci """Return an undefined object for unsafe attributes.""" 3991cb0ef41Sopenharmony_ci return self.undefined('access to attribute %r of %r ' 4001cb0ef41Sopenharmony_ci 'object is unsafe.' % ( 4011cb0ef41Sopenharmony_ci attribute, 4021cb0ef41Sopenharmony_ci obj.__class__.__name__ 4031cb0ef41Sopenharmony_ci ), name=attribute, obj=obj, exc=SecurityError) 4041cb0ef41Sopenharmony_ci 4051cb0ef41Sopenharmony_ci def format_string(self, s, args, kwargs): 4061cb0ef41Sopenharmony_ci """If a format call is detected, then this is routed through this 4071cb0ef41Sopenharmony_ci method so that our safety sandbox can be used for it. 4081cb0ef41Sopenharmony_ci """ 4091cb0ef41Sopenharmony_ci if isinstance(s, Markup): 4101cb0ef41Sopenharmony_ci formatter = SandboxedEscapeFormatter(self, s.escape) 4111cb0ef41Sopenharmony_ci else: 4121cb0ef41Sopenharmony_ci formatter = SandboxedFormatter(self) 4131cb0ef41Sopenharmony_ci kwargs = _MagicFormatMapping(args, kwargs) 4141cb0ef41Sopenharmony_ci rv = formatter.vformat(s, args, kwargs) 4151cb0ef41Sopenharmony_ci return type(s)(rv) 4161cb0ef41Sopenharmony_ci 4171cb0ef41Sopenharmony_ci def call(__self, __context, __obj, *args, **kwargs): 4181cb0ef41Sopenharmony_ci """Call an object from sandboxed code.""" 4191cb0ef41Sopenharmony_ci fmt = inspect_format_method(__obj) 4201cb0ef41Sopenharmony_ci if fmt is not None: 4211cb0ef41Sopenharmony_ci return __self.format_string(fmt, args, kwargs) 4221cb0ef41Sopenharmony_ci 4231cb0ef41Sopenharmony_ci # the double prefixes are to avoid double keyword argument 4241cb0ef41Sopenharmony_ci # errors when proxying the call. 4251cb0ef41Sopenharmony_ci if not __self.is_safe_callable(__obj): 4261cb0ef41Sopenharmony_ci raise SecurityError('%r is not safely callable' % (__obj,)) 4271cb0ef41Sopenharmony_ci return __context.call(__obj, *args, **kwargs) 4281cb0ef41Sopenharmony_ci 4291cb0ef41Sopenharmony_ci 4301cb0ef41Sopenharmony_ciclass ImmutableSandboxedEnvironment(SandboxedEnvironment): 4311cb0ef41Sopenharmony_ci """Works exactly like the regular `SandboxedEnvironment` but does not 4321cb0ef41Sopenharmony_ci permit modifications on the builtin mutable objects `list`, `set`, and 4331cb0ef41Sopenharmony_ci `dict` by using the :func:`modifies_known_mutable` function. 4341cb0ef41Sopenharmony_ci """ 4351cb0ef41Sopenharmony_ci 4361cb0ef41Sopenharmony_ci def is_safe_attribute(self, obj, attr, value): 4371cb0ef41Sopenharmony_ci if not SandboxedEnvironment.is_safe_attribute(self, obj, attr, value): 4381cb0ef41Sopenharmony_ci return False 4391cb0ef41Sopenharmony_ci return not modifies_known_mutable(obj, attr) 4401cb0ef41Sopenharmony_ci 4411cb0ef41Sopenharmony_ci 4421cb0ef41Sopenharmony_ci# This really is not a public API apparenlty. 4431cb0ef41Sopenharmony_citry: 4441cb0ef41Sopenharmony_ci from _string import formatter_field_name_split 4451cb0ef41Sopenharmony_ciexcept ImportError: 4461cb0ef41Sopenharmony_ci def formatter_field_name_split(field_name): 4471cb0ef41Sopenharmony_ci return field_name._formatter_field_name_split() 4481cb0ef41Sopenharmony_ci 4491cb0ef41Sopenharmony_ci 4501cb0ef41Sopenharmony_ciclass SandboxedFormatterMixin(object): 4511cb0ef41Sopenharmony_ci 4521cb0ef41Sopenharmony_ci def __init__(self, env): 4531cb0ef41Sopenharmony_ci self._env = env 4541cb0ef41Sopenharmony_ci 4551cb0ef41Sopenharmony_ci def get_field(self, field_name, args, kwargs): 4561cb0ef41Sopenharmony_ci first, rest = formatter_field_name_split(field_name) 4571cb0ef41Sopenharmony_ci obj = self.get_value(first, args, kwargs) 4581cb0ef41Sopenharmony_ci for is_attr, i in rest: 4591cb0ef41Sopenharmony_ci if is_attr: 4601cb0ef41Sopenharmony_ci obj = self._env.getattr(obj, i) 4611cb0ef41Sopenharmony_ci else: 4621cb0ef41Sopenharmony_ci obj = self._env.getitem(obj, i) 4631cb0ef41Sopenharmony_ci return obj, first 4641cb0ef41Sopenharmony_ci 4651cb0ef41Sopenharmony_ciclass SandboxedFormatter(SandboxedFormatterMixin, Formatter): 4661cb0ef41Sopenharmony_ci 4671cb0ef41Sopenharmony_ci def __init__(self, env): 4681cb0ef41Sopenharmony_ci SandboxedFormatterMixin.__init__(self, env) 4691cb0ef41Sopenharmony_ci Formatter.__init__(self) 4701cb0ef41Sopenharmony_ci 4711cb0ef41Sopenharmony_ciclass SandboxedEscapeFormatter(SandboxedFormatterMixin, EscapeFormatter): 4721cb0ef41Sopenharmony_ci 4731cb0ef41Sopenharmony_ci def __init__(self, env, escape): 4741cb0ef41Sopenharmony_ci SandboxedFormatterMixin.__init__(self, env) 4751cb0ef41Sopenharmony_ci EscapeFormatter.__init__(self, escape) 476