summaryrefslogtreecommitdiffstats
path: root/module/lib/jinja2/sandbox.py
diff options
context:
space:
mode:
Diffstat (limited to 'module/lib/jinja2/sandbox.py')
-rw-r--r--module/lib/jinja2/sandbox.py127
1 files changed, 112 insertions, 15 deletions
diff --git a/module/lib/jinja2/sandbox.py b/module/lib/jinja2/sandbox.py
index 749719548..da479c1ba 100644
--- a/module/lib/jinja2/sandbox.py
+++ b/module/lib/jinja2/sandbox.py
@@ -13,11 +13,10 @@
:license: BSD.
"""
import operator
-from jinja2.runtime import Undefined
from jinja2.environment import Environment
from jinja2.exceptions import SecurityError
-from jinja2.utils import FunctionType, MethodType, TracebackType, CodeType, \
- FrameType, GeneratorType
+from jinja2._compat import string_types, function_type, method_type, \
+ traceback_type, code_type, frame_type, generator_type, PY2
#: maximum number of items a range may produce
@@ -30,6 +29,13 @@ UNSAFE_FUNCTION_ATTRIBUTES = set(['func_closure', 'func_code', 'func_dict',
#: unsafe method attributes. function attributes are unsafe for methods too
UNSAFE_METHOD_ATTRIBUTES = set(['im_class', 'im_func', 'im_self'])
+#: unsafe generator attirbutes.
+UNSAFE_GENERATOR_ATTRIBUTES = set(['gi_frame', 'gi_code'])
+
+# On versions > python 2 the special attributes on functions are gone,
+# but they remain on methods and generators for whatever reason.
+if not PY2:
+ UNSAFE_FUNCTION_ATTRIBUTES = set()
import warnings
@@ -91,7 +97,7 @@ def safe_range(*args):
"""A range that can't generate ranges with a length of more than
MAX_RANGE items.
"""
- rng = xrange(*args)
+ rng = range(*args)
if len(rng) > MAX_RANGE:
raise OverflowError('range too big, maximum size for range is %d' %
MAX_RANGE)
@@ -99,8 +105,9 @@ def safe_range(*args):
def unsafe(f):
- """
- Mark a function or method as unsafe::
+ """Marks a function or method as unsafe.
+
+ ::
@unsafe
def delete(self):
@@ -114,7 +121,7 @@ def is_internal_attribute(obj, attr):
"""Test if the attribute given is an internal python attribute. For
example this function returns `True` for the `func_code` attribute of
python objects. This is useful if the environment method
- :meth:`~SandboxedEnvironment.is_safe_attribute` is overriden.
+ :meth:`~SandboxedEnvironment.is_safe_attribute` is overridden.
>>> from jinja2.sandbox import is_internal_attribute
>>> is_internal_attribute(lambda: None, "func_code")
@@ -124,20 +131,20 @@ def is_internal_attribute(obj, attr):
>>> is_internal_attribute(str, "upper")
False
"""
- if isinstance(obj, FunctionType):
+ if isinstance(obj, function_type):
if attr in UNSAFE_FUNCTION_ATTRIBUTES:
return True
- elif isinstance(obj, MethodType):
+ elif isinstance(obj, method_type):
if attr in UNSAFE_FUNCTION_ATTRIBUTES or \
attr in UNSAFE_METHOD_ATTRIBUTES:
return True
elif isinstance(obj, type):
if attr == 'mro':
return True
- elif isinstance(obj, (CodeType, TracebackType, FrameType)):
+ elif isinstance(obj, (code_type, traceback_type, frame_type)):
return True
- elif isinstance(obj, GeneratorType):
- if attr == 'gi_frame':
+ elif isinstance(obj, generator_type):
+ if attr in UNSAFE_GENERATOR_ATTRIBUTES:
return True
return attr.startswith('__')
@@ -182,9 +189,81 @@ class SandboxedEnvironment(Environment):
"""
sandboxed = True
+ #: default callback table for the binary operators. A copy of this is
+ #: available on each instance of a sandboxed environment as
+ #: :attr:`binop_table`
+ default_binop_table = {
+ '+': operator.add,
+ '-': operator.sub,
+ '*': operator.mul,
+ '/': operator.truediv,
+ '//': operator.floordiv,
+ '**': operator.pow,
+ '%': operator.mod
+ }
+
+ #: default callback table for the unary operators. A copy of this is
+ #: available on each instance of a sandboxed environment as
+ #: :attr:`unop_table`
+ default_unop_table = {
+ '+': operator.pos,
+ '-': operator.neg
+ }
+
+ #: a set of binary operators that should be intercepted. Each operator
+ #: that is added to this set (empty by default) is delegated to the
+ #: :meth:`call_binop` method that will perform the operator. The default
+ #: operator callback is specified by :attr:`binop_table`.
+ #:
+ #: The following binary operators are interceptable:
+ #: ``//``, ``%``, ``+``, ``*``, ``-``, ``/``, and ``**``
+ #:
+ #: The default operation form the operator table corresponds to the
+ #: builtin function. Intercepted calls are always slower than the native
+ #: operator call, so make sure only to intercept the ones you are
+ #: interested in.
+ #:
+ #: .. versionadded:: 2.6
+ intercepted_binops = frozenset()
+
+ #: a set of unary operators that should be intercepted. Each operator
+ #: that is added to this set (empty by default) is delegated to the
+ #: :meth:`call_unop` method that will perform the operator. The default
+ #: operator callback is specified by :attr:`unop_table`.
+ #:
+ #: The following unary operators are interceptable: ``+``, ``-``
+ #:
+ #: The default operation form the operator table corresponds to the
+ #: builtin function. Intercepted calls are always slower than the native
+ #: operator call, so make sure only to intercept the ones you are
+ #: interested in.
+ #:
+ #: .. versionadded:: 2.6
+ intercepted_unops = frozenset()
+
+ def intercept_unop(self, operator):
+ """Called during template compilation with the name of a unary
+ operator to check if it should be intercepted at runtime. If this
+ method returns `True`, :meth:`call_unop` is excuted for this unary
+ operator. The default implementation of :meth:`call_unop` will use
+ the :attr:`unop_table` dictionary to perform the operator with the
+ same logic as the builtin one.
+
+ The following unary operators are interceptable: ``+`` and ``-``
+
+ Intercepted calls are always slower than the native operator call,
+ so make sure only to intercept the ones you are interested in.
+
+ .. versionadded:: 2.6
+ """
+ return False
+
+
def __init__(self, *args, **kwargs):
Environment.__init__(self, *args, **kwargs)
self.globals['range'] = safe_range
+ self.binop_table = self.default_binop_table.copy()
+ self.unop_table = self.default_unop_table.copy()
def is_safe_attribute(self, obj, attr, value):
"""The sandboxed environment will call this method to check if the
@@ -201,18 +280,36 @@ class SandboxedEnvironment(Environment):
True. Override this method to alter the behavior, but this won't
affect the `unsafe` decorator from this module.
"""
- return not (getattr(obj, 'unsafe_callable', False) or \
+ return not (getattr(obj, 'unsafe_callable', False) or
getattr(obj, 'alters_data', False))
+ def call_binop(self, context, operator, left, right):
+ """For intercepted binary operator calls (:meth:`intercepted_binops`)
+ this function is executed instead of the builtin operator. This can
+ be used to fine tune the behavior of certain operators.
+
+ .. versionadded:: 2.6
+ """
+ return self.binop_table[operator](left, right)
+
+ def call_unop(self, context, operator, arg):
+ """For intercepted unary operator calls (:meth:`intercepted_unops`)
+ this function is executed instead of the builtin operator. This can
+ be used to fine tune the behavior of certain operators.
+
+ .. versionadded:: 2.6
+ """
+ return self.unop_table[operator](arg)
+
def getitem(self, obj, argument):
"""Subscribe an object from sandboxed code."""
try:
return obj[argument]
except (TypeError, LookupError):
- if isinstance(argument, basestring):
+ if isinstance(argument, string_types):
try:
attr = str(argument)
- except:
+ except Exception:
pass
else:
try: