changeset 647:f4072789fd7d experimental-sandboxed

restricted is the new secure
author aronacher
date Wed, 26 Sep 2007 17:56:41 +0000
parents 3ab910e36ff7
children 4ad264337a50
files genshi/template/base.py genshi/template/directives.py genshi/template/eval.py genshi/template/interpolation.py genshi/template/loader.py genshi/template/markup.py genshi/template/text.py
diffstat 7 files changed, 45 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- a/genshi/template/base.py
+++ b/genshi/template/base.py
@@ -305,7 +305,7 @@
 
     def __init__(self, source, basedir=None, filename=None, loader=None,
                  encoding=None, lookup='strict', allow_exec=True,
-                 secure=False):
+                 restricted=False):
         """Initialize a template from either a string, a file-like object, or
         an already parsed markup stream.
         
@@ -324,9 +324,9 @@
                        default), "lenient", or a custom lookup class
         :param allow_exec: whether Python code blocks in templates should be
                            allowed
-        :param secure: whether genshi should evaluate the template in safe
+        :param restricted: whether genshi should evaluate the template in safe
                        mode. See the documentation on the sandbox features
-                       for more details. In secure mode allow_exec is
+                       for more details. In restricted mode allow_exec is
                        automatically disabled.
         
         :note: Changed in 0.5: Added the `allow_exec` argument
@@ -339,8 +339,8 @@
             self.filepath = filename
         self.loader = loader
         self.lookup = lookup
-        self.allow_exec = not secure and allow_exec
-        self.secure = secure
+        self.allow_exec = not restricted and allow_exec
+        self.restricted = restricted
 
         self.filters = [self._flatten, self._eval, self._exec]
         if loader:
--- a/genshi/template/directives.py
+++ b/genshi/template/directives.py
@@ -111,7 +111,7 @@
         try:
             return expr and Expression(expr, template.filepath, lineno,
                                        lookup=template.lookup,
-                                       secure=template.secure) or None
+                                       restricted=template.restricted) or None
         except SyntaxError, err:
             err.msg += ' in expression "%s" of "%s" directive' % (expr,
                                                                   cls.tagname)
--- a/genshi/template/eval.py
+++ b/genshi/template/eval.py
@@ -37,10 +37,10 @@
 
 class Code(object):
     """Abstract base class for the `Expression` and `Suite` classes."""
-    __slots__ = ['source', 'code', 'ast', 'secure', '_globals']
+    __slots__ = ['source', 'code', 'ast', 'restricted', '_globals']
 
     def __init__(self, source, filename=None, lineno=-1, lookup='strict',
-                 xform=None, secure=False):
+                 xform=None, restricted=False):
         """Create the code object, either from a string, or from an AST node.
         
         :param source: either a string containing the source code, or an AST
@@ -54,7 +54,7 @@
         :param xform: the AST transformer that should be applied to the code;
                       if `None`, the appropriate transformation is chosen
                       depending on the mode
-        :param secure: If security features should be enabled.
+        :param restricted: If security features should be enabled.
         """
         if isinstance(source, basestring):
             self.source = source
@@ -71,7 +71,7 @@
         self.ast = node
         self.code = _compile(node, self.source, mode=self.mode,
                              filename=filename, lineno=lineno, xform=xform,
-                             secure=secure)
+                             restricted=restricted)
         if lookup is None:
             lookup = LenientLookup
         elif isinstance(lookup, basestring):
@@ -79,9 +79,9 @@
                 'lenient':  LenientLookup,
                 'strict':   StrictLookup
             }[lookup]
-            if secure:
-                lookup = SecurityLookupWrapper(lookup)
-        self.secure = secure
+            if restricted:
+                lookup = RestrictedLookupWrapper(lookup)
+        self.restricted = restricted
         self._globals = lookup.globals()
 
     def __eq__(self, other):
@@ -374,7 +374,7 @@
     undefined = classmethod(undefined)
 
 
-class SecurityLookupWrapper(object):
+class RestrictedLookupWrapper(object):
     """
     Special class that wraps a lookup so that insecure accesses result
     in undefined.  Additionally the globals are secured.
