1# -*- coding: utf-8 -*-
2"""
3    jinja2.sandbox
4    ~~~~~~~~~~~~~~
5
6    Adds a sandbox layer to Jinja as it was the default behavior in the old
7    Jinja 1 releases.  This sandbox is slightly different from Jinja 1 as the
8    default behavior is easier to use.
9
10    The behavior can be changed by subclassing the environment.
11
12    :copyright: (c) 2010 by the Jinja Team.
13    :license: BSD.
14"""
15import operator
16from jinja2.environment import Environment
17from jinja2.exceptions import SecurityError
18from jinja2._compat import string_types, function_type, method_type, \
19     traceback_type, code_type, frame_type, generator_type, PY2
20
21
22#: maximum number of items a range may produce
23MAX_RANGE = 100000
24
25#: attributes of function objects that are considered unsafe.
26UNSAFE_FUNCTION_ATTRIBUTES = set(['func_closure', 'func_code', 'func_dict',
27                                  'func_defaults', 'func_globals'])
28
29#: unsafe method attributes.  function attributes are unsafe for methods too
30UNSAFE_METHOD_ATTRIBUTES = set(['im_class', 'im_func', 'im_self'])
31
32#: unsafe generator attirbutes.
33UNSAFE_GENERATOR_ATTRIBUTES = set(['gi_frame', 'gi_code'])
34
35# On versions > python 2 the special attributes on functions are gone,
36# but they remain on methods and generators for whatever reason.
37if not PY2:
38    UNSAFE_FUNCTION_ATTRIBUTES = set()
39
40import warnings
41
42# make sure we don't warn in python 2.6 about stuff we don't care about
43warnings.filterwarnings('ignore', 'the sets module', DeprecationWarning,
44                        module='jinja2.sandbox')
45
46from collections import deque
47
48_mutable_set_types = (set,)
49_mutable_mapping_types = (dict,)
50_mutable_sequence_types = (list,)
51
52
53# on python 2.x we can register the user collection types
54try:
55    from UserDict import UserDict, DictMixin
56    from UserList import UserList
57    _mutable_mapping_types += (UserDict, DictMixin)
58    _mutable_set_types += (UserList,)
59except ImportError:
60    pass
61
62# if sets is still available, register the mutable set from there as well
63try:
64    from sets import Set
65    _mutable_set_types += (Set,)
66except ImportError:
67    pass
68
69#: register Python 2.6 abstract base classes
70try:
71    from collections import MutableSet, MutableMapping, MutableSequence
72    _mutable_set_types += (MutableSet,)
73    _mutable_mapping_types += (MutableMapping,)
74    _mutable_sequence_types += (MutableSequence,)
75except ImportError:
76    pass
77
78_mutable_spec = (
79    (_mutable_set_types, frozenset([
80        'add', 'clear', 'difference_update', 'discard', 'pop', 'remove',
81        'symmetric_difference_update', 'update'
82    ])),
83    (_mutable_mapping_types, frozenset([
84        'clear', 'pop', 'popitem', 'setdefault', 'update'
85    ])),
86    (_mutable_sequence_types, frozenset([
87        'append', 'reverse', 'insert', 'sort', 'extend', 'remove'
88    ])),
89    (deque, frozenset([
90        'append', 'appendleft', 'clear', 'extend', 'extendleft', 'pop',
91        'popleft', 'remove', 'rotate'
92    ]))
93)
94
95
96def safe_range(*args):
97    """A range that can't generate ranges with a length of more than
98    MAX_RANGE items.
99    """
100    rng = range(*args)
101    if len(rng) > MAX_RANGE:
102        raise OverflowError('range too big, maximum size for range is %d' %
103                            MAX_RANGE)
104    return rng
105
106
107def unsafe(f):
108    """Marks a function or method as unsafe.
109
110    ::
111
112        @unsafe
113        def delete(self):
114            pass
115    """
116    f.unsafe_callable = True
117    return f
118
119
120def is_internal_attribute(obj, attr):
121    """Test if the attribute given is an internal python attribute.  For
122    example this function returns `True` for the `func_code` attribute of
123    python objects.  This is useful if the environment method
124    :meth:`~SandboxedEnvironment.is_safe_attribute` is overridden.
125
126    >>> from jinja2.sandbox import is_internal_attribute
127    >>> is_internal_attribute(lambda: None, "func_code")
128    True
129    >>> is_internal_attribute((lambda x:x).func_code, 'co_code')
130    True
131    >>> is_internal_attribute(str, "upper")
132    False
133    """
134    if isinstance(obj, function_type):
135        if attr in UNSAFE_FUNCTION_ATTRIBUTES:
136            return True
137    elif isinstance(obj, method_type):
138        if attr in UNSAFE_FUNCTION_ATTRIBUTES or \
139           attr in UNSAFE_METHOD_ATTRIBUTES:
140            return True
141    elif isinstance(obj, type):
142        if attr == 'mro':
143            return True
144    elif isinstance(obj, (code_type, traceback_type, frame_type)):
145        return True
146    elif isinstance(obj, generator_type):
147        if attr in UNSAFE_GENERATOR_ATTRIBUTES:
148            return True
149    return attr.startswith('__')
150
151
152def modifies_known_mutable(obj, attr):
153    """This function checks if an attribute on a builtin mutable object
154    (list, dict, set or deque) would modify it if called.  It also supports
155    the "user"-versions of the objects (`sets.Set`, `UserDict.*` etc.) and
156    with Python 2.6 onwards the abstract base classes `MutableSet`,
157    `MutableMapping`, and `MutableSequence`.
158
159    >>> modifies_known_mutable({}, "clear")
160    True
161    >>> modifies_known_mutable({}, "keys")
162    False
163    >>> modifies_known_mutable([], "append")
164    True
165    >>> modifies_known_mutable([], "index")
166    False
167
168    If called with an unsupported object (such as unicode) `False` is
169    returned.
170
171    >>> modifies_known_mutable("foo", "upper")
172    False
173    """
174    for typespec, unsafe in _mutable_spec:
175        if isinstance(obj, typespec):
176            return attr in unsafe
177    return False
178
179
180class SandboxedEnvironment(Environment):
181    """The sandboxed environment.  It works like the regular environment but
182    tells the compiler to generate sandboxed code.  Additionally subclasses of
183    this environment may override the methods that tell the runtime what
184    attributes or functions are safe to access.
185
186    If the template tries to access insecure code a :exc:`SecurityError` is
187    raised.  However also other exceptions may occour during the rendering so
188    the caller has to ensure that all exceptions are catched.
189    """
190    sandboxed = True
191
192    #: default callback table for the binary operators.  A copy of this is
193    #: available on each instance of a sandboxed environment as
194    #: :attr:`binop_table`
195    default_binop_table = {
196        '+':        operator.add,
197        '-':        operator.sub,
198        '*':        operator.mul,
199        '/':        operator.truediv,
200        '//':       operator.floordiv,
201        '**':       operator.pow,
202        '%':        operator.mod
203    }
204
205    #: default callback table for the unary operators.  A copy of this is
206    #: available on each instance of a sandboxed environment as
207    #: :attr:`unop_table`
208    default_unop_table = {
209        '+':        operator.pos,
210        '-':        operator.neg
211    }
212
213    #: a set of binary operators that should be intercepted.  Each operator
214    #: that is added to this set (empty by default) is delegated to the
215    #: :meth:`call_binop` method that will perform the operator.  The default
216    #: operator callback is specified by :attr:`binop_table`.
217    #:
218    #: The following binary operators are interceptable:
219    #: ``//``, ``%``, ``+``, ``*``, ``-``, ``/``, and ``**``
220    #:
221    #: The default operation form the operator table corresponds to the
222    #: builtin function.  Intercepted calls are always slower than the native
223    #: operator call, so make sure only to intercept the ones you are
224    #: interested in.
225    #:
226    #: .. versionadded:: 2.6
227    intercepted_binops = frozenset()
228
229    #: a set of unary operators that should be intercepted.  Each operator
230    #: that is added to this set (empty by default) is delegated to the
231    #: :meth:`call_unop` method that will perform the operator.  The default
232    #: operator callback is specified by :attr:`unop_table`.
233    #:
234    #: The following unary operators are interceptable: ``+``, ``-``
235    #:
236    #: The default operation form the operator table corresponds to the
237    #: builtin function.  Intercepted calls are always slower than the native
238    #: operator call, so make sure only to intercept the ones you are
239    #: interested in.
240    #:
241    #: .. versionadded:: 2.6
242    intercepted_unops = frozenset()
243
244    def intercept_unop(self, operator):
245        """Called during template compilation with the name of a unary
246        operator to check if it should be intercepted at runtime.  If this
247        method returns `True`, :meth:`call_unop` is excuted for this unary
248        operator.  The default implementation of :meth:`call_unop` will use
249        the :attr:`unop_table` dictionary to perform the operator with the
250        same logic as the builtin one.
251
252        The following unary operators are interceptable: ``+`` and ``-``
253
254        Intercepted calls are always slower than the native operator call,
255        so make sure only to intercept the ones you are interested in.
256
257        .. versionadded:: 2.6
258        """
259        return False
260
261
262    def __init__(self, *args, **kwargs):
263        Environment.__init__(self, *args, **kwargs)
264        self.globals['range'] = safe_range
265        self.binop_table = self.default_binop_table.copy()
266        self.unop_table = self.default_unop_table.copy()
267
268    def is_safe_attribute(self, obj, attr, value):
269        """The sandboxed environment will call this method to check if the
270        attribute of an object is safe to access.  Per default all attributes
271        starting with an underscore are considered private as well as the
272        special attributes of internal python objects as returned by the
273        :func:`is_internal_attribute` function.
274        """
275        return not (attr.startswith('_') or is_internal_attribute(obj, attr))
276
277    def is_safe_callable(self, obj):
278        """Check if an object is safely callable.  Per default a function is
279        considered safe unless the `unsafe_callable` attribute exists and is
280        True.  Override this method to alter the behavior, but this won't
281        affect the `unsafe` decorator from this module.
282        """
283        return not (getattr(obj, 'unsafe_callable', False) or
284                    getattr(obj, 'alters_data', False))
285
286    def call_binop(self, context, operator, left, right):
287        """For intercepted binary operator calls (:meth:`intercepted_binops`)
288        this function is executed instead of the builtin operator.  This can
289        be used to fine tune the behavior of certain operators.
290
291        .. versionadded:: 2.6
292        """
293        return self.binop_table[operator](left, right)
294
295    def call_unop(self, context, operator, arg):
296        """For intercepted unary operator calls (:meth:`intercepted_unops`)
297        this function is executed instead of the builtin operator.  This can
298        be used to fine tune the behavior of certain operators.
299
300        .. versionadded:: 2.6
301        """
302        return self.unop_table[operator](arg)
303
304    def getitem(self, obj, argument):
305        """Subscribe an object from sandboxed code."""
306        try:
307            return obj[argument]
308        except (TypeError, LookupError):
309            if isinstance(argument, string_types):
310                try:
311                    attr = str(argument)
312                except Exception:
313                    pass
314                else:
315                    try:
316                        value = getattr(obj, attr)
317                    except AttributeError:
318                        pass
319                    else:
320                        if self.is_safe_attribute(obj, argument, value):
321                            return value
322                        return self.unsafe_undefined(obj, argument)
323        return self.undefined(obj=obj, name=argument)
324
325    def getattr(self, obj, attribute):
326        """Subscribe an object from sandboxed code and prefer the
327        attribute.  The attribute passed *must* be a bytestring.
328        """
329        try:
330            value = getattr(obj, attribute)
331        except AttributeError:
332            try:
333                return obj[attribute]
334            except (TypeError, LookupError):
335                pass
336        else:
337            if self.is_safe_attribute(obj, attribute, value):
338                return value
339            return self.unsafe_undefined(obj, attribute)
340        return self.undefined(obj=obj, name=attribute)
341
342    def unsafe_undefined(self, obj, attribute):
343        """Return an undefined object for unsafe attributes."""
344        return self.undefined('access to attribute %r of %r '
345                              'object is unsafe.' % (
346            attribute,
347            obj.__class__.__name__
348        ), name=attribute, obj=obj, exc=SecurityError)
349
350    def call(__self, __context, __obj, *args, **kwargs):
351        """Call an object from sandboxed code."""
352        # the double prefixes are to avoid double keyword argument
353        # errors when proxying the call.
354        if not __self.is_safe_callable(__obj):
355            raise SecurityError('%r is not safely callable' % (__obj,))
356        return __context.call(__obj, *args, **kwargs)
357
358
359class ImmutableSandboxedEnvironment(SandboxedEnvironment):
360    """Works exactly like the regular `SandboxedEnvironment` but does not
361    permit modifications on the builtin mutable objects `list`, `set`, and
362    `dict` by using the :func:`modifies_known_mutable` function.
363    """
364
365    def is_safe_attribute(self, obj, attr, value):
366        if not SandboxedEnvironment.is_safe_attribute(self, obj, attr, value):
367            return False
368        return not modifies_known_mutable(obj, attr)
369