Ticket #4952: 4952.4.diff

File 4952.4.diff, 6.4 KB (added by Chris Beaven, 12 years ago)
  • django/template/loaders/app_directories.py

     
    1 # Wrapper for loading templates from "template" directories in installed app packages.
     1"""
     2Wrapper for loading templates from "template" directories in INSTALLED_APPS
     3packages.
     4"""
    25
     6import os
     7
    38from django.conf import settings
    49from django.core.exceptions import ImproperlyConfigured
    510from django.template import TemplateDoesNotExist
    6 import os
     11from django.utils._os import safe_join
    712
    813# At compile time, cache the directories to search.
    914app_template_dirs = []
     
    2833app_template_dirs = tuple(app_template_dirs)
    2934
    3035def get_template_sources(template_name, template_dirs=None):
    31     for template_dir in app_template_dirs:
    32         yield os.path.join(template_dir, template_name)
     36    if not template_dirs:
     37        template_dirs = app_template_dirs
     38    for template_dir in template_dirs:
     39        try:
     40            yield safe_join(template_dir, template_name)
     41        except ValueError:
     42            # The joined path was located outside of template_dir.
     43            pass
    3344
    3445def load_template_source(template_name, template_dirs=None):
    3546    for filepath in get_template_sources(template_name, template_dirs):
  • django/template/loaders/filesystem.py

     
    1 # Wrapper for loading templates from the filesystem.
     1"""
     2Wrapper for loading templates from the filesystem.
     3"""
    24
    35from django.conf import settings
    46from django.template import TemplateDoesNotExist
    5 import os
     7from django.utils._os import safe_join
    68
    79def get_template_sources(template_name, template_dirs=None):
    810    if not template_dirs:
    911        template_dirs = settings.TEMPLATE_DIRS
    1012    for template_dir in template_dirs:
    11         yield os.path.join(template_dir, template_name)
     13        try:
     14            yield safe_join(template_dir, template_name)
     15        except ValueError:
     16            # The joined path was located outside of template_dir.
     17            pass
    1218
    1319def load_template_source(template_name, template_dirs=None):
    1420    tried = []
  • django/utils/_os.py

     
     1from os.path import join, normcase, abspath, sep
     2
     3def safe_join(base, *paths):
     4    """
     5    Joins one or more path components to the base path component intelligently.
     6    Returns a normalized absolutized version of the final path.
     7
     8    The final path must be located inside of the base path component (otherwise
     9    a ValueError is raised).
     10    """
     11    # We need to use normcase to ensure we don't false-negative on case
     12    # insensitive operating systems (like Windows).
     13    final_path = normcase(abspath(join(base, *paths)))
     14    base_path = normcase(abspath(base))
     15    base_path_len = len(base_path)
     16    # Ensure final_path starts with base_path and that the next character after
     17    # the final path is os.sep (or nothing, in which case final_path must be
     18    # equal to base_path).
     19    if not final_path.startswith(base_path) or final_path[base_path_len:base_path_len+1] not in ('', sep):
     20        raise ValueError, 'the joined path is located outside of the base path component'
     21    return final_path
  • tests/regressiontests/templates/tests.py

     
    88
    99from django import template
    1010from django.template import loader
     11from django.template.loaders import app_directories, filesystem
    1112from django.utils.translation import activate, deactivate, install, ugettext as _
    1213from django.utils.tzinfo import LocalTimezone
    1314from datetime import datetime, timedelta
    1415from unicode import unicode_tests
    1516import unittest
     17import os
    1618
    1719# Some other tests we would like to run
    1820__test__ = {
     
    7577        return u'ŠĐĆŽćžšđ'.encode('utf-8')
    7678
    7779class Templates(unittest.TestCase):
     80    def test_loaders_security(self):
     81        def test_template_sources(path, template_dirs, expected_sources):
     82            # Fix expected sources so they are normcased and abspathed
     83            expected_sources = [os.path.normcase(os.path.abspath(s)) for s in expected_sources]
     84            # Test app_directories loader
     85            sources = app_directories.get_template_sources(path, template_dirs)
     86            self.assertEqual(list(sources), expected_sources)
     87            # Test filesystem loader
     88            sources = filesystem.get_template_sources(path, template_dirs)
     89            self.assertEqual(list(sources), expected_sources)
     90
     91        template_dirs = ['/dir1', '/dir2']
     92        test_template_sources('index.html', template_dirs,
     93                              ['/dir1/index.html', '/dir2/index.html'])
     94        test_template_sources('/etc/passwd', template_dirs,
     95                              [])
     96        test_template_sources('etc/passwd', template_dirs,
     97                              ['/dir1/etc/passwd', '/dir2/etc/passwd'])
     98        test_template_sources('../etc/passwd', template_dirs,
     99                              [])
     100        test_template_sources('../../../etc/passwd', template_dirs,
     101                              [])
     102        test_template_sources('/dir1/index.html', template_dirs,
     103                              ['/dir1/index.html'])
     104        test_template_sources('../dir2/index.html', template_dirs,
     105                              ['/dir2/index.html'])
     106
     107        # Case insensitive tests (for win32). Not run unless we're on
     108        # a case insensitive operating system.
     109        if os.path.normcase('/TEST') == os.path.normpath('/test'):
     110            template_dirs = ['/dir1', '/DIR2']
     111            test_template_sources('index.html', template_dirs,
     112                                  ['/dir1/index.html', '/dir2/index.html'])
     113            test_template_sources('/DIR1/index.HTML', template_dirs,
     114                                  ['/dir1/index.html'])
     115
    78116    def test_templates(self):
    79117        # NOW and NOW_tz are used by timesince tag tests.
    80118        NOW = datetime.now()
Back to Top