diff --git a/xwiki-commons-core/xwiki-commons-velocity/src/main/java/org/xwiki/velocity/tools/EscapeTool.java b/xwiki-commons-core/xwiki-commons-velocity/src/main/java/org/xwiki/velocity/tools/EscapeTool.java index 60ffb3463f..3fe2f17098 100644 --- a/xwiki-commons-core/xwiki-commons-velocity/src/main/java/org/xwiki/velocity/tools/EscapeTool.java +++ b/xwiki-commons-core/xwiki-commons-velocity/src/main/java/org/xwiki/velocity/tools/EscapeTool.java @@ -30,6 +30,8 @@ import org.apache.commons.codec.net.QCodec; import org.apache.commons.codec.net.QuotedPrintableCodec; import org.apache.commons.text.StringEscapeUtils; +import org.apache.commons.text.translate.CharSequenceTranslator; +import org.apache.commons.text.translate.LookupTranslator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xwiki.xml.XMLUtils; @@ -66,6 +68,13 @@ public class EscapeTool extends org.apache.velocity.tools.generic.EscapeTool /** And sign. */ private static final String AND = "&"; + private static final CharSequenceTranslator XWIKI_ESCAPE_HTML4 = StringEscapeUtils.ESCAPE_HTML4.with( + new LookupTranslator(Map.ofEntries( + Map.entry("{", "{"), + Map.entry("}", "}") + )) + ); + /** * Change the default key defined in {@link org.apache.velocity.tools.generic.EscapeTool}. */ @@ -74,6 +83,24 @@ public EscapeTool() setKey(DEFAULT_KEY); } + /** + * Escapes the HTML special characters in a String using HTML entities. This overrides the base + * implementation from Velocity in order to also escape characters potentially harmful in the context of XWiki, + * such as curly brackets. + * + * @param content the string to escape, may be {@code null} + * @return a new escaped {@code String}, {@code null} if {@code null} input + */ + @Override + public String html(Object content) + { + if (content == null) + { + return null; + } + return XWIKI_ESCAPE_HTML4.translate(String.valueOf(content)); + } + /** * Escapes the XML special characters in a String using numerical XML entities. This overrides the base * implementation from Velocity, which is over-zealous and escapes any non-ASCII character. Since XWiki works with diff --git a/xwiki-commons-core/xwiki-commons-velocity/src/test/java/org/xwiki/velocity/tools/EscapeToolTest.java b/xwiki-commons-core/xwiki-commons-velocity/src/test/java/org/xwiki/velocity/tools/EscapeToolTest.java index 523cc78a5d..456ceb5e75 100644 --- a/xwiki-commons-core/xwiki-commons-velocity/src/test/java/org/xwiki/velocity/tools/EscapeToolTest.java +++ b/xwiki-commons-core/xwiki-commons-velocity/src/test/java/org/xwiki/velocity/tools/EscapeToolTest.java @@ -259,4 +259,12 @@ void velocity() { assertEquals("one${escapetool.h}${escapetool.h}two", this.tool.velocity("one##two")); } + + @Test + void html() + { + assertEquals("<script>alert("Hello, &lt;World&gt;!");</script>{{" + + "/html}}", + this.tool.html("{{/html}}")); + } }