Files
sanctum/src/pathutil.rs
T

78 lines
2.5 KiB
Rust

use anyhow::{bail, Result};
/// Prüft, ob ein Name Path-Traversal-Muster oder Pfadtrennzeichen enthält (S-02).
pub fn is_path_traversal(name: &str) -> bool {
name.is_empty()
|| name == "."
|| name == ".."
|| name.contains('/')
|| name.contains('\\')
|| name.contains('\0')
}
/// Validiert einen Datei- oder Verzeichnisnamen gegen Path-Traversal, Null-Bytes,
/// unzulässige Steuerzeichen und Windows-reservierte Gerätenamen (S-08, R-03).
pub fn validate_node_name(name: &str) -> Result<()> {
if name.is_empty() {
bail!("Dateiname darf nicht leer sein.");
}
if name == "." || name == ".." {
bail!(
"Ungültiger Dateiname (Verzeichnisreferenz verboten): '{}'",
name
);
}
if name.contains('/') || name.contains('\\') || name.contains('\0') {
bail!(
"Dateiname enthält unzulässige Trennzeichen oder Null-Bytes: '{}'",
name
);
}
for c in name.chars() {
if (c as u32) < 0x20 {
bail!("Dateiname enthält Steuerzeichen: '{}'", name);
}
}
// Windows reservierte Gerätenamen (CON, PRN, AUX, NUL, COM1..9, LPT1..9)
let base_name = if let Some(dot_idx) = name.find('.') {
&name[..dot_idx]
} else {
name
};
let base_upper = base_name.to_ascii_uppercase();
let reserved = [
"CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8",
"COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
];
if reserved.contains(&base_upper.as_str()) {
bail!(
"Dateiname '{}' kollidiert mit einem reservierten Windows-Gerätenamen.",
name
);
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_validate_node_name() {
assert!(validate_node_name("test.txt").is_ok());
assert!(validate_node_name("").is_err());
assert!(validate_node_name(".").is_err());
assert!(validate_node_name("..").is_err());
assert!(validate_node_name("foo/bar").is_err());
assert!(validate_node_name("foo\\bar").is_err());
assert!(validate_node_name("CON").is_err());
assert!(validate_node_name("aux.txt").is_err());
assert!(validate_node_name("nul").is_err());
assert!(validate_node_name("com1.log").is_err());
assert!(validate_node_name("line\nbreak").is_err());
assert!(validate_node_name("null\0byte").is_err());
}
}