| OLD | NEW | 
| (Empty) |  | 
 |    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     """Marks a function or method as unsafe. | 
 |  102  | 
 |  103     :: | 
 |  104  | 
 |  105         @unsafe | 
 |  106         def delete(self): | 
 |  107             pass | 
 |  108     """ | 
 |  109     f.unsafe_callable = True | 
 |  110     return f | 
 |  111  | 
 |  112  | 
 |  113 def is_internal_attribute(obj, attr): | 
 |  114     """Test if the attribute given is an internal python attribute.  For | 
 |  115     example this function returns `True` for the `func_code` attribute of | 
 |  116     python objects.  This is useful if the environment method | 
 |  117     :meth:`~SandboxedEnvironment.is_safe_attribute` is overriden. | 
 |  118  | 
 |  119     >>> from jinja2.sandbox import is_internal_attribute | 
 |  120     >>> is_internal_attribute(lambda: None, "func_code") | 
 |  121     True | 
 |  122     >>> is_internal_attribute((lambda x:x).func_code, 'co_code') | 
 |  123     True | 
 |  124     >>> is_internal_attribute(str, "upper") | 
 |  125     False | 
 |  126     """ | 
 |  127     if isinstance(obj, FunctionType): | 
 |  128         if attr in UNSAFE_FUNCTION_ATTRIBUTES: | 
 |  129             return True | 
 |  130     elif isinstance(obj, MethodType): | 
 |  131         if attr in UNSAFE_FUNCTION_ATTRIBUTES or \ | 
 |  132            attr in UNSAFE_METHOD_ATTRIBUTES: | 
 |  133             return True | 
 |  134     elif isinstance(obj, type): | 
 |  135         if attr == 'mro': | 
 |  136             return True | 
 |  137     elif isinstance(obj, (CodeType, TracebackType, FrameType)): | 
 |  138         return True | 
 |  139     elif isinstance(obj, GeneratorType): | 
 |  140         if attr == 'gi_frame': | 
 |  141             return True | 
 |  142     return attr.startswith('__') | 
 |  143  | 
 |  144  | 
 |  145 def modifies_known_mutable(obj, attr): | 
 |  146     """This function checks if an attribute on a builtin mutable object | 
 |  147     (list, dict, set or deque) would modify it if called.  It also supports | 
 |  148     the "user"-versions of the objects (`sets.Set`, `UserDict.*` etc.) and | 
 |  149     with Python 2.6 onwards the abstract base classes `MutableSet`, | 
 |  150     `MutableMapping`, and `MutableSequence`. | 
 |  151  | 
 |  152     >>> modifies_known_mutable({}, "clear") | 
 |  153     True | 
 |  154     >>> modifies_known_mutable({}, "keys") | 
 |  155     False | 
 |  156     >>> modifies_known_mutable([], "append") | 
 |  157     True | 
 |  158     >>> modifies_known_mutable([], "index") | 
 |  159     False | 
 |  160  | 
 |  161     If called with an unsupported object (such as unicode) `False` is | 
 |  162     returned. | 
 |  163  | 
 |  164     >>> modifies_known_mutable("foo", "upper") | 
 |  165     False | 
 |  166     """ | 
 |  167     for typespec, unsafe in _mutable_spec: | 
 |  168         if isinstance(obj, typespec): | 
 |  169             return attr in unsafe | 
 |  170     return False | 
 |  171  | 
 |  172  | 
 |  173 class SandboxedEnvironment(Environment): | 
 |  174     """The sandboxed environment.  It works like the regular environment but | 
 |  175     tells the compiler to generate sandboxed code.  Additionally subclasses of | 
 |  176     this environment may override the methods that tell the runtime what | 
 |  177     attributes or functions are safe to access. | 
 |  178  | 
 |  179     If the template tries to access insecure code a :exc:`SecurityError` is | 
 |  180     raised.  However also other exceptions may occour during the rendering so | 
 |  181     the caller has to ensure that all exceptions are catched. | 
 |  182     """ | 
 |  183     sandboxed = True | 
 |  184  | 
 |  185     #: default callback table for the binary operators.  A copy of this is | 
 |  186     #: available on each instance of a sandboxed environment as | 
 |  187     #: :attr:`binop_table` | 
 |  188     default_binop_table = { | 
 |  189         '+':        operator.add, | 
 |  190         '-':        operator.sub, | 
 |  191         '*':        operator.mul, | 
 |  192         '/':        operator.truediv, | 
 |  193         '//':       operator.floordiv, | 
 |  194         '**':       operator.pow, | 
 |  195         '%':        operator.mod | 
 |  196     } | 
 |  197  | 
 |  198     #: default callback table for the unary operators.  A copy of this is | 
 |  199     #: available on each instance of a sandboxed environment as | 
 |  200     #: :attr:`unop_table` | 
 |  201     default_unop_table = { | 
 |  202         '+':        operator.pos, | 
 |  203         '-':        operator.neg | 
 |  204     } | 
 |  205  | 
 |  206     #: a set of binary operators that should be intercepted.  Each operator | 
 |  207     #: that is added to this set (empty by default) is delegated to the | 
 |  208     #: :meth:`call_binop` method that will perform the operator.  The default | 
 |  209     #: operator callback is specified by :attr:`binop_table`. | 
 |  210     #: | 
 |  211     #: The following binary operators are interceptable: | 
 |  212     #: ``//``, ``%``, ``+``, ``*``, ``-``, ``/``, and ``**`` | 
 |  213     #: | 
 |  214     #: The default operation form the operator table corresponds to the | 
 |  215     #: builtin function.  Intercepted calls are always slower than the native | 
 |  216     #: operator call, so make sure only to intercept the ones you are | 
 |  217     #: interested in. | 
 |  218     #: | 
 |  219     #: .. versionadded:: 2.6 | 
 |  220     intercepted_binops = frozenset() | 
 |  221  | 
 |  222     #: a set of unary operators that should be intercepted.  Each operator | 
 |  223     #: that is added to this set (empty by default) is delegated to the | 
 |  224     #: :meth:`call_unop` method that will perform the operator.  The default | 
 |  225     #: operator callback is specified by :attr:`unop_table`. | 
 |  226     #: | 
 |  227     #: The following unary operators are interceptable: ``+``, ``-`` | 
 |  228     #: | 
 |  229     #: The default operation form the operator table corresponds to the | 
 |  230     #: builtin function.  Intercepted calls are always slower than the native | 
 |  231     #: operator call, so make sure only to intercept the ones you are | 
 |  232     #: interested in. | 
 |  233     #: | 
 |  234     #: .. versionadded:: 2.6 | 
 |  235     intercepted_unops = frozenset() | 
 |  236  | 
 |  237     def intercept_unop(self, operator): | 
 |  238         """Called during template compilation with the name of a unary | 
 |  239         operator to check if it should be intercepted at runtime.  If this | 
 |  240         method returns `True`, :meth:`call_unop` is excuted for this unary | 
 |  241         operator.  The default implementation of :meth:`call_unop` will use | 
 |  242         the :attr:`unop_table` dictionary to perform the operator with the | 
 |  243         same logic as the builtin one. | 
 |  244  | 
 |  245         The following unary operators are interceptable: ``+`` and ``-`` | 
 |  246  | 
 |  247         Intercepted calls are always slower than the native operator call, | 
 |  248         so make sure only to intercept the ones you are interested in. | 
 |  249  | 
 |  250         .. versionadded:: 2.6 | 
 |  251         """ | 
 |  252         return False | 
 |  253  | 
 |  254  | 
 |  255     def __init__(self, *args, **kwargs): | 
 |  256         Environment.__init__(self, *args, **kwargs) | 
 |  257         self.globals['range'] = safe_range | 
 |  258         self.binop_table = self.default_binop_table.copy() | 
 |  259         self.unop_table = self.default_unop_table.copy() | 
 |  260  | 
 |  261     def is_safe_attribute(self, obj, attr, value): | 
 |  262         """The sandboxed environment will call this method to check if the | 
 |  263         attribute of an object is safe to access.  Per default all attributes | 
 |  264         starting with an underscore are considered private as well as the | 
 |  265         special attributes of internal python objects as returned by the | 
 |  266         :func:`is_internal_attribute` function. | 
 |  267         """ | 
 |  268         return not (attr.startswith('_') or is_internal_attribute(obj, attr)) | 
 |  269  | 
 |  270     def is_safe_callable(self, obj): | 
 |  271         """Check if an object is safely callable.  Per default a function is | 
 |  272         considered safe unless the `unsafe_callable` attribute exists and is | 
 |  273         True.  Override this method to alter the behavior, but this won't | 
 |  274         affect the `unsafe` decorator from this module. | 
 |  275         """ | 
 |  276         return not (getattr(obj, 'unsafe_callable', False) or | 
 |  277                     getattr(obj, 'alters_data', False)) | 
 |  278  | 
 |  279     def call_binop(self, context, operator, left, right): | 
 |  280         """For intercepted binary operator calls (:meth:`intercepted_binops`) | 
 |  281         this function is executed instead of the builtin operator.  This can | 
 |  282         be used to fine tune the behavior of certain operators. | 
 |  283  | 
 |  284         .. versionadded:: 2.6 | 
 |  285         """ | 
 |  286         return self.binop_table[operator](left, right) | 
 |  287  | 
 |  288     def call_unop(self, context, operator, arg): | 
 |  289         """For intercepted unary operator calls (:meth:`intercepted_unops`) | 
 |  290         this function is executed instead of the builtin operator.  This can | 
 |  291         be used to fine tune the behavior of certain operators. | 
 |  292  | 
 |  293         .. versionadded:: 2.6 | 
 |  294         """ | 
 |  295         return self.unop_table[operator](arg) | 
 |  296  | 
 |  297     def getitem(self, obj, argument): | 
 |  298         """Subscribe an object from sandboxed code.""" | 
 |  299         try: | 
 |  300             return obj[argument] | 
 |  301         except (TypeError, LookupError): | 
 |  302             if isinstance(argument, basestring): | 
 |  303                 try: | 
 |  304                     attr = str(argument) | 
 |  305                 except Exception: | 
 |  306                     pass | 
 |  307                 else: | 
 |  308                     try: | 
 |  309                         value = getattr(obj, attr) | 
 |  310                     except AttributeError: | 
 |  311                         pass | 
 |  312                     else: | 
 |  313                         if self.is_safe_attribute(obj, argument, value): | 
 |  314                             return value | 
 |  315                         return self.unsafe_undefined(obj, argument) | 
 |  316         return self.undefined(obj=obj, name=argument) | 
 |  317  | 
 |  318     def getattr(self, obj, attribute): | 
 |  319         """Subscribe an object from sandboxed code and prefer the | 
 |  320         attribute.  The attribute passed *must* be a bytestring. | 
 |  321         """ | 
 |  322         try: | 
 |  323             value = getattr(obj, attribute) | 
 |  324         except AttributeError: | 
 |  325             try: | 
 |  326                 return obj[attribute] | 
 |  327             except (TypeError, LookupError): | 
 |  328                 pass | 
 |  329         else: | 
 |  330             if self.is_safe_attribute(obj, attribute, value): | 
 |  331                 return value | 
 |  332             return self.unsafe_undefined(obj, attribute) | 
 |  333         return self.undefined(obj=obj, name=attribute) | 
 |  334  | 
 |  335     def unsafe_undefined(self, obj, attribute): | 
 |  336         """Return an undefined object for unsafe attributes.""" | 
 |  337         return self.undefined('access to attribute %r of %r ' | 
 |  338                               'object is unsafe.' % ( | 
 |  339             attribute, | 
 |  340             obj.__class__.__name__ | 
 |  341         ), name=attribute, obj=obj, exc=SecurityError) | 
 |  342  | 
 |  343     def call(__self, __context, __obj, *args, **kwargs): | 
 |  344         """Call an object from sandboxed code.""" | 
 |  345         # the double prefixes are to avoid double keyword argument | 
 |  346         # errors when proxying the call. | 
 |  347         if not __self.is_safe_callable(__obj): | 
 |  348             raise SecurityError('%r is not safely callable' % (__obj,)) | 
 |  349         return __context.call(__obj, *args, **kwargs) | 
 |  350  | 
 |  351  | 
 |  352 class ImmutableSandboxedEnvironment(SandboxedEnvironment): | 
 |  353     """Works exactly like the regular `SandboxedEnvironment` but does not | 
 |  354     permit modifications on the builtin mutable objects `list`, `set`, and | 
 |  355     `dict` by using the :func:`modifies_known_mutable` function. | 
 |  356     """ | 
 |  357  | 
 |  358     def is_safe_attribute(self, obj, attr, value): | 
 |  359         if not SandboxedEnvironment.is_safe_attribute(self, obj, attr, value): | 
 |  360             return False | 
 |  361         return not modifies_known_mutable(obj, attr) | 
| OLD | NEW |