@optique/core 0.8.0 → 0.9.0-dev.172

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,12 +2,41 @@ const require_message = require('./message.cjs');
2
2
 
3
3
  //#region src/completion.ts
4
4
  /**
5
+ * A regular expression pattern for valid program names that can be safely
6
+ * interpolated into shell scripts.
7
+ *
8
+ * This pattern allows:
9
+ * - Letters (a-z, A-Z)
10
+ * - Numbers (0-9)
11
+ * - Underscore (_)
12
+ * - Hyphen (-)
13
+ * - Dot (.)
14
+ *
15
+ * @internal
16
+ */
17
+ const SAFE_PROGRAM_NAME_PATTERN = /^[a-zA-Z0-9_.-]+$/;
18
+ /**
19
+ * Validates a program name for safe use in shell scripts.
20
+ *
21
+ * Program names that contain shell metacharacters or other special characters
22
+ * could enable command injection attacks when interpolated into shell scripts.
23
+ * This function ensures only safe characters are used.
24
+ *
25
+ * @param programName The program name to validate.
26
+ * @throws {Error} If the program name contains invalid characters.
27
+ * @internal
28
+ */
29
+ function validateProgramName(programName) {
30
+ if (!SAFE_PROGRAM_NAME_PATTERN.test(programName)) throw new Error(`Invalid program name for shell completion: "${programName}". Program names must contain only alphanumeric characters, underscores, hyphens, and dots.`);
31
+ }
32
+ /**
5
33
  * The Bash shell completion generator.
6
34
  * @since 0.6.0
7
35
  */
8
36
  const bash = {
9
37
  name: "bash",
10
38
  generateScript(programName, args = []) {
39
+ validateProgramName(programName);
11
40
  const escapedArgs = args.map((arg) => `'${arg.replace(/'/g, "'\\''")}'`).join(" ");
12
41
  return `
13
42
  function _${programName} () {
@@ -107,6 +136,7 @@ complete -F _${programName} ${programName}
107
136
  const zsh = {
108
137
  name: "zsh",
109
138
  generateScript(programName, args = []) {
139
+ validateProgramName(programName);
110
140
  const escapedArgs = args.map((arg) => `'${arg.replace(/'/g, "'\\''")}'`).join(" ");
111
141
  return `
112
142
  function _${programName.replace(/[^a-zA-Z0-9]/g, "_")} () {
@@ -222,6 +252,7 @@ compdef _${programName.replace(/[^a-zA-Z0-9]/g, "_")} ${programName}
222
252
  const fish = {
223
253
  name: "fish",
224
254
  generateScript(programName, args = []) {
255
+ validateProgramName(programName);
225
256
  const escapedArgs = args.map((arg) => `'${arg.replace(/'/g, "\\'")}'`).join(" ");
226
257
  const functionName = `__${programName.replace(/[^a-zA-Z0-9]/g, "_")}_complete`;
227
258
  return `
@@ -354,6 +385,7 @@ complete -c ${programName} -f -a '(${functionName})'
354
385
  const nu = {
355
386
  name: "nu",
356
387
  generateScript(programName, args = []) {
388
+ validateProgramName(programName);
357
389
  const escapedArgs = args.map((arg) => `'${arg.replace(/'/g, "''")}'`).join(" ");
358
390
  const safeName = programName.replace(/[^a-zA-Z0-9]+/g, "-");
359
391
  const functionName = `nu-complete-${safeName}`;
