From c845c7f9e0bab4a5ee420a8cab272b4357aa9068 Mon Sep 17 00:00:00 2001 From: Nigel Ihza Firdausy <106657905+Ni-zav@users.noreply.github.com> Date: Sat, 10 Oct 2026 23:43:09 +0700 Subject: [PATCH 1/2] fix(crop): reject malformed crop rectangles without shifting coordinates --- crates/tools/src/cropimage.rs | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/crates/tools/src/cropimage.rs b/crates/tools/src/cropimage.rs index 467182a7..ac022f4f 100644 --- a/crates/tools/src/cropimage.rs +++ b/crates/tools/src/cropimage.rs @@ -232,9 +232,15 @@ impl Tool for CropImageTool { if key != "rect" { return; } - let n: Vec = value.as_array().map(|v| v.iter().filter_map(Value::as_f64).filter(|n| n.is_finite()).collect()).unwrap_or_default(); - self.rect = match n.as_slice() { - [x, y, w, h] => Some((None, Rect::new(*x, *y, x + w, y + h))), + // Invalid components must discard the whole box, not silently shift the + // coordinates by dropping a non-numeric entry. + let numbers = value + .as_array() + .filter(|a| a.len() == 4) + .and_then(|a| a.iter().map(Value::as_f64).collect::>>()) + .filter(|a| a.iter().all(|n| n.is_finite())); + self.rect = match numbers.as_deref() { + Some([x, y, w, h]) => Some((None, Rect::new(*x, *y, x + w, y + h))), _ => None, }; } @@ -336,6 +342,23 @@ mod tests { assert!(t.overlays(&cx).is_empty() && !t.claims_key(&cx, ToolKey::Enter)); } + + #[test] + fn crop_box_option_requires_exactly_four_finite_numeric_values() { + let mut tool = CropImageTool::default(); + for invalid in [ + json!([10, "ignored", 20, 30, 40]), + json!([10, 20, 30, null, 40]), + json!([10, 20, 30, 40, 50]), + json!("not a rectangle"), + ] { + tool.set_option("rect", &invalid); + assert!(tool.options().get("rect").is_none(), "invalid box should reset crop: {invalid}"); + } + tool.set_option("rect", &json!([10, 20, 30, 40])); + assert_eq!(tool.options()["rect"], json!([10.0, 20.0, 30.0, 40.0])); + } + #[test] fn the_tool_is_made_by_its_id() { assert_eq!(crate::create(ID).id(), ID); From 311d75fc9728ec3c1349bdcf9adc1b40506bb187 Mon Sep 17 00:00:00 2001 From: bflatastic Date: Sun, 11 Oct 2026 01:58:43 +0700 Subject: [PATCH 2/2] Review #988: rustfmt Co-Authored-By: Claude Opus 5.5 --- crates/tools/src/cropimage.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/crates/tools/src/cropimage.rs b/crates/tools/src/cropimage.rs index ac022f4f..c0711639 100644 --- a/crates/tools/src/cropimage.rs +++ b/crates/tools/src/cropimage.rs @@ -342,16 +342,10 @@ mod tests { assert!(t.overlays(&cx).is_empty() && !t.claims_key(&cx, ToolKey::Enter)); } - #[test] fn crop_box_option_requires_exactly_four_finite_numeric_values() { let mut tool = CropImageTool::default(); - for invalid in [ - json!([10, "ignored", 20, 30, 40]), - json!([10, 20, 30, null, 40]), - json!([10, 20, 30, 40, 50]), - json!("not a rectangle"), - ] { + for invalid in [json!([10, "ignored", 20, 30, 40]), json!([10, 20, 30, null, 40]), json!([10, 20, 30, 40, 50]), json!("not a rectangle")] { tool.set_option("rect", &invalid); assert!(tool.options().get("rect").is_none(), "invalid box should reset crop: {invalid}"); }