From 405b9f99dd817679dab70b775f1d05ace51ac562 Mon Sep 17 00:00:00 2001 From: Rob Reynolds Date: Sun, 21 Jun 2015 17:59:09 -0500 Subject: [PATCH 1/5] (GH-305) add warning if application not uninstalled If the underlying application is not uninstalled by autouninstaller, warn the user they will need to take manual action --- .../infrastructure.app/services/AutomaticUninstallerService.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/chocolatey/infrastructure.app/services/AutomaticUninstallerService.cs b/src/chocolatey/infrastructure.app/services/AutomaticUninstallerService.cs index f90f7d7cfc..928203830a 100644 --- a/src/chocolatey/infrastructure.app/services/AutomaticUninstallerService.cs +++ b/src/chocolatey/infrastructure.app/services/AutomaticUninstallerService.cs @@ -149,6 +149,7 @@ public void run(PackageResult packageResult, ChocolateyConfiguration config) if (skipUninstaller) { this.Log().Info(" Skipping auto uninstaller - Installer type was not detected and no silent uninstall key exists."); + this.Log().Warn("If the application was not removed with a chocolateyUninstall.ps1,{0} please remove it from Programs and Features manually.".format_with(Environment.NewLine)); return; } } From 0840f7990d4eb1a599483f4d16305c1761d03031 Mon Sep 17 00:00:00 2001 From: Rob Reynolds Date: Fri, 26 Jun 2015 16:21:11 -0500 Subject: [PATCH 2/5] (spec) Set uninstall base scenario --- src/chocolatey.tests.integration/Scenario.cs | 8 ++++++++ .../scenarios/UninstallScenarios.cs | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/chocolatey.tests.integration/Scenario.cs b/src/chocolatey.tests.integration/Scenario.cs index 08fa4ae024..2cd30486f3 100644 --- a/src/chocolatey.tests.integration/Scenario.cs +++ b/src/chocolatey.tests.integration/Scenario.cs @@ -149,5 +149,13 @@ public static ChocolateyConfiguration upgrade() return config; } + + public static ChocolateyConfiguration uninstall() + { + var config = baseline_configuration(); + config.CommandName = CommandNameType.uninstall.to_string(); + + return config; + } } } \ No newline at end of file diff --git a/src/chocolatey.tests.integration/scenarios/UninstallScenarios.cs b/src/chocolatey.tests.integration/scenarios/UninstallScenarios.cs index 4708192dfd..ae1e0257a3 100644 --- a/src/chocolatey.tests.integration/scenarios/UninstallScenarios.cs +++ b/src/chocolatey.tests.integration/scenarios/UninstallScenarios.cs @@ -41,7 +41,7 @@ public abstract class ScenariosBase : TinySpec public override void Context() { - Configuration = Scenario.install(); + Configuration = Scenario.uninstall(); Scenario.reset(Configuration); Configuration.PackageNames = Configuration.Input = "installpackage"; Scenario.add_packages_to_source_location(Configuration, Configuration.Input + "*" + Constants.PackageExtension); From 8edaa75be85dd0720eb2b0112c132518c174af03 Mon Sep 17 00:00:00 2001 From: Rob Reynolds Date: Fri, 26 Jun 2015 16:25:27 -0500 Subject: [PATCH 3/5] (GH-219)(GH-56) Allow PowerShell interaction Allow PowerShell to use the same window as the choco process that brings back the download progress bar and being able to do things like read-host. --- .../commands/CommandExecutorSpecs.cs | 2 +- .../services/ChocolateyPackageService.cs | 4 ++-- .../infrastructure/commands/CommandExecutor.cs | 15 +++++++++++---- .../infrastructure/commands/PowershellExecutor.cs | 13 ++++++++++++- 4 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/chocolatey.tests.integration/infrastructure/commands/CommandExecutorSpecs.cs b/src/chocolatey.tests.integration/infrastructure/commands/CommandExecutorSpecs.cs index 80b2868545..07d67cb769 100644 --- a/src/chocolatey.tests.integration/infrastructure/commands/CommandExecutorSpecs.cs +++ b/src/chocolatey.tests.integration/infrastructure/commands/CommandExecutorSpecs.cs @@ -47,7 +47,7 @@ public override void Context() public override void Because() { - result = CommandExecutor.execute("cmd.exe", "/c bob123123", ApplicationParameters.DefaultWaitForExitInSeconds, fileSystem.get_current_directory(), null, (s, e) => { errorOutput += e.Data; }, updateProcessPath: false); + result = CommandExecutor.execute("cmd.exe", "/c bob123123", ApplicationParameters.DefaultWaitForExitInSeconds, fileSystem.get_current_directory(), null, (s, e) => { errorOutput += e.Data; }, updateProcessPath: false, allowUseWindow: false); } [Fact] diff --git a/src/chocolatey/infrastructure.app/services/ChocolateyPackageService.cs b/src/chocolatey/infrastructure.app/services/ChocolateyPackageService.cs index c8a5294021..02108c33e7 100644 --- a/src/chocolatey/infrastructure.app/services/ChocolateyPackageService.cs +++ b/src/chocolatey/infrastructure.app/services/ChocolateyPackageService.cs @@ -178,7 +178,7 @@ public void handle_package_result(PackageResult packageResult, ChocolateyConfigu if (powerShellRan) { // we don't care about the exit code - if (config.Information.PlatformType == PlatformType.Windows) CommandExecutor.execute("shutdown", "/a", config.CommandExecutionTimeoutSeconds, _fileSystem.get_current_directory(), (s, e) => { }, (s, e) => { }, false); + if (config.Information.PlatformType == PlatformType.Windows) CommandExecutor.execute("shutdown", "/a", config.CommandExecutionTimeoutSeconds, _fileSystem.get_current_directory(), (s, e) => { }, (s, e) => { }, false, false); } var difference = _registryService.get_differences(before, _registryService.get_installer_keys()); @@ -503,7 +503,7 @@ public ConcurrentDictionary uninstall_run(ChocolateyConfi } // we don't care about the exit code - if (config.Information.PlatformType == PlatformType.Windows) CommandExecutor.execute("shutdown", "/a", config.CommandExecutionTimeoutSeconds, _fileSystem.get_current_directory(), (s, e) => { }, (s, e) => { }, false); + if (config.Information.PlatformType == PlatformType.Windows) CommandExecutor.execute("shutdown", "/a", config.CommandExecutionTimeoutSeconds, _fileSystem.get_current_directory(), (s, e) => { }, (s, e) => { }, false, false); if (packageResult.Success) { diff --git a/src/chocolatey/infrastructure/commands/CommandExecutor.cs b/src/chocolatey/infrastructure/commands/CommandExecutor.cs index 409850d7b8..e4548eb3a8 100644 --- a/src/chocolatey/infrastructure/commands/CommandExecutor.cs +++ b/src/chocolatey/infrastructure/commands/CommandExecutor.cs @@ -67,13 +67,14 @@ public int execute( file_system.get_directory_name(Assembly.GetExecutingAssembly().CodeBase.Replace("file:///", string.Empty)), stdOutAction, stdErrAction, - updateProcessPath + updateProcessPath, + allowUseWindow:false ); } public int execute(string process, string arguments, int waitForExitInSeconds, string workingDirectory) { - return execute(process, arguments, waitForExitInSeconds, workingDirectory, null, null, updateProcessPath: true); + return execute(process, arguments, waitForExitInSeconds, workingDirectory, null, null, updateProcessPath: true, allowUseWindow: false); } public static int execute(string process, @@ -82,7 +83,8 @@ public static int execute(string process, string workingDirectory, Action stdOutAction, Action stdErrAction, - bool updateProcessPath + bool updateProcessPath, + bool allowUseWindow ) { int exitCode = -1; @@ -105,9 +107,14 @@ bool updateProcessPath WorkingDirectory = workingDirectory, RedirectStandardOutput = true, RedirectStandardError = true, - CreateNoWindow = true + CreateNoWindow = !allowUseWindow, }; + if (allowUseWindow) + { + psi.WindowStyle = ProcessWindowStyle.Minimized; + } + using (var p = initialize_process()) { p.StartInfo = psi; diff --git a/src/chocolatey/infrastructure/commands/PowershellExecutor.cs b/src/chocolatey/infrastructure/commands/PowershellExecutor.cs index e79081b469..c81552da50 100644 --- a/src/chocolatey/infrastructure/commands/PowershellExecutor.cs +++ b/src/chocolatey/infrastructure/commands/PowershellExecutor.cs @@ -17,6 +17,7 @@ namespace chocolatey.infrastructure.commands { using System; using System.Collections.Generic; + using System.ComponentModel; using System.Diagnostics; using System.IO; using adapters; @@ -25,6 +26,15 @@ namespace chocolatey.infrastructure.commands public sealed class PowershellExecutor { + private static bool _allowUseWindow = true; + + [EditorBrowsable(EditorBrowsableState.Never)] + public static bool AllowUseWindow + { + get { return _allowUseWindow; } + set { _allowUseWindow = value; } + } + private static readonly IList _powershellLocations = new List { Environment.ExpandEnvironmentVariables("%systemroot%\\SysNative\\WindowsPowerShell\\v1.0\\powershell.exe"), @@ -53,7 +63,8 @@ Action stdErrAction workingDirectory: fileSystem.get_directory_name(Assembly.GetExecutingAssembly().CodeBase.Replace("file:///", string.Empty)), stdOutAction: stdOutAction, stdErrAction: stdErrAction, - updateProcessPath: true + updateProcessPath: true, + allowUseWindow: _allowUseWindow ); } From e4daf2d4ffc570feefd3bab8f86a3b33f7a5a800 Mon Sep 17 00:00:00 2001 From: Rob Reynolds Date: Fri, 26 Jun 2015 16:26:14 -0500 Subject: [PATCH 4/5] (spec) don't allow interactive windows in specs This keeps boxes from popping up during integration tests. --- src/chocolatey.tests.integration/Scenario.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/chocolatey.tests.integration/Scenario.cs b/src/chocolatey.tests.integration/Scenario.cs index 2cd30486f3..9f54ae2b63 100644 --- a/src/chocolatey.tests.integration/Scenario.cs +++ b/src/chocolatey.tests.integration/Scenario.cs @@ -24,6 +24,7 @@ namespace chocolatey.tests.integration using chocolatey.infrastructure.app.domain; using chocolatey.infrastructure.app.nuget; using chocolatey.infrastructure.app.services; + using chocolatey.infrastructure.commands; using chocolatey.infrastructure.filesystem; public class Scenario @@ -67,6 +68,8 @@ public static void reset(ChocolateyConfiguration config) _fileSystem.create_directory(backupPackagesPath); _fileSystem.create_directory(_fileSystem.combine_paths(get_top_level(), ".chocolatey")); _fileSystem.create_directory(_fileSystem.combine_paths(get_top_level(), "extensions")); + + PowershellExecutor.AllowUseWindow = false; } public static void add_packages_to_source_location(ChocolateyConfiguration config, string pattern) From 270ea940ee1bd48747f1968307f75c30023535d1 Mon Sep 17 00:00:00 2001 From: Rob Reynolds Date: Fri, 26 Jun 2015 18:02:50 -0500 Subject: [PATCH 5/5] (GH-341) Do not allow combining paths with colon When attempting to combine paths, do not allow any paths being added to have colon `:` as that will reset the path. This can lead to possibly very bad situations when an incorrect command is sent to choco. --- .../infrastructure/filesystem/DotNetFileSystemSpecs.cs | 8 ++++++++ .../commands/ChocolateyInstallCommand.cs | 7 +++++++ .../infrastructure/filesystem/DotNetFileSystem.cs | 8 ++++++++ 3 files changed, 23 insertions(+) diff --git a/src/chocolatey.tests/infrastructure/filesystem/DotNetFileSystemSpecs.cs b/src/chocolatey.tests/infrastructure/filesystem/DotNetFileSystemSpecs.cs index f00fb5b6d0..f7ca43dcbc 100644 --- a/src/chocolatey.tests/infrastructure/filesystem/DotNetFileSystemSpecs.cs +++ b/src/chocolatey.tests/infrastructure/filesystem/DotNetFileSystemSpecs.cs @@ -17,6 +17,7 @@ namespace chocolatey.tests.infrastructure.filesystem { using System; using System.IO; + using NUnit.Framework; using Should; using chocolatey.infrastructure.filesystem; using chocolatey.infrastructure.platforms; @@ -113,6 +114,13 @@ public void Combine_should_combine_when_paths_start_with_forwardslashes_in_subpa "C:\\temp\\yo\\filename.txt" : "C:/temp/yo/filename.txt"); } + + [Fact] + [ExpectedException(typeof(ApplicationException), MatchType = MessageMatch.StartsWith, ExpectedMessage = "Cannot combine a path with")] + public void Combine_should_error_if_any_path_but_the_primary_contains_colon() + { + FileSystem.combine_paths("C:\\temp", "C:"); + } } } } \ No newline at end of file diff --git a/src/chocolatey/infrastructure.app/commands/ChocolateyInstallCommand.cs b/src/chocolatey/infrastructure.app/commands/ChocolateyInstallCommand.cs index c26cbe973c..7181b0a87e 100644 --- a/src/chocolatey/infrastructure.app/commands/ChocolateyInstallCommand.cs +++ b/src/chocolatey/infrastructure.app/commands/ChocolateyInstallCommand.cs @@ -97,6 +97,13 @@ public void handle_validation(ChocolateyConfiguration configuration) { throw new ApplicationException("Package name is required. Please pass at least one package name to install."); } + // Need a better check on this before releasing. Issue will be covered by other fixes + //// investigate https://msdn.microsoft.com/en-us/library/system.io.path.getinvalidpathchars(v=vs.100).aspx + //if (configuration.PackageNames.Contains(":")) + //{ + // throw new ApplicationException("Package name cannot contain invalid characters."); + //} + if (configuration.ForceDependencies && !configuration.Force) { throw new ApplicationException("Force dependencies can only be used with force also turned on."); diff --git a/src/chocolatey/infrastructure/filesystem/DotNetFileSystem.cs b/src/chocolatey/infrastructure/filesystem/DotNetFileSystem.cs index 19dc815ddb..77aac30f4d 100644 --- a/src/chocolatey/infrastructure/filesystem/DotNetFileSystem.cs +++ b/src/chocolatey/infrastructure/filesystem/DotNetFileSystem.cs @@ -50,6 +50,8 @@ public string combine_paths(string leftItem, params string[] rightItems) var combinedPath = Platform.get_platform() == PlatformType.Windows ? leftItem : leftItem.Replace('\\', '/'); foreach (var rightItem in rightItems) { + if (rightItem.Contains(":")) throw new ApplicationException("Cannot combine a path with ':' attempted to combine '{0}' with '{1}'".format_with(rightItem, combinedPath)); + var rightSide = Platform.get_platform() == PlatformType.Windows ? rightItem : rightItem.Replace('\\', '/'); if (rightSide.StartsWith(Path.DirectorySeparatorChar.to_string()) || rightSide.StartsWith(Path.AltDirectorySeparatorChar.to_string())) { @@ -336,6 +338,9 @@ public void create_directory(string directoryPath) public void move_directory(string directoryPath, string newDirectoryPath) { + if (string.IsNullOrWhiteSpace(directoryPath) || string.IsNullOrWhiteSpace(newDirectoryPath)) throw new ApplicationException("You must provide a directory to move from or to."); + if (combine_paths(directoryPath,"").is_equal_to(combine_paths(Environment.GetEnvironmentVariable("SystemDrive"),""))) throw new ApplicationException("Cannot move or delete the root of the system drive"); + try { this.Log().Debug("Moving '{0}'{1} to '{2}'".format_with(directoryPath, Environment.NewLine, newDirectoryPath)); @@ -404,6 +409,9 @@ public void create_directory_if_not_exists(string directoryPath, bool ignoreErro public void delete_directory(string directoryPath, bool recursive) { + if (string.IsNullOrWhiteSpace(directoryPath)) throw new ApplicationException("You must provide a directory to delete."); + if (combine_paths(directoryPath, "").is_equal_to(combine_paths(Environment.GetEnvironmentVariable("SystemDrive"), ""))) throw new ApplicationException("Cannot move or delete the root of the system drive"); + this.Log().Debug(() => "Attempting to delete directory \"{0}\".".format_with(get_full_path(directoryPath))); allow_retries(() => Directory.Delete(directoryPath, recursive)); }