8000 Add signature-handling methods by carlosmn · Pull Request #1304 · libgit2/libgit2sharp · GitHub
[go: up one dir, main page]

Skip to content

Add signature-handling methods #1304

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 27, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 114 additions & 0 deletions LibGit2Sharp.Tests/CommitFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using LibGit2Sharp.Core;
using LibGit2Sharp.Tests.TestHelpers;
using Xunit;
Expand Down Expand Up @@ -1055,5 +1056,118 @@ public void CanPrettifyAMessage()
Assert.Equal(expected, Commit.PrettifyMessage(input, '#'));
Assert.Equal(expected, Commit.PrettifyMessage(input.Replace('#', ';'), ';'));
}

private readonly string signedCommit = @"tree 6b79e22d69bf46e289df0345a14ca059dfc9bdf6
parent 34734e478d6cf50c27c9d69026d93974d052c454
author Ben Burkert <ben@benburkert.com> 1358451456 -0800
committer Ben Burkert <ben@benburkert.com> 1358451456 -0800
gpgsig -----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.12 (Darwin)

iQIcBAABAgAGBQJQ+FMIAAoJEH+LfPdZDSs1e3EQAJMjhqjWF+WkGLHju7pTw2al
o6IoMAhv0Z/LHlWhzBd9e7JeCnanRt12bAU7yvYp9+Z+z+dbwqLwDoFp8LVuigl8
JGLcnwiUW3rSvhjdCp9irdb4+bhKUnKUzSdsR2CK4/hC0N2i/HOvMYX+BRsvqweq
AsAkA6dAWh+gAfedrBUkCTGhlNYoetjdakWqlGL1TiKAefEZrtA1TpPkGn92vbLq
SphFRUY9hVn1ZBWrT3hEpvAIcZag3rTOiRVT1X1flj8B2vGCEr3RrcwOIZikpdaW
who/X3xh/DGbI2RbuxmmJpxxP/8dsVchRJJzBwG+yhwU/iN3MlV2c5D69tls/Dok
6VbyU4lm/ae0y3yR83D9dUlkycOnmmlBAHKIZ9qUts9X7mWJf0+yy2QxJVpjaTGG
cmnQKKPeNIhGJk2ENnnnzjEve7L7YJQF6itbx5VCOcsGh3Ocb3YR7DMdWjt7f8pu
c6j+q1rP7EpE2afUN/geSlp5i3x8aXZPDj67jImbVCE/Q1X9voCtyzGJH7MXR0N9
ZpRF8yzveRfMH8bwAJjSOGAFF5XkcR/RNY95o+J+QcgBLdX48h+ZdNmUf6jqlu3J
7KmTXXQcOVpN6dD3CmRFsbjq+x6RHwa8u1iGn+oIkX908r97ckfB/kHKH7ZdXIJc
cpxtDQQMGYFpXK/71stq
=ozeK
-----END PGP SIGNATURE-----

a simple commit which works
";

private readonly string signatureData = @"-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.12 (Darwin)

iQIcBAABAgAGBQJQ+FMIAAoJEH+LfPdZDSs1e3EQAJMjhqjWF+WkGLHju7pTw2al
o6IoMAhv0Z/LHlWhzBd9e7JeCnanRt12bAU7yvYp9+Z+z+dbwqLwDoFp8LVuigl8
JGLcnwiUW3rSvhjdCp9irdb4+bhKUnKUzSdsR2CK4/hC0N2i/HOvMYX+BRsvqweq
AsAkA6dAWh+gAfedrBUkCTGhlNYoetjdakWqlGL1TiKAefEZrtA1TpPkGn92vbLq
SphFRUY9hVn1ZBWrT3hEpvAIcZag3rTOiRVT1X1flj8B2vGCEr3RrcwOIZikpdaW
who/X3xh/DGbI2RbuxmmJpxxP/8dsVchRJJzBwG+yhwU/iN3MlV2c5D69tls/Dok
6VbyU4lm/ae0y3yR83D9dUlkycOnmmlBAHKIZ9qUts9X7mWJf0+yy2QxJVpjaTGG
cmnQKKPeNIhGJk2ENnnnzjEve7L7YJQF6itbx5VCOcsGh3Ocb3YR7DMdWjt7f8pu
c6j+q1rP7EpE2afUN/geSlp5i3x8aXZPDj67jImbVCE/Q1X9voCtyzGJH7MXR0N9
ZpRF8yzveRfMH8bwAJjSOGAFF5XkcR/RNY95o+J+QcgBLdX48h+ZdNmUf6jqlu3J
7KmTXXQcOVpN6dD3CmRFsbjq+x6RHwa8u1iGn+oIkX908r97ckfB/kHKH7ZdXIJc
cpxtDQQMGYFpXK/71stq
=ozeK
-----END PGP SIGNATURE-----";

