From 0a20b7047849459427987426881b032c661fc2c7 Mon Sep 17 00:00:00 2001 From: Matthias Blankertz Date: Tue, 27 Jan 2026 18:15:15 +0100 Subject: [PATCH 1/2] fix: frontend: Correctly escape filenames in URL parameters Signed-off-by: Matthias Blankertz --- software/frontend/index.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/software/frontend/index.html b/software/frontend/index.html index 43de408..4a56059 100644 --- a/software/frontend/index.html +++ b/software/frontend/index.html @@ -938,7 +938,7 @@ } } }; - xhr.open("POST", `/api/v1/audiofiles?type=file&location=${location}`); + xhr.open("POST", `/api/v1/audiofiles?type=file&location=${encodeURIComponent(location)}`); xhr.overrideMimeType("audio/mpeg"); xhr.send(files[0]); } @@ -956,7 +956,7 @@ const location = selectedNodes.length === 1 ? selectedNodes[0].getAttribute('data-path') + '/' + name.value : '/' + name.value; - const saveRes = await fetch(`/api/v1/audiofiles?type=directory&location=${location}`, + const saveRes = await fetch(`/api/v1/audiofiles?type=directory&location=${encodeURIComponent(location)}`, {method: 'POST'}); // Reload file list from device onShow('refresh'); @@ -973,7 +973,7 @@ items.sort(); items.reverse(); for (const item of items) { - const saveRes = await fetch(`/api/v1/audiofiles?location=${item}`, + const saveRes = await fetch(`/api/v1/audiofiles?location=${encodeURIComponent(item)}`, {method: 'DELETE'}); if (!saveRes.ok) { alert(`Failed to delete item ${item}: ${await saveRes.text()}`); From fa4d8debd01655ddb9f7256db579d3a51040cc22 Mon Sep 17 00:00:00 2001 From: Matthias Blankertz Date: Tue, 27 Jan 2026 19:11:47 +0100 Subject: [PATCH 2/2] fix: webserver: catch and report exceptions from open and mkdir, too Signed-off-by: Matthias Blankertz --- software/src/webserver.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/software/src/webserver.py b/software/src/webserver.py index 9118f8f..a495961 100644 --- a/software/src/webserver.py +++ b/software/src/webserver.py @@ -235,16 +235,19 @@ async def audiofile_upload(request): if type_ == 'directory': if length != 0: return 'directory request may not have content', 400 - os.mkdir(path) - return '', 204 - with open(path, 'wb') as newfile: try: + os.mkdir(path) + except OSError as ex: + return f'error creating directory: {ex}', 500 + return '', 204 + try: + with open(path, 'wb') as newfile: if length > Request.max_body_length: bytes_copied = await stream_to_file(request.stream, newfile, length) else: bytes_copied = newfile.write(request.body) - except OSError as ex: - return f'error writing data to file: {ex}', 500 + except OSError as ex: + return f'error writing data to file: {ex}', 500 if bytes_copied == length: return '', 204 else: