Django

Code

Changeset 5750

Show
Ignore:
Timestamp:
07/22/07 23:45:01 (1 year ago)
Author:
gwilson
Message:

Fixed #4952 -- Fixed the get_template_sources functions of the app_directories and filesystem template loaders to not return paths outside of given template directories. Both functions now make use of a new safe_join utility function. Thanks to SmileyChris? for help with the patch.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/trunk/django/template/loaders/app_directories.py

    r5609 r5750  
    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""" 
     5 
     6import os 
    27 
    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. 
     
    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): 
  • django/trunk/django/template/loaders/filesystem.py

    r5609 r5750  
    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): 
     
    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): 
  • django/trunk/tests/regressiontests/templates/tests.py

    r5728 r5750  
    77    settings.configure() 
    88 
     9import os 
     10import unittest 
     11from datetime import datetime, timedelta 
     12 
    913from django import template 
    1014from django.template import loader 
     15from django.template.loaders import app_directories, filesystem 
    1116from django.utils.translation import activate, deactivate, install, ugettext as _ 
    1217from django.utils.tzinfo import LocalTimezone 
    13 from datetime import datetime, timedelta 
     18 
    1419from unicode import unicode_tests 
    15 import unittest 
    1620 
    1721# Some other tests we would like to run 
     
    7680 
    7781class Templates(unittest.TestCase): 
     82    def test_loaders_security(self): 
     83        def test_template_sources(path, template_dirs, expected_sources): 
     84            # Fix expected sources so they are normcased and abspathed 
     85            expected_sources = [os.path.normcase(os.path.abspath(s)) for s in expected_sources] 
     86            # Test app_directories loader 
     87            sources = app_directories.get_template_sources(path, template_dirs) 
     88            self.assertEqual(list(sources), expected_sources) 
     89            # Test filesystem loader 
     90            sources = filesystem.get_template_sources(path, template_dirs) 
     91            self.assertEqual(list(sources), expected_sources) 
     92 
     93        template_dirs = ['/dir1', '/dir2'] 
     94        test_template_sources('index.html', template_dirs, 
     95                              ['/dir1/index.html', '/dir2/index.html']) 
     96        test_template_sources('/etc/passwd', template_dirs, 
     97                              []) 
     98        test_template_sources('etc/passwd', template_dirs, 
     99                              ['/dir1/etc/passwd', '/dir2/etc/passwd']) 
     100        test_template_sources('../etc/passwd', template_dirs, 
     101                              []) 
     102        test_template_sources('../../../etc/passwd', template_dirs, 
     103                              []) 
     104        test_template_sources('/dir1/index.html', template_dirs, 
     105                              ['/dir1/index.html']) 
     106        test_template_sources('../dir2/index.html', template_dirs, 
     107                              ['/dir2/index.html']) 
     108        test_template_sources('/dir1blah', template_dirs, 
     109                              []) 
     110        test_template_sources('../dir1blah', template_dirs, 
     111                              []) 
     112 
     113        # Case insensitive tests (for win32). Not run unless we're on 
     114        # a case insensitive operating system. 
     115        if os.path.normcase('/TEST') == os.path.normpath('/test'): 
     116            template_dirs = ['/dir1', '/DIR2'] 
     117            test_template_sources('index.html', template_dirs, 
     118                                  ['/dir1/index.html', '/dir2/index.html']) 
     119            test_template_sources('/DIR1/index.HTML', template_dirs, 
     120                                  ['/dir1/index.html']) 
     121 
    78122    def test_templates(self): 
    79123        # NOW and NOW_tz are used by timesince tag tests.