Skip to content

Commit 3829d20

Browse files
authored
fix: shell escaping (#511)
* fix: shell escaping on non windows platforms * fix: refactor shell escaping, only on windows and escape cmd/pwsh args
1 parent af76abd commit 3829d20

File tree

8 files changed

+121
-28
lines changed

8 files changed

+121
-28
lines changed

bin/pact-broker.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
#!/usr/bin/env node
22

33
import childProcess = require('child_process');
4-
import rubyStandalone from '../src/pact-standalone';
4+
import {
5+
standalone,
6+
standaloneUseShell,
7+
setStandaloneArgs,
8+
} from '../src/pact-standalone';
59

10+
const args = process.argv.slice(2);
11+
const opts = standaloneUseShell ? { shell: true } : {};
612
const { error, status } = childProcess.spawnSync(
7-
rubyStandalone.brokerFullPath,
8-
process.argv.slice(2),
13+
standalone().brokerFullPath,
14+
setStandaloneArgs(args, standaloneUseShell),
915
{
1016
stdio: 'inherit',
11-
shell: true,
17+
...opts,
1218
}
1319
);
1420
if (error) throw error;

bin/pact-message.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
11
#!/usr/bin/env node
22

33
import childProcess = require('child_process');
4-
import rubyStandalone from '../src/pact-standalone';
4+
import {
5+
standalone,
6+
standaloneUseShell,
7+
setStandaloneArgs,
8+
} from '../src/pact-standalone';
9+
10+
const args = process.argv.slice(2);
11+
const opts = standaloneUseShell ? { shell: true } : {};
512

613
const { error, status } = childProcess.spawnSync(
7-
rubyStandalone.messageFullPath,
8-
process.argv.slice(2),
14+
standalone().messageFullPath,
15+
setStandaloneArgs(args, standaloneUseShell),
916
{
1017
stdio: 'inherit',
11-
shell: true,
18+
...opts,
1219
}
1320
);
1421
if (error) throw error;

bin/pact-mock-service.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
11
#!/usr/bin/env node
22

33
import childProcess = require('child_process');
4-
import rubyStandalone from '../src/pact-standalone';
4+
import {
5+
standalone,
6+
standaloneUseShell,
7+
setStandaloneArgs,
8+
} from '../src/pact-standalone';
9+
10+
const args = process.argv.slice(2);
11+
const opts = standaloneUseShell ? { shell: true } : {};
512

613
const { error, status } = childProcess.spawnSync(
7-
rubyStandalone.mockServiceFullPath,
8-
process.argv.slice(2),
14+
standalone().mockServiceFullPath,
15+
setStandaloneArgs(args, standaloneUseShell),
916
{
1017
stdio: 'inherit',
11-
shell: true,
18+
...opts,
1219
}
1320
);
1421
if (error) throw error;

bin/pact-provider-verifier.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
11
#!/usr/bin/env node
22

33
import childProcess = require('child_process');
4-
import rubyStandalone from '../src/pact-standalone';
4+
import {
5+
standalone,
6+
standaloneUseShell,
7+
setStandaloneArgs,
8+
} from '../src/pact-standalone';
9+
10+
const args = process.argv.slice(2);
11+
const opts = standaloneUseShell ? { shell: true } : {};
512

613
const { error, status } = childProcess.spawnSync(
7-
rubyStandalone.verifierFullPath,
8-
process.argv.slice(2),
14+
standalone().verifierFullPath,
15+
setStandaloneArgs(args, standaloneUseShell),
916
{
1017
stdio: 'inherit',
11-
shell: true,
18+
...opts,
1219
}
1320
);
1421
if (error) throw error;

bin/pact-stub-service.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
11
#!/usr/bin/env node
22

33
import childProcess = require('child_process');
4-
import rubyStandalone from '../src/pact-standalone';
4+
import {
5+
standalone,
6+
standaloneUseShell,
7+
setStandaloneArgs,
8+
} from '../src/pact-standalone';
9+
10+
const args = process.argv.slice(2);
11+
const opts = standaloneUseShell ? { shell: true } : {};
512

613
const { error, status } = childProcess.spawnSync(
7-
rubyStandalone.stubFullPath,
8-
process.argv.slice(2),
14+
standalone().stubFullPath,
15+
setStandaloneArgs(args, standaloneUseShell),
916
{
1017
stdio: 'inherit',
11-
shell: true,
18+
...opts,
1219
}
1320
);
1421
if (error) throw error;

bin/pact.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
11
#!/usr/bin/env node
22

33
import childProcess = require('child_process');
4-
import rubyStandalone from '../src/pact-standalone';
4+
import {
5+
standalone,
6+
standaloneUseShell,
7+
setStandaloneArgs,
8+
} from '../src/pact-standalone';
9+
10+
const args = process.argv.slice(2);
11+
const opts = standaloneUseShell ? { shell: true } : {};
512

613
const { error, status } = childProcess.spawnSync(
7-
rubyStandalone.pactFullPath,
8-
process.argv.slice(2),
14+
standalone().pactFullPath,
15+
setStandaloneArgs(args, standaloneUseShell),
916
{
1017
stdio: 'inherit',
11-
shell: true,
18+
...opts,
1219
}
1320
);
1421
if (error) throw error;

bin/pactflow.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
11
#!/usr/bin/env node
22

33
import childProcess = require('child_process');
4-
import rubyStandalone from '../src/pact-standalone';
4+
import {
5+
standalone,
6+
standaloneUseShell,
7+
setStandaloneArgs,
8+
} from '../src/pact-standalone';
9+
10+
const args = process.argv.slice(2);
11+
const opts = standaloneUseShell ? { shell: true } : {};
512

613
const { error, status } = childProcess.spawnSync(
7-
rubyStandalone.pactflowFullPath,
8-
process.argv.slice(2),
14+
standalone().pactflowPath,
15+
setStandaloneArgs(args, standaloneUseShell),
916
{
1017
stdio: 'inherit',
11-
shell: true,
18+
...opts,
1219
}
1320
);
1421
if (error) throw error;

src/pact-standalone.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,49 @@ export const standalone = (
6767
};
6868
};
6969

