Skip to content

Commit 876ca3e

Browse files
Zxun2fcollonval
andauthored
Deny git access to nested server root (#1278)
* Deny git access to nested server root * Clean up code * Shift code logic to server side * Remove redundant utility function * Restore unintended line deletion * Enable path parsing for windows and linux * Remove un-needed response attributes * Add test case * Replace test for new case * Add trailing slash Co-authored-by: Frédéric Collonval <fcollonval@users.noreply.github.com> * Fix testcase Co-authored-by: Frédéric Collonval <fcollonval@users.noreply.github.com> * Fix format --------- Co-authored-by: Frédéric Collonval <fcollonval@users.noreply.github.com> Co-authored-by: Frédéric Collonval <fcollonval@gmail.com>
1 parent 837bbf3 commit 876ca3e

File tree

4 files changed

+59
-5
lines changed

4 files changed

+59
-5
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,4 +135,7 @@ dmypy.json
135135
.vscode
136136

137137
# vim stuff
138-
*.swp
138+
*.swp
139+
140+
# virtual env
141+
venv/

jupyterlab_git/git.py

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -950,7 +950,7 @@ async def show_top_level(self, path):
950950
"message": my_error,
951951
}
952952

953-
async def show_prefix(self, path):
953+
async def show_prefix(self, path, contents_manager):
954954
"""
955955
Execute git --show-prefix command & return the result.
956956
"""
@@ -959,9 +959,28 @@ async def show_prefix(self, path):
959959
cmd,
960960
cwd=path,
961961
)
962+
962963
if code == 0:
963-
result = {"code": code, "path": my_output.strip("\n")}
964-
return result
964+
relative_git_path = my_output.strip("\n")
965+
repository_path = (
966+
path[: -len(relative_git_path)] if relative_git_path else path
967+
)
968+
try:
969+
# Raise an error is the repository_path is not a subpath of root_dir
970+
Path(repository_path).absolute().relative_to(
971+
Path(contents_manager.root_dir).absolute()
972+
)
973+
except ValueError:
974+
return {
975+
"code": code,
976+
"path": None,
977+
}
978+
else:
979+
result = {
980+
"code": code,
981+
"path": relative_git_path,
982+
}
983+
return result
965984
else:
966985
# Handle special case where cwd not inside a git repo
967986
lower_error = my_error.lower()

jupyterlab_git/handlers.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,8 @@ async def post(self, path: str = ""):
174174
POST request handler, displays the prefix path of a directory in a repository,
175175
with respect to the root directory.
176176
"""
177-
result = await self.git.show_prefix(self.url2localpath(path))
177+
local_path, cm = self.url2localpath(path, with_contents_manager=True)
178+
result = await self.git.show_prefix(local_path, cm)
178179

179180
if result["code"] != 0:
180181
self.set_status(500)

jupyterlab_git/tests/test_handlers.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
from .testutils import assert_http_error, maybe_future
1111
from tornado.httpclient import HTTPClientError
1212

13+
from pathlib import Path
14+
1315

1416
def test_mapping_added():
1517
mock_web_app = Mock()
@@ -112,6 +114,35 @@ async def test_git_show_prefix(mock_execute, jp_fetch, jp_root_dir):
112114
)
113115

114116

117+
@patch("jupyterlab_git.git.execute")
118+
async def test_git_show_prefix_nested_directory(mock_execute, jp_fetch, jp_root_dir):
119+
mock_execute.return_value = maybe_future((0, f"{jp_root_dir.name}/", ""))
120+
# When
121+
response = await jp_fetch(
122+
NAMESPACE,
123+
"show_prefix",
124+
body="{}",
125+
method="POST",
126+
)
127+
# Then
128+
assert response.code == 200
129+
payload = json.loads(response.body)
130+
assert payload["path"] is None
131+
mock_execute.assert_has_calls(
132+
[
133+
call(
134+
["git", "rev-parse", "--show-prefix"],
135+
cwd=str(jp_root_dir) + "/",
136+
timeout=20,
137+
env=None,
138+
username=None,
139+
password=None,
140+
is_binary=False,
141+
),
142+
]
143+
)
144+
145+
115146
async def test_git_show_prefix_for_excluded_path(
116147
jp_fetch, jp_server_config, jp_root_dir
117148
):

0 commit comments

Comments
 (0)