8000 Merge pull request #1304 from libgit2/cmn/signatures · libgit2/libgit2sharp@1fb7fc5 · GitHub
[go: up one dir, main page]

Skip to content

Commit 1fb7fc5

Browse files
author
Edward Thomson
committed
Merge pull request #1304 from libgit2/cmn/signatures
Add signature-handling methods
2 parents ccee01a + 508807f commit 1fb7fc5

File tree

8 files changed

+350
-1
lines changed

8 files changed

+350
-1
lines changed

LibGit2Sharp.Tests/CommitFixture.cs

Lines changed: 114 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;
@@ -1055,5 +1056,118 @@ public void CanPrettifyAMessage()
10551056
Assert.Equal(expected, Commit.PrettifyMessage(input, '#'));
10561057
Assert.Equal(expected, Commit.PrettifyMessage(input.Replace('#', ';'), ';'));
10571058
}
1059+
1060+
private readonly string signedCommit = @"tree 6b79e22d69bf46e289df0345a14ca059dfc9bdf6
1061+
parent 34734e478d6cf50c27c9d69026d93974d052c454
1062+
author Ben Burkert <ben@benburkert.com> 1358451456 -0800
1063+
committer Ben Burkert <ben@benburkert.com> 1358451456 -0800
1064+
gpgsig -----BEGIN PGP SIGNATURE-----
1065+
Version: GnuPG v1.4.12 (Darwin)
1066+
1067+
iQIcBAABAgAGBQJQ+FMIAAoJEH+LfPdZDSs1e3EQAJMjhqjWF+WkGLHju7pTw2al
1068+
o6IoMAhv0Z/LHlWhzBd9e7JeCnanRt12bAU7yvYp9+Z+z+dbwqLwDoFp8LVuigl8
1069+
JGLcnwiUW3rSvhjdCp9irdb4+bhKUnKUzSdsR2CK4/hC0N2i/HOvMYX+BRsvqweq
1070+
AsAkA6dAWh+gAfedrBUkCTGhlNYoetjdakWqlGL1TiKAefEZrtA1TpPkGn92vbLq
1071+
SphFRUY9hVn1ZBWrT3hEpvAIcZag3rTOiRVT1X1flj8B2vGCEr3RrcwOIZikpdaW
1072+
who/X3xh/DGbI2RbuxmmJpxxP/8dsVchRJJzBwG+yhwU/iN3MlV2c5D69tls/Dok
1073+
6VbyU4lm/ae0y3yR83D9dUlkycOnmmlBAHKIZ9qUts9X7mWJf0+yy2QxJVpjaTGG
1074+
cmnQKKPeNIhGJk2ENnnnzjEve7L7YJQF6itbx5VCOcsGh3Ocb3YR7DMdWjt7f8pu
1075+
c6j+q1rP7EpE2afUN/geSlp5i3x8aXZPDj67jImbVCE/Q1X9voCtyzGJH7MXR0N9
1076+
ZpRF8yzveRfMH8bwAJjSOGAFF5XkcR/RNY95o+J+QcgBLdX48h+ZdNmUf6jqlu3J
1077+
7KmTXXQcOVpN6dD3CmRFsbjq+x6RHwa8u1iGn+oIkX908r97ckfB/kHKH7ZdXIJc
1078+
cpxtDQQMGYFpXK/71stq
1079+
=ozeK
1080+
-----END PGP SIGNATURE-----
1081+
1082+
a simple commit which works
1083+
";
1084+
1085+
private readonly string signatureData = @"-----BEGIN PGP SIGNATURE-----
1086+
Version: GnuPG v1.4.12 (Darwin)
1087+
1088+
iQIcBAABAgAGBQJQ+FMIAAoJEH+LfPdZDSs1e3EQAJMjhqjWF+WkGLHju7pTw2al
1089+
o6IoMAhv0Z/LHlWhzBd9e7JeCnanRt12bAU7yvYp9+Z+z+dbwqLwDoFp8LVuigl8
1090+
JGLcnwiUW3rSvhjdCp9irdb4+bhKUnKUzSdsR2CK4/hC0N2i/HOvMYX+BRsvqweq
1091+
AsAkA6dAWh+gAfedrBUkCTGhlNYoetjdakWqlGL1TiKAefEZrtA1TpPkGn92vbLq
1092+
SphFRUY9hVn1ZBWrT3hEpvAIcZag3rTOiRVT1X1flj8B2vGCEr3RrcwOIZikpdaW
1093+
who/X3xh/DGbI2RbuxmmJpxxP/8dsVchRJJzBwG+yhwU/iN3MlV2c5D69tls/Dok
1094+
6VbyU4lm/ae0y3yR83D9dUlkycOnmmlBAHKIZ9qUts9X7mWJf0+yy2QxJVpjaTGG
1095+
cmnQKKPeNIhGJk2ENnnnzjEve7L7YJQF6itbx5VCOcsGh3Ocb3YR7DMdWjt7f8pu
1096+
c6j+q1rP7EpE2afUN/geSlp5i3x8aXZPDj67jImbVCE/Q1X9voCtyzGJH7MXR0N9
1097+
ZpRF8yzveRfMH8bwAJjSOGAFF5XkcR/RNY95o+J+QcgBLdX48h+ZdNmUf6jqlu3J
1098+
7KmTXXQcOVpN6dD3CmRFsbjq+x6RHwa8u1iGn+oIkX908r97ckfB/kHKH7ZdXIJc
1099+
cpxtDQQMGYFpXK/71stq
1100+
=ozeK
1101+
-----END PGP SIGNATURE-----";
1102+
1103+
private readonly string signedData = @"tree 6b79e22d69bf46e289df0345a14ca059dfc9bdf6
1104+
parent 34734e478d6cf50c27c9d69026d93974d052c454
1105+
author Ben Burkert <ben@benburkert.com> 1358451456 -0800
1106+
committer Ben Burkert <ben@benburkert.com> 1358451456 -0800
1107+
1108+
a simple commit which works
1109+
";
1110+
1111+
1112+
[Fact]
1113+
public void CanExtractSignatureFromCommit()
1114+
{
1115+
string repoPath = InitNewRepository();
1116+
using (var repo = new Repository(repoPath))
1117+
{
1118+
var odb = repo.ObjectDatabase;
1119+
var signedId = odb.Write<Commit>(Encoding.UTF8.GetBytes(signedCommit));
1120+
1121+
// Look up the commit to make sure we wrote something valid
1122+
var commit = repo.Lookup<Commit>(signedId);
1123+
Assert.Equal("a simple commit which works\n", commit.Message);
1124+
1125+
var signatureInfo = Commit.ExtractSignature(repo, signedId, "gpgsig");
1126+
Assert.Equal(signedData, signatureInfo.SignedData);
1127+
Assert.Equal(signatureData, signatureInfo.Signature);
1128+
1129+
signatureInfo = Commit.ExtractSignature(repo, signedId);
1130+
Assert.Equal(signedData, signatureInfo.SignedData);
1131+
Assert.Equal(signatureData, signatureInfo.Signature);
1132+
}
1133+
}
1134+
1135+
[Fact]
1136+
public void CanCreateACommitString()
1137+
{
1138+
string repoPath = SandboxStandardTestRepo();
1139+
using (var repo = new Repository(repoPath))
1140+
{
1141+
var tipCommit = repo.Head.Tip;
1142+
var recreatedCommit = Commit.CreateBuffer(
1143+
tipCommit.Author,
1144+
tipCommit.Committer,
1145+
tipCommit.Message,
1146+
tipCommit.Tree,
1147+
tipCommit.Parents,
1148+
false, null);
1149+
1150+
var recreatedId = repo.ObjectDatabase.Write<Commit>(Encoding.UTF8.GetBytes(recreatedCommit));
1151+
Assert.Equal(tipCommit.Id, recreatedId);
1152+
}
1153+
}
1154+
1155+
[Fact]
1156+
public void CanCreateASignedCommit()
1157+
{
1158+
string repoPath = InitNewRepository();
1159+
using (var repo = new Repository(repoPath))
1160+
{
1161+
var odb = repo.ObjectDatabase;
1162+
var signedId = odb.Write<Commit>(Encoding.UTF8.GetBytes(signedCommit));
1163+
var signedId2 = odb.CreateCommitWithSignature(signedData, signatureData);
1164+
1165+
Assert.Equal(signedId, signedId2);
1166+
1167+
var signatureInfo = Commit.ExtractSignature(repo, signedId2);
1168+
Assert.Equal(signedData, signatureInfo.SignedData);
1169+
Assert.Equal(signatureData, signatureInfo.Signature);
1170+
}
1171+
}
10581172
}
10591173
}

