mirror of
https://github.com/javascript-obfuscator/javascript-obfuscator
synced 2026-08-09 12:42:29 +00:00
1564 lines
67 KiB
TypeScript
1564 lines
67 KiB
TypeScript
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
import * as rimraf from 'rimraf';
|
|
import * as sinon from 'sinon';
|
|
import { resolveSources } from 'source-map-resolve';
|
|
|
|
import { assert } from 'chai';
|
|
|
|
import { ISourceMap } from '../../../src/interfaces/source-code/ISourceMap';
|
|
|
|
import { StdoutWriteMock } from '../../mocks/StdoutWriteMock';
|
|
|
|
import { JavaScriptObfuscatorCLI } from '../../../src/JavaScriptObfuscatorCLIFacade';
|
|
import { ProApiClient } from '../../../src/pro-api/ProApiClient';
|
|
import { parseSourceMapFromObfuscatedCode } from '../../helpers/parseSourceMapFromObfuscatedCode';
|
|
|
|
describe('JavaScriptObfuscatorCLI', function (): void {
|
|
this.timeout(100000);
|
|
|
|
const expectedError: RegExp = /Given input path must be a valid/;
|
|
|
|
const fixturesDirName: string = path.join('test', 'fixtures');
|
|
const fixtureFileName: string = 'sample.js';
|
|
const fixtureFilePath: string = path.join(fixturesDirName, fixtureFileName);
|
|
const outputDirName: string = path.join('test', 'tmp');
|
|
const outputFileName: string = 'sample-obfuscated.js';
|
|
const outputFilePath: string = path.join(outputDirName, outputFileName);
|
|
const configDirName: string = path.join('test', 'fixtures');
|
|
const configFileName: string = 'config.js';
|
|
const configFilePath: string = path.join(configDirName, configFileName);
|
|
|
|
describe('run', () => {
|
|
before(async () => {
|
|
fs.mkdirSync(outputDirName, { recursive: true });
|
|
});
|
|
|
|
describe('Variant #1: obfuscation of single file', () => {
|
|
describe('--output` option is set', () => {
|
|
describe('Variant #1: input file path is before options', () => {
|
|
let isFileExist: boolean;
|
|
|
|
before(async () => {
|
|
await JavaScriptObfuscatorCLI.obfuscate([
|
|
'node',
|
|
'javascript-obfuscator',
|
|
fixtureFilePath,
|
|
'--output',
|
|
outputFilePath,
|
|
'--compact',
|
|
'true',
|
|
'--self-defending',
|
|
'0'
|
|
]);
|
|
|
|
isFileExist = fs.existsSync(outputFilePath);
|
|
});
|
|
|
|
it('should create file with obfuscated code in `--output` directory', () => {
|
|
assert.equal(isFileExist, true);
|
|
});
|
|
|
|
after(() => {
|
|
fs.unlinkSync(outputFilePath);
|
|
});
|
|
});
|
|
|
|
describe('Variant #2: input file path is after options', () => {
|
|
let isFileExist: boolean;
|
|
|
|
before(async () => {
|
|
await JavaScriptObfuscatorCLI.obfuscate([
|
|
'node',
|
|
'javascript-obfuscator',
|
|
'--output',
|
|
outputFilePath,
|
|
'--compact',
|
|
'true',
|
|
'--self-defending',
|
|
'0',
|
|
fixtureFilePath
|
|
]);
|
|
|
|
isFileExist = fs.existsSync(outputFilePath);
|
|
});
|
|
|
|
it('should create file with obfuscated code in `--output` directory', () => {
|
|
assert.equal(isFileExist, true);
|
|
});
|
|
|
|
after(() => {
|
|
fs.unlinkSync(outputFilePath);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("`--output` option isn't set", () => {
|
|
describe('Variant #1: default behaviour', () => {
|
|
let outputFixturesFilePath: string, isFileExist: boolean;
|
|
|
|
before(async () => {
|
|
outputFixturesFilePath = path.join(fixturesDirName, outputFileName);
|
|
|
|
await JavaScriptObfuscatorCLI.obfuscate(['node', 'javascript-obfuscator', fixtureFilePath]);
|
|
|
|
isFileExist = fs.existsSync(outputFixturesFilePath);
|
|
});
|
|
|
|
it(`should create file \`${outputFileName}\` with obfuscated code in \`${fixturesDirName}\` directory`, () => {
|
|
assert.equal(isFileExist, true);
|
|
});
|
|
|
|
after(() => {
|
|
fs.unlinkSync(outputFixturesFilePath);
|
|
});
|
|
});
|
|
|
|
describe('Variant #2: invalid input file path', () => {
|
|
it(`should throw an error`, async () => {
|
|
try {
|
|
await await JavaScriptObfuscatorCLI.obfuscate([
|
|
'node',
|
|
'javascript-obfuscator',
|
|
path.join('wrong', 'file', 'path')
|
|
]);
|
|
assert.fail('Expected error was not thrown');
|
|
} catch (error) {
|
|
assert.match((error as Error).message, expectedError);
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("Variant #3: input file extension isn't `.js`", () => {
|
|
const expectedError: RegExp = /Given input path must be a valid/;
|
|
const outputFileName: string = 'sample-obfuscated.ts';
|
|
const outputFilePath: string = path.join(outputDirName, outputFileName);
|
|
|
|
before(async () => {
|
|
fs.writeFileSync(outputFilePath, 'data');
|
|
});
|
|
|
|
it(`should throw an error`, async () => {
|
|
try {
|
|
await await JavaScriptObfuscatorCLI.obfuscate(['node', 'javascript-obfuscator', outputFilePath]);
|
|
assert.fail('Expected error was not thrown');
|
|
} catch (error) {
|
|
assert.match((error as Error).message, expectedError);
|
|
}
|
|
});
|
|
|
|
after(() => {
|
|
fs.unlinkSync(outputFilePath);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('--exclude option', () => {
|
|
describe('Variant #1: --exclude option is pointed on different file', () => {
|
|
let isFileExist: boolean;
|
|
|
|
before(async () => {
|
|
await await JavaScriptObfuscatorCLI.obfuscate([
|
|
'node',
|
|
'javascript-obfuscator',
|
|
fixtureFilePath,
|
|
'--output',
|
|
outputFilePath,
|
|
'--exclude',
|
|
path.join('**', 'foo.js')
|
|
]);
|
|
|
|
isFileExist = fs.existsSync(outputFilePath);
|
|
});
|
|
|
|
it('should create file with obfuscated code in `--output` directory', () => {
|
|
assert.equal(isFileExist, true);
|
|
});
|
|
});
|
|
|
|
describe('Variant #2: --exclude option is pointed on input file', () => {
|
|
it('should throw an error', async () => {
|
|
try {
|
|
await await JavaScriptObfuscatorCLI.obfuscate([
|
|
'node',
|
|
'javascript-obfuscator',
|
|
fixtureFilePath,
|
|
'--output',
|
|
outputFilePath,
|
|
'--exclude',
|
|
path.join('**', 'sample.js')
|
|
]);
|
|
assert.fail('Expected error was not thrown');
|
|
} catch (error) {
|
|
assert.match((error as Error).message, expectedError);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Variant #2: obfuscation of directory', () => {
|
|
describe(`Variant #1: default behaviour`, () => {
|
|
const directoryPath: string = path.join(fixturesDirName, 'directory-obfuscation');
|
|
const outputFileName1: string = 'foo-obfuscated.js';
|
|
const outputFileName2: string = 'bar-obfuscated.js';
|
|
const outputFileName3: string = 'baz-obfuscated.js';
|
|
const readFileEncoding = 'utf8';
|
|
const regExp1: RegExp = /^var a1_0x(\w){4,6} *= *0x1;$/;
|
|
const regExp2: RegExp = /^var a0_0x(\w){4,6} *= *0x2;$/;
|
|
|
|
let outputFixturesFilePath1: string,
|
|
outputFixturesFilePath2: string,
|
|
outputFixturesFilePath3: string,
|
|
isFileExist1: boolean,
|
|
isFileExist2: boolean,
|
|
isFileExist3: boolean,
|
|
fileContent1: string,
|
|
fileContent2: string;
|
|
|
|
before(async () => {
|
|
outputFixturesFilePath1 = path.join(directoryPath, outputFileName1);
|
|
outputFixturesFilePath2 = path.join(directoryPath, outputFileName2);
|
|
outputFixturesFilePath3 = path.join(directoryPath, outputFileName3);
|
|
|
|
await await JavaScriptObfuscatorCLI.obfuscate([
|
|
'node',
|
|
'javascript-obfuscator',
|
|
directoryPath,
|
|
'--rename-globals',
|
|
'true'
|
|
]);
|
|
|
|
isFileExist1 = fs.existsSync(outputFixturesFilePath1);
|
|
isFileExist2 = fs.existsSync(outputFixturesFilePath2);
|
|
isFileExist3 = fs.existsSync(outputFixturesFilePath3);
|
|
|
|
fileContent1 = fs.readFileSync(outputFixturesFilePath1, readFileEncoding);
|
|
fileContent2 = fs.readFileSync(outputFixturesFilePath2, readFileEncoding);
|
|
});
|
|
|
|
it(`should create file \`${outputFileName1}\` with obfuscated code in \`${fixturesDirName}\` directory`, () => {
|
|
assert.equal(isFileExist1, true);
|
|
});
|
|
|
|
it(`should create file \`${outputFileName2}\` with obfuscated code in \`${fixturesDirName}\` directory`, () => {
|
|
assert.equal(isFileExist2, true);
|
|
});
|
|
|
|
it(`shouldn't create file \`${outputFileName3}\` in \`${fixturesDirName}\` directory`, () => {
|
|
assert.equal(isFileExist3, false);
|
|
});
|
|
|
|
it(`match #1: should create file with obfuscated code with prefixed identifier`, () => {
|
|
assert.match(fileContent1, regExp1);
|
|
});
|
|
|
|
it(`match #2: should create file with obfuscated code with prefixed identifier`, () => {
|
|
assert.match(fileContent2, regExp2);
|
|
});
|
|
|
|
after(() => {
|
|
rimraf.sync(outputFixturesFilePath1);
|
|
rimraf.sync(outputFixturesFilePath2);
|
|
});
|
|
});
|
|
|
|
describe('Variant #2: obfuscation of directory with `identifiersPrefix` option value', () => {
|
|
const directoryPath: string = path.join(fixturesDirName, 'directory-obfuscation');
|
|
const identifiersPrefix: string = 'foo';
|
|
const outputFileName1: string = 'foo-obfuscated.js';
|
|
const outputFileName2: string = 'bar-obfuscated.js';
|
|
const readFileEncoding = 'utf8';
|
|
const regExp1: RegExp = /^var foo1_0x(\w){4,6} *= *0x1;$/;
|
|
const regExp2: RegExp = /^var foo0_0x(\w){4,6} *= *0x2;$/;
|
|
|
|
let outputFixturesFilePath1: string,
|
|
outputFixturesFilePath2: string,
|
|
isFileExist1: boolean,
|
|
isFileExist2: boolean,
|
|
fileContent1: string,
|
|
fileContent2: string;
|
|
|
|
before(async () => {
|
|
outputFixturesFilePath1 = path.join(directoryPath, outputFileName1);
|
|
outputFixturesFilePath2 = path.join(directoryPath, outputFileName2);
|
|
|
|
await JavaScriptObfuscatorCLI.obfuscate([
|
|
'node',
|
|
'javascript-obfuscator',
|
|
directoryPath,
|
|
'--identifiers-prefix',
|
|
identifiersPrefix,
|
|
'--rename-globals',
|
|
'true'
|
|
]);
|
|
|
|
isFileExist1 = fs.existsSync(outputFixturesFilePath1);
|
|
isFileExist2 = fs.existsSync(outputFixturesFilePath2);
|
|
|
|
fileContent1 = fs.readFileSync(outputFixturesFilePath1, readFileEncoding);
|
|
fileContent2 = fs.readFileSync(outputFixturesFilePath2, readFileEncoding);
|
|
});
|
|
|
|
it(`should create file \`${outputFileName1}\` with obfuscated code in \`${fixturesDirName}\` directory`, () => {
|
|
assert.equal(isFileExist1, true);
|
|
});
|
|
|
|
it(`should create file \`${outputFileName2}\` with obfuscated code in \`${fixturesDirName}\` directory`, () => {
|
|
assert.equal(isFileExist2, true);
|
|
});
|
|
|
|
it(`match #1: should create file with obfuscated code with prefixed identifier`, () => {
|
|
assert.match(fileContent1, regExp1);
|
|
});
|
|
|
|
it(`match #2: should create file with obfuscated code with prefixed identifier`, () => {
|
|
assert.match(fileContent2, regExp2);
|
|
});
|
|
|
|
after(() => {
|
|
rimraf.sync(outputFixturesFilePath1);
|
|
rimraf.sync(outputFixturesFilePath2);
|
|
});
|
|
});
|
|
|
|
describe('Variant #3: obfuscation of directory with `output` option', () => {
|
|
const directoryPath: string = path.join(fixturesDirName, 'directory-obfuscation');
|
|
const outputDirectoryName: string = 'obfuscated';
|
|
const outputDirectoryPath: string = path.join(directoryPath, outputDirectoryName);
|
|
const outputFileName1: string = 'foo.js';
|
|
const outputFileName2: string = 'bar.js';
|
|
const outputFileName3: string = 'baz.js';
|
|
|
|
let outputFixturesFilePath1: string,
|
|
outputFixturesFilePath2: string,
|
|
outputFixturesFilePath3: string,
|
|
isFileExist1: boolean,
|
|
isFileExist2: boolean,
|
|
isFileExist3: boolean;
|
|
|
|
before(async () => {
|
|
outputFixturesFilePath1 = path.join(outputDirectoryPath, outputFileName1);
|
|
outputFixturesFilePath2 = path.join(outputDirectoryPath, outputFileName2);
|
|
outputFixturesFilePath3 = path.join(outputDirectoryPath, outputFileName3);
|
|
|
|
await JavaScriptObfuscatorCLI.obfuscate([
|
|
'node',
|
|
'javascript-obfuscator',
|
|
directoryPath,
|
|
'--output',
|
|
outputDirectoryPath
|
|
]);
|
|
|
|
isFileExist1 = fs.existsSync(outputFixturesFilePath1);
|
|
isFileExist2 = fs.existsSync(outputFixturesFilePath2);
|
|
isFileExist3 = fs.existsSync(outputFixturesFilePath3);
|
|
});
|
|
|
|
it(
|
|
`should create file \`${outputFileName1}\` with obfuscated code in ` +
|
|
`\`${path.join(fixturesDirName, outputDirectoryName)}\` directory`,
|
|
() => {
|
|
assert.equal(isFileExist1, true);
|
|
}
|
|
);
|
|
|
|
it(
|
|
`should create file \`${outputFileName2}\` with obfuscated code in ` +
|
|
`\`${path.join(fixturesDirName, outputDirectoryName)}\` directory`,
|
|
() => {
|
|
assert.equal(isFileExist2, true);
|
|
}
|
|
);
|
|
|
|
it(
|
|
`shouldn't create file \`${outputFileName3}\` in ` +
|
|
`\`${path.join(fixturesDirName, outputDirectoryName)}\` directory`,
|
|
() => {
|
|
assert.equal(isFileExist3, false);
|
|
}
|
|
);
|
|
|
|
after(() => {
|
|
rimraf.sync(outputDirectoryPath);
|
|
});
|
|
});
|
|
|
|
describe('Variant #4: --exclude option', () => {
|
|
describe('Variant #1: --exclude option is pointed on different file', () => {
|
|
const directoryPath: string = path.join(fixturesDirName, 'directory-obfuscation');
|
|
const outputFileName1: string = 'foo-obfuscated.js';
|
|
const outputFileName2: string = 'bar-obfuscated.js';
|
|
const outputFileName3: string = 'baz-obfuscated.js';
|
|
const readFileEncoding = 'utf8';
|
|
const regExp1: RegExp = /^var a1_0x(\w){4,6} *= *0x1;$/;
|
|
const regExp2: RegExp = /^var a0_0x(\w){4,6} *= *0x2;$/;
|
|
|
|
let outputFixturesFilePath1: string,
|
|
outputFixturesFilePath2: string,
|
|
outputFixturesFilePath3: string,
|
|
isFileExist1: boolean,
|
|
isFileExist2: boolean,
|
|
isFileExist3: boolean,
|
|
fileContent1: string,
|
|
fileContent2: string;
|
|
|
|
before(async () => {
|
|
outputFixturesFilePath1 = path.join(directoryPath, outputFileName1);
|
|
outputFixturesFilePath2 = path.join(directoryPath, outputFileName2);
|
|
outputFixturesFilePath3 = path.join(directoryPath, outputFileName3);
|
|
|
|
await JavaScriptObfuscatorCLI.obfuscate([
|
|
'node',
|
|
'javascript-obfuscator',
|
|
directoryPath,
|
|
'--exclude',
|
|
path.join('**', 'bark.js'),
|
|
'--rename-globals',
|
|
'true'
|
|
]);
|
|
|
|
isFileExist1 = fs.existsSync(outputFixturesFilePath1);
|
|
isFileExist2 = fs.existsSync(outputFixturesFilePath2);
|
|
isFileExist3 = fs.existsSync(outputFixturesFilePath3);
|
|
|
|
fileContent1 = fs.readFileSync(outputFixturesFilePath1, readFileEncoding);
|
|
fileContent2 = fs.readFileSync(outputFixturesFilePath2, readFileEncoding);
|
|
});
|
|
|
|
it(`should create file \`${outputFileName1}\` with obfuscated code in \`${fixturesDirName}\` directory`, () => {
|
|
assert.equal(isFileExist1, true);
|
|
});
|
|
|
|
it(`should create file \`${outputFileName2}\` with obfuscated code in \`${fixturesDirName}\` directory`, () => {
|
|
assert.equal(isFileExist2, true);
|
|
});
|
|
|
|
it(`shouldn't create file \`${outputFileName3}\` in \`${fixturesDirName}\` directory`, () => {
|
|
assert.equal(isFileExist3, false);
|
|
});
|
|
|
|
it(`match #1: should create file with obfuscated code with prefixed identifier`, () => {
|
|
assert.match(fileContent1, regExp1);
|
|
});
|
|
|
|
it(`match #2: should create file with obfuscated code with prefixed identifier`, () => {
|
|
assert.match(fileContent2, regExp2);
|
|
});
|
|
|
|
after(() => {
|
|
rimraf.sync(outputFixturesFilePath1);
|
|
rimraf.sync(outputFixturesFilePath2);
|
|
});
|
|
});
|
|
|
|
describe('Variant #2: --exclude option is pointed on file under obfuscating directory', () => {
|
|
const directoryPath: string = path.join(fixturesDirName, 'directory-obfuscation');
|
|
const outputFileName1: string = 'foo-obfuscated.js';
|
|
const outputFileName2: string = 'bar-obfuscated.js';
|
|
const outputFileName3: string = 'baz-obfuscated.js';
|
|
const readFileEncoding = 'utf8';
|
|
const regExp1: RegExp = /^var a0_0x(\w){4,6} *= *0x2;$/;
|
|
|
|
let outputFixturesFilePath1: string,
|
|
outputFixturesFilePath2: string,
|
|
outputFixturesFilePath3: string,
|
|
isFileExist1: boolean,
|
|
isFileExist2: boolean,
|
|
isFileExist3: boolean,
|
|
fileContent1: string;
|
|
|
|
before(async () => {
|
|
outputFixturesFilePath1 = path.join(directoryPath, outputFileName1);
|
|
outputFixturesFilePath2 = path.join(directoryPath, outputFileName2);
|
|
outputFixturesFilePath3 = path.join(directoryPath, outputFileName3);
|
|
|
|
await JavaScriptObfuscatorCLI.obfuscate([
|
|
'node',
|
|
'javascript-obfuscator',
|
|
directoryPath,
|
|
'--exclude',
|
|
path.join('**', 'foo.js'),
|
|
'--rename-globals',
|
|
'true'
|
|
]);
|
|
|
|
isFileExist1 = fs.existsSync(outputFixturesFilePath1);
|
|
isFileExist2 = fs.existsSync(outputFixturesFilePath2);
|
|
isFileExist3 = fs.existsSync(outputFixturesFilePath3);
|
|
|
|
fileContent1 = fs.readFileSync(outputFixturesFilePath2, readFileEncoding);
|
|
});
|
|
|
|
it(`shouldn't create file \`${outputFileName1}\` in \`${fixturesDirName}\` directory`, () => {
|
|
assert.equal(isFileExist1, false);
|
|
});
|
|
|
|
it(`should create file \`${outputFileName2}\` with obfuscated code in \`${fixturesDirName}\` directory`, () => {
|
|
assert.equal(isFileExist2, true);
|
|
});
|
|
|
|
it(`shouldn't create file \`${outputFileName3}\` in \`${fixturesDirName}\` directory`, () => {
|
|
assert.equal(isFileExist3, false);
|
|
});
|
|
|
|
it(`match #1: should create file with obfuscated code with prefixed identifier`, () => {
|
|
assert.match(fileContent1, regExp1);
|
|
});
|
|
|
|
after(() => {
|
|
rimraf.sync(outputFixturesFilePath1);
|
|
rimraf.sync(outputFixturesFilePath2);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('`--sourceMap` option is set', () => {
|
|
const outputSourceMapPath: string = `${outputFilePath}.map`;
|
|
|
|
describe('Variant #1: `--sourceMapMode` option value is `separate`', () => {
|
|
describe('Variant #1: default behaviour', () => {
|
|
let isFileExist: boolean,
|
|
resolvedSources: string,
|
|
sourceCodeContent: string,
|
|
sourceMapObject: ISourceMap;
|
|
|
|
before(async () => {
|
|
await JavaScriptObfuscatorCLI.obfuscate([
|
|
'node',
|
|
'javascript-obfuscator',
|
|
fixtureFilePath,
|
|
'--output',
|
|
outputFilePath,
|
|
'--compact',
|
|
'true',
|
|
'--self-defending',
|
|
'0',
|
|
'--source-map',
|
|
'true'
|
|
]);
|
|
|
|
try {
|
|
sourceCodeContent = fs.readFileSync(fixtureFilePath, { encoding: 'utf8' });
|
|
const sourceMapContent: string = fs.readFileSync(outputSourceMapPath, { encoding: 'utf8' });
|
|
|
|
isFileExist = true;
|
|
sourceMapObject = JSON.parse(sourceMapContent);
|
|
|
|
await new Promise<void>((resolve) => {
|
|
resolveSources(sourceMapObject, fixtureFilePath, fs.readFile, (error, result) => {
|
|
resolvedSources =
|
|
typeof result.sourcesContent[0] === 'string' ? result.sourcesContent[0] : '';
|
|
resolve();
|
|
});
|
|
});
|
|
} catch (e) {
|
|
isFileExist = false;
|
|
}
|
|
});
|
|
|
|
it('should create file with source map in the same directory as output file', () => {
|
|
assert.equal(isFileExist, true);
|
|
});
|
|
|
|
it('source map from created file should contains property `version`', () => {
|
|
assert.property(sourceMapObject, 'version');
|
|
});
|
|
|
|
it('source map from created file should contains property `names`', () => {
|
|
assert.property(sourceMapObject, 'names');
|
|
});
|
|
|
|
it('should resolve correct sources from source map', () => {
|
|
assert.equal(resolvedSources, sourceCodeContent);
|
|
});
|
|
|
|
after(() => {
|
|
rimraf.sync(outputFilePath);
|
|
rimraf.sync(outputSourceMapPath);
|
|
});
|
|
});
|
|
|
|
describe('Variant #2: `sourceMapBaseUrl` option is set', () => {
|
|
let isFileExist: boolean,
|
|
resolvedSources: string,
|
|
sourceCodeContent: string,
|
|
sourceMapObject: ISourceMap;
|
|
|
|
before(async () => {
|
|
await JavaScriptObfuscatorCLI.obfuscate([
|
|
'node',
|
|
'javascript-obfuscator',
|
|
fixtureFilePath,
|
|
'--output',
|
|
outputFilePath,
|
|
'--compact',
|
|
'true',
|
|
'--self-defending',
|
|
'0',
|
|
'--source-map',
|
|
'true',
|
|
'--source-map-base-url',
|
|
'http://localhost:9000/'
|
|
]);
|
|
|
|
try {
|
|
sourceCodeContent = fs.readFileSync(fixtureFilePath, { encoding: 'utf8' });
|
|
const sourceMapContent: string = fs.readFileSync(outputSourceMapPath, { encoding: 'utf8' });
|
|
|
|
isFileExist = true;
|
|
sourceMapObject = JSON.parse(sourceMapContent);
|
|
|
|
await new Promise<void>((resolve) => {
|
|
resolveSources(sourceMapObject, fixtureFilePath, fs.readFile, (error, result) => {
|
|
resolvedSources =
|
|
typeof result.sourcesContent[0] === 'string' ? result.sourcesContent[0] : '';
|
|
resolve();
|
|
});
|
|
});
|
|
} catch (e) {
|
|
isFileExist = false;
|
|
}
|
|
});
|
|
|
|
it('should create file with source map in the same directory as output file', () => {
|
|
assert.equal(isFileExist, true);
|
|
});
|
|
|
|
it('source map from created file should contains property `version`', () => {
|
|
assert.property(sourceMapObject, 'version');
|
|
});
|
|
|
|
it('source map from created file should contains property `names`', () => {
|
|
assert.property(sourceMapObject, 'names');
|
|
});
|
|
|
|
it('should resolve correct sources from source map', () => {
|
|
assert.equal(resolvedSources, sourceCodeContent);
|
|
});
|
|
|
|
after(() => {
|
|
fs.unlinkSync(outputFilePath);
|
|
fs.unlinkSync(outputSourceMapPath);
|
|
});
|
|
});
|
|
|
|
describe('Variant #3: `--sourceMapFileName` option is set', () => {
|
|
const sourceMapFileName: string = 'test';
|
|
const sourceMapFilePath: string = `${sourceMapFileName}.js.map`;
|
|
const outputSourceMapFilePath: string = path.join(outputDirName, sourceMapFilePath);
|
|
|
|
let isFileExist: boolean,
|
|
resolvedSources: string,
|
|
sourceCodeContent: string,
|
|
sourceMapObject: ISourceMap;
|
|
|
|
before(async () => {
|
|
await JavaScriptObfuscatorCLI.obfuscate([
|
|
'node',
|
|
'javascript-obfuscator',
|
|
fixtureFilePath,
|
|
'--output',
|
|
outputFilePath,
|
|
'--compact',
|
|
'true',
|
|
'--self-defending',
|
|
'0',
|
|
'--source-map',
|
|
'true',
|
|
'--source-map-file-name',
|
|
sourceMapFileName
|
|
]);
|
|
|
|
try {
|
|
sourceCodeContent = fs.readFileSync(fixtureFilePath, { encoding: 'utf8' });
|
|
const sourceMapContent: string = fs.readFileSync(outputSourceMapFilePath, {
|
|
encoding: 'utf8'
|
|
});
|
|
|
|
isFileExist = true;
|
|
sourceMapObject = JSON.parse(sourceMapContent);
|
|
|
|
await new Promise<void>((resolve) => {
|
|
resolveSources(sourceMapObject, fixtureFilePath, fs.readFile, (error, result) => {
|
|
resolvedSources =
|
|
typeof result.sourcesContent[0] === 'string' ? result.sourcesContent[0] : '';
|
|
resolve();
|
|
});
|
|
});
|
|
} catch (e) {
|
|
isFileExist = false;
|
|
}
|
|
});
|
|
|
|
it('should create source map file with given name in the same directory as output file', () => {
|
|
assert.equal(isFileExist, true);
|
|
});
|
|
|
|
it('source map from created file should contains property `version`', () => {
|
|
assert.property(sourceMapObject, 'version');
|
|
});
|
|
|
|
it('source map from created file should contains property `names`', () => {
|
|
assert.property(sourceMapObject, 'names');
|
|
});
|
|
|
|
it('should resolve correct sources from source map', () => {
|
|
assert.equal(resolvedSources, sourceCodeContent);
|
|
});
|
|
|
|
after(() => {
|
|
fs.unlinkSync(outputFilePath);
|
|
fs.unlinkSync(outputSourceMapFilePath);
|
|
});
|
|
});
|
|
|
|
describe('Variant #4: `sourceMapSourcesMode` option is set', () => {
|
|
describe('Variant #1: `sourcesContent` value', () => {
|
|
const expectedSourceMapSourceName: string = 'sourceMap';
|
|
|
|
let isFileExist: boolean,
|
|
resolvedSources: string,
|
|
sourceCodeContent: string,
|
|
sourceMapObject: ISourceMap;
|
|
|
|
before(async () => {
|
|
await JavaScriptObfuscatorCLI.obfuscate([
|
|
'node',
|
|
'javascript-obfuscator',
|
|
fixtureFilePath,
|
|
'--output',
|
|
outputFilePath,
|
|
'--compact',
|
|
'true',
|
|
'--self-defending',
|
|
'0',
|
|
'--source-map',
|
|
'true',
|
|
'--source-map-sources-mode',
|
|
'sources-content'
|
|
]);
|
|
|
|
try {
|
|
sourceCodeContent = fs.readFileSync(fixtureFilePath, { encoding: 'utf8' });
|
|
const sourceMapContent: string = fs.readFileSync(outputSourceMapPath, {
|
|
encoding: 'utf8'
|
|
});
|
|
|
|
isFileExist = true;
|
|
sourceMapObject = JSON.parse(sourceMapContent);
|
|
|
|
await new Promise<void>((resolve) => {
|
|
resolveSources(sourceMapObject, fixtureFilePath, fs.readFile, (error, result) => {
|
|
resolvedSources =
|
|
typeof result.sourcesContent[0] === 'string' ? result.sourcesContent[0] : '';
|
|
resolve();
|
|
});
|
|
});
|
|
} catch (e) {
|
|
isFileExist = false;
|
|
}
|
|
});
|
|
|
|
it('should create file with source map in the same directory as output file', () => {
|
|
assert.equal(isFileExist, true);
|
|
});
|
|
|
|
it('source map from created file should contains property `sources`', () => {
|
|
assert.property(sourceMapObject, 'sources');
|
|
});
|
|
|
|
it('source map from created file should contains property `sourcesContent`', () => {
|
|
assert.property(sourceMapObject, 'sourcesContent');
|
|
});
|
|
|
|
it('source map source should has correct sources', () => {
|
|
assert.equal(sourceMapObject.sources[0], expectedSourceMapSourceName);
|
|
});
|
|
|
|
it('source map source should has correct sources content', () => {
|
|
assert.equal(sourceMapObject.sourcesContent[0], sourceCodeContent);
|
|
});
|
|
|
|
it('should resolve correct sources from source map', () => {
|
|
assert.equal(resolvedSources, sourceCodeContent);
|
|
});
|
|
|
|
after(() => {
|
|
rimraf.sync(outputFilePath);
|
|
rimraf.sync(outputSourceMapPath);
|
|
});
|
|
});
|
|
|
|
describe('Variant #2: `sources` value', () => {
|
|
const expectedSourceMapSourceName: string = path.basename(fixtureFileName);
|
|
|
|
let isFileExist: boolean,
|
|
resolvedSources: string,
|
|
sourceCodeContent: string,
|
|
sourceMapObject: ISourceMap;
|
|
|
|
before(async () => {
|
|
await JavaScriptObfuscatorCLI.obfuscate([
|
|
'node',
|
|
'javascript-obfuscator',
|
|
fixtureFilePath,
|
|
'--output',
|
|
outputFilePath,
|
|
'--compact',
|
|
'true',
|
|
'--self-defending',
|
|
'0',
|
|
'--source-map',
|
|
'true',
|
|
'--source-map-sources-mode',
|
|
'sources'
|
|
]);
|
|
|
|
try {
|
|
sourceCodeContent = fs.readFileSync(fixtureFilePath, { encoding: 'utf8' });
|
|
const sourceMapContent: string = fs.readFileSync(outputSourceMapPath, {
|
|
encoding: 'utf8'
|
|
});
|
|
|
|
isFileExist = true;
|
|
sourceMapObject = JSON.parse(sourceMapContent);
|
|
|
|
await new Promise<void>((resolve) => {
|
|
resolveSources(sourceMapObject, fixtureFilePath, fs.readFile, (error, result) => {
|
|
resolvedSources =
|
|
typeof result.sourcesContent[0] === 'string' ? result.sourcesContent[0] : '';
|
|
resolve();
|
|
});
|
|
});
|
|
} catch (e) {
|
|
isFileExist = false;
|
|
}
|
|
});
|
|
|
|
it('should create file with source map in the same directory as output file', () => {
|
|
assert.equal(isFileExist, true);
|
|
});
|
|
|
|
it('source map from created file should contains property `sources`', () => {
|
|
assert.property(sourceMapObject, 'sources');
|
|
});
|
|
|
|
it('source map from created file should not contains property `sourcesContent`', () => {
|
|
assert.notProperty(sourceMapObject, 'sourcesContent');
|
|
});
|
|
|
|
it('source map source should has correct sources', () => {
|
|
assert.equal(sourceMapObject.sources[0], expectedSourceMapSourceName);
|
|
});
|
|
|
|
it('should resolve correct sources from source map', () => {
|
|
assert.equal(resolvedSources, sourceCodeContent);
|
|
});
|
|
|
|
after(() => {
|
|
rimraf.sync(outputFilePath);
|
|
rimraf.sync(outputSourceMapPath);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Variant #2: `--sourceMapMode` option is `inline`', () => {
|
|
describe('Variant #1: default behaviour', () => {
|
|
let isFileExist: boolean,
|
|
resolvedSources: string,
|
|
sourceCodeContent: string,
|
|
sourceMapObject: ISourceMap;
|
|
|
|
before(async () => {
|
|
await JavaScriptObfuscatorCLI.obfuscate([
|
|
'node',
|
|
'javascript-obfuscator',
|
|
fixtureFilePath,
|
|
'--output',
|
|
outputFilePath,
|
|
'--compact',
|
|
'true',
|
|
'--self-defending',
|
|
'0',
|
|
'--source-map',
|
|
'true',
|
|
'--source-map-mode',
|
|
'inline'
|
|
]);
|
|
|
|
isFileExist = fs.existsSync(outputSourceMapPath);
|
|
|
|
sourceCodeContent = fs.readFileSync(fixtureFilePath, { encoding: 'utf8' });
|
|
const obfuscatedCodeContent = fs.readFileSync(outputFilePath, { encoding: 'utf8' });
|
|
|
|
sourceMapObject = parseSourceMapFromObfuscatedCode(obfuscatedCodeContent);
|
|
|
|
await new Promise<void>((resolve) => {
|
|
resolveSources(sourceMapObject, fixtureFilePath, fs.readFile, (error, result) => {
|
|
resolvedSources =
|
|
typeof result.sourcesContent[0] === 'string' ? result.sourcesContent[0] : '';
|
|
resolve();
|
|
});
|
|
});
|
|
});
|
|
|
|
it("shouldn't create file with source map", () => {
|
|
assert.equal(isFileExist, false);
|
|
});
|
|
|
|
it('should resolve correct sources from source map', () => {
|
|
assert.equal(resolvedSources, sourceCodeContent);
|
|
});
|
|
|
|
after(() => {
|
|
fs.unlinkSync(outputFilePath);
|
|
});
|
|
});
|
|
|
|
describe('Variant #2: `sourceMapSourcesMode` option is set', () => {
|
|
describe('Variant #1: `sourcesContent` value', () => {
|
|
const expectedSourceMapSourceName: string = 'sourceMap';
|
|
|
|
let isFileExist: boolean,
|
|
resolvedSources: string,
|
|
sourceCodeContent: string,
|
|
sourceMapObject: ISourceMap;
|
|
|
|
before(async () => {
|
|
await JavaScriptObfuscatorCLI.obfuscate([
|
|
'node',
|
|
'javascript-obfuscator',
|
|
fixtureFilePath,
|
|
'--output',
|
|
outputFilePath,
|
|
'--compact',
|
|
'true',
|
|
'--self-defending',
|
|
'0',
|
|
'--source-map',
|
|
'true',
|
|
'--source-map-mode',
|
|
'inline',
|
|
'--source-map-sources-mode',
|
|
'sources-content'
|
|
]);
|
|
|
|
isFileExist = fs.existsSync(outputSourceMapPath);
|
|
|
|
sourceCodeContent = fs.readFileSync(fixtureFilePath, { encoding: 'utf8' });
|
|
const obfuscatedCodeContent = fs.readFileSync(outputFilePath, { encoding: 'utf8' });
|
|
sourceMapObject = parseSourceMapFromObfuscatedCode(obfuscatedCodeContent);
|
|
|
|
await new Promise<void>((resolve) => {
|
|
resolveSources(sourceMapObject, fixtureFilePath, fs.readFile, (error, result) => {
|
|
resolvedSources =
|
|
typeof result.sourcesContent[0] === 'string' ? result.sourcesContent[0] : '';
|
|
resolve();
|
|
});
|
|
});
|
|
});
|
|
|
|
it("shouldn't create file with source map", () => {
|
|
assert.equal(isFileExist, false);
|
|
});
|
|
|
|
it('source map from created file should contains property `sources`', () => {
|
|
assert.property(sourceMapObject, 'sources');
|
|
});
|
|
|
|
it('source map from created file should contains property `sourcesContent`', () => {
|
|
assert.property(sourceMapObject, 'sourcesContent');
|
|
});
|
|
|
|
it('source map source should has correct sources', () => {
|
|
assert.equal(sourceMapObject.sources[0], expectedSourceMapSourceName);
|
|
});
|
|
|
|
it('source map source should has correct sources content', () => {
|
|
assert.equal(sourceMapObject.sourcesContent[0], sourceCodeContent);
|
|
});
|
|
|
|
it('should resolve correct sources from source map', () => {
|
|
assert.equal(resolvedSources, sourceCodeContent);
|
|
});
|
|
|
|
after(() => {
|
|
fs.unlinkSync(outputFilePath);
|
|
});
|
|
});
|
|
|
|
describe('Variant #2: `sources` value', () => {
|
|
const expectedSourceMapSourceName: string = path.basename(fixtureFileName);
|
|
|
|
let isFileExist: boolean,
|
|
resolvedSources: string,
|
|
sourceCodeContent: string,
|
|
sourceMapObject: ISourceMap;
|
|
|
|
before(async () => {
|
|
await JavaScriptObfuscatorCLI.obfuscate([
|
|
'node',
|
|
'javascript-obfuscator',
|
|
fixtureFilePath,
|
|
'--output',
|
|
outputFilePath,
|
|
'--compact',
|
|
'true',
|
|
'--self-defending',
|
|
'0',
|
|
'--source-map',
|
|
'true',
|
|
'--source-map-mode',
|
|
'inline',
|
|
'--source-map-sources-mode',
|
|
'sources'
|
|
]);
|
|
|
|
isFileExist = fs.existsSync(outputSourceMapPath);
|
|
|
|
sourceCodeContent = fs.readFileSync(fixtureFilePath, { encoding: 'utf8' });
|
|
const obfuscatedCodeContent = fs.readFileSync(outputFilePath, { encoding: 'utf8' });
|
|
sourceMapObject = parseSourceMapFromObfuscatedCode(obfuscatedCodeContent);
|
|
|
|
await new Promise<void>((resolve) => {
|
|
resolveSources(sourceMapObject, fixtureFilePath, fs.readFile, (error, result) => {
|
|
resolvedSources =
|
|
typeof result.sourcesContent[0] === 'string' ? result.sourcesContent[0] : '';
|
|
resolve();
|
|
});
|
|
});
|
|
});
|
|
|
|
it("shouldn't create file with source map", () => {
|
|
assert.equal(isFileExist, false);
|
|
});
|
|
|
|
it('source map from created file should contains property `sources`', () => {
|
|
assert.property(sourceMapObject, 'sources');
|
|
});
|
|
|
|
it('source map from created file should contains property `sourcesContent`', () => {
|
|
assert.notProperty(sourceMapObject, 'sourcesContent');
|
|
});
|
|
|
|
it('source map source should has correct sources', () => {
|
|
assert.equal(sourceMapObject.sources[0], expectedSourceMapSourceName);
|
|
});
|
|
|
|
it('should resolve correct sources from source map', () => {
|
|
assert.equal(resolvedSources, sourceCodeContent);
|
|
});
|
|
|
|
after(() => {
|
|
fs.unlinkSync(outputFilePath);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('help output', () => {
|
|
let callback: sinon.SinonSpy<any, void>, stdoutWriteMock: StdoutWriteMock, stubExit: sinon.SinonStub;
|
|
|
|
beforeEach(() => {
|
|
stubExit = sinon.stub(process, 'exit');
|
|
callback = sinon.spy(console, 'log');
|
|
stdoutWriteMock = new StdoutWriteMock(process.stdout.write);
|
|
});
|
|
|
|
describe('`--help` option is set without any additional parameters', () => {
|
|
let isConsoleLogCalled: boolean;
|
|
|
|
beforeEach(async () => {
|
|
stdoutWriteMock.mute();
|
|
|
|
await JavaScriptObfuscatorCLI.obfuscate(['node', 'javascript-obfuscator', '--help']);
|
|
|
|
stdoutWriteMock.restore();
|
|
isConsoleLogCalled = callback.called;
|
|
});
|
|
|
|
it('should print `console.log` help', () => {
|
|
assert.equal(isConsoleLogCalled, true);
|
|
});
|
|
});
|
|
|
|
describe('`--help` option is set before file path', () => {
|
|
let isConsoleLogCalled: boolean;
|
|
|
|
beforeEach(async () => {
|
|
stdoutWriteMock.mute();
|
|
|
|
await JavaScriptObfuscatorCLI.obfuscate(['node', 'javascript-obfuscator', '--help', fixtureFilePath]);
|
|
|
|
stdoutWriteMock.restore();
|
|
isConsoleLogCalled = callback.called;
|
|
});
|
|
|
|
it('should print `console.log` help', () => {
|
|
assert.equal(isConsoleLogCalled, true);
|
|
});
|
|
});
|
|
|
|
describe('`--help` option is set after file path', () => {
|
|
let isConsoleLogCalled: boolean;
|
|
|
|
beforeEach(async () => {
|
|
stdoutWriteMock.mute();
|
|
|
|
await JavaScriptObfuscatorCLI.obfuscate(['node', 'javascript-obfuscator', fixtureFilePath, '--help']);
|
|
|
|
stdoutWriteMock.restore();
|
|
isConsoleLogCalled = callback.called;
|
|
});
|
|
|
|
it('should print `console.log` help', () => {
|
|
assert.equal(isConsoleLogCalled, true);
|
|
});
|
|
});
|
|
|
|
describe('no arguments passed', () => {
|
|
let isConsoleLogCalled: boolean;
|
|
|
|
beforeEach(async () => {
|
|
stdoutWriteMock.mute();
|
|
|
|
await JavaScriptObfuscatorCLI.obfuscate(['node', 'javascript-obfuscator']);
|
|
|
|
stdoutWriteMock.restore();
|
|
isConsoleLogCalled = callback.called;
|
|
});
|
|
|
|
it('should print `console.log` help', () => {
|
|
assert.equal(isConsoleLogCalled, true);
|
|
});
|
|
});
|
|
|
|
afterEach(() => {
|
|
stubExit.restore();
|
|
callback.restore();
|
|
});
|
|
});
|
|
|
|
describe('`--config` option is set', () => {
|
|
describe('Base options', () => {
|
|
const outputSourceMapPath: string = `${outputFilePath}.map`;
|
|
|
|
let isFileExist: boolean, sourceMapObject: any;
|
|
|
|
before(async () => {
|
|
await JavaScriptObfuscatorCLI.obfuscate([
|
|
'node',
|
|
'javascript-obfuscator',
|
|
fixtureFilePath,
|
|
'--output',
|
|
outputFilePath,
|
|
'--config',
|
|
configFilePath
|
|
]);
|
|
|
|
try {
|
|
const content: string = fs.readFileSync(outputSourceMapPath, { encoding: 'utf8' });
|
|
|
|
isFileExist = true;
|
|
sourceMapObject = JSON.parse(content);
|
|
} catch (e) {
|
|
isFileExist = false;
|
|
}
|
|
});
|
|
|
|
it('should create file with source map in the same directory as output file', () => {
|
|
assert.equal(isFileExist, true);
|
|
});
|
|
|
|
it('source map from created file should contains property `version`', () => {
|
|
assert.property(sourceMapObject, 'version');
|
|
});
|
|
|
|
it('source map from created file should contains property `sources`', () => {
|
|
assert.property(sourceMapObject, 'sources');
|
|
});
|
|
|
|
it('source map from created file should contains property `names`', () => {
|
|
assert.property(sourceMapObject, 'names');
|
|
});
|
|
|
|
after(() => {
|
|
fs.unlinkSync(outputFilePath);
|
|
fs.unlinkSync(outputSourceMapPath);
|
|
});
|
|
});
|
|
|
|
describe('`--exclude` option', () => {
|
|
const directoryPath: string = path.join(fixturesDirName, 'directory-obfuscation');
|
|
const outputFileName1: string = 'foo-obfuscated.js';
|
|
const outputFileName2: string = 'bar-obfuscated.js';
|
|
|
|
let outputFixturesFilePath1: string,
|
|
outputFixturesFilePath2: string,
|
|
isFileExist1: boolean,
|
|
isFileExist2: boolean;
|
|
|
|
before(async () => {
|
|
outputFixturesFilePath1 = path.join(directoryPath, outputFileName1);
|
|
outputFixturesFilePath2 = path.join(directoryPath, outputFileName2);
|
|
|
|
await JavaScriptObfuscatorCLI.obfuscate([
|
|
'node',
|
|
'javascript-obfuscator',
|
|
directoryPath,
|
|
'--config',
|
|
configFilePath
|
|
]);
|
|
|
|
isFileExist1 = fs.existsSync(outputFixturesFilePath1);
|
|
isFileExist2 = fs.existsSync(outputFixturesFilePath2);
|
|
});
|
|
|
|
it(`shouldn't create file \`${outputFileName1}\` in \`${fixturesDirName}\` directory`, () => {
|
|
assert.equal(isFileExist1, false);
|
|
});
|
|
|
|
it(`should create file \`${outputFileName2}\` with obfuscated code in \`${fixturesDirName}\` directory`, () => {
|
|
assert.equal(isFileExist2, true);
|
|
});
|
|
|
|
after(() => {
|
|
rimraf.sync(outputFixturesFilePath1);
|
|
rimraf.sync(outputFixturesFilePath2);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('`--config` option is set but overridden by CLI option', () => {
|
|
const outputSourceMapPath: string = `${outputFilePath}.map`;
|
|
|
|
let isFileExist: boolean;
|
|
|
|
before(async () => {
|
|
await JavaScriptObfuscatorCLI.obfuscate([
|
|
'node',
|
|
'javascript-obfuscator',
|
|
fixtureFilePath,
|
|
'--output',
|
|
outputFilePath,
|
|
'--config',
|
|
configFilePath,
|
|
'--source-map',
|
|
'false'
|
|
]);
|
|
|
|
try {
|
|
fs.readFileSync(outputSourceMapPath, { encoding: 'utf8' });
|
|
|
|
isFileExist = true;
|
|
} catch (e) {
|
|
isFileExist = false;
|
|
}
|
|
});
|
|
|
|
it('should create file without source map in the same directory as output file', () => {
|
|
assert.equal(isFileExist, false);
|
|
});
|
|
|
|
after(() => {
|
|
fs.unlinkSync(outputFilePath);
|
|
});
|
|
});
|
|
|
|
describe('Logging', () => {
|
|
describe('Obfuscating file message', () => {
|
|
const directoryPath: string = path.join(fixturesDirName, 'directory-obfuscation');
|
|
|
|
const inputFileName1: string = 'foo.js';
|
|
const inputFileName2: string = 'bar.js';
|
|
const inputFilePath1: string = path.join(directoryPath, inputFileName1);
|
|
const inputFilePath2: string = path.join(directoryPath, inputFileName2);
|
|
|
|
const outputFileName1: string = 'foo-obfuscated.js';
|
|
const outputFileName2: string = 'bar-obfuscated.js';
|
|
const outputFilePath1: string = path.join(directoryPath, outputFileName1);
|
|
const outputFilePath2: string = path.join(directoryPath, outputFileName2);
|
|
|
|
const expectedLoggingMessage1: string = `[javascript-obfuscator-cli] Obfuscating file: ${inputFilePath1}...`;
|
|
const expectedLoggingMessage2: string = `[javascript-obfuscator-cli] Obfuscating file: ${inputFilePath2}...`;
|
|
|
|
let consoleLogSpy: sinon.SinonSpy<any, void>,
|
|
loggingMessageResult1: string,
|
|
loggingMessageResult2: string;
|
|
|
|
before(async () => {
|
|
consoleLogSpy = sinon.spy(console, 'log');
|
|
|
|
await JavaScriptObfuscatorCLI.obfuscate([
|
|
'node',
|
|
'javascript-obfuscator',
|
|
directoryPath,
|
|
'--rename-globals',
|
|
'true'
|
|
]);
|
|
|
|
loggingMessageResult1 = consoleLogSpy.getCall(1).args[0];
|
|
loggingMessageResult2 = consoleLogSpy.getCall(0).args[0];
|
|
});
|
|
|
|
it('Variant #1: should log file name to the console', () => {
|
|
assert.include(loggingMessageResult1, expectedLoggingMessage1);
|
|
});
|
|
|
|
it('Variant #2: should log file name to the console', () => {
|
|
assert.include(loggingMessageResult2, expectedLoggingMessage2);
|
|
});
|
|
|
|
after(() => {
|
|
rimraf.sync(outputFilePath1);
|
|
rimraf.sync(outputFilePath2);
|
|
consoleLogSpy.restore();
|
|
});
|
|
});
|
|
|
|
describe('Error message', () => {
|
|
const directoryPath: string = path.join(fixturesDirName, 'directory-obfuscation-error');
|
|
|
|
const inputFileName: string = 'foo.js';
|
|
const inputFilePath: string = path.join(directoryPath, inputFileName);
|
|
|
|
const expectedLoggingMessage1: string = `[javascript-obfuscator-cli] Error in file: ${inputFilePath}...`;
|
|
|
|
let consoleLogSpy: sinon.SinonSpy<any, void>, loggingMessageResult: string;
|
|
|
|
before(async () => {
|
|
consoleLogSpy = sinon.spy(console, 'log');
|
|
|
|
try {
|
|
await JavaScriptObfuscatorCLI.obfuscate([
|
|
'node',
|
|
'javascript-obfuscator',
|
|
directoryPath,
|
|
'--rename-globals',
|
|
'true'
|
|
]);
|
|
} catch {}
|
|
|
|
loggingMessageResult = consoleLogSpy.getCall(1).args[0];
|
|
});
|
|
|
|
it('Should log file name to the console', () => {
|
|
assert.include(loggingMessageResult, expectedLoggingMessage1);
|
|
});
|
|
|
|
after(() => {
|
|
consoleLogSpy.restore();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('`--pro-api-token` option', () => {
|
|
let fetchStub: sinon.SinonStub;
|
|
let proApiFilePath: string;
|
|
|
|
before(async () => {
|
|
proApiFilePath = path.join(outputDirName, 'pro-api-test.js');
|
|
fs.writeFileSync(proApiFilePath, 'const test = 1;');
|
|
});
|
|
|
|
afterEach(() => {
|
|
if (fetchStub) {
|
|
fetchStub.restore();
|
|
}
|
|
});
|
|
|
|
after(() => {
|
|
if (fs.existsSync(proApiFilePath)) {
|
|
fs.unlinkSync(proApiFilePath);
|
|
}
|
|
});
|
|
|
|
describe('Variant #1: Pro API token with vmObfuscation', () => {
|
|
it('should use Pro API when --pro-api-token and --vm-obfuscation are provided', async () => {
|
|
const mockResponse = {
|
|
ok: true,
|
|
status: 200,
|
|
text: async () => JSON.stringify({ type: 'result', code: 'var obfuscated=1;', sourceMap: '' })
|
|
} as Response;
|
|
|
|
fetchStub = sinon.stub(global, 'fetch').resolves(mockResponse);
|
|
|
|
await JavaScriptObfuscatorCLI.obfuscate([
|
|
'node',
|
|
'javascript-obfuscator',
|
|
proApiFilePath,
|
|
'--output',
|
|
path.join(outputDirName, 'pro-api-output.js'),
|
|
'--pro-api-token',
|
|
'test-token-123',
|
|
'--vm-obfuscation',
|
|
'true'
|
|
]);
|
|
|
|
// Wait for async operations
|
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
|
|
assert.isTrue(fetchStub.called, 'fetch should be called for Pro API');
|
|
const calledUrl = fetchStub.firstCall?.args[0];
|
|
assert.include(calledUrl, 'obfuscator.io/api/v1');
|
|
});
|
|
});
|
|
|
|
describe('Variant #2: Pro API token with parseHtml', () => {
|
|
it('should use Pro API when --pro-api-token and --parse-html are provided', async () => {
|
|
const mockResponse = {
|
|
ok: true,
|
|
status: 200,
|
|
text: async () => JSON.stringify({ type: 'result', code: 'var obfuscated=1;', sourceMap: '' })
|
|
} as Response;
|
|
|
|
fetchStub = sinon.stub(global, 'fetch').resolves(mockResponse);
|
|
|
|
await JavaScriptObfuscatorCLI.obfuscate([
|
|
'node',
|
|
'javascript-obfuscator',
|
|
proApiFilePath,
|
|
'--output',
|
|
path.join(outputDirName, 'pro-api-output2.js'),
|
|
'--pro-api-token',
|
|
'test-token-123',
|
|
'--parse-html',
|
|
'true'
|
|
]);
|
|
|
|
// Wait for async operations
|
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
|
|
assert.isTrue(fetchStub.called, 'fetch should be called for Pro API');
|
|
});
|
|
});
|
|
|
|
describe('Variant #3: Pro API token with version', () => {
|
|
it('should pass version to Pro API URL when --pro-api-version is provided', async () => {
|
|
const mockResponse = {
|
|
ok: true,
|
|
status: 200,
|
|
text: async () => JSON.stringify({ type: 'result', code: 'var obfuscated=1;', sourceMap: '' })
|
|
} as Response;
|
|
|
|
fetchStub = sinon.stub(global, 'fetch').resolves(mockResponse);
|
|
|
|
await JavaScriptObfuscatorCLI.obfuscate([
|
|
'node',
|
|
'javascript-obfuscator',
|
|
proApiFilePath,
|
|
'--output',
|
|
path.join(outputDirName, 'pro-api-output3.js'),
|
|
'--pro-api-token',
|
|
'test-token-123',
|
|
'--pro-api-version',
|
|
'5.0.0-beta.20',
|
|
'--vm-obfuscation',
|
|
'true'
|
|
]);
|
|
|
|
// Wait for async operations
|
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
|
|
assert.isTrue(fetchStub.called, 'fetch should be called for Pro API');
|
|
const calledUrl = fetchStub.firstCall?.args[0];
|
|
assert.include(calledUrl, 'version=5.0.0-beta.20');
|
|
});
|
|
});
|
|
|
|
describe('Variant #4: Pro API token without Pro features throws error', () => {
|
|
it('should throw error when --pro-api-token is provided but no Pro features enabled', async () => {
|
|
const outputPath = path.join(outputDirName, 'local-output.js');
|
|
|
|
try {
|
|
await JavaScriptObfuscatorCLI.obfuscate([
|
|
'node',
|
|
'javascript-obfuscator',
|
|
proApiFilePath,
|
|
'--output',
|
|
outputPath,
|
|
'--pro-api-token',
|
|
'test-token-123',
|
|
'--compact',
|
|
'true'
|
|
]);
|
|
assert.fail('Expected error was not thrown');
|
|
} catch (error) {
|
|
assert.include(
|
|
(error as Error).message,
|
|
'Obfuscator.io Pro obfuscation works only when Pro features set.'
|
|
);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('hasProFeatures static method', () => {
|
|
it('should return true for vmObfuscation', () => {
|
|
assert.isTrue(ProApiClient.hasProFeatures({ vmObfuscation: true }));
|
|
});
|
|
|
|
it('should return true for parseHtml', () => {
|
|
assert.isTrue(ProApiClient.hasProFeatures({ parseHtml: true }));
|
|
});
|
|
|
|
it('should return false for no Pro features', () => {
|
|
assert.isFalse(ProApiClient.hasProFeatures({ compact: true }));
|
|
});
|
|
});
|
|
|
|
/**
|
|
* 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);
|
|
});
|
|
});
|
|
});
|