diff --git a/.vscode/launch.json b/.vscode/launch.json index 7c89965d..b583119f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -2,7 +2,7 @@ "version": "0.2.0", "configurations": [ { - "name": ".NET Core Launch (console)", + "name": "net 6 launch", "type": "coreclr", "request": "launch", "preLaunchTask": "build", @@ -13,7 +13,10 @@ ], "cwd": "${workspaceFolder}/CredentialProvider.Microsoft", "console": "integratedTerminal", - "stopAtEntry": false + "stopAtEntry": false, + "env": { + "ARTIFACTS_CREDENTIALPROVIDER_PROGRAM_CONTEXT":"nuGET" + } }, { "name": ".NET Core Attach", diff --git a/CredentialProvider.Microsoft/Program.cs b/CredentialProvider.Microsoft/Program.cs index 3059fcb3..fa21aa49 100644 --- a/CredentialProvider.Microsoft/Program.cs +++ b/CredentialProvider.Microsoft/Program.cs @@ -113,6 +113,7 @@ public static async Task Main(string[] args) multiLogger.Add(new PluginConnectionLogger(plugin.Connection)); multiLogger.Verbose(Resources.RunningInPlugin); multiLogger.Verbose(string.Format(Resources.CommandLineArgs, PlatformInformation.GetProgramVersion(), Environment.CommandLine)); + EnvUtil.SetProgramContextInEnvironment(Context.NuGet); await WaitForPluginExitAsync(plugin, multiLogger, TimeSpan.FromMinutes(2)).ConfigureAwait(continueOnCapturedContext: false); } diff --git a/CredentialProvider.Microsoft/Util/EnvUtil.cs b/CredentialProvider.Microsoft/Util/EnvUtil.cs index 3d310329..d11b8b12 100644 --- a/CredentialProvider.Microsoft/Util/EnvUtil.cs +++ b/CredentialProvider.Microsoft/Util/EnvUtil.cs @@ -39,6 +39,8 @@ public static class EnvUtil public const string EndpointCredentials = "ARTIFACTS_CREDENTIALPROVIDER_FEED_ENDPOINTS"; public const string BuildTaskExternalEndpoints = "VSS_NUGET_EXTERNAL_FEED_ENDPOINTS"; + public const string ProgramContext = "ARTIFACTS_CREDENTIALPROVIDER_PROGRAM_CONTEXT"; + public static bool GetLogPIIEnabled() { return GetEnabledFromEnvironment(LogPIIEnvVar, defaultValue: false); @@ -182,6 +184,24 @@ public static int GetDeviceFlowTimeoutFromEnvironmentInSeconds(ILogger logger) return null; } + public static Context? GetProgramContextFromEnvironment() + { + var context = Environment.GetEnvironmentVariable(ProgramContext); + + if (!string.IsNullOrWhiteSpace(context) && Enum.TryParse(context, ignoreCase: true, out Context result)) + { + return result; + } + + return null; + } + + public static void SetProgramContextInEnvironment(Context context) + { + Environment.SetEnvironmentVariable(ProgramContext, context.ToString()); + return; + } + private static bool GetEnabledFromEnvironment(string envVar, bool defaultValue = true) { if (bool.TryParse(Environment.GetEnvironmentVariable(envVar), out bool result)) diff --git a/CredentialProvider.Microsoft/Util/HttpClientFactory.cs b/CredentialProvider.Microsoft/Util/HttpClientFactory.cs index 35f0fb18..2c31fb20 100644 --- a/CredentialProvider.Microsoft/Util/HttpClientFactory.cs +++ b/CredentialProvider.Microsoft/Util/HttpClientFactory.cs @@ -3,6 +3,7 @@ // Licensed under the MIT license. using System.Net.Http; +using System.Net.Http.Headers; using Microsoft.Artifacts.Authentication; namespace NuGetCredentialProvider.Util @@ -26,7 +27,32 @@ static HttpClientFactory() UseDefaultCredentials = true }); + // Add program context to headers if available + if (ProgramContext != null) + { + httpClient.DefaultRequestHeaders.UserAgent.Add(ProgramContext); + } + httpClientFactory = new(httpClient); } + + private static ProductInfoHeaderValue ProgramContext + { + get + { + var context = EnvUtil.GetProgramContextFromEnvironment(); + return context != null + ? new ProductInfoHeaderValue($"({context})") + : null; + } + } + } + + public enum Context + { + Maven, + NuGet, + Pip, + Conda, } }