@@ -448,11 +448,11 @@
     return parse(source, mode)
 
 def _compile(node, source=None, mode='eval', filename=None, lineno=-1,
-             xform=None, secure=False):
+             xform=None, restricted=False):
     if xform is None:
         xform = {'eval': ExpressionASTTransformer}.get(mode,
                                                        TemplateASTTransformer)
-    tree = xform(secure).visit(node)
+    tree = xform(restricted).visit(node)
     if isinstance(filename, unicode):
         # unicode file names not allowed for code objects
         filename = filename.encode('utf-8', 'replace')
@@ -487,14 +487,13 @@
 
 # XXX: if we weaken the rule for global name resultion so that leading
 # underscores are valid we have to add __import__ here.
-UNSAFE_NAMES = ['file', 'open', 'eval', 'locals', 'globals', 'vars',
+UNSAFE_NAMES = ['file', 'open', 'eval', 'locals', 'globals', 'vars', 'buffer',
                 'help', 'quit', 'exit', 'input', 'raw_input', 'setattr',
-                'getattr', 'delattr', 'reload', 'compile', 'type']
+                'getattr', 'delattr', 'reload', 'compile', 'type', 'intern']
 
-# XXX: provide a secure range function
 SECURE_BUILTINS = BUILTINS.copy()
 for _unsafe_name in UNSAFE_NAMES:
-    del SECURE_BUILTINS[_unsafe_name]
+    SECURE_BUILTINS.pop(_unsafe_name, None)
 del _unsafe_name
 SECURE_BUILTINS['range'] = safe_range
 
@@ -508,8 +507,8 @@
     altered or replaced in some way.
     """
 
-    def __init__(self, secure):
-        self.secure = secure
+    def __init__(self, restricted):
+        self.restricted = restricted
 
     def visit(self, node):
         if node is None:
@@ -744,8 +743,8 @@
     for code embedded in templates.
     """
 
-    def __init__(self, secure):
-        ASTTransformer.__init__(self, secure)
+    def __init__(self, restricted):
+        ASTTransformer.__init__(self, restricted)
         self.locals = [CONSTANTS]
 
     def visitConst(self, node):
--- a/genshi/template/interpolation.py
+++ b/genshi/template/interpolation.py
@@ -31,7 +31,7 @@
 PREFIX = '$'
 
 def interpolate(text, basedir=None, filename=None, lineno=-1, offset=0,
-                lookup='strict'):
+                lookup='strict', restricted=False):
     """Parse the given string and extract expressions.
     
     This function is a generator that yields `TEXT` events for literal strings,
@@ -73,7 +73,7 @@
             if chunk:
                 try:
                     expr = Expression(chunk.strip(), pos[0], pos[1],
-                                      lookup=lookup)
+                                      lookup=lookup, restricted=restricted)
                     yield EXPR, expr, tuple(pos)
                 except SyntaxError, err:
                     raise TemplateSyntaxError(err, filepath, pos[1],
--- a/genshi/template/loader.py
+++ b/genshi/template/loader.py
@@ -78,7 +78,7 @@
     def __init__(self, search_path=None, auto_reload=False,
                  default_encoding=None, max_cache_size=25, default_class=None,
                  variable_lookup='strict', allow_exec=True,
-                 secure=False, callback=None):
+                 restricted=False, callback=None):
         """Create the template laoder.
         
         :param search_path: a list of absolute path names that should be
@@ -96,7 +96,7 @@
                                 (the default), "lenient", or a custom lookup
                                 class
         :param allow_exec: whether to allow Python code blocks in templates
-        :param secure: use secure template evaluation
+        :param restricted: use restricted template evaluation
         :param callback: (optional) a callback function that is invoked after a
                          template was initialized by this loader; the function
                          is passed the template object as only argument. This
@@ -122,7 +122,7 @@
         self.default_class = default_class or MarkupTemplate
         self.variable_lookup = variable_lookup
         self.allow_exec = allow_exec
