# HG changeset patch # User aronacher # Date 1190829401 0 # Node ID 5af131b37ab4950b6033383ed879f79b02ec0a62 # Parent b6cdfcb37496a46bb8d51eae0d60984590f4cf04 restricted is the new secure diff --git a/genshi/template/base.py b/genshi/template/base.py --- 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: diff --git a/genshi/template/directives.py b/genshi/template/directives.py --- 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) diff --git a/genshi/template/eval.py b/genshi/template/eval.py --- 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): diff --git a/genshi/template/interpolation.py b/genshi/template/interpolation.py --- 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], diff --git a/genshi/template/loader.py b/genshi/template/loader.py --- 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 diff --git a/genshi/template/markup.py b/genshi/template/markup.py --- 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: diff --git a/genshi/template/text.py b/genshi/template/text.py --- 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