##// END OF EJS Templates
Creating and testing IPython.html.utils.is_hidden.
Brian E. Granger -
Show More
@@ -22,7 +22,6 b' import json'
22 import logging
22 import logging
23 import os
23 import os
24 import re
24 import re
25 import stat
26 import sys
25 import sys
27 import traceback
26 import traceback
28 try:
27 try:
@@ -42,10 +41,7 b' except ImportError:'
42 from IPython.config import Application
41 from IPython.config import Application
43 from IPython.utils.path import filefind
42 from IPython.utils.path import filefind
44 from IPython.utils.py3compat import string_types
43 from IPython.utils.py3compat import string_types
45
44 from IPython.html.utils import is_hidden
46 # UF_HIDDEN is a stat flag not defined in the stat module.
47 # It is used by BSD to indicate hidden files.
48 UF_HIDDEN = getattr(stat, 'UF_HIDDEN', 32768)
49
45
50 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
51 # Top-level handlers
47 # Top-level handlers
@@ -269,28 +265,9 b' class AuthenticatedFileHandler(IPythonHandler, web.StaticFileHandler):'
269 """
265 """
270 abs_path = super(AuthenticatedFileHandler, self).validate_absolute_path(root, absolute_path)
266 abs_path = super(AuthenticatedFileHandler, self).validate_absolute_path(root, absolute_path)
271 abs_root = os.path.abspath(root)
267 abs_root = os.path.abspath(root)
272 self.forbid_hidden(abs_root, abs_path)
268 if is_hidden(abs_root, abs_path):
273 return abs_path
274
275 def forbid_hidden(self, absolute_root, absolute_path):
276 """Raise 403 if a file is hidden or contained in a hidden directory.
277
278 Hidden is determined by either name starting with '.'
279 or the UF_HIDDEN flag as reported by stat
280 """
281 inside_root = absolute_path[len(absolute_root):]
282 if any(part.startswith('.') for part in inside_root.split(os.sep)):
283 raise web.HTTPError(403)
269 raise web.HTTPError(403)
284
270 return abs_path
285 # check UF_HIDDEN on any location up to root
286 path = absolute_path
287 while path and path.startswith(absolute_root) and path != absolute_root:
288 st = os.stat(path)
289 if getattr(st, 'st_flags', 0) & UF_HIDDEN:
290 raise web.HTTPError(403)
291 path = os.path.dirname(path)
292
293 return absolute_path
294
271
295
272
296 def json_errors(method):
273 def json_errors(method):
@@ -29,6 +29,7 b' from .nbmanager import NotebookManager'
29 from IPython.nbformat import current
29 from IPython.nbformat import current
30 from IPython.utils.traitlets import Unicode, Dict, Bool, TraitError
30 from IPython.utils.traitlets import Unicode, Dict, Bool, TraitError
31 from IPython.utils import tz
31 from IPython.utils import tz
32 from IPython.html.utils import is_hidden
32
33
33 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
34 # Classes
35 # Classes
@@ -108,7 +109,26 b' class FileNotebookManager(NotebookManager):'
108 path = path.strip('/')
109 path = path.strip('/')
109 os_path = self.get_os_path(path=path)
110 os_path = self.get_os_path(path=path)
110 return os.path.isdir(os_path)
111 return os.path.isdir(os_path)
111
112
113 def is_hidden(self, path):
114 """Does the API style path correspond to a hidden directory or file?
115
116 Parameters
117 ----------
118 path : string
119 The path to check. This is an API path (`/` separated,
120 relative to base notebook-dir).
121
122 Returns
123 -------
124 exists : bool
125 Whether the path is hidden.
126
127 """
128 path = path.strip('/')
129 os_path = self.get_os_path(path=path)
130 return is_hidden(self.notebook_dir, os_path)
131
112 def get_os_path(self, name=None, path=''):
132 def get_os_path(self, name=None, path=''):
113 """Given a notebook name and a URL path, return its file system
133 """Given a notebook name and a URL path, return its file system
114 path.
134 path.
@@ -159,13 +179,13 b' class FileNotebookManager(NotebookManager):'
159 """List the directories for a given API style path."""
179 """List the directories for a given API style path."""
160 path = path.strip('/')
180 path = path.strip('/')
161 os_path = self.get_os_path('', path)
181 os_path = self.get_os_path('', path)
162 if not os.path.isdir(os_path):
182 if not os.path.isdir(os_path) or is_hidden(self.notebook_dir, os_path):
163 raise web.HTTPError(404, u'diretory does not exist: %r' % os_path)
183 raise web.HTTPError(404, u'directory does not exist: %r' % os_path)
164 dir_names = os.listdir(os_path)
184 dir_names = os.listdir(os_path)
165 dirs = []
185 dirs = []
166 for name in dir_names:
186 for name in dir_names:
167 os_path = self.get_os_path(name, path)
187 os_path = self.get_os_path(name, path)
168 if os.path.isdir(os_path) and not name.startswith('.'):
188 if os.path.isdir(os_path) and not is_hidden(self.notebook_dir, os_path):
169 try:
189 try:
170 model = self.get_dir_model(name, path)
190 model = self.get_dir_model(name, path)
171 except IOError:
191 except IOError:
@@ -82,7 +82,24 b' class NotebookManager(LoggingConfigurable):'
82 Whether the path does indeed exist.
82 Whether the path does indeed exist.
83 """
83 """
84 raise NotImplementedError
84 raise NotImplementedError
85
85
86 def is_hidden(self, path):
87 """Does the API style path correspond to a hidden directory or file?
88
89 Parameters
90 ----------
91 path : string
92 The path to check. This is an API path (`/` separated,
93 relative to base notebook-dir).
94
95 Returns
96 -------
97 exists : bool
98 Whether the path is hidden.
99
100 """
101 raise NotImplementedError
102
86 def _notebook_dir_changed(self, name, old, new):
103 def _notebook_dir_changed(self, name, old, new):
87 """Do a bit of validation of the notebook dir."""
104 """Do a bit of validation of the notebook dir."""
88 if not os.path.isabs(new):
105 if not os.path.isabs(new):
@@ -11,10 +11,13 b''
11 # Imports
11 # Imports
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 import os
15
14 import nose.tools as nt
16 import nose.tools as nt
15
17
16 import IPython.testing.tools as tt
18 import IPython.testing.tools as tt
17 from IPython.html.utils import url_escape, url_unescape
19 from IPython.html.utils import url_escape, url_unescape, is_hidden
20 from IPython.utils.tempdir import TemporaryDirectory
18
21
19 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
20 # Test functions
23 # Test functions
@@ -59,3 +62,14 b' def test_url_unescape():'
59 '/%20%21%40%24%23%25%5E%26%2A%20/%20test%20%25%5E%20notebook%20%40%23%24%20name.ipynb')
62 '/%20%21%40%24%23%25%5E%26%2A%20/%20test%20%25%5E%20notebook%20%40%23%24%20name.ipynb')
60 nt.assert_equal(path, '/ !@$#%^&* / test %^ notebook @#$ name.ipynb')
63 nt.assert_equal(path, '/ !@$#%^&* / test %^ notebook @#$ name.ipynb')
61
64
65 def test_is_hidden():
66 with TemporaryDirectory() as root:
67 subdir1 = os.path.join(root, 'subdir')
68 os.makedirs(subdir1)
69 nt.assert_equal(is_hidden(root, subdir1), False)
70 subdir2 = os.path.join(root, '.subdir2')
71 os.makedirs(subdir2)
72 nt.assert_equal(is_hidden(root, subdir2), True)
73 subdir34 = os.path.join(root, 'subdir3', '.subdir4')
74 os.makedirs(subdir34)
75 nt.assert_equal(is_hidden(root, subdir34), True)
@@ -19,7 +19,7 b' import os'
19
19
20 from tornado import web
20 from tornado import web
21 from ..base.handlers import IPythonHandler, notebook_path_regex, path_regex
21 from ..base.handlers import IPythonHandler, notebook_path_regex, path_regex
22 from ..utils import url_path_join, path2url, url2path, url_escape
22 from ..utils import url_path_join, path2url, url2path, url_escape, is_hidden
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # Handlers
25 # Handlers
@@ -62,8 +62,8 b' class TreeHandler(IPythonHandler):'
62 self.log.debug("Redirecting %s to %s", self.request.path, url)
62 self.log.debug("Redirecting %s to %s", self.request.path, url)
63 self.redirect(url)
63 self.redirect(url)
64 else:
64 else:
65 if not nbm.path_exists(path=path):
65 if not nbm.path_exists(path=path) or nbm.is_hidden(path):
66 # no such directory, 404
66 # Directory is hidden or does not exist.
67 raise web.HTTPError(404)
67 raise web.HTTPError(404)
68 breadcrumbs = self.generate_breadcrumbs(path)
68 breadcrumbs = self.generate_breadcrumbs(path)
69 page_title = self.generate_page_title(path)
69 page_title = self.generate_page_title(path)
@@ -12,7 +12,11 b' Authors:'
12 # the file COPYING, distributed as part of this software.
12 # the file COPYING, distributed as part of this software.
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 from __future__ import print_function
16
15 import os
17 import os
18 import stat
19
16 try:
20 try:
17 from urllib.parse import quote, unquote
21 from urllib.parse import quote, unquote
18 except ImportError:
22 except ImportError:
@@ -20,6 +24,10 b' except ImportError:'
20
24
21 from IPython.utils import py3compat
25 from IPython.utils import py3compat
22
26
27 # UF_HIDDEN is a stat flag not defined in the stat module.
28 # It is used by BSD to indicate hidden files.
29 UF_HIDDEN = getattr(stat, 'UF_HIDDEN', 32768)
30
23 #-----------------------------------------------------------------------------
31 #-----------------------------------------------------------------------------
24 # Imports
32 # Imports
25 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
@@ -72,3 +80,28 b' def url_unescape(path):'
72 for p in py3compat.unicode_to_str(path).split('/')
80 for p in py3compat.unicode_to_str(path).split('/')
73 ])
81 ])
74
82
83 def is_hidden(absolute_root, absolute_path):
84 """Is a file is hidden or contained in a hidden directory.
85
86 Hidden is determined by either name starting with '.' or the UF_HIDDEN
87 flag as reported by stat.
88
89 Parameters
90 ----------
91 absolute_root : unicode
92 absolute_path : unicode
93 """
94 inside_root = absolute_path[len(absolute_root):]
95 if any(part.startswith('.') for part in inside_root.split(os.sep)):
96 return True
97
98 # check UF_HIDDEN on any location up to root
99 path = absolute_path
100 while path and path.startswith(absolute_root) and path != absolute_root:
101 st = os.stat(path)
102 if getattr(st, 'st_flags', 0) & UF_HIDDEN:
103 return True
104 path = os.path.dirname(path)
105
106 return False
107
General Comments 0
You need to be logged in to leave comments. Login now