@@ -583,6 +615,7 @@ ${functionName}-external
583
615
  const pwsh = {
584
616
  name: "pwsh",
585
617
  generateScript(programName, args = []) {
618
+ validateProgramName(programName);
586
619
  const escapedArgs = args.map((arg) => `'${arg.replace(/'/g, "''")}'`).join(", ");
587
620
  return `
588
621
  Register-ArgumentCompleter -Native -CommandName ${programName} -ScriptBlock {
@@ -2,12 +2,41 @@ import { formatMessage } from "./message.js";
2
2
 
3
3
  //#region src/completion.ts
4
4
  /**
5
+ * A regular expression pattern for valid program names that can be safely
6
+ * interpolated into shell scripts.
7
+ *
8
+ * This pattern allows:
9
+ * - Letters (a-z, A-Z)
10
+ * - Numbers (0-9)
11
+ * - Underscore (_)
12
+ * - Hyphen (-)
13
+ * - Dot (.)
14
+ *
15
+ * @internal
16
+ */
17
+ const SAFE_PROGRAM_NAME_PATTERN = /^[a-zA-Z0-9_.-]+$/;
18
+ /**
19
+ * Validates a program name for safe use in shell scripts.
20
+ *
21
+ * Program names that contain shell metacharacters or other special characters
22
+ * could enable command injection attacks when interpolated into shell scripts.
23
+ * This function ensures only safe characters are used.
24
+ *
25
+ * @param programName The program name to validate.
26
+ * @throws {Error} If the program name contains invalid characters.
27
+ * @internal
28
+ */
29
+ function validateProgramName(programName) {
30
+ if (!SAFE_PROGRAM_NAME_PATTERN.test(programName)) throw new Error(`Invalid program name for shell completion: "${programName}". Program names must contain only alphanumeric characters, underscores, hyphens, and dots.`);
31
+ }
32
+ /**
5
33
  * The Bash shell completion generator.
6
34
  * @since 0.6.0
7
35
  */
8
36
  const bash = {
9
37
  name: "bash",
10
38
  generateScript(programName, args = []) {
39
+ validateProgramName(programName);
11
40
  const escapedArgs = args.map((arg) => `'${arg.replace(/'/g, "'\\''")}'`).join(" ");
12
41
  return `
13
42
  function _${programName} () {
@@ -107,6 +136,7 @@ complete -F _${programName} ${programName}
107
136
  const zsh = {
108
137
  name: "zsh",
109
138
  generateScript(programName, args = []) {
139
+ validateProgramName(programName);
110
140
  const escapedArgs = args.map((arg) => `'${arg.replace(/'/g, "'\\''")}'`).join(" ");
111
141
  return `
112
142
  function _${programName.replace(/[^a-zA-Z0-9]/g, "_")} () {
@@ -222,6 +252,7 @@ compdef _${programName.replace(/[^a-zA-Z0-9]/g, "_")} ${programName}
222
252
  const fish = {
223
253
  name: "fish",
224
254
  generateScript(programName, args = []) {
255
+ validateProgramName(programName);
225
256
  const escapedArgs = args.map((arg) => `'${arg.replace(/'/g, "\\'")}'`).join(" ");
226
257
  const functionName = `__${programName.replace(/[^a-zA-Z0-9]/g, "_")}_complete`;
227
258
  return `
@@ -354,6 +385,7 @@ complete -c ${programName} -f -a '(${functionName})'
354
385
  const nu = {
355
386
  name: "nu",
356
387
  generateScript(programName, args = []) {
388
+ validateProgramName(programName);
357
389
  const escapedArgs = args.map((arg) => `'${arg.replace(/'/g, "''")}'`).join(" ");
358
390
  const safeName = programName.replace(/[^a-zA-Z0-9]+/g, "-");
359
391
  const functionName = `nu-complete-${safeName}`;
