[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