private readonly string signedData = @"tree 6b79e22d69bf46e289df0345a14ca059dfc9bdf6
parent 34734e478d6cf50c27c9d69026d93974d052c454
author Ben Burkert <ben@benburkert.com> 1358451456 -0800
committer Ben Burkert <ben@benburkert.com> 1358451456 -0800

a simple commit which works
";


[Fact]
public void CanExtractSignatureFromCommit()
{
string repoPath = InitNewRepository();
using (var repo = new Repository(repoPath))
{
var odb = repo.ObjectDatabase;
var signedId = odb.Write<Commit>(Encoding.UTF8.GetBytes(signedCommit));

// Look up the commit to make sure we wrote something valid
var commit = repo.Lookup<Commit>(signedId);
Assert.Equal("a simple commit which works\n", commit.Message);

var signatureInfo = Commit.ExtractSignature(repo, signedId, "gpgsig");
Assert.Equal(signedData, signatureInfo.SignedData);
Assert.Equal(signatureData, signatureInfo.Signature);

signatureInfo = Commit.ExtractSignature(repo, signedId);
Assert.Equal(signedData, signatureInfo.SignedData);
Assert.Equal(signatureData, signatureInfo.Signature);
}
}

[Fact]
public void CanCreateACommitString()
{
string repoPath = SandboxStandardTestRepo();
using (var repo = new Repository(repoPath))
{
var tipCommit = repo.Head.Tip;
var recreatedCommit = Commit.CreateBuffer(
tipCommit.Author,
tipCommit.Committer,
tipCommit.Message,
tipCommit.Tree,
tipCommit.Parents,
false, null);

var recreatedId = repo.ObjectDatabase.Write<Commit>(Encoding.UTF8.GetBytes(recreatedCommit));
Assert.Equal(tipCommit.Id, recreatedId);
}
}

[Fact]
public void CanCreateASignedCommit()
{
string repoPath = InitNewRepository();
using (var repo = new Repository(repoPath))
{
var odb = repo.ObjectDatabase;
var signedId = odb.Write<Commit>(Encoding.UTF8.GetBytes(signedCommit));
var signedId2 = odb.CreateCommitWithSignature(signedData, signatureData);

Assert.Equal(signedId, signedId2);

var signatureInfo = Commit.ExtractSignature(repo, signedId2);
Assert.Equal(signedData, signatureInfo.SignedData);
Assert.Equal(signatureData, signatureInfo.Signature);
}
}
}
}
62 changes: 62 additions & 0 deletions LibGit2Sharp/Commit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,68 @@ private string DebuggerDisplay
}
}

/// <summary>
/// Extract the signature data from this commit
/// </summary>
/// <returns>The signature and the signed data</returns>
/// <param name="repo">The repository in which the object lives</param>
/// <param name="id">The commit to extract the signature from</param>
/// <param name="field">The header field which contains the signature; use null for the default of "gpgsig"</param>
public static SignatureInfo ExtractSignature(Repository repo, ObjectId id, string field)
{
return Proxy.git_commit_extract_signature(repo.Handle, id, field);
}

/// <summary>
/// Extract the signature data from this commit
/// <para>
/// The overload uses the default header field "gpgsig"
/// </para>
/// </summary>
/// <returns>The signature and the signed data</returns>
/// <param name="repo">The repository in which the object lives</param>
/// <param name="id">The commit to extract the signature from</param>
public static SignatureInfo ExtractSignature(Repository repo, ObjectId id)
{
return Proxy.git_commit_extract_signature(repo.Handle, id, null);
}

