Changeset 123:446c42e017fd

Show
Ignore:
Timestamp:
2007-08-02 19:17:43 (1 year ago)
Author:
Stefan Schwarzer <sschwarzer@sschwarzer.net>
branch:
default
Message:
Moved `is_safe_path` from `websourcebrowser.py` to `urlpath.py`.
Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • urlpath.py

    r109 r123  
    2424import urllib 
    2525import os 
     26import re 
    2627 
    2728 
     29# separator in URLs 
    2830sep = "/" 
    2931 
    3032class NotUnderRoot(Exception): 
    3133    pass 
     34 
     35def _normalize_path(path): 
     36    """ 
     37    Return the `path` in "normalized" form: 
     38    - change each sequence of path separators to a single path separator 
     39    - change path by evaluating "." and ".." occurences 
     40    - make path absolute 
     41    """ 
     42    if os.sep == "\\": 
     43        replacement = "\\\\" 
     44    else: 
     45        replacement = os.sep 
     46    path = re.sub("(?:%s)+" % re.escape(os.sep), replacement, path) 
     47    path = os.path.normcase(os.path.normpath(path)) 
     48    return os.path.abspath(path) 
     49 
     50def _is_file_system_root(path): 
     51    r""" 
     52    Return `True` if `path` is a file system root directory, else 
     53    `False`. 
     54 
     55    Under Posix, the file system root directory is "/", under 
     56    Windows, it's r"x:\", where x is any drive letter. 
     57    """ 
     58    path = _normalize_path(path) 
     59    drive, rest = os.path.splitdrive(path) 
     60    return rest == os.sep 
     61 
     62def is_safe_path(root, path): 
     63    """ 
     64    Return `True` if the `path` is a subdirectory of or a file 
     65    under the document root directory `root`, else return `False`. 
     66 
     67    >>> import urlpath 
     68    >>> urlpath.is_safe_path("/the/root", "/the/root/some_file") 
     69    True 
     70    >>> urlpath.is_safe_path("/the/root", "/somewhere/else/some_file") 
     71    False 
     72    """ 
     73    root = _normalize_path(root) 
     74    path = _normalize_path(path) 
     75    if root == path: 
     76        return True 
     77    if _is_file_system_root(root): 
     78        return path.startswith(root) 
     79    else: 
     80        return path.startswith(root + os.sep) 
    3281 
    3382def to_url(root, path): 
     
    4392    >>> urlpath.to_url("/the/root", "/the/root/some dir/some file") 
    4493    '/some%20dir/some%20file' 
    45  
    46     It also works on Windows: 
    47  
    48     >>> import os 
    49     >>> oldsep = os.sep; os.sep = "\\" 
    50     >>> urlpath.to_url(r"C:\the\root", r"C:\the\root\somedir\somefile") 
    51     '/somedir/somefile' 
    52     >>> os.sep = oldsep 
    5394 
    5495    Trailing path separators on the `root` or `path` don't matter: 
     
    92133    '/the/root/some dir/some file' 
    93134 
    94     It also works on Windows: 
    95  
    96     >>> import os 
    97     >>> oldsep = os.sep; os.sep = "\\" 
    98     >>> urlpath.to_file_system(r"C:\the\root", "/somedir/somefile") 
    99     'C:\\the\\root\\somedir\\somefile' 
    100     >>> os.sep = oldsep 
    101  
    102135    Trailing path separators on the `root` or `url` don't matter: 
    103136 
  • websourcebrowser.py

    r120 r123  
    6767    return css_path 
    6868 
    69 def is_safe_path(absolute_path): 
    70     """ 
    71     Return `True` if the `absolute_path` is a subdirectory of or a 
    72     file in the document root directory, else return `False`. 
    73     """ 
    74     if absolute_path.count(os.sep) == 1: 
    75         # file system root directory 
    76         # Attention: On Posix, we could now just return `True`, but on 
    77         #  Windows, we have a file system root directory _per drive letter_ 
    78         return absolute_path.startswith(config.root) 
    79     else: 
    80         return absolute_path.startswith(config.root + os.sep) 
    81  
    8269 
    8370class SourceBrowserHandler(BaseHTTPServer.BaseHTTPRequestHandler): 
     
    182169                source_path = urllib.unquote(source_path) 
    183170                source_path = os.path.join(config.root, source_path[1:]) 
    184                 if is_safe_path(source_path): 
     171                if urlpath.is_safe_path(config.root, source_path): 
    185172                    content_type = mimetypes.guess_type(source_path)[0] 
    186173                    if content_type is None: 
     
    192179            return 
    193180        path = urlpath.to_file_system(config.root, self.path) 
    194         if not is_safe_path(path): 
     181        if not urlpath.is_safe_path(config.root, path): 
    195182            # don't show items "above" the current directory; thereby 
    196183            #  avoiding information disclosure (double dot attack)