diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.tpd
index 938d80b87..b6a4d6abb 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.9.tpd
@@ -1,7 +1,7 @@
target "jgit-4.9" with source configurePhase
include "projects/jetty-9.4.x.tpd"
-include "orbit/R20210602031627-2021-06.tpd"
+include "orbit/R20210825222808-2021-09.tpd"
location "https://download.eclipse.org/releases/2018-09/" {
org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20210825222808-2021-09.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20210825222808-2021-09.tpd
new file mode 100644
index 000000000..059a5844a
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20210825222808-2021-09.tpd
@@ -0,0 +1,69 @@
+target "R20210825222808-2021-09" with source configurePhase
+// see https://download.eclipse.org/tools/orbit/downloads/
+
+location "https://download.eclipse.org/tools/orbit/downloads/drops/R20210825222808/repository" {
+ com.google.gson [2.8.7.v20210624-1215,2.8.7.v20210624-1215]
+ com.google.gson.source [2.8.7.v20210624-1215,2.8.7.v20210624-1215]
+ com.jcraft.jsch [0.1.55.v20190404-1902,0.1.55.v20190404-1902]
+ com.jcraft.jsch.source [0.1.55.v20190404-1902,0.1.55.v20190404-1902]
+ com.jcraft.jzlib [1.1.1.v201205102305,1.1.1.v201205102305]
+ com.jcraft.jzlib.source [1.1.1.v201205102305,1.1.1.v201205102305]
+ javaewah [1.1.12.v20210622-2206,1.1.12.v20210622-2206]
+ javaewah.source [1.1.12.v20210622-2206,1.1.12.v20210622-2206]
+ javax.servlet [3.1.0.v201410161800,3.1.0.v201410161800]
+ javax.servlet.source [3.1.0.v201410161800,3.1.0.v201410161800]
+ net.bytebuddy.byte-buddy [1.9.0.v20181107-1410,1.9.0.v20181107-1410]
+ net.bytebuddy.byte-buddy-agent [1.9.0.v20181106-1534,1.9.0.v20181106-1534]
+ net.bytebuddy.byte-buddy-agent.source [1.9.0.v20181106-1534,1.9.0.v20181106-1534]
+ net.bytebuddy.byte-buddy.source [1.9.0.v20181107-1410,1.9.0.v20181107-1410]
+ net.i2p.crypto.eddsa [0.3.0.v20181102-1323,0.3.0.v20181102-1323]
+ net.i2p.crypto.eddsa.source [0.3.0.v20181102-1323,0.3.0.v20181102-1323]
+ org.apache.ant [1.10.11.v20210720-1445,1.10.11.v20210720-1445]
+ org.apache.ant.source [1.10.11.v20210720-1445,1.10.11.v20210720-1445]
+ org.apache.commons.codec [1.14.0.v20200818-1422,1.14.0.v20200818-1422]
+ org.apache.commons.codec.source [1.14.0.v20200818-1422,1.14.0.v20200818-1422]
+ org.apache.commons.compress [1.20.0.v20210713-1928,1.20.0.v20210713-1928]
+ org.apache.commons.compress.source [1.20.0.v20210713-1928,1.20.0.v20210713-1928]
+ org.apache.commons.logging [1.2.0.v20180409-1502,1.2.0.v20180409-1502]
+ org.apache.commons.logging.source [1.2.0.v20180409-1502,1.2.0.v20180409-1502]
+ org.apache.httpcomponents.httpclient [4.5.13.v20210128-2225,4.5.13.v20210128-2225]
+ org.apache.httpcomponents.httpclient.source [4.5.13.v20210128-2225,4.5.13.v20210128-2225]
+ org.apache.httpcomponents.httpcore [4.4.14.v20210128-2225,4.4.14.v20210128-2225]
+ org.apache.httpcomponents.httpcore.source [4.4.14.v20210128-2225,4.4.14.v20210128-2225]
+ org.apache.log4j [1.2.15.v201012070815,1.2.15.v201012070815]
+ org.apache.log4j.source [1.2.15.v201012070815,1.2.15.v201012070815]
+ org.apache.sshd.osgi [2.7.0.v20210623-0618,2.7.0.v20210623-0618]
+ org.apache.sshd.osgi.source [2.7.0.v20210623-0618,2.7.0.v20210623-0618]
+ org.apache.sshd.sftp [2.7.0.v20210623-0618,2.7.0.v20210623-0618]
+ org.apache.sshd.sftp.source [2.7.0.v20210623-0618,2.7.0.v20210623-0618]
+ org.assertj [3.20.2.v20210706-1104,3.20.2.v20210706-1104]
+ org.assertj.source [3.20.2.v20210706-1104,3.20.2.v20210706-1104]
+ org.bouncycastle.bcpg [1.69.0.v20210713-1924,1.69.0.v20210713-1924]
+ org.bouncycastle.bcpg.source [1.69.0.v20210713-1924,1.69.0.v20210713-1924]
+ org.bouncycastle.bcpkix [1.69.0.v20210713-1924,1.69.0.v20210713-1924]
+ org.bouncycastle.bcpkix.source [1.69.0.v20210713-1924,1.69.0.v20210713-1924]
+ org.bouncycastle.bcprov [1.69.0.v20210713-1924,1.69.0.v20210713-1924]
+ org.bouncycastle.bcprov.source [1.69.0.v20210713-1924,1.69.0.v20210713-1924]
+ org.bouncycastle.bcutil [1.69.0.v20210713-1924,1.69.0.v20210713-1924]
+ org.bouncycastle.bcutil.source [1.69.0.v20210713-1924,1.69.0.v20210713-1924]
+ org.hamcrest [2.2.0.v20210711-0821,2.2.0.v20210711-0821]
+ org.hamcrest.source [2.2.0.v20210711-0821,2.2.0.v20210711-0821]
+ org.hamcrest.core [1.3.0.v20180420-1519,1.3.0.v20180420-1519]
+ org.hamcrest.core.source [1.3.0.v20180420-1519,1.3.0.v20180420-1519]
+ org.hamcrest.library [1.3.0.v20180524-2246,1.3.0.v20180524-2246]
+ org.hamcrest.library.source [1.3.0.v20180524-2246,1.3.0.v20180524-2246]
+ org.junit [4.13.0.v20200204-1500,4.13.0.v20200204-1500]
+ org.junit.source [4.13.0.v20200204-1500,4.13.0.v20200204-1500]
+ org.kohsuke.args4j [2.33.0.v20160323-2218,2.33.0.v20160323-2218]
+ org.kohsuke.args4j.source [2.33.0.v20160323-2218,2.33.0.v20160323-2218]
+ org.mockito [2.23.0.v20200310-1642,2.23.0.v20200310-1642]
+ org.mockito.source [2.23.0.v20200310-1642,2.23.0.v20200310-1642]
+ org.objenesis [2.6.0.v20180420-1519,2.6.0.v20180420-1519]
+ org.objenesis.source [2.6.0.v20180420-1519,2.6.0.v20180420-1519]
+ org.slf4j.api [1.7.30.v20200204-2150,1.7.30.v20200204-2150]
+ org.slf4j.api.source [1.7.30.v20200204-2150,1.7.30.v20200204-2150]
+ org.slf4j.binding.log4j12 [1.7.30.v20201108-2042,1.7.30.v20201108-2042]
+ org.slf4j.binding.log4j12.source [1.7.30.v20201108-2042,1.7.30.v20201108-2042]
+ org.tukaani.xz [1.9.0.v20210624-1259,1.9.0.v20210624-1259]
+ org.tukaani.xz.source [1.9.0.v20210624-1259,1.9.0.v20210624-1259]
+}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.x.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.x.tpd
index 8645e9ba2..bcfd22169 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.x.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/projects/jetty-9.4.x.tpd
@@ -1,22 +1,22 @@
target "jetty-9.4.x" with source configurePhase
-location jetty-9.4.40 "https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.42.v20210604/" {
- org.eclipse.jetty.client [9.4.42.v20210604,9.4.42.v20210604]
- org.eclipse.jetty.client.source [9.4.42.v20210604,9.4.42.v20210604]
- org.eclipse.jetty.continuation [9.4.42.v20210604,9.4.42.v20210604]
- org.eclipse.jetty.continuation.source [9.4.42.v20210604,9.4.42.v20210604]
- org.eclipse.jetty.http [9.4.42.v20210604,9.4.42.v20210604]
- org.eclipse.jetty.http.source [9.4.42.v20210604,9.4.42.v20210604]
- org.eclipse.jetty.io [9.4.42.v20210604,9.4.42.v20210604]
- org.eclipse.jetty.io.source [9.4.42.v20210604,9.4.42.v20210604]
- org.eclipse.jetty.security [9.4.42.v20210604,9.4.42.v20210604]
- org.eclipse.jetty.security.source [9.4.42.v20210604,9.4.42.v20210604]
- org.eclipse.jetty.server [9.4.42.v20210604,9.4.42.v20210604]
- org.eclipse.jetty.server.source [9.4.42.v20210604,9.4.42.v20210604]
- org.eclipse.jetty.servlet [9.4.42.v20210604,9.4.42.v20210604]
- org.eclipse.jetty.servlet.source [9.4.42.v20210604,9.4.42.v20210604]
- org.eclipse.jetty.util [9.4.42.v20210604,9.4.42.v20210604]
- org.eclipse.jetty.util.source [9.4.42.v20210604,9.4.42.v20210604]
- org.eclipse.jetty.util.ajax [9.4.42.v20210604,9.4.42.v20210604]
- org.eclipse.jetty.util.ajax.source [9.4.42.v20210604,9.4.42.v20210604]
+location jetty-9.4.x "https://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.4.43.v20210629/" {
+ org.eclipse.jetty.client [9.4.43.v20210629,9.4.43.v20210629]
+ org.eclipse.jetty.client.source [9.4.43.v20210629,9.4.43.v20210629]
+ org.eclipse.jetty.continuation [9.4.43.v20210629,9.4.43.v20210629]
+ org.eclipse.jetty.continuation.source [9.4.43.v20210629,9.4.43.v20210629]
+ org.eclipse.jetty.http [9.4.43.v20210629,9.4.43.v20210629]
+ org.eclipse.jetty.http.source [9.4.43.v20210629,9.4.43.v20210629]
+ org.eclipse.jetty.io [9.4.43.v20210629,9.4.43.v20210629]
+ org.eclipse.jetty.io.source [9.4.43.v20210629,9.4.43.v20210629]
+ org.eclipse.jetty.security [9.4.43.v20210629,9.4.43.v20210629]
+ org.eclipse.jetty.security.source [9.4.43.v20210629,9.4.43.v20210629]
+ org.eclipse.jetty.server [9.4.43.v20210629,9.4.43.v20210629]
+ org.eclipse.jetty.server.source [9.4.43.v20210629,9.4.43.v20210629]
+ org.eclipse.jetty.servlet [9.4.43.v20210629,9.4.43.v20210629]
+ org.eclipse.jetty.servlet.source [9.4.43.v20210629,9.4.43.v20210629]
+ org.eclipse.jetty.util [9.4.43.v20210629,9.4.43.v20210629]
+ org.eclipse.jetty.util.source [9.4.43.v20210629,9.4.43.v20210629]
+ org.eclipse.jetty.util.ajax [9.4.43.v20210629,9.4.43.v20210629]
+ org.eclipse.jetty.util.ajax.source [9.4.43.v20210629,9.4.43.v20210629]
}
diff --git a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
index 809f438e9..52b59a370 100644
--- a/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.pgm.test/META-INF/MANIFEST.MF
@@ -25,7 +25,7 @@ Import-Package: org.eclipse.jgit.api;version="[6.0.0,6.1.0)",
org.eclipse.jgit.treewalk;version="[6.0.0,6.1.0)",
org.eclipse.jgit.util;version="[6.0.0,6.1.0)",
org.eclipse.jgit.util.io;version="[6.0.0,6.1.0)",
- org.hamcrest.core;bundle-version="[1.1.0,2.0.0)",
+ org.hamcrest.core;bundle-version="[2.2.0,3.0.0)",
org.junit;version="[4.13,5.0.0)",
org.junit.rules;version="[4.13,5.0.0)",
org.kohsuke.args4j;version="[2.33.0,3.0.0)"
diff --git a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
index 38deab99a..97450033e 100644
--- a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
+++ b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
@@ -8,7 +8,7 @@ VAL=VAL
# default meta variable defined in the org.kohsuke.args4j.spi.ExplicitBooleanOptionHandler
VALUE=VAL
# default meta variable defined in the org.kohsuke.args4j.spi.StopOptionHandler
-ARGUMENTS=ARGUMENTS
+ARGS=ARGS
# default meta variable defined in the org.kohsuke.args4j.spi.OneArgumentOptionHandler
N=N
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/TextBuiltin.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/TextBuiltin.java
index f70e72d43..600200d71 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/TextBuiltin.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/TextBuiltin.java
@@ -219,8 +219,12 @@ public final void execute(String[] args) throws Exception {
case APACHE: {
SshdSessionFactory factory = new SshdSessionFactory(
new JGitKeyCache(), new DefaultProxyDataFactory());
- Runtime.getRuntime()
- .addShutdownHook(new Thread(factory::close));
+ try {
+ Runtime.getRuntime()
+ .addShutdownHook(new Thread(factory::close));
+ } catch (IllegalStateException e) {
+ // ignore - the VM is already shutting down
+ }
SshSessionFactory.setInstance(factory);
break;
}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/PathTreeFilterHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/PathTreeFilterHandler.java
index 96c72d9dc..653511947 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/PathTreeFilterHandler.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/PathTreeFilterHandler.java
@@ -25,7 +25,7 @@
import org.kohsuke.args4j.spi.Setter;
/**
- * Create a {@link org.eclipse.jgit.treewalk.filter.TreeFilter} to patch math
+ * Create a {@link org.eclipse.jgit.treewalk.filter.TreeFilter} to match path
* names.
*
* This handler consumes all arguments to the end of the command line, and is
diff --git a/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF
index 007073012..1b885af92 100644
--- a/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ssh.apache.test/META-INF/MANIFEST.MF
@@ -7,19 +7,20 @@ Bundle-Version: 6.0.0.qualifier
Bundle-Vendor: %Bundle-Vendor
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
-Import-Package: org.apache.sshd.client.config.hosts;version="[2.6.0,2.7.0)",
- org.apache.sshd.common;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.auth;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.config.keys;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.helpers;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.keyprovider;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.session;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.signature;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.util.net;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.util.security;version="[2.6.0,2.7.0)",
- org.apache.sshd.core;version="[2.6.0,2.7.0)",
- org.apache.sshd.server;version="[2.6.0,2.7.0)",
- org.apache.sshd.server.forward;version="[2.6.0,2.7.0)",
+Import-Package: org.apache.sshd.client.config.hosts;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.auth;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.config.keys;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.helpers;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.kex;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.keyprovider;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.session;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.signature;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.util.net;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.util.security;version="[2.7.0,2.8.0)",
+ org.apache.sshd.core;version="[2.7.0,2.8.0)",
+ org.apache.sshd.server;version="[2.7.0,2.8.0)",
+ org.apache.sshd.server.forward;version="[2.7.0,2.8.0)",
org.eclipse.jgit.api;version="[6.0.0,6.1.0)",
org.eclipse.jgit.api.errors;version="[6.0.0,6.1.0)",
org.eclipse.jgit.internal.transport.sshd.proxy;version="[6.0.0,6.1.0)",
@@ -29,7 +30,7 @@ Import-Package: org.apache.sshd.client.config.hosts;version="[2.6.0,2.7.0)",
org.eclipse.jgit.transport;version="[6.0.0,6.1.0)",
org.eclipse.jgit.transport.sshd;version="[6.0.0,6.1.0)",
org.eclipse.jgit.util;version="[6.0.0,6.1.0)",
+ org.hamcrest;version="[1.1.0,3.0.0)",
org.junit;version="[4.13,5.0.0)",
org.junit.experimental.theories;version="[4.13,5.0.0)",
org.junit.runner;version="[4.13,5.0.0)"
-Require-Bundle: org.hamcrest.core;bundle-version="[1.3.0,2.0.0)"
diff --git a/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/ApacheSshTest.java b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/ApacheSshTest.java
index c56d2307c..c1f5fef3c 100644
--- a/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/ApacheSshTest.java
+++ b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/transport/sshd/ApacheSshTest.java
@@ -34,13 +34,18 @@
import org.apache.sshd.client.config.hosts.KnownHostEntry;
import org.apache.sshd.client.config.hosts.KnownHostHashValue;
+import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.config.keys.AuthorizedKeyEntry;
import org.apache.sshd.common.config.keys.KeyUtils;
import org.apache.sshd.common.config.keys.PublicKeyEntry;
import org.apache.sshd.common.config.keys.PublicKeyEntryResolver;
+import org.apache.sshd.common.kex.BuiltinDHFactories;
+import org.apache.sshd.common.kex.DHFactory;
+import org.apache.sshd.common.kex.KeyExchangeFactory;
import org.apache.sshd.common.session.Session;
import org.apache.sshd.common.util.net.SshdSocketAddress;
import org.apache.sshd.server.ServerAuthenticationManager;
+import org.apache.sshd.server.ServerBuilder;
import org.apache.sshd.server.SshServer;
import org.apache.sshd.server.forward.StaticDecisionForwardingFilter;
import org.eclipse.jgit.api.Git;
@@ -702,4 +707,42 @@ public void testConnectAuthSshRsa() throws Exception {
session.disconnect();
}
}
+
+ /**
+ * Tests that one can log in at an even poorer server that also only has the
+ * SHA1 KEX methods available. Apparently this is the case for at least some
+ * Microsoft TFS instances. The user has to enable the poor KEX methods in
+ * the ssh config explicitly; we don't enable them by default.
+ *
+ * @throws Exception
+ * on failure
+ */
+ @Test
+ public void testConnectOnlyRsaSha1() throws Exception {
+ try (SshServer oldServer = createServer(TEST_USER, publicKey1)) {
+ oldServer.setSignatureFactoriesNames("ssh-rsa");
+ List sha1Factories = BuiltinDHFactories
+ .parseDHFactoriesList(
+ "diffie-hellman-group1-sha1,diffie-hellman-group14-sha1")
+ .getParsedFactories();
+ assertEquals(2, sha1Factories.size());
+ List kexFactories = NamedFactory
+ .setUpTransformedFactories(true, sha1Factories,
+ ServerBuilder.DH2KEX);
+ oldServer.setKeyExchangeFactories(kexFactories);
+ oldServer.start();
+ registerServer(oldServer);
+ installConfig("Host server", //
+ "HostName localhost", //
+ "Port " + oldServer.getPort(), //
+ "User " + TEST_USER, //
+ "IdentityFile " + privateKey1.getAbsolutePath(), //
+ "KexAlgorithms +diffie-hellman-group1-sha1");
+ RemoteSession session = getSessionFactory().getSession(
+ new URIish("ssh://server/doesntmatter"), null, FS.DETECTED,
+ 10000);
+ assertNotNull(session);
+ session.disconnect();
+ }
+ }
}
diff --git a/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF b/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF
index 89b5133af..03b046271 100644
--- a/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF
@@ -33,53 +33,53 @@ Export-Package: org.eclipse.jgit.internal.transport.sshd;version="6.0.0";x-inter
org.apache.sshd.client.session,
org.apache.sshd.client.keyverifier"
Import-Package: net.i2p.crypto.eddsa;version="[0.3.0,0.4.0)",
- org.apache.sshd.agent;version="[2.6.0,2.7.0)",
- org.apache.sshd.client;version="[2.6.0,2.7.0)",
- org.apache.sshd.client.auth;version="[2.6.0,2.7.0)",
- org.apache.sshd.client.auth.keyboard;version="[2.6.0,2.7.0)",
- org.apache.sshd.client.auth.password;version="[2.6.0,2.7.0)",
- org.apache.sshd.client.auth.pubkey;version="[2.6.0,2.7.0)",
- org.apache.sshd.client.channel;version="[2.6.0,2.7.0)",
- org.apache.sshd.client.config.hosts;version="[2.6.0,2.7.0)",
- org.apache.sshd.client.config.keys;version="[2.6.0,2.7.0)",
- org.apache.sshd.client.future;version="[2.6.0,2.7.0)",
- org.apache.sshd.client.keyverifier;version="[2.6.0,2.7.0)",
- org.apache.sshd.client.session;version="[2.6.0,2.7.0)",
- org.apache.sshd.client.session.forward;version="[2.6.0,2.7.0)",
- org.apache.sshd.common;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.auth;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.channel;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.compression;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.config.keys;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.config.keys.loader;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.config.keys.loader.openssh.kdf;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.digest;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.forward;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.future;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.helpers;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.io;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.kex;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.kex.extension;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.kex.extension.parser;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.keyprovider;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.mac;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.random;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.session;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.session.helpers;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.signature;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.util;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.util.buffer;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.util.closeable;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.util.io;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.util.io.resource;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.util.logging;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.util.net;version="[2.6.0,2.7.0)",
- org.apache.sshd.common.util.security;version="[2.6.0,2.7.0)",
- org.apache.sshd.core;version="[2.6.0,2.7.0)",
- org.apache.sshd.server.auth;version="[2.6.0,2.7.0)",
- org.apache.sshd.sftp;version="[2.6.0,2.7.0)",
- org.apache.sshd.sftp.client;version="[2.6.0,2.7.0)",
- org.apache.sshd.sftp.common;version="[2.6.0,2.7.0)",
+ org.apache.sshd.agent;version="[2.7.0,2.8.0)",
+ org.apache.sshd.client;version="[2.7.0,2.8.0)",
+ org.apache.sshd.client.auth;version="[2.7.0,2.8.0)",
+ org.apache.sshd.client.auth.keyboard;version="[2.7.0,2.8.0)",
+ org.apache.sshd.client.auth.password;version="[2.7.0,2.8.0)",
+ org.apache.sshd.client.auth.pubkey;version="[2.7.0,2.8.0)",
+ org.apache.sshd.client.channel;version="[2.7.0,2.8.0)",
+ org.apache.sshd.client.config.hosts;version="[2.7.0,2.8.0)",
+ org.apache.sshd.client.config.keys;version="[2.7.0,2.8.0)",
+ org.apache.sshd.client.future;version="[2.7.0,2.8.0)",
+ org.apache.sshd.client.keyverifier;version="[2.7.0,2.8.0)",
+ org.apache.sshd.client.session;version="[2.7.0,2.8.0)",
+ org.apache.sshd.client.session.forward;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.auth;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.channel;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.compression;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.config.keys;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.config.keys.loader;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.config.keys.loader.openssh.kdf;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.digest;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.forward;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.future;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.helpers;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.io;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.kex;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.kex.extension;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.kex.extension.parser;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.keyprovider;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.mac;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.random;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.session;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.session.helpers;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.signature;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.util;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.util.buffer;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.util.closeable;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.util.io;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.util.io.resource;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.util.logging;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.util.net;version="[2.7.0,2.8.0)",
+ org.apache.sshd.common.util.security;version="[2.7.0,2.8.0)",
+ org.apache.sshd.core;version="[2.7.0,2.8.0)",
+ org.apache.sshd.server.auth;version="[2.7.0,2.8.0)",
+ org.apache.sshd.sftp;version="[2.7.0,2.8.0)",
+ org.apache.sshd.sftp.client;version="[2.7.0,2.8.0)",
+ org.apache.sshd.sftp.common;version="[2.7.0,2.8.0)",
org.eclipse.jgit.annotations;version="[6.0.0,6.1.0)",
org.eclipse.jgit.errors;version="[6.0.0,6.1.0)",
org.eclipse.jgit.fnmatch;version="[6.0.0,6.1.0)",
diff --git a/org.eclipse.jgit.ssh.apache/resources/org/eclipse/jgit/internal/transport/sshd/SshdText.properties b/org.eclipse.jgit.ssh.apache/resources/org/eclipse/jgit/internal/transport/sshd/SshdText.properties
index 5bc086767..defcbdcfc 100644
--- a/org.eclipse.jgit.ssh.apache/resources/org/eclipse/jgit/internal/transport/sshd/SshdText.properties
+++ b/org.eclipse.jgit.ssh.apache/resources/org/eclipse/jgit/internal/transport/sshd/SshdText.properties
@@ -8,6 +8,7 @@ configInvalidProxyJump=Ssh config, host ''{0}'': Cannot parse ProxyJump ''{1}''
configNoKnownAlgorithms=Ssh config ''{0}'' ''{1}'' resulted in empty list (none known, or all known removed); using default.
configProxyJumpNotSsh=Non-ssh URI in ProxyJump ssh config
configProxyJumpWithPath=ProxyJump ssh config: jump host specification must not have a path
+configUnknownAlgorithm=Ssh config {0}: ignoring unknown algorithm ''{1}'' in {2} {3}
ftpCloseFailed=Closing the SFTP channel failed
gssapiFailure=GSS-API error for mechanism OID {0}
gssapiInitFailure=GSS-API initialization failure for mechanism {0}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java
index f9e80121e..f7b37d781 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitClientSession.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018, 2019 Thomas Wolf and others
+ * Copyright (C) 2018, 2021 Thomas Wolf and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -16,7 +16,6 @@
import java.io.StreamCorruptedException;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets;
-import java.security.GeneralSecurityException;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.Collection;
@@ -29,17 +28,27 @@
import java.util.Objects;
import java.util.Set;
+import org.apache.sshd.client.ClientBuilder;
import org.apache.sshd.client.ClientFactoryManager;
import org.apache.sshd.client.config.hosts.HostConfigEntry;
import org.apache.sshd.client.keyverifier.ServerKeyVerifier;
import org.apache.sshd.client.session.ClientSessionImpl;
import org.apache.sshd.common.AttributeRepository;
import org.apache.sshd.common.FactoryManager;
+import org.apache.sshd.common.NamedResource;
import org.apache.sshd.common.PropertyResolver;
import org.apache.sshd.common.config.keys.KeyUtils;
import org.apache.sshd.common.io.IoSession;
import org.apache.sshd.common.io.IoWriteFuture;
+import org.apache.sshd.common.kex.BuiltinDHFactories;
+import org.apache.sshd.common.kex.DHFactory;
import org.apache.sshd.common.kex.KexProposalOption;
+import org.apache.sshd.common.kex.KeyExchangeFactory;
+import org.apache.sshd.common.kex.extension.KexExtensionHandler;
+import org.apache.sshd.common.kex.extension.KexExtensionHandler.AvailabilityPhase;
+import org.apache.sshd.common.kex.extension.KexExtensions;
+import org.apache.sshd.common.keyprovider.KeyPairProvider;
+import org.apache.sshd.common.signature.BuiltinSignatures;
import org.apache.sshd.common.util.Readable;
import org.apache.sshd.common.util.buffer.Buffer;
import org.eclipse.jgit.errors.InvalidPatternException;
@@ -70,6 +79,8 @@ public class JGitClientSession extends ClientSessionImpl {
*/
private static final int DEFAULT_MAX_IDENTIFICATION_SIZE = 64 * 1024;
+ private static final AttributeKey INITIAL_KEX_DONE = new AttributeKey<>();
+
private HostConfigEntry hostConfig;
private CredentialsProvider credentialsProvider;
@@ -136,51 +147,38 @@ public void setProxyHandler(StatefulProxyConnector handler) {
}
@Override
- protected IoWriteFuture sendIdentification(String ident)
- throws IOException {
+ protected IoWriteFuture sendIdentification(String ident,
+ List extraLines) throws Exception {
StatefulProxyConnector proxy = proxyHandler;
if (proxy != null) {
- try {
- // We must not block here; the framework starts reading messages
- // from the peer only once the initial sendKexInit() following
- // this call to sendIdentification() has returned!
- proxy.runWhenDone(() -> {
- JGitClientSession.super.sendIdentification(ident);
- return null;
- });
- // Called only from the ClientSessionImpl constructor, where the
- // return value is ignored.
+ // We must not block here; the framework starts reading messages
+ // from the peer only once the initial sendKexInit() following
+ // this call to sendIdentification() has returned!
+ proxy.runWhenDone(() -> {
+ JGitClientSession.super.sendIdentification(ident, extraLines);
return null;
- } catch (IOException e) {
- throw e;
- } catch (Exception other) {
- throw new IOException(other.getLocalizedMessage(), other);
- }
+ });
+ // Called only from the ClientSessionImpl constructor, where the
+ // return value is ignored.
+ return null;
}
- return super.sendIdentification(ident);
+ return super.sendIdentification(ident, extraLines);
}
@Override
- protected byte[] sendKexInit()
- throws IOException, GeneralSecurityException {
+ protected byte[] sendKexInit() throws Exception {
StatefulProxyConnector proxy = proxyHandler;
if (proxy != null) {
- try {
- // We must not block here; the framework starts reading messages
- // from the peer only once the initial sendKexInit() has
- // returned!
- proxy.runWhenDone(() -> {
- JGitClientSession.super.sendKexInit();
- return null;
- });
- // This is called only from the ClientSessionImpl
- // constructor, where the return value is ignored.
+ // We must not block here; the framework starts reading messages
+ // from the peer only once the initial sendKexInit() has
+ // returned!
+ proxy.runWhenDone(() -> {
+ JGitClientSession.super.sendKexInit();
return null;
- } catch (IOException | GeneralSecurityException e) {
- throw e;
- } catch (Exception other) {
- throw new IOException(other.getLocalizedMessage(), other);
- }
+ });
+ // This is called only from the ClientSessionImpl
+ // constructor, where the return value is ignored.
+ return null;
}
return super.sendKexInit();
}
@@ -219,6 +217,32 @@ protected Map setNegotiationResult(
return result;
}
+ Set getAllAvailableSignatureAlgorithms() {
+ Set allAvailable = new HashSet<>();
+ BuiltinSignatures.VALUES.forEach(s -> allAvailable.add(s.getName()));
+ BuiltinSignatures.getRegisteredExtensions()
+ .forEach(s -> allAvailable.add(s.getName()));
+ return allAvailable;
+ }
+
+ private void setNewFactories(Collection defaultFactories,
+ Collection finalFactories) {
+ // If new factory names were added make sure we actually have factories
+ // for them all.
+ //
+ // But add new ones at the end: we don't want to change the order for
+ // pubkey auth, and any new ones added here were not included in the
+ // default set for some reason, such as being deprecated or weak.
+ //
+ // The order for KEX is determined by the order in the proposal string,
+ // but the order in pubkey auth is determined by the order in the
+ // factory list (possibly overridden via ssh config
+ // PubkeyAcceptedAlgorithms; see JGitPublicKeyAuthentication).
+ Set resultSet = new LinkedHashSet<>(defaultFactories);
+ resultSet.addAll(finalFactories);
+ setSignatureFactoriesNames(resultSet);
+ }
+
@Override
protected String resolveAvailableSignaturesProposal(
FactoryManager manager) {
@@ -229,16 +253,17 @@ protected String resolveAvailableSignaturesProposal(
.getProperty(SshConstants.HOST_KEY_ALGORITHMS);
if (!StringUtils.isEmptyOrNull(algorithms)) {
List result = modifyAlgorithmList(defaultSignatures,
- algorithms, SshConstants.HOST_KEY_ALGORITHMS);
+ getAllAvailableSignatureAlgorithms(), algorithms,
+ SshConstants.HOST_KEY_ALGORITHMS);
if (!result.isEmpty()) {
if (log.isDebugEnabled()) {
log.debug(SshConstants.HOST_KEY_ALGORITHMS + ' ' + result);
}
+ setNewFactories(defaultSignatures, result);
return String.join(",", result); //$NON-NLS-1$
}
log.warn(format(SshdText.get().configNoKnownAlgorithms,
- SshConstants.HOST_KEY_ALGORITHMS,
- algorithms));
+ SshConstants.HOST_KEY_ALGORITHMS, algorithms));
}
// No HostKeyAlgorithms; using default -- change order to put existing
// keys first.
@@ -253,6 +278,11 @@ protected String resolveAvailableSignaturesProposal(
if (key != null) {
String keyType = KeyUtils.getKeyType(key);
if (keyType != null) {
+ if (KeyPairProvider.SSH_RSA.equals(keyType)) {
+ // Add all available signatures for ssh-rsa.
+ reordered.add(KeyUtils.RSA_SHA512_KEY_TYPE_ALIAS);
+ reordered.add(KeyUtils.RSA_SHA256_KEY_TYPE_ALIAS);
+ }
reordered.add(keyType);
}
}
@@ -261,6 +291,10 @@ protected String resolveAvailableSignaturesProposal(
if (log.isDebugEnabled()) {
log.debug(SshConstants.HOST_KEY_ALGORITHMS + ' ' + reordered);
}
+ // Make sure we actually have factories for them all.
+ if (reordered.size() > defaultSignatures.size()) {
+ setNewFactories(defaultSignatures, reordered);
+ }
return String.join(",", reordered); //$NON-NLS-1$
}
if (log.isDebugEnabled()) {
@@ -270,15 +304,87 @@ protected String resolveAvailableSignaturesProposal(
return String.join(",", defaultSignatures); //$NON-NLS-1$
}
+ private List determineKexProposal() {
+ List kexFactories = getKeyExchangeFactories();
+ List defaultKexMethods = NamedResource
+ .getNameList(kexFactories);
+ HostConfigEntry config = resolveAttribute(
+ JGitSshClient.HOST_CONFIG_ENTRY);
+ String algorithms = config.getProperty(SshConstants.KEX_ALGORITHMS);
+ if (!StringUtils.isEmptyOrNull(algorithms)) {
+ Set allAvailable = new HashSet<>();
+ BuiltinDHFactories.VALUES
+ .forEach(s -> allAvailable.add(s.getName()));
+ BuiltinDHFactories.getRegisteredExtensions()
+ .forEach(s -> allAvailable.add(s.getName()));
+ List result = modifyAlgorithmList(defaultKexMethods,
+ allAvailable, algorithms, SshConstants.KEX_ALGORITHMS);
+ if (!result.isEmpty()) {
+ // If new ones were added, update the installed factories
+ Set configuredKexMethods = new HashSet<>(
+ defaultKexMethods);
+ List newKexFactories = new ArrayList<>();
+ result.forEach(name -> {
+ if (!configuredKexMethods.contains(name)) {
+ DHFactory factory = BuiltinDHFactories
+ .resolveFactory(name);
+ if (factory == null) {
+ // Should not occur here
+ if (log.isDebugEnabled()) {
+ log.debug(
+ "determineKexProposal({}) unknown KEX algorithm {} ignored", //$NON-NLS-1$
+ this, name);
+ }
+ } else {
+ newKexFactories
+ .add(ClientBuilder.DH2KEX.apply(factory));
+ }
+ }
+ });
+ if (!newKexFactories.isEmpty()) {
+ newKexFactories.addAll(kexFactories);
+ setKeyExchangeFactories(newKexFactories);
+ }
+ return result;
+ }
+ log.warn(format(SshdText.get().configNoKnownAlgorithms,
+ SshConstants.KEX_ALGORITHMS, algorithms));
+ }
+ return defaultKexMethods;
+ }
+
+ @Override
+ protected String resolveSessionKexProposal(String hostKeyTypes)
+ throws IOException {
+ String kexMethods = String.join(",", determineKexProposal()); //$NON-NLS-1$
+ Boolean isRekey = getAttribute(INITIAL_KEX_DONE);
+ if (isRekey == null || !isRekey.booleanValue()) {
+ // First time
+ KexExtensionHandler extHandler = getKexExtensionHandler();
+ if (extHandler != null && extHandler.isKexExtensionsAvailable(this,
+ AvailabilityPhase.PROPOSAL)) {
+ if (kexMethods.isEmpty()) {
+ kexMethods = KexExtensions.CLIENT_KEX_EXTENSION;
+ } else {
+ kexMethods += ',' + KexExtensions.CLIENT_KEX_EXTENSION;
+ }
+ }
+ setAttribute(INITIAL_KEX_DONE, Boolean.TRUE);
+ }
+ if (log.isDebugEnabled()) {
+ log.debug(SshConstants.KEX_ALGORITHMS + ' ' + kexMethods);
+ }
+ return kexMethods;
+ }
+
/**
* Modifies a given algorithm list according to a list from the ssh config,
- * including remove ('-') and reordering ('^') operators. Addition ('+') is
- * not handled since we have no way of adding dynamically implementations,
- * and the defaultList is supposed to contain all known implementations
- * already.
+ * including add ('+'), remove ('-') and reordering ('^') operators.
*
* @param defaultList
* to modify
+ * @param allAvailable
+ * all available values
* @param fromConfig
* telling how to modify the {@code defaultList}, must not be
* {@code null} or empty
@@ -288,22 +394,22 @@ protected String resolveAvailableSignaturesProposal(
* set
*/
public List modifyAlgorithmList(List defaultList,
- String fromConfig, String overrideKey) {
+ Set allAvailable, String fromConfig, String overrideKey) {
Set defaults = new LinkedHashSet<>();
defaults.addAll(defaultList);
switch (fromConfig.charAt(0)) {
case '+':
- // Additions make not much sense -- it's either in
- // defaultList already, or we have no implementation for
- // it. No point in proposing it.
- return defaultList;
+ List newSignatures = filteredList(allAvailable, overrideKey,
+ fromConfig.substring(1));
+ defaults.addAll(newSignatures);
+ return new ArrayList<>(defaults);
case '-':
// This takes wildcard patterns!
removeFromList(defaults, overrideKey, fromConfig.substring(1));
return new ArrayList<>(defaults);
case '^':
// Specified entries go to the front of the default list
- List allSignatures = filteredList(defaults,
+ List allSignatures = filteredList(allAvailable, overrideKey,
fromConfig.substring(1));
Set atFront = new HashSet<>(allSignatures);
for (String sig : defaults) {
@@ -315,7 +421,7 @@ public List modifyAlgorithmList(List defaultList,
default:
// Default is overridden -- only accept the ones for which we do
// have an implementation.
- return filteredList(defaults, fromConfig);
+ return filteredList(allAvailable, overrideKey, fromConfig);
}
}
@@ -342,11 +448,15 @@ private void removeFromList(Set current, String key,
}
}
- private List filteredList(Set known, String values) {
+ private List filteredList(Set known, String key,
+ String values) {
List newNames = new ArrayList<>();
for (String newValue : values.split("\\s*,\\s*")) { //$NON-NLS-1$
if (known.contains(newValue)) {
newNames.add(newValue);
+ } else {
+ log.warn(format(SshdText.get().configUnknownAlgorithm, this,
+ newValue, key, values));
}
}
return newNames;
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitKexExtensionHandler.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitKexExtensionHandler.java
deleted file mode 100644
index 9446aaa7d..000000000
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitKexExtensionHandler.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (C) 2021 Thomas Wolf and others
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Distribution License v. 1.0 which is available at
- * https://www.eclipse.org/org/documents/edl-v10.php.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-package org.eclipse.jgit.internal.transport.sshd;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-
-import org.apache.sshd.common.AttributeRepository.AttributeKey;
-import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.kex.KexProposalOption;
-import org.apache.sshd.common.kex.extension.KexExtensionHandler;
-import org.apache.sshd.common.kex.extension.KexExtensions;
-import org.apache.sshd.common.kex.extension.parser.ServerSignatureAlgorithms;
-import org.apache.sshd.common.session.Session;
-import org.apache.sshd.common.signature.Signature;
-import org.apache.sshd.common.util.logging.AbstractLoggingBean;
-import org.eclipse.jgit.util.StringUtils;
-
-/**
- * Do not use the DefaultClientKexExtensionHandler from sshd; it doesn't work
- * properly because of misconceptions. See SSHD-1141.
- *
- * @see SSHD-1141
- */
-public class JGitKexExtensionHandler extends AbstractLoggingBean
- implements KexExtensionHandler {
-
- /** Singleton instance. */
- public static final JGitKexExtensionHandler INSTANCE = new JGitKexExtensionHandler();
-
- /**
- * Session {@link AttributeKey} used to store whether the extension
- * indicator was already sent.
- */
- private static final AttributeKey CLIENT_PROPOSAL_MADE = new AttributeKey<>();
-
- /**
- * Session {@link AttributeKey} storing the algorithms announced by the
- * server as known.
- */
- public static final AttributeKey> SERVER_ALGORITHMS = new AttributeKey<>();
-
- private JGitKexExtensionHandler() {
- // No public instantiation for singleton
- }
-
- @Override
- public boolean isKexExtensionsAvailable(Session session,
- AvailabilityPhase phase) throws IOException {
- return !AvailabilityPhase.PREKEX.equals(phase);
- }
-
- @Override
- public void handleKexInitProposal(Session session, boolean initiator,
- Map proposal) throws IOException {
- // If it's the very first time, we may add the marker telling the server
- // that we are ready to handle SSH_MSG_EXT_INFO
- if (session == null || session.isServerSession() || !initiator) {
- return;
- }
- if (session.getAttribute(CLIENT_PROPOSAL_MADE) != null) {
- return;
- }
- String kexAlgorithms = proposal.get(KexProposalOption.SERVERKEYS);
- if (StringUtils.isEmptyOrNull(kexAlgorithms)) {
- return;
- }
- List algorithms = new ArrayList<>();
- // We're a client. We mustn't send the server extension, and we should
- // send the client extension only once.
- for (String algo : kexAlgorithms.split(",")) { //$NON-NLS-1$
- if (KexExtensions.CLIENT_KEX_EXTENSION.equalsIgnoreCase(algo)
- || KexExtensions.SERVER_KEX_EXTENSION
- .equalsIgnoreCase(algo)) {
- continue;
- }
- algorithms.add(algo);
- }
- // Tell the server that we want to receive SSH2_MSG_EXT_INFO
- algorithms.add(KexExtensions.CLIENT_KEX_EXTENSION);
- if (log.isDebugEnabled()) {
- log.debug(
- "handleKexInitProposal({}): proposing HostKeyAlgorithms {}", //$NON-NLS-1$
- session, algorithms);
- }
- proposal.put(KexProposalOption.SERVERKEYS,
- String.join(",", algorithms)); //$NON-NLS-1$
- session.setAttribute(CLIENT_PROPOSAL_MADE, Boolean.TRUE);
- }
-
- @Override
- public boolean handleKexExtensionRequest(Session session, int index,
- int count, String name, byte[] data) throws IOException {
- if (ServerSignatureAlgorithms.NAME.equals(name)) {
- handleServerSignatureAlgorithms(session,
- ServerSignatureAlgorithms.INSTANCE.parseExtension(data));
- }
- return true;
- }
-
- /**
- * Perform updates after a server-sig-algs extension has been received.
- *
- * @param session
- * the message was received for
- * @param serverAlgorithms
- * signature algorithm names announced by the server
- */
- protected void handleServerSignatureAlgorithms(Session session,
- Collection serverAlgorithms) {
- if (log.isDebugEnabled()) {
- log.debug("handleServerSignatureAlgorithms({}): {}", session, //$NON-NLS-1$
- serverAlgorithms);
- }
- // Client determines order; server says what it supports. Re-order
- // such that supported ones are at the front, in client order,
- // followed by unsupported ones, also in client order.
- if (serverAlgorithms != null && !serverAlgorithms.isEmpty()) {
- List> clientAlgorithms = new ArrayList<>(
- session.getSignatureFactories());
- if (log.isDebugEnabled()) {
- log.debug(
- "handleServerSignatureAlgorithms({}): PubkeyAcceptedAlgorithms before: {}", //$NON-NLS-1$
- session, clientAlgorithms);
- }
- List> unknown = new ArrayList<>();
- Set known = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
- known.addAll(serverAlgorithms);
- for (Iterator> iter = clientAlgorithms
- .iterator(); iter.hasNext();) {
- NamedFactory algo = iter.next();
- if (!known.contains(algo.getName())) {
- unknown.add(algo);
- iter.remove();
- }
- }
- // Re-add the unknown ones at the end. Per RFC 8308, some
- // servers may not announce _all_ their supported algorithms,
- // and a client may use unknown algorithms.
- clientAlgorithms.addAll(unknown);
- if (log.isDebugEnabled()) {
- log.debug(
- "handleServerSignatureAlgorithms({}): PubkeyAcceptedAlgorithms after: {}", //$NON-NLS-1$
- session, clientAlgorithms);
- }
- session.setAttribute(SERVER_ALGORITHMS, known);
- session.setSignatureFactories(clientAlgorithms);
- }
- }
-}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthentication.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthentication.java
index 675509442..08da18f5a 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthentication.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitPublicKeyAuthentication.java
@@ -9,216 +9,56 @@
*/
package org.eclipse.jgit.internal.transport.sshd;
-import java.io.IOException;
-import java.security.PublicKey;
-import java.security.spec.InvalidKeySpecException;
-import java.text.MessageFormat;
-import java.util.Deque;
-import java.util.HashSet;
-import java.util.LinkedList;
+import static java.text.MessageFormat.format;
+import static org.eclipse.jgit.transport.SshConstants.PUBKEY_ACCEPTED_ALGORITHMS;
+
import java.util.List;
-import java.util.Set;
import org.apache.sshd.client.auth.pubkey.UserAuthPublicKey;
+import org.apache.sshd.client.config.hosts.HostConfigEntry;
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.NamedFactory;
-import org.apache.sshd.common.NamedResource;
-import org.apache.sshd.common.RuntimeSshException;
-import org.apache.sshd.common.SshConstants;
-import org.apache.sshd.common.config.keys.KeyUtils;
import org.apache.sshd.common.signature.Signature;
-import org.apache.sshd.common.signature.SignatureFactoriesHolder;
-import org.apache.sshd.common.util.buffer.Buffer;
+import org.eclipse.jgit.util.StringUtils;
/**
- * Custom {@link UserAuthPublicKey} implementation fixing SSHD-1105: if there
- * are several signature algorithms applicable for a public key type, we must
- * try them all, in the correct order.
- *
- * @see SSHD-1105
- * @see Bug
- * 572056
+ * Custom {@link UserAuthPublicKey} implementation for handling SSH config
+ * PubkeyAcceptedAlgorithms.
*/
public class JGitPublicKeyAuthentication extends UserAuthPublicKey {
- private final Deque currentAlgorithms = new LinkedList<>();
-
- private String chosenAlgorithm;
-
JGitPublicKeyAuthentication(List> factories) {
super(factories);
}
@Override
- protected boolean sendAuthDataRequest(ClientSession session, String service)
+ public void init(ClientSession rawSession, String service)
throws Exception {
- if (current == null) {
- currentAlgorithms.clear();
- chosenAlgorithm = null;
+ if (!(rawSession instanceof JGitClientSession)) {
+ throw new IllegalStateException("Wrong session type: " //$NON-NLS-1$
+ + rawSession.getClass().getCanonicalName());
}
- String currentAlgorithm = null;
- if (current != null && !currentAlgorithms.isEmpty()) {
- currentAlgorithm = currentAlgorithms.poll();
- if (chosenAlgorithm != null) {
- Set knownServerAlgorithms = session.getAttribute(
- JGitKexExtensionHandler.SERVER_ALGORITHMS);
- if (knownServerAlgorithms != null
- && knownServerAlgorithms.contains(chosenAlgorithm)) {
- // We've tried key 'current' with 'chosenAlgorithm', but it
- // failed. However, the server had told us it supported
- // 'chosenAlgorithm'. Thus it makes no sense to continue
- // with this key and other signature algorithms. Skip to the
- // next key, if any.
- currentAlgorithm = null;
- }
- }
- }
- if (currentAlgorithm == null) {
- try {
- if (keys == null || !keys.hasNext()) {
- if (log.isDebugEnabled()) {
- log.debug(
- "sendAuthDataRequest({})[{}] no more keys to send", //$NON-NLS-1$
- session, service);
- }
- current = null;
- return false;
- }
- current = keys.next();
- currentAlgorithms.clear();
- chosenAlgorithm = null;
- } catch (Error e) { // Copied from superclass
- throw new RuntimeSshException(e);
- }
- }
- PublicKey key;
- try {
- key = current.getPublicKey();
- } catch (Error e) { // Copied from superclass
- throw new RuntimeSshException(e);
- }
- if (currentAlgorithm == null) {
- String keyType = KeyUtils.getKeyType(key);
- Set aliases = new HashSet<>(
- KeyUtils.getAllEquivalentKeyTypes(keyType));
- aliases.add(keyType);
- List> existingFactories;
- if (current instanceof SignatureFactoriesHolder) {
- existingFactories = ((SignatureFactoriesHolder) current)
- .getSignatureFactories();
- } else {
- existingFactories = getSignatureFactories();
- }
- if (existingFactories != null) {
+ JGitClientSession session = ((JGitClientSession) rawSession);
+ HostConfigEntry hostConfig = session.getHostConfigEntry();
+ // Set signature algorithms for public key authentication
+ String pubkeyAlgos = hostConfig.getProperty(PUBKEY_ACCEPTED_ALGORITHMS);
+ if (!StringUtils.isEmptyOrNull(pubkeyAlgos)) {
+ List signatures = session.getSignatureFactoriesNames();
+ signatures = session.modifyAlgorithmList(signatures,
+ session.getAllAvailableSignatureAlgorithms(), pubkeyAlgos,
+ PUBKEY_ACCEPTED_ALGORITHMS);
+ if (!signatures.isEmpty()) {
if (log.isDebugEnabled()) {
- log.debug(
- "sendAuthDataRequest({})[{}] selecting from PubKeyAcceptedAlgorithms {}", //$NON-NLS-1$
- session, service,
- NamedResource.getNames(existingFactories));
+ log.debug(PUBKEY_ACCEPTED_ALGORITHMS + ' ' + signatures);
}
- // Select the factories by name and in order
- existingFactories.forEach(f -> {
- if (aliases.contains(f.getName())) {
- currentAlgorithms.add(f.getName());
- }
- });
+ setSignatureFactoriesNames(signatures);
+ } else {
+ log.warn(format(SshdText.get().configNoKnownAlgorithms,
+ PUBKEY_ACCEPTED_ALGORITHMS, pubkeyAlgos));
}
- currentAlgorithm = currentAlgorithms.isEmpty() ? keyType
- : currentAlgorithms.poll();
}
- String name = getName();
- if (log.isDebugEnabled()) {
- log.debug(
- "sendAuthDataRequest({})[{}] send SSH_MSG_USERAUTH_REQUEST request {} type={} - fingerprint={}", //$NON-NLS-1$
- session, service, name, currentAlgorithm,
- KeyUtils.getFingerPrint(key));
- }
-
- chosenAlgorithm = currentAlgorithm;
- Buffer buffer = session
- .createBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST);
- buffer.putString(session.getUsername());
- buffer.putString(service);
- buffer.putString(name);
- buffer.putBoolean(false);
- buffer.putString(currentAlgorithm);
- buffer.putPublicKey(key);
- session.writePacket(buffer);
- return true;
- }
-
- @Override
- protected boolean processAuthDataRequest(ClientSession session,
- String service, Buffer buffer) throws Exception {
- String name = getName();
- int cmd = buffer.getUByte();
- if (cmd != SshConstants.SSH_MSG_USERAUTH_PK_OK) {
- throw new IllegalStateException(MessageFormat.format(
- SshdText.get().pubkeyAuthWrongCommand,
- SshConstants.getCommandMessageName(cmd),
- session.getConnectAddress(), session.getServerVersion()));
- }
- PublicKey key;
- try {
- key = current.getPublicKey();
- } catch (Error e) { // Copied from superclass
- throw new RuntimeSshException(e);
- }
- String rspKeyAlgorithm = buffer.getString();
- PublicKey rspKey = buffer.getPublicKey();
- if (log.isDebugEnabled()) {
- log.debug(
- "processAuthDataRequest({})[{}][{}] SSH_MSG_USERAUTH_PK_OK type={}, fingerprint={}", //$NON-NLS-1$
- session, service, name, rspKeyAlgorithm,
- KeyUtils.getFingerPrint(rspKey));
- }
- if (!KeyUtils.compareKeys(rspKey, key)) {
- throw new InvalidKeySpecException(MessageFormat.format(
- SshdText.get().pubkeyAuthWrongKey,
- KeyUtils.getFingerPrint(key),
- KeyUtils.getFingerPrint(rspKey),
- session.getConnectAddress(), session.getServerVersion()));
- }
- if (!chosenAlgorithm.equalsIgnoreCase(rspKeyAlgorithm)) {
- // 'algo' SHOULD be the same as 'chosenAlgorithm', which is the one
- // we sent above. See https://tools.ietf.org/html/rfc4252#page-9 .
- //
- // However, at least Github (SSH-2.0-babeld-383743ad) servers seem
- // to return the key type, not the algorithm name.
- //
- // So we don't check but just log the inconsistency. We sign using
- // 'chosenAlgorithm' in any case, so we don't really care what the
- // server says here.
- log.warn(MessageFormat.format(
- SshdText.get().pubkeyAuthWrongSignatureAlgorithm,
- chosenAlgorithm, rspKeyAlgorithm, session.getConnectAddress(),
- session.getServerVersion()));
- }
- String username = session.getUsername();
- Buffer out = session
- .createBuffer(SshConstants.SSH_MSG_USERAUTH_REQUEST);
- out.putString(username);
- out.putString(service);
- out.putString(name);
- out.putBoolean(true);
- out.putString(chosenAlgorithm);
- out.putPublicKey(key);
- if (log.isDebugEnabled()) {
- log.debug(
- "processAuthDataRequest({})[{}][{}]: signing with algorithm {}", //$NON-NLS-1$
- session, service, name, chosenAlgorithm);
- }
- appendSignature(session, service, name, username, chosenAlgorithm, key,
- out);
- session.writePacket(out);
- return true;
- }
-
- @Override
- protected void releaseKeys() throws IOException {
- currentAlgorithms.clear();
- current = null;
- chosenAlgorithm = null;
- super.releaseKeys();
+ // If we don't set signature factories here, the default ones from the
+ // session will be used.
+ super.init(session, service);
}
}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshClient.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshClient.java
index 071e1979d..ae12c2028 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshClient.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/JGitSshClient.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018, 2020 Thomas Wolf and others
+ * Copyright (C) 2018, 2021 Thomas Wolf and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -267,24 +267,6 @@ private JGitClientSession createSession(IoSession ioSession,
session.setUsername(username);
session.setConnectAddress(address);
session.setHostConfigEntry(hostConfig);
- // Set signature algorithms for public key authentication
- String pubkeyAlgos = hostConfig
- .getProperty(SshConstants.PUBKEY_ACCEPTED_ALGORITHMS);
- if (!StringUtils.isEmptyOrNull(pubkeyAlgos)) {
- List signatures = getSignatureFactoriesNames();
- signatures = session.modifyAlgorithmList(signatures, pubkeyAlgos,
- SshConstants.PUBKEY_ACCEPTED_ALGORITHMS);
- if (!signatures.isEmpty()) {
- if (log.isDebugEnabled()) {
- log.debug(SshConstants.PUBKEY_ACCEPTED_ALGORITHMS + ' '
- + signatures);
- }
- session.setSignatureFactoriesNames(signatures);
- } else {
- log.warn(format(SshdText.get().configNoKnownAlgorithms,
- SshConstants.PUBKEY_ACCEPTED_ALGORITHMS, pubkeyAlgos));
- }
- }
if (session.getCredentialsProvider() == null) {
session.setCredentialsProvider(getCredentialsProvider());
}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyDatabase.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyDatabase.java
index 1a530b774..85e406f42 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyDatabase.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyDatabase.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018, 2019 Thomas Wolf and others
+ * Copyright (C) 2018, 2021 Thomas Wolf and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
@@ -182,10 +182,13 @@ public List lookup(@NonNull String connectAddress,
for (HostKeyFile file : filesToUse) {
for (HostEntryPair current : file.get()) {
KnownHostEntry entry = current.getHostEntry();
- for (SshdSocketAddress host : candidates) {
- if (entry.isHostMatch(host.getHostName(), host.getPort())) {
- result.add(current.getServerKey());
- break;
+ if (!isRevoked(entry)) {
+ for (SshdSocketAddress host : candidates) {
+ if (entry.isHostMatch(host.getHostName(),
+ host.getPort())) {
+ result.add(current.getServerKey());
+ break;
+ }
}
}
}
@@ -266,6 +269,10 @@ private static class RevokedKeyException extends Exception {
private static final long serialVersionUID = 1L;
}
+ private boolean isRevoked(KnownHostEntry entry) {
+ return MARKER_REVOKED.equals(entry.getMarker());
+ }
+
private boolean find(Collection candidates,
PublicKey serverKey, List entries,
HostEntryPair[] modified) throws RevokedKeyException {
@@ -273,22 +280,22 @@ private boolean find(Collection candidates,
KnownHostEntry entry = current.getHostEntry();
for (SshdSocketAddress host : candidates) {
if (entry.isHostMatch(host.getHostName(), host.getPort())) {
- boolean isRevoked = MARKER_REVOKED
- .equals(entry.getMarker());
+ boolean revoked = isRevoked(entry);
if (KeyUtils.compareKeys(serverKey,
current.getServerKey())) {
// Exact match
- if (isRevoked) {
+ if (revoked) {
throw new RevokedKeyException();
}
modified[0] = null;
return true;
- } else if (!isRevoked) {
+ } else if (!revoked) {
// Server sent a different key
modified[0] = current;
// Keep going -- maybe there's another entry for this
// host
}
+ break;
}
}
}
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java
index 73c2288cc..c0f571962 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/SshdText.java
@@ -28,6 +28,7 @@ public static SshdText get() {
/***/ public String configNoKnownAlgorithms;
/***/ public String configProxyJumpNotSsh;
/***/ public String configProxyJumpWithPath;
+ /***/ public String configUnknownAlgorithm;
/***/ public String ftpCloseFailed;
/***/ public String gssapiFailure;
/***/ public String gssapiInitFailure;
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/ServerKeyDatabase.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/ServerKeyDatabase.java
index b8e6cfd14..b1b3c1808 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/ServerKeyDatabase.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/ServerKeyDatabase.java
@@ -30,7 +30,7 @@
public interface ServerKeyDatabase {
/**
- * Retrieves all known host keys for the given addresses.
+ * Retrieves all known and not revoked host keys for the given addresses.
*
* @param connectAddress
* IP address the session tried to connect to
@@ -39,7 +39,7 @@ public interface ServerKeyDatabase {
* @param config
* giving access to potentially interesting configuration
* settings
- * @return the list of known keys for the given addresses
+ * @return the list of known and not revoked keys for the given addresses
*/
@NonNull
List lookup(@NonNull String connectAddress,
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSessionFactory.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSessionFactory.java
index 2d7e0c7c7..cad959c90 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSessionFactory.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/transport/sshd/SshdSessionFactory.java
@@ -47,7 +47,6 @@
import org.eclipse.jgit.internal.transport.sshd.AuthenticationCanceledException;
import org.eclipse.jgit.internal.transport.sshd.CachingKeyPairProvider;
import org.eclipse.jgit.internal.transport.sshd.GssApiWithMicAuthFactory;
-import org.eclipse.jgit.internal.transport.sshd.JGitKexExtensionHandler;
import org.eclipse.jgit.internal.transport.sshd.JGitPasswordAuthFactory;
import org.eclipse.jgit.internal.transport.sshd.JGitPublicKeyAuthFactory;
import org.eclipse.jgit.internal.transport.sshd.JGitServerKeyVerifier;
@@ -217,7 +216,6 @@ public SshdSession getSession(URIish uri,
new JGitUserInteraction(credentialsProvider));
client.setUserAuthFactories(getUserAuthFactories());
client.setKeyIdentityProvider(defaultKeysProvider);
- client.setKexExtensionHandler(JGitKexExtensionHandler.INSTANCE);
// JGit-specific things:
JGitSshClient jgitClient = (JGitSshClient) client;
jgitClient.setKeyCache(getKeyCache());
diff --git a/org.eclipse.jgit.ssh.jsch.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.ssh.jsch.test/META-INF/MANIFEST.MF
index 9ab1652a5..b5ad6808d 100644
--- a/org.eclipse.jgit.ssh.jsch.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ssh.jsch.test/META-INF/MANIFEST.MF
@@ -14,7 +14,7 @@ Import-Package: com.jcraft.jsch;version="[0.1.54,0.2.0)",
org.eclipse.jgit.lib;version="[6.0.0,6.1.0)",
org.eclipse.jgit.transport;version="[6.0.0,6.1.0)",
org.eclipse.jgit.util;version="[6.0.0,6.1.0)",
+ org.hamcrest;version="[1.1.0,3.0.0)",
org.junit;version="[4.13,5.0.0)",
org.junit.experimental.theories;version="[4.13,5.0.0)",
org.junit.runner;version="[4.13,5.0.0)"
-Require-Bundle: org.hamcrest.core;bundle-version="[1.3.0,2.0.0)"
diff --git a/org.eclipse.jgit.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
index ca6c58717..4facbfc44 100644
--- a/org.eclipse.jgit.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
@@ -69,6 +69,8 @@ Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)",
org.eclipse.jgit.util;version="[6.0.0,6.1.0)",
org.eclipse.jgit.util.io;version="[6.0.0,6.1.0)",
org.eclipse.jgit.util.sha1;version="[6.0.0,6.1.0)",
+ org.hamcrest;version="[1.1.0,3.0.0)",
+ org.hamcrest.collection;version="[1.1.0,3.0.0)",
org.junit;version="[4.13,5.0.0)",
org.junit.experimental.theories;version="[4.13,5.0.0)",
org.junit.function;version="[4.13.0,5.0.0)",
@@ -82,5 +84,3 @@ Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)",
org.objenesis;version="[2.6.0,3.0.0)",
org.slf4j;version="[1.7.0,2.0.0)",
org.tukaani.xz;version="[1.6.0,2.0)"
-Require-Bundle: org.hamcrest.core;bundle-version="[1.1.0,2.0.0)",
- org.hamcrest.library;bundle-version="[1.1.0,2.0.0)"
diff --git a/org.eclipse.jgit.test/pom.xml b/org.eclipse.jgit.test/pom.xml
index 345e3a4be..fd581fcab 100644
--- a/org.eclipse.jgit.test/pom.xml
+++ b/org.eclipse.jgit.test/pom.xml
@@ -60,9 +60,9 @@
org.hamcrest
- hamcrest-library
+ hamcrest
test
- [1.1.0,2.0.0)
+ ${hamcrest-version}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/revwalk/ReachabilityCheckerTestCase.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/revwalk/ReachabilityCheckerTestCase.java
index 1ff6e7def..7679c1109 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/revwalk/ReachabilityCheckerTestCase.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/revwalk/ReachabilityCheckerTestCase.java
@@ -57,7 +57,7 @@ public void reachable() throws Exception {
assertReachable("reachable from another tip",
checker.areAllReachable(Arrays.asList(a), Stream.of(b2)));
assertReachable("reachable from itself",
- checker.areAllReachable(Arrays.asList(a), Stream.of(b2)));
+ checker.areAllReachable(Arrays.asList(a), Stream.of(a)));
}
@Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java
index 327b554b4..fe3c1db50 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java
@@ -34,6 +34,7 @@
import static org.junit.Assert.fail;
import java.io.File;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.text.MessageFormat;
@@ -50,6 +51,7 @@
import org.eclipse.jgit.api.MergeCommand.FastForwardMode;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.junit.JGitTestUtil;
import org.eclipse.jgit.junit.MockSystemReader;
import org.eclipse.jgit.merge.MergeConfig;
import org.eclipse.jgit.storage.file.FileBasedConfig;
@@ -1463,6 +1465,107 @@ public void testWhitespaceContinuation() throws ConfigInvalidException {
assertEquals("tr ue", parseEscapedValue("tr \\\r\n ue"));
}
+ @Test
+ public void testCommitTemplateEmptyConfig()
+ throws ConfigInvalidException, IOException {
+ // no values defined nowhere
+ Config config = new Config(null);
+ assertNull(config.get(CommitConfig.KEY).getCommitTemplatePath());
+ assertNull(config.get(CommitConfig.KEY).getCommitTemplateContent());
+ }
+
+ @Test
+ public void testCommitTemplateConfig()
+ throws ConfigInvalidException, IOException {
+
+ File tempFile = tmp.newFile("testCommitTemplate-");
+ String templateContent = "content of the template";
+ JGitTestUtil.write(tempFile, templateContent);
+ String expectedTemplatePath = tempFile.getPath();
+
+ Config config = parse(
+ "[commit]\n\ttemplate = " + expectedTemplatePath + "\n");
+
+ String templatePath = config.get(CommitConfig.KEY)
+ .getCommitTemplatePath();
+ String commitEncoding = config.get(CommitConfig.KEY)
+ .getCommitEncoding();
+ assertEquals(expectedTemplatePath, templatePath);
+ assertEquals(templateContent,
+ config.get(CommitConfig.KEY).getCommitTemplateContent());
+ assertNull("no commitEncoding has been set so it must be null",
+ commitEncoding);
+ }
+
+ @Test
+ public void testCommitTemplateEncoding()
+ throws ConfigInvalidException, IOException {
+ Config config = new Config(null);
+ File tempFile = tmp.newFile("testCommitTemplate-");
+ String templateContent = "content of the template";
+ JGitTestUtil.write(tempFile, templateContent);
+ String expectedTemplatePath = tempFile.getPath();
+ config = parse("[i18n]\n\tcommitEncoding = utf-8\n"
+ + "[commit]\n\ttemplate = " + expectedTemplatePath + "\n");
+ assertEquals(templateContent,
+ config.get(CommitConfig.KEY).getCommitTemplateContent());
+ String commitEncoding = config.get(CommitConfig.KEY)
+ .getCommitEncoding();
+ assertEquals("commitEncoding has been set to utf-8 it must be utf-8",
+ "utf-8", commitEncoding);
+ }
+
+ @Test
+ public void testCommitTemplatePathInHomeDirecory()
+ throws ConfigInvalidException, IOException {
+ Config config = new Config(null);
+ File tempFile = tmp.newFile("testCommitTemplate-");
+ String templateContent = "content of the template";
+ JGitTestUtil.write(tempFile, templateContent);
+ // proper evaluation of the ~/ directory
+ String homeDir = System.getProperty("user.home");
+ File tempFileInHomeDirectory = File.createTempFile("fileInHomeFolder",
+ ".tmp", new File(homeDir));
+ tempFileInHomeDirectory.deleteOnExit();
+ JGitTestUtil.write(tempFileInHomeDirectory, templateContent);
+ String expectedTemplatePath = tempFileInHomeDirectory.getPath()
+ .replace(homeDir, "~");
+ config = parse("[commit]\n\ttemplate = " + expectedTemplatePath + "\n");
+ String templatePath = config.get(CommitConfig.KEY)
+ .getCommitTemplatePath();
+ assertEquals(expectedTemplatePath, templatePath);
+ assertEquals(templateContent,
+ config.get(CommitConfig.KEY).getCommitTemplateContent());
+ }
+
+ @Test(expected = ConfigInvalidException.class)
+ public void testCommitTemplateWithInvalidEncoding()
+ throws ConfigInvalidException, IOException {
+ Config config = new Config(null);
+ File tempFile = tmp.newFile("testCommitTemplate-");
+ String templateContent = "content of the template";
+ JGitTestUtil.write(tempFile, templateContent);
+ config = parse("[i18n]\n\tcommitEncoding = invalidEcoding\n"
+ + "[commit]\n\ttemplate = " + tempFile.getPath() + "\n");
+ config.get(CommitConfig.KEY).getCommitTemplateContent();
+ }
+
+ @Test(expected = FileNotFoundException.class)
+ public void testCommitTemplateWithInvalidPath()
+ throws ConfigInvalidException, IOException {
+ Config config = new Config(null);
+ File tempFile = tmp.newFile("testCommitTemplate-");
+ String templateContent = "content of the template";
+ JGitTestUtil.write(tempFile, templateContent);
+ // commit message encoding
+ String expectedTemplatePath = "nonExistingTemplate";
+ config = parse("[commit]\n\ttemplate = " + expectedTemplatePath + "\n");
+ String templatePath = config.get(CommitConfig.KEY)
+ .getCommitTemplatePath();
+ assertEquals(expectedTemplatePath, templatePath);
+ config.get(CommitConfig.KEY).getCommitTemplateContent();
+ }
+
private static void assertValueRoundTrip(String value)
throws ConfigInvalidException {
assertValueRoundTrip(value, value);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkUtilsReachableTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkUtilsReachableTest.java
index d9ed0c1c6..200cb6a4f 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkUtilsReachableTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkUtilsReachableTest.java
@@ -76,6 +76,28 @@ public void withCommitLoadedByDifferentRevWalk() throws Exception {
}
}
+ @Test
+ public void findBranchesReachableManyTimes() throws Exception {
+ /*
+ * a b
+ * | |
+ * c d
+ */
+ RevCommit a = commit();
+ RevCommit b = commit();
+ RevCommit c = commit(a);
+ RevCommit d = commit(b);
+ Ref branchA = branch("a", a);
+ Ref branchB = branch("b", b);
+ Ref branchC = branch("c", c);
+ Ref branchD = branch("d", d);
+
+ assertContains(a, asList(branchA, branchC));
+ assertContains(b, asList(branchB, branchD));
+ assertContains(c, asList(branchC));
+ assertContains(d, asList(branchD));
+ }
+
private Ref branch(String name, RevCommit dst) throws Exception {
return Git.wrap(db).branchCreate().setName(name)
.setStartPoint(dst.name()).call();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ObjectIdMatcher.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ObjectIdMatcher.java
index c3df19a23..77e8afb2b 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ObjectIdMatcher.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ObjectIdMatcher.java
@@ -16,7 +16,6 @@
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Sets;
import org.hamcrest.Description;
-import org.hamcrest.Factory;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
@@ -59,7 +58,6 @@ protected boolean matchesSafely(Collection resultOids) {
* @return true if examined and specified sets contains exactly the same
* elements.
*/
- @Factory
static Matcher> hasOnlyObjectIds(
String... oids) {
return new ObjectIdMatcher(Sets.of(oids));
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java
index b0b5f68ef..f4bbb4c9f 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java
@@ -460,6 +460,8 @@ private static class TestV2Hook implements ProtocolV2Hook {
private FetchV2Request fetchRequest;
+ private ObjectInfoRequest objectInfoRequest;
+
@Override
public void onCapabilities(CapabilitiesV2Request req) {
capabilitiesRequest = req;
@@ -474,6 +476,11 @@ public void onLsRefs(LsRefsV2Request req) {
public void onFetch(FetchV2Request req) {
fetchRequest = req;
}
+
+ @Override
+ public void onObjectInfo(ObjectInfoRequest req) {
+ objectInfoRequest = req;
+ }
}
@Test
@@ -2641,4 +2648,44 @@ public RefDatabase getRefDatabase() {
return refdb;
}
}
+
+ @Test
+ public void testObjectInfo() throws Exception {
+ server.getConfig().setBoolean("uploadpack", null, "advertiseobjectinfo",
+ true);
+
+ RevBlob blob1 = remote.blob("foobar");
+ RevBlob blob2 = remote.blob("fooba");
+ RevTree tree = remote.tree(remote.file("1", blob1),
+ remote.file("2", blob2));
+ RevCommit commit = remote.commit(tree);
+ remote.update("master", commit);
+
+ TestV2Hook hook = new TestV2Hook();
+ ByteArrayInputStream recvStream = uploadPackV2((UploadPack up) -> {
+ up.setProtocolV2Hook(hook);
+ }, "command=object-info\n", "size",
+ "oid " + ObjectId.toString(blob1.getId()),
+ "oid " + ObjectId.toString(blob2.getId()), PacketLineIn.end());
+ PacketLineIn pckIn = new PacketLineIn(recvStream);
+
+ assertThat(hook.objectInfoRequest, notNullValue());
+ assertThat(pckIn.readString(), is("size"));
+ assertThat(pckIn.readString(),
+ is(ObjectId.toString(blob1.getId()) + " 6"));
+ assertThat(pckIn.readString(),
+ is(ObjectId.toString(blob2.getId()) + " 5"));
+ assertTrue(PacketLineIn.isEnd(pckIn.readString()));
+ }
+
+ @Test
+ public void testObjectInfo_invalidOid() throws Exception {
+ server.getConfig().setBoolean("uploadpack", null, "advertiseobjectinfo",
+ true);
+
+ assertThrows(UploadPackInternalServerErrorException.class,
+ () -> uploadPackV2("command=object-info\n", "size",
+ "oid invalid",
+ PacketLineIn.end()));
+ }
}
diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters
index 14c505de0..83a83817f 100644
--- a/org.eclipse.jgit/.settings/.api_filters
+++ b/org.eclipse.jgit/.settings/.api_filters
@@ -8,6 +8,14 @@
+
+
+
+
+
+
+
+
diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
index 33e7452d9..3acceab09 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -365,6 +365,7 @@ invalidBooleanValue=Invalid boolean value: {0}.{1}={2}
invalidChannel=Invalid channel {0}
invalidCommitParentNumber=Invalid commit parent number
invalidDepth=Invalid depth: {0}
+invalidEncoding=Invalid encoding from git config i18n.commitEncoding: {0}
invalidEncryption=Invalid encryption
invalidExpandWildcard=ExpandFromSource on a refspec that can have mismatched wildcards does not make sense.
invalidFilter=Invalid filter: {0}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
index cf7bc1f26..3aa711455 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
@@ -173,7 +173,11 @@ public Git call() throws GitAPIException, InvalidRemoteException,
Repository repository = init();
FetchResult fetchResult = null;
Thread cleanupHook = new Thread(() -> cleanup());
- Runtime.getRuntime().addShutdownHook(cleanupHook);
+ try {
+ Runtime.getRuntime().addShutdownHook(cleanupHook);
+ } catch (IllegalStateException e) {
+ // ignore - the VM is already shutting down
+ }
try {
fetchResult = fetch(repository, u);
} catch (IOException ioe) {
@@ -197,7 +201,11 @@ public Git call() throws GitAPIException, InvalidRemoteException,
cleanup();
throw e;
} finally {
- Runtime.getRuntime().removeShutdownHook(cleanupHook);
+ try {
+ Runtime.getRuntime().removeShutdownHook(cleanupHook);
+ } catch (IllegalStateException e) {
+ // ignore - the VM is already shutting down
+ }
}
if (!noCheckout) {
try {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
index 8622e0a1a..76340dabb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -393,6 +393,7 @@ public static JGitText get() {
/***/ public String invalidChannel;
/***/ public String invalidCommitParentNumber;
/***/ public String invalidDepth;
+ /***/ public String invalidEncoding;
/***/ public String invalidEncryption;
/***/ public String invalidExpandWildcard;
/***/ public String invalidFilter;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java
index 96ca690c1..9be3df3b1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFile.java
@@ -25,6 +25,7 @@
import java.nio.channels.Channels;
import java.text.MessageFormat;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.zip.CRC32;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
@@ -162,10 +163,17 @@ private PackIndex idx(DfsReader ctx) throws IOException {
try {
DfsStreamKey idxKey = desc.getStreamKey(INDEX);
+ AtomicBoolean cacheHit = new AtomicBoolean(true);
DfsBlockCache.Ref idxref = cache.getOrLoadRef(
idxKey,
REF_POSITION,
- () -> loadPackIndex(ctx, idxKey));
+ () -> {
+ cacheHit.set(false);
+ return loadPackIndex(ctx, idxKey);
+ });
+ if (cacheHit.get()) {
+ ctx.stats.idxCacheHit++;
+ }
PackIndex idx = idxref.get();
if (index == null && idx != null) {
index = idx;
@@ -200,10 +208,17 @@ PackBitmapIndex getBitmapIndex(DfsReader ctx) throws IOException {
PackIndex idx = idx(ctx);
PackReverseIndex revidx = getReverseIdx(ctx);
DfsStreamKey bitmapKey = desc.getStreamKey(BITMAP_INDEX);
+ AtomicBoolean cacheHit = new AtomicBoolean(true);
DfsBlockCache.Ref idxref = cache.getOrLoadRef(
bitmapKey,
REF_POSITION,
- () -> loadBitmapIndex(ctx, bitmapKey, idx, revidx));
+ () -> {
+ cacheHit.set(false);
+ return loadBitmapIndex(ctx, bitmapKey, idx, revidx);
+ });
+ if (cacheHit.get()) {
+ ctx.stats.bitmapCacheHit++;
+ }
PackBitmapIndex bmidx = idxref.get();
if (bitmapIndex == null && bmidx != null) {
bitmapIndex = bmidx;
@@ -225,10 +240,17 @@ PackReverseIndex getReverseIdx(DfsReader ctx) throws IOException {
PackIndex idx = idx(ctx);
DfsStreamKey revKey = new DfsStreamKey.ForReverseIndex(
desc.getStreamKey(INDEX));
+ AtomicBoolean cacheHit = new AtomicBoolean(true);
DfsBlockCache.Ref revref = cache.getOrLoadRef(
revKey,
REF_POSITION,
- () -> loadReverseIdx(revKey, idx));
+ () -> {
+ cacheHit.set(false);
+ return loadReverseIdx(ctx, revKey, idx);
+ });
+ if (cacheHit.get()) {
+ ctx.stats.ridxCacheHit++;
+ }
PackReverseIndex revidx = revref.get();
if (reverseIndex == null && revidx != null) {
reverseIndex = revidx;
@@ -1031,9 +1053,12 @@ private DfsBlockCache.Ref loadPackIndex(
}
private DfsBlockCache.Ref loadReverseIdx(
- DfsStreamKey revKey, PackIndex idx) {
+ DfsReader ctx, DfsStreamKey revKey, PackIndex idx) {
+ ctx.stats.readReverseIdx++;
+ long start = System.nanoTime();
PackReverseIndex revidx = new PackReverseIndex(idx);
reverseIndex = revidx;
+ ctx.stats.readReverseIdxMicros += elapsedMicros(start);
return new DfsBlockCache.Ref<>(
revKey,
REF_POSITION,
@@ -1064,8 +1089,8 @@ private DfsBlockCache.Ref loadBitmapIndex(
bmidx = PackBitmapIndex.read(in, idx, revidx);
} finally {
size = rc.position();
- ctx.stats.readIdxBytes += size;
- ctx.stats.readIdxMicros += elapsedMicros(start);
+ ctx.stats.readBitmapIdxBytes += size;
+ ctx.stats.readBitmapIdxMicros += elapsedMicros(start);
}
bitmapIndex = bmidx;
return new DfsBlockCache.Ref<>(
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderIoStats.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderIoStats.java
index b7a71969b..5c4742501 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderIoStats.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReaderIoStats.java
@@ -19,18 +19,39 @@ public static class Accumulator {
/** Number of times the reader explicitly called scanPacks. */
long scanPacks;
+ /** Total number of cache hits for pack indexes. */
+ long idxCacheHit;
+
+ /** Total number of cache hits for reverse indexes. */
+ long ridxCacheHit;
+
+ /** Total number of cache hits for bitmap indexes. */
+ long bitmapCacheHit;
+
/** Total number of complete pack indexes read into memory. */
long readIdx;
/** Total number of complete bitmap indexes read into memory. */
long readBitmap;
- /** Total number of bytes read from indexes. */
+ /** Total number of reverse indexes added into memory. */
+ long readReverseIdx;
+
+ /** Total number of bytes read from pack indexes. */
long readIdxBytes;
- /** Total microseconds spent reading pack or bitmap indexes. */
+ /** Total microseconds spent reading pack indexes. */
long readIdxMicros;
+ /** Total microseconds spent creating reverse indexes. */
+ long readReverseIdxMicros;
+
+ /** Total number of bytes read from bitmap indexes. */
+ long readBitmapIdxBytes;
+
+ /** Total microseconds spent reading bitmap indexes. */
+ long readBitmapIdxMicros;
+
/** Total number of block cache hits. */
long blockCacheHit;
@@ -74,6 +95,33 @@ public long getScanPacks() {
return stats.scanPacks;
}
+ /**
+ * Get total number of pack index cache hits.
+ *
+ * @return total number of pack index cache hits.
+ */
+ public long getPackIndexCacheHits() {
+ return stats.idxCacheHit;
+ }
+
+ /**
+ * Get total number of reverse index cache hits.
+ *
+ * @return total number of reverse index cache hits.
+ */
+ public long getReverseIndexCacheHits() {
+ return stats.ridxCacheHit;
+ }
+
+ /**
+ * Get total number of bitmap index cache hits.
+ *
+ * @return total number of bitmap index cache hits.
+ */
+ public long getBitmapIndexCacheHits() {
+ return stats.bitmapCacheHit;
+ }
+
/**
* Get total number of complete pack indexes read into memory.
*
@@ -83,6 +131,15 @@ public long getReadPackIndexCount() {
return stats.readIdx;
}
+ /**
+ * Get total number of times the reverse index was computed.
+ *
+ * @return total number of reverse index was computed.
+ */
+ public long getReadReverseIndexCount() {
+ return stats.readReverseIdx;
+ }
+
/**
* Get total number of complete bitmap indexes read into memory.
*
@@ -93,23 +150,50 @@ public long getReadBitmapIndexCount() {
}
/**
- * Get total number of bytes read from indexes.
+ * Get total number of bytes read from pack indexes.
*
- * @return total number of bytes read from indexes.
+ * @return total number of bytes read from pack indexes.
*/
public long getReadIndexBytes() {
return stats.readIdxBytes;
}
/**
- * Get total microseconds spent reading pack or bitmap indexes.
+ * Get total microseconds spent reading pack indexes.
*
- * @return total microseconds spent reading pack or bitmap indexes.
+ * @return total microseconds spent reading pack indexes.
*/
public long getReadIndexMicros() {
return stats.readIdxMicros;
}
+ /**
+ * Get total microseconds spent creating reverse indexes.
+ *
+ * @return total microseconds spent creating reverse indexes.
+ */
+ public long getReadReverseIndexMicros() {
+ return stats.readReverseIdxMicros;
+ }
+
+ /**
+ * Get total number of bytes read from bitmap indexes.
+ *
+ * @return total number of bytes read from bitmap indexes.
+ */
+ public long getReadBitmapIndexBytes() {
+ return stats.readBitmapIdxBytes;
+ }
+
+ /**
+ * Get total microseconds spent reading bitmap indexes.
+ *
+ * @return total microseconds spent reading bitmap indexes.
+ */
+ public long getReadBitmapIndexMicros() {
+ return stats.readBitmapIdxMicros;
+ }
+
/**
* Get total number of block cache hits.
*
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitConfig.java
new file mode 100644
index 000000000..e4e7cd6e0
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CommitConfig.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2020 Julian Ruppel
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.eclipse.jgit.lib;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.StandardCharsets;
+import java.nio.charset.UnsupportedCharsetException;
+import java.text.MessageFormat;
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.Config.SectionParser;
+import org.eclipse.jgit.util.FS;
+import org.eclipse.jgit.util.IO;
+import org.eclipse.jgit.util.RawParseUtils;
+
+/**
+ * The standard "commit" configuration parameters.
+ *
+ * @since 5.13
+ */
+public class CommitConfig {
+ /**
+ * Key for {@link Config#get(SectionParser)}.
+ */
+ public static final Config.SectionParser KEY = CommitConfig::new;
+
+ private final static Charset DEFAULT_COMMIT_MESSAGE_ENCODING = StandardCharsets.UTF_8;
+
+ private String i18nCommitEncoding;
+
+ private String commitTemplatePath;
+
+ private CommitConfig(Config rc) {
+ commitTemplatePath = rc.getString(ConfigConstants.CONFIG_COMMIT_SECTION,
+ null, ConfigConstants.CONFIG_KEY_COMMIT_TEMPLATE);
+ i18nCommitEncoding = rc.getString(ConfigConstants.CONFIG_SECTION_I18N,
+ null, ConfigConstants.CONFIG_KEY_COMMIT_ENCODING);
+ }
+
+ /**
+ * Get the path to the commit template as defined in the git
+ * {@code commit.template} property.
+ *
+ * @return the path to commit template or {@code null} if not present.
+ */
+ @Nullable
+ public String getCommitTemplatePath() {
+ return commitTemplatePath;
+ }
+
+ /**
+ * Get the encoding of the commit as defined in the git
+ * {@code i18n.commitEncoding} property.
+ *
+ * @return the encoding or {@code null} if not present.
+ */
+ @Nullable
+ public String getCommitEncoding() {
+ return i18nCommitEncoding;
+ }
+
+ /**
+ * Get the content to the commit template as defined in
+ * {@code commit.template}. If no {@code i18n.commitEncoding} is specified,
+ * UTF-8 fallback is used.
+ *
+ * @return content of the commit template or {@code null} if not present.
+ * @throws IOException
+ * if the template file can not be read
+ * @throws FileNotFoundException
+ * if the template file does not exists
+ * @throws ConfigInvalidException
+ * if a {@code commitEncoding} is specified and is invalid
+ */
+ @Nullable
+ public String getCommitTemplateContent()
+ throws FileNotFoundException, IOException, ConfigInvalidException {
+
+ if (commitTemplatePath == null) {
+ return null;
+ }
+
+ File commitTemplateFile;
+ if (commitTemplatePath.startsWith("~/")) { //$NON-NLS-1$
+ commitTemplateFile = FS.DETECTED.resolve(FS.DETECTED.userHome(),
+ commitTemplatePath.substring(2));
+ } else {
+ commitTemplateFile = FS.DETECTED.resolve(null, commitTemplatePath);
+ }
+
+ Charset commitMessageEncoding = getEncoding();
+ return RawParseUtils.decode(commitMessageEncoding,
+ IO.readFully(commitTemplateFile));
+
+ }
+
+ private Charset getEncoding() throws ConfigInvalidException {
+ Charset commitMessageEncoding = DEFAULT_COMMIT_MESSAGE_ENCODING;
+
+ if (i18nCommitEncoding == null) {
+ return null;
+ }
+
+ try {
+ commitMessageEncoding = Charset.forName(i18nCommitEncoding);
+ } catch (IllegalCharsetNameException | UnsupportedCharsetException e) {
+ throw new ConfigInvalidException(MessageFormat.format(
+ JGitText.get().invalidEncoding, i18nCommitEncoding), e);
+ }
+
+ return commitMessageEncoding;
+ }
+}
\ No newline at end of file
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
index b6f4798dc..24eebc6a1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
@@ -124,6 +124,13 @@ public final class ConfigConstants {
*/
public static final String CONFIG_COMMIT_SECTION = "commit";
+ /**
+ * The "template" key
+ *
+ * @since 5.13
+ */
+ public static final String CONFIG_KEY_COMMIT_TEMPLATE = "template";
+
/**
* The "tag" section
*
@@ -517,6 +524,13 @@ public final class ConfigConstants {
*/
public static final String CONFIG_SECTION_I18N = "i18n";
+ /**
+ * The "commitEncoding" key
+ *
+ * @since 5.13
+ */
+ public static final String CONFIG_KEY_COMMIT_ENCODING = "commitEncoding";
+
/**
* The "logOutputEncoding" key
*
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
index 5d5ba12ba..d5b3643af 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
@@ -527,10 +527,12 @@ public boolean isMergedIntoAll(RevCommit commit, Collection[ refs)
private List][ getMergedInto(RevCommit needle, Collection][ haystacks,
Enum returnStrategy, ProgressMonitor monitor) throws IOException {
List][ result = new ArrayList<>();
+ List uninteresting = new ArrayList<>();
RevFilter oldRF = filter;
TreeFilter oldTF = treeFilter;
try {
finishDelayedFreeFlags();
+ reset(~freeFlags & APP_FLAGS);
filter = RevFilter.ALL;
treeFilter = TreeFilter.ALL;
for (Ref r: haystacks) {
@@ -559,13 +561,14 @@ private List][ getMergedInto(RevCommit needle, Collection][ haystacks,
}
if(!commitFound){
markUninteresting(c);
+ uninteresting.add(c);
if (returnStrategy == GetMergedIntoStrategy.RETURN_ON_FIRST_NOT_FOUND) {
return result;
}
}
}
} finally {
- reset(~freeFlags & APP_FLAGS);
+ roots.addAll(uninteresting);
filter = oldRF;
treeFilter = oldTF;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java
index c5e52bef9..aaa9308ac 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java
@@ -254,6 +254,13 @@ public final class GitProtocolConstants {
*/
public static final String COMMAND_FETCH = "fetch"; //$NON-NLS-1$
+ /**
+ * The server supports the object-info capability.
+ *
+ * @since 5.13
+ */
+ public static final String COMMAND_OBJECT_INFO = "object-info"; //$NON-NLS-1$
+
/**
* HTTP header to set by clients to request a specific git protocol version
* in the HTTP transport.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ObjectInfoRequest.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ObjectInfoRequest.java
new file mode 100644
index 000000000..86a271667
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ObjectInfoRequest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2021, Google LLC. and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.transport;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.jgit.lib.ObjectId;
+
+/**
+ * object-info request.
+ *
+ * ]
+ * This is the parsed request for an object-info call, used as input to
+ * {@link ProtocolV2Hook}.
+ *
+ * @see object-info
+ * documentation
+ *
+ * @since 5.13
+ */
+public final class ObjectInfoRequest {
+ private final List objectIDs;
+
+ private ObjectInfoRequest(List objectIDs) {
+ this.objectIDs = objectIDs;
+ }
+
+ /** @return object IDs that the client requested. */
+ public List getObjectIDs() {
+ return this.objectIDs;
+ }
+
+ /** @return A builder of {@link ObjectInfoRequest}. */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /** A builder for {@link ObjectInfoRequest}. */
+ public static final class Builder {
+ private List objectIDs = Collections.emptyList();
+
+ private Builder() {
+ }
+
+ /**
+ * @param value
+ * @return the Builder
+ */
+ public Builder setObjectIDs(List value) {
+ objectIDs = value;
+ return this;
+ }
+
+ /** @return ObjectInfoRequest */
+ public ObjectInfoRequest build() {
+ return new ObjectInfoRequest(
+ Collections.unmodifiableList(objectIDs));
+ }
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV2Hook.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV2Hook.java
index bfa749066..d7626df3f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV2Hook.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV2Hook.java
@@ -55,4 +55,16 @@ default void onFetch(FetchV2Request req)
throws ServiceMayNotContinueException {
// Do nothing by default
}
+
+ /**
+ * @param req
+ * the object-info request
+ * @throws ServiceMayNotContinueException
+ * abort; the message will be sent to the user
+ * @since 5.13
+ */
+ default void onObjectInfo(ObjectInfoRequest req)
+ throws ServiceMayNotContinueException {
+ // Do nothing by default
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV2HookChain.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV2HookChain.java
index 4cf8db6f5..7b3a4cea0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV2HookChain.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV2HookChain.java
@@ -71,6 +71,14 @@ public void onFetch(FetchV2Request req)
}
}
+ @Override
+ public void onObjectInfo(ObjectInfoRequest req)
+ throws ServiceMayNotContinueException {
+ for (ProtocolV2Hook hook : hooks) {
+ hook.onObjectInfo(req);
+ }
+ }
+
private ProtocolV2HookChain(List extends ProtocolV2Hook> hooks) {
this.hooks = Collections.unmodifiableList(hooks);
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV2Parser.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV2Parser.java
index 92f0133f5..6cec4b9a3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV2Parser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV2Parser.java
@@ -28,6 +28,7 @@
import java.util.List;
import java.util.function.Consumer;
+import org.eclipse.jgit.errors.InvalidObjectIdException;
import org.eclipse.jgit.errors.PackProtocolException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.ObjectId;
@@ -248,4 +249,38 @@ LsRefsV2Request parseLsRefsRequest(PacketLineIn pckIn)
return builder.setRefPrefixes(prefixes).build();
}
+ ObjectInfoRequest parseObjectInfoRequest(PacketLineIn pckIn)
+ throws PackProtocolException, IOException {
+ ObjectInfoRequest.Builder builder = ObjectInfoRequest.builder();
+ List objectIDs = new ArrayList<>();
+
+ String line = pckIn.readString();
+
+ if (PacketLineIn.isEnd(line)) {
+ return builder.build();
+ }
+
+ if (!line.equals("size")) { //$NON-NLS-1$
+ throw new PackProtocolException(MessageFormat
+ .format(JGitText.get().unexpectedPacketLine, line));
+ }
+
+ for (String line2 : pckIn.readStrings()) {
+ if (!line2.startsWith("oid ")) { //$NON-NLS-1$
+ throw new PackProtocolException(MessageFormat
+ .format(JGitText.get().unexpectedPacketLine, line2));
+ }
+
+ String oidStr = line2.substring("oid ".length()); //$NON-NLS-1$
+
+ try {
+ objectIDs.add(ObjectId.fromString(oidStr));
+ } catch (InvalidObjectIdException e) {
+ throw new PackProtocolException(MessageFormat
+ .format(JGitText.get().invalidObject, oidStr), e);
+ }
+ }
+
+ return builder.setObjectIDs(objectIDs).build();
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
index 79f60c320..58f8895e0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
@@ -29,6 +29,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.io.UncheckedIOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
@@ -37,6 +38,8 @@
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
+import java.util.stream.Collectors;
import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.errors.InvalidObjectIdException;
@@ -441,7 +444,7 @@ public Map getAdvertisedRefs() {
*/
public void setAdvertisedRefs(Map allRefs,
Set additionalHaves) {
- refs = allRefs != null ? allRefs : db.getAllRefs();
+ refs = allRefs != null ? allRefs : getAllRefs();
refs = refFilter.filter(refs);
advertisedHaves.clear();
@@ -1295,6 +1298,21 @@ public ReceivedPackStatistics getReceivedPackStatistics() {
return stats;
}
+ /**
+ * Extract the full list of refs from the ref-db.
+ *
+ * @return Map of all refname/ref
+ */
+ private Map getAllRefs() {
+ try {
+ return db.getRefDatabase().getRefs().stream()
+ .collect(Collectors.toMap(Ref::getName,
+ Function.identity()));
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
/**
* Receive a list of commands from the input.
*
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java
index da97f1e58..02be43488 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransferConfig.java
@@ -123,6 +123,7 @@ static ProtocolVersion parse(@Nullable String name) {
private final boolean advertiseSidebandAll;
private final boolean advertiseWaitForDone;
+ private final boolean advertiseObjectInfo;
final @Nullable ProtocolVersion protocolVersion;
final String[] hideRefs;
@@ -211,6 +212,8 @@ public TransferConfig(Config rc) {
"advertisesidebandall", false);
advertiseWaitForDone = rc.getBoolean("uploadpack",
"advertisewaitfordone", false);
+ advertiseObjectInfo = rc.getBoolean("uploadpack",
+ "advertiseobjectinfo", false);
}
/**
@@ -317,6 +320,14 @@ public boolean isAdvertiseWaitForDone() {
return advertiseWaitForDone;
}
+ /**
+ * @return true to advertise object-info to all clients
+ * @since 5.13
+ */
+ public boolean isAdvertiseObjectInfo() {
+ return advertiseObjectInfo;
+ }
+
/**
* Get {@link org.eclipse.jgit.transport.RefFilter} respecting configured
* hidden refs.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
index 37a1c1e58..07b348d0e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
@@ -17,6 +17,7 @@
import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_SERVER_OPTION;
import static org.eclipse.jgit.transport.GitProtocolConstants.COMMAND_FETCH;
import static org.eclipse.jgit.transport.GitProtocolConstants.COMMAND_LS_REFS;
+import static org.eclipse.jgit.transport.GitProtocolConstants.COMMAND_OBJECT_INFO;
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_AGENT;
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_ALLOW_REACHABLE_SHA1_IN_WANT;
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_ALLOW_TIP_SHA1_IN_WANT;
@@ -1269,6 +1270,32 @@ private void fetchV2(PacketLineOut pckOut) throws IOException {
}
}
+ private void objectInfo(PacketLineOut pckOut) throws IOException {
+ ProtocolV2Parser parser = new ProtocolV2Parser(transferConfig);
+ ObjectInfoRequest req = parser.parseObjectInfoRequest(pckIn);
+
+ protocolV2Hook.onObjectInfo(req);
+
+ ObjectReader or = getRepository().newObjectReader();
+
+ // Size is the only attribute currently supported.
+ pckOut.writeString("size"); //$NON-NLS-1$
+
+ for (ObjectId oid : req.getObjectIDs()) {
+ long size;
+ try {
+ size = or.getObjectSize(oid, ObjectReader.OBJ_ANY);
+ } catch (MissingObjectException e) {
+ throw new PackProtocolException(MessageFormat
+ .format(JGitText.get().missingObject, oid.name()), e);
+ }
+
+ pckOut.writeString(oid.getName() + " " + size); //$NON-NLS-1$
+ }
+
+ pckOut.end();
+ }
+
/*
* Returns true if this is the last command and we should tear down the
* connection.
@@ -1295,6 +1322,10 @@ private boolean serveOneCommandV2(PacketLineOut pckOut) throws IOException {
fetchV2(pckOut);
return false;
}
+ if (command.equals("command=" + COMMAND_OBJECT_INFO)) { //$NON-NLS-1$
+ objectInfo(pckOut);
+ return false;
+ }
throw new PackProtocolException(MessageFormat
.format(JGitText.get().unknownTransportCommand, command));
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
index 0946f645f..31a05933c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
@@ -524,7 +524,7 @@ private static void write(Path p, String body) throws IOException {
}
private static String read(Path p) throws IOException {
- final byte[] body = IO.readFully(p.toFile());
+ byte[] body = IO.readFully(p.toFile());
return new String(body, 0, body.length, UTF_8);
}
@@ -766,7 +766,7 @@ private static void saveToConfig(FileStore s,
}
private static String getConfigKey(FileStore s) {
- final String storeKey;
+ String storeKey;
if (SystemReader.getInstance().isWindows()) {
Object attribute = null;
try {
@@ -1164,7 +1164,7 @@ public void delete(File f) throws IOException {
* platform does not require path name translation.
*/
public File resolve(File dir, String name) {
- final File abspn = new File(name);
+ File abspn = new File(name);
if (abspn.isAbsolute())
return abspn;
return new File(dir, name);
@@ -1257,7 +1257,7 @@ protected File userHomeImpl() {
}
private File defaultUserHomeImpl() {
- final String home = AccessController.doPrivileged(
+ String home = AccessController.doPrivileged(
(PrivilegedAction) () -> System.getProperty("user.home") //$NON-NLS-1$
);
if (home == null || home.length() == 0)
@@ -1267,7 +1267,8 @@ private File defaultUserHomeImpl() {
/**
* Searches the given path to see if it contains one of the given files.
- * Returns the first it finds. Returns null if not found or if path is null.
+ * Returns the first it finds which is executable. Returns null if not found
+ * or if path is null.
*
* @param path
* List of paths to search separated by File.pathSeparator
@@ -1277,14 +1278,15 @@ private File defaultUserHomeImpl() {
* @since 3.0
*/
protected static File searchPath(String path, String... lookFor) {
- if (path == null)
+ if (path == null) {
return null;
+ }
for (String p : path.split(File.pathSeparator)) {
for (String command : lookFor) {
- final File file = new File(p, command);
+ File file = new File(p, command);
try {
- if (file.isFile()) {
+ if (file.isFile() && file.canExecute()) {
return file.getAbsoluteFile();
}
} catch (SecurityException e) {
@@ -1339,7 +1341,7 @@ protected static String readPipe(File dir, String[] command,
protected static String readPipe(File dir, String[] command,
String encoding, Map env)
throws CommandFailedException {
- final boolean debug = LOG.isDebugEnabled();
+ boolean debug = LOG.isDebugEnabled();
try {
if (debug) {
LOG.debug("readpipe " + Arrays.asList(command) + "," //$NON-NLS-1$ //$NON-NLS-2$
@@ -1806,11 +1808,11 @@ public String relativize(String base, String other) {
* @since 5.0
*/
public Entry[] list(File directory, FileModeStrategy fileModeStrategy) {
- final File[] all = directory.listFiles();
+ File[] all = directory.listFiles();
if (all == null) {
return NO_ENTRIES;
}
- final Entry[] result = new Entry[all.length];
+ Entry[] result = new Entry[all.length];
for (int i = 0; i < result.length; i++) {
result[i] = new FileEntry(all[i], this, fileModeStrategy);
}
@@ -1840,10 +1842,9 @@ public Entry[] list(File directory, FileModeStrategy fileModeStrategy) {
* @since 4.0
*/
public ProcessResult runHookIfPresent(Repository repository,
- final String hookName,
- String[] args) throws JGitInternalException {
- return runHookIfPresent(repository, hookName, args, System.out, System.err,
- null);
+ String hookName, String[] args) throws JGitInternalException {
+ return runHookIfPresent(repository, hookName, args, System.out,
+ System.err, null);
}
/**
@@ -1875,9 +1876,9 @@ public ProcessResult runHookIfPresent(Repository repository,
* @since 5.11
*/
public ProcessResult runHookIfPresent(Repository repository,
- final String hookName,
- String[] args, OutputStream outRedirect, OutputStream errRedirect,
- String stdinArgs) throws JGitInternalException {
+ String hookName, String[] args, OutputStream outRedirect,
+ OutputStream errRedirect, String stdinArgs)
+ throws JGitInternalException {
return new ProcessResult(Status.NOT_SUPPORTED);
}
@@ -1911,7 +1912,7 @@ public ProcessResult runHookIfPresent(Repository repository,
* @since 5.11
*/
protected ProcessResult internalRunHookIfPresent(Repository repository,
- final String hookName, String[] args, OutputStream outRedirect,
+ String hookName, String[] args, OutputStream outRedirect,
OutputStream errRedirect, String stdinArgs)
throws JGitInternalException {
File hookFile = findHook(repository, hookName);
@@ -2107,7 +2108,7 @@ public int runProcess(ProcessBuilder processBuilder,
OutputStream outRedirect, OutputStream errRedirect,
InputStream inRedirect) throws IOException,
InterruptedException {
- final ExecutorService executor = Executors.newFixedThreadPool(2);
+ ExecutorService executor = Executors.newFixedThreadPool(2);
Process process = null;
// We'll record the first I/O exception that occurs, but keep on trying
// to dispose of our open streams and file handles
diff --git a/pom.xml b/pom.xml
index 000be66e5..80f693db8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -152,17 +152,17 @@
${project.build.directory}/META-INF/MANIFEST.MF
5.12.0.202106070339-r
- 2.6.0
+ 2.7.0
0.1.55
1.1.1
- 1.1.7
+ 1.1.12
4.13
1C
2.33
- 1.19
+ 1.20
4.3.1
3.1.0
- 9.4.42.v20210604
+ 9.4.43.v20210629
0.15.3
4.5.13
4.4.14
@@ -170,15 +170,17 @@
1.2.15
3.2.0
1.7.0
- 2.8.6
- 1.65
- 4.2.3
+ 2.8.7
+ 1.69
+ 4.3.0
3.1.2
3.1.1
3.0.0-M5
${maven-surefire-plugin-version}
3.8.1
2.8.8
+ 2.2
+ 3.20.2
jacoco
@@ -688,7 +690,7 @@
org.tukaani
xz
- 1.8
+ 1.9
true
@@ -767,7 +769,13 @@
org.bouncycastle
bcprov-jdk15on
- 1.65.01
+ ${bouncycastle-version}
+
+
+
+ org.bouncycastle
+ bcutil-jdk15on
+ ${bouncycastle-version}
@@ -779,7 +787,7 @@
org.assertj
assertj-core
- 3.14.0
+ ${assertj-version}