1645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez# -*- coding: utf-8 -*-
2645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez"""
3645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    jinja2.sandbox
4645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    ~~~~~~~~~~~~~~
5645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
6645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    Adds a sandbox layer to Jinja as it was the default behavior in the old
7645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    Jinja 1 releases.  This sandbox is slightly different from Jinja 1 as the
8645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    default behavior is easier to use.
9645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
10645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    The behavior can be changed by subclassing the environment.
11645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
12645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    :copyright: (c) 2010 by the Jinja Team.
13645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    :license: BSD.
14645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez"""
15645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezimport operator
16645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezfrom jinja2.environment import Environment
17645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezfrom jinja2.exceptions import SecurityError
18645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezfrom jinja2._compat import string_types, function_type, method_type, \
19645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez     traceback_type, code_type, frame_type, generator_type, PY2
20645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
21645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
22645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#: maximum number of items a range may produce
23645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezMAX_RANGE = 100000
24645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
25645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#: attributes of function objects that are considered unsafe.
26645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezUNSAFE_FUNCTION_ATTRIBUTES = set(['func_closure', 'func_code', 'func_dict',
27645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                                  'func_defaults', 'func_globals'])
28645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
29645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#: unsafe method attributes.  function attributes are unsafe for methods too
30645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezUNSAFE_METHOD_ATTRIBUTES = set(['im_class', 'im_func', 'im_self'])
31645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
32645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#: unsafe generator attirbutes.
33645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezUNSAFE_GENERATOR_ATTRIBUTES = set(['gi_frame', 'gi_code'])
34645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
35645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez# On versions > python 2 the special attributes on functions are gone,
36645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez# but they remain on methods and generators for whatever reason.
37645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezif not PY2:
38645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    UNSAFE_FUNCTION_ATTRIBUTES = set()
39645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
40645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezimport warnings
41645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
42645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez# make sure we don't warn in python 2.6 about stuff we don't care about
43645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezwarnings.filterwarnings('ignore', 'the sets module', DeprecationWarning,
44645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                        module='jinja2.sandbox')
45645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
46645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezfrom collections import deque
47645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
48645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez_mutable_set_types = (set,)
49645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez_mutable_mapping_types = (dict,)
50645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez_mutable_sequence_types = (list,)
51645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
52645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
53645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez# on python 2.x we can register the user collection types
54645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chaveztry:
55645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    from UserDict import UserDict, DictMixin
56645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    from UserList import UserList
57645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    _mutable_mapping_types += (UserDict, DictMixin)
58645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    _mutable_set_types += (UserList,)
59645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezexcept ImportError:
60645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    pass
61645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
62645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez# if sets is still available, register the mutable set from there as well
63645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chaveztry:
64645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    from sets import Set
65645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    _mutable_set_types += (Set,)
66645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezexcept ImportError:
67645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    pass
68645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
69645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#: register Python 2.6 abstract base classes
70645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chaveztry:
71645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    from collections import MutableSet, MutableMapping, MutableSequence
72645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    _mutable_set_types += (MutableSet,)
73645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    _mutable_mapping_types += (MutableMapping,)
74645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    _mutable_sequence_types += (MutableSequence,)
75645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezexcept ImportError:
76645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    pass
77645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
78645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez_mutable_spec = (
79645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    (_mutable_set_types, frozenset([
80645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        'add', 'clear', 'difference_update', 'discard', 'pop', 'remove',
81645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        'symmetric_difference_update', 'update'
82645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    ])),
83645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    (_mutable_mapping_types, frozenset([
84645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        'clear', 'pop', 'popitem', 'setdefault', 'update'
85645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    ])),
86645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    (_mutable_sequence_types, frozenset([
87645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        'append', 'reverse', 'insert', 'sort', 'extend', 'remove'
88645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    ])),
89645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    (deque, frozenset([
90645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        'append', 'appendleft', 'clear', 'extend', 'extendleft', 'pop',
91645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        'popleft', 'remove', 'rotate'
92645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    ]))
93645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez)
94645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
95645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
96645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezdef safe_range(*args):
97645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """A range that can't generate ranges with a length of more than
98645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    MAX_RANGE items.
99645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """
100645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    rng = range(*args)
101645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if len(rng) > MAX_RANGE:
102645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        raise OverflowError('range too big, maximum size for range is %d' %
103645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                            MAX_RANGE)
104645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return rng
105645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
106645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
107645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezdef unsafe(f):
108645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """Marks a function or method as unsafe.
109645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
110645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    ::
111645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
112645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        @unsafe
113645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        def delete(self):
114645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            pass
115645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """
116645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    f.unsafe_callable = True
117645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return f
118645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
119645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
120645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezdef is_internal_attribute(obj, attr):
121645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """Test if the attribute given is an internal python attribute.  For
122645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    example this function returns `True` for the `func_code` attribute of
123645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    python objects.  This is useful if the environment method
124645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    :meth:`~SandboxedEnvironment.is_safe_attribute` is overridden.
125645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
126645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    >>> from jinja2.sandbox import is_internal_attribute
127645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    >>> is_internal_attribute(lambda: None, "func_code")
128645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    True
129645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    >>> is_internal_attribute((lambda x:x).func_code, 'co_code')
130645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    True
131645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    >>> is_internal_attribute(str, "upper")
132645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    False
133645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """
134645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if isinstance(obj, function_type):
135645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if attr in UNSAFE_FUNCTION_ATTRIBUTES:
136645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            return True
137645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    elif isinstance(obj, method_type):
138645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if attr in UNSAFE_FUNCTION_ATTRIBUTES or \
139645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez           attr in UNSAFE_METHOD_ATTRIBUTES:
140645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            return True
141645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    elif isinstance(obj, type):
142645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if attr == 'mro':
143645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            return True
144645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    elif isinstance(obj, (code_type, traceback_type, frame_type)):
145645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return True
146645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    elif isinstance(obj, generator_type):
147645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if attr in UNSAFE_GENERATOR_ATTRIBUTES:
148645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            return True
149645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return attr.startswith('__')
150645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
151645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
152645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezdef modifies_known_mutable(obj, attr):
153645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """This function checks if an attribute on a builtin mutable object
154645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    (list, dict, set or deque) would modify it if called.  It also supports
155645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    the "user"-versions of the objects (`sets.Set`, `UserDict.*` etc.) and
156645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    with Python 2.6 onwards the abstract base classes `MutableSet`,
157645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    `MutableMapping`, and `MutableSequence`.
158645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
159645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    >>> modifies_known_mutable({}, "clear")
160645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    True
161645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    >>> modifies_known_mutable({}, "keys")
162645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    False
163645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    >>> modifies_known_mutable([], "append")
164645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    True
165645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    >>> modifies_known_mutable([], "index")
166645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    False
167645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
168645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    If called with an unsupported object (such as unicode) `False` is
169645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    returned.
170645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
171645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    >>> modifies_known_mutable("foo", "upper")
172645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    False
173645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """
174645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    for typespec, unsafe in _mutable_spec:
175645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if isinstance(obj, typespec):
176645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            return attr in unsafe
177645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return False
178645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
179645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
180645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezclass SandboxedEnvironment(Environment):
181645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """The sandboxed environment.  It works like the regular environment but
182645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    tells the compiler to generate sandboxed code.  Additionally subclasses of
183645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    this environment may override the methods that tell the runtime what
184645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    attributes or functions are safe to access.
185645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
186645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    If the template tries to access insecure code a :exc:`SecurityError` is
187645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    raised.  However also other exceptions may occour during the rendering so
188645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    the caller has to ensure that all exceptions are catched.
189645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """
190645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    sandboxed = True
191645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
192645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    #: default callback table for the binary operators.  A copy of this is
193645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    #: available on each instance of a sandboxed environment as
194645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    #: :attr:`binop_table`
195645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    default_binop_table = {
196645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        '+':        operator.add,
197645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        '-':        operator.sub,
198645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        '*':        operator.mul,
199645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        '/':        operator.truediv,
200645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        '//':       operator.floordiv,
201645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        '**':       operator.pow,
202645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        '%':        operator.mod
203645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
204645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
205645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    #: default callback table for the unary operators.  A copy of this is
206645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    #: available on each instance of a sandboxed environment as
207645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    #: :attr:`unop_table`
208645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    default_unop_table = {
209645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        '+':        operator.pos,
210645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        '-':        operator.neg
211645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    }
212645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
213645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    #: a set of binary operators that should be intercepted.  Each operator
214645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    #: that is added to this set (empty by default) is delegated to the
215645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    #: :meth:`call_binop` method that will perform the operator.  The default
216645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    #: operator callback is specified by :attr:`binop_table`.
217645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    #:
218645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    #: The following binary operators are interceptable:
219645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    #: ``//``, ``%``, ``+``, ``*``, ``-``, ``/``, and ``**``
220645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    #:
221645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    #: The default operation form the operator table corresponds to the
222645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    #: builtin function.  Intercepted calls are always slower than the native
223645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    #: operator call, so make sure only to intercept the ones you are
224645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    #: interested in.
225645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    #:
226645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    #: .. versionadded:: 2.6
227645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    intercepted_binops = frozenset()
228645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
229645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    #: a set of unary operators that should be intercepted.  Each operator
230645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    #: that is added to this set (empty by default) is delegated to the
231645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    #: :meth:`call_unop` method that will perform the operator.  The default
232645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    #: operator callback is specified by :attr:`unop_table`.
233645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    #:
234645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    #: The following unary operators are interceptable: ``+``, ``-``
235645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    #:
236645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    #: The default operation form the operator table corresponds to the
237645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    #: builtin function.  Intercepted calls are always slower than the native
238645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    #: operator call, so make sure only to intercept the ones you are
239645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    #: interested in.
240645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    #:
241645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    #: .. versionadded:: 2.6
242645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    intercepted_unops = frozenset()
243645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
244645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def intercept_unop(self, operator):
245645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        """Called during template compilation with the name of a unary
246645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        operator to check if it should be intercepted at runtime.  If this
247645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        method returns `True`, :meth:`call_unop` is excuted for this unary
248645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        operator.  The default implementation of :meth:`call_unop` will use
249645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        the :attr:`unop_table` dictionary to perform the operator with the
250645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        same logic as the builtin one.
251645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
252645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        The following unary operators are interceptable: ``+`` and ``-``
253645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
254645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        Intercepted calls are always slower than the native operator call,
255645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        so make sure only to intercept the ones you are interested in.
256645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
257645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        .. versionadded:: 2.6
258645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        """
259645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return False
260645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
261645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
262645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def __init__(self, *args, **kwargs):
263645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        Environment.__init__(self, *args, **kwargs)
264645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        self.globals['range'] = safe_range
265645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        self.binop_table = self.default_binop_table.copy()
266645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        self.unop_table = self.default_unop_table.copy()
267645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
268645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def is_safe_attribute(self, obj, attr, value):
269645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        """The sandboxed environment will call this method to check if the
270645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        attribute of an object is safe to access.  Per default all attributes
271645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        starting with an underscore are considered private as well as the
272645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        special attributes of internal python objects as returned by the
273645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        :func:`is_internal_attribute` function.
274645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        """
275645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return not (attr.startswith('_') or is_internal_attribute(obj, attr))
276645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
277645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def is_safe_callable(self, obj):
278645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        """Check if an object is safely callable.  Per default a function is
279645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        considered safe unless the `unsafe_callable` attribute exists and is
280645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        True.  Override this method to alter the behavior, but this won't
281645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        affect the `unsafe` decorator from this module.
282645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        """
283645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return not (getattr(obj, 'unsafe_callable', False) or
284645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                    getattr(obj, 'alters_data', False))
285645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
286645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def call_binop(self, context, operator, left, right):
287645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        """For intercepted binary operator calls (:meth:`intercepted_binops`)
288645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        this function is executed instead of the builtin operator.  This can
289645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        be used to fine tune the behavior of certain operators.
290645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
291645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        .. versionadded:: 2.6
292645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        """
293645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return self.binop_table[operator](left, right)
294645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
295645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def call_unop(self, context, operator, arg):
296645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        """For intercepted unary operator calls (:meth:`intercepted_unops`)
297645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        this function is executed instead of the builtin operator.  This can
298645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        be used to fine tune the behavior of certain operators.
299645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
300645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        .. versionadded:: 2.6
301645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        """
302645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return self.unop_table[operator](arg)
303645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
304645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def getitem(self, obj, argument):
305645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        """Subscribe an object from sandboxed code."""
306645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        try:
307645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            return obj[argument]
308645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        except (TypeError, LookupError):
309645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            if isinstance(argument, string_types):
310645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                try:
311645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                    attr = str(argument)
312645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                except Exception:
313645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                    pass
314645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                else:
315645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                    try:
316645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                        value = getattr(obj, attr)
317645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                    except AttributeError:
318645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                        pass
319645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                    else:
320645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                        if self.is_safe_attribute(obj, argument, value):
321645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                            return value
322645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                        return self.unsafe_undefined(obj, argument)
323645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return self.undefined(obj=obj, name=argument)
324645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
325645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def getattr(self, obj, attribute):
326645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        """Subscribe an object from sandboxed code and prefer the
327645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        attribute.  The attribute passed *must* be a bytestring.
328645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        """
329645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        try:
330645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            value = getattr(obj, attribute)
331645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        except AttributeError:
332645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            try:
333645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                return obj[attribute]
334645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            except (TypeError, LookupError):
335645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                pass
336645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        else:
337645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            if self.is_safe_attribute(obj, attribute, value):
338645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                return value
339645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            return self.unsafe_undefined(obj, attribute)
340645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return self.undefined(obj=obj, name=attribute)
341645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
342645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def unsafe_undefined(self, obj, attribute):
343645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        """Return an undefined object for unsafe attributes."""
344645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return self.undefined('access to attribute %r of %r '
345645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez                              'object is unsafe.' % (
346645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            attribute,
347645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            obj.__class__.__name__
348645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        ), name=attribute, obj=obj, exc=SecurityError)
349645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
350645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def call(__self, __context, __obj, *args, **kwargs):
351645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        """Call an object from sandboxed code."""
352645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        # the double prefixes are to avoid double keyword argument
353645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        # errors when proxying the call.
354645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if not __self.is_safe_callable(__obj):
355645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            raise SecurityError('%r is not safely callable' % (__obj,))
356645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return __context.call(__obj, *args, **kwargs)
357645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
358645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
359645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezclass ImmutableSandboxedEnvironment(SandboxedEnvironment):
360645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """Works exactly like the regular `SandboxedEnvironment` but does not
361645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    permit modifications on the builtin mutable objects `list`, `set`, and
362645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    `dict` by using the :func:`modifies_known_mutable` function.
363645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    """
364645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
365645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    def is_safe_attribute(self, obj, attr, value):
366645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        if not SandboxedEnvironment.is_safe_attribute(self, obj, attr, value):
367645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez            return False
368645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez        return not modifies_known_mutable(obj, attr)
369