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.5.2 to 1.5.3

src/platforms.js

5

CHANGELOG.md

@@ -12,2 +12,6 @@ # Changelog

## [1.5.3] - 2022-03-06
- Fix documented type of `interpolation` option. ([#190])
## [1.5.2] - 2022-02-23

@@ -121,3 +125,4 @@

[#178]: https://github.com/ericcornelissen/shescape/pull/178
[#190]: https://github.com/ericcornelissen/shescape/pull/190
[keep a changelog]: https://keepachangelog.com/en/1.0.0/
[semantic versioning]: https://semver.org/spec/v2.0.0.html

68

index.js

@@ -11,3 +11,3 @@ /**

* @module shescape
* @version 1.5.2
* @version 1.5.3
* @license MPL-2.0

@@ -20,5 +20,17 @@ * @author Eric Cornelissen <ericornelissen@gmail.com>

import * as main from "./src/main.js";
import { escapeShellArg, quoteShellArg } from "./src/main.js";
import { getHelpersByPlatform } from "./src/platforms.js";
/**
* Get the helper functions for the current platform.
*
* @returns {Object} The helper functions for the current platform.
*/
function getPlatformHelpers() {
const platform = os.platform();
const helpers = getHelpersByPlatform(platform);
return helpers;
}
/**
* Take a single value, the argument, and escape any dangerous characters.

@@ -30,3 +42,3 @@ *

* @param {Object} [options] The escape options.
* @param {string} [options.interpolation=false] Is interpolation enabled.
* @param {boolean} [options.interpolation=false] Is interpolation enabled.
* @param {string} [options.shell] The shell to escape the argument for.

@@ -38,12 +50,4 @@ * @returns {string} The escaped argument.

export function escape(arg, options = {}) {
const { interpolation, shell } = options;
const env = process.env;
const platform = os.platform();
return main.escapeShellArgByPlatform(
arg,
platform,
env,
shell,
interpolation
);
const helpers = getPlatformHelpers();
return escapeShellArg({ arg, options, process }, helpers);
}

@@ -60,3 +64,3 @@

* @param {Object} [options] The escape options.
* @param {string} [options.interpolation=false] Is interpolation enabled.
* @param {boolean} [options.interpolation=false] Is interpolation enabled.
* @param {string} [options.shell] The shell to escape the arguments for.

@@ -70,18 +74,4 @@ * @returns {string[]} The escaped arguments.

const { interpolation, shell } = options;
const env = process.env;
const platform = os.platform();
const result = [];
for (const arg of args) {
const safeArg = main.escapeShellArgByPlatform(
arg,
platform,
env,
shell,
interpolation
);
result.push(safeArg);
}
return result;
const helpers = getPlatformHelpers();
return args.map((arg) => escapeShellArg({ arg, options, process }, helpers));
}

@@ -103,6 +93,4 @@

export function quote(arg, options = {}) {
const shell = options.shell;
const env = process.env;
const platform = os.platform();
return main.quoteShellArgByPlatform(arg, platform, env, shell);
const helpers = getPlatformHelpers();
return quoteShellArg({ arg, options, process }, helpers);
}

@@ -127,12 +115,4 @@

const shell = options.shell;
const env = process.env;
const platform = os.platform();
const result = [];
for (const arg of args) {
const safeArg = main.quoteShellArgByPlatform(arg, platform, env, shell);
result.push(safeArg);
}
return result;
const helpers = getPlatformHelpers();
return args.map((arg) => quoteShellArg({ arg, options, process }, helpers));
}
{
"name": "shescape",
"version": "1.5.2",
"version": "1.5.3",
"description": "simple shell escape library",

@@ -63,3 +63,3 @@ "homepage": "https://ericcornelissen.github.io/shescape/",

"prettier": "2.5.1",
"rollup": "2.68.0",
"rollup": "2.69.0",
"sinon": "13.0.1"

@@ -66,0 +66,0 @@ },

@@ -8,11 +8,21 @@ /**

import * as fs from "fs";
import which from "which";
import { typeError, win32 } from "./constants.js";
import { resolveExecutable } from "./executables.js";
import * as unix from "./unix.js";
import * as win from "./win.js";
/**
* @constant {string} typeError The error message for incorrect parameter types.
*/
const typeError =
"Shescape requires strings or values that can be converted into a string using .toString()";
/**
* @constant {string} typeofFunction The `typeof` value of functions.
*/
const typeofFunction = "function";
/**
* @constant {string} typeofString The `typeof` value of strings.
*/
const typeofString = "string";
/**
* Check if a value can be converted into a string.

@@ -28,3 +38,3 @@ *

if (typeof value.toString !== "function") {
if (typeof value.toString !== typeofFunction) {
return false;

@@ -34,57 +44,61 @@ }

const str = value.toString();
return typeof str === "string";
return typeof str === typeofString;
}
/**
* Get the shell to escape arguments for.
* Merge any number of objects into a single object.
*
* @param {string} platform The platform to get the shell for.
* @param {Object} env The environment variables.
* @param {string} [shell] The provided shell, if any.
* @returns The shell to escape arguments for.
* Note: the values of objects appearing later in the list of arguments take
* precedence when merging.
*
* @param {...Object} objects The objects to merge.
* @returns {Object} The merged object.
*/
function getShell(platform, env, shell) {
if (shell === undefined) {
switch (platform) {
case win32:
shell = win.getDefaultShell(env);
break;
default:
shell = unix.getDefaultShell();
break;
}
}
function mergeObjects(...objects) {
const baseObject = Object.create(null);
const mergedObjects = Object.assign(baseObject, ...objects);
return mergedObjects;
}
return resolveExecutable(
{
executable: shell,
},
{
exists: fs.existsSync,
readlink: fs.readlinkSync,
which: which.sync,
}
);
/**
* Parse inputs and escape the provided argument.
*
* @param {Object} args The arguments for this function.
* @param {string} args.arg The argument to escape.
* @param {Object} args.options The options for escaping `arg`.
* @param {string} [args.options.shell] The shell to escape `arg` for.
* @param {boolean} [args.options.interpolation] Is interpolation enabled.
* @param {Object} args.process The `process` values.
* @param {Object} args.process.env The environment variables.
* @param {Object} deps The dependencies for this function.
* @param {Function} deps.getDefaultShell Get the default shell.
* @param {Function} deps.getShellName Get the name of a shell.
* @returns {Object} The parsed arguments `{ arg, interpolation, shellName }`.
*/
function parseArgs(
{ arg, options, process },
{ getDefaultShell, getShellName }
) {
const env = process.env;
const interpolation = options.interpolation;
const shell =
options.shell === undefined ? getDefaultShell({ env }) : options.shell;
const shellName = getShellName({ shell }, { resolveExecutable });
return { arg, interpolation, shellName };
}
/**
* Take a value and escape any dangerous characters.
* Escape an argument for the given shell.
*
* Non-string inputs will be converted to strings using a `toString()` method.
*
* @param {string} arg The argument to escape.
* @param {string} platform The platform to escape the argument for.
* @param {Object} env The environment variables.
* @param {string} [shell] The shell to escape the argument for, if any.
* @param {boolean} [interpolation=false] Is interpolation enabled.
* @param {Object} args The arguments for this function.
* @param {string} args.arg The argument to escape.
* @param {boolean} args.interpolation Is interpolation enabled.
* @param {string} args.shellName The name of the shell to escape `arg` for.
* @param {Object} deps The dependencies for this function.
* @param {Function} deps.getEscapeFunction Get the escape function for a shell.
* @returns {string} The escaped argument.
* @throws {TypeError} The argument is not stringable.
* @throws {TypeError} The argument to escape is not stringable.
*/
export function escapeShellArgByPlatform(
arg,
platform,
env,
shell,
interpolation = false
) {
function escape({ arg, interpolation, shellName }, { getEscapeFunction }) {
if (!isStringable(arg)) {

@@ -94,33 +108,71 @@ throw new TypeError(typeError);

shell = getShell(platform, env, shell);
const argAsString = arg.toString();
switch (platform) {
case win32:
return win.escapeShellArg(argAsString, shell, interpolation);
default:
return unix.escapeShellArg(argAsString, shell, interpolation);
}
const escape = getEscapeFunction(shellName);
const escapedArg = escape(argAsString, interpolation);
return escapedArg;
}
/**
* Take a value, put OS-specific quotes around it, and escape any dangerous
* characters.
* Quote and escape an argument for the given shell.
*
* Non-string inputs will be converted to strings using a `toString()` method.
* @param {Object} args The arguments for this function.
* @param {string} args.arg The argument to escape.
* @param {string} args.shellName The name of the shell to escape `arg` for.
* @param {Object} deps The dependencies for this function.
* @param {Function} deps.getEscapeFunction Get the escape function for a shell.
* @param {Function} deps.getQuoteFunction Get the quote function for a shell.
* @returns {string} The quoted and escaped argument.
* @throws {TypeError} The argument to escape is not stringable.
*/
function quote({ arg, shellName }, { getEscapeFunction, getQuoteFunction }) {
const escapedArg = escape(
{ arg, interpolation: false, shellName },
{ getEscapeFunction }
);
const quote = getQuoteFunction(shellName);
const escapedAndQuotedArg = quote(escapedArg);
return escapedAndQuotedArg;
}
/**
* Escape an argument for the given shell.
*
* @param {string} arg The argument to escape and quote.
* @param {string} platform The platform to escape and quote the argument for.
* @param {Object} env The environment variables.
* @param {string} [shell] The shell to escape the argument for, if any.
* @param {Object} args The arguments for this function.
* @param {string} args.arg The argument to escape.
* @param {Object} args.options The options for escaping `arg`.
* @param {string} [args.options.shell] The shell to escape `arg` for.
* @param {boolean} [args.options.interpolation=false] Is interpolation enabled.
* @param {Object} args.process The `process` values.
* @param {Object} args.process.env The environment variables.
* @param {Object} deps The dependencies for this function.
* @param {Function} deps.getDefaultShell Get the default shell.
* @param {Function} deps.getEscapeFunction Get an escape function for a shell.
* @param {Function} deps.getShellName Get the name of a shell.
* @returns {string} The escaped argument.
* @throws {TypeError} The argument is not stringable.
*/
export function quoteShellArgByPlatform(arg, platform, env, shell) {
const safeArg = escapeShellArgByPlatform(arg, platform, env, shell, false);
switch (platform) {
case win32:
return `"${safeArg}"`;
default:
return `'${safeArg}'`;
}
export function escapeShellArg({ arg, options, process }, deps) {
options = mergeObjects({ interpolation: false }, options);
const escapeArgs = parseArgs({ arg, options, process }, deps);
return escape(escapeArgs, deps);
}
/**
* Quote and escape an argument for the given shell.
*
* @param {Object} args The arguments for this function.
* @param {string} args.arg The argument to escape.
* @param {Object} args.options The options for escaping `arg`.
* @param {string} [args.options.shell] The shell to escape `arg` for.
* @param {Object} args.process The `process` values.
* @param {Object} args.process.env The environment variables.
* @param {Object} deps The dependencies for this function.
* @param {Function} deps.getDefaultShell Get the default shell.
* @param {Function} deps.getEscapeFunction Get an escape function for a shell.
* @param {Function} deps.getQuoteFunction Get a quote function for a shell.
* @param {Function} deps.getShellName Get the name of a shell.
* @returns {string} The quoted and escaped argument.
*/
export function quoteShellArg(args, deps) {
const quoteArgs = parseArgs(args, deps);
return quote(quoteArgs, deps);
}

@@ -7,39 +7,43 @@ /**

import { shellRequiredError } from "./constants.js";
import * as fs from "fs";
import * as path from "path";
import which from "which";
/**
* Escape a shell argument when string interpolation is *disabled* (e.g. when
* the argument is surrounded by single quotes in bash-family shells).
*
* @param {string} arg The argument to escape.
* @returns {string} The escaped argument.
* @constant {string} binBash The name of the Bourne-again shell (Bash) binary.
*/
function escapeShellArgNoInterpolation(arg) {
return arg.replace(/\u{0}/gu, "").replace(/'/g, `'\\''`);
}
const binBash = "bash";
/**
* Escape a shell argument when string interpolation is *enabled* (e.g. when
* the argument is surrounded by double quotes in bash-family shells).
* @constant {string} binDash The name of the Debian Almquist shell (Dash) binary.
*/
const binDash = "dash";
/**
* @constant {string} binZsh The name of the Z shell (Zsh) binary.
*/
const binZsh = "zsh";
/**
* Escape a shell argument for use in Bash (like shells).
*
* @param {string} arg The argument to escape.
* @param {string} shell The shell to escape the argument for.
* @param {boolean} interpolation Is interpolation enabled.
* @returns {string} The escaped argument.
*/
function escapeShellArgWithInterpolation(arg, shell) {
let result = arg
.replace(/\u{0}/gu, "")
.replace(/\\/g, "\\\\")
.replace(/^(~|#)/g, "\\$1")
.replace(/(\*|\?)/gu, "\\$1")
.replace(/(\$|\;|\&|\|)/g, "\\$1")
.replace(/(\(|\)|\<|\>)/g, "\\$1")
.replace(/("|'|`)/g, "\\$1");
function escapeArgBash(arg, interpolation) {
let result = arg.replace(/\u{0}/gu, "");
if (shell.endsWith("zsh")) {
result = result.replace(/^=/gu, "\\=").replace(/(\[|\]|\{|\})/g, "\\$1");
} else {
if (interpolation) {
result = result
.replace(/\\/g, "\\\\")
.replace(/^(~|#)/g, "\\$1")
.replace(/(\*|\?)/gu, "\\$1")
.replace(/(\$|\;|\&|\|)/g, "\\$1")
.replace(/(\(|\)|\<|\>)/g, "\\$1")
.replace(/("|'|`)/g, "\\$1")
.replace(/\{(?=(.*?(?:\,|\.).*?)\})/g, "\\{")
.replace(/(?<=\=(?:.*?:)?)(~)(?=\:|\=|\-|\+|\/|0|\s|$)/g, "\\$1");
} else {
result = result.replace(/'/g, `'\\''`);
}

@@ -51,22 +55,72 @@

/**
* Escape a shell argument.
* Escape a shell argument for use in Zsh.
*
* @param {string} arg The argument to escape.
* @param {string} shell The shell to escape the argument for.
* @param {boolean} interpolation Is interpolation enabled.
* @returns {string} The escaped argument.
*/
export function escapeShellArg(arg, shell, interpolation) {
if (shell === undefined) throw new TypeError(shellRequiredError);
function escapeArgZsh(arg, interpolation) {
let result = arg.replace(/\u{0}/gu, "");
if (interpolation) {
return escapeShellArgWithInterpolation(arg, shell);
result = result
.replace(/\\/g, "\\\\")
.replace(/^(~|#)/g, "\\$1")
.replace(/(\*|\?)/gu, "\\$1")
.replace(/(\$|\;|\&|\|)/g, "\\$1")
.replace(/(\(|\)|\<|\>)/g, "\\$1")
.replace(/("|'|`)/g, "\\$1")
.replace(/^=/gu, "\\=")
.replace(/(\[|\]|\{|\})/g, "\\$1");
} else {
return escapeShellArgNoInterpolation(arg);
result = result.replace(/'/g, `'\\''`);
}
return result;
}
/**
* Quote an argument for use in a Unix shell.
*
* @param {string} arg The argument to quote.
* @returns {string} The quoted argument.
*/
function quoteArg(arg) {
return `'${arg}'`;
}
/**
* A mapping from shell names to functions that escape arguments for that shell.
*/
const escapeFunctionsByShell = new Map([
[binBash, escapeArgBash],
[binDash, escapeArgBash],
[binZsh, escapeArgZsh],
]);
/**
* A mapping from shell names to functions that quote arguments for that shell.
*/
const quoteFunctionsByShell = new Map([
[binBash, quoteArg],
[binDash, quoteArg],
[binZsh, quoteArg],
]);
/**
* Get the basename of a directory or file path on a Unix system.
*
* @param {string} fullPath A Unix-style directory or file path.
* @returns {string} The basename of `fullPath`.
*/
function getBasename(fullPath) {
return path.basename(fullPath);
}
/**
* Get the default shell for Unix systems.
*
* For more information, see `options.shell` in:
* https://nodejs.org/api/child_process.html#child_processexeccommand-options-callback
*
* @returns {string} The default shell.

@@ -77,1 +131,44 @@ */

}
/**
* Get a function to escape strings for use in a particular shell.
*
* @param {string} shellName The name of a Unix shell.
* @returns {Function?} A function to escape strings for use in the shell.
*/
export function getEscapeFunction(shellName) {
return escapeFunctionsByShell.get(shellName) || null;
}
/**
* Get a function to quote strings for use in a particular shell.
*
* @param {string} shellName The name of a Unix shell.
* @returns {Function?} A function to quote strings for use in the shell.
*/
export function getQuoteFunction(shellName) {
return quoteFunctionsByShell.get(shellName) || null;
}
/**
* Get the shell name given a shell name or path.
*
* @param {Object} args The arguments for this function.
* @param {string} args.shell The name or path of the shell.
* @param {Object} deps The dependencies for this function.
* @param {Function} deps.resolveExecutable Resolve the path to an executable.
* @returns {string} The shell name.
*/
export function getShellName({ shell }, { resolveExecutable }) {
shell = resolveExecutable(
{ executable: shell },
{ exists: fs.existsSync, readlink: fs.readlinkSync, which: which.sync }
);
const shellName = getBasename(shell);
if (getEscapeFunction(shellName) === null) {
return binBash;
}
return shellName;
}

@@ -7,6 +7,18 @@ /**

import { regexpPowerShell, shellRequiredError } from "./constants.js";
import * as fs from "fs";
import * as path from "path/win32";
import which from "which";
/**
* Escape a shell argument for use in CMD.
* @constant {string} binZsh The name of the Windows Command Prompt binary.
*/
const binCmd = "cmd.exe";
/**
* @constant {string} binPowerShell The name of the Windows PowerShell binary.
*/
const binPowerShell = "powershell.exe";
/**
* Escape a shell argument for use in the Windows Command Prompt.
*

@@ -17,3 +29,3 @@ * @param {string} arg The argument to escape.

*/
function escapeShellArgsForCmd(arg, interpolation) {
function escapeArgCmd(arg, interpolation) {
let result = arg.replace(/\u{0}/gu, "");

@@ -35,3 +47,3 @@

/**
* Escape a shell argument for use in PowerShell.
* Escape a shell argument for use in Windows PowerShell.
*

@@ -42,3 +54,3 @@ * @param {string} arg The argument to escape.

*/
function escapeShellArgsForPowerShell(arg, interpolation) {
function escapeArgPowerShell(arg, interpolation) {
let result = arg

@@ -65,17 +77,35 @@ .replace(/\u{0}/gu, "")

/**
* Escape a shell argument.
* Quote an argument for use in a Windows shell.
*
* @param {string} arg The argument to escape.
* @param {string} shell The shell to escape the argument for.
* @param {boolean} interpolation Is interpolation enabled.
* @returns {string} The escaped argument.
* @param {string} arg The argument to quote.
* @returns {string} The quoted argument.
*/
export function escapeShellArg(arg, shell, interpolation) {
if (shell === undefined) throw new TypeError(shellRequiredError);
function quoteArg(arg) {
return `"${arg}"`;
}
if (regexpPowerShell.test(shell)) {
return escapeShellArgsForPowerShell(arg, interpolation);
} else {
return escapeShellArgsForCmd(arg, interpolation);
}
/**
* A mapping from shell names to functions that escape arguments for that shell.
*/
const escapeFunctionsByShell = new Map([
[binCmd, escapeArgCmd],
[binPowerShell, escapeArgPowerShell],
]);
/**
* A mapping from shell names to functions that quote arguments for that shell.
*/
const quoteFunctionsByShell = new Map([
[binCmd, quoteArg],
[binPowerShell, quoteArg],
]);
/**
* Get the basename of a directory or file path on a Windows system.
*
* @param {string} fullPath A Windows-style directory or file path.
* @returns {string} The basename of `fullPath`.
*/
function getBasename(fullPath) {
return path.basename(fullPath);
}

@@ -86,8 +116,11 @@

*
* @param {Object} env The environment variables.
* @param {string} env.ComSpec The ComSpec value.
* For more information, see:
* https://nodejs.org/api/child_process.html#default-windows-shell
*
* @param {Object} args The arguments for this function.
* @param {Object} args.env The environment variables.
* @param {string} [args.env.ComSpec] The ComSpec value.
* @returns {string} The default shell.
*/
export function getDefaultShell(env) {
// See: https://nodejs.org/api/child_process.html#default-windows-shell
export function getDefaultShell({ env }) {
if (Object.prototype.hasOwnProperty.call(env, "ComSpec")) {

@@ -97,3 +130,46 @@ return env.ComSpec;

return "cmd.exe";
return binCmd;
}
/**
* Get a function to escape strings for use in a particular shell.
*
* @param {string} shellName The name of a Windows shell.
* @returns {Function?} A function to escape strings for use in the shell.
*/
export function getEscapeFunction(shellName) {
return escapeFunctionsByShell.get(shellName) || null;
}
/**
* Get a function to quote strings for use in a particular shell.
*
* @param {string} shellName The name of a Windows shell.
* @returns {Function?} A function to quote strings for use in the shell.
*/
export function getQuoteFunction(shellName) {
return quoteFunctionsByShell.get(shellName) || null;
}
/**
* Get the shell name given a shell name or path.
*
* @param {Object} args The arguments for this function.
* @param {string} args.shell The name or path of the shell.
* @param {Object} deps The dependencies for this function.
* @param {Function} deps.resolveExecutable Resolve the path to an executable.
* @returns {string} The shell name.
*/
export function getShellName({ shell }, { resolveExecutable }) {
shell = resolveExecutable(
{ executable: shell },
{ exists: fs.existsSync, readlink: fs.readlinkSync, which: which.sync }
);
const shellName = getBasename(shell);
if (getEscapeFunction(shellName) === null) {
return binCmd;
}
return shellName;
}

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