-        self.secure = secure
+        self.restricted = restricted
         if callback is not None and not callable(callback):
             raise TypeError('The "callback" parameter needs to be callable')
         self.callback = callback
@@ -217,7 +217,7 @@
                                    loader=self, encoding=encoding,
                                    lookup=self.variable_lookup,
                                    allow_exec=self.allow_exec,
-                                   secure=self.secure)
+                                   restricted=self.restricted)
                         if self.callback:
                             self.callback(tmpl)
                         self._cache[filename] = tmpl
--- a/genshi/template/markup.py
+++ b/genshi/template/markup.py
@@ -62,10 +62,10 @@
 
     def __init__(self, source, basedir=None, filename=None, loader=None,
                  encoding=None, lookup='strict', allow_exec=True,
-                 secure=False):
+                 restricted=False):
         Template.__init__(self, source, basedir=basedir, filename=filename,
                           loader=loader, encoding=encoding, lookup=lookup,
-                          allow_exec=allow_exec, secure=secure)
+                          allow_exec=allow_exec, restricted=restricted)
         # Make sure the include filter comes after the match filter
         if loader:
             self.filters.remove(self._include)
@@ -130,7 +130,8 @@
                         if value:
                             value = list(interpolate(value, self.basedir,
                                                      pos[0], pos[1], pos[2],
-                                                     lookup=self.lookup))
+                                                     lookup=self.lookup,
+                                                     restricted=self.restricted))
                             if len(value) == 1 and value[0][0] is TEXT:
                                 value = value[0][1]
                         else:
@@ -213,7 +214,8 @@
             elif kind is TEXT:
                 for kind, data, pos in interpolate(data, self.basedir, pos[0],
                                                    pos[1], pos[2],
-                                                   lookup=self.lookup):
+                                                   lookup=self.lookup,
+                                                   restricted=self.restricted):
                     stream.append((kind, data, pos))
 
             elif kind is COMMENT:
--- a/genshi/template/text.py
+++ b/genshi/template/text.py
@@ -131,11 +131,11 @@
 
     def __init__(self, source, basedir=None, filename=None, loader=None,
                  encoding=None, lookup='strict', allow_exec=False,
-                 secure=False, delims=('{%', '%}', '{#', '#}')):
+                 restricted=False, delims=('{%', '%}', '{#', '#}')):
         self.delimiters = delims
         Template.__init__(self, source, basedir=basedir, filename=filename,
                           loader=loader, encoding=encoding, lookup=lookup,
-                          secure=secure)
+                          restricted=restricted)
 
     def _get_delims(self):
         return self._delims
@@ -180,7 +180,8 @@
                 text = _escape_sub(_escape_repl, source[offset:start])
                 for kind, data, pos in interpolate(text, self.basedir,
                                                    self.filename, lineno,
-                                                   lookup=self.lookup):
+                                                   lookup=self.lookup,
+                                                   restricted=self.restricted):
                     stream.append((kind, data, pos))
                 lineno += len(text.splitlines())
 
@@ -226,7 +227,8 @@
             text = _escape_sub(_escape_repl, source[offset:])
             for kind, data, pos in interpolate(text, self.basedir,
                                                self.filename, lineno,
-                                               lookup=self.lookup):
+                                               lookup=self.lookup,
+                                               restricted=self.restricted):
                 stream.append((kind, data, pos))
 
         return stream
@@ -288,7 +290,8 @@
                 text = source[offset:start]
                 for kind, data, pos in interpolate(text, self.basedir,
                                                    self.filename, lineno,
-                                                   lookup=self.lookup):
+                                                   lookup=self.lookup,
+                                                   restricted=self.restricted):
                     stream.append((kind, data, pos))
                 lineno += len(text.splitlines())
 
@@ -324,7 +327,8 @@
             text = source[offset:].replace('\\#', '#')
             for kind, data, pos in interpolate(text, self.basedir,
                                                self.filename, lineno,
-                                               lookup=self.lookup):
+                                               lookup=self.lookup,
+                                               restricted=self.restricted):
                 stream.append((kind, data, pos))
 
         return stream
Copyright (C) 2012-2017 Edgewall Software