Support libssh2 based callbacks by zentron · Pull Request #2182 · libgit2/libgit2sharp · GitHub
Skip to content
Closed
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
6 changes: 3 additions & 3 deletions LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj
10 changes: 7 additions & 3 deletions LibGit2Sharp.Tests/NetworkFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ namespace LibGit2Sharp.Tests
public class NetworkFixture : BaseFixture
{
[Theory]
[InlineData("http://github.com/libgit2/TestGitRepository")]
[InlineData("https://github.com/libgit2/TestGitRepository")]
//[InlineData("http://github.com/libgit2/TestGitRepository")]
[InlineData("git@github.com:libgit2/TestGitRepository.git")]
public void CanListRemoteReferences(string url)
{
string remoteName = "testRemote";
Expand All @@ -20,7 +20,11 @@ public void CanListRemoteReferences(string url)
using (var repo = new Repository(repoPath))
{
Remote remote = repo.Network.Remotes.Add(remoteName, url);
IList<Reference> references = repo.Network.ListReferences(remote).ToList();
IList<Reference> references = repo.Network.ListReferences(remote, (s, fromUrl, types) =>
{

return null;
}).ToList();


foreach (var reference in references)
Expand Down
141 changes: 141 additions & 0 deletions LibGit2Sharp/Core/SshExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@

@zentron zentron Mar 16, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This methods are required to be able to call down into the c libraries methods that are only available when using libssh2. The files in this class can be properly tidied up and split up before merge

using LibGit2Sharp.Core;
using System;
using System.Runtime.InteropServices;

namespace LibGit2Sharp.Ssh
{

internal static class NativeMethods
{
private const string libgit2 = NativeDllName.Name;

[DllImport(libgit2, CallingConvention = CallingConvention.Cdecl)]
internal static extern int git_cred_ssh_key_new(
out IntPtr cred,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string username,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string publickey,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string privatekey,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string passphrase);

[DllImport(libgit2)]
internal static extern int git_cred_ssh_key_memory_new(
out IntPtr cred,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string username,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string publickey,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string privatekey,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalCookie = UniqueId.UniqueIdentifier, MarshalTypeRef = typeof(StrictUtf8Marshaler))] string passphrase);
}

/// <summary>
/// Class that holds SSH username with key credentials for remote repository access.
/// </summary>
public sealed class SshUserKeyCredentials : Credentials
{
/// <summary>
/// Callback to acquire a credential object.
/// </summary>
/// <param name="cred">The newly created credential object.</param>
/// <returns>0 for success, &lt; 0 to indicate an error, &gt; 0 to indicate no credential was acquired.</returns>
protected internal override int GitCredentialHandler(out IntPtr cred)
{
if (Username == null)
{
throw new InvalidOperationException("SshUserKeyCredentials contains a null Username.");
}

if (Passphrase == null)
{
throw new InvalidOperationException("SshUserKeyCredentials contains a null Passphrase.");
}

if (PublicKey == null)
{
throw new InvalidOperationException("SshUserKeyCredentials contains a null PublicKey.");
}

if (PrivateKey == null)
{
throw new InvalidOperationException("SshUserKeyCredentials contains a null PrivateKey.");
}

return NativeMethods.git_cred_ssh_key_new(out cred, Username, PublicKey, PrivateKey, Passphrase);
}

/// <summary>
/// Username for SSH authentication.
/// </summary>
public string Username { get; set; }

/// <summary>
/// Public key file location for SSH authentication.
/// </summary>
public string PublicKey { get; set; }

/// <summary>
/// Private key file location for SSH authentication.
/// </summary>
public string PrivateKey { get; set; }

/// <summary>
/// Passphrase for SSH authentication.
/// </summary>
public string Passphrase { get; set; }
}

/// <summary>
/// Class that holds SSH username with in-memory key credentials for remote repository access.
/// </summary>
public sealed class SshUserKeyMemoryCredentials : Credentials
{
/// <summary>
/// Callback to acquire a credential object.
/// </summary>
/// <param name="cred">The newly created credential object.</param>
/// <returns>0 for success, &lt; 0 to indicate an error, &gt; 0 to indicate no credential was acquired.</returns>
protected internal override int GitCredentialHandler(out IntPtr cred)
{
if (Username == null)
{
throw new InvalidOperationException("SshUserKeyMemoryCredentials contains a null Username.");
}

if (Passphrase == null)
{
throw new InvalidOperationException("SshUserKeyMemoryCredentials contains a null Passphrase.");
}

if (PublicKey == null)
{
//throw new InvalidOperationException("SshUserKeyMemoryCredentials contains a null PublicKey.");
}

if (PrivateKey == null)
{
throw new InvalidOperationException("SshUserKeyMemoryCredentials contains a null PrivateKey.");
}

return NativeMethods.git_cred_ssh_key_memory_new(out cred, Username, PublicKey, PrivateKey, Passphrase);
}

/// <summary>
/// Username for SSH authentication.
/// </summary>
public string Username { get; set; }

/// <summary>
/// Public key for SSH authentication.
/// </summary>
public string PublicKey { get; set; }

/// <summary>
/// Private key for SSH authentication.
/// </summary>
public string PrivateKey { get; set; }

/// <summary>
/// Passphrase for SSH authentication.
/// </summary>
public string Passphrase { get; set; }
}
}
2 changes: 1 addition & 1 deletion LibGit2Sharp/GlobalSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public static class GlobalSettings

private static string nativeLibraryPath;
private static bool nativeLibraryPathLocked;
private static readonly string nativeLibraryDefaultPath = null;
private static readonly string nativeLibraryDefaultPath = "/Users/robert/Development/Sandbox/libgit2/build";

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Obviously not something to merge, just that helped testing against my local build of libgit2


static GlobalSettings()
{
Expand Down
26 changes: 26 additions & 0 deletions LibGit2Sharp/ListRemoteOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using LibGit2Sharp.Handlers;

namespace LibGit2Sharp;

/// <summary>
/// Options controlling ListRemote behavior.
/// </summary>
public sealed class ListRemoteOptions

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New ListRemoteOptions required to get appropriate handlers on the network list operation

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can probably be put in as its own PR back into the upstream repo as its not really dependant on anything ssh

{
/// <summary>
/// Handler to generate <see cref="LibGit2Sharp.Credentials"/> for authentication.
/// </summary>
public CredentialsHandler CredentialsProvider { get; set; }

/// <summary>
/// This handler will be called to let the user make a decision on whether to allow
/// the connection to proceed based on the certificate presented by the server.
/// </summary>
public CertificateCheckHandler CertificateCheck { get; set; }


/// <summary>
/// Options for connecting through a proxy.
/// </summary>
public ProxyOptions ProxyOptions { get; set; } = new();
}
105 changes: 93 additions & 12 deletions LibGit2Sharp/Network.cs
Loading
Loading