##// END OF EJS Templates
contents: double check that os_path is always within root...
Min RK -
Show More
@@ -96,8 +96,16 b' class FileManagerMixin(object):'
96 -------
96 -------
97 path : string
97 path : string
98 Native, absolute OS path to for a file.
98 Native, absolute OS path to for a file.
99
100 Raises
101 ------
102 404: if path is outside root
99 """
103 """
100 return to_os_path(path, self.root_dir)
104 root = os.path.abspath(self.root_dir)
105 os_path = to_os_path(path, root)
106 if not (os.path.abspath(os_path) + os.path.sep).startswith(root):
107 raise HTTPError(404, "%s is outside root contents directory" % path)
108 return os_path
101
109
102 def _read_notebook(self, os_path, as_version=4):
110 def _read_notebook(self, os_path, as_version=4):
103 """Read a notebook from an os path."""
111 """Read a notebook from an os path."""
@@ -373,10 +373,11 b' class FileContentsManager(FileManagerMixin, ContentsManager):'
373 if 'content' not in model and model['type'] != 'directory':
373 if 'content' not in model and model['type'] != 'directory':
374 raise web.HTTPError(400, u'No file content provided')
374 raise web.HTTPError(400, u'No file content provided')
375
375
376 self.run_pre_save_hook(model=model, path=path)
377
378 os_path = self._get_os_path(path)
376 os_path = self._get_os_path(path)
379 self.log.debug("Saving %s", os_path)
377 self.log.debug("Saving %s", os_path)
378
379 self.run_pre_save_hook(model=model, path=path)
380
380 try:
381 try:
381 if model['type'] == 'notebook':
382 if model['type'] == 'notebook':
382 nb = nbformat.from_dict(model['content'])
383 nb = nbformat.from_dict(model['content'])
@@ -5,6 +5,7 b' from __future__ import print_function'
5 import os
5 import os
6 import sys
6 import sys
7 import time
7 import time
8 from contextlib import contextmanager
8
9
9 from nose import SkipTest
10 from nose import SkipTest
10 from tornado.web import HTTPError
11 from tornado.web import HTTPError
@@ -164,7 +165,17 b' class TestContentsManager(TestCase):'
164
165
165 def tearDown(self):
166 def tearDown(self):
166 self._temp_dir.cleanup()
167 self._temp_dir.cleanup()
167
168
169 @contextmanager
170 def assertRaisesHTTPError(self, status, msg=None):
171 msg = msg or "Should have raised HTTPError(%i)" % status
172 try:
173 yield
174 except HTTPError as e:
175 self.assertEqual(e.status_code, status)
176 else:
177 self.fail(msg)
178
168 def make_dir(self, api_path):
179 def make_dir(self, api_path):
169 """make a subdirectory at api_path
180 """make a subdirectory at api_path
170
181
@@ -461,4 +472,29 b' class TestContentsManager(TestCase):'
461 cm.mark_trusted_cells(nb, path)
472 cm.mark_trusted_cells(nb, path)
462 cm.check_and_sign(nb, path)
473 cm.check_and_sign(nb, path)
463 assert cm.notary.check_signature(nb)
474 assert cm.notary.check_signature(nb)
475
476 def test_escape_root(self):
477 cm = self.contents_manager
478 # make foo, bar next to root
479 with open(os.path.join(cm.root_dir, '..', 'foo'), 'w') as f:
480 f.write('foo')
481 with open(os.path.join(cm.root_dir, '..', 'bar'), 'w') as f:
482 f.write('bar')
483
484 with self.assertRaisesHTTPError(404):
485 cm.get('..')
486 with self.assertRaisesHTTPError(404):
487 cm.get('foo/../../../bar')
488 with self.assertRaisesHTTPError(404):
489 cm.delete('../foo')
490 with self.assertRaisesHTTPError(404):
491 cm.rename('../foo', '../bar')
492 with self.assertRaisesHTTPError(404):
493 cm.save(model={
494 'type': 'file',
495 'content': u'',
496 'format': 'text',
497 }, path='../foo')
498
499
464
500
General Comments 0
You need to be logged in to leave comments. Login now