From 67ae35b1553d4870a01c1d5f8c1f0d88f3f9acbd Mon Sep 17 00:00:00 2001 From: NetterSilver <133535268+Silvertree2010@users.noreply.github.com> Date: Thu, 22 Oct 2026 21:11:15 +0200 Subject: [PATCH] Match widget data check depth to serde_json's recursion limit Fixes #1118 Co-Authored-By: Claude Haiku 5.5 Co-Authored-By: Claude Sonnet 5.5 --- crates/engine/src/plugins.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/crates/engine/src/plugins.rs b/crates/engine/src/plugins.rs index be997079..49efe3d3 100644 --- a/crates/engine/src/plugins.rs +++ b/crates/engine/src/plugins.rs @@ -155,7 +155,8 @@ fn refusal(m: &Manifest, command: &str, params: &Value) -> Option { /// Whether `params` set layer data (`pluginData`, anywhere in them) under a widget's own keys. fn writes_widget_data(params: &Value, depth: usize) -> bool { let own = |data: &Value| data.as_object().is_some_and(|m| m.keys().any(|k| k.starts_with(crate::widgets::DATA_PREFIX))); - depth < 64 + // serde_json refuses nesting past 128, so nothing deeper can reach here. + depth < 128 && match params { Value::Object(m) => m.iter().any(|(k, v)| (k == "pluginData" && own(v)) || writes_widget_data(v, depth + 1)), Value::Array(a) => a.iter().any(|v| writes_widget_data(v, depth + 1)), @@ -592,3 +593,16 @@ pub fn specs() -> Vec { spec!("plugins.manage", "Manage plugins…", "{} opens the plugins window; returns the list like `plugin.list`", false, manage), ] } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn widget_data_is_found_at_any_depth_serde_accepts() { + let depth = 100; + let text = format!("{}{{\"pluginData\":{{\"{}x\":1}}}}{}", "{\"a\":".repeat(depth), crate::widgets::DATA_PREFIX, "}".repeat(depth)); + let v: Value = serde_json::from_str(&text).unwrap(); + assert!(writes_widget_data(&v, 0)); + } +}