xref: /aosp_15_r20/external/libchrome/third_party/jinja2/sandbox.py (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
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