Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
35 changes: 35 additions & 0 deletions src/cli/utils/ObfuscatedCodeFileUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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;
}
}
}
43 changes: 43 additions & 0 deletions test/unit-tests/cli/utils/ObfuscatedCodeFileUtils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down
Loading