Skip to content

Commit

Permalink
fix: escape backslash input (#834)
Browse files Browse the repository at this point in the history
  • Loading branch information
charliecruzan-stripe authored Oct 29, 2024
1 parent ab74d3c commit c51e93d
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 18 deletions.
20 changes: 12 additions & 8 deletions src/shellEscape.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,31 @@ export function shellEscape(args: Array<string>): string {
var output: Array<string> = [];

if (getOSType() === OSType.windows) {
args.forEach(function(arg) {
args.forEach(function (arg) {
// Check if the argument is a file path
const isFilePath = /^([a-zA-Z]:)?(\\[^<>:"/\\|?*]+)+\.exe$/.test(arg);

if (!isFilePath && /[^A-Za-z0-9_\/:=-]/.test(arg)) {
arg = arg.replace(/\\/g, '\\\\');
arg = '"' + arg.replace(/"/g, '\\"') + '"';
arg = arg.replace(/^(?:"")+/g, '') // unduplicate double-quote at the beginning
arg = arg
.replace(/^(?:"")+/g, '') // unduplicate double-quote at the beginning
.replace(/\\"""/g, '\\"'); // remove non-escaped double-quote if there are enclosed between 2 escaped
}
output.push(arg);
});
return output.join(' ');
} else {
args.forEach(function(arg) {
args.forEach(function (arg) {
if (/[^A-Za-z0-9_\/:=-]/.test(arg)) {
arg = "'" + arg.replace(/'/g,"'\\''") + "'";
arg = arg.replace(/^(?:'')+/g, '') // unduplicate single-quote at the beginning
arg = arg.replace(/\\/g, '\\\\');
arg = "'" + arg.replace(/'/g, "'\\''") + "'";
arg = arg
.replace(/^(?:'')+/g, '') // unduplicate single-quote at the beginning
.replace(/\\'''/g, "\\'"); // remove non-escaped single-quote if there are enclosed between 2 escaped
};
}
output.push(arg);
});
return output.join(' ');
};
};
}
}
29 changes: 19 additions & 10 deletions test/suite/shellEscape.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
/* eslint-disable quotes */
import * as assert from 'assert';
import * as shellEscape from '../../src/shellEscape';
import * as sinon from 'sinon';
import * as utils from '../../src/utils';

import {shellEscape} from '../../src/shellEscape';

suite('shellEscape', () => {
let sandbox: sinon.SinonSandbox;
Expand All @@ -19,43 +18,53 @@ suite('shellEscape', () => {
suite('shellEscape', () => {
test('non windows case: flag with spaces', () => {
sandbox.stub(utils, 'getOSType').returns(utils.OSType.macOSarm);
const output = shellEscape.shellEscape(['--project-name', 'test | whoami']); // test | whoami
const output = shellEscape(['--project-name', 'test | whoami']); // test | whoami
assert.strictEqual(output, `--project-name 'test | whoami'`); // --project-name 'test | whoami'
});
test('non windows case: flag with single quote around entire arg', () => {
sandbox.stub(utils, 'getOSType').returns(utils.OSType.macOSarm);
const output = shellEscape.shellEscape(['--project-name', `'test name'`]); // 'test name'
const output = shellEscape(['--project-name', `'test name'`]); // 'test name'
assert.strictEqual(output, `--project-name \\''test name'\\'`); // --project-name \''test name'\'
});
test('non windows case: flag with double quote', () => {
sandbox.stub(utils, 'getOSType').returns(utils.OSType.macOSarm);
const output = shellEscape.shellEscape(['--project-name', `test "name"`]); // test "name"
const output = shellEscape(['--project-name', `test "name"`]); // test "name"
assert.strictEqual(output, `--project-name 'test "name"'`); // --project-name 'test "name"'
});
test('non windows case: flag with lots of quotes', () => {
sandbox.stub(utils, 'getOSType').returns(utils.OSType.macOSarm);
const output = shellEscape.shellEscape(['--project-name', `'test's "name"'`]); // 'test's "name"'
const output = shellEscape(['--project-name', `'test's "name"'`]); // 'test's "name"'
assert.strictEqual(output, `--project-name \\''test'\\''s "name"'\\'`); // --project-name \''test'\''s "name"'\'
});
test.only('non windows case: flag with backspace character', () => {
sandbox.stub(utils, 'getOSType').returns(utils.OSType.macOSarm);
const output = shellEscape(['--project-name', `\\bte\\bst | whoami`]);
assert.strictEqual(output, `--project-name '\\\\bte\\\\bst | whoami'`);
});
test.only('windows case: flag with space', () => {
sandbox.stub(utils, 'getOSType').returns(utils.OSType.windows);
const output = shellEscape.shellEscape(['--project-name', 'test | whoami']); // test | whoami
const output = shellEscape(['--project-name', 'test | whoami']); // test | whoami
assert.strictEqual(output, `--project-name "test | whoami"`); // --project-name "test | whoami"
});
test.only('windows case: flag with single quote around entire arg', () => {
sandbox.stub(utils, 'getOSType').returns(utils.OSType.windows);
const output = shellEscape.shellEscape(['--project-name', `'test name'`]); // 'test name'
const output = shellEscape(['--project-name', `'test name'`]); // 'test name'
assert.strictEqual(output, `--project-name "'test name'"`); // --project-name "'test name'"
});
test.only('windows case: flag with double quote', () => {
sandbox.stub(utils, 'getOSType').returns(utils.OSType.windows);
const output = shellEscape.shellEscape(['--project-name', `test "name"`]); // test "name"
const output = shellEscape(['--project-name', `test "name"`]); // test "name"
assert.strictEqual(output, `--project-name "test \\"name\\""`); // --project-name "test \"name\""
});
test.only('windows case: flag with lots of quotes', () => {
sandbox.stub(utils, 'getOSType').returns(utils.OSType.windows);
const output = shellEscape.shellEscape(['--project-name', `'test's "name"'`]); // 'test's "name"'
const output = shellEscape(['--project-name', `'test's "name"'`]); // 'test's "name"'
assert.strictEqual(output, `--project-name "'test's \\"name\\"'"`); // --project-name "'test's \"name\"'"
});
test.only('windows case: flag with backspace character', () => {
sandbox.stub(utils, 'getOSType').returns(utils.OSType.windows);
const output = shellEscape(['--project-name', `\\bte\\bst | whoami`]);
assert.strictEqual(output, `--project-name "\\\\bte\\\\bst | whoami"`);
});
});
});

0 comments on commit c51e93d

Please sign in to comment.