diff --git a/src/chocolatey.tests.integration/scenarios/ListScenarios.cs b/src/chocolatey.tests.integration/scenarios/ListScenarios.cs index cf72223c35..d00930ddd8 100644 --- a/src/chocolatey.tests.integration/scenarios/ListScenarios.cs +++ b/src/chocolatey.tests.integration/scenarios/ListScenarios.cs @@ -21,6 +21,7 @@ using NuGet.Configuration; using FluentAssertions; using FluentAssertions.Execution; +using NUnit.Framework; namespace chocolatey.tests.integration.scenarios { @@ -140,7 +141,10 @@ public void Should_contain_packages_and_versions_with_a_pipe_between_them() MockLogger.ContainsMessage("upgradepackage|1.0.0").Should().BeTrue(); } + // Windows only because decryption fallback on Mac/Linux logs a message [Fact] + [WindowsOnly] + [Platform(Exclude = "Mono")] public void Should_only_have_messages_related_to_package_information() { MockLogger.Messages.Should() diff --git a/src/chocolatey/infrastructure.app/services/NugetService.cs b/src/chocolatey/infrastructure.app/services/NugetService.cs index eed43df34c..e91910412c 100644 --- a/src/chocolatey/infrastructure.app/services/NugetService.cs +++ b/src/chocolatey/infrastructure.app/services/NugetService.cs @@ -192,6 +192,7 @@ it is possible that incomplete package lists are returned from a command foreach (var pkg in NugetList.GetPackages(config, _nugetLogger, _fileSystem)) { var package = pkg; // for lamda access + string packageArgumentsUnencrypted = null; ChocolateyPackageMetadata packageLocalMetadata; string packageInstallLocation = null; @@ -218,6 +219,12 @@ it is possible that incomplete package lists are returned from a command } deploymentLocation = packageInfo.DeploymentLocation; + if (!string.IsNullOrWhiteSpace(packageInfo.Arguments)) + { + var decryptedArguments = ArgumentsUtility.DecryptPackageArgumentsFile(_fileSystem, packageInfo.Package.Id, packageInfo.Package.Version.ToNormalizedStringChecked()); + + packageArgumentsUnencrypted = "\n Remembered Package Arguments: \n {0}".FormatWith(string.Join(Environment.NewLine + " ", decryptedArguments)); + } } if (!config.QuietOutput) @@ -244,7 +251,7 @@ Package url{6} Tags: {9} Software Site: {10} Software License: {11}{12}{13}{14}{15}{16} - Description: {17}{18}{19} + Description: {17}{18}{19}{20} ".FormatWith( package.Title.EscapeCurlyBraces(), package.Published.GetValueOrDefault().UtcDateTime.ToShortDateString(), @@ -279,7 +286,8 @@ Package url{6} package.Summary != null && !string.IsNullOrWhiteSpace(package.Summary.ToStringSafe()) ? "\r\n Summary: {0}".FormatWith(package.Summary.EscapeCurlyBraces().ToStringSafe()) : string.Empty, package.Description.EscapeCurlyBraces().Replace("\n ", "\n").Replace("\n", "\n "), !string.IsNullOrWhiteSpace(package.ReleaseNotes.ToStringSafe()) ? "{0} Release Notes: {1}".FormatWith(Environment.NewLine, package.ReleaseNotes.EscapeCurlyBraces().Replace("\n ", "\n").Replace("\n", "\n ")) : string.Empty, - !string.IsNullOrWhiteSpace(deploymentLocation) ? "{0} Deployed to: '{1}'".FormatWith(Environment.NewLine, deploymentLocation) : string.Empty + !string.IsNullOrWhiteSpace(deploymentLocation) ? "{0} Deployed to: '{1}'".FormatWith(Environment.NewLine, deploymentLocation) : string.Empty, + packageArgumentsUnencrypted != null ? packageArgumentsUnencrypted : string.Empty )); } } diff --git a/src/chocolatey/infrastructure.app/utility/ArgumentsUtility.cs b/src/chocolatey/infrastructure.app/utility/ArgumentsUtility.cs index 53df50dbbf..a1a5bd58a5 100644 --- a/src/chocolatey/infrastructure.app/utility/ArgumentsUtility.cs +++ b/src/chocolatey/infrastructure.app/utility/ArgumentsUtility.cs @@ -15,6 +15,9 @@ // limitations under the License. using System; +using System.Collections.Generic; +using chocolatey.infrastructure.app.nuget; +using chocolatey.infrastructure.filesystem; namespace chocolatey.infrastructure.app.utility { @@ -50,6 +53,72 @@ public static bool SensitiveArgumentsProvided(string commandArguments) ; } + public static IEnumerable DecryptPackageArgumentsFile(IFileSystem fileSystem, string id, string version) + { + var argumentsPath = fileSystem.CombinePaths(ApplicationParameters.InstallLocation, ".chocolatey", "{0}.{1}".FormatWith(id, version)); + var argumentsFile = fileSystem.CombinePaths(argumentsPath, ".arguments"); + + var arguments = string.Empty; + + // Get the arguments decrypted in here and return them + try + { + if (fileSystem.FileExists(argumentsFile)) + { + arguments = fileSystem.ReadFile(argumentsFile); + } + } + catch (Exception ex) + { + "chocolatey".Log().Error("There was an error attempting to read the contents of the .arguments file for version '{0}' of package '{1}'. See log file for more information.".FormatWith(version, id)); + } + + if (string.IsNullOrEmpty(arguments)) + { + "chocolatey".Log().Debug("Unable to locate .arguments file for version '{0}' of package '{1}'.".FormatWith(version, id)); + yield break; + } + + // The following code is borrowed from the Chocolatey codebase, should + // be extracted to a separate location in choco executable so we can re-use it. + var packageArgumentsUnencrypted = arguments.Contains(" --") && arguments.ToStringSafe().Length > 4 + ? arguments + : NugetEncryptionUtility.DecryptString(arguments); + + // Lets do a global check first to see if there are any sensitive arguments + // before we filter out the values used later. + var sensitiveArgs = SensitiveArgumentsProvided(packageArgumentsUnencrypted); + + var packageArgumentsSplit = + packageArgumentsUnencrypted.Split(new[] { " --" }, StringSplitOptions.RemoveEmptyEntries); + + foreach (var packageArgument in packageArgumentsSplit.OrEmpty()) + { + var isSensitiveArgument = sensitiveArgs && SensitiveArgumentsProvided(string.Concat("--", packageArgument)); + + var packageArgumentSplit = + packageArgument.Split(new[] { '=' }, 2, StringSplitOptions.RemoveEmptyEntries); + + var optionName = packageArgumentSplit[0].ToStringSafe(); + var optionValue = string.Empty; + + if (packageArgumentSplit.Length == 2 && isSensitiveArgument) + { + optionValue = "[REDACTED ARGUMENT]"; + } + else if (packageArgumentSplit.Length == 2) + { + optionValue = packageArgumentSplit[1].ToStringSafe().UnquoteSafe(); + if (optionValue.StartsWith("'")) + { + optionValue.UnquoteSafe(); + } + } + + yield return "--{0}{1}".FormatWith(optionName, string.IsNullOrWhiteSpace(optionValue) ? string.Empty : "=" + optionValue); + } + } + #pragma warning disable IDE0022, IDE1006 [Obsolete("This overload is deprecated and will be removed in v3.")] public static bool arguments_contain_sensitive_information(string commandArguments)