Skip to content

Commit

Permalink
added hidden checks on FileContentsManager and accompanying tests
Browse files Browse the repository at this point in the history
  • Loading branch information
rashley-iqt committed May 20, 2022
1 parent 2a76184 commit f69eb96
Show file tree
Hide file tree
Showing 2 changed files with 172 additions and 10 deletions.
39 changes: 29 additions & 10 deletions notebook/services/contents/filemanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,12 @@ def _base_model(self, path):
os_path = self._get_os_path(path)
info = os.lstat(os_path)

four_o_four = "file or directory does not exist: %r" % path

if is_hidden(os_path, self.root_dir) and not self.allow_hidden:
self.log.info("Refusing to serve hidden file or file in hidden directory %r, via 404 Error", os_path)
raise web.HTTPError(404, four_o_four)

try:
# size of file
size = info.st_size
Expand Down Expand Up @@ -364,12 +370,6 @@ def _file_model(self, path, content=True, format=None):

os_path = self._get_os_path(path)

four_o_four = "file does not exist: %r" % path

if is_hidden(os_path, self.root_dir) and not self.allow_hidden:
self.log.info("Refusing to serve hidden file or file in hidden directory %r, via 404 Error", os_path)
raise web.HTTPError(404, four_o_four)

model['mimetype'] = mimetypes.guess_type(os_path)[0]

