pinakes-server: sanitize Content-Disposition filenames in dls

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Id8769e010ed634b9baf0e2c76905ad336a6a6964
This commit is contained in:
raf 2026-03-07 16:55:43 +03:00
commit b2b9adb0af
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF
2 changed files with 19 additions and 3 deletions

View file

@ -14,6 +14,22 @@ use crate::{
state::AppState,
};
/// Sanitize a filename for use in Content-Disposition headers.
/// Strips characters that could break header parsing or enable injection.
fn sanitize_content_disposition(filename: &str) -> String {
let safe: String = filename
.chars()
.map(|c| {
if c == '"' || c == '\\' || c == '\n' || c == '\r' {
'_'
} else {
c
}
})
.collect();
format!("attachment; filename=\"{safe}\"")
}
/// Upload a file to managed storage
/// POST /api/upload
pub async fn upload_file(
@ -105,7 +121,7 @@ pub async fn download_file(
(header::CONTENT_TYPE, content_type),
(
header::CONTENT_DISPOSITION,
format!("attachment; filename=\"{}\"", filename),
sanitize_content_disposition(&filename),
),
],
body,
@ -130,7 +146,7 @@ pub async fn download_file(
(header::CONTENT_TYPE, content_type),
(
header::CONTENT_DISPOSITION,
format!("attachment; filename=\"{}\"", filename),
sanitize_content_disposition(&filename),
),
],
body,

View file

@ -50,7 +50,7 @@ pub fn MarkdownViewer(
});
// Set up global wikilink click handler that the inline onclick attributes
// will call This bridges JavaScript Rust communication
// will call This bridges JavaScript -> Rust communication
use_effect(move || {
if let Some(handler) = on_wikilink_click {
spawn(async move {