1*635a8641SAndroid Build Coastguard Worker# -*- coding: utf-8 -*- 2*635a8641SAndroid Build Coastguard Worker""" 3*635a8641SAndroid Build Coastguard Worker jinja2.sandbox 4*635a8641SAndroid Build Coastguard Worker ~~~~~~~~~~~~~~ 5*635a8641SAndroid Build Coastguard Worker 6*635a8641SAndroid Build Coastguard Worker Adds a sandbox layer to Jinja as it was the default behavior in the old 7*635a8641SAndroid Build Coastguard Worker Jinja 1 releases. This sandbox is slightly different from Jinja 1 as the 8*635a8641SAndroid Build Coastguard Worker default behavior is easier to use. 9*635a8641SAndroid Build Coastguard Worker 10*635a8641SAndroid Build Coastguard Worker The behavior can be changed by subclassing the environment. 11*635a8641SAndroid Build Coastguard Worker 12*635a8641SAndroid Build Coastguard Worker :copyright: (c) 2017 by the Jinja Team. 13*635a8641SAndroid Build Coastguard Worker :license: BSD. 14*635a8641SAndroid Build Coastguard Worker""" 15*635a8641SAndroid Build Coastguard Workerimport types 16*635a8641SAndroid Build Coastguard Workerimport operator 17*635a8641SAndroid Build Coastguard Workerfrom collections import Mapping 18*635a8641SAndroid Build Coastguard Workerfrom jinja2.environment import Environment 19*635a8641SAndroid Build Coastguard Workerfrom jinja2.exceptions import SecurityError 20*635a8641SAndroid Build Coastguard Workerfrom jinja2._compat import string_types, PY2 21*635a8641SAndroid Build Coastguard Workerfrom jinja2.utils import Markup 22*635a8641SAndroid Build Coastguard Worker 23*635a8641SAndroid Build Coastguard Workerfrom markupsafe import EscapeFormatter 24*635a8641SAndroid Build Coastguard Workerfrom string import Formatter 25*635a8641SAndroid Build Coastguard Worker 26*635a8641SAndroid Build Coastguard Worker 27*635a8641SAndroid Build Coastguard Worker#: maximum number of items a range may produce 28*635a8641SAndroid Build Coastguard WorkerMAX_RANGE = 100000 29*635a8641SAndroid Build Coastguard Worker 30*635a8641SAndroid Build Coastguard Worker#: attributes of function objects that are considered unsafe. 31*635a8641SAndroid Build Coastguard Workerif PY2: 32*635a8641SAndroid Build Coastguard Worker UNSAFE_FUNCTION_ATTRIBUTES = set(['func_closure', 'func_code', 'func_dict', 33*635a8641SAndroid Build Coastguard Worker 'func_defaults', 'func_globals']) 34*635a8641SAndroid Build Coastguard Workerelse: 35*635a8641SAndroid Build Coastguard Worker # On versions > python 2 the special attributes on functions are gone, 36*635a8641SAndroid Build Coastguard Worker # but they remain on methods and generators for whatever reason. 37*635a8641SAndroid Build Coastguard Worker UNSAFE_FUNCTION_ATTRIBUTES = set() 38*635a8641SAndroid Build Coastguard Worker 39*635a8641SAndroid Build Coastguard Worker 40*635a8641SAndroid Build Coastguard Worker#: unsafe method attributes. function attributes are unsafe for methods too 41*635a8641SAndroid Build Coastguard WorkerUNSAFE_METHOD_ATTRIBUTES = set(['im_class', 'im_func', 'im_self']) 42*635a8641SAndroid Build Coastguard Worker 43*635a8641SAndroid Build Coastguard Worker#: unsafe generator attirbutes. 44*635a8641SAndroid Build Coastguard WorkerUNSAFE_GENERATOR_ATTRIBUTES = set(['gi_frame', 'gi_code']) 45*635a8641SAndroid Build Coastguard Worker 46*635a8641SAndroid Build Coastguard Worker#: unsafe attributes on coroutines 47*635a8641SAndroid Build Coastguard WorkerUNSAFE_COROUTINE_ATTRIBUTES = set(['cr_frame', 'cr_code']) 48*635a8641SAndroid Build Coastguard Worker 49*635a8641SAndroid Build Coastguard Worker#: unsafe attributes on async generators 50*635a8641SAndroid Build Coastguard WorkerUNSAFE_ASYNC_GENERATOR_ATTRIBUTES = set(['ag_code', 'ag_frame']) 51*635a8641SAndroid Build Coastguard Worker 52*635a8641SAndroid Build Coastguard Workerimport warnings 53*635a8641SAndroid Build Coastguard Worker 54*635a8641SAndroid Build Coastguard Worker# make sure we don't warn in python 2.6 about stuff we don't care about 55*635a8641SAndroid Build Coastguard Workerwarnings.filterwarnings('ignore', 'the sets module', DeprecationWarning, 56*635a8641SAndroid Build Coastguard Worker module='jinja2.sandbox') 57*635a8641SAndroid Build Coastguard Worker 58*635a8641SAndroid Build Coastguard Workerfrom collections import deque 59*635a8641SAndroid Build Coastguard Worker 60*635a8641SAndroid Build Coastguard Worker_mutable_set_types = (set,) 61*635a8641SAndroid Build Coastguard Worker_mutable_mapping_types = (dict,) 62*635a8641SAndroid Build Coastguard Worker_mutable_sequence_types = (list,) 63*635a8641SAndroid Build Coastguard Worker 64*635a8641SAndroid Build Coastguard Worker 65*635a8641SAndroid Build Coastguard Worker# on python 2.x we can register the user collection types 66*635a8641SAndroid Build Coastguard Workertry: 67*635a8641SAndroid Build Coastguard Worker from UserDict import UserDict, DictMixin 68*635a8641SAndroid Build Coastguard Worker from UserList import UserList 69*635a8641SAndroid Build Coastguard Worker _mutable_mapping_types += (UserDict, DictMixin) 70*635a8641SAndroid Build Coastguard Worker _mutable_set_types += (UserList,) 71*635a8641SAndroid Build Coastguard Workerexcept ImportError: 72*635a8641SAndroid Build Coastguard Worker pass 73*635a8641SAndroid Build Coastguard Worker 74*635a8641SAndroid Build Coastguard Worker# if sets is still available, register the mutable set from there as well 75*635a8641SAndroid Build Coastguard Workertry: 76*635a8641SAndroid Build Coastguard Worker from sets import Set 77*635a8641SAndroid Build Coastguard Worker _mutable_set_types += (Set,) 78*635a8641SAndroid Build Coastguard Workerexcept ImportError: 79*635a8641SAndroid Build Coastguard Worker pass 80*635a8641SAndroid Build Coastguard Worker 81*635a8641SAndroid Build Coastguard Worker#: register Python 2.6 abstract base classes 82*635a8641SAndroid Build Coastguard Workerfrom collections import MutableSet, MutableMapping, MutableSequence 83*635a8641SAndroid Build Coastguard Worker_mutable_set_types += (MutableSet,) 84*635a8641SAndroid Build Coastguard Worker_mutable_mapping_types += (MutableMapping,) 85*635a8641SAndroid Build Coastguard Worker_mutable_sequence_types += (MutableSequence,) 86*635a8641SAndroid Build Coastguard Worker 87*635a8641SAndroid Build Coastguard Worker 88*635a8641SAndroid Build Coastguard Worker_mutable_spec = ( 89*635a8641SAndroid Build Coastguard Worker (_mutable_set_types, frozenset([ 90*635a8641SAndroid Build Coastguard Worker 'add', 'clear', 'difference_update', 'discard', 'pop', 'remove', 91*635a8641SAndroid Build Coastguard Worker 'symmetric_difference_update', 'update' 92*635a8641SAndroid Build Coastguard Worker ])), 93*635a8641SAndroid Build Coastguard Worker (_mutable_mapping_types, frozenset([ 94*635a8641SAndroid Build Coastguard Worker 'clear', 'pop', 'popitem', 'setdefault', 'update' 95*635a8641SAndroid Build Coastguard Worker ])), 96*635a8641SAndroid Build Coastguard Worker (_mutable_sequence_types, frozenset([ 97*635a8641SAndroid Build Coastguard Worker 'append', 'reverse', 'insert', 'sort', 'extend', 'remove' 98*635a8641SAndroid Build Coastguard Worker ])), 99*635a8641SAndroid Build Coastguard Worker (deque, frozenset([ 100*635a8641SAndroid Build Coastguard Worker 'append', 'appendleft', 'clear', 'extend', 'extendleft', 'pop', 101*635a8641SAndroid Build Coastguard Worker 'popleft', 'remove', 'rotate' 102*635a8641SAndroid Build Coastguard Worker ])) 103*635a8641SAndroid Build Coastguard Worker) 104*635a8641SAndroid Build Coastguard Worker 105*635a8641SAndroid Build Coastguard Worker 106*635a8641SAndroid Build Coastguard Workerclass _MagicFormatMapping(Mapping): 107*635a8641SAndroid Build Coastguard Worker """This class implements a dummy wrapper to fix a bug in the Python 108*635a8641SAndroid Build Coastguard Worker standard library for string formatting. 109*635a8641SAndroid Build Coastguard Worker 110*635a8641SAndroid Build Coastguard Worker See https://bugs.python.org/issue13598 for information about why 111*635a8641SAndroid Build Coastguard Worker this is necessary. 112*635a8641SAndroid Build Coastguard Worker """ 113*635a8641SAndroid Build Coastguard Worker 114*635a8641SAndroid Build Coastguard Worker def __init__(self, args, kwargs): 115*635a8641SAndroid Build Coastguard Worker self._args = args 116*635a8641SAndroid Build Coastguard Worker self._kwargs = kwargs 117*635a8641SAndroid Build Coastguard Worker self._last_index = 0 118*635a8641SAndroid Build Coastguard Worker 119*635a8641SAndroid Build Coastguard Worker def __getitem__(self, key): 120*635a8641SAndroid Build Coastguard Worker if key == '': 121*635a8641SAndroid Build Coastguard Worker idx = self._last_index 122*635a8641SAndroid Build Coastguard Worker self._last_index += 1 123*635a8641SAndroid Build Coastguard Worker try: 124*635a8641SAndroid Build Coastguard Worker return self._args[idx] 125*635a8641SAndroid Build Coastguard Worker except LookupError: 126*635a8641SAndroid Build Coastguard Worker pass 127*635a8641SAndroid Build Coastguard Worker key = str(idx) 128*635a8641SAndroid Build Coastguard Worker return self._kwargs[key] 129*635a8641SAndroid Build Coastguard Worker 130*635a8641SAndroid Build Coastguard Worker def __iter__(self): 131*635a8641SAndroid Build Coastguard Worker return iter(self._kwargs) 132*635a8641SAndroid Build Coastguard Worker 133*635a8641SAndroid Build Coastguard Worker def __len__(self): 134*635a8641SAndroid Build Coastguard Worker return len(self._kwargs) 135*635a8641SAndroid Build Coastguard Worker 136*635a8641SAndroid Build Coastguard Worker 137*635a8641SAndroid Build Coastguard Workerdef inspect_format_method(callable): 138*635a8641SAndroid Build Coastguard Worker if not isinstance(callable, (types.MethodType, 139*635a8641SAndroid Build Coastguard Worker types.BuiltinMethodType)) or \ 140*635a8641SAndroid Build Coastguard Worker callable.__name__ != 'format': 141*635a8641SAndroid Build Coastguard Worker return None 142*635a8641SAndroid Build Coastguard Worker obj = callable.__self__ 143*635a8641SAndroid Build Coastguard Worker if isinstance(obj, string_types): 144*635a8641SAndroid Build Coastguard Worker return obj 145*635a8641SAndroid Build Coastguard Worker 146*635a8641SAndroid Build Coastguard Worker 147*635a8641SAndroid Build Coastguard Workerdef safe_range(*args): 148*635a8641SAndroid Build Coastguard Worker """A range that can't generate ranges with a length of more than 149*635a8641SAndroid Build Coastguard Worker MAX_RANGE items. 150*635a8641SAndroid Build Coastguard Worker """ 151*635a8641SAndroid Build Coastguard Worker rng = range(*args) 152*635a8641SAndroid Build Coastguard Worker if len(rng) > MAX_RANGE: 153*635a8641SAndroid Build Coastguard Worker raise OverflowError('range too big, maximum size for range is %d' % 154*635a8641SAndroid Build Coastguard Worker MAX_RANGE) 155*635a8641SAndroid Build Coastguard Worker return rng 156*635a8641SAndroid Build Coastguard Worker 157*635a8641SAndroid Build Coastguard Worker 158*635a8641SAndroid Build Coastguard Workerdef unsafe(f): 159*635a8641SAndroid Build Coastguard Worker """Marks a function or method as unsafe. 160*635a8641SAndroid Build Coastguard Worker 161*635a8641SAndroid Build Coastguard Worker :: 162*635a8641SAndroid Build Coastguard Worker 163*635a8641SAndroid Build Coastguard Worker @unsafe 164*635a8641SAndroid Build Coastguard Worker def delete(self): 165*635a8641SAndroid Build Coastguard Worker pass 166*635a8641SAndroid Build Coastguard Worker """ 167*635a8641SAndroid Build Coastguard Worker f.unsafe_callable = True 168*635a8641SAndroid Build Coastguard Worker return f 169*635a8641SAndroid Build Coastguard Worker 170*635a8641SAndroid Build Coastguard Worker 171*635a8641SAndroid Build Coastguard Workerdef is_internal_attribute(obj, attr): 172*635a8641SAndroid Build Coastguard Worker """Test if the attribute given is an internal python attribute. For 173*635a8641SAndroid Build Coastguard Worker example this function returns `True` for the `func_code` attribute of 174*635a8641SAndroid Build Coastguard Worker python objects. This is useful if the environment method 175*635a8641SAndroid Build Coastguard Worker :meth:`~SandboxedEnvironment.is_safe_attribute` is overridden. 176*635a8641SAndroid Build Coastguard Worker 177*635a8641SAndroid Build Coastguard Worker >>> from jinja2.sandbox import is_internal_attribute 178*635a8641SAndroid Build Coastguard Worker >>> is_internal_attribute(str, "mro") 179*635a8641SAndroid Build Coastguard Worker True 180*635a8641SAndroid Build Coastguard Worker >>> is_internal_attribute(str, "upper") 181*635a8641SAndroid Build Coastguard Worker False 182*635a8641SAndroid Build Coastguard Worker """ 183*635a8641SAndroid Build Coastguard Worker if isinstance(obj, types.FunctionType): 184*635a8641SAndroid Build Coastguard Worker if attr in UNSAFE_FUNCTION_ATTRIBUTES: 185*635a8641SAndroid Build Coastguard Worker return True 186*635a8641SAndroid Build Coastguard Worker elif isinstance(obj, types.MethodType): 187*635a8641SAndroid Build Coastguard Worker if attr in UNSAFE_FUNCTION_ATTRIBUTES or \ 188*635a8641SAndroid Build Coastguard Worker attr in UNSAFE_METHOD_ATTRIBUTES: 189*635a8641SAndroid Build Coastguard Worker return True 190*635a8641SAndroid Build Coastguard Worker elif isinstance(obj, type): 191*635a8641SAndroid Build Coastguard Worker if attr == 'mro': 192*635a8641SAndroid Build Coastguard Worker return True 193*635a8641SAndroid Build Coastguard Worker elif isinstance(obj, (types.CodeType, types.TracebackType, types.FrameType)): 194*635a8641SAndroid Build Coastguard Worker return True 195*635a8641SAndroid Build Coastguard Worker elif isinstance(obj, types.GeneratorType): 196*635a8641SAndroid Build Coastguard Worker if attr in UNSAFE_GENERATOR_ATTRIBUTES: 197*635a8641SAndroid Build Coastguard Worker return True 198*635a8641SAndroid Build Coastguard Worker elif hasattr(types, 'CoroutineType') and isinstance(obj, types.CoroutineType): 199*635a8641SAndroid Build Coastguard Worker if attr in UNSAFE_COROUTINE_ATTRIBUTES: 200*635a8641SAndroid Build Coastguard Worker return True 201*635a8641SAndroid Build Coastguard Worker elif hasattr(types, 'AsyncGeneratorType') and isinstance(obj, types.AsyncGeneratorType): 202*635a8641SAndroid Build Coastguard Worker if attr in UNSAFE_ASYNC_GENERATOR_ATTRIBUTES: 203*635a8641SAndroid Build Coastguard Worker return True 204*635a8641SAndroid Build Coastguard Worker return attr.startswith('__') 205*635a8641SAndroid Build Coastguard Worker 206*635a8641SAndroid Build Coastguard Worker 207*635a8641SAndroid Build Coastguard Workerdef modifies_known_mutable(obj, attr): 208*635a8641SAndroid Build Coastguard Worker """This function checks if an attribute on a builtin mutable object 209*635a8641SAndroid Build Coastguard Worker (list, dict, set or deque) would modify it if called. It also supports 210*635a8641SAndroid Build Coastguard Worker the "user"-versions of the objects (`sets.Set`, `UserDict.*` etc.) and 211*635a8641SAndroid Build Coastguard Worker with Python 2.6 onwards the abstract base classes `MutableSet`, 212*635a8641SAndroid Build Coastguard Worker `MutableMapping`, and `MutableSequence`. 213*635a8641SAndroid Build Coastguard Worker 214*635a8641SAndroid Build Coastguard Worker >>> modifies_known_mutable({}, "clear") 215*635a8641SAndroid Build Coastguard Worker True 216*635a8641SAndroid Build Coastguard Worker >>> modifies_known_mutable({}, "keys") 217*635a8641SAndroid Build Coastguard Worker False 218*635a8641SAndroid Build Coastguard Worker >>> modifies_known_mutable([], "append") 219*635a8641SAndroid Build Coastguard Worker True 220*635a8641SAndroid Build Coastguard Worker >>> modifies_known_mutable([], "index") 221*635a8641SAndroid Build Coastguard Worker False 222*635a8641SAndroid Build Coastguard Worker 223*635a8641SAndroid Build Coastguard Worker If called with an unsupported object (such as unicode) `False` is 224*635a8641SAndroid Build Coastguard Worker returned. 225*635a8641SAndroid Build Coastguard Worker 226*635a8641SAndroid Build Coastguard Worker >>> modifies_known_mutable("foo", "upper") 227*635a8641SAndroid Build Coastguard Worker False 228*635a8641SAndroid Build Coastguard Worker """ 229*635a8641SAndroid Build Coastguard Worker for typespec, unsafe in _mutable_spec: 230*635a8641SAndroid Build Coastguard Worker if isinstance(obj, typespec): 231*635a8641SAndroid Build Coastguard Worker return attr in unsafe 232*635a8641SAndroid Build Coastguard Worker return False 233*635a8641SAndroid Build Coastguard Worker 234*635a8641SAndroid Build Coastguard Worker 235*635a8641SAndroid Build Coastguard Workerclass SandboxedEnvironment(Environment): 236*635a8641SAndroid Build Coastguard Worker """The sandboxed environment. It works like the regular environment but 237*635a8641SAndroid Build Coastguard Worker tells the compiler to generate sandboxed code. Additionally subclasses of 238*635a8641SAndroid Build Coastguard Worker this environment may override the methods that tell the runtime what 239*635a8641SAndroid Build Coastguard Worker attributes or functions are safe to access. 240*635a8641SAndroid Build Coastguard Worker 241*635a8641SAndroid Build Coastguard Worker If the template tries to access insecure code a :exc:`SecurityError` is 242*635a8641SAndroid Build Coastguard Worker raised. However also other exceptions may occur during the rendering so 243*635a8641SAndroid Build Coastguard Worker the caller has to ensure that all exceptions are caught. 244*635a8641SAndroid Build Coastguard Worker """ 245*635a8641SAndroid Build Coastguard Worker sandboxed = True 246*635a8641SAndroid Build Coastguard Worker 247*635a8641SAndroid Build Coastguard Worker #: default callback table for the binary operators. A copy of this is 248*635a8641SAndroid Build Coastguard Worker #: available on each instance of a sandboxed environment as 249*635a8641SAndroid Build Coastguard Worker #: :attr:`binop_table` 250*635a8641SAndroid Build Coastguard Worker default_binop_table = { 251*635a8641SAndroid Build Coastguard Worker '+': operator.add, 252*635a8641SAndroid Build Coastguard Worker '-': operator.sub, 253*635a8641SAndroid Build Coastguard Worker '*': operator.mul, 254*635a8641SAndroid Build Coastguard Worker '/': operator.truediv, 255*635a8641SAndroid Build Coastguard Worker '//': operator.floordiv, 256*635a8641SAndroid Build Coastguard Worker '**': operator.pow, 257*635a8641SAndroid Build Coastguard Worker '%': operator.mod 258*635a8641SAndroid Build Coastguard Worker } 259*635a8641SAndroid Build Coastguard Worker 260*635a8641SAndroid Build Coastguard Worker #: default callback table for the unary operators. A copy of this is 261*635a8641SAndroid Build Coastguard Worker #: available on each instance of a sandboxed environment as 262*635a8641SAndroid Build Coastguard Worker #: :attr:`unop_table` 263*635a8641SAndroid Build Coastguard Worker default_unop_table = { 264*635a8641SAndroid Build Coastguard Worker '+': operator.pos, 265*635a8641SAndroid Build Coastguard Worker '-': operator.neg 266*635a8641SAndroid Build Coastguard Worker } 267*635a8641SAndroid Build Coastguard Worker 268*635a8641SAndroid Build Coastguard Worker #: a set of binary operators that should be intercepted. Each operator 269*635a8641SAndroid Build Coastguard Worker #: that is added to this set (empty by default) is delegated to the 270*635a8641SAndroid Build Coastguard Worker #: :meth:`call_binop` method that will perform the operator. The default 271*635a8641SAndroid Build Coastguard Worker #: operator callback is specified by :attr:`binop_table`. 272*635a8641SAndroid Build Coastguard Worker #: 273*635a8641SAndroid Build Coastguard Worker #: The following binary operators are interceptable: 274*635a8641SAndroid Build Coastguard Worker #: ``//``, ``%``, ``+``, ``*``, ``-``, ``/``, and ``**`` 275*635a8641SAndroid Build Coastguard Worker #: 276*635a8641SAndroid Build Coastguard Worker #: The default operation form the operator table corresponds to the 277*635a8641SAndroid Build Coastguard Worker #: builtin function. Intercepted calls are always slower than the native 278*635a8641SAndroid Build Coastguard Worker #: operator call, so make sure only to intercept the ones you are 279*635a8641SAndroid Build Coastguard Worker #: interested in. 280*635a8641SAndroid Build Coastguard Worker #: 281*635a8641SAndroid Build Coastguard Worker #: .. versionadded:: 2.6 282*635a8641SAndroid Build Coastguard Worker intercepted_binops = frozenset() 283*635a8641SAndroid Build Coastguard Worker 284*635a8641SAndroid Build Coastguard Worker #: a set of unary operators that should be intercepted. Each operator 285*635a8641SAndroid Build Coastguard Worker #: that is added to this set (empty by default) is delegated to the 286*635a8641SAndroid Build Coastguard Worker #: :meth:`call_unop` method that will perform the operator. The default 287*635a8641SAndroid Build Coastguard Worker #: operator callback is specified by :attr:`unop_table`. 288*635a8641SAndroid Build Coastguard Worker #: 289*635a8641SAndroid Build Coastguard Worker #: The following unary operators are interceptable: ``+``, ``-`` 290*635a8641SAndroid Build Coastguard Worker #: 291*635a8641SAndroid Build Coastguard Worker #: The default operation form the operator table corresponds to the 292*635a8641SAndroid Build Coastguard Worker #: builtin function. Intercepted calls are always slower than the native 293*635a8641SAndroid Build Coastguard Worker #: operator call, so make sure only to intercept the ones you are 294*635a8641SAndroid Build Coastguard Worker #: interested in. 295*635a8641SAndroid Build Coastguard Worker #: 296*635a8641SAndroid Build Coastguard Worker #: .. versionadded:: 2.6 297*635a8641SAndroid Build Coastguard Worker intercepted_unops = frozenset() 298*635a8641SAndroid Build Coastguard Worker 299*635a8641SAndroid Build Coastguard Worker def intercept_unop(self, operator): 300*635a8641SAndroid Build Coastguard Worker """Called during template compilation with the name of a unary 301*635a8641SAndroid Build Coastguard Worker operator to check if it should be intercepted at runtime. If this 302*635a8641SAndroid Build Coastguard Worker method returns `True`, :meth:`call_unop` is excuted for this unary 303*635a8641SAndroid Build Coastguard Worker operator. The default implementation of :meth:`call_unop` will use 304*635a8641SAndroid Build Coastguard Worker the :attr:`unop_table` dictionary to perform the operator with the 305*635a8641SAndroid Build Coastguard Worker same logic as the builtin one. 306*635a8641SAndroid Build Coastguard Worker 307*635a8641SAndroid Build Coastguard Worker The following unary operators are interceptable: ``+`` and ``-`` 308*635a8641SAndroid Build Coastguard Worker 309*635a8641SAndroid Build Coastguard Worker Intercepted calls are always slower than the native operator call, 310*635a8641SAndroid Build Coastguard Worker so make sure only to intercept the ones you are interested in. 311*635a8641SAndroid Build Coastguard Worker 312*635a8641SAndroid Build Coastguard Worker .. versionadded:: 2.6 313*635a8641SAndroid Build Coastguard Worker """ 314*635a8641SAndroid Build Coastguard Worker return False 315*635a8641SAndroid Build Coastguard Worker 316*635a8641SAndroid Build Coastguard Worker 317*635a8641SAndroid Build Coastguard Worker def __init__(self, *args, **kwargs): 318*635a8641SAndroid Build Coastguard Worker Environment.__init__(self, *args, **kwargs) 319*635a8641SAndroid Build Coastguard Worker self.globals['range'] = safe_range 320*635a8641SAndroid Build Coastguard Worker self.binop_table = self.default_binop_table.copy() 321*635a8641SAndroid Build Coastguard Worker self.unop_table = self.default_unop_table.copy() 322*635a8641SAndroid Build Coastguard Worker 323*635a8641SAndroid Build Coastguard Worker def is_safe_attribute(self, obj, attr, value): 324*635a8641SAndroid Build Coastguard Worker """The sandboxed environment will call this method to check if the 325*635a8641SAndroid Build Coastguard Worker attribute of an object is safe to access. Per default all attributes 326*635a8641SAndroid Build Coastguard Worker starting with an underscore are considered private as well as the 327*635a8641SAndroid Build Coastguard Worker special attributes of internal python objects as returned by the 328*635a8641SAndroid Build Coastguard Worker :func:`is_internal_attribute` function. 329*635a8641SAndroid Build Coastguard Worker """ 330*635a8641SAndroid Build Coastguard Worker return not (attr.startswith('_') or is_internal_attribute(obj, attr)) 331*635a8641SAndroid Build Coastguard Worker 332*635a8641SAndroid Build Coastguard Worker def is_safe_callable(self, obj): 333*635a8641SAndroid Build Coastguard Worker """Check if an object is safely callable. Per default a function is 334*635a8641SAndroid Build Coastguard Worker considered safe unless the `unsafe_callable` attribute exists and is 335*635a8641SAndroid Build Coastguard Worker True. Override this method to alter the behavior, but this won't 336*635a8641SAndroid Build Coastguard Worker affect the `unsafe` decorator from this module. 337*635a8641SAndroid Build Coastguard Worker """ 338*635a8641SAndroid Build Coastguard Worker return not (getattr(obj, 'unsafe_callable', False) or 339*635a8641SAndroid Build Coastguard Worker getattr(obj, 'alters_data', False)) 340*635a8641SAndroid Build Coastguard Worker 341*635a8641SAndroid Build Coastguard Worker def call_binop(self, context, operator, left, right): 342*635a8641SAndroid Build Coastguard Worker """For intercepted binary operator calls (:meth:`intercepted_binops`) 343*635a8641SAndroid Build Coastguard Worker this function is executed instead of the builtin operator. This can 344*635a8641SAndroid Build Coastguard Worker be used to fine tune the behavior of certain operators. 345*635a8641SAndroid Build Coastguard Worker 346*635a8641SAndroid Build Coastguard Worker .. versionadded:: 2.6 347*635a8641SAndroid Build Coastguard Worker """ 348*635a8641SAndroid Build Coastguard Worker return self.binop_table[operator](left, right) 349*635a8641SAndroid Build Coastguard Worker 350*635a8641SAndroid Build Coastguard Worker def call_unop(self, context, operator, arg): 351*635a8641SAndroid Build Coastguard Worker """For intercepted unary operator calls (:meth:`intercepted_unops`) 352*635a8641SAndroid Build Coastguard Worker this function is executed instead of the builtin operator. This can 353*635a8641SAndroid Build Coastguard Worker be used to fine tune the behavior of certain operators. 354*635a8641SAndroid Build Coastguard Worker 355*635a8641SAndroid Build Coastguard Worker .. versionadded:: 2.6 356*635a8641SAndroid Build Coastguard Worker """ 357*635a8641SAndroid Build Coastguard Worker return self.unop_table[operator](arg) 358*635a8641SAndroid Build Coastguard Worker 359*635a8641SAndroid Build Coastguard Worker def getitem(self, obj, argument): 360*635a8641SAndroid Build Coastguard Worker """Subscribe an object from sandboxed code.""" 361*635a8641SAndroid Build Coastguard Worker try: 362*635a8641SAndroid Build Coastguard Worker return obj[argument] 363*635a8641SAndroid Build Coastguard Worker except (TypeError, LookupError): 364*635a8641SAndroid Build Coastguard Worker if isinstance(argument, string_types): 365*635a8641SAndroid Build Coastguard Worker try: 366*635a8641SAndroid Build Coastguard Worker attr = str(argument) 367*635a8641SAndroid Build Coastguard Worker except Exception: 368*635a8641SAndroid Build Coastguard Worker pass 369*635a8641SAndroid Build Coastguard Worker else: 370*635a8641SAndroid Build Coastguard Worker try: 371*635a8641SAndroid Build Coastguard Worker value = getattr(obj, attr) 372*635a8641SAndroid Build Coastguard Worker except AttributeError: 373*635a8641SAndroid Build Coastguard Worker pass 374*635a8641SAndroid Build Coastguard Worker else: 375*635a8641SAndroid Build Coastguard Worker if self.is_safe_attribute(obj, argument, value): 376*635a8641SAndroid Build Coastguard Worker return value 377*635a8641SAndroid Build Coastguard Worker return self.unsafe_undefined(obj, argument) 378*635a8641SAndroid Build Coastguard Worker return self.undefined(obj=obj, name=argument) 379*635a8641SAndroid Build Coastguard Worker 380*635a8641SAndroid Build Coastguard Worker def getattr(self, obj, attribute): 381*635a8641SAndroid Build Coastguard Worker """Subscribe an object from sandboxed code and prefer the 382*635a8641SAndroid Build Coastguard Worker attribute. The attribute passed *must* be a bytestring. 383*635a8641SAndroid Build Coastguard Worker """ 384*635a8641SAndroid Build Coastguard Worker try: 385*635a8641SAndroid Build Coastguard Worker value = getattr(obj, attribute) 386*635a8641SAndroid Build Coastguard Worker except AttributeError: 387*635a8641SAndroid Build Coastguard Worker try: 388*635a8641SAndroid Build Coastguard Worker return obj[attribute] 389*635a8641SAndroid Build Coastguard Worker except (TypeError, LookupError): 390*635a8641SAndroid Build Coastguard Worker pass 391*635a8641SAndroid Build Coastguard Worker else: 392*635a8641SAndroid Build Coastguard Worker if self.is_safe_attribute(obj, attribute, value): 393*635a8641SAndroid Build Coastguard Worker return value 394*635a8641SAndroid Build Coastguard Worker return self.unsafe_undefined(obj, attribute) 395*635a8641SAndroid Build Coastguard Worker return self.undefined(obj=obj, name=attribute) 396*635a8641SAndroid Build Coastguard Worker 397*635a8641SAndroid Build Coastguard Worker def unsafe_undefined(self, obj, attribute): 398*635a8641SAndroid Build Coastguard Worker """Return an undefined object for unsafe attributes.""" 399*635a8641SAndroid Build Coastguard Worker return self.undefined('access to attribute %r of %r ' 400*635a8641SAndroid Build Coastguard Worker 'object is unsafe.' % ( 401*635a8641SAndroid Build Coastguard Worker attribute, 402*635a8641SAndroid Build Coastguard Worker obj.__class__.__name__ 403*635a8641SAndroid Build Coastguard Worker ), name=attribute, obj=obj, exc=SecurityError) 404*635a8641SAndroid Build Coastguard Worker 405*635a8641SAndroid Build Coastguard Worker def format_string(self, s, args, kwargs): 406*635a8641SAndroid Build Coastguard Worker """If a format call is detected, then this is routed through this 407*635a8641SAndroid Build Coastguard Worker method so that our safety sandbox can be used for it. 408*635a8641SAndroid Build Coastguard Worker """ 409*635a8641SAndroid Build Coastguard Worker if isinstance(s, Markup): 410*635a8641SAndroid Build Coastguard Worker formatter = SandboxedEscapeFormatter(self, s.escape) 411*635a8641SAndroid Build Coastguard Worker else: 412*635a8641SAndroid Build Coastguard Worker formatter = SandboxedFormatter(self) 413*635a8641SAndroid Build Coastguard Worker kwargs = _MagicFormatMapping(args, kwargs) 414*635a8641SAndroid Build Coastguard Worker rv = formatter.vformat(s, args, kwargs) 415*635a8641SAndroid Build Coastguard Worker return type(s)(rv) 416*635a8641SAndroid Build Coastguard Worker 417*635a8641SAndroid Build Coastguard Worker def call(__self, __context, __obj, *args, **kwargs): 418*635a8641SAndroid Build Coastguard Worker """Call an object from sandboxed code.""" 419*635a8641SAndroid Build Coastguard Worker fmt = inspect_format_method(__obj) 420*635a8641SAndroid Build Coastguard Worker if fmt is not None: 421*635a8641SAndroid Build Coastguard Worker return __self.format_string(fmt, args, kwargs) 422*635a8641SAndroid Build Coastguard Worker 423*635a8641SAndroid Build Coastguard Worker # the double prefixes are to avoid double keyword argument 424*635a8641SAndroid Build Coastguard Worker # errors when proxying the call. 425*635a8641SAndroid Build Coastguard Worker if not __self.is_safe_callable(__obj): 426*635a8641SAndroid Build Coastguard Worker raise SecurityError('%r is not safely callable' % (__obj,)) 427*635a8641SAndroid Build Coastguard Worker return __context.call(__obj, *args, **kwargs) 428*635a8641SAndroid Build Coastguard Worker 429*635a8641SAndroid Build Coastguard Worker 430*635a8641SAndroid Build Coastguard Workerclass ImmutableSandboxedEnvironment(SandboxedEnvironment): 431*635a8641SAndroid Build Coastguard Worker """Works exactly like the regular `SandboxedEnvironment` but does not 432*635a8641SAndroid Build Coastguard Worker permit modifications on the builtin mutable objects `list`, `set`, and 433*635a8641SAndroid Build Coastguard Worker `dict` by using the :func:`modifies_known_mutable` function. 434*635a8641SAndroid Build Coastguard Worker """ 435*635a8641SAndroid Build Coastguard Worker 436*635a8641SAndroid Build Coastguard Worker def is_safe_attribute(self, obj, attr, value): 437*635a8641SAndroid Build Coastguard Worker if not SandboxedEnvironment.is_safe_attribute(self, obj, attr, value): 438*635a8641SAndroid Build Coastguard Worker return False 439*635a8641SAndroid Build Coastguard Worker return not modifies_known_mutable(obj, attr) 440*635a8641SAndroid Build Coastguard Worker 441*635a8641SAndroid Build Coastguard Worker 442*635a8641SAndroid Build Coastguard Worker# This really is not a public API apparenlty. 443*635a8641SAndroid Build Coastguard Workertry: 444*635a8641SAndroid Build Coastguard Worker from _string import formatter_field_name_split 445*635a8641SAndroid Build Coastguard Workerexcept ImportError: 446*635a8641SAndroid Build Coastguard Worker def formatter_field_name_split(field_name): 447*635a8641SAndroid Build Coastguard Worker return field_name._formatter_field_name_split() 448*635a8641SAndroid Build Coastguard Worker 449*635a8641SAndroid Build Coastguard Worker 450*635a8641SAndroid Build Coastguard Workerclass SandboxedFormatterMixin(object): 451*635a8641SAndroid Build Coastguard Worker 452*635a8641SAndroid Build Coastguard Worker def __init__(self, env): 453*635a8641SAndroid Build Coastguard Worker self._env = env 454*635a8641SAndroid Build Coastguard Worker 455*635a8641SAndroid Build Coastguard Worker def get_field(self, field_name, args, kwargs): 456*635a8641SAndroid Build Coastguard Worker first, rest = formatter_field_name_split(field_name) 457*635a8641SAndroid Build Coastguard Worker obj = self.get_value(first, args, kwargs) 458*635a8641SAndroid Build Coastguard Worker for is_attr, i in rest: 459*635a8641SAndroid Build Coastguard Worker if is_attr: 460*635a8641SAndroid Build Coastguard Worker obj = self._env.getattr(obj, i) 461*635a8641SAndroid Build Coastguard Worker else: 462*635a8641SAndroid Build Coastguard Worker obj = self._env.getitem(obj, i) 463*635a8641SAndroid Build Coastguard Worker return obj, first 464*635a8641SAndroid Build Coastguard Worker 465*635a8641SAndroid Build Coastguard Workerclass SandboxedFormatter(SandboxedFormatterMixin, Formatter): 466*635a8641SAndroid Build Coastguard Worker 467*635a8641SAndroid Build Coastguard Worker def __init__(self, env): 468*635a8641SAndroid Build Coastguard Worker SandboxedFormatterMixin.__init__(self, env) 469*635a8641SAndroid Build Coastguard Worker Formatter.__init__(self) 470*635a8641SAndroid Build Coastguard Worker 471*635a8641SAndroid Build Coastguard Workerclass SandboxedEscapeFormatter(SandboxedFormatterMixin, EscapeFormatter): 472*635a8641SAndroid Build Coastguard Worker 473*635a8641SAndroid Build Coastguard Worker def __init__(self, env, escape): 474*635a8641SAndroid Build Coastguard Worker SandboxedFormatterMixin.__init__(self, env) 475*635a8641SAndroid Build Coastguard Worker EscapeFormatter.__init__(self, escape) 476