Skip to content

Commit 996071c

Browse files
aidy1991fcollonval
andauthored
Show error message dialog when failed to extract an archive file (#101)
* Fix path traversal * Add unit test and minor refactoring * Update jupyter_archive/handlers.py Co-authored-by: Frédéric Collonval <[email protected]> * Use parametrize * Show error message dialog when failed to extract an archive file * Show detailed error message * Implement write_error() Co-authored-by: Frédéric Collonval <[email protected]>
1 parent 0311cf0 commit 996071c

File tree

2 files changed

+30
-3
lines changed

2 files changed

+30
-3
lines changed

jupyter_archive/handlers.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
import json
12
import os
23
import pathlib
34
import tarfile
45
import time
6+
import traceback
57
import zipfile
68
import threading
9+
from http.client import responses
710

811
from jupyter_server.base.handlers import JupyterHandler
912
from jupyter_server.utils import url2path, url_path_join
@@ -244,8 +247,9 @@ def extract_archive(self, archive_path):
244247
with archive_reader as archive:
245248
for name in archive_reader.getnames():
246249
if os.path.relpath(archive_destination / name, archive_destination).startswith(os.pardir):
247-
self.log.error(f"The archive file includes an unsafe file: {name}")
248-
raise web.HTTPError(400)
250+
error_message = f"The archive file includes an unsafe file path: {name}"
251+
self.log.error(error_message)
252+
raise web.HTTPError(400, reason=error_message)
249253
# Re-open stream
250254
archive_reader = make_reader(archive_path)
251255

@@ -254,6 +258,26 @@ def extract_archive(self, archive_path):
254258

255259
self.log.info("Finished extracting {} to {}.".format(archive_path, archive_destination))
256260

261+
def write_error(self, status_code, **kwargs):
262+
# Return error response as JSON
263+
# See https://github.com/pyenv/pyenv/blob/ff9d3ca69ef5006352cadc31e57f51aca42705a6/versions/3.8.12/lib/python3.8/site-packages/jupyter_server/base/handlers.py#L610
264+
self.set_header("Content-Type", "application/json")
265+
message = responses.get(status_code, "Unknown HTTP Error")
266+
reply = {
267+
"message": message,
268+
}
269+
exc_info = kwargs.get("exc_info")
270+
if exc_info:
271+
e = exc_info[1]
272+
if isinstance(e, web.HTTPError):
273+
reply["message"] = e.log_message or message
274+
reply["reason"] = e.reason
275+
else:
276+
reply["message"] = "Unhandled error"
277+
reply["reason"] = None
278+
reply["traceback"] = "".join(traceback.format_exception(*exc_info))
279+
self.finish(json.dumps(reply))
280+
257281

258282
def setup_handlers(web_app):
259283
host_pattern = ".*$"

src/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,10 @@ function extractArchiveRequest(path: string): Promise<void> {
107107

108108
return ServerConnection.makeRequest(url, request, settings).then(response => {
109109
if (response.status !== 200) {
110-
throw new ServerConnection.ResponseError(response);
110+
response.json().then(data => {
111+
showErrorMessage('Fail to extract the archive file', data.reason);
112+
throw new ServerConnection.ResponseError(response);
113+
});
111114
}
112115
});
113116
}

0 commit comments

Comments
 (0)