From 8694c6fca9a8b4e969993fbe1b9c26d25666564b Mon Sep 17 00:00:00 2001 From: sanex3339 Date: Sun, 22 Mar 2026 14:50:10 +0700 Subject: [PATCH] Fixed CLI `--options-preset` not applying preset values for options not explicitly set via command line --- CHANGELOG.md | 1 + src/cli/JavaScriptObfuscatorCLI.ts | 28 +++++++++--- test/fixtures/sample-long-string.js | 2 + .../cli/JavaScriptObfuscatorCLI.spec.ts | 45 +++++++++++++++++++ 4 files changed, 69 insertions(+), 7 deletions(-) create mode 100644 test/fixtures/sample-long-string.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f3c63e2f..b050fb812 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ v5.4.0 * Fixed `reservedNames` not preserving class method and property names when `stringArray` or `deadCodeInjection` is enabled. Fixes https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1279 * Fixed infinite loop / stack overflow when `reservedNames` patterns match all generated identifier names. Now throws a descriptive error instead. Fixes https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1382 * Fixed `transformObjectKeys` changing evaluation order when object expression is inside a sequence expression with preceding side effects (e.g. `return aux(ys), { min }`). Fixes https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1246 +* Fixed CLI `--options-preset` not applying preset values for options not explicitly set via command line (e.g. `splitStrings` from `high-obfuscation` preset was ignored). Fixes https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1236 * Replaced `mkdirp` dependency with native `fs.mkdirSync({ recursive: true })`. Fixes https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1275. Thank you https://github.com/roli-lpci! * Replaced `conf` dependency with custom implementation using `env-paths` and native `fs` diff --git a/src/cli/JavaScriptObfuscatorCLI.ts b/src/cli/JavaScriptObfuscatorCLI.ts index 99b16d53a..95eb5b78d 100644 --- a/src/cli/JavaScriptObfuscatorCLI.ts +++ b/src/cli/JavaScriptObfuscatorCLI.ts @@ -4,6 +4,7 @@ import * as path from 'path'; import { TInputCLIOptions } from '../types/options/TInputCLIOptions'; import { TInputOptions } from '../types/options/TInputOptions'; +import { TOptionsPreset } from '../types/options/TOptionsPreset'; import { IFileData } from '../interfaces/cli/IFileData'; import { IInitializable } from '../interfaces/IInitializable'; @@ -24,11 +25,10 @@ import { StringArrayEncoding } from '../enums/node-transformers/string-array-tra import { StringArrayIndexesType } from '../enums/node-transformers/string-array-transformers/StringArrayIndexesType'; import { StringArrayWrappersType } from '../enums/node-transformers/string-array-transformers/StringArrayWrappersType'; -import { DEFAULT_PRESET } from '../options/presets/Default'; - import { ArraySanitizer } from './sanitizers/ArraySanitizer'; import { BooleanSanitizer } from './sanitizers/BooleanSanitizer'; +import { Options } from '../options/Options'; import { CLIUtils } from './utils/CLIUtils'; import { IdentifierNamesCacheFileUtils } from './utils/IdentifierNamesCacheFileUtils'; import { JavaScriptObfuscator } from '../JavaScriptObfuscatorFacade'; @@ -112,26 +112,36 @@ export class JavaScriptObfuscatorCLI implements IInitializable { /** * @param {TInputCLIOptions} inputOptions + * @param {commander.Command} command * @returns {TInputOptions} */ - private static buildOptions(inputOptions: TInputCLIOptions): TInputOptions { - const inputCLIOptions: TInputOptions = JavaScriptObfuscatorCLI.filterOptions(inputOptions); + private static buildOptions(inputOptions: TInputCLIOptions, command: commander.Command): TInputOptions { + const inputCLIOptions: TInputOptions = JavaScriptObfuscatorCLI.filterOptions(inputOptions, command); const configFilePath: string | undefined = inputOptions.config; const configFileLocation: string = configFilePath ? path.resolve(configFilePath, '.') : ''; const configFileOptions: TInputOptions = configFileLocation ? CLIUtils.getUserConfig(configFileLocation) : {}; + const presetName: TOptionsPreset = + inputCLIOptions.optionsPreset ?? configFileOptions.optionsPreset ?? OptionsPreset.Default; + const presetOptions: TInputOptions = Options.getOptionsByPreset(presetName); + return { - ...DEFAULT_PRESET, + ...presetOptions, ...configFileOptions, ...inputCLIOptions }; } /** + * Filters out options that were not explicitly set by the user. + * Commander.js sets default values for all options, which would + * override preset values. Only user-provided options should be kept. + * * @param {TObject} options + * @param {commander.Command} command * @returns {TInputOptions} */ - private static filterOptions(options: TInputCLIOptions): TInputOptions { + private static filterOptions(options: TInputCLIOptions, command: commander.Command): TInputOptions { const filteredOptions: TInputOptions = {}; Object.keys(options).forEach((option: keyof TInputCLIOptions) => { @@ -139,6 +149,10 @@ export class JavaScriptObfuscatorCLI implements IInitializable { return; } + if (command.getOptionValueSource(String(option)) === 'default') { + return; + } + filteredOptions[option] = options[option]; }); @@ -152,7 +166,7 @@ export class JavaScriptObfuscatorCLI implements IInitializable { this.configureHelp(); this.inputPath = path.normalize(this.commands.args[0] || ''); - this.inputCLIOptions = JavaScriptObfuscatorCLI.buildOptions(this.commands.opts()); + this.inputCLIOptions = JavaScriptObfuscatorCLI.buildOptions(this.commands.opts(), this.commands); this.sourceCodeFileUtils = new SourceCodeFileUtils(this.inputPath, this.inputCLIOptions); this.obfuscatedCodeFileUtils = new ObfuscatedCodeFileUtils(this.inputPath, this.inputCLIOptions); this.identifierNamesCacheFileUtils = new IdentifierNamesCacheFileUtils( diff --git a/test/fixtures/sample-long-string.js b/test/fixtures/sample-long-string.js new file mode 100644 index 000000000..c259a23a8 --- /dev/null +++ b/test/fixtures/sample-long-string.js @@ -0,0 +1,2 @@ +var x = "This is a long string and it should really be split by the obfuscator"; +console.log(x); diff --git a/test/functional-tests/cli/JavaScriptObfuscatorCLI.spec.ts b/test/functional-tests/cli/JavaScriptObfuscatorCLI.spec.ts index 541e33108..8b9462599 100644 --- a/test/functional-tests/cli/JavaScriptObfuscatorCLI.spec.ts +++ b/test/functional-tests/cli/JavaScriptObfuscatorCLI.spec.ts @@ -1511,6 +1511,51 @@ describe('JavaScriptObfuscatorCLI', function (): void { }); }); + /** + * https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1236 + */ + describe('`--options-preset` should apply preset options that are not explicitly set via CLI', () => { + const longStringFixturePath: string = path.join(fixturesDirName, 'sample-long-string.js'); + + let obfuscatedCode: string; + + before(async () => { + await JavaScriptObfuscatorCLI.obfuscate([ + 'node', + 'javascript-obfuscator', + longStringFixturePath, + '--output', + outputFilePath, + '--options-preset', + 'medium-obfuscation', + '--string-array', + 'false', + '--dead-code-injection', + 'false', + '--control-flow-flattening', + 'false', + '--self-defending', + 'false', + '--debug-protection', + 'false', + '--disable-console-output', + 'false', + '--seed', + '1' + ]); + + obfuscatedCode = fs.readFileSync(outputFilePath, 'utf8'); + }); + + it('should apply `splitStrings` from preset without explicit `--split-strings` flag', () => { + assert.match(obfuscatedCode, /'.+'\s*\+\s*'.+'\s*\+\s*'.+'/); + }); + + after(() => { + fs.unlinkSync(outputFilePath); + }); + }); + after(() => { rimraf.sync(outputDirName); });