mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-13 23:14:53 +09:00
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:
1 parent
660af756e6
commit
70cf680edd
6 files changed
+161
-7
No files matched your search
@@ -0,0 +1,4 @@
|
||||
"use strict";
|
||||
if (module === require.main) {
|
||||
process.stdout.write(JSON.stringify(process.argv.slice(2)));
|
||||
}
|
||||
@@ -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: "" }
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,3 @@
|
||||
@ECHO off
|
||||
REM this is how npm and package.json bin entries forwards arguments on Windows
|
||||
node.exe %*
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
# this is how package.json bin entries forwards arguments on Linux
|
||||
exec node "$@"
|
||||
Reference in new issue
Block a user