Skip to content

Commit 83f0a77

Browse files
committed
Add Commit.ExtractSignature to get signature data from a commit
This method returns the signature data along with the rest of the commit without this header field, ready to be fed to whatever authentication method the caller prefers.
1 parent 20a788e commit 83f0a77

File tree

6 files changed

+142
-0
lines changed

6 files changed

+142
-0
lines changed

LibGit2Sharp.Tests/CommitFixture.cs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.IO;
44
using System.Linq;
5+
using System.Text;
56
using LibGit2Sharp.Core;
67
using LibGit2Sharp.Tests.TestHelpers;
78
using Xunit;
@@ -1045,5 +1046,75 @@ public void CanNotAmendACommitInAWayThatWouldLeadTheNewCommitToBecomeEmpty()
10451046
new CommitOptions { AmendPreviousCommit = true }));
10461047
}
10471048
}
1049+
1050+
[Fact]
1051+
public void CanExtractSignatureFromCommit()
1052+
{
1053+
string commitData = @"tree 6b79e22d69bf46e289df0345a14ca059dfc9bdf6
1054+
parent 34734e478d6cf50c27c9d69026d93974d052c454
1055+
author Ben Burkert <ben@benburkert.com> 1358451456 -0800
1056+
committer Ben Burkert <ben@benburkert.com> 1358451456 -0800
1057+
gpgsig -----BEGIN PGP SIGNATURE-----
1058+
Version: GnuPG v1.4.12 (Darwin)
1059+
1060+
iQIcBAABAgAGBQJQ+FMIAAoJEH+LfPdZDSs1e3EQAJMjhqjWF+WkGLHju7pTw2al
1061+
o6IoMAhv0Z/LHlWhzBd9e7JeCnanRt12bAU7yvYp9+Z+z+dbwqLwDoFp8LVuigl8
1062+
JGLcnwiUW3rSvhjdCp9irdb4+bhKUnKUzSdsR2CK4/hC0N2i/HOvMYX+BRsvqweq
1063+
AsAkA6dAWh+gAfedrBUkCTGhlNYoetjdakWqlGL1TiKAefEZrtA1TpPkGn92vbLq
1064+
SphFRUY9hVn1ZBWrT3hEpvAIcZag3rTOiRVT1X1flj8B2vGCEr3RrcwOIZikpdaW
1065+
who/X3xh/DGbI2RbuxmmJpxxP/8dsVchRJJzBwG+yhwU/iN3MlV2c5D69tls/Dok
1066+
6VbyU4lm/ae0y3yR83D9dUlkycOnmmlBAHKIZ9qUts9X7mWJf0+yy2QxJVpjaTGG
1067+
cmnQKKPeNIhGJk2ENnnnzjEve7L7YJQF6itbx5VCOcsGh3Ocb3YR7DMdWjt7f8pu
1068+
c6j+q1rP7EpE2afUN/geSlp5i3x8aXZPDj67jImbVCE/Q1X9voCtyzGJH7MXR0N9
1069+
ZpRF8yzveRfMH8bwAJjSOGAFF5XkcR/RNY95o+J+QcgBLdX48h+ZdNmUf6jqlu3J
1070+
7KmTXXQcOVpN6dD3CmRFsbjq+x6RHwa8u1iGn+oIkX908r97ckfB/kHKH7ZdXIJc
1071+
cpxtDQQMGYFpXK/71stq
1072+
=ozeK
1073+
-----END PGP SIGNATURE-----
1074+
1075+
a simple commit which works
1076+
";
1077+
1078+
string signatureData = @"-----BEGIN PGP SIGNATURE-----
1079+
Version: GnuPG v1.4.12 (Darwin)
1080+
1081+
iQIcBAABAgAGBQJQ+FMIAAoJEH+LfPdZDSs1e3EQAJMjhqjWF+WkGLHju7pTw2al
1082+
o6IoMAhv0Z/LHlWhzBd9e7JeCnanRt12bAU7yvYp9+Z+z+dbwqLwDoFp8LVuigl8
1083+
JGLcnwiUW3rSvhjdCp9irdb4+bhKUnKUzSdsR2CK4/hC0N2i/HOvMYX+BRsvqweq
1084+
AsAkA6dAWh+gAfedrBUkCTGhlNYoetjdakWqlGL1TiKAefEZrtA1TpPkGn92vbLq
1085+
SphFRUY9hVn1ZBWrT3hEpvAIcZag3rTOiRVT1X1flj8B2vGCEr3RrcwOIZikpdaW
1086+
who/X3xh/DGbI2RbuxmmJpxxP/8dsVchRJJzBwG+yhwU/iN3MlV2c5D69tls/Dok
1087+
6VbyU4lm/ae0y3yR83D9dUlkycOnmmlBAHKIZ9qUts9X7mWJf0+yy2QxJVpjaTGG
1088+
cmnQKKPeNIhGJk2ENnnnzjEve7L7YJQF6itbx5VCOcsGh3Ocb3YR7DMdWjt7f8pu
1089+
c6j+q1rP7EpE2afUN/geSlp5i3x8aXZPDj67jImbVCE/Q1X9voCtyzGJH7MXR0N9
1090+
ZpRF8yzveRfMH8bwAJjSOGAFF5XkcR/RNY95o+J+QcgBLdX48h+ZdNmUf6jqlu3J
1091+
7KmTXXQcOVpN6dD3CmRFsbjq+x6RHwa8u1iGn+oIkX908r97ckfB/kHKH7ZdXIJc
1092+
cpxtDQQMGYFpXK/71stq
1093+
=ozeK
1094+
-----END PGP SIGNATURE-----";
1095+
1096+
string signedData = @"tree 6b79e22d69bf46e289df0345a14ca059dfc9bdf6
1097+
parent 34734e478d6cf50c27c9d69026d93974d052c454
1098+
author Ben Burkert <ben@benburkert.com> 1358451456 -0800
1099+
committer Ben Burkert <ben@benburkert.com> 1358451456 -0800
1100+
1101+
a simple commit which works
1102+
";
1103+
1104+
string repoPath = InitNewRepository();
1105+
using (var repo = new Repository(repoPath))
1106+
{
1107+
var odb = repo.ObjectDatabase;
1108+
var signedId = odb.Write<Commit>(Encoding.UTF8.GetBytes(commitData));
1109+
1110+
// Look up the commit to make sure we wrote something valid
1111+
var commit = repo.Lookup<Commit>(signedId);
1112+
Assert.Equal("a simple commit which works\n", commit.Message);
1113+
1114+
var signatureInfo = Commit.ExtractSignature(repo, signedId, "gpgsig");
1115+
Assert.Equal(signedData, signatureInfo.SignedData);
1116+
Assert.Equal(signatureData, signatureInfo.Signature);
1117+
}
1118+
}
10481119
}
10491120
}

