Fix 30 critical and high severity bugs from audit passes 6-8
Critical fixes: - Prevent path traversal via rename templates (sanitize_filename) - Prevent input == output data loss (paths_are_same check) - Undo now uses actual executor output paths instead of scanning directory - Filter empty paths from output_files (prevents trashing CWD on undo) - Sanitize URL download filenames to prevent path traversal writes High severity fixes: - Fix EXIF orientation 5/7 transforms per spec - Atomic file creation in find_unique_path (TOCTOU race) - Clean up 0-byte placeholder files on encoding failure - Cap canvas padding to 10000px, total dimensions to 65535 - Clamp crop dimensions to minimum 1px - Clamp DPI to 65535 before u16 cast in JPEG encoder - Force pixel path for non-JPEG/TIFF metadata stripping - Fast path now applies regex find/replace on rename stem - Add output_dpi to needs_pixel_processing check - Cap watermark image scale dimensions to 16384 - Cap template counter padding to 10 - Cap URL download size to 100MB - Fix progress bar NaN when total is zero - Fix calculate_eta underflow when current > total - Fix loaded.len()-1 underflow in preview callbacks - Replace ListItem downcast unwrap with if-let - Fix resize preview division by zero on degenerate images - Clamp rename cursor position to prevent overflow panic - Watch mode: skip output dirs to prevent infinite loop - Watch mode: drop tx sender so channel closes on exit - Watch mode: add delay for partially-written files - Watch mode: warn and skip unmatched files instead of wrong preset - Clean temp download directory on app close - Replace action downcast unwrap with checked if-let - Add BatchResult.output_files for accurate undo tracking
This commit is contained in:
@@ -883,20 +883,25 @@ fn download_image_url(url: &str) -> Option<std::path::PathBuf> {
|
||||
let temp_dir = std::env::temp_dir().join("pixstrip-downloads");
|
||||
std::fs::create_dir_all(&temp_dir).ok()?;
|
||||
|
||||
// Extract filename from URL
|
||||
// Extract and sanitize filename from URL to prevent path traversal
|
||||
let url_path = url.split('?').next().unwrap_or(url);
|
||||
let filename = url_path
|
||||
let raw_name = url_path
|
||||
.rsplit('/')
|
||||
.next()
|
||||
.unwrap_or("downloaded.jpg")
|
||||
.to_string();
|
||||
.unwrap_or("downloaded.jpg");
|
||||
let sanitized = std::path::Path::new(raw_name)
|
||||
.file_name()
|
||||
.and_then(|f| f.to_str())
|
||||
.unwrap_or("downloaded.jpg");
|
||||
let filename = if sanitized.is_empty() { "downloaded.jpg" } else { sanitized };
|
||||
|
||||
let dest = temp_dir.join(&filename);
|
||||
let dest = temp_dir.join(filename);
|
||||
|
||||
// Use GIO for the download (synchronous, runs in background thread)
|
||||
let gfile = gtk::gio::File::for_uri(url);
|
||||
let stream = gfile.read(gtk::gio::Cancellable::NONE).ok()?;
|
||||
|
||||
const MAX_DOWNLOAD_BYTES: usize = 100 * 1024 * 1024; // 100 MB
|
||||
let mut buf = Vec::new();
|
||||
loop {
|
||||
let bytes = stream.read_bytes(8192, gtk::gio::Cancellable::NONE).ok()?;
|
||||
@@ -904,6 +909,9 @@ fn download_image_url(url: &str) -> Option<std::path::PathBuf> {
|
||||
break;
|
||||
}
|
||||
buf.extend_from_slice(&bytes);
|
||||
if buf.len() > MAX_DOWNLOAD_BYTES {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
if buf.is_empty() {
|
||||
|
||||
Reference in New Issue
Block a user