Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

shescape

Package Overview
Dependencies
Maintainers
1
Versions
51
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

shescape - npm Package Compare versions

Comparing version 1.7.2 to 2.0.0-rc1

8

CHANGELOG.md

@@ -10,6 +10,5 @@ # Changelog

- _No changes yet_
## [1.7.2] - 2023-07-07
- BREAKING CHANGE: Drop support for Node.js `^10.13.0`, `^12`, `14.0.0` through
`14.18.0`, and `16.0.0` through `16.13.0`. ([#963])
- Bump dependency `which` from v2 to v3. ([#963])
- Fix incorrect escaping of `"` when escaping for CMD. ([#1022])

@@ -278,2 +277,3 @@ - Fix incorrect escaping of `"` when escaping for PowerShell. ([#1023])

[#936]: https://github.com/ericcornelissen/shescape/pull/936
[#963]: https://github.com/ericcornelissen/shescape/pull/963
[#969]: https://github.com/ericcornelissen/shescape/pull/969

@@ -280,0 +280,0 @@ [#982]: https://github.com/ericcornelissen/shescape/pull/982

@@ -9,16 +9,20 @@ # Shescape API

## `quote(arg[, options])`
## `Shescape([options])`
The `quote` function escapes and quotes a single argument and optionally takes
an [options] object. `quote` always returns a string, the escaped and quoted
argument.
The class to create a `shescape` instance for quoting and escaping. optionally
takes an [options] object.
### `Shescape#quote(arg)`
The `quote` function escapes and quotes a single argument. Always returns a
string, the escaped and quoted argument.
Non-string arguments are converted to strings; an error is thrown if this is not
possible.
## `quoteAll(args[, options])`
### `Shescape#quoteAll(args)`
The `quoteAll` function escapes and quotes an array of arguments and optionally
takes an [options] object. `quoteAll` always returns an array of strings (same
length as the input array), the escaped and quoted arguments.
The `quoteAll` function escapes and quotes an array of arguments. Always returns
an array of strings (same length as the input array), the escaped and quoted
arguments.

@@ -28,6 +32,6 @@ Non-array inputs are converted to single-value arrays. Non-string arguments are

## `escape(arg[, options])`
### `Shescape#escape(arg)`
The `escape` function escapes a single argument and optionally takes an
[options] object. `escape` always returns a string, the escaped argument.
The `escape` function escapes a single argument. Always returns a string, the
escaped argument.

@@ -37,7 +41,6 @@ Non-string arguments are converted to strings; an error is thrown if this is not

## `escapeAll(args[, options])`
### `Shescape#escapeAll(args)`
The `escapeAll` function escapes an array of arguments and optionally takes an
[options] object. `escapeAll` always returns an array of strings (same length as
the input array), the escaped arguments.
The `escapeAll` function escapes an array of arguments. Always returns an array
of strings (same length as the input array), the escaped arguments.

@@ -56,3 +59,3 @@ Non-array inputs are converted to single-value arrays. Non-string arguments are

It is recommended to set this to `true` unless you use (and verified the command
It is recommended to leave this `true` unless you use (and verified the command
you invoke supports) the special `--` option.

@@ -63,3 +66,3 @@

| Used | Yes | Yes |
| Default | `false` | `false` |
| Default | `true` | `true` |
| Type | `boolean` | `boolean` |

@@ -72,3 +75,3 @@

It is recommended to set this to `true` if you're unsure whether or not shell
It is recommended to leave this `true` if you're unsure whether or not shell
interpolation is enabled.

@@ -79,3 +82,3 @@

| Used | Yes | No |
| Default | `false` | n/a |
| Default | `true` | n/a |
| Type | `boolean` | n/a |

@@ -82,0 +85,0 @@

@@ -19,12 +19,17 @@ # Shescape Recipes

When using `child_process.exec` without the `options` argument, use
`shescape.quote` to escape all user input in the command string.
`Shescape#quote` to escape all user input in the command string.
```javascript
import { exec } from "node:child_process";
import * as shescape from "shescape";
import { Shescape } from "shescape";
/* 1. Collect user input */
/* 1. Set up */
const shescape = new Shescape({
interpolation: false,
});
/* 2. Collect user input */
const userInput = "&& ls";
/* 2. Execute shell command */
/* 3. Execute shell command */
exec(`echo Hello ${shescape.quote(userInput)}`, (error, stdout) => {

@@ -43,10 +48,10 @@ if (error) {

When using `child_process.exec` with the `options` argument, use
`shescape.quote` to escape all user input in the command string. Provide the
`options` argument to `shescape.quote` as well.
`Shescape#quote` to escape all user input in the command string. Provide the
`options` argument to `Shescape#quote` as well.
```javascript
import { exec } from "node:child_process";
import * as shescape from "shescape";
import { Shescape } from "shescape";
/* 1. Set up configuration */
/* 1. Set up */
const execOptions = {

@@ -56,7 +61,10 @@ // Example configuration for `exec`

};
const shescapeOptions = {
const shescape = new Shescape({
interpolation: false,
// Set options for Shescape first, then add the options for `exec`. DO NOT set
// any keys from the child_process API here.
...execOptions,
};
});

@@ -68,3 +76,3 @@ /* 2. Collect user input */

exec(
`echo Hello ${shescape.quote(userInput, shescapeOptions)}`,
`echo Hello ${shescape.quote(userInput)}`,
execOptions,

@@ -85,12 +93,17 @@ (error, stdout) => {

When using `child_process.execSync` without the `options` argument, use
`shescape.quote` to escape all user input in the command string.
`Shescape#quote` to escape all user input in the command string.
```javascript
import { execSync } from "node:child_process";
import * as shescape from "shescape";
import { Shescape } from "shescape";
/* 1. Collect user input */
/* 1. Set up */
const shescape = new Shescape({
interpolation: false,
});
/* 2. Collect user input */
const userInput = "&& ls";
/* 2. Execute shell command */
/* 3. Execute shell command */
try {

@@ -108,10 +121,10 @@ const stdout = execSync(`echo Hello ${shescape.quote(userInput)}`);

When using `child_process.execSync` with the `options` argument, use
`shescape.quote` to escape all user input in the command string. Provide the
`options` argument to `shescape.quote` as well.
`Shescape#quote` to escape all user input in the command string. Provide the
`options` argument to `Shescape#quote` as well.
```javascript
import { execSync } from "node:child_process";
import * as shescape from "shescape";
import { Shescape } from "shescape";
/* 1. Set up configuration */
/* 1. Set up */
const execOptions = {

@@ -121,7 +134,10 @@ // Example configuration for `execSync`

};
const shescapeOptions = {
const shescape = new Shescape({
interpolation: false,
// Set options for Shescape first, then add the options for `execSync`. DO NOT
// set any keys from the child_process API here.
...execOptions,
};
});

@@ -134,3 +150,3 @@ /* 2. Collect user input */

const stdout = execSync(
`echo Hello ${shescape.quote(userInput, shescapeOptions)}`,
`echo Hello ${shescape.quote(userInput)}`,
execOptions,

@@ -145,9 +161,9 @@ );

#### With `shescape.escape`
#### With `Shescape#escape`
If you find yourself in a situation where the inputted argument to `exec` cannot
be quoted, you can use `shescape.escape` with `interpolation: true` instead.
be quoted, you can use `Shescape#escape` with `interpolation: true` instead.
> **Warning**: If possible, it is advised to rewrite your code so that you can
> use `shescape.quote` as shown above. Or use a different function from the
> use `Shescape#quote` as shown above. Or use a different function from the
> `child_process` API, as shown further down below.

@@ -157,8 +173,8 @@

import { exec } from "node:child_process";
import * as shescape from "shescape";
import { Shescape } from "shescape";
/* 1. Set up configuration */
const options = {
/* 1. Set up */
const shescape = new Shescape({
interpolation: true,
};
});

@@ -169,3 +185,3 @@ /* 2. Collect user input */

/* 3. Execute shell command */
exec(`echo Hello ${shescape.escape(userInput, options)}`, (error, stdout) => {
exec(`echo Hello ${shescape.escape(userInput)}`, (error, stdout) => {
if (error) {

@@ -185,3 +201,3 @@ console.error(`An error occurred: ${error}`);

- On Windows, cmd.exe does not support whitespace preservation. So, if argument
splitting is a concern, use `shescape.quote` instead.
splitting is a concern, use `Shescape#quote` instead.
- On Windows, PowerShell will strip whitespace at the beginning of arguments.

@@ -194,12 +210,17 @@

When using `child_process.execFile` without the `options` argument, use
`shescape.escapeAll` to escape all `args`.
`Shescape#escapeAll` to escape all `args`.
```javascript
import { execFile } from "node:child_process";
import * as shescape from "shescape";
import { Shescape } from "shescape";
/* 1. Collect user input */
/* 1. Set up */
const shescape = new Shescape({
interpolation: false,
});
/* 2. Collect user input */
const userInput = "\x00world";
/* 2. Execute shell command */
/* 3. Execute shell command */
execFile(

@@ -223,4 +244,4 @@ "echo",

the `options` argument to Shescape as well. If `options.shell` is set to a
truthy value, use `shescape.quoteAll` to escape all `args`. If `options.shell`
is set to a falsy value (or omitted), use `shescape.escapeAll` to escape all
truthy value, use `Shescape#quoteAll` to escape all `args`. If `options.shell`
is set to a falsy value (or omitted), use `Shescape#escapeAll` to escape all
`args`.

@@ -230,5 +251,5 @@

import { execFile } from "node:child_process";
import * as shescape from "shescape";
import { Shescape } from "shescape";
/* 1. Set up configuration */
/* 1. Set up */
const execFileOptions = {

@@ -238,7 +259,10 @@ // Example configuration for `execFile`

};
const shescapeOptions = {
const shescape = new Shescape({
interpolation: false,
// Set options for Shescape first, then add the options for `execFile`. DO NOT
// set any keys from the child_process API here.
...execFileOptions,
};
});

@@ -253,5 +277,5 @@ /* 2. Collect user input */

? // When the `shell` option is configured, arguments should be quoted
shescape.quoteAll(["Hello", userInput], shescapeOptions)
shescape.quoteAll(["Hello", userInput])
: // When the `shell` option is NOT configured, arguments should NOT be quoted
shescape.escapeAll(["Hello", userInput], shescapeOptions),
shescape.escapeAll(["Hello", userInput]),
execFileOptions,

@@ -272,12 +296,17 @@ (error, stdout) => {

When using `child_process.execFileSync` without the `options` argument, use
`shescape.escapeAll` to escape all `args`.
`Shescape#escapeAll` to escape all `args`.
```javascript
import { execFileSync } from "node:child_process";
import * as shescape from "shescape";
import { Shescape } from "shescape";
/* 1. Collect user input */
/* 1. Set up */
const shescape = new Shescape({
interpolation: false,
});
/* 2. Collect user input */
const userInput = "\x00world";
/* 2. Execute shell command */
/* 3. Execute shell command */
try {

@@ -299,4 +328,4 @@ const stdout = execFileSync(

the `options` argument to Shescape as well. If `options.shell` is set to a
truthy value, use `shescape.quoteAll` to escape all `args`. If `options.shell`
is set to a falsy value (or omitted), use `shescape.escapeAll` to escape all
truthy value, use `Shescape#quoteAll` to escape all `args`. If `options.shell`
is set to a falsy value (or omitted), use `Shescape#escapeAll` to escape all
`args`.

@@ -310,5 +339,5 @@

import { execFileSync } from "node:child_process";
import * as shescape from "shescape";
import { Shescape } from "shescape";
/* 1. Set up configuration */
/* 1. Set up */
const execFileOptions = {

@@ -318,7 +347,10 @@ // Example configuration for `execFileSync`

};
const shescapeOptions = {
const shescape = new Shescape({
interpolation: false,
// Set options for Shescape first, then add the options for `execFileSync`. DO
// NOT set any keys from the child_process API here.
...execFileOptions,
};
});

@@ -334,5 +366,5 @@ /* 2. Collect user input */

? // When the `shell` option is configured, arguments should be quoted
shescape.quoteAll(["Hello", userInput], shescapeOptions)
shescape.quoteAll(["Hello", userInput])
: // When the `shell` option is NOT configured, arguments should NOT be quoted
shescape.escapeAll(["Hello", userInput], shescapeOptions),
shescape.escapeAll(["Hello", userInput]),
execFileOptions,

@@ -352,3 +384,3 @@ );

When using `child_process.fork` without the `options` argument, use
`shescape.escapeAll` to escape all `args`.
`Shescape#escapeAll` to escape all `args`.

@@ -360,3 +392,3 @@ ```javascript

import { argv } from "node:process";
import * as shescape from "shescape";
import { Shescape } from "shescape";

@@ -367,6 +399,11 @@ if (argv[2] === "Hello") {

} else {
/* 1. Collect user input */
/* 1. Set up */
const shescape = new Shescape({
interpolation: false,
});
/* 2. Collect user input */
const userInput = "\x00world";
/* 2. Execute a Node.js module */
/* 3. Execute a Node.js module */
const echo = fork("echo.js", shescape.escapeAll(["Hello", userInput, "!"]));

@@ -382,3 +419,3 @@ echo.on("error", (error) => {

When using `child_process.fork` with the `options` argument, use
`shescape.escapeAll` to escape all `args`.
`Shescape#escapeAll` to escape all `args`.

@@ -390,3 +427,3 @@ ```javascript

import { argv } from "node:process";
import * as shescape from "shescape";
import { Shescape } from "shescape";

@@ -397,3 +434,3 @@ if (argv[2] === "Hello") {

} else {
/* 1. Set up configuration */
/* 1. Set up */
const forkOptions = {

@@ -403,7 +440,10 @@ // Example configuration for `fork`

};
const shescapeOptions = {
const shescape = new Shescape({
interpolation: false,
// Set options for Shescape first, then add the options for `fork`. DO NOT set
// any keys from the child_process API here.
...forkOptions,
};
});

@@ -416,3 +456,3 @@ /* 2. Collect user input */

"echo.js",
shescape.escapeAll(["Hello", userInput, "!"], shescapeOptions),
shescape.escapeAll(["Hello", userInput, "!"]),
forkOptions,

@@ -431,12 +471,17 @@ );

When using `child_process.spawn` without the `options` argument, use
`shescape.escapeAll` to escape all `args`.
`Shescape#escapeAll` to escape all `args`.
```javascript
import { spawn } from "node:child_process";
import * as shescape from "shescape";
import { Shescape } from "shescape";
/* 1. Collect user input */
/* 1. Set up */
const shescape = new Shescape({
interpolation: false,
});
/* 2. Collect user input */
const userInput = "\x00world";
/* 2. Execute shell command */
/* 3. Execute shell command */
const echo = spawn("echo", shescape.escapeAll(["Hello", userInput, "!"]));

@@ -456,4 +501,4 @@ echo.on("error", (error) => {

the `options` argument to Shescape as well. If `options.shell` is set to a
truthy value, use `shescape.quoteAll` to escape all `args`. If `options.shell`
is set to a falsy value (or omitted), use `shescape.escapeAll` to escape all
truthy value, use `Shescape#quoteAll` to escape all `args`. If `options.shell`
is set to a falsy value (or omitted), use `Shescape#escapeAll` to escape all
`args`.

@@ -463,5 +508,5 @@

import { spawn } from "node:child_process";
import * as shescape from "shescape";
import { Shescape } from "shescape";
/* 1. Set up configuration */
/* 1. Set up */
const spawnOptions = {

@@ -471,7 +516,10 @@ // Example configuration for `spawn`

};
const shescapeOptions = {
const shescape = new Shescape({
interpolation: false,
// Set options for Shescape first, then add the options for `spawn`. DO NOT
// set any keys from the child_process API here.
...spawnOptions,
};
});

@@ -486,5 +534,5 @@ /* 2. Collect user input */

? // When the `shell` option is configured, arguments should be quoted
shescape.quoteAll(["Hello", userInput], shescapeOptions)
shescape.quoteAll(["Hello", userInput])
: // When the `shell` option is NOT configured, arguments should NOT be quoted
shescape.escapeAll(["Hello", userInput], shescapeOptions),
shescape.escapeAll(["Hello", userInput]),
spawnOptions,

@@ -504,12 +552,17 @@ );

When using `child_process.spawnSync` without the `options` argument, use
`shescape.escapeAll` to escape all `args`.
`Shescape#escapeAll` to escape all `args`.
```javascript
import { spawnSync } from "node:child_process";
import * as shescape from "shescape";
import { Shescape } from "shescape";
/* 1. Collect user input */
/* 1. Set up */
const shescape = new Shescape({
interpolation: false,
});
/* 2. Collect user input */
const userInput = "\x00world";
/* 2. Execute shell command */
/* 3. Execute shell command */
const echo = spawnSync("echo", shescape.escapeAll(["Hello", userInput, "!"]));

@@ -528,4 +581,4 @@ if (echo.error) {

the `options` argument to Shescape as well. If `options.shell` is set to a
truthy value, use `shescape.quoteAll` to escape all `args`. If `options.shell`
is set to a falsy value (or omitted), use `shescape.escapeAll` to escape all
truthy value, use `Shescape#quoteAll` to escape all `args`. If `options.shell`
is set to a falsy value (or omitted), use `Shescape#escapeAll` to escape all
`args`.

@@ -535,5 +588,5 @@

import { spawnSync } from "node:child_process";
import * as shescape from "shescape";
import { Shescape } from "shescape";
/* 1. Set up configuration */
/* 1. Set up */
const spawnOptions = {

@@ -543,7 +596,10 @@ // Example configuration for `spawn`

};
const shescapeOptions = {
const shescape = new Shescape({
interpolation: false,
// Set options for Shescape first, then add the options for `spawnSync`. DO
// NOT set any keys from the child_process API here.
...spawnOptions,
};
});

@@ -558,5 +614,5 @@ /* 2. Collect user input */

? // When the `shell` option is configured, arguments should be quoted
shescape.quoteAll(["Hello", userInput], shescapeOptions)
shescape.quoteAll(["Hello", userInput])
: // When the `shell` option is NOT configured, arguments should NOT be quoted
shescape.escapeAll(["Hello", userInput], shescapeOptions),
shescape.escapeAll(["Hello", userInput]),
spawnOptions,

@@ -563,0 +619,0 @@ );

@@ -22,5 +22,6 @@ # Testing with Shescape

import assert from "node:assert";
import { shescape as stubscape } from "shescape/testing";
import { Shescape as Stubscape } from "shescape/testing";
import { functionUnderTest } from "./my-module.js";
const stubscape = new Stubscape();
assert.ok(functionUnderTest(stubscape));

@@ -27,0 +28,0 @@ ```

@@ -22,4 +22,5 @@ # Tips

import { exec } from "node:child_process";
import * as shescape from "shescape";
import { Shescape } from "shescape";
const shescape = new Shescape();
const userInput = "Yes";

@@ -100,3 +101,3 @@

import { exec } from "node:child_process";
import * as shescape from "shescape";
import { Shescape } from "shescape";

@@ -106,8 +107,8 @@ const userInput = "foobar.txt";

// Good
let options = { flagProtection: true };
exec(`git clean -n ${shescape.quote(userInput, options)}`);
let shescape = new Shescape({ flagProtection: true });
exec(`git clean -n ${shescape.quote(userInput)}`);
// Better
options = { flagProtection: false };
exec(`git clean -n -- ${shescape.quote(userInput, options)}`);
shescape = new Shescape({ flagProtection: false });
exec(`git clean -n -- ${shescape.quote(userInput)}`);
```

@@ -125,4 +126,5 @@

import { exec } from "node:child_process";
import * as shescape from "shescape";
import { Shescape } from "shescape";
const shescape = new Shescape();
const userInput = "&& ls";

@@ -129,0 +131,0 @@

@@ -7,12 +7,7 @@ /**

/**
* Possible values of a shell. `false` and `undefined` mean no shell. `true`
* means the default system shell, and any non-empty string configures a
* particular shell.
* Options for {@link Shescape}.
*
* @since 2.0.0
*/
type ShellOption = boolean | string | undefined;
/**
* Options for {@link escape} and {@link escapeAll}.
*/
interface EscapeOptions {
interface ShescapeOptions {
/**

@@ -22,4 +17,4 @@ * Whether or not to protect against flag and option (such as `--verbose`)

*
* @default false
* @since 1.7.0
* @default true
* @since 2.0.0
*/

@@ -31,4 +26,4 @@ readonly flagProtection?: boolean;

*
* @default false
* @since 1.4.0
* @default true
* @since 2.0.0
*/

@@ -38,39 +33,19 @@ readonly interpolation?: boolean;

/**
* The shell to escape for.
* The shell to escape for. `false` and `undefined` mean no shell. `true`
* means the default system shell, and any non-empty string configures a
* particular shell.
*
* @default undefined
* @since 1.3.0
* @since 2.0.0
*/
readonly shell?: ShellOption;
readonly shell?: boolean | string;
}
/**
* Options for {@link quote} and {@link quoteAll}.
*/
interface QuoteOptions {
/**
* Whether or not to protect against flag and option (such as `--verbose`)
* injection.
*
* @default false
* @since 1.7.0
*/
readonly flagProtection?: boolean;
/**
* The shell to escape for.
*
* @default undefined
* @since 1.3.0
*/
readonly shell?: ShellOption;
}
/**
* Take a single value, the argument, and escape any dangerous characters.
* A class to escape user-controlled inputs to shell commands to prevent shell
* injection.
*
* Non-string inputs will be converted to strings using a `toString()` method.
*
* @example
* import { spawn } from "node:child_process";
* const shescape = Shescape();
* spawn(

@@ -81,22 +56,5 @@ * "echo",

* );
* @param {string} arg The argument to escape.
* @param {object} [options] The escape options.
* @param {boolean} [options.flagProtection=false] Is flag protection enabled.
* @param {boolean} [options.interpolation=false] Is interpolation enabled.
* @param {boolean | string} [options.shell] The shell to escape for.
* @returns {string} The escaped argument.
* @throws {TypeError} The argument is not stringable.
* @since 0.1.0
*/
export function escape(arg: string, options?: EscapeOptions): string;
/**
* Take a array of values, the arguments, and escape any dangerous characters in
* every argument.
*
* Non-array inputs will be converted to one-value arrays and non-string values
* will be converted to strings using a `toString()` method.
*
* @example
* import { spawn } from "node:child_process";
* const shescape = Shescape();
* spawn(

@@ -107,70 +65,85 @@ * "echo",

* );
* @param {string[]} args The arguments to escape.
* @param {object} [options] The escape options.
* @param {boolean} [options.flagProtection=false] Is flag protection enabled.
* @param {boolean} [options.interpolation=false] Is interpolation enabled.
* @param {boolean | string} [options.shell] The shell to escape for.
* @returns {string[]} The escaped arguments.
* @throws {TypeError} One of the arguments is not stringable.
* @since 1.1.0
*/
export function escapeAll(args: string[], options?: EscapeOptions): string[];
/**
* Take a single value, the argument, put shell-specific quotes around it and
* escape any dangerous characters.
*
* Non-string inputs will be converted to strings using a `toString()` method.
*
* @example
* import { spawn } from "node:child_process";
* const spawnOptions = { shell: true }; // `options.shell` SHOULD be truthy
* const shescapeOptions = { ...spawnOptions };
* const shescape = Shescape({ ...spawnOptions });
* spawn(
* "echo",
* ["Hello", shescape.quote(userInput, shescapeOptions)],
* ["Hello", shescape.quote(userInput)],
* spawnOptions
* );
* @example
* import { exec } from "node:child_process";
* const execOptions = null || { };
* const shescapeOptions = { ...execOptions };
* exec(
* `echo Hello ${shescape.quote(userInput, shescapeOptions)}`,
* execOptions
* );
* @param {string} arg The argument to quote and escape.
* @param {object} [options] The escape and quote options.
* @param {boolean} [options.flagProtection=false] Is flag protection enabled.
* @param {boolean | string} [options.shell] The shell to escape for.
* @returns {string} The quoted and escaped argument.
* @throws {TypeError} The argument is not stringable.
* @since 0.3.0
*/
export function quote(arg: string, options?: QuoteOptions): string;
/**
* Take an array of values, the arguments, put shell-specific quotes around
* every argument and escape any dangerous characters in every argument.
*
* Non-array inputs will be converted to one-value arrays and non-string values
* will be converted to strings using a `toString()` method.
*
* @example
* import { spawn } from "node:child_process";
* const spawnOptions = { shell: true }; // `options.shell` SHOULD be truthy
* const shescapeOptions = { ...spawnOptions };
* const shescape = Shescape({ ...spawnOptions });
* spawn(
* "echo",
* shescape.quoteAll(["Hello", userInput], shescapeOptions),
* shescape.quoteAll(["Hello", userInput]),
* spawnOptions
* );
* @param {string[]} args The arguments to quote and escape.
* @param {object} [options] The escape and quote options.
* @param {boolean} [options.flagProtection=false] Is flag protection enabled.
* @param {boolean | string} [options.shell] The shell to escape for.
* @returns {string[]} The quoted and escaped arguments.
* @throws {TypeError} One of the arguments is not stringable.
* @since 0.4.0
*/
export function quoteAll(args: string[], options?: QuoteOptions): string[];
interface Shescape {
/**
* Create a new {@link Shescape} instance.
*
* @param {object} [options] The escape options.
* @param {boolean} [options.flagProtection=true] Is flag protection enabled.
* @param {boolean} [options.interpolation=true] Is interpolation enabled.
* @param {boolean | string} [options.shell] The shell to escape for.
* @since 2.0.0
*/
new (options: ShescapeOptions): Shescape;
/**
* Take a single value, the argument, and escape any dangerous characters.
*
* Non-string inputs will be converted to strings using a `toString()` method.
*
* @param {string} arg The argument to escape.
* @returns {string} The escaped argument.
* @throws {TypeError} The argument is not stringable.
* @since 2.0.0
*/
escape(arg: string): string;
/**
* Take a array of values, the arguments, and escape any dangerous characters
* in every argument.
*
* Non-array inputs will be converted to one-value arrays and non-string
* values will be converted to strings using a `toString()` method.
*
* @param {string[]} args The arguments to escape.
* @returns {string[]} The escaped arguments.
* @throws {TypeError} One of the arguments is not stringable.
* @since 2.0.0
*/
escapeAll(args: string[]): string[];
/**
* Take a single value, the argument, put shell-specific quotes around it and
* escape any dangerous characters.
*
* Non-string inputs will be converted to strings using a `toString()` method.
*
* @param {string} arg The argument to quote and escape.
* @returns {string} The quoted and escaped argument.
* @throws {TypeError} The argument is not stringable.
* @since 2.0.0
*/
quote(arg: string): string;
/**
* Take an array of values, the arguments, put shell-specific quotes around
* every argument and escape any dangerous characters in every argument.
*
* Non-array inputs will be converted to one-value arrays and non-string
* values will be converted to strings using a `toString()` method.
*
* @param {string[]} args The arguments to quote and escape.
* @returns {string[]} The quoted and escaped arguments.
* @throws {TypeError} One of the arguments is not stringable.
* @since 2.0.0
*/
quoteAll(args: string[]): string[];
}

@@ -7,8 +7,8 @@ /**

* @module shescape
* @version 1.7.2
* @version 1.7.1
* @license MPL-2.0
*/
import os from "os";
import process from "process";
import os from "node:os";
import process from "node:process";

@@ -20,22 +20,8 @@ import { parseOptions } from "./src/options.js";

/**
* Get the helper functions for the current platform.
* A class to escape user-controlled inputs to shell commands to prevent shell
* injection.
*
* @returns {object} The helper functions for the current platform.
*/
function getPlatformHelpers() {
const platform = os.platform();
const helpers = getHelpersByPlatform({ env: process.env, platform });
return helpers;
}
/**
* Take a single value, the argument, and escape any dangerous characters.
*
* Non-string inputs will be converted to strings using a `toString()` method.
*
* NOTE: when the `interpolation` option is set to `true`, whitespace is escaped
* to prevent argument splitting except for cmd.exe (which does not support it).
*
* @example
* import { spawn } from "node:child_process";
* const shescape = Shescape();
* spawn(

@@ -46,37 +32,5 @@ * "echo",

* );
* @param {string} arg The argument to escape.
* @param {object} [options] The escape options.
* @param {boolean} [options.flagProtection=false] Is flag protection enabled.
* @param {boolean} [options.interpolation=false] Is interpolation enabled.
* @param {boolean | string} [options.shell] The shell to escape for.
* @returns {string} The escaped argument.
* @throws {TypeError} The argument is not stringable.
* @since 0.1.0
*/
export function escape(arg, options = {}) {
const helpers = getPlatformHelpers();
const { flagProtection, interpolation, shellName } = parseOptions(
{ options, process },
helpers,
);
const argAsString = checkedToString(arg);
const escape = helpers.getEscapeFunction(shellName, { interpolation });
const escapedArg = escape(argAsString);
if (flagProtection) {
const flagProtect = helpers.getFlagProtectionFunction(shellName);
return flagProtect(escapedArg);
} else {
return escapedArg;
}
}
/**
* Take a array of values, the arguments, and escape any dangerous characters in
* every argument.
*
* Non-array inputs will be converted to one-value arrays and non-string values
* will be converted to strings using a `toString()` method.
*
* @example
* import { spawn } from "node:child_process";
* const shescape = Shescape();
* spawn(

@@ -87,91 +41,125 @@ * "echo",

* );
* @param {string[]} args The arguments to escape.
* @param {object} [options] The escape options.
* @param {boolean} [options.flagProtection=false] Is flag protection enabled.
* @param {boolean} [options.interpolation=false] Is interpolation enabled.
* @param {boolean | string} [options.shell] The shell to escape for.
* @returns {string[]} The escaped arguments.
* @throws {TypeError} One of the arguments is not stringable.
* @since 1.1.0
*/
export function escapeAll(args, options = {}) {
args = toArrayIfNecessary(args);
return args.map((arg) => escape(arg, options));
}
/**
* Take a single value, the argument, put shell-specific quotes around it and
* escape any dangerous characters.
*
* Non-string inputs will be converted to strings using a `toString()` method.
*
* @example
* import { spawn } from "node:child_process";
* const spawnOptions = { shell: true }; // `options.shell` SHOULD be truthy
* const shescapeOptions = { ...spawnOptions };
* const shescape = Shescape({ ...spawnOptions });
* spawn(
* "echo",
* ["Hello", shescape.quote(userInput, shescapeOptions)],
* ["Hello", shescape.quote(userInput)],
* spawnOptions
* );
* @example
* import { exec } from "node:child_process";
* const execOptions = null || { };
* const shescapeOptions = { ...execOptions };
* exec(
* `echo Hello ${shescape.quote(userInput, shescapeOptions)}`,
* execOptions
* );
* @param {string} arg The argument to quote and escape.
* @param {object} [options] The escape and quote options.
* @param {boolean} [options.flagProtection=false] Is flag protection enabled.
* @param {boolean | string} [options.shell] The shell to escape for.
* @returns {string} The quoted and escaped argument.
* @throws {TypeError} The argument is not stringable.
* @since 0.3.0
*/
export function quote(arg, options = {}) {
const helpers = getPlatformHelpers();
const { flagProtection, shellName } = parseOptions(
{ options, process },
helpers,
);
const argAsString = checkedToString(arg);
const [escape, quote] = helpers.getQuoteFunction(shellName);
const escapedArg = escape(argAsString);
if (flagProtection) {
const flagProtect = helpers.getFlagProtectionFunction(shellName);
return quote(flagProtect(escapedArg));
} else {
return quote(escapedArg);
}
}
/**
* Take an array of values, the arguments, put shell-specific quotes around
* every argument and escape any dangerous characters in every argument.
*
* Non-array inputs will be converted to one-value arrays and non-string values
* will be converted to strings using a `toString()` method.
*
* @example
* import { spawn } from "node:child_process";
* const spawnOptions = { shell: true }; // `options.shell` SHOULD be truthy
* const shescapeOptions = { ...spawnOptions };
* const shescape = Shescape({ ...spawnOptions });
* spawn(
* "echo",
* shescape.quoteAll(["Hello", userInput], shescapeOptions),
* shescape.quoteAll(["Hello", userInput]),
* spawnOptions
* );
* @param {string[]} args The arguments to quote and escape.
* @param {object} [options] The escape and quote options.
* @param {boolean} [options.flagProtection=false] Is flag protection enabled.
* @param {boolean | string} [options.shell] The shell to escape for.
* @returns {string[]} The quoted and escaped arguments.
* @throws {TypeError} One of the arguments is not stringable.
* @since 0.4.0
*/
export function quoteAll(args, options = {}) {
args = toArrayIfNecessary(args);
return args.map((arg) => quote(arg, options));
export class Shescape {
/**
* Create a new {@link Shescape} instance.
*
* @param {object} [options] The escape options.
* @param {boolean} [options.flagProtection=true] Is flag protection enabled.
* @param {boolean} [options.interpolation=true] Is interpolation enabled.
* @param {boolean | string} [options.shell] The shell to escape for.
* @since 2.0.0
*/
constructor(options = {}) {
const platform = os.platform();
const helpers = getHelpersByPlatform({ env: process.env, platform });
const { flagProtection, interpolation, shellName } = parseOptions(
{ options, process },
helpers,
);
{
const escape = helpers.getEscapeFunction(shellName, { interpolation });
if (flagProtection) {
const flagProtect = helpers.getFlagProtectionFunction(shellName);
this._escape = (arg) => flagProtect(escape(arg));
} else {
this._escape = escape;
}
}
{
const [escape, quote] = helpers.getQuoteFunction(shellName);
if (flagProtection) {
const flagProtect = helpers.getFlagProtectionFunction(shellName);
this._quote = (arg) => quote(flagProtect(escape(arg)));
} else {
this._quote = (arg) => quote(escape(arg));
}
}
}
/**
* Take a single value, the argument, and escape any dangerous characters.
*
* Non-string inputs will be converted to strings using a `toString()` method.
*
* @param {string} arg The argument to escape.
* @returns {string} The escaped argument.
* @throws {TypeError} The argument is not stringable.
* @since 2.0.0
*/
escape(arg) {
const argAsString = checkedToString(arg);
return this._escape(argAsString);
}
/**
* Take a array of values, the arguments, and escape any dangerous characters
* in every argument.
*
* Non-array inputs will be converted to one-value arrays and non-string
* values will be converted to strings using a `toString()` method.
*
* @param {string[]} args The arguments to escape.
* @returns {string[]} The escaped arguments.
* @throws {TypeError} One of the arguments is not stringable.
* @since 2.0.0
*/
escapeAll(args) {
args = toArrayIfNecessary(args);
return args.map((arg) => this.escape(arg));
}
/**
* Take a single value, the argument, put shell-specific quotes around it and
* escape any dangerous characters.
*
* Non-string inputs will be converted to strings using a `toString()` method.
*
* @param {string} arg The argument to quote and escape.
* @returns {string} The quoted and escaped argument.
* @throws {TypeError} The argument is not stringable.
* @since 2.0.0
*/
quote(arg) {
const argAsString = checkedToString(arg);
return this._quote(argAsString);
}
/**
* Take an array of values, the arguments, put shell-specific quotes around
* every argument and escape any dangerous characters in every argument.
*
* Non-array inputs will be converted to one-value arrays and non-string
* values will be converted to strings using a `toString()` method.
*
* @param {string[]} args The arguments to quote and escape.
* @returns {string[]} The quoted and escaped arguments.
* @throws {TypeError} One of the arguments is not stringable.
* @since 2.0.0
*/
quoteAll(args) {
args = toArrayIfNecessary(args);
return args.map((arg) => this.quote(arg));
}
}
{
"name": "shescape",
"version": "1.7.2",
"version": "2.0.0-rc1",
"description": "simple shell escape library",

@@ -8,3 +8,2 @@ "homepage": "https://github.com/ericcornelissen/shescape#readme",

"type": "module",
"main": "./index.cjs",
"exports": {

@@ -24,3 +23,3 @@ ".": {

"engines": {
"node": "^10.13.0 || ^12 || ^14 || ^16 || ^18 || ^19 || ^20"
"node": "^14.18.0 || ^16.13.0 || ^18 || ^19 || ^20"
},

@@ -45,3 +44,3 @@ "repository": {

"dependencies": {
"which": "^2.0.0"
"which": "^3.0.0"
},

@@ -60,3 +59,3 @@ "devDependencies": {

"dotenv": "16.3.1",
"eslint": "8.44.0",
"eslint": "8.43.0",
"eslint-plugin-ava": "14.0.0",

@@ -119,3 +118,3 @@ "eslint-plugin-jsdoc": "46.4.3",

"test:compat": "mocha test/compat/**/*.test.cjs",
"test:compat-all": "nve 10.13.0,12.0.0,14.0.0,16.0.0,18.0.0,19.0.0,20.0.0 mocha test/compat/**/*.test.cjs",
"test:compat-all": "nve 14.18.0,16.13.0,18.0.0,19.0.0,20.0.0 mocha test/compat/**/*.test.cjs",
"test:e2e": "ava test/e2e/**/*.test.js --timeout 1m",

@@ -122,0 +121,0 @@ "test:integration": "ava test/integration/**/*.test.js --timeout 1m",

@@ -48,7 +48,13 @@ # Shescape

```javascript
import * as shescape from "shescape";
import { Shescape } from "shescape";
```
3. Use `shescape`.
3. Initialize `Shescape`.
```javascript
const shescape = new Shescape(/* options */);
```
4. Use `shescape`.
### Recipes

@@ -55,0 +61,0 @@

@@ -6,4 +6,4 @@ /**

import * as fs from "fs";
import * as path from "path";
import * as fs from "node:fs";
import * as path from "node:path";

@@ -10,0 +10,0 @@ import which from "which";

@@ -6,3 +6,3 @@ /**

import { TextEncoder } from "util";
import { TextEncoder } from "node:util";

@@ -9,0 +9,0 @@ /**

@@ -6,4 +6,4 @@ /**

import * as fs from "fs";
import * as path from "path";
import * as fs from "node:fs";
import * as path from "node:path";

@@ -10,0 +10,0 @@ import which from "which";

@@ -29,3 +29,3 @@ /**

/**
* A test stub of shescape that has the same input-output profile as the real
* A test stub of Shescape that has the same input-output profile as the real
* shescape implementation.

@@ -38,10 +38,23 @@ *

*/
export const shescape = {
escape: (arg, _options) => checkedToString(arg),
escapeAll: (args, _options) => {
export class Shescape {
constructor(_options) {
// Nothing to do.
}
escape(arg) {
return checkedToString(arg);
}
escapeAll(args) {
args = toArrayIfNecessary(args);
return args.map(shescape.escape);
},
quote: (arg, _options) => shescape.escape(arg),
quoteAll: (args, _options) => shescape.escapeAll(args),
};
return args.map((arg) => this.escape(arg));
}
quote(arg) {
return this.escape(arg);
}
quoteAll(args) {
return this.escapeAll(args);
}
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc