mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-01 19:15:52 +01:00
work on getting signatures running
This commit is contained in:
@@ -422,16 +422,8 @@ public final class GitUtil
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method description
|
* Returns the commit for the given ref.
|
||||||
*
|
* If the given ref is for a tag, the commit that this tag belongs to is returned instead.
|
||||||
*
|
|
||||||
* @param repository
|
|
||||||
* @param revWalk
|
|
||||||
* @param ref
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
*/
|
||||||
public static RevCommit getCommit(org.eclipse.jgit.lib.Repository repository,
|
public static RevCommit getCommit(org.eclipse.jgit.lib.Repository repository,
|
||||||
RevWalk revWalk, Ref ref)
|
RevWalk revWalk, Ref ref)
|
||||||
@@ -710,22 +702,20 @@ public final class GitUtil
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final byte[] GPG_HEADER = {'P', 'G', 'P'};
|
private static final String GPG_HEADER = "-----BEGIN PGP SIGNATURE-----";
|
||||||
|
|
||||||
public static Optional<Signature> getTagSignature(RevObject revObject, GPG gpg) {
|
public static Optional<Signature> getTagSignature(RevObject revObject, GPG gpg, RevWalk revWalk) throws IOException {
|
||||||
if (revObject instanceof RevTag) {
|
if (revObject instanceof RevTag) {
|
||||||
RevTag tag = (RevTag) revObject;
|
final byte[] bytes = revWalk.getObjectReader().open(revObject.getId()).getBytes();
|
||||||
byte[] raw = tag.getFullMessage().getBytes();
|
final String message = new String(bytes);
|
||||||
|
final int signatureStartIndex = message.indexOf(GPG_HEADER);
|
||||||
int start = RawParseUtils.headerStart(GPG_HEADER, raw, 0);
|
if (signatureStartIndex < 0) {
|
||||||
if (start < 0) {
|
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
int end = RawParseUtils.headerEnd(raw, start);
|
final String signature = message.substring(signatureStartIndex);
|
||||||
byte[] signature = Arrays.copyOfRange(raw, start, end);
|
|
||||||
|
|
||||||
String publicKeyId = gpg.findPublicKeyId(signature);
|
String publicKeyId = gpg.findPublicKeyId(signature.getBytes());
|
||||||
if (Strings.isNullOrEmpty(publicKeyId)) {
|
if (Strings.isNullOrEmpty(publicKeyId)) {
|
||||||
// key not found
|
// key not found
|
||||||
return Optional.of(new Signature(publicKeyId, "gpg", SignatureStatus.NOT_FOUND, null, Collections.emptySet()));
|
return Optional.of(new Signature(publicKeyId, "gpg", SignatureStatus.NOT_FOUND, null, Collections.emptySet()));
|
||||||
@@ -739,19 +729,7 @@ public final class GitUtil
|
|||||||
|
|
||||||
PublicKey publicKey = publicKeyById.get();
|
PublicKey publicKey = publicKeyById.get();
|
||||||
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
boolean verified = publicKey.verify(message.substring(0, signatureStartIndex - 1).getBytes(), signature.getBytes());
|
||||||
try {
|
|
||||||
byte[] headerPrefix = Arrays.copyOfRange(raw, 0, start - GPG_HEADER.length - 1);
|
|
||||||
baos.write(headerPrefix);
|
|
||||||
|
|
||||||
byte[] headerSuffix = Arrays.copyOfRange(raw, end + 1, raw.length);
|
|
||||||
baos.write(headerSuffix);
|
|
||||||
} catch (IOException ex) {
|
|
||||||
// this will never happen, because we are writing into memory
|
|
||||||
throw new IllegalStateException("failed to write into memory", ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean verified = publicKey.verify(baos.toByteArray(), signature);
|
|
||||||
return Optional.of(new Signature(
|
return Optional.of(new Signature(
|
||||||
publicKeyId,
|
publicKeyId,
|
||||||
"gpg",
|
"gpg",
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ public class GitTagCommand extends AbstractGitCommand implements TagCommand {
|
|||||||
|
|
||||||
try (RevWalk walk = new RevWalk(git.getRepository())) {
|
try (RevWalk walk = new RevWalk(git.getRepository())) {
|
||||||
revObject = walk.parseTag(ref.getObjectId());
|
revObject = walk.parseTag(ref.getObjectId());
|
||||||
final Optional<Signature> tagSignature = GitUtil.getTagSignature(revObject, gpg);
|
final Optional<Signature> tagSignature = GitUtil.getTagSignature(revObject, gpg, walk);
|
||||||
tagSignature.ifPresent(tag::addSignature);
|
tagSignature.ifPresent(tag::addSignature);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ public class GitTagsCommand extends AbstractGitCommand implements TagsCommand {
|
|||||||
List<Ref> tagList = git.tagList().call();
|
List<Ref> tagList = git.tagList().call();
|
||||||
|
|
||||||
tags = Lists.transform(tagList,
|
tags = Lists.transform(tagList,
|
||||||
new TransformFuntion(git.getRepository(), revWalk, gpg, git));
|
new TransformFunction(git.getRepository(), revWalk, gpg, git));
|
||||||
} catch (GitAPIException ex) {
|
} catch (GitAPIException ex) {
|
||||||
throw new InternalRepositoryException(repository, "could not read tags from repository", ex);
|
throw new InternalRepositoryException(repository, "could not read tags from repository", ex);
|
||||||
} finally {
|
} finally {
|
||||||
@@ -100,13 +100,13 @@ public class GitTagsCommand extends AbstractGitCommand implements TagsCommand {
|
|||||||
* @author Enter your name here...
|
* @author Enter your name here...
|
||||||
* @version Enter version here..., 12/07/06
|
* @version Enter version here..., 12/07/06
|
||||||
*/
|
*/
|
||||||
private static class TransformFuntion implements Function<Ref, Tag> {
|
private static class TransformFunction implements Function<Ref, Tag> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the logger for TransformFuntion
|
* the logger for TransformFuntion
|
||||||
*/
|
*/
|
||||||
private static final Logger logger =
|
private static final Logger logger =
|
||||||
LoggerFactory.getLogger(TransformFuntion.class);
|
LoggerFactory.getLogger(TransformFunction.class);
|
||||||
|
|
||||||
//~--- constructors -------------------------------------------------------
|
//~--- constructors -------------------------------------------------------
|
||||||
|
|
||||||
@@ -116,10 +116,10 @@ public class GitTagsCommand extends AbstractGitCommand implements TagsCommand {
|
|||||||
* @param repository
|
* @param repository
|
||||||
* @param revWalk
|
* @param revWalk
|
||||||
*/
|
*/
|
||||||
public TransformFuntion(org.eclipse.jgit.lib.Repository repository,
|
public TransformFunction(org.eclipse.jgit.lib.Repository repository,
|
||||||
RevWalk revWalk,
|
RevWalk revWalk,
|
||||||
GPG gpg,
|
GPG gpg,
|
||||||
Git git) {
|
Git git) {
|
||||||
this.repository = repository;
|
this.repository = repository;
|
||||||
this.revWalk = revWalk;
|
this.revWalk = revWalk;
|
||||||
this.gpg = gpg;
|
this.gpg = gpg;
|
||||||
@@ -149,12 +149,12 @@ public class GitTagsCommand extends AbstractGitCommand implements TagsCommand {
|
|||||||
try {
|
try {
|
||||||
RevTag revTag = GitUtil.getTag(repository, revWalk, ref);
|
RevTag revTag = GitUtil.getTag(repository, revWalk, ref);
|
||||||
|
|
||||||
final Optional<Signature> tagSignature = GitUtil.getTagSignature(revTag, gpg);
|
final Optional<Signature> tagSignature = GitUtil.getTagSignature(revTag, gpg, revWalk);
|
||||||
if (tagSignature.isPresent()) {
|
if (tagSignature.isPresent()) {
|
||||||
tag.addSignature(tagSignature.get());
|
tag.addSignature(tagSignature.get());
|
||||||
}
|
}
|
||||||
} catch (IncorrectObjectTypeException e) {
|
} catch (IncorrectObjectTypeException e) {
|
||||||
// Ignore, this must be a lightweight tag
|
// Ignore because it is a lightweight tag which cannot have signatures
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,41 +24,33 @@
|
|||||||
|
|
||||||
package sonia.scm.repository.spi;
|
package sonia.scm.repository.spi;
|
||||||
|
|
||||||
import com.github.sdorra.shiro.ShiroRule;
|
|
||||||
import com.github.sdorra.shiro.SubjectAware;
|
import com.github.sdorra.shiro.SubjectAware;
|
||||||
import org.junit.Rule;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.rules.TemporaryFolder;
|
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.ArgumentMatchers;
|
import org.mockito.ArgumentMatchers;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.Mockito;
|
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
import sonia.scm.repository.Tag;
|
import sonia.scm.repository.Tag;
|
||||||
import sonia.scm.security.GPG;
|
import sonia.scm.security.GPG;
|
||||||
|
import sonia.scm.security.PublicKey;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.anyOf;
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@SubjectAware(configuration = "classpath:sonia/scm/configuration/shiro.ini", username = "admin", password = "secret")
|
@SubjectAware(configuration = "classpath:sonia/scm/configuration/shiro.ini", username = "admin", password = "secret")
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
public class GitTagsCommandTest extends AbstractGitCommandTestBase {
|
public class GitTagsCommandTest extends AbstractGitCommandTestBase {
|
||||||
|
|
||||||
@Rule
|
|
||||||
public TemporaryFolder temporaryFolder = new TemporaryFolder();
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
public BindTransportProtocolRule transportProtocolRule = new BindTransportProtocolRule();
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
public ShiroRule shiro = new ShiroRule();
|
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
GPG gpg;
|
GPG gpg;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
PublicKey publicKey;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldGetDatesCorrectly() throws IOException {
|
public void shouldGetDatesCorrectly() throws IOException {
|
||||||
final GitContext gitContext = createContext();
|
final GitContext gitContext = createContext();
|
||||||
@@ -79,7 +71,24 @@ public class GitTagsCommandTest extends AbstractGitCommandTestBase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldGetSignatures() throws IOException {
|
public void shouldGetSignatures() throws IOException {
|
||||||
Mockito.when(gpg.findPublicKeyId(ArgumentMatchers.any())).thenReturn("2BA27721F113C005CC16F06BAE63EFBC49F140CF");
|
when(gpg.findPublicKeyId(ArgumentMatchers.any())).thenReturn("2BA27721F113C005CC16F06BAE63EFBC49F140CF");
|
||||||
|
when(gpg.findPublicKey("2BA27721F113C005CC16F06BAE63EFBC49F140CF")).thenReturn(Optional.of(publicKey));
|
||||||
|
String signature = "-----BEGIN PGP SIGNATURE-----\n" +
|
||||||
|
"\n" +
|
||||||
|
"iQEzBAABCgAdFiEEK6J3IfETwAXMFvBrrmPvvEnxQM8FAl+9acoACgkQrmPvvEnx\n" +
|
||||||
|
"QM9abwgAnGP+Y/Ijli+PAsimfOmZQWYepjptoOv9m7i3bnHv8V+Qg6cm51I3E0YV\n" +
|
||||||
|
"R2QaxxzW9PgS4hcES+L1qs8Lwo18RurF469eZEmNb8DcUFJ3sEWeHlIl5wZNNo/v\n" +
|
||||||
|
"jJm0d9LNcSmtAIiQ8eDMoGdFXJzHewGickLOSsQGmfZgZus4Qlsh7r3BZTI1Zwd/\n" +
|
||||||
|
"6jaBFctX13FuepCTxq2SjEfRaQHIYkyFQq2o6mjL5S2qfYJ/S//gcCCzxllQrisF\n" +
|
||||||
|
"5fRW3LzLI4eXFH0vua7+UzNS2Rwpifg2OENJA/Kn+3R36LWEGxFK9pNqjVPRAcQj\n" +
|
||||||
|
"1vSkcjK26RqhAqCjNLSagM8ATZrh+g==\n" +
|
||||||
|
"=kUKm\n" +
|
||||||
|
"-----END PGP SIGNATURE-----\n";
|
||||||
|
String signedContent = "Tagger: Arthur Dent <arthur.dent@hitchhiker.com>\n" +
|
||||||
|
"Date: Tue Nov 24 21:37:46 2020 +0100\n" +
|
||||||
|
"\n" +
|
||||||
|
"this tag is signed";
|
||||||
|
when(publicKey.verify(signedContent.getBytes(), signature.getBytes())).thenReturn(true);
|
||||||
|
|
||||||
final GitContext gitContext = createContext();
|
final GitContext gitContext = createContext();
|
||||||
final GitTagsCommand tagsCommand = new GitTagsCommand(gitContext, gpg);
|
final GitTagsCommand tagsCommand = new GitTagsCommand(gitContext, gpg);
|
||||||
|
|||||||
Reference in New Issue
Block a user