Creating and testing IPython.html.utils.is_hidden.

Brian E. Granger 12 years ago
parent 7e1a179a7c
commit 243392d810

@ -22,7 +22,6 @@ import json
import logging
import os
import re
import stat
import sys
import traceback
try:
@ -42,10 +41,7 @@ except ImportError:
from IPython.config import Application
from IPython.utils.path import filefind
from IPython.utils.py3compat import string_types
# UF_HIDDEN is a stat flag not defined in the stat module.
# It is used by BSD to indicate hidden files.
UF_HIDDEN = getattr(stat, 'UF_HIDDEN', 32768)
from IPython.html.utils import is_hidden
#-----------------------------------------------------------------------------
# Top-level handlers
@ -269,28 +265,9 @@ class AuthenticatedFileHandler(IPythonHandler, web.StaticFileHandler):
"""
abs_path = super(AuthenticatedFileHandler, self).validate_absolute_path(root, absolute_path)
abs_root = os.path.abspath(root)
self.forbid_hidden(abs_root, abs_path)
return abs_path
def forbid_hidden(self, absolute_root, absolute_path):
"""Raise 403 if a file is hidden or contained in a hidden directory.
Hidden is determined by either name starting with '.'
or the UF_HIDDEN flag as reported by stat
"""
inside_root = absolute_path[len(absolute_root):]
if any(part.startswith('.') for part in inside_root.split(os.sep)):
if is_hidden(abs_root, abs_path):
raise web.HTTPError(403)
# check UF_HIDDEN on any location up to root
path = absolute_path
while path and path.startswith(absolute_root) and path != absolute_root:
st = os.stat(path)
if getattr(st, 'st_flags', 0) & UF_HIDDEN:
raise web.HTTPError(403)
path = os.path.dirname(path)
return absolute_path
return abs_path
def json_errors(method):

@ -29,6 +29,7 @@ from .nbmanager import NotebookManager
from IPython.nbformat import current
from IPython.utils.traitlets import Unicode, Dict, Bool, TraitError
from IPython.utils import tz
from IPython.html.utils import is_hidden
#-----------------------------------------------------------------------------
# Classes
@ -108,7 +109,26 @@ class FileNotebookManager(NotebookManager):
path = path.strip('/')
os_path = self.get_os_path(path=path)
return os.path.isdir(os_path)
def is_hidden(self, path):
"""Does the API style path correspond to a hidden directory or file?
Parameters
----------
path : string
The path to check. This is an API path (`/` separated,
relative to base notebook-dir).
Returns
-------
exists : bool
Whether the path is hidden.
"""
path = path.strip('/')
os_path = self.get_os_path(path=path)
return is_hidden(self.notebook_dir, os_path)
def get_os_path(self, name=None, path=''):
"""Given a notebook name and a URL path, return its file system
path.
@ -159,13 +179,13 @@ class FileNotebookManager(NotebookManager):
"""List the directories for a given API style path."""
path = path.strip('/')
os_path = self.get_os_path('', path)
if not os.path.isdir(os_path):
raise web.HTTPError(404, u'diretory does not exist: %r' % os_path)
if not os.path.isdir(os_path) or is_hidden(self.notebook_dir, os_path):
raise web.HTTPError(404, u'directory does not exist: %r' % os_path)
dir_names = os.listdir(os_path)
dirs = []
for name in dir_names:
os_path = self.get_os_path(name, path)
if os.path.isdir(os_path) and not name.startswith('.'):
if os.path.isdir(os_path) and not is_hidden(self.notebook_dir, os_path):
try:
model = self.get_dir_model(name, path)
except IOError:

@ -82,7 +82,24 @@ class NotebookManager(LoggingConfigurable):
Whether the path does indeed exist.
"""
raise NotImplementedError
def is_hidden(self, path):
"""Does the API style path correspond to a hidden directory or file?
Parameters
----------
path : string
The path to check. This is an API path (`/` separated,
relative to base notebook-dir).
Returns
-------
exists : bool
Whether the path is hidden.
"""
raise NotImplementedError
def _notebook_dir_changed(self, name, old, new):
"""Do a bit of validation of the notebook dir."""
if not os.path.isabs(new):

@ -11,10 +11,13 @@
# Imports
#-----------------------------------------------------------------------------
import os
import nose.tools as nt
import IPython.testing.tools as tt
from IPython.html.utils import url_escape, url_unescape
from IPython.html.utils import url_escape, url_unescape, is_hidden
from IPython.utils.tempdir import TemporaryDirectory
#-----------------------------------------------------------------------------
# Test functions
@ -59,3 +62,14 @@ def test_url_unescape():
'/%20%21%40%24%23%25%5E%26%2A%20/%20test%20%25%5E%20notebook%20%40%23%24%20name.ipynb')
nt.assert_equal(path, '/ !@$#%^&* / test %^ notebook @#$ name.ipynb')
def test_is_hidden():
with TemporaryDirectory() as root:
subdir1 = os.path.join(root, 'subdir')
os.makedirs(subdir1)
nt.assert_equal(is_hidden(root, subdir1), False)
subdir2 = os.path.join(root, '.subdir2')
os.makedirs(subdir2)
nt.assert_equal(is_hidden(root, subdir2), True)
subdir34 = os.path.join(root, 'subdir3', '.subdir4')
os.makedirs(subdir34)
nt.assert_equal(is_hidden(root, subdir34), True)

@ -19,7 +19,7 @@ import os
from tornado import web
from ..base.handlers import IPythonHandler, notebook_path_regex, path_regex
from ..utils import url_path_join, path2url, url2path, url_escape
from ..utils import url_path_join, path2url, url2path, url_escape, is_hidden
#-----------------------------------------------------------------------------
# Handlers
@ -62,8 +62,8 @@ class TreeHandler(IPythonHandler):
self.log.debug("Redirecting %s to %s", self.request.path, url)
self.redirect(url)
else:
if not nbm.path_exists(path=path):
# no such directory, 404
if not nbm.path_exists(path=path) or nbm.is_hidden(path):
# Directory is hidden or does not exist.
raise web.HTTPError(404)
breadcrumbs = self.generate_breadcrumbs(path)
page_title = self.generate_page_title(path)

@ -12,7 +12,11 @@ Authors:
# the file COPYING, distributed as part of this software.
#-----------------------------------------------------------------------------
from __future__ import print_function
import os
import stat
try:
from urllib.parse import quote, unquote
except ImportError:
@ -20,6 +24,10 @@ except ImportError:
from IPython.utils import py3compat
# UF_HIDDEN is a stat flag not defined in the stat module.
# It is used by BSD to indicate hidden files.
UF_HIDDEN = getattr(stat, 'UF_HIDDEN', 32768)
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
@ -72,3 +80,28 @@ def url_unescape(path):
for p in py3compat.unicode_to_str(path).split('/')
])
def is_hidden(absolute_root, absolute_path):
"""Is a file is hidden or contained in a hidden directory.
Hidden is determined by either name starting with '.' or the UF_HIDDEN
flag as reported by stat.
Parameters
----------
absolute_root : unicode
absolute_path : unicode
"""
inside_root = absolute_path[len(absolute_root):]
if any(part.startswith('.') for part in inside_root.split(os.sep)):
return True
# check UF_HIDDEN on any location up to root
path = absolute_path
while path and path.startswith(absolute_root) and path != absolute_root:
st = os.stat(path)
if getattr(st, 'st_flags', 0) & UF_HIDDEN:
return True
path = os.path.dirname(path)
return False

Loading…
Cancel
Save