Commits

Mike Bayer  committed b6d322b

- A Template is explicitly disallowed
from having a url that normalizes to relative outside
of the root. That is, if the Lookup is based
at /home/mytemplates, an include that would place
the ultimate template at
/home/mytemplates/../some_other_directory,
i.e. outside of /home/mytemplates,
is disallowed. This usage was never intended
despite the lack of an explicit check.
The main issue this causes
is that module files can be written outside
of the module root (or raise an error, if file perms aren't
set up), and can also lead to the same template being
cached in the lookup under multiple, relative roots.
TemplateLookup instead has always supported multiple
file roots for this purpose.
[ticket:174]

  • Participants
  • Parent commits d0b7f5d
  • Tags rel_0_5_0

Comments (0)

Files changed (7)

+0.5
+- A Template is explicitly disallowed
+  from having a url that normalizes to relative outside
+  of the root.   That is, if the Lookup is based 
+  at /home/mytemplates, an include that would place
+  the ultimate template at 
+  /home/mytemplates/../some_other_directory,
+  i.e. outside of /home/mytemplates,
+  is disallowed.   This usage was never intended
+  despite the lack of an explicit check.
+  The main issue this causes
+  is that module files can be written outside 
+  of the module root (or raise an error, if file perms aren't
+  set up), and can also lead to the same template being 
+  cached in the lookup under multiple, relative roots. 
+  TemplateLookup instead has always supported multiple 
+  file roots for this purpose.
+  [ticket:174]
+
 0.4.2
 - Fixed bug regarding <%call>/def calls w/ content
   whereby the identity of the "caller" callable

File mako/__init__.py

 # the MIT License: http://www.opensource.org/licenses/mit-license.php
 
 
-__version__ = '0.4.2'
+__version__ = '0.5.0'
 

File mako/lookup.py

         Note the "relativeto" argument is not supported here at the moment.
  
         """
- 
+
         try:
             if self.filesystem_checks:
                 return self._check(uri, self._collection[uri])

File mako/template.py

         else:
             self.module_id = "memory:" + hex(id(self))
             self.uri = self.module_id
- 
+
+        u_norm = self.uri
+        if u_norm.startswith("/"):
+            u_norm = u_norm[1:]
+        u_norm = os.path.normpath(u_norm)
+        if u_norm.startswith(".."):
+            raise exceptions.TemplateLookupException(
+                    "Template uri \"%s\" is invalid - "
+                    "it cannot be relative outside "
+                    "of the root path." % self.uri)
+
         self.input_encoding = input_encoding
         self.output_encoding = output_encoding
         self.encoding_errors = encoding_errors
             if module_filename is not None:
                 path = module_filename
             elif module_directory is not None:
-                u = self.uri
-                if u[0] == '/':
-                    u = u[1:]
                 path = os.path.abspath(
                         os.path.join(
                             os.path.normpath(module_directory), 
-                            os.path.normpath(u) + ".py"
+                            u_norm + ".py"
                             )
                         )
             else:
                 path = None
- 
             module = self._compile_from_file(path, filename)
         else:
             raise exceptions.RuntimeException(

File test/templates/othersubdir/foo.html

Empty file added.

File test/test_lookup.py

 from mako.template import Template
-from mako import lookup, exceptions
+from mako import lookup, exceptions, runtime
+from mako.util import FastEncodingBuffer
 from util import flatten_result, result_lines
 import unittest
+import os
 
-from test import TemplateTest, template_base, module_base
+from test import TemplateTest, template_base, module_base, assert_raises_message
 
 tl = lookup.TemplateLookup(directories=[template_base])
 class LookupTest(unittest.TestCase):
         )
         assert f.uri not in tl._collection
 
+    def test_dont_accept_relative_outside_of_root(self):
+        """test the mechanics of an include where 
+        the include goes outside of the path"""
+        tl = lookup.TemplateLookup(directories=[os.path.join(template_base, "subdir")])
+        index = tl.get_template("index.html")
+
+        ctx = runtime.Context(FastEncodingBuffer())
+        ctx._with_template=index
+
+        assert_raises_message(
+            exceptions.TemplateLookupException,
+           "Template uri \"../index.html\" is invalid - it "
+            "cannot be relative outside of the root path",
+            runtime._lookup_template, ctx, "../index.html", index.uri
+        )
+
+        assert_raises_message(
+            exceptions.TemplateLookupException,
+           "Template uri \"../othersubdir/foo.html\" is invalid - it "
+            "cannot be relative outside of the root path",
+            runtime._lookup_template, ctx, "../othersubdir/foo.html", index.uri
+        )
+
+        # this is OK since the .. cancels out
+        t = runtime._lookup_template(ctx, "foo/../index.html", index.uri)
+

File test/test_template.py

 from util import flatten_result, result_lines
 import codecs
 from test import TemplateTest, eq_, template_base, module_base, \
-    skip_if, assert_raises
+    skip_if, assert_raises, assert_raises_message
 
 class EncodingTest(TemplateTest):
     def test_unicode(self):
         finally:
             os.path = current_path
  
- 
- 
+    def test_dont_accept_relative_outside_of_root(self):
+        assert_raises_message(
+            exceptions.TemplateLookupException,
+            "Template uri \"../../foo.html\" is invalid - it "
+            "cannot be relative outside of the root path",
+            Template, "test", uri="../../foo.html", 
+        )
+
+        assert_raises_message(
+            exceptions.TemplateLookupException,
+            "Template uri \"/../../foo.html\" is invalid - it "
+            "cannot be relative outside of the root path",
+            Template, "test", uri="/../../foo.html", 
+        )
+
+        # normalizes in the root is OK
+        t = Template("test", uri="foo/bar/../../foo.html")
+        eq_(t.uri, "foo/bar/../../foo.html")
+
 class ModuleTemplateTest(TemplateTest):
     def test_module_roundtrip(self):
         lookup = TemplateLookup()