From ec18f3ab4e9463749cfe43c29d481a6a7bb5a3cc Mon Sep 17 00:00:00 2001 From: Manuel Leduc Date: Thu, 18 Jan 2024 11:15:00 +0100 Subject: [PATCH] XWIKI-21810: Improve suggest URL escaping in StringClass --- .../xwiki/objects/classes/StringClass.java | 56 +++++++++---- .../objects/classes/StringClassTest.java | 81 +++++++++++++++++++ 2 files changed, 120 insertions(+), 17 deletions(-) create mode 100644 xwiki-platform-core/xwiki-platform-oldcore/src/test/java/com/xpn/xwiki/objects/classes/StringClassTest.java diff --git a/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/objects/classes/StringClass.java b/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/objects/classes/StringClass.java index adbece77ccb9..6b670225a02d 100644 --- a/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/objects/classes/StringClass.java +++ b/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/objects/classes/StringClass.java @@ -19,7 +19,11 @@ */ package com.xpn.xwiki.objects.classes; +import java.util.LinkedHashMap; +import java.util.Map; + import org.apache.ecs.xhtml.input; +import org.xwiki.velocity.tools.EscapeTool; import org.xwiki.xml.XMLUtils; import com.xpn.xwiki.XWiki; @@ -30,6 +34,8 @@ import com.xpn.xwiki.objects.StringProperty; import com.xpn.xwiki.objects.meta.PropertyMetaClass; +import static org.apache.commons.lang.StringEscapeUtils.escapeJavaScript; + public class StringClass extends PropertyClass { private static final long serialVersionUID = 1L; @@ -89,7 +95,8 @@ public BaseProperty newProperty() } @Override - public void displayEdit(StringBuffer buffer, String name, String prefix, BaseCollection object, XWikiContext context) + public void displayEdit(StringBuffer buffer, String name, String prefix, BaseCollection object, + XWikiContext context) { input input = new input(); input.setAttributeFilter(new XMLAttributeValueFilter()); @@ -105,23 +112,9 @@ public void displayEdit(StringBuffer buffer, String name, String prefix, BaseCol input.setDisabled(isDisabled()); if (isPicker()) { - input.setClass("suggested"); - String path = ""; - XWiki xwiki = context.getWiki(); - path = xwiki.getURL("Main.WebHome", "view", context); - - String classname = this.getObject().getName(); - String fieldname = this.getName(); - String secondCol = "-", firstCol = "-"; - - String script = - "\"" + path + "?xpage=suggest&classname=" + classname + "&fieldname=" + fieldname + "&firCol=" - + firstCol + "&secCol=" + secondCol + "&\""; - String varname = "\"input\""; - input.setOnFocus("new ajaxSuggest(this, {script:" + script + ", varname:" + varname + "} )"); + displayPickerEdit(input); } - - buffer.append(input.toString()); + buffer.append(input); } @Override @@ -133,4 +126,33 @@ public void displayView(StringBuffer buffer, String name, String prefix, BaseCol buffer.append(XMLUtils.escapeElementText(property.toText())); } } + + private void displayPickerEdit(input input) + { + input.setClass("suggested"); + XWikiContext xWikiContext = getXWikiContext(); + XWiki xwiki = xWikiContext.getWiki(); + String path = xwiki.getURL("Main.WebHome", "view", xWikiContext); + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append(path); + stringBuilder.append('?'); + stringBuilder.append(new EscapeTool().url(getParametersMap())); + stringBuilder.append('&'); + input.setOnFocus(String.format("new ajaxSuggest(this, {script:\"%s\", varname:\"input\"} )", + escapeJavaScript(stringBuilder.toString()))); + } + + private Map getParametersMap() + { + String dash = "-"; + // Using a linked hash map to keep the order of the keys stable when generating the query parameters, which + // is especially handy for testing, but could be useful in other scenarios. + Map parameters = new LinkedHashMap<>(); + parameters.put("xpage", "suggest"); + parameters.put("classname", getObject().getName()); + parameters.put("fieldname", getName()); + parameters.put("firCol", dash); + parameters.put("secCol", dash); + return parameters; + } } diff --git a/xwiki-platform-core/xwiki-platform-oldcore/src/test/java/com/xpn/xwiki/objects/classes/StringClassTest.java b/xwiki-platform-core/xwiki-platform-oldcore/src/test/java/com/xpn/xwiki/objects/classes/StringClassTest.java new file mode 100644 index 000000000000..7a564f4c214a --- /dev/null +++ b/xwiki-platform-core/xwiki-platform-oldcore/src/test/java/com/xpn/xwiki/objects/classes/StringClassTest.java @@ -0,0 +1,81 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package com.xpn.xwiki.objects.classes; + +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.xwiki.model.reference.DocumentReference; + +import com.xpn.xwiki.XWikiContext; +import com.xpn.xwiki.test.MockitoOldcore; +import com.xpn.xwiki.test.component.XWikiDocumentFilterUtilsComponentList; +import com.xpn.xwiki.test.junit5.mockito.InjectMockitoOldcore; +import com.xpn.xwiki.test.junit5.mockito.OldcoreTest; +import com.xpn.xwiki.web.XWikiURLFactory; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.when; + +/** + * Test of {@link StringClass}. + * + * @version $Id$ + */ +@OldcoreTest +@XWikiDocumentFilterUtilsComponentList +class StringClassTest +{ + @InjectMockitoOldcore + private MockitoOldcore oldCore; + + @Mock + private XWikiURLFactory urlFactory; + + @Test + void displayEdit() + { + XWikiContext xWikiContext = this.oldCore.getXWikiContext(); + xWikiContext.setURLFactory(this.urlFactory); + when(this.oldCore.getSpyXWiki().getURL("Main.WebHome", "view", xWikiContext)).thenReturn("/a/b"); + + String fieldName = "test"; + String spaceName = "\" + alert(1) + \""; + String pageName = "WebHome"; + StringClass stringClass = new StringClass(); + stringClass.setPicker(true); + BaseClass baseClass = new BaseClass(); + stringClass.setObject(baseClass); + baseClass.setDocumentReference( + new DocumentReference(this.oldCore.getXWikiContext().getWikiId(), spaceName, pageName)); + stringClass.setName(fieldName); + StringBuffer stringBuffer = new StringBuffer(); + stringClass.displayEdit(stringBuffer, fieldName, spaceName + "." + pageName + "_0_", baseClass, + xWikiContext); + assertEquals("", stringBuffer.toString()); + } +}