fix(gradient): reject malformed freeform line index lists

This commit is contained in:
Nigel Ihza Firdausy 2026-10-11 04:50:49 +07:00 committed by bflatastic
parent 212fb9994a
commit f5111045a9
1 changed files with 40 additions and 3 deletions

View File

@ -148,9 +148,19 @@ pub(crate) fn parse_freeform(v: &Value) -> std::result::Result<Freeform, String>
point_fields(pv, &mut pt, Affine::IDENTITY).map_err(|e| format!("freeform point {i}: {e}"))?;
f.points.push(pt);
}
for l in v.get("lines").and_then(Value::as_array).into_iter().flatten() {
let ix = l.as_array().map(|a| a.iter().filter_map(Value::as_u64).map(|i| i as usize).collect()).unwrap_or_default();
f.add_line(ix)?;
if let Some(lines) = v.get("lines") {
let lines = lines.as_array().ok_or("`freeform.lines` must be an array")?;
for (line, values) in lines.iter().enumerate() {
let values = values.as_array().ok_or_else(|| format!("freeform line {line} must be an array of point indices"))?;
let indices: Vec<usize> = values
.iter()
.map(|v| {
let id = v.as_u64().ok_or_else(|| format!("freeform line {line} has a non-integer point index: {v}"))?;
usize::try_from(id).map_err(|_| format!("freeform line {line} has an out-of-range point index: {id}"))
})
.collect::<std::result::Result<_, _>>()?;
f.add_line(indices).map_err(|e| format!("freeform line {line}: {e}"))?;
}
}
if let Some(m) = str_param(v, "mode") {
f.mode = parse_mode(m)?;
@ -323,3 +333,30 @@ fn get(s: &mut Session, p: &Value) -> Result<Value> {
v["selected"] = json!(selected);
Ok(v)
}
#[cfg(test)]
mod parse_tests {
use super::*;
#[test]
fn malformed_freeform_lines_are_not_silently_shortened() {
let points = json!([
{"at": [0, 0], "color": "#ff0000"},
{"at": [50, 0], "color": "#00ff00"},
{"at": [100, 0], "color": "#0000ff"}
]);
for lines in [
json!([[0, "broken", 2]]),
json!([[0, -1, 2]]),
json!([[0, 1.5, 2]]),
json!([{"points": [0, 1]}]),
json!("not an array"),
] {
let value = json!({"points": points, "lines": lines, "mode": "lines"});
assert!(parse_freeform(&value).is_err(), "invalid lines accepted: {value}");
}
let good = parse_freeform(&json!({"points": points, "lines": [[0, 1, 2]], "mode": "lines"})).unwrap();
assert_eq!(good.lines, vec![vec![0, 1, 2]]);
}
}