Mercurial > genshi > mirror
changeset 545:619340e2d805 trunk
Support for Python code blocks in templates can now be disabled. Closes #123.
author | cmlenz |
---|---|
date | Thu, 28 Jun 2007 23:00:24 +0000 |
parents | 82e37439c5f4 |
children | 2a3fc03b11de |
files | ChangeLog doc/plugin.txt doc/templates.txt genshi/template/base.py genshi/template/loader.py genshi/template/markup.py genshi/template/plugin.py genshi/template/tests/markup.py |
diffstat | 8 files changed, 71 insertions(+), 6 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog +++ b/ChangeLog @@ -11,6 +11,8 @@ understand. * Added support for the XPath 2 `matches()` function in XPath expressions, which allow matching against regular expressions. + * Support for Python code blocks in templates can now be disabled + (ticket #123). Version 0.4.3
--- a/doc/plugin.txt +++ b/doc/plugin.txt @@ -101,6 +101,14 @@ or may not be made available by your framework. TurboGears 1.0, for example, only passes a fixed set of options to all plugins. +``genshi.allow_exec`` +-------------------------- +Whether the Python code blocks should be permitted in templates. Specify "yes" +to allow code blocks (which is the default), or "no" otherwise. Please note +that disallowing code blocks in templates does not turn Genshi into a +sandboxable template engine; there are sufficient ways to do harm even using +plain expressions. + ``genshi.auto_reload`` ---------------------- Whether the template loader should check the last modification time of template
--- a/doc/templates.txt +++ b/doc/templates.txt @@ -240,6 +240,14 @@ design. If you're using many code blocks, that may be a sign that you should move such code into separate Python modules. +If you'd rather not allow the use of Python code blocks in templates, you can +simply set the ``allow_exec`` parameter (available on the ``Template`` and the +``TemplateLoader`` initializers) to ``False``. In that case Genshi will raise +a syntax error when a ``<?python ?>`` processing instruction is encountered. +But please note that disallowing code blocks in templates does not turn Genshi +into a sandboxable template engine; there are sufficient ways to do harm even +using plain expressions. + .. note:: Code blocks are not currently supported in text templates.
--- a/genshi/template/base.py +++ b/genshi/template/base.py @@ -288,7 +288,7 @@ """ def __init__(self, source, basedir=None, filename=None, loader=None, - encoding=None, lookup='lenient'): + encoding=None, lookup='lenient', allow_exec=True): """Initialize a template from either a string, a file-like object, or an already parsed markup stream. @@ -305,6 +305,10 @@ :param encoding: the encoding of the `source` :param lookup: the variable lookup mechanism; either "lenient" (the default), "strict", or a custom lookup class + :param allow_exec: whether Python code blocks in templates should be + allowed + + :note: Changed in 0.5: Added the `allow_exec` argument """ self.basedir = basedir self.filename = filename @@ -314,6 +318,7 @@ self.filepath = filename self.loader = loader self.lookup = lookup + self.allow_exec = allow_exec if isinstance(source, basestring): source = StringIO(source)
--- a/genshi/template/loader.py +++ b/genshi/template/loader.py @@ -73,7 +73,7 @@ """ def __init__(self, search_path=None, auto_reload=False, default_encoding=None, max_cache_size=25, default_class=None, - variable_lookup='lenient', callback=None): + variable_lookup='lenient', allow_exec=True, callback=None): """Create the template laoder. :param search_path: a list of absolute path names that should be @@ -90,12 +90,15 @@ :param variable_lookup: the variable lookup mechanism; either "lenient" (the default), "strict", or a custom lookup class + :param allow_exec: whether to allow Python code blocks in templates :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 callback can be used for example to add any desired filters to the template :see: `LenientLookup`, `StrictLookup` + + :note: Changed in 0.5: Added the `allow_exec` argument """ from genshi.template.markup import MarkupTemplate @@ -108,6 +111,7 @@ self.default_encoding = default_encoding self.default_class = default_class or MarkupTemplate self.variable_lookup = variable_lookup + self.allow_exec = allow_exec if callback is not None and not callable(callback): raise TypeError('The "callback" parameter needs to be callable') self.callback = callback @@ -199,8 +203,9 @@ filename = os.path.join(dirname, filename) dirname = '' tmpl = cls(fileobj, basedir=dirname, filename=filename, - loader=self, lookup=self.variable_lookup, - encoding=encoding) + loader=self, encoding=encoding, + lookup=self.variable_lookup, + allow_exec=self.allow_exec) if self.callback: self.callback(tmpl) self._cache[filename] = tmpl
--- a/genshi/template/markup.py +++ b/genshi/template/markup.py @@ -67,9 +67,10 @@ ('strip', StripDirective)] def __init__(self, source, basedir=None, filename=None, loader=None, - encoding=None, lookup='lenient'): + encoding=None, lookup='lenient', allow_exec=True): Template.__init__(self, source, basedir=basedir, filename=filename, - loader=loader, encoding=encoding, lookup=lookup) + loader=loader, encoding=encoding, lookup=lookup, + allow_exec=allow_exec) # Make sure the include filter comes after the match filter if loader: self.filters.remove(self._include) @@ -185,6 +186,9 @@ pos)] elif kind is PI and data[0] == 'python': + if not self.allow_exec: + raise TemplateSyntaxError('Python code blocks not allowed', + self.filepath, *pos[1:]) try: # As Expat doesn't report whitespace between the PI target # and the data, we have to jump through some hoops here to
--- a/genshi/template/plugin.py +++ b/genshi/template/plugin.py @@ -67,11 +67,18 @@ raise ConfigurationError('Unknown lookup errors mode "%s"' % lookup_errors) + try: + allow_exec = bool(options.get('genshi.allow_exec', True)) + except ValueError: + raise ConfigurationError('Invalid value for allow_exec "%s"' % + options.get('genshi.allow_exec')) + self.loader = TemplateLoader(filter(None, search_path), auto_reload=auto_reload, max_cache_size=max_cache_size, default_class=self.template_class, variable_lookup=lookup_errors, + allow_exec=allow_exec, callback=loader_callback) def load_template(self, templatename, template_string=None):
--- a/genshi/template/tests/markup.py +++ b/genshi/template/tests/markup.py @@ -449,6 +449,32 @@ finally: shutil.rmtree(dirname) + def test_allow_exec_false(self): + xml = ("""<?python + title = "A Genshi Template" + ?> + <html xmlns:py="http://genshi.edgewall.org/"> + <head> + <title py:content="title">This is replaced.</title> + </head> + </html>""") + try: + tmpl = MarkupTemplate(xml, filename='test.html', + allow_exec=False) + self.fail('Expected SyntaxError') + except TemplateSyntaxError, e: + pass + + def test_allow_exec_true(self): + xml = ("""<?python + title = "A Genshi Template" + ?> + <html xmlns:py="http://genshi.edgewall.org/"> + <head> + <title py:content="title">This is replaced.</title> + </head> + </html>""") + tmpl = MarkupTemplate(xml, filename='test.html', allow_exec=True) def suite(): suite = unittest.TestSuite()