/// <summary>
/// Create a commit in-memory
/// <para>
/// Prettifing the message includes:
/// * Removing empty lines from the beginning and end.
/// * Removing trailing spaces from every line.
/// * Turning multiple consecutive empty lines between paragraphs into just one empty line.
/// * Ensuring the commit message ends with a newline.
/// * Removing every line starting with the <paramref name="commentChar"/>.
/// </para>
/// </summary>
/// <param name="author">The <see cref="Signature"/> of who made the change.</param>
/// <param name="committer">The <see cref="Signature"/> of who added the change to the repository.</param>
/// <param name="message">The description of why a change was made to the repository.</param>
/// <param name="tree">The <see cref="Tree"/> of the <see cref="Commit"/> to be created.</param>
/// <param name="parents">The parents of the <see cref="Commit"/> to be created.</param>
/// <param name="prettifyMessage">True to prettify the message, or false to leave it as is.</param>
/// <param name="commentChar">When non null, lines starting with this character will be stripped if prettifyMessage is true.</param>
/// <returns>The contents of the commit object.</returns>
public static string CreateBuffer(Signature author, Signature committer, string message, Tree tree, IEnumerable<Commit> parents, bool prettifyMessage, char? commentChar)
{
Ensure.ArgumentNotNull(message, "message");
Ensure.ArgumentDoesNotContainZeroByte(message, "message");
Ensure.ArgumentNotNull(author, "author");
Ensure.ArgumentNotNull(committer, "committer");
Ensure.ArgumentNotNull(tree, "tree");
Ensure.ArgumentNotNull(parents, "parents");

if (prettifyMessage)
{
message = Proxy.git_message_prettify(message, commentChar);
}

return Proxy.git_commit_create_buffer(tree.repo.Handle, author, committer, message, tree, parents.ToArray());
}

