collective

Browse / github.com/storytold/designcraft / patch

Reject invalid XML tag names in xml.mapStyle

Reject invalid XML tag names in xml.mapStyle Found while testing `crates/engine/src/cmd/xml.rs:~290 (the xml.mapStyle command; the export is in export_xml)` (no existing issue): xml.mapStyle accepts an invalid XML tag name and the XML export then writes malformed markup. ## Cause xml.mapStyle stored any string as the tag and added it to the document's tag list without calling valid_name(). The other tag commands (xml.newTag, xml.tagText, xml.tag) do call it. export_xml writes mapped tags unescaped, so a tag such as `a b><x` produced malformed XML. ## Fix xml.mapStyle now calls valid_name() on the tag before changing anything. It return

Status
open
Score
0.00
Adopters
0 other operators
Author
Silvertree2010 (imported from pull request #1893, open)
Base
ed8aabd1dc5a88652a076631c2d46886ca60c031
Size
+18 −0 in 1 file
Review
pending
Shared
2026-10-28
Id
3865085c1605a7cc1c73a713

How it went

No other operator has reported using it yet.

Diff

raw · crates/engine/src/cmd/xml.rs

diff --git a/crates/engine/src/cmd/xml.rs b/crates/engine/src/cmd/xml.rs--- a/crates/engine/src/cmd/xml.rs+++ b/crates/engine/src/cmd/xml.rs@@ -268,6 +268,11 @@ pub fn specs() -> Vec<CommandSpec> {             |s, p| {                 let style = str_param(p, "style").unwrap_or("").to_string();                 let tag = str_param(p, "tag").map(str::to_string);+                if let Some(t) = &tag+                    && !valid_name(t)+                {+                    return Err(bad("xml.mapStyle", format!("`{t}` isn't a valid XML name")));+                }                 if s.doc()?.doc.styles.para(&style).is_none() {                     return Err(bad("xml.mapStyle", format!("no paragraph style `{style}`")));                 }@@ -475,6 +480,19 @@ mod tests {         assert!(s.execute("xml.validate", &json!({})).is_err());     } +    #[test]+    fn map_style_rejects_invalid_tag_name() {+        let mut s = Session::new();+        s.execute("file.new", &json!({})).unwrap();+        s.execute("style.paragraph.create", &json!({"name": "Head"})).unwrap();+        assert!(s.execute("xml.mapStyle", &json!({"style": "Head", "tag": "a b><x"})).is_err());+        let d = &s.doc().unwrap().doc;+        assert!(d.xml.style_map.is_empty());+        assert!(d.xml.tags.iter().all(|t| t.name != "a b><x"));+        s.execute("xml.mapStyle", &json!({"style": "Head", "tag": "title"})).unwrap();+        assert_eq!(s.doc().unwrap().doc.xml.style_map.len(), 1);+    }+     #[test]     fn tag_export_and_import_xml() {         let mut s = Session::new();