145 lines
4.6 KiB
C#
145 lines
4.6 KiB
C#
using System;
|
|
using NuGet.Protocol.Plugins;
|
|
|
|
namespace NugetSecretCredential;
|
|
|
|
public static class Program
|
|
{
|
|
private static bool _shuttingDown = false;
|
|
public static bool IsShuttingDown => Volatile.Read(ref _shuttingDown);
|
|
|
|
public static async Task<int> Main(string[] args)
|
|
{
|
|
CancellationTokenSource tokenSource = new CancellationTokenSource();
|
|
|
|
List<ICredentialProvider> credentialProviders = new List<ICredentialProvider>
|
|
{
|
|
new GitTokenCredentialProvider(),
|
|
};
|
|
|
|
try
|
|
{
|
|
bool isPlugin = false;
|
|
bool isRetry = false;
|
|
bool isNonInteractive = false;
|
|
bool canShowDialog = false;
|
|
Uri? uri = null;
|
|
for (int i = 0; i < args.Length; i++)
|
|
switch (args[i].ToLower())
|
|
{
|
|
case "-p": case "-plugin": isPlugin = true; break;
|
|
case "-i": case "-isretry": isRetry = true; break;
|
|
case "-n": case "-noninteractive": isNonInteractive = true; break;
|
|
case "-c": case "-canshowdialog": canShowDialog = true; break;
|
|
case "-u": case "-uri":
|
|
if (i + 1 == args.Length)
|
|
throw new ArgumentException("Expected uri after -U");
|
|
if (!Uri.TryCreate(args[i + 1], UriKind.Absolute, out uri))
|
|
throw new ArgumentException("Invalid uri format");
|
|
break;
|
|
}
|
|
|
|
IRequestHandlers requestHandlers = new RequestHandlerCollection
|
|
{
|
|
{ MessageMethod.GetAuthenticationCredentials, new GetAuthenticationCredentialsRequestHandler(credentialProviders) },
|
|
{ MessageMethod.GetOperationClaims, new GetOperationClaimsRequestHandler() },
|
|
{ MessageMethod.Initialize, new InitializeRequestHandler() },
|
|
{ MessageMethod.SetLogLevel, new SetLogLevelRequestHandler() },
|
|
{ MessageMethod.SetCredentials, new SetCredentialsRequestHandler() },
|
|
};
|
|
|
|
if (isPlugin)
|
|
{
|
|
// Plugin mode
|
|
try
|
|
{
|
|
using (IPlugin plugin = await PluginFactory.CreateFromCurrentProcessAsync(requestHandlers, ConnectionOptions.CreateDefault(), tokenSource.Token))
|
|
{
|
|
await WaitForPluginExitAsync(plugin, TimeSpan.FromMinutes(2)).ConfigureAwait(continueOnCapturedContext: false);
|
|
}
|
|
}
|
|
catch (OperationCanceledException ex)
|
|
{
|
|
// When restoring from multiple sources, one of the sources will throw an unhandled TaskCanceledException
|
|
// if it has been restored successfully from a different source.
|
|
|
|
// This is probably more confusing than interesting to users, but may be helpful in debugging,
|
|
// so log the exception but not to the console.
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
// Stand-alone mode
|
|
if (requestHandlers.TryGet(MessageMethod.GetAuthenticationCredentials, out IRequestHandler requestHandler) && requestHandler is GetAuthenticationCredentialsRequestHandler getAuthenticationCredentialsRequestHandler)
|
|
{
|
|
if (uri == null)
|
|
{
|
|
Console.WriteLine("Uri argument -U not provided");
|
|
return 1;
|
|
}
|
|
|
|
GetAuthenticationCredentialsRequest request = new GetAuthenticationCredentialsRequest(uri, isRetry: isRetry, isNonInteractive, canShowDialog);
|
|
GetAuthenticationCredentialsResponse response = await getAuthenticationCredentialsRequestHandler.HandleRequestAsync(request, default);
|
|
|
|
// Fail if credentials are not found
|
|
if (response?.ResponseCode != MessageResponseCode.Success)
|
|
{
|
|
return 2;
|
|
}
|
|
|
|
Console.WriteLine("username=" + response.Username);
|
|
Console.WriteLine("password=" + response.Password);
|
|
return 0;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Console.Error.WriteLine("Error " + e.GetType().Name + ": " + e.Message);
|
|
File.WriteAllText("/home/rv/temp/nsc.error.log", "Error " + e.GetType().Name + ": " + e.Message);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
internal static async Task WaitForPluginExitAsync(IPlugin plugin, TimeSpan shutdownTimeout)
|
|
{
|
|
var beginShutdownTaskSource = new TaskCompletionSource<object>();
|
|
var endShutdownTaskSource = new TaskCompletionSource<object>();
|
|
|
|
plugin.Connection.Faulted += (sender, a) =>
|
|
{
|
|
Console.WriteLine(a.Exception.ToString());
|
|
};
|
|
|
|
plugin.BeforeClose += (sender, args) =>
|
|
{
|
|
Volatile.Write(ref _shuttingDown, true);
|
|
beginShutdownTaskSource.TrySetResult(null);
|
|
};
|
|
|
|
plugin.Closed += (sender, a) =>
|
|
{
|
|
// beginShutdownTaskSource should already be set in BeforeClose, but just in case do it here too
|
|
beginShutdownTaskSource.TrySetResult(null);
|
|
|
|
endShutdownTaskSource.TrySetResult(null);
|
|
};
|
|
|
|
await beginShutdownTaskSource.Task;
|
|
using (new Timer(_ => endShutdownTaskSource.TrySetCanceled(), null, shutdownTimeout, TimeSpan.FromMilliseconds(-1)))
|
|
{
|
|
await endShutdownTaskSource.Task;
|
|
}
|
|
|
|
if (endShutdownTaskSource.Task.IsCanceled)
|
|
{
|
|
Console.WriteLine("Plugin timeout");
|
|
}
|
|
}
|
|
}
|