1414"""
1515import types
1616import operator
17+ from collections import Mapping
1718from jinja2 .environment import Environment
1819from jinja2 .exceptions import SecurityError
19- from jinja2 ._compat import string_types , PY2
20+ from jinja2 ._compat import string_types , text_type , PY2
21+ from jinja2 .utils import Markup
22+
23+ has_format = False
24+ if hasattr (text_type , 'format' ):
25+ from markupsafe import EscapeFormatter
26+ from string import Formatter
27+ has_format = True
2028
2129
2230#: maximum number of items a range may produce
3846#: unsafe generator attirbutes.
3947UNSAFE_GENERATOR_ATTRIBUTES = set (['gi_frame' , 'gi_code' ])
4048
49+ #: unsafe attributes on coroutines
50+ UNSAFE_COROUTINE_ATTRIBUTES = set (['cr_frame' , 'cr_code' ])
51+
52+ #: unsafe attributes on async generators
53+ UNSAFE_ASYNC_GENERATOR_ATTRIBUTES = set (['ag_code' , 'ag_frame' ])
54+
4155import warnings
4256
4357# make sure we don't warn in python 2.6 about stuff we don't care about
94108)
95109
96110
111+ class _MagicFormatMapping (Mapping ):
112+ """This class implements a dummy wrapper to fix a bug in the Python
113+ standard library for string formatting.
114+
115+ See http://bugs.python.org/issue13598 for information about why
116+ this is necessary.
117+ """
118+
119+ def __init__ (self , args , kwargs ):
120+ self ._args = args
121+ self ._kwargs = kwargs
122+ self ._last_index = 0
123+
124+ def __getitem__ (self , key ):
125+ if key == '' :
126+ idx = self ._last_index
127+ self ._last_index += 1
128+ try :
129+ return self ._args [idx ]
130+ except LookupError :
131+ pass
132+ key = str (idx )
133+ return self ._kwargs [key ]
134+
135+ def __iter__ (self ):
136+ return iter (self ._kwargs )
137+
138+ def __len__ (self ):
139+ return len (self ._kwargs )
140+
141+
142+ def inspect_format_method (callable ):
143+ if not has_format :
144+ return None
145+ if not isinstance (callable , (types .MethodType ,
146+ types .BuiltinMethodType )) or \
147+ callable .__name__ != 'format' :
148+ return None
149+ obj = callable .__self__
150+ if isinstance (obj , string_types ):
151+ return obj
152+
153+
97154def safe_range (* args ):
98155 """A range that can't generate ranges with a length of more than
99156 MAX_RANGE items.
@@ -145,6 +202,12 @@ def is_internal_attribute(obj, attr):
145202 elif isinstance (obj , types .GeneratorType ):
146203 if attr in UNSAFE_GENERATOR_ATTRIBUTES :
147204 return True
205+ elif hasattr (types , 'CoroutineType' ) and isinstance (obj , types .CoroutineType ):
206+ if attr in UNSAFE_COROUTINE_ATTRIBUTES :
207+ return True
208+ elif hasattr (types , 'AsyncGeneratorType' ) and isinstance (obj , types .AsyncGeneratorType ):
209+ if attri in UNSAFE_ASYNC_GENERATOR_ATTRIBUTES :
210+ return True
148211 return attr .startswith ('__' )
149212
150213
@@ -183,8 +246,8 @@ class SandboxedEnvironment(Environment):
183246 attributes or functions are safe to access.
184247
185248 If the template tries to access insecure code a :exc:`SecurityError` is
186- raised. However also other exceptions may occour during the rendering so
187- the caller has to ensure that all exceptions are catched .
249+ raised. However also other exceptions may occur during the rendering so
250+ the caller has to ensure that all exceptions are caught .
188251 """
189252 sandboxed = True
190253
@@ -346,8 +409,24 @@ def unsafe_undefined(self, obj, attribute):
346409 obj .__class__ .__name__
347410 ), name = attribute , obj = obj , exc = SecurityError )
348411
412+ def format_string (self , s , args , kwargs ):
413+ """If a format call is detected, then this is routed through this
414+ method so that our safety sandbox can be used for it.
415+ """
416+ if isinstance (s , Markup ):
417+ formatter = SandboxedEscapeFormatter (self , s .escape )
418+ else :
419+ formatter = SandboxedFormatter (self )
420+ kwargs = _MagicFormatMapping (args , kwargs )
421+ rv = formatter .vformat (s , args , kwargs )
422+ return type (s )(rv )
423+
349424 def call (__self , __context , __obj , * args , ** kwargs ):
350425 """Call an object from sandboxed code."""
426+ fmt = inspect_format_method (__obj )
427+ if fmt is not None :
428+ return __self .format_string (fmt , args , kwargs )
429+
351430 # the double prefixes are to avoid double keyword argument
352431 # errors when proxying the call.
353432 if not __self .is_safe_callable (__obj ):
@@ -365,3 +444,37 @@ def is_safe_attribute(self, obj, attr, value):
365444 if not SandboxedEnvironment .is_safe_attribute (self , obj , attr , value ):
366445 return False
367446 return not modifies_known_mutable (obj , attr )
447+
448+
449+ if has_format :
450+ # This really is not a public API apparenlty.
451+ try :
452+ from _string import formatter_field_name_split
453+ except ImportError :
454+ def formatter_field_name_split (field_name ):
455+ return field_name ._formatter_field_name_split ()
456+
457+ class SandboxedFormatterMixin (object ):
458+
459+ def __init__ (self , env ):
460+ self ._env = env
461+
462+ def get_field (self , field_name , args , kwargs ):
463+ first , rest = formatter_field_name_split (field_name )
464+ obj = self .get_value (first , args , kwargs )
465+ for is_attr , i in rest :
466+ if is_attr :
467+ obj = self ._env .getattr (obj , i )
468+ else :
469+ obj = self ._env .getitem (obj , i )
470+ return obj , first
471+
472+ class SandboxedFormatter (SandboxedFormatterMixin , Formatter ):
473+ def __init__ (self , env ):
474+ SandboxedFormatterMixin .__init__ (self , env )
475+ Formatter .__init__ (self )
476+
477+ class SandboxedEscapeFormatter (SandboxedFormatterMixin , EscapeFormatter ):
478+ def __init__ (self , env , escape ):
479+ SandboxedFormatterMixin .__init__ (self , env )
480+ EscapeFormatter .__init__ (self , escape )
0 commit comments