Browse Source

Allow to check for signing key

The new API is intended for UIs to check if signing will be possible or
would fail

Bug: 543579
Change-Id: I6ce1fd4210e46d49dcdf420c99d08c93e022136c
Signed-off-by: Gunnar Wagenknecht <gunnar@wagenknecht.org>
stable-5.4
Gunnar Wagenknecht 6 years ago committed by Matthias Sohn
parent
commit
c4420d2434
  1. 17
      org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java
  2. 32
      org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSigner.java
  3. 45
      org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/BouncyCastleGpgSigner.java

17
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java

@ -56,6 +56,7 @@ import java.util.List;
import java.util.TimeZone;
import java.util.concurrent.atomic.AtomicInteger;
import org.eclipse.jgit.api.errors.CanceledException;
import org.eclipse.jgit.api.errors.EmptyCommitException;
import org.eclipse.jgit.api.errors.WrongRepositoryStateException;
import org.eclipse.jgit.diff.DiffEntry;
@ -651,6 +652,14 @@ public class CommitCommandTest extends RepositoryTestCase {
signingCommitters[0] = signingCommitter;
callCount.incrementAndGet();
}
@Override
public boolean canLocateSigningKey(String gpgSigningKey,
PersonIdent signingCommitter,
CredentialsProvider credentialsProvider)
throws CanceledException {
return false;
}
});
// first call should use config, which is expected to be null at
@ -706,6 +715,14 @@ public class CommitCommandTest extends RepositoryTestCase {
PersonIdent signingCommitter, CredentialsProvider credentialsProvider) {
callCount.incrementAndGet();
}
@Override
public boolean canLocateSigningKey(String gpgSigningKey,
PersonIdent signingCommitter,
CredentialsProvider credentialsProvider)
throws CanceledException {
return false;
}
});
// first call should use config, which is expected to be null at

32
org.eclipse.jgit/src/org/eclipse/jgit/lib/GpgSigner.java

@ -43,6 +43,7 @@
package org.eclipse.jgit.lib;
import org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.api.errors.CanceledException;
import org.eclipse.jgit.lib.internal.BouncyCastleGpgSigner;
import org.eclipse.jgit.transport.CredentialsProvider;
@ -95,9 +96,11 @@ public abstract class GpgSigner {
* the commit to sign (must not be <code>null</code> and must be
* complete to allow proper calculation of payload)
* @param gpgSigningKey
* the signing key (passed as is to the GPG signing tool)
* the signing key to locate (passed as is to the GPG signing
* tool as is; eg., value of <code>user.signingkey</code>)
* @param committer
* the signing identity (to help with key lookup)
* the signing identity (to help with key lookup in case signing
* key is not specified)
* @param credentialsProvider
* provider to use when querying for signing key credentials (eg.
* passphrase)
@ -106,7 +109,30 @@ public abstract class GpgSigner {
* passphrase)
*/
public abstract void sign(@NonNull CommitBuilder commit,
String gpgSigningKey, @NonNull PersonIdent committer,
@Nullable String gpgSigningKey, @NonNull PersonIdent committer,
CredentialsProvider credentialsProvider) throws CanceledException;
/**
* Indicates if a signing key is available for the specified committer
* and/or signing key.
*
* @param gpgSigningKey
* the signing key to locate (passed as is to the GPG signing
* tool as is; eg., value of <code>user.signingkey</code>)
* @param committer
* the signing identity (to help with key lookup in case signing
* key is not specified)
* @param credentialsProvider
* provider to use when querying for signing key credentials (eg.
* passphrase)
* @return <code>true</code> if a signing key is available,
* <code>false</code> otherwise
* @throws CanceledException
* when signing was canceled (eg., user aborted when entering
* passphrase)
*/
public abstract boolean canLocateSigningKey(@Nullable String gpgSigningKey,
@NonNull PersonIdent committer,
CredentialsProvider credentialsProvider) throws CanceledException;
}

45
org.eclipse.jgit/src/org/eclipse/jgit/lib/internal/BouncyCastleGpgSigner.java

@ -59,8 +59,10 @@ import org.bouncycastle.openpgp.PGPSignatureGenerator;
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
import org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.api.errors.CanceledException;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.errors.UnsupportedCredentialItem;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.CommitBuilder;
import org.eclipse.jgit.lib.GpgSignature;
@ -90,27 +92,50 @@ public class BouncyCastleGpgSigner extends GpgSigner {
}
@Override
public void sign(@NonNull CommitBuilder commit, String gpgSigningKey,
@NonNull PersonIdent committer,
CredentialsProvider credentialsProvider) throws CanceledException {
public boolean canLocateSigningKey(@Nullable String gpgSigningKey,
PersonIdent committer, CredentialsProvider credentialsProvider)
throws CanceledException {
try (BouncyCastleGpgKeyPassphrasePrompt passphrasePrompt = new BouncyCastleGpgKeyPassphrasePrompt(
credentialsProvider)) {
BouncyCastleGpgKey gpgKey = locateSigningKey(gpgSigningKey,
committer, passphrasePrompt);
return gpgKey != null;
} catch (PGPException | IOException | URISyntaxException e) {
return false;
}
}
private BouncyCastleGpgKey locateSigningKey(@Nullable String gpgSigningKey,
PersonIdent committer,
BouncyCastleGpgKeyPassphrasePrompt passphrasePrompt)
throws CanceledException, UnsupportedCredentialItem, IOException,
PGPException, URISyntaxException {
if (gpgSigningKey == null || gpgSigningKey.isEmpty()) {
gpgSigningKey = committer.getEmailAddress();
}
BouncyCastleGpgKeyLocator keyHelper = new BouncyCastleGpgKeyLocator(
gpgSigningKey, passphrasePrompt);
return keyHelper.findSecretKey();
}
@Override
public void sign(@NonNull CommitBuilder commit,
@Nullable String gpgSigningKey, @NonNull PersonIdent committer,
CredentialsProvider credentialsProvider) throws CanceledException {
try (BouncyCastleGpgKeyPassphrasePrompt passphrasePrompt = new BouncyCastleGpgKeyPassphrasePrompt(
credentialsProvider)) {
BouncyCastleGpgKeyLocator keyHelper = new BouncyCastleGpgKeyLocator(
gpgSigningKey, passphrasePrompt);
BouncyCastleGpgKey gpgKey = keyHelper.findSecretKey();
BouncyCastleGpgKey gpgKey = locateSigningKey(gpgSigningKey,
committer, passphrasePrompt);
PGPSecretKey secretKey = gpgKey.getSecretKey();
if (secretKey == null) {
throw new JGitInternalException(
JGitText.get().unableToSignCommitNoSecretKey);
}
char[] passphrase = passphrasePrompt
.getPassphrase(secretKey.getPublicKey().getFingerprint(),
gpgKey.getOrigin());
char[] passphrase = passphrasePrompt.getPassphrase(
secretKey.getPublicKey().getFingerprint(),
gpgKey.getOrigin());
PGPPrivateKey privateKey = secretKey
.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder()
.setProvider(BouncyCastleProvider.PROVIDER_NAME)

Loading…
Cancel
Save