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