[Git][java-team/ivy][upstream] New upstream version 2.5.1

Emmanuel Bourg (@ebourg) gitlab at salsa.debian.org
Mon Dec 5 15:25:17 GMT 2022



Emmanuel Bourg pushed to branch upstream at Debian Java Maintainers / ivy


Commits:
06e278b3 by Emmanuel Bourg at 2022-12-05T16:21:22+01:00
New upstream version 2.5.1
- - - - -


22 changed files:

- NOTICE
- build-release.xml
- build.properties
- build.xml
- src/example/go-ivy/build.xml
- src/java/org/apache/ivy/Main.java
- + src/java/org/apache/ivy/ant/EmptyFileSet.java
- src/java/org/apache/ivy/ant/IvyCacheFileset.java
- src/java/org/apache/ivy/ant/IvyRetrieve.java
- src/java/org/apache/ivy/core/IvyPatternHelper.java
- src/java/org/apache/ivy/core/cache/DefaultRepositoryCacheManager.java
- src/java/org/apache/ivy/core/cache/DefaultResolutionCacheManager.java
- src/java/org/apache/ivy/core/pack/ZipPacking.java
- src/java/org/apache/ivy/core/resolve/IvyNode.java
- src/java/org/apache/ivy/core/resolve/ResolveEngine.java
- src/java/org/apache/ivy/core/retrieve/RetrieveEngine.java
- src/java/org/apache/ivy/plugins/report/XmlReportOutputter.java
- src/java/org/apache/ivy/plugins/repository/file/FileRepository.java
- src/java/org/apache/ivy/util/FileUtil.java
- src/java/org/apache/ivy/util/MessageLoggerHelper.java
- src/java/org/apache/ivy/util/url/BasicURLHandler.java
- version.properties


Changes:

=====================================
NOTICE
=====================================
@@ -1,5 +1,5 @@
 Apache Ivy (TM)