@@ -583,6 +615,7 @@ ${functionName}-external
583
615
  const pwsh = {
584
616
  name: "pwsh",
585
617
  generateScript(programName, args = []) {
618
+ validateProgramName(programName);
586
619
  const escapedArgs = args.map((arg) => `'${arg.replace(/'/g, "''")}'`).join(", ");
587
620
  return `
588
621
  Register-ArgumentCompleter -Native -CommandName ${programName} -ScriptBlock {
@@ -64,6 +64,11 @@ function choice(choices, options = {}) {
64
64
  *
65
65
  * This parser validates that the input is a string and optionally checks
66
66
  * if it matches a specified regular expression pattern.
67
+ *
68
+ * **Security note**: When using the `pattern` option with user-defined or
69
+ * complex patterns, be aware of potential Regular Expression Denial of Service
70
+ * (ReDoS) attacks. See {@link StringOptions.pattern} for more details.
71
+ *
67
72
  * @param options Configuration options for the string parser.
68
73
  * @returns A {@link ValueParser} that parses strings according to the
69
74
  * specified options.
@@ -78,6 +78,14 @@ interface StringOptions {
78
78
  readonly metavar?: string;
79
79
  /**
80
80
  * Optional regular expression pattern that the string must match.
81
+ *
82
+ * **Security note**: When using user-defined or complex patterns, be aware
83
+ * of potential Regular Expression Denial of Service (ReDoS) attacks.
84
+ * Maliciously crafted input strings can cause exponential backtracking in
85
+ * vulnerable patterns, leading to high CPU usage. Avoid patterns with
86
+ * nested quantifiers like `(a+)+` or overlapping alternations. Consider
87
+ * using tools like [safe-regex](https://www.npmjs.com/package/safe-regex)
88
+ * to validate patterns before use.
81
89
  */
82
90
  readonly pattern?: RegExp;
83
91
  /**
@@ -149,6 +157,11 @@ declare function choice<const T extends string>(choices: readonly T[], options?:
149
157
  *
150
158
  * This parser validates that the input is a string and optionally checks
151
159
  * if it matches a specified regular expression pattern.
160
+ *
161
+ * **Security note**: When using the `pattern` option with user-defined or
162
+ * complex patterns, be aware of potential Regular Expression Denial of Service
163
+ * (ReDoS) attacks. See {@link StringOptions.pattern} for more details.
164
+ *
152
165
  * @param options Configuration options for the string parser.
153
166
  * @returns A {@link ValueParser} that parses strings according to the
154
167
  * specified options.
@@ -78,6 +78,14 @@ interface StringOptions {
78
78
  readonly metavar?: string;
79
79
  /**
80
80
  * Optional regular expression pattern that the string must match.
81
+ *
82
+ * **Security note**: When using user-defined or complex patterns, be aware
83
+ * of potential Regular Expression Denial of Service (ReDoS) attacks.
84
+ * Maliciously crafted input strings can cause exponential backtracking in
85
+ * vulnerable patterns, leading to high CPU usage. Avoid patterns with
86
+ * nested quantifiers like `(a+)+` or overlapping alternations. Consider
87
+ * using tools like [safe-regex](https://www.npmjs.com/package/safe-regex)
88
+ * to validate patterns before use.
81
89
  */
82
90
  readonly pattern?: RegExp;
83
91
  /**
@@ -149,6 +157,11 @@ declare function choice<const T extends string>(choices: readonly T[], options?:
149
157
  *
150
158
  * This parser validates that the input is a string and optionally checks
151
159
  * if it matches a specified regular expression pattern.
160
+ *
161
+ * **Security note**: When using the `pattern` option with user-defined or
162
+ * complex patterns, be aware of potential Regular Expression Denial of Service
163
+ * (ReDoS) attacks. See {@link StringOptions.pattern} for more details.
164
+ *
152
165
  * @param options Configuration options for the string parser.
153
166
  * @returns A {@link ValueParser} that parses strings according to the
154
167
  * specified options.
@@ -64,6 +64,11 @@ function choice(choices, options = {}) {
64
64
  *
65
65
  * This parser validates that the input is a string and optionally checks
66
66
  * if it matches a specified regular expression pattern.
67
+ *
68
+ * **Security note**: When using the `pattern` option with user-defined or
69
+ * complex patterns, be aware of potential Regular Expression Denial of Service
70
+ * (ReDoS) attacks. See {@link StringOptions.pattern} for more details.
71
+ *
67
72
  * @param options Configuration options for the string parser.
68
73
  * @returns A {@link ValueParser} that parses strings according to the
69
74
  * specified options.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optique/core",
3
- "version": "0.8.0",
3
+ "version": "0.9.0-dev.172+ab781f75",
4
4
  "description": "Type-safe combinatorial command-line interface parser",
5
5
  "keywords": [
6
6
  "CLI",