LibGit2Sharp/Commit.cs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,68 @@ private string DebuggerDisplay
138138
}
139139
}
140140

141+
/// <summary>
142+
/// Extract the signature data from this commit
143+
/// </summary>
144+
/// <returns>The signature and the signed data</returns>
145+
/// <param name="repo">The repository in which the object lives</param>
146+
/// <param name="id">The commit to extract the signature from</param>
147+
/// <param name="field">The header field which contains the signature; use null for the default of "gpgsig"</param>
148+
public static SignatureInfo ExtractSignature(Repository repo, ObjectId id, string field)
149+
{
150+
return Proxy.git_commit_extract_signature(repo.Handle, id, field);
151+
}
152+
153+
/// <summary>
154+
/// Extract the signature data from this commit
155+
/// <para>
156+
/// The overload uses the default header field "gpgsig"
157+
/// </para>
158+
/// </summary>
159+
/// <returns>The signature and the signed data</returns>
160+
/// <param name="repo">The repository in which the object lives</param>
161+
/// <param name="id">The commit to extract the signature from</param>
162+
public static SignatureInfo ExtractSignature(Repository repo, ObjectId id)
163+
{
164+
return Proxy.git_commit_extract_signature(repo.Handle, id, null);
165+
}
166+
167+
/// <summary>
168+
/// Create a commit in-memory
169+
/// <para>
170+
/// Prettifing the message includes:
171+
/// * Removing empty lines from the beginning and end.
172+
/// * Removing trailing spaces from every line.
173+
/// * Turning multiple consecutive empty lines between paragraphs into just one empty line.
174+
/// * Ensuring the commit message ends with a newline.
175+
/// * Removing every line starting with the <paramref name="commentChar"/>.
176+
/// </para>
177+
/// </summary>
178+
/// <param name="author">The <see cref="Signature"/> of who made the change.</param>
179+
/// <param name="committer">The <see cref="Signature"/> of who added the change to the repository.</param>
180+
/// <param name="message">The description of why a change was made to the repository.</param>
181+
/// <param name="tree">The <see cref="Tree"/> of the <see cref="Commit"/> to be created.</param>
182+
/// <param name="parents">The parents of the <see cref="Commit"/> to be created.</param>
183+
/// <param name="prettifyMessage">True to prettify the message, or false to leave it as is.</param>
184+
/// <param name="commentChar">When non null, lines starting with this character will be stripped if prettifyMessage is true.</param>
185+
/// <returns>The contents of the commit object.</returns>
186+
public static string CreateBuffer(Signature author, Signature committer, string message, Tree tree, IEnumerable<Commit> parents, bool prettifyMessage, char? commentChar)
187+
{
188+
Ensure.ArgumentNotNull(message, "message");
189+
Ensure.ArgumentDoesNotContainZeroByte(message, "message");
190+
Ensure.ArgumentNotNull(author, "author");
191+
Ensure.ArgumentNotNull(committer, "committer");
192+
Ensure.ArgumentNotNull(tree, "tree");
193+
Ensure.ArgumentNotNull(parents, "parents");
194+
195+
if (prettifyMessage)
196+
{
197+
message = Proxy.git_message_prettify(message, commentChar);
198+
}
199+
200+
return Proxy.git_commit_create_buffer(tree.repo.Handle, author, committer, message, tree, parents.ToArray());
201+
}
202+
141203
private class ParentsCollection : ICollection<Commit>
142204
{
143205
private readonly Lazy<ICollection<Commit>> _parents;

LibGit2Sharp/Core/NativeMethods.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,27 @@ internal static extern unsafe int git_commit_create_from_ids(
316316
UIntPtr parentCount,
317317
[MarshalAs(UnmanagedType.LPArray)] [In] IntPtr[] parents);
318318

319+
[DllImport(libgit2)]
320+
internal static extern unsafe int git_commit_create_buffer(
321+
GitBuf res,
322+
git_repository* repo,
323+
git_signature* author,
324+
git_signature* committer,
325+
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string encoding,
326+
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string message,
327+
git_object* tree,
328+
UIntPtr parent_count,
329+
IntPtr* parents /* git_commit** originally */);
330+
331+
[DllImport(libgit2)]
332+
internal static extern unsafe int git_commit_create_with_signature(
333+
out GitOid id,
334+
git_repository* repo,
335+
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string commit_content,
336+
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string signature,
337+
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string signature_field);
338+
339+
319340
[DllImport(libgit2)]
320341
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(LaxUtf8NoCleanupMarshaler))]
321342
internal static extern unsafe string git_commit_message(git_object* commit);
@@ -337,6 +358,14 @@ internal static extern unsafe int git_commit_create_from_ids(
337358
[DllImport(libgit2)]
338359
internal static extern unsafe git_oid* git_commit_tree_id(git_object* commit);
339360

361+
[DllImport(libgit2)]
362+
internal static extern unsafe int git_commit_extract_signature(
363+
GitBuf signature,
364+
GitBuf signed_data,
365+
git_repository *repo,
366+
ref GitOid commit_id,
367+
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string field);
368+
340369
[DllImport(libgit2)]
341370
internal static extern unsafe int git_config_delete_entry(
342371
git_config* cfg,
@@ -919,6 +948,9 @@ internal static extern unsafe int git_odb_foreach(
919948
[DllImport(libgit2)]
920949
internal static extern unsafe void git_odb_stream_free(git_odb_stream* stream);
921950

951+
[DllImport(libgit2)]
952+
internal static extern unsafe int git_odb_write(out GitOid id, git_odb *odb, byte* data, UIntPtr len, GitObjectType type);
953+
922954
[DllImport(libgit2)]
923955
internal static extern unsafe git_oid* git_object_id(git_object* obj);
924956

LibGit2Sharp/Core/Proxy.cs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,61 @@ public static unsafe ObjectId git_commit_create(
388388
}
389389
}
390390

391+
public static unsafe string git_commit_create_buffer(
392+
RepositoryHandle repo,
393+
Signature author,
394+
Signature committer,
395+
string message,
396+
Tree tree,
397+
Commit[] parents)
398+
{
399+
using (SignatureHandle authorHandle = author.BuildHandle())
400+
using (SignatureHandle committerHandle = committer.BuildHandle())
401+
using (var treeHandle = Proxy.git_object_lookup(tree.repo.Handle, tree.Id, GitObjectType.Tree))
402+
using (var buf = new GitBuf())
403+
{
404+
ObjectHandle[] handles = new ObjectHandle[0];
405+
try
406+
{
407+
handles = parents.Select(c => Proxy.git_object_lookup(c.repo.Handle, c.Id, GitObjectType.Commit)).ToArray();
408+
var ptrs = handles.Select(p => p.AsIntPtr()).ToArray();
409+
int res;
410+
fixed(IntPtr* objs = ptrs)
411+
{
412+
res = NativeMethods.git_commit_create_buffer(buf,
413+
repo,
414+
authorHandle,
415+
committerHandle,
416+
null,
417+
message,
418+
treeHandle,
419+
new UIntPtr((ulong)parents.LongCount()),
420+
objs);
421+
}
422+
Ensure.ZeroResult(res);
423+
}
424+
finally
425+
{
426+
foreach (var handle in handles)
427+
{
428+
handle.Dispose();
429+
}
430+
}
431+
432+
return LaxUtf8Marshaler.FromNative(buf.ptr);
433+
}
434+
}
435+
436+
public static unsafe ObjectId git_commit_create_with_signature(RepositoryHandle repo, string commitContent,
437+
string signature, string field)
438+
{
439+
GitOid id;
440+
int res = NativeMethods.git_commit_create_with_signature(out id, repo, commitContent, signature, field);
441+
Ensure.ZeroResult(res);
442+
443+
return id;
444+
}
445+
391446
public static unsafe string git_commit_message(ObjectHandle obj)
392447
{
393448
return NativeMethods.git_commit_message(obj);
@@ -426,6 +481,22 @@ public static unsafe ObjectId git_commit_tree_id(ObjectHandle obj)
426481
return ObjectId.BuildFromPtr(NativeMethods.git_commit_tree_id(obj));
427482
}
428483

484+
public static unsafe SignatureInfo git_commit_extract_signature(RepositoryHandle repo, ObjectId id, string field)
485+
{
486+
using (var signature = new GitBuf())
487+
using (var signedData = new GitBuf())
488+
{
489+
var oid = id.Oid;
490+
Ensure.ZeroResult(NativeMethods.git_commit_extract_signature(signature, signedData, repo, ref oid, field));
491+
492+
return new SignatureInfo()
493+
{
494+
Signature = LaxUtf8Marshaler.FromNative(signature.ptr, signature.size.ConvertToInt()),
495+
SignedData = LaxUtf8Marshaler.FromNative(signedData.ptr, signedData.size.ConvertToInt()),
496+
};
497+
}
498+
}
499+
429500
#endregion
430501

431502
#region git_config_
@@ -1510,6 +1581,19 @@ public static unsafe ObjectId git_odb_stream_finalize_write(OdbStreamHandle stre
15101581
return id;
15111582
}
15121583

1584+
public static unsafe ObjectId git_odb_write(ObjectDatabaseHandle odb, byte[] data, ObjectType type)
1585+
{
1586+
GitOid id;
1587+
int res;
1588+
fixed(byte* p = data)
1589+
{
1590+
res = NativeMethods.git_odb_write(out id, odb, p, new UIntPtr((ulong)data.LongLength), type.ToGitObjectType());
1591+
}
1592+
Ensure.ZeroResult(res);
1593+
1594+
return id;
1595+
}
1596+
15131597
#endregion
15141598

15151599
#region git_patch_

LibGit2Sharp/GitObject.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public abstract class GitObject : IEquatable<GitObject>, IBelongToARepository
2828
/// <summary>
2929
/// The <see cref="Repository"/> containing the object.
3030
/// </summary>
31-
protected readonly Repository repo;
31+
internal readonly Repository repo;
3232

3333
/// <summary>
3434
/// Needed for mocking purposes.

LibGit2Sharp/LibGit2Sharp.csproj

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

0 commit comments

Comments
 (0)
0