-Copyright 2007-2019 The Apache Software Foundation
+Copyright 2007-2019,2022 The Apache Software Foundation
 
 This product includes software developed at
 The Apache Software Foundation (http://www.apache.org/).


=====================================
build-release.xml
=====================================
@@ -58,9 +58,6 @@
                 <sysproperty key="ivy.local.default.root" value="${tutorial.local-repo}"/>
                 <sysproperty key="ivy.cache.ttl.default" value="1s"/>
                 <sysproperty key="skip.download" value="true"/>
-                <!-- We select specific HTTPS protocols, based on the Java version we are running
-                    on -->
-                <sysproperty key="https.protocols" value="${java.sysprop.https.protocols}"/>
                 <arg line="-f @{antfile}"/>
                 <arg line="@{target}"/>
             </java>
@@ -483,7 +480,7 @@
 
     <target name="rat" depends="init-ivy">
         <property name="rat.failOnError" value="true"/>
-        <ivy:cachepath organisation="org.apache.rat" module="apache-rat-tasks" revision="0.12"
+        <ivy:cachepath organisation="org.apache.rat" module="apache-rat-tasks" revision="0.15"
                        inline="true" conf="default" pathid="rat.classpath"
                        log="download-only"/>
 


=====================================
build.properties
=====================================
@@ -44,10 +44,9 @@ checkstyle.report.dir=${reports.dir}/checkstyle
 checkstyle.src.dir=${basedir}/src/etc/checkstyle
 rat.report.dir=${reports.dir}/rat
 
-ivy.minimum.javaversion=1.7
+ivy.minimum.javaversion=1.8
 debug.mode=on
-ivy.install.version=1.4.1
-ivy.api.reference=2.4.0
+ivy.api.reference=2.5.0
 
 #status=integration
 


=====================================
build.xml
=====================================
@@ -23,12 +23,6 @@
     <property file="build.properties"/>
 
     <property name="final.name" value="ivy.jar"/>
-    <!-- Java 7 runs into TLS protocol issues when dealing with repositories
-    that no longer support older protocols -->
-    <condition property="java.sysprop.https.protocols" value="" else="TLSv1.2">
-        <javaversion atleast="1.8"/>
-    </condition>
-
 
     <target name="init-ivy-user-home" unless="ivy.use.local.home">
         <condition property="ivy.home" value="${env.IVY_HOME}">
@@ -259,10 +253,6 @@
                 <exclude name="**/*.java"/>
             </fileset>
         </copy>
-
-        <!-- copy antlib for backward compatibility with fr.jayasoft.ivy package -->
-        <copy file="${ant.classes.build.dir}/org/apache/ivy/ant/antlib.xml"
-                todir="${ant.classes.build.dir}/fr/jayasoft/ivy/ant"/>
     </target>
 
     <target name="compile-optional" depends="compile-ant">
@@ -438,7 +428,7 @@
     </target>
 
     <target name="init-jacoco" depends="jar" unless="skip.test">
-        <ivy:cachepath organisation="org.jacoco" module="org.jacoco.ant" revision="0.8.3"
+        <ivy:cachepath organisation="org.jacoco" module="org.jacoco.ant" revision="${jacoco.version}"
                        inline="true" conf="default" pathid="jacoco.classpath" log="download-only"/>
         <taskdef uri="antlib:org.jacoco.ant" resource="org/jacoco/ant/antlib.xml"
                  classpathref="jacoco.classpath"/>
@@ -449,8 +439,10 @@
 
         <!-- multiple runs into the same logfile let the later report generation fail -->
         <delete file="${jacoco.log}"/>
+        <property name="jacoco.coverage.enabled" value="true"/>
         <jacoco:coverage xmlns:jacoco="antlib:org.jacoco.ant" destfile="${jacoco.log}"
-                         exclclassloader="sun.reflect.DelegatingClassLoader:javassist.Loader">
+                         exclclassloader="sun.reflect.DelegatingClassLoader:javassist.Loader"
+                         enabled="${jacoco.coverage.enabled}">
             <junit
                 haltonfailure="off"
                 haltonerror="off"
@@ -470,9 +462,6 @@
                 <syspropertyset>
                     <propertyref prefix="http"/>
                 </syspropertyset>
-                <!-- We select specific HTTPS protocols, based on the Java version we are running
-                    on -->
-                <sysproperty key="https.protocols" value="${java.sysprop.https.protocols}"/>
 
                 <!-- Added this to test IVY-65 -->
                 <jvmarg value="-Duser.region=TR"/>


=====================================
src/example/go-ivy/build.xml
=====================================
@@ -38,7 +38,7 @@
 
     <!-- here is the version of ivy we will use. change this property to try a newer
          version if you want -->
-    <property name="ivy.install.version" value="2.0.0-beta1"/>
+    <property name="ivy.install.version" value="2.5.0"/>
     <property name="ivy.jar.dir" value="${basedir}/ivy"/>
     <property name="ivy.jar.file" value="${ivy.jar.dir}/ivy.jar"/>
 


=====================================
src/java/org/apache/ivy/Main.java
=====================================
@@ -24,6 +24,8 @@ import java.io.PrintWriter;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.net.URL;
 import java.net.URLClassLoader;
 import java.util.ArrayList;
@@ -76,8 +78,8 @@ public final class Main {
         return new CommandLineParser()
                 .addCategory("settings options")
                 .addOption(
-                    new OptionBuilder("settings").arg("settingsfile")
-                            .description("use given file for settings").create())
+                    new OptionBuilder("settings").arg("settingsfile|url")
+                            .description("use given file or URL for settings").create())
                 .addOption(
                         new OptionBuilder("properties").arg("propertiesfile")
                             .description("use given file for properties not specified in settings").create())
@@ -515,17 +517,39 @@ public final class Main {
         if ("".equals(settingsPath)) {
             ivy.configureDefault();
         } else {
-            File conffile = new File(settingsPath);
-            if (!conffile.exists()) {
-                error("ivy configuration file not found: " + conffile);
-            } else if (conffile.isDirectory()) {
-                error("ivy configuration file is not a file: " + conffile);
+            final URI confUri = getSettingsURI(settingsPath);
+            if ("file".equals(confUri.getScheme())) {
+                File conffile = new File(confUri);
+                if (!conffile.exists()) {
+                    throw new IOException("ivy configuration file not found: " + conffile);
+                } else if (conffile.isDirectory()) {
+                    throw new IOException("ivy configuration file is not a file: " + conffile);
+                }
+                ivy.configure(conffile);
+            } else {
+                try {
+                    ivy.configure(confUri.toURL());
+                } catch (IOException ioe) {
+                    throw new IOException("ivy configuration failed to load from: " + settingsPath, ioe);
+                }
             }
-            ivy.configure(conffile);
         }
         return settings;
     }
 
+    private static URI getSettingsURI(String settingsPath) {
+        URI settingsUri;
+        try {
+            settingsUri = new URI(settingsPath);
+            if (settingsUri.getScheme() == null) {
+                settingsUri = new File(settingsPath).toURI();
+            }
+        } catch (URISyntaxException badUriEx) {
+            return new File(settingsPath).toURI();
+        }
+        return settingsUri;
+    }
+
     private static void initMessage(CommandLine line, Ivy ivy) {
         if (line.hasOption("debug")) {
             ivy.getLoggerEngine().pushLogger(new DefaultMessageLogger(Message.MSG_DEBUG));


=====================================
src/java/org/apache/ivy/ant/EmptyFileSet.java
=====================================
@@ -0,0 +1,71 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You 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
+ *
+ *      https://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.apache.ivy.ant;
+
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Resource;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+class EmptyFileSet extends FileSet {
+
+    private DirectoryScanner ds = new EmptyDirectoryScanner();
+
+    public Iterator<Resource> iterator() {
+        return new EmptyIterator<>();
+    }
+
+    public Object clone() {
+        return new EmptyFileSet();
+    }
+
+    public int size() {
+        return 0;
+    }
+
+    public DirectoryScanner getDirectoryScanner(Project project) {
+        return ds;
+    }
+
+    private static class EmptyIterator<T> implements Iterator<T> {
+
+        public boolean hasNext() {
+            return false;
+        }
+
+        public T next() {
+            throw new NoSuchElementException("EmptyFileSet Iterator");
+        }
+
+        public void remove() {
+            throw new IllegalStateException("EmptyFileSet Iterator");
+        }
+
+    }
+
+    private static class EmptyDirectoryScanner extends DirectoryScanner {
+
+        public String[] getIncludedFiles() {
+            return new String[0];
+        }
+
+    }
+}


=====================================
src/java/org/apache/ivy/ant/IvyCacheFileset.java
=====================================
@@ -21,15 +21,11 @@ import java.io.File;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.NoSuchElementException;
 
 import org.apache.ivy.core.report.ArtifactDownloadReport;
 import org.apache.tools.ant.BuildException;
-import org.apache.tools.ant.DirectoryScanner;
-import org.apache.tools.ant.Project;
 import org.apache.tools.ant.types.FileSet;
 import org.apache.tools.ant.types.PatternSet.NameEntry;
-import org.apache.tools.ant.types.Resource;
 
 /**
  * Creates an ant fileset consisting in all artifacts found during a resolve. Note that this task
@@ -194,49 +190,4 @@ public class IvyCacheFileset extends IvyCacheTask {
         }
         return r;
     }
-
-    private static class EmptyFileSet extends FileSet {
-
-        private DirectoryScanner ds = new EmptyDirectoryScanner();
-
-        public Iterator<Resource> iterator() {
-            return new EmptyIterator<>();
-        }
-
-        public Object clone() {
-            return new EmptyFileSet();
-        }
-
-        public int size() {
-            return 0;
-        }
-
-        public DirectoryScanner getDirectoryScanner(Project project) {
-            return ds;
-        }
-    }
-
-    private static class EmptyIterator<T> implements Iterator<T> {
-
-        public boolean hasNext() {
-            return false;
-        }
-
-        public T next() {
-            throw new NoSuchElementException("EmptyFileSet Iterator");
-        }
-
-        public void remove() {
-            throw new IllegalStateException("EmptyFileSet Iterator");
-        }
-
-    }
-
-    private static class EmptyDirectoryScanner extends DirectoryScanner {
-
-        public String[] getIncludedFiles() {
-            return new String[0];
-        }
-
-    }
 }


=====================================
src/java/org/apache/ivy/ant/IvyRetrieve.java
=====================================
@@ -126,16 +126,24 @@ public class IvyRetrieve extends IvyPostResolveTask {
             }
 
             if (getSetId() != null) {
-                FileSet fileset = new FileSet();
-                fileset.setProject(getProject());
-                getProject().addReference(getSetId(), fileset);
-
-                fileset.setDir(report.getRetrieveRoot());
-
-                for (File file : report.getRetrievedFiles()) {
-                    PatternSet.NameEntry ne = fileset.createInclude();
-                    ne.setName(getPath(report.getRetrieveRoot(), file));
+                FileSet fileset;
+
+                Collection<File> retrievedFiles = report.getRetrievedFiles();
+                if (retrievedFiles.isEmpty()) {
+                    fileset = new EmptyFileSet();
+                    fileset.setProject(getProject());
+                } else {
+                    fileset = new FileSet();
+                    fileset.setProject(getProject());
+                    fileset.setDir(report.getRetrieveRoot());
+
+                    for (File file : retrievedFiles) {
+                        PatternSet.NameEntry ne = fileset.createInclude();
+                        ne.setName(getPath(report.getRetrieveRoot(), file));
+                    }
                 }
+
+                getProject().addReference(getSetId(), fileset);
             }
         } catch (Exception ex) {
             throw new BuildException("impossible to ivy retrieve: " + ex, ex);


=====================================
src/java/org/apache/ivy/core/IvyPatternHelper.java
=====================================
@@ -22,6 +22,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Stack;
+import java.util.StringTokenizer;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -135,7 +136,7 @@ public final class IvyPatternHelper {
                 if (token.indexOf(':') > 0) {
                     token = token.substring(token.indexOf(':') + 1);
                 }
-                tokens.put(token, entry.getValue());
+                tokens.put(token, new Validated(token, entry.getValue()));
             }
         }
         if (extraArtifactAttributes != null) {
@@ -144,19 +145,19 @@ public final class IvyPatternHelper {
                 if (token.indexOf(':') > 0) {
                     token = token.substring(token.indexOf(':') + 1);
                 }
-                tokens.put(token, entry.getValue());
+                tokens.put(token, new Validated(token, entry.getValue()));
             }
         }
-        tokens.put(ORGANISATION_KEY, org == null ? "" : org);
-        tokens.put(ORGANISATION_KEY2, org == null ? "" : org);
+        tokens.put(ORGANISATION_KEY, org == null ? "" : new Validated(ORGANISATION_KEY, org));
+        tokens.put(ORGANISATION_KEY2, org == null ? "" : new Validated(ORGANISATION_KEY2, org));
         tokens.put(ORGANISATION_PATH_KEY, org == null ? "" : org.replace('.', '/'));
-        tokens.put(MODULE_KEY, module == null ? "" : module);
-        tokens.put(BRANCH_KEY, branch == null ? "" : branch);
-        tokens.put(REVISION_KEY, revision == null ? "" : revision);
-        tokens.put(ARTIFACT_KEY, artifact == null ? module : artifact);
-        tokens.put(TYPE_KEY, type == null ? "jar" : type);
-        tokens.put(EXT_KEY, ext == null ? "jar" : ext);
-        tokens.put(CONF_KEY, conf == null ? "default" : conf);
+        tokens.put(MODULE_KEY, module == null ? "" : new Validated(MODULE_KEY, module));
+        tokens.put(BRANCH_KEY, branch == null ? "" : new Validated(BRANCH_KEY, branch));
+        tokens.put(REVISION_KEY, revision == null ? "" : new Validated(REVISION_KEY, revision));
+        tokens.put(ARTIFACT_KEY, new Validated(ARTIFACT_KEY, artifact == null ? module : artifact));
+        tokens.put(TYPE_KEY, type == null ? "jar" : new Validated(TYPE_KEY, type));
+        tokens.put(EXT_KEY, ext == null ? "jar" : new Validated(EXT_KEY, ext));
+        tokens.put(CONF_KEY, conf == null ? "default" : new Validated(CONF_KEY, conf));
         if (origin == null) {
             tokens.put(ORIGINAL_ARTIFACTNAME_KEY, new OriginalArtifactNameValue(org, module,
                     branch, revision, artifact, type, ext, extraModuleAttributes,
@@ -328,7 +329,9 @@ public final class IvyPatternHelper {
                     + pattern);
         }
 
-        return buffer.toString();
+        String afterTokenSubstitution = buffer.toString();
+        checkAgainstPathTraversal(pattern, afterTokenSubstitution);
+        return afterTokenSubstitution;
     }
 
     public static String substituteVariable(String pattern, String variable, String value) {
@@ -518,4 +521,49 @@ public final class IvyPatternHelper {
         }
         return pattern.substring(startIndex + 1, endIndex);
     }
+
+    /**
+     * This class returns a captured value after validating it doesn't
+     * contain any path traversal sequence.
+     *
+     * <p>{@code toString}</p> will be invoked when the value is
+     * actually used as a token inside of a pattern passed to {@link
+     * #substituteTokens}.</p>
+     */
+    private static class Validated {
+        private final String tokenName, tokenValue;
+
+        private Validated(String tokenName, String tokenValue) {
+            this.tokenName = tokenName;
+            this.tokenValue = tokenValue;
+        }
+
+        @Override
+        public String toString() {
+            if (tokenValue != null && !tokenValue.isEmpty()) {
+                StringTokenizer tok = new StringTokenizer(tokenValue.replace("\\", "/"), "/");
+                while (tok.hasMoreTokens()) {
+                    if ("..".equals(tok.nextToken())) {
+                        throw new IllegalArgumentException("\'" + tokenName + "\' value " + tokenValue + " contains an illegal path sequence");
+                    }
+                }
+            }
+            return tokenValue;
+        }
+    }
+
+    private static void checkAgainstPathTraversal(String pattern, String afterTokenSubstitution) {
+        String root = getTokenRoot(pattern);
+        int rootLen = root.length(); // it is OK to have a token root containing .. sequences
+        if (root.endsWith("/") || root.endsWith("\\")) {
+            --rootLen;
+        }
+        String patternedPartWithNormalizedSlashes =
+            afterTokenSubstitution.substring(rootLen).replace("\\", "/");
+        if (patternedPartWithNormalizedSlashes.endsWith("/..")
+            || patternedPartWithNormalizedSlashes.indexOf("/../") >= 0) {
+            throw new IllegalArgumentException("path after token expansion contains an illegal sequence");
+        }
+    }
+
 }


=====================================
src/java/org/apache/ivy/core/cache/DefaultRepositoryCacheManager.java
=====================================
@@ -21,6 +21,8 @@ import java.io.File;
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
 import java.net.URL;
 import java.nio.charset.StandardCharsets;
 import java.security.MessageDigest;
@@ -385,7 +387,7 @@ public class DefaultRepositoryCacheManager implements RepositoryCacheManager, Iv
     public File getArchiveFileInCache(Artifact artifact, ArtifactOrigin origin) {
         File archive = new File(getRepositoryCacheRoot(), getArchivePathInCache(artifact, origin));
         if (!archive.exists() && !ArtifactOrigin.isUnknown(origin) && origin.isLocal()) {
-            File original = Checks.checkAbsolute(origin.getLocation(), artifact
+            File original = Checks.checkAbsolute(parseArtifactOriginFilePath(origin), artifact
                     + " origin location");
             if (original.exists()) {
                 return original;
@@ -407,7 +409,7 @@ public class DefaultRepositoryCacheManager implements RepositoryCacheManager, Iv
      */
     private File getArchiveFileInCache(Artifact artifact, ArtifactOrigin origin, boolean useOrigin) {
         if (useOrigin && !ArtifactOrigin.isUnknown(origin) && origin.isLocal()) {
-            return Checks.checkAbsolute(origin.getLocation(), artifact + " origin location");
+            return Checks.checkAbsolute(parseArtifactOriginFilePath(origin), artifact + " origin location");
         }
         return new File(getRepositoryCacheRoot(), getArchivePathInCache(artifact, origin));
     }
@@ -681,8 +683,10 @@ public class DefaultRepositoryCacheManager implements RepositoryCacheManager, Iv
     }
 
     private PropertiesFile getCachedDataFile(ModuleRevisionId mRevId) {
-        return new PropertiesFile(new File(getRepositoryCacheRoot(), IvyPatternHelper.substitute(
-            getDataFilePattern(), mRevId)), "ivy cached data file for " + mRevId);
+        File file = new File(getRepositoryCacheRoot(), IvyPatternHelper.substitute(
+            getDataFilePattern(), mRevId));
+        assertInsideCache(file);
+        return new PropertiesFile(file, "ivy cached data file for " + mRevId);
     }
 
     /**
@@ -691,9 +695,10 @@ public class DefaultRepositoryCacheManager implements RepositoryCacheManager, Iv
      */
     private PropertiesFile getCachedDataFile(String resolverName, ModuleRevisionId mRevId) {
         // we append ".${resolverName} onto the end of the regular ivydata location
-        return new PropertiesFile(new File(getRepositoryCacheRoot(),
-                IvyPatternHelper.substitute(getDataFilePattern(), mRevId) + "." + resolverName),
-                "ivy cached data file for " + mRevId);
+        File file = new File(getRepositoryCacheRoot(),
+            IvyPatternHelper.substitute(getDataFilePattern(), mRevId) + "." + resolverName);
+        assertInsideCache(file);
+        return new PropertiesFile(file, "ivy cached data file for " + mRevId);
     }
 
     public ResolvedModuleRevision findModuleInCache(DependencyDescriptor dd,
@@ -1027,6 +1032,7 @@ public class DefaultRepositoryCacheManager implements RepositoryCacheManager, Iv
                                         + resourceResolver
                                         + "': pointing repository to ivy cache is forbidden !");
                             }
+                            assertInsideCache(archiveFile);
                             if (listener != null) {
                                 listener.startArtifactDownload(this, artifactRef, artifact, origin);
                             }
@@ -1145,6 +1151,7 @@ public class DefaultRepositoryCacheManager implements RepositoryCacheManager, Iv
                         }
 
                         // actual download
+                        assertInsideCache(archiveFile);
                         if (archiveFile.exists()) {
                             archiveFile.delete();
                         }
@@ -1532,6 +1539,49 @@ public class DefaultRepositoryCacheManager implements RepositoryCacheManager, Iv
         Message.debug("\t\tchangingMatcher: " + getChangingMatcherName());
     }
 
+    /**
+     * @throws IllegalArgumentException if the given path points outside of the cache.
+     */
+    public final void assertInsideCache(File fileInCache) {
+        File root = getRepositoryCacheRoot();
+        if (root != null && !FileUtil.isLeadingPath(root, fileInCache)) {
+            throw new IllegalArgumentException(fileInCache + " is outside of the cache");
+        }
+    }
+
+    /**
+     * If the {@link ArtifactOrigin#getLocation() location of the artifact origin} is a
+     * {@code file:} scheme URI, then this method parses that URI and returns back the
+     * path of the file it represents. Else returns back {@link ArtifactOrigin#getLocation()}
+     * @param origin The artifact origin
+     * @return
+     */
+    private static String parseArtifactOriginFilePath(final ArtifactOrigin origin) {
+        if (origin == null || origin.getLocation() == null) {
+            return null;
+        }
+        final String location = origin.getLocation();
+        if (!location.startsWith("file:")) {
+            // no need to parse it into a URI, if it's not a "file" scheme URI
+            return location;
+        }
+        final URI uri;
+        try {
+            uri = new URI(location);
+        } catch (URISyntaxException e) {
+            return location;
+        }
+        if (!uri.isAbsolute()) {
+            // no scheme in URI, just return the original location
+            return location;
+        } else if (uri.getScheme().equals("file")) {
+            // return the file path
+            return uri.getPath();
+        }
+        // not a "file" scheme URI, just return back the original location
+        return location;
+    }
+
     /**
      * Resource downloader which makes a copy of the previously existing file before overriding it.
      * <p>


=====================================
src/java/org/apache/ivy/core/cache/DefaultResolutionCacheManager.java
=====================================
@@ -180,6 +180,7 @@ public class DefaultResolutionCacheManager implements ResolutionCacheManager, Iv
             IOException {
         ModuleRevisionId mrevId = md.getResolvedModuleRevisionId();
         File ivyFileInCache = getResolvedIvyFileInCache(mrevId);
+        assertInsideCache(ivyFileInCache);
         md.toIvyFile(ivyFileInCache);
 
         Properties paths = new Properties();
@@ -188,12 +189,22 @@ public class DefaultResolutionCacheManager implements ResolutionCacheManager, Iv
         if (!paths.isEmpty()) {
             File parentsFile = getResolvedIvyPropertiesInCache(ModuleRevisionId.newInstance(mrevId,
                 mrevId.getRevision() + "-parents"));
+            assertInsideCache(parentsFile);
             FileOutputStream out = new FileOutputStream(parentsFile);
             paths.store(out, null);
             out.close();
         }
     }
 
+    /**
+     * @throws IllegalArgumentException if the given path points outside of the cache.
+     */
+    public final void assertInsideCache(File fileInCache) {
+        if (!FileUtil.isLeadingPath(getResolutionCacheRoot(), fileInCache)) {
+            throw new IllegalArgumentException(fileInCache + " is outside of the cache");
+        }
+    }
+
     private void saveLocalParents(ModuleRevisionId baseMrevId, ModuleDescriptor md, File mdFile,
             Properties paths) throws ParseException, IOException {
         for (ExtendsDescriptor parent : md.getInheritedDescriptors()) {
@@ -206,6 +217,7 @@ public class DefaultResolutionCacheManager implements ResolutionCacheManager, Iv
             ModuleRevisionId pRevId = ModuleRevisionId.newInstance(baseMrevId,
                 baseMrevId.getRevision() + "-parent." + paths.size());
             File parentFile = getResolvedIvyFileInCache(pRevId);
+            assertInsideCache(parentFile);
             parentMd.toIvyFile(parentFile);
 
             paths.setProperty(mdFile.getName() + "|" + parent.getLocation(),


=====================================
src/java/org/apache/ivy/core/pack/ZipPacking.java
=====================================
@@ -52,8 +52,15 @@ public class ZipPacking extends ArchivePacking {
         try (ZipInputStream zip = new ZipInputStream(packed)) {
             ZipEntry entry = null;
             while (((entry = zip.getNextEntry()) != null)) {
-                File f = new File(dest, entry.getName());
-                Message.verbose("\t\texpanding " + entry.getName() + " to " + f);
+                String entryName = entry.getName();
+                File f = FileUtil.resolveFile(dest, entryName);
+                if (!FileUtil.isLeadingPath(dest, f, true)) {
+                    Message.verbose("\t\tskipping " + entryName + " as its target "
+                                    + f.getCanonicalPath()
+                                    + " is outside of " + dest.getCanonicalPath() + ".");
+                    continue;
+                }
+                Message.verbose("\t\texpanding " + entryName + " to " + f);
 
                 // create intermediary directories - sometimes zip don't add them
                 File dirF = f.getParentFile();


=====================================
src/java/org/apache/ivy/core/resolve/IvyNode.java
=====================================
@@ -165,7 +165,13 @@ public class IvyNode implements Comparable<IvyNode> {
         } else {
             markRootModuleConfLoaded(rootModuleConf);
             if (md == null) {
-                DependencyResolver resolver = data.getSettings().getResolver(getId());
+                ResolveEngine engine = IvyContext.getContext().getIvy().getResolveEngine();
+                // get the resolver configured on the engine and if none is configured then
+                // get the one configured in ivy settings
+                DependencyResolver resolver = engine.getDictatorResolver();
+                if (resolver == null) {
+                    resolver = data.getSettings().getResolver(getId());
+                }
                 if (resolver == null) {
                     Message.error("no resolver found for " + getModuleId()
                             + ": check your configuration");


=====================================
src/java/org/apache/ivy/core/resolve/ResolveEngine.java
=====================================
@@ -39,6 +39,7 @@ import org.apache.ivy.Ivy;
 import org.apache.ivy.core.IvyContext;
 import org.apache.ivy.core.LogOptions;
 import org.apache.ivy.core.cache.ArtifactOrigin;
+import org.apache.ivy.core.cache.DefaultResolutionCacheManager;
 import org.apache.ivy.core.cache.ResolutionCacheManager;
 import org.apache.ivy.core.event.EventManager;
 import org.apache.ivy.core.event.download.PrepareDownloadEvent;
@@ -126,7 +127,6 @@ public class ResolveEngine {
      */
     public void setDictatorResolver(DependencyResolver dictatorResolver) {
         this.dictatorResolver = dictatorResolver;
-        settings.setDictatorResolver(dictatorResolver);
     }
 
     public ResolveReport resolve(File ivySource) throws ParseException, IOException {
@@ -263,6 +263,9 @@ public class ResolveEngine {
             // this is used by the deliver task to resolve dynamic revisions to static ones
             File ivyPropertiesInCache = cacheManager.getResolvedIvyPropertiesInCache(md
                     .getResolvedModuleRevisionId());
+            if (cacheManager instanceof DefaultResolutionCacheManager) {
+                ((DefaultResolutionCacheManager) cacheManager).assertInsideCache(ivyPropertiesInCache);
+            }
             Properties props = new Properties();
             if (dependencies.length > 0) {
                 Map<ModuleId, ModuleRevisionId> forcedRevisions = new HashMap<>();


=====================================
src/java/org/apache/ivy/core/retrieve/RetrieveEngine.java
=====================================
@@ -290,6 +290,11 @@ public class RetrieveEngine {
         String destIvyPattern = IvyPatternHelper.substituteVariables(options.getDestIvyPattern(),
             settings.getVariables());
 
+        File fileRetrieveRoot = settings.resolveFile(IvyPatternHelper
+                .getTokenRoot(destFilePattern));
+        File ivyRetrieveRoot = destIvyPattern == null ? null : settings
+                .resolveFile(IvyPatternHelper.getTokenRoot(destIvyPattern));
+
         // find what we must retrieve where
 
         // ArtifactDownloadReport source -> Set (String copyDestAbsolutePath)
@@ -340,6 +345,7 @@ public class RetrieveEngine {
                 }
 
                 String destPattern = "ivy".equals(adr.getType()) ? destIvyPattern : destFilePattern;
+                File root = "ivy".equals(adr.getType()) ? ivyRetrieveRoot : fileRetrieveRoot;
 
                 if (!"ivy".equals(adr.getType())
                         && !options.getArtifactFilter().accept(adr.getArtifact())) {
@@ -357,7 +363,14 @@ public class RetrieveEngine {
                     dest = new HashSet<>();
                     artifactsToCopy.put(adr, dest);
                 }
-                String copyDest = settings.resolveFile(destFileName).getAbsolutePath();
+                File copyDestFile = settings.resolveFile(destFileName).getAbsoluteFile();
+                if (root != null &&
+                    !FileUtil.isLeadingPath(root, copyDestFile)) {
+                    Message.warn("not retrieving artifact " + artifact + " as its destination "
+                                 + copyDestFile + " is not inside " + root);
+                    continue;
+                }
+                String copyDest = copyDestFile.getPath();
 
                 String[] destinations = new String[] {copyDest};
                 if (options.getMapper() != null) {
@@ -411,7 +424,7 @@ public class RetrieveEngine {
                     ArtifactDownloadReport current = artifactsList.get(i);
                     if (winnerMD.equals(current.getArtifact().getModuleRevisionId())) {
                         throw new RuntimeException("Multiple artifacts of the module " + winnerMD
-                                + " are retrieved to the same file! Update the retrieve pattern "
+                                + " are retrieved to the same file! Update the retrieve pattern"
                                 + " to fix this error.");
                     }
                 }


=====================================
src/java/org/apache/ivy/plugins/report/XmlReportOutputter.java
=====================================
@@ -22,6 +22,7 @@ import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 
+import org.apache.ivy.core.cache.DefaultResolutionCacheManager;
 import org.apache.ivy.core.cache.ResolutionCacheManager;
 import org.apache.ivy.core.report.ConfigurationResolveReport;
 import org.apache.ivy.core.report.ResolveReport;
@@ -52,6 +53,9 @@ public class XmlReportOutputter implements ReportOutputter {
             ResolutionCacheManager cacheMgr) throws IOException {
         File reportFile = cacheMgr.getConfigurationResolveReportInCache(resolveId,
             report.getConfiguration());
+        if (cacheMgr instanceof DefaultResolutionCacheManager) {
+            ((DefaultResolutionCacheManager) cacheMgr).assertInsideCache(reportFile);
+        }
         File reportParentDir = reportFile.getParentFile();
         reportParentDir.mkdirs();
         OutputStream stream = new FileOutputStream(reportFile);


=====================================
src/java/org/apache/ivy/plugins/repository/file/FileRepository.java
=====================================
@@ -49,13 +49,15 @@ public class FileRepository extends AbstractRepository {
     }
 
     public void get(String source, File destination) throws IOException {
+        File s = getFile(source);
         fireTransferInitiated(getResource(source), TransferEvent.REQUEST_GET);
-        copy(getFile(source), destination, true);
+        copy(s, destination, true);
     }
 
     public void put(File source, String destination, boolean overwrite) throws IOException {
+        File d = getFile(destination);
         fireTransferInitiated(getResource(destination), TransferEvent.REQUEST_PUT);
-        copy(source, getFile(destination), overwrite);
+        copy(source, d, overwrite);
     }
 
     public void move(File src, File dest) throws IOException {
@@ -112,7 +114,11 @@ public class FileRepository extends AbstractRepository {
         if (baseDir == null) {
             return Checks.checkAbsolute(source, "source");
         }
-        return FileUtil.resolveFile(baseDir, source);
+        File file = FileUtil.resolveFile(baseDir, source);
+        if (!FileUtil.isLeadingPath(baseDir, file)) {
+            throw new IllegalArgumentException(source + " outside of repository root");
+        }
+        return file;
     }
 
     public boolean isLocal() {


=====================================
src/java/org/apache/ivy/util/FileUtil.java
=====================================
@@ -610,6 +610,68 @@ public final class FileUtil {
         return new DissectedPath(File.separator, pathToDissect);
     }
 
+    /**
+     * Learn whether one path "leads" another.
+     *
+     * <p>This method uses {@link #normalize} under the covers and
+     * does not resolve symbolic links.</p>
+     *
+     * <p>If either path tries to go beyond the file system root
+     * (i.e. it contains more ".." segments than can be travelled up)
+     * the method will return false.</p>
+     *
+     * @param leading The leading path, must not be null, must be absolute.
+     * @param path The path to check, must not be null, must be absolute.
+     * @return true if path starts with leading; false otherwise.
+     * @since Ant 1.7
+     */
+    public static boolean isLeadingPath(File leading, File path) {
+        String l = normalize(leading.getAbsolutePath()).getAbsolutePath();
+        String p = normalize(path.getAbsolutePath()).getAbsolutePath();
+        if (l.equals(p)) {
+            return true;
+        }
+        // ensure that l ends with a /
+        // so we never think /foo was a parent directory of /foobar
+        if (!l.endsWith(File.separator)) {
+            l += File.separator;
+        }
+        // ensure "/foo/"  is not considered a parent of "/foo/../../bar"
+        String up = File.separator + ".." + File.separator;
+        if (l.contains(up) || p.contains(up) || (p + File.separator).contains(up)) {
+            return false;
+        }
+        return p.startsWith(l);
+    }
+
+    /**
+     * Learn whether one path "leads" another.
+     *
+     * @param leading The leading path, must not be null, must be absolute.
+     * @param path The path to check, must not be null, must be absolute.
+     * @param resolveSymlinks whether symbolic links shall be resolved
+     * prior to comparing the paths.
+     * @return true if path starts with leading; false otherwise.
+     * @since Ant 1.9.13
+     * @throws IOException if resolveSymlinks is true and invoking
+     * getCanonicaPath on either argument throws an exception
+     */
+    public static boolean isLeadingPath(File leading, File path, boolean resolveSymlinks)
+        throws IOException {
+        if (!resolveSymlinks) {
+            return isLeadingPath(leading, path);
+        }
+        final File l = leading.getCanonicalFile();
+        File p = path.getCanonicalFile();
+        do {
+            if (l.equals(p)) {
+                return true;
+            }
+            p = p.getParentFile();
+        } while (p != null);
+        return false;
+    }
+
     /**
      * Get the length of the file, or the sum of the children lengths if it is a directory
      *


=====================================
src/java/org/apache/ivy/util/MessageLoggerHelper.java
=====================================
@@ -17,34 +17,35 @@
  */
 package org.apache.ivy.util;
 
+import java.util.ArrayList;
 import java.util.List;
 
 public final class MessageLoggerHelper {
     public static void sumupProblems(MessageLogger logger) {
-        List<String> myProblems = logger.getProblems();
-        if (myProblems.size() > 0) {
-            List<String> myWarns = logger.getWarns();
-            List<String> myErrors = logger.getErrors();
-            logger.info(""); // new line on info to isolate error summary
-            if (!myErrors.isEmpty()) {
-                logger.log(":: problems summary ::", Message.MSG_ERR);
-            } else {
-                logger.log(":: problems summary ::", Message.MSG_WARN);
-            }
-            if (myWarns.size() > 0) {
-                logger.log(":::: WARNINGS", Message.MSG_WARN);
-                for (String msg : myWarns) {
-                    logger.log("\t" + msg + "\n", Message.MSG_WARN);
-                }
+        if (logger.getProblems().isEmpty()) {
+            return;
+        }
+        final List<String> warns = new ArrayList<>(logger.getWarns());
+        final List<String> errors = new ArrayList<>(logger.getErrors());
+        logger.info(""); // new line on info to isolate error summary
+        if (!errors.isEmpty()) {
+            logger.log(":: problems summary ::", Message.MSG_ERR);
+        } else {
+            logger.log(":: problems summary ::", Message.MSG_WARN);
+        }
+        if (warns.size() > 0) {
+            logger.log(":::: WARNINGS", Message.MSG_WARN);
+            for (String msg : warns) {
+                logger.log("\t" + msg + "\n", Message.MSG_WARN);
             }
-            if (myErrors.size() > 0) {
-                logger.log(":::: ERRORS", Message.MSG_ERR);
-                for (String msg : myErrors) {
-                    logger.log("\t" + msg + "\n", Message.MSG_ERR);
-                }
+        }
+        if (errors.size() > 0) {
+            logger.log(":::: ERRORS", Message.MSG_ERR);
+            for (String msg : errors) {
+                logger.log("\t" + msg + "\n", Message.MSG_ERR);
             }
-            logger.info("\n:: USE VERBOSE OR DEBUG MESSAGE LEVEL FOR MORE DETAILS");
         }
+        logger.info("\n:: USE VERBOSE OR DEBUG MESSAGE LEVEL FOR MORE DETAILS");
     }
 
     private MessageLoggerHelper() {


=====================================
src/java/org/apache/ivy/util/url/BasicURLHandler.java
=====================================
@@ -41,6 +41,8 @@ public class BasicURLHandler extends AbstractURLHandler implements TimeoutConstr
 
     private static final int BUFFER_SIZE = 64 * 1024;
 
+    private static final String ACCEPT_HEADER_VALUE = "*/*";
+
     private static final class HttpStatus {
         static final int SC_OK = 200;
 
@@ -96,6 +98,7 @@ public class BasicURLHandler extends AbstractURLHandler implements TimeoutConstr
             con.setConnectTimeout(connectionTimeout);
             con.setReadTimeout(readTimeout);
             con.setRequestProperty("User-Agent", getUserAgent());
+            con.setRequestProperty("Accept", ACCEPT_HEADER_VALUE);
             if (con instanceof HttpURLConnection) {
                 HttpURLConnection httpCon = (HttpURLConnection) con;
                 if (getRequestMethod() == TimeoutConstrainedURLHandler.REQUEST_METHOD_HEAD) {
@@ -199,6 +202,7 @@ public class BasicURLHandler extends AbstractURLHandler implements TimeoutConstr
             conn.setConnectTimeout(connectionTimeout);
             conn.setReadTimeout(readTimeout);
             conn.setRequestProperty("User-Agent", getUserAgent());
+            conn.setRequestProperty("Accept", ACCEPT_HEADER_VALUE);
             conn.setRequestProperty("Accept-Encoding", "gzip,deflate");
             if (conn instanceof HttpURLConnection) {
                 HttpURLConnection httpCon = (HttpURLConnection) conn;
@@ -245,6 +249,7 @@ public class BasicURLHandler extends AbstractURLHandler implements TimeoutConstr
             srcConn.setConnectTimeout(connectionTimeout);
             srcConn.setReadTimeout(readTimeout);
             srcConn.setRequestProperty("User-Agent", getUserAgent());
+            srcConn.setRequestProperty("Accept", ACCEPT_HEADER_VALUE);
             srcConn.setRequestProperty("Accept-Encoding", "gzip,deflate");
             if (srcConn instanceof HttpURLConnection) {
                 HttpURLConnection httpCon = (HttpURLConnection) srcConn;


=====================================
version.properties
=====================================
@@ -16,9 +16,9 @@
 #	 * specific language governing permissions and limitations
 #	 * under the License.
 #	 ***************************************************************
-target.ivy.version=2.5.0
+target.ivy.version=2.5.1
 # Following OSGi spec: have to be 3 numbers separated by dots
-target.ivy.bundle.version=2.5.0
+target.ivy.bundle.version=2.5.1
 # in case we want to add a qualifier such as alpha, beta, etc...
 # if non empty, add a '_' at the end of the qualifier, so the version would look like 1.2.3.alpha_200901011200
 # NB: be careful with naming, OSGi orders version alphabetically. Suggested values: alpha_, beta_, cr1_ (for RC-1), final_
@@ -31,10 +31,11 @@ target.ivy.bundle.version.qualifier=final_
 # running Ant, so we could not use that name here.
 apache-ant.version=1.9.14
 ant-contrib.version=1.0b3
-bouncycastle.version=1.62
+bouncycastle.version=1.64
 commons-vfs2.version=2.2
 hamcrest.version=1.3
-httpclient.version=4.5.9
+httpclient.version=4.5.10
+jacoco.version=0.8.6
 jsch.agentproxy.version=0.0.9
 jsch.version=0.1.55
 junit.version=4.12



View it on GitLab: https://salsa.debian.org/java-team/ivy/-/commit/06e278b3bdf4609263ddd056f5fdeaf6fb6d7827

-- 
View it on GitLab: https://salsa.debian.org/java-team/ivy/-/commit/06e278b3bdf4609263ddd056f5fdeaf6fb6d7827
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-java-commits/attachments/20221205/cbe5168a/attachment.htm>


More information about the pkg-java-commits mailing list