Fixed directory obfuscation with a set sourceMapFileName making all files share and overwrite one .map (#1436)

This commit is contained in:
Timofey Kachalov
2026-07-10 20:46:53 +04:00
committed by GitHub
parent ecbffd87fc
commit 35860ec708
3 changed files with 79 additions and 0 deletions
+1
View File
@@ -2,6 +2,7 @@ Change Log
v5.4.7
---
* Fixed directory obfuscation with a set `sourceMapFileName` making all files share and overwrite one `.map`. Fixes https://github.com/javascript-obfuscator/javascript-obfuscator/issues/817
* 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
+35
View File
@@ -88,6 +88,8 @@ export class ObfuscatedCodeFileUtils {
throw new Error('Output code path is empty');
}
sourceMapFileName = this.getUniqueSourceMapFileName(outputCodePath, sourceMapFileName);
let normalizedOutputCodePath: string = path.normalize(outputCodePath);
let parsedOutputCodePath: path.ParsedPath = path.parse(normalizedOutputCodePath);
@@ -140,4 +142,37 @@ export class ObfuscatedCodeFileUtils {
encoding: JavaScriptObfuscatorCLI.encoding
});
}
/**
* For directory obfuscation a single `sourceMapFileName` would be shared by every file and the
* source maps would overwrite each other, so it is prefixed with the output code file name to
* keep each source map unique.
* https://github.com/javascript-obfuscator/javascript-obfuscator/issues/817
*
* @param {string} outputCodePath
* @param {string} sourceMapFileName
* @returns {string}
*/
private getUniqueSourceMapFileName(outputCodePath: string, sourceMapFileName: string): string {
if (!sourceMapFileName || !this.isDirectoryInputPath()) {
return sourceMapFileName;
}
const outputCodeName: string = path.parse(outputCodePath).name;
const parsedSourceMapFileName: path.ParsedPath = path.parse(sourceMapFileName);
// keep any leading directory part of `sourceMapFileName`, prefix only its file name
return path.join(parsedSourceMapFileName.dir, `${outputCodeName}-${parsedSourceMapFileName.base}`);
}
/**
* @returns {boolean}
*/
private isDirectoryInputPath(): boolean {
try {
return fs.lstatSync(this.inputPath).isDirectory();
} catch {
return false;
}
}
}
@@ -715,6 +715,49 @@ describe('obfuscatedCodeFileUtils', () => {
});
});
// https://github.com/javascript-obfuscator/javascript-obfuscator/issues/817
describe('Variant #2: input path is a directory', () => {
const rawInputPath: string = path.join(tmpDirectoryPath, 'sm-input');
const rawOutputPath: string = path.join(tmpDirectoryPath, 'output');
const sourceMapFileName: string = 'map';
let firstOutputSourceMapPath: string;
let secondOutputSourceMapPath: string;
before(() => {
fs.mkdirSync(rawInputPath, { recursive: true });
const obfuscatedCodeFileUtils: ObfuscatedCodeFileUtils = new ObfuscatedCodeFileUtils(rawInputPath, {
output: rawOutputPath
});
firstOutputSourceMapPath = obfuscatedCodeFileUtils.getOutputSourceMapPath(
path.join(rawOutputPath, 'foo.js'),
sourceMapFileName
);
secondOutputSourceMapPath = obfuscatedCodeFileUtils.getOutputSourceMapPath(
path.join(rawOutputPath, 'bar.js'),
sourceMapFileName
);
});
after(() => {
rimraf.sync(rawInputPath);
});
it('match #1: should prefix the source map file name with the output code file name', () => {
assert.equal(firstOutputSourceMapPath, path.join(rawOutputPath, 'foo-map.js.map'));
});
it('match #2: should prefix the source map file name with the output code file name', () => {
assert.equal(secondOutputSourceMapPath, path.join(rawOutputPath, 'bar-map.js.map'));
});
it('should produce a unique source map path per file', () => {
assert.notEqual(firstOutputSourceMapPath, secondOutputSourceMapPath);
});
});
describe('Variant #3: empty paths', () => {
const rawInputPath: string = path.join(tmpDirectoryPath, 'input', 'test-input.js');
const rawOutputPath: string = path.join(tmpDirectoryPath, 'output', 'test-output.js');