blob: 02a04383cefb69c6fd83b0d10080bd9dfa5b3164 [file] [log] [blame]
Armin Ronacherc63243e2008-04-14 22:53:58 +02001# -*- 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: Copyright 2008 by Armin Ronacher.
13 :license: BSD.
14"""
15from types import FunctionType, MethodType
16from jinja2.runtime import Undefined
17from jinja2.environment import Environment
18
19
20#: maximum number of items a range may produce
21MAX_RANGE = 100000
22
23
24def safe_range(*args):
25 """A range that can't generate ranges with a length of more than
Armin Ronacher7ceced52008-05-03 10:15:31 +020026 MAX_RANGE items.
27 """
Armin Ronacherc63243e2008-04-14 22:53:58 +020028 rng = xrange(*args)
29 if len(rng) > MAX_RANGE:
30 raise OverflowError('range too big')
31 return rng
32
33
34def unsafe(f):
35 """Mark a function as unsafe."""
36 f.unsafe_callable = True
37 return f
38
39
40class SandboxedEnvironment(Environment):
41 """The sandboxed environment"""
42 sandboxed = True
43
44 def __init__(self, *args, **kwargs):
45 Environment.__init__(self, *args, **kwargs)
46 self.globals['range'] = safe_range
47
Armin Ronacher9a822052008-04-17 18:44:07 +020048 def is_safe_attribute(self, obj, attr, value):
Armin Ronacherc63243e2008-04-14 22:53:58 +020049 """The sandboxed environment will call this method to check if the
50 attribute of an object is safe to access. Per default all attributes
51 starting with an underscore are considered private as well as the
52 special attributes of functions and methods.
53 """
54 if attr.startswith('_'):
55 return False
56 if isinstance(obj, FunctionType):
57 return not attr.startswith('func_')
58 if isinstance(obj, MethodType):
59 return not attr.startswith('im_')
60 return True
61
62 def is_safe_callable(self, obj):
63 """Check if an object is safely callable. Per default a function is
64 considered safe unless the `unsafe_callable` attribute exists and is
Armin Ronacher7ceced52008-05-03 10:15:31 +020065 True. Override this method to alter the behavior, but this won't
Armin Ronacherc63243e2008-04-14 22:53:58 +020066 affect the `unsafe` decorator from this module.
67 """
Armin Ronacher7ceced52008-05-03 10:15:31 +020068 return not (getattr(obj, 'unsafe_callable', False) or \
69 getattr(obj, 'alters_data', False))
Armin Ronacherc63243e2008-04-14 22:53:58 +020070
Armin Ronacher9a822052008-04-17 18:44:07 +020071 def subscribe(self, obj, argument):
Armin Ronacherc63243e2008-04-14 22:53:58 +020072 """Subscribe an object from sandboxed code."""
Armin Ronacher9a822052008-04-17 18:44:07 +020073 is_unsafe = False
Armin Ronacherc63243e2008-04-14 22:53:58 +020074 try:
Armin Ronacher9a822052008-04-17 18:44:07 +020075 value = getattr(obj, str(argument))
76 except (AttributeError, UnicodeError):
77 pass
78 else:
79 if self.is_safe_attribute(obj, argument, value):
80 return value
81 is_unsafe = True
82 try:
83 return obj[argument]
Armin Ronacherc63243e2008-04-14 22:53:58 +020084 except (TypeError, LookupError):
Armin Ronacher9a822052008-04-17 18:44:07 +020085 if is_unsafe:
86 return self.undefined('access to attribute %r of %r object is'
87 ' unsafe.' % (
88 argument,
89 obj.__class__.__name__
90 ))
91 return self.undefined(obj=obj, name=argument)
Armin Ronacherc63243e2008-04-14 22:53:58 +020092
93 def call(__self, __obj, *args, **kwargs):
94 """Call an object from sandboxed code."""
95 # the double prefixes are to avoid double keyword argument
96 # errors when proxying the call.
97 if not __self.is_safe_callable(__obj):
98 raise TypeError('%r is not safely callable' % (__obj,))
99 return __obj(*args, **kwargs)