diff --git a/addons/changelog/common/src/main/java/org/commonjava/indy/changelog/DiffUtil.java b/addons/changelog/common/src/main/java/org/commonjava/indy/changelog/DiffUtil.java index 14b5865ea9..0f2c62c320 100644 --- a/addons/changelog/common/src/main/java/org/commonjava/indy/changelog/DiffUtil.java +++ b/addons/changelog/common/src/main/java/org/commonjava/indy/changelog/DiffUtil.java @@ -46,7 +46,10 @@ public static String diffPatch( final String fileName, final String changed, fin DIFF_PATCH_CONTEXT_LINES ); StringBuilder builder = new StringBuilder(); patchDiff.forEach( ps -> builder.append( ps ).append( LINE_BREAK ) ); - builder.deleteCharAt( builder.lastIndexOf( LINE_BREAK ) ); + if ( builder.lastIndexOf( LINE_BREAK ) > 0 ) + { + builder.deleteCharAt( builder.lastIndexOf( LINE_BREAK ) ); + } return builder.toString(); } diff --git a/core/src/main/java/org/commonjava/indy/core/ctl/ContentController.java b/core/src/main/java/org/commonjava/indy/core/ctl/ContentController.java index d796848d41..d36e38600d 100644 --- a/core/src/main/java/org/commonjava/indy/core/ctl/ContentController.java +++ b/core/src/main/java/org/commonjava/indy/core/ctl/ContentController.java @@ -43,7 +43,6 @@ import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; -import javax.ws.rs.core.MediaType; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -57,11 +56,12 @@ import java.util.Map; import java.util.Set; import java.util.TreeMap; +import java.util.regex.Pattern; import static org.apache.commons.io.IOUtils.closeQuietly; -import static org.apache.commons.lang.StringUtils.isNotBlank; import static org.commonjava.maven.galley.util.PathUtils.normalize; import static org.commonjava.maven.galley.util.PathUtils.parentPath; +import static org.jsoup.helper.StringUtil.isBlank; @ApplicationScoped public class ContentController @@ -82,6 +82,8 @@ public class ContentController public static final String HTML_TAG_PATTERN = ".*\\<(!DOCTYPE|[-_.a-zA-Z0-9]+).*"; + public static final Pattern PATH_PATTERN = Pattern.compile( "^([-\\w:@&?=+,.!/~*'%$_;\\(\\)]*)?$"); + private static final int MAX_PEEK_BYTES = 16384; @Inject @@ -192,16 +194,27 @@ public Transfer store( final StoreKey key, final String path, final InputStream return contentManager.store( store, path, stream, TransferOperation.UPLOAD, eventMetadata ); } - private void validatePath( final StoreKey key, final String path ) - throws IndyWorkflowException + private void validatePath( final StoreKey key, final String path ) throws IndyWorkflowException { - if ( isNotBlank( path ) && ( path.contains( "{" ) || path.contains( "}" ) || path.contains( "@@" ) - || path.contains( "%" ) ) ) + if ( !isValidPath( path ) ) { throw new IndyWorkflowException( 400, "Invalid path: %s (target repo: %s)", path, key ); } } + boolean isValidPath( String path ) + { + if ( isBlank( path ) ) + { + return false; + } + if ( !PATH_PATTERN.matcher( path ).matches() ) + { + return false; + } + return true; + } + public void rescan( final StoreKey key ) throws IndyWorkflowException { diff --git a/core/src/test/java/org/commonjava/indy/core/ctl/ControllerTest.java b/core/src/test/java/org/commonjava/indy/core/ctl/ControllerTest.java new file mode 100644 index 0000000000..da54c822d0 --- /dev/null +++ b/core/src/test/java/org/commonjava/indy/core/ctl/ControllerTest.java @@ -0,0 +1,39 @@ +/** + * Copyright (C) 2011-2018 Red Hat, Inc. (https://github.com/Commonjava/indy) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.commonjava.indy.core.ctl; + +import org.junit.Test; + +import static junit.framework.TestCase.assertTrue; +import static org.junit.Assert.assertFalse; + +public class ControllerTest +{ + @Test + public void validatePath() + { + ContentController controller = new ContentController(); + + assertTrue( controller.isValidPath( "/foo/bar" ) ); + assertTrue( controller.isValidPath( "/@babel%2fparser" ) ); + assertTrue( controller.isValidPath( "@babel%2fparser" ) ); + assertTrue( controller.isValidPath( "/a-zA-Z0-9.-_~!$&'()*+,;=:@" ) ); + + assertFalse( controller.isValidPath( "" ) ); + assertFalse( controller.isValidPath( null ) ); + } + +}