From 0ffd4844bba68b9180850f804ead8ec395bf9431 Mon Sep 17 00:00:00 2001 From: "taylor.smock" Date: Tue, 18 Jun 2024 21:29:43 +0000 Subject: [PATCH] Fix an XPath injection issue This isn't really an issue for JOSM, since we are only reading from public remote sources. git-svn-id: https://josm.openstreetmap.de/svn/trunk@19114 0c6e7542-c601-0410-84e7-c038aed88b3b --- .../openstreetmap/josm/tools/Mediawiki.java | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/org/openstreetmap/josm/tools/Mediawiki.java b/src/org/openstreetmap/josm/tools/Mediawiki.java index 5a5b72f31c6..29415227038 100644 --- a/src/org/openstreetmap/josm/tools/Mediawiki.java +++ b/src/org/openstreetmap/josm/tools/Mediawiki.java @@ -6,6 +6,7 @@ import java.net.URL; import java.util.List; import java.util.Optional; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.BiConsumer; import java.util.stream.Collectors; @@ -59,22 +60,33 @@ public Optional findExistingPage(List pages) ); final Document document = getDocument(url); final XPath xPath = XPathFactory.newInstance().newXPath(); - for (String page : distinctPages) { - String normalized = xPath.evaluate("/api/query/normalized/n[@from='" + page + "']/@to", document); - if (Utils.isEmpty(normalized)) { - normalized = page; + AtomicReference normalized = new AtomicReference<>(); + AtomicReference page = new AtomicReference<>(); + xPath.setXPathVariableResolver(v -> { + if ("page".equals(v.getLocalPart())) { + return page.get(); + } else if ("normalized".equals(v.getLocalPart())) { + return normalized.get(); } - final Node node = (Node) xPath.evaluate("/api/query/pages/page[@title='" + normalized + "']", document, XPathConstants.NODE); + throw new IllegalArgumentException(); + }); + for (String p : distinctPages) { + page.set(p); + normalized.set(xPath.evaluate("/api/query/normalized/n[@from=$page]/@to", document)); + if (Utils.isEmpty(normalized.get())) { + normalized.set(page.get()); + } + final Node node = (Node) xPath.evaluate("/api/query/pages/page[@title=$normalized]", document, XPathConstants.NODE); if (node != null && node.getAttributes().getNamedItem("missing") == null && node.getAttributes().getNamedItem("invalid") == null) { - return Optional.of(page); + return Optional.of(page.get()); } } return Optional.empty(); } - private Document getDocument(URL url) throws IOException, ParserConfigurationException, SAXException { + private static Document getDocument(URL url) throws IOException, ParserConfigurationException, SAXException { final HttpClient.Response conn = HttpClient.create(url).connect(); try (InputStream content = conn.getContent()) { return XmlUtils.parseSafeDOM(content);