70+
const isWindows = process.platform === 'win32';
71+
72+
function quoteCmdArg(arg: string) {
73+
return `"${arg.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`;
74+
}
75+
76+
function quotePwshArg(arg: string) {
77+
return `'${arg.replace(/'/g, "''")}'`;
78+
}
79+
80+
function quotePosixShArg(arg: string) {
81+
return `'${arg.replace(/'/g, "'\\''")}'`;
82+
}
83+
84+
function testWindowsExe(cmd: string, file: string) {
85+
return new RegExp(`^(?:.*\\\\)?${cmd}(?:\\.exe)?$`, 'i').test(file);
86+
}
87+
88+
function parseArgs(unparsed_args: string[]) {
89+
if (isWindows === true) {
90+
const file = process.env['comspec'] || 'cmd.exe';
91+
if (testWindowsExe('cmd', file) === true) {
92+
return unparsed_args.map((i) => quoteCmdArg(i));
93+
}
94+
if (testWindowsExe('(powershell|pwsh)', file) || file.endsWith('/pwsh')) {
95+
return unparsed_args.map((i) => quotePwshArg(i));
96+
}
97+
return unparsed_args;
98+
}
99+
return unparsed_args.map((i) => quotePosixShArg(i));
100+
}
101+
102+
export function setStandaloneArgs(
103+
unparsed_args: string[],
104+
shell: boolean
105+
): string[] {
106+
let parsedArgs = unparsed_args;
107+
if (shell === true) {
108+
parsedArgs = parseArgs(unparsed_args);
109+
}
110+
return parsedArgs;
111+
}
112+
113+
export const standaloneUseShell = isWindows;
114+
70115
export default standalone();

0 commit comments

Comments
 (0)