use super::*;
fn save_png(path: &Path, width: u32, height: u32) {
image::RgbaImage::from_pixel(width, height, image::Rgba([12, 34, 56, 255]))
.save(path)
.unwrap();
}
#[test]
fn local_preview_decodes_pixels_and_honors_configured_byte_limit() {
let directory = tempfile::tempdir().unwrap();
save_png(&directory.path().join("image.png"), 12, 8);
let image = read_local_preview_image(directory.path(), "image.png", false, 1024).unwrap();
assert_eq!((image.width(), image.height()), (12, 8));
assert_eq!(image.to_rgba8().get_pixel(0, 0).0, [12, 34, 56, 255]);
assert!(read_local_preview_image(directory.path(), "image.png", false, 1).is_err());
}
#[test]
fn local_preview_rejects_network_data_and_control_references_before_filesystem_access() {
for path in [
"https://host/image.png",
"http://host/image.png",
"data:image/png;base64,AA==",
"file:///tmp/image.png",
"//host/image.png",
"\\\\host\\image.png",
"image\x1b.png",
"",
] {
let error =
read_local_preview_image(Path::new("/nonexistent-preview-root"), path, true, 1024)
.unwrap_err();
assert_eq!(error.to_string(), "preview requires a local file path");
}
}
#[test]
fn local_preview_checks_absolute_policy_on_every_load() {
let directory = tempfile::tempdir().unwrap();
let outside = tempfile::tempdir().unwrap();
let path = outside.path().join("outside.png");
save_png(&path, 2, 2);
assert!(
read_local_preview_image(directory.path(), path.to_str().unwrap(), false, 1024).is_err()
);
assert!(read_local_preview_image(directory.path(), path.to_str().unwrap(), true, 1024).is_ok());
}
#[cfg(unix)]
#[test]
fn local_preview_rejects_relative_symlink_escape_even_when_absolute_access_is_allowed() {
let directory = tempfile::tempdir().unwrap();
let outside = tempfile::tempdir().unwrap();
save_png(&outside.path().join("outside.png"), 2, 2);
std::os::unix::fs::symlink(
outside.path().join("outside.png"),
directory.path().join("link.png"),
)
.unwrap();
assert!(read_local_preview_image(directory.path(), "link.png", true, 1024).is_err());
}
#[test]
fn local_preview_rejects_corrupt_disguised_and_oversized_images() {
let directory = tempfile::tempdir().unwrap();
save_png(&directory.path().join("wide.png"), 4097, 1);
assert!(read_local_preview_image(directory.path(), "wide.png", false, 8192).is_err());
fs::write(
directory.path().join("corrupt.png"),
b"\x89PNG\r\n\x1a\nnot a PNG",
)
.unwrap();
assert!(read_local_preview_image(directory.path(), "corrupt.png", false, 8192).is_err());
save_png(&directory.path().join("valid.png"), 2, 2);
fs::copy(
directory.path().join("valid.png"),
directory.path().join("disguised.jpg"),
)
.unwrap();
assert!(read_local_preview_image(directory.path(), "disguised.jpg", false, 8192).is_err());
assert!(read_local_preview_image(directory.path(), ".", false, 8192).is_err());
}
#[cfg(unix)]
#[test]
fn local_preview_rejects_fifo_without_waiting_for_writer() {
use std::os::unix::ffi::OsStrExt;
let directory = tempfile::tempdir().unwrap();
let fifo = directory.path().join("pipe.png");
let c_path = std::ffi::CString::new(fifo.as_os_str().as_bytes()).unwrap();
assert_eq!(unsafe { libc::mkfifo(c_path.as_ptr(), 0o600) }, 0);
assert!(read_local_preview_image(directory.path(), "pipe.png", false, 8192).is_err());
assert!(read_bounded_image_bytes(&fifo, 8192).is_err());
}