import { assert } from 'chai'; import { IObfuscationResult } from '../../../src/interfaces/IObfuscationResult'; import { JavaScriptObfuscator } from '../../../src/JavaScriptObfuscator'; import { NO_CUSTOM_NODES_PRESET } from '../../../src/options/presets/NoCustomNodes'; import { readFileAsString } from '../../helpers/readFileAsString'; import { RandomGeneratorUtils } from '../../../src/utils/RandomGeneratorUtils'; describe('JavaScriptObfuscator', () => { describe('obfuscate (sourceCode: string, customOptions?: IObfuscatorOptions): IObfuscationResult', () => { beforeEach(() => { RandomGeneratorUtils.initializeRandomGenerator(0); }); describe('if `sourceMap` option is `false`', () => { it('should returns object with obfuscated code and empty source map', () => { let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( readFileAsString(__dirname + '/fixtures/simple-input-1.js'), { ...NO_CUSTOM_NODES_PRESET } ); assert.isOk(obfuscationResult.getObfuscatedCode()); assert.isNotOk(obfuscationResult.getSourceMap()); }); }); describe('if `sourceMap` option is `true`', () => { it('should returns object with obfuscated code and source map', () => { let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( readFileAsString(__dirname + '/fixtures/simple-input-1.js'), { ...NO_CUSTOM_NODES_PRESET, sourceMap: true } ); assert.isOk(obfuscationResult.getObfuscatedCode()); assert.isOk(JSON.parse(obfuscationResult.getSourceMap()).mappings); }); it('should returns object with obfuscated code with inline source map as Base64 string', () => { let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( readFileAsString(__dirname + '/fixtures/simple-input-1.js'), { ...NO_CUSTOM_NODES_PRESET, sourceMap: true, sourceMapMode: 'inline' } ); assert.isOk(obfuscationResult.getObfuscatedCode()); assert.match( obfuscationResult.getObfuscatedCode(), /sourceMappingURL=data:application\/json;base64/ ); assert.isOk(obfuscationResult.getSourceMap()); }); it('should returns object with empty obfuscated code and source map with empty data if source code is empty', () => { let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( readFileAsString(__dirname + '/fixtures/empty-input.js'), { sourceMap: true } ); assert.isNotOk(obfuscationResult.getObfuscatedCode()); assert.deepEqual(JSON.parse(obfuscationResult.getSourceMap()).names, []); assert.deepEqual(JSON.parse(obfuscationResult.getSourceMap()).sources, []); assert.isNotOk(JSON.parse(obfuscationResult.getSourceMap()).mappings); }); }); it('should returns an empty string if source code is empty', () => { assert.isNotOk( JavaScriptObfuscator.obfuscate( readFileAsString(__dirname + '/fixtures/empty-input.js'), ).getObfuscatedCode() ); }); it('should returns an empty string if source code contains only comments', () => { assert.isNotOk( JavaScriptObfuscator.obfuscate( readFileAsString(__dirname + '/fixtures/comments-only.js'), ).getObfuscatedCode() ); }); it('should obfuscate simple code with variable inside global scope', () => { assert.match( JavaScriptObfuscator.obfuscate( readFileAsString(__dirname + '/fixtures/simple-input-1.js'), { ...NO_CUSTOM_NODES_PRESET } ).getObfuscatedCode(), /^var *test *= *0x\d+;$/ ); }); it('should obfuscate simple code with variable inside block-scope', () => { assert.match( JavaScriptObfuscator.obfuscate( readFileAsString(__dirname + '/fixtures/block-scope.js'), { ...NO_CUSTOM_NODES_PRESET } ).getObfuscatedCode(), /^\(function *\(\) *\{ *var *_0x[\w]+ *= *0x\d+; *\}(\(\)\)|\)\(\));?$/ ); }); it('should obfuscate simple code with latin literal variable value', () => { let stringArrayLatinRegExp: RegExp = /^var _0x(\w){4} *= *\['abc'\];/, stringArrayCallRegExp: RegExp = /var *test *= *_0x(\w){4}\('0x0'\);$/, obfuscatedCode1: string = JavaScriptObfuscator.obfuscate( readFileAsString(__dirname + '/fixtures/simple-input-2.js'), { ...NO_CUSTOM_NODES_PRESET, stringArray: true, stringArrayThreshold: 1 } ).getObfuscatedCode(); assert.match(obfuscatedCode1, stringArrayLatinRegExp); assert.match(obfuscatedCode1, stringArrayCallRegExp); }); it('should obfuscate simple code with cyrillic literal variable value', () => { let stringArrayCyrillicRegExp: RegExp = /^var _0x(\w){4} *= *\['(\\u\d+)+'\];/, stringArrayCallRegExp: RegExp = /var *test *= *_0x(\w){4}\('0x0'\);$/, obfuscatedCode2: string = JavaScriptObfuscator.obfuscate( readFileAsString(__dirname + '/fixtures/simple-input-cyrillic.js'), { ...NO_CUSTOM_NODES_PRESET, stringArray: true, stringArrayThreshold: 1 } ).getObfuscatedCode(); assert.match(obfuscatedCode2, stringArrayCyrillicRegExp); assert.match(obfuscatedCode2, stringArrayCallRegExp); }); it('should returns same code every time with same `seed`', function () { this.timeout(60000); const code: string = readFileAsString('./test/fixtures/sample.js'); const samples: number = 100; let seed: number = 12345, equalsCount: number = 0; for (let i: number = 0; i < samples; i++) { if (i % 20 === 0) { seed++; } const obfuscationResult1: IObfuscationResult = JavaScriptObfuscator.obfuscate( code, { seed: seed } ); const obfuscationResult2: IObfuscationResult = JavaScriptObfuscator.obfuscate( code, { seed: seed } ); if (obfuscationResult1.getObfuscatedCode() === obfuscationResult2.getObfuscatedCode()) { equalsCount++; } } assert.equal(equalsCount, samples); }); it('should returns different code with different `seed` option value', () => { const code: string = readFileAsString('./test/fixtures/sample.js'); const obfuscationResult1: IObfuscationResult = JavaScriptObfuscator.obfuscate( code, { seed: 12345 } ); const obfuscationResult2: IObfuscationResult = JavaScriptObfuscator.obfuscate( code, { seed: 12346 } ); const obfuscationResult3: IObfuscationResult = JavaScriptObfuscator.obfuscate( code, { seed: 0 } ); const obfuscationResult4: IObfuscationResult = JavaScriptObfuscator.obfuscate( code, { seed: 0 } ); assert.notEqual(obfuscationResult1.getObfuscatedCode(), obfuscationResult2.getObfuscatedCode()); assert.notEqual(obfuscationResult3.getObfuscatedCode(), obfuscationResult4.getObfuscatedCode()); }); it('should keep new.target MetaProperty', () => { assert.match( JavaScriptObfuscator.obfuscate( readFileAsString(__dirname + '/fixtures/new-target.js'), { ...NO_CUSTOM_NODES_PRESET } ).getObfuscatedCode(), /new\.target *=== *Foo/ ); }); it('should mangle obfuscated code', () => { const code: string = readFileAsString(__dirname + '/fixtures/mangle.js'); const obfuscationResult1: IObfuscationResult = JavaScriptObfuscator.obfuscate( code, { mangle: true } ); const mangleMatch: RegExp = /var *a *= *0x1/; assert.match(obfuscationResult1.getObfuscatedCode(), mangleMatch); }); afterEach(() => { RandomGeneratorUtils.initializeRandomGenerator(0); }); }); });