private class ParentsCollection : ICollection<Commit>
{
private readonly Lazy<ICollection<Commit>> _parents;
Expand Down
32 changes: 32 additions & 0 deletions LibGit2Sharp/Core/NativeMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,27 @@ internal static extern unsafe int git_commit_create_from_ids(
UIntPtr parentCount,
[MarshalAs(UnmanagedType.LPArray)] [In] IntPtr[] parents);

[DllImport(libgit2)]
internal static extern unsafe int git_commit_create_buffer(
GitBuf res,
git_repository* repo,
git_signature* author,
git_signature* committer,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string encoding,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string message,
git_object* tree,
UIntPtr parent_count,
IntPtr* parents /* git_commit** originally */);

[DllImport(libgit2)]
internal static extern unsafe int git_commit_create_with_signature(
out GitOid id,
git_repository* repo,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string commit_content,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string signature,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string signature_field);


[DllImport(libgit2)]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(LaxUtf8NoCleanupMarshaler))]
internal static extern unsafe string git_commit_message(git_object* commit);
Expand All @@ -337,6 +358,14 @@ internal static extern unsafe int git_commit_create_from_ids(
[DllImport(libgit2)]
internal static extern unsafe git_oid* git_commit_tree_id(git_object* commit);

[DllImport(libgit2)]
internal static extern unsafe int git_commit_extract_signature(
GitBuf signature,
GitBuf signed_data,
git_repository *repo,
ref GitOid commit_id,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string field);

[DllImport(libgit2)]
internal static extern unsafe int git_config_delete_entry(
git_config* cfg,
Expand Down Expand Up @@ -919,6 +948,9 @@ internal static extern unsafe int git_odb_foreach(
[DllImport(libgit2)]
internal static extern unsafe void git_odb_stream_free(git_odb_stream* stream);

[DllImport(libgit2)]
internal static extern unsafe int git_odb_write(out GitOid id, git_odb *odb, byte* data, UIntPtr len, GitObjectType type);

[DllImport(libgit2)]
internal static extern unsafe git_oid* git_object_id(git_object* obj);

Expand Down
84 changes: 84 additions & 0 deletions LibGit2Sharp/Core/Proxy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,61 @@ public static unsafe ObjectId git_commit_create(
}
}

public static unsafe string git_commit_create_buffer(
RepositoryHandle repo,
Signature author,
Signature committer,
string message,
Tree tree,
Commit[] parents)
{
using (SignatureHandle authorHandle = author.BuildHandle())
using (SignatureHandle committerHandle = committer.BuildHandle())
using (var treeHandle = Proxy.git_object_lookup(tree.repo.Handle, tree.Id, GitObjectType.Tree))
using (var buf = new GitBuf())
{
ObjectHandle[] handles = new ObjectHandle[0];
try
{
handles = parents.Select(c => Proxy.git_object_lookup(c.repo.Handle, c.Id, GitObjectType.Commit)).ToArray();
var ptrs = handles.Select(p => p.AsIntPtr()).ToArray();
int res;
fixed(IntPtr* objs = ptrs)
{
res = NativeMethods.git_commit_create_buffer(buf,
repo,
authorHandle,
committerHandle,
null,
message,
treeHandle,
new UIntPtr((ulong)parents.LongCount()),
objs);
}
Ensure.ZeroResult(res);
}
finally
{
foreach (var handle in handles)
{
handle.Dispose();
}
}

return LaxUtf8Marshaler.FromNative(buf.ptr);
}
}

public static unsafe ObjectId git_commit_create_with_signature(RepositoryHandle repo, string commitContent,
string signature, string field)
{
GitOid id;
int res = NativeMethods.git_commit_create_with_signature(out id, repo, commitContent, signature, field);
Ensure.ZeroResult(res);

return id;
}

public static unsafe string git_commit_message(ObjectHandle obj)
{
return NativeMethods.git_commit_message(obj);
Expand Down Expand Up @@ -426,6 +481,22 @@ public static unsafe ObjectId git_commit_tree_id(ObjectHandle obj)
return ObjectId.BuildFromPtr(NativeMethods.git_commit_tree_id(obj));
}

public static unsafe SignatureInfo git_commit_extract_signature(RepositoryHandle repo, ObjectId id, string field)
{
using (var signature = new GitBuf())
using (var signedData = new GitBuf())
{
var oid = id.Oid;
Ensure.ZeroResult(NativeMethods.git_commit_extract_signature(signature, signedData, repo, ref oid, field));

return new SignatureInfo()
{
Signature = LaxUtf8Marshaler.FromNative(signature.ptr, signature.size.ConvertToInt()),
SignedData = LaxUtf8Marshaler.FromNative(signedData.ptr, signedData.size.ConvertToInt()),
};
}
}

#endregion

#region git_config_
Expand Down Expand Up @@ -1510,6 +1581,19 @@ public static unsafe ObjectId git_odb_stream_finalize_write(OdbStreamHandle stre
return id;
}

public static unsafe ObjectId git_odb_write(ObjectDatabaseHandle odb, byte[] data, ObjectType type)
{
GitOid id;
int res;
fixed(byte* p = data)
{
res = NativeMethods.git_odb_write(out id, odb, p, new UIntPtr((ulong)data.LongLength), type.ToGitObjectType());
}
Ensure.ZeroResult(res);

return id;
}

#endregion

#region git_patch_
Expand Down
2 changes: 1 addition & 1 deletion LibGit2Sharp/GitObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public abstract class GitObject : IEquatable<GitObject>, IBelongToARepository
/// <summary>
/// The <see cref="Repository"/> containing the object.
/// </summary>
protected readonly Repository repo;
internal readonly Repository repo;

/// <summary>
/// Needed for mocking purposes.
Expand Down
1 change: 1 addition & 0 deletions LibGit2Sharp/LibGit2Sharp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@
<Compile Include="Commands\Stage.cs" />
<Compile Include="Commands\Remove.cs" />
<Compile Include="Commands\Checkout.cs" />
<Compile Include="SignatureInfo.cs" />
</ItemGroup>
<ItemGroup>
<CodeAnalysisDictionary Include="CustomDictionary.xml" />
Expand Down
Loading
0