Initial implementation
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
obj
|
||||
bin
|
||||
15
.vscode/launch.json
vendored
Normal file
15
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Launch",
|
||||
"type": "coreclr",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/bin/Debug/net9.0/NugetSecretCredential.dll",
|
||||
"args": ["-U", "https://www.example.org"]
|
||||
}
|
||||
]
|
||||
}
|
||||
60
GetAuthenticationCredentialsRequestHandler.cs
Normal file
60
GetAuthenticationCredentialsRequestHandler.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using NuGet.Protocol.Plugins;
|
||||
|
||||
namespace NugetSecretCredential;
|
||||
|
||||
internal class GetAuthenticationCredentialsRequestHandler : RequestHandlerBase<GetAuthenticationCredentialsRequest, GetAuthenticationCredentialsResponse>
|
||||
{
|
||||
private readonly IReadOnlyCollection<ICredentialProvider> _credentialProviders;
|
||||
private readonly TimeSpan progressReporterTimeSpan = TimeSpan.FromSeconds(2);
|
||||
|
||||
public GetAuthenticationCredentialsRequestHandler(IReadOnlyCollection<ICredentialProvider> credentialProviders)
|
||||
{
|
||||
this._credentialProviders = credentialProviders ?? throw new ArgumentNullException();
|
||||
}
|
||||
|
||||
public override async Task<GetAuthenticationCredentialsResponse> HandleRequestAsync(GetAuthenticationCredentialsRequest request, CancellationToken cancel)
|
||||
{
|
||||
if (request?.Uri == null)
|
||||
return new GetAuthenticationCredentialsResponse(
|
||||
username: null,
|
||||
password: null,
|
||||
message: "Uri is null",
|
||||
authenticationTypes: null,
|
||||
responseCode: MessageResponseCode.Error);
|
||||
|
||||
foreach (ICredentialProvider credentialProvider in _credentialProviders)
|
||||
{
|
||||
if (await credentialProvider.CanProvideCredentialsAsync(request.Uri, cancel) == false)
|
||||
continue;
|
||||
|
||||
try
|
||||
{
|
||||
GetAuthenticationCredentialsResponse response = await credentialProvider.HandleRequestAsync(request, cancel);
|
||||
if (response != null && response.ResponseCode == MessageResponseCode.Success)
|
||||
return response;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return new GetAuthenticationCredentialsResponse(
|
||||
username: null,
|
||||
password: null,
|
||||
message: e.Message,
|
||||
authenticationTypes: null,
|
||||
responseCode: MessageResponseCode.Error);
|
||||
}
|
||||
}
|
||||
|
||||
return new GetAuthenticationCredentialsResponse(
|
||||
username: null,
|
||||
password: null,
|
||||
message: null,
|
||||
authenticationTypes: null,
|
||||
responseCode: MessageResponseCode.NotFound);
|
||||
}
|
||||
|
||||
protected override AutomaticProgressReporter GetProgressReporter(IConnection connection, Message message, CancellationToken cancellationToken)
|
||||
{
|
||||
return AutomaticProgressReporter.Create(connection, message, progressReporterTimeSpan, cancellationToken);
|
||||
}
|
||||
}
|
||||
20
GetOperationClaimsRequestHandler.cs
Normal file
20
GetOperationClaimsRequestHandler.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using NuGet.Protocol.Plugins;
|
||||
|
||||
namespace NugetSecretCredential;
|
||||
|
||||
internal class GetOperationClaimsRequestHandler : RequestHandlerBase<GetOperationClaimsRequest, GetOperationClaimsResponse>
|
||||
{
|
||||
private static readonly GetOperationClaimsResponse CanProvideCredentialsResponse =
|
||||
new GetOperationClaimsResponse(new List<OperationClaim> { OperationClaim.Authentication });
|
||||
|
||||
private static readonly GetOperationClaimsResponse EmptyGetOperationClaimsResponse =
|
||||
new GetOperationClaimsResponse(new List<OperationClaim>());
|
||||
|
||||
public override Task<GetOperationClaimsResponse> HandleRequestAsync(GetOperationClaimsRequest request, CancellationToken cancel)
|
||||
{
|
||||
return request.PackageSourceRepository != null || request.ServiceIndex != null
|
||||
? Task.FromResult(EmptyGetOperationClaimsResponse)
|
||||
: Task.FromResult(CanProvideCredentialsResponse);
|
||||
}
|
||||
}
|
||||
132
GitTokenCredentialProvider.cs
Normal file
132
GitTokenCredentialProvider.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using NuGet.Protocol.Plugins;
|
||||
|
||||
namespace NugetSecretCredential;
|
||||
|
||||
sealed class GitTokenCredentialProvider : ICredentialProvider
|
||||
{
|
||||
private const string TokenUserName = "nugetToken"; // can be anything constant
|
||||
|
||||
private const int MaxCredentialHelperTimeout = 2000;
|
||||
|
||||
private static Lazy<Task<string?>> _credentialHelper = new Lazy<Task<string?>>(DetermineGitCredentialHelper);
|
||||
|
||||
public async Task<bool> CanProvideCredentialsAsync(Uri uri, CancellationToken cancel)
|
||||
{
|
||||
Task<string?> credHelper;
|
||||
if (!_credentialHelper.IsValueCreated || !_credentialHelper.Value.IsCompleted)
|
||||
{
|
||||
TaskCompletionSource cancelTrigger = new TaskCompletionSource();
|
||||
using (CancellationTokenRegistration cancelReg = cancel.Register(() => cancelTrigger.SetResult()))
|
||||
{
|
||||
credHelper = _credentialHelper.Value;
|
||||
Task t = await Task.WhenAny(credHelper, cancelTrigger.Task);
|
||||
if (t != credHelper)
|
||||
throw new TaskCanceledException();
|
||||
}
|
||||
}
|
||||
else
|
||||
credHelper = _credentialHelper.Value;
|
||||
|
||||
return credHelper.Result != null;
|
||||
}
|
||||
|
||||
public async Task<GetAuthenticationCredentialsResponse> HandleRequestAsync(GetAuthenticationCredentialsRequest request, CancellationToken cancel)
|
||||
{
|
||||
ProcessStartInfo psiHelper = new ProcessStartInfo();
|
||||
psiHelper.FileName = _credentialHelper.Value.Result;
|
||||
psiHelper.ArgumentList.Add("get");
|
||||
psiHelper.RedirectStandardInput = true;
|
||||
psiHelper.RedirectStandardOutput = true;
|
||||
Process? pHelper = Process.Start(psiHelper);
|
||||
if (pHelper == null)
|
||||
// Credential helper executable not found
|
||||
return new GetAuthenticationCredentialsResponse(null, null, null, null, responseCode: MessageResponseCode.Error);
|
||||
|
||||
pHelper.StandardInput.WriteLine("protocol=https");
|
||||
pHelper.StandardInput.WriteLine("username=s" + TokenUserName);
|
||||
pHelper.StandardInput.WriteLine("host=" + request.Uri.DnsSafeHost);
|
||||
pHelper.StandardInput.WriteLine();
|
||||
|
||||
await pHelper.WaitForExitAsync(cancel);
|
||||
|
||||
string? line;
|
||||
while ((line = pHelper.StandardOutput.ReadLine()) != null)
|
||||
{
|
||||
const string PasswordKey = "password=";
|
||||
if (line.StartsWith(PasswordKey))
|
||||
// Password found
|
||||
return new GetAuthenticationCredentialsResponse(
|
||||
TokenUserName, line.Substring(PasswordKey.Length), null,
|
||||
new List<string> { "Basic" }, MessageResponseCode.Success
|
||||
);
|
||||
}
|
||||
|
||||
// Password not found (we may be allowed to ask for it interactively)
|
||||
if (request.CanShowDialog)
|
||||
{
|
||||
ProcessStartInfo psiDialog = new ProcessStartInfo();
|
||||
psiDialog.FileName = "zenity";
|
||||
foreach (string i in (IEnumerable<string>)["--forms", "--title", "Nuget repository", "--text", request.Uri.DnsSafeHost, "--add-password=Token"])
|
||||
psiDialog.ArgumentList.Add(i);
|
||||
psiDialog.RedirectStandardOutput = true;
|
||||
Process? pDialog = Process.Start(psiDialog);
|
||||
if (pDialog != null)
|
||||
{
|
||||
// Zenity dialog executable found
|
||||
await pDialog.WaitForExitAsync(cancel);
|
||||
string? password = pDialog.StandardOutput.ReadLine();
|
||||
if (password != null && password.Length != 0 && pDialog.StandardOutput.ReadLine() == null)
|
||||
{
|
||||
// We have a new password, persist it also
|
||||
ProcessStartInfo psiHelperStore = new ProcessStartInfo();
|
||||
psiHelperStore.FileName = _credentialHelper.Value.Result;
|
||||
psiHelperStore.ArgumentList.Add("store");
|
||||
psiHelperStore.RedirectStandardInput = true;
|
||||
Process? pHelperStore = Process.Start(psiHelperStore);
|
||||
if (pHelperStore == null)
|
||||
// Credential helper executable not found
|
||||
return new GetAuthenticationCredentialsResponse(null, null, null, null, responseCode: MessageResponseCode.Error);
|
||||
|
||||
pHelperStore.StandardInput.WriteLine("protocol=https");
|
||||
pHelperStore.StandardInput.WriteLine("username=" + TokenUserName);
|
||||
pHelperStore.StandardInput.WriteLine("password=" + password);
|
||||
pHelperStore.StandardInput.WriteLine("host=" + request.Uri.DnsSafeHost);
|
||||
pHelper.StandardInput.WriteLine();
|
||||
await pHelperStore.WaitForExitAsync(cancel);
|
||||
|
||||
return new GetAuthenticationCredentialsResponse(
|
||||
TokenUserName, password, null,
|
||||
new List<string> { "Basic" }, MessageResponseCode.Success
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new GetAuthenticationCredentialsResponse(null, null, null, null, responseCode: MessageResponseCode.NotFound);
|
||||
}
|
||||
|
||||
private static async Task<string?> DetermineGitCredentialHelper()
|
||||
{
|
||||
CancellationTokenSource cancel = new CancellationTokenSource(MaxCredentialHelperTimeout);
|
||||
ProcessStartInfo psi = new ProcessStartInfo();
|
||||
psi.FileName = "git";
|
||||
psi.ArgumentList.Add("config");
|
||||
psi.ArgumentList.Add("--global");
|
||||
psi.ArgumentList.Add("credential.helper");
|
||||
psi.RedirectStandardOutput = true;
|
||||
Process? p = Process.Start(psi);
|
||||
if (p == null)
|
||||
// Git executable not found
|
||||
return null;
|
||||
|
||||
await p.WaitForExitAsync(cancel.Token);
|
||||
string? result = p.StandardOutput.ReadLine();
|
||||
if (p.StandardOutput.ReadLine() != null)
|
||||
// Expected a single line with the credential helper executable path
|
||||
return null;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
18
ICredentialProvider.cs
Normal file
18
ICredentialProvider.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using NuGet.Protocol.Plugins;
|
||||
|
||||
namespace NugetSecretCredential;
|
||||
|
||||
internal interface ICredentialProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks if implementation can provide credentials.
|
||||
/// </summary>
|
||||
/// <param name="uri">The of the target.</param>
|
||||
Task<bool> CanProvideCredentialsAsync(Uri uri, CancellationToken cancel);
|
||||
|
||||
/// <summary>
|
||||
/// Handle credential request.
|
||||
/// </summary>
|
||||
Task<GetAuthenticationCredentialsResponse> HandleRequestAsync(GetAuthenticationCredentialsRequest request, CancellationToken cancellationToken);
|
||||
}
|
||||
12
InitializeRequestHandler.cs
Normal file
12
InitializeRequestHandler.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using NuGet.Protocol.Plugins;
|
||||
|
||||
namespace NugetSecretCredential;
|
||||
|
||||
internal class InitializeRequestHandler : RequestHandlerBase<InitializeRequest, InitializeResponse>
|
||||
{
|
||||
public override Task<InitializeResponse> HandleRequestAsync(InitializeRequest request, CancellationToken cancel)
|
||||
{
|
||||
return Task.FromResult(new InitializeResponse(MessageResponseCode.Success));
|
||||
}
|
||||
}
|
||||
13
NugetSecretCredential.csproj
Normal file
13
NugetSecretCredential.csproj
Normal file
@@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NuGet.Protocol" Version="6.13.2" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
24
NugetSecretCredential.sln
Normal file
24
NugetSecretCredential.sln
Normal file
@@ -0,0 +1,24 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.5.2.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NugetSecretCredential", "NugetSecretCredential.csproj", "{E0BA52C4-F4D2-9748-5150-5C8C38E7E84A}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{E0BA52C4-F4D2-9748-5150-5C8C38E7E84A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E0BA52C4-F4D2-9748-5150-5C8C38E7E84A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E0BA52C4-F4D2-9748-5150-5C8C38E7E84A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E0BA52C4-F4D2-9748-5150-5C8C38E7E84A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {5D4949AB-9A45-4602-9433-7372AE5554B8}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
145
Program.cs
Normal file
145
Program.cs
Normal file
@@ -0,0 +1,145 @@
|
||||
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)
|
||||
{
|
||||
File.WriteAllText("/home/rv/temp/nsc.log", "Starting");
|
||||
|
||||
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);
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
40
RequestHandlerBase.cs
Normal file
40
RequestHandlerBase.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using NuGet.Protocol.Plugins;
|
||||
|
||||
namespace NugetSecretCredential;
|
||||
|
||||
internal abstract class RequestHandlerBase<TRequest, TResponse> : IRequestHandler
|
||||
where TResponse : class
|
||||
{
|
||||
protected RequestHandlerBase()
|
||||
{
|
||||
}
|
||||
|
||||
CancellationToken IRequestHandler.CancellationToken => default;
|
||||
|
||||
public IConnection? Connection { get; private set; }
|
||||
|
||||
public virtual CancellationToken CancellationToken { get; private set; } = CancellationToken.None;
|
||||
|
||||
public async Task HandleResponseAsync(IConnection connection, Message message, IResponseHandler responseHandler, CancellationToken cancel)
|
||||
{
|
||||
Connection = connection;
|
||||
|
||||
TRequest request = MessageUtilities.DeserializePayload<TRequest>(message);
|
||||
|
||||
TResponse? response = null;
|
||||
using (GetProgressReporter(connection, message, cancel))
|
||||
{
|
||||
response = await HandleRequestAsync(request, cancel);
|
||||
}
|
||||
// If we did not send a cancel message, we must submit the response even if cancellationToken is canceled.
|
||||
await responseHandler.SendResponseAsync(message, response, CancellationToken.None);
|
||||
}
|
||||
|
||||
public abstract Task<TResponse> HandleRequestAsync(TRequest request, CancellationToken cancel);
|
||||
|
||||
protected virtual AutomaticProgressReporter? GetProgressReporter(IConnection connection, Message message, CancellationToken cancel)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
28
RequestHandlerCollection.cs
Normal file
28
RequestHandlerCollection.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using NuGet.Protocol.Plugins;
|
||||
|
||||
namespace NugetSecretCredential;
|
||||
|
||||
internal class RequestHandlerCollection : ConcurrentDictionary<MessageMethod, IRequestHandler>, IRequestHandlers
|
||||
{
|
||||
public void Add(MessageMethod method, IRequestHandler handler)
|
||||
{
|
||||
TryAdd(method, handler);
|
||||
}
|
||||
|
||||
public void AddOrUpdate(MessageMethod method, Func<IRequestHandler> addHandlerFunc, Func<IRequestHandler, IRequestHandler> updateHandlerFunc)
|
||||
{
|
||||
AddOrUpdate(method, messageMethod => addHandlerFunc(), (messageMethod, requestHandler) => updateHandlerFunc(requestHandler));
|
||||
}
|
||||
|
||||
public bool TryGet(MessageMethod method, out IRequestHandler requestHandler)
|
||||
{
|
||||
return TryGetValue(method, out requestHandler);
|
||||
}
|
||||
|
||||
public bool TryRemove(MessageMethod method)
|
||||
{
|
||||
return TryRemove(method, out IRequestHandler _);
|
||||
}
|
||||
}
|
||||
15
SetCredentialsRequestHandler.cs
Normal file
15
SetCredentialsRequestHandler.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using NuGet.Protocol.Plugins;
|
||||
|
||||
namespace NugetSecretCredential;
|
||||
|
||||
internal class SetCredentialsRequestHandler : RequestHandlerBase<SetCredentialsRequest, SetCredentialsResponse>
|
||||
{
|
||||
private static readonly SetCredentialsResponse SuccessResponse = new SetCredentialsResponse(MessageResponseCode.Success);
|
||||
|
||||
public override Task<SetCredentialsResponse> HandleRequestAsync(SetCredentialsRequest request, CancellationToken cancel)
|
||||
{
|
||||
// There's currently no way to handle proxies, so nothing we can do here
|
||||
return Task.FromResult(SuccessResponse);
|
||||
}
|
||||
}
|
||||
14
SetLogLevelRequestHandler.cs
Normal file
14
SetLogLevelRequestHandler.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using NuGet.Protocol.Plugins;
|
||||
|
||||
namespace NugetSecretCredential;
|
||||
|
||||
internal class SetLogLevelRequestHandler : RequestHandlerBase<SetLogLevelRequest, SetLogLevelResponse>
|
||||
{
|
||||
private static readonly SetLogLevelResponse SuccessResponse = new SetLogLevelResponse(MessageResponseCode.Success);
|
||||
|
||||
public override Task<SetLogLevelResponse> HandleRequestAsync(SetLogLevelRequest request, CancellationToken cancel)
|
||||
{
|
||||
return Task.FromResult(SuccessResponse);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user