Escape arguments when installer invokes commands

The usage of shell: true means that no escaping is done on the arguments
passed to the commands invoked by the installer. This leads to the
installation failing if the user for example puts a space in the
username for the admin account.

Fix by escaping the arguments passed on command lines. This is
unreasonably complicated on Windows 😡.
This commit is contained in:
Hornwitser committed 2024-08-30 00:32:58 +02:00
1 parent 660af756e6
commit 70cf680edd
6 files changed
+161 -7

No files matched your search

+4
View File
@@ -0,0 +1,4 @@
"use strict";
if (module === require.main) {
process.stdout.write(JSON.stringify(process.argv.slice(2)));
}
+71
View File
@@ -0,0 +1,71 @@
"use strict";
const child_process = require("child_process");
const util = require("util");
const assert = require("assert").strict;
const path = require("path");
const { escapeArg } = require("../../packages/create/escape_arg");
const execFile = util.promisify(child_process.execFile);
async function exec(file, args) {
const { stdout, stderr } = await execFile(
file,
args.map(escapeArg),
// eslint-disable-next-line node/no-process-env
{ shell: true, cwd: __dirname, env: { ...process.env, pct: "%"} }
);
return { stdout: JSON.parse(stdout), stderr };
}
const strings = [
'"a"',
"a sentence of text.",
" irregular \tspaces ",
'"C:\\path\\"',
"C:\\path\\",
'\\ "\\" \\\\ "\\\\" \\\\\\ "\\\\\\" \\\\\\\\ "\\\\\\\\" \\\\\\\\\\ "\\\\\\\\\\" \\\\\\\\\\\ "\\\\\\\\\\\\"',
'"C:\\path"',
"C:\\path",
"%OS%",
"!OS!",
"😮",
];
for (let i=1; i < 128; i++) {
const char = String.fromCodePoint(i);
// Skip newline and carriage return because those are difficult to escape
// Skip most alphanumeric characters as they don't behave differently to each other.
if (/[\n\r1-9B-Zb-z]/.test(char)) {
continue;
}
strings.push(char, `${char}${char}`, `${char}"`);
}
// Test 100 strings at a time.
const tests = [[]];
for (const string of strings) {
if (tests[tests.length - 1].length >= 100) {
tests.push([]);
}
tests[tests.length - 1].push(string);
}
describe("create/escape_arg", function() {
it("should correctly escape strings when args are forwarded", async function() {
const ext = process.platform === "win32" ? ".cmd" : ".sh";
for (const args of tests) {
assert.deepEqual(
await exec(`.${path.sep}forward_args${ext}`, ["echo_args.js", ...args]),
{ stdout: args, stderr: "" }
);
}
});
it("should correctly escape strings when invoking node directly", async function() {
for (const args of tests) {
assert.deepEqual(
await exec("node", ["echo_args.js", ...args]),
{ stdout: args, stderr: "" }
);
}
});
});
+3
View File
@@ -0,0 +1,3 @@
@ECHO off
REM this is how npm and package.json bin entries forwards arguments on Windows
node.exe %*
+3
View File
@@ -0,0 +1,3 @@
#!/bin/sh
# this is how package.json bin entries forwards arguments on Linux
exec node "$@"