if content:
Expand Down Expand Up @@ -430,11 +430,17 @@ def get(self, path, content=True, type=None, format=None):
of the file or directory as well.
"""
path = path.strip('/')
os_path = self._get_os_path(path)
four_o_four = "file or directory does not exist: %r" % path

if not self.exists(path):
raise web.HTTPError(404, f'No such file or directory: {path}')
raise web.HTTPError(404, four_o_four)

os_path = self._get_os_path(path)
if is_hidden(os_path, self.root_dir) and not self.allow_hidden:
self.log.info("Refusing to serve hidden file or file in hidden directory %r, via 404 Error", os_path)
raise web.HTTPError(404, four_o_four)


if os.path.isdir(os_path):
if type not in (None, 'directory'):
raise web.HTTPError(400,
Expand Down Expand Up @@ -472,6 +478,10 @@ def save(self, model, path=''):
raise web.HTTPError(400, 'No file content provided')

os_path = self._get_os_path(path)

if is_hidden(os_path, self.root_dir) and not self.allow_hidden:
raise web.HTTPError(400, f'Cannot create hidden file or directory {os_path!r}')

self.log.debug("Saving %s", os_path)

self.run_pre_save_hook(model=model, path=path)
Expand Down Expand Up @@ -515,8 +525,14 @@ def delete_file(self, path):
path = path.strip('/')
os_path = self._get_os_path(path)
rm = os.unlink
if not os.path.exists(os_path):
raise web.HTTPError(404, f'File or directory does not exist: {os_path}')

four_o_four = "file or directory does not exist: %r" % path

if not self.exists(path):
raise web.HTTPError(404, four_o_four)

if is_hidden(os_path, self.root_dir) and not self.allow_hidden:
raise web.HTTPError(400, f'Cannot delete hidden file or directory {os_path!r}')

def is_non_empty_dir(os_path):
if os.path.isdir(os_path):
Expand Down Expand Up @@ -559,6 +575,9 @@ def rename_file(self, old_path, new_path):
if new_path == old_path:
return

if (is_hidden(old_path, self.root_dir) or is_hidden(new_path, self.root_dir)) and not self.allow_hidden:
raise web.HTTPError(400, f'Cannot rename hidden file or directory {os_path!r}')

# Perform path validation prior to converting to os-specific value since this
# is still relative to root_dir.
self._validate_path(new_path)
Expand Down
143 changes: 143 additions & 0 deletions notebook/services/contents/tests/test_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,149 @@ def test_403(self):
else:
self.fail("Should have raised HTTPError(403)")

@skipIf(sys.platform.startswith('win'), "Can't test hidden files on Windows")
def test_400(self):
#Test Delete behavior
#Test delete of file in hidden directory
with self.assertRaises(HTTPError) as excinfo:
with TemporaryDirectory() as td:
cm = FileContentsManager(root_dir=td)
hidden_dir = '.hidden'
file_in_hidden_path = os.path.join(hidden_dir,'visible.txt')
_make_dir(cm, hidden_dir)
model = cm.new(path=file_in_hidden_path)
os_path = cm._get_os_path(model['path'])

try:
result = cm.delete_file(os_path)
except HTTPError as e:
self.assertEqual(e.status_code, 400)
else:
self.fail("Should have raised HTTPError(400)")
#Test delete hidden file in visible directory
with self.assertRaises(HTTPError) as excinfo:
with TemporaryDirectory() as td:
cm = FileContentsManager(root_dir=td)
hidden_dir = 'visible'
file_in_hidden_path = os.path.join(hidden_dir,'.hidden.txt')
_make_dir(cm, hidden_dir)
model = cm.new(path=file_in_hidden_path)
os_path = cm._get_os_path(model['path'])

try:
result = cm.delete_file(os_path)
except HTTPError as e:
self.assertEqual(e.status_code, 400)
else:
self.fail("Should have raised HTTPError(400)")

#Test Save behavior
#Test save of file in hidden directory
with self.assertRaises(HTTPError) as excinfo:
with TemporaryDirectory() as td:
cm = FileContentsManager(root_dir=td)
hidden_dir = '.hidden'
file_in_hidden_path = os.path.join(hidden_dir,'visible.txt')
_make_dir(cm, hidden_dir)
model = cm.new(path=file_in_hidden_path)
os_path = cm._get_os_path(model['path'])

try:
result = cm.save(model,path=os_path)
except HTTPError as e:
self.assertEqual(e.status_code, 400)
else:
self.fail("Should have raised HTTPError(400)")
#Test save hidden file in visible directory
with self.assertRaises(HTTPError) as excinfo:
with TemporaryDirectory() as td:
cm = FileContentsManager(root_dir=td)
hidden_dir = 'visible'
file_in_hidden_path = os.path.join(hidden_dir,'.hidden.txt')
_make_dir(cm, hidden_dir)
model = cm.new(path=file_in_hidden_path)
os_path = cm._get_os_path(model['path'])

try:
result = cm.save(model,path=os_path)
except HTTPError as e:
self.assertEqual(e.status_code, 400)
else:
self.fail("Should have raised HTTPError(400)")

#Test rename behavior
#Test rename with source file in hidden directory
with self.assertRaises(HTTPError) as excinfo:
with TemporaryDirectory() as td:
cm = FileContentsManager(root_dir=td)
hidden_dir = '.hidden'
file_in_hidden_path = os.path.join(hidden_dir,'visible.txt')
_make_dir(cm, hidden_dir)
model = cm.new(path=file_in_hidden_path)
old_path = cm._get_os_path(model['path'])
new_path = "new.txt"

try:
result = cm.rename_file(old_path, new_path)
except HTTPError as e:
self.assertEqual(e.status_code, 400)
else:
self.fail("Should have raised HTTPError(400)")

#Test rename of dest file in hidden directory
with self.assertRaises(HTTPError) as excinfo:
with TemporaryDirectory() as td:
cm = FileContentsManager(root_dir=td)
hidden_dir = '.hidden'
file_in_hidden_path = os.path.join(hidden_dir,'visible.txt')
_make_dir(cm, hidden_dir)
model = cm.new(path=file_in_hidden_path)
new_path = cm._get_os_path(model['path'])
old_path = "old.txt"

try:
result = cm.rename_file(old_path, new_path)
except HTTPError as e:
self.assertEqual(e.status_code, 400)
else:
self.fail("Should have raised HTTPError(400)")

#Test rename with hidden source file in visible directory
with self.assertRaises(HTTPError) as excinfo:
with TemporaryDirectory() as td:
cm = FileContentsManager(root_dir=td)
hidden_dir = 'visible'
file_in_hidden_path = os.path.join(hidden_dir,'.hidden.txt')
_make_dir(cm, hidden_dir)
model = cm.new(path=file_in_hidden_path)
old_path = cm._get_os_path(model['path'])
new_path = "new.txt"

try:
result = cm.rename_file(old_path, new_path)
except HTTPError as e:
self.assertEqual(e.status_code, 400)
else:
self.fail("Should have raised HTTPError(400)")

#Test rename with hidden dest file in visible directory
with self.assertRaises(HTTPError) as excinfo:
with TemporaryDirectory() as td:
cm = FileContentsManager(root_dir=td)
hidden_dir = 'visible'
file_in_hidden_path = os.path.join(hidden_dir,'.hidden.txt')
_make_dir(cm, hidden_dir)
model = cm.new(path=file_in_hidden_path)
new_path = cm._get_os_path(model['path'])
old_path = "old.txt"

try:
result = cm.rename_file(old_path, new_path)
except HTTPError as e:
self.assertEqual(e.status_code, 400)
else:
self.fail("Should have raised HTTPError(400)")

@skipIf(sys.platform.startswith('win'), "Can't test hidden files on Windows")
def test_404(self):
#Test visible file in hidden folder
Expand Down

0 comments on commit f69eb96

Please sign in to comment.