Fixed CLI --config failures hiding the real cause behind a generic Cannot open config file message (#1435)

This commit is contained in:
Timofey Kachalov
2026-07-10 20:34:31 +04:00
committed by GitHub
parent 1bdaa51b22
commit ecbffd87fc
4 changed files with 60 additions and 11 deletions
+1
View File
@@ -2,6 +2,7 @@ Change Log
v5.4.7
---
* Fixed CLI `--config` failures hiding the real cause behind a generic `Cannot open config file` message. Fixes https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1101
* Fixed `sourceMapFileName` ending in `.js.map` (e.g. `foo.min.js.map`) being mangled in the emitted `//# sourceMappingURL=` comment. Fixes https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1312
* Fixed `URIError: URI malformed` crash when `stringArray` with `base64`/`rc4` encoding processed a string literal containing lone surrogate code units (e.g. `"[^\uD800-\uDFFF]"`). Fixes https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1431
* Bumped the production `brace-expansion` transitive dependency to a patched version, resolving `CVE-2026-25547`. Fixes https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1405
+33 -11
View File
@@ -15,26 +15,32 @@ export class CLIUtils {
* @returns {TDictionary}
*/
public static getUserConfig(configPath: string): TDictionary {
let config: TDictionary;
const configFileExtension: string = path.extname(configPath);
const isValidExtension: boolean = CLIUtils.allowedConfigFileExtensions.includes(configFileExtension);
if (!isValidExtension) {
throw new ReferenceError('Given config path must be a valid `.js|.mjs|.cjs` or `.json` file path');
throw new ReferenceError('Given config path must be a valid `.js`, `.cjs` or `.json` file path');
}
const errors: Error[] = [];
try {
return require(configPath);
} catch (error) {
errors.push(<Error>error);
}
try {
config = require(configPath);
} catch {
try {
config = __non_webpack_require__(configPath);
} catch {
throw new ReferenceError(`Cannot open config file with path: ${configPath}`);
}
return __non_webpack_require__(configPath);
} catch (error) {
errors.push(<Error>error);
}
return config;
// surface the underlying reason (invalid JSON, `ERR_REQUIRE_ESM`, missing file, ...)
// instead of masking it behind a generic message
throw new ReferenceError(
`Cannot open config file with path: ${configPath}. Reason: ${CLIUtils.getConfigErrorReason(errors)}`
);
}
/**
@@ -44,4 +50,20 @@ export class CLIUtils {
public static stringifyOptionAvailableValues(optionEnum: TDictionary): string {
return Object.values(optionEnum).join(`${StringSeparator.Comma} `);
}
/**
* @param {Error[]} errors
* @returns {string}
*/
private static getConfigErrorReason(errors: Error[]): string {
const [firstError, secondError] = errors;
// in the webpack bundle the real reason comes from the `__non_webpack_require__` call (the second error);
// in a plain Node/ts-node context `__non_webpack_require__` is not defined, so the real reason is the first error
if (secondError && !secondError.message.includes('__non_webpack_require__')) {
return secondError.message;
}
return firstError.message;
}
}
+5
View File
@@ -0,0 +1,5 @@
{
compact: true,
selfDefending: false,
sourceMap: true
}
@@ -106,6 +106,27 @@ describe('CLIUtils', () => {
assert.throws(testFunc, /Cannot open config file/);
});
});
// https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1101
describe('Variant #4: config file with invalid content', () => {
const configDirName: string = 'test/fixtures';
const configFileName: string = 'invalid-config.json';
const configFilePath: string = `../../../${configDirName}/${configFileName}`;
let testFunc: () => void;
before(() => {
testFunc = () => CLIUtils.getUserConfig(configFilePath);
});
it('should throw an error that includes the config file path', () => {
assert.throws(testFunc, /Cannot open config file with path/);
});
it('should surface the underlying reason instead of masking it', () => {
assert.throws(testFunc, /Reason:.*JSON/);
});
});
});
describe('stringifyOptionAvailableValues', () => {