blob: cd5b5796c544c1527e1e3a9765309760c184af42 [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
Armin Ronacher76c280b2008-05-04 12:31:48 +020023#: attributes of function objects that are considered unsafe.
24UNSAFE_FUNCTION_ATTRIBUTES = set(['func_closure', 'func_code', 'func_dict',
25 'func_defaults', 'func_globals'])
26
27#: unsafe method attributes. function attributes are unsafe for methods too
28UNSAFE_METHOD_ATTRIBUTES = set(['im_class', 'im_func', 'im_self'])
29
Armin Ronacherc63243e2008-04-14 22:53:58 +020030
31def safe_range(*args):
32 """A range that can't generate ranges with a length of more than
Armin Ronacher7ceced52008-05-03 10:15:31 +020033 MAX_RANGE items.
34 """
Armin Ronacherc63243e2008-04-14 22:53:58 +020035 rng = xrange(*args)
36 if len(rng) > MAX_RANGE:
Armin Ronacher76c280b2008-05-04 12:31:48 +020037 raise OverflowError('range too big, maximum size for range is %d' %
38 MAX_RANGE)
Armin Ronacherc63243e2008-04-14 22:53:58 +020039 return rng
40
41
42def unsafe(f):
43 """Mark a function as unsafe."""
44 f.unsafe_callable = True
45 return f
46
47
48class SandboxedEnvironment(Environment):
49 """The sandboxed environment"""
50 sandboxed = True
51
52 def __init__(self, *args, **kwargs):
53 Environment.__init__(self, *args, **kwargs)
54 self.globals['range'] = safe_range
55
Armin Ronacher9a822052008-04-17 18:44:07 +020056 def is_safe_attribute(self, obj, attr, value):
Armin Ronacherc63243e2008-04-14 22:53:58 +020057 """The sandboxed environment will call this method to check if the
58 attribute of an object is safe to access. Per default all attributes
59 starting with an underscore are considered private as well as the
60 special attributes of functions and methods.
61 """
62 if attr.startswith('_'):
63 return False
64 if isinstance(obj, FunctionType):
Armin Ronacher76c280b2008-05-04 12:31:48 +020065 return attr not in UNSAFE_FUNCTION_ATTRIBUTES
Armin Ronacherc63243e2008-04-14 22:53:58 +020066 if isinstance(obj, MethodType):
Armin Ronacher76c280b2008-05-04 12:31:48 +020067 return attr not in UNSAFE_FUNCTION_ATTRIBUTES and \
68 attr not in UNSAFE_METHOD_ATTRIBUTES
Armin Ronacherc63243e2008-04-14 22:53:58 +020069 return True
70
71 def is_safe_callable(self, obj):
72 """Check if an object is safely callable. Per default a function is
73 considered safe unless the `unsafe_callable` attribute exists and is
Armin Ronacher7ceced52008-05-03 10:15:31 +020074 True. Override this method to alter the behavior, but this won't
Armin Ronacherc63243e2008-04-14 22:53:58 +020075 affect the `unsafe` decorator from this module.
76 """
Armin Ronacher7ceced52008-05-03 10:15:31 +020077 return not (getattr(obj, 'unsafe_callable', False) or \
78 getattr(obj, 'alters_data', False))
Armin Ronacherc63243e2008-04-14 22:53:58 +020079
Armin Ronacher9a822052008-04-17 18:44:07 +020080 def subscribe(self, obj, argument):
Armin Ronacherc63243e2008-04-14 22:53:58 +020081 """Subscribe an object from sandboxed code."""
Armin Ronacher9a822052008-04-17 18:44:07 +020082 is_unsafe = False
Armin Ronacherc63243e2008-04-14 22:53:58 +020083 try:
Armin Ronacher9a822052008-04-17 18:44:07 +020084 value = getattr(obj, str(argument))
85 except (AttributeError, UnicodeError):
86 pass
87 else:
88 if self.is_safe_attribute(obj, argument, value):
89 return value
90 is_unsafe = True
91 try:
92 return obj[argument]
Armin Ronacherc63243e2008-04-14 22:53:58 +020093 except (TypeError, LookupError):
Armin Ronacher9a822052008-04-17 18:44:07 +020094 if is_unsafe:
95 return self.undefined('access to attribute %r of %r object is'
96 ' unsafe.' % (
97 argument,
98 obj.__class__.__name__
99 ))
100 return self.undefined(obj=obj, name=argument)
Armin Ronacherc63243e2008-04-14 22:53:58 +0200101
102 def call(__self, __obj, *args, **kwargs):
103 """Call an object from sandboxed code."""
104 # the double prefixes are to avoid double keyword argument
105 # errors when proxying the call.
106 if not __self.is_safe_callable(__obj):
107 raise TypeError('%r is not safely callable' % (__obj,))
108 return __obj(*args, **kwargs)