use sanitize-filename crate to make filenames safe

Sanitizes filenames by removing or replacing potentially problematic characters
Makes filenames safe for cross-platform use
Prevents directory traversal attacks (e.g., "../../../")
This commit is contained in:
zuisong 2025-04-10 13:49:13 +08:00
parent a60a52453a
commit 31c515e403
No known key found for this signature in database
GPG Key ID: A617F31AFE6F5E8D
5 changed files with 21 additions and 4 deletions

10
Cargo.lock generated
View File

@ -1841,6 +1841,15 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "sanitize-filename"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc984f4f9ceb736a7bb755c3e3bd17dc56370af2600c9780dcc48c66453da34d"
dependencies = [
"regex",
]
[[package]]
name = "schannel"
version = "0.1.27"
@ -2823,6 +2832,7 @@ dependencies = [
"rpassword",
"rustls",
"ruzstd",
"sanitize-filename",
"serde",
"serde-transcode",
"serde_json",

View File

@ -61,6 +61,7 @@ rustls = { version = "0.23.25", optional = true, default-features = false, featu
tracing = { version = "0.1.41", default-features = false, features = ["log"] }
reqwest_cookie_store = { version = "0.8.0", features = ["serde"] }
percent-encoding = "2.3.1"
sanitize-filename = "0.6.0"
[dependencies.reqwest]
version = "0.12.3"

View File

@ -41,7 +41,7 @@ fn parse_regular_filename(part: &str) -> Option<String> {
// It's not a standard practice
// It rarely occurs in real-world scenarios
// When filenames contain special characters, they should use the filename* parameter
let filename = if filename.starts_with('"') && filename.ends_with('"') {
let filename = if filename.starts_with('"') && filename.ends_with('"') && filename.len() >= 2 {
&filename[1..(filename.len() - 1)]
} else {
filename

View File

@ -52,7 +52,7 @@ fn get_file_name(response: &Response, orig_url: &reqwest::Url) -> String {
.or_else(|| from_url(orig_url))
.unwrap_or_else(|| "index".to_string());
let filename = filename.split(std::path::is_separator).next_back().unwrap();
let filename = sanitize_filename::sanitize(&filename);
let mut filename = filename.trim().trim_start_matches('.').to_string();

View File

@ -229,7 +229,10 @@ fn download_filename_with_directory_traversal() {
.current_dir(&dir)
.assert()
.success();
assert_eq!(fs::read_to_string(dir.path().join("bar")).unwrap(), "file");
assert_eq!(
fs::read_to_string(dir.path().join("foobazbar")).unwrap(),
"file"
);
}
#[cfg(windows)]
@ -251,7 +254,10 @@ fn download_filename_with_windows_directory_traversal() {
.current_dir(&dir)
.assert()
.success();
assert_eq!(fs::read_to_string(dir.path().join("bar")).unwrap(), "file");
assert_eq!(
fs::read_to_string(dir.path().join("foobazbar")).unwrap(),
"file"
);
}
// TODO: test implicit download filenames