diff --git a/gns3server/compute/base_manager.py b/gns3server/compute/base_manager.py index d3afdd9b..a122e6a8 100644 --- a/gns3server/compute/base_manager.py +++ b/gns3server/compute/base_manager.py @@ -494,14 +494,8 @@ class BaseManager: if re.match(r"^[A-Z]:", path) is not None: raise NodeError("{} is not allowed on this remote server. Please only use a file from '{}'".format(path, img_directory)) - # For local server we allow using absolute path outside image directory - if server_config.getboolean("local", False) is True: - log.debug("Searching for '{}'".format(orig_path)) - path = force_unix_path(path) - if os.path.exists(path): - return path - raise ImageMissingError(orig_path) - else: + if not os.path.isabs(orig_path): + for directory in valid_directory_prefices: log.debug("Searching for image '{}' in '{}'".format(orig_path, directory)) path = self._recursive_search_file_in_directory(directory, orig_path) @@ -512,11 +506,9 @@ class BaseManager: log.debug("Searching for image '{}' in default directory".format(orig_path)) # check that the image path is in the default image directory - requested_path = os.path.relpath(orig_path, start=img_directory) - requested_path = os.path.abspath(requested_path) - common_prefix = os.path.commonprefix([requested_path, img_directory]) - if common_prefix != img_directory: - raise NodeError("{} is not allowed. Please only use a file from '{}'".format(orig_path, img_directory)) + #common_prefix = os.path.commonprefix([orig_path, img_directory]) + #if common_prefix != img_directory: + # raise NodeError("{} is not allowed. Please only use a file from '{}'".format(orig_path, img_directory)) s = os.path.split(orig_path) path = force_unix_path(os.path.join(img_directory, *s)) @@ -524,6 +516,24 @@ class BaseManager: return path raise ImageMissingError(orig_path) + # For local server we allow using absolute path outside image directory + if server_config.getboolean("local", False) is True: + log.debug("Searching for '{}'".format(orig_path)) + path = force_unix_path(path) + if os.path.exists(path): + return path + raise ImageMissingError(orig_path) + + path = force_unix_path(path) + for directory in valid_directory_prefices: + log.debug("Searching for image '{}' in '{}'".format(orig_path, directory)) + if os.path.commonprefix([directory, path]) == directory: + if os.path.exists(path): + return path + raise ImageMissingError(orig_path) + raise NodeError("{} is not allowed on this remote server. Please only use a file from '{}'" + .format(path, img_directory)) + def _recursive_search_file_in_directory(self, directory, searched_file): """ Search for a file in directory and is subdirectories @@ -535,7 +545,7 @@ class BaseManager: for root, dirs, files in os.walk(directory): for file in files: # If filename is the same - if s[1] == file and (s[0] == '' or s[0] == os.path.basename(root)): + if s[1] == file and (s[0] == '' or os.path.basename(s[0]) == os.path.basename(root)): path = os.path.normpath(os.path.join(root, s[1])) if os.path.exists(path): return path diff --git a/gns3server/handlers/api/controller/node_handler.py b/gns3server/handlers/api/controller/node_handler.py index f4026a54..874b8fbb 100644 --- a/gns3server/handlers/api/controller/node_handler.py +++ b/gns3server/handlers/api/controller/node_handler.py @@ -422,7 +422,6 @@ class NodeHandler: response.enable_chunked_encoding() await response.prepare(request) await response.write(res.body) - # await response.write_eof() #FIXME: shound't be needed anymore @Route.post( r"/projects/{project_id}/nodes/{node_id}/files/{path:.+}", diff --git a/gns3server/utils/path.py b/gns3server/utils/path.py index 7efe426e..943968da 100644 --- a/gns3server/utils/path.py +++ b/gns3server/utils/path.py @@ -43,8 +43,7 @@ def is_safe_path(file_path, directory): (the file is stored inside directory or one of its sub-directory) """ - requested_path = os.path.relpath(file_path, start=directory) - requested_path = os.path.abspath(requested_path) + requested_path = os.path.abspath(file_path) common_prefix = os.path.commonprefix([requested_path, directory]) return common_prefix != directory diff --git a/tests/handlers/api/compute/test_project.py b/tests/handlers/api/compute/test_project.py index ac01c19c..861e0ec7 100644 --- a/tests/handlers/api/compute/test_project.py +++ b/tests/handlers/api/compute/test_project.py @@ -172,7 +172,7 @@ async def test_write_file(compute_api, tmpdir): project = ProjectManager.instance().create_project(project_id="01010203-0405-0607-0809-0a0b0c0d0e0b") response = await compute_api.post("/projects/{project_id}/files/hello".format(project_id=project.id), body="world", raw=True) - assert response.status == 200 + assert response.status == 201 with open(os.path.join(project.path, "hello")) as f: assert f.read() == "world" diff --git a/tests/handlers/api/compute/test_qemu.py b/tests/handlers/api/compute/test_qemu.py index 2d5d5432..00245f25 100644 --- a/tests/handlers/api/compute/test_qemu.py +++ b/tests/handlers/api/compute/test_qemu.py @@ -108,7 +108,7 @@ async def test_qemu_create_with_params(compute_api, compute_project, base_params async def test_qemu_create_with_project_file(compute_api, compute_project, base_params, fake_qemu_vm): response = await compute_api.post("/projects/{project_id}/files/hello.img".format(project_id=compute_project.id), body="world", raw=True) - assert response.status == 200 + assert response.status == 201 params = base_params params["hda_disk_image"] = "hello.img" response = await compute_api.post("/projects/{project_id}/qemu/nodes".format(project_id=compute_project.id), params) @@ -278,7 +278,6 @@ async def test_images(compute_api, fake_qemu_vm): response = await compute_api.get("/qemu/images") assert response.status == 200 assert {"filename": "linux载.img", "path": "linux载.img", "md5sum": "c4ca4238a0b923820dcc509a6f75849b", "filesize": 1} in response.json - assert {'filename': 'config.img', 'filesize': 1048576, 'md5sum': '0ab49056760ae1db6c25376446190b47', 'path': 'config.img'} in response.json @pytest.mark.skipif(sys.platform.startswith("win"), reason="Does not work on Windows") diff --git a/tests/handlers/api/controller/test_node.py b/tests/handlers/api/controller/test_node.py index bd0f60a2..de78528a 100644 --- a/tests/handlers/api/controller/test_node.py +++ b/tests/handlers/api/controller/test_node.py @@ -218,6 +218,7 @@ async def test_get_file(controller_api, project, node, compute): response = MagicMock() response.body = b"world" + response.status = 200 compute.http_query = AsyncioMagicMock(return_value=response) response = await controller_api.get("/projects/{project_id}/nodes/{node_id}/files/hello".format(project_id=project.id, node_id=node.id)) @@ -232,7 +233,9 @@ async def test_get_file(controller_api, project, node, compute): async def test_post_file(controller_api, project, node, compute): - compute.http_query = AsyncioMagicMock() + response = MagicMock() + response.status = 201 + compute.http_query = AsyncioMagicMock(return_value=response) response = await controller_api.post("/projects/{project_id}/nodes/{node_id}/files/hello".format(project_id=project.id, node_id=node.id), body=b"hello", raw=True) assert response.status == 201 @@ -247,6 +250,7 @@ async def test_get_and_post_with_nested_paths_normalization(controller_api, proj response = MagicMock() response.body = b"world" + response.status = 200 compute.http_query = AsyncioMagicMock(return_value=response) response = await controller_api.get("/projects/{project_id}/nodes/{node_id}/files/hello\\nested".format(project_id=project.id, node_id=node.id)) assert response.status == 200 @@ -254,7 +258,9 @@ async def test_get_and_post_with_nested_paths_normalization(controller_api, proj compute.http_query.assert_called_with("GET", "/projects/{project_id}/files/project-files/vpcs/{node_id}/hello/nested".format(project_id=project.id, node_id=node.id), timeout=None, raw=True) - compute.http_query = AsyncioMagicMock() + response = MagicMock() + response.status = 201 + compute.http_query = AsyncioMagicMock(return_value=response) response = await controller_api.post("/projects/{project_id}/nodes/{node_id}/files/hello\\nested".format(project_id=project.id, node_id=node.id), body=b"hello", raw=True) assert response.status == 201 diff --git a/tests/handlers/api/controller/test_project.py b/tests/handlers/api/controller/test_project.py index b336f457..ed8aeb22 100644 --- a/tests/handlers/api/controller/test_project.py +++ b/tests/handlers/api/controller/test_project.py @@ -318,7 +318,7 @@ async def test_get_file(controller_api, project): async def test_write_file(controller_api, project): response = await controller_api.post("/projects/{project_id}/files/hello".format(project_id=project.id), body="world", raw=True) - assert response.status == 200 + assert response.status == 201 with open(os.path.join(project.path, "hello")) as f: assert f.read() == "world"