From babe12cd7b1d7e97236f3a6fd7e776719e67c596 Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Thu, 11 May 2017 18:05:40 -0400 Subject: [PATCH] fix(GUI): handle spaces in installation path when elevating on Windows (#1411) Etcher will get stuck at "Starting..." when executing the application on a directory that contains spaces, like "C:\Program Files (x86)". The problem is that the command is not quoted correctly when passed to `cmd.exe /c`. This commit addresses the following specific problems: - Quote the whole argument to `cmd.exe /c` - Quote each individual argument after `call` Change-Type: patch Changelog-Entry: Fix application stuck at "Starting..." on Windows. See: https://github.com/resin-io/etcher/pull/1376 Signed-off-by: Juan Cruz Viotti --- lib/shared/permissions.js | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/lib/shared/permissions.js b/lib/shared/permissions.js index e20e9c28..a9cce645 100644 --- a/lib/shared/permissions.js +++ b/lib/shared/permissions.js @@ -118,6 +118,21 @@ exports.getEnvironmentCommandPrefix = (environment) => { return _.concat([ 'env' ], argv); }; +/** + * @summary Quote a string + * @function + * @private + * + * @param {String} string - input string + * @returns {String} quoted string + * + * @example + * const result = quote('foo'); + */ +const quoteString = (string) => { + return `"${string}"`; +}; + /** * @summary Elevate a command * @function @@ -143,14 +158,22 @@ exports.getEnvironmentCommandPrefix = (environment) => { * }); */ exports.elevateCommand = (command, options) => { - const prefixedCommand = _.concat(exports.getEnvironmentCommandPrefix(options.environment), command); + const isWindows = os.platform() === 'win32'; - if (os.platform() === 'win32') { + const prefixedCommand = _.concat( + exports.getEnvironmentCommandPrefix(options.environment), + _.map(command, (string) => { + return isWindows ? quoteString(string) : string; + }) + ); + + if (isWindows) { const elevator = Bluebird.promisifyAll(nativeModule.load('elevator')); - return elevator.elevateAsync(_.concat([ + return elevator.elevateAsync([ 'cmd.exe', - '/c' - ], prefixedCommand)).then((results) => { + '/c', + quoteString(_.join(prefixedCommand, ' ')) + ]).then((results) => { return { cancelled: results.cancelled };