diff --git a/opengrok-indexer/src/main/java/org/opengrok/indexer/web/Laundromat.java b/opengrok-indexer/src/main/java/org/opengrok/indexer/web/Laundromat.java index 9ca8979effb..29f2e03d39a 100644 --- a/opengrok-indexer/src/main/java/org/opengrok/indexer/web/Laundromat.java +++ b/opengrok-indexer/src/main/java/org/opengrok/indexer/web/Laundromat.java @@ -19,6 +19,7 @@ /* * Copyright (c) 2020, Chris Fraire . + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. */ package org.opengrok.indexer.web; @@ -72,6 +73,17 @@ public static String launderRevision(String value) { return replaceAll(value, "[^a-zA-Z0-9:]", ""); } + /** + * Sanitize {@code value} where it will be used in subsequent OpenGrok + * (non-logging) processing. The value is assumed to represent a pagination query string, + * e.g. {@code n=25&start=25} + * @return {@code null} if null or else {@code value} with anything besides + * alphanumeric or {@code &}, {@code =} characters removed. + */ + public static String launderPaginationQuery(String value) { + return replaceAll(value, "[^a-zA-Z0-9=&]", ""); + } + /** * Sanitize {@code value} where it will be used in subsequent OpenGrok * (non-logging) processing. The value is assumed to represent URI path, diff --git a/opengrok-indexer/src/test/java/org/opengrok/indexer/web/LaundromatTest.java b/opengrok-indexer/src/test/java/org/opengrok/indexer/web/LaundromatTest.java index 0ff05731a94..5a66755bbc7 100644 --- a/opengrok-indexer/src/test/java/org/opengrok/indexer/web/LaundromatTest.java +++ b/opengrok-indexer/src/test/java/org/opengrok/indexer/web/LaundromatTest.java @@ -60,30 +60,41 @@ void launderLog() { } private static Stream> getParamsForTestLaunderServerName() { - return Stream.of(Pair.of("foo.example.com", Laundromat.launderServerName("--foo.example\n.com?=")), - Pair.of("[2001:db8::1]:8080", Laundromat.launderServerName("[2001:db8::1]:8080"))); + return Stream.of(Pair.of("foo.example.com", "--foo.example\n.com?="), + Pair.of("[2001:db8::1]:8080", "[2001:db8::1]:8080")); } @ParameterizedTest @MethodSource("getParamsForTestLaunderServerName") void testLaunderServerName(Pair param) { - assertEquals(param.getLeft(), param.getRight()); + assertEquals(param.getLeft(), Laundromat.launderServerName(param.getRight())); } private static Stream> getParamsForTestLaunderUriPath() { - return Stream.of(Pair.of("foo", Laundromat.launderUriPath("../../../foo")), - Pair.of("/foo/bar", Laundromat.launderUriPath("/foo/../../bar")), - Pair.of("/foo/bar..", Laundromat.launderUriPath("/foo/bar..")), - Pair.of("/foo/bar", Laundromat.launderUriPath("/foo//bar")), - Pair.of("..foo/bar", Laundromat.launderUriPath("..foo/bar")), - Pair.of("/foo/bar.txt", Laundromat.launderUriPath("/foo/bar.txt")), - Pair.of("/foo/bar_.txt", Laundromat.launderUriPath("/foo/bar\u0000.txt"))); + return Stream.of(Pair.of("foo", "../../../foo"), + Pair.of("/foo/bar", "/foo/../../bar"), + Pair.of("/foo/bar..", "/foo/bar.."), + Pair.of("/foo/bar", "/foo//bar"), + Pair.of("..foo/bar", "..foo/bar"), + Pair.of("/foo/bar.txt", "/foo/bar.txt"), + Pair.of("/foo/bar_.txt", "/foo/bar\u0000.txt")); } @ParameterizedTest @MethodSource("getParamsForTestLaunderUriPath") void testLaunderUriPath(Pair param) { - assertEquals(param.getLeft(), param.getRight()); + assertEquals(param.getLeft(), Laundromat.launderUriPath(param.getRight())); + } + + private static Stream> getParamsForTestLaunderPaginationQuery() { + return Stream.of(Pair.of("foo=bar", "?foo=/bar"), + Pair.of("foo=bar&1=2", "foo=bar&1=2")); + } + + @ParameterizedTest + @MethodSource("getParamsForTestLaunderPaginationQuery") + void testLaunderPaginationQuery(Pair param) { + assertEquals(param.getLeft(), Laundromat.launderPaginationQuery(param.getRight())); } @Test diff --git a/opengrok-web/src/main/webapp/history.jsp b/opengrok-web/src/main/webapp/history.jsp index d28da679aae..38ec1656c77 100644 --- a/opengrok-web/src/main/webapp/history.jsp +++ b/opengrok-web/src/main/webapp/history.jsp @@ -48,6 +48,7 @@ org.opengrok.indexer.web.Util" <%@ page import="jakarta.servlet.http.HttpServletResponse" %> <%@ page import="org.opengrok.indexer.web.SortOrder" %> <%@ page import="java.util.Optional" %> +<%@ page import="org.opengrok.indexer.web.Laundromat" %> <%/* ---------------------- history.jsp start --------------------- */ { final Logger LOGGER = LoggerFactory.getLogger(getClass()); @@ -291,7 +292,7 @@ document.domReady.push(function() {domReadyHistory();}); if (entry.isActive()) { StringBuffer urlBuffer = new StringBuffer(context + Prefix.HIST_L + uriEncodedName); if (request.getQueryString() != null) { - urlBuffer.append('?').append(request.getQueryString()); + urlBuffer.append('?').append(Laundromat.launderPaginationQuery(request.getQueryString())); } urlBuffer.append('#').append(Util.uriEncode(rev)); %>