Skip to content

Commit

Permalink
Added KeyringCredentialProvider
Browse files Browse the repository at this point in the history
  • Loading branch information
bastianeicher committed Feb 17, 2024
1 parent 5635f29 commit 5a14ec6
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 1 deletion.
3 changes: 3 additions & 0 deletions src/Common.AnsiCli/Common.AnsiCli.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
<ItemGroup>
<PackageReference Include="Spectre.Console" Version="0.48.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)'=='net6.0' Or '$(TargetFramework)'=='net7.0' Or '$(TargetFramework)'=='net8.0'">
<PackageReference Include="GnomeStack.Os.Secrets" Version="0.1.3" />
</ItemGroup>

<!-- Global usings -->
<ItemGroup>
Expand Down
64 changes: 64 additions & 0 deletions src/Common.AnsiCli/Net/KeyringCredentialProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright Bastian Eicher
// Licensed under the MIT License

#if NET
using System.Net;
using GnomeStack.Os.Secrets.Darwin;
using GnomeStack.Os.Secrets.Linux;
using NanoByte.Common.Native;
using NanoByte.Common.Storage;

namespace NanoByte.Common.Net;

/// <summary>
/// Gets and stores <see cref="NetworkCredential"/>s using the OS keyring.
/// </summary>
/// <param name="innerProvider">The provider to fall back to if no suitable credentials can be found in the OS keyring (yet).</param>
public class KeyringCredentialProvider(ICredentialProvider? innerProvider = null) : ICredentialProvider
{
/// <inheritdoc/>
public NetworkCredential? GetCredential(Uri uri, bool previousIncorrect = false)
{
string service = uri.ToStringRfc();

try
{
if (UnixUtils.IsLinux && LibSecret.ListSecrets(service) is [var secret, ..])
{
if (previousIncorrect) LibSecret.DeleteSecret(service, secret.Account);
else return new(secret.Account, secret.Secret);
}
if (UnixUtils.IsMacOSX)
{
if (previousIncorrect) KeyChain.DeleteSecret(service);
else if (KeyChain.GetSecret(service, "") is {} json)
return JsonStorage.FromJsonString<NetworkCredential>(json);
}
}
#region Error handling
catch (Exception ex)
{
Log.Info("Failed to read from OS keyring", ex);
}
#endregion

var credential = innerProvider?.GetCredential(uri, previousIncorrect);
if (credential != null)
{
try
{
if (UnixUtils.IsLinux) LibSecret.SetSecret(service, credential.UserName, credential.Password);
if (UnixUtils.IsMacOSX) KeyChain.SetSecret(service, "", new {credential.UserName, credential.Password}.ToJsonString());
}
#region Error handling
catch (Exception ex)
{
Log.Info("Failed to write to OS keyring", ex);
}
#endregion
}

return credential;
}
}
#endif
8 changes: 7 additions & 1 deletion src/Common.AnsiCli/Tasks/AnsiCliTaskHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,14 @@ protected override ICredentialProvider CredentialProvider
? new WindowsCliCredentialProvider(RemoveProgressBar)
: new WindowsNonInteractiveCredentialProvider()
: IsInteractive
#if NET
? new KeyringCredentialProvider(new AnsiCliCredentialProvider(RemoveProgressBar))
: new KeyringCredentialProvider()
#else
? new AnsiCliCredentialProvider(RemoveProgressBar)
: null);
: null
#endif
);

private readonly object _progressContextLock = new();
private AnsiCliProgressContext? _progressContext;
Expand Down

0 comments on commit 5a14ec6

Please sign in to comment.