LibGit2Sharp/Commit.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,32 @@ private string DebuggerDisplay
124124
}
125125
}
126126

127+
/// <summary>
128+
/// Extract the signature data from this commit
129+
/// </summary>
130+
/// <returns>The signature and the signed data</returns>
131+
/// <param name="repo">The repository in which the object lives</param>
132+
/// <param name="id">The commit to extract the signature from</param>
133+
/// <param name="field">The header field which contains the signature; use null for the default of "gpgsig"</param>
134+
public static SignatureInfo ExtractSignature(Repository repo, ObjectId id, string field)
135+
{
136+
return Proxy.git_commit_extract_signature(repo.Handle, id, field);
137+
}
138+
139+
/// <summary>
140+
/// Extract the signature data from this commit
141+
/// <para>
142+
/// The overload uses the default header field "gpgsig"
143+
/// </para>
144+
/// </summary>
145+
/// <returns>The signature and the signed data</returns>
146+
/// <param name="repo">The repository in which the object lives</param>
147+
/// <param name="id">The commit to extract the signature from</param>
148+
public static SignatureInfo ExtractSignature(Repository repo, ObjectId id)
149+
{
150+
return Proxy.git_commit_extract_signature(repo.Handle, id, null);
151+
}
152+
127153
private class ParentsCollection : ICollection<Commit>
128154
{
129155
private readonly Lazy<ICollection<Commit>> _parents;

LibGit2Sharp/Core/NativeMethods.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,14 @@ internal static extern unsafe int git_commit_create_from_ids(
337337
[DllImport(libgit2)]
338338
internal static extern unsafe git_oid* git_commit_tree_id(git_object* commit);
339339

340+
[DllImport(libgit2)]
341+
internal static extern unsafe int git_commit_extract_signature(
342+
GitBuf signature,
343+
GitBuf signed_data,
344+
git_repository *repo,
345+
ref GitOid commit_id,
346+
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string field);
347+
340348
[DllImport(libgit2)]
341349
internal static extern unsafe int git_config_delete_entry(
342350
git_config* cfg,

LibGit2Sharp/Core/Proxy.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,22 @@ public static unsafe ObjectId git_commit_tree_id(ObjectHandle obj)
426426
return ObjectId.BuildFromPtr(NativeMethods.git_commit_tree_id(obj));
427427
}
428428

429+
public static unsafe SignatureInfo git_commit_extract_signature(RepositoryHandle repo, ObjectId id, string field)
430+
{
431+
using (var signature = new GitBuf())
432+
using (var signedData = new GitBuf())
433+
{
434+
var oid = id.Oid;
435+
Ensure.ZeroResult(NativeMethods.git_commit_extract_signature(signature, signedData, repo, ref oid, field));
436+
437+
return new SignatureInfo()
438+
{
439+
Signature = LaxUtf8Marshaler.FromNative(signature.ptr, signature.size.ConvertToInt()),
440+
SignedData = LaxUtf8Marshaler.FromNative(signedData.ptr, signedData.size.ConvertToInt()),
441+
};
442+
}
443+
}
444+
429445
#endregion
430446

431447
#region git_config_

LibGit2Sharp/LibGit2Sharp.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@
354354
<Compile Include="Commands\Fetch.cs" />
355355
<Compile Include="Commands\Stage.cs" />
356356
<Compile Include="Commands\Remove.cs" />
357+
<Compile Include="SignatureInfo.cs" />
357358
</ItemGroup>
358359
<ItemGroup>
359360
<CodeAnalysisDictionary Include="CustomDictionary.xml" />

LibGit2Sharp/SignatureInfo.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System;
2+
3+
namespace LibGit2Sharp
4+
{
5+
/// <summary>
6+
/// Structure for holding a signature extracted from a commit or a tag
7+
/// </summary>
8+
public struct SignatureInfo
9+
{
10+
/// <summary>
11+
/// The signature data, PGP/GPG or otherwise.
12+
/// </summary>
13+
public string Signature;
14+
/// <summary>
15+
/// The data which was signed. The object contents without the signature part.
16+
/// </summary>
17+
public string SignedData;
18+
}
19+
}
20+

0 commit